summaryrefslogtreecommitdiff
path: root/kern
diff options
context:
space:
mode:
authorHanjie Wu <hanjiew@andrew.cmu.edu>2023-04-22 23:25:43 -0400
committerHanjie Wu <hanjiew@andrew.cmu.edu>2023-04-22 23:25:43 -0400
commita7e1cbd3cb53bd4fb43a52a806fd50ab6fa24a24 (patch)
treeed823adb61b2b43d7c4f2f5ca45cff0dd9f66df5 /kern
parented4192548143468362124ee7ee6105c001fe29c0 (diff)
pv
Diffstat (limited to 'kern')
-rw-r--r--kern/hvcall.c674
-rw-r--r--kern/inc/pv.h76
-rw-r--r--kern/inc/sched.h12
-rw-r--r--kern/interrupt.c172
-rw-r--r--kern/interrupt_asm.S11
-rw-r--r--kern/kbd.c2
-rw-r--r--kern/pv.c165
-rw-r--r--kern/sched.c6
-rw-r--r--kern/sched_asm.S9
-rw-r--r--kern/syscall_asm.S109
-rw-r--r--kern/syscall_hvcall.c66
-rw-r--r--kern/syscall_misc.c8
-rw-r--r--kern/timer.c3
-rw-r--r--kern/usermem.c6
14 files changed, 1140 insertions, 179 deletions
diff --git a/kern/hvcall.c b/kern/hvcall.c
new file mode 100644
index 0000000..1513942
--- /dev/null
+++ b/kern/hvcall.c
@@ -0,0 +1,674 @@
+/** @file syscall_hvcall.c
+ *
+ * @brief miscellaneous syscalls.
+ *
+ * @author Hanjie Wu (hanjiew)
+ * @bug No functional bugs
+ */
+
+#include <simics.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <common_kern.h>
+#include <elf/elf_410.h>
+#include <hvcall.h>
+#include <hvcall_int.h>
+#include <malloc_internal.h>
+#include <ureg.h>
+
+#include <x86/asm.h>
+#include <x86/cr.h>
+#include <x86/eflags.h>
+#include <x86/seg.h>
+
+#include <asm_instr.h>
+#include <assert.h>
+#include <console.h>
+#include <loader.h>
+#include <malloc.h>
+#include <mm.h>
+#include <paging.h>
+#include <sched.h>
+#include <sync.h>
+#include <timer.h>
+#include <usermem.h>
+
+#define HV_REFPD_OP HV_RESERVED_0
+#define HV_UNREFPD_OP HV_RESERVED_1
+
+static void hvcall_exit(stack_frame_t* f);
+static void hvcall_iret(stack_frame_t* f);
+static void hvcall_setidt(stack_frame_t* f);
+static void hvcall_setpd(stack_frame_t* f);
+static void hvcall_adjustpg(stack_frame_t* f);
+static void hvcall_print(stack_frame_t* f);
+static void hvcall_set_color(stack_frame_t* f);
+static void hvcall_set_cursor(stack_frame_t* f);
+static void hvcall_get_cursor(stack_frame_t* f);
+static void hvcall_print_at(stack_frame_t* f);
+
+static void hvcall_refpd(int ref);
+
+// 0: not pv, 1: processed
+int handle_pv_syscall(stack_frame_t* f, int index) {
+ if (get_current()->process->pv == NULL) {
+ return 0;
+ }
+ if (f->eip >= USER_MEM_START) {
+ // inject interrupt
+ return 1;
+ }
+ pv_die("Syscall is not allowed for PV kernels");
+ return 1;
+}
+
+void sys_hvcall_real(stack_frame_t* f) {
+ pv_t* pv = get_current()->process->pv;
+ if (pv == NULL || f->eip >= USER_MEM_START) {
+ return;
+ }
+ switch (f->eax) {
+ case HV_MAGIC_OP:
+ f->eax = (reg_t)HV_MAGIC;
+ break;
+ case HV_EXIT_OP:
+ hvcall_exit(f);
+ break;
+ case HV_IRET_OP:
+ hvcall_iret(f);
+ break;
+ case HV_SETIDT_OP:
+ hvcall_setidt(f);
+ break;
+ case HV_DISABLE_OP:
+ pv_mask_interrupt(pv);
+ break;
+ case HV_ENABLE_OP:
+ pv_unmask_interrupt(pv);
+ break;
+ case HV_SETPD_OP:
+ hvcall_setpd(f);
+ break;
+ case HV_ADJUSTPG_OP:
+ hvcall_adjustpg(f);
+ break;
+ case HV_PRINT_OP:
+ hvcall_print(f);
+ break;
+ case HV_SET_COLOR_OP:
+ hvcall_set_color(f);
+ break;
+ case HV_SET_CURSOR_OP:
+ hvcall_set_cursor(f);
+ break;
+ case HV_GET_CURSOR_OP:
+ hvcall_get_cursor(f);
+ break;
+ case HV_PRINT_AT_OP:
+ hvcall_print_at(f);
+ break;
+ case HV_REFPD_OP:
+ hvcall_refpd(1);
+ break;
+ case HV_UNREFPD_OP:
+ hvcall_refpd(0);
+ break;
+ default:
+ pv_die("Bad hvcall number");
+ break;
+ }
+}
+
+static void hvcall_exit(stack_frame_t* f) {
+ reg_t esp = f->esp;
+ int status;
+ if (copy_from_user(esp, sizeof(int), &status) != 0) {
+ goto read_arg_fail;
+ }
+ get_current()->process->exit_value = status;
+ kill_current();
+
+read_arg_fail:
+ pv_die("Bad argument address");
+}
+
+#define EFLAGS_PV_MASK \
+ (EFL_CF | EFL_PF | EFL_AF | EFL_ZF | EFL_SF | EFL_TF | EFL_DF | EFL_OF | \
+ EFL_RF)
+
+static void hvcall_iret(stack_frame_t* f) {
+ thread_t* t = get_current();
+ pv_t* pv = t->process->pv;
+ reg_t esp = f->esp;
+ reg_t regs[5];
+ if (copy_from_user(esp, 5 * sizeof(reg_t), regs) != 0) {
+ goto read_arg_fail;
+ }
+ f->eip = regs[0];
+ reg_t eflags_user = (regs[1] & EFLAGS_PV_MASK);
+ reg_t eflags_kernel = (regs[1] & (~EFLAGS_PV_MASK));
+ if ((eflags_kernel & (~(EFL_IF | EFL_RESV1))) != EFL_IOPL_RING0) {
+ goto bad_eflags;
+ }
+ if ((eflags_kernel & EFL_IF) != 0) {
+ pv_unmask_interrupt(pv);
+ } else {
+ pv_mask_interrupt(pv);
+ }
+ f->eflags = (eflags_user | DEFAULT_EFLAGS);
+ f->esp = regs[2];
+ if (regs[3] != 0) {
+ pv->vesp0 = regs[3];
+ pv_switch_mode(t->process, 0);
+ }
+ f->eax = regs[4];
+ return;
+
+bad_eflags:
+ pv_die("Bad eflags value in iret");
+read_arg_fail:
+ pv_die("Bad argument address");
+}
+
+static void hvcall_setidt(stack_frame_t* f) {
+ reg_t esp = f->esp;
+ int index;
+ va_t eip0;
+ int is_dpl0;
+ if (copy_from_user(esp, sizeof(int), &index) != 0) {
+ goto read_arg_fail;
+ }
+ if (copy_from_user(esp + sizeof(va_t), sizeof(va_t), &eip0) != 0) {
+ goto read_arg_fail;
+ }
+ if (copy_from_user(esp + 2 * sizeof(va_t), sizeof(int), &is_dpl0) != 0) {
+ goto read_arg_fail;
+ }
+ if (index < 0 || index >= IDT_ENTS) {
+ goto bad_idt_index;
+ }
+ pv_t* pv = get_current()->process->pv;
+ pv_idt_entry_t* idt = pv_classify_interrupt(pv, index);
+ idt->eip = eip0;
+ idt->desc = ((idt->desc & (~VIDT_DPL_MASK)) |
+ (is_dpl0 != 0 ? VIDT_DPL_0 : VIDT_DPL_3));
+ return;
+
+bad_idt_index:
+ pv_die("Bad IDT index");
+read_arg_fail:
+ pv_die("Bad argument address");
+}
+
+static pv_pd_t* translate_pv_pd(pv_t* pv, pa_t pd, int wp);
+
+static void hvcall_setpd(stack_frame_t* f) {
+ thread_t* t = get_current();
+ pv_t* pv = t->process->pv;
+ reg_t esp = f->esp;
+ pa_t pd;
+ int wp;
+ if (copy_from_user(esp, sizeof(pa_t), &pd) != 0) {
+ goto read_arg_fail;
+ }
+ if (copy_from_user(esp + sizeof(va_t), sizeof(int), &wp) != 0) {
+ goto read_arg_fail;
+ }
+ if ((pd & PAGE_OFFSET_MASK) != 0) {
+ goto bad_cr3;
+ }
+ pv_pd_t* pv_pd = translate_pv_pd(pv, pd, wp);
+ if (pv_pd == NULL) {
+ goto alloc_pd_fail;
+ }
+ queue_insert_head(&pv->shadow_pds, &pv_pd->pv_link);
+ select_pv_pd(t->process, pv_pd);
+ return;
+
+alloc_pd_fail:
+ pv_die("Page table translation failed");
+bad_cr3:
+ pv_die("Bad page directory address");
+read_arg_fail:
+ pv_die("Bad argument address");
+}
+
+#define PDE_RESV_MASK 0xf00
+#define PTE_RESV_MASK 0xe00
+
+static pv_pd_t* translate_pv_pd(pv_t* pv, pa_t pd, int wp) {
+ pa_t mem_limit = pv->n_pages * PAGE_SIZE;
+ pa_t overflow_pa = machine_phys_frames() * PAGE_SIZE;
+
+ char* temp_space = smalloc(4 * PAGE_SIZE);
+ if (temp_space == NULL) {
+ goto alloc_temp_fail;
+ }
+ page_directory_t* t_pd = (page_directory_t*)(temp_space);
+ page_table_t* t_pt = (page_table_t*)(temp_space + PAGE_SIZE);
+ page_directory_t* t_user_pd =
+ (page_directory_t*)(temp_space + 2 * PAGE_SIZE);
+ page_table_t* t_user_pt = (page_table_t*)(temp_space + 3 * PAGE_SIZE);
+
+ pv_pd_t* pv_pd = smalloc(sizeof(pv_pd_t));
+ if (pv_pd == NULL) {
+ goto alloc_pv_pd_fail;
+ }
+ pa_t cr3 = alloc_user_pages(1);
+ if (cr3 == BAD_PA) {
+ goto alloc_cr3_fail;
+ }
+ int old_if = save_clear_if();
+ memset((void*)map_phys_page(cr3, NULL), 0, PAGE_SIZE);
+ restore_if(old_if);
+
+ pa_t user_cr3 = alloc_user_pages(1);
+ if (user_cr3 == BAD_PA) {
+ free_user_pages(cr3, 1);
+ goto alloc_user_cr3_fail;
+ }
+ old_if = save_clear_if();
+ memset((void*)map_phys_page(user_cr3, NULL), 0, PAGE_SIZE);
+ restore_if(old_if);
+
+ memset(t_pd, 0, PAGE_SIZE);
+ memset(t_user_pd, 0, PAGE_SIZE);
+ int i;
+ for (i = 0; i < USER_PD_START; i++) {
+ (*t_pd)[i] = (*kernel_pd)[i];
+ (*t_user_pd)[i] = (*kernel_pd)[i];
+ }
+ old_if = save_clear_if();
+ if (pd >= mem_limit) {
+ goto bad_pt;
+ }
+ pd += pv->mem_base;
+ for (i = 0; i < NUM_PAGE_ENTRY - USER_PD_START; i++) {
+ page_directory_t* old_pd = (page_directory_t*)map_phys_page(pd, NULL);
+ pde_t old_pde = (*old_pd)[i];
+ if ((old_pde & (PTE_PRESENT << PTE_P_SHIFT)) == 0) {
+ continue;
+ }
+ pa_t pt_pa = get_page_table(old_pde);
+ if (pt_pa >= mem_limit) {
+ goto bad_pt;
+ }
+ pt_pa += pv->mem_base;
+ page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL);
+ int j;
+ for (j = 0; j < NUM_PAGE_ENTRY; j++) {
+ pte_t old_pte = (*pt)[j];
+ if ((old_pte & (PTE_PRESENT << PTE_P_SHIFT)) == 0) {
+ (*t_pt)[j] = BAD_PTE;
+ (*t_user_pt)[j] = BAD_PTE;
+ continue;
+ }
+ pa_t pa = get_page_base(old_pte);
+ if (pa > mem_limit) {
+ pa = overflow_pa;
+ } else {
+ pa = pv->mem_base + pa;
+ }
+ int old_us = (old_pte & (1 << PTE_US_SHIFT));
+ int old_rw = (old_pte & (1 << PTE_RW_SHIFT));
+ int new_mask, new_user_mask;
+ if (wp == 0) {
+ new_mask = ((1 << PTE_P_SHIFT) | (PTE_RW << PTE_RW_SHIFT) |
+ (PTE_USER << PTE_US_SHIFT));
+ } else {
+ new_mask =
+ ((1 << PTE_P_SHIFT) | old_rw | (PTE_USER << PTE_US_SHIFT));
+ }
+ if (old_us != 0) {
+ new_user_mask =
+ ((1 << PTE_P_SHIFT) | old_rw | (PTE_USER << PTE_US_SHIFT));
+ } else {
+ new_user_mask = 0;
+ }
+ (*t_pt)[j] =
+ ((pa & PAGE_BASE_MASK) | (old_pte & PTE_RESV_MASK) | new_mask);
+ (*t_user_pt)[j] = (new_user_mask == 0 ? BAD_PTE
+ : ((pa & PAGE_BASE_MASK) |
+ (old_pte & PTE_RESV_MASK) |
+ new_user_mask));
+ }
+ pa_t new_pt = alloc_user_pages(1);
+ if (new_pt == BAD_PA) {
+ goto alloc_pt_fail;
+ }
+ pa_t new_user_pt = alloc_user_pages(1);
+ if (new_user_pt == BAD_PA) {
+ free_user_pages(new_pt, 1);
+ goto alloc_pt_fail;
+ }
+ memcpy((void*)map_phys_page(new_pt, NULL), t_pt, PAGE_SIZE);
+ memcpy((void*)map_phys_page(new_user_pt, NULL), t_user_pt, PAGE_SIZE);
+ pde_t new_pde = ((old_pde & PDE_RESV_MASK) |
+ (PTE_USER << PTE_US_SHIFT) | (1 << PTE_P_SHIFT));
+ if (wp == 0) {
+ new_pde |= (PTE_RW << PTE_RW_SHIFT);
+ } else {
+ new_pde |= (old_pde & (1 << PTE_RW_SHIFT));
+ }
+ (*t_pd)[USER_PD_START + i] = (new_pt | new_pde);
+ (*t_user_pd)[USER_PD_START + i] = (new_user_pt | new_pde);
+ }
+ memcpy((void*)map_phys_page(cr3, NULL), t_pd, PAGE_SIZE);
+ memcpy((void*)map_phys_page(user_cr3, NULL), t_user_pd, PAGE_SIZE);
+ restore_if(old_if);
+ sfree(temp_space, 4 * PAGE_SIZE);
+ pv_pd->guest_pd = pd;
+ pv_pd->wp = wp;
+ pv_pd->cr3 = cr3;
+ pv_pd->user_cr3 = user_cr3;
+ pv_pd->refcount = 0;
+ return pv_pd;
+
+bad_pt:
+alloc_pt_fail:
+ memcpy((void*)map_phys_page(cr3, NULL), t_pd, PAGE_SIZE);
+ memcpy((void*)map_phys_page(user_cr3, NULL), t_user_pd, PAGE_SIZE);
+ restore_if(old_if);
+ destroy_pd(cr3);
+ destroy_pd(user_cr3);
+alloc_user_cr3_fail:
+alloc_cr3_fail:
+ sfree(pv_pd, sizeof(pv_pd_t));
+alloc_pv_pd_fail:
+ sfree(temp_space, 4 * PAGE_SIZE);
+alloc_temp_fail:
+ return NULL;
+}
+
+static void hvcall_adjustpg(stack_frame_t* f) {
+ thread_t* t = get_current();
+ pv_t* pv = t->process->pv;
+ pv_pd_t* pv_pd = pv->active_shadow_pd;
+ reg_t esp = f->esp;
+ va_t addr;
+ if (copy_from_user(esp, sizeof(va_t), &addr) != 0) {
+ goto read_arg_fail;
+ }
+ if ((addr & PAGE_OFFSET_MASK) != 0 || addr >= PV_VM_LIMIT) {
+ goto bad_addr;
+ }
+ pa_t mem_limit = pv->n_pages * PAGE_SIZE;
+
+ pa_t pt_pa, user_pt_pa;
+ int old_if = save_clear_if();
+ page_directory_t* old_pd =
+ (page_directory_t*)map_phys_page(pv_pd->guest_pd, NULL);
+ pde_t old_pde = (*old_pd)[get_pd_index(addr)];
+ if ((old_pde & (1 << PTE_P_SHIFT)) == 0) {
+ page_directory_t* pd =
+ (page_directory_t*)map_phys_page(pv_pd->cr3, NULL);
+ pde_t* pde = &(*pd)[get_pd_index(addr) + USER_PD_START];
+ if (*pde != BAD_PDE) {
+ pt_pa = get_page_table(*pde);
+ *pde = BAD_PDE;
+ free_user_pages(pt_pa, 1);
+ }
+ page_directory_t* user_pd =
+ (page_directory_t*)map_phys_page(pv_pd->user_cr3, NULL);
+ pde_t* user_pde = &(*user_pd)[get_pd_index(addr) + USER_PD_START];
+ if (*user_pde != BAD_PDE) {
+ user_pt_pa = get_page_table(*user_pde);
+ *user_pde = BAD_PDE;
+ free_user_pages(user_pt_pa, 1);
+ }
+ } else {
+ pde_t new_pde = ((old_pde & PDE_RESV_MASK) |
+ (PTE_USER << PTE_US_SHIFT) | (1 << PTE_P_SHIFT));
+ if (pv_pd->wp == 0) {
+ new_pde |= (PTE_RW << PTE_RW_SHIFT);
+ } else {
+ new_pde |= (old_pde & (1 << PTE_RW_SHIFT));
+ }
+ page_directory_t* pd =
+ (page_directory_t*)map_phys_page(pv_pd->cr3, NULL);
+ pde_t* pde = &(*pd)[get_pd_index(addr) + USER_PD_START];
+ if (*pde != BAD_PDE) {
+ pt_pa = get_page_table(*pde);
+ *pde = (pt_pa | new_pde);
+ } else {
+ pt_pa = alloc_user_pages(1);
+ if (pt_pa == BAD_PA) {
+ goto alloc_pt_fail;
+ }
+ *pde = (pt_pa | new_pde);
+ memset((void*)map_phys_page(pt_pa, NULL), 0, PAGE_SIZE);
+ }
+ page_directory_t* user_pd =
+ (page_directory_t*)map_phys_page(pv_pd->user_cr3, NULL);
+ pde_t* user_pde = &(*user_pd)[get_pd_index(addr) + USER_PD_START];
+ if (*user_pde != BAD_PDE) {
+ user_pt_pa = get_page_table(*user_pde);
+ *user_pde = (user_pt_pa | new_pde);
+ } else {
+ user_pt_pa = alloc_user_pages(1);
+ if (user_pt_pa == BAD_PA) {
+ goto alloc_pt_fail;
+ }
+ *user_pde = (user_pt_pa | new_pde);
+ memset((void*)map_phys_page(user_pt_pa, NULL), 0, PAGE_SIZE);
+ }
+ pa_t old_pt_pa = get_page_table(old_pde);
+ if (old_pt_pa >= mem_limit) {
+ goto bad_pt;
+ }
+ old_pt_pa += pv->mem_base;
+ page_table_t* old_pt = (page_table_t*)map_phys_page(old_pt_pa, NULL);
+ pte_t old_pte = (*old_pt)[get_pt_index(addr)];
+ pte_t pte, user_pte;
+ if ((old_pte & (PTE_PRESENT << PTE_P_SHIFT)) == 0) {
+ user_pte = pte = BAD_PTE;
+ } else {
+ pa_t pa = get_page_base(old_pte);
+ if (pa > mem_limit) {
+ pa = machine_phys_frames() * PAGE_SIZE;
+ } else {
+ pa = pv->mem_base + pa;
+ }
+ int old_us = (old_pte & (1 << PTE_US_SHIFT));
+ int old_rw = (old_pte & (1 << PTE_RW_SHIFT));
+ int new_mask, new_user_mask;
+ if (pv_pd->wp == 0) {
+ new_mask = ((1 << PTE_P_SHIFT) | (PTE_RW << PTE_RW_SHIFT) |
+ (PTE_USER << PTE_US_SHIFT));
+ } else {
+ new_mask =
+ ((1 << PTE_P_SHIFT) | old_rw | (PTE_USER << PTE_US_SHIFT));
+ }
+ if (old_us != 0) {
+ new_user_mask =
+ ((1 << PTE_P_SHIFT) | old_rw | (PTE_USER << PTE_US_SHIFT));
+ } else {
+ new_user_mask = 0;
+ }
+ pte =
+ ((pa & PAGE_BASE_MASK) | (old_pte & PTE_RESV_MASK) | new_mask);
+ user_pte = (new_user_mask == 0
+ ? BAD_PTE
+ : ((pa & PAGE_BASE_MASK) |
+ (old_pte & PTE_RESV_MASK) | new_user_mask));
+ }
+ page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL);
+ (*pt)[get_pt_index(addr)] = pte;
+ page_table_t* user_pt = (page_table_t*)map_phys_page(user_pt_pa, NULL);
+ (*user_pt)[get_pt_index(addr)] = user_pte;
+ }
+ restore_if(old_if);
+ invlpg(addr);
+ return;
+
+bad_pt:
+ restore_if(old_if);
+ pv_die("Bad page table address");
+alloc_pt_fail:
+ restore_if(old_if);
+ pv_die("Failed to alloc page table");
+bad_addr:
+ pv_die("Unaligned virtual address");
+read_arg_fail:
+ pv_die("Bad argument address");
+}
+
+static void hvcall_print(stack_frame_t* f) {
+ reg_t esp = f->esp;
+ int len;
+ va_t base;
+ if (copy_from_user(esp, sizeof(int), &len) != 0) {
+ goto read_arg_fail;
+ }
+ if (copy_from_user(esp + sizeof(va_t), sizeof(va_t), &base) != 0) {
+ goto read_arg_fail;
+ }
+ if (len < 0) {
+ goto bad_length;
+ }
+ mutex_lock(&console_lock);
+ int result = print_buf_from_user(base, len);
+ mutex_unlock(&console_lock);
+ if (result != 0) {
+ goto print_fail;
+ }
+ return;
+
+print_fail:
+ pv_die("Error when printing buffer");
+bad_length:
+ pv_die("Bad buffer length");
+read_arg_fail:
+ pv_die("Bad argument address");
+}
+
+static void hvcall_set_color(stack_frame_t* f) {
+ reg_t esp = f->esp;
+ int color;
+ if (copy_from_user(esp, sizeof(int), &color) != 0) {
+ goto read_arg_fail;
+ }
+ mutex_lock(&console_lock);
+ int result = set_term_color(color);
+ mutex_unlock(&console_lock);
+ if (result != 0) {
+ goto set_fail;
+ }
+ return;
+
+set_fail:
+ pv_die("Error when setting color");
+read_arg_fail:
+ pv_die("Bad argument address");
+}
+
+static void hvcall_set_cursor(stack_frame_t* f) {
+ reg_t esp = f->esp;
+ int row, col;
+ if (copy_from_user(esp, sizeof(int), &row) != 0) {
+ goto read_arg_fail;
+ }
+ if (copy_from_user(esp + sizeof(va_t), sizeof(int), &col) != 0) {
+ goto read_arg_fail;
+ }
+ mutex_lock(&console_lock);
+ int result = set_cursor(row, col);
+ mutex_unlock(&console_lock);
+ if (result != 0) {
+ goto set_fail;
+ }
+ return;
+
+set_fail:
+ pv_die("Error when setting cursor position");
+read_arg_fail:
+ pv_die("Bad argument address");
+}
+
+static void hvcall_get_cursor(stack_frame_t* f) {
+ reg_t esp = f->esp;
+ va_t prow, pcol;
+ if (copy_from_user(esp, sizeof(va_t), &prow) != 0) {
+ goto read_arg_fail;
+ }
+ if (copy_from_user(esp + sizeof(va_t), sizeof(va_t), &pcol) != 0) {
+ goto read_arg_fail;
+ }
+ int row, col;
+ mutex_lock(&console_lock);
+ get_cursor(&row, &col);
+ mutex_unlock(&console_lock);
+ if (copy_to_user(prow, sizeof(int), &row) != 0) {
+ goto bad_arg;
+ }
+ if (copy_to_user(pcol, sizeof(int), &col) != 0) {
+ goto bad_arg;
+ }
+ return;
+
+bad_arg:
+read_arg_fail:
+ pv_die("Bad argument address");
+}
+
+static void hvcall_print_at(stack_frame_t* f) {
+ reg_t esp = f->esp;
+ int len;
+ va_t base;
+ int row, col, old_row, old_col;
+ int color, old_color;
+ if (copy_from_user(esp, sizeof(int), &len) != 0) {
+ goto read_arg_fail;
+ }
+ if (copy_from_user(esp + sizeof(va_t), sizeof(va_t), &base) != 0) {
+ goto read_arg_fail;
+ }
+ if (copy_from_user(esp + 2 * sizeof(va_t), sizeof(int), &row) != 0) {
+ goto read_arg_fail;
+ }
+ if (copy_from_user(esp + 3 * sizeof(va_t), sizeof(int), &col) != 0) {
+ goto read_arg_fail;
+ }
+ if (copy_from_user(esp + 4 * sizeof(va_t), sizeof(int), &color) != 0) {
+ goto read_arg_fail;
+ }
+ mutex_lock(&console_lock);
+ get_cursor(&old_row, &old_col);
+ if (set_cursor(row, col) != 0) {
+ goto bad_pos;
+ }
+ get_term_color(&old_color);
+ if (set_term_color(color) != 0) {
+ goto bad_color;
+ }
+ if (print_buf_from_user(base, len) != 0) {
+ goto bad_print;
+ }
+ set_term_color(old_color);
+ set_cursor(old_row, old_col);
+ mutex_unlock(&console_lock);
+ return;
+
+bad_print:
+ set_term_color(old_color);
+bad_color:
+ set_cursor(old_row, old_col);
+bad_pos:
+ mutex_unlock(&console_lock);
+ pv_die("Bad argument");
+read_arg_fail:
+ pv_die("Bad argument address");
+}
+
+static void hvcall_refpd(int ref) {
+ pv_t* pv = get_current()->process->pv;
+ if (ref == 1) {
+ pv->active_shadow_pd->refcount++;
+ } else {
+ pv->active_shadow_pd->refcount--;
+ if (pv->active_shadow_pd->refcount <= 0) {
+ pv_die("Page table destroyed by kerenl");
+ }
+ }
+}
diff --git a/kern/inc/pv.h b/kern/inc/pv.h
index 7cd8c50..550446c 100644
--- a/kern/inc/pv.h
+++ b/kern/inc/pv.h
@@ -1,8 +1,12 @@
#ifndef _PV_H_
#define _PV_H_
+#include <stdlib.h>
+
#include <common_kern.h>
#include <elf/elf_410.h>
+#include <ureg.h>
+#include <x86/eflags.h>
#include <x86/idt.h>
#include <x86/seg.h>
@@ -19,7 +23,7 @@
#define SEGSEL_PV_FS (SEGSEL_SPARE3 | SEGSEL_RPL3)
#define SEGSEL_PV_FS_IDX SEGSEL_SPARE3_IDX
-#define PV_VM_LIMIT (~(USER_MEM_START - 1))
+#define PV_VM_LIMIT (va_t)(~(USER_MEM_START - 1))
#define PV_DEFAULT_SIZE 24
#define PV_MINIMUM_SIZE 20
@@ -27,18 +31,40 @@
typedef struct pv_pd_s {
int refcount;
queue_t pv_link;
+ pa_t guest_pd;
+ int wp;
pa_t cr3;
pa_t user_cr3;
} pv_pd_t;
+#define VIDT_DPL_0 0
+#define VIDT_DPL_3 3
+#define VIDT_DPL_MASK 3
+
typedef struct pv_idt_entry_s {
va_t eip;
- int dpl;
+ int desc;
} pv_idt_entry_t;
-typedef pv_idt_entry_t pv_idt_t[IDT_ENTS];
+#define PV_FAULT_START 0
+#define PV_FAULT_END 20
+#define PV_IRQ_START 32
+#define PV_IRQ_END 34
+#define PV_SYSCALL_1_START 65
+#define PV_SYSCALL_1_END 117
+#define PV_SYSCALL_2_START 128
+#define PV_SYSCALL_2_END 135
+
+typedef struct pv_idt_s {
+ pv_idt_entry_t fault[PV_FAULT_END - PV_FAULT_START];
+ pv_idt_entry_t irq[PV_IRQ_END - PV_IRQ_START];
+ pv_idt_entry_t syscall_1[PV_SYSCALL_1_END - PV_SYSCALL_1_START];
+ pv_idt_entry_t syscall_2[PV_SYSCALL_2_END - PV_SYSCALL_2_START];
+} pv_idt_t;
typedef struct pv_s {
+ int n_pages;
+ pa_t mem_base;
int vif;
pv_pd_t* active_shadow_pd;
queue_t* shadow_pds;
@@ -58,6 +84,50 @@ thread_t* create_pv_process(thread_t* t,
char* exe,
va_size_t mem_size);
+static inline void pv_mask_interrupt(pv_t* pv) {
+ pv->vif = 0;
+}
+
+static inline void pv_unmask_interrupt(pv_t* pv) {
+ pv->vif = EFL_IF;
+}
+
+static inline pv_idt_entry_t* pv_classify_interrupt(pv_t* pv, int index) {
+ if (index >= PV_FAULT_START && index < PV_FAULT_END) {
+ return &pv->vidt.fault[index - PV_FAULT_START];
+ }
+ if (index >= PV_IRQ_START && index < PV_IRQ_END) {
+ return &pv->vidt.irq[index - PV_IRQ_START];
+ }
+ if (index >= PV_SYSCALL_1_START && index < PV_SYSCALL_1_END) {
+ return &pv->vidt.syscall_1[index - PV_SYSCALL_1_START];
+ }
+ if (index >= PV_SYSCALL_2_START && index < PV_SYSCALL_2_END) {
+ return &pv->vidt.syscall_2[index - PV_SYSCALL_2_START];
+ }
+ return NULL;
+}
+
void destroy_pv(pv_t* pv);
+void pv_die(char* reason);
+
+void pv_switch_mode(process_t* p, int kernelmode);
+
+void select_pv_pd(process_t* p, pv_pd_t* pv_pd);
+
+void pv_handle_fault(ureg_t* frame, thread_t* t);
+
+struct stack_frame_s;
+typedef struct stack_frame_s stack_frame_t;
+int pv_inject_interrupt(stack_frame_t* f, int index, int arg);
+
+typedef struct pv_frame_s {
+ reg_t cr2;
+ reg_t error_code;
+ reg_t eip;
+ reg_t vcs;
+ reg_t eflags;
+} pv_frame_t;
+
#endif
diff --git a/kern/inc/sched.h b/kern/inc/sched.h
index 8fc0108..eddb849 100644
--- a/kern/inc/sched.h
+++ b/kern/inc/sched.h
@@ -231,6 +231,18 @@ int add_region(process_t* p, va_t vaddr, int n_pages, pa_t pa, int is_rw);
*/
pa_t find_or_create_pt(process_t* p, va_t vaddr);
+/**
+ * @brief set fs
+ * @param fs fs
+ */
+void set_fs(reg_t fs);
+
+/**
+ * @brief set gs
+ * @param gs gs
+ */
+void set_gs(reg_t gs);
+
/** CPU specific varibles */
typedef struct percpu_s {
thread_t* current; /* current running thread */
diff --git a/kern/interrupt.c b/kern/interrupt.c
index e3c2c64..467c7c9 100644
--- a/kern/interrupt.c
+++ b/kern/interrupt.c
@@ -25,6 +25,7 @@
#include <interrupt.h>
#include <mm.h>
#include <paging.h>
+#include <pv.h>
#include <sched.h>
#include <sync.h>
#include <timer.h>
@@ -55,6 +56,8 @@
/** EIP's low part's bits */
#define IDT_EIP_LO_MASK 0x0000ffff
+#define IDT_FAULT_15 15
+
/**
* @brief an idt entry
*/
@@ -139,6 +142,10 @@ int gp_handler();
*/
int pf_handler();
/**
+ * @brief Fault 15 entry
+ */
+int fault_15_handler();
+/**
* @brief MF handler entry
*/
int mf_handler();
@@ -270,10 +277,38 @@ void sys_readfile();
*/
void sys_swexn();
+void sys_67();
+void sys_86();
+void sys_97();
+void sys_99();
+void sys_100();
+void sys_101();
+void sys_102();
+void sys_103();
+void sys_104();
+void sys_105();
+void sys_106();
+void sys_107();
+void sys_108();
+void sys_109();
+void sys_110();
+void sys_111();
+void sys_112();
+void sys_113();
+void sys_114();
+void sys_115();
+void sys_128();
+void sys_129();
+void sys_130();
+void sys_131();
+void sys_132();
+void sys_133();
+void sys_134();
+
/**
* @brief all other syscall entries
*/
-void sys_enosys();
+void sys_nonexist();
void sys_hvcall();
@@ -303,6 +338,8 @@ void idt_init() {
idt[IDT_SS] = make_idt((va_t)ss_handler, IDT_TYPE_I32, IDT_DPL_KERNEL);
idt[IDT_GP] = make_idt((va_t)gp_handler, IDT_TYPE_I32, IDT_DPL_KERNEL);
idt[IDT_PF] = make_idt((va_t)pf_handler, IDT_TYPE_I32, IDT_DPL_KERNEL);
+ idt[IDT_FAULT_15] =
+ make_idt((va_t)fault_15_handler, IDT_TYPE_I32, IDT_DPL_KERNEL);
idt[IDT_MF] = make_idt((va_t)mf_handler, IDT_TYPE_I32, IDT_DPL_KERNEL);
idt[IDT_AC] = make_idt((va_t)ac_handler, IDT_TYPE_I32, IDT_DPL_KERNEL);
idt[IDT_MC] = make_idt((va_t)mc_handler, IDT_TYPE_I32, IDT_DPL_KERNEL);
@@ -314,11 +351,12 @@ void idt_init() {
make_idt((va_t)kbd_handler, IDT_TYPE_I32, IDT_DPL_KERNEL);
for (i = IDT_SYSCALL_START; i < IDT_ENTS; i++) {
- idt[i] = make_idt((va_t)sys_enosys, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[i] = make_idt((va_t)sys_nonexist, IDT_TYPE_T32, IDT_DPL_USER);
}
idt[FORK_INT] = make_idt((va_t)sys_fork, IDT_TYPE_T32, IDT_DPL_USER);
idt[EXEC_INT] = make_idt((va_t)sys_exec, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[67] = make_idt((va_t)sys_67, IDT_TYPE_T32, IDT_DPL_USER);
idt[WAIT_INT] = make_idt((va_t)sys_wait, IDT_TYPE_T32, IDT_DPL_USER);
idt[YIELD_INT] = make_idt((va_t)sys_yield, IDT_TYPE_T32, IDT_DPL_USER);
idt[DESCHEDULE_INT] =
@@ -348,15 +386,42 @@ void idt_init() {
idt[MISBEHAVE_INT] =
make_idt((va_t)sys_misbehave, IDT_TYPE_T32, IDT_DPL_USER);
idt[HALT_INT] = make_idt((va_t)sys_halt, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[86] = make_idt((va_t)sys_86, IDT_TYPE_T32, IDT_DPL_USER);
idt[TASK_VANISH_INT] =
make_idt((va_t)sys_task_vanish, IDT_TYPE_T32, IDT_DPL_USER);
idt[SET_STATUS_INT] =
make_idt((va_t)sys_set_status, IDT_TYPE_T32, IDT_DPL_USER);
idt[VANISH_INT] = make_idt((va_t)sys_vanish, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[97] = make_idt((va_t)sys_97, IDT_TYPE_T32, IDT_DPL_USER);
idt[READFILE_INT] =
make_idt((va_t)sys_readfile, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[99] = make_idt((va_t)sys_99, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[100] = make_idt((va_t)sys_100, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[101] = make_idt((va_t)sys_101, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[102] = make_idt((va_t)sys_102, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[103] = make_idt((va_t)sys_103, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[104] = make_idt((va_t)sys_104, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[105] = make_idt((va_t)sys_105, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[106] = make_idt((va_t)sys_106, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[107] = make_idt((va_t)sys_107, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[108] = make_idt((va_t)sys_108, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[109] = make_idt((va_t)sys_109, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[110] = make_idt((va_t)sys_110, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[111] = make_idt((va_t)sys_111, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[112] = make_idt((va_t)sys_112, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[113] = make_idt((va_t)sys_113, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[114] = make_idt((va_t)sys_114, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[115] = make_idt((va_t)sys_115, IDT_TYPE_T32, IDT_DPL_USER);
idt[SWEXN_INT] = make_idt((va_t)sys_swexn, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[128] = make_idt((va_t)sys_128, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[129] = make_idt((va_t)sys_129, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[130] = make_idt((va_t)sys_130, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[131] = make_idt((va_t)sys_131, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[132] = make_idt((va_t)sys_132, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[133] = make_idt((va_t)sys_133, IDT_TYPE_T32, IDT_DPL_USER);
+ idt[134] = make_idt((va_t)sys_134, IDT_TYPE_T32, IDT_DPL_USER);
+
idt[HV_INT] = make_idt((va_t)sys_hvcall, IDT_TYPE_T32, IDT_DPL_USER);
}
@@ -401,6 +466,8 @@ const static char* reasons[] = {"Division Error",
static void dump_fault(ureg_t* frame);
static int handle_zfod(ureg_t* frame, thread_t* t);
+static void handle_kernel_fault(ureg_t* frame, thread_t* t);
+static void handle_user_fault(ureg_t* frame, thread_t* t);
/**
* @brief handle a fault
@@ -414,22 +481,57 @@ void handle_fault(ureg_t* frame) {
return;
}
}
- if (frame->cs == SEGSEL_KERNEL_CS) {
- /* recover from accessing user memory */
- if ((frame->cause == SWEXN_CAUSE_PAGEFAULT ||
- frame->cause == SWEXN_CAUSE_PROTFAULT) &&
- current->eip0 != 0) {
- frame->eip = current->eip0;
- return;
- }
- /* all other non recoverable fault */
- dump_fault(frame);
- while (1) {
+ if (frame->cs == SEGSEL_PV_CS) {
+ pv_handle_fault(frame, current);
+ return;
+ } else if (frame->cs == SEGSEL_KERNEL_CS) {
+ handle_kernel_fault(frame, current);
+ return;
+ }
+ handle_user_fault(frame, 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 handle_kernel_fault(ureg_t* frame, thread_t* t) {
+ /* recover from accessing user memory */
+ if ((frame->cause == SWEXN_CAUSE_PAGEFAULT ||
+ frame->cause == SWEXN_CAUSE_PROTFAULT) &&
+ t->eip0 != 0) {
+ frame->eip = t->eip0;
+ return;
+ }
+ /* all other non recoverable fault */
+ dump_fault(frame);
+ while (1) {
+ }
+}
+
+static void handle_user_fault(ureg_t* frame, thread_t* t) {
/* send to user swexn */
- if (current->eip3 != 0 && current->df3 == 0) {
- va_t esp3 = (va_t)current->esp3;
+ if (t->eip3 != 0 && t->df3 == 0) {
+ va_t esp3 = (va_t)t->esp3;
esp3 -= sizeof(ureg_t);
esp3 = (esp3 & (~(sizeof(va_t) - 1)));
/* push ureg */
@@ -440,7 +542,7 @@ void handle_fault(ureg_t* frame) {
* swexn handler must call swexn to jump back, we use 0 address to cause
* a GP on function return
*/
- unsigned long stack[3] = {0, current->swexn_arg, (unsigned long)esp3};
+ unsigned long stack[3] = {0, t->swexn_arg, (unsigned long)esp3};
unsigned long* new_esp = (unsigned long*)esp3;
new_esp -= 3;
if (copy_to_user((va_t)new_esp, 3 * sizeof(unsigned long), stack) !=
@@ -455,47 +557,23 @@ void handle_fault(ureg_t* frame) {
frame->edx = 0;
frame->ecx = 0;
frame->eax = 0;
- frame->eip = current->eip3;
+ frame->eip = t->eip3;
frame->eflags = DEFAULT_EFLAGS;
frame->esp = (unsigned int)new_esp;
- current->df3 = 1;
- current->eip3 = 0;
+ t->df3 = 1;
+ t->eip3 = 0;
return;
}
/* no swexn handler or fault inside swexn */
kill_thread:
- sim_printf("LWP %d killed: %s", current->rb_node.key,
- reasons[frame->cause]);
- printf("LWP %d killed: %s\n", current->rb_node.key, reasons[frame->cause]);
- if (current->process->refcount == 1) {
- current->process->exit_value = -2;
+ sim_printf("LWP %d killed: %s", t->rb_node.key, reasons[frame->cause]);
+ printf("LWP %d killed: %s\n", t->rb_node.key, reasons[frame->cause]);
+ if (t->process->refcount == 1) {
+ t->process->exit_value = -2;
}
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);
diff --git a/kern/interrupt_asm.S b/kern/interrupt_asm.S
index 3941d16..2a5b098 100644
--- a/kern/interrupt_asm.S
+++ b/kern/interrupt_asm.S
@@ -15,7 +15,7 @@
default_handler:
iret
-.macro FAULT_HANDLER_ERR name cause
+.macro FAULT_HANDLER_ERR name cause
.global \name\()_handler
.type \name\()_handler, %function
\name\()_handler:
@@ -45,11 +45,11 @@ default_handler:
iret
.endm
-.macro FAULT_HANDLER_NOERR name cause
+.macro FAULT_HANDLER_NOERR name cause
.global \name\()_handler
.type \name\()_handler, %function
\name\()_handler:
- sub $0x4, %esp /* dummy error code */
+ push $0 /* dummy error code */
pusha
push %gs
push %fs
@@ -91,6 +91,7 @@ FAULT_HANDLER_ERR np 0xb
FAULT_HANDLER_ERR ss 0xc
FAULT_HANDLER_ERR gp 0xd
FAULT_HANDLER_ERR pf 0xe
+FAULT_HANDLER_ERR fault_15 0xf
FAULT_HANDLER_NOERR mf 0x10
FAULT_HANDLER_ERR ac 0x11
FAULT_HANDLER_NOERR mc 0x12
@@ -110,7 +111,9 @@ timer_handler:
mov $SEGSEL_KERNEL_FS, %eax
mov %ax, %fs
cld
+ push %esp
call timer_handler_real
+ add $0x4, %esp
jmp return_to_user /* check pending exit before iret */
@@ -128,5 +131,7 @@ kbd_handler:
mov $SEGSEL_KERNEL_FS, %eax
mov %ax, %fs
cld
+ push %esp
call kbd_handler_real
+ add $0x4, %esp
jmp return_to_user /* check pending exit before iret */
diff --git a/kern/kbd.c b/kern/kbd.c
index 5ba1bcb..ab359be 100644
--- a/kern/kbd.c
+++ b/kern/kbd.c
@@ -69,7 +69,7 @@ static int chr_w_pos = 0;
/**
* @brief keyboard inturrupt handler
*/
-void kbd_handler_real() {
+void kbd_handler_real(stack_frame_t* f) {
unsigned char sc = inb(KEYBOARD_PORT);
int next_w_pos = (sc_w_pos + 1) % SC_RING_SIZE;
if (next_w_pos != sc_r_pos) {
diff --git a/kern/pv.c b/kern/pv.c
index 77e6920..c2c3d23 100644
--- a/kern/pv.c
+++ b/kern/pv.c
@@ -1,3 +1,5 @@
+#include <simics.h>
+#include <stdio.h>
#include <string.h>
#include <hvcall.h>
@@ -10,6 +12,7 @@
#include <paging.h>
#include <pv.h>
#include <sched.h>
+#include <usermem.h>
static int create_boot_pd(process_t* p, pa_t bootmem, int n_pages);
@@ -20,8 +23,8 @@ void pv_init() {
/* copy ds's flags so we do not need to create one */
uint64_t ds_flags = (gdt[SEGSEL_USER_DS_IDX] & GDT_FLAG_MASK);
uint64_t fs_flags = (ds_flags & (~GDT_G_BIT));
- uint64_t base = USER_MEM_START;
- uint64_t limit = (PV_VM_LIMIT / PAGE_SIZE) - 1;
+ va_t base = USER_MEM_START;
+ va_size_t limit = (PV_VM_LIMIT / PAGE_SIZE) - 1;
gdt[SEGSEL_PV_CS_IDX] = create_segsel(base, limit, cs_flags);
gdt[SEGSEL_PV_DS_IDX] = create_segsel(base, limit, ds_flags);
gdt[SEGSEL_PV_FS_IDX] = create_segsel(base, limit, fs_flags);
@@ -57,11 +60,12 @@ static int create_boot_pd(process_t* p, pa_t bootmem, int n_pages) {
}
int old_if = save_clear_if();
page_table_t* pt = (page_table_t*)map_phys_page(pt_pa, NULL);
- /* do not set P bit for ZFOD */
- (*pt)[pt_index] = make_pte(bootmem + offset, 0, PTE_USER, PTE_RW, 0);
+ (*pt)[pt_index] =
+ make_pte(bootmem + offset, 0, PTE_USER, PTE_RW, PTE_PRESENT);
restore_if(old_if);
invlpg(m_start + offset);
} while (++i < n_pages);
+ memset((char*)USER_MEM_START, 0, n_pages * PAGE_SIZE);
return 0;
add_pt_fail:
@@ -88,17 +92,21 @@ thread_t* create_pv_process(thread_t* t,
if (bootmem == BAD_PA) {
goto alloc_bootmem_fail;
}
+ pv->n_pages = n_bootmem_pages;
+ pv->mem_base = bootmem;
if (add_region(p, USER_MEM_START, n_bootmem_pages, bootmem, 1) != 0) {
goto alloc_region_fail;
}
- if (create_boot_pd(p, bootmem, n_bootmem_pages) != 0) {
- goto create_boot_pd_fail;
- }
+
/* temporarily use new process's cr3 to load elf */
pa_t old_cr3 = get_current()->process->cr3;
get_current()->process->cr3 = p->cr3;
set_cr3(p->cr3);
+ if (create_boot_pd(p, bootmem, n_bootmem_pages) != 0) {
+ goto create_boot_pd_fail;
+ }
+
file_t* f = find_file(exe);
if (elf->e_txtlen != 0) {
@@ -152,9 +160,9 @@ thread_t* create_pv_process(thread_t* t,
return t;
load_elf_fail:
+create_boot_pd_fail:
get_current()->process->cr3 = old_cr3;
set_cr3(old_cr3);
-create_boot_pd_fail:
vector_pop(&p->regions);
alloc_region_fail:
free_user_pages(bootmem, n_bootmem_pages);
@@ -169,14 +177,145 @@ void destroy_pv(pv_t* pv) {
queue_t* node = pv->shadow_pds;
queue_t* end = node;
do {
- pv_pd_t* shadow_pd = queue_data(node, pv_pd_t, pv_link);
- destroy_pd(shadow_pd->cr3);
- if (shadow_pd->user_cr3 != shadow_pd->cr3) {
- destroy_pd(shadow_pd->user_cr3);
+ pv_pd_t* pv_pd = queue_data(node, pv_pd_t, pv_link);
+ destroy_pd(pv_pd->cr3);
+ if (pv_pd->user_cr3 != pv_pd->cr3) {
+ destroy_pd(pv_pd->user_cr3);
}
node = node->next;
- sfree(shadow_pd, sizeof(pv_pd_t));
+ sfree(pv_pd, sizeof(pv_pd_t));
} while (node != end);
}
sfree(pv, sizeof(pv_t));
}
+
+void pv_die(char* reason) {
+ thread_t* t = get_current();
+ sim_printf("PV kernel %d killed: %s", t->rb_node.key, reason);
+ printf("PV kernel %d killed: %s\n", t->rb_node.key, reason);
+ t->process->exit_value = GUEST_CRASH_STATUS;
+ kill_current();
+}
+
+void pv_switch_mode(process_t* p, int kernelmode) {
+ pv_pd_t* pv_pd = p->pv->active_shadow_pd;
+ pa_t target_cr3 = (kernelmode != 0 ? pv_pd->cr3 : pv_pd->user_cr3);
+ p->cr3 = target_cr3;
+ set_cr3(target_cr3);
+}
+
+void select_pv_pd(process_t* p, pv_pd_t* pv_pd) {
+ pv_t* pv = p->pv;
+ pv_pd_t* old_pv_pd = pv->active_shadow_pd;
+ pv->active_shadow_pd = pv_pd;
+ pv_pd->refcount++;
+ p->cr3 = pv_pd->cr3;
+ set_cr3(p->cr3);
+ old_pv_pd->refcount--;
+ if (old_pv_pd->refcount == 0) {
+ queue_detach(&pv->shadow_pds, &old_pv_pd->pv_link);
+ destroy_pd(old_pv_pd->cr3);
+ if (old_pv_pd->user_cr3 != old_pv_pd->cr3) {
+ destroy_pd(old_pv_pd->user_cr3);
+ }
+ sfree(old_pv_pd, sizeof(pv_pd_t));
+ }
+}
+
+void pv_handle_fault(ureg_t* frame, thread_t* t) {
+ pv_t* pv = t->process->pv;
+ pv_idt_entry_t* idt = pv_classify_interrupt(pv, frame->cause);
+ if (idt->eip == 0) {
+ goto no_idt_handler;
+ }
+ reg_t new_esp;
+ pv_frame_t pv_f;
+ pv_f.cr2 =
+ (frame->cause == SWEXN_CAUSE_PAGEFAULT ? frame->cr2 - USER_MEM_START
+ : 0);
+ pv_f.error_code = frame->error_code;
+ pv_f.eip = frame->eip;
+ pv_f.eflags =
+ (pv->vif != 0 ? (frame->eflags | EFL_IF) : (frame->eflags & (~EFL_IF)));
+ if (frame->eip >= USER_MEM_START) {
+ pv_switch_mode(t->process, 1);
+ reg_t esp0 = pv->vesp0;
+ esp0 = (esp0 & (~(sizeof(va_t) - 1)));
+ reg_t esp = frame->esp;
+ esp0 -= sizeof(reg_t);
+ if (copy_to_user(esp0, sizeof(reg_t), &esp) != 0) {
+ goto push_frame_fail;
+ }
+ pv_f.vcs = GUEST_INTERRUPT_UMODE;
+ esp0 -= sizeof(pv_frame_t);
+ if (copy_to_user(esp0, sizeof(pv_frame_t), &pv_f) != 0) {
+ goto push_frame_fail;
+ }
+ new_esp = esp0;
+ } else {
+ new_esp = frame->esp;
+ pv_f.vcs = GUEST_INTERRUPT_KMODE;
+ new_esp -= sizeof(pv_frame_t);
+ if (copy_to_user(new_esp, sizeof(pv_frame_t), &pv_f) != 0) {
+ goto push_frame_fail;
+ }
+ }
+ frame->eip = idt->eip;
+ frame->esp = new_esp;
+ return;
+
+push_frame_fail:
+ pv_die("Error when pushing interrupt frame to stack");
+no_idt_handler:
+ pv_die("No interrupt handler installed");
+}
+
+int pv_inject_interrupt(stack_frame_t* f, int index, int arg) {
+ thread_t* t = get_current();
+ pv_t* pv = t->process->pv;
+ if (pv == NULL || (pv->vif & EFL_IF) == 0 || f->cs != SEGSEL_PV_CS) {
+ return -1;
+ }
+ pv_idt_entry_t* idt = pv_classify_interrupt(pv, index);
+ if (idt == NULL) {
+ goto no_idt_handler;
+ }
+ reg_t new_esp;
+ pv_frame_t pv_f;
+ pv_f.cr2 = 0;
+ pv_f.error_code = arg;
+ pv_f.eip = f->eip;
+ pv_f.eflags = f->eflags;
+ if (f->eip >= USER_MEM_START) {
+ pv_switch_mode(t->process, 1);
+ reg_t esp0 = pv->vesp0;
+ esp0 = (esp0 & (~(sizeof(va_t) - 1)));
+ reg_t esp = f->esp;
+ esp0 -= sizeof(reg_t);
+ if (copy_to_user(esp0, sizeof(reg_t), &esp) != 0) {
+ goto push_frame_fail;
+ }
+ pv_f.vcs = GUEST_INTERRUPT_UMODE;
+ esp0 -= sizeof(pv_frame_t);
+ if (copy_to_user(esp0, sizeof(pv_frame_t), &pv_f) != 0) {
+ goto push_frame_fail;
+ }
+ new_esp = esp0;
+ } else {
+ new_esp = f->esp;
+ pv_f.vcs = GUEST_INTERRUPT_KMODE;
+ new_esp -= sizeof(pv_frame_t);
+ if (copy_to_user(new_esp, sizeof(pv_frame_t), &pv_f) != 0) {
+ goto push_frame_fail;
+ }
+ }
+ f->eip = idt->eip;
+ f->esp = new_esp;
+ return 0;
+
+push_frame_fail:
+ pv_die("Error when pushing interrupt frame to stack");
+no_idt_handler:
+ pv_die("No interrupt handler installed");
+ return -1;
+}
diff --git a/kern/sched.c b/kern/sched.c
index 7f7dc75..7882361 100644
--- a/kern/sched.c
+++ b/kern/sched.c
@@ -70,12 +70,6 @@ uint64_t create_segsel(va_t base, va_size_t limit, uint64_t flags) {
return ss;
}
-/**
- * @brief set fs
- * @param fs fs
- */
-void set_fs(reg_t fs);
-
void setup_percpu(percpu_t* percpu) {
uint64_t* gdt = (uint64_t*)gdt_base();
uint64_t ds = gdt[SEGSEL_KERNEL_DS_IDX];
diff --git a/kern/sched_asm.S b/kern/sched_asm.S
index 747598e..7bf8e3b 100644
--- a/kern/sched_asm.S
+++ b/kern/sched_asm.S
@@ -13,8 +13,13 @@
.global set_fs
.type set_fs, %function
set_fs:
- push 0x4(%esp)
- pop %fs
+ mov 0x4(%esp), %fs
+ ret
+
+.global set_gs
+.type set_gs, %function
+set_gs:
+ mov 0x4(%esp), %gs
ret
.macro PERCPU_GETSET name offset
diff --git a/kern/syscall_asm.S b/kern/syscall_asm.S
index 6bb2b8d..5d63a39 100644
--- a/kern/syscall_asm.S
+++ b/kern/syscall_asm.S
@@ -11,7 +11,7 @@
#define SEGSEL_KERNEL_FS SEGSEL_SPARE2
-.macro SYSCALL name
+.macro SYSCALL name index
.global sys_\name
.type sys_\name, %function
sys_\name:
@@ -26,9 +26,10 @@ sys_\name:
mov $SEGSEL_KERNEL_FS, %eax
mov %ax, %fs
cld
+ push $\index
push %esp
call handle_pv_syscall
- add $0x4, %esp
+ add $0x8, %esp
test %eax, %eax
jne return_to_user
push %esp
@@ -37,33 +38,31 @@ sys_\name:
jmp return_to_user /* check pending exit before iret */
.endm
-SYSCALL fork
-SYSCALL exec
-SYSCALL wait
-SYSCALL yield
-SYSCALL deschedule
-SYSCALL make_runnable
-SYSCALL gettid
-SYSCALL new_pages
-SYSCALL remove_pages
-SYSCALL sleep
-SYSCALL getchar
-SYSCALL readline
-SYSCALL print
-SYSCALL set_term_color
-SYSCALL set_cursor_pos
-SYSCALL get_cursor_pos
-SYSCALL thread_fork
-SYSCALL get_ticks
-SYSCALL misbehave
-SYSCALL halt
-SYSCALL task_vanish
-SYSCALL set_status
-SYSCALL vanish
-SYSCALL readfile
-SYSCALL swexn
-
-SYSCALL enosys
+SYSCALL fork 0x41
+SYSCALL exec 0x42
+SYSCALL wait 0x44
+SYSCALL yield 0x45
+SYSCALL deschedule 0x46
+SYSCALL make_runnable 0x47
+SYSCALL gettid 0x48
+SYSCALL new_pages 0x49
+SYSCALL remove_pages 0x4a
+SYSCALL sleep 0x4b
+SYSCALL getchar 0x4c
+SYSCALL readline 0x4d
+SYSCALL print 0x4e
+SYSCALL set_term_color 0x4f
+SYSCALL set_cursor_pos 0x50
+SYSCALL get_cursor_pos 0x51
+SYSCALL thread_fork 0x52
+SYSCALL get_ticks 0x53
+SYSCALL misbehave 0x54
+SYSCALL halt 0x55
+SYSCALL task_vanish 0x57
+SYSCALL set_status 0x59
+SYSCALL vanish 0x60
+SYSCALL readfile 0x62
+SYSCALL swexn 0x74
.global sys_hvcall
.type sys_hvcall, %function
@@ -83,3 +82,55 @@ sys_hvcall:
call sys_hvcall_real
add $0x4, %esp
jmp return_to_user /* check pending exit before iret */
+
+.macro NONEXIST_SYSCALL name index
+.global sys_\name
+.type sys_\name, %function
+sys_\name:
+ pusha /* save a stack_frame_t structure */
+ push %ds
+ push %es
+ push %fs
+ push %gs
+ mov $SEGSEL_KERNEL_DS, %eax
+ mov %ax, %ds
+ mov %ax, %es
+ mov $SEGSEL_KERNEL_FS, %eax
+ mov %ax, %fs
+ cld
+ push $\index
+ push %esp
+ call handle_pv_syscall
+ add $0x8, %esp
+ jmp return_to_user /* check pending exit before iret */
+.endm
+
+NONEXIST_SYSCALL 67 0x43
+NONEXIST_SYSCALL 86 0x56
+NONEXIST_SYSCALL 97 0x61
+NONEXIST_SYSCALL 99 0x63
+NONEXIST_SYSCALL 100 0x64
+NONEXIST_SYSCALL 101 0x65
+NONEXIST_SYSCALL 102 0x66
+NONEXIST_SYSCALL 103 0x67
+NONEXIST_SYSCALL 104 0x68
+NONEXIST_SYSCALL 105 0x69
+NONEXIST_SYSCALL 106 0x6a
+NONEXIST_SYSCALL 107 0x6b
+NONEXIST_SYSCALL 108 0x6c
+NONEXIST_SYSCALL 109 0x6d
+NONEXIST_SYSCALL 110 0x6e
+NONEXIST_SYSCALL 111 0x6f
+NONEXIST_SYSCALL 112 0x70
+NONEXIST_SYSCALL 113 0x71
+NONEXIST_SYSCALL 114 0x72
+NONEXIST_SYSCALL 115 0x73
+NONEXIST_SYSCALL 128 0x80
+NONEXIST_SYSCALL 129 0x81
+NONEXIST_SYSCALL 130 0x82
+NONEXIST_SYSCALL 131 0x83
+NONEXIST_SYSCALL 132 0x84
+NONEXIST_SYSCALL 133 0x85
+NONEXIST_SYSCALL 134 0x86
+
+NONEXIST_SYSCALL nonexist 0x0
diff --git a/kern/syscall_hvcall.c b/kern/syscall_hvcall.c
deleted file mode 100644
index 18ef741..0000000
--- a/kern/syscall_hvcall.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/** @file syscall_hvcall.c
- *
- * @brief miscellaneous syscalls.
- *
- * @author Hanjie Wu (hanjiew)
- * @bug No functional bugs
- */
-
-#include <simics.h>
-#include <stdio.h>
-#include <string.h>
-
-#include <common_kern.h>
-#include <elf/elf_410.h>
-#include <hvcall.h>
-#include <hvcall_int.h>
-#include <malloc_internal.h>
-#include <ureg.h>
-
-#include <x86/asm.h>
-#include <x86/cr.h>
-#include <x86/eflags.h>
-#include <x86/seg.h>
-
-#include <asm_instr.h>
-#include <assert.h>
-#include <loader.h>
-#include <malloc.h>
-#include <mm.h>
-#include <paging.h>
-#include <sched.h>
-#include <sync.h>
-#include <timer.h>
-#include <usermem.h>
-
-// 0: not pv, 1: processed
-int handle_pv_syscall(stack_frame_t* f) {
- if (get_current()->process->pv == NULL) {
- return 0;
- }
- if (f->eip >= USER_MEM_START) {
- // inject interrupt
- return 1;
- }
- // kernel called syscall
- return 1;
-}
-
-void sys_hvcall_real(stack_frame_t* f) {
- if (get_current()->process->pv == NULL) {
- f->eax = (reg_t)-1;
- return;
- }
- if (f->eip >= USER_MEM_START) {
- // inject interrupt
- return;
- }
- switch (f->eax) {
- case HV_MAGIC_OP:
- f->eax = (reg_t)HV_MAGIC;
- break;
- default:
- f->eax = (reg_t)-1;
- break;
- }
-}
diff --git a/kern/syscall_misc.c b/kern/syscall_misc.c
index 4c94513..4d0dd25 100644
--- a/kern/syscall_misc.c
+++ b/kern/syscall_misc.c
@@ -40,14 +40,6 @@ void sys_misbehave_real(stack_frame_t* f) {
}
/**
- * @brief all other syscalls handler
- * @param f saved regs
- */
-void sys_enosys_real(stack_frame_t* f) {
- f->eax = (reg_t)-1;
-}
-
-/**
* @brief halt() syscall handler
* @param f saved regs
*/
diff --git a/kern/timer.c b/kern/timer.c
index e857b51..b863c75 100644
--- a/kern/timer.c
+++ b/kern/timer.c
@@ -60,10 +60,11 @@ static void check_timers() {
spl_unlock(&timer_lock, old_if);
}
-void timer_handler_real() {
+void timer_handler_real(stack_frame_t* f) {
pic_acknowledge(TIMER_IRQ);
ticks++;
check_timers();
+ pv_inject_interrupt(f, TIMER_IDT_ENTRY, 0);
int old_if = spl_lock(&ready_lock);
thread_t* current = get_current();
if (current != get_idle()) {
diff --git a/kern/usermem.c b/kern/usermem.c
index ae48833..c4ce8d6 100644
--- a/kern/usermem.c
+++ b/kern/usermem.c
@@ -11,6 +11,7 @@
#include <common_kern.h>
#include <x86/asm.h>
+#include <x86/seg.h>
#include <console.h>
#include <mm.h>
@@ -46,6 +47,11 @@ static reg_t usermem_setup() {
thread_t* current = get_current();
reg_t old_eip0 = current->eip0;
current->eip0 = (reg_t)usermem_fail;
+ if (current->process->pv != NULL) {
+ set_gs(SEGSEL_PV_DS);
+ } else {
+ set_gs(SEGSEL_USER_DS);
+ }
return old_eip0;
}