[BACK]Return to cdbr.S CVS log [TXT][DIR] Up to [local] / sys / arch / i386 / stand / cdbr

Annotation of sys/arch/i386/stand/cdbr/cdbr.S, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: cdbr.S,v 1.2 2004/08/24 15:24:05 tom Exp $    */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2004 Tom Cosgrove <tom.cosgrove@arches-consulting.com>
        !             5:  * Copyright (c) 2001 John Baldwin <jhb@FreeBSD.org>
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. 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 distribution.
        !            16:  * 3. Neither the name of the author nor the names of any co-contributors
        !            17:  *    may be used to endorse or promote products derived from this software
        !            18:  *    without specific prior written permission.
        !            19:  *
        !            20:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
        !            21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
        !            24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            30:  * SUCH DAMAGE.
        !            31:  */
        !            32:
        !            33:        .file   "cdbr.S"
        !            34:
        !            35: /* #include <machine/asm.h> */
        !            36: /* #include <assym.h> */
        !            37:
        !            38: /*
        !            39:  * This program is a CD boot sector, similar to the partition boot record
        !            40:  * (pbr, also called biosboot) used by hard disks.  It is implemented as a
        !            41:  * "no-emulation" boot sector, as described in the "El Torito" Bootable
        !            42:  * CD-ROM Format Specification.
        !            43:  *
        !            44:  * The function of this boot sector is to load and start the next-stage
        !            45:  * cdboot program, which will load the kernel.
        !            46:  *
        !            47:  * The El Torito standard allows us to specify where we want to be loaded,
        !            48:  * but for maximum compatibility we choose the default load address of
        !            49:  * 0x07C00.
        !            50:  *
        !            51:  * Memory layout:
        !            52:  *
        !            53:  * 0x00000 -> 0x003FF  real mode interrupt vector table
        !            54:  * 0x00400 -> 0x00500  BIOS data segment
        !            55:  *
        !            56:  * 0x00000 -> 0x073FF  our stack (grows down)          (from 29k)
        !            57:  * 0x07400 -> 0x07BFF  we relocate to here             (at 29k)
        !            58:  * 0x07C00 -> 0x08400  BIOS loads us here              (at 31k, for 2k)
        !            59:  * 0x07C00 -> ...      /cdboot
        !            60:  *
        !            61:  * The BIOS loads us at physical address 0x07C00.  We then relocate to
        !            62:  * 0x07400, seg:offset 0740:0000.  We then load /cdboot at seg:offset
        !            63:  * 07C0:0000.
        !            64:  */
        !            65: #define BOOTSEG                0x7c0                   /* segment we're loaded to */
        !            66: #define BOOTSECTSIZE   0x800                   /* our size in bytes */
        !            67: #define BOOTRELOCSEG   0x740                   /* segment we relocate to */
        !            68: #define BOOTSTACKOFF  ((BOOTRELOCSEG << 4) - 4)        /* starts here, grows down */
        !            69:
        !            70: /* Constants for reading from the CD */
        !            71: #define ERROR_TIMEOUT          0x80            /* BIOS timeout on read */
        !            72: #define NUM_RETRIES            3               /* Num times to retry */
        !            73: #define SECTOR_SIZE            0x800           /* size of a sector */
        !            74: #define SECTOR_SHIFT           11              /* number of place to shift */
        !            75: #define BUFFER_LEN             0x100           /* number of sectors in buffr */
        !            76: #define MAX_READ               0x10000         /* max we can read at a time */
        !            77: #define MAX_READ_PARAS         MAX_READ >> 4
        !            78: #define MAX_READ_SEC           MAX_READ >> SECTOR_SHIFT
        !            79: #define MEM_READ_BUFFER                0x9000          /* buffer to read from CD */
        !            80: #define MEM_VOLDESC            MEM_READ_BUFFER /* volume descriptor */
        !            81: #define MEM_DIR                        MEM_VOLDESC+SECTOR_SIZE /* Lookup buffer */
        !            82: #define VOLDESC_LBA            0x10            /* LBA of vol descriptor */
        !            83: #define VD_PRIMARY             1               /* Primary VD */
        !            84: #define VD_END                 255             /* VD Terminator */
        !            85: #define VD_ROOTDIR             156             /* Offset of Root Dir Record */
        !            86: #define DIR_LEN                        0               /* Offset of Dir Rec length */
        !            87: #define DIR_EA_LEN             1               /* Offset of EA length */
        !            88: #define DIR_EXTENT             2               /* Offset of 64-bit LBA */
        !            89: #define DIR_SIZE               10              /* Offset of 64-bit length */
        !            90: #define DIR_NAMELEN            32              /* Offset of 8-bit name len */
        !            91: #define DIR_NAME               33              /* Offset of dir name */
        !            92:
        !            93:        .text
        !            94:        .code16
        !            95:
        !            96:        .globl  start
        !            97: start:
        !            98:        /* Set up stack */
        !            99:        xorw    %ax, %ax
        !           100:        movw    %ax, %ss
        !           101:        movw    $BOOTSTACKOFF, %sp
        !           102:
        !           103:        /* Relocate so we can load cdboot where we were */
        !           104:        movw    $BOOTSEG, %ax
        !           105:        movw    %ax, %ds
        !           106:        movw    $BOOTRELOCSEG, %ax
        !           107:        movw    %ax, %es
        !           108:        xorw    %si, %si
        !           109:        xorw    %di, %di
        !           110:        movw    $BOOTSECTSIZE, %cx      /* Bytes in cdbr, relocate it all */
        !           111:        cld
        !           112:        rep
        !           113:        movsb
        !           114:
        !           115:        /* Jump to relocated self */
        !           116:        ljmp $BOOTRELOCSEG, $reloc
        !           117: reloc:
        !           118:
        !           119:        /*
        !           120:         * Set up %ds and %es: %ds is our data segment (= %cs), %es is
        !           121:         * used to specify the segment address of the destination buffer
        !           122:         * for cd reads.  We initially have %es = %ds.
        !           123:         */
        !           124:        movw    %cs, %ax
        !           125:        movw    %ax, %ds
        !           126:        movw    %ax, %es
        !           127:
        !           128:        movb    %dl, drive              /* Store the boot drive number */
        !           129:
        !           130:        movw    $signon, %si            /* Say "hi", and give boot drive */
        !           131:        call    display_string
        !           132:        movb    drive, %al
        !           133:        call    hex_byte
        !           134:        movw    $crlf, %si
        !           135:        call    display_string
        !           136:
        !           137: /*
        !           138:  * Load Volume Descriptor
        !           139:  */
        !           140:        movl    $VOLDESC_LBA, %eax      /* Get the sector # for vol desc */
        !           141: load_vd:
        !           142:        pushl   %eax
        !           143:        movb    $1, %dh                 /* One sector */
        !           144:        movw    $MEM_VOLDESC, %bx       /* Destination */
        !           145:        call    read                    /* Read it in */
        !           146:        popl    %eax
        !           147:        cmpb    $VD_PRIMARY, (%bx)      /* Primary vol descriptor? */
        !           148:        je      have_vd                 /* Yes */
        !           149:        inc     %eax                    /* Try the next one */
        !           150:        cmpb    $VD_END, (%bx)          /* Is it the last one? */
        !           151:        jne     load_vd                 /* No, so go try the next one */
        !           152:        movw    $msg_novd, %si          /* No pri vol descriptor */
        !           153:        jmp     err_stop                /* Panic */
        !           154: have_vd:                               /* Have Primary VD */
        !           155:
        !           156: /*
        !           157:  * Look for the next-stage loader binary at pre-defined paths (loader_paths)
        !           158:  */
        !           159:        movw    $loader_paths, %si      /* Point to start of array */
        !           160: lookup_path:
        !           161:        movw    %si, loader             /* remember the one we're looking for */
        !           162:        pushw   %si                     /* Save file name pointer */
        !           163:        call    lookup                  /* Try to find file */
        !           164:        popw    %di                     /* Restore file name pointer */
        !           165:        jnc     lookup_found            /* Found this file */
        !           166:        xorb    %al, %al                /* Look for next */
        !           167:        movw    $0xffff, %cx            /*  path name by */
        !           168:        repnz                           /*  scanning for */
        !           169:        scasb                           /*  nul char */
        !           170:        movw    %di, %si                /* Point %si at next path */
        !           171:        movb    (%si), %al              /* Get first char of next path */
        !           172:        orb     %al, %al                /* Is it double nul? */
        !           173:        jnz     lookup_path             /* No, try it */
        !           174:        movw    $msg_failed, %si        /* Failed message */
        !           175:        jmp     err_stop                /* Print it and halt */
        !           176:
        !           177: lookup_found:                          /* Found a loader file */
        !           178:
        !           179: /*
        !           180:  * Load the binary into the buffer.  Due to real mode addressing limitations
        !           181:  * we have to read it in in 64k chunks.
        !           182:  */
        !           183:        movl    DIR_SIZE(%bx), %eax     /* Read file length */
        !           184:        add     $SECTOR_SIZE-1, %eax    /* Convert length to sectors */
        !           185:        shr     $SECTOR_SHIFT, %eax
        !           186:        cmp     $BUFFER_LEN, %eax
        !           187:        jbe     load_sizeok
        !           188:        movw    $msg_load2big, %si      /* Error message */
        !           189:        jmp     err_stop
        !           190: load_sizeok:
        !           191:        movzbw  %al, %cx                /* Num sectors to read */
        !           192:        movl    DIR_EXTENT(%bx), %eax   /* Load extent */
        !           193:        xorl    %edx, %edx
        !           194:        movb    DIR_EA_LEN(%bx), %dl
        !           195:        addl    %edx, %eax              /* Skip extended */
        !           196:
        !           197:        /* Use %bx to hold the segment (para) number */
        !           198:        movw    $BOOTSEG, %bx           /* We put cdboot here too */
        !           199: load_loop:
        !           200:        movb    %cl, %dh
        !           201:        cmpb    $MAX_READ_SEC, %cl      /* Truncate to max read size */
        !           202:        jbe     load_notrunc
        !           203:        movb    $MAX_READ_SEC, %dh
        !           204: load_notrunc:
        !           205:        subb    %dh, %cl                /* Update count */
        !           206:        pushl   %eax                    /* Save */
        !           207:        movw    %bx, %es                /* %bx had the segment (para) number */
        !           208:        xorw    %bx, %bx                /* %es:0000  for destination */
        !           209:        call    read                    /* Read it in */
        !           210:        popl    %eax                    /* Restore */
        !           211:        addl    $MAX_READ_SEC, %eax     /* Update LBA */
        !           212:        addw    $MAX_READ_PARAS, %bx    /* Update dest addr */
        !           213:        jcxz    load_done               /* Done? */
        !           214:        jmp     load_loop               /* Keep going */
        !           215: load_done:
        !           216:
        !           217:        /* Now we can start the loaded program */
        !           218:
        !           219:        movw    loader, %cx             /* Tell cdboot where it is */
        !           220:                                        /* (Older versions of cdbr have */
        !           221:                                        /*  %cx == 0 from the jcxz load_done) */
        !           222:        movb    drive, %dl              /* Get the boot drive number */
        !           223:        ljmp    $BOOTSEG, $0            /* Go run cdboot */
        !           224:
        !           225: /*
        !           226:  * Lookup the file in the path at [SI] from the root directory.
        !           227:  *
        !           228:  * Trashes: All but BX
        !           229:  * Returns: CF = 0 (success), BX = pointer to record
        !           230:  *          CF = 1 (not found)
        !           231:  */
        !           232: lookup:
        !           233:        movw    $VD_ROOTDIR + MEM_VOLDESC, %bx  /* Root directory record */
        !           234:
        !           235: lookup_dir:
        !           236:        lodsb                           /* Get first char of path */
        !           237:        cmpb    $0, %al                 /* Are we done? */
        !           238:        je      lookup_done             /* Yes */
        !           239:        cmpb    $'/', %al               /* Skip path separator */
        !           240:        je      lookup_dir
        !           241:        decw    %si                     /* Undo lodsb side effect */
        !           242:        call    find_file               /* Lookup first path item */
        !           243:        jnc     lookup_dir              /* Try next component */
        !           244:        ret
        !           245: lookup_done:
        !           246:        movw    $msg_loading, %si       /* Success message - say which file */
        !           247:        call    display_string
        !           248:        mov     loader, %si
        !           249:        call    display_string
        !           250:        mov     $crlf, %si
        !           251:        call    display_string
        !           252:        clc                             /* Clear carry */
        !           253:        ret
        !           254:
        !           255: /*
        !           256:  * Lookup file at [SI] in directory whose record is at [BX].
        !           257:  *
        !           258:  * Trashes: All but returns
        !           259:  * Returns: CF = 0 (success), BX = pointer to record, SI = next path item
        !           260:  *          CF = 1 (not found), SI = preserved
        !           261:  */
        !           262: find_file:
        !           263:        mov     DIR_EXTENT(%bx), %eax   /* Load extent */
        !           264:        xor     %edx, %edx
        !           265:        mov     DIR_EA_LEN(%bx), %dl
        !           266:        add     %edx, %eax              /* Skip extended attributes */
        !           267:        mov     %eax, rec_lba           /* Save LBA */
        !           268:        mov     DIR_SIZE(%bx), %eax     /* Save size */
        !           269:        mov     %eax, rec_size
        !           270:        xor     %cl, %cl                /* Zero length */
        !           271:        push    %si                     /* Save */
        !           272: ff_namelen:
        !           273:        inc     %cl                     /* Update length */
        !           274:        lodsb                           /* Read char */
        !           275:        cmp     $0, %al                 /* Nul? */
        !           276:        je      ff_namedone             /* Yes */
        !           277:        cmp     $'/', %al               /* Path separator? */
        !           278:        jnz     ff_namelen              /* No, keep going */
        !           279: ff_namedone:
        !           280:        dec     %cl                     /* Adjust length and save */
        !           281:        mov     %cl, name_len
        !           282:        pop     %si                     /* Restore */
        !           283: ff_load:
        !           284:        mov     rec_lba, %eax           /* Load LBA */
        !           285:        mov     $MEM_DIR, %ebx          /* Address buffer */
        !           286:        mov     $1, %dh                 /* One sector */
        !           287:        call    read                    /* Read directory block */
        !           288:        incl    rec_lba                 /* Update LBA to next block */
        !           289: ff_scan:
        !           290:        mov     %ebx, %edx              /* Check for EOF */
        !           291:        sub     $MEM_DIR, %edx
        !           292:        cmp     %edx, rec_size
        !           293:        ja      ff_scan_1
        !           294:        stc                             /* EOF reached */
        !           295:        ret
        !           296: ff_scan_1:
        !           297:        cmpb    $0, DIR_LEN(%bx)        /* Last record in block? */
        !           298:        je      ff_nextblock
        !           299:        push    %si                     /* Save */
        !           300:        movzbw  DIR_NAMELEN(%bx), %si   /* Find end of string */
        !           301: ff_checkver:
        !           302:        cmpb    $'0', DIR_NAME-1(%bx,%si)       /* Less than '0'? */
        !           303:        jb      ff_checkver_1
        !           304:        cmpb    $'9', DIR_NAME-1(%bx,%si)       /* Greater than '9'? */
        !           305:        ja      ff_checkver_1
        !           306:        dec     %si                     /* Next char */
        !           307:        jnz     ff_checkver
        !           308:        jmp     ff_checklen             /* All numbers in name, so */
        !           309:                                        /*  no version */
        !           310: ff_checkver_1:
        !           311:        movzbw  DIR_NAMELEN(%bx), %cx
        !           312:        cmp     %cx, %si                /* Did we find any digits? */
        !           313:        je      ff_checkdot             /* No */
        !           314:        cmpb    $';', DIR_NAME-1(%bx,%si)       /* Check for semicolon */
        !           315:        jne     ff_checkver_2
        !           316:        dec     %si                     /* Skip semicolon */
        !           317:        mov     %si, %cx
        !           318:        mov     %cl, DIR_NAMELEN(%bx)   /* Adjust length */
        !           319:        jmp     ff_checkdot
        !           320: ff_checkver_2:
        !           321:        mov     %cx, %si                /* Restore %si to end of string */
        !           322: ff_checkdot:
        !           323:        cmpb    $'.', DIR_NAME-1(%bx,%si)       /* Trailing dot? */
        !           324:        jne     ff_checklen                     /* No */
        !           325:        decb    DIR_NAMELEN(%bx)        /* Adjust length */
        !           326: ff_checklen:
        !           327:        pop     %si                     /* Restore */
        !           328:        movzbw  name_len, %cx           /* Load length of name */
        !           329:        cmp     %cl, DIR_NAMELEN(%bx)   /* Does length match? */
        !           330:        je      ff_checkname            /* Yes, check name */
        !           331: ff_nextrec:
        !           332:        add     DIR_LEN(%bx), %bl       /* Next record */
        !           333:        adc     $0, %bh
        !           334:        jmp     ff_scan
        !           335: ff_nextblock:
        !           336:        subl    $SECTOR_SIZE, rec_size  /* Adjust size */
        !           337:        jnc     ff_load                 /* If subtract ok, keep going */
        !           338:        ret                             /* End of file, so not found */
        !           339: ff_checkname:
        !           340:        lea     DIR_NAME(%bx), %di      /* Address name in record */
        !           341:        push    %si                     /* Save */
        !           342:        repe    cmpsb                   /* Compare name */
        !           343:        jcxz    ff_match                /* We have a winner! */
        !           344:        pop     %si                     /* Restore */
        !           345:        jmp     ff_nextrec              /* Keep looking */
        !           346: ff_match:
        !           347:        add     $2, %sp                 /* Discard saved %si */
        !           348:        clc                             /* Clear carry */
        !           349:        ret
        !           350:
        !           351: /*
        !           352:  * Load DH sectors starting at LBA %eax into address %es:%bx.
        !           353:  *
        !           354:  * Preserves %bx, %cx, %dx, %si, %es
        !           355:  * Trashes %eax
        !           356:  */
        !           357: read:
        !           358:        pushw   %si                     /* Save */
        !           359:        pushw   %cx                     /* Save since some BIOSs trash */
        !           360:        movl    %eax, edd_lba           /* LBA to read from */
        !           361:        movw    %es, %ax                /* Get the segment */
        !           362:        movw    %ax, edd_addr + 2       /*  and store */
        !           363:        movw    %bx, edd_addr           /* Store offset too */
        !           364: read_retry:
        !           365:        call    twiddle                 /* Entertain the user */
        !           366:        pushw   %dx                     /* Save */
        !           367:        movw    $edd_packet, %si        /* Address Packet */
        !           368:        movb    %dh, edd_len            /* Set length */
        !           369:        movb    drive, %dl              /* BIOS Device */
        !           370:        movb    $0x42, %ah              /* BIOS: Extended Read */
        !           371:        int     $0x13                   /* Call BIOS */
        !           372:        popw    %dx                     /* Restore */
        !           373:        jc      read_fail               /* Worked? */
        !           374:        popw    %cx                     /* Restore */
        !           375:        popw    %si
        !           376:        ret                             /* Return */
        !           377: read_fail:
        !           378:        cmpb    $ERROR_TIMEOUT, %ah     /* Timeout? */
        !           379:        je      read_retry              /* Yes, Retry */
        !           380: read_error:
        !           381:        pushw   %ax                     /* Save error */
        !           382:        movw    $msg_badread, %si       /* "Read error: 0x" */
        !           383:        call    display_string
        !           384:        popw    %ax                     /* Retrieve error code */
        !           385:        movb    %ah, %al                /* Into %al */
        !           386:        call    hex_byte                /* Display error code */
        !           387:        jmp     stay_stopped            /* ... then hang */
        !           388:
        !           389: /*
        !           390:  * Display the ASCIZ error message in %esi then halt
        !           391:  */
        !           392: err_stop:
        !           393:        call    display_string
        !           394:
        !           395: stay_stopped:
        !           396:        sti                             /* Ensure Ctl-Alt-Del will work */
        !           397:        hlt                             /* (don't require power cycle) */
        !           398:        jmp     stay_stopped            /* (Just to make sure) */
        !           399:
        !           400: /*
        !           401:  * Output the "twiddle"
        !           402:  */
        !           403: twiddle:
        !           404:        push    %ax                     /* Save */
        !           405:        push    %bx                     /* Save */
        !           406:        mov     twiddle_index, %al      /* Load index */
        !           407:        mov     twiddle_chars, %bx      /* Address table */
        !           408:        inc     %al                     /* Next */
        !           409:        and     $3, %al                 /*  char */
        !           410:        mov     %al, twiddle_index      /* Save index for next call */
        !           411:        xlat                            /* Get char */
        !           412:        call    display_char            /* Output it */
        !           413:        mov     $8, %al                 /* Backspace */
        !           414:        call    display_char            /* Output it */
        !           415:        pop     %bx                     /* Restore */
        !           416:        pop     %ax                     /* Restore */
        !           417:        ret
        !           418:
        !           419: /*
        !           420:  * Display the ASCIZ string pointed to by %si.
        !           421:  *
        !           422:  * Destroys %si, possibly others.
        !           423:  */
        !           424: display_string:
        !           425:        pushw   %ax
        !           426:        cld
        !           427: 1:
        !           428:        lodsb                   /* %al = *%si++ */
        !           429:        testb   %al, %al
        !           430:        jz      1f
        !           431:        call    display_char
        !           432:        jmp     1b
        !           433:
        !           434: /*
        !           435:  * Write out value in %eax in hex
        !           436:  */
        !           437: hex_long:
        !           438:        pushl   %eax
        !           439:        shrl    $16, %eax
        !           440:        call    hex_word
        !           441:        popl    %eax
        !           442:        /* fall thru */
        !           443:
        !           444: /*
        !           445:  * Write out value in %ax in hex
        !           446:  */
        !           447: hex_word:
        !           448:        pushw   %ax
        !           449:        mov     %ah, %al
        !           450:        call    hex_byte
        !           451:        popw    %ax
        !           452:        /* fall thru */
        !           453: /*
        !           454:  * Write out value in %al in hex
        !           455:  */
        !           456: hex_byte:
        !           457:        pushw   %ax
        !           458:        shrb    $4, %al
        !           459:        call    hex_nibble
        !           460:        popw    %ax
        !           461:        /* fall thru */
        !           462:
        !           463: /* Write out nibble in %al */
        !           464: hex_nibble:
        !           465:        and     $0x0F, %al
        !           466:        add     $'0', %al
        !           467:        cmpb    $'9', %al
        !           468:        jbe     display_char
        !           469:        addb    $'A'-'9'-1, %al
        !           470:        /* fall thru to display_char */
        !           471:
        !           472: /*
        !           473:  * Display the character in %al
        !           474:  */
        !           475: display_char:
        !           476:        pushw   %ax
        !           477:
        !           478:        pushw   %bx
        !           479:        movb    $0x0e, %ah
        !           480:        movw    $1, %bx
        !           481:        int     $0x10
        !           482:        popw    %bx
        !           483: 1:     popw    %ax
        !           484:        ret
        !           485:
        !           486: /*
        !           487:  * Data
        !           488:  */
        !           489: drive:         .byte   0                       /* Given to us by the BIOS */
        !           490: signon:                .asciz  "CD-ROM: "
        !           491: crlf:          .asciz  "\r\n"
        !           492: msg_load2big:  .asciz  "File too big"
        !           493: msg_badread:   .asciz  "Read error: 0x"
        !           494: msg_novd:      .asciz  "No Primary Volume Descriptor"
        !           495: msg_loading:   .asciz  "Loading "
        !           496:
        !           497: /* State for searching dir */
        !           498: rec_lba:       .long   0x0                     /* LBA (adjusted for EA) */
        !           499: rec_size:      .long   0x0                     /* File size */
        !           500: name_len:      .byte   0x0                     /* Length of current name */
        !           501:
        !           502: twiddle_index: .byte   0x0
        !           503: twiddle_chars: .ascii  "|/-\\"
        !           504:
        !           505: /* Packet for LBA (CD) read */
        !           506: edd_packet:    .byte   0x10                    /* Length */
        !           507:                .byte   0                       /* Reserved */
        !           508: edd_len:       .byte   0x0                     /* Num to read */
        !           509:                .byte   0                       /* Reserved */
        !           510: edd_addr:      .word   0x0, 0x0                /* Seg:Off */
        !           511: edd_lba:       .quad   0x0                     /* LBA */
        !           512:
        !           513: /* The data from here must be last in the file, only followed by 0x00 bytes */
        !           514:
        !           515: loader:                .word   0                       /* The path we end up using */
        !           516:
        !           517: msg_failed:    .ascii  "Can't find "           /* This string runs into... */
        !           518:
        !           519: /* loader_paths is a list of ASCIZ strings followed by a term NUL byte */
        !           520: loader_paths:  .asciz  "/cdboot"
        !           521:                .asciz  "/CDBOOT"
        !           522:                .ascii  "/", OSREV, "/", MACH, "/cdboot"
        !           523:                .byte   0                       /* NUL-term line above */
        !           524:                .ascii  "/", OSREV, "/", MACH_U, "/CDBOOT"
        !           525:                .byte   0                       /* NUL-term line above */
        !           526:                .byte   0                       /* Terminate the list */
        !           527:
        !           528:        . = BOOTSECTSIZE
        !           529:
        !           530:        .end

CVSweb