Statistics
| Branch: | Revision:

root / hw / xen_platform.c @ 679f4f8b

History | View | Annotate | Download (10.7 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.h"
29
#include "pc.h"
30
#include "pci.h"
31
#include "irq.h"
32
#include "xen_common.h"
33
#include "net.h"
34
#include "xen_backend.h"
35
#include "rwhandler.h"
36
#include "trace.h"
37

    
38
#include <xenguest.h>
39

    
40
//#define DEBUG_PLATFORM
41

    
42
#ifdef DEBUG_PLATFORM
43
#define DPRINTF(fmt, ...) do { \
44
    fprintf(stderr, "xen_platform: " fmt, ## __VA_ARGS__); \
45
} while (0)
46
#else
47
#define DPRINTF(fmt, ...) do { } while (0)
48
#endif
49

    
50
#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
51

    
52
typedef struct PCIXenPlatformState {
53
    PCIDevice  pci_dev;
54
    uint8_t flags; /* used only for version_id == 2 */
55
    int drivers_blacklisted;
56
    uint16_t driver_product_version;
57

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

    
63
#define XEN_PLATFORM_IOPORT 0x10
64

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

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

    
83
static void unplug_nic(PCIBus *b, PCIDevice *d)
84
{
85
    if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
86
            PCI_CLASS_NETWORK_ETHERNET) {
87
        qdev_unplug(&(d->qdev));
88
    }
89
}
90

    
91
static void pci_unplug_nics(PCIBus *bus)
92
{
93
    pci_for_each_device(bus, 0, unplug_nic);
94
}
95

    
96
static void unplug_disks(PCIBus *b, PCIDevice *d)
97
{
98
    if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
99
            PCI_CLASS_STORAGE_IDE) {
100
        qdev_unplug(&(d->qdev));
101
    }
102
}
103

    
104
static void pci_unplug_disks(PCIBus *bus)
105
{
106
    pci_for_each_device(bus, 0, unplug_disks);
107
}
108

    
109
static void platform_fixed_ioport_writew(void *opaque, uint32_t addr, uint32_t val)
110
{
111
    PCIXenPlatformState *s = opaque;
112

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

    
149
static void platform_fixed_ioport_writel(void *opaque, uint32_t addr,
150
                                         uint32_t val)
151
{
152
    switch (addr - XEN_PLATFORM_IOPORT) {
153
    case 0:
154
        /* PV driver version */
155
        break;
156
    }
157
}
158

    
159
static void platform_fixed_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
160
{
161
    PCIXenPlatformState *s = opaque;
162

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

    
182
static uint32_t platform_fixed_ioport_readw(void *opaque, uint32_t addr)
183
{
184
    PCIXenPlatformState *s = opaque;
185

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

    
201
static uint32_t platform_fixed_ioport_readb(void *opaque, uint32_t addr)
202
{
203
    PCIXenPlatformState *s = opaque;
204

    
205
    switch (addr - XEN_PLATFORM_IOPORT) {
206
    case 0:
207
        /* Platform flags */
208
        return s->flags;
209
    case 2:
210
        /* Version number */
211
        return 1;
212
    default:
213
        return 0xff;
214
    }
215
}
216

    
217
static void platform_fixed_ioport_reset(void *opaque)
218
{
219
    PCIXenPlatformState *s = opaque;
220

    
221
    platform_fixed_ioport_writeb(s, XEN_PLATFORM_IOPORT, 0);
222
}
223

    
224
static void platform_fixed_ioport_init(PCIXenPlatformState* s)
225
{
226
    register_ioport_write(XEN_PLATFORM_IOPORT, 16, 4, platform_fixed_ioport_writel, s);
227
    register_ioport_write(XEN_PLATFORM_IOPORT, 16, 2, platform_fixed_ioport_writew, s);
228
    register_ioport_write(XEN_PLATFORM_IOPORT, 16, 1, platform_fixed_ioport_writeb, s);
229
    register_ioport_read(XEN_PLATFORM_IOPORT, 16, 2, platform_fixed_ioport_readw, s);
230
    register_ioport_read(XEN_PLATFORM_IOPORT, 16, 1, platform_fixed_ioport_readb, s);
231
}
232

    
233
/* Xen Platform PCI Device */
234

    
235
static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr)
236
{
237
    addr &= 0xff;
238

    
239
    if (addr == 0) {
240
        return platform_fixed_ioport_readb(opaque, XEN_PLATFORM_IOPORT);
241
    } else {
242
        return ~0u;
243
    }
244
}
245

    
246
static void xen_platform_ioport_writeb(void *opaque, uint32_t addr, uint32_t val)
247
{
248
    PCIXenPlatformState *s = opaque;
249

    
250
    addr &= 0xff;
251
    val  &= 0xff;
252

    
253
    switch (addr) {
254
    case 0: /* Platform flags */
255
        platform_fixed_ioport_writeb(opaque, XEN_PLATFORM_IOPORT, val);
256
        break;
257
    case 8:
258
        log_writeb(s, val);
259
        break;
260
    default:
261
        break;
262
    }
263
}
264

    
265
static void platform_ioport_map(PCIDevice *pci_dev, int region_num, pcibus_t addr, pcibus_t size, int type)
266
{
267
    PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, pci_dev);
268

    
269
    register_ioport_write(addr, size, 1, xen_platform_ioport_writeb, d);
270
    register_ioport_read(addr, size, 1, xen_platform_ioport_readb, d);
271
}
272

    
273
static uint32_t platform_mmio_read(ReadWriteHandler *handler, pcibus_t addr, int len)
274
{
275
    DPRINTF("Warning: attempted read from physical address "
276
            "0x" TARGET_FMT_plx " in xen platform mmio space\n", addr);
277

    
278
    return 0;
279
}
280

    
281
static void platform_mmio_write(ReadWriteHandler *handler, pcibus_t addr,
282
                                uint32_t val, int len)
283
{
284
    DPRINTF("Warning: attempted write of 0x%x to physical "
285
            "address 0x" TARGET_FMT_plx " in xen platform mmio space\n",
286
            val, addr);
287
}
288

    
289
static ReadWriteHandler platform_mmio_handler = {
290
    .read = &platform_mmio_read,
291
    .write = &platform_mmio_write,
292
};
293

    
294
static void platform_mmio_map(PCIDevice *d, int region_num,
295
                              pcibus_t addr, pcibus_t size, int type)
296
{
297
    int mmio_io_addr;
298

    
299
    mmio_io_addr = cpu_register_io_memory_simple(&platform_mmio_handler,
300
                                                 DEVICE_NATIVE_ENDIAN);
301

    
302
    cpu_register_physical_memory(addr, size, mmio_io_addr);
303
}
304

    
305
static int xen_platform_post_load(void *opaque, int version_id)
306
{
307
    PCIXenPlatformState *s = opaque;
308

    
309
    platform_fixed_ioport_writeb(s, XEN_PLATFORM_IOPORT, s->flags);
310

    
311
    return 0;
312
}
313

    
314
static const VMStateDescription vmstate_xen_platform = {
315
    .name = "platform",
316
    .version_id = 4,
317
    .minimum_version_id = 4,
318
    .minimum_version_id_old = 4,
319
    .post_load = xen_platform_post_load,
320
    .fields = (VMStateField []) {
321
        VMSTATE_PCI_DEVICE(pci_dev, PCIXenPlatformState),
322
        VMSTATE_UINT8(flags, PCIXenPlatformState),
323
        VMSTATE_END_OF_LIST()
324
    }
325
};
326

    
327
static int xen_platform_initfn(PCIDevice *dev)
328
{
329
    PCIXenPlatformState *d = DO_UPCAST(PCIXenPlatformState, pci_dev, dev);
330
    uint8_t *pci_conf;
331

    
332
    pci_conf = d->pci_dev.config;
333

    
334
    pci_set_word(pci_conf + PCI_COMMAND, PCI_COMMAND_IO | PCI_COMMAND_MEMORY);
335

    
336
    pci_config_set_prog_interface(pci_conf, 0);
337

    
338
    pci_conf[PCI_INTERRUPT_PIN] = 1;
339

    
340
    pci_register_bar(&d->pci_dev, 0, 0x100,
341
            PCI_BASE_ADDRESS_SPACE_IO, platform_ioport_map);
342

    
343
    /* reserve 16MB mmio address for share memory*/
344
    pci_register_bar(&d->pci_dev, 1, 0x1000000,
345
            PCI_BASE_ADDRESS_MEM_PREFETCH, platform_mmio_map);
346

    
347
    platform_fixed_ioport_init(d);
348

    
349
    return 0;
350
}
351

    
352
static void platform_reset(DeviceState *dev)
353
{
354
    PCIXenPlatformState *s = DO_UPCAST(PCIXenPlatformState, pci_dev.qdev, dev);
355

    
356
    platform_fixed_ioport_reset(s);
357
}
358

    
359
static PCIDeviceInfo xen_platform_info = {
360
    .init = xen_platform_initfn,
361
    .qdev.name = "xen-platform",
362
    .qdev.desc = "XEN platform pci device",
363
    .qdev.size = sizeof(PCIXenPlatformState),
364
    .qdev.vmsd = &vmstate_xen_platform,
365
    .qdev.reset = platform_reset,
366

    
367
    .vendor_id    =  PCI_VENDOR_ID_XEN,
368
    .device_id    = PCI_DEVICE_ID_XEN_PLATFORM,
369
    .class_id     = PCI_CLASS_OTHERS << 8 | 0x80,
370
    .subsystem_vendor_id = PCI_VENDOR_ID_XEN,
371
    .subsystem_id = PCI_DEVICE_ID_XEN_PLATFORM,
372
    .revision = 1,
373
};
374

    
375
static void xen_platform_register(void)
376
{
377
    pci_qdev_register(&xen_platform_info);
378
}
379

    
380
device_init(xen_platform_register);