Home | History | Annotate | Download | only in mbr
      1 /* -----------------------------------------------------------------------
      2  *
      3  *   Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
      4  *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
      5  *
      6  *   Permission is hereby granted, free of charge, to any person
      7  *   obtaining a copy of this software and associated documentation
      8  *   files (the "Software"), to deal in the Software without
      9  *   restriction, including without limitation the rights to use,
     10  *   copy, modify, merge, publish, distribute, sublicense, and/or
     11  *   sell copies of the Software, and to permit persons to whom
     12  *   the Software is furnished to do so, subject to the following
     13  *   conditions:
     14  *
     15  *   The above copyright notice and this permission notice shall
     16  *   be included in all copies or substantial portions of the Software.
     17  *
     18  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     19  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
     20  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     21  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
     22  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
     23  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     24  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     25  *   OTHER DEALINGS IN THE SOFTWARE.
     26  *
     27  * ----------------------------------------------------------------------- */
     28 
     29 #include "adjust.h"
     30 
     31 	.code16
     32 	.text
     33 
     34 	.globl	bootsec
     35 stack		= 0x7c00
     36 driveno		= (stack-6)
     37 sectors		= (stack-8)
     38 secpercyl	= (stack-12)
     39 
     40 BIOS_kbdflags	= 0x417
     41 BIOS_page	= 0x462
     42 
     43 	/* gas/ld has issues with doing this as absolute addresses... */
     44 	.section ".bootsec", "a", @nobits
     45 	.globl	bootsec
     46 bootsec:
     47 	.space	512
     48 
     49 	.text
     50 	.globl	_start
     51 _start:
     52 	.byte	0x33, 0xc0	/* xorw	%ax, %ax */
     53 	cli
     54 	movw	%ax, %ds
     55 	movw	%ax, %ss
     56 	movw	$stack, %sp
     57 	movw	%sp, %si
     58 	pushw	%es		/* es:di -> $PnP header */
     59 	pushw	%di
     60 	movw	%ax, %es
     61 	sti
     62 	cld
     63 
     64 	/* Copy down to 0:0x600 */
     65 	movw	$_start, %di
     66 	movw	$(512/2), %cx
     67 	rep; movsw
     68 
     69 	ljmpw	$0, $next
     70 next:
     71 
     72 	ADJUST_DRIVE
     73 	pushw	%dx		/* dl -> drive number */
     74 
     75 	/* Check to see if we have EBIOS */
     76 	pushw	%dx		/* drive number */
     77 	movb	$0x41, %ah	/* %al == 0 already */
     78 	movw	$0x55aa, %bx
     79 	xorw	%cx, %cx
     80 	xorb	%dh, %dh
     81 	stc
     82 	int	$0x13
     83 	jc	1f
     84 	cmpw	$0xaa55, %bx
     85 	jne	1f
     86 	shrw	%cx		/* Bit 0 = fixed disk subset */
     87 	jnc	1f
     88 
     89 	/* We have EBIOS; patch in the following code at
     90 	   read_sector_cbios: movb $0x42, %ah ;  jmp read_common */
     91 	movl	$0xeb42b4+((read_common-read_sector_cbios-4) << 24), \
     92 		(read_sector_cbios)
     93 
     94 1:
     95 	popw	%dx
     96 
     97 	/* Get (C)HS geometry */
     98 	movb	$0x08, %ah
     99 	int	$0x13
    100 	andw	$0x3f, %cx	/* Sector count */
    101 	pushw	%cx		/* Save sectors on the stack */
    102 	movzbw	%dh, %ax	/* dh = max head */
    103 	incw	%ax		/* From 0-based max to count */
    104 	mulw	%cx		/* Heads*sectors -> sectors per cylinder */
    105 
    106 	/* Save sectors/cylinder on the stack */
    107 	pushw	%dx		/* High word */
    108 	pushw	%ax		/* Low word */
    109 
    110 	xorl	%eax, %eax	/* Base */
    111 	cdq			/* Root (%edx <- 0) */
    112 	call	scan_partition_table
    113 
    114 	/* If we get here, we have no OS */
    115 missing_os:
    116 	call	error
    117 	.ascii	"Missing operating system.\r\n"
    118 
    119 /*
    120  * read_sector: read a single sector pointed to by %eax to 0x7c00.
    121  * CF is set on error.  All registers saved.
    122  */
    123 read_sector:
    124 	pushal
    125 	xorl	%edx, %edx
    126 	movw	$bootsec, %bx
    127 	pushl	%edx	/* MSW of LBA */
    128 	pushl	%eax	/* LSW of LBA */
    129 	pushw	%es	/* Buffer segment */
    130 	pushw	%bx	/* Buffer offset */
    131 	pushw	$1	/* Sector count */
    132 	pushw	$16	/* Size of packet */
    133 	movw	%sp, %si
    134 
    135 	/* This chunk is skipped if we have ebios */
    136 	/* Do not clobber %eax before this chunk! */
    137 	/* This also relies on %bx and %edx as set up above. */
    138 read_sector_cbios:
    139 	divl	(secpercyl)
    140 	shlb	$6, %ah
    141 	movb	%ah, %cl
    142 	movb	%al, %ch
    143 	xchgw	%dx, %ax
    144 	divb	(sectors)
    145 	movb	%al, %dh
    146 	orb	%ah, %cl
    147 	incw	%cx	/* Sectors are 1-based */
    148 	movw	$0x0201, %ax
    149 
    150 read_common:
    151 	movb	(driveno), %dl
    152 	int	$0x13
    153 	leaw	16(%si), %sp	/* Drop DAPA */
    154 	popal
    155 	ret
    156 
    157 /*
    158  * read_partition_table:
    159  *	Read a partition table (pointed to by %eax), and copy
    160  *	the partition table into the ptab buffer.
    161  *
    162  *	Clobbers %si, %di, and %cx, other registers preserved.
    163  *	%cx = 0 on exit.
    164  *
    165  *	On error, CF is set and ptab is overwritten with junk.
    166  */
    167 ptab	= _start+446
    168 
    169 read_partition_table:
    170 	call	read_sector
    171 	movw	$bootsec+446, %si
    172 	movw	$ptab, %di
    173 	movw	$(16*4/2), %cx
    174 	rep ; movsw
    175 	ret
    176 
    177 /*
    178  * scan_partition_table:
    179  *	Scan a partition table currently loaded in the partition table
    180  *	area.  Preserve all registers.
    181  *
    182  *      On entry:
    183  *	  %eax - base (location of this partition table)
    184  *	  %edx - root (offset from MBR, or 0 for MBR)
    185  *
    186  *      These get pushed into stack slots:
    187  *        28(%bp) - %eax - base
    188  *	  20(%bp) - %edx - root
    189  */
    190 
    191 scan_partition_table:
    192 	pushal
    193 	movw	%sp, %bp
    194 
    195 	/* Scan the primary partition table */
    196 	movw	$ptab, %si
    197 	movw	$4, %cx
    198 	/* Is it a primary partition table? */
    199 	andl	%edx, %edx
    200 	jnz	7f
    201 	push	%si
    202 	push	%cx
    203 
    204 5:
    205 	decb	(partition)
    206 	jz	boot
    207 	addw	$16, %si
    208 	loopw	5b
    209 
    210 	popw	%cx			/* %cx <- 4    */
    211 	popw	%si			/* %si <- ptab */
    212 
    213 	/* No primary partitions found, look for extended/logical partitions */
    214 7:
    215 	movb	4(%si), %al
    216 	andb	%al, %al
    217 	jz	12f			/* Not a valid partition */
    218 	cmpb	$0x0f, %al		/* 0x0f = Win9x extended */
    219 	je	8f
    220 	andb	$~0x80, %al		/* 0x85 = Linux extended */
    221 	cmpb	$0x05, %al		/* 0x05 = MS-DOS extended */
    222 	jne	9f
    223 
    224 	/* It is an extended partition.  Read the extended partition and
    225 	   try to scan it.  If the scan returns, re-load the current
    226 	   partition table and resume scan. */
    227 8:
    228 	movl	8(%si), %eax		/* Partition table offset */
    229 	addl	%edx, %eax		/* Compute location of new ptab */
    230 	andl	%edx, %edx		/* Is this the MBR? */
    231 	jnz	10f
    232 	movl	%eax, %edx		/* Offset -> root if this was MBR */
    233 10:
    234 	call	read_partition_table
    235 	jc	11f
    236 	call	scan_partition_table
    237 11:
    238 	/* This returned, so we need to reload the current partition table */
    239 	movl	28(%bp), %eax		/* "Base" */
    240 	call	read_partition_table
    241 
    242 	/* fall through */
    243 9:
    244 	/* Not an extended partition */
    245 	andl	%edx, %edx		/* Are we inside an extended part? */
    246 	jz	12f
    247 	/* If so, this is a logical partition */
    248 	decb	(partition)
    249 	je	boot
    250 12:
    251 	addw	$16, %si
    252 	loopw	7b
    253 
    254 	/* Nothing found, return */
    255 	popal
    256 	ret
    257 
    258 /*
    259  * boot: invoke the actual bootstrap. (%si) points to the partition
    260  *	 table entry, and 28(%bp) has the partition table base.
    261  */
    262 boot:
    263 	cmpb	$0, 4(%si)
    264 	je	missing_os
    265 	movl	8(%si), %eax
    266 	addl	28(%bp), %eax
    267 	movl	%eax, 8(%si)	/* Adjust in-memory partition table entry */
    268 	call	read_sector
    269 	jc	disk_error
    270 	cmpw	$0xaa55, (bootsec+510)
    271 	jne	missing_os		/* Not a valid boot sector */
    272 	movw	$driveno, %sp	/* driveno == bootsec-6 */
    273 	popw	%dx		/* dl -> drive number */
    274 	popw	%di		/* es:di -> $PnP vector */
    275 	popw	%es
    276 	cli
    277 	jmpw	*%sp		/* %sp == bootsec */
    278 
    279 disk_error:
    280 	call	error
    281 	.ascii	"Operating system load error.\r\n"
    282 
    283 /*
    284  * Print error messages.  This is invoked with "call", with the
    285  * error message at the return address.
    286  */
    287 error:
    288 	popw	%si
    289 2:
    290 	lodsb
    291 	movb	$0x0e, %ah
    292 	movb	(BIOS_page), %bh
    293 	movb	$0x07, %bl
    294 	int	$0x10		/* May destroy %bp */
    295 	cmpb	$10, %al	/* Newline? */
    296 	jne	2b
    297 
    298 	int	$0x18		/* Boot failure */
    299 die:
    300 	hlt
    301 	jmp	die
    302 
    303 /* Location of the partition configuration byte */
    304 partition = _start + 439
    305