// Copyright 2017 The Fuchsia Authors
//
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT

#include <lib/ktrace.h>
#include <zircon/errors.h>
#include <zircon/syscalls/hypervisor.h>
#include <zircon/types.h>

#include <fbl/alloc_checker.h>
#include <fbl/auto_lock.h>
#include <hypervisor/ktrace.h>
#include <hypervisor/trap_map.h>
#include <kernel/range_check.h>

namespace {

constexpr size_t kMaxPacketsPerRange = 256;

bool ValidRange(uint32_t kind, zx_gpaddr_t addr, size_t len) {
  if (len == 0) {
    return false;
  }
  zx_gpaddr_t end;
  if (add_overflow(addr, len, &end)) {
    return false;
  }
#ifdef ARCH_X86
  if (kind == ZX_GUEST_TRAP_IO && end > UINT16_MAX) {
    return false;
  }
#endif  // ARCH_X86
  return true;
}

}  // namespace

namespace hypervisor {

BlockingPortAllocator::BlockingPortAllocator() : semaphore_(kMaxPacketsPerRange) {}

zx::status<> BlockingPortAllocator::Init() {
  zx_status_t status = arena_.Init("hypervisor-packets", kMaxPacketsPerRange);
  return zx::make_status(status);
}

PortPacket* BlockingPortAllocator::AllocBlocking() {
  ktrace_vcpu(TAG_VCPU_BLOCK, VCPU_PORT);
  zx_status_t status = semaphore_.Wait(Deadline::infinite());
  ktrace_vcpu(TAG_VCPU_UNBLOCK, VCPU_PORT);
  if (status != ZX_OK) {
    return nullptr;
  }
  return Alloc();
}

PortPacket* BlockingPortAllocator::Alloc() {
  return arena_.New(this /* handle */, this /* allocator */);
}

void BlockingPortAllocator::Free(PortPacket* port_packet) {
  arena_.Delete(port_packet);
  semaphore_.Post();
}

Trap::Trap(uint32_t kind, zx_gpaddr_t addr, size_t len, fbl::RefPtr<PortDispatcher> port,
           uint64_t key)
    : kind_(kind), addr_(addr), len_(len), port_(ktl::move(port)), key_(key) {}

Trap::~Trap() {
  if (port_ == nullptr) {
    return;
  }
  port_->CancelQueued(&port_allocator_ /* handle */, key_);
}

zx::status<> Trap::Init() { return port_allocator_.Init(); }

zx::status<> Trap::Queue(const zx_port_packet_t& packet, StateInvalidator* invalidator) {
  if (invalidator != nullptr) {
    invalidator->Invalidate();
  }
  if (port_ == nullptr) {
    return zx::error(ZX_ERR_NOT_FOUND);
  }
  PortPacket* port_packet = port_allocator_.AllocBlocking();
  if (port_packet == nullptr) {
    return zx::error(ZX_ERR_NO_MEMORY);
  }
  port_packet->packet = packet;
  zx_status_t status = port_->Queue(port_packet, ZX_SIGNAL_NONE);
  if (status != ZX_OK) {
    port_allocator_.Free(port_packet);
    if (status == ZX_ERR_BAD_HANDLE) {
      // If the last handle to the port has been closed, then we're in a bad state.
      status = ZX_ERR_BAD_STATE;
    }
  }
  return zx::make_status(status);
}

zx::status<> TrapMap::InsertTrap(uint32_t kind, zx_gpaddr_t addr, size_t len,
                                 fbl::RefPtr<PortDispatcher> port, uint64_t key) {
  if (!ValidRange(kind, addr, len)) {
    return zx::error(ZX_ERR_OUT_OF_RANGE);
  }
  TrapTree* traps = TreeOf(kind);
  if (traps == nullptr) {
    return zx::error(ZX_ERR_INVALID_ARGS);
  }

  fbl::AllocChecker ac;
  ktl::unique_ptr<Trap> range(new (&ac) Trap(kind, addr, len, ktl::move(port), key));
  if (!ac.check()) {
    return zx::error(ZX_ERR_NO_MEMORY);
  }
  if (auto result = range->Init(); result.is_error()) {
    return result.take_error();
  }

  Guard<SpinLock, IrqSave> guard{&lock_};
  auto iter = traps->upper_bound(addr);
  // If `upper_bound()` does not return `end()`, check if the range intersects.
  if (iter.IsValid() && Intersects(addr, len, iter->addr(), iter->len())) {
    return zx::error(ZX_ERR_ALREADY_EXISTS);
  }
  // Decrement the iterator, and check if the next range intersects.
  if (--iter; iter.IsValid() && Intersects(addr, len, iter->addr(), iter->len())) {
    return zx::error(ZX_ERR_ALREADY_EXISTS);
  }
  traps->insert(ktl::move(range));
  return zx::ok();
}

zx::status<Trap*> TrapMap::FindTrap(uint32_t kind, zx_gpaddr_t addr) {
  TrapTree* traps = TreeOf(kind);
  if (traps == nullptr) {
    return zx::error(ZX_ERR_INVALID_ARGS);
  }

  Trap* found;
  {
    Guard<SpinLock, IrqSave> guard{&lock_};
    auto iter = --traps->upper_bound(addr);
    if (!iter.IsValid()) {
      return zx::error(ZX_ERR_NOT_FOUND);
    }
    found = &*iter;
  }
  if (!found->Contains(addr)) {
    return zx::error(ZX_ERR_NOT_FOUND);
  }
  return zx::ok(found);
}

TrapMap::TrapTree* TrapMap::TreeOf(uint32_t kind) {
  switch (kind) {
    case ZX_GUEST_TRAP_BELL:
    case ZX_GUEST_TRAP_MEM:
      return &mem_traps_;
#ifdef ARCH_X86
    case ZX_GUEST_TRAP_IO:
      return &io_traps_;
#endif  // ARCH_X86
    default:
      return nullptr;
  }
}

}  // namespace hypervisor
