iPXE
Data Structures | Defines | Functions
nbi.c File Reference

NBI image format. More...

#include <errno.h>
#include <assert.h>
#include <realmode.h>
#include <memsizes.h>
#include <basemem_packet.h>
#include <ipxe/uaccess.h>
#include <ipxe/segment.h>
#include <ipxe/init.h>
#include <ipxe/netdevice.h>
#include <ipxe/fakedhcp.h>
#include <ipxe/image.h>
#include <ipxe/features.h>
#include <ipxe/version.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)
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_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.
static int nbi_probe (struct image *image)
 Probe NBI image.
struct image_type nbi_image_type __image_type (PROBE_NORMAL)
 NBI image type.

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 53 of file nbi.c.

Referenced by nbi_probe().

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

Definition at line 56 of file nbi.c.

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

Definition at line 57 of file nbi.c.

Definition at line 58 of file nbi.c.

Referenced by nbi_process_segments().

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

Definition at line 61 of file nbi.c.

Referenced by nbi_exec().

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

Definition at line 62 of file nbi.c.

Referenced by nbi_exec().

#define NBI_HEADER_LENGTH   512

NBI header length.

Definition at line 65 of file nbi.c.

Referenced by nbi_probe(), and nbi_process_segments().

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

Definition at line 85 of file nbi.c.

Referenced by nbi_process_segments().

#define NBI_LOADADDR_ABS   0x00

Definition at line 86 of file nbi.c.

Referenced by nbi_process_segments().

#define NBI_LOADADDR_AFTER   0x01

Definition at line 87 of file nbi.c.

Referenced by nbi_process_segments().

#define NBI_LOADADDR_END   0x02

Definition at line 88 of file nbi.c.

Referenced by nbi_process_segments().

#define NBI_LOADADDR_BEFORE   0x03

Definition at line 89 of file nbi.c.

Referenced by nbi_process_segments().

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

Definition at line 90 of file nbi.c.

Referenced by nbi_process_segments().


Function Documentation

FEATURE ( FEATURE_IMAGE  ,
"NBI"  ,
DHCP_EB_FEATURE_NBI  ,
 
)
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:
imageNBI image
offsetOffset within NBI image
fileszLength of initialised-data portion of the segment
memszTotal length of the segment
srcSource for initialised data
Return values:
rcReturn status code

Definition at line 108 of file nbi.c.

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

Referenced by nbi_exec().

                                                                              {
        int rc;

        if ( ( rc = prep_segment ( dest, filesz, memsz ) ) != 0 ) {
                DBGC ( image, "NBI %p could not prepare segment: %s\n",
                       image, strerror ( rc ) );
                return rc;
        }

        return 0;
}
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:
imageNBI image
offsetOffset within NBI image
fileszLength of initialised-data portion of the segment
memszTotal length of the segment
srcSource for initialised data
Return values:
rcReturn status code

Definition at line 131 of file nbi.c.

References image::data, and memcpy_user().

Referenced by nbi_exec().

                                                      {
        memcpy_user ( dest, 0, image->data, offset, filesz );
        return 0;
}
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:
imageNBI image
imgheaderImage header information
processFunction to call for each segment
Return values:
rcReturn status code

Definition at line 146 of file nbi.c.

References assert, copy_from_user(), image::data, DBGC, dest, ENOEXEC, extmemsize(), segheader::flags, segheader::imglength, image::len, imgheader::length, segheader::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(), rc, real_to_user(), segoff::segment, and userptr_add().

Referenced by nbi_exec().

                                                                       {
        struct segheader sh;
        size_t offset = 0;
        size_t sh_off;
        userptr_t dest;
        size_t filesz;
        size_t memsz;
        int rc;
        
        /* Copy image header to target location */
        dest = real_to_user ( imgheader->location.segment,
                              imgheader->location.offset );
        filesz = memsz = NBI_HEADER_LENGTH;
        if ( ( rc = process ( image, offset, dest, filesz, memsz ) ) != 0 )
                return rc;
        offset += filesz;

        /* Process segments in turn */
        sh_off = NBI_LENGTH ( imgheader->length );
        do {
                /* Read segment header */
                copy_from_user ( &sh, image->data, sh_off, sizeof ( sh ) );
                if ( sh.length == 0 ) {
                        /* Avoid infinite loop? */
                        DBGC ( image, "NBI %p invalid segheader length 0\n",
                               image );
                        return -ENOEXEC;
                }
                
                /* Calculate segment load address */
                switch ( NBI_LOADADDR_FLAGS ( sh.flags ) ) {
                case NBI_LOADADDR_ABS:
                        dest = phys_to_user ( sh.loadaddr );
                        break;
                case NBI_LOADADDR_AFTER:
                        dest = userptr_add ( dest, memsz + sh.loadaddr );
                        break;
                case NBI_LOADADDR_BEFORE:
                        dest = userptr_add ( dest, -sh.loadaddr );
                        break;
                case NBI_LOADADDR_END:
                        /* Not correct according to the spec, but
                         * maintains backwards compatibility with
                         * previous versions of Etherboot.
                         */
                        dest = phys_to_user ( ( extmemsize() + 1024 ) * 1024
                                              - sh.loadaddr );
                        break;
                default:
                        /* Cannot be reached */
                        assert ( 0 );
                }

                /* Process this segment */
                filesz = sh.imglength;
                memsz = sh.memlength;
                if ( ( offset + filesz ) > image->len ) {
                        DBGC ( image, "NBI %p segment outside file\n", image );
                        return -ENOEXEC;
                }
                if ( ( rc = process ( image, offset, dest,
                                      filesz, memsz ) ) != 0 ) {
                        return rc;
                }
                offset += filesz;

                /* Next segheader */
                sh_off += NBI_LENGTH ( sh.length );
                if ( sh_off >= NBI_HEADER_LENGTH ) {
                        DBGC ( image, "NBI %p header overflow\n", image );
                        return -ENOEXEC;
                }

        } while ( ! NBI_LAST_SEGHEADER ( sh.flags ) );

        if ( offset != image->len ) {
                DBGC ( image, "NBI %p length wrong (file %zd, metadata %zd)\n",
                       image, image->len, offset );
                return -ENOEXEC;
        }

        return 0;
}
static int nbi_boot16 ( struct image image,
struct imgheader imgheader 
) [static]

Boot a 16-bit NBI image.

Parameters:
imgheaderImage header information
Return values:
rcReturn status code, if image returns

Definition at line 242 of file nbi.c.

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

Referenced by nbi_exec().

                                                                           {
        int discard_D, discard_S, discard_b;
        int32_t rc;

        DBGC ( image, "NBI %p executing 16-bit image at %04x:%04x\n", image,
               imgheader->execaddr.segoff.segment,
               imgheader->execaddr.segoff.offset );

        __asm__ __volatile__ (
                REAL_CODE ( "pushl %%ebp\n\t"   /* gcc bug */
                            "pushw %%ds\n\t"    /* far pointer to bootp data */
                            "pushw %%bx\n\t"
                            "pushl %%esi\n\t"   /* location */
                            "pushw %%cs\n\t"    /* lcall execaddr */
                            "call 1f\n\t"
                            "jmp 2f\n\t"
                            "\n1:\n\t"
                            "pushl %%edi\n\t"
                            "lret\n\t"
                            "\n2:\n\t"
                            "addw $8,%%sp\n\t"  /* clean up stack */
                            "popl %%ebp\n\t"    /* gcc bug */ )
                : "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ),
                  "=b" ( discard_b )
                : "D" ( imgheader->execaddr.segoff ),
                  "S" ( imgheader->location ),
                  "b" ( __from_data16 ( basemem_packet ) )
                : "ecx", "edx" );

        return rc;
}
static int nbi_boot32 ( struct image image,
struct imgheader imgheader 
) [static]

Boot a 32-bit NBI image.

Parameters:
imgheaderImage header information
Return values:
rcReturn status code, if image returns

Definition at line 280 of file nbi.c.

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

Referenced by nbi_exec().

                                                                           {
        struct ebinfo loaderinfo = {
                product_major_version, product_minor_version,
                0
        };
        int discard_D, discard_S, discard_b;
        int32_t rc;

        DBGC ( image, "NBI %p executing 32-bit image at %lx\n",
               image, imgheader->execaddr.linear );

        /* Jump to OS with flat physical addressing */
        __asm__ __volatile__ (
                PHYS_CODE ( "pushl %%ebp\n\t" /* gcc bug */
                            "pushl %%ebx\n\t" /* bootp data */
                            "pushl %%esi\n\t" /* imgheader */
                            "pushl %%eax\n\t" /* loaderinfo */
                            "call *%%edi\n\t"
                            "addl $12, %%esp\n\t" /* clean up stack */
                            "popl %%ebp\n\t" /* gcc bug */ )
                : "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ),
                  "=b" ( discard_b )
                : "D" ( imgheader->execaddr.linear ),
                  "S" ( ( imgheader->location.segment << 4 ) +
                        imgheader->location.offset ),
                  "b" ( virt_to_phys ( basemem_packet ) ),
                  "a" ( virt_to_phys ( &loaderinfo ) )
                : "ecx", "edx", "memory" );

        return rc;
}
static int nbi_prepare_dhcp ( struct image image) [static]

Prepare DHCP parameter block for NBI image.

Parameters:
imageNBI image
Return values:
rcReturn status code

Definition at line 318 of file nbi.c.

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

Referenced by nbi_exec().

                                                    {
        struct net_device *boot_netdev;
        int rc;

        boot_netdev = last_opened_netdev();
        if ( ! boot_netdev ) {
                DBGC ( image, "NBI %p could not identify a network device\n",
                       image );
                return -ENODEV;
        }

        if ( ( rc = create_fakedhcpack ( boot_netdev, basemem_packet,
                                         sizeof ( basemem_packet ) ) ) != 0 ) {
                DBGC ( image, "NBI %p failed to build DHCP packet\n", image );
                return rc;
        }

        return 0;
}
static int nbi_exec ( struct image image) [static]

Execute a loaded NBI image.

Parameters:
imageNBI image
Return values:
rcReturn status code

Definition at line 344 of file nbi.c.

References copy_from_user(), image::data, DBGC, imgheader::flags, imgheader::location, nbi_boot16(), nbi_boot32(), NBI_LINEAR_EXEC_ADDR, nbi_load_segment(), nbi_prepare_dhcp(), nbi_prepare_segment(), nbi_process_segments(), NBI_PROGRAM_RETURNS, segoff::offset, rc, segoff::segment, and shutdown_boot().

                                            {
        struct imgheader imgheader;
        int may_return;
        int rc;

        /* Retrieve image header */
        copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );

        DBGC ( image, "NBI %p placing header at %hx:%hx\n", image,
               imgheader.location.segment, imgheader.location.offset );

        /* NBI files can have overlaps between segments; the bss of
         * one segment may overlap the initialised data of another.  I
         * assume this is a design flaw, but there are images out
         * there that we need to work with.  We therefore do two
         * passes: first to initialise the segments, then to copy the
         * data.  This avoids zeroing out already-copied data.
         */
        if ( ( rc = nbi_process_segments ( image, &imgheader,
                                           nbi_prepare_segment ) ) != 0 )
                return rc;
        if ( ( rc = nbi_process_segments ( image, &imgheader,
                                           nbi_load_segment ) ) != 0 )
                return rc;

        /* Prepare DHCP option block */
        if ( ( rc = nbi_prepare_dhcp ( image ) ) != 0 )
                return rc;

        /* Shut down now if NBI image will not return */
        may_return = NBI_PROGRAM_RETURNS ( imgheader.flags );
        if ( ! may_return )
                shutdown_boot();

        /* Execute NBI image */
        if ( NBI_LINEAR_EXEC_ADDR ( imgheader.flags ) ) {
                rc = nbi_boot32 ( image, &imgheader );
        } else {
                rc = nbi_boot16 ( image, &imgheader );
        }

        if ( ! may_return ) {
                /* Cannot continue after shutdown() called */
                DBGC ( image, "NBI %p returned %d from non-returnable image\n",
                       image, rc  );
                while ( 1 ) {}
        }

        DBGC ( image, "NBI %p returned %d\n", image, rc );

        return rc;
}
static int nbi_probe ( struct image image) [static]

Probe NBI image.

Parameters:
imageNBI image
Return values:
rcReturn status code

Definition at line 403 of file nbi.c.

References copy_from_user(), image::data, DBGC, ENOEXEC, image::len, imgheader::magic, NBI_HEADER_LENGTH, and NBI_MAGIC.

                                             {
        struct imgheader imgheader;

        /* If we don't have enough data give up */
        if ( image->len < NBI_HEADER_LENGTH ) {
                DBGC ( image, "NBI %p too short for an NBI image\n", image );
                return -ENOEXEC;
        }

        /* Check image header */
        copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );
        if ( imgheader.magic != NBI_MAGIC ) {
                DBGC ( image, "NBI %p has no NBI signature\n", image );
                return -ENOEXEC;
        }

        return 0;
}
struct image_type nbi_image_type __image_type ( PROBE_NORMAL  ) [read]

NBI image type.