1 ; -----------------------------------------------------------------------
3 ; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved
4 ; Copyright 2009 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.
23 SuperInfo resq 16 ; The first 16 bytes expanded 8 times
28 ; Some of the things that have to be saved very early are saved
29 ; "close" to the initial stack pointer offset, in order to
30 ; reduce the code size...
32 StackBuf equ $-44-32 ; Start the stack here (grow down - 4K)
33 PartInfo equ StackBuf ; Saved partition table entry
34 FloppyTable equ PartInfo+16 ; Floppy info table (must follow PartInfo)
35 OrigFDCTabPtr equ StackBuf-8 ; The 2nd high dword on the stack
36 OrigESDI equ StackBuf-4 ; The high dword on the stack
37 StackTop equ OrigFDCTabPtr ; The start of the canonical stack
40 ; Primary entry point. Tempting as though it may be, we can't put the
41 ; initial "cli" here; the jmp opcode in the first byte is part of the
42 ; "magic number" (using the term very loosely) for the DOS superblock.
45 _start: jmp short start ; 2 bytes
48 ; "Superblock" follows -- it's in the boot sector, so it's already
49 ; loaded and ready for us
51 bsOemName db MY_NAME ; The SYS command sets this, so...
55 ; These are the fields we actually care about. We end up expanding them
56 ; all to dword size early in the code, so generate labels for both
57 ; the expanded and unexpanded versions.
60 bx %+ %1 equ SuperInfo+($-superblock)*8+4
65 bx %+ %1 equ SuperInfo+($-superblock)*8
70 bx %+ %1 equ $ ; no expansion for dwords
85 superinfo_size equ ($-superblock)-1 ; How much to expand
89 ; This is as far as FAT12/16 and FAT32 are consistent
91 ; FAT12/16 need 26 more bytes,
92 ; FAT32 need 54 more bytes
94 superblock_len_fat16 equ $-superblock+26
95 superblock_len_fat32 equ $-superblock+54
96 zb 54 ; Maximum needed size
97 superblock_max equ $-superblock
100 SecPerClust equ bxSecPerClust
102 ; Note we don't check the constraints above now; we did that at install
106 cli ; No interrupts yet, please
113 mov sp,StackBuf ; Just below BSS
114 push es ; Save initial ES:DI -> $PnP pointer
118 ; DS:SI may contain a partition table entry. Preserve it for us.
120 mov cx,8 ; Save partition info
124 mov ds,ax ; Now we can initialize DS...
127 ; Now sautee the BIOS floppy info block to that it will support decent-
128 ; size transfers; the floppy block is 11 bytes and is stored in the
129 ; INT 1Eh vector (brilliant waste of resources, eh?)
131 ; Of course, if BIOSes had been properly programmed, we wouldn't have
132 ; had to waste precious space with this code.
135 lfs si,[bx] ; FS:SI -> original fdctab
136 push fs ; Save on stack in case we need to bail
139 ; Save the old fdctab even if hard disk so the stack layout
140 ; is the same. The instructions above do not change the flags
141 mov [DriveNumber],dl ; Save drive number in DL
142 and dl,dl ; If floppy disk (00-7F), assume no
147 mov cl,6 ; 12 bytes (CX == 0)
148 ; es:di -> FloppyTable already
149 ; This should be safe to do now, interrupts are off...
150 mov [bx],di ; FloppyTable
151 mov [bx+2],ax ; Segment 0
152 fs rep movsw ; Faster to move words
153 mov cl,[bsSecPerTrack] ; Patch the sector count
156 int 13h ; Some BIOSes need this
158 jmp short not_harddisk
160 ; The drive number and possibly partition information was passed to us
161 ; by the BIOS or previous boot loader (MBR). Current "best practice" is to
162 ; trust that rather than what the superblock contains.
164 ; Would it be better to zero out bsHidden if we don't have a partition table?
166 ; Note: di points to beyond the end of PartInfo
169 test byte [di-16],7Fh ; Sanity check: "active flag" should
170 jnz no_partition ; be 00 or 80
171 mov eax,[di-8] ; Partition offset (dword)
175 ; Get disk drive parameters (don't trust the superblock.) Don't do this for
176 ; floppy drives -- INT 13:08 on floppy drives will (may?) return info about
177 ; what the *drive* supports, not about the *media*. Fortunately floppy disks
178 ; tend to have a fixed, well-defined geometry which is stored in the superblock.
180 ; DL == drive # still
187 inc dx ; Contains # of heads - 1
190 mov [bsSecPerTrack],cx
194 ; Ready to enable interrupts, captain
199 ; Do we have EBIOS (EDD)?
203 mov ah,41h ; EDD existence query
209 test cl,1 ; Extended disk access functionality set
212 ; We have EDD support...
214 mov byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
218 ; Load the first sector of LDLINUX.SYS; this used to be all proper
219 ; with parsing the superblock and root directory; it doesn't fit
220 ; together with EBIOS support, unfortunately.
222 mov eax,[FirstSector] ; Sector start
223 mov bx,ldlinux_sys ; Where to load it
226 ; Some modicum of integrity checking
227 cmp dword [ldlinux_magic+4],LDLINUX_MAGIC^HEXDATE
234 ; getonesec: get one disk sector
237 mov bp,1 ; One sector
241 ; getlinsec: load a sequence of BP floppy sector given by the linear sector
242 ; number in EAX into the buffer at ES:BX. We try to optimize
243 ; by loading up to a whole track at a time, but the user
244 ; is responsible for not crossing a 64K boundary.
245 ; (Yes, BP is weird for a count, but it was available...)
247 ; On return, BX points to the first byte after the transferred
250 ; This routine assumes CS == DS, and trashes most registers.
252 ; Stylistic note: use "xchg" instead of "mov" when the source is a register
253 ; that is dead from that point; this saves space. However, please keep
254 ; the order to dst,src to keep things sane.
258 add eax,[bsHidden] ; Add partition offset
259 xor edx,edx ; Zero-extend LBA (eventually allow 64 bits)
261 .jmp: jmp strict short getlinsec_cbios
266 ; getlinsec implementation for EBIOS (EDD)
270 push bp ; Sectors left
272 call maxtrans ; Enforce maximum transfer size
273 movzx edi,bp ; Sectors we are about to read
290 mov ah,42h ; Extended Read
294 lea sp,[si+16] ; Remove DAPA
297 add eax,edi ; Advance sector pointer
298 sub bp,di ; Sectors left
299 shl di,SECTOR_SHIFT ; 512-byte sectors
300 add bx,di ; Advance buffer pointer
307 ; Some systems seem to get "stuck" in an error state when
308 ; using EBIOS. Doesn't happen when using CBIOS, which is
309 ; good, since some other systems get timeout failures
310 ; waiting for the floppy disk to spin up.
312 pushad ; Try resetting the device
317 loop .retry ; CX-- and jump if not zero
319 ;shr word [MaxTransfer],1 ; Reduce the transfer size
322 ; Total failure. Try falling back to CBIOS.
323 mov byte [getlinsec.jmp+1],(getlinsec_cbios-(getlinsec.jmp+2))
324 ;mov byte [MaxTransfer],63 ; Max possibe CBIOS transfer
327 ; ... fall through ...
332 ; getlinsec implementation for legacy CBIOS
341 movzx esi,word [bsSecPerTrack]
342 movzx edi,word [bsHeads]
344 ; Dividing by sectors to get (track,sector): we may have
345 ; up to 2^18 tracks, so we need to use 32-bit arithmetric.
349 xchg cx,dx ; CX <- sector index (0-based)
352 div edi ; Convert track to head/cyl
354 ; We should test this, but it doesn't fit...
359 ; Now we have AX = cyl, DX = head, CX = sector (0-based),
360 ; BP = sectors to transfer, SI = bsSecPerTrack,
361 ; ES:BX = data target
364 call maxtrans ; Enforce maximum transfer size
366 ; Must not cross track boundaries, so BP <= SI-CX
373 shl ah,6 ; Because IBM was STOOPID
374 ; and thought 8 bits were enough
375 ; then thought 10 bits were enough...
376 inc cx ; Sector numbers are 1-based, sigh
381 xchg ax,bp ; Sector to transfer count
382 mov ah,02h ; Read sectors
390 movzx ecx,al ; ECX <- sectors transferred
391 shl ax,SECTOR_SHIFT ; Convert sectors in AL to bytes in AX
406 xchg ax,bp ; Sectors transferred <- 0
407 shr word [MaxTransfer],1
409 ; Fall through to disk_error
412 ; kaboom: write a message and bail out.
418 mov sp,OrigFDCTabPtr ; Reset stack
419 mov ds,si ; Reset data segment
420 pop dword [fdctab] ; Restore FDC table
421 .patch: ; When we have full code, intercept here
424 ; Write error message, this assumes screen page 0
428 mov ah,0Eh ; Write to screen as TTY
429 mov bx,0007h ; Attribute
434 .again: int 16h ; Wait for keypress
435 ; NB: replaced by int 18h if
436 ; chosen at install time..
437 int 19h ; And try once more to boot...
438 .norge: jmp short .norge ; If int 19h returned; this is the end
441 ; Truncate BP to MaxTransfer
450 ; Error message on failure
452 bailmsg: db 'Boot error', 0Dh, 0Ah, 0
454 ; This fails if the boot sector overflows
457 FirstSector dd 0xDEADBEEF ; Location of sector 1
459 MaxTransfer dw 0x007F ; Max transfer size
461 ; This field will be filled in 0xAA55 by the installer, but we abuse it
462 ; to house a pointer to the INT 16h instruction at
463 ; kaboom.again, which gets patched to INT 18h in RAID mode.
464 bootsignature dw kaboom.again-bootsec
467 ; ===========================================================================
469 ; ===========================================================================
470 ; Start of LDLINUX.SYS
471 ; ===========================================================================
475 syslinux_banner db 0Dh, 0Ah
476 db MY_NAME, ' ', VERSION_STR, ' ', DATE_STR, ' ', 0
477 db 0Dh, 0Ah, 1Ah ; EOF if we "type" this in DOS
480 ldlinux_magic dd LDLINUX_MAGIC
481 dd LDLINUX_MAGIC^HEXDATE
484 ; This area is patched by the installer. It is found by looking for
485 ; LDLINUX_MAGIC, plus 8 bytes.
488 DataSectors dw 0 ; Number of sectors (not including bootsec)
489 ADVSectors dw 0 ; Additional sectors for ADVs
490 LDLDwords dd 0 ; Total dwords starting at ldlinux_sys,
491 CheckSum dd 0 ; Checksum starting at ldlinux_sys
492 ; value = LDLINUX_MAGIC - [sum of dwords]
494 CurrentDir dd 2 ; "Current" directory inode number (EXTLINUX)
495 SecPtrOffset dw SectorPtrs - ldlinux_sys
496 SecPtrCnt dw (SectorPtrsEnd - SectorPtrs) >> 2
500 ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000
501 ; instead of 0000:7C00 and the like. We don't want to add anything
502 ; more to the boot sector, so it is written to not assume a fixed
503 ; value in CS, but we don't want to deal with that anymore from now
510 ; Tell the user we got this far
512 mov si,syslinux_banner
516 ; Tell the user if we're using EBIOS or CBIOS
520 cmp byte [getlinsec.jmp+1],(getlinsec_ebios-(getlinsec.jmp+2))
528 %define HAVE_BIOSNAME 1
533 ; Now we read the rest of LDLINUX.SYS. Don't bother loading the first
534 ; sector again, though.
538 mov ebx,7C00h+2*SECTOR_SIZE ; Where we start loading
540 dec cx ; Minus this sector
545 mov di,bx ; Low 64K of target address
546 lodsd ; First sector of this chunk
554 cmp ebx,esi ; Pointer we don't have yet?
556 inc edx ; Next linear sector
557 cmp [si],edx ; Does it match
558 jnz .chunk_ready ; If not, this is it
559 add si,4 ; If so, add sector to chunk
560 add di,SECTOR_SIZE ; Check for 64K segment wrap
566 shr ebx,4 ; Convert to a segment
569 xor edx,edx ; Zero-extend LBA
580 ; All loaded up, verify that we got what we needed.
581 ; Note: the checksum field is embedded in the checksum region, so
582 ; by the time we get to the end it should all cancel out.
587 mov eax,-LDLINUX_MAGIC
593 ; Handle segment wrap
602 and eax,eax ; Should be zero
603 jz all_read ; We're cool, go for it!
606 ; Uh-oh, something went bad...
608 mov si,checksumerr_msg
613 ; -----------------------------------------------------------------------------
614 ; Subroutines that have to be in the first sector
615 ; -----------------------------------------------------------------------------
619 ; writestr_early: write a null-terminated string to the console
620 ; This assumes we're on page 0. This is only used for early
621 ; messages, so it should be OK.
628 mov ah,0Eh ; Write to screen as TTY
629 mov bx,0007h ; Attribute
636 ; getlinsecsr: save registers, call getlinsec, restore registers
644 ; Checksum error message
646 checksumerr_msg db ' Load error - ', 0 ; Boot failed appended
651 cbios_name db 'CBIOS', 0
652 ebios_name db 'EBIOS', 0
659 cmp word [Debug_Magic],0D00Dh
664 rl_checkpt equ $ ; Must be <= 8000h
666 rl_checkpt_off equ ($-$$)
668 %if rl_checkpt_off > 3FCh ; Need one pointer in here
669 %error "Sector 1 overflow"
675 MaxInitDataSize equ 96 << 10
676 MaxLMA equ 0x7c00+SECTOR_SIZE+MaxInitDataSize
677 SectorPtrs times MaxInitDataSize >> SECTOR_SHIFT dd 0
680 ; ----------------------------------------------------------------------------
681 ; End of code and data that have to be in the first sector
682 ; ----------------------------------------------------------------------------
687 ; Let the user (and programmer!) know we got this far. This used to be
688 ; in Sector 1, but makes a lot more sense here.
695 ; Insane hack to expand the DOS superblock to dwords
701 mov cx,superinfo_size
705 stosd ; Store expanded word
707 stosd ; Store expanded byte
712 ; Common initialization code
715 %include "cpuinit.inc"
734 mov dh,0 ; we are boot from disk not CDROM
738 mov di,[bsSecPerTrack]