aboutsummaryrefslogtreecommitdiff
path: root/src/fw
diff options
context:
space:
mode:
authorKevin O'Connor <kevin@koconnor.net>2014-04-07 19:49:12 -0400
committerKevin O'Connor <kevin@koconnor.net>2014-06-04 11:06:58 -0400
commitf4c511cd7a5a475d542389341a320cb1c946fe25 (patch)
tree01333f28304bfaf0b309c274439a797099e9412e /src/fw
parent2126994528a160f56fbaa6e5f0a2da9c0d628095 (diff)
downloadseabios-hppa-f4c511cd7a5a475d542389341a320cb1c946fe25.zip
seabios-hppa-f4c511cd7a5a475d542389341a320cb1c946fe25.tar.gz
seabios-hppa-f4c511cd7a5a475d542389341a320cb1c946fe25.tar.bz2
smm: Replace SMI assembler code with C code.
Convert the SMI handler from assembly to C. This makes the handler easier to understand and enhance. The new handler will use references to the reserved memory at 0xf0000-0x100000. If the physical memory in that range is modified at runtime, then the SMI handler will cease to function properly (and may allow unintended code to run in SMM mode). However, that area is marked as reserved and is normally made read-only at runtime, so there is little risk in relying on it. Signed-off-by: Kevin O'Connor <kevin@koconnor.net>
Diffstat (limited to 'src/fw')
-rw-r--r--src/fw/smm.c69
1 files changed, 30 insertions, 39 deletions
diff --git a/src/fw/smm.c b/src/fw/smm.c
index f486c78..3d0caa1 100644
--- a/src/fw/smm.c
+++ b/src/fw/smm.c
@@ -1,6 +1,6 @@
// System Management Mode support (on emulators)
//
-// Copyright (C) 2008 Kevin O'Connor <kevin@koconnor.net>
+// Copyright (C) 2008-2014 Kevin O'Connor <kevin@koconnor.net>
// Copyright (C) 2006 Fabrice Bellard
//
// This file may be distributed under the terms of the GNU LGPLv3 license.
@@ -17,47 +17,39 @@
#include "util.h" // smm_setup
#include "x86.h" // wbinvd
-extern u8 smm_code_start, smm_code_end;
-
-ASM32FLAT(
- ".global smm_code_start, smm_code_end\n"
- " .code16gcc\n"
- "smm_code_start:\n"
- " mov %cs, %ax\n"
- " cmp $0xa000, %ax\n"
- " je smm_exit\n"
-
- /* code to relocate SMBASE to 0xa0000 */
- " movl $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7efc, %ebx\n"
- " addr32 movb (%ebx), %al\n" /* revision ID to see if x86_64 or x86 */
- " cmpb $0x64, %al\n"
- " je 1f\n"
- " movl $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7ef8, %ebx\n"
- " jmp 2f\n"
- "1:\n"
- " movl $" __stringify(BUILD_SMM_INIT_ADDR) " + 0x7f00, %ebx\n"
- "2:\n"
- " movl $" __stringify(BUILD_SMM_ADDR) " - 0x8000, %eax\n"
- " addr32 movl %eax, (%ebx)\n"
- /* indicate to the BIOS that the SMM code was executed */
- " movb $0x00, %al\n"
- " movw $" __stringify(PORT_SMI_STATUS) ", %dx\n"
- " outb %al, %dx\n"
- "smm_exit:\n"
- " rsm\n"
- "smm_code_end:\n"
- " .code32\n"
- );
+void VISIBLE32FLAT
+handle_smi(u16 cs)
+{
+ u8 cmd = inb(PORT_SMI_CMD);
+ dprintf(DEBUG_HDL_smi, "handle_smi cmd=%x cs=%x\n", cmd, cs);
+
+ void *smbase = MAKE_FLATPTR(cs, 0) + 0x8000;
+ if (smbase == (void*)BUILD_SMM_INIT_ADDR) {
+ // relocate SMBASE to 0xa0000
+ u8 *smrev = smbase + 0x7efc;
+ u32 *newbase = smbase + 0x7ef8;
+ if (*smrev == 0x64)
+ newbase = smbase + 0x7f00;
+ *newbase = BUILD_SMM_ADDR - 0x8000;
+ // indicate to smm_relocate_and_restore() that the SMM code was executed
+ outb(0x00, PORT_SMI_STATUS);
+ return;
+ }
+}
+
+extern void entry_smi(void);
+// movw %cs, %ax; ljmpw $SEG_BIOS, $(entry_smi - BUILD_BIOS_ADDR)
+#define SMI_INSN (0xeac88c | ((u64)SEG_BIOS<<40) \
+ | ((u64)((u32)entry_smi - BUILD_BIOS_ADDR) << 24))
static void
smm_save_and_copy(void)
{
- /* save original memory content */
+ // save original memory content
memcpy((void *)BUILD_SMM_ADDR, (void *)BUILD_SMM_INIT_ADDR, BUILD_SMM_SIZE);
- /* copy the SMM code, which will relocate itself on the first execution */
- memcpy((void *)BUILD_SMM_INIT_ADDR, &smm_code_start,
- &smm_code_end - &smm_code_start);
+ // Setup code entry point.
+ *(u64*)BUILD_SMM_INIT_ADDR = SMI_INSN;
}
static void
@@ -76,9 +68,8 @@ smm_relocate_and_restore(void)
/* restore original memory content */
memcpy((void *)BUILD_SMM_INIT_ADDR, (void *)BUILD_SMM_ADDR, BUILD_SMM_SIZE);
- /* copy the SMM code */
- memcpy((void *)BUILD_SMM_ADDR, &smm_code_start
- , &smm_code_end - &smm_code_start);
+ // Setup code entry point.
+ *(u64*)BUILD_SMM_ADDR = SMI_INSN;
wbinvd();
}