gem5 v24.0.0.0
Loading...
Searching...
No Matches
vm.cc
Go to the documentation of this file.
1/*
2 * Copyright 2014 Google, Inc.
3 * Copyright (c) 2012, 2015 ARM Limited
4 * All rights reserved
5 *
6 * The license below extends only to copyright in the software and shall
7 * not be construed as granting a license to any other intellectual
8 * property including but not limited to intellectual property relating
9 * to a hardware implementation of the functionality of the software
10 * licensed hereunder. You may use the software subject to the license
11 * terms below provided that you ensure that this notice is replicated
12 * unmodified and in its entirety in all distributions of the software,
13 * modified or unmodified, in source code or in binary form.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions are
17 * met: redistributions of source code must retain the above copyright
18 * notice, this list of conditions and the following disclaimer;
19 * redistributions in binary form must reproduce the above copyright
20 * notice, this list of conditions and the following disclaimer in the
21 * documentation and/or other materials provided with the distribution;
22 * neither the name of the copyright holders nor the names of its
23 * contributors may be used to endorse or promote products derived from
24 * this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
27 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
28 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
29 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
30 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
31 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
32 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
36 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 */
38
39#include "cpu/kvm/vm.hh"
40
41#include <fcntl.h>
42#include <linux/kvm.h>
43#include <sys/ioctl.h>
44#include <sys/stat.h>
45#include <sys/types.h>
46#include <unistd.h>
47
48#include <cerrno>
49#include <memory>
50
51#include "cpu/kvm/base.hh"
52#include "debug/Kvm.hh"
53#include "mem/physical.hh"
54#include "params/KvmVM.hh"
55#include "sim/system.hh"
56
57namespace gem5
58{
59
60namespace
61{
62
63constexpr int ExpectedKvmApiVersion = 12;
64static_assert(KVM_API_VERSION == ExpectedKvmApiVersion,
65 "Unsupported KVM version");
66
67} // anonymous namespace
68
69Kvm *Kvm::instance = NULL;
70
72 : kvmFD(-1), apiVersion(-1), vcpuMMapSize(0)
73{
74 static bool created = false;
75 if (created)
76 warn_once("Use of multiple KvmVMs is currently untested!");
77
78 created = true;
79
80 kvmFD = ::open("/dev/kvm", O_RDWR);
81 if (kvmFD == -1)
82 fatal("KVM: Failed to open /dev/kvm\n");
83
84 apiVersion = ioctl(KVM_GET_API_VERSION);
85 if (apiVersion != ExpectedKvmApiVersion)
86 fatal("KVM: Incompatible API version\n");
87
88 vcpuMMapSize = ioctl(KVM_GET_VCPU_MMAP_SIZE);
89 if (vcpuMMapSize == -1)
90 panic("KVM: Failed to get virtual CPU MMAP size\n");
91}
92
94{
95 close(kvmFD);
96}
97
98Kvm *
100{
101 if (!instance)
102 instance = new Kvm();
103
104 return instance;
105}
106
107bool
109{
110 return checkExtension(KVM_CAP_USER_MEMORY) != 0;
111}
112
113bool
115{
116 return checkExtension(KVM_CAP_SET_TSS_ADDR) != 0;
117}
118
119bool
121{
122 return checkExtension(KVM_CAP_EXT_CPUID) != 0;
123}
124
125bool
127{
128#ifdef KVM_CAP_USER_NMI
129 return checkExtension(KVM_CAP_USER_NMI) != 0;
130#else
131 return false;
132#endif
133}
134
135int
137{
138 return checkExtension(KVM_CAP_COALESCED_MMIO);
139}
140
141int
143{
144#ifdef KVM_CAP_NR_MEMSLOTS
145 return checkExtension(KVM_CAP_NR_MEMSLOTS);
146#else
147 return 0;
148#endif
149}
150
151bool
153{
154#ifdef KVM_CAP_ONE_REG
155 return checkExtension(KVM_CAP_ONE_REG) != 0;
156#else
157 return false;
158#endif
159}
160
161bool
163{
164 return checkExtension(KVM_CAP_IRQCHIP) != 0;
165}
166
167bool
169{
170#ifdef KVM_CAP_VCPU_EVENTS
171 return checkExtension(KVM_CAP_VCPU_EVENTS) != 0;
172#else
173 return false;
174#endif
175}
176
177bool
179{
180#ifdef KVM_CAP_DEBUGREGS
181 return checkExtension(KVM_CAP_DEBUGREGS) != 0;
182#else
183 return false;
184#endif
185}
186
187bool
189{
190#ifdef KVM_CAP_XCRS
191 return checkExtension(KVM_CAP_XCRS) != 0;
192#else
193 return false;
194#endif
195}
196
197bool
199{
200#ifdef KVM_CAP_XSAVE
201 return checkExtension(KVM_CAP_XSAVE) != 0;
202#else
203 return false;
204#endif
205}
206
207bool
209{
210#if defined(KVM_CAP_ARM_IRQ_LINE_LAYOUT_2)
211 return checkExtension(KVM_CAP_ARM_IRQ_LINE_LAYOUT_2) != 0;
212#else
213 return false;
214#endif
215}
216
217#if defined(__i386__) || defined(__x86_64__)
218bool
219Kvm::getSupportedCPUID(struct kvm_cpuid2 &cpuid) const
220{
221 if (ioctl(KVM_GET_SUPPORTED_CPUID, (void *)&cpuid) == -1) {
222 if (errno == E2BIG)
223 return false;
224 else
225 panic("KVM: Failed to get supported CPUID (errno: %i)\n", errno);
226 } else
227 return true;
228}
229
230const Kvm::CPUIDVector &
231Kvm::getSupportedCPUID() const
232{
233 if (supportedCPUIDCache.empty()) {
234 std::unique_ptr<struct kvm_cpuid2, void(*)(void *p)>
235 cpuid(nullptr, [](void *p) { operator delete(p); });
236 int i(1);
237 do {
238 cpuid.reset((struct kvm_cpuid2 *)operator new(
239 sizeof(kvm_cpuid2) + i * sizeof(kvm_cpuid_entry2)));
240
241 cpuid->nent = i;
242 ++i;
243 } while (!getSupportedCPUID(*cpuid));
244 supportedCPUIDCache.assign(cpuid->entries,
245 cpuid->entries + cpuid->nent);
246 }
247
248 return supportedCPUIDCache;
249}
250
251bool
252Kvm::getSupportedMSRs(struct kvm_msr_list &msrs) const
253{
254 if (ioctl(KVM_GET_MSR_INDEX_LIST, (void *)&msrs) == -1) {
255 if (errno == E2BIG)
256 return false;
257 else
258 panic("KVM: Failed to get supported CPUID (errno: %i)\n", errno);
259 } else
260 return true;
261}
262
263const Kvm::MSRIndexVector &
264Kvm::getSupportedMSRs() const
265{
266 if (supportedMSRCache.empty()) {
267 std::unique_ptr<struct kvm_msr_list, void(*)(void *p)>
268 msrs(nullptr, [](void *p) { operator delete(p); });
269 int i(0);
270 do {
271 msrs.reset((struct kvm_msr_list *)operator new(
272 sizeof(kvm_msr_list) + i * sizeof(uint32_t)));
273
274 msrs->nmsrs = i;
275 ++i;
276 } while (!getSupportedMSRs(*msrs));
277 supportedMSRCache.assign(msrs->indices, msrs->indices + msrs->nmsrs);
278 }
279
280 return supportedMSRCache;
281}
282
283#endif // x86-specific
284
285
286int
287Kvm::checkExtension(int extension) const
288{
289 int ret = ioctl(KVM_CHECK_EXTENSION, extension);
290 if (ret == -1)
291 panic("KVM: ioctl failed when checking for extension\n");
292 return ret;
293}
294
295int
296Kvm::ioctl(int request, long p1) const
297{
298 assert(kvmFD != -1);
299
300 return ::ioctl(kvmFD, request, p1);
301}
302
303int
305{
306 int vmFD;
307
308 vmFD = ioctl(KVM_CREATE_VM);
309 if (vmFD == -1)
310 panic("Failed to create KVM VM\n");
311
312 return vmFD;
313}
314
315
316KvmVM::KvmVM(const KvmVMParams &params)
317 : SimObject(params),
318 kvm(new Kvm()), system(params.system),
319 vmFD(kvm->createVM()),
320 started(false),
321 _hasKernelIRQChip(false),
322 nextVCPUID(0)
323{
324 system->setKvmVM(this);
326 /* If we couldn't determine how memory slots there are, guess 32. */
327 if (!maxMemorySlot)
328 maxMemorySlot = 32;
329 /* Setup the coalesced MMIO regions */
330 for (int i = 0; i < params.coalescedMMIO.size(); ++i)
331 coalesceMMIO(params.coalescedMMIO[i]);
332}
333
335{
336 if (vmFD != -1)
337 close(vmFD);
338
339 if (kvm)
340 delete kvm;
341}
342
343void
345{
346 if (vmFD != -1) {
347 if (close(vmFD) == -1)
348 warn("kvm VM: notifyFork failed to close vmFD\n");
349
350 vmFD = -1;
351
352 delete kvm;
353 kvm = NULL;
354 }
355}
356
357void
359{
360 if (started)
361 return;
362 started = true;
363
365}
366
367void
369{
372
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");
377 continue;
378 }
379
380 const AddrRange &range(memories[slot].range);
381 void *pmem(memories[slot].pmem);
382
383 if (pmem) {
384 DPRINTF(Kvm, "Mapping region: 0x%p -> 0x%llx [size: 0x%llx]\n",
385 pmem, range.start(), range.size());
386
387 if (range.interleaved()) {
388 panic("Tried to map an interleaved memory range into "
389 "a KVM VM.\n");
390 }
391
392 const MemSlot slot = allocMemSlot(range.size());
393 setupMemSlot(slot, pmem, range.start(), 0/* flags */);
394 } else {
395 DPRINTF(Kvm, "Zero-region not mapped: [0x%llx]\n", range.start());
396 hack("KVM: Zero memory handled as IO\n");
397 }
398 }
399}
400
401const KvmVM::MemSlot
403{
404 if (!size)
405 panic("Memory slots must have non-zero size.\n");
406
408 for (pos = memorySlots.begin(); pos != memorySlots.end(); pos++) {
409 if (!pos->size) {
410 pos->size = size;
411 pos->active = false;
412 return pos->slot;
413 }
414 }
415
416 uint32_t nextSlot = memorySlots.size();
417 if (nextSlot > maxMemorySlot)
418 panic("Out of memory slots.\n");
419
420 MemorySlot slot;
421 slot.size = size;
422 slot.slot = nextSlot;
423 slot.active = false;
424
425 memorySlots.push_back(slot);
426 return MemSlot(slot.slot);
427}
428
429void
430KvmVM::setupMemSlot(const KvmVM::MemSlot num, void *host_addr, Addr guest,
431 uint32_t flags)
432{
433 MemorySlot &slot = memorySlots.at(num.num);
434 slot.active = true;
435 setUserMemoryRegion(num.num, host_addr, guest, slot.size, flags);
436}
437
438void
440{
441 MemorySlot &slot = memorySlots.at(num.num);
442 if (slot.active)
443 setUserMemoryRegion(num.num, NULL, 0, 0, 0);
444 slot.active = false;
445}
446
447void
449{
450 disableMemSlot(num.num);
451 MemorySlot &slot = memorySlots.at(num.num);
452 slot.size = 0;
453}
454
455void
457 void *host_addr, Addr guest_addr,
458 uint64_t len, uint32_t flags)
459{
460 struct kvm_userspace_memory_region m;
461
462 memset(&m, 0, sizeof(m));
463 m.slot = slot;
464 m.flags = flags;
465 m.guest_phys_addr = (uint64_t)guest_addr;
466 m.memory_size = len;
467 m.userspace_addr = (__u64)host_addr;
468
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",
473 "\tSize: %ll\n",
474 "\tFlags: 0x%x\n",
475 m.userspace_addr, m.guest_phys_addr,
476 m.memory_size, m.flags);
477 }
478}
479
480void
482{
483 coalesceMMIO(range.start(), range.size());
484}
485
486void
487KvmVM::coalesceMMIO(Addr start, int size)
488{
489 struct kvm_coalesced_mmio_zone zone;
490
491 zone.addr = start;
492 zone.size = size;
493 zone.pad = 0;
494
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",
499 errno);
500}
501
502void
504{
505 if (ioctl(KVM_SET_TSS_ADDR, (unsigned long)tss_address) == -1)
506 panic("KVM: Failed to set VM TSS address\n");
507}
508
509void
511{
513 panic("KvmVM::createIRQChip called twice.\n");
514
515 if (ioctl(KVM_CREATE_IRQCHIP) != -1) {
516 _hasKernelIRQChip = true;
517 } else {
518 warn("KVM: Failed to create in-kernel IRQ chip (errno: %i)\n",
519 errno);
520 _hasKernelIRQChip = false;
521 }
522}
523
524void
525KvmVM::setIRQLine(uint32_t irq, bool high)
526{
527 struct kvm_irq_level kvm_level;
528
529 kvm_level.irq = irq;
530 kvm_level.level = high ? 1 : 0;
531
532 if (ioctl(KVM_IRQ_LINE, &kvm_level) == -1)
533 panic("KVM: Failed to set IRQ line level (errno: %i)\n",
534 errno);
535}
536
537int
538KvmVM::createDevice(uint32_t type, uint32_t flags)
539{
540#if defined(KVM_CREATE_DEVICE)
541 struct kvm_create_device dev = { type, 0, flags };
542
543 if (ioctl(KVM_CREATE_DEVICE, &dev) == -1) {
544 panic("KVM: Failed to create device (errno: %i)\n",
545 errno);
546 }
547
548 return dev.fd;
549#else
550 panic("Kernel headers don't support KVM_CREATE_DEVICE\n");
551#endif
552}
553
554bool
556{
557 for (auto *tc: system->threads) {
558 if (!dynamic_cast<BaseKvmCPU *>(tc->getCpuPtr()))
559 return false;
560 }
561
562 return true;
563}
564
565long
567{
568 return dynamic_cast<BaseKvmCPU*>
569 (system->threads[ctx]->getCpuPtr())->getVCpuID();
570}
571
572int
574{
575 int fd;
576
577 fd = ioctl(KVM_CREATE_VCPU, vcpuID);
578 if (fd == -1)
579 panic("KVM: Failed to create virtual CPU");
580
581 return fd;
582}
583
584long
586{
587 return nextVCPUID++;
588}
589
590#if defined(__aarch64__)
591void
592KvmVM::kvmArmPreferredTarget(struct kvm_vcpu_init &target) const
593{
594 if (ioctl(KVM_ARM_PREFERRED_TARGET, &target) == -1) {
595 panic("KVM: Failed to get ARM preferred CPU target (errno: %i)\n",
596 errno);
597 }
598}
599#endif
600
601int
602KvmVM::ioctl(int request, long p1) const
603{
604 assert(vmFD != -1);
605
606 return ::ioctl(vmFD, request, p1);
607}
608
609} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
The AddrRange class encapsulates an address range, and supports a number of tests to check if two ran...
Definition addr_range.hh:82
Base class for KVM based CPU models.
Definition base.hh:88
Structures tracking memory slots.
Definition vm.hh:552
virtual ~KvmVM()
Definition vm.cc:334
long contextIdToVCpuId(ContextID ctx) const
Get the VCPUID for a given context.
Definition vm.cc:566
const MemSlot allocMemSlot(uint64_t size)
Allocate a memory slot within the VM.
Definition vm.cc:402
long nextVCPUID
Next unallocated vCPU ID.
Definition vm.hh:546
void notifyFork()
Notify a child process of a fork.
Definition vm.cc:344
bool validEnvironment() const
Verify gem5 configuration will support KVM emulation.
Definition vm.cc:555
uint32_t maxMemorySlot
Definition vm.hh:559
int createVCPU(long vcpuID)
Create a new vCPU within a VM.
Definition vm.cc:573
KvmVM(const KvmVMParams &params)
Definition vm.cc:316
bool started
Has delayedStartup() already been called?
Definition vm.hh:540
std::vector< MemorySlot > memorySlots
Definition vm.hh:558
System * system
Definition vm.hh:534
Kvm * kvm
Global KVM interface.
Definition vm.hh:421
int vmFD
KVM VM file descriptor.
Definition vm.hh:537
void freeMemSlot(const MemSlot slot)
Free a previously allocated memory slot.
Definition vm.cc:448
long allocVCPUID()
Allocate a new vCPU ID within the VM.
Definition vm.cc:585
void cpuStartup()
VM CPU initialization code.
Definition vm.cc:358
void setTSSAddress(Addr tss_address)
Setup a shared three-page memory region used by the internals of KVM.
Definition vm.cc:503
void disableMemSlot(const MemSlot slot)
Disable a memory slot.
Definition vm.cc:439
void setupMemSlot(const MemSlot slot, void *host_addr, Addr guest_addr, uint32_t flags)
Setup a region of physical memory in the guest.
Definition vm.cc:430
bool _hasKernelIRQChip
Do we have in-kernel IRQ-chip emulation enabled?
Definition vm.hh:543
void delayedStartup()
Delayed initialization, executed once before the first CPU starts.
Definition vm.cc:368
int createDevice(uint32_t type, uint32_t flags=0)
Create an in-kernel device model.
Definition vm.cc:538
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.
Definition vm.cc:456
void coalesceMMIO(Addr start, int size)
Request coalescing MMIO for a memory range.
Definition vm.cc:487
KVM parent interface.
Definition vm.hh:81
virtual ~Kvm()
Definition vm.cc:93
int apiVersion
KVM API version.
Definition vm.hh:267
int checkExtension(int extension) const
Check for the presence of an extension to the KVM API.
Definition vm.cc:287
int capNumMemSlots() const
Attempt to determine how many memory slots are available.
Definition vm.cc:142
bool capIRQLineLayout2() const
Support for ARM IRQ line layout 2.
Definition vm.cc:208
bool capXCRs() const
Support for getting and setting the x86 XCRs.
Definition vm.cc:188
Kvm * create()
Definition vm.cc:99
bool capIRQChip() const
Support for creating an in-kernel IRQ chip model.
Definition vm.cc:162
bool capExtendedCPUID() const
Support for BaseKvmCPU::setCPUID2 and getSupportedCPUID().
Definition vm.cc:120
bool capSetTSSAddress() const
Support for KvmVM::setTSSAddress()
Definition vm.cc:114
int createVM()
Create a KVM Virtual Machine.
Definition vm.cc:304
bool capUserNMI() const
Support for BaseKvmCPU::kvmNonMaskableInterrupt().
Definition vm.cc:126
bool capDebugRegs() const
Support for getting and setting the kvm_debugregs structure.
Definition vm.cc:178
int vcpuMMapSize
Size of the MMAPed vCPU parameter area.
Definition vm.hh:269
int capCoalescedMMIO() const
Check if coalesced MMIO is supported and which page in the MMAP'ed structure it stores requests in.
Definition vm.cc:136
bool capXSave() const
Support for getting and setting the kvm_xsave structure.
Definition vm.cc:198
Kvm()
Definition vm.cc:71
bool capUserMemory() const
Support for KvmVM::setUserMemoryRegion()
Definition vm.cc:108
bool capVCPUEvents() const
Support for getting and setting the kvm_vcpu_events structure.
Definition vm.cc:168
bool capOneReg() const
Support for reading and writing single registers.
Definition vm.cc:152
static Kvm * instance
Singleton instance.
Definition vm.hh:272
int kvmFD
KVM VM file descriptor.
Definition vm.hh:265
Abstract superclass for simulation objects.
void setKvmVM(KvmVM *const vm)
Set the pointer to the Kernel Virtual Machine (KVM) SimObject.
Definition system.hh:339
memory::PhysicalMemory & getPhysMem()
Get a pointer to access the physical memory of the system.
Definition system.hh:342
Threads threads
Definition system.hh:310
std::vector< BackingStoreEntry > getBackingStore() const
Get the pointers to the backing store for external host access.
Definition physical.hh:245
STL vector class.
Definition stl.hh:37
void setIRQLine(uint32_t irq, bool high)
Set the status of an IRQ line using KVM_IRQ_LINE.
Definition vm.cc:525
void createIRQChip()
Create an in-kernel interrupt controller.
Definition vm.cc:510
int ioctl(int request, long p1) const
Main VM ioctl interface.
Definition vm.cc:296
int ioctl(int request, long p1) const
KVM VM ioctl interface.
Definition vm.cc:602
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.
Definition logging.hh:188
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
const Params & params() const
uint8_t flags
Definition helpers.cc:87
#define hack(...)
Definition logging.hh:258
#define warn(...)
Definition logging.hh:256
#define warn_once(...)
Definition logging.hh:260
Bitfield< 14, 12 > fd
Definition types.hh:150
Bitfield< 18, 16 > len
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 1 > irq
Bitfield< 0 > m
Bitfield< 0 > p
Bitfield< 28, 21 > cpuid
Bitfield< 15 > system
Definition misc.hh:1032
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition types.hh:147
int ContextID
Globally unique thread context ID.
Definition types.hh:239

Generated on Tue Jun 18 2024 16:24:01 for gem5 by doxygen 1.11.0