Fix call32() so that it doesn't require %ss==0, and enable it to pass a parameter.
-Kevin
Kevin O'Connor (2): Don't pass return address to transition(32,16,16big) on stack. Enhance call32() to pass a parameter to called function.
src/entryfuncs.S | 2 +- src/resume.c | 2 +- src/romlayout.S | 14 ++++++++++---- src/stacks.c | 22 +++++++++++----------- src/util.h | 1 + 5 files changed, 24 insertions(+), 17 deletions(-)
It's difficult to have a uniform view of the stack when transition modes, so pass the return address in a register. As a result, the transition functions only access memory via the %cs selector now. --- src/entryfuncs.S | 2 +- src/resume.c | 2 +- src/romlayout.S | 14 ++++++++++---- src/stacks.c | 4 ++-- 4 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/src/entryfuncs.S b/src/entryfuncs.S index 3c29b3f..afc5e61 100644 --- a/src/entryfuncs.S +++ b/src/entryfuncs.S @@ -156,7 +156,7 @@ xorw %ax, %ax movw %ax, %ss movl $ BUILD_STACK_ADDR , %esp - pushl $ \cfunc + movl $ \cfunc , %edx jmp transition32 .endm
diff --git a/src/resume.c b/src/resume.c index 81ad1ac..2a743c9 100644 --- a/src/resume.c +++ b/src/resume.c @@ -40,7 +40,7 @@ handle_resume(u8 status) asm volatile( "movw %w1, %%ss\n" "movl %0, %%esp\n" - "pushl $s3_resume\n" + "movl $s3_resume, %%edx\n" "jmp transition32\n" : : "i"(BUILD_S3RESUME_STACK_ADDR), "r"(0) ); diff --git a/src/romlayout.S b/src/romlayout.S index a469596..d83f337 100644 --- a/src/romlayout.S +++ b/src/romlayout.S @@ -26,6 +26,7 @@ ****************************************************************/
// Place CPU into 32bit mode from 16bit mode. +// %edx = return location (in 32bit mode) // Clobbers: ecx, flags, segment registers, cr0, idt/gdt DECLFUNC transition32 transition32: @@ -68,9 +69,10 @@ transition32: movw %ax, %gs
movl %ecx, %eax - retl + jmpl *%edx
// Place CPU into 16bit mode from 32bit mode. +// %edx = return location (in 16bit mode) // Clobbers: ecx, flags, segment registers, cr0, idt/gdt DECLFUNC transition16 .global transition16big @@ -130,7 +132,7 @@ transition16big: movw %ax, %ss // Assume stack is in segment 0
movl %ecx, %eax - retl + jmpl *%edx
// Call a 16bit function from 16bit mode with a specified cpu register state // %eax = address of struct bregs @@ -195,18 +197,22 @@ __call16: .global __call16big_from32 .code32 __call16_from32: - pushl $1f + movl $1f, %edx jmp transition16 __call16big_from32: - pushl $1f + movl $1f, %edx jmp transition16big
// Make call. .code16gcc 1: calll __call16 // Return via transition32 + movl $(2f + BUILD_BIOS_ADDR), %edx jmp transition32 + .code32 +2: retl
+ .code16gcc // IRQ trampolines .macro IRQ_TRAMPOLINE num DECLFUNC irq_trampoline_0x\num diff --git a/src/stacks.c b/src/stacks.c index 14f6f8a..a68d37c 100644 --- a/src/stacks.c +++ b/src/stacks.c @@ -66,11 +66,11 @@ call32(void *func) " movl %%ss, %0\n"
// Transition to 32bit mode, call func, return to 16bit - " pushl $(" __stringify(BUILD_BIOS_ADDR) " + 1f)\n" + " movl $(" __stringify(BUILD_BIOS_ADDR) " + 1f), %%edx\n" " jmp transition32\n" " .code32\n" "1:calll *%2\n" - " pushl $2f\n" + " movl $2f, %%edx\n" " jmp transition16big\n"
// Restore ds/ss/esp
Support passing a parameter to the 32bit function, as well as returning the result of the function back to the 16bit code.
Also, make call32 available outside of stacks.c. --- src/stacks.c | 18 +++++++++--------- src/util.h | 1 + 2 files changed, 10 insertions(+), 9 deletions(-)
diff --git a/src/stacks.c b/src/stacks.c index a68d37c..c77ba1f 100644 --- a/src/stacks.c +++ b/src/stacks.c @@ -37,14 +37,14 @@ static inline void lgdt(struct descloc_s *desc) { }
// Call a 32bit SeaBIOS function from a 16bit SeaBIOS function. -static inline int -call32(void *func) +u32 +call32(void *func, u32 eax, u32 errret) { ASSERT16(); u32 cr0 = getcr0(); if (cr0 & CR0_PE) // Called in 16bit protected mode?! - return -1; + return errret;
// Backup cmos index register and disable nmi u8 cmosindex = inb(PORT_CMOS_INDEX); @@ -63,13 +63,13 @@ call32(void *func) " movl %%esp, %1\n" " shll $4, %0\n" " addl %0, %%esp\n" - " movl %%ss, %0\n" + " shrl $4, %0\n"
// Transition to 32bit mode, call func, return to 16bit " movl $(" __stringify(BUILD_BIOS_ADDR) " + 1f), %%edx\n" " jmp transition32\n" " .code32\n" - "1:calll *%2\n" + "1:calll *%3\n" " movl $2f, %%edx\n" " jmp transition16big\n"
@@ -78,9 +78,9 @@ call32(void *func) "2:movl %0, %%ds\n" " movl %0, %%ss\n" " movl %1, %%esp\n" - : "=&r" (bkup_ss), "=&r" (bkup_esp) + : "=&r" (bkup_ss), "=&r" (bkup_esp), "+a" (eax) : "r" (func) - : "eax", "ecx", "edx", "cc", "memory"); + : "ecx", "edx", "cc", "memory");
// Restore gdt and fs/gs lgdt(&gdt); @@ -90,7 +90,7 @@ call32(void *func) // Restore cmos index register outb(cmosindex, PORT_CMOS_INDEX); inb(PORT_CMOS_DATA); - return 0; + return eax; }
// 16bit trampoline for enabling irqs from 32bit mode. @@ -393,5 +393,5 @@ check_preempt(void) || GET_FLATPTR(MainThread.next) == &MainThread) return;
- call32(yield_preempt); + call32(yield_preempt, 0, 0); } diff --git a/src/util.h b/src/util.h index 18ab814..e513e84 100644 --- a/src/util.h +++ b/src/util.h @@ -211,6 +211,7 @@ char *strtcpy(char *dest, const char *src, size_t len); int get_keystroke(int msec);
// stacks.c +u32 call32(void *func, u32 eax, u32 errret); inline u32 stack_hop(u32 eax, u32 edx, void *func); extern struct thread_info MainThread; struct thread_info *getCurThread(void);
On 11/25/10 15:23, Kevin O'Connor wrote:
Fix call32() so that it doesn't require %ss==0, and enable it to pass a parameter.
Patches look good to me. Also tested with the ahci driver, works fine.
Acked-by: Gerd Hoffmann kraxel@redhat.com
cheers, Gerd