GAS LISTING /tmp/ccrGufok.s 			page 1


   1              	# 1 "mbr.S"
   2              	# 1 "<built-in>"
   1              	/* -----------------------------------------------------------------------
   0              	
   0              	
   2              	 *
   3              	 *   Copyright 2007 H. Peter Anvin - All Rights Reserved
   4              	 *
   5              	 *   Permission is hereby granted, free of charge, to any person
   6              	 *   obtaining a copy of this software and associated documentation
   7              	 *   files (the "Software"), to deal in the Software without
   8              	 *   restriction, including without limitation the rights to use,
   9              	 *   copy, modify, merge, publish, distribute, sublicense, and/or
  10              	 *   sell copies of the Software, and to permit persons to whom
  11              	 *   the Software is furnished to do so, subject to the following
  12              	 *   conditions:
  13              	 *
  14              	 *   The above copyright notice and this permission notice shall
  15              	 *   be included in all copies or substantial portions of the Software.
  16              	 *
  17              	 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  18              	 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  19              	 *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  20              	 *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  21              	 *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  22              	 *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  23              	 *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  24              	 *   OTHER DEALINGS IN THE SOFTWARE.
  25              	 *
  26              	 * ----------------------------------------------------------------------- */
  27              	
  28              		.code16
  29              		.text
  30              	
  31              		.globl	bootsec
  32              	stack		= 0x7c00
  33              	driveno		= (stack-6)
  34              	sectors		= (stack-8)
  35              	secpercyl	= (stack-12)
  36              	
  37              	BIOS_page = 0x462
  38              	
  39              		/* gas/ld has issues with doing this as absolute addresses... */
  40              		.section ".bootsec", "a", @nobits
  41              		.globl	bootsec
  42              	bootsec:
  43 0000 00000000 		.space	512
  43      00000000 
  43      00000000 
  43      00000000 
  43      00000000 
  44              	
  45              		.text
  46              		.globl	_start
  47              	_start:
  48 0000 FA       		cli
  49 0001 31C0     		xorw	%ax, %ax
GAS LISTING /tmp/ccrGufok.s 			page 2


  50 0003 8ED8     		movw	%ax, %ds
  51 0005 8ED0     		movw	%ax, %ss
  52 0007 BC007C   		movw	$stack, %sp
  53 000a 89E6     		movw	%sp, %si
  54 000c 06       		pushw	%es		/* es:di -> $PnP header */
  55 000d 57       		pushw	%di
  56 000e 52       		pushw	%dx		/* dl -> drive number */
  57 000f 8EC0     		movw	%ax, %es
  58 0011 FB       		sti
  59 0012 FC       		cld
  60              	
  61              		/* Copy down to 0:0x600 */
  62 0013 BF0000   		movw	$_start, %di
  63 0016 B90001   		movw	$(512/2), %cx
  64 0019 F3A5     		rep; movsw
  65              	
  66 001b EA200000 		ljmpw	$0, $next
  66      00
  67              	
  68              	next:
  69              		/* Check to see if we have EBIOS */
  70 0020 52       		pushw	%dx		/* drive number */
  71 0021 B80041   		movw	$0x4100, %ax
  72 0024 BBAA55   		movw	$0x55aa, %bx
  73 0027 31C9     		xorw	%cx, %cx
  74 0029 30F6     		xorb	%dh, %dh
  75 002b F9       		stc
  76 002c CD13     		int	$0x13
  77 002e 7213     		jc	1f
  78 0030 81FB55AA 		cmpw	$0xaa55, %bx
  79 0034 750D     		jne	1f
  80 0036 D1E9     		shrw	%cx		/* Bit 0 = fixed disk subset */
  81 0038 7309     		jnc	1f
  82              	
  83              		/* We have EBIOS; patch in the following code at
  84              		   read_sector_cbios: movb $0x42, %ah ;  jmp read_common */
  85 003a 66C7068F 		movl	$0xeb42b4+((read_common-read_sector_cbios-4) << 24), \
  85      00B442EB 
  85      15
  86              			(read_sector_cbios)
  87              	
  88              	1:
  89 0043 5A       		popw	%dx
  90              	
  91              		/* Get (C)HS geometry */
  92 0044 B408     		movb	$0x08, %ah
  93 0046 CD13     		int	$0x13
  94 0048 83E13F   		andw	$0x3f, %cx	/* Sector count */
  95 004b 51       		pushw	%cx		/* Save sectors on the stack */
  96 004c 0FB6C6   		movzbw	%dh, %ax	/* dh = max head */
  97 004f 40       		incw	%ax		/* From 0-based max to count */
  98 0050 F7E1     		mulw	%cx		/* Heads*sectors -> sectors per cylinder */
  99              	
 100              		/* Save sectors/cylinder on the stack */
 101 0052 52       		pushw	%dx		/* High word */
 102 0053 50       		pushw	%ax		/* Low word */
 103              	
GAS LISTING /tmp/ccrGufok.s 			page 3


 104 0054 6631C0   		xorl	%eax, %eax	/* Base */
 105 0057 6699     		cdq			/* Root (%edx <- 0) */
 106 0059 E86700   		call	scan_partition_table
 107              	
 108              		/* If we get here, we have no OS */
 109              	missing_os:
 110 005c E82401   		call	error
 111 005f 4D697373 		.ascii	"Missing operating system.\r\n"
 111      696E6720 
 111      6F706572 
 111      6174696E 
 111      67207379 
 112 007a 00       		.byte	0
 113              	
 114              	/*
 115              	 * read_sector: read a single sector pointed to by %eax to 0x7c00.
 116              	 * CF is set on error.  All registers saved.
 117              	 */
 118              	read_sector:
 119 007b 6660     		pushal
 120 007d 6631D2   		xorl	%edx, %edx
 121 0080 BB0000   		movw	$bootsec, %bx
 122 0083 6652     		pushl	%edx	/* MSW of LBA */
 123 0085 6650     		pushl	%eax	/* LSW of LBA */
 124 0087 06       		pushw	%es	/* Buffer segment */
 125 0088 53       		pushw	%bx	/* Buffer offset */
 126 0089 6A01     		pushw	$1	/* Sector count */
 127 008b 6A10     		pushw	$16	/* Size of packet */
 128 008d 89E6     		movw	%sp, %si
 129              	
 130              		/* This chunk is skipped if we have ebios */
 131              		/* Do not clobber %eax before this chunk! */
 132              		/* This also relies on %bx and %edx as set up above. */
 133              	read_sector_cbios:
 134 008f 66F736F4 		divl	(secpercyl)
 134      7B
 135 0094 C0E406   		shlb	$6, %ah
 136 0097 88E1     		movb	%ah, %cl
 137 0099 88C5     		movb	%al, %ch
 138 009b 92       		xchgw	%dx, %ax
 139 009c F636F87B 		divb	(sectors)
 140 00a0 88C6     		movb	%al, %dh
 141 00a2 08E1     		orb	%ah, %cl
 142 00a4 41       		incw	%cx	/* Sectors are 1-based */
 143 00a5 B80102   		movw	$0x0201, %ax
 144              	
 145              	read_common:
 146 00a8 8A16FA7B 		movb	(driveno), %dl
 147 00ac CD13     		int	$0x13
 148 00ae 83C410   		addw	$16, %sp	/* Drop DAPA */
 149 00b1 6661     		popal
 150 00b3 C3       		ret
 151              	
 152              	/*
 153              	 * read_partition_table:
 154              	 *	Read a partition table (pointed to by %eax), and copy
 155              	 *	the partition table into the ptab buffer.
GAS LISTING /tmp/ccrGufok.s 			page 4


 156              	 *
 157              	 *	Clobbers %si, %di, and %cx, other registers preserved.
 158              	 *	%cx = 0 on exit.
 159              	 *
 160              	 *	On error, CF is set and ptab is overwritten with junk.
 161              	 */
 162              	ptab	= _start+446
 163              	
 164              	read_partition_table:
 165 00b4 E8C4FF   		call	read_sector
 166 00b7 BEBE01   		movw	$bootsec+446, %si
 167 00ba BFBE01   		movw	$ptab, %di
 168 00bd B92000   		movw	$(16*4/2), %cx
 169 00c0 F3A5     		rep ; movsw
 170 00c2 C3       		ret
 171              	
 172              	/*
 173              	 * scan_partition_table:
 174              	 *	Scan a partition table currently loaded in the partition table
 175              	 *	area.  Preserve all registers.
 176              	 *
 177              	 *      On entry:
 178              	 *	  %eax - base (location of this partition table)
 179              	 *	  %edx - root (offset from MBR, or 0 for MBR)
 180              	 *
 181              	 *      These get pushed into stack slots:
 182              	 *        28(%bp) - %eax - base
 183              	 *	  20(%bp) - %edx - root
 184              	 */
 185              	
 186              	scan_partition_table:
 187 00c3 6660     		pushal
 188 00c5 89E5     		movw	%sp, %bp
 189              	
 190              		/* Search for active partitions */
 191 00c7 BBBE01   		movw	$ptab, %bx
 192 00ca B90400   		movw	$4, %cx
 193 00cd 31C0     		xorw	%ax, %ax
 194 00cf 53       		push	%bx
 195 00d0 51       		push	%cx
 196              	5:
 197 00d1 F60780   		testb	$0x80, (%bx)
 198 00d4 7403     		jz	6f
 199 00d6 40       		incw	%ax
 200 00d7 89DE     		movw	%bx, %si
 201              	6:
 202 00d9 83C310   		addw	$16, %bx
 203 00dc E2F3     		loopw	5b
 204              	
 205 00de 48       		decw	%ax		/* Number of active partitions found */
 206 00df 745C     		jz	boot
 207 00e1 7939     		jns	too_many_active
 208              	
 209              		/* No active partitions found, look for extended partitions */
 210 00e3 5B       		popw	%bx		/* %bx <- ptab */
 211 00e4 59       		popw	%cx		/* %cx <- 4    */
 212              	7:
GAS LISTING /tmp/ccrGufok.s 			page 5


 213 00e5 8A4704   		movb	4(%bx), %al
 214 00e8 3C0F     		cmpb	$0x0f, %al	/* 0x0f = Win9x extended */
 215 00ea 7406     		je	8f
 216 00ec 247F     		andb	$~0x80, %al	/* 0x85 = Linux extended */
 217 00ee 3C05     		cmpb	$0x05, %al	/* 0x05 = MS-DOS extended */
 218 00f0 7522     		jne	9f
 219              	
 220              		/* It is an extended partition.  Read the extended partition and
 221              		   try to scan it.  If the scan returns, re-load the current
 222              		   partition table and resume scan. */
 223              	8:
 224 00f2 668B4708 		movl	8(%bx), %eax		/* Partition table offset */
 225 00f6 668B5614 		movl	20(%bp), %edx		/* "Root" */
 226 00fa 6601D0   		addl	%edx, %eax		/* Compute location of new ptab */
 227 00fd 6621D2   		andl	%edx, %edx		/* Is this the MBR? */
 228 0100 7503     		jnz	10f
 229 0102 6689C2   		movl	%eax, %edx		/* Offset -> root if this was MBR */
 230              	10:
 231 0105 E8ACFF   		call	read_partition_table
 232 0108 7203     		jc	11f
 233 010a E8B6FF   		call	scan_partition_table
 234              	11:
 235              		/* This returned, so we need to reload the current partition table */
 236 010d 668B461C 		movl	28(%bp), %eax		/* "Base" */
 237 0111 E8A0FF   		call	read_partition_table
 238              	
 239              		/* fall through */
 240              	9:
 241              		/* Not an extended partition */
 242 0114 83C310   		addw	$16, %bx
 243 0117 E2CC     		loopw	7b
 244              	
 245              		/* Nothing found, return */
 246 0119 6661     		popal
 247 011b C3       		ret
 248              	
 249              	too_many_active:
 250 011c E86400   		call	error
 251 011f 4D756C74 		.ascii	"Multiple active partitions.\r\n"
 251      69706C65 
 251      20616374 
 251      69766520 
 251      70617274 
 252 013c 00       		.byte	0
 253              	
 254              	/*
 255              	 * boot: invoke the actual bootstrap. (%si) points to the partition
 256              	 *	 table entry, and 28(%bp) has the partition table base.
 257              	 */
 258              	boot:
 259 013d 668B4408 		movl	8(%si), %eax
 260 0141 6603461C 		addl	28(%bp), %eax
 261 0145 66894408 		movl	%eax, 8(%si)	/* Adjust in-memory partition table entry */
 262 0149 E82FFF   		call	read_sector
 263 014c 7213     		jc	disk_error
 264 014e 813EFE01 		cmpw	$0xaa55, (bootsec+510)
 264      55AA
GAS LISTING /tmp/ccrGufok.s 			page 6


 265 0154 0F8504FF 		jne	missing_os		/* Not a valid boot sector */
 266 0158 BCFA7B   		movw	$driveno, %sp	/* driveno == bootsec-6 */
 267 015b 5A       		popw	%dx		/* dl -> drive number */
 268 015c 5F       		popw	%di		/* es:di -> $PnP vector */
 269 015d 07       		popw	%es
 270 015e FA       		cli
 271 015f FFE4     		jmpw	*%sp		/* %sp == bootsec */
 272              	
 273              	disk_error:
 274 0161 E81F00   		call	error
 275 0164 4F706572 		.ascii	"Operating system load error.\r\n"
 275      6174696E 
 275      67207379 
 275      7374656D 
 275      206C6F61 
 276 0182 00       		.byte	0
 277              	
 278              	/*
 279              	 * Print error messages.  This is invoked with "call", with the
 280              	 * error message at the return address.
 281              	 */
 282              	error:
 283 0183 5E       		popw	%si
 284              	2:
 285 0184 AC       		lodsb
 286 0185 20C0     		andb	%al, %al
 287 0187 740C     		jz	3f
 288 0189 B40E     		movb	$0x0e, %ah
 289 018b 8A3E6204 		movb	(BIOS_page), %bh
 290 018f B307     		movb	$0x07, %bl
 291 0191 CD10     		int	$0x10
 292 0193 EBEF     		jmp	2b
 293              	3:
 294 0195 CD18     		int	$0x18		/* Boot failure */
 295              	die:
 296 0197 F4       		hlt
 297 0198 EBFD     		jmp	die
GAS LISTING /tmp/ccrGufok.s 			page 7


DEFINED SYMBOLS
                            *ABS*:0000000000000000 mbr.S
               mbr.S:42     .bootsec:0000000000000000 bootsec
               mbr.S:32     *ABS*:0000000000007c00 stack
               mbr.S:33     *ABS*:0000000000007bfa driveno
               mbr.S:34     *ABS*:0000000000007bf8 sectors
               mbr.S:35     *ABS*:0000000000007bf4 secpercyl
               mbr.S:37     *ABS*:0000000000000462 BIOS_page
               mbr.S:47     .text:0000000000000000 _start
               mbr.S:68     .text:0000000000000020 next
               mbr.S:145    .text:00000000000000a8 read_common
               mbr.S:133    .text:000000000000008f read_sector_cbios
               mbr.S:186    .text:00000000000000c3 scan_partition_table
               mbr.S:109    .text:000000000000005c missing_os
               mbr.S:282    .text:0000000000000183 error
               mbr.S:118    .text:000000000000007b read_sector
               mbr.S:47     .text:00000000000001be ptab
               mbr.S:164    .text:00000000000000b4 read_partition_table
               mbr.S:258    .text:000000000000013d boot
               mbr.S:249    .text:000000000000011c too_many_active
               mbr.S:273    .text:0000000000000161 disk_error
               mbr.S:295    .text:0000000000000197 die

NO UNDEFINED SYMBOLS
