diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2010-05-23 10:24:22 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2010-05-23 10:24:22 -0400 |
commit | 9c447c3a6d94b4e43e0b55a1d0cf0f9731472aa2 (patch) | |
tree | 2cb21e691276a923a0e2e4252c673b0ca16a62c2 | |
parent | 49cc72ba1e59e552754217225d66c7ef0feaf84f (diff) | |
download | seabios-9c447c3a6d94b4e43e0b55a1d0cf0f9731472aa2.tar.gz |
Allow wait_irq to be called in 32bit code.
If wait_irq() is called from 32bit code, then jump to 16bit mode for
the wait.
Have wait_irq check for threads, and have it use yield if threads are
pending. This ensures threads aren't delayed if anything calls
wait_irq.
Use wait_irq() in 32bit mode during a failed boot.
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | src/boot.c | 2 | ||||
-rw-r--r-- | src/stacks.c | 83 | ||||
-rw-r--r-- | src/util.c | 29 | ||||
-rw-r--r-- | src/util.h | 14 |
5 files changed, 79 insertions, 51 deletions
@@ -20,7 +20,7 @@ SRC16=$(SRCBOTH) system.c disk.c apm.c font.c SRC32FLAT=$(SRCBOTH) post.c shadow.c memmap.c coreboot.c boot.c \ acpi.c smm.c mptable.c smbios.c pciinit.c optionroms.c mtrr.c \ lzmadecode.c usb-hub.c paravirt.c -SRC32SEG=util.c output.c pci.c pcibios.c apm.c +SRC32SEG=util.c output.c pci.c pcibios.c apm.c stacks.c cc-option = $(shell if test -z "`$(1) $(2) -S -o /dev/null -xc \ /dev/null 2>&1`"; then echo "$(2)"; else echo "$(3)"; fi ;) @@ -449,7 +449,7 @@ do_boot(u16 seq_nr) printf("No bootable device.\n"); // Loop with irqs enabled - this allows ctrl+alt+delete to work. for (;;) - biosusleep(1000000); + wait_irq(); } /* Do the loading, and set up vector as a far pointer to the boot diff --git a/src/stacks.c b/src/stacks.c index 859de3f5..f5feeebe 100644 --- a/src/stacks.c +++ b/src/stacks.c @@ -8,6 +8,20 @@ #include "util.h" // dprintf #include "bregs.h" // CR0_PE +// 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; + + +/**************************************************************** + * Low level helpers + ****************************************************************/ + static inline u32 getcr0(void) { u32 cr0; asm("movl %%cr0, %0" : "=r"(cr0)); @@ -77,6 +91,65 @@ call32(void *func) return 0; } +// 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); +} + /**************************************************************** * Stack in EBDA @@ -115,16 +188,6 @@ 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 @@ -57,35 +57,6 @@ __call16_int(struct bregs *callregs, u16 offset) call16(callregs); } -// 16bit trampoline for enabling irqs from 32bit mode. -ASM16( - " .global trampoline_checkirqs\n" - "trampoline_checkirqs:\n" - " rep ; nop\n" - " lretw" - ); - -void -check_irqs(void) -{ - if (MODE16) { - 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); - } -} - /**************************************************************** * String ops @@ -21,7 +21,7 @@ static inline void irq_enable(void) static inline unsigned long irq_save(void) { unsigned long flags; - asm volatile("pushfl ; popl %0" : "=g" (flags)); + asm volatile("pushfl ; popl %0" : "=g" (flags): :"memory"); irq_disable(); return flags; } @@ -36,12 +36,6 @@ static inline void cpu_relax(void) asm volatile("rep ; nop": : :"memory"); } -// Atomically enable irqs and sleep until an irq; then re-disable irqs. -static inline void wait_irq(void) -{ - asm volatile("sti ; hlt ; cli ; cld": : :"memory"); -} - static inline void nop(void) { asm volatile("nop"); @@ -49,12 +43,12 @@ static inline void nop(void) static inline void hlt(void) { - asm volatile("hlt"); + asm volatile("hlt": : :"memory"); } static inline void wbinvd(void) { - asm volatile("wbinvd"); + asm volatile("wbinvd": : :"memory"); } #define CPUID_MSR (1 << 5) @@ -182,7 +176,6 @@ inline void __call16_int(struct bregs *callregs, u16 offset); extern void irq_trampoline_ ##nr (); \ __call16_int((callregs), (u32)&irq_trampoline_ ##nr ); \ } while (0) -void check_irqs(void); u8 checksum_far(u16 buf_seg, void *buf_far, u32 len); u8 checksum(void *buf, u32 len); size_t strlen(const char *s); @@ -209,6 +202,7 @@ extern struct thread_info MainThread; void thread_setup(void); struct thread_info *getCurThread(void); void yield(void); +void wait_irq(void); void run_thread(void (*func)(void*), void *data); void wait_threads(void); struct mutex_s { u32 isLocked; }; |