1 ; -----------------------------------------------------------------------
3 ; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
4 ; Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
6 ; This program is free software; you can redistribute it and/or modify
7 ; it under the terms of the GNU General Public License as published by
8 ; the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
9 ; Boston MA 02110-1301, USA; either version 2 of the License, or
10 ; (at your option) any later version; incorporated herein by reference.
12 ; -----------------------------------------------------------------------
17 ; Common early-bootstrap code for harddisk-based Syslinux derivatives.
22 PartInfo: ; Partition table info
23 .mbr: resb 16 ; MBR partition info
25 .gpt: resb 56 ; GPT partition info (minus name)
26 FloppyTable resb 16 ; Floppy info table (must follow PartInfo)
30 ; Some of the things that have to be saved very early are saved
31 ; "close" to the initial stack pointer offset, in order to
32 ; reduce the code size...
34 StackBuf equ STACK_TOP-44 ; Start the stack here (grow down - 4K)
35 Hidden equ StackBuf-20 ; Partition offset
36 OrigFDCTabPtr equ StackBuf-12 ; The 2nd high dword on the stack
37 OrigESDI equ StackBuf-8 ; The high dword on the stack
38 DriveNumber equ StackBuf-4 ; Drive number
39 StackHome equ Hidden ; The start of the canonical stack
42 ; Primary entry point. Tempting as though it may be, we can't put the
43 ; initial "cli" here; the jmp opcode in the first byte is part of the
44 ; "magic number" (using the term very loosely) for the DOS superblock.
47 _start: jmp short start ; 2 bytes
50 ; "Superblock" follows -- it's in the boot sector, so it's already
51 ; loaded and ready for us
53 bsOemName db MY_NAME ; The SYS command sets this, so...
57 ; These are the fields we actually care about. We end up expanding them
58 ; all to dword size early in the code, so generate labels for both
59 ; the expanded and unexpanded versions.
62 bx %+ %1 equ SuperInfo+($-superblock)*8+4
67 bx %+ %1 equ SuperInfo+($-superblock)*8
72 bx %+ %1 equ $ ; no expansion for dwords
87 superinfo_size equ ($-superblock)-1 ; How much to expand
91 ; This is as far as FAT12/16 and FAT32 are consistent
93 ; FAT12/16 need 26 more bytes,
94 ; FAT32 need 54 more bytes
96 superblock_len_fat16 equ $-superblock+26
97 superblock_len_fat32 equ $-superblock+54
98 zb 54 ; Maximum needed size
99 superblock_max equ $-superblock
102 SecPerClust equ bxSecPerClust
105 ; Note we don't check the constraints above now; we did that at install
109 cli ; No interrupts yet, please
116 mov sp,StackBuf-2 ; Just below BSS (-2 for alignment)
117 push dx ; Save drive number (in DL)
118 push es ; Save initial ES:DI -> $PnP pointer
123 ; DS:SI may contain a partition table entry and possibly a GPT entry.
124 ; Preserve it for us. This saves 56 bytes of the GPT entry, which is
125 ; currently the maximum we care about. Total is 76 bytes.
127 mov cl,(16+4+56)/2 ; Save partition info
129 rep movsw ; This puts CX back to zero
131 mov ds,cx ; Now we can initialize DS...
134 ; Now sautee the BIOS floppy info block to that it will support decent-
135 ; size transfers; the floppy block is 11 bytes and is stored in the
136 ; INT 1Eh vector (brilliant waste of resources, eh?)
138 ; Of course, if BIOSes had been properly programmed, we wouldn't have
139 ; had to waste precious space with this code.
142 lfs si,[bx] ; FS:SI -> original fdctab
143 push fs ; Save on stack in case we need to bail
146 ; Save the old fdctab even if hard disk so the stack layout
147 ; is the same. The instructions above do not change the flags
148 and dl,dl ; If floppy disk (00-7F), assume no
154 mov cl,6 ; 12 bytes (CX == 0)
155 ; es:di -> FloppyTable already
156 ; This should be safe to do now, interrupts are off...
157 mov [bx],di ; FloppyTable
158 mov [bx+2],ax ; Segment 0
159 fs rep movsw ; Faster to move words
160 mov cl,[bsSecPerTrack] ; Patch the sector count
163 push ax ; Partition offset == 0
168 int 13h ; Some BIOSes need this
169 jmp short not_harddisk
171 ; The drive number and possibly partition information was passed to us
172 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to
173 ; trust that rather than what the superblock contains.
175 ; Note: di points to beyond the end of PartInfo
178 test byte [di-76],7Fh ; Sanity check: "active flag" should
179 jnz .no_partition ; be 00 or 80
180 cmp eax,'!GPT' ; !GPT signature?
182 cmp byte [di-76+4],0EDh ; Synthetic GPT partition entry?
184 .gpt: ; GPT-style partition info
185 push dword [di-76+20+36]
186 push dword [di-76+20+32]
188 .mbr: ; MBR-style partition info
189 push cx ; Upper half partition offset == 0
191 push dword [di-76+8] ; Partition offset (dword)
200 ; Get disk drive parameters (don't trust the superblock.) Don't do this for
201 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
202 ; what the *drive* supports, not about the *media*. Fortunately floppy disks
203 ; tend to have a fixed, well-defined geometry which is stored in the superblock.
205 ; DL == drive # still
212 inc dx ; Contains # of heads - 1
215 mov [bsSecPerTrack],cx
219 ; Ready to enable interrupts, captain
224 ; Do we have EBIOS (EDD)?
228 mov ah,41h ; EDD existence query
234 test cl,1 ; Extended disk access functionality set
237 ; We have EDD support...
239 mov byte [getonesec.jmp+1],(getonesec_ebios-(getonesec.jmp+2))
243 ; Load the first sector of LDLINUX.SYS; this used to be all proper
244 ; with parsing the superblock and root directory; it doesn't fit
245 ; together with EBIOS support, unfortunately.
247 mov eax,strict dword 0xdeadbeef
249 mov edx,strict dword 0xfeedface
251 mov bx,ldlinux_sys ; Where to load it
254 ; Some modicum of integrity checking
255 cmp dword [ldlinux_magic+4],LDLINUX_MAGIC^HEXDATE
263 ; getonesec: load a single disk linear sector EDX:EAX into the buffer
266 ; This routine assumes CS == DS == SS, and trashes most registers.
268 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
269 ; that is dead from that point; this saves space. However, please keep
270 ; the order to dst,src to keep things sane.
273 add eax,[Hidden] ; Add partition offset
276 .jmp: jmp strict short getonesec_cbios
281 ; getonesec implementation for EBIOS (EDD)
293 mov ah,42h ; Extended Read
295 lea sp,[si+16] ; Remove DAPA
300 ; Some systems seem to get "stuck" in an error state when
301 ; using EBIOS. Doesn't happen when using CBIOS, which is
302 ; good, since some other systems get timeout failures
303 ; waiting for the floppy disk to spin up.
305 pushad ; Try resetting the device
309 loop .retry ; CX-- and jump if not zero
311 ; Total failure. Try falling back to CBIOS.
312 mov byte [getonesec.jmp+1],(getonesec_cbios-(getonesec.jmp+2))
317 ; getlinsec implementation for legacy CBIOS
323 movzx esi,word [bsSecPerTrack]
324 movzx edi,word [bsHeads]
326 ; Dividing by sectors to get (track,sector): we may have
327 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
331 xchg cx,dx ; CX <- sector index (0-based)
334 div edi ; Convert track to head/cyl
336 cmp eax,1023 ; Outside the CHS range?
340 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
341 ; SI = bsSecPerTrack, ES:BX = data target
343 shl ah,6 ; Because IBM was STOOPID
344 ; and thought 8 bits were enough
345 ; then thought 10 bits were enough...
346 inc cx ; Sector numbers are 1-based, sigh
350 mov ax,0201h ; Read one sector
358 ; Fall through to disk_error
361 ; kaboom: write a message and bail out.
368 mov sp,OrigFDCTabPtr ; Reset stack
369 mov ds,si ; Reset data segment
370 pop dword [fdctab] ; Restore FDC table
371 .patch: ; When we have full code, intercept here
376 .again: int 16h ; Wait for keypress
377 ; NB: replaced by int 18h if
378 ; chosen at install time..
379 int 19h ; And try once more to boot...
380 .norge: hlt ; If int 19h returned; this is the end
385 ; writestr_early: write a null-terminated string to the console
386 ; This assumes we're on page 0. This is only used for early
387 ; messages, so it should be OK.
394 mov ah,0Eh ; Write to screen as TTY
395 mov bx,0007h ; Attribute
402 ; INT 13h wrapper function
412 ; Error message on failure
414 bailmsg: db 'Boot error', 0Dh, 0Ah, 0
416 ; This fails if the boot sector overflowsg
419 bootsignature dw 0xAA55
422 ; ===========================================================================
424 ; ===========================================================================
425 ; Start of LDLINUX.SYS
426 ; ===========================================================================
428 LDLINUX_SYS equ ($-$$)+TEXT_START
431 syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
432 db CR, LF, 1Ah ; EOF if we "type" this in DOS
435 ldlinux_magic dd LDLINUX_MAGIC
436 dd LDLINUX_MAGIC^HEXDATE
439 ; This area is patched by the installer. It is found by looking for
440 ; LDLINUX_MAGIC, plus 8 bytes.
443 CURRENTDIR_MAX equ FILENAME_MAX
446 DataSectors dw 0 ; Number of sectors (not including bootsec)
447 ADVSectors dw 0 ; Additional sectors for ADVs
448 LDLDwords dd 0 ; Total dwords starting at ldlinux_sys,
449 CheckSum dd 0 ; Checksum starting at ldlinux_sys
450 ; value = LDLINUX_MAGIC - [sum of dwords]
451 MaxTransfer dw 127 ; Max sectors to transfer
452 EPAPtr dw EPA - LDLINUX_SYS ; Pointer to the extended patch area
455 ; Extended patch area -- this is in .data16 so it doesn't occupy space in
456 ; the first sector. Use this structure for anything that isn't used by
457 ; the first sector itself.
462 ADVSecPtr dw ADVSec0 - LDLINUX_SYS
463 CurrentDirPtr dw CurrentDirName-LDLINUX_SYS ; Current directory name string
464 CurrentDirLen dw CURRENTDIR_MAX
465 SubvolPtr dw SubvolName-LDLINUX_SYS
466 SubvolLen dw SUBVOL_MAX
467 SecPtrOffset dw SectorPtrs-LDLINUX_SYS
468 SecPtrCnt dw (SectorPtrsEnd - SectorPtrs)/10
471 ; Boot sector patch pointers
473 Sect1Ptr0Ptr dw Sect1Ptr0 - bootsec ; Pointers to Sector 1 location
474 Sect1Ptr1Ptr dw Sect1Ptr1 - bootsec
475 RAIDPatchPtr dw kaboom.again - bootsec ; Patch to INT 18h in RAID mode
478 ; Base directory name and subvolume, if applicable.
480 %define HAVE_CURRENTDIRNAME
481 global CurrentDirName, SubvolName
482 CurrentDirName times CURRENTDIR_MAX db 0
483 SubvolName times SUBVOL_MAX db 0
488 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
489 ; instead of 0000:7C00 and the like. We don't want to add anything
490 ; more to the boot sector, so it is written to not assume a fixed
491 ; value in CS, but we don't want to deal with that anymore from now
494 sti ; In case of broken INT 13h BIOSes
497 ; Tell the user we got this far
499 mov si,syslinux_banner
503 ; Checksum data thus far
506 mov cx,SECTOR_SIZE >> 2
507 mov edx,-LDLINUX_MAGIC
512 mov [CheckSum],edx ; Save intermediate result
515 ; Tell the user if we're using EBIOS or CBIOS
519 cmp byte [getonesec.jmp+1],(getonesec_ebios-(getonesec.jmp+2))
522 mov byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
528 %define HAVE_BIOSNAME 1
533 ; Now we read the rest of LDLINUX.SYS.
537 mov ebx,TEXT_START+2*SECTOR_SIZE ; Where we start loading
539 dec cx ; Minus this sector
545 movzx ebp,word [si+8]
548 shr ebx,4 ; Convert to a segment
561 ; All loaded up, verify that we got what we needed.
562 ; Note: the checksum field is embedded in the checksum region, so
563 ; by the time we get to the end it should all cancel out.
566 mov si,ldlinux_sys + SECTOR_SIZE
568 sub ecx,SECTOR_SIZE >> 2
574 ; Handle segment wrap
582 and eax,eax ; Should be zero
583 jz all_read ; We're cool, go for it!
586 ; Uh-oh, something went bad...
588 mov si,checksumerr_msg
593 ; -----------------------------------------------------------------------------
594 ; Subroutines that have to be in the first sector
595 ; -----------------------------------------------------------------------------
600 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
601 ; number in EAX into the buffer at ES:BX. We try to optimize
602 ; by loading up to a whole track at a time, but the user
603 ; is responsible for not crossing a 64K boundary.
604 ; (Yes, BP is weird for a count, but it was available...)
606 ; On return, BX points to the first byte after the transferred
609 ; This routine assumes CS == DS.
614 add eax,[Hidden] ; Add partition offset
616 .jmp: jmp strict short getlinsec_cbios
621 ; getlinsec implementation for EBIOS (EDD)
625 push bp ; Sectors left
627 call maxtrans ; Enforce maximum transfer size
628 movzx edi,bp ; Sectors we are about to read
640 mov ah,42h ; Extended Read
646 lea sp,[si+16] ; Remove DAPA
649 add eax,edi ; Advance sector pointer
651 sub bp,di ; Sectors left
652 shl di,SECTOR_SHIFT ; 512-byte sectors
653 add bx,di ; Advance buffer pointer
661 ; Some systems seem to get "stuck" in an error state when
662 ; using EBIOS. Doesn't happen when using CBIOS, which is
663 ; good, since some other systems get timeout failures
664 ; waiting for the floppy disk to spin up.
666 pushad ; Try resetting the device
671 loop .retry ; CX-- and jump if not zero
673 ;shr word [MaxTransfer],1 ; Reduce the transfer size
676 ; Total failure. Try falling back to CBIOS.
677 mov byte [getlinsec.jmp+1],(getlinsec_cbios-(getlinsec.jmp+2))
678 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
681 ; ... fall through ...
686 ; getlinsec implementation for legacy CBIOS
695 movzx esi,word [bsSecPerTrack]
696 movzx edi,word [bsHeads]
698 ; Dividing by sectors to get (track,sector): we may have
699 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
703 xchg cx,dx ; CX <- sector index (0-based)
706 div edi ; Convert track to head/cyl
708 cmp eax,1023 ; Outside the CHS range?
712 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
713 ; BP = sectors to transfer, SI = bsSecPerTrack,
714 ; ES:BX = data target
717 call maxtrans ; Enforce maximum transfer size
719 ; Must not cross track boundaries, so BP <= SI-CX
726 shl ah,6 ; Because IBM was STOOPID
727 ; and thought 8 bits were enough
728 ; then thought 10 bits were enough...
729 inc cx ; Sector numbers are 1-based, sigh
733 xchg ax,bp ; Sector to transfer count
734 mov ah,02h ; Read sectors
740 movzx ecx,al ; ECX <- sectors transferred
741 shl ax,SECTOR_SHIFT ; Convert sectors in AL to bytes in AX
757 xchg ax,bp ; Sectors transferred <- 0
758 shr word [MaxTransfer],1
769 ; Checksum error message
771 checksumerr_msg db ' Load error - ', 0 ; Boot failed appended
776 cbios_name db 'CHS', 0 ; CHS/CBIOS
777 ebios_name db 'EDD', 0 ; EDD/EBIOS
784 cmp word [Debug_Magic],0D00Dh
789 rl_checkpt equ $ ; Must be <= 8000h
791 rl_checkpt_off equ ($-$$)
793 %if rl_checkpt_off > 3F6h ; Need one extent
794 %assign rl_checkpt_overflow rl_checkpt_off - 3F6h
795 %error Sector 1 overflow by rl_checkpt_overflow bytes
800 ; Extent pointers... each extent contains an 8-byte LBA and an 2-byte
801 ; sector count. In most cases, we will only ever need a handful of
802 ; extents, but we have to assume a maximally fragmented system where each
803 ; extent contains only one sector.
806 MaxInitDataSize equ 96 << 10
807 MaxLMA equ TEXT_START+SECTOR_SIZE+MaxInitDataSize
808 SectorPtrs zb 10*(MaxInitDataSize >> SECTOR_SHIFT)
811 ; ----------------------------------------------------------------------------
812 ; End of code and data that have to be in the first sector
813 ; ----------------------------------------------------------------------------
817 ; We enter here with both DS and ES scrambled...
822 ; Let the user (and programmer!) know we got this far. This used to be
823 ; in Sector 1, but makes a lot more sense here.
830 ; Insane hack to expand the DOS superblock to dwords
836 mov cx,superinfo_size
840 stosd ; Store expanded word
842 stosd ; Store expanded byte
847 ; Common initialization code
853 movzx dx,byte [DriveNumber]
854 ; DH = 0: we are boot from disk not CDROM
858 mov di,[bsSecPerTrack]
859 movzx ebp,word [MaxTransfer]
864 SuperInfo resq 16 ; The first 16 bytes expanded 8 times