// Code for manipulating stack locations.
//
-// Copyright (C) 2009 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2009-2010 Kevin O'Connor <kevin@koconnor.net>
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
#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));
}
}
// 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);
" 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
"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);
// 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);
}
****************************************************************/
#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)
*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.
}
CanPreempt = 0;
releaseRTC();
- dprintf(1, "Done preempt - %d checks\n", PreemptCount);
+ dprintf(9, "Done preempt - %d checks\n", PreemptCount);
yield();
}
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
{
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);
}