| /* |
| * Copyright 2017, Data61 |
| * Commonwealth Scientific and Industrial Research Organisation (CSIRO) |
| * ABN 41 687 119 230. |
| * |
| * This software may be distributed and modified according to the terms of |
| * the GNU General Public License version 2. Note that NO WARRANTY is provided. |
| * See "LICENSE_GPLv2.txt" for details. |
| * |
| * @TAG(DATA61_GPL) |
| */ |
| |
| /* Initialization functions related to the seL4 side of vmm |
| * booting and management. */ |
| |
| #include <autoconf.h> |
| #include <sel4vmm/gen_config.h> |
| |
| #include <stdio.h> |
| #include <string.h> |
| #include <stdlib.h> |
| |
| #include <sel4/sel4.h> |
| #include <simple/simple.h> |
| #include <vka/capops.h> |
| |
| #include "vmm/platform/boot.h" |
| #include "vmm/platform/guest_vspace.h" |
| #include "vmm/processor/apicdef.h" |
| #include "vmm/processor/lapic.h" |
| |
| int vmm_init(vmm_t *vmm, allocman_t *allocman, simple_t simple, vka_t vka, vspace_t vspace, |
| platform_callbacks_t callbacks) |
| { |
| int err; |
| memset(vmm, 0, sizeof(vmm_t)); |
| vmm->allocman = allocman; |
| vmm->vka = vka; |
| vmm->host_simple = simple; |
| vmm->host_vspace = vspace; |
| vmm->plat_callbacks = callbacks; |
| vmm->tcb = simple_get_tcb(&simple); |
| vmm->sc = simple_get_sc(&simple); |
| vmm->sched_ctrl = simple_get_sched_ctrl(&simple, 0); |
| // Currently set this to 4k pages by default |
| vmm->page_size = seL4_PageBits; |
| err = vmm_pci_init(&vmm->pci); |
| if (err) { |
| return err; |
| } |
| err = vmm_io_port_init(&vmm->io_port); |
| if (err) { |
| return err; |
| } |
| err = vmm_mmio_init(&vmm->mmio_list); |
| if (err) { |
| return err; |
| } |
| |
| vmm->vmcall_handlers = NULL; |
| vmm->vmcall_num_handlers = 0; |
| |
| return 0; |
| } |
| |
| int vmm_init_host(vmm_t *vmm) |
| { |
| vmm->done_host_init = 1; |
| return 0; |
| } |
| |
| static int vmm_init_vcpu(vmm_t *vmm, unsigned int vcpu_num, int priority) |
| { |
| int UNUSED error; |
| assert(vcpu_num < vmm->num_vcpus); |
| vmm_vcpu_t *vcpu = &vmm->vcpus[vcpu_num]; |
| |
| /* sel4 vcpu (vmcs) */ |
| vcpu->guest_vcpu = vka_alloc_vcpu_leaky(&vmm->vka); |
| if (vcpu->guest_vcpu == 0) { |
| return -1; |
| } |
| |
| /* bind the VCPU to the VMM thread */ |
| error = seL4_X86_VCPU_SetTCB(vcpu->guest_vcpu, vmm->tcb); |
| assert(error == seL4_NoError); |
| |
| vcpu->vmm = vmm; |
| vcpu->vcpu_id = vcpu_num; |
| |
| /* All LAPICs are created enabled, in virtual wire mode */ |
| vmm_create_lapic(vcpu, 1); |
| |
| return 0; |
| } |
| |
| int vmm_init_guest(vmm_t *vmm, int priority) |
| { |
| return vmm_init_guest_multi(vmm, priority, 1); |
| } |
| |
| int vmm_init_guest_multi(vmm_t *vmm, int priority, int num_vcpus) |
| { |
| int error; |
| |
| assert(vmm->done_host_init); |
| |
| vmm->num_vcpus = num_vcpus; |
| vmm->vcpus = malloc(num_vcpus * sizeof(vmm_vcpu_t)); |
| if (!vmm->vcpus) { |
| return -1; |
| } |
| |
| /* Create an EPT which is the pd for all the vcpu tcbs */ |
| vmm->guest_pd = vka_alloc_ept_pml4_leaky(&vmm->vka); |
| if (vmm->guest_pd == 0) { |
| return -1; |
| } |
| /* Assign an ASID */ |
| error = simple_ASIDPool_assign(&vmm->host_simple, vmm->guest_pd); |
| if (error != seL4_NoError) { |
| ZF_LOGE("Failed to assign ASID pool to EPT root"); |
| return -1; |
| } |
| /* Install the guest PD */ |
| error = seL4_TCB_SetEPTRoot(vmm->tcb, vmm->guest_pd); |
| assert(error == seL4_NoError); |
| /* Initialize a vspace for the guest */ |
| error = vmm_get_guest_vspace(&vmm->host_vspace, &vmm->host_vspace, |
| &vmm->guest_mem.vspace, &vmm->vka, vmm->guest_pd); |
| if (error) { |
| return error; |
| } |
| |
| for (int i = 0; i < num_vcpus; i++) { |
| vmm_init_vcpu(vmm, i, priority); |
| } |
| |
| /* Init guest memory information. |
| * TODO: should probably done elsewhere */ |
| vmm->guest_mem.num_ram_regions = 0; |
| vmm->guest_mem.ram_regions = malloc(0); |
| |
| vmm_mmio_add_handler(&vmm->mmio_list, APIC_DEFAULT_PHYS_BASE, |
| APIC_DEFAULT_PHYS_BASE + sizeof(struct local_apic_regs) - 1, |
| NULL, "Local APIC", vmm_apic_mmio_read, vmm_apic_mmio_write); |
| |
| vmm->done_guest_init = 1; |
| return 0; |
| } |