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@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) \
Maybe it should be documented to prevent this bug from being re-introduced in the future.
Maybe a comment in the code so developers don't get confused.
On Sun, Jun 3, 2012 at 2:40 AM, Kevin O'Connor kevin@koconnor.net wrote:
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@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
SeaBIOS mailing list SeaBIOS@seabios.org http://www.seabios.org/mailman/listinfo/seabios