52#include "debug/Kvm.hh"
54#include "params/KvmVM.hh"
63constexpr int ExpectedKvmApiVersion = 12;
64static_assert(KVM_API_VERSION == ExpectedKvmApiVersion,
65 "Unsupported KVM version");
72 : kvmFD(-1), apiVersion(-1), vcpuMMapSize(0)
74 static bool created =
false;
76 warn_once(
"Use of multiple KvmVMs is currently untested!");
80 kvmFD = ::open(
"/dev/kvm", O_RDWR);
82 fatal(
"KVM: Failed to open /dev/kvm\n");
86 fatal(
"KVM: Incompatible API version\n");
90 panic(
"KVM: Failed to get virtual CPU MMAP size\n");
128#ifdef KVM_CAP_USER_NMI
144#ifdef KVM_CAP_NR_MEMSLOTS
154#ifdef KVM_CAP_ONE_REG
170#ifdef KVM_CAP_VCPU_EVENTS
180#ifdef KVM_CAP_DEBUGREGS
210#if defined(KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)
217#if defined(__i386__) || defined(__x86_64__)
219Kvm::getSupportedCPUID(
struct kvm_cpuid2 &
cpuid)
const
221 if (
ioctl(KVM_GET_SUPPORTED_CPUID, (
void *)&
cpuid) == -1) {
225 panic(
"KVM: Failed to get supported CPUID (errno: %i)\n", errno);
230const Kvm::CPUIDVector &
231Kvm::getSupportedCPUID()
const
233 if (supportedCPUIDCache.empty()) {
234 std::unique_ptr<
struct kvm_cpuid2, void(*)(
void *
p)>
235 cpuid(
nullptr, [](
void *
p) {
operator delete(
p); });
238 cpuid.reset((
struct kvm_cpuid2 *)
operator new(
239 sizeof(kvm_cpuid2) +
i *
sizeof(kvm_cpuid_entry2)));
243 }
while (!getSupportedCPUID(*
cpuid));
244 supportedCPUIDCache.assign(
cpuid->entries,
248 return supportedCPUIDCache;
252Kvm::getSupportedMSRs(
struct kvm_msr_list &msrs)
const
254 if (
ioctl(KVM_GET_MSR_INDEX_LIST, (
void *)&msrs) == -1) {
258 panic(
"KVM: Failed to get supported CPUID (errno: %i)\n", errno);
263const Kvm::MSRIndexVector &
264Kvm::getSupportedMSRs()
const
266 if (supportedMSRCache.empty()) {
267 std::unique_ptr<
struct kvm_msr_list, void(*)(
void *
p)>
268 msrs(
nullptr, [](
void *
p) {
operator delete(
p); });
271 msrs.reset((
struct kvm_msr_list *)
operator new(
272 sizeof(kvm_msr_list) +
i *
sizeof(uint32_t)));
276 }
while (!getSupportedMSRs(*msrs));
277 supportedMSRCache.assign(msrs->indices, msrs->indices + msrs->nmsrs);
280 return supportedMSRCache;
289 int ret =
ioctl(KVM_CHECK_EXTENSION, extension);
291 panic(
"KVM: ioctl failed when checking for extension\n");
300 return ::ioctl(
kvmFD, request, p1);
308 vmFD =
ioctl(KVM_CREATE_VM);
310 panic(
"Failed to create KVM VM\n");
319 vmFD(kvm->createVM()),
321 _hasKernelIRQChip(false),
330 for (
int i = 0;
i <
params.coalescedMMIO.size(); ++
i)
347 if (close(
vmFD) == -1)
348 warn(
"kvm VM: notifyFork failed to close vmFD\n");
373 DPRINTF(
Kvm,
"Mapping %i memory region(s)\n", memories.size());
374 for (
int slot(0); slot < memories.size(); ++slot) {
375 if (!memories[slot].kvmMap) {
376 DPRINTF(
Kvm,
"Skipping region marked as not usable by KVM\n");
380 const AddrRange &range(memories[slot].range);
381 void *pmem(memories[slot].pmem);
384 DPRINTF(
Kvm,
"Mapping region: 0x%p -> 0x%llx [size: 0x%llx]\n",
385 pmem, range.start(), range.size());
387 if (range.interleaved()) {
388 panic(
"Tried to map an interleaved memory range into "
395 DPRINTF(
Kvm,
"Zero-region not mapped: [0x%llx]\n", range.start());
396 hack(
"KVM: Zero memory handled as IO\n");
405 panic(
"Memory slots must have non-zero size.\n");
418 panic(
"Out of memory slots.\n");
422 slot.
slot = nextSlot;
457 void *host_addr,
Addr guest_addr,
460 struct kvm_userspace_memory_region
m;
462 memset(&
m, 0,
sizeof(
m));
465 m.guest_phys_addr = (uint64_t)guest_addr;
467 m.userspace_addr = (__u64)host_addr;
469 if (
ioctl(KVM_SET_USER_MEMORY_REGION, (
void *)&
m) == -1) {
470 panic(
"Failed to setup KVM memory region:\n"
471 "\tHost Address: 0x%p\n"
472 "\tGuest Address: 0x%llx\n",
475 m.userspace_addr,
m.guest_phys_addr,
476 m.memory_size,
m.flags);
489 struct kvm_coalesced_mmio_zone zone;
495 DPRINTF(
Kvm,
"KVM: Registering coalesced MMIO region [0x%x, 0x%x]\n",
496 zone.addr, zone.addr + zone.size - 1);
497 if (
ioctl(KVM_REGISTER_COALESCED_MMIO, (
void *)&zone) == -1)
498 panic(
"KVM: Failed to register coalesced MMIO region (%i)\n",
505 if (
ioctl(KVM_SET_TSS_ADDR, (
unsigned long)tss_address) == -1)
506 panic(
"KVM: Failed to set VM TSS address\n");
513 panic(
"KvmVM::createIRQChip called twice.\n");
515 if (
ioctl(KVM_CREATE_IRQCHIP) != -1) {
518 warn(
"KVM: Failed to create in-kernel IRQ chip (errno: %i)\n",
527 struct kvm_irq_level kvm_level;
530 kvm_level.level = high ? 1 : 0;
532 if (
ioctl(KVM_IRQ_LINE, &kvm_level) == -1)
533 panic(
"KVM: Failed to set IRQ line level (errno: %i)\n",
540#if defined(KVM_CREATE_DEVICE)
541 struct kvm_create_device dev = {
type, 0,
flags };
543 if (
ioctl(KVM_CREATE_DEVICE, &dev) == -1) {
544 panic(
"KVM: Failed to create device (errno: %i)\n",
550 panic(
"Kernel headers don't support KVM_CREATE_DEVICE\n");
558 if (!
dynamic_cast<BaseKvmCPU *
>(tc->getCpuPtr()))
577 fd =
ioctl(KVM_CREATE_VCPU, vcpuID);
579 panic(
"KVM: Failed to create virtual CPU");
590#if defined(__aarch64__)
592KvmVM::kvmArmPreferredTarget(
struct kvm_vcpu_init &target)
const
594 if (
ioctl(KVM_ARM_PREFERRED_TARGET, &target) == -1) {
595 panic(
"KVM: Failed to get ARM preferred CPU target (errno: %i)\n",
606 return ::ioctl(
vmFD, request, p1);
The AddrRange class encapsulates an address range, and supports a number of tests to check if two ran...
Base class for KVM based CPU models.
Structures tracking memory slots.
long contextIdToVCpuId(ContextID ctx) const
Get the VCPUID for a given context.
const MemSlot allocMemSlot(uint64_t size)
Allocate a memory slot within the VM.
long nextVCPUID
Next unallocated vCPU ID.
void notifyFork()
Notify a child process of a fork.
bool validEnvironment() const
Verify gem5 configuration will support KVM emulation.
int createVCPU(long vcpuID)
Create a new vCPU within a VM.
KvmVM(const KvmVMParams ¶ms)
bool started
Has delayedStartup() already been called?
std::vector< MemorySlot > memorySlots
Kvm * kvm
Global KVM interface.
int vmFD
KVM VM file descriptor.
void freeMemSlot(const MemSlot slot)
Free a previously allocated memory slot.
long allocVCPUID()
Allocate a new vCPU ID within the VM.
void cpuStartup()
VM CPU initialization code.
void setTSSAddress(Addr tss_address)
Setup a shared three-page memory region used by the internals of KVM.
void disableMemSlot(const MemSlot slot)
Disable a memory slot.
void setupMemSlot(const MemSlot slot, void *host_addr, Addr guest_addr, uint32_t flags)
Setup a region of physical memory in the guest.
bool _hasKernelIRQChip
Do we have in-kernel IRQ-chip emulation enabled?
void delayedStartup()
Delayed initialization, executed once before the first CPU starts.
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.
void coalesceMMIO(Addr start, int size)
Request coalescing MMIO for a memory range.
int apiVersion
KVM API version.
int checkExtension(int extension) const
Check for the presence of an extension to the KVM API.
int capNumMemSlots() const
Attempt to determine how many memory slots are available.
bool capIRQLineLayout2() const
Support for ARM IRQ line layout 2.
bool capXCRs() const
Support for getting and setting the x86 XCRs.
bool capIRQChip() const
Support for creating an in-kernel IRQ chip model.
bool capExtendedCPUID() const
Support for BaseKvmCPU::setCPUID2 and getSupportedCPUID().
bool capSetTSSAddress() const
Support for KvmVM::setTSSAddress()
int createVM()
Create a KVM Virtual Machine.
bool capUserNMI() const
Support for BaseKvmCPU::kvmNonMaskableInterrupt().
bool capDebugRegs() const
Support for getting and setting the kvm_debugregs structure.
int vcpuMMapSize
Size of the MMAPed vCPU parameter area.
int capCoalescedMMIO() const
Check if coalesced MMIO is supported and which page in the MMAP'ed structure it stores requests in.
bool capXSave() const
Support for getting and setting the kvm_xsave structure.
bool capUserMemory() const
Support for KvmVM::setUserMemoryRegion()
bool capVCPUEvents() const
Support for getting and setting the kvm_vcpu_events structure.
bool capOneReg() const
Support for reading and writing single registers.
static Kvm * instance
Singleton instance.
int kvmFD
KVM VM file descriptor.
Abstract superclass for simulation objects.
void setKvmVM(KvmVM *const vm)
Set the pointer to the Kernel Virtual Machine (KVM) SimObject.
memory::PhysicalMemory & getPhysMem()
Get a pointer to access the physical memory of the system.
std::vector< BackingStoreEntry > getBackingStore() const
Get the pointers to the backing store for external host access.
void setIRQLine(uint32_t irq, bool high)
Set the status of an IRQ line using KVM_IRQ_LINE.
void createIRQChip()
Create an in-kernel interrupt controller.
int ioctl(int request, long p1) const
Main VM ioctl interface.
int ioctl(int request, long p1) const
KVM VM ioctl interface.
Addr start() const
Get the start address of the range.
Addr size() const
Get the size of the address range.
#define panic(...)
This implements a cprintf based panic() function.
#define fatal(...)
This implements a cprintf based fatal() function.
const Params & params() const
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
int ContextID
Globally unique thread context ID.