vm.cc revision 10860:cba0f26038b4
111185Serfan.azarkhish@unibo.it/*
211185Serfan.azarkhish@unibo.it * Copyright 2014 Google, Inc.
311185Serfan.azarkhish@unibo.it * Copyright (c) 2012, 2015 ARM Limited
411185Serfan.azarkhish@unibo.it * All rights reserved
511185Serfan.azarkhish@unibo.it *
611185Serfan.azarkhish@unibo.it * The license below extends only to copyright in the software and shall
711185Serfan.azarkhish@unibo.it * not be construed as granting a license to any other intellectual
811185Serfan.azarkhish@unibo.it * property including but not limited to intellectual property relating
911185Serfan.azarkhish@unibo.it * to a hardware implementation of the functionality of the software
1011185Serfan.azarkhish@unibo.it * licensed hereunder.  You may use the software subject to the license
1111185Serfan.azarkhish@unibo.it * terms below provided that you ensure that this notice is replicated
1211185Serfan.azarkhish@unibo.it * unmodified and in its entirety in all distributions of the software,
1311185Serfan.azarkhish@unibo.it * modified or unmodified, in source code or in binary form.
1411185Serfan.azarkhish@unibo.it *
1511185Serfan.azarkhish@unibo.it * Redistribution and use in source and binary forms, with or without
1611185Serfan.azarkhish@unibo.it * modification, are permitted provided that the following conditions are
1711185Serfan.azarkhish@unibo.it * met: redistributions of source code must retain the above copyright
1811185Serfan.azarkhish@unibo.it * notice, this list of conditions and the following disclaimer;
1911185Serfan.azarkhish@unibo.it * redistributions in binary form must reproduce the above copyright
2011185Serfan.azarkhish@unibo.it * notice, this list of conditions and the following disclaimer in the
2111185Serfan.azarkhish@unibo.it * documentation and/or other materials provided with the distribution;
2211185Serfan.azarkhish@unibo.it * neither the name of the copyright holders nor the names of its
2311185Serfan.azarkhish@unibo.it * contributors may be used to endorse or promote products derived from
2411185Serfan.azarkhish@unibo.it * this software without specific prior written permission.
2511185Serfan.azarkhish@unibo.it *
2611185Serfan.azarkhish@unibo.it * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
2711185Serfan.azarkhish@unibo.it * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
2811185Serfan.azarkhish@unibo.it * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2911185Serfan.azarkhish@unibo.it * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
3011185Serfan.azarkhish@unibo.it * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
3111185Serfan.azarkhish@unibo.it * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3211185Serfan.azarkhish@unibo.it * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3311185Serfan.azarkhish@unibo.it * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3411185Serfan.azarkhish@unibo.it * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3511185Serfan.azarkhish@unibo.it * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3611185Serfan.azarkhish@unibo.it * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3711185Serfan.azarkhish@unibo.it *
3811185Serfan.azarkhish@unibo.it * Authors: Andreas Sandberg
3911185Serfan.azarkhish@unibo.it */
4011185Serfan.azarkhish@unibo.it
4111185Serfan.azarkhish@unibo.it#include <linux/kvm.h>
4211185Serfan.azarkhish@unibo.it#include <sys/ioctl.h>
4311185Serfan.azarkhish@unibo.it#include <sys/stat.h>
4411185Serfan.azarkhish@unibo.it#include <sys/types.h>
4511185Serfan.azarkhish@unibo.it#include <fcntl.h>
4611185Serfan.azarkhish@unibo.it#include <unistd.h>
4711185Serfan.azarkhish@unibo.it
4811185Serfan.azarkhish@unibo.it#include <cerrno>
4911185Serfan.azarkhish@unibo.it#include <memory>
5011185Serfan.azarkhish@unibo.it
5111185Serfan.azarkhish@unibo.it#include "cpu/kvm/vm.hh"
5211185Serfan.azarkhish@unibo.it#include "debug/Kvm.hh"
5311185Serfan.azarkhish@unibo.it#include "params/KvmVM.hh"
5411185Serfan.azarkhish@unibo.it#include "sim/system.hh"
5511185Serfan.azarkhish@unibo.it
5611185Serfan.azarkhish@unibo.it#define EXPECTED_KVM_API_VERSION 12
5711185Serfan.azarkhish@unibo.it
5811185Serfan.azarkhish@unibo.it#if EXPECTED_KVM_API_VERSION != KVM_API_VERSION
5911185Serfan.azarkhish@unibo.it#error Unsupported KVM version
6011185Serfan.azarkhish@unibo.it#endif
6111185Serfan.azarkhish@unibo.it
6211185Serfan.azarkhish@unibo.itKvm *Kvm::instance = NULL;
6311185Serfan.azarkhish@unibo.it
6411185Serfan.azarkhish@unibo.itKvm::Kvm()
6511185Serfan.azarkhish@unibo.it    : kvmFD(-1), apiVersion(-1), vcpuMMapSize(0)
6611185Serfan.azarkhish@unibo.it{
6711185Serfan.azarkhish@unibo.it    kvmFD = ::open("/dev/kvm", O_RDWR);
6811185Serfan.azarkhish@unibo.it    if (kvmFD == -1)
6911185Serfan.azarkhish@unibo.it        fatal("KVM: Failed to open /dev/kvm\n");
7011185Serfan.azarkhish@unibo.it
7111185Serfan.azarkhish@unibo.it    apiVersion = ioctl(KVM_GET_API_VERSION);
7211185Serfan.azarkhish@unibo.it    if (apiVersion != EXPECTED_KVM_API_VERSION)
7311185Serfan.azarkhish@unibo.it        fatal("KVM: Incompatible API version\n");
7411185Serfan.azarkhish@unibo.it
7511185Serfan.azarkhish@unibo.it    vcpuMMapSize = ioctl(KVM_GET_VCPU_MMAP_SIZE);
7611185Serfan.azarkhish@unibo.it    if (vcpuMMapSize == -1)
7711185Serfan.azarkhish@unibo.it        panic("KVM: Failed to get virtual CPU MMAP size\n");
7811185Serfan.azarkhish@unibo.it}
7911185Serfan.azarkhish@unibo.it
8011185Serfan.azarkhish@unibo.itKvm::~Kvm()
8111185Serfan.azarkhish@unibo.it{
8211185Serfan.azarkhish@unibo.it    close(kvmFD);
8311185Serfan.azarkhish@unibo.it}
8411185Serfan.azarkhish@unibo.it
8511185Serfan.azarkhish@unibo.itKvm *
8611185Serfan.azarkhish@unibo.itKvm::create()
8711185Serfan.azarkhish@unibo.it{
8811185Serfan.azarkhish@unibo.it    if (!instance)
8911185Serfan.azarkhish@unibo.it        instance = new Kvm();
9011185Serfan.azarkhish@unibo.it
9111185Serfan.azarkhish@unibo.it    return instance;
9211185Serfan.azarkhish@unibo.it}
9311185Serfan.azarkhish@unibo.it
9411185Serfan.azarkhish@unibo.itbool
9511185Serfan.azarkhish@unibo.itKvm::capUserMemory() const
9611185Serfan.azarkhish@unibo.it{
9711185Serfan.azarkhish@unibo.it    return checkExtension(KVM_CAP_USER_MEMORY) != 0;
9811185Serfan.azarkhish@unibo.it}
9911185Serfan.azarkhish@unibo.it
10011185Serfan.azarkhish@unibo.itbool
10111185Serfan.azarkhish@unibo.itKvm::capSetTSSAddress() const
10211185Serfan.azarkhish@unibo.it{
10311185Serfan.azarkhish@unibo.it    return checkExtension(KVM_CAP_SET_TSS_ADDR) != 0;
10411185Serfan.azarkhish@unibo.it}
10511185Serfan.azarkhish@unibo.it
10611185Serfan.azarkhish@unibo.itbool
10711185Serfan.azarkhish@unibo.itKvm::capExtendedCPUID() const
10811185Serfan.azarkhish@unibo.it{
10911185Serfan.azarkhish@unibo.it    return checkExtension(KVM_CAP_EXT_CPUID) != 0;
11011185Serfan.azarkhish@unibo.it}
11111185Serfan.azarkhish@unibo.it
11211185Serfan.azarkhish@unibo.itbool
11311185Serfan.azarkhish@unibo.itKvm::capUserNMI() const
11411185Serfan.azarkhish@unibo.it{
11511185Serfan.azarkhish@unibo.it#ifdef KVM_CAP_USER_NMI
11611185Serfan.azarkhish@unibo.it    return checkExtension(KVM_CAP_USER_NMI) != 0;
11711185Serfan.azarkhish@unibo.it#else
11811185Serfan.azarkhish@unibo.it    return false;
11911185Serfan.azarkhish@unibo.it#endif
12011185Serfan.azarkhish@unibo.it}
12111185Serfan.azarkhish@unibo.it
12211185Serfan.azarkhish@unibo.itint
12311185Serfan.azarkhish@unibo.itKvm::capCoalescedMMIO() const
12411185Serfan.azarkhish@unibo.it{
12511185Serfan.azarkhish@unibo.it    return checkExtension(KVM_CAP_COALESCED_MMIO);
12611185Serfan.azarkhish@unibo.it}
12711185Serfan.azarkhish@unibo.it
12811185Serfan.azarkhish@unibo.itint
12911185Serfan.azarkhish@unibo.itKvm::capNumMemSlots() const
13011185Serfan.azarkhish@unibo.it{
13111185Serfan.azarkhish@unibo.it#ifdef KVM_CAP_NR_MEMSLOTS
13211185Serfan.azarkhish@unibo.it    return checkExtension(KVM_CAP_NR_MEMSLOTS);
13311185Serfan.azarkhish@unibo.it#else
13411185Serfan.azarkhish@unibo.it    return 0;
13511185Serfan.azarkhish@unibo.it#endif
13611185Serfan.azarkhish@unibo.it}
13711185Serfan.azarkhish@unibo.it
13811185Serfan.azarkhish@unibo.itbool
13911185Serfan.azarkhish@unibo.itKvm::capOneReg() const
14011185Serfan.azarkhish@unibo.it{
14111185Serfan.azarkhish@unibo.it#ifdef KVM_CAP_ONE_REG
14211185Serfan.azarkhish@unibo.it    return checkExtension(KVM_CAP_ONE_REG) != 0;
14311185Serfan.azarkhish@unibo.it#else
14411185Serfan.azarkhish@unibo.it    return false;
14511185Serfan.azarkhish@unibo.it#endif
14611185Serfan.azarkhish@unibo.it}
14711185Serfan.azarkhish@unibo.it
14811185Serfan.azarkhish@unibo.itbool
14911185Serfan.azarkhish@unibo.itKvm::capIRQChip() const
15011185Serfan.azarkhish@unibo.it{
15111185Serfan.azarkhish@unibo.it    return checkExtension(KVM_CAP_IRQCHIP) != 0;
15211185Serfan.azarkhish@unibo.it}
15311185Serfan.azarkhish@unibo.it
15411185Serfan.azarkhish@unibo.itbool
15511185Serfan.azarkhish@unibo.itKvm::capVCPUEvents() const
15611185Serfan.azarkhish@unibo.it{
15711185Serfan.azarkhish@unibo.it#ifdef KVM_CAP_VCPU_EVENTS
15811185Serfan.azarkhish@unibo.it    return checkExtension(KVM_CAP_VCPU_EVENTS) != 0;
15911185Serfan.azarkhish@unibo.it#else
16011185Serfan.azarkhish@unibo.it    return false;
16111185Serfan.azarkhish@unibo.it#endif
16211185Serfan.azarkhish@unibo.it}
16311185Serfan.azarkhish@unibo.it
16411185Serfan.azarkhish@unibo.itbool
16511185Serfan.azarkhish@unibo.itKvm::capDebugRegs() const
16611185Serfan.azarkhish@unibo.it{
16711185Serfan.azarkhish@unibo.it#ifdef KVM_CAP_DEBUGREGS
16811185Serfan.azarkhish@unibo.it    return checkExtension(KVM_CAP_DEBUGREGS) != 0;
16911185Serfan.azarkhish@unibo.it#else
17011185Serfan.azarkhish@unibo.it    return false;
17111185Serfan.azarkhish@unibo.it#endif
17211185Serfan.azarkhish@unibo.it}
17311185Serfan.azarkhish@unibo.it
17411185Serfan.azarkhish@unibo.itbool
17511185Serfan.azarkhish@unibo.itKvm::capXCRs() const
17611185Serfan.azarkhish@unibo.it{
17711185Serfan.azarkhish@unibo.it#ifdef KVM_CAP_XCRS
17811185Serfan.azarkhish@unibo.it    return checkExtension(KVM_CAP_XCRS) != 0;
17911185Serfan.azarkhish@unibo.it#else
18011185Serfan.azarkhish@unibo.it    return false;
18111185Serfan.azarkhish@unibo.it#endif
18211185Serfan.azarkhish@unibo.it}
18311185Serfan.azarkhish@unibo.it
18411185Serfan.azarkhish@unibo.itbool
18511185Serfan.azarkhish@unibo.itKvm::capXSave() const
18611185Serfan.azarkhish@unibo.it{
18711185Serfan.azarkhish@unibo.it#ifdef KVM_CAP_XSAVE
18811185Serfan.azarkhish@unibo.it    return checkExtension(KVM_CAP_XSAVE) != 0;
18911185Serfan.azarkhish@unibo.it#else
19011185Serfan.azarkhish@unibo.it    return false;
19111185Serfan.azarkhish@unibo.it#endif
19211185Serfan.azarkhish@unibo.it}
19311185Serfan.azarkhish@unibo.it
19411185Serfan.azarkhish@unibo.it
19511185Serfan.azarkhish@unibo.it#if defined(__i386__) || defined(__x86_64__)
19611185Serfan.azarkhish@unibo.itbool
19711185Serfan.azarkhish@unibo.itKvm::getSupportedCPUID(struct kvm_cpuid2 &cpuid) const
19811185Serfan.azarkhish@unibo.it{
19911185Serfan.azarkhish@unibo.it    if (ioctl(KVM_GET_SUPPORTED_CPUID, (void *)&cpuid) == -1) {
20011185Serfan.azarkhish@unibo.it        if (errno == E2BIG)
20111185Serfan.azarkhish@unibo.it            return false;
20211185Serfan.azarkhish@unibo.it        else
20311185Serfan.azarkhish@unibo.it            panic("KVM: Failed to get supported CPUID (errno: %i)\n", errno);
20411185Serfan.azarkhish@unibo.it    } else
20511185Serfan.azarkhish@unibo.it        return true;
20611185Serfan.azarkhish@unibo.it}
20711185Serfan.azarkhish@unibo.it
20811185Serfan.azarkhish@unibo.itconst Kvm::CPUIDVector &
20911185Serfan.azarkhish@unibo.itKvm::getSupportedCPUID() const
21011185Serfan.azarkhish@unibo.it{
21111185Serfan.azarkhish@unibo.it    if (supportedCPUIDCache.empty()) {
21211185Serfan.azarkhish@unibo.it        std::unique_ptr<struct kvm_cpuid2> cpuid;
21311185Serfan.azarkhish@unibo.it        int i(1);
21411185Serfan.azarkhish@unibo.it        do {
21511185Serfan.azarkhish@unibo.it            cpuid.reset((struct kvm_cpuid2 *)operator new(
21611185Serfan.azarkhish@unibo.it                            sizeof(kvm_cpuid2) + i * sizeof(kvm_cpuid_entry2)));
21711185Serfan.azarkhish@unibo.it
21811185Serfan.azarkhish@unibo.it            cpuid->nent = i;
21911185Serfan.azarkhish@unibo.it            ++i;
22011185Serfan.azarkhish@unibo.it        } while (!getSupportedCPUID(*cpuid));
22111185Serfan.azarkhish@unibo.it        supportedCPUIDCache.assign(cpuid->entries,
22211185Serfan.azarkhish@unibo.it                                   cpuid->entries + cpuid->nent);
22311185Serfan.azarkhish@unibo.it    }
22411185Serfan.azarkhish@unibo.it
22511185Serfan.azarkhish@unibo.it    return supportedCPUIDCache;
22611185Serfan.azarkhish@unibo.it}
22711185Serfan.azarkhish@unibo.it
22811185Serfan.azarkhish@unibo.itbool
22911185Serfan.azarkhish@unibo.itKvm::getSupportedMSRs(struct kvm_msr_list &msrs) const
23011185Serfan.azarkhish@unibo.it{
23111185Serfan.azarkhish@unibo.it    if (ioctl(KVM_GET_MSR_INDEX_LIST, (void *)&msrs) == -1) {
23211185Serfan.azarkhish@unibo.it        if (errno == E2BIG)
23311185Serfan.azarkhish@unibo.it            return false;
23411185Serfan.azarkhish@unibo.it        else
23511185Serfan.azarkhish@unibo.it            panic("KVM: Failed to get supported CPUID (errno: %i)\n", errno);
23611185Serfan.azarkhish@unibo.it    } else
23711185Serfan.azarkhish@unibo.it        return true;
23811185Serfan.azarkhish@unibo.it}
23911185Serfan.azarkhish@unibo.it
24011185Serfan.azarkhish@unibo.itconst Kvm::MSRIndexVector &
24111185Serfan.azarkhish@unibo.itKvm::getSupportedMSRs() const
24211185Serfan.azarkhish@unibo.it{
24311185Serfan.azarkhish@unibo.it    if (supportedMSRCache.empty()) {
24411185Serfan.azarkhish@unibo.it        std::unique_ptr<struct kvm_msr_list> msrs;
24511185Serfan.azarkhish@unibo.it        int i(0);
24611185Serfan.azarkhish@unibo.it        do {
24711185Serfan.azarkhish@unibo.it            msrs.reset((struct kvm_msr_list *)operator new(
24811185Serfan.azarkhish@unibo.it                           sizeof(kvm_msr_list) + i * sizeof(uint32_t)));
24911185Serfan.azarkhish@unibo.it
25011185Serfan.azarkhish@unibo.it            msrs->nmsrs = i;
25111185Serfan.azarkhish@unibo.it            ++i;
25211185Serfan.azarkhish@unibo.it        } while (!getSupportedMSRs(*msrs));
25311185Serfan.azarkhish@unibo.it        supportedMSRCache.assign(msrs->indices, msrs->indices + msrs->nmsrs);
25411185Serfan.azarkhish@unibo.it    }
25511185Serfan.azarkhish@unibo.it
25611185Serfan.azarkhish@unibo.it    return supportedMSRCache;
25711185Serfan.azarkhish@unibo.it}
25811185Serfan.azarkhish@unibo.it
25911185Serfan.azarkhish@unibo.it#endif // x86-specific
26011185Serfan.azarkhish@unibo.it
26111185Serfan.azarkhish@unibo.it
26211185Serfan.azarkhish@unibo.itint
26311185Serfan.azarkhish@unibo.itKvm::checkExtension(int extension) const
26411185Serfan.azarkhish@unibo.it{
26511185Serfan.azarkhish@unibo.it    int ret = ioctl(KVM_CHECK_EXTENSION, extension);
26611185Serfan.azarkhish@unibo.it    if (ret == -1)
26711185Serfan.azarkhish@unibo.it        panic("KVM: ioctl failed when checking for extension\n");
26811185Serfan.azarkhish@unibo.it    return ret;
26911185Serfan.azarkhish@unibo.it}
27011185Serfan.azarkhish@unibo.it
27111185Serfan.azarkhish@unibo.itint
27211185Serfan.azarkhish@unibo.itKvm::ioctl(int request, long p1) const
27311185Serfan.azarkhish@unibo.it{
27411185Serfan.azarkhish@unibo.it    assert(kvmFD != -1);
27511185Serfan.azarkhish@unibo.it
27611185Serfan.azarkhish@unibo.it    return ::ioctl(kvmFD, request, p1);
27711185Serfan.azarkhish@unibo.it}
27811185Serfan.azarkhish@unibo.it
27911185Serfan.azarkhish@unibo.itint
28011185Serfan.azarkhish@unibo.itKvm::createVM()
28111185Serfan.azarkhish@unibo.it{
28211185Serfan.azarkhish@unibo.it    int vmFD;
28311185Serfan.azarkhish@unibo.it
28411185Serfan.azarkhish@unibo.it    vmFD = ioctl(KVM_CREATE_VM);
28511185Serfan.azarkhish@unibo.it    if (vmFD == -1)
28611185Serfan.azarkhish@unibo.it        panic("Failed to create KVM VM\n");
28711185Serfan.azarkhish@unibo.it
28811185Serfan.azarkhish@unibo.it    return vmFD;
28911185Serfan.azarkhish@unibo.it}
29011185Serfan.azarkhish@unibo.it
29111185Serfan.azarkhish@unibo.it
29211185Serfan.azarkhish@unibo.itKvmVM::KvmVM(KvmVMParams *params)
29311185Serfan.azarkhish@unibo.it    : SimObject(params),
29411185Serfan.azarkhish@unibo.it      kvm(), system(params->system),
29511185Serfan.azarkhish@unibo.it      vmFD(kvm.createVM()),
29611185Serfan.azarkhish@unibo.it      started(false),
29711185Serfan.azarkhish@unibo.it      nextVCPUID(0)
29811185Serfan.azarkhish@unibo.it{
29911185Serfan.azarkhish@unibo.it    maxMemorySlot = kvm.capNumMemSlots();
30011185Serfan.azarkhish@unibo.it    /* If we couldn't determine how memory slots there are, guess 32. */
30111185Serfan.azarkhish@unibo.it    if (!maxMemorySlot)
30211185Serfan.azarkhish@unibo.it        maxMemorySlot = 32;
30311185Serfan.azarkhish@unibo.it    /* Setup the coalesced MMIO regions */
30411185Serfan.azarkhish@unibo.it    for (int i = 0; i < params->coalescedMMIO.size(); ++i)
30511185Serfan.azarkhish@unibo.it        coalesceMMIO(params->coalescedMMIO[i]);
30611185Serfan.azarkhish@unibo.it}
30711185Serfan.azarkhish@unibo.it
30811185Serfan.azarkhish@unibo.itKvmVM::~KvmVM()
30911185Serfan.azarkhish@unibo.it{
31011185Serfan.azarkhish@unibo.it    close(vmFD);
31111185Serfan.azarkhish@unibo.it}
31211185Serfan.azarkhish@unibo.it
31311185Serfan.azarkhish@unibo.itvoid
31411185Serfan.azarkhish@unibo.itKvmVM::cpuStartup()
31511185Serfan.azarkhish@unibo.it{
31611185Serfan.azarkhish@unibo.it    if (started)
31711185Serfan.azarkhish@unibo.it        return;
31811185Serfan.azarkhish@unibo.it    started = true;
31911185Serfan.azarkhish@unibo.it
32011185Serfan.azarkhish@unibo.it    delayedStartup();
32111185Serfan.azarkhish@unibo.it}
32211185Serfan.azarkhish@unibo.it
32311185Serfan.azarkhish@unibo.itvoid
32411185Serfan.azarkhish@unibo.itKvmVM::delayedStartup()
32511185Serfan.azarkhish@unibo.it{
32611185Serfan.azarkhish@unibo.it    const std::vector<std::pair<AddrRange, uint8_t*> >&memories(
32711185Serfan.azarkhish@unibo.it        system->getPhysMem().getBackingStore());
32811185Serfan.azarkhish@unibo.it
32911185Serfan.azarkhish@unibo.it    DPRINTF(Kvm, "Mapping %i memory region(s)\n", memories.size());
330    for (int slot(0); slot < memories.size(); ++slot) {
331        const AddrRange &range(memories[slot].first);
332        void *pmem(memories[slot].second);
333
334        if (pmem) {
335            DPRINTF(Kvm, "Mapping region: 0x%p -> 0x%llx [size: 0x%llx]\n",
336                    pmem, range.start(), range.size());
337
338            if (range.interleaved()) {
339                panic("Tried to map an interleaved memory range into "
340                      "a KVM VM.\n");
341            }
342
343            const MemSlot slot = allocMemSlot(range.size());
344            setupMemSlot(slot, pmem, range.start(), 0/* flags */);
345        } else {
346            DPRINTF(Kvm, "Zero-region not mapped: [0x%llx]\n", range.start());
347            hack("KVM: Zero memory handled as IO\n");
348        }
349    }
350}
351
352const KvmVM::MemSlot
353KvmVM::allocMemSlot(uint64_t size)
354{
355    if (!size)
356        panic("Memory slots must have non-zero size.\n");
357
358    std::vector<MemorySlot>::iterator pos;
359    for (pos = memorySlots.begin(); pos != memorySlots.end(); pos++) {
360        if (!pos->size) {
361            pos->size = size;
362            pos->active = false;
363            return pos->slot;
364        }
365    }
366
367    uint32_t nextSlot = memorySlots.size();
368    if (nextSlot > maxMemorySlot)
369        panic("Out of memory slots.\n");
370
371    MemorySlot slot;
372    slot.size = size;
373    slot.slot = nextSlot;
374    slot.active = false;
375
376    memorySlots.push_back(slot);
377    return MemSlot(slot.slot);
378}
379
380void
381KvmVM::setupMemSlot(const KvmVM::MemSlot num, void *host_addr, Addr guest,
382                    uint32_t flags)
383{
384    MemorySlot &slot = memorySlots.at(num.num);
385    slot.active = true;
386    setUserMemoryRegion(num.num, host_addr, guest, slot.size, flags);
387}
388
389void
390KvmVM::disableMemSlot(const KvmVM::MemSlot num)
391{
392    MemorySlot &slot = memorySlots.at(num.num);
393    if (slot.active)
394        setUserMemoryRegion(num.num, NULL, 0, 0, 0);
395    slot.active = false;
396}
397
398void
399KvmVM::freeMemSlot(const KvmVM::MemSlot num)
400{
401    disableMemSlot(num.num);
402    MemorySlot &slot = memorySlots.at(num.num);
403    slot.size = 0;
404}
405
406void
407KvmVM::setUserMemoryRegion(uint32_t slot,
408                           void *host_addr, Addr guest_addr,
409                           uint64_t len, uint32_t flags)
410{
411    struct kvm_userspace_memory_region m;
412
413    memset(&m, 0, sizeof(m));
414    m.slot = slot;
415    m.flags = flags;
416    m.guest_phys_addr = (uint64_t)guest_addr;
417    m.memory_size = len;
418    m.userspace_addr = (__u64)host_addr;
419
420    if (ioctl(KVM_SET_USER_MEMORY_REGION, (void *)&m) == -1) {
421        panic("Failed to setup KVM memory region:\n"
422              "\tHost Address: 0x%p\n"
423              "\tGuest Address: 0x%llx\n",
424              "\tSize: %ll\n",
425              "\tFlags: 0x%x\n",
426              m.userspace_addr, m.guest_phys_addr,
427              m.memory_size, m.flags);
428    }
429}
430
431void
432KvmVM::coalesceMMIO(const AddrRange &range)
433{
434    coalesceMMIO(range.start(), range.size());
435}
436
437void
438KvmVM::coalesceMMIO(Addr start, int size)
439{
440    struct kvm_coalesced_mmio_zone zone;
441
442    zone.addr = start;
443    zone.size = size;
444    zone.pad = 0;
445
446    DPRINTF(Kvm, "KVM: Registering coalesced MMIO region [0x%x, 0x%x]\n",
447            zone.addr, zone.addr + zone.size - 1);
448    if (ioctl(KVM_REGISTER_COALESCED_MMIO, (void *)&zone) == -1)
449        panic("KVM: Failed to register coalesced MMIO region (%i)\n",
450              errno);
451}
452
453void
454KvmVM::setTSSAddress(Addr tss_address)
455{
456    if (ioctl(KVM_SET_TSS_ADDR, (unsigned long)tss_address) == -1)
457        panic("KVM: Failed to set VM TSS address\n");
458}
459
460void
461KvmVM::createIRQChip()
462{
463    if (_hasKernelIRQChip)
464        panic("KvmVM::createIRQChip called twice.\n");
465
466    if (ioctl(KVM_CREATE_IRQCHIP) != -1) {
467        _hasKernelIRQChip = true;
468    } else {
469        warn("KVM: Failed to create in-kernel IRQ chip (errno: %i)\n",
470             errno);
471        _hasKernelIRQChip = false;
472    }
473}
474
475void
476KvmVM::setIRQLine(uint32_t irq, bool high)
477{
478    struct kvm_irq_level kvm_level;
479
480    kvm_level.irq = irq;
481    kvm_level.level = high ? 1 : 0;
482
483    if (ioctl(KVM_IRQ_LINE, &kvm_level) == -1)
484        panic("KVM: Failed to set IRQ line level (errno: %i)\n",
485              errno);
486}
487
488int
489KvmVM::createDevice(uint32_t type, uint32_t flags)
490{
491#if defined(KVM_CREATE_DEVICE)
492    struct kvm_create_device dev = { type, 0, flags };
493
494    if (ioctl(KVM_CREATE_DEVICE, &dev) == -1) {
495        panic("KVM: Failed to create device (errno: %i)\n",
496              errno);
497    }
498
499    return dev.fd;
500#else
501    panic("Kernel headers don't support KVM_CREATE_DEVICE\n");
502#endif
503}
504
505int
506KvmVM::createVCPU(long vcpuID)
507{
508    int fd;
509
510    fd = ioctl(KVM_CREATE_VCPU, vcpuID);
511    if (fd == -1)
512        panic("KVM: Failed to create virtual CPU");
513
514    return fd;
515}
516
517long
518KvmVM::allocVCPUID()
519{
520    return nextVCPUID++;
521}
522
523#if defined(__aarch64__)
524void
525KvmVM::kvmArmPreferredTarget(struct kvm_vcpu_init &target) const
526{
527    if (ioctl(KVM_ARM_PREFERRED_TARGET, &target) == -1) {
528        panic("KVM: Failed to get ARM preferred CPU target (errno: %i)\n",
529              errno);
530    }
531}
532#endif
533
534int
535KvmVM::ioctl(int request, long p1) const
536{
537    assert(vmFD != -1);
538
539    return ::ioctl(vmFD, request, p1);
540}
541
542
543KvmVM *
544KvmVMParams::create()
545{
546    static bool created = false;
547    if (created)
548        warn_once("Use of multiple KvmVMs is currently untested!\n");
549
550    created = true;
551
552    return new KvmVM(this);
553}
554