cdboot.S revision 167191
1# 2# Copyright (c) 2006 TAKAHASHI Yoshihiro <nyan@FreeBSD.org> 3# Copyright (c) 2001 John Baldwin <jhb@FreeBSD.org> 4# All rights reserved. 5# 6# Redistribution and use in source and binary forms, with or without 7# modification, are permitted provided that the following conditions 8# are met: 9# 1. Redistributions of source code must retain the above copyright 10# notice, this list of conditions and the following disclaimer. 11# 2. Redistributions in binary form must reproduce the above copyright 12# notice, this list of conditions and the following disclaimer in the 13# documentation and/or other materials provided with the distribution. 14# 3. Neither the name of the author nor the names of any co-contributors 15# may be used to endorse or promote products derived from this software 16# without specific prior written permission. 17# 18# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28# SUCH DAMAGE. 29# 30 31# $FreeBSD: head/sys/boot/pc98/cdboot/cdboot.s 167191 2007-03-04 04:53:17Z nyan $ 32 33# 34# Basically, we first create a set of boot arguments to pass to the loaded 35# binary. Then we attempt to load /boot/loader from the CD we were booted 36# off of. 37# 38 39# 40# Memory locations. 41# 42 .set STACK_OFF,0x6000 # Stack offset 43 .set LOAD_SEG,0x0700 # Load segment 44 .set LOAD_SIZE,2048 # Load size 45 .set DAUA,0x0584 # DA/UA 46 47 .set MEM_PAGE_SIZE,0x1000 # memory page size, 4k 48 .set MEM_ARG,0x900 # Arguments at start 49 .set MEM_ARG_BTX,0xa100 # Where we move them to so the 50 # BTX client can see them 51 .set MEM_ARG_SIZE,0x18 # Size of the arguments 52 .set MEM_BTX_ADDRESS,0x9000 # where BTX lives 53 .set MEM_BTX_ENTRY,0x9010 # where BTX starts to execute 54 .set MEM_BTX_OFFSET,MEM_PAGE_SIZE # offset of BTX in the loader 55 .set MEM_BTX_CLIENT,0xa000 # where BTX clients live 56# 57# PC98 machine type from sys/pc98/pc98/pc98_machdep.h 58# 59 .set MEM_SYS, 0xa100 # System common area segment 60 .set PC98_MACHINE_TYPE, 0x0620 # PC98 machine type 61 .set EPSON_ID, 0x0624 # EPSON machine id 62 63 .set M_NEC_PC98, 0x0001 64 .set M_EPSON_PC98, 0x0002 65 .set M_NOT_H98, 0x0010 66 .set M_H98, 0x0020 67 .set M_NOTE, 0x0040 68 .set M_NORMAL, 0x1000 69 .set M_8M, 0x8000 70# 71# Signature Constants 72# 73 .set SIG1_OFF,0x1fe # Signature offset 74 .set SIG2_OFF,0x7fe # Signature offset 75# 76# a.out header fields 77# 78 .set AOUT_TEXT,0x04 # text segment size 79 .set AOUT_DATA,0x08 # data segment size 80 .set AOUT_BSS,0x0c # zero'd BSS size 81 .set AOUT_SYMBOLS,0x10 # symbol table 82 .set AOUT_ENTRY,0x14 # entry point 83 .set AOUT_HEADER,MEM_PAGE_SIZE # size of the a.out header 84# 85# Flags for kargs->bootflags 86# 87 .set KARGS_FLAGS_CD,0x1 # flag to indicate booting from 88 # CD loader 89# 90# Segment selectors. 91# 92 .set SEL_SDATA,0x8 # Supervisor data 93 .set SEL_RDATA,0x10 # Real mode data 94 .set SEL_SCODE,0x18 # PM-32 code 95 .set SEL_SCODE16,0x20 # PM-16 code 96# 97# BTX constants 98# 99 .set INT_SYS,0x30 # BTX syscall interrupt 100# 101# Constants for reading from the CD. 102# 103 .set ERROR_TIMEOUT,0x90 # BIOS timeout on read 104 .set NUM_RETRIES,3 # Num times to retry 105 .set SECTOR_SIZE,0x800 # size of a sector 106 .set SECTOR_SHIFT,11 # number of place to shift 107 .set BUFFER_LEN,0x100 # number of sectors in buffer 108 .set MAX_READ,0xf800 # max we can read at a time 109 .set MAX_READ_SEC,MAX_READ >> SECTOR_SHIFT 110 .set MEM_READ_BUFFER,0x9000 # buffer to read from CD 111 .set MEM_VOLDESC,MEM_READ_BUFFER # volume descriptor 112 .set MEM_DIR,MEM_VOLDESC+SECTOR_SIZE # Lookup buffer 113 .set VOLDESC_LBA,0x10 # LBA of vol descriptor 114 .set VD_PRIMARY,1 # Primary VD 115 .set VD_END,255 # VD Terminator 116 .set VD_ROOTDIR,156 # Offset of Root Dir Record 117 .set DIR_LEN,0 # Offset of Dir Record length 118 .set DIR_EA_LEN,1 # Offset of EA length 119 .set DIR_EXTENT,2 # Offset of 64-bit LBA 120 .set DIR_SIZE,10 # Offset of 64-bit length 121 .set DIR_NAMELEN,32 # Offset of 8-bit name len 122 .set DIR_NAME,33 # Offset of dir name 123 124# 125# Program start. 126# 127 .code16 128 .globl start 129 130start: jmp main 131 132 .org 4 133 .ascii "IPL1 " 134 135main: cld 136 137 /* Setup the stack */ 138 xor %ax,%ax 139 mov %ax,%ss 140 mov $STACK_OFF,%sp 141 142 push %ecx 143 144 /* Setup graphic screen */ 145 mov $0x42,%ah # 640x400 146 mov $0xc0,%ch 147 int $0x18 148 mov $0x40,%ah # graph on 149 int $0x18 150 151 /* Setup text screen */ 152 mov $0x0a00,%ax # 80x25 153 int $0x18 154 mov $0x0c,%ah # text on 155 int $0x18 156 mov $0x13,%ah # cursor home 157 xor %dx,%dx 158 int $0x18 159 mov $0x11,%ah # cursor on 160 int $0x18 161 162 /* Setup keyboard */ 163 mov $0x03,%ah 164 int $0x18 165 166 /* Transfer PC-9801 system common area */ 167 xor %ax,%ax 168 mov %ax,%si 169 mov %ax,%ds 170 mov %ax,%di 171 mov $MEM_SYS,%ax 172 mov %ax,%es 173 mov $0x0600,%cx 174 rep 175 movsb 176 177 /* Transfer EPSON machine type */ 178 mov $0xfd00,%ax 179 mov %ax,%ds 180 mov (0x804),%eax 181 and $0x00ffffff,%eax 182 mov %eax,%es:(EPSON_ID) 183 184 /* Set machine type to PC98_SYSTEM_PARAMETER */ 185 call machine_check 186 187 /* Load cdboot */ 188 xor %ax,%ax 189 mov %ax,%ds 190 mov $0x06,%ah /* Read data */ 191 mov (DAUA),%al /* Read drive */ 192 pop %ecx /* cylinder */ 193 xor %dx,%dx /* head / sector */ 194 mov $LOAD_SEG,%bx /* Load address */ 195 mov %bx,%es 196 xor %bp,%bp 197 mov $LOAD_SIZE,%bx /* Load size */ 198 int $0x1b 199 mov $msg_readerr,%si 200 jc error 201 202 /* Jump to cdboot */ 203 ljmp $LOAD_SEG,$cdboot 204 205# 206# Set machine type to PC98_SYSTEM_PARAMETER. 207# 208machine_check: xor %edx,%edx 209 mov %dx,%ds 210 mov $MEM_SYS,%ax 211 mov %ax,%es 212 213 /* Wait V-SYNC */ 214vsync.1: inb $0x60,%al 215 test $0x20,%al 216 jnz vsync.1 217vsync.2: inb $0x60,%al 218 test $0x20,%al 219 jz vsync.2 220 221 /* ANK 'A' font */ 222 xor %al,%al 223 outb %al,$0xa1 224 mov $0x41,%al 225 outb %al,$0xa3 226 227 /* Get 'A' font from CG window */ 228 push %ds 229 mov $0xa400,%ax 230 mov %ax,%ds 231 xor %eax,%eax 232 xor %bx,%bx 233 mov $4,%cx 234font.1: add (%bx),%eax 235 add $4,%bx 236 loop font.1 237 pop %ds 238 cmp $0x6efc58fc,%eax 239 jnz m_epson 240 241m_pc98: or $M_NEC_PC98,%edx 242 mov $0x0458,%bx 243 mov (%bx),%al 244 test $0x80,%al 245 jz m_not_h98 246 or $M_H98,%edx 247 jmp 1f 248m_epson: or $M_EPSON_PC98,%edx 249m_not_h98: or $M_NOT_H98,%edx 250 2511: inb $0x42,%al 252 test $0x20,%al 253 jz 1f 254 or $M_8M,%edx 255 2561: mov $0x0400,%bx 257 mov (%bx),%al 258 test $0x80,%al 259 jz 1f 260 or $M_NOTE,%edx 261 2621: mov $PC98_MACHINE_TYPE,%bx 263 mov %edx,%es:(%bx) 264 ret 265 266# 267# Print out the error message at [SI], wait for a keypress, and then 268# reboot the machine. 269# 270error: call putstr 271 mov $msg_keypress,%si 272 call putstr 273 xor %ax,%ax # Get keypress 274 int $0x18 275 xor %ax,%ax # CPU reset 276 outb %al,$0xf0 277halt: hlt 278 jmp halt # Spin 279 280# 281# Display a null-terminated string at [SI]. 282# 283# Trashes: AX, BX, CX, DX, SI, DI 284# 285putstr: push %ds 286 push %es 287 mov %cs,%ax 288 mov %ax,%ds 289 mov $0xa000,%ax 290 mov %ax,%es 291 mov cursor,%di 292 mov $0x00e1,%bx # Attribute 293 mov $160,%cx 294putstr.0: lodsb 295 testb %al,%al 296 jz putstr.done 297 cmp $0x0d,%al 298 jz putstr.cr 299 cmp $0x0a,%al 300 jz putstr.lf 301 mov %bl,%es:0x2000(%di) 302 stosb 303 inc %di 304 jmp putstr.move 305putstr.cr: xor %dx,%dx 306 mov %di,%ax 307 div %cx 308 sub %dx,%di 309 jmp putstr.move 310putstr.lf: add %cx,%di 311putstr.move: mov %di,%dx 312 mov $0x13,%ah # Move cursor 313 int $0x18 314 jmp putstr.0 315putstr.done: mov %di,cursor 316 pop %es 317 pop %ds 318 ret 319 320# 321# Display a single char at [AL], but don't move a cursor. 322# 323putc: push %es 324 push %di 325 push %bx 326 mov $0xa000,%bx 327 mov %bx,%es 328 mov cursor,%di 329 mov $0xe1,%bl # Attribute 330 mov %bl,%es:0x2000(%di) 331 stosb 332 pop %bx 333 pop %di 334 pop %es 335 ret 336 337msg_readerr: .asciz "Read Error\r\n" 338msg_keypress: .asciz "\r\nPress any key to reboot\r\n" 339 340/* Boot signature */ 341 342 .org SIG1_OFF,0x90 343 344 .word 0xaa55 # Magic number 345 346# 347# cdboot 348# 349cdboot: mov %cs,%ax 350 mov %ax,%ds 351 xor %ax,%ax 352 mov %ax,%es 353 mov %es:(DAUA),%al # Save BIOS boot device 354 mov %al,drive 355 mov %cx,cylinder # Save BIOS boot cylinder 356 357 mov $msg_welcome,%si # %ds:(%si) -> welcome message 358 call putstr # display the welcome message 359# 360# Setup the arguments that the loader is expecting from boot[12] 361# 362 mov $msg_bootinfo,%si # %ds:(%si) -> boot args message 363 call putstr # display the message 364 mov $MEM_ARG,%bx # %ds:(%bx) -> boot args 365 mov %bx,%di # %es:(%di) -> boot args 366 xor %eax,%eax # zero %eax 367 mov $(MEM_ARG_SIZE/4),%cx # Size of arguments in 32-bit 368 # dwords 369 rep # Clear the arguments 370 stosl # to zero 371 mov drive,%dl # Store BIOS boot device 372 mov %dl,%es:0x4(%bx) # in kargs->bootdev 373 or $KARGS_FLAGS_CD,%es:0x8(%bx) # kargs->bootflags |= 374 # KARGS_FLAGS_CD 375# 376# Load Volume Descriptor 377# 378 mov $VOLDESC_LBA,%eax # Set LBA of first VD 379load_vd: push %eax # Save %eax 380 mov $1,%dh # One sector 381 mov $MEM_VOLDESC,%ebx # Destination 382 call read # Read it in 383 cmpb $VD_PRIMARY,%es:(%bx) # Primary VD? 384 je have_vd # Yes 385 pop %eax # Prepare to 386 inc %eax # try next 387 cmpb $VD_END,%es:(%bx) # Last VD? 388 jne load_vd # No, read next 389 mov $msg_novd,%si # No VD 390 jmp error # Halt 391have_vd: # Have Primary VD 392# 393# Try to look up the loader binary using the paths in the loader_paths 394# array. 395# 396 mov $loader_paths,%si # Point to start of array 397lookup_path: push %si # Save file name pointer 398 call lookup # Try to find file 399 pop %di # Restore file name pointer 400 jnc lookup_found # Found this file 401 push %es 402 mov %cs,%ax 403 mov %ax,%es 404 xor %al,%al # Look for next 405 mov $0xffff,%cx # path name by 406 repnz # scanning for 407 scasb # nul char 408 pop %es 409 mov %di,%si # Point %si at next path 410 mov (%si),%al # Get first char of next path 411 or %al,%al # Is it double nul? 412 jnz lookup_path # No, try it. 413 mov $msg_failed,%si # Failed message 414 jmp error # Halt 415lookup_found: # Found a loader file 416# 417# Load the binary into the buffer. Due to real mode addressing limitations 418# we have to read it in in 64k chunks. 419# 420 mov %es:DIR_SIZE(%bx),%eax # Read file length 421 add $SECTOR_SIZE-1,%eax # Convert length to sectors 422 shr $SECTOR_SHIFT,%eax 423 cmp $BUFFER_LEN,%eax 424 jbe load_sizeok 425 mov $msg_load2big,%si # Error message 426 jmp error 427load_sizeok: movzbw %al,%cx # Num sectors to read 428 mov %es:DIR_EXTENT(%bx),%eax # Load extent 429 xor %edx,%edx 430 mov %es:DIR_EA_LEN(%bx),%dl 431 add %edx,%eax # Skip extended 432 mov $MEM_READ_BUFFER,%ebx # Read into the buffer 433load_loop: mov %cl,%dh 434 cmp $MAX_READ_SEC,%cl # Truncate to max read size 435 jbe load_notrunc 436 mov $MAX_READ_SEC,%dh 437load_notrunc: sub %dh,%cl # Update count 438 push %eax # Save 439 call read # Read it in 440 pop %eax # Restore 441 add $MAX_READ_SEC,%eax # Update LBA 442 add $MAX_READ,%ebx # Update dest addr 443 jcxz load_done # Done? 444 jmp load_loop # Keep going 445load_done: 446# 447# Turn on the A20 address line 448# 449 xor %ax,%ax # Turn A20 on 450 outb %al,$0xf2 451 mov $0x02,%al 452 outb %al,$0xf6 453# 454# Relocate the loader and BTX using a very lazy protected mode 455# 456 mov $msg_relocate,%si # Display the 457 call putstr # relocation message 458 mov %es:(MEM_READ_BUFFER+AOUT_ENTRY),%edi # %edi is the destination 459 mov $(MEM_READ_BUFFER+AOUT_HEADER),%esi # %esi is 460 # the start of the text 461 # segment 462 mov %es:(MEM_READ_BUFFER+AOUT_TEXT),%ecx # %ecx = length of the text 463 # segment 464 push %edi # Save entry point for later 465 lgdt gdtdesc # setup our own gdt 466 cli # turn off interrupts 467 mov %cr0,%eax # Turn on 468 or $0x1,%al # protected 469 mov %eax,%cr0 # mode 470 ljmp $SEL_SCODE,$pm_start # long jump to clear the 471 # instruction pre-fetch queue 472 .code32 473pm_start: mov $SEL_SDATA,%ax # Initialize 474 mov %ax,%ds # %ds and 475 mov %ax,%es # %es to a flat selector 476 rep # Relocate the 477 movsb # text segment 478 add $(MEM_PAGE_SIZE - 1),%edi # pad %edi out to a new page 479 and $~(MEM_PAGE_SIZE - 1),%edi # for the data segment 480 mov MEM_READ_BUFFER+AOUT_DATA,%ecx # size of the data segment 481 rep # Relocate the 482 movsb # data segment 483 mov MEM_READ_BUFFER+AOUT_BSS,%ecx # size of the bss 484 xor %eax,%eax # zero %eax 485 add $3,%cl # round %ecx up to 486 shr $2,%ecx # a multiple of 4 487 rep # zero the 488 stosl # bss 489 mov MEM_READ_BUFFER+AOUT_ENTRY,%esi # %esi -> relocated loader 490 add $MEM_BTX_OFFSET,%esi # %esi -> BTX in the loader 491 mov $MEM_BTX_ADDRESS,%edi # %edi -> where BTX needs to go 492 movzwl 0xa(%esi),%ecx # %ecx -> length of BTX 493 rep # Relocate 494 movsb # BTX 495 ljmp $SEL_SCODE16,$pm_16 # Jump to 16-bit PM 496 .code16 497pm_16: mov $SEL_RDATA,%ax # Initialize 498 mov %ax,%ds # %ds and 499 mov %ax,%es # %es to a real mode selector 500 mov %cr0,%eax # Turn off 501 and $~0x1,%al # protected 502 mov %eax,%cr0 # mode 503 ljmp $LOAD_SEG,$pm_end # Long jump to clear the 504 # instruction pre-fetch queue 505pm_end: sti # Turn interrupts back on now 506# 507# Copy the BTX client to MEM_BTX_CLIENT 508# 509 mov %cs,%ax 510 mov %ax,%ds 511 xor %ax,%ax 512 mov %ax,%es 513 mov $MEM_BTX_CLIENT,%di # Prepare to relocate 514 mov $btx_client,%si # the simple btx client 515 mov $(btx_client_end-btx_client),%cx # length of btx client 516 rep # Relocate the 517 movsb # simple BTX client 518# 519# Copy the boot[12] args to where the BTX client can see them 520# 521 xor %ax,%ax 522 mov %ax,%ds 523 mov $MEM_ARG,%si # where the args are at now 524 mov $MEM_ARG_BTX,%di # where the args are moving to 525 mov $(MEM_ARG_SIZE/4),%cx # size of the arguments in longs 526 rep # Relocate 527 movsl # the words 528# 529# Save the entry point so the client can get to it later on 530# 531 pop %eax # Restore saved entry point 532 stosl # and add it to the end of 533 # the arguments 534# 535# Now we just start up BTX and let it do the rest 536# 537 mov $msg_jump,%si # Display the 538 call putstr # jump message 539 ljmp $0,$MEM_BTX_ENTRY # Jump to the BTX entry point 540 541# 542# Lookup the file in the path at [SI] from the root directory. 543# 544# Trashes: All but BX 545# Returns: CF = 0 (success), BX = pointer to record 546# CF = 1 (not found) 547# 548lookup: mov $VD_ROOTDIR+MEM_VOLDESC,%bx # Root directory record 549 push %bx 550 push %si 551 mov $msg_lookup,%si # Display lookup message 552 call putstr 553 pop %si 554 push %si 555 call putstr 556 mov $msg_lookup2,%si 557 call putstr 558 pop %si 559 pop %bx 560lookup_dir: lodsb # Get first char of path 561 cmp $0,%al # Are we done? 562 je lookup_done # Yes 563 cmp $'/',%al # Skip path separator. 564 je lookup_dir 565 dec %si # Undo lodsb side effect 566 call find_file # Lookup first path item 567 jnc lookup_dir # Try next component 568 mov $msg_lookupfail,%si # Not found message 569 push %bx 570 call putstr 571 pop %bx 572 stc # Set carry 573 ret 574lookup_done: mov $msg_lookupok,%si # Success message 575 push %bx 576 call putstr 577 pop %bx 578 clc # Clear carry 579 ret 580 581# 582# Lookup file at [SI] in directory whose record is at [BX]. 583# 584# Trashes: All but returns 585# Returns: CF = 0 (success), BX = pointer to record, SI = next path item 586# CF = 1 (not found), SI = preserved 587# 588find_file: mov %es:DIR_EXTENT(%bx),%eax # Load extent 589 xor %edx,%edx 590 mov %es:DIR_EA_LEN(%bx),%dl 591 add %edx,%eax # Skip extended attributes 592 mov %eax,rec_lba # Save LBA 593 mov %es:DIR_SIZE(%bx),%eax # Save size 594 mov %eax,rec_size 595 xor %cl,%cl # Zero length 596 push %si # Save 597ff.namelen: inc %cl # Update length 598 lodsb # Read char 599 cmp $0,%al # Nul? 600 je ff.namedone # Yes 601 cmp $'/',%al # Path separator? 602 jnz ff.namelen # No, keep going 603ff.namedone: dec %cl # Adjust length and save 604 mov %cl,name_len 605 pop %si # Restore 606ff.load: mov rec_lba,%eax # Load LBA 607 mov $MEM_DIR,%ebx # Address buffer 608 mov $1,%dh # One sector 609 call read # Read directory block 610 incl rec_lba # Update LBA to next block 611ff.scan: mov %ebx,%edx # Check for EOF 612 sub $MEM_DIR,%edx 613 cmp %edx,rec_size 614 ja ff.scan.1 615 stc # EOF reached 616 ret 617ff.scan.1: cmpb $0,%es:DIR_LEN(%bx) # Last record in block? 618 je ff.nextblock 619 push %si # Save 620 movzbw %es:DIR_NAMELEN(%bx),%si # Find end of string 621ff.checkver: cmpb $'0',%es:DIR_NAME-1(%bx,%si) # Less than '0'? 622 jb ff.checkver.1 623 cmpb $'9',%es:DIR_NAME-1(%bx,%si) # Greater than '9'? 624 ja ff.checkver.1 625 dec %si # Next char 626 jnz ff.checkver 627 jmp ff.checklen # All numbers in name, so 628 # no version 629ff.checkver.1: movzbw %es:DIR_NAMELEN(%bx),%cx 630 cmp %cx,%si # Did we find any digits? 631 je ff.checkdot # No 632 cmpb $';',%es:DIR_NAME-1(%bx,%si) # Check for semicolon 633 jne ff.checkver.2 634 dec %si # Skip semicolon 635 mov %si,%cx 636 mov %cl,%es:DIR_NAMELEN(%bx) # Adjust length 637 jmp ff.checkdot 638ff.checkver.2: mov %cx,%si # Restore %si to end of string 639ff.checkdot: cmpb $'.',%es:DIR_NAME-1(%bx,%si) # Trailing dot? 640 jne ff.checklen # No 641 decb %es:DIR_NAMELEN(%bx) # Adjust length 642ff.checklen: pop %si # Restore 643 movzbw name_len,%cx # Load length of name 644 cmp %cl,%es:DIR_NAMELEN(%bx) # Does length match? 645 je ff.checkname # Yes, check name 646ff.nextrec: add %es:DIR_LEN(%bx),%bl # Next record 647 adc $0,%bh 648 jmp ff.scan 649ff.nextblock: subl $SECTOR_SIZE,rec_size # Adjust size 650 jnc ff.load # If subtract ok, keep going 651 ret # End of file, so not found 652ff.checkname: lea DIR_NAME(%bx),%di # Address name in record 653 push %si # Save 654 repe cmpsb # Compare name 655 je ff.match # We have a winner! 656 pop %si # Restore 657 jmp ff.nextrec # Keep looking. 658ff.match: add $2,%sp # Discard saved %si 659 clc # Clear carry 660 ret 661 662# 663# Load DH sectors starting at LBA EAX into [EBX]. 664# 665# Trashes: EAX 666# 667read: push %es # Save 668 push %bp 669 push %dx 670 push %cx 671 push %ebx 672 mov %bx,%bp # Set destination address 673 and $0x000f,%bp 674 shr $4,%ebx 675 mov %bx,%es 676 xor %bx,%bx # Set read bytes 677 mov %dh,%bl 678 shl $SECTOR_SHIFT,%bx # 2048 bytes/sec 679 mov %ax,%cx # Set LBA 680 shr $16,%eax 681 mov %ax,%dx 682read.retry: mov $0x06,%ah # BIOS device read 683 mov drive,%al 684 and $0x7f,%al 685 call twiddle # Entertain the user 686 int $0x1b # Call BIOS 687 jc read.fail # Worked? 688 pop %ebx # Restore 689 pop %cx 690 pop %dx 691 pop %bp 692 pop %es 693 ret # Return 694read.fail: cmp $ERROR_TIMEOUT,%ah # Timeout? 695 je read.retry # Yes, Retry. 696read.error: mov %ah,%al # Save error 697 mov $hex_error,%di # Format it 698 call hex8 # as hex 699 mov $msg_badread,%si # Display Read error message 700 jmp error 701 702# 703# Output the "twiddle" 704# 705twiddle: push %ax # Save 706 push %bx # Save 707 mov twiddle_index,%al # Load index 708 mov $twiddle_chars,%bx # Address table 709 inc %al # Next 710 and $3,%al # char 711 mov %al,twiddle_index # Save index for next call 712 xlat # Get char 713 call putc # Output it 714 pop %bx # Restore 715 pop %ax # Restore 716 ret 717 718# 719# Convert AL to hex, saving the result to [EDI]. 720# 721hex8: pushl %eax # Save 722 shrb $0x4,%al # Do upper 723 call hex8.1 # 4 724 popl %eax # Restore 725hex8.1: andb $0xf,%al # Get lower 4 726 cmpb $0xa,%al # Convert 727 sbbb $0x69,%al # to hex 728 das # digit 729 orb $0x20,%al # To lower case 730 mov %al,(%di) # Save char 731 inc %di 732 ret # (Recursive) 733 734# 735# BTX client to start btxldr 736# 737 .code32 738btx_client: mov $(MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE-4), %esi 739 # %ds:(%esi) -> end 740 # of boot[12] args 741 mov $(MEM_ARG_SIZE/4),%ecx # Number of words to push 742 std # Go backwards 743push_arg: lodsl # Read argument 744 push %eax # Push it onto the stack 745 loop push_arg # Push all of the arguments 746 cld # In case anyone depends on this 747 pushl MEM_ARG_BTX-MEM_BTX_CLIENT+MEM_ARG_SIZE # Entry point of 748 # the loader 749 push %eax # Emulate a near call 750 mov $0x1,%eax # 'exec' system call 751 int $INT_SYS # BTX system call 752btx_client_end: 753 .code16 754 755 .p2align 4 756# 757# Global descriptor table. 758# 759gdt: .word 0x0,0x0,0x0,0x0 # Null entry 760 .word 0xffff,0x0000,0x9200,0x00cf # SEL_SDATA 761 .word 0xffff,0x0000,0x9200,0x0000 # SEL_RDATA 762 .word 0xffff,LOAD_SEG<<4,0x9a00,0x00cf # SEL_SCODE (32-bit) 763 .word 0xffff,LOAD_SEG<<4,0x9a00,0x008f # SEL_SCODE16 (16-bit) 764gdt.1: 765# 766# Pseudo-descriptors. 767# 768gdtdesc: .word gdt.1-gdt-1 # Limit 769 .long LOAD_SEG<<4 + gdt # Base 770 771# 772# BOOT device 773# 774drive: .byte 0 775cylinder: .word 0 776 777# 778# State for searching dir 779# 780rec_lba: .long 0x0 # LBA (adjusted for EA) 781rec_size: .long 0x0 # File size 782name_len: .byte 0x0 # Length of current name 783 784cursor: .word 0 785twiddle_index: .byte 0x0 786 787msg_welcome: .asciz "CD Loader 1.2\r\n\n" 788msg_bootinfo: .asciz "Building the boot loader arguments\r\n" 789msg_relocate: .asciz "Relocating the loader and the BTX\r\n" 790msg_jump: .asciz "Starting the BTX loader\r\n" 791msg_badread: .ascii "Read Error: 0x" 792hex_error: .ascii "00\r\n" 793msg_novd: .asciz "Could not find Primary Volume Descriptor\r\n" 794msg_lookup: .asciz "Looking up " 795msg_lookup2: .asciz "... " 796msg_lookupok: .asciz "Found\r\n" 797msg_lookupfail: .asciz "File not found\r\n" 798msg_load2big: .asciz "File too big\r\n" 799msg_failed: .asciz "Boot failed\r\n" 800twiddle_chars: .ascii "|/-\\" 801loader_paths: .asciz "/BOOT.PC98/LOADER" 802 .asciz "/boot.pc98/loader" 803 .asciz "/BOOT/LOADER" 804 .asciz "/boot/loader" 805 .byte 0 806 807/* Boot signature */ 808 809 .org SIG2_OFF,0x90 810 811 .word 0xaa55 # Magic number 812