1 ; -----------------------------------------------------------------------
3 ; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
4 ; Copyright 2009-2011 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.
20 Sect1Ptr0_VAL equ 0xdeadbeef
21 Sect1Ptr1_VAL equ 0xfeedface
23 %include "diskboot.inc"
25 ; ===========================================================================
26 ; Padding after the (minimum) 512-byte boot sector so that the rest of
27 ; the file has aligned sectors, even if they are larger than 512 bytes.
28 ; ===========================================================================
33 ; ===========================================================================
34 ; Start of LDLINUX.SYS
35 ; ===========================================================================
37 LDLINUX_SYS equ ($-$$)+TEXT_START
40 early_banner db CR, LF, MY_NAME, ' ', VERSION_STR, ' ', 0
41 db CR, LF, 1Ah ; EOF if we "type" this in DOS
44 ldlinux_magic dd LDLINUX_MAGIC
45 dd LDLINUX_MAGIC^HEXDATE
48 ; This area is patched by the installer. It is found by looking for
49 ; LDLINUX_MAGIC, plus 8 bytes.
52 CURRENTDIR_MAX equ FILENAME_MAX
55 DataSectors dw 0 ; Number of sectors (not including bootsec)
56 ADVSectors dw 0 ; Additional sectors for ADVs
57 LDLDwords dd 0 ; Total dwords starting at ldlinux_sys,
58 CheckSum dd 0 ; Checksum starting at ldlinux_sys
59 ; value = LDLINUX_MAGIC - [sum of dwords]
60 MaxTransfer dw 127 ; Max sectors to transfer
61 EPAPtr dw EPA - LDLINUX_SYS ; Pointer to the extended patch area
64 ; Extended patch area -- this is in .data16 so it doesn't occupy space in
65 ; the first sector. Use this structure for anything that isn't used by
66 ; the first sector itself.
71 ADVSecPtr dw ADVSec0 - LDLINUX_SYS
72 CurrentDirPtr dw CurrentDirName-LDLINUX_SYS ; Current directory name string
73 CurrentDirLen dw CURRENTDIR_MAX
74 SubvolPtr dw SubvolName-LDLINUX_SYS
75 SubvolLen dw SUBVOL_MAX
76 SecPtrOffset dw SectorPtrs-LDLINUX_SYS
77 SecPtrCnt dw (SectorPtrsEnd - SectorPtrs)/10
80 ; Boot sector patch pointers
82 Sect1Ptr0Ptr dw Sect1Ptr0 - bootsec ; Pointers to Sector 1 location
83 Sect1Ptr1Ptr dw Sect1Ptr1 - bootsec
84 RAIDPatchPtr dw kaboom.again - bootsec ; Patch to INT 18h in RAID mode
87 ; Pointer to the Syslinux banner
89 BannerPtr dw syslinux_banner - LDLINUX_SYS
92 ; Base directory name and subvolume, if applicable.
94 %define HAVE_CURRENTDIRNAME
95 global CurrentDirName:data hidden, SubvolName:data hidden
96 CurrentDirName times CURRENTDIR_MAX db 0
97 SubvolName times SUBVOL_MAX db 0
102 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
103 ; instead of 0000:7C00 and the like. We don't want to add anything
104 ; more to the boot sector, so it is written to not assume a fixed
105 ; value in CS, but we don't want to deal with that anymore from now
108 jmp 0:.next ; Normalize CS:IP
109 .next: sti ; In case of broken INT 13h BIOSes
112 ; Tell the user we got this far
118 ; Checksum data thus far
121 mov cx,[bsBytesPerSec]
123 mov edx,-LDLINUX_MAGIC
128 mov [CheckSum],edx ; Save intermediate result
129 movzx ebx,si ; Start of the next sector
132 ; Tell the user if we're using EBIOS or CBIOS
136 cmp byte [getonesec.jmp+1],(getonesec_ebios-(getonesec.jmp+2))
139 mov byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
147 %define HAVE_BIOSNAME 1
152 ; Now we read the rest of LDLINUX.SYS.
155 push bx ; LSW of load address
159 dec cx ; Minus this sector
165 movzx ebp,word [si+8]
168 shr ebx,4 ; Convert to a segment
173 imul bp,[bsBytesPerSec] ; Will be < 64K
181 ; All loaded up, verify that we got what we needed.
182 ; Note: the checksum field is embedded in the checksum region, so
183 ; by the time we get to the end it should all cancel out.
186 pop si ; LSW of load address
187 movzx eax,word [bsBytesPerSec]
189 mov ecx,[LDLDwords] ; Total dwords
190 sub ecx,eax ; ... minus one sector
196 ; Handle segment wrap
206 and eax,eax ; Should be zero
207 jz all_read ; We're cool, go for it!
210 ; Uh-oh, something went bad...
212 mov si,checksumerr_msg
217 ; -----------------------------------------------------------------------------
218 ; Subroutines that have to be in the first sector
219 ; -----------------------------------------------------------------------------
224 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
225 ; number in EAX into the buffer at ES:BX. We try to optimize
226 ; by loading up to a whole track at a time, but the user
227 ; is responsible for not crossing a 64K boundary.
228 ; (Yes, BP is weird for a count, but it was available...)
230 ; On return, BX points to the first byte after the transferred
233 ; This routine assumes CS == DS.
235 global getlinsec:function hidden
238 add eax,[Hidden] ; Add partition offset
240 .jmp: jmp strict short getlinsec_cbios
245 ; getlinsec implementation for EBIOS (EDD)
249 push bp ; Sectors left
251 call maxtrans ; Enforce maximum transfer size
252 movzx edi,bp ; Sectors we are about to read
265 mov ah,42h ; Extended Read
272 lea sp,[si+16] ; Remove DAPA
275 add eax,edi ; Advance sector pointer
277 sub bp,di ; Sectors left
278 imul di,[bsBytesPerSec]
279 add bx,di ; Advance buffer pointer
287 ; Some systems seem to get "stuck" in an error state when
288 ; using EBIOS. Doesn't happen when using CBIOS, which is
289 ; good, since some other systems get timeout failures
290 ; waiting for the floppy disk to spin up.
292 pushad ; Try resetting the device
296 loop .retry ; CX-- and jump if not zero
298 ;shr word [MaxTransfer],1 ; Reduce the transfer size
301 ; Total failure. Try falling back to CBIOS.
302 mov byte [getlinsec.jmp+1],(getlinsec_cbios-(getlinsec.jmp+2))
303 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
306 ; ... fall through ...
311 ; getlinsec implementation for legacy CBIOS
320 movzx esi,word [bsSecPerTrack]
321 movzx edi,word [bsHeads]
323 ; Dividing by sectors to get (track,sector): we may have
324 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
328 xchg cx,dx ; CX <- sector index (0-based)
331 div edi ; Convert track to head/cyl
333 cmp eax,1023 ; Outside the CHS range?
337 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
338 ; BP = sectors to transfer, SI = bsSecPerTrack,
339 ; ES:BX = data target
342 call maxtrans ; Enforce maximum transfer size
344 ; Must not cross track boundaries, so BP <= SI-CX
351 shl ah,6 ; Because IBM was STOOPID
352 ; and thought 8 bits were enough
353 ; then thought 10 bits were enough...
354 inc cx ; Sector numbers are 1-based, sigh
358 xchg ax,bp ; Sector to transfer count
359 mov ah,02h ; Read sectors
367 movzx ecx,al ; ECX <- sectors transferred
368 imul ax,[bsBytesPerSec] ; Convert sectors in AL to bytes in AX
384 xchg ax,bp ; Sectors transferred <- 0
385 shr word [MaxTransfer],1
397 ; writestr_early: write a null-terminated string to the console
398 ; This assumes we're on page 0. This is only used for early
399 ; messages, so it should be OK.
406 mov ah,0Eh ; Write to screen as TTY
407 mov bx,0007h ; Attribute
414 ; Checksum error message
416 checksumerr_msg db ' Load error - ', 0 ; Boot failed appended
421 cbios_name db 'CHS', 0 ; CHS/CBIOS
422 ebios_name db 'EDD', 0 ; EDD/EBIOS
429 cmp word [Debug_Magic],0D00Dh
434 rl_checkpt equ $ ; Must be <= 8000h
436 rl_checkpt_off equ $-ldlinux_sys
438 %if rl_checkpt_off > 512-10 ; Need minimum one extent
439 %assign rl_checkpt_overflow rl_checkpt_off - (512-10)
440 %error Sector 1 overflow by rl_checkpt_overflow bytes
445 ; Extent pointers... each extent contains an 8-byte LBA and an 2-byte
446 ; sector count. In most cases, we will only ever need a handful of
447 ; extents, but we have to assume a maximally fragmented system where each
448 ; extent contains only one sector.
451 MaxInitDataSize equ 96 << 10
452 MaxLMA equ LDLINUX_SYS+MaxInitDataSize
453 SectorPtrs zb 10*(MaxInitDataSize >> MIN_SECTOR_SHIFT)
456 ; ----------------------------------------------------------------------------
457 ; End of code and data that have to be in the first sector
458 ; ----------------------------------------------------------------------------
462 ; We enter here with ES scrambled...
466 ; Let the user (and programmer!) know we got this far. This used to be
467 ; in Sector 1, but makes a lot more sense here.
477 ; Insane hack to expand the DOS superblock to dwords
483 mov cx,superinfo_size
487 stosd ; Store expanded word
489 stosd ; Store expanded byte
494 ; Common initialization code
500 movzx dx,byte [DriveNumber]
501 ; DH = 0: we are boot from disk not CDROM
505 mov di,[bsSecPerTrack]
506 movzx ebp,word [MaxTransfer]
512 SuperInfo resq 16 ; The first 16 bytes expanded 8 times
515 ; Banner information not needed in sector 1
518 global syslinux_banner
519 syslinux_banner db CR, LF, MY_NAME, ' ', VERSION_STR
520 late_banner db ' ', DATE_STR, 0