Home | History | Annotate | Line # | Download | only in mbr
      1  1.1  jakllsch /* -----------------------------------------------------------------------
      2  1.1  jakllsch  *
      3  1.1  jakllsch  *   Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
      4  1.1  jakllsch  *   Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin
      5  1.1  jakllsch  *
      6  1.1  jakllsch  *   Permission is hereby granted, free of charge, to any person
      7  1.1  jakllsch  *   obtaining a copy of this software and associated documentation
      8  1.1  jakllsch  *   files (the "Software"), to deal in the Software without
      9  1.1  jakllsch  *   restriction, including without limitation the rights to use,
     10  1.1  jakllsch  *   copy, modify, merge, publish, distribute, sublicense, and/or
     11  1.1  jakllsch  *   sell copies of the Software, and to permit persons to whom
     12  1.1  jakllsch  *   the Software is furnished to do so, subject to the following
     13  1.1  jakllsch  *   conditions:
     14  1.1  jakllsch  *
     15  1.1  jakllsch  *   The above copyright notice and this permission notice shall
     16  1.1  jakllsch  *   be included in all copies or substantial portions of the Software.
     17  1.1  jakllsch  *
     18  1.1  jakllsch  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     19  1.1  jakllsch  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
     20  1.1  jakllsch  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     21  1.1  jakllsch  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
     22  1.1  jakllsch  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     23  1.1  jakllsch  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     24  1.1  jakllsch  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     25  1.1  jakllsch  *   OTHER DEALINGS IN THE SOFTWARE.
     26  1.1  jakllsch  *
     27  1.1  jakllsch  * ----------------------------------------------------------------------- */
     28  1.1  jakllsch 
     29  1.1  jakllsch #include <machine/asm.h>
     30  1.1  jakllsch #include <sys/bootblock.h>
     31  1.1  jakllsch 
     32  1.1  jakllsch #ifdef CTRL_80
     33  1.1  jakllsch 	.macro ADJUST_DRIVE
     34  1.1  jakllsch 	testb	$0x04, BIOS_kbdflags
     35  1.1  jakllsch 	jz	1f
     36  1.1  jakllsch 	movb	$0x80, %dl
     37  1.1  jakllsch 1:
     38  1.1  jakllsch 	.endm
     39  1.1  jakllsch #elif defined(FORCE_80)
     40  1.1  jakllsch 	.macro ADJUST_DRIVE
     41  1.1  jakllsch 	movb	$0x80, %dl
     42  1.1  jakllsch 	.endm
     43  1.1  jakllsch #else
     44  1.1  jakllsch 	.macro ADJUST_DRIVE
     45  1.1  jakllsch 	.endm
     46  1.1  jakllsch #endif
     47  1.1  jakllsch 
     48  1.1  jakllsch 	.code16
     49  1.1  jakllsch 	.text
     50  1.1  jakllsch 
     51  1.1  jakllsch 	.globl	bootsec
     52  1.1  jakllsch stack		= 0x7c00
     53  1.1  jakllsch 
     54  1.1  jakllsch /* Partition table header here */
     55  1.1  jakllsch phdr		= stack		/* Above the stack, overwritten by bootsect */
     56  1.1  jakllsch /* Partition table sector here */
     57  1.1  jakllsch /* To handle > 32K we need to play segment tricks... */
     58  1.1  jakllsch psec		= _phdr + 512
     59  1.1  jakllsch 
     60  1.1  jakllsch /* Where we put DS:SI */
     61  1.1  jakllsch dssi_out	= start + 0x1be
     62  1.1  jakllsch 
     63  1.1  jakllsch BIOS_kbdflags	= 0x417
     64  1.1  jakllsch BIOS_page	= 0x462
     65  1.1  jakllsch 
     66  1.1  jakllsch 	/* gas/ld has issues with doing this as absolute addresses... */
     67  1.1  jakllsch 	.section ".bootsec", "a", @nobits
     68  1.1  jakllsch 	.globl	bootsec
     69  1.1  jakllsch bootsec:
     70  1.1  jakllsch 	.space	512
     71  1.1  jakllsch 
     72  1.1  jakllsch 	.text
     73  1.1  jakllsch 	.globl	start
     74  1.1  jakllsch start:
     75  1.1  jakllsch 	cli
     76  1.1  jakllsch 	xorw	%ax, %ax
     77  1.1  jakllsch 	movw	%ax, %ds
     78  1.1  jakllsch 	movw	%ax, %ss
     79  1.1  jakllsch 	movw	$stack, %sp
     80  1.1  jakllsch 	movw	%sp, %si
     81  1.1  jakllsch 	pushw	%es		/* 4(%bp) es:di -> $PnP header */
     82  1.1  jakllsch 	pushw	%di		/* 2(%bp) */
     83  1.1  jakllsch 	movw	%ax, %es
     84  1.1  jakllsch 	sti
     85  1.1  jakllsch 	cld
     86  1.1  jakllsch 
     87  1.1  jakllsch 	/* Copy down to 0:0x600 */
     88  1.1  jakllsch 	movw	$start, %di
     89  1.1  jakllsch 	movw	$(512/2), %cx
     90  1.1  jakllsch 	rep; movsw
     91  1.1  jakllsch 
     92  1.1  jakllsch 	ljmpw	$0, $next
     93  1.1  jakllsch next:
     94  1.1  jakllsch 
     95  1.1  jakllsch 	ADJUST_DRIVE
     96  1.1  jakllsch 	pushw	%dx		/* 0(%bp) = %dl -> drive number */
     97  1.1  jakllsch 
     98  1.1  jakllsch 	/* Check to see if we have EBIOS */
     99  1.1  jakllsch 	pushw	%dx		/* drive number */
    100  1.1  jakllsch 	movb	$0x41, %ah	/* %al == 0 already */
    101  1.1  jakllsch 	movw	$0x55aa, %bx
    102  1.1  jakllsch 	xorw	%cx, %cx
    103  1.1  jakllsch 	xorb	%dh, %dh
    104  1.1  jakllsch 	stc
    105  1.1  jakllsch 	int	$0x13
    106  1.1  jakllsch 	jc	1f
    107  1.1  jakllsch 	cmpw	$0xaa55, %bx
    108  1.1  jakllsch 	jne	1f
    109  1.1  jakllsch 	shrw	%cx		/* Bit 0 = fixed disk subset */
    110  1.1  jakllsch 	jnc	1f
    111  1.1  jakllsch 
    112  1.1  jakllsch 	/* We have EBIOS; patch in the following code at
    113  1.1  jakllsch 	   read_sector_cbios: movb $0x42, %ah ;  jmp read_common */
    114  1.1  jakllsch 	movl	$0xeb42b4+((read_common-read_sector_cbios-4) << 24), \
    115  1.1  jakllsch 		(read_sector_cbios)
    116  1.1  jakllsch 
    117  1.1  jakllsch 1:
    118  1.1  jakllsch 	popw	%dx
    119  1.1  jakllsch 
    120  1.1  jakllsch 	/* Get (C)HS geometry */
    121  1.1  jakllsch 	movb	$0x08, %ah
    122  1.1  jakllsch 	int	$0x13
    123  1.1  jakllsch 	andw	$0x3f, %cx	/* Sector count */
    124  1.1  jakllsch 	movw	%sp, %bp	/* %bp -> frame pointer: LEAVE UNCHANGED */
    125  1.1  jakllsch 	pushw	%cx		/* -2(%bp) Save sectors on the stack */
    126  1.1  jakllsch 	movzbw	%dh, %ax	/* dh = max head */
    127  1.1  jakllsch 	incw	%ax		/* From 0-based max to count */
    128  1.1  jakllsch 	mulw	%cx		/* Heads*sectors -> sectors per cylinder */
    129  1.1  jakllsch 
    130  1.1  jakllsch 	/* Save sectors/cylinder on the stack */
    131  1.1  jakllsch 	pushw	%dx		/* -4(%bp) High word */
    132  1.1  jakllsch 	pushw	%ax		/* -6(%bp) Low word */
    133  1.1  jakllsch 
    134  1.1  jakllsch 	/* Load partition table header */
    135  1.1  jakllsch 	xorl	%eax,%eax
    136  1.1  jakllsch 	cltd
    137  1.1  jakllsch 	incw	%ax		/* %edx:%eax = 1 */
    138  1.1  jakllsch 	movw	$phdr, %bx
    139  1.1  jakllsch 	pushw	%bx		/* -8(%bp) phdr == bootsect */
    140  1.1  jakllsch 	call	read_sector
    141  1.1  jakllsch 
    142  1.1  jakllsch 	/* Number of partition sectors */
    143  1.1  jakllsch 	/* We assume the partition table is 32K or less, and that
    144  1.1  jakllsch 	   the sector size is 512. */
    145  1.1  jakllsch 	/* Note: phdr == 6(%bp) */
    146  1.1  jakllsch 	movw	(80+6)(%bp),%cx		/* NumberOfPartitionEntries */
    147  1.1  jakllsch 	movw	(84+6)(%bp),%ax		/* SizeOfPartitionEntry */
    148  1.1  jakllsch 	pushw	%ax
    149  1.1  jakllsch 	pushw	%cx
    150  1.1  jakllsch 	mulw	%cx
    151  1.1  jakllsch 	shrw	$9,%ax
    152  1.1  jakllsch 	xchgw	%ax,%cx
    153  1.1  jakllsch 	incw	%cx
    154  1.1  jakllsch 
    155  1.1  jakllsch 	/* Starting LBA of partition array */
    156  1.1  jakllsch 	movl	(72+6)(%bp),%eax
    157  1.1  jakllsch 	movl	(76+6)(%bp),%edx
    158  1.1  jakllsch 
    159  1.1  jakllsch 	pushw	%bx
    160  1.1  jakllsch get_ptab:
    161  1.1  jakllsch 	call	read_sector
    162  1.1  jakllsch 	call	inc64
    163  1.2     joerg 	loop	get_ptab
    164  1.1  jakllsch 
    165  1.1  jakllsch 	/* Find the boot partition */
    166  1.1  jakllsch 	xorw	%si,%si			/* Nothing found yet */
    167  1.1  jakllsch 	popw	%di			/* Partition table in memory */
    168  1.1  jakllsch 	popw	%cx			/* NumberOfPartitionEntries */
    169  1.1  jakllsch 	popw	%ax			/* SizeOfPartitionEntry */
    170  1.1  jakllsch 
    171  1.1  jakllsch find_part:
    172  1.1  jakllsch 	/* If the PartitionTypeGUID is all zero, it's an empty slot */
    173  1.1  jakllsch 	movl	  (%di),%edx
    174  1.1  jakllsch 	orl	 4(%di),%edx
    175  1.1  jakllsch 	orl	 8(%di),%edx
    176  1.1  jakllsch 	orl	12(%di),%edx
    177  1.1  jakllsch 	jz	not_this
    178  1.1  jakllsch 	testb	$0x04,48(%di)
    179  1.1  jakllsch 	jz	not_this
    180  1.1  jakllsch 	andw	%si,%si
    181  1.1  jakllsch 	jnz	found_multiple
    182  1.1  jakllsch 	movw	%di,%si
    183  1.1  jakllsch not_this:
    184  1.1  jakllsch 	addw	%ax,%di
    185  1.2     joerg 	loop	find_part
    186  1.1  jakllsch 
    187  1.1  jakllsch 	andw	%si,%si
    188  1.1  jakllsch 	jnz	found_part
    189  1.1  jakllsch 
    190  1.1  jakllsch missing_os:
    191  1.1  jakllsch 	call	error
    192  1.1  jakllsch 	.ascii	"Missing OS\r\n"
    193  1.1  jakllsch 
    194  1.1  jakllsch found_multiple:
    195  1.1  jakllsch 	call	error
    196  1.1  jakllsch 	.ascii	"Multiple active partitions\r\n"
    197  1.1  jakllsch 
    198  1.1  jakllsch found_part:
    199  1.1  jakllsch 	xchgw	%ax,%cx		/* Set up %cx for rep movsb further down */
    200  1.1  jakllsch 
    201  1.1  jakllsch 	movw	$dssi_out,%di
    202  1.1  jakllsch 	pushw	%di
    203  1.1  jakllsch 
    204  1.1  jakllsch 	/* 80 00 00 00 ee 00 00 00
    205  1.1  jakllsch 	   - bootable partition, type EFI (EE), no CHS information */
    206  1.1  jakllsch 	xorl	%eax,%eax
    207  1.1  jakllsch 	movb	$0x80,%al
    208  1.1  jakllsch 	stosl
    209  1.1  jakllsch 	movb	$0xed,%al
    210  1.1  jakllsch 	stosl
    211  1.1  jakllsch 	movl	32(%si),%eax
    212  1.1  jakllsch 	movl	36(%si),%edx
    213  1.1  jakllsch 	call	saturate_stosl		/* Partition start */
    214  1.1  jakllsch 
    215  1.1  jakllsch 	movl	40(%si),%eax
    216  1.1  jakllsch 	movl	44(%si),%edx
    217  1.1  jakllsch 	subl	32(%si),%eax
    218  1.1  jakllsch 	sbbl	36(%si),%edx
    219  1.1  jakllsch 	call	inc64
    220  1.1  jakllsch 	call	saturate_stosl		/* Partition length */
    221  1.1  jakllsch 
    222  1.1  jakllsch 	movzwl	%cx,%eax		/* Length of GPT entry */
    223  1.1  jakllsch 	stosl
    224  1.1  jakllsch 
    225  1.1  jakllsch 	rep; movsb			/* GPT entry follows MBR entry */
    226  1.1  jakllsch 	popw	%si
    227  1.1  jakllsch 
    228  1.1  jakllsch /*
    229  1.1  jakllsch  * boot: invoke the actual bootstrap. %ds:%si points to the
    230  1.1  jakllsch  * partition information in memory.  The top word on the stack
    231  1.1  jakllsch  * is phdr == 0x7c00 == the address of the boot sector.
    232  1.1  jakllsch  */
    233  1.1  jakllsch boot:
    234  1.1  jakllsch 	movl	(32+20)(%si),%eax
    235  1.1  jakllsch 	movl	(36+20)(%si),%edx
    236  1.1  jakllsch 	popw	%bx
    237  1.1  jakllsch 	call	read_sector
    238  1.1  jakllsch 	cmpw	$0xaa55, -2(%bx)
    239  1.1  jakllsch 	jne	missing_os	/* Not a valid boot sector */
    240  1.1  jakllsch 	movw	%bp, %sp	/* driveno == bootsec-6 */
    241  1.1  jakllsch 	popw	%dx		/* dl -> drive number */
    242  1.1  jakllsch 	popw	%di		/* es:di -> $PnP vector */
    243  1.1  jakllsch 	popw	%es
    244  1.1  jakllsch 	movl	$0x54504721,%eax /* !GPT magic number */
    245  1.1  jakllsch 	cli
    246  1.1  jakllsch 	jmpw	*%sp		/* %sp == bootsec */
    247  1.1  jakllsch 
    248  1.1  jakllsch /*
    249  1.1  jakllsch  * Store the value in %eax to %di iff %edx == 0, otherwise store -1.
    250  1.1  jakllsch  * Returns the value that was actually written in %eax.
    251  1.1  jakllsch  */
    252  1.1  jakllsch saturate_stosl:
    253  1.1  jakllsch 	andl	%edx,%edx
    254  1.1  jakllsch 	jz 1f
    255  1.1  jakllsch 	orl	$-1,%eax
    256  1.1  jakllsch 1:	stosl
    257  1.1  jakllsch 	ret
    258  1.1  jakllsch 
    259  1.1  jakllsch /*
    260  1.1  jakllsch  * Increment %edx:%eax
    261  1.1  jakllsch  */
    262  1.1  jakllsch inc64:
    263  1.1  jakllsch 	addl	$1,%eax
    264  1.1  jakllsch 	adcl	$0,%edx
    265  1.1  jakllsch 	ret
    266  1.1  jakllsch 
    267  1.1  jakllsch /*
    268  1.1  jakllsch  * read_sector: read a single sector pointed to by %edx:%eax to
    269  1.1  jakllsch  * %es:%bx.  CF is set on error.  All registers saved.
    270  1.1  jakllsch  */
    271  1.1  jakllsch read_sector:
    272  1.1  jakllsch 	pushal
    273  1.1  jakllsch 	pushl	%edx	/* MSW of LBA */
    274  1.1  jakllsch 	pushl	%eax	/* LSW of LBA */
    275  1.1  jakllsch 	pushw	%es	/* Buffer segment */
    276  1.1  jakllsch 	pushw	%bx	/* Buffer offset */
    277  1.1  jakllsch 	pushw	$1	/* Sector count */
    278  1.1  jakllsch 	pushw	$16	/* Size of packet */
    279  1.1  jakllsch 	movw	%sp, %si
    280  1.1  jakllsch 
    281  1.1  jakllsch 	/* This chunk is skipped if we have ebios */
    282  1.1  jakllsch 	/* Do not clobber %es:%bx or %edx:%eax before this chunk! */
    283  1.1  jakllsch read_sector_cbios:
    284  1.1  jakllsch 	divl	-6(%bp)	/* secpercyl */
    285  1.1  jakllsch 	shlb	$6, %ah
    286  1.1  jakllsch 	movb	%ah, %cl
    287  1.1  jakllsch 	movb	%al, %ch
    288  1.1  jakllsch 	xchgw	%dx, %ax
    289  1.1  jakllsch 	divb	-2(%bp)	/* sectors */
    290  1.1  jakllsch 	movb	%al, %dh
    291  1.1  jakllsch 	orb	%ah, %cl
    292  1.1  jakllsch 	incw	%cx	/* Sectors are 1-based */
    293  1.1  jakllsch 	movw	$0x0201, %ax
    294  1.1  jakllsch 
    295  1.1  jakllsch read_common:
    296  1.1  jakllsch 	movb	(%bp), %dl /* driveno */
    297  1.1  jakllsch 	int	$0x13
    298  1.1  jakllsch 	leaw	16(%si), %sp	/* Drop DAPA */
    299  1.1  jakllsch 	popal
    300  1.1  jakllsch 	jc	disk_error
    301  1.1  jakllsch 	addb	$2, %bh		/* bx += 512: point to the next buffer */
    302  1.1  jakllsch 	ret
    303  1.1  jakllsch 
    304  1.1  jakllsch disk_error:
    305  1.1  jakllsch 	call	error
    306  1.1  jakllsch 	.ascii	"Disk error on boot\r\n"
    307  1.1  jakllsch 
    308  1.1  jakllsch /*
    309  1.1  jakllsch  * Print error messages.  This is invoked with "call", with the
    310  1.1  jakllsch  * error message at the return address.
    311  1.1  jakllsch  */
    312  1.1  jakllsch error:
    313  1.1  jakllsch 	popw	%si
    314  1.1  jakllsch 2:
    315  1.1  jakllsch 	lodsb
    316  1.1  jakllsch 	movb	$0x0e, %ah
    317  1.1  jakllsch 	movb	(BIOS_page), %bh
    318  1.1  jakllsch 	movb	$0x07, %bl
    319  1.1  jakllsch 	int	$0x10		/* May destroy %bp */
    320  1.1  jakllsch 	cmpb	$10, %al	/* Newline? */
    321  1.1  jakllsch 	jne	2b
    322  1.1  jakllsch 
    323  1.1  jakllsch 	int	$0x18		/* Boot failure */
    324  1.1  jakllsch die:
    325  1.1  jakllsch 	hlt
    326  1.1  jakllsch 	jmp	die
    327  1.1  jakllsch 
    328  1.1  jakllsch mbr_space = end - .
    329  1.1  jakllsch 	. = MBR_DSN_OFFSET
    330  1.1  jakllsch end:
    331