]>
Commit | Line | Data |
---|---|---|
01195b73 SS |
1 | /* |
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 | ||
b6a0aa05 | 26 | #include "qemu/osdep.h" |
da34e65c | 27 | #include "qapi/error.h" |
83c9f4ca | 28 | #include "hw/hw.h" |
15e8159e | 29 | #include "hw/ide.h" |
83c9f4ca PB |
30 | #include "hw/pci/pci.h" |
31 | #include "hw/irq.h" | |
0d09e41a | 32 | #include "hw/xen/xen_common.h" |
d6454270 | 33 | #include "migration/vmstate.h" |
2d0ed5e6 | 34 | #include "hw/xen/xen-legacy-backend.h" |
01195b73 | 35 | #include "trace.h" |
022c62cb | 36 | #include "exec/address-spaces.h" |
4be74634 | 37 | #include "sysemu/block-backend.h" |
b1ecd51b | 38 | #include "qemu/error-report.h" |
0b8fa32f | 39 | #include "qemu/module.h" |
01195b73 SS |
40 | |
41 | #include <xenguest.h> | |
42 | ||
43 | //#define DEBUG_PLATFORM | |
44 | ||
45 | #ifdef DEBUG_PLATFORM | |
46 | #define DPRINTF(fmt, ...) do { \ | |
47 | fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \ | |
48 | } while (0) | |
49 | #else | |
50 | #define DPRINTF(fmt, ...) do { } while (0) | |
51 | #endif | |
52 | ||
53 | #define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */ | |
54 | ||
55 | typedef struct PCIXenPlatformState { | |
dc4aa51b AF |
56 | /*< private >*/ |
57 | PCIDevice parent_obj; | |
58 | /*< public >*/ | |
59 | ||
de00982e AK |
60 | MemoryRegion fixed_io; |
61 | MemoryRegion bar; | |
62 | MemoryRegion mmio_bar; | |
01195b73 SS |
63 | uint8_t flags; /* used only for version_id == 2 */ |
64 | int drivers_blacklisted; | |
65 | uint16_t driver_product_version; | |
66 | ||
67 | /* Log from guest drivers */ | |
68 | char log_buffer[4096]; | |
69 | int log_buffer_off; | |
70 | } PCIXenPlatformState; | |
71 | ||
51a3fe99 PC |
72 | #define TYPE_XEN_PLATFORM "xen-platform" |
73 | #define XEN_PLATFORM(obj) \ | |
74 | OBJECT_CHECK(PCIXenPlatformState, (obj), TYPE_XEN_PLATFORM) | |
75 | ||
01195b73 SS |
76 | #define XEN_PLATFORM_IOPORT 0x10 |
77 | ||
78 | /* Send bytes to syslog */ | |
79 | static 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 | ||
04d6da4f SS |
91 | /* |
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) | |
679f4f8b | 115 | |
7aa8cbb9 | 116 | static void unplug_nic(PCIBus *b, PCIDevice *d, void *o) |
679f4f8b | 117 | { |
bd4982a6 | 118 | /* We have to ignore passthrough devices */ |
679f4f8b | 119 | if (pci_get_word(d->config + PCI_CLASS_DEVICE) == |
bd4982a6 AP |
120 | PCI_CLASS_NETWORK_ETHERNET |
121 | && strcmp(d->name, "xen-pci-passthrough") != 0) { | |
02a5c4c9 | 122 | object_unparent(OBJECT(d)); |
679f4f8b SS |
123 | } |
124 | } | |
125 | ||
6c808651 RL |
126 | /* Remove the peer of the NIC device. Normally, this would be a tap device. */ |
127 | static 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 | ||
679f4f8b SS |
136 | static void pci_unplug_nics(PCIBus *bus) |
137 | { | |
6c808651 | 138 | qemu_foreach_nic(del_nic_peer, NULL); |
7aa8cbb9 | 139 | pci_for_each_device(bus, 0, unplug_nic, NULL); |
679f4f8b SS |
140 | } |
141 | ||
ae4d2eb2 | 142 | static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque) |
679f4f8b | 143 | { |
ae4d2eb2 PD |
144 | uint32_t flags = *(uint32_t *)opaque; |
145 | bool aux = (flags & UNPLUG_AUX_IDE_DISKS) && | |
04d6da4f | 146 | !(flags & UNPLUG_IDE_SCSI_DISKS); |
ae4d2eb2 | 147 | |
bd4982a6 | 148 | /* We have to ignore passthrough devices */ |
3d89e3f7 PD |
149 | 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: | |
ae4d2eb2 | 155 | pci_piix3_xen_ide_unplug(DEVICE(d), aux); |
3d89e3f7 PD |
156 | break; |
157 | ||
158 | case PCI_CLASS_STORAGE_SCSI: | |
ae4d2eb2 PD |
159 | if (!aux) { |
160 | object_unparent(OBJECT(d)); | |
161 | } | |
3d89e3f7 PD |
162 | break; |
163 | ||
04d6da4f SS |
164 | case PCI_CLASS_STORAGE_EXPRESS: |
165 | if (flags & UNPLUG_NVME_DISKS) { | |
166 | object_unparent(OBJECT(d)); | |
167 | } | |
168 | ||
3d89e3f7 PD |
169 | default: |
170 | break; | |
679f4f8b SS |
171 | } |
172 | } | |
173 | ||
ae4d2eb2 | 174 | static void pci_unplug_disks(PCIBus *bus, uint32_t flags) |
679f4f8b | 175 | { |
ae4d2eb2 | 176 | pci_for_each_device(bus, 0, unplug_disks, &flags); |
679f4f8b | 177 | } |
01195b73 SS |
178 | |
179 | static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val) | |
180 | { | |
181 | PCIXenPlatformState *s = opaque; | |
182 | ||
e7b48c97 | 183 | switch (addr) { |
dc4aa51b AF |
184 | case 0: { |
185 | PCIDevice *pci_dev = PCI_DEVICE(s); | |
04d6da4f SS |
186 | /* Unplug devices. See comment above flag definitions */ |
187 | if (val & (UNPLUG_IDE_SCSI_DISKS | UNPLUG_AUX_IDE_DISKS | | |
188 | UNPLUG_NVME_DISKS)) { | |
679f4f8b | 189 | DPRINTF("unplug disks\n"); |
fd56e061 | 190 | pci_unplug_disks(pci_get_bus(pci_dev), val); |
679f4f8b SS |
191 | } |
192 | if (val & UNPLUG_ALL_NICS) { | |
193 | DPRINTF("unplug nics\n"); | |
fd56e061 | 194 | pci_unplug_nics(pci_get_bus(pci_dev)); |
679f4f8b | 195 | } |
01195b73 | 196 | break; |
dc4aa51b | 197 | } |
01195b73 SS |
198 | 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 | ||
215 | static void platform_fixed_ioport_writel(void *opaque, uint32_t addr, | |
216 | uint32_t val) | |
217 | { | |
e7b48c97 | 218 | switch (addr) { |
01195b73 SS |
219 | case 0: |
220 | /* PV driver version */ | |
221 | break; | |
222 | } | |
223 | } | |
224 | ||
225 | static void platform_fixed_ioport_writeb(void *opaque, uint32_t addr, uint32_t val) | |
226 | { | |
227 | PCIXenPlatformState *s = opaque; | |
228 | ||
e7b48c97 | 229 | switch (addr) { |
01195b73 SS |
230 | case 0: /* Platform flags */ { |
231 | hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ? | |
232 | HVMMEM_ram_ro : HVMMEM_ram_rw; | |
8f25e754 | 233 | if (xen_set_mem_type(xen_domid, mem_type, 0xc0, 0x40)) { |
01195b73 SS |
234 | 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 | ||
248 | static uint32_t platform_fixed_ioport_readw(void *opaque, uint32_t addr) | |
249 | { | |
250 | PCIXenPlatformState *s = opaque; | |
251 | ||
e7b48c97 | 252 | switch (addr) { |
01195b73 SS |
253 | 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 | ||
267 | static uint32_t platform_fixed_ioport_readb(void *opaque, uint32_t addr) | |
268 | { | |
269 | PCIXenPlatformState *s = opaque; | |
270 | ||
e7b48c97 | 271 | switch (addr) { |
01195b73 SS |
272 | 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 | ||
283 | static void platform_fixed_ioport_reset(void *opaque) | |
284 | { | |
285 | PCIXenPlatformState *s = opaque; | |
286 | ||
e7b48c97 | 287 | platform_fixed_ioport_writeb(s, 0, 0); |
01195b73 SS |
288 | } |
289 | ||
626c7a17 AG |
290 | static 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 | ||
304 | static 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 | ||
de00982e AK |
321 | |
322 | static const MemoryRegionOps platform_fixed_io_ops = { | |
626c7a17 AG |
323 | .read = platform_fixed_ioport_read, |
324 | .write = platform_fixed_ioport_write, | |
962b03fc JK |
325 | .valid = { |
326 | .unaligned = true, | |
327 | }, | |
626c7a17 AG |
328 | .impl = { |
329 | .min_access_size = 1, | |
330 | .max_access_size = 4, | |
962b03fc | 331 | .unaligned = true, |
626c7a17 AG |
332 | }, |
333 | .endianness = DEVICE_LITTLE_ENDIAN, | |
de00982e AK |
334 | }; |
335 | ||
01195b73 SS |
336 | static void platform_fixed_ioport_init(PCIXenPlatformState* s) |
337 | { | |
22fc860b | 338 | memory_region_init_io(&s->fixed_io, OBJECT(s), &platform_fixed_io_ops, s, |
de00982e AK |
339 | "xen-fixed", 16); |
340 | memory_region_add_subregion(get_system_io(), XEN_PLATFORM_IOPORT, | |
341 | &s->fixed_io); | |
01195b73 SS |
342 | } |
343 | ||
344 | /* Xen Platform PCI Device */ | |
345 | ||
7a652efa HP |
346 | static uint64_t xen_platform_ioport_readb(void *opaque, hwaddr addr, |
347 | unsigned int size) | |
01195b73 | 348 | { |
01195b73 | 349 | if (addr == 0) { |
e7b48c97 | 350 | return platform_fixed_ioport_readb(opaque, 0); |
01195b73 SS |
351 | } else { |
352 | return ~0u; | |
353 | } | |
354 | } | |
355 | ||
7a652efa HP |
356 | static void xen_platform_ioport_writeb(void *opaque, hwaddr addr, |
357 | uint64_t val, unsigned int size) | |
01195b73 SS |
358 | { |
359 | PCIXenPlatformState *s = opaque; | |
35132016 | 360 | PCIDevice *pci_dev = PCI_DEVICE(s); |
01195b73 | 361 | |
01195b73 SS |
362 | switch (addr) { |
363 | case 0: /* Platform flags */ | |
7a652efa | 364 | platform_fixed_ioport_writeb(opaque, 0, (uint32_t)val); |
01195b73 | 365 | break; |
35132016 OH |
366 | 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 | */ | |
fd56e061 DG |
376 | pci_unplug_disks(pci_get_bus(pci_dev), UNPLUG_IDE_SCSI_DISKS); |
377 | pci_unplug_nics(pci_get_bus(pci_dev)); | |
35132016 OH |
378 | } |
379 | break; | |
01195b73 | 380 | case 8: |
35132016 OH |
381 | switch (val) { |
382 | case 1: | |
fd56e061 | 383 | pci_unplug_disks(pci_get_bus(pci_dev), UNPLUG_IDE_SCSI_DISKS); |
35132016 OH |
384 | break; |
385 | case 2: | |
fd56e061 | 386 | pci_unplug_nics(pci_get_bus(pci_dev)); |
35132016 OH |
387 | break; |
388 | default: | |
389 | log_writeb(s, (uint32_t)val); | |
390 | break; | |
391 | } | |
01195b73 SS |
392 | break; |
393 | default: | |
394 | break; | |
395 | } | |
396 | } | |
397 | ||
de00982e | 398 | static const MemoryRegionOps xen_pci_io_ops = { |
7a652efa HP |
399 | .read = xen_platform_ioport_readb, |
400 | .write = xen_platform_ioport_writeb, | |
401 | .impl.min_access_size = 1, | |
402 | .impl.max_access_size = 1, | |
de00982e | 403 | }; |
01195b73 | 404 | |
de00982e AK |
405 | static void platform_ioport_bar_setup(PCIXenPlatformState *d) |
406 | { | |
22fc860b PB |
407 | memory_region_init_io(&d->bar, OBJECT(d), &xen_pci_io_ops, d, |
408 | "xen-pci", 0x100); | |
01195b73 SS |
409 | } |
410 | ||
a8170e5e | 411 | static uint64_t platform_mmio_read(void *opaque, hwaddr addr, |
de00982e | 412 | unsigned size) |
01195b73 SS |
413 | { |
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 | ||
a8170e5e | 420 | static void platform_mmio_write(void *opaque, hwaddr addr, |
de00982e | 421 | uint64_t val, unsigned size) |
01195b73 | 422 | { |
de00982e | 423 | DPRINTF("Warning: attempted write of 0x%"PRIx64" to physical " |
01195b73 SS |
424 | "address 0x" TARGET_FMT_plx " in xen platform mmio space\n", |
425 | val, addr); | |
426 | } | |
427 | ||
de00982e | 428 | static const MemoryRegionOps platform_mmio_handler = { |
01195b73 SS |
429 | .read = &platform_mmio_read, |
430 | .write = &platform_mmio_write, | |
de00982e | 431 | .endianness = DEVICE_NATIVE_ENDIAN, |
01195b73 SS |
432 | }; |
433 | ||
de00982e | 434 | static void platform_mmio_setup(PCIXenPlatformState *d) |
01195b73 | 435 | { |
22fc860b | 436 | memory_region_init_io(&d->mmio_bar, OBJECT(d), &platform_mmio_handler, d, |
de00982e | 437 | "xen-mmio", 0x1000000); |
01195b73 SS |
438 | } |
439 | ||
440 | static int xen_platform_post_load(void *opaque, int version_id) | |
441 | { | |
442 | PCIXenPlatformState *s = opaque; | |
443 | ||
e7b48c97 | 444 | platform_fixed_ioport_writeb(s, 0, s->flags); |
01195b73 SS |
445 | |
446 | return 0; | |
447 | } | |
448 | ||
449 | static const VMStateDescription vmstate_xen_platform = { | |
450 | .name = "platform", | |
451 | .version_id = 4, | |
452 | .minimum_version_id = 4, | |
01195b73 | 453 | .post_load = xen_platform_post_load, |
d49805ae | 454 | .fields = (VMStateField[]) { |
dc4aa51b | 455 | VMSTATE_PCI_DEVICE(parent_obj, PCIXenPlatformState), |
01195b73 SS |
456 | VMSTATE_UINT8(flags, PCIXenPlatformState), |
457 | VMSTATE_END_OF_LIST() | |
458 | } | |
459 | }; | |
460 | ||
4098d49d | 461 | static void xen_platform_realize(PCIDevice *dev, Error **errp) |
01195b73 | 462 | { |
51a3fe99 | 463 | PCIXenPlatformState *d = XEN_PLATFORM(dev); |
01195b73 SS |
464 | uint8_t *pci_conf; |
465 | ||
dbb7405d | 466 | /* Device will crash on reset if xen is not initialized */ |
b1ecd51b EH |
467 | if (!xen_enabled()) { |
468 | error_setg(errp, "xen-platform device requires the Xen accelerator"); | |
469 | return; | |
470 | } | |
dbb7405d | 471 | |
dc4aa51b | 472 | pci_conf = dev->config; |
01195b73 | 473 | |
01195b73 SS |
474 | pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY); |
475 | ||
01195b73 SS |
476 | pci_config_set_prog_interface(pci_conf, 0); |
477 | ||
01195b73 SS |
478 | pci_conf[PCI_INTERRUPT_PIN] = 1; |
479 | ||
de00982e | 480 | platform_ioport_bar_setup(d); |
dc4aa51b | 481 | pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->bar); |
01195b73 SS |
482 | |
483 | /* reserve 16MB mmio address for share memory*/ | |
de00982e | 484 | platform_mmio_setup(d); |
dc4aa51b | 485 | pci_register_bar(dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH, |
e824b2cc | 486 | &d->mmio_bar); |
01195b73 SS |
487 | |
488 | platform_fixed_ioport_init(d); | |
01195b73 SS |
489 | } |
490 | ||
491 | static void platform_reset(DeviceState *dev) | |
492 | { | |
51a3fe99 | 493 | PCIXenPlatformState *s = XEN_PLATFORM(dev); |
01195b73 SS |
494 | |
495 | platform_fixed_ioport_reset(s); | |
496 | } | |
497 | ||
40021f08 AL |
498 | static void xen_platform_class_init(ObjectClass *klass, void *data) |
499 | { | |
39bffca2 | 500 | DeviceClass *dc = DEVICE_CLASS(klass); |
40021f08 AL |
501 | PCIDeviceClass *k = PCI_DEVICE_CLASS(klass); |
502 | ||
4098d49d | 503 | k->realize = xen_platform_realize; |
40021f08 AL |
504 | 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; | |
125ee0ed | 510 | set_bit(DEVICE_CATEGORY_MISC, dc->categories); |
39bffca2 AL |
511 | dc->desc = "XEN platform pci device"; |
512 | dc->reset = platform_reset; | |
513 | dc->vmsd = &vmstate_xen_platform; | |
40021f08 AL |
514 | } |
515 | ||
8c43a6f0 | 516 | static const TypeInfo xen_platform_info = { |
51a3fe99 | 517 | .name = TYPE_XEN_PLATFORM, |
39bffca2 AL |
518 | .parent = TYPE_PCI_DEVICE, |
519 | .instance_size = sizeof(PCIXenPlatformState), | |
520 | .class_init = xen_platform_class_init, | |
fd3b02c8 EH |
521 | .interfaces = (InterfaceInfo[]) { |
522 | { INTERFACE_CONVENTIONAL_PCI_DEVICE }, | |
523 | { }, | |
524 | }, | |
01195b73 SS |
525 | }; |
526 | ||
83f7d43a | 527 | static void xen_platform_register_types(void) |
01195b73 | 528 | { |
39bffca2 | 529 | type_register_static(&xen_platform_info); |
01195b73 SS |
530 | } |
531 | ||
83f7d43a | 532 | type_init(xen_platform_register_types) |