xref: /openbmc/qemu/hw/i386/xen/xen_platform.c (revision 5d721b78)
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 
26 #include "qemu/osdep.h"
27 #include "qapi/error.h"
28 #include "hw/hw.h"
29 #include "hw/i386/pc.h"
30 #include "hw/ide.h"
31 #include "hw/pci/pci.h"
32 #include "hw/irq.h"
33 #include "hw/xen/xen_common.h"
34 #include "hw/xen/xen_backend.h"
35 #include "trace.h"
36 #include "exec/address-spaces.h"
37 #include "sysemu/block-backend.h"
38 #include "qemu/error-report.h"
39 
40 #include <xenguest.h>
41 
42 //#define DEBUG_PLATFORM
43 
44 #ifdef DEBUG_PLATFORM
45 #define DPRINTF(fmt, ...) do { \
46     fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
47 } while (0)
48 #else
49 #define DPRINTF(fmt, ...) do { } while (0)
50 #endif
51 
52 #define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
53 
54 typedef struct PCIXenPlatformState {
55     /*< private >*/
56     PCIDevice parent_obj;
57     /*< public >*/
58 
59     MemoryRegion fixed_io;
60     MemoryRegion bar;
61     MemoryRegion mmio_bar;
62     uint8_t flags; /* used only for version_id == 2 */
63     int drivers_blacklisted;
64     uint16_t driver_product_version;
65 
66     /* Log from guest drivers */
67     char log_buffer[4096];
68     int log_buffer_off;
69 } PCIXenPlatformState;
70 
71 #define TYPE_XEN_PLATFORM "xen-platform"
72 #define XEN_PLATFORM(obj) \
73     OBJECT_CHECK(PCIXenPlatformState, (obj), TYPE_XEN_PLATFORM)
74 
75 #define XEN_PLATFORM_IOPORT 0x10
76 
77 /* Send bytes to syslog */
78 static void log_writeb(PCIXenPlatformState *s, char val)
79 {
80     if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
81         /* Flush buffer */
82         s->log_buffer[s->log_buffer_off] = 0;
83         trace_xen_platform_log(s->log_buffer);
84         s->log_buffer_off = 0;
85     } else {
86         s->log_buffer[s->log_buffer_off++] = val;
87     }
88 }
89 
90 /* Xen Platform, Fixed IOPort */
91 #define UNPLUG_ALL_DISKS 1
92 #define UNPLUG_ALL_NICS 2
93 #define UNPLUG_AUX_IDE_DISKS 4
94 
95 static void unplug_nic(PCIBus *b, PCIDevice *d, void *o)
96 {
97     /* We have to ignore passthrough devices */
98     if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
99             PCI_CLASS_NETWORK_ETHERNET
100             && strcmp(d->name, "xen-pci-passthrough") != 0) {
101         object_unparent(OBJECT(d));
102     }
103 }
104 
105 /* Remove the peer of the NIC device. Normally, this would be a tap device. */
106 static void del_nic_peer(NICState *nic, void *opaque)
107 {
108     NetClientState *nc;
109 
110     nc = qemu_get_queue(nic);
111     if (nc->peer)
112         qemu_del_net_client(nc->peer);
113 }
114 
115 static void pci_unplug_nics(PCIBus *bus)
116 {
117     qemu_foreach_nic(del_nic_peer, NULL);
118     pci_for_each_device(bus, 0, unplug_nic, NULL);
119 }
120 
121 static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque)
122 {
123     uint32_t flags = *(uint32_t *)opaque;
124     bool aux = (flags & UNPLUG_AUX_IDE_DISKS) &&
125         !(flags & UNPLUG_ALL_DISKS);
126 
127     /* We have to ignore passthrough devices */
128     if (!strcmp(d->name, "xen-pci-passthrough")) {
129         return;
130     }
131 
132     switch (pci_get_word(d->config + PCI_CLASS_DEVICE)) {
133     case PCI_CLASS_STORAGE_IDE:
134         pci_piix3_xen_ide_unplug(DEVICE(d), aux);
135         break;
136 
137     case PCI_CLASS_STORAGE_SCSI:
138     case PCI_CLASS_STORAGE_EXPRESS:
139         if (!aux) {
140             object_unparent(OBJECT(d));
141         }
142         break;
143 
144     default:
145         break;
146     }
147 }
148 
149 static void pci_unplug_disks(PCIBus *bus, uint32_t flags)
150 {
151     pci_for_each_device(bus, 0, unplug_disks, &flags);
152 }
153 
154 static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
155 {
156     PCIXenPlatformState *s = opaque;
157 
158     switch (addr) {
159     case 0: {
160         PCIDevice *pci_dev = PCI_DEVICE(s);
161         /* Unplug devices.  Value is a bitmask of which devices to
162            unplug, with bit 0 the disk devices, bit 1 the network
163            devices, and bit 2 the non-primary-master IDE devices. */
164         if (val & (UNPLUG_ALL_DISKS | UNPLUG_AUX_IDE_DISKS)) {
165             DPRINTF("unplug disks\n");
166             pci_unplug_disks(pci_dev->bus, val);
167         }
168         if (val & UNPLUG_ALL_NICS) {
169             DPRINTF("unplug nics\n");
170             pci_unplug_nics(pci_dev->bus);
171         }
172         break;
173     }
174     case 2:
175         switch (val) {
176         case 1:
177             DPRINTF("Citrix Windows PV drivers loaded in guest\n");
178             break;
179         case 0:
180             DPRINTF("Guest claimed to be running PV product 0?\n");
181             break;
182         default:
183             DPRINTF("Unknown PV product %d loaded in guest\n", val);
184             break;
185         }
186         s->driver_product_version = val;
187         break;
188     }
189 }
190 
191 static void platform_fixed_ioport_writel(void *opaque, uint32_t addr,
192                                          uint32_t val)
193 {
194     switch (addr) {
195     case 0:
196         /* PV driver version */
197         break;
198     }
199 }
200 
201 static void platform_fixed_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
202 {
203     PCIXenPlatformState *s = opaque;
204 
205     switch (addr) {
206     case 0: /* Platform flags */ {
207         hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ?
208             HVMMEM_ram_ro : HVMMEM_ram_rw;
209         if (xen_set_mem_type(xen_domid, mem_type, 0xc0, 0x40)) {
210             DPRINTF("unable to change ro/rw state of ROM memory area!\n");
211         } else {
212             s->flags = val & PFFLAG_ROM_LOCK;
213             DPRINTF("changed ro/rw state of ROM memory area. now is %s state.\n",
214                     (mem_type == HVMMEM_ram_ro ? "ro":"rw"));
215         }
216         break;
217     }
218     case 2:
219         log_writeb(s, val);
220         break;
221     }
222 }
223 
224 static uint32_t platform_fixed_ioport_readw(void *opaque, uint32_t addr)
225 {
226     PCIXenPlatformState *s = opaque;
227 
228     switch (addr) {
229     case 0:
230         if (s->drivers_blacklisted) {
231             /* The drivers will recognise this magic number and refuse
232              * to do anything. */
233             return 0xd249;
234         } else {
235             /* Magic value so that you can identify the interface. */
236             return 0x49d2;
237         }
238     default:
239         return 0xffff;
240     }
241 }
242 
243 static uint32_t platform_fixed_ioport_readb(void *opaque, uint32_t addr)
244 {
245     PCIXenPlatformState *s = opaque;
246 
247     switch (addr) {
248     case 0:
249         /* Platform flags */
250         return s->flags;
251     case 2:
252         /* Version number */
253         return 1;
254     default:
255         return 0xff;
256     }
257 }
258 
259 static void platform_fixed_ioport_reset(void *opaque)
260 {
261     PCIXenPlatformState *s = opaque;
262 
263     platform_fixed_ioport_writeb(s, 0, 0);
264 }
265 
266 static uint64_t platform_fixed_ioport_read(void *opaque,
267                                            hwaddr addr,
268                                            unsigned size)
269 {
270     switch (size) {
271     case 1:
272         return platform_fixed_ioport_readb(opaque, addr);
273     case 2:
274         return platform_fixed_ioport_readw(opaque, addr);
275     default:
276         return -1;
277     }
278 }
279 
280 static void platform_fixed_ioport_write(void *opaque, hwaddr addr,
281 
282                                         uint64_t val, unsigned size)
283 {
284     switch (size) {
285     case 1:
286         platform_fixed_ioport_writeb(opaque, addr, val);
287         break;
288     case 2:
289         platform_fixed_ioport_writew(opaque, addr, val);
290         break;
291     case 4:
292         platform_fixed_ioport_writel(opaque, addr, val);
293         break;
294     }
295 }
296 
297 
298 static const MemoryRegionOps platform_fixed_io_ops = {
299     .read = platform_fixed_ioport_read,
300     .write = platform_fixed_ioport_write,
301     .valid = {
302         .unaligned = true,
303     },
304     .impl = {
305         .min_access_size = 1,
306         .max_access_size = 4,
307         .unaligned = true,
308     },
309     .endianness = DEVICE_LITTLE_ENDIAN,
310 };
311 
312 static void platform_fixed_ioport_init(PCIXenPlatformState* s)
313 {
314     memory_region_init_io(&s->fixed_io, OBJECT(s), &platform_fixed_io_ops, s,
315                           "xen-fixed", 16);
316     memory_region_add_subregion(get_system_io(), XEN_PLATFORM_IOPORT,
317                                 &s->fixed_io);
318 }
319 
320 /* Xen Platform PCI Device */
321 
322 static uint64_t xen_platform_ioport_readb(void *opaque, hwaddr addr,
323                                           unsigned int size)
324 {
325     if (addr == 0) {
326         return platform_fixed_ioport_readb(opaque, 0);
327     } else {
328         return ~0u;
329     }
330 }
331 
332 static void xen_platform_ioport_writeb(void *opaque, hwaddr addr,
333                                        uint64_t val, unsigned int size)
334 {
335     PCIXenPlatformState *s = opaque;
336     PCIDevice *pci_dev = PCI_DEVICE(s);
337 
338     switch (addr) {
339     case 0: /* Platform flags */
340         platform_fixed_ioport_writeb(opaque, 0, (uint32_t)val);
341         break;
342     case 4:
343         if (val == 1) {
344             /*
345              * SUSE unplug for Xenlinux
346              * xen-kmp used this since xen-3.0.4, instead the official protocol
347              * from xen-3.3+ It did an unconditional "outl(1, (ioaddr + 4));"
348              * Pre VMDP 1.7 used 4 and 8 depending on how VMDP was configured.
349              * If VMDP was to control both disk and LAN it would use 4.
350              * If it controlled just disk or just LAN, it would use 8 below.
351              */
352             pci_unplug_disks(pci_dev->bus, UNPLUG_ALL_DISKS);
353             pci_unplug_nics(pci_dev->bus);
354         }
355         break;
356     case 8:
357         switch (val) {
358         case 1:
359             pci_unplug_disks(pci_dev->bus, UNPLUG_ALL_DISKS);
360             break;
361         case 2:
362             pci_unplug_nics(pci_dev->bus);
363             break;
364         default:
365             log_writeb(s, (uint32_t)val);
366             break;
367         }
368         break;
369     default:
370         break;
371     }
372 }
373 
374 static const MemoryRegionOps xen_pci_io_ops = {
375     .read  = xen_platform_ioport_readb,
376     .write = xen_platform_ioport_writeb,
377     .impl.min_access_size = 1,
378     .impl.max_access_size = 1,
379 };
380 
381 static void platform_ioport_bar_setup(PCIXenPlatformState *d)
382 {
383     memory_region_init_io(&d->bar, OBJECT(d), &xen_pci_io_ops, d,
384                           "xen-pci", 0x100);
385 }
386 
387 static uint64_t platform_mmio_read(void *opaque, hwaddr addr,
388                                    unsigned size)
389 {
390     DPRINTF("Warning: attempted read from physical address "
391             "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
392 
393     return 0;
394 }
395 
396 static void platform_mmio_write(void *opaque, hwaddr addr,
397                                 uint64_t val, unsigned size)
398 {
399     DPRINTF("Warning: attempted write of 0x%"PRIx64" to physical "
400             "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
401             val, addr);
402 }
403 
404 static const MemoryRegionOps platform_mmio_handler = {
405     .read = &platform_mmio_read,
406     .write = &platform_mmio_write,
407     .endianness = DEVICE_NATIVE_ENDIAN,
408 };
409 
410 static void platform_mmio_setup(PCIXenPlatformState *d)
411 {
412     memory_region_init_io(&d->mmio_bar, OBJECT(d), &platform_mmio_handler, d,
413                           "xen-mmio", 0x1000000);
414 }
415 
416 static int xen_platform_post_load(void *opaque, int version_id)
417 {
418     PCIXenPlatformState *s = opaque;
419 
420     platform_fixed_ioport_writeb(s, 0, s->flags);
421 
422     return 0;
423 }
424 
425 static const VMStateDescription vmstate_xen_platform = {
426     .name = "platform",
427     .version_id = 4,
428     .minimum_version_id = 4,
429     .post_load = xen_platform_post_load,
430     .fields = (VMStateField[]) {
431         VMSTATE_PCI_DEVICE(parent_obj, PCIXenPlatformState),
432         VMSTATE_UINT8(flags, PCIXenPlatformState),
433         VMSTATE_END_OF_LIST()
434     }
435 };
436 
437 static void xen_platform_realize(PCIDevice *dev, Error **errp)
438 {
439     PCIXenPlatformState *d = XEN_PLATFORM(dev);
440     uint8_t *pci_conf;
441 
442     /* Device will crash on reset if xen is not initialized */
443     if (!xen_enabled()) {
444         error_setg(errp, "xen-platform device requires the Xen accelerator");
445         return;
446     }
447 
448     pci_conf = dev->config;
449 
450     pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
451 
452     pci_config_set_prog_interface(pci_conf, 0);
453 
454     pci_conf[PCI_INTERRUPT_PIN] = 1;
455 
456     platform_ioport_bar_setup(d);
457     pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->bar);
458 
459     /* reserve 16MB mmio address for share memory*/
460     platform_mmio_setup(d);
461     pci_register_bar(dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
462                      &d->mmio_bar);
463 
464     platform_fixed_ioport_init(d);
465 }
466 
467 static void platform_reset(DeviceState *dev)
468 {
469     PCIXenPlatformState *s = XEN_PLATFORM(dev);
470 
471     platform_fixed_ioport_reset(s);
472 }
473 
474 static void xen_platform_class_init(ObjectClass *klass, void *data)
475 {
476     DeviceClass *dc = DEVICE_CLASS(klass);
477     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
478 
479     k->realize = xen_platform_realize;
480     k->vendor_id = PCI_VENDOR_ID_XEN;
481     k->device_id = PCI_DEVICE_ID_XEN_PLATFORM;
482     k->class_id = PCI_CLASS_OTHERS << 8 | 0x80;
483     k->subsystem_vendor_id = PCI_VENDOR_ID_XEN;
484     k->subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM;
485     k->revision = 1;
486     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
487     dc->desc = "XEN platform pci device";
488     dc->reset = platform_reset;
489     dc->vmsd = &vmstate_xen_platform;
490 }
491 
492 static const TypeInfo xen_platform_info = {
493     .name          = TYPE_XEN_PLATFORM,
494     .parent        = TYPE_PCI_DEVICE,
495     .instance_size = sizeof(PCIXenPlatformState),
496     .class_init    = xen_platform_class_init,
497 };
498 
499 static void xen_platform_register_types(void)
500 {
501     type_register_static(&xen_platform_info);
502 }
503 
504 type_init(xen_platform_register_types)
505