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