nbi.c File Reference

NBI image format. More...

#include <errno.h>
#include <assert.h>
#include <realmode.h>
#include <gateA20.h>
#include <memsizes.h>
#include <basemem_packet.h>
#include <gpxe/uaccess.h>
#include <gpxe/segment.h>
#include <gpxe/init.h>
#include <gpxe/netdevice.h>
#include <gpxe/fakedhcp.h>
#include <gpxe/image.h>
#include <gpxe/features.h>

Go to the source code of this file.

Data Structures

struct  imgheader
 An NBI image header. More...
struct  segheader
 An NBI segment header. More...
struct  ebinfo

Defines

#define NBI_MAGIC   0x1B031336UL
 NBI magic number.
#define NBI_NONVENDOR_LENGTH(len)   ( ( (len) & 0x0f ) << 2 )
#define NBI_VENDOR_LENGTH(len)   ( ( (len) & 0xf0 ) >> 2 )
#define NBI_LENGTH(len)   ( NBI_NONVENDOR_LENGTH(len) + NBI_VENDOR_LENGTH(len) )
#define NBI_PROGRAM_RETURNS(flags)   ( (flags) & ( 1 << 8 ) )
#define NBI_LINEAR_EXEC_ADDR(flags)   ( (flags) & ( 1 << 31 ) )
#define NBI_HEADER_LENGTH   512
 NBI header length.
#define NBI_LOADADDR_FLAGS(flags)   ( (flags) & 0x03 )
#define NBI_LOADADDR_ABS   0x00
#define NBI_LOADADDR_AFTER   0x01
#define NBI_LOADADDR_END   0x02
#define NBI_LOADADDR_BEFORE   0x03
#define NBI_LAST_SEGHEADER(flags)   ( (flags) & ( 1 << 2 ) )

Functions

 FEATURE (FEATURE_IMAGE,"NBI", DHCP_EB_FEATURE_NBI, 1)
struct image_type nbi_image_type __image_type (PROBE_NORMAL)
 NBI image type.
static int nbi_prepare_segment (struct image *image, size_t offset __unused, userptr_t dest, size_t filesz, size_t memsz)
 Prepare a segment for an NBI image.
static int nbi_load_segment (struct image *image, size_t offset, userptr_t dest, size_t filesz, size_t memsz __unused)
 Load a segment for an NBI image.
static int nbi_process_segments (struct image *image, struct imgheader *imgheader, int(*process)(struct image *image, size_t offset, userptr_t dest, size_t filesz, size_t memsz))
 Process segments of an NBI image.
static int nbi_load (struct image *image)
 Load an NBI image into memory.
static int nbi_boot16 (struct image *image, struct imgheader *imgheader)
 Boot a 16-bit NBI image.
static int nbi_boot32 (struct image *image, struct imgheader *imgheader)
 Boot a 32-bit NBI image.
static int nbi_prepare_dhcp (struct image *image)
 Prepare DHCP parameter block for NBI image.
static int nbi_exec (struct image *image)
 Execute a loaded NBI image.

Variables

static struct ebinfo loaderinfo
 Info passed to NBI image.


Detailed Description

NBI image format.

The Net Boot Image format is defined by the "Draft Net Boot Image Proposal 0.3" by Jamie Honan, Gero Kuhlmann and Ken Yap. It is now considered to be a legacy format, but it still included because a large amount of software (e.g. nymph, LTSP) makes use of NBI files.

Etherboot does not implement the INT 78 callback interface described by the NBI specification. For a callback interface on x86 architecture, use PXE.

Definition in file nbi.c.


Define Documentation

#define NBI_MAGIC   0x1B031336UL

NBI magic number.

Definition at line 55 of file nbi.c.

Referenced by nbi_load().

#define NBI_NONVENDOR_LENGTH ( len   )     ( ( (len) & 0x0f ) << 2 )

Definition at line 58 of file nbi.c.

#define NBI_VENDOR_LENGTH ( len   )     ( ( (len) & 0xf0 ) >> 2 )

Definition at line 59 of file nbi.c.

#define NBI_LENGTH ( len   )     ( NBI_NONVENDOR_LENGTH(len) + NBI_VENDOR_LENGTH(len) )

Definition at line 60 of file nbi.c.

Referenced by nbi_process_segments().

#define NBI_PROGRAM_RETURNS ( flags   )     ( (flags) & ( 1 << 8 ) )

Definition at line 63 of file nbi.c.

Referenced by nbi_exec().

#define NBI_LINEAR_EXEC_ADDR ( flags   )     ( (flags) & ( 1 << 31 ) )

Definition at line 64 of file nbi.c.

Referenced by nbi_exec().

#define NBI_HEADER_LENGTH   512

NBI header length.

Definition at line 67 of file nbi.c.

Referenced by nbi_load(), and nbi_process_segments().

#define NBI_LOADADDR_FLAGS ( flags   )     ( (flags) & 0x03 )

Definition at line 87 of file nbi.c.

Referenced by nbi_process_segments().

#define NBI_LOADADDR_ABS   0x00

Definition at line 88 of file nbi.c.

Referenced by nbi_process_segments().

#define NBI_LOADADDR_AFTER   0x01

Definition at line 89 of file nbi.c.

Referenced by nbi_process_segments().

#define NBI_LOADADDR_END   0x02

Definition at line 90 of file nbi.c.

Referenced by nbi_process_segments().

#define NBI_LOADADDR_BEFORE   0x03

Definition at line 91 of file nbi.c.

Referenced by nbi_process_segments().

#define NBI_LAST_SEGHEADER ( flags   )     ( (flags) & ( 1 << 2 ) )

Definition at line 92 of file nbi.c.

Referenced by nbi_process_segments().


Function Documentation

FEATURE ( FEATURE_IMAGE  ,
"NBI"  ,
DHCP_EB_FEATURE_NBI  ,
 
)

struct image_type nbi_image_type __image_type ( PROBE_NORMAL   )  [read]

NBI image type.

static int nbi_prepare_segment ( struct image image,
size_t offset  __unused,
userptr_t  dest,
size_t  filesz,
size_t  memsz 
) [static]

Prepare a segment for an NBI image.

Parameters:
image NBI image
offset Offset within NBI image
filesz Length of initialised-data portion of the segment
memsz Total length of the segment
src Source for initialised data
Return values:
rc Return status code

Definition at line 116 of file nbi.c.

References DBGC, prep_segment(), and strerror().

Referenced by nbi_load().

00117                                                                               {
00118         int rc;
00119 
00120         if ( ( rc = prep_segment ( dest, filesz, memsz ) ) != 0 ) {
00121                 DBGC ( image, "NBI %p could not prepare segment: %s\n",
00122                        image, strerror ( rc ) );
00123                 return rc;
00124         }
00125 
00126         return 0;
00127 }

static int nbi_load_segment ( struct image image,
size_t  offset,
userptr_t  dest,
size_t  filesz,
size_t memsz  __unused 
) [static]

Load a segment for an NBI image.

Parameters:
image NBI image
offset Offset within NBI image
filesz Length of initialised-data portion of the segment
memsz Total length of the segment
src Source for initialised data
Return values:
rc Return status code

Definition at line 139 of file nbi.c.

References image::data, and memcpy_user().

Referenced by nbi_load().

00141                                                       {
00142         memcpy_user ( dest, 0, image->data, offset, filesz );
00143         return 0;
00144 }

static int nbi_process_segments ( struct image image,
struct imgheader imgheader,
int(*)(struct image *image, size_t offset, userptr_t dest, size_t filesz, size_t memsz)  process 
) [static]

Process segments of an NBI image.

Parameters:
image NBI image
imgheader Image header information
process Function to call for each segment
Return values:
rc Return status code

Definition at line 154 of file nbi.c.

References assert, copy_from_user(), image::data, DBGC, ENOEXEC, extmemsize(), segheader::flags, segheader::imglength, image::len, segheader::length, imgheader::length, segheader::loadaddr, imgheader::location, segheader::memlength, NBI_HEADER_LENGTH, NBI_LAST_SEGHEADER, NBI_LENGTH, NBI_LOADADDR_ABS, NBI_LOADADDR_AFTER, NBI_LOADADDR_BEFORE, NBI_LOADADDR_END, NBI_LOADADDR_FLAGS, segoff::offset, phys_to_user(), real_to_user(), segoff::segment, and userptr_add().

Referenced by nbi_load().

00160                                                                        {
00161         struct segheader sh;
00162         size_t offset = 0;
00163         size_t sh_off;
00164         userptr_t dest;
00165         size_t filesz;
00166         size_t memsz;
00167         int rc;
00168         
00169         /* Copy image header to target location */
00170         dest = real_to_user ( imgheader->location.segment,
00171                               imgheader->location.offset );
00172         filesz = memsz = NBI_HEADER_LENGTH;
00173         if ( ( rc = process ( image, offset, dest, filesz, memsz ) ) != 0 )
00174                 return rc;
00175         offset += filesz;
00176 
00177         /* Process segments in turn */
00178         sh_off = NBI_LENGTH ( imgheader->length );
00179         do {
00180                 /* Read segment header */
00181                 copy_from_user ( &sh, image->data, sh_off, sizeof ( sh ) );
00182                 if ( sh.length == 0 ) {
00183                         /* Avoid infinite loop? */
00184                         DBGC ( image, "NBI %p invalid segheader length 0\n",
00185                                image );
00186                         return -ENOEXEC;
00187                 }
00188                 
00189                 /* Calculate segment load address */
00190                 switch ( NBI_LOADADDR_FLAGS ( sh.flags ) ) {
00191                 case NBI_LOADADDR_ABS:
00192                         dest = phys_to_user ( sh.loadaddr );
00193                         break;
00194                 case NBI_LOADADDR_AFTER:
00195                         dest = userptr_add ( dest, memsz + sh.loadaddr );
00196                         break;
00197                 case NBI_LOADADDR_BEFORE:
00198                         dest = userptr_add ( dest, -sh.loadaddr );
00199                         break;
00200                 case NBI_LOADADDR_END:
00201                         /* Not correct according to the spec, but
00202                          * maintains backwards compatibility with
00203                          * previous versions of Etherboot.
00204                          */
00205                         dest = phys_to_user ( ( extmemsize() + 1024 ) * 1024
00206                                               - sh.loadaddr );
00207                         break;
00208                 default:
00209                         /* Cannot be reached */
00210                         assert ( 0 );
00211                 }
00212 
00213                 /* Process this segment */
00214                 filesz = sh.imglength;
00215                 memsz = sh.memlength;
00216                 if ( ( offset + filesz ) > image->len ) {
00217                         DBGC ( image, "NBI %p segment outside file\n", image );
00218                         return -ENOEXEC;
00219                 }
00220                 if ( ( rc = process ( image, offset, dest,
00221                                       filesz, memsz ) ) != 0 ) {
00222                         return rc;
00223                 }
00224                 offset += filesz;
00225 
00226                 /* Next segheader */
00227                 sh_off += NBI_LENGTH ( sh.length );
00228                 if ( sh_off >= NBI_HEADER_LENGTH ) {
00229                         DBGC ( image, "NBI %p header overflow\n", image );
00230                         return -ENOEXEC;
00231                 }
00232 
00233         } while ( ! NBI_LAST_SEGHEADER ( sh.flags ) );
00234 
00235         if ( offset != image->len ) {
00236                 DBGC ( image, "NBI %p length wrong (file %zd, metadata %zd)\n",
00237                        image, image->len, offset );
00238                 return -ENOEXEC;
00239         }
00240 
00241         return 0;
00242 }

static int nbi_load ( struct image image  )  [static]

Load an NBI image into memory.

Parameters:
image NBI image
Return values:
rc Return status code

Definition at line 250 of file nbi.c.

References copy_from_user(), image::data, DBGC, ENOEXEC, image::len, imgheader::location, imgheader::magic, NBI_HEADER_LENGTH, nbi_load_segment(), NBI_MAGIC, nbi_prepare_segment(), nbi_process_segments(), segoff::offset, image::priv, real_to_user(), segoff::segment, image::type, and image::user.

00250                                             {
00251         struct imgheader imgheader;
00252         int rc;
00253 
00254         /* If we don't have enough data give up */
00255         if ( image->len < NBI_HEADER_LENGTH ) {
00256                 DBGC ( image, "NBI %p too short for an NBI image\n", image );
00257                 return -ENOEXEC;
00258         }
00259 
00260         /* Check image header */
00261         copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );
00262         if ( imgheader.magic != NBI_MAGIC ) {
00263                 DBGC ( image, "NBI %p has no NBI signature\n", image );
00264                 return -ENOEXEC;
00265         }
00266 
00267         /* This is an NBI image, valid or otherwise */
00268         if ( ! image->type )
00269                 image->type = &nbi_image_type;
00270 
00271         DBGC ( image, "NBI %p placing header at %hx:%hx\n", image,
00272                imgheader.location.segment, imgheader.location.offset );
00273 
00274         /* NBI files can have overlaps between segments; the bss of
00275          * one segment may overlap the initialised data of another.  I
00276          * assume this is a design flaw, but there are images out
00277          * there that we need to work with.  We therefore do two
00278          * passes: first to initialise the segments, then to copy the
00279          * data.  This avoids zeroing out already-copied data.
00280          */
00281         if ( ( rc = nbi_process_segments ( image, &imgheader,
00282                                            nbi_prepare_segment ) ) != 0 )
00283                 return rc;
00284         if ( ( rc = nbi_process_segments ( image, &imgheader,
00285                                            nbi_load_segment ) ) != 0 )
00286                 return rc;
00287 
00288         /* Record header address in image private data field */
00289         image->priv.user = real_to_user ( imgheader.location.segment,
00290                                           imgheader.location.offset );
00291 
00292         return 0;
00293 }

static int nbi_boot16 ( struct image image,
struct imgheader imgheader 
) [static]

Boot a 16-bit NBI image.

Parameters:
imgheader Image header information
Return values:
rc Return status code, if image returns

Definition at line 301 of file nbi.c.

References __asm__(), __from_data16, basemem_packet, DBGC, imgheader::execaddr, gateA20_set(), gateA20_unset(), imgheader::location, segoff::offset, REAL_CODE, segoff::segment, and imgheader::segoff.

Referenced by nbi_exec().

00301                                                                            {
00302         int discard_D, discard_S, discard_b;
00303         int rc;
00304 
00305         DBGC ( image, "NBI %p executing 16-bit image at %04x:%04x\n", image,
00306                imgheader->execaddr.segoff.segment,
00307                imgheader->execaddr.segoff.offset );
00308 
00309         gateA20_unset();
00310 
00311         __asm__ __volatile__ (
00312                 REAL_CODE ( "pushw %%ds\n\t"    /* far pointer to bootp data */
00313                             "pushw %%bx\n\t"
00314                             "pushl %%esi\n\t"   /* location */
00315                             "pushw %%cs\n\t"    /* lcall execaddr */
00316                             "call 1f\n\t"
00317                             "jmp 2f\n\t"
00318                             "\n1:\n\t"
00319                             "pushl %%edi\n\t"
00320                             "lret\n\t"
00321                             "\n2:\n\t"
00322                             "addw $8,%%sp\n\t"  /* clean up stack */ )
00323                 : "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ),
00324                   "=b" ( discard_b )
00325                 : "D" ( imgheader->execaddr.segoff ),
00326                   "S" ( imgheader->location ),
00327                   "b" ( __from_data16 ( basemem_packet ) )
00328                 : "ecx", "edx", "ebp" );
00329 
00330         gateA20_set();
00331 
00332         return rc;
00333 }

static int nbi_boot32 ( struct image image,
struct imgheader imgheader 
) [static]

Boot a 32-bit NBI image.

Parameters:
imgheader Image header information
Return values:
rc Return status code, if image returns

Definition at line 341 of file nbi.c.

References __asm__(), basemem_packet, DBGC, imgheader::execaddr, imgheader::linear, imgheader::location, segoff::offset, PHYS_CODE, segoff::segment, and virt_to_phys().

Referenced by nbi_exec().

00341                                                                            {
00342         int discard_D, discard_S, discard_b;
00343         int rc;
00344 
00345         DBGC ( image, "NBI %p executing 32-bit image at %lx\n",
00346                image, imgheader->execaddr.linear );
00347 
00348         /* no gateA20_unset for PM call */
00349 
00350         /* Jump to OS with flat physical addressing */
00351         __asm__ __volatile__ (
00352                 PHYS_CODE ( "pushl %%ebx\n\t" /* bootp data */
00353                             "pushl %%esi\n\t" /* imgheader */
00354                             "pushl %%eax\n\t" /* loaderinfo */
00355                             "call *%%edi\n\t"
00356                             "addl $12, %%esp\n\t" /* clean up stack */ )
00357                 : "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ),
00358                   "=b" ( discard_b )
00359                 : "D" ( imgheader->execaddr.linear ),
00360                   "S" ( ( imgheader->location.segment << 4 ) +
00361                         imgheader->location.offset ),
00362                   "b" ( virt_to_phys ( basemem_packet ) ),
00363                   "a" ( virt_to_phys ( &loaderinfo ) )
00364                 : "ecx", "edx", "ebp", "memory" );
00365 
00366         return rc;
00367 }

static int nbi_prepare_dhcp ( struct image image  )  [static]

Prepare DHCP parameter block for NBI image.

Parameters:
image NBI image
Return values:
rc Return status code

Definition at line 375 of file nbi.c.

References basemem_packet, create_fakedhcpack(), DBGC, ENODEV, and last_opened_netdev().

Referenced by nbi_exec().

00375                                                     {
00376         struct net_device *boot_netdev;
00377         int rc;
00378 
00379         boot_netdev = last_opened_netdev();
00380         if ( ! boot_netdev ) {
00381                 DBGC ( image, "NBI %p could not identify a network device\n",
00382                        image );
00383                 return -ENODEV;
00384         }
00385 
00386         if ( ( rc = create_fakedhcpack ( boot_netdev, basemem_packet,
00387                                          sizeof ( basemem_packet ) ) ) != 0 ) {
00388                 DBGC ( image, "NBI %p failed to build DHCP packet\n", image );
00389                 return rc;
00390         }
00391 
00392         return 0;
00393 }

static int nbi_exec ( struct image image  )  [static]

Execute a loaded NBI image.

Parameters:
image NBI image
Return values:
rc Return status code

Definition at line 401 of file nbi.c.

References copy_from_user(), DBGC, imgheader::flags, nbi_boot16(), nbi_boot32(), NBI_LINEAR_EXEC_ADDR, nbi_prepare_dhcp(), NBI_PROGRAM_RETURNS, image::priv, shutdown(), SHUTDOWN_BOOT, and image::user.

00401                                             {
00402         struct imgheader imgheader;
00403         int may_return;
00404         int rc;
00405 
00406         copy_from_user ( &imgheader, image->priv.user, 0,
00407                          sizeof ( imgheader ) );
00408 
00409         /* Prepare DHCP option block */
00410         if ( ( rc = nbi_prepare_dhcp ( image ) ) != 0 )
00411                 return rc;
00412 
00413         /* Shut down now if NBI image will not return */
00414         may_return = NBI_PROGRAM_RETURNS ( imgheader.flags );
00415         if ( ! may_return )
00416                 shutdown ( SHUTDOWN_BOOT );
00417 
00418         /* Execute NBI image */
00419         if ( NBI_LINEAR_EXEC_ADDR ( imgheader.flags ) ) {
00420                 rc = nbi_boot32 ( image, &imgheader );
00421         } else {
00422                 rc = nbi_boot16 ( image, &imgheader );
00423         }
00424 
00425         if ( ! may_return ) {
00426                 /* Cannot continue after shutdown() called */
00427                 DBGC ( image, "NBI %p returned %d from non-returnable image\n",
00428                        image, rc  );
00429                 while ( 1 ) {}
00430         }
00431 
00432         DBGC ( image, "NBI %p returned %d\n", image, rc );
00433 
00434         return rc;
00435 }


Variable Documentation

struct ebinfo loaderinfo [static]

Initial value:

 {
        VERSION_MAJOR, VERSION_MINOR,
        0
}
Info passed to NBI image.

Definition at line 101 of file nbi.c.


Generated on Tue Apr 6 20:01:12 2010 for gPXE by  doxygen 1.5.7.1