diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/stacks.c | 163 | ||||
-rw-r--r-- | src/util.c | 195 | ||||
-rw-r--r-- | src/util.h | 45 |
3 files changed, 206 insertions, 197 deletions
diff --git a/src/stacks.c b/src/stacks.c new file mode 100644 index 0000000..d71381f --- /dev/null +++ b/src/stacks.c @@ -0,0 +1,163 @@ +// Code for manipulating stack locations. +// +// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net> +// +// This file may be distributed under the terms of the GNU LGPLv3 license. + +#include "biosvar.h" // get_ebda_seg +#include "util.h" // dprintf + + +/**************************************************************** + * Stack in EBDA + ****************************************************************/ + +// Switch to the extra stack in ebda and call a function. +inline u32 +stack_hop(u32 eax, u32 edx, u32 ecx, void *func) +{ + ASSERT16(); + u16 ebda_seg = get_ebda_seg(), bkup_ss; + u32 bkup_esp; + asm volatile( + // Backup current %ss/%esp values. + "movw %%ss, %w3\n" + "movl %%esp, %4\n" + // Copy ebda seg to %ds/%ss and set %esp + "movw %w6, %%ds\n" + "movw %w6, %%ss\n" + "movl %5, %%esp\n" + // Call func + "calll %7\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) + : "cc", "memory"); + return eax; +} + + +/**************************************************************** + * Threads + ****************************************************************/ + +#define THREADSTACKSIZE 4096 + +struct thread_info { + struct thread_info *next; + void *stackpos; +}; + +struct thread_info MainThread; + +void +thread_setup() +{ + MainThread.next = &MainThread; + MainThread.stackpos = NULL; +} + +struct thread_info * +getCurThread() +{ + u32 esp = getesp(); + if (esp <= BUILD_STACK_ADDR) + return &MainThread; + return (void*)ALIGN_DOWN(esp, THREADSTACKSIZE); +} + +// Briefly permit irqs to occur. +void +yield() +{ + if (MODE16 || !CONFIG_THREADS) { + // Just directly check irqs. + check_irqs(); + return; + } + struct thread_info *cur = getCurThread(); + if (cur == &MainThread) + // Permit irqs to fire + check_irqs(); + + // Switch to the next thread + struct thread_info *next = cur->next; + asm volatile( + " pushl $1f\n" // store return pc + " pushl %%ebp\n" // backup %ebp + " movl %%esp, 4(%%eax)\n" // cur->stackpos = %esp + " movl 4(%%ecx), %%esp\n" // %esp = next->stackpos + " popl %%ebp\n" // restore %ebp + " retl\n" // restore pc + "1:\n" + : "+a"(cur), "+c"(next) + : + : "ebx", "edx", "esi", "edi", "cc", "memory"); +} + +// Last thing called from a thread (called on "next" stack). +static void +__end_thread(struct thread_info *old) +{ + struct thread_info *pos = &MainThread; + while (pos->next != old) + pos = pos->next; + pos->next = old->next; + free(old); + dprintf(DEBUG_thread, "\\%08x/ End thread\n", (u32)old); +} + +void +run_thread(void (*func)(void*), void *data) +{ + ASSERT32(); + if (! CONFIG_THREADS) + goto fail; + struct thread_info *thread; + thread = memalign_tmphigh(THREADSTACKSIZE, THREADSTACKSIZE); + if (!thread) + goto fail; + + thread->stackpos = (void*)thread + THREADSTACKSIZE; + struct thread_info *cur = getCurThread(); + thread->next = cur->next; + cur->next = thread; + + dprintf(DEBUG_thread, "/%08x\\ Start thread\n", (u32)thread); + asm volatile( + // Start thread + " pushl $1f\n" // store return pc + " pushl %%ebp\n" // backup %ebp + " movl %%esp, 4(%%edx)\n" // cur->stackpos = %esp + " movl 4(%%ebx), %%esp\n" // %esp = thread->stackpos + " calll *%%ecx\n" // Call func + + // End thread + " movl (%%ebx), %%ecx\n" // %ecx = thread->next + " movl 4(%%ecx), %%esp\n" // %esp = next->stackpos + " movl %%ebx, %%eax\n" + " calll %4\n" // call __end_thread(thread) + " popl %%ebp\n" // restore %ebp + " retl\n" // restore pc + "1:\n" + : "+a"(data), "+c"(func), "+b"(thread), "+d"(cur) + : "m"(*(u8*)__end_thread) + : "esi", "edi", "cc", "memory"); + return; + +fail: + func(data); +} + +void +wait_threads() +{ + ASSERT32(); + if (! CONFIG_THREADS) + return; + while (MainThread.next != &MainThread) + yield(); +} @@ -6,14 +6,7 @@ #include "util.h" // call16 #include "bregs.h" // struct bregs -#include "farptr.h" // GET_FLATPTR -#include "biosvar.h" // get_ebda_seg - -static inline u32 getesp() { - u32 esp; - asm("movl %%esp, %0" : "=rm"(esp)); - return esp; -} +#include "config.h" // BUILD_STACK_ADDR /**************************************************************** @@ -64,33 +57,6 @@ __call16_int(struct bregs *callregs, u16 offset) call16(callregs); } -// Switch to the extra stack in ebda and call a function. -inline u32 -stack_hop(u32 eax, u32 edx, u32 ecx, void *func) -{ - ASSERT16(); - u16 ebda_seg = get_ebda_seg(), bkup_ss; - u32 bkup_esp; - asm volatile( - // Backup current %ss/%esp values. - "movw %%ss, %w3\n" - "movl %%esp, %4\n" - // Copy ebda seg to %ds/%ss and set %esp - "movw %w6, %%ds\n" - "movw %w6, %%ss\n" - "movl %5, %%esp\n" - // Call func - "calll %7\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) - : "cc", "memory"); - return eax; -} - // 16bit trampoline for enabling irqs from 32bit mode. ASM16( " .global trampoline_checkirqs\n" @@ -99,154 +65,25 @@ ASM16( " lretw" ); -static void -check_irqs32() -{ - extern void trampoline_checkirqs(); - struct bregs br; - br.flags = F_IF; - br.code.seg = SEG_BIOS; - br.code.offset = (u32)&trampoline_checkirqs; - call16big(&br); -} - -static void -check_irqs16() -{ - asm volatile( - "sti\n" - "nop\n" - "rep ; nop\n" - "cli\n" - "cld\n" - : : :"memory"); -} - - -/**************************************************************** - * Threads - ****************************************************************/ - -#define THREADSTACKSIZE 4096 - -struct thread_info { - struct thread_info *next; - void *stackpos; -}; - -struct thread_info MainThread; - void -thread_setup() -{ - MainThread.next = &MainThread; - MainThread.stackpos = NULL; -} - -struct thread_info * -getCurThread() -{ - u32 esp = getesp(); - if (esp <= BUILD_STACK_ADDR) - return &MainThread; - return (void*)ALIGN_DOWN(esp, THREADSTACKSIZE); -} - -// Briefly permit irqs to occur. -void -yield() +check_irqs() { if (MODE16) { - // In 16bit mode, just directly check irqs. - check_irqs16(); - return; - } - if (! CONFIG_THREADS) { - check_irqs32(); - return; + asm volatile( + "sti\n" + "nop\n" + "rep ; nop\n" + "cli\n" + "cld\n" + : : :"memory"); + } else { + extern void trampoline_checkirqs(); + struct bregs br; + br.flags = F_IF; + br.code.seg = SEG_BIOS; + br.code.offset = (u32)&trampoline_checkirqs; + call16big(&br); } - struct thread_info *cur = getCurThread(); - if (cur == &MainThread) - // Permit irqs to fire - check_irqs32(); - - // Switch to the next thread - struct thread_info *next = cur->next; - asm volatile( - " pushl $1f\n" // store return pc - " pushl %%ebp\n" // backup %ebp - " movl %%esp, 4(%%eax)\n" // cur->stackpos = %esp - " movl 4(%%ecx), %%esp\n" // %esp = next->stackpos - " popl %%ebp\n" // restore %ebp - " retl\n" // restore pc - "1:\n" - : "+a"(cur), "+c"(next) - : - : "ebx", "edx", "esi", "edi", "cc", "memory"); -} - -// Last thing called from a thread (called on "next" stack). -static void -__end_thread(struct thread_info *old) -{ - struct thread_info *pos = &MainThread; - while (pos->next != old) - pos = pos->next; - pos->next = old->next; - free(old); - dprintf(DEBUG_thread, "\\%08x/ End thread\n", (u32)old); -} - -void -run_thread(void (*func)(void*), void *data) -{ - ASSERT32(); - if (! CONFIG_THREADS) - goto fail; - struct thread_info *thread; - thread = memalign_tmphigh(THREADSTACKSIZE, THREADSTACKSIZE); - if (!thread) - goto fail; - - thread->stackpos = (void*)thread + THREADSTACKSIZE; - struct thread_info *cur = getCurThread(); - thread->next = cur->next; - cur->next = thread; - - dprintf(DEBUG_thread, "/%08x\\ Start thread\n", (u32)thread); - asm volatile( - // Start thread - " pushl $1f\n" // store return pc - " pushl %%ebp\n" // backup %ebp - " movl %%esp, 4(%%edx)\n" // cur->stackpos = %esp - " movl 4(%%ebx), %%esp\n" // %esp = thread->stackpos - " calll *%%ecx\n" // Call func - - // End thread - " movl (%%ebx), %%ecx\n" // %ecx = thread->next - " movl 4(%%ecx), %%esp\n" // %esp = next->stackpos - " movl %%ebx, %%eax\n" - " calll %4\n" // call __end_thread(thread) - " popl %%ebp\n" // restore %ebp - " retl\n" // restore pc - "1:\n" - : "+a"(data), "+c"(func), "+b"(thread), "+d"(cur) - : "m"(*(u8*)__end_thread) - : "esi", "edi", "cc", "memory"); - return; - -fail: - func(data); -} - -void -wait_threads() -{ - ASSERT32(); - if (! CONFIG_THREADS) - return; - while (MainThread.next != &MainThread) - yield(); } @@ -101,6 +101,12 @@ static inline u32 __fls(u32 word) return word; } +static inline u32 getesp() { + u32 esp; + asm("movl %%esp, %0" : "=rm"(esp)); + return esp; +} + static inline void writel(void *addr, u32 val) { *(volatile u32 *)addr = val; } @@ -145,41 +151,44 @@ static inline u8 readb(const void *addr) { } while (0) // util.c -inline u32 stack_hop(u32 eax, u32 edx, u32 ecx, void *func); -extern struct thread_info MainThread; -void thread_setup(); -struct thread_info *getCurThread(); -void run_thread(void (*func)(void*), void *data); -void wait_threads(); +struct bregs; +inline void call16(struct bregs *callregs); +inline void call16big(struct bregs *callregs); +inline void __call16_int(struct bregs *callregs, u16 offset); +#define call16_int(nr, callregs) do { \ + extern void irq_trampoline_ ##nr (); \ + __call16_int((callregs), (u32)&irq_trampoline_ ##nr ); \ + } while (0) +void check_irqs(); u8 checksum_far(u16 buf_seg, void *buf_far, u32 len); u8 checksum(void *buf, u32 len); -int memcmp(const void *s1, const void *s2, size_t n); size_t strlen(const char *s); +int memcmp(const void *s1, const void *s2, size_t n); int strcmp(const char *s1, const char *s2); inline void memset_far(u16 d_seg, void *d_far, u8 c, size_t len); inline void memset16_far(u16 d_seg, void *d_far, u16 c, size_t len); void *memset(void *s, int c, size_t n); +inline void memcpy_far(u16 d_seg, void *d_far + , u16 s_seg, const void *s_far, size_t len); void *memcpy(void *d1, const void *s1, size_t len); #if MODE16 == 0 #define memcpy __builtin_memcpy #endif -inline void memcpy_far(u16 d_seg, void *d_far - , u16 s_seg, const void *s_far, size_t len); void iomemcpy(void *d, const void *s, u32 len); void *memmove(void *d, const void *s, size_t len); char *strtcpy(char *dest, const char *src, size_t len); -struct bregs; -inline void call16(struct bregs *callregs); -inline void call16big(struct bregs *callregs); -inline void __call16_int(struct bregs *callregs, u16 offset); -#define call16_int(nr, callregs) do { \ - extern void irq_trampoline_ ##nr (); \ - __call16_int((callregs), (u32)&irq_trampoline_ ##nr ); \ - } while (0) -void yield(); void biosusleep(u32 usec); int get_keystroke(int msec); +// stacks.c +inline u32 stack_hop(u32 eax, u32 edx, u32 ecx, void *func); +extern struct thread_info MainThread; +void thread_setup(); +struct thread_info *getCurThread(); +void yield(); +void run_thread(void (*func)(void*), void *data); +void wait_threads(); + // output.c void debug_serial_setup(); void panic(const char *fmt, ...) |