Fix typo in Makefile rule
[syslinux.git] / ldlinux.asm
blobb5a9ebf69e4a6f072a327bdad135e21bc3fad566
1 ; -*- fundamental -*- (asm-mode sucks)
2 ; ****************************************************************************
4 ; ldlinux.asm
6 ; A program to boot Linux kernels off an MS-DOS formatted floppy disk. This
7 ; functionality is good to have for installation floppies, where it may
8 ; be hard to find a functional Linux system to run LILO off.
10 ; This program allows manipulation of the disk to take place entirely
11 ; from MS-LOSS, and can be especially useful in conjunction with the
12 ; umsdos filesystem.
14 ; Copyright (C) 1994-2005 H. Peter Anvin
16 ; This program is free software; you can redistribute it and/or modify
17 ; it under the terms of the GNU General Public License as published by
18 ; the Free Software Foundation, Inc., 53 Temple Place Ste 330,
19 ; Boston MA 02111-1307, USA; either version 2 of the License, or
20 ; (at your option) any later version; incorporated herein by reference.
22 ; ****************************************************************************
24 %ifndef IS_MDSLINUX
25 %define IS_SYSLINUX 1
26 %endif
27 %include "head.inc"
30 ; Some semi-configurable constants... change on your own risk.
32 my_id equ syslinux_id
33 FILENAME_MAX_LG2 equ 4 ; log2(Max filename size Including final null)
34 FILENAME_MAX equ 11 ; Max mangled filename size
35 NULLFILE equ ' ' ; First char space == null filename
36 NULLOFFSET equ 0 ; Position in which to look
37 retry_count equ 16 ; How patient are we with the disk?
38 %assign HIGHMEM_SLOP 0 ; Avoid this much memory near the top
39 LDLINUX_MAGIC equ 0x3eb202fe ; A random number to identify ourselves with
41 MAX_OPEN_LG2 equ 6 ; log2(Max number of open files)
42 MAX_OPEN equ (1 << MAX_OPEN_LG2)
44 SECTOR_SHIFT equ 9
45 SECTOR_SIZE equ (1 << SECTOR_SHIFT)
48 ; This is what we need to do when idle
50 %macro RESET_IDLE 0
51 ; Nothing
52 %endmacro
53 %macro DO_IDLE 0
54 ; Nothing
55 %endmacro
58 ; The following structure is used for "virtual kernels"; i.e. LILO-style
59 ; option labels. The options we permit here are `kernel' and `append
60 ; Since there is no room in the bottom 64K for all of these, we
61 ; stick them at vk_seg:0000 and copy them down before we need them.
63 struc vkernel
64 vk_vname: resb FILENAME_MAX ; Virtual name **MUST BE FIRST!**
65 vk_rname: resb FILENAME_MAX ; Real name
66 vk_appendlen: resw 1
67 alignb 4
68 vk_append: resb max_cmd_len+1 ; Command line
69 alignb 4
70 vk_end: equ $ ; Should be <= vk_size
71 endstruc
74 ; Segment assignments in the bottom 640K
75 ; Stick to the low 512K in case we're using something like M-systems flash
76 ; which load a driver into low RAM (evil!!)
78 ; 0000h - main code/data segment (and BIOS segment)
80 real_mode_seg equ 4000h
81 cache_seg equ 3000h ; 64K area for metadata cache
82 vk_seg equ 2000h ; Virtual kernels
83 xfer_buf_seg equ 1000h ; Bounce buffer for I/O to high mem
84 comboot_seg equ real_mode_seg ; COMBOOT image loading zone
87 ; File structure. This holds the information for each currently open file.
89 struc open_file_t
90 file_sector resd 1 ; Sector pointer (0 = structure free)
91 file_left resd 1 ; Number of sectors left
92 endstruc
94 %ifndef DEPEND
95 %if (open_file_t_size & (open_file_t_size-1))
96 %error "open_file_t is not a power of 2"
97 %endif
98 %endif
100 ; ---------------------------------------------------------------------------
101 ; BEGIN CODE
102 ; ---------------------------------------------------------------------------
105 ; Memory below this point is reserved for the BIOS and the MBR
107 section .earlybss
108 trackbufsize equ 8192
109 trackbuf resb trackbufsize ; Track buffer goes here
110 getcbuf resb trackbufsize
111 ; ends at 4800h
113 section .bss
114 alignb 8
116 ; Expanded superblock
117 SuperInfo equ $
118 resq 16 ; The first 16 bytes expanded 8 times
119 FAT resd 1 ; Location of (first) FAT
120 RootDirArea resd 1 ; Location of root directory area
121 RootDir resd 1 ; Location of root directory proper
122 DataArea resd 1 ; Location of data area
123 RootDirSize resd 1 ; Root dir size in sectors
124 TotalSectors resd 1 ; Total number of sectors
125 EndSector resd 1 ; Location of filesystem end
126 ClustSize resd 1 ; Bytes/cluster
127 ClustMask resd 1 ; Sectors/cluster - 1
128 CopySuper resb 1 ; Distinguish .bs versus .bss
129 DriveNumber resb 1 ; BIOS drive number
130 ClustShift resb 1 ; Shift count for sectors/cluster
131 ClustByteShift resb 1 ; Shift count for bytes/cluster
133 alignb open_file_t_size
134 Files resb MAX_OPEN*open_file_t_size
137 ; Constants for the xfer_buf_seg
139 ; The xfer_buf_seg is also used to store message file buffers. We
140 ; need two trackbuffers (text and graphics), plus a work buffer
141 ; for the graphics decompressor.
143 xbs_textbuf equ 0 ; Also hard-coded, do not change
144 xbs_vgabuf equ trackbufsize
145 xbs_vgatmpbuf equ 2*trackbufsize
148 section .text
150 ; Some of the things that have to be saved very early are saved
151 ; "close" to the initial stack pointer offset, in order to
152 ; reduce the code size...
154 StackBuf equ $-44-32 ; Start the stack here (grow down - 4K)
155 PartInfo equ StackBuf ; Saved partition table entry
156 FloppyTable equ PartInfo+16 ; Floppy info table (must follow PartInfo)
157 OrigFDCTabPtr equ StackBuf-4 ; The high dword on the stack
160 ; Primary entry point. Tempting as though it may be, we can't put the
161 ; initial "cli" here; the jmp opcode in the first byte is part of the
162 ; "magic number" (using the term very loosely) for the DOS superblock.
164 bootsec equ $
165 jmp short start ; 2 bytes
166 nop ; 1 byte
168 ; "Superblock" follows -- it's in the boot sector, so it's already
169 ; loaded and ready for us
171 bsOemName db 'SYSLINUX' ; The SYS command sets this, so...
173 ; These are the fields we actually care about. We end up expanding them
174 ; all to dword size early in the code, so generate labels for both
175 ; the expanded and unexpanded versions.
177 %macro superb 1
178 bx %+ %1 equ SuperInfo+($-superblock)*8+4
179 bs %+ %1 equ $
180 zb 1
181 %endmacro
182 %macro superw 1
183 bx %+ %1 equ SuperInfo+($-superblock)*8
184 bs %+ %1 equ $
185 zw 1
186 %endmacro
187 %macro superd 1
188 bx %+ %1 equ $ ; no expansion for dwords
189 bs %+ %1 equ $
190 zd 1
191 %endmacro
192 superblock equ $
193 superw BytesPerSec
194 superb SecPerClust
195 superw ResSectors
196 superb FATs
197 superw RootDirEnts
198 superw Sectors
199 superb Media
200 superw FATsecs
201 superw SecPerTrack
202 superw Heads
203 superinfo_size equ ($-superblock)-1 ; How much to expand
204 superd Hidden
205 superd HugeSectors
207 ; This is as far as FAT12/16 and FAT32 are consistent
209 zb 54 ; FAT12/16 need 26 more bytes,
210 ; FAT32 need 54 more bytes
211 superblock_len equ $-superblock
213 SecPerClust equ bxSecPerClust
215 ; Note we don't check the constraints above now; we did that at install
216 ; time (we hope!)
218 start:
219 cli ; No interrupts yet, please
220 cld ; Copy upwards
222 ; Set up the stack
224 xor ax,ax
225 mov ss,ax
226 mov sp,StackBuf ; Just below BSS
227 mov es,ax
229 ; DS:SI may contain a partition table entry. Preserve it for us.
231 mov cx,8 ; Save partition info
232 mov di,sp
233 rep movsw
235 mov ds,ax ; Now we can initialize DS...
238 ; Now sautee the BIOS floppy info block to that it will support decent-
239 ; size transfers; the floppy block is 11 bytes and is stored in the
240 ; INT 1Eh vector (brilliant waste of resources, eh?)
242 ; Of course, if BIOSes had been properly programmed, we wouldn't have
243 ; had to waste precious space with this code.
245 mov bx,fdctab
246 lfs si,[bx] ; FS:SI -> original fdctab
247 push fs ; Save on stack in case we need to bail
248 push si
250 ; Save the old fdctab even if hard disk so the stack layout
251 ; is the same. The instructions above do not change the flags
252 mov [DriveNumber],dl ; Save drive number in DL
253 and dl,dl ; If floppy disk (00-7F), assume no
254 ; partition table
255 js harddisk
257 floppy:
258 mov cl,6 ; 12 bytes (CX == 0)
259 ; es:di -> FloppyTable already
260 ; This should be safe to do now, interrupts are off...
261 mov [bx],di ; FloppyTable
262 mov [bx+2],ax ; Segment 0
263 fs rep movsw ; Faster to move words
264 mov cl,[bsSecPerTrack] ; Patch the sector count
265 mov [di-8],cl
266 ; AX == 0 here
267 int 13h ; Some BIOSes need this
269 jmp short not_harddisk
271 ; The drive number and possibly partition information was passed to us
272 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to
273 ; trust that rather than what the superblock contains.
275 ; Would it be better to zero out bsHidden if we don't have a partition table?
277 ; Note: di points to beyond the end of PartInfo
279 harddisk:
280 test byte [di-16],7Fh ; Sanity check: "active flag" should
281 jnz no_partition ; be 00 or 80
282 mov eax,[di-8] ; Partition offset (dword)
283 mov [bsHidden],eax
284 no_partition:
286 ; Get disk drive parameters (don't trust the superblock.) Don't do this for
287 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
288 ; what the *drive* supports, not about the *media*. Fortunately floppy disks
289 ; tend to have a fixed, well-defined geometry which is stored in the superblock.
291 ; DL == drive # still
292 mov ah,08h
293 int 13h
294 jc no_driveparm
295 and ah,ah
296 jnz no_driveparm
297 shr dx,8
298 inc dx ; Contains # of heads - 1
299 mov [bsHeads],dx
300 and cx,3fh
301 mov [bsSecPerTrack],cx
302 no_driveparm:
303 not_harddisk:
305 ; Ready to enable interrupts, captain
310 ; Do we have EBIOS (EDD)?
312 eddcheck:
313 mov bx,55AAh
314 mov ah,41h ; EDD existence query
315 mov dl,[DriveNumber]
316 int 13h
317 jc .noedd
318 cmp bx,0AA55h
319 jne .noedd
320 test cl,1 ; Extended disk access functionality set
321 jz .noedd
323 ; We have EDD support...
325 mov byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
326 .noedd:
329 ; Load the first sector of LDLINUX.SYS; this used to be all proper
330 ; with parsing the superblock and root directory; it doesn't fit
331 ; together with EBIOS support, unfortunately.
333 mov eax,[FirstSector] ; Sector start
334 mov bx,ldlinux_sys ; Where to load it
335 call getonesec
337 ; Some modicum of integrity checking
338 cmp dword [ldlinux_magic+4],LDLINUX_MAGIC^HEXDATE
339 jne kaboom
341 ; Go for it...
342 jmp ldlinux_ent
345 ; getonesec: get one disk sector
347 getonesec:
348 mov bp,1 ; One sector
349 ; Fall through
352 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
353 ; number in EAX into the buffer at ES:BX. We try to optimize
354 ; by loading up to a whole track at a time, but the user
355 ; is responsible for not crossing a 64K boundary.
356 ; (Yes, BP is weird for a count, but it was available...)
358 ; On return, BX points to the first byte after the transferred
359 ; block.
361 ; This routine assumes CS == DS, and trashes most registers.
363 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
364 ; that is dead from that point; this saves space. However, please keep
365 ; the order to dst,src to keep things sane.
367 getlinsec:
368 add eax,[bsHidden] ; Add partition offset
369 xor edx,edx ; Zero-extend LBA (eventually allow 64 bits)
371 .jmp: jmp strict short getlinsec_cbios
374 ; getlinsec_ebios:
376 ; getlinsec implementation for EBIOS (EDD)
378 getlinsec_ebios:
379 .loop:
380 push bp ; Sectors left
381 .retry2:
382 call maxtrans ; Enforce maximum transfer size
383 movzx edi,bp ; Sectors we are about to read
384 mov cx,retry_count
385 .retry:
387 ; Form DAPA on stack
388 push edx
389 push eax
390 push es
391 push bx
392 push di
393 push word 16
394 mov si,sp
395 pushad
396 mov dl,[DriveNumber]
397 push ds
398 push ss
399 pop ds ; DS <- SS
400 mov ah,42h ; Extended Read
401 int 13h
402 pop ds
403 popad
404 lea sp,[si+16] ; Remove DAPA
405 jc .error
406 pop bp
407 add eax,edi ; Advance sector pointer
408 sub bp,di ; Sectors left
409 shl di,SECTOR_SHIFT ; 512-byte sectors
410 add bx,di ; Advance buffer pointer
411 and bp,bp
412 jnz .loop
416 .error:
417 ; Some systems seem to get "stuck" in an error state when
418 ; using EBIOS. Doesn't happen when using CBIOS, which is
419 ; good, since some other systems get timeout failures
420 ; waiting for the floppy disk to spin up.
422 pushad ; Try resetting the device
423 xor ax,ax
424 mov dl,[DriveNumber]
425 int 13h
426 popad
427 loop .retry ; CX-- and jump if not zero
429 ;shr word [MaxTransfer],1 ; Reduce the transfer size
430 ;jnz .retry2
432 ; Total failure. Try falling back to CBIOS.
433 mov byte [getlinsec.jmp+1],(getlinsec_cbios-(getlinsec.jmp+2))
434 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
436 pop bp
437 ; ... fall through ...
440 ; getlinsec_cbios:
442 ; getlinsec implementation for legacy CBIOS
444 getlinsec_cbios:
445 .loop:
446 push edx
447 push eax
448 push bp
449 push bx
451 movzx esi,word [bsSecPerTrack]
452 movzx edi,word [bsHeads]
454 ; Dividing by sectors to get (track,sector): we may have
455 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
457 div esi
458 xor cx,cx
459 xchg cx,dx ; CX <- sector index (0-based)
460 ; EDX <- 0
461 ; eax = track #
462 div edi ; Convert track to head/cyl
464 ; We should test this, but it doesn't fit...
465 ; cmp eax,1023
466 ; ja .error
469 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
470 ; BP = sectors to transfer, SI = bsSecPerTrack,
471 ; ES:BX = data target
474 call maxtrans ; Enforce maximum transfer size
476 ; Must not cross track boundaries, so BP <= SI-CX
477 sub si,cx
478 cmp bp,si
479 jna .bp_ok
480 mov bp,si
481 .bp_ok:
483 shl ah,6 ; Because IBM was STOOPID
484 ; and thought 8 bits were enough
485 ; then thought 10 bits were enough...
486 inc cx ; Sector numbers are 1-based, sigh
487 or cl,ah
488 mov ch,al
489 mov dh,dl
490 mov dl,[DriveNumber]
491 xchg ax,bp ; Sector to transfer count
492 mov ah,02h ; Read sectors
493 mov bp,retry_count
494 .retry:
495 pushad
496 int 13h
497 popad
498 jc .error
499 .resume:
500 movzx ecx,al ; ECX <- sectors transferred
501 shl ax,SECTOR_SHIFT ; Convert sectors in AL to bytes in AX
502 pop bx
503 add bx,ax
504 pop bp
505 pop eax
506 pop edx
507 add eax,ecx
508 sub bp,cx
509 jnz .loop
512 .error:
513 dec bp
514 jnz .retry
516 xchg ax,bp ; Sectors transferred <- 0
517 shr word [MaxTransfer],1
518 jnz .resume
519 ; Fall through to disk_error
522 ; kaboom: write a message and bail out.
524 disk_error:
525 kaboom:
526 xor si,si
527 mov ss,si
528 mov sp,StackBuf-4 ; Reset stack
529 mov ds,si ; Reset data segment
530 pop dword [fdctab] ; Restore FDC table
531 .patch: ; When we have full code, intercept here
532 mov si,bailmsg
534 ; Write error message, this assumes screen page 0
535 .loop: lodsb
536 and al,al
537 jz .done
538 mov ah,0Eh ; Write to screen as TTY
539 mov bx,0007h ; Attribute
540 int 10h
541 jmp short .loop
542 .done:
543 cbw ; AH <- 0
544 int 16h ; Wait for keypress
545 int 19h ; And try once more to boot...
546 .norge: jmp short .norge ; If int 19h returned; this is the end
549 ; Truncate BP to MaxTransfer
551 maxtrans:
552 cmp bp,[MaxTransfer]
553 jna .ok
554 mov bp,[MaxTransfer]
555 .ok: ret
558 ; Error message on failure
560 bailmsg: db 'Boot error', 0Dh, 0Ah, 0
562 ; This fails if the boot sector overflows
563 zb 1F8h-($-$$)
565 FirstSector dd 0xDEADBEEF ; Location of sector 1
566 MaxTransfer dw 0x007F ; Max transfer size
567 bootsignature dw 0AA55h
570 ; ===========================================================================
571 ; End of boot sector
572 ; ===========================================================================
573 ; Start of LDLINUX.SYS
574 ; ===========================================================================
576 ldlinux_sys:
578 syslinux_banner db 0Dh, 0Ah
579 %if IS_MDSLINUX
580 db 'MDSLINUX '
581 %else
582 db 'SYSLINUX '
583 %endif
584 db version_str, ' ', date, ' ', 0
585 db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
587 align 8, db 0
588 ldlinux_magic dd LDLINUX_MAGIC
589 dd LDLINUX_MAGIC^HEXDATE
592 ; This area is patched by the installer. It is found by looking for
593 ; LDLINUX_MAGIC, plus 8 bytes.
595 patch_area:
596 LDLDwords dw 0 ; Total dwords starting at ldlinux_sys
597 LDLSectors dw 0 ; Number of sectors - (bootsec+this sec)
598 CheckSum dd 0 ; Checksum starting at ldlinux_sys
599 ; value = LDLINUX_MAGIC - [sum of dwords]
601 ; Space for up to 64 sectors, the theoretical maximum
602 SectorPtrs times 64 dd 0
604 ldlinux_ent:
606 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
607 ; instead of 0000:7C00 and the like. We don't want to add anything
608 ; more to the boot sector, so it is written to not assume a fixed
609 ; value in CS, but we don't want to deal with that anymore from now
610 ; on.
612 jmp 0:.next
613 .next:
616 ; Tell the user we got this far
618 mov si,syslinux_banner
619 call writestr
622 ; Tell the user if we're using EBIOS or CBIOS
624 print_bios:
625 mov si,cbios_name
626 cmp byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
627 jne .cbios
628 mov si,ebios_name
629 .cbios:
630 mov [BIOSName],si
631 call writestr
633 section .bss
634 %define HAVE_BIOSNAME 1
635 BIOSName resw 1
637 section .text
639 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
640 ; sector again, though.
642 load_rest:
643 mov si,SectorPtrs
644 mov bx,7C00h+2*SECTOR_SIZE ; Where we start loading
645 mov cx,[LDLSectors]
647 .get_chunk:
648 jcxz .done
649 xor bp,bp
650 lodsd ; First sector of this chunk
652 mov edx,eax
654 .make_chunk:
655 inc bp
656 dec cx
657 jz .chunk_ready
658 inc edx ; Next linear sector
659 cmp [si],edx ; Does it match
660 jnz .chunk_ready ; If not, this is it
661 add si,4 ; If so, add sector to chunk
662 jmp short .make_chunk
664 .chunk_ready:
665 call getlinsecsr
666 shl bp,SECTOR_SHIFT
667 add bx,bp
668 jmp .get_chunk
670 .done:
673 ; All loaded up, verify that we got what we needed.
674 ; Note: the checksum field is embedded in the checksum region, so
675 ; by the time we get to the end it should all cancel out.
677 verify_checksum:
678 mov si,ldlinux_sys
679 mov cx,[LDLDwords]
680 mov edx,-LDLINUX_MAGIC
681 .checksum:
682 lodsd
683 add edx,eax
684 loop .checksum
686 and edx,edx ; Should be zero
687 jz all_read ; We're cool, go for it!
690 ; Uh-oh, something went bad...
692 mov si,checksumerr_msg
693 call writestr
694 jmp kaboom
697 ; -----------------------------------------------------------------------------
698 ; Subroutines that have to be in the first sector
699 ; -----------------------------------------------------------------------------
703 ; writestr: write a null-terminated string to the console
704 ; This assumes we're on page 0. This is only used for early
705 ; messages, so it should be OK.
707 writestr:
708 .loop: lodsb
709 and al,al
710 jz .return
711 mov ah,0Eh ; Write to screen as TTY
712 mov bx,0007h ; Attribute
713 int 10h
714 jmp short .loop
715 .return: ret
718 ; getlinsecsr: save registers, call getlinsec, restore registers
720 getlinsecsr: pushad
721 call getlinsec
722 popad
726 ; Checksum error message
728 checksumerr_msg db ' Load error - ', 0 ; Boot failed appended
731 ; BIOS type string
733 cbios_name db 'CBIOS', 0
734 ebios_name db 'EBIOS', 0
737 ; Debug routine
739 %ifdef debug
740 safedumpregs:
741 cmp word [Debug_Magic],0D00Dh
742 jnz nc_return
743 jmp dumpregs
744 %endif
746 rl_checkpt equ $ ; Must be <= 8000h
748 rl_checkpt_off equ ($-$$)
749 %ifndef DEPEND
750 %if rl_checkpt_off > 400h
751 %error "Sector 1 overflow"
752 %endif
753 %endif
755 ; ----------------------------------------------------------------------------
756 ; End of code and data that have to be in the first sector
757 ; ----------------------------------------------------------------------------
759 all_read:
761 ; Let the user (and programmer!) know we got this far. This used to be
762 ; in Sector 1, but makes a lot more sense here.
764 mov si,copyright_str
765 call writestr
769 ; Insane hack to expand the superblock to dwords
771 expand_super:
772 xor eax,eax
773 mov si,superblock
774 mov di,SuperInfo
775 mov cx,superinfo_size
776 .loop:
777 lodsw
778 dec si
779 stosd ; Store expanded word
780 xor ah,ah
781 stosd ; Store expanded byte
782 loop .loop
785 ; Compute some information about this filesystem.
788 ; First, generate the map of regions
789 genfatinfo:
790 mov edx,[bxSectors]
791 and dx,dx
792 jnz .have_secs
793 mov edx,[bsHugeSectors]
794 .have_secs:
795 mov [TotalSectors],edx
797 add edx,eax
798 mov [EndSector],edx
800 mov eax,[bxResSectors]
801 mov [FAT],eax ; Beginning of FAT
802 mov edx,[bxFATsecs]
803 and dx,dx
804 jnz .have_fatsecs
805 mov edx,[bootsec+36] ; FAT32 BPB_FATsz32
806 .have_fatsecs:
807 imul edx,[bxFATs]
808 add eax,edx
809 mov [RootDirArea],eax ; Beginning of root directory
810 mov [RootDir],eax ; For FAT12/16 == root dir location
812 mov edx,[bxRootDirEnts]
813 add dx,SECTOR_SIZE/32-1
814 shr dx,SECTOR_SHIFT-5
815 mov [RootDirSize],edx
816 add eax,edx
817 mov [DataArea],eax ; Beginning of data area
819 ; Next, generate a cluster size shift count and mask
820 mov eax,[bxSecPerClust]
821 bsr cx,ax
822 mov [ClustShift],cl
823 push cx
824 add cl,9
825 mov [ClustByteShift],cl
826 pop cx
827 dec ax
828 mov [ClustMask],eax
829 inc ax
830 shl eax,9
831 mov [ClustSize],eax
834 ; FAT12, FAT16 or FAT28^H^H32? This computation is fscking ridiculous.
836 getfattype:
837 mov eax,[EndSector]
838 sub eax,[DataArea]
839 shr eax,cl ; cl == ClustShift
840 mov cl,nextcluster_fat12-(nextcluster+2)
841 cmp eax,4085 ; FAT12 limit
842 jb .setsize
843 mov cl,nextcluster_fat16-(nextcluster+2)
844 cmp eax,65525 ; FAT16 limit
845 jb .setsize
847 ; FAT32, root directory is a cluster chain
849 mov cl,[ClustShift]
850 mov eax,[bootsec+44] ; Root directory cluster
851 sub eax,2
852 shl eax,cl
853 add eax,[DataArea]
854 mov [RootDir],eax
855 mov cl,nextcluster_fat28-(nextcluster+2)
856 .setsize:
857 mov byte [nextcluster+1],cl
860 ; Common initialization code
862 %include "cpuinit.inc"
863 %include "init.inc"
866 ; Clear Files structures
868 mov di,Files
869 mov cx,(MAX_OPEN*open_file_t_size)/4
870 xor eax,eax
871 rep stosd
874 ; Initialize the metadata cache
876 call initcache
879 ; Now, everything is "up and running"... patch kaboom for more
880 ; verbosity and using the full screen system
882 ; E9 = JMP NEAR
883 mov dword [kaboom.patch],0e9h+((kaboom2-(kaboom.patch+3)) << 8)
886 ; Now we're all set to start with our *real* business. First load the
887 ; configuration file (if any) and parse it.
889 ; In previous versions I avoided using 32-bit registers because of a
890 ; rumour some BIOSes clobbered the upper half of 32-bit registers at
891 ; random. I figure, though, that if there are any of those still left
892 ; they probably won't be trying to install Linux on them...
894 ; The code is still ripe with 16-bitisms, though. Not worth the hassle
895 ; to take'm out. In fact, we may want to put them back if we're going
896 ; to boot ELKS at some point.
900 ; Load configuration file
902 mov di,syslinux_cfg
903 call open
904 jz no_config_file
907 ; Now we have the config file open. Parse the config file and
908 ; run the user interface.
910 %include "ui.inc"
913 ; Linux kernel loading code is common.
915 %include "runkernel.inc"
918 ; COMBOOT-loading code
920 %include "comboot.inc"
921 %include "com32.inc"
922 %include "cmdline.inc"
925 ; Boot sector loading code
927 %include "bootsect.inc"
930 ; Abort loading code
932 %include "abort.inc"
935 ; allocate_file: Allocate a file structure
937 ; If successful:
938 ; ZF set
939 ; BX = file pointer
940 ; In unsuccessful:
941 ; ZF clear
943 allocate_file:
944 TRACER 'a'
945 push cx
946 mov bx,Files
947 mov cx,MAX_OPEN
948 .check: cmp dword [bx], byte 0
949 je .found
950 add bx,open_file_t_size ; ZF = 0
951 loop .check
952 ; ZF = 0 if we fell out of the loop
953 .found: pop cx
957 ; searchdir:
958 ; Search the root directory for a pre-mangled filename in DS:DI.
960 ; NOTE: This file considers finding a zero-length file an
961 ; error. This is so we don't have to deal with that special
962 ; case elsewhere in the program (most loops have the test
963 ; at the end).
965 ; If successful:
966 ; ZF clear
967 ; SI = file pointer
968 ; DX:AX = file length in bytes
969 ; If unsuccessful
970 ; ZF set
973 searchdir:
974 push bx
975 call allocate_file
976 jnz .alloc_failure
978 push cx
979 push gs
980 push es
981 push ds
982 pop es ; ES = DS
984 mov eax,[RootDir] ; First root directory sector
986 .scansector:
987 call getcachesector
988 ; GS:SI now points to this sector
990 mov cx,SECTOR_SIZE/32 ; 32 == directory entry size
991 .scanentry:
992 cmp byte [gs:si],0
993 jz .failure ; Hit directory high water mark
994 push cx
995 push si
996 push di
997 mov cx,11
998 gs repe cmpsb
999 pop di
1000 pop si
1001 pop cx
1002 jz .found
1003 add si,32
1004 loop .scanentry
1006 call nextsector
1007 jnc .scansector ; CF is set if we're at end
1009 ; If we get here, we failed
1010 .failure:
1011 pop es
1012 pop gs
1013 pop cx
1014 .alloc_failure:
1015 pop bx
1016 xor eax,eax ; ZF <- 1
1018 .found:
1019 mov eax,[gs:si+28] ; File size
1020 add eax,SECTOR_SIZE-1
1021 shr eax,SECTOR_SHIFT
1022 jz .failure ; Zero-length file
1023 mov [bx+4],eax
1025 mov cl,[ClustShift]
1026 mov dx,[gs:si+20] ; High cluster word
1027 shl edx,16
1028 mov dx,[gs:si+26] ; Low cluster word
1029 sub edx,2
1030 shl edx,cl
1031 add edx,[DataArea]
1032 mov [bx],edx ; Starting sector
1034 mov eax,[gs:si+28] ; File length again
1035 mov dx,[gs:si+30] ; 16-bitism, sigh
1036 mov si,bx
1037 and eax,eax ; ZF <- 0
1039 pop es
1040 pop gs
1041 pop cx
1042 pop bx
1047 ; kaboom2: once everything is loaded, replace the part of kaboom
1048 ; starting with "kaboom.patch" with this part
1050 kaboom2:
1051 mov si,err_bootfailed
1052 call cwritestr
1053 call getchar
1054 call vgaclearmode
1055 int 19h ; And try once more to boot...
1056 .norge: jmp short .norge ; If int 19h returned; this is the end
1059 ; mangle_name: Mangle a DOS filename pointed to by DS:SI into a buffer pointed
1060 ; to by ES:DI; ends on encountering any whitespace
1063 mangle_name:
1064 mov cx,11 ; # of bytes to write
1065 mn_loop:
1066 lodsb
1067 cmp al,' ' ; If control or space, end
1068 jna mn_end
1069 cmp al,'.' ; Period -> space-fill
1070 je mn_is_period
1071 cmp al,'a'
1072 jb mn_not_lower
1073 cmp al,'z'
1074 ja mn_not_uslower
1075 sub al,020h
1076 jmp short mn_not_lower
1077 mn_is_period: mov al,' ' ; We need to space-fill
1078 mn_period_loop: cmp cx,3 ; If <= 3 characters left
1079 jbe mn_loop ; Just ignore it
1080 stosb ; Otherwise, write a period
1081 loop mn_period_loop ; Dec CX and (always) jump
1082 mn_not_uslower: cmp al,ucase_low
1083 jb mn_not_lower
1084 cmp al,ucase_high
1085 ja mn_not_lower
1086 mov bx,ucase_tab-ucase_low
1087 cs xlatb
1088 mn_not_lower: stosb
1089 loop mn_loop ; Don't continue if too long
1090 mn_end:
1091 mov al,' ' ; Space-fill name
1092 rep stosb ; Doesn't do anything if CX=0
1093 ret ; Done
1096 ; Upper-case table for extended characters; this is technically code page 865,
1097 ; but code page 437 users will probably not miss not being able to use the
1098 ; cent sign in kernel images too much :-)
1100 ; The table only covers the range 129 to 164; the rest we can deal with.
1102 ucase_low equ 129
1103 ucase_high equ 164
1104 ucase_tab db 154, 144, 'A', 142, 'A', 143, 128, 'EEEIII'
1105 db 142, 143, 144, 146, 146, 'O', 153, 'OUUY', 153, 154
1106 db 157, 156, 157, 158, 159, 'AIOU', 165
1109 ; unmangle_name: Does the opposite of mangle_name; converts a DOS-mangled
1110 ; filename to the conventional representation. This is needed
1111 ; for the BOOT_IMAGE= parameter for the kernel.
1112 ; NOTE: A 13-byte buffer is mandatory, even if the string is
1113 ; known to be shorter.
1115 ; DS:SI -> input mangled file name
1116 ; ES:DI -> output buffer
1118 ; On return, DI points to the first byte after the output name,
1119 ; which is set to a null byte.
1121 unmangle_name:
1122 push si ; Save pointer to original name
1123 mov cx,8
1124 mov bp,di
1125 un_copy_body: lodsb
1126 call lower_case
1127 stosb
1128 cmp al,' '
1129 jbe un_cb_space
1130 mov bp,di ; Position of last nonblank+1
1131 un_cb_space: loop un_copy_body
1132 mov di,bp
1133 mov al,'.' ; Don't save
1134 stosb
1135 mov cx,3
1136 un_copy_ext: lodsb
1137 call lower_case
1138 stosb
1139 cmp al,' '
1140 jbe un_ce_space
1141 mov bp,di
1142 un_ce_space: loop un_copy_ext
1143 mov di,bp
1144 mov byte [es:di], 0
1145 pop si
1149 ; lower_case: Lower case a character in AL
1151 lower_case:
1152 cmp al,'A'
1153 jb lc_ret
1154 cmp al,'Z'
1155 ja lc_1
1156 or al,20h
1158 lc_1: cmp al,lcase_low
1159 jb lc_ret
1160 cmp al,lcase_high
1161 ja lc_ret
1162 push bx
1163 mov bx,lcase_tab-lcase_low
1164 cs xlatb
1165 pop bx
1166 lc_ret: ret
1169 ; getfssec_edx: Get multiple sectors from a file
1171 ; This routine makes sure the subtransfers do not cross a 64K boundary,
1172 ; and will correct the situation if it does, UNLESS *sectors* cross
1173 ; 64K boundaries.
1175 ; ES:BX -> Buffer
1176 ; EDX -> Current sector number
1177 ; CX -> Sector count (0FFFFh = until end of file)
1178 ; Must not exceed the ES segment
1179 ; Returns EDX=0, CF=1 on EOF (not necessarily error)
1180 ; All arguments are advanced to reflect data read.
1182 getfssec_edx:
1183 push ebp
1184 push eax
1185 .getfragment:
1186 xor ebp,ebp ; Fragment sector count
1187 push edx ; Starting sector pointer
1188 .getseccnt:
1189 inc bp
1190 dec cx
1191 jz .do_read
1192 xor eax,eax
1193 mov ax,es
1194 shl ax,4
1195 add ax,bx ; Now AX = how far into 64K block we are
1196 not ax ; Bytes left in 64K block
1197 inc eax
1198 shr eax,SECTOR_SHIFT ; Sectors left in 64K block
1199 cmp bp,ax
1200 jnb .do_read ; Unless there is at least 1 more sector room...
1201 mov eax,edx ; Current sector
1202 inc edx ; Predict it's the linearly next sector
1203 call nextsector
1204 jc .do_read
1205 cmp edx,eax ; Did it match?
1206 jz .getseccnt
1207 .do_read:
1208 pop eax ; Starting sector pointer
1209 call getlinsecsr
1210 lea eax,[eax+ebp-1] ; This is the last sector actually read
1211 shl bp,9
1212 add bx,bp ; Adjust buffer pointer
1213 call nextsector
1214 jc .eof
1215 mov edx,eax
1216 and cx,cx
1217 jnz .getfragment
1218 .done:
1219 pop eax
1220 pop ebp
1222 .eof:
1223 xor edx,edx
1225 jmp .done
1228 ; getfssec: Get multiple sectors from a file
1230 ; Same as above, except SI is a pointer to a open_file_t
1232 ; ES:BX -> Buffer
1233 ; DS:SI -> Pointer to open_file_t
1234 ; CX -> Sector count (0FFFFh = until end of file)
1235 ; Must not exceed the ES segment
1236 ; Returns CF=1 on EOF (not necessarily error)
1237 ; All arguments are advanced to reflect data read.
1239 getfssec:
1240 push edx
1241 movzx edx,cx
1242 cmp edx,[si+4]
1243 jbe .sizeok
1244 mov edx,[si+4]
1245 mov cx,dx
1246 .sizeok:
1247 sub [si+4],edx
1248 mov edx,[si]
1249 call getfssec_edx
1250 mov [si],edx
1251 pop edx
1255 ; nextcluster: Advance a cluster pointer in EDI to the next cluster
1256 ; pointed at in the FAT tables. CF=0 on return if end of file.
1258 nextcluster:
1259 jmp strict short nextcluster_fat28 ; This gets patched
1261 nextcluster_fat12:
1262 push eax
1263 push edx
1264 push bx
1265 push cx
1266 push si
1267 mov edx,edi
1268 shr edi,1
1269 pushf ; Save the shifted-out LSB (=CF)
1270 add edx,edi
1271 mov eax,edx
1272 shr eax,9
1273 call getfatsector
1274 mov bx,dx
1275 and bx,1FFh
1276 mov cl,[gs:si+bx]
1277 inc edx
1278 mov eax,edx
1279 shr eax,9
1280 call getfatsector
1281 mov bx,dx
1282 and bx,1FFh
1283 mov ch,[gs:si+bx]
1284 popf
1285 jnc .even
1286 shr cx,4
1287 .even: and cx,0FFFh
1288 movzx edi,cx
1289 cmp di,0FF0h
1290 pop si
1291 pop cx
1292 pop bx
1293 pop edx
1294 pop eax
1298 ; FAT16 decoding routine.
1300 nextcluster_fat16:
1301 push eax
1302 push si
1303 push bx
1304 mov eax,edi
1305 shr eax,SECTOR_SHIFT-1
1306 call getfatsector
1307 mov bx,di
1308 add bx,bx
1309 and bx,1FEh
1310 movzx edi,word [gs:si+bx]
1311 cmp di,0FFF0h
1312 pop bx
1313 pop si
1314 pop eax
1317 ; FAT28 ("FAT32") decoding routine.
1319 nextcluster_fat28:
1320 push eax
1321 push si
1322 push bx
1323 mov eax,edi
1324 shr eax,SECTOR_SHIFT-2
1325 call getfatsector
1326 mov bx,di
1327 add bx,bx
1328 add bx,bx
1329 and bx,1FCh
1330 mov edi,dword [gs:si+bx]
1331 and edi,0FFFFFFFh ; 28 bits only
1332 cmp edi,0FFFFFF0h
1333 pop bx
1334 pop si
1335 pop eax
1339 ; nextsector: Given a sector in EAX on input, return the next sector
1340 ; of the same filesystem object, which may be the root
1341 ; directory or a cluster chain. Returns EOF.
1343 ; Assumes CS == DS.
1345 nextsector:
1346 push edi
1347 push edx
1348 mov edx,[DataArea]
1349 mov edi,eax
1350 sub edi,edx
1351 jae .isdata
1353 ; Root directory
1354 inc eax
1355 cmp eax,edx
1357 jmp .done
1359 .isdata:
1360 not edi
1361 test edi,[ClustMask]
1362 jz .endcluster
1364 ; It's not the final sector in a cluster
1365 inc eax
1366 jmp .done
1368 .endcluster:
1369 push gs ; nextcluster trashes gs
1370 push cx
1371 not edi
1372 mov cl,[ClustShift]
1373 shr edi,cl
1374 add edi,2
1376 ; Now EDI contains the cluster number
1377 call nextcluster
1379 jc .exit ; There isn't anything else...
1381 ; New cluster number now in EDI
1382 sub edi,2
1383 shl edi,cl ; CF <- 0, unless something is very wrong
1384 lea eax,[edi+edx]
1385 .exit:
1386 pop cx
1387 pop gs
1388 .done:
1389 pop edx
1390 pop edi
1394 ; getfatsector: Check for a particular sector (in EAX) in the FAT cache,
1395 ; and return a pointer in GS:SI, loading it if needed.
1397 ; Assumes CS == DS.
1399 getfatsector:
1400 add eax,[FAT] ; FAT starting address
1401 jmp getcachesector
1403 ; -----------------------------------------------------------------------------
1404 ; Common modules
1405 ; -----------------------------------------------------------------------------
1407 %include "getc.inc" ; getc et al
1408 %include "conio.inc" ; Console I/O
1409 %include "plaincon.inc" ; writechr
1410 %include "writestr.inc" ; String output
1411 %include "parseconfig.inc" ; High-level config file handling
1412 %include "parsecmd.inc" ; Low-level config file handling
1413 %include "bcopy32.inc" ; 32-bit bcopy
1414 %include "loadhigh.inc" ; Load a file into high memory
1415 %include "font.inc" ; VGA font stuff
1416 %include "graphics.inc" ; VGA graphics
1417 %include "highmem.inc" ; High memory sizing
1418 %include "strcpy.inc" ; strcpy()
1419 %include "cache.inc" ; Metadata disk cache
1421 ; -----------------------------------------------------------------------------
1422 ; Begin data section
1423 ; -----------------------------------------------------------------------------
1425 section .data
1427 ; Lower-case table for codepage 865
1429 lcase_low equ 128
1430 lcase_high equ 165
1431 lcase_tab db 135, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138
1432 db 139, 140, 141, 132, 134, 130, 145, 145, 147, 148, 149
1433 db 150, 151, 152, 148, 129, 155, 156, 155, 158, 159, 160
1434 db 161, 162, 163, 164, 164
1436 copyright_str db ' Copyright (C) 1994-', year, ' H. Peter Anvin'
1437 db CR, LF, 0
1438 boot_prompt db 'boot: ', 0
1439 wipe_char db BS, ' ', BS, 0
1440 err_notfound db 'Could not find kernel image: ',0
1441 err_notkernel db CR, LF, 'Invalid or corrupt kernel image.', CR, LF, 0
1442 err_noram db 'It appears your computer has less than '
1443 asciidec dosram_k
1444 db 'K of low ("DOS")'
1445 db CR, LF
1446 db 'RAM. Linux needs at least this amount to boot. If you get'
1447 db CR, LF
1448 db 'this message in error, hold down the Ctrl key while'
1449 db CR, LF
1450 db 'booting, and I will take your word for it.', CR, LF, 0
1451 err_badcfg db 'Unknown keyword in syslinux.cfg.', CR, LF, 0
1452 err_noparm db 'Missing parameter in syslinux.cfg.', CR, LF, 0
1453 err_noinitrd db CR, LF, 'Could not find ramdisk image: ', 0
1454 err_nohighmem db 'Not enough memory to load specified kernel.', CR, LF, 0
1455 err_highload db CR, LF, 'Kernel transfer failure.', CR, LF, 0
1456 err_oldkernel db 'Cannot load a ramdisk with an old kernel image.'
1457 db CR, LF, 0
1458 err_notdos db ': attempted DOS system call', CR, LF, 0
1459 err_comlarge db 'COMBOOT image too large.', CR, LF, 0
1460 err_a20 db CR, LF, 'A20 gate not responding!', CR, LF, 0
1461 err_bootfailed db CR, LF, 'Boot failed: please change disks and press '
1462 db 'a key to continue.', CR, LF, 0
1463 ready_msg db 'Ready.', CR, LF, 0
1464 crlfloading_msg db CR, LF
1465 loading_msg db 'Loading ', 0
1466 dotdot_msg db '.'
1467 dot_msg db '.', 0
1468 aborted_msg db ' aborted.' ; Fall through to crlf_msg!
1469 crlf_msg db CR, LF
1470 null_msg db 0
1471 crff_msg db CR, FF, 0
1472 syslinux_cfg db 'SYSLINUXCFG' ; Mangled form
1473 ConfigName db 'syslinux.cfg',0 ; Unmangled form
1474 %if IS_MDSLINUX
1475 manifest db 'MANIFEST '
1476 %endif
1478 ; Command line options we'd like to take a look at
1480 ; mem= and vga= are handled as normal 32-bit integer values
1481 initrd_cmd db 'initrd='
1482 initrd_cmd_len equ 7
1485 ; Config file keyword table
1487 %include "keywords.inc"
1490 ; Extensions to search for (in *forward* order).
1492 exten_table: db 'CBT',0 ; COMBOOT (specific)
1493 db 'BSS',0 ; Boot Sector (add superblock)
1494 db 'BS ',0 ; Boot Sector
1495 db 'COM',0 ; COMBOOT (same as DOS)
1496 db 'C32',0 ; COM32
1497 exten_table_end:
1498 dd 0, 0 ; Need 8 null bytes here
1501 ; Misc initialized (data) variables
1503 %ifdef debug ; This code for debugging only
1504 debug_magic dw 0D00Dh ; Debug code sentinel
1505 %endif
1507 alignb 4, db 0
1508 BufSafe dw trackbufsize/SECTOR_SIZE ; Clusters we can load into trackbuf
1509 BufSafeSec dw trackbufsize/SECTOR_SIZE ; = how many sectors?
1510 BufSafeBytes dw trackbufsize ; = how many bytes?
1511 EndOfGetCBuf dw getcbuf+trackbufsize ; = getcbuf+BufSafeBytes
1512 %ifndef DEPEND
1513 %if ( trackbufsize % SECTOR_SIZE ) != 0
1514 %error trackbufsize must be a multiple of SECTOR_SIZE
1515 %endif
1516 %endif