]> xenbits.xensource.com Git - seabios.git/commitdiff
Run all hardware irq handlers on the extra stack.
authorKevin O'Connor <kevin@koconnor.net>
Mon, 28 May 2012 18:25:15 +0000 (14:25 -0400)
committerKevin O'Connor <kevin@koconnor.net>
Thu, 31 May 2012 01:04:52 +0000 (21:04 -0400)
Jump into the extra stack for all hardware irq handlers.  This reduces
the overall stack requirements of SeaBIOS.

Replace all users of call16_simpint with call16_int.  Only the
hardware irq handlers used the old call, and they need to use the new
call to ensure the extra stack is properly re-entrant.

Also, pass in a 'struct bregs' to the hardware irq handlers now.  It
was not done previously to save stack space.  Now that the extra stack
is used, that is no longer an issue.

Note that should an old OS invoke a hardware irq in 16bit protected
mode, then this patch could break that OS.  However, the chances of
this causing a regression seem small as several existing hardware irq
handlers already do not work in 16bit protected mode.

Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
13 files changed:
src/asm-offsets.c
src/clock.c
src/disk.c
src/floppy.c
src/kbd.c
src/misc.c
src/mouse.c
src/output.c
src/ps2port.c
src/romlayout.S
src/stacks.c
src/util.h
tools/checkstack.py

index b98f3b5a87c510ac46f16fdd2bdd13e731ad5ac9..576bf343f7f0e94a5d7da4a4b79fb3ba076e36f2 100644 (file)
@@ -20,4 +20,5 @@ void foo(void)
     OFFSET(BREGS_edi, bregs, edi);
     OFFSET(BREGS_flags, bregs, flags);
     OFFSET(BREGS_code, bregs, code);
+    DEFINE(BREGS_size, sizeof(struct bregs));
 }
index 97d530115963cf4849e39b39cd4833bcfb87c3e9..55dde2e88569efeb4373e26c07d137af6fb702d4 100644 (file)
@@ -516,9 +516,9 @@ handle_1a(struct bregs *regs)
 
 // INT 08h System Timer ISR Entry Point
 void VISIBLE16
-handle_08(void)
+handle_08(struct bregs *regs)
 {
-    debug_isr(DEBUG_ISR_08);
+    debug_enter(regs, DEBUG_ISR_08);
 
     floppy_tick();
 
@@ -536,8 +536,10 @@ handle_08(void)
     usb_check_event();
 
     // chain to user timer tick INT #0x1c
-    u32 eax=0, flags;
-    call16_simpint(0x1c, &eax, &flags);
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.flags = F_IF;
+    call16_int(0x1c, &br);
 
     eoi_pic1();
 }
@@ -657,9 +659,9 @@ handle_1583(struct bregs *regs)
 
 // int70h: IRQ8 - CMOS RTC
 void VISIBLE16
-handle_70(void)
+handle_70(struct bregs *regs)
 {
-    debug_isr(DEBUG_ISR_70);
+    debug_enter(regs, DEBUG_ISR_70);
 
     // Check which modes are enabled and have occurred.
     u8 registerB = inb_cmos(CMOS_STATUS_B);
@@ -669,8 +671,10 @@ handle_70(void)
         goto done;
     if (registerC & RTC_B_AIE) {
         // Handle Alarm Interrupt.
-        u32 eax=0, flags;
-        call16_simpint(0x4a, &eax, &flags);
+        struct bregs br;
+        memset(&br, 0, sizeof(br));
+        br.flags = F_IF;
+        call16_int(0x4a, &br);
     }
     if (!(registerC & RTC_B_PIE))
         goto done;
index 080d6cd8ece3c2f8c434e8e7b1f5c64f5f1591e7..ed54e97de195b5d9edc048818c1ebb2426cf2575 100644 (file)
@@ -883,9 +883,9 @@ handle_13(struct bregs *regs)
 
 // record completion in BIOS task complete flag
 void VISIBLE16
-handle_76(void)
+handle_76(struct bregs *regs)
 {
-    debug_isr(DEBUG_ISR_76);
+    debug_enter(regs, DEBUG_ISR_76);
     SET_BDA(disk_interrupt_flag, 0xff);
     eoi_pic2();
 }
index 72bc79b8f4984638e0d63e04f9acbf4c407d3328..5400bb02224f0eff37bb384b977290fc87435ad6 100644 (file)
@@ -582,9 +582,9 @@ process_floppy_op(struct disk_op_s *op)
 
 // INT 0Eh Diskette Hardware ISR Entry Point
 void VISIBLE16
-handle_0e(void)
+handle_0e(struct bregs *regs)
 {
-    debug_isr(DEBUG_ISR_0e);
+    debug_enter(regs, DEBUG_ISR_0e);
     if (! CONFIG_FLOPPY)
         goto done;
 
index fdb61d4729a05e3bec286600ced18e245e055519..586d57eb1db6fd1cf5557a1f8a4ea82680e891f5 100644 (file)
--- a/src/kbd.c
+++ b/src/kbd.c
@@ -379,7 +379,7 @@ static struct scaninfo {
 };
 
 // Handle a scancode read from the ps2 port.  Note that "noinline" is
-// used to make sure the call to call16_simpint in process_key doesn't
+// used to make sure the call to call16_int in process_key doesn't
 // have the overhead of this function's stack.
 static void noinline
 __process_key(u8 scancode)
@@ -562,12 +562,14 @@ process_key(u8 key)
 
     if (CONFIG_KBD_CALL_INT15_4F) {
         // allow for keyboard intercept
-        u32 eax = (0x4f << 8) | key;
-        u32 flags;
-        call16_simpint(0x15, &eax, &flags);
-        if (!(flags & F_CF))
+        struct bregs br;
+        memset(&br, 0, sizeof(br));
+        br.eax = (0x4f << 8) | key;
+        br.flags = F_IF|F_CF;
+        call16_int(0x15, &br);
+        if (!(br.flags & F_CF))
             return;
-        key = eax;
+        key = br.eax;
     }
     __process_key(key);
 }
index 9db49e3820c3f7bde31be04f306d649bd99ac424..d0d66656069a922a2e22071ac0b0f8e10bcabee0 100644 (file)
@@ -55,9 +55,9 @@ handle_10(struct bregs *regs)
 
 // NMI handler
 void VISIBLE16
-handle_02(void)
+handle_02(struct bregs *regs)
 {
-    debug_isr(DEBUG_ISR_02);
+    debug_enter(regs, DEBUG_ISR_02);
 }
 
 void
@@ -71,17 +71,19 @@ mathcp_setup(void)
 
 // INT 75 - IRQ13 - MATH COPROCESSOR EXCEPTION
 void VISIBLE16
-handle_75(void)
+handle_75(struct bregs *regs)
 {
-    debug_isr(DEBUG_ISR_75);
+    debug_enter(regs, DEBUG_ISR_75);
 
     // clear irq13
     outb(0, PORT_MATH_CLEAR);
     // clear interrupt
     eoi_pic2();
     // legacy nmi call
-    u32 eax=0, flags;
-    call16_simpint(0x02, &eax, &flags);
+    struct bregs br;
+    memset(&br, 0, sizeof(br));
+    br.flags = F_IF;
+    call16_int(0x02, &br);
 }
 
 
index 237c8ff943a7fe3a0bc93204b2e2d8e2660b4580..93e4ed2872f89aef28a89651a09bce13add399b8 100644 (file)
@@ -6,8 +6,7 @@
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
 #include "biosvar.h" // GET_EBDA
-#include "util.h" // debug_isr
-#include "pic.h" // eoi_pic2
+#include "util.h" // dprintf
 #include "bregs.h" // struct bregs
 #include "ps2port.h" // ps2_mouse_command
 #include "usb-hid.h" // usb_mouse_command
@@ -273,34 +272,12 @@ handle_15c2(struct bregs *regs)
     }
 }
 
-void noinline
-process_mouse(u8 data)
+static void
+invoke_mouse_handler(u16 ebda_seg)
 {
-    if (!CONFIG_MOUSE)
-        return;
-
-    u16 ebda_seg = get_ebda_seg();
-    u8 mouse_flags_1 = GET_EBDA(ebda_seg, mouse_flag1);
-    u8 mouse_flags_2 = GET_EBDA(ebda_seg, mouse_flag2);
-
-    if (! (mouse_flags_2 & 0x80))
-        // far call handler not installed
-        return;
-
-    u8 package_count = mouse_flags_2 & 0x07;
-    u8 index = mouse_flags_1 & 0x07;
-    SET_EBDA(ebda_seg, mouse_data[index], data);
-
-    if ((index+1) < package_count) {
-        mouse_flags_1++;
-        SET_EBDA(ebda_seg, mouse_flag1, mouse_flags_1);
-        return;
-    }
-
     u16 status = GET_EBDA(ebda_seg, mouse_data[0]);
     u16 X      = GET_EBDA(ebda_seg, mouse_data[1]);
     u16 Y      = GET_EBDA(ebda_seg, mouse_data[2]);
-    SET_EBDA(ebda_seg, mouse_flag1, 0);
 
     struct segoff_s func = GET_EBDA(ebda_seg, far_call_pointer);
     dprintf(16, "mouse farcall s=%04x x=%04x y=%04x func=%04x:%04x\n"
@@ -325,3 +302,31 @@ process_mouse(u8 data)
         :
         : "edi", "esi", "cc", "memory");
 }
+
+void noinline
+process_mouse(u8 data)
+{
+    if (!CONFIG_MOUSE)
+        return;
+
+    u16 ebda_seg = get_ebda_seg();
+    u8 mouse_flags_1 = GET_EBDA(ebda_seg, mouse_flag1);
+    u8 mouse_flags_2 = GET_EBDA(ebda_seg, mouse_flag2);
+
+    if (! (mouse_flags_2 & 0x80))
+        // far call handler not installed
+        return;
+
+    u8 package_count = mouse_flags_2 & 0x07;
+    u8 index = mouse_flags_1 & 0x07;
+    SET_EBDA(ebda_seg, mouse_data[index], data);
+
+    if ((index+1) < package_count) {
+        mouse_flags_1++;
+        SET_EBDA(ebda_seg, mouse_flag1, mouse_flags_1);
+        return;
+    }
+
+    SET_EBDA(ebda_seg, mouse_flag1, 0);
+    stack_hop_back(ebda_seg, 0, invoke_mouse_handler);
+}
index 37c4942eddd482828694865d021ff61547359d3f..1fe5d919fc57997110a68ad0e0e28136c2fa8d5e 100644 (file)
@@ -487,15 +487,6 @@ 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)
index 15bce8ed8f3a9126e66efd4938bd5f98bae3e575..c835e14f84367f30c5a9370ee5919a187b6d77d2 100644 (file)
@@ -357,12 +357,12 @@ ps2_mouse_command(int command, u8 *param)
 
 // INT74h : PS/2 mouse hardware interrupt
 void VISIBLE16
-handle_74(void)
+handle_74(struct bregs *regs)
 {
     if (! CONFIG_PS2PORT)
         return;
 
-    debug_isr(DEBUG_ISR_74);
+    debug_enter(regs, DEBUG_ISR_74);
 
     u8 v = inb(PORT_PS2_STATUS);
     if ((v & (I8042_STR_OBF|I8042_STR_AUXDATA))
@@ -384,12 +384,12 @@ done:
 
 // INT09h : Keyboard Hardware Service Entry Point
 void VISIBLE16
-handle_09(void)
+handle_09(struct bregs *regs)
 {
     if (! CONFIG_PS2PORT)
         return;
 
-    debug_isr(DEBUG_ISR_09);
+    debug_enter(regs, DEBUG_ISR_09);
 
     // read key from keyboard controller
     u8 v = inb(PORT_PS2_STATUS);
index 147cd3bd68cccda71b06e87001e05ceb33b50207..aadc9cf2a66fedeee09163ac88d27819b4bf8bc4 100644 (file)
@@ -219,12 +219,15 @@ __call16big:
         lretw
         .endm
 
+        IRQ_TRAMPOLINE 02
         IRQ_TRAMPOLINE 10
         IRQ_TRAMPOLINE 13
         IRQ_TRAMPOLINE 15
         IRQ_TRAMPOLINE 16
         IRQ_TRAMPOLINE 18
         IRQ_TRAMPOLINE 19
+        IRQ_TRAMPOLINE 1c
+        IRQ_TRAMPOLINE 4a
 
 
 /****************************************************************
@@ -386,10 +389,55 @@ entry_elf:
  * Interrupt entry points
  ****************************************************************/
 
-        // Main entry point for interrupts without args
-        DECLFUNC irqentry
-irqentry:
-        ENTRY_ST
+        // Main entry point for interrupts handled on extra stack
+        DECLFUNC irqentry_extrastack
+irqentry_extrastack:
+        cli
+        cld
+        pushw %ds
+        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)
+        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
+        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)
+        popl %eax
+        popw %ds
         iretw
 
         // Main entry point for interrupts with args
@@ -398,12 +446,12 @@ irqentryarg:
         ENTRY_ARG_ST
         iretw
 
-        // Define an entry point for an interrupt (no args passed).
+        // Define an entry point for hardware interrupts.
         .macro IRQ_ENTRY num
         .global entry_\num
         entry_\num :
         pushl $ handle_\num
-        jmp irqentry
+        jmp irqentry_extrastack
         .endm
 
         .macro DECL_IRQ_ENTRY num
index cfdd68de54059fc52de64c3af814cceacc06fbfb..2804e478c60ec14228f1489c4953b53c6e0366a3 100644 (file)
@@ -25,7 +25,7 @@ on_extra_stack(void)
 }
 
 // Switch to the extra stack and call a function.
-inline u32
+u32
 stack_hop(u32 eax, u32 edx, void *func)
 {
     if (on_extra_stack())
@@ -58,7 +58,7 @@ stack_hop(u32 eax, u32 edx, void *func)
 }
 
 // Switch back to original caller's stack and call a function.
-static u32
+u32
 stack_hop_back(u32 eax, u32 edx, void *func)
 {
     if (!on_extra_stack())
index a4fabd50102499ef9d055972878f3d4937d8306f..0d41785d89a6f15b505ed201f102b8b6d88cc38f 100644 (file)
@@ -159,23 +159,6 @@ static inline u8 readb(const void *addr) {
     return *(volatile const u8 *)addr;
 }
 
-#define call16_simpint(nr, peax, pflags) do {                           \
-        ASSERT16();                                                     \
-        asm volatile(                                                   \
-            "pushl %%ebp\n"                                             \
-            "sti\n"                                                     \
-            "stc\n"                                                     \
-            "int %2\n"                                                  \
-            "pushfl\n"                                                  \
-            "popl %1\n"                                                 \
-            "cli\n"                                                     \
-            "cld\n"                                                     \
-            "popl %%ebp"                                                \
-            : "+a"(*peax), "=c"(*pflags)                                \
-            : "i"(nr)                                                   \
-            : "ebx", "edx", "esi", "edi", "cc", "memory");              \
-    } while (0)
-
 // GDT bits
 #define GDT_CODE     (0x9bULL << 40) // Code segment - P,R,A bits also set
 #define GDT_DATA     (0x93ULL << 40) // Data segment - W,A bits also set
@@ -222,7 +205,8 @@ int get_keystroke(int msec);
 
 // stacks.c
 extern u8 ExtraStack[], *StackPos;
-inline u32 stack_hop(u32 eax, u32 edx, void *func);
+u32 stack_hop(u32 eax, u32 edx, void *func);
+u32 stack_hop_back(u32 eax, u32 edx, void *func);
 u32 call32(void *func, u32 eax, u32 errret);
 struct bregs;
 inline void farcall16(struct bregs *callregs);
@@ -260,7 +244,6 @@ 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);
@@ -282,10 +265,6 @@ 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)                      \
index 717de2d48cc70930e79ac240387b5dfd8f1aad6c..23b7c8edbcd63db998fd0234f82c1aa2bf83b4ad 100755 (executable)
@@ -13,7 +13,7 @@ import sys
 import re
 
 # Functions that change stacks
-STACKHOP = ['__send_disk_op']
+STACKHOP = ['stack_hop', 'stack_hop_back']
 # List of functions we can assume are never called.
 #IGNORE = ['panic', '__dprintf']
 IGNORE = ['panic']