From 2f898d5eae41c7bec54ab60c3ea25f200d46728d Mon Sep 17 00:00:00 2001 From: Kevin O'Connor Date: Mon, 28 May 2012 10:56:20 -0400 Subject: [PATCH] Replace 32bit->16bit farcall system with regular calls. 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 --- 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). -- 2.39.5