Reduce stack usage of hw irq handlers.
authorKevin O'Connor <kevin@koconnor.net>
Fri, 2 Jan 2009 02:00:59 +0000 (21:00 -0500)
committerKevin O'Connor <kevin@koconnor.net>
Fri, 2 Jan 2009 02:00:59 +0000 (21:00 -0500)
Avoid using call16_int() -- it consumes too much stack space.
    Instead, use a new function (call16_simpint).  This assumes that
    the handler wont corrupt regs - which should be a safe assumption,
    because if they did corrupt regs they wouldn't work on any bios.
Avoid enabling irqs in the hw irq handlers - there are no loops in the
    handlers that could cause any notable latency.

src/clock.c
src/kbd.c
src/mouse.c
src/system.c
src/util.c
src/util.h

index c76ea75a41c5865665e7bd3c02b8b3ba8dafb96a..caa94badeb58607c5f6aebe709ffc01e76ccfec7 100644 (file)
@@ -411,7 +411,6 @@ void VISIBLE16
 handle_08()
 {
     debug_isr(DEBUG_ISR_08);
-    irq_enable();
 
     floppy_tick();
 
@@ -427,11 +426,8 @@ handle_08()
     SET_BDA(timer_counter, counter);
 
     // chain to user timer tick INT #0x1c
-    struct bregs br;
-    memset(&br, 0, sizeof(br));
-    call16_int(0x1c, &br);
-
-    irq_disable();
+    u32 eax=0, flags;
+    call16_simpint(0x1c, &eax, &flags);
 
     eoi_pic1();
 }
@@ -541,10 +537,8 @@ handle_70()
         goto done;
     if (registerC & 0x20) {
         // Handle Alarm Interrupt.
-        struct bregs br;
-        memset(&br, 0, sizeof(br));
-        call16_int(0x4a, &br);
-        irq_disable();
+        u32 eax=0, flags;
+        call16_simpint(0x4a, &eax, &flags);
     }
     if (!(registerC & 0x40))
         goto done;
index 9c59005661ba70dc8195e7ae0be3eb0f6883ee46..3af70337abac7026888308a536cd72e1d9e179d1 100644 (file)
--- a/src/kbd.c
+++ b/src/kbd.c
@@ -418,7 +418,10 @@ static struct scaninfo {
     { 0x8600, 0x8800, 0x8a00, 0x8c00, none }, /* F12 */
 };
 
-static void
+// Handle a scancode read from the ps2 port.  Note that "noinline" is
+// used to make sure the call to call16_simpint in handle_09 doesn't
+// have the overhead of this function's stack.
+static void noinline
 process_key(u8 scancode)
 {
     u8 shift_flags = GET_BDA(kbd_flag0);
@@ -620,23 +623,17 @@ handle_09()
     }
     u8 key = inb(PORT_PS2_DATA);
 
-    irq_enable();
     if (CONFIG_KBD_CALL_INT15_4F) {
         // allow for keyboard intercept
-        struct bregs tr;
-        memset(&tr, 0, sizeof(tr));
-        tr.al = key;
-        tr.ah = 0x4f;
-        tr.flags = F_CF;
-        call16_int(0x15, &tr);
-        if (!(tr.flags & F_CF))
+        u32 eax = (0x4f << 8) | key;
+        u32 flags;
+        call16_simpint(0x15, &eax, &flags);
+        if (!(flags & F_CF))
             goto done;
-        key = tr.al;
+        key = eax;
     }
     process_key(key);
 
-    irq_disable();
-
 done:
     eoi_pic1();
 }
index 6c74fc1ed515b4fcb63bec4c1cdd07caafa5df4a..65baa20dda212412c7d35005f938dcb05e007e85 100644 (file)
@@ -319,6 +319,8 @@ int74_function()
     SET_EBDA2(ebda_seg, mouse_flag1, 0);
 
     u32 func = GET_EBDA2(ebda_seg, far_call_pointer);
+
+    irq_enable();
     asm volatile(
         "pushl %0\n"
         "pushw %w1\n"  // status
@@ -328,10 +330,11 @@ int74_function()
         "lcallw *8(%%esp)\n"
         "addl $12, %%esp\n"
         "cld\n"
-        : "+a" (func), "+b" (status), "+c" (X), "+d" (Y)
         :
-        : "esi", "edi", "ebp", "cc"
+        : "r"(func), "r"(status), "r"(X), "r"(Y)
+        : "cc"
         );
+    irq_disable();
 }
 
 // INT74h : PS/2 mouse hardware interrupt
@@ -342,9 +345,7 @@ handle_74()
     if (! CONFIG_PS2_MOUSE)
         goto done;
 
-    irq_enable();
     int74_function();
-    irq_disable();
 
 done:
     eoi_pic2();
index 235e88c9eaa1cad051eeea578ebe3c7555030290..47d58174224588e951bcf00a93ca7518ab65a19e 100644 (file)
@@ -399,7 +399,6 @@ handle_75()
     // clear interrupt
     eoi_pic2();
     // legacy nmi call
-    struct bregs br;
-    memset(&br, 0, sizeof(br));
-    call16_int(0x02, &br);
+    u32 eax=0, flags;
+    call16_simpint(0x02, &eax, &flags);
 }
index b94f0d18ecbada2369483c8b8317e15683f107e8..abc1fb246fc76dd03f07dc353264c205c5da47f2 100644 (file)
@@ -48,6 +48,25 @@ __call16_int(struct bregs *callregs, u16 offset)
     call16(callregs);
 }
 
+inline void
+call16_simpint(int nr, u32 *eax, u32 *flags)
+{
+    extern void __force_link_error__call16_simpint_only_in_16bit_mode();
+    if (!MODE16)
+        __force_link_error__call16_simpint_only_in_16bit_mode();
+
+    asm volatile(
+        "stc\n"
+        "int %2\n"
+        "pushfl\n"
+        "popl %1\n"
+        "cld\n"
+        "cli\n"
+        : "+a"(*eax), "=r"(*flags)
+        : "i"(nr)
+        : "cc", "memory");
+}
+
 // Switch to the extra stack in ebda and call a function.
 inline u32
 stack_hop(u32 eax, u32 edx, u32 ecx, void *func)
index 5db1ba0ec0e12273ec4b752b18135ee9317cde89..acd5d0c31a49f71ce6b56bcd11aa7a802ac81151 100644 (file)
@@ -65,11 +65,13 @@ static inline u64 rdtscll(void)
     return val;
 }
 
+// util.c
+inline u32 stack_hop(u32 eax, u32 edx, u32 ecx, void *func);
+u8 checksum(u8 *far_data, u32 len);
 void *memset(void *s, int c, size_t n);
 void *memcpy(void *d1, const void *s1, size_t len);
 void *memcpy_far(void *far_d1, const void *far_s1, size_t len);
 void *memmove(void *d, const void *s, size_t len);
-
 struct bregs;
 inline void call16(struct bregs *callregs);
 inline void call16big(struct bregs *callregs);
@@ -78,6 +80,7 @@ inline void __call16_int(struct bregs *callregs, u16 offset);
         extern void irq_trampoline_ ##nr ();                    \
         __call16_int((callregs), (u32)&irq_trampoline_ ##nr );  \
     } while (0)
+inline void call16_simpint(int nr, u32 *eax, u32 *flags);
 
 // output.c
 void debug_serial_setup();
@@ -137,10 +140,6 @@ void VISIBLE16 handle_1553(struct bregs *regs);
 // pcibios.c
 void handle_1ab1(struct bregs *regs);
 
-// util.c
-inline u32 stack_hop(u32 eax, u32 edx, u32 ecx, void *func);
-u8 checksum(u8 *far_data, u32 len);
-
 // shadow.c
 void make_bios_writable();
 void make_bios_readonly();