blob: d9eadf1e75183f61d1ae7489830e936469690763 [file] [log] [blame]
/*
* 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;
}