[SeaBIOS] [PATCH 13/15] Implement protected mode exception handlers

Kevin O'Connor kevin at koconnor.net
Thu Oct 1 04:04:16 CET 2015


Support simple exception handlers for General Protection (GP) and Page
Fault (PF) faults.  The handlers will report the issue and halt the
machine.

Signed-off-by: Kevin O'Connor <kevin at koconnor.net>
---
 src/malloc.c    |  2 ++
 src/memmap.c    | 66 +++++++++++++++++++++++++++++++++++++++++++--------------
 src/memmap.h    |  2 ++
 src/romlayout.S | 21 +++++++++++++++---
 src/x86.h       | 22 ++++++++++++++++++-
 5 files changed, 93 insertions(+), 20 deletions(-)

diff --git a/src/malloc.c b/src/malloc.c
index 093b165..ec7a21f 100644
--- a/src/malloc.c
+++ b/src/malloc.c
@@ -445,6 +445,8 @@ malloc_preinit(void)
         alloc_add(&ZoneHigh, highram, highram + BUILD_MAX_HIGHTABLE);
         e820_add(highram, BUILD_MAX_HIGHTABLE, E820_RESERVED);
     }
+
+    memmap_preinit();
 }
 
 void
diff --git a/src/memmap.c b/src/memmap.c
index 51a0123..b08313a 100644
--- a/src/memmap.c
+++ b/src/memmap.c
@@ -5,6 +5,10 @@
 // This file may be distributed under the terms of the GNU LGPLv3 license.
 
 #include "biosvar.h" // struct rmode_IVT
+#include "malloc.h" // malloc_high
+#include "memmap.h" // memmap_preinit
+#include "string.h" // memset
+#include "output.h" // panic
 #include "x86.h" // struct descloc_s
 
 
@@ -12,22 +16,6 @@
  * GDT and IDT tables
  ****************************************************************/
 
-// Real mode IDT descriptor
-struct descloc_s rmode_IDT_info VARFSEG = {
-    .length = sizeof(struct rmode_IVT) - 1,
-    .addr = (u32)MAKE_FLATPTR(SEG_IVT, 0),
-};
-
-// Dummy IDT that forces a machine shutdown if an irq happens in
-// protected mode.
-u8 dummy_IDT VARFSEG;
-
-// Protected mode IDT descriptor
-struct descloc_s pmode_IDT_info VARFSEG = {
-    .length = sizeof(dummy_IDT) - 1,
-    .addr = (u32)&dummy_IDT,
-};
-
 // GDT
 u64 rombios32_gdt[] VARFSEG __aligned(8) = {
     // First entry can't be used.
@@ -51,3 +39,49 @@ struct descloc_s rombios32_gdt_48 VARFSEG = {
     .length = sizeof(rombios32_gdt) - 1,
     .addr = (u32)rombios32_gdt,
 };
+
+// Real mode IDT descriptor
+struct descloc_s rmode_IDT_info VARFSEG = {
+    .length = sizeof(struct rmode_IVT) - 1,
+    .addr = (u32)MAKE_FLATPTR(SEG_IVT, 0),
+};
+
+// Protected mode IDT descriptor
+struct descloc_s pmode_IDT_info VARFSEG;
+
+void VISIBLE32FLAT
+handle_gp(struct x86_exception_stack *data)
+{
+    panic("#GP exception: %x %x %x %x\n", data->error_code, data->eip
+          , data->cs, data->eflags);
+}
+
+void VISIBLE32FLAT
+handle_pf(struct x86_exception_stack *data)
+{
+    panic("#PF exception: %x %x %x %x %x\n", data->error_code, data->eip
+          , data->cs, data->eflags, cr2_read());
+}
+
+// Setup a 32bit General Protection (GP) and Page Fault (PF) handler
+void
+memmap_preinit(void)
+{
+    u32 ilen = sizeof(u64)*(IDT_VECTOR_PF+1);
+    u64 *pidt = malloc_high(ilen);
+    if (!pidt) {
+        warn_noalloc();
+        return;
+    }
+    memset(pidt, 0, ilen);
+    extern void entry_gp(void);
+    extern void entry_pf(void);
+    pidt[IDT_VECTOR_GP] = IDT_IRQ | IDT_SEGMENT(SEG32_MODE32_CS)
+        | IDT_OFFSET((u32)&entry_gp);
+    pidt[IDT_VECTOR_PF] = IDT_IRQ | IDT_SEGMENT(SEG32_MODE32_CS)
+        | IDT_OFFSET((u32)&entry_pf);
+    pmode_IDT_info.addr = virt_to_phys(pidt);
+    pmode_IDT_info.length = ilen-1;
+    dprintf(1, "Installing pmode exception handler\n");
+    lidt(&pmode_IDT_info);
+}
diff --git a/src/memmap.h b/src/memmap.h
index c927ab9..d4f150a 100644
--- a/src/memmap.h
+++ b/src/memmap.h
@@ -7,6 +7,8 @@
 #define PAGE_SIZE 4096
 #define PAGE_SHIFT 12
 
+void memmap_preinit(void);
+
 static inline u32 virt_to_phys(void *v) {
     return (u32)v;
 }
diff --git a/src/romlayout.S b/src/romlayout.S
index 823188b..acf0f32 100644
--- a/src/romlayout.S
+++ b/src/romlayout.S
@@ -42,8 +42,8 @@ transition32:
 
 transition32_nmi_off:
         // Set segment descriptors
-        lidtw %cs:pmode_IDT_info
-        lgdtw %cs:rombios32_gdt_48
+        lidtl %cs:pmode_IDT_info
+        lgdtl %cs:rombios32_gdt_48
 
         // Enable protected mode
         movl %cr0, %ecx
@@ -104,7 +104,7 @@ transition16big:
         ljmpw $SEG_BIOS, $2f
 
         // restore IDT to normal real-mode defaults
-2:      lidtw %cs:rmode_IDT_info
+2:      lidtl %cs:rmode_IDT_info
 
         // Clear segment registers
         xorw %cx, %cx
@@ -412,6 +412,21 @@ __csm_return:
         popfw
         lretw
 
+// Entry point for protected mode exceptions
+        DECLFUNC entry_gp
+        .code32
+entry_gp:
+        movl %esp, %eax
+        calll _cfunc32flat_handle_gp - BUILD_BIOS_ADDR
+        .code16
+
+        DECLFUNC entry_pf
+        .code32
+entry_pf:
+        movl %esp, %eax
+        calll _cfunc32flat_handle_pf - BUILD_BIOS_ADDR
+        .code16
+
 
 /****************************************************************
  * Interrupt entry points
diff --git a/src/x86.h b/src/x86.h
index 53378e9..5de149a 100644
--- a/src/x86.h
+++ b/src/x86.h
@@ -92,6 +92,12 @@ static inline u16 cr0_vm86_read(void) {
     return cr0;
 }
 
+static inline u32 cr2_read(void) {
+    u32 cr2;
+    asm("movl %%cr2, %0" : "=r"(cr2));
+    return cr2;
+}
+
 static inline u64 rdmsr(u32 index)
 {
     u64 ret;
@@ -228,7 +234,7 @@ static inline u8 readb(const void *addr) {
 
 // GDT bits
 #define GDT_CODE     (0x9bULL << 40) // Code segment - P,R,A bits also set
-#define GDT_DATA     (0x93ULL << 40) // Data segment - W,A bits also set
+#define GDT_DATA     (0x93ULL << 40) // Data segment - P,W,A bits also set
 #define GDT_B        (0x1ULL << 54)  // Big flag
 #define GDT_G        (0x1ULL << 55)  // Granularity flag
 // GDT bits for segment base
@@ -239,6 +245,17 @@ static inline u8 readb(const void *addr) {
                       | (((u64)(v) & 0x0000ffff) << 0))
 // GDT bits for segment limit (0-4Gig in 4K chunks)
 #define GDT_GRANLIMIT(v) (GDT_G | GDT_LIMIT((v) >> 12))
+// IDT bits
+#define IDT_IRQ        (0x8eULL << 40) // IRQ gate - P,D bits also set
+#define IDT_OFFSET(v)  ((((u64)(v) & 0xffff0000) << 32)           \
+                        | ((u64)(v) & 0x0000ffff))
+#define IDT_SEGMENT(v) ((u64)(v) << 16)
+#define IDT_VECTOR_GP 13
+#define IDT_VECTOR_PF 14
+
+struct x86_exception_stack {
+    u32 error_code, eip, cs, eflags;
+};
 
 struct descloc_s {
     u16 length;
@@ -251,6 +268,9 @@ static inline void sgdt(struct descloc_s *desc) {
 static inline void lgdt(struct descloc_s *desc) {
     asm("lgdtl %0" : : "m"(*desc) : "memory");
 }
+static inline void lidt(struct descloc_s *desc) {
+    asm("lidtl %0" : : "m"(*desc) : "memory");
+}
 
 static inline u8 get_a20(void) {
     return (inb(PORT_A20) & A20_ENABLE_BIT) != 0;
-- 
2.4.3




More information about the SeaBIOS mailing list