diff options
| author | Hanjie Wu <hanjiew@andrew.cmu.edu> | 2023-04-28 21:14:37 -0400 |
|---|---|---|
| committer | Hanjie Wu <hanjiew@andrew.cmu.edu> | 2023-04-28 21:14:37 -0400 |
| commit | 119b5e6fde37c53a5037a6ba959ba60c882bd6d0 (patch) | |
| tree | a41be842bfc966befb80324cc405414b35cf91d2 /kern/hvcall.c | |
| parent | ff90341c64565ac7d8034d2f8cf460532a5b51fd (diff) | |
Diffstat (limited to 'kern/hvcall.c')
| -rw-r--r-- | kern/hvcall.c | 105 |
1 files changed, 94 insertions, 11 deletions
diff --git a/kern/hvcall.c b/kern/hvcall.c index d387771..391882a 100644 --- a/kern/hvcall.c +++ b/kern/hvcall.c @@ -1,6 +1,6 @@ -/** @file syscall_hvcall.c +/** @file hvcall.c * - * @brief miscellaneous syscalls. + * @brief hypercalls. * * @author Hanjie Wu (hanjiew) * @bug No functional bugs @@ -34,25 +34,87 @@ #include <timer.h> #include <usermem.h> +/** reference a page table to prevent hypevisor of freeing its shadow page table + */ #define HV_REFPD_OP HV_RESERVED_0 +/** release the reference to a page table to let hypevisor free its + * shadow page table + */ #define HV_UNREFPD_OP HV_RESERVED_1 +/** load a previously referenced page table so hypervisor do not need to + * retranslate it + */ #define HV_LOADPD_OP HV_RESERVED_2 +/** + * @brief exit() hypercall handler + * @param f saved regs + */ static void hvcall_exit(stack_frame_t* f); +/** + * @brief iret() hypercall handler + * @param f saved regs + */ static void hvcall_iret(stack_frame_t* f); +/** + * @brief setidt() hypercall handler + * @param f saved regs + */ static void hvcall_setidt(stack_frame_t* f); +/** + * @brief setpd() hypercall handler + * @param f saved regs + */ static void hvcall_setpd(stack_frame_t* f); +/** + * @brief adjustpg() hypercall handler + * @param f saved regs + */ static void hvcall_adjustpg(stack_frame_t* f); +/** + * @brief print() hypercall handler + * @param f saved regs + */ static void hvcall_print(stack_frame_t* f); +/** + * @brief set_color() hypercall handler + * @param f saved regs + */ static void hvcall_set_color(stack_frame_t* f); +/** + * @brief set_cursor() hypercall handler + * @param f saved regs + */ static void hvcall_set_cursor(stack_frame_t* f); +/** + * @brief get_cursor() hypercall handler + * @param f saved regs + */ static void hvcall_get_cursor(stack_frame_t* f); +/** + * @brief print_at() hypercall handler + * @param f saved regs + */ static void hvcall_print_at(stack_frame_t* f); +/** + * @brief refpd/unrefpd() hypercall handler + * @param f saved regs + */ static void hvcall_refpd(int ref); +/** + * @brief loadpd() hypercall handler + * @param f saved regs + */ static void hvcall_loadpd(stack_frame_t* f); -// 0: processed +/** + * @brief try to handle a syscall for PV guest + * @param index syscall index + * @param f saved regs + * @return 0 if a syscall is injected to PV guest, -1 if current thread is not + * PV guest + */ int pv_handle_syscall(int index, stack_frame_t* f) { thread_t* t = get_current(); pv_t* pv = t->process->pv; @@ -65,7 +127,7 @@ int pv_handle_syscall(int index, stack_frame_t* f) { goto no_idt_handler; } if (idt->desc != VIDT_DPL_3) { - idt = &pv->vidt.fault[SWEXN_CAUSE_PROTFAULT - PV_FAULT_START]; + idt = &pv->vidt.fault_irq[SWEXN_CAUSE_PROTFAULT - PV_FAULT_START]; if (idt->eip == 0) { goto no_idt_handler; } @@ -80,8 +142,13 @@ no_idt_handler: return 1; } +/** + * @brief all hypercall entry + * @param f saved regs + */ void sys_hvcall_real(stack_frame_t* f) { pv_t* pv = get_current()->process->pv; + /** hide hypercall for non-PV process and usermode programs in PV guest */ if (pv == NULL || f->eip >= USER_MEM_START) { return; } @@ -153,6 +220,7 @@ read_arg_fail: pv_die("Bad argument address"); } +/** eflags that can be changed by PV guests */ #define EFLAGS_PV_MASK \ (EFL_CF | EFL_PF | EFL_AF | EFL_ZF | EFL_SF | EFL_TF | EFL_DF | EFL_OF | \ EFL_RF) @@ -161,7 +229,7 @@ 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]; + reg_t regs[5]; /* eip, eflags, esp, esp0, eax */ if (copy_from_user(esp, 5 * sizeof(reg_t), regs) != 0) { goto read_arg_fail; } @@ -205,11 +273,11 @@ static void hvcall_setidt(stack_frame_t* f) { 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); + if (idt == NULL) { + goto bad_idt_index; + } idt->eip = eip0; idt->desc = ((idt->desc & (~VIDT_DPL_MASK)) | (is_dpl0 != 0 ? VIDT_DPL_0 : VIDT_DPL_3)); @@ -221,6 +289,13 @@ read_arg_fail: pv_die("Bad argument address"); } +/** + * @brief translate a PV guest's page table to shadow page tables + * @param pv PV control block for PV guest + * @param pd guest page table physical address + * @param wp is CR0_WP bit enabled for guest + * @return shadow page table, or NULL on failure + */ static pv_pd_t* translate_pv_pd(pv_t* pv, pa_t pd, int wp); static void hvcall_setpd(stack_frame_t* f) { @@ -254,7 +329,9 @@ read_arg_fail: pv_die("Bad argument address"); } +/** customizable bits in pde */ #define PDE_RESV_MASK 0xf00 +/** customizable bits in pte */ #define PTE_RESV_MASK 0xe00 static pv_pd_t* translate_pv_pd(pv_t* pv, pa_t pd, int wp) { @@ -303,7 +380,8 @@ static pv_pd_t* translate_pv_pd(pv_t* pv, pa_t pd, int wp) { if (pd >= mem_limit) { goto bad_pt; } - pd += pv->mem_base; + pd += pv->mem_base; /** convert guest physical address to host physical + address */ 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]; @@ -327,13 +405,15 @@ static pv_pd_t* translate_pv_pd(pv_t* pv, pa_t pd, int wp) { } pa_t pa = get_page_base(old_pte); if (pa > mem_limit) { - pa = overflow_pa; + pa = overflow_pa; /** emulate memory access outside physical + address limit */ } 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 is disabled, PV kernel can always write anywhere */ if (wp == 0) { new_mask = ((1 << PTE_P_SHIFT) | (PTE_RW << PTE_RW_SHIFT) | (PTE_USER << PTE_US_SHIFT)); @@ -341,6 +421,7 @@ static pv_pd_t* translate_pv_pd(pv_t* pv, pa_t pd, int wp) { new_mask = ((1 << PTE_P_SHIFT) | old_rw | (PTE_USER << PTE_US_SHIFT)); } + /** hide PV kernel in usermode program's page table */ if ((old_us & old_pde_us) != 0) { new_user_mask = ((1 << PTE_P_SHIFT) | old_rw | (PTE_USER << PTE_US_SHIFT)); @@ -363,6 +444,7 @@ static pv_pd_t* translate_pv_pd(pv_t* pv, pa_t pd, int wp) { free_user_pages(new_pt, 1); goto alloc_pt_fail; } + /** write the new page table */ 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) | @@ -372,6 +454,7 @@ static pv_pd_t* translate_pv_pd(pv_t* pv, pa_t pd, int wp) { } else { new_pde |= (old_pde & (1 << PTE_RW_SHIFT)); } + /** insert the page table into page directory */ (*t_pd)[USER_PD_START + i] = (new_pt | new_pde); (*t_user_pd)[USER_PD_START + i] = (new_user_pt | new_pde); } @@ -687,7 +770,7 @@ static void hvcall_refpd(int ref) { } else { pv_pd->refcount--; if (pv_pd->refcount <= 0) { - pv_die("Page table destroyed by kerenl"); + pv_die("Page table destroyed by PV kerenl"); } } } |
