Annotation of qemu/roms/ipxe/src/arch/i386/image/nbi.c, revision 1.1.1.1

1.1       root        1: #include <errno.h>
                      2: #include <assert.h>
                      3: #include <realmode.h>
                      4: #include <memsizes.h>
                      5: #include <basemem_packet.h>
                      6: #include <ipxe/uaccess.h>
                      7: #include <ipxe/segment.h>
                      8: #include <ipxe/init.h>
                      9: #include <ipxe/netdevice.h>
                     10: #include <ipxe/fakedhcp.h>
                     11: #include <ipxe/image.h>
                     12: #include <ipxe/features.h>
                     13: 
                     14: /** @file
                     15:  *
                     16:  * NBI image format.
                     17:  *
                     18:  * The Net Boot Image format is defined by the "Draft Net Boot Image
                     19:  * Proposal 0.3" by Jamie Honan, Gero Kuhlmann and Ken Yap.  It is now
                     20:  * considered to be a legacy format, but it still included because a
                     21:  * large amount of software (e.g. nymph, LTSP) makes use of NBI files.
                     22:  *
                     23:  * Etherboot does not implement the INT 78 callback interface
                     24:  * described by the NBI specification.  For a callback interface on
                     25:  * x86 architecture, use PXE.
                     26:  *
                     27:  */
                     28: 
                     29: FEATURE ( FEATURE_IMAGE, "NBI", DHCP_EB_FEATURE_NBI, 1 );
                     30: 
                     31: /**
                     32:  * An NBI image header
                     33:  *
                     34:  * Note that the length field uses a peculiar encoding; use the
                     35:  * NBI_LENGTH() macro to decode the actual header length.
                     36:  *
                     37:  */
                     38: struct imgheader {
                     39:        unsigned long magic;            /**< Magic number (NBI_MAGIC) */
                     40:        union {
                     41:                unsigned char length;   /**< Nibble-coded header length */
                     42:                unsigned long flags;    /**< Image flags */
                     43:        };
                     44:        segoff_t location;              /**< 16-bit seg:off header location */
                     45:        union {
                     46:                segoff_t segoff;        /**< 16-bit seg:off entry point */
                     47:                unsigned long linear;   /**< 32-bit entry point */
                     48:        } execaddr;
                     49: } __attribute__ (( packed ));
                     50: 
                     51: /** NBI magic number */
                     52: #define NBI_MAGIC 0x1B031336UL
                     53: 
                     54: /* Interpretation of the "length" fields */
                     55: #define NBI_NONVENDOR_LENGTH(len)      ( ( (len) & 0x0f ) << 2 )
                     56: #define NBI_VENDOR_LENGTH(len)         ( ( (len) & 0xf0 ) >> 2 )
                     57: #define NBI_LENGTH(len) ( NBI_NONVENDOR_LENGTH(len) + NBI_VENDOR_LENGTH(len) )
                     58: 
                     59: /* Interpretation of the "flags" fields */
                     60: #define        NBI_PROGRAM_RETURNS(flags)      ( (flags) & ( 1 << 8 ) )
                     61: #define        NBI_LINEAR_EXEC_ADDR(flags)     ( (flags) & ( 1 << 31 ) )
                     62: 
                     63: /** NBI header length */
                     64: #define NBI_HEADER_LENGTH      512
                     65: 
                     66: /**
                     67:  * An NBI segment header
                     68:  *
                     69:  * Note that the length field uses a peculiar encoding; use the
                     70:  * NBI_LENGTH() macro to decode the actual header length.
                     71:  *
                     72:  */
                     73: struct segheader {
                     74:        unsigned char length;           /**< Nibble-coded header length */
                     75:        unsigned char vendortag;        /**< Vendor-defined private tag */
                     76:        unsigned char reserved;
                     77:        unsigned char flags;            /**< Segment flags */
                     78:        unsigned long loadaddr;         /**< Load address */
                     79:        unsigned long imglength;        /**< Segment length in NBI file */
                     80:        unsigned long memlength;        /**< Segment length in memory */
                     81: };
                     82: 
                     83: /* Interpretation of the "flags" fields */
                     84: #define NBI_LOADADDR_FLAGS(flags)      ( (flags) & 0x03 )
                     85: #define NBI_LOADADDR_ABS               0x00
                     86: #define NBI_LOADADDR_AFTER             0x01
                     87: #define NBI_LOADADDR_END               0x02
                     88: #define NBI_LOADADDR_BEFORE            0x03
                     89: #define NBI_LAST_SEGHEADER(flags)      ( (flags) & ( 1 << 2 ) )
                     90: 
                     91: /* Define a type for passing info to a loaded program */
                     92: struct ebinfo {
                     93:        uint8_t  major, minor;  /* Version */
                     94:        uint16_t flags;         /* Bit flags */
                     95: };
                     96: 
                     97: /** Info passed to NBI image */
                     98: static struct ebinfo loaderinfo = {
                     99:        VERSION_MAJOR, VERSION_MINOR,
                    100:        0
                    101: };
                    102: 
                    103: /**
                    104:  * Prepare a segment for an NBI image
                    105:  *
                    106:  * @v image            NBI image
                    107:  * @v offset           Offset within NBI image
                    108:  * @v filesz           Length of initialised-data portion of the segment
                    109:  * @v memsz            Total length of the segment
                    110:  * @v src              Source for initialised data
                    111:  * @ret rc             Return status code
                    112:  */
                    113: static int nbi_prepare_segment ( struct image *image, size_t offset __unused,
                    114:                                 userptr_t dest, size_t filesz, size_t memsz ){
                    115:        int rc;
                    116: 
                    117:        if ( ( rc = prep_segment ( dest, filesz, memsz ) ) != 0 ) {
                    118:                DBGC ( image, "NBI %p could not prepare segment: %s\n",
                    119:                       image, strerror ( rc ) );
                    120:                return rc;
                    121:        }
                    122: 
                    123:        return 0;
                    124: }
                    125: 
                    126: /**
                    127:  * Load a segment for an NBI image
                    128:  *
                    129:  * @v image            NBI image
                    130:  * @v offset           Offset within NBI image
                    131:  * @v filesz           Length of initialised-data portion of the segment
                    132:  * @v memsz            Total length of the segment
                    133:  * @v src              Source for initialised data
                    134:  * @ret rc             Return status code
                    135:  */
                    136: static int nbi_load_segment ( struct image *image, size_t offset,
                    137:                              userptr_t dest, size_t filesz,
                    138:                              size_t memsz __unused ) {
                    139:        memcpy_user ( dest, 0, image->data, offset, filesz );
                    140:        return 0;
                    141: }
                    142: 
                    143: /**
                    144:  * Process segments of an NBI image
                    145:  *
                    146:  * @v image            NBI image
                    147:  * @v imgheader                Image header information
                    148:  * @v process          Function to call for each segment
                    149:  * @ret rc             Return status code
                    150:  */
                    151: static int nbi_process_segments ( struct image *image,
                    152:                                  struct imgheader *imgheader,
                    153:                                  int ( * process ) ( struct image *image,
                    154:                                                      size_t offset,
                    155:                                                      userptr_t dest,
                    156:                                                      size_t filesz,
                    157:                                                      size_t memsz ) ) {
                    158:        struct segheader sh;
                    159:        size_t offset = 0;
                    160:        size_t sh_off;
                    161:        userptr_t dest;
                    162:        size_t filesz;
                    163:        size_t memsz;
                    164:        int rc;
                    165:        
                    166:        /* Copy image header to target location */
                    167:        dest = real_to_user ( imgheader->location.segment,
                    168:                              imgheader->location.offset );
                    169:        filesz = memsz = NBI_HEADER_LENGTH;
                    170:        if ( ( rc = process ( image, offset, dest, filesz, memsz ) ) != 0 )
                    171:                return rc;
                    172:        offset += filesz;
                    173: 
                    174:        /* Process segments in turn */
                    175:        sh_off = NBI_LENGTH ( imgheader->length );
                    176:        do {
                    177:                /* Read segment header */
                    178:                copy_from_user ( &sh, image->data, sh_off, sizeof ( sh ) );
                    179:                if ( sh.length == 0 ) {
                    180:                        /* Avoid infinite loop? */
                    181:                        DBGC ( image, "NBI %p invalid segheader length 0\n",
                    182:                               image );
                    183:                        return -ENOEXEC;
                    184:                }
                    185:                
                    186:                /* Calculate segment load address */
                    187:                switch ( NBI_LOADADDR_FLAGS ( sh.flags ) ) {
                    188:                case NBI_LOADADDR_ABS:
                    189:                        dest = phys_to_user ( sh.loadaddr );
                    190:                        break;
                    191:                case NBI_LOADADDR_AFTER:
                    192:                        dest = userptr_add ( dest, memsz + sh.loadaddr );
                    193:                        break;
                    194:                case NBI_LOADADDR_BEFORE:
                    195:                        dest = userptr_add ( dest, -sh.loadaddr );
                    196:                        break;
                    197:                case NBI_LOADADDR_END:
                    198:                        /* Not correct according to the spec, but
                    199:                         * maintains backwards compatibility with
                    200:                         * previous versions of Etherboot.
                    201:                         */
                    202:                        dest = phys_to_user ( ( extmemsize() + 1024 ) * 1024
                    203:                                              - sh.loadaddr );
                    204:                        break;
                    205:                default:
                    206:                        /* Cannot be reached */
                    207:                        assert ( 0 );
                    208:                }
                    209: 
                    210:                /* Process this segment */
                    211:                filesz = sh.imglength;
                    212:                memsz = sh.memlength;
                    213:                if ( ( offset + filesz ) > image->len ) {
                    214:                        DBGC ( image, "NBI %p segment outside file\n", image );
                    215:                        return -ENOEXEC;
                    216:                }
                    217:                if ( ( rc = process ( image, offset, dest,
                    218:                                      filesz, memsz ) ) != 0 ) {
                    219:                        return rc;
                    220:                }
                    221:                offset += filesz;
                    222: 
                    223:                /* Next segheader */
                    224:                sh_off += NBI_LENGTH ( sh.length );
                    225:                if ( sh_off >= NBI_HEADER_LENGTH ) {
                    226:                        DBGC ( image, "NBI %p header overflow\n", image );
                    227:                        return -ENOEXEC;
                    228:                }
                    229: 
                    230:        } while ( ! NBI_LAST_SEGHEADER ( sh.flags ) );
                    231: 
                    232:        if ( offset != image->len ) {
                    233:                DBGC ( image, "NBI %p length wrong (file %zd, metadata %zd)\n",
                    234:                       image, image->len, offset );
                    235:                return -ENOEXEC;
                    236:        }
                    237: 
                    238:        return 0;
                    239: }
                    240: 
                    241: /**
                    242:  * Boot a 16-bit NBI image
                    243:  *
                    244:  * @v imgheader                Image header information
                    245:  * @ret rc             Return status code, if image returns
                    246:  */
                    247: static int nbi_boot16 ( struct image *image, struct imgheader *imgheader ) {
                    248:        int discard_D, discard_S, discard_b;
                    249:        int rc;
                    250: 
                    251:        DBGC ( image, "NBI %p executing 16-bit image at %04x:%04x\n", image,
                    252:               imgheader->execaddr.segoff.segment,
                    253:               imgheader->execaddr.segoff.offset );
                    254: 
                    255:        __asm__ __volatile__ (
                    256:                REAL_CODE ( "pushw %%ds\n\t"    /* far pointer to bootp data */
                    257:                            "pushw %%bx\n\t"
                    258:                            "pushl %%esi\n\t"   /* location */
                    259:                            "pushw %%cs\n\t"    /* lcall execaddr */
                    260:                            "call 1f\n\t"
                    261:                            "jmp 2f\n\t"
                    262:                            "\n1:\n\t"
                    263:                            "pushl %%edi\n\t"
                    264:                            "lret\n\t"
                    265:                            "\n2:\n\t"
                    266:                            "addw $8,%%sp\n\t"  /* clean up stack */ )
                    267:                : "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ),
                    268:                  "=b" ( discard_b )
                    269:                : "D" ( imgheader->execaddr.segoff ),
                    270:                  "S" ( imgheader->location ),
                    271:                  "b" ( __from_data16 ( basemem_packet ) )
                    272:                : "ecx", "edx", "ebp" );
                    273: 
                    274:        return rc;
                    275: }
                    276: 
                    277: /**
                    278:  * Boot a 32-bit NBI image
                    279:  *
                    280:  * @v imgheader                Image header information
                    281:  * @ret rc             Return status code, if image returns
                    282:  */
                    283: static int nbi_boot32 ( struct image *image, struct imgheader *imgheader ) {
                    284:        int discard_D, discard_S, discard_b;
                    285:        int rc;
                    286: 
                    287:        DBGC ( image, "NBI %p executing 32-bit image at %lx\n",
                    288:               image, imgheader->execaddr.linear );
                    289: 
                    290:        /* Jump to OS with flat physical addressing */
                    291:        __asm__ __volatile__ (
                    292:                PHYS_CODE ( "pushl %%ebx\n\t" /* bootp data */
                    293:                            "pushl %%esi\n\t" /* imgheader */
                    294:                            "pushl %%eax\n\t" /* loaderinfo */
                    295:                            "call *%%edi\n\t"
                    296:                            "addl $12, %%esp\n\t" /* clean up stack */ )
                    297:                : "=a" ( rc ), "=D" ( discard_D ), "=S" ( discard_S ),
                    298:                  "=b" ( discard_b )
                    299:                : "D" ( imgheader->execaddr.linear ),
                    300:                  "S" ( ( imgheader->location.segment << 4 ) +
                    301:                        imgheader->location.offset ),
                    302:                  "b" ( virt_to_phys ( basemem_packet ) ),
                    303:                  "a" ( virt_to_phys ( &loaderinfo ) )
                    304:                : "ecx", "edx", "ebp", "memory" );
                    305: 
                    306:        return rc;
                    307: }
                    308: 
                    309: /**
                    310:  * Prepare DHCP parameter block for NBI image
                    311:  *
                    312:  * @v image            NBI image
                    313:  * @ret rc             Return status code
                    314:  */
                    315: static int nbi_prepare_dhcp ( struct image *image ) {
                    316:        struct net_device *boot_netdev;
                    317:        int rc;
                    318: 
                    319:        boot_netdev = last_opened_netdev();
                    320:        if ( ! boot_netdev ) {
                    321:                DBGC ( image, "NBI %p could not identify a network device\n",
                    322:                       image );
                    323:                return -ENODEV;
                    324:        }
                    325: 
                    326:        if ( ( rc = create_fakedhcpack ( boot_netdev, basemem_packet,
                    327:                                         sizeof ( basemem_packet ) ) ) != 0 ) {
                    328:                DBGC ( image, "NBI %p failed to build DHCP packet\n", image );
                    329:                return rc;
                    330:        }
                    331: 
                    332:        return 0;
                    333: }
                    334: 
                    335: /**
                    336:  * Execute a loaded NBI image
                    337:  *
                    338:  * @v image            NBI image
                    339:  * @ret rc             Return status code
                    340:  */
                    341: static int nbi_exec ( struct image *image ) {
                    342:        struct imgheader imgheader;
                    343:        int may_return;
                    344:        int rc;
                    345: 
                    346:        /* Retrieve image header */
                    347:        copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );
                    348: 
                    349:        DBGC ( image, "NBI %p placing header at %hx:%hx\n", image,
                    350:               imgheader.location.segment, imgheader.location.offset );
                    351: 
                    352:        /* NBI files can have overlaps between segments; the bss of
                    353:         * one segment may overlap the initialised data of another.  I
                    354:         * assume this is a design flaw, but there are images out
                    355:         * there that we need to work with.  We therefore do two
                    356:         * passes: first to initialise the segments, then to copy the
                    357:         * data.  This avoids zeroing out already-copied data.
                    358:         */
                    359:        if ( ( rc = nbi_process_segments ( image, &imgheader,
                    360:                                           nbi_prepare_segment ) ) != 0 )
                    361:                return rc;
                    362:        if ( ( rc = nbi_process_segments ( image, &imgheader,
                    363:                                           nbi_load_segment ) ) != 0 )
                    364:                return rc;
                    365: 
                    366:        /* Prepare DHCP option block */
                    367:        if ( ( rc = nbi_prepare_dhcp ( image ) ) != 0 )
                    368:                return rc;
                    369: 
                    370:        /* Shut down now if NBI image will not return */
                    371:        may_return = NBI_PROGRAM_RETURNS ( imgheader.flags );
                    372:        if ( ! may_return )
                    373:                shutdown_boot();
                    374: 
                    375:        /* Execute NBI image */
                    376:        if ( NBI_LINEAR_EXEC_ADDR ( imgheader.flags ) ) {
                    377:                rc = nbi_boot32 ( image, &imgheader );
                    378:        } else {
                    379:                rc = nbi_boot16 ( image, &imgheader );
                    380:        }
                    381: 
                    382:        if ( ! may_return ) {
                    383:                /* Cannot continue after shutdown() called */
                    384:                DBGC ( image, "NBI %p returned %d from non-returnable image\n",
                    385:                       image, rc  );
                    386:                while ( 1 ) {}
                    387:        }
                    388: 
                    389:        DBGC ( image, "NBI %p returned %d\n", image, rc );
                    390: 
                    391:        return rc;
                    392: }
                    393: 
                    394: /**
                    395:  * Probe NBI image
                    396:  *
                    397:  * @v image            NBI image
                    398:  * @ret rc             Return status code
                    399:  */
                    400: static int nbi_probe ( struct image *image ) {
                    401:        struct imgheader imgheader;
                    402: 
                    403:        /* If we don't have enough data give up */
                    404:        if ( image->len < NBI_HEADER_LENGTH ) {
                    405:                DBGC ( image, "NBI %p too short for an NBI image\n", image );
                    406:                return -ENOEXEC;
                    407:        }
                    408: 
                    409:        /* Check image header */
                    410:        copy_from_user ( &imgheader, image->data, 0, sizeof ( imgheader ) );
                    411:        if ( imgheader.magic != NBI_MAGIC ) {
                    412:                DBGC ( image, "NBI %p has no NBI signature\n", image );
                    413:                return -ENOEXEC;
                    414:        }
                    415: 
                    416:        return 0;
                    417: }
                    418: 
                    419: /** NBI image type */
                    420: struct image_type nbi_image_type __image_type ( PROBE_NORMAL ) = {
                    421:        .name = "NBI",
                    422:        .probe = nbi_probe,
                    423:        .exec = nbi_exec,
                    424: };

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.