Statistics
| Branch: | Revision:

root / hw / xen_platform.c @ 0d09e41a

History | View | Annotate | Download (11.9 kB)

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

    
51
typedef struct PCIXenPlatformState {
52
    PCIDevice  pci_dev;
53
    MemoryRegion fixed_io;
54
    MemoryRegion bar;
55
    MemoryRegion mmio_bar;
56
    uint8_t flags; /* used only for version_id == 2 */
57
    int drivers_blacklisted;
58
    uint16_t driver_product_version;
59

    
60
    /* Log from guest drivers */
61
    char log_buffer[4096];
62
    int log_buffer_off;
63
} PCIXenPlatformState;
64

    
65
#define XEN_PLATFORM_IOPORT 0x10
66

    
67
/* Send bytes to syslog */
68
static void log_writeb(PCIXenPlatformState *s, char val)
69
{
70
    if (val == '\n' || s->log_buffer_off == sizeof(s->log_buffer) - 1) {
71
        /* Flush buffer */
72
        s->log_buffer[s->log_buffer_off] = 0;
73
        trace_xen_platform_log(s->log_buffer);
74
        s->log_buffer_off = 0;
75
    } else {
76
        s->log_buffer[s->log_buffer_off++] = val;
77
    }
78
}
79

    
80
/* Xen Platform, Fixed IOPort */
81
#define UNPLUG_ALL_IDE_DISKS 1
82
#define UNPLUG_ALL_NICS 2
83
#define UNPLUG_AUX_IDE_DISKS 4
84

    
85
static void unplug_nic(PCIBus *b, PCIDevice *d, void *o)
86
{
87
    /* We have to ignore passthrough devices */
88
    if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
89
            PCI_CLASS_NETWORK_ETHERNET
90
            && strcmp(d->name, "xen-pci-passthrough") != 0) {
91
        qdev_free(&d->qdev);
92
    }
93
}
94

    
95
static void pci_unplug_nics(PCIBus *bus)
96
{
97
    pci_for_each_device(bus, 0, unplug_nic, NULL);
98
}
99

    
100
static void unplug_disks(PCIBus *b, PCIDevice *d, void *o)
101
{
102
    /* We have to ignore passthrough devices */
103
    if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
104
            PCI_CLASS_STORAGE_IDE
105
            && strcmp(d->name, "xen-pci-passthrough") != 0) {
106
        qdev_unplug(&(d->qdev), NULL);
107
    }
108
}
109

    
110
static void pci_unplug_disks(PCIBus *bus)
111
{
112
    pci_for_each_device(bus, 0, unplug_disks, NULL);
113
}
114

    
115
static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
116
{
117
    PCIXenPlatformState *s = opaque;
118

    
119
    switch (addr) {
120
    case 0:
121
        /* Unplug devices.  Value is a bitmask of which devices to
122
           unplug, with bit 0 the IDE devices, bit 1 the network
123
           devices, and bit 2 the non-primary-master IDE devices. */
124
        if (val & UNPLUG_ALL_IDE_DISKS) {
125
            DPRINTF("unplug disks\n");
126
            bdrv_drain_all();
127
            bdrv_flush_all();
128
            pci_unplug_disks(s->pci_dev.bus);
129
        }
130
        if (val & UNPLUG_ALL_NICS) {
131
            DPRINTF("unplug nics\n");
132
            pci_unplug_nics(s->pci_dev.bus);
133
        }
134
        if (val & UNPLUG_AUX_IDE_DISKS) {
135
            DPRINTF("unplug auxiliary disks not supported\n");
136
        }
137
        break;
138
    case 2:
139
        switch (val) {
140
        case 1:
141
            DPRINTF("Citrix Windows PV drivers loaded in guest\n");
142
            break;
143
        case 0:
144
            DPRINTF("Guest claimed to be running PV product 0?\n");
145
            break;
146
        default:
147
            DPRINTF("Unknown PV product %d loaded in guest\n", val);
148
            break;
149
        }
150
        s->driver_product_version = val;
151
        break;
152
    }
153
}
154

    
155
static void platform_fixed_ioport_writel(void *opaque, uint32_t addr,
156
                                         uint32_t val)
157
{
158
    switch (addr) {
159
    case 0:
160
        /* PV driver version */
161
        break;
162
    }
163
}
164

    
165
static void platform_fixed_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
166
{
167
    PCIXenPlatformState *s = opaque;
168

    
169
    switch (addr) {
170
    case 0: /* Platform flags */ {
171
        hvmmem_type_t mem_type = (val & PFFLAG_ROM_LOCK) ?
172
            HVMMEM_ram_ro : HVMMEM_ram_rw;
173
        if (xc_hvm_set_mem_type(xen_xc, xen_domid, mem_type, 0xc0, 0x40)) {
174
            DPRINTF("unable to change ro/rw state of ROM memory area!\n");
175
        } else {
176
            s->flags = val & PFFLAG_ROM_LOCK;
177
            DPRINTF("changed ro/rw state of ROM memory area. now is %s state.\n",
178
                    (mem_type == HVMMEM_ram_ro ? "ro":"rw"));
179
        }
180
        break;
181
    }
182
    case 2:
183
        log_writeb(s, val);
184
        break;
185
    }
186
}
187

    
188
static uint32_t platform_fixed_ioport_readw(void *opaque, uint32_t addr)
189
{
190
    PCIXenPlatformState *s = opaque;
191

    
192
    switch (addr) {
193
    case 0:
194
        if (s->drivers_blacklisted) {
195
            /* The drivers will recognise this magic number and refuse
196
             * to do anything. */
197
            return 0xd249;
198
        } else {
199
            /* Magic value so that you can identify the interface. */
200
            return 0x49d2;
201
        }
202
    default:
203
        return 0xffff;
204
    }
205
}
206

    
207
static uint32_t platform_fixed_ioport_readb(void *opaque, uint32_t addr)
208
{
209
    PCIXenPlatformState *s = opaque;
210

    
211
    switch (addr) {
212
    case 0:
213
        /* Platform flags */
214
        return s->flags;
215
    case 2:
216
        /* Version number */
217
        return 1;
218
    default:
219
        return 0xff;
220
    }
221
}
222

    
223
static void platform_fixed_ioport_reset(void *opaque)
224
{
225
    PCIXenPlatformState *s = opaque;
226

    
227
    platform_fixed_ioport_writeb(s, 0, 0);
228
}
229

    
230
static uint64_t platform_fixed_ioport_read(void *opaque,
231
                                           hwaddr addr,
232
                                           unsigned size)
233
{
234
    switch (size) {
235
    case 1:
236
        return platform_fixed_ioport_readb(opaque, addr);
237
    case 2:
238
        return platform_fixed_ioport_readw(opaque, addr);
239
    default:
240
        return -1;
241
    }
242
}
243

    
244
static void platform_fixed_ioport_write(void *opaque, hwaddr addr,
245

    
246
                                        uint64_t val, unsigned size)
247
{
248
    switch (size) {
249
    case 1:
250
        platform_fixed_ioport_writeb(opaque, addr, val);
251
        break;
252
    case 2:
253
        platform_fixed_ioport_writew(opaque, addr, val);
254
        break;
255
    case 4:
256
        platform_fixed_ioport_writel(opaque, addr, val);
257
        break;
258
    }
259
}
260

    
261

    
262
static const MemoryRegionOps platform_fixed_io_ops = {
263
    .read = platform_fixed_ioport_read,
264
    .write = platform_fixed_ioport_write,
265
    .impl = {
266
        .min_access_size = 1,
267
        .max_access_size = 4,
268
    },
269
    .endianness = DEVICE_LITTLE_ENDIAN,
270
};
271

    
272
static void platform_fixed_ioport_init(PCIXenPlatformState* s)
273
{
274
    memory_region_init_io(&s->fixed_io, &platform_fixed_io_ops, s,
275
                          "xen-fixed", 16);
276
    memory_region_add_subregion(get_system_io(), XEN_PLATFORM_IOPORT,
277
                                &s->fixed_io);
278
}
279

    
280
/* Xen Platform PCI Device */
281

    
282
static uint64_t xen_platform_ioport_readb(void *opaque, hwaddr addr,
283
                                          unsigned int size)
284
{
285
    if (addr == 0) {
286
        return platform_fixed_ioport_readb(opaque, 0);
287
    } else {
288
        return ~0u;
289
    }
290
}
291

    
292
static void xen_platform_ioport_writeb(void *opaque, hwaddr addr,
293
                                       uint64_t val, unsigned int size)
294
{
295
    PCIXenPlatformState *s = opaque;
296

    
297
    switch (addr) {
298
    case 0: /* Platform flags */
299
        platform_fixed_ioport_writeb(opaque, 0, (uint32_t)val);
300
        break;
301
    case 8:
302
        log_writeb(s, (uint32_t)val);
303
        break;
304
    default:
305
        break;
306
    }
307
}
308

    
309
static const MemoryRegionOps xen_pci_io_ops = {
310
    .read  = xen_platform_ioport_readb,
311
    .write = xen_platform_ioport_writeb,
312
    .impl.min_access_size = 1,
313
    .impl.max_access_size = 1,
314
};
315

    
316
static void platform_ioport_bar_setup(PCIXenPlatformState *d)
317
{
318
    memory_region_init_io(&d->bar, &xen_pci_io_ops, d, "xen-pci", 0x100);
319
}
320

    
321
static uint64_t platform_mmio_read(void *opaque, hwaddr addr,
322
                                   unsigned size)
323
{
324
    DPRINTF("Warning: attempted read from physical address "
325
            "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
326

    
327
    return 0;
328
}
329

    
330
static void platform_mmio_write(void *opaque, hwaddr addr,
331
                                uint64_t val, unsigned size)
332
{
333
    DPRINTF("Warning: attempted write of 0x%"PRIx64" to physical "
334
            "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
335
            val, addr);
336
}
337

    
338
static const MemoryRegionOps platform_mmio_handler = {
339
    .read = &platform_mmio_read,
340
    .write = &platform_mmio_write,
341
    .endianness = DEVICE_NATIVE_ENDIAN,
342
};
343

    
344
static void platform_mmio_setup(PCIXenPlatformState *d)
345
{
346
    memory_region_init_io(&d->mmio_bar, &platform_mmio_handler, d,
347
                          "xen-mmio", 0x1000000);
348
}
349

    
350
static int xen_platform_post_load(void *opaque, int version_id)
351
{
352
    PCIXenPlatformState *s = opaque;
353

    
354
    platform_fixed_ioport_writeb(s, 0, s->flags);
355

    
356
    return 0;
357
}
358

    
359
static const VMStateDescription vmstate_xen_platform = {
360
    .name = "platform",
361
    .version_id = 4,
362
    .minimum_version_id = 4,
363
    .minimum_version_id_old = 4,
364
    .post_load = xen_platform_post_load,
365
    .fields = (VMStateField []) {
366
        VMSTATE_PCI_DEVICE(pci_dev, PCIXenPlatformState),
367
        VMSTATE_UINT8(flags, PCIXenPlatformState),
368
        VMSTATE_END_OF_LIST()
369
    }
370
};
371

    
372
static int xen_platform_initfn(PCIDevice *dev)
373
{
374
    PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, dev);
375
    uint8_t *pci_conf;
376

    
377
    pci_conf = d->pci_dev.config;
378

    
379
    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
380

    
381
    pci_config_set_prog_interface(pci_conf, 0);
382

    
383
    pci_conf[PCI_INTERRUPT_PIN] = 1;
384

    
385
    platform_ioport_bar_setup(d);
386
    pci_register_bar(&d->pci_dev, 0, PCI_BASE_ADDRESS_SPACE_IO, &d->bar);
387

    
388
    /* reserve 16MB mmio address for share memory*/
389
    platform_mmio_setup(d);
390
    pci_register_bar(&d->pci_dev, 1, PCI_BASE_ADDRESS_MEM_PREFETCH,
391
                     &d->mmio_bar);
392

    
393
    platform_fixed_ioport_init(d);
394

    
395
    return 0;
396
}
397

    
398
static void platform_reset(DeviceState *dev)
399
{
400
    PCIXenPlatformState *s = DO_UPCAST(PCIXenPlatformState, pci_dev.qdev, dev);
401

    
402
    platform_fixed_ioport_reset(s);
403
}
404

    
405
static void xen_platform_class_init(ObjectClass *klass, void *data)
406
{
407
    DeviceClass *dc = DEVICE_CLASS(klass);
408
    PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
409

    
410
    k->init = xen_platform_initfn;
411
    k->vendor_id = PCI_VENDOR_ID_XEN;
412
    k->device_id = PCI_DEVICE_ID_XEN_PLATFORM;
413
    k->class_id = PCI_CLASS_OTHERS << 8 | 0x80;
414
    k->subsystem_vendor_id = PCI_VENDOR_ID_XEN;
415
    k->subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM;
416
    k->revision = 1;
417
    dc->desc = "XEN platform pci device";
418
    dc->reset = platform_reset;
419
    dc->vmsd = &vmstate_xen_platform;
420
}
421

    
422
static const TypeInfo xen_platform_info = {
423
    .name          = "xen-platform",
424
    .parent        = TYPE_PCI_DEVICE,
425
    .instance_size = sizeof(PCIXenPlatformState),
426
    .class_init    = xen_platform_class_init,
427
};
428

    
429
static void xen_platform_register_types(void)
430
{
431
    type_register_static(&xen_platform_info);
432
}
433

    
434
type_init(xen_platform_register_types)