diff options
author | 2016-05-18 13:18:31 +0300 | |
---|---|---|
committer | 2016-05-18 13:42:15 +0300 | |
commit | 437fd90c0250dee670290f9b714253671a990160 (patch) | |
tree | b871786c360704244a07411c69fb58da9ead4a06 /qemu/roms/seabios/src/stacks.c | |
parent | 5bbd6fe9b8bab2a93e548c5a53b032d1939eec05 (diff) |
These changes are the raw update to qemu-2.6.
Collission happened in the following patches:
migration: do cleanup operation after completion(738df5b9)
Bug fix.(1750c932f86)
kvmclock: add a new function to update env->tsc.(b52baab2)
The code provided by the patches was already in the upstreamed
version.
Change-Id: I3cc11841a6a76ae20887b2e245710199e1ea7f9a
Signed-off-by: José Pekkarinen <jose.pekkarinen@nokia.com>
Diffstat (limited to 'qemu/roms/seabios/src/stacks.c')
-rw-r--r-- | qemu/roms/seabios/src/stacks.c | 382 |
1 files changed, 159 insertions, 223 deletions
diff --git a/qemu/roms/seabios/src/stacks.c b/qemu/roms/seabios/src/stacks.c index 1dbdfe9bb..ef6a70775 100644 --- a/qemu/roms/seabios/src/stacks.c +++ b/qemu/roms/seabios/src/stacks.c @@ -1,6 +1,6 @@ // Code for manipulating stack locations. // -// Copyright (C) 2009-2014 Kevin O'Connor <kevin@koconnor.net> +// Copyright (C) 2009-2015 Kevin O'Connor <kevin@koconnor.net> // // This file may be distributed under the terms of the GNU LGPLv3 license. @@ -13,6 +13,7 @@ #include "output.h" // dprintf #include "romfile.h" // romfile_loadint #include "stacks.h" // struct mutex_s +#include "string.h" // memset #include "util.h" // useRTC #define MAIN_STACK_MAX (1024*1024) @@ -27,40 +28,108 @@ struct { u8 cmosindex; u8 a20; u16 ss, fs, gs; + u32 cr0; struct descloc_s gdt; -} Call32Data VARLOW; +} Call16Data VARLOW; -#define C32_SLOPPY 1 -#define C32_SMM 2 +#define C16_BIG 1 +#define C16_SMM 2 int HaveSmmCall32 VARFSEG; -// Backup state in preparation for call32_smm() -static void -call32_smm_prep(void) -{ +// Backup state in preparation for call32 +static int +call32_prep(u8 method) +{ + if (!CONFIG_CALL32_SMM || method != C16_SMM) { + // Backup cr0 + u32 cr0 = cr0_read(); + if (cr0 & CR0_PE) + // Called in 16bit protected mode?! + return -1; + SET_LOW(Call16Data.cr0, cr0); + + // Backup fs/gs and gdt + SET_LOW(Call16Data.fs, GET_SEG(FS)); + SET_LOW(Call16Data.gs, GET_SEG(GS)); + struct descloc_s gdt; + sgdt(&gdt); + SET_LOW(Call16Data.gdt.length, gdt.length); + SET_LOW(Call16Data.gdt.addr, gdt.addr); + + // Enable a20 and backup its previous state + SET_LOW(Call16Data.a20, set_a20(1)); + } + + // Backup ss + SET_LOW(Call16Data.ss, GET_SEG(SS)); + // Backup cmos index register and disable nmi u8 cmosindex = inb(PORT_CMOS_INDEX); outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX); inb(PORT_CMOS_DATA); - SET_LOW(Call32Data.cmosindex, cmosindex); - - // Backup ss - SET_LOW(Call32Data.ss, GET_SEG(SS)); + SET_LOW(Call16Data.cmosindex, cmosindex); - SET_LOW(Call32Data.method, C32_SMM); + SET_LOW(Call16Data.method, method); + return 0; } -// Restore state backed up during call32_smm() -static void -call32_smm_post(void) +// Restore state backed up during call32 +static u8 +call32_post(void) { - SET_LOW(Call32Data.method, 0); - SET_LOW(Call32Data.ss, 0); + u8 method = GET_LOW(Call16Data.method); + SET_LOW(Call16Data.method, 0); + SET_LOW(Call16Data.ss, 0); + + if (!CONFIG_CALL32_SMM || method != C16_SMM) { + // Restore a20 + set_a20(GET_LOW(Call16Data.a20)); + + // Restore gdt and fs/gs + struct descloc_s gdt; + gdt.length = GET_LOW(Call16Data.gdt.length); + gdt.addr = GET_LOW(Call16Data.gdt.addr); + lgdt(&gdt); + SET_SEG(FS, GET_LOW(Call16Data.fs)); + SET_SEG(GS, GET_LOW(Call16Data.gs)); + + // Restore cr0 + u32 cr0_caching = GET_LOW(Call16Data.cr0) & (CR0_CD|CR0_NW); + if (cr0_caching) + cr0_mask(CR0_CD|CR0_NW, cr0_caching); + } // Restore cmos index register - outb(GET_LOW(Call32Data.cmosindex), PORT_CMOS_INDEX); + outb(GET_LOW(Call16Data.cmosindex), PORT_CMOS_INDEX); inb(PORT_CMOS_DATA); + return method; +} + +// Force next call16() to restore to a pristine cpu environment state +static void +call16_override(int big) +{ + ASSERT32FLAT(); + if (getesp() > BUILD_STACK_ADDR) + panic("call16_override with invalid stack\n"); + memset(&Call16Data, 0, sizeof(Call16Data)); + if (big) { + Call16Data.method = C16_BIG; + Call16Data.a20 = 1; + } else { + Call16Data.a20 = !CONFIG_DISABLE_A20; + } +} + +// 16bit handler code called from call16() / call16_smm() +u32 VISIBLE16 +call16_helper(u32 eax, u32 edx, u32 (*func)(u32 eax, u32 edx)) +{ + u8 method = call32_post(); + u32 ret = func(eax, edx); + call32_prep(method); + return ret; } #define ASM32_SWITCH16 " .pushsection .text.32fseg." UNIQSEC "\n .code16\n" @@ -74,7 +143,7 @@ call32_smm(void *func, u32 eax) { ASSERT16(); dprintf(9, "call32_smm %p %x\n", func, eax); - call32_smm_prep(); + call32_prep(C16_SMM); u32 bkup_esp; asm volatile( // Backup esp / set esp to flat stack location @@ -109,24 +178,12 @@ call32_smm(void *func, u32 eax) : "=&r" (bkup_esp), "+r" (eax) : "r" (func) : "eax", "ecx", "edx", "ebx", "cc", "memory"); - call32_smm_post(); + call32_post(); dprintf(9, "call32_smm done %p %x\n", func, eax); return eax; } -// 16bit handler code called from call16_smm() -u32 VISIBLE16 -call16_smm_helper(u32 eax, u32 edx, u32 (*func)(u32 eax, u32 edx)) -{ - if (!CONFIG_CALL32_SMM) - return eax; - call32_smm_post(); - u32 ret = func(eax, edx); - call32_smm_prep(); - return ret; -} - static u32 call16_smm(u32 eax, u32 edx, void *func) { @@ -135,7 +192,7 @@ call16_smm(u32 eax, u32 edx, void *func) return eax; func -= BUILD_BIOS_ADDR; dprintf(9, "call16_smm %p %x %x\n", func, eax, edx); - u32 stackoffset = Call32Data.ss << 4; + u32 stackoffset = Call16Data.ss << 4; asm volatile( // Restore esp " subl %0, %%esp\n" @@ -151,7 +208,7 @@ call16_smm(u32 eax, u32 edx, void *func) ASM32_SWITCH16 "1:movl %1, %%eax\n" " movl %3, %%ecx\n" - " calll _cfunc16_call16_smm_helper\n" + " calll _cfunc16_call16_helper\n" " movl %%eax, %1\n" " movl $" __stringify(CALL32SMM_CMDID) ", %%eax\n" @@ -170,61 +227,18 @@ call16_smm(u32 eax, u32 edx, void *func) return eax; } -// Backup state in preparation for call32_sloppy() -static void -call32_sloppy_prep(void) -{ - // Backup cmos index register and disable nmi - u8 cmosindex = inb(PORT_CMOS_INDEX); - outb(cmosindex | NMI_DISABLE_BIT, PORT_CMOS_INDEX); - inb(PORT_CMOS_DATA); - SET_LOW(Call32Data.cmosindex, cmosindex); - - // Enable a20 and backup it's previous state - SET_LOW(Call32Data.a20, set_a20(1)); - - // Backup ss/fs/gs and gdt - SET_LOW(Call32Data.ss, GET_SEG(SS)); - SET_LOW(Call32Data.fs, GET_SEG(FS)); - SET_LOW(Call32Data.gs, GET_SEG(GS)); - struct descloc_s gdt; - sgdt(&gdt); - SET_LOW(Call32Data.gdt.length, gdt.length); - SET_LOW(Call32Data.gdt.addr, gdt.addr); - - SET_LOW(Call32Data.method, C32_SLOPPY); -} - -// Restore state backed up during call32_sloppy() -static void -call32_sloppy_post(void) -{ - SET_LOW(Call32Data.method, 0); - SET_LOW(Call32Data.ss, 0); - - // Restore gdt and fs/gs - struct descloc_s gdt; - gdt.length = GET_LOW(Call32Data.gdt.length); - gdt.addr = GET_LOW(Call32Data.gdt.addr); - lgdt(&gdt); - SET_SEG(FS, GET_LOW(Call32Data.fs)); - SET_SEG(GS, GET_LOW(Call32Data.gs)); - - // Restore a20 - set_a20(GET_LOW(Call32Data.a20)); - - // Restore cmos index register - outb(GET_LOW(Call32Data.cmosindex), PORT_CMOS_INDEX); - inb(PORT_CMOS_DATA); -} - -// Call a C function in 32bit mode. This clobbers the 16bit segment -// selector registers. -static u32 -call32_sloppy(void *func, u32 eax) +// Call a 32bit SeaBIOS function from a 16bit SeaBIOS function. +u32 VISIBLE16 +__call32(void *func, u32 eax, u32 errret) { ASSERT16(); - call32_sloppy_prep(); + if (CONFIG_CALL32_SMM && GET_GLOBAL(HaveSmmCall32)) + return call32_smm(func, eax); + // Jump direclty to 32bit mode - this clobbers the 16bit segment + // selector registers. + int ret = call32_prep(C16_BIG); + if (ret) + return errret; u32 bkup_ss, bkup_esp; asm volatile( // Backup ss/esp / set esp to flat stack location @@ -236,7 +250,7 @@ call32_sloppy(void *func, u32 eax) // Transition to 32bit mode, call func, return to 16bit " movl $(" __stringify(BUILD_BIOS_ADDR) " + 1f), %%edx\n" - " jmp transition32\n" + " jmp transition32_nmi_off\n" ASM16_SWITCH32 "1:calll *%3\n" " movl $2f, %%edx\n" @@ -250,136 +264,52 @@ call32_sloppy(void *func, u32 eax) : "=&r" (bkup_ss), "=&r" (bkup_esp), "+a" (eax) : "r" (func) : "ecx", "edx", "cc", "memory"); - call32_sloppy_post(); + call32_post(); return eax; } -// 16bit handler code called from call16_sloppy() -u32 VISIBLE16 -call16_sloppy_helper(u32 eax, u32 edx, u32 (*func)(u32 eax, u32 edx)) -{ - call32_sloppy_post(); - u32 ret = func(eax, edx); - call32_sloppy_prep(); - return ret; -} - -// Jump back to 16bit mode while in 32bit mode from call32_sloppy() +// Call a 16bit SeaBIOS function, restoring the mode from last call32(). static u32 -call16_sloppy(u32 eax, u32 edx, void *func) +call16(u32 eax, u32 edx, void *func) { ASSERT32FLAT(); if (getesp() > MAIN_STACK_MAX) - panic("call16_sloppy with invalid stack\n"); + panic("call16 with invalid stack\n"); + if (CONFIG_CALL32_SMM && Call16Data.method == C16_SMM) + return call16_smm(eax, edx, func); + + extern void transition16big(void); + extern void transition16(void); + void *thunk = transition16; + if (Call16Data.method == C16_BIG || in_post()) + thunk = transition16big; func -= BUILD_BIOS_ADDR; - u32 stackseg = Call32Data.ss; + u32 stackseg = Call16Data.ss; asm volatile( // Transition to 16bit mode " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n" - " jmp transition16big\n" + " jmp *%%ecx\n" // Setup ss/esp and call func ASM32_SWITCH16 - "1:movl %3, %%ecx\n" - " shll $4, %3\n" + "1:movl %2, %%ecx\n" + " shll $4, %2\n" " movw %%cx, %%ss\n" - " subl %3, %%esp\n" + " subl %2, %%esp\n" " movw %%cx, %%ds\n" - " movl %2, %%edx\n" - " movl %1, %%ecx\n" - " calll _cfunc16_call16_sloppy_helper\n" + " movl %4, %%edx\n" + " movl %3, %%ecx\n" + " calll _cfunc16_call16_helper\n" // Return to 32bit and restore esp " movl $2f, %%edx\n" - " jmp transition32\n" - ASM32_BACK32 - "2:addl %3, %%esp\n" - : "+a" (eax) - : "r" (func), "r" (edx), "r" (stackseg) - : "edx", "ecx", "cc", "memory"); - return eax; -} - -// Call a 32bit SeaBIOS function from a 16bit SeaBIOS function. -u32 VISIBLE16 -call32(void *func, u32 eax, u32 errret) -{ - ASSERT16(); - if (CONFIG_CALL32_SMM && GET_GLOBAL(HaveSmmCall32)) - return call32_smm(func, eax); - u32 cr0 = getcr0(); - if (cr0 & CR0_PE) - // Called in 16bit protected mode?! - return errret; - return call32_sloppy(func, eax); -} - -// Call a 16bit SeaBIOS function from a 32bit SeaBIOS function. -static u32 -call16(u32 eax, u32 edx, void *func) -{ - ASSERT32FLAT(); - if (getesp() > BUILD_STACK_ADDR) - panic("call16 with invalid stack\n"); - func -= BUILD_BIOS_ADDR; - asm volatile( - // Transition to 16bit mode - " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n" - " jmp transition16\n" - // Call func - ASM32_SWITCH16 - "1:movl %2, %%edx\n" - " calll *%1\n" - // Return to 32bit - " movl $2f, %%edx\n" - " jmp transition32\n" - ASM32_BACK32 - "2:\n" - : "+a" (eax) - : "r" (func), "r" (edx) - : "edx", "ecx", "cc", "memory"); - return eax; -} - -// Call a 16bit SeaBIOS function in "big real" mode. -static u32 -call16big(u32 eax, u32 edx, void *func) -{ - ASSERT32FLAT(); - if (getesp() > BUILD_STACK_ADDR) - panic("call16big with invalid stack\n"); - func -= BUILD_BIOS_ADDR; - asm volatile( - // Transition to 16bit mode - " movl $(1f - " __stringify(BUILD_BIOS_ADDR) "), %%edx\n" - " jmp transition16big\n" - // Call func - ASM32_SWITCH16 - "1:movl %2, %%edx\n" - " calll *%1\n" - // Return to 32bit - " movl $2f, %%edx\n" - " jmp transition32\n" + " jmp transition32_nmi_off\n" ASM32_BACK32 - "2:\n" - : "+a" (eax) + "2:addl %2, %%esp\n" + : "+a" (eax), "+c"(thunk), "+r"(stackseg) : "r" (func), "r" (edx) - : "edx", "ecx", "cc", "memory"); + : "edx", "cc", "memory"); return eax; } -// Call a 16bit SeaBIOS function, restoring the mode from last call32(). -static u32 -call16_back(u32 eax, u32 edx, void *func) -{ - ASSERT32FLAT(); - if (CONFIG_CALL32_SMM && Call32Data.method == C32_SMM) - return call16_smm(eax, edx, func); - if (Call32Data.method == C32_SLOPPY) - return call16_sloppy(eax, edx, func); - if (in_post()) - return call16big(eax, edx, func); - return call16(eax, edx, func); -} - /**************************************************************** * Extra 16bit stack @@ -398,7 +328,7 @@ on_extra_stack(void) // Switch to the extra stack and call a function. u32 -stack_hop(u32 eax, u32 edx, void *func) +__stack_hop(u32 eax, u32 edx, void *func) { if (on_extra_stack()) return ((u32 (*)(u32, u32))func)(eax, edx); @@ -431,10 +361,10 @@ stack_hop(u32 eax, u32 edx, void *func) // Switch back to original caller's stack and call a function. u32 -stack_hop_back(u32 eax, u32 edx, void *func) +__stack_hop_back(u32 eax, u32 edx, void *func) { if (!MODESEGMENT) - return call16_back(eax, edx, func); + return call16(eax, edx, func); if (!MODE16 || !on_extra_stack()) return ((u32 (*)(u32, u32))func)(eax, edx); ASSERT16(); @@ -474,8 +404,7 @@ void VISIBLE16 _farcall16(struct bregs *callregs, u16 callregseg) { if (need_hop_back()) { - extern void _cfunc16__farcall16(void); - stack_hop_back((u32)callregs, callregseg, _cfunc16__farcall16); + stack_hop_back(_farcall16, callregs, callregseg); return; } ASSERT16(); @@ -486,18 +415,20 @@ _farcall16(struct bregs *callregs, u16 callregseg) : "ebx", "ecx", "esi", "edi", "cc", "memory"); } +// Invoke external 16bit code. void farcall16(struct bregs *callregs) { - extern void _cfunc16__farcall16(void); - call16((u32)callregs, 0, _cfunc16__farcall16); + call16_override(0); + _farcall16(callregs, 0); } +// Invoke external 16bit code in "big real" mode. void farcall16big(struct bregs *callregs) { - extern void _cfunc16__farcall16(void); - call16big((u32)callregs, 0, _cfunc16__farcall16); + call16_override(1); + _farcall16(callregs, 0); } // Invoke a 16bit software interrupt. @@ -507,7 +438,7 @@ __call16_int(struct bregs *callregs, u16 offset) callregs->code.offset = offset; if (!MODESEGMENT) { callregs->code.seg = SEG_BIOS; - _farcall16((void*)callregs - Call32Data.ss * 16, Call32Data.ss); + _farcall16((void*)callregs - Call16Data.ss * 16, Call16Data.ss); return; } callregs->code.seg = GET_SEG(CS); @@ -520,7 +451,7 @@ reset(void) { extern void reset_vector(void) __noreturn; if (!MODE16) - call16_back(0, 0, reset_vector); + call16(0, 0, reset_vector); reset_vector(); } @@ -558,12 +489,13 @@ getCurThread(void) return (void*)ALIGN_DOWN(esp, THREADSTACKSIZE); } -static int ThreadControl; +static u8 CanInterrupt, ThreadControl; // Initialize the support for internal threads. void -thread_init(void) +thread_setup(void) { + CanInterrupt = 1; if (! CONFIG_THREADS) return; ThreadControl = romfile_loadint("etc/threads", 1); @@ -573,7 +505,7 @@ thread_init(void) int threads_during_optionroms(void) { - return CONFIG_THREADS && ThreadControl == 2 && in_post(); + return CONFIG_THREADS && CONFIG_RTC_TIMER && ThreadControl == 2 && in_post(); } // Switch to next thread stack. @@ -660,11 +592,17 @@ fail: void VISIBLE16 check_irqs(void) { + if (!MODESEGMENT && !CanInterrupt) { + // Can't enable interrupts (PIC and/or IVT not yet setup) + cpu_relax(); + return; + } if (need_hop_back()) { - extern void _cfunc16_check_irqs(void); - stack_hop_back(0, 0, _cfunc16_check_irqs); + stack_hop_back(check_irqs, 0, 0); return; } + if (MODE16) + clock_poll_irq(); asm volatile("sti ; nop ; rep ; nop ; cli ; cld" : : :"memory"); } @@ -689,8 +627,7 @@ void VISIBLE16 wait_irq(void) { if (need_hop_back()) { - extern void _cfunc16_wait_irq(void); - stack_hop_back(0, 0, _cfunc16_wait_irq); + stack_hop_back(wait_irq, 0, 0); return; } asm volatile("sti ; hlt ; cli ; cld": : :"memory"); @@ -700,8 +637,9 @@ wait_irq(void) void yield_toirq(void) { - if (!MODESEGMENT && have_threads()) { - // Threads still active - do a yield instead. + if (!CONFIG_HARDWARE_IRQ + || (!MODESEGMENT && (have_threads() || !CanInterrupt))) { + // Threads still active or irqs not available - do a yield instead. yield(); return; } @@ -794,9 +732,8 @@ yield_preempt(void) void check_preempt(void) { - extern void _cfunc32flat_yield_preempt(void); if (CONFIG_THREADS && GET_GLOBAL(CanPreempt) && have_threads()) - call32(_cfunc32flat_yield_preempt, 0, 0); + call32(yield_preempt, 0, 0); } @@ -817,11 +754,10 @@ call32_params_helper(struct call32_params_s *params) } u32 -call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret) +__call32_params(void *func, u32 eax, u32 edx, u32 ecx, u32 errret) { ASSERT16(); struct call32_params_s params = {func, eax, edx, ecx}; - extern void _cfunc32flat_call32_params_helper(void); - return call32(_cfunc32flat_call32_params_helper - , (u32)MAKE_FLATPTR(GET_SEG(SS), ¶ms), errret); + return call32(call32_params_helper, MAKE_FLATPTR(GET_SEG(SS), ¶ms) + , errret); } |