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