diff options
author | Kevin O'Connor <kevin@koconnor.net> | 2012-05-28 12:59:58 -0400 |
---|---|---|
committer | Kevin O'Connor <kevin@koconnor.net> | 2012-05-28 23:39:49 -0400 |
commit | bf2e8c2a304c1aafc612e89deaaa6066d6cdb3f6 (patch) | |
tree | dc8972dcdc2f52fdc4fa30f0699f739cecd092c6 /src | |
parent | 2f898d5eae41c7bec54ab60c3ea25f200d46728d (diff) | |
download | seabios-hppa-bf2e8c2a304c1aafc612e89deaaa6066d6cdb3f6.zip seabios-hppa-bf2e8c2a304c1aafc612e89deaaa6066d6cdb3f6.tar.gz seabios-hppa-bf2e8c2a304c1aafc612e89deaaa6066d6cdb3f6.tar.bz2 |
Make the extra stack re-entrant and "hop back" to check for irqs.
When on the extra stack and it's necessary to check for irqs, switch
back to the original caller's stack to check for irqs. Make the extra
stack re-entrant, so that a new user of the extra stack wont collide
with an existing user.
Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src')
-rw-r--r-- | src/post.c | 3 | ||||
-rw-r--r-- | src/stacks.c | 58 | ||||
-rw-r--r-- | src/util.h | 2 |
3 files changed, 56 insertions, 7 deletions
@@ -95,6 +95,9 @@ init_bda(void) add_e820((u32)MAKE_FLATPTR(ebda_seg, 0), GET_EBDA(ebda_seg, size) * 1024 , E820_RESERVED); + + // Init extra stack + StackPos = (void*)(&ExtraStack[BUILD_EXTRA_STACK_SIZE] - _datalow_base); } static void diff --git a/src/stacks.c b/src/stacks.c index 044d9ea..febd8bc 100644 --- a/src/stacks.c +++ b/src/stacks.c @@ -15,14 +15,24 @@ // Space for a stack for 16bit code. u8 ExtraStack[BUILD_EXTRA_STACK_SIZE+1] VARLOW __aligned(8); +u8 *StackPos VARLOW; + +// Test if currently on the extra stack +static inline int +on_extra_stack(void) +{ + return MODE16 && GET_SEG(SS) == SEG_LOW && getesp() > (u32)ExtraStack; +} // Switch to the extra stack and call a function. inline u32 stack_hop(u32 eax, u32 edx, void *func) { + if (on_extra_stack()) + return ((u32 (*)(u32, u32))func)(eax, edx); ASSERT16(); - u16 stack_seg = SEG_LOW, bkup_ss; - u32 bkup_esp; + u16 stack_seg = SEG_LOW; + u32 bkup_ss, bkup_esp; asm volatile( // Backup current %ss/%esp values. "movw %%ss, %w3\n" @@ -31,14 +41,51 @@ stack_hop(u32 eax, u32 edx, void *func) "movw %w6, %%ds\n" "movw %w6, %%ss\n" "movl %5, %%esp\n" + "pushl %3\n" + "pushl %4\n" // Call func "calll *%2\n" + "popl %4\n" + "popl %3\n" // Restore segments and stack "movw %w3, %%ds\n" "movw %w3, %%ss\n" "movl %4, %%esp" : "+a" (eax), "+d" (edx), "+c" (func), "=&r" (bkup_ss), "=&r" (bkup_esp) - : "i" (&ExtraStack[BUILD_EXTRA_STACK_SIZE]), "r" (stack_seg) + : "m" (StackPos), "r" (stack_seg) + : "cc", "memory"); + return eax; +} + +// Switch back to original caller's stack and call a function. +static u32 +stack_hop_back(u32 eax, u32 edx, void *func) +{ + if (!on_extra_stack()) + return ((u32 (*)(u32, u32))func)(eax, edx); + ASSERT16(); + u16 bkup_ss; + u32 bkup_stack_pos, temp; + asm volatile( + // Backup stack_pos and current %ss/%esp + "movl %6, %4\n" + "movw %%ss, %w3\n" + "movl %%esp, %6\n" + // Restore original callers' %ss/%esp + "movl -4(%4), %5\n" + "movl %5, %%ss\n" + "movl %%ds:-8(%4), %%esp\n" + "movl %5, %%ds\n" + // Call func + "calll *%2\n" + // Restore %ss/%esp and stack_pos + "movw %w3, %%ds\n" + "movw %w3, %%ss\n" + "movl %6, %%esp\n" + "movl %4, %6" + : "+a" (eax), "+d" (edx), "+c" (func), "=&r" (bkup_ss) + , "=&r" (bkup_stack_pos), "=&r" (temp), "+m" (StackPos) + : : "cc", "memory"); return eax; } @@ -245,8 +292,7 @@ void yield(void) { if (MODESEGMENT) { - // Just directly check irqs. - check_irqs(); + stack_hop_back(0, 0, check_irqs); return; } extern void _cfunc16_check_irqs(void); @@ -274,7 +320,7 @@ void yield_toirq(void) { if (MODESEGMENT) { - wait_irq(); + stack_hop_back(0, 0, wait_irq); return; } if (CONFIG_THREADS && MainThread.next != &MainThread) { @@ -221,7 +221,7 @@ void nullTrailingSpace(char *buf); int get_keystroke(int msec); // stacks.c -extern u8 ExtraStack[]; +extern u8 ExtraStack[], *StackPos; inline u32 stack_hop(u32 eax, u32 edx, void *func); u32 call32(void *func, u32 eax, u32 errret); struct bregs; |