/* -----------------------------------------------------------------------
*
- * Copyright 2007 H. Peter Anvin - All Rights Reserved
+ * Copyright 2007-2009 H. Peter Anvin - All Rights Reserved
+ * Copyright 2009 Intel Corporation; author: H. Peter Anvin
*
* Permission is hereby granted, free of charge, to any person
* obtaining a copy of this software and associated documentation
*
* ----------------------------------------------------------------------- */
+#include "adjust.h"
+
.code16
.text
.globl bootsec
-stack = 0x7c00
-driveno = (stack-6)
-heads = (stack-8)
-sectors = (stack-10)
+stack = 0x7c00
+driveno = (stack-6)
+sectors = (stack-8)
+secpercyl = (stack-12)
-BIOS_page = 0x462
+BIOS_kbdflags = 0x417
+BIOS_page = 0x462
/* gas/ld has issues with doing this as absolute addresses... */
.section ".bootsec", "a", @nobits
.text
.globl _start
_start:
+ .byte 0x33, 0xc0 /* xorw %ax, %ax */
cli
- xorw %ax, %ax
movw %ax, %ds
movw %ax, %ss
movw $stack, %sp
movw %sp, %si
pushw %es /* es:di -> $PnP header */
pushw %di
- pushw %dx /* dl -> drive number */
movw %ax, %es
sti
cld
rep; movsw
ljmpw $0, $next
-
next:
+
+ ADJUST_DRIVE
+ pushw %dx /* dl -> drive number */
+
/* Check to see if we have EBIOS */
pushw %dx /* drive number */
- movw $0x4100, %ax
+ movb $0x41, %ah /* %al == 0 already */
movw $0x55aa, %bx
xorw %cx, %cx
xorb %dh, %dh
jc 1f
cmpw $0xaa55, %bx
jne 1f
- testb $0x01, %cl
- jz 1f
+ shrw %cx /* Bit 0 = fixed disk subset */
+ jnc 1f
- /* We have EBIOS; patch in a jump to read_sector_ebios */
- movw $0xeb+((read_sector_ebios-read_sector_cbios-2)<< 8), (read_sector_cbios)
+ /* We have EBIOS; patch in the following code at
+ read_sector_cbios: movb $0x42, %ah ; jmp read_common */
+ movl $0xeb42b4+((read_common-read_sector_cbios-4) << 24), \
+ (read_sector_cbios)
1:
popw %dx
/* Get (C)HS geometry */
movb $0x08, %ah
int $0x13
- xorw %ax, %ax
- movb %dh, %al /* dh = number of heads */
- incw %ax /* From 0-based to count */
- pushw %ax /* Save heads on the stack */
andw $0x3f, %cx /* Sector count */
pushw %cx /* Save sectors on the stack */
+ movzbw %dh, %ax /* dh = max head */
+ incw %ax /* From 0-based max to count */
+ mulw %cx /* Heads*sectors -> sectors per cylinder */
- xorl %eax, %eax
- pushl %eax /* Base */
- pushl %eax /* Root */
+ /* Save sectors/cylinder on the stack */
+ pushw %dx /* High word */
+ pushw %ax /* Low word */
+
+ xorl %eax, %eax /* Base */
+ cdq /* Root (%edx <- 0) */
call scan_partition_table
/* If we get here, we have no OS */
- jmp missing_os
+missing_os:
+ call error
+ .ascii "Missing operating system.\r\n"
/*
* read_sector: read a single sector pointed to by %eax to 0x7c00.
- * CF is set on error. All registers clobbered.
+ * CF is set on error. All registers saved.
*/
read_sector:
+ pushal
+ xorl %edx, %edx
+ movw $bootsec, %bx
+ pushl %edx /* MSW of LBA */
+ pushl %eax /* LSW of LBA */
+ pushw %es /* Buffer segment */
+ pushw %bx /* Buffer offset */
+ pushw $1 /* Sector count */
+ pushw $16 /* Size of packet */
+ movw %sp, %si
+
+ /* This chunk is skipped if we have ebios */
+ /* Do not clobber %eax before this chunk! */
+ /* This also relies on %bx and %edx as set up above. */
read_sector_cbios:
- movl %eax, %edx
- shrl $16, %edx
- divw (sectors)
- incw %dx
- movw %dx, %cx
- xorw %dx, %dx
- divw (heads)
- /* dx = head, ax = cylinder */
+ divl (secpercyl)
+ shlb $6, %ah
+ movb %ah, %cl
movb %al, %ch
- shrw $2, %ax
- shrw %ax
- andb $0xc0, %al
- orb %al, %cl
- movb %dl, %dh
- movw $bootsec, %bx
+ xchgw %dx, %ax
+ divb (sectors)
+ movb %al, %dh
+ orb %ah, %cl
+ incw %cx /* Sectors are 1-based */
movw $0x0201, %ax
- jmp read_common
-read_sector_ebios:
- movw $dapa, %si
- movl %eax, 8(%si)
- movb $0x42, %ah
+
read_common:
movb (driveno), %dl
int $0x13
+ leaw 16(%si), %sp /* Drop DAPA */
+ popal
ret
/*
* read_partition_table:
* Read a partition table (pointed to by %eax), and copy
* the partition table into the ptab buffer.
- * Preserve registers.
+ *
+ * Clobbers %si, %di, and %cx, other registers preserved.
+ * %cx = 0 on exit.
+ *
+ * On error, CF is set and ptab is overwritten with junk.
*/
ptab = _start+446
read_partition_table:
- pushal
call read_sector
- jc 20f
movw $bootsec+446, %si
movw $ptab, %di
movw $(16*4/2), %cx
rep ; movsw
-20:
- popal
ret
/*
* scan_partition_table:
* Scan a partition table currently loaded in the partition table
- * area. Preserve 16-bit registers.
+ * area. Preserve all registers.
+ *
+ * On entry:
+ * %eax - base (location of this partition table)
+ * %edx - root (offset from MBR, or 0 for MBR)
*
- * On stack:
- * 18(%bp) - root (offset from MBR, or 0 for MBR)
- * 22(%bp) - base (location of this partition table)
+ * These get pushed into stack slots:
+ * 28(%bp) - %eax - base
+ * 20(%bp) - %edx - root
*/
scan_partition_table:
- pusha
+ pushal
movw %sp, %bp
/* Search for active partitions */
- movw $ptab, %di
+ movw $ptab, %bx
movw $4, %cx
xorw %ax, %ax
+ push %bx
+ push %cx
5:
- testb $0x80, (%di)
- jz 6f
+ testb $0x80, (%bx)
+ jz 6f
incw %ax
- movw %di, %si
+ movw %bx, %si
6:
- addw $16, %di
+ addw $16, %bx
loopw 5b
- cmpw $1, %ax /* Number of active partitions found */
- je boot
- ja too_many_active
+ decw %ax /* Number of active partitions found */
+ jz boot
+ jns too_many_active
/* No active partitions found, look for extended partitions */
- movw $ptab, %di
- movb $4, %cl /* cx == 0 here */
+ popw %cx /* %cx <- 4 */
+ popw %bx /* %bx <- ptab */
7:
- movb 4(%di), %al
- cmpb $0x05, %al /* MS-DOS extended */
- je 8f
- cmpb $0x0f, %al /* Win9x extended */
+ movb 4(%bx), %al
+ cmpb $0x0f, %al /* 0x0f = Win9x extended */
je 8f
- cmpb $0x85, %al /* Linux extended */
+ andb $~0x80, %al /* 0x85 = Linux extended */
+ cmpb $0x05, %al /* 0x05 = MS-DOS extended */
jne 9f
/* It is an extended partition. Read the extended partition and
try to scan it. If the scan returns, re-load the current
partition table and resume scan. */
8:
- movl 8(%di), %eax /* Partition table offset */
- movl 18(%bp), %edx /* "Root" */
+ movl 8(%bx), %eax /* Partition table offset */
+ movl 20(%bp), %edx /* "Root" */
addl %edx, %eax /* Compute location of new ptab */
andl %edx, %edx /* Is this the MBR? */
jnz 10f
movl %eax, %edx /* Offset -> root if this was MBR */
10:
- pushl %eax /* Push new base */
- pushl %edx /* Push new root */
call read_partition_table
- jc 11f
+ jc 11f
call scan_partition_table
11:
- addw $8, %sp
/* This returned, so we need to reload the current partition table */
- movl 22(%bp), %eax
+ movl 28(%bp), %eax /* "Base" */
call read_partition_table
/* fall through */
9:
/* Not an extended partition */
- addw $16, %di
+ addw $16, %bx
loopw 7b
/* Nothing found, return */
- popa
+ popal
ret
+too_many_active:
+ call error
+ .ascii "Multiple active partitions.\r\n"
+
/*
* boot: invoke the actual bootstrap. (%si) points to the partition
- * table entry, and 22(%bp) has the partition table base.
+ * table entry, and 28(%bp) has the partition table base.
*/
boot:
movl 8(%si), %eax
- addl 22(%bp), %eax
- movl %eax, 8(%si)
- pushw %si
+ addl 28(%bp), %eax
+ movl %eax, 8(%si) /* Adjust in-memory partition table entry */
call read_sector
- popw %si
jc disk_error
cmpw $0xaa55, (bootsec+510)
jne missing_os /* Not a valid boot sector */
- movw $driveno, %sp
+ movw $driveno, %sp /* driveno == bootsec-6 */
popw %dx /* dl -> drive number */
popw %di /* es:di -> $PnP vector */
popw %es
cli
- jmp bootsec
+ jmpw *%sp /* %sp == bootsec */
-/*
- * error messages
- */
-missing_os:
- movw $missing_os_msg, %si
- jmp error
disk_error:
- movw $disk_error_msg, %si
- jmp error
-too_many_active:
- movw $too_many_active_msg, %si
- /* jmp error */
+ call error
+ .ascii "Operating system load error.\r\n"
+/*
+ * Print error messages. This is invoked with "call", with the
+ * error message at the return address.
+ */
error:
+ popw %si
2:
lodsb
- andb %al, %al
- jz 3f
movb $0x0e, %ah
movb (BIOS_page), %bh
movb $0x07, %bl
- int $0x10
- jmp 2b
-3:
+ int $0x10 /* May destroy %bp */
+ cmpb $10, %al /* Newline? */
+ jne 2b
+
int $0x18 /* Boot failure */
- jmp . /* Die */
-
-missing_os_msg:
- .ascii "Missing operating system."
- .byte 0
-disk_error_msg:
- .ascii "Operating system load error."
- .byte 0
-too_many_active_msg:
- .ascii "Multiple active partitions."
- .byte 0
-
- .balign 4
-dapa:
- .short 16 /* Size of packet */
- .short 1 /* Sector count */
- .short 0x7c00 /* Buffer offset */
- .short 0 /* Buffer segment */
- .long 0 /* LSW of LBA */
- .long 0 /* MSW of LBA */
+die:
+ hlt
+ jmp die