[SeaBIOS] [PATCH 05/13] Replace 32bit->16bit farcall system with regular calls.
Kevin O'Connor
kevin at koconnor.net
Tue May 29 06:08:25 CEST 2012
Instead of always "far calling" to 16bit mode, use a regular call.
When actually needing to "far call", transition to the 16bit C code
that does far calling. This reduces the overhead to the check_irqs
and wait_irq code.
Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---
src/romlayout.S | 16 ++++----
src/stacks.c | 123 ++++++++++++++++++++++++++++--------------------------
2 files changed, 72 insertions(+), 67 deletions(-)
diff --git a/src/romlayout.S b/src/romlayout.S
index 666f763..676658f 100644
--- a/src/romlayout.S
+++ b/src/romlayout.S
@@ -183,22 +183,22 @@ __farcall16:
retl
-// Far call a 16bit function from 32bit mode.
-// %eax = address of struct bregs
-// Clobbers: %e[bcd]x, %e[ds]i, flags, segment registers, idt/gdt
- DECLFUNC __farcall16_from32
- .global __farcall16big_from32
+// Call a 16bit SeaBIOS function from SeaBIOS 32bit C code.
+// %ebx = calling function
+// Clobbers: %ecx, %edx, flags, segment registers, idt/gdt
+ DECLFUNC __call16
+ .global __call16big
.code32
-__farcall16_from32:
+__call16:
movl $1f, %edx
jmp transition16
-__farcall16big_from32:
+__call16big:
movl $1f, %edx
jmp transition16big
// Make call.
.code16gcc
-1: calll __farcall16
+1: calll *%ebx
// Return via transition32
movl $(2f + BUILD_BIOS_ADDR), %edx
jmp transition32
diff --git a/src/stacks.c b/src/stacks.c
index da5daa9..044d9ea 100644
--- a/src/stacks.c
+++ b/src/stacks.c
@@ -112,39 +112,68 @@ call32(void *func, u32 eax, u32 errret)
return eax;
}
-// Call a function with a specified register state. Note that on
-// return, the interrupt enable/disable flag may be altered.
-inline void
-farcall16(struct bregs *callregs)
+// Call a 16bit SeaBIOS function from a 32bit SeaBIOS function.
+static inline u32
+call16(u32 eax, void *func)
{
- if (!MODESEGMENT && getesp() > BUILD_STACK_ADDR)
+ ASSERT32FLAT();
+ if (getesp() > BUILD_STACK_ADDR)
panic("call16 with invalid stack\n");
asm volatile(
-#if MODE16 == 1
+ "calll __call16"
+ : "+a" (eax)
+ : "b" ((u32)func - BUILD_BIOS_ADDR)
+ : "ecx", "edx", "cc", "memory");
+ return eax;
+}
+
+static inline u32
+call16big(u32 eax, void *func)
+{
+ ASSERT32FLAT();
+ if (getesp() > BUILD_STACK_ADDR)
+ panic("call16big with invalid stack\n");
+ asm volatile(
+ "calll __call16big"
+ : "+a" (eax)
+ : "b" ((u32)func - BUILD_BIOS_ADDR)
+ : "ecx", "edx", "cc", "memory");
+ return eax;
+}
+
+// Far call 16bit code with a specified register state.
+void VISIBLE16
+_farcall16(struct bregs *callregs)
+{
+ ASSERT16();
+ asm volatile(
"calll __farcall16\n"
"cli\n"
"cld"
-#else
- "calll __farcall16_from32"
-#endif
: "+a" (callregs), "+m" (*callregs)
:
: "ebx", "ecx", "edx", "esi", "edi", "cc", "memory");
}
inline void
+farcall16(struct bregs *callregs)
+{
+ if (MODE16) {
+ _farcall16(callregs);
+ return;
+ }
+ extern void _cfunc16__farcall16(void);
+ call16((u32)callregs, _cfunc16__farcall16);
+}
+
+inline void
farcall16big(struct bregs *callregs)
{
- ASSERT32FLAT();
- if (getesp() > BUILD_STACK_ADDR)
- panic("call16 with invalid stack\n");
- asm volatile(
- "calll __farcall16big_from32"
- : "+a" (callregs), "+m" (*callregs)
- :
- : "ebx", "ecx", "edx", "esi", "edi", "cc", "memory");
+ extern void _cfunc16__farcall16(void);
+ call16big((u32)callregs, _cfunc16__farcall16);
}
+// Invoke a 16bit software interrupt.
inline void
__call16_int(struct bregs *callregs, u16 offset)
{
@@ -204,68 +233,48 @@ switch_next(struct thread_info *cur)
: "ebx", "edx", "esi", "edi", "cc", "memory");
}
-// 16bit trampoline for enabling irqs from 32bit mode.
-ASM16(
- " .global trampoline_checkirqs\n"
- "trampoline_checkirqs:\n"
- " rep ; nop\n"
- " lretw"
- );
-
-static void
+// Low-level irq enable.
+void VISIBLE16
check_irqs(void)
{
- if (MODESEGMENT) {
- asm volatile(
- "sti\n"
- "nop\n"
- "rep ; nop\n"
- "cli\n"
- "cld\n"
- : : :"memory");
- return;
- }
- extern void trampoline_checkirqs();
- struct bregs br;
- br.flags = F_IF;
- br.code.seg = SEG_BIOS;
- br.code.offset = (u32)&trampoline_checkirqs;
- farcall16big(&br);
+ asm volatile("sti ; nop ; rep ; nop ; cli ; cld" : : :"memory");
}
// Briefly permit irqs to occur.
void
yield(void)
{
- if (MODESEGMENT || !CONFIG_THREADS) {
+ if (MODESEGMENT) {
// Just directly check irqs.
check_irqs();
return;
}
+ extern void _cfunc16_check_irqs(void);
+ if (!CONFIG_THREADS) {
+ call16big(0, _cfunc16_check_irqs);
+ return;
+ }
struct thread_info *cur = getCurThread();
if (cur == &MainThread)
// Permit irqs to fire
- check_irqs();
+ call16big(0, _cfunc16_check_irqs);
// Switch to the next thread
switch_next(cur);
}
-// 16bit trampoline for waiting for an irq from 32bit mode.
-ASM16(
- " .global trampoline_waitirq\n"
- "trampoline_waitirq:\n"
- " sti\n"
- " hlt\n"
- " lretw"
- );
+void VISIBLE16
+wait_irq(void)
+{
+ asm volatile("sti ; hlt ; cli ; cld": : :"memory");
+}
// Wait for next irq to occur.
void
yield_toirq(void)
{
if (MODESEGMENT) {
- asm volatile("sti ; hlt ; cli ; cld": : :"memory");
+ wait_irq();
return;
}
if (CONFIG_THREADS && MainThread.next != &MainThread) {
@@ -273,12 +282,8 @@ yield_toirq(void)
yield();
return;
}
- extern void trampoline_waitirq();
- struct bregs br;
- br.flags = 0;
- br.code.seg = SEG_BIOS;
- br.code.offset = (u32)&trampoline_waitirq;
- farcall16big(&br);
+ extern void _cfunc16_wait_irq(void);
+ call16big(0, _cfunc16_wait_irq);
}
// Last thing called from a thread (called on "next" stack).
--
1.7.6.5
More information about the SeaBIOS
mailing list