summaryrefslogtreecommitdiff
path: root/sys/arch/i386
diff options
context:
space:
mode:
authorJoel Sing <jsing@cvs.openbsd.org>2012-10-31 14:31:31 +0000
committerJoel Sing <jsing@cvs.openbsd.org>2012-10-31 14:31:31 +0000
commit9557829cedab1caf723629c0053691ca2086e80d (patch)
tree39a87f410cdee7d5c1103db3e3d86c08a3238b8b /sys/arch/i386
parenta598db0083212e273ae26daa59426c4ba169554a (diff)
Make cdboot(8) and pxeboot(8) work correctly when it is larger than 64KB in
size. When relocating use blocks that are a maximum of 32KB in size and increment the segment registers after relocating each block. This keeps us within the confines of the %cx register and the real mode segmented addressing.
Diffstat (limited to 'sys/arch/i386')
-rw-r--r--sys/arch/i386/stand/cdboot/srt0.S49
-rw-r--r--sys/arch/i386/stand/pxeboot/srt0.S51
2 files changed, 73 insertions, 27 deletions
diff --git a/sys/arch/i386/stand/cdboot/srt0.S b/sys/arch/i386/stand/cdboot/srt0.S
index 9a3d241a263..5a721e21c02 100644
--- a/sys/arch/i386/stand/cdboot/srt0.S
+++ b/sys/arch/i386/stand/cdboot/srt0.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: srt0.S,v 1.2 2012/10/11 12:08:24 jsing Exp $ */
+/* $OpenBSD: srt0.S,v 1.3 2012/10/31 14:31:30 jsing Exp $ */
/*
* Copyright (c) 1997 Michael Shalayeff
@@ -58,13 +58,10 @@ _start:
* Like the standard /boot, we are linked to run at 0x40120
* (load address 0x40000), so we relocate to there.
*
- * From 0x7C00 to 0x40000 is 0x38400 (230400) bytes, so don't
+ * From 0x7C00 to 0x40000 is 0x38400 (230400) bytes, so we don't
* have to worry about an overlapping copy until cdboot is
* over 225 KB.
*
- * Note that there are other reasons to be worried if
- * sizeof(/boot) > 64 KB. So currently we copy a maximum of 64 KB.
- *
* Our cdbr CD-ROM boot sector passes us the drive number to use
* in %dl.
*/
@@ -73,20 +70,46 @@ _start:
movw %ax, %ss /* CPU disables interrupts till... */
movl $CDBOOTADDR-4, %esp /* after this instruction */
- movw $(CDBOOTADDR >> 4), %ax
- movw %ax, %ds
- xorw %si, %si /* Where we're coming from */
+ pushl %edx /* Preserve the drive number. */
- movw $(LINKADDR >> 4), %ax
- movw %ax, %es /* Set %es = 0x4000 */
- xorw %di, %di /* Where we're going to */
+ movw $(CDBOOTADDR >> 4), %ax /* Reloc from %ds = 0x7c0. */
+ movw $(LINKADDR >> 4), %bx /* Reloc to %es = 0x4012. */
- movl $_C_LABEL(end), %ecx
- subl $_C_LABEL(_start), %ecx /* How big are we? */
+ movl $_C_LABEL(end), %edx
+ subl $_C_LABEL(_start), %edx /* How big are we? */
+
+ /*
+ * Relocate in blocks that are a maximum of 32KB in size, incrementing
+ * the segment registers after each block. The 'rep; movsb' instruction
+ * uses %cx, which limits us to a maximum block size of 0xfff0, even
+ * though we can address the full 64KB within a single segment.
+ */
+#define RELOC_BLOCK_SIZE 0x8000
+reloc_loop:
+ movl %edx, %ecx
+ jcxz reloc_done
+ cmpl $RELOC_BLOCK_SIZE, %ecx
+ jbe reloc_notrunc
+ movl $RELOC_BLOCK_SIZE, %ecx
+reloc_notrunc:
+ subl %ecx, %edx
+
+ movw %ax, %ds /* Where we're coming from */
+ xorw %si, %si
+
+ movw %bx, %es /* Where we're going to */
+ xorw %di, %di
cld
rep; movsb /* Copy into place */
+ addw $(RELOC_BLOCK_SIZE >> 4), %ax
+ addw $(RELOC_BLOCK_SIZE >> 4), %bx
+
+ jmp reloc_loop
+
+reloc_done:
+ popl %edx
jmpl $(LINKADDR >> 4), $(relocated-_start) /* Now relocate */
relocated:
diff --git a/sys/arch/i386/stand/pxeboot/srt0.S b/sys/arch/i386/stand/pxeboot/srt0.S
index e0cc7ddb8f1..16a0313222c 100644
--- a/sys/arch/i386/stand/pxeboot/srt0.S
+++ b/sys/arch/i386/stand/pxeboot/srt0.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: srt0.S,v 1.2 2012/10/11 12:08:24 jsing Exp $ */
+/* $OpenBSD: srt0.S,v 1.3 2012/10/31 14:31:30 jsing Exp $ */
/*
* Copyright (c) 1997 Michael Shalayeff
@@ -56,13 +56,10 @@ _start:
* the standard /boot, we are linked to run at 0x40120 (load
* address 0x40000), so we relocate to there.
*
- * From 0x7C00 to 0x40000 is 0x38400 (230400) bytes, so don't
+ * From 0x7C00 to 0x40000 is 0x38400 (230400) bytes, so we don't
* have to worry about an overlapping copy until pxeboot is
* over 225 KB.
*
- * Note that there are other reasons to be worried if
- * sizeof(/boot) > 64 KB. So currently we copy a maximum of 64 KB.
- *
* PXE loads us with a stack that grows down from 0x80000 (512 KB).
* While it is unlikely that this will clash with our code that
* we're copying up, we create a temporary stack just below us
@@ -71,23 +68,49 @@ _start:
*/
#define PXEBOOTADDR 0x7c00 /* Address where we are loaded by PXE */
xorw %ax, %ax
- movw %ax, %ss /* CPU disables interrupts till.. */
+ movw %ax, %ss /* CPU disables interrupts till... */
movl $PXEBOOTADDR-4, %esp /* after this instruction */
- movw $(PXEBOOTADDR >> 4), %ax
- movw %ax, %ds
- xorw %si, %si /* Where we're coming from */
+ pushl %edx /* Preserve the drive number. */
- movw $(LINKADDR >> 4), %ax
- movw %ax, %es /* Set %es = 0x4000 */
- xorw %di, %di /* Where we're going to */
+ movw $(PXEBOOTADDR >> 4), %ax /* Reloc from %ds = 0x7c0. */
+ movw $(LINKADDR >> 4), %bx /* Reloc to %es = 0x4012. */
- movl $_C_LABEL(end), %ecx
- subl $_C_LABEL(_start), %ecx /* How big are we? */
+ movl $_C_LABEL(end), %edx
+ subl $_C_LABEL(_start), %edx /* How big are we? */
+
+ /*
+ * Relocate in blocks that are a maximum of 32KB in size, incrementing
+ * the segment registers after each block. The 'rep; movsb' instruction
+ * uses %cx, which limits us to a maximum block size of 0xfff0, even
+ * though we can address the full 64KB within a single segment.
+ */
+#define RELOC_BLOCK_SIZE 0x8000
+reloc_loop:
+ movl %edx, %ecx
+ jcxz reloc_done
+ cmpl $RELOC_BLOCK_SIZE, %ecx
+ jbe reloc_notrunc
+ movl $RELOC_BLOCK_SIZE, %ecx
+reloc_notrunc:
+ subl %ecx, %edx
+
+ movw %ax, %ds /* Where we're coming from */
+ xorw %si, %si
+
+ movw %bx, %es /* Where we're going to */
+ xorw %di, %di
cld
rep; movsb /* Copy into place */
+ addw $(RELOC_BLOCK_SIZE >> 4), %ax
+ addw $(RELOC_BLOCK_SIZE >> 4), %bx
+
+ jmp reloc_loop
+
+reloc_done:
+ popl %edx
jmpl $(LINKADDR >> 4), $(relocated-_start) /* Now relocate */
relocated: