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 <hypervisor/trap_map.h> 8 9#include <fbl/alloc_checker.h> 10#include <fbl/auto_lock.h> 11#include <hypervisor/ktrace.h> 12#include <lib/ktrace.h> 13#include <zircon/syscalls/hypervisor.h> 14#include <zircon/types.h> 15 16static constexpr size_t kMaxPacketsPerRange = 256; 17 18namespace hypervisor { 19 20BlockingPortAllocator::BlockingPortAllocator() : semaphore_(kMaxPacketsPerRange) {} 21 22zx_status_t BlockingPortAllocator::Init() { 23 return arena_.Init("hypervisor-packets", kMaxPacketsPerRange); 24} 25 26PortPacket* BlockingPortAllocator::AllocBlocking() { 27 ktrace_vcpu(TAG_VCPU_BLOCK, VCPU_PORT); 28 zx_status_t status = semaphore_.Wait(ZX_TIME_INFINITE); 29 ktrace_vcpu(TAG_VCPU_UNBLOCK, VCPU_PORT); 30 if (status != ZX_OK) { 31 return nullptr; 32 } 33 return Alloc(); 34} 35 36PortPacket* BlockingPortAllocator::Alloc() { 37 return arena_.New(nullptr, this); 38} 39 40void BlockingPortAllocator::Free(PortPacket* port_packet) { 41 arena_.Delete(port_packet); 42 semaphore_.Post(); 43} 44 45Trap::Trap(uint32_t kind, zx_gpaddr_t addr, size_t len, fbl::RefPtr<PortDispatcher> port, 46 uint64_t key) 47 : kind_(kind), addr_(addr), len_(len), port_(fbl::move(port)), key_(key) { 48 (void) key_; 49} 50 51Trap::~Trap() { 52 if (port_ == nullptr) { 53 return; 54 } 55 port_->CancelQueued(nullptr /* handle */, key_); 56} 57 58zx_status_t Trap::Init() { 59 return port_allocator_.Init(); 60} 61 62zx_status_t Trap::Queue(const zx_port_packet_t& packet, StateInvalidator* invalidator) { 63 if (invalidator != nullptr) { 64 invalidator->Invalidate(); 65 } 66 if (port_ == nullptr) { 67 return ZX_ERR_NOT_FOUND; 68 } 69 PortPacket* port_packet = port_allocator_.AllocBlocking(); 70 if (port_packet == nullptr) { 71 return ZX_ERR_NO_MEMORY; 72 } 73 port_packet->packet = packet; 74 zx_status_t status = port_->Queue(port_packet, ZX_SIGNAL_NONE, 0); 75 if (status != ZX_OK) { 76 port_allocator_.Free(port_packet); 77 } 78 return status; 79} 80 81zx_status_t TrapMap::InsertTrap(uint32_t kind, zx_gpaddr_t addr, size_t len, 82 fbl::RefPtr<PortDispatcher> port, uint64_t key) { 83 TrapTree* traps = TreeOf(kind); 84 if (traps == nullptr) { 85 return ZX_ERR_INVALID_ARGS; 86 } 87 auto iter = traps->find(addr); 88 if (iter.IsValid()) { 89 dprintf(INFO, "Trap for kind %u (addr %#lx len %lu key %lu) already exists " 90 "(addr %#lx len %lu key %lu)\n", kind, addr, len, key, iter->addr(), iter->len(), 91 iter->key()); 92 return ZX_ERR_ALREADY_EXISTS; 93 } 94 fbl::AllocChecker ac; 95 fbl::unique_ptr<Trap> range(new (&ac) Trap(kind, addr, len, fbl::move(port), key)); 96 if (!ac.check()) { 97 return ZX_ERR_NO_MEMORY; 98 } 99 zx_status_t status = range->Init(); 100 if (status != ZX_OK) { 101 return status; 102 } 103 { 104 fbl::AutoLock lock(&mutex_); 105 traps->insert(fbl::move(range)); 106 } 107 return ZX_OK; 108} 109 110zx_status_t TrapMap::FindTrap(uint32_t kind, zx_gpaddr_t addr, Trap** trap) { 111 TrapTree* traps = TreeOf(kind); 112 if (traps == nullptr) { 113 return ZX_ERR_INVALID_ARGS; 114 } 115 TrapTree::iterator iter; 116 { 117 fbl::AutoLock lock(&mutex_); 118 iter = traps->upper_bound(addr); 119 } 120 --iter; 121 if (!iter.IsValid() || !iter->Contains(addr)) { 122 return ZX_ERR_NOT_FOUND; 123 } 124 *trap = const_cast<Trap*>(&*iter); 125 return ZX_OK; 126} 127 128TrapMap::TrapTree* TrapMap::TreeOf(uint32_t kind) { 129 switch (kind) { 130 case ZX_GUEST_TRAP_BELL: 131 case ZX_GUEST_TRAP_MEM: 132 return &mem_traps_; 133#ifdef ARCH_X86 134 case ZX_GUEST_TRAP_IO: 135 return &io_traps_; 136#endif // ARCH_X86 137 default: 138 return nullptr; 139 } 140} 141 142} // namespace hypervisor 143