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