vm.cc revision 9883
1/* 2 * Copyright (c) 2012 ARM Limited 3 * All rights reserved 4 * 5 * The license below extends only to copyright in the software and shall 6 * not be construed as granting a license to any other intellectual 7 * property including but not limited to intellectual property relating 8 * to a hardware implementation of the functionality of the software 9 * licensed hereunder. You may use the software subject to the license 10 * terms below provided that you ensure that this notice is replicated 11 * unmodified and in its entirety in all distributions of the software, 12 * modified or unmodified, in source code or in binary form. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions are 16 * met: redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer; 18 * redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution; 21 * neither the name of the copyright holders nor the names of its 22 * contributors may be used to endorse or promote products derived from 23 * this software without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 * 37 * Authors: Andreas Sandberg 38 */ 39 40#include <linux/kvm.h> 41#include <sys/ioctl.h> 42#include <sys/stat.h> 43#include <sys/types.h> 44#include <fcntl.h> 45#include <unistd.h> 46 47#include <cerrno> 48#include <memory> 49 50#include "cpu/kvm/vm.hh" 51#include "debug/Kvm.hh" 52#include "params/KvmVM.hh" 53#include "sim/system.hh" 54 55#define EXPECTED_KVM_API_VERSION 12 56 57#if EXPECTED_KVM_API_VERSION != KVM_API_VERSION 58#error Unsupported KVM version 59#endif 60 61Kvm *Kvm::instance = NULL; 62 63Kvm::Kvm() 64 : kvmFD(-1), apiVersion(-1), vcpuMMapSize(0) 65{ 66 kvmFD = ::open("/dev/kvm", O_RDWR); 67 if (kvmFD == -1) 68 fatal("KVM: Failed to open /dev/kvm\n"); 69 70 apiVersion = ioctl(KVM_GET_API_VERSION); 71 if (apiVersion != EXPECTED_KVM_API_VERSION) 72 fatal("KVM: Incompatible API version\n"); 73 74 vcpuMMapSize = ioctl(KVM_GET_VCPU_MMAP_SIZE); 75 if (vcpuMMapSize == -1) 76 panic("KVM: Failed to get virtual CPU MMAP size\n"); 77} 78 79Kvm::~Kvm() 80{ 81 close(kvmFD); 82} 83 84Kvm * 85Kvm::create() 86{ 87 if (!instance) 88 instance = new Kvm(); 89 90 return instance; 91} 92 93bool 94Kvm::capUserMemory() const 95{ 96 return checkExtension(KVM_CAP_USER_MEMORY) != 0; 97} 98 99bool 100Kvm::capSetTSSAddress() const 101{ 102 return checkExtension(KVM_CAP_SET_TSS_ADDR) != 0; 103} 104 105bool 106Kvm::capExtendedCPUID() const 107{ 108 return checkExtension(KVM_CAP_EXT_CPUID) != 0; 109} 110 111bool 112Kvm::capUserNMI() const 113{ 114#ifdef KVM_CAP_USER_NMI 115 return checkExtension(KVM_CAP_USER_NMI) != 0; 116#else 117 return false; 118#endif 119} 120 121int 122Kvm::capCoalescedMMIO() const 123{ 124 return checkExtension(KVM_CAP_COALESCED_MMIO); 125} 126 127bool 128Kvm::capOneReg() const 129{ 130#ifdef KVM_CAP_ONE_REG 131 return checkExtension(KVM_CAP_ONE_REG) != 0; 132#else 133 return false; 134#endif 135} 136 137bool 138Kvm::capIRQChip() const 139{ 140 return checkExtension(KVM_CAP_IRQCHIP) != 0; 141} 142 143bool 144Kvm::capVCPUEvents() const 145{ 146#ifdef KVM_CAP_VCPU_EVENTS 147 return checkExtension(KVM_CAP_VCPU_EVENTS) != 0; 148#else 149 return false; 150#endif 151} 152 153bool 154Kvm::capDebugRegs() const 155{ 156#ifdef KVM_CAP_DEBUGREGS 157 return checkExtension(KVM_CAP_DEBUGREGS) != 0; 158#else 159 return false; 160#endif 161} 162 163bool 164Kvm::capXCRs() const 165{ 166#ifdef KVM_CAP_XCRS 167 return checkExtension(KVM_CAP_XCRS) != 0; 168#else 169 return false; 170#endif 171} 172 173bool 174Kvm::capXSave() const 175{ 176#ifdef KVM_CAP_XSAVE 177 return checkExtension(KVM_CAP_XSAVE) != 0; 178#else 179 return false; 180#endif 181} 182 183bool 184Kvm::getSupportedCPUID(struct kvm_cpuid2 &cpuid) const 185{ 186#if defined(__i386__) || defined(__x86_64__) 187 if (ioctl(KVM_GET_SUPPORTED_CPUID, (void *)&cpuid) == -1) { 188 if (errno == E2BIG) 189 return false; 190 else 191 panic("KVM: Failed to get supported CPUID (errno: %i)\n", errno); 192 } else 193 return true; 194#else 195 panic("KVM: getSupportedCPUID is unsupported on this platform.\n"); 196#endif 197} 198 199const Kvm::CPUIDVector & 200Kvm::getSupportedCPUID() const 201{ 202 if (supportedCPUIDCache.empty()) { 203 std::unique_ptr<struct kvm_cpuid2> cpuid; 204 int i(1); 205 do { 206 cpuid.reset((struct kvm_cpuid2 *)operator new( 207 sizeof(kvm_cpuid2) + i * sizeof(kvm_cpuid_entry2))); 208 209 cpuid->nent = i; 210 ++i; 211 } while (!getSupportedCPUID(*cpuid)); 212 supportedCPUIDCache.assign(cpuid->entries, 213 cpuid->entries + cpuid->nent); 214 } 215 216 return supportedCPUIDCache; 217} 218 219bool 220Kvm::getSupportedMSRs(struct kvm_msr_list &msrs) const 221{ 222#if defined(__i386__) || defined(__x86_64__) 223 if (ioctl(KVM_GET_MSR_INDEX_LIST, (void *)&msrs) == -1) { 224 if (errno == E2BIG) 225 return false; 226 else 227 panic("KVM: Failed to get supported CPUID (errno: %i)\n", errno); 228 } else 229 return true; 230#else 231 panic("KVM: getSupportedCPUID is unsupported on this platform.\n"); 232#endif 233} 234 235const Kvm::MSRIndexVector & 236Kvm::getSupportedMSRs() const 237{ 238 if (supportedMSRCache.empty()) { 239 std::unique_ptr<struct kvm_msr_list> msrs; 240 int i(0); 241 do { 242 msrs.reset((struct kvm_msr_list *)operator new( 243 sizeof(kvm_msr_list) + i * sizeof(uint32_t))); 244 245 msrs->nmsrs = i; 246 ++i; 247 } while (!getSupportedMSRs(*msrs)); 248 supportedMSRCache.assign(msrs->indices, msrs->indices + msrs->nmsrs); 249 } 250 251 return supportedMSRCache; 252} 253 254int 255Kvm::checkExtension(int extension) const 256{ 257 int ret = ioctl(KVM_CHECK_EXTENSION, extension); 258 if (ret == -1) 259 panic("KVM: ioctl failed when checking for extension\n"); 260 return ret; 261} 262 263int 264Kvm::ioctl(int request, long p1) const 265{ 266 assert(kvmFD != -1); 267 268 return ::ioctl(kvmFD, request, p1); 269} 270 271int 272Kvm::createVM() 273{ 274 int vmFD; 275 276 vmFD = ioctl(KVM_CREATE_VM); 277 if (vmFD == -1) 278 panic("Failed to create KVM VM\n"); 279 280 return vmFD; 281} 282 283 284KvmVM::KvmVM(KvmVMParams *params) 285 : SimObject(params), 286 kvm(), system(params->system), 287 vmFD(kvm.createVM()), 288 started(false), 289 nextVCPUID(0) 290{ 291 /* Setup the coalesced MMIO regions */ 292 for (int i = 0; i < params->coalescedMMIO.size(); ++i) 293 coalesceMMIO(params->coalescedMMIO[i]); 294} 295 296KvmVM::~KvmVM() 297{ 298 close(vmFD); 299} 300 301void 302KvmVM::cpuStartup() 303{ 304 if (started) 305 return; 306 started = true; 307 308 delayedStartup(); 309} 310 311void 312KvmVM::delayedStartup() 313{ 314 const std::vector<std::pair<AddrRange, uint8_t*> >&memories( 315 system->getPhysMem().getBackingStore()); 316 317 DPRINTF(Kvm, "Mapping %i memory region(s)\n", memories.size()); 318 for (int slot(0); slot < memories.size(); ++slot) { 319 const AddrRange &range(memories[slot].first); 320 void *pmem(memories[slot].second); 321 322 if (pmem) { 323 DPRINTF(Kvm, "Mapping region: 0x%p -> 0x%llx [size: 0x%llx]\n", 324 pmem, range.start(), range.size()); 325 326 setUserMemoryRegion(slot, pmem, range, 0 /* flags */); 327 } else { 328 DPRINTF(Kvm, "Zero-region not mapped: [0x%llx]\n", range.start()); 329 hack("KVM: Zero memory handled as IO\n"); 330 } 331 } 332} 333 334void 335KvmVM::setUserMemoryRegion(uint32_t slot, 336 void *host_addr, AddrRange guest_range, 337 uint32_t flags) 338{ 339 if (guest_range.interleaved()) 340 panic("Tried to map an interleaved memory range into a KVM VM.\n"); 341 342 setUserMemoryRegion(slot, host_addr, 343 guest_range.start(), guest_range.size(), 344 flags); 345} 346 347void 348KvmVM::setUserMemoryRegion(uint32_t slot, 349 void *host_addr, Addr guest_addr, 350 uint64_t len, uint32_t flags) 351{ 352 struct kvm_userspace_memory_region m; 353 354 memset(&m, 0, sizeof(m)); 355 m.slot = slot; 356 m.flags = flags; 357 m.guest_phys_addr = (uint64_t)guest_addr; 358 m.memory_size = len; 359 m.userspace_addr = (__u64)host_addr; 360 361 if (ioctl(KVM_SET_USER_MEMORY_REGION, (void *)&m) == -1) { 362 panic("Failed to setup KVM memory region:\n" 363 "\tHost Address: 0x%p\n" 364 "\tGuest Address: 0x%llx\n", 365 "\tSize: %ll\n", 366 "\tFlags: 0x%x\n", 367 m.userspace_addr, m.guest_phys_addr, 368 m.memory_size, m.flags); 369 } 370} 371 372void 373KvmVM::coalesceMMIO(const AddrRange &range) 374{ 375 coalesceMMIO(range.start(), range.size()); 376} 377 378void 379KvmVM::coalesceMMIO(Addr start, int size) 380{ 381 struct kvm_coalesced_mmio_zone zone; 382 383 zone.addr = start; 384 zone.size = size; 385 zone.pad = 0; 386 387 DPRINTF(Kvm, "KVM: Registering coalesced MMIO region [0x%x, 0x%x]\n", 388 zone.addr, zone.addr + zone.size - 1); 389 if (ioctl(KVM_REGISTER_COALESCED_MMIO, (void *)&zone) == -1) 390 panic("KVM: Failed to register coalesced MMIO region (%i)\n", 391 errno); 392} 393 394void 395KvmVM::setTSSAddress(Addr tss_address) 396{ 397 if (ioctl(KVM_SET_TSS_ADDR, (unsigned long)tss_address) == -1) 398 panic("KVM: Failed to set VM TSS address\n"); 399} 400 401void 402KvmVM::createIRQChip() 403{ 404 if (_hasKernelIRQChip) 405 panic("KvmVM::createIRQChip called twice.\n"); 406 407 if (ioctl(KVM_CREATE_IRQCHIP) != -1) { 408 _hasKernelIRQChip = true; 409 } else { 410 warn("KVM: Failed to create in-kernel IRQ chip (errno: %i)\n", 411 errno); 412 _hasKernelIRQChip = false; 413 } 414} 415 416void 417KvmVM::setIRQLine(uint32_t irq, bool high) 418{ 419 struct kvm_irq_level kvm_level; 420 421 kvm_level.irq = irq; 422 kvm_level.level = high ? 1 : 0; 423 424 if (ioctl(KVM_IRQ_LINE, &kvm_level) == -1) 425 panic("KVM: Failed to set IRQ line level (errno: %i)\n", 426 errno); 427} 428 429int 430KvmVM::createVCPU(long vcpuID) 431{ 432 int fd; 433 434 fd = ioctl(KVM_CREATE_VCPU, vcpuID); 435 if (fd == -1) 436 panic("KVM: Failed to create virtual CPU"); 437 438 return fd; 439} 440 441long 442KvmVM::allocVCPUID() 443{ 444 return nextVCPUID++; 445} 446 447int 448KvmVM::ioctl(int request, long p1) const 449{ 450 assert(vmFD != -1); 451 452 return ::ioctl(vmFD, request, p1); 453} 454 455 456KvmVM * 457KvmVMParams::create() 458{ 459 static bool created = false; 460 if (created) 461 warn_once("Use of multiple KvmVMs is currently untested!\n"); 462 463 created = true; 464 465 return new KvmVM(this); 466} 467