1 ; -*- fundamental -*- (asm-mode sucks) 2 ; $Id: ldlinux.asm,v 1.28 1998/04/20 19:28:40 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-1998 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 31 ; 32 max_cmd_len equ 255 ; Must be odd; 255 is the kernel limit 33 retry_count equ 6 ; How patient are we with the disk? 34 35 ; 36 ; Should be updated with every release to avoid bootsector/SYS file mismatch 37 ; 38 %define version_str VERSION ; Must be 4 characters long! 39 %define date DATE_STR ; Defined from the Makefile 40 %define year '1998' 41 ; 42 ; Debgging stuff 43 ; 44 ; %define debug 1 ; Uncomment to enable debugging 45 ; 46 ; ID for SYSLINUX (reported to kernel) 47 ; 48 syslinux_id equ 031h ; SYSLINUX (3) version 1.x (1) 49 ; 50 ; Segments used by Linux 51 ; 52 real_mode_seg equ 9000h 53 struc real_mode_seg_t 54 00000000 resb 20h-($-$$) ; org 20h 55 00000020 kern_cmd_magic resw 1 ; Magic # for command line 56 00000022 kern_cmd_offset resw 1 ; Offset for kernel command line 57 00000024 resb 497-($-$$) ; org 497d 58 000001F1 bs_setupsecs resb 1 ; Sectors for setup code (0 -> 4) 59 000001F2 bs_rootflags resw 1 ; Root readonly flag 60 000001F4 bs_syssize resw 1 61 000001F6 bs_swapdev resw 1 ; Swap device (obsolete) 62 000001F8 bs_ramsize resw 1 ; Ramdisk flags, formerly ramdisk size 63 000001FA bs_vidmode resw 1 ; Video mode 64 000001FC bs_rootdev resw 1 ; Root device 65 000001FE bs_bootsign resw 1 ; Boot sector signature (0AA55h) 66 00000200 su_jump resb 1 ; 0EBh 67 00000201 su_jump2 resb 1 68 00000202 su_header resd 1 ; New setup code: header 69 00000206 su_version resw 1 ; See linux/arch/i386/boot/setup.S 70 00000208 su_switch resw 1 71 0000020A su_setupseg resw 1 72 0000020C su_startsys resw 1 73 0000020E su_kver resw 1 ; Kernel version pointer 74 00000210 su_loader resb 1 ; Loader ID 75 00000211 su_loadflags resb 1 ; Load high flag 76 00000212 su_movesize resw 1 77 00000214 su_code32start resd 1 ; Start of code loaded high 78 00000218 su_ramdiskat resd 1 ; Start of initial ramdisk 79 su_ramdisklen equ $ ; Length of initial ramdisk 80 0000021C su_ramdisklen1 resw 1 81 0000021E su_ramdisklen2 resw 1 82 00000220 su_bsklugeoffs resw 1 83 00000222 su_bsklugeseg resw 1 84 00000224 su_heapend resw 1 85 00000226 resb (8000h-12)-($-$$) ; Were bootsect.S puts it... 86 linux_stack equ $ 87 linux_fdctab equ $ 88 00007FF4 resb 8000h-($-$$) 89 cmd_line_here equ $ ; Should be out of the way 90 endstruc 91 92 setup_seg equ 9020h 93 struc setup_seg_t 94 org 0h ; as 9020:0000, not 9000:0200 95 setup_entry equ $ 96 endstruc 97 98 ; 99 ; Magic number of su_header field 100 ; 101 HEADER_ID equ 'HdrS' ; HdrS (in littleendian hex) 102 ; 103 ; Flags for the su_loadflags field 104 ; 105 LOAD_HIGH equ 01h ; Large kernel, load high 106 CAN_USE_HEAP equ 80h ; Boot loader reports heap size 107 ; 108 ; The following structure is used for "virtual kernels"; i.e. LILO-style 109 ; option labels. The options we permit here are `kernel' and `append 110 ; Since there is no room in the bottom 64K for all of these, we 111 ; stick them at 8000:0000 and copy them down before we need them. 112 ; 113 ; Note: this structure can be added to, but it must 114 ; 115 %define vk_power 7 ; log2(max number of vkernels) 116 %define max_vk (1 << vk_power) ; Maximum number of vkernels 117 %define vk_shift (16-vk_power) ; Number of bits to shift 118 %define vk_size (1 << vk_shift) ; Size of a vkernel buffer 119 120 struc vkernel 121 00000000 vk_vname: resb 11 ; Virtual name **MUST BE FIRST!** 122 0000000B vk_rname: resb 11 ; Real name 123 00000016 vk_appendlen: resw 1 124 alignb 4 125 00000018 vk_append: resb max_cmd_len+1 ; Command line 126 alignb 4 127 vk_end: equ $ ; Should be <= vk_size 128 endstruc 129 130 %if (vk_end > vk_size) || (vk_size*max_vk > 65536) 131 %error "Too many vkernels defined, reduce vk_power" 132 %endif 133 134 ; 135 ; Segment assignments in the bottom 640K 136 ; 0000h - main code/data segment (and BIOS segment) 137 ; 9000h - real_mode_seg 138 ; 139 vk_seg equ 8000h ; This is where we stick'em 140 xfer_buf_seg equ 7000h ; Bounce buffer for I/O to high mem 141 fat_seg equ 1000h ; 128K area for FAT (2x64K) 142 143 ; 144 ; For our convenience: define macros for jump-over-unconditinal jumps 145 ; 146 %macro jmpz 1 147 jnz %%skip 148 jmp %1 149 %%skip: 150 %endmacro 151 152 %macro jmpnz 1 153 jz %%skip 154 jmp %1 155 %%skip: 156 %endmacro 157 158 %macro jmpe 1 159 jne %%skip 160 jmp %1 161 %%skip: 162 %endmacro 163 164 %macro jmpne 1 165 je %%skip 166 jmp %1 167 %%skip: 168 %endmacro 169 170 %macro jmpc 1 171 jnc %%skip 172 jmp %1 173 %%skip: 174 %endmacro 175 176 %macro jmpnc 1 177 jc %%skip 178 jmp %1 179 %%skip: 180 %endmacro 181 182 %macro jmpb 1 183 jnb %%skip 184 jmp %1 185 %%skip: 186 %endmacro 187 188 %macro jmpnb 1 189 jb %%skip 190 jmp %1 191 %%skip: 192 %endmacro 193 194 ; 195 ; Macros similar to res[bwd], but which works in the code segment (after 196 ; section .text) 197 ; 198 %macro zb 1 199 times %1 db 0 200 %endmacro 201 202 %macro zw 1 203 times %1 dw 0 204 %endmacro 205 206 %macro zd 1 207 times %1 dd 0 208 %endmacro 209 210 ; --------------------------------------------------------------------------- 211 ; BEGIN THE BIOS/CODE/DATA SEGMENT 212 ; --------------------------------------------------------------------------- 213 absolute 4*1Eh ; In the interrupt table 214 fdctab equ $ 215 00000078 fdctab1 resw 1 216 0000007A fdctab2 resw 1 217 218 %ifdef debug 219 org 0100h 220 ..start: 221 ; 222 ; Hook for debugger stuff. This gets automatically removed when 223 ; generating the real thing. 224 ; 225 ; Initialize the registers for debugger operation 226 ; 227 cli 228 mov ax,cs 229 mov ds,ax 230 mov es,ax 231 mov ss,ax 232 mov sp,StackBuf 233 sti 234 cld 235 ; 236 ; Load the actual boot sector so we can copy the data block 237 ; 238 xor ax,ax ; Reset floppy 239 xor dx,dx 240 int 13h 241 mov cx,6 ; Retry count... 242 debug_tryloop: push cx 243 mov bx,trackbuf 244 mov cx,0001h 245 xor dx,dx 246 mov ax,0201h 247 int 13h 248 pop cx 249 jnc debug_okay 250 loop debug_tryloop 251 int 3 ; Halt! (Breakpoint) 252 debug_okay: mov si,trackbuf+0bh 253 mov di,bsBytesPerSec 254 mov cx,33h 255 rep movsb 256 ; 257 ; Save bogus "BIOS floppy block" info to the stack in case we hit kaboom 258 ; 259 push si 260 push si 261 push si ; Writing to the trackbuf is harmless 262 ; 263 ; Copy the BIOS data area 264 ; 265 push ds 266 xor ax,ax 267 mov ds,ax 268 mov si,0400h 269 mov di,si 270 mov cx,0100h 271 rep movsw 272 pop ds 273 ; 274 ; 275 ; A NOP where we can breakpoint, then jump into the code *after* 276 ; the segment register initialization section 277 ; 278 nop 279 jmp debugentrypt 280 %endif 281 282 absolute 0484h 283 00000484 BIOS_vidrows resb 1 ; Number of screen rows 284 285 ; 286 ; Memory below this point is reserved for the BIOS and the MBR 287 ; 288 absolute 1000h 289 trackbuf equ $ ; Track buffer goes here 290 trackbufsize equ 16384 ; Safe size of track buffer 291 ; trackbuf ends at 5000h 292 293 absolute 6000h ; Here we keep our BSS stuff 294 StackBuf equ $ ; Start the stack here (grow down - 4K) 295 00006000 VKernelBuf: resb vk_size ; "Current" vkernel 296 alignb 4 297 00006200 AppendBuf resb max_cmd_len+1 ; append= 298 00006300 KbdMap resb 256 ; Keyboard map 299 00006400 FKeyName resb 10*16 ; File names for F-key help 300 000064A0 NumBuf resb 16 ; Buffer to load number 301 NumBufEnd equ NumBuf+15 ; Pointer to last byte in NumBuf 302 alignb 4 303 000064B0 InitRDat resd 1 ; Load address (linear) for initrd 304 000064B4 HiLoadAddr resd 1 ; Address pointer for high load loop 305 RootDir equ $ ; Location of root directory 306 000064B8 RootDir1 resw 1 307 000064BA RootDir2 resw 1 308 DataArea equ $ ; Location of data area 309 000064BC DataArea1 resw 1 310 000064BE DataArea2 resw 1 311 FBytes equ $ ; Used by open/getc 312 000064C0 FBytes1 resw 1 313 000064C2 FBytes2 resw 1 314 000064C4 RootDirSize resw 1 ; Root dir size in sectors 315 000064C6 DirScanCtr resw 1 ; Used while searching directory 316 000064C8 DirBlocksLeft resw 1 ; Ditto 317 000064CA EndofDirSec resw 1 ; = trackbuf+bsBytesPerSec-31 318 000064CC RunLinClust resw 1 ; Cluster # for LDLINUX.SYS 319 000064CE ClustSize resw 1 ; Bytes/cluster 320 000064D0 SecPerClust resw 1 ; Same as bsSecPerClust, but a word 321 000064D2 NextCluster resw 1 ; Pointer to "nextcluster" routine 322 000064D4 BufSafe resw 1 ; Clusters we can load into trackbuf 323 000064D6 BufSafeSec resw 1 ; = how many sectors? 324 000064D8 BufSafeBytes resw 1 ; = how many bytes? 325 000064DA EndOfGetCBuf resw 1 ; = getcbuf+BufSafeBytes 326 000064DC HighMemSize resw 1 ; High memory (K) 327 000064DE KernelClust resw 1 ; Kernel size in clusters 328 000064E0 KernelK resw 1 ; Kernel size in kilobytes 329 000064E2 InitRDClust resw 1 ; Ramdisk size in clusters 330 000064E4 ClustPerMoby resw 1 ; Clusters per 64K 331 000064E6 FClust resw 1 ; Number of clusters in open/getc file 332 000064E8 FNextClust resw 1 ; Pointer to next cluster in d:o 333 000064EA FPtr resw 1 ; Pointer to next char in buffer 334 000064EC CmdOptPtr resw 1 ; Pointer to first option on cmd line 335 000064EE KernelCNameLen resw 1 ; Length of unmangled kernel name 336 000064F0 InitRDCNameLen resw 1 ; Length of unmangled initrd name 337 000064F2 NextCharJump resw 1 ; Routine to interpret next print char 338 000064F4 SetupSecs resw 1 ; Number of setup sectors 339 TextAttrBX equ $ 340 000064F6 TextAttribute resb 1 ; Text attribute for message file 341 000064F7 TextPage resb 1 ; Active display page 342 CursorDX equ $ 343 000064F8 CursorCol resb 1 ; Cursor column for message file 344 000064F9 CursorRow resb 1 ; Cursor row for message file 345 ScreenSize equ $ 346 000064FA VidCols resb 1 ; Columns on screen-1 347 000064FB VidRows resb 1 ; Rows on screen-1 348 000064FC RetryCount resb 1 ; Used for disk access retries 349 000064FD KbdFlags resb 1 ; Check for keyboard escapes 350 000064FE LoadFlags resb 1 ; Loadflags from kernel 351 000064FF MNameBuf resb 11 ; Generic mangled file name buffer 352 0000650A KernelName resb 11 ; Mangled name for kernel 353 00006515 InitRD resb 11 ; initrd= mangled name 354 00006520 KernelCName resb 13 ; Unmangled kernel name 355 0000652D InitRDCName resb 13 ; Unmangled initrd name 356 357 section .text 358 org 7C00h 359 bootsec equ $ 360 00000000 EB3C jmp short start ; 2 bytes 361 00000002 90 nop ; 1 byte 362 ; 363 ; "Superblock" follows -- it's in the boot sector, so it's already 364 ; loaded and ready for us 365 ; 366 00000003 5359534C494E5558 bsOemName db 'SYSLINUX' ; The SYS command sets this, so... 367 bsBytesPerSec zw 1 368 0000000B 0000 <1> bsBytesPerSec times %1 dw 0 369 bsSecPerClust zb 1 370 0000000D 00 <1> bsSecPerClust times %1 db 0 371 bsResSectors zw 1 372 0000000E 0000 <1> bsResSectors times %1 dw 0 373 bsFATs zb 1 374 00000010 00 <1> bsFATs times %1 db 0 375 bsRootDirEnts zw 1 376 00000011 0000 <1> bsRootDirEnts times %1 dw 0 377 bsSectors zw 1 378 00000013 0000 <1> bsSectors times %1 dw 0 379 bsMedia zb 1 380 00000015 00 <1> bsMedia times %1 db 0 381 bsFATsecs zw 1 382 00000016 0000 <1> bsFATsecs times %1 dw 0 383 bsSecPerTrack zw 1 384 00000018 0000 <1> bsSecPerTrack times %1 dw 0 385 bsHeads zw 1 386 0000001A 0000 <1> bsHeads times %1 dw 0 387 bsHiddenSecs equ $ 388 bsHidden1 zw 1 389 0000001C 0000 <1> bsHidden1 times %1 dw 0 390 bsHidden2 zw 1 391 0000001E 0000 <1> bsHidden2 times %1 dw 0 392 bsHugeSectors equ $ 393 bsHugeSec1 zw 1 394 00000020 0000 <1> bsHugeSec1 times %1 dw 0 395 bsHugeSec2 zw 1 396 00000022 0000 <1> bsHugeSec2 times %1 dw 0 397 bsDriveNumber zb 1 398 00000024 00 <1> bsDriveNumber times %1 db 0 399 bsReserved1 zb 1 400 00000025 00 <1> bsReserved1 times %1 db 0 401 bsBootSignature zb 1 ; 29h if the following fields exist 402 00000026 00 <1> bsBootSignature times %1 db 0 403 bsVolumeID zd 1 404 00000027 00000000 <1> bsVolumeID times %1 dd 0 405 bsVolumeLabel zb 11 406 0000002B 00 <1> bsVolumeLabel times %1 db 0 407 bsFileSysType zb 8 ; Must be FAT12 for this version 408 00000036 00 <1> bsFileSysType times %1 db 0 409 ; 410 ; Note we don't check the constraints above now; we did that at install 411 ; time (we hope!) 412 ; 413 414 floppy_table equ $ ; No sense in wasting memory, overwrite start 415 416 start: 417 0000003E FA cli ; No interrupts yet, please 418 ; 419 ; Set up the stack 420 ; 421 0000003F 31C0 xor ax,ax 422 00000041 8ED0 mov ss,ax 423 00000043 BC0060 mov sp,StackBuf ; Just below BSS 424 ; 425 ; DS:SI may contain a partition table entry. Preserve it for us. 426 ; 427 00000046 8A34 mov dh,[si] ; "Active flag" (sanity check) 428 00000048 8B6C08 mov bp,[si+8] ; LSW of linear offset 429 0000004B 8B5C0A mov bx,[si+10] ; MSW of linear offset 430 431 ; Now sautee the BIOS floppy info block to that it will support decent- 432 ; size transfers; the floppy block is 11 bytes and is stored in the 433 ; INT 1Eh vector (brilliant waste of resources, eh?) 434 ; 435 ; Of course, if BIOSes had been properly programmed, we wouldn't have 436 ; had to waste precious boot sector space with this code. 437 ; 438 ; This code no longer fits. Hope that noone really needs it anymore. 439 ; In fact, some indications is that this code does more harm than good 440 ; with all the new kinds of drives and media. 441 ; 442 %ifdef SUPPORT_REALLY_BROKEN_BIOSES 443 lds si,[ss:fdctab] ; DS:SI -> original 444 push ds ; Save on stack in case 445 push si ; we have to bail 446 push bx 447 mov cx,6 ; 12 bytes 448 mov di,floppy_table 449 push di 450 cld 451 rep movsw ; Faster to move words 452 pop di 453 mov ds,ax ; Now we can point DS to here, too 454 mov cl,[bsSecPerTrack] ; Patch the sector count 455 mov [di+4],cl 456 mov [fdctab+2],ax ; Segment 0 457 mov [fdctab],di ; offset floppy_block 458 %else 459 0000004E 8ED8 mov ds,ax 460 %endif 461 ; 462 ; Ready to enable interrupts, captain 463 ; 464 00000050 FB sti 465 ; 466 ; The drive number and possibly partition information was passed to us 467 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to 468 ; trust that rather than what the superblock contains. 469 ; 470 ; Would it be better to zero out bsHidden if we don't have a partition table? 471 ; 472 00000051 52 push dx 473 00000052 8816[2400] mov [bsDriveNumber],dl 474 00000056 F6C280 test dl,80h ; If floppy disk (00-7F), assume no 475 00000059 7426 jz not_harddisk ; partition table 476 0000005B F6C67F test dh,7Fh ; Sanity check: "active flag" should 477 0000005E 7508 jnz no_partition ; be 00 or 80 478 00000060 892E[1C00] mov [bsHidden1],bp 479 00000064 891E[1E00] mov [bsHidden2],bx 480 no_partition: 481 ; 482 ; Get disk drive parameters (don't trust the superblock.) Don't do this for 483 ; floppy drives -- INT 13:08 on floppy drives will return info about what the 484 ; *drive* supports, not about the *media*... 485 ; 486 00000068 5A pop dx ; Restore DL = drive # 487 00000069 B408 mov ah,08h 488 0000006B CD13 int 13h 489 0000006D 7212 jc no_driveparm 490 0000006F 20E4 and ah,ah 491 00000071 750E jnz no_driveparm 492 00000073 FEC6 inc dh ; Contains # of heads - 1 493 00000075 8836[1A00] mov [bsHeads],dh 494 00000079 81E13F00 and cx,3fh 495 0000007D 890E[1800] mov [bsSecPerTrack],cx 496 no_driveparm: 497 not_harddisk: 498 ; 499 ; Now we have to do some arithmetric to figure out where things are located. 500 ; If Microsoft had had brains they would already have done this for us, 501 ; and stored it in the superblock at format time, but here we go, 502 ; wasting precious boot sector space again... 503 ; 504 debugentrypt: 505 00000081 31C0 xor ax,ax ; INT 13:08 destroys ES 506 00000083 8EC0 mov es,ax ; so we clear it this late 507 00000085 A0[1000] mov al,[bsFATs] ; Number of FATs (AH == 0) 508 00000088 727E jc kaboom ; If the floppy init failed 509 0000008A F726[1600] mul word [bsFATsecs] ; Get the size of the FAT area 510 0000008E 0306[1C00] add ax,[bsHidden1] ; Add hidden sectors 511 00000092 1316[1E00] adc dx,[bsHidden2] 512 00000096 0306[0E00] add ax,[bsResSectors] ; And reserved sectors 513 0000009A 83D200 adc dx,byte 0 514 515 0000009D A3B864 mov [RootDir1],ax ; Location of root directory 516 000000A0 8916BA64 mov [RootDir2],dx 517 000000A4 A3BC64 mov [DataArea1],ax 518 000000A7 8916BE64 mov [DataArea2],dx 519 000000AB 50 push ax 520 000000AC 52 push dx 521 522 000000AD B82000 mov ax,32 ; Size of a directory entry 523 000000B0 F726[1100] mul word [bsRootDirEnts] 524 000000B4 8B1E[0B00] mov bx,[bsBytesPerSec] 525 000000B8 01D8 add ax,bx ; Round up, not down 526 000000BA 48 dec ax 527 000000BB F7F3 div bx ; Now we have the size of the root dir 528 000000BD A3C464 mov [RootDirSize],ax 529 000000C0 A3C664 mov [DirScanCtr],ax 530 000000C3 81C3E10F add bx,trackbuf-31 531 000000C7 891ECA64 mov [EndofDirSec],bx ; End of a single directory sector 532 533 000000CB 0106BC64 add [DataArea1],ax 534 000000CF 8316BE6400 adc word [DataArea2],byte 0 535 536 000000D4 5A pop dx ; Reload root directory starting point 537 000000D5 58 pop ax 538 ; 539 ; Now the fun begins. We have to search the root directory for 540 ; LDLINUX.SYS and load the first sector, so we have a little more 541 ; space to have fun with. Then we can go chasing through the FAT. 542 ; Joy!! 543 ; 544 000000D6 50 sd_nextsec: push ax 545 000000D7 52 push dx 546 000000D8 BB0010 mov bx,trackbuf 547 000000DB 53 push bx 548 000000DC E88A00 call getonesec 549 000000DF 5E pop si 550 000000E0 803C00 sd_nextentry: cmp byte [si],0 ; Directory high water mark 551 000000E3 7423 je kaboom 552 000000E5 BF[E301] mov di,ldlinux_sys 553 000000E8 B90B00 mov cx,11 554 000000EB 56 push si 555 000000EC F3A6 repe cmpsb 556 000000EE 5E pop si 557 000000EF 742F je found_it 558 000000F1 83C620 add si,byte 32 ; Distance to next 559 000000F4 3B36CA64 cmp si,[EndofDirSec] 560 000000F8 72E6 jb sd_nextentry 561 000000FA 5A pop dx 562 000000FB 58 pop ax 563 000000FC 83C001 add ax,byte 1 564 000000FF 83D200 adc dx,byte 0 565 00000102 FF0EC664 dec word [DirScanCtr] 566 00000106 75CE jnz sd_nextsec 567 ; 568 ; kaboom: write a message and bail out. 569 ; 570 kaboom: 571 00000108 BCFA5F mov sp,StackBuf-2*3 ; Reset stack 572 0000010B 5E pop si ; BIOS floppy block address 573 0000010C FA cli 574 0000010D 8F04 pop word [si] ; Restore location 575 0000010F 8F4402 pop word [si+2] 576 00000112 FB sti 577 00000113 BE[D301] mov si,bailmsg 578 00000116 E83800 call writestr ; Returns with AL = 0 579 00000119 98 cbw ; AH <- 0 580 0000011A CD16 int 16h ; Wait for keypress 581 0000011C CD19 int 19h ; And try once more to boot... 582 0000011E EBFE norge: jmp short norge ; If int 19h returned; this is the end 583 584 ; 585 ; found_it: now we compute the location of the first sector, then 586 ; load it and JUMP (since we're almost out of space) 587 ; 588 found_it: ; Note: we actually leave two words on the stack here 589 ; (who cares?) 590 00000120 31C0 xor ax,ax 591 00000122 A0[0D00] mov al,[bsSecPerClust] 592 00000125 89C5 mov bp,ax ; Load an entire cluster 593 00000127 8B5C1A mov bx,[si+26] ; First cluster 594 0000012A 891ECC64 mov [RunLinClust],bx ; Save for later use 595 0000012E 4B dec bx ; First cluster is "cluster 2" 596 0000012F 4B dec bx 597 00000130 F7E3 mul bx 598 00000132 0306BC64 add ax,[DataArea1] 599 00000136 1316BE64 adc dx,[DataArea2] 600 0000013A BB[0002] mov bx,ldlinux_magic 601 0000013D 53 push bx 602 0000013E E82B00 call getlinsec 603 00000141 BE[E301] mov si,bs_magic 604 00000144 5F pop di 605 00000145 B91B00 mov cx,magic_len 606 00000148 F3A6 repe cmpsb ; Make sure that the bootsector 607 0000014A 75BC jne kaboom ; matches LDLINUX.SYS 608 ; 609 ; Some BIOSes are buggy and don't jump to 0000:7C00 but to an alias address. 610 ; We depend on CS == 0 later in the program, but in order to conserve space 611 ; we don't do this until here. 612 ; 613 0000014C EA[2002]0000 jmp 0:ldlinux_ent 614 ; 615 ; writestr: write a null-terminated string to the console 616 ; 617 writestr: 618 00000151 AC wstr_1: lodsb 619 00000152 20C0 and al,al 620 00000154 7412 jz return 621 00000156 B40E mov ah,0Eh ; Write to screen as TTY 622 00000158 BB0700 mov bx,0007h ; White on black, current page 623 0000015B CD10 int 10h 624 0000015D EBF2 jmp short wstr_1 625 ; 626 ; disk_error: decrement the retry count and bail if zero 627 ; 628 0000015F 4E disk_error: dec si ; SI holds the disk retry counter 629 00000160 74A6 jz kaboom 630 00000162 93 xchg ax,bx ; Shorter than MOV 631 00000163 5B pop bx ; 632 00000164 59 pop cx ; 633 00000165 5A pop dx ; 634 00000166 EB37 jmp short disk_try_again 635 636 00000168 C3 return: ret 637 638 ; 639 ; getonesec: like getlinsec, but pre-sets the count to 1 640 ; 641 getonesec: 642 00000169 BD0100 mov bp,1 643 ; Fall through to getlinsec 644 645 ; 646 ; getlinsec: load a sequence of BP floppy sector given by the linear sector 647 ; number in DX:AX into the buffer at ES:BX. We try to optimize 648 ; by loading up to a whole track at a time, but the user 649 ; is responsible for not crossing a 64K boundary. 650 ; (Yes, BP is weird for a count, but it was available...) 651 ; 652 ; On return, BX points to the first byte after the transferred 653 ; block. 654 ; 655 ; The "stupid patch area" gets replaced by the code 656 ; mov bp,1 ; nop ... (BD 01 00 90 90...) when installing with 657 ; the -s option. 658 ; 659 getlinsec: 660 0000016C 8B36[1800] mov si,[bsSecPerTrack] 661 00000170 F7F6 div si ; Convert linear to sector/track 662 00000172 89D1 mov cx,dx ; Save sector 663 00000174 31D2 xor dx,dx ; 32-bit track number 664 00000176 F736[1A00] div word [bsHeads] ; Convert track to head/cyl 665 ; 666 ; Now we have AX = cyl, DX = head, CX = sector (0-based), 667 ; BP = sectors to transfer, SI = bsSecPerTrack, 668 ; ES:BX = data target 669 ; 670 0000017A 56 gls_nextchunk: push si ; bsSecPerTrack 671 0000017B 55 push bp ; Sectors to transfer 672 673 __BEGIN_STUPID_PATCH_AREA: 674 0000017C 29CE sub si,cx ; Sectors left on track 675 0000017E 39F5 cmp bp,si 676 00000180 7602 jna gls_lastchunk 677 00000182 89F5 mov bp,si ; No more than a trackful, please! 678 __END_STUPID_PATCH_AREA: 679 gls_lastchunk: 680 00000184 50 push ax ; Cylinder # 681 00000185 52 push dx ; Head # 682 00000186 55 push bp ; Number of sectors we're transferring 683 684 00000187 51 push cx ; Sector # 685 00000188 B106 mov cl,6 ; Because IBM was STOOPID 686 0000018A D2E4 shl ah,cl ; and thought 8 bits were enough 687 ; then thought 10 bits were enough... 688 0000018C 59 pop cx ; Sector # 689 0000018D 51 push cx 690 0000018E 41 inc cx ; Sector numbers are 1-based 691 0000018F 08E1 or cl,ah 692 00000191 88C5 mov ch,al 693 00000193 88D6 mov dh,dl 694 00000195 8A16[2400] mov dl,[bsDriveNumber] 695 00000199 95 xchg ax,bp ; Sector to transfer count 696 ; (xchg shorter than mov) 697 0000019A B402 mov ah,02h ; Read it! 698 ; 699 ; Do the disk transfer... save the registers in case we fail :( 700 ; 701 0000019C BE0600 mov si,retry_count ; # of times to retry a disk access 702 0000019F 52 disk_try_again: push dx ; 703 000001A0 51 push cx ; 704 000001A1 53 push bx ; 705 000001A2 50 push ax ; 706 000001A3 56 push si ; 707 000001A4 CD13 int 13h 708 000001A6 5E pop si ; 709 000001A7 5B pop bx ; 710 000001A8 72B5 jc disk_error 711 ; 712 ; Disk access successful 713 ; 714 000001AA 5B pop bx ; Buffer location 715 000001AB 58 pop ax ; No longer needed 716 000001AC 58 pop ax ; No longer needed 717 000001AD 59 pop cx ; Sector # 718 000001AE 5F pop di ; Sector transferred count 719 000001AF 89F8 mov ax,di ; Reduce sector left count 720 000001B1 F726[0B00] mul word [bsBytesPerSec] ; Figure out how much to advance ptr 721 000001B5 01C3 add bx,ax ; Update buffer location 722 000001B7 5A pop dx ; Head # 723 000001B8 58 pop ax ; Cyl # 724 000001B9 5D pop bp ; Sectors left to transfer 725 000001BA 5E pop si ; Number of sectors/track 726 000001BB 29FD sub bp,di ; Reduce with # of sectors just read 727 000001BD 74A9 jz return ; Done! 728 000001BF 01F9 add cx,di 729 000001C1 39F1 cmp cx,si 730 000001C3 72B5 jb gls_nextchunk 731 000001C5 42 inc dx ; Next track on cyl 732 000001C6 3B16[1A00] cmp dx,[bsHeads] ; Was this the last one? 733 000001CA 7203 jb gls_nonewcyl 734 000001CC 40 inc ax ; If so, new cylinder 735 000001CD 31D2 xor dx,dx ; First head on new cylinder 736 000001CF 29F1 gls_nonewcyl: sub cx,si ; First sector on new track 737 000001D1 EBA7 jmp short gls_nextchunk 738 739 000001D3 426F6F74206661696C- bailmsg db 'Boot failed!', 0Dh, 0Ah, 0 740 000001DC 6564210D0A00 741 742 bs_checkpt equ $ ; Must be <= 1E3h 743 744 zb 1E3h-($-$$) 745 000001E2 00 <1> times %1 db 0 746 bs_magic equ $ ; The following 32 bytes should 747 ; match ldlinux_magic 748 000001E3 4C444C494E55582053- ldlinux_sys db 'LDLINUX SYS' ; Looks like this in the root dir 749 000001EC 5953 750 000001EE 20 db ' ' 751 000001EF 312E3337 bs_version db version_str 752 000001F3 20 db ' ' 753 000001F4 307833353530366337- bs_date db date 754 000001FD 38 755 magic_len equ $-bs_magic 756 757 000001FE 55AA bootsignature dw 0AA55h 758 759 ; 760 ; =========================================================================== 761 ; End of boot sector 762 ; =========================================================================== 763 ; Start of LDLINUX.SYS 764 ; =========================================================================== 765 ; 766 ; This "magic number" works well with the "type" command... the 0 we treat 767 ; as end of string, but is ignored by "type". 768 ; 769 00000200 4C444C494E5558 ldlinux_magic db 'LDLINUX' 770 00000207 20 missing_dot db ' ' 771 00000208 53595320312E333720- db 'SYS ', version_str, ' ', date 772 00000211 307833353530366337- 773 0000021A 38 774 0000021B 00 magic_eof db 0, 775 0000021C 0D0A001A crlf db 0Dh, 0Ah, 0, 01Ah 776 777 align 4 778 ldlinux_ent: 779 ; 780 ; Tell the user we got this far 781 ; 782 00000220 BE[1C02] mov si,crlf 783 00000223 E82BFF call writestr 784 00000226 C606[0702]2E mov byte [missing_dot],'.' 785 0000022B BE[0002] mov si,ldlinux_magic 786 0000022E E820FF call writestr 787 ; 788 ; Remember, the boot sector loaded only the first cluster of LDLINUX.SYS. 789 ; We can really only rely on a single sector having been loaded. Hence 790 ; we should load the FAT into RAM and start chasing pointers... 791 ; 792 00000231 BA0100 mov dx,1 ; 64K 793 00000234 31C0 xor ax,ax 794 00000236 F736[0B00] div word [bsBytesPerSec] ; sectors/64K 795 0000023A 89C6 mov si,ax 796 797 0000023C 06 push es 798 0000023D BB0010 mov bx,fat_seg ; Load into fat_seg:0000 799 00000240 8EC3 mov es,bx 800 801 00000242 A1[1C00] mov ax,[bsHidden1] ; Hidden sectors 802 00000245 8B16[1E00] mov dx,[bsHidden2] 803 00000249 0306[0E00] add ax,[bsResSectors] ; plus reserved sectors = FAT 804 0000024D 83D200 adc dx,byte 0 805 00000250 8B0E[1600] mov cx,[bsFATsecs] ; Sectors/FAT 806 fat_load_loop: 807 00000254 89CD mov bp,cx 808 00000256 39F5 cmp bp,si 809 00000258 7602 jna fat_load 810 0000025A 89F5 mov bp,si ; A full 64K moby 811 fat_load: 812 0000025C 31DB xor bx,bx ; Offset 0 in the current ES 813 0000025E E82201 call getlinsecsr 814 00000261 29E9 sub cx,bp 815 00000263 740F jz fat_load_done ; Last moby? 816 00000265 01E8 add ax,bp ; Advance sector count 817 00000267 83D200 adc dx,byte 0 818 0000026A 8CC3 mov bx,es ; Next 64K moby 819 0000026C 81C30010 add bx,1000h 820 00000270 8EC3 mov es,bx 821 00000272 EBE0 jmp short fat_load_loop 822 fat_load_done: 823 00000274 07 pop es 824 ; 825 ; Fine, now we have the FAT in memory. How big is a cluster, really? 826 ; Also figure out how many clusters will fit in an 8K buffer, and how 827 ; many sectors and bytes that is 828 ; 829 00000275 8B3E[0B00] mov di,[bsBytesPerSec] ; Used a lot below 830 831 00000279 A0[0D00] mov al,[bsSecPerClust] ; We do this in the boot 832 0000027C 30E4 xor ah,ah ; sector, too, but there 833 0000027E A3D064 mov [SecPerClust],ax ; wasn't space to save it 834 00000281 89C6 mov si,ax ; Also used a lot... 835 00000283 F7E7 mul di 836 00000285 A3CE64 mov [ClustSize],ax ; Bytes/cluster 837 00000288 89C3 mov bx,ax 838 0000028A B80040 mov ax,trackbufsize 839 0000028D 31D2 xor dx,dx 840 0000028F F7F3 div bx 841 00000291 A3D464 mov [BufSafe],ax ; # of cluster in trackbuf 842 00000294 F726D064 mul word [SecPerClust] 843 00000298 A3D664 mov [BufSafeSec],ax 844 0000029B F7E7 mul di 845 0000029D A3D864 mov [BufSafeBytes],ax 846 000002A0 050094 add ax,getcbuf ; getcbuf is same size as 847 000002A3 A3DA64 mov [EndOfGetCBuf],ax ; trackbuf, for simplicity 848 ; 849 ; FAT12 or FAT16? This computation is fscking ridiculous... 850 ; 851 000002A6 31D2 xor dx,dx 852 000002A8 31C9 xor cx,cx 853 000002AA A1[1300] mov ax,[bsSectors] 854 000002AD 21C0 and ax,ax 855 000002AF 7507 jnz have_secs 856 000002B1 A1[2000] mov ax,[bsHugeSectors] 857 000002B4 8B16[2200] mov dx,[bsHugeSectors+2] 858 000002B8 2B06[0E00] have_secs: sub ax,[bsResSectors] 859 000002BC 83DA00 sbb dx,byte 0 860 000002BF 8A0E[1000] mov cl,[bsFATs] 861 000002C3 2B06[1600] sec_fat_loop: sub ax,[bsFATsecs] 862 000002C7 83DA00 sbb dx,byte 0 863 000002CA E2F7 loop sec_fat_loop 864 000002CC 50 push ax 865 000002CD 52 push dx 866 000002CE A1[1100] mov ax,[bsRootDirEnts] 867 000002D1 BB2000 mov bx,32 ; Smaller than shift since we 868 000002D4 F7E3 mul bx ; need the doubleword product 869 000002D6 01F8 add ax,di 870 000002D8 83D200 adc dx,byte 0 871 000002DB 83E801 sub ax,byte 1 872 000002DE 83DA00 sbb dx,byte 0 873 000002E1 F7F7 div di 874 000002E3 89C3 mov bx,ax 875 000002E5 5A pop dx 876 000002E6 58 pop ax 877 000002E7 29D8 sub ax,bx 878 000002E9 83DA00 sbb dx,byte 0 879 000002EC F7F6 div si 880 000002EE 3DF60F cmp ax,4086 ; Right value? 881 000002F1 B8[B803] mov ax,nextcluster_fat16 882 000002F4 7703 ja have_fat_type 883 000002F6 B8[9103] have_fat12: mov ax,nextcluster_fat12 884 000002F9 A3D264 have_fat_type: mov word [NextCluster],ax 885 886 ; 887 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first 888 ; cluster again, though. 889 ; 890 load_rest: 891 000002FC 8B0ECE64 mov cx,[ClustSize] 892 00000300 BB[0002] mov bx,ldlinux_magic 893 00000303 01CB add bx,cx 894 00000305 8B36CC64 mov si,[RunLinClust] 895 00000309 FF16D264 call [NextCluster] 896 0000030D 31D2 xor dx,dx 897 0000030F B8BC14 mov ax,ldlinux_len-1 ; To be on the safe side 898 00000312 01C8 add ax,cx 899 00000314 F7F1 div cx ; the number of clusters 900 00000316 48 dec ax ; We've already read one 901 00000317 7405 jz all_read_jmp 902 00000319 89C1 mov cx,ax 903 0000031B E80300 call getfssec 904 ; 905 ; All loaded up 906 ; 907 all_read_jmp: 908 0000031E E9AF00 jmp all_read 909 ; 910 ; ----------------------------------------------------------------------------- 911 ; Subroutines that have to be in the first sector 912 ; ----------------------------------------------------------------------------- 913 ; 914 ; getfssec: Get multiple clusters from a file, given the starting cluster. 915 ; 916 ; This routine makes sure the subtransfers do not cross a 64K boundary, 917 ; and will correct the situation if it does, UNLESS *sectors* cross 918 ; 64K boundaries. 919 ; 920 ; ES:BX -> Buffer 921 ; SI -> Starting cluster number (2-based) 922 ; CX -> Cluster count (0FFFFh = until end of file) 923 ; 924 ; 386 check 925 getfssec: 926 00000321 31ED getfragment: xor bp,bp ; Fragment sector count 927 00000323 89F0 mov ax,si ; Get sector address 928 00000325 48 dec ax ; Convert to 0-based 929 00000326 48 dec ax 930 00000327 F726D064 mul word [SecPerClust] 931 0000032B 0306BC64 add ax,[DataArea1] 932 0000032F 1316BE64 adc dx,[DataArea2] 933 getseccnt: ; See if we can read > 1 clust 934 00000333 032ED064 add bp,[SecPerClust] 935 00000337 49 dec cx ; Reduce clusters left to find 936 00000338 89F7 mov di,si ; Predict next cluster 937 0000033A 47 inc di 938 0000033B FF16D264 call [NextCluster] 939 0000033F 7207 jc gfs_eof ; At EOF? 940 00000341 E304 jcxz endfragment ; Or was it the last we wanted? 941 00000343 39FE cmp si,di ; Is file continuous? 942 00000345 74EC jz getseccnt ; Yes, we can get 943 00000347 F8 endfragment: clc ; Not at EOF 944 00000348 9C gfs_eof: pushf ; Remember EOF or not 945 00000349 56 push si 946 0000034A 51 push cx 947 gfs_getchunk: 948 0000034B 50 push ax 949 0000034C 52 push dx 950 0000034D 8CC0 mov ax,es ; Check for 64K boundaries. 951 0000034F B104 mov cl,4 952 00000351 D3E0 shl ax,cl 953 00000353 01D8 add ax,bx 954 00000355 31D2 xor dx,dx 955 00000357 F7D8 neg ax 956 00000359 7501 jnz gfs_partseg 957 0000035B 42 inc dx ; Full 64K segment 958 gfs_partseg: 959 0000035C F736[0B00] div word [bsBytesPerSec] ; How many sectors fit? 960 00000360 89EE mov si,bp 961 00000362 29C6 sub si,ax ; Compute remaining sectors 962 00000364 7610 jbe gfs_lastchunk 963 00000366 89C5 mov bp,ax 964 00000368 5A pop dx 965 00000369 58 pop ax 966 0000036A E81600 call getlinsecsr 967 0000036D 01E8 add ax,bp 968 0000036F 83D200 adc dx,byte 0 969 00000372 89F5 mov bp,si ; Remaining sector count 970 00000374 EBD5 jmp short gfs_getchunk 971 00000376 5A gfs_lastchunk: pop dx 972 00000377 58 pop ax 973 00000378 E8F1FD call getlinsec 974 0000037B 59 pop cx 975 0000037C 5E pop si 976 0000037D 9D popf 977 0000037E E302 jcxz gfs_return ; If we hit the count limit 978 00000380 739F jnc getfragment ; If we didn't hit EOF 979 00000382 C3 gfs_return: ret 980 981 ; 982 ; getlinsecsr: save registers, call getlinsec, restore registers 983 ; 984 00000383 50 getlinsecsr: push ax 985 00000384 52 push dx 986 00000385 51 push cx 987 00000386 55 push bp 988 00000387 56 push si 989 00000388 E8E1FD call getlinsec 990 0000038B 5E pop si 991 0000038C 5D pop bp 992 0000038D 59 pop cx 993 0000038E 5A pop dx 994 0000038F 58 pop ax 995 00000390 C3 ret 996 997 ; 998 ; nextcluster: Advance a cluster pointer in SI to the next cluster 999 ; pointed at in the FAT tables (note: FAT12 assumed) 1000 ; Sets CF on return if end of file. 1001 ; 1002 ; The variable NextCluster gets set to the appropriate 1003 ; value here. 1004 ; 1005 nextcluster_fat12: 1006 00000391 50 push ax 1007 00000392 1E push ds 1008 00000393 B80010 mov ax,fat_seg 1009 00000396 8ED8 mov ds,ax 1010 00000398 89F0 mov ax,si ; Multiply by 3/2 1011 0000039A D1E8 shr ax,1 1012 0000039C 9C pushf ; CF now set if odd 1013 0000039D 01C6 add si,ax 1014 0000039F 8B34 mov si,[si] 1015 000003A1 9D popf 1016 000003A2 7308 jnc nc_even 1017 000003A4 D1EE shr si,1 ; Needed for odd only 1018 000003A6 D1EE shr si,1 1019 000003A8 D1EE shr si,1 1020 000003AA D1EE shr si,1 1021 nc_even: 1022 000003AC 81E6FF0F and si,0FFFh 1023 000003B0 81FEF00F cmp si,0FF0h ; Clears CF if at end of file 1024 000003B4 F5 cmc ; But we want it SET... 1025 000003B5 1F pop ds 1026 000003B6 58 pop ax 1027 000003B7 C3 nc_return: ret 1028 1029 ; 1030 ; FAT16 decoding routine. Note that a 16-bit FAT can be up to 128K, 1031 ; so we have to decide if we're in the "low" or the "high" 64K-segment... 1032 ; 1033 nextcluster_fat16: 1034 000003B8 50 push ax 1035 000003B9 1E push ds 1036 000003BA B80010 mov ax,fat_seg 1037 000003BD D1E6 shl si,1 1038 000003BF 7303 jnc .seg0 1039 000003C1 B80020 mov ax,fat_seg+1000h 1040 000003C4 8ED8 .seg0: mov ds,ax 1041 000003C6 8B34 mov si,[si] 1042 000003C8 81FEF0FF cmp si,0FFF0h 1043 000003CC F5 cmc 1044 000003CD 1F pop ds 1045 000003CE 58 pop ax 1046 000003CF C3 ret 1047 ; 1048 ; Debug routine 1049 ; 1050 %ifdef debug 1051 safedumpregs: 1052 cmp word [Debug_Magic],0D00Dh 1053 jnz nc_return 1054 jmp dumpregs 1055 %endif 1056 1057 rl_checkpt equ $ ; Must be <= 400h 1058 1059 ; ---------------------------------------------------------------------------- 1060 ; End of code and data that have to be in the first sector 1061 ; ---------------------------------------------------------------------------- 1062 1063 all_read: 1064 ; 1065 ; Let the user (and programmer!) know we got this far. This used to be 1066 ; in Sector 1, but makes a lot more sense here. 1067 ; 1068 000003D0 BE[1C11] mov si,copyright_str 1069 000003D3 E87BFD call writestr 1070 ; 1071 ; Check that no moron is trying to boot Linux on a 286 or so. According 1072 ; to Intel, the way to check is to see if the high 4 bits of the FLAGS 1073 ; register are either all stuck at 1 (8086/8088) or all stuck at 0 1074 ; (286 in real mode), if not it is a 386 or higher. They didn't 1075 ; say how to check for a 186/188, so I *hope* it falls out as a 8086 1076 ; or 286 in this test. 1077 ; 1078 ; Also, provide an escape route in case it doesn't work. 1079 ; 1080 check_escapes: 1081 000003D6 B402 mov ah,02h ; Check keyboard flags 1082 000003D8 CD16 int 16h 1083 000003DA A2FD64 mov [KbdFlags],al ; Save for boot prompt check 1084 000003DD A804 test al,04h ; Ctrl->skip 386 check 1085 000003DF 7538 jnz skip_checks 1086 test_8086: 1087 000003E1 9C pushf ; Get flags 1088 000003E2 58 pop ax 1089 000003E3 25FF0F and ax,0FFFh ; Clear top 4 bits 1090 000003E6 50 push ax ; Load into FLAGS 1091 000003E7 9D popf 1092 000003E8 9C pushf ; And load back 1093 000003E9 58 pop ax 1094 000003EA 2500F0 and ax,0F000h ; Get top 4 bits 1095 000003ED 3D00F0 cmp ax,0F000h ; If set -> 8086/8088 1096 000003F0 740E je not_386 1097 test_286: 1098 000003F2 9C pushf ; Get flags 1099 000003F3 58 pop ax 1100 000003F4 0D00F0 or ax,0F000h ; Set top 4 bits 1101 000003F7 50 push ax 1102 000003F8 9D popf 1103 000003F9 9C pushf 1104 000003FA 58 pop ax 1105 000003FB 2500F0 and ax,0F000h ; Get top 4 bits 1106 000003FE 7509 jnz is_386 ; If not clear -> 386 1107 not_386: 1108 00000400 BE[9411] mov si,err_not386 1109 00000403 E84BFD call writestr 1110 00000406 E9FFFC jmp kaboom 1111 is_386: 1112 ; Now we know it's a 386 or higher 1113 ; 1114 ; Now check that there is at least 608K of low (DOS) memory 1115 ; (608K = 9800h segments) 1116 ; 1117 00000409 CD12 int 12h 1118 0000040B 3D6002 cmp ax,608 1119 0000040E 7309 jae enough_ram 1120 00000410 BE[8112] mov si,err_noram 1121 00000413 E83BFD call writestr 1122 00000416 E9EFFC jmp kaboom 1123 enough_ram: 1124 skip_checks: 1125 1126 ; 1127 ; Initialization that does not need to go into the any of the pre-load 1128 ; areas 1129 ; 1130 00000419 E8D408 call adjust_screen 1131 ; 1132 ; Now we're all set to start with our *real* business. First load the 1133 ; configuration file (if any) and parse it. 1134 ; 1135 ; In previous versions I avoided using 32-bit registers because of a 1136 ; rumour some BIOSes clobbered the upper half of 32-bit registers at 1137 ; random. I figure, though, that if there are any of those still left 1138 ; they probably won't be trying to install Linux on them... 1139 ; 1140 ; The code is still ripe with 16-bitisms, though. Not worth the hassle 1141 ; to take'm out. In fact, we may want to put them back if we're going 1142 ; to boot ELKS at some point. 1143 ; 1144 0000041C BE[A614] mov si,linuxauto_cmd ; Default command: "linux auto" 1145 0000041F BF[BD15] mov di,default_cmd 1146 00000422 B90B00 mov cx,linuxauto_len 1147 00000425 F3A4 rep movsb 1148 1149 00000427 BF0063 mov di,KbdMap ; Default keymap 1:1 1150 0000042A 30C0 xor al,al 1151 0000042C B90001 mov cx,256 1152 0000042F AA mkkeymap: stosb 1153 00000430 FEC0 inc al 1154 00000432 E2FB loop mkkeymap 1155 1156 ; 1157 ; Load configuration file 1158 ; 1159 00000434 BF[5A14] mov di,syslinux_cfg 1160 00000437 E82B0A call open 1161 0000043A 0F849501 jz near no_config_file 1162 parse_config: 1163 0000043E E8C00A call getkeyword 1164 00000441 0F828B01 jc near end_config_file ; Config file loaded 1165 00000445 3D6465 cmp ax,'de' ; DEfault 1166 00000448 7442 je pc_default 1167 0000044A 3D6170 cmp ax,'ap' ; APpend 1168 0000044D 744D je pc_append 1169 0000044F 3D7469 cmp ax,'ti' ; TImeout 1170 00000452 0F849500 je near pc_timeout 1171 00000456 3D7072 cmp ax,'pr' ; PRompt 1172 00000459 0F84AB00 je near pc_prompt 1173 0000045D 3D666F cmp ax,'fo' ; FOnt 1174 00000460 0F841601 je near pc_font 1175 00000464 3D6B62 cmp ax,'kb' ; KBd 1176 00000467 0F841901 je near pc_kbd 1177 0000046B 3D6469 cmp ax,'di' ; DIsplay 1178 0000046E 0F848B00 je near pc_display 1179 00000472 3D6C61 cmp ax,'la' ; LAbel 1180 00000475 0F84CF00 je near pc_label 1181 00000479 3D6B65 cmp ax,'ke' ; KErnel 1182 0000047C 7454 je pc_kernel 1183 0000047E 3D696D cmp ax,'im' ; IMplicit 1184 00000481 0F848E00 je near pc_implicit 1185 00000485 3C66 cmp al,'f' ; F-key 1186 00000487 75B5 jne parse_config 1187 00000489 E99200 jmp pc_fkey 1188 1189 0000048C BF[BD15] pc_default: mov di,default_cmd ; "default" command 1190 0000048F E8800B call getline 1191 00000492 BE[AC14] mov si,auto_cmd ; add "auto"+null 1192 00000495 B90500 mov cx,auto_len 1193 00000498 F3A4 rep movsb 1194 0000049A EBA2 jmp short parse_config 1195 1196 0000049C 833E[A014]00 pc_append: cmp word [VKernelCtr],byte 0 ; "append" command 1197 000004A1 7710 ja pc_append_vk 1198 000004A3 BF0062 mov di,AppendBuf 1199 000004A6 E8690B call getline 1200 000004A9 81EF0062 sub di,AppendBuf 1201 000004AD 893E[9614] pc_app1: mov [AppendLen],di 1202 000004B1 EB8B jmp short parse_config 1203 000004B3 BF1860 pc_append_vk: mov di,VKernelBuf+vk_append ; "append" command (vkernel) 1204 000004B6 E8590B call getline 1205 000004B9 81EF1860 sub di,VKernelBuf+vk_append 1206 000004BD 83FF02 cmp di,byte 2 1207 000004C0 750A jne pc_app2 1208 000004C2 803E18602D cmp byte [VKernelBuf+vk_append],'-' 1209 000004C7 7503 jne pc_app2 1210 000004C9 BF0000 mov di,0 ; If "append -" -> null string 1211 000004CC 893E1660 pc_app2: mov [VKernelBuf+vk_appendlen],di 1212 000004D0 EB33 jmp short parse_config_2 1213 1214 000004D2 833E[A014]00 pc_kernel: cmp word [VKernelCtr],byte 0 ; "kernel" command 1215 000004D7 0F8463FF je near parse_config ; ("label" section only) 1216 000004DB BF0010 mov di,trackbuf 1217 000004DE 57 push di 1218 000004DF E8300B call getline 1219 000004E2 5E pop si 1220 000004E3 BF0B60 mov di,VKernelBuf+vk_rname 1221 000004E6 E8660B call mangle_name 1222 000004E9 EB1A jmp short parse_config_2 1223 1224 000004EB E86F0A pc_timeout: call getint ; "timeout" command 1225 000004EE 7215 jc parse_config_2 1226 000004F0 B815D2 mov ax,0D215h ; There are approx 1.D215h 1227 000004F3 F7E3 mul bx ; clock ticks per 1/10 s 1228 000004F5 01D3 add bx,dx 1229 000004F7 891E[9814] mov [KbdTimeOut],bx 1230 000004FB EB08 jmp short parse_config_2 1231 1232 000004FD E88F00 pc_display: call pc_getfile ; "display" command 1233 00000500 7403 jz parse_config_2 ; File not found? 1234 00000502 E86408 call get_msg_file ; Load and display file 1235 00000505 E936FF parse_config_2: jmp parse_config 1236 1237 00000508 E8520A pc_prompt: call getint ; "prompt" command 1238 0000050B 72F8 jc parse_config_2 1239 0000050D 891E[A214] mov [ForcePrompt],bx 1240 00000511 EBF2 jmp short parse_config_2 1241 1242 00000513 E8470A pc_implicit: call getint ; "implicit" command 1243 00000516 72ED jc parse_config_2 1244 00000518 891E[A414] mov [AllowImplicit],bx 1245 0000051C EBE7 jmp short parse_config_2 1246 1247 0000051E 80EC31 pc_fkey: sub ah,'1' 1248 00000521 7302 jnb pc_fkey1 1249 00000523 B409 mov ah,9 ; F10 1250 00000525 31C9 pc_fkey1: xor cx,cx 1251 00000527 88E1 mov cl,ah 1252 00000529 51 push cx 1253 0000052A B80100 mov ax,1 1254 0000052D D3E0 shl ax,cl 1255 0000052F 0906[9A14] or [FKeyMap], ax ; Mark that we have this loaded 1256 00000533 BF0010 mov di,trackbuf 1257 00000536 57 push di 1258 00000537 E8D80A call getline ; Get filename to display 1259 0000053A 5E pop si 1260 0000053B 5F pop di 1261 0000053C C1E704 shl di,4 ; Multiply number by 16 1262 0000053F 81C70064 add di,FKeyName 1263 00000543 E8090B call mangle_name ; Mangle file name 1264 00000546 EBBD jmp short parse_config_2 1265 1266 00000548 E85700 pc_label: call commit_vk ; Commit any current vkernel 1267 0000054B BF0010 mov di,trackbuf ; Get virtual filename 1268 0000054E 57 push di 1269 0000054F E8C00A call getline 1270 00000552 5E pop si 1271 00000553 BF0060 mov di,VKernelBuf+vk_vname 1272 00000556 E8F60A call mangle_name ; Mangle virtual name 1273 00000559 FF06[A014] inc word [VKernelCtr] ; One more vkernel 1274 0000055D BE0060 mov si,VKernelBuf+vk_vname ; By default, rname == vname 1275 00000560 BF0B60 mov di,VKernelBuf+vk_rname 1276 00000563 B90B00 mov cx,11 1277 00000566 F3A4 rep movsb 1278 00000568 BE0062 mov si,AppendBuf ; Default append==global append 1279 0000056B BF1860 mov di,VKernelBuf+vk_append 1280 0000056E 8B0E[9614] mov cx,[AppendLen] 1281 00000572 890E1660 mov [VKernelBuf+vk_appendlen],cx 1282 00000576 F3A4 rep movsb 1283 00000578 EB8B jmp short parse_config_2 1284 1285 0000057A E81200 pc_font: call pc_getfile ; "font" command 1286 0000057D 7486 jz parse_config_2 ; File not found? 1287 0000057F E88907 call loadfont ; Load and install font 1288 00000582 EB08 jmp short parse_config_3 1289 1290 00000584 E80800 pc_kbd: call pc_getfile ; "kbd" command 1291 00000587 7403 jz parse_config_3 1292 00000589 E8BE07 call loadkeys 1293 0000058C E9AFFE parse_config_3: jmp parse_config 1294 1295 ; 1296 ; pc_getfile: For command line options that take file argument, this 1297 ; routine decodes the file argument and runs it through searchdir 1298 ; 1299 0000058F BF0010 pc_getfile: mov di,trackbuf 1300 00000592 57 push di 1301 00000593 E87C0A call getline 1302 00000596 5E pop si 1303 00000597 BFFF64 mov di,MNameBuf 1304 0000059A 57 push di 1305 0000059B E8B10A call mangle_name 1306 0000059E 5F pop di 1307 0000059F E9C106 jmp searchdir ; Tailcall 1308 1309 ; 1310 ; commit_vk: Store the current VKernelBuf into buffer segment 1311 ; 1312 commit_vk: 1313 000005A2 833E[A014]00 cmp word [VKernelCtr],byte 0 1314 000005A7 741F je cvk_ret ; No VKernel = return 1315 000005A9 813E[A014]8000 cmp word [VKernelCtr],max_vk ; Above limit? 1316 000005AF 7718 ja cvk_overflow 1317 000005B1 8B3E[A014] mov di,[VKernelCtr] 1318 000005B5 4F dec di 1319 000005B6 C1E709 shl di,vk_shift 1320 000005B9 BE0060 mov si,VKernelBuf 1321 000005BC B98000 mov cx,(vk_size >> 2) 1322 000005BF 06 push es 1323 000005C0 680080 push word vk_seg 1324 000005C3 07 pop es 1325 000005C4 F366A5 rep movsd ; Copy to buffer segment 1326 000005C7 07 pop es 1327 000005C8 C3 cvk_ret: ret 1328 000005C9 C706[A014]8000 cvk_overflow: mov word [VKernelCtr],max_vk ; No more than max_vk, please 1329 000005CF C3 ret 1330 1331 ; 1332 ; End of configuration file 1333 ; 1334 end_config_file: 1335 000005D0 E8CFFF call commit_vk ; Commit any current vkernel 1336 no_config_file: 1337 ; 1338 ; Check whether or not we are supposed to display the boot prompt. 1339 ; 1340 check_for_key: 1341 000005D3 833E[A214]00 cmp word [ForcePrompt],byte 0 ; Force prompt? 1342 000005D8 7509 jnz enter_command 1343 000005DA F606FD645B test byte [KbdFlags],5Bh ; Caps, Scroll, Shift, Alt 1344 000005DF 0F84B700 jz near auto_boot ; If neither, default boot 1345 1346 enter_command: 1347 000005E3 BE[4711] mov si,boot_prompt 1348 000005E6 E868FB call writestr 1349 1350 000005E9 BF[BC14] mov di,command_line 1351 ; 1352 ; get the very first character -- we can either time 1353 ; out, or receive a character press at this time. Some dorky BIOSes stuff 1354 ; a return in the buffer on bootup, so wipe the keyboard buffer first. 1355 ; 1356 000005EC B401 clear_buffer: mov ah,1 ; Check for pending char 1357 000005EE CD16 int 16h 1358 000005F0 7406 jz get_char_time 1359 000005F2 31C0 xor ax,ax ; Get char 1360 000005F4 CD16 int 16h 1361 000005F6 EBF4 jmp short clear_buffer 1362 000005F8 8B0E[9814] get_char_time: mov cx,[KbdTimeOut] 1363 000005FC 21C9 and cx,cx 1364 000005FE 741A jz get_char ; Timeout == 0 -> no timeout 1365 00000600 41 inc cx ; The first loop will happen 1366 ; immediately as we don't 1367 ; know the appropriate DX value 1368 00000601 51 time_loop: push cx 1369 00000602 52 tick_loop: push dx 1370 00000603 B401 mov ah,1 ; Check for pending keystroke 1371 00000605 CD16 int 16h 1372 00000607 750F jnz get_char_pop 1373 00000609 31C0 xor ax,ax 1374 0000060B CD1A int 1Ah ; Get time "of day" 1375 0000060D 58 pop ax 1376 0000060E 39C2 cmp dx,ax ; Has the timer advanced? 1377 00000610 74F0 je tick_loop 1378 00000612 59 pop cx 1379 00000613 E2EC loop time_loop ; If so, decrement counter 1380 00000615 E99000 jmp command_done ; Timeout! 1381 00000618 6658 get_char_pop: pop eax ; Clear the stack 1382 0000061A 31C0 get_char: xor ax,ax ; Get char 1383 0000061C CD16 int 16h 1384 0000061E 20C0 and al,al 1385 00000620 7433 jz func_key 1386 00000622 BB0063 mov bx,KbdMap ; Keyboard map translation 1387 00000625 D7 xlatb 1388 00000626 3C20 cmp al,' ' ; ASCII? 1389 00000628 7214 jb not_ascii 1390 0000062A 7706 ja enter_char 1391 0000062C 81FF[BC14] cmp di,command_line ; Space must not be first 1392 00000630 74E8 je get_char 1393 00000632 81FF[BB15] enter_char: cmp di,max_cmd_len+command_line ; Check there's space 1394 00000636 73E2 jnb get_char 1395 00000638 AA stosb ; Save it 1396 00000639 E8AA06 call writechr ; Echo to screen 1397 0000063C EBDC jmp short get_char 1398 0000063E 3C0D not_ascii: cmp al,0Dh ; Enter 1399 00000640 7466 je command_done 1400 00000642 3C08 cmp al,08h ; Backspace 1401 00000644 75D4 jne get_char 1402 00000646 81FF[BC14] cmp di,command_line ; Make sure there is anything 1403 0000064A 74CE je get_char ; to erase 1404 0000064C 4F dec di ; Unstore one character 1405 0000064D BE[4E11] mov si,wipe_char ; and erase it from the screen 1406 00000650 E8FEFA call writestr 1407 00000653 EBC5 jmp short get_char 1408 func_key: 1409 00000655 57 push di 1410 00000656 80FC44 cmp ah,68 ; F10 1411 00000659 77BF ja get_char 1412 0000065B 80EC3B sub ah,59 ; F1 1413 0000065E 72BA jb get_char 1414 00000660 88E1 mov cl,ah 1415 00000662 C1E804 shr ax,4 ; Convert to x16 1416 00000665 BB0100 mov bx,1 1417 00000668 D3E3 shl bx,cl 1418 0000066A 231E[9A14] and bx,[FKeyMap] 1419 0000066E 74AA jz get_char ; Undefined F-key 1420 00000670 89C7 mov di,ax 1421 00000672 81C70064 add di,FKeyName 1422 00000676 E8EA05 call searchdir 1423 00000679 7405 jz fk_nofile 1424 0000067B E8EB06 call get_msg_file 1425 0000067E EB06 jmp short fk_wrcmd 1426 fk_nofile: 1427 00000680 BE[1C02] mov si,crlf 1428 00000683 E8CBFA call writestr 1429 fk_wrcmd: 1430 00000686 BE[4711] mov si,boot_prompt 1431 00000689 E8C5FA call writestr 1432 0000068C 5F pop di ; Command line write pointer 1433 0000068D 57 push di 1434 0000068E C60500 mov byte [di],0 ; Null-terminate command line 1435 00000691 BE[BC14] mov si,command_line 1436 00000694 E8BAFA call writestr ; Write command line so far 1437 00000697 5F pop di 1438 00000698 EB80 jmp short get_char 1439 auto_boot: 1440 0000069A BE[BD15] mov si,default_cmd 1441 0000069D BF[BC14] mov di,command_line 1442 000006A0 B94000 mov cx,(max_cmd_len+4) >> 2 1443 000006A3 F366A5 rep movsd 1444 000006A6 EB0F jmp short load_kernel 1445 command_done: 1446 000006A8 BE[1C02] mov si,crlf 1447 000006AB E8A3FA call writestr 1448 000006AE 81FF[BC14] cmp di,command_line ; Did we just hit return? 1449 000006B2 74E6 je auto_boot 1450 000006B4 30C0 xor al,al ; Store a final null 1451 000006B6 AA stosb 1452 1453 load_kernel: ; Load the kernel now 1454 ; 1455 ; First we need to mangle the kernel name the way DOS would... 1456 ; 1457 000006B7 BE[BC14] mov si,command_line 1458 000006BA BF0A65 mov di,KernelName 1459 000006BD 56 push si 1460 000006BE 57 push di 1461 000006BF E88D09 call mangle_name 1462 000006C2 5F pop di 1463 000006C3 5E pop si 1464 ; 1465 ; Fast-forward to first option (we start over from the beginning, since 1466 ; mangle_name doesn't necessarily return a consistent ending state.) 1467 ; 1468 000006C4 AC clin_non_wsp: lodsb 1469 000006C5 3C20 cmp al,' ' 1470 000006C7 77FB ja clin_non_wsp 1471 000006C9 20C0 clin_is_wsp: and al,al 1472 000006CB 7405 jz clin_opt_ptr 1473 000006CD AC lodsb 1474 000006CE 3C20 cmp al,' ' 1475 000006D0 76F7 jbe clin_is_wsp 1476 000006D2 4E clin_opt_ptr: dec si ; Point to first nonblank 1477 000006D3 8936EC64 mov [CmdOptPtr],si ; Save ptr to first option 1478 ; 1479 ; Now check if it is a "virtual kernel" 1480 ; 1481 000006D7 8B0E[A014] mov cx,[VKernelCtr] 1482 000006DB 1E push ds 1483 000006DC 680080 push word vk_seg 1484 000006DF 1F pop ds 1485 000006E0 83F900 cmp cx,byte 0 1486 000006E3 7411 je not_vk 1487 000006E5 31F6 xor si,si ; Point to first vkernel 1488 000006E7 60 vk_check: pusha 1489 000006E8 B90B00 mov cx,11 1490 000006EB F3A6 repe cmpsb ; Is this it? 1491 000006ED 7460 je vk_found 1492 000006EF 61 popa 1493 000006F0 81C60002 add si,vk_size 1494 000006F4 E2F1 loop vk_check 1495 000006F6 1F not_vk: pop ds 1496 ; 1497 ; Not a "virtual kernel" - check that's OK and construct the command line 1498 ; 1499 000006F7 833E[A414]00 cmp word [AllowImplicit],byte 0 1500 000006FC 7446 je bad_implicit 1501 000006FE 06 push es 1502 000006FF 56 push si 1503 00000700 57 push di 1504 00000701 BF0090 mov di,real_mode_seg 1505 00000704 8EC7 mov es,di 1506 00000706 BE0062 mov si,AppendBuf 1507 00000709 BF0080 mov di,cmd_line_here 1508 0000070C 8B0E[9614] mov cx,[AppendLen] 1509 00000710 F3A4 rep movsb 1510 00000712 893E[9C14] mov [CmdLinePtr],di 1511 00000716 5F pop di 1512 00000717 5E pop si 1513 00000718 07 pop es 1514 ; 1515 ; Find the kernel on disk 1516 ; 1517 00000719 BE0A65 get_kernel: mov si,KernelName 1518 0000071C BF2065 mov di,KernelCName 1519 0000071F E88909 call unmangle_name ; Get human form 1520 00000722 81EF2065 sub di,KernelCName 1521 00000726 893EEE64 mov [KernelCNameLen],di 1522 0000072A BF0A65 mov di,KernelName ; Search on disk 1523 0000072D E83305 call searchdir 1524 00000730 7553 jnz kernel_good 1525 00000732 BE[5211] bad_kernel: mov si,err_notfound ; Complain about missing kernel 1526 00000735 E819FA call writestr 1527 00000738 BE2065 mov si,KernelCName 1528 0000073B E813FA call writestr 1529 0000073E BE[1C02] mov si,crlf 1530 00000741 E90A05 jmp abort_load ; Ask user for clue 1531 ; 1532 ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0" 1533 ; 1534 00000744 BE0A65 bad_implicit: mov si,KernelName ; For the error message 1535 00000747 BF2065 mov di,KernelCName 1536 0000074A E85E09 call unmangle_name 1537 0000074D EBE3 jmp short bad_kernel 1538 ; 1539 ; vk_found: We *are* using a "virtual kernel" 1540 ; 1541 0000074F 61 vk_found: popa 1542 00000750 57 push di 1543 00000751 BF0060 mov di,VKernelBuf 1544 00000754 B98000 mov cx,vk_size >> 2 1545 00000757 F366A5 rep movsd 1546 0000075A 06 push es ; Restore old DS 1547 0000075B 1F pop ds 1548 0000075C 06 push es 1549 0000075D 680090 push word real_mode_seg 1550 00000760 07 pop es 1551 00000761 BF0080 mov di,cmd_line_here 1552 00000764 BE1860 mov si,VKernelBuf+vk_append 1553 00000767 8B0E1660 mov cx,[VKernelBuf+vk_appendlen] 1554 0000076B F3A4 rep movsb 1555 0000076D 893E[9C14] mov [CmdLinePtr],di ; Where to add rest of cmd 1556 00000771 07 pop es 1557 00000772 5F pop di ; DI -> KernelName 1558 00000773 57 push di 1559 00000774 BE0B60 mov si,VKernelBuf+vk_rname 1560 00000777 B90B00 mov cx,11 1561 0000077A F3A4 rep movsb 1562 0000077C 5F pop di 1563 0000077D EB9A jmp short get_kernel 1564 ; 1565 ; kernel_corrupt: Called if the kernel file does not seem healthy 1566 ; 1567 0000077F BE[7011] kernel_corrupt: mov si,err_notkernel 1568 00000782 E9C904 jmp abort_load 1569 kernel_good: 1570 ; 1571 ; This is it! We have a name (and location on the disk)... let's load 1572 ; that sucker!! 1573 ; 1574 ; A Linux kernel consists of three parts: boot sector, setup code, and 1575 ; kernel code. The boot sector is never executed when using an external 1576 ; booting utility, but it contains some status bytes that are necessary. 1577 ; The boot sector and setup code together form exactly 5 sectors that 1578 ; should be loaded at 9000:0. The subsequent code should be loaded 1579 ; at 1000:0. For simplicity, we load the whole thing at 0F60:0, and 1580 ; copy the latter stuff afterwards. 1581 ; 1582 ; NOTE: In the previous code I have avoided making any assumptions regarding 1583 ; the size of a sector, in case this concept ever gets extended to other 1584 ; media like CD-ROM (not that a CD-ROM would be bloody likely to use a FAT 1585 ; filesystem, of course). However, a "sector" when it comes to Linux booting 1586 ; stuff means 512 bytes *no matter what*, so here I am using that piece 1587 ; of knowledge. 1588 ; 1589 ; First check that our kernel is at least 64K and less than 8M (if it is 1590 ; more than 8M, we need to change the logic for loading it anyway...) 1591 ; 1592 load_it: 1593 00000785 81FA8000 cmp dx,80h ; 8 megs 1594 00000789 77F4 ja kernel_corrupt 1595 0000078B 21D2 and dx,dx 1596 0000078D 74F0 jz kernel_corrupt 1597 0000078F 50 kernel_sane: push ax 1598 00000790 52 push dx 1599 00000791 56 push si 1600 00000792 BE[4214] mov si,loading_msg 1601 00000795 E84F03 call cwritestr 1602 ; 1603 ; Now start transferring the kernel 1604 ; 1605 00000798 680090 push word real_mode_seg 1606 0000079B 07 pop es 1607 1608 0000079C 50 push ax 1609 0000079D 52 push dx 1610 0000079E F736CE64 div word [ClustSize] ; # of clusters total 1611 000007A2 21D2 and dx,dx ; Round up 1612 000007A4 0F95C2 setnz dl 1613 000007A7 0FB6D2 movzx dx,dl 1614 000007AA 01D0 add ax,dx 1615 000007AC A3DE64 mov [KernelClust],ax 1616 000007AF 5A pop dx 1617 000007B0 58 pop ax 1618 000007B1 05FF03 add ax,1023 1619 000007B4 83D200 adc dx,byte 0 1620 000007B7 BB0004 mov bx,1024 1621 000007BA F7F3 div bx ; Get number of kilobytes 1622 000007BC A3E064 mov [KernelK],ax 1623 ; 1624 ; Now, if we transfer these straight, we'll hit 64K boundaries. Hence we 1625 ; have to see if we're loading more than 64K, and if so, load it step by 1626 ; step. 1627 ; 1628 000007BF BA0100 mov dx,1 ; 10000h 1629 000007C2 31C0 xor ax,ax 1630 000007C4 F736CE64 div word [ClustSize] 1631 000007C8 A3E464 mov [ClustPerMoby],ax ; Clusters/64K 1632 ; 1633 ; Start by loading the bootsector/setup code, to see if we need to 1634 ; do something funky. It should fit in the first 32K (loading 64K won't 1635 ; work since we might have funny stuff up near the end of memory). 1636 ; If we have larger than 32K clusters, yes, we're hosed. 1637 ; 1638 000007CB E86604 call abort_check ; Check for abort key 1639 000007CE 8B0EE464 mov cx,[ClustPerMoby] 1640 000007D2 D1E9 shr cx,1 ; Half a moby 1641 000007D4 290EDE64 sub [KernelClust],cx 1642 000007D8 31DB xor bx,bx 1643 000007DA 5E pop si ; Cluster pointer on stack 1644 000007DB E843FB call getfssec 1645 000007DE 729F jc kernel_corrupt ; Failure in first 32K 1646 000007E0 26813EFE0155AA cmp word [es:bs_bootsign],0AA55h 1647 000007E7 7596 jne kernel_corrupt ; Boot sec signature missing 1648 ; 1649 ; Get the BIOS' idea of what the size of high memory is 1650 ; 1651 000007E9 56 push si ; Save our cluster pointer! 1652 000007EA B488 mov ah,88h 1653 000007EC CD15 int 15h 1654 000007EE 3D0038 cmp ax,14*1024 ; Don't trust memory >15M 1655 000007F1 7603 jna hms_ok 1656 000007F3 B80038 mov ax,14*1024 1657 000007F6 A3DC64 hms_ok: mov [HighMemSize],ax 1658 ; 1659 ; Construct the command line (append options have already been copied) 1660 ; 1661 000007F9 26C70620003FA3 mov word [es:kern_cmd_magic],0A33Fh ; Command line magic no 1662 00000800 26C70622000080 mov word [es:kern_cmd_offset],cmd_line_here 1663 00000807 8B3E[9C14] mov di,[CmdLinePtr] 1664 0000080B BE[B114] mov si,boot_image ; BOOT_IMAGE= 1665 0000080E B90B00 mov cx,boot_image_len 1666 00000811 F3A4 rep movsb 1667 00000813 BE2065 mov si,KernelCName ; Unmangled kernel name 1668 00000816 8B0EEE64 mov cx,[KernelCNameLen] 1669 0000081A F3A4 rep movsb 1670 0000081C B020 mov al,' ' ; Space 1671 0000081E AA stosb 1672 0000081F 8B36EC64 mov si,[CmdOptPtr] ; Options from user input 1673 00000823 B98100 mov cx,(kern_cmd_len+3) >> 2 1674 00000826 F366A5 rep movsd 1675 ; 1676 %ifdef debug 1677 push ds ; DEBUG DEBUG DEBUG 1678 push es 1679 pop ds 1680 mov si,offset cmd_line_here 1681 call cwritestr 1682 pop ds 1683 mov si,offset crlf 1684 call cwritestr 1685 %endif 1686 ; 1687 ; Scan through the command line for anything that looks like we might be 1688 ; interested in. The original version of this code automatically assumed 1689 ; the first option was BOOT_IMAGE=, but that is no longer certain. 1690 ; 1691 00000829 BE0080 mov si,cmd_line_here 1692 0000082C C606[9E14]00 mov byte [initrd_flag],0 1693 00000831 06 push es ; Set DS <- real_mode_seg 1694 00000832 1F pop ds 1695 00000833 AC get_next_opt: lodsb 1696 00000834 20C0 and al,al 1697 00000836 0F84A000 jz near cmdline_end 1698 0000083A 3C20 cmp al,' ' 1699 0000083C 76F5 jbe get_next_opt 1700 0000083E 4E dec si 1701 0000083F 668B04 mov eax,[si] 1702 00000842 663D7667613D cmp eax,'vga=' 1703 00000848 7432 je is_vga_cmd 1704 0000084A 663D6D656D3D cmp eax,'mem=' 1705 00000850 7462 je is_mem_cmd 1706 00000852 06 push es ; Save ES -> real_mode_seg 1707 00000853 16 push ss 1708 00000854 07 pop es ; Set ES <- normal DS 1709 00000855 BF[6514] mov di,initrd_cmd 1710 00000858 B90700 mov cx,initrd_cmd_len 1711 0000085B F3A6 repe cmpsb 1712 0000085D 7514 jne not_initrd 1713 0000085F BF1565 mov di,InitRD 1714 00000862 56 push si ; mangle_dir mangles si 1715 00000863 E8E907 call mangle_name ; Mangle ramdisk name 1716 00000866 5E pop si 1717 00000867 26803E156520 cmp byte [es:InitRD],' ' ; Null filename? 1718 0000086D 260F9706[9E14] seta byte [es:initrd_flag] ; Set flag if not 1719 00000873 07 not_initrd: pop es ; Restore ES -> real_mode_seg 1720 00000874 AC skip_this_opt: lodsb ; Load from command line 1721 00000875 3C20 cmp al,' ' 1722 00000877 77FB ja skip_this_opt 1723 00000879 4E dec si 1724 0000087A EBB7 jmp short get_next_opt 1725 is_vga_cmd: 1726 0000087C 83C604 add si,byte 4 1727 0000087F 668B04 mov eax,[si] 1728 00000882 BBFFFF mov bx,-1 1729 00000885 663D6E6F726D cmp eax, 'norm' ; vga=normal 1730 0000088B 7421 je vc0 1731 0000088D 6625FFFFFF00 and eax,0ffffffh ; 3 bytes 1732 00000893 BBFEFF mov bx,-2 1733 00000896 663D65787400 cmp eax, 'ext' ; vga=ext 1734 0000089C 7410 je vc0 1735 0000089E BBFDFF mov bx,-3 1736 000008A1 663D61736B00 cmp eax, 'ask' ; vga=ask 1737 000008A7 7405 je vc0 1738 000008A9 E8CF06 call parseint ; vga= 1739 000008AC 72C6 jc skip_this_opt ; Not an integer 1740 000008AE 891EFA01 vc0: mov [bs_vidmode],bx ; Set video mode 1741 000008B2 EBC0 jmp short skip_this_opt 1742 is_mem_cmd: 1743 000008B4 83C604 add si,byte 4 1744 000008B7 E8C106 call parseint 1745 000008BA 72B8 jc skip_this_opt ; Not an integer 1746 000008BC 66C1EB0A shr ebx,10 ; Convert to kilobytes 1747 000008C0 6681EB00040000 sub ebx,1024 ; Don't count first meg 1748 000008C7 6681FB00380000 cmp ebx,14*1024 ; Only trust < 15M point 1749 000008CE 7603 jna memcmd_fair 1750 000008D0 BB0038 mov bx,14*1024 1751 000008D3 36891EDC64 memcmd_fair: mov [ss:HighMemSize],bx 1752 000008D8 EB9A jmp short skip_this_opt 1753 cmdline_end: 1754 000008DA 16 push ss ; Restore standard DS 1755 000008DB 1F pop ds 1756 ; 1757 ; Now check if we have a large kernel, which needs to be loaded high 1758 ; 1759 000008DC 2666813E0202486472- cmp dword [es:su_header],HEADER_ID ; New setup code ID 1760 000008E5 53 1761 000008E6 0F85E201 jne near old_kernel ; Old kernel, load low 1762 000008EA 26813E06020002 cmp word [es:su_version],0200h ; Setup code version 2.0 1763 000008F1 0F82D701 jb near old_kernel ; Old kernel, load low 1764 000008F5 26813E06020102 cmp word [es:su_version],0201h ; Version 2.01+? 1765 000008FC 720D jb new_kernel ; If 2.00, skip this step 1766 000008FE 26C7062402F47F mov word [es:su_heapend],linux_stack ; Set up the heap 1767 00000905 26800E110280 or byte [es:su_loadflags],80h ; Let the kernel know we care 1768 ; 1769 ; We definitely have a new-style kernel. Let the kernel know who we are, 1770 ; and that we are clueful 1771 ; 1772 new_kernel: 1773 0000090B 26C606100231 mov byte [es:su_loader],syslinux_id ; Show some ID 1774 00000911 260FB606F101 movzx ax,byte [es:bs_setupsecs] ; Variable # of setup sectors 1775 00000917 A3F464 mov [SetupSecs],ax 1776 ; 1777 ; Now see if we have an initial RAMdisk; if so, do requisite computation 1778 ; 1779 0000091A F606[9E14]01 test byte [initrd_flag],1 1780 0000091F 7476 jz nk_noinitrd 1781 00000921 06 push es ; ES->real_mode_seg 1782 00000922 1E push ds 1783 00000923 07 pop es ; We need ES==DS 1784 00000924 BE1565 mov si,InitRD 1785 00000927 BF2D65 mov di,InitRDCName 1786 0000092A E87E07 call unmangle_name ; Create human-readable name 1787 0000092D 81EF2D65 sub di,InitRDCName 1788 00000931 893EF064 mov [InitRDCNameLen],di 1789 00000935 BF1565 mov di,InitRD 1790 00000938 E82803 call searchdir ; Look for it in directory 1791 0000093B 07 pop es 1792 0000093C 7441 jz initrd_notthere 1793 0000093E 8936[9E14] mov [initrd_ptr],si ; Save cluster pointer 1794 00000942 26A31C02 mov [es:su_ramdisklen1],ax ; Ram disk length 1795 00000946 2689161E02 mov [es:su_ramdisklen2],dx 1796 0000094B F736CE64 div word [ClustSize] 1797 0000094F 21D2 and dx,dx ; Round up 1798 00000951 0F95C2 setnz dl 1799 00000954 0FB6D2 movzx dx,dl 1800 00000957 01D0 add ax,dx 1801 00000959 A3E264 mov [InitRDClust],ax ; Ramdisk clusters 1802 0000095C 660FB716DC64 movzx edx,word [HighMemSize] ; End of memory 1803 00000962 6681C200040000 add edx,1024 ; Add "low" memory 1804 00000969 66C1E20A shl edx,10 ; Convert to bytes 1805 0000096D 26662B161C02 sub edx,[es:su_ramdisklen] ; Subtract size of ramdisk 1806 00000973 31D2 xor dx,dx ; Round down to 64K boundary 1807 00000975 668916B064 mov [InitRDat],edx ; Load address 1808 0000097A E83802 call loadinitrd ; Load initial ramdisk 1809 0000097D EB18 jmp short initrd_end 1810 1811 initrd_notthere: 1812 0000097F BE[A413] mov si,err_noinitrd 1813 00000982 E8CCF7 call writestr 1814 00000985 BE2D65 mov si,InitRDCName 1815 00000988 E8C6F7 call writestr 1816 0000098B BE[1C02] mov si,crlf 1817 0000098E E9BD02 jmp abort_load 1818 1819 00000991 BE[C513] no_high_mem: mov si,err_nohighmem ; Error routine 1820 00000994 E9B702 jmp abort_load 1821 ; 1822 ; About to load the kernel. This is a modern kernel, so use the boot flags 1823 ; we were provided. 1824 ; 1825 nk_noinitrd: 1826 initrd_end: 1827 00000997 26A01102 mov al,[es:su_loadflags] 1828 0000099B A2FE64 mov [LoadFlags],al 1829 ; 1830 ; Load the kernel. We always load it at 100000h even if we're supposed to 1831 ; load it "low"; for a "low" load we copy it down to low memory right before 1832 ; jumping to it. 1833 ; 1834 read_kernel: 1835 0000099E BE2065 mov si,KernelCName ; Print kernel name part of 1836 000009A1 E84301 call cwritestr ; "Loading" message 1837 000009A4 BE[4B14] mov si,dotdot_msg ; Print dots 1838 000009A7 E83D01 call cwritestr 1839 1840 000009AA A1DC64 mov ax,[HighMemSize] 1841 000009AD 3B06E064 cmp ax,[KernelK] 1842 000009B1 72DE jb no_high_mem ; Not enough high memory 1843 ; 1844 ; Move the stuff beyond the setup code to high memory at 100000h 1845 ; 1846 000009B3 660FB736F464 movzx esi,word [SetupSecs] ; Setup sectors 1847 000009B9 6646 inc esi ; plus 1 boot sector 1848 000009BB 66C1E609 shl esi,9 ; Convert to bytes 1849 000009BF 66B900801000 mov ecx,108000h ; 108000h = 1M + 32K 1850 000009C5 6629F1 sub ecx,esi ; Adjust pointer to 2nd block 1851 000009C8 66890EB464 mov [HiLoadAddr],ecx 1852 000009CD 6681E900001000 sub ecx,100000h ; Turn into a counter 1853 000009D4 66C1E902 shr ecx,2 ; Convert to dwords 1854 000009D8 6681C600000900 add esi,90000h ; Pointer to source 1855 000009DF 66BF00001000 mov edi,100000h ; Copy to address 100000h 1856 000009E5 E83801 call bcopy ; Transfer to high memory 1857 ; 1858 000009E8 680070 push word xfer_buf_seg ; Segment 7000h is xfer buffer 1859 000009EB 07 pop es 1860 high_load_loop: 1861 000009EC BE[4C14] mov si,dot_msg ; Progress report 1862 000009EF E8F500 call cwritestr 1863 000009F2 E83F02 call abort_check 1864 000009F5 8B0EDE64 mov cx,[KernelClust] 1865 000009F9 3B0EE464 cmp cx,[ClustPerMoby] 1866 000009FD 7604 jna high_last_moby 1867 000009FF 8B0EE464 mov cx,[ClustPerMoby] 1868 high_last_moby: 1869 00000A03 290EDE64 sub [KernelClust],cx 1870 00000A07 31DB xor bx,bx ; Load at offset 0 1871 00000A09 5E pop si ; Restore cluster pointer 1872 00000A0A E814F9 call getfssec 1873 00000A0D 56 push si ; Save cluster pointer 1874 00000A0E 9C pushf ; Save EOF 1875 00000A0F 31DB xor bx,bx 1876 00000A11 66BE00000700 mov esi,(xfer_buf_seg << 4) 1877 00000A17 668B3EB464 mov edi,[HiLoadAddr] ; Destination address 1878 00000A1C 66B900400000 mov ecx,4000h ; Cheating - transfer 64K 1879 00000A22 E8FB00 call bcopy ; Transfer to high memory 1880 00000A25 66893EB464 mov [HiLoadAddr],edi ; Point to next target area 1881 00000A2A 9D popf ; Restore EOF 1882 00000A2B 7207 jc high_load_done ; If EOF we are done 1883 00000A2D 833EDE6400 cmp word [KernelClust],byte 0 ; Are we done? 1884 00000A32 75B8 jne high_load_loop ; Apparently not 1885 high_load_done: 1886 00000A34 5E pop si ; No longer needed 1887 00000A35 B80090 mov ax,real_mode_seg ; Set to real mode seg 1888 00000A38 8EC0 mov es,ax 1889 1890 00000A3A BE[4C14] mov si,dot_msg 1891 00000A3D E8A700 call cwritestr 1892 ; 1893 ; Abandon hope, ye that enter here! We do no longer permit aborts. 1894 ; 1895 00000A40 E8F101 call abort_check ; Last chance!! 1896 1897 ; 1898 ; Some kernels in the 1.2 ballpark but pre-bzImage have more than 4 1899 ; setup sectors, but the boot protocol had not yet been defined. They 1900 ; rely on a signature to figure out if they need to copy stuff from 1901 ; the "protected mode" kernel area. Unfortunately, we used that area 1902 ; as a transfer buffer, so it's going to find the signature there. 1903 ; Hence, zero the low 32K beyond the setup area. 1904 ; 1905 00000A43 8B3EF464 mov di,[SetupSecs] 1906 00000A47 47 inc di ; Setup + boot sector 1907 00000A48 B94000 mov cx,32768/512 ; Sectors/32K 1908 00000A4B 29F9 sub cx,di ; Remaining sectors 1909 00000A4D C1E709 shl di,9 ; Sectors -> bytes 1910 00000A50 C1E107 shl cx,7 ; Sectors -> dwords 1911 00000A53 6631C0 xor eax,eax 1912 00000A56 F366AB rep stosd ; Clear region 1913 ; 1914 ; Now, if we were supposed to load "low", copy the kernel down to 10000h 1915 ; 1916 00000A59 F606FE6401 test byte [LoadFlags],LOAD_HIGH 1917 00000A5E 7519 jnz in_proper_place ; If high load, we're done 1918 1919 00000A60 660FB70EE064 movzx ecx,word [KernelK] 1920 00000A66 66C1E108 shl ecx,8 ; K -> dword 1921 00000A6A 66BE00001000 mov esi,100000h 1922 00000A70 66BF00000100 mov edi,10000h 1923 00000A76 E8A700 call bcopy 1924 in_proper_place: 1925 ; 1926 ; If the default root device is set to FLOPPY (0000h), change to 1927 ; /dev/fd0 (0200h) 1928 ; 1929 00000A79 26833EFC0100 cmp word [es:bs_rootdev],byte 0 1930 00000A7F 7507 jne root_not_floppy 1931 00000A81 26C706FC010002 mov word [es:bs_rootdev],0200h 1932 root_not_floppy: 1933 ; 1934 ; Copy the disk table to high memory, then re-initialize the floppy 1935 ; controller 1936 ; 1937 00000A88 1E push ds 1938 00000A89 C5367800 lds si,[fdctab] 1939 00000A8D BFF47F mov di,linux_fdctab 1940 00000A90 B90300 mov cx,3 ; 12 bytes 1941 00000A93 57 push di 1942 00000A94 F366A5 rep movsd 1943 00000A97 5F pop di 1944 00000A98 FA cli 1945 00000A99 893E7800 mov [fdctab1],di ; Save new floppy tab pos 1946 00000A9D 8C067A00 mov [fdctab2],es 1947 00000AA1 FB sti 1948 00000AA2 31C0 xor ax,ax 1949 00000AA4 31D2 xor dx,dx 1950 00000AA6 CD13 int 13h 1951 00000AA8 1F pop ds 1952 ; 1953 ; Linux wants the floppy motor shut off before starting the kernel, 1954 ; at least bootsect.S seems to imply so 1955 ; 1956 kill_motor: 1957 00000AA9 BAF203 mov dx,03F2h 1958 00000AAC 30C0 xor al,al 1959 00000AAE EE out dx,al 1960 ; 1961 ; Now we're as close to be done as we can be and still use our normal 1962 ; routines, print a CRLF to end the row of dots 1963 ; 1964 00000AAF BE[1C02] mov si,crlf 1965 00000AB2 E89CF6 call writestr 1966 ; 1967 ; If we're debugging, wait for a keypress so we can read any debug messages 1968 ; 1969 %ifdef debug 1970 xor ax,ax 1971 int 16h 1972 %endif 1973 ; 1974 ; Set up segment registers and the Linux real-mode stack 1975 ; 1976 00000AB5 B80090 mov ax,real_mode_seg 1977 00000AB8 8ED8 mov ds,ax 1978 00000ABA 8EC0 mov es,ax 1979 00000ABC 8EE0 mov fs,ax 1980 00000ABE 8EE8 mov gs,ax 1981 00000AC0 FA cli 1982 00000AC1 8ED0 mov ss,ax 1983 00000AC3 BCF47F mov sp,linux_stack 1984 00000AC6 FB sti 1985 ; 1986 ; We're done... now RUN THAT KERNEL!!!! 1987 ; 1988 00000AC7 EA00002090 jmp setup_seg:setup_entry 1989 ; 1990 ; Load an older kernel. Older kernels always have 4 setup sectors, can't have 1991 ; initrd, and are always loaded low. 1992 ; 1993 old_kernel: 1994 00000ACC F606[9E14]01 test byte [initrd_flag],1 ; Old kernel can't have initrd 1995 00000AD1 7406 jz load_old_kernel 1996 00000AD3 BE[1014] mov si,err_oldkernel 1997 00000AD6 E97501 jmp abort_load 1998 load_old_kernel: 1999 00000AD9 C706F4640400 mov word [SetupSecs],4 ; Always 4 setup sectors 2000 00000ADF C606FE6400 mov byte [LoadFlags],0 ; Always low 2001 00000AE4 E9B7FE jmp read_kernel 2002 ; 2003 ; cwritestr: write a null-terminated string to the console, saving 2004 ; registers on entry (we can't use this in the boot sector, 2005 ; since we haven't verified 386-ness yet) 2006 ; 2007 cwritestr: 2008 00000AE7 60 pusha 2009 00000AE8 AC cwstr_1: lodsb 2010 00000AE9 20C0 and al,al 2011 00000AEB 7409 jz cwstr_2 2012 00000AED B40E mov ah,0Eh ; Write to screen as TTY 2013 00000AEF BB0700 mov bx,0007h ; White on black, current page 2014 00000AF2 CD10 int 10h 2015 00000AF4 EBF2 jmp short cwstr_1 2016 00000AF6 61 cwstr_2: popa 2017 00000AF7 C3 ret 2018 2019 ; 2020 ; 32-bit bcopy routine for real mode 2021 ; 2022 ; We enter protected mode, set up a flat 32-bit environment, run rep movsd 2023 ; and then exit. IMPORTANT: This code assumes cs == ss == 0. 2024 ; 2025 ; This code is probably excessively anal-retentive in its handling of 2026 ; segments, but this stuff is painful enough as it is without having to rely 2027 ; on everything happening "as it ought to." 2028 ; 2029 align 2 2030 00000AF8 1F00 bcopy_gdt_ptr: dw bcopy_gdt_size-1 2031 00000AFA [000B0000] dd bcopy_gdt 2032 2033 00000AFE 90 align 4 2034 00000B00 00000000 bcopy_gdt: dd 0 ; Null descriptor 2035 00000B04 00000000 dd 0 2036 00000B08 FFFF0000 dd 0000ffffh ; Code segment, use16, readable, 2037 00000B0C 009B0000 dd 00009b00h ; present, dpl 0, cover 64K 2038 00000B10 FFFF0000 dd 0000ffffh ; Data segment, use16, read/write, 2039 00000B14 00938F00 dd 008f9300h ; present, dpl 0, cover all 4G 2040 00000B18 FFFF0000 dd 0000ffffh ; Data segment, use16, read/write, 2041 00000B1C 00930000 dd 00009300h ; present, dpl 0, cover 64K 2042 bcopy_gdt_size: equ $-bcopy_gdt 2043 2044 bcopy: 2045 00000B20 6650 push eax 2046 00000B22 9C pushf ; Saves, among others, the IF flag 2047 00000B23 0FA8 push gs 2048 00000B25 0FA0 push fs 2049 00000B27 1E push ds 2050 00000B28 06 push es 2051 2052 00000B29 FA cli 2053 00000B2A E84800 call enable_a20 2054 2055 00000B2D 660F0116[F80A] o32 lgdt [bcopy_gdt_ptr] 2056 00000B33 0F20C0 mov eax,cr0 2057 00000B36 0C01 or al,1 2058 00000B38 0F22C0 mov cr0,eax ; Enter protected mode 2059 00000B3B EA[400B]0800 jmp 8:.in_pm 2060 2061 00000B40 B81000 .in_pm: mov ax,16 ; Data segment selector 2062 00000B43 8EC0 mov es,ax 2063 00000B45 8ED8 mov ds,ax 2064 2065 00000B47 B018 mov al,24 ; "Real-mode-like" data segment 2066 00000B49 8ED0 mov ss,ax 2067 00000B4B 8EE0 mov fs,ax 2068 00000B4D 8EE8 mov gs,ax 2069 2070 00000B4F 67F366A5 a32 rep movsd ; Do our business 2071 2072 00000B53 8EC0 mov es,ax ; Set to "real-mode-like" 2073 00000B55 8ED8 mov ds,ax 2074 2075 00000B57 0F20C0 mov eax,cr0 2076 00000B5A 24FE and al,0feh 2077 00000B5C 0F22C0 mov cr0,eax ; Disable protected mode 2078 00000B5F EA[640B]0000 jmp 0:.in_rm 2079 2080 00000B64 31C0 .in_rm: xor ax,ax ; Back in real mode 2081 00000B66 8ED0 mov ss,ax 2082 00000B68 07 pop es 2083 00000B69 1F pop ds 2084 00000B6A 0FA1 pop fs 2085 00000B6C 0FA9 pop gs 2086 00000B6E E81F00 call disable_a20 2087 2088 00000B71 9D popf ; Re-enables interrupts 2089 00000B72 6658 pop eax 2090 00000B74 C3 ret 2091 2092 ; 2093 ; Routines to enable and disable (yuck) A20 2094 ; These routines are largely cut-and-paste from the Linux setup code 2095 ; 2096 %define io_delay out 080h, ax ; Invalid port (we hope) 2097 2098 enable_a20: 2099 00000B75 E82800 call empty_8042 2100 00000B78 B0D1 mov al,0D1h ; Command write 2101 00000B7A E664 out 064h, al 2102 00000B7C E82100 call empty_8042 2103 00000B7F B0DF mov al,0DFh ; A20 on 2104 00000B81 E660 out 060h, al 2105 00000B83 E81A00 kbc_delay: call empty_8042 2106 00000B86 51 push cx 2107 00000B87 B90010 mov cx,1000h 2108 00000B8A E780 .delayloop: io_delay 2109 00000B8C E2FC loop .delayloop 2110 00000B8E 59 pop cx 2111 00000B8F C3 ret 2112 2113 disable_a20: 2114 00000B90 E80D00 call empty_8042 2115 00000B93 B0D1 mov al,0D1h 2116 00000B95 E664 out 064h, al ; Command write 2117 00000B97 E80600 call empty_8042 2118 00000B9A B0DD mov al,0DDh ; A20 off 2119 00000B9C E660 out 060h, al 2120 00000B9E EBE3 jmp short kbc_delay 2121 2122 empty_8042: 2123 00000BA0 E780 io_delay 2124 00000BA2 E464 in al, 064h ; Status port 2125 00000BA4 A801 test al,1 2126 00000BA6 7406 jz .no_output 2127 00000BA8 E780 io_delay 2128 00000BAA E460 in al, 060h ; Read input 2129 00000BAC EBF2 jmp short empty_8042 2130 .no_output: 2131 00000BAE A802 test al,2 2132 00000BB0 75EE jnz empty_8042 2133 00000BB2 E780 io_delay 2134 00000BB4 C3 ret 2135 2136 ; 2137 ; Load RAM disk into high memory 2138 ; 2139 loadinitrd: 2140 00000BB5 06 push es ; Save ES on entry 2141 00000BB6 B80090 mov ax,real_mode_seg 2142 00000BB9 8EC0 mov es,ax 2143 00000BBB 8B36[9E14] mov si,[initrd_ptr] 2144 00000BBF 668B3EB064 mov edi,[InitRDat] ; initrd load address 2145 00000BC4 2666893E1802 mov [es:su_ramdiskat],edi ; Offset for ram disk 2146 00000BCA 56 push si 2147 00000BCB BE2D65 mov si,InitRDCName ; Write ramdisk name 2148 00000BCE E816FF call cwritestr 2149 00000BD1 BE[4B14] mov si,dotdot_msg ; Write dots 2150 00000BD4 E810FF call cwritestr 2151 rd_load_loop: 2152 00000BD7 BE[4C14] mov si,dot_msg ; Progress report 2153 00000BDA E80AFF call cwritestr 2154 00000BDD 5E pop si ; Restore cluster pointer 2155 00000BDE E85300 call abort_check 2156 00000BE1 8B0EE264 mov cx,[InitRDClust] 2157 00000BE5 3B0EE464 cmp cx,[ClustPerMoby] 2158 00000BE9 7604 jna rd_last_moby 2159 00000BEB 8B0EE464 mov cx,[ClustPerMoby] 2160 rd_last_moby: 2161 00000BEF 290EE264 sub [InitRDClust],cx 2162 00000BF3 31DB xor bx,bx ; Load at offset 0 2163 00000BF5 680070 push word xfer_buf_seg ; Bounce buffer segment 2164 00000BF8 07 pop es 2165 00000BF9 51 push cx 2166 00000BFA E824F7 call getfssec 2167 00000BFD 59 pop cx 2168 00000BFE 56 push si ; Save cluster pointer 2169 00000BFF 66BE00000700 mov esi,(xfer_buf_seg << 4) 2170 00000C05 668B3EB064 mov edi,[InitRDat] 2171 00000C0A 66B900400000 mov ecx,4000h ; Copy 64K 2172 00000C10 E80DFF call bcopy ; Does not change flags!! 2173 00000C13 7210 jc rd_load_done ; EOF? 2174 00000C15 668106B06400000100 add dword [InitRDat],10000h ; Point to next 64K 2175 00000C1E 833EE26400 cmp word [InitRDClust],byte 0 ; Are we done? 2176 00000C23 75B2 jne rd_load_loop ; Apparently not 2177 rd_load_done: 2178 00000C25 5E pop si ; Clean up the stack 2179 00000C26 BE[5714] mov si,crlf_msg 2180 00000C29 E825F5 call writestr 2181 00000C2C BE[4214] mov si,loading_msg ; Write new "Loading " for 2182 00000C2F E81FF5 call writestr ; the benefit of the kernel 2183 00000C32 07 pop es ; Restore original ES 2184 00000C33 C3 ret 2185 2186 ; 2187 ; abort_check: let the user abort with or 2188 ; 2189 abort_check: 2190 00000C34 60 pusha 2191 ac1: 2192 00000C35 B401 mov ah,1 ; Check for pending keystroke 2193 00000C37 CD16 int 16h 2194 00000C39 7426 jz ac_ret ; If no pending keystroke 2195 00000C3B 31C0 xor ax,ax ; Load pending keystroke 2196 00000C3D CD16 int 16h 2197 00000C3F BB0063 mov bx,KbdMap 2198 00000C42 D7 xlatb 2199 00000C43 3C1B cmp al,27 ; aborts (DOS geeks) 2200 00000C45 7404 je ac2 2201 00000C47 3C03 cmp al,3 ; So does Ctrl-C (UNIX geeks) 2202 00000C49 75EA jne ac1 ; Unknown key... try again 2203 ac2: ; If we get here, ABORT! 2204 00000C4B BE[4E14] mov si,aborted_msg 2205 ; Fall through to abort_load 2206 ; 2207 ; abort_load: Called by various routines which wants to print a fatal 2208 ; error message and return to the command prompt. Since this 2209 ; may happen at just about any stage of the boot process, assume 2210 ; our state is messed up, and just reset the segment registers 2211 ; and the stack forcibly. 2212 ; 2213 ; SI = offset (in _text) of error message to print 2214 ; 2215 abort_load: 2216 00000C4E 8CC8 mov ax,cs ; Restore CS = DS = ES 2217 00000C50 8ED8 mov ds,ax 2218 00000C52 8EC0 mov es,ax 2219 00000C54 FA cli 2220 00000C55 BCFA5F mov sp,StackBuf-2*3 ; Reset stack 2221 00000C58 8ED0 mov ss,ax ; Just in case... 2222 00000C5A FB sti 2223 00000C5B E8F3F4 call writestr ; Expects SI -> error msg 2224 00000C5E E982F9 al_ok: jmp enter_command ; Return to command prompt 2225 ; 2226 ; End of abort_check 2227 ; 2228 00000C61 61 ac_ret: popa 2229 00000C62 C3 ret 2230 2231 ; 2232 ; searchdir: Search the root directory for a pre-mangled filename in 2233 ; DS:DI. This routine is similar to the one in the boot 2234 ; sector, but is a little less Draconian when it comes to 2235 ; error handling, plus it reads the root directory in 2236 ; larger chunks than a sector at a time (which is probably 2237 ; a waste of coding effort, but I like to do things right). 2238 ; 2239 ; NOTE: This file considers finding a zero-length file an 2240 ; error. This is so we don't have to deal with that special 2241 ; case elsewhere in the program (most loops have the test 2242 ; at the end). 2243 ; 2244 ; If successful: 2245 ; ZF clear 2246 ; SI = cluster # for the first cluster 2247 ; DX:AX = file length in bytes 2248 ; If unsuccessful 2249 ; ZF set 2250 ; 2251 2252 searchdir: 2253 00000C63 A1[1100] mov ax,[bsRootDirEnts] 2254 00000C66 A3C664 mov [DirScanCtr],ax 2255 00000C69 A1C464 mov ax,[RootDirSize] 2256 00000C6C A3C864 mov [DirBlocksLeft],ax 2257 00000C6F A1B864 mov ax,[RootDir1] 2258 00000C72 8B16BA64 mov dx,[RootDir2] 2259 scan_group: 2260 00000C76 8B2EC864 mov bp,[DirBlocksLeft] 2261 00000C7A 21ED and bp,bp 2262 00000C7C 7467 jz dir_return 2263 00000C7E 3B2ED664 cmp bp,[BufSafeSec] 2264 00000C82 7604 jna load_last 2265 00000C84 8B2ED664 mov bp,[BufSafeSec] 2266 load_last: 2267 00000C88 292EC864 sub [DirBlocksLeft],bp 2268 00000C8C 50 push ax 2269 00000C8D 52 push dx 2270 00000C8E A1[0B00] mov ax,[bsBytesPerSec] 2271 00000C91 F7E5 mul bp 2272 00000C93 05E10F add ax,trackbuf-31 2273 00000C96 A3CA64 mov [EndofDirSec],ax ; End of loaded 2274 00000C99 5A pop dx 2275 00000C9A 58 pop ax 2276 00000C9B 55 push bp ; Save number of sectors 2277 00000C9C 50 push ax ; Save present location 2278 00000C9D 52 push dx 2279 00000C9E 57 push di ; Save name 2280 00000C9F BB0010 mov bx,trackbuf 2281 00000CA2 E8C7F4 call getlinsec 2282 00000CA5 5F pop di 2283 00000CA6 5A pop dx 2284 00000CA7 58 pop ax 2285 00000CA8 5D pop bp 2286 00000CA9 BE0010 mov si,trackbuf 2287 00000CAC 803C00 dir_test_name: cmp byte [si],0 ; Directory high water mark 2288 00000CAF 7434 je dir_return ; Failed 2289 00000CB1 F6440B18 test byte [si+11],018h ; Check it really is a file 2290 00000CB5 750B jnz dir_not_this 2291 00000CB7 57 push di 2292 00000CB8 56 push si 2293 00000CB9 B90B00 mov cx,11 ; Filename = 11 bytes 2294 00000CBC F3A6 repe cmpsb 2295 00000CBE 5E pop si 2296 00000CBF 5F pop di 2297 00000CC0 7416 je dir_success 2298 00000CC2 83C620 dir_not_this: add si,byte 32 2299 00000CC5 FF0EC664 dec word [DirScanCtr] 2300 00000CC9 741A jz dir_return ; Out of it... 2301 00000CCB 3B36CA64 cmp si,[EndofDirSec] 2302 00000CCF 72DB jb dir_test_name 2303 00000CD1 01E8 add ax,bp ; Increment linear sector number 2304 00000CD3 83D200 adc dx,byte 0 2305 00000CD6 EB9E jmp short scan_group 2306 dir_success: 2307 00000CD8 8B441C mov ax,[si+28] ; Length of file 2308 00000CDB 8B541E mov dx,[si+30] 2309 00000CDE 8B741A mov si,[si+26] ; Cluster pointer 2310 00000CE1 89C3 mov bx,ax 2311 00000CE3 09D3 or bx,dx ; Sets ZF iff DX:AX is zero 2312 dir_return: 2313 00000CE5 C3 ret 2314 2315 ; 2316 ; writechr: Write a single character in AL to the screen without 2317 ; mangling any registers 2318 ; 2319 writechr: 2320 00000CE6 60 pusha 2321 00000CE7 B40E mov ah,0Eh 2322 00000CE9 BB0700 mov bx,0007h ; white text on this page 2323 00000CEC CD10 int 10h 2324 00000CEE 61 popa 2325 00000CEF C3 ret 2326 2327 ; 2328 ; adjust_screen: Set the internal variables associated with the screen size. 2329 ; This is a subroutine in case we're loading a custom font. 2330 ; 2331 adjust_screen: 2332 00000CF0 A08404 mov al,[BIOS_vidrows] 2333 00000CF3 20C0 and al,al 2334 00000CF5 7502 jnz vidrows_is_ok 2335 00000CF7 B018 mov al,24 ; No vidrows in BIOS, assume 25 2336 ; (Remember: vidrows == rows-1) 2337 00000CF9 A2FB64 vidrows_is_ok: mov [VidRows],al 2338 00000CFC B40F mov ah,0fh 2339 00000CFE CD10 int 10h ; Read video state 2340 00000D00 883EF764 mov [TextPage],bh 2341 00000D04 FECC dec ah ; Store count-1 (same as rows) 2342 00000D06 8826FA64 mov [VidCols],ah 2343 00000D0A C3 bf_ret: ret 2344 2345 ; 2346 ; loadfont: Load a .psf font file and install it onto the VGA console 2347 ; (if we're not on a VGA screen then ignore.) It is called with 2348 ; SI and DX:AX set by routine searchdir 2349 ; 2350 loadfont: 2351 00000D0B BB0010 mov bx,trackbuf ; The trackbuf is >= 16K; the part 2352 00000D0E 8B0ED464 mov cx,[BufSafe] ; of a PSF file we care about is no 2353 00000D12 E80CF6 call getfssec ; more than 8K+4 bytes 2354 2355 00000D15 A10010 mov ax,[trackbuf] ; Magic number 2356 00000D18 3D3604 cmp ax,0436h 2357 00000D1B 75ED jne bf_ret 2358 2359 00000D1D A00210 mov al,[trackbuf+2] ; File mode 2360 00000D20 3C03 cmp al,3 ; Font modes 0-3 supported 2361 00000D22 77E6 ja bf_ret 2362 2363 00000D24 8A3E0310 mov bh,byte [trackbuf+3] ; Height of font 2364 00000D28 80FF02 cmp bh,2 ; VGA minimum 2365 00000D2B 72DD jb bf_ret 2366 00000D2D 80FF20 cmp bh,32 ; VGA maximum 2367 00000D30 77D8 ja bf_ret 2368 2369 00000D32 BD0410 mov bp,trackbuf+4 ; Address of font data 2370 00000D35 30DB xor bl,bl 2371 00000D37 B90001 mov cx,256 2372 00000D3A 31D2 xor dx,dx 2373 00000D3C B81011 mov ax,1110h 2374 00000D3F CD10 int 10h ; Load into VGA RAM 2375 2376 00000D41 30DB xor bl,bl 2377 00000D43 B80311 mov ax,1103h ; Select page 0 2378 00000D46 CD10 int 10h 2379 2380 00000D48 EBA6 jmp short adjust_screen 2381 2382 ; 2383 ; loadkeys: Load a LILO-style keymap; SI and DX:AX set by searchdir 2384 ; 2385 loadkeys: 2386 00000D4A 21D2 and dx,dx ; Should be 256 bytes exactly 2387 00000D4C 751A jne loadkeys_ret 2388 00000D4E 3D0001 cmp ax,256 2389 00000D51 7515 jne loadkeys_ret 2390 2391 00000D53 BB0010 mov bx,trackbuf 2392 00000D56 B90100 mov cx,1 ; 1 cluster should be >= 256 bytes 2393 00000D59 E8C5F5 call getfssec 2394 2395 00000D5C BE0010 mov si,trackbuf 2396 00000D5F BF0063 mov di,KbdMap 2397 00000D62 B94000 mov cx,256 >> 2 2398 00000D65 F366A5 rep movsd 2399 2400 00000D68 C3 loadkeys_ret: ret 2401 2402 ; 2403 ; get_msg_file: Load a text file and write its contents to the screen, 2404 ; interpreting color codes. Is called with SI and DX:AX 2405 ; set by routine searchdir 2406 ; 2407 get_msg_file: 2408 00000D69 C706F264[BD0D] mov word [NextCharJump],msg_putchar ; State machine for color 2409 00000D6F C606F66407 mov byte [TextAttribute],07h ; Default grey on white 2410 00000D74 60 pusha 2411 00000D75 8A3EF764 mov bh,[TextPage] 2412 00000D79 B403 mov ah,03h ; Read cursor position 2413 00000D7B CD10 int 10h 2414 00000D7D 8916F864 mov [CursorDX],dx 2415 00000D81 61 popa 2416 00000D82 50 get_msg_chunk: push ax ; DX:AX = length of file 2417 00000D83 52 push dx 2418 00000D84 BB0010 mov bx,trackbuf 2419 00000D87 8B0ED464 mov cx,[BufSafe] 2420 00000D8B E893F5 call getfssec 2421 00000D8E 5A pop dx 2422 00000D8F 58 pop ax 2423 00000D90 56 push si ; Save current cluster 2424 00000D91 BE0010 mov si,trackbuf 2425 00000D94 8B0ED864 mov cx,[BufSafeBytes] ; No more than many bytes 2426 00000D98 51 print_msg_file: push cx 2427 00000D99 50 push ax 2428 00000D9A 52 push dx 2429 00000D9B AC lodsb 2430 00000D9C 3C1A cmp al,1Ah ; ASCII EOF? 2431 00000D9E 7418 je msg_done_pop 2432 00000DA0 FF16F264 call [NextCharJump] ; Do what shall be done 2433 00000DA4 5A pop dx 2434 00000DA5 58 pop ax 2435 00000DA6 59 pop cx 2436 00000DA7 83E801 sub ax,byte 1 2437 00000DAA 83DA00 sbb dx,byte 0 2438 00000DAD 89C3 mov bx,ax 2439 00000DAF 09D3 or bx,dx 2440 00000DB1 7408 jz msg_done 2441 00000DB3 E2E3 loop print_msg_file 2442 00000DB5 5E pop si 2443 00000DB6 EBCA jmp short get_msg_chunk 2444 msg_done_pop: 2445 00000DB8 83C406 add sp,byte 6 ; Lose 3 words on the stack 2446 msg_done: 2447 00000DBB 5E pop si 2448 00000DBC C3 ret 2449 msg_putchar: ; Normal character 2450 00000DBD 3C0F cmp al,0Fh ; ^O = color code follows 2451 00000DBF 7431 je msg_ctrl_o 2452 00000DC1 3C0D cmp al,0Dh ; Ignore 2453 00000DC3 742C je msg_ignore 2454 00000DC5 3C0A cmp al,0Ah ; = newline 2455 00000DC7 7430 je msg_newline 2456 00000DC9 3C0C cmp al,0Ch ; = clear screen 2457 00000DCB 7455 je msg_formfeed 2458 00000DCD 8B1EF664 mov bx,[TextAttrBX] 2459 00000DD1 B409 mov ah,09h ; Write character/attribute 2460 00000DD3 B90100 mov cx,1 ; One character only 2461 00000DD6 CD10 int 10h ; Write to screen 2462 00000DD8 A0F864 mov al,[CursorCol] 2463 00000DDB 40 inc ax 2464 00000DDC 3A06FA64 cmp al,[VidCols] 2465 00000DE0 7717 ja msg_newline 2466 00000DE2 A2F864 mov [CursorCol],al 2467 00000DE5 8A3EF764 msg_gotoxy: mov bh,[TextPage] 2468 00000DE9 8B16F864 mov dx,[CursorDX] 2469 00000DED B402 mov ah,02h ; Set cursor position 2470 00000DEF CD10 int 10h 2471 00000DF1 C3 msg_ignore: ret 2472 msg_ctrl_o: ; ^O = color code follows 2473 00000DF2 C706F264[370E] mov word [NextCharJump],msg_setbg 2474 00000DF8 C3 ret 2475 msg_newline: ; Newline char or end of line 2476 00000DF9 C606F86400 mov byte [CursorCol],0 2477 00000DFE A0F964 mov al,[CursorRow] 2478 00000E01 40 inc ax 2479 00000E02 3A06FB64 cmp al,[VidRows] 2480 00000E06 7705 ja msg_scroll 2481 00000E08 A2F964 mov [CursorRow],al 2482 00000E0B EBD8 jmp short msg_gotoxy 2483 00000E0D 31C9 msg_scroll: xor cx,cx ; Upper left hand corner 2484 00000E0F 8B16FA64 mov dx,[ScreenSize] 2485 00000E13 8836F964 mov [CursorRow],dh ; New cursor at the bottom 2486 00000E17 8A3EF664 mov bh,[TextAttribute] 2487 00000E1B B80106 mov ax,0601h ; Scroll up one line 2488 00000E1E CD10 int 10h 2489 00000E20 EBC3 jmp short msg_gotoxy 2490 msg_formfeed: ; Form feed character 2491 00000E22 31C9 xor cx,cx 2492 00000E24 890EF864 mov [CursorDX],cx ; Upper lefthand corner 2493 00000E28 8B16FA64 mov dx,[ScreenSize] 2494 00000E2C 8A3EF664 mov bh,[TextAttribute] 2495 00000E30 B80006 mov ax,0600h ; Clear screen region 2496 00000E33 CD10 int 10h 2497 00000E35 EBAE jmp short msg_gotoxy 2498 msg_setbg: ; Color background character 2499 00000E37 E8BE01 call unhexchar 2500 00000E3A 721D jc msg_color_bad 2501 00000E3C C0E004 shl al,4 2502 00000E3F A2F664 mov [TextAttribute],al 2503 00000E42 C706F264[490E] mov word [NextCharJump],msg_setfg 2504 00000E48 C3 ret 2505 msg_setfg: ; Color foreground character 2506 00000E49 E8AC01 call unhexchar 2507 00000E4C 720B jc msg_color_bad 2508 00000E4E 0806F664 or [TextAttribute],al ; setbg set foreground to 0 2509 00000E52 C706F264[BD0D] mov word [NextCharJump],msg_putchar 2510 00000E58 C3 ret 2511 msg_color_bad: 2512 00000E59 C606F66407 mov byte [TextAttribute],07h ; Default attribute 2513 00000E5E C706F264[BD0D] mov word [NextCharJump],msg_putchar 2514 00000E64 C3 ret 2515 2516 ; 2517 ; open,getc: Load a file a character at a time for parsing in a manner 2518 ; similar to the C library getc routine. Only one simultaneous 2519 ; use is supported. Note: "open" trashes the trackbuf. 2520 ; 2521 ; open: Input: mangled filename in DS:DI 2522 ; Output: ZF set on file not found or zero length 2523 ; 2524 ; getc: Output: CF set on end of file 2525 ; Character loaded in AL 2526 ; 2527 open: 2528 00000E65 E8FBFD call searchdir 2529 00000E68 7427 jz open_return 2530 00000E6A 9C pushf 2531 00000E6B A3C064 mov [FBytes1],ax 2532 00000E6E 8916C264 mov [FBytes2],dx 2533 00000E72 0306CE64 add ax,[ClustSize] 2534 00000E76 83D200 adc dx,byte 0 2535 00000E79 83E801 sub ax,byte 1 2536 00000E7C 83DA00 sbb dx,byte 0 2537 00000E7F F736CE64 div word [ClustSize] 2538 00000E83 A3E664 mov [FClust],ax ; Number of clusters 2539 00000E86 8936E864 mov [FNextClust],si ; Cluster pointer 2540 00000E8A A1DA64 mov ax,[EndOfGetCBuf] ; Pointer at end of buffer -> 2541 00000E8D A3EA64 mov [FPtr],ax ; nothing loaded yet 2542 00000E90 9D popf ; Restore no ZF 2543 00000E91 C3 open_return: ret 2544 2545 ; 2546 getc: 2547 00000E92 F9 stc ; If we exit here -> EOF 2548 00000E93 668B0EC064 mov ecx,[FBytes] 2549 00000E98 66E33B jecxz getc_ret 2550 00000E9B 8B36EA64 mov si,[FPtr] 2551 00000E9F 3B36DA64 cmp si,[EndOfGetCBuf] 2552 00000EA3 7226 jb getc_loaded 2553 ; Buffer empty -- load another set 2554 00000EA5 8B0EE664 mov cx,[FClust] 2555 00000EA9 3B0ED464 cmp cx,[BufSafe] 2556 00000EAD 7604 jna getc_oksize 2557 00000EAF 8B0ED464 mov cx,[BufSafe] 2558 00000EB3 290EE664 getc_oksize: sub [FClust],cx ; Reduce remaining clusters 2559 00000EB7 8B36E864 mov si,[FNextClust] 2560 00000EBB BB0094 mov bx,getcbuf 2561 00000EBE 53 push bx 2562 00000EBF 06 push es ; ES may be != DS, save old ES 2563 00000EC0 1E push ds ; Trackbuf is in DS, not ES 2564 00000EC1 07 pop es 2565 00000EC2 E85CF4 call getfssec ; Load a trackbuf full of data 2566 00000EC5 8936E864 mov [FNextClust],si ; Store new next pointer 2567 00000EC9 07 pop es ; Restore ES 2568 00000ECA 5E pop si ; SI -> newly loaded data 2569 00000ECB AC getc_loaded: lodsb ; Load a byte 2570 00000ECC 8936EA64 mov [FPtr],si ; Update next byte pointer 2571 00000ED0 66FF0EC064 dec dword [FBytes] ; Update bytes left counter (CF = 1) 2572 00000ED5 F8 clc ; Not EOF 2573 00000ED6 C3 getc_ret: ret 2574 2575 ; 2576 ; ungetc: Push a character (in AL) back into the getc buffer 2577 ; Note: if more than one byte is pushed back, this may cause 2578 ; bytes to be written below the getc buffer boundary. If there 2579 ; is a risk for this to occur, the getcbuf base address should 2580 ; be moved up. 2581 ; 2582 ungetc: 2583 00000ED7 8B36EA64 mov si,[FPtr] 2584 00000EDB 4E dec si 2585 00000EDC 8804 mov [si],al 2586 00000EDE 8936EA64 mov [FPtr],si 2587 00000EE2 66FF06C064 inc dword [FBytes] 2588 00000EE7 C3 ret 2589 2590 ; 2591 ; skipspace: Skip leading whitespace using "getc". If we hit end-of-line 2592 ; or end-of-file, return with carry set; ZF = true of EOF 2593 ; ZF = false for EOLN; otherwise CF = ZF = 0. 2594 ; 2595 ; Otherwise AL = first character after whitespace 2596 ; 2597 skipspace: 2598 00000EE8 E8A7FF skipspace_loop: call getc 2599 00000EEB 720D jc skipspace_eof 2600 00000EED 3C1A cmp al,1Ah ; DOS EOF 2601 00000EEF 7409 je skipspace_eof 2602 00000EF1 3C0A cmp al,0Ah 2603 00000EF3 7409 je skipspace_eoln 2604 00000EF5 3C20 cmp al,' ' 2605 00000EF7 76EF jbe skipspace_loop 2606 00000EF9 C3 ret ; CF = ZF = 0 2607 00000EFA 38C0 skipspace_eof: cmp al,al ; Set ZF 2608 00000EFC F9 stc ; Set CF 2609 00000EFD C3 ret 2610 00000EFE 04FF skipspace_eoln: add al,0FFh ; Set CF, clear ZF 2611 00000F00 C3 ret 2612 2613 ; 2614 ; getkeyword: Get a keyword from the current "getc" file; only the two 2615 ; first characters are considered significant. 2616 ; 2617 ; Lines beginning with ASCII characters 33-47 are treated 2618 ; as comments and ignored; other lines are checked for 2619 ; validity by scanning through the keywd_table. 2620 ; 2621 ; The keyword and subsequent whitespace is skipped. 2622 ; 2623 ; On EOF, CF = 1; otherwise, CF = 0, AL:AH = lowercase char pair 2624 ; 2625 getkeyword: 2626 00000F01 E8E4FF gkw_find: call skipspace 2627 00000F04 7438 jz gkw_eof ; end of file 2628 00000F06 72F9 jc gkw_find ; end of line: try again 2629 00000F08 3C30 cmp al,'0' 2630 00000F0A 7246 jb gkw_skipline ; skip comment line 2631 00000F0C 50 push ax 2632 00000F0D E882FF call getc 2633 00000F10 5B pop bx 2634 00000F11 722B jc gkw_eof 2635 00000F13 88C7 mov bh,al ; Move character pair into BL:BH 2636 00000F15 81CB2020 or bx,2020h ; Lower-case it 2637 00000F19 BE[6C14] mov si,keywd_table 2638 00000F1C AD gkw_check: lodsw 2639 00000F1D 21C0 and ax,ax 2640 00000F1F 7429 jz gkw_badline ; Bad keyword, write message 2641 00000F21 39D8 cmp ax,bx 2642 00000F23 75F7 jne gkw_check 2643 00000F25 50 push ax 2644 gkw_skiprest: 2645 00000F26 E869FF call getc 2646 00000F29 7212 jc gkw_eof_pop 2647 00000F2B 3C30 cmp al,'0' 2648 00000F2D 77F7 ja gkw_skiprest 2649 00000F2F E8A5FF call ungetc 2650 00000F32 E8B3FF call skipspace 2651 00000F35 7406 jz gkw_eof_pop 2652 00000F37 7206 jc gkw_missingpar ; Missing parameter after keyword 2653 00000F39 E89BFF call ungetc ; Return character to buffer 2654 00000F3C F8 clc ; Successful return 2655 00000F3D 58 gkw_eof_pop: pop ax 2656 00000F3E C3 gkw_eof: ret ; CF = 1 on all EOF conditions 2657 00000F3F 58 gkw_missingpar: pop ax 2658 00000F40 BE[7F13] mov si,err_noparm 2659 00000F43 E80BF2 call writestr 2660 00000F46 E9B8FF jmp gkw_find 2661 00000F49 58 gkw_badline_pop: pop ax 2662 00000F4A BE[5C13] gkw_badline: mov si,err_badcfg 2663 00000F4D E801F2 call writestr 2664 00000F50 EBAF jmp short gkw_find 2665 00000F52 3C0A gkw_skipline: cmp al,10 ; Scan for LF 2666 00000F54 74AB je gkw_find 2667 00000F56 E839FF call getc 2668 00000F59 72E3 jc gkw_eof 2669 00000F5B EBF5 jmp short gkw_skipline 2670 2671 ; 2672 ; getint: Load an integer from the getc file. 2673 ; Return CF if error; otherwise return integer in EBX 2674 ; 2675 getint: 2676 00000F5D BFA064 mov di,NumBuf 2677 00000F60 81FFAF64 gi_getnum: cmp di,NumBufEnd ; Last byte in NumBuf 2678 00000F64 730F jae gi_loaded 2679 00000F66 57 push di 2680 00000F67 E828FF call getc 2681 00000F6A 5F pop di 2682 00000F6B 7208 jc gi_loaded 2683 00000F6D AA stosb 2684 00000F6E 3C2D cmp al,'-' 2685 00000F70 73EE jnb gi_getnum 2686 00000F72 E862FF call ungetc ; Unget non-numeric 2687 00000F75 C60500 gi_loaded: mov byte [di],0 2688 00000F78 BEA064 mov si,NumBuf 2689 ; Fall through to parseint 2690 2691 ; 2692 ; parseint: Convert an integer to a number in EBX 2693 ; Get characters from string in DS:SI 2694 ; Return CF on error 2695 ; DS:SI points to first character after number 2696 ; 2697 ; Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+K, val+M 2698 ; 2699 parseint: 2700 00000F7B 6650 push eax 2701 00000F7D 6651 push ecx 2702 00000F7F 55 push bp 2703 00000F80 6631C0 xor eax,eax ; Current digit (keep eax == al) 2704 00000F83 6689C3 mov ebx,eax ; Accumulator 2705 00000F86 6689D9 mov ecx,ebx ; Base 2706 00000F89 31ED xor bp,bp ; Used for negative flag 2707 00000F8B AC pi_begin: lodsb 2708 00000F8C 3C2D cmp al,'-' 2709 00000F8E 7506 jne pi_not_minus 2710 00000F90 81F50100 xor bp,1 ; Set unary minus flag 2711 00000F94 EBF5 jmp short pi_begin 2712 pi_not_minus: 2713 00000F96 3C30 cmp al,'0' 2714 00000F98 724F jb pi_err 2715 00000F9A 7408 je pi_octhex 2716 00000F9C 3C39 cmp al,'9' 2717 00000F9E 7749 ja pi_err 2718 00000FA0 B10A mov cl,10 ; Base = decimal 2719 00000FA2 EB17 jmp short pi_foundbase 2720 pi_octhex: 2721 00000FA4 AC lodsb 2722 00000FA5 3C30 cmp al,'0' 2723 00000FA7 7225 jb pi_km ; Value is zero 2724 00000FA9 0C20 or al,20h ; Downcase 2725 00000FAB 3C78 cmp al,'x' 2726 00000FAD 7408 je pi_ishex 2727 00000FAF 3C37 cmp al,'7' 2728 00000FB1 7736 ja pi_err 2729 00000FB3 B108 mov cl,8 ; Base = octal 2730 00000FB5 EB04 jmp short pi_foundbase 2731 pi_ishex: 2732 00000FB7 B030 mov al,'0' ; No numeric value accrued yet 2733 00000FB9 B110 mov cl,16 ; Base = hex 2734 pi_foundbase: 2735 00000FBB E83A00 call unhexchar 2736 00000FBE 720E jc pi_km ; Not a (hex) digit 2737 00000FC0 38C8 cmp al,cl 2738 00000FC2 730A jae pi_km ; Invalid for base 2739 00000FC4 660FAFD9 imul ebx,ecx ; Multiply accumulated by base 2740 00000FC8 6601C3 add ebx,eax ; Add current digit 2741 00000FCB AC lodsb 2742 00000FCC EBED jmp short pi_foundbase 2743 pi_km: 2744 00000FCE 4E dec si ; Back up to last non-numeric 2745 00000FCF AC lodsb 2746 00000FD0 0C20 or al,20h 2747 00000FD2 3C6B cmp al,'k' 2748 00000FD4 7416 je pi_isk 2749 00000FD6 3C6D cmp al,'m' 2750 00000FD8 7418 je pi_ism 2751 00000FDA 4E dec si ; Back up 2752 00000FDB 21ED pi_fini: and bp,bp 2753 00000FDD 7404 jz pi_ret ; CF=0! 2754 00000FDF 66F7DB neg ebx ; Value was negative 2755 00000FE2 F8 pi_done: clc 2756 00000FE3 5D pi_ret: pop bp 2757 00000FE4 6659 pop ecx 2758 00000FE6 6658 pop eax 2759 00000FE8 C3 ret 2760 00000FE9 F9 pi_err: stc 2761 00000FEA EBF7 jmp short pi_ret 2762 00000FEC 66C1E30A pi_isk: shl ebx,10 ; x 2^10 2763 00000FF0 EBF0 jmp short pi_done 2764 00000FF2 66C1E314 pi_ism: shl ebx,20 ; x 2^20 2765 00000FF6 EBEA jmp short pi_done 2766 2767 ; 2768 ; unhexchar: Convert a hexadecimal digit in AL to the equivalent number; 2769 ; return CF=1 if not a hex digit 2770 ; 2771 unhexchar: 2772 00000FF8 3C30 cmp al,'0' 2773 00000FFA 7215 jb uxc_ret ; If failure, CF == 1 already 2774 00000FFC 3C39 cmp al,'9' 2775 00000FFE 7703 ja uxc_1 2776 00001000 2C30 sub al,'0' ; CF <- 0 2777 00001002 C3 ret 2778 00001003 0C20 uxc_1: or al,20h ; upper case -> lower case 2779 00001005 3C61 cmp al,'a' 2780 00001007 7208 jb uxc_ret ; If failure, CF == 1 already 2781 00001009 3C66 cmp al,'f' 2782 0000100B 7703 ja uxc_err 2783 0000100D 2C57 sub al,'a'-10 ; CF <- 0 2784 0000100F C3 ret 2785 00001010 F9 uxc_err: stc 2786 00001011 C3 uxc_ret: ret 2787 2788 ; 2789 ; 2790 ; getline: Get a command line, converting control characters to spaces 2791 ; and collapsing streches to one; a space is appended to the 2792 ; end of the string, unless the line is empty. 2793 ; The line is terminated by ^J, ^Z or EOF and is written 2794 ; to ES:DI. On return, DI points to first char after string. 2795 ; CF is set if we hit EOF. 2796 ; 2797 getline: 2798 00001012 E8D3FE call skipspace 2799 00001015 B201 mov dl,1 ; Empty line -> empty string. 2800 00001017 742B jz gl_eof ; eof 2801 00001019 7226 jc gl_eoln ; eoln 2802 0000101B E8B9FE call ungetc 2803 0000101E 52 gl_fillloop: push dx 2804 0000101F 57 push di 2805 00001020 E86FFE call getc 2806 00001023 5F pop di 2807 00001024 5A pop dx 2808 00001025 721E jc gl_ret ; CF set! 2809 00001027 3C20 cmp al,' ' 2810 00001029 7605 jna gl_ctrl 2811 0000102B 31D2 xor dx,dx 2812 0000102D AA gl_store: stosb 2813 0000102E EBEE jmp short gl_fillloop 2814 00001030 3C0A gl_ctrl: cmp al,10 2815 00001032 7411 je gl_ret ; CF clear! 2816 00001034 3C1A cmp al,26 2817 00001036 740C je gl_eof 2818 00001038 20D2 and dl,dl 2819 0000103A 75E2 jnz gl_fillloop ; Ignore multiple spaces 2820 0000103C B020 mov al,' ' ; Ctrl -> space 2821 0000103E 42 inc dx 2822 0000103F EBEC jmp short gl_store 2823 00001041 F8 gl_eoln: clc ; End of line is not end of file 2824 00001042 EB01 jmp short gl_ret 2825 00001044 F9 gl_eof: stc 2826 00001045 9C gl_ret: pushf ; We want the last char to be space! 2827 00001046 20D2 and dl,dl 2828 00001048 7503 jnz gl_xret 2829 0000104A B020 mov al,' ' 2830 0000104C AA stosb 2831 0000104D 9D gl_xret: popf 2832 0000104E C3 ret 2833 2834 2835 %ifdef debug ; This code for debugging only 2836 ; 2837 ; dumpregs: Dumps the contents of all registers 2838 ; 2839 assume ds:_text, es:NOTHING, fs:NOTHING, gs:NOTHING 2840 dumpregs proc near ; When calling, IP is on stack 2841 pushf ; Store flags 2842 pusha 2843 push ds 2844 push es 2845 push fs 2846 push gs 2847 push cs ; Set DS <- CS 2848 pop ds 2849 cld ; Clear direction flag 2850 mov si,offset crlf 2851 call writestr 2852 mov bx,sp 2853 add bx,byte 26 2854 mov si,offset regnames 2855 mov cx,2 ; 2*7 registers to dump 2856 dump_line: push cx 2857 mov cx,7 ; 7 registers per line 2858 dump_reg: push cx 2859 mov cx,4 ; 4 characters/register name 2860 wr_reg_name: lodsb 2861 call writechr 2862 loop wr_reg_name 2863 mov ax,ss:[bx] 2864 dec bx 2865 dec bx 2866 call writehex 2867 pop cx 2868 loop dump_reg 2869 mov al,0Dh ; 2870 call writechr 2871 mov al,0Ah ; 2872 call writechr 2873 pop cx 2874 loop dump_line 2875 pop gs 2876 pop fs 2877 pop es 2878 pop ds 2879 popa ; Restore the remainder 2880 popf ; Restore flags 2881 ret 2882 dumpregs endp 2883 2884 regnames db ' IP: FL: AX: CX: DX: BX: SP: BP: SI: DI: DS: ES: FS: GS:' 2885 2886 ; 2887 ; writehex: Writes a 16-bit hexadecimal number (in AX) 2888 ; 2889 writehex proc near 2890 push bx 2891 push cx 2892 mov cx,4 ; 4 numbers 2893 write_hexdig: xor bx,bx 2894 push cx 2895 mov cx,4 ; 4 bits/digit 2896 xfer_digit: shl ax,1 2897 rcl bx,1 2898 loop xfer_digit 2899 push ax 2900 mov ax,bx 2901 or al,'0' 2902 cmp al,'9' 2903 jna ok_digit 2904 add al,'A'-'0'-10 2905 ok_digit: call writechr 2906 pop ax 2907 pop cx 2908 loop write_hexdig 2909 pop cx 2910 pop bx 2911 ret 2912 writehex endp 2913 2914 debug_magic dw 0D00Dh 2915 2916 %endif ; debug 2917 ; 2918 ; mangle_name: Mangle a DOS filename pointed to by DS:SI into a buffer pointed 2919 ; to by ES:DI; ends on encountering any whitespace 2920 ; 2921 2922 mangle_name: 2923 0000104F B90B00 mov cx,11 ; # of bytes to write 2924 mn_loop: 2925 00001052 AC lodsb 2926 00001053 3C20 cmp al,' ' ; If control or space, end 2927 00001055 762B jna mn_end 2928 00001057 3C2E cmp al,'.' ; Period -> space-fill 2929 00001059 740C je mn_is_period 2930 0000105B 3C61 cmp al,'a' 2931 0000105D 7220 jb mn_not_lower 2932 0000105F 3C7A cmp al,'z' 2933 00001061 770F ja mn_not_uslower 2934 00001063 2C20 sub al,020h 2935 00001065 EB18 jmp short mn_not_lower 2936 00001067 B020 mn_is_period: mov al,' ' ; We need to space-fill 2937 00001069 81F90300 mn_period_loop: cmp cx,3 ; If <= 3 characters left 2938 0000106D 76E3 jbe mn_loop ; Just ignore it 2939 0000106F AA stosb ; Otherwise, write a period 2940 00001070 E2F7 loop mn_period_loop ; Dec CX and (always) jump 2941 00001072 3C81 mn_not_uslower: cmp al,ucase_low 2942 00001074 7209 jb mn_not_lower 2943 00001076 3CA4 cmp al,ucase_high 2944 00001078 7705 ja mn_not_lower 2945 0000107A BB[0610] mov bx,ucase_tab-ucase_low 2946 0000107D 2ED7 cs xlatb 2947 0000107F AA mn_not_lower: stosb 2948 00001080 E2D0 loop mn_loop ; Don't continue if too long 2949 mn_end: 2950 00001082 B020 mov al,' ' ; Space-fill name 2951 00001084 F3AA rep stosb ; Doesn't do anything if CX=0 2952 00001086 C3 ret ; Done 2953 2954 ; 2955 ; Upper-case table for extended characters; this is technically code page 865, 2956 ; but code page 437 users will probably not miss not being able to use the 2957 ; cent sign in kernel images too much :-) 2958 ; 2959 ; The table only covers the range 129 to 164; the rest we can deal with. 2960 ; 2961 ucase_low equ 129 2962 ucase_high equ 164 2963 00001087 9A90418E418F804545- ucase_tab db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII' 2964 00001090 45494949 2965 00001094 8E8F9092924F994F55- db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154 2966 0000109D 5559999A 2967 000010A1 9D9C9D9E9F41494F55- db 157, 156, 157, 158, 159, 'AIOU', 165 2968 000010AA A5 2969 2970 ; 2971 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled 2972 ; filename to the conventional representation. This is needed 2973 ; for the BOOT_IMAGE= parameter for the kernel. 2974 ; NOTE: A 13-byte buffer is mandatory, even if the string is 2975 ; known to be shorter. 2976 ; 2977 ; DS:SI -> input mangled file name 2978 ; ES:DI -> output buffer 2979 ; 2980 ; On return, DI points to the first byte after the output name, 2981 ; which is set to a null byte. 2982 ; 2983 unmangle_name: 2984 000010AB 56 push si ; Save pointer to original name 2985 000010AC B90800 mov cx,8 2986 000010AF 89FD mov bp,di 2987 000010B1 AC un_copy_body: lodsb 2988 000010B2 E82600 call lower_case 2989 000010B5 AA stosb 2990 000010B6 3C20 cmp al,' ' 2991 000010B8 7602 jbe un_cb_space 2992 000010BA 89FD mov bp,di ; Position of last nonblank+1 2993 000010BC E2F3 un_cb_space: loop un_copy_body 2994 000010BE 89EF mov di,bp 2995 000010C0 B02E mov al,'.' ; Don't save 2996 000010C2 AA stosb 2997 000010C3 B90300 mov cx,3 2998 000010C6 AC un_copy_ext: lodsb 2999 000010C7 E81100 call lower_case 3000 000010CA AA stosb 3001 000010CB 3C20 cmp al,' ' 3002 000010CD 7602 jbe un_ce_space 3003 000010CF 89FD mov bp,di 3004 000010D1 E2F3 un_ce_space: loop un_copy_ext 3005 000010D3 89EF mov di,bp 3006 000010D5 26C60500 mov byte [es:di], 0 3007 000010D9 5E pop si 3008 000010DA C3 ret 3009 3010 ; 3011 ; lower_case: Lower case a character in AL 3012 ; 3013 lower_case: 3014 000010DB 3C41 cmp al,'A' 3015 000010DD 7216 jb lc_ret 3016 000010DF 3C5A cmp al,'Z' 3017 000010E1 7703 ja lc_1 3018 000010E3 0C20 or al,20h 3019 000010E5 C3 ret 3020 000010E6 3C80 lc_1: cmp al,lcase_low 3021 000010E8 720B jb lc_ret 3022 000010EA 3CA5 cmp al,lcase_high 3023 000010EC 7707 ja lc_ret 3024 000010EE 53 push bx 3025 000010EF BB[7610] mov bx,lcase_tab-lcase_low 3026 000010F2 2ED7 cs xlatb 3027 000010F4 5B pop bx 3028 000010F5 C3 lc_ret: ret 3029 3030 ; 3031 ; Lower-case table for codepage 865 3032 ; 3033 lcase_low equ 128 3034 lcase_high equ 165 3035 000010F6 878182838485868788- lcase_tab db 135, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138 3036 000010FF 898A 3037 00001101 8B8C8D848682919193- db 139, 140, 141, 132, 134, 130, 145, 145, 147, 148, 149 3038 0000110A 9495 3039 0000110C 96979894819B9C9B9E- db 150, 151, 152, 148, 129, 155, 156, 155, 158, 159, 160 3040 00001115 9FA0 3041 00001117 A1A2A3A4A4 db 161, 162, 163, 164, 164 3042 ; 3043 ; Various initialized or semi-initialized variables 3044 ; 3045 0000111C 2020436F7079726967- copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin' 3046 00001125 687420284329203139- 3047 0000112E 39342D313939382048- 3048 00001137 2E2050657465722041- 3049 00001140 6E76696E 3050 00001144 0D0A00 db 0Dh, 0Ah, 0 3051 00001147 626F6F743A2000 boot_prompt db 'boot: ',0 3052 0000114E 08200800 wipe_char db 08h, ' ', 08h, 0 3053 00001152 436F756C64206E6F74- err_notfound db 'Could not find kernel image: ',0 3054 0000115B 2066696E64206B6572- 3055 00001164 6E656C20696D616765- 3056 0000116D 3A2000 3057 00001170 0D0A496E76616C6964- err_notkernel db 0Dh, 0Ah, 'Invalid or corrupt kernel image: ', 0 3058 00001179 206F7220636F727275- 3059 00001182 7074206B65726E656C- 3060 0000118B 20696D6167653A2000 3061 00001194 497420617070656172- err_not386 db 'It appears your computer uses a 286 or lower CPU.' 3062 0000119D 7320796F757220636F- 3063 000011A6 6D7075746572207573- 3064 000011AF 657320612032383620- 3065 000011B8 6F72206C6F77657220- 3066 000011C1 4350552E 3067 000011C5 0D0A db 0Dh, 0Ah 3068 000011C7 596F752063616E6E6F- db 'You cannot run Linux unless you have a 386 or higher CPU' 3069 000011D0 742072756E204C696E- 3070 000011D9 757820756E6C657373- 3071 000011E2 20796F752068617665- 3072 000011EB 206120333836206F72- 3073 000011F4 206869676865722043- 3074 000011FD 5055 3075 000011FF 0D0A db 0Dh, 0Ah 3076 00001201 696E20796F7572206D- db 'in your machine. If you get this message in error, hold' 3077 0000120A 616368696E652E2020- 3078 00001213 496620796F75206765- 3079 0000121C 742074686973206D65- 3080 00001225 737361676520696E20- 3081 0000122E 6572726F722C20686F- 3082 00001237 6C64 3083 00001239 0D0A db 0Dh, 0Ah 3084 0000123B 646F776E2074686520- db 'down the Ctrl key while booting, and I will take your' 3085 00001244 4374726C206B657920- 3086 0000124D 7768696C6520626F6F- 3087 00001256 74696E672C20616E64- 3088 0000125F 20492077696C6C2074- 3089 00001268 616B6520796F7572 3090 00001270 0D0A db 0Dh, 0Ah 3091 00001272 776F726420666F7220- db 'word for it.', 0Dh, 0Ah, 0 3092 0000127B 69742E0D0A00 3093 00001281 497420617070656172- err_noram db 'It appears your computer has less than 608K of low ("DOS")' 3094 0000128A 7320796F757220636F- 3095 00001293 6D7075746572206861- 3096 0000129C 73206C657373207468- 3097 000012A5 616E203630384B206F- 3098 000012AE 66206C6F7720282244- 3099 000012B7 4F532229 3100 000012BB 0D0A db 0Dh, 0Ah 3101 000012BD 52414D2E20204C696E- db 'RAM. Linux needs at least this amount to boot. If you get' 3102 000012C6 7578206E6565647320- 3103 000012CF 6174206C6561737420- 3104 000012D8 7468697320616D6F75- 3105 000012E1 6E7420746F20626F6F- 3106 000012EA 742E2020496620796F- 3107 000012F3 7520676574 3108 000012F8 0D0A db 0Dh, 0Ah 3109 000012FA 74686973206D657373- db 'this message in error, hold down the Ctrl key while' 3110 00001303 61676520696E206572- 3111 0000130C 726F722C20686F6C64- 3112 00001315 20646F776E20746865- 3113 0000131E 204374726C206B6579- 3114 00001327 207768696C65 3115 0000132D 0D0A db 0Dh, 0Ah 3116 0000132F 626F6F74696E672C20- db 'booting, and I will take your word for it.', 0Dh, 0Ah, 0 3117 00001338 616E6420492077696C- 3118 00001341 6C2074616B6520796F- 3119 0000134A 757220776F72642066- 3120 00001353 6F722069742E0D0A00 3121 0000135C 556E6B6E6F776E206B- err_badcfg db 'Unknown keyword in syslinux.cfg.', 0Dh, 0Ah, 0 3122 00001365 6579776F726420696E- 3123 0000136E 207379736C696E7578- 3124 00001377 2E6366672E0D0A00 3125 0000137F 4D697373696E672070- err_noparm db 'Missing parameter in syslinux.cfg.', 0Dh, 0Ah, 0 3126 00001388 6172616D6574657220- 3127 00001391 696E207379736C696E- 3128 0000139A 75782E6366672E0D0A- 3129 000013A3 00 3130 000013A4 0D0A436F756C64206E- err_noinitrd db 0Dh, 0Ah, 'Could not find ramdisk image: ', 0 3131 000013AD 6F742066696E642072- 3132 000013B6 616D6469736B20696D- 3133 000013BF 6167653A2000 3134 000013C5 4E6F7420656E6F7567- err_nohighmem db 'Not enough memory to load specified kernel.', 0Dh, 0Ah, 0 3135 000013CE 68206D656D6F727920- 3136 000013D7 746F206C6F61642073- 3137 000013E0 706563696669656420- 3138 000013E9 6B65726E656C2E0D0A- 3139 000013F2 00 3140 000013F3 0D0A4B65726E656C20- err_highload db 0Dh, 0Ah, 'Kernel transfer failure.', 0Dh, 0Ah, 0 3141 000013FC 7472616E7366657220- 3142 00001405 6661696C7572652E0D- 3143 0000140E 0A00 3144 00001410 43616E6E6F74206C6F- err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' 3145 00001419 616420612072616D64- 3146 00001422 69736B207769746820- 3147 0000142B 616E206F6C64206B65- 3148 00001434 726E656C20696D6167- 3149 0000143D 652E 3150 0000143F 0D0A00 db 0Dh, 0Ah, 0 3151 00001442 4C6F6164696E672000 loading_msg db 'Loading ', 0 3152 0000144B 2E dotdot_msg db '.' 3153 0000144C 2E00 dot_msg db '.', 0 3154 0000144E 2061626F727465642E aborted_msg db ' aborted.' ; Fall through to crlf_msg! 3155 00001457 0D0A00 crlf_msg db 0Dh, 0Ah, 0 3156 0000145A 5359534C494E555843- syslinux_cfg db 'SYSLINUXCFG' 3157 00001463 4647 3158 ; 3159 ; Command line options we'd like to take a look at 3160 ; 3161 ; mem= and vga= are handled as normal 32-bit integer values 3162 00001465 696E697472643D initrd_cmd db 'initrd=' 3163 initrd_cmd_len equ 7 3164 ; 3165 ; Config file keyword table 3166 ; 3167 align 2 3168 0000146C 6170 keywd_table db 'ap' ; append 3169 0000146E 6465 db 'de' ; default 3170 00001470 7469 db 'ti' ; timeout 3171 00001472 666F db 'fo' ; font 3172 00001474 6B62 db 'kb' ; kbd 3173 00001476 6469 db 'di' ; display 3174 00001478 7072 db 'pr' ; prompt 3175 0000147A 6C61 db 'la' ; label 3176 0000147C 696D db 'im' ; implicit 3177 0000147E 6B65 db 'ke' ; kernel 3178 00001480 6631 db 'f1' ; F1 3179 00001482 6632 db 'f2' ; F2 3180 00001484 6633 db 'f3' ; F3 3181 00001486 6634 db 'f4' ; F4 3182 00001488 6635 db 'f5' ; F5 3183 0000148A 6636 db 'f6' ; F6 3184 0000148C 6637 db 'f7' ; F7 3185 0000148E 6638 db 'f8' ; F8 3186 00001490 6639 db 'f9' ; F9 3187 00001492 6630 db 'f0' ; F10 3188 00001494 0000 dw 0 3189 ; 3190 ; Misc initialized (data) variables 3191 ; 3192 00001496 0000 AppendLen dw 0 ; Bytes in append= command 3193 00001498 0000 KbdTimeOut dw 0 ; Keyboard timeout (if any) 3194 0000149A 0000 FKeyMap dw 0 ; Bitmap for F-keys loaded 3195 0000149C 0080 CmdLinePtr dw cmd_line_here ; Command line advancing pointer 3196 initrd_flag equ $ 3197 0000149E 0000 initrd_ptr dw 0 ; Initial ramdisk pointer/flag 3198 000014A0 0000 VKernelCtr dw 0 ; Number of registered vkernels 3199 000014A2 0000 ForcePrompt dw 0 ; Force prompt 3200 000014A4 0100 AllowImplicit dw 1 ; Allow implicit kernels 3201 ; 3202 ; Stuff for the command line; we do some trickery here with equ to avoid 3203 ; tons of zeros appended to our file and wasting space 3204 ; 3205 000014A6 6C696E757820 linuxauto_cmd db 'linux ' 3206 000014AC 6175746F00 auto_cmd db 'auto',0 3207 linuxauto_len equ $-linuxauto_cmd 3208 auto_len equ $-auto_cmd 3209 000014B1 424F4F545F494D4147- boot_image db 'BOOT_IMAGE=' 3210 000014BA 453D 3211 boot_image_len equ $-boot_image 3212 align 4, db 0 ; For the good of REP MOVSD 3213 command_line equ $ 3214 default_cmd equ $+(max_cmd_len+2) 3215 ldlinux_end equ default_cmd+(max_cmd_len+1) 3216 kern_cmd_len equ ldlinux_end-command_line 3217 ldlinux_len equ ldlinux_end-ldlinux_magic 3218 ; 3219 ; Put the getcbuf right after the code, aligned on a sector boundary 3220 ; 3221 end_of_code equ (ldlinux_end-bootsec)+7C00h 3222 getcbuf equ (end_of_code + 511) & 0FE00h