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,
222 cpuid->entries + cpuid->nent);
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");
304 for (
int i = 0;
i < params->coalescedMMIO.size(); ++
i)
321 if (close(
vmFD) == -1)
322 warn(
"kvm VM: notifyFork failed to close vmFD\n");
348 DPRINTF(
Kvm,
"Mapping %i memory region(s)\n", memories.size());
349 for (
int slot(0); slot < memories.size(); ++slot) {
350 if (!memories[slot].kvmMap) {
351 DPRINTF(
Kvm,
"Skipping region marked as not usable by KVM\n");
355 const AddrRange &range(memories[slot].range);
356 void *pmem(memories[slot].pmem);
359 DPRINTF(
Kvm,
"Mapping region: 0x%p -> 0x%llx [size: 0x%llx]\n",
363 panic(
"Tried to map an interleaved memory range into " 371 hack(
"KVM: Zero memory handled as IO\n");
380 panic(
"Memory slots must have non-zero size.\n");
393 panic(
"Out of memory slots.\n");
397 slot.
slot = nextSlot;
432 void *host_addr,
Addr guest_addr,
433 uint64_t
len, uint32_t flags)
435 struct kvm_userspace_memory_region m;
437 memset(&m, 0,
sizeof(m));
440 m.guest_phys_addr = (uint64_t)guest_addr;
442 m.userspace_addr = (__u64)host_addr;
444 if (
ioctl(KVM_SET_USER_MEMORY_REGION, (
void *)&
m) == -1) {
445 panic(
"Failed to setup KVM memory region:\n" 446 "\tHost Address: 0x%p\n" 447 "\tGuest Address: 0x%llx\n",
450 m.userspace_addr, m.guest_phys_addr,
451 m.memory_size, m.flags);
464 struct kvm_coalesced_mmio_zone zone;
470 DPRINTF(
Kvm,
"KVM: Registering coalesced MMIO region [0x%x, 0x%x]\n",
471 zone.addr, zone.addr + zone.size - 1);
472 if (
ioctl(KVM_REGISTER_COALESCED_MMIO, (
void *)&zone) == -1)
473 panic(
"KVM: Failed to register coalesced MMIO region (%i)\n",
480 if (
ioctl(KVM_SET_TSS_ADDR, (
unsigned long)tss_address) == -1)
481 panic(
"KVM: Failed to set VM TSS address\n");
488 panic(
"KvmVM::createIRQChip called twice.\n");
490 if (
ioctl(KVM_CREATE_IRQCHIP) != -1) {
493 warn(
"KVM: Failed to create in-kernel IRQ chip (errno: %i)\n",
502 struct kvm_irq_level kvm_level;
505 kvm_level.level = high ? 1 : 0;
507 if (
ioctl(KVM_IRQ_LINE, &kvm_level) == -1)
508 panic(
"KVM: Failed to set IRQ line level (errno: %i)\n",
515 #if defined(KVM_CREATE_DEVICE) 516 struct kvm_create_device dev = {
type, 0, flags };
518 if (
ioctl(KVM_CREATE_DEVICE, &dev) == -1) {
519 panic(
"KVM: Failed to create device (errno: %i)\n",
525 panic(
"Kernel headers don't support KVM_CREATE_DEVICE\n");
532 panic_if(
system !=
nullptr,
"setSystem() can only be called once");
533 panic_if(s ==
nullptr,
"setSystem() called with null System*");
540 assert(
system !=
nullptr);
550 fd =
ioctl(KVM_CREATE_VCPU, vcpuID);
552 panic(
"KVM: Failed to create virtual CPU");
563 #if defined(__aarch64__) 565 KvmVM::kvmArmPreferredTarget(
struct kvm_vcpu_init &target)
const 567 if (
ioctl(KVM_ARM_PREFERRED_TARGET, &target) == -1) {
568 panic(
"KVM: Failed to get ARM preferred CPU target (errno: %i)\n",
579 return ::ioctl(
vmFD, request, p1);
584 KvmVMParams::create()
586 static bool created =
false;
588 warn_once(
"Use of multiple KvmVMs is currently untested!\n");
592 return new KvmVM(
this);
#define panic(...)
This implements a cprintf based panic() function.
int ioctl(int request, long p1) const
KVM VM ioctl interface.
int kvmFD
KVM VM file descriptor.
bool capExtendedCPUID() const
Support for BaseKvmCPU::setCPUID2 and getSupportedCPUID().
int vcpuMMapSize
Size of the MMAPed vCPU parameter area.
#define fatal(...)
This implements a cprintf based fatal() function.
void createIRQChip()
Create an in-kernel interrupt controller.
void cpuStartup()
VM CPU initialization code.
int apiVersion
KVM API version.
long allocVCPUID()
Allocate a new vCPU ID within the VM.
std::vector< MemorySlot > memorySlots
int capNumMemSlots() const
Attempt to determine how many memory slots are available.
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.
bool capVCPUEvents() const
Support for getting and setting the kvm_vcpu_events structure.
int ioctl(int request, long p1) const
Main VM ioctl interface.
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 capOneReg() const
Support for reading and writing single registers.
bool _hasKernelIRQChip
Do we have in-kernel IRQ-chip emulation enabled?
void setIRQLine(uint32_t irq, bool high)
Set the status of an IRQ line using KVM_IRQ_LINE.
ThreadContext * getThreadContext(ContextID tid) const
void setSystem(System *s)
Initialize system pointer.
bool capUserNMI() const
Support for BaseKvmCPU::kvmNonMaskableInterrupt().
The AddrRange class encapsulates an address range, and supports a number of tests to check if two ran...
std::vector< BackingStoreEntry > getBackingStore() const
Get the pointers to the backing store for external host access.
void freeMemSlot(const MemSlot slot)
Free a previously allocated memory slot.
bool started
Has delayedStartup() already been called?
long contextIdToVCpuId(ContextID ctx) const
Get the VCPUID for a given context.
int checkExtension(int extension) const
Check for the presence of an extension to the KVM API.
void delayedStartup()
Delayed initialization, executed once before the first CPU starts.
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.
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 capSetTSSAddress() const
Support for KvmVM::setTSSAddress()
bool interleaved() const
Determine if the range is interleaved or not.
bool capUserMemory() const
Support for KvmVM::setUserMemoryRegion()
PhysicalMemory & getPhysMem()
Get a pointer to access the physical memory of the system.
bool capXCRs() const
Support for getting and setting the x86 XCRs.
void notifyFork()
Notify a child process of a fork.
#define EXPECTED_KVM_API_VERSION
bool capXSave() const
Support for getting and setting the kvm_xsave structure.
Addr start() const
Get the start address of the range.
int capCoalescedMMIO() const
Check if coalesced MMIO is supported and which page in the MMAP'ed structure it stores requests in...
Addr size() const
Get the size of the address range.
bool capIRQChip() const
Support for creating an in-kernel IRQ chip model.
Kvm * kvm
Global KVM interface.
bool capDebugRegs() const
Support for getting and setting the kvm_debugregs structure.
void disableMemSlot(const MemSlot slot)
Disable a memory slot.
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
const MemSlot allocMemSlot(uint64_t size)
Allocate a memory slot within the VM.
Abstract superclass for simulation objects.
int ContextID
Globally unique thread context ID.