X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Fstacks.c;h=17f1a4a81915b51fedee507aacc7ba0c8c9a60ad;hb=34203cdf8a89c747e221005850a4558252235360;hp=4a30b3d82ebb43471c5546b972430718d6880bfa;hpb=d7eb27efa3f9265dca8357cfa05d9e0560fd4534;p=seabios.git diff --git a/src/stacks.c b/src/stacks.c index 4a30b3d..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); @@ -40,7 +51,6 @@ call32(void *func) struct descloc_s gdt; sgdt(&gdt); - func -= BUILD_BIOS_ADDR; u32 bkup_ss, bkup_esp; asm volatile( // Backup ss/esp / set esp to flat stack location @@ -48,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 @@ -63,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) - : "m" (*(u8*)func) - : "eax", "ecx", "edx", "cc", "memory"); + : "=&r" (bkup_ss), "=&r" (bkup_esp), "+a" (eax) + : "r" (func) + : "ecx", "edx", "cc", "memory"); // Restore gdt and fs/gs lgdt(&gdt); @@ -75,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); } @@ -85,7 +154,7 @@ call32(void *func) // Switch to the extra stack in ebda and call a function. inline u32 -stack_hop(u32 eax, u32 edx, u32 ecx, void *func) +stack_hop(u32 eax, u32 edx, void *func) { ASSERT16(); u16 ebda_seg = get_ebda_seg(), bkup_ss; @@ -99,13 +168,13 @@ stack_hop(u32 eax, u32 edx, u32 ecx, void *func) "movw %w6, %%ss\n" "movl %5, %%esp\n" // Call func - "calll %7\n" + "calll *%2\n" // Restore segments and stack "movw %w3, %%ds\n" "movw %w3, %%ss\n" "movl %4, %%esp" - : "+a" (eax), "+d" (edx), "+c" (ecx), "=&r" (bkup_ss), "=&r" (bkup_esp) - : "i" (EBDA_OFFSET_TOP_STACK), "r" (ebda_seg), "m" (*(u8*)func) + : "+a" (eax), "+d" (edx), "+c" (func), "=&r" (bkup_ss), "=&r" (bkup_esp) + : "i" (EBDA_OFFSET_TOP_STACK), "r" (ebda_seg) : "cc", "memory"); return eax; } @@ -116,23 +185,8 @@ stack_hop(u32 eax, u32 edx, u32 ecx, void *func) ****************************************************************/ #define THREADSTACKSIZE 4096 - -struct thread_info { - struct thread_info *next; - void *stackpos; -}; - -struct thread_info VAR16VISIBLE MainThread; int VAR16VISIBLE CanPreempt; -void -thread_setup(void) -{ - MainThread.next = &MainThread; - MainThread.stackpos = NULL; - CanPreempt = 0; -} - // Return the 'struct thread_info' for the currently running thread. struct thread_info * getCurThread(void) @@ -186,12 +240,12 @@ yield(void) static void __end_thread(struct thread_info *old) { - struct thread_info *pos = &MainThread; - while (pos->next != old) - pos = pos->next; - pos->next = old->next; + old->next->pprev = old->pprev; + *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. @@ -208,8 +262,10 @@ run_thread(void (*func)(void*), void *data) thread->stackpos = (void*)thread + THREADSTACKSIZE; struct thread_info *cur = getCurThread(); - thread->next = cur->next; - cur->next = thread; + thread->next = cur; + thread->pprev = cur->pprev; + cur->pprev = &thread->next; + *thread->pprev = thread; dprintf(DEBUG_thread, "/%08x\\ Start thread\n", (u32)thread); asm volatile( @@ -290,11 +346,14 @@ start_preempt(void) void finish_preempt(void) { - if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS) + if (! CONFIG_THREADS || ! CONFIG_THREAD_OPTIONROMS) { + yield(); return; + } CanPreempt = 0; releaseRTC(); - dprintf(1, "Done preempt - %d checks\n", PreemptCount); + dprintf(9, "Done preempt - %d checks\n", PreemptCount); + yield(); } // Check if preemption is on, and wait for it to complete if so. @@ -309,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 @@ -326,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); }