1/* 2 * Copyright 2019, Data61, CSIRO (ABN 41 687 119 230) 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <string.h> 8#include <stdio.h> 9#include <stdlib.h> 10 11#include <utils/util.h> 12#include <sel4/sel4.h> 13#include <vka/object.h> 14#include <vka/capops.h> 15#include <sel4utils/mapping.h> 16#include <sel4utils/api.h> 17 18#include <sel4vm/guest_vm.h> 19#include <sel4vm/guest_vm_exits.h> 20 21#include <sel4vm/boot.h> 22#include <sel4vm/guest_memory.h> 23#include <sel4vm/guest_memory_helpers.h> 24 25#include "vm_boot.h" 26#include "guest_vspace.h" 27#include "guest_memory.h" 28#include "guest_state.h" 29#include "vmcs.h" 30#include "processor/decode.h" 31#include "processor/apicdef.h" 32#include "processor/lapic.h" 33#include "processor/platfeature.h" 34 35#define VM_VMCS_CR0_MASK (X86_CR0_PG | X86_CR0_PE) 36#define VM_VMCS_CR0_VALUE VM_VMCS_CR0_MASK 37/* We need to own the PSE and PAE bits up until the guest has actually turned on paging, 38 * then it can control them 39 */ 40#define VM_VMCS_CR4_MASK (X86_CR4_PSE | X86_CR4_PAE | X86_CR4_VMXE) 41#define VM_VMCS_CR4_VALUE (X86_CR4_PSE | X86_CR4_VMXE) 42 43#define GUEST_PAGE_DIR 0x10000000 44 45static int make_guest_page_dir_continued(void *access_addr, void *vaddr, void *cookie) 46{ 47 /* Write into this frame as the init page directory: 4M pages, 1 to 1 mapping. */ 48 uint32_t *pd = vaddr; 49 for (int i = 0; i < 1024; i++) { 50 /* Present, write, user, page size 4M */ 51 pd[i] = (i << PAGE_BITS_4M) | 0x87; 52 } 53 return 0; 54} 55 56static vm_frame_t pd_alloc_iterator(uintptr_t addr, void *cookie) 57{ 58 int ret; 59 vka_object_t object; 60 vm_frame_t frame_result = { seL4_CapNull, seL4_NoRights, 0, 0 }; 61 vm_t *vm = (vm_t *)cookie; 62 if (!vm) { 63 return frame_result; 64 } 65 int page_size = seL4_PageBits; 66 uintptr_t frame_start = ROUND_DOWN(addr, BIT(page_size)); 67 ret = vka_alloc_frame_maybe_device(vm->vka, page_size, false, &object); 68 if (ret) { 69 ZF_LOGE("Failed to allocate frame for address 0x%x", (unsigned int)addr); 70 return frame_result; 71 } 72 frame_result.cptr = object.cptr; 73 frame_result.rights = seL4_AllRights; 74 frame_result.vaddr = frame_start; 75 frame_result.size_bits = page_size; 76 return frame_result; 77} 78 79 80static int make_guest_page_dir(vm_t *vm) 81{ 82 /* Create a 4K Page to be our 1-1 pd */ 83 /* This is constructed with magical new memory that we will not tell Linux about */ 84 vm_memory_reservation_t *pd_reservation = vm_reserve_memory_at(vm, GUEST_PAGE_DIR, BIT(seL4_PageBits), 85 default_error_fault_callback, NULL); 86 if (!pd_reservation) { 87 ZF_LOGE("Failed to reserve page for initial guest pd"); 88 return -1; 89 } 90 int err = map_vm_memory_reservation(vm, pd_reservation, pd_alloc_iterator, (void *)vm); 91 if (err) { 92 ZF_LOGE("Failed to map page for initial guest pd"); 93 } 94 printf("Guest page dir allocated at 0x%x. Creating 1-1 entries\n", (unsigned int)GUEST_PAGE_DIR); 95 vm->arch.guest_pd = GUEST_PAGE_DIR; 96 return vspace_access_page_with_callback(&vm->mem.vm_vspace, &vm->mem.vmm_vspace, (void *)GUEST_PAGE_DIR, 97 seL4_PageBits, seL4_AllRights, 1, make_guest_page_dir_continued, NULL); 98} 99 100int vm_init_arch(vm_t *vm) 101{ 102 int err; 103 104 if (!vm) { 105 ZF_LOGE("Failed to initialise vm arch: Invalid vm"); 106 return -1; 107 } 108 109 vm->arch.vmcall_handlers = NULL; 110 vm->arch.vmcall_num_handlers = 0; 111 vm->arch.ioport_list.num_ioports = 0; 112 vm->arch.ioport_list.ioports = NULL; 113 114 /* Create an EPT which is the pd for all the vcpu tcbs */ 115 err = vka_alloc_ept_pml4(vm->vka, &vm->mem.vm_vspace_root); 116 if (err) { 117 return -1; 118 } 119 /* Assign an ASID */ 120 err = simple_ASIDPool_assign(vm->simple, vm->mem.vm_vspace_root.cptr); 121 if (err != seL4_NoError) { 122 ZF_LOGE("Failed to assign ASID pool to EPT root"); 123 return -1; 124 } 125 /* Install the guest PD */ 126 err = seL4_TCB_SetEPTRoot(simple_get_tcb(vm->simple), vm->mem.vm_vspace_root.cptr); 127 assert(err == seL4_NoError); 128 /* Initialize a vspace for the guest */ 129 err = vm_init_guest_vspace(&vm->mem.vmm_vspace, &vm->mem.vmm_vspace, 130 &vm->mem.vm_vspace, vm->vka, vm->mem.vm_vspace_root.cptr); 131 if (err) { 132 return err; 133 } 134 135 /* Bind our interrupt pending callback */ 136 err = seL4_TCB_BindNotification(simple_get_init_cap(vm->simple, seL4_CapInitThreadTCB), vm->host_endpoint); 137 assert(err == seL4_NoError); 138 return err; 139} 140 141int vm_create_vcpu_arch(vm_t *vm, vm_vcpu_t *vcpu) 142{ 143 int err; 144 err = seL4_X86_VCPU_SetTCB(vcpu->vcpu.cptr, simple_get_tcb(vm->simple)); 145 assert(err == seL4_NoError); 146 /* All LAPICs are created enabled, in virtual wire mode */ 147 vm_create_lapic(vcpu, 1); 148 vcpu->vcpu_arch.guest_state = calloc(1, sizeof(guest_state_t)); 149 if (!vcpu->vcpu_arch.guest_state) { 150 return -1; 151 } 152 153 /* Create our 4K page 1-1 pd */ 154 err = make_guest_page_dir(vm); 155 if (err) { 156 return -1; 157 } 158 159 vm_guest_state_initialise(vcpu->vcpu_arch.guest_state); 160 /* Set the initial CR state */ 161 vcpu->vcpu_arch.guest_state->virt.cr.cr0_mask = VM_VMCS_CR0_MASK; 162 vcpu->vcpu_arch.guest_state->virt.cr.cr0_shadow = 0; 163 vcpu->vcpu_arch.guest_state->virt.cr.cr0_host_bits = VM_VMCS_CR0_VALUE; 164 vcpu->vcpu_arch.guest_state->virt.cr.cr4_mask = VM_VMCS_CR4_MASK; 165 vcpu->vcpu_arch.guest_state->virt.cr.cr4_shadow = 0; 166 vcpu->vcpu_arch.guest_state->virt.cr.cr4_host_bits = VM_VMCS_CR4_VALUE; 167 /* Set the initial CR states */ 168 vm_guest_state_set_cr0(vcpu->vcpu_arch.guest_state, vcpu->vcpu_arch.guest_state->virt.cr.cr0_host_bits); 169 vm_guest_state_set_cr3(vcpu->vcpu_arch.guest_state, vm->arch.guest_pd); 170 vm_guest_state_set_cr4(vcpu->vcpu_arch.guest_state, vcpu->vcpu_arch.guest_state->virt.cr.cr4_host_bits); 171 /* Init guest OS vcpu state. */ 172 vm_vmcs_init_guest(vcpu); 173 return 0; 174} 175