[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