1 ; -*- fundamental -*- (asm-mode sucks) 2 ; $Id: ldlinux.asm,v 1.87 2001/04/24 05:10:09 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-2001 H. Peter Anvin 20 ; 21 ; This program is free software; you can redistribute it and/or modify 22 ; it under the terms of the GNU General Public License as published by 23 ; the Free Software Foundation, Inc., 675 Mass Ave, Cambridge MA 02139, 24 ; USA; either version 2 of the License, or (at your option) any later 25 ; version; incorporated herein by reference. 26 ; 27 ; **************************************************************************** 28 29 ; 30 ; Some semi-configurable constants... change on your own risk. Most are imposed 31 ; by the kernel. 32 ; 33 max_cmd_len equ 255 ; Must be odd; 255 is the kernel limit 34 retry_count equ 6 ; How patient are we with the disk? 35 HIGHMEM_MAX equ 038000000h ; Highest address for an initrd 36 DEFAULT_BAUD equ 9600 ; Default baud rate for serial port 37 BAUD_DIVISOR equ 115200 ; Serial port parameter 38 ; 39 ; Should be updated with every release to avoid bootsector/SYS file mismatch 40 ; 41 %define version_str VERSION ; Must be 4 characters long! 42 %define date DATE_STR ; Defined from the Makefile 43 %define year '2001' 44 ; 45 ; Debgging stuff 46 ; 47 ; %define debug 1 ; Uncomment to enable debugging 48 ; 49 ; ID for SYSLINUX (reported to kernel) 50 ; 51 syslinux_id equ 031h ; SYSLINUX (3) version 1.x (1) 52 ; 53 ; Segments used by Linux 54 ; 55 ; Note: the real_mode_seg is supposed to be 9000h, but some device drivers 56 ; hog some of high memory. Therefore, we load it at 7000:0000h and copy 57 ; it before starting the Linux kernel. 58 ; 59 real_mode_seg equ 7000h 60 fake_setup_seg equ real_mode_seg+020h 61 62 struc real_mode_seg_t 63 00000000 resb 20h-($-$$) ; org 20h 64 00000020 kern_cmd_magic resw 1 ; 0020 Magic # for command line 65 00000022 kern_cmd_offset resw 1 ; 0022 Offset for kernel command line 66 00000024 resb 497-($-$$) ; org 497d 67 000001F1 bs_setupsecs resb 1 ; 01F1 Sectors for setup code (0 -> 4) 68 000001F2 bs_rootflags resw 1 ; 01F2 Root readonly flag 69 000001F4 bs_syssize resw 1 ; 01F4 70 000001F6 bs_swapdev resw 1 ; 01F6 Swap device (obsolete) 71 000001F8 bs_ramsize resw 1 ; 01F8 Ramdisk flags, formerly ramdisk size 72 000001FA bs_vidmode resw 1 ; 01FA Video mode 73 000001FC bs_rootdev resw 1 ; 01FC Root device 74 000001FE bs_bootsign resw 1 ; 01FE Boot sector signature (0AA55h) 75 00000200 su_jump resb 1 ; 0200 0EBh 76 00000201 su_jump2 resb 1 ; 0201 Size of following header 77 00000202 su_header resd 1 ; 0202 New setup code: header 78 00000206 su_version resw 1 ; 0206 See linux/arch/i386/boot/setup.S 79 00000208 su_switch resw 1 ; 0208 80 0000020A su_setupseg resw 1 ; 020A 81 0000020C su_startsys resw 1 ; 020C 82 0000020E su_kver resw 1 ; 020E Kernel version pointer 83 00000210 su_loader resb 1 ; 0210 Loader ID 84 00000211 su_loadflags resb 1 ; 0211 Load high flag 85 00000212 su_movesize resw 1 ; 0212 86 00000214 su_code32start resd 1 ; 0214 Start of code loaded high 87 00000218 su_ramdiskat resd 1 ; 0218 Start of initial ramdisk 88 su_ramdisklen equ $ ; Length of initial ramdisk 89 0000021C su_ramdisklen1 resw 1 ; 021C 90 0000021E su_ramdisklen2 resw 1 ; 021E 91 00000220 su_bsklugeoffs resw 1 ; 0220 92 00000222 su_bsklugeseg resw 1 ; 0222 93 00000224 su_heapend resw 1 ; 0224 94 00000226 su_pad1 resw 1 ; 0226 95 00000228 su_cmd_line_ptr resd 1 ; 0228 96 0000022C resb (9000h-12)-($-$$) ; The setup is up to 32K long 97 linux_stack equ $ ; 8FF4 98 linux_fdctab equ $ 99 00008FF4 resb 9000h-($-$$) 100 cmd_line_here equ $ ; 9000 Should be out of the way 101 endstruc 102 103 ; 104 ; Kernel command line signature 105 ; 106 CMD_MAGIC equ 0A33Fh ; Command line magic 107 108 ; 109 ; Magic number of su_header field 110 ; 111 HEADER_ID equ 'HdrS' ; HdrS (in littleendian hex) 112 113 ; 114 ; Flags for the su_loadflags field 115 ; 116 LOAD_HIGH equ 01h ; Large kernel, load high 117 CAN_USE_HEAP equ 80h ; Boot loader reports heap size 118 119 ; 120 ; The following structure is used for "virtual kernels"; i.e. LILO-style 121 ; option labels. The options we permit here are `kernel' and `append 122 ; Since there is no room in the bottom 64K for all of these, we 123 ; stick them at vk_seg:0000 and copy them down before we need them. 124 ; 125 ; Note: this structure can be added to, but it must 126 ; 127 %define vk_power 7 ; log2(max number of vkernels) 128 %define max_vk (1 << vk_power) ; Maximum number of vkernels 129 %define vk_shift (16-vk_power) ; Number of bits to shift 130 %define vk_size (1 << vk_shift) ; Size of a vkernel buffer 131 132 struc vkernel 133 00000000 vk_vname: resb 11 ; Virtual name **MUST BE FIRST!** 134 0000000B vk_rname: resb 11 ; Real name 135 00000016 vk_appendlen: resw 1 136 alignb 4 137 00000018 vk_append: resb max_cmd_len+1 ; Command line 138 alignb 4 139 vk_end: equ $ ; Should be <= vk_size 140 endstruc 141 142 %if (vk_end > vk_size) || (vk_size*max_vk > 65536) 143 %error "Too many vkernels defined, reduce vk_power" 144 %endif 145 146 ; 147 ; Segment assignments in the bottom 640K 148 ; Stick to the low 512K in case we're using something like M-systems flash 149 ; which load a driver into low RAM (evil!!) 150 ; 151 ; 0000h - main code/data segment (and BIOS segment) 152 ; 7000h - real_mode_seg 153 ; 154 fat_seg equ 5000h ; 128K area for FAT (2x64K) 155 vk_seg equ 4000h ; Virtual kernels 156 xfer_buf_seg equ 3000h ; Bounce buffer for I/O to high mem 157 comboot_seg equ 2000h ; COMBOOT image loading zone 158 159 ; 160 ; For our convenience: define macros for jump-over-unconditinal jumps 161 ; 162 %macro jmpz 1 163 jnz %%skip 164 jmp %1 165 %%skip: 166 %endmacro 167 168 %macro jmpnz 1 169 jz %%skip 170 jmp %1 171 %%skip: 172 %endmacro 173 174 %macro jmpe 1 175 jne %%skip 176 jmp %1 177 %%skip: 178 %endmacro 179 180 %macro jmpne 1 181 je %%skip 182 jmp %1 183 %%skip: 184 %endmacro 185 186 %macro jmpc 1 187 jnc %%skip 188 jmp %1 189 %%skip: 190 %endmacro 191 192 %macro jmpnc 1 193 jc %%skip 194 jmp %1 195 %%skip: 196 %endmacro 197 198 %macro jmpb 1 199 jnb %%skip 200 jmp %1 201 %%skip: 202 %endmacro 203 204 %macro jmpnb 1 205 jb %%skip 206 jmp %1 207 %%skip: 208 %endmacro 209 210 ; 211 ; Macros similar to res[bwd], but which works in the code segment (after 212 ; section .text) 213 ; 214 %macro zb 1 215 times %1 db 0 216 %endmacro 217 218 %macro zw 1 219 times %1 dw 0 220 %endmacro 221 222 %macro zd 1 223 times %1 dd 0 224 %endmacro 225 226 ; --------------------------------------------------------------------------- 227 ; BEGIN THE BIOS/CODE/DATA SEGMENT 228 ; --------------------------------------------------------------------------- 229 absolute 4*1Eh ; In the interrupt table 230 fdctab equ $ 231 00000078 fdctab1 resw 1 232 0000007A fdctab2 resw 1 233 234 absolute 0400h 235 00000400 serial_base resw 4 ; Base addresses for 4 serial ports 236 237 absolute 0484h 238 00000484 BIOS_vidrows resb 1 ; Number of screen rows 239 240 ; 241 ; Memory below this point is reserved for the BIOS and the MBR 242 ; 243 absolute 1000h 244 trackbuf equ $ ; Track buffer goes here 245 trackbufsize equ 16384 ; Safe size of track buffer 246 ; trackbuf ends at 5000h 247 248 249 ; 250 ; Constants for the xfer_buf_seg 251 ; 252 ; The xfer_buf_seg is also used to store message file buffers. We 253 ; need two trackbuffers (text and graphics), plus a work buffer 254 ; for the graphics decompressor. 255 ; 256 xbs_textbuf equ 0 ; Also hard-coded, do not change 257 xbs_vgabuf equ trackbufsize 258 xbs_vgatmpbuf equ 2*trackbufsize 259 260 261 absolute 5000h ; Here we keep our BSS stuff 262 StackBuf equ $ ; Start the stack here (grow down - 4K) 263 00005000 VKernelBuf: resb vk_size ; "Current" vkernel 264 alignb 4 265 00005200 AppendBuf resb max_cmd_len+1 ; append= 266 00005300 KbdMap resb 256 ; Keyboard map 267 00005400 FKeyName resb 10*16 ; File names for F-key help 268 000054A0 NumBuf resb 15 ; Buffer to load number 269 000054AF NumBufEnd resb 1 ; Last byte in NumBuf 270 alignb 4 271 000054B0 PartInfo resb 16 ; Partition table entry 272 000054C0 E820Buf resd 5 ; INT 15:E820 data buffer 273 000054D4 InitRDat resd 1 ; Load address (linear) for initrd 274 000054D8 HiLoadAddr resd 1 ; Address pointer for high load loop 275 000054DC HighMemSize resd 1 ; End of memory pointer (bytes) 276 000054E0 KernelSize resd 1 ; Size of kernel (bytes) 277 000054E4 KernelName resb 12 ; Mangled name for kernel 278 ; (note the spare byte after!) 279 RootDir equ $ ; Location of root directory 280 000054F0 RootDir1 resw 1 281 000054F2 RootDir2 resw 1 282 DataArea equ $ ; Location of data area 283 000054F4 DataArea1 resw 1 284 000054F6 DataArea2 resw 1 285 FBytes equ $ ; Used by open/getc 286 000054F8 FBytes1 resw 1 287 000054FA FBytes2 resw 1 288 000054FC RootDirSize resw 1 ; Root dir size in sectors 289 000054FE DirScanCtr resw 1 ; Used while searching directory 290 00005500 DirBlocksLeft resw 1 ; Ditto 291 00005502 EndofDirSec resw 1 ; = trackbuf+bsBytesPerSec-31 292 00005504 RunLinClust resw 1 ; Cluster # for LDLINUX.SYS 293 00005506 ClustSize resw 1 ; Bytes/cluster 294 00005508 SecPerClust resw 1 ; Same as bsSecPerClust, but a word 295 0000550A NextCluster resw 1 ; Pointer to "nextcluster" routine 296 0000550C BufSafe resw 1 ; Clusters we can load into trackbuf 297 0000550E BufSafeSec resw 1 ; = how many sectors? 298 00005510 BufSafeBytes resw 1 ; = how many bytes? 299 00005512 EndOfGetCBuf resw 1 ; = getcbuf+BufSafeBytes 300 00005514 KernelClust resw 1 ; Kernel size in clusters 301 00005516 InitRDClust resw 1 ; Ramdisk size in clusters 302 00005518 ClustPerMoby resw 1 ; Clusters per 64K 303 0000551A FClust resw 1 ; Number of clusters in open/getc file 304 0000551C FNextClust resw 1 ; Pointer to next cluster in d:o 305 0000551E FPtr resw 1 ; Pointer to next char in buffer 306 00005520 CmdOptPtr resw 1 ; Pointer to first option on cmd line 307 00005522 KernelCNameLen resw 1 ; Length of unmangled kernel name 308 00005524 InitRDCNameLen resw 1 ; Length of unmangled initrd name 309 00005526 NextCharJump resw 1 ; Routine to interpret next print char 310 00005528 SetupSecs resw 1 ; Number of setup sectors 311 0000552A SavedSP resw 1 ; Our SP while running a COMBOOT image 312 0000552C A20Test resw 1 ; Counter for testing status of A20 313 0000552E CmdLineLen resw 1 ; Length of command line including null 314 00005530 GraphXSize resw 1 ; Width of splash screen file 315 00005532 VGAPos resw 1 ; Pointer into VGA memory 316 00005534 VGACluster resw 1 ; Cluster pointer for VGA image file 317 00005536 VGAFilePtr resw 1 ; Pointer into VGAFileBuf 318 TextAttrBX equ $ 319 00005538 TextAttribute resb 1 ; Text attribute for message file 320 00005539 TextPage resb 1 ; Active display page 321 CursorDX equ $ 322 0000553A CursorCol resb 1 ; Cursor column for message file 323 0000553B CursorRow resb 1 ; Cursor row for message file 324 ScreenSize equ $ 325 0000553C VidCols resb 1 ; Columns on screen-1 326 0000553D VidRows resb 1 ; Rows on screen-1 327 0000553E RetryCount resb 1 ; Used for disk access retries 328 0000553F KbdFlags resb 1 ; Check for keyboard escapes 329 00005540 LoadFlags resb 1 ; Loadflags from kernel 330 00005541 A20Tries resb 1 ; Times until giving up on A20 331 00005542 FuncFlag resb 1 ; Escape sequences received from keyboard 332 00005543 DisplayMask resb 1 ; Display modes mask 333 00005544 MNameBuf resb 11 ; Generic mangled file name buffer 334 0000554F InitRD resb 11 ; initrd= mangled name 335 0000555A KernelCName resb 13 ; Unmangled kernel name 336 00005567 InitRDCName resb 13 ; Unmangled initrd name 337 00005574 TextColorReg resb 17 ; VGA color registers for text mode 338 00005585 VGAFileBuf resb 13 ; Unmangled VGA image name 339 VGAFileBufEnd equ $ 340 00005592 VGAFileMBuf resb 11 ; Mangled VGA image name 341 342 section .text 343 org 7C00h 344 ; 345 ; Primary entry point. Tempting as though it may be, we can't put the 346 ; initial "cli" here; the jmp opcode in the first byte is part of the 347 ; "magic number" (using the term very loosely) for the DOS superblock. 348 ; 349 bootsec equ $ 350 00000000 EB3C jmp short start ; 2 bytes 351 00000002 90 nop ; 1 byte 352 ; 353 ; "Superblock" follows -- it's in the boot sector, so it's already 354 ; loaded and ready for us 355 ; 356 00000003 5359534C494E5558 bsOemName db 'SYSLINUX' ; The SYS command sets this, so... 357 superblock equ $ 358 bsBytesPerSec zw 1 359 <1> bsBytesPerSec : 360 0000000B 0000 <1> times %1 dw 0 361 bsSecPerClust zb 1 362 <1> bsSecPerClust : 363 0000000D 00 <1> times %1 db 0 364 bsResSectors zw 1 365 <1> bsResSectors : 366 0000000E 0000 <1> times %1 dw 0 367 bsFATs zb 1 368 <1> bsFATs : 369 00000010 00 <1> times %1 db 0 370 bsRootDirEnts zw 1 371 <1> bsRootDirEnts : 372 00000011 0000 <1> times %1 dw 0 373 bsSectors zw 1 374 <1> bsSectors : 375 00000013 0000 <1> times %1 dw 0 376 bsMedia zb 1 377 <1> bsMedia : 378 00000015 00 <1> times %1 db 0 379 bsFATsecs zw 1 380 <1> bsFATsecs : 381 00000016 0000 <1> times %1 dw 0 382 bsSecPerTrack zw 1 383 <1> bsSecPerTrack : 384 00000018 0000 <1> times %1 dw 0 385 bsHeads zw 1 386 <1> bsHeads : 387 0000001A 0000 <1> times %1 dw 0 388 bsHiddenSecs equ $ 389 bsHidden1 zw 1 390 <1> bsHidden1 : 391 0000001C 0000 <1> times %1 dw 0 392 bsHidden2 zw 1 393 <1> bsHidden2 : 394 0000001E 0000 <1> times %1 dw 0 395 bsHugeSectors equ $ 396 bsHugeSec1 zw 1 397 <1> bsHugeSec1 : 398 00000020 0000 <1> times %1 dw 0 399 bsHugeSec2 zw 1 400 <1> bsHugeSec2 : 401 00000022 0000 <1> times %1 dw 0 402 bsDriveNumber zb 1 403 <1> bsDriveNumber : 404 00000024 00 <1> times %1 db 0 405 bsReserved1 zb 1 406 <1> bsReserved1 : 407 00000025 00 <1> times %1 db 0 408 bsBootSignature zb 1 ; 29h if the following fields exist 409 <1> bsBootSignature : 410 00000026 00 <1> times %1 db 0 411 bsVolumeID zd 1 412 <1> bsVolumeID : 413 00000027 00000000 <1> times %1 dd 0 414 bsVolumeLabel zb 11 415 <1> bsVolumeLabel : 416 0000002B 00 <1> times %1 db 0 417 bsFileSysType zb 8 ; Must be FAT12 for this version 418 <1> bsFileSysType : 419 00000036 00 <1> times %1 db 0 420 superblock_len equ $-superblock 421 ; 422 ; Note we don't check the constraints above now; we did that at install 423 ; time (we hope!) 424 ; 425 426 ;floppy_table equ $ ; No sense in wasting memory, overwrite start 427 428 start: 429 0000003E FA cli ; No interrupts yet, please 430 0000003F FC cld ; Copy upwards 431 ; 432 ; Set up the stack 433 ; 434 00000040 31C9 xor cx,cx 435 00000042 8ED1 mov ss,cx 436 00000044 BC0050 mov sp,StackBuf ; Just below BSS 437 00000047 8EC1 mov es,cx 438 ; 439 ; DS:SI may contain a partition table entry. Preserve it for us. 440 ; 441 00000049 B108 mov cl,8 ; Save partition info (CH == 0) 442 0000004B BFB054 mov di,PartInfo 443 0000004E F3A5 rep movsw 444 ; 445 ; Now sautee the BIOS floppy info block to that it will support decent- 446 ; size transfers; the floppy block is 11 bytes and is stored in the 447 ; INT 1Eh vector (brilliant waste of resources, eh?) 448 ; 449 ; Of course, if BIOSes had been properly programmed, we wouldn't have 450 ; had to waste precious boot sector space with this code. 451 ; 452 ; This code no longer fits. Hope that noone really needs it anymore. 453 ; (If so, it needs serious updating.) In fact, some indications is that 454 ; this code does more harm than good with all the new kinds of drives and 455 ; media. 456 ; 457 %ifdef SUPPORT_REALLY_BROKEN_BIOSES 458 lds si,[ss:fdctab] ; DS:SI -> original 459 push ds ; Save on stack in case 460 push si ; we have to bail 461 push bx 462 mov cx,6 ; 12 bytes 463 mov di,floppy_table 464 push di 465 cld 466 rep movsw ; Faster to move words 467 pop di 468 mov ds,ax ; Now we can point DS to here, too 469 mov cl,[bsSecPerTrack] ; Patch the sector count 470 mov [di+4],cl 471 mov [fdctab+2],ax ; Segment 0 472 mov [fdctab],di ; offset floppy_block 473 %else 474 00000050 8ED9 mov ds,cx ; CX == 0 475 %endif 476 ; 477 ; Ready to enable interrupts, captain 478 ; 479 00000052 FB sti 480 ; 481 ; The drive number and possibly partition information was passed to us 482 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to 483 ; trust that rather than what the superblock contains. 484 ; 485 ; Would it be better to zero out bsHidden if we don't have a partition table? 486 ; 487 ; Note: di points to beyond the end of PartInfo 488 ; 489 00000053 8816[2400] mov [bsDriveNumber],dl 490 00000057 F6C280 test dl,80h ; If floppy disk (00-7F), assume no 491 0000005A 7428 jz not_harddisk ; partition table 492 0000005C F645F07F test byte [di-16],7Fh ; Sanity check: "active flag" should 493 00000060 750A jnz no_partition ; be 00 or 80 494 00000062 8D75F8 lea si,[di-8] ; Partition offset (dword) 495 00000065 BF[1C00] mov di,bsHidden1 496 00000068 B102 mov cl,2 ; CH == 0 497 0000006A F3A5 rep movsw 498 no_partition: 499 ; 500 ; Get disk drive parameters (don't trust the superblock.) Don't do this for 501 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about 502 ; what the *drive* supports, not about the *media*. Fortunately floppy disks 503 ; tend to have a fixed, well-defined geometry which is stored in the superblock. 504 ; 505 ; DL == drive # still 506 0000006C B408 mov ah,08h 507 0000006E CD13 int 13h 508 00000070 7212 jc no_driveparm 509 00000072 20E4 and ah,ah 510 00000074 750E jnz no_driveparm 511 00000076 FEC6 inc dh ; Contains # of heads - 1 512 00000078 8836[1A00] mov [bsHeads],dh 513 0000007C 81E13F00 and cx,3fh 514 00000080 890E[1800] mov [bsSecPerTrack],cx 515 no_driveparm: 516 not_harddisk: 517 ; 518 ; Now we have to do some arithmetric to figure out where things are located. 519 ; If Micro$oft had had brains they would already have done this for us, 520 ; and stored it in the superblock at format time, but here we go, 521 ; wasting precious boot sector space again... 522 ; 523 debugentrypt: 524 00000084 31C0 xor ax,ax ; INT 13:08 destroys ES 525 00000086 8EC0 mov es,ax 526 00000088 A0[1000] mov al,[bsFATs] ; Number of FATs (AH == 0) 527 0000008B F726[1600] mul word [bsFATsecs] ; Get the size of the FAT area 528 0000008F 0306[1C00] add ax,[bsHidden1] ; Add hidden sectors 529 00000093 1316[1E00] adc dx,[bsHidden2] 530 00000097 0306[0E00] add ax,[bsResSectors] ; And reserved sectors 531 0000009B 83D200 adc dx,byte 0 532 533 0000009E A3F054 mov [RootDir1],ax ; Location of root directory 534 000000A1 8916F254 mov [RootDir2],dx 535 000000A5 A3F454 mov [DataArea1],ax 536 000000A8 8916F654 mov [DataArea2],dx 537 000000AC 50 push ax 538 000000AD 52 push dx 539 540 000000AE B82000 mov ax,32 ; Size of a directory entry 541 000000B1 F726[1100] mul word [bsRootDirEnts] 542 000000B5 8B1E[0B00] mov bx,[bsBytesPerSec] 543 000000B9 01D8 add ax,bx ; Round up, not down 544 000000BB 48 dec ax 545 000000BC F7F3 div bx ; Now we have the size of the root dir 546 000000BE A3FC54 mov [RootDirSize],ax 547 000000C1 A3FE54 mov [DirScanCtr],ax 548 000000C4 81C3E10F add bx,trackbuf-31 549 000000C8 891E0255 mov [EndofDirSec],bx ; End of a single directory sector 550 551 000000CC 0106F454 add [DataArea1],ax 552 000000D0 8316F65400 adc word [DataArea2],byte 0 553 554 000000D5 5A pop dx ; Reload root directory starting point 555 000000D6 58 pop ax 556 ; 557 ; Now the fun begins. We have to search the root directory for 558 ; LDLINUX.SYS and load the first sector, so we have a little more 559 ; space to have fun with. Then we can go chasing through the FAT. 560 ; Joy!! 561 ; 562 000000D7 50 sd_nextsec: push ax 563 000000D8 52 push dx 564 000000D9 BB0010 mov bx,trackbuf 565 000000DC 53 push bx 566 000000DD E89100 call getonesec 567 000000E0 5E pop si 568 000000E1 803C00 sd_nextentry: cmp byte [si],0 ; Directory high water mark 569 000000E4 7429 je kaboom 570 000000E6 F6440B18 test byte [si+11],18h ; Must be a file 571 000000EA 750C jnz sd_not_file 572 000000EC BF[EF01] mov di,ldlinux_name 573 000000EF B90B00 mov cx,11 574 000000F2 56 push si 575 000000F3 F3A6 repe cmpsb 576 000000F5 5E pop si 577 000000F6 742D je found_it 578 000000F8 83C620 sd_not_file: add si,byte 32 ; Distance to next 579 000000FB 3B360255 cmp si,[EndofDirSec] 580 000000FF 72E0 jb sd_nextentry 581 00000101 5A pop dx 582 00000102 58 pop ax 583 00000103 83C001 add ax,byte 1 584 00000106 83D200 adc dx,byte 0 585 00000109 FF0EFE54 dec word [DirScanCtr] 586 0000010D 75C8 jnz sd_nextsec 587 ; 588 ; kaboom: write a message and bail out. 589 ; 590 kaboom: 591 0000010F 31F6 xor si,si 592 00000111 8ED6 mov ss,si 593 00000113 BC0050 mov sp,StackBuf ; Reset stack 594 00000116 8EDE mov ds,si ; Reset data segment 595 00000118 BE[DE01] .patch: mov si,bailmsg 596 0000011B E83900 call writestr ; Returns with AL = 0 597 0000011E 98 cbw ; AH <- 0 598 0000011F CD16 int 16h ; Wait for keypress 599 00000121 CD19 int 19h ; And try once more to boot... 600 00000123 EBFE .norge: jmp short .norge ; If int 19h returned; this is the end 601 602 ; 603 ; found_it: now we compute the location of the first sector, then 604 ; load it and JUMP (since we're almost out of space) 605 ; 606 found_it: ; Note: we actually leave two words on the stack here 607 ; (who cares?) 608 00000125 31C0 xor ax,ax 609 00000127 A0[0D00] mov al,[bsSecPerClust] 610 0000012A 89C5 mov bp,ax ; Load an entire cluster 611 0000012C 8B5C1A mov bx,[si+26] ; First cluster 612 0000012F 891E0455 mov [RunLinClust],bx ; Save for later use 613 00000133 4B dec bx ; First cluster is "cluster 2" 614 00000134 4B dec bx 615 00000135 F7E3 mul bx 616 00000137 0306F454 add ax,[DataArea1] 617 0000013B 1316F654 adc dx,[DataArea2] 618 0000013F BB[0002] mov bx,ldlinux_sys 619 00000142 E82F00 call getlinsec 620 00000145 BE[EF01] mov si,bs_magic 621 00000148 BF[1F02] mov di,ldlinux_magic 622 0000014B B91100 mov cx,magic_len 623 0000014E F3A6 repe cmpsb ; Make sure that the bootsector 624 00000150 75BD jne kaboom ; matches LDLINUX.SYS 625 ; 626 ; Done! Jump to the entry point! 627 ; 628 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000 629 ; instead of 0000:7C00 and the like. We don't want to add anything 630 ; more to the boot sector, so it is written to not assume a fixed 631 ; value in CS, but we don't want to deal with that anymore from now 632 ; on. 633 ; 634 00000152 EA[3002]0000 jmp 0:ldlinux_ent 635 636 ; 637 ; 638 ; writestr: write a null-terminated string to the console 639 ; 640 writestr: 641 00000157 AC wstr_1: lodsb 642 00000158 20C0 and al,al 643 0000015A 7414 jz return 644 0000015C B40E mov ah,0Eh ; Write to screen as TTY 645 0000015E BB0700 mov bx,0007h ; White on black, current page 646 00000161 CD10 int 10h 647 00000163 EBF2 jmp short wstr_1 648 ; 649 ; disk_error: decrement the retry count and bail if zero 650 ; 651 00000165 4E disk_error: dec si ; SI holds the disk retry counter 652 00000166 74A7 jz kaboom 653 00000168 5B pop bx ; 654 00000169 59 pop cx ; 655 0000016A 5A pop dx ; 656 0000016B 58 pop ax ; (AH = 0) 657 0000016C B001 mov al,1 ; Once we fail, only transfer 1 sector 658 0000016E EB39 jmp short disk_try_again 659 660 00000170 C3 return: ret 661 662 ; 663 ; getonesec: like getlinsec, but pre-sets the count to 1 664 ; 665 getonesec: 666 00000171 BD0100 mov bp,1 667 ; Fall through to getlinsec 668 669 ; 670 ; getlinsec: load a sequence of BP floppy sector given by the linear sector 671 ; number in DX:AX into the buffer at ES:BX. We try to optimize 672 ; by loading up to a whole track at a time, but the user 673 ; is responsible for not crossing a 64K boundary. 674 ; (Yes, BP is weird for a count, but it was available...) 675 ; 676 ; On return, BX points to the first byte after the transferred 677 ; block. 678 ; 679 ; The "stupid patch area" gets replaced by the code 680 ; mov bp,1 ; nop ... (BD 01 00 90 90...) when installing with 681 ; the -s option. 682 ; 683 ; Stylistic note: use "xchg" instead of "mov" when the source is a register 684 ; that is dead from that point; this saves space. However, please keep 685 ; the order to dst,src to keep things sane. 686 ; 687 getlinsec: 688 00000174 8B36[1800] mov si,[bsSecPerTrack] 689 ; 690 ; Dividing by sectors to get (track,sector): we may have 691 ; up to 2^18 tracks, so we need to do this in two steps 692 ; to produce a 32-bit quotient. 693 ; 694 00000178 91 xchg cx,ax ; CX <- LSW of LBA 695 00000179 92 xchg ax,dx 696 0000017A 31D2 xor dx,dx ; DX:AX now == MSW of LBA 697 0000017C F7F6 div si ; Obtain MSW of track # 698 0000017E 91 xchg ax,cx ; Remainder -> MSW of new dividend 699 ; LSW of LBA -> LSW of new dividend 700 ; Quotient -> MSW of track # 701 0000017F F7F6 div si ; Obtain LSW of track #, remainder 702 00000181 87CA xchg cx,dx ; CX <- Sector index (0-based) 703 ; DX <- MSW of track # 704 00000183 F736[1A00] div word [bsHeads] ; Convert track to head/cyl 705 ; 706 ; Now we have AX = cyl, DX = head, CX = sector (0-based), 707 ; BP = sectors to transfer, SI = bsSecPerTrack, 708 ; ES:BX = data target 709 ; 710 00000187 56 gls_nextchunk: push si ; bsSecPerTrack 711 00000188 55 push bp ; Sectors to transfer 712 713 __BEGIN_STUPID_PATCH_AREA: 714 00000189 29CE sub si,cx ; Sectors left on track 715 0000018B 39F5 cmp bp,si 716 0000018D 7602 jna gls_lastchunk 717 0000018F 89F5 mov bp,si ; No more than a trackful, please! 718 __END_STUPID_PATCH_AREA: 719 gls_lastchunk: 720 00000191 50 push ax ; Cylinder # 721 00000192 52 push dx ; Head # 722 723 00000193 51 push cx ; Sector # 724 00000194 B106 mov cl,6 ; Because IBM was STOOPID 725 00000196 D2E4 shl ah,cl ; and thought 8 bits were enough 726 ; then thought 10 bits were enough... 727 00000198 59 pop cx ; Sector # 728 00000199 51 push cx ; Sector # 729 0000019A 41 inc cx ; Sector numbers are 1-based 730 0000019B 08E1 or cl,ah 731 0000019D 88C5 mov ch,al 732 0000019F 88D6 mov dh,dl 733 000001A1 8A16[2400] mov dl,[bsDriveNumber] 734 000001A5 95 xchg ax,bp ; Sector to transfer count 735 ; (xchg shorter than mov) 736 000001A6 BE0600 mov si,retry_count ; # of times to retry a disk access 737 ; 738 ; Do the disk transfer... save the registers in case we fail :( 739 ; 740 disk_try_again: 741 000001A9 50 push ax ; Number of sectors we're transferring 742 000001AA B402 mov ah,02h ; READ DISK 743 000001AC 52 push dx ; 744 000001AD 51 push cx ; 745 000001AE 53 push bx ; 746 000001AF 56 push si ; 747 000001B0 CD13 int 13h 748 000001B2 5E pop si ; 749 000001B3 72B0 jc disk_error 750 ; 751 ; Disk access successful 752 ; 753 000001B5 5B pop bx ; Buffer location 754 000001B6 58 pop ax ; No longer needed 755 000001B7 58 pop ax ; No longer needed 756 000001B8 5F pop di ; Sector transferred count 757 000001B9 59 pop cx ; Sector # 758 000001BA 89F8 mov ax,di ; Reduce sector left count 759 000001BC F726[0B00] mul word [bsBytesPerSec] ; Figure out how much to advance ptr 760 000001C0 01C3 add bx,ax ; Update buffer location 761 000001C2 5A pop dx ; Head # 762 000001C3 58 pop ax ; Cyl # 763 000001C4 5D pop bp ; Sectors left to transfer 764 000001C5 5E pop si ; Number of sectors/track 765 000001C6 29FD sub bp,di ; Reduce with # of sectors just read 766 000001C8 74A6 jz return ; Done! 767 000001CA 01F9 add cx,di 768 000001CC 39F1 cmp cx,si 769 000001CE 72B7 jb gls_nextchunk 770 000001D0 42 inc dx ; Next track on cyl 771 000001D1 3B16[1A00] cmp dx,[bsHeads] ; Was this the last one? 772 000001D5 7203 jb gls_nonewcyl 773 000001D7 40 inc ax ; If so, new cylinder 774 000001D8 31D2 xor dx,dx ; First head on new cylinder 775 000001DA 29F1 gls_nonewcyl: sub cx,si ; First sector on new track 776 000001DC EBA9 jmp short gls_nextchunk 777 778 000001DE 426F6F74206661696C- bailmsg: db 'Boot failed', 0Dh, 0Ah, 0 779 000001E7 65640D0A00 780 781 bs_checkpt equ $ ; Must be <= 7DEFh 782 783 bs_checkpt_off equ ($-$$) 784 %if bs_checkpt_off > 1EFh 785 %error "Boot sector overflow" 786 %endif 787 788 zb 1EFh-($-$$) 789 000001EC 00 <1> times %1 db 0 790 bs_magic equ $ ; From here to the magic_len equ 791 ; must match ldlinux_magic 792 000001EF 4C444C494E55582053- ldlinux_name: db 'LDLINUX SYS' ; Looks like this in the root dir 793 000001F8 5953 794 000001FA 9EC7E53A dd HEXDATE ; Hopefully unique between compiles 795 796 000001FE 55AA bootsignature dw 0AA55h 797 magic_len equ $-bs_magic 798 799 ; 800 ; =========================================================================== 801 ; End of boot sector 802 ; =========================================================================== 803 ; Start of LDLINUX.SYS 804 ; =========================================================================== 805 806 ldlinux_sys: 807 808 00000200 0D0A5359534C494E55- syslinux_banner db 0Dh, 0Ah, 'SYSLINUX ', version_str, ' ', date, ' ', 0 809 00000209 5820312E3632203230- 810 00000212 30312D30342D323420- 811 0000021B 00 812 0000021C 0D0A1A db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS 813 814 0000021F 4C444C494E55582053- ldlinux_magic db 'LDLINUX SYS' 815 00000228 5953 816 0000022A 9EC7E53A dd HEXDATE 817 0000022E 55AA dw 0AA55h 818 819 align 4 820 821 ldlinux_ent: 822 ; 823 ; Tell the user we got this far 824 ; 825 00000230 BE[0002] mov si,syslinux_banner 826 00000233 E821FF call writestr 827 ; 828 ; Remember, the boot sector loaded only the first cluster of LDLINUX.SYS. 829 ; We can really only rely on a single sector having been loaded. Hence 830 ; we should load the FAT into RAM and start chasing pointers... 831 ; 832 00000236 BA0100 mov dx,1 ; 64K 833 00000239 31C0 xor ax,ax 834 0000023B F736[0B00] div word [bsBytesPerSec] ; sectors/64K 835 0000023F 89C6 mov si,ax 836 837 00000241 06 push es 838 00000242 BB0050 mov bx,fat_seg ; Load into fat_seg:0000 839 00000245 8EC3 mov es,bx 840 841 00000247 A1[1C00] mov ax,[bsHidden1] ; Hidden sectors 842 0000024A 8B16[1E00] mov dx,[bsHidden2] 843 0000024E 0306[0E00] add ax,[bsResSectors] ; plus reserved sectors = FAT 844 00000252 83D200 adc dx,byte 0 845 00000255 8B0E[1600] mov cx,[bsFATsecs] ; Sectors/FAT 846 fat_load_loop: 847 00000259 89CD mov bp,cx 848 0000025B 39F5 cmp bp,si 849 0000025D 7602 jna fat_load 850 0000025F 89F5 mov bp,si ; A full 64K moby 851 fat_load: 852 00000261 31DB xor bx,bx ; Offset 0 in the current ES 853 00000263 E82201 call getlinsecsr 854 00000266 29E9 sub cx,bp 855 00000268 740F jz fat_load_done ; Last moby? 856 0000026A 01E8 add ax,bp ; Advance sector count 857 0000026C 83D200 adc dx,byte 0 858 0000026F 8CC3 mov bx,es ; Next 64K moby 859 00000271 81C30010 add bx,1000h 860 00000275 8EC3 mov es,bx 861 00000277 EBE0 jmp short fat_load_loop 862 fat_load_done: 863 00000279 07 pop es 864 ; 865 ; Fine, now we have the FAT in memory. How big is a cluster, really? 866 ; Also figure out how many clusters will fit in an 8K buffer, and how 867 ; many sectors and bytes that is 868 ; 869 0000027A 8B3E[0B00] mov di,[bsBytesPerSec] ; Used a lot below 870 871 0000027E A0[0D00] mov al,[bsSecPerClust] ; We do this in the boot 872 00000281 30E4 xor ah,ah ; sector, too, but there 873 00000283 A30855 mov [SecPerClust],ax ; wasn't space to save it 874 00000286 89C6 mov si,ax ; Also used a lot... 875 00000288 F7E7 mul di 876 0000028A A30655 mov [ClustSize],ax ; Bytes/cluster 877 0000028D 89C3 mov bx,ax 878 0000028F B80040 mov ax,trackbufsize 879 00000292 31D2 xor dx,dx 880 00000294 F7F3 div bx 881 00000296 A30C55 mov [BufSafe],ax ; # of cluster in trackbuf 882 00000299 F7260855 mul word [SecPerClust] 883 0000029D A30E55 mov [BufSafeSec],ax 884 000002A0 F7E7 mul di 885 000002A2 A31055 mov [BufSafeBytes],ax 886 000002A5 05009C add ax,getcbuf ; Size of getcbuf is the same 887 000002A8 A31255 mov [EndOfGetCBuf],ax ; as for trackbuf 888 ; 889 ; FAT12 or FAT16? This computation is fscking ridiculous... 890 ; 891 000002AB 31D2 xor dx,dx 892 000002AD 31C9 xor cx,cx 893 000002AF A1[1300] mov ax,[bsSectors] 894 000002B2 21C0 and ax,ax 895 000002B4 7507 jnz have_secs 896 000002B6 A1[2000] mov ax,[bsHugeSectors] 897 000002B9 8B16[2200] mov dx,[bsHugeSectors+2] 898 000002BD 2B06[0E00] have_secs: sub ax,[bsResSectors] 899 000002C1 83DA00 sbb dx,byte 0 900 000002C4 8A0E[1000] mov cl,[bsFATs] 901 000002C8 2B06[1600] sec_fat_loop: sub ax,[bsFATsecs] 902 000002CC 83DA00 sbb dx,byte 0 903 000002CF E2F7 loop sec_fat_loop 904 000002D1 50 push ax 905 000002D2 52 push dx 906 000002D3 A1[1100] mov ax,[bsRootDirEnts] 907 000002D6 BB2000 mov bx,32 ; Smaller than shift since we 908 000002D9 F7E3 mul bx ; need the doubleword product 909 000002DB 01F8 add ax,di 910 000002DD 83D200 adc dx,byte 0 911 000002E0 83E801 sub ax,byte 1 912 000002E3 83DA00 sbb dx,byte 0 913 000002E6 F7F7 div di 914 000002E8 89C3 mov bx,ax 915 000002EA 5A pop dx 916 000002EB 58 pop ax 917 000002EC 29D8 sub ax,bx 918 000002EE 83DA00 sbb dx,byte 0 919 000002F1 F7F6 div si 920 000002F3 3DF60F cmp ax,4086 ; Right value? 921 000002F6 B8[BF03] mov ax,nextcluster_fat16 922 000002F9 7703 ja have_fat_type 923 000002FB B8[9803] have_fat12: mov ax,nextcluster_fat12 924 000002FE A30A55 have_fat_type: mov word [NextCluster],ax 925 926 ; 927 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first 928 ; cluster again, though. 929 ; 930 load_rest: 931 00000301 8B0E0655 mov cx,[ClustSize] 932 00000305 BB[0002] mov bx,ldlinux_sys 933 00000308 01CB add bx,cx 934 0000030A 8B360455 mov si,[RunLinClust] 935 0000030E FF160A55 call [NextCluster] 936 00000312 31D2 xor dx,dx 937 00000314 B8E91C mov ax,ldlinux_len-1 ; To be on the safe side 938 00000317 01C8 add ax,cx 939 00000319 F7F1 div cx ; the number of clusters 940 0000031B 48 dec ax ; We've already read one 941 0000031C 7405 jz all_read_jmp 942 0000031E 89C1 mov cx,ax 943 00000320 E80300 call getfssec 944 ; 945 ; All loaded up 946 ; 947 all_read_jmp: 948 00000323 E9B100 jmp all_read 949 ; 950 ; ----------------------------------------------------------------------------- 951 ; Subroutines that have to be in the first sector 952 ; ----------------------------------------------------------------------------- 953 ; 954 ; getfssec: Get multiple clusters from a file, given the starting cluster. 955 ; 956 ; This routine makes sure the subtransfers do not cross a 64K boundary, 957 ; and will correct the situation if it does, UNLESS *sectors* cross 958 ; 64K boundaries. 959 ; 960 ; ES:BX -> Buffer 961 ; SI -> Starting cluster number (2-based) 962 ; CX -> Cluster count (0FFFFh = until end of file) 963 ; 964 ; 386 check 965 getfssec: 966 00000326 31ED getfragment: xor bp,bp ; Fragment sector count 967 00000328 89F0 mov ax,si ; Get sector address 968 0000032A 48 dec ax ; Convert to 0-based 969 0000032B 48 dec ax 970 0000032C F7260855 mul word [SecPerClust] 971 00000330 0306F454 add ax,[DataArea1] 972 00000334 1316F654 adc dx,[DataArea2] 973 getseccnt: ; See if we can read > 1 clust 974 00000338 032E0855 add bp,[SecPerClust] 975 0000033C 49 dec cx ; Reduce clusters left to find 976 0000033D 89F7 mov di,si ; Predict next cluster 977 0000033F 47 inc di 978 00000340 FF160A55 call [NextCluster] 979 00000344 7207 jc gfs_eof ; At EOF? 980 00000346 E304 jcxz endfragment ; Or was it the last we wanted? 981 00000348 39FE cmp si,di ; Is file continuous? 982 0000034A 74EC jz getseccnt ; Yes, we can get 983 0000034C F8 endfragment: clc ; Not at EOF 984 0000034D 9C gfs_eof: pushf ; Remember EOF or not 985 0000034E 56 push si 986 0000034F 51 push cx 987 gfs_getchunk: 988 00000350 50 push ax 989 00000351 52 push dx 990 00000352 8CC0 mov ax,es ; Check for 64K boundaries. 991 00000354 B104 mov cl,4 992 00000356 D3E0 shl ax,cl 993 00000358 01D8 add ax,bx 994 0000035A 31D2 xor dx,dx 995 0000035C F7D8 neg ax 996 0000035E 7501 jnz gfs_partseg 997 00000360 42 inc dx ; Full 64K segment 998 gfs_partseg: 999 00000361 F736[0B00] div word [bsBytesPerSec] ; How many sectors fit? 1000 00000365 89EE mov si,bp 1001 00000367 29C6 sub si,ax ; Compute remaining sectors 1002 00000369 7610 jbe gfs_lastchunk 1003 0000036B 89C5 mov bp,ax 1004 0000036D 5A pop dx 1005 0000036E 58 pop ax 1006 0000036F E81600 call getlinsecsr 1007 00000372 01E8 add ax,bp 1008 00000374 83D200 adc dx,byte 0 1009 00000377 89F5 mov bp,si ; Remaining sector count 1010 00000379 EBD5 jmp short gfs_getchunk 1011 0000037B 5A gfs_lastchunk: pop dx 1012 0000037C 58 pop ax 1013 0000037D E8F4FD call getlinsec 1014 00000380 59 pop cx 1015 00000381 5E pop si 1016 00000382 9D popf 1017 00000383 E302 jcxz gfs_return ; If we hit the count limit 1018 00000385 739F jnc getfragment ; If we didn't hit EOF 1019 00000387 C3 gfs_return: ret 1020 1021 ; 1022 ; getlinsecsr: save registers, call getlinsec, restore registers 1023 ; 1024 00000388 50 getlinsecsr: push ax 1025 00000389 52 push dx 1026 0000038A 51 push cx 1027 0000038B 55 push bp 1028 0000038C 56 push si 1029 0000038D 57 push di 1030 0000038E E8E3FD call getlinsec 1031 00000391 5F pop di 1032 00000392 5E pop si 1033 00000393 5D pop bp 1034 00000394 59 pop cx 1035 00000395 5A pop dx 1036 00000396 58 pop ax 1037 00000397 C3 ret 1038 1039 ; 1040 ; nextcluster: Advance a cluster pointer in SI to the next cluster 1041 ; pointed at in the FAT tables (note: FAT12 assumed) 1042 ; Sets CF on return if end of file. 1043 ; 1044 ; The variable NextCluster gets set to the appropriate 1045 ; value here. 1046 ; 1047 nextcluster_fat12: 1048 00000398 50 push ax 1049 00000399 1E push ds 1050 0000039A B80050 mov ax,fat_seg 1051 0000039D 8ED8 mov ds,ax 1052 0000039F 89F0 mov ax,si ; Multiply by 3/2 1053 000003A1 D1E8 shr ax,1 1054 000003A3 9C pushf ; CF now set if odd 1055 000003A4 01C6 add si,ax 1056 000003A6 8B34 mov si,[si] 1057 000003A8 9D popf 1058 000003A9 7308 jnc nc_even 1059 000003AB D1EE shr si,1 ; Needed for odd only 1060 000003AD D1EE shr si,1 1061 000003AF D1EE shr si,1 1062 000003B1 D1EE shr si,1 1063 nc_even: 1064 000003B3 81E6FF0F and si,0FFFh 1065 000003B7 81FEF00F cmp si,0FF0h ; Clears CF if at end of file 1066 000003BB F5 cmc ; But we want it SET... 1067 000003BC 1F pop ds 1068 000003BD 58 pop ax 1069 000003BE C3 nc_return: ret 1070 1071 ; 1072 ; FAT16 decoding routine. Note that a 16-bit FAT can be up to 128K, 1073 ; so we have to decide if we're in the "low" or the "high" 64K-segment... 1074 ; 1075 nextcluster_fat16: 1076 000003BF 50 push ax 1077 000003C0 1E push ds 1078 000003C1 B80050 mov ax,fat_seg 1079 000003C4 D1E6 shl si,1 1080 000003C6 7303 jnc .seg0 1081 000003C8 B80060 mov ax,fat_seg+1000h 1082 000003CB 8ED8 .seg0: mov ds,ax 1083 000003CD 8B34 mov si,[si] 1084 000003CF 81FEF0FF cmp si,0FFF0h 1085 000003D3 F5 cmc 1086 000003D4 1F pop ds 1087 000003D5 58 pop ax 1088 000003D6 C3 ret 1089 ; 1090 ; Debug routine 1091 ; 1092 %ifdef debug 1093 safedumpregs: 1094 cmp word [Debug_Magic],0D00Dh 1095 jnz nc_return 1096 jmp dumpregs 1097 %endif 1098 1099 rl_checkpt equ $ ; Must be <= 8000h 1100 1101 rl_checkpt_off equ ($-$$) 1102 %if rl_checkpt_off > 400h 1103 %error "Sector 1 overflow" 1104 %endif 1105 1106 ; ---------------------------------------------------------------------------- 1107 ; End of code and data that have to be in the first sector 1108 ; ---------------------------------------------------------------------------- 1109 1110 all_read: 1111 ; 1112 ; Let the user (and programmer!) know we got this far. This used to be 1113 ; in Sector 1, but makes a lot more sense here. 1114 ; 1115 000003D7 BE[6818] mov si,copyright_str 1116 000003DA E87AFD call writestr 1117 ; 1118 ; Check that no moron is trying to boot Linux on a 286 or so. According 1119 ; to Intel, the way to check is to see if the high 4 bits of the FLAGS 1120 ; register are either all stuck at 1 (8086/8088) or all stuck at 0 1121 ; (286 in real mode), if not it is a 386 or higher. They didn't 1122 ; say how to check for a 186/188, so I *hope* it falls out as a 8086 1123 ; or 286 in this test. 1124 ; 1125 ; Also, provide an escape route in case it doesn't work. 1126 ; 1127 check_escapes: 1128 000003DD B402 mov ah,02h ; Check keyboard flags 1129 000003DF CD16 int 16h 1130 000003E1 A23F55 mov [KbdFlags],al ; Save for boot prompt check 1131 000003E4 A804 test al,04h ; Ctrl->skip 386 check 1132 000003E6 7538 jnz skip_checks 1133 test_8086: 1134 000003E8 9C pushf ; Get flags 1135 000003E9 58 pop ax 1136 000003EA 25FF0F and ax,0FFFh ; Clear top 4 bits 1137 000003ED 50 push ax ; Load into FLAGS 1138 000003EE 9D popf 1139 000003EF 9C pushf ; And load back 1140 000003F0 58 pop ax 1141 000003F1 2500F0 and ax,0F000h ; Get top 4 bits 1142 000003F4 3D00F0 cmp ax,0F000h ; If set -> 8086/8088 1143 000003F7 740E je not_386 1144 test_286: 1145 000003F9 9C pushf ; Get flags 1146 000003FA 58 pop ax 1147 000003FB 0D00F0 or ax,0F000h ; Set top 4 bits 1148 000003FE 50 push ax 1149 000003FF 9D popf 1150 00000400 9C pushf 1151 00000401 58 pop ax 1152 00000402 2500F0 and ax,0F000h ; Get top 4 bits 1153 00000405 7509 jnz is_386 ; If not clear -> 386 1154 not_386: 1155 00000407 BE[E018] mov si,err_not386 1156 0000040A E84AFD call writestr 1157 0000040D E9FFFC jmp kaboom 1158 is_386: 1159 ; Now we know it's a 386 or higher 1160 ; 1161 ; Now check that there is at least 512K of low (DOS) memory 1162 ; 1163 00000410 CD12 int 12h 1164 00000412 3D0002 cmp ax,512 1165 00000415 7309 jae enough_ram 1166 00000417 BE[CD19] mov si,err_noram 1167 0000041A E83AFD call writestr 1168 0000041D E9EFFC jmp kaboom 1169 enough_ram: 1170 skip_checks: 1171 ; 1172 ; Check if we're 386 (as opposed to 486+); if so we need to blank out 1173 ; the WBINVD instruction 1174 ; 1175 ; We check for 486 by setting EFLAGS.AC 1176 ; 1177 00000420 669C pushfd ; Save the good flags 1178 00000422 669C pushfd 1179 00000424 6658 pop eax 1180 00000426 6689C3 mov ebx,eax 1181 00000429 663500000400 xor eax,(1 << 18) ; AC bit 1182 0000042F 6650 push eax 1183 00000431 669D popfd 1184 00000433 669C pushfd 1185 00000435 6658 pop eax 1186 00000437 669D popfd ; Restore the original flags 1187 00000439 6631D8 xor eax,ebx 1188 0000043C 7505 jnz is_486 1189 ; 1190 ; 386 - Looks like we better blot out the WBINVD instruction 1191 ; 1192 0000043E C606[B80F]C3 mov byte [try_wbinvd],0c3h ; Near RET 1193 is_486: 1194 1195 ; 1196 ; Initialization that does not need to go into the any of the pre-load 1197 ; areas 1198 ; 1199 1200 ; Get ROM 8x16 font in case we switch to graphics mode 1201 00000443 31C9 xor cx,cx 1202 00000445 B83011 mov ax,1130h 1203 00000448 B706 mov bh,6 ; Get ROM 8x16 font 1204 0000044A CD10 int 10h 1205 0000044C 06 push es 1206 0000044D 0FA1 pop fs 1207 0000044F 1E push ds 1208 00000450 07 pop es 1209 00000451 81F91000 cmp cx,16 1210 00000455 750C jne not_vga ; If not VGA we don't care 1211 00000457 89EE mov si,bp 1212 00000459 BF00E0 mov di,vgafontbuf 1213 0000045C B90004 mov cx,(16*256) >> 2 1214 0000045F 64F366A5 fs rep movsd 1215 not_vga: 1216 1217 ; Now set up screen parameters 1218 00000463 E8F50C call adjust_screen 1219 ; 1220 ; Now, everything is "up and running"... patch kaboom for more 1221 ; verbosity and using the full screen system 1222 ; 1223 00000466 C606[1801]E9 mov byte [kaboom.patch],0e9h ; JMP NEAR 1224 0000046B C706[1901]AE12 mov word [kaboom.patch+1],kaboom2-(kaboom.patch+3) 1225 1226 ; 1227 ; Now we're all set to start with our *real* business. First load the 1228 ; configuration file (if any) and parse it. 1229 ; 1230 ; In previous versions I avoided using 32-bit registers because of a 1231 ; rumour some BIOSes clobbered the upper half of 32-bit registers at 1232 ; random. I figure, though, that if there are any of those still left 1233 ; they probably won't be trying to install Linux on them... 1234 ; 1235 ; The code is still ripe with 16-bitisms, though. Not worth the hassle 1236 ; to take'm out. In fact, we may want to put them back if we're going 1237 ; to boot ELKS at some point. 1238 ; 1239 00000471 BE[F11C] mov si,linuxauto_cmd ; Default command: "linux auto" 1240 00000474 BF[091E] mov di,default_cmd 1241 00000477 B90B00 mov cx,linuxauto_len 1242 0000047A F3A4 rep movsb 1243 1244 0000047C BF0053 mov di,KbdMap ; Default keymap 1:1 1245 0000047F 30C0 xor al,al 1246 00000481 B90001 mov cx,256 1247 00000484 AA mkkeymap: stosb 1248 00000485 FEC0 inc al 1249 00000487 E2FB loop mkkeymap 1250 1251 ; 1252 ; Load configuration file 1253 ; 1254 00000489 BF[731C] mov di,syslinux_cfg 1255 0000048C E84A0F call open 1256 0000048F 0F840802 jz near no_config_file 1257 parse_config: 1258 00000493 E8DF0F call getkeyword 1259 00000496 0F82FE01 jc near end_config_file ; Config file loaded 1260 0000049A 3D6465 cmp ax,'de' ; DEfault 1261 0000049D 7449 je pc_default 1262 0000049F 3D6170 cmp ax,'ap' ; APpend 1263 000004A2 744F je pc_append 1264 000004A4 3D7469 cmp ax,'ti' ; TImeout 1265 000004A7 0F849700 je near pc_timeout 1266 000004AB 3D7072 cmp ax,'pr' ; PRompt 1267 000004AE 0F84AD00 je near pc_prompt 1268 000004B2 3D666F cmp ax,'fo' ; FOnt 1269 000004B5 0F848901 je near pc_font 1270 000004B9 3D6B62 cmp ax,'kb' ; KBd 1271 000004BC 0F848C01 je near pc_kbd 1272 000004C0 3D6469 cmp ax,'di' ; DIsplay 1273 000004C3 0F848D00 je near pc_display 1274 000004C7 3D6C61 cmp ax,'la' ; LAbel 1275 000004CA 0F844101 je near pc_label 1276 000004CE 3D6B65 cmp ax,'ke' ; KErnel 1277 000004D1 7456 je pc_kernel 1278 000004D3 3D696D cmp ax,'im' ; IMplicit 1279 000004D6 0F849000 je near pc_implicit 1280 000004DA 3D7365 cmp ax,'se' ; SErial 1281 000004DD 0F849400 je near pc_serial 1282 000004E1 3C66 cmp al,'f' ; F-key 1283 000004E3 75AE jne parse_config 1284 000004E5 E9FD00 jmp pc_fkey 1285 1286 000004E8 BF[091E] pc_default: mov di,default_cmd ; "default" command 1287 000004EB E89810 call getline 1288 000004EE 30C0 xor al,al 1289 000004F0 AA stosb ; null-terminate 1290 000004F1 EBA0 jmp short parse_config 1291 1292 000004F3 833E[D01C]00 pc_append: cmp word [VKernelCtr],byte 0 ; "append" command 1293 000004F8 7710 ja pc_append_vk 1294 000004FA BF0052 mov di,AppendBuf 1295 000004FD E88610 call getline 1296 00000500 81EF0052 sub di,AppendBuf 1297 00000504 893E[C61C] pc_app1: mov [AppendLen],di 1298 00000508 EB89 jmp short parse_config 1299 0000050A BF1850 pc_append_vk: mov di,VKernelBuf+vk_append ; "append" command (vkernel) 1300 0000050D E87610 call getline 1301 00000510 81EF1850 sub di,VKernelBuf+vk_append 1302 00000514 83FF02 cmp di,byte 2 1303 00000517 750A jne pc_app2 1304 00000519 803E18502D cmp byte [VKernelBuf+vk_append],'-' 1305 0000051E 7503 jne pc_app2 1306 00000520 BF0000 mov di,0 ; If "append -" -> null string 1307 00000523 893E1650 pc_app2: mov [VKernelBuf+vk_appendlen],di 1308 00000527 EB33 jmp short parse_config_2 1309 1310 00000529 833E[D01C]00 pc_kernel: cmp word [VKernelCtr],byte 0 ; "kernel" command 1311 0000052E 0F8461FF je near parse_config ; ("label" section only) 1312 00000532 BF0010 mov di,trackbuf 1313 00000535 57 push di 1314 00000536 E84D10 call getline 1315 00000539 5E pop si 1316 0000053A BF0B50 mov di,VKernelBuf+vk_rname 1317 0000053D E88310 call mangle_name 1318 00000540 EB1A jmp short parse_config_2 1319 1320 00000542 E88C0F pc_timeout: call getint ; "timeout" command 1321 00000545 7215 jc parse_config_2 1322 00000547 B815D2 mov ax,0D215h ; There are approx 1.D215h 1323 0000054A F7E3 mul bx ; clock ticks per 1/10 s 1324 0000054C 01D3 add bx,dx 1325 0000054E 891E[C81C] mov [KbdTimeOut],bx 1326 00000552 EB08 jmp short parse_config_2 1327 1328 00000554 E80001 pc_display: call pc_getfile ; "display" command 1329 00000557 7403 jz parse_config_2 ; File not found? 1330 00000559 E8390C call get_msg_file ; Load and display file 1331 0000055C E934FF parse_config_2: jmp parse_config 1332 1333 0000055F E86F0F pc_prompt: call getint ; "prompt" command 1334 00000562 72F8 jc parse_config_2 1335 00000564 891E[D21C] mov [ForcePrompt],bx 1336 00000568 EBF2 jmp short parse_config_2 1337 1338 0000056A E8640F pc_implicit: call getint ; "implicit" command 1339 0000056D 72ED jc parse_config_2 1340 0000056F 891E[D41C] mov [AllowImplicit],bx 1341 00000573 EBE7 jmp short parse_config_2 1342 1343 00000575 E8590F pc_serial: call getint ; "serial" command 1344 00000578 72E2 jc parse_config_2 1345 0000057A 53 push bx ; Serial port # 1346 0000057B E8DE0E call skipspace 1347 0000057E 72DC jc parse_config_2 1348 00000580 E8C80E call ungetc 1349 00000583 E84B0F call getint 1350 00000586 7306 jnc .valid_baud 1351 00000588 66BB80250000 mov ebx,DEFAULT_BAUD ; No baud rate given 1352 0000058E 5F .valid_baud: pop di ; Serial port # 1353 0000058F 6683FB4B cmp ebx,byte 75 1354 00000593 72C7 jb parse_config_2 ; < 75 baud == bogus 1355 00000595 66B800C20100 mov eax,BAUD_DIVISOR 1356 0000059B 6699 cdq 1357 0000059D 66F7F3 div ebx 1358 000005A0 50 push ax ; Baud rate divisor 1359 000005A1 89FA mov dx,di 1360 000005A3 D1E7 shl di,1 1361 000005A5 8B850004 mov ax,[di+serial_base] 1362 000005A9 A3[D61C] mov [SerialPort],ax 1363 000005AC 50 push ax ; Serial port base 1364 000005AD B8E300 mov ax,00e3h ; INT 14h init parameters 1365 000005B0 CD14 int 14h ; Init serial port 1366 000005B2 5B pop bx ; Serial port base 1367 000005B3 8D5703 lea dx,[bx+3] 1368 000005B6 B083 mov al,83h ; Enable DLAB 1369 000005B8 E8F208 call slow_out 1370 000005BB 58 pop ax ; Divisor 1371 000005BC 89DA mov dx,bx 1372 000005BE E8EC08 call slow_out 1373 000005C1 42 inc dx 1374 000005C2 88E0 mov al,ah 1375 000005C4 E8E608 call slow_out 1376 000005C7 B003 mov al,03h ; Disable DLAB 1377 000005C9 83C202 add dx,byte 2 1378 000005CC E8DE08 call slow_out 1379 000005CF 83EA02 sub dx,byte 2 1380 000005D2 30C0 xor al,al ; IRQ disable 1381 000005D4 E8D608 call slow_out 1382 1383 ; Show some life 1384 000005D7 BE[0002] mov si,syslinux_banner 1385 000005DA E8760D call write_serial_str 1386 000005DD BE[6818] mov si,copyright_str 1387 000005E0 E8700D call write_serial_str 1388 1389 000005E3 EB6F jmp short parse_config_3 1390 1391 000005E5 80EC31 pc_fkey: sub ah,'1' 1392 000005E8 7302 jnb pc_fkey1 1393 000005EA B409 mov ah,9 ; F10 1394 000005EC 31C9 pc_fkey1: xor cx,cx 1395 000005EE 88E1 mov cl,ah 1396 000005F0 51 push cx 1397 000005F1 B80100 mov ax,1 1398 000005F4 D3E0 shl ax,cl 1399 000005F6 0906[CA1C] or [FKeyMap], ax ; Mark that we have this loaded 1400 000005FA BF0010 mov di,trackbuf 1401 000005FD 57 push di 1402 000005FE E8850F call getline ; Get filename to display 1403 00000601 5E pop si 1404 00000602 5F pop di 1405 00000603 C1E704 shl di,4 ; Multiply number by 16 1406 00000606 81C70054 add di,FKeyName 1407 0000060A E8B60F call mangle_name ; Mangle file name 1408 0000060D EB45 jmp short parse_config_3 1409 1410 0000060F E85800 pc_label: call commit_vk ; Commit any current vkernel 1411 00000612 BF0010 mov di,trackbuf ; Get virtual filename 1412 00000615 57 push di 1413 00000616 E86D0F call getline 1414 00000619 5E pop si 1415 0000061A BF0050 mov di,VKernelBuf+vk_vname 1416 0000061D E8A30F call mangle_name ; Mangle virtual name 1417 00000620 FF06[D01C] inc word [VKernelCtr] ; One more vkernel 1418 00000624 BE0050 mov si,VKernelBuf+vk_vname ; By default, rname == vname 1419 00000627 BF0B50 mov di,VKernelBuf+vk_rname 1420 0000062A B90B00 mov cx,11 1421 0000062D F3A4 rep movsb 1422 0000062F BE0052 mov si,AppendBuf ; Default append==global append 1423 00000632 BF1850 mov di,VKernelBuf+vk_append 1424 00000635 8B0E[C61C] mov cx,[AppendLen] 1425 00000639 890E1650 mov [VKernelBuf+vk_appendlen],cx 1426 0000063D F3A4 rep movsb 1427 0000063F E91200 jmp near parse_config_3 1428 1429 00000642 E81200 pc_font: call pc_getfile ; "font" command 1430 00000645 740D jz parse_config_3 ; File not found? 1431 00000647 E8990A call loadfont ; Load and install font 1432 0000064A EB08 jmp short parse_config_3 1433 1434 0000064C E80800 pc_kbd: call pc_getfile ; "kbd" command 1435 0000064F 7403 jz parse_config_3 1436 00000651 E8220B call loadkeys 1437 00000654 E93CFE parse_config_3: jmp parse_config 1438 1439 ; 1440 ; pc_getfile: For command line options that take file argument, this 1441 ; routine decodes the file argument and runs it through searchdir 1442 ; 1443 00000657 BF0010 pc_getfile: mov di,trackbuf 1444 0000065A 57 push di 1445 0000065B E8280F call getline 1446 0000065E 5E pop si 1447 0000065F BF4455 mov di,MNameBuf 1448 00000662 57 push di 1449 00000663 E85D0F call mangle_name 1450 00000666 5F pop di 1451 00000667 E9F609 jmp searchdir ; Tailcall 1452 1453 ; 1454 ; commit_vk: Store the current VKernelBuf into buffer segment 1455 ; 1456 commit_vk: 1457 0000066A 833E[D01C]00 cmp word [VKernelCtr],byte 0 1458 0000066F 741F je cvk_ret ; No VKernel = return 1459 00000671 813E[D01C]8000 cmp word [VKernelCtr],max_vk ; Above limit? 1460 00000677 7718 ja cvk_overflow 1461 00000679 8B3E[D01C] mov di,[VKernelCtr] 1462 0000067D 4F dec di 1463 0000067E C1E709 shl di,vk_shift 1464 00000681 BE0050 mov si,VKernelBuf 1465 00000684 B98000 mov cx,(vk_size >> 2) 1466 00000687 06 push es 1467 00000688 680040 push word vk_seg 1468 0000068B 07 pop es 1469 0000068C F366A5 rep movsd ; Copy to buffer segment 1470 0000068F 07 pop es 1471 00000690 C3 cvk_ret: ret 1472 00000691 C706[D01C]8000 cvk_overflow: mov word [VKernelCtr],max_vk ; No more than max_vk, please 1473 00000697 C3 ret 1474 1475 ; 1476 ; End of configuration file 1477 ; 1478 end_config_file: 1479 00000698 E8CFFF call commit_vk ; Commit any current vkernel 1480 no_config_file: 1481 ; 1482 ; Check whether or not we are supposed to display the boot prompt. 1483 ; 1484 check_for_key: 1485 0000069B 833E[D21C]00 cmp word [ForcePrompt],byte 0 ; Force prompt? 1486 000006A0 7509 jnz enter_command 1487 000006A2 F6063F555B test byte [KbdFlags],5Bh ; Caps, Scroll, Shift, Alt 1488 000006A7 0F84FA00 jz near auto_boot ; If neither, default boot 1489 1490 enter_command: 1491 000006AB BE[9218] mov si,boot_prompt 1492 000006AE E8C30C call cwritestr 1493 1494 000006B1 C606425500 mov byte [FuncFlag],0 ; not pressed 1495 000006B6 BF[081D] mov di,command_line 1496 ; 1497 ; get the very first character -- we can either time 1498 ; out, or receive a character press at this time. Some dorky BIOSes stuff 1499 ; a return in the buffer on bootup, so wipe the keyboard buffer first. 1500 ; 1501 000006B9 B401 clear_buffer: mov ah,1 ; Check for pending char 1502 000006BB CD16 int 16h 1503 000006BD 7406 jz get_char_time 1504 000006BF 31C0 xor ax,ax ; Get char 1505 000006C1 CD16 int 16h 1506 000006C3 EBF4 jmp short clear_buffer 1507 get_char_time: 1508 000006C5 E84A11 call vgashowcursor 1509 000006C8 8B0E[C81C] mov cx,[KbdTimeOut] 1510 000006CC 21C9 and cx,cx 1511 000006CE 741C jz get_char ; Timeout == 0 -> no timeout 1512 000006D0 41 inc cx ; The first loop will happen 1513 ; immediately as we don't 1514 ; know the appropriate DX value 1515 000006D1 51 time_loop: push cx 1516 000006D2 52 tick_loop: push dx 1517 000006D3 E8B10C call pollchar 1518 000006D6 7512 jnz get_char_pop 1519 000006D8 31C0 xor ax,ax 1520 000006DA CD1A int 1Ah ; Get time "of day" 1521 000006DC 58 pop ax 1522 000006DD 39C2 cmp dx,ax ; Has the timer advanced? 1523 000006DF 74F1 je tick_loop 1524 000006E1 59 pop cx 1525 000006E2 E2ED loop time_loop ; If so, decrement counter 1526 000006E4 E83111 call vgahidecursor 1527 000006E7 E9C900 jmp command_done ; Timeout! 1528 1529 000006EA 6658 get_char_pop: pop eax ; Clear stack 1530 get_char: 1531 000006EC E82311 call vgashowcursor 1532 000006EF E8AE0C call getchar 1533 000006F2 E82311 call vgahidecursor 1534 000006F5 20C0 and al,al 1535 000006F7 7462 jz func_key 1536 1537 000006F9 3C7F got_ascii: cmp al,7Fh ; == 1538 000006FB 743F je backspace 1539 000006FD 3C20 cmp al,' ' ; ASCII? 1540 000006FF 722A jb not_ascii 1541 00000701 7706 ja enter_char 1542 00000703 81FF[081D] cmp di,command_line ; Space must not be first 1543 00000707 74E3 je get_char 1544 00000709 F606425501 enter_char: test byte [FuncFlag],1 1545 0000070E 740F jz .not_ctrl_f 1546 00000710 C606425500 mov byte [FuncFlag],0 1547 00000715 3C30 cmp al,'0' 1548 00000717 7206 jb .not_ctrl_f 1549 00000719 7437 je ctrl_f_0 1550 0000071B 3C39 cmp al,'9' 1551 0000071D 7635 jbe ctrl_f 1552 0000071F 81FF[071E] .not_ctrl_f: cmp di,max_cmd_len+command_line ; Check there's space 1553 00000723 73C7 jnb get_char 1554 00000725 AA stosb ; Save it 1555 00000726 E8350C call writechr ; Echo to screen 1556 00000729 EBC1 get_char_2: jmp short get_char 1557 0000072B C606425500 not_ascii: mov byte [FuncFlag],0 1558 00000730 3C0D cmp al,0Dh ; Enter 1559 00000732 747F je command_done 1560 00000734 3C06 cmp al,06h ; 1561 00000736 7413 je set_func_flag 1562 00000738 3C08 cmp al,08h ; Backspace 1563 0000073A 75B0 jne get_char 1564 0000073C 81FF[081D] backspace: cmp di,command_line ; Make sure there is anything 1565 00000740 74AA je get_char ; to erase 1566 00000742 4F dec di ; Unstore one character 1567 00000743 BE[9918] mov si,wipe_char ; and erase it from the screen 1568 00000746 E82B0C call cwritestr 1569 00000749 EBDE jmp short get_char_2 1570 1571 set_func_flag: 1572 0000074B C606425501 mov byte [FuncFlag],1 1573 00000750 EBD7 jmp short get_char_2 1574 1575 00000752 040A ctrl_f_0: add al,10 ; 0 == F10 1576 00000754 57 ctrl_f: push di 1577 00000755 2C31 sub al,'1' 1578 00000757 30E4 xor ah,ah 1579 00000759 EB0E jmp short show_help 1580 1581 func_key: 1582 0000075B 57 push di 1583 0000075C 80FC44 cmp ah,68 ; F10 1584 0000075F 77C8 ja get_char_2 1585 00000761 80EC3B sub ah,59 ; F1 1586 00000764 72C3 jb get_char_2 1587 00000766 C1E808 shr ax,8 1588 show_help: ; AX = func key # (0 = F1, 9 = F10) 1589 00000769 88C1 mov cl,al 1590 0000076B C1E004 shl ax,4 ; Convert to x16 1591 0000076E BB0100 mov bx,1 1592 00000771 D3E3 shl bx,cl 1593 00000773 231E[CA1C] and bx,[FKeyMap] 1594 00000777 74B0 jz get_char_2 ; Undefined F-key 1595 00000779 89C7 mov di,ax 1596 0000077B 81C70054 add di,FKeyName 1597 0000077F E8DE08 call searchdir 1598 00000782 740A jz fk_nofile 1599 00000784 56 push si 1600 00000785 E8E90B call crlf 1601 00000788 5E pop si 1602 00000789 E8090A call get_msg_file 1603 0000078C EB03 jmp short fk_wrcmd 1604 fk_nofile: 1605 0000078E E8E00B call crlf 1606 fk_wrcmd: 1607 00000791 BE[9218] mov si,boot_prompt 1608 00000794 E8DD0B call cwritestr 1609 00000797 5F pop di ; Command line write pointer 1610 00000798 57 push di 1611 00000799 C60500 mov byte [di],0 ; Null-terminate command line 1612 0000079C BE[081D] mov si,command_line 1613 0000079F E8D20B call cwritestr ; Write command line so far 1614 000007A2 5F pop di 1615 000007A3 EB84 jmp short get_char_2 1616 auto_boot: 1617 000007A5 BE[091E] mov si,default_cmd 1618 000007A8 BF[081D] mov di,command_line 1619 000007AB B94000 mov cx,(max_cmd_len+4) >> 2 1620 000007AE F366A5 rep movsd 1621 000007B1 EB0C jmp short load_kernel 1622 command_done: 1623 000007B3 E8BB0B call crlf 1624 000007B6 81FF[081D] cmp di,command_line ; Did we just hit return? 1625 000007BA 74E9 je auto_boot 1626 000007BC 30C0 xor al,al ; Store a final null 1627 000007BE AA stosb 1628 1629 load_kernel: ; Load the kernel now 1630 ; 1631 ; First we need to mangle the kernel name the way DOS would... 1632 ; 1633 000007BF BE[081D] mov si,command_line 1634 000007C2 BFE454 mov di,KernelName 1635 000007C5 56 push si 1636 000007C6 57 push di 1637 000007C7 E8F90D call mangle_name 1638 000007CA 5F pop di 1639 000007CB 5E pop si 1640 ; 1641 ; Fast-forward to first option (we start over from the beginning, since 1642 ; mangle_name doesn't necessarily return a consistent ending state.) 1643 ; 1644 000007CC AC clin_non_wsp: lodsb 1645 000007CD 3C20 cmp al,' ' 1646 000007CF 77FB ja clin_non_wsp 1647 000007D1 20C0 clin_is_wsp: and al,al 1648 000007D3 7405 jz clin_opt_ptr 1649 000007D5 AC lodsb 1650 000007D6 3C20 cmp al,' ' 1651 000007D8 76F7 jbe clin_is_wsp 1652 000007DA 4E clin_opt_ptr: dec si ; Point to first nonblank 1653 000007DB 89362055 mov [CmdOptPtr],si ; Save ptr to first option 1654 ; 1655 ; Now check if it is a "virtual kernel" 1656 ; 1657 000007DF 8B0E[D01C] mov cx,[VKernelCtr] 1658 000007E3 1E push ds 1659 000007E4 680040 push word vk_seg 1660 000007E7 1F pop ds 1661 000007E8 83F900 cmp cx,byte 0 1662 000007EB 7413 je not_vk 1663 000007ED 31F6 xor si,si ; Point to first vkernel 1664 000007EF 60 vk_check: pusha 1665 000007F0 B90B00 mov cx,11 1666 000007F3 F3A6 repe cmpsb ; Is this it? 1667 000007F5 0F847700 je near vk_found 1668 000007F9 61 popa 1669 000007FA 81C60002 add si,vk_size 1670 000007FE E2EF loop vk_check 1671 00000800 1F not_vk: pop ds 1672 ; 1673 ; Not a "virtual kernel" - check that's OK and construct the command line 1674 ; 1675 00000801 833E[D41C]00 cmp word [AllowImplicit],byte 0 1676 00000806 745D je bad_implicit 1677 00000808 06 push es 1678 00000809 56 push si 1679 0000080A 57 push di 1680 0000080B BF0070 mov di,real_mode_seg 1681 0000080E 8EC7 mov es,di 1682 00000810 BE0052 mov si,AppendBuf 1683 00000813 BF0090 mov di,cmd_line_here 1684 00000816 8B0E[C61C] mov cx,[AppendLen] 1685 0000081A F3A4 rep movsb 1686 0000081C 893E[CC1C] mov [CmdLinePtr],di 1687 00000820 5F pop di 1688 00000821 5E pop si 1689 00000822 07 pop es 1690 00000823 BB1000 mov bx,exten_count << 2 ; Alternates to try 1691 ; 1692 ; Find the kernel on disk 1693 ; 1694 00000826 C606EF5400 get_kernel: mov byte [KernelName+11],0 ; Zero-terminate filename/extension 1695 0000082B 66A1EC54 mov eax,[KernelName+8] ; Save initial extension 1696 0000082F 66A3[B21C] mov [OrigKernelExt],eax 1697 00000833 53 .search_loop: push bx 1698 00000834 BFE454 mov di,KernelName ; Search on disk 1699 00000837 E82608 call searchdir 1700 0000083A 5B pop bx 1701 0000083B 756C jnz kernel_good 1702 0000083D 668B87[B21C] mov eax,[exten_table+bx] ; Try a different extension 1703 00000842 66A3EC54 mov [KernelName+8],eax 1704 00000846 83EB04 sub bx,byte 4 1705 00000849 73E8 jnb .search_loop 1706 bad_kernel: 1707 0000084B BEE454 mov si,KernelName 1708 0000084E BF5A55 mov di,KernelCName 1709 00000851 57 push di 1710 00000852 E8CA0D call unmangle_name ; Get human form 1711 00000855 BE[9D18] mov si,err_notfound ; Complain about missing kernel 1712 00000858 E8190B call cwritestr 1713 0000085B 5E pop si ; KernelCName 1714 0000085C E8150B call cwritestr 1715 0000085F BE[6D1C] mov si,crlf_msg 1716 00000862 E9E607 jmp abort_load ; Ask user for clue 1717 ; 1718 ; bad_implicit: The user entered a nonvirtual kernel name, with "implicit 0" 1719 ; 1720 00000865 BEE454 bad_implicit: mov si,KernelName ; For the error message 1721 00000868 BF5A55 mov di,KernelCName 1722 0000086B E8B10D call unmangle_name 1723 0000086E EBDB jmp short bad_kernel 1724 ; 1725 ; vk_found: We *are* using a "virtual kernel" 1726 ; 1727 00000870 61 vk_found: popa 1728 00000871 57 push di 1729 00000872 BF0050 mov di,VKernelBuf 1730 00000875 B98000 mov cx,vk_size >> 2 1731 00000878 F366A5 rep movsd 1732 0000087B 06 push es ; Restore old DS 1733 0000087C 1F pop ds 1734 0000087D 06 push es 1735 0000087E 680070 push word real_mode_seg 1736 00000881 07 pop es 1737 00000882 BF0090 mov di,cmd_line_here 1738 00000885 BE1850 mov si,VKernelBuf+vk_append 1739 00000888 8B0E1650 mov cx,[VKernelBuf+vk_appendlen] 1740 0000088C F3A4 rep movsb 1741 0000088E 893E[CC1C] mov [CmdLinePtr],di ; Where to add rest of cmd 1742 00000892 07 pop es 1743 00000893 5F pop di ; DI -> KernelName 1744 00000894 57 push di 1745 00000895 BE0B50 mov si,VKernelBuf+vk_rname 1746 00000898 B90B00 mov cx,11 ; We need ECX == CX later 1747 0000089B F3A4 rep movsb 1748 0000089D 5F pop di 1749 0000089E 31DB xor bx,bx ; Try only one version 1750 000008A0 E983FF jmp get_kernel 1751 ; 1752 ; kernel_corrupt: Called if the kernel file does not seem healthy 1753 ; 1754 000008A3 BE[BB18] kernel_corrupt: mov si,err_notkernel 1755 000008A6 E9A207 jmp abort_load 1756 ; 1757 ; This is it! We have a name (and location on the disk)... let's load 1758 ; that sucker!! First we have to decide what kind of file this is; base 1759 ; that decision on the file extension. The following extensions are 1760 ; recognized: 1761 ; 1762 ; .COM - COMBOOT image 1763 ; .CBT - COMBOOT image 1764 ; .BS - Boot sector 1765 ; .BSS - Boot sector, but transfer over DOS superblock 1766 ; 1767 ; Anything else is assumed to be a Linux kernel. 1768 ; 1769 kernel_good: 1770 000008A9 60 pusha 1771 000008AA BEE454 mov si,KernelName 1772 000008AD BF5A55 mov di,KernelCName 1773 000008B0 E86C0D call unmangle_name ; Get human form 1774 000008B3 81EF5A55 sub di,KernelCName 1775 000008B7 893E2255 mov [KernelCNameLen],di 1776 000008BB 61 popa 1777 1778 000008BC 668B0EEC54 mov ecx,[KernelName+8] ; Get (mangled) extension 1779 000008C1 6681F9434F4D00 cmp ecx,'COM' 1780 000008C8 0F845204 je near is_comboot_image 1781 000008CC 6681F943425400 cmp ecx,'CBT' 1782 000008D3 0F844704 je near is_comboot_image 1783 000008D7 6681F942532000 cmp ecx,'BS ' 1784 000008DE 0F84F104 je near is_bootsector 1785 000008E2 6681F942535300 cmp ecx,'BSS' 1786 000008E9 0F84EB04 je near is_bss_sector 1787 ; Otherwise Linux kernel 1788 ; 1789 ; A Linux kernel consists of three parts: boot sector, setup code, and 1790 ; kernel code. The boot sector is never executed when using an external 1791 ; booting utility, but it contains some status bytes that are necessary. 1792 ; The boot sector and setup code together form exactly 5 sectors that 1793 ; should be loaded at 9000:0. The subsequent code should be loaded 1794 ; at 1000:0. For simplicity, we load the whole thing at 0F60:0, and 1795 ; copy the latter stuff afterwards. 1796 ; 1797 ; NOTE: In the previous code I have avoided making any assumptions regarding 1798 ; the size of a sector, in case this concept ever gets extended to other 1799 ; media like CD-ROM (not that a CD-ROM would be bloody likely to use a FAT 1800 ; filesystem, of course). However, a "sector" when it comes to Linux booting 1801 ; stuff means 512 bytes *no matter what*, so here I am using that piece 1802 ; of knowledge. 1803 ; 1804 ; First check that our kernel is at least 64K and less than 8M (if it is 1805 ; more than 8M, we need to change the logic for loading it anyway...) 1806 ; 1807 is_linux_kernel: 1808 000008ED 81FA8000 cmp dx,80h ; 8 megs 1809 000008F1 77B0 ja kernel_corrupt 1810 000008F3 21D2 and dx,dx 1811 000008F5 74AC jz kernel_corrupt 1812 000008F7 50 kernel_sane: push ax 1813 000008F8 52 push dx 1814 000008F9 56 push si 1815 000008FA BE[581C] mov si,loading_msg 1816 000008FD E8740A call cwritestr 1817 ; 1818 ; Now start transferring the kernel 1819 ; 1820 00000900 680070 push word real_mode_seg 1821 00000903 07 pop es 1822 1823 00000904 50 push ax 1824 00000905 52 push dx 1825 00000906 F7360655 div word [ClustSize] ; # of clusters total 1826 0000090A 21D2 and dx,dx ; Round up 1827 0000090C 0F95C2 setnz dl 1828 0000090F 0FB6D2 movzx dx,dl 1829 00000912 01D0 add ax,dx 1830 00000914 A31455 mov [KernelClust],ax 1831 00000917 5A pop dx 1832 00000918 58 pop ax 1833 00000919 A3E054 mov [KernelSize],ax 1834 0000091C 8916E254 mov [KernelSize+2],dx 1835 ; 1836 ; Now, if we transfer these straight, we'll hit 64K boundaries. Hence we 1837 ; have to see if we're loading more than 64K, and if so, load it step by 1838 ; step. 1839 ; 1840 00000920 BA0100 mov dx,1 ; 10000h 1841 00000923 31C0 xor ax,ax 1842 00000925 F7360655 div word [ClustSize] 1843 00000929 A31855 mov [ClustPerMoby],ax ; Clusters/64K 1844 ; 1845 ; Start by loading the bootsector/setup code, to see if we need to 1846 ; do something funky. It should fit in the first 32K (loading 64K won't 1847 ; work since we might have funny stuff up near the end of memory). 1848 ; If we have larger than 32K clusters, yes, we're hosed. 1849 ; 1850 0000092C E80807 call abort_check ; Check for abort key 1851 0000092F 8B0E1855 mov cx,[ClustPerMoby] 1852 00000933 D1E9 shr cx,1 ; Half a moby 1853 00000935 290E1455 sub [KernelClust],cx 1854 00000939 31DB xor bx,bx 1855 0000093B 5E pop si ; Cluster pointer on stack 1856 0000093C E8E7F9 call getfssec 1857 0000093F 0F8260FF jc near kernel_corrupt ; Failure in first 32K 1858 00000943 26813EFE0155AA cmp word [es:bs_bootsign],0AA55h 1859 0000094A 0F8555FF jne near kernel_corrupt ; Boot sec signature missing 1860 ; 1861 ; Get the BIOS' idea of what the size of high memory is. 1862 ; 1863 0000094E 56 push si ; Save our cluster pointer! 1864 ; 1865 ; First, try INT 15:E820 (get BIOS memory map) 1866 ; 1867 get_e820: 1868 0000094F 06 push es 1869 00000950 6631DB xor ebx,ebx ; Start with first record 1870 00000953 8EC3 mov es,bx ; Need ES = DS = 0 for now 1871 00000955 EB05 jmp short .do_e820 ; Skip "at end" check first time! 1872 00000957 6621DB .int_loop: and ebx,ebx ; If we're back at beginning... 1873 0000095A 745A jz no_e820 ; ... bail; nothing found 1874 0000095C 66B820E80000 .do_e820: mov eax,0000E820h 1875 00000962 66BA50414D53 mov edx,534D4150h ; "SMAP" backwards 1876 00000968 66B914000000 mov ecx,20 1877 0000096E BFC054 mov di,E820Buf 1878 00000971 CD15 int 15h 1879 00000973 7241 jc no_e820 1880 00000975 663D50414D53 cmp eax,534D4150h 1881 0000097B 7539 jne no_e820 1882 ; 1883 ; Look for a memory block starting at <= 1 MB and continuing upward 1884 ; 1885 0000097D 66833EC45400 cmp dword [E820Buf+4], byte 0 1886 00000983 77D2 ja .int_loop ; Start >= 4 GB? 1887 00000985 66BA00001000 mov edx, (1 << 20) 1888 0000098B 662B16C054 sub edx, [E820Buf] 1889 00000990 72C5 jb .int_loop ; Start >= 1 MB? 1890 00000992 66B8FFFFFFFF mov eax, 0FFFFFFFFh 1891 00000998 66833ECC5400 cmp dword [E820Buf+12], byte 0 1892 0000099E 7704 ja .huge ; Size >= 4 GB 1893 000009A0 66A1C854 mov eax, [E820Buf+8] 1894 000009A4 6629D0 .huge: sub eax, edx ; Adjust size to start at 1 MB 1895 000009A7 76AE jbe .int_loop ; Completely below 1 MB? 1896 1897 ; Now EAX contains the size of memory 1 MB...up 1898 000009A9 66833ED05401 cmp dword [E820Buf+16], byte 1 1899 000009AF 0F855E11 jne near err_nohighmem ; High memory isn't usable memory!!!! 1900 1901 ; We're good! 1902 000009B3 07 pop es 1903 000009B4 EB33 jmp short got_highmem_add1mb ; Still need to add low 1 MB 1904 1905 ; 1906 ; INT 15:E820 failed. Try INT 15:E801. 1907 ; 1908 000009B6 07 no_e820: pop es 1909 1910 000009B7 B801E8 mov ax,0e801h ; Query high memory (semi-recent) 1911 000009BA CD15 int 15h 1912 000009BC 7215 jc no_e801 1913 000009BE 3D003C cmp ax,3c00h 1914 000009C1 7710 ja no_e801 ; > 3C00h something's wrong with this call 1915 000009C3 721A jb e801_hole ; If memory hole we can only use low part 1916 1917 000009C5 89D8 mov ax,bx 1918 000009C7 66C1E010 shl eax,16 ; 64K chunks 1919 000009CB 660500000001 add eax,(16 << 20) ; Add first 16M 1920 000009D1 EB1C jmp short got_highmem 1921 1922 ; 1923 ; INT 15:E801 failed. Try INT 15:88. 1924 ; 1925 no_e801: 1926 000009D3 B488 mov ah,88h ; Query high memory (oldest) 1927 000009D5 CD15 int 15h 1928 000009D7 3D0038 cmp ax,14*1024 ; Don't trust memory >15M 1929 000009DA 7603 jna e801_hole 1930 000009DC B80038 mov ax,14*1024 1931 e801_hole: 1932 000009DF 6625FFFF0000 and eax,0ffffh 1933 000009E5 66C1E00A shl eax,10 ; Convert from kilobytes 1934 got_highmem_add1mb: 1935 000009E9 660500001000 add eax,(1 << 20) ; First megabyte 1936 got_highmem: 1937 000009EF 66A3DC54 mov [HighMemSize],eax 1938 1939 ; 1940 ; Construct the command line (append options have already been copied) 1941 ; 1942 000009F3 8B3E[CC1C] mov di,[CmdLinePtr] 1943 000009F7 BE[FC1C] mov si,boot_image ; BOOT_IMAGE= 1944 000009FA B90B00 mov cx,boot_image_len 1945 000009FD F3A4 rep movsb 1946 000009FF BE5A55 mov si,KernelCName ; Unmangled kernel name 1947 00000A02 8B0E2255 mov cx,[KernelCNameLen] 1948 00000A06 F3A4 rep movsb 1949 00000A08 B020 mov al,' ' ; Space 1950 00000A0A AA stosb 1951 00000A0B 8B362055 mov si,[CmdOptPtr] ; Options from user input 1952 00000A0F B98100 mov cx,(kern_cmd_len+3) >> 2 1953 00000A12 F366A5 rep movsd 1954 ; 1955 %ifdef debug 1956 push ds ; DEBUG DEBUG DEBUG 1957 push es 1958 pop ds 1959 mov si,cmd_line_here 1960 call cwritestr 1961 pop ds 1962 call crlf 1963 %endif 1964 ; 1965 ; Scan through the command line for anything that looks like we might be 1966 ; interested in. The original version of this code automatically assumed 1967 ; the first option was BOOT_IMAGE=, but that is no longer certain. 1968 ; 1969 00000A15 BE0090 mov si,cmd_line_here 1970 00000A18 C606[CE1C]00 mov byte [initrd_flag],0 1971 00000A1D 06 push es ; Set DS <- real_mode_seg 1972 00000A1E 1F pop ds 1973 00000A1F AC get_next_opt: lodsb 1974 00000A20 20C0 and al,al 1975 00000A22 0F848A00 jz near cmdline_end 1976 00000A26 3C20 cmp al,' ' 1977 00000A28 76F5 jbe get_next_opt 1978 00000A2A 4E dec si 1979 00000A2B 668B04 mov eax,[si] 1980 00000A2E 663D7667613D cmp eax,'vga=' 1981 00000A34 7432 je is_vga_cmd 1982 00000A36 663D6D656D3D cmp eax,'mem=' 1983 00000A3C 7462 je is_mem_cmd 1984 00000A3E 06 push es ; Save ES -> real_mode_seg 1985 00000A3F 16 push ss 1986 00000A40 07 pop es ; Set ES <- normal DS 1987 00000A41 BF[7E1C] mov di,initrd_cmd 1988 00000A44 B90700 mov cx,initrd_cmd_len 1989 00000A47 F3A6 repe cmpsb 1990 00000A49 7514 jne not_initrd 1991 00000A4B BF4F55 mov di,InitRD 1992 00000A4E 56 push si ; mangle_dir mangles si 1993 00000A4F E8710B call mangle_name ; Mangle ramdisk name 1994 00000A52 5E pop si 1995 00000A53 26803E4F5520 cmp byte [es:InitRD],' ' ; Null filename? 1996 00000A59 260F9706[CE1C] seta byte [es:initrd_flag] ; Set flag if not 1997 00000A5F 07 not_initrd: pop es ; Restore ES -> real_mode_seg 1998 00000A60 AC skip_this_opt: lodsb ; Load from command line 1999 00000A61 3C20 cmp al,' ' 2000 00000A63 77FB ja skip_this_opt 2001 00000A65 4E dec si 2002 00000A66 EBB7 jmp short get_next_opt 2003 is_vga_cmd: 2004 00000A68 83C604 add si,byte 4 2005 00000A6B 668B04 mov eax,[si] 2006 00000A6E BBFFFF mov bx,-1 2007 00000A71 663D6E6F726D cmp eax, 'norm' ; vga=normal 2008 00000A77 7421 je vc0 2009 00000A79 6625FFFFFF00 and eax,0ffffffh ; 3 bytes 2010 00000A7F BBFEFF mov bx,-2 2011 00000A82 663D65787400 cmp eax, 'ext' ; vga=ext 2012 00000A88 7410 je vc0 2013 00000A8A BBFDFF mov bx,-3 2014 00000A8D 663D61736B00 cmp eax, 'ask' ; vga=ask 2015 00000A93 7405 je vc0 2016 00000A95 E8570A call parseint ; vga= 2017 00000A98 72C6 jc skip_this_opt ; Not an integer 2018 00000A9A 891EFA01 vc0: mov [bs_vidmode],bx ; Set video mode 2019 00000A9E EBC0 jmp short skip_this_opt 2020 is_mem_cmd: 2021 00000AA0 83C604 add si,byte 4 2022 00000AA3 E8490A call parseint 2023 00000AA6 72B8 jc skip_this_opt ; Not an integer 2024 00000AA8 2E66891EDC54 mov [cs:HighMemSize],ebx 2025 00000AAE EBB0 jmp short skip_this_opt 2026 cmdline_end: 2027 00000AB0 0E push cs ; Restore standard DS 2028 00000AB1 1F pop ds 2029 00000AB2 81EE0090 sub si,cmd_line_here 2030 00000AB6 89362E55 mov [CmdLineLen],si ; Length including final null 2031 ; 2032 ; Now check if we have a large kernel, which needs to be loaded high 2033 ; 2034 00000ABA 2666813E0202486472- cmp dword [es:su_header],HEADER_ID ; New setup code ID 2035 00000AC3 53 2036 00000AC4 0F853B02 jne near old_kernel ; Old kernel, load low 2037 00000AC8 26813E06020002 cmp word [es:su_version],0200h ; Setup code version 2.0 2038 00000ACF 0F823002 jb near old_kernel ; Old kernel, load low 2039 00000AD3 26813E06020102 cmp word [es:su_version],0201h ; Version 2.01+? 2040 00000ADA 720D jb new_kernel ; If 2.00, skip this step 2041 00000ADC 26C7062402F48F mov word [es:su_heapend],linux_stack ; Set up the heap 2042 00000AE3 26800E110280 or byte [es:su_loadflags],80h ; Let the kernel know we care 2043 ; 2044 ; We definitely have a new-style kernel. Let the kernel know who we are, 2045 ; and that we are clueful 2046 ; 2047 new_kernel: 2048 00000AE9 26C606100231 mov byte [es:su_loader],syslinux_id ; Show some ID 2049 00000AEF 260FB606F101 movzx ax,byte [es:bs_setupsecs] ; Variable # of setup sectors 2050 00000AF5 A32855 mov [SetupSecs],ax 2051 ; 2052 ; Now see if we have an initial RAMdisk; if so, do requisite computation 2053 ; 2054 00000AF8 F606[CE1C]01 test byte [initrd_flag],1 2055 00000AFD 747A jz nk_noinitrd 2056 00000AFF 06 push es ; ES->real_mode_seg 2057 00000B00 1E push ds 2058 00000B01 07 pop es ; We need ES==DS 2059 00000B02 BE4F55 mov si,InitRD 2060 00000B05 BF6755 mov di,InitRDCName 2061 00000B08 E8140B call unmangle_name ; Create human-readable name 2062 00000B0B 81EF6755 sub di,InitRDCName 2063 00000B0F 893E2455 mov [InitRDCNameLen],di 2064 00000B13 BF4F55 mov di,InitRD 2065 00000B16 E84705 call searchdir ; Look for it in directory 2066 00000B19 07 pop es 2067 00000B1A 7445 jz initrd_notthere 2068 00000B1C 8936[CE1C] mov [initrd_ptr],si ; Save cluster pointer 2069 00000B20 26A31C02 mov [es:su_ramdisklen1],ax ; Ram disk length 2070 00000B24 2689161E02 mov [es:su_ramdisklen2],dx 2071 00000B29 F7360655 div word [ClustSize] 2072 00000B2D 21D2 and dx,dx ; Round up 2073 00000B2F 0F95C2 setnz dl 2074 00000B32 0FB6D2 movzx dx,dl 2075 00000B35 01D0 add ax,dx 2076 00000B37 A31655 mov [InitRDClust],ax ; Ramdisk clusters 2077 00000B3A 668B16DC54 mov edx,[HighMemSize] ; End of memory (64K chunks) 2078 00000B3F 66B800000038 mov eax,HIGHMEM_MAX ; Limit imposed by kernel 2079 00000B45 6639C2 cmp edx,eax 2080 00000B48 7603 jna memsize_ok 2081 00000B4A 6689C2 mov edx,eax ; Adjust to fit inside limit 2082 memsize_ok: 2083 00000B4D 31D2 xor dx,dx ; Round down to 64K boundary 2084 00000B4F 26662B161C02 sub edx,[es:su_ramdisklen] ; Subtract size of ramdisk 2085 00000B55 31D2 xor dx,dx ; Round down to 64K boundary 2086 00000B57 668916D454 mov [InitRDat],edx ; Load address 2087 00000B5C E85C04 call loadinitrd ; Load initial ramdisk 2088 00000B5F EB18 jmp short initrd_end 2089 2090 initrd_notthere: 2091 00000B61 BE[F01A] mov si,err_noinitrd 2092 00000B64 E80D08 call cwritestr 2093 00000B67 BE6755 mov si,InitRDCName 2094 00000B6A E80708 call cwritestr 2095 00000B6D BE[6D1C] mov si,crlf_msg 2096 00000B70 E9D804 jmp abort_load 2097 2098 00000B73 BE[111B] no_high_mem: mov si,err_nohighmem ; Error routine 2099 00000B76 E9D204 jmp abort_load 2100 ; 2101 ; About to load the kernel. This is a modern kernel, so use the boot flags 2102 ; we were provided. 2103 ; 2104 nk_noinitrd: 2105 initrd_end: 2106 00000B79 26A01102 mov al,[es:su_loadflags] 2107 00000B7D A24055 mov [LoadFlags],al 2108 ; 2109 ; Load the kernel. We always load it at 100000h even if we're supposed to 2110 ; load it "low"; for a "low" load we copy it down to low memory right before 2111 ; jumping to it. 2112 ; 2113 read_kernel: 2114 00000B80 BE5A55 mov si,KernelCName ; Print kernel name part of 2115 00000B83 E8EE07 call cwritestr ; "Loading" message 2116 00000B86 BE[611C] mov si,dotdot_msg ; Print dots 2117 00000B89 E8E807 call cwritestr 2118 2119 00000B8C 66A1DC54 mov eax,[HighMemSize] 2120 00000B90 662D00001000 sub eax,100000h ; Load address 2121 00000B96 663B06E054 cmp eax,[KernelSize] 2122 00000B9B 72D6 jb no_high_mem ; Not enough high memory 2123 ; 2124 ; Move the stuff beyond the setup code to high memory at 100000h 2125 ; 2126 00000B9D 660FB7362855 movzx esi,word [SetupSecs] ; Setup sectors 2127 00000BA3 6646 inc esi ; plus 1 boot sector 2128 00000BA5 66C1E609 shl esi,9 ; Convert to bytes 2129 00000BA9 66B900801000 mov ecx,108000h ; 108000h = 1M + 32K 2130 00000BAF 6629F1 sub ecx,esi ; Adjust pointer to 2nd block 2131 00000BB2 66890ED854 mov [HiLoadAddr],ecx 2132 00000BB7 6681E900001000 sub ecx,100000h ; Turn into a counter 2133 00000BBE 66C1E902 shr ecx,2 ; Convert to dwords 2134 00000BC2 6681C600000700 add esi,(real_mode_seg << 4) ; Pointer to source 2135 00000BC9 66BF00001000 mov edi,100000h ; Copy to address 100000h 2136 00000BCF E88602 call bcopy ; Transfer to high memory 2137 2138 00000BD2 680030 push word xfer_buf_seg ; Transfer buffer segment 2139 00000BD5 07 pop es 2140 high_load_loop: 2141 00000BD6 BE[621C] mov si,dot_msg ; Progress report 2142 00000BD9 E89807 call cwritestr 2143 00000BDC E85804 call abort_check 2144 00000BDF 8B0E1455 mov cx,[KernelClust] 2145 00000BE3 3B0E1855 cmp cx,[ClustPerMoby] 2146 00000BE7 7604 jna high_last_moby 2147 00000BE9 8B0E1855 mov cx,[ClustPerMoby] 2148 high_last_moby: 2149 00000BED 290E1455 sub [KernelClust],cx 2150 00000BF1 31DB xor bx,bx ; Load at offset 0 2151 00000BF3 5E pop si ; Restore cluster pointer 2152 00000BF4 E82FF7 call getfssec 2153 00000BF7 56 push si ; Save cluster pointer 2154 00000BF8 9C pushf ; Save EOF 2155 00000BF9 31DB xor bx,bx 2156 00000BFB 66BE00000300 mov esi,(xfer_buf_seg << 4) 2157 00000C01 668B3ED854 mov edi,[HiLoadAddr] ; Destination address 2158 00000C06 66B900400000 mov ecx,4000h ; Cheating - transfer 64K 2159 00000C0C E84902 call bcopy ; Transfer to high memory 2160 00000C0F 66893ED854 mov [HiLoadAddr],edi ; Point to next target area 2161 00000C14 9D popf ; Restore EOF 2162 00000C15 7207 jc high_load_done ; If EOF we are done 2163 00000C17 833E145500 cmp word [KernelClust],byte 0 ; Are we done? 2164 00000C1C 75B8 jne high_load_loop ; Apparently not 2165 high_load_done: 2166 00000C1E 5E pop si ; No longer needed 2167 00000C1F B80070 mov ax,real_mode_seg ; Set to real mode seg 2168 00000C22 8EC0 mov es,ax 2169 2170 00000C24 BE[621C] mov si,dot_msg 2171 00000C27 E84A07 call cwritestr 2172 ; 2173 ; Abandon hope, ye that enter here! We do no longer permit aborts. 2174 ; 2175 00000C2A E80A04 call abort_check ; Last chance!! 2176 2177 00000C2D BE[4E1C] mov si,ready_msg 2178 00000C30 E84107 call cwritestr 2179 2180 00000C33 E8BA0B call vgaclearmode ; We can't trust ourselves after this 2181 ; 2182 ; Now, if we were supposed to load "low", copy the kernel down to 10000h 2183 ; and the real mode stuff to 90000h. We assume that all bzImage kernels are 2184 ; capable of starting their setup from a different address. 2185 ; 2186 00000C36 BB0070 mov bx,real_mode_seg ; Real mode segment 2187 00000C39 8EE3 mov fs,bx ; FS -> real_mode_seg 2188 ; 2189 ; Copy command line. Unfortunately, the kernel boot protocol requires 2190 ; the command line to exist in the 9xxxxh range even if the rest of the 2191 ; setup doesn't. 2192 ; 2193 00000C3B FA cli ; In case of hooked interrupts 2194 00000C3C F606405501 test byte [LoadFlags],LOAD_HIGH 2195 00000C41 7415 jz need_high_cmdline 2196 00000C43 64813E06020202 cmp word [fs:su_version],0202h ; Support new cmdline protocol? 2197 00000C4A 720C jb need_high_cmdline 2198 ; New cmdline protocol 2199 ; Store 32-bit (flat) pointer to command line 2200 00000C4C 6466C7062802009007- mov dword [fs:su_cmd_line_ptr],(real_mode_seg << 4) + cmd_line_here 2201 00000C55 00 2202 00000C56 EB7D jmp short in_proper_place 2203 2204 need_high_cmdline: 2205 ; 2206 ; Copy command line up to 90000h 2207 ; 2208 00000C58 B80090 mov ax,9000h 2209 00000C5B 8EC0 mov es,ax 2210 00000C5D BE0090 mov si,cmd_line_here 2211 00000C60 89F7 mov di,si 2212 00000C62 64C70620003FA3 mov [fs:kern_cmd_magic],word CMD_MAGIC ; Store magic 2213 00000C69 64893E2200 mov [fs:kern_cmd_offset],di ; Store pointer 2214 2215 00000C6E 8B0E2E55 mov cx,[CmdLineLen] 2216 00000C72 83C103 add cx,byte 3 2217 00000C75 C1E902 shr cx,2 ; Convert to dwords 2218 00000C78 64F366A5 fs rep movsd 2219 2220 00000C7C F606405501 test byte [LoadFlags],LOAD_HIGH 2221 ; Note bx -> real_mode_seg still 2222 00000C81 7552 jnz in_proper_place ; If high load, we're done 2223 2224 ; 2225 ; Loading low; we can't assume it's safe to run in place. 2226 ; 2227 ; Copy real_mode stuff up to 90000h 2228 ; 2229 00000C83 B80070 mov ax,real_mode_seg 2230 00000C86 8EE0 mov fs,ax 2231 00000C88 B80090 mov ax,9000h 2232 00000C8B 8EC0 mov es,ax 2233 00000C8D 8B0E2855 mov cx,[SetupSecs] 2234 00000C91 41 inc cx ; Setup + boot sector 2235 00000C92 C1E107 shl cx,7 ; Sectors -> dwords 2236 00000C95 31F6 xor si,si 2237 00000C97 31FF xor di,di 2238 00000C99 64F366A5 fs rep movsd ; Copy setup + boot sector 2239 ; 2240 ; Some kernels in the 1.2 ballpark but pre-bzImage have more than 4 2241 ; setup sectors, but the boot protocol had not yet been defined. They 2242 ; rely on a signature to figure out if they need to copy stuff from 2243 ; the "protected mode" kernel area. Unfortunately, we used that area 2244 ; as a transfer buffer, so it's going to find the signature there. 2245 ; Hence, zero the low 32K beyond the setup area. 2246 ; 2247 00000C9D 8B3E2855 mov di,[SetupSecs] 2248 00000CA1 47 inc di ; Setup + boot sector 2249 00000CA2 B94000 mov cx,32768/512 ; Sectors/32K 2250 00000CA5 29F9 sub cx,di ; Remaining sectors 2251 00000CA7 C1E709 shl di,9 ; Sectors -> bytes 2252 00000CAA C1E107 shl cx,7 ; Sectors -> dwords 2253 00000CAD 6631C0 xor eax,eax 2254 00000CB0 F366AB rep stosd ; Clear region 2255 ; 2256 00000CB3 668B0EE054 mov ecx,[KernelSize] 2257 00000CB8 6681C103000000 add ecx,3 ; Round upwards 2258 00000CBF 66C1E902 shr ecx,2 ; Bytes -> dwords 2259 00000CC3 66BE00001000 mov esi,100000h 2260 00000CC9 66BF00000100 mov edi,10000h 2261 00000CCF E88601 call bcopy 2262 2263 00000CD2 BB0090 mov bx,9000h ; Real mode segment 2264 2265 ; 2266 ; Now everything is where it needs to be... 2267 ; 2268 in_proper_place: 2269 00000CD5 8EC3 mov es,bx ; Real mode segment 2270 ; 2271 ; If the default root device is set to FLOPPY (0000h), change to 2272 ; /dev/fd0 (0200h) 2273 ; 2274 00000CD7 26833EFC0100 cmp word [es:bs_rootdev],byte 0 2275 00000CDD 7507 jne root_not_floppy 2276 00000CDF 26C706FC010002 mov word [es:bs_rootdev],0200h 2277 root_not_floppy: 2278 ; 2279 ; Copy the disk table to high memory, then re-initialize the floppy 2280 ; controller 2281 ; 2282 ; This needs to be moved before the copy 2283 ; 2284 %if 0 2285 push ds 2286 push bx 2287 lds si,[fdctab] 2288 mov di,linux_fdctab 2289 mov cx,3 ; 12 bytes 2290 push di 2291 rep movsd 2292 pop di 2293 mov [fdctab1],di ; Save new floppy tab pos 2294 mov [fdctab2],es 2295 xor ax,ax 2296 xor dx,dx 2297 int 13h 2298 pop bx 2299 pop ds 2300 %endif 2301 ; 2302 ; Linux wants the floppy motor shut off before starting the kernel, 2303 ; at least bootsect.S seems to imply so 2304 ; 2305 kill_motor: 2306 00000CE6 BAF203 mov dx,03F2h 2307 00000CE9 30C0 xor al,al 2308 00000CEB E8BF01 call slow_out 2309 ; 2310 ; If we're debugging, wait for a keypress so we can read any debug messages 2311 ; 2312 %ifdef debug 2313 xor ax,ax 2314 int 16h 2315 %endif 2316 ; 2317 ; Set up segment registers and the Linux real-mode stack 2318 ; Note: bx == the real mode segment 2319 ; 2320 00000CEE FA cli 2321 ; es is already == real mode segment 2322 00000CEF 8EDB mov ds,bx 2323 00000CF1 8EE3 mov fs,bx 2324 00000CF3 8EEB mov gs,bx 2325 00000CF5 8ED3 mov ss,bx 2326 00000CF7 BCF48F mov sp,linux_stack 2327 ; 2328 ; We're done... now RUN THAT KERNEL!!!! 2329 ; Setup segment == real mode segment + 020h; we need to jump to offset 2330 ; zero in the real mode segment. 2331 ; 2332 00000CFA 81C32000 add bx,020h 2333 00000CFE 53 push bx 2334 00000CFF 680000 push word 0h 2335 00000D02 CB retf 2336 2337 ; 2338 ; Load an older kernel. Older kernels always have 4 setup sectors, can't have 2339 ; initrd, and are always loaded low. 2340 ; 2341 old_kernel: 2342 00000D03 F606[CE1C]01 test byte [initrd_flag],1 ; Old kernel can't have initrd 2343 00000D08 7406 jz load_old_kernel 2344 00000D0A BE[5C1B] mov si,err_oldkernel 2345 00000D0D E93B03 jmp abort_load 2346 load_old_kernel: 2347 00000D10 C70628550400 mov word [SetupSecs],4 ; Always 4 setup sectors 2348 00000D16 C606405500 mov byte [LoadFlags],0 ; Always low 2349 00000D1B E962FE jmp read_kernel 2350 2351 ; 2352 ; Load a COMBOOT image. A COMBOOT image is basically a DOS .COM file, 2353 ; except that it may, of course, not contain any DOS system calls. We 2354 ; do, however, allow the execution of INT 20h to return to SYSLINUX. 2355 ; 2356 is_comboot_image: 2357 00000D1E 21D2 and dx,dx 2358 00000D20 7578 jnz comboot_too_large 2359 00000D22 3D00FF cmp ax,0ff00h ; Max size in bytes 2360 00000D25 7373 jae comboot_too_large 2361 2362 ; 2363 ; Set up the DOS vectors in the IVT (INT 20h-3fh) 2364 ; 2365 00000D27 66C7068000- mov dword [4*0x20],comboot_return ; INT 20h vector 2366 00000D2C [A30D0000] 2367 00000D30 66B8[B50D0000] mov eax,comboot_bogus 2368 00000D36 BF8400 mov di,4*0x21 2369 00000D39 B91F00 mov cx,31 ; All remaining DOS vectors 2370 00000D3C F366AB rep stosd 2371 2372 00000D3F B90020 mov cx,comboot_seg 2373 00000D42 8EC1 mov es,cx 2374 2375 00000D44 BB0001 mov bx,100h ; Load at :0100h 2376 2377 00000D47 8B0E1855 mov cx,[ClustPerMoby] ; Absolute maximum # of clusters 2378 00000D4B E8D8F5 call getfssec 2379 2380 00000D4E 31FF xor di,di 2381 00000D50 B94000 mov cx,64 ; 256 bytes (size of PSP) 2382 00000D53 6631C0 xor eax,eax ; Clear PSP 2383 00000D56 F366AB rep stosd 2384 2385 00000D59 26C7060000CD20 mov word [es:0], 020CDh ; INT 20h instruction 2386 ; First non-free paragraph 2387 00000D60 26C70602000030 mov word [es:02h], comboot_seg+1000h 2388 2389 ; Copy the command line from high memory 2390 00000D67 B97D00 mov cx,125 ; Max cmdline len (minus space and CR) 2391 00000D6A 8B362055 mov si,[CmdOptPtr] 2392 00000D6E BF8100 mov di,081h ; Offset in PSP for command line 2393 00000D71 B020 mov al,' ' ; DOS command lines begin with a space 2394 00000D73 AA stosb 2395 2396 00000D74 AC comboot_cmd_cp: lodsb 2397 00000D75 20C0 and al,al 2398 00000D77 7403 jz comboot_end_cmd 2399 00000D79 AA stosb 2400 00000D7A E2F8 loop comboot_cmd_cp 2401 00000D7C B00D comboot_end_cmd: mov al,0Dh ; CR after last character 2402 00000D7E AA stosb 2403 00000D7F B07E mov al,126 ; Include space but not CR 2404 00000D81 28C8 sub al,cl 2405 00000D83 26A28000 mov [es:80h], al ; Store command line length 2406 2407 00000D87 E8660A call vgaclearmode ; Reset video 2408 2409 00000D8A 8CC0 mov ax,es 2410 00000D8C 8ED8 mov ds,ax 2411 00000D8E 8ED0 mov ss,ax 2412 00000D90 31E4 xor sp,sp 2413 00000D92 680000 push word 0 ; Return to address 0 -> exit 2414 2415 00000D95 EA00010020 jmp comboot_seg:100h ; Run it 2416 2417 ; Looks like a COMBOOT image but too large 2418 comboot_too_large: 2419 00000D9A BE[AC1B] mov si,err_comlarge 2420 00000D9D E8D405 call cwritestr 2421 00000DA0 E908F9 cb_enter: jmp enter_command 2422 2423 ; Proper return vector 2424 00000DA3 FA comboot_return: cli ; Don't trust anyone 2425 00000DA4 31C0 xor ax,ax 2426 00000DA6 8ED0 mov ss,ax 2427 00000DA8 368B262A55 mov sp,[ss:SavedSP] 2428 00000DAD 8ED8 mov ds,ax 2429 00000DAF 8EC0 mov es,ax 2430 00000DB1 FB sti 2431 00000DB2 FC cld 2432 00000DB3 EBEB jmp short cb_enter 2433 2434 ; Attempted to execute DOS system call 2435 00000DB5 FA comboot_bogus: cli ; Don't trust anyone 2436 00000DB6 31C0 xor ax,ax 2437 00000DB8 8ED0 mov ss,ax 2438 00000DBA 368B262A55 mov sp,[ss:SavedSP] 2439 00000DBF 8ED8 mov ds,ax 2440 00000DC1 8EC0 mov es,ax 2441 00000DC3 FB sti 2442 00000DC4 FC cld 2443 00000DC5 BE5A55 mov si,KernelCName 2444 00000DC8 E8A905 call cwritestr 2445 00000DCB BE[8E1B] mov si,err_notdos 2446 00000DCE E8A305 call cwritestr 2447 00000DD1 EBCD jmp short cb_enter 2448 2449 ; 2450 ; Load a boot sector 2451 ; 2452 is_bootsector: 2453 ; Transfer zero bytes 2454 00000DD3 680000 push word 0 2455 00000DD6 EB03 jmp short load_bootsec 2456 is_bss_sector: 2457 ; Transfer the superblock 2458 00000DD8 683300 push word superblock_len 2459 load_bootsec: 2460 00000DDB 21D2 and dx,dx 2461 00000DDD 754F jnz bad_bootsec 2462 00000DDF 8B1E[0B00] mov bx,[bsBytesPerSec] 2463 00000DE3 39D8 cmp ax,bx 2464 00000DE5 7547 jne bad_bootsec 2465 2466 ; Make sure we don't test this uninitialized 2467 00000DE7 8997FE0F mov [bx+trackbuf-2],dx ; Note DX == 0 2468 2469 00000DEB BB0010 mov bx,trackbuf 2470 00000DEE B90100 mov cx,1 ; 1 cluster >= 1 sector 2471 00000DF1 E832F5 call getfssec 2472 2473 00000DF4 8B1E[0B00] mov bx,[bsBytesPerSec] 2474 00000DF8 8B87FE0F mov ax,[bx+trackbuf-2] 2475 00000DFC 3D55AA cmp ax,0AA55h ; Boot sector signature 2476 00000DFF 752D jne bad_bootsec 2477 2478 00000E01 BE[0B00] mov si,superblock 2479 00000E04 BF0B10 mov di,trackbuf+(superblock-bootsec) 2480 00000E07 59 pop cx ; Transfer count 2481 00000E08 F3A4 rep movsb 2482 ; 2483 ; Okay, here we go... copy over our own boot sector and run the new one 2484 ; 2485 00000E0A E8E309 call vgaclearmode ; Reset video 2486 2487 00000E0D FA cli ; Point of no return 2488 2489 00000E0E 8A16[2400] mov dl,[bsDriveNumber] ; May not be in new bootsector! 2490 2491 00000E12 BE0010 mov si,trackbuf 2492 00000E15 BF[0000] mov di,bootsec 2493 00000E18 8B0E[0B00] mov cx,[bsBytesPerSec] 2494 00000E1C F3A4 rep movsb ; Copy the boot sector! 2495 2496 00000E1E BEB054 mov si,PartInfo 2497 00000E21 BFEE07 mov di,800h-18 ; Put partition info here 2498 00000E24 57 push di 2499 00000E25 B90800 mov cx,8 ; 16 bytes 2500 00000E28 F3A5 rep movsw 2501 00000E2A 5E pop si ; DS:SI points to partition info 2502 2503 00000E2B E9D2F1 jmp bootsec 2504 2505 bad_bootsec: 2506 00000E2E BE[C71B] mov si,err_bootsec 2507 00000E31 E84005 call cwritestr 2508 00000E34 E974F8 jmp enter_command 2509 2510 ; 2511 ; 32-bit bcopy routine for real mode 2512 ; 2513 ; We enter protected mode, set up a flat 32-bit environment, run rep movsd 2514 ; and then exit. IMPORTANT: This code assumes cs == ss == 0. 2515 ; 2516 ; This code is probably excessively anal-retentive in its handling of 2517 ; segments, but this stuff is painful enough as it is without having to rely 2518 ; on everything happening "as it ought to." 2519 ; 2520 00000E37 90 align 4 2521 00000E38 1F00 bcopy_gdt: dw bcopy_gdt_size-1 ; Null descriptor - contains GDT 2522 00000E3A [380E0000] dd bcopy_gdt ; pointer for LGDT instruction 2523 00000E3E 0000 dw 0 2524 00000E40 FFFF0000 dd 0000ffffh ; Code segment, use16, readable, 2525 00000E44 009B0000 dd 00009b00h ; present, dpl 0, cover 64K 2526 00000E48 FFFF0000 dd 0000ffffh ; Data segment, use16, read/write, 2527 00000E4C 00938F00 dd 008f9300h ; present, dpl 0, cover all 4G 2528 00000E50 FFFF0000 dd 0000ffffh ; Data segment, use16, read/write, 2529 00000E54 00930000 dd 00009300h ; present, dpl 0, cover 64K 2530 bcopy_gdt_size: equ $-bcopy_gdt 2531 2532 00000E58 6650 bcopy: push eax 2533 00000E5A 9C pushf ; Saves, among others, the IF flag 2534 00000E5B 0FA8 push gs 2535 00000E5D 0FA0 push fs 2536 00000E5F 1E push ds 2537 00000E60 06 push es 2538 2539 00000E61 FA cli 2540 00000E62 E84E00 call enable_a20 2541 2542 00000E65 660F0116[380E] o32 lgdt [bcopy_gdt] 2543 00000E6B 0F20C0 mov eax,cr0 2544 00000E6E 0C01 or al,1 2545 00000E70 0F22C0 mov cr0,eax ; Enter protected mode 2546 00000E73 EA[780E]0800 jmp 08h:.in_pm 2547 2548 00000E78 B81000 .in_pm: mov ax,10h ; Data segment selector 2549 00000E7B 8EC0 mov es,ax 2550 00000E7D 8ED8 mov ds,ax 2551 2552 00000E7F B018 mov al,18h ; "Real-mode-like" data segment 2553 00000E81 8ED0 mov ss,ax 2554 00000E83 8EE0 mov fs,ax 2555 00000E85 8EE8 mov gs,ax 2556 2557 00000E87 67F366A5 a32 rep movsd ; Do our business 2558 2559 00000E8B 8EC0 mov es,ax ; Set to "real-mode-like" 2560 00000E8D 8ED8 mov ds,ax 2561 2562 00000E8F 0F20C0 mov eax,cr0 2563 00000E92 24FE and al,~1 2564 00000E94 0F22C0 mov cr0,eax ; Disable protected mode 2565 00000E97 EA[9C0E]0000 jmp 0:.in_rm 2566 2567 00000E9C 31C0 .in_rm: xor ax,ax ; Back in real mode 2568 00000E9E 8ED0 mov ss,ax 2569 00000EA0 07 pop es 2570 00000EA1 1F pop ds 2571 00000EA2 0FA1 pop fs 2572 00000EA4 0FA9 pop gs 2573 00000EA6 E8AD00 call disable_a20 2574 2575 00000EA9 9D popf ; Re-enables interrupts 2576 00000EAA 6658 pop eax 2577 00000EAC C3 ret 2578 2579 ; 2580 ; Routines to enable and disable (yuck) A20. These routines are gathered 2581 ; from tips from a couple of sources, including the Linux kernel and 2582 ; http://www.x86.org/. The need for the delay to be as large as given here 2583 ; is indicated by Donnie Barnes of RedHat, the problematic system being an 2584 ; IBM ThinkPad 760EL. 2585 ; 2586 ; We typically toggle A20 twice for every 64K transferred. 2587 ; 2588 %define io_delay call _io_delay 2589 %define IO_DELAY_PORT 80h ; Invalid port (we hope!) 2590 %define disable_wait 32 ; How long to wait for a disable 2591 2592 %define A20_DUNNO 0 ; A20 type unknown 2593 %define A20_NONE 1 ; A20 always on? 2594 %define A20_BIOS 2 ; A20 BIOS enable 2595 %define A20_KBC 3 ; A20 through KBC 2596 %define A20_FAST 4 ; A20 through port 92h 2597 2598 00000EAD EE slow_out: out dx, al ; Fall through 2599 2600 00000EAE E680 _io_delay: out IO_DELAY_PORT,al 2601 00000EB0 E680 out IO_DELAY_PORT,al 2602 00000EB2 C3 ret 2603 2604 enable_a20: 2605 00000EB3 6660 pushad 2606 00000EB5 2EC6064155FF mov byte [cs:A20Tries],255 ; Times to try to make this work 2607 2608 try_enable_a20: 2609 ; 2610 ; Flush the caches 2611 ; 2612 ; call try_wbinvd 2613 2614 ; 2615 ; If the A20 type is known, jump straight to type 2616 ; 2617 00000EBB 2E8B2E[EC1C] mov bp,[cs:A20Type] 2618 00000EC0 01ED add bp,bp ; Convert to word offset 2619 00000EC2 2EFFA6[D81C] jmp word [cs:bp+A20List] 2620 2621 ; 2622 ; First, see if we are on a system with no A20 gate 2623 ; 2624 a20_dunno: 2625 a20_none: 2626 00000EC7 2EC606[EC1C]01 mov byte [cs:A20Type], A20_NONE 2627 00000ECD E86400 call a20_test 2628 00000ED0 755F jnz a20_done 2629 2630 ; 2631 ; Next, try the BIOS (INT 15h AX=2401h) 2632 ; 2633 a20_bios: 2634 00000ED2 2EC606[EC1C]02 mov byte [cs:A20Type], A20_BIOS 2635 00000ED8 B80124 mov ax,2401h 2636 00000EDB 9C pushf ; Some BIOSes muck with IF 2637 00000EDC CD15 int 15h 2638 00000EDE 9D popf 2639 2640 00000EDF E85200 call a20_test 2641 00000EE2 754D jnz a20_done 2642 2643 ; 2644 ; Enable the keyboard controller A20 gate 2645 ; 2646 a20_kbc: 2647 00000EE4 B201 mov dl, 1 ; Allow early exit 2648 00000EE6 E8AE00 call empty_8042 2649 00000EE9 7546 jnz a20_done ; A20 live, no need to use KBC 2650 2651 00000EEB 2EC606[EC1C]03 mov byte [cs:A20Type], A20_KBC ; Starting KBC command sequence 2652 2653 00000EF1 B0D1 mov al,0D1h ; Command write 2654 00000EF3 E664 out 064h, al 2655 00000EF5 E89D00 call empty_8042_uncond 2656 2657 00000EF8 B0DF mov al,0DFh ; A20 on 2658 00000EFA E660 out 060h, al 2659 00000EFC E89600 call empty_8042_uncond 2660 2661 ; Verify that A20 actually is enabled. Do that by 2662 ; observing a word in low memory and the same word in 2663 ; the HMA until they are no longer coherent. Note that 2664 ; we don't do the same check in the disable case, because 2665 ; we don't want to *require* A20 masking (SYSLINUX should 2666 ; work fine without it, if the BIOS does.) 2667 00000EFF 51 .kbc_wait: push cx 2668 00000F00 31C9 xor cx,cx 2669 .kbc_wait_loop: 2670 00000F02 E82F00 call a20_test 2671 00000F05 7529 jnz a20_done_pop 2672 00000F07 E2F9 loop .kbc_wait_loop 2673 2674 00000F09 59 pop cx 2675 ; 2676 ; Running out of options here. Final attempt: enable the "fast A20 gate" 2677 ; 2678 a20_fast: 2679 00000F0A 2EC606[EC1C]04 mov byte [cs:A20Type], A20_FAST ; Haven't used the KBC yet 2680 00000F10 E492 in al, 092h 2681 00000F12 0C02 or al,02h 2682 00000F14 24FE and al,~01h ; Don't accidentally reset the machine! 2683 00000F16 E692 out 092h, al 2684 2685 00000F18 51 .fast_wait: push cx 2686 00000F19 31C9 xor cx,cx 2687 .fast_wait_loop: 2688 00000F1B E81600 call a20_test 2689 00000F1E 7510 jnz a20_done_pop 2690 00000F20 E2F9 loop .fast_wait_loop 2691 2692 00000F22 59 pop cx 2693 2694 ; 2695 ; Oh bugger. A20 is not responding. Try frobbing it again; eventually give up 2696 ; and report failure to the user. 2697 ; 2698 2699 2700 00000F23 2EFE0E4155 dec byte [cs:A20Tries] 2701 00000F28 7591 jnz try_enable_a20 2702 2703 00000F2A BE[EF1B] mov si, err_a20 2704 00000F2D E91B01 jmp abort_load 2705 ; 2706 ; A20 unmasked, proceed... 2707 ; 2708 00000F30 59 a20_done_pop: pop cx 2709 00000F31 6661 a20_done: popad 2710 00000F33 C3 ret 2711 2712 ; 2713 ; This routine tests if A20 is enabled (ZF = 0). This routine 2714 ; must not destroy any register contents. 2715 ; 2716 a20_test: 2717 00000F34 06 push es 2718 00000F35 51 push cx 2719 00000F36 50 push ax 2720 00000F37 B9FFFF mov cx,0FFFFh ; HMA = segment 0FFFFh 2721 00000F3A 8EC1 mov es,cx 2722 00000F3C B92000 mov cx,32 ; Loop count 2723 00000F3F 2EA12C55 mov ax,[cs:A20Test] 2724 00000F43 40 .a20_wait: inc ax 2725 00000F44 2EA32C55 mov [cs:A20Test],ax 2726 00000F48 E863FF io_delay ; Serialize, and fix delay 2727 00000F4B 263B063C55 cmp ax,[es:A20Test+10h] 2728 00000F50 E1F1 loopz .a20_wait 2729 00000F52 58 .a20_done: pop ax 2730 00000F53 59 pop cx 2731 00000F54 07 pop es 2732 00000F55 C3 ret 2733 2734 disable_a20: 2735 00000F56 6660 pushad 2736 ; 2737 ; Flush the caches 2738 ; 2739 ; call try_wbinvd 2740 2741 00000F58 2E8B2E[EC1C] mov bp,[cs:A20Type] 2742 00000F5D 01ED add bp,bp ; Convert to word offset 2743 00000F5F 2EFFA6[E21C] jmp word [cs:bp+A20DList] 2744 2745 a20d_bios: 2746 00000F64 B80024 mov ax,2400h 2747 00000F67 9C pushf ; Some BIOSes muck with IF 2748 00000F68 CD15 int 15h 2749 00000F6A 9D popf 2750 00000F6B EB19 jmp short a20d_snooze 2751 2752 ; 2753 ; Disable the "fast A20 gate" 2754 ; 2755 a20d_fast: 2756 00000F6D E492 in al, 092h 2757 00000F6F 24FC and al,~03h 2758 00000F71 E692 out 092h, al 2759 00000F73 EB11 jmp short a20d_snooze 2760 2761 ; 2762 ; Disable the keyboard controller A20 gate 2763 ; 2764 a20d_kbc: 2765 00000F75 E81D00 call empty_8042_uncond 2766 00000F78 B0D1 mov al,0D1h 2767 00000F7A E664 out 064h, al ; Command write 2768 00000F7C E81600 call empty_8042_uncond 2769 00000F7F B0DD mov al,0DDh ; A20 off 2770 00000F81 E660 out 060h, al 2771 00000F83 E80F00 call empty_8042_uncond 2772 ; Wait a bit for it to take effect 2773 a20d_snooze: 2774 00000F86 51 push cx 2775 00000F87 B92000 mov cx, disable_wait 2776 00000F8A E8A7FF .delayloop: call a20_test 2777 00000F8D 7402 jz .disabled 2778 00000F8F E2F9 loop .delayloop 2779 00000F91 59 .disabled: pop cx 2780 a20d_dunno: 2781 a20d_none: 2782 00000F92 6661 popad 2783 00000F94 C3 ret 2784 2785 ; 2786 ; Routine to empty the 8042 KBC controller. If dl != 0 2787 ; then we will test A20 in the loop and exit if A20 is 2788 ; suddenly enabled. 2789 ; 2790 empty_8042_uncond: 2791 00000F95 30D2 xor dl,dl 2792 empty_8042: 2793 00000F97 E89AFF call a20_test 2794 00000F9A 7404 jz .a20_on 2795 00000F9C 20D2 and dl,dl 2796 00000F9E 7517 jnz .done 2797 00000FA0 E80BFF .a20_on: io_delay 2798 00000FA3 E464 in al, 064h ; Status port 2799 00000FA5 A801 test al,1 2800 00000FA7 7407 jz .no_output 2801 00000FA9 E802FF io_delay 2802 00000FAC E460 in al, 060h ; Read input 2803 00000FAE EBE7 jmp short empty_8042 2804 .no_output: 2805 00000FB0 A802 test al,2 2806 00000FB2 75E3 jnz empty_8042 2807 00000FB4 E8F7FE io_delay 2808 00000FB7 C3 .done: ret 2809 2810 ; 2811 ; WBINVD instruction; gets auto-eliminated on 386 CPUs 2812 ; 2813 try_wbinvd: 2814 00000FB8 0F09 wbinvd 2815 00000FBA C3 ret 2816 2817 ; 2818 ; Load RAM disk into high memory 2819 ; 2820 loadinitrd: 2821 00000FBB 06 push es ; Save ES on entry 2822 00000FBC B80070 mov ax,real_mode_seg 2823 00000FBF 8EC0 mov es,ax 2824 00000FC1 8B36[CE1C] mov si,[initrd_ptr] 2825 00000FC5 668B3ED454 mov edi,[InitRDat] ; initrd load address 2826 00000FCA 2666893E1802 mov [es:su_ramdiskat],edi ; Offset for ram disk 2827 00000FD0 56 push si 2828 00000FD1 BE6755 mov si,InitRDCName ; Write ramdisk name 2829 00000FD4 E89D03 call cwritestr 2830 00000FD7 BE[611C] mov si,dotdot_msg ; Write dots 2831 00000FDA E89703 call cwritestr 2832 rd_load_loop: 2833 00000FDD BE[621C] mov si,dot_msg ; Progress report 2834 00000FE0 E89103 call cwritestr 2835 00000FE3 5E pop si ; Restore cluster pointer 2836 00000FE4 E85000 call abort_check 2837 00000FE7 8B0E1655 mov cx,[InitRDClust] 2838 00000FEB 3B0E1855 cmp cx,[ClustPerMoby] 2839 00000FEF 7604 jna rd_last_moby 2840 00000FF1 8B0E1855 mov cx,[ClustPerMoby] 2841 rd_last_moby: 2842 00000FF5 290E1655 sub [InitRDClust],cx 2843 00000FF9 31DB xor bx,bx ; Load at offset 0 2844 00000FFB 680030 push word xfer_buf_seg ; Bounce buffer segment 2845 00000FFE 07 pop es 2846 00000FFF 51 push cx 2847 00001000 E823F3 call getfssec 2848 00001003 59 pop cx 2849 00001004 56 push si ; Save cluster pointer 2850 00001005 66BE00000300 mov esi,(xfer_buf_seg << 4) 2851 0000100B 668B3ED454 mov edi,[InitRDat] 2852 00001010 66B900400000 mov ecx,4000h ; Copy 64K 2853 00001016 E83FFE call bcopy ; Does not change flags!! 2854 00001019 7210 jc rd_load_done ; EOF? 2855 0000101B 668106D45400000100 add dword [InitRDat],10000h ; Point to next 64K 2856 00001024 833E165500 cmp word [InitRDClust],byte 0 ; Are we done? 2857 00001029 75B2 jne rd_load_loop ; Apparently not 2858 rd_load_done: 2859 0000102B 5E pop si ; Clean up the stack 2860 0000102C E84203 call crlf 2861 0000102F BE[581C] mov si,loading_msg ; Write new "Loading " for 2862 00001032 E83F03 call cwritestr ; the benefit of the kernel 2863 00001035 07 pop es ; Restore original ES 2864 00001036 C3 ret 2865 2866 ; 2867 ; abort_check: let the user abort with or 2868 ; 2869 abort_check: 2870 00001037 E84D03 call pollchar 2871 0000103A 7423 jz ac_ret1 2872 0000103C 60 pusha 2873 0000103D E86003 call getchar 2874 00001040 3C1B cmp al,27 ; 2875 00001042 7404 je ac_kill 2876 00001044 3C03 cmp al,3 ; 2877 00001046 7516 jne ac_ret2 2878 00001048 BE[641C] ac_kill: mov si,aborted_msg 2879 2880 ; 2881 ; abort_load: Called by various routines which wants to print a fatal 2882 ; error message and return to the command prompt. Since this 2883 ; may happen at just about any stage of the boot process, assume 2884 ; our state is messed up, and just reset the segment registers 2885 ; and the stack forcibly. 2886 ; 2887 ; SI = offset (in _text) of error message to print 2888 ; 2889 abort_load: 2890 0000104B 8CC8 mov ax,cs ; Restore CS = DS = ES 2891 0000104D 8ED8 mov ds,ax 2892 0000104F 8EC0 mov es,ax 2893 00001051 FA cli 2894 00001052 BCFA4F mov sp,StackBuf-2*3 ; Reset stack 2895 00001055 8ED0 mov ss,ax ; Just in case... 2896 00001057 FB sti 2897 00001058 E81903 call cwritestr ; Expects SI -> error msg 2898 0000105B E94DF6 al_ok: jmp enter_command ; Return to command prompt 2899 ; 2900 ; End of abort_check 2901 ; 2902 0000105E 61 ac_ret2: popa 2903 0000105F C3 ac_ret1: ret 2904 2905 ; 2906 ; searchdir: Search the root directory for a pre-mangled filename in 2907 ; DS:DI. This routine is similar to the one in the boot 2908 ; sector, but is a little less Draconian when it comes to 2909 ; error handling, plus it reads the root directory in 2910 ; larger chunks than a sector at a time (which is probably 2911 ; a waste of coding effort, but I like to do things right). 2912 ; 2913 ; FIXME: usually we can load the entire root dir in memory, 2914 ; and files are usually at the beginning anyway. It probably 2915 ; would be worthwhile to remember if we have the first chunk 2916 ; in memory and skip the load if that (it would speed up online 2917 ; help, mainly.) 2918 ; 2919 ; NOTE: This file considers finding a zero-length file an 2920 ; error. This is so we don't have to deal with that special 2921 ; case elsewhere in the program (most loops have the test 2922 ; at the end). 2923 ; 2924 ; If successful: 2925 ; ZF clear 2926 ; SI = cluster # for the first cluster 2927 ; DX:AX = file length in bytes 2928 ; If unsuccessful 2929 ; ZF set 2930 ; 2931 2932 searchdir: 2933 00001060 A1[1100] mov ax,[bsRootDirEnts] 2934 00001063 A3FE54 mov [DirScanCtr],ax 2935 00001066 A1FC54 mov ax,[RootDirSize] 2936 00001069 A30055 mov [DirBlocksLeft],ax 2937 0000106C A1F054 mov ax,[RootDir1] 2938 0000106F 8B16F254 mov dx,[RootDir2] 2939 scan_group: 2940 00001073 8B2E0055 mov bp,[DirBlocksLeft] 2941 00001077 21ED and bp,bp 2942 00001079 7467 jz dir_return 2943 0000107B 3B2E0E55 cmp bp,[BufSafeSec] 2944 0000107F 7604 jna load_last 2945 00001081 8B2E0E55 mov bp,[BufSafeSec] 2946 load_last: 2947 00001085 292E0055 sub [DirBlocksLeft],bp 2948 00001089 50 push ax 2949 0000108A 52 push dx 2950 0000108B A1[0B00] mov ax,[bsBytesPerSec] 2951 0000108E F7E5 mul bp 2952 00001090 05E10F add ax,trackbuf-31 2953 00001093 A30255 mov [EndofDirSec],ax ; End of loaded 2954 00001096 5A pop dx 2955 00001097 58 pop ax 2956 00001098 55 push bp ; Save number of sectors 2957 00001099 50 push ax ; Save present location 2958 0000109A 52 push dx 2959 0000109B 57 push di ; Save name 2960 0000109C BB0010 mov bx,trackbuf 2961 0000109F E8D2F0 call getlinsec 2962 000010A2 5F pop di 2963 000010A3 5A pop dx 2964 000010A4 58 pop ax 2965 000010A5 5D pop bp 2966 000010A6 BE0010 mov si,trackbuf 2967 000010A9 803C00 dir_test_name: cmp byte [si],0 ; Directory high water mark 2968 000010AC 7434 je dir_return ; Failed 2969 000010AE F6440B18 test byte [si+11],18h ; Check it really is a file 2970 000010B2 750B jnz dir_not_this 2971 000010B4 57 push di 2972 000010B5 56 push si 2973 000010B6 B90B00 mov cx,11 ; Filename = 11 bytes 2974 000010B9 F3A6 repe cmpsb 2975 000010BB 5E pop si 2976 000010BC 5F pop di 2977 000010BD 7416 je dir_success 2978 000010BF 83C620 dir_not_this: add si,byte 32 2979 000010C2 FF0EFE54 dec word [DirScanCtr] 2980 000010C6 741A jz dir_return ; Out of it... 2981 000010C8 3B360255 cmp si,[EndofDirSec] 2982 000010CC 72DB jb dir_test_name 2983 000010CE 01E8 add ax,bp ; Increment linear sector number 2984 000010D0 83D200 adc dx,byte 0 2985 000010D3 EB9E jmp short scan_group 2986 dir_success: 2987 000010D5 8B441C mov ax,[si+28] ; Length of file 2988 000010D8 8B541E mov dx,[si+30] 2989 000010DB 8B741A mov si,[si+26] ; Cluster pointer 2990 000010DE 89C3 mov bx,ax 2991 000010E0 09D3 or bx,dx ; Sets ZF iff DX:AX is zero 2992 dir_return: 2993 000010E2 C3 lf_ret: ret 2994 2995 ; 2996 ; loadfont: Load a .psf font file and install it onto the VGA console 2997 ; (if we're not on a VGA screen then ignore.) It is called with 2998 ; SI and DX:AX set by routine searchdir 2999 ; 3000 loadfont: 3001 000010E3 BB0010 mov bx,trackbuf ; The trackbuf is >= 16K; the part 3002 000010E6 8B0E0C55 mov cx,[BufSafe] ; of a PSF file we care about is no 3003 000010EA E839F2 call getfssec ; more than 8K+4 bytes 3004 3005 000010ED A10010 mov ax,[trackbuf] ; Magic number 3006 000010F0 3D3604 cmp ax,0436h 3007 000010F3 75ED jne lf_ret 3008 3009 000010F5 A00210 mov al,[trackbuf+2] ; File mode 3010 000010F8 3C05 cmp al,5 ; Font modes 0-5 supported 3011 000010FA 77E6 ja lf_ret 3012 3013 000010FC 8A3E0310 mov bh,byte [trackbuf+3] ; Height of font 3014 00001100 80FF02 cmp bh,2 ; VGA minimum 3015 00001103 72DD jb lf_ret 3016 00001105 80FF20 cmp bh,32 ; VGA maximum 3017 00001108 77D8 ja lf_ret 3018 3019 ; Copy to font buffer 3020 0000110A BE0410 mov si,trackbuf+4 ; Start of font data 3021 0000110D 883E[EE1C] mov [VGAFontSize],bh 3022 00001111 BF00E0 mov di,vgafontbuf 3023 00001114 B90008 mov cx,(32*256) >> 2 ; Maximum size 3024 00001117 F366A5 rep movsd 3025 3026 ; Fall through to use_font 3027 3028 ; 3029 ; use_font: 3030 ; This routine activates whatever font happens to be in the 3031 ; vgafontbuf, and updates the adjust_screen data. 3032 ; 3033 use_font: 3034 0000111A BD00E0 mov bp,vgafontbuf 3035 0000111D 8A3E[EE1C] mov bh,[VGAFontSize] 3036 3037 00001121 30DB xor bl,bl ; Needed by both INT 10h calls 3038 00001123 803E[4118]01 cmp [UsingVGA], byte 1 ; Are we in graphics mode? 3039 00001128 7520 jne .text 3040 3041 .graphics: 3042 0000112A 31C9 xor cx,cx 3043 0000112C 88F9 mov cl,bh ; CX = bytes/character 3044 0000112E B8E001 mov ax,480 3045 00001131 F6F1 div cl ; Compute char rows per screen 3046 00001133 88C2 mov dl,al 3047 00001135 FEC8 dec al 3048 00001137 A23D55 mov [VidRows],al 3049 0000113A B82111 mov ax,1121h ; Set user character table 3050 0000113D CD10 int 10h 3051 0000113F C6063C554F mov [VidCols], byte 79 ; Always 80 bytes/line 3052 00001144 C606395500 mov [TextPage], byte 0 ; Always page 0 3053 00001149 C3 ret ; No need to call adjust_screen 3054 3055 .text: 3056 0000114A B90001 mov cx,256 3057 0000114D 31D2 xor dx,dx 3058 0000114F B81011 mov ax,1110h 3059 00001152 CD10 int 10h ; Load into VGA RAM 3060 3061 00001154 30DB xor bl,bl 3062 00001156 B80311 mov ax,1103h ; Select page 0 3063 00001159 CD10 int 10h 3064 3065 ; Fall through to adjust_screen 3066 3067 ; 3068 ; adjust_screen: Set the internal variables associated with the screen size. 3069 ; This is a subroutine in case we're loading a custom font. 3070 ; 3071 adjust_screen: 3072 0000115B A08404 mov al,[BIOS_vidrows] 3073 0000115E 20C0 and al,al 3074 00001160 7502 jnz vidrows_is_ok 3075 00001162 B018 mov al,24 ; No vidrows in BIOS, assume 25 3076 ; (Remember: vidrows == rows-1) 3077 00001164 A23D55 vidrows_is_ok: mov [VidRows],al 3078 00001167 B40F mov ah,0fh 3079 00001169 CD10 int 10h ; Read video state 3080 0000116B 883E3955 mov [TextPage],bh 3081 0000116F FECC dec ah ; Store count-1 (same as rows) 3082 00001171 88263C55 mov [VidCols],ah 3083 00001175 C3 ret 3084 3085 ; 3086 ; loadkeys: Load a LILO-style keymap; SI and DX:AX set by searchdir 3087 ; 3088 loadkeys: 3089 00001176 21D2 and dx,dx ; Should be 256 bytes exactly 3090 00001178 751A jne loadkeys_ret 3091 0000117A 3D0001 cmp ax,256 3092 0000117D 7515 jne loadkeys_ret 3093 3094 0000117F BB0010 mov bx,trackbuf 3095 00001182 B90100 mov cx,1 ; 1 cluster should be >= 256 bytes 3096 00001185 E89EF1 call getfssec 3097 3098 00001188 BE0010 mov si,trackbuf 3099 0000118B BF0053 mov di,KbdMap 3100 0000118E B94000 mov cx,256 >> 2 3101 00001191 F366A5 rep movsd 3102 3103 00001194 C3 loadkeys_ret: ret 3104 3105 ; 3106 ; get_msg_file: Load a text file and write its contents to the screen, 3107 ; interpreting color codes. Is called with SI and DX:AX 3108 ; set by routine searchdir 3109 ; 3110 get_msg_file: 3111 00001195 06 push es 3112 00001196 66C1E210 shl edx,16 ; EDX <- DX:AX (length of file) 3113 0000119A 89C2 mov dx,ax 3114 0000119C B80030 mov ax,xfer_buf_seg ; Use for temporary storage 3115 0000119F 8EC0 mov es,ax 3116 3117 000011A1 C606385507 mov byte [TextAttribute],07h ; Default grey on white 3118 000011A6 C606435507 mov byte [DisplayMask],07h ; Display text in all modes 3119 000011AB E86001 call msg_initvars 3120 3121 000011AE 6652 get_msg_chunk: push edx ; EDX = length of file 3122 000011B0 31DB xor bx,bx ; == xbs_textbuf 3123 000011B2 8B0E0C55 mov cx,[BufSafe] 3124 000011B6 E86DF1 call getfssec 3125 000011B9 665A pop edx 3126 000011BB 56 push si ; Save current cluster 3127 000011BC 31F6 xor si,si ; == xbs_textbuf 3128 000011BE 8B0E1055 mov cx,[BufSafeBytes] ; Number of bytes left in chunk 3129 print_msg_file: 3130 000011C2 51 push cx 3131 000011C3 6652 push edx 3132 000011C5 26AC es lodsb 3133 000011C7 3C1A cmp al,1Ah ; DOS EOF? 3134 000011C9 7418 je msg_done_pop 3135 000011CB 56 push si 3136 000011CC 8A0E[4118] mov cl,[UsingVGA] 3137 000011D0 FEC1 inc cl ; 01h = text mode, 02h = graphics 3138 000011D2 FF162655 call [NextCharJump] ; Do what shall be done 3139 000011D6 5E pop si 3140 000011D7 665A pop edx 3141 000011D9 59 pop cx 3142 000011DA 664A dec edx 3143 000011DC 7408 jz msg_done 3144 000011DE E2E2 loop print_msg_file 3145 000011E0 5E pop si 3146 000011E1 EBCB jmp short get_msg_chunk 3147 msg_done_pop: 3148 000011E3 83C406 add sp,byte 6 ; Drop pushed EDX, CX 3149 msg_done: 3150 000011E6 5E pop si 3151 000011E7 07 pop es 3152 000011E8 C3 ret 3153 msg_putchar: ; Normal character 3154 000011E9 3C0F cmp al,0Fh ; ^O = color code follows 3155 000011EB 744E je msg_ctrl_o 3156 000011ED 3C0D cmp al,0Dh ; Ignore 3157 000011EF 7449 je msg_ignore 3158 000011F1 3C0A cmp al,0Ah ; = newline 3159 000011F3 744D je msg_newline 3160 000011F5 3C0C cmp al,0Ch ; = clear screen 3161 000011F7 747E je msg_formfeed 3162 000011F9 3C19 cmp al,19h ; = return to text mode 3163 000011FB 0F84F300 je near msg_novga 3164 000011FF 3C18 cmp al,18h ; = VGA filename follows 3165 00001201 0F84BC00 je near msg_vga 3166 00001205 7306 jnb .not_modectl 3167 00001207 3C10 cmp al,10h ; 10h to 17h are mode controls 3168 00001209 0F831101 jae near msg_modectl 3169 .not_modectl: 3170 3171 0000120D E81501 msg_normal: call write_serial_displaymask ; Write to serial port 3172 00001210 840E4355 test [DisplayMask],cl 3173 00001214 7424 jz msg_ignore ; Not screen 3174 00001216 8B1E3855 mov bx,[TextAttrBX] 3175 0000121A B409 mov ah,09h ; Write character/attribute 3176 0000121C B90100 mov cx,1 ; One character only 3177 0000121F CD10 int 10h ; Write to screen 3178 00001221 A03A55 mov al,[CursorCol] 3179 00001224 40 inc ax 3180 00001225 3A063C55 cmp al,[VidCols] 3181 00001229 771D ja msg_line_wrap ; Screen wraparound 3182 0000122B A23A55 mov [CursorCol],al 3183 3184 0000122E 8A3E3955 msg_gotoxy: mov bh,[TextPage] 3185 00001232 8B163A55 mov dx,[CursorDX] 3186 00001236 B402 mov ah,02h ; Set cursor position 3187 00001238 CD10 int 10h 3188 0000123A C3 msg_ignore: ret 3189 msg_ctrl_o: ; ^O = color code follows 3190 0000123B C7062655[9812] mov word [NextCharJump],msg_setbg 3191 00001241 C3 ret 3192 msg_newline: ; Newline char or end of line 3193 00001242 BE[6D1C] mov si,crlf_msg 3194 00001245 E80401 call write_serial_str_displaymask 3195 msg_line_wrap: ; Screen wraparound 3196 00001248 840E4355 test [DisplayMask],cl 3197 0000124C 74EC jz msg_ignore 3198 0000124E C6063A5500 mov byte [CursorCol],0 3199 00001253 A03B55 mov al,[CursorRow] 3200 00001256 40 inc ax 3201 00001257 3A063D55 cmp al,[VidRows] 3202 0000125B 7705 ja msg_scroll 3203 0000125D A23B55 mov [CursorRow],al 3204 00001260 EBCC jmp short msg_gotoxy 3205 00001262 31C9 msg_scroll: xor cx,cx ; Upper left hand corner 3206 00001264 8B163C55 mov dx,[ScreenSize] 3207 00001268 88363B55 mov [CursorRow],dh ; New cursor at the bottom 3208 0000126C 8A3E[F01C] mov bh,[ScrollAttribute] 3209 00001270 B80106 mov ax,0601h ; Scroll up one line 3210 00001273 CD10 int 10h 3211 00001275 EBB7 jmp short msg_gotoxy 3212 msg_formfeed: ; Form feed character 3213 00001277 BE[701C] mov si,crff_msg 3214 0000127A E8CF00 call write_serial_str_displaymask 3215 0000127D 840E4355 test [DisplayMask],cl 3216 00001281 74B7 jz msg_ignore 3217 00001283 31C9 xor cx,cx 3218 00001285 890E3A55 mov [CursorDX],cx ; Upper lefthand corner 3219 00001289 8B163C55 mov dx,[ScreenSize] 3220 0000128D 8A3E3855 mov bh,[TextAttribute] 3221 00001291 B80006 mov ax,0600h ; Clear screen region 3222 00001294 CD10 int 10h 3223 00001296 EB96 jmp short msg_gotoxy 3224 msg_setbg: ; Color background character 3225 00001298 E8D102 call unhexchar 3226 0000129B 722F jc msg_color_bad 3227 0000129D C0E004 shl al,4 3228 000012A0 840E4355 test [DisplayMask],cl 3229 000012A4 7403 jz .dontset 3230 000012A6 A23855 mov [TextAttribute],al 3231 .dontset: 3232 000012A9 C7062655[B012] mov word [NextCharJump],msg_setfg 3233 000012AF C3 ret 3234 msg_setfg: ; Color foreground character 3235 000012B0 E8B902 call unhexchar 3236 000012B3 7217 jc msg_color_bad 3237 000012B5 840E4355 test [DisplayMask],cl 3238 000012B9 7404 jz .dontset 3239 000012BB 08063855 or [TextAttribute],al ; setbg set foreground to 0 3240 .dontset: 3241 000012BF EB10 jmp short msg_putcharnext 3242 msg_vga: 3243 000012C1 C7062655[D812] mov word [NextCharJump],msg_filename 3244 000012C7 BF8555 mov di, VGAFileBuf 3245 000012CA EB21 jmp short msg_setvgafileptr 3246 3247 msg_color_bad: 3248 000012CC C606385507 mov byte [TextAttribute],07h ; Default attribute 3249 msg_putcharnext: 3250 000012D1 C7062655[E911] mov word [NextCharJump],msg_putchar 3251 000012D7 C3 ret 3252 3253 msg_filename: ; Getting VGA filename 3254 000012D8 3C0A cmp al,0Ah ; = end of filename 3255 000012DA 741B je msg_viewimage 3256 000012DC 3C20 cmp al,' ' 3257 000012DE 7611 jbe msg_ret ; Ignore space/control char 3258 000012E0 8B3E3655 mov di,[VGAFilePtr] 3259 000012E4 81FF9255 cmp di,VGAFileBufEnd 3260 000012E8 7307 jnb msg_ret 3261 000012EA 8805 mov [di],al ; Can't use stosb (DS:) 3262 000012EC 47 inc di 3263 msg_setvgafileptr: 3264 000012ED 893E3655 mov [VGAFilePtr],di 3265 000012F1 C3 msg_ret: ret 3266 3267 msg_novga: 3268 000012F2 E8FB04 call vgaclearmode 3269 000012F5 EB17 jmp short msg_initvars 3270 3271 msg_viewimage: 3272 000012F7 06 push es 3273 000012F8 1E push ds 3274 000012F9 07 pop es ; ES <- DS 3275 000012FA BE8555 mov si,VGAFileBuf 3276 000012FD BF9255 mov di,VGAFileMBuf 3277 00001300 57 push di 3278 00001301 E8BF02 call mangle_name 3279 00001304 5F pop di 3280 00001305 E858FD call searchdir 3281 00001308 07 pop es 3282 00001309 74C6 jz msg_putcharnext ; Not there 3283 0000130B E85C03 call vgadisplayfile 3284 ; Fall through 3285 3286 ; Subroutine to initialize variables, also needed 3287 ; after loading a graphics file 3288 msg_initvars: 3289 0000130E 60 pusha 3290 0000130F 8A3E3955 mov bh,[TextPage] 3291 00001313 B403 mov ah,03h ; Read cursor position 3292 00001315 CD10 int 10h 3293 00001317 89163A55 mov [CursorDX],dx 3294 0000131B 61 popa 3295 0000131C EBB3 jmp short msg_putcharnext ; Initialize state machine 3296 3297 msg_modectl: 3298 0000131E 2407 and al,07h 3299 00001320 A24355 mov [DisplayMask],al 3300 00001323 EBAC jmp short msg_putcharnext 3301 3302 ; 3303 ; write_serial: If serial output is enabled, write character on serial port 3304 ; write_serial_displaymask: d:o, but ignore if DisplayMask & 04h == 0 3305 ; 3306 write_serial_displaymask: 3307 00001325 F606435504 test byte [DisplayMask], 04h 3308 0000132A 741F jz write_serial.end 3309 write_serial: 3310 0000132C 669C pushfd 3311 0000132E 6660 pushad 3312 00001330 8B1E[D61C] mov bx,[SerialPort] 3313 00001334 21DB and bx,bx 3314 00001336 740F je .noserial 3315 00001338 50 push ax 3316 00001339 8D5705 .waitspace: lea dx,[bx+5] ; Wait for space in transmit reg 3317 0000133C EC in al,dx 3318 0000133D A820 test al,20h 3319 0000133F 74F8 jz .waitspace 3320 00001341 87D3 xchg dx,bx 3321 00001343 58 pop ax 3322 00001344 E866FB call slow_out ; Send data 3323 00001347 6661 .noserial: popad 3324 00001349 669D popfd 3325 0000134B C3 .end: ret 3326 3327 ; 3328 ; write_serial_str: write_serial for strings 3329 ; write_serial_str_displaymask: d:o, but ignore if DisplayMask & 04h == 0 3330 ; 3331 write_serial_str_displaymask: 3332 0000134C F606435504 test byte [DisplayMask], 04h 3333 00001351 740A jz write_serial_str.end 3334 3335 write_serial_str: 3336 00001353 AC .loop lodsb 3337 00001354 20C0 and al,al 3338 00001356 7405 jz .end 3339 00001358 E8D1FF call write_serial 3340 0000135B EBF6 jmp short .loop 3341 0000135D C3 .end: ret 3342 3343 ; 3344 ; writechr: Write a single character in AL to the console without 3345 ; mangling any registers 3346 ; 3347 writechr: 3348 0000135E E8CBFF call write_serial ; write to serial port if needed 3349 00001361 669C pushfd 3350 00001363 6660 pushad 3351 00001365 B40E mov ah,0Eh 3352 00001367 BB0700 mov bx,0007h ; white text on this page 3353 0000136A CD10 int 10h 3354 0000136C 6661 popad 3355 0000136E 669D popfd 3356 00001370 C3 ret 3357 3358 ; 3359 ; crlf: Print a newline 3360 ; 3361 00001371 BE[6D1C] crlf: mov si,crlf_msg 3362 ; Fall through 3363 3364 ; 3365 ; cwritestr: write a null-terminated string to the console, saving 3366 ; registers on entry. 3367 ; 3368 cwritestr: 3369 00001374 669C pushfd 3370 00001376 6660 pushad 3371 00001378 AC .top: lodsb 3372 00001379 20C0 and al,al 3373 0000137B 7405 jz .end 3374 0000137D E8DEFF call writechr 3375 00001380 EBF6 jmp short .top 3376 00001382 6661 .end: popad 3377 00001384 669D popfd 3378 00001386 C3 ret 3379 3380 %ifdef debug 3381 3382 ; 3383 ; writehex[248]: Write a hex number in (AL, AX, EAX) to the console 3384 ; 3385 writehex2: 3386 pushfd 3387 pushad 3388 rol eax,24 3389 mov cx,2 3390 jmp short writehex_common 3391 writehex4: 3392 pushfd 3393 pushad 3394 rol eax,16 3395 mov cx,4 3396 jmp short writehex_common 3397 writehex8: 3398 pushfd 3399 pushad 3400 mov cx,8 3401 writehex_common: 3402 .loop: rol eax,4 3403 push eax 3404 and al,0Fh 3405 cmp al,10 3406 jae .high 3407 .low: add al,'0' 3408 jmp short .ischar 3409 .high: add al,'A'-10 3410 .ischar: call writechr 3411 pop eax 3412 loop .loop 3413 popad 3414 popfd 3415 ret 3416 3417 ; 3418 ; crlf: write CR LF 3419 ; 3420 crlf: push ax 3421 mov al, 13 3422 call writechr 3423 mov al, 10 3424 call writechr 3425 pop ax 3426 ret 3427 3428 %endif 3429 3430 ; 3431 ; pollchar: check if we have an input character pending (ZF = 0) 3432 ; 3433 pollchar: 3434 00001387 6660 pushad 3435 00001389 B401 mov ah,1 ; Poll keyboard 3436 0000138B CD16 int 16h 3437 0000138D 750E jnz .done ; Keyboard response 3438 0000138F 8B16[D61C] mov dx,[SerialPort] 3439 00001393 21D2 and dx,dx 3440 00001395 7406 jz .done ; No serial port -> no input 3441 00001397 83C205 add dx,byte 5 ; Serial status register 3442 0000139A EC in al,dx 3443 0000139B A801 test al,1 ; ZF = 0 if traffic 3444 0000139D 6661 .done: popad 3445 0000139F C3 ret 3446 3447 ; 3448 ; getchar: Read a character from keyboard or serial port 3449 ; 3450 getchar: 3451 000013A0 B401 .again: mov ah,1 ; Poll keyboard 3452 000013A2 CD16 int 16h 3453 000013A4 7516 jnz .kbd ; Keyboard input? 3454 000013A6 8B1E[D61C] mov bx,[SerialPort] 3455 000013AA 21DB and bx,bx 3456 000013AC 74F2 jz .again 3457 000013AE 8D5705 lea dx,[bx+5] ; Serial status register 3458 000013B1 EC in al,dx 3459 000013B2 A801 test al,1 3460 000013B4 74EA jz .again 3461 000013B6 30E4 .serial: xor ah,ah ; Avoid confusion 3462 000013B8 87D3 xchg dx,bx ; Data port 3463 000013BA EC in al,dx 3464 000013BB C3 ret 3465 000013BC 31C0 .kbd: xor ax,ax ; Get keyboard input 3466 000013BE CD16 int 16h 3467 000013C0 20C0 and al,al 3468 000013C2 7404 jz .func_key 3469 000013C4 BB0053 mov bx,KbdMap ; Convert character sets 3470 000013C7 D7 xlatb 3471 000013C8 C3 .func_key: ret 3472 3473 ; 3474 ; 3475 ; kaboom2: once everything is loaded, replace the part of kaboom 3476 ; starting with "kaboom.patch" with this part 3477 3478 kaboom2: 3479 000013C9 BE[0C1C] mov si,err_bootfailed 3480 000013CC E8A5FF call cwritestr 3481 000013CF E8CEFF call getchar 3482 000013D2 E81B04 call vgaclearmode 3483 000013D5 CD19 int 19h ; And try once more to boot... 3484 000013D7 EBFE .norge: jmp short .norge ; If int 19h returned; this is the end 3485 3486 ; 3487 ; open,getc: Load a file a character at a time for parsing in a manner 3488 ; similar to the C library getc routine. Only one simultaneous 3489 ; use is supported. Note: "open" trashes the trackbuf. 3490 ; 3491 ; open: Input: mangled filename in DS:DI 3492 ; Output: ZF set on file not found or zero length 3493 ; 3494 ; getc: Output: CF set on end of file 3495 ; Character loaded in AL 3496 ; 3497 open: 3498 000013D9 E884FC call searchdir 3499 000013DC 7427 jz open_return 3500 000013DE 9C pushf 3501 000013DF A3F854 mov [FBytes1],ax 3502 000013E2 8916FA54 mov [FBytes2],dx 3503 000013E6 03060655 add ax,[ClustSize] 3504 000013EA 83D200 adc dx,byte 0 3505 000013ED 83E801 sub ax,byte 1 3506 000013F0 83DA00 sbb dx,byte 0 3507 000013F3 F7360655 div word [ClustSize] 3508 000013F7 A31A55 mov [FClust],ax ; Number of clusters 3509 000013FA 89361C55 mov [FNextClust],si ; Cluster pointer 3510 000013FE A11255 mov ax,[EndOfGetCBuf] ; Pointer at end of buffer -> 3511 00001401 A31E55 mov [FPtr],ax ; nothing loaded yet 3512 00001404 9D popf ; Restore no ZF 3513 00001405 C3 open_return: ret 3514 3515 ; 3516 getc: 3517 00001406 F9 stc ; If we exit here -> EOF 3518 00001407 668B0EF854 mov ecx,[FBytes] 3519 0000140C 66E33B jecxz getc_ret 3520 0000140F 8B361E55 mov si,[FPtr] 3521 00001413 3B361255 cmp si,[EndOfGetCBuf] 3522 00001417 7226 jb getc_loaded 3523 ; Buffer empty -- load another set 3524 00001419 8B0E1A55 mov cx,[FClust] 3525 0000141D 3B0E0C55 cmp cx,[BufSafe] 3526 00001421 7604 jna getc_oksize 3527 00001423 8B0E0C55 mov cx,[BufSafe] 3528 00001427 290E1A55 getc_oksize: sub [FClust],cx ; Reduce remaining clusters 3529 0000142B 8B361C55 mov si,[FNextClust] 3530 0000142F BB009C mov bx,getcbuf 3531 00001432 53 push bx 3532 00001433 06 push es ; ES may be != DS, save old ES 3533 00001434 1E push ds ; Trackbuf is in DS, not ES 3534 00001435 07 pop es 3535 00001436 E8EDEE call getfssec ; Load a trackbuf full of data 3536 00001439 89361C55 mov [FNextClust],si ; Store new next pointer 3537 0000143D 07 pop es ; Restore ES 3538 0000143E 5E pop si ; SI -> newly loaded data 3539 0000143F AC getc_loaded: lodsb ; Load a byte 3540 00001440 89361E55 mov [FPtr],si ; Update next byte pointer 3541 00001444 66FF0EF854 dec dword [FBytes] ; Update bytes left counter (CF = 1) 3542 00001449 F8 clc ; Not EOF 3543 0000144A C3 getc_ret: ret 3544 3545 ; 3546 ; ungetc: Push a character (in AL) back into the getc buffer 3547 ; Note: if more than one byte is pushed back, this may cause 3548 ; bytes to be written below the getc buffer boundary. If there 3549 ; is a risk for this to occur, the getcbuf base address should 3550 ; be moved up. 3551 ; 3552 ungetc: 3553 0000144B 8B361E55 mov si,[FPtr] 3554 0000144F 4E dec si 3555 00001450 8804 mov [si],al 3556 00001452 89361E55 mov [FPtr],si 3557 00001456 66FF06F854 inc dword [FBytes] 3558 0000145B C3 ret 3559 3560 ; 3561 ; skipspace: Skip leading whitespace using "getc". If we hit end-of-line 3562 ; or end-of-file, return with carry set; ZF = true of EOF 3563 ; ZF = false for EOLN; otherwise CF = ZF = 0. 3564 ; 3565 ; Otherwise AL = first character after whitespace 3566 ; 3567 skipspace: 3568 0000145C E8A7FF skipspace_loop: call getc 3569 0000145F 720D jc skipspace_eof 3570 00001461 3C1A cmp al,1Ah ; DOS EOF 3571 00001463 7409 je skipspace_eof 3572 00001465 3C0A cmp al,0Ah 3573 00001467 7409 je skipspace_eoln 3574 00001469 3C20 cmp al,' ' 3575 0000146B 76EF jbe skipspace_loop 3576 0000146D C3 ret ; CF = ZF = 0 3577 0000146E 38C0 skipspace_eof: cmp al,al ; Set ZF 3578 00001470 F9 stc ; Set CF 3579 00001471 C3 ret 3580 00001472 04FF skipspace_eoln: add al,0FFh ; Set CF, clear ZF 3581 00001474 C3 ret 3582 3583 ; 3584 ; getkeyword: Get a keyword from the current "getc" file; only the two 3585 ; first characters are considered significant. 3586 ; 3587 ; Lines beginning with ASCII characters 33-47 are treated 3588 ; as comments and ignored; other lines are checked for 3589 ; validity by scanning through the keywd_table. 3590 ; 3591 ; The keyword and subsequent whitespace is skipped. 3592 ; 3593 ; On EOF, CF = 1; otherwise, CF = 0, AL:AH = lowercase char pair 3594 ; 3595 getkeyword: 3596 00001475 E8E4FF gkw_find: call skipspace 3597 00001478 7438 jz gkw_eof ; end of file 3598 0000147A 72F9 jc gkw_find ; end of line: try again 3599 0000147C 3C30 cmp al,'0' 3600 0000147E 7246 jb gkw_skipline ; skip comment line 3601 00001480 50 push ax 3602 00001481 E882FF call getc 3603 00001484 5B pop bx 3604 00001485 722B jc gkw_eof 3605 00001487 88C7 mov bh,al ; Move character pair into BL:BH 3606 00001489 81CB2020 or bx,2020h ; Lower-case it 3607 0000148D BE[861C] mov si,keywd_table 3608 00001490 AD gkw_check: lodsw 3609 00001491 21C0 and ax,ax 3610 00001493 7429 jz gkw_badline ; Bad keyword, write message 3611 00001495 39D8 cmp ax,bx 3612 00001497 75F7 jne gkw_check 3613 00001499 50 push ax 3614 gkw_skiprest: 3615 0000149A E869FF call getc 3616 0000149D 7212 jc gkw_eof_pop 3617 0000149F 3C30 cmp al,'0' 3618 000014A1 77F7 ja gkw_skiprest 3619 000014A3 E8A5FF call ungetc 3620 000014A6 E8B3FF call skipspace 3621 000014A9 7406 jz gkw_eof_pop 3622 000014AB 7206 jc gkw_missingpar ; Missing parameter after keyword 3623 000014AD E89BFF call ungetc ; Return character to buffer 3624 000014B0 F8 clc ; Successful return 3625 000014B1 58 gkw_eof_pop: pop ax 3626 000014B2 C3 gkw_eof: ret ; CF = 1 on all EOF conditions 3627 000014B3 58 gkw_missingpar: pop ax 3628 000014B4 BE[CB1A] mov si,err_noparm 3629 000014B7 E8BAFE call cwritestr 3630 000014BA E9B8FF jmp gkw_find 3631 000014BD 58 gkw_badline_pop: pop ax 3632 000014BE BE[A81A] gkw_badline: mov si,err_badcfg 3633 000014C1 E8B0FE call cwritestr 3634 000014C4 EBAF jmp short gkw_find 3635 000014C6 3C0A gkw_skipline: cmp al,10 ; Scan for LF 3636 000014C8 74AB je gkw_find 3637 000014CA E839FF call getc 3638 000014CD 72E3 jc gkw_eof 3639 000014CF EBF5 jmp short gkw_skipline 3640 3641 ; 3642 ; getint: Load an integer from the getc file. 3643 ; Return CF if error; otherwise return integer in EBX 3644 ; 3645 getint: 3646 000014D1 BFA054 mov di,NumBuf 3647 000014D4 81FFAF54 gi_getnum: cmp di,NumBufEnd ; Last byte in NumBuf 3648 000014D8 730F jae gi_loaded 3649 000014DA 57 push di 3650 000014DB E828FF call getc 3651 000014DE 5F pop di 3652 000014DF 7208 jc gi_loaded 3653 000014E1 AA stosb 3654 000014E2 3C2D cmp al,'-' 3655 000014E4 73EE jnb gi_getnum 3656 000014E6 E862FF call ungetc ; Unget non-numeric 3657 000014E9 C60500 gi_loaded: mov byte [di],0 3658 000014EC BEA054 mov si,NumBuf 3659 ; Fall through to parseint 3660 3661 ; 3662 ; parseint: Convert an integer to a number in EBX 3663 ; Get characters from string in DS:SI 3664 ; Return CF on error 3665 ; DS:SI points to first character after number 3666 ; 3667 ; Syntaxes accepted: [-]dec, [-]0+oct, [-]0x+hex, val+K, val+M 3668 ; 3669 parseint: 3670 000014EF 6650 push eax 3671 000014F1 6651 push ecx 3672 000014F3 55 push bp 3673 000014F4 6631C0 xor eax,eax ; Current digit (keep eax == al) 3674 000014F7 6689C3 mov ebx,eax ; Accumulator 3675 000014FA 6689D9 mov ecx,ebx ; Base 3676 000014FD 31ED xor bp,bp ; Used for negative flag 3677 000014FF AC pi_begin: lodsb 3678 00001500 3C2D cmp al,'-' 3679 00001502 7506 jne pi_not_minus 3680 00001504 81F50100 xor bp,1 ; Set unary minus flag 3681 00001508 EBF5 jmp short pi_begin 3682 pi_not_minus: 3683 0000150A 3C30 cmp al,'0' 3684 0000150C 724F jb pi_err 3685 0000150E 7408 je pi_octhex 3686 00001510 3C39 cmp al,'9' 3687 00001512 7749 ja pi_err 3688 00001514 B10A mov cl,10 ; Base = decimal 3689 00001516 EB17 jmp short pi_foundbase 3690 pi_octhex: 3691 00001518 AC lodsb 3692 00001519 3C30 cmp al,'0' 3693 0000151B 7225 jb pi_km ; Value is zero 3694 0000151D 0C20 or al,20h ; Downcase 3695 0000151F 3C78 cmp al,'x' 3696 00001521 7408 je pi_ishex 3697 00001523 3C37 cmp al,'7' 3698 00001525 7736 ja pi_err 3699 00001527 B108 mov cl,8 ; Base = octal 3700 00001529 EB04 jmp short pi_foundbase 3701 pi_ishex: 3702 0000152B B030 mov al,'0' ; No numeric value accrued yet 3703 0000152D B110 mov cl,16 ; Base = hex 3704 pi_foundbase: 3705 0000152F E83A00 call unhexchar 3706 00001532 720E jc pi_km ; Not a (hex) digit 3707 00001534 38C8 cmp al,cl 3708 00001536 730A jae pi_km ; Invalid for base 3709 00001538 660FAFD9 imul ebx,ecx ; Multiply accumulated by base 3710 0000153C 6601C3 add ebx,eax ; Add current digit 3711 0000153F AC lodsb 3712 00001540 EBED jmp short pi_foundbase 3713 pi_km: 3714 00001542 4E dec si ; Back up to last non-numeric 3715 00001543 AC lodsb 3716 00001544 0C20 or al,20h 3717 00001546 3C6B cmp al,'k' 3718 00001548 7416 je pi_isk 3719 0000154A 3C6D cmp al,'m' 3720 0000154C 7418 je pi_ism 3721 0000154E 4E dec si ; Back up 3722 0000154F 21ED pi_fini: and bp,bp 3723 00001551 7404 jz pi_ret ; CF=0! 3724 00001553 66F7DB neg ebx ; Value was negative 3725 00001556 F8 pi_done: clc 3726 00001557 5D pi_ret: pop bp 3727 00001558 6659 pop ecx 3728 0000155A 6658 pop eax 3729 0000155C C3 ret 3730 0000155D F9 pi_err: stc 3731 0000155E EBF7 jmp short pi_ret 3732 00001560 66C1E30A pi_isk: shl ebx,10 ; x 2^10 3733 00001564 EBF0 jmp short pi_done 3734 00001566 66C1E314 pi_ism: shl ebx,20 ; x 2^20 3735 0000156A EBEA jmp short pi_done 3736 3737 ; 3738 ; unhexchar: Convert a hexadecimal digit in AL to the equivalent number; 3739 ; return CF=1 if not a hex digit 3740 ; 3741 unhexchar: 3742 0000156C 3C30 cmp al,'0' 3743 0000156E 7215 jb uxc_ret ; If failure, CF == 1 already 3744 00001570 3C39 cmp al,'9' 3745 00001572 7703 ja uxc_1 3746 00001574 2C30 sub al,'0' ; CF <- 0 3747 00001576 C3 ret 3748 00001577 0C20 uxc_1: or al,20h ; upper case -> lower case 3749 00001579 3C61 cmp al,'a' 3750 0000157B 7208 jb uxc_ret ; If failure, CF == 1 already 3751 0000157D 3C66 cmp al,'f' 3752 0000157F 7703 ja uxc_err 3753 00001581 2C57 sub al,'a'-10 ; CF <- 0 3754 00001583 C3 ret 3755 00001584 F9 uxc_err: stc 3756 00001585 C3 uxc_ret: ret 3757 3758 ; 3759 ; 3760 ; getline: Get a command line, converting control characters to spaces 3761 ; and collapsing streches to one; a space is appended to the 3762 ; end of the string, unless the line is empty. 3763 ; The line is terminated by ^J, ^Z or EOF and is written 3764 ; to ES:DI. On return, DI points to first char after string. 3765 ; CF is set if we hit EOF. 3766 ; 3767 getline: 3768 00001586 E8D3FE call skipspace 3769 00001589 B201 mov dl,1 ; Empty line -> empty string. 3770 0000158B 742B jz gl_eof ; eof 3771 0000158D 7226 jc gl_eoln ; eoln 3772 0000158F E8B9FE call ungetc 3773 00001592 52 gl_fillloop: push dx 3774 00001593 57 push di 3775 00001594 E86FFE call getc 3776 00001597 5F pop di 3777 00001598 5A pop dx 3778 00001599 721E jc gl_ret ; CF set! 3779 0000159B 3C20 cmp al,' ' 3780 0000159D 7605 jna gl_ctrl 3781 0000159F 31D2 xor dx,dx 3782 000015A1 AA gl_store: stosb 3783 000015A2 EBEE jmp short gl_fillloop 3784 000015A4 3C0A gl_ctrl: cmp al,10 3785 000015A6 7411 je gl_ret ; CF clear! 3786 000015A8 3C1A cmp al,26 3787 000015AA 740C je gl_eof 3788 000015AC 20D2 and dl,dl 3789 000015AE 75E2 jnz gl_fillloop ; Ignore multiple spaces 3790 000015B0 B020 mov al,' ' ; Ctrl -> space 3791 000015B2 42 inc dx 3792 000015B3 EBEC jmp short gl_store 3793 000015B5 F8 gl_eoln: clc ; End of line is not end of file 3794 000015B6 EB01 jmp short gl_ret 3795 000015B8 F9 gl_eof: stc 3796 000015B9 9C gl_ret: pushf ; We want the last char to be space! 3797 000015BA 20D2 and dl,dl 3798 000015BC 7503 jnz gl_xret 3799 000015BE B020 mov al,' ' 3800 000015C0 AA stosb 3801 000015C1 9D gl_xret: popf 3802 000015C2 C3 ret 3803 3804 3805 ; 3806 ; mangle_name: Mangle a DOS filename pointed to by DS:SI into a buffer pointed 3807 ; to by ES:DI; ends on encountering any whitespace 3808 ; 3809 3810 mangle_name: 3811 000015C3 B90B00 mov cx,11 ; # of bytes to write 3812 mn_loop: 3813 000015C6 AC lodsb 3814 000015C7 3C20 cmp al,' ' ; If control or space, end 3815 000015C9 762B jna mn_end 3816 000015CB 3C2E cmp al,'.' ; Period -> space-fill 3817 000015CD 740C je mn_is_period 3818 000015CF 3C61 cmp al,'a' 3819 000015D1 7220 jb mn_not_lower 3820 000015D3 3C7A cmp al,'z' 3821 000015D5 770F ja mn_not_uslower 3822 000015D7 2C20 sub al,020h 3823 000015D9 EB18 jmp short mn_not_lower 3824 000015DB B020 mn_is_period: mov al,' ' ; We need to space-fill 3825 000015DD 81F90300 mn_period_loop: cmp cx,3 ; If <= 3 characters left 3826 000015E1 76E3 jbe mn_loop ; Just ignore it 3827 000015E3 AA stosb ; Otherwise, write a period 3828 000015E4 E2F7 loop mn_period_loop ; Dec CX and (always) jump 3829 000015E6 3C81 mn_not_uslower: cmp al,ucase_low 3830 000015E8 7209 jb mn_not_lower 3831 000015EA 3CA4 cmp al,ucase_high 3832 000015EC 7705 ja mn_not_lower 3833 000015EE BB[7A15] mov bx,ucase_tab-ucase_low 3834 000015F1 2ED7 cs xlatb 3835 000015F3 AA mn_not_lower: stosb 3836 000015F4 E2D0 loop mn_loop ; Don't continue if too long 3837 mn_end: 3838 000015F6 B020 mov al,' ' ; Space-fill name 3839 000015F8 F3AA rep stosb ; Doesn't do anything if CX=0 3840 000015FA C3 ret ; Done 3841 3842 ; 3843 ; Upper-case table for extended characters; this is technically code page 865, 3844 ; but code page 437 users will probably not miss not being able to use the 3845 ; cent sign in kernel images too much :-) 3846 ; 3847 ; The table only covers the range 129 to 164; the rest we can deal with. 3848 ; 3849 ucase_low equ 129 3850 ucase_high equ 164 3851 000015FB 9A90418E418F804545- ucase_tab db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII' 3852 00001604 45494949 3853 00001608 8E8F9092924F994F55- db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154 3854 00001611 5559999A 3855 00001615 9D9C9D9E9F41494F55- db 157, 156, 157, 158, 159, 'AIOU', 165 3856 0000161E A5 3857 3858 ; 3859 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled 3860 ; filename to the conventional representation. This is needed 3861 ; for the BOOT_IMAGE= parameter for the kernel. 3862 ; NOTE: A 13-byte buffer is mandatory, even if the string is 3863 ; known to be shorter. 3864 ; 3865 ; DS:SI -> input mangled file name 3866 ; ES:DI -> output buffer 3867 ; 3868 ; On return, DI points to the first byte after the output name, 3869 ; which is set to a null byte. 3870 ; 3871 unmangle_name: 3872 0000161F 56 push si ; Save pointer to original name 3873 00001620 B90800 mov cx,8 3874 00001623 89FD mov bp,di 3875 00001625 AC un_copy_body: lodsb 3876 00001626 E82600 call lower_case 3877 00001629 AA stosb 3878 0000162A 3C20 cmp al,' ' 3879 0000162C 7602 jbe un_cb_space 3880 0000162E 89FD mov bp,di ; Position of last nonblank+1 3881 00001630 E2F3 un_cb_space: loop un_copy_body 3882 00001632 89EF mov di,bp 3883 00001634 B02E mov al,'.' ; Don't save 3884 00001636 AA stosb 3885 00001637 B90300 mov cx,3 3886 0000163A AC un_copy_ext: lodsb 3887 0000163B E81100 call lower_case 3888 0000163E AA stosb 3889 0000163F 3C20 cmp al,' ' 3890 00001641 7602 jbe un_ce_space 3891 00001643 89FD mov bp,di 3892 00001645 E2F3 un_ce_space: loop un_copy_ext 3893 00001647 89EF mov di,bp 3894 00001649 26C60500 mov byte [es:di], 0 3895 0000164D 5E pop si 3896 0000164E C3 ret 3897 3898 ; 3899 ; lower_case: Lower case a character in AL 3900 ; 3901 lower_case: 3902 0000164F 3C41 cmp al,'A' 3903 00001651 7216 jb lc_ret 3904 00001653 3C5A cmp al,'Z' 3905 00001655 7703 ja lc_1 3906 00001657 0C20 or al,20h 3907 00001659 C3 ret 3908 0000165A 3C80 lc_1: cmp al,lcase_low 3909 0000165C 720B jb lc_ret 3910 0000165E 3CA5 cmp al,lcase_high 3911 00001660 7707 ja lc_ret 3912 00001662 53 push bx 3913 00001663 BB[C217] mov bx,lcase_tab-lcase_low 3914 00001666 2ED7 cs xlatb 3915 00001668 5B pop bx 3916 00001669 C3 lc_ret: ret 3917 3918 ; ---------------------------------------------------------------------------------- 3919 ; VGA splash screen code 3920 ; ---------------------------------------------------------------------------------- 3921 3922 ; 3923 ; vgadisplayfile: 3924 ; Display a graphical splash screen. 3925 ; 3926 ; Input: 3927 ; 3928 ; SI = cluster/socket pointer 3929 ; 3930 vgadisplayfile: 3931 0000166A 89363455 mov [VGACluster],si 3932 0000166E 06 push es 3933 3934 ; This is a cheap and easy way to make sure the screen is 3935 ; cleared in case we were in graphics mode already 3936 0000166F E87E01 call vgaclearmode 3937 00001672 E85001 call vgasetmode 3938 00001675 7514 jnz .error_nz 3939 3940 .graphalready: 3941 00001677 B80030 mov ax,xfer_buf_seg ; Use as temporary storage 3942 0000167A 8EC0 mov es,ax 3943 0000167C 8EE0 mov fs,ax 3944 3945 0000167E E8F600 call vgagetchunk ; Get the first chunk 3946 3947 ; The header WILL be in the first chunk. 3948 00001681 2666813E00403DF313- cmp dword [es:xbs_vgabuf],0x1413f33d ; Magic number 3949 0000168A 14 3950 0000168B 0F857D00 .error_nz: jne near .error 3951 0000168F 26A10440 mov ax,[es:xbs_vgabuf+4] 3952 00001693 A33055 mov [GraphXSize],ax 3953 3954 00001696 BA0840 mov dx,xbs_vgabuf+8 ; Color map offset 3955 00001699 B81210 mov ax,1012h ; Set RGB registers 3956 0000169C 31DB xor bx,bx ; First register number 3957 0000169E B91000 mov cx,16 ; 16 registers 3958 000016A1 CD10 int 10h 3959 3960 .movecursor: 3961 000016A3 26A10640 mov ax,[es:xbs_vgabuf+6] ; Number of pixel rows 3962 000016A7 8B16[EE1C] mov dx,[VGAFontSize] 3963 000016AB 01D0 add ax,dx 3964 000016AD 48 dec ax 3965 000016AE F6F2 div dl 3966 000016B0 31D2 xor dx,dx ; Set column to 0 3967 000016B2 3A063D55 cmp al,[VidRows] 3968 000016B6 7205 jb .rowsok 3969 000016B8 A03D55 mov al,[VidRows] 3970 000016BB FEC8 dec al 3971 .rowsok: 3972 000016BD 88C6 mov dh,al 3973 000016BF B402 mov ah,2 3974 000016C1 31DB xor bx,bx 3975 000016C3 CD10 int 10h ; Set cursor below image 3976 3977 000016C5 268B0E0640 mov cx,[es:xbs_vgabuf+6] ; Number of graphics rows 3978 3979 000016CA BE3840 mov si,xbs_vgabuf+8+3*16 ; Beginning of pixel data 3980 000016CD C70632550000 mov word [VGAPos],0 3981 3982 .drawpixelrow: 3983 000016D3 51 push cx 3984 000016D4 8B0E3055 mov cx,[GraphXSize] 3985 000016D8 BF0080 mov di,xbs_vgatmpbuf ; Row buffer 3986 000016DB E83000 call rledecode ; Decode one row 3987 000016DE 56 push si 3988 000016DF BE0080 mov si,xbs_vgatmpbuf 3989 000016E2 89F7 mov di,si 3990 000016E4 033E3055 add di,[GraphXSize] 3991 000016E8 B9A000 mov cx,640/4 3992 000016EB 6631C0 xor eax,eax 3993 000016EE F366AB rep stosd ; Clear rest of row 3994 000016F1 BF00A0 mov di,0A000h ; VGA segment 3995 000016F4 8EC7 mov es,di 3996 000016F6 8B3E3255 mov di,[VGAPos] 3997 000016FA BD8002 mov bp,640 3998 000016FD E89600 call packedpixel2vga 3999 00001700 8306325550 add word [VGAPos],byte 80 ; Advance to next pixel row 4000 00001705 0FA0 push fs 4001 00001707 07 pop es 4002 00001708 5E pop si 4003 00001709 59 pop cx 4004 0000170A E2C7 loop .drawpixelrow 4005 4006 .error: 4007 0000170C 07 pop es 4008 0000170D C3 ret 4009 4010 ; 4011 ; rledecode: 4012 ; Decode a pixel row in RLE16 format. 4013 ; 4014 ; FS:SI -> input 4015 ; CX -> pixel count 4016 ; ES:DI -> output (packed pixel) 4017 ; 4018 rledecode: 4019 0000170E 66D1E6 shl esi,1 ; Nybble pointer 4020 00001711 30D2 xor dl,dl ; Last pixel 4021 .loop: 4022 00001713 E83F00 call .getnybble 4023 00001716 38D0 cmp al,dl 4024 00001718 740D je .run ; Start of run sequence 4025 0000171A AA stosb 4026 0000171B 88C2 mov dl,al 4027 0000171D 49 dec cx 4028 0000171E 75F3 jnz .loop 4029 .done: 4030 00001720 66D1EE shr esi,1 4031 00001723 83D600 adc si,byte 0 4032 00001726 C3 ret 4033 .run: 4034 00001727 31DB xor bx,bx 4035 00001729 E82900 call .getnybble 4036 0000172C 20C0 and al,al 4037 0000172E 7410 jz .longrun 4038 00001730 88C3 mov bl,al 4039 .dorun: 4040 00001732 51 push cx 4041 00001733 89D9 mov cx,bx 4042 00001735 88D0 mov al,dl 4043 00001737 F3AA rep stosb 4044 00001739 59 pop cx 4045 0000173A 29D9 sub cx,bx 4046 0000173C 77D5 ja .loop 4047 0000173E EBE0 jmp short .done 4048 .longrun: 4049 00001740 E81200 call .getnybble 4050 00001743 88C4 mov ah,al 4051 00001745 E80D00 call .getnybble 4052 00001748 C0E004 shl al,4 4053 0000174B 08E0 or al,ah 4054 0000174D 88C3 mov bl,al 4055 0000174F 81C31000 add bx,16 4056 00001753 EBDD jmp short .dorun 4057 .getnybble: 4058 00001755 66D1EE shr esi,1 4059 00001758 64AC fs lodsb 4060 0000175A 7208 jc .high 4061 0000175C 4E dec si 4062 0000175D 240F and al,0Fh 4063 0000175F F9 stc 4064 00001760 66D1D6 rcl esi,1 4065 00001763 C3 ret 4066 .high: 4067 00001764 C0E804 shr al,4 4068 00001767 81FE0080 cmp si,xbs_vgabuf+trackbufsize ; Chunk overrun 4069 0000176B 7206 jb .nonewchunk 4070 0000176D E80700 call vgagetchunk 4071 00001770 BE0040 mov si,xbs_vgabuf ; Start at beginning of buffer 4072 .nonewchunk: 4073 00001773 66D1E6 shl esi,1 4074 00001776 C3 ret 4075 4076 ; 4077 ; vgagetchunk: 4078 ; Get a new trackbufsize chunk of VGA image data 4079 ; 4080 ; On input, ES is assumed to point to the buffer segment. 4081 ; 4082 vgagetchunk: 4083 00001777 6660 pushad 4084 00001779 8B363455 mov si,[VGACluster] 4085 0000177D 21F6 and si,si 4086 0000177F 7412 jz .eof ; EOF overrun, not much to do... 4087 4088 00001781 8B0E0C55 mov cx,[BufSafe] ; One trackbuf worth of data 4089 00001785 BB0040 mov bx,xbs_vgabuf 4090 00001788 E89BEB call getfssec 4091 4092 0000178B 7302 jnc .noteof 4093 0000178D 31F6 xor si,si 4094 0000178F 89363455 .noteof: mov [VGACluster],si 4095 4096 00001793 6661 .eof: popad 4097 00001795 C3 ret 4098 4099 ; 4100 ; packedpixel2vga: 4101 ; Convert packed-pixel to VGA bitplanes 4102 ; 4103 ; FS:SI -> packed pixel string 4104 ; BP -> pixel count (multiple of 8) 4105 ; ES:DI -> output 4106 ; 4107 packedpixel2vga: 4108 00001796 BAC403 mov dx,3C4h ; VGA Sequencer Register select port 4109 00001799 B002 mov al,2 ; Sequencer mask 4110 0000179B EE out dx,al ; Select the sequencer mask 4111 0000179C 42 inc dx ; VGA Sequencer Register data port 4112 0000179D B001 mov al,1 4113 0000179F 88C3 mov bl,al 4114 .planeloop: 4115 000017A1 60 pusha 4116 000017A2 EE out dx,al 4117 .loop1: 4118 000017A3 B90800 mov cx,8 4119 .loop2: 4120 000017A6 87CB xchg cx,bx 4121 000017A8 64AC fs lodsb 4122 000017AA D2E8 shr al,cl 4123 000017AC D0D5 rcl ch,1 ; VGA is bigendian. Sigh. 4124 000017AE 87CB xchg cx,bx 4125 000017B0 E2F4 loop .loop2 4126 000017B2 88F8 mov al,bh 4127 000017B4 AA stosb 4128 000017B5 83ED08 sub bp,byte 8 4129 000017B8 77E9 ja .loop1 4130 000017BA 61 popa 4131 000017BB FEC3 inc bl 4132 000017BD D0E0 shl al,1 4133 000017BF 80FB04 cmp bl,4 4134 000017C2 76DD jbe .planeloop 4135 000017C4 C3 ret 4136 4137 ; 4138 ; vgasetmode: 4139 ; Enable VGA graphics, if possible; return ZF=1 on success 4140 ; DS must be set to the base segment. 4141 ; 4142 vgasetmode: 4143 000017C5 1E push ds 4144 000017C6 07 pop es 4145 000017C7 B8001A mov ax,1A00h ; Get video card and monitor 4146 000017CA 31DB xor bx,bx 4147 000017CC CD10 int 10h 4148 000017CE 80FB08 cmp bl, 8 ; If not VGA card/VGA monitor, give up 4149 000017D1 751C jne .error ; ZF=0 4150 ; mov bx,TextColorReg 4151 ; mov dx,1009h ; Read color registers 4152 ; int 10h 4153 000017D3 B81200 mov ax,0012h ; Set mode = 640x480 VGA 16 colors 4154 000017D6 CD10 int 10h 4155 000017D8 BA[3018] mov dx,linear_color 4156 000017DB B80210 mov ax,1002h ; Write color registers 4157 000017DE CD10 int 10h 4158 000017E0 C606[4118]01 mov [UsingVGA], byte 1 4159 4160 000017E5 E832F9 call use_font ; Set graphics font/data 4161 000017E8 C606[F01C]00 mov byte [ScrollAttribute], 00h 4162 4163 000017ED 31C0 xor ax,ax ; Set ZF 4164 .error: 4165 000017EF C3 ret 4166 4167 ; 4168 ; vgaclearmode: 4169 ; Disable VGA graphics. It is not safe to assume any value for DS. 4170 ; 4171 vgaclearmode: 4172 000017F0 1E push ds 4173 000017F1 0E push cs 4174 000017F2 1F pop ds ; DS <- CS 4175 000017F3 6660 pushad 4176 000017F5 803E[4118]01 cmp [UsingVGA], byte 1 4177 000017FA 7512 jne .done 4178 000017FC B80300 mov ax,0003h ; Return to normal video mode 4179 000017FF CD10 int 10h 4180 ; mov dx,TextColorReg ; Restore color registers 4181 ; mov ax,1002h 4182 ; int 10h 4183 00001801 C606[4118]00 mov [UsingVGA], byte 0 4184 4185 00001806 E811F9 call use_font ; Restore text font/data 4186 00001809 C606[F01C]07 mov byte [ScrollAttribute], 07h 4187 .done: 4188 0000180E 6661 popad 4189 00001810 1F pop ds 4190 00001811 C3 ret 4191 4192 ; 4193 ; vgashowcursor/vgahidecursor: 4194 ; If VGA graphics is enabled, draw a cursor/clear a cursor 4195 ; 4196 vgashowcursor: 4197 00001812 6660 pushad 4198 00001814 B05F mov al,'_' 4199 00001816 EB04 jmp short vgacursorcommon 4200 vgahidecursor: 4201 00001818 6660 pushad 4202 0000181A B020 mov al,' ' 4203 vgacursorcommon: 4204 0000181C 803E[4118]01 cmp [UsingVGA], byte 1 4205 00001821 750A jne .done 4206 00001823 B409 mov ah,09h 4207 00001825 BB0700 mov bx,0007h 4208 00001828 B90100 mov cx,1 4209 0000182B CD10 int 10h 4210 .done: 4211 0000182D 6661 popad 4212 0000182F C3 ret 4213 4214 4215 ; Map colors to consecutive DAC registers 4216 00001830 000102030405060708- linear_color db 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 0 4217 00001839 090A0B0C0D0E0F00 4218 00001841 00 UsingVGA db 0 4219 4220 ; ---------------------------------------------------------------------------------- 4221 ; Begin data section 4222 ; ---------------------------------------------------------------------------------- 4223 4224 CR equ 13 ; Carriage Return 4225 LF equ 10 ; Line Feed 4226 FF equ 12 ; Form Feed 4227 BS equ 8 ; Backspace 4228 4229 ; 4230 ; Lower-case table for codepage 865 4231 ; 4232 lcase_low equ 128 4233 lcase_high equ 165 4234 00001842 878182838485868788- lcase_tab db 135, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138 4235 0000184B 898A 4236 0000184D 8B8C8D848682919193- db 139, 140, 141, 132, 134, 130, 145, 145, 147, 148, 149 4237 00001856 9495 4238 00001858 96979894819B9C9B9E- db 150, 151, 152, 148, 129, 155, 156, 155, 158, 159, 160 4239 00001861 9FA0 4240 00001863 A1A2A3A4A4 db 161, 162, 163, 164, 164 4241 4242 00001868 20436F707972696768- copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin' 4243 00001871 742028432920313939- 4244 0000187A 342D3230303120482E- 4245 00001883 20506574657220416E- 4246 0000188C 76696E 4247 0000188F 0D0A00 db CR, LF, 0 4248 00001892 626F6F743A2000 boot_prompt db 'boot: ', 0 4249 00001899 08200800 wipe_char db BS, ' ', BS, 0 4250 0000189D 436F756C64206E6F74- err_notfound db 'Could not find kernel image: ',0 4251 000018A6 2066696E64206B6572- 4252 000018AF 6E656C20696D616765- 4253 000018B8 3A2000 4254 000018BB 0D0A496E76616C6964- err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0 4255 000018C4 206F7220636F727275- 4256 000018CD 7074206B65726E656C- 4257 000018D6 20696D6167652E0D0A- 4258 000018DF 00 4259 000018E0 497420617070656172- err_not386 db 'It appears your computer uses a 286 or lower CPU.' 4260 000018E9 7320796F757220636F- 4261 000018F2 6D7075746572207573- 4262 000018FB 657320612032383620- 4263 00001904 6F72206C6F77657220- 4264 0000190D 4350552E 4265 00001911 0D0A db CR, LF 4266 00001913 596F752063616E6E6F- db 'You cannot run Linux unless you have a 386 or higher CPU' 4267 0000191C 742072756E204C696E- 4268 00001925 757820756E6C657373- 4269 0000192E 20796F752068617665- 4270 00001937 206120333836206F72- 4271 00001940 206869676865722043- 4272 00001949 5055 4273 0000194B 0D0A db CR, LF 4274 0000194D 696E20796F7572206D- db 'in your machine. If you get this message in error, hold' 4275 00001956 616368696E652E2020- 4276 0000195F 496620796F75206765- 4277 00001968 742074686973206D65- 4278 00001971 737361676520696E20- 4279 0000197A 6572726F722C20686F- 4280 00001983 6C64 4281 00001985 0D0A db CR, LF 4282 00001987 646F776E2074686520- db 'down the Ctrl key while booting, and I will take your' 4283 00001990 4374726C206B657920- 4284 00001999 7768696C6520626F6F- 4285 000019A2 74696E672C20616E64- 4286 000019AB 20492077696C6C2074- 4287 000019B4 616B6520796F7572 4288 000019BC 0D0A db CR, LF 4289 000019BE 776F726420666F7220- db 'word for it.', CR, LF, 0 4290 000019C7 69742E0D0A00 4291 000019CD 497420617070656172- err_noram db 'It appears your computer has less than 512K of low ("DOS")' 4292 000019D6 7320796F757220636F- 4293 000019DF 6D7075746572206861- 4294 000019E8 73206C657373207468- 4295 000019F1 616E203531324B206F- 4296 000019FA 66206C6F7720282244- 4297 00001A03 4F532229 4298 00001A07 0D0A db CR, LF 4299 00001A09 52414D2E20204C696E- db 'RAM. Linux needs at least this amount to boot. If you get' 4300 00001A12 7578206E6565647320- 4301 00001A1B 6174206C6561737420- 4302 00001A24 7468697320616D6F75- 4303 00001A2D 6E7420746F20626F6F- 4304 00001A36 742E2020496620796F- 4305 00001A3F 7520676574 4306 00001A44 0D0A db CR, LF 4307 00001A46 74686973206D657373- db 'this message in error, hold down the Ctrl key while' 4308 00001A4F 61676520696E206572- 4309 00001A58 726F722C20686F6C64- 4310 00001A61 20646F776E20746865- 4311 00001A6A 204374726C206B6579- 4312 00001A73 207768696C65 4313 00001A79 0D0A db CR, LF 4314 00001A7B 626F6F74696E672C20- db 'booting, and I will take your word for it.', CR, LF, 0 4315 00001A84 616E6420492077696C- 4316 00001A8D 6C2074616B6520796F- 4317 00001A96 757220776F72642066- 4318 00001A9F 6F722069742E0D0A00 4319 00001AA8 556E6B6E6F776E206B- err_badcfg db 'Unknown keyword in syslinux.cfg.', CR, LF, 0 4320 00001AB1 6579776F726420696E- 4321 00001ABA 207379736C696E7578- 4322 00001AC3 2E6366672E0D0A00 4323 00001ACB 4D697373696E672070- err_noparm db 'Missing parameter in syslinux.cfg.', CR, LF, 0 4324 00001AD4 6172616D6574657220- 4325 00001ADD 696E207379736C696E- 4326 00001AE6 75782E6366672E0D0A- 4327 00001AEF 00 4328 00001AF0 0D0A436F756C64206E- err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0 4329 00001AF9 6F742066696E642072- 4330 00001B02 616D6469736B20696D- 4331 00001B0B 6167653A2000 4332 00001B11 4E6F7420656E6F7567- err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0 4333 00001B1A 68206D656D6F727920- 4334 00001B23 746F206C6F61642073- 4335 00001B2C 706563696669656420- 4336 00001B35 6B65726E656C2E0D0A- 4337 00001B3E 00 4338 00001B3F 0D0A4B65726E656C20- err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0 4339 00001B48 7472616E7366657220- 4340 00001B51 6661696C7572652E0D- 4341 00001B5A 0A00 4342 00001B5C 43616E6E6F74206C6F- err_oldkernel db 'Cannot load a ramdisk with an old kernel image.' 4343 00001B65 616420612072616D64- 4344 00001B6E 69736B207769746820- 4345 00001B77 616E206F6C64206B65- 4346 00001B80 726E656C20696D6167- 4347 00001B89 652E 4348 00001B8B 0D0A00 db CR, LF, 0 4349 00001B8E 3A20617474656D7074- err_notdos db ': attempted DOS system call', CR, LF, 0 4350 00001B97 656420444F53207379- 4351 00001BA0 7374656D2063616C6C- 4352 00001BA9 0D0A00 4353 00001BAC 434F4D424F4F542069- err_comlarge db 'COMBOOT image too large.', CR, LF, 0 4354 00001BB5 6D61676520746F6F20- 4355 00001BBE 6C617267652E0D0A00 4356 00001BC7 496E76616C6964206F- err_bootsec db 'Invalid or corrupt boot sector image.', CR, LF, 0 4357 00001BD0 7220636F7272757074- 4358 00001BD9 20626F6F7420736563- 4359 00001BE2 746F7220696D616765- 4360 00001BEB 2E0D0A00 4361 00001BEF 0D0A41323020676174- err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0 4362 00001BF8 65206E6F7420726573- 4363 00001C01 706F6E64696E67210D- 4364 00001C0A 0A00 4365 00001C0C 0D0A426F6F74206661- err_bootfailed db CR, LF, 'Boot failed: please change disks and press ' 4366 00001C15 696C65643A20706C65- 4367 00001C1E 617365206368616E67- 4368 00001C27 65206469736B732061- 4369 00001C30 6E6420707265737320 4370 00001C39 61206B657920746F20- db 'a key to continue.', CR, LF, 0 4371 00001C42 636F6E74696E75652E- 4372 00001C4B 0D0A00 4373 00001C4E 2072656164792E0D0A- ready_msg db ' ready.', CR, LF, 0 4374 00001C57 00 4375 00001C58 4C6F6164696E672000 loading_msg db 'Loading ', 0 4376 00001C61 2E dotdot_msg db '.' 4377 00001C62 2E00 dot_msg db '.', 0 4378 00001C64 2061626F727465642E aborted_msg db ' aborted.' ; Fall through to crlf_msg! 4379 00001C6D 0D0A00 crlf_msg db CR, LF, 0 4380 00001C70 0D0C00 crff_msg db CR, FF, 0 4381 00001C73 5359534C494E555843- syslinux_cfg db 'SYSLINUXCFG' 4382 00001C7C 4647 4383 ; 4384 ; Command line options we'd like to take a look at 4385 ; 4386 ; mem= and vga= are handled as normal 32-bit integer values 4387 00001C7E 696E697472643D initrd_cmd db 'initrd=' 4388 initrd_cmd_len equ 7 4389 ; 4390 ; Config file keyword table 4391 ; 4392 00001C85 90 align 2 4393 00001C86 6170 keywd_table db 'ap' ; append 4394 00001C88 6465 db 'de' ; default 4395 00001C8A 7469 db 'ti' ; timeout 4396 00001C8C 666F db 'fo' ; font 4397 00001C8E 6B62 db 'kb' ; kbd 4398 00001C90 6469 db 'di' ; display 4399 00001C92 7072 db 'pr' ; prompt 4400 00001C94 6C61 db 'la' ; label 4401 00001C96 696D db 'im' ; implicit 4402 00001C98 6B65 db 'ke' ; kernel 4403 00001C9A 7365 db 'se' ; serial 4404 00001C9C 6631 db 'f1' ; F1 4405 00001C9E 6632 db 'f2' ; F2 4406 00001CA0 6633 db 'f3' ; F3 4407 00001CA2 6634 db 'f4' ; F4 4408 00001CA4 6635 db 'f5' ; F5 4409 00001CA6 6636 db 'f6' ; F6 4410 00001CA8 6637 db 'f7' ; F7 4411 00001CAA 6638 db 'f8' ; F8 4412 00001CAC 6639 db 'f9' ; F9 4413 00001CAE 6630 db 'f0' ; F10 4414 00001CB0 0000 dw 0 4415 ; 4416 ; Extensions to search for (in *reverse* order). Note that the last 4417 ; (lexically first) entry in the table is a placeholder for the original 4418 ; extension, needed for error messages. The exten_table is shifted so 4419 ; the table is 1-based; this is because a "loop" cx is used as index. 4420 ; 4421 exten_table: 4422 00001CB2 00000000 OrigKernelExt: dd 0 ; Original extension 4423 00001CB6 434F4D00 db 'COM',0 ; COMBOOT (same as DOS) 4424 00001CBA 42532000 db 'BS ',0 ; Boot Sector 4425 00001CBE 42535300 db 'BSS',0 ; Boot Sector (add superblock) 4426 00001CC2 43425400 db 'CBT',0 ; COMBOOT (specific) 4427 4428 exten_count equ (($-exten_table) >> 2) - 1 ; Number of alternates 4429 ; 4430 ; Misc initialized (data) variables 4431 ; 4432 %ifdef debug ; This code for debugging only 4433 debug_magic dw 0D00Dh ; Debug code sentinel 4434 %endif 4435 00001CC6 0000 AppendLen dw 0 ; Bytes in append= command 4436 00001CC8 0000 KbdTimeOut dw 0 ; Keyboard timeout (if any) 4437 00001CCA 0000 FKeyMap dw 0 ; Bitmap for F-keys loaded 4438 00001CCC 0090 CmdLinePtr dw cmd_line_here ; Command line advancing pointer 4439 initrd_flag equ $ 4440 00001CCE 0000 initrd_ptr dw 0 ; Initial ramdisk pointer/flag 4441 00001CD0 0000 VKernelCtr dw 0 ; Number of registered vkernels 4442 00001CD2 0000 ForcePrompt dw 0 ; Force prompt 4443 00001CD4 0100 AllowImplicit dw 1 ; Allow implicit kernels 4444 00001CD6 0000 SerialPort dw 0 ; Serial port base (or 0 for no serial port) 4445 00001CD8 [C70E][C70E][D20E]- A20List dw a20_dunno, a20_none, a20_bios, a20_kbc, a20_fast 4446 00001CDE [E40E][0A0F] 4447 00001CE2 [920F][920F][640F]- A20DList dw a20d_dunno, a20d_none, a20d_bios, a20d_kbc, a20d_fast 4448 00001CE8 [750F][6D0F] 4449 00001CEC 0000 A20Type dw A20_DUNNO ; A20 type unknown 4450 00001CEE 1000 VGAFontSize dw 16 ; Defaults to 16 byte font 4451 00001CF0 07 ScrollAttribute db 07h ; White on black (for text mode) 4452 ; 4453 ; Stuff for the command line; we do some trickery here with equ to avoid 4454 ; tons of zeros appended to our file and wasting space 4455 ; 4456 00001CF1 6C696E757820617574- linuxauto_cmd db 'linux auto',0 4457 00001CFA 6F00 4458 linuxauto_len equ $-linuxauto_cmd 4459 00001CFC 424F4F545F494D4147- boot_image db 'BOOT_IMAGE=' 4460 00001D05 453D 4461 boot_image_len equ $-boot_image 4462 00001D07 00 align 4, db 0 ; For the good of REP MOVSD 4463 command_line equ $ 4464 default_cmd equ $+(max_cmd_len+2) 4465 ldlinux_end equ default_cmd+(max_cmd_len+1) 4466 kern_cmd_len equ ldlinux_end-command_line 4467 ldlinux_len equ ldlinux_end-ldlinux_magic 4468 ; 4469 ; Put the getcbuf right after the code, aligned on a sector boundary 4470 ; 4471 end_of_code equ (ldlinux_end-bootsec)+7C00h 4472 getcbuf equ (end_of_code + 511) & 0FE00h 4473 4474 ; VGA font buffer at the end of memory (so loading a font works even 4475 ; in graphics mode.) 4476 vgafontbuf equ 0E000h 4477 4478 ; This is a compile-time assert that we didn't run out of space 4479 %if (getcbuf+trackbufsize) > vgafontbuf 4480 %error "Out of memory, better reorganize something..." 4481 %endif