Annotation of qemu/roms/ipxe/src/arch/i386/image/nbi.c, revision 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.