blob: e9601031bfd9cbd9f66ff742a4fa2508538cb412 [file] [log] [blame]
Steven Smith01195b72011-06-16 17:05:17 +01001/*
2 * XEN platform pci device, formerly known as the event channel device
3 *
4 * Copyright (c) 2003-2004 Intel Corp.
5 * Copyright (c) 2006 XenSource
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
Peter Maydellb6a0aa02016-01-26 18:17:03 +000026#include "qemu/osdep.h"
Markus Armbrusterda34e652016-03-14 09:01:28 +010027#include "qapi/error.h"
Stefano Stabellini15e81592014-02-20 17:28:08 +000028#include "hw/ide.h"
Paolo Bonzini83c9f4c2013-02-04 15:40:22 +010029#include "hw/pci/pci.h"
30#include "hw/irq.h"
Paolo Bonzini0d09e412013-02-05 17:06:20 +010031#include "hw/xen/xen_common.h"
Markus Armbrusterd6454272019-08-12 07:23:45 +020032#include "migration/vmstate.h"
Paul Durrant2d0ed5e2019-01-08 14:48:46 +000033#include "hw/xen/xen-legacy-backend.h"
Steven Smith01195b72011-06-16 17:05:17 +010034#include "trace.h"
Paolo Bonzini022c62c2012-12-17 18:19:49 +010035#include "exec/address-spaces.h"
Philippe Mathieu-Daudéda278d52020-05-08 12:02:22 +020036#include "sysemu/xen.h"
Markus Armbruster4be74632014-10-07 13:59:18 +020037#include "sysemu/block-backend.h"
Eduardo Habkostb1ecd512015-10-21 13:46:50 -020038#include "qemu/error-report.h"
Markus Armbruster0b8fa322019-05-23 16:35:07 +020039#include "qemu/module.h"
Steven Smith01195b72011-06-16 17:05:17 +010040
41#include <xenguest.h>
Eduardo Habkostdb1015e2020-09-03 16:43:22 -040042#include "qom/object.h"
Steven Smith01195b72011-06-16 17:05:17 +010043
44//#define DEBUG_PLATFORM
45
46#ifdef DEBUG_PLATFORM
47#define DPRINTF(fmt, ...) do { \
48 fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
49} while (0)
50#else
51#define DPRINTF(fmt, ...) do { } while (0)
52#endif
53
54#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
55
Eduardo Habkostdb1015e2020-09-03 16:43:22 -040056struct PCIXenPlatformState {
Andreas Färberdc4aa512013-06-30 15:20:05 +020057 /*< private >*/
58 PCIDevice parent_obj;
59 /*< public >*/
60
Avi Kivityde009822011-08-08 16:09:25 +030061 MemoryRegion fixed_io;
62 MemoryRegion bar;
63 MemoryRegion mmio_bar;
Steven Smith01195b72011-06-16 17:05:17 +010064 uint8_t flags; /* used only for version_id == 2 */
65 int drivers_blacklisted;
66 uint16_t driver_product_version;
67
68 /* Log from guest drivers */
69 char log_buffer[4096];
70 int log_buffer_off;
Eduardo Habkostdb1015e2020-09-03 16:43:22 -040071};
Steven Smith01195b72011-06-16 17:05:17 +010072
Peter Crosthwaite51a3fe92013-06-24 17:00:14 +100073#define TYPE_XEN_PLATFORM "xen-platform"
Eduardo Habkost80633962020-09-16 14:25:19 -040074OBJECT_DECLARE_SIMPLE_TYPE(PCIXenPlatformState, XEN_PLATFORM)
Peter Crosthwaite51a3fe92013-06-24 17:00:14 +100075
Steven Smith01195b72011-06-16 17:05:17 +010076#define XEN_PLATFORM_IOPORT 0x10
77
78/* Send bytes to syslog */
79static void log_writeb(PCIXenPlatformState *s, char val)
80{
81 if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
82 /* Flush buffer */
83 s->log_buffer[s->log_buffer_off] = 0;
84 trace_xen_platform_log(s->log_buffer);
85 s->log_buffer_off = 0;
86 } else {
87 s->log_buffer[s->log_buffer_off++] = val;
88 }
89}
90
Stefano Stabellini04d6da42017-07-18 13:28:12 -070091/*
92 * Unplug device flags.
93 *
94 * The logic got a little confused at some point in the past but this is
95 * what they do now.
96 *
97 * bit 0: Unplug all IDE and SCSI disks.
98 * bit 1: Unplug all NICs.
99 * bit 2: Unplug IDE disks except primary master. This is overridden if
100 * bit 0 is also present in the mask.
101 * bit 3: Unplug all NVMe disks.
102 *
103 */
104#define _UNPLUG_IDE_SCSI_DISKS 0
105#define UNPLUG_IDE_SCSI_DISKS (1u << _UNPLUG_IDE_SCSI_DISKS)
106
107#define _UNPLUG_ALL_NICS 1
108#define UNPLUG_ALL_NICS (1u << _UNPLUG_ALL_NICS)
109
110#define _UNPLUG_AUX_IDE_DISKS 2
111#define UNPLUG_AUX_IDE_DISKS (1u << _UNPLUG_AUX_IDE_DISKS)
112
113#define _UNPLUG_NVME_DISKS 3
114#define UNPLUG_NVME_DISKS (1u << _UNPLUG_NVME_DISKS)
Stefano Stabellini679f4f82011-07-18 06:07:02 +0000115
Anthony PERARD7aa8cbb2012-06-21 15:35:28 +0000116static void unplug_nic(PCIBus *b, PCIDevice *d, void *o)
Stefano Stabellini679f4f82011-07-18 06:07:02 +0000117{
Anthony PERARDbd4982a2012-10-03 13:45:24 +0000118 /* We have to ignore passthrough devices */
Stefano Stabellini679f4f82011-07-18 06:07:02 +0000119 if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
Anthony PERARDbd4982a2012-10-03 13:45:24 +0000120 PCI_CLASS_NETWORK_ETHERNET
121 && strcmp(d->name, "xen-pci-passthrough") != 0) {
Stefan Hajnoczi02a5c4c2013-09-11 14:54:09 +0200122 object_unparent(OBJECT(d));
Stefano Stabellini679f4f82011-07-18 06:07:02 +0000123 }
124}
125
Ross Lagerwall6c808652017-06-30 13:50:28 +0100126/* Remove the peer of the NIC device. Normally, this would be a tap device. */
127static void del_nic_peer(NICState *nic, void *opaque)
128{
129 NetClientState *nc;
130
131 nc = qemu_get_queue(nic);
132 if (nc->peer)
133 qemu_del_net_client(nc->peer);
134}
135
Stefano Stabellini679f4f82011-07-18 06:07:02 +0000136static void pci_unplug_nics(PCIBus *bus)
137{
Ross Lagerwall6c808652017-06-30 13:50:28 +0100138 qemu_foreach_nic(del_nic_peer, NULL);
Anthony PERARD7aa8cbb2012-06-21 15:35:28 +0000139 pci_for_each_device(bus, 0, unplug_nic, NULL);
Stefano Stabellini679f4f82011-07-18 06:07:02 +0000140}
141
Paul Durrantae4d2eb2017-01-24 14:05:47 +0000142static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque)
Stefano Stabellini679f4f82011-07-18 06:07:02 +0000143{
Paul Durrantae4d2eb2017-01-24 14:05:47 +0000144 uint32_t flags = *(uint32_t *)opaque;
145 bool aux = (flags & UNPLUG_AUX_IDE_DISKS) &&
Stefano Stabellini04d6da42017-07-18 13:28:12 -0700146 !(flags & UNPLUG_IDE_SCSI_DISKS);
Paul Durrantae4d2eb2017-01-24 14:05:47 +0000147
Anthony PERARDbd4982a2012-10-03 13:45:24 +0000148 /* We have to ignore passthrough devices */
Paul Durrant3d89e3f2017-01-24 14:05:45 +0000149 if (!strcmp(d->name, "xen-pci-passthrough")) {
150 return;
151 }
152
153 switch (pci_get_word(d->config + PCI_CLASS_DEVICE)) {
154 case PCI_CLASS_STORAGE_IDE:
Paul Durrantae4d2eb2017-01-24 14:05:47 +0000155 pci_piix3_xen_ide_unplug(DEVICE(d), aux);
Paul Durrant3d89e3f2017-01-24 14:05:45 +0000156 break;
157
158 case PCI_CLASS_STORAGE_SCSI:
Paul Durrantae4d2eb2017-01-24 14:05:47 +0000159 if (!aux) {
160 object_unparent(OBJECT(d));
161 }
Paul Durrant3d89e3f2017-01-24 14:05:45 +0000162 break;
163
Stefano Stabellini04d6da42017-07-18 13:28:12 -0700164 case PCI_CLASS_STORAGE_EXPRESS:
165 if (flags & UNPLUG_NVME_DISKS) {
166 object_unparent(OBJECT(d));
167 }
168
Paul Durrant3d89e3f2017-01-24 14:05:45 +0000169 default:
170 break;
Stefano Stabellini679f4f82011-07-18 06:07:02 +0000171 }
172}
173
Paul Durrantae4d2eb2017-01-24 14:05:47 +0000174static void pci_unplug_disks(PCIBus *bus, uint32_t flags)
Stefano Stabellini679f4f82011-07-18 06:07:02 +0000175{
Paul Durrantae4d2eb2017-01-24 14:05:47 +0000176 pci_for_each_device(bus, 0, unplug_disks, &flags);
Stefano Stabellini679f4f82011-07-18 06:07:02 +0000177}
Steven Smith01195b72011-06-16 17:05:17 +0100178
179static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
180{
181 PCIXenPlatformState *s = opaque;
182
Anthony PERARDe7b48c92011-11-04 15:35:11 +0000183 switch (addr) {
Andreas Färberdc4aa512013-06-30 15:20:05 +0200184 case 0: {
185 PCIDevice *pci_dev = PCI_DEVICE(s);
Stefano Stabellini04d6da42017-07-18 13:28:12 -0700186 /* Unplug devices. See comment above flag definitions */
187 if (val & (UNPLUG_IDE_SCSI_DISKS | UNPLUG_AUX_IDE_DISKS |
188 UNPLUG_NVME_DISKS)) {
Stefano Stabellini679f4f82011-07-18 06:07:02 +0000189 DPRINTF("unplug disks\n");
David Gibsonfd56e062017-11-29 19:46:27 +1100190 pci_unplug_disks(pci_get_bus(pci_dev), val);
Stefano Stabellini679f4f82011-07-18 06:07:02 +0000191 }
192 if (val & UNPLUG_ALL_NICS) {
193 DPRINTF("unplug nics\n");
David Gibsonfd56e062017-11-29 19:46:27 +1100194 pci_unplug_nics(pci_get_bus(pci_dev));
Stefano Stabellini679f4f82011-07-18 06:07:02 +0000195 }
Steven Smith01195b72011-06-16 17:05:17 +0100196 break;
Andreas Färberdc4aa512013-06-30 15:20:05 +0200197 }
Steven Smith01195b72011-06-16 17:05:17 +0100198 case 2:
199 switch (val) {
200 case 1:
201 DPRINTF("Citrix Windows PV drivers loaded in guest\n");
202 break;
203 case 0:
204 DPRINTF("Guest claimed to be running PV product 0?\n");
205 break;
206 default:
207 DPRINTF("Unknown PV product %d loaded in guest\n", val);
208 break;
209 }
210 s->driver_product_version = val;
211 break;
212 }
213}
214
215static void platform_fixed_ioport_writel(void *opaque, uint32_t addr,
216 uint32_t val)
217{
Anthony PERARDe7b48c92011-11-04 15:35:11 +0000218 switch (addr) {
Steven Smith01195b72011-06-16 17:05:17 +0100219 case 0:
220 /* PV driver version */
221 break;
222 }
223}
224
225static void platform_fixed_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
226{
227 PCIXenPlatformState *s = opaque;
228
Anthony PERARDe7b48c92011-11-04 15:35:11 +0000229 switch (addr) {
Steven Smith01195b72011-06-16 17:05:17 +0100230 case 0: /* Platform flags */ {
231 hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ?
232 HVMMEM_ram_ro : HVMMEM_ram_rw;
Paul Durrant8f25e752017-03-07 10:55:32 +0000233 if (xen_set_mem_type(xen_domid, mem_type, 0xc0, 0x40)) {
Steven Smith01195b72011-06-16 17:05:17 +0100234 DPRINTF("unable to change ro/rw state of ROM memory area!\n");
235 } else {
236 s->flags = val & PFFLAG_ROM_LOCK;
237 DPRINTF("changed ro/rw state of ROM memory area. now is %s state.\n",
238 (mem_type == HVMMEM_ram_ro ? "ro":"rw"));
239 }
240 break;
241 }
242 case 2:
243 log_writeb(s, val);
244 break;
245 }
246}
247
248static uint32_t platform_fixed_ioport_readw(void *opaque, uint32_t addr)
249{
250 PCIXenPlatformState *s = opaque;
251
Anthony PERARDe7b48c92011-11-04 15:35:11 +0000252 switch (addr) {
Steven Smith01195b72011-06-16 17:05:17 +0100253 case 0:
254 if (s->drivers_blacklisted) {
255 /* The drivers will recognise this magic number and refuse
256 * to do anything. */
257 return 0xd249;
258 } else {
259 /* Magic value so that you can identify the interface. */
260 return 0x49d2;
261 }
262 default:
263 return 0xffff;
264 }
265}
266
267static uint32_t platform_fixed_ioport_readb(void *opaque, uint32_t addr)
268{
269 PCIXenPlatformState *s = opaque;
270
Anthony PERARDe7b48c92011-11-04 15:35:11 +0000271 switch (addr) {
Steven Smith01195b72011-06-16 17:05:17 +0100272 case 0:
273 /* Platform flags */
274 return s->flags;
275 case 2:
276 /* Version number */
277 return 1;
278 default:
279 return 0xff;
280 }
281}
282
283static void platform_fixed_ioport_reset(void *opaque)
284{
285 PCIXenPlatformState *s = opaque;
286
Anthony PERARDe7b48c92011-11-04 15:35:11 +0000287 platform_fixed_ioport_writeb(s, 0, 0);
Steven Smith01195b72011-06-16 17:05:17 +0100288}
289
Alexander Graf626c7a12012-10-08 13:47:30 +0200290static uint64_t platform_fixed_ioport_read(void *opaque,
291 hwaddr addr,
292 unsigned size)
293{
294 switch (size) {
295 case 1:
296 return platform_fixed_ioport_readb(opaque, addr);
297 case 2:
298 return platform_fixed_ioport_readw(opaque, addr);
299 default:
300 return -1;
301 }
302}
303
304static void platform_fixed_ioport_write(void *opaque, hwaddr addr,
305
306 uint64_t val, unsigned size)
307{
308 switch (size) {
309 case 1:
310 platform_fixed_ioport_writeb(opaque, addr, val);
311 break;
312 case 2:
313 platform_fixed_ioport_writew(opaque, addr, val);
314 break;
315 case 4:
316 platform_fixed_ioport_writel(opaque, addr, val);
317 break;
318 }
319}
320
Avi Kivityde009822011-08-08 16:09:25 +0300321
322static const MemoryRegionOps platform_fixed_io_ops = {
Alexander Graf626c7a12012-10-08 13:47:30 +0200323 .read = platform_fixed_ioport_read,
324 .write = platform_fixed_ioport_write,
Jan Kiszka962b03f2013-06-22 08:07:03 +0200325 .valid = {
326 .unaligned = true,
327 },
Alexander Graf626c7a12012-10-08 13:47:30 +0200328 .impl = {
329 .min_access_size = 1,
330 .max_access_size = 4,
Jan Kiszka962b03f2013-06-22 08:07:03 +0200331 .unaligned = true,
Alexander Graf626c7a12012-10-08 13:47:30 +0200332 },
333 .endianness = DEVICE_LITTLE_ENDIAN,
Avi Kivityde009822011-08-08 16:09:25 +0300334};
335
Steven Smith01195b72011-06-16 17:05:17 +0100336static void platform_fixed_ioport_init(PCIXenPlatformState* s)
337{
Paolo Bonzini22fc8602013-06-06 21:25:08 -0400338 memory_region_init_io(&s->fixed_io, OBJECT(s), &platform_fixed_io_ops, s,
Avi Kivityde009822011-08-08 16:09:25 +0300339 "xen-fixed", 16);
340 memory_region_add_subregion(get_system_io(), XEN_PLATFORM_IOPORT,
341 &s->fixed_io);
Steven Smith01195b72011-06-16 17:05:17 +0100342}
343
344/* Xen Platform PCI Device */
345
Hervé Poussineau7a652ef2013-01-04 22:29:40 +0100346static uint64_t xen_platform_ioport_readb(void *opaque, hwaddr addr,
347 unsigned int size)
Steven Smith01195b72011-06-16 17:05:17 +0100348{
Steven Smith01195b72011-06-16 17:05:17 +0100349 if (addr == 0) {
Anthony PERARDe7b48c92011-11-04 15:35:11 +0000350 return platform_fixed_ioport_readb(opaque, 0);
Steven Smith01195b72011-06-16 17:05:17 +0100351 } else {
352 return ~0u;
353 }
354}
355
Hervé Poussineau7a652ef2013-01-04 22:29:40 +0100356static void xen_platform_ioport_writeb(void *opaque, hwaddr addr,
357 uint64_t val, unsigned int size)
Steven Smith01195b72011-06-16 17:05:17 +0100358{
359 PCIXenPlatformState *s = opaque;
Olaf Hering35132012016-10-21 14:37:07 +0200360 PCIDevice *pci_dev = PCI_DEVICE(s);
Steven Smith01195b72011-06-16 17:05:17 +0100361
Steven Smith01195b72011-06-16 17:05:17 +0100362 switch (addr) {
363 case 0: /* Platform flags */
Hervé Poussineau7a652ef2013-01-04 22:29:40 +0100364 platform_fixed_ioport_writeb(opaque, 0, (uint32_t)val);
Steven Smith01195b72011-06-16 17:05:17 +0100365 break;
Olaf Hering35132012016-10-21 14:37:07 +0200366 case 4:
367 if (val == 1) {
368 /*
369 * SUSE unplug for Xenlinux
370 * xen-kmp used this since xen-3.0.4, instead the official protocol
371 * from xen-3.3+ It did an unconditional "outl(1, (ioaddr + 4));"
372 * Pre VMDP 1.7 used 4 and 8 depending on how VMDP was configured.
373 * If VMDP was to control both disk and LAN it would use 4.
374 * If it controlled just disk or just LAN, it would use 8 below.
375 */
David Gibsonfd56e062017-11-29 19:46:27 +1100376 pci_unplug_disks(pci_get_bus(pci_dev), UNPLUG_IDE_SCSI_DISKS);
377 pci_unplug_nics(pci_get_bus(pci_dev));
Olaf Hering35132012016-10-21 14:37:07 +0200378 }
379 break;
Steven Smith01195b72011-06-16 17:05:17 +0100380 case 8:
Olaf Hering35132012016-10-21 14:37:07 +0200381 switch (val) {
382 case 1:
David Gibsonfd56e062017-11-29 19:46:27 +1100383 pci_unplug_disks(pci_get_bus(pci_dev), UNPLUG_IDE_SCSI_DISKS);
Olaf Hering35132012016-10-21 14:37:07 +0200384 break;
385 case 2:
David Gibsonfd56e062017-11-29 19:46:27 +1100386 pci_unplug_nics(pci_get_bus(pci_dev));
Olaf Hering35132012016-10-21 14:37:07 +0200387 break;
388 default:
389 log_writeb(s, (uint32_t)val);
390 break;
391 }
Steven Smith01195b72011-06-16 17:05:17 +0100392 break;
393 default:
394 break;
395 }
396}
397
Avi Kivityde009822011-08-08 16:09:25 +0300398static const MemoryRegionOps xen_pci_io_ops = {
Hervé Poussineau7a652ef2013-01-04 22:29:40 +0100399 .read = xen_platform_ioport_readb,
400 .write = xen_platform_ioport_writeb,
401 .impl.min_access_size = 1,
402 .impl.max_access_size = 1,
Avi Kivityde009822011-08-08 16:09:25 +0300403};
404
405static void platform_ioport_bar_setup(PCIXenPlatformState *d)
406{
Paolo Bonzini22fc8602013-06-06 21:25:08 -0400407 memory_region_init_io(&d->bar, OBJECT(d), &xen_pci_io_ops, d,
408 "xen-pci", 0x100);
Steven Smith01195b72011-06-16 17:05:17 +0100409}
410
Avi Kivitya8170e52012-10-23 12:30:10 +0200411static uint64_t platform_mmio_read(void *opaque, hwaddr addr,
Avi Kivityde009822011-08-08 16:09:25 +0300412 unsigned size)
Steven Smith01195b72011-06-16 17:05:17 +0100413{
414 DPRINTF("Warning: attempted read from physical address "
415 "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
416
417 return 0;
418}
419
Avi Kivitya8170e52012-10-23 12:30:10 +0200420static void platform_mmio_write(void *opaque, hwaddr addr,
Avi Kivityde009822011-08-08 16:09:25 +0300421 uint64_t val, unsigned size)
Steven Smith01195b72011-06-16 17:05:17 +0100422{
Avi Kivityde009822011-08-08 16:09:25 +0300423 DPRINTF("Warning: attempted write of 0x%"PRIx64" to physical "
Steven Smith01195b72011-06-16 17:05:17 +0100424 "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
425 val, addr);
426}
427
Avi Kivityde009822011-08-08 16:09:25 +0300428static const MemoryRegionOps platform_mmio_handler = {
Steven Smith01195b72011-06-16 17:05:17 +0100429 .read = &platform_mmio_read,
430 .write = &platform_mmio_write,
Avi Kivityde009822011-08-08 16:09:25 +0300431 .endianness = DEVICE_NATIVE_ENDIAN,
Steven Smith01195b72011-06-16 17:05:17 +0100432};
433
Avi Kivityde009822011-08-08 16:09:25 +0300434static void platform_mmio_setup(PCIXenPlatformState *d)
Steven Smith01195b72011-06-16 17:05:17 +0100435{
Paolo Bonzini22fc8602013-06-06 21:25:08 -0400436 memory_region_init_io(&d->mmio_bar, OBJECT(d), &platform_mmio_handler, d,
Avi Kivityde009822011-08-08 16:09:25 +0300437 "xen-mmio", 0x1000000);
Steven Smith01195b72011-06-16 17:05:17 +0100438}
439
440static int xen_platform_post_load(void *opaque, int version_id)
441{
442 PCIXenPlatformState *s = opaque;
443
Anthony PERARDe7b48c92011-11-04 15:35:11 +0000444 platform_fixed_ioport_writeb(s, 0, s->flags);
Steven Smith01195b72011-06-16 17:05:17 +0100445
446 return 0;
447}
448
449static const VMStateDescription vmstate_xen_platform = {
450 .name = "platform",
451 .version_id = 4,
452 .minimum_version_id = 4,
Steven Smith01195b72011-06-16 17:05:17 +0100453 .post_load = xen_platform_post_load,
Juan Quintelad49805a2014-04-16 15:32:32 +0200454 .fields = (VMStateField[]) {
Andreas Färberdc4aa512013-06-30 15:20:05 +0200455 VMSTATE_PCI_DEVICE(parent_obj, PCIXenPlatformState),
Steven Smith01195b72011-06-16 17:05:17 +0100456 VMSTATE_UINT8(flags, PCIXenPlatformState),
457 VMSTATE_END_OF_LIST()
458 }
459};
460
Stefano Stabellini4098d492015-10-21 13:46:49 -0200461static void xen_platform_realize(PCIDevice *dev, Error **errp)
Steven Smith01195b72011-06-16 17:05:17 +0100462{
Peter Crosthwaite51a3fe92013-06-24 17:00:14 +1000463 PCIXenPlatformState *d = XEN_PLATFORM(dev);
Steven Smith01195b72011-06-16 17:05:17 +0100464 uint8_t *pci_conf;
465
Eduardo Habkostdbb74052015-09-28 17:01:24 -0300466 /* Device will crash on reset if xen is not initialized */
Eduardo Habkostb1ecd512015-10-21 13:46:50 -0200467 if (!xen_enabled()) {
468 error_setg(errp, "xen-platform device requires the Xen accelerator");
469 return;
470 }
Eduardo Habkostdbb74052015-09-28 17:01:24 -0300471
Andreas Färberdc4aa512013-06-30 15:20:05 +0200472 pci_conf = dev->config;
Steven Smith01195b72011-06-16 17:05:17 +0100473
Steven Smith01195b72011-06-16 17:05:17 +0100474 pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
475
Steven Smith01195b72011-06-16 17:05:17 +0100476 pci_config_set_prog_interface(pci_conf, 0);
477
Steven Smith01195b72011-06-16 17:05:17 +0100478 pci_conf[PCI_INTERRUPT_PIN] = 1;
479
Avi Kivityde009822011-08-08 16:09:25 +0300480 platform_ioport_bar_setup(d);
Andreas Färberdc4aa512013-06-30 15:20:05 +0200481 pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->bar);
Steven Smith01195b72011-06-16 17:05:17 +0100482
483 /* reserve 16MB mmio address for share memory*/
Avi Kivityde009822011-08-08 16:09:25 +0300484 platform_mmio_setup(d);
Andreas Färberdc4aa512013-06-30 15:20:05 +0200485 pci_register_bar(dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
Avi Kivitye824b2c2011-08-08 16:09:31 +0300486 &d->mmio_bar);
Steven Smith01195b72011-06-16 17:05:17 +0100487
488 platform_fixed_ioport_init(d);
Steven Smith01195b72011-06-16 17:05:17 +0100489}
490
491static void platform_reset(DeviceState *dev)
492{
Peter Crosthwaite51a3fe92013-06-24 17:00:14 +1000493 PCIXenPlatformState *s = XEN_PLATFORM(dev);
Steven Smith01195b72011-06-16 17:05:17 +0100494
495 platform_fixed_ioport_reset(s);
496}
497
Anthony Liguori40021f02011-12-04 12:22:06 -0600498static void xen_platform_class_init(ObjectClass *klass, void *data)
499{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600500 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori40021f02011-12-04 12:22:06 -0600501 PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
Michael S. Tsirkin0d2b9622011-06-26 16:30:45 +0300502
Stefano Stabellini4098d492015-10-21 13:46:49 -0200503 k->realize = xen_platform_realize;
Anthony Liguori40021f02011-12-04 12:22:06 -0600504 k->vendor_id = PCI_VENDOR_ID_XEN;
505 k->device_id = PCI_DEVICE_ID_XEN_PLATFORM;
506 k->class_id = PCI_CLASS_OTHERS << 8 | 0x80;
507 k->subsystem_vendor_id = PCI_VENDOR_ID_XEN;
508 k->subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM;
509 k->revision = 1;
Marcel Apfelbaum125ee0e2013-07-29 17:17:45 +0300510 set_bit(DEVICE_CATEGORY_MISC, dc->categories);
Anthony Liguori39bffca2011-12-07 21:34:16 -0600511 dc->desc = "XEN platform pci device";
512 dc->reset = platform_reset;
513 dc->vmsd = &vmstate_xen_platform;
Anthony Liguori40021f02011-12-04 12:22:06 -0600514}
515
Andreas Färber8c43a6f2013-01-10 16:19:07 +0100516static const TypeInfo xen_platform_info = {
Peter Crosthwaite51a3fe92013-06-24 17:00:14 +1000517 .name = TYPE_XEN_PLATFORM,
Anthony Liguori39bffca2011-12-07 21:34:16 -0600518 .parent = TYPE_PCI_DEVICE,
519 .instance_size = sizeof(PCIXenPlatformState),
520 .class_init = xen_platform_class_init,
Eduardo Habkostfd3b02c2017-09-27 16:56:34 -0300521 .interfaces = (InterfaceInfo[]) {
522 { INTERFACE_CONVENTIONAL_PCI_DEVICE },
523 { },
524 },
Steven Smith01195b72011-06-16 17:05:17 +0100525};
526
Andreas Färber83f7d432012-02-09 15:20:55 +0100527static void xen_platform_register_types(void)
Steven Smith01195b72011-06-16 17:05:17 +0100528{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600529 type_register_static(&xen_platform_info);
Steven Smith01195b72011-06-16 17:05:17 +0100530}
531
Andreas Färber83f7d432012-02-09 15:20:55 +0100532type_init(xen_platform_register_types)