diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2012-05-28 14:25:15 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2012-05-30 21:04:52 -0400 |
commit | ecdc655a867480b938652d52a0880853595e2976 (patch) | |
tree | bb05ef9488ce19343b805ef246ca95636a6f5fb2 | |
parent | beeabd63df5ad76c74360626549b0be2f6bbad91 (diff) | |
download | seabios-ecdc655a867480b938652d52a0880853595e2976.tar.gz |
Run all hardware irq handlers on the extra stack.
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>
-rw-r--r-- | src/asm-offsets.c | 1 | ||||
-rw-r--r-- | src/clock.c | 20 | ||||
-rw-r--r-- | src/disk.c | 4 | ||||
-rw-r--r-- | src/floppy.c | 4 | ||||
-rw-r--r-- | src/kbd.c | 14 | ||||
-rw-r--r-- | src/misc.c | 14 | ||||
-rw-r--r-- | src/mouse.c | 57 | ||||
-rw-r--r-- | src/output.c | 9 | ||||
-rw-r--r-- | src/ps2port.c | 8 | ||||
-rw-r--r-- | src/romlayout.S | 60 | ||||
-rw-r--r-- | src/stacks.c | 4 | ||||
-rw-r--r-- | src/util.h | 25 | ||||
-rwxr-xr-x | tools/checkstack.py | 2 |
13 files changed, 127 insertions, 95 deletions
diff --git a/src/asm-offsets.c b/src/asm-offsets.c index b98f3b5a..576bf343 100644 --- a/src/asm-offsets.c +++ b/src/asm-offsets.c @@ -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)); } diff --git a/src/clock.c b/src/clock.c index 97d53011..55dde2e8 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(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; @@ -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(); } diff --git a/src/floppy.c b/src/floppy.c index 72bc79b8..5400bb02 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(void) +handle_0e(struct bregs *regs) { - debug_isr(DEBUG_ISR_0e); + debug_enter(regs, DEBUG_ISR_0e); if (! CONFIG_FLOPPY) goto done; @@ -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); } @@ -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); } diff --git a/src/mouse.c b/src/mouse.c index 237c8ff9..93e4ed28 100644 --- a/src/mouse.c +++ b/src/mouse.c @@ -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); +} diff --git a/src/output.c b/src/output.c index 37c4942e..1fe5d919 100644 --- a/src/output.c +++ b/src/output.c @@ -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) diff --git a/src/ps2port.c b/src/ps2port.c index 15bce8ed..c835e14f 100644 --- a/src/ps2port.c +++ b/src/ps2port.c @@ -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); diff --git a/src/romlayout.S b/src/romlayout.S index 147cd3bd..aadc9cf2 100644 --- a/src/romlayout.S +++ b/src/romlayout.S @@ -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 diff --git a/src/stacks.c b/src/stacks.c index cfdd68de..2804e478 100644 --- a/src/stacks.c +++ b/src/stacks.c @@ -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()) @@ -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) \ diff --git a/tools/checkstack.py b/tools/checkstack.py index 717de2d4..23b7c8ed 100755 --- a/tools/checkstack.py +++ b/tools/checkstack.py @@ -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'] |