diff options
| author | Hanjie Wu <hanjiew@andrew.cmu.edu> | 2023-04-22 23:25:43 -0400 |
|---|---|---|
| committer | Hanjie Wu <hanjiew@andrew.cmu.edu> | 2023-04-22 23:25:43 -0400 |
| commit | a7e1cbd3cb53bd4fb43a52a806fd50ab6fa24a24 (patch) | |
| tree | ed823adb61b2b43d7c4f2f5ca45cff0dd9f66df5 /kern | |
| parent | ed4192548143468362124ee7ee6105c001fe29c0 (diff) | |
pv
Diffstat (limited to 'kern')
| -rw-r--r-- | kern/hvcall.c | 674 | ||||
| -rw-r--r-- | kern/inc/pv.h | 76 | ||||
| -rw-r--r-- | kern/inc/sched.h | 12 | ||||
| -rw-r--r-- | kern/interrupt.c | 172 | ||||
| -rw-r--r-- | kern/interrupt_asm.S | 11 | ||||
| -rw-r--r-- | kern/kbd.c | 2 | ||||
| -rw-r--r-- | kern/pv.c | 165 | ||||
| -rw-r--r-- | kern/sched.c | 6 | ||||
| -rw-r--r-- | kern/sched_asm.S | 9 | ||||
| -rw-r--r-- | kern/syscall_asm.S | 109 | ||||
| -rw-r--r-- | kern/syscall_hvcall.c | 66 | ||||
| -rw-r--r-- | kern/syscall_misc.c | 8 | ||||
| -rw-r--r-- | kern/timer.c | 3 | ||||
| -rw-r--r-- | kern/usermem.c | 6 |
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 */ @@ -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) { @@ -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; } |
