1// Copyright 2017 The Fuchsia Authors 2// 3// Use of this source code is governed by a MIT-style 4// license that can be found in the LICENSE file or at 5// https://opensource.org/licenses/MIT 6 7#include <arch/hypervisor.h> 8#include <dev/interrupt/arm_gic_hw_interface.h> 9#include <hypervisor/guest_physical_address_space.h> 10#include <vm/pmm.h> 11#include <zircon/syscalls/hypervisor.h> 12 13#include "el2_cpu_state_priv.h" 14 15static constexpr zx_gpaddr_t kGicvAddress = 0x800002000; 16static constexpr size_t kGicvSize = 0x2000; 17 18// static 19zx_status_t Guest::Create(fbl::unique_ptr<Guest>* out) { 20 if (arm64_get_boot_el() < 2) { 21 return ZX_ERR_NOT_SUPPORTED; 22 } 23 24 uint8_t vmid; 25 zx_status_t status = alloc_vmid(&vmid); 26 if (status != ZX_OK) { 27 return status; 28 } 29 30 fbl::AllocChecker ac; 31 fbl::unique_ptr<Guest> guest(new (&ac) Guest(vmid)); 32 if (!ac.check()) { 33 free_vmid(vmid); 34 return ZX_ERR_NO_MEMORY; 35 } 36 37 fbl::AutoLock lock(&guest->vcpu_mutex_); 38 status = guest->vpid_allocator_.Init(); 39 if (status != ZX_OK) { 40 return status; 41 } 42 43 status = hypervisor::GuestPhysicalAddressSpace::Create(vmid, &guest->gpas_); 44 if (status != ZX_OK) { 45 return status; 46 } 47 48 zx_paddr_t gicv_paddr; 49 status = gic_get_gicv(&gicv_paddr); 50 51 // If status == ZX_ERR_NOT_FOUND, we are running GICv3 52 // There is no need to map GICV to the guest 53 // Handle other cases below 54 if (status == ZX_OK) { 55 status = guest->gpas_->MapInterruptController(kGicvAddress, gicv_paddr, kGicvSize); 56 if (status != ZX_OK) { 57 return status; 58 } 59 } else if (status == ZX_ERR_NOT_SUPPORTED) { 60 return status; 61 } 62 63 *out = fbl::move(guest); 64 return ZX_OK; 65} 66 67Guest::Guest(uint8_t vmid) 68 : vmid_(vmid) {} 69 70Guest::~Guest() { 71 free_vmid(vmid_); 72} 73 74zx_status_t Guest::SetTrap(uint32_t kind, zx_gpaddr_t addr, size_t len, 75 fbl::RefPtr<PortDispatcher> port, uint64_t key) { 76 switch (kind) { 77 case ZX_GUEST_TRAP_MEM: 78 if (port) { 79 return ZX_ERR_INVALID_ARGS; 80 } 81 break; 82 case ZX_GUEST_TRAP_BELL: 83 if (!port) { 84 return ZX_ERR_INVALID_ARGS; 85 } 86 break; 87 case ZX_GUEST_TRAP_IO: 88 return ZX_ERR_NOT_SUPPORTED; 89 default: 90 return ZX_ERR_INVALID_ARGS; 91 } 92 93 if (SIZE_MAX - len < addr) { 94 return ZX_ERR_OUT_OF_RANGE; 95 } else if (!IS_PAGE_ALIGNED(addr) || !IS_PAGE_ALIGNED(len) || len == 0) { 96 return ZX_ERR_INVALID_ARGS; 97 } 98 zx_status_t status = gpas_->UnmapRange(addr, len); 99 if (status != ZX_OK) { 100 return status; 101 } 102 return traps_.InsertTrap(kind, addr, len, fbl::move(port), key); 103} 104 105zx_status_t Guest::AllocVpid(uint8_t* vpid) { 106 fbl::AutoLock lock(&vcpu_mutex_); 107 return vpid_allocator_.AllocId(vpid); 108} 109 110zx_status_t Guest::FreeVpid(uint8_t vpid) { 111 fbl::AutoLock lock(&vcpu_mutex_); 112 return vpid_allocator_.FreeId(vpid); 113} 114