1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
|
/*
*
* Copyright (c) 2015 Linaro Limited
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2 or later, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*
* Emulate a virtual board which works by passing Linux all the information
* it needs about what devices are present via the device tree.
* There are some restrictions about what we can do here:
* + we can only present devices whose Linux drivers will work based
* purely on the device tree with no platform data at all
* + we want to present a very stripped-down minimalist platform,
* both because this reduces the security attack surface from the guest
* and also because it reduces our exposure to being broken when
* the kernel updates its device tree bindings and requires further
* information in a device binding that we aren't providing.
* This is essentially the same approach kvmtool uses.
*/
#ifndef QEMU_ARM_VIRT_H
#define QEMU_ARM_VIRT_H
#include "exec/hwaddr.h"
#include "qemu/notify.h"
#include "hw/boards.h"
#include "hw/arm/boot.h"
#include "hw/block/flash.h"
#include "sysemu/kvm.h"
#include "hw/intc/arm_gicv3_common.h"
#define NUM_GICV2M_SPIS 64
#define NUM_VIRTIO_TRANSPORTS 32
#define NUM_SMMU_IRQS 4
#define ARCH_GIC_MAINT_IRQ 9
#define ARCH_TIMER_VIRT_IRQ 11
#define ARCH_TIMER_S_EL1_IRQ 13
#define ARCH_TIMER_NS_EL1_IRQ 14
#define ARCH_TIMER_NS_EL2_IRQ 10
#define VIRTUAL_PMU_IRQ 7
#define PPI(irq) ((irq) + 16)
enum {
VIRT_FLASH,
VIRT_MEM,
VIRT_CPUPERIPHS,
VIRT_GIC_DIST,
VIRT_GIC_CPU,
VIRT_GIC_V2M,
VIRT_GIC_HYP,
VIRT_GIC_VCPU,
VIRT_GIC_ITS,
VIRT_GIC_REDIST,
VIRT_SMMU,
VIRT_UART,
VIRT_MMIO,
VIRT_RTC,
VIRT_FW_CFG,
VIRT_PCIE,
VIRT_PCIE_MMIO,
VIRT_PCIE_PIO,
VIRT_PCIE_ECAM,
VIRT_PLATFORM_BUS,
VIRT_GPIO,
VIRT_SECURE_UART,
VIRT_SECURE_MEM,
VIRT_PCDIMM_ACPI,
VIRT_ACPI_GED,
VIRT_NVDIMM_ACPI,
VIRT_LOWMEMMAP_LAST,
};
/* indices of IO regions located after the RAM */
enum {
VIRT_HIGH_GIC_REDIST2 = VIRT_LOWMEMMAP_LAST,
VIRT_HIGH_PCIE_ECAM,
VIRT_HIGH_PCIE_MMIO,
};
typedef enum VirtIOMMUType {
VIRT_IOMMU_NONE,
VIRT_IOMMU_SMMUV3,
VIRT_IOMMU_VIRTIO,
} VirtIOMMUType;
typedef enum VirtGICType {
VIRT_GIC_VERSION_MAX,
VIRT_GIC_VERSION_HOST,
VIRT_GIC_VERSION_2,
VIRT_GIC_VERSION_3,
VIRT_GIC_VERSION_NOSEL,
} VirtGICType;
typedef struct MemMapEntry {
hwaddr base;
hwaddr size;
} MemMapEntry;
typedef struct {
MachineClass parent;
bool disallow_affinity_adjustment;
bool no_its;
bool no_pmu;
bool claim_edge_triggered_timers;
bool smbios_old_sys_ver;
bool no_highmem_ecam;
bool no_ged; /* Machines < 4.2 has no support for ACPI GED device */
bool kvm_no_adjvtime;
} VirtMachineClass;
typedef struct {
MachineState parent;
Notifier machine_done;
DeviceState *platform_bus_dev;
FWCfgState *fw_cfg;
PFlashCFI01 *flash[2];
bool secure;
bool highmem;
bool highmem_ecam;
bool its;
bool virt;
OnOffAuto acpi;
VirtGICType gic_version;
VirtIOMMUType iommu;
uint16_t virtio_iommu_bdf;
struct arm_boot_info bootinfo;
MemMapEntry *memmap;
char *pciehb_nodename;
const int *irqmap;
int smp_cpus;
void *fdt;
int fdt_size;
uint32_t clock_phandle;
uint32_t gic_phandle;
uint32_t msi_phandle;
uint32_t iommu_phandle;
int psci_conduit;
hwaddr highest_gpa;
DeviceState *gic;
DeviceState *acpi_dev;
Notifier powerdown_notifier;
} VirtMachineState;
#define VIRT_ECAM_ID(high) (high ? VIRT_HIGH_PCIE_ECAM : VIRT_PCIE_ECAM)
#define TYPE_VIRT_MACHINE MACHINE_TYPE_NAME("virt")
#define VIRT_MACHINE(obj) \
OBJECT_CHECK(VirtMachineState, (obj), TYPE_VIRT_MACHINE)
#define VIRT_MACHINE_GET_CLASS(obj) \
OBJECT_GET_CLASS(VirtMachineClass, obj, TYPE_VIRT_MACHINE)
#define VIRT_MACHINE_CLASS(klass) \
OBJECT_CLASS_CHECK(VirtMachineClass, klass, TYPE_VIRT_MACHINE)
void virt_acpi_setup(VirtMachineState *vms);
bool virt_is_acpi_enabled(VirtMachineState *vms);
/* Return the number of used redistributor regions */
static inline int virt_gicv3_redist_region_count(VirtMachineState *vms)
{
uint32_t redist0_capacity =
vms->memmap[VIRT_GIC_REDIST].size / GICV3_REDIST_SIZE;
assert(vms->gic_version == VIRT_GIC_VERSION_3);
return vms->smp_cpus > redist0_capacity ? 2 : 1;
}
#endif /* QEMU_ARM_VIRT_H */
|