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@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).