44 #include <linux/kvm.h>
45 #include <sys/ioctl.h>
47 #include <sys/types.h>
54 #include "debug/Kvm.hh"
55 #include "params/KvmVM.hh"
58 #define EXPECTED_KVM_API_VERSION 12
60 #if EXPECTED_KVM_API_VERSION != KVM_API_VERSION
61 #error Unsupported KVM version
67 : kvmFD(-1), apiVersion(-1), vcpuMMapSize(0)
69 kvmFD = ::open(
"/dev/kvm", O_RDWR);
71 fatal(
"KVM: Failed to open /dev/kvm\n");
75 fatal(
"KVM: Incompatible API version\n");
79 panic(
"KVM: Failed to get virtual CPU MMAP size\n");
117 #ifdef KVM_CAP_USER_NMI
133 #ifdef KVM_CAP_NR_MEMSLOTS
143 #ifdef KVM_CAP_ONE_REG
159 #ifdef KVM_CAP_VCPU_EVENTS
169 #ifdef KVM_CAP_DEBUGREGS
197 #if defined(__i386__) || defined(__x86_64__)
199 Kvm::getSupportedCPUID(
struct kvm_cpuid2 &
cpuid)
const
201 if (
ioctl(KVM_GET_SUPPORTED_CPUID, (
void *)&cpuid) == -1) {
205 panic(
"KVM: Failed to get supported CPUID (errno: %i)\n", errno);
210 const Kvm::CPUIDVector &
211 Kvm::getSupportedCPUID()
const
213 if (supportedCPUIDCache.empty()) {
214 std::unique_ptr<struct kvm_cpuid2>
cpuid;
217 cpuid.reset((
struct kvm_cpuid2 *)
operator new(
218 sizeof(kvm_cpuid2) +
i *
sizeof(kvm_cpuid_entry2)));
222 }
while (!getSupportedCPUID(*cpuid));
223 supportedCPUIDCache.assign(cpuid->entries,
224 cpuid->entries + cpuid->nent);
227 return supportedCPUIDCache;
231 Kvm::getSupportedMSRs(
struct kvm_msr_list &msrs)
const
233 if (
ioctl(KVM_GET_MSR_INDEX_LIST, (
void *)&msrs) == -1) {
237 panic(
"KVM: Failed to get supported CPUID (errno: %i)\n", errno);
242 const Kvm::MSRIndexVector &
243 Kvm::getSupportedMSRs()
const
245 if (supportedMSRCache.empty()) {
246 std::unique_ptr<struct kvm_msr_list> msrs;
249 msrs.reset((
struct kvm_msr_list *)
operator new(
250 sizeof(kvm_msr_list) +
i *
sizeof(uint32_t)));
254 }
while (!getSupportedMSRs(*msrs));
255 supportedMSRCache.assign(msrs->indices, msrs->indices + msrs->nmsrs);
258 return supportedMSRCache;
261 #endif // x86-specific
267 int ret =
ioctl(KVM_CHECK_EXTENSION, extension);
269 panic(
"KVM: ioctl failed when checking for extension\n");
278 return ::ioctl(
kvmFD, request, p1);
286 vmFD =
ioctl(KVM_CREATE_VM);
288 panic(
"Failed to create KVM VM\n");
297 vmFD(kvm->createVM()),
306 for (
int i = 0;
i < params->coalescedMMIO.size(); ++
i)
323 if (close(
vmFD) == -1)
324 warn(
"kvm VM: notifyFork failed to close vmFD\n");
350 DPRINTF(
Kvm,
"Mapping %i memory region(s)\n", memories.size());
351 for (
int slot(0); slot < memories.size(); ++slot) {
352 if (!memories[slot].kvmMap) {
353 DPRINTF(
Kvm,
"Skipping region marked as not usable by KVM\n");
357 const AddrRange &range(memories[slot].range);
358 void *pmem(memories[slot].pmem);
361 DPRINTF(
Kvm,
"Mapping region: 0x%p -> 0x%llx [size: 0x%llx]\n",
365 panic(
"Tried to map an interleaved memory range into "
373 hack(
"KVM: Zero memory handled as IO\n");
382 panic(
"Memory slots must have non-zero size.\n");
395 panic(
"Out of memory slots.\n");
399 slot.
slot = nextSlot;
434 void *host_addr,
Addr guest_addr,
435 uint64_t
len, uint32_t flags)
437 struct kvm_userspace_memory_region m;
439 memset(&m, 0,
sizeof(m));
442 m.guest_phys_addr = (uint64_t)guest_addr;
444 m.userspace_addr = (__u64)host_addr;
446 if (
ioctl(KVM_SET_USER_MEMORY_REGION, (
void *)&
m) == -1) {
447 panic(
"Failed to setup KVM memory region:\n"
448 "\tHost Address: 0x%p\n"
449 "\tGuest Address: 0x%llx\n",
452 m.userspace_addr, m.guest_phys_addr,
453 m.memory_size, m.flags);
466 struct kvm_coalesced_mmio_zone zone;
472 DPRINTF(
Kvm,
"KVM: Registering coalesced MMIO region [0x%x, 0x%x]\n",
473 zone.addr, zone.addr + zone.size - 1);
474 if (
ioctl(KVM_REGISTER_COALESCED_MMIO, (
void *)&zone) == -1)
475 panic(
"KVM: Failed to register coalesced MMIO region (%i)\n",
482 if (
ioctl(KVM_SET_TSS_ADDR, (
unsigned long)tss_address) == -1)
483 panic(
"KVM: Failed to set VM TSS address\n");
490 panic(
"KvmVM::createIRQChip called twice.\n");
492 if (
ioctl(KVM_CREATE_IRQCHIP) != -1) {
495 warn(
"KVM: Failed to create in-kernel IRQ chip (errno: %i)\n",
504 struct kvm_irq_level kvm_level;
507 kvm_level.level = high ? 1 : 0;
509 if (
ioctl(KVM_IRQ_LINE, &kvm_level) == -1)
510 panic(
"KVM: Failed to set IRQ line level (errno: %i)\n",
517 #if defined(KVM_CREATE_DEVICE)
518 struct kvm_create_device dev = {
type, 0, flags };
520 if (
ioctl(KVM_CREATE_DEVICE, &dev) == -1) {
521 panic(
"KVM: Failed to create device (errno: %i)\n",
527 panic(
"Kernel headers don't support KVM_CREATE_DEVICE\n");
534 panic_if(
system !=
nullptr,
"setSystem() can only be called once");
535 panic_if(s ==
nullptr,
"setSystem() called with null System*");
542 assert(
system !=
nullptr);
552 fd =
ioctl(KVM_CREATE_VCPU, vcpuID);
554 panic(
"KVM: Failed to create virtual CPU");
565 #if defined(__aarch64__)
567 KvmVM::kvmArmPreferredTarget(
struct kvm_vcpu_init &target)
const
569 if (
ioctl(KVM_ARM_PREFERRED_TARGET, &target) == -1) {
570 panic(
"KVM: Failed to get ARM preferred CPU target (errno: %i)\n",
581 return ::ioctl(
vmFD, request, p1);
586 KvmVMParams::create()
588 static bool created =
false;
590 warn_once(
"Use of multiple KvmVMs is currently untested!\n");
594 return new KvmVM(
this);
bool capDebugRegs() const
Support for getting and setting the kvm_debugregs structure.
int kvmFD
KVM VM file descriptor.
bool capUserMemory() const
Support for KvmVM::setUserMemoryRegion()
int vcpuMMapSize
Size of the MMAPed vCPU parameter area.
Addr start() const
Get the start address of the range.
bool interleaved() const
Determine if the range is interleaved or not.
void createIRQChip()
Create an in-kernel interrupt controller.
void cpuStartup()
VM CPU initialization code.
int apiVersion
KVM API version.
panic_if(!root,"Invalid expression\n")
long allocVCPUID()
Allocate a new vCPU ID within the VM.
long contextIdToVCpuId(ContextID ctx) const
Get the VCPUID for a given context.
std::vector< MemorySlot > memorySlots
static Kvm * instance
Singleton instance.
virtual BaseCPU * getCpuPtr()=0
long nextVCPUID
Next unallocated vCPU ID.
int createVCPU(long vcpuID)
Create a new vCPU within a VM.
Base class for KVM based CPU models.
std::vector< BackingStoreEntry > getBackingStore() const
Get the pointers to the backing store for external host access.
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.
bool _hasKernelIRQChip
Do we have in-kernel IRQ-chip emulation enabled?
bool capXCRs() const
Support for getting and setting the x86 XCRs.
bool capOneReg() const
Support for reading and writing single registers.
void setIRQLine(uint32_t irq, bool high)
Set the status of an IRQ line using KVM_IRQ_LINE.
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.
void setSystem(System *s)
Initialize system pointer.
The AddrRange class encapsulates an address range, and supports a number of tests to check if two ran...
void freeMemSlot(const MemSlot slot)
Free a previously allocated memory slot.
bool started
Has delayedStartup() already been called?
void delayedStartup()
Delayed initialization, executed once before the first CPU starts.
bool capSetTSSAddress() const
Support for KvmVM::setTSSAddress()
void coalesceMMIO(Addr start, int size)
Request coalescing MMIO for a memory range.
void setTSSAddress(Addr tss_address)
Setup a shared three-page memory region used by the internals of KVM.
ThreadContext * getThreadContext(ContextID tid)
int createVM()
Create a KVM Virtual Machine.
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Structures tracking memory slots.
void setupMemSlot(const MemSlot slot, void *host_addr, Addr guest_addr, uint32_t flags)
Setup a region of physical memory in the guest.
KvmVM(KvmVMParams *params)
int vmFD
KVM VM file descriptor.
int createDevice(uint32_t type, uint32_t flags=0)
Create an in-kernel device model.
bool capUserNMI() const
Support for BaseKvmCPU::kvmNonMaskableInterrupt().
bool capVCPUEvents() const
Support for getting and setting the kvm_vcpu_events structure.
bool capXSave() const
Support for getting and setting the kvm_xsave structure.
int capCoalescedMMIO() const
Check if coalesced MMIO is supported and which page in the MMAP'ed structure it stores requests in...
int ioctl(int request, long p1) const
KVM VM ioctl interface.
PhysicalMemory & getPhysMem()
Get a pointer to access the physical memory of the system.
void notifyFork()
Notify a child process of a fork.
#define EXPECTED_KVM_API_VERSION
Kvm * kvm
Global KVM interface.
bool capIRQChip() const
Support for creating an in-kernel IRQ chip model.
int ioctl(int request, long p1) const
Main VM ioctl interface.
void disableMemSlot(const MemSlot slot)
Disable a memory slot.
const MemSlot allocMemSlot(uint64_t size)
Allocate a memory slot within the VM.
Addr size() const
Get the size of the address range.
Abstract superclass for simulation objects.
int ContextID
Globally unique thread context ID.
bool capExtendedCPUID() const
Support for BaseKvmCPU::setCPUID2 and getSupportedCPUID().