101195b73SSteven Smith /*
201195b73SSteven Smith * XEN platform pci device, formerly known as the event channel device
301195b73SSteven Smith *
401195b73SSteven Smith * Copyright (c) 2003-2004 Intel Corp.
501195b73SSteven Smith * Copyright (c) 2006 XenSource
601195b73SSteven Smith *
701195b73SSteven Smith * Permission is hereby granted, free of charge, to any person obtaining a copy
801195b73SSteven Smith * of this software and associated documentation files (the "Software"), to deal
901195b73SSteven Smith * in the Software without restriction, including without limitation the rights
1001195b73SSteven Smith * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
1101195b73SSteven Smith * copies of the Software, and to permit persons to whom the Software is
1201195b73SSteven Smith * furnished to do so, subject to the following conditions:
1301195b73SSteven Smith *
1401195b73SSteven Smith * The above copyright notice and this permission notice shall be included in
1501195b73SSteven Smith * all copies or substantial portions of the Software.
1601195b73SSteven Smith *
1701195b73SSteven Smith * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1801195b73SSteven Smith * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1901195b73SSteven Smith * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
2001195b73SSteven Smith * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2101195b73SSteven Smith * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2201195b73SSteven Smith * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
2301195b73SSteven Smith * THE SOFTWARE.
2401195b73SSteven Smith */
2501195b73SSteven Smith
26b6a0aa05SPeter Maydell #include "qemu/osdep.h"
27da34e65cSMarkus Armbruster #include "qapi/error.h"
286a8a8b62SBernhard Beschow #include "hw/ide/pci.h"
2983c9f4caSPaolo Bonzini #include "hw/pci/pci.h"
30d6454270SMarkus Armbruster #include "migration/vmstate.h"
31bb346faeSJoao Martins #include "net/net.h"
3201195b73SSteven Smith #include "trace.h"
3332cad1ffSPhilippe Mathieu-Daudé #include "system/xen.h"
3432cad1ffSPhilippe Mathieu-Daudé #include "system/block-backend.h"
35b1ecd51bSEduardo Habkost #include "qemu/error-report.h"
360b8fa32fSMarkus Armbruster #include "qemu/module.h"
37db1015e9SEduardo Habkost #include "qom/object.h"
3801195b73SSteven Smith
39bb346faeSJoao Martins #ifdef CONFIG_XEN
40e2abfe5eSDavid Woodhouse #include "hw/xen/xen_native.h"
41bb346faeSJoao Martins #endif
42bb346faeSJoao Martins
43e2abfe5eSDavid Woodhouse /* The rule is that xen_native.h must come first */
44e2abfe5eSDavid Woodhouse #include "hw/xen/xen.h"
45e2abfe5eSDavid Woodhouse
4601195b73SSteven Smith //#define DEBUG_PLATFORM
4701195b73SSteven Smith
4801195b73SSteven Smith #ifdef DEBUG_PLATFORM
4901195b73SSteven Smith #define DPRINTF(fmt, ...) do { \
5001195b73SSteven Smith fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
5101195b73SSteven Smith } while (0)
5201195b73SSteven Smith #else
5301195b73SSteven Smith #define DPRINTF(fmt, ...) do { } while (0)
5401195b73SSteven Smith #endif
5501195b73SSteven Smith
5601195b73SSteven Smith #define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
5701195b73SSteven Smith
58db1015e9SEduardo Habkost struct PCIXenPlatformState {
59dc4aa51bSAndreas Färber /*< private >*/
60dc4aa51bSAndreas Färber PCIDevice parent_obj;
61dc4aa51bSAndreas Färber /*< public >*/
62dc4aa51bSAndreas Färber
63de00982eSAvi Kivity MemoryRegion fixed_io;
64de00982eSAvi Kivity MemoryRegion bar;
65de00982eSAvi Kivity MemoryRegion mmio_bar;
6601195b73SSteven Smith uint8_t flags; /* used only for version_id == 2 */
6701195b73SSteven Smith uint16_t driver_product_version;
6801195b73SSteven Smith
6901195b73SSteven Smith /* Log from guest drivers */
7001195b73SSteven Smith char log_buffer[4096];
7101195b73SSteven Smith int log_buffer_off;
72db1015e9SEduardo Habkost };
7301195b73SSteven Smith
7451a3fe99SPeter Crosthwaite #define TYPE_XEN_PLATFORM "xen-platform"
OBJECT_DECLARE_SIMPLE_TYPE(PCIXenPlatformState,XEN_PLATFORM)758063396bSEduardo Habkost OBJECT_DECLARE_SIMPLE_TYPE(PCIXenPlatformState, XEN_PLATFORM)
7651a3fe99SPeter Crosthwaite
7701195b73SSteven Smith #define XEN_PLATFORM_IOPORT 0x10
7801195b73SSteven Smith
7901195b73SSteven Smith /* Send bytes to syslog */
8001195b73SSteven Smith static void log_writeb(PCIXenPlatformState *s, char val)
8101195b73SSteven Smith {
8201195b73SSteven Smith if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
8301195b73SSteven Smith /* Flush buffer */
8401195b73SSteven Smith s->log_buffer[s->log_buffer_off] = 0;
8501195b73SSteven Smith trace_xen_platform_log(s->log_buffer);
8601195b73SSteven Smith s->log_buffer_off = 0;
8701195b73SSteven Smith } else {
8801195b73SSteven Smith s->log_buffer[s->log_buffer_off++] = val;
8901195b73SSteven Smith }
9001195b73SSteven Smith }
9101195b73SSteven Smith
9204d6da4fSStefano Stabellini /*
9304d6da4fSStefano Stabellini * Unplug device flags.
9404d6da4fSStefano Stabellini *
9504d6da4fSStefano Stabellini * The logic got a little confused at some point in the past but this is
9604d6da4fSStefano Stabellini * what they do now.
9704d6da4fSStefano Stabellini *
9804d6da4fSStefano Stabellini * bit 0: Unplug all IDE and SCSI disks.
9904d6da4fSStefano Stabellini * bit 1: Unplug all NICs.
10004d6da4fSStefano Stabellini * bit 2: Unplug IDE disks except primary master. This is overridden if
10104d6da4fSStefano Stabellini * bit 0 is also present in the mask.
10204d6da4fSStefano Stabellini * bit 3: Unplug all NVMe disks.
10304d6da4fSStefano Stabellini *
10404d6da4fSStefano Stabellini */
10504d6da4fSStefano Stabellini #define _UNPLUG_IDE_SCSI_DISKS 0
10604d6da4fSStefano Stabellini #define UNPLUG_IDE_SCSI_DISKS (1u << _UNPLUG_IDE_SCSI_DISKS)
10704d6da4fSStefano Stabellini
10804d6da4fSStefano Stabellini #define _UNPLUG_ALL_NICS 1
10904d6da4fSStefano Stabellini #define UNPLUG_ALL_NICS (1u << _UNPLUG_ALL_NICS)
11004d6da4fSStefano Stabellini
11104d6da4fSStefano Stabellini #define _UNPLUG_AUX_IDE_DISKS 2
11204d6da4fSStefano Stabellini #define UNPLUG_AUX_IDE_DISKS (1u << _UNPLUG_AUX_IDE_DISKS)
11304d6da4fSStefano Stabellini
11404d6da4fSStefano Stabellini #define _UNPLUG_NVME_DISKS 3
11504d6da4fSStefano Stabellini #define UNPLUG_NVME_DISKS (1u << _UNPLUG_NVME_DISKS)
116679f4f8bSStefano Stabellini
pci_device_is_passthrough(PCIDevice * d)1173bb1ebacSJoao Martins static bool pci_device_is_passthrough(PCIDevice *d)
1183bb1ebacSJoao Martins {
1193bb1ebacSJoao Martins if (!strcmp(d->name, "xen-pci-passthrough")) {
1203bb1ebacSJoao Martins return true;
1213bb1ebacSJoao Martins }
1223bb1ebacSJoao Martins
1233bb1ebacSJoao Martins if (xen_mode == XEN_EMULATE && !strcmp(d->name, "vfio-pci")) {
1243bb1ebacSJoao Martins return true;
1253bb1ebacSJoao Martins }
1263bb1ebacSJoao Martins
1273bb1ebacSJoao Martins return false;
1283bb1ebacSJoao Martins }
1293bb1ebacSJoao Martins
unplug_nic(PCIBus * b,PCIDevice * d,void * o)1307aa8cbb9SAnthony PERARD static void unplug_nic(PCIBus *b, PCIDevice *d, void *o)
131679f4f8bSStefano Stabellini {
132bd4982a6SAnthony PERARD /* We have to ignore passthrough devices */
133679f4f8bSStefano Stabellini if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
134bd4982a6SAnthony PERARD PCI_CLASS_NETWORK_ETHERNET
1353bb1ebacSJoao Martins && !pci_device_is_passthrough(d)) {
13602a5c4c9SStefan Hajnoczi object_unparent(OBJECT(d));
137679f4f8bSStefano Stabellini }
138679f4f8bSStefano Stabellini }
139679f4f8bSStefano Stabellini
1406c808651SRoss Lagerwall /* Remove the peer of the NIC device. Normally, this would be a tap device. */
del_nic_peer(NICState * nic,void * opaque)1416c808651SRoss Lagerwall static void del_nic_peer(NICState *nic, void *opaque)
1426c808651SRoss Lagerwall {
14325511f3eSDavid Woodhouse NetClientState *nc = qemu_get_queue(nic);
14425511f3eSDavid Woodhouse ObjectClass *klass = module_object_class_by_name(nc->model);
1456c808651SRoss Lagerwall
14625511f3eSDavid Woodhouse /* Only delete peers of PCI NICs that we're about to delete */
14725511f3eSDavid Woodhouse if (!klass || !object_class_dynamic_cast(klass, TYPE_PCI_DEVICE)) {
14825511f3eSDavid Woodhouse return;
14925511f3eSDavid Woodhouse }
15025511f3eSDavid Woodhouse
1516c808651SRoss Lagerwall if (nc->peer)
1526c808651SRoss Lagerwall qemu_del_net_client(nc->peer);
1536c808651SRoss Lagerwall }
1546c808651SRoss Lagerwall
pci_unplug_nics(PCIBus * bus)155679f4f8bSStefano Stabellini static void pci_unplug_nics(PCIBus *bus)
156679f4f8bSStefano Stabellini {
1576c808651SRoss Lagerwall qemu_foreach_nic(del_nic_peer, NULL);
1587aa8cbb9SAnthony PERARD pci_for_each_device(bus, 0, unplug_nic, NULL);
159679f4f8bSStefano Stabellini }
160679f4f8bSStefano Stabellini
1616a8a8b62SBernhard Beschow /*
1626a8a8b62SBernhard Beschow * The Xen HVM unplug protocol [1] specifies a mechanism to allow guests to
1636a8a8b62SBernhard Beschow * request unplug of 'aux' disks (which is stated to mean all IDE disks,
1646a8a8b62SBernhard Beschow * except the primary master).
1656a8a8b62SBernhard Beschow *
1666a8a8b62SBernhard Beschow * NOTE: The semantics of what happens if unplug of all disks and 'aux' disks
1676a8a8b62SBernhard Beschow * is simultaneously requested is not clear. The implementation assumes
1686a8a8b62SBernhard Beschow * that an 'all' request overrides an 'aux' request.
1696a8a8b62SBernhard Beschow *
1706a8a8b62SBernhard Beschow * [1] https://xenbits.xen.org/gitweb/?p=xen.git;a=blob;f=docs/misc/hvm-emulated-unplug.pandoc
1716a8a8b62SBernhard Beschow */
172a7304995SDavid Woodhouse struct ide_unplug_state {
173a7304995SDavid Woodhouse bool aux;
174a7304995SDavid Woodhouse int nr_unplugged;
175a7304995SDavid Woodhouse };
176a7304995SDavid Woodhouse
ide_dev_unplug(DeviceState * dev,void * _st)177a7304995SDavid Woodhouse static int ide_dev_unplug(DeviceState *dev, void *_st)
1786a8a8b62SBernhard Beschow {
179a7304995SDavid Woodhouse struct ide_unplug_state *st = _st;
1806a8a8b62SBernhard Beschow IDEDevice *idedev;
1816a8a8b62SBernhard Beschow IDEBus *idebus;
1826a8a8b62SBernhard Beschow BlockBackend *blk;
183a7304995SDavid Woodhouse int unit;
1846a8a8b62SBernhard Beschow
185a7304995SDavid Woodhouse idedev = IDE_DEVICE(object_dynamic_cast(OBJECT(dev), "ide-hd"));
186a7304995SDavid Woodhouse if (!idedev) {
187a7304995SDavid Woodhouse return 0;
1886a8a8b62SBernhard Beschow }
1896a8a8b62SBernhard Beschow
190a7304995SDavid Woodhouse idebus = IDE_BUS(qdev_get_parent_bus(dev));
191a7304995SDavid Woodhouse
192a7304995SDavid Woodhouse unit = (idedev == idebus->slave);
193a7304995SDavid Woodhouse assert(unit || idedev == idebus->master);
194a7304995SDavid Woodhouse
195a7304995SDavid Woodhouse if (st->aux && !unit && !strcmp(BUS(idebus)->name, "ide.0")) {
196a7304995SDavid Woodhouse return 0;
197a7304995SDavid Woodhouse }
198a7304995SDavid Woodhouse
199a7304995SDavid Woodhouse blk = idebus->ifs[unit].blk;
200a7304995SDavid Woodhouse if (blk) {
2016a8a8b62SBernhard Beschow blk_drain(blk);
2026a8a8b62SBernhard Beschow blk_flush(blk);
2036a8a8b62SBernhard Beschow
2046a8a8b62SBernhard Beschow blk_detach_dev(blk, DEVICE(idedev));
205a7304995SDavid Woodhouse idebus->ifs[unit].blk = NULL;
2066a8a8b62SBernhard Beschow idedev->conf.blk = NULL;
2076a8a8b62SBernhard Beschow monitor_remove_blk(blk);
2086a8a8b62SBernhard Beschow blk_unref(blk);
2096a8a8b62SBernhard Beschow }
210a7304995SDavid Woodhouse
211a7304995SDavid Woodhouse object_unparent(OBJECT(dev));
212a7304995SDavid Woodhouse st->nr_unplugged++;
213a7304995SDavid Woodhouse
214a7304995SDavid Woodhouse return 0;
2156a8a8b62SBernhard Beschow }
216a7304995SDavid Woodhouse
pci_xen_ide_unplug(PCIDevice * d,bool aux)217a7304995SDavid Woodhouse static void pci_xen_ide_unplug(PCIDevice *d, bool aux)
218a7304995SDavid Woodhouse {
219a7304995SDavid Woodhouse struct ide_unplug_state st = { aux, 0 };
220a7304995SDavid Woodhouse DeviceState *dev = DEVICE(d);
221a7304995SDavid Woodhouse
222a7304995SDavid Woodhouse qdev_walk_children(dev, NULL, NULL, ide_dev_unplug, NULL, &st);
223a7304995SDavid Woodhouse if (st.nr_unplugged) {
224856ca10fSOlaf Hering pci_device_reset(d);
2256a8a8b62SBernhard Beschow }
226a7304995SDavid Woodhouse }
2276a8a8b62SBernhard Beschow
unplug_disks(PCIBus * b,PCIDevice * d,void * opaque)228ae4d2eb2SPaul Durrant static void unplug_disks(PCIBus *b, PCIDevice *d, void *opaque)
229679f4f8bSStefano Stabellini {
230ae4d2eb2SPaul Durrant uint32_t flags = *(uint32_t *)opaque;
231ae4d2eb2SPaul Durrant bool aux = (flags & UNPLUG_AUX_IDE_DISKS) &&
23204d6da4fSStefano Stabellini !(flags & UNPLUG_IDE_SCSI_DISKS);
233ae4d2eb2SPaul Durrant
234bd4982a6SAnthony PERARD /* We have to ignore passthrough devices */
2353bb1ebacSJoao Martins if (pci_device_is_passthrough(d))
2363d89e3f7SPaul Durrant return;
2373d89e3f7SPaul Durrant
2383d89e3f7SPaul Durrant switch (pci_get_word(d->config + PCI_CLASS_DEVICE)) {
2393d89e3f7SPaul Durrant case PCI_CLASS_STORAGE_IDE:
240a7304995SDavid Woodhouse case PCI_CLASS_STORAGE_SATA:
241856ca10fSOlaf Hering pci_xen_ide_unplug(d, aux);
2423d89e3f7SPaul Durrant break;
2433d89e3f7SPaul Durrant
2443d89e3f7SPaul Durrant case PCI_CLASS_STORAGE_SCSI:
245ae4d2eb2SPaul Durrant if (!aux) {
24678f66897SOlaf Hering object_unparent(OBJECT(d));
247ae4d2eb2SPaul Durrant }
2483d89e3f7SPaul Durrant break;
2493d89e3f7SPaul Durrant
25004d6da4fSStefano Stabellini case PCI_CLASS_STORAGE_EXPRESS:
25104d6da4fSStefano Stabellini if (flags & UNPLUG_NVME_DISKS) {
25204d6da4fSStefano Stabellini object_unparent(OBJECT(d));
25304d6da4fSStefano Stabellini }
25404d6da4fSStefano Stabellini
2553d89e3f7SPaul Durrant default:
2563d89e3f7SPaul Durrant break;
257679f4f8bSStefano Stabellini }
258679f4f8bSStefano Stabellini }
259679f4f8bSStefano Stabellini
pci_unplug_disks(PCIBus * bus,uint32_t flags)260ae4d2eb2SPaul Durrant static void pci_unplug_disks(PCIBus *bus, uint32_t flags)
261679f4f8bSStefano Stabellini {
262ae4d2eb2SPaul Durrant pci_for_each_device(bus, 0, unplug_disks, &flags);
263679f4f8bSStefano Stabellini }
26401195b73SSteven Smith
platform_fixed_ioport_writew(void * opaque,uint32_t addr,uint32_t val)26501195b73SSteven Smith static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
26601195b73SSteven Smith {
26701195b73SSteven Smith PCIXenPlatformState *s = opaque;
26801195b73SSteven Smith
269e7b48c97SAnthony PERARD switch (addr) {
270dc4aa51bSAndreas Färber case 0: {
271dc4aa51bSAndreas Färber PCIDevice *pci_dev = PCI_DEVICE(s);
27204d6da4fSStefano Stabellini /* Unplug devices. See comment above flag definitions */
27304d6da4fSStefano Stabellini if (val & (UNPLUG_IDE_SCSI_DISKS | UNPLUG_AUX_IDE_DISKS |
27404d6da4fSStefano Stabellini UNPLUG_NVME_DISKS)) {
275679f4f8bSStefano Stabellini DPRINTF("unplug disks\n");
276fd56e061SDavid Gibson pci_unplug_disks(pci_get_bus(pci_dev), val);
277679f4f8bSStefano Stabellini }
278679f4f8bSStefano Stabellini if (val & UNPLUG_ALL_NICS) {
279679f4f8bSStefano Stabellini DPRINTF("unplug nics\n");
280fd56e061SDavid Gibson pci_unplug_nics(pci_get_bus(pci_dev));
281679f4f8bSStefano Stabellini }
28201195b73SSteven Smith break;
283dc4aa51bSAndreas Färber }
28401195b73SSteven Smith case 2:
28501195b73SSteven Smith switch (val) {
28601195b73SSteven Smith case 1:
28701195b73SSteven Smith DPRINTF("Citrix Windows PV drivers loaded in guest\n");
28801195b73SSteven Smith break;
28901195b73SSteven Smith case 0:
29001195b73SSteven Smith DPRINTF("Guest claimed to be running PV product 0?\n");
29101195b73SSteven Smith break;
29201195b73SSteven Smith default:
29301195b73SSteven Smith DPRINTF("Unknown PV product %d loaded in guest\n", val);
29401195b73SSteven Smith break;
29501195b73SSteven Smith }
29601195b73SSteven Smith s->driver_product_version = val;
29701195b73SSteven Smith break;
29801195b73SSteven Smith }
29901195b73SSteven Smith }
30001195b73SSteven Smith
platform_fixed_ioport_writel(void * opaque,uint32_t addr,uint32_t val)30101195b73SSteven Smith static void platform_fixed_ioport_writel(void *opaque, uint32_t addr,
30201195b73SSteven Smith uint32_t val)
30301195b73SSteven Smith {
304e7b48c97SAnthony PERARD switch (addr) {
30501195b73SSteven Smith case 0:
30601195b73SSteven Smith /* PV driver version */
30701195b73SSteven Smith break;
30801195b73SSteven Smith }
30901195b73SSteven Smith }
31001195b73SSteven Smith
platform_fixed_ioport_writeb(void * opaque,uint32_t addr,uint32_t val)31101195b73SSteven Smith static void platform_fixed_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
31201195b73SSteven Smith {
31301195b73SSteven Smith PCIXenPlatformState *s = opaque;
31401195b73SSteven Smith
315e7b48c97SAnthony PERARD switch (addr) {
316bb346faeSJoao Martins case 0: /* Platform flags */
317bb346faeSJoao Martins if (xen_mode == XEN_EMULATE) {
318bb346faeSJoao Martins /* XX: Use i440gx/q35 PAM setup to do this? */
319bb346faeSJoao Martins s->flags = val & PFFLAG_ROM_LOCK;
320bb346faeSJoao Martins #ifdef CONFIG_XEN
321bb346faeSJoao Martins } else {
32201195b73SSteven Smith hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ?
32301195b73SSteven Smith HVMMEM_ram_ro : HVMMEM_ram_rw;
324bb346faeSJoao Martins
3258f25e754SPaul Durrant if (xen_set_mem_type(xen_domid, mem_type, 0xc0, 0x40)) {
32601195b73SSteven Smith DPRINTF("unable to change ro/rw state of ROM memory area!\n");
32701195b73SSteven Smith } else {
32801195b73SSteven Smith s->flags = val & PFFLAG_ROM_LOCK;
32901195b73SSteven Smith DPRINTF("changed ro/rw state of ROM memory area. now is %s state.\n",
33001195b73SSteven Smith (mem_type == HVMMEM_ram_ro ? "ro" : "rw"));
33101195b73SSteven Smith }
332bb346faeSJoao Martins #endif
33301195b73SSteven Smith }
334bb346faeSJoao Martins break;
335bb346faeSJoao Martins
33601195b73SSteven Smith case 2:
33701195b73SSteven Smith log_writeb(s, val);
33801195b73SSteven Smith break;
33901195b73SSteven Smith }
34001195b73SSteven Smith }
34101195b73SSteven Smith
platform_fixed_ioport_readw(void * opaque,uint32_t addr)34201195b73SSteven Smith static uint32_t platform_fixed_ioport_readw(void *opaque, uint32_t addr)
34301195b73SSteven Smith {
344e7b48c97SAnthony PERARD switch (addr) {
34501195b73SSteven Smith case 0:
34601195b73SSteven Smith /* Magic value so that you can identify the interface. */
34701195b73SSteven Smith return 0x49d2;
34801195b73SSteven Smith default:
34901195b73SSteven Smith return 0xffff;
35001195b73SSteven Smith }
35101195b73SSteven Smith }
35201195b73SSteven Smith
platform_fixed_ioport_readb(void * opaque,uint32_t addr)35301195b73SSteven Smith static uint32_t platform_fixed_ioport_readb(void *opaque, uint32_t addr)
35401195b73SSteven Smith {
35501195b73SSteven Smith PCIXenPlatformState *s = opaque;
35601195b73SSteven Smith
357e7b48c97SAnthony PERARD switch (addr) {
35801195b73SSteven Smith case 0:
35901195b73SSteven Smith /* Platform flags */
36001195b73SSteven Smith return s->flags;
36101195b73SSteven Smith case 2:
36201195b73SSteven Smith /* Version number */
36301195b73SSteven Smith return 1;
36401195b73SSteven Smith default:
36501195b73SSteven Smith return 0xff;
36601195b73SSteven Smith }
36701195b73SSteven Smith }
36801195b73SSteven Smith
platform_fixed_ioport_reset(void * opaque)36901195b73SSteven Smith static void platform_fixed_ioport_reset(void *opaque)
37001195b73SSteven Smith {
37101195b73SSteven Smith PCIXenPlatformState *s = opaque;
37201195b73SSteven Smith
373e7b48c97SAnthony PERARD platform_fixed_ioport_writeb(s, 0, 0);
37401195b73SSteven Smith }
37501195b73SSteven Smith
platform_fixed_ioport_read(void * opaque,hwaddr addr,unsigned size)376626c7a17SAlexander Graf static uint64_t platform_fixed_ioport_read(void *opaque,
377626c7a17SAlexander Graf hwaddr addr,
378626c7a17SAlexander Graf unsigned size)
379626c7a17SAlexander Graf {
380626c7a17SAlexander Graf switch (size) {
381626c7a17SAlexander Graf case 1:
382626c7a17SAlexander Graf return platform_fixed_ioport_readb(opaque, addr);
383626c7a17SAlexander Graf case 2:
384626c7a17SAlexander Graf return platform_fixed_ioport_readw(opaque, addr);
385626c7a17SAlexander Graf default:
386626c7a17SAlexander Graf return -1;
387626c7a17SAlexander Graf }
388626c7a17SAlexander Graf }
389626c7a17SAlexander Graf
platform_fixed_ioport_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)390626c7a17SAlexander Graf static void platform_fixed_ioport_write(void *opaque, hwaddr addr,
391626c7a17SAlexander Graf
392626c7a17SAlexander Graf uint64_t val, unsigned size)
393626c7a17SAlexander Graf {
394626c7a17SAlexander Graf switch (size) {
395626c7a17SAlexander Graf case 1:
396626c7a17SAlexander Graf platform_fixed_ioport_writeb(opaque, addr, val);
397626c7a17SAlexander Graf break;
398626c7a17SAlexander Graf case 2:
399626c7a17SAlexander Graf platform_fixed_ioport_writew(opaque, addr, val);
400626c7a17SAlexander Graf break;
401626c7a17SAlexander Graf case 4:
402626c7a17SAlexander Graf platform_fixed_ioport_writel(opaque, addr, val);
403626c7a17SAlexander Graf break;
404626c7a17SAlexander Graf }
405626c7a17SAlexander Graf }
406626c7a17SAlexander Graf
407de00982eSAvi Kivity
408de00982eSAvi Kivity static const MemoryRegionOps platform_fixed_io_ops = {
409626c7a17SAlexander Graf .read = platform_fixed_ioport_read,
410626c7a17SAlexander Graf .write = platform_fixed_ioport_write,
411962b03fcSJan Kiszka .valid = {
412962b03fcSJan Kiszka .unaligned = true,
413962b03fcSJan Kiszka },
414626c7a17SAlexander Graf .impl = {
415626c7a17SAlexander Graf .min_access_size = 1,
416626c7a17SAlexander Graf .max_access_size = 4,
417962b03fcSJan Kiszka .unaligned = true,
418626c7a17SAlexander Graf },
419626c7a17SAlexander Graf .endianness = DEVICE_LITTLE_ENDIAN,
420de00982eSAvi Kivity };
421de00982eSAvi Kivity
platform_fixed_ioport_init(PCIXenPlatformState * s)42201195b73SSteven Smith static void platform_fixed_ioport_init(PCIXenPlatformState* s)
42301195b73SSteven Smith {
42422fc860bSPaolo Bonzini memory_region_init_io(&s->fixed_io, OBJECT(s), &platform_fixed_io_ops, s,
425de00982eSAvi Kivity "xen-fixed", 16);
426de00982eSAvi Kivity memory_region_add_subregion(get_system_io(), XEN_PLATFORM_IOPORT,
427de00982eSAvi Kivity &s->fixed_io);
42801195b73SSteven Smith }
42901195b73SSteven Smith
43001195b73SSteven Smith /* Xen Platform PCI Device */
43101195b73SSteven Smith
xen_platform_ioport_readb(void * opaque,hwaddr addr,unsigned int size)4327a652efaSHervé Poussineau static uint64_t xen_platform_ioport_readb(void *opaque, hwaddr addr,
4337a652efaSHervé Poussineau unsigned int size)
43401195b73SSteven Smith {
43501195b73SSteven Smith if (addr == 0) {
436e7b48c97SAnthony PERARD return platform_fixed_ioport_readb(opaque, 0);
43701195b73SSteven Smith } else {
43801195b73SSteven Smith return ~0u;
43901195b73SSteven Smith }
44001195b73SSteven Smith }
44101195b73SSteven Smith
xen_platform_ioport_writeb(void * opaque,hwaddr addr,uint64_t val,unsigned int size)4427a652efaSHervé Poussineau static void xen_platform_ioport_writeb(void *opaque, hwaddr addr,
4437a652efaSHervé Poussineau uint64_t val, unsigned int size)
44401195b73SSteven Smith {
44501195b73SSteven Smith PCIXenPlatformState *s = opaque;
44635132016SOlaf Hering PCIDevice *pci_dev = PCI_DEVICE(s);
44701195b73SSteven Smith
44801195b73SSteven Smith switch (addr) {
44901195b73SSteven Smith case 0: /* Platform flags */
4507a652efaSHervé Poussineau platform_fixed_ioport_writeb(opaque, 0, (uint32_t)val);
45101195b73SSteven Smith break;
45235132016SOlaf Hering case 4:
45335132016SOlaf Hering if (val == 1) {
45435132016SOlaf Hering /*
45535132016SOlaf Hering * SUSE unplug for Xenlinux
45635132016SOlaf Hering * xen-kmp used this since xen-3.0.4, instead the official protocol
45735132016SOlaf Hering * from xen-3.3+ It did an unconditional "outl(1, (ioaddr + 4));"
45835132016SOlaf Hering * Pre VMDP 1.7 used 4 and 8 depending on how VMDP was configured.
45935132016SOlaf Hering * If VMDP was to control both disk and LAN it would use 4.
46035132016SOlaf Hering * If it controlled just disk or just LAN, it would use 8 below.
46135132016SOlaf Hering */
462fd56e061SDavid Gibson pci_unplug_disks(pci_get_bus(pci_dev), UNPLUG_IDE_SCSI_DISKS);
463fd56e061SDavid Gibson pci_unplug_nics(pci_get_bus(pci_dev));
46435132016SOlaf Hering }
46535132016SOlaf Hering break;
46601195b73SSteven Smith case 8:
46735132016SOlaf Hering switch (val) {
46835132016SOlaf Hering case 1:
469fd56e061SDavid Gibson pci_unplug_disks(pci_get_bus(pci_dev), UNPLUG_IDE_SCSI_DISKS);
47035132016SOlaf Hering break;
47135132016SOlaf Hering case 2:
472fd56e061SDavid Gibson pci_unplug_nics(pci_get_bus(pci_dev));
47335132016SOlaf Hering break;
47435132016SOlaf Hering default:
4757a652efaSHervé Poussineau log_writeb(s, (uint32_t)val);
47601195b73SSteven Smith break;
47735132016SOlaf Hering }
47835132016SOlaf Hering break;
47901195b73SSteven Smith default:
48001195b73SSteven Smith break;
48101195b73SSteven Smith }
48201195b73SSteven Smith }
48301195b73SSteven Smith
484de00982eSAvi Kivity static const MemoryRegionOps xen_pci_io_ops = {
4857a652efaSHervé Poussineau .read = xen_platform_ioport_readb,
4867a652efaSHervé Poussineau .write = xen_platform_ioport_writeb,
4877a652efaSHervé Poussineau .impl.min_access_size = 1,
4887a652efaSHervé Poussineau .impl.max_access_size = 1,
489de00982eSAvi Kivity };
490de00982eSAvi Kivity
platform_ioport_bar_setup(PCIXenPlatformState * d)491de00982eSAvi Kivity static void platform_ioport_bar_setup(PCIXenPlatformState *d)
492de00982eSAvi Kivity {
49322fc860bSPaolo Bonzini memory_region_init_io(&d->bar, OBJECT(d), &xen_pci_io_ops, d,
49422fc860bSPaolo Bonzini "xen-pci", 0x100);
49501195b73SSteven Smith }
49601195b73SSteven Smith
platform_mmio_read(void * opaque,hwaddr addr,unsigned size)497a8170e5eSAvi Kivity static uint64_t platform_mmio_read(void *opaque, hwaddr addr,
498de00982eSAvi Kivity unsigned size)
49901195b73SSteven Smith {
50001195b73SSteven Smith DPRINTF("Warning: attempted read from physical address "
501883f2c59SPhilippe Mathieu-Daudé "0x" HWADDR_FMT_plx " in xen platform mmio space\n", addr);
50201195b73SSteven Smith
50301195b73SSteven Smith return 0;
50401195b73SSteven Smith }
50501195b73SSteven Smith
platform_mmio_write(void * opaque,hwaddr addr,uint64_t val,unsigned size)506a8170e5eSAvi Kivity static void platform_mmio_write(void *opaque, hwaddr addr,
507de00982eSAvi Kivity uint64_t val, unsigned size)
50801195b73SSteven Smith {
509de00982eSAvi Kivity DPRINTF("Warning: attempted write of 0x%"PRIx64" to physical "
510883f2c59SPhilippe Mathieu-Daudé "address 0x" HWADDR_FMT_plx " in xen platform mmio space\n",
51101195b73SSteven Smith val, addr);
51201195b73SSteven Smith }
51301195b73SSteven Smith
514de00982eSAvi Kivity static const MemoryRegionOps platform_mmio_handler = {
51501195b73SSteven Smith .read = &platform_mmio_read,
51601195b73SSteven Smith .write = &platform_mmio_write,
517a115ab5bSPhilippe Mathieu-Daudé .endianness = DEVICE_LITTLE_ENDIAN,
51801195b73SSteven Smith };
51901195b73SSteven Smith
platform_mmio_setup(PCIXenPlatformState * d)520de00982eSAvi Kivity static void platform_mmio_setup(PCIXenPlatformState *d)
52101195b73SSteven Smith {
52222fc860bSPaolo Bonzini memory_region_init_io(&d->mmio_bar, OBJECT(d), &platform_mmio_handler, d,
523de00982eSAvi Kivity "xen-mmio", 0x1000000);
52401195b73SSteven Smith }
52501195b73SSteven Smith
xen_platform_post_load(void * opaque,int version_id)52601195b73SSteven Smith static int xen_platform_post_load(void *opaque, int version_id)
52701195b73SSteven Smith {
52801195b73SSteven Smith PCIXenPlatformState *s = opaque;
52901195b73SSteven Smith
530e7b48c97SAnthony PERARD platform_fixed_ioport_writeb(s, 0, s->flags);
53101195b73SSteven Smith
53201195b73SSteven Smith return 0;
53301195b73SSteven Smith }
53401195b73SSteven Smith
53501195b73SSteven Smith static const VMStateDescription vmstate_xen_platform = {
53601195b73SSteven Smith .name = "platform",
53701195b73SSteven Smith .version_id = 4,
53801195b73SSteven Smith .minimum_version_id = 4,
53901195b73SSteven Smith .post_load = xen_platform_post_load,
5409231a017SRichard Henderson .fields = (const VMStateField[]) {
541dc4aa51bSAndreas Färber VMSTATE_PCI_DEVICE(parent_obj, PCIXenPlatformState),
54201195b73SSteven Smith VMSTATE_UINT8(flags, PCIXenPlatformState),
54301195b73SSteven Smith VMSTATE_END_OF_LIST()
54401195b73SSteven Smith }
54501195b73SSteven Smith };
54601195b73SSteven Smith
xen_platform_realize(PCIDevice * dev,Error ** errp)5474098d49dSStefano Stabellini static void xen_platform_realize(PCIDevice *dev, Error **errp)
54801195b73SSteven Smith {
54951a3fe99SPeter Crosthwaite PCIXenPlatformState *d = XEN_PLATFORM(dev);
55001195b73SSteven Smith uint8_t *pci_conf;
55101195b73SSteven Smith
552dbb7405dSEduardo Habkost /* Device will crash on reset if xen is not initialized */
553bb346faeSJoao Martins if (xen_mode == XEN_DISABLED) {
554bb346faeSJoao Martins error_setg(errp, "xen-platform device requires a Xen guest");
555b1ecd51bSEduardo Habkost return;
556b1ecd51bSEduardo Habkost }
557dbb7405dSEduardo Habkost
558dc4aa51bSAndreas Färber pci_conf = dev->config;
55901195b73SSteven Smith
56001195b73SSteven Smith pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
56101195b73SSteven Smith
56201195b73SSteven Smith pci_config_set_prog_interface(pci_conf, 0);
56301195b73SSteven Smith
56401195b73SSteven Smith pci_conf[PCI_INTERRUPT_PIN] = 1;
56501195b73SSteven Smith
566de00982eSAvi Kivity platform_ioport_bar_setup(d);
567dc4aa51bSAndreas Färber pci_register_bar(dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->bar);
56801195b73SSteven Smith
56901195b73SSteven Smith /* reserve 16MB mmio address for share memory*/
570de00982eSAvi Kivity platform_mmio_setup(d);
571dc4aa51bSAndreas Färber pci_register_bar(dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
572e824b2ccSAvi Kivity &d->mmio_bar);
57301195b73SSteven Smith
57401195b73SSteven Smith platform_fixed_ioport_init(d);
57501195b73SSteven Smith }
57601195b73SSteven Smith
platform_reset(DeviceState * dev)57701195b73SSteven Smith static void platform_reset(DeviceState *dev)
57801195b73SSteven Smith {
57951a3fe99SPeter Crosthwaite PCIXenPlatformState *s = XEN_PLATFORM(dev);
58001195b73SSteven Smith
58101195b73SSteven Smith platform_fixed_ioport_reset(s);
58201195b73SSteven Smith }
58301195b73SSteven Smith
xen_platform_class_init(ObjectClass * klass,const void * data)58412d1a768SPhilippe Mathieu-Daudé static void xen_platform_class_init(ObjectClass *klass, const void *data)
58540021f08SAnthony Liguori {
58639bffca2SAnthony Liguori DeviceClass *dc = DEVICE_CLASS(klass);
58740021f08SAnthony Liguori PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
5880d2b962dSMichael S. Tsirkin
5894098d49dSStefano Stabellini k->realize = xen_platform_realize;
59040021f08SAnthony Liguori k->vendor_id = PCI_VENDOR_ID_XEN;
59140021f08SAnthony Liguori k->device_id = PCI_DEVICE_ID_XEN_PLATFORM;
59240021f08SAnthony Liguori k->class_id = PCI_CLASS_OTHERS << 8 | 0x80;
59340021f08SAnthony Liguori k->subsystem_vendor_id = PCI_VENDOR_ID_XEN;
59440021f08SAnthony Liguori k->subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM;
59540021f08SAnthony Liguori k->revision = 1;
596125ee0edSMarcel Apfelbaum set_bit(DEVICE_CATEGORY_MISC, dc->categories);
59739bffca2SAnthony Liguori dc->desc = "XEN platform pci device";
598e3d08143SPeter Maydell device_class_set_legacy_reset(dc, platform_reset);
59939bffca2SAnthony Liguori dc->vmsd = &vmstate_xen_platform;
60040021f08SAnthony Liguori }
60140021f08SAnthony Liguori
6028c43a6f0SAndreas Färber static const TypeInfo xen_platform_info = {
60351a3fe99SPeter Crosthwaite .name = TYPE_XEN_PLATFORM,
60439bffca2SAnthony Liguori .parent = TYPE_PCI_DEVICE,
60539bffca2SAnthony Liguori .instance_size = sizeof(PCIXenPlatformState),
60640021f08SAnthony Liguori .class_init = xen_platform_class_init,
607*2cd09e47SPhilippe Mathieu-Daudé .interfaces = (const InterfaceInfo[]) {
608fd3b02c8SEduardo Habkost { INTERFACE_CONVENTIONAL_PCI_DEVICE },
609fd3b02c8SEduardo Habkost { },
610fd3b02c8SEduardo Habkost },
61101195b73SSteven Smith };
61201195b73SSteven Smith
xen_platform_register_types(void)61383f7d43aSAndreas Färber static void xen_platform_register_types(void)
61401195b73SSteven Smith {
61539bffca2SAnthony Liguori type_register_static(&xen_platform_info);
61601195b73SSteven Smith }
61701195b73SSteven Smith
61883f7d43aSAndreas Färber type_init(xen_platform_register_types)
619