]> xenbits.xensource.com Git - seabios.git/commitdiff
smm: Replace SMI assembler code with C code.
authorKevin O'Connor <kevin@koconnor.net>
Mon, 7 Apr 2014 23:49:12 +0000 (19:49 -0400)
committerKevin O'Connor <kevin@koconnor.net>
Wed, 4 Jun 2014 15:06:58 +0000 (11:06 -0400)
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>
src/config.h
src/fw/smm.c
src/romlayout.S

index d7056154a9404fb58817c2ee6c3b25140e15f2fe..269a022c4f65c2f186c99648daad6707e50c1478 100644 (file)
@@ -95,6 +95,7 @@
 #define DEBUG_ISR_76 10
 #define DEBUG_ISR_hwpic1 5
 #define DEBUG_ISR_hwpic2 5
+#define DEBUG_HDL_smi 9
 #define DEBUG_HDL_pnp 1
 #define DEBUG_HDL_pmm 1
 #define DEBUG_HDL_pcibios 9
index f486c781c855746e51b3e69666e1e55e4bb19761..3d0caa1caf6ef9d9d889c5959ad5e4f494dc6958 100644 (file)
@@ -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.
 #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();
 }
 
index 57e8bcc12785960a810643473f4f29a654d5523d..5b48062218055bc8fbc259d0cb1d4a4a1e732bb3 100644 (file)
@@ -22,6 +22,9 @@
 // Clobbers: ecx, flags, segment registers, cr0, idt/gdt
         DECLFUNC transition32
         .code16gcc
+transition32_for_smi:
+        movl %eax, %ecx
+        jmp 1f
 transition32:
         movl %eax, %ecx
 
@@ -40,7 +43,7 @@ transition32:
         outb %al, $PORT_A20
 
         // Set segment descriptors
-        lidtw %cs:pmode_IDT_info
+1:      lidtw %cs:pmode_IDT_info
         lgdtw %cs:rombios32_gdt_48
 
         // Enable protected mode
@@ -49,12 +52,11 @@ transition32:
         movl %eax, %cr0
 
         // start 32bit protected mode code
-        ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 1f)
+        ljmpl $SEG32_MODE32_CS, $(BUILD_BIOS_ADDR + 2f)
 
         .code32
-1:
         // init data segments
-        movl $SEG32_MODE32_DS, %eax
+2:      movl $SEG32_MODE32_DS, %eax
         movw %ax, %ds
         movw %ax, %es
         movw %ax, %ss
@@ -260,6 +262,18 @@ __farcall16:
  * Misc. entry points.
  ****************************************************************/
 
+// Entry point for QEMU smi interrupts.
+        DECLFUNC entry_smi
+entry_smi:
+        // Transition to 32bit mode.
+        movl $1f + BUILD_BIOS_ADDR, %edx
+        jmp transition32_for_smi
+        .code32
+1:      movl $BUILD_SMM_ADDR, %esp
+        calll _cfunc32flat_handle_smi - BUILD_BIOS_ADDR
+        rsm
+        .code16gcc
+
 // Resume (and reboot) entry point - called from entry_post
         DECLFUNC entry_resume
 entry_resume: