110860Sandreas.sandberg@arm.com/*
212111Sandreas.sandberg@arm.com * Copyright (c) 2012, 2015, 2017 ARM Limited
310860Sandreas.sandberg@arm.com * All rights reserved
410860Sandreas.sandberg@arm.com *
510860Sandreas.sandberg@arm.com * The license below extends only to copyright in the software and shall
610860Sandreas.sandberg@arm.com * not be construed as granting a license to any other intellectual
710860Sandreas.sandberg@arm.com * property including but not limited to intellectual property relating
810860Sandreas.sandberg@arm.com * to a hardware implementation of the functionality of the software
910860Sandreas.sandberg@arm.com * licensed hereunder.  You may use the software subject to the license
1010860Sandreas.sandberg@arm.com * terms below provided that you ensure that this notice is replicated
1110860Sandreas.sandberg@arm.com * unmodified and in its entirety in all distributions of the software,
1210860Sandreas.sandberg@arm.com * modified or unmodified, in source code or in binary form.
1310860Sandreas.sandberg@arm.com *
1410860Sandreas.sandberg@arm.com * Redistribution and use in source and binary forms, with or without
1510860Sandreas.sandberg@arm.com * modification, are permitted provided that the following conditions are
1610860Sandreas.sandberg@arm.com * met: redistributions of source code must retain the above copyright
1710860Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer;
1810860Sandreas.sandberg@arm.com * redistributions in binary form must reproduce the above copyright
1910860Sandreas.sandberg@arm.com * notice, this list of conditions and the following disclaimer in the
2010860Sandreas.sandberg@arm.com * documentation and/or other materials provided with the distribution;
2110860Sandreas.sandberg@arm.com * neither the name of the copyright holders nor the names of its
2210860Sandreas.sandberg@arm.com * contributors may be used to endorse or promote products derived from
2310860Sandreas.sandberg@arm.com * this software without specific prior written permission.
2410860Sandreas.sandberg@arm.com *
2510860Sandreas.sandberg@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2610860Sandreas.sandberg@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2710860Sandreas.sandberg@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2810860Sandreas.sandberg@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2910860Sandreas.sandberg@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3010860Sandreas.sandberg@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3110860Sandreas.sandberg@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3210860Sandreas.sandberg@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3310860Sandreas.sandberg@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3410860Sandreas.sandberg@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3510860Sandreas.sandberg@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3610860Sandreas.sandberg@arm.com *
3710860Sandreas.sandberg@arm.com * Authors: Andreas Sandberg
3810860Sandreas.sandberg@arm.com */
3910860Sandreas.sandberg@arm.com
4010860Sandreas.sandberg@arm.com#include "arch/arm/kvm/base_cpu.hh"
4110860Sandreas.sandberg@arm.com
4210860Sandreas.sandberg@arm.com#include <linux/kvm.h>
4310860Sandreas.sandberg@arm.com
4410860Sandreas.sandberg@arm.com#include "debug/KvmInt.hh"
4510860Sandreas.sandberg@arm.com#include "params/BaseArmKvmCPU.hh"
4610860Sandreas.sandberg@arm.com
4710860Sandreas.sandberg@arm.com#define INTERRUPT_ID(type, vcpu, irq) (                    \
4810860Sandreas.sandberg@arm.com        ((type) << KVM_ARM_IRQ_TYPE_SHIFT) |               \
4910860Sandreas.sandberg@arm.com        ((vcpu) << KVM_ARM_IRQ_VCPU_SHIFT) |               \
5010860Sandreas.sandberg@arm.com        ((irq) << KVM_ARM_IRQ_NUM_SHIFT))
5110860Sandreas.sandberg@arm.com
5210860Sandreas.sandberg@arm.com#define INTERRUPT_VCPU_IRQ(vcpu)                                \
5310860Sandreas.sandberg@arm.com    INTERRUPT_ID(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_IRQ)
5410860Sandreas.sandberg@arm.com
5510860Sandreas.sandberg@arm.com#define INTERRUPT_VCPU_FIQ(vcpu)                                \
5610860Sandreas.sandberg@arm.com    INTERRUPT_ID(KVM_ARM_IRQ_TYPE_CPU, vcpu, KVM_ARM_IRQ_CPU_FIQ)
5710860Sandreas.sandberg@arm.com
5810860Sandreas.sandberg@arm.com
5910860Sandreas.sandberg@arm.comBaseArmKvmCPU::BaseArmKvmCPU(BaseArmKvmCPUParams *params)
6010860Sandreas.sandberg@arm.com    : BaseKvmCPU(params),
6110860Sandreas.sandberg@arm.com      irqAsserted(false), fiqAsserted(false)
6210860Sandreas.sandberg@arm.com{
6310860Sandreas.sandberg@arm.com}
6410860Sandreas.sandberg@arm.com
6510860Sandreas.sandberg@arm.comBaseArmKvmCPU::~BaseArmKvmCPU()
6610860Sandreas.sandberg@arm.com{
6710860Sandreas.sandberg@arm.com}
6810860Sandreas.sandberg@arm.com
6910860Sandreas.sandberg@arm.comvoid
7010860Sandreas.sandberg@arm.comBaseArmKvmCPU::startup()
7110860Sandreas.sandberg@arm.com{
7210860Sandreas.sandberg@arm.com    BaseKvmCPU::startup();
7310860Sandreas.sandberg@arm.com
7410860Sandreas.sandberg@arm.com    /* TODO: This needs to be moved when we start to support VMs with
7510860Sandreas.sandberg@arm.com     * multiple threads since kvmArmVCpuInit requires that all CPUs in
7610860Sandreas.sandberg@arm.com     * the VM have been created.
7710860Sandreas.sandberg@arm.com     */
7810860Sandreas.sandberg@arm.com    struct kvm_vcpu_init target_config;
7910860Sandreas.sandberg@arm.com    memset(&target_config, 0, sizeof(target_config));
8010860Sandreas.sandberg@arm.com
8110860Sandreas.sandberg@arm.com    vm.kvmArmPreferredTarget(target_config);
8211891Srjthakur@google.com    if (!((ArmSystem *)system)->highestELIs64()) {
8311891Srjthakur@google.com        target_config.features[0] |= (1 << KVM_ARM_VCPU_EL1_32BIT);
8411891Srjthakur@google.com    }
8510860Sandreas.sandberg@arm.com    kvmArmVCpuInit(target_config);
8610860Sandreas.sandberg@arm.com}
8710860Sandreas.sandberg@arm.com
8810860Sandreas.sandberg@arm.comTick
8910860Sandreas.sandberg@arm.comBaseArmKvmCPU::kvmRun(Tick ticks)
9010860Sandreas.sandberg@arm.com{
9112111Sandreas.sandberg@arm.com    const bool simFIQ(interrupts[0]->checkRaw(INT_FIQ));
9212111Sandreas.sandberg@arm.com    const bool simIRQ(interrupts[0]->checkRaw(INT_IRQ));
9310860Sandreas.sandberg@arm.com
9412111Sandreas.sandberg@arm.com    if (!vm.hasKernelIRQChip()) {
9512111Sandreas.sandberg@arm.com        if (fiqAsserted != simFIQ) {
9612111Sandreas.sandberg@arm.com            DPRINTF(KvmInt, "KVM: Update FIQ state: %i\n", simFIQ);
9712111Sandreas.sandberg@arm.com            vm.setIRQLine(INTERRUPT_VCPU_FIQ(vcpuID), simFIQ);
9812111Sandreas.sandberg@arm.com        }
9912111Sandreas.sandberg@arm.com        if (irqAsserted != simIRQ) {
10012111Sandreas.sandberg@arm.com            DPRINTF(KvmInt, "KVM: Update IRQ state: %i\n", simIRQ);
10112111Sandreas.sandberg@arm.com            vm.setIRQLine(INTERRUPT_VCPU_IRQ(vcpuID), simIRQ);
10212111Sandreas.sandberg@arm.com        }
10312111Sandreas.sandberg@arm.com    } else {
10412111Sandreas.sandberg@arm.com        warn_if(simFIQ && !fiqAsserted,
10512111Sandreas.sandberg@arm.com                "FIQ raised by the simulated interrupt controller " \
10612111Sandreas.sandberg@arm.com                "despite in-kernel GIC emulation. This is probably a bug.");
10712111Sandreas.sandberg@arm.com
10812111Sandreas.sandberg@arm.com        warn_if(simIRQ && !irqAsserted,
10912111Sandreas.sandberg@arm.com                "IRQ raised by the simulated interrupt controller " \
11012111Sandreas.sandberg@arm.com                "despite in-kernel GIC emulation. This is probably a bug.");
11110860Sandreas.sandberg@arm.com    }
11212111Sandreas.sandberg@arm.com
11312111Sandreas.sandberg@arm.com    irqAsserted = simIRQ;
11412111Sandreas.sandberg@arm.com    fiqAsserted = simFIQ;
11510860Sandreas.sandberg@arm.com
11610860Sandreas.sandberg@arm.com    return BaseKvmCPU::kvmRun(ticks);
11710860Sandreas.sandberg@arm.com}
11810860Sandreas.sandberg@arm.com
11910860Sandreas.sandberg@arm.comconst BaseArmKvmCPU::RegIndexVector &
12010860Sandreas.sandberg@arm.comBaseArmKvmCPU::getRegList() const
12110860Sandreas.sandberg@arm.com{
12210860Sandreas.sandberg@arm.com    // Do we need to request a list of registers from the kernel?
12310860Sandreas.sandberg@arm.com    if (_regIndexList.size() == 0) {
12410860Sandreas.sandberg@arm.com        // Start by probing for the size of the list. We do this
12510860Sandreas.sandberg@arm.com        // calling the ioctl with a struct size of 0. The kernel will
12610860Sandreas.sandberg@arm.com        // return the number of elements required to hold the list.
12710860Sandreas.sandberg@arm.com        kvm_reg_list regs_probe;
12810860Sandreas.sandberg@arm.com        regs_probe.n = 0;
12910860Sandreas.sandberg@arm.com        getRegList(regs_probe);
13010860Sandreas.sandberg@arm.com
13110860Sandreas.sandberg@arm.com        // Request the actual register list now that we know how many
13210860Sandreas.sandberg@arm.com        // register we need to allocate space for.
13310860Sandreas.sandberg@arm.com        std::unique_ptr<struct kvm_reg_list> regs;
13410860Sandreas.sandberg@arm.com        const size_t size(sizeof(struct kvm_reg_list) +
13510860Sandreas.sandberg@arm.com                          regs_probe.n * sizeof(uint64_t));
13610860Sandreas.sandberg@arm.com        regs.reset((struct kvm_reg_list *)operator new(size));
13710860Sandreas.sandberg@arm.com        regs->n = regs_probe.n;
13810860Sandreas.sandberg@arm.com        if (!getRegList(*regs))
13910860Sandreas.sandberg@arm.com            panic("Failed to determine register list size.\n");
14010860Sandreas.sandberg@arm.com
14110860Sandreas.sandberg@arm.com        _regIndexList.assign(regs->reg, regs->reg + regs->n);
14210860Sandreas.sandberg@arm.com    }
14310860Sandreas.sandberg@arm.com
14410860Sandreas.sandberg@arm.com    return _regIndexList;
14510860Sandreas.sandberg@arm.com}
14610860Sandreas.sandberg@arm.com
14710860Sandreas.sandberg@arm.comvoid
14810860Sandreas.sandberg@arm.comBaseArmKvmCPU::kvmArmVCpuInit(const struct kvm_vcpu_init &init)
14910860Sandreas.sandberg@arm.com{
15010860Sandreas.sandberg@arm.com    if (ioctl(KVM_ARM_VCPU_INIT, (void *)&init) == -1)
15110860Sandreas.sandberg@arm.com        panic("KVM: Failed to initialize vCPU\n");
15210860Sandreas.sandberg@arm.com}
15310860Sandreas.sandberg@arm.com
15410860Sandreas.sandberg@arm.combool
15510860Sandreas.sandberg@arm.comBaseArmKvmCPU::getRegList(struct kvm_reg_list &regs) const
15610860Sandreas.sandberg@arm.com{
15710860Sandreas.sandberg@arm.com    if (ioctl(KVM_GET_REG_LIST, (void *)&regs) == -1) {
15810860Sandreas.sandberg@arm.com        if (errno == E2BIG) {
15910860Sandreas.sandberg@arm.com            return false;
16010860Sandreas.sandberg@arm.com        } else {
16110860Sandreas.sandberg@arm.com            panic("KVM: Failed to get vCPU register list (errno: %i)\n",
16210860Sandreas.sandberg@arm.com                  errno);
16310860Sandreas.sandberg@arm.com        }
16410860Sandreas.sandberg@arm.com    } else {
16510860Sandreas.sandberg@arm.com        return true;
16610860Sandreas.sandberg@arm.com    }
16710860Sandreas.sandberg@arm.com}
168