xref: /dragonfly/stand/boot/pc32/cdboot/cdboot.S (revision 479ab7f0492f2a51b48e8537e4f1dc686fc6014b)
1/*
2 * Copyright (c) 2001 John Baldwin
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are freely
6 * permitted provided that the above copyright notice and this
7 * paragraph and the following disclaimer are duplicated in all
8 * such forms.
9 *
10 * This software is provided "AS IS" and without any express or
11 * implied warranties, including, without limitation, the implied
12 * warranties of merchantability and fitness for a particular
13 * purpose.
14 *
15 *
16 * $FreeBSD: src/sys/boot/i386/cdboot/cdboot.s,v 1.9 2001/11/07 01:20:33 jhb Exp $
17 * $DragonFly: src/sys/boot/pc32/cdboot/cdboot.S,v 1.8 2007/05/18 07:41:43 dillon Exp $
18 */
19
20/*
21 * This program is a freestanding boot program to load an a.out binary
22 * from a CD-ROM booted with no emulation mode as described by the El
23 * Torito standard.  Due to broken BIOSen that do not load the desired
24 * number of sectors, we try to fit this in as small a space as possible.
25 *
26 * Basically, we first create a set of boot arguments to pass to the loaded
27 * binary.  Then we attempt to load /boot/loader from the CD we were booted
28 * off of.
29 */
30
31#include "../bootasm.h"
32
33                    /*
34                     * a.out header fields
35                     */
36                    .set AOUT_TEXT,0x04           # text segment size
37                    .set AOUT_DATA,0x08           # data segment size
38                    .set AOUT_BSS,0x0c            # zerod BSS size
39                    .set AOUT_SYMBOLS,0x10                  # symbol table
40                    .set AOUT_ENTRY,0x14                    # entry point
41                    .set AOUT_HEADER,MEM_PAGE_SIZE          # size of the a.out header
42
43                    /*
44                     * Flags for kargs->bootflags
45                     */
46                    .set KARGS_FLAGS_CD,0x1                 # flag to indicate booting from
47                                                            #  CD loader
48                    /*
49                     * Segment selectors.
50                     */
51                    .set SEL_SDATA,0x8            # Supervisor data
52                    .set SEL_RDATA,0x10           # Real mode data
53                    .set SEL_SCODE,0x18           # PM-32 code
54                    .set SEL_SCODE16,0x20                   # PM-16 code
55
56                    /*
57                     * BTX constants
58                     */
59                    .set INT_SYS,0x30             # BTX syscall interrupt
60
61                    /*
62                     * Constants for reading from the CD.
63                     */
64                    .set ERROR_TIMEOUT,0x80                 # BIOS timeout on read
65                    .set NUM_RETRIES,3            # Num times to retry
66                    .set SECTOR_SIZE,0x800                  # size of a sector
67                    .set SECTOR_SHIFT,11                    # number of place to shift
68                    .set BUFFER_LEN,0x100                   # number of sectors in buffer
69# Some BIOSes just can't handle this
70#                   .set MAX_READ,0x10000                   # max we can read at a time
71#                   .set MAX_READ_SEC,MAX_READ >> SECTOR_SHIFT
72                    .set MAX_READ,0x800           # max we can read at a time
73                    .set MAX_READ_SEC,1
74                    .set MEM_READ_BUFFER,0x9000   # buffer to read from CD
75                    .set MEM_VOLDESC,MEM_READ_BUFFER # volume descriptor
76                    .set MEM_DIR,MEM_VOLDESC+SECTOR_SIZE # Lookup buffer
77                    .set VOLDESC_LBA,0x10                   # LBA of vol descriptor
78                    .set VD_PRIMARY,1             # Primary VD
79                    .set VD_END,255                         # VD Terminator
80                    .set VD_ROOTDIR,156           # Offset of Root Dir Record
81                    .set DIR_LEN,0                          # Offset of Dir Record length
82                    .set DIR_EA_LEN,1             # Offset of EA length
83                    .set DIR_EXTENT,2             # Offset of 64-bit LBA
84                    .set DIR_SIZE,10              # Offset of 64-bit length
85                    .set DIR_NAMELEN,32           # Offset of 8-bit name len
86                    .set DIR_NAME,33              # Offset of dir name
87
88                    /*
89                     * Program start.
90                     *
91                     * We expect to be loaded by the BIOS at 0x7c00 (standard
92                     * boot loader entry point)
93                     */
94                    .code16
95                    .globl start
96                    .org 0x0, 0x0
97
98start:              cld                                     # string ops inc
99                    xor %ax,%ax                             # zero %ax
100                    mov %ax,%ss                             # setup the
101                    mov $start,%sp                          #  stack
102                    mov %ax,%ds                             # setup the
103                    mov %ax,%es                             #  data segments
104                    mov %dl,drive                           # Save BIOS boot device
105                    sti                                     # make sure intrs are enabled
106                    mov $msg_welcome,%si                    # %ds:(%si) -> welcome message
107                    call putstr                             # display the welcome message
108
109                    /*
110                     * Setup the arguments that the loader is expecting from
111                     * boot[12]
112                     */
113                    mov $msg_bootinfo,%si                   # %ds:(%si) -> boot args message
114                    call putstr                             # display the message
115                    mov $MEM_ARG,%bx              # %ds:(%bx) -> boot args
116                    mov %bx,%di                             # %es:(%di) -> boot args
117                    xor %eax,%eax                           # zero %eax
118                    mov $(MEM_ARG_SIZE/4),%cx     # Size of arguments in 32-bit
119                                                            #  dwords
120                    rep                                     # Clear the arguments
121                    stosl                                   #  to zero
122                    mov drive,%dl                           # Store BIOS boot device
123                    mov %dl,0x4(%bx)              #  in kargs->bootdev
124                    or $KARGS_FLAGS_CD,0x8(%bx)   # kargs->bootflags |=
125                                                            #  KARGS_FLAGS_CD
126                    /*
127                     * Load Volume Descriptor
128                     */
129                    mov $VOLDESC_LBA,%eax                   # Set LBA of first VD
130load_vd:
131                    mov $1,%dh                              # One sector
132                    mov $MEM_VOLDESC,%ebx                   # Destination
133                    call read                     # Read it in
134                    cmpb $VD_PRIMARY,(%bx)                  # Primary VD?
135                    je have_vd                              # Yes
136                    inc %eax                      #  try next
137                    cmpb $VD_END,(%bx)            # Last VD?
138                    jne load_vd                             # No, read next
139                    mov $msg_novd,%si             # No VD
140                    jmp error                     # Halt
141have_vd:                                          # Have Primary VD
142
143                    /*
144                     * Lookup the loader binary.
145                     */
146                    mov $loader_path,%si                    # File to lookup
147                    call lookup                             # Try to find it
148
149                    /*
150                     * Load the binary into the buffer.  Due to real mode
151                     * addressing limitations we have to read it in in 64k
152                     * chunks.
153                     */
154                    mov DIR_SIZE(%bx),%eax                  # Read file length
155                    add $SECTOR_SIZE-1,%eax                 # Convert length to sectors
156                    shr $SECTOR_SHIFT,%eax
157                    cmp $BUFFER_LEN,%eax
158                    jbe load_sizeok
159                    mov $msg_load2big,%si                   # Error message
160                    call error
161load_sizeok:        mov       %al,%cl
162                    mov DIR_EXTENT(%bx),%eax      # Load extent
163                    xor %edx,%edx
164                    mov DIR_EA_LEN(%bx),%dl
165                    add %edx,%eax                           # Skip extended
166                    mov $MEM_READ_BUFFER,%ebx     # Read into the buffer
167load_loop:          mov %cl,%dh
168                    cmp $MAX_READ_SEC,%cl                   # Truncate to max read size
169                    jbe load_notrunc
170                    mov $MAX_READ_SEC,%dh
171load_notrunc:       sub %dh,%cl                             # Update count
172                    call read                     # Read it in
173                    add $MAX_READ_SEC,%eax                  # Update LBA
174                    add $MAX_READ,%ebx            # Update dest addr
175                    testb %cl,%cl
176                    jnz load_loop
177load_done:
178                    /*
179                     * Turn on the A20 address line.
180                     */
181                    call seta20                             # Turn A20 on
182
183                    /*
184                     * Relocate the loader and BTX using a very lazy
185                     * protected mode.
186                     */
187                    mov $msg_relocate,%si                   # Display the
188                    call putstr                             #  relocation message
189                    mov MEM_READ_BUFFER+AOUT_ENTRY,%edi # %edi is the destination
190                    mov $(MEM_READ_BUFFER+AOUT_HEADER),%esi # %esi is
191                                                            #  the start of the text
192                                                            #  segment
193                    mov MEM_READ_BUFFER+AOUT_TEXT,%ecx # %ecx = length of the text
194                                                            #  segment
195                    push %edi                     # Save entry point for later
196                    lgdt gdtdesc                            # setup our own gdt
197                    cli                                     # turn off interrupts
198                    mov %cr0,%eax                           # Turn on
199                    or $0x1,%al                             #  protected
200                    mov %eax,%cr0                           #  mode
201                    ljmp $SEL_SCODE,$pm_start     # long jump to clear the
202                                                            #  instruction pre-fetch queue
203                    .code32
204pm_start: mov $SEL_SDATA,%ax            # Initialize
205                    mov %ax,%ds                             #  %ds and
206                    mov %ax,%es                             #  %es to a flat selector
207                    rep                                     # Relocate the
208                    movsb                                   #  text segment
209                    add $(MEM_PAGE_SIZE - 1),%edi # pad %edi out to a new page
210                    and $~(MEM_PAGE_SIZE - 1),%edi #  for the data segment
211                    mov MEM_READ_BUFFER+AOUT_DATA,%ecx # size of the data segment
212                    rep                                     # Relocate the
213                    movsb                                   #  data segment
214                    mov MEM_READ_BUFFER+AOUT_BSS,%ecx # size of the bss
215                    xor %eax,%eax                           # zero %eax
216                    add $3,%cl                              # round %ecx up to
217                    shr $2,%ecx                             #  a multiple of 4
218                    rep                                     # zero the
219                    stosl                                   #  bss
220                    mov MEM_READ_BUFFER+AOUT_ENTRY,%esi # %esi -> relocated loader
221                    add $MEM_BTX_LDR_OFF,%esi     # %esi -> BTX in the loader
222                    mov $MEM_BTX_ORG,%edi         # %edi -> where BTX needs to go
223                    movzwl 0xa(%esi),%ecx                   # %ecx -> length of BTX
224                    rep                                     # Relocate
225                    movsb                                   #  BTX
226                    ljmp $SEL_SCODE16,$pm_16      # Jump to 16-bit PM
227                    .code16
228pm_16:              mov $SEL_RDATA,%ax            # Initialize
229                    mov %ax,%ds                             #  %ds and
230                    mov %ax,%es                             #  %es to a real mode selector
231                    mov %cr0,%eax                           # Turn off
232                    and $~0x1,%al                           #  protected
233                    mov %eax,%cr0                           #  mode
234                    ljmp $0,$pm_end                         # Long jump to clear the
235                                                            #  instruction pre-fetch queue
236pm_end:             sti                                     # Turn interrupts back on now
237
238                    /*
239                     * Copy the BTX client to MEM_BTX_USR.
240                     */
241                    xor %ax,%ax                             # zero %ax and set
242                    mov %ax,%ds                             #  %ds and %es
243                    mov %ax,%es                             #  to segment 0
244                    mov $MEM_BTX_USR,%di                    # Prepare to relocate
245                    mov $btx_client,%si           #  the simple btx client
246                    mov $(btx_client_end-btx_client),%cx # length of btx client
247                    rep                                     # Relocate the
248                    movsb                                   #  simple BTX client
249
250                    /*
251                     * Copy the boot[12] args to where the BTX client
252                     * can see them.
253                     */
254                    mov $MEM_ARG,%si              # where the args are at now
255                    mov $MEM_BTX_USR_ARG,%di      # where the args are moving to
256                    mov $(MEM_ARG_SIZE/4),%cx     # size of the arguments in longs
257                    rep                                     # Relocate
258                    movsl                                   #  the words
259
260                    /*
261                     * Save the entry point so the client can get to it
262                     * later on
263                     */
264                    pop %eax                      # Restore saved entry point
265                    stosl                                   #  and add it to the end of
266                                                            #  the arguments
267                    /*
268                     * Now we just start up BTX and let it do the rest
269                     */
270                    mov $msg_jump,%si             # Display the
271                    call putstr                             #  jump message
272                    ljmp $0,$MEM_BTX_ENTRY                  # Jump to the BTX entry point
273
274                    /*
275                     * Lookup the file in the path at [SI] from the root
276                     * directory.
277                     *
278                     * Trashes: All but BX
279                     * Returns: BX = pointer to record
280                     */
281lookup:             mov $VD_ROOTDIR+MEM_VOLDESC,%bx         # Root directory record
282                    push %si
283                    mov $msg_lookup,%si           # Display lookup message
284                    call putstr
285                    pop %si
286                    push %si
287                    call putstr
288                    mov $msg_lookup2,%si
289                    call putstr
290                    pop %si
291lookup_dir:         lodsb                                   # Get first char of path
292                    cmp $0,%al                              # Are we done?
293                    je lookup_done                          # Yes
294                    cmp $'/',%al                            # Skip path separator.
295                    je lookup_dir
296                    dec %si                                 # Undo lodsb side effect
297                    call find_file                          # Lookup first path item
298                    jnc lookup_dir                          # Try next component
299                    mov $msg_lookupfail,%si                 # Not found.
300                    jmp error
301lookup_done:        mov $msg_lookupok,%si                   # Success message
302                    call putstr
303                    ret
304
305                    /*
306                     * Lookup file at [SI] in directory whose record is at [BX].
307                     *
308                     * Trashes: All but returns
309                     *
310                     * Returns:         CF = 0 (success)
311                     *                  BX = pointer to record,
312                     *                  SX = next path item
313                     *                  CF = 1 (not found)
314                     *                  SI = preserved
315                     */
316find_file:          mov DIR_EXTENT(%bx),%eax      # Load extent
317                    xor %edx,%edx
318                    mov DIR_EA_LEN(%bx),%dl
319                    add %edx,%eax                           # Skip extended attributes
320                    mov %eax,rec_lba              # Save LBA
321                    mov DIR_SIZE(%bx),%eax                  # Save size
322                    mov %eax,rec_size
323                    xor %cl,%cl                             # Zero length
324                    push %si                      # Save
325ff.namelen:         inc %cl                                 # Update length
326                    lodsb                                   # Read char
327                    cmp $0,%al                              # Nul?
328                    je ff.namedone                          # Yes
329                    cmp $'/',%al                            # Path separator?
330                    jnz ff.namelen                          # No, keep going
331ff.namedone:        dec %cl                                 # Adjust length and save
332                    mov %cl,name_len
333                    pop %si                                 # Restore
334ff.load:  mov rec_lba,%eax              # Load LBA
335                    mov $MEM_DIR,%ebx             # Address buffer
336                    mov $1,%dh                              # One sector
337                    call read                     # Read directory block
338                    incl rec_lba                            # Update LBA to next block
339ff.scan:  mov %ebx,%edx                           # Check for EOF
340                    sub $MEM_DIR,%edx
341                    cmp %edx,rec_size
342                    ja ff.scan.1
343                    stc                                     # EOF reached
344                    ret
345ff.scan.1:          cmpb $0,DIR_LEN(%bx)                    # Last record in block?
346                    je ff.nextblock
347                    push %si                      # Save
348                    movzbw DIR_NAMELEN(%bx),%si   # Find end of string
349ff.checkver:        cmpb $'0',DIR_NAME-1(%bx,%si) # Less than '0'?
350                    jb ff.checkver.1
351                    cmpb $'9',DIR_NAME-1(%bx,%si) # Greater than '9'?
352                    ja ff.checkver.1
353                    dec %si                                 # Next char
354                    jnz ff.checkver
355                    jmp ff.checklen                         # All numbers in name, so
356                                                            #  no version
357ff.checkver.1:      movzbw DIR_NAMELEN(%bx),%cx
358                    cmp %cx,%si                             # Did we find any digits?
359                    je ff.checkdot                          # No
360                    cmpb $';',DIR_NAME-1(%bx,%si) # Check for semicolon
361                    jne ff.checkver.2
362                    dec %si                                 # Skip semicolon
363                    mov %si,%cx
364                    mov %cl,DIR_NAMELEN(%bx)      # Adjust length
365                    jmp ff.checkdot
366ff.checkver.2:      mov %cx,%si                             # Restore %si to end of string
367ff.checkdot:        cmpb $'.',DIR_NAME-1(%bx,%si) # Trailing dot?
368                    jne ff.checklen                         # No
369                    decb DIR_NAMELEN(%bx)                   # Adjust length
370ff.checklen:        pop %si                                 # Restore
371                    movzbw name_len,%cx           # Load length of name
372                    cmp %cl,DIR_NAMELEN(%bx)      # Does length match?
373                    je ff.checkname                         # Yes, check name
374ff.nextrec:         add DIR_LEN(%bx),%bl                    # Next record
375                    adc $0,%bh
376                    jmp ff.scan
377ff.nextblock:       subl $SECTOR_SIZE,rec_size    # Adjust size
378                    jnc ff.load                             # If subtract ok, keep going
379                    ret                                     # End of file, so not found
380ff.checkname:       lea DIR_NAME(%bx),%di                   # Address name in record
381                    push %si                      # Save
382                    repe cmpsb                              # Compare name
383                    testw %cx,%cx
384                    jz ff.match                             # We have a winner!
385                    pop %si                                 # Restore
386                    jmp ff.nextrec                          # Keep looking.
387ff.match: add $2,%sp                              # Discard saved %si
388                    clc                                     # Clear carry
389                    ret
390
391                    /*
392                     * Load DH sectors starting at LBA EAX into [EBX].  No
393                     * registers are destroyed.  Don't trust the BIOS, especially
394                     * with regards to the msb 16 bits of our registers.
395                     */
396read:               pushal                                  # dont screw around
397                    mov %eax,edd_lba              # LBA to read from
398                    mov %ebx,%eax                           # Convert address
399                    shr $4,%eax                             #  to segment
400                    mov %ax,edd_addr+0x2                    #  and store
401                    call twiddle                            # Entertain the user
402                    mov $edd_packet,%si           # Address Packet
403                    mov %dh,edd_len                         # Set length
404                    mov drive,%dl                           # BIOS Device
405                    mov $0x42,%ah                           # BIOS: Extended Read
406                    int $0x13                     # Call BIOS
407                    jc read.fail                            # Worked?
408                    popal
409                    ret                                     # Return
410read.fail:          cmp $ERROR_TIMEOUT,%ah
411                    jne read.error
412
413                    # Tell the user what is going on
414                    #
415                    mov $msg_timeout,%si
416                    call putstr
417
418                    # If an error occurs wait a second and try again.  Also
419                    # reload the packet.  In early boot CDs can timeout for
420                    # a lengthy period and if we do not delay the retry
421                    # the BIOS can get seriously confused and wind up returning
422                    # endless timeouts.
423                    #
424                    movw      $0200,%ax
425                    int       $0x1a                         # returns seconds in %dh
426                    mov       %dx,%ax
4271:                  push      %ax
428                    movw      $0200,%ax           # returns seconds in %dh
429                    int       $0x1a
430                    pop       %ax
431                    cmp       %ah,%dh                       # wait for seconds to cycle
432                    je        1b
433                    popal
434                    jmp       read
435
436read.error:         mov %ah,%al                             # Save error
437                    mov $hex_error,%di            # Format it
438                    call hex8                     #  as hex
439                    mov $msg_badread,%si                    # Display Read error message
440
441                    /*
442                     * Display error message at [SI] and halt.
443                     */
444error:              call putstr                             # Display message
445halt:               hlt
446                    jmp halt                      # Spin
447
448                    /*
449                     * Display a null-terminated string.
450                     *
451                     * Trashes: AX, SI
452                     */
453putstr:
454putstr.load:        lodsb                                   # load %al from %ds:(%si)
455                    test %al,%al                            # stop at null
456                    jnz putstr.putc                         # if the char != null, output it
457                    ret                                     # return when null is hit
458putstr.putc:        call putc                     # output char
459                    jmp putstr.load                         # next char
460
461                    /*
462                     * Display a single char(%al).  Don't trust the bios to save
463                     * our regs.
464                     */
465putc:               pushal
466                    mov $0x7,%bx                            # attribute for output
467                    mov $0xe,%ah                            # BIOS: put_char
468                    int $0x10                     # call BIOS, print char in %al
469                    popal
470                    ret                                     # Return to caller
471
472                    /*
473                     * Output the "twiddle"
474                     */
475twiddle:  push %ax                      # Save
476                    push %bx                      # Save
477                    mov twiddle_index,%al                   # Load index
478                    mov $twiddle_chars,%bx                  # Address table
479                    inc %al                                 # Next
480                    and $3,%al                              #  char
481                    mov %al,twiddle_index                   # Save index for next call
482                    xlat                                    # Get char
483                    call putc                     # Output it
484                    mov $8,%al                              # Backspace
485                    call putc                     # Output it
486                    pop %bx                                 # Restore
487                    pop %ax                                 # Restore
488                    ret
489
490                    /*
491                     * Enable A20. Put upper limit on amount of time we wait for the
492                     * keyboard controller to get ready (65K x ISA access time). If
493                     * we wait more than that amount it's likely that the hardware
494                     * is legacy-free and simply doesn't have keyboard controller
495                     * and don't need enabling A20 at all.
496                     */
497seta20:   cli                                     # Disable interrupts
498                    xor %cx,%cx                             # Clear
499seta20.1: inc %cx                                 # Increment, overflow?
500                    jz seta20.3                             # Yes
501                    in $0x64,%al                            # Get status
502                    test $0x2,%al                           # Busy?
503                    jnz seta20.1                            # Yes
504                    mov $0xd1,%al                           # Command: Write
505                    out %al,$0x64                           #  output port
506seta20.2: in $0x64,%al                            # Get status
507                    test $0x2,%al                           # Busy?
508                    jnz seta20.2                            # Yes
509                    mov $0xdf,%al                           # Enable
510                    out %al,$0x60                           #  A20
511seta20.3: sti                                     # Enable interrupts
512                    ret                                     # To caller
513
514                    /*
515                     * Convert AL to hex, saving the result to [EDI].
516                     */
517hex8:               pushl %eax                              # Save
518                    shrb $0x4,%al                           # Do upper
519                    call hex8.1                             #  4
520                    popl %eax                     # Restore
521hex8.1:   andb $0xf,%al                           # Get lower 4
522                    cmpb $0xa,%al                           # Convert
523                    sbbb $0x69,%al                          #  to hex
524                    das                                     #  digit
525                    orb $0x20,%al                           # To lower case
526                    stosb                                   # Save char
527                    ret                                     # (Recursive)
528
529                    /*
530                     * BTX client to start btxldr
531                     */
532                    .code32
533btx_client:         mov $(MEM_BTX_USR_ARG-MEM_BTX_USR+MEM_ARG_SIZE-4), %esi
534                                                            # %ds:(%esi) -> end
535                                                            #  of boot[12] args
536                    mov $(MEM_ARG_SIZE/4),%ecx    # Number of words to push
537                    std                                     # Go backwards
538push_arg: lodsl                                   # Read argument
539                    push %eax                     # Push it onto the stack
540                    loop push_arg                           # Push all of the arguments
541                    cld                                     # In case anyone depends on this
542                    pushl MEM_BTX_USR_ARG-MEM_BTX_USR+MEM_ARG_SIZE # Entry point of
543                                                            #  the loader
544                    push %eax                     # Emulate a near call
545                    mov $0x1,%eax                           # "exec" system call
546                    int $INT_SYS                            # BTX system call
547btx_client_end:
548                    .code16
549
550                    .p2align 4
551
552                    /*
553                     * Global descriptor table.
554                     */
555gdt:                .word 0x0,0x0,0x0,0x0                   # Null entry
556                    .word 0xffff,0x0,0x9200,0xcf  # SEL_SDATA
557                    .word 0xffff,0x0,0x9200,0x0   # SEL_RDATA
558                    .word 0xffff,0x0,0x9a00,0xcf  # SEL_SCODE (32-bit)
559                    .word 0xffff,0x0,0x9a00,0x8f  # SEL_SCODE16 (16-bit)
560gdt.1:
561
562                    /*
563                     * Pseudo-descriptors.
564                     */
565gdtdesc:  .word gdt.1-gdt-1             # Limit
566                    .long gdt                     # Base
567
568                    /*
569                     * EDD Packet
570                     */
571edd_packet:         .byte 0x10                              # Length
572                    .byte 0                                 # Reserved
573edd_len:  .byte 0x0                     # Num to read
574                    .byte 0                                 # Reserved
575edd_addr: .word 0x0,0x0                           # Seg:Off
576edd_lba:  .quad 0x0                     # LBA
577
578drive:              .byte 0
579
580                    /*
581                     * State for searching dir
582                     */
583rec_lba:  .long 0x0                     # LBA (adjusted for EA)
584rec_size: .long 0x0                     # File size
585name_len: .byte 0x0                     # Length of current name
586
587twiddle_index:      .byte 0x0
588
589msg_welcome:        .asciz    "CD Loader 1.01\r\n\n"
590msg_bootinfo:       .asciz    "Building the boot loader arguments\r\n"
591msg_relocate:       .asciz    "Relocating the loader and the BTX\r\n"
592msg_jump: .asciz    "Starting the BTX loader\r\n"
593msg_badread:        .ascii  "Read Error: 0x"
594hex_error:          .asciz    "00\r\n"
595msg_novd: .asciz  "Could not find Primary Volume Descriptor\r\n"
596msg_lookup:         .asciz  "Looking up "
597msg_lookup2:        .asciz  "... "
598msg_lookupok:       .asciz  "Found\r\n"
599msg_lookupfail:     .asciz  "File not found\r\n"
600msg_load2big:       .asciz  "File too big\r\n"
601msg_timeout:        .asciz  "Drive not ready, retry\r\n"
602loader_path:        .asciz  "/BOOT/LOADER"
603twiddle_chars:      .ascii    "|/-\\"
604
605