boot - Multiple changes to try to make cdboot work with more bioses
[dragonfly.git] / sys / boot / pc32 / cdboot / cdboot.S
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
98 start:          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
130 load_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
141 have_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
161 load_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
167 load_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
171 load_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
177 load_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
204 pm_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
228 pm_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
236 pm_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                  */
281 lookup:         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
291 lookup_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
301 lookup_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                  */
316 find_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
325 ff.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
331 ff.namedone:    dec %cl                         # Adjust length and save
332                 mov %cl,name_len
333                 pop %si                         # Restore
334 ff.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
339 ff.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
345 ff.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
349 ff.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
357 ff.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
366 ff.checkver.2:  mov %cx,%si                     # Restore %si to end of string
367 ff.checkdot:    cmpb $'.',DIR_NAME-1(%bx,%si)   # Trailing dot?
368                 jne ff.checklen                 # No
369                 decb DIR_NAMELEN(%bx)           # Adjust length
370 ff.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
374 ff.nextrec:     add DIR_LEN(%bx),%bl            # Next record
375                 adc $0,%bh
376                 jmp ff.scan
377 ff.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
380 ff.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.
387 ff.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                  */
396 read:           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
410 read.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
427 1:              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
436 read.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                  */
444 error:          call putstr                     # Display message
445 halt:           hlt
446                 jmp halt                        # Spin
447
448                 /*
449                  * Display a null-terminated string.
450                  *
451                  * Trashes: AX, SI
452                  */
453 putstr:
454 putstr.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
458 putstr.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                  */
465 putc:           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                  */
475 twiddle:        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                  */
497 seta20:         cli                             # Disable interrupts
498                 xor %cx,%cx                     # Clear
499 seta20.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
506 seta20.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
511 seta20.3:       sti                             # Enable interrupts
512                 ret                             # To caller
513
514                 /*
515                  * Convert AL to hex, saving the result to [EDI].
516                  */
517 hex8:           pushl %eax                      # Save
518                 shrb $0x4,%al                   # Do upper
519                 call hex8.1                     #  4
520                 popl %eax                       # Restore
521 hex8.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
533 btx_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
538 push_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
547 btx_client_end:
548                 .code16
549
550                 .p2align 4
551
552                 /*
553                  * Global descriptor table.
554                  */
555 gdt:            .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)
560 gdt.1:
561
562                 /*
563                  * Pseudo-descriptors.
564                  */
565 gdtdesc:        .word gdt.1-gdt-1               # Limit
566                 .long gdt                       # Base
567
568                 /*
569                  * EDD Packet
570                  */
571 edd_packet:     .byte 0x10                      # Length
572                 .byte 0                         # Reserved
573 edd_len:        .byte 0x0                       # Num to read
574                 .byte 0                         # Reserved
575 edd_addr:       .word 0x0,0x0                   # Seg:Off
576 edd_lba:        .quad 0x0                       # LBA
577
578 drive:          .byte 0
579
580                 /*
581                  * State for searching dir
582                  */
583 rec_lba:        .long 0x0                       # LBA (adjusted for EA)
584 rec_size:       .long 0x0                       # File size
585 name_len:       .byte 0x0                       # Length of current name
586
587 twiddle_index:  .byte 0x0
588
589 msg_welcome:    .asciz  "CD Loader 1.01\r\n\n"
590 msg_bootinfo:   .asciz  "Building the boot loader arguments\r\n"
591 msg_relocate:   .asciz  "Relocating the loader and the BTX\r\n"
592 msg_jump:       .asciz  "Starting the BTX loader\r\n"
593 msg_badread:    .ascii  "Read Error: 0x"
594 hex_error:      .asciz  "00\r\n"
595 msg_novd:       .asciz  "Could not find Primary Volume Descriptor\r\n"
596 msg_lookup:     .asciz  "Looking up "
597 msg_lookup2:    .asciz  "... "
598 msg_lookupok:   .asciz  "Found\r\n"
599 msg_lookupfail: .asciz  "File not found\r\n"
600 msg_load2big:   .asciz  "File too big\r\n"
601 msg_timeout:    .asciz  "Drive not ready, retry\r\n"
602 loader_path:    .asciz  "/BOOT/LOADER"
603 twiddle_chars:  .ascii  "|/-\\"
604