X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fstacks.c;h=17f1a4a81915b51fedee507aacc7ba0c8c9a60ad;hb=34203cdf8a89c747e221005850a4558252235360;hp=92d91a0602c6e19997101e73d2464b94b1b60e7e;hpb=a7eb8fcf812c69c32d430b6fc79806256921f75e;p=seabios.git diff --git a/src/stacks.c b/src/stacks.c index 92d91a0..17f1a4a 100644 --- a/src/stacks.c +++ b/src/stacks.c @@ -1,6 +1,6 @@ // Code for manipulating stack locations. // -// Copyright (C) 2009 Kevin O'Connor +// Copyright (C) 2009-2010 Kevin O'Connor // // This file may be distributed under the terms of the GNU LGPLv3 license. @@ -8,11 +8,22 @@ #include "util.h" // dprintf #include "bregs.h" // CR0_PE -static inline u32 getcr0(void) { - u32 cr0; - asm("movl %%cr0, %0" : "=r"(cr0)); - return cr0; -} +// Thread info - stored at bottom of each thread stack - don't change +// without also updating the inline assembler below. +struct thread_info { + struct thread_info *next; + void *stackpos; + struct thread_info **pprev; +}; +struct thread_info VAR32FLATVISIBLE MainThread = { + &MainThread, NULL, &MainThread.next +}; + + +/**************************************************************** + * Low level helpers + ****************************************************************/ + static inline void sgdt(struct descloc_s *desc) { asm("sgdtl %0" : "=m"(*desc)); } @@ -21,14 +32,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 VISIBLE16 +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); @@ -47,14 +58,14 @@ 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 - " 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" + "1:calll *%3\n" + " movl $2f, %%edx\n" " jmp transition16big\n" // Restore ds/ss/esp @@ -62,9 +73,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); @@ -74,7 +85,66 @@ 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. +ASM16( + " .global trampoline_checkirqs\n" + "trampoline_checkirqs:\n" + " rep ; nop\n" + " lretw" + ); + +static void +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; + call16big(&br); +} + +// 16bit trampoline for waiting for an irq from 32bit mode. +ASM16( + " .global trampoline_waitirq\n" + "trampoline_waitirq:\n" + " sti\n" + " hlt\n" + " lretw" + ); + +// Wait for next irq to occur. +void +wait_irq(void) +{ + if (MODESEGMENT) { + asm volatile("sti ; hlt ; cli ; cld": : :"memory"); + return; + } + if (CONFIG_THREADS && MainThread.next != &MainThread) { + // Threads still active - do a yield instead. + yield(); + return; + } + extern void trampoline_waitirq(); + struct bregs br; + br.flags = 0; + br.code.seg = SEG_BIOS; + br.code.offset = (u32)&trampoline_waitirq; + call16big(&br); } @@ -115,27 +185,8 @@ stack_hop(u32 eax, u32 edx, void *func) ****************************************************************/ #define THREADSTACKSIZE 4096 - -// Thread info - stored at bottom of each thread stack - don't change -// without also updating the inline assembler below. -struct thread_info { - struct thread_info *next; - void *stackpos; - struct thread_info **pprev; -}; - -struct thread_info VAR16VISIBLE MainThread; int VAR16VISIBLE CanPreempt; -void -thread_setup(void) -{ - MainThread.next = &MainThread; - MainThread.pprev = &MainThread.next; - MainThread.stackpos = NULL; - CanPreempt = 0; -} - // Return the 'struct thread_info' for the currently running thread. struct thread_info * getCurThread(void) @@ -193,6 +244,8 @@ __end_thread(struct thread_info *old) *old->pprev = old->next; free(old); dprintf(DEBUG_thread, "\\%08x/ End thread\n", (u32)old); + if (MainThread.next == &MainThread) + dprintf(1, "All threads complete.\n"); } // Create a new thread and start executing 'func' in it. @@ -299,7 +352,7 @@ finish_preempt(void) } CanPreempt = 0; releaseRTC(); - dprintf(1, "Done preempt - %d checks\n", PreemptCount); + dprintf(9, "Done preempt - %d checks\n", PreemptCount); yield(); } @@ -315,16 +368,13 @@ wait_preempt(void) return 1; } -extern void yield_preempt(void); -#if MODESEGMENT == 0 // Try to execute 32bit threads. -void VISIBLE32FLAT +void VISIBLE32INIT yield_preempt(void) { PreemptCount++; switch_next(&MainThread); } -#endif // 16bit code that checks if threads are pending and executes them if so. void @@ -332,8 +382,9 @@ check_preempt(void) { if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS || !GET_GLOBAL(CanPreempt) - || GET_GLOBAL(MainThread.next) == &MainThread) + || GET_FLATPTR(MainThread.next) == &MainThread) return; - call32(yield_preempt); + extern void _cfunc32flat_yield_preempt(void); + call32(_cfunc32flat_yield_preempt, 0, 0); }