cpu: o3: replace issueLatency with bool pipelined
[gem5.git] / src / cpu / kvm / vm.cc
1 /*
2 * Copyright 2014 Google, Inc.
3 * Copyright (c) 2012 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 * Authors: Andreas Sandberg
39 */
40
41 #include <linux/kvm.h>
42 #include <sys/ioctl.h>
43 #include <sys/stat.h>
44 #include <sys/types.h>
45 #include <fcntl.h>
46 #include <unistd.h>
47
48 #include <cerrno>
49 #include <memory>
50
51 #include "cpu/kvm/vm.hh"
52 #include "debug/Kvm.hh"
53 #include "params/KvmVM.hh"
54 #include "sim/system.hh"
55
56 #define EXPECTED_KVM_API_VERSION 12
57
58 #if EXPECTED_KVM_API_VERSION != KVM_API_VERSION
59 #error Unsupported KVM version
60 #endif
61
62 Kvm *Kvm::instance = NULL;
63
64 Kvm::Kvm()
65 : kvmFD(-1), apiVersion(-1), vcpuMMapSize(0)
66 {
67 kvmFD = ::open("/dev/kvm", O_RDWR);
68 if (kvmFD == -1)
69 fatal("KVM: Failed to open /dev/kvm\n");
70
71 apiVersion = ioctl(KVM_GET_API_VERSION);
72 if (apiVersion != EXPECTED_KVM_API_VERSION)
73 fatal("KVM: Incompatible API version\n");
74
75 vcpuMMapSize = ioctl(KVM_GET_VCPU_MMAP_SIZE);
76 if (vcpuMMapSize == -1)
77 panic("KVM: Failed to get virtual CPU MMAP size\n");
78 }
79
80 Kvm::~Kvm()
81 {
82 close(kvmFD);
83 }
84
85 Kvm *
86 Kvm::create()
87 {
88 if (!instance)
89 instance = new Kvm();
90
91 return instance;
92 }
93
94 bool
95 Kvm::capUserMemory() const
96 {
97 return checkExtension(KVM_CAP_USER_MEMORY) != 0;
98 }
99
100 bool
101 Kvm::capSetTSSAddress() const
102 {
103 return checkExtension(KVM_CAP_SET_TSS_ADDR) != 0;
104 }
105
106 bool
107 Kvm::capExtendedCPUID() const
108 {
109 return checkExtension(KVM_CAP_EXT_CPUID) != 0;
110 }
111
112 bool
113 Kvm::capUserNMI() const
114 {
115 #ifdef KVM_CAP_USER_NMI
116 return checkExtension(KVM_CAP_USER_NMI) != 0;
117 #else
118 return false;
119 #endif
120 }
121
122 int
123 Kvm::capCoalescedMMIO() const
124 {
125 return checkExtension(KVM_CAP_COALESCED_MMIO);
126 }
127
128 int
129 Kvm::capNumMemSlots() const
130 {
131 #ifdef KVM_CAP_NR_MEMSLOTS
132 return checkExtension(KVM_CAP_NR_MEMSLOTS);
133 #else
134 return 0;
135 #endif
136 }
137
138 bool
139 Kvm::capOneReg() const
140 {
141 #ifdef KVM_CAP_ONE_REG
142 return checkExtension(KVM_CAP_ONE_REG) != 0;
143 #else
144 return false;
145 #endif
146 }
147
148 bool
149 Kvm::capIRQChip() const
150 {
151 return checkExtension(KVM_CAP_IRQCHIP) != 0;
152 }
153
154 bool
155 Kvm::capVCPUEvents() const
156 {
157 #ifdef KVM_CAP_VCPU_EVENTS
158 return checkExtension(KVM_CAP_VCPU_EVENTS) != 0;
159 #else
160 return false;
161 #endif
162 }
163
164 bool
165 Kvm::capDebugRegs() const
166 {
167 #ifdef KVM_CAP_DEBUGREGS
168 return checkExtension(KVM_CAP_DEBUGREGS) != 0;
169 #else
170 return false;
171 #endif
172 }
173
174 bool
175 Kvm::capXCRs() const
176 {
177 #ifdef KVM_CAP_XCRS
178 return checkExtension(KVM_CAP_XCRS) != 0;
179 #else
180 return false;
181 #endif
182 }
183
184 bool
185 Kvm::capXSave() const
186 {
187 #ifdef KVM_CAP_XSAVE
188 return checkExtension(KVM_CAP_XSAVE) != 0;
189 #else
190 return false;
191 #endif
192 }
193
194 bool
195 Kvm::getSupportedCPUID(struct kvm_cpuid2 &cpuid) const
196 {
197 #if defined(__i386__) || defined(__x86_64__)
198 if (ioctl(KVM_GET_SUPPORTED_CPUID, (void *)&cpuid) == -1) {
199 if (errno == E2BIG)
200 return false;
201 else
202 panic("KVM: Failed to get supported CPUID (errno: %i)\n", errno);
203 } else
204 return true;
205 #else
206 panic("KVM: getSupportedCPUID is unsupported on this platform.\n");
207 #endif
208 }
209
210 const Kvm::CPUIDVector &
211 Kvm::getSupportedCPUID() const
212 {
213 if (supportedCPUIDCache.empty()) {
214 std::unique_ptr<struct kvm_cpuid2> cpuid;
215 int i(1);
216 do {
217 cpuid.reset((struct kvm_cpuid2 *)operator new(
218 sizeof(kvm_cpuid2) + i * sizeof(kvm_cpuid_entry2)));
219
220 cpuid->nent = i;
221 ++i;
222 } while (!getSupportedCPUID(*cpuid));
223 supportedCPUIDCache.assign(cpuid->entries,
224 cpuid->entries + cpuid->nent);
225 }
226
227 return supportedCPUIDCache;
228 }
229
230 bool
231 Kvm::getSupportedMSRs(struct kvm_msr_list &msrs) const
232 {
233 #if defined(__i386__) || defined(__x86_64__)
234 if (ioctl(KVM_GET_MSR_INDEX_LIST, (void *)&msrs) == -1) {
235 if (errno == E2BIG)
236 return false;
237 else
238 panic("KVM: Failed to get supported CPUID (errno: %i)\n", errno);
239 } else
240 return true;
241 #else
242 panic("KVM: getSupportedCPUID is unsupported on this platform.\n");
243 #endif
244 }
245
246 const Kvm::MSRIndexVector &
247 Kvm::getSupportedMSRs() const
248 {
249 if (supportedMSRCache.empty()) {
250 std::unique_ptr<struct kvm_msr_list> msrs;
251 int i(0);
252 do {
253 msrs.reset((struct kvm_msr_list *)operator new(
254 sizeof(kvm_msr_list) + i * sizeof(uint32_t)));
255
256 msrs->nmsrs = i;
257 ++i;
258 } while (!getSupportedMSRs(*msrs));
259 supportedMSRCache.assign(msrs->indices, msrs->indices + msrs->nmsrs);
260 }
261
262 return supportedMSRCache;
263 }
264
265 int
266 Kvm::checkExtension(int extension) const
267 {
268 int ret = ioctl(KVM_CHECK_EXTENSION, extension);
269 if (ret == -1)
270 panic("KVM: ioctl failed when checking for extension\n");
271 return ret;
272 }
273
274 int
275 Kvm::ioctl(int request, long p1) const
276 {
277 assert(kvmFD != -1);
278
279 return ::ioctl(kvmFD, request, p1);
280 }
281
282 int
283 Kvm::createVM()
284 {
285 int vmFD;
286
287 vmFD = ioctl(KVM_CREATE_VM);
288 if (vmFD == -1)
289 panic("Failed to create KVM VM\n");
290
291 return vmFD;
292 }
293
294
295 KvmVM::KvmVM(KvmVMParams *params)
296 : SimObject(params),
297 kvm(), system(params->system),
298 vmFD(kvm.createVM()),
299 started(false),
300 nextVCPUID(0)
301 {
302 maxMemorySlot = kvm.capNumMemSlots();
303 /* If we couldn't determine how memory slots there are, guess 32. */
304 if (!maxMemorySlot)
305 maxMemorySlot = 32;
306 /* Setup the coalesced MMIO regions */
307 for (int i = 0; i < params->coalescedMMIO.size(); ++i)
308 coalesceMMIO(params->coalescedMMIO[i]);
309 }
310
311 KvmVM::~KvmVM()
312 {
313 close(vmFD);
314 }
315
316 void
317 KvmVM::cpuStartup()
318 {
319 if (started)
320 return;
321 started = true;
322
323 delayedStartup();
324 }
325
326 void
327 KvmVM::delayedStartup()
328 {
329 const std::vector<std::pair<AddrRange, uint8_t*> >&memories(
330 system->getPhysMem().getBackingStore());
331
332 DPRINTF(Kvm, "Mapping %i memory region(s)\n", memories.size());
333 for (int slot(0); slot < memories.size(); ++slot) {
334 const AddrRange &range(memories[slot].first);
335 void *pmem(memories[slot].second);
336
337 if (pmem) {
338 DPRINTF(Kvm, "Mapping region: 0x%p -> 0x%llx [size: 0x%llx]\n",
339 pmem, range.start(), range.size());
340
341 if (range.interleaved()) {
342 panic("Tried to map an interleaved memory range into "
343 "a KVM VM.\n");
344 }
345
346 const MemSlot slot = allocMemSlot(range.size());
347 setupMemSlot(slot, pmem, range.start(), 0/* flags */);
348 } else {
349 DPRINTF(Kvm, "Zero-region not mapped: [0x%llx]\n", range.start());
350 hack("KVM: Zero memory handled as IO\n");
351 }
352 }
353 }
354
355 const KvmVM::MemSlot
356 KvmVM::allocMemSlot(uint64_t size)
357 {
358 if (!size)
359 panic("Memory slots must have non-zero size.\n");
360
361 std::vector<MemorySlot>::iterator pos;
362 for (pos = memorySlots.begin(); pos != memorySlots.end(); pos++) {
363 if (!pos->size) {
364 pos->size = size;
365 pos->active = false;
366 return pos->slot;
367 }
368 }
369
370 uint32_t nextSlot = memorySlots.size();
371 if (nextSlot > maxMemorySlot)
372 panic("Out of memory slots.\n");
373
374 MemorySlot slot;
375 slot.size = size;
376 slot.slot = nextSlot;
377 slot.active = false;
378
379 memorySlots.push_back(slot);
380 return MemSlot(slot.slot);
381 }
382
383 void
384 KvmVM::setupMemSlot(const KvmVM::MemSlot num, void *host_addr, Addr guest,
385 uint32_t flags)
386 {
387 MemorySlot &slot = memorySlots.at(num.num);
388 slot.active = true;
389 setUserMemoryRegion(num.num, host_addr, guest, slot.size, flags);
390 }
391
392 void
393 KvmVM::disableMemSlot(const KvmVM::MemSlot num)
394 {
395 MemorySlot &slot = memorySlots.at(num.num);
396 if (slot.active)
397 setUserMemoryRegion(num.num, NULL, 0, 0, 0);
398 slot.active = false;
399 }
400
401 void
402 KvmVM::freeMemSlot(const KvmVM::MemSlot num)
403 {
404 disableMemSlot(num.num);
405 MemorySlot &slot = memorySlots.at(num.num);
406 slot.size = 0;
407 }
408
409 void
410 KvmVM::setUserMemoryRegion(uint32_t slot,
411 void *host_addr, Addr guest_addr,
412 uint64_t len, uint32_t flags)
413 {
414 struct kvm_userspace_memory_region m;
415
416 memset(&m, 0, sizeof(m));
417 m.slot = slot;
418 m.flags = flags;
419 m.guest_phys_addr = (uint64_t)guest_addr;
420 m.memory_size = len;
421 m.userspace_addr = (__u64)host_addr;
422
423 if (ioctl(KVM_SET_USER_MEMORY_REGION, (void *)&m) == -1) {
424 panic("Failed to setup KVM memory region:\n"
425 "\tHost Address: 0x%p\n"
426 "\tGuest Address: 0x%llx\n",
427 "\tSize: %ll\n",
428 "\tFlags: 0x%x\n",
429 m.userspace_addr, m.guest_phys_addr,
430 m.memory_size, m.flags);
431 }
432 }
433
434 void
435 KvmVM::coalesceMMIO(const AddrRange &range)
436 {
437 coalesceMMIO(range.start(), range.size());
438 }
439
440 void
441 KvmVM::coalesceMMIO(Addr start, int size)
442 {
443 struct kvm_coalesced_mmio_zone zone;
444
445 zone.addr = start;
446 zone.size = size;
447 zone.pad = 0;
448
449 DPRINTF(Kvm, "KVM: Registering coalesced MMIO region [0x%x, 0x%x]\n",
450 zone.addr, zone.addr + zone.size - 1);
451 if (ioctl(KVM_REGISTER_COALESCED_MMIO, (void *)&zone) == -1)
452 panic("KVM: Failed to register coalesced MMIO region (%i)\n",
453 errno);
454 }
455
456 void
457 KvmVM::setTSSAddress(Addr tss_address)
458 {
459 if (ioctl(KVM_SET_TSS_ADDR, (unsigned long)tss_address) == -1)
460 panic("KVM: Failed to set VM TSS address\n");
461 }
462
463 void
464 KvmVM::createIRQChip()
465 {
466 if (_hasKernelIRQChip)
467 panic("KvmVM::createIRQChip called twice.\n");
468
469 if (ioctl(KVM_CREATE_IRQCHIP) != -1) {
470 _hasKernelIRQChip = true;
471 } else {
472 warn("KVM: Failed to create in-kernel IRQ chip (errno: %i)\n",
473 errno);
474 _hasKernelIRQChip = false;
475 }
476 }
477
478 void
479 KvmVM::setIRQLine(uint32_t irq, bool high)
480 {
481 struct kvm_irq_level kvm_level;
482
483 kvm_level.irq = irq;
484 kvm_level.level = high ? 1 : 0;
485
486 if (ioctl(KVM_IRQ_LINE, &kvm_level) == -1)
487 panic("KVM: Failed to set IRQ line level (errno: %i)\n",
488 errno);
489 }
490
491 int
492 KvmVM::createVCPU(long vcpuID)
493 {
494 int fd;
495
496 fd = ioctl(KVM_CREATE_VCPU, vcpuID);
497 if (fd == -1)
498 panic("KVM: Failed to create virtual CPU");
499
500 return fd;
501 }
502
503 long
504 KvmVM::allocVCPUID()
505 {
506 return nextVCPUID++;
507 }
508
509 int
510 KvmVM::ioctl(int request, long p1) const
511 {
512 assert(vmFD != -1);
513
514 return ::ioctl(vmFD, request, p1);
515 }
516
517
518 KvmVM *
519 KvmVMParams::create()
520 {
521 static bool created = false;
522 if (created)
523 warn_once("Use of multiple KvmVMs is currently untested!\n");
524
525 created = true;
526
527 return new KvmVM(this);
528 }