aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2012-05-28 14:25:15 -0400
committerKevin O'Connor <kevin@koconnor.net>2012-05-30 21:04:52 -0400
commitecdc655a867480b938652d52a0880853595e2976 (patch)
treebb05ef9488ce19343b805ef246ca95636a6f5fb2
parentbeeabd63df5ad76c74360626549b0be2f6bbad91 (diff)
downloadseabios-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.c1
-rw-r--r--src/clock.c20
-rw-r--r--src/disk.c4
-rw-r--r--src/floppy.c4
-rw-r--r--src/kbd.c14
-rw-r--r--src/misc.c14
-rw-r--r--src/mouse.c57
-rw-r--r--src/output.c9
-rw-r--r--src/ps2port.c8
-rw-r--r--src/romlayout.S60
-rw-r--r--src/stacks.c4
-rw-r--r--src/util.h25
-rwxr-xr-xtools/checkstack.py2
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;
diff --git a/src/disk.c b/src/disk.c
index 080d6cd8..ed54e97d 100644
--- a/src/disk.c
+++ b/src/disk.c
@@ -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;
diff --git a/src/kbd.c b/src/kbd.c
index fdb61d47..586d57eb 100644
--- 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);
}
diff --git a/src/misc.c b/src/misc.c
index 9db49e38..d0d66656 100644
--- a/src/misc.c
+++ b/src/misc.c
@@ -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())
diff --git a/src/util.h b/src/util.h
index a4fabd50..0d41785d 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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']