#include <sys/ioctl.h>
#include <linux/cdrom.h>
#include <linux/fd.h>
+#include <sys/mount.h>
#endif
#ifdef __FreeBSD__
#include <signal.h>
{
BDRVRawState *s = bs->opaque;
if (s->fd >= 0) {
+#ifndef CONFIG_STUBDOM
+ /* Invalidate buffer cache for this device. */
+ ioctl(s->fd, BLKFLSBUF, 0);
+#endif
close(s->fd);
s->fd = -1;
if (s->aligned_buf != NULL)
int type; /* see IDE_TYPE_xxx */
} PCIIDEState;
+static PCIIDEState *principal_ide_controller;
#if defined(__ia64__)
#include <xen/hvm/ioreq.h>
s->media_changed = 0;
}
+/* Unplug all of the IDE hard disks, starting at index @start in the
+ table. */
+static void _ide_unplug_harddisks(int start)
+{
+ IDEState *s;
+ int i, j;
+
+ if (!principal_ide_controller) {
+ fprintf(stderr, "No principal controller?\n");
+ return;
+ }
+ for (i = start; i < 4; i++) {
+ s = principal_ide_controller->ide_if + i;
+ if (!s->bs)
+ continue; /* drive not present */
+ if (s->is_cdrom)
+ continue; /* cdrom */
+ /* Is a hard disk, unplug it. */
+ for (j = 0; j < nb_drives; j++)
+ if (drives_table[j].bdrv == s->bs)
+ drives_table[j].bdrv = NULL;
+ bdrv_close(s->bs);
+ s->bs = NULL;
+ ide_reset(s);
+ }
+}
+
+/* Unplug all hard disks except for the primary master (which will
+ almost always be the boot device). */
+void ide_unplug_aux_harddisks(void)
+{
+ _ide_unplug_harddisks(1);
+}
+
+/* Unplug all hard disks, including the boot device. */
+void ide_unplug_harddisks(void)
+{
+ _ide_unplug_harddisks(0);
+}
+
+
struct partition {
uint8_t boot_ind; /* 0x80 - active */
uint8_t head; /* starting head */
sizeof(PCIIDEState),
-1,
NULL, NULL);
+ if (principal_ide_controller)
+ abort();
+ principal_ide_controller = d;
d->type = IDE_TYPE_CMD646;
pci_conf = d->dev.config;
pci_conf[0x00] = 0x95; // CMD646
sizeof(PCIIDEState),
devfn,
NULL, NULL);
+ if (principal_ide_controller)
+ abort();
+ principal_ide_controller = d;
d->type = IDE_TYPE_PIIX3;
pci_conf = d->dev.config;
qemu_irq *pic);
void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
qemu_irq *pic);
+void ide_unplug_harddisks(void);
+void ide_unplug_aux_harddisks(void);
/* ne2000.c */
#include "console.h"
#include "net.h"
+#include "exec-all.h"
+#include "qemu-xen.h"
+
//#define DEBUG_PCI
struct PCIBus {
}
}
+void pci_unplug_netifs(void)
+{
+ PCIBus *bus;
+ PCIDevice *dev;
+ PCIIORegion *region;
+ int x;
+ int i;
+
+ /* We only support one PCI bus */
+ for (bus = first_bus; bus; bus = NULL) {
+ for (x = 0; x < 256; x++) {
+ dev = bus->devices[x];
+ if (dev &&
+ dev->config[0xa] == 0 &&
+ dev->config[0xb] == 2) {
+ /* Found a netif. Remove it from the bus. Note that
+ we don't free it here, since there could still be
+ references to it floating around. There are only
+ ever one or two structures leaked, and it's not
+ worth finding them all. */
+ bus->devices[x] = NULL;
+ for (i = 0; i < PCI_NUM_REGIONS; i++) {
+ region = &dev->io_regions[i];
+ if (region->addr == (uint32_t)-1 ||
+ region->size == 0)
+ continue;
+ fprintf(logfile, "region type %d at [%x,%x).\n",
+ region->type, region->addr,
+ region->addr+region->size);
+ if (region->type == PCI_ADDRESS_SPACE_IO) {
+ isa_unassign_ioport(region->addr, region->size);
+ } else if (region->type == PCI_ADDRESS_SPACE_MEM) {
+ unregister_iomem(region->addr);
+ }
+ }
+ }
+ }
+ }
+}
+
typedef struct {
PCIDevice dev;
PCIBus *bus;
*/
#include "hw.h"
+#include "pc.h"
#include "pci.h"
#include "irq.h"
#include "qemu-xen.h"
+#include <assert.h>
#include <xenguest.h>
+static int drivers_blacklisted;
+static uint16_t driver_product_version;
+static int throttling_disabled;
extern FILE *logfile;
+static char log_buffer[4096];
+static int log_buffer_off;
#define PFFLAG_ROM_LOCK 1 /* Sets whether ROM memory area is RW or RO */
uint64_t vga_stolen_ram;
} PCIXenPlatformState;
+/* We throttle access to dom0 syslog, to avoid DOS attacks. This is
+ modelled as a token bucket, with one token for every byte of log.
+ The bucket size is 128KB (->1024 lines of 128 bytes each) and
+ refills at 256B/s. It starts full. The guest is blocked if no
+ tokens are available when it tries to generate a log message. */
+#define BUCKET_MAX_SIZE (128*1024)
+#define BUCKET_FILL_RATE 256
+
+static void throttle(unsigned count)
+{
+ static unsigned available;
+ static struct timespec last_refil;
+ static int started;
+ static int warned;
+
+ struct timespec waiting_for, now;
+ double delay;
+ struct timespec ts;
+
+ if (throttling_disabled)
+ return;
+
+ if (!started) {
+ clock_gettime(CLOCK_MONOTONIC, &last_refil);
+ available = BUCKET_MAX_SIZE;
+ started = 1;
+ }
+
+ if (count > BUCKET_MAX_SIZE) {
+ fprintf(logfile, "tried to get %d tokens, but bucket size is %d\n",
+ BUCKET_MAX_SIZE, count);
+ exit(1);
+ }
+
+ if (available < count) {
+ /* The bucket is empty. Refil it */
+
+ /* When will it be full enough to handle this request? */
+ delay = (double)(count - available) / BUCKET_FILL_RATE;
+ waiting_for = last_refil;
+ waiting_for.tv_sec += delay;
+ waiting_for.tv_nsec += (delay - (int)delay) * 1e9;
+ if (waiting_for.tv_nsec >= 1000000000) {
+ waiting_for.tv_nsec -= 1000000000;
+ waiting_for.tv_sec++;
+ }
+
+ /* How long do we have to wait? (might be negative) */
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ ts.tv_sec = waiting_for.tv_sec - now.tv_sec;
+ ts.tv_nsec = waiting_for.tv_nsec - now.tv_nsec;
+ if (ts.tv_nsec < 0) {
+ ts.tv_sec--;
+ ts.tv_nsec += 1000000000;
+ }
+
+ /* Wait for it. */
+ if (ts.tv_sec > 0 ||
+ (ts.tv_sec == 0 && ts.tv_nsec > 0)) {
+ if (!warned) {
+ fprintf(logfile, "throttling guest access to syslog");
+ warned = 1;
+ }
+ while (nanosleep(&ts, &ts) < 0 && errno == EINTR)
+ ;
+ }
+
+ /* Refil */
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ delay = (now.tv_sec - last_refil.tv_sec) +
+ (now.tv_nsec - last_refil.tv_nsec) * 1.0e-9;
+ available += BUCKET_FILL_RATE * delay;
+ if (available > BUCKET_MAX_SIZE)
+ available = BUCKET_MAX_SIZE;
+ last_refil = now;
+ }
+
+ assert(available >= count);
+
+ available -= count;
+}
+
static uint32_t xen_platform_ioport_readb(void *opaque, uint32_t addr)
{
PCIXenPlatformState *s = opaque;
d->platform_flags = val & PFFLAG_ROM_LOCK;
break;
}
+ case 8:
+ {
+ if (val == '\n' || log_buffer_off == sizeof(log_buffer) - 1) {
+ /* Flush buffer */
+ log_buffer[log_buffer_off] = 0;
+ throttle(log_buffer_off);
+ fprintf(logfile, "%s\n", log_buffer);
+ log_buffer_off = 0;
+ break;
+ }
+ log_buffer[log_buffer_off++] = val;
+ }
+ break;
default:
break;
}
cpu_register_physical_memory(addr, 0x1000000, mmio_io_addr);
}
+#define UNPLUG_ALL_IDE_DISKS 1
+#define UNPLUG_ALL_NICS 2
+#define UNPLUG_AUX_IDE_DISKS 4
+
+static void platform_fixed_ioport_write2(void *opaque, uint32_t addr, uint32_t val)
+{
+ switch (addr - 0x10) {
+ case 0:
+ /* Unplug devices. Value is a bitmask of which devices to
+ unplug, with bit 0 the IDE devices, bit 1 the network
+ devices, and bit 2 the non-primary-master IDE devices. */
+ if (val & UNPLUG_ALL_IDE_DISKS)
+ ide_unplug_harddisks();
+ if (val & UNPLUG_ALL_NICS) {
+ pci_unplug_netifs();
+ net_tap_shutdown_all();
+ }
+ if (val & UNPLUG_AUX_IDE_DISKS) {
+ ide_unplug_aux_harddisks();
+ }
+ break;
+ case 2:
+ switch (val) {
+ case 1:
+ fprintf(logfile, "Citrix Windows PV drivers loaded in guest\n");
+ break;
+ case 0:
+ fprintf(logfile, "Guest claimed to be running PV product 0?\n");
+ break;
+ default:
+ fprintf(logfile, "Unknown PV product %d loaded in guest\n", val);
+ break;
+ }
+ driver_product_version = val;
+ break;
+ }
+}
+
+static void platform_fixed_ioport_write4(void *opaque, uint32_t addr,
+ uint32_t val)
+{
+ switch (addr - 0x10) {
+ case 0:
+ /* PV driver version */
+ if (driver_product_version == 0) {
+ fprintf(logfile,
+ "Drivers tried to set their version number (%d) before setting the product number?\n",
+ val);
+ return;
+ }
+ fprintf(logfile, "PV driver build %d\n", val);
+ if (xenstore_pv_driver_build_blacklisted(driver_product_version,
+ val)) {
+ fprintf(logfile, "Drivers are blacklisted!\n");
+ drivers_blacklisted = 1;
+ }
+ break;
+ }
+}
+
+
+static void platform_fixed_ioport_write1(void *opaque, uint32_t addr, uint32_t val)
+{
+ switch (addr - 0x10) {
+ case 2:
+ /* Send bytes to syslog */
+ if (val == '\n' || log_buffer_off == sizeof(log_buffer) - 1) {
+ /* Flush buffer */
+ log_buffer[log_buffer_off] = 0;
+ throttle(log_buffer_off);
+ fprintf(logfile, "%s\n", log_buffer);
+ log_buffer_off = 0;
+ break;
+ }
+ log_buffer[log_buffer_off++] = val;
+ break;
+ }
+}
+
+static uint32_t platform_fixed_ioport_read2(void *opaque, uint32_t addr)
+{
+ switch (addr - 0x10) {
+ case 0:
+ if (drivers_blacklisted) {
+ /* The drivers will recognise this magic number and refuse
+ * to do anything. */
+ return 0xd249;
+ } else {
+ /* Magic value so that you can identify the interface. */
+ return 0x49d2;
+ }
+ default:
+ return 0xffff;
+ }
+}
+
+static uint32_t platform_fixed_ioport_read1(void *opaque, uint32_t addr)
+{
+ switch (addr - 0x10) {
+ case 2:
+ /* Version number */
+ return 1;
+ default:
+ return 0xff;
+ }
+}
+
struct pci_config_header {
uint16_t vendor_id;
uint16_t device_id;
{
PCIXenPlatformState *d;
struct pci_config_header *pch;
+ struct stat stbuf;
printf("Register xen platform.\n");
d = (PCIXenPlatformState *)pci_register_device(
register_savevm("platform", 0, 2, xen_pci_save, xen_pci_load, d);
printf("Done register platform.\n");
+ register_ioport_write(0x10, 16, 4, platform_fixed_ioport_write4, NULL);
+ register_ioport_write(0x10, 16, 2, platform_fixed_ioport_write2, NULL);
+ register_ioport_write(0x10, 16, 1, platform_fixed_ioport_write1, NULL);
+ register_ioport_read(0x10, 16, 2, platform_fixed_ioport_read2, NULL);
+ register_ioport_read(0x10, 16, 1, platform_fixed_ioport_read1, NULL);
+
+ if (stat("/etc/disable-guest-log-throttle", &stbuf) == 0)
+ throttling_disabled = 1;
+
}
/* XXX: Simple implementation. Fix later */
#define MAX_MMIO 32
-struct mmio_space {
+static struct mmio_space {
target_phys_addr_t start;
unsigned long size;
unsigned long io_index;
return 0;
}
+void unregister_iomem(target_phys_addr_t start)
+{
+ int index = iomem_index(start);
+ if (index) {
+ fprintf(logfile, "squash iomem [%lx, %lx).\n", mmio[index].start,
+ mmio[index].start + mmio[index].size);
+ mmio[index].start = mmio[index].size = 0;
+ }
+}
+
+
#if defined(__i386__) || defined(__x86_64__)
#define phys_ram_addr(x) (qemu_map_cache(x))
#elif defined(__ia64__)
void xen_vga_vram_map(uint64_t vram_addr, int copy);
#endif
-
+void ide_unplug_harddisks(void);
+void net_tap_shutdown_all(void);
+void pci_unplug_netifs(void);
void destroy_hvm_domain(void);
+void unregister_iomem(target_phys_addr_t start);
#ifdef __ia64__
static inline void xc_domain_shutdown_hook(int xc_handle, uint32_t domid)
char *xenstore_device_model_read(int domid, char *key, unsigned int *len);
char *xenstore_read_battery_data(int battery_status);
int xenstore_refresh_battery_status(void);
+int xenstore_pv_driver_build_blacklisted(uint16_t product_number,
+ uint32_t build_nr);
/* xenfbfront.c */
int xenfb_pv_display_init(DisplayState *ds);
#include "xen-vl-extra.c"
+typedef struct IOHandlerRecord {
+ int fd;
+ IOCanRWHandler *fd_read_poll;
+ IOHandler *fd_read;
+ IOHandler *fd_write;
+ int deleted;
+ void *opaque;
+ /* temporary data */
+ struct pollfd *ufd;
+ struct IOHandlerRecord *next;
+} IOHandlerRecord;
+
+static IOHandlerRecord *first_io_handler;
+
/***********************************************************/
/* x86 ISA bus support */
typedef struct TAPState {
VLANClientState *vc;
int fd;
+ struct TAPState *next;
char down_script[1024];
char script_arg[1024];
} TAPState;
}
}
+static TAPState *head_net_tap;
+
+void net_tap_shutdown_all(void)
+{
+ struct IOHandlerRecord **pioh, *ioh;
+
+ while (head_net_tap) {
+ pioh = &first_io_handler;
+ for (;;) {
+ ioh = *pioh;
+ if (ioh == NULL)
+ break;
+ if (ioh->fd == head_net_tap->fd) {
+ *pioh = ioh->next;
+ qemu_free(ioh);
+ break;
+ }
+ pioh = &ioh->next;
+ }
+ if (!ioh)
+ fprintf(stderr,
+ "warning: can't find iohandler for %d to close it properly.\n",
+ head_net_tap->fd);
+ close(head_net_tap->fd);
+ head_net_tap = head_net_tap->next;
+ }
+}
+
/* fd support */
static TAPState *net_tap_fd_init(VLANState *vlan, int fd)
return NULL;
s->fd = fd;
s->vc = qemu_new_vlan_client(vlan, tap_receive, NULL, s);
+ s->next = head_net_tap;
+ head_net_tap = s;
qemu_set_fd_handler(s->fd, tap_send, NULL, s);
snprintf(s->vc->info_str, sizeof(s->vc->info_str), "tap: fd=%d", fd);
return s;
#define MAX_IO_HANDLERS 64
-typedef struct IOHandlerRecord {
- int fd;
- IOCanRWHandler *fd_read_poll;
- IOHandler *fd_read;
- IOHandler *fd_write;
- int deleted;
- void *opaque;
- /* temporary data */
- struct pollfd *ufd;
- struct IOHandlerRecord *next;
-} IOHandlerRecord;
-
-static IOHandlerRecord *first_io_handler;
-
/* XXX: fd_read_poll should be suppressed, but an API change is
necessary in the character devices to suppress fd_can_read(). */
int qemu_set_fd_handler2(int fd,
free(path);
}
+int
+xenstore_pv_driver_build_blacklisted(uint16_t product_nr,
+ uint32_t build_nr)
+{
+ char *buf = NULL;
+ char *tmp;
+ const char *product;
+
+ switch (product_nr) {
+ case 1:
+ product = "xensource-windows";
+ break;
+ default:
+ /* Don't know what product this is -> we can't blacklist
+ * it. */
+ return 0;
+ }
+ if (asprintf(&buf, "/mh/driver-blacklist/%s/%d", product, build_nr) < 0)
+ return 0;
+ tmp = xs_read(xsh, XBT_NULL, buf, NULL);
+ free(tmp);
+ free(buf);
+ if (tmp == NULL)
+ return 0;
+ else
+ return 1;
+}
+
void xenstore_record_dm_state(char *state)
{
xenstore_record_dm("state", state);