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 35stack = 0x7c00 36driveno = (stack-6) 37sectors = (stack-8) 38secpercyl = (stack-12) 39 40BIOS_kbdflags = 0x417 41BIOS_page = 0x462 42 43 /* gas/ld has issues with doing this as absolute addresses... */ 44 .section ".bootsec", "a", @nobits 45 .globl bootsec 46bootsec: 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 70next: 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 941: 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 */ 115missing_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 */ 123read_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. */ 138read_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 150read_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 */ 167ptab = _start+446 168 169read_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 191scan_partition_table: 192 pushal 193 movw %sp, %bp 194 195 /* Search for active partitions */ 196 movw $ptab, %bx 197 movw $4, %cx 198 xorw %ax, %ax 199 push %bx 200 push %cx 2015: 202 testb $0x80, (%bx) 203 jz 6f 204 incw %ax 205 movw %bx, %si 2066: 207 addw $16, %bx 208 loopw 5b 209 210 decw %ax /* Number of active partitions found */ 211 jz boot 212 jns too_many_active 213 214 /* No active partitions found, look for extended partitions */ 215 popw %cx /* %cx <- 4 */ 216 popw %bx /* %bx <- ptab */ 2177: 218 movb 4(%bx), %al 219 cmpb $0x0f, %al /* 0x0f = Win9x extended */ 220 je 8f 221 andb $~0x80, %al /* 0x85 = Linux extended */ 222 cmpb $0x05, %al /* 0x05 = MS-DOS extended */ 223 jne 9f 224 225 /* It is an extended partition. Read the extended partition and 226 try to scan it. If the scan returns, re-load the current 227 partition table and resume scan. */ 2288: 229 movl 8(%bx), %eax /* Partition table offset */ 230 movl 20(%bp), %edx /* "Root" */ 231 addl %edx, %eax /* Compute location of new ptab */ 232 andl %edx, %edx /* Is this the MBR? */ 233 jnz 10f 234 movl %eax, %edx /* Offset -> root if this was MBR */ 23510: 236 call read_partition_table 237 jc 11f 238 call scan_partition_table 23911: 240 /* This returned, so we need to reload the current partition table */ 241 movl 28(%bp), %eax /* "Base" */ 242 call read_partition_table 243 244 /* fall through */ 2459: 246 /* Not an extended partition */ 247 addw $16, %bx 248 loopw 7b 249 250 /* Nothing found, return */ 251 popal 252 ret 253 254too_many_active: 255 call error 256 .ascii "Multiple active partitions.\r\n" 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 */ 262boot: 263 movl 8(%si), %eax 264 addl 28(%bp), %eax 265 movl %eax, 8(%si) /* Adjust in-memory partition table entry */ 266 call read_sector 267 jc disk_error 268 269 /* Check if the read sector is a XFS superblock */ 270 cmpl $0x42534658, (bootsec) /* "XFSB" */ 271 jne no_xfs 272 273 /* We put the Syslinux boot sector at offset 0x800 (4 sectors), so we 274 * need to adjust %eax (%eax + 4) to read the right sector into 0x7C00. 275 */ 276 addl $0x800 >> 0x09, %eax /* plus 4 sectors */ 277 call read_sector 278 jc disk_error 279 280no_xfs: 281 cmpw $0xaa55, (bootsec+510) 282 jne missing_os /* Not a valid boot sector */ 283 movw $driveno, %sp /* driveno == bootsec-6 */ 284 popw %dx /* dl -> drive number */ 285 popw %di /* es:di -> $PnP vector */ 286 popw %es 287 cli 288 jmpw *%sp /* %sp == bootsec */ 289 290disk_error: 291 call error 292 .ascii "Operating system load error.\r\n" 293 294/* 295 * Print error messages. This is invoked with "call", with the 296 * error message at the return address. 297 */ 298error: 299 popw %si 3002: 301 lodsb 302 movb $0x0e, %ah 303 movb (BIOS_page), %bh 304 movb $0x07, %bl 305 int $0x10 /* May destroy %bp */ 306 cmpb $10, %al /* Newline? */ 307 jne 2b 308 309 int $0x18 /* Boot failure */ 310die: 311 hlt 312 jmp die 313