Go to the documentation of this file.
42 #include <linux/kvm.h>
43 #include <sys/ioctl.h>
45 #include <sys/types.h>
52 #include "debug/Kvm.hh"
53 #include "params/KvmVM.hh"
56 #define EXPECTED_KVM_API_VERSION 12
58 #if EXPECTED_KVM_API_VERSION != KVM_API_VERSION
59 #error Unsupported KVM version
65 : kvmFD(-1), apiVersion(-1), vcpuMMapSize(0)
67 kvmFD = ::open(
"/dev/kvm", O_RDWR);
69 fatal(
"KVM: Failed to open /dev/kvm\n");
73 fatal(
"KVM: Incompatible API version\n");
77 panic(
"KVM: Failed to get virtual CPU MMAP size\n");
115 #ifdef KVM_CAP_USER_NMI
131 #ifdef KVM_CAP_NR_MEMSLOTS
141 #ifdef KVM_CAP_ONE_REG
157 #ifdef KVM_CAP_VCPU_EVENTS
167 #ifdef KVM_CAP_DEBUGREGS
195 #if defined(__i386__) || defined(__x86_64__)
197 Kvm::getSupportedCPUID(
struct kvm_cpuid2 &
cpuid)
const
199 if (
ioctl(KVM_GET_SUPPORTED_CPUID, (
void *)&
cpuid) == -1) {
203 panic(
"KVM: Failed to get supported CPUID (errno: %i)\n", errno);
208 const Kvm::CPUIDVector &
209 Kvm::getSupportedCPUID()
const
211 if (supportedCPUIDCache.empty()) {
212 std::unique_ptr<struct kvm_cpuid2>
cpuid;
215 cpuid.reset((
struct kvm_cpuid2 *)
operator new(
216 sizeof(kvm_cpuid2) +
i *
sizeof(kvm_cpuid_entry2)));
220 }
while (!getSupportedCPUID(*
cpuid));
221 supportedCPUIDCache.assign(
cpuid->entries,
225 return supportedCPUIDCache;
229 Kvm::getSupportedMSRs(
struct kvm_msr_list &msrs)
const
231 if (
ioctl(KVM_GET_MSR_INDEX_LIST, (
void *)&msrs) == -1) {
235 panic(
"KVM: Failed to get supported CPUID (errno: %i)\n", errno);
240 const Kvm::MSRIndexVector &
241 Kvm::getSupportedMSRs()
const
243 if (supportedMSRCache.empty()) {
244 std::unique_ptr<struct kvm_msr_list> msrs;
247 msrs.reset((
struct kvm_msr_list *)
operator new(
248 sizeof(kvm_msr_list) +
i *
sizeof(uint32_t)));
252 }
while (!getSupportedMSRs(*msrs));
253 supportedMSRCache.assign(msrs->indices, msrs->indices + msrs->nmsrs);
256 return supportedMSRCache;
259 #endif // x86-specific
265 int ret =
ioctl(KVM_CHECK_EXTENSION, extension);
267 panic(
"KVM: ioctl failed when checking for extension\n");
276 return ::ioctl(
kvmFD, request, p1);
284 vmFD =
ioctl(KVM_CREATE_VM);
286 panic(
"Failed to create KVM VM\n");
295 vmFD(kvm->createVM()),
297 _hasKernelIRQChip(false),
305 for (
int i = 0;
i <
params->coalescedMMIO.size(); ++
i)
322 if (close(
vmFD) == -1)
323 warn(
"kvm VM: notifyFork failed to close vmFD\n");
349 DPRINTF(
Kvm,
"Mapping %i memory region(s)\n", memories.size());
350 for (
int slot(0); slot < memories.size(); ++slot) {
351 if (!memories[slot].kvmMap) {
352 DPRINTF(
Kvm,
"Skipping region marked as not usable by KVM\n");
356 const AddrRange &range(memories[slot].range);
357 void *pmem(memories[slot].pmem);
360 DPRINTF(
Kvm,
"Mapping region: 0x%p -> 0x%llx [size: 0x%llx]\n",
364 panic(
"Tried to map an interleaved memory range into "
372 hack(
"KVM: Zero memory handled as IO\n");
381 panic(
"Memory slots must have non-zero size.\n");
394 panic(
"Out of memory slots.\n");
398 slot.
slot = nextSlot;
433 void *host_addr,
Addr guest_addr,
434 uint64_t
len, uint32_t flags)
436 struct kvm_userspace_memory_region
m;
438 memset(&
m, 0,
sizeof(
m));
441 m.guest_phys_addr = (uint64_t)guest_addr;
443 m.userspace_addr = (__u64)host_addr;
445 if (
ioctl(KVM_SET_USER_MEMORY_REGION, (
void *)&
m) == -1) {
446 panic(
"Failed to setup KVM memory region:\n"
447 "\tHost Address: 0x%p\n"
448 "\tGuest Address: 0x%llx\n",
451 m.userspace_addr,
m.guest_phys_addr,
452 m.memory_size,
m.flags);
465 struct kvm_coalesced_mmio_zone zone;
471 DPRINTF(
Kvm,
"KVM: Registering coalesced MMIO region [0x%x, 0x%x]\n",
472 zone.addr, zone.addr + zone.size - 1);
473 if (
ioctl(KVM_REGISTER_COALESCED_MMIO, (
void *)&zone) == -1)
474 panic(
"KVM: Failed to register coalesced MMIO region (%i)\n",
481 if (
ioctl(KVM_SET_TSS_ADDR, (
unsigned long)tss_address) == -1)
482 panic(
"KVM: Failed to set VM TSS address\n");
489 panic(
"KvmVM::createIRQChip called twice.\n");
491 if (
ioctl(KVM_CREATE_IRQCHIP) != -1) {
494 warn(
"KVM: Failed to create in-kernel IRQ chip (errno: %i)\n",
503 struct kvm_irq_level kvm_level;
506 kvm_level.level = high ? 1 : 0;
508 if (
ioctl(KVM_IRQ_LINE, &kvm_level) == -1)
509 panic(
"KVM: Failed to set IRQ line level (errno: %i)\n",
516 #if defined(KVM_CREATE_DEVICE)
517 struct kvm_create_device dev = {
type, 0, flags };
519 if (
ioctl(KVM_CREATE_DEVICE, &dev) == -1) {
520 panic(
"KVM: Failed to create device (errno: %i)\n",
526 panic(
"Kernel headers don't support KVM_CREATE_DEVICE\n");
533 panic_if(
system !=
nullptr,
"setSystem() can only be called once");
534 panic_if(
s ==
nullptr,
"setSystem() called with null System*");
541 assert(
system !=
nullptr);
551 fd =
ioctl(KVM_CREATE_VCPU, vcpuID);
553 panic(
"KVM: Failed to create virtual CPU");
564 #if defined(__aarch64__)
566 KvmVM::kvmArmPreferredTarget(
struct kvm_vcpu_init &target)
const
568 if (
ioctl(KVM_ARM_PREFERRED_TARGET, &target) == -1) {
569 panic(
"KVM: Failed to get ARM preferred CPU target (errno: %i)\n",
580 return ::ioctl(
vmFD, request, p1);
585 KvmVMParams::create()
587 static bool created =
false;
589 warn_once(
"Use of multiple KvmVMs is currently untested!\n");
593 return new KvmVM(
this);
Kvm * kvm
Global KVM interface.
#define fatal(...)
This implements a cprintf based fatal() function.
static Kvm * instance
Singleton instance.
bool capUserMemory() const
Support for KvmVM::setUserMemoryRegion()
bool capXCRs() const
Support for getting and setting the x86 XCRs.
bool interleaved() const
Determine if the range is interleaved or not.
int capNumMemSlots() const
Attempt to determine how many memory slots are available.
bool _hasKernelIRQChip
Do we have in-kernel IRQ-chip emulation enabled?
int ContextID
Globally unique thread context ID.
void freeMemSlot(const MemSlot slot)
Free a previously allocated memory slot.
std::vector< BackingStoreEntry > getBackingStore() const
Get the pointers to the backing store for external host access.
const MemSlot allocMemSlot(uint64_t size)
Allocate a memory slot within the VM.
bool capDebugRegs() const
Support for getting and setting the kvm_debugregs structure.
void delayedStartup()
Delayed initialization, executed once before the first CPU starts.
int checkExtension(int extension) const
Check for the presence of an extension to the KVM API.
long contextIdToVCpuId(ContextID ctx) const
Get the VCPUID for a given context.
void cpuStartup()
VM CPU initialization code.
PhysicalMemory & getPhysMem()
Get a pointer to access the physical memory of the system.
bool capSetTSSAddress() const
Support for KvmVM::setTSSAddress()
Structures tracking memory slots.
KvmVM(KvmVMParams *params)
int vcpuMMapSize
Size of the MMAPed vCPU parameter area.
long nextVCPUID
Next unallocated vCPU ID.
int createVCPU(long vcpuID)
Create a new vCPU within a VM.
void coalesceMMIO(Addr start, int size)
Request coalescing MMIO for a memory range.
Base class for KVM based CPU models.
int ioctl(int request, long p1) const
Main VM ioctl interface.
bool capOneReg() const
Support for reading and writing single registers.
The AddrRange class encapsulates an address range, and supports a number of tests to check if two ran...
int kvmFD
KVM VM file descriptor.
void setSystem(System *s)
Initialize system pointer.
int createDevice(uint32_t type, uint32_t flags=0)
Create an in-kernel device model.
void setUserMemoryRegion(uint32_t slot, void *host_addr, Addr guest_addr, uint64_t len, uint32_t flags)
Setup a region of physical memory in the guest.
int apiVersion
KVM API version.
int capCoalescedMMIO() const
Check if coalesced MMIO is supported and which page in the MMAP'ed structure it stores requests in.
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
const Params * params() const
int createVM()
Create a KVM Virtual Machine.
void createIRQChip()
Create an in-kernel interrupt controller.
bool started
Has delayedStartup() already been called?
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
bool capUserNMI() const
Support for BaseKvmCPU::kvmNonMaskableInterrupt().
Addr start() const
Get the start address of the range.
void disableMemSlot(const MemSlot slot)
Disable a memory slot.
void setIRQLine(uint32_t irq, bool high)
Set the status of an IRQ line using KVM_IRQ_LINE.
int vmFD
KVM VM file descriptor.
void setTSSAddress(Addr tss_address)
Setup a shared three-page memory region used by the internals of KVM.
int ioctl(int request, long p1) const
KVM VM ioctl interface.
void setupMemSlot(const MemSlot slot, void *host_addr, Addr guest_addr, uint32_t flags)
Setup a region of physical memory in the guest.
bool capXSave() const
Support for getting and setting the kvm_xsave structure.
bool capExtendedCPUID() const
Support for BaseKvmCPU::setCPUID2 and getSupportedCPUID().
Addr size() const
Get the size of the address range.
long allocVCPUID()
Allocate a new vCPU ID within the VM.
#define EXPECTED_KVM_API_VERSION
std::vector< MemorySlot > memorySlots
void notifyFork()
Notify a child process of a fork.
#define panic(...)
This implements a cprintf based panic() function.
bool capIRQChip() const
Support for creating an in-kernel IRQ chip model.
Abstract superclass for simulation objects.
bool capVCPUEvents() const
Support for getting and setting the kvm_vcpu_events structure.
Generated on Wed Sep 30 2020 14:02:08 for gem5 by doxygen 1.8.17