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