1 ; mbr.S -- Master Boot Record to boot first partition marked active
3 ; Copyright 2002-2004 John Coffman.
6 ; Licensed under the terms contained in the file 'COPYING' in the
10 /* set to 1 for debugging output */
13 #define SEARCH 1 /* turn on search for device code */
14 #define CYL1023 0 /* 1==compare to 1023 / 0==fn8 cyl # */
15 #define PASS_PARAMS 1 /* 1==pass lilo parameters */
16 #define BYPASS18 0 /* bypass int 18h exit */
19 # define EXT_PART 1 /* search extended partitions, too */
20 /*# define VIDEO_ENABLE / we just have no space for this */
21 # define VIDEO_ENABLE /* we now do have space for this */
23 # define EXT_PART 0 /* search primary partition only */
27 DELAY = 12 /* tenths of a second */
30 STEP = 1 /* delay is in seconds if DEBUG */
32 /*# undef VIDEO_ENABLE*/
35 STEP = 10 /* delay is in deciseconds if not DEBUG */
49 _main: cli ! NT 4 blows up if this is missing
53 stage: .byte STAGE_MBR2 ! search extended partitions, too
55 stage: .byte STAGE_MBR ! search primary parition only
59 sig: .ascii "LILO" ! signature
62 ! the disk I/O packet DS:SI uses it
63 packet: .word 16 ! size of packet
64 .word 1 ! count of sectors to transfer
65 addr: .word BOOTSEG*16 ! address offset to transfer to
66 .word 0 ! address segment to transfer to
67 daddr: .long 0 ! low order disk address
68 .long 0 ! high order disk address
75 dout: push ax ! save low half
77 call wout ! put out high word
80 xchg ah,al ! put out AH first
84 bout: push ax ! convert & output hex byte in AL
85 shr al,#4 ! high nibble
88 nout: and al,#0x0F ! write the nibble in low half of AL
89 daa ! convert to upper case hex character
92 cout: push bx ! write character to the console
93 mov ah,#0x0E ! video BIOS function 14
95 int 0x10 ! video interrupt
100 say: pop si ! get CS:SI pointer to character string
101 say1: lodsb ! but DS==CS, so this works
102 or al,al ! NUL terminated?
107 mov ah,#0x0E ! in-line character write routine
108 mov bx,#07 ! write to page 0
109 int 0x10 ! video interrupt
114 jmp si ! return from "say:"
118 hlt ! wait for interrupt
119 jmp stop ! loop back after interrupt
122 xor eax,eax ! EXPERIMENTAL code
123 mov [daddr],eax ! zero the disk address
124 inc dx ! try the next device code
125 call disk_read ! read sector 0
128 mov cx,#DELAY*16/STEP ! delay DELAY/10 seconds, DX doesn't matter
131 int 0x15 ! delay call
133 int 0x18 ! exit to BIOS
135 #endif /* BYPASS18 */
139 xor ax,ax ! all addressing from 0000:0000
140 mov ss,ax ! set up the stack
141 mov sp,#BOOTSEG*16 ! #0x7C00
142 sti ! enable interrupts
151 mov si,sp ! from here 0000:7C000
153 cld ! clear direction flag (UP)
156 mov di,#PARTS_LOAD ! move to here 0000:0600
157 mov cx,#SECTOR_SIZE/2 ! one sector worth
160 jmpi go,0 ! intersegment jump 0:go
163 pusha ! certain video cards trash DX
165 mov al,[0x449] ! get video mode
168 mov ax,#0x1200 ! enable video (VGA)
169 mov bl,#0x36 ! (probably a nop on EGA or MDA)
173 popa ! DX must be protected from rogue video cards
177 mov edi,[serial_no] ! serial number to look for
181 mov ah,#8 ! get number of hard drives
186 xchg ax,dx ! save device code in AX
187 mov dx,#0x80 ! device 80
192 cmp edi,[BOOTSEG*16+PART_TABLE_OFFSET-6]
194 inc dx ! try next device
197 xchg ax,dx ! try what we were passed
205 call say ! debugging dump of DL
209 call bout ! write the byte in AL
213 mov eax,[serial_no] ! serial number to look for
219 mov si,#p_table ! scan the partition table
221 xor edi,edi ! BASE = 0
223 mov cx,#4 ! 4 entries
226 call is_ext ! test for extended
228 test byte ptr (si),#0x80 ! test hi-bit
229 mov bp,si ! save possible ptr
230 js one_found ! found Active if sign bit set
231 add si,#16 ! move to next entry
232 loop find_active ! & loop back
235 /* no primary partition was marked active */
236 xchg edi,ebp ! EBP = base, EDI = second
239 /* extended partitions exist, search them */
241 add edi,ebp ! second += base
244 mov si,#BOOTSEG*16+PART_TABLE_OFFSET ! pt[0]
245 test byte ptr (si),#0x80 ! test hi-bit
246 js boot_si ! one to boot if set
248 call is_ext ! will set EDI
252 call say ! comment & quit
256 .ascii "No partition active"
265 find_more: ! check for more that one partition
267 call is_ext ! continue check for extended part.
269 test byte ptr (si),#0x80 ! with active bit set
271 call say ! oops, a second partition is active
277 .byte 13,10,0 ! comment & quit
282 one_found: ! one partition is active
283 add si,#16 ! go on & test others
284 loop find_more ! continue the loop
286 ; BP points at the only active partition
288 mov si,bp ; now SI points at active partition
291 #endif /* !EXT_PART */
294 mov eax,(si+8) ; get partition start
296 add [daddr],eax ; set disk address
298 mov [daddr],eax ; set disk address
300 call disk_read ; read sector
303 ;;; seg es ! DS==ES, so don't need prefix
304 cmp word ptr [BOOTSEG*16+BOOT_SIG_OFFSET],#0xAA55 ! look for boot signature
305 jne no_boot ! not bootable if no sig.
308 mov (si),dl ; move into partition table
310 xor ax,ax ; signal no disk error
317 mov cx,#DELAY*16/STEP/2 ! delay DELAY/10 seconds, DX doesn't matter
320 int 0x15 ! delay call
324 pop ax ! check for possible params
342 ;;; .ascii "No 0xAA55 in partition"
343 .ascii "No boot sig. in partition"
345 .ascii "No boot signature in partition"
353 ! packet read routine
356 mov bp,#12 ! retry count
360 mov bx,#0x55AA ;magic number
364 cmp bx,#0xAA55 ;changed?
366 test cl,#EDD_PACKET ;EDD packet calls supported
375 mov ah,#8 ! get geometry
382 xchg cl,ch ;CX is max cylinder number
383 mov di,cx ;DI saves it
388 inc ax ;AX is number of heads (256 allowed)
390 and cx,#0x003f ;CX is number of sectors
391 mul cx ; kills DX also
392 xchg ax,bx ;save in BX
394 mov ax,[daddr] ;low part of address
395 mov dx,[daddr+2] ;hi part of address
398 jae disk_error2 ;prevent division error
399 div bx ;AX is cyl, DX is head/sect
405 ja disk_error2 ;cyl is too big
407 shl ah,#6 ; save hi 2 bits
410 div cl ;AH = sec-1, AL = head
411 or dl,ah ;form Cyl/Sec
413 inc cx ; sector is 1 based
415 pop dx ! restore device code
416 mov dh,al ! set head#
417 mov ax,#0x201 ;read, count of 1
420 les bx,[addr-packet](si) ! for both reads
429 mov ah,#0x40 ; signal seek error
436 ;; mov ah,#0x0D ! reset fixed disk controller
444 xchg al,ah ; error code to AL
449 call say ; something is wrong with the disk read
450 .ascii "Disk read error"
460 /* return ZF=1 if SI -> extended partition and set EDI */
462 mov al,(si+4) ; get partition type
463 cmp al,#PART_DOS_EXTD
465 cmp al,#PART_WIN_EXTD_LBA
467 cmp al,#PART_LINUX_EXTD
470 mov edi,(si+8) ; get start to edi
475 theend1: /* better be at or below 07B6 */
477 .org PARTS_LOAD+MAX_BOOT_SIZE
479 serial_no: .blkb 4 ! volume serial number
482 !!! .org 0x1be ! spot for the partition table
484 .blkb 16 ! the partition table is filled in
485 .blkb 16 ! when this Master Boot Record is installed
486 .blkb 16 ! just leave space
490 .long MBX ! boot block signature check
493 .long MBR ! boot block signature check
495 .word 0xAA55 ! boot block signature goes here
498 theend: ! must be 0000:0800