blob: 04d1386c5451c4f9e9562294c91a7656d313311f [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <machina/interrupt_controller.h>
#include <hypervisor/address.h>
#include <hypervisor/bits.h>
#include <hypervisor/guest.h>
static const uint64_t kMaxInterrupts = 128;
static const uint64_t kGicRevision = 2;
// clang-format off
enum class GicdRegister : uint64_t {
CTL = 0x000,
TYPE = 0x004,
ISENABLE0 = 0x100,
ISENABLE15 = 0x13c,
ICENABLE0 = 0x180,
ICENABLE15 = 0x1bc,
ICPEND0 = 0x280,
ICPEND15 = 0x2bc,
ICFG0 = 0xc00,
ICFG31 = 0xc7c,
PID2 = 0xfe8,
};
// clang-format on
static inline uint32_t typer_it_lines(uint32_t num_interrupts) {
return set_bits((num_interrupts >> 5) - 1, 4, 0);
}
static inline uint32_t pidr2_arch_rev(uint32_t revision) {
return set_bits(revision, 7, 4);
}
zx_status_t GicDistributor::Init(Guest* guest) {
return guest->CreateMapping(TrapType::MMIO_SYNC, GIC_DISTRIBUTOR_PHYS_BASE,
GIC_DISTRIBUTOR_SIZE, 0, this);
}
zx_status_t GicDistributor::Read(uint64_t addr, IoValue* value) const {
if (value->access_size != 4)
return ZX_ERR_IO_DATA_INTEGRITY;
switch (static_cast<GicdRegister>(addr)) {
case GicdRegister::TYPE:
// TODO(abdulla): Set the number of VCPUs.
value->u32 = typer_it_lines(kMaxInterrupts);
return ZX_OK;
case GicdRegister::ICFG0... GicdRegister::ICFG31:
if (addr % 4)
return ZX_ERR_IO_DATA_INTEGRITY;
value->u32 = 0;
return ZX_OK;
case GicdRegister::PID2:
value->u32 = pidr2_arch_rev(kGicRevision);
return ZX_OK;
default:
fprintf(stderr, "Unhandled GIC distributor address %#lx\n", addr);
return ZX_ERR_NOT_SUPPORTED;
}
}
zx_status_t GicDistributor::Write(uint64_t addr, const IoValue& value) {
switch (static_cast<GicdRegister>(addr)) {
case GicdRegister::CTL:
return ZX_OK;
case GicdRegister::ISENABLE0... GicdRegister::ISENABLE15:
case GicdRegister::ICENABLE0... GicdRegister::ICENABLE15:
case GicdRegister::ICPEND0... GicdRegister::ICPEND15:
case GicdRegister::ICFG0... GicdRegister::ICFG31:
if (addr % 4)
return ZX_ERR_IO_DATA_INTEGRITY;
return ZX_OK;
default:
fprintf(stderr, "Unhandled GIC distributor address %#lx\n", addr);
return ZX_ERR_NOT_SUPPORTED;
}
}
zx_status_t GicDistributor::Interrupt(uint32_t global_irq) const {
return ZX_ERR_NOT_SUPPORTED;
}