[SeaBIOS] [PATCH] Fix winxp boot regression introduced in ecdc655a.

Kevin O'Connor kevin at koconnor.net
Sun Jun 3 02:40:32 CEST 2012


The winxp boot loader does something curious - it sets an int 0x1c
handler, records the stack location, and then spins in place with irqs
enabled.  The 0x1c handler alters the memory just past the stack
pointer so that when the timer irq returns the code jumps to a new
location and stop spinning.  The winxp code relies on the fact that a
hw irq will always place 6 bytes at a specific location and that it
can alter those bytes.

The ecdc655a patch does a full backup/restore of the register state.
Unfortunately, the restore overwrites the changes made by the winxp
0x1c handler.

This patch reverts much of ecdc655a.  Hardware irqs are still handled
on the extra stack, but only the essential register state is backed up
and restored.

Also, stack_hop_back is changed to only use %sp when changing states -
this enables the entry code to store just %esp instead of both %esp
and %sp.

Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---
 src/clock.c     |    8 ++++----
 src/disk.c      |    4 ++--
 src/floppy.c    |    4 ++--
 src/misc.c      |    8 ++++----
 src/output.c    |    9 +++++++++
 src/ps2port.c   |    8 ++++----
 src/romlayout.S |   53 ++++++++++++++++++++---------------------------------
 src/stacks.c    |    2 +-
 src/util.h      |    5 +++++
 9 files changed, 51 insertions(+), 50 deletions(-)

diff --git a/src/clock.c b/src/clock.c
index 55dde2e..69e9f17 100644
--- a/src/clock.c
+++ b/src/clock.c
@@ -516,9 +516,9 @@ handle_1a(struct bregs *regs)
 
 // INT 08h System Timer ISR Entry Point
 void VISIBLE16
-handle_08(struct bregs *regs)
+handle_08(void)
 {
-    debug_enter(regs, DEBUG_ISR_08);
+    debug_isr(DEBUG_ISR_08);
 
     floppy_tick();
 
@@ -659,9 +659,9 @@ handle_1583(struct bregs *regs)
 
 // int70h: IRQ8 - CMOS RTC
 void VISIBLE16
-handle_70(struct bregs *regs)
+handle_70(void)
 {
-    debug_enter(regs, DEBUG_ISR_70);
+    debug_isr(DEBUG_ISR_70);
 
     // Check which modes are enabled and have occurred.
     u8 registerB = inb_cmos(CMOS_STATUS_B);
diff --git a/src/disk.c b/src/disk.c
index 3ca5697..8eff464 100644
--- a/src/disk.c
+++ b/src/disk.c
@@ -885,9 +885,9 @@ handle_13(struct bregs *regs)
 
 // record completion in BIOS task complete flag
 void VISIBLE16
-handle_76(struct bregs *regs)
+handle_76(void)
 {
-    debug_enter(regs, DEBUG_ISR_76);
+    debug_isr(DEBUG_ISR_76);
     SET_BDA(disk_interrupt_flag, 0xff);
     eoi_pic2();
 }
diff --git a/src/floppy.c b/src/floppy.c
index 5400bb0..72bc79b 100644
--- a/src/floppy.c
+++ b/src/floppy.c
@@ -582,9 +582,9 @@ process_floppy_op(struct disk_op_s *op)
 
 // INT 0Eh Diskette Hardware ISR Entry Point
 void VISIBLE16
-handle_0e(struct bregs *regs)
+handle_0e(void)
 {
-    debug_enter(regs, DEBUG_ISR_0e);
+    debug_isr(DEBUG_ISR_0e);
     if (! CONFIG_FLOPPY)
         goto done;
 
diff --git a/src/misc.c b/src/misc.c
index d0d6665..b948778 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -55,9 +55,9 @@ handle_10(struct bregs *regs)
 
 // NMI handler
 void VISIBLE16
-handle_02(struct bregs *regs)
+handle_02(void)
 {
-    debug_enter(regs, DEBUG_ISR_02);
+    debug_isr(DEBUG_ISR_02);
 }
 
 void
@@ -71,9 +71,9 @@ mathcp_setup(void)
 
 // INT 75 - IRQ13 - MATH COPROCESSOR EXCEPTION
 void VISIBLE16
-handle_75(struct bregs *regs)
+handle_75(void)
 {
-    debug_enter(regs, DEBUG_ISR_75);
+    debug_isr(DEBUG_ISR_75);
 
     // clear irq13
     outb(0, PORT_MATH_CLEAR);
diff --git a/src/output.c b/src/output.c
index 1fe5d91..37c4942 100644
--- a/src/output.c
+++ b/src/output.c
@@ -487,6 +487,15 @@ dump_regs(struct bregs *regs)
             , regs->code.seg, regs->code.offset, regs->flags);
 }
 
+// Report entry to an Interrupt Service Routine (ISR).
+void
+__debug_isr(const char *fname)
+{
+    puts_cs(&debuginfo, fname);
+    putc(&debuginfo, '\n');
+    debug_serial_flush();
+}
+
 // Function called on handler startup.
 void
 __debug_enter(struct bregs *regs, const char *fname)
diff --git a/src/ps2port.c b/src/ps2port.c
index 601e40d..d4626d6 100644
--- a/src/ps2port.c
+++ b/src/ps2port.c
@@ -356,12 +356,12 @@ ps2_mouse_command(int command, u8 *param)
 
 // INT74h : PS/2 mouse hardware interrupt
 void VISIBLE16
-handle_74(struct bregs *regs)
+handle_74(void)
 {
     if (! CONFIG_PS2PORT)
         return;
 
-    debug_enter(regs, DEBUG_ISR_74);
+    debug_isr(DEBUG_ISR_74);
 
     u8 v = inb(PORT_PS2_STATUS);
     if ((v & (I8042_STR_OBF|I8042_STR_AUXDATA))
@@ -383,12 +383,12 @@ done:
 
 // INT09h : Keyboard Hardware Service Entry Point
 void VISIBLE16
-handle_09(struct bregs *regs)
+handle_09(void)
 {
     if (! CONFIG_PS2PORT)
         return;
 
-    debug_enter(regs, DEBUG_ISR_09);
+    debug_isr(DEBUG_ISR_09);
 
     // read key from keyboard controller
     u8 v = inb(PORT_PS2_STATUS);
diff --git a/src/romlayout.S b/src/romlayout.S
index aadc9cf..8125277 100644
--- a/src/romlayout.S
+++ b/src/romlayout.S
@@ -394,48 +394,35 @@ entry_elf:
 irqentry_extrastack:
         cli
         cld
-        pushw %ds
+        pushw %ds               // Set %ds:%eax to space on ExtraStack
         pushl %eax
         movl $_datalow_seg, %eax
         movl %eax, %ds
         movl StackPos, %eax
-        subl $BREGS_size+12, %eax
-        popl BREGS_eax(%eax)
-        popw BREGS_ds(%eax)
-        movl %edi, BREGS_edi(%eax)
-        movl %esi, BREGS_esi(%eax)
-        movl %ebp, BREGS_ebp(%eax)
-        movl %ebx, BREGS_ebx(%eax)
-        movl %edx, BREGS_edx(%eax)
-        movl %ecx, BREGS_ecx(%eax)
-        movw %es, BREGS_es(%eax)
+        subl $24, %eax
+        popl 0(%eax)            // Backup %eax, %ds, %es, %ecx, %edx
+        popw 4(%eax)
+        movw %es, 6(%eax)
+        movl %ecx, 8(%eax)
         popl %ecx
-        popl BREGS_code(%eax)
-        popw BREGS_flags(%eax)
-
-        movw %ss, BREGS_size+8(%eax)
-        movzwl %sp, %edx
-        movl %edx, BREGS_size+4(%eax)
-        movl %esp, BREGS_size+0(%eax)
-        movw %ds, %dx
+        movl %edx, 12(%eax)
+        movl %esp, 16(%eax)
+        movzwl %sp, %esp
+        movw %ss, 20(%eax)
+
+        movw %ds, %dx           // Setup %ss/%esp and call function
         movw %dx, %ss
         movl %eax, %esp
         calll *%ecx
 
-        movl %esp, %eax
-        movw BREGS_size+8(%eax), %ss
-        movl BREGS_size+0(%eax), %esp
-        movl BREGS_edi(%eax), %edi
-        movl BREGS_esi(%eax), %esi
-        movl BREGS_ebp(%eax), %ebp
-        movl BREGS_ebx(%eax), %ebx
-        movl BREGS_edx(%eax), %edx
-        movl BREGS_ecx(%eax), %ecx
-        movw BREGS_es(%eax), %es
-        pushw BREGS_flags(%eax)
-        pushl BREGS_code(%eax)
-        pushw BREGS_ds(%eax)
-        pushl BREGS_eax(%eax)
+        movl %esp, %eax         // Restore registers and return
+        movw 20(%eax), %ss
+        movl 16(%eax), %esp
+        movl 12(%eax), %edx
+        movl 8(%eax), %ecx
+        movw 6(%eax), %es
+        pushw 4(%eax)
+        pushl 0(%eax)
         popl %eax
         popw %ds
         iretw
diff --git a/src/stacks.c b/src/stacks.c
index 2804e47..9381729 100644
--- a/src/stacks.c
+++ b/src/stacks.c
@@ -74,7 +74,7 @@ stack_hop_back(u32 eax, u32 edx, void *func)
         // Restore original callers' %ss/%esp
         "movl -4(%4), %5\n"
         "movl %5, %%ss\n"
-        "movl %%ds:-8(%4), %%esp\n"
+        "movw %%ds:-8(%4), %%sp\n"
         "movl %5, %%ds\n"
         // Call func
         "calll *%2\n"
diff --git a/src/util.h b/src/util.h
index 39350cc..ba39678 100644
--- a/src/util.h
+++ b/src/util.h
@@ -243,6 +243,7 @@ char * znprintf(size_t size, const char *fmt, ...)
 void __dprintf(const char *fmt, ...)
     __attribute__ ((format (printf, 1, 2)));
 void __debug_enter(struct bregs *regs, const char *fname);
+void __debug_isr(const char *fname);
 void __debug_stub(struct bregs *regs, int lineno, const char *fname);
 void __warn_invalid(struct bregs *regs, int lineno, const char *fname);
 void __warn_unimplemented(struct bregs *regs, int lineno, const char *fname);
@@ -264,6 +265,10 @@ void hexdump(const void *d, int len);
         if ((lvl) && (lvl) <= CONFIG_DEBUG_LEVEL)       \
             __debug_enter((regs), __func__);            \
     } while (0)
+#define debug_isr(lvl) do {                             \
+        if ((lvl) && (lvl) <= CONFIG_DEBUG_LEVEL)       \
+            __debug_isr(__func__);                      \
+    } while (0)
 #define debug_stub(regs)                        \
     __debug_stub((regs), __LINE__, __func__)
 #define warn_invalid(regs)                      \
-- 
1.7.6.5




More information about the SeaBIOS mailing list