summaryrefslogtreecommitdiff
path: root/kern/interrupt.c
diff options
context:
space:
mode:
Diffstat (limited to 'kern/interrupt.c')
-rw-r--r--kern/interrupt.c51
1 files changed, 33 insertions, 18 deletions
diff --git a/kern/interrupt.c b/kern/interrupt.c
index ad48e5f..e3c2c64 100644
--- a/kern/interrupt.c
+++ b/kern/interrupt.c
@@ -13,6 +13,7 @@
#include <x86/seg.h>
#include <x86/timer_defines.h>
+#include <hvcall_int.h>
#include <keyhelp.h>
#include <simics.h>
#include <stdio.h>
@@ -274,6 +275,8 @@ void sys_swexn();
*/
void sys_enosys();
+void sys_hvcall();
+
/** index of first syscall */
#define IDT_SYSCALL_START (X86_PIC_MASTER_IRQ_BASE + 16)
@@ -282,7 +285,7 @@ void idt_init() {
int i;
for (i = 0; i < IDT_SYSCALL_START; i++) {
- idt[i] = make_idt((va_t)default_handler, IDT_TYPE_I32, IDT_DPL_KERNEL);
+ idt[i] = make_idt((va_t)default_handler, IDT_TYPE_T32, IDT_DPL_KERNEL);
}
idt[IDT_DE] = make_idt((va_t)de_handler, IDT_TYPE_I32, IDT_DPL_KERNEL);
@@ -353,6 +356,8 @@ void idt_init() {
idt[READFILE_INT] =
make_idt((va_t)sys_readfile, IDT_TYPE_T32, IDT_DPL_USER);
idt[SWEXN_INT] = make_idt((va_t)sys_swexn, IDT_TYPE_T32, IDT_DPL_USER);
+
+ idt[HV_INT] = make_idt((va_t)sys_hvcall, IDT_TYPE_T32, IDT_DPL_USER);
}
/** string explanation of fault */
@@ -395,6 +400,8 @@ const static char* reasons[] = {"Division Error",
*/
static void dump_fault(ureg_t* frame);
+static int handle_zfod(ureg_t* frame, thread_t* t);
+
/**
* @brief handle a fault
* @param frame ureg registers
@@ -403,24 +410,9 @@ void handle_fault(ureg_t* frame) {
thread_t* current = get_current();
if (frame->cause == SWEXN_CAUSE_PAGEFAULT && frame->cr2 >= USER_MEM_START) {
/* check ZFOD */
- pa_t old_pa;
- page_directory_t* pd =
- (page_directory_t*)map_phys_page(current->process->cr3, &old_pa);
- pde_t* pde = &(*pd)[get_pd_index(frame->cr2)];
- if (*pde != BAD_PDE) {
- pa_t pt_pa = get_page_table(*pde);
- page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL);
- pte_t* pte = &(*pt)[get_pt_index(frame->cr2)];
- if (*pte != BAD_PTE &&
- ((*pte & (PTE_PRESENT << PTE_P_SHIFT)) == 0)) {
- *pte = (*pte | (PTE_PRESENT << PTE_P_SHIFT));
- invlpg(frame->cr2);
- memset((void*)(frame->cr2 & PAGE_BASE_MASK), 0, PAGE_SIZE);
- map_phys_page(old_pa, NULL);
- return;
- }
+ if (handle_zfod(frame, current) == 0) {
+ return;
}
- map_phys_page(old_pa, NULL);
}
if (frame->cs == SEGSEL_KERNEL_CS) {
/* recover from accessing user memory */
@@ -481,6 +473,29 @@ kill_thread:
kill_current();
}
+static int handle_zfod(ureg_t* frame, thread_t* t) {
+ int result = -1;
+ process_t* p = t->process;
+ int old_if = save_clear_if();
+ pa_t old_pa;
+ page_directory_t* pd = (page_directory_t*)map_phys_page(p->cr3, &old_pa);
+ pde_t* pde = &(*pd)[get_pd_index(frame->cr2)];
+ if (*pde != BAD_PDE) {
+ pa_t pt_pa = get_page_table(*pde);
+ page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL);
+ pte_t* pte = &(*pt)[get_pt_index(frame->cr2)];
+ if (*pte != BAD_PTE && ((*pte & (PTE_PRESENT << PTE_P_SHIFT)) == 0)) {
+ *pte = (*pte | (PTE_PRESENT << PTE_P_SHIFT));
+ invlpg(frame->cr2);
+ memset((void*)(frame->cr2 & PAGE_BASE_MASK), 0, PAGE_SIZE);
+ result = 0;
+ }
+ }
+ map_phys_page(old_pa, NULL);
+ restore_if(old_if);
+ return result;
+}
+
static void dump_fault(ureg_t* frame) {
sim_printf("Fault: %s Error Code: %08x", reasons[frame->cause],
frame->error_code);