vm.cc revision 11363:f3f72c0ab03e
12381SN/A/*
212652Sandreas.sandberg@arm.com * Copyright 2014 Google, Inc.
38949Sandreas.hansson@arm.com * Copyright (c) 2012, 2015 ARM Limited
48949Sandreas.hansson@arm.com * All rights reserved
58949Sandreas.hansson@arm.com *
68949Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall
78949Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual
88949Sandreas.hansson@arm.com * property including but not limited to intellectual property relating
98949Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software
108949Sandreas.hansson@arm.com * licensed hereunder.  You may use the software subject to the license
118949Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated
128949Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software,
138949Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form.
142592SN/A *
1510975Sdavid.hashe@amd.com * Redistribution and use in source and binary forms, with or without
162381SN/A * modification, are permitted provided that the following conditions are
172381SN/A * met: redistributions of source code must retain the above copyright
182381SN/A * notice, this list of conditions and the following disclaimer;
192381SN/A * redistributions in binary form must reproduce the above copyright
202381SN/A * notice, this list of conditions and the following disclaimer in the
212381SN/A * documentation and/or other materials provided with the distribution;
222381SN/A * neither the name of the copyright holders nor the names of its
232381SN/A * contributors may be used to endorse or promote products derived from
242381SN/A * this software without specific prior written permission.
252381SN/A *
262381SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
272381SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
282381SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
292381SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
302381SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
312381SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
322381SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
332381SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
342381SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
352381SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
362381SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
372381SN/A *
382381SN/A * Authors: Andreas Sandberg
392381SN/A */
402665Ssaidi@eecs.umich.edu
412665Ssaidi@eecs.umich.edu#include <linux/kvm.h>
422665Ssaidi@eecs.umich.edu#include <sys/ioctl.h>
432665Ssaidi@eecs.umich.edu#include <sys/stat.h>
449031Sandreas.hansson@arm.com#include <sys/types.h>
4512349Snikos.nikoleris@arm.com#include <fcntl.h>
462381SN/A#include <unistd.h>
472381SN/A
482381SN/A#include <cerrno>
492381SN/A#include <memory>
502662Sstever@eecs.umich.edu
512381SN/A#include "cpu/kvm/vm.hh"
522381SN/A#include "debug/Kvm.hh"
532381SN/A#include "params/KvmVM.hh"
542381SN/A#include "sim/system.hh"
552381SN/A
568229Snate@binkert.org#define EXPECTED_KVM_API_VERSION 12
573348Sbinkertn@umich.edu
583348Sbinkertn@umich.edu#if EXPECTED_KVM_API_VERSION != KVM_API_VERSION
593348Sbinkertn@umich.edu#error Unsupported KVM version
605735Snate@binkert.org#endif
614024Sbinkertn@umich.edu
625735Snate@binkert.orgKvm *Kvm::instance = NULL;
6312334Sgabeblack@google.com
645314Sstever@gmail.comKvm::Kvm()
656216Snate@binkert.org    : kvmFD(-1), apiVersion(-1), vcpuMMapSize(0)
6613347Sgabeblack@google.com{
672392SN/A    kvmFD = ::open("/dev/kvm", O_RDWR);
684167Sbinkertn@umich.edu    if (kvmFD == -1)
692394SN/A        fatal("KVM: Failed to open /dev/kvm\n");
708737Skoansin.tan@gmail.com
713349Sbinkertn@umich.edu    apiVersion = ioctl(KVM_GET_API_VERSION);
722394SN/A    if (apiVersion != EXPECTED_KVM_API_VERSION)
732812Srdreslin@umich.edu        fatal("KVM: Incompatible API version\n");
7412351Snikos.nikoleris@arm.com
752812Srdreslin@umich.edu    vcpuMMapSize = ioctl(KVM_GET_VCPU_MMAP_SIZE);
764022Sstever@eecs.umich.edu    if (vcpuMMapSize == -1)
774022Sstever@eecs.umich.edu        panic("KVM: Failed to get virtual CPU MMAP size\n");
785735Snate@binkert.org}
795735Snate@binkert.org
804022Sstever@eecs.umich.eduKvm::~Kvm()
815735Snate@binkert.org{
825735Snate@binkert.org    close(kvmFD);
835735Snate@binkert.org}
844022Sstever@eecs.umich.edu
854022Sstever@eecs.umich.eduKvm *
864022Sstever@eecs.umich.eduKvm::create()
874022Sstever@eecs.umich.edu{
884473Sstever@eecs.umich.edu    if (!instance)
895319Sstever@gmail.com        instance = new Kvm();
904022Sstever@eecs.umich.edu
914022Sstever@eecs.umich.edu    return instance;
9211199Sandreas.hansson@arm.com}
9311199Sandreas.hansson@arm.com
9412344Snikos.nikoleris@arm.combool
9510883Sali.jafri@arm.comKvm::capUserMemory() const
964022Sstever@eecs.umich.edu{
974022Sstever@eecs.umich.edu    return checkExtension(KVM_CAP_USER_MEMORY) != 0;
984022Sstever@eecs.umich.edu}
994022Sstever@eecs.umich.edu
10010886Sandreas.hansson@arm.combool
1014022Sstever@eecs.umich.eduKvm::capSetTSSAddress() const
1027465Ssteve.reinhardt@amd.com{
1034628Sstever@eecs.umich.edu    return checkExtension(KVM_CAP_SET_TSS_ADDR) != 0;
1047465Ssteve.reinhardt@amd.com}
1057465Ssteve.reinhardt@amd.com
1064022Sstever@eecs.umich.edubool
1074022Sstever@eecs.umich.eduKvm::capExtendedCPUID() const
10810885Sandreas.hansson@arm.com{
10910885Sandreas.hansson@arm.com    return checkExtension(KVM_CAP_EXT_CPUID) != 0;
1104626Sstever@eecs.umich.edu}
1114626Sstever@eecs.umich.edu
1127669Ssteve.reinhardt@amd.combool
1134626Sstever@eecs.umich.eduKvm::capUserNMI() const
1144040Ssaidi@eecs.umich.edu{
1154040Ssaidi@eecs.umich.edu#ifdef KVM_CAP_USER_NMI
1165650Sgblack@eecs.umich.edu    return checkExtension(KVM_CAP_USER_NMI) != 0;
1175650Sgblack@eecs.umich.edu#else
11811256Santhony.gutierrez@amd.com    return false;
11911256Santhony.gutierrez@amd.com#endif
12012347Snikos.nikoleris@arm.com}
12112347Snikos.nikoleris@arm.com
12212347Snikos.nikoleris@arm.comint
12312347Snikos.nikoleris@arm.comKvm::capCoalescedMMIO() const
1244870Sstever@eecs.umich.edu{
1254870Sstever@eecs.umich.edu    return checkExtension(KVM_CAP_COALESCED_MMIO);
1264870Sstever@eecs.umich.edu}
1274870Sstever@eecs.umich.edu
1284870Sstever@eecs.umich.eduint
1294870Sstever@eecs.umich.eduKvm::capNumMemSlots() const
1308436SBrad.Beckmann@amd.com{
1318436SBrad.Beckmann@amd.com#ifdef KVM_CAP_NR_MEMSLOTS
1325314Sstever@gmail.com    return checkExtension(KVM_CAP_NR_MEMSLOTS);
1335314Sstever@gmail.com#else
1348184Ssomayeh@cs.wisc.edu    return 0;
13510886Sandreas.hansson@arm.com#endif
13610886Sandreas.hansson@arm.com}
1374022Sstever@eecs.umich.edu
1384022Sstever@eecs.umich.edubool
1394022Sstever@eecs.umich.eduKvm::capOneReg() const
1404022Sstever@eecs.umich.edu{
1415735Snate@binkert.org#ifdef KVM_CAP_ONE_REG
1425735Snate@binkert.org    return checkExtension(KVM_CAP_ONE_REG) != 0;
1435735Snate@binkert.org#else
1444022Sstever@eecs.umich.edu    return false;
1454022Sstever@eecs.umich.edu#endif
1464626Sstever@eecs.umich.edu}
1474626Sstever@eecs.umich.edu
1487465Ssteve.reinhardt@amd.combool
1494022Sstever@eecs.umich.eduKvm::capIRQChip() const
15012347Snikos.nikoleris@arm.com{
15111284Sandreas.hansson@arm.com    return checkExtension(KVM_CAP_IRQCHIP) != 0;
1524626Sstever@eecs.umich.edu}
1534626Sstever@eecs.umich.edu
1544626Sstever@eecs.umich.edubool
15511199Sandreas.hansson@arm.comKvm::capVCPUEvents() const
1564022Sstever@eecs.umich.edu{
1574022Sstever@eecs.umich.edu#ifdef KVM_CAP_VCPU_EVENTS
1586076Sgblack@eecs.umich.edu    return checkExtension(KVM_CAP_VCPU_EVENTS) != 0;
1594626Sstever@eecs.umich.edu#else
1604870Sstever@eecs.umich.edu    return false;
1615314Sstever@gmail.com#endif
1628184Ssomayeh@cs.wisc.edu}
16311600Sandreas.hansson@arm.com
1644022Sstever@eecs.umich.edubool
1654022Sstever@eecs.umich.eduKvm::capDebugRegs() const
1664022Sstever@eecs.umich.edu{
1675735Snate@binkert.org#ifdef KVM_CAP_DEBUGREGS
1685735Snate@binkert.org    return checkExtension(KVM_CAP_DEBUGREGS) != 0;
1695735Snate@binkert.org#else
1705735Snate@binkert.org    return false;
1715735Snate@binkert.org#endif
1725735Snate@binkert.org}
1735735Snate@binkert.org
1744022Sstever@eecs.umich.edubool
1755735Snate@binkert.orgKvm::capXCRs() const
1765735Snate@binkert.org{
1774022Sstever@eecs.umich.edu#ifdef KVM_CAP_XCRS
1785735Snate@binkert.org    return checkExtension(KVM_CAP_XCRS) != 0;
1794022Sstever@eecs.umich.edu#else
1804022Sstever@eecs.umich.edu    return false;
1814022Sstever@eecs.umich.edu#endif
1825735Snate@binkert.org}
1834022Sstever@eecs.umich.edu
1844022Sstever@eecs.umich.edubool
1854022Sstever@eecs.umich.eduKvm::capXSave() const
1864022Sstever@eecs.umich.edu{
1874022Sstever@eecs.umich.edu#ifdef KVM_CAP_XSAVE
1884022Sstever@eecs.umich.edu    return checkExtension(KVM_CAP_XSAVE) != 0;
1895735Snate@binkert.org#else
1905735Snate@binkert.org    return false;
1915735Snate@binkert.org#endif
1924022Sstever@eecs.umich.edu}
1934022Sstever@eecs.umich.edu
1944022Sstever@eecs.umich.edu
1954022Sstever@eecs.umich.edu#if defined(__i386__) || defined(__x86_64__)
1964022Sstever@eecs.umich.edubool
19710583SCurtis.Dunham@arm.comKvm::getSupportedCPUID(struct kvm_cpuid2 &cpuid) const
19810583SCurtis.Dunham@arm.com{
19910583SCurtis.Dunham@arm.com    if (ioctl(KVM_GET_SUPPORTED_CPUID, (void *)&cpuid) == -1) {
20010583SCurtis.Dunham@arm.com        if (errno == E2BIG)
20110583SCurtis.Dunham@arm.com            return false;
20211284Sandreas.hansson@arm.com        else
20310583SCurtis.Dunham@arm.com            panic("KVM: Failed to get supported CPUID (errno: %i)\n", errno);
20410583SCurtis.Dunham@arm.com    } else
20511199Sandreas.hansson@arm.com        return true;
20612347Snikos.nikoleris@arm.com}
20711600Sandreas.hansson@arm.com
20811199Sandreas.hansson@arm.comconst Kvm::CPUIDVector &
20911199Sandreas.hansson@arm.comKvm::getSupportedCPUID() const
21011199Sandreas.hansson@arm.com{
21111199Sandreas.hansson@arm.com    if (supportedCPUIDCache.empty()) {
21211199Sandreas.hansson@arm.com        std::unique_ptr<struct kvm_cpuid2> cpuid;
21311199Sandreas.hansson@arm.com        int i(1);
21410570Sandreas.hansson@arm.com        do {
21510570Sandreas.hansson@arm.com            cpuid.reset((struct kvm_cpuid2 *)operator new(
21610570Sandreas.hansson@arm.com                            sizeof(kvm_cpuid2) + i * sizeof(kvm_cpuid_entry2)));
21710570Sandreas.hansson@arm.com
21810570Sandreas.hansson@arm.com            cpuid->nent = i;
21910570Sandreas.hansson@arm.com            ++i;
2204022Sstever@eecs.umich.edu        } while (!getSupportedCPUID(*cpuid));
2216102Sgblack@eecs.umich.edu        supportedCPUIDCache.assign(cpuid->entries,
22210343SCurtis.Dunham@arm.com                                   cpuid->entries + cpuid->nent);
22310343SCurtis.Dunham@arm.com    }
22410343SCurtis.Dunham@arm.com
22510343SCurtis.Dunham@arm.com    return supportedCPUIDCache;
2264870Sstever@eecs.umich.edu}
2275314Sstever@gmail.com
2288184Ssomayeh@cs.wisc.edubool
2294022Sstever@eecs.umich.eduKvm::getSupportedMSRs(struct kvm_msr_list &msrs) const
23011294Sandreas.hansson@arm.com{
2315735Snate@binkert.org    if (ioctl(KVM_GET_MSR_INDEX_LIST, (void *)&msrs) == -1) {
2325735Snate@binkert.org        if (errno == E2BIG)
2334022Sstever@eecs.umich.edu            return false;
2344022Sstever@eecs.umich.edu        else
2354022Sstever@eecs.umich.edu            panic("KVM: Failed to get supported CPUID (errno: %i)\n", errno);
2365735Snate@binkert.org    } else
2375735Snate@binkert.org        return true;
2384022Sstever@eecs.umich.edu}
2394022Sstever@eecs.umich.edu
2405735Snate@binkert.orgconst Kvm::MSRIndexVector &
2415735Snate@binkert.orgKvm::getSupportedMSRs() const
2425735Snate@binkert.org{
2434022Sstever@eecs.umich.edu    if (supportedMSRCache.empty()) {
2445735Snate@binkert.org        std::unique_ptr<struct kvm_msr_list> msrs;
2455735Snate@binkert.org        int i(0);
2464022Sstever@eecs.umich.edu        do {
2474022Sstever@eecs.umich.edu            msrs.reset((struct kvm_msr_list *)operator new(
2482381SN/A                           sizeof(kvm_msr_list) + i * sizeof(uint32_t)));
2492662Sstever@eecs.umich.edu
2502662Sstever@eecs.umich.edu            msrs->nmsrs = i;
2512662Sstever@eecs.umich.edu            ++i;
2522662Sstever@eecs.umich.edu        } while (!getSupportedMSRs(*msrs));
2532662Sstever@eecs.umich.edu        supportedMSRCache.assign(msrs->indices, msrs->indices + msrs->nmsrs);
2542381SN/A    }
2559044SAli.Saidi@ARM.com
2562381SN/A    return supportedMSRCache;
2572813Srdreslin@umich.edu}
2585735Snate@binkert.org
2595735Snate@binkert.org#endif // x86-specific
2604022Sstever@eecs.umich.edu
2615735Snate@binkert.org
2625735Snate@binkert.orgint
26310938Sandreas.hansson@arm.comKvm::checkExtension(int extension) const
26410938Sandreas.hansson@arm.com{
26512349Snikos.nikoleris@arm.com    int ret = ioctl(KVM_CHECK_EXTENSION, extension);
26610938Sandreas.hansson@arm.com    if (ret == -1)
26711284Sandreas.hansson@arm.com        panic("KVM: ioctl failed when checking for extension\n");
26811284Sandreas.hansson@arm.com    return ret;
26911284Sandreas.hansson@arm.com}
27011284Sandreas.hansson@arm.com
27110938Sandreas.hansson@arm.comint
27210938Sandreas.hansson@arm.comKvm::ioctl(int request, long p1) const
27310938Sandreas.hansson@arm.com{
27411284Sandreas.hansson@arm.com    assert(kvmFD != -1);
27511284Sandreas.hansson@arm.com
27611284Sandreas.hansson@arm.com    return ::ioctl(kvmFD, request, p1);
27711284Sandreas.hansson@arm.com}
27811284Sandreas.hansson@arm.com
27911284Sandreas.hansson@arm.comint
28011284Sandreas.hansson@arm.comKvm::createVM()
28111284Sandreas.hansson@arm.com{
28211284Sandreas.hansson@arm.com    int vmFD;
28310938Sandreas.hansson@arm.com
28412346Snikos.nikoleris@arm.com    vmFD = ioctl(KVM_CREATE_VM);
28512346Snikos.nikoleris@arm.com    if (vmFD == -1)
28612346Snikos.nikoleris@arm.com        panic("Failed to create KVM VM\n");
28712346Snikos.nikoleris@arm.com
28812349Snikos.nikoleris@arm.com    return vmFD;
28912349Snikos.nikoleris@arm.com}
29012349Snikos.nikoleris@arm.com
29112349Snikos.nikoleris@arm.com
29211057Sandreas.hansson@arm.comKvmVM::KvmVM(KvmVMParams *params)
29311057Sandreas.hansson@arm.com    : SimObject(params),
29411057Sandreas.hansson@arm.com      kvm(new Kvm()), system(params->system),
29511057Sandreas.hansson@arm.com      vmFD(kvm->createVM()),
29610938Sandreas.hansson@arm.com      started(false),
29710938Sandreas.hansson@arm.com      nextVCPUID(0)
29810938Sandreas.hansson@arm.com{
29910938Sandreas.hansson@arm.com    maxMemorySlot = kvm->capNumMemSlots();
30010938Sandreas.hansson@arm.com    /* If we couldn't determine how memory slots there are, guess 32. */
30110938Sandreas.hansson@arm.com    if (!maxMemorySlot)
30210938Sandreas.hansson@arm.com        maxMemorySlot = 32;
30310938Sandreas.hansson@arm.com    /* Setup the coalesced MMIO regions */
30410938Sandreas.hansson@arm.com    for (int i = 0; i < params->coalescedMMIO.size(); ++i)
30510938Sandreas.hansson@arm.com        coalesceMMIO(params->coalescedMMIO[i]);
30610938Sandreas.hansson@arm.com}
30710938Sandreas.hansson@arm.com
30810938Sandreas.hansson@arm.comKvmVM::~KvmVM()
30910938Sandreas.hansson@arm.com{
31010938Sandreas.hansson@arm.com    if (vmFD != -1)
31110938Sandreas.hansson@arm.com        close(vmFD);
3125735Snate@binkert.org
3135735Snate@binkert.org    if (kvm)
3145735Snate@binkert.org        delete kvm;
3155735Snate@binkert.org}
3164022Sstever@eecs.umich.edu
3174022Sstever@eecs.umich.eduvoid
3185735Snate@binkert.orgKvmVM::notifyFork()
3194870Sstever@eecs.umich.edu{
3204870Sstever@eecs.umich.edu    if (vmFD != -1) {
32112351Snikos.nikoleris@arm.com        if (close(vmFD) == -1)
32212351Snikos.nikoleris@arm.com            warn("kvm VM: notifyFork failed to close vmFD\n");
3235735Snate@binkert.org
32412749Sgiacomo.travaglini@arm.com        vmFD = -1;
3254870Sstever@eecs.umich.edu
3262566SN/A        delete kvm;
3275735Snate@binkert.org        kvm = NULL;
32812633Sodanrc@yahoo.com.br    }
32912633Sodanrc@yahoo.com.br}
3305735Snate@binkert.org
33112633Sodanrc@yahoo.com.brvoid
3325735Snate@binkert.orgKvmVM::cpuStartup()
3332566SN/A{
3342566SN/A    if (started)
3352566SN/A        return;
3365735Snate@binkert.org    started = true;
3375735Snate@binkert.org
3382381SN/A    delayedStartup();
3392381SN/A}
34010028SGiacomo.Gabrielli@arm.com
34110028SGiacomo.Gabrielli@arm.comvoid
34210028SGiacomo.Gabrielli@arm.comKvmVM::delayedStartup()
3435735Snate@binkert.org{
3446227Snate@binkert.org    const std::vector<std::pair<AddrRange, uint8_t*> >&memories(
3452381SN/A        system->getPhysMem().getBackingStore());
3465735Snate@binkert.org
34710723Sandreas.hansson@arm.com    DPRINTF(Kvm, "Mapping %i memory region(s)\n", memories.size());
3488668Sgeoffrey.blake@arm.com    for (int slot(0); slot < memories.size(); ++slot) {
34910723Sandreas.hansson@arm.com        const AddrRange &range(memories[slot].first);
3508668Sgeoffrey.blake@arm.com        void *pmem(memories[slot].second);
35112966SMatteo.Andreozzi@arm.com
35212966SMatteo.Andreozzi@arm.com        if (pmem) {
35312966SMatteo.Andreozzi@arm.com            DPRINTF(Kvm, "Mapping region: 0x%p -> 0x%llx [size: 0x%llx]\n",
3542641Sstever@eecs.umich.edu                    pmem, range.start(), range.size());
3552811Srdreslin@umich.edu
3569547Sandreas.hansson@arm.com            if (range.interleaved()) {
35710694SMarco.Balboni@ARM.com                panic("Tried to map an interleaved memory range into "
35810405Sandreas.hansson@arm.com                      "a KVM VM.\n");
35910405Sandreas.hansson@arm.com            }
36010405Sandreas.hansson@arm.com
36110405Sandreas.hansson@arm.com            const MemSlot slot = allocMemSlot(range.size());
3629547Sandreas.hansson@arm.com            setupMemSlot(slot, pmem, range.start(), 0/* flags */);
36310694SMarco.Balboni@ARM.com        } else {
3643218Sgblack@eecs.umich.edu            DPRINTF(Kvm, "Zero-region not mapped: [0x%llx]\n", range.start());
3659547Sandreas.hansson@arm.com            hack("KVM: Zero memory handled as IO\n");
36611127Sandreas.hansson@arm.com        }
36711127Sandreas.hansson@arm.com    }
36811127Sandreas.hansson@arm.com}
36911127Sandreas.hansson@arm.com
37011127Sandreas.hansson@arm.comconst KvmVM::MemSlot
37111127Sandreas.hansson@arm.comKvmVM::allocMemSlot(uint64_t size)
37211127Sandreas.hansson@arm.com{
37311127Sandreas.hansson@arm.com    if (!size)
37410694SMarco.Balboni@ARM.com        panic("Memory slots must have non-zero size.\n");
37510694SMarco.Balboni@ARM.com
37610694SMarco.Balboni@ARM.com    std::vector<MemorySlot>::iterator pos;
37710694SMarco.Balboni@ARM.com    for (pos = memorySlots.begin(); pos != memorySlots.end(); pos++) {
37810405Sandreas.hansson@arm.com        if (!pos->size) {
37910405Sandreas.hansson@arm.com            pos->size = size;
3809547Sandreas.hansson@arm.com            pos->active = false;
38110694SMarco.Balboni@ARM.com            return pos->slot;
3823218Sgblack@eecs.umich.edu        }
3835735Snate@binkert.org    }
3845735Snate@binkert.org
3859542Sandreas.hansson@arm.com    uint32_t nextSlot = memorySlots.size();
3869542Sandreas.hansson@arm.com    if (nextSlot > maxMemorySlot)
3879542Sandreas.hansson@arm.com        panic("Out of memory slots.\n");
3889542Sandreas.hansson@arm.com
3899542Sandreas.hansson@arm.com    MemorySlot slot;
3909542Sandreas.hansson@arm.com    slot.size = size;
3919542Sandreas.hansson@arm.com    slot.slot = nextSlot;
3929542Sandreas.hansson@arm.com    slot.active = false;
3939542Sandreas.hansson@arm.com
3949542Sandreas.hansson@arm.com    memorySlots.push_back(slot);
3959542Sandreas.hansson@arm.com    return MemSlot(slot.slot);
3969542Sandreas.hansson@arm.com}
3979542Sandreas.hansson@arm.com
3989542Sandreas.hansson@arm.comvoid
3995735Snate@binkert.orgKvmVM::setupMemSlot(const KvmVM::MemSlot num, void *host_addr, Addr guest,
4005735Snate@binkert.org                    uint32_t flags)
4015735Snate@binkert.org{
4029542Sandreas.hansson@arm.com    MemorySlot &slot = memorySlots.at(num.num);
4039542Sandreas.hansson@arm.com    slot.active = true;
4042641Sstever@eecs.umich.edu    setUserMemoryRegion(num.num, host_addr, guest, slot.size, flags);
4052641Sstever@eecs.umich.edu}
4062641Sstever@eecs.umich.edu
4075315Sstever@gmail.comvoid
4085315Sstever@gmail.comKvmVM::disableMemSlot(const KvmVM::MemSlot num)
4095315Sstever@gmail.com{
4105315Sstever@gmail.com    MemorySlot &slot = memorySlots.at(num.num);
4119044SAli.Saidi@ARM.com    if (slot.active)
4125735Snate@binkert.org        setUserMemoryRegion(num.num, NULL, 0, 0, 0);
4135735Snate@binkert.org    slot.active = false;
4145735Snate@binkert.org}
4155735Snate@binkert.org
4165735Snate@binkert.orgvoid
4175735Snate@binkert.orgKvmVM::freeMemSlot(const KvmVM::MemSlot num)
4185735Snate@binkert.org{
4195314Sstever@gmail.com    disableMemSlot(num.num);
4205314Sstever@gmail.com    MemorySlot &slot = memorySlots.at(num.num);
4215314Sstever@gmail.com    slot.size = 0;
4225735Snate@binkert.org}
4235314Sstever@gmail.com
4245314Sstever@gmail.comvoid
4255314Sstever@gmail.comKvmVM::setUserMemoryRegion(uint32_t slot,
4265314Sstever@gmail.com                           void *host_addr, Addr guest_addr,
4275314Sstever@gmail.com                           uint64_t len, uint32_t flags)
4285314Sstever@gmail.com{
4295314Sstever@gmail.com    struct kvm_userspace_memory_region m;
4305314Sstever@gmail.com
4315314Sstever@gmail.com    memset(&m, 0, sizeof(m));
4325314Sstever@gmail.com    m.slot = slot;
4335314Sstever@gmail.com    m.flags = flags;
4345314Sstever@gmail.com    m.guest_phys_addr = (uint64_t)guest_addr;
4355314Sstever@gmail.com    m.memory_size = len;
4365314Sstever@gmail.com    m.userspace_addr = (__u64)host_addr;
4375735Snate@binkert.org
4385735Snate@binkert.org    if (ioctl(KVM_SET_USER_MEMORY_REGION, (void *)&m) == -1) {
4395735Snate@binkert.org        panic("Failed to setup KVM memory region:\n"
4405314Sstever@gmail.com              "\tHost Address: 0x%p\n"
4415315Sstever@gmail.com              "\tGuest Address: 0x%llx\n",
4425735Snate@binkert.org              "\tSize: %ll\n",
4435735Snate@binkert.org              "\tFlags: 0x%x\n",
4445315Sstever@gmail.com              m.userspace_addr, m.guest_phys_addr,
4455735Snate@binkert.org              m.memory_size, m.flags);
4465735Snate@binkert.org    }
4475314Sstever@gmail.com}
4485314Sstever@gmail.com
4495735Snate@binkert.orgvoid
4505735Snate@binkert.orgKvmVM::coalesceMMIO(const AddrRange &range)
4515735Snate@binkert.org{
4525735Snate@binkert.org    coalesceMMIO(range.start(), range.size());
4535314Sstever@gmail.com}
4545735Snate@binkert.org
4555735Snate@binkert.orgvoid
4565735Snate@binkert.orgKvmVM::coalesceMMIO(Addr start, int size)
4575315Sstever@gmail.com{
4585735Snate@binkert.org    struct kvm_coalesced_mmio_zone zone;
4595735Snate@binkert.org
4605314Sstever@gmail.com    zone.addr = start;
4615735Snate@binkert.org    zone.size = size;
4625735Snate@binkert.org    zone.pad = 0;
4635735Snate@binkert.org
4645735Snate@binkert.org    DPRINTF(Kvm, "KVM: Registering coalesced MMIO region [0x%x, 0x%x]\n",
4655735Snate@binkert.org            zone.addr, zone.addr + zone.size - 1);
4665314Sstever@gmail.com    if (ioctl(KVM_REGISTER_COALESCED_MMIO, (void *)&zone) == -1)
4675314Sstever@gmail.com        panic("KVM: Failed to register coalesced MMIO region (%i)\n",
4685314Sstever@gmail.com              errno);
4695735Snate@binkert.org}
4705735Snate@binkert.org
4715735Snate@binkert.orgvoid
4725735Snate@binkert.orgKvmVM::setTSSAddress(Addr tss_address)
4739542Sandreas.hansson@arm.com{
4745735Snate@binkert.org    if (ioctl(KVM_SET_TSS_ADDR, (unsigned long)tss_address) == -1)
4755735Snate@binkert.org        panic("KVM: Failed to set VM TSS address\n");
4765735Snate@binkert.org}
4772662Sstever@eecs.umich.edu
4782641Sstever@eecs.umich.eduvoid
4799542Sandreas.hansson@arm.comKvmVM::createIRQChip()
4809542Sandreas.hansson@arm.com{
4819542Sandreas.hansson@arm.com    if (_hasKernelIRQChip)
4829542Sandreas.hansson@arm.com        panic("KvmVM::createIRQChip called twice.\n");
4839542Sandreas.hansson@arm.com
4849542Sandreas.hansson@arm.com    if (ioctl(KVM_CREATE_IRQCHIP) != -1) {
4859542Sandreas.hansson@arm.com        _hasKernelIRQChip = true;
4869542Sandreas.hansson@arm.com    } else {
4879542Sandreas.hansson@arm.com        warn("KVM: Failed to create in-kernel IRQ chip (errno: %i)\n",
4889542Sandreas.hansson@arm.com             errno);
4899542Sandreas.hansson@arm.com        _hasKernelIRQChip = false;
4909542Sandreas.hansson@arm.com    }
4919542Sandreas.hansson@arm.com}
4929542Sandreas.hansson@arm.com
4939542Sandreas.hansson@arm.comvoid
4949542Sandreas.hansson@arm.comKvmVM::setIRQLine(uint32_t irq, bool high)
4959542Sandreas.hansson@arm.com{
4969542Sandreas.hansson@arm.com    struct kvm_irq_level kvm_level;
4979542Sandreas.hansson@arm.com
4989542Sandreas.hansson@arm.com    kvm_level.irq = irq;
4999543Ssascha.bischoff@arm.com    kvm_level.level = high ? 1 : 0;
5009543Ssascha.bischoff@arm.com
5019543Ssascha.bischoff@arm.com    if (ioctl(KVM_IRQ_LINE, &kvm_level) == -1)
5029543Ssascha.bischoff@arm.com        panic("KVM: Failed to set IRQ line level (errno: %i)\n",
5039543Ssascha.bischoff@arm.com              errno);
5049543Ssascha.bischoff@arm.com}
5059543Ssascha.bischoff@arm.com
5069543Ssascha.bischoff@arm.comint
5079543Ssascha.bischoff@arm.comKvmVM::createDevice(uint32_t type, uint32_t flags)
5089543Ssascha.bischoff@arm.com{
5099543Ssascha.bischoff@arm.com#if defined(KVM_CREATE_DEVICE)
5109543Ssascha.bischoff@arm.com    struct kvm_create_device dev = { type, 0, flags };
5119543Ssascha.bischoff@arm.com
5129543Ssascha.bischoff@arm.com    if (ioctl(KVM_CREATE_DEVICE, &dev) == -1) {
5139543Ssascha.bischoff@arm.com        panic("KVM: Failed to create device (errno: %i)\n",
5149543Ssascha.bischoff@arm.com              errno);
5159543Ssascha.bischoff@arm.com    }
5169543Ssascha.bischoff@arm.com
5179543Ssascha.bischoff@arm.com    return dev.fd;
5185735Snate@binkert.org#else
5195735Snate@binkert.org    panic("Kernel headers don't support KVM_CREATE_DEVICE\n");
5204022Sstever@eecs.umich.edu#endif
5212811Srdreslin@umich.edu}
5225735Snate@binkert.org
5234022Sstever@eecs.umich.eduint
5242811Srdreslin@umich.eduKvmVM::createVCPU(long vcpuID)
52510583SCurtis.Dunham@arm.com{
52610583SCurtis.Dunham@arm.com    int fd;
52710583SCurtis.Dunham@arm.com
52810583SCurtis.Dunham@arm.com    fd = ioctl(KVM_CREATE_VCPU, vcpuID);
52910583SCurtis.Dunham@arm.com    if (fd == -1)
53011287Sandreas.hansson@arm.com        panic("KVM: Failed to create virtual CPU");
53111287Sandreas.hansson@arm.com
53211287Sandreas.hansson@arm.com    return fd;
53311287Sandreas.hansson@arm.com}
53411287Sandreas.hansson@arm.com
53511287Sandreas.hansson@arm.comlong
53611287Sandreas.hansson@arm.comKvmVM::allocVCPUID()
53711287Sandreas.hansson@arm.com{
53811287Sandreas.hansson@arm.com    return nextVCPUID++;
53910583SCurtis.Dunham@arm.com}
54010583SCurtis.Dunham@arm.com
54111199Sandreas.hansson@arm.com#if defined(__aarch64__)
54212347Snikos.nikoleris@arm.comvoid
54311600Sandreas.hansson@arm.comKvmVM::kvmArmPreferredTarget(struct kvm_vcpu_init &target) const
54411199Sandreas.hansson@arm.com{
54510583SCurtis.Dunham@arm.com    if (ioctl(KVM_ARM_PREFERRED_TARGET, &target) == -1) {
54611286Sandreas.hansson@arm.com        panic("KVM: Failed to get ARM preferred CPU target (errno: %i)\n",
54711286Sandreas.hansson@arm.com              errno);
54811286Sandreas.hansson@arm.com    }
54911286Sandreas.hansson@arm.com}
55011286Sandreas.hansson@arm.com#endif
55110583SCurtis.Dunham@arm.com
55210583SCurtis.Dunham@arm.comint
55310583SCurtis.Dunham@arm.comKvmVM::ioctl(int request, long p1) const
55410583SCurtis.Dunham@arm.com{
5552812Srdreslin@umich.edu    assert(vmFD != -1);
55611284Sandreas.hansson@arm.com
55711284Sandreas.hansson@arm.com    return ::ioctl(vmFD, request, p1);
55811284Sandreas.hansson@arm.com}
55911284Sandreas.hansson@arm.com
56011284Sandreas.hansson@arm.com
56111284Sandreas.hansson@arm.comKvmVM *
56211284Sandreas.hansson@arm.comKvmVMParams::create()
56311284Sandreas.hansson@arm.com{
56411284Sandreas.hansson@arm.com    static bool created = false;
56511284Sandreas.hansson@arm.com    if (created)
56611284Sandreas.hansson@arm.com        warn_once("Use of multiple KvmVMs is currently untested!\n");
56711284Sandreas.hansson@arm.com
56811284Sandreas.hansson@arm.com    created = true;
56911284Sandreas.hansson@arm.com
57011284Sandreas.hansson@arm.com    return new KvmVM(this);
57111284Sandreas.hansson@arm.com}
57211284Sandreas.hansson@arm.com