1 ; mbr.S - Master Boot Record to boot first partition marked active
3 ; Copyright 2002-2004 John Coffman
4 ; Copyright 2009-2015 Joachim Wiedorn
7 ; Licensed under the terms contained in the file 'COPYING'
8 ; in the source directory.
11 /* set to 1 for debugging output */
14 #define SEARCH 1 /* turn on search for device code */
15 #define CYL1023 0 /* 1==compare to 1023 / 0==fn8 cyl # */
16 #define PASS_PARAMS 1 /* 1==pass lilo parameters */
17 #define BYPASS18 0 /* bypass int 18h exit */
20 # define EXT_PART 1 /* search extended partitions, too */
21 /*# define VIDEO_ENABLE / we just have no space for this */
22 # define VIDEO_ENABLE /* we now do have space for this */
24 # define EXT_PART 0 /* search primary partition only */
28 DELAY = 12 /* tenths of a second */
31 STEP = 1 /* delay is in seconds if DEBUG */
33 /*# undef VIDEO_ENABLE*/
36 STEP = 10 /* delay is in deciseconds if not DEBUG */
50 _main: cli ! NT 4 blows up if this is missing
54 stage: .byte STAGE_MBR2 ! search extended partitions, too
56 stage: .byte STAGE_MBR ! search primary partition only
60 sig: .ascii "LILO" ! signature
63 ! the disk I/O packet DS:SI uses it
64 packet: .word 16 ! size of packet
65 .word 1 ! count of sectors to transfer
66 addr: .word BOOTSEG*16 ! address offset to transfer to
67 .word 0 ! address segment to transfer to
68 daddr: .long 0 ! low order disk address
69 .long 0 ! high order disk address
76 dout: push ax ! save low half
78 call wout ! put out high word
81 xchg ah,al ! put out AH first
85 bout: push ax ! convert & output hex byte in AL
86 shr al,#4 ! high nibble
89 nout: and al,#0x0F ! write the nibble in low half of AL
90 daa ! convert to upper case hex character
93 cout: push bx ! write character to the console
94 mov ah,#0x0E ! video BIOS function 14
96 int 0x10 ! video interrupt
101 say: pop si ! get CS:SI pointer to character string
102 say1: lodsb ! but DS==CS, so this works
103 or al,al ! NUL terminated?
108 mov ah,#0x0E ! in-line character write routine
109 mov bx,#07 ! write to page 0
110 int 0x10 ! video interrupt
115 jmp si ! return from "say:"
119 hlt ! wait for interrupt
120 jmp stop ! loop back after interrupt
123 xor eax,eax ! EXPERIMENTAL code
124 mov [daddr],eax ! zero the disk address
125 inc dx ! try the next device code
126 call disk_read ! read sector 0
129 mov cx,#DELAY*16/STEP ! delay DELAY/10 seconds, DX doesn't matter
132 int 0x15 ! delay call
134 int 0x18 ! exit to BIOS
136 #endif /* BYPASS18 */
140 xor ax,ax ! all addressing from 0000:0000
141 mov ss,ax ! set up the stack
142 mov sp,#BOOTSEG*16 ! #0x7C00
143 sti ! enable interrupts
152 mov si,sp ! from here 0000:7C000
154 cld ! clear direction flag (UP)
157 mov di,#PARTS_LOAD ! move to here 0000:0600
158 mov cx,#SECTOR_SIZE/2 ! one sector worth
161 jmpi go,0 ! intersegment jump 0:go
164 pusha ! certain video cards trash DX
166 mov al,[0x449] ! get video mode
169 mov ax,#0x1200 ! enable video (VGA)
170 mov bl,#0x36 ! (probably a nop on EGA or MDA)
174 popa ! DX must be protected from rogue video cards
178 mov edi,[serial_no] ! serial number to look for
182 mov ah,#8 ! get number of hard drives
187 xchg ax,dx ! save device code in AX
188 mov dx,#0x80 ! device 80
193 cmp edi,[BOOTSEG*16+PART_TABLE_OFFSET-6]
195 inc dx ! try next device
198 xchg ax,dx ! try what we were passed
206 call say ! debugging dump of DL
210 call bout ! write the byte in AL
214 mov eax,[serial_no] ! serial number to look for
220 mov si,#p_table ! scan the partition table
222 xor edi,edi ! BASE = 0
224 mov cx,#4 ! 4 entries
227 call is_ext ! test for extended
229 test byte ptr (si),#0x80 ! test hi-bit
230 mov bp,si ! save possible ptr
231 js one_found ! found Active if sign bit set
232 add si,#16 ! move to next entry
233 loop find_active ! & loop back
236 /* no primary partition was marked active */
237 xchg edi,ebp ! EBP = base, EDI = second
240 /* extended partitions exist, search them */
242 add edi,ebp ! second += base
245 mov si,#BOOTSEG*16+PART_TABLE_OFFSET ! pt[0]
246 test byte ptr (si),#0x80 ! test hi-bit
247 js boot_si ! one to boot if set
249 call is_ext ! will set EDI
253 call say ! comment & quit
257 .ascii "No partition active"
266 find_more: ! check for more that one partition
268 call is_ext ! continue check for extended part.
270 test byte ptr (si),#0x80 ! with active bit set
272 call say ! oops, a second partition is active
278 .byte 13,10,0 ! comment & quit
283 one_found: ! one partition is active
284 add si,#16 ! go on & test others
285 loop find_more ! continue the loop
287 ; BP points at the only active partition
289 mov si,bp ; now SI points at active partition
292 #endif /* !EXT_PART */
295 mov eax,(si+8) ; get partition start
297 add [daddr],eax ; set disk address
299 mov [daddr],eax ; set disk address
301 call disk_read ; read sector
304 ;;; seg es ! DS==ES, so don't need prefix
305 cmp word ptr [BOOTSEG*16+BOOT_SIG_OFFSET],#0xAA55 ! look for boot signature
306 jne no_boot ! not bootable if no sig.
309 mov (si),dl ; move into partition table
311 xor ax,ax ; signal no disk error
318 mov cx,#DELAY*16/STEP/2 ! delay DELAY/10 seconds, DX doesn't matter
321 int 0x15 ! delay call
325 pop ax ! check for possible params
343 ;;; .ascii "No 0xAA55 in partition"
344 .ascii "No boot sig. in partition"
346 .ascii "No boot signature in partition"
354 ! packet read routine
357 mov bp,#12 ! retry count
361 mov bx,#0x55AA ;magic number
365 cmp bx,#0xAA55 ;changed?
367 test cl,#EDD_PACKET ;EDD packet calls supported
376 mov ah,#8 ! get geometry
383 xchg cl,ch ;CX is max cylinder number
384 mov di,cx ;DI saves it
389 inc ax ;AX is number of heads (256 allowed)
391 and cx,#0x003f ;CX is number of sectors
392 mul cx ; kills DX also
393 xchg ax,bx ;save in BX
395 mov ax,[daddr] ;low part of address
396 mov dx,[daddr+2] ;hi part of address
399 jae disk_error2 ;prevent division error
400 div bx ;AX is cyl, DX is head/sect
406 ja disk_error2 ;cyl is too big
408 shl ah,#6 ; save hi 2 bits
411 div cl ;AH = sec-1, AL = head
412 or dl,ah ;form Cyl/Sec
414 inc cx ; sector is 1 based
416 pop dx ! restore device code
417 mov dh,al ! set head#
418 mov ax,#0x201 ;read, count of 1
421 les bx,[addr-packet](si) ! for both reads
430 mov ah,#0x40 ; signal seek error
437 ;; mov ah,#0x0D ! reset fixed disk controller
445 xchg al,ah ; error code to AL
450 call say ; something is wrong with the disk read
451 .ascii "Disk read error"
461 /* return ZF=1 if SI -> extended partition and set EDI */
463 mov al,(si+4) ; get partition type
464 cmp al,#PART_DOS_EXTD
466 cmp al,#PART_WIN_EXTD_LBA
468 cmp al,#PART_LINUX_EXTD
471 mov edi,(si+8) ; get start to edi
476 theend1: /* better be at or below 07B6 */
478 .org PARTS_LOAD+MAX_BOOT_SIZE
480 serial_no: .blkb 4 ! volume serial number
483 !!! .org 0x1be ! spot for the partition table
485 .blkb 16 ! the partition table is filled in
486 .blkb 16 ! when this Master Boot Record is installed
487 .blkb 16 ! just leave space
491 .long MBX ! boot block signature check
494 .long MBR ! boot block signature check
496 .word 0xAA55 ! boot block signature goes here
499 theend: ! must be 0000:0800