/* -----------------------------------------------------------------------
*
- * 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
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
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
int $0x13
andw $0x3f, %cx /* Sector count */
pushw %cx /* Save sectors on the stack */
- xorw %ax, %ax
- pushw %ax /* High word of sectors/cylinder */
- movb %dh, %al /* dh = number of heads */
- incw %ax /* From 0-based to count */
+ movzbw %dh, %ax /* dh = max head */
+ incw %ax /* From 0-based max to count */
mulw %cx /* Heads*sectors -> sectors per cylinder */
- pushw %ax /* Save sectors/cylinder on the stack */
+
+ /* 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:
-read_sector_cbios:
+ 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:
divl (secpercyl)
- rorb %ah
- rorb %ah
+ shlb $6, %ah
movb %ah, %cl
movb %al, %ch
- movw %dx, %ax
+ xchgw %dx, %ax
divb (sectors)
movb %al, %dh
- incb %ah
orb %ah, %cl
- movw $bootsec, %bx
+ 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
/*
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)
+ 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
+ movb 4(%bx), %al
cmpb $0x0f, %al /* 0x0f = Win9x extended */
je 8f
andb $~0x80, %al /* 0x85 = Linux extended */
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 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? */
call scan_partition_table
11:
/* This returned, so we need to reload the current partition table */
- movl 28(%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 */
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 28(%bp) has the partition table base.
boot:
movl 8(%si), %eax
addl 28(%bp), %eax
- movl %eax, 8(%si)
- pushw %si
+ 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
-
-#ifndef NO_ALIGN
- .balign 4
-#endif
-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