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 static bool created =
false;
69 warn_once(
"Use of multiple KvmVMs is currently untested!");
73 kvmFD = ::open(
"/dev/kvm", O_RDWR);
75 fatal(
"KVM: Failed to open /dev/kvm\n");
79 fatal(
"KVM: Incompatible API version\n");
83 panic(
"KVM: Failed to get virtual CPU MMAP size\n");
121 #ifdef KVM_CAP_USER_NMI
137 #ifdef KVM_CAP_NR_MEMSLOTS
147 #ifdef KVM_CAP_ONE_REG
163 #ifdef KVM_CAP_VCPU_EVENTS
173 #ifdef KVM_CAP_DEBUGREGS
201 #if defined(__i386__) || defined(__x86_64__)
203 Kvm::getSupportedCPUID(
struct kvm_cpuid2 &
cpuid)
const
205 if (
ioctl(KVM_GET_SUPPORTED_CPUID, (
void *)&
cpuid) == -1) {
209 panic(
"KVM: Failed to get supported CPUID (errno: %i)\n", errno);
214 const Kvm::CPUIDVector &
215 Kvm::getSupportedCPUID()
const
217 if (supportedCPUIDCache.empty()) {
218 std::unique_ptr<struct kvm_cpuid2>
cpuid;
221 cpuid.reset((
struct kvm_cpuid2 *)
operator new(
222 sizeof(kvm_cpuid2) +
i *
sizeof(kvm_cpuid_entry2)));
226 }
while (!getSupportedCPUID(*
cpuid));
227 supportedCPUIDCache.assign(
cpuid->entries,
231 return supportedCPUIDCache;
235 Kvm::getSupportedMSRs(
struct kvm_msr_list &msrs)
const
237 if (
ioctl(KVM_GET_MSR_INDEX_LIST, (
void *)&msrs) == -1) {
241 panic(
"KVM: Failed to get supported CPUID (errno: %i)\n", errno);
246 const Kvm::MSRIndexVector &
247 Kvm::getSupportedMSRs()
const
249 if (supportedMSRCache.empty()) {
250 std::unique_ptr<struct kvm_msr_list> msrs;
253 msrs.reset((
struct kvm_msr_list *)
operator new(
254 sizeof(kvm_msr_list) +
i *
sizeof(uint32_t)));
258 }
while (!getSupportedMSRs(*msrs));
259 supportedMSRCache.assign(msrs->indices, msrs->indices + msrs->nmsrs);
262 return supportedMSRCache;
265 #endif // x86-specific
271 int ret =
ioctl(KVM_CHECK_EXTENSION, extension);
273 panic(
"KVM: ioctl failed when checking for extension\n");
282 return ::ioctl(
kvmFD, request, p1);
290 vmFD =
ioctl(KVM_CREATE_VM);
292 panic(
"Failed to create KVM VM\n");
301 vmFD(kvm->createVM()),
303 _hasKernelIRQChip(false),
311 for (
int i = 0;
i <
params.coalescedMMIO.size(); ++
i)
328 if (close(
vmFD) == -1)
329 warn(
"kvm VM: notifyFork failed to close vmFD\n");
355 DPRINTF(
Kvm,
"Mapping %i memory region(s)\n", memories.size());
356 for (
int slot(0); slot < memories.size(); ++slot) {
357 if (!memories[slot].kvmMap) {
358 DPRINTF(
Kvm,
"Skipping region marked as not usable by KVM\n");
362 const AddrRange &range(memories[slot].range);
363 void *pmem(memories[slot].pmem);
366 DPRINTF(
Kvm,
"Mapping region: 0x%p -> 0x%llx [size: 0x%llx]\n",
370 panic(
"Tried to map an interleaved memory range into "
378 hack(
"KVM: Zero memory handled as IO\n");
387 panic(
"Memory slots must have non-zero size.\n");
400 panic(
"Out of memory slots.\n");
404 slot.
slot = nextSlot;
439 void *host_addr,
Addr guest_addr,
440 uint64_t
len, uint32_t flags)
442 struct kvm_userspace_memory_region
m;
444 memset(&
m, 0,
sizeof(
m));
447 m.guest_phys_addr = (uint64_t)guest_addr;
449 m.userspace_addr = (__u64)host_addr;
451 if (
ioctl(KVM_SET_USER_MEMORY_REGION, (
void *)&
m) == -1) {
452 panic(
"Failed to setup KVM memory region:\n"
453 "\tHost Address: 0x%p\n"
454 "\tGuest Address: 0x%llx\n",
457 m.userspace_addr,
m.guest_phys_addr,
458 m.memory_size,
m.flags);
471 struct kvm_coalesced_mmio_zone zone;
477 DPRINTF(
Kvm,
"KVM: Registering coalesced MMIO region [0x%x, 0x%x]\n",
478 zone.addr, zone.addr + zone.size - 1);
479 if (
ioctl(KVM_REGISTER_COALESCED_MMIO, (
void *)&zone) == -1)
480 panic(
"KVM: Failed to register coalesced MMIO region (%i)\n",
487 if (
ioctl(KVM_SET_TSS_ADDR, (
unsigned long)tss_address) == -1)
488 panic(
"KVM: Failed to set VM TSS address\n");
495 panic(
"KvmVM::createIRQChip called twice.\n");
497 if (
ioctl(KVM_CREATE_IRQCHIP) != -1) {
500 warn(
"KVM: Failed to create in-kernel IRQ chip (errno: %i)\n",
509 struct kvm_irq_level kvm_level;
512 kvm_level.level = high ? 1 : 0;
514 if (
ioctl(KVM_IRQ_LINE, &kvm_level) == -1)
515 panic(
"KVM: Failed to set IRQ line level (errno: %i)\n",
522 #if defined(KVM_CREATE_DEVICE)
523 struct kvm_create_device dev = {
type, 0, flags };
525 if (
ioctl(KVM_CREATE_DEVICE, &dev) == -1) {
526 panic(
"KVM: Failed to create device (errno: %i)\n",
532 panic(
"Kernel headers don't support KVM_CREATE_DEVICE\n");
539 panic_if(
system !=
nullptr,
"setSystem() can only be called once");
540 panic_if(
s ==
nullptr,
"setSystem() called with null System*");
547 assert(
system !=
nullptr);
557 fd =
ioctl(KVM_CREATE_VCPU, vcpuID);
559 panic(
"KVM: Failed to create virtual CPU");
570 #if defined(__aarch64__)
572 KvmVM::kvmArmPreferredTarget(
struct kvm_vcpu_init &target)
const
574 if (
ioctl(KVM_ARM_PREFERRED_TARGET, &target) == -1) {
575 panic(
"KVM: Failed to get ARM preferred CPU target (errno: %i)\n",
586 return ::ioctl(
vmFD, request, p1);
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.
KvmVM(const KvmVMParams ¶ms)
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.
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.
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.
const Params & params() const
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 Tue Jun 22 2021 15:28:26 for gem5 by doxygen 1.8.17