aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2012-08-31 12:43:17 -0300
committerMarcelo Tosatti <mtosatti@redhat.com>2012-08-31 12:43:17 -0300
commit1cc707b10567b0ebf2670e39f4a3c01da664fd6a (patch)
tree16cdc115c50e38a550915ca1ca2a014abce4d569
parent352183cdb01761ba813576b3bc559947cbccbae8 (diff)
parent01fd4b8e9e28b92f124556a5889167820c52635f (diff)
Merge branch 'upstream-merge'qemu-kvm-1.2.0-rc2
* upstream-merge: (47 commits) w32: Fix broken build Update version for 1.2.0-rc2 scsi-disk: Fix typo (uint32 -> uint32_t) msix: make [un]use vectors on reset/load optional kvm: get/set PV EOI MSR linux-headers: update to 3.6-rc3 target-i386: disable pv eoi to fix migration across QEMU versions reset PMBA and PMREGMISC PIIX4 registers. qemu-ga: Fix null pointer passed to unlink in failure branch memory: Fix copy&paste mistake in memory_region_iorange_write ivshmem: remove redundant ioeventfd configuration hw/arm_gic.c: Define .class_size in arm_gic_info TypeInfo tcg/mips: fix broken CONFIG_TCG_PASS_AREG0 code Update OpenBIOS PPC image target-ppc: fix altivec instructions audio/winwave: previous audio buffer should be flushed iscsi: Set number of blocks to 0 for blank CDROM devices scsi: more fixes to properties for passthrough devices esp: support 24-bit DMA megasas: Add 'hba_serial' property ... Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
-rw-r--r--VERSION2
-rw-r--r--audio/winwaveaudio.c12
-rw-r--r--block/iscsi.c7
-rw-r--r--hw/acpi_piix4.c6
-rw-r--r--hw/arm_gic.c1
-rw-r--r--hw/esp.c16
-rw-r--r--hw/ivshmem.c19
-rw-r--r--hw/megasas.c9
-rw-r--r--hw/msix.c13
-rw-r--r--hw/qdev.c2
-rw-r--r--hw/scsi-disk.c3
-rw-r--r--hw/scsi-generic.c3
-rw-r--r--hw/shpc.c1
-rw-r--r--hw/virtio-pci.c2
-rw-r--r--hw/xen_platform.c3
-rw-r--r--linux-headers/asm-s390/kvm.h2
-rw-r--r--linux-headers/asm-s390/kvm_para.h2
-rw-r--r--linux-headers/asm-x86/kvm.h1
-rw-r--r--linux-headers/asm-x86/kvm_para.h7
-rw-r--r--linux-headers/linux/kvm.h3
-rw-r--r--linux-user/main.c11
-rw-r--r--linux-user/syscall.c11
-rw-r--r--linux-user/syscall_defs.h8
-rw-r--r--memory.c2
-rw-r--r--pc-bios/README2
-rw-r--r--pc-bios/openbios-ppcbin729876 -> 729908 bytes
-rw-r--r--qemu-ga.c4
-rw-r--r--qom/object.c5
m---------roms/openbios0
-rw-r--r--target-i386/cpu.c15
-rw-r--r--target-i386/cpu.h1
-rw-r--r--target-i386/kvm.c13
-rw-r--r--target-i386/machine.c21
-rw-r--r--target-i386/translate.c14
-rw-r--r--target-mips/op_helper.c75
-rw-r--r--target-mips/translate.c32
-rw-r--r--target-ppc/translate.c2
-rw-r--r--tcg/arm/tcg-target.c237
-rw-r--r--tcg/ia64/tcg-target.c58
-rw-r--r--tcg/mips/tcg-target.c158
40 files changed, 480 insertions, 303 deletions
diff --git a/VERSION b/VERSION
index 069199b82..99f6a00b1 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.1.91
+1.1.92
diff --git a/audio/winwaveaudio.c b/audio/winwaveaudio.c
index 663abb9b5..72babbf18 100644
--- a/audio/winwaveaudio.c
+++ b/audio/winwaveaudio.c
@@ -349,21 +349,15 @@ static int winwave_ctl_out (HWVoiceOut *hw, int cmd, ...)
else {
hw->poll_mode = 0;
}
- if (wave->paused) {
- mr = waveOutRestart (wave->hwo);
- if (mr != MMSYSERR_NOERROR) {
- winwave_logerr (mr, "waveOutRestart");
- }
- wave->paused = 0;
- }
+ wave->paused = 0;
}
return 0;
case VOICE_DISABLE:
if (!wave->paused) {
- mr = waveOutPause (wave->hwo);
+ mr = waveOutReset (wave->hwo);
if (mr != MMSYSERR_NOERROR) {
- winwave_logerr (mr, "waveOutPause");
+ winwave_logerr (mr, "waveOutReset");
}
else {
wave->paused = 1;
diff --git a/block/iscsi.c b/block/iscsi.c
index 4828b8392..0b96165ec 100644
--- a/block/iscsi.c
+++ b/block/iscsi.c
@@ -721,7 +721,12 @@ iscsi_readcapacity10_cb(struct iscsi_context *iscsi, int status,
}
itask->iscsilun->block_size = rc10->block_size;
- itask->iscsilun->num_blocks = rc10->lba + 1;
+ if (rc10->lba == 0) {
+ /* blank disk loaded */
+ itask->iscsilun->num_blocks = 0;
+ } else {
+ itask->iscsilun->num_blocks = rc10->lba + 1;
+ }
itask->bs->total_sectors = itask->iscsilun->num_blocks *
itask->iscsilun->block_size / BDRV_SECTOR_SIZE ;
diff --git a/hw/acpi_piix4.c b/hw/acpi_piix4.c
index f7fec6281..dad38870a 100644
--- a/hw/acpi_piix4.c
+++ b/hw/acpi_piix4.c
@@ -311,7 +311,6 @@ static void acpi_piix_eject_slot(PIIX4PMState *s, unsigned slots)
if (pc->no_hotplug) {
slot_free = false;
} else {
- object_unparent(OBJECT(dev));
qdev_free(qdev);
}
}
@@ -359,6 +358,9 @@ static void piix4_reset(void *opaque)
pci_conf[0x5a] = 0;
pci_conf[0x5b] = 0;
+ pci_conf[0x40] = 0x01; /* PM io base read only bit */
+ pci_conf[0x80] = 0;
+
if (s->kvm_enabled) {
/* Mark SMM as already inited (until KVM supports SMM). */
pci_conf[0x5B] = 0x02;
@@ -403,8 +405,6 @@ static int piix4_pm_initfn(PCIDevice *dev)
pci_conf[0x09] = 0x00;
pci_conf[0x3d] = 0x01; // interrupt pin 1
- pci_conf[0x40] = 0x01; /* PM io base read only bit */
-
/* APM */
apm_init(&s->apm, apm_ctrl_changed, s);
diff --git a/hw/arm_gic.c b/hw/arm_gic.c
index 186ac66f0..55871fad1 100644
--- a/hw/arm_gic.c
+++ b/hw/arm_gic.c
@@ -703,6 +703,7 @@ static TypeInfo arm_gic_info = {
.parent = TYPE_ARM_GIC_COMMON,
.instance_size = sizeof(gic_state),
.class_init = arm_gic_class_init,
+ .class_size = sizeof(ARMGICClass),
};
static void arm_gic_register_types(void)
diff --git a/hw/esp.c b/hw/esp.c
index 52c46e615..84a4e74e2 100644
--- a/hw/esp.c
+++ b/hw/esp.c
@@ -87,7 +87,9 @@ static uint32_t get_cmd(ESPState *s, uint8_t *buf)
target = s->wregs[ESP_WBUSID] & BUSID_DID;
if (s->dma) {
- dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
+ dmalen = s->rregs[ESP_TCLO];
+ dmalen |= s->rregs[ESP_TCMID] << 8;
+ dmalen |= s->rregs[ESP_TCHI] << 16;
s->dma_memory_read(s->dma_opaque, buf, dmalen);
} else {
dmalen = s->ti_size;
@@ -226,6 +228,7 @@ static void esp_dma_done(ESPState *s)
s->rregs[ESP_RFLAGS] = 0;
s->rregs[ESP_TCLO] = 0;
s->rregs[ESP_TCMID] = 0;
+ s->rregs[ESP_TCHI] = 0;
esp_raise_irq(s);
}
@@ -328,7 +331,9 @@ static void handle_ti(ESPState *s)
return;
}
- dmalen = s->rregs[ESP_TCLO] | (s->rregs[ESP_TCMID] << 8);
+ dmalen = s->rregs[ESP_TCLO];
+ dmalen |= s->rregs[ESP_TCMID] << 8;
+ dmalen |= s->rregs[ESP_TCHI] << 16;
if (dmalen==0) {
dmalen=0x10000;
}
@@ -429,6 +434,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
switch (saddr) {
case ESP_TCLO:
case ESP_TCMID:
+ case ESP_TCHI:
s->rregs[ESP_RSTAT] &= ~STAT_TC;
break;
case ESP_FIFO:
@@ -448,6 +454,7 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
/* Reload DMA counter. */
s->rregs[ESP_TCLO] = s->wregs[ESP_TCLO];
s->rregs[ESP_TCMID] = s->wregs[ESP_TCMID];
+ s->rregs[ESP_TCHI] = s->wregs[ESP_TCHI];
} else {
s->dma = 0;
}
@@ -530,13 +537,12 @@ void esp_reg_write(ESPState *s, uint32_t saddr, uint64_t val)
case ESP_WBUSID ... ESP_WSYNO:
break;
case ESP_CFG1:
+ case ESP_CFG2: case ESP_CFG3:
+ case ESP_RES3: case ESP_RES4:
s->rregs[saddr] = val;
break;
case ESP_WCCF ... ESP_WTEST:
break;
- case ESP_CFG2 ... ESP_RES4:
- s->rregs[saddr] = val;
- break;
default:
trace_esp_error_invalid_write(val, saddr);
return;
diff --git a/hw/ivshmem.c b/hw/ivshmem.c
index b4d65a6db..62fe53ae2 100644
--- a/hw/ivshmem.c
+++ b/hw/ivshmem.c
@@ -366,6 +366,10 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
{
int i, guest_curr_max;
+ if (!ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
+ return;
+ }
+
guest_curr_max = s->peers[posn].nb_eventfds;
memory_region_transaction_begin();
@@ -381,17 +385,6 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
s->peers[posn].nb_eventfds = 0;
}
-static void setup_ioeventfds(IVShmemState *s) {
-
- int i, j;
-
- for (i = 0; i <= s->max_peer; i++) {
- for (j = 0; j < s->peers[i].nb_eventfds; j++) {
- ivshmem_add_eventfd(s, i, j);
- }
- }
-}
-
/* this function increase the dynamic storage need to store data about other
* guests */
static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
@@ -692,10 +685,6 @@ static int pci_ivshmem_init(PCIDevice *dev)
memory_region_init_io(&s->ivshmem_mmio, &ivshmem_mmio_ops, s,
"ivshmem-mmio", IVSHMEM_REG_BAR_SIZE);
- if (ivshmem_has_feature(s, IVSHMEM_IOEVENTFD)) {
- setup_ioeventfds(s);
- }
-
/* region for registers*/
pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_SPACE_MEMORY,
&s->ivshmem_mmio);
diff --git a/hw/megasas.c b/hw/megasas.c
index c35a15db4..c728aea69 100644
--- a/hw/megasas.c
+++ b/hw/megasas.c
@@ -38,6 +38,7 @@
#define MEGASAS_MAX_SECTORS 0xFFFF /* No real limit */
#define MEGASAS_MAX_ARRAYS 128
+#define MEGASAS_HBA_SERIAL "QEMU123456"
#define NAA_LOCALLY_ASSIGNED_ID 0x3ULL
#define IEEE_COMPANY_LOCALLY_ASSIGNED 0x525400
@@ -93,6 +94,7 @@ typedef struct MegasasState {
int boot_event;
uint64_t sas_addr;
+ char *hba_serial;
uint64_t reply_queue_pa;
void *reply_queue;
@@ -698,8 +700,7 @@ static int megasas_ctrl_get_info(MegasasState *s, MegasasCmd *cmd)
}
memcpy(info.product_name, "MegaRAID SAS 8708EM2", 20);
- snprintf(info.serial_number, 32, "QEMU%08lx",
- (unsigned long)s & 0xFFFFFFFF);
+ snprintf(info.serial_number, 32, "%s", s->hba_serial);
snprintf(info.package_version, 0x60, "%s-QEMU", QEMU_VERSION);
memcpy(info.image_component[0].name, "APP", 3);
memcpy(info.image_component[0].version, MEGASAS_VERSION "-QEMU", 9);
@@ -2132,6 +2133,9 @@ static int megasas_scsi_init(PCIDevice *dev)
s->sas_addr |= (PCI_SLOT(dev->devfn) << 8);
s->sas_addr |= PCI_FUNC(dev->devfn);
}
+ if (!s->hba_serial) {
+ s->hba_serial = g_strdup(MEGASAS_HBA_SERIAL);
+ }
if (s->fw_sge >= MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE) {
s->fw_sge = MEGASAS_MAX_SGE - MFI_PASS_FRAME_SIZE;
} else if (s->fw_sge >= 128 - MFI_PASS_FRAME_SIZE) {
@@ -2166,6 +2170,7 @@ static Property megasas_properties[] = {
MEGASAS_DEFAULT_SGE),
DEFINE_PROP_UINT32("max_cmds", MegasasState, fw_cmds,
MEGASAS_DEFAULT_FRAMES),
+ DEFINE_PROP_STRING("hba_serial", MegasasState, hba_serial),
DEFINE_PROP_HEX64("sas_address", MegasasState, sas_addr, 0),
#ifdef USE_MSIX
DEFINE_PROP_BIT("use_msix", MegasasState, flags,
diff --git a/hw/msix.c b/hw/msix.c
index aea340b7c..d81209413 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -336,6 +336,15 @@ static void msix_free_irq_entries(PCIDevice *dev)
}
}
+static void msix_clear_all_vectors(PCIDevice *dev)
+{
+ int vector;
+
+ for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
+ msix_clr_pending(dev, vector);
+ }
+}
+
/* Clean up resources for the device. */
void msix_uninit(PCIDevice *dev, MemoryRegion *table_bar, MemoryRegion *pba_bar)
{
@@ -390,7 +399,7 @@ void msix_load(PCIDevice *dev, QEMUFile *f)
return;
}
- msix_free_irq_entries(dev);
+ msix_clear_all_vectors(dev);
qemu_get_buffer(f, dev->msix_table, n * PCI_MSIX_ENTRY_SIZE);
qemu_get_buffer(f, dev->msix_pba, (n + 7) / 8);
msix_update_function_masked(dev);
@@ -436,7 +445,7 @@ void msix_reset(PCIDevice *dev)
if (!msix_present(dev)) {
return;
}
- msix_free_irq_entries(dev);
+ msix_clear_all_vectors(dev);
dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] &=
~dev->wmask[dev->msix_cap + MSIX_CONTROL_OFFSET];
memset(dev->msix_table, 0, dev->msix_entries_nr * PCI_MSIX_ENTRY_SIZE);
diff --git a/hw/qdev.c b/hw/qdev.c
index b5b74b913..b5a52ac50 100644
--- a/hw/qdev.c
+++ b/hw/qdev.c
@@ -159,7 +159,6 @@ int qdev_init(DeviceState *dev)
rc = dc->init(dev);
if (rc < 0) {
- object_unparent(OBJECT(dev));
qdev_free(dev);
return rc;
}
@@ -243,7 +242,6 @@ void qbus_reset_all_fn(void *opaque)
int qdev_simple_unplug_cb(DeviceState *dev)
{
/* just zap it */
- object_unparent(OBJECT(dev));
qdev_free(dev);
return 0;
}
diff --git a/hw/scsi-disk.c b/hw/scsi-disk.c
index 409f760ef..1585683bc 100644
--- a/hw/scsi-disk.c
+++ b/hw/scsi-disk.c
@@ -1461,7 +1461,7 @@ static void scsi_unmap_complete(void *opaque, int ret)
SCSIDiskReq *r = data->r;
SCSIDiskState *s = DO_UPCAST(SCSIDiskState, qdev, r->req.dev);
uint64_t sector_num;
- uint32 nb_sectors;
+ uint32_t nb_sectors;
r->req.aiocb = NULL;
if (ret < 0) {
@@ -2421,6 +2421,7 @@ static TypeInfo scsi_cd_info = {
#ifdef __linux__
static Property scsi_block_properties[] = {
DEFINE_PROP_DRIVE("drive", SCSIDiskState, qdev.conf.bs),
+ DEFINE_PROP_INT32("bootindex", SCSIDiskState, qdev.conf.bootindex, -1),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/scsi-generic.c b/hw/scsi-generic.c
index 8d5106061..a5eb663ec 100644
--- a/hw/scsi-generic.c
+++ b/hw/scsi-generic.c
@@ -479,7 +479,8 @@ static SCSIRequest *scsi_new_request(SCSIDevice *d, uint32_t tag, uint32_t lun,
}
static Property scsi_generic_properties[] = {
- DEFINE_BLOCK_PROPERTIES(SCSIDevice, conf),
+ DEFINE_PROP_DRIVE("drive", SCSIDevice, conf.bs),
+ DEFINE_PROP_INT32("bootindex", SCSIDevice, conf.bootindex, -1),
DEFINE_PROP_END_OF_LIST(),
};
diff --git a/hw/shpc.c b/hw/shpc.c
index 6b9884d54..a5baf246f 100644
--- a/hw/shpc.c
+++ b/hw/shpc.c
@@ -253,7 +253,6 @@ static void shpc_free_devices_in_slot(SHPCDevice *shpc, int slot)
++devfn) {
PCIDevice *affected_dev = shpc->sec_bus->devices[devfn];
if (affected_dev) {
- object_unparent(OBJECT(affected_dev));
qdev_free(&affected_dev->qdev);
}
}
diff --git a/hw/virtio-pci.c b/hw/virtio-pci.c
index 2a3d86f17..b3f0710f3 100644
--- a/hw/virtio-pci.c
+++ b/hw/virtio-pci.c
@@ -131,6 +131,7 @@ static int virtio_pci_load_config(void * opaque, QEMUFile *f)
if (ret) {
return ret;
}
+ msix_unuse_all_vectors(&proxy->pci_dev);
msix_load(&proxy->pci_dev, f);
if (msix_present(&proxy->pci_dev)) {
qemu_get_be16s(f, &proxy->vdev->config_vector);
@@ -246,6 +247,7 @@ void virtio_pci_reset(DeviceState *d)
VirtIOPCIProxy *proxy = container_of(d, VirtIOPCIProxy, pci_dev.qdev);
virtio_pci_stop_ioeventfd(proxy);
virtio_reset(proxy->vdev);
+ msix_unuse_all_vectors(&proxy->pci_dev);
proxy->flags &= ~VIRTIO_PCI_FLAG_BUS_MASTER_BUG;
}
diff --git a/hw/xen_platform.c b/hw/xen_platform.c
index c1fe984f0..0d6c2ff8c 100644
--- a/hw/xen_platform.c
+++ b/hw/xen_platform.c
@@ -87,9 +87,6 @@ static void unplug_nic(PCIBus *b, PCIDevice *d, void *o)
{
if (pci_get_word(d->config + PCI_CLASS_DEVICE) ==
PCI_CLASS_NETWORK_ETHERNET) {
- /* Until qdev_free includes a call to object_unparent, we call it here
- */
- object_unparent(&d->qdev.parent_obj);
qdev_free(&d->qdev);
}
}
diff --git a/linux-headers/asm-s390/kvm.h b/linux-headers/asm-s390/kvm.h
index bdcbe0f8d..d25da598e 100644
--- a/linux-headers/asm-s390/kvm.h
+++ b/linux-headers/asm-s390/kvm.h
@@ -1,7 +1,7 @@
#ifndef __LINUX_KVM_S390_H
#define __LINUX_KVM_S390_H
/*
- * asm-s390/kvm.h - KVM s390 specific structures and definitions
+ * KVM s390 specific structures and definitions
*
* Copyright IBM Corp. 2008
*
diff --git a/linux-headers/asm-s390/kvm_para.h b/linux-headers/asm-s390/kvm_para.h
index 8e2dd6706..870051f64 100644
--- a/linux-headers/asm-s390/kvm_para.h
+++ b/linux-headers/asm-s390/kvm_para.h
@@ -1,5 +1,5 @@
/*
- * asm-s390/kvm_para.h - definition for paravirtual devices on s390
+ * definition for paravirtual devices on s390
*
* Copyright IBM Corp. 2008
*
diff --git a/linux-headers/asm-x86/kvm.h b/linux-headers/asm-x86/kvm.h
index e7d1c194d..246617efd 100644
--- a/linux-headers/asm-x86/kvm.h
+++ b/linux-headers/asm-x86/kvm.h
@@ -12,6 +12,7 @@
/* Select x86 specific features in <linux/kvm.h> */
#define __KVM_HAVE_PIT
#define __KVM_HAVE_IOAPIC
+#define __KVM_HAVE_IRQ_LINE
#define __KVM_HAVE_DEVICE_ASSIGNMENT
#define __KVM_HAVE_MSI
#define __KVM_HAVE_USER_NMI
diff --git a/linux-headers/asm-x86/kvm_para.h b/linux-headers/asm-x86/kvm_para.h
index f2ac46a2a..a1c3d72ac 100644
--- a/linux-headers/asm-x86/kvm_para.h
+++ b/linux-headers/asm-x86/kvm_para.h
@@ -22,6 +22,7 @@
#define KVM_FEATURE_CLOCKSOURCE2 3
#define KVM_FEATURE_ASYNC_PF 4
#define KVM_FEATURE_STEAL_TIME 5
+#define KVM_FEATURE_PV_EOI 6
/* The last 8 bits are used to indicate how to interpret the flags field
* in pvclock structure. If no bits are set, all flags are ignored.
@@ -37,6 +38,7 @@
#define MSR_KVM_SYSTEM_TIME_NEW 0x4b564d01
#define MSR_KVM_ASYNC_PF_EN 0x4b564d02
#define MSR_KVM_STEAL_TIME 0x4b564d03
+#define MSR_KVM_PV_EOI_EN 0x4b564d04
struct kvm_steal_time {
__u64 steal;
@@ -89,5 +91,10 @@ struct kvm_vcpu_pv_apf_data {
__u32 enabled;
};
+#define KVM_PV_EOI_BIT 0
+#define KVM_PV_EOI_MASK (0x1 << KVM_PV_EOI_BIT)
+#define KVM_PV_EOI_ENABLED KVM_PV_EOI_MASK
+#define KVM_PV_EOI_DISABLED 0x0
+
#endif /* _ASM_X86_KVM_PARA_H */
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 5a9d4e350..4b9e575dd 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -617,6 +617,7 @@ struct kvm_ppc_smmu_info {
#define KVM_CAP_SIGNAL_MSI 77
#define KVM_CAP_PPC_GET_SMMU_INFO 78
#define KVM_CAP_S390_COW 79
+#define KVM_CAP_PPC_ALLOC_HTAB 80
#ifdef KVM_CAP_IRQ_ROUTING
@@ -828,6 +829,8 @@ struct kvm_s390_ucas_mapping {
#define KVM_SIGNAL_MSI _IOW(KVMIO, 0xa5, struct kvm_msi)
/* Available with KVM_CAP_PPC_GET_SMMU_INFO */
#define KVM_PPC_GET_SMMU_INFO _IOR(KVMIO, 0xa6, struct kvm_ppc_smmu_info)
+/* Available with KVM_CAP_PPC_ALLOC_HTAB */
+#define KVM_PPC_ALLOCATE_HTAB _IOWR(KVMIO, 0xa7, __u32)
/*
* ioctls for vcpu fds
diff --git a/linux-user/main.c b/linux-user/main.c
index 7dea08487..1a1c661ee 100644
--- a/linux-user/main.c
+++ b/linux-user/main.c
@@ -3222,7 +3222,7 @@ struct qemu_argument {
const char *help;
};
-struct qemu_argument arg_table[] = {
+static const struct qemu_argument arg_table[] = {
{"h", "", false, handle_arg_help,
"", "print this help"},
{"g", "QEMU_GDB", true, handle_arg_gdb,
@@ -3264,7 +3264,7 @@ struct qemu_argument arg_table[] = {
static void usage(void)
{
- struct qemu_argument *arginfo;
+ const struct qemu_argument *arginfo;
int maxarglen;
int maxenvlen;
@@ -3330,7 +3330,7 @@ static int parse_args(int argc, char **argv)
{
const char *r;
int optind;
- struct qemu_argument *arginfo;
+ const struct qemu_argument *arginfo;
for (arginfo = arg_table; arginfo->handle_opt != NULL; arginfo++) {
if (arginfo->env == NULL) {
@@ -3519,7 +3519,10 @@ int main(int argc, char **argv, char **envp)
guest_base = init_guest_space(guest_base, reserved_va, 0,
have_guest_base);
if (guest_base == (unsigned long)-1) {
- fprintf(stderr, "Unable to reserve guest address space\n");
+ fprintf(stderr, "Unable to reserve 0x%lx bytes of virtual address "
+ "space for use as guest address space (check your virtual "
+ "memory ulimit setting or reserve less using -R option)\n",
+ reserved_va);
exit(1);
}
diff --git a/linux-user/syscall.c b/linux-user/syscall.c
index 11743065e..6257a04d0 100644
--- a/linux-user/syscall.c
+++ b/linux-user/syscall.c
@@ -7025,15 +7025,14 @@ abi_long do_syscall(void *cpu_env, int num, abi_long arg1,
tde = target_dirp;
while (len > 0) {
reclen = de->d_reclen;
- treclen = reclen - (2 * (sizeof(long) - sizeof(abi_long)));
+ tnamelen = reclen - offsetof(struct linux_dirent, d_name);
+ assert(tnamelen >= 0);
+ treclen = tnamelen + offsetof(struct target_dirent, d_name);
+ assert(count1 + treclen <= count);
tde->d_reclen = tswap16(treclen);
tde->d_ino = tswapal(de->d_ino);
tde->d_off = tswapal(de->d_off);
- tnamelen = treclen - (2 * sizeof(abi_long) + 2);
- if (tnamelen > 256)
- tnamelen = 256;
- /* XXX: may not be correct */
- pstrcpy(tde->d_name, tnamelen, de->d_name);
+ memcpy(tde->d_name, de->d_name, tnamelen);
de = (struct linux_dirent *)((char *)de + reclen);
len -= reclen;
tde = (struct target_dirent *)((char *)tde + treclen);
diff --git a/linux-user/syscall_defs.h b/linux-user/syscall_defs.h
index 2cfda5afd..a98cbf7b8 100644
--- a/linux-user/syscall_defs.h
+++ b/linux-user/syscall_defs.h
@@ -255,10 +255,10 @@ struct kernel_statfs {
};
struct target_dirent {
- abi_long d_ino;
- abi_long d_off;
- unsigned short d_reclen;
- char d_name[256]; /* We must not include limits.h! */
+ abi_long d_ino;
+ abi_long d_off;
+ unsigned short d_reclen;
+ char d_name[];
};
struct target_dirent64 {
diff --git a/memory.c b/memory.c
index 643871baf..d528d1f7f 100644
--- a/memory.c
+++ b/memory.c
@@ -426,7 +426,7 @@ static void memory_region_iorange_write(IORange *iorange,
if (mrp) {
mrp->write(mr->opaque, offset, data);
} else if (width == 2) {
- mrp = find_portio(mr, offset - mrio->offset, 1, false);
+ mrp = find_portio(mr, offset - mrio->offset, 1, true);
assert(mrp);
mrp->write(mr->opaque, offset, data & 0xff);
mrp->write(mr->opaque, offset + 1, data >> 8);
diff --git a/pc-bios/README b/pc-bios/README
index fc07ebc21..303713099 100644
--- a/pc-bios/README
+++ b/pc-bios/README
@@ -12,7 +12,7 @@
1275-1994 (referred to as Open Firmware) compliant firmware.
The included images for PowerPC (for 32 and 64 bit PPC CPUs),
Sparc32 and Sparc64 are built from OpenBIOS SVN revision
- 1062.
+ 1063.
- SLOF (Slimline Open Firmware) is a free IEEE 1275 Open Firmware
implementation for certain IBM POWER hardware. The sources are at
diff --git a/pc-bios/openbios-ppc b/pc-bios/openbios-ppc
index 1c3753d3e..5311eca69 100644
--- a/pc-bios/openbios-ppc
+++ b/pc-bios/openbios-ppc
Binary files differ
diff --git a/qemu-ga.c b/qemu-ga.c
index 26671fee3..762307988 100644
--- a/qemu-ga.c
+++ b/qemu-ga.c
@@ -438,7 +438,9 @@ static void become_daemon(const char *pidfile)
return;
fail:
- unlink(pidfile);
+ if (pidfile) {
+ unlink(pidfile);
+ }
g_critical("failed to daemonize");
exit(EXIT_FAILURE);
#endif
diff --git a/qom/object.c b/qom/object.c
index a552be258..e3e924263 100644
--- a/qom/object.c
+++ b/qom/object.c
@@ -373,8 +373,6 @@ static void object_deinit(Object *obj, TypeImpl *type)
if (type_has_parent(type)) {
object_deinit(obj, type_get_parent(type));
}
-
- object_unparent(obj);
}
void object_finalize(void *data)
@@ -411,8 +409,9 @@ Object *object_new(const char *typename)
void object_delete(Object *obj)
{
+ object_unparent(obj);
+ g_assert(obj->ref == 1);
object_unref(obj);
- g_assert(obj->ref == 0);
g_free(obj);
}
diff --git a/roms/openbios b/roms/openbios
-Subproject d1d2787f87167edf487a60e61b9168514d5a743
+Subproject f095c858136896d236931357b8d597f407286f7
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 120a2e3d3..423e00905 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -33,6 +33,9 @@
#include "hyperv.h"
#include "hw/hw.h"
+#if defined(CONFIG_KVM)
+#include <linux/kvm_para.h>
+#endif
/* feature flags taken from "Intel Processor Identification and the CPUID
* Instruction" and AMD's "CPUID Specification". In cases of disagreement
@@ -887,7 +890,17 @@ static int cpu_x86_find_by_name(x86_def_t *x86_cpu_def, const char *cpu_model)
memcpy(x86_cpu_def, def, sizeof(*def));
}
- plus_kvm_features = ~0; /* not supported bits will be filtered out later */
+#if defined(CONFIG_KVM)
+ plus_kvm_features = (1 << KVM_FEATURE_CLOCKSOURCE) |
+ (1 << KVM_FEATURE_NOP_IO_DELAY) |
+ (1 << KVM_FEATURE_MMU_OP) |
+ (1 << KVM_FEATURE_CLOCKSOURCE2) |
+ (1 << KVM_FEATURE_ASYNC_PF) |
+ (1 << KVM_FEATURE_STEAL_TIME) |
+ (1 << KVM_FEATURE_CLOCKSOURCE_STABLE_BIT);
+#else
+ plus_kvm_features = 0;
+#endif
add_flagname_to_bitmaps("hypervisor", &plus_features,
&plus_ext_features, &plus_ext2_features, &plus_ext3_features,
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index aabf99395..3c57d8b6b 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -699,6 +699,7 @@ typedef struct CPUX86State {
uint64_t system_time_msr;
uint64_t wall_clock_msr;
uint64_t async_pf_en_msr;
+ uint64_t pv_eoi_en_msr;
uint64_t tsc;
uint64_t tsc_deadline;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 5e2d4f5db..6790180b0 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -64,6 +64,7 @@ static bool has_msr_star;
static bool has_msr_hsave_pa;
static bool has_msr_tsc_deadline;
static bool has_msr_async_pf_en;
+static bool has_msr_pv_eoi_en;
static bool has_msr_misc_enable;
static int lm_capable_kernel;
@@ -456,6 +457,8 @@ int kvm_arch_init_vcpu(CPUX86State *env)
has_msr_async_pf_en = c->eax & (1 << KVM_FEATURE_ASYNC_PF);
+ has_msr_pv_eoi_en = c->eax & (1 << KVM_FEATURE_PV_EOI);
+
cpu_x86_cpuid(env, 0, 0, &limit, &unused, &unused, &unused);
for (i = 0; i <= limit; i++) {
@@ -1018,6 +1021,10 @@ static int kvm_put_msrs(CPUX86State *env, int level)
kvm_msr_entry_set(&msrs[n++], MSR_KVM_ASYNC_PF_EN,
env->async_pf_en_msr);
}
+ if (has_msr_pv_eoi_en) {
+ kvm_msr_entry_set(&msrs[n++], MSR_KVM_PV_EOI_EN,
+ env->pv_eoi_en_msr);
+ }
if (hyperv_hypercall_available()) {
kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_GUEST_OS_ID, 0);
kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_HYPERCALL, 0);
@@ -1260,6 +1267,9 @@ static int kvm_get_msrs(CPUX86State *env)
if (has_msr_async_pf_en) {
msrs[n++].index = MSR_KVM_ASYNC_PF_EN;
}
+ if (has_msr_pv_eoi_en) {
+ msrs[n++].index = MSR_KVM_PV_EOI_EN;
+ }
if (env->mcg_cap) {
msrs[n++].index = MSR_MCG_STATUS;
@@ -1339,6 +1349,9 @@ static int kvm_get_msrs(CPUX86State *env)
case MSR_KVM_ASYNC_PF_EN:
env->async_pf_en_msr = msrs[i].data;
break;
+ case MSR_KVM_PV_EOI_EN:
+ env->pv_eoi_en_msr = msrs[i].data;
+ break;
}
}
diff --git a/target-i386/machine.c b/target-i386/machine.c
index a8be058d2..477150887 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -279,6 +279,13 @@ static bool async_pf_msr_needed(void *opaque)
return cpu->async_pf_en_msr != 0;
}
+static bool pv_eoi_msr_needed(void *opaque)
+{
+ CPUX86State *cpu = opaque;
+
+ return cpu->pv_eoi_en_msr != 0;
+}
+
static const VMStateDescription vmstate_async_pf_msr = {
.name = "cpu/async_pf_msr",
.version_id = 1,
@@ -290,6 +297,17 @@ static const VMStateDescription vmstate_async_pf_msr = {
}
};
+static const VMStateDescription vmstate_pv_eoi_msr = {
+ .name = "cpu/async_pv_eoi_msr",
+ .version_id = 1,
+ .minimum_version_id = 1,
+ .minimum_version_id_old = 1,
+ .fields = (VMStateField []) {
+ VMSTATE_UINT64(pv_eoi_en_msr, CPUX86State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
static bool fpop_ip_dp_needed(void *opaque)
{
CPUX86State *env = opaque;
@@ -454,6 +472,9 @@ static const VMStateDescription vmstate_cpu = {
.vmsd = &vmstate_async_pf_msr,
.needed = async_pf_msr_needed,
} , {
+ .vmsd = &vmstate_pv_eoi_msr,
+ .needed = pv_eoi_msr_needed,
+ } , {
.vmsd = &vmstate_fpop_ip_dp,
.needed = fpop_ip_dp_needed,
}, {
diff --git a/target-i386/translate.c b/target-i386/translate.c
index 7ab2ccb19..eb0cabcf1 100644
--- a/target-i386/translate.c
+++ b/target-i386/translate.c
@@ -7551,8 +7551,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
modrm = cpu_ldub_code(cpu_single_env, s->pc++);
- if ((modrm & 0xc0) != 0xc0)
- goto illegal_op;
+ /* Ignore the mod bits (assume (modrm&0xc0)==0xc0).
+ * AMD documentation (24594.pdf) and testing of
+ * intel 386 and 486 processors all show that the mod bits
+ * are assumed to be 1's, regardless of actual values.
+ */
rm = (modrm & 7) | REX_B(s);
reg = ((modrm >> 3) & 7) | rex_r;
if (CODE64(s))
@@ -7594,8 +7597,11 @@ static target_ulong disas_insn(DisasContext *s, target_ulong pc_start)
gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
} else {
modrm = cpu_ldub_code(cpu_single_env, s->pc++);
- if ((modrm & 0xc0) != 0xc0)
- goto illegal_op;
+ /* Ignore the mod bits (assume (modrm&0xc0)==0xc0).
+ * AMD documentation (24594.pdf) and testing of
+ * intel 386 and 486 processors all show that the mod bits
+ * are assumed to be 1's, regardless of actual values.
+ */
rm = (modrm & 7) | REX_B(s);
reg = ((modrm >> 3) & 7) | rex_r;
if (CODE64(s))
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index 66037acec..e5bc93e22 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -192,115 +192,98 @@ static inline uint64_t get_HILO (void)
return ((uint64_t)(env->active_tc.HI[0]) << 32) | (uint32_t)env->active_tc.LO[0];
}
-static inline void set_HIT0_LO (target_ulong arg1, uint64_t HILO)
+static inline target_ulong set_HIT0_LO(uint64_t HILO)
{
+ target_ulong tmp;
env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
- arg1 = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
+ tmp = env->active_tc.HI[0] = (int32_t)(HILO >> 32);
+ return tmp;
}
-static inline void set_HI_LOT0 (target_ulong arg1, uint64_t HILO)
+static inline target_ulong set_HI_LOT0(uint64_t HILO)
{
- arg1 = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
+ target_ulong tmp = env->active_tc.LO[0] = (int32_t)(HILO & 0xFFFFFFFF);
env->active_tc.HI[0] = (int32_t)(HILO >> 32);
+ return tmp;
}
/* Multiplication variants of the vr54xx. */
target_ulong helper_muls (target_ulong arg1, target_ulong arg2)
{
- set_HI_LOT0(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
-
- return arg1;
+ return set_HI_LOT0(0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
}
target_ulong helper_mulsu (target_ulong arg1, target_ulong arg2)
{
- set_HI_LOT0(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
-
- return arg1;
+ return set_HI_LOT0(0 - (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
}
target_ulong helper_macc (target_ulong arg1, target_ulong arg2)
{
- set_HI_LOT0(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
-
- return arg1;
+ return set_HI_LOT0((int64_t)get_HILO() + (int64_t)(int32_t)arg1 *
+ (int64_t)(int32_t)arg2);
}
target_ulong helper_macchi (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, ((int64_t)get_HILO()) + ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
-
- return arg1;
+ return set_HIT0_LO((int64_t)get_HILO() + (int64_t)(int32_t)arg1 *
+ (int64_t)(int32_t)arg2);
}
target_ulong helper_maccu (target_ulong arg1, target_ulong arg2)
{
- set_HI_LOT0(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
-
- return arg1;
+ return set_HI_LOT0((uint64_t)get_HILO() + (uint64_t)(uint32_t)arg1 *
+ (uint64_t)(uint32_t)arg2);
}
target_ulong helper_macchiu (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, ((uint64_t)get_HILO()) + ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
-
- return arg1;
+ return set_HIT0_LO((uint64_t)get_HILO() + (uint64_t)(uint32_t)arg1 *
+ (uint64_t)(uint32_t)arg2);
}
target_ulong helper_msac (target_ulong arg1, target_ulong arg2)
{
- set_HI_LOT0(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
-
- return arg1;
+ return set_HI_LOT0((int64_t)get_HILO() - (int64_t)(int32_t)arg1 *
+ (int64_t)(int32_t)arg2);
}
target_ulong helper_msachi (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, ((int64_t)get_HILO()) - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
-
- return arg1;
+ return set_HIT0_LO((int64_t)get_HILO() - (int64_t)(int32_t)arg1 *
+ (int64_t)(int32_t)arg2);
}
target_ulong helper_msacu (target_ulong arg1, target_ulong arg2)
{
- set_HI_LOT0(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
-
- return arg1;
+ return set_HI_LOT0((uint64_t)get_HILO() - (uint64_t)(uint32_t)arg1 *
+ (uint64_t)(uint32_t)arg2);
}
target_ulong helper_msachiu (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, ((uint64_t)get_HILO()) - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
-
- return arg1;
+ return set_HIT0_LO((uint64_t)get_HILO() - (uint64_t)(uint32_t)arg1 *
+ (uint64_t)(uint32_t)arg2);
}
target_ulong helper_mulhi (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
-
- return arg1;
+ return set_HIT0_LO((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
}
target_ulong helper_mulhiu (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
-
- return arg1;
+ return set_HIT0_LO((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
}
target_ulong helper_mulshi (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, 0 - ((int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2));
-
- return arg1;
+ return set_HIT0_LO(0 - (int64_t)(int32_t)arg1 * (int64_t)(int32_t)arg2);
}
target_ulong helper_mulshiu (target_ulong arg1, target_ulong arg2)
{
- set_HIT0_LO(arg1, 0 - ((uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2));
-
- return arg1;
+ return set_HIT0_LO(0 - (uint64_t)(uint32_t)arg1 * (uint64_t)(uint32_t)arg2);
}
#ifdef TARGET_MIPS64
diff --git a/target-mips/translate.c b/target-mips/translate.c
index d643676e5..b29341953 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -5933,6 +5933,7 @@ static void gen_cp0 (CPUMIPSState *env, DisasContext *ctx, uint32_t opc, int rt,
{
const char *opn = "ldst";
+ check_cp0_enabled(ctx);
switch (opc) {
case OPC_MFC0:
if (rt == 0) {
@@ -6805,7 +6806,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
TCGv_i32 fp1 = tcg_temp_new_i32();
gen_load_fpr32(fp0, fs);
- gen_load_fpr32(fp1, fd);
+ gen_load_fpr32(fp1, ft);
gen_helper_float_recip2_s(fp0, fp0, fp1);
tcg_temp_free_i32(fp1);
gen_store_fpr32(fp0, fd);
@@ -6900,7 +6901,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
gen_load_fpr32(fp32_0, fs);
gen_load_fpr32(fp32_1, ft);
- tcg_gen_concat_i32_i64(fp64, fp32_0, fp32_1);
+ tcg_gen_concat_i32_i64(fp64, fp32_1, fp32_0);
tcg_temp_free_i32(fp32_1);
tcg_temp_free_i32(fp32_0);
gen_store_fpr64(ctx, fp64, fd);
@@ -7543,7 +7544,7 @@ static void gen_farith (DisasContext *ctx, enum fopcode op1,
TCGv_i64 fp1 = tcg_temp_new_i64();
gen_load_fpr64(ctx, fp0, fs);
- gen_load_fpr64(ctx, fp1, fd);
+ gen_load_fpr64(ctx, fp1, ft);
gen_helper_float_recip2_ps(fp0, fp0, fp1);
tcg_temp_free_i64(fp1);
gen_store_fpr64(ctx, fp0, fd);
@@ -7742,8 +7743,7 @@ static void gen_flt3_ldst (DisasContext *ctx, uint32_t opc,
} else if (index == 0) {
gen_load_gpr(t0, base);
} else {
- gen_load_gpr(t0, index);
- gen_op_addr_add(ctx, t0, cpu_gpr[base], t0);
+ gen_op_addr_add(ctx, t0, cpu_gpr[base], cpu_gpr[index]);
}
/* Don't do NOP if destination is zero: we must perform the actual
memory access. */
@@ -8112,7 +8112,11 @@ gen_rdhwr (CPUMIPSState *env, DisasContext *ctx, int rt, int rd)
{
TCGv t0;
+#if !defined(CONFIG_USER_ONLY)
+ /* The Linux kernel will emulate rdhwr if it's not supported natively.
+ Therefore only check the ISA in system mode. */
check_insn(env, ctx, ISA_MIPS32R2);
+#endif
t0 = tcg_temp_new();
switch (rd) {
@@ -10027,7 +10031,7 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
const char *opn = "ldst_pair";
TCGv t0, t1;
- if (ctx->hflags & MIPS_HFLAG_BMASK || rd == 31 || rd == base) {
+ if (ctx->hflags & MIPS_HFLAG_BMASK || rd == 31) {
generate_exception(ctx, EXCP_RI);
return;
}
@@ -10039,6 +10043,10 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
switch (opc) {
case LWP:
+ if (rd == base) {
+ generate_exception(ctx, EXCP_RI);
+ return;
+ }
save_cpu_state(ctx, 0);
op_ld_lw(t1, t0, ctx);
gen_store_gpr(t1, rd);
@@ -10060,6 +10068,10 @@ static void gen_ldst_pair (DisasContext *ctx, uint32_t opc, int rd,
break;
#ifdef TARGET_MIPS64
case LDP:
+ if (rd == base) {
+ generate_exception(ctx, EXCP_RI);
+ return;
+ }
save_cpu_state(ctx, 0);
op_ld_ld(t1, t0, ctx);
gen_store_gpr(t1, rd);
@@ -10118,6 +10130,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs,
#ifndef CONFIG_USER_ONLY
case MFC0:
case MFC0 + 32:
+ check_cp0_enabled(ctx);
if (rt == 0) {
/* Treat as NOP. */
break;
@@ -10126,6 +10139,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs,
break;
case MTC0:
case MTC0 + 32:
+ check_cp0_enabled(ctx);
{
TCGv t0 = tcg_temp_new();
@@ -10222,10 +10236,12 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs,
case 0x05:
switch (minor) {
case RDPGPR:
+ check_cp0_enabled(ctx);
check_insn(env, ctx, ISA_MIPS32R2);
gen_load_srsgpr(rt, rs);
break;
case WRPGPR:
+ check_cp0_enabled(ctx);
check_insn(env, ctx, ISA_MIPS32R2);
gen_store_srsgpr(rt, rs);
break;
@@ -10266,6 +10282,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs,
case 0x1d:
switch (minor) {
case DI:
+ check_cp0_enabled(ctx);
{
TCGv t0 = tcg_temp_new();
@@ -10278,6 +10295,7 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs,
}
break;
case EI:
+ check_cp0_enabled(ctx);
{
TCGv t0 = tcg_temp_new();
@@ -10758,6 +10776,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx,
minor = (ctx->opcode >> 12) & 0xf;
switch (minor) {
case CACHE:
+ check_cp0_enabled(ctx);
/* Treat as no-op. */
break;
case LWC2:
@@ -12208,6 +12227,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int *is_branch)
gen_st_cond(ctx, op, rt, rs, imm);
break;
case OPC_CACHE:
+ check_cp0_enabled(ctx);
check_insn(env, ctx, ISA_MIPS3 | ISA_MIPS32);
/* Treat as NOP. */
break;
diff --git a/target-ppc/translate.c b/target-ppc/translate.c
index 91eb7a062..ac915ccad 100644
--- a/target-ppc/translate.c
+++ b/target-ppc/translate.c
@@ -6530,7 +6530,7 @@ static void glue(gen_, name)(DisasContext *ctx) \
ra = gen_avr_ptr(rA(ctx->opcode)); \
rb = gen_avr_ptr(rB(ctx->opcode)); \
rd = gen_avr_ptr(rD(ctx->opcode)); \
- gen_helper_##name(rd, cpu_env, ra, rb); \
+ gen_helper_##name(cpu_env, rd, ra, rb); \
tcg_temp_free_ptr(ra); \
tcg_temp_free_ptr(rb); \
tcg_temp_free_ptr(rd); \
diff --git a/tcg/arm/tcg-target.c b/tcg/arm/tcg-target.c
index 4d59a6385..cf0ca3d0b 100644
--- a/tcg/arm/tcg-target.c
+++ b/tcg/arm/tcg-target.c
@@ -176,6 +176,13 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
so don't use these. */
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
+#if defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64)
+ /* If we're passing env to the helper as r0 and need a regpair
+ * for the address then r2 will be overwritten as we're setting
+ * up the args to the helper.
+ */
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2);
+#endif
#endif
break;
case 'L':
@@ -197,6 +204,12 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
use these. */
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R0);
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R1);
+#if defined(CONFIG_SOFTMMU) && \
+ defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64)
+ /* Avoid clashes with registers being used for helper args */
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2);
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
+#endif
break;
/* qemu_st64 data_reg2 */
case 'S':
@@ -210,6 +223,10 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
#ifdef CONFIG_SOFTMMU
/* r2 is still needed to load data_reg, so don't use it. */
tcg_regset_reset_reg(ct->u.regs, TCG_REG_R2);
+#if defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64)
+ /* Avoid clashes with registers being used for helper args */
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_R3);
+#endif
#endif
break;
@@ -388,6 +405,14 @@ static inline void tcg_out_dat_reg(TCGContext *s,
(rn << 16) | (rd << 12) | shift | rm);
}
+static inline void tcg_out_mov_reg(TCGContext *s, int cond, int rd, int rm)
+{
+ /* Simple reg-reg move, optimising out the 'do nothing' case */
+ if (rd != rm) {
+ tcg_out_dat_reg(s, cond, ARITH_MOV, rd, 0, rm, SHIFT_IMM_LSL(0));
+ }
+}
+
static inline void tcg_out_dat_reg2(TCGContext *s,
int cond, int opc0, int opc1, int rd0, int rd1,
int rn0, int rn1, int rm0, int rm1, int shift)
@@ -966,6 +991,90 @@ static void *qemu_st_helpers[4] = {
__stq_mmu,
};
#endif
+
+/* Helper routines for marshalling helper function arguments into
+ * the correct registers and stack.
+ * argreg is where we want to put this argument, arg is the argument itself.
+ * Return value is the updated argreg ready for the next call.
+ * Note that argreg 0..3 is real registers, 4+ on stack.
+ * When we reach the first stacked argument, we allocate space for it
+ * and the following stacked arguments using "str r8, [sp, #-0x10]!".
+ * Following arguments are filled in with "str r8, [sp, #0xNN]".
+ * For more than 4 stacked arguments we'd need to know how much
+ * space to allocate when we pushed the first stacked argument.
+ * We don't need this, so don't implement it (and will assert if you try it.)
+ *
+ * We provide routines for arguments which are: immediate, 32 bit
+ * value in register, 16 and 8 bit values in register (which must be zero
+ * extended before use) and 64 bit value in a lo:hi register pair.
+ */
+#define DEFINE_TCG_OUT_ARG(NAME, ARGPARAM) \
+ static TCGReg NAME(TCGContext *s, TCGReg argreg, ARGPARAM) \
+ { \
+ if (argreg < 4) { \
+ TCG_OUT_ARG_GET_ARG(argreg); \
+ } else if (argreg == 4) { \
+ TCG_OUT_ARG_GET_ARG(TCG_REG_R8); \
+ tcg_out32(s, (COND_AL << 28) | 0x052d8010); \
+ } else { \
+ assert(argreg < 8); \
+ TCG_OUT_ARG_GET_ARG(TCG_REG_R8); \
+ tcg_out32(s, (COND_AL << 28) | 0x058d8000 | (argreg - 4) * 4); \
+ } \
+ return argreg + 1; \
+ }
+
+#define TCG_OUT_ARG_GET_ARG(A) tcg_out_dat_imm(s, COND_AL, ARITH_MOV, A, 0, arg)
+DEFINE_TCG_OUT_ARG(tcg_out_arg_imm32, uint32_t arg)
+#undef TCG_OUT_ARG_GET_ARG
+#define TCG_OUT_ARG_GET_ARG(A) tcg_out_ext8u(s, COND_AL, A, arg)
+DEFINE_TCG_OUT_ARG(tcg_out_arg_reg8, TCGReg arg)
+#undef TCG_OUT_ARG_GET_ARG
+#define TCG_OUT_ARG_GET_ARG(A) tcg_out_ext16u(s, COND_AL, A, arg)
+DEFINE_TCG_OUT_ARG(tcg_out_arg_reg16, TCGReg arg)
+#undef TCG_OUT_ARG_GET_ARG
+
+/* We don't use the macro for this one to avoid an unnecessary reg-reg
+ * move when storing to the stack.
+ */
+static TCGReg tcg_out_arg_reg32(TCGContext *s, TCGReg argreg, TCGReg arg)
+{
+ if (argreg < 4) {
+ tcg_out_mov_reg(s, COND_AL, argreg, arg);
+ } else if (argreg == 4) {
+ /* str arg, [sp, #-0x10]! */
+ tcg_out32(s, (COND_AL << 28) | 0x052d0010 | (arg << 12));
+ } else {
+ assert(argreg < 8);
+ /* str arg, [sp, #0xNN] */
+ tcg_out32(s, (COND_AL << 28) | 0x058d0000 |
+ (arg << 12) | (argreg - 4) * 4);
+ }
+ return argreg + 1;
+}
+
+static inline TCGReg tcg_out_arg_reg64(TCGContext *s, TCGReg argreg,
+ TCGReg arglo, TCGReg arghi)
+{
+ /* 64 bit arguments must go in even/odd register pairs
+ * and in 8-aligned stack slots.
+ */
+ if (argreg & 1) {
+ argreg++;
+ }
+ argreg = tcg_out_arg_reg32(s, argreg, arglo);
+ argreg = tcg_out_arg_reg32(s, argreg, arghi);
+ return argreg;
+}
+
+static inline void tcg_out_arg_stacktidy(TCGContext *s, TCGReg argreg)
+{
+ /* Output any necessary post-call cleanup of the stack */
+ if (argreg > 4) {
+ tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10);
+ }
+}
+
#endif
#define TLB_SHIFT (CPU_TLB_ENTRY_BITS + CPU_TLB_BITS)
@@ -975,6 +1084,7 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
int addr_reg, data_reg, data_reg2, bswap;
#ifdef CONFIG_SOFTMMU
int mem_index, s_bits;
+ TCGReg argreg;
# if TARGET_LONG_BITS == 64
int addr_reg2;
# endif
@@ -1088,31 +1198,22 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
tcg_out_b_noaddr(s, COND_EQ);
/* TODO: move this code to where the constants pool will be */
- if (addr_reg != TCG_REG_R0) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R0, 0, addr_reg, SHIFT_IMM_LSL(0));
- }
-# if TARGET_LONG_BITS == 32
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R1, 0, mem_index);
-# else
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
-# endif
+ /* Note that this code relies on the constraints we set in arm_op_defs[]
+ * to ensure that later arguments are not passed to us in registers we
+ * trash by moving the earlier arguments into them.
+ */
+ argreg = TCG_REG_R0;
#ifdef CONFIG_TCG_PASS_AREG0
- /* XXX/FIXME: suboptimal and incorrect for 64 bit */
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[2], 0,
- tcg_target_call_iarg_regs[1], SHIFT_IMM_LSL(0));
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[1], 0,
- tcg_target_call_iarg_regs[0], SHIFT_IMM_LSL(0));
-
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[0], 0, TCG_AREG0,
- SHIFT_IMM_LSL(0));
+ argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0);
#endif
+#if TARGET_LONG_BITS == 64
+ argreg = tcg_out_arg_reg64(s, argreg, addr_reg, addr_reg2);
+#else
+ argreg = tcg_out_arg_reg32(s, argreg, addr_reg);
+#endif
+ argreg = tcg_out_arg_imm32(s, argreg, mem_index);
tcg_out_call(s, (tcg_target_long) qemu_ld_helpers[s_bits]);
+ tcg_out_arg_stacktidy(s, argreg);
switch (opc) {
case 0 | 4:
@@ -1211,6 +1312,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
int addr_reg, data_reg, data_reg2, bswap;
#ifdef CONFIG_SOFTMMU
int mem_index, s_bits;
+ TCGReg argreg;
# if TARGET_LONG_BITS == 64
int addr_reg2;
# endif
@@ -1314,89 +1416,38 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
tcg_out_b_noaddr(s, COND_EQ);
/* TODO: move this code to where the constants pool will be */
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R0, 0, addr_reg, SHIFT_IMM_LSL(0));
-# if TARGET_LONG_BITS == 32
- switch (opc) {
- case 0:
- tcg_out_ext8u(s, COND_AL, TCG_REG_R1, data_reg);
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
- break;
- case 1:
- tcg_out_ext16u(s, COND_AL, TCG_REG_R1, data_reg);
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
- break;
- case 2:
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R1, 0, data_reg, SHIFT_IMM_LSL(0));
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R2, 0, mem_index);
- break;
- case 3:
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R8, 0, mem_index);
- tcg_out32(s, (COND_AL << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */
- if (data_reg != TCG_REG_R2) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
- }
- if (data_reg2 != TCG_REG_R3) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R3, 0, data_reg2, SHIFT_IMM_LSL(0));
- }
- break;
- }
-# else
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R1, 0, addr_reg2, SHIFT_IMM_LSL(0));
+ /* Note that this code relies on the constraints we set in arm_op_defs[]
+ * to ensure that later arguments are not passed to us in registers we
+ * trash by moving the earlier arguments into them.
+ */
+ argreg = TCG_REG_R0;
+#ifdef CONFIG_TCG_PASS_AREG0
+ argreg = tcg_out_arg_reg32(s, argreg, TCG_AREG0);
+#endif
+#if TARGET_LONG_BITS == 64
+ argreg = tcg_out_arg_reg64(s, argreg, addr_reg, addr_reg2);
+#else
+ argreg = tcg_out_arg_reg32(s, argreg, addr_reg);
+#endif
+
switch (opc) {
case 0:
- tcg_out_ext8u(s, COND_AL, TCG_REG_R2, data_reg);
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+ argreg = tcg_out_arg_reg8(s, argreg, data_reg);
break;
case 1:
- tcg_out_ext16u(s, COND_AL, TCG_REG_R2, data_reg);
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+ argreg = tcg_out_arg_reg16(s, argreg, data_reg);
break;
case 2:
- if (data_reg != TCG_REG_R2) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
- }
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R3, 0, mem_index);
+ argreg = tcg_out_arg_reg32(s, argreg, data_reg);
break;
case 3:
- tcg_out_dat_imm(s, COND_AL, ARITH_MOV, TCG_REG_R8, 0, mem_index);
- tcg_out32(s, (COND_AL << 28) | 0x052d8010); /* str r8, [sp, #-0x10]! */
- if (data_reg != TCG_REG_R2) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R2, 0, data_reg, SHIFT_IMM_LSL(0));
- }
- if (data_reg2 != TCG_REG_R3) {
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- TCG_REG_R3, 0, data_reg2, SHIFT_IMM_LSL(0));
- }
+ argreg = tcg_out_arg_reg64(s, argreg, data_reg, data_reg2);
break;
}
-# endif
-
-#ifdef CONFIG_TCG_PASS_AREG0
- /* XXX/FIXME: suboptimal and incorrect for 64 bit */
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[3], 0,
- tcg_target_call_iarg_regs[2], SHIFT_IMM_LSL(0));
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[2], 0,
- tcg_target_call_iarg_regs[1], SHIFT_IMM_LSL(0));
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[1], 0,
- tcg_target_call_iarg_regs[0], SHIFT_IMM_LSL(0));
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV,
- tcg_target_call_iarg_regs[0], 0, TCG_AREG0,
- SHIFT_IMM_LSL(0));
-#endif
+ argreg = tcg_out_arg_imm32(s, argreg, mem_index);
tcg_out_call(s, (tcg_target_long) qemu_st_helpers[s_bits]);
- if (opc == 3)
- tcg_out_dat_imm(s, COND_AL, ARITH_ADD, TCG_REG_R13, TCG_REG_R13, 0x10);
+ tcg_out_arg_stacktidy(s, argreg);
reloc_pc24(label_ptr, (tcg_target_long)s->code_ptr);
#else /* !CONFIG_SOFTMMU */
diff --git a/tcg/ia64/tcg-target.c b/tcg/ia64/tcg-target.c
index e02dacc84..dc588dbea 100644
--- a/tcg/ia64/tcg-target.c
+++ b/tcg/ia64/tcg-target.c
@@ -107,7 +107,7 @@ enum {
};
static const int tcg_target_reg_alloc_order[] = {
- TCG_REG_R34,
+ TCG_REG_R33,
TCG_REG_R35,
TCG_REG_R36,
TCG_REG_R37,
@@ -1532,12 +1532,13 @@ static inline void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, int opc)
}
#ifdef CONFIG_TCG_PASS_AREG0
/* XXX/FIXME: suboptimal */
- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2],
- tcg_target_call_iarg_regs[1]);
- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
- tcg_target_call_iarg_regs[0]);
- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
- TCG_AREG0);
+ tcg_out_bundle(s, mII,
+ tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R58,
+ mem_index, TCG_REG_R0),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R57, 0, TCG_REG_R56),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R56, 0, TCG_AREG0));
#endif
if (!bswap || s_bits == 0) {
tcg_out_bundle(s, miB,
@@ -1659,15 +1660,21 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
#ifdef CONFIG_TCG_PASS_AREG0
/* XXX/FIXME: suboptimal */
- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3],
- tcg_target_call_iarg_regs[2]);
- tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
- tcg_target_call_iarg_regs[1]);
- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
- tcg_target_call_iarg_regs[0]);
- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
- TCG_AREG0);
-#endif
+ tcg_out_bundle(s, mII,
+ tcg_opc_a5 (TCG_REG_P7, OPC_ADDL_A5, TCG_REG_R59,
+ mem_index, TCG_REG_R0),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R58, 0, TCG_REG_R57),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R57, 0, TCG_REG_R56));
+ tcg_out_bundle(s, miB,
+ tcg_opc_m4 (TCG_REG_P6, opc_st_m4[opc],
+ data_reg, TCG_REG_R3),
+ tcg_opc_a4 (TCG_REG_P7, OPC_ADDS_A4,
+ TCG_REG_R56, 0, TCG_AREG0),
+ tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
+ TCG_REG_B0, TCG_REG_B6));
+#else
tcg_out_bundle(s, miB,
tcg_opc_m4 (TCG_REG_P6, opc_st_m4[opc],
data_reg, TCG_REG_R3),
@@ -1675,6 +1682,7 @@ static inline void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, int opc)
mem_index, TCG_REG_R0),
tcg_opc_b5 (TCG_REG_P7, OPC_BR_CALL_SPTK_MANY_B5,
TCG_REG_B0, TCG_REG_B6));
+#endif
}
#else /* !CONFIG_SOFTMMU */
@@ -2314,13 +2322,13 @@ static void tcg_target_qemu_prologue(TCGContext *s)
s->code_ptr += 16; /* skip GP */
/* prologue */
- tcg_out_bundle(s, mII,
+ tcg_out_bundle(s, miI,
tcg_opc_m34(TCG_REG_P0, OPC_ALLOC_M34,
- TCG_REG_R33, 32, 24, 0),
+ TCG_REG_R34, 32, 24, 0),
+ tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
+ TCG_AREG0, 0, TCG_REG_R32),
tcg_opc_i21(TCG_REG_P0, OPC_MOV_I21,
- TCG_REG_B6, TCG_REG_R33, 0),
- tcg_opc_i22(TCG_REG_P0, OPC_MOV_I22,
- TCG_REG_R32, TCG_REG_B0));
+ TCG_REG_B6, TCG_REG_R33, 0));
/* ??? If GUEST_BASE < 0x200000, we could load the register via
an ADDL in the M slot of the next bundle. */
@@ -2335,9 +2343,9 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_bundle(s, miB,
tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
- TCG_AREG0, 0, TCG_REG_R32),
- tcg_opc_a4 (TCG_REG_P0, OPC_ADDS_A4,
TCG_REG_R12, -frame_size, TCG_REG_R12),
+ tcg_opc_i22(TCG_REG_P0, OPC_MOV_I22,
+ TCG_REG_R32, TCG_REG_B0),
tcg_opc_b4 (TCG_REG_P0, OPC_BR_SPTK_MANY_B4, TCG_REG_B6));
/* epilogue */
@@ -2351,7 +2359,7 @@ static void tcg_target_qemu_prologue(TCGContext *s)
tcg_out_bundle(s, miB,
tcg_opc_m48(TCG_REG_P0, OPC_NOP_M48, 0),
tcg_opc_i26(TCG_REG_P0, OPC_MOV_I_I26,
- TCG_REG_PFS, TCG_REG_R33),
+ TCG_REG_PFS, TCG_REG_R34),
tcg_opc_b4 (TCG_REG_P0, OPC_BR_RET_SPTK_MANY_B4,
TCG_REG_B0));
}
@@ -2403,7 +2411,7 @@ static void tcg_target_init(TCGContext *s)
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R12); /* stack pointer */
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R13); /* thread pointer */
tcg_regset_set_reg(s->reserved_regs, TCG_REG_R32); /* return address */
- tcg_regset_set_reg(s->reserved_regs, TCG_REG_R33); /* PFS */
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_R34); /* PFS */
/* The following 3 are not in use, are call-saved, but *not* saved
by the prologue. Therefore we cannot use them without modifying
diff --git a/tcg/mips/tcg-target.c b/tcg/mips/tcg-target.c
index 393ba07f2..1006e2800 100644
--- a/tcg/mips/tcg-target.c
+++ b/tcg/mips/tcg-target.c
@@ -217,6 +217,9 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
tcg_regset_set(ct->u.regs, 0xffffffff);
#if defined(CONFIG_SOFTMMU)
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
+# if defined(CONFIG_TCG_PASS_AREG0) && (TARGET_LONG_BITS == 64)
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
+# endif
#endif
break;
case 'S': /* qemu_st constraint */
@@ -224,10 +227,14 @@ static int target_parse_constraint(TCGArgConstraint *ct, const char **pct_str)
tcg_regset_set(ct->u.regs, 0xffffffff);
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A0);
#if defined(CONFIG_SOFTMMU)
-# if TARGET_LONG_BITS == 64
+# if (defined(CONFIG_TCG_PASS_AREG0) && TARGET_LONG_BITS == 32) || \
+ (!defined(CONFIG_TCG_PASS_AREG0) && TARGET_LONG_BITS == 64)
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A1);
# endif
tcg_regset_reset_reg(ct->u.regs, TCG_REG_A2);
+# if defined(CONFIG_TCG_PASS_AREG0) && TARGET_LONG_BITS == 64
+ tcg_regset_reset_reg(ct->u.regs, TCG_REG_A3);
+# endif
#endif
break;
case 'I':
@@ -382,7 +389,10 @@ static inline void tcg_out_nop(TCGContext *s)
static inline void tcg_out_mov(TCGContext *s, TCGType type,
TCGReg ret, TCGReg arg)
{
- tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO);
+ /* Simple reg-reg move, optimising out the 'do nothing' case */
+ if (ret != arg) {
+ tcg_out_opc_reg(s, OPC_ADDU, ret, arg, TCG_REG_ZERO);
+ }
}
static inline void tcg_out_movi(TCGContext *s, TCGType type,
@@ -503,6 +513,67 @@ static inline void tcg_out_addi(TCGContext *s, int reg, tcg_target_long val)
}
}
+/* Helper routines for marshalling helper function arguments into
+ * the correct registers and stack.
+ * arg_num is where we want to put this argument, and is updated to be ready
+ * for the next call. arg is the argument itself. Note that arg_num 0..3 is
+ * real registers, 4+ on stack.
+ *
+ * We provide routines for arguments which are: immediate, 32 bit
+ * value in register, 16 and 8 bit values in register (which must be zero
+ * extended before use) and 64 bit value in a lo:hi register pair.
+ */
+#define DEFINE_TCG_OUT_CALL_IARG(NAME, ARGPARAM) \
+ static inline void NAME(TCGContext *s, int *arg_num, ARGPARAM) \
+ { \
+ if (*arg_num < 4) { \
+ DEFINE_TCG_OUT_CALL_IARG_GET_ARG(tcg_target_call_iarg_regs[*arg_num]); \
+ } else { \
+ DEFINE_TCG_OUT_CALL_IARG_GET_ARG(TCG_REG_AT); \
+ tcg_out_st(s, TCG_TYPE_I32, TCG_REG_AT, TCG_REG_SP, 4 * (*arg_num)); \
+ } \
+ (*arg_num)++; \
+}
+#define DEFINE_TCG_OUT_CALL_IARG_GET_ARG(A) \
+ tcg_out_opc_imm(s, OPC_ANDI, A, arg, 0xff);
+DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_reg8, TCGReg arg)
+#undef DEFINE_TCG_OUT_CALL_IARG_GET_ARG
+#define DEFINE_TCG_OUT_CALL_IARG_GET_ARG(A) \
+ tcg_out_opc_imm(s, OPC_ANDI, A, arg, 0xffff);
+DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_reg16, TCGReg arg)
+#undef DEFINE_TCG_OUT_CALL_IARG_GET_ARG
+#define DEFINE_TCG_OUT_CALL_IARG_GET_ARG(A) \
+ tcg_out_movi(s, TCG_TYPE_I32, A, arg);
+DEFINE_TCG_OUT_CALL_IARG(tcg_out_call_iarg_imm32, uint32_t arg)
+#undef DEFINE_TCG_OUT_CALL_IARG_GET_ARG
+
+/* We don't use the macro for this one to avoid an unnecessary reg-reg
+ move when storing to the stack. */
+static inline void tcg_out_call_iarg_reg32(TCGContext *s, int *arg_num,
+ TCGReg arg)
+{
+ if (*arg_num < 4) {
+ tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[*arg_num], arg);
+ } else {
+ tcg_out_st(s, TCG_TYPE_I32, arg, TCG_REG_SP, 4 * (*arg_num));
+ }
+ (*arg_num)++;
+}
+
+static inline void tcg_out_call_iarg_reg64(TCGContext *s, int *arg_num,
+ TCGReg arg_low, TCGReg arg_high)
+{
+ (*arg_num) = (*arg_num + 1) & ~1;
+
+#if defined(TCG_TARGET_WORDS_BIGENDIAN)
+ tcg_out_call_iarg_reg32(s, arg_num, arg_high);
+ tcg_out_call_iarg_reg32(s, arg_num, arg_low);
+#else
+ tcg_out_call_iarg_reg32(s, arg_num, arg_low);
+ tcg_out_call_iarg_reg32(s, arg_num, arg_high);
+#endif
+}
+
static void tcg_out_brcond(TCGContext *s, TCGCond cond, int arg1,
int arg2, int label_index)
{
@@ -792,18 +863,18 @@ static void *qemu_st_helpers[4] = {
static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
int opc)
{
- int addr_regl, addr_reg1, addr_meml;
+ int addr_regl, addr_meml;
int data_regl, data_regh, data_reg1, data_reg2;
int mem_index, s_bits;
#if defined(CONFIG_SOFTMMU)
void *label1_ptr, *label2_ptr;
- int sp_args;
+ int arg_num;
#endif
#if TARGET_LONG_BITS == 64
# if defined(CONFIG_SOFTMMU)
uint8_t *label3_ptr;
# endif
- int addr_regh, addr_reg2, addr_memh;
+ int addr_regh, addr_memh;
#endif
data_regl = *args++;
if (opc == 3)
@@ -831,18 +902,13 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
}
#if TARGET_LONG_BITS == 64
# if defined(TCG_TARGET_WORDS_BIGENDIAN)
- addr_reg1 = addr_regh;
- addr_reg2 = addr_regl;
addr_memh = 0;
addr_meml = 4;
# else
- addr_reg1 = addr_regl;
- addr_reg2 = addr_regh;
addr_memh = 4;
addr_meml = 0;
# endif
#else
- addr_reg1 = addr_regl;
addr_meml = 0;
#endif
@@ -875,22 +941,17 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
# endif
/* slow path */
- sp_args = TCG_REG_A0;
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg1);
+ arg_num = 0;
+# ifdef CONFIG_TCG_PASS_AREG0
+ tcg_out_call_iarg_reg32(s, &arg_num, TCG_AREG0);
+# endif
# if TARGET_LONG_BITS == 64
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg2);
+ tcg_out_call_iarg_reg64(s, &arg_num, addr_regl, addr_regh);
+# else
+ tcg_out_call_iarg_reg32(s, &arg_num, addr_regl);
# endif
- tcg_out_movi(s, TCG_TYPE_I32, sp_args++, mem_index);
+ tcg_out_call_iarg_imm32(s, &arg_num, mem_index);
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_ld_helpers[s_bits]);
-#ifdef CONFIG_TCG_PASS_AREG0
- /* XXX/FIXME: suboptimal and incorrect for 64 on 32 bit */
- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[2],
- tcg_target_call_iarg_regs[1]);
- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
- tcg_target_call_iarg_regs[0]);
- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
- TCG_AREG0);
-#endif
tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
tcg_out_nop(s);
@@ -991,18 +1052,18 @@ static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args,
static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
int opc)
{
- int addr_regl, addr_reg1, addr_meml;
+ int addr_regl, addr_meml;
int data_regl, data_regh, data_reg1, data_reg2;
int mem_index, s_bits;
#if defined(CONFIG_SOFTMMU)
uint8_t *label1_ptr, *label2_ptr;
- int sp_args;
+ int arg_num;
#endif
#if TARGET_LONG_BITS == 64
# if defined(CONFIG_SOFTMMU)
uint8_t *label3_ptr;
# endif
- int addr_regh, addr_reg2, addr_memh;
+ int addr_regh, addr_memh;
#endif
data_regl = *args++;
@@ -1024,18 +1085,13 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
#if TARGET_LONG_BITS == 64
addr_regh = *args++;
# if defined(TCG_TARGET_WORDS_BIGENDIAN)
- addr_reg1 = addr_regh;
- addr_reg2 = addr_regl;
addr_memh = 0;
addr_meml = 4;
# else
- addr_reg1 = addr_regl;
- addr_reg2 = addr_regh;
addr_memh = 4;
addr_meml = 0;
# endif
#else
- addr_reg1 = addr_regl;
addr_meml = 0;
#endif
mem_index = *args;
@@ -1070,49 +1126,33 @@ static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args,
# endif
/* slow path */
- sp_args = TCG_REG_A0;
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg1);
+ arg_num = 0;
+# ifdef CONFIG_TCG_PASS_AREG0
+ tcg_out_call_iarg_reg32(s, &arg_num, TCG_AREG0);
+# endif
# if TARGET_LONG_BITS == 64
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, addr_reg2);
+ tcg_out_call_iarg_reg64(s, &arg_num, addr_regl, addr_regh);
+# else
+ tcg_out_call_iarg_reg32(s, &arg_num, addr_regl);
# endif
switch(opc) {
case 0:
- tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xff);
+ tcg_out_call_iarg_reg8(s, &arg_num, data_regl);
break;
case 1:
- tcg_out_opc_imm(s, OPC_ANDI, sp_args++, data_reg1, 0xffff);
+ tcg_out_call_iarg_reg16(s, &arg_num, data_regl);
break;
case 2:
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg1);
+ tcg_out_call_iarg_reg32(s, &arg_num, data_regl);
break;
case 3:
- sp_args = (sp_args + 1) & ~1;
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg1);
- tcg_out_mov(s, TCG_TYPE_I32, sp_args++, data_reg2);
+ tcg_out_call_iarg_reg64(s, &arg_num, data_regl, data_regh);
break;
default:
tcg_abort();
}
- if (sp_args > TCG_REG_A3) {
- /* Push mem_index on the stack */
- tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_AT, mem_index);
- tcg_out_st(s, TCG_TYPE_I32, TCG_REG_AT, TCG_REG_SP, 16);
- } else {
- tcg_out_movi(s, TCG_TYPE_I32, sp_args, mem_index);
- }
-
+ tcg_out_call_iarg_imm32(s, &arg_num, mem_index);
tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T9, (tcg_target_long)qemu_st_helpers[s_bits]);
-#ifdef CONFIG_TCG_PASS_AREG0
- /* XXX/FIXME: suboptimal and incorrect for 64 on 32 bit */
- tcg_out_mov(s, TCG_TYPE_I32, tcg_target_call_iarg_regs[3],
- tcg_target_call_iarg_regs[2]);
- tcg_out_mov(s, TCG_TYPE_I64, tcg_target_call_iarg_regs[2],
- tcg_target_call_iarg_regs[1]);
- tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
- tcg_target_call_iarg_regs[0]);
- tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0],
- TCG_AREG0);
-#endif
tcg_out_opc_reg(s, OPC_JALR, TCG_REG_RA, TCG_REG_T9, 0);
tcg_out_nop(s);