/* -----------------------------------------------------------------------
*
- * 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.
*/
read_sector:
pushal
-read_sector_cbios:
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.
+ *
* 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:
call read_sector
- jc 20f
movw $bootsec+446, %si
movw $ptab, %di
movw $(16*4/2), %cx
rep ; movsw
-20:
ret
/*
jns too_many_active
/* No active partitions found, look for extended partitions */
- popw %bx /* %bx <- ptab */
popw %cx /* %cx <- 4 */
+ popw %bx /* %bx <- ptab */
7:
movb 4(%bx), %al
cmpb $0x0f, %al /* 0x0f = Win9x extended */
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.
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