summaryrefslogtreecommitdiff
path: root/sys/arch/amd64
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/amd64')
-rw-r--r--sys/arch/amd64/amd64/trap.S5
-rw-r--r--sys/arch/amd64/amd64/trap.c39
2 files changed, 37 insertions, 7 deletions
diff --git a/sys/arch/amd64/amd64/trap.S b/sys/arch/amd64/amd64/trap.S
index 66dd2a9..3cf6888 100644
--- a/sys/arch/amd64/amd64/trap.S
+++ b/sys/arch/amd64/amd64/trap.S
@@ -131,9 +131,8 @@ page_fault:
handle_trap
- /* TODO */
- cli
- hlt
+ pop_trapframe
+ iretq
.globl nmi
nmi:
diff --git a/sys/arch/amd64/amd64/trap.c b/sys/arch/amd64/amd64/trap.c
index 3caaaff..be0493f 100644
--- a/sys/arch/amd64/amd64/trap.c
+++ b/sys/arch/amd64/amd64/trap.c
@@ -35,6 +35,7 @@
#include <sys/signal.h>
#include <sys/proc.h>
#include <sys/sched.h>
+#include <vm/fault.h>
static const char *trap_type[] = {
[TRAP_BREAKPOINT] = "breakpoint",
@@ -53,6 +54,31 @@ static const char *trap_type[] = {
static const int TRAP_COUNT = __ARRAY_COUNT(trap_type);
+
+static inline vaddr_t
+pf_faultaddr(void)
+{
+ uintptr_t cr2;
+ __ASMV("mov %%cr2, %0\n" : "=r" (cr2) :: "memory");
+ return cr2;
+}
+
+static inline vm_prot_t
+pf_accesstype(struct trapframe *tf)
+{
+ vm_prot_t prot = 0;
+ uint64_t ec = tf->error_code;
+
+ if (__TEST(ec, __BIT(1)))
+ prot |= PROT_WRITE;
+ if (__TEST(ec, __BIT(2)))
+ prot |= PROT_USER;
+ if (__TEST(ec, __BIT(4)))
+ prot |= PROT_EXEC;
+
+ return prot;
+}
+
static void
dbg_errcode(struct trapframe *tf)
{
@@ -87,11 +113,10 @@ trap_print(struct trapframe *tf)
static void
regdump(struct trapframe *tf)
{
- uintptr_t cr3, cr2;
+ uintptr_t cr3, cr2 = pf_faultaddr();
- __ASMV("mov %%cr2, %0\n"
- "mov %%cr3, %1\n"
- : "=r" (cr2), "=r" (cr3)
+ __ASMV("mov %%cr3, %0\n"
+ : "=r" (cr3)
:
: "memory"
);
@@ -121,6 +146,7 @@ void
trap_handler(struct trapframe *tf)
{
struct proc *curtd = this_td();
+ int s;
/*
* XXX: Handle NMIs better. For now we just
@@ -142,6 +168,11 @@ trap_handler(struct trapframe *tf)
case TRAP_ARITH_ERR:
signal_raise(curtd, SIGFPE);
break;
+ case TRAP_PAGEFLT:
+ s = vm_fault(pf_faultaddr(), pf_accesstype(tf));
+ if (s != 0)
+ signal_raise(curtd, SIGSEGV);
+ break;
default:
signal_raise(curtd, SIGSEGV);
break;