aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2010-03-20 20:41:38 -0400
committerKevin O'Connor <kevin@koconnor.net>2010-03-20 20:41:38 -0400
commitbca0736f5a6df16d0d98a877d695d406a9be88b7 (patch)
tree10b87622bea1f2eccbb76b1234bdf9b0f429c456
parentd7eb27efa3f9265dca8357cfa05d9e0560fd4534 (diff)
downloadseabios-bca0736f5a6df16d0d98a877d695d406a9be88b7.tar.gz
Force use of indirect function calls in inline assembler.
For indirect calls, place function address in a register and call it. This is less optimal when gcc can inline the code and the destination address is known at compile time. However, older gcc compilers don't do as well with inlining, and they then mess up the code generation. There doesn't seem to be a way to tell gcc how to emit the code correctly for both immediate addresses and register addresses, so fall back to a safe way. Also, reduce params to stack_hop to avoid register assignment issues.
-rw-r--r--src/block.c2
-rw-r--r--src/stacks.c13
-rw-r--r--src/util.h2
3 files changed, 8 insertions, 9 deletions
diff --git a/src/block.c b/src/block.c
index d485c41e..ddf441f9 100644
--- a/src/block.c
+++ b/src/block.c
@@ -324,7 +324,7 @@ send_disk_op(struct disk_op_s *op)
if (! CONFIG_DRIVES)
return -1;
- return stack_hop((u32)op, GET_SEG(SS), 0, __send_disk_op);
+ return stack_hop((u32)op, GET_SEG(SS), __send_disk_op);
}
diff --git a/src/stacks.c b/src/stacks.c
index 4a30b3d8..570948a4 100644
--- a/src/stacks.c
+++ b/src/stacks.c
@@ -40,7 +40,6 @@ call32(void *func)
struct descloc_s gdt;
sgdt(&gdt);
- func -= BUILD_BIOS_ADDR;
u32 bkup_ss, bkup_esp;
asm volatile(
// Backup ss/esp / set esp to flat stack location
@@ -54,7 +53,7 @@ call32(void *func)
" pushl $(" __stringify(BUILD_BIOS_ADDR) " + 1f)\n"
" jmp transition32\n"
" .code32\n"
- "1:calll %2\n"
+ "1:calll *%2\n"
" pushl $2f\n"
" jmp transition16big\n"
@@ -64,7 +63,7 @@ call32(void *func)
" movl %0, %%ss\n"
" movl %1, %%esp\n"
: "=&r" (bkup_ss), "=&r" (bkup_esp)
- : "m" (*(u8*)func)
+ : "r" (func)
: "eax", "ecx", "edx", "cc", "memory");
// Restore gdt and fs/gs
@@ -85,7 +84,7 @@ call32(void *func)
// Switch to the extra stack in ebda and call a function.
inline u32
-stack_hop(u32 eax, u32 edx, u32 ecx, void *func)
+stack_hop(u32 eax, u32 edx, void *func)
{
ASSERT16();
u16 ebda_seg = get_ebda_seg(), bkup_ss;
@@ -99,13 +98,13 @@ stack_hop(u32 eax, u32 edx, u32 ecx, void *func)
"movw %w6, %%ss\n"
"movl %5, %%esp\n"
// Call func
- "calll %7\n"
+ "calll *%2\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)
+ : "+a" (eax), "+d" (edx), "+c" (func), "=&r" (bkup_ss), "=&r" (bkup_esp)
+ : "i" (EBDA_OFFSET_TOP_STACK), "r" (ebda_seg)
: "cc", "memory");
return eax;
}
diff --git a/src/util.h b/src/util.h
index d2ac08a5..e47860f9 100644
--- a/src/util.h
+++ b/src/util.h
@@ -204,7 +204,7 @@ void biosusleep(u32 usec);
int get_keystroke(int msec);
// stacks.c
-inline u32 stack_hop(u32 eax, u32 edx, u32 ecx, void *func);
+inline u32 stack_hop(u32 eax, u32 edx, void *func);
extern struct thread_info MainThread;
void thread_setup(void);
struct thread_info *getCurThread(void);