summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvi Kivity <avi@redhat.com>2009-08-29 10:36:54 +0300
committerAvi Kivity <avi@redhat.com>2009-08-29 10:36:54 +0300
commit1a20533f56f5e2c0e2f4507205bf4acb0f669a43 (patch)
tree7799aa18f7dba660def0cd5c29869816a99f2ea6
parentMerge commit 'b31a0277558db5eeb71164ad511467cf5125b853' into upstream-merge (diff)
parentAdd isa_reserve_irq(). (diff)
downloadqemu-kvm-1a20533f56f5e2c0e2f4507205bf4acb0f669a43.tar.gz
qemu-kvm-1a20533f56f5e2c0e2f4507205bf4acb0f669a43.tar.bz2
qemu-kvm-1a20533f56f5e2c0e2f4507205bf4acb0f669a43.zip
Merge commit '3a38d437ca60ce19ee92dbabbe6e672e9ba3c529' into upstream-merge
* commit '3a38d437ca60ce19ee92dbabbe6e672e9ba3c529': Add isa_reserve_irq(). isa bus irq changes and fixes. hw/eepro100.c: Use extended TBD only where applicable pci-hotplug: initialize dinfo to NULL in pci_device_hot_add block/vdi.c: Fix several bugs introduce kvm64 CPU allow overriding of CPUID level on command line set CPUID bits to present cores and threads topology push CPUID level to 4 to allow Intel multicore decoding extend -smp parsing to include cores= and threads= options add file descriptor migration Add sparse to new feature convention Conflicts: hw/pc.c Signed-off-by: Avi Kivity <avi@redhat.com>
-rw-r--r--Makefile2
-rw-r--r--Makefile.target4
-rw-r--r--block/vdi.c13
-rwxr-xr-xconfigure19
-rw-r--r--cpu-defs.h2
-rw-r--r--hw/cs4231a.c12
-rw-r--r--hw/eepro100.c6
-rw-r--r--hw/fdc.c47
-rw-r--r--hw/fdc.h9
-rw-r--r--hw/hw.h1
-rw-r--r--hw/ide.c7
-rw-r--r--hw/isa-bus.c91
-rw-r--r--hw/isa.h5
-rw-r--r--hw/mips_jazz.c2
-rw-r--r--hw/mips_malta.c2
-rw-r--r--hw/pc.c34
-rw-r--r--hw/pci-hotplug.c2
-rw-r--r--hw/ppc_prep.c2
-rw-r--r--hw/sb16.c25
-rw-r--r--hw/sun4u.c2
-rw-r--r--migration-fd.c137
-rw-r--r--migration.c4
-rw-r--r--migration.h7
-rw-r--r--savevm.c28
-rw-r--r--target-i386/helper.c97
-rw-r--r--vl.c66
26 files changed, 516 insertions, 110 deletions
diff --git a/Makefile b/Makefile
index bc736e6ff..81781690b 100644
--- a/Makefile
+++ b/Makefile
@@ -110,7 +110,7 @@ obj-y += qdev.o qdev-properties.o ssi.o
obj-$(CONFIG_BRLAPI) += baum.o
obj-$(CONFIG_WIN32) += tap-win32.o
-obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o
+obj-$(CONFIG_POSIX) += migration-exec.o migration-unix.o migration-fd.o
audio/audio.o audio/fmodaudio.o: QEMU_CFLAGS += $(FMOD_CFLAGS)
diff --git a/Makefile.target b/Makefile.target
index 0c20ca2d9..80932eb8f 100644
--- a/Makefile.target
+++ b/Makefile.target
@@ -303,7 +303,7 @@ obj-arm-y += arm-semi.o
obj-arm-y += pxa2xx.o pxa2xx_pic.o pxa2xx_gpio.o pxa2xx_timer.o pxa2xx_dma.o
obj-arm-y += pxa2xx_lcd.o pxa2xx_mmci.o pxa2xx_pcmcia.o pxa2xx_keypad.o
obj-arm-y += pflash_cfi01.o gumstix.o
-obj-arm-y += zaurus.o ide.o serial.o spitz.o tosa.o tc6393xb.o
+obj-arm-y += zaurus.o ide.o isa-bus.o serial.o spitz.o tosa.o tc6393xb.o
obj-arm-y += omap1.o omap_lcdc.o omap_dma.o omap_clk.o omap_mmc.o omap_i2c.o
obj-arm-y += omap2.o omap_dss.o soc_dma.o
obj-arm-y += omap_sx1.o palm.o tsc210x.o
@@ -317,7 +317,7 @@ obj-arm-y += syborg_virtio.o
obj-sh4-y = shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
obj-sh4-y += sh_timer.o sh_serial.o sh_intc.o sh_pci.o sm501.o serial.o
-obj-sh4-y += ide.o
+obj-sh4-y += ide.o isa-bus.o
obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
obj-m68k-y += m68k-semi.o dummy_m68k.o
diff --git a/block/vdi.c b/block/vdi.c
index 4ca8dcb7d..c9c8890f5 100644
--- a/block/vdi.c
+++ b/block/vdi.c
@@ -437,9 +437,9 @@ static int vdi_open(BlockDriverState *bs, const char *filename, int flags)
s->header = header;
bmap_size = header.blocks_in_image * sizeof(uint32_t);
- s->bmap = qemu_malloc(bmap_size);
- if (bdrv_read(s->hd, s->bmap_sector,
- (uint8_t *)s->bmap, bmap_size / SECTOR_SIZE) < 0) {
+ bmap_size = (bmap_size + SECTOR_SIZE - 1) / SECTOR_SIZE;
+ s->bmap = qemu_malloc(bmap_size * SECTOR_SIZE);
+ if (bdrv_read(s->hd, s->bmap_sector, (uint8_t *)s->bmap, bmap_size) < 0) {
goto fail_free_bmap;
}
@@ -817,7 +817,9 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
#endif
#if defined(CONFIG_VDI_STATIC_IMAGE)
} else if (!strcmp(options->name, BLOCK_OPT_STATIC)) {
- image_type = VDI_TYPE_STATIC;
+ if (options->value.n) {
+ image_type = VDI_TYPE_STATIC;
+ }
#endif
}
options++;
@@ -845,6 +847,9 @@ static int vdi_create(const char *filename, QEMUOptionParameter *options)
header.disk_size = bytes;
header.block_size = block_size;
header.blocks_in_image = blocks;
+ if (image_type == VDI_TYPE_STATIC) {
+ header.blocks_allocated = blocks;
+ }
uuid_generate(header.uuid_image);
uuid_generate(header.uuid_last_snap);
/* There is no need to set header.uuid_link or header.uuid_parent here. */
diff --git a/configure b/configure
index 7d30ee5a4..21607dab2 100755
--- a/configure
+++ b/configure
@@ -196,6 +196,7 @@ fdt=""
kvm=""
nptl=""
sdl=""
+sparse="no"
vde=""
vnc_tls=""
vnc_sasl=""
@@ -204,7 +205,6 @@ xen=""
gprof="no"
debug_tcg="no"
debug="no"
-sparse="no"
strip_opt="yes"
bigendian="no"
mingw32="no"
@@ -719,10 +719,6 @@ echo "NOTE: The object files are built at the place where configure is launched"
exit 1
fi
-if test ! -x "$(which cgcc 2>/dev/null)"; then
- sparse="no"
-fi
-
#
# Solaris specific configure tool chain decisions
#
@@ -1000,6 +996,19 @@ EOF
fi
##########################################
+# Sparse probe
+if test "$sparse" != "no" ; then
+ if test -x "$(which cgcc 2>/dev/null)"; then
+ sparse=yes
+ else
+ if test "$sparse" = "yes" ; then
+ feature_not_found "sparse"
+ fi
+ sparse=no
+ fi
+fi
+
+##########################################
# SDL probe
sdl_too_old=no
diff --git a/cpu-defs.h b/cpu-defs.h
index 1cd9a1504..a7d6d94e4 100644
--- a/cpu-defs.h
+++ b/cpu-defs.h
@@ -194,6 +194,8 @@ struct KVMCPUState {
int cpu_index; /* CPU index (informative) */ \
uint32_t host_tid; /* host thread ID */ \
int numa_node; /* NUMA node this cpu is belonging to */ \
+ int nr_cores; /* number of cores within this CPU package */ \
+ int nr_threads;/* number of threads within this CPU */ \
int running; /* Nonzero if cpu is currently running(usermode). */ \
int thread_id; \
/* user data */ \
diff --git a/hw/cs4231a.c b/hw/cs4231a.c
index 5516867ab..d482e04ac 100644
--- a/hw/cs4231a.c
+++ b/hw/cs4231a.c
@@ -60,10 +60,9 @@ static struct {
typedef struct CSState {
QEMUSoundCard card;
- qemu_irq *pic;
+ qemu_irq pic;
uint32_t regs[CS_REGS];
uint8_t dregs[CS_DREGS];
- int irq;
int dma;
int port;
int shift;
@@ -483,7 +482,7 @@ IO_WRITE_PROTO (cs_write)
case Alternate_Feature_Status:
if ((s->dregs[iaddr] & PI) && !(val & PI)) {
/* XXX: TI CI */
- qemu_irq_lower (s->pic[s->irq]);
+ qemu_irq_lower (s->pic);
s->regs[Status] &= ~INT;
}
s->dregs[iaddr] = val;
@@ -503,7 +502,7 @@ IO_WRITE_PROTO (cs_write)
case Status:
if (s->regs[Status] & INT) {
- qemu_irq_lower (s->pic[s->irq]);
+ qemu_irq_lower (s->pic);
}
s->regs[Status] &= ~INT;
s->dregs[Alternate_Feature_Status] &= ~(PI | CI | TI);
@@ -588,7 +587,7 @@ static int cs_dma_read (void *opaque, int nchan, int dma_pos, int dma_len)
s->regs[Status] |= INT;
s->dregs[Alternate_Feature_Status] |= PI;
s->transferred = 0;
- qemu_irq_raise (s->pic[s->irq]);
+ qemu_irq_raise (s->pic);
}
else {
s->transferred += written;
@@ -643,8 +642,7 @@ int cs4231a_init (qemu_irq *pic)
s = qemu_mallocz (sizeof (*s));
- s->pic = pic;
- s->irq = conf.irq;
+ s->pic = isa_reserve_irq(conf.irq);
s->dma = conf.dma;
s->port = conf.port;
diff --git a/hw/eepro100.c b/hw/eepro100.c
index 8988b3f94..199026443 100644
--- a/hw/eepro100.c
+++ b/hw/eepro100.c
@@ -715,8 +715,8 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
} else {
/* Flexible mode. */
uint8_t tbd_count = 0;
- if (!(s->configuration[6] & BIT(4))) {
- /* Extended TCB. */
+ if ((s->device >= i82558B) && !(s->configuration[6] & BIT(4))) {
+ /* Extended Flexible TCB. */
assert(tcb_bytes == 0);
for (; tbd_count < 2; tbd_count++) {
uint32_t tx_buffer_address = ldl_phys(tbd_address);
@@ -724,7 +724,7 @@ static void eepro100_cu_command(EEPRO100State * s, uint8_t val)
uint16_t tx_buffer_el = lduw_phys(tbd_address + 6);
tbd_address += 8;
logout
- ("TBD (extended mode): buffer address 0x%08x, size 0x%04x\n",
+ ("TBD (extended flexible mode): buffer address 0x%08x, size 0x%04x\n",
tx_buffer_address, tx_buffer_size);
cpu_physical_memory_read(tx_buffer_address, &buf[size],
tx_buffer_size);
diff --git a/hw/fdc.c b/hw/fdc.c
index dabbf3a01..0ece6db23 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -1871,33 +1871,42 @@ static void fdctrl_connect_drives(fdctrl_t *fdctrl, BlockDriverState **fds)
}
}
-fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped,
- target_phys_addr_t io_base,
- BlockDriverState **fds)
+fdctrl_t *fdctrl_init_isa(int isairq, int dma_chann,
+ uint32_t io_base,
+ BlockDriverState **fds)
{
fdctrl_t *fdctrl;
+ ISADevice *dev;
- if (mem_mapped) {
- DeviceState *dev;
- fdctrl_sysbus_t *sys;
+ dev = isa_create_simple("isa-fdc", io_base, 0);
+ fdctrl = &(DO_UPCAST(fdctrl_isabus_t, busdev, dev)->state);
+ isa_connect_irq(dev, 0, isairq);
- dev = qdev_create(NULL, "sysbus-fdc");
- qdev_init(dev);
- sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev);
- fdctrl = &sys->state;
- sysbus_connect_irq(&sys->busdev, 0, irq);
- sysbus_mmio_map(&sys->busdev, 0, io_base);
- } else {
- ISADevice *dev;
+ fdctrl->dma_chann = dma_chann;
+ DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
- dev = isa_create_simple("isa-fdc", io_base, 0);
- fdctrl = &(DO_UPCAST(fdctrl_isabus_t, busdev, dev)->state);
- isa_connect_irq(dev, 0, irq);
- }
+ fdctrl_connect_drives(fdctrl, fds);
+
+ return fdctrl;
+}
+
+fdctrl_t *fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
+ target_phys_addr_t mmio_base,
+ BlockDriverState **fds)
+{
+ fdctrl_t *fdctrl;
+ DeviceState *dev;
+ fdctrl_sysbus_t *sys;
+
+ dev = qdev_create(NULL, "sysbus-fdc");
+ qdev_init(dev);
+ sys = DO_UPCAST(fdctrl_sysbus_t, busdev.qdev, dev);
+ fdctrl = &sys->state;
+ sysbus_connect_irq(&sys->busdev, 0, irq);
+ sysbus_mmio_map(&sys->busdev, 0, mmio_base);
fdctrl->dma_chann = dma_chann;
DMA_register_channel(dma_chann, &fdctrl_transfer_handler, fdctrl);
-
fdctrl_connect_drives(fdctrl, fds);
return fdctrl;
diff --git a/hw/fdc.h b/hw/fdc.h
index 7b6a9ded8..04d64ea96 100644
--- a/hw/fdc.h
+++ b/hw/fdc.h
@@ -3,9 +3,12 @@
typedef struct fdctrl_t fdctrl_t;
-fdctrl_t *fdctrl_init (qemu_irq irq, int dma_chann, int mem_mapped,
- target_phys_addr_t io_base,
- BlockDriverState **fds);
+fdctrl_t *fdctrl_init_isa(int isairq, int dma_chann,
+ uint32_t io_base,
+ BlockDriverState **fds);
+fdctrl_t *fdctrl_init_sysbus(qemu_irq irq, int dma_chann,
+ target_phys_addr_t mmio_base,
+ BlockDriverState **fds);
fdctrl_t *sun4m_fdctrl_init (qemu_irq irq, target_phys_addr_t io_base,
BlockDriverState **fds, qemu_irq *fdc_tc);
int fdctrl_get_drive_type(fdctrl_t *fdctrl, int drive_num);
diff --git a/hw/hw.h b/hw/hw.h
index 322f07707..91bf80062 100644
--- a/hw/hw.h
+++ b/hw/hw.h
@@ -49,6 +49,7 @@ QEMUFile *qemu_fopen_ops(void *opaque, QEMUFilePutBufferFunc *put_buffer,
QEMUFileRateLimit *rate_limit,
QEMUFileSetRateLimit *set_rate_limit);
QEMUFile *qemu_fopen(const char *filename, const char *mode);
+QEMUFile *qemu_fdopen(int fd, const char *mode);
QEMUFile *qemu_fopen_socket(int fd);
QEMUFile *qemu_popen(FILE *popen_file, const char *mode);
QEMUFile *qemu_popen_cmd(const char *command, const char *mode);
diff --git a/hw/ide.c b/hw/ide.c
index 0bde632eb..28b93f4bf 100644
--- a/hw/ide.c
+++ b/hw/ide.c
@@ -3610,8 +3610,8 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
pci_register_bar((PCIDevice *)d, 4, 0x10,
PCI_ADDRESS_SPACE_IO, bmdma_map);
- ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]);
- ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], pic[15]);
+ ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], isa_reserve_irq(14));
+ ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], isa_reserve_irq(15));
ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
ide_init_ioport(&d->ide_if[2], 0x170, 0x376);
@@ -3650,6 +3650,9 @@ void pci_piix4_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
pci_register_bar((PCIDevice *)d, 4, 0x10,
PCI_ADDRESS_SPACE_IO, bmdma_map);
+ /*
+ * These should call isa_reserve_irq() instead when MIPS supports it
+ */
ide_init2(&d->ide_if[0], hd_table[0], hd_table[1], pic[14]);
ide_init2(&d->ide_if[2], hd_table[2], hd_table[3], pic[15]);
ide_init_ioport(&d->ide_if[0], 0x1f0, 0x3f6);
diff --git a/hw/isa-bus.c b/hw/isa-bus.c
index 315efbbec..9561c3112 100644
--- a/hw/isa-bus.c
+++ b/hw/isa-bus.c
@@ -18,17 +18,24 @@
*/
#include "hw.h"
#include "sysemu.h"
+#include "monitor.h"
+#include "sysbus.h"
#include "isa.h"
struct ISABus {
BusState qbus;
+ qemu_irq *irqs;
+ uint32_t assigned;
};
static ISABus *isabus;
+static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent);
+
static struct BusInfo isa_bus_info = {
- .name = "ISA",
- .size = sizeof(ISABus),
- .props = (Property[]) {
+ .name = "ISA",
+ .size = sizeof(ISABus),
+ .print_dev = isabus_dev_print,
+ .props = (Property[]) {
DEFINE_PROP_HEX32("iobase", ISADevice, iobase[0], -1),
DEFINE_PROP_HEX32("iobase2", ISADevice, iobase[1], -1),
DEFINE_PROP_END_OF_LIST(),
@@ -41,16 +48,53 @@ ISABus *isa_bus_new(DeviceState *dev)
fprintf(stderr, "Can't create a second ISA bus\n");
return NULL;
}
+ if (NULL == dev) {
+ dev = qdev_create(NULL, "isabus-bridge");
+ qdev_init(dev);
+ }
isabus = FROM_QBUS(ISABus, qbus_create(&isa_bus_info, dev, NULL));
return isabus;
}
-void isa_connect_irq(ISADevice *dev, int n, qemu_irq irq)
+void isa_bus_irqs(qemu_irq *irqs)
+{
+ isabus->irqs = irqs;
+}
+
+void isa_connect_irq(ISADevice *dev, int devnr, int isairq)
{
- assert(n >= 0 && n < dev->nirqs);
- if (dev->irqs[n])
- *dev->irqs[n] = irq;
+ assert(devnr >= 0 && devnr < dev->nirqs);
+ if (isabus->assigned & (1 << isairq)) {
+ fprintf(stderr, "isa irq %d already assigned\n", isairq);
+ exit(1);
+ }
+ if (dev->irqs[devnr]) {
+ isabus->assigned |= (1 << isairq);
+ dev->isairq[devnr] = isairq;
+ *dev->irqs[devnr] = isabus->irqs[isairq];
+ }
+}
+
+/*
+ * isa_reserve_irq() reserves the ISA irq and returns the corresponding
+ * qemu_irq entry for the i8259.
+ *
+ * This function is only for special cases such as the 'ferr', and
+ * temporary use for normal devices until they are converted to qdev.
+ */
+qemu_irq isa_reserve_irq(int isairq)
+{
+ if (isairq < 0 || isairq > 15) {
+ fprintf(stderr, "isa irq %d invalid\n", isairq);
+ exit(1);
+ }
+ if (isabus->assigned & (1 << isairq)) {
+ fprintf(stderr, "isa irq %d already assigned\n", isairq);
+ exit(1);
+ }
+ isabus->assigned |= (1 << isairq);
+ return isabus->irqs[isairq];
}
void isa_init_irq(ISADevice *dev, qemu_irq *p)
@@ -65,6 +109,8 @@ static void isa_qdev_init(DeviceState *qdev, DeviceInfo *base)
ISADevice *dev = DO_UPCAST(ISADevice, qdev, qdev);
ISADeviceInfo *info = DO_UPCAST(ISADeviceInfo, qdev, base);
+ dev->isairq[0] = -1;
+ dev->isairq[1] = -1;
info->init(dev);
}
@@ -91,3 +137,34 @@ ISADevice *isa_create_simple(const char *name, uint32_t iobase, uint32_t iobase2
qdev_init(dev);
return isa;
}
+
+static void isabus_dev_print(Monitor *mon, DeviceState *dev, int indent)
+{
+ ISADevice *d = DO_UPCAST(ISADevice, qdev, dev);
+
+ if (d->isairq[1] != -1) {
+ monitor_printf(mon, "%*sisa irqs %d,%d\n", indent, "",
+ d->isairq[0], d->isairq[1]);
+ } else if (d->isairq[0] != -1) {
+ monitor_printf(mon, "%*sisa irq %d\n", indent, "",
+ d->isairq[0]);
+ }
+}
+
+static void isabus_bridge_init(SysBusDevice *dev)
+{
+ /* nothing */
+}
+
+static SysBusDeviceInfo isabus_bridge_info = {
+ .init = isabus_bridge_init,
+ .qdev.name = "isabus-bridge",
+ .qdev.size = sizeof(SysBusDevice),
+};
+
+static void isabus_register_devices(void)
+{
+ sysbus_register_withprop(&isabus_bridge_info);
+}
+
+device_init(isabus_register_devices)
diff --git a/hw/isa.h b/hw/isa.h
index 49c58f84f..31853a040 100644
--- a/hw/isa.h
+++ b/hw/isa.h
@@ -13,6 +13,7 @@ typedef struct ISADeviceInfo ISADeviceInfo;
struct ISADevice {
DeviceState qdev;
uint32_t iobase[2];
+ uint32_t isairq[2];
qemu_irq *irqs[2];
int nirqs;
};
@@ -24,7 +25,9 @@ struct ISADeviceInfo {
};
ISABus *isa_bus_new(DeviceState *dev);
-void isa_connect_irq(ISADevice *dev, int n, qemu_irq irq);
+void isa_bus_irqs(qemu_irq *irqs);
+void isa_connect_irq(ISADevice *dev, int devirq, int isairq);
+qemu_irq isa_reserve_irq(int isairq);
void isa_init_irq(ISADevice *dev, qemu_irq *p);
void isa_qdev_register(ISADeviceInfo *info);
ISADevice *isa_create_simple(const char *name, uint32_t iobase, uint32_t iobase2);
diff --git a/hw/mips_jazz.c b/hw/mips_jazz.c
index 9740d728c..1cbd947fe 100644
--- a/hw/mips_jazz.c
+++ b/hw/mips_jazz.c
@@ -238,7 +238,7 @@ void mips_jazz_init (ram_addr_t ram_size,
DriveInfo *dinfo = drive_get(IF_FLOPPY, 0, n);
fds[n] = dinfo ? dinfo->bdrv : NULL;
}
- fdctrl_init(rc4030[1], 0, 1, 0x80003000, fds);
+ fdctrl_init_sysbus(rc4030[1], 0, 0x80003000, fds);
/* Real time clock */
rtc_init(0x70, i8259[8], 1980);
diff --git a/hw/mips_malta.c b/hw/mips_malta.c
index d8fa26437..6d4145035 100644
--- a/hw/mips_malta.c
+++ b/hw/mips_malta.c
@@ -929,7 +929,7 @@ void mips_malta_init (ram_addr_t ram_size,
dinfo = drive_get(IF_FLOPPY, 0, i);
fd[i] = dinfo ? dinfo->bdrv : NULL;
}
- floppy_controller = fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
+ floppy_controller = fdctrl_init_isa(6, 2, 0x3f0, fd);
/* Sound card */
#ifdef HAS_AUDIO
diff --git a/hw/pc.c b/hw/pc.c
index 503feb0d4..2e3f51785 100644
--- a/hw/pc.c
+++ b/hw/pc.c
@@ -1047,13 +1047,14 @@ static void audio_init (PCIBus *pci_bus, qemu_irq *pic)
}
#endif
-static void pc_init_ne2k_isa(NICInfo *nd, qemu_irq *pic)
+static void pc_init_ne2k_isa(NICInfo *nd)
{
static int nb_ne2k = 0;
if (nb_ne2k == NE2000_NB_MAX)
return;
- isa_ne2000_init(ne2000_io[nb_ne2k], pic[ne2000_irq[nb_ne2k]], nd);
+ isa_ne2000_init(ne2000_io[nb_ne2k],
+ isa_reserve_irq(ne2000_irq[nb_ne2k]), nd);
nb_ne2k++;
}
@@ -1294,14 +1295,17 @@ static void pc_init1(ram_addr_t ram_size,
isa_irq_state->i8259 = i8259;
isa_irq = qemu_allocate_irqs(isa_irq_handler, isa_irq_state, 24);
}
- ferr_irq = isa_irq[13];
if (pci_enabled) {
pci_bus = i440fx_init(&i440fx_state, isa_irq);
piix3_devfn = piix3_init(pci_bus, -1);
} else {
pci_bus = NULL;
+ isa_bus_new(NULL);
}
+ isa_bus_irqs(isa_irq);
+
+ ferr_irq = isa_reserve_irq(13);
/* init basic PC hardware */
register_ioport_write(0x80, 1, 1, ioport80_write, NULL);
@@ -1327,7 +1331,7 @@ static void pc_init1(ram_addr_t ram_size,
}
}
- rtc_state = rtc_init(0x70, isa_irq[8], 2000);
+ rtc_state = rtc_init(0x70, isa_reserve_irq(8), 2000);
qemu_register_boot_set(pc_boot_set, rtc_state);
@@ -1339,10 +1343,10 @@ static void pc_init1(ram_addr_t ram_size,
}
#ifdef USE_KVM_PIT
if (kvm_enabled() && qemu_kvm_pit_in_kernel())
- pit = kvm_pit_init(0x40, isa_irq[0]);
+ pit = kvm_pit_init(0x40, isa_reserve_irq(0));
else
#endif
- pit = pit_init(0x40, isa_irq[0]);
+ pit = pit_init(0x40, isa_reserve_irq(0));
pcspk_init(pit);
if (!no_hpet) {
hpet_init(isa_irq);
@@ -1350,14 +1354,14 @@ static void pc_init1(ram_addr_t ram_size,
for(i = 0; i < MAX_SERIAL_PORTS; i++) {
if (serial_hds[i]) {
- serial_init(serial_io[i], isa_irq[serial_irq[i]], 115200,
+ serial_init(serial_io[i], isa_reserve_irq(serial_irq[i]), 115200,
serial_hds[i]);
}
}
for(i = 0; i < MAX_PARALLEL_PORTS; i++) {
if (parallel_hds[i]) {
- parallel_init(parallel_io[i], isa_irq[parallel_irq[i]],
+ parallel_init(parallel_io[i], isa_reserve_irq(parallel_irq[i]),
parallel_hds[i]);
}
}
@@ -1368,7 +1372,7 @@ static void pc_init1(ram_addr_t ram_size,
NICInfo *nd = &nd_table[i];
if (!pci_enabled || (nd->model && strcmp(nd->model, "ne2k_isa") == 0))
- pc_init_ne2k_isa(nd, isa_irq);
+ pc_init_ne2k_isa(nd);
else
pci_nic_init(nd, "e1000", NULL);
}
@@ -1389,14 +1393,15 @@ static void pc_init1(ram_addr_t ram_size,
pci_piix3_ide_init(pci_bus, hd, piix3_devfn + 1, isa_irq);
} else {
for(i = 0; i < MAX_IDE_BUS; i++) {
- isa_ide_init(ide_iobase[i], ide_iobase2[i], isa_irq[ide_irq[i]],
+ isa_ide_init(ide_iobase[i], ide_iobase2[i],
+ isa_reserve_irq(ide_irq[i]),
hd[MAX_IDE_DEVS * i], hd[MAX_IDE_DEVS * i + 1]);
}
}
isa_dev = isa_create_simple("i8042", 0x60, 0x64);
- isa_connect_irq(isa_dev, 0, isa_irq[1]);
- isa_connect_irq(isa_dev, 1, isa_irq[12]);
+ isa_connect_irq(isa_dev, 0, 1);
+ isa_connect_irq(isa_dev, 1, 12);
DMA_init(0);
#ifdef HAS_AUDIO
audio_init(pci_enabled ? pci_bus : NULL, isa_irq);
@@ -1406,7 +1411,7 @@ static void pc_init1(ram_addr_t ram_size,
dinfo = drive_get(IF_FLOPPY, 0, i);
fd[i] = dinfo ? dinfo->bdrv : NULL;
}
- floppy_controller = fdctrl_init(isa_irq[6], 2, 0, 0x3f0, fd);
+ floppy_controller = fdctrl_init_isa(6, 2, 0x3f0, fd);
cmos_init(below_4g_mem_size, above_4g_mem_size, boot_device, hd);
@@ -1419,7 +1424,8 @@ static void pc_init1(ram_addr_t ram_size,
i2c_bus *smbus;
/* TODO: Populate SPD eeprom data. */
- smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100, isa_irq[9]);
+ smbus = piix4_pm_init(pci_bus, piix3_devfn + 3, 0xb100,
+ isa_reserve_irq(9));
for (i = 0; i < 8; i++) {
DeviceState *eeprom;
eeprom = qdev_create((BusState *)smbus, "smbus-eeprom");
diff --git a/hw/pci-hotplug.c b/hw/pci-hotplug.c
index 69ee92a13..206239109 100644
--- a/hw/pci-hotplug.c
+++ b/hw/pci-hotplug.c
@@ -100,7 +100,7 @@ static PCIDevice *qemu_pci_hot_add_storage(Monitor *mon,
const char *opts)
{
PCIDevice *dev;
- DriveInfo *dinfo;
+ DriveInfo *dinfo = NULL;
int type = -1;
char buf[128];
diff --git a/hw/ppc_prep.c b/hw/ppc_prep.c
index 223ca6193..7665cb7dd 100644
--- a/hw/ppc_prep.c
+++ b/hw/ppc_prep.c
@@ -719,7 +719,7 @@ static void ppc_prep_init (ram_addr_t ram_size,
dinfo = drive_get(IF_FLOPPY, 0, i);
fd[i] = dinfo ? dinfo->bdrv : NULL;
}
- fdctrl_init(i8259[6], 2, 0, 0x3f0, fd);
+ fdctrl_init_isa(6, 2, 0x3f0, fd);
/* Register speaker port */
register_ioport_read(0x61, 1, 1, speaker_ioport_read, NULL);
diff --git a/hw/sb16.c b/hw/sb16.c
index 2506d982f..9f7680d40 100644
--- a/hw/sb16.c
+++ b/hw/sb16.c
@@ -56,7 +56,7 @@ static struct {
typedef struct SB16State {
QEMUSoundCard card;
- qemu_irq *pic;
+ qemu_irq pic;
int irq;
int dma;
int hdma;
@@ -190,7 +190,7 @@ static void aux_timer (void *opaque)
{
SB16State *s = opaque;
s->can_write = 1;
- qemu_irq_raise (s->pic[s->irq]);
+ qemu_irq_raise (s->pic);
}
#define DMA8_AUTO 1
@@ -598,7 +598,7 @@ static void command (SB16State *s, uint8_t cmd)
case 0xf3:
dsp_out_data (s, 0xaa);
s->mixer_regs[0x82] |= (cmd == 0xf2) ? 1 : 2;
- qemu_irq_raise (s->pic[s->irq]);
+ qemu_irq_raise (s->pic);
break;
case 0xf9:
@@ -766,7 +766,7 @@ static void complete (SB16State *s)
bytes = samples << s->fmt_stereo << (s->fmt_bits == 16);
ticks = (bytes * ticks_per_sec) / freq;
if (ticks < ticks_per_sec / 1024) {
- qemu_irq_raise (s->pic[s->irq]);
+ qemu_irq_raise (s->pic);
}
else {
if (s->aux_ts) {
@@ -858,10 +858,10 @@ static void legacy_reset (SB16State *s)
static void reset (SB16State *s)
{
- qemu_irq_lower (s->pic[s->irq]);
+ qemu_irq_lower (s->pic);
if (s->dma_auto) {
- qemu_irq_raise (s->pic[s->irq]);
- qemu_irq_lower (s->pic[s->irq]);
+ qemu_irq_raise (s->pic);
+ qemu_irq_lower (s->pic);
}
s->mixer_regs[0x82] = 0;
@@ -897,7 +897,7 @@ static IO_WRITE_PROTO (dsp_write)
if (s->v2x6 == 1) {
if (0 && s->highspeed) {
s->highspeed = 0;
- qemu_irq_lower (s->pic[s->irq]);
+ qemu_irq_lower (s->pic);
control (s, 0);
}
else {
@@ -1008,7 +1008,7 @@ static IO_READ_PROTO (dsp_read)
if (s->mixer_regs[0x82] & 1) {
ack = 1;
s->mixer_regs[0x82] &= 1;
- qemu_irq_lower (s->pic[s->irq]);
+ qemu_irq_lower (s->pic);
}
break;
@@ -1017,7 +1017,7 @@ static IO_READ_PROTO (dsp_read)
if (s->mixer_regs[0x82] & 2) {
ack = 1;
s->mixer_regs[0x82] &= 2;
- qemu_irq_lower (s->pic[s->irq]);
+ qemu_irq_lower (s->pic);
}
break;
@@ -1231,7 +1231,7 @@ static int SB_read_DMA (void *opaque, int nchan, int dma_pos, int dma_len)
if (s->left_till_irq <= 0) {
s->mixer_regs[0x82] |= (nchan & 4) ? 2 : 1;
- qemu_irq_raise (s->pic[s->irq]);
+ qemu_irq_raise (s->pic);
if (0 == s->dma_auto) {
control (s, 0);
speaker (s, 0);
@@ -1408,8 +1408,7 @@ int SB16_init (qemu_irq *pic)
s = qemu_mallocz (sizeof (*s));
s->cmd = -1;
- s->pic = pic;
- s->irq = conf.irq;
+ s->pic = isa_reserve_irq(conf.irq);
s->dma = conf.dma;
s->hdma = conf.hdma;
s->port = conf.port;
diff --git a/hw/sun4u.c b/hw/sun4u.c
index bc832557d..09027e2f9 100644
--- a/hw/sun4u.c
+++ b/hw/sun4u.c
@@ -618,7 +618,7 @@ static void sun4uv_init(ram_addr_t RAM_size,
dinfo = drive_get(IF_FLOPPY, 0, i);
fd[i] = dinfo ? dinfo->bdrv : NULL;
}
- floppy_controller = fdctrl_init(NULL/*6*/, 2, 0, 0x3f0, fd);
+ floppy_controller = fdctrl_init_isa(6, 2, 0x3f0, fd);
nvram = m48t59_init(NULL/*8*/, 0, 0x0074, NVRAM_SIZE, 59);
initrd_size = 0;
diff --git a/migration-fd.c b/migration-fd.c
new file mode 100644
index 000000000..15b44158f
--- /dev/null
+++ b/migration-fd.c
@@ -0,0 +1,137 @@
+/*
+ * QEMU live migration via generic fd
+ *
+ * Copyright Red Hat, Inc. 2009
+ *
+ * Authors:
+ * Chris Lalancette <clalance@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu-common.h"
+#include "qemu_socket.h"
+#include "migration.h"
+#include "monitor.h"
+#include "qemu-char.h"
+#include "sysemu.h"
+#include "buffered_file.h"
+#include "block.h"
+#include "qemu_socket.h"
+
+//#define DEBUG_MIGRATION_FD
+
+#ifdef DEBUG_MIGRATION_FD
+#define dprintf(fmt, ...) \
+ do { printf("migration-fd: " fmt, ## __VA_ARGS__); } while (0)
+#else
+#define dprintf(fmt, ...) \
+ do { } while (0)
+#endif
+
+static int fd_errno(FdMigrationState *s)
+{
+ return errno;
+}
+
+static int fd_write(FdMigrationState *s, const void * buf, size_t size)
+{
+ return write(s->fd, buf, size);
+}
+
+static int fd_close(FdMigrationState *s)
+{
+ dprintf("fd_close\n");
+ if (s->fd != -1) {
+ close(s->fd);
+ s->fd = -1;
+ }
+ return 0;
+}
+
+MigrationState *fd_start_outgoing_migration(Monitor *mon,
+ const char *fdname,
+ int64_t bandwidth_limit,
+ int detach)
+{
+ FdMigrationState *s;
+
+ s = qemu_mallocz(sizeof(*s));
+
+ s->fd = monitor_get_fd(mon, fdname);
+ if (s->fd == -1) {
+ dprintf("fd_migration: invalid file descriptor identifier\n");
+ goto err_after_alloc;
+ }
+
+ if (fcntl(s->fd, F_SETFL, O_NONBLOCK) == -1) {
+ dprintf("Unable to set nonblocking mode on file descriptor\n");
+ goto err_after_open;
+ }
+
+ s->get_error = fd_errno;
+ s->write = fd_write;
+ s->close = fd_close;
+ s->mig_state.cancel = migrate_fd_cancel;
+ s->mig_state.get_status = migrate_fd_get_status;
+ s->mig_state.release = migrate_fd_release;
+
+ s->state = MIG_STATE_ACTIVE;
+ s->mon_resume = NULL;
+ s->bandwidth_limit = bandwidth_limit;
+
+ if (!detach)
+ migrate_fd_monitor_suspend(s);
+
+ migrate_fd_connect(s);
+ return &s->mig_state;
+
+err_after_open:
+ close(s->fd);
+err_after_alloc:
+ qemu_free(s);
+ return NULL;
+}
+
+static void fd_accept_incoming_migration(void *opaque)
+{
+ QEMUFile *f = opaque;
+ int ret;
+
+ ret = qemu_loadvm_state(f);
+ if (ret < 0) {
+ fprintf(stderr, "load of migration failed\n");
+ goto err;
+ }
+ qemu_announce_self();
+ dprintf("successfully loaded vm state\n");
+ /* we've successfully migrated, close the fd */
+ qemu_set_fd_handler2(qemu_stdio_fd(f), NULL, NULL, NULL, NULL);
+ if (autostart)
+ vm_start();
+
+err:
+ qemu_fclose(f);
+}
+
+int fd_start_incoming_migration(const char *infd)
+{
+ int fd;
+ QEMUFile *f;
+
+ dprintf("Attempting to start an incoming migration via fd\n");
+
+ fd = strtol(infd, NULL, 0);
+ f = qemu_fdopen(fd, "rb");
+ if(f == NULL) {
+ dprintf("Unable to apply qemu wrapper to file descriptor\n");
+ return -errno;
+ }
+
+ qemu_set_fd_handler2(fd, NULL, fd_accept_incoming_migration, NULL,
+ (void *)(unsigned long)f);
+
+ return 0;
+}
diff --git a/migration.c b/migration.c
index 34e2bc14c..c18d59584 100644
--- a/migration.c
+++ b/migration.c
@@ -45,6 +45,8 @@ void qemu_start_incoming_migration(const char *uri)
exec_start_incoming_migration(p);
else if (strstart(uri, "unix:", &p))
unix_start_incoming_migration(p);
+ else if (strstart(uri, "fd:", &p))
+ fd_start_incoming_migration(p);
#endif
else
fprintf(stderr, "unknown migration protocol: %s\n", uri);
@@ -62,6 +64,8 @@ void do_migrate(Monitor *mon, int detach, const char *uri)
s = exec_start_outgoing_migration(p, max_throttle, detach);
else if (strstart(uri, "unix:", &p))
s = unix_start_outgoing_migration(p, max_throttle, detach);
+ else if (strstart(uri, "fd:", &p))
+ s = fd_start_outgoing_migration(mon, p, max_throttle, detach);
#endif
else
monitor_printf(mon, "unknown migration protocol: %s\n", uri);
diff --git a/migration.h b/migration.h
index 0ed1fcb51..96dad38eb 100644
--- a/migration.h
+++ b/migration.h
@@ -79,6 +79,13 @@ MigrationState *unix_start_outgoing_migration(const char *path,
int64_t bandwidth_limit,
int detach);
+int fd_start_incoming_migration(const char *path);
+
+MigrationState *fd_start_outgoing_migration(Monitor *mon,
+ const char *fdname,
+ int64_t bandwidth_limit,
+ int detach);
+
void migrate_fd_monitor_suspend(FdMigrationState *s);
void migrate_fd_error(FdMigrationState *s);
diff --git a/savevm.c b/savevm.c
index 975e7ab46..457565377 100644
--- a/savevm.c
+++ b/savevm.c
@@ -285,6 +285,34 @@ int qemu_stdio_fd(QEMUFile *f)
return fd;
}
+QEMUFile *qemu_fdopen(int fd, const char *mode)
+{
+ QEMUFileStdio *s;
+
+ if (mode == NULL ||
+ (mode[0] != 'r' && mode[0] != 'w') ||
+ mode[1] != 'b' || mode[2] != 0) {
+ fprintf(stderr, "qemu_fdopen: Argument validity check failed\n");
+ return NULL;
+ }
+
+ s = qemu_mallocz(sizeof(QEMUFileStdio));
+ s->stdio_file = fdopen(fd, mode);
+ if (!s->stdio_file)
+ goto fail;
+
+ if(mode[0] == 'r') {
+ s->file = qemu_fopen_ops(s, NULL, stdio_get_buffer, stdio_fclose, NULL, NULL);
+ } else {
+ s->file = qemu_fopen_ops(s, stdio_put_buffer, NULL, stdio_fclose, NULL, NULL);
+ }
+ return s->file;
+
+fail:
+ qemu_free(s);
+ return NULL;
+}
+
QEMUFile *qemu_fopen_socket(int fd)
{
QEMUFileSocket *s = qemu_mallocz(sizeof(QEMUFileSocket));
diff --git a/target-i386/helper.c b/target-i386/helper.c
index 81feef7a6..4a16887c1 100644
--- a/target-i386/helper.c
+++ b/target-i386/helper.c
@@ -121,7 +121,7 @@ static x86_def_t x86_defs[] = {
#ifdef TARGET_X86_64
{
.name = "qemu64",
- .level = 2,
+ .level = 4,
.vendor1 = CPUID_VENDOR_AMD_1,
.vendor2 = CPUID_VENDOR_AMD_2,
.vendor3 = CPUID_VENDOR_AMD_3,
@@ -189,10 +189,36 @@ static x86_def_t x86_defs[] = {
.xlevel = 0x80000008,
.model_id = "Intel(R) Core(TM)2 Duo CPU T7700 @ 2.40GHz",
},
+ {
+ .name = "kvm64",
+ .level = 5,
+ .vendor1 = CPUID_VENDOR_INTEL_1,
+ .vendor2 = CPUID_VENDOR_INTEL_2,
+ .vendor3 = CPUID_VENDOR_INTEL_3,
+ .family = 15,
+ .model = 6,
+ .stepping = 1,
+ /* Missing: CPUID_VME, CPUID_HT */
+ .features = PPRO_FEATURES |
+ CPUID_MTRR | CPUID_CLFLUSH | CPUID_MCA |
+ CPUID_PSE36,
+ /* Missing: CPUID_EXT_POPCNT, CPUID_EXT_MONITOR */
+ .ext_features = CPUID_EXT_SSE3 | CPUID_EXT_CX16,
+ /* Missing: CPUID_EXT2_PDPE1GB, CPUID_EXT2_RDTSCP */
+ .ext2_features = (PPRO_FEATURES & 0x0183F3FF) |
+ CPUID_EXT2_LM | CPUID_EXT2_SYSCALL | CPUID_EXT2_NX,
+ /* Missing: CPUID_EXT3_LAHF_LM, CPUID_EXT3_CMP_LEG, CPUID_EXT3_EXTAPIC,
+ CPUID_EXT3_CR8LEG, CPUID_EXT3_ABM, CPUID_EXT3_SSE4A,
+ CPUID_EXT3_MISALIGNSSE, CPUID_EXT3_3DNOWPREFETCH,
+ CPUID_EXT3_OSVW, CPUID_EXT3_IBS, CPUID_EXT3_SVM */
+ .ext3_features = 0,
+ .xlevel = 0x80000008,
+ .model_id = "Common KVM processor"
+ },
#endif
{
.name = "qemu32",
- .level = 2,
+ .level = 4,
.family = 6,
.model = 3,
.stepping = 3,
@@ -351,7 +377,7 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
char *featurestr, *name = strtok(s, ",");
uint32_t plus_features = 0, plus_ext_features = 0, plus_ext2_features = 0, plus_ext3_features = 0;
uint32_t minus_features = 0, minus_ext_features = 0, minus_ext2_features = 0, minus_ext3_features = 0;
- int family = -1, model = -1, stepping = -1;
+ uint32_t numvalue;
def = NULL;
for (i = 0; i < ARRAY_SIZE(x86_defs); i++) {
@@ -383,28 +409,47 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
*val = 0; val++;
if (!strcmp(featurestr, "family")) {
char *err;
- family = strtol(val, &err, 10);
- if (!*val || *err || family < 0) {
+ numvalue = strtoul(val, &err, 0);
+ if (!*val || *err) {
fprintf(stderr, "bad numerical value %s\n", val);
goto error;
}
- x86_cpu_def->family = family;
+ x86_cpu_def->family = numvalue;
} else if (!strcmp(featurestr, "model")) {
char *err;
- model = strtol(val, &err, 10);
- if (!*val || *err || model < 0 || model > 0xff) {
+ numvalue = strtoul(val, &err, 0);
+ if (!*val || *err || numvalue > 0xff) {
fprintf(stderr, "bad numerical value %s\n", val);
goto error;
}
- x86_cpu_def->model = model;
+ x86_cpu_def->model = numvalue;
} else if (!strcmp(featurestr, "stepping")) {
char *err;
- stepping = strtol(val, &err, 10);
- if (!*val || *err || stepping < 0 || stepping > 0xf) {
+ numvalue = strtoul(val, &err, 0);
+ if (!*val || *err || numvalue > 0xf) {
fprintf(stderr, "bad numerical value %s\n", val);
goto error;
}
- x86_cpu_def->stepping = stepping;
+ x86_cpu_def->stepping = numvalue ;
+ } else if (!strcmp(featurestr, "level")) {
+ char *err;
+ numvalue = strtoul(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ x86_cpu_def->level = numvalue;
+ } else if (!strcmp(featurestr, "xlevel")) {
+ char *err;
+ numvalue = strtoul(val, &err, 0);
+ if (!*val || *err) {
+ fprintf(stderr, "bad numerical value %s\n", val);
+ goto error;
+ }
+ if (numvalue < 0x80000000) {
+ numvalue += 0x80000000;
+ }
+ x86_cpu_def->xlevel = numvalue;
} else if (!strcmp(featurestr, "vendor")) {
if (strlen(val) != 12) {
fprintf(stderr, "vendor string must be 12 chars long\n");
@@ -1634,6 +1679,10 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ebx = (env->cpuid_apic_id << 24) | 8 << 8; /* CLFLUSH size in quad words, Linux wants it. */
*ecx = env->cpuid_ext_features;
*edx = env->cpuid_features;
+ if (env->nr_cores * env->nr_threads > 1) {
+ *ebx |= (env->nr_cores * env->nr_threads) << 16;
+ *edx |= 1 << 28; /* HTT bit */
+ }
break;
case 2:
/* cache info: needed for Pentium Pro compatibility */
@@ -1644,21 +1693,29 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
break;
case 4:
/* cache info: needed for Core compatibility */
+ if (env->nr_cores > 1) {
+ *eax = (env->nr_cores - 1) << 26;
+ } else {
+ *eax = 0;
+ }
switch (count) {
case 0: /* L1 dcache info */
- *eax = 0x0000121;
+ *eax |= 0x0000121;
*ebx = 0x1c0003f;
*ecx = 0x000003f;
*edx = 0x0000001;
break;
case 1: /* L1 icache info */
- *eax = 0x0000122;
+ *eax |= 0x0000122;
*ebx = 0x1c0003f;
*ecx = 0x000003f;
*edx = 0x0000001;
break;
case 2: /* L2 cache info */
- *eax = 0x0000143;
+ *eax |= 0x0000143;
+ if (env->nr_threads > 1) {
+ *eax |= (env->nr_threads - 1) << 14;
+ }
*ebx = 0x3c0003f;
*ecx = 0x0000fff;
*edx = 0x0000001;
@@ -1711,6 +1768,13 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ecx = env->cpuid_ext3_features;
*edx = env->cpuid_ext2_features;
+ if (env->nr_cores * env->nr_threads > 1 &&
+ env->cpuid_vendor1 == CPUID_VENDOR_AMD_1 &&
+ env->cpuid_vendor2 == CPUID_VENDOR_AMD_2 &&
+ env->cpuid_vendor3 == CPUID_VENDOR_AMD_3) {
+ *ecx |= 1 << 1; /* CmpLegacy bit */
+ }
+
if (kvm_enabled()) {
uint32_t h_eax, h_edx;
@@ -1778,6 +1842,9 @@ void cpu_x86_cpuid(CPUX86State *env, uint32_t index, uint32_t count,
*ebx = 0;
*ecx = 0;
*edx = 0;
+ if (env->nr_cores * env->nr_threads > 1) {
+ *ecx |= (env->nr_cores * env->nr_threads) - 1;
+ }
break;
case 0x8000000A:
*eax = 0x00000001; /* SVM Revision */
diff --git a/vl.c b/vl.c
index 5d2f359d1..3cf4c5dcf 100644
--- a/vl.c
+++ b/vl.c
@@ -222,6 +222,8 @@ const char *assigned_devices[MAX_DEV_ASSIGN_CMDLINE];
int assigned_devices_index;
int smp_cpus = 1;
int max_cpus = 0;
+int smp_cores = 1;
+int smp_threads = 1;
const char *vnc_display;
int acpi_enabled = 1;
#ifdef TARGET_I386
@@ -2380,6 +2382,56 @@ static void numa_add(const char *optarg)
return;
}
+static void smp_parse(const char *optarg)
+{
+ int smp, sockets = 0, threads = 0, cores = 0;
+ char *endptr;
+ char option[128];
+
+ smp = strtoul(optarg, &endptr, 10);
+ if (endptr != optarg) {
+ if (*endptr == ',') {
+ endptr++;
+ }
+ }
+ if (get_param_value(option, 128, "sockets", endptr) != 0)
+ sockets = strtoull(option, NULL, 10);
+ if (get_param_value(option, 128, "cores", endptr) != 0)
+ cores = strtoull(option, NULL, 10);
+ if (get_param_value(option, 128, "threads", endptr) != 0)
+ threads = strtoull(option, NULL, 10);
+ if (get_param_value(option, 128, "maxcpus", endptr) != 0)
+ max_cpus = strtoull(option, NULL, 10);
+
+ /* compute missing values, prefer sockets over cores over threads */
+ if (smp == 0 || sockets == 0) {
+ sockets = sockets > 0 ? sockets : 1;
+ cores = cores > 0 ? cores : 1;
+ threads = threads > 0 ? threads : 1;
+ if (smp == 0) {
+ smp = cores * threads * sockets;
+ } else {
+ sockets = smp / (cores * threads);
+ }
+ } else {
+ if (cores == 0) {
+ threads = threads > 0 ? threads : 1;
+ cores = smp / (sockets * threads);
+ } else {
+ if (sockets == 0) {
+ sockets = smp / (cores * threads);
+ } else {
+ threads = smp / (cores * sockets);
+ }
+ }
+ }
+ smp_cpus = smp;
+ smp_cores = cores > 0 ? cores : 1;
+ smp_threads = threads > 0 ? threads : 1;
+ if (max_cpus == 0)
+ max_cpus = smp_cpus;
+}
+
/***********************************************************/
/* USB devices */
@@ -3613,6 +3665,8 @@ void qemu_init_vcpu(void *_env)
if (kvm_enabled())
kvm_init_vcpu(env);
+ env->nr_cores = smp_cores;
+ env->nr_threads = smp_threads;
return;
}
@@ -3942,6 +3996,8 @@ void qemu_init_vcpu(void *_env)
kvm_start_vcpu(env);
else
tcg_init_vcpu(env);
+ env->nr_cores = smp_cores;
+ env->nr_threads = smp_threads;
}
void qemu_notify_event(void)
@@ -5470,18 +5526,11 @@ int main(int argc, char **argv, char **envp)
}
break;
case QEMU_OPTION_smp:
- {
- char *p;
- char option[128];
- smp_cpus = strtol(optarg, &p, 10);
+ smp_parse(optarg);
if (smp_cpus < 1) {
fprintf(stderr, "Invalid number of CPUs\n");
exit(1);
}
- if (*p++ != ',')
- break;
- if (get_param_value(option, 128, "maxcpus", p))
- max_cpus = strtol(option, NULL, 0);
if (max_cpus < smp_cpus) {
fprintf(stderr, "maxcpus must be equal to or greater than "
"smp\n");
@@ -5492,7 +5541,6 @@ int main(int argc, char **argv, char **envp)
exit(1);
}
break;
- }
case QEMU_OPTION_vnc:
display_type = DT_VNC;
vnc_display = optarg;