vm.hh revision 9651:f551c8ad12a5
1/*
2 * Copyright (c) 2012 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Andreas Sandberg
38 */
39
40#ifndef __CPU_KVM_KVMVM_HH__
41#define __CPU_KVM_KVMVM_HH__
42
43#include "base/addr_range.hh"
44#include "sim/sim_object.hh"
45
46// forward declarations
47struct KvmVMParams;
48class System;
49
50/**
51 * @defgroup KvmInterrupts KVM Interrupt handling.
52 *
53 * These methods control interrupt delivery to the guest system.
54 */
55
56/**
57 * @defgroup KvmIoctl KVM low-level ioctl interface.
58 *
59 * These methods provide a low-level interface to the underlying KVM
60 * layer.
61 */
62
63/**
64 * KVM parent interface
65 *
66 * The main Kvm object is used to provide functionality that is not
67 * specific to a VM or CPU. For example, it allows checking of the
68 * optional features and creation of VM containers.
69 */
70class Kvm
71{
72    friend class KvmVM;
73
74  public:
75    virtual ~Kvm();
76
77    Kvm *create();
78
79    /** Get the version of the KVM API implemented by the kernel. */
80    int getAPIVersion() const { return apiVersion; }
81    /**
82     * Get the size of the MMAPed parameter area used to communicate
83     * vCPU parameters between the kernel and userspace. This area,
84     * amongst other things, contains the kvm_run data structure.
85     */
86    int getVCPUMMapSize() const { return vcpuMMapSize; }
87
88    /** @{ */
89    /** Support for KvmVM::setUserMemoryRegion() */
90    bool capUserMemory() const;
91    /** Support for KvmVM::setTSSAddress() */
92    bool capSetTSSAddress() const;
93    /** Support for BaseKvmCPU::setCPUID2 and getSupportedCPUID(). */
94    bool capExtendedCPUID() const;
95    /** Support for BaseKvmCPU::kvmNonMaskableInterrupt(). */
96    bool capUserNMI() const;
97
98    /**
99     * Check if coalesced MMIO is supported and which page in the
100     * MMAP'ed structure it stores requests in.
101     *
102     * @return Offset (in pages) into the mmap'ed vCPU area where the
103     * MMIO buffer is stored. 0 if unsupported.
104     */
105    int capCoalescedMMIO() const;
106
107    /**
108     * Support for reading and writing single registers.
109     *
110     * @see BaseKvmCPU::getOneReg(), and BaseKvmCPU::setOneReg()
111     */
112    bool capOneReg() const;
113
114    /**
115     * Support for creating an in-kernel IRQ chip model.
116     *
117     * @see KvmVM::createIRQChip()
118     */
119    bool capIRQChip() const;
120    /** @} */
121
122    /**
123     * Get the CPUID features supported by the hardware and Kvm.
124     *
125     * @note Requires capExtendedCPUID().
126     *
127     * @return False if the allocation is too small, true on success.
128     */
129    bool getSupportedCPUID(struct kvm_cpuid2 &cpuid) const;
130
131  protected:
132    /**
133     * Check for the presence of an extension to the KVM API.
134     *
135     * The return value depends on the extension, but is always zero
136     * if it is unsupported or positive otherwise. Some extensions use
137     * the return value provide additional data about the extension.
138     *
139     * @return 0 if the extension is unsupported, positive integer
140     * otherwise.
141     */
142    int checkExtension(int extension) const;
143
144    /**
145     * @addtogroup KvmIoctl
146     * @{
147     */
148    /**
149     * Main VM ioctl interface.
150     *
151     * @param request KVM request
152     * @param p1 Optional request parameter
153     *
154     * @return -1 on error (error number in errno), ioctl dependent
155     * value otherwise.
156     */
157    int ioctl(int request, long p1) const;
158    int ioctl(int request, void *p1) const {
159        return ioctl(request, (long)p1);
160    }
161    int ioctl(int request) const {
162        return ioctl(request, 0L);
163    }
164    /** @} */
165
166  private:
167    // This object is a singleton, so prevent instantiation.
168    Kvm();
169
170    // Prevent copying
171    Kvm(const Kvm &kvm);
172    // Prevent assignment
173    Kvm &operator=(const Kvm &kvm);
174
175    /**
176     * Create a KVM Virtual Machine
177     *
178     * @return File descriptor pointing to the VM
179     */
180    int createVM();
181
182    /** KVM VM file descriptor */
183    int kvmFD;
184    /** KVM API version */
185    int apiVersion;
186    /** Size of the MMAPed vCPU parameter area. */
187    int vcpuMMapSize;
188
189    /** Singleton instance */
190    static Kvm *instance;
191};
192
193/**
194 * KVM VM container
195 *
196 * A KVM VM container normally contains all the CPUs in a shared
197 * memory machine. The VM container handles things like physical
198 * memory and to some extent interrupts. Normally, the VM API is only
199 * used for interrupts when the PIC is emulated by the kernel, which
200 * is a feature we do not use. However, some architectures (notably
201 * ARM) use the VM interface to deliver interrupts to specific CPUs as
202 * well.
203 *
204 * VM initialization is a bit different from that of other
205 * SimObjects. When we initialize the VM, we discover all physical
206 * memory mappings in the system. Since AbstractMem::unserialize
207 * re-maps the guests memory, we need to make sure that this is done
208 * after the memory has been re-mapped, but before the vCPUs are
209 * initialized (KVM requires memory mappings to be setup before CPUs
210 * can be created). Normally, we would just initialize the VM in
211 * init() or startup(), however, we can not use init() since this is
212 * called before AbstractMem::unserialize() and we can not use
213 * startup() since it must be called before BaseKvmCPU::startup() and
214 * the simulator framework does not guarantee call order. We therefore
215 * call cpuStartup() from BaseKvmCPU::startup() instead and execute
216 * the initialization code once when the first CPU in the VM is
217 * starting.
218 */
219class KvmVM : public SimObject
220{
221    friend class BaseKvmCPU;
222
223  public:
224    KvmVM(KvmVMParams *params);
225    virtual ~KvmVM();
226
227    /**
228     * Setup a shared three-page memory region used by the internals
229     * of KVM. This is currently only needed by x86 implementations.
230     *
231     * @param tss_address Physical address of the start of the TSS
232     */
233    void setTSSAddress(Addr tss_address);
234
235    /** @{ */
236    /**
237     * Request coalescing MMIO for a memory range.
238     *
239     * @param start Physical start address in guest
240     * @param size Size of the MMIO region
241     */
242    void coalesceMMIO(Addr start, int size);
243
244    /**
245     * Request coalescing MMIO for a memory range.
246     *
247     * @param range Coalesced MMIO range
248     */
249    void coalesceMMIO(const AddrRange &range);
250    /** @} */
251
252    /**
253     * @addtogroup KvmInterrupts
254     * @{
255     */
256    /**
257     * Create an in-kernel interrupt  controller
258     *
259     * @note This functionality depends on Kvm::capIRQChip().
260     */
261    void createIRQChip();
262
263    /**
264     * Set the status of an IRQ line using KVM_IRQ_LINE.
265     *
266     * @note This ioctl is usually only used if the interrupt
267     * controller is emulated by the kernel (i.e., after calling
268     * createIRQChip()). Some architectures (e.g., ARM) use it instead
269     * of BaseKvmCPU::kvmInterrupt().
270     *
271     * @param irq Interrupt number
272     * @param high Line level (true for high, false for low)
273     */
274    void setIRQLine(uint32_t irq, bool high);
275
276    /**
277     * Is in-kernel IRQ chip emulation enabled?
278     */
279    bool hasKernelIRQChip() const { return _hasKernelIRQChip; }
280    /** @} */
281
282    /** Global KVM interface */
283    Kvm kvm;
284
285  protected:
286    /**
287     * VM CPU initialization code.
288     *
289     * This method is called from BaseKvmCPU::startup() when a CPU in
290     * the VM executes its BaseKvmCPU::startup() method. The first
291     * time method is executed on a VM, it calls the delayedStartup()
292     * method.
293     */
294    void cpuStartup();
295
296    /**
297     * Delayed initialization, executed once before the first CPU
298     * starts.
299     *
300     * This method provides a way to do VM initialization once before
301     * the first CPU in a VM starts. It is needed since some resources
302     * (e.g., memory mappings) can change in the normal
303     * SimObject::startup() path. Since the call order of
304     * SimObject::startup() is not guaranteed, we simply defer some
305     * initialization until a CPU is about to start.
306     */
307    void delayedStartup();
308
309
310    /** @{ */
311    /**
312     * Setup a region of physical memory in the guest
313     *
314     * @param slot KVM memory slot ID (must be unique)
315     * @param host_addr Memory allocation backing the memory
316     * @param guest_addr Address in the guest
317     * @param guest_range Address range used by guest.
318     * @param len Size of the allocation in bytes
319     * @param flags Flags (see the KVM API documentation)
320     */
321    void setUserMemoryRegion(uint32_t slot,
322                             void *host_addr, Addr guest_addr,
323                             uint64_t len, uint32_t flags);
324    void setUserMemoryRegion(uint32_t slot,
325                             void *host_addr, AddrRange guest_range,
326                             uint32_t flags);
327    /** @} */
328
329    /**
330     * Create a new vCPU within a VM.
331     *
332     * @param vcpuID ID of the new CPU within the VM.
333     * @return File descriptor referencing the CPU.
334     */
335    int createVCPU(long vcpuID);
336
337    /**
338     * Allocate a new vCPU ID within the VM.
339     *
340     * The returned vCPU ID is guaranteed to be unique within the
341     * VM. New IDs are allocated sequentially starting from 0.
342     *
343     * @return ID of the new vCPU
344     */
345    long allocVCPUID();
346
347    /**
348     * @addtogroup KvmIoctl
349     * @{
350     */
351    /**
352     * KVM VM ioctl interface.
353     *
354     * @param request KVM VM request
355     * @param p1 Optional request parameter
356     *
357     * @return -1 on error (error number in errno), ioctl dependent
358     * value otherwise.
359     */
360    int ioctl(int request, long p1) const;
361    int ioctl(int request, void *p1) const {
362        return ioctl(request, (long)p1);
363    }
364    int ioctl(int request) const {
365        return ioctl(request, 0L);
366    }
367    /**@}*/
368
369  private:
370    // Prevent copying
371    KvmVM(const KvmVM &vm);
372    // Prevent assignment
373    KvmVM &operator=(const KvmVM &vm);
374
375    System *system;
376
377    /** KVM VM file descriptor */
378    const int vmFD;
379
380    /** Has delayedStartup() already been called? */
381    bool started;
382
383    /** Do we have in-kernel IRQ-chip emulation enabled? */
384    bool _hasKernelIRQChip;
385
386    /** Next unallocated vCPU ID */
387    long nextVCPUID;
388};
389
390#endif
391