1 /*
2 *
3 * Copyright (C) 2010 Texas Instruments Incorporated - http://www.ti.com/
4 *
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 *
13 * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the
16 * distribution.
17 *
18 * Neither the name of Texas Instruments Incorporated nor the names of
19 * its contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
26 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
27 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
28 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
32 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 *
34 */
36 /**
37 * @file iblinit.c
38 *
39 * @brief
40 * This file contains code which runs prior to loading the full IBL
41 *
42 * @details
43 * The IBL loads itself in a two stage process. The ROM boot loader
44 * loads this first stage IBL first. This entire program must be
45 * endian independent in execution.
46 *
47 * This first loader reads the IBL parameters, and will endian
48 * switch them if required. The PLL is configured if indicated
49 * by the parameters.
50 *
51 * The I2C block which contains the I2C EEPROM address for both
52 * the big and little endian images is then read. Based on the
53 * endianness of the device the rest of the IBL is read from
54 * the I2C EEPROM, and execution is transferred to the full
55 * IBL.
56 *
57 * The subsequent reads are allowed to cross 16 bit i2c EEPROM
58 * addresses. When the boundary is crossed the i2c address
59 * field is incremented.
60 *
61 */
63 #include "ibl.h"
64 #include "iblloc.h"
65 #include "iblcfg.h"
66 #include "device.h"
67 #include "iblbtbl.h"
68 #include "iblinit.h"
69 #include <string.h>
72 /**
73 * @brief
74 * Data structures shared between the 1st and 2nd stage IBL load
75 * are declared in a single header file, included in both stages
76 */
77 #include "iblStage.h"
79 /**
80 * @brief
81 * The boot table processing status is declared in the boot table wrapper,
82 * and used here in the main status fields.
83 */
84 extern Int32 btblWrapEcode;
86 /**
87 * @brief
88 * The malloc function used for both boot stages of the ibl
89 */
90 void *iblMalloc (Uint32 size)
91 {
92 return (malloc (size));
93 }
95 /**
96 * @brief
97 * The free function used for both stages of the ibl
98 */
99 void iblFree (void *mem)
100 {
101 free (mem);
102 }
104 /**
105 * @brief
106 * The memset function used for both stages of the ibl
107 */
108 void *iblMemset (void *mem, Int32 ch, Uint32 n)
109 {
110 return (memset (mem, ch, n));
111 }
113 /**
114 * @brief
115 * The memcpy function used for both stages of the ibl
116 */
117 void *iblMemcpy (void *s1, const void *s2, Uint32 n)
118 {
119 return (memcpy (s1, s2, n));
121 }
123 /**
124 * @brief
125 * Ones complement addition
126 */
127 inline uint16 onesComplementAdd (uint16 value1, uint16 value2)
128 {
129 uint32 result;
131 result = (uint32)value1 + (uint32)value2;
133 result = (result >> 16) + (result & 0xFFFF); /* add in carry */
134 result += (result >> 16); /* maybe one more */
135 return ((uint16)result);
136 }
139 /**
140 * @brief
141 * Ones complement checksum computation
142 */
143 uint16 onesComplementChksum (uint16 * restrict p_data, uint16 len)
144 {
145 uint16 chksum = 0;
147 while (len > 0)
148 {
149 chksum = onesComplementAdd(chksum, *p_data);
150 p_data++;
151 len--;
152 }
153 return (chksum);
154 }
158 /**
159 * @brief
160 * Do a 4 byte endian swap
161 */
162 uint32 swap32val (uint32 v)
163 {
164 v = (((v >> 24) & 0xff) << 0) |
165 (((v >> 16) & 0xff) << 8) |
166 (((v >> 8) & 0xff) << 16) |
167 (((v >> 0) & 0xff) << 24);
169 return (v);
171 }
173 /**
174 * @brief
175 * Do a 2 byte endian swap
176 */
177 uint16 swap16val (uint16 v)
178 {
179 v = (((v >> 8) & 0xff) << 0) |
180 (((v >> 0) & 0xff) << 8);
182 return (v);
184 }
186 /**
187 * @brief
188 * Do an endian swap on the ibl structure
189 */
190 void iblSwap (void)
191 {
192 int i, j, k;
194 ibl.iblMagic = swap32val (ibl.iblMagic);
196 for (i = 0; i < ibl_N_PLL_CFGS; i++) {
197 ibl.pllConfig[i].doEnable = swap16val (ibl.pllConfig[i].doEnable);
198 ibl.pllConfig[i].prediv = swap32val (ibl.pllConfig[i].prediv);
199 ibl.pllConfig[i].mult = swap32val (ibl.pllConfig[i].mult);
200 ibl.pllConfig[i].postdiv = swap32val (ibl.pllConfig[i].postdiv);
201 ibl.pllConfig[i].pllOutFreqMhz = swap32val (ibl.pllConfig[i].pllOutFreqMhz);
202 }
204 ibl.ddrConfig.configDdr = swap16val (ibl.ddrConfig.configDdr);
207 if (targetEmifType() == ibl_EMIF_TYPE_31) {
208 ibl.ddrConfig.uEmif.emif3p1.sdcfg = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdcfg);
209 ibl.ddrConfig.uEmif.emif3p1.sdrfc = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdrfc);
210 ibl.ddrConfig.uEmif.emif3p1.sdtim1 = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdtim1);
211 ibl.ddrConfig.uEmif.emif3p1.sdtim2 = swap32val(ibl.ddrConfig.uEmif.emif3p1.sdtim2);
212 ibl.ddrConfig.uEmif.emif3p1.dmcctl = swap32val(ibl.ddrConfig.uEmif.emif3p1.dmcctl);
214 } else if (targetEmifType() == ibl_EMIF_TYPE_40) {
215 ibl.ddrConfig.uEmif.emif4p0.registerMask = swap32val(ibl.ddrConfig.uEmif.emif4p0.registerMask);
216 ibl.ddrConfig.uEmif.emif4p0.sdRamConfig = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamConfig);
217 ibl.ddrConfig.uEmif.emif4p0.sdRamConfig2 = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamConfig2);
218 ibl.ddrConfig.uEmif.emif4p0.sdRamRefreshCtl = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamRefreshCtl);
219 ibl.ddrConfig.uEmif.emif4p0.sdRamTiming1 = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamTiming1);
220 ibl.ddrConfig.uEmif.emif4p0.sdRamTiming2 = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamTiming2);
221 ibl.ddrConfig.uEmif.emif4p0.sdRamTiming3 = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamTiming3);
222 ibl.ddrConfig.uEmif.emif4p0.lpDdrNvmTiming = swap32val(ibl.ddrConfig.uEmif.emif4p0.lpDdrNvmTiming);
223 ibl.ddrConfig.uEmif.emif4p0.powerManageCtl = swap32val(ibl.ddrConfig.uEmif.emif4p0.powerManageCtl);
224 ibl.ddrConfig.uEmif.emif4p0.iODFTTestLogic = swap32val(ibl.ddrConfig.uEmif.emif4p0.iODFTTestLogic);
225 ibl.ddrConfig.uEmif.emif4p0.performCountCfg = swap32val(ibl.ddrConfig.uEmif.emif4p0.performCountCfg);
226 ibl.ddrConfig.uEmif.emif4p0.performCountMstRegSel = swap32val(ibl.ddrConfig.uEmif.emif4p0.performCountMstRegSel);
227 ibl.ddrConfig.uEmif.emif4p0.readIdleCtl = swap32val(ibl.ddrConfig.uEmif.emif4p0.readIdleCtl);
228 ibl.ddrConfig.uEmif.emif4p0.sysVbusmIntEnSet = swap32val(ibl.ddrConfig.uEmif.emif4p0.sysVbusmIntEnSet);
229 ibl.ddrConfig.uEmif.emif4p0.sdRamOutImpdedCalCfg = swap32val(ibl.ddrConfig.uEmif.emif4p0.sdRamOutImpdedCalCfg);
230 ibl.ddrConfig.uEmif.emif4p0.tempAlterCfg = swap32val(ibl.ddrConfig.uEmif.emif4p0.tempAlterCfg);
231 ibl.ddrConfig.uEmif.emif4p0.ddrPhyCtl1 = swap32val(ibl.ddrConfig.uEmif.emif4p0.ddrPhyCtl1);
232 ibl.ddrConfig.uEmif.emif4p0.ddrPhyCtl2 = swap32val(ibl.ddrConfig.uEmif.emif4p0.ddrPhyCtl2);
233 ibl.ddrConfig.uEmif.emif4p0.priClassSvceMap = swap32val(ibl.ddrConfig.uEmif.emif4p0.priClassSvceMap);
234 ibl.ddrConfig.uEmif.emif4p0.mstId2ClsSvce1Map = swap32val(ibl.ddrConfig.uEmif.emif4p0.mstId2ClsSvce1Map);
235 ibl.ddrConfig.uEmif.emif4p0.mstId2ClsSvce2Map = swap32val(ibl.ddrConfig.uEmif.emif4p0.mstId2ClsSvce2Map);
236 ibl.ddrConfig.uEmif.emif4p0.eccCtl = swap32val(ibl.ddrConfig.uEmif.emif4p0.eccCtl);
237 ibl.ddrConfig.uEmif.emif4p0.eccRange1 = swap32val(ibl.ddrConfig.uEmif.emif4p0.eccRange1);
238 ibl.ddrConfig.uEmif.emif4p0.eccRange2 = swap32val(ibl.ddrConfig.uEmif.emif4p0.eccRange2);
239 ibl.ddrConfig.uEmif.emif4p0.rdWrtExcThresh = swap32val(ibl.ddrConfig.uEmif.emif4p0.rdWrtExcThresh);
240 }
243 for (i = 0; i < ibl_N_ETH_PORTS; i++) {
244 ibl.sgmiiConfig[i].configure = swap16val(ibl.sgmiiConfig[i].configure);
245 ibl.sgmiiConfig[i].adviseAbility = swap32val(ibl.sgmiiConfig[i].adviseAbility);
246 ibl.sgmiiConfig[i].control = swap32val(ibl.sgmiiConfig[i].control);
247 ibl.sgmiiConfig[i].txConfig = swap32val(ibl.sgmiiConfig[i].txConfig);
248 ibl.sgmiiConfig[i].rxConfig = swap32val(ibl.sgmiiConfig[i].rxConfig);
249 ibl.sgmiiConfig[i].auxConfig = swap32val(ibl.sgmiiConfig[i].auxConfig);
250 }
253 ibl.mdioConfig.nMdioOps = swap16val (ibl.mdioConfig.nMdioOps);
254 ibl.mdioConfig.mdioClkDiv = swap16val (ibl.mdioConfig.mdioClkDiv);
255 ibl.mdioConfig.interDelay = swap32val (ibl.mdioConfig.interDelay);
257 for (i = 0; i < ibl_N_MDIO_CFGS; i++)
258 ibl.mdioConfig.mdio[i] = swap32val (ibl.mdioConfig.mdio[i]);
261 ibl.spiConfig.addrWidth = swap16val(ibl.spiConfig.addrWidth);
262 ibl.spiConfig.nPins = swap16val(ibl.spiConfig.nPins);
263 ibl.spiConfig.mode = swap16val(ibl.spiConfig.mode);
264 ibl.spiConfig.csel = swap16val(ibl.spiConfig.csel);
265 ibl.spiConfig.c2tdelay = swap16val(ibl.spiConfig.c2tdelay);
266 ibl.spiConfig.busFreqMHz = swap16val(ibl.spiConfig.busFreqMHz);
268 for (i = 0; i < ibl_MAX_EMIF_PMEM; i++) {
269 ibl.emifConfig[i].csSpace = swap16val(ibl.emifConfig[i].csSpace);
270 ibl.emifConfig[i].busWidth = swap16val(ibl.emifConfig[i].busWidth);
271 ibl.emifConfig[i].waitEnable = swap16val(ibl.emifConfig[i].waitEnable);
272 }
275 for (i = 0; i < ibl_N_BOOT_MODES; i++) {
276 ibl.bootModes[i].bootMode = swap32val(ibl.bootModes[i].bootMode);
277 ibl.bootModes[i].priority = swap32val(ibl.bootModes[i].priority);
278 ibl.bootModes[i].port = swap32val(ibl.bootModes[i].port);
280 if (ibl.bootModes[i].bootMode == ibl_BOOT_MODE_TFTP) {
281 ibl.bootModes[i].u.ethBoot.doBootp = swap16val(ibl.bootModes[i].u.ethBoot.doBootp);
282 ibl.bootModes[i].u.ethBoot.useBootpServerIp = swap16val(ibl.bootModes[i].u.ethBoot.useBootpServerIp);
283 ibl.bootModes[i].u.ethBoot.useBootpFileName = swap16val(ibl.bootModes[i].u.ethBoot.useBootpFileName);
284 ibl.bootModes[i].u.ethBoot.bootFormat = swap32val(ibl.bootModes[i].u.ethBoot.bootFormat);
285 ibl.bootModes[i].u.ethBoot.blob.startAddress = swap32val(ibl.bootModes[i].u.ethBoot.blob.startAddress);
286 ibl.bootModes[i].u.ethBoot.blob.sizeBytes = swap32val(ibl.bootModes[i].u.ethBoot.blob.sizeBytes);
287 ibl.bootModes[i].u.ethBoot.blob.branchAddress = swap32val(ibl.bootModes[i].u.ethBoot.blob.branchAddress);
289 } else if (ibl.bootModes[i].bootMode == ibl_BOOT_MODE_NAND) {
290 ibl.bootModes[i].u.nandBoot.bootFormat = swap32val(ibl.bootModes[i].u.nandBoot.bootFormat);
291 for (j = 0; j < ibl_N_ENDIANS; j++)
292 {
293 for (k = 0; k < ibl_N_IMAGES; k++)
294 {
295 ibl.bootModes[i].u.nandBoot.bootAddress[j][k] = swap32val(ibl.bootModes[i].u.nandBoot.bootAddress[j][k]);
296 }
297 }
298 ibl.bootModes[i].u.nandBoot.interface = swap32val(ibl.bootModes[i].u.nandBoot.interface);
299 for (j = 0; j < ibl_N_ENDIANS; j++)
300 {
301 for (k = 0; k < ibl_N_IMAGES; k++)
302 {
303 ibl.bootModes[i].u.nandBoot.blob[j][k].startAddress = swap32val(ibl.bootModes[i].u.nandBoot.blob[j][k].startAddress);
304 ibl.bootModes[i].u.nandBoot.blob[j][k].sizeBytes = swap32val(ibl.bootModes[i].u.nandBoot.blob[j][k].sizeBytes);
305 ibl.bootModes[i].u.nandBoot.blob[j][k].branchAddress = swap32val(ibl.bootModes[i].u.nandBoot.blob[j][k].branchAddress);
306 }
307 }
308 ibl.bootModes[i].u.nandBoot.nandInfo.busWidthBits = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.busWidthBits);
309 ibl.bootModes[i].u.nandBoot.nandInfo.pageSizeBytes = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.pageSizeBytes);
310 ibl.bootModes[i].u.nandBoot.nandInfo.pageEccBytes = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.pageEccBytes);
311 ibl.bootModes[i].u.nandBoot.nandInfo.pagesPerBlock = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.pagesPerBlock);
312 ibl.bootModes[i].u.nandBoot.nandInfo.totalBlocks = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.totalBlocks);
313 ibl.bootModes[i].u.nandBoot.nandInfo.addressBytes = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.addressBytes);
314 ibl.bootModes[i].u.nandBoot.nandInfo.lsbFirst = swap16val(ibl.bootModes[i].u.nandBoot.nandInfo.lsbFirst);
315 ibl.bootModes[i].u.nandBoot.nandInfo.blockOffset = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.blockOffset);
316 ibl.bootModes[i].u.nandBoot.nandInfo.pageOffset = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.pageOffset);
317 ibl.bootModes[i].u.nandBoot.nandInfo.columnOffset = swap32val(ibl.bootModes[i].u.nandBoot.nandInfo.columnOffset);
318 ibl.bootModes[i].u.nandBoot.nandInfo.postCommand = swap16val(ibl.bootModes[i].u.nandBoot.nandInfo.postCommand);
319 } else if (ibl.bootModes[i].bootMode == ibl_BOOT_MODE_NOR) {
320 ibl.bootModes[i].u.norBoot.bootFormat = swap32val(ibl.bootModes[i].u.norBoot.bootFormat);
321 for (j = 0; j < ibl_N_ENDIANS; j++)
322 {
323 for (k = 0; k < ibl_N_IMAGES; k++)
324 {
325 ibl.bootModes[i].u.norBoot.bootAddress[j][k] = swap32val(ibl.bootModes[i].u.norBoot.bootAddress[j][k]);
326 }
327 }
328 ibl.bootModes[i].u.norBoot.interface = swap32val(ibl.bootModes[i].u.norBoot.interface);
329 for (j = 0; j < ibl_N_ENDIANS; j++)
330 {
331 for (k = 0; k < ibl_N_IMAGES; k++)
332 {
333 ibl.bootModes[i].u.norBoot.blob[j][k].startAddress = swap32val(ibl.bootModes[i].u.norBoot.blob[j][k].startAddress);
334 ibl.bootModes[i].u.norBoot.blob[j][k].sizeBytes = swap32val(ibl.bootModes[i].u.norBoot.blob[j][k].sizeBytes);
335 ibl.bootModes[i].u.norBoot.blob[j][k].branchAddress = swap32val(ibl.bootModes[i].u.norBoot.blob[j][k].branchAddress);
336 }
337 }
339 }
341 }
343 ibl.iblEvmType = swap16val (ibl.iblEvmType);
344 ibl.chkSum = swap16val (ibl.chkSum);
345 }
349 /**
350 * @brief
351 * The init load context consists of the address of the next block
352 * to read, and a simple fifo-ish structure holding any existing data.
353 *
354 * A full fifo is not defined here. The individual init load blocks
355 * (I2C, SPI NOR, SPI NAND) will poke the structure values directly
356 * to minimize the compiled code size. Most notably is the absence
357 * of the write function. This fifo will always be completely emptied
358 * before any writes are done, so writes are always done from the top.
359 */
360 uint32 iFifoIn = 0;
361 uint32 iFifoOut = 0;
362 uint8 iData[I_MAX_BLOCK_SIZE];
364 /**
365 * @brief
366 * Checkum calculation. 16 bit values constructed from received bytes
367 * always in big endian format, regardless of the endianness of the device
368 */
369 uint16 iSum[I_MAX_BLOCK_SIZE >> 1];
372 /**
373 * @brief
374 * Return the number of elements in the fifo
375 */
376 Uint32 iFifoCount (void)
377 {
378 Int32 count;
380 if (iFifoIn >= iFifoOut)
381 count = iFifoIn - iFifoOut;
382 else
383 count = iFifoIn + I_MAX_BLOCK_SIZE - iFifoOut;
385 return (count);
387 }
390 /**
391 * @brief
392 * Read a byte from the fifo
393 */
394 Uint8 iFifoRead(void)
395 {
396 Uint8 v;
398 v = iData[iFifoOut];
400 iFifoOut += 1;
402 if (iFifoOut == iFifoIn)
403 iFifoOut = iFifoIn = 0;
405 if (iFifoOut >= I_MAX_BLOCK_SIZE)
406 iFifoOut = 0;
408 return (v);
410 }
413 #define iblBITMASK(x,y) ( ( ( ((UINT32)1 << (((UINT32)x)-((UINT32)y)+(UINT32)1) ) - (UINT32)1 ) ) << ((UINT32)y) )
414 #define iblREAD_BITFIELD(z,x,y) (((UINT32)z) & iblBITMASK(x,y)) >> (y)
415 /**
416 * @brief
417 * Return the lower 16 bits of a 32 bit value. A function is used (with cross-function optomization off)
418 * which results in an endian independent version
419 */
420 uint16 readLower16 (uint32 v)
421 {
422 return (iblREAD_BITFIELD(v,15,0));
424 }
426 /**
427 * @brief
428 * Return the upper 16 bits of a 32 bit value. A function is used to force an endian independent version
429 */
430 uint16 readUpper16 (uint32 v)
431 {
432 return (iblREAD_BITFIELD(v,31,16));
433 }
437 /**
438 * @brief
439 * The main function
440 *
441 * @details
442 * The ibl configuration parameters are read from the i2c,
443 * followed by the i2c mapping information. The second stage
444 * of the IBL is then loaded, and execution transferred
445 * to the second stage.
446 */
447 void main (void)
448 {
450 int32 bootDevice;
451 uint32 entry;
452 void (*exit)();
454 BOOT_MODULE_FXN_TABLE *bFxnTbl;
456 memset (&iblStatus, 0, sizeof(iblStatus_t));
457 iblStatus.iblMagic = ibl_MAGIC_VALUE;
458 iblStatus.iblVersion = ibl_VERSION;
459 iblStatus.activeDevice = ibl_ACTIVE_DEVICE_I2C;
462 /* Determine the boot device to read from */
463 bootDevice = deviceReadBootDevice();
465 switch (bootDevice) {
467 #ifndef EXCLUDE_I2C
468 case BOOT_DEVICE_I2C: bFxnTbl = iblInitI2c ();
469 break;
470 #endif
472 #ifndef EXCLUDE_NOR_SPI
473 case BOOT_DEVICE_SPI_NOR: bFxnTbl = iblInitSpiNor ();
474 break;
475 #endif
478 default: iblStatus.iblFail = ibl_FAIL_CODE_INVALID_INIT_DEVICE;
479 for (;;);
481 }
484 /* Pll configuration is device specific */
485 devicePllConfig ();
487 /* Enable the EDC for local memory */
488 if (IBL_ENABLE_EDC)
489 {
490 iblEnableEDC ();
491 }
493 /* Check if need to enter Rom boot loader again */
494 if (IBL_ENTER_ROM)
495 {
496 iblEnterRom ();
497 }
499 /* Pass control to the boot table processor */
500 iblBootBtbl (bFxnTbl, &entry);
502 if (btblWrapEcode != 0) {
503 iblStatus.iblFail = ibl_FAIL_CODE_BTBL_FAIL;
504 for (;;);
505 }
507 /* jump to the exit point, which will be the entry point for the full IBL */
508 exit = (void (*)())entry;
509 (*exit)();
512 }