1 ; -*- fundamental -*- (asm-mode sucks) 2 ; $Id: ldlinux.asm,v 1.52 1999/06/15 03:19:07 hpa Exp $ 3 ; **************************************************************************** 4 ; 5 ; ldlinux.asm 6 ; 7 ; A program to boot Linux kernels off an MS-DOS formatted floppy disk. This 8 ; functionality is good to have for installation floppies, where it may 9 ; be hard to find a functional Linux system to run LILO off. 10 ; 11 ; This program allows manipulation of the disk to take place entirely 12 ; from MS-LOSS, and can be especially useful in conjunction with the 13 ; umsdos filesystem. 14 ; 15 ; This file is loaded in stages; first the boot sector at offset 7C00h, 16 ; then the first sector (cluster, really, but we can only assume 1 sector) 17 ; of LDLINUX.SYS at 7E00h and finally the remainder of LDLINUX.SYS at 8000h. 18 ; 19 ; Copyright (C) 1994-1999 H. Peter Anvin 20 ; 21 ; This program is free software; you can redistribute it and/or modify 22 ; it under the terms of the GNU General Public License as published by 23 ; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, 24 ; USA; either version 2 of the License, or (at your option) any later 25 ; version; incorporated herein by reference. 26 ; 27 ; **************************************************************************** 28 29 ; 30 ; Some semi-configurable constants... change on your own risk. Most are imposed 31 ; by the kernel. 32 ; 33 max_cmd_len equ 255 ; Must be odd; 255 is the kernel limit 34 retry_count equ 6 ; How patient are we with the disk? 35 HIGHMEM_MAX equ 038000000h ; Highest address for an initrd 36 DEFAULT_BAUD equ 9600 ; Default baud rate for serial port 37 BAUD_DIVISOR equ 115200 ; Serial port parameter 38 ; 39 ; Should be updated with every release to avoid bootsector/SYS file mismatch 40 ; 41 %define version_str VERSION ; Must be 4 characters long! 42 %define date DATE_STR ; Defined from the Makefile 43 %define year '1999' 44 ; 45 ; Debgging stuff 46 ; 47 ; %define debug 1 ; Uncomment to enable debugging 48 ; 49 ; ID for SYSLINUX (reported to kernel) 50 ; 51 syslinux_id equ 031h ; SYSLINUX (3) version 1.x (1) 52 ; 53 ; Segments used by Linux 54 ; 55 real_mode_seg equ 9000h 56 struc real_mode_seg_t 57 00000000 resb 20h-($-$$) ; org 20h 58 00000020 kern_cmd_magic resw 1 ; Magic # for command line 59 00000022 kern_cmd_offset resw 1 ; Offset for kernel command line 60 00000024 resb 497-($-$$) ; org 497d 61 000001F1 bs_setupsecs resb 1 ; Sectors for setup code (0 -> 4) 62 000001F2 bs_rootflags resw 1 ; Root readonly flag 63 000001F4 bs_syssize resw 1 64 000001F6 bs_swapdev resw 1 ; Swap device (obsolete) 65 000001F8 bs_ramsize resw 1 ; Ramdisk flags, formerly ramdisk size 66 000001FA bs_vidmode resw 1 ; Video mode 67 000001FC bs_rootdev resw 1 ; Root device 68 000001FE bs_bootsign resw 1 ; Boot sector signature (0AA55h) 69 00000200 su_jump resb 1 ; 0EBh 70 00000201 su_jump2 resb 1 71 00000202 su_header resd 1 ; New setup code: header 72 00000206 su_version resw 1 ; See linux/arch/i386/boot/setup.S 73 00000208 su_switch resw 1 74 0000020A su_setupseg resw 1 75 0000020C su_startsys resw 1 76 0000020E su_kver resw 1 ; Kernel version pointer 77 00000210 su_loader resb 1 ; Loader ID 78 00000211 su_loadflags resb 1 ; Load high flag 79 00000212 su_movesize resw 1 80 00000214 su_code32start resd 1 ; Start of code loaded high 81 00000218 su_ramdiskat resd 1 ; Start of initial ramdisk 82 su_ramdisklen equ $ ; Length of initial ramdisk 83 0000021C su_ramdisklen1 resw 1 84 0000021E su_ramdisklen2 resw 1 85 00000220 su_bsklugeoffs resw 1 86 00000222 su_bsklugeseg resw 1 87 00000224 su_heapend resw 1 88 00000226 resb (8000h-12)-($-$$) ; Were bootsect.S puts it... 89 linux_stack equ $ 90 linux_fdctab equ $ 91 00007FF4 resb 8000h-($-$$) 92 cmd_line_here equ $ ; Should be out of the way 93 endstruc 94 95 setup_seg equ 9020h 96 struc setup_seg_t 97 org 0h ; as 9020:0000, not 9000:0200 98 setup_entry equ $ 99 endstruc 100 101 ; 102 ; Magic number of su_header field 103 ; 104 HEADER_ID equ 'HdrS' ; HdrS (in littleendian hex) 105 ; 106 ; Flags for the su_loadflags field 107 ; 108 LOAD_HIGH equ 01h ; Large kernel, load high 109 CAN_USE_HEAP equ 80h ; Boot loader reports heap size 110 ; 111 ; The following structure is used for "virtual kernels"; i.e. LILO-style 112 ; option labels. The options we permit here are `kernel' and `append 113 ; Since there is no room in the bottom 64K for all of these, we 114 ; stick them at 8000:0000 and copy them down before we need them. 115 ; 116 ; Note: this structure can be added to, but it must 117 ; 118 %define vk_power 7 ; log2(max number of vkernels) 119 %define max_vk (1 << vk_power) ; Maximum number of vkernels 120 %define vk_shift (16-vk_power) ; Number of bits to shift 121 %define vk_size (1 << vk_shift) ; Size of a vkernel buffer 122 123 struc vkernel 124 00000000 vk_vname: resb 11 ; Virtual name **MUST BE FIRST!** 125 0000000B vk_rname: resb 11 ; Real name 126 00000016 vk_appendlen: resw 1 127 alignb 4 128 00000018 vk_append: resb max_cmd_len+1 ; Command line 129 alignb 4 130 vk_end: equ $ ; Should be <= vk_size 131 endstruc 132 133 %if (vk_end > vk_size) || (vk_size*max_vk > 65536) 134 %error "Too many vkernels defined, reduce vk_power" 135 %endif 136 137 ; 138 ; Segment assignments in the bottom 640K 139 ; 0000h - main code/data segment (and BIOS segment) 140 ; 9000h - real_mode_seg 141 ; 142 vk_seg equ 8000h ; This is where we stick'em 143 xfer_buf_seg equ 7000h ; Bounce buffer for I/O to high mem 144 fat_seg equ 5000h ; 128K area for FAT (2x64K) 145 comboot_seg equ 2000h ; COMBOOT image loading zone 146 147 ; 148 ; For our convenience: define macros for jump-over-unconditinal jumps 149 ; 150 %macro jmpz 1 151 jnz %%skip 152 jmp %1 153 %%skip: 154 %endmacro 155 156 %macro jmpnz 1 157 jz %%skip 158 jmp %1 159 %%skip: 160 %endmacro 161 162 %macro jmpe 1 163 jne %%skip 164 jmp %1 165 %%skip: 166 %endmacro 167 168 %macro jmpne 1 169 je %%skip 170 jmp %1 171 %%skip: 172 %endmacro 173 174 %macro jmpc 1 175 jnc %%skip 176 jmp %1 177 %%skip: 178 %endmacro 179 180 %macro jmpnc 1 181 jc %%skip 182 jmp %1 183 %%skip: 184 %endmacro 185 186 %macro jmpb 1 187 jnb %%skip 188 jmp %1 189 %%skip: 190 %endmacro 191 192 %macro jmpnb 1 193 jb %%skip 194 jmp %1 195 %%skip: 196 %endmacro 197 198 ; 199 ; Macros similar to res[bwd], but which works in the code segment (after 200 ; section .text) 201 ; 202 %macro zb 1 203 times %1 db 0 204 %endmacro 205 206 %macro zw 1 207 times %1 dw 0 208 %endmacro 209 210 %macro zd 1 211 times %1 dd 0 212 %endmacro 213 214 ; --------------------------------------------------------------------------- 215 ; BEGIN THE BIOS/CODE/DATA SEGMENT 216 ; --------------------------------------------------------------------------- 217 absolute 4*1Eh ; In the interrupt table 218 fdctab equ $ 219 00000078 fdctab1 resw 1 220 0000007A fdctab2 resw 1 221 222 %ifdef debug 223 org 0100h 224 ..start: 225 ; 226 ; Hook for debugger stuff. This gets automatically removed when 227 ; generating the real thing. 228 ; 229 ; Initialize the registers for debugger operation 230 ; 231 cli 232 mov ax,cs 233 mov ds,ax 234 mov es,ax 235 mov ss,ax 236 mov sp,StackBuf 237 sti 238 cld 239 ; 240 ; Load the actual boot sector so we can copy the data block 241 ; 242 xor ax,ax ; Reset floppy 243 xor dx,dx 244 int 13h 245 mov cx,6 ; Retry count... 246 debug_tryloop: push cx 247 mov bx,trackbuf 248 mov cx,0001h 249 xor dx,dx 250 mov ax,0201h 251 int 13h 252 pop cx 253 jnc debug_okay 254 loop debug_tryloop 255 int 3 ; Halt! (Breakpoint) 256 debug_okay: mov si,trackbuf+0bh 257 mov di,bsBytesPerSec 258 mov cx,33h 259 rep movsb 260 ; 261 ; Save bogus "BIOS floppy block" info to the stack in case we hit kaboom 262 ; 263 push si 264 push si 265 push si ; Writing to the trackbuf is harmless 266 ; 267 ; Copy the BIOS data area 268 ; 269 push ds 270 xor ax,ax 271 mov ds,ax 272 mov si,0400h 273 mov di,si 274 mov cx,0100h 275 rep movsw 276 pop ds 277 ; 278 ; 279 ; A NOP where we can breakpoint, then jump into the code *after* 280 ; the segment register initialization section 281 ; 282 nop 283 jmp debugentrypt 284 %endif 285 absolute 0400h 286 00000400 serial_base resw 4 ; Base addresses for 4 serial ports 287 288 absolute 0484h 289 00000484 BIOS_vidrows resb 1 ; Number of screen rows 290 291 ; 292 ; Memory below this point is reserved for the BIOS and the MBR 293 ; 294 absolute 1000h 295 trackbuf equ $ ; Track buffer goes here 296 trackbufsize equ 16384 ; Safe size of track buffer 297 ; trackbuf ends at 5000h 298 299 absolute 6000h ; Here we keep our BSS stuff 300 StackBuf equ $ ; Start the stack here (grow down - 4K) 301 00006000 VKernelBuf: resb vk_size ; "Current" vkernel 302 alignb 4 303 00006200 AppendBuf resb max_cmd_len+1 ; append= 304 00006300 KbdMap resb 256 ; Keyboard map 305 00006400 FKeyName resb 10*16 ; File names for F-key help 306 000064A0 NumBuf resb 16 ; Buffer to load number 307 NumBufEnd equ NumBuf+15 ; Pointer to last byte in NumBuf 308 alignb 4 309 000064B0 PartInfo resb 16 ; Partition table entry 310 000064C0 InitRDat resd 1 ; Load address (linear) for initrd 311 000064C4 HiLoadAddr resd 1 ; Address pointer for high load loop 312 000064C8 HighMemSize resd 1 ; End of memory pointer (bytes) 313 000064CC KernelSize resd 1 ; Size of kernel (bytes) 314 000064D0 KernelName resb 12 ; Mangled name for kernel 315 ; (note the spare byte after!) 316 RootDir equ $ ; Location of root directory 317 000064DC RootDir1 resw 1 318 000064DE RootDir2 resw 1 319 DataArea equ $ ; Location of data area 320 000064E0 DataArea1 resw 1 321 000064E2 DataArea2 resw 1 322 FBytes equ $ ; Used by open/getc 323 000064E4 FBytes1 resw 1 324 000064E6 FBytes2 resw 1 325 000064E8 RootDirSize resw 1 ; Root dir size in sectors 326 000064EA DirScanCtr resw 1 ; Used while searching directory 327 000064EC DirBlocksLeft resw 1 ; Ditto 328 000064EE EndofDirSec resw 1 ; = trackbuf+bsBytesPerSec-31 329 000064F0 RunLinClust resw 1 ; Cluster # for LDLINUX.SYS 330 000064F2 ClustSize resw 1 ; Bytes/cluster 331 000064F4 SecPerClust resw 1 ; Same as bsSecPerClust, but a word 332 000064F6 NextCluster resw 1 ; Pointer to "nextcluster" routine 333 000064F8 BufSafe resw 1 ; Clusters we can load into trackbuf 334 000064FA BufSafeSec resw 1 ; = how many sectors? 335 000064FC BufSafeBytes resw 1 ; = how many bytes? 336 000064FE EndOfGetCBuf resw 1 ; = getcbuf+BufSafeBytes 337 00006500 KernelClust resw 1 ; Kernel size in clusters 338 00006502 InitRDClust resw 1 ; Ramdisk size in clusters 339 00006504 ClustPerMoby resw 1 ; Clusters per 64K 340 00006506 FClust resw 1 ; Number of clusters in open/getc file 341 00006508 FNextClust resw 1 ; Pointer to next cluster in d:o 342 0000650A FPtr resw 1 ; Pointer to next char in buffer 343 0000650C CmdOptPtr resw 1 ; Pointer to first option on cmd line 344 0000650E KernelCNameLen resw 1 ; Length of unmangled kernel name 345 00006510 InitRDCNameLen resw 1 ; Length of unmangled initrd name 346 00006512 NextCharJump resw 1 ; Routine to interpret next print char 347 00006514 SetupSecs resw 1 ; Number of setup sectors 348 00006516 SavedSP resw 1 ; Our SP while running a COMBOOT image 349 00006518 A20Test resw 1 ; Counter for testing status of A20 350 TextAttrBX equ $ 351 0000651A TextAttribute resb 1 ; Text attribute for message file 352 0000651B TextPage resb 1 ; Active display page 353 CursorDX equ $ 354 0000651C CursorCol resb 1 ; Cursor column for message file 355 0000651D CursorRow resb 1 ; Cursor row for message file 356 ScreenSize equ $ 357 0000651E VidCols resb 1 ; Columns on screen-1 358 0000651F VidRows resb 1 ; Rows on screen-1 359 00006520 RetryCount resb 1 ; Used for disk access retries 360 00006521 KbdFlags resb 1 ; Check for keyboard escapes 361 00006522 LoadFlags resb 1 ; Loadflags from kernel 362 00006523 A20Tries resb 1 ; Times until giving up on A20 363 00006524 FuncFlag resb 1 ; == 1 if pressed 364 00006525 MNameBuf resb 11 ; Generic mangled file name buffer 365 00006530 InitRD resb 11 ; initrd= mangled name 366 0000653B KernelCName resb 13 ; Unmangled kernel name 367 00006548 InitRDCName resb 13 ; Unmangled initrd name 368 369 section .text 370 org 7C00h 371 ; 372 ; Primary entry point. Tempting as though it may be, we can't put the 373 ; initial "cli" here; the jmp opcode in the first byte is part of the 374 ; "magic number" (using the term very loosely) for the DOS superblock. 375 ; 376 bootsec equ $ 377 00000000 EB3C jmp short start ; 2 bytes 378 00000002 90 nop ; 1 byte 379 ; 380 ; "Superblock" follows -- it's in the boot sector, so it's already 381 ; loaded and ready for us 382 ; 383 00000003 5359534C494E5558 bsOemName db 'SYSLINUX' ; The SYS command sets this, so... 384 superblock equ $ 385 bsBytesPerSec zw 1 386 <1> bsBytesPerSec : 387 0000000B 0000 <1> times %1 dw 0 388 bsSecPerClust zb 1 389 <1> bsSecPerClust : 390 0000000D 00 <1> times %1 db 0 391 bsResSectors zw 1 392 <1> bsResSectors : 393 0000000E 0000 <1> times %1 dw 0 394 bsFATs zb 1 395 <1> bsFATs : 396 00000010 00 <1> times %1 db 0 397 bsRootDirEnts zw 1 398 <1> bsRootDirEnts : 399 00000011 0000 <1> times %1 dw 0 400 bsSectors zw 1 401 <1> bsSectors : 402 00000013 0000 <1> times %1 dw 0 403 bsMedia zb 1 404 <1> bsMedia : 405 00000015 00 <1> times %1 db 0 406 bsFATsecs zw 1 407 <1> bsFATsecs : 408 00000016 0000 <1> times %1 dw 0 409 bsSecPerTrack zw 1 410 <1> bsSecPerTrack : 411 00000018 0000 <1> times %1 dw 0 412 bsHeads zw 1 413 <1> bsHeads : 414 0000001A 0000 <1> times %1 dw 0 415 bsHiddenSecs equ $ 416 bsHidden1 zw 1 417 <1> bsHidden1 : 418 0000001C 0000 <1> times %1 dw 0 419 bsHidden2 zw 1 420 <1> bsHidden2 : 421 0000001E 0000 <1> times %1 dw 0 422 bsHugeSectors equ $ 423 bsHugeSec1 zw 1 424 <1> bsHugeSec1 : 425 00000020 0000 <1> times %1 dw 0 426 bsHugeSec2 zw 1 427 <1> bsHugeSec2 : 428 00000022 0000 <1> times %1 dw 0 429 bsDriveNumber zb 1 430 <1> bsDriveNumber : 431 00000024 00 <1> times %1 db 0 432 bsReserved1 zb 1 433 <1> bsReserved1 : 434 00000025 00 <1> times %1 db 0 435 bsBootSignature zb 1 ; 29h if the following fields exist 436 <1> bsBootSignature : 437 00000026 00 <1> times %1 db 0 438 bsVolumeID zd 1 439 <1> bsVolumeID : 440 00000027 00000000 <1> times %1 dd 0 441 bsVolumeLabel zb 11 442 <1> bsVolumeLabel : 443 0000002B 00 <1> times %1 db 0 444 bsFileSysType zb 8 ; Must be FAT12 for this version 445 <1> bsFileSysType : 446 00000036 00 <1> times %1 db 0 447 superblock_len equ $-superblock 448 ; 449 ; Note we don't check the constraints above now; we did that at install 450 ; time (we hope!) 451 ; 452 453 ;floppy_table equ $ ; No sense in wasting memory, overwrite start 454 455 start: 456 0000003E FA cli ; No interrupts yet, please 457 0000003F FC cld ; Copy upwards 458 ; 459 ; Set up the stack 460 ; 461 00000040 31C9 xor cx,cx 462 00000042 8ED1 mov ss,cx 463 00000044 BC0060 mov sp,StackBuf ; Just below BSS 464 00000047 8EC1 mov es,cx 465 ; 466 ; DS:SI may contain a partition table entry. Preserve it for us. 467 ; 468 00000049 B108 mov cl,8 ; Save partition info (CH == 0) 469 0000004B BFB064 mov di,PartInfo 470 0000004E F3A5 rep movsw 471 ; 472 ; Now sautee the BIOS floppy info block to that it will support decent- 473 ; size transfers; the floppy block is 11 bytes and is stored in the 474 ; INT 1Eh vector (brilliant waste of resources, eh?) 475 ; 476 ; Of course, if BIOSes had been properly programmed, we wouldn't have 477 ; had to waste precious boot sector space with this code. 478 ; 479 ; This code no longer fits. Hope that noone really needs it anymore. 480 ; (If so, it needs serious updating.) In fact, some indications is that 481 ; this code does more harm than good with all the new kinds of drives and 482 ; media. 483 ; 484 %ifdef SUPPORT_REALLY_BROKEN_BIOSES 485 lds si,[ss:fdctab] ; DS:SI -> original 486 push ds ; Save on stack in case 487 push si ; we have to bail 488 push bx 489 mov cx,6 ; 12 bytes 490 mov di,floppy_table 491 push di 492 cld 493 rep movsw ; Faster to move words 494 pop di 495 mov ds,ax ; Now we can point DS to here, too 496 mov cl,[bsSecPerTrack] ; Patch the sector count 497 mov [di+4],cl 498 mov [fdctab+2],ax ; Segment 0 499 mov [fdctab],di ; offset floppy_block 500 %else 501 00000050 8ED9 mov ds,cx ; CX == 0 502 %endif 503 ; 504 ; Ready to enable interrupts, captain 505 ; 506 00000052 FB sti 507 ; 508 ; The drive number and possibly partition information was passed to us 509 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to 510 ; trust that rather than what the superblock contains. 511 ; 512 ; Would it be better to zero out bsHidden if we don't have a partition table? 513 ; 514 ; Note: di points to beyond the end of PartInfo 515 ; 516 00000053 8816[2400] mov [bsDriveNumber],dl 517 00000057 F6C280 test dl,80h ; If floppy disk (00-7F), assume no 518 0000005A 7428 jz not_harddisk ; partition table 519 0000005C F645F07F test byte [di-16],7Fh ; Sanity check: "active flag" should 520 00000060 750A jnz no_partition ; be 00 or 80 521 00000062 8D75F8 lea si,[di-8] ; Partition offset (dword) 522 00000065 BF[1C00] mov di,bsHidden1 523 00000068 B102 mov cl,2 ; CH == 0 524 0000006A F3A5 rep movsw 525 no_partition: 526 ; 527 ; Get disk drive parameters (don't trust the superblock.) Don't do this for 528 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about 529 ; what the *drive* supports, not about the *media*. Fortunately floppy disks 530 ; tend to have a fixed, well-defined geometry which is stored in the superblock. 531 ; 532 ; DL == drive # still 533 0000006C B408 mov ah,08h 534 0000006E CD13 int 13h 535 00000070 7212 jc no_driveparm 536 00000072 20E4 and ah,ah 537 00000074 750E jnz no_driveparm 538 00000076 FEC6 inc dh ; Contains # of heads - 1 539 00000078 8836[1A00] mov [bsHeads],dh 540 0000007C 81E13F00 and cx,3fh 541 00000080 890E[1800] mov [bsSecPerTrack],cx 542 no_driveparm: 543 not_harddisk: 544 ; 545 ; Now we have to do some arithmetric to figure out where things are located. 546 ; If Micro$oft had had brains they would already have done this for us, 547 ; and stored it in the superblock at format time, but here we go, 548 ; wasting precious boot sector space again... 549 ; 550 debugentrypt: 551 00000084 31C0 xor ax,ax ; INT 13:08 destroys ES 552 00000086 8EC0 mov es,ax 553 00000088 A0[1000] mov al,[bsFATs] ; Number of FATs (AH == 0) 554 0000008B F726[1600] mul word [bsFATsecs] ; Get the size of the FAT area 555 0000008F 0306[1C00] add ax,[bsHidden1] ; Add hidden sectors 556 00000093 1316[1E00] adc dx,[bsHidden2] 557 00000097 0306[0E00] add ax,[bsResSectors] ; And reserved sectors 558 0000009B 83D200 adc dx,byte 0 559 560 0000009E A3DC64 mov [RootDir1],ax ; Location of root directory 561 000000A1 8916DE64 mov [RootDir2],dx 562 000000A5 A3E064 mov [DataArea1],ax 563 000000A8 8916E264 mov [DataArea2],dx 564 000000AC 50 push ax 565 000000AD 52 push dx 566 567 000000AE B82000 mov ax,32 ; Size of a directory entry 568 000000B1 F726[1100] mul word [bsRootDirEnts] 569 000000B5 8B1E[0B00] mov bx,[bsBytesPerSec] 570 000000B9 01D8 add ax,bx ; Round up, not down 571 000000BB 48 dec ax 572 000000BC F7F3 div bx ; Now we have the size of the root dir 573 000000BE A3E864 mov [RootDirSize],ax 574 000000C1 A3EA64 mov [DirScanCtr],ax 575 000000C4 81C3E10F add bx,trackbuf-31 576 000000C8 891EEE64 mov [EndofDirSec],bx ; End of a single directory sector 577 578 000000CC 0106E064 add [DataArea1],ax 579 000000D0 8316E26400 adc word [DataArea2],byte 0 580 581 000000D5 5A pop dx ; Reload root directory starting point 582 000000D6 58 pop ax 583 ; 584 ; Now the fun begins. We have to search the root directory for 585 ; LDLINUX.SYS and load the first sector, so we have a little more 586 ; space to have fun with. Then we can go chasing through the FAT. 587 ; Joy!! 588 ; 589 000000D7 50 sd_nextsec: push ax 590 000000D8 52 push dx 591 000000D9 BB0010 mov bx,trackbuf 592 000000DC 53 push bx 593 000000DD E88F00 call getonesec 594 000000E0 5E pop si 595 000000E1 803C00 sd_nextentry: cmp byte [si],0 ; Directory high water mark 596 000000E4 7429 je kaboom 597 000000E6 F6440B18 test byte [si+11],18h ; Must be a file 598 000000EA 750C jnz sd_not_file 599 000000EC BF[EF01] mov di,ldlinux_name 600 000000EF B90B00 mov cx,11 601 000000F2 56 push si 602 000000F3 F3A6 repe cmpsb 603 000000F5 5E pop si 604 000000F6 742D je found_it 605 000000F8 83C620 sd_not_file: add si,byte 32 ; Distance to next 606 000000FB 3B36EE64 cmp si,[EndofDirSec] 607 000000FF 72E0 jb sd_nextentry 608 00000101 5A pop dx 609 00000102 58 pop ax 610 00000103 83C001 add ax,byte 1 611 00000106 83D200 adc dx,byte 0 612 00000109 FF0EEA64 dec word [DirScanCtr] 613 0000010D 75C8 jnz sd_nextsec 614 ; 615 ; kaboom: write a message and bail out. 616 ; 617 kaboom: 618 0000010F 31F6 xor si,si 619 00000111 8ED6 mov ss,si 620 00000113 BC0060 mov sp,StackBuf ; Reset stack 621 00000116 8EDE mov ds,si ; Reset data segment 622 00000118 BE[DE01] .patch: mov si,bailmsg 623 0000011B E83900 call writestr ; Returns with AL = 0 624 0000011E 98 cbw ; AH <- 0 625 0000011F CD16 int 16h ; Wait for keypress 626 00000121 CD19 int 19h ; And try once more to boot... 627 00000123 EBFE .norge: jmp short .norge ; If int 19h returned; this is the end 628 629 ; 630 ; found_it: now we compute the location of the first sector, then 631 ; load it and JUMP (since we're almost out of space) 632 ; 633 found_it: ; Note: we actually leave two words on the stack here 634 ; (who cares?) 635 00000125 31C0 xor ax,ax 636 00000127 A0[0D00] mov al,[bsSecPerClust] 637 0000012A 89C5 mov bp,ax ; Load an entire cluster 638 0000012C 8B5C1A mov bx,[si+26] ; First cluster 639 0000012F 891EF064 mov [RunLinClust],bx ; Save for later use 640 00000133 4B dec bx ; First cluster is "cluster 2" 641 00000134 4B dec bx 642 00000135 F7E3 mul bx 643 00000137 0306E064 add ax,[DataArea1] 644 0000013B 1316E264 adc dx,[DataArea2] 645 0000013F BB[0002] mov bx,ldlinux_sys 646 00000142 E82D00 call getlinsec 647 00000145 BE[EF01] mov si,bs_magic 648 00000148 BF[1F02] mov di,ldlinux_magic 649 0000014B B91100 mov cx,magic_len 650 0000014E F3A6 repe cmpsb ; Make sure that the bootsector 651 00000150 75BD jne kaboom ; matches LDLINUX.SYS 652 ; 653 ; Done! Jump to the entry point! 654 ; 655 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000 656 ; instead of 0000:7C00 and the like. We don't want to add anything 657 ; more to the boot sector, so it is written to not assume a fixed 658 ; value in CS, but we don't want to deal with that anymore from now 659 ; on. 660 ; 661 00000152 EA[3002]0000 jmp 0:ldlinux_ent 662 663 ; 664 ; 665 ; writestr: write a null-terminated string to the console 666 ; 667 writestr: 668 00000157 AC wstr_1: lodsb 669 00000158 20C0 and al,al 670 0000015A 7412 jz return 671 0000015C B40E mov ah,0Eh ; Write to screen as TTY 672 0000015E BB0700 mov bx,0007h ; White on black, current page 673 00000161 CD10 int 10h 674 00000163 EBF2 jmp short wstr_1 675 ; 676 ; disk_error: decrement the retry count and bail if zero 677 ; 678 00000165 4E disk_error: dec si ; SI holds the disk retry counter 679 00000166 74A7 jz kaboom 680 00000168 93 xchg ax,bx ; Shorter than MOV 681 00000169 5B pop bx ; 682 0000016A 59 pop cx ; 683 0000016B 5A pop dx ; 684 0000016C EB3C jmp short disk_try_again 685 686 0000016E C3 return: ret 687 688 ; 689 ; getonesec: like getlinsec, but pre-sets the count to 1 690 ; 691 getonesec: 692 0000016F BD0100 mov bp,1 693 ; Fall through to getlinsec 694 695 ; 696 ; getlinsec: load a sequence of BP floppy sector given by the linear sector 697 ; number in DX:AX into the buffer at ES:BX. We try to optimize 698 ; by loading up to a whole track at a time, but the user 699 ; is responsible for not crossing a 64K boundary. 700 ; (Yes, BP is weird for a count, but it was available...) 701 ; 702 ; On return, BX points to the first byte after the transferred 703 ; block. 704 ; 705 ; The "stupid patch area" gets replaced by the code 706 ; mov bp,1 ; nop ... (BD 01 00 90 90...) when installing with 707 ; the -s option. 708 ; 709 ; Stylistic note: use "xchg" instead of "mov" when the source is a register 710 ; that is dead from that point; this saves space. However, please keep 711 ; the order to dst,src to keep things sane. 712 ; 713 getlinsec: 714 00000172 8B36[1800] mov si,[bsSecPerTrack] 715 ; 716 ; Dividing by sectors to get (track,sector): we may have 717 ; up to 2^18 tracks, so we need to do this in two steps 718 ; to produce a 32-bit quotient. 719 ; 720 00000176 91 xchg cx,ax ; CX <- LSW of LBA 721 00000177 92 xchg ax,dx 722 00000178 31D2 xor dx,dx ; DX:AX now == MSW of LBA 723 0000017A F7F6 div si ; Obtain MSW of track # 724 0000017C 91 xchg ax,cx ; Remainder -> MSW of new dividend 725 ; LSW of LBA -> LSW of new dividend 726 ; Quotient -> MSW of track # 727 0000017D F7F6 div si ; Obtain LSW of track #, remainder 728 0000017F 87CA xchg cx,dx ; CX <- Sector index (0-based) 729 ; DX <- MSW of track # 730 00000181 F736[1A00] div word [bsHeads] ; Convert track to head/cyl 731 ; 732 ; Now we have AX = cyl, DX = head, CX = sector (0-based), 733 ; BP = sectors to transfer, SI = bsSecPerTrack, 734 ; ES:BX = data target 735 ; 736 00000185 56 gls_nextchunk: push si ; bsSecPerTrack 737 00000186 55 push bp ; Sectors to transfer 738 739 __BEGIN_STUPID_PATCH_AREA: 740 00000187 29CE sub si,cx ; Sectors left on track 741 00000189 39F5 cmp bp,si 742 0000018B 7602 jna gls_lastchunk 743 0000018D 89F5 mov bp,si ; No more than a trackful, please! 744 __END_STUPID_PATCH_AREA: 745 gls_lastchunk: 746 0000018F 50 push ax ; Cylinder # 747 00000190 52 push dx ; Head # 748 749 00000191 51 push cx ; Sector # 750 00000192 B106 mov cl,6 ; Because IBM was STOOPID 751 00000194 D2E4 shl ah,cl ; and thought 8 bits were enough 752 ; then thought 10 bits were enough... 753 00000196 59 pop cx ; Sector # 754 00000197 51 push cx ; Sector # 755 00000198 41 inc cx ; Sector numbers are 1-based 756 00000199 08E1 or cl,ah 757 0000019B 88C5 mov ch,al 758 0000019D 88D6 mov dh,dl 759 0000019F 8A16[2400] mov dl,[bsDriveNumber] 760 000001A3 95 xchg ax,bp ; Sector to transfer count 761 ; (xchg shorter than mov) 762 000001A4 50 push ax ; Number of sectors we're transferring 763 000001A5 B402 mov ah,02h ; Read it! 764 ; 765 ; Do the disk transfer... save the registers in case we fail :( 766 ; 767 000001A7 BE0600 mov si,retry_count ; # of times to retry a disk access 768 000001AA 52 disk_try_again: push dx ; 769 000001AB 51 push cx ; 770 000001AC 53 push bx ; 771 000001AD 50 push ax ; 772 000001AE 56 push si ; 773 000001AF CD13 int 13h 774 000001B1 5E pop si ; 775 000001B2 5B pop bx ; 776 000001B3 72B0 jc disk_error 777 ; 778 ; Disk access successful 779 ; 780 000001B5 5B pop bx ; Buffer location 781 000001B6 58 pop ax ; No longer needed 782 000001B7 58 pop ax ; No longer needed 783 000001B8 5F pop di ; Sector transferred count 784 000001B9 59 pop cx ; Sector # 785 000001BA 89F8 mov ax,di ; Reduce sector left count 786 000001BC F726[0B00] mul word [bsBytesPerSec] ; Figure out how much to advance ptr 787 000001C0 01C3 add bx,ax ; Update buffer location 788 000001C2 5A pop dx ; Head # 789 000001C3 58 pop ax ; Cyl # 790 000001C4 5D pop bp ; Sectors left to transfer 791 000001C5 5E pop si ; Number of sectors/track 792 000001C6 29FD sub bp,di ; Reduce with # of sectors just read 793 000001C8 74A4 jz return ; Done! 794 000001CA 01F9 add cx,di 795 000001CC 39F1 cmp cx,si 796 000001CE 72B5 jb gls_nextchunk 797 000001D0 42 inc dx ; Next track on cyl 798 000001D1 3B16[1A00] cmp dx,[bsHeads] ; Was this the last one? 799 000001D5 7203 jb gls_nonewcyl 800 000001D7 40 inc ax ; If so, new cylinder 801 000001D8 31D2 xor dx,dx ; First head on new cylinder 802 000001DA 29F1 gls_nonewcyl: sub cx,si ; First sector on new track 803 000001DC EBA7 jmp short gls_nextchunk 804 805 000001DE 426F6F74206661696C- bailmsg: db 'Boot failed', 0Dh, 0Ah, 0 806 000001E7 65640D0A00 807 808 bs_checkpt equ $ ; Must be <= 1EFh 809 810 zb 1EFh-($-$$) 811 000001EC 00 <1> times %1 db 0 812 bs_magic equ $ ; From here to the magic_len equ 813 ; must match ldlinux_magic 814 000001EF 4C444C494E55582053- ldlinux_name: db 'LDLINUX SYS' ; Looks like this in the root dir 815 000001F8 5953 816 000001FA 34C66537 dd HEXDATE ; Hopefully unique between compiles 817 818 000001FE 55AA bootsignature dw 0AA55h 819 magic_len equ $-bs_magic 820 821 ; 822 ; =========================================================================== 823 ; End of boot sector 824 ; =========================================================================== 825 ; Start of LDLINUX.SYS 826 ; =========================================================================== 827 828 ldlinux_sys: 829 830 00000200 0D0A5359534C494E55- syslinux_banner db 0Dh, 0Ah, 'SYSLINUX ', version_str, ' ', date, ' ', 0 831 00000209 5820312E3435203139- 832 00000212 39392D30362D313420- 833 0000021B 00 834 0000021C 0D0A1A db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS 835 836 0000021F 4C444C494E55582053- ldlinux_magic db 'LDLINUX SYS' 837 00000228 5953 838 0000022A 34C66537 dd HEXDATE 839 0000022E 55AA dw 0AA55h 840 841 align 4 842 843 ldlinux_ent: 844 ; 845 ; Tell the user we got this far 846 ; 847 00000230 BE[0002] mov si,syslinux_banner 848 00000233 E821FF call writestr 849 ; 850 ; Remember, the boot sector loaded only the first cluster of LDLINUX.SYS. 851 ; We can really only rely on a single sector having been loaded. Hence 852 ; we should load the FAT into RAM and start chasing pointers... 853 ; 854 00000236 BA0100 mov dx,1 ; 64K 855 00000239 31C0 xor ax,ax 856 0000023B F736[0B00] div word [bsBytesPerSec] ; sectors/64K 857 0000023F 89C6 mov si,ax 858 859 00000241 06 push es 860 00000242 BB0050 mov bx,fat_seg ; Load into fat_seg:0000 861 00000245 8EC3 mov es,bx 862 863 00000247 A1[1C00] mov ax,[bsHidden1] ; Hidden sectors 864 0000024A 8B16[1E00] mov dx,[bsHidden2] 865 0000024E 0306[0E00] add ax,[bsResSectors] ; plus reserved sectors = FAT 866 00000252 83D200 adc dx,byte 0 867 00000255 8B0E[1600] mov cx,[bsFATsecs] ; Sectors/FAT 868 fat_load_loop: 869 00000259 89CD mov bp,cx 870 0000025B 39F5 cmp bp,si 871 0000025D 7602 jna fat_load 872 0000025F 89F5 mov bp,si ; A full 64K moby 873 fat_load: 874 00000261 31DB xor bx,bx ; Offset 0 in the current ES 875 00000263 E82201 call getlinsecsr 876 00000266 29E9 sub cx,bp 877 00000268 740F jz fat_load_done ; Last moby? 878 0000026A 01E8 add ax,bp ; Advance sector count 879 0000026C 83D200 adc dx,byte 0 880 0000026F 8CC3 mov bx,es ; Next 64K moby 881 00000271 81C30010 add bx,1000h 882 00000275 8EC3 mov es,bx 883 00000277 EBE0 jmp short fat_load_loop 884 fat_load_done: 885 00000279 07 pop es 886 ; 887 ; Fine, now we have the FAT in memory. How big is a cluster, really? 888 ; Also figure out how many clusters will fit in an 8K buffer, and how 889 ; many sectors and bytes that is 890 ; 891 0000027A 8B3E[0B00] mov di,[bsBytesPerSec] ; Used a lot below 892 893 0000027E A0[0D00] mov al,[bsSecPerClust] ; We do this in the boot 894 00000281 30E4 xor ah,ah ; sector, too, but there 895 00000283 A3F464 mov [SecPerClust],ax ; wasn't space to save it 896 00000286 89C6 mov si,ax ; Also used a lot... 897 00000288 F7E7 mul di 898 0000028A A3F264 mov [ClustSize],ax ; Bytes/cluster 899 0000028D 89C3 mov bx,ax 900 0000028F B80040 mov ax,trackbufsize 901 00000292 31D2 xor dx,dx 902 00000294 F7F3 div bx 903 00000296 A3F864 mov [BufSafe],ax ; # of cluster in trackbuf 904 00000299 F726F464 mul word [SecPerClust] 905 0000029D A3FA64 mov [BufSafeSec],ax 906 000002A0 F7E7 mul di 907 000002A2 A3FC64 mov [BufSafeBytes],ax 908 000002A5 050098 add ax,getcbuf ; Size of getcbuf is the same 909 000002A8 A3FE64 mov [EndOfGetCBuf],ax ; as for trackbuf 910 ; 911 ; FAT12 or FAT16? This computation is fscking ridiculous... 912 ; 913 000002AB 31D2 xor dx,dx 914 000002AD 31C9 xor cx,cx 915 000002AF A1[1300] mov ax,[bsSectors] 916 000002B2 21C0 and ax,ax 917 000002B4 7507 jnz have_secs 918 000002B6 A1[2000] mov ax,[bsHugeSectors] 919 000002B9 8B16[2200] mov dx,[bsHugeSectors+2] 920 000002BD 2B06[0E00] have_secs: sub ax,[bsResSectors] 921 000002C1 83DA00 sbb dx,byte 0 922 000002C4 8A0E[1000] mov cl,[bsFATs] 923 000002C8 2B06[1600] sec_fat_loop: sub ax,[bsFATsecs] 924 000002CC 83DA00 sbb dx,byte 0 925 000002CF E2F7 loop sec_fat_loop 926 000002D1 50 push ax 927 000002D2 52 push dx 928 000002D3 A1[1100] mov ax,[bsRootDirEnts] 929 000002D6 BB2000 mov bx,32 ; Smaller than shift since we 930 000002D9 F7E3 mul bx ; need the doubleword product 931 000002DB 01F8 add ax,di 932 000002DD 83D200 adc dx,byte 0 933 000002E0 83E801 sub ax,byte 1 934 000002E3 83DA00 sbb dx,byte 0 935 000002E6 F7F7 div di 936 000002E8 89C3 mov bx,ax 937 000002EA 5A pop dx 938 000002EB 58 pop ax 939 000002EC 29D8 sub ax,bx 940 000002EE 83DA00 sbb dx,byte 0 941 000002F1 F7F6 div si 942 000002F3 3DF60F cmp ax,4086 ; Right value? 943 000002F6 B8[BF03] mov ax,nextcluster_fat16 944 000002F9 7703 ja have_fat_type 945 000002FB B8[9803] have_fat12: mov ax,nextcluster_fat12 946 000002FE A3F664 have_fat_type: mov word [NextCluster],ax 947 948 ; 949 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first 950 ; cluster again, though. 951 ; 952 load_rest: 953 00000301 8B0EF264 mov cx,[ClustSize] 954 00000305 BB[0002] mov bx,ldlinux_sys 955 00000308 01CB add bx,cx 956 0000030A 8B36F064 mov si,[RunLinClust] 957 0000030E FF16F664 call [NextCluster] 958 00000312 31D2 xor dx,dx 959 00000314 B8C518 mov ax,ldlinux_len-1 ; To be on the safe side 960 00000317 01C8 add ax,cx 961 00000319 F7F1 div cx ; the number of clusters 962 0000031B 48 dec ax ; We've already read one 963 0000031C 7405 jz all_read_jmp 964 0000031E 89C1 mov cx,ax 965 00000320 E80300 call getfssec 966 ; 967 ; All loaded up 968 ; 969 all_read_jmp: 970 00000323 E9B100 jmp all_read 971 ; 972 ; ----------------------------------------------------------------------------- 973 ; Subroutines that have to be in the first sector 974 ; ----------------------------------------------------------------------------- 975 ; 976 ; getfssec: Get multiple clusters from a file, given the starting cluster. 977 ; 978 ; This routine makes sure the subtransfers do not cross a 64K boundary, 979 ; and will correct the situation if it does, UNLESS *sectors* cross 980 ; 64K boundaries. 981 ; 982 ; ES:BX -> Buffer 983 ; SI -> Starting cluster number (2-based) 984 ; CX -> Cluster count (0FFFFh = until end of file) 985 ; 986 ; 386 check 987 getfssec: 988 00000326 31ED getfragment: xor bp,bp ; Fragment sector count 989 00000328 89F0 mov ax,si ; Get sector address 990 0000032A 48 dec ax ; Convert to 0-based 991 0000032B 48 dec ax 992 0000032C F726F464 mul word [SecPerClust] 993 00000330 0306E064 add ax,[DataArea1] 994 00000334 1316E264 adc dx,[DataArea2] 995 getseccnt: ; See if we can read > 1 clust 996 00000338 032EF464 add bp,[SecPerClust] 997 0000033C 49 dec cx ; Reduce clusters left to find 998 0000033D 89F7 mov di,si ; Predict next cluster 999 0000033F 47 inc di 1000 00000340 FF16F664 call [NextCluster] 1001 00000344 7207 jc gfs_eof ; At EOF? 1002 00000346 E304 jcxz endfragment ; Or was it the last we wanted? 1003 00000348 39FE cmp si,di ; Is file continuous? 1004 0000034A 74EC jz getseccnt ; Yes, we can get 1005 0000034C F8 endfragment: clc ; Not at EOF 1006 0000034D 9C gfs_eof: pushf ; Remember EOF or not 1007 0000034E 56 push si 1008 0000034F 51 push cx 1009 gfs_getchunk: 1010 00000350 50 push ax 1011 00000351 52 push dx 1012 00000352 8CC0 mov ax,es ; Check for 64K boundaries. 1013 00000354 B104 mov cl,4 1014 00000356 D3E0 shl ax,cl 1015 00000358 01D8 add ax,bx 1016 0000035A 31D2 xor dx,dx 1017 0000035C F7D8 neg ax 1018 0000035E 7501 jnz gfs_partseg 1019 00000360 42 inc dx ; Full 64K segment 1020 gfs_partseg: 1021 00000361 F736[0B00] div word [bsBytesPerSec] ; How many sectors fit? 1022 00000365 89EE mov si,bp 1023 00000367 29C6 sub si,ax ; Compute remaining sectors 1024 00000369 7610 jbe gfs_lastchunk 1025 0000036B 89C5 mov bp,ax 1026 0000036D 5A pop dx 1027 0000036E 58 pop ax 1028 0000036F E81600 call getlinsecsr 1029 00000372 01E8 add ax,bp 1030 00000374 83D200 adc dx,byte 0 1031 00000377 89F5 mov bp,si ; Remaining sector count 1032 00000379 EBD5 jmp short gfs_getchunk 1033 0000037B 5A gfs_lastchunk: pop dx 1034 0000037C 58 pop ax 1035 0000037D E8F2FD call getlinsec 1036 00000380 59 pop cx 1037 00000381 5E pop si 1038 00000382 9D popf 1039 00000383 E302 jcxz gfs_return ; If we hit the count limit 1040 00000385 739F jnc getfragment ; If we didn't hit EOF 1041 00000387 C3 gfs_return: ret 1042 1043 ; 1044 ; getlinsecsr: save registers, call getlinsec, restore registers 1045 ; 1046 00000388 50 getlinsecsr: push ax 1047 00000389 52 push dx 1048 0000038A 51 push cx 1049 0000038B 55 push bp 1050 0000038C 56 push si 1051 0000038D 57 push di 1052 0000038E E8E1FD call getlinsec 1053 00000391 5F pop di 1054 00000392 5E pop si 1055 00000393 5D pop bp 1056 00000394 59 pop cx 1057 00000395 5A pop dx 1058 00000396 58 pop ax 1059 00000397 C3 ret 1060 1061 ; 1062 ; nextcluster: Advance a cluster pointer in SI to the next cluster 1063 ; pointed at in the FAT tables (note: FAT12 assumed) 1064 ; Sets CF on return if end of file. 1065 ; 1066 ; The variable NextCluster gets set to the appropriate 1067 ; value here. 1068 ; 1069 nextcluster_fat12: 1070 00000398 50 push ax 1071 00000399 1E push ds 1072 0000039A B80050 mov ax,fat_seg 1073 0000039D 8ED8 mov ds,ax 1074 0000039F 89F0 mov ax,si ; Multiply by 3/2 1075 000003A1 D1E8 shr ax,1 1076 000003A3 9C pushf ; CF now set if odd 1077 000003A4 01C6 add si,ax 1078 000003A6 8B34 mov si,[si] 1079 000003A8 9D popf 1080 000003A9 7308 jnc nc_even 1081 000003AB D1EE shr si,1 ; Needed for odd only 1082 000003AD D1EE shr si,1 1083 000003AF D1EE shr si,1 1084 000003B1 D1EE shr si,1 1085 nc_even: 1086 000003B3 81E6FF0F and si,0FFFh 1087 000003B7 81FEF00F cmp si,0FF0h ; Clears CF if at end of file 1088 000003BB F5 cmc ; But we want it SET... 1089 000003BC 1F pop ds 1090 000003BD 58 pop ax 1091 000003BE C3 nc_return: ret 1092 1093 ; 1094 ; FAT16 decoding routine. Note that a 16-bit FAT can be up to 128K, 1095 ; so we have to decide if we're in the "low" or the "high" 64K-segment... 1096 ; 1097 nextcluster_fat16: 1098 000003BF 50 push ax 1099 000003C0 1E push ds 1100 000003C1 B80050 mov ax,fat_seg 1101 000003C4 D1E6 shl si,1 1102 000003C6 7303 jnc .seg0 1103 000003C8 B80060 mov ax,fat_seg+1000h 1104 000003CB 8ED8 .seg0: mov ds,ax 1105 000003CD 8B34 mov si,[si] 1106 000003CF 81FEF0FF cmp si,0FFF0h 1107 000003D3 F5 cmc 1108 000003D4 1F pop ds 1109 000003D5 58 pop ax 1110 000003D6 C3 ret 1111 ; 1112 ; Debug routine 1113 ; 1114 %ifdef debug 1115 safedumpregs: 1116 cmp word [Debug_Magic],0D00Dh 1117 jnz nc_return 1118 jmp dumpregs 1119 %endif 1120 1121 rl_checkpt equ $ ; Must be <= 400h 1122 1123 ; ---------------------------------------------------------------------------- 1124 ; End of code and data that have to be in the first sector 1125 ; ---------------------------------------------------------------------------- 1126 1127 all_read: 1128 ; 1129 ; Let the user (and programmer!) know we got this far. This used to be 1130 ; in Sector 1, but makes a lot more sense here. 1131 ; 1132 000003D7 BE[6914] mov si,copyright_str 1133 000003DA E87AFD call writestr 1134 ; 1135 ; Check that no moron is trying to boot Linux on a 286 or so. According 1136 ; to Intel, the way to check is to see if the high 4 bits of the FLAGS 1137 ; register are either all stuck at 1 (8086/8088) or all stuck at 0 1138 ; (286 in real mode), if not it is a 386 or higher. They didn't 1139 ; say how to check for a 186/188, so I *hope* it falls out as a 8086 1140 ; or 286 in this test. 1141 ; 1142 ; Also, provide an escape route in case it doesn't work. 1143 ; 1144 check_escapes: 1145 000003DD B402 mov ah,02h ; Check keyboard flags 1146 000003DF CD16 int 16h 1147 000003E1 A22165 mov [KbdFlags],al ; Save for boot prompt check 1148 000003E4 A804 test al,04h ; Ctrl->skip 386 check 1149 000003E6 7538 jnz skip_checks 1150 test_8086: 1151 000003E8 9C pushf ; Get flags 1152 000003E9 58 pop ax 1153 000003EA 25FF0F and ax,0FFFh ; Clear top 4 bits 1154 000003ED 50 push ax ; Load into FLAGS 1155 000003EE 9D popf 1156 000003EF 9C pushf ; And load back 1157 000003F0 58 pop ax 1158 000003F1 2500F0 and ax,0F000h ; Get top 4 bits 1159 000003F4 3D00F0 cmp ax,0F000h ; If set -> 8086/8088 1160 000003F7 740E je not_386 1161 test_286: 1162 000003F9 9C pushf ; Get flags 1163 000003FA 58 pop ax 1164 000003FB 0D00F0 or ax,0F000h ; Set top 4 bits 1165 000003FE 50 push ax 1166 000003FF 9D popf 1167 00000400 9C pushf 1168 00000401 58 pop ax 1169 00000402 2500F0 and ax,0F000h ; Get top 4 bits 1170 00000405 7509 jnz is_386 ; If not clear -> 386 1171 not_386: 1172 00000407 BE[E114] mov si,err_not386 1173 0000040A E84AFD call writestr 1174 0000040D E9FFFC jmp kaboom 1175 is_386: 1176 ; Now we know it's a 386 or higher 1177 ; 1178 ; Now check that there is at least 608K of low (DOS) memory 1179 ; (608K = 9800h segments) 1180 ; 1181 00000410 CD12 int 12h 1182 00000412 3D6002 cmp ax,608 1183 00000415 7309 jae enough_ram 1184 00000417 BE[CE15] mov si,err_noram 1185 0000041A E83AFD call writestr 1186 0000041D E9EFFC jmp kaboom 1187 enough_ram: 1188 skip_checks: 1189 ; 1190 ; Check if we're 386 (as opposed to 486+); if so we need to blank out 1191 ; the WBINVD instruction 1192 ; 1193 ; We check for 486 by setting EFLAGS.AC 1194 ; 1195 00000420 669C pushfd ; Save the good flags 1196 00000422 669C pushfd 1197 00000424 6658 pop eax 1198 00000426 6689C3 mov ebx,eax 1199 00000429 663500000400 xor eax,(1 << 18) ; AC bit 1200 0000042F 6650 push eax 1201 00000431 669D popfd 1202 00000433 669C pushfd 1203 00000435 6658 pop eax 1204 00000437 669D popfd ; Restore the original flags 1205 00000439 6631D8 xor eax,ebx 1206 0000043C 7505 jnz is_486 1207 ; 1208 ; 386 - Looks like we better blot out the WBINVD instruction 1209 ; 1210 0000043E C606[700E]C3 mov byte [try_wbinvd],0c3h ; Near RET 1211 is_486: 1212 1213 ; 1214 ; Initialization that does not need to go into the any of the pre-load 1215 ; areas 1216 ; 1217 00000443 E8580B call adjust_screen 1218 ; 1219 ; Now, everything is "up and running"... patch kaboom for more 1220 ; verbosity and using the full screen system 1221 ; 1222 00000446 C606[1801]E9 mov byte [kaboom.patch],0e9h ; JMP NEAR 1223 0000044B C706[1901]8A10 mov word [kaboom.patch+1],kaboom2-(kaboom.patch+3) 1224 1225 ; 1226 ; Now we're all set to start with our *real* business. First load the 1227 ; configuration file (if any) and parse it. 1228 ; 1229 ; In previous versions I avoided using 32-bit registers because of a 1230 ; rumour some BIOSes clobbered the upper half of 32-bit registers at 1231 ; random. I figure, though, that if there are any of those still left 1232 ; they probably won't be trying to install Linux on them... 1233 ; 1234 ; The code is still ripe with 16-bitisms, though. Not worth the hassle 1235 ; to take'm out. In fact, we may want to put them back if we're going 1236 ; to boot ELKS at some point. 1237 ; 1238 00000451 BE[CE18] mov si,linuxauto_cmd ; Default command: "linux auto" 1239 00000454 BF[E519] mov di,default_cmd 1240 00000457 B90B00 mov cx,linuxauto_len 1241 0000045A F3A4 rep movsb 1242 1243 0000045C BF0063 mov di,KbdMap ; Default keymap 1:1 1244 0000045F 30C0 xor al,al 1245 00000461 B90001 mov cx,256 1246 00000464 AA mkkeymap: stosb 1247 00000465 FEC0 inc al 1248 00000467 E2FB loop mkkeymap 1249 1250 ; 1251 ; Load configuration file 1252 ; 1253 00000469 BF[6A18] mov di,syslinux_cfg 1254 0000046C E8430D call open 1255 0000046F 0F840D02 jz near no_config_file 1256 parse_config: 1257 00000473 E8D80D call getkeyword 1258 00000476 0F820302 jc near end_config_file ; Config file loaded 1259 0000047A 3D6465 cmp ax,'de' ; DEfault 1260 0000047D 7449 je pc_default 1261 0000047F 3D6170 cmp ax,'ap' ; APpend 1262 00000482 7454 je pc_append 1263 00000484 3D7469 cmp ax,'ti' ; TImeout 1264 00000487 0F849C00 je near pc_timeout 1265 0000048B 3D7072 cmp ax,'pr' ; PRompt 1266 0000048E 0F84B200 je near pc_prompt 1267 00000492 3D666F cmp ax,'fo' ; FOnt 1268 00000495 0F848E01 je near pc_font 1269 00000499 3D6B62 cmp ax,'kb' ; KBd 1270 0000049C 0F849101 je near pc_kbd 1271 000004A0 3D6469 cmp ax,'di' ; DIsplay 1272 000004A3 0F849200 je near pc_display 1273 000004A7 3D6C61 cmp ax,'la' ; LAbel 1274 000004AA 0F844601 je near pc_label 1275 000004AE 3D6B65 cmp ax,'ke' ; KErnel 1276 000004B1 745B je pc_kernel 1277 000004B3 3D696D cmp ax,'im' ; IMplicit 1278 000004B6 0F849500 je near pc_implicit 1279 000004BA 3D7365 cmp ax,'se' ; SErial 1280 000004BD 0F849900 je near pc_serial 1281 000004C1 3C66 cmp al,'f' ; F-key 1282 000004C3 75AE jne parse_config 1283 000004C5 E90201 jmp pc_fkey 1284 1285 000004C8 BF[E519] pc_default: mov di,default_cmd ; "default" command 1286 000004CB E8910E call getline 1287 000004CE BE[D418] mov si,auto_cmd ; add "auto"+null 1288 000004D1 B90500 mov cx,auto_len 1289 000004D4 F3A4 rep movsb 1290 000004D6 EB9B jmp short parse_config 1291 1292 000004D8 833E[C618]00 pc_append: cmp word [VKernelCtr],byte 0 ; "append" command 1293 000004DD 7710 ja pc_append_vk 1294 000004DF BF0062 mov di,AppendBuf 1295 000004E2 E87A0E call getline 1296 000004E5 81EF0062 sub di,AppendBuf 1297 000004E9 893E[BC18] pc_app1: mov [AppendLen],di 1298 000004ED EB84 jmp short parse_config 1299 000004EF BF1860 pc_append_vk: mov di,VKernelBuf+vk_append ; "append" command (vkernel) 1300 000004F2 E86A0E call getline 1301 000004F5 81EF1860 sub di,VKernelBuf+vk_append 1302 000004F9 83FF02 cmp di,byte 2 1303 000004FC 750A jne pc_app2 1304 000004FE 803E18602D cmp byte [VKernelBuf+vk_append],'-' 1305 00000503 7503 jne pc_app2 1306 00000505 BF0000 mov di,0 ; If "append -" -> null string 1307 00000508 893E1660 pc_app2: mov [VKernelBuf+vk_appendlen],di 1308 0000050C EB33 jmp short parse_config_2 1309 1310 0000050E 833E[C618]00 pc_kernel: cmp word [VKernelCtr],byte 0 ; "kernel" command 1311 00000513 0F845CFF je near parse_config ; ("label" section only) 1312 00000517 BF0010 mov di,trackbuf 1313 0000051A 57 push di 1314 0000051B E8410E call getline 1315 0000051E 5E pop si 1316 0000051F BF0B60 mov di,VKernelBuf+vk_rname 1317 00000522 E8770E call mangle_name 1318 00000525 EB1A jmp short parse_config_2 1319 1320 00000527 E8800D pc_timeout: call getint ; "timeout" command 1321 0000052A 7215 jc parse_config_2 1322 0000052C B815D2 mov ax,0D215h ; There are approx 1.D215h 1323 0000052F F7E3 mul bx ; clock ticks per 1/10 s 1324 00000531 01D3 add bx,dx 1325 00000533 891E[BE18] mov [KbdTimeOut],bx 1326 00000537 EB08 jmp short parse_config_2 1327 1328 00000539 E80001 pc_display: call pc_getfile ; "display" command 1329 0000053C 7403 jz parse_config_2 ; File not found? 1330 0000053E E8D60A call get_msg_file ; Load and display file 1331 00000541 E92FFF parse_config_2: jmp parse_config 1332 1333 00000544 E8630D pc_prompt: call getint ; "prompt" command 1334 00000547 72F8 jc parse_config_2 1335 00000549 891E[C818] mov [ForcePrompt],bx 1336 0000054D EBF2 jmp short parse_config_2 1337 1338 0000054F E8580D pc_implicit: call getint ; "implicit" command 1339 00000552 72ED jc parse_config_2 1340 00000554 891E[CA18] mov [AllowImplicit],bx 1341 00000558 EBE7 jmp short parse_config_2 1342 1343 0000055A E84D0D pc_serial: call getint ; "serial" command 1344 0000055D 72E2 jc parse_config_2 1345 0000055F 53 push bx ; Serial port # 1346 00000560 E8D20C call skipspace 1347 00000563 72DC jc parse_config_2 1348 00000565 E8BC0C call ungetc 1349 00000568 E83F0D call getint 1350 0000056B 7306 jnc .valid_baud 1351 0000056D 66BB80250000 mov ebx,DEFAULT_BAUD ; No baud rate given 1352 00000573 5F .valid_baud: pop di ; Serial port # 1353 00000574 6683FB4B cmp ebx,byte 75 1354 00000578 72C7 jb parse_config_2 ; < 75 baud == bogus 1355 0000057A 66B800C20100 mov eax,BAUD_DIVISOR 1356 00000580 6699 cdq 1357 00000582 66F7F3 div ebx 1358 00000585 50 push ax ; Baud rate divisor 1359 00000586 89FA mov dx,di 1360 00000588 D1E7 shl di,1 1361 0000058A 8B850004 mov ax,[di+serial_base] 1362 0000058E A3[CC18] mov [SerialPort],ax 1363 00000591 50 push ax ; Serial port base 1364 00000592 B8E300 mov ax,00e3h ; INT 14h init parameters 1365 00000595 CD14 int 14h ; Init serial port 1366 00000597 5B pop bx ; Serial port base 1367 00000598 8D5703 lea dx,[bx+3] 1368 0000059B B083 mov al,83h ; Enable DLAB 1369 0000059D E83908 call slow_out 1370 000005A0 58 pop ax ; Divisor 1371 000005A1 89DA mov dx,bx 1372 000005A3 E83308 call slow_out 1373 000005A6 42 inc dx 1374 000005A7 88E0 mov al,ah 1375 000005A9 E82D08 call slow_out 1376 000005AC B003 mov al,03h ; Disable DLAB 1377 000005AE 83C202 add dx,byte 2 1378 000005B1 E82508 call slow_out 1379 000005B4 83EA02 sub dx,byte 2 1380 000005B7 30C0 xor al,al ; IRQ disable 1381 000005B9 E81D08 call slow_out 1382 1383 ; Show some life 1384 000005BC BE[0002] mov si,syslinux_banner 1385 000005BF E87E0B call write_serial_str 1386 000005C2 BE[6914] mov si,copyright_str 1387 000005C5 E8780B call write_serial_str 1388 1389 000005C8 EB6F jmp short parse_config_3 1390 1391 000005CA 80EC31 pc_fkey: sub ah,'1' 1392 000005CD 7302 jnb pc_fkey1 1393 000005CF B409 mov ah,9 ; F10 1394 000005D1 31C9 pc_fkey1: xor cx,cx 1395 000005D3 88E1 mov cl,ah 1396 000005D5 51 push cx 1397 000005D6 B80100 mov ax,1 1398 000005D9 D3E0 shl ax,cl 1399 000005DB 0906[C018] or [FKeyMap], ax ; Mark that we have this loaded 1400 000005DF BF0010 mov di,trackbuf 1401 000005E2 57 push di 1402 000005E3 E8790D call getline ; Get filename to display 1403 000005E6 5E pop si 1404 000005E7 5F pop di 1405 000005E8 C1E704 shl di,4 ; Multiply number by 16 1406 000005EB 81C70064 add di,FKeyName 1407 000005EF E8AA0D call mangle_name ; Mangle file name 1408 000005F2 EB45 jmp short parse_config_3 1409 1410 000005F4 E85800 pc_label: call commit_vk ; Commit any current vkernel 1411 000005F7 BF0010 mov di,trackbuf ; Get virtual filename 1412 000005FA 57 push di 1413 000005FB E8610D call getline 1414 000005FE 5E pop si 1415 000005FF BF0060 mov di,VKernelBuf+vk_vname 1416 00000602 E8970D call mangle_name ; Mangle virtual name 1417 00000605 FF06[C618] inc word [VKernelCtr] ; One more vkernel 1418 00000609 BE0060 mov si,VKernelBuf+vk_vname ; By default, rname == vname 1419 0000060C BF0B60 mov di,VKernelBuf+vk_rname 1420 0000060F B90B00 mov cx,11 1421 00000612 F3A4 rep movsb 1422 00000614 BE0062 mov si,AppendBuf ; Default append==global append 1423 00000617 BF1860 mov di,VKernelBuf+vk_append 1424 0000061A 8B0E[BC18] mov cx,[AppendLen] 1425 0000061E 890E1660 mov [VKernelBuf+vk_appendlen],cx 1426 00000622 F3A4 rep movsb 1427 00000624 E91200 jmp near parse_config_3 1428 1429 00000627 E81200 pc_font: call pc_getfile ; "font" command 1430 0000062A 740D jz parse_config_3 ; File not found? 1431 0000062C E88A09 call loadfont ; Load and install font 1432 0000062F EB08 jmp short parse_config_3 1433 1434 00000631 E80800 pc_kbd: call pc_getfile ; "kbd" command 1435 00000634 7403 jz parse_config_3 1436 00000636 E8BF09 call loadkeys 1437 00000639 E937FE parse_config_3: jmp parse_config 1438 1439 ; 1440 ; pc_getfile: For command line options that take file argument, this 1441 ; routine decodes the file argument and runs it through searchdir 1442 ; 1443 0000063C BF0010 pc_getfile: mov di,trackbuf 1444 0000063F 57 push di 1445 00000640 E81C0D call getline 1446 00000643 5E pop si 1447 00000644 BF2565 mov di,MNameBuf 1448 00000647 57 push di 1449 00000648 E8510D call mangle_name 1450 0000064B 5F pop di 1451 0000064C E9CC08 jmp searchdir ; Tailcall 1452 1453 ; 1454 ; commit_vk: Store the current VKernelBuf into buffer segment 1455 ; 1456 commit_vk: 1457 0000064F 833E[C618]00 cmp word [VKernelCtr],byte 0 1458 00000654 741F je cvk_ret ; No VKernel = return 1459 00000656 813E[C618]8000 cmp word [VKernelCtr],max_vk ; Above limit? 1460 0000065C 7718 ja cvk_overflow 1461 0000065E 8B3E[C618] mov di,[VKernelCtr] 1462 00000662 4F dec di 1463 00000663 C1E709 shl di,vk_shift 1464 00000666 BE0060 mov si,VKernelBuf 1465 00000669 B98000 mov cx,(vk_size >> 2) 1466 0000066C 06 push es 1467 0000066D 680080 push word vk_seg 1468 00000670 07 pop es 1469 00000671 F366A5 rep movsd ; Copy to buffer segment 1470 00000674 07 pop es 1471 00000675 C3 cvk_ret: ret 1472 00000676 C706[C618]8000 cvk_overflow: mov word [VKernelCtr],max_vk ; No more than max_vk, please 1473 0000067C C3 ret 1474 1475 ; 1476 ; End of configuration file 1477 ; 1478 end_config_file: 1479 0000067D E8CFFF call commit_vk ; Commit any current vkernel 1480 no_config_file: 1481 ; 1482 ; Check whether or not we are supposed to display the boot prompt. 1483 ; 1484 check_for_key: 1485 00000680 833E[C818]00 cmp word [ForcePrompt],byte 0 ; Force prompt? 1486 00000685 7509 jnz enter_command 1487 00000687 F60621655B test byte [KbdFlags],5Bh ; Caps, Scroll, Shift, Alt 1488 0000068C 0F84EC00 jz near auto_boot ; If neither, default boot 1489 1490 enter_command: 1491 00000690 BE[9314] mov si,boot_prompt 1492 00000693 E8C20A call cwritestr 1493 1494 00000696 C606246500 mov byte [FuncFlag],0 ; not pressed 1495 0000069B BF[E418] mov di,command_line 1496 ; 1497 ; get the very first character -- we can either time 1498 ; out, or receive a character press at this time. Some dorky BIOSes stuff 1499 ; a return in the buffer on bootup, so wipe the keyboard buffer first. 1500 ; 1501 0000069E B401 clear_buffer: mov ah,1 ; Check for pending char 1502 000006A0 CD16 int 16h 1503 000006A2 7406 jz get_char_time 1504 000006A4 31C0 xor ax,ax ; Get char 1505 000006A6 CD16 int 16h 1506 000006A8 EBF4 jmp short clear_buffer 1507 000006AA 8B0E[BE18] get_char_time: mov cx,[KbdTimeOut] 1508 000006AE 21C9 and cx,cx 1509 000006B0 7419 jz get_char ; Timeout == 0 -> no timeout 1510 000006B2 41 inc cx ; The first loop will happen 1511 ; immediately as we don't 1512 ; know the appropriate DX value 1513 000006B3 51 time_loop: push cx 1514 000006B4 52 tick_loop: push dx 1515 000006B5 E8AD0A call pollchar 1516 000006B8 750F jnz get_char_pop 1517 000006BA 31C0 xor ax,ax 1518 000006BC CD1A int 1Ah ; Get time "of day" 1519 000006BE 58 pop ax 1520 000006BF 39C2 cmp dx,ax ; Has the timer advanced? 1521 000006C1 74F1 je tick_loop 1522 000006C3 59 pop cx 1523 000006C4 E2ED loop time_loop ; If so, decrement counter 1524 000006C6 E9C100 jmp command_done ; Timeout! 1525 1526 000006C9 6658 get_char_pop: pop eax ; Clear stack 1527 000006CB E8AE0A get_char: call getchar 1528 000006CE 20C0 and al,al 1529 000006D0 7462 jz func_key 1530 1531 000006D2 3C7F got_ascii: cmp al,7Fh ; == 1532 000006D4 743F je backspace 1533 000006D6 3C20 cmp al,' ' ; ASCII? 1534 000006D8 722A jb not_ascii 1535 000006DA 7706 ja enter_char 1536 000006DC 81FF[E418] cmp di,command_line ; Space must not be first 1537 000006E0 74E9 je get_char 1538 000006E2 F606246501 enter_char: test byte [FuncFlag],1 1539 000006E7 740F jz .not_ctrl_f 1540 000006E9 C606246500 mov byte [FuncFlag],0 1541 000006EE 3C30 cmp al,'0' 1542 000006F0 7206 jb .not_ctrl_f 1543 000006F2 7437 je ctrl_f_0 1544 000006F4 3C39 cmp al,'9' 1545 000006F6 7635 jbe ctrl_f 1546 000006F8 81FF[E319] .not_ctrl_f: cmp di,max_cmd_len+command_line ; Check there's space 1547 000006FC 73CD jnb get_char 1548 000006FE AA stosb ; Save it 1549 000006FF E8490A call writechr ; Echo to screen 1550 00000702 EBC7 get_char_2: jmp short get_char 1551 00000704 C606246500 not_ascii: mov byte [FuncFlag],0 1552 00000709 3C0D cmp al,0Dh ; Enter 1553 0000070B 747D je command_done 1554 0000070D 3C06 cmp al,06h ; 1555 0000070F 7413 je set_func_flag 1556 00000711 3C08 cmp al,08h ; Backspace 1557 00000713 75B6 jne get_char 1558 00000715 81FF[E418] backspace: cmp di,command_line ; Make sure there is anything 1559 00000719 74B0 je get_char ; to erase 1560 0000071B 4F dec di ; Unstore one character 1561 0000071C BE[9A14] mov si,wipe_char ; and erase it from the screen 1562 0000071F E8360A call cwritestr 1563 00000722 EBDE jmp short get_char_2 1564 1565 set_func_flag: 1566 00000724 C606246501 mov byte [FuncFlag],1 1567 00000729 EBD7 jmp short get_char_2 1568 1569 0000072B 040A ctrl_f_0: add al,10 ; 0 == F10 1570 0000072D 57 ctrl_f: push di 1571 0000072E 2C31 sub al,'1' 1572 00000730 30E4 xor ah,ah 1573 00000732 EB0E jmp short show_help 1574 1575 func_key: 1576 00000734 57 push di 1577 00000735 80FC44 cmp ah,68 ; F10 1578 00000738 77C8 ja get_char_2 1579 0000073A 80EC3B sub ah,59 ; F1 1580 0000073D 72C3 jb get_char_2 1581 0000073F C1E808 shr ax,8 1582 show_help: ; AX = func key # (0 = F1, 9 = F10) 1583 00000742 88C1 mov cl,al 1584 00000744 C1E004 shl ax,4 ; Convert to x16 1585 00000747 BB0100 mov bx,1 1586 0000074A D3E3 shl bx,cl 1587 0000074C 231E[C018] and bx,[FKeyMap] 1588 00000750 74B0 jz get_char_2 ; Undefined F-key 1589 00000752 89C7 mov di,ax 1590 00000754 81C70064 add di,FKeyName 1591 00000758 E8C007 call searchdir 1592 0000075B 7405 jz fk_nofile 1593 0000075D E8B708 call get_msg_file 1594 00000760 EB06 jmp short fk_wrcmd 1595 fk_nofile: 1596 00000762 BE[6418] mov si,crlf_msg 1597 00000765 E8F009 call cwritestr 1598 fk_wrcmd: 1599 00000768 BE[9314] mov si,boot_prompt 1600 0000076B E8EA09 call cwritestr 1601 0000076E 5F pop di ; Command line write pointer 1602 0000076F 57 push di 1603 00000770 C60500 mov byte [di],0 ; Null-terminate command line 1604 00000773 BE[E418] mov si,command_line 1605 00000776 E8DF09 call cwritestr ; Write command line so far 1606 00000779 5F pop di 1607 0000077A EB86 jmp short get_char_2 1608 auto_boot: 1609 0000077C BE[E519] mov si,default_cmd 1610 0000077F BF[E418] mov di,command_line 1611 00000782 B94000 mov cx,(max_cmd_len+4) >> 2 1612 00000785 F366A5 rep movsd 1613 00000788 EB0F jmp short load_kernel 1614 command_done: 1615 0000078A BE[6418] mov si,crlf_msg 1616 0000078D E8C809 call cwritestr 1617 00000790 81FF[E418] cmp di,command_line ; Did we just hit return? 1618 00000794 74E6 je auto_boot 1619 00000796 30C0 xor al,al ; Store a final null 1620 00000798 AA stosb 1621 1622 load_kernel: ; Load the kernel now 1623 ; 1624 ; First we need to mangle the kernel name the way DOS would... 1625 ; 1626 00000799 BE[E418] mov si,command_line 1627 0000079C BFD064 mov di,KernelName 1628 0000079F 56 push si 1629 000007A0 57 push di 1630 000007A1 E8F80B call mangle_name 1631 000007A4 5F pop di 1632 000007A5 5E pop si 1633 ; 1634 ; Fast-forward to first option (we start over from the beginning, since 1635 ; mangle_name doesn't necessarily return a consistent ending state.) 1636 ; 1637 000007A6 AC clin_non_wsp: lodsb 1638 000007A7 3C20 cmp al,' ' 1639 000007A9 77FB ja clin_non_wsp 1640 000007AB 20C0 clin_is_wsp: and al,al 1641 000007AD 7405 jz clin_opt_ptr 1642 000007AF AC lodsb 1643 000007B0 3C20 cmp al,' ' 1644 000007B2 76F7 jbe clin_is_wsp 1645 000007B4 4E clin_opt_ptr: dec si ; Point to first nonblank 1646 000007B5 89360C65 mov [CmdOptPtr],si ; Save ptr to first option 1647 ; 1648 ; Now check if it is a "virtual kernel" 1649 ; 1650 000007B9 8B0E[C618] mov cx,[VKernelCtr] 1651 000007BD 1E push ds 1652 000007BE 680080 push word vk_seg 1653 000007C1 1F pop ds 1654 000007C2 83F900 cmp cx,byte 0 1655 000007C5 7413 je not_vk 1656 000007C7 31F6 xor si,si ; Point to first vkernel 1657 000007C9 60 vk_check: pusha 1658 000007CA B90B00 mov cx,11 1659 000007CD F3A6 repe cmpsb ; Is this it? 1660 000007CF 0F847700 je near vk_found 1661 000007D3 61 popa 1662 000007D4 81C60002 add si,vk_size 1663 000007D8 E2EF loop vk_check 1664 000007DA 1F not_vk: pop ds 1665 ; 1666 ; Not a "virtual kernel" - check that's OK and construct the command line 1667 ; 1668 000007DB 833E[CA18]00 cmp word [AllowImplicit],byte 0 1669 000007E0 745D je bad_implicit 1670 000007E2 06 push es 1671 000007E3 56 push si 1672 000007E4 57 push di 1673 000007E5 BF0090 mov di,real_mode_seg 1674 000007E8 8EC7 mov es,di 1675 000007EA BE0062 mov si,AppendBuf 1676 000007ED BF0080 mov di,cmd_line_here 1677 000007F0 8B0E[BC18] mov cx,[AppendLen] 1678 000007F4 F3A4 rep movsb 1679 000007F6 893E[C218] mov [CmdLinePtr],di 1680 000007FA 5F pop di 1681 000007FB 5E pop si 1682 000007FC 07 pop es 1683 000007FD BB1000 mov bx,exten_count << 2 ; Alternates to try 1684 ; 1685 ; Find the kernel on disk 1686 ; 1687 00000800 C606DB6400 get_kernel: mov byte [KernelName+11],0 ; Zero-terminate filename/extension 1688 00000805 66A1D864 mov eax,[KernelName+8] ; Save initial extension 1689 00000809 66A3[A818] mov [OrigKernelExt],eax 1690 0000080D 53 .search_loop: push bx 1691 0000080E BFD064 mov di,KernelName ; Search on disk 1692 00000811 E80707 call searchdir 1693 00000814 5B pop bx 1694 00000815 756C jnz kernel_good 1695 00000817 668B87[A818] mov eax,[exten_table+bx] ; Try a different extension 1696 0000081C 66A3D864 mov [KernelName+8],eax 1697 00000820 83EB04 sub bx,byte 4 1698 00000823 73E8 jnb .search_loop 1699 bad_kernel: 1700 00000825 BED064 mov si,KernelName 1701 00000828 BF3B65 mov di,KernelCName 1702 0000082B 57 push di 1703 0000082C E8C90B call unmangle_name ; Get human form 1704 0000082F BE[9E14] mov si,err_notfound ; Complain about missing kernel 1705 00000832 E82309 call cwritestr 1706 00000835 5E pop si ; KernelCName 1707 00000836 E81F09 call cwritestr 1708 00000839 BE[6418] mov si,crlf_msg 1709 0000083C E9C706 jmp abort_load ; Ask user for clue 1710 ; 1711 ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0" 1712 ; 1713 0000083F BED064 bad_implicit: mov si,KernelName ; For the error message 1714 00000842 BF3B65 mov di,KernelCName 1715 00000845 E8B00B call unmangle_name 1716 00000848 EBDB jmp short bad_kernel 1717 ; 1718 ; vk_found: We *are* using a "virtual kernel" 1719 ; 1720 0000084A 61 vk_found: popa 1721 0000084B 57 push di 1722 0000084C BF0060 mov di,VKernelBuf 1723 0000084F B98000 mov cx,vk_size >> 2 1724 00000852 F366A5 rep movsd 1725 00000855 06 push es ; Restore old DS 1726 00000856 1F pop ds 1727 00000857 06 push es 1728 00000858 680090 push word real_mode_seg 1729 0000085B 07 pop es 1730 0000085C BF0080 mov di,cmd_line_here 1731 0000085F BE1860 mov si,VKernelBuf+vk_append 1732 00000862 8B0E1660 mov cx,[VKernelBuf+vk_appendlen] 1733 00000866 F3A4 rep movsb 1734 00000868 893E[C218] mov [CmdLinePtr],di ; Where to add rest of cmd 1735 0000086C 07 pop es 1736 0000086D 5F pop di ; DI -> KernelName 1737 0000086E 57 push di 1738 0000086F BE0B60 mov si,VKernelBuf+vk_rname 1739 00000872 B90B00 mov cx,11 ; We need ECX == CX later 1740 00000875 F3A4 rep movsb 1741 00000877 5F pop di 1742 00000878 31DB xor bx,bx ; Try only one version 1743 0000087A E983FF jmp get_kernel 1744 ; 1745 ; kernel_corrupt: Called if the kernel file does not seem healthy 1746 ; 1747 0000087D BE[BC14] kernel_corrupt: mov si,err_notkernel 1748 00000880 E98306 jmp abort_load 1749 ; 1750 ; This is it! We have a name (and location on the disk)... let's load 1751 ; that sucker!! First we have to decide what kind of file this is; base 1752 ; that decision on the file extension. The following extensions are 1753 ; recognized: 1754 ; 1755 ; .COM - COMBOOT image 1756 ; .CBT - COMBOOT image 1757 ; .BS - Boot sector 1758 ; .BSS - Boot sector, but transfer over DOS superblock 1759 ; 1760 ; Anything else is assumed to be a Linux kernel. 1761 ; 1762 kernel_good: 1763 00000883 60 pusha 1764 00000884 BED064 mov si,KernelName 1765 00000887 BF3B65 mov di,KernelCName 1766 0000088A E86B0B call unmangle_name ; Get human form 1767 0000088D 81EF3B65 sub di,KernelCName 1768 00000891 893E0E65 mov [KernelCNameLen],di 1769 00000895 61 popa 1770 1771 00000896 668B0ED864 mov ecx,[KernelName+8] ; Get (mangled) extension 1772 0000089B 6681F9434F4D00 cmp ecx,'COM' 1773 000008A2 0F84A903 je near is_comboot_image 1774 000008A6 6681F943425400 cmp ecx,'CBT' 1775 000008AD 0F849E03 je near is_comboot_image 1776 000008B1 6681F942532000 cmp ecx,'BS ' 1777 000008B8 0F844504 je near is_bootsector 1778 000008BC 6681F942535300 cmp ecx,'BSS' 1779 000008C3 0F843F04 je near is_bss_sector 1780 ; Otherwise Linux kernel 1781 ; 1782 ; A Linux kernel consists of three parts: boot sector, setup code, and 1783 ; kernel code. The boot sector is never executed when using an external 1784 ; booting utility, but it contains some status bytes that are necessary. 1785 ; The boot sector and setup code together form exactly 5 sectors that 1786 ; should be loaded at 9000:0. The subsequent code should be loaded 1787 ; at 1000:0. For simplicity, we load the whole thing at 0F60:0, and 1788 ; copy the latter stuff afterwards. 1789 ; 1790 ; NOTE: In the previous code I have avoided making any assumptions regarding 1791 ; the size of a sector, in case this concept ever gets extended to other 1792 ; media like CD-ROM (not that a CD-ROM would be bloody likely to use a FAT 1793 ; filesystem, of course). However, a "sector" when it comes to Linux booting 1794 ; stuff means 512 bytes *no matter what*, so here I am using that piece 1795 ; of knowledge. 1796 ; 1797 ; First check that our kernel is at least 64K and less than 8M (if it is 1798 ; more than 8M, we need to change the logic for loading it anyway...) 1799 ; 1800 is_linux_kernel: 1801 000008C7 81FA8000 cmp dx,80h ; 8 megs 1802 000008CB 77B0 ja kernel_corrupt 1803 000008CD 21D2 and dx,dx 1804 000008CF 74AC jz kernel_corrupt 1805 000008D1 50 kernel_sane: push ax 1806 000008D2 52 push dx 1807 000008D3 56 push si 1808 000008D4 BE[4F18] mov si,loading_msg 1809 000008D7 E87E08 call cwritestr 1810 ; 1811 ; Now start transferring the kernel 1812 ; 1813 000008DA 680090 push word real_mode_seg 1814 000008DD 07 pop es 1815 1816 000008DE 50 push ax 1817 000008DF 52 push dx 1818 000008E0 F736F264 div word [ClustSize] ; # of clusters total 1819 000008E4 21D2 and dx,dx ; Round up 1820 000008E6 0F95C2 setnz dl 1821 000008E9 0FB6D2 movzx dx,dl 1822 000008EC 01D0 add ax,dx 1823 000008EE A30065 mov [KernelClust],ax 1824 000008F1 5A pop dx 1825 000008F2 58 pop ax 1826 000008F3 A3CC64 mov [KernelSize],ax 1827 000008F6 8916CE64 mov [KernelSize+2],dx 1828 ; 1829 ; Now, if we transfer these straight, we'll hit 64K boundaries. Hence we 1830 ; have to see if we're loading more than 64K, and if so, load it step by 1831 ; step. 1832 ; 1833 000008FA BA0100 mov dx,1 ; 10000h 1834 000008FD 31C0 xor ax,ax 1835 000008FF F736F264 div word [ClustSize] 1836 00000903 A30465 mov [ClustPerMoby],ax ; Clusters/64K 1837 ; 1838 ; Start by loading the bootsector/setup code, to see if we need to 1839 ; do something funky. It should fit in the first 32K (loading 64K won't 1840 ; work since we might have funny stuff up near the end of memory). 1841 ; If we have larger than 32K clusters, yes, we're hosed. 1842 ; 1843 00000906 E8E905 call abort_check ; Check for abort key 1844 00000909 8B0E0465 mov cx,[ClustPerMoby] 1845 0000090D D1E9 shr cx,1 ; Half a moby 1846 0000090F 290E0065 sub [KernelClust],cx 1847 00000913 31DB xor bx,bx 1848 00000915 5E pop si ; Cluster pointer on stack 1849 00000916 E80DFA call getfssec 1850 00000919 0F8260FF jc near kernel_corrupt ; Failure in first 32K 1851 0000091D 26813EFE0155AA cmp word [es:bs_bootsign],0AA55h 1852 00000924 0F8555FF jne near kernel_corrupt ; Boot sec signature missing 1853 ; 1854 ; Get the BIOS' idea of what the size of high memory is 1855 ; 1856 00000928 56 push si ; Save our cluster pointer! 1857 1858 00000929 B801E8 mov ax,0e801h ; Query high memory (semi-recent) 1859 0000092C CD15 int 15h 1860 0000092E 7215 jc no_e801 1861 00000930 3D003C cmp ax,3c00h 1862 00000933 7710 ja no_e801 ; > 3C00h something's wrong with this call 1863 00000935 721A jb e801_hole ; If memory hole we can only use low part 1864 1865 00000937 89D8 mov ax,bx 1866 00000939 66C1E010 shl eax,16 ; 64K chunks 1867 0000093D 660500000001 add eax,(16 << 20) ; Add first 16M 1868 00000943 EB1C jmp short got_highmem 1869 1870 no_e801: 1871 00000945 B488 mov ah,88h ; Query high memory (oldest) 1872 00000947 CD15 int 15h 1873 00000949 3D0038 cmp ax,14*1024 ; Don't trust memory >15M 1874 0000094C 7603 jna e801_hole 1875 0000094E B80038 mov ax,14*1024 1876 e801_hole: 1877 00000951 6625FFFF0000 and eax,0ffffh 1878 00000957 66C1E00A shl eax,10 ; Convert from kilobytes 1879 0000095B 660500001000 add eax,(1 << 20) ; First megabyte 1880 got_highmem: 1881 00000961 66A3C864 mov [HighMemSize],eax 1882 ; 1883 ; Construct the command line (append options have already been copied) 1884 ; 1885 00000965 26C70620003FA3 mov word [es:kern_cmd_magic],0A33Fh ; Command line magic no 1886 0000096C 26C70622000080 mov word [es:kern_cmd_offset],cmd_line_here 1887 00000973 8B3E[C218] mov di,[CmdLinePtr] 1888 00000977 BE[D918] mov si,boot_image ; BOOT_IMAGE= 1889 0000097A B90B00 mov cx,boot_image_len 1890 0000097D F3A4 rep movsb 1891 0000097F BE3B65 mov si,KernelCName ; Unmangled kernel name 1892 00000982 8B0E0E65 mov cx,[KernelCNameLen] 1893 00000986 F3A4 rep movsb 1894 00000988 B020 mov al,' ' ; Space 1895 0000098A AA stosb 1896 0000098B 8B360C65 mov si,[CmdOptPtr] ; Options from user input 1897 0000098F B98100 mov cx,(kern_cmd_len+3) >> 2 1898 00000992 F366A5 rep movsd 1899 ; 1900 %ifdef debug 1901 push ds ; DEBUG DEBUG DEBUG 1902 push es 1903 pop ds 1904 mov si,offset cmd_line_here 1905 call cwritestr 1906 pop ds 1907 mov si,offset crlf_msg 1908 call cwritestr 1909 %endif 1910 ; 1911 ; Scan through the command line for anything that looks like we might be 1912 ; interested in. The original version of this code automatically assumed 1913 ; the first option was BOOT_IMAGE=, but that is no longer certain. 1914 ; 1915 00000995 BE0080 mov si,cmd_line_here 1916 00000998 C606[C418]00 mov byte [initrd_flag],0 1917 0000099D 06 push es ; Set DS <- real_mode_seg 1918 0000099E 1F pop ds 1919 0000099F AC get_next_opt: lodsb 1920 000009A0 20C0 and al,al 1921 000009A2 0F848A00 jz near cmdline_end 1922 000009A6 3C20 cmp al,' ' 1923 000009A8 76F5 jbe get_next_opt 1924 000009AA 4E dec si 1925 000009AB 668B04 mov eax,[si] 1926 000009AE 663D7667613D cmp eax,'vga=' 1927 000009B4 7432 je is_vga_cmd 1928 000009B6 663D6D656D3D cmp eax,'mem=' 1929 000009BC 7462 je is_mem_cmd 1930 000009BE 06 push es ; Save ES -> real_mode_seg 1931 000009BF 16 push ss 1932 000009C0 07 pop es ; Set ES <- normal DS 1933 000009C1 BF[7518] mov di,initrd_cmd 1934 000009C4 B90700 mov cx,initrd_cmd_len 1935 000009C7 F3A6 repe cmpsb 1936 000009C9 7514 jne not_initrd 1937 000009CB BF3065 mov di,InitRD 1938 000009CE 56 push si ; mangle_dir mangles si 1939 000009CF E8CA09 call mangle_name ; Mangle ramdisk name 1940 000009D2 5E pop si 1941 000009D3 26803E306520 cmp byte [es:InitRD],' ' ; Null filename? 1942 000009D9 260F9706[C418] seta byte [es:initrd_flag] ; Set flag if not 1943 000009DF 07 not_initrd: pop es ; Restore ES -> real_mode_seg 1944 000009E0 AC skip_this_opt: lodsb ; Load from command line 1945 000009E1 3C20 cmp al,' ' 1946 000009E3 77FB ja skip_this_opt 1947 000009E5 4E dec si 1948 000009E6 EBB7 jmp short get_next_opt 1949 is_vga_cmd: 1950 000009E8 83C604 add si,byte 4 1951 000009EB 668B04 mov eax,[si] 1952 000009EE BBFFFF mov bx,-1 1953 000009F1 663D6E6F726D cmp eax, 'norm' ; vga=normal 1954 000009F7 7421 je vc0 1955 000009F9 6625FFFFFF00 and eax,0ffffffh ; 3 bytes 1956 000009FF BBFEFF mov bx,-2 1957 00000A02 663D65787400 cmp eax, 'ext' ; vga=ext 1958 00000A08 7410 je vc0 1959 00000A0A BBFDFF mov bx,-3 1960 00000A0D 663D61736B00 cmp eax, 'ask' ; vga=ask 1961 00000A13 7405 je vc0 1962 00000A15 E8B008 call parseint ; vga= 1963 00000A18 72C6 jc skip_this_opt ; Not an integer 1964 00000A1A 891EFA01 vc0: mov [bs_vidmode],bx ; Set video mode 1965 00000A1E EBC0 jmp short skip_this_opt 1966 is_mem_cmd: 1967 00000A20 83C604 add si,byte 4 1968 00000A23 E8A208 call parseint 1969 00000A26 72B8 jc skip_this_opt ; Not an integer 1970 00000A28 3666891EC864 mov [ss:HighMemSize],ebx 1971 00000A2E EBB0 jmp short skip_this_opt 1972 cmdline_end: 1973 00000A30 16 push ss ; Restore standard DS 1974 00000A31 1F pop ds 1975 ; 1976 ; Now check if we have a large kernel, which needs to be loaded high 1977 ; 1978 00000A32 2666813E0202486472- cmp dword [es:su_header],HEADER_ID ; New setup code ID 1979 00000A3B 53 1980 00000A3C 0F85F401 jne near old_kernel ; Old kernel, load low 1981 00000A40 26813E06020002 cmp word [es:su_version],0200h ; Setup code version 2.0 1982 00000A47 0F82E901 jb near old_kernel ; Old kernel, load low 1983 00000A4B 26813E06020102 cmp word [es:su_version],0201h ; Version 2.01+? 1984 00000A52 720D jb new_kernel ; If 2.00, skip this step 1985 00000A54 26C7062402F47F mov word [es:su_heapend],linux_stack ; Set up the heap 1986 00000A5B 26800E110280 or byte [es:su_loadflags],80h ; Let the kernel know we care 1987 ; 1988 ; We definitely have a new-style kernel. Let the kernel know who we are, 1989 ; and that we are clueful 1990 ; 1991 new_kernel: 1992 00000A61 26C606100231 mov byte [es:su_loader],syslinux_id ; Show some ID 1993 00000A67 260FB606F101 movzx ax,byte [es:bs_setupsecs] ; Variable # of setup sectors 1994 00000A6D A31465 mov [SetupSecs],ax 1995 ; 1996 ; Now see if we have an initial RAMdisk; if so, do requisite computation 1997 ; 1998 00000A70 F606[C418]01 test byte [initrd_flag],1 1999 00000A75 7478 jz nk_noinitrd 2000 00000A77 06 push es ; ES->real_mode_seg 2001 00000A78 1E push ds 2002 00000A79 07 pop es ; We need ES==DS 2003 00000A7A BE3065 mov si,InitRD 2004 00000A7D BF4865 mov di,InitRDCName 2005 00000A80 E87509 call unmangle_name ; Create human-readable name 2006 00000A83 81EF4865 sub di,InitRDCName 2007 00000A87 893E1065 mov [InitRDCNameLen],di 2008 00000A8B BF3065 mov di,InitRD 2009 00000A8E E88A04 call searchdir ; Look for it in directory 2010 00000A91 07 pop es 2011 00000A92 7443 jz initrd_notthere 2012 00000A94 8936[C418] mov [initrd_ptr],si ; Save cluster pointer 2013 00000A98 26A31C02 mov [es:su_ramdisklen1],ax ; Ram disk length 2014 00000A9C 2689161E02 mov [es:su_ramdisklen2],dx 2015 00000AA1 F736F264 div word [ClustSize] 2016 00000AA5 21D2 and dx,dx ; Round up 2017 00000AA7 0F95C2 setnz dl 2018 00000AAA 0FB6D2 movzx dx,dl 2019 00000AAD 01D0 add ax,dx 2020 00000AAF A30265 mov [InitRDClust],ax ; Ramdisk clusters 2021 00000AB2 668B16C864 mov edx,[HighMemSize] ; End of memory 2022 00000AB7 66B800000038 mov eax,HIGHMEM_MAX ; Limit imposed by kernel 2023 00000ABD 6639C2 cmp edx,eax 2024 00000AC0 7603 jna memsize_ok 2025 00000AC2 6689C2 mov edx,eax ; Adjust to fit inside limit 2026 memsize_ok: 2027 00000AC5 26662B161C02 sub edx,[es:su_ramdisklen] ; Subtract size of ramdisk 2028 00000ACB 31D2 xor dx,dx ; Round down to 64K boundary 2029 00000ACD 668916C064 mov [InitRDat],edx ; Load address 2030 00000AD2 E89E03 call loadinitrd ; Load initial ramdisk 2031 00000AD5 EB18 jmp short initrd_end 2032 2033 initrd_notthere: 2034 00000AD7 BE[F116] mov si,err_noinitrd 2035 00000ADA E87B06 call cwritestr 2036 00000ADD BE4865 mov si,InitRDCName 2037 00000AE0 E87506 call cwritestr 2038 00000AE3 BE[6418] mov si,crlf_msg 2039 00000AE6 E91D04 jmp abort_load 2040 2041 00000AE9 BE[1217] no_high_mem: mov si,err_nohighmem ; Error routine 2042 00000AEC E91704 jmp abort_load 2043 ; 2044 ; About to load the kernel. This is a modern kernel, so use the boot flags 2045 ; we were provided. 2046 ; 2047 nk_noinitrd: 2048 initrd_end: 2049 00000AEF 26A01102 mov al,[es:su_loadflags] 2050 00000AF3 A22265 mov [LoadFlags],al 2051 ; 2052 ; Load the kernel. We always load it at 100000h even if we're supposed to 2053 ; load it "low"; for a "low" load we copy it down to low memory right before 2054 ; jumping to it. 2055 ; 2056 read_kernel: 2057 00000AF6 BE3B65 mov si,KernelCName ; Print kernel name part of 2058 00000AF9 E85C06 call cwritestr ; "Loading" message 2059 00000AFC BE[5818] mov si,dotdot_msg ; Print dots 2060 00000AFF E85606 call cwritestr 2061 2062 00000B02 66A1C864 mov eax,[HighMemSize] 2063 00000B06 662D00001000 sub eax,100000h ; Load address 2064 00000B0C 663B06CC64 cmp eax,[KernelSize] 2065 00000B11 72D6 jb no_high_mem ; Not enough high memory 2066 ; 2067 ; Move the stuff beyond the setup code to high memory at 100000h 2068 ; 2069 00000B13 660FB7361465 movzx esi,word [SetupSecs] ; Setup sectors 2070 00000B19 6646 inc esi ; plus 1 boot sector 2071 00000B1B 66C1E609 shl esi,9 ; Convert to bytes 2072 00000B1F 66B900801000 mov ecx,108000h ; 108000h = 1M + 32K 2073 00000B25 6629F1 sub ecx,esi ; Adjust pointer to 2nd block 2074 00000B28 66890EC464 mov [HiLoadAddr],ecx 2075 00000B2D 6681E900001000 sub ecx,100000h ; Turn into a counter 2076 00000B34 66C1E902 shr ecx,2 ; Convert to dwords 2077 00000B38 6681C600000900 add esi,90000h ; Pointer to source 2078 00000B3F 66BF00001000 mov edi,100000h ; Copy to address 100000h 2079 00000B45 E83C02 call bcopy ; Transfer to high memory 2080 ; 2081 00000B48 680070 push word xfer_buf_seg ; Segment 7000h is xfer buffer 2082 00000B4B 07 pop es 2083 high_load_loop: 2084 00000B4C BE[5918] mov si,dot_msg ; Progress report 2085 00000B4F E80606 call cwritestr 2086 00000B52 E89D03 call abort_check 2087 00000B55 8B0E0065 mov cx,[KernelClust] 2088 00000B59 3B0E0465 cmp cx,[ClustPerMoby] 2089 00000B5D 7604 jna high_last_moby 2090 00000B5F 8B0E0465 mov cx,[ClustPerMoby] 2091 high_last_moby: 2092 00000B63 290E0065 sub [KernelClust],cx 2093 00000B67 31DB xor bx,bx ; Load at offset 0 2094 00000B69 5E pop si ; Restore cluster pointer 2095 00000B6A E8B9F7 call getfssec 2096 00000B6D 56 push si ; Save cluster pointer 2097 00000B6E 9C pushf ; Save EOF 2098 00000B6F 31DB xor bx,bx 2099 00000B71 66BE00000700 mov esi,(xfer_buf_seg << 4) 2100 00000B77 668B3EC464 mov edi,[HiLoadAddr] ; Destination address 2101 00000B7C 66B900400000 mov ecx,4000h ; Cheating - transfer 64K 2102 00000B82 E8FF01 call bcopy ; Transfer to high memory 2103 00000B85 66893EC464 mov [HiLoadAddr],edi ; Point to next target area 2104 00000B8A 9D popf ; Restore EOF 2105 00000B8B 7207 jc high_load_done ; If EOF we are done 2106 00000B8D 833E006500 cmp word [KernelClust],byte 0 ; Are we done? 2107 00000B92 75B8 jne high_load_loop ; Apparently not 2108 high_load_done: 2109 00000B94 5E pop si ; No longer needed 2110 00000B95 B80090 mov ax,real_mode_seg ; Set to real mode seg 2111 00000B98 8EC0 mov es,ax 2112 2113 00000B9A BE[5918] mov si,dot_msg 2114 00000B9D E8B805 call cwritestr 2115 ; 2116 ; Abandon hope, ye that enter here! We do no longer permit aborts. 2117 ; 2118 00000BA0 E84F03 call abort_check ; Last chance!! 2119 2120 ; 2121 ; Some kernels in the 1.2 ballpark but pre-bzImage have more than 4 2122 ; setup sectors, but the boot protocol had not yet been defined. They 2123 ; rely on a signature to figure out if they need to copy stuff from 2124 ; the "protected mode" kernel area. Unfortunately, we used that area 2125 ; as a transfer buffer, so it's going to find the signature there. 2126 ; Hence, zero the low 32K beyond the setup area. 2127 ; 2128 00000BA3 8B3E1465 mov di,[SetupSecs] 2129 00000BA7 47 inc di ; Setup + boot sector 2130 00000BA8 B94000 mov cx,32768/512 ; Sectors/32K 2131 00000BAB 29F9 sub cx,di ; Remaining sectors 2132 00000BAD C1E709 shl di,9 ; Sectors -> bytes 2133 00000BB0 C1E107 shl cx,7 ; Sectors -> dwords 2134 00000BB3 6631C0 xor eax,eax 2135 00000BB6 F366AB rep stosd ; Clear region 2136 ; 2137 ; Now, if we were supposed to load "low", copy the kernel down to 10000h 2138 ; 2139 00000BB9 F606226501 test byte [LoadFlags],LOAD_HIGH 2140 00000BBE 751F jnz in_proper_place ; If high load, we're done 2141 2142 00000BC0 668B0ECC64 mov ecx,[KernelSize] 2143 00000BC5 6681C103000000 add ecx,3 ; Round upwards 2144 00000BCC 66C1E902 shr ecx,2 ; Bytes -> dwords 2145 00000BD0 66BE00001000 mov esi,100000h 2146 00000BD6 66BF00000100 mov edi,10000h 2147 00000BDC E8A501 call bcopy 2148 in_proper_place: 2149 ; 2150 ; If the default root device is set to FLOPPY (0000h), change to 2151 ; /dev/fd0 (0200h) 2152 ; 2153 00000BDF 26833EFC0100 cmp word [es:bs_rootdev],byte 0 2154 00000BE5 7507 jne root_not_floppy 2155 00000BE7 26C706FC010002 mov word [es:bs_rootdev],0200h 2156 root_not_floppy: 2157 ; 2158 ; Copy the disk table to high memory, then re-initialize the floppy 2159 ; controller 2160 ; 2161 00000BEE 1E push ds 2162 00000BEF C5367800 lds si,[fdctab] 2163 00000BF3 BFF47F mov di,linux_fdctab 2164 00000BF6 B90300 mov cx,3 ; 12 bytes 2165 00000BF9 57 push di 2166 00000BFA F366A5 rep movsd 2167 00000BFD 5F pop di 2168 00000BFE FA cli 2169 00000BFF 893E7800 mov [fdctab1],di ; Save new floppy tab pos 2170 00000C03 8C067A00 mov [fdctab2],es 2171 00000C07 FB sti 2172 00000C08 31C0 xor ax,ax 2173 00000C0A 31D2 xor dx,dx 2174 00000C0C CD13 int 13h 2175 00000C0E 1F pop ds 2176 ; 2177 ; Linux wants the floppy motor shut off before starting the kernel, 2178 ; at least bootsect.S seems to imply so 2179 ; 2180 kill_motor: 2181 00000C0F BAF203 mov dx,03F2h 2182 00000C12 30C0 xor al,al 2183 00000C14 E8C201 call slow_out 2184 ; 2185 ; Now we're as close to be done as we can be and still use our normal 2186 ; routines, print a CRLF to end the row of dots 2187 ; 2188 00000C17 BE[6418] mov si,crlf_msg 2189 00000C1A E83B05 call cwritestr 2190 ; 2191 ; If we're debugging, wait for a keypress so we can read any debug messages 2192 ; 2193 %ifdef debug 2194 xor ax,ax 2195 int 16h 2196 %endif 2197 ; 2198 ; Set up segment registers and the Linux real-mode stack 2199 ; 2200 00000C1D B80090 mov ax,real_mode_seg 2201 00000C20 8ED8 mov ds,ax 2202 00000C22 8EC0 mov es,ax 2203 00000C24 8EE0 mov fs,ax 2204 00000C26 8EE8 mov gs,ax 2205 00000C28 FA cli 2206 00000C29 8ED0 mov ss,ax 2207 00000C2B BCF47F mov sp,linux_stack 2208 00000C2E FB sti 2209 ; 2210 ; We're done... now RUN THAT KERNEL!!!! 2211 ; 2212 00000C2F EA00002090 jmp setup_seg:setup_entry 2213 ; 2214 ; Load an older kernel. Older kernels always have 4 setup sectors, can't have 2215 ; initrd, and are always loaded low. 2216 ; 2217 old_kernel: 2218 00000C34 F606[C418]01 test byte [initrd_flag],1 ; Old kernel can't have initrd 2219 00000C39 7406 jz load_old_kernel 2220 00000C3B BE[5D17] mov si,err_oldkernel 2221 00000C3E E9C502 jmp abort_load 2222 load_old_kernel: 2223 00000C41 C70614650400 mov word [SetupSecs],4 ; Always 4 setup sectors 2224 00000C47 C606226500 mov byte [LoadFlags],0 ; Always low 2225 00000C4C E9A7FE jmp read_kernel 2226 2227 ; 2228 ; Load a COMBOOT image. A COMBOOT image is basically a DOS .COM file, 2229 ; except that it may, of course, not contain any DOS system calls. We 2230 ; do, however, allow the execution of INT 20h to return to SYSLINUX. 2231 ; 2232 is_comboot_image: 2233 00000C4F 21D2 and dx,dx 2234 00000C51 7575 jnz comboot_too_large 2235 00000C53 3D00FF cmp ax,0ff00h ; Max size in bytes 2236 00000C56 7370 jae comboot_too_large 2237 2238 ; 2239 ; Set up the DOS vectors in the IVT (INT 20h-3fh) 2240 ; 2241 00000C58 66C7068000- mov dword [4*0x20],comboot_return ; INT 20h vector 2242 00000C5D [D10C0000] 2243 00000C61 66B8[E30C0000] mov eax,comboot_bogus 2244 00000C67 BF8400 mov di,4*0x21 2245 00000C6A B91F00 mov cx,31 ; All remaining DOS vectors 2246 00000C6D F366AB rep stosd 2247 2248 00000C70 B90020 mov cx,comboot_seg 2249 00000C73 8EC1 mov es,cx 2250 2251 00000C75 BB0001 mov bx,100h ; Load at :0100h 2252 2253 00000C78 8B0E0465 mov cx,[ClustPerMoby] ; Absolute maximum # of clusters 2254 00000C7C E8A7F6 call getfssec 2255 2256 00000C7F 31FF xor di,di 2257 00000C81 B94000 mov cx,64 ; 256 bytes (size of PSP) 2258 00000C84 6631C0 xor eax,eax ; Clear PSP 2259 00000C87 F366AB rep stosd 2260 2261 00000C8A 26C7060000CD20 mov word [es:0], 020CDh ; INT 20h instruction 2262 ; First non-free paragraph 2263 00000C91 26C70602000030 mov word [es:02h], comboot_seg+1000h 2264 2265 ; Copy the command line from high memory 2266 00000C98 B97D00 mov cx,125 ; Max cmdline len (minus space and CR) 2267 00000C9B 8B360C65 mov si,[CmdOptPtr] 2268 00000C9F BF8100 mov di,081h ; Offset in PSP for command line 2269 00000CA2 B020 mov al,' ' ; DOS command lines begin with a space 2270 00000CA4 AA stosb 2271 2272 00000CA5 AC comboot_cmd_cp: lodsb 2273 00000CA6 20C0 and al,al 2274 00000CA8 7403 jz comboot_end_cmd 2275 00000CAA AA stosb 2276 00000CAB E2F8 loop comboot_cmd_cp 2277 00000CAD B00D comboot_end_cmd: mov al,0Dh ; CR after last character 2278 00000CAF AA stosb 2279 00000CB0 B07E mov al,126 ; Include space but not CR 2280 00000CB2 28C8 sub al,cl 2281 00000CB4 26A28000 mov [es:80h], al ; Store command line length 2282 2283 00000CB8 8CC0 mov ax,es 2284 00000CBA 8ED8 mov ds,ax 2285 00000CBC 8ED0 mov ss,ax 2286 00000CBE 31E4 xor sp,sp 2287 00000CC0 680000 push word 0 ; Return to address 0 -> exit 2288 2289 00000CC3 EA00010020 jmp comboot_seg:100h ; Run it 2290 2291 ; Looks like a COMBOOT image but too large 2292 comboot_too_large: 2293 00000CC8 BE[AD17] mov si,err_comlarge 2294 00000CCB E88A04 call cwritestr 2295 00000CCE E9BFF9 cb_enter: jmp enter_command 2296 2297 ; Proper return vector 2298 00000CD1 FA comboot_return: cli ; Don't trust anyone 2299 00000CD2 31C0 xor ax,ax 2300 00000CD4 8ED0 mov ss,ax 2301 00000CD6 368B261665 mov sp,[ss:SavedSP] 2302 00000CDB 8ED8 mov ds,ax 2303 00000CDD 8EC0 mov es,ax 2304 00000CDF FB sti 2305 00000CE0 FC cld 2306 00000CE1 EBEB jmp short cb_enter 2307 2308 ; Attempted to execute DOS system call 2309 00000CE3 FA comboot_bogus: cli ; Don't trust anyone 2310 00000CE4 31C0 xor ax,ax 2311 00000CE6 8ED0 mov ss,ax 2312 00000CE8 368B261665 mov sp,[ss:SavedSP] 2313 00000CED 8ED8 mov ds,ax 2314 00000CEF 8EC0 mov es,ax 2315 00000CF1 FB sti 2316 00000CF2 FC cld 2317 00000CF3 BE3B65 mov si,KernelCName 2318 00000CF6 E85F04 call cwritestr 2319 00000CF9 BE[8F17] mov si,err_notdos 2320 00000CFC E85904 call cwritestr 2321 00000CFF EBCD jmp short cb_enter 2322 2323 ; 2324 ; Load a boot sector 2325 ; 2326 is_bootsector: 2327 ; Transfer zero bytes 2328 00000D01 680000 push word 0 2329 00000D04 EB03 jmp short load_bootsec 2330 is_bss_sector: 2331 ; Transfer the superblock 2332 00000D06 683300 push word superblock_len 2333 load_bootsec: 2334 00000D09 21D2 and dx,dx 2335 00000D0B 754C jnz bad_bootsec 2336 00000D0D 8B1E[0B00] mov bx,[bsBytesPerSec] 2337 00000D11 39D8 cmp ax,bx 2338 00000D13 7544 jne bad_bootsec 2339 2340 ; Make sure we don't test this uninitialized 2341 00000D15 8997FE0F mov [bx+trackbuf-2],dx ; Note DX == 0 2342 2343 00000D19 BB0010 mov bx,trackbuf 2344 00000D1C B90100 mov cx,1 ; 1 cluster >= 1 sector 2345 00000D1F E804F6 call getfssec 2346 2347 00000D22 8B1E[0B00] mov bx,[bsBytesPerSec] 2348 00000D26 8B87FE0F mov ax,[bx+trackbuf-2] 2349 00000D2A 3D55AA cmp ax,0AA55h ; Boot sector signature 2350 00000D2D 752A jne bad_bootsec 2351 2352 00000D2F BE[0B00] mov si,superblock 2353 00000D32 BF0B10 mov di,trackbuf+(superblock-bootsec) 2354 00000D35 59 pop cx ; Transfer count 2355 00000D36 F3A4 rep movsb 2356 ; 2357 ; Okay, here we go... copy over our own boot sector and run the new one 2358 ; 2359 00000D38 FA cli ; Point of no return 2360 2361 00000D39 8A16[2400] mov dl,[bsDriveNumber] ; May not be in new bootsector! 2362 2363 00000D3D BE0010 mov si,trackbuf 2364 00000D40 BF[0000] mov di,bootsec 2365 00000D43 8B0E[0B00] mov cx,[bsBytesPerSec] 2366 00000D47 F3A4 rep movsb ; Copy the boot sector! 2367 2368 00000D49 BEB064 mov si,PartInfo 2369 00000D4C BFEE07 mov di,800h-18 ; Put partition info here 2370 00000D4F 57 push di 2371 00000D50 B90800 mov cx,8 ; 16 bytes 2372 00000D53 F3A5 rep movsw 2373 00000D55 5E pop si ; DS:SI points to partition info 2374 2375 00000D56 E9A7F2 jmp bootsec 2376 2377 bad_bootsec: 2378 00000D59 BE[C817] mov si,err_bootsec 2379 00000D5C E8F903 call cwritestr 2380 00000D5F E92EF9 jmp enter_command 2381 2382 ; 2383 ; 32-bit bcopy routine for real mode 2384 ; 2385 ; We enter protected mode, set up a flat 32-bit environment, run rep movsd 2386 ; and then exit. IMPORTANT: This code assumes cs == ss == 0. 2387 ; 2388 ; This code is probably excessively anal-retentive in its handling of 2389 ; segments, but this stuff is painful enough as it is without having to rely 2390 ; on everything happening "as it ought to." 2391 ; 2392 00000D62 90 align 4 2393 00000D64 1F00 bcopy_gdt: dw bcopy_gdt_size-1 ; Null descriptor - contains GDT 2394 00000D66 [640D0000] dd bcopy_gdt ; pointer for LGDT instruction 2395 00000D6A 0000 dw 0 2396 00000D6C FFFF0000 dd 0000ffffh ; Code segment, use16, readable, 2397 00000D70 009B0000 dd 00009b00h ; present, dpl 0, cover 64K 2398 00000D74 FFFF0000 dd 0000ffffh ; Data segment, use16, read/write, 2399 00000D78 00938F00 dd 008f9300h ; present, dpl 0, cover all 4G 2400 00000D7C FFFF0000 dd 0000ffffh ; Data segment, use16, read/write, 2401 00000D80 00930000 dd 00009300h ; present, dpl 0, cover 64K 2402 bcopy_gdt_size: equ $-bcopy_gdt 2403 2404 00000D84 6650 bcopy: push eax 2405 00000D86 9C pushf ; Saves, among others, the IF flag 2406 00000D87 0FA8 push gs 2407 00000D89 0FA0 push fs 2408 00000D8B 1E push ds 2409 00000D8C 06 push es 2410 2411 00000D8D FA cli 2412 00000D8E E85400 call enable_a20 2413 2414 00000D91 660F0116[640D] o32 lgdt [bcopy_gdt] 2415 00000D97 0F20C0 mov eax,cr0 2416 00000D9A 0C01 or al,1 2417 00000D9C 0F22C0 mov cr0,eax ; Enter protected mode 2418 00000D9F EA[A40D]0800 jmp 08h:.in_pm 2419 2420 00000DA4 B81000 .in_pm: mov ax,10h ; Data segment selector 2421 00000DA7 8EC0 mov es,ax 2422 00000DA9 8ED8 mov ds,ax 2423 2424 00000DAB B018 mov al,18h ; "Real-mode-like" data segment 2425 00000DAD 8ED0 mov ss,ax 2426 00000DAF 8EE0 mov fs,ax 2427 00000DB1 8EE8 mov gs,ax 2428 2429 00000DB3 67F366A5 a32 rep movsd ; Do our business 2430 2431 00000DB7 8EC0 mov es,ax ; Set to "real-mode-like" 2432 00000DB9 8ED8 mov ds,ax 2433 2434 00000DBB 0F20C0 mov eax,cr0 2435 00000DBE 24FE and al,~1 2436 00000DC0 0F22C0 mov cr0,eax ; Disable protected mode 2437 00000DC3 EA[C80D]0000 jmp 0:.in_rm 2438 2439 00000DC8 31C0 .in_rm: xor ax,ax ; Back in real mode 2440 00000DCA 8ED0 mov ss,ax 2441 00000DCC 07 pop es 2442 00000DCD 1F pop ds 2443 00000DCE 0FA1 pop fs 2444 00000DD0 0FA9 pop gs 2445 00000DD2 E85E00 call disable_a20 2446 2447 00000DD5 9D popf ; Re-enables interrupts 2448 00000DD6 6658 pop eax 2449 00000DD8 C3 ret 2450 2451 ; 2452 ; Routines to enable and disable (yuck) A20. These routines are gathered 2453 ; from tips from a couple of sources, including the Linux kernel and 2454 ; http://www.x86.org/. The need for the delay to be as large as given here 2455 ; is indicated by Donnie Barnes of RedHat, the problematic system being an 2456 ; IBM ThinkPad 760EL. 2457 ; 2458 ; We typically toggle A20 twice for every 64K transferred. 2459 ; 2460 %define io_delay call _io_delay 2461 %define IO_DELAY_PORT 80h ; Invalid port (we hope!) 2462 %define delaytime 1024 ; 4 x ISA bus cycles (@ 1.5 µs) 2463 2464 00000DD9 EE slow_out: out dx, al ; Fall through 2465 2466 00000DDA 50 _io_delay: push ax 2467 00000DDB E580 in ax,IO_DELAY_PORT 2468 00000DDD E580 in ax,IO_DELAY_PORT 2469 00000DDF E580 in ax,IO_DELAY_PORT 2470 00000DE1 E580 in ax,IO_DELAY_PORT 2471 00000DE3 58 pop ax 2472 00000DE4 C3 ret 2473 2474 enable_a20: 2475 00000DE5 36C6062365FF mov byte [ss:A20Tries],255 ; Times to try to make this work 2476 2477 try_enable_a20: 2478 ; 2479 ; Flush the caches 2480 ; 2481 00000DEB E88200 call try_wbinvd 2482 2483 ; 2484 ; Enable the "fast A20 gate" 2485 ; 2486 00000DEE E492 in al, 092h 2487 00000DF0 0C02 or al,02h 2488 00000DF2 E692 out 092h, al 2489 ; 2490 ; Enable the keyboard controller A20 gate 2491 ; 2492 00000DF4 E86100 call empty_8042 2493 00000DF7 B0D1 mov al,0D1h ; Command write 2494 00000DF9 E664 out 064h, al 2495 00000DFB E85A00 call empty_8042 2496 00000DFE B0DF mov al,0DFh ; A20 on 2497 00000E00 E660 out 060h, al 2498 00000E02 E84500 call kbc_delay 2499 ; Verify that A20 actually is enabled. Do that by 2500 ; observing a word in low memory and the same word in 2501 ; the HMA until they are no longer coherent. Note that 2502 ; we don't do the same check in the disable case, because 2503 ; we don't want to *require* A20 masking (SYSLINUX should 2504 ; work fine without it, if the BIOS does.) 2505 00000E05 06 push es 2506 00000E06 51 push cx 2507 00000E07 B9FFFF mov cx,0FFFFh ; Times to try, also HMA 2508 00000E0A 8EC1 mov es,cx ; HMA = segment 0FFFFh 2509 00000E0C 36FF061865 .a20_wait: inc word [ss:A20Test] 2510 00000E11 E85C00 call try_wbinvd 2511 00000E14 26A12865 mov ax,[es:A20Test+10h] 2512 00000E18 363B061865 cmp ax,[ss:A20Test] 2513 00000E1D 7511 jne .a20_done 2514 00000E1F E2EB loop .a20_wait 2515 ; 2516 ; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up 2517 ; and report failure to the user. 2518 ; 2519 00000E21 59 pop cx 2520 00000E22 07 pop es 2521 2522 00000E23 36FE0E2365 dec byte [ss:A20Tries] 2523 00000E28 75C1 jnz try_enable_a20 2524 2525 00000E2A BE[F017] mov si, err_a20 2526 00000E2D E9D600 jmp abort_load 2527 ; 2528 ; A20 unmasked, proceed... 2529 ; 2530 00000E30 59 .a20_done: pop cx 2531 00000E31 07 pop es 2532 00000E32 C3 ret 2533 2534 disable_a20: 2535 ; 2536 ; Flush the caches 2537 ; 2538 00000E33 E83A00 call try_wbinvd 2539 ; 2540 ; Disable the "fast A20 gate" 2541 ; 2542 00000E36 E492 in al, 092h 2543 00000E38 24FD and al,~02h 2544 00000E3A E692 out 092h, al 2545 ; 2546 ; Disable the keyboard controller A20 gate 2547 ; 2548 00000E3C E81900 call empty_8042 2549 00000E3F B0D1 mov al,0D1h 2550 00000E41 E664 out 064h, al ; Command write 2551 00000E43 E81200 call empty_8042 2552 00000E46 B0DD mov al,0DDh ; A20 off 2553 00000E48 E660 out 060h, al 2554 ; Fall through/tailcall to kbc_delay 2555 2556 00000E4A E80B00 kbc_delay: call empty_8042 2557 00000E4D 51 push cx 2558 00000E4E B90004 mov cx, delaytime 2559 00000E51 E886FF .delayloop: io_delay 2560 00000E54 E2FB loop .delayloop 2561 00000E56 59 pop cx 2562 00000E57 C3 ret 2563 2564 empty_8042: 2565 00000E58 E87FFF io_delay 2566 00000E5B E464 in al, 064h ; Status port 2567 00000E5D A801 test al,1 2568 00000E5F 7407 jz .no_output 2569 00000E61 E876FF io_delay 2570 00000E64 E460 in al, 060h ; Read input 2571 00000E66 EBF0 jmp short empty_8042 2572 .no_output: 2573 00000E68 A802 test al,2 2574 00000E6A 75EC jnz empty_8042 2575 00000E6C E86BFF io_delay 2576 00000E6F C3 ret 2577 2578 ; 2579 ; WBINVD instruction; gets auto-eliminated on 386 CPUs 2580 ; 2581 try_wbinvd: 2582 00000E70 0F09 wbinvd 2583 00000E72 C3 ret 2584 2585 ; 2586 ; Load RAM disk into high memory 2587 ; 2588 loadinitrd: 2589 00000E73 06 push es ; Save ES on entry 2590 00000E74 B80090 mov ax,real_mode_seg 2591 00000E77 8EC0 mov es,ax 2592 00000E79 8B36[C418] mov si,[initrd_ptr] 2593 00000E7D 668B3EC064 mov edi,[InitRDat] ; initrd load address 2594 00000E82 2666893E1802 mov [es:su_ramdiskat],edi ; Offset for ram disk 2595 00000E88 56 push si 2596 00000E89 BE4865 mov si,InitRDCName ; Write ramdisk name 2597 00000E8C E8C902 call cwritestr 2598 00000E8F BE[5818] mov si,dotdot_msg ; Write dots 2599 00000E92 E8C302 call cwritestr 2600 rd_load_loop: 2601 00000E95 BE[5918] mov si,dot_msg ; Progress report 2602 00000E98 E8BD02 call cwritestr 2603 00000E9B 5E pop si ; Restore cluster pointer 2604 00000E9C E85300 call abort_check 2605 00000E9F 8B0E0265 mov cx,[InitRDClust] 2606 00000EA3 3B0E0465 cmp cx,[ClustPerMoby] 2607 00000EA7 7604 jna rd_last_moby 2608 00000EA9 8B0E0465 mov cx,[ClustPerMoby] 2609 rd_last_moby: 2610 00000EAD 290E0265 sub [InitRDClust],cx 2611 00000EB1 31DB xor bx,bx ; Load at offset 0 2612 00000EB3 680070 push word xfer_buf_seg ; Bounce buffer segment 2613 00000EB6 07 pop es 2614 00000EB7 51 push cx 2615 00000EB8 E86BF4 call getfssec 2616 00000EBB 59 pop cx 2617 00000EBC 56 push si ; Save cluster pointer 2618 00000EBD 66BE00000700 mov esi,(xfer_buf_seg << 4) 2619 00000EC3 668B3EC064 mov edi,[InitRDat] 2620 00000EC8 66B900400000 mov ecx,4000h ; Copy 64K 2621 00000ECE E8B3FE call bcopy ; Does not change flags!! 2622 00000ED1 7210 jc rd_load_done ; EOF? 2623 00000ED3 668106C06400000100 add dword [InitRDat],10000h ; Point to next 64K 2624 00000EDC 833E026500 cmp word [InitRDClust],byte 0 ; Are we done? 2625 00000EE1 75B2 jne rd_load_loop ; Apparently not 2626 rd_load_done: 2627 00000EE3 5E pop si ; Clean up the stack 2628 00000EE4 BE[6418] mov si,crlf_msg 2629 00000EE7 E86E02 call cwritestr 2630 00000EEA BE[4F18] mov si,loading_msg ; Write new "Loading " for 2631 00000EED E86802 call cwritestr ; the benefit of the kernel 2632 00000EF0 07 pop es ; Restore original ES 2633 00000EF1 C3 ret 2634 2635 ; 2636 ; abort_check: let the user abort with or 2637 ; 2638 abort_check: 2639 00000EF2 E87002 call pollchar 2640 00000EF5 7423 jz ac_ret1 2641 00000EF7 60 pusha 2642 00000EF8 E88102 call getchar 2643 00000EFB 3C1B cmp al,27 ; 2644 00000EFD 7404 je ac_kill 2645 00000EFF 3C03 cmp al,3 ; 2646 00000F01 7516 jne ac_ret2 2647 00000F03 BE[5B18] ac_kill: mov si,aborted_msg 2648 2649 ; 2650 ; abort_load: Called by various routines which wants to print a fatal 2651 ; error message and return to the command prompt. Since this 2652 ; may happen at just about any stage of the boot process, assume 2653 ; our state is messed up, and just reset the segment registers 2654 ; and the stack forcibly. 2655 ; 2656 ; SI = offset (in _text) of error message to print 2657 ; 2658 abort_load: 2659 00000F06 8CC8 mov ax,cs ; Restore CS = DS = ES 2660 00000F08 8ED8 mov ds,ax 2661 00000F0A 8EC0 mov es,ax 2662 00000F0C FA cli 2663 00000F0D BCFA5F mov sp,StackBuf-2*3 ; Reset stack 2664 00000F10 8ED0 mov ss,ax ; Just in case... 2665 00000F12 FB sti 2666 00000F13 E84202 call cwritestr ; Expects SI -> error msg 2667 00000F16 E977F7 al_ok: jmp enter_command ; Return to command prompt 2668 ; 2669 ; End of abort_check 2670 ; 2671 00000F19 61 ac_ret2: popa 2672 00000F1A C3 ac_ret1: ret 2673 2674 ; 2675 ; searchdir: Search the root directory for a pre-mangled filename in 2676 ; DS:DI. This routine is similar to the one in the boot 2677 ; sector, but is a little less Draconian when it comes to 2678 ; error handling, plus it reads the root directory in 2679 ; larger chunks than a sector at a time (which is probably 2680 ; a waste of coding effort, but I like to do things right). 2681 ; 2682 ; FIXME: usually we can load the entire root dir in memory, 2683 ; and files are usually at the beginning anyway. It probably 2684 ; would be worthwhile to remember if we have the first chunk 2685 ; in memory and skip the load if that (it would speed up online 2686 ; help, mainly.) 2687 ; 2688 ; NOTE: This file considers finding a zero-length file an 2689 ; error. This is so we don't have to deal with that special 2690 ; case elsewhere in the program (most loops have the test 2691 ; at the end). 2692 ; 2693 ; If successful: 2694 ; ZF clear 2695 ; SI = cluster # for the first cluster 2696 ; DX:AX = file length in bytes 2697 ; If unsuccessful 2698 ; ZF set 2699 ; 2700 2701 searchdir: 2702 00000F1B A1[1100] mov ax,[bsRootDirEnts] 2703 00000F1E A3EA64 mov [DirScanCtr],ax 2704 00000F21 A1E864 mov ax,[RootDirSize] 2705 00000F24 A3EC64 mov [DirBlocksLeft],ax 2706 00000F27 A1DC64 mov ax,[RootDir1] 2707 00000F2A 8B16DE64 mov dx,[RootDir2] 2708 scan_group: 2709 00000F2E 8B2EEC64 mov bp,[DirBlocksLeft] 2710 00000F32 21ED and bp,bp 2711 00000F34 7467 jz dir_return 2712 00000F36 3B2EFA64 cmp bp,[BufSafeSec] 2713 00000F3A 7604 jna load_last 2714 00000F3C 8B2EFA64 mov bp,[BufSafeSec] 2715 load_last: 2716 00000F40 292EEC64 sub [DirBlocksLeft],bp 2717 00000F44 50 push ax 2718 00000F45 52 push dx 2719 00000F46 A1[0B00] mov ax,[bsBytesPerSec] 2720 00000F49 F7E5 mul bp 2721 00000F4B 05E10F add ax,trackbuf-31 2722 00000F4E A3EE64 mov [EndofDirSec],ax ; End of loaded 2723 00000F51 5A pop dx 2724 00000F52 58 pop ax 2725 00000F53 55 push bp ; Save number of sectors 2726 00000F54 50 push ax ; Save present location 2727 00000F55 52 push dx 2728 00000F56 57 push di ; Save name 2729 00000F57 BB0010 mov bx,trackbuf 2730 00000F5A E815F2 call getlinsec 2731 00000F5D 5F pop di 2732 00000F5E 5A pop dx 2733 00000F5F 58 pop ax 2734 00000F60 5D pop bp 2735 00000F61 BE0010 mov si,trackbuf 2736 00000F64 803C00 dir_test_name: cmp byte [si],0 ; Directory high water mark 2737 00000F67 7434 je dir_return ; Failed 2738 00000F69 F6440B18 test byte [si+11],18h ; Check it really is a file 2739 00000F6D 750B jnz dir_not_this 2740 00000F6F 57 push di 2741 00000F70 56 push si 2742 00000F71 B90B00 mov cx,11 ; Filename = 11 bytes 2743 00000F74 F3A6 repe cmpsb 2744 00000F76 5E pop si 2745 00000F77 5F pop di 2746 00000F78 7416 je dir_success 2747 00000F7A 83C620 dir_not_this: add si,byte 32 2748 00000F7D FF0EEA64 dec word [DirScanCtr] 2749 00000F81 741A jz dir_return ; Out of it... 2750 00000F83 3B36EE64 cmp si,[EndofDirSec] 2751 00000F87 72DB jb dir_test_name 2752 00000F89 01E8 add ax,bp ; Increment linear sector number 2753 00000F8B 83D200 adc dx,byte 0 2754 00000F8E EB9E jmp short scan_group 2755 dir_success: 2756 00000F90 8B441C mov ax,[si+28] ; Length of file 2757 00000F93 8B541E mov dx,[si+30] 2758 00000F96 8B741A mov si,[si+26] ; Cluster pointer 2759 00000F99 89C3 mov bx,ax 2760 00000F9B 09D3 or bx,dx ; Sets ZF iff DX:AX is zero 2761 dir_return: 2762 00000F9D C3 ret 2763 2764 ; 2765 ; adjust_screen: Set the internal variables associated with the screen size. 2766 ; This is a subroutine in case we're loading a custom font. 2767 ; 2768 adjust_screen: 2769 00000F9E A08404 mov al,[BIOS_vidrows] 2770 00000FA1 20C0 and al,al 2771 00000FA3 7502 jnz vidrows_is_ok 2772 00000FA5 B018 mov al,24 ; No vidrows in BIOS, assume 25 2773 ; (Remember: vidrows == rows-1) 2774 00000FA7 A21F65 vidrows_is_ok: mov [VidRows],al 2775 00000FAA B40F mov ah,0fh 2776 00000FAC CD10 int 10h ; Read video state 2777 00000FAE 883E1B65 mov [TextPage],bh 2778 00000FB2 FECC dec ah ; Store count-1 (same as rows) 2779 00000FB4 88261E65 mov [VidCols],ah 2780 00000FB8 C3 bf_ret: ret 2781 2782 ; 2783 ; loadfont: Load a .psf font file and install it onto the VGA console 2784 ; (if we're not on a VGA screen then ignore.) It is called with 2785 ; SI and DX:AX set by routine searchdir 2786 ; 2787 loadfont: 2788 00000FB9 BB0010 mov bx,trackbuf ; The trackbuf is >= 16K; the part 2789 00000FBC 8B0EF864 mov cx,[BufSafe] ; of a PSF file we care about is no 2790 00000FC0 E863F3 call getfssec ; more than 8K+4 bytes 2791 2792 00000FC3 A10010 mov ax,[trackbuf] ; Magic number 2793 00000FC6 3D3604 cmp ax,0436h 2794 00000FC9 75ED jne bf_ret 2795 2796 00000FCB A00210 mov al,[trackbuf+2] ; File mode 2797 00000FCE 3C03 cmp al,3 ; Font modes 0-3 supported 2798 00000FD0 77E6 ja bf_ret 2799 2800 00000FD2 8A3E0310 mov bh,byte [trackbuf+3] ; Height of font 2801 00000FD6 80FF02 cmp bh,2 ; VGA minimum 2802 00000FD9 72DD jb bf_ret 2803 00000FDB 80FF20 cmp bh,32 ; VGA maximum 2804 00000FDE 77D8 ja bf_ret 2805 2806 00000FE0 BD0410 mov bp,trackbuf+4 ; Address of font data 2807 00000FE3 30DB xor bl,bl 2808 00000FE5 B90001 mov cx,256 2809 00000FE8 31D2 xor dx,dx 2810 00000FEA B81011 mov ax,1110h 2811 00000FED CD10 int 10h ; Load into VGA RAM 2812 2813 00000FEF 30DB xor bl,bl 2814 00000FF1 B80311 mov ax,1103h ; Select page 0 2815 00000FF4 CD10 int 10h 2816 2817 00000FF6 EBA6 jmp short adjust_screen 2818 2819 ; 2820 ; loadkeys: Load a LILO-style keymap; SI and DX:AX set by searchdir 2821 ; 2822 loadkeys: 2823 00000FF8 21D2 and dx,dx ; Should be 256 bytes exactly 2824 00000FFA 751A jne loadkeys_ret 2825 00000FFC 3D0001 cmp ax,256 2826 00000FFF 7515 jne loadkeys_ret 2827 2828 00001001 BB0010 mov bx,trackbuf 2829 00001004 B90100 mov cx,1 ; 1 cluster should be >= 256 bytes 2830 00001007 E81CF3 call getfssec 2831 2832 0000100A BE0010 mov si,trackbuf 2833 0000100D BF0063 mov di,KbdMap 2834 00001010 B94000 mov cx,256 >> 2 2835 00001013 F366A5 rep movsd 2836 2837 00001016 C3 loadkeys_ret: ret 2838 2839 ; 2840 ; get_msg_file: Load a text file and write its contents to the screen, 2841 ; interpreting color codes. Is called with SI and DX:AX 2842 ; set by routine searchdir 2843 ; 2844 get_msg_file: 2845 00001017 C7061265[6B10] mov word [NextCharJump],msg_putchar ; State machine for color 2846 0000101D C6061A6507 mov byte [TextAttribute],07h ; Default grey on white 2847 00001022 60 pusha 2848 00001023 8A3E1B65 mov bh,[TextPage] 2849 00001027 B403 mov ah,03h ; Read cursor position 2850 00001029 CD10 int 10h 2851 0000102B 89161C65 mov [CursorDX],dx 2852 0000102F 61 popa 2853 00001030 50 get_msg_chunk: push ax ; DX:AX = length of file 2854 00001031 52 push dx 2855 00001032 BB0010 mov bx,trackbuf 2856 00001035 8B0EF864 mov cx,[BufSafe] 2857 00001039 E8EAF2 call getfssec 2858 0000103C 5A pop dx 2859 0000103D 58 pop ax 2860 0000103E 56 push si ; Save current cluster 2861 0000103F BE0010 mov si,trackbuf 2862 00001042 8B0EFC64 mov cx,[BufSafeBytes] ; No more than many bytes 2863 00001046 51 print_msg_file: push cx 2864 00001047 50 push ax 2865 00001048 52 push dx 2866 00001049 AC lodsb 2867 0000104A 3C1A cmp al,1Ah ; ASCII EOF? 2868 0000104C 7418 je msg_done_pop 2869 0000104E FF161265 call [NextCharJump] ; Do what shall be done 2870 00001052 5A pop dx 2871 00001053 58 pop ax 2872 00001054 59 pop cx 2873 00001055 83E801 sub ax,byte 1 2874 00001058 83DA00 sbb dx,byte 0 2875 0000105B 89C3 mov bx,ax 2876 0000105D 09D3 or bx,dx 2877 0000105F 7408 jz msg_done 2878 00001061 E2E3 loop print_msg_file 2879 00001063 5E pop si 2880 00001064 EBCA jmp short get_msg_chunk 2881 msg_done_pop: 2882 00001066 83C406 add sp,byte 6 ; Lose 3 words on the stack 2883 msg_done: 2884 00001069 5E pop si 2885 0000106A C3 ret 2886 msg_putchar: ; Normal character 2887 0000106B 3C0F cmp al,0Fh ; ^O = color code follows 2888 0000106D 7434 je msg_ctrl_o 2889 0000106F 3C0D cmp al,0Dh ; Ignore 2890 00001071 742F je msg_ignore 2891 00001073 3C0A cmp al,0Ah ; = newline 2892 00001075 7433 je msg_newline 2893 00001077 3C0C cmp al,0Ch ; = clear screen 2894 00001079 7460 je msg_formfeed 2895 2896 0000107B E8A800 msg_normal: call write_serial ; Write to serial port 2897 0000107E 8B1E1A65 mov bx,[TextAttrBX] 2898 00001082 B409 mov ah,09h ; Write character/attribute 2899 00001084 B90100 mov cx,1 ; One character only 2900 00001087 CD10 int 10h ; Write to screen 2901 00001089 A01C65 mov al,[CursorCol] 2902 0000108C 40 inc ax 2903 0000108D 3A061E65 cmp al,[VidCols] 2904 00001091 7717 ja msg_newline 2905 00001093 A21C65 mov [CursorCol],al 2906 2907 00001096 8A3E1B65 msg_gotoxy: mov bh,[TextPage] 2908 0000109A 8B161C65 mov dx,[CursorDX] 2909 0000109E B402 mov ah,02h ; Set cursor position 2910 000010A0 CD10 int 10h 2911 000010A2 C3 msg_ignore: ret 2912 msg_ctrl_o: ; ^O = color code follows 2913 000010A3 C7061265[F810] mov word [NextCharJump],msg_setbg 2914 000010A9 C3 ret 2915 msg_newline: ; Newline char or end of line 2916 000010AA 56 push si 2917 000010AB BE[6418] mov si,crlf_msg 2918 000010AE E88F00 call write_serial_str 2919 000010B1 5E pop si 2920 000010B2 C6061C6500 mov byte [CursorCol],0 2921 000010B7 A01D65 mov al,[CursorRow] 2922 000010BA 40 inc ax 2923 000010BB 3A061F65 cmp al,[VidRows] 2924 000010BF 7705 ja msg_scroll 2925 000010C1 A21D65 mov [CursorRow],al 2926 000010C4 EBD0 jmp short msg_gotoxy 2927 000010C6 31C9 msg_scroll: xor cx,cx ; Upper left hand corner 2928 000010C8 8B161E65 mov dx,[ScreenSize] 2929 000010CC 88361D65 mov [CursorRow],dh ; New cursor at the bottom 2930 000010D0 8A3E1A65 mov bh,[TextAttribute] 2931 000010D4 B80106 mov ax,0601h ; Scroll up one line 2932 000010D7 CD10 int 10h 2933 000010D9 EBBB jmp short msg_gotoxy 2934 msg_formfeed: ; Form feed character 2935 000010DB 56 push si 2936 000010DC BE[6718] mov si,crff_msg 2937 000010DF E85E00 call write_serial_str 2938 000010E2 5E pop si 2939 000010E3 31C9 xor cx,cx 2940 000010E5 890E1C65 mov [CursorDX],cx ; Upper lefthand corner 2941 000010E9 8B161E65 mov dx,[ScreenSize] 2942 000010ED 8A3E1A65 mov bh,[TextAttribute] 2943 000010F1 B80006 mov ax,0600h ; Clear screen region 2944 000010F4 CD10 int 10h 2945 000010F6 EB9E jmp short msg_gotoxy 2946 msg_setbg: ; Color background character 2947 000010F8 E84A02 call unhexchar 2948 000010FB 721D jc msg_color_bad 2949 000010FD C0E004 shl al,4 2950 00001100 A21A65 mov [TextAttribute],al 2951 00001103 C7061265[0A11] mov word [NextCharJump],msg_setfg 2952 00001109 C3 ret 2953 msg_setfg: ; Color foreground character 2954 0000110A E83802 call unhexchar 2955 0000110D 720B jc msg_color_bad 2956 0000110F 08061A65 or [TextAttribute],al ; setbg set foreground to 0 2957 00001113 C7061265[6B10] mov word [NextCharJump],msg_putchar 2958 00001119 C3 ret 2959 msg_color_bad: 2960 0000111A C6061A6507 mov byte [TextAttribute],07h ; Default attribute 2961 0000111F C7061265[6B10] mov word [NextCharJump],msg_putchar 2962 00001125 C3 ret 2963 2964 ; 2965 ; write_serial: If serial output is enabled, write character on serial port 2966 ; 2967 write_serial: 2968 00001126 60 pusha 2969 00001127 8B1E[CC18] mov bx,[SerialPort] 2970 0000112B 21DB and bx,bx 2971 0000112D 740F je .noserial 2972 0000112F 50 push ax 2973 00001130 8D5705 .waitspace: lea dx,[bx+5] ; Wait for space in transmit reg 2974 00001133 EC in al,dx 2975 00001134 A820 test al,20h 2976 00001136 74F8 jz .waitspace 2977 00001138 87D3 xchg dx,bx 2978 0000113A 58 pop ax 2979 0000113B E89BFC call slow_out ; Send data 2980 0000113E 61 .noserial: popa 2981 0000113F C3 ret 2982 2983 ; 2984 ; write_serial_str: write_serial for strings 2985 ; 2986 write_serial_str: 2987 00001140 AC .loop lodsb 2988 00001141 20C0 and al,al 2989 00001143 7405 jz .end 2990 00001145 E8DEFF call write_serial 2991 00001148 EBF6 jmp short .loop 2992 0000114A C3 .end: ret 2993 2994 ; 2995 ; writechr: Write a single character in AL to the console without 2996 ; mangling any registers 2997 ; 2998 writechr: 2999 0000114B E8D8FF call write_serial ; write to serial port if needed 3000 0000114E 60 pusha 3001 0000114F B40E mov ah,0Eh 3002 00001151 BB0700 mov bx,0007h ; white text on this page 3003 00001154 CD10 int 10h 3004 00001156 61 popa 3005 00001157 C3 ret 3006 3007 ; 3008 ; cwritestr: write a null-terminated string to the console, saving 3009 ; registers on entry. 3010 ; 3011 cwritestr: 3012 00001158 60 pusha 3013 00001159 AC .top: lodsb 3014 0000115A 20C0 and al,al 3015 0000115C 7405 jz .end 3016 0000115E E8EAFF call writechr 3017 00001161 EBF6 jmp short .top 3018 00001163 61 .end: popa 3019 00001164 C3 ret 3020 3021 ; 3022 ; pollchar: check if we have an input character pending (ZF = 0) 3023 ; 3024 pollchar: 3025 00001165 60 pusha 3026 00001166 B401 mov ah,1 ; Poll keyboard 3027 00001168 CD16 int 16h 3028 0000116A 750E jnz .done ; Keyboard response 3029 0000116C 8B16[CC18] mov dx,[SerialPort] 3030 00001170 21D2 and dx,dx 3031 00001172 7406 jz .done ; No serial port -> no input 3032 00001174 83C205 add dx,byte 5 ; Serial status register 3033 00001177 EC in al,dx 3034 00001178 A801 test al,1 ; ZF = 0 if traffic 3035 0000117A 61 .done: popa 3036 0000117B C3 ret 3037 3038 ; 3039 ; getchar: Read a character from keyboard or serial port 3040 ; 3041 getchar: 3042 0000117C B401 .again: mov ah,1 ; Poll keyboard 3043 0000117E CD16 int 16h 3044 00001180 7516 jnz .kbd ; Keyboard input? 3045 00001182 8B1E[CC18] mov bx,[SerialPort] 3046 00001186 21DB and bx,bx 3047 00001188 74F2 jz .again 3048 0000118A 8D5705 lea dx,[bx+5] ; Serial status register 3049 0000118D EC in al,dx 3050 0000118E A801 test al,1 3051 00001190 74EA jz .again 3052 00001192 30E4 .serial: xor ah,ah ; Avoid confusion 3053 00001194 87D3 xchg dx,bx ; Data port 3054 00001196 EC in al,dx 3055 00001197 C3 ret 3056 00001198 31C0 .kbd: xor ax,ax ; Get keyboard input 3057 0000119A CD16 int 16h 3058 0000119C 20C0 and al,al 3059 0000119E 7404 jz .func_key 3060 000011A0 BB0063 mov bx,KbdMap ; Convert character sets 3061 000011A3 D7 xlatb 3062 000011A4 C3 .func_key: ret 3063 3064 ; 3065 ; 3066 ; kaboom2: once everything is loaded, replace the part of kaboom 3067 ; starting with "kaboom.patch" with this part 3068 3069 kaboom2: 3070 000011A5 BE[0D18] mov si,err_bootfailed 3071 000011A8 E8ADFF call cwritestr 3072 000011AB E8CEFF call getchar 3073 000011AE CD19 int 19h ; And try once more to boot... 3074 000011B0 EBFE .norge: jmp short .norge ; If int 19h returned; this is the end 3075 3076 ; 3077 ; open,getc: Load a file a character at a time for parsing in a manner 3078 ; similar to the C library getc routine. Only one simultaneous 3079 ; use is supported. Note: "open" trashes the trackbuf. 3080 ; 3081 ; open: Input: mangled filename in DS:DI 3082 ; Output: ZF set on file not found or zero length 3083 ; 3084 ; getc: Output: CF set on end of file 3085 ; Character loaded in AL 3086 ; 3087 open: 3088 000011B2 E866FD call searchdir 3089 000011B5 7427 jz open_return 3090 000011B7 9C pushf 3091 000011B8 A3E464 mov [FBytes1],ax 3092 000011BB 8916E664 mov [FBytes2],dx 3093 000011BF 0306F264 add ax,[ClustSize] 3094 000011C3 83D200 adc dx,byte 0 3095 000011C6 83E801 sub ax,byte 1 3096 000011C9 83DA00 sbb dx,byte 0 3097 000011CC F736F264 div word [ClustSize] 3098 000011D0 A30665 mov [FClust],ax ; Number of clusters 3099 000011D3 89360865 mov [FNextClust],si ; Cluster pointer 3100 000011D7 A1FE64 mov ax,[EndOfGetCBuf] ; Pointer at end of buffer -> 3101 000011DA A30A65 mov [FPtr],ax ; nothing loaded yet 3102 000011DD 9D popf ; Restore no ZF 3103 000011DE C3 open_return: ret 3104 3105 ; 3106 getc: 3107 000011DF F9 stc ; If we exit here -> EOF 3108 000011E0 668B0EE464 mov ecx,[FBytes] 3109 000011E5 66E33B jecxz getc_ret 3110 000011E8 8B360A65 mov si,[FPtr] 3111 000011EC 3B36FE64 cmp si,[EndOfGetCBuf] 3112 000011F0 7226 jb getc_loaded 3113 ; Buffer empty -- load another set 3114 000011F2 8B0E0665 mov cx,[FClust] 3115 000011F6 3B0EF864 cmp cx,[BufSafe] 3116 000011FA 7604 jna getc_oksize 3117 000011FC 8B0EF864 mov cx,[BufSafe] 3118 00001200 290E0665 getc_oksize: sub [FClust],cx ; Reduce remaining clusters 3119 00001204 8B360865 mov si,[FNextClust] 3120 00001208 BB0098 mov bx,getcbuf 3121 0000120B 53 push bx 3122 0000120C 06 push es ; ES may be != DS, save old ES 3123 0000120D 1E push ds ; Trackbuf is in DS, not ES 3124 0000120E 07 pop es 3125 0000120F E814F1 call getfssec ; Load a trackbuf full of data 3126 00001212 89360865 mov [FNextClust],si ; Store new next pointer 3127 00001216 07 pop es ; Restore ES 3128 00001217 5E pop si ; SI -> newly loaded data 3129 00001218 AC getc_loaded: lodsb ; Load a byte 3130 00001219 89360A65 mov [FPtr],si ; Update next byte pointer 3131 0000121D 66FF0EE464 dec dword [FBytes] ; Update bytes left counter (CF = 1) 3132 00001222 F8 clc ; Not EOF 3133 00001223 C3 getc_ret: ret 3134 3135 ; 3136 ; ungetc: Push a character (in AL) back into the getc buffer 3137 ; Note: if more than one byte is pushed back, this may cause 3138 ; bytes to be written below the getc buffer boundary. If there 3139 ; is a risk for this to occur, the getcbuf base address should 3140 ; be moved up. 3141 ; 3142 ungetc: 3143 00001224 8B360A65 mov si,[FPtr] 3144 00001228 4E dec si 3145 00001229 8804 mov [si],al 3146 0000122B 89360A65 mov [FPtr],si 3147 0000122F 66FF06E464 inc dword [FBytes] 3148 00001234 C3 ret 3149 3150 ; 3151 ; skipspace: Skip leading whitespace using "getc". If we hit end-of-line 3152 ; or end-of-file, return with carry set; ZF = true of EOF 3153 ; ZF = false for EOLN; otherwise CF = ZF = 0. 3154 ; 3155 ; Otherwise AL = first character after whitespace 3156 ; 3157 skipspace: 3158 00001235 E8A7FF skipspace_loop: call getc 3159 00001238 720D jc skipspace_eof 3160 0000123A 3C1A cmp al,1Ah ; DOS EOF 3161 0000123C 7409 je skipspace_eof 3162 0000123E 3C0A cmp al,0Ah 3163 00001240 7409 je skipspace_eoln 3164 00001242 3C20 cmp al,' ' 3165 00001244 76EF jbe skipspace_loop 3166 00001246 C3 ret ; CF = ZF = 0 3167 00001247 38C0 skipspace_eof: cmp al,al ; Set ZF 3168 00001249 F9 stc ; Set CF 3169 0000124A C3 ret 3170 0000124B 04FF skipspace_eoln: add al,0FFh ; Set CF, clear ZF 3171 0000124D C3 ret 3172 3173 ; 3174 ; getkeyword: Get a keyword from the current "getc" file; only the two 3175 ; first characters are considered significant. 3176 ; 3177 ; Lines beginning with ASCII characters 33-47 are treated 3178 ; as comments and ignored; other lines are checked for 3179 ; validity by scanning through the keywd_table. 3180 ; 3181 ; The keyword and subsequent whitespace is skipped. 3182 ; 3183 ; On EOF, CF = 1; otherwise, CF = 0, AL:AH = lowercase char pair 3184 ; 3185 getkeyword: 3186 0000124E E8E4FF gkw_find: call skipspace 3187 00001251 7438 jz gkw_eof ; end of file 3188 00001253 72F9 jc gkw_find ; end of line: try again 3189 00001255 3C30 cmp al,'0' 3190 00001257 7246 jb gkw_skipline ; skip comment line 3191 00001259 50 push ax 3192 0000125A E882FF call getc 3193 0000125D 5B pop bx 3194 0000125E 722B jc gkw_eof 3195 00001260 88C7 mov bh,al ; Move character pair into BL:BH 3196 00001262 81CB2020 or bx,2020h ; Lower-case it 3197 00001266 BE[7C18] mov si,keywd_table 3198 00001269 AD gkw_check: lodsw 3199 0000126A 21C0 and ax,ax 3200 0000126C 7429 jz gkw_badline ; Bad keyword, write message 3201 0000126E 39D8 cmp ax,bx 3202 00001270 75F7 jne gkw_check 3203 00001272 50 push ax 3204 gkw_skiprest: 3205 00001273 E869FF call getc 3206 00001276 7212 jc gkw_eof_pop 3207 00001278 3C30 cmp al,'0' 3208 0000127A 77F7 ja gkw_skiprest 3209 0000127C E8A5FF call ungetc 3210 0000127F E8B3FF call skipspace 3211 00001282 7406 jz gkw_eof_pop 3212 00001284 7206 jc gkw_missingpar ; Missing parameter after keyword 3213 00001286 E89BFF call ungetc ; Return character to buffer 3214 00001289 F8 clc ; Successful return 3215 0000128A 58 gkw_eof_pop: pop ax 3216 0000128B C3 gkw_eof: ret ; CF = 1 on all EOF conditions 3217 0000128C 58 gkw_missingpar: pop ax 3218 0000128D BE[CC16] mov si,err_noparm 3219 00001290 E8C5FE call cwritestr 3220 00001293 E9B8FF jmp gkw_find 3221 00001296 58 gkw_badline_pop: pop ax 3222 00001297 BE[A916] gkw_badline: mov si,err_badcfg 3223 0000129A E8BBFE call cwritestr 3224 0000129D EBAF jmp short gkw_find 3225 0000129F 3C0A gkw_skipline: cmp al,10 ; Scan for LF 3226 000012A1 74AB je gkw_find 3227 000012A3 E839FF call getc 3228 000012A6 72E3 jc gkw_eof 3229 000012A8 EBF5 jmp short gkw_skipline 3230 3231 ; 3232 ; getint: Load an integer from the getc file. 3233 ; Return CF if error; otherwise return integer in EBX 3234 ; 3235 getint: 3236 000012AA BFA064 mov di,NumBuf 3237 000012AD 81FFAF64 gi_getnum: cmp di,NumBufEnd ; Last byte in NumBuf 3238 000012B1 730F jae gi_loaded 3239 000012B3 57 push di 3240 000012B4 E828FF call getc 3241 000012B7 5F pop di 3242 000012B8 7208 jc gi_loaded 3243 000012BA AA stosb 3244 000012BB 3C2D cmp al,'-' 3245 000012BD 73EE jnb gi_getnum 3246 000012BF E862FF call ungetc ; Unget non-numeric 3247 000012C2 C60500 gi_loaded: mov byte [di],0 3248 000012C5 BEA064 mov si,NumBuf 3249 ; Fall through to parseint 3250 3251 ; 3252 ; parseint: Convert an integer to a number in EBX 3253 ; Get characters from string in DS:SI 3254 ; Return CF on error 3255 ; DS:SI points to first character after number 3256 ; 3257 ; Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+K, val+M 3258 ; 3259 parseint: 3260 000012C8 6650 push eax 3261 000012CA 6651 push ecx 3262 000012CC 55 push bp 3263 000012CD 6631C0 xor eax,eax ; Current digit (keep eax == al) 3264 000012D0 6689C3 mov ebx,eax ; Accumulator 3265 000012D3 6689D9 mov ecx,ebx ; Base 3266 000012D6 31ED xor bp,bp ; Used for negative flag 3267 000012D8 AC pi_begin: lodsb 3268 000012D9 3C2D cmp al,'-' 3269 000012DB 7506 jne pi_not_minus 3270 000012DD 81F50100 xor bp,1 ; Set unary minus flag 3271 000012E1 EBF5 jmp short pi_begin 3272 pi_not_minus: 3273 000012E3 3C30 cmp al,'0' 3274 000012E5 724F jb pi_err 3275 000012E7 7408 je pi_octhex 3276 000012E9 3C39 cmp al,'9' 3277 000012EB 7749 ja pi_err 3278 000012ED B10A mov cl,10 ; Base = decimal 3279 000012EF EB17 jmp short pi_foundbase 3280 pi_octhex: 3281 000012F1 AC lodsb 3282 000012F2 3C30 cmp al,'0' 3283 000012F4 7225 jb pi_km ; Value is zero 3284 000012F6 0C20 or al,20h ; Downcase 3285 000012F8 3C78 cmp al,'x' 3286 000012FA 7408 je pi_ishex 3287 000012FC 3C37 cmp al,'7' 3288 000012FE 7736 ja pi_err 3289 00001300 B108 mov cl,8 ; Base = octal 3290 00001302 EB04 jmp short pi_foundbase 3291 pi_ishex: 3292 00001304 B030 mov al,'0' ; No numeric value accrued yet 3293 00001306 B110 mov cl,16 ; Base = hex 3294 pi_foundbase: 3295 00001308 E83A00 call unhexchar 3296 0000130B 720E jc pi_km ; Not a (hex) digit 3297 0000130D 38C8 cmp al,cl 3298 0000130F 730A jae pi_km ; Invalid for base 3299 00001311 660FAFD9 imul ebx,ecx ; Multiply accumulated by base 3300 00001315 6601C3 add ebx,eax ; Add current digit 3301 00001318 AC lodsb 3302 00001319 EBED jmp short pi_foundbase 3303 pi_km: 3304 0000131B 4E dec si ; Back up to last non-numeric 3305 0000131C AC lodsb 3306 0000131D 0C20 or al,20h 3307 0000131F 3C6B cmp al,'k' 3308 00001321 7416 je pi_isk 3309 00001323 3C6D cmp al,'m' 3310 00001325 7418 je pi_ism 3311 00001327 4E dec si ; Back up 3312 00001328 21ED pi_fini: and bp,bp 3313 0000132A 7404 jz pi_ret ; CF=0! 3314 0000132C 66F7DB neg ebx ; Value was negative 3315 0000132F F8 pi_done: clc 3316 00001330 5D pi_ret: pop bp 3317 00001331 6659 pop ecx 3318 00001333 6658 pop eax 3319 00001335 C3 ret 3320 00001336 F9 pi_err: stc 3321 00001337 EBF7 jmp short pi_ret 3322 00001339 66C1E30A pi_isk: shl ebx,10 ; x 2^10 3323 0000133D EBF0 jmp short pi_done 3324 0000133F 66C1E314 pi_ism: shl ebx,20 ; x 2^20 3325 00001343 EBEA jmp short pi_done 3326 3327 ; 3328 ; unhexchar: Convert a hexadecimal digit in AL to the equivalent number; 3329 ; return CF=1 if not a hex digit 3330 ; 3331 unhexchar: 3332 00001345 3C30 cmp al,'0' 3333 00001347 7215 jb uxc_ret ; If failure, CF == 1 already 3334 00001349 3C39 cmp al,'9' 3335 0000134B 7703 ja uxc_1 3336 0000134D 2C30 sub al,'0' ; CF <- 0 3337 0000134F C3 ret 3338 00001350 0C20 uxc_1: or al,20h ; upper case -> lower case 3339 00001352 3C61 cmp al,'a' 3340 00001354 7208 jb uxc_ret ; If failure, CF == 1 already 3341 00001356 3C66 cmp al,'f' 3342 00001358 7703 ja uxc_err 3343 0000135A 2C57 sub al,'a'-10 ; CF <- 0 3344 0000135C C3 ret 3345 0000135D F9 uxc_err: stc 3346 0000135E C3 uxc_ret: ret 3347 3348 ; 3349 ; 3350 ; getline: Get a command line, converting control characters to spaces 3351 ; and collapsing streches to one; a space is appended to the 3352 ; end of the string, unless the line is empty. 3353 ; The line is terminated by ^J, ^Z or EOF and is written 3354 ; to ES:DI. On return, DI points to first char after string. 3355 ; CF is set if we hit EOF. 3356 ; 3357 getline: 3358 0000135F E8D3FE call skipspace 3359 00001362 B201 mov dl,1 ; Empty line -> empty string. 3360 00001364 742B jz gl_eof ; eof 3361 00001366 7226 jc gl_eoln ; eoln 3362 00001368 E8B9FE call ungetc 3363 0000136B 52 gl_fillloop: push dx 3364 0000136C 57 push di 3365 0000136D E86FFE call getc 3366 00001370 5F pop di 3367 00001371 5A pop dx 3368 00001372 721E jc gl_ret ; CF set! 3369 00001374 3C20 cmp al,' ' 3370 00001376 7605 jna gl_ctrl 3371 00001378 31D2 xor dx,dx 3372 0000137A AA gl_store: stosb 3373 0000137B EBEE jmp short gl_fillloop 3374 0000137D 3C0A gl_ctrl: cmp al,10 3375 0000137F 7411 je gl_ret ; CF clear! 3376 00001381 3C1A cmp al,26 3377 00001383 740C je gl_eof 3378 00001385 20D2 and dl,dl 3379 00001387 75E2 jnz gl_fillloop ; Ignore multiple spaces 3380 00001389 B020 mov al,' ' ; Ctrl -> space 3381 0000138B 42 inc dx 3382 0000138C EBEC jmp short gl_store 3383 0000138E F8 gl_eoln: clc ; End of line is not end of file 3384 0000138F EB01 jmp short gl_ret 3385 00001391 F9 gl_eof: stc 3386 00001392 9C gl_ret: pushf ; We want the last char to be space! 3387 00001393 20D2 and dl,dl 3388 00001395 7503 jnz gl_xret 3389 00001397 B020 mov al,' ' 3390 00001399 AA stosb 3391 0000139A 9D gl_xret: popf 3392 0000139B C3 ret 3393 3394 3395 %ifdef debug ; This code for debugging only 3396 ; 3397 ; dumpregs: Dumps the contents of all registers 3398 ; 3399 assume ds:_text, es:NOTHING, fs:NOTHING, gs:NOTHING 3400 dumpregs proc near ; When calling, IP is on stack 3401 pushf ; Store flags 3402 pusha 3403 push ds 3404 push es 3405 push fs 3406 push gs 3407 push cs ; Set DS <- CS 3408 pop ds 3409 cld ; Clear direction flag 3410 mov si,offset crlf_msg 3411 call cwritestr 3412 mov bx,sp 3413 add bx,byte 26 3414 mov si,offset regnames 3415 mov cx,2 ; 2*7 registers to dump 3416 dump_line: push cx 3417 mov cx,7 ; 7 registers per line 3418 dump_reg: push cx 3419 mov cx,4 ; 4 characters/register name 3420 wr_reg_name: lodsb 3421 call writechr 3422 loop wr_reg_name 3423 mov ax,ss:[bx] 3424 dec bx 3425 dec bx 3426 call writehex 3427 pop cx 3428 loop dump_reg 3429 mov al,0Dh ; 3430 call writechr 3431 mov al,0Ah ; 3432 call writechr 3433 pop cx 3434 loop dump_line 3435 pop gs 3436 pop fs 3437 pop es 3438 pop ds 3439 popa ; Restore the remainder 3440 popf ; Restore flags 3441 ret 3442 dumpregs endp 3443 3444 regnames db ' IP: FL: AX: CX: DX: BX: SP: BP: SI: DI: DS: ES: FS: GS:' 3445 3446 ; 3447 ; writehex: Writes a 16-bit hexadecimal number (in AX) 3448 ; 3449 writehex proc near 3450 push bx 3451 push cx 3452 mov cx,4 ; 4 numbers 3453 write_hexdig: xor bx,bx 3454 push cx 3455 mov cx,4 ; 4 bits/digit 3456 xfer_digit: shl ax,1 3457 rcl bx,1 3458 loop xfer_digit 3459 push ax 3460 mov ax,bx 3461 or al,'0' 3462 cmp al,'9' 3463 jna ok_digit 3464 add al,'A'-'0'-10 3465 ok_digit: call writechr 3466 pop ax 3467 pop cx 3468 loop write_hexdig 3469 pop cx 3470 pop bx 3471 ret 3472 writehex endp 3473 3474 debug_magic dw 0D00Dh 3475 3476 %endif ; debug 3477 ; 3478 ; mangle_name: Mangle a DOS filename pointed to by DS:SI into a buffer pointed 3479 ; to by ES:DI; ends on encountering any whitespace 3480 ; 3481 3482 mangle_name: 3483 0000139C B90B00 mov cx,11 ; # of bytes to write 3484 mn_loop: 3485 0000139F AC lodsb 3486 000013A0 3C20 cmp al,' ' ; If control or space, end 3487 000013A2 762B jna mn_end 3488 000013A4 3C2E cmp al,'.' ; Period -> space-fill 3489 000013A6 740C je mn_is_period 3490 000013A8 3C61 cmp al,'a' 3491 000013AA 7220 jb mn_not_lower 3492 000013AC 3C7A cmp al,'z' 3493 000013AE 770F ja mn_not_uslower 3494 000013B0 2C20 sub al,020h 3495 000013B2 EB18 jmp short mn_not_lower 3496 000013B4 B020 mn_is_period: mov al,' ' ; We need to space-fill 3497 000013B6 81F90300 mn_period_loop: cmp cx,3 ; If <= 3 characters left 3498 000013BA 76E3 jbe mn_loop ; Just ignore it 3499 000013BC AA stosb ; Otherwise, write a period 3500 000013BD E2F7 loop mn_period_loop ; Dec CX and (always) jump 3501 000013BF 3C81 mn_not_uslower: cmp al,ucase_low 3502 000013C1 7209 jb mn_not_lower 3503 000013C3 3CA4 cmp al,ucase_high 3504 000013C5 7705 ja mn_not_lower 3505 000013C7 BB[5313] mov bx,ucase_tab-ucase_low 3506 000013CA 2ED7 cs xlatb 3507 000013CC AA mn_not_lower: stosb 3508 000013CD E2D0 loop mn_loop ; Don't continue if too long 3509 mn_end: 3510 000013CF B020 mov al,' ' ; Space-fill name 3511 000013D1 F3AA rep stosb ; Doesn't do anything if CX=0 3512 000013D3 C3 ret ; Done 3513 3514 ; 3515 ; Upper-case table for extended characters; this is technically code page 865, 3516 ; but code page 437 users will probably not miss not being able to use the 3517 ; cent sign in kernel images too much :-) 3518 ; 3519 ; The table only covers the range 129 to 164; the rest we can deal with. 3520 ; 3521 ucase_low equ 129 3522 ucase_high equ 164 3523 000013D4 9A90418E418F804545- ucase_tab db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII' 3524 000013DD 45494949 3525 000013E1 8E8F9092924F994F55- db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154 3526 000013EA 5559999A 3527 000013EE 9D9C9D9E9F41494F55- db 157, 156, 157, 158, 159, 'AIOU', 165 3528 000013F7 A5 3529 3530 ; 3531 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled 3532 ; filename to the conventional representation. This is needed 3533 ; for the BOOT_IMAGE= parameter for the kernel. 3534 ; NOTE: A 13-byte buffer is mandatory, even if the string is 3535 ; known to be shorter. 3536 ; 3537 ; DS:SI -> input mangled file name 3538 ; ES:DI -> output buffer 3539 ; 3540 ; On return, DI points to the first byte after the output name, 3541 ; which is set to a null byte. 3542 ; 3543 unmangle_name: 3544 000013F8 56 push si ; Save pointer to original name 3545 000013F9 B90800 mov cx,8 3546 000013FC 89FD mov bp,di 3547 000013FE AC un_copy_body: lodsb 3548 000013FF E82600 call lower_case 3549 00001402 AA stosb 3550 00001403 3C20 cmp al,' ' 3551 00001405 7602 jbe un_cb_space 3552 00001407 89FD mov bp,di ; Position of last nonblank+1 3553 00001409 E2F3 un_cb_space: loop un_copy_body 3554 0000140B 89EF mov di,bp 3555 0000140D B02E mov al,'.' ; Don't save 3556 0000140F AA stosb 3557 00001410 B90300 mov cx,3 3558 00001413 AC un_copy_ext: lodsb 3559 00001414 E81100 call lower_case 3560 00001417 AA stosb 3561 00001418 3C20 cmp al,' ' 3562 0000141A 7602 jbe un_ce_space 3563 0000141C 89FD mov bp,di 3564 0000141E E2F3 un_ce_space: loop un_copy_ext 3565 00001420 89EF mov di,bp 3566 00001422 26C60500 mov byte [es:di], 0 3567 00001426 5E pop si 3568 00001427 C3 ret 3569 3570 ; 3571 ; lower_case: Lower case a character in AL 3572 ; 3573 lower_case: 3574 00001428 3C41 cmp al,'A' 3575 0000142A 7216 jb lc_ret 3576 0000142C 3C5A cmp al,'Z' 3577 0000142E 7703 ja lc_1 3578 00001430 0C20 or al,20h 3579 00001432 C3 ret 3580 00001433 3C80 lc_1: cmp al,lcase_low 3581 00001435 720B jb lc_ret 3582 00001437 3CA5 cmp al,lcase_high 3583 00001439 7707 ja lc_ret 3584 0000143B 53 push bx 3585 0000143C BB[C313] mov bx,lcase_tab-lcase_low 3586 0000143F 2ED7 cs xlatb 3587 00001441 5B pop bx 3588 00001442 C3 lc_ret: ret 3589 3590 ; 3591 ; Lower-case table for codepage 865 3592 ; 3593 lcase_low equ 128 3594 lcase_high equ 165 3595 00001443 878182838485868788- lcase_tab db 135, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138 3596 0000144C 898A 3597 0000144E 8B8C8D848682919193- db 139, 140, 141, 132, 134, 130, 145, 145, 147, 148, 149 3598 00001457 9495 3599 00001459 96979894819B9C9B9E- db 150, 151, 152, 148, 129, 155, 156, 155, 158, 159, 160 3600 00001462 9FA0 3601 00001464 A1A2A3A4A4 db 161, 162, 163, 164, 164 3602 ; 3603 ; Various initialized or semi-initialized variables 3604 ; 3605 00001469 20436F707972696768- copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin' 3606 00001472 742028432920313939- 3607 0000147B 342D3139393920482E- 3608 00001484 20506574657220416E- 3609 0000148D 76696E 3610 00001490 0D0A00 db 0Dh, 0Ah, 0 3611 00001493 626F6F743A2000 boot_prompt db 'boot: ', 0 3612 0000149A 08200800 wipe_char db 08h, ' ', 08h, 0 3613 0000149E 436F756C64206E6F74- err_notfound db 'Could not find kernel image: ',0 3614 000014A7 2066696E64206B6572- 3615 000014B0 6E656C20696D616765- 3616 000014B9 3A2000 3617 000014BC 0D0A496E76616C6964- err_notkernel db 0Dh, 0Ah, 'Invalid or corrupt kernel image.', 0Dh, 0Ah, 0 3618 000014C5 206F7220636F727275- 3619 000014CE 7074206B65726E656C- 3620 000014D7 20696D6167652E0D0A- 3621 000014E0 00 3622 000014E1 497420617070656172- err_not386 db 'It appears your computer uses a 286 or lower CPU.' 3623 000014EA 7320796F757220636F- 3624 000014F3 6D7075746572207573- 3625 000014FC 657320612032383620- 3626 00001505 6F72206C6F77657220- 3627 0000150E 4350552E 3628 00001512 0D0A db 0Dh, 0Ah 3629 00001514 596F752063616E6E6F- db 'You cannot run Linux unless you have a 386 or higher CPU' 3630 0000151D 742072756E204C696E- 3631 00001526 757820756E6C657373- 3632 0000152F 20796F752068617665- 3633 00001538 206120333836206F72- 3634 00001541 206869676865722043- 3635 0000154A 5055 3636 0000154C 0D0A db 0Dh, 0Ah 3637 0000154E 696E20796F7572206D- db 'in your machine. If you get this message in error, hold' 3638 00001557 616368696E652E2020- 3639 00001560 496620796F75206765- 3640 00001569 742074686973206D65- 3641 00001572 737361676520696E20- 3642 0000157B 6572726F722C20686F- 3643 00001584 6C64 3644 00001586 0D0A db 0Dh, 0Ah 3645 00001588 646F776E2074686520- db 'down the Ctrl key while booting, and I will take your' 3646 00001591 4374726C206B657920- 3647 0000159A 7768696C6520626F6F- 3648 000015A3 74696E672C20616E64- 3649 000015AC 20492077696C6C2074- 3650 000015B5 616B6520796F7572 3651 000015BD 0D0A db 0Dh, 0Ah 3652 000015BF 776F726420666F7220- db 'word for it.', 0Dh, 0Ah, 0 3653 000015C8 69742E0D0A00 3654 000015CE 497420617070656172- err_noram db 'It appears your computer has less than 608K of low ("DOS")' 3655 000015D7 7320796F757220636F- 3656 000015E0 6D7075746572206861- 3657 000015E9 73206C657373207468- 3658 000015F2 616E203630384B206F- 3659 000015FB 66206C6F7720282244- 3660 00001604 4F532229 3661 00001608 0D0A db 0Dh, 0Ah 3662 0000160A 52414D2E20204C696E- db 'RAM. Linux needs at least this amount to boot. If you get' 3663 00001613 7578206E6565647320- 3664 0000161C 6174206C6561737420- 3665 00001625 7468697320616D6F75- 3666 0000162E 6E7420746F20626F6F- 3667 00001637 742E2020496620796F- 3668 00001640 7520676574 3669 00001645 0D0A db 0Dh, 0Ah 3670 00001647 74686973206D657373- db 'this message in error, hold down the Ctrl key while' 3671 00001650 61676520696E206572- 3672 00001659 726F722C20686F6C64- 3673 00001662 20646F776E20746865- 3674 0000166B 204374726C206B6579- 3675 00001674 207768696C65 3676 0000167A 0D0A db 0Dh, 0Ah 3677 0000167C 626F6F74696E672C20- db 'booting, and I will take your word for it.', 0Dh, 0Ah, 0 3678 00001685 616E6420492077696C- 3679 0000168E 6C2074616B6520796F- 3680 00001697 757220776F72642066- 3681 000016A0 6F722069742E0D0A00 3682 000016A9 556E6B6E6F776E206B- err_badcfg db 'Unknown keyword in syslinux.cfg.', 0Dh, 0Ah, 0 3683 000016B2 6579776F726420696E- 3684 000016BB 207379736C696E7578- 3685 000016C4 2E6366672E0D0A00 3686 000016CC 4D697373696E672070- err_noparm db 'Missing parameter in syslinux.cfg.', 0Dh, 0Ah, 0 3687 000016D5 6172616D6574657220- 3688 000016DE 696E207379736C696E- 3689 000016E7 75782E6366672E0D0A- 3690 000016F0 00 3691 000016F1 0D0A436F756C64206E- err_noinitrd db 0Dh, 0Ah, 'Could not find ramdisk image: ', 0 3692 000016FA 6F742066696E642072- 3693 00001703 616D6469736B20696D- 3694 0000170C 6167653A2000 3695 00001712 4E6F7420656E6F7567- err_nohighmem db 'Not enough memory to load specified kernel.', 0Dh, 0Ah, 0 3696 0000171B 68206D656D6F727920- 3697 00001724 746F206C6F61642073- 3698 0000172D 706563696669656420- 3699 00001736 6B65726E656C2E0D0A- 3700 0000173F 00 3701 00001740 0D0A4B65726E656C20- err_highload db 0Dh, 0Ah, 'Kernel transfer failure.', 0Dh, 0Ah, 0 3702 00001749 7472616E7366657220- 3703 00001752 6661696C7572652E0D- 3704 0000175B 0A00 3705 0000175D 43616E6E6F74206C6F- err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' 3706 00001766 616420612072616D64- 3707 0000176F 69736B207769746820- 3708 00001778 616E206F6C64206B65- 3709 00001781 726E656C20696D6167- 3710 0000178A 652E 3711 0000178C 0D0A00 db 0Dh, 0Ah, 0 3712 0000178F 3A20617474656D7074- err_notdos db ': attempted DOS system call', 0Dh, 0Ah, 0 3713 00001798 656420444F53207379- 3714 000017A1 7374656D2063616C6C- 3715 000017AA 0D0A00 3716 000017AD 434F4D424F4F542069- err_comlarge db 'COMBOOT image too large.', 0Dh, 0Ah, 0 3717 000017B6 6D61676520746F6F20- 3718 000017BF 6C617267652E0D0A00 3719 000017C8 496E76616C6964206F- err_bootsec db 'Invalid or corrupt boot sector image.', 0Dh, 0Ah, 0 3720 000017D1 7220636F7272757074- 3721 000017DA 20626F6F7420736563- 3722 000017E3 746F7220696D616765- 3723 000017EC 2E0D0A00 3724 000017F0 0D0A41323020676174- err_a20 db 0Dh, 0Ah, 'A20 gate not responding!', 0Dh, 0Ah, 0 3725 000017F9 65206E6F7420726573- 3726 00001802 706F6E64696E67210D- 3727 0000180B 0A00 3728 0000180D 0D0A426F6F74206661- err_bootfailed db 0Dh, 0Ah, 'Boot failed: please change disks and press ' 3729 00001816 696C65643A20706C65- 3730 0000181F 617365206368616E67- 3731 00001828 65206469736B732061- 3732 00001831 6E6420707265737320 3733 0000183A 61206B657920746F20- db 'a key to continue.', 0Dh, 0Ah, 0 3734 00001843 636F6E74696E75652E- 3735 0000184C 0D0A00 3736 0000184F 4C6F6164696E672000 loading_msg db 'Loading ', 0 3737 00001858 2E dotdot_msg db '.' 3738 00001859 2E00 dot_msg db '.', 0 3739 0000185B 2061626F727465642E aborted_msg db ' aborted.' ; Fall through to crlf_msg! 3740 00001864 0D0A00 crlf_msg db 0Dh, 0Ah, 0 3741 00001867 0D0C00 crff_msg db 0Dh, 0Ch, 0 3742 0000186A 5359534C494E555843- syslinux_cfg db 'SYSLINUXCFG' 3743 00001873 4647 3744 ; 3745 ; Command line options we'd like to take a look at 3746 ; 3747 ; mem= and vga= are handled as normal 32-bit integer values 3748 00001875 696E697472643D initrd_cmd db 'initrd=' 3749 initrd_cmd_len equ 7 3750 ; 3751 ; Config file keyword table 3752 ; 3753 align 2 3754 0000187C 6170 keywd_table db 'ap' ; append 3755 0000187E 6465 db 'de' ; default 3756 00001880 7469 db 'ti' ; timeout 3757 00001882 666F db 'fo' ; font 3758 00001884 6B62 db 'kb' ; kbd 3759 00001886 6469 db 'di' ; display 3760 00001888 7072 db 'pr' ; prompt 3761 0000188A 6C61 db 'la' ; label 3762 0000188C 696D db 'im' ; implicit 3763 0000188E 6B65 db 'ke' ; kernel 3764 00001890 7365 db 'se' ; serial 3765 00001892 6631 db 'f1' ; F1 3766 00001894 6632 db 'f2' ; F2 3767 00001896 6633 db 'f3' ; F3 3768 00001898 6634 db 'f4' ; F4 3769 0000189A 6635 db 'f5' ; F5 3770 0000189C 6636 db 'f6' ; F6 3771 0000189E 6637 db 'f7' ; F7 3772 000018A0 6638 db 'f8' ; F8 3773 000018A2 6639 db 'f9' ; F9 3774 000018A4 6630 db 'f0' ; F10 3775 000018A6 0000 dw 0 3776 ; 3777 ; Extensions to search for (in *reverse* order). Note that the last 3778 ; (lexically first) entry in the table is a placeholder for the original 3779 ; extension, needed for error messages. The exten_table is shifted so 3780 ; the table is 1-based; this is because a "loop" cx is used as index. 3781 ; 3782 exten_table: 3783 000018A8 00000000 OrigKernelExt: dd 0 ; Original extension 3784 000018AC 434F4D00 db 'COM',0 ; COMBOOT (same as DOS) 3785 000018B0 42532000 db 'BS ',0 ; Boot Sector 3786 000018B4 42535300 db 'BSS',0 ; Boot Sector (add superblock) 3787 000018B8 43425400 db 'CBT',0 ; COMBOOT (specific) 3788 3789 exten_count equ (($-exten_table) >> 2) - 1 ; Number of alternates 3790 ; 3791 ; Misc initialized (data) variables 3792 ; 3793 000018BC 0000 AppendLen dw 0 ; Bytes in append= command 3794 000018BE 0000 KbdTimeOut dw 0 ; Keyboard timeout (if any) 3795 000018C0 0000 FKeyMap dw 0 ; Bitmap for F-keys loaded 3796 000018C2 0080 CmdLinePtr dw cmd_line_here ; Command line advancing pointer 3797 initrd_flag equ $ 3798 000018C4 0000 initrd_ptr dw 0 ; Initial ramdisk pointer/flag 3799 000018C6 0000 VKernelCtr dw 0 ; Number of registered vkernels 3800 000018C8 0000 ForcePrompt dw 0 ; Force prompt 3801 000018CA 0100 AllowImplicit dw 1 ; Allow implicit kernels 3802 000018CC 0000 SerialPort dw 0 ; Serial port base (or 0 for no serial port) 3803 ; 3804 ; Stuff for the command line; we do some trickery here with equ to avoid 3805 ; tons of zeros appended to our file and wasting space 3806 ; 3807 000018CE 6C696E757820 linuxauto_cmd db 'linux ' 3808 000018D4 6175746F00 auto_cmd db 'auto',0 3809 linuxauto_len equ $-linuxauto_cmd 3810 auto_len equ $-auto_cmd 3811 000018D9 424F4F545F494D4147- boot_image db 'BOOT_IMAGE=' 3812 000018E2 453D 3813 boot_image_len equ $-boot_image 3814 align 4, db 0 ; For the good of REP MOVSD 3815 command_line equ $ 3816 default_cmd equ $+(max_cmd_len+2) 3817 ldlinux_end equ default_cmd+(max_cmd_len+1) 3818 kern_cmd_len equ ldlinux_end-command_line 3819 ldlinux_len equ ldlinux_end-ldlinux_magic 3820 ; 3821 ; Put the getcbuf right after the code, aligned on a sector boundary 3822 ; 3823 end_of_code equ (ldlinux_end-bootsec)+7C00h 3824 getcbuf equ (end_of_code + 511) & 0FE00h