Merge remote-tracking branch 'remotes/nvme/tags/nvme-next-pull-request' into staging
hw/nvme updates
- fix CVE-2021-3929
- add zone random write area support
- misc cleanups from Philippe
# gpg: Signature made Mon 14 Feb 2022 08:01:34 GMT
# gpg: using RSA key 522833AA75E2DCE6A24766C04DE1AF316D4F0DE9
# gpg: Good signature from "Klaus Jensen <its@irrelevant.dk>" [unknown]
# gpg: aka "Klaus Jensen <k.jensen@samsung.com>" [unknown]
# gpg: WARNING: This key is not certified with a trusted signature!
# gpg: There is no indication that the signature belongs to the owner.
# Primary key fingerprint: DDCA 4D9C 9EF9 31CC 3468 4272 63D5 6FC5 E55D A838
# Subkey fingerprint: 5228 33AA 75E2 DCE6 A247 66C0 4DE1 AF31 6D4F 0DE9
* remotes/nvme/tags/nvme-next-pull-request:
hw/nvme: add support for zoned random write area
hw/nvme: add ozcs enum
hw/nvme: add struct for zone management send
hw/nvme/ctrl: Pass buffers as 'void *' types
hw/nvme/ctrl: Have nvme_addr_write() take const buffer
hw/nvme: fix CVE-2021-3929
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
diff --git a/MAINTAINERS b/MAINTAINERS
index b0b845f..4b3ae2a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -408,7 +408,7 @@
M: Marcelo Tosatti <mtosatti@redhat.com>
L: kvm@vger.kernel.org
S: Supported
-F: docs/amd-memory-encryption.txt
+F: docs/system/i386/amd-memory-encryption.rst
F: docs/system/i386/sgx.rst
F: target/i386/kvm/
F: target/i386/sev*
diff --git a/accel/tcg/cpu-exec.c b/accel/tcg/cpu-exec.c
index 8b4cd6c..8da6a55 100644
--- a/accel/tcg/cpu-exec.c
+++ b/accel/tcg/cpu-exec.c
@@ -648,7 +648,8 @@
if (replay_has_exception()
&& cpu_neg(cpu)->icount_decr.u16.low + cpu->icount_extra == 0) {
/* Execute just one insn to trigger exception pending in the log */
- cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT) | 1;
+ cpu->cflags_next_tb = (curr_cflags(cpu) & ~CF_USE_ICOUNT)
+ | CF_NOIRQ | 1;
}
#endif
return false;
diff --git a/accel/tcg/cputlb.c b/accel/tcg/cputlb.c
index 82adefe..3b918fe 100644
--- a/accel/tcg/cputlb.c
+++ b/accel/tcg/cputlb.c
@@ -783,6 +783,15 @@
}
qemu_spin_unlock(&env_tlb(env)->c.lock);
+ /*
+ * If the length is larger than the jump cache size, then it will take
+ * longer to clear each entry individually than it will to clear it all.
+ */
+ if (d.len >= (TARGET_PAGE_SIZE * TB_JMP_CACHE_SIZE)) {
+ cpu_tb_jmp_cache_clear(cpu);
+ return;
+ }
+
for (target_ulong i = 0; i < d.len; i += TARGET_PAGE_SIZE) {
tb_flush_jmp_cache(cpu, d.addr + i);
}
diff --git a/blockdev.c b/blockdev.c
index 8197165..42e098b 100644
--- a/blockdev.c
+++ b/blockdev.c
@@ -3530,6 +3530,7 @@
{
BlockReopenQueue *queue = NULL;
GSList *drained = NULL;
+ GSList *p;
/* Add each one of the BDS that we want to reopen to the queue */
for (; reopen_list != NULL; reopen_list = reopen_list->next) {
@@ -3579,7 +3580,15 @@
fail:
bdrv_reopen_queue_free(queue);
- g_slist_free_full(drained, (GDestroyNotify) bdrv_subtree_drained_end);
+ for (p = drained; p; p = p->next) {
+ BlockDriverState *bs = p->data;
+ AioContext *ctx = bdrv_get_aio_context(bs);
+
+ aio_context_acquire(ctx);
+ bdrv_subtree_drained_end(bs);
+ aio_context_release(ctx);
+ }
+ g_slist_free(drained);
}
void qmp_blockdev_del(const char *node_name, Error **errp)
diff --git a/common-user/host/sparc64/safe-syscall.inc.S b/common-user/host/sparc64/safe-syscall.inc.S
index a2f2b9c..c7be8f2 100644
--- a/common-user/host/sparc64/safe-syscall.inc.S
+++ b/common-user/host/sparc64/safe-syscall.inc.S
@@ -24,7 +24,8 @@
.type safe_syscall_end, @function
#define STACK_BIAS 2047
-#define PARAM(N) STACK_BIAS + N*8
+#define WINDOW_SIZE 16 * 8
+#define PARAM(N) STACK_BIAS + WINDOW_SIZE + N * 8
/*
* This is the entry point for making a system call. The calling
@@ -74,7 +75,7 @@
/* code path for having successfully executed the syscall */
bcs,pn %xcc, 1f
nop
- ret
+ retl
nop
/* code path when we didn't execute the syscall */
diff --git a/docs/confidential-guest-support.txt b/docs/system/confidential-guest-support.rst
similarity index 76%
rename from docs/confidential-guest-support.txt
rename to docs/system/confidential-guest-support.rst
index 71d07ba..0c490db 100644
--- a/docs/confidential-guest-support.txt
+++ b/docs/system/confidential-guest-support.rst
@@ -19,10 +19,10 @@
To run a confidential guest you need to add two command line parameters:
-1. Use "-object" to create a "confidential guest support" object. The
+1. Use ``-object`` to create a "confidential guest support" object. The
type and parameters will vary with the specific mechanism to be
used
-2. Set the "confidential-guest-support" machine parameter to the ID of
+2. Set the ``confidential-guest-support`` machine parameter to the ID of
the object from (1).
Example (for AMD SEV)::
@@ -37,13 +37,8 @@
Currently supported confidential guest mechanisms are:
-AMD Secure Encrypted Virtualization (SEV)
- docs/amd-memory-encryption.txt
-
-POWER Protected Execution Facility (PEF)
- docs/papr-pef.txt
-
-s390x Protected Virtualization (PV)
- docs/system/s390x/protvirt.rst
+* AMD Secure Encrypted Virtualization (SEV) (see :doc:`i386/amd-memory-encryption`)
+* POWER Protected Execution Facility (PEF) (see :ref:`power-papr-protected-execution-facility-pef`)
+* s390x Protected Virtualization (PV) (see :doc:`s390x/protvirt`)
Other mechanisms may be supported in future.
diff --git a/docs/amd-memory-encryption.txt b/docs/system/i386/amd-memory-encryption.rst
similarity index 62%
rename from docs/amd-memory-encryption.txt
rename to docs/system/i386/amd-memory-encryption.rst
index ffca382..215946f 100644
--- a/docs/amd-memory-encryption.txt
+++ b/docs/system/i386/amd-memory-encryption.rst
@@ -1,3 +1,6 @@
+AMD Secure Encrypted Virtualization (SEV)
+=========================================
+
Secure Encrypted Virtualization (SEV) is a feature found on AMD processors.
SEV is an extension to the AMD-V architecture which supports running encrypted
@@ -24,17 +27,18 @@
Launching
---------
+
Boot images (such as bios) must be encrypted before a guest can be booted. The
-MEMORY_ENCRYPT_OP ioctl provides commands to encrypt the images: LAUNCH_START,
-LAUNCH_UPDATE_DATA, LAUNCH_MEASURE and LAUNCH_FINISH. These four commands
+``MEMORY_ENCRYPT_OP`` ioctl provides commands to encrypt the images: ``LAUNCH_START``,
+``LAUNCH_UPDATE_DATA``, ``LAUNCH_MEASURE`` and ``LAUNCH_FINISH``. These four commands
together generate a fresh memory encryption key for the VM, encrypt the boot
images and provide a measurement than can be used as an attestation of a
successful launch.
-For a SEV-ES guest, the LAUNCH_UPDATE_VMSA command is also used to encrypt the
+For a SEV-ES guest, the ``LAUNCH_UPDATE_VMSA`` command is also used to encrypt the
guest register state, or VM save area (VMSA), for all of the guest vCPUs.
-LAUNCH_START is called first to create a cryptographic launch context within
+``LAUNCH_START`` is called first to create a cryptographic launch context within
the firmware. To create this context, guest owner must provide a guest policy,
its public Diffie-Hellman key (PDH) and session parameters. These inputs
should be treated as a binary blob and must be passed as-is to the SEV firmware.
@@ -45,37 +49,37 @@
several flags that restricts what can be done on a running SEV guest.
See KM Spec section 3 and 6.2 for more details.
-The guest policy can be provided via the 'policy' property (see below)
+The guest policy can be provided via the ``policy`` property::
-# ${QEMU} \
- sev-guest,id=sev0,policy=0x1...\
+ # ${QEMU} \
+ sev-guest,id=sev0,policy=0x1...\
Setting the "SEV-ES required" policy bit (bit 2) will launch the guest as a
-SEV-ES guest (see below)
+SEV-ES guest::
-# ${QEMU} \
- sev-guest,id=sev0,policy=0x5...\
+ # ${QEMU} \
+ sev-guest,id=sev0,policy=0x5...\
The guest owner provided DH certificate and session parameters will be used to
establish a cryptographic session with the guest owner to negotiate keys used
for the attestation.
-The DH certificate and session blob can be provided via the 'dh-cert-file' and
-'session-file' properties (see below)
+The DH certificate and session blob can be provided via the ``dh-cert-file`` and
+``session-file`` properties::
-# ${QEMU} \
- sev-guest,id=sev0,dh-cert-file=<file1>,session-file=<file2>
+ # ${QEMU} \
+ sev-guest,id=sev0,dh-cert-file=<file1>,session-file=<file2>
-LAUNCH_UPDATE_DATA encrypts the memory region using the cryptographic context
-created via the LAUNCH_START command. If required, this command can be called
+``LAUNCH_UPDATE_DATA`` encrypts the memory region using the cryptographic context
+created via the ``LAUNCH_START`` command. If required, this command can be called
multiple times to encrypt different memory regions. The command also calculates
the measurement of the memory contents as it encrypts.
-LAUNCH_UPDATE_VMSA encrypts all the vCPU VMSAs for a SEV-ES guest using the
-cryptographic context created via the LAUNCH_START command. The command also
+``LAUNCH_UPDATE_VMSA`` encrypts all the vCPU VMSAs for a SEV-ES guest using the
+cryptographic context created via the ``LAUNCH_START`` command. The command also
calculates the measurement of the VMSAs as it encrypts them.
-LAUNCH_MEASURE can be used to retrieve the measurement of encrypted memory and,
+``LAUNCH_MEASURE`` can be used to retrieve the measurement of encrypted memory and,
for a SEV-ES guest, encrypted VMSAs. This measurement is a signature of the
memory contents and, for a SEV-ES guest, the VMSA contents, that can be sent
to the guest owner as an attestation that the memory and VMSAs were encrypted
@@ -85,27 +89,28 @@
attestation measurement can be verified by comparing it to what the guest owner
expects.
-LAUNCH_FINISH finalizes the guest launch and destroys the cryptographic
+``LAUNCH_FINISH`` finalizes the guest launch and destroys the cryptographic
context.
-See SEV KM API Spec [1] 'Launching a guest' usage flow (Appendix A) for the
+See SEV KM API Spec ([SEVKM]_) 'Launching a guest' usage flow (Appendix A) for the
complete flow chart.
-To launch a SEV guest
+To launch a SEV guest::
-# ${QEMU} \
- -machine ...,confidential-guest-support=sev0 \
- -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1
+ # ${QEMU} \
+ -machine ...,confidential-guest-support=sev0 \
+ -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1
-To launch a SEV-ES guest
+To launch a SEV-ES guest::
-# ${QEMU} \
- -machine ...,confidential-guest-support=sev0 \
- -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1,policy=0x5
+ # ${QEMU} \
+ -machine ...,confidential-guest-support=sev0 \
+ -object sev-guest,id=sev0,cbitpos=47,reduced-phys-bits=1,policy=0x5
An SEV-ES guest has some restrictions as compared to a SEV guest. Because the
guest register state is encrypted and cannot be updated by the VMM/hypervisor,
a SEV-ES guest:
+
- Does not support SMM - SMM support requires updating the guest register
state.
- Does not support reboot - a system reset requires updating the guest register
@@ -114,35 +119,42 @@
manage booting APs.
Debugging
------------
+---------
+
Since the memory contents of a SEV guest are encrypted, hypervisor access to
the guest memory will return cipher text. If the guest policy allows debugging,
then a hypervisor can use the DEBUG_DECRYPT and DEBUG_ENCRYPT commands to access
the guest memory region for debug purposes. This is not supported in QEMU yet.
Snapshot/Restore
------------------
+----------------
+
TODO
Live Migration
-----------------
+---------------
+
TODO
References
------------------
+----------
-AMD Memory Encryption whitepaper:
-https://developer.amd.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf
+`AMD Memory Encryption whitepaper
+<https://developer.amd.com/wordpress/media/2013/12/AMD_Memory_Encryption_Whitepaper_v7-Public.pdf>`_
-Secure Encrypted Virtualization Key Management:
-[1] http://developer.amd.com/wordpress/media/2017/11/55766_SEV-KM-API_Specification.pdf
+.. [SEVKM] `Secure Encrypted Virtualization Key Management
+ <http://developer.amd.com/wordpress/media/2017/11/55766_SEV-KM-API_Specification.pdf>`_
KVM Forum slides:
-http://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf
-https://www.linux-kvm.org/images/9/94/Extending-Secure-Encrypted-Virtualization-with-SEV-ES-Thomas-Lendacky-AMD.pdf
-AMD64 Architecture Programmer's Manual:
- http://support.amd.com/TechDocs/24593.pdf
- SME is section 7.10
- SEV is section 15.34
- SEV-ES is section 15.35
+* `AMD’s Virtualization Memory Encryption (2016)
+ <http://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf>`_
+* `Extending Secure Encrypted Virtualization With SEV-ES (2018)
+ <https://www.linux-kvm.org/images/9/94/Extending-Secure-Encrypted-Virtualization-with-SEV-ES-Thomas-Lendacky-AMD.pdf>`_
+
+`AMD64 Architecture Programmer's Manual:
+<http://support.amd.com/TechDocs/24593.pdf>`_
+
+* SME is section 7.10
+* SEV is section 15.34
+* SEV-ES is section 15.35
diff --git a/docs/system/index.rst b/docs/system/index.rst
index 73bbedb..23e30e2 100644
--- a/docs/system/index.rst
+++ b/docs/system/index.rst
@@ -34,3 +34,4 @@
targets
security
multi-process
+ confidential-guest-support
diff --git a/docs/system/ppc/pseries.rst b/docs/system/ppc/pseries.rst
index 569237d..d9b65ad 100644
--- a/docs/system/ppc/pseries.rst
+++ b/docs/system/ppc/pseries.rst
@@ -224,6 +224,8 @@
.. [3] Introduced on Power10 machines.
+.. _power-papr-protected-execution-facility-pef:
+
POWER (PAPR) Protected Execution Facility (PEF)
-----------------------------------------------
diff --git a/docs/system/target-i386.rst b/docs/system/target-i386.rst
index 4daa53c..96bf548 100644
--- a/docs/system/target-i386.rst
+++ b/docs/system/target-i386.rst
@@ -28,6 +28,7 @@
i386/cpu
i386/kvm-pv
i386/sgx
+ i386/amd-memory-encryption
.. _pcsys_005freq:
diff --git a/hw/block/fdc-isa.c b/hw/block/fdc-isa.c
index 3bf64e0..ab663dc 100644
--- a/hw/block/fdc-isa.c
+++ b/hw/block/fdc-isa.c
@@ -216,6 +216,7 @@
static void fdc_isa_build_aml(ISADevice *isadev, Aml *scope)
{
+ FDCtrlISABus *isa = ISA_FDC(isadev);
Aml *dev;
Aml *crs;
int i;
@@ -227,11 +228,13 @@
};
crs = aml_resource_template();
- aml_append(crs, aml_io(AML_DECODE16, 0x03F2, 0x03F2, 0x00, 0x04));
- aml_append(crs, aml_io(AML_DECODE16, 0x03F7, 0x03F7, 0x00, 0x01));
- aml_append(crs, aml_irq_no_flags(6));
aml_append(crs,
- aml_dma(AML_COMPATIBILITY, AML_NOTBUSMASTER, AML_TRANSFER8, 2));
+ aml_io(AML_DECODE16, isa->iobase + 2, isa->iobase + 2, 0x00, 0x04));
+ aml_append(crs,
+ aml_io(AML_DECODE16, isa->iobase + 7, isa->iobase + 7, 0x00, 0x01));
+ aml_append(crs, aml_irq_no_flags(isa->irq));
+ aml_append(crs,
+ aml_dma(AML_COMPATIBILITY, AML_NOTBUSMASTER, AML_TRANSFER8, isa->dma));
dev = aml_device("FDC0");
aml_append(dev, aml_name_decl("_HID", aml_eisaid("PNP0700")));
diff --git a/hw/net/e1000e_core.c b/hw/net/e1000e_core.c
index 8ae6fb7..2c51089 100644
--- a/hw/net/e1000e_core.c
+++ b/hw/net/e1000e_core.c
@@ -2607,6 +2607,11 @@
core->mac[ICR] = 0;
}
+ if (!msix_enabled(core->owner)) {
+ trace_e1000e_irq_icr_clear_nonmsix_icr_read();
+ core->mac[ICR] = 0;
+ }
+
if ((core->mac[ICR] & E1000_ICR_ASSERTED) &&
(core->mac[CTRL_EXT] & E1000_CTRL_EXT_IAME)) {
trace_e1000e_irq_icr_clear_iame();
diff --git a/hw/net/trace-events b/hw/net/trace-events
index 643338f..4c0ec3f 100644
--- a/hw/net/trace-events
+++ b/hw/net/trace-events
@@ -221,6 +221,7 @@
e1000e_irq_icr_process_iame(void) "Clearing IMS bits due to IAME"
e1000e_irq_read_ics(uint32_t ics) "Current ICS: 0x%x"
e1000e_irq_read_ims(uint32_t ims) "Current IMS: 0x%x"
+e1000e_irq_icr_clear_nonmsix_icr_read(void) "Clearing ICR on read due to non MSI-X int"
e1000e_irq_icr_read_entry(uint32_t icr) "Starting ICR read. Current ICR: 0x%x"
e1000e_irq_icr_read_exit(uint32_t icr) "Ending ICR read. Current ICR: 0x%x"
e1000e_irq_icr_clear_zero_ims(void) "Clearing ICR on read due to zero IMS"
diff --git a/hw/net/vmxnet3.c b/hw/net/vmxnet3.c
index f65af4e..0b7acf7 100644
--- a/hw/net/vmxnet3.c
+++ b/hw/net/vmxnet3.c
@@ -1816,7 +1816,9 @@
case VMXNET3_REG_ICR:
VMW_CBPRN("Write BAR1 [VMXNET3_REG_ICR] = %" PRIx64 ", size %d",
val, size);
- g_assert_not_reached();
+ qemu_log_mask(LOG_GUEST_ERROR,
+ "%s: write to read-only register VMXNET3_REG_ICR\n",
+ TYPE_VMXNET3);
break;
/* Event Cause Register */
diff --git a/hw/ppc/ppc.c b/hw/ppc/ppc.c
index 462c87d..ba7fa0f 100644
--- a/hw/ppc/ppc.c
+++ b/hw/ppc/ppc.c
@@ -1083,27 +1083,6 @@
return &cpu_ppc_set_tb_clk;
}
-/* Specific helpers for POWER & PowerPC 601 RTC */
-void cpu_ppc601_store_rtcu (CPUPPCState *env, uint32_t value)
-{
- _cpu_ppc_store_tbu(env, value);
-}
-
-uint32_t cpu_ppc601_load_rtcu (CPUPPCState *env)
-{
- return _cpu_ppc_load_tbu(env);
-}
-
-void cpu_ppc601_store_rtcl (CPUPPCState *env, uint32_t value)
-{
- cpu_ppc_store_tbl(env, value & 0x3FFFFF80);
-}
-
-uint32_t cpu_ppc601_load_rtcl (CPUPPCState *env)
-{
- return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
-}
-
/*****************************************************************************/
/* PowerPC 40x timers */
diff --git a/hw/ppc/prep.c b/hw/ppc/prep.c
index 25a2e86..bf622aa 100644
--- a/hw/ppc/prep.c
+++ b/hw/ppc/prep.c
@@ -255,13 +255,8 @@
exit(1);
}
- if (env->flags & POWERPC_FLAG_RTC_CLK) {
- /* POWER / PowerPC 601 RTC clock frequency is 7.8125 MHz */
- cpu_ppc_tb_init(env, 7812500UL);
- } else {
- /* Set time-base frequency to 100 Mhz */
- cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
- }
+ /* Set time-base frequency to 100 Mhz */
+ cpu_ppc_tb_init(env, 100UL * 1000UL * 1000UL);
qemu_register_reset(ppc_prep_reset, cpu);
/* PCI host */
diff --git a/linux-user/include/host/aarch64/host-signal.h b/linux-user/include/host/aarch64/host-signal.h
index 9770b36..be07968 100644
--- a/linux-user/include/host/aarch64/host-signal.h
+++ b/linux-user/include/host/aarch64/host-signal.h
@@ -11,6 +11,9 @@
#ifndef AARCH64_HOST_SIGNAL_H
#define AARCH64_HOST_SIGNAL_H
+/* The third argument to a SA_SIGINFO handler is ucontext_t. */
+typedef ucontext_t host_sigcontext;
+
/* Pre-3.16 kernel headers don't have these, so provide fallback definitions */
#ifndef ESR_MAGIC
#define ESR_MAGIC 0x45535201
@@ -20,7 +23,7 @@
};
#endif
-static inline struct _aarch64_ctx *first_ctx(ucontext_t *uc)
+static inline struct _aarch64_ctx *first_ctx(host_sigcontext *uc)
{
return (struct _aarch64_ctx *)&uc->uc_mcontext.__reserved;
}
@@ -30,17 +33,22 @@
return (struct _aarch64_ctx *)((char *)hdr + hdr->size);
}
-static inline uintptr_t host_signal_pc(ucontext_t *uc)
+static inline uintptr_t host_signal_pc(host_sigcontext *uc)
{
return uc->uc_mcontext.pc;
}
-static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+static inline void host_signal_set_pc(host_sigcontext *uc, uintptr_t pc)
{
uc->uc_mcontext.pc = pc;
}
-static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+static inline void *host_signal_mask(host_sigcontext *uc)
+{
+ return &uc->uc_sigmask;
+}
+
+static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc)
{
struct _aarch64_ctx *hdr;
uint32_t insn;
diff --git a/linux-user/include/host/alpha/host-signal.h b/linux-user/include/host/alpha/host-signal.h
index f4c9429..4f9e2ab 100644
--- a/linux-user/include/host/alpha/host-signal.h
+++ b/linux-user/include/host/alpha/host-signal.h
@@ -11,17 +11,25 @@
#ifndef ALPHA_HOST_SIGNAL_H
#define ALPHA_HOST_SIGNAL_H
-static inline uintptr_t host_signal_pc(ucontext_t *uc)
+/* The third argument to a SA_SIGINFO handler is ucontext_t. */
+typedef ucontext_t host_sigcontext;
+
+static inline uintptr_t host_signal_pc(host_sigcontext *uc)
{
return uc->uc_mcontext.sc_pc;
}
-static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+static inline void host_signal_set_pc(host_sigcontext *uc, uintptr_t pc)
{
uc->uc_mcontext.sc_pc = pc;
}
-static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+static inline void *host_signal_mask(host_sigcontext *uc)
+{
+ return &uc->uc_sigmask;
+}
+
+static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc)
{
uint32_t *pc = (uint32_t *)host_signal_pc(uc);
uint32_t insn = *pc;
diff --git a/linux-user/include/host/arm/host-signal.h b/linux-user/include/host/arm/host-signal.h
index 6c09577..faba496 100644
--- a/linux-user/include/host/arm/host-signal.h
+++ b/linux-user/include/host/arm/host-signal.h
@@ -11,17 +11,25 @@
#ifndef ARM_HOST_SIGNAL_H
#define ARM_HOST_SIGNAL_H
-static inline uintptr_t host_signal_pc(ucontext_t *uc)
+/* The third argument to a SA_SIGINFO handler is ucontext_t. */
+typedef ucontext_t host_sigcontext;
+
+static inline uintptr_t host_signal_pc(host_sigcontext *uc)
{
return uc->uc_mcontext.arm_pc;
}
-static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+static inline void host_signal_set_pc(host_sigcontext *uc, uintptr_t pc)
{
uc->uc_mcontext.arm_pc = pc;
}
-static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+static inline void *host_signal_mask(host_sigcontext *uc)
+{
+ return &uc->uc_sigmask;
+}
+
+static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc)
{
/*
* In the FSR, bit 11 is WnR, assuming a v6 or
diff --git a/linux-user/include/host/i386/host-signal.h b/linux-user/include/host/i386/host-signal.h
index abe1ece..e2b64f0 100644
--- a/linux-user/include/host/i386/host-signal.h
+++ b/linux-user/include/host/i386/host-signal.h
@@ -11,17 +11,25 @@
#ifndef I386_HOST_SIGNAL_H
#define I386_HOST_SIGNAL_H
-static inline uintptr_t host_signal_pc(ucontext_t *uc)
+/* The third argument to a SA_SIGINFO handler is ucontext_t. */
+typedef ucontext_t host_sigcontext;
+
+static inline uintptr_t host_signal_pc(host_sigcontext *uc)
{
return uc->uc_mcontext.gregs[REG_EIP];
}
-static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+static inline void host_signal_set_pc(host_sigcontext *uc, uintptr_t pc)
{
uc->uc_mcontext.gregs[REG_EIP] = pc;
}
-static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+static inline void *host_signal_mask(host_sigcontext *uc)
+{
+ return &uc->uc_sigmask;
+}
+
+static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc)
{
return uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe
&& (uc->uc_mcontext.gregs[REG_ERR] & 0x2);
diff --git a/linux-user/include/host/loongarch64/host-signal.h b/linux-user/include/host/loongarch64/host-signal.h
index 7effa24..d33c3fc 100644
--- a/linux-user/include/host/loongarch64/host-signal.h
+++ b/linux-user/include/host/loongarch64/host-signal.h
@@ -11,17 +11,25 @@
#ifndef LOONGARCH64_HOST_SIGNAL_H
#define LOONGARCH64_HOST_SIGNAL_H
-static inline uintptr_t host_signal_pc(ucontext_t *uc)
+/* The third argument to a SA_SIGINFO handler is ucontext_t. */
+typedef ucontext_t host_sigcontext;
+
+static inline uintptr_t host_signal_pc(host_sigcontext *uc)
{
return uc->uc_mcontext.__pc;
}
-static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+static inline void host_signal_set_pc(host_sigcontext *uc, uintptr_t pc)
{
uc->uc_mcontext.__pc = pc;
}
-static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+static inline void *host_signal_mask(host_sigcontext *uc)
+{
+ return &uc->uc_sigmask;
+}
+
+static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc)
{
const uint32_t *pinsn = (const uint32_t *)host_signal_pc(uc);
uint32_t insn = pinsn[0];
diff --git a/linux-user/include/host/mips/host-signal.h b/linux-user/include/host/mips/host-signal.h
index c666ed8..0dbc5ce 100644
--- a/linux-user/include/host/mips/host-signal.h
+++ b/linux-user/include/host/mips/host-signal.h
@@ -11,21 +11,29 @@
#ifndef MIPS_HOST_SIGNAL_H
#define MIPS_HOST_SIGNAL_H
-static inline uintptr_t host_signal_pc(ucontext_t *uc)
+/* The third argument to a SA_SIGINFO handler is ucontext_t. */
+typedef ucontext_t host_sigcontext;
+
+static inline uintptr_t host_signal_pc(host_sigcontext *uc)
{
return uc->uc_mcontext.pc;
}
-static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+static inline void host_signal_set_pc(host_sigcontext *uc, uintptr_t pc)
{
uc->uc_mcontext.pc = pc;
}
+static inline void *host_signal_mask(host_sigcontext *uc)
+{
+ return &uc->uc_sigmask;
+}
+
#if defined(__misp16) || defined(__mips_micromips)
#error "Unsupported encoding"
#endif
-static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc)
{
uint32_t insn = *(uint32_t *)host_signal_pc(uc);
diff --git a/linux-user/include/host/ppc/host-signal.h b/linux-user/include/host/ppc/host-signal.h
index 1d8e658..b80384d 100644
--- a/linux-user/include/host/ppc/host-signal.h
+++ b/linux-user/include/host/ppc/host-signal.h
@@ -11,17 +11,25 @@
#ifndef PPC_HOST_SIGNAL_H
#define PPC_HOST_SIGNAL_H
-static inline uintptr_t host_signal_pc(ucontext_t *uc)
+/* The third argument to a SA_SIGINFO handler is ucontext_t. */
+typedef ucontext_t host_sigcontext;
+
+static inline uintptr_t host_signal_pc(host_sigcontext *uc)
{
return uc->uc_mcontext.regs->nip;
}
-static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+static inline void host_signal_set_pc(host_sigcontext *uc, uintptr_t pc)
{
uc->uc_mcontext.regs->nip = pc;
}
-static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+static inline void *host_signal_mask(host_sigcontext *uc)
+{
+ return &uc->uc_sigmask;
+}
+
+static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc)
{
return uc->uc_mcontext.regs->trap != 0x400
&& (uc->uc_mcontext.regs->dsisr & 0x02000000);
diff --git a/linux-user/include/host/riscv/host-signal.h b/linux-user/include/host/riscv/host-signal.h
index a4f170e..decacb2 100644
--- a/linux-user/include/host/riscv/host-signal.h
+++ b/linux-user/include/host/riscv/host-signal.h
@@ -11,17 +11,25 @@
#ifndef RISCV_HOST_SIGNAL_H
#define RISCV_HOST_SIGNAL_H
-static inline uintptr_t host_signal_pc(ucontext_t *uc)
+/* The third argument to a SA_SIGINFO handler is ucontext_t. */
+typedef ucontext_t host_sigcontext;
+
+static inline uintptr_t host_signal_pc(host_sigcontext *uc)
{
return uc->uc_mcontext.__gregs[REG_PC];
}
-static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+static inline void host_signal_set_pc(host_sigcontext *uc, uintptr_t pc)
{
uc->uc_mcontext.__gregs[REG_PC] = pc;
}
-static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+static inline void *host_signal_mask(host_sigcontext *uc)
+{
+ return &uc->uc_sigmask;
+}
+
+static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc)
{
/*
* Detect store by reading the instruction at the program counter.
diff --git a/linux-user/include/host/s390/host-signal.h b/linux-user/include/host/s390/host-signal.h
index a524f2a..6f191e6 100644
--- a/linux-user/include/host/s390/host-signal.h
+++ b/linux-user/include/host/s390/host-signal.h
@@ -11,17 +11,25 @@
#ifndef S390_HOST_SIGNAL_H
#define S390_HOST_SIGNAL_H
-static inline uintptr_t host_signal_pc(ucontext_t *uc)
+/* The third argument to a SA_SIGINFO handler is ucontext_t. */
+typedef ucontext_t host_sigcontext;
+
+static inline uintptr_t host_signal_pc(host_sigcontext *uc)
{
return uc->uc_mcontext.psw.addr;
}
-static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+static inline void host_signal_set_pc(host_sigcontext *uc, uintptr_t pc)
{
uc->uc_mcontext.psw.addr = pc;
}
-static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+static inline void *host_signal_mask(host_sigcontext *uc)
+{
+ return &uc->uc_sigmask;
+}
+
+static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc)
{
uint16_t *pinsn = (uint16_t *)host_signal_pc(uc);
diff --git a/linux-user/include/host/sparc/host-signal.h b/linux-user/include/host/sparc/host-signal.h
deleted file mode 100644
index 7342936..0000000
--- a/linux-user/include/host/sparc/host-signal.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * host-signal.h: signal info dependent on the host architecture
- *
- * Copyright (c) 2003-2005 Fabrice Bellard
- * Copyright (c) 2021 Linaro Limited
- *
- * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
- * See the COPYING file in the top-level directory.
- */
-
-#ifndef SPARC_HOST_SIGNAL_H
-#define SPARC_HOST_SIGNAL_H
-
-static inline uintptr_t host_signal_pc(ucontext_t *uc)
-{
-#ifdef __arch64__
- return uc->uc_mcontext.mc_gregs[MC_PC];
-#else
- return uc->uc_mcontext.gregs[REG_PC];
-#endif
-}
-
-static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
-{
-#ifdef __arch64__
- uc->uc_mcontext.mc_gregs[MC_PC] = pc;
-#else
- uc->uc_mcontext.gregs[REG_PC] = pc;
-#endif
-}
-
-static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
-{
- uint32_t insn = *(uint32_t *)host_signal_pc(uc);
-
- if ((insn >> 30) == 3) {
- switch ((insn >> 19) & 0x3f) {
- case 0x05: /* stb */
- case 0x15: /* stba */
- case 0x06: /* sth */
- case 0x16: /* stha */
- case 0x04: /* st */
- case 0x14: /* sta */
- case 0x07: /* std */
- case 0x17: /* stda */
- case 0x0e: /* stx */
- case 0x1e: /* stxa */
- case 0x24: /* stf */
- case 0x34: /* stfa */
- case 0x27: /* stdf */
- case 0x37: /* stdfa */
- case 0x26: /* stqf */
- case 0x36: /* stqfa */
- case 0x25: /* stfsr */
- case 0x3c: /* casa */
- case 0x3e: /* casxa */
- return true;
- }
- }
- return false;
-}
-
-#endif
diff --git a/linux-user/include/host/sparc64/host-signal.h b/linux-user/include/host/sparc64/host-signal.h
index 1191fe2..64957c2 100644
--- a/linux-user/include/host/sparc64/host-signal.h
+++ b/linux-user/include/host/sparc64/host-signal.h
@@ -1 +1,64 @@
-#include "../sparc/host-signal.h"
+/*
+ * host-signal.h: signal info dependent on the host architecture
+ *
+ * Copyright (c) 2003-2005 Fabrice Bellard
+ * Copyright (c) 2021 Linaro Limited
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
+ * See the COPYING file in the top-level directory.
+ */
+
+#ifndef SPARC64_HOST_SIGNAL_H
+#define SPARC64_HOST_SIGNAL_H
+
+/* The third argument to a SA_SIGINFO handler is struct sigcontext. */
+typedef struct sigcontext host_sigcontext;
+
+static inline uintptr_t host_signal_pc(host_sigcontext *sc)
+{
+ return sc->sigc_regs.tpc;
+}
+
+static inline void host_signal_set_pc(host_sigcontext *sc, uintptr_t pc)
+{
+ sc->sigc_regs.tpc = pc;
+ sc->sigc_regs.tnpc = pc + 4;
+}
+
+static inline void *host_signal_mask(host_sigcontext *sc)
+{
+ return &sc->sigc_mask;
+}
+
+static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc)
+{
+ uint32_t insn = *(uint32_t *)host_signal_pc(uc);
+
+ if ((insn >> 30) == 3) {
+ switch ((insn >> 19) & 0x3f) {
+ case 0x05: /* stb */
+ case 0x15: /* stba */
+ case 0x06: /* sth */
+ case 0x16: /* stha */
+ case 0x04: /* st */
+ case 0x14: /* sta */
+ case 0x07: /* std */
+ case 0x17: /* stda */
+ case 0x0e: /* stx */
+ case 0x1e: /* stxa */
+ case 0x24: /* stf */
+ case 0x34: /* stfa */
+ case 0x27: /* stdf */
+ case 0x37: /* stdfa */
+ case 0x26: /* stqf */
+ case 0x36: /* stqfa */
+ case 0x25: /* stfsr */
+ case 0x3c: /* casa */
+ case 0x3e: /* casxa */
+ return true;
+ }
+ }
+ return false;
+}
+
+#endif
diff --git a/linux-user/include/host/x86_64/host-signal.h b/linux-user/include/host/x86_64/host-signal.h
index c71d597..5a7627f 100644
--- a/linux-user/include/host/x86_64/host-signal.h
+++ b/linux-user/include/host/x86_64/host-signal.h
@@ -10,17 +10,25 @@
#ifndef X86_64_HOST_SIGNAL_H
#define X86_64_HOST_SIGNAL_H
-static inline uintptr_t host_signal_pc(ucontext_t *uc)
+/* The third argument to a SA_SIGINFO handler is ucontext_t. */
+typedef ucontext_t host_sigcontext;
+
+static inline uintptr_t host_signal_pc(host_sigcontext *uc)
{
return uc->uc_mcontext.gregs[REG_RIP];
}
-static inline void host_signal_set_pc(ucontext_t *uc, uintptr_t pc)
+static inline void host_signal_set_pc(host_sigcontext *uc, uintptr_t pc)
{
uc->uc_mcontext.gregs[REG_RIP] = pc;
}
-static inline bool host_signal_write(siginfo_t *info, ucontext_t *uc)
+static inline void *host_signal_mask(host_sigcontext *uc)
+{
+ return &uc->uc_sigmask;
+}
+
+static inline bool host_signal_write(siginfo_t *info, host_sigcontext *uc)
{
return uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe
&& (uc->uc_mcontext.gregs[REG_ERR] & 0x2);
diff --git a/linux-user/ppc/cpu_loop.c b/linux-user/ppc/cpu_loop.c
index 46e6ffd..38097b0 100644
--- a/linux-user/ppc/cpu_loop.c
+++ b/linux-user/ppc/cpu_loop.c
@@ -54,14 +54,6 @@
return cpu_ppc_get_tb(env);
}
-uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env)
-__attribute__ (( alias ("cpu_ppc_load_tbu") ));
-
-uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env)
-{
- return cpu_ppc_load_tbl(env) & 0x3FFFFF80;
-}
-
/* XXX: to be fixed */
int ppc_dcr_read (ppc_dcr_t *dcr_env, int dcrn, uint32_t *valp)
{
@@ -289,14 +281,6 @@
cpu_abort(cs, "Programmable interval timer interrupt "
"while in user mode. Aborting\n");
break;
- case POWERPC_EXCP_IO: /* IO error exception */
- cpu_abort(cs, "IO error exception while in user mode. "
- "Aborting\n");
- break;
- case POWERPC_EXCP_RUNM: /* Run mode exception */
- cpu_abort(cs, "Run mode exception while in user mode. "
- "Aborting\n");
- break;
case POWERPC_EXCP_EMUL: /* Emulation trap exception */
cpu_abort(cs, "Emulation trap exception not handled\n");
break;
diff --git a/linux-user/signal.c b/linux-user/signal.c
index 32854bb..27a0ff3 100644
--- a/linux-user/signal.c
+++ b/linux-user/signal.c
@@ -800,7 +800,7 @@
/* Adjust the signal context to rewind out of safe-syscall if we're in it */
static inline void rewind_if_in_safe_syscall(void *puc)
{
- ucontext_t *uc = (ucontext_t *)puc;
+ host_sigcontext *uc = (host_sigcontext *)puc;
uintptr_t pcreg = host_signal_pc(uc);
if (pcreg > (uintptr_t)safe_syscall_start
@@ -815,11 +815,12 @@
CPUState *cpu = env_cpu(env);
TaskState *ts = cpu->opaque;
target_siginfo_t tinfo;
- ucontext_t *uc = puc;
+ host_sigcontext *uc = puc;
struct emulated_sigtable *k;
int guest_sig;
uintptr_t pc = 0;
bool sync_sig = false;
+ void *sigmask = host_signal_mask(uc);
/*
* Non-spoofed SIGSEGV and SIGBUS are synchronous, and need special
@@ -849,8 +850,7 @@
if (info->si_code == SEGV_ACCERR && h2g_valid(host_addr)) {
/* If this was a write to a TB protected page, restart. */
if (is_write &&
- handle_sigsegv_accerr_write(cpu, &uc->uc_sigmask,
- pc, guest_addr)) {
+ handle_sigsegv_accerr_write(cpu, sigmask, pc, guest_addr)) {
return;
}
@@ -865,10 +865,10 @@
}
}
- sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+ sigprocmask(SIG_SETMASK, sigmask, NULL);
cpu_loop_exit_sigsegv(cpu, guest_addr, access_type, maperr, pc);
} else {
- sigprocmask(SIG_SETMASK, &uc->uc_sigmask, NULL);
+ sigprocmask(SIG_SETMASK, sigmask, NULL);
if (info->si_code == BUS_ADRALN) {
cpu_loop_exit_sigbus(cpu, guest_addr, access_type, pc);
}
@@ -909,17 +909,15 @@
* now and it getting out to the main loop. Signals will be
* unblocked again in process_pending_signals().
*
- * WARNING: we cannot use sigfillset() here because the uc_sigmask
+ * WARNING: we cannot use sigfillset() here because the sigmask
* field is a kernel sigset_t, which is much smaller than the
* libc sigset_t which sigfillset() operates on. Using sigfillset()
* would write 0xff bytes off the end of the structure and trash
* data on the struct.
- * We can't use sizeof(uc->uc_sigmask) either, because the libc
- * headers define the struct field with the wrong (too large) type.
*/
- memset(&uc->uc_sigmask, 0xff, SIGSET_T_SIZE);
- sigdelset(&uc->uc_sigmask, SIGSEGV);
- sigdelset(&uc->uc_sigmask, SIGBUS);
+ memset(sigmask, 0xff, SIGSET_T_SIZE);
+ sigdelset(sigmask, SIGSEGV);
+ sigdelset(sigmask, SIGBUS);
/* interrupt the virtual CPU as soon as possible */
cpu_exit(thread_cpu);
diff --git a/net/colo-compare.c b/net/colo-compare.c
index b966e7e..62554b5 100644
--- a/net/colo-compare.c
+++ b/net/colo-compare.c
@@ -197,7 +197,7 @@
/* Use restricted to colo_insert_packet() */
static gint seq_sorter(Packet *a, Packet *b, gpointer data)
{
- return a->tcp_seq - b->tcp_seq;
+ return b->tcp_seq - a->tcp_seq;
}
static void fill_pkt_tcp_info(void *data, uint32_t *max_ack)
@@ -421,13 +421,13 @@
if (g_queue_is_empty(&conn->primary_list)) {
return;
}
- ppkt = g_queue_pop_head(&conn->primary_list);
+ ppkt = g_queue_pop_tail(&conn->primary_list);
sec:
if (g_queue_is_empty(&conn->secondary_list)) {
- g_queue_push_head(&conn->primary_list, ppkt);
+ g_queue_push_tail(&conn->primary_list, ppkt);
return;
}
- spkt = g_queue_pop_head(&conn->secondary_list);
+ spkt = g_queue_pop_tail(&conn->secondary_list);
if (ppkt->tcp_seq == ppkt->seq_end) {
colo_release_primary_pkt(s, ppkt);
@@ -458,7 +458,7 @@
}
}
if (!ppkt) {
- g_queue_push_head(&conn->secondary_list, spkt);
+ g_queue_push_tail(&conn->secondary_list, spkt);
goto pri;
}
}
@@ -477,7 +477,7 @@
if (mark == COLO_COMPARE_FREE_PRIMARY) {
conn->compare_seq = ppkt->seq_end;
colo_release_primary_pkt(s, ppkt);
- g_queue_push_head(&conn->secondary_list, spkt);
+ g_queue_push_tail(&conn->secondary_list, spkt);
goto pri;
} else if (mark == COLO_COMPARE_FREE_SECONDARY) {
conn->compare_seq = spkt->seq_end;
@@ -490,8 +490,8 @@
goto pri;
}
} else {
- g_queue_push_head(&conn->primary_list, ppkt);
- g_queue_push_head(&conn->secondary_list, spkt);
+ g_queue_push_tail(&conn->primary_list, ppkt);
+ g_queue_push_tail(&conn->secondary_list, spkt);
#ifdef DEBUG_COLO_PACKETS
qemu_hexdump(stderr, "colo-compare ppkt", ppkt->data, ppkt->size);
@@ -673,7 +673,7 @@
while (!g_queue_is_empty(&conn->primary_list) &&
!g_queue_is_empty(&conn->secondary_list)) {
- pkt = g_queue_pop_head(&conn->primary_list);
+ pkt = g_queue_pop_tail(&conn->primary_list);
result = g_queue_find_custom(&conn->secondary_list,
pkt, (GCompareFunc)HandlePacket);
@@ -689,7 +689,7 @@
* timeout, it will trigger a checkpoint request.
*/
trace_colo_compare_main("packet different");
- g_queue_push_head(&conn->primary_list, pkt);
+ g_queue_push_tail(&conn->primary_list, pkt);
colo_compare_inconsistency_notify(s);
break;
@@ -819,7 +819,7 @@
entry->buf = g_malloc(size);
memcpy(entry->buf, buf, size);
}
- g_queue_push_head(&sendco->send_list, entry);
+ g_queue_push_tail(&sendco->send_list, entry);
if (sendco->done) {
sendco->co = qemu_coroutine_create(_compare_chr_send, sendco);
@@ -1267,7 +1267,7 @@
}
if (!s->expired_scan_cycle) {
- /* Set default value to 3000 MS */
+ /* Set default value to 1000 MS */
s->expired_scan_cycle = REGULAR_PACKET_CHECK_MS;
}
@@ -1347,7 +1347,7 @@
Packet *pkt = NULL;
while (!g_queue_is_empty(&conn->primary_list)) {
- pkt = g_queue_pop_head(&conn->primary_list);
+ pkt = g_queue_pop_tail(&conn->primary_list);
compare_chr_send(s,
pkt->data,
pkt->size,
@@ -1357,7 +1357,7 @@
packet_destroy_partial(pkt, NULL);
}
while (!g_queue_is_empty(&conn->secondary_list)) {
- pkt = g_queue_pop_head(&conn->secondary_list);
+ pkt = g_queue_pop_tail(&conn->secondary_list);
packet_destroy(pkt, NULL);
}
}
diff --git a/net/eth.c b/net/eth.c
index fe876d1..f074b2f 100644
--- a/net/eth.c
+++ b/net/eth.c
@@ -389,7 +389,6 @@
case IP6_HOP_BY_HOP:
case IP6_ROUTING:
case IP6_FRAGMENT:
- case IP6_ESP:
case IP6_AUTHENTICATION:
case IP6_DESTINATON:
case IP6_MOBILITY:
diff --git a/net/filter-mirror.c b/net/filter-mirror.c
index f20240c..34a63b5 100644
--- a/net/filter-mirror.c
+++ b/net/filter-mirror.c
@@ -20,6 +20,7 @@
#include "chardev/char-fe.h"
#include "qemu/iov.h"
#include "qemu/sockets.h"
+#include "block/aio-wait.h"
#define TYPE_FILTER_MIRROR "filter-mirror"
typedef struct MirrorState MirrorState;
@@ -42,20 +43,21 @@
bool vnet_hdr;
};
-static int filter_send(MirrorState *s,
- const struct iovec *iov,
- int iovcnt)
+typedef struct FilterSendCo {
+ MirrorState *s;
+ char *buf;
+ ssize_t size;
+ bool done;
+ int ret;
+} FilterSendCo;
+
+static int _filter_send(MirrorState *s,
+ char *buf,
+ ssize_t size)
{
NetFilterState *nf = NETFILTER(s);
int ret = 0;
- ssize_t size = 0;
uint32_t len = 0;
- char *buf;
-
- size = iov_size(iov, iovcnt);
- if (!size) {
- return 0;
- }
len = htonl(size);
ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)&len, sizeof(len));
@@ -80,10 +82,7 @@
}
}
- buf = g_malloc(size);
- iov_to_buf(iov, iovcnt, 0, buf, size);
ret = qemu_chr_fe_write_all(&s->chr_out, (uint8_t *)buf, size);
- g_free(buf);
if (ret != size) {
goto err;
}
@@ -94,6 +93,47 @@
return ret < 0 ? ret : -EIO;
}
+static void coroutine_fn filter_send_co(void *opaque)
+{
+ FilterSendCo *data = opaque;
+
+ data->ret = _filter_send(data->s, data->buf, data->size);
+ data->done = true;
+ g_free(data->buf);
+ aio_wait_kick();
+}
+
+static int filter_send(MirrorState *s,
+ const struct iovec *iov,
+ int iovcnt)
+{
+ ssize_t size = iov_size(iov, iovcnt);
+ char *buf = NULL;
+
+ if (!size) {
+ return 0;
+ }
+
+ buf = g_malloc(size);
+ iov_to_buf(iov, iovcnt, 0, buf, size);
+
+ FilterSendCo data = {
+ .s = s,
+ .size = size,
+ .buf = buf,
+ .ret = 0,
+ };
+
+ Coroutine *co = qemu_coroutine_create(filter_send_co, &data);
+ qemu_coroutine_enter(co);
+
+ while (!data.done) {
+ aio_poll(qemu_get_aio_context(), true);
+ }
+
+ return data.ret;
+}
+
static void redirector_to_filter(NetFilterState *nf,
const uint8_t *buf,
int len)
diff --git a/net/tap-linux.c b/net/tap-linux.c
index 9584769..5e70b93 100644
--- a/net/tap-linux.c
+++ b/net/tap-linux.c
@@ -150,6 +150,7 @@
int tap_probe_vnet_hdr(int fd, Error **errp)
{
struct ifreq ifr;
+ memset(&ifr, 0, sizeof(ifr));
if (ioctl(fd, TUNGETIFF, &ifr) != 0) {
/* TUNGETIFF is available since kernel v2.6.27 */
diff --git a/net/tap.c b/net/tap.c
index f716be3..c5cbeaa 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -900,6 +900,7 @@
if (i == 0) {
vnet_hdr = tap_probe_vnet_hdr(fd, errp);
if (vnet_hdr < 0) {
+ ret = -1;
goto free_fail;
}
} else if (vnet_hdr != tap_probe_vnet_hdr(fd, NULL)) {
diff --git a/pc-bios/meson.build b/pc-bios/meson.build
index 4ac7a55..c86dedf 100644
--- a/pc-bios/meson.build
+++ b/pc-bios/meson.build
@@ -81,6 +81,8 @@
'opensbi-riscv32-generic-fw_dynamic.bin',
'opensbi-riscv64-generic-fw_dynamic.bin',
'npcm7xx_bootrom.bin',
+ 'vof.bin',
+ 'vof-nvram.bin',
)
if get_option('install_blobs')
diff --git a/softmmu/cpus.c b/softmmu/cpus.c
index 23bca46..035395a 100644
--- a/softmmu/cpus.c
+++ b/softmmu/cpus.c
@@ -73,12 +73,7 @@
bool cpu_work_list_empty(CPUState *cpu)
{
- bool ret;
-
- qemu_mutex_lock(&cpu->work_mutex);
- ret = QSIMPLEQ_EMPTY(&cpu->work_list);
- qemu_mutex_unlock(&cpu->work_mutex);
- return ret;
+ return QSIMPLEQ_EMPTY_ATOMIC(&cpu->work_list);
}
bool cpu_thread_is_idle(CPUState *cpu)
diff --git a/target/ppc/cpu-models.c b/target/ppc/cpu-models.c
index a2c720c..976be5e 100644
--- a/target/ppc/cpu-models.c
+++ b/target/ppc/cpu-models.c
@@ -422,12 +422,6 @@
CPU_POWERPC_MPC8641D, POWERPC_SVR_8641D, e600)
/* 32 bits "classic" PowerPC */
/* PowerPC 6xx family */
- POWERPC_DEF("601_v0", CPU_POWERPC_601_v0, 601,
- "PowerPC 601v0")
- POWERPC_DEF("601_v1", CPU_POWERPC_601_v1, 601,
- "PowerPC 601v1")
- POWERPC_DEF("601_v2", CPU_POWERPC_601_v2, 601v,
- "PowerPC 601v2")
POWERPC_DEF("603", CPU_POWERPC_603, 603,
"PowerPC 603")
POWERPC_DEF("603e_v1.1", CPU_POWERPC_603E_v11, 603E,
@@ -859,8 +853,6 @@
{ "mpc8555", "mpc8555_v11" },
{ "mpc8555e", "mpc8555e_v11" },
{ "mpc8560", "mpc8560_v21" },
- { "601", "601_v2" },
- { "601v", "601_v2" },
{ "vanilla", "603" },
{ "603e", "603e_v4.1" },
{ "stretch", "603e_v4.1" },
diff --git a/target/ppc/cpu-models.h b/target/ppc/cpu-models.h
index 612978a..76775a7 100644
--- a/target/ppc/cpu-models.h
+++ b/target/ppc/cpu-models.h
@@ -205,9 +205,6 @@
#define CPU_POWERPC_MPC8641 CPU_POWERPC_e600
#define CPU_POWERPC_MPC8641D CPU_POWERPC_e600
/* PowerPC 6xx cores */
- CPU_POWERPC_601_v0 = 0x00010001,
- CPU_POWERPC_601_v1 = 0x00010001,
- CPU_POWERPC_601_v2 = 0x00010002,
CPU_POWERPC_603 = 0x00030100,
CPU_POWERPC_603E_v11 = 0x00060101,
CPU_POWERPC_603E_v12 = 0x00060102,
diff --git a/target/ppc/cpu-qom.h b/target/ppc/cpu-qom.h
index 99a6b50..98facee 100644
--- a/target/ppc/cpu-qom.h
+++ b/target/ppc/cpu-qom.h
@@ -61,8 +61,6 @@
POWERPC_MMU_BOOKE = 0x00000008,
/* BookE 2.06 MMU model */
POWERPC_MMU_BOOKE206 = 0x00000009,
- /* PowerPC 601 MMU model (specific BATs format) */
- POWERPC_MMU_601 = 0x0000000A,
#define POWERPC_MMU_64 0x00010000
/* 64 bits PowerPC MMU */
POWERPC_MMU_64B = POWERPC_MMU_64 | 0x00000001,
@@ -90,20 +88,10 @@
POWERPC_EXCP_STD,
/* PowerPC 40x exception model */
POWERPC_EXCP_40x,
- /* PowerPC 601 exception model */
- POWERPC_EXCP_601,
- /* PowerPC 602 exception model */
- POWERPC_EXCP_602,
- /* PowerPC 603 exception model */
- POWERPC_EXCP_603,
- /* PowerPC G2 exception model */
- POWERPC_EXCP_G2,
- /* PowerPC 604 exception model */
- POWERPC_EXCP_604,
- /* PowerPC 7x0 exception model */
- POWERPC_EXCP_7x0,
- /* PowerPC 7x5 exception model */
- POWERPC_EXCP_7x5,
+ /* PowerPC 603/604/G2 exception model */
+ POWERPC_EXCP_6xx,
+ /* PowerPC 7xx exception model */
+ POWERPC_EXCP_7xx,
/* PowerPC 74xx exception model */
POWERPC_EXCP_74xx,
/* BookE exception model */
diff --git a/target/ppc/cpu.h b/target/ppc/cpu.h
index dcd83b5..555c6b9 100644
--- a/target/ppc/cpu.h
+++ b/target/ppc/cpu.h
@@ -89,11 +89,9 @@
POWERPC_EXCP_VPU = 73, /* Vector unavailable exception */
/* 40x specific exceptions */
POWERPC_EXCP_PIT = 74, /* Programmable interval timer interrupt */
- /* 601 specific exceptions */
- POWERPC_EXCP_IO = 75, /* IO error exception */
- POWERPC_EXCP_RUNM = 76, /* Run mode exception */
+ /* Vectors 75-76 are 601 specific exceptions */
/* 602 specific exceptions */
- POWERPC_EXCP_EMUL = 77, /* Emulation trap exception */
+ POWERPC_EXCP_EMUL = 77, /* Emulation trap exception */
/* 602/603 specific exceptions */
POWERPC_EXCP_IFTLB = 78, /* Instruction fetch TLB miss */
POWERPC_EXCP_DLTLB = 79, /* Data load TLB miss */
@@ -632,8 +630,7 @@
POWERPC_FLAG_PX = 0x00000200,
POWERPC_FLAG_PMM = 0x00000400,
/* Flag for special features */
- /* Decrementer clock: RTC clock (POWER, 601) or bus clock */
- POWERPC_FLAG_RTC_CLK = 0x00010000,
+ /* Decrementer clock */
POWERPC_FLAG_BUS_CLK = 0x00020000,
/* Has CFAR */
POWERPC_FLAG_CFAR = 0x00040000,
@@ -643,8 +640,6 @@
POWERPC_FLAG_TM = 0x00100000,
/* Has SCV (ISA 3.00) */
POWERPC_FLAG_SCV = 0x00200000,
- /* Has HID0 for LE bit (601) */
- POWERPC_FLAG_HID0_LE = 0x00400000,
};
/*
@@ -655,7 +650,7 @@
* the MSR are validated in hreg_compute_hflags.
*/
enum {
- HFLAGS_LE = 0, /* MSR_LE -- comes from elsewhere on 601 */
+ HFLAGS_LE = 0, /* MSR_LE */
HFLAGS_HV = 1, /* computed from MSR_HV and other state */
HFLAGS_64 = 2, /* computed from MSR_CE and MSR_SF */
HFLAGS_GTSE = 3, /* computed from SPR_LPCR[GTSE] */
@@ -1389,11 +1384,7 @@
void cpu_ppc_store_tbu40(CPUPPCState *env, uint64_t value);
uint64_t cpu_ppc_load_purr(CPUPPCState *env);
void cpu_ppc_store_purr(CPUPPCState *env, uint64_t value);
-uint32_t cpu_ppc601_load_rtcl(CPUPPCState *env);
-uint32_t cpu_ppc601_load_rtcu(CPUPPCState *env);
#if !defined(CONFIG_USER_ONLY)
-void cpu_ppc601_store_rtcl(CPUPPCState *env, uint32_t value);
-void cpu_ppc601_store_rtcu(CPUPPCState *env, uint32_t value);
target_ulong load_40x_pit(CPUPPCState *env);
void store_40x_pit(CPUPPCState *env, target_ulong val);
void store_40x_dbcr0(CPUPPCState *env, uint32_t val);
@@ -1516,17 +1507,12 @@
/* SPR definitions */
#define SPR_MQ (0x000)
#define SPR_XER (0x001)
-#define SPR_601_VRTCU (0x004)
-#define SPR_601_VRTCL (0x005)
-#define SPR_601_UDECR (0x006)
#define SPR_LR (0x008)
#define SPR_CTR (0x009)
#define SPR_UAMR (0x00D)
#define SPR_DSCR (0x011)
#define SPR_DSISR (0x012)
-#define SPR_DAR (0x013) /* DAE for PowerPC 601 */
-#define SPR_601_RTCU (0x014)
-#define SPR_601_RTCL (0x015)
+#define SPR_DAR (0x013)
#define SPR_DECR (0x016)
#define SPR_SDR1 (0x019)
#define SPR_SRR0 (0x01A)
@@ -2003,7 +1989,6 @@
#define SPR_HID1 (0x3F1)
#define SPR_IABR (0x3F2)
#define SPR_40x_DBCR0 (0x3F2)
-#define SPR_601_HID2 (0x3F2)
#define SPR_Exxx_L1CSR0 (0x3F2)
#define SPR_ICTRL (0x3F3)
#define SPR_HID2 (0x3F3)
@@ -2019,7 +2004,6 @@
#define DABR_MASK (~(target_ulong)0x7)
#define SPR_Exxx_BUCSR (0x3F5)
#define SPR_40x_IAC2 (0x3F5)
-#define SPR_601_HID5 (0x3F5)
#define SPR_40x_DAC1 (0x3F6)
#define SPR_MSSCR0 (0x3F6)
#define SPR_970_HID5 (0x3F6)
@@ -2052,7 +2036,6 @@
#define SPR_403_PBL2 (0x3FE)
#define SPR_PIR (0x3FF)
#define SPR_403_PBU2 (0x3FF)
-#define SPR_601_HID15 (0x3FF)
#define SPR_604_HID15 (0x3FF)
#define SPR_E500_SVR (0x3FF)
@@ -2117,15 +2100,6 @@
#define PPC_RES PPC_INSNS_BASE
/* spr/msr access instructions */
#define PPC_MISC PPC_INSNS_BASE
- /* Deprecated instruction sets */
- /* Original POWER instruction set */
- PPC_POWER = 0x0000000000000002ULL,
- /* POWER2 instruction set extension */
- PPC_POWER2 = 0x0000000000000004ULL,
- /* Power RTC support */
- PPC_POWER_RTC = 0x0000000000000008ULL,
- /* Power-to-PowerPC bridge (601) */
- PPC_POWER_BR = 0x0000000000000010ULL,
/* 64 bits PowerPC instruction set */
PPC_64B = 0x0000000000000020ULL,
/* New 64 bits extensions (PowerPC 2.0x) */
@@ -2236,8 +2210,7 @@
/* popcntw and popcntd instructions */
PPC_POPCNTWD = 0x8000000000000000ULL,
-#define PPC_TCG_INSNS (PPC_INSNS_BASE | PPC_POWER | PPC_POWER2 \
- | PPC_POWER_RTC | PPC_POWER_BR | PPC_64B \
+#define PPC_TCG_INSNS (PPC_INSNS_BASE | PPC_64B \
| PPC_64BX | PPC_64H | PPC_WAIT | PPC_MFTB \
| PPC_ISEL | PPC_POPCNTB \
| PPC_STRING | PPC_FLOAT | PPC_FLOAT_EXT \
diff --git a/target/ppc/cpu_init.c b/target/ppc/cpu_init.c
index bf60529..d97f718 100644
--- a/target/ppc/cpu_init.c
+++ b/target/ppc/cpu_init.c
@@ -749,83 +749,6 @@
0x00000000);
}
-/* SPR specific to PowerPC 601 implementation */
-static void register_601_sprs(CPUPPCState *env)
-{
- /* Multiplication/division register */
- /* MQ */
- spr_register(env, SPR_MQ, "MQ",
- &spr_read_generic, &spr_write_generic,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* RTC registers */
- spr_register(env, SPR_601_RTCU, "RTCU",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, &spr_write_601_rtcu,
- 0x00000000);
- spr_register(env, SPR_601_VRTCU, "RTCU",
- &spr_read_601_rtcu, SPR_NOACCESS,
- &spr_read_601_rtcu, SPR_NOACCESS,
- 0x00000000);
- spr_register(env, SPR_601_RTCL, "RTCL",
- SPR_NOACCESS, SPR_NOACCESS,
- SPR_NOACCESS, &spr_write_601_rtcl,
- 0x00000000);
- spr_register(env, SPR_601_VRTCL, "RTCL",
- &spr_read_601_rtcl, SPR_NOACCESS,
- &spr_read_601_rtcl, SPR_NOACCESS,
- 0x00000000);
- /* Timer */
-#if 0 /* ? */
- spr_register(env, SPR_601_UDECR, "UDECR",
- &spr_read_decr, SPR_NOACCESS,
- &spr_read_decr, SPR_NOACCESS,
- 0x00000000);
-#endif
- /* External access control */
- /* XXX : not implemented */
- spr_register(env, SPR_EAR, "EAR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* Memory management */
-#if !defined(CONFIG_USER_ONLY)
- spr_register(env, SPR_IBAT0U, "IBAT0U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_601_ubat, &spr_write_601_ubatu,
- 0x00000000);
- spr_register(env, SPR_IBAT0L, "IBAT0L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_601_ubat, &spr_write_601_ubatl,
- 0x00000000);
- spr_register(env, SPR_IBAT1U, "IBAT1U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_601_ubat, &spr_write_601_ubatu,
- 0x00000000);
- spr_register(env, SPR_IBAT1L, "IBAT1L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_601_ubat, &spr_write_601_ubatl,
- 0x00000000);
- spr_register(env, SPR_IBAT2U, "IBAT2U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_601_ubat, &spr_write_601_ubatu,
- 0x00000000);
- spr_register(env, SPR_IBAT2L, "IBAT2L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_601_ubat, &spr_write_601_ubatl,
- 0x00000000);
- spr_register(env, SPR_IBAT3U, "IBAT3U",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_601_ubat, &spr_write_601_ubatu,
- 0x00000000);
- spr_register(env, SPR_IBAT3L, "IBAT3L",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_601_ubat, &spr_write_601_ubatl,
- 0x00000000);
- env->nb_BATs = 4;
-#endif
-}
-
static void register_74xx_sprs(CPUPPCState *env)
{
/* Processor identification */
@@ -2060,26 +1983,6 @@
#endif
}
-static void init_excp_601(CPUPPCState *env)
-{
-#if !defined(CONFIG_USER_ONLY)
- env->excp_vectors[POWERPC_EXCP_RESET] = 0x00000100;
- env->excp_vectors[POWERPC_EXCP_MCHECK] = 0x00000200;
- env->excp_vectors[POWERPC_EXCP_DSI] = 0x00000300;
- env->excp_vectors[POWERPC_EXCP_ISI] = 0x00000400;
- env->excp_vectors[POWERPC_EXCP_EXTERNAL] = 0x00000500;
- env->excp_vectors[POWERPC_EXCP_ALIGN] = 0x00000600;
- env->excp_vectors[POWERPC_EXCP_PROGRAM] = 0x00000700;
- env->excp_vectors[POWERPC_EXCP_FPU] = 0x00000800;
- env->excp_vectors[POWERPC_EXCP_DECR] = 0x00000900;
- env->excp_vectors[POWERPC_EXCP_IO] = 0x00000A00;
- env->excp_vectors[POWERPC_EXCP_SYSCALL] = 0x00000C00;
- env->excp_vectors[POWERPC_EXCP_RUNM] = 0x00002000;
- /* Hardware reset vector */
- env->hreset_vector = 0x00000100UL;
-#endif
-}
-
static void init_excp_603(CPUPPCState *env)
{
#if !defined(CONFIG_USER_ONLY)
@@ -2703,89 +2606,6 @@
POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK;
}
-static void init_proc_440x4(CPUPPCState *env)
-{
- /* Time base */
- register_tbl(env);
- register_BookE_sprs(env, 0x000000000000FFFFULL);
- register_440_sprs(env);
- register_usprgh_sprs(env);
- /* Processor identification */
- spr_register(env, SPR_BOOKE_PIR, "PIR",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_pir,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_BOOKE_IAC3, "IAC3",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_BOOKE_IAC4, "IAC4",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_BOOKE_DVC1, "DVC1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_BOOKE_DVC2, "DVC2",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* Memory management */
-#if !defined(CONFIG_USER_ONLY)
- env->nb_tlb = 64;
- env->nb_ways = 1;
- env->id_tlbs = 0;
- env->tlb_type = TLB_EMB;
-#endif
- init_excp_BookE(env);
- env->dcache_line_size = 32;
- env->icache_line_size = 32;
- /* XXX: TODO: allocate internal IRQ controller */
-
- SET_FIT_PERIOD(12, 16, 20, 24);
- SET_WDT_PERIOD(20, 24, 28, 32);
-}
-
-POWERPC_FAMILY(440x4)(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-
- dc->desc = "PowerPC 440x4";
- pcc->init_proc = init_proc_440x4;
- pcc->check_pow = check_pow_nocheck;
- pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING |
- PPC_DCR | PPC_WRTEE |
- PPC_CACHE | PPC_CACHE_ICBI |
- PPC_CACHE_DCBZ | PPC_CACHE_DCBA |
- PPC_MEM_TLBSYNC | PPC_MFTB |
- PPC_BOOKE | PPC_4xx_COMMON | PPC_405_MAC |
- PPC_440_SPEC;
- pcc->msr_mask = (1ull << MSR_POW) |
- (1ull << MSR_CE) |
- (1ull << MSR_EE) |
- (1ull << MSR_PR) |
- (1ull << MSR_FP) |
- (1ull << MSR_ME) |
- (1ull << MSR_FE0) |
- (1ull << MSR_DWE) |
- (1ull << MSR_DE) |
- (1ull << MSR_FE1) |
- (1ull << MSR_IR) |
- (1ull << MSR_DR);
- pcc->mmu_model = POWERPC_MMU_BOOKE;
- pcc->excp_model = POWERPC_EXCP_BOOKE;
- pcc->bus_model = PPC_FLAGS_INPUT_BookE;
- pcc->bfd_mach = bfd_mach_ppc_403;
- pcc->flags = POWERPC_FLAG_CE | POWERPC_FLAG_DWE |
- POWERPC_FLAG_DE | POWERPC_FLAG_BUS_CLK;
-}
-
static void init_proc_440x5(CPUPPCState *env)
{
/* Time base */
@@ -2962,7 +2782,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_REAL;
- pcc->excp_model = POWERPC_EXCP_603;
+ pcc->excp_model = POWERPC_EXCP_6xx;
pcc->bus_model = PPC_FLAGS_INPUT_RCPU;
pcc->bfd_mach = bfd_mach_ppc_505;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
@@ -3005,7 +2825,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_MPC8xx;
- pcc->excp_model = POWERPC_EXCP_603;
+ pcc->excp_model = POWERPC_EXCP_6xx;
pcc->bus_model = PPC_FLAGS_INPUT_RCPU;
pcc->bfd_mach = bfd_mach_ppc_860;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
@@ -3086,7 +2906,7 @@
(1ull << MSR_DR) |
(1ull << MSR_RI);
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
- pcc->excp_model = POWERPC_EXCP_G2;
+ pcc->excp_model = POWERPC_EXCP_6xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_ec603e;
pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |
@@ -3168,7 +2988,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
- pcc->excp_model = POWERPC_EXCP_G2;
+ pcc->excp_model = POWERPC_EXCP_6xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_ec603e;
pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |
@@ -3423,7 +3243,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
- pcc->excp_model = POWERPC_EXCP_603;
+ pcc->excp_model = POWERPC_EXCP_6xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_603;
pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |
@@ -3892,120 +3712,6 @@
#endif
/* Non-embedded PowerPC */
-
-#define POWERPC_MSRR_601 (0x0000000000001040ULL)
-
-static void init_proc_601(CPUPPCState *env)
-{
- register_ne_601_sprs(env);
- register_sdr1_sprs(env);
- register_601_sprs(env);
- /* Hardware implementation registers */
- /* XXX : not implemented */
- spr_register(env, SPR_HID0, "HID0",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_hid0_601,
- 0x80010080);
- /* XXX : not implemented */
- spr_register(env, SPR_HID1, "HID1",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_601_HID2, "HID2",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* XXX : not implemented */
- spr_register(env, SPR_601_HID5, "HID5",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
- /* Memory management */
- init_excp_601(env);
- /*
- * XXX: beware that dcache line size is 64
- * but dcbz uses 32 bytes "sectors"
- * XXX: this breaks clcs instruction !
- */
- env->dcache_line_size = 32;
- env->icache_line_size = 64;
- /* Allocate hardware IRQ controller */
- ppc6xx_irq_init(env_archcpu(env));
-}
-
-POWERPC_FAMILY(601)(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-
- dc->desc = "PowerPC 601";
- pcc->init_proc = init_proc_601;
- pcc->check_pow = check_pow_none;
- pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR |
- PPC_FLOAT |
- PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
- PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE |
- PPC_SEGMENT | PPC_EXTERN;
- pcc->msr_mask = (1ull << MSR_EE) |
- (1ull << MSR_PR) |
- (1ull << MSR_FP) |
- (1ull << MSR_ME) |
- (1ull << MSR_FE0) |
- (1ull << MSR_SE) |
- (1ull << MSR_FE1) |
- (1ull << MSR_EP) |
- (1ull << MSR_IR) |
- (1ull << MSR_DR);
- pcc->mmu_model = POWERPC_MMU_601;
- pcc->excp_model = POWERPC_EXCP_601;
- pcc->bus_model = PPC_FLAGS_INPUT_6xx;
- pcc->bfd_mach = bfd_mach_ppc_601;
- pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_HID0_LE;
-}
-
-#define POWERPC_MSRR_601v (0x0000000000001040ULL)
-
-static void init_proc_601v(CPUPPCState *env)
-{
- init_proc_601(env);
- /* XXX : not implemented */
- spr_register(env, SPR_601_HID15, "HID15",
- SPR_NOACCESS, SPR_NOACCESS,
- &spr_read_generic, &spr_write_generic,
- 0x00000000);
-}
-
-POWERPC_FAMILY(601v)(ObjectClass *oc, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(oc);
- PowerPCCPUClass *pcc = POWERPC_CPU_CLASS(oc);
-
- dc->desc = "PowerPC 601v";
- pcc->init_proc = init_proc_601v;
- pcc->check_pow = check_pow_none;
- pcc->insns_flags = PPC_INSNS_BASE | PPC_STRING | PPC_POWER_BR |
- PPC_FLOAT |
- PPC_CACHE | PPC_CACHE_ICBI | PPC_CACHE_DCBZ |
- PPC_MEM_SYNC | PPC_MEM_EIEIO | PPC_MEM_TLBIE |
- PPC_SEGMENT | PPC_EXTERN;
- pcc->msr_mask = (1ull << MSR_EE) |
- (1ull << MSR_PR) |
- (1ull << MSR_FP) |
- (1ull << MSR_ME) |
- (1ull << MSR_FE0) |
- (1ull << MSR_SE) |
- (1ull << MSR_FE1) |
- (1ull << MSR_EP) |
- (1ull << MSR_IR) |
- (1ull << MSR_DR);
- pcc->mmu_model = POWERPC_MMU_601;
- pcc->excp_model = POWERPC_EXCP_601;
- pcc->bus_model = PPC_FLAGS_INPUT_6xx;
- pcc->bfd_mach = bfd_mach_ppc_601;
- pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_HID0_LE;
-}
-
static void init_proc_603(CPUPPCState *env)
{
register_ne_601_sprs(env);
@@ -4066,7 +3772,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
- pcc->excp_model = POWERPC_EXCP_603;
+ pcc->excp_model = POWERPC_EXCP_6xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_603;
pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |
@@ -4105,7 +3811,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
- pcc->excp_model = POWERPC_EXCP_603;
+ pcc->excp_model = POWERPC_EXCP_6xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_ec603e;
pcc->flags = POWERPC_FLAG_TGPR | POWERPC_FLAG_SE |
@@ -4166,7 +3872,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_32B;
- pcc->excp_model = POWERPC_EXCP_604;
+ pcc->excp_model = POWERPC_EXCP_6xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_604;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
@@ -4247,7 +3953,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_32B;
- pcc->excp_model = POWERPC_EXCP_604;
+ pcc->excp_model = POWERPC_EXCP_6xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_604;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
@@ -4315,7 +4021,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_32B;
- pcc->excp_model = POWERPC_EXCP_7x0;
+ pcc->excp_model = POWERPC_EXCP_7xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
@@ -4392,7 +4098,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_32B;
- pcc->excp_model = POWERPC_EXCP_7x0;
+ pcc->excp_model = POWERPC_EXCP_7xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
@@ -4592,7 +4298,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_32B;
- pcc->excp_model = POWERPC_EXCP_7x0;
+ pcc->excp_model = POWERPC_EXCP_7xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
@@ -4672,7 +4378,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_32B;
- pcc->excp_model = POWERPC_EXCP_7x0;
+ pcc->excp_model = POWERPC_EXCP_7xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
@@ -4757,7 +4463,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_32B;
- pcc->excp_model = POWERPC_EXCP_7x0;
+ pcc->excp_model = POWERPC_EXCP_7xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
@@ -4842,7 +4548,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_32B;
- pcc->excp_model = POWERPC_EXCP_7x0;
+ pcc->excp_model = POWERPC_EXCP_7xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
@@ -4918,7 +4624,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
- pcc->excp_model = POWERPC_EXCP_7x5;
+ pcc->excp_model = POWERPC_EXCP_7xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
@@ -5005,7 +4711,7 @@
(1ull << MSR_RI) |
(1ull << MSR_LE);
pcc->mmu_model = POWERPC_MMU_SOFT_6xx;
- pcc->excp_model = POWERPC_EXCP_7x5;
+ pcc->excp_model = POWERPC_EXCP_7xx;
pcc->bus_model = PPC_FLAGS_INPUT_6xx;
pcc->bfd_mach = bfd_mach_ppc_750;
pcc->flags = POWERPC_FLAG_SE | POWERPC_FLAG_BE |
@@ -7760,7 +7466,7 @@
"Should not define POWERPC_FLAG_PX nor POWERPC_FLAG_PMM\n");
exit(1);
}
- if ((env->flags & (POWERPC_FLAG_RTC_CLK | POWERPC_FLAG_BUS_CLK)) == 0) {
+ if ((env->flags & POWERPC_FLAG_BUS_CLK) == 0) {
fprintf(stderr, "PowerPC flags inconsistency\n"
"Should define the time-base and decrementer clock source\n");
exit(1);
@@ -8574,7 +8280,6 @@
switch (env->mmu_model) {
case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
case POWERPC_MMU_SOFT_6xx:
#if defined(TARGET_PPC64)
case POWERPC_MMU_64B:
diff --git a/target/ppc/excp_helper.c b/target/ppc/excp_helper.c
index c107953..fcc83a7 100644
--- a/target/ppc/excp_helper.c
+++ b/target/ppc/excp_helper.c
@@ -73,8 +73,6 @@
case POWERPC_EXCP_HISEG: return "HISEG";
case POWERPC_EXCP_VPU: return "VPU";
case POWERPC_EXCP_PIT: return "PIT";
- case POWERPC_EXCP_IO: return "IO";
- case POWERPC_EXCP_RUNM: return "RUNM";
case POWERPC_EXCP_EMUL: return "EMUL";
case POWERPC_EXCP_IFTLB: return "IFTLB";
case POWERPC_EXCP_DLTLB: return "DLTLB";
@@ -165,7 +163,7 @@
env->error_code);
}
-
+#if defined(TARGET_PPC64)
static int powerpc_reset_wakeup(CPUState *cs, CPUPPCState *env, int excp,
target_ulong *msr)
{
@@ -264,12 +262,10 @@
* | a | h | 11 | 1 | 1 | h |
* +--------------------------------------------------------------------+
*/
-static void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp_model, int excp,
- target_ulong msr,
- target_ulong *new_msr,
- target_ulong *vector)
+static void ppc_excp_apply_ail(PowerPCCPU *cpu, int excp, target_ulong msr,
+ target_ulong *new_msr, target_ulong *vector)
{
-#if defined(TARGET_PPC64)
+ PowerPCCPUClass *pcc = POWERPC_CPU_GET_CLASS(cpu);
CPUPPCState *env = &cpu->env;
bool mmu_all_on = ((msr >> MSR_IR) & 1) && ((msr >> MSR_DR) & 1);
bool hv_escalation = !(msr & MSR_HVB) && (*new_msr & MSR_HVB);
@@ -282,8 +278,13 @@
return;
}
- if (excp_model == POWERPC_EXCP_POWER8 ||
- excp_model == POWERPC_EXCP_POWER9) {
+ if (!(pcc->lpcr_mask & LPCR_AIL)) {
+ /* This CPU does not have AIL */
+ return;
+ }
+
+ /* P8 & P9 */
+ if (!(pcc->lpcr_mask & LPCR_HAIL)) {
if (!mmu_all_on) {
/* AIL only works if MSR[IR] and MSR[DR] are both enabled. */
return;
@@ -306,7 +307,8 @@
return;
}
- } else if (excp_model == POWERPC_EXCP_POWER10) {
+ /* P10 and up */
+ } else {
if (!mmu_all_on && !hv_escalation) {
/*
* AIL works for HV interrupts even with guest MSR[IR/DR] disabled.
@@ -331,9 +333,6 @@
/* AIL=1 and AIL=2 are reserved, treat them like AIL=0 */
return;
}
- } else {
- /* Other processors do not support AIL */
- return;
}
/*
@@ -358,8 +357,8 @@
*vector |= 0xc000000000003000ull; /* Apply scv's AIL=3 offset */
}
}
-#endif
}
+#endif
static void powerpc_set_excp_state(PowerPCCPU *cpu,
target_ulong vector, target_ulong msr)
@@ -367,6 +366,8 @@
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
+ assert((msr & env->msr_mask) == msr);
+
/*
* We don't use hreg_store_msr here as already have treated any
* special case that could occur. Just store MSR and update hflags
@@ -375,7 +376,7 @@
* will prevent setting of the HV bit which some exceptions might need
* to do.
*/
- env->msr = msr & env->msr_mask;
+ env->msr = msr;
hreg_compute_hflags(env);
env->nip = vector;
/* Reset exception state */
@@ -399,14 +400,6 @@
target_ulong msr, new_msr, vector;
int srr0, srr1;
- if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
- cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
- }
-
- qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
- " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
- excp, env->error_code);
-
/* new srr1 value excluding must-be-zero bits */
msr = env->msr & ~0x783f0000ULL;
@@ -530,18 +523,6 @@
break;
}
- /* Sanity check */
- if (!(env->msr_mask & MSR_HVB)) {
- if (new_msr & MSR_HVB) {
- cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
- "no HV support\n", excp);
- }
- if (srr0 == SPR_HSRR0) {
- cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
- "no HV support\n", excp);
- }
- }
-
/* Save PC */
env->spr[srr0] = env->nip;
@@ -551,19 +532,373 @@
powerpc_set_excp_state(cpu, vector, new_msr);
}
-static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
+static void powerpc_excp_6xx(PowerPCCPU *cpu, int excp)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
target_ulong msr, new_msr, vector;
- if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
- cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
+ /* new srr1 value excluding must-be-zero bits */
+ msr = env->msr & ~0x783f0000ULL;
+
+ /*
+ * new interrupt handler msr preserves existing ME unless
+ * explicitly overriden
+ */
+ new_msr = env->msr & ((target_ulong)1 << MSR_ME);
+
+ /*
+ * Hypervisor emulation assistance interrupt only exists on server
+ * arch 2.05 server or later.
+ */
+ if (excp == POWERPC_EXCP_HV_EMU) {
+ excp = POWERPC_EXCP_PROGRAM;
}
- qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
- " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
- excp, env->error_code);
+ vector = env->excp_vectors[excp];
+ if (vector == (target_ulong)-1ULL) {
+ cpu_abort(cs, "Raised an exception without defined vector %d\n",
+ excp);
+ }
+
+ vector |= env->excp_prefix;
+
+ switch (excp) {
+ case POWERPC_EXCP_CRITICAL: /* Critical input */
+ break;
+ case POWERPC_EXCP_MCHECK: /* Machine check exception */
+ if (msr_me == 0) {
+ /*
+ * Machine check exception is not enabled. Enter
+ * checkstop state.
+ */
+ fprintf(stderr, "Machine check while not allowed. "
+ "Entering checkstop state\n");
+ if (qemu_log_separate()) {
+ qemu_log("Machine check while not allowed. "
+ "Entering checkstop state\n");
+ }
+ cs->halted = 1;
+ cpu_interrupt_exittb(cs);
+ }
+
+ /* machine check exceptions don't have ME set */
+ new_msr &= ~((target_ulong)1 << MSR_ME);
+
+ break;
+ case POWERPC_EXCP_DSI: /* Data storage exception */
+ trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+ break;
+ case POWERPC_EXCP_ISI: /* Instruction storage exception */
+ trace_ppc_excp_isi(msr, env->nip);
+ msr |= env->error_code;
+ break;
+ case POWERPC_EXCP_EXTERNAL: /* External input */
+ break;
+ case POWERPC_EXCP_ALIGN: /* Alignment exception */
+ /* Get rS/rD and rA from faulting opcode */
+ /*
+ * Note: the opcode fields will not be set properly for a
+ * direct store load/store, but nobody cares as nobody
+ * actually uses direct store segments.
+ */
+ env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
+ break;
+ case POWERPC_EXCP_PROGRAM: /* Program exception */
+ switch (env->error_code & ~0xF) {
+ case POWERPC_EXCP_FP:
+ if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
+ trace_ppc_excp_fp_ignore();
+ cs->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+ return;
+ }
+
+ /*
+ * FP exceptions always have NIP pointing to the faulting
+ * instruction, so always use store_next and claim we are
+ * precise in the MSR.
+ */
+ msr |= 0x00100000;
+ break;
+ case POWERPC_EXCP_INVAL:
+ trace_ppc_excp_inval(env->nip);
+ msr |= 0x00080000;
+ break;
+ case POWERPC_EXCP_PRIV:
+ msr |= 0x00040000;
+ break;
+ case POWERPC_EXCP_TRAP:
+ msr |= 0x00020000;
+ break;
+ default:
+ /* Should never occur */
+ cpu_abort(cs, "Invalid program exception %d. Aborting\n",
+ env->error_code);
+ break;
+ }
+ break;
+ case POWERPC_EXCP_SYSCALL: /* System call exception */
+ dump_syscall(env);
+
+ /*
+ * We need to correct the NIP which in this case is supposed
+ * to point to the next instruction
+ */
+ env->nip += 4;
+ break;
+ case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
+ case POWERPC_EXCP_DECR: /* Decrementer exception */
+ break;
+ case POWERPC_EXCP_DTLB: /* Data TLB error */
+ case POWERPC_EXCP_ITLB: /* Instruction TLB error */
+ break;
+ case POWERPC_EXCP_RESET: /* System reset exception */
+ if (msr_pow) {
+ cpu_abort(cs, "Trying to deliver power-saving system reset "
+ "exception %d with no HV support\n", excp);
+ }
+ break;
+ case POWERPC_EXCP_TRACE: /* Trace exception */
+ break;
+ case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
+ case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
+ case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
+ /* Swap temporary saved registers with GPRs */
+ if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
+ new_msr |= (target_ulong)1 << MSR_TGPR;
+ hreg_swap_gpr_tgpr(env);
+ }
+
+ ppc_excp_debug_sw_tlb(env, excp);
+
+ msr |= env->crf[0] << 28;
+ msr |= env->error_code; /* key, D/I, S/L bits */
+ /* Set way using a LRU mechanism */
+ msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
+ break;
+ case POWERPC_EXCP_FPA: /* Floating-point assist exception */
+ case POWERPC_EXCP_DABR: /* Data address breakpoint */
+ case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
+ case POWERPC_EXCP_SMI: /* System management interrupt */
+ case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
+ case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
+ cpu_abort(cs, "%s exception not implemented\n",
+ powerpc_excp_name(excp));
+ break;
+ default:
+ cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
+ break;
+ }
+
+ /*
+ * Sort out endianness of interrupt, this differs depending on the
+ * CPU, the HV mode, etc...
+ */
+ if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
+ new_msr |= (target_ulong)1 << MSR_LE;
+ }
+
+ /* Save PC */
+ env->spr[SPR_SRR0] = env->nip;
+
+ /* Save MSR */
+ env->spr[SPR_SRR1] = msr;
+
+ powerpc_set_excp_state(cpu, vector, new_msr);
+}
+
+static void powerpc_excp_7xx(PowerPCCPU *cpu, int excp)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+ target_ulong msr, new_msr, vector;
+
+ /* new srr1 value excluding must-be-zero bits */
+ msr = env->msr & ~0x783f0000ULL;
+
+ /*
+ * new interrupt handler msr preserves existing ME unless
+ * explicitly overriden
+ */
+ new_msr = env->msr & ((target_ulong)1 << MSR_ME);
+
+ /*
+ * Hypervisor emulation assistance interrupt only exists on server
+ * arch 2.05 server or later.
+ */
+ if (excp == POWERPC_EXCP_HV_EMU) {
+ excp = POWERPC_EXCP_PROGRAM;
+ }
+
+ vector = env->excp_vectors[excp];
+ if (vector == (target_ulong)-1ULL) {
+ cpu_abort(cs, "Raised an exception without defined vector %d\n",
+ excp);
+ }
+
+ vector |= env->excp_prefix;
+
+ switch (excp) {
+ case POWERPC_EXCP_MCHECK: /* Machine check exception */
+ if (msr_me == 0) {
+ /*
+ * Machine check exception is not enabled. Enter
+ * checkstop state.
+ */
+ fprintf(stderr, "Machine check while not allowed. "
+ "Entering checkstop state\n");
+ if (qemu_log_separate()) {
+ qemu_log("Machine check while not allowed. "
+ "Entering checkstop state\n");
+ }
+ cs->halted = 1;
+ cpu_interrupt_exittb(cs);
+ }
+
+ /* machine check exceptions don't have ME set */
+ new_msr &= ~((target_ulong)1 << MSR_ME);
+
+ break;
+ case POWERPC_EXCP_DSI: /* Data storage exception */
+ trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
+ break;
+ case POWERPC_EXCP_ISI: /* Instruction storage exception */
+ trace_ppc_excp_isi(msr, env->nip);
+ msr |= env->error_code;
+ break;
+ case POWERPC_EXCP_EXTERNAL: /* External input */
+ break;
+ case POWERPC_EXCP_ALIGN: /* Alignment exception */
+ /* Get rS/rD and rA from faulting opcode */
+ /*
+ * Note: the opcode fields will not be set properly for a
+ * direct store load/store, but nobody cares as nobody
+ * actually uses direct store segments.
+ */
+ env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
+ break;
+ case POWERPC_EXCP_PROGRAM: /* Program exception */
+ switch (env->error_code & ~0xF) {
+ case POWERPC_EXCP_FP:
+ if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
+ trace_ppc_excp_fp_ignore();
+ cs->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+ return;
+ }
+
+ /*
+ * FP exceptions always have NIP pointing to the faulting
+ * instruction, so always use store_next and claim we are
+ * precise in the MSR.
+ */
+ msr |= 0x00100000;
+ break;
+ case POWERPC_EXCP_INVAL:
+ trace_ppc_excp_inval(env->nip);
+ msr |= 0x00080000;
+ break;
+ case POWERPC_EXCP_PRIV:
+ msr |= 0x00040000;
+ break;
+ case POWERPC_EXCP_TRAP:
+ msr |= 0x00020000;
+ break;
+ default:
+ /* Should never occur */
+ cpu_abort(cs, "Invalid program exception %d. Aborting\n",
+ env->error_code);
+ break;
+ }
+ break;
+ case POWERPC_EXCP_SYSCALL: /* System call exception */
+ {
+ int lev = env->error_code;
+
+ if (lev == 1 && cpu->vhyp) {
+ dump_hcall(env);
+ } else {
+ dump_syscall(env);
+ }
+
+ /*
+ * We need to correct the NIP which in this case is supposed
+ * to point to the next instruction
+ */
+ env->nip += 4;
+
+ /*
+ * The Virtual Open Firmware (VOF) relies on the 'sc 1'
+ * instruction to communicate with QEMU. The pegasos2 machine
+ * uses VOF and the 7xx CPUs, so although the 7xx don't have
+ * HV mode, we need to keep hypercall support.
+ */
+ if (lev == 1 && cpu->vhyp) {
+ PPCVirtualHypervisorClass *vhc =
+ PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
+ vhc->hypercall(cpu->vhyp, cpu);
+ return;
+ }
+
+ break;
+ }
+ case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
+ case POWERPC_EXCP_DECR: /* Decrementer exception */
+ break;
+ case POWERPC_EXCP_RESET: /* System reset exception */
+ if (msr_pow) {
+ cpu_abort(cs, "Trying to deliver power-saving system reset "
+ "exception %d with no HV support\n", excp);
+ }
+ break;
+ case POWERPC_EXCP_TRACE: /* Trace exception */
+ break;
+ case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
+ case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
+ case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
+ ppc_excp_debug_sw_tlb(env, excp);
+
+ msr |= env->crf[0] << 28;
+ msr |= env->error_code; /* key, D/I, S/L bits */
+ /* Set way using a LRU mechanism */
+ msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
+
+ break;
+ case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
+ case POWERPC_EXCP_SMI: /* System management interrupt */
+ case POWERPC_EXCP_THERM: /* Thermal interrupt */
+ case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
+ cpu_abort(cs, "%s exception not implemented\n",
+ powerpc_excp_name(excp));
+ break;
+ default:
+ cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
+ break;
+ }
+
+ /*
+ * Sort out endianness of interrupt, this differs depending on the
+ * CPU, the HV mode, etc...
+ */
+ if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
+ new_msr |= (target_ulong)1 << MSR_LE;
+ }
+
+ /* Save PC */
+ env->spr[SPR_SRR0] = env->nip;
+
+ /* Save MSR */
+ env->spr[SPR_SRR1] = msr;
+
+ powerpc_set_excp_state(cpu, vector, new_msr);
+}
+
+static void powerpc_excp_74xx(PowerPCCPU *cpu, int excp)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+ target_ulong msr, new_msr, vector;
/* new srr1 value excluding must-be-zero bits */
msr = env->msr & ~0x783f0000ULL;
@@ -720,14 +1055,6 @@
break;
}
- /* Sanity check */
- if (!(env->msr_mask & MSR_HVB)) {
- if (new_msr & MSR_HVB) {
- cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
- "no HV support\n", excp);
- }
- }
-
/*
* Sort out endianness of interrupt, this differs depending on the
* CPU, the HV mode, etc...
@@ -745,23 +1072,219 @@
powerpc_set_excp_state(cpu, vector, new_msr);
}
+static void powerpc_excp_booke(PowerPCCPU *cpu, int excp)
+{
+ CPUState *cs = CPU(cpu);
+ CPUPPCState *env = &cpu->env;
+ target_ulong msr, new_msr, vector;
+ int srr0, srr1;
+
+ msr = env->msr;
+
+ /*
+ * new interrupt handler msr preserves existing ME unless
+ * explicitly overriden
+ */
+ new_msr = env->msr & ((target_ulong)1 << MSR_ME);
+
+ /* target registers */
+ srr0 = SPR_SRR0;
+ srr1 = SPR_SRR1;
+
+ /*
+ * Hypervisor emulation assistance interrupt only exists on server
+ * arch 2.05 server or later.
+ */
+ if (excp == POWERPC_EXCP_HV_EMU) {
+ excp = POWERPC_EXCP_PROGRAM;
+ }
+
+#ifdef TARGET_PPC64
+ /*
+ * SPEU and VPU share the same IVOR but they exist in different
+ * processors. SPEU is e500v1/2 only and VPU is e6500 only.
+ */
+ if (excp == POWERPC_EXCP_VPU) {
+ excp = POWERPC_EXCP_SPEU;
+ }
+#endif
+
+ vector = env->excp_vectors[excp];
+ if (vector == (target_ulong)-1ULL) {
+ cpu_abort(cs, "Raised an exception without defined vector %d\n",
+ excp);
+ }
+
+ vector |= env->excp_prefix;
+
+ switch (excp) {
+ case POWERPC_EXCP_CRITICAL: /* Critical input */
+ srr0 = SPR_BOOKE_CSRR0;
+ srr1 = SPR_BOOKE_CSRR1;
+ break;
+ case POWERPC_EXCP_MCHECK: /* Machine check exception */
+ if (msr_me == 0) {
+ /*
+ * Machine check exception is not enabled. Enter
+ * checkstop state.
+ */
+ fprintf(stderr, "Machine check while not allowed. "
+ "Entering checkstop state\n");
+ if (qemu_log_separate()) {
+ qemu_log("Machine check while not allowed. "
+ "Entering checkstop state\n");
+ }
+ cs->halted = 1;
+ cpu_interrupt_exittb(cs);
+ }
+
+ /* machine check exceptions don't have ME set */
+ new_msr &= ~((target_ulong)1 << MSR_ME);
+
+ /* FIXME: choose one or the other based on CPU type */
+ srr0 = SPR_BOOKE_MCSRR0;
+ srr1 = SPR_BOOKE_MCSRR1;
+
+ env->spr[SPR_BOOKE_CSRR0] = env->nip;
+ env->spr[SPR_BOOKE_CSRR1] = msr;
+
+ break;
+ case POWERPC_EXCP_DSI: /* Data storage exception */
+ trace_ppc_excp_dsi(env->spr[SPR_BOOKE_ESR], env->spr[SPR_BOOKE_DEAR]);
+ break;
+ case POWERPC_EXCP_ISI: /* Instruction storage exception */
+ trace_ppc_excp_isi(msr, env->nip);
+ break;
+ case POWERPC_EXCP_EXTERNAL: /* External input */
+ if (env->mpic_proxy) {
+ /* IACK the IRQ on delivery */
+ env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
+ }
+ break;
+ case POWERPC_EXCP_ALIGN: /* Alignment exception */
+ break;
+ case POWERPC_EXCP_PROGRAM: /* Program exception */
+ switch (env->error_code & ~0xF) {
+ case POWERPC_EXCP_FP:
+ if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
+ trace_ppc_excp_fp_ignore();
+ cs->exception_index = POWERPC_EXCP_NONE;
+ env->error_code = 0;
+ return;
+ }
+
+ /*
+ * FP exceptions always have NIP pointing to the faulting
+ * instruction, so always use store_next and claim we are
+ * precise in the MSR.
+ */
+ msr |= 0x00100000;
+ env->spr[SPR_BOOKE_ESR] = ESR_FP;
+ break;
+ case POWERPC_EXCP_INVAL:
+ trace_ppc_excp_inval(env->nip);
+ msr |= 0x00080000;
+ env->spr[SPR_BOOKE_ESR] = ESR_PIL;
+ break;
+ case POWERPC_EXCP_PRIV:
+ msr |= 0x00040000;
+ env->spr[SPR_BOOKE_ESR] = ESR_PPR;
+ break;
+ case POWERPC_EXCP_TRAP:
+ msr |= 0x00020000;
+ env->spr[SPR_BOOKE_ESR] = ESR_PTR;
+ break;
+ default:
+ /* Should never occur */
+ cpu_abort(cs, "Invalid program exception %d. Aborting\n",
+ env->error_code);
+ break;
+ }
+ break;
+ case POWERPC_EXCP_SYSCALL: /* System call exception */
+ dump_syscall(env);
+
+ /*
+ * We need to correct the NIP which in this case is supposed
+ * to point to the next instruction
+ */
+ env->nip += 4;
+ break;
+ case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
+ case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
+ case POWERPC_EXCP_DECR: /* Decrementer exception */
+ break;
+ case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
+ /* FIT on 4xx */
+ trace_ppc_excp_print("FIT");
+ break;
+ case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
+ trace_ppc_excp_print("WDT");
+ srr0 = SPR_BOOKE_CSRR0;
+ srr1 = SPR_BOOKE_CSRR1;
+ break;
+ case POWERPC_EXCP_DTLB: /* Data TLB error */
+ case POWERPC_EXCP_ITLB: /* Instruction TLB error */
+ break;
+ case POWERPC_EXCP_DEBUG: /* Debug interrupt */
+ if (env->flags & POWERPC_FLAG_DE) {
+ /* FIXME: choose one or the other based on CPU type */
+ srr0 = SPR_BOOKE_DSRR0;
+ srr1 = SPR_BOOKE_DSRR1;
+
+ env->spr[SPR_BOOKE_CSRR0] = env->nip;
+ env->spr[SPR_BOOKE_CSRR1] = msr;
+
+ /* DBSR already modified by caller */
+ } else {
+ cpu_abort(cs, "Debug exception triggered on unsupported model\n");
+ }
+ break;
+ case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable/VPU */
+ env->spr[SPR_BOOKE_ESR] = ESR_SPV;
+ break;
+ case POWERPC_EXCP_RESET: /* System reset exception */
+ if (msr_pow) {
+ cpu_abort(cs, "Trying to deliver power-saving system reset "
+ "exception %d with no HV support\n", excp);
+ }
+ break;
+ case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
+ case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
+ cpu_abort(cs, "%s exception not implemented\n",
+ powerpc_excp_name(excp));
+ break;
+ default:
+ cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
+ break;
+ }
+
+#if defined(TARGET_PPC64)
+ if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
+ /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
+ new_msr |= (target_ulong)1 << MSR_CM;
+ } else {
+ vector = (uint32_t)vector;
+ }
+#endif
+
+ /* Save PC */
+ env->spr[srr0] = env->nip;
+
+ /* Save MSR */
+ env->spr[srr1] = msr;
+
+ powerpc_set_excp_state(cpu, vector, new_msr);
+}
+
#ifdef TARGET_PPC64
static void powerpc_excp_books(PowerPCCPU *cpu, int excp)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
- int excp_model = env->excp_model;
target_ulong msr, new_msr, vector;
int srr0, srr1, lev = -1;
- if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
- cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
- }
-
- qemu_log_mask(CPU_LOG_INT, "Raise exception at " TARGET_FMT_lx
- " => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
- excp, env->error_code);
-
/* new srr1 value excluding must-be-zero bits */
msr = env->msr & ~0x783f0000ULL;
@@ -1005,15 +1528,9 @@
}
/* Sanity check */
- if (!(env->msr_mask & MSR_HVB)) {
- if (new_msr & MSR_HVB) {
- cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
- "no HV support\n", excp);
- }
- if (srr0 == SPR_HSRR0) {
- cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
- "no HV support\n", excp);
- }
+ if (!(env->msr_mask & MSR_HVB) && srr0 == SPR_HSRR0) {
+ cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
+ "no HV support\n", excp);
}
/*
@@ -1035,7 +1552,7 @@
}
/* This can update new_msr and vector if AIL applies */
- ppc_excp_apply_ail(cpu, excp_model, excp, msr, &new_msr, &vector);
+ ppc_excp_apply_ail(cpu, excp, msr, &new_msr, &vector);
powerpc_set_excp_state(cpu, vector, new_msr);
}
@@ -1046,17 +1563,10 @@
}
#endif
-/*
- * Note that this function should be greatly optimized when called
- * with a constant excp, from ppc_hw_interrupt
- */
-static inline void powerpc_excp_legacy(PowerPCCPU *cpu, int excp)
+static void powerpc_excp(PowerPCCPU *cpu, int excp)
{
CPUState *cs = CPU(cpu);
CPUPPCState *env = &cpu->env;
- int excp_model = env->excp_model;
- target_ulong msr, new_msr, vector;
- int srr0, srr1, lev = -1;
if (excp <= POWERPC_EXCP_NONE || excp >= POWERPC_EXCP_NB) {
cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
@@ -1066,471 +1576,22 @@
" => %s (%d) error=%02x\n", env->nip, powerpc_excp_name(excp),
excp, env->error_code);
- /* new srr1 value excluding must-be-zero bits */
- if (excp_model == POWERPC_EXCP_BOOKE) {
- msr = env->msr;
- } else {
- msr = env->msr & ~0x783f0000ULL;
- }
-
- /*
- * new interrupt handler msr preserves existing HV and ME unless
- * explicitly overriden
- */
- new_msr = env->msr & (((target_ulong)1 << MSR_ME) | MSR_HVB);
-
- /* target registers */
- srr0 = SPR_SRR0;
- srr1 = SPR_SRR1;
-
- /*
- * check for special resume at 0x100 from doze/nap/sleep/winkle on
- * P7/P8/P9
- */
- if (env->resume_as_sreset) {
- excp = powerpc_reset_wakeup(cs, env, excp, &msr);
- }
-
- /*
- * Hypervisor emulation assistance interrupt only exists on server
- * arch 2.05 server or later. We also don't want to generate it if
- * we don't have HVB in msr_mask (PAPR mode).
- */
- if (excp == POWERPC_EXCP_HV_EMU
-#if defined(TARGET_PPC64)
- && !(mmu_is_64bit(env->mmu_model) && (env->msr_mask & MSR_HVB))
-#endif /* defined(TARGET_PPC64) */
-
- ) {
- excp = POWERPC_EXCP_PROGRAM;
- }
-
-#ifdef TARGET_PPC64
- /*
- * SPEU and VPU share the same IVOR but they exist in different
- * processors. SPEU is e500v1/2 only and VPU is e6500 only.
- */
- if (excp_model == POWERPC_EXCP_BOOKE && excp == POWERPC_EXCP_VPU) {
- excp = POWERPC_EXCP_SPEU;
- }
-#endif
-
- vector = env->excp_vectors[excp];
- if (vector == (target_ulong)-1ULL) {
- cpu_abort(cs, "Raised an exception without defined vector %d\n",
- excp);
- }
-
- vector |= env->excp_prefix;
-
- switch (excp) {
- case POWERPC_EXCP_CRITICAL: /* Critical input */
- switch (excp_model) {
- case POWERPC_EXCP_40x:
- srr0 = SPR_40x_SRR2;
- srr1 = SPR_40x_SRR3;
- break;
- case POWERPC_EXCP_BOOKE:
- srr0 = SPR_BOOKE_CSRR0;
- srr1 = SPR_BOOKE_CSRR1;
- break;
- case POWERPC_EXCP_G2:
- break;
- default:
- goto excp_invalid;
- }
- break;
- case POWERPC_EXCP_MCHECK: /* Machine check exception */
- if (msr_me == 0) {
- /*
- * Machine check exception is not enabled. Enter
- * checkstop state.
- */
- fprintf(stderr, "Machine check while not allowed. "
- "Entering checkstop state\n");
- if (qemu_log_separate()) {
- qemu_log("Machine check while not allowed. "
- "Entering checkstop state\n");
- }
- cs->halted = 1;
- cpu_interrupt_exittb(cs);
- }
- if (env->msr_mask & MSR_HVB) {
- /*
- * ISA specifies HV, but can be delivered to guest with HV
- * clear (e.g., see FWNMI in PAPR).
- */
- new_msr |= (target_ulong)MSR_HVB;
- }
-
- /* machine check exceptions don't have ME set */
- new_msr &= ~((target_ulong)1 << MSR_ME);
-
- /* XXX: should also have something loaded in DAR / DSISR */
- switch (excp_model) {
- case POWERPC_EXCP_40x:
- srr0 = SPR_40x_SRR2;
- srr1 = SPR_40x_SRR3;
- break;
- case POWERPC_EXCP_BOOKE:
- /* FIXME: choose one or the other based on CPU type */
- srr0 = SPR_BOOKE_MCSRR0;
- srr1 = SPR_BOOKE_MCSRR1;
-
- env->spr[SPR_BOOKE_CSRR0] = env->nip;
- env->spr[SPR_BOOKE_CSRR1] = msr;
- break;
- default:
- break;
- }
- break;
- case POWERPC_EXCP_DSI: /* Data storage exception */
- trace_ppc_excp_dsi(env->spr[SPR_DSISR], env->spr[SPR_DAR]);
- break;
- case POWERPC_EXCP_ISI: /* Instruction storage exception */
- trace_ppc_excp_isi(msr, env->nip);
- msr |= env->error_code;
- break;
- case POWERPC_EXCP_EXTERNAL: /* External input */
- {
- bool lpes0;
-
- cs = CPU(cpu);
-
- /*
- * Exception targeting modifiers
- *
- * LPES0 is supported on POWER7/8/9
- * LPES1 is not supported (old iSeries mode)
- *
- * On anything else, we behave as if LPES0 is 1
- * (externals don't alter MSR:HV)
- */
-#if defined(TARGET_PPC64)
- if (excp_model == POWERPC_EXCP_POWER7 ||
- excp_model == POWERPC_EXCP_POWER8 ||
- excp_model == POWERPC_EXCP_POWER9 ||
- excp_model == POWERPC_EXCP_POWER10) {
- lpes0 = !!(env->spr[SPR_LPCR] & LPCR_LPES0);
- } else
-#endif /* defined(TARGET_PPC64) */
- {
- lpes0 = true;
- }
-
- if (!lpes0) {
- new_msr |= (target_ulong)MSR_HVB;
- new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
- srr0 = SPR_HSRR0;
- srr1 = SPR_HSRR1;
- }
- if (env->mpic_proxy) {
- /* IACK the IRQ on delivery */
- env->spr[SPR_BOOKE_EPR] = ldl_phys(cs->as, env->mpic_iack);
- }
- break;
- }
- case POWERPC_EXCP_ALIGN: /* Alignment exception */
- /* Get rS/rD and rA from faulting opcode */
- /*
- * Note: the opcode fields will not be set properly for a
- * direct store load/store, but nobody cares as nobody
- * actually uses direct store segments.
- */
- env->spr[SPR_DSISR] |= (env->error_code & 0x03FF0000) >> 16;
- break;
- case POWERPC_EXCP_PROGRAM: /* Program exception */
- switch (env->error_code & ~0xF) {
- case POWERPC_EXCP_FP:
- if ((msr_fe0 == 0 && msr_fe1 == 0) || msr_fp == 0) {
- trace_ppc_excp_fp_ignore();
- cs->exception_index = POWERPC_EXCP_NONE;
- env->error_code = 0;
- return;
- }
-
- /*
- * FP exceptions always have NIP pointing to the faulting
- * instruction, so always use store_next and claim we are
- * precise in the MSR.
- */
- msr |= 0x00100000;
- env->spr[SPR_BOOKE_ESR] = ESR_FP;
- break;
- case POWERPC_EXCP_INVAL:
- trace_ppc_excp_inval(env->nip);
- msr |= 0x00080000;
- env->spr[SPR_BOOKE_ESR] = ESR_PIL;
- break;
- case POWERPC_EXCP_PRIV:
- msr |= 0x00040000;
- env->spr[SPR_BOOKE_ESR] = ESR_PPR;
- break;
- case POWERPC_EXCP_TRAP:
- msr |= 0x00020000;
- env->spr[SPR_BOOKE_ESR] = ESR_PTR;
- break;
- default:
- /* Should never occur */
- cpu_abort(cs, "Invalid program exception %d. Aborting\n",
- env->error_code);
- break;
- }
- break;
- case POWERPC_EXCP_SYSCALL: /* System call exception */
- lev = env->error_code;
-
- if ((lev == 1) && cpu->vhyp) {
- dump_hcall(env);
- } else {
- dump_syscall(env);
- }
-
- /*
- * We need to correct the NIP which in this case is supposed
- * to point to the next instruction
- */
- env->nip += 4;
-
- /* "PAPR mode" built-in hypercall emulation */
- if ((lev == 1) && cpu->vhyp) {
- PPCVirtualHypervisorClass *vhc =
- PPC_VIRTUAL_HYPERVISOR_GET_CLASS(cpu->vhyp);
- vhc->hypercall(cpu->vhyp, cpu);
- return;
- }
- if (lev == 1) {
- new_msr |= (target_ulong)MSR_HVB;
- }
- break;
- case POWERPC_EXCP_SYSCALL_VECTORED: /* scv exception */
- lev = env->error_code;
- dump_syscall(env);
- env->nip += 4;
- new_msr |= env->msr & ((target_ulong)1 << MSR_EE);
- new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-
- vector += lev * 0x20;
-
- env->lr = env->nip;
- env->ctr = msr;
- break;
- case POWERPC_EXCP_FPU: /* Floating-point unavailable exception */
- case POWERPC_EXCP_APU: /* Auxiliary processor unavailable */
- case POWERPC_EXCP_DECR: /* Decrementer exception */
- break;
- case POWERPC_EXCP_FIT: /* Fixed-interval timer interrupt */
- /* FIT on 4xx */
- trace_ppc_excp_print("FIT");
- break;
- case POWERPC_EXCP_WDT: /* Watchdog timer interrupt */
- trace_ppc_excp_print("WDT");
- switch (excp_model) {
- case POWERPC_EXCP_BOOKE:
- srr0 = SPR_BOOKE_CSRR0;
- srr1 = SPR_BOOKE_CSRR1;
- break;
- default:
- break;
- }
- break;
- case POWERPC_EXCP_DTLB: /* Data TLB error */
- case POWERPC_EXCP_ITLB: /* Instruction TLB error */
- break;
- case POWERPC_EXCP_DEBUG: /* Debug interrupt */
- if (env->flags & POWERPC_FLAG_DE) {
- /* FIXME: choose one or the other based on CPU type */
- srr0 = SPR_BOOKE_DSRR0;
- srr1 = SPR_BOOKE_DSRR1;
-
- env->spr[SPR_BOOKE_CSRR0] = env->nip;
- env->spr[SPR_BOOKE_CSRR1] = msr;
-
- /* DBSR already modified by caller */
- } else {
- cpu_abort(cs, "Debug exception triggered on unsupported model\n");
- }
- break;
- case POWERPC_EXCP_SPEU: /* SPE/embedded floating-point unavailable/VPU */
- env->spr[SPR_BOOKE_ESR] = ESR_SPV;
- break;
- case POWERPC_EXCP_DOORI: /* Embedded doorbell interrupt */
- break;
- case POWERPC_EXCP_DOORCI: /* Embedded doorbell critical interrupt */
- srr0 = SPR_BOOKE_CSRR0;
- srr1 = SPR_BOOKE_CSRR1;
- break;
- case POWERPC_EXCP_RESET: /* System reset exception */
- /* A power-saving exception sets ME, otherwise it is unchanged */
- if (msr_pow) {
- /* indicate that we resumed from power save mode */
- msr |= 0x10000;
- new_msr |= ((target_ulong)1 << MSR_ME);
- }
- if (env->msr_mask & MSR_HVB) {
- /*
- * ISA specifies HV, but can be delivered to guest with HV
- * clear (e.g., see FWNMI in PAPR, NMI injection in QEMU).
- */
- new_msr |= (target_ulong)MSR_HVB;
- } else {
- if (msr_pow) {
- cpu_abort(cs, "Trying to deliver power-saving system reset "
- "exception %d with no HV support\n", excp);
- }
- }
- break;
- case POWERPC_EXCP_DSEG: /* Data segment exception */
- case POWERPC_EXCP_ISEG: /* Instruction segment exception */
- case POWERPC_EXCP_TRACE: /* Trace exception */
- break;
- case POWERPC_EXCP_HISI: /* Hypervisor instruction storage exception */
- msr |= env->error_code;
- /* fall through */
- case POWERPC_EXCP_HDECR: /* Hypervisor decrementer exception */
- case POWERPC_EXCP_HDSI: /* Hypervisor data storage exception */
- case POWERPC_EXCP_HDSEG: /* Hypervisor data segment exception */
- case POWERPC_EXCP_HISEG: /* Hypervisor instruction segment exception */
- case POWERPC_EXCP_SDOOR_HV: /* Hypervisor Doorbell interrupt */
- case POWERPC_EXCP_HV_EMU:
- case POWERPC_EXCP_HVIRT: /* Hypervisor virtualization */
- srr0 = SPR_HSRR0;
- srr1 = SPR_HSRR1;
- new_msr |= (target_ulong)MSR_HVB;
- new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
- break;
- case POWERPC_EXCP_VPU: /* Vector unavailable exception */
- case POWERPC_EXCP_VSXU: /* VSX unavailable exception */
- case POWERPC_EXCP_FU: /* Facility unavailable exception */
-#ifdef TARGET_PPC64
- env->spr[SPR_FSCR] |= ((target_ulong)env->error_code << 56);
-#endif
- break;
- case POWERPC_EXCP_HV_FU: /* Hypervisor Facility Unavailable Exception */
-#ifdef TARGET_PPC64
- env->spr[SPR_HFSCR] |= ((target_ulong)env->error_code << FSCR_IC_POS);
- srr0 = SPR_HSRR0;
- srr1 = SPR_HSRR1;
- new_msr |= (target_ulong)MSR_HVB;
- new_msr |= env->msr & ((target_ulong)1 << MSR_RI);
-#endif
- break;
- case POWERPC_EXCP_PIT: /* Programmable interval timer interrupt */
- trace_ppc_excp_print("PIT");
- break;
- case POWERPC_EXCP_IFTLB: /* Instruction fetch TLB error */
- case POWERPC_EXCP_DLTLB: /* Data load TLB miss */
- case POWERPC_EXCP_DSTLB: /* Data store TLB miss */
- switch (excp_model) {
- case POWERPC_EXCP_603:
- case POWERPC_EXCP_G2:
- /* Swap temporary saved registers with GPRs */
- if (!(new_msr & ((target_ulong)1 << MSR_TGPR))) {
- new_msr |= (target_ulong)1 << MSR_TGPR;
- hreg_swap_gpr_tgpr(env);
- }
- /* fall through */
- case POWERPC_EXCP_7x5:
- ppc_excp_debug_sw_tlb(env, excp);
-
- msr |= env->crf[0] << 28;
- msr |= env->error_code; /* key, D/I, S/L bits */
- /* Set way using a LRU mechanism */
- msr |= ((env->last_way + 1) & (env->nb_ways - 1)) << 17;
- break;
- default:
- cpu_abort(cs, "Invalid TLB miss exception\n");
- break;
- }
- break;
- case POWERPC_EXCP_EFPDI: /* Embedded floating-point data interrupt */
- case POWERPC_EXCP_EFPRI: /* Embedded floating-point round interrupt */
- case POWERPC_EXCP_EPERFM: /* Embedded performance monitor interrupt */
- case POWERPC_EXCP_IO: /* IO error exception */
- case POWERPC_EXCP_RUNM: /* Run mode exception */
- case POWERPC_EXCP_EMUL: /* Emulation trap exception */
- case POWERPC_EXCP_FPA: /* Floating-point assist exception */
- case POWERPC_EXCP_DABR: /* Data address breakpoint */
- case POWERPC_EXCP_IABR: /* Instruction address breakpoint */
- case POWERPC_EXCP_SMI: /* System management interrupt */
- case POWERPC_EXCP_THERM: /* Thermal interrupt */
- case POWERPC_EXCP_PERFM: /* Embedded performance monitor interrupt */
- case POWERPC_EXCP_VPUA: /* Vector assist exception */
- case POWERPC_EXCP_SOFTP: /* Soft patch exception */
- case POWERPC_EXCP_MAINT: /* Maintenance exception */
- case POWERPC_EXCP_MEXTBR: /* Maskable external breakpoint */
- case POWERPC_EXCP_NMEXTBR: /* Non maskable external breakpoint */
- cpu_abort(cs, "%s exception not implemented\n",
- powerpc_excp_name(excp));
- break;
- default:
- excp_invalid:
- cpu_abort(cs, "Invalid PowerPC exception %d. Aborting\n", excp);
- break;
- }
-
- /* Sanity check */
- if (!(env->msr_mask & MSR_HVB)) {
- if (new_msr & MSR_HVB) {
- cpu_abort(cs, "Trying to deliver HV exception (MSR) %d with "
- "no HV support\n", excp);
- }
- if (srr0 == SPR_HSRR0) {
- cpu_abort(cs, "Trying to deliver HV exception (HSRR) %d with "
- "no HV support\n", excp);
- }
- }
-
- /*
- * Sort out endianness of interrupt, this differs depending on the
- * CPU, the HV mode, etc...
- */
- if (ppc_interrupts_little_endian(cpu, !!(new_msr & MSR_HVB))) {
- new_msr |= (target_ulong)1 << MSR_LE;
- }
-
-#if defined(TARGET_PPC64)
- if (excp_model == POWERPC_EXCP_BOOKE) {
- if (env->spr[SPR_BOOKE_EPCR] & EPCR_ICM) {
- /* Cat.64-bit: EPCR.ICM is copied to MSR.CM */
- new_msr |= (target_ulong)1 << MSR_CM;
- } else {
- vector = (uint32_t)vector;
- }
- } else {
- if (!msr_isf && !mmu_is_64bit(env->mmu_model)) {
- vector = (uint32_t)vector;
- } else {
- new_msr |= (target_ulong)1 << MSR_SF;
- }
- }
-#endif
-
- if (excp != POWERPC_EXCP_SYSCALL_VECTORED) {
- /* Save PC */
- env->spr[srr0] = env->nip;
-
- /* Save MSR */
- env->spr[srr1] = msr;
- }
-
- /* This can update new_msr and vector if AIL applies */
- ppc_excp_apply_ail(cpu, excp_model, excp, msr, &new_msr, &vector);
-
- powerpc_set_excp_state(cpu, vector, new_msr);
-}
-
-static void powerpc_excp(PowerPCCPU *cpu, int excp)
-{
- CPUPPCState *env = &cpu->env;
-
switch (env->excp_model) {
case POWERPC_EXCP_40x:
powerpc_excp_40x(cpu, excp);
break;
+ case POWERPC_EXCP_6xx:
+ powerpc_excp_6xx(cpu, excp);
+ break;
+ case POWERPC_EXCP_7xx:
+ powerpc_excp_7xx(cpu, excp);
+ break;
case POWERPC_EXCP_74xx:
powerpc_excp_74xx(cpu, excp);
break;
+ case POWERPC_EXCP_BOOKE:
+ powerpc_excp_booke(cpu, excp);
+ break;
case POWERPC_EXCP_970:
case POWERPC_EXCP_POWER7:
case POWERPC_EXCP_POWER8:
@@ -1539,7 +1600,7 @@
powerpc_excp_books(cpu, excp);
break;
default:
- powerpc_excp_legacy(cpu, excp);
+ g_assert_not_reached();
}
}
@@ -1974,14 +2035,8 @@
#endif
#if !defined(CONFIG_USER_ONLY)
-/*****************************************************************************/
-/* PowerPC 601 specific instructions (POWER bridge) */
#ifdef CONFIG_TCG
-void helper_rfsvc(CPUPPCState *env)
-{
- do_rfi(env, env->lr, env->ctr & 0x0000FFFF);
-}
/* Embedded.Processor Control */
static int dbell2irq(target_ulong rb)
diff --git a/target/ppc/fpu_helper.c b/target/ppc/fpu_helper.c
index e5c29b5..bd76bee 100644
--- a/target/ppc/fpu_helper.c
+++ b/target/ppc/fpu_helper.c
@@ -1696,7 +1696,7 @@
void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \
ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t t = *xt; \
+ ppc_vsr_t t = { }; \
int i; \
\
helper_reset_fpstatus(env); \
@@ -1772,7 +1772,7 @@
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t t = *xt; \
+ ppc_vsr_t t = { }; \
int i; \
\
helper_reset_fpstatus(env); \
@@ -1843,7 +1843,7 @@
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, \
ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t t = *xt; \
+ ppc_vsr_t t = { }; \
int i; \
\
helper_reset_fpstatus(env); \
@@ -1919,7 +1919,7 @@
#define VSX_RE(op, nels, tp, fld, sfprf, r2sp) \
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t t = *xt; \
+ ppc_vsr_t t = { }; \
int i; \
\
helper_reset_fpstatus(env); \
@@ -1959,7 +1959,7 @@
#define VSX_SQRT(op, nels, tp, fld, sfprf, r2sp) \
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t t = *xt; \
+ ppc_vsr_t t = { }; \
int i; \
\
helper_reset_fpstatus(env); \
@@ -2004,7 +2004,7 @@
#define VSX_RSQRTE(op, nels, tp, fld, sfprf, r2sp) \
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t t = *xt; \
+ ppc_vsr_t t = { }; \
int i; \
\
helper_reset_fpstatus(env); \
@@ -2472,7 +2472,7 @@
void helper_##name(CPUPPCState *env, ppc_vsr_t *xt, \
ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t t = *xt; \
+ ppc_vsr_t t = { }; \
int i; \
\
for (i = 0; i < nels; i++) { \
@@ -2498,7 +2498,7 @@
void helper_##name(CPUPPCState *env, \
ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t t = *xt; \
+ ppc_vsr_t t = { }; \
bool vxsnan_flag = false, vex_flag = false; \
\
if (unlikely(float64_is_any_nan(xa->VsrD(0)) || \
@@ -2533,7 +2533,7 @@
void helper_##name(CPUPPCState *env, \
ppc_vsr_t *xt, ppc_vsr_t *xa, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t t = *xt; \
+ ppc_vsr_t t = { }; \
bool vxsnan_flag = false, vex_flag = false; \
\
if (unlikely(float64_is_any_nan(xa->VsrD(0)))) { \
@@ -2654,7 +2654,7 @@
#define VSX_CVT_FP_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf) \
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t t = *xt; \
+ ppc_vsr_t t = { }; \
int i; \
\
for (i = 0; i < nels; i++) { \
@@ -2833,7 +2833,7 @@
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
int all_flags = env->fp_status.float_exception_flags, flags; \
- ppc_vsr_t t = *xt; \
+ ppc_vsr_t t = { }; \
int i; \
\
for (i = 0; i < nels; i++) { \
@@ -2917,7 +2917,7 @@
#define VSX_CVT_INT_TO_FP(op, nels, stp, ttp, sfld, tfld, sfprf, r2sp) \
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t t = *xt; \
+ ppc_vsr_t t = { }; \
int i; \
\
for (i = 0; i < nels; i++) { \
@@ -2990,7 +2990,7 @@
#define VSX_ROUND(op, nels, tp, fld, rmode, sfprf) \
void helper_##op(CPUPPCState *env, ppc_vsr_t *xt, ppc_vsr_t *xb) \
{ \
- ppc_vsr_t t = *xt; \
+ ppc_vsr_t t = { }; \
int i; \
FloatRoundMode curr_rounding_mode; \
\
diff --git a/target/ppc/helper.h b/target/ppc/helper.h
index f2e5060..ab008c9 100644
--- a/target/ppc/helper.h
+++ b/target/ppc/helper.h
@@ -7,7 +7,6 @@
#if !defined(CONFIG_USER_ONLY)
DEF_HELPER_2(store_msr, void, env, tl)
DEF_HELPER_1(rfi, void, env)
-DEF_HELPER_1(rfsvc, void, env)
DEF_HELPER_1(40x_rfci, void, env)
DEF_HELPER_1(rfci, void, env)
DEF_HELPER_1(rfdi, void, env)
@@ -653,14 +652,9 @@
#endif
DEF_HELPER_4(dlmzb, tl, env, tl, tl, i32)
-DEF_HELPER_FLAGS_2(clcs, TCG_CALL_NO_RWG_SE, tl, env, i32)
#if !defined(CONFIG_USER_ONLY)
DEF_HELPER_2(rac, tl, env, tl)
#endif
-DEF_HELPER_3(div, tl, env, tl, tl)
-DEF_HELPER_3(divo, tl, env, tl, tl)
-DEF_HELPER_3(divs, tl, env, tl, tl)
-DEF_HELPER_3(divso, tl, env, tl, tl)
DEF_HELPER_2(load_dcr, tl, env, tl)
DEF_HELPER_3(store_dcr, void, env, tl, tl)
@@ -674,8 +668,6 @@
DEF_HELPER_FLAGS_1(load_atbl, TCG_CALL_NO_RWG, tl, env)
DEF_HELPER_FLAGS_1(load_atbu, TCG_CALL_NO_RWG, tl, env)
DEF_HELPER_FLAGS_1(load_vtb, TCG_CALL_NO_RWG, tl, env)
-DEF_HELPER_FLAGS_1(load_601_rtcl, TCG_CALL_NO_RWG, tl, env)
-DEF_HELPER_FLAGS_1(load_601_rtcu, TCG_CALL_NO_RWG, tl, env)
#if !defined(CONFIG_USER_ONLY)
#if defined(TARGET_PPC64)
DEF_HELPER_FLAGS_1(load_purr, TCG_CALL_NO_RWG, tl, env)
@@ -693,15 +685,12 @@
DEF_HELPER_FLAGS_2(store_tbu, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(store_atbl, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(store_atbu, TCG_CALL_NO_RWG, void, env, tl)
-DEF_HELPER_FLAGS_2(store_601_rtcl, TCG_CALL_NO_RWG, void, env, tl)
-DEF_HELPER_FLAGS_2(store_601_rtcu, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_1(load_decr, TCG_CALL_NO_RWG, tl, env)
DEF_HELPER_FLAGS_2(store_decr, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_1(load_hdecr, TCG_CALL_NO_RWG, tl, env)
DEF_HELPER_FLAGS_2(store_hdecr, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(store_vtb, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(store_tbu40, TCG_CALL_NO_RWG, void, env, tl)
-DEF_HELPER_2(store_hid0_601, void, env, tl)
DEF_HELPER_FLAGS_1(load_40x_pit, TCG_CALL_NO_RWG, tl, env)
DEF_HELPER_FLAGS_2(store_40x_pit, TCG_CALL_NO_RWG, void, env, tl)
DEF_HELPER_FLAGS_2(store_40x_tcr, TCG_CALL_NO_RWG, void, env, tl)
@@ -715,8 +704,6 @@
DEF_HELPER_3(store_ibatu, void, env, i32, tl)
DEF_HELPER_3(store_dbatl, void, env, i32, tl)
DEF_HELPER_3(store_dbatu, void, env, i32, tl)
-DEF_HELPER_3(store_601_batl, void, env, i32, tl)
-DEF_HELPER_3(store_601_batu, void, env, i32, tl)
#endif
#define dh_alias_fprp ptr
diff --git a/target/ppc/helper_regs.c b/target/ppc/helper_regs.c
index 5b12cb0..38fcb5f 100644
--- a/target/ppc/helper_regs.c
+++ b/target/ppc/helper_regs.c
@@ -59,15 +59,6 @@
msr_mask = ((1 << MSR_LE) | (1 << MSR_PR) |
(1 << MSR_DR) | (1 << MSR_FP));
- if (ppc_flags & POWERPC_FLAG_HID0_LE) {
- /*
- * Note that MSR_LE is not set in env->msr_mask for this cpu,
- * and so will never be set in msr.
- */
- uint32_t le = extract32(env->spr[SPR_HID0], 3, 1);
- hflags |= le << MSR_LE;
- }
-
if (ppc_flags & POWERPC_FLAG_DE) {
target_ulong dbcr0 = env->spr[SPR_BOOKE_DBCR0];
if (dbcr0 & DBCR0_ICMP) {
@@ -249,7 +240,6 @@
hreg_swap_gpr_tgpr(env);
}
if (unlikely((value >> MSR_EP) & 1) != msr_ep) {
- /* Change the exception prefix on PowerPC 601 */
env->excp_prefix = ((value >> MSR_EP) & 1) * 0xFFF00000;
}
/*
diff --git a/target/ppc/int_helper.c b/target/ppc/int_helper.c
index d7765fd..d1b1278 100644
--- a/target/ppc/int_helper.c
+++ b/target/ppc/int_helper.c
@@ -423,72 +423,6 @@
}
/*****************************************************************************/
-/* PowerPC 601 specific instructions (POWER bridge) */
-target_ulong helper_div(CPUPPCState *env, target_ulong arg1, target_ulong arg2)
-{
- uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
-
- if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
- (int32_t)arg2 == 0) {
- env->spr[SPR_MQ] = 0;
- return INT32_MIN;
- } else {
- env->spr[SPR_MQ] = tmp % arg2;
- return tmp / (int32_t)arg2;
- }
-}
-
-target_ulong helper_divo(CPUPPCState *env, target_ulong arg1,
- target_ulong arg2)
-{
- uint64_t tmp = (uint64_t)arg1 << 32 | env->spr[SPR_MQ];
-
- if (((int32_t)tmp == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
- (int32_t)arg2 == 0) {
- env->so = env->ov = 1;
- env->spr[SPR_MQ] = 0;
- return INT32_MIN;
- } else {
- env->spr[SPR_MQ] = tmp % arg2;
- tmp /= (int32_t)arg2;
- if ((int32_t)tmp != tmp) {
- env->so = env->ov = 1;
- } else {
- env->ov = 0;
- }
- return tmp;
- }
-}
-
-target_ulong helper_divs(CPUPPCState *env, target_ulong arg1,
- target_ulong arg2)
-{
- if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
- (int32_t)arg2 == 0) {
- env->spr[SPR_MQ] = 0;
- return INT32_MIN;
- } else {
- env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
- return (int32_t)arg1 / (int32_t)arg2;
- }
-}
-
-target_ulong helper_divso(CPUPPCState *env, target_ulong arg1,
- target_ulong arg2)
-{
- if (((int32_t)arg1 == INT32_MIN && (int32_t)arg2 == (int32_t)-1) ||
- (int32_t)arg2 == 0) {
- env->so = env->ov = 1;
- env->spr[SPR_MQ] = 0;
- return INT32_MIN;
- } else {
- env->ov = 0;
- env->spr[SPR_MQ] = (int32_t)arg1 % (int32_t)arg2;
- return (int32_t)arg1 / (int32_t)arg2;
- }
-}
-
-/*****************************************************************************/
/* Altivec extension helpers */
#if defined(HOST_WORDS_BIGENDIAN)
#define VECTOR_FOR_INORDER_I(index, element) \
diff --git a/target/ppc/machine.c b/target/ppc/machine.c
index a503e00..1b63146 100644
--- a/target/ppc/machine.c
+++ b/target/ppc/machine.c
@@ -205,9 +205,8 @@
}
}
- /* Retain migration compatibility for pre 6.0 for 601 machines. */
- env->hflags_compat_nmsr = (env->flags & POWERPC_FLAG_HID0_LE
- ? env->hflags & MSR_LE : 0);
+ /* Used to retain migration compatibility for pre 6.0 for 601 machines. */
+ env->hflags_compat_nmsr = 0;
return 0;
}
diff --git a/target/ppc/misc_helper.c b/target/ppc/misc_helper.c
index 1bcefa7..29e73a6 100644
--- a/target/ppc/misc_helper.c
+++ b/target/ppc/misc_helper.c
@@ -211,21 +211,6 @@
tlb_flush(env_cpu(env));
}
-void helper_store_hid0_601(CPUPPCState *env, target_ulong val)
-{
- target_ulong hid0;
-
- hid0 = env->spr[SPR_HID0];
- env->spr[SPR_HID0] = (uint32_t)val;
-
- if ((val ^ hid0) & 0x00000008) {
- /* Change current endianness */
- hreg_compute_hflags(env);
- qemu_log("%s: set endianness to %c => %08x\n", __func__,
- val & 0x8 ? 'l' : 'b', env->hflags);
- }
-}
-
void helper_store_40x_dbcr0(CPUPPCState *env, target_ulong val)
{
/* Bits 26 & 27 affect single-stepping. */
@@ -239,31 +224,6 @@
store_40x_sler(env, val);
}
#endif
-/*****************************************************************************/
-/* PowerPC 601 specific instructions (POWER bridge) */
-
-target_ulong helper_clcs(CPUPPCState *env, uint32_t arg)
-{
- switch (arg) {
- case 0x0CUL:
- /* Instruction cache line size */
- return env->icache_line_size;
- case 0x0DUL:
- /* Data cache line size */
- return env->dcache_line_size;
- case 0x0EUL:
- /* Minimum cache line size */
- return (env->icache_line_size < env->dcache_line_size) ?
- env->icache_line_size : env->dcache_line_size;
- case 0x0FUL:
- /* Maximum cache line size */
- return (env->icache_line_size > env->dcache_line_size) ?
- env->icache_line_size : env->dcache_line_size;
- default:
- /* Undefined */
- return 0;
- }
-}
/*****************************************************************************/
/* Special registers manipulation */
diff --git a/target/ppc/mmu-hash32.c b/target/ppc/mmu-hash32.c
index 3957aab..cc091c3 100644
--- a/target/ppc/mmu-hash32.c
+++ b/target/ppc/mmu-hash32.c
@@ -125,30 +125,6 @@
return prot;
}
-static target_ulong hash32_bat_601_size(PowerPCCPU *cpu,
- target_ulong batu, target_ulong batl)
-{
- if (!(batl & BATL32_601_V)) {
- return 0;
- }
-
- return BATU32_BEPI & ~((batl & BATL32_601_BL) << 17);
-}
-
-static int hash32_bat_601_prot(int mmu_idx,
- target_ulong batu, target_ulong batl)
-{
- int key, pp;
-
- pp = batu & BATU32_601_PP;
- if (mmuidx_pr(mmu_idx) == 0) {
- key = !!(batu & BATU32_601_KS);
- } else {
- key = !!(batu & BATU32_601_KP);
- }
- return ppc_hash32_pp_prot(key, pp, 0);
-}
-
static hwaddr ppc_hash32_bat_lookup(PowerPCCPU *cpu, target_ulong ea,
MMUAccessType access_type, int *prot,
int mmu_idx)
@@ -172,11 +148,7 @@
target_ulong batl = BATlt[i];
target_ulong mask;
- if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
- mask = hash32_bat_601_size(cpu, batu, batl);
- } else {
- mask = hash32_bat_size(mmu_idx, batu, batl);
- }
+ mask = hash32_bat_size(mmu_idx, batu, batl);
LOG_BATS("%s: %cBAT%d v " TARGET_FMT_lx " BATu " TARGET_FMT_lx
" BATl " TARGET_FMT_lx "\n", __func__,
ifetch ? 'I' : 'D', i, ea, batu, batl);
@@ -184,11 +156,7 @@
if (mask && ((ea & mask) == (batu & BATU32_BEPI))) {
hwaddr raddr = (batl & mask) | (ea & ~mask);
- if (unlikely(env->mmu_model == POWERPC_MMU_601)) {
- *prot = hash32_bat_601_prot(mmu_idx, batu, batl);
- } else {
- *prot = hash32_bat_prot(cpu, batu, batl);
- }
+ *prot = hash32_bat_prot(cpu, batu, batl);
return raddr & TARGET_PAGE_MASK;
}
@@ -231,18 +199,6 @@
qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
- if ((sr & 0x1FF00000) >> 20 == 0x07f) {
- /*
- * Memory-forced I/O controller interface access
- *
- * If T=1 and BUID=x'07F', the 601 performs a memory access
- * to SR[28-31] LA[4-31], bypassing all protection mechanisms.
- */
- *raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
- *prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- return true;
- }
-
if (access_type == MMU_INST_FETCH) {
/* No code fetch is allowed in direct-store areas */
if (guest_visible) {
diff --git a/target/ppc/mmu-hash32.h b/target/ppc/mmu-hash32.h
index 3892b69..7119a63 100644
--- a/target/ppc/mmu-hash32.h
+++ b/target/ppc/mmu-hash32.h
@@ -34,15 +34,6 @@
#define BATL32_WIMG 0x00000078
#define BATL32_PP 0x00000003
-/* PowerPC 601 has slightly different BAT registers */
-
-#define BATU32_601_KS 0x00000008
-#define BATU32_601_KP 0x00000004
-#define BATU32_601_PP 0x00000003
-
-#define BATL32_601_V 0x00000040
-#define BATL32_601_BL 0x0000003f
-
/*
* Hash page table definitions
*/
diff --git a/target/ppc/mmu-radix64.c b/target/ppc/mmu-radix64.c
index 040c055..d4e16bd 100644
--- a/target/ppc/mmu-radix64.c
+++ b/target/ppc/mmu-radix64.c
@@ -327,13 +327,9 @@
uint64_t pte;
qemu_log_mask(CPU_LOG_MMU, "%s for %s @0x%"VADDR_PRIx
- " mmu_idx %u (prot %c%c%c) 0x%"HWADDR_PRIx"\n",
+ " mmu_idx %u 0x%"HWADDR_PRIx"\n",
__func__, access_str(access_type),
- eaddr, mmu_idx,
- *h_prot & PAGE_READ ? 'r' : '-',
- *h_prot & PAGE_WRITE ? 'w' : '-',
- *h_prot & PAGE_EXEC ? 'x' : '-',
- g_raddr);
+ eaddr, mmu_idx, g_raddr);
*h_page_size = PRTBE_R_GET_RTS(pate.dw0);
/* No valid pte or access denied due to protection */
diff --git a/target/ppc/mmu_common.c b/target/ppc/mmu_common.c
index 6512ee0..e9c5b14 100644
--- a/target/ppc/mmu_common.c
+++ b/target/ppc/mmu_common.c
@@ -441,29 +441,9 @@
ret = -3;
}
} else {
- target_ulong sr;
-
qemu_log_mask(CPU_LOG_MMU, "direct store...\n");
/* Direct-store segment : absolutely *BUGGY* for now */
- /*
- * Direct-store implies a 32-bit MMU.
- * Check the Segment Register's bus unit ID (BUID).
- */
- sr = env->sr[eaddr >> 28];
- if ((sr & 0x1FF00000) >> 20 == 0x07f) {
- /*
- * Memory-forced I/O controller interface access
- *
- * If T=1 and BUID=x'07F', the 601 performs a memory
- * access to SR[28-31] LA[4-31], bypassing all protection
- * mechanisms.
- */
- ctx->raddr = ((sr & 0xF) << 28) | (eaddr & 0x0FFFFFFF);
- ctx->prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
- return 0;
- }
-
switch (type) {
case ACCESS_INT:
/* Integer load/store : only access allowed */
@@ -1539,7 +1519,6 @@
#endif
case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
return ppc_hash32_xlate(cpu, eaddr, access_type, raddrp,
psizep, protp, mmu_idx, guest_visible);
diff --git a/target/ppc/mmu_helper.c b/target/ppc/mmu_helper.c
index a2a52a1..142a717 100644
--- a/target/ppc/mmu_helper.c
+++ b/target/ppc/mmu_helper.c
@@ -279,88 +279,6 @@
env->DBAT[1][nr] = value;
}
-void helper_store_601_batu(CPUPPCState *env, uint32_t nr, target_ulong value)
-{
- target_ulong mask;
-#if defined(FLUSH_ALL_TLBS)
- int do_inval;
-#endif
-
- dump_store_bat(env, 'I', 0, nr, value);
- if (env->IBAT[0][nr] != value) {
-#if defined(FLUSH_ALL_TLBS)
- do_inval = 0;
-#endif
- mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
- if (env->IBAT[1][nr] & 0x40) {
- /* Invalidate BAT only if it is valid */
-#if !defined(FLUSH_ALL_TLBS)
- do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#else
- do_inval = 1;
-#endif
- }
- /*
- * When storing valid upper BAT, mask BEPI and BRPN and
- * invalidate all TLBs covered by this BAT
- */
- env->IBAT[0][nr] = (value & 0x00001FFFUL) |
- (value & ~0x0001FFFFUL & ~mask);
- env->DBAT[0][nr] = env->IBAT[0][nr];
- if (env->IBAT[1][nr] & 0x40) {
-#if !defined(FLUSH_ALL_TLBS)
- do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#else
- do_inval = 1;
-#endif
- }
-#if defined(FLUSH_ALL_TLBS)
- if (do_inval) {
- tlb_flush(env_cpu(env));
- }
-#endif
- }
-}
-
-void helper_store_601_batl(CPUPPCState *env, uint32_t nr, target_ulong value)
-{
-#if !defined(FLUSH_ALL_TLBS)
- target_ulong mask;
-#else
- int do_inval;
-#endif
-
- dump_store_bat(env, 'I', 1, nr, value);
- if (env->IBAT[1][nr] != value) {
-#if defined(FLUSH_ALL_TLBS)
- do_inval = 0;
-#endif
- if (env->IBAT[1][nr] & 0x40) {
-#if !defined(FLUSH_ALL_TLBS)
- mask = (env->IBAT[1][nr] << 17) & 0x0FFE0000UL;
- do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#else
- do_inval = 1;
-#endif
- }
- if (value & 0x40) {
-#if !defined(FLUSH_ALL_TLBS)
- mask = (value << 17) & 0x0FFE0000UL;
- do_invalidate_BAT(env, env->IBAT[0][nr], mask);
-#else
- do_inval = 1;
-#endif
- }
- env->IBAT[1][nr] = value;
- env->DBAT[1][nr] = value;
-#if defined(FLUSH_ALL_TLBS)
- if (do_inval) {
- tlb_flush(env_cpu(env));
- }
-#endif
- }
-}
-
/*****************************************************************************/
/* TLB management */
void ppc_tlb_invalidate_all(CPUPPCState *env)
@@ -392,7 +310,6 @@
booke206_flush_tlb(env, -1, 0);
break;
case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
env->tlb_need_flush = 0;
tlb_flush(env_cpu(env));
break;
@@ -426,7 +343,6 @@
}
break;
case POWERPC_MMU_32B:
- case POWERPC_MMU_601:
/*
* Actual CPUs invalidate entire congruence classes based on
* the geometry of their TLBs and some OSes take that into
diff --git a/target/ppc/spr_tcg.h b/target/ppc/spr_tcg.h
index 89ff111..df2abac 100644
--- a/target/ppc/spr_tcg.h
+++ b/target/ppc/spr_tcg.h
@@ -45,8 +45,6 @@
void spr_read_tbu(DisasContext *ctx, int gprn, int sprn);
void spr_read_atbl(DisasContext *ctx, int gprn, int sprn);
void spr_read_atbu(DisasContext *ctx, int gprn, int sprn);
-void spr_read_601_rtcl(DisasContext *ctx, int gprn, int sprn);
-void spr_read_601_rtcu(DisasContext *ctx, int gprn, int sprn);
void spr_read_spefscr(DisasContext *ctx, int gprn, int sprn);
void spr_write_spefscr(DisasContext *ctx, int sprn, int gprn);
void spr_write_MMCR0_ureg(DisasContext *ctx, int sprn, int gprn);
@@ -77,12 +75,6 @@
void spr_write_dbatl(DisasContext *ctx, int sprn, int gprn);
void spr_write_dbatl_h(DisasContext *ctx, int sprn, int gprn);
void spr_write_sdr1(DisasContext *ctx, int sprn, int gprn);
-void spr_write_601_rtcu(DisasContext *ctx, int sprn, int gprn);
-void spr_write_601_rtcl(DisasContext *ctx, int sprn, int gprn);
-void spr_write_hid0_601(DisasContext *ctx, int sprn, int gprn);
-void spr_read_601_ubat(DisasContext *ctx, int gprn, int sprn);
-void spr_write_601_ubatu(DisasContext *ctx, int sprn, int gprn);
-void spr_write_601_ubatl(DisasContext *ctx, int sprn, int gprn);
void spr_read_40x_pit(DisasContext *ctx, int gprn, int sprn);
void spr_write_40x_pit(DisasContext *ctx, int sprn, int gprn);
void spr_write_40x_dbcr0(DisasContext *ctx, int sprn, int gprn);
diff --git a/target/ppc/timebase_helper.c b/target/ppc/timebase_helper.c
index af37831..86d01d6 100644
--- a/target/ppc/timebase_helper.c
+++ b/target/ppc/timebase_helper.c
@@ -63,16 +63,6 @@
}
#endif
-target_ulong helper_load_601_rtcl(CPUPPCState *env)
-{
- return cpu_ppc601_load_rtcl(env);
-}
-
-target_ulong helper_load_601_rtcu(CPUPPCState *env)
-{
- return cpu_ppc601_load_rtcu(env);
-}
-
#if !defined(CONFIG_USER_ONLY)
void helper_store_tbl(CPUPPCState *env, target_ulong val)
{
@@ -94,16 +84,6 @@
cpu_ppc_store_atbu(env, val);
}
-void helper_store_601_rtcl(CPUPPCState *env, target_ulong val)
-{
- cpu_ppc601_store_rtcl(env, val);
-}
-
-void helper_store_601_rtcu(CPUPPCState *env, target_ulong val)
-{
- cpu_ppc601_store_rtcu(env, val);
-}
-
target_ulong helper_load_decr(CPUPPCState *env)
{
return cpu_ppc_load_decr(env);
diff --git a/target/ppc/translate.c b/target/ppc/translate.c
index c2f436f..2eaffd4 100644
--- a/target/ppc/translate.c
+++ b/target/ppc/translate.c
@@ -794,61 +794,6 @@
#endif
#endif
-/* PowerPC 601 specific registers */
-/* RTC */
-void spr_read_601_rtcl(DisasContext *ctx, int gprn, int sprn)
-{
- gen_helper_load_601_rtcl(cpu_gpr[gprn], cpu_env);
-}
-
-void spr_read_601_rtcu(DisasContext *ctx, int gprn, int sprn)
-{
- gen_helper_load_601_rtcu(cpu_gpr[gprn], cpu_env);
-}
-
-#if !defined(CONFIG_USER_ONLY)
-void spr_write_601_rtcu(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_601_rtcu(cpu_env, cpu_gpr[gprn]);
-}
-
-void spr_write_601_rtcl(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_601_rtcl(cpu_env, cpu_gpr[gprn]);
-}
-
-void spr_write_hid0_601(DisasContext *ctx, int sprn, int gprn)
-{
- gen_helper_store_hid0_601(cpu_env, cpu_gpr[gprn]);
- /* Must stop the translation as endianness may have changed */
- ctx->base.is_jmp = DISAS_EXIT_UPDATE;
-}
-#endif
-
-/* Unified bats */
-#if !defined(CONFIG_USER_ONLY)
-void spr_read_601_ubat(DisasContext *ctx, int gprn, int sprn)
-{
- tcg_gen_ld_tl(cpu_gpr[gprn], cpu_env,
- offsetof(CPUPPCState,
- IBAT[sprn & 1][(sprn - SPR_IBAT0U) / 2]));
-}
-
-void spr_write_601_ubatu(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
- gen_helper_store_601_batl(cpu_env, t0, cpu_gpr[gprn]);
- tcg_temp_free_i32(t0);
-}
-
-void spr_write_601_ubatl(DisasContext *ctx, int sprn, int gprn)
-{
- TCGv_i32 t0 = tcg_const_i32((sprn - SPR_IBAT0U) / 2);
- gen_helper_store_601_batu(cpu_env, t0, cpu_gpr[gprn]);
- tcg_temp_free_i32(t0);
-}
-#endif
-
/* PowerPC 40x specific registers */
#if !defined(CONFIG_USER_ONLY)
void spr_read_40x_pit(DisasContext *ctx, int gprn, int sprn)
@@ -5609,669 +5554,6 @@
tcg_temp_free(t0);
}
-/* PowerPC 601 specific instructions */
-
-/* abs - abs. */
-static void gen_abs(DisasContext *ctx)
-{
- TCGv d = cpu_gpr[rD(ctx->opcode)];
- TCGv a = cpu_gpr[rA(ctx->opcode)];
-
- tcg_gen_abs_tl(d, a);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, d);
- }
-}
-
-/* abso - abso. */
-static void gen_abso(DisasContext *ctx)
-{
- TCGv d = cpu_gpr[rD(ctx->opcode)];
- TCGv a = cpu_gpr[rA(ctx->opcode)];
-
- tcg_gen_setcondi_tl(TCG_COND_EQ, cpu_ov, a, 0x80000000);
- tcg_gen_abs_tl(d, a);
- tcg_gen_or_tl(cpu_so, cpu_so, cpu_ov);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, d);
- }
-}
-
-/* clcs */
-static void gen_clcs(DisasContext *ctx)
-{
- TCGv_i32 t0 = tcg_const_i32(rA(ctx->opcode));
- gen_helper_clcs(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
- tcg_temp_free_i32(t0);
- /* Rc=1 sets CR0 to an undefined state */
-}
-
-/* div - div. */
-static void gen_div(DisasContext *ctx)
-{
- gen_helper_div(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)],
- cpu_gpr[rB(ctx->opcode)]);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
- }
-}
-
-/* divo - divo. */
-static void gen_divo(DisasContext *ctx)
-{
- gen_helper_divo(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)],
- cpu_gpr[rB(ctx->opcode)]);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
- }
-}
-
-/* divs - divs. */
-static void gen_divs(DisasContext *ctx)
-{
- gen_helper_divs(cpu_gpr[rD(ctx->opcode)], cpu_env, cpu_gpr[rA(ctx->opcode)],
- cpu_gpr[rB(ctx->opcode)]);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
- }
-}
-
-/* divso - divso. */
-static void gen_divso(DisasContext *ctx)
-{
- gen_helper_divso(cpu_gpr[rD(ctx->opcode)], cpu_env,
- cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
- }
-}
-
-/* doz - doz. */
-static void gen_doz(DisasContext *ctx)
-{
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)],
- cpu_gpr[rA(ctx->opcode)], l1);
- tcg_gen_sub_tl(cpu_gpr[rD(ctx->opcode)], cpu_gpr[rB(ctx->opcode)],
- cpu_gpr[rA(ctx->opcode)]);
- tcg_gen_br(l2);
- gen_set_label(l1);
- tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
- gen_set_label(l2);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
- }
-}
-
-/* dozo - dozo. */
-static void gen_dozo(DisasContext *ctx)
-{
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- TCGv t2 = tcg_temp_new();
- /* Start with XER OV disabled, the most likely case */
- tcg_gen_movi_tl(cpu_ov, 0);
- tcg_gen_brcond_tl(TCG_COND_GE, cpu_gpr[rB(ctx->opcode)],
- cpu_gpr[rA(ctx->opcode)], l1);
- tcg_gen_sub_tl(t0, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
- tcg_gen_xor_tl(t1, cpu_gpr[rB(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
- tcg_gen_xor_tl(t2, cpu_gpr[rA(ctx->opcode)], t0);
- tcg_gen_andc_tl(t1, t1, t2);
- tcg_gen_mov_tl(cpu_gpr[rD(ctx->opcode)], t0);
- tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2);
- tcg_gen_movi_tl(cpu_ov, 1);
- tcg_gen_movi_tl(cpu_so, 1);
- tcg_gen_br(l2);
- gen_set_label(l1);
- tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
- gen_set_label(l2);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
- }
-}
-
-/* dozi */
-static void gen_dozi(DisasContext *ctx)
-{
- target_long simm = SIMM(ctx->opcode);
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- tcg_gen_brcondi_tl(TCG_COND_LT, cpu_gpr[rA(ctx->opcode)], simm, l1);
- tcg_gen_subfi_tl(cpu_gpr[rD(ctx->opcode)], simm, cpu_gpr[rA(ctx->opcode)]);
- tcg_gen_br(l2);
- gen_set_label(l1);
- tcg_gen_movi_tl(cpu_gpr[rD(ctx->opcode)], 0);
- gen_set_label(l2);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
- }
-}
-
-/* lscbx - lscbx. */
-static void gen_lscbx(DisasContext *ctx)
-{
- TCGv t0 = tcg_temp_new();
- TCGv_i32 t1 = tcg_const_i32(rD(ctx->opcode));
- TCGv_i32 t2 = tcg_const_i32(rA(ctx->opcode));
- TCGv_i32 t3 = tcg_const_i32(rB(ctx->opcode));
-
- gen_addr_reg_index(ctx, t0);
- gen_helper_lscbx(t0, cpu_env, t0, t1, t2, t3);
- tcg_temp_free_i32(t1);
- tcg_temp_free_i32(t2);
- tcg_temp_free_i32(t3);
- tcg_gen_andi_tl(cpu_xer, cpu_xer, ~0x7F);
- tcg_gen_or_tl(cpu_xer, cpu_xer, t0);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, t0);
- }
- tcg_temp_free(t0);
-}
-
-/* maskg - maskg. */
-static void gen_maskg(DisasContext *ctx)
-{
- TCGLabel *l1 = gen_new_label();
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- TCGv t2 = tcg_temp_new();
- TCGv t3 = tcg_temp_new();
- tcg_gen_movi_tl(t3, 0xFFFFFFFF);
- tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
- tcg_gen_andi_tl(t1, cpu_gpr[rS(ctx->opcode)], 0x1F);
- tcg_gen_addi_tl(t2, t0, 1);
- tcg_gen_shr_tl(t2, t3, t2);
- tcg_gen_shr_tl(t3, t3, t1);
- tcg_gen_xor_tl(cpu_gpr[rA(ctx->opcode)], t2, t3);
- tcg_gen_brcond_tl(TCG_COND_GE, t0, t1, l1);
- tcg_gen_neg_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)]);
- gen_set_label(l1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
- tcg_temp_free(t3);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* maskir - maskir. */
-static void gen_maskir(DisasContext *ctx)
-{
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- tcg_gen_and_tl(t0, cpu_gpr[rS(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
- tcg_gen_andc_tl(t1, cpu_gpr[rA(ctx->opcode)], cpu_gpr[rB(ctx->opcode)]);
- tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* mul - mul. */
-static void gen_mul(DisasContext *ctx)
-{
- TCGv_i64 t0 = tcg_temp_new_i64();
- TCGv_i64 t1 = tcg_temp_new_i64();
- TCGv t2 = tcg_temp_new();
- tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
- tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
- tcg_gen_mul_i64(t0, t0, t1);
- tcg_gen_trunc_i64_tl(t2, t0);
- gen_store_spr(SPR_MQ, t2);
- tcg_gen_shri_i64(t1, t0, 32);
- tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1);
- tcg_temp_free_i64(t0);
- tcg_temp_free_i64(t1);
- tcg_temp_free(t2);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
- }
-}
-
-/* mulo - mulo. */
-static void gen_mulo(DisasContext *ctx)
-{
- TCGLabel *l1 = gen_new_label();
- TCGv_i64 t0 = tcg_temp_new_i64();
- TCGv_i64 t1 = tcg_temp_new_i64();
- TCGv t2 = tcg_temp_new();
- /* Start with XER OV disabled, the most likely case */
- tcg_gen_movi_tl(cpu_ov, 0);
- tcg_gen_extu_tl_i64(t0, cpu_gpr[rA(ctx->opcode)]);
- tcg_gen_extu_tl_i64(t1, cpu_gpr[rB(ctx->opcode)]);
- tcg_gen_mul_i64(t0, t0, t1);
- tcg_gen_trunc_i64_tl(t2, t0);
- gen_store_spr(SPR_MQ, t2);
- tcg_gen_shri_i64(t1, t0, 32);
- tcg_gen_trunc_i64_tl(cpu_gpr[rD(ctx->opcode)], t1);
- tcg_gen_ext32s_i64(t1, t0);
- tcg_gen_brcond_i64(TCG_COND_EQ, t0, t1, l1);
- tcg_gen_movi_tl(cpu_ov, 1);
- tcg_gen_movi_tl(cpu_so, 1);
- gen_set_label(l1);
- tcg_temp_free_i64(t0);
- tcg_temp_free_i64(t1);
- tcg_temp_free(t2);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rD(ctx->opcode)]);
- }
-}
-
-/* nabs - nabs. */
-static void gen_nabs(DisasContext *ctx)
-{
- TCGv d = cpu_gpr[rD(ctx->opcode)];
- TCGv a = cpu_gpr[rA(ctx->opcode)];
-
- tcg_gen_abs_tl(d, a);
- tcg_gen_neg_tl(d, d);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, d);
- }
-}
-
-/* nabso - nabso. */
-static void gen_nabso(DisasContext *ctx)
-{
- TCGv d = cpu_gpr[rD(ctx->opcode)];
- TCGv a = cpu_gpr[rA(ctx->opcode)];
-
- tcg_gen_abs_tl(d, a);
- tcg_gen_neg_tl(d, d);
- /* nabs never overflows */
- tcg_gen_movi_tl(cpu_ov, 0);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, d);
- }
-}
-
-/* rlmi - rlmi. */
-static void gen_rlmi(DisasContext *ctx)
-{
- uint32_t mb = MB(ctx->opcode);
- uint32_t me = ME(ctx->opcode);
- TCGv t0 = tcg_temp_new();
- tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
- tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
- tcg_gen_andi_tl(t0, t0, MASK(mb, me));
- tcg_gen_andi_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)],
- ~MASK(mb, me));
- tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rA(ctx->opcode)], t0);
- tcg_temp_free(t0);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* rrib - rrib. */
-static void gen_rrib(DisasContext *ctx)
-{
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
- tcg_gen_movi_tl(t1, 0x80000000);
- tcg_gen_shr_tl(t1, t1, t0);
- tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
- tcg_gen_and_tl(t0, t0, t1);
- tcg_gen_andc_tl(t1, cpu_gpr[rA(ctx->opcode)], t1);
- tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* sle - sle. */
-static void gen_sle(DisasContext *ctx)
-{
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
- tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
- tcg_gen_subfi_tl(t1, 32, t1);
- tcg_gen_shr_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
- tcg_gen_or_tl(t1, t0, t1);
- tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
- gen_store_spr(SPR_MQ, t1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* sleq - sleq. */
-static void gen_sleq(DisasContext *ctx)
-{
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- TCGv t2 = tcg_temp_new();
- tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
- tcg_gen_movi_tl(t2, 0xFFFFFFFF);
- tcg_gen_shl_tl(t2, t2, t0);
- tcg_gen_rotl_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
- gen_load_spr(t1, SPR_MQ);
- gen_store_spr(SPR_MQ, t0);
- tcg_gen_and_tl(t0, t0, t2);
- tcg_gen_andc_tl(t1, t1, t2);
- tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* sliq - sliq. */
-static void gen_sliq(DisasContext *ctx)
-{
- int sh = SH(ctx->opcode);
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- tcg_gen_shli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
- tcg_gen_shri_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
- tcg_gen_or_tl(t1, t0, t1);
- tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
- gen_store_spr(SPR_MQ, t1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* slliq - slliq. */
-static void gen_slliq(DisasContext *ctx)
-{
- int sh = SH(ctx->opcode);
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- tcg_gen_rotli_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
- gen_load_spr(t1, SPR_MQ);
- gen_store_spr(SPR_MQ, t0);
- tcg_gen_andi_tl(t0, t0, (0xFFFFFFFFU << sh));
- tcg_gen_andi_tl(t1, t1, ~(0xFFFFFFFFU << sh));
- tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* sllq - sllq. */
-static void gen_sllq(DisasContext *ctx)
-{
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- TCGv t0 = tcg_temp_local_new();
- TCGv t1 = tcg_temp_local_new();
- TCGv t2 = tcg_temp_local_new();
- tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
- tcg_gen_movi_tl(t1, 0xFFFFFFFF);
- tcg_gen_shl_tl(t1, t1, t2);
- tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
- gen_load_spr(t0, SPR_MQ);
- tcg_gen_and_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
- tcg_gen_br(l2);
- gen_set_label(l1);
- tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
- gen_load_spr(t2, SPR_MQ);
- tcg_gen_andc_tl(t1, t2, t1);
- tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
- gen_set_label(l2);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* slq - slq. */
-static void gen_slq(DisasContext *ctx)
-{
- TCGLabel *l1 = gen_new_label();
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
- tcg_gen_shl_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
- tcg_gen_subfi_tl(t1, 32, t1);
- tcg_gen_shr_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
- tcg_gen_or_tl(t1, t0, t1);
- gen_store_spr(SPR_MQ, t1);
- tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x20);
- tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
- tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
- gen_set_label(l1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* sraiq - sraiq. */
-static void gen_sraiq(DisasContext *ctx)
-{
- int sh = SH(ctx->opcode);
- TCGLabel *l1 = gen_new_label();
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
- tcg_gen_shli_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
- tcg_gen_or_tl(t0, t0, t1);
- gen_store_spr(SPR_MQ, t0);
- tcg_gen_movi_tl(cpu_ca, 0);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t1, 0, l1);
- tcg_gen_brcondi_tl(TCG_COND_GE, cpu_gpr[rS(ctx->opcode)], 0, l1);
- tcg_gen_movi_tl(cpu_ca, 1);
- gen_set_label(l1);
- tcg_gen_sari_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], sh);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* sraq - sraq. */
-static void gen_sraq(DisasContext *ctx)
-{
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_local_new();
- TCGv t2 = tcg_temp_local_new();
- tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
- tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
- tcg_gen_sar_tl(t1, cpu_gpr[rS(ctx->opcode)], t2);
- tcg_gen_subfi_tl(t2, 32, t2);
- tcg_gen_shl_tl(t2, cpu_gpr[rS(ctx->opcode)], t2);
- tcg_gen_or_tl(t0, t0, t2);
- gen_store_spr(SPR_MQ, t0);
- tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, l1);
- tcg_gen_mov_tl(t2, cpu_gpr[rS(ctx->opcode)]);
- tcg_gen_sari_tl(t1, cpu_gpr[rS(ctx->opcode)], 31);
- gen_set_label(l1);
- tcg_temp_free(t0);
- tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t1);
- tcg_gen_movi_tl(cpu_ca, 0);
- tcg_gen_brcondi_tl(TCG_COND_GE, t1, 0, l2);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t2, 0, l2);
- tcg_gen_movi_tl(cpu_ca, 1);
- gen_set_label(l2);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* sre - sre. */
-static void gen_sre(DisasContext *ctx)
-{
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
- tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
- tcg_gen_subfi_tl(t1, 32, t1);
- tcg_gen_shl_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
- tcg_gen_or_tl(t1, t0, t1);
- tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
- gen_store_spr(SPR_MQ, t1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* srea - srea. */
-static void gen_srea(DisasContext *ctx)
-{
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
- tcg_gen_rotr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
- gen_store_spr(SPR_MQ, t0);
- tcg_gen_sar_tl(cpu_gpr[rA(ctx->opcode)], cpu_gpr[rS(ctx->opcode)], t1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* sreq */
-static void gen_sreq(DisasContext *ctx)
-{
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- TCGv t2 = tcg_temp_new();
- tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x1F);
- tcg_gen_movi_tl(t1, 0xFFFFFFFF);
- tcg_gen_shr_tl(t1, t1, t0);
- tcg_gen_rotr_tl(t0, cpu_gpr[rS(ctx->opcode)], t0);
- gen_load_spr(t2, SPR_MQ);
- gen_store_spr(SPR_MQ, t0);
- tcg_gen_and_tl(t0, t0, t1);
- tcg_gen_andc_tl(t2, t2, t1);
- tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t2);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* sriq */
-static void gen_sriq(DisasContext *ctx)
-{
- int sh = SH(ctx->opcode);
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- tcg_gen_shri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
- tcg_gen_shli_tl(t1, cpu_gpr[rS(ctx->opcode)], 32 - sh);
- tcg_gen_or_tl(t1, t0, t1);
- tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
- gen_store_spr(SPR_MQ, t1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* srliq */
-static void gen_srliq(DisasContext *ctx)
-{
- int sh = SH(ctx->opcode);
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- tcg_gen_rotri_tl(t0, cpu_gpr[rS(ctx->opcode)], sh);
- gen_load_spr(t1, SPR_MQ);
- gen_store_spr(SPR_MQ, t0);
- tcg_gen_andi_tl(t0, t0, (0xFFFFFFFFU >> sh));
- tcg_gen_andi_tl(t1, t1, ~(0xFFFFFFFFU >> sh));
- tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* srlq */
-static void gen_srlq(DisasContext *ctx)
-{
- TCGLabel *l1 = gen_new_label();
- TCGLabel *l2 = gen_new_label();
- TCGv t0 = tcg_temp_local_new();
- TCGv t1 = tcg_temp_local_new();
- TCGv t2 = tcg_temp_local_new();
- tcg_gen_andi_tl(t2, cpu_gpr[rB(ctx->opcode)], 0x1F);
- tcg_gen_movi_tl(t1, 0xFFFFFFFF);
- tcg_gen_shr_tl(t2, t1, t2);
- tcg_gen_andi_tl(t0, cpu_gpr[rB(ctx->opcode)], 0x20);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
- gen_load_spr(t0, SPR_MQ);
- tcg_gen_and_tl(cpu_gpr[rA(ctx->opcode)], t0, t2);
- tcg_gen_br(l2);
- gen_set_label(l1);
- tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t2);
- tcg_gen_and_tl(t0, t0, t2);
- gen_load_spr(t1, SPR_MQ);
- tcg_gen_andc_tl(t1, t1, t2);
- tcg_gen_or_tl(cpu_gpr[rA(ctx->opcode)], t0, t1);
- gen_set_label(l2);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free(t2);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
-/* srq */
-static void gen_srq(DisasContext *ctx)
-{
- TCGLabel *l1 = gen_new_label();
- TCGv t0 = tcg_temp_new();
- TCGv t1 = tcg_temp_new();
- tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x1F);
- tcg_gen_shr_tl(t0, cpu_gpr[rS(ctx->opcode)], t1);
- tcg_gen_subfi_tl(t1, 32, t1);
- tcg_gen_shl_tl(t1, cpu_gpr[rS(ctx->opcode)], t1);
- tcg_gen_or_tl(t1, t0, t1);
- gen_store_spr(SPR_MQ, t1);
- tcg_gen_andi_tl(t1, cpu_gpr[rB(ctx->opcode)], 0x20);
- tcg_gen_mov_tl(cpu_gpr[rA(ctx->opcode)], t0);
- tcg_gen_brcondi_tl(TCG_COND_EQ, t0, 0, l1);
- tcg_gen_movi_tl(cpu_gpr[rA(ctx->opcode)], 0);
- gen_set_label(l1);
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- if (unlikely(Rc(ctx->opcode) != 0)) {
- gen_set_Rc0(ctx, cpu_gpr[rA(ctx->opcode)]);
- }
-}
-
/* 602 - 603 - G2 TLB management */
/* tlbld */
@@ -6296,81 +5578,6 @@
#endif /* defined(CONFIG_USER_ONLY) */
}
-/* POWER instructions not in PowerPC 601 */
-
-/* clf */
-static void gen_clf(DisasContext *ctx)
-{
- /* Cache line flush: implemented as no-op */
-}
-
-/* cli */
-static void gen_cli(DisasContext *ctx)
-{
-#if defined(CONFIG_USER_ONLY)
- GEN_PRIV;
-#else
- /* Cache line invalidate: privileged and treated as no-op */
- CHK_SV;
-#endif /* defined(CONFIG_USER_ONLY) */
-}
-
-/* dclst */
-static void gen_dclst(DisasContext *ctx)
-{
- /* Data cache line store: treated as no-op */
-}
-
-static void gen_mfsri(DisasContext *ctx)
-{
-#if defined(CONFIG_USER_ONLY)
- GEN_PRIV;
-#else
- int ra = rA(ctx->opcode);
- int rd = rD(ctx->opcode);
- TCGv t0;
-
- CHK_SV;
- t0 = tcg_temp_new();
- gen_addr_reg_index(ctx, t0);
- tcg_gen_extract_tl(t0, t0, 28, 4);
- gen_helper_load_sr(cpu_gpr[rd], cpu_env, t0);
- tcg_temp_free(t0);
- if (ra != 0 && ra != rd) {
- tcg_gen_mov_tl(cpu_gpr[ra], cpu_gpr[rd]);
- }
-#endif /* defined(CONFIG_USER_ONLY) */
-}
-
-static void gen_rac(DisasContext *ctx)
-{
-#if defined(CONFIG_USER_ONLY)
- GEN_PRIV;
-#else
- TCGv t0;
-
- CHK_SV;
- t0 = tcg_temp_new();
- gen_addr_reg_index(ctx, t0);
- gen_helper_rac(cpu_gpr[rD(ctx->opcode)], cpu_env, t0);
- tcg_temp_free(t0);
-#endif /* defined(CONFIG_USER_ONLY) */
-}
-
-static void gen_rfsvc(DisasContext *ctx)
-{
-#if defined(CONFIG_USER_ONLY)
- GEN_PRIV;
-#else
- CHK_SV;
-
- gen_helper_rfsvc(cpu_env);
- ctx->base.is_jmp = DISAS_EXIT;
-#endif /* defined(CONFIG_USER_ONLY) */
-}
-
-/* svc is not implemented for now */
-
/* BookE specific instructions */
/* XXX: not implemented on 440 ? */
@@ -7718,56 +6925,8 @@
#endif
GEN_HANDLER(eciwx, 0x1F, 0x16, 0x0D, 0x00000001, PPC_EXTERN),
GEN_HANDLER(ecowx, 0x1F, 0x16, 0x09, 0x00000001, PPC_EXTERN),
-GEN_HANDLER(abs, 0x1F, 0x08, 0x0B, 0x0000F800, PPC_POWER_BR),
-GEN_HANDLER(abso, 0x1F, 0x08, 0x1B, 0x0000F800, PPC_POWER_BR),
-GEN_HANDLER(clcs, 0x1F, 0x10, 0x13, 0x0000F800, PPC_POWER_BR),
-GEN_HANDLER(div, 0x1F, 0x0B, 0x0A, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(divo, 0x1F, 0x0B, 0x1A, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(divs, 0x1F, 0x0B, 0x0B, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(divso, 0x1F, 0x0B, 0x1B, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(doz, 0x1F, 0x08, 0x08, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(dozo, 0x1F, 0x08, 0x18, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(dozi, 0x09, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(lscbx, 0x1F, 0x15, 0x08, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(maskg, 0x1F, 0x1D, 0x00, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(maskir, 0x1F, 0x1D, 0x10, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(mul, 0x1F, 0x0B, 0x03, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(mulo, 0x1F, 0x0B, 0x13, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(nabs, 0x1F, 0x08, 0x0F, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(nabso, 0x1F, 0x08, 0x1F, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(rlmi, 0x16, 0xFF, 0xFF, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(rrib, 0x1F, 0x19, 0x10, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(sle, 0x1F, 0x19, 0x04, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(sleq, 0x1F, 0x19, 0x06, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(sliq, 0x1F, 0x18, 0x05, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(slliq, 0x1F, 0x18, 0x07, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(sllq, 0x1F, 0x18, 0x06, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(slq, 0x1F, 0x18, 0x04, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(sraiq, 0x1F, 0x18, 0x1D, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(sraq, 0x1F, 0x18, 0x1C, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(sre, 0x1F, 0x19, 0x14, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(srea, 0x1F, 0x19, 0x1C, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(sreq, 0x1F, 0x19, 0x16, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(sriq, 0x1F, 0x18, 0x15, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(srliq, 0x1F, 0x18, 0x17, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(srlq, 0x1F, 0x18, 0x16, 0x00000000, PPC_POWER_BR),
-GEN_HANDLER(srq, 0x1F, 0x18, 0x14, 0x00000000, PPC_POWER_BR),
GEN_HANDLER2(tlbld_6xx, "tlbld", 0x1F, 0x12, 0x1E, 0x03FF0001, PPC_6xx_TLB),
GEN_HANDLER2(tlbli_6xx, "tlbli", 0x1F, 0x12, 0x1F, 0x03FF0001, PPC_6xx_TLB),
-GEN_HANDLER(clf, 0x1F, 0x16, 0x03, 0x03E00000, PPC_POWER),
-GEN_HANDLER(cli, 0x1F, 0x16, 0x0F, 0x03E00000, PPC_POWER),
-GEN_HANDLER(dclst, 0x1F, 0x16, 0x13, 0x03E00000, PPC_POWER),
-GEN_HANDLER(mfsri, 0x1F, 0x13, 0x13, 0x00000001, PPC_POWER),
-GEN_HANDLER(rac, 0x1F, 0x12, 0x19, 0x00000001, PPC_POWER),
-GEN_HANDLER(rfsvc, 0x13, 0x12, 0x02, 0x03FFF0001, PPC_POWER),
-GEN_HANDLER(lfq, 0x38, 0xFF, 0xFF, 0x00000003, PPC_POWER2),
-GEN_HANDLER(lfqu, 0x39, 0xFF, 0xFF, 0x00000003, PPC_POWER2),
-GEN_HANDLER(lfqux, 0x1F, 0x17, 0x19, 0x00000001, PPC_POWER2),
-GEN_HANDLER(lfqx, 0x1F, 0x17, 0x18, 0x00000001, PPC_POWER2),
-GEN_HANDLER(stfq, 0x3C, 0xFF, 0xFF, 0x00000003, PPC_POWER2),
-GEN_HANDLER(stfqu, 0x3D, 0xFF, 0xFF, 0x00000003, PPC_POWER2),
-GEN_HANDLER(stfqux, 0x1F, 0x17, 0x1D, 0x00000001, PPC_POWER2),
-GEN_HANDLER(stfqx, 0x1F, 0x17, 0x1C, 0x00000001, PPC_POWER2),
GEN_HANDLER(mfapidi, 0x1F, 0x13, 0x08, 0x0000F801, PPC_MFAPIDI),
GEN_HANDLER(tlbiva, 0x1F, 0x12, 0x18, 0x03FFF801, PPC_TLBIVA),
GEN_HANDLER(mfdcr, 0x1F, 0x03, 0x0A, 0x00000001, PPC_DCR),
@@ -8463,7 +7622,6 @@
ctx->has_cfar = !!(env->flags & POWERPC_FLAG_CFAR);
#endif
ctx->lazy_tlb_flush = env->mmu_model == POWERPC_MMU_32B
- || env->mmu_model == POWERPC_MMU_601
|| env->mmu_model & POWERPC_MMU_64;
ctx->fpu_enabled = (hflags >> HFLAGS_FP) & 1;
diff --git a/target/ppc/translate/fp-impl.c.inc b/target/ppc/translate/fp-impl.c.inc
index c967697..cfb27bd 100644
--- a/target/ppc/translate/fp-impl.c.inc
+++ b/target/ppc/translate/fp-impl.c.inc
@@ -1105,185 +1105,6 @@
/* stfiwx */
GEN_STXF(stfiw, st32fiw, 0x17, 0x1E, PPC_FLOAT_STFIWX);
-/* POWER2 specific instructions */
-/* Quad manipulation (load/store two floats at a time) */
-
-/* lfq */
-static void gen_lfq(DisasContext *ctx)
-{
- int rd = rD(ctx->opcode);
- TCGv t0;
- TCGv_i64 t1;
- gen_set_access_type(ctx, ACCESS_FLOAT);
- t0 = tcg_temp_new();
- t1 = tcg_temp_new_i64();
- gen_addr_imm_index(ctx, t0, 0);
- gen_qemu_ld64_i64(ctx, t1, t0);
- set_fpr(rd, t1);
- gen_addr_add(ctx, t0, t0, 8);
- gen_qemu_ld64_i64(ctx, t1, t0);
- set_fpr((rd + 1) % 32, t1);
- tcg_temp_free(t0);
- tcg_temp_free_i64(t1);
-}
-
-/* lfqu */
-static void gen_lfqu(DisasContext *ctx)
-{
- int ra = rA(ctx->opcode);
- int rd = rD(ctx->opcode);
- TCGv t0, t1;
- TCGv_i64 t2;
- gen_set_access_type(ctx, ACCESS_FLOAT);
- t0 = tcg_temp_new();
- t1 = tcg_temp_new();
- t2 = tcg_temp_new_i64();
- gen_addr_imm_index(ctx, t0, 0);
- gen_qemu_ld64_i64(ctx, t2, t0);
- set_fpr(rd, t2);
- gen_addr_add(ctx, t1, t0, 8);
- gen_qemu_ld64_i64(ctx, t2, t1);
- set_fpr((rd + 1) % 32, t2);
- if (ra != 0) {
- tcg_gen_mov_tl(cpu_gpr[ra], t0);
- }
- tcg_temp_free(t0);
- tcg_temp_free(t1);
- tcg_temp_free_i64(t2);
-}
-
-/* lfqux */
-static void gen_lfqux(DisasContext *ctx)
-{
- int ra = rA(ctx->opcode);
- int rd = rD(ctx->opcode);
- gen_set_access_type(ctx, ACCESS_FLOAT);
- TCGv t0, t1;
- TCGv_i64 t2;
- t2 = tcg_temp_new_i64();
- t0 = tcg_temp_new();
- gen_addr_reg_index(ctx, t0);
- gen_qemu_ld64_i64(ctx, t2, t0);
- set_fpr(rd, t2);
- t1 = tcg_temp_new();
- gen_addr_add(ctx, t1, t0, 8);
- gen_qemu_ld64_i64(ctx, t2, t1);
- set_fpr((rd + 1) % 32, t2);
- tcg_temp_free(t1);
- if (ra != 0) {
- tcg_gen_mov_tl(cpu_gpr[ra], t0);
- }
- tcg_temp_free(t0);
- tcg_temp_free_i64(t2);
-}
-
-/* lfqx */
-static void gen_lfqx(DisasContext *ctx)
-{
- int rd = rD(ctx->opcode);
- TCGv t0;
- TCGv_i64 t1;
- gen_set_access_type(ctx, ACCESS_FLOAT);
- t0 = tcg_temp_new();
- t1 = tcg_temp_new_i64();
- gen_addr_reg_index(ctx, t0);
- gen_qemu_ld64_i64(ctx, t1, t0);
- set_fpr(rd, t1);
- gen_addr_add(ctx, t0, t0, 8);
- gen_qemu_ld64_i64(ctx, t1, t0);
- set_fpr((rd + 1) % 32, t1);
- tcg_temp_free(t0);
- tcg_temp_free_i64(t1);
-}
-
-/* stfq */
-static void gen_stfq(DisasContext *ctx)
-{
- int rd = rD(ctx->opcode);
- TCGv t0;
- TCGv_i64 t1;
- gen_set_access_type(ctx, ACCESS_FLOAT);
- t0 = tcg_temp_new();
- t1 = tcg_temp_new_i64();
- gen_addr_imm_index(ctx, t0, 0);
- get_fpr(t1, rd);
- gen_qemu_st64_i64(ctx, t1, t0);
- gen_addr_add(ctx, t0, t0, 8);
- get_fpr(t1, (rd + 1) % 32);
- gen_qemu_st64_i64(ctx, t1, t0);
- tcg_temp_free(t0);
- tcg_temp_free_i64(t1);
-}
-
-/* stfqu */
-static void gen_stfqu(DisasContext *ctx)
-{
- int ra = rA(ctx->opcode);
- int rd = rD(ctx->opcode);
- TCGv t0, t1;
- TCGv_i64 t2;
- gen_set_access_type(ctx, ACCESS_FLOAT);
- t2 = tcg_temp_new_i64();
- t0 = tcg_temp_new();
- gen_addr_imm_index(ctx, t0, 0);
- get_fpr(t2, rd);
- gen_qemu_st64_i64(ctx, t2, t0);
- t1 = tcg_temp_new();
- gen_addr_add(ctx, t1, t0, 8);
- get_fpr(t2, (rd + 1) % 32);
- gen_qemu_st64_i64(ctx, t2, t1);
- tcg_temp_free(t1);
- if (ra != 0) {
- tcg_gen_mov_tl(cpu_gpr[ra], t0);
- }
- tcg_temp_free(t0);
- tcg_temp_free_i64(t2);
-}
-
-/* stfqux */
-static void gen_stfqux(DisasContext *ctx)
-{
- int ra = rA(ctx->opcode);
- int rd = rD(ctx->opcode);
- TCGv t0, t1;
- TCGv_i64 t2;
- gen_set_access_type(ctx, ACCESS_FLOAT);
- t2 = tcg_temp_new_i64();
- t0 = tcg_temp_new();
- gen_addr_reg_index(ctx, t0);
- get_fpr(t2, rd);
- gen_qemu_st64_i64(ctx, t2, t0);
- t1 = tcg_temp_new();
- gen_addr_add(ctx, t1, t0, 8);
- get_fpr(t2, (rd + 1) % 32);
- gen_qemu_st64_i64(ctx, t2, t1);
- tcg_temp_free(t1);
- if (ra != 0) {
- tcg_gen_mov_tl(cpu_gpr[ra], t0);
- }
- tcg_temp_free(t0);
- tcg_temp_free_i64(t2);
-}
-
-/* stfqx */
-static void gen_stfqx(DisasContext *ctx)
-{
- int rd = rD(ctx->opcode);
- TCGv t0;
- TCGv_i64 t1;
- gen_set_access_type(ctx, ACCESS_FLOAT);
- t1 = tcg_temp_new_i64();
- t0 = tcg_temp_new();
- gen_addr_reg_index(ctx, t0);
- get_fpr(t1, rd);
- gen_qemu_st64_i64(ctx, t1, t0);
- gen_addr_add(ctx, t0, t0, 8);
- get_fpr(t1, (rd + 1) % 32);
- gen_qemu_st64_i64(ctx, t1, t0);
- tcg_temp_free(t0);
- tcg_temp_free_i64(t1);
-}
-
/* Floating-point Load/Store Instructions */
static bool do_lsfpsd(DisasContext *ctx, int rt, int ra, TCGv displ,
bool update, bool store, bool single)
diff --git a/target/ppc/translate/vsx-impl.c.inc b/target/ppc/translate/vsx-impl.c.inc
index c636e38..128968b 100644
--- a/target/ppc/translate/vsx-impl.c.inc
+++ b/target/ppc/translate/vsx-impl.c.inc
@@ -747,6 +747,7 @@
} \
} \
set_cpu_vsr(xT(ctx->opcode), xb, true); \
+ set_cpu_vsr(xT(ctx->opcode), tcg_constant_i64(0), false); \
tcg_temp_free_i64(xb); \
tcg_temp_free_i64(sgm); \
}
@@ -1073,6 +1074,7 @@
get_cpu_vsr(t0, xB(ctx->opcode), true); \
gen_helper_##name(t1, cpu_env, t0); \
set_cpu_vsr(xT(ctx->opcode), t1, true); \
+ set_cpu_vsr(xT(ctx->opcode), tcg_constant_i64(0), false); \
tcg_temp_free_i64(t0); \
tcg_temp_free_i64(t1); \
}
@@ -1700,7 +1702,7 @@
tcg_gen_shli_i64(t0, t0, 52);
tcg_gen_or_i64(xth, xth, t0);
set_cpu_vsr(xT(ctx->opcode), xth, true);
- /* dword[1] is undefined */
+ set_cpu_vsr(xT(ctx->opcode), tcg_constant_i64(0), false);
tcg_temp_free_i64(t0);
tcg_temp_free_i64(xth);
}
diff --git a/tcg/aarch64/tcg-target.c.inc b/tcg/aarch64/tcg-target.c.inc
index a8db553..077fc51 100644
--- a/tcg/aarch64/tcg-target.c.inc
+++ b/tcg/aarch64/tcg-target.c.inc
@@ -10,6 +10,7 @@
* See the COPYING file in the top-level directory for details.
*/
+#include "../tcg-ldst.c.inc"
#include "../tcg-pool.c.inc"
#include "qemu/bitops.h"
@@ -443,6 +444,7 @@
I3404_ANDI = 0x12000000,
I3404_ORRI = 0x32000000,
I3404_EORI = 0x52000000,
+ I3404_ANDSI = 0x72000000,
/* Move wide immediate instructions. */
I3405_MOVN = 0x12800000,
@@ -1328,8 +1330,9 @@
if (offset == sextract64(offset, 0, 26)) {
tcg_out_insn(s, 3206, B, offset);
} else {
- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_TMP, (intptr_t)target);
- tcg_out_insn(s, 3207, BR, TCG_REG_TMP);
+ /* Choose X9 as a call-clobbered non-LR temporary. */
+ tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_X9, (intptr_t)target);
+ tcg_out_insn(s, 3207, BR, TCG_REG_X9);
}
}
@@ -1541,9 +1544,14 @@
}
}
-#ifdef CONFIG_SOFTMMU
-#include "../tcg-ldst.c.inc"
+static void tcg_out_adr(TCGContext *s, TCGReg rd, const void *target)
+{
+ ptrdiff_t offset = tcg_pcrel_diff(s, target);
+ tcg_debug_assert(offset == sextract64(offset, 0, 21));
+ tcg_out_insn(s, 3406, ADR, rd, offset);
+}
+#ifdef CONFIG_SOFTMMU
/* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr,
* MemOpIdx oi, uintptr_t ra)
*/
@@ -1577,13 +1585,6 @@
#endif
};
-static inline void tcg_out_adr(TCGContext *s, TCGReg rd, const void *target)
-{
- ptrdiff_t offset = tcg_pcrel_diff(s, target);
- tcg_debug_assert(offset == sextract64(offset, 0, 21));
- tcg_out_insn(s, 3406, ADR, rd, offset);
-}
-
static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *lb)
{
MemOpIdx oi = lb->oi;
@@ -1714,15 +1715,58 @@
tcg_out_insn(s, 3202, B_C, TCG_COND_NE, 0);
}
+#else
+static void tcg_out_test_alignment(TCGContext *s, bool is_ld, TCGReg addr_reg,
+ unsigned a_bits)
+{
+ unsigned a_mask = (1 << a_bits) - 1;
+ TCGLabelQemuLdst *label = new_ldst_label(s);
+
+ label->is_ld = is_ld;
+ label->addrlo_reg = addr_reg;
+
+ /* tst addr, #mask */
+ tcg_out_logicali(s, I3404_ANDSI, 0, TCG_REG_XZR, addr_reg, a_mask);
+
+ label->label_ptr[0] = s->code_ptr;
+
+ /* b.ne slow_path */
+ tcg_out_insn(s, 3202, B_C, TCG_COND_NE, 0);
+
+ label->raddr = tcg_splitwx_to_rx(s->code_ptr);
+}
+
+static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ if (!reloc_pc19(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) {
+ return false;
+ }
+
+ tcg_out_mov(s, TCG_TYPE_TL, TCG_REG_X1, l->addrlo_reg);
+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_X0, TCG_AREG0);
+
+ /* "Tail call" to the helper, with the return address back inline. */
+ tcg_out_adr(s, TCG_REG_LR, l->raddr);
+ tcg_out_goto_long(s, (const void *)(l->is_ld ? helper_unaligned_ld
+ : helper_unaligned_st));
+ return true;
+}
+
+static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
+
+static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
#endif /* CONFIG_SOFTMMU */
static void tcg_out_qemu_ld_direct(TCGContext *s, MemOp memop, TCGType ext,
TCGReg data_r, TCGReg addr_r,
TCGType otype, TCGReg off_r)
{
- /* Byte swapping is left to middle-end expansion. */
- tcg_debug_assert((memop & MO_BSWAP) == 0);
-
switch (memop & MO_SSIZE) {
case MO_UB:
tcg_out_ldst_r(s, I3312_LDRB, data_r, addr_r, otype, off_r);
@@ -1756,9 +1800,6 @@
TCGReg data_r, TCGReg addr_r,
TCGType otype, TCGReg off_r)
{
- /* Byte swapping is left to middle-end expansion. */
- tcg_debug_assert((memop & MO_BSWAP) == 0);
-
switch (memop & MO_SIZE) {
case MO_8:
tcg_out_ldst_r(s, I3312_STRB, data_r, addr_r, otype, off_r);
@@ -1782,6 +1823,10 @@
{
MemOp memop = get_memop(oi);
const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64 : TCG_TYPE_I32;
+
+ /* Byte swapping is left to middle-end expansion. */
+ tcg_debug_assert((memop & MO_BSWAP) == 0);
+
#ifdef CONFIG_SOFTMMU
unsigned mem_index = get_mmuidx(oi);
tcg_insn_unit *label_ptr;
@@ -1792,6 +1837,10 @@
add_qemu_ldst_label(s, true, oi, ext, data_reg, addr_reg,
s->code_ptr, label_ptr);
#else /* !CONFIG_SOFTMMU */
+ unsigned a_bits = get_alignment_bits(memop);
+ if (a_bits) {
+ tcg_out_test_alignment(s, true, addr_reg, a_bits);
+ }
if (USE_GUEST_BASE) {
tcg_out_qemu_ld_direct(s, memop, ext, data_reg,
TCG_REG_GUEST_BASE, otype, addr_reg);
@@ -1807,6 +1856,10 @@
{
MemOp memop = get_memop(oi);
const TCGType otype = TARGET_LONG_BITS == 64 ? TCG_TYPE_I64 : TCG_TYPE_I32;
+
+ /* Byte swapping is left to middle-end expansion. */
+ tcg_debug_assert((memop & MO_BSWAP) == 0);
+
#ifdef CONFIG_SOFTMMU
unsigned mem_index = get_mmuidx(oi);
tcg_insn_unit *label_ptr;
@@ -1817,6 +1870,10 @@
add_qemu_ldst_label(s, false, oi, (memop & MO_SIZE)== MO_64,
data_reg, addr_reg, s->code_ptr, label_ptr);
#else /* !CONFIG_SOFTMMU */
+ unsigned a_bits = get_alignment_bits(memop);
+ if (a_bits) {
+ tcg_out_test_alignment(s, false, addr_reg, a_bits);
+ }
if (USE_GUEST_BASE) {
tcg_out_qemu_st_direct(s, memop, data_reg,
TCG_REG_GUEST_BASE, otype, addr_reg);
diff --git a/tcg/aarch64/tcg-target.h b/tcg/aarch64/tcg-target.h
index 7a93ac8..876af58 100644
--- a/tcg/aarch64/tcg-target.h
+++ b/tcg/aarch64/tcg-target.h
@@ -151,9 +151,7 @@
void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
-#ifdef CONFIG_SOFTMMU
#define TCG_TARGET_NEED_LDST_LABELS
-#endif
#define TCG_TARGET_NEED_POOL_LABELS
#endif /* AARCH64_TCG_TARGET_H */
diff --git a/tcg/arm/tcg-target.c.inc b/tcg/arm/tcg-target.c.inc
index 5345c4e..e1ea696 100644
--- a/tcg/arm/tcg-target.c.inc
+++ b/tcg/arm/tcg-target.c.inc
@@ -23,6 +23,7 @@
*/
#include "elf.h"
+#include "../tcg-ldst.c.inc"
#include "../tcg-pool.c.inc"
int arm_arch = __ARM_ARCH;
@@ -34,13 +35,6 @@
bool use_neon_instructions;
#endif
-/* ??? Ought to think about changing CONFIG_SOFTMMU to always defined. */
-#ifdef CONFIG_SOFTMMU
-# define USING_SOFTMMU 1
-#else
-# define USING_SOFTMMU 0
-#endif
-
#ifdef CONFIG_DEBUG_TCG
static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
"%r0", "%r1", "%r2", "%r3", "%r4", "%r5", "%r6", "%r7",
@@ -91,6 +85,9 @@
#define TCG_REG_TMP TCG_REG_R12
#define TCG_VEC_TMP TCG_REG_Q15
+#ifndef CONFIG_SOFTMMU
+#define TCG_REG_GUEST_BASE TCG_REG_R11
+#endif
typedef enum {
COND_EQ = 0x0,
@@ -596,11 +593,7 @@
* Unless the C portion of QEMU is compiled as thumb, we don't need
* true BX semantics; merely a branch to an address held in a register.
*/
- if (use_armv5t_instructions) {
- tcg_out_bx_reg(s, cond, rn);
- } else {
- tcg_out_mov_reg(s, cond, TCG_REG_PC, rn);
- }
+ tcg_out_bx_reg(s, cond, rn);
}
static void tcg_out_dat_imm(TCGContext *s, ARMCond cond, ARMInsn opc,
@@ -927,17 +920,6 @@
static void tcg_out_mul32(TCGContext *s, ARMCond cond, TCGReg rd,
TCGReg rn, TCGReg rm)
{
- /* if ArchVersion() < 6 && d == n then UNPREDICTABLE; */
- if (!use_armv6_instructions && rd == rn) {
- if (rd == rm) {
- /* rd == rn == rm; copy an input to tmp first. */
- tcg_out_mov_reg(s, cond, TCG_REG_TMP, rn);
- rm = rn = TCG_REG_TMP;
- } else {
- rn = rm;
- rm = rd;
- }
- }
/* mul */
tcg_out32(s, (cond << 28) | 0x90 | (rd << 16) | (rm << 8) | rn);
}
@@ -945,17 +927,6 @@
static void tcg_out_umull32(TCGContext *s, ARMCond cond, TCGReg rd0,
TCGReg rd1, TCGReg rn, TCGReg rm)
{
- /* if ArchVersion() < 6 && (dHi == n || dLo == n) then UNPREDICTABLE; */
- if (!use_armv6_instructions && (rd0 == rn || rd1 == rn)) {
- if (rd0 == rm || rd1 == rm) {
- tcg_out_mov_reg(s, cond, TCG_REG_TMP, rn);
- rn = TCG_REG_TMP;
- } else {
- TCGReg t = rn;
- rn = rm;
- rm = t;
- }
- }
/* umull */
tcg_out32(s, (cond << 28) | 0x00800090 |
(rd1 << 16) | (rd0 << 12) | (rm << 8) | rn);
@@ -964,17 +935,6 @@
static void tcg_out_smull32(TCGContext *s, ARMCond cond, TCGReg rd0,
TCGReg rd1, TCGReg rn, TCGReg rm)
{
- /* if ArchVersion() < 6 && (dHi == n || dLo == n) then UNPREDICTABLE; */
- if (!use_armv6_instructions && (rd0 == rn || rd1 == rn)) {
- if (rd0 == rm || rd1 == rm) {
- tcg_out_mov_reg(s, cond, TCG_REG_TMP, rn);
- rn = TCG_REG_TMP;
- } else {
- TCGReg t = rn;
- rn = rm;
- rm = t;
- }
- }
/* smull */
tcg_out32(s, (cond << 28) | 0x00c00090 |
(rd1 << 16) | (rd0 << 12) | (rm << 8) | rn);
@@ -994,15 +954,8 @@
static void tcg_out_ext8s(TCGContext *s, ARMCond cond, TCGReg rd, TCGReg rn)
{
- if (use_armv6_instructions) {
- /* sxtb */
- tcg_out32(s, 0x06af0070 | (cond << 28) | (rd << 12) | rn);
- } else {
- tcg_out_dat_reg(s, cond, ARITH_MOV,
- rd, 0, rn, SHIFT_IMM_LSL(24));
- tcg_out_dat_reg(s, cond, ARITH_MOV,
- rd, 0, rd, SHIFT_IMM_ASR(24));
- }
+ /* sxtb */
+ tcg_out32(s, 0x06af0070 | (cond << 28) | (rd << 12) | rn);
}
static void __attribute__((unused))
@@ -1013,113 +966,37 @@
static void tcg_out_ext16s(TCGContext *s, ARMCond cond, TCGReg rd, TCGReg rn)
{
- if (use_armv6_instructions) {
- /* sxth */
- tcg_out32(s, 0x06bf0070 | (cond << 28) | (rd << 12) | rn);
- } else {
- tcg_out_dat_reg(s, cond, ARITH_MOV,
- rd, 0, rn, SHIFT_IMM_LSL(16));
- tcg_out_dat_reg(s, cond, ARITH_MOV,
- rd, 0, rd, SHIFT_IMM_ASR(16));
- }
+ /* sxth */
+ tcg_out32(s, 0x06bf0070 | (cond << 28) | (rd << 12) | rn);
}
static void tcg_out_ext16u(TCGContext *s, ARMCond cond, TCGReg rd, TCGReg rn)
{
- if (use_armv6_instructions) {
- /* uxth */
- tcg_out32(s, 0x06ff0070 | (cond << 28) | (rd << 12) | rn);
- } else {
- tcg_out_dat_reg(s, cond, ARITH_MOV,
- rd, 0, rn, SHIFT_IMM_LSL(16));
- tcg_out_dat_reg(s, cond, ARITH_MOV,
- rd, 0, rd, SHIFT_IMM_LSR(16));
- }
+ /* uxth */
+ tcg_out32(s, 0x06ff0070 | (cond << 28) | (rd << 12) | rn);
}
static void tcg_out_bswap16(TCGContext *s, ARMCond cond,
TCGReg rd, TCGReg rn, int flags)
{
- if (use_armv6_instructions) {
- if (flags & TCG_BSWAP_OS) {
- /* revsh */
- tcg_out32(s, 0x06ff0fb0 | (cond << 28) | (rd << 12) | rn);
- return;
- }
-
- /* rev16 */
- tcg_out32(s, 0x06bf0fb0 | (cond << 28) | (rd << 12) | rn);
- if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) {
- /* uxth */
- tcg_out32(s, 0x06ff0070 | (cond << 28) | (rd << 12) | rd);
- }
+ if (flags & TCG_BSWAP_OS) {
+ /* revsh */
+ tcg_out32(s, 0x06ff0fb0 | (cond << 28) | (rd << 12) | rn);
return;
}
- if (flags == 0) {
- /*
- * For stores, no input or output extension:
- * rn = xxAB
- * lsr tmp, rn, #8 tmp = 0xxA
- * and tmp, tmp, #0xff tmp = 000A
- * orr rd, tmp, rn, lsl #8 rd = xABA
- */
- tcg_out_dat_reg(s, cond, ARITH_MOV,
- TCG_REG_TMP, 0, rn, SHIFT_IMM_LSR(8));
- tcg_out_dat_imm(s, cond, ARITH_AND, TCG_REG_TMP, TCG_REG_TMP, 0xff);
- tcg_out_dat_reg(s, cond, ARITH_ORR,
- rd, TCG_REG_TMP, rn, SHIFT_IMM_LSL(8));
- return;
+ /* rev16 */
+ tcg_out32(s, 0x06bf0fb0 | (cond << 28) | (rd << 12) | rn);
+ if ((flags & (TCG_BSWAP_IZ | TCG_BSWAP_OZ)) == TCG_BSWAP_OZ) {
+ /* uxth */
+ tcg_out32(s, 0x06ff0070 | (cond << 28) | (rd << 12) | rd);
}
-
- /*
- * Byte swap, leaving the result at the top of the register.
- * We will then shift down, zero or sign-extending.
- */
- if (flags & TCG_BSWAP_IZ) {
- /*
- * rn = 00AB
- * ror tmp, rn, #8 tmp = B00A
- * orr tmp, tmp, tmp, lsl #16 tmp = BA00
- */
- tcg_out_dat_reg(s, cond, ARITH_MOV,
- TCG_REG_TMP, 0, rn, SHIFT_IMM_ROR(8));
- tcg_out_dat_reg(s, cond, ARITH_ORR,
- TCG_REG_TMP, TCG_REG_TMP, TCG_REG_TMP,
- SHIFT_IMM_LSL(16));
- } else {
- /*
- * rn = xxAB
- * and tmp, rn, #0xff00 tmp = 00A0
- * lsl tmp, tmp, #8 tmp = 0A00
- * orr tmp, tmp, rn, lsl #24 tmp = BA00
- */
- tcg_out_dat_rI(s, cond, ARITH_AND, TCG_REG_TMP, rn, 0xff00, 1);
- tcg_out_dat_reg(s, cond, ARITH_MOV,
- TCG_REG_TMP, 0, TCG_REG_TMP, SHIFT_IMM_LSL(8));
- tcg_out_dat_reg(s, cond, ARITH_ORR,
- TCG_REG_TMP, TCG_REG_TMP, rn, SHIFT_IMM_LSL(24));
- }
- tcg_out_dat_reg(s, cond, ARITH_MOV, rd, 0, TCG_REG_TMP,
- (flags & TCG_BSWAP_OS
- ? SHIFT_IMM_ASR(8) : SHIFT_IMM_LSR(8)));
}
static void tcg_out_bswap32(TCGContext *s, ARMCond cond, TCGReg rd, TCGReg rn)
{
- if (use_armv6_instructions) {
- /* rev */
- tcg_out32(s, 0x06bf0f30 | (cond << 28) | (rd << 12) | rn);
- } else {
- tcg_out_dat_reg(s, cond, ARITH_EOR,
- TCG_REG_TMP, rn, rn, SHIFT_IMM_ROR(16));
- tcg_out_dat_imm(s, cond, ARITH_BIC,
- TCG_REG_TMP, TCG_REG_TMP, 0xff | 0x800);
- tcg_out_dat_reg(s, cond, ARITH_MOV,
- rd, 0, rn, SHIFT_IMM_ROR(8));
- tcg_out_dat_reg(s, cond, ARITH_EOR,
- rd, rd, TCG_REG_TMP, SHIFT_IMM_LSR(8));
- }
+ /* rev */
+ tcg_out32(s, 0x06bf0f30 | (cond << 28) | (rd << 12) | rn);
}
static void tcg_out_deposit(TCGContext *s, ARMCond cond, TCGReg rd,
@@ -1247,14 +1124,7 @@
}
/* LDR is interworking from v5t. */
- if (arm_mode || use_armv5t_instructions) {
- tcg_out_movi_pool(s, cond, TCG_REG_PC, addri);
- return;
- }
-
- /* else v4t */
- tcg_out_movi32(s, COND_AL, TCG_REG_TMP, addri);
- tcg_out_bx_reg(s, COND_AL, TCG_REG_TMP);
+ tcg_out_movi_pool(s, cond, TCG_REG_PC, addri);
}
/*
@@ -1270,26 +1140,14 @@
if (disp - 8 < 0x02000000 && disp - 8 >= -0x02000000) {
if (arm_mode) {
tcg_out_bl_imm(s, COND_AL, disp);
- return;
- }
- if (use_armv5t_instructions) {
+ } else {
tcg_out_blx_imm(s, disp);
- return;
}
+ return;
}
- if (use_armv5t_instructions) {
- tcg_out_movi32(s, COND_AL, TCG_REG_TMP, addri);
- tcg_out_blx_reg(s, COND_AL, TCG_REG_TMP);
- } else if (arm_mode) {
- /* ??? Know that movi_pool emits exactly 1 insn. */
- tcg_out_mov_reg(s, COND_AL, TCG_REG_R14, TCG_REG_PC);
- tcg_out_movi_pool(s, COND_AL, TCG_REG_PC, addri);
- } else {
- tcg_out_movi32(s, COND_AL, TCG_REG_TMP, addri);
- tcg_out_mov_reg(s, COND_AL, TCG_REG_R14, TCG_REG_PC);
- tcg_out_bx_reg(s, COND_AL, TCG_REG_TMP);
- }
+ tcg_out_movi32(s, COND_AL, TCG_REG_TMP, addri);
+ tcg_out_blx_reg(s, COND_AL, TCG_REG_TMP);
}
static void tcg_out_goto_label(TCGContext *s, ARMCond cond, TCGLabel *l)
@@ -1306,7 +1164,7 @@
{
if (use_armv7_instructions) {
tcg_out32(s, INSN_DMB_ISH);
- } else if (use_armv6_instructions) {
+ } else {
tcg_out32(s, INSN_DMB_MCR);
}
}
@@ -1432,8 +1290,6 @@
}
#ifdef CONFIG_SOFTMMU
-#include "../tcg-ldst.c.inc"
-
/* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr,
* int mmu_idx, uintptr_t ra)
*/
@@ -1512,8 +1368,7 @@
if (argreg & 1) {
argreg++;
}
- if (use_armv6_instructions && argreg >= 4
- && (arglo & 1) == 0 && arghi == arglo + 1) {
+ if (argreg >= 4 && (arglo & 1) == 0 && arghi == arglo + 1) {
tcg_out_strd_8(s, COND_AL, arglo,
TCG_REG_CALL_STACK, (argreg - 4) * 4);
return argreg + 2;
@@ -1543,26 +1398,12 @@
int cmp_off = (is_load ? offsetof(CPUTLBEntry, addr_read)
: offsetof(CPUTLBEntry, addr_write));
int fast_off = TLB_MASK_TABLE_OFS(mem_index);
- int mask_off = fast_off + offsetof(CPUTLBDescFast, mask);
- int table_off = fast_off + offsetof(CPUTLBDescFast, table);
- unsigned s_bits = opc & MO_SIZE;
- unsigned a_bits = get_alignment_bits(opc);
-
- /*
- * We don't support inline unaligned acceses, but we can easily
- * support overalignment checks.
- */
- if (a_bits < s_bits) {
- a_bits = s_bits;
- }
+ unsigned s_mask = (1 << (opc & MO_SIZE)) - 1;
+ unsigned a_mask = (1 << get_alignment_bits(opc)) - 1;
+ TCGReg t_addr;
/* Load env_tlb(env)->f[mmu_idx].{mask,table} into {r0,r1}. */
- if (use_armv6_instructions) {
- tcg_out_ldrd_8(s, COND_AL, TCG_REG_R0, TCG_AREG0, fast_off);
- } else {
- tcg_out_ld(s, TCG_TYPE_I32, TCG_REG_R0, TCG_AREG0, mask_off);
- tcg_out_ld(s, TCG_TYPE_I32, TCG_REG_R1, TCG_AREG0, table_off);
- }
+ tcg_out_ldrd_8(s, COND_AL, TCG_REG_R0, TCG_AREG0, fast_off);
/* Extract the tlb index from the address into R0. */
tcg_out_dat_reg(s, COND_AL, ARITH_AND, TCG_REG_R0, TCG_REG_R0, addrlo,
@@ -1573,7 +1414,7 @@
* Load the tlb comparator into R2/R3 and the fast path addend into R1.
*/
if (cmp_off == 0) {
- if (use_armv6_instructions && TARGET_LONG_BITS == 64) {
+ if (TARGET_LONG_BITS == 64) {
tcg_out_ldrd_rwb(s, COND_AL, TCG_REG_R2, TCG_REG_R1, TCG_REG_R0);
} else {
tcg_out_ld32_rwb(s, COND_AL, TCG_REG_R2, TCG_REG_R1, TCG_REG_R0);
@@ -1581,15 +1422,12 @@
} else {
tcg_out_dat_reg(s, COND_AL, ARITH_ADD,
TCG_REG_R1, TCG_REG_R1, TCG_REG_R0, 0);
- if (use_armv6_instructions && TARGET_LONG_BITS == 64) {
+ if (TARGET_LONG_BITS == 64) {
tcg_out_ldrd_8(s, COND_AL, TCG_REG_R2, TCG_REG_R1, cmp_off);
} else {
tcg_out_ld32_12(s, COND_AL, TCG_REG_R2, TCG_REG_R1, cmp_off);
}
}
- if (!use_armv6_instructions && TARGET_LONG_BITS == 64) {
- tcg_out_ld32_12(s, COND_AL, TCG_REG_R3, TCG_REG_R1, cmp_off + 4);
- }
/* Load the tlb addend. */
tcg_out_ld32_12(s, COND_AL, TCG_REG_R1, TCG_REG_R1,
@@ -1597,27 +1435,35 @@
/*
* Check alignment, check comparators.
- * Do this in no more than 3 insns. Use MOVW for v7, if possible,
+ * Do this in 2-4 insns. Use MOVW for v7, if possible,
* to reduce the number of sequential conditional instructions.
* Almost all guests have at least 4k pages, which means that we need
* to clear at least 9 bits even for an 8-byte memory, which means it
* isn't worth checking for an immediate operand for BIC.
+ *
+ * For unaligned accesses, test the page of the last unit of alignment.
+ * This leaves the least significant alignment bits unchanged, and of
+ * course must be zero.
*/
+ t_addr = addrlo;
+ if (a_mask < s_mask) {
+ t_addr = TCG_REG_R0;
+ tcg_out_dat_imm(s, COND_AL, ARITH_ADD, t_addr,
+ addrlo, s_mask - a_mask);
+ }
if (use_armv7_instructions && TARGET_PAGE_BITS <= 16) {
- tcg_target_ulong mask = ~(TARGET_PAGE_MASK | ((1 << a_bits) - 1));
-
- tcg_out_movi32(s, COND_AL, TCG_REG_TMP, mask);
+ tcg_out_movi32(s, COND_AL, TCG_REG_TMP, ~(TARGET_PAGE_MASK | a_mask));
tcg_out_dat_reg(s, COND_AL, ARITH_BIC, TCG_REG_TMP,
- addrlo, TCG_REG_TMP, 0);
+ t_addr, TCG_REG_TMP, 0);
tcg_out_dat_reg(s, COND_AL, ARITH_CMP, 0, TCG_REG_R2, TCG_REG_TMP, 0);
} else {
- if (a_bits) {
- tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, addrlo,
- (1 << a_bits) - 1);
+ if (a_mask) {
+ tcg_debug_assert(a_mask <= 0xff);
+ tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, addrlo, a_mask);
}
- tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_TMP, 0, addrlo,
+ tcg_out_dat_reg(s, COND_AL, ARITH_MOV, TCG_REG_TMP, 0, t_addr,
SHIFT_IMM_LSR(TARGET_PAGE_BITS));
- tcg_out_dat_reg(s, (a_bits ? COND_EQ : COND_AL), ARITH_CMP,
+ tcg_out_dat_reg(s, (a_mask ? COND_EQ : COND_AL), ARITH_CMP,
0, TCG_REG_R2, TCG_REG_TMP,
SHIFT_IMM_LSL(TARGET_PAGE_BITS));
}
@@ -1654,7 +1500,6 @@
TCGReg argreg, datalo, datahi;
MemOpIdx oi = lb->oi;
MemOp opc = get_memop(oi);
- void *func;
if (!reloc_pc24(lb->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) {
return false;
@@ -1669,18 +1514,8 @@
argreg = tcg_out_arg_imm32(s, argreg, oi);
argreg = tcg_out_arg_reg32(s, argreg, TCG_REG_R14);
- /* For armv6 we can use the canonical unsigned helpers and minimize
- icache usage. For pre-armv6, use the signed helpers since we do
- not have a single insn sign-extend. */
- if (use_armv6_instructions) {
- func = qemu_ld_helpers[opc & MO_SIZE];
- } else {
- func = qemu_ld_helpers[opc & MO_SSIZE];
- if (opc & MO_SIGN) {
- opc = MO_UL;
- }
- }
- tcg_out_call(s, func);
+ /* Use the canonical unsigned helpers and minimize icache usage. */
+ tcg_out_call(s, qemu_ld_helpers[opc & MO_SIZE]);
datalo = lb->datalo_reg;
datahi = lb->datahi_reg;
@@ -1756,11 +1591,80 @@
tcg_out_goto(s, COND_AL, qemu_st_helpers[opc & MO_SIZE]);
return true;
}
+#else
+
+static void tcg_out_test_alignment(TCGContext *s, bool is_ld, TCGReg addrlo,
+ TCGReg addrhi, unsigned a_bits)
+{
+ unsigned a_mask = (1 << a_bits) - 1;
+ TCGLabelQemuLdst *label = new_ldst_label(s);
+
+ label->is_ld = is_ld;
+ label->addrlo_reg = addrlo;
+ label->addrhi_reg = addrhi;
+
+ /* We are expecting a_bits to max out at 7, and can easily support 8. */
+ tcg_debug_assert(a_mask <= 0xff);
+ /* tst addr, #mask */
+ tcg_out_dat_imm(s, COND_AL, ARITH_TST, 0, addrlo, a_mask);
+
+ /* blne slow_path */
+ label->label_ptr[0] = s->code_ptr;
+ tcg_out_bl_imm(s, COND_NE, 0);
+
+ label->raddr = tcg_splitwx_to_rx(s->code_ptr);
+}
+
+static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ if (!reloc_pc24(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) {
+ return false;
+ }
+
+ if (TARGET_LONG_BITS == 64) {
+ /* 64-bit target address is aligned into R2:R3. */
+ if (l->addrhi_reg != TCG_REG_R2) {
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R2, l->addrlo_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R3, l->addrhi_reg);
+ } else if (l->addrlo_reg != TCG_REG_R3) {
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R3, l->addrhi_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R2, l->addrlo_reg);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R1, TCG_REG_R2);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R2, TCG_REG_R3);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R3, TCG_REG_R1);
+ }
+ } else {
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R1, l->addrlo_reg);
+ }
+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_R0, TCG_AREG0);
+
+ /*
+ * Tail call to the helper, with the return address back inline,
+ * just for the clarity of the debugging traceback -- the helper
+ * cannot return. We have used BLNE to arrive here, so LR is
+ * already set.
+ */
+ tcg_out_goto(s, COND_AL, (const void *)
+ (l->is_ld ? helper_unaligned_ld : helper_unaligned_st));
+ return true;
+}
+
+static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
+
+static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
#endif /* SOFTMMU */
static void tcg_out_qemu_ld_index(TCGContext *s, MemOp opc,
TCGReg datalo, TCGReg datahi,
- TCGReg addrlo, TCGReg addend)
+ TCGReg addrlo, TCGReg addend,
+ bool scratch_addend)
{
/* Byte swapping is left to middle-end expansion. */
tcg_debug_assert((opc & MO_BSWAP) == 0);
@@ -1782,11 +1686,11 @@
tcg_out_ld32_r(s, COND_AL, datalo, addrlo, addend);
break;
case MO_UQ:
- /* Avoid ldrd for user-only emulation, to handle unaligned. */
- if (USING_SOFTMMU && use_armv6_instructions
+ /* LDRD requires alignment; double-check that. */
+ if (get_alignment_bits(opc) >= MO_64
&& (datalo & 1) == 0 && datahi == datalo + 1) {
tcg_out_ldrd_r(s, COND_AL, datalo, addrlo, addend);
- } else if (datalo != addend) {
+ } else if (scratch_addend) {
tcg_out_ld32_rwb(s, COND_AL, datalo, addend, addrlo);
tcg_out_ld32_12(s, COND_AL, datahi, addend, 4);
} else {
@@ -1825,8 +1729,8 @@
tcg_out_ld32_12(s, COND_AL, datalo, addrlo, 0);
break;
case MO_UQ:
- /* Avoid ldrd for user-only emulation, to handle unaligned. */
- if (USING_SOFTMMU && use_armv6_instructions
+ /* LDRD requires alignment; double-check that. */
+ if (get_alignment_bits(opc) >= MO_64
&& (datalo & 1) == 0 && datahi == datalo + 1) {
tcg_out_ldrd_8(s, COND_AL, datalo, addrlo, 0);
} else if (datalo == addrlo) {
@@ -1852,6 +1756,8 @@
int mem_index;
TCGReg addend;
tcg_insn_unit *label_ptr;
+#else
+ unsigned a_bits;
#endif
datalo = *args++;
@@ -1870,14 +1776,18 @@
label_ptr = s->code_ptr;
tcg_out_bl_imm(s, COND_NE, 0);
- tcg_out_qemu_ld_index(s, opc, datalo, datahi, addrlo, addend);
+ tcg_out_qemu_ld_index(s, opc, datalo, datahi, addrlo, addend, true);
add_qemu_ldst_label(s, true, oi, datalo, datahi, addrlo, addrhi,
s->code_ptr, label_ptr);
#else /* !CONFIG_SOFTMMU */
+ a_bits = get_alignment_bits(opc);
+ if (a_bits) {
+ tcg_out_test_alignment(s, true, addrlo, addrhi, a_bits);
+ }
if (guest_base) {
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP, guest_base);
- tcg_out_qemu_ld_index(s, opc, datalo, datahi, addrlo, TCG_REG_TMP);
+ tcg_out_qemu_ld_index(s, opc, datalo, datahi,
+ addrlo, TCG_REG_GUEST_BASE, false);
} else {
tcg_out_qemu_ld_direct(s, opc, datalo, datahi, addrlo);
}
@@ -1886,7 +1796,8 @@
static void tcg_out_qemu_st_index(TCGContext *s, ARMCond cond, MemOp opc,
TCGReg datalo, TCGReg datahi,
- TCGReg addrlo, TCGReg addend)
+ TCGReg addrlo, TCGReg addend,
+ bool scratch_addend)
{
/* Byte swapping is left to middle-end expansion. */
tcg_debug_assert((opc & MO_BSWAP) == 0);
@@ -1902,13 +1813,18 @@
tcg_out_st32_r(s, cond, datalo, addrlo, addend);
break;
case MO_64:
- /* Avoid strd for user-only emulation, to handle unaligned. */
- if (USING_SOFTMMU && use_armv6_instructions
+ /* STRD requires alignment; double-check that. */
+ if (get_alignment_bits(opc) >= MO_64
&& (datalo & 1) == 0 && datahi == datalo + 1) {
tcg_out_strd_r(s, cond, datalo, addrlo, addend);
- } else {
+ } else if (scratch_addend) {
tcg_out_st32_rwb(s, cond, datalo, addend, addrlo);
tcg_out_st32_12(s, cond, datahi, addend, 4);
+ } else {
+ tcg_out_dat_reg(s, cond, ARITH_ADD, TCG_REG_TMP,
+ addend, addrlo, SHIFT_IMM_LSL(0));
+ tcg_out_st32_12(s, cond, datalo, TCG_REG_TMP, 0);
+ tcg_out_st32_12(s, cond, datahi, TCG_REG_TMP, 4);
}
break;
default:
@@ -1934,8 +1850,8 @@
tcg_out_st32_12(s, COND_AL, datalo, addrlo, 0);
break;
case MO_64:
- /* Avoid strd for user-only emulation, to handle unaligned. */
- if (USING_SOFTMMU && use_armv6_instructions
+ /* STRD requires alignment; double-check that. */
+ if (get_alignment_bits(opc) >= MO_64
&& (datalo & 1) == 0 && datahi == datalo + 1) {
tcg_out_strd_8(s, COND_AL, datalo, addrlo, 0);
} else {
@@ -1958,6 +1874,8 @@
int mem_index;
TCGReg addend;
tcg_insn_unit *label_ptr;
+#else
+ unsigned a_bits;
#endif
datalo = *args++;
@@ -1971,7 +1889,8 @@
mem_index = get_mmuidx(oi);
addend = tcg_out_tlb_read(s, addrlo, addrhi, opc, mem_index, 0);
- tcg_out_qemu_st_index(s, COND_EQ, opc, datalo, datahi, addrlo, addend);
+ tcg_out_qemu_st_index(s, COND_EQ, opc, datalo, datahi,
+ addrlo, addend, true);
/* The conditional call must come last, as we're going to return here. */
label_ptr = s->code_ptr;
@@ -1980,10 +1899,13 @@
add_qemu_ldst_label(s, false, oi, datalo, datahi, addrlo, addrhi,
s->code_ptr, label_ptr);
#else /* !CONFIG_SOFTMMU */
+ a_bits = get_alignment_bits(opc);
+ if (a_bits) {
+ tcg_out_test_alignment(s, false, addrlo, addrhi, a_bits);
+ }
if (guest_base) {
- tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP, guest_base);
- tcg_out_qemu_st_index(s, COND_AL, opc, datalo,
- datahi, addrlo, TCG_REG_TMP);
+ tcg_out_qemu_st_index(s, COND_AL, opc, datalo, datahi,
+ addrlo, TCG_REG_GUEST_BASE, false);
} else {
tcg_out_qemu_st_direct(s, opc, datalo, datahi, addrlo);
}
@@ -2474,6 +2396,11 @@
if (pl != NULL && pl[0] == 'v' && pl[1] >= '4' && pl[1] <= '9') {
arm_arch = pl[1] - '0';
}
+
+ if (arm_arch < 6) {
+ error_report("TCG: ARMv%d is unsupported; exiting", arm_arch);
+ exit(EXIT_FAILURE);
+ }
}
tcg_target_available_regs[TCG_TYPE_I32] = ALL_GENERAL_REGS;
@@ -3120,6 +3047,13 @@
tcg_out_mov(s, TCG_TYPE_PTR, TCG_AREG0, tcg_target_call_iarg_regs[0]);
+#ifndef CONFIG_SOFTMMU
+ if (guest_base) {
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_GUEST_BASE, guest_base);
+ tcg_regset_set_reg(s->reserved_regs, TCG_REG_GUEST_BASE);
+ }
+#endif
+
tcg_out_b_reg(s, COND_AL, tcg_target_call_iarg_regs[1]);
/*
diff --git a/tcg/arm/tcg-target.h b/tcg/arm/tcg-target.h
index f41b809..27c27a1 100644
--- a/tcg/arm/tcg-target.h
+++ b/tcg/arm/tcg-target.h
@@ -28,8 +28,6 @@
extern int arm_arch;
-#define use_armv5t_instructions (__ARM_ARCH >= 5 || arm_arch >= 5)
-#define use_armv6_instructions (__ARM_ARCH >= 6 || arm_arch >= 6)
#define use_armv7_instructions (__ARM_ARCH >= 7 || arm_arch >= 7)
#undef TCG_TARGET_STACK_GROWSUP
@@ -109,7 +107,7 @@
#define TCG_TARGET_HAS_eqv_i32 0
#define TCG_TARGET_HAS_nand_i32 0
#define TCG_TARGET_HAS_nor_i32 0
-#define TCG_TARGET_HAS_clz_i32 use_armv5t_instructions
+#define TCG_TARGET_HAS_clz_i32 1
#define TCG_TARGET_HAS_ctz_i32 use_armv7_instructions
#define TCG_TARGET_HAS_ctpop_i32 0
#define TCG_TARGET_HAS_deposit_i32 use_armv7_instructions
@@ -153,9 +151,7 @@
/* not defined -- call should be eliminated at compile time */
void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t);
-#ifdef CONFIG_SOFTMMU
#define TCG_TARGET_NEED_LDST_LABELS
-#endif
#define TCG_TARGET_NEED_POOL_LABELS
#endif
diff --git a/tcg/i386/tcg-target.c.inc b/tcg/i386/tcg-target.c.inc
index 4dab09f..faa15ee 100644
--- a/tcg/i386/tcg-target.c.inc
+++ b/tcg/i386/tcg-target.c.inc
@@ -22,6 +22,7 @@
* THE SOFTWARE.
*/
+#include "../tcg-ldst.c.inc"
#include "../tcg-pool.c.inc"
#ifdef CONFIG_DEBUG_TCG
@@ -421,8 +422,9 @@
#define OPC_VZEROUPPER (0x77 | P_EXT)
#define OPC_XCHG_ax_r32 (0x90)
-#define OPC_GRP3_Ev (0xf7)
-#define OPC_GRP5 (0xff)
+#define OPC_GRP3_Eb (0xf6)
+#define OPC_GRP3_Ev (0xf7)
+#define OPC_GRP5 (0xff)
#define OPC_GRP14 (0x73 | P_EXT | P_DATA16)
/* Group 1 opcode extensions for 0x80-0x83.
@@ -444,6 +446,7 @@
#define SHIFT_SAR 7
/* Group 3 opcode extensions for 0xf6, 0xf7. To be used with OPC_GRP3. */
+#define EXT3_TESTi 0
#define EXT3_NOT 2
#define EXT3_NEG 3
#define EXT3_MUL 4
@@ -1606,8 +1609,6 @@
}
#if defined(CONFIG_SOFTMMU)
-#include "../tcg-ldst.c.inc"
-
/* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr,
* int mmu_idx, uintptr_t ra)
*/
@@ -1916,7 +1917,84 @@
tcg_out_jmp(s, qemu_st_helpers[opc & (MO_BSWAP | MO_SIZE)]);
return true;
}
-#elif TCG_TARGET_REG_BITS == 32
+#else
+
+static void tcg_out_test_alignment(TCGContext *s, bool is_ld, TCGReg addrlo,
+ TCGReg addrhi, unsigned a_bits)
+{
+ unsigned a_mask = (1 << a_bits) - 1;
+ TCGLabelQemuLdst *label;
+
+ /*
+ * We are expecting a_bits to max out at 7, so we can usually use testb.
+ * For i686, we have to use testl for %esi/%edi.
+ */
+ if (a_mask <= 0xff && (TCG_TARGET_REG_BITS == 64 || addrlo < 4)) {
+ tcg_out_modrm(s, OPC_GRP3_Eb | P_REXB_RM, EXT3_TESTi, addrlo);
+ tcg_out8(s, a_mask);
+ } else {
+ tcg_out_modrm(s, OPC_GRP3_Ev, EXT3_TESTi, addrlo);
+ tcg_out32(s, a_mask);
+ }
+
+ /* jne slow_path */
+ tcg_out_opc(s, OPC_JCC_long + JCC_JNE, 0, 0, 0);
+
+ label = new_ldst_label(s);
+ label->is_ld = is_ld;
+ label->addrlo_reg = addrlo;
+ label->addrhi_reg = addrhi;
+ label->raddr = tcg_splitwx_to_rx(s->code_ptr + 4);
+ label->label_ptr[0] = s->code_ptr;
+
+ s->code_ptr += 4;
+}
+
+static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ /* resolve label address */
+ tcg_patch32(l->label_ptr[0], s->code_ptr - l->label_ptr[0] - 4);
+
+ if (TCG_TARGET_REG_BITS == 32) {
+ int ofs = 0;
+
+ tcg_out_st(s, TCG_TYPE_PTR, TCG_AREG0, TCG_REG_ESP, ofs);
+ ofs += 4;
+
+ tcg_out_st(s, TCG_TYPE_I32, l->addrlo_reg, TCG_REG_ESP, ofs);
+ ofs += 4;
+ if (TARGET_LONG_BITS == 64) {
+ tcg_out_st(s, TCG_TYPE_I32, l->addrhi_reg, TCG_REG_ESP, ofs);
+ ofs += 4;
+ }
+
+ tcg_out_pushi(s, (uintptr_t)l->raddr);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_TL, tcg_target_call_iarg_regs[1],
+ l->addrlo_reg);
+ tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], TCG_AREG0);
+
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RAX, (uintptr_t)l->raddr);
+ tcg_out_push(s, TCG_REG_RAX);
+ }
+
+ /* "Tail call" to the helper, with the return address back inline. */
+ tcg_out_jmp(s, (const void *)(l->is_ld ? helper_unaligned_ld
+ : helper_unaligned_st));
+ return true;
+}
+
+static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
+
+static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
+
+#if TCG_TARGET_REG_BITS == 32
# define x86_guest_base_seg 0
# define x86_guest_base_index -1
# define x86_guest_base_offset guest_base
@@ -1950,6 +2028,7 @@
return 0;
}
# endif
+#endif
#endif /* SOFTMMU */
static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg datalo, TCGReg datahi,
@@ -2059,6 +2138,8 @@
#if defined(CONFIG_SOFTMMU)
int mem_index;
tcg_insn_unit *label_ptr[2];
+#else
+ unsigned a_bits;
#endif
datalo = *args++;
@@ -2081,6 +2162,11 @@
add_qemu_ldst_label(s, true, is64, oi, datalo, datahi, addrlo, addrhi,
s->code_ptr, label_ptr);
#else
+ a_bits = get_alignment_bits(opc);
+ if (a_bits) {
+ tcg_out_test_alignment(s, true, addrlo, addrhi, a_bits);
+ }
+
tcg_out_qemu_ld_direct(s, datalo, datahi, addrlo, x86_guest_base_index,
x86_guest_base_offset, x86_guest_base_seg,
is64, opc);
@@ -2148,6 +2234,8 @@
#if defined(CONFIG_SOFTMMU)
int mem_index;
tcg_insn_unit *label_ptr[2];
+#else
+ unsigned a_bits;
#endif
datalo = *args++;
@@ -2170,6 +2258,11 @@
add_qemu_ldst_label(s, false, is64, oi, datalo, datahi, addrlo, addrhi,
s->code_ptr, label_ptr);
#else
+ a_bits = get_alignment_bits(opc);
+ if (a_bits) {
+ tcg_out_test_alignment(s, false, addrlo, addrhi, a_bits);
+ }
+
tcg_out_qemu_st_direct(s, datalo, datahi, addrlo, x86_guest_base_index,
x86_guest_base_offset, x86_guest_base_seg, opc);
#endif
diff --git a/tcg/i386/tcg-target.h b/tcg/i386/tcg-target.h
index b00a6da..3b2c943 100644
--- a/tcg/i386/tcg-target.h
+++ b/tcg/i386/tcg-target.h
@@ -232,9 +232,7 @@
#define TCG_TARGET_HAS_MEMORY_BSWAP have_movbe
-#ifdef CONFIG_SOFTMMU
#define TCG_TARGET_NEED_LDST_LABELS
-#endif
#define TCG_TARGET_NEED_POOL_LABELS
#endif
diff --git a/tcg/loongarch64/tcg-target.c.inc b/tcg/loongarch64/tcg-target.c.inc
index 9cd46c9..a3debf6 100644
--- a/tcg/loongarch64/tcg-target.c.inc
+++ b/tcg/loongarch64/tcg-target.c.inc
@@ -29,6 +29,8 @@
* THE SOFTWARE.
*/
+#include "../tcg-ldst.c.inc"
+
#ifdef CONFIG_DEBUG_TCG
static const char * const tcg_target_reg_names[TCG_TARGET_NB_REGS] = {
"zero",
@@ -642,8 +644,6 @@
*/
#if defined(CONFIG_SOFTMMU)
-#include "../tcg-ldst.c.inc"
-
/*
* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr,
* MemOpIdx oi, uintptr_t ra)
@@ -825,6 +825,61 @@
return tcg_out_goto(s, l->raddr);
}
+#else
+
+/*
+ * Alignment helpers for user-mode emulation
+ */
+
+static void tcg_out_test_alignment(TCGContext *s, bool is_ld, TCGReg addr_reg,
+ unsigned a_bits)
+{
+ TCGLabelQemuLdst *l = new_ldst_label(s);
+
+ l->is_ld = is_ld;
+ l->addrlo_reg = addr_reg;
+
+ /*
+ * Without micro-architecture details, we don't know which of bstrpick or
+ * andi is faster, so use bstrpick as it's not constrained by imm field
+ * width. (Not to say alignments >= 2^12 are going to happen any time
+ * soon, though)
+ */
+ tcg_out_opc_bstrpick_d(s, TCG_REG_TMP1, addr_reg, 0, a_bits - 1);
+
+ l->label_ptr[0] = s->code_ptr;
+ tcg_out_opc_bne(s, TCG_REG_TMP1, TCG_REG_ZERO, 0);
+
+ l->raddr = tcg_splitwx_to_rx(s->code_ptr);
+}
+
+static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ /* resolve label address */
+ if (!reloc_br_sk16(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) {
+ return false;
+ }
+
+ tcg_out_mov(s, TCG_TYPE_TL, TCG_REG_A1, l->addrlo_reg);
+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A0, TCG_AREG0);
+
+ /* tail call, with the return address back inline. */
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RA, (uintptr_t)l->raddr);
+ tcg_out_call_int(s, (const void *)(l->is_ld ? helper_unaligned_ld
+ : helper_unaligned_st), true);
+ return true;
+}
+
+static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
+
+static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
+
#endif /* CONFIG_SOFTMMU */
/*
@@ -871,7 +926,7 @@
case MO_SL:
tcg_out_opc_ldx_w(s, rd, rj, rk);
break;
- case MO_Q:
+ case MO_UQ:
tcg_out_opc_ldx_d(s, rd, rj, rk);
break;
default:
@@ -887,6 +942,8 @@
MemOp opc;
#if defined(CONFIG_SOFTMMU)
tcg_insn_unit *label_ptr[1];
+#else
+ unsigned a_bits;
#endif
TCGReg base;
@@ -903,6 +960,10 @@
data_regl, addr_regl,
s->code_ptr, label_ptr);
#else
+ a_bits = get_alignment_bits(opc);
+ if (a_bits) {
+ tcg_out_test_alignment(s, true, addr_regl, a_bits);
+ }
base = tcg_out_zext_addr_if_32_bit(s, addr_regl, TCG_REG_TMP0);
TCGReg guest_base_reg = USE_GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_ZERO;
tcg_out_qemu_ld_indexed(s, data_regl, base, guest_base_reg, opc, type);
@@ -941,6 +1002,8 @@
MemOp opc;
#if defined(CONFIG_SOFTMMU)
tcg_insn_unit *label_ptr[1];
+#else
+ unsigned a_bits;
#endif
TCGReg base;
@@ -958,6 +1021,10 @@
data_regl, addr_regl,
s->code_ptr, label_ptr);
#else
+ a_bits = get_alignment_bits(opc);
+ if (a_bits) {
+ tcg_out_test_alignment(s, false, addr_regl, a_bits);
+ }
base = tcg_out_zext_addr_if_32_bit(s, addr_regl, TCG_REG_TMP0);
TCGReg guest_base_reg = USE_GUEST_BASE ? TCG_GUEST_BASE_REG : TCG_REG_ZERO;
tcg_out_qemu_st_indexed(s, data_regl, base, guest_base_reg, opc);
diff --git a/tcg/loongarch64/tcg-target.h b/tcg/loongarch64/tcg-target.h
index 0501080..d58a616 100644
--- a/tcg/loongarch64/tcg-target.h
+++ b/tcg/loongarch64/tcg-target.h
@@ -171,9 +171,7 @@
#define TCG_TARGET_DEFAULT_MO (0)
-#ifdef CONFIG_SOFTMMU
#define TCG_TARGET_NEED_LDST_LABELS
-#endif
#define TCG_TARGET_HAS_MEMORY_BSWAP 0
diff --git a/tcg/mips/tcg-target.c.inc b/tcg/mips/tcg-target.c.inc
index 27b020e..993149d 100644
--- a/tcg/mips/tcg-target.c.inc
+++ b/tcg/mips/tcg-target.c.inc
@@ -24,6 +24,8 @@
* THE SOFTWARE.
*/
+#include "../tcg-ldst.c.inc"
+
#ifdef HOST_WORDS_BIGENDIAN
# define MIPS_BE 1
#else
@@ -230,16 +232,26 @@
OPC_ORI = 015 << 26,
OPC_XORI = 016 << 26,
OPC_LUI = 017 << 26,
+ OPC_BNEL = 025 << 26,
+ OPC_BNEZALC_R6 = 030 << 26,
OPC_DADDIU = 031 << 26,
+ OPC_LDL = 032 << 26,
+ OPC_LDR = 033 << 26,
OPC_LB = 040 << 26,
OPC_LH = 041 << 26,
+ OPC_LWL = 042 << 26,
OPC_LW = 043 << 26,
OPC_LBU = 044 << 26,
OPC_LHU = 045 << 26,
+ OPC_LWR = 046 << 26,
OPC_LWU = 047 << 26,
OPC_SB = 050 << 26,
OPC_SH = 051 << 26,
+ OPC_SWL = 052 << 26,
OPC_SW = 053 << 26,
+ OPC_SDL = 054 << 26,
+ OPC_SDR = 055 << 26,
+ OPC_SWR = 056 << 26,
OPC_LD = 067 << 26,
OPC_SD = 077 << 26,
@@ -1015,8 +1027,6 @@
}
#if defined(CONFIG_SOFTMMU)
-#include "../tcg-ldst.c.inc"
-
static void * const qemu_ld_helpers[(MO_SSIZE | MO_BSWAP) + 1] = {
[MO_UB] = helper_ret_ldub_mmu,
[MO_SB] = helper_ret_ldsb_mmu,
@@ -1124,8 +1134,10 @@
tcg_insn_unit *label_ptr[2], bool is_load)
{
MemOp opc = get_memop(oi);
- unsigned s_bits = opc & MO_SIZE;
unsigned a_bits = get_alignment_bits(opc);
+ unsigned s_bits = opc & MO_SIZE;
+ unsigned a_mask = (1 << a_bits) - 1;
+ unsigned s_mask = (1 << s_bits) - 1;
int mem_index = get_mmuidx(oi);
int fast_off = TLB_MASK_TABLE_OFS(mem_index);
int mask_off = fast_off + offsetof(CPUTLBDescFast, mask);
@@ -1133,7 +1145,7 @@
int add_off = offsetof(CPUTLBEntry, addend);
int cmp_off = (is_load ? offsetof(CPUTLBEntry, addr_read)
: offsetof(CPUTLBEntry, addr_write));
- target_ulong mask;
+ target_ulong tlb_mask;
/* Load tlb_mask[mmu_idx] and tlb_table[mmu_idx]. */
tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP0, TCG_AREG0, mask_off);
@@ -1147,27 +1159,13 @@
/* Add the tlb_table pointer, creating the CPUTLBEntry address in TMP3. */
tcg_out_opc_reg(s, ALIAS_PADD, TCG_TMP3, TCG_TMP3, TCG_TMP1);
- /* We don't currently support unaligned accesses.
- We could do so with mips32r6. */
- if (a_bits < s_bits) {
- a_bits = s_bits;
- }
-
- /* Mask the page bits, keeping the alignment bits to compare against. */
- mask = (target_ulong)TARGET_PAGE_MASK | ((1 << a_bits) - 1);
-
/* Load the (low-half) tlb comparator. */
if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
- tcg_out_ld(s, TCG_TYPE_I32, TCG_TMP0, TCG_TMP3, cmp_off + LO_OFF);
- tcg_out_movi(s, TCG_TYPE_I32, TCG_TMP1, mask);
+ tcg_out_ldst(s, OPC_LW, TCG_TMP0, TCG_TMP3, cmp_off + LO_OFF);
} else {
tcg_out_ldst(s, (TARGET_LONG_BITS == 64 ? OPC_LD
: TCG_TARGET_REG_BITS == 64 ? OPC_LWU : OPC_LW),
TCG_TMP0, TCG_TMP3, cmp_off);
- tcg_out_movi(s, TCG_TYPE_TL, TCG_TMP1, mask);
- /* No second compare is required here;
- load the tlb addend for the fast path. */
- tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP2, TCG_TMP3, add_off);
}
/* Zero extend a 32-bit guest address for a 64-bit host. */
@@ -1175,7 +1173,25 @@
tcg_out_ext32u(s, base, addrl);
addrl = base;
}
- tcg_out_opc_reg(s, OPC_AND, TCG_TMP1, TCG_TMP1, addrl);
+
+ /*
+ * Mask the page bits, keeping the alignment bits to compare against.
+ * For unaligned accesses, compare against the end of the access to
+ * verify that it does not cross a page boundary.
+ */
+ tlb_mask = (target_ulong)TARGET_PAGE_MASK | a_mask;
+ tcg_out_movi(s, TCG_TYPE_I32, TCG_TMP1, tlb_mask);
+ if (a_mask >= s_mask) {
+ tcg_out_opc_reg(s, OPC_AND, TCG_TMP1, TCG_TMP1, addrl);
+ } else {
+ tcg_out_opc_imm(s, ALIAS_PADDI, TCG_TMP2, addrl, s_mask - a_mask);
+ tcg_out_opc_reg(s, OPC_AND, TCG_TMP1, TCG_TMP1, TCG_TMP2);
+ }
+
+ if (TCG_TARGET_REG_BITS >= TARGET_LONG_BITS) {
+ /* Load the tlb addend for the fast path. */
+ tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP2, TCG_TMP3, add_off);
+ }
label_ptr[0] = s->code_ptr;
tcg_out_opc_br(s, OPC_BNE, TCG_TMP1, TCG_TMP0);
@@ -1183,7 +1199,7 @@
/* Load and test the high half tlb comparator. */
if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
/* delay slot */
- tcg_out_ld(s, TCG_TYPE_I32, TCG_TMP0, TCG_TMP3, cmp_off + HI_OFF);
+ tcg_out_ldst(s, OPC_LW, TCG_TMP0, TCG_TMP3, cmp_off + HI_OFF);
/* Load the tlb addend for the fast path. */
tcg_out_ld(s, TCG_TYPE_PTR, TCG_TMP2, TCG_TMP3, add_off);
@@ -1324,7 +1340,82 @@
tcg_out_mov(s, TCG_TYPE_PTR, tcg_target_call_iarg_regs[0], TCG_AREG0);
return true;
}
-#endif
+
+#else
+
+static void tcg_out_test_alignment(TCGContext *s, bool is_ld, TCGReg addrlo,
+ TCGReg addrhi, unsigned a_bits)
+{
+ unsigned a_mask = (1 << a_bits) - 1;
+ TCGLabelQemuLdst *l = new_ldst_label(s);
+
+ l->is_ld = is_ld;
+ l->addrlo_reg = addrlo;
+ l->addrhi_reg = addrhi;
+
+ /* We are expecting a_bits to max out at 7, much lower than ANDI. */
+ tcg_debug_assert(a_bits < 16);
+ tcg_out_opc_imm(s, OPC_ANDI, TCG_TMP0, addrlo, a_mask);
+
+ l->label_ptr[0] = s->code_ptr;
+ if (use_mips32r6_instructions) {
+ tcg_out_opc_br(s, OPC_BNEZALC_R6, TCG_REG_ZERO, TCG_TMP0);
+ } else {
+ tcg_out_opc_br(s, OPC_BNEL, TCG_TMP0, TCG_REG_ZERO);
+ tcg_out_nop(s);
+ }
+
+ l->raddr = tcg_splitwx_to_rx(s->code_ptr);
+}
+
+static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ void *target;
+
+ if (!reloc_pc16(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) {
+ return false;
+ }
+
+ if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
+ /* A0 is env, A1 is skipped, A2:A3 is the uint64_t address. */
+ TCGReg a2 = MIPS_BE ? l->addrhi_reg : l->addrlo_reg;
+ TCGReg a3 = MIPS_BE ? l->addrlo_reg : l->addrhi_reg;
+
+ if (a3 != TCG_REG_A2) {
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_A2, a2);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_A3, a3);
+ } else if (a2 != TCG_REG_A3) {
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_A3, a3);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_A2, a2);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_TMP0, TCG_REG_A2);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_A2, TCG_REG_A3);
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_A3, TCG_TMP0);
+ }
+ } else {
+ tcg_out_mov(s, TCG_TYPE_TL, TCG_REG_A1, l->addrlo_reg);
+ }
+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A0, TCG_AREG0);
+
+ /*
+ * Tail call to the helper, with the return address back inline.
+ * We have arrived here via BNEL, so $31 is already set.
+ */
+ target = (l->is_ld ? helper_unaligned_ld : helper_unaligned_st);
+ tcg_out_call_int(s, target, true);
+ return true;
+}
+
+static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
+
+static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
+#endif /* SOFTMMU */
static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg lo, TCGReg hi,
TCGReg base, MemOp opc, bool is_64)
@@ -1430,6 +1521,126 @@
}
}
+static void tcg_out_qemu_ld_unalign(TCGContext *s, TCGReg lo, TCGReg hi,
+ TCGReg base, MemOp opc, bool is_64)
+{
+ const MIPSInsn lw1 = MIPS_BE ? OPC_LWL : OPC_LWR;
+ const MIPSInsn lw2 = MIPS_BE ? OPC_LWR : OPC_LWL;
+ const MIPSInsn ld1 = MIPS_BE ? OPC_LDL : OPC_LDR;
+ const MIPSInsn ld2 = MIPS_BE ? OPC_LDR : OPC_LDL;
+
+ bool sgn = (opc & MO_SIGN);
+
+ switch (opc & (MO_SSIZE | MO_BSWAP)) {
+ case MO_SW | MO_BE:
+ case MO_UW | MO_BE:
+ tcg_out_opc_imm(s, sgn ? OPC_LB : OPC_LBU, TCG_TMP0, base, 0);
+ tcg_out_opc_imm(s, OPC_LBU, lo, base, 1);
+ if (use_mips32r2_instructions) {
+ tcg_out_opc_bf(s, OPC_INS, lo, TCG_TMP0, 31, 8);
+ } else {
+ tcg_out_opc_sa(s, OPC_SLL, TCG_TMP0, TCG_TMP0, 8);
+ tcg_out_opc_reg(s, OPC_OR, lo, TCG_TMP0, TCG_TMP1);
+ }
+ break;
+
+ case MO_SW | MO_LE:
+ case MO_UW | MO_LE:
+ if (use_mips32r2_instructions && lo != base) {
+ tcg_out_opc_imm(s, OPC_LBU, lo, base, 0);
+ tcg_out_opc_imm(s, sgn ? OPC_LB : OPC_LBU, TCG_TMP0, base, 1);
+ tcg_out_opc_bf(s, OPC_INS, lo, TCG_TMP0, 31, 8);
+ } else {
+ tcg_out_opc_imm(s, OPC_LBU, TCG_TMP0, base, 0);
+ tcg_out_opc_imm(s, sgn ? OPC_LB : OPC_LBU, TCG_TMP1, base, 1);
+ tcg_out_opc_sa(s, OPC_SLL, TCG_TMP1, TCG_TMP1, 8);
+ tcg_out_opc_reg(s, OPC_OR, lo, TCG_TMP0, TCG_TMP1);
+ }
+ break;
+
+ case MO_SL:
+ case MO_UL:
+ tcg_out_opc_imm(s, lw1, lo, base, 0);
+ tcg_out_opc_imm(s, lw2, lo, base, 3);
+ if (TCG_TARGET_REG_BITS == 64 && is_64 && !sgn) {
+ tcg_out_ext32u(s, lo, lo);
+ }
+ break;
+
+ case MO_UL | MO_BSWAP:
+ case MO_SL | MO_BSWAP:
+ if (use_mips32r2_instructions) {
+ tcg_out_opc_imm(s, lw1, lo, base, 0);
+ tcg_out_opc_imm(s, lw2, lo, base, 3);
+ tcg_out_bswap32(s, lo, lo,
+ TCG_TARGET_REG_BITS == 64 && is_64
+ ? (sgn ? TCG_BSWAP_OS : TCG_BSWAP_OZ) : 0);
+ } else {
+ const tcg_insn_unit *subr =
+ (TCG_TARGET_REG_BITS == 64 && is_64 && !sgn
+ ? bswap32u_addr : bswap32_addr);
+
+ tcg_out_opc_imm(s, lw1, TCG_TMP0, base, 0);
+ tcg_out_bswap_subr(s, subr);
+ /* delay slot */
+ tcg_out_opc_imm(s, lw2, TCG_TMP0, base, 3);
+ tcg_out_mov(s, is_64 ? TCG_TYPE_I64 : TCG_TYPE_I32, lo, TCG_TMP3);
+ }
+ break;
+
+ case MO_UQ:
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_out_opc_imm(s, ld1, lo, base, 0);
+ tcg_out_opc_imm(s, ld2, lo, base, 7);
+ } else {
+ tcg_out_opc_imm(s, lw1, MIPS_BE ? hi : lo, base, 0 + 0);
+ tcg_out_opc_imm(s, lw2, MIPS_BE ? hi : lo, base, 0 + 3);
+ tcg_out_opc_imm(s, lw1, MIPS_BE ? lo : hi, base, 4 + 0);
+ tcg_out_opc_imm(s, lw2, MIPS_BE ? lo : hi, base, 4 + 3);
+ }
+ break;
+
+ case MO_UQ | MO_BSWAP:
+ if (TCG_TARGET_REG_BITS == 64) {
+ if (use_mips32r2_instructions) {
+ tcg_out_opc_imm(s, ld1, lo, base, 0);
+ tcg_out_opc_imm(s, ld2, lo, base, 7);
+ tcg_out_bswap64(s, lo, lo);
+ } else {
+ tcg_out_opc_imm(s, ld1, TCG_TMP0, base, 0);
+ tcg_out_bswap_subr(s, bswap64_addr);
+ /* delay slot */
+ tcg_out_opc_imm(s, ld2, TCG_TMP0, base, 7);
+ tcg_out_mov(s, TCG_TYPE_I64, lo, TCG_TMP3);
+ }
+ } else if (use_mips32r2_instructions) {
+ tcg_out_opc_imm(s, lw1, TCG_TMP0, base, 0 + 0);
+ tcg_out_opc_imm(s, lw2, TCG_TMP0, base, 0 + 3);
+ tcg_out_opc_imm(s, lw1, TCG_TMP1, base, 4 + 0);
+ tcg_out_opc_imm(s, lw2, TCG_TMP1, base, 4 + 3);
+ tcg_out_opc_reg(s, OPC_WSBH, TCG_TMP0, 0, TCG_TMP0);
+ tcg_out_opc_reg(s, OPC_WSBH, TCG_TMP1, 0, TCG_TMP1);
+ tcg_out_opc_sa(s, OPC_ROTR, MIPS_BE ? lo : hi, TCG_TMP0, 16);
+ tcg_out_opc_sa(s, OPC_ROTR, MIPS_BE ? hi : lo, TCG_TMP1, 16);
+ } else {
+ tcg_out_opc_imm(s, lw1, TCG_TMP0, base, 0 + 0);
+ tcg_out_bswap_subr(s, bswap32_addr);
+ /* delay slot */
+ tcg_out_opc_imm(s, lw2, TCG_TMP0, base, 0 + 3);
+ tcg_out_opc_imm(s, lw1, TCG_TMP0, base, 4 + 0);
+ tcg_out_mov(s, TCG_TYPE_I32, MIPS_BE ? lo : hi, TCG_TMP3);
+ tcg_out_bswap_subr(s, bswap32_addr);
+ /* delay slot */
+ tcg_out_opc_imm(s, lw2, TCG_TMP0, base, 4 + 3);
+ tcg_out_mov(s, TCG_TYPE_I32, MIPS_BE ? hi : lo, TCG_TMP3);
+ }
+ break;
+
+ default:
+ g_assert_not_reached();
+ }
+}
+
static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
{
TCGReg addr_regl, addr_regh __attribute__((unused));
@@ -1438,7 +1649,9 @@
MemOp opc;
#if defined(CONFIG_SOFTMMU)
tcg_insn_unit *label_ptr[2];
+#else
#endif
+ unsigned a_bits, s_bits;
TCGReg base = TCG_REG_A0;
data_regl = *args++;
@@ -1447,10 +1660,20 @@
addr_regh = (TCG_TARGET_REG_BITS < TARGET_LONG_BITS ? *args++ : 0);
oi = *args++;
opc = get_memop(oi);
+ a_bits = get_alignment_bits(opc);
+ s_bits = opc & MO_SIZE;
+ /*
+ * R6 removes the left/right instructions but requires the
+ * system to support misaligned memory accesses.
+ */
#if defined(CONFIG_SOFTMMU)
tcg_out_tlb_load(s, base, addr_regl, addr_regh, oi, label_ptr, 1);
- tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc, is_64);
+ if (use_mips32r6_instructions || a_bits >= s_bits) {
+ tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc, is_64);
+ } else {
+ tcg_out_qemu_ld_unalign(s, data_regl, data_regh, base, opc, is_64);
+ }
add_qemu_ldst_label(s, 1, oi,
(is_64 ? TCG_TYPE_I64 : TCG_TYPE_I32),
data_regl, data_regh, addr_regl, addr_regh,
@@ -1467,7 +1690,21 @@
} else {
tcg_out_opc_reg(s, ALIAS_PADD, base, TCG_GUEST_BASE_REG, addr_regl);
}
- tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc, is_64);
+ if (use_mips32r6_instructions) {
+ if (a_bits) {
+ tcg_out_test_alignment(s, true, addr_regl, addr_regh, a_bits);
+ }
+ tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc, is_64);
+ } else {
+ if (a_bits && a_bits != s_bits) {
+ tcg_out_test_alignment(s, true, addr_regl, addr_regh, a_bits);
+ }
+ if (a_bits >= s_bits) {
+ tcg_out_qemu_ld_direct(s, data_regl, data_regh, base, opc, is_64);
+ } else {
+ tcg_out_qemu_ld_unalign(s, data_regl, data_regh, base, opc, is_64);
+ }
+ }
#endif
}
@@ -1532,6 +1769,78 @@
}
}
+static void tcg_out_qemu_st_unalign(TCGContext *s, TCGReg lo, TCGReg hi,
+ TCGReg base, MemOp opc)
+{
+ const MIPSInsn sw1 = MIPS_BE ? OPC_SWL : OPC_SWR;
+ const MIPSInsn sw2 = MIPS_BE ? OPC_SWR : OPC_SWL;
+ const MIPSInsn sd1 = MIPS_BE ? OPC_SDL : OPC_SDR;
+ const MIPSInsn sd2 = MIPS_BE ? OPC_SDR : OPC_SDL;
+
+ /* Don't clutter the code below with checks to avoid bswapping ZERO. */
+ if ((lo | hi) == 0) {
+ opc &= ~MO_BSWAP;
+ }
+
+ switch (opc & (MO_SIZE | MO_BSWAP)) {
+ case MO_16 | MO_BE:
+ tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, lo, 8);
+ tcg_out_opc_imm(s, OPC_SB, TCG_TMP0, base, 0);
+ tcg_out_opc_imm(s, OPC_SB, lo, base, 1);
+ break;
+
+ case MO_16 | MO_LE:
+ tcg_out_opc_sa(s, OPC_SRL, TCG_TMP0, lo, 8);
+ tcg_out_opc_imm(s, OPC_SB, lo, base, 0);
+ tcg_out_opc_imm(s, OPC_SB, TCG_TMP0, base, 1);
+ break;
+
+ case MO_32 | MO_BSWAP:
+ tcg_out_bswap32(s, TCG_TMP3, lo, 0);
+ lo = TCG_TMP3;
+ /* fall through */
+ case MO_32:
+ tcg_out_opc_imm(s, sw1, lo, base, 0);
+ tcg_out_opc_imm(s, sw2, lo, base, 3);
+ break;
+
+ case MO_64 | MO_BSWAP:
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_out_bswap64(s, TCG_TMP3, lo);
+ lo = TCG_TMP3;
+ } else if (use_mips32r2_instructions) {
+ tcg_out_opc_reg(s, OPC_WSBH, TCG_TMP0, 0, MIPS_BE ? hi : lo);
+ tcg_out_opc_reg(s, OPC_WSBH, TCG_TMP1, 0, MIPS_BE ? lo : hi);
+ tcg_out_opc_sa(s, OPC_ROTR, TCG_TMP0, TCG_TMP0, 16);
+ tcg_out_opc_sa(s, OPC_ROTR, TCG_TMP1, TCG_TMP1, 16);
+ hi = MIPS_BE ? TCG_TMP0 : TCG_TMP1;
+ lo = MIPS_BE ? TCG_TMP1 : TCG_TMP0;
+ } else {
+ tcg_out_bswap32(s, TCG_TMP3, MIPS_BE ? lo : hi, 0);
+ tcg_out_opc_imm(s, sw1, TCG_TMP3, base, 0 + 0);
+ tcg_out_opc_imm(s, sw2, TCG_TMP3, base, 0 + 3);
+ tcg_out_bswap32(s, TCG_TMP3, MIPS_BE ? hi : lo, 0);
+ tcg_out_opc_imm(s, sw1, TCG_TMP3, base, 4 + 0);
+ tcg_out_opc_imm(s, sw2, TCG_TMP3, base, 4 + 3);
+ break;
+ }
+ /* fall through */
+ case MO_64:
+ if (TCG_TARGET_REG_BITS == 64) {
+ tcg_out_opc_imm(s, sd1, lo, base, 0);
+ tcg_out_opc_imm(s, sd2, lo, base, 7);
+ } else {
+ tcg_out_opc_imm(s, sw1, MIPS_BE ? hi : lo, base, 0 + 0);
+ tcg_out_opc_imm(s, sw2, MIPS_BE ? hi : lo, base, 0 + 3);
+ tcg_out_opc_imm(s, sw1, MIPS_BE ? lo : hi, base, 4 + 0);
+ tcg_out_opc_imm(s, sw2, MIPS_BE ? lo : hi, base, 4 + 3);
+ }
+ break;
+
+ default:
+ tcg_abort();
+ }
+}
static void tcg_out_qemu_st(TCGContext *s, const TCGArg *args, bool is_64)
{
TCGReg addr_regl, addr_regh __attribute__((unused));
@@ -1541,6 +1850,7 @@
#if defined(CONFIG_SOFTMMU)
tcg_insn_unit *label_ptr[2];
#endif
+ unsigned a_bits, s_bits;
TCGReg base = TCG_REG_A0;
data_regl = *args++;
@@ -1549,16 +1859,25 @@
addr_regh = (TCG_TARGET_REG_BITS < TARGET_LONG_BITS ? *args++ : 0);
oi = *args++;
opc = get_memop(oi);
+ a_bits = get_alignment_bits(opc);
+ s_bits = opc & MO_SIZE;
+ /*
+ * R6 removes the left/right instructions but requires the
+ * system to support misaligned memory accesses.
+ */
#if defined(CONFIG_SOFTMMU)
tcg_out_tlb_load(s, base, addr_regl, addr_regh, oi, label_ptr, 0);
- tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc);
+ if (use_mips32r6_instructions || a_bits >= s_bits) {
+ tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc);
+ } else {
+ tcg_out_qemu_st_unalign(s, data_regl, data_regh, base, opc);
+ }
add_qemu_ldst_label(s, 0, oi,
(is_64 ? TCG_TYPE_I64 : TCG_TYPE_I32),
data_regl, data_regh, addr_regl, addr_regh,
s->code_ptr, label_ptr);
#else
- base = TCG_REG_A0;
if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) {
tcg_out_ext32u(s, base, addr_regl);
addr_regl = base;
@@ -1570,7 +1889,21 @@
} else {
tcg_out_opc_reg(s, ALIAS_PADD, base, TCG_GUEST_BASE_REG, addr_regl);
}
- tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc);
+ if (use_mips32r6_instructions) {
+ if (a_bits) {
+ tcg_out_test_alignment(s, true, addr_regl, addr_regh, a_bits);
+ }
+ tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc);
+ } else {
+ if (a_bits && a_bits != s_bits) {
+ tcg_out_test_alignment(s, true, addr_regl, addr_regh, a_bits);
+ }
+ if (a_bits >= s_bits) {
+ tcg_out_qemu_st_direct(s, data_regl, data_regh, base, opc);
+ } else {
+ tcg_out_qemu_st_unalign(s, data_regl, data_regh, base, opc);
+ }
+ }
#endif
}
diff --git a/tcg/mips/tcg-target.h b/tcg/mips/tcg-target.h
index c366fdf..7669213 100644
--- a/tcg/mips/tcg-target.h
+++ b/tcg/mips/tcg-target.h
@@ -207,8 +207,6 @@
void tb_target_set_jmp_target(uintptr_t, uintptr_t, uintptr_t, uintptr_t)
QEMU_ERROR("code path is reachable");
-#ifdef CONFIG_SOFTMMU
#define TCG_TARGET_NEED_LDST_LABELS
-#endif
#endif
diff --git a/tcg/ppc/tcg-target.c.inc b/tcg/ppc/tcg-target.c.inc
index 9e79a7e..dea24f2 100644
--- a/tcg/ppc/tcg-target.c.inc
+++ b/tcg/ppc/tcg-target.c.inc
@@ -24,6 +24,7 @@
#include "elf.h"
#include "../tcg-pool.c.inc"
+#include "../tcg-ldst.c.inc"
/*
* Standardize on the _CALL_FOO symbols used by GCC:
@@ -1881,7 +1882,8 @@
}
}
-static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target)
+static void tcg_out_call_int(TCGContext *s, int lk,
+ const tcg_insn_unit *target)
{
#ifdef _CALL_AIX
/* Look through the descriptor. If the branch is in range, and we
@@ -1892,7 +1894,7 @@
if (in_range_b(diff) && toc == (uint32_t)toc) {
tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_TMP1, toc);
- tcg_out_b(s, LK, tgt);
+ tcg_out_b(s, lk, tgt);
} else {
/* Fold the low bits of the constant into the addresses below. */
intptr_t arg = (intptr_t)target;
@@ -1907,7 +1909,7 @@
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R0, TCG_REG_TMP1, ofs);
tcg_out32(s, MTSPR | RA(TCG_REG_R0) | CTR);
tcg_out_ld(s, TCG_TYPE_PTR, TCG_REG_R2, TCG_REG_TMP1, ofs + SZP);
- tcg_out32(s, BCCTR | BO_ALWAYS | LK);
+ tcg_out32(s, BCCTR | BO_ALWAYS | lk);
}
#elif defined(_CALL_ELF) && _CALL_ELF == 2
intptr_t diff;
@@ -1921,16 +1923,21 @@
diff = tcg_pcrel_diff(s, target);
if (in_range_b(diff)) {
- tcg_out_b(s, LK, target);
+ tcg_out_b(s, lk, target);
} else {
tcg_out32(s, MTSPR | RS(TCG_REG_R12) | CTR);
- tcg_out32(s, BCCTR | BO_ALWAYS | LK);
+ tcg_out32(s, BCCTR | BO_ALWAYS | lk);
}
#else
- tcg_out_b(s, LK, target);
+ tcg_out_b(s, lk, target);
#endif
}
+static void tcg_out_call(TCGContext *s, const tcg_insn_unit *target)
+{
+ tcg_out_call_int(s, LK, target);
+}
+
static const uint32_t qemu_ldx_opc[(MO_SSIZE + MO_BSWAP) + 1] = {
[MO_UB] = LBZX,
[MO_UW] = LHZX,
@@ -1960,8 +1967,6 @@
};
#if defined (CONFIG_SOFTMMU)
-#include "../tcg-ldst.c.inc"
-
/* helper signature: helper_ld_mmu(CPUState *env, target_ulong addr,
* int mmu_idx, uintptr_t ra)
*/
@@ -2227,6 +2232,71 @@
tcg_out_b(s, 0, lb->raddr);
return true;
}
+#else
+
+static void tcg_out_test_alignment(TCGContext *s, bool is_ld, TCGReg addrlo,
+ TCGReg addrhi, unsigned a_bits)
+{
+ unsigned a_mask = (1 << a_bits) - 1;
+ TCGLabelQemuLdst *label = new_ldst_label(s);
+
+ label->is_ld = is_ld;
+ label->addrlo_reg = addrlo;
+ label->addrhi_reg = addrhi;
+
+ /* We are expecting a_bits to max out at 7, much lower than ANDI. */
+ tcg_debug_assert(a_bits < 16);
+ tcg_out32(s, ANDI | SAI(addrlo, TCG_REG_R0, a_mask));
+
+ label->label_ptr[0] = s->code_ptr;
+ tcg_out32(s, BC | BI(0, CR_EQ) | BO_COND_FALSE | LK);
+
+ label->raddr = tcg_splitwx_to_rx(s->code_ptr);
+}
+
+static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ if (!reloc_pc14(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) {
+ return false;
+ }
+
+ if (TCG_TARGET_REG_BITS < TARGET_LONG_BITS) {
+ TCGReg arg = TCG_REG_R4;
+#ifdef TCG_TARGET_CALL_ALIGN_ARGS
+ arg |= 1;
+#endif
+ if (l->addrlo_reg != arg) {
+ tcg_out_mov(s, TCG_TYPE_I32, arg, l->addrhi_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, arg + 1, l->addrlo_reg);
+ } else if (l->addrhi_reg != arg + 1) {
+ tcg_out_mov(s, TCG_TYPE_I32, arg + 1, l->addrlo_reg);
+ tcg_out_mov(s, TCG_TYPE_I32, arg, l->addrhi_reg);
+ } else {
+ tcg_out_mov(s, TCG_TYPE_I32, TCG_REG_R0, arg);
+ tcg_out_mov(s, TCG_TYPE_I32, arg, arg + 1);
+ tcg_out_mov(s, TCG_TYPE_I32, arg + 1, TCG_REG_R0);
+ }
+ } else {
+ tcg_out_mov(s, TCG_TYPE_TL, TCG_REG_R4, l->addrlo_reg);
+ }
+ tcg_out_mov(s, TCG_TYPE_TL, TCG_REG_R3, TCG_AREG0);
+
+ /* "Tail call" to the helper, with the return address back inline. */
+ tcg_out_call_int(s, 0, (const void *)(l->is_ld ? helper_unaligned_ld
+ : helper_unaligned_st));
+ return true;
+}
+
+static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
+
+static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
+
#endif /* SOFTMMU */
static void tcg_out_qemu_ld(TCGContext *s, const TCGArg *args, bool is_64)
@@ -2238,6 +2308,8 @@
#ifdef CONFIG_SOFTMMU
int mem_index;
tcg_insn_unit *label_ptr;
+#else
+ unsigned a_bits;
#endif
datalo = *args++;
@@ -2258,6 +2330,10 @@
rbase = TCG_REG_R3;
#else /* !CONFIG_SOFTMMU */
+ a_bits = get_alignment_bits(opc);
+ if (a_bits) {
+ tcg_out_test_alignment(s, true, addrlo, addrhi, a_bits);
+ }
rbase = guest_base ? TCG_GUEST_BASE_REG : 0;
if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) {
tcg_out_ext32u(s, TCG_REG_TMP1, addrlo);
@@ -2313,6 +2389,8 @@
#ifdef CONFIG_SOFTMMU
int mem_index;
tcg_insn_unit *label_ptr;
+#else
+ unsigned a_bits;
#endif
datalo = *args++;
@@ -2333,6 +2411,10 @@
rbase = TCG_REG_R3;
#else /* !CONFIG_SOFTMMU */
+ a_bits = get_alignment_bits(opc);
+ if (a_bits) {
+ tcg_out_test_alignment(s, false, addrlo, addrhi, a_bits);
+ }
rbase = guest_base ? TCG_GUEST_BASE_REG : 0;
if (TCG_TARGET_REG_BITS > TARGET_LONG_BITS) {
tcg_out_ext32u(s, TCG_REG_TMP1, addrlo);
diff --git a/tcg/ppc/tcg-target.h b/tcg/ppc/tcg-target.h
index 0943192..c775c97 100644
--- a/tcg/ppc/tcg-target.h
+++ b/tcg/ppc/tcg-target.h
@@ -182,9 +182,7 @@
#define TCG_TARGET_DEFAULT_MO (0)
#define TCG_TARGET_HAS_MEMORY_BSWAP 1
-#ifdef CONFIG_SOFTMMU
#define TCG_TARGET_NEED_LDST_LABELS
-#endif
#define TCG_TARGET_NEED_POOL_LABELS
#endif
diff --git a/tcg/riscv/tcg-target.c.inc b/tcg/riscv/tcg-target.c.inc
index e9488f7..6409d9c 100644
--- a/tcg/riscv/tcg-target.c.inc
+++ b/tcg/riscv/tcg-target.c.inc
@@ -27,6 +27,7 @@
* THE SOFTWARE.
*/
+#include "../tcg-ldst.c.inc"
#include "../tcg-pool.c.inc"
#ifdef CONFIG_DEBUG_TCG
@@ -847,8 +848,6 @@
*/
#if defined(CONFIG_SOFTMMU)
-#include "../tcg-ldst.c.inc"
-
/* helper signature: helper_ret_ld_mmu(CPUState *env, target_ulong addr,
* MemOpIdx oi, uintptr_t ra)
*/
@@ -1053,6 +1052,54 @@
tcg_out_goto(s, l->raddr);
return true;
}
+#else
+
+static void tcg_out_test_alignment(TCGContext *s, bool is_ld, TCGReg addr_reg,
+ unsigned a_bits)
+{
+ unsigned a_mask = (1 << a_bits) - 1;
+ TCGLabelQemuLdst *l = new_ldst_label(s);
+
+ l->is_ld = is_ld;
+ l->addrlo_reg = addr_reg;
+
+ /* We are expecting a_bits to max out at 7, so we can always use andi. */
+ tcg_debug_assert(a_bits < 12);
+ tcg_out_opc_imm(s, OPC_ANDI, TCG_REG_TMP1, addr_reg, a_mask);
+
+ l->label_ptr[0] = s->code_ptr;
+ tcg_out_opc_branch(s, OPC_BNE, TCG_REG_TMP1, TCG_REG_ZERO, 0);
+
+ l->raddr = tcg_splitwx_to_rx(s->code_ptr);
+}
+
+static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ /* resolve label address */
+ if (!reloc_sbimm12(l->label_ptr[0], tcg_splitwx_to_rx(s->code_ptr))) {
+ return false;
+ }
+
+ tcg_out_mov(s, TCG_TYPE_TL, TCG_REG_A1, l->addrlo_reg);
+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_A0, TCG_AREG0);
+
+ /* tail call, with the return address back inline. */
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_RA, (uintptr_t)l->raddr);
+ tcg_out_call_int(s, (const void *)(l->is_ld ? helper_unaligned_ld
+ : helper_unaligned_st), true);
+ return true;
+}
+
+static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
+
+static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
+
#endif /* CONFIG_SOFTMMU */
static void tcg_out_qemu_ld_direct(TCGContext *s, TCGReg lo, TCGReg hi,
@@ -1108,6 +1155,8 @@
MemOp opc;
#if defined(CONFIG_SOFTMMU)
tcg_insn_unit *label_ptr[1];
+#else
+ unsigned a_bits;
#endif
TCGReg base = TCG_REG_TMP0;
@@ -1130,6 +1179,10 @@
tcg_out_ext32u(s, base, addr_regl);
addr_regl = base;
}
+ a_bits = get_alignment_bits(opc);
+ if (a_bits) {
+ tcg_out_test_alignment(s, true, addr_regl, a_bits);
+ }
if (guest_base != 0) {
tcg_out_opc_reg(s, OPC_ADD, base, TCG_GUEST_BASE_REG, addr_regl);
}
@@ -1174,6 +1227,8 @@
MemOp opc;
#if defined(CONFIG_SOFTMMU)
tcg_insn_unit *label_ptr[1];
+#else
+ unsigned a_bits;
#endif
TCGReg base = TCG_REG_TMP0;
@@ -1196,6 +1251,10 @@
tcg_out_ext32u(s, base, addr_regl);
addr_regl = base;
}
+ a_bits = get_alignment_bits(opc);
+ if (a_bits) {
+ tcg_out_test_alignment(s, false, addr_regl, a_bits);
+ }
if (guest_base != 0) {
tcg_out_opc_reg(s, OPC_ADD, base, TCG_GUEST_BASE_REG, addr_regl);
}
diff --git a/tcg/riscv/tcg-target.h b/tcg/riscv/tcg-target.h
index ef78b99..11c9b3e 100644
--- a/tcg/riscv/tcg-target.h
+++ b/tcg/riscv/tcg-target.h
@@ -165,9 +165,7 @@
#define TCG_TARGET_DEFAULT_MO (0)
-#ifdef CONFIG_SOFTMMU
#define TCG_TARGET_NEED_LDST_LABELS
-#endif
#define TCG_TARGET_NEED_POOL_LABELS
#define TCG_TARGET_HAS_MEMORY_BSWAP 0
diff --git a/tcg/s390x/tcg-target.c.inc b/tcg/s390x/tcg-target.c.inc
index b12fbfd..d56c1e5 100644
--- a/tcg/s390x/tcg-target.c.inc
+++ b/tcg/s390x/tcg-target.c.inc
@@ -29,6 +29,7 @@
#error "unsupported code generation mode"
#endif
+#include "../tcg-ldst.c.inc"
#include "../tcg-pool.c.inc"
#include "elf.h"
@@ -136,6 +137,7 @@
RI_OIHL = 0xa509,
RI_OILH = 0xa50a,
RI_OILL = 0xa50b,
+ RI_TMLL = 0xa701,
RIE_CGIJ = 0xec7c,
RIE_CGRJ = 0xec64,
@@ -1804,8 +1806,6 @@
}
#if defined(CONFIG_SOFTMMU)
-#include "../tcg-ldst.c.inc"
-
/* We're expecting to use a 20-bit negative offset on the tlb memory ops. */
QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) > 0);
QEMU_BUILD_BUG_ON(TLB_MASK_TABLE_OFS(0) < -(1 << 19));
@@ -1942,6 +1942,53 @@
return true;
}
#else
+static void tcg_out_test_alignment(TCGContext *s, bool is_ld,
+ TCGReg addrlo, unsigned a_bits)
+{
+ unsigned a_mask = (1 << a_bits) - 1;
+ TCGLabelQemuLdst *l = new_ldst_label(s);
+
+ l->is_ld = is_ld;
+ l->addrlo_reg = addrlo;
+
+ /* We are expecting a_bits to max out at 7, much lower than TMLL. */
+ tcg_debug_assert(a_bits < 16);
+ tcg_out_insn(s, RI, TMLL, addrlo, a_mask);
+
+ tcg_out16(s, RI_BRC | (7 << 4)); /* CC in {1,2,3} */
+ l->label_ptr[0] = s->code_ptr;
+ s->code_ptr += 1;
+
+ l->raddr = tcg_splitwx_to_rx(s->code_ptr);
+}
+
+static bool tcg_out_fail_alignment(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ if (!patch_reloc(l->label_ptr[0], R_390_PC16DBL,
+ (intptr_t)tcg_splitwx_to_rx(s->code_ptr), 2)) {
+ return false;
+ }
+
+ tcg_out_mov(s, TCG_TYPE_TL, TCG_REG_R3, l->addrlo_reg);
+ tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_R2, TCG_AREG0);
+
+ /* "Tail call" to the helper, with the return address back inline. */
+ tcg_out_movi(s, TCG_TYPE_PTR, TCG_REG_R14, (uintptr_t)l->raddr);
+ tgen_gotoi(s, S390_CC_ALWAYS, (const void *)(l->is_ld ? helper_unaligned_ld
+ : helper_unaligned_st));
+ return true;
+}
+
+static bool tcg_out_qemu_ld_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
+
+static bool tcg_out_qemu_st_slow_path(TCGContext *s, TCGLabelQemuLdst *l)
+{
+ return tcg_out_fail_alignment(s, l);
+}
+
static void tcg_prepare_user_ldst(TCGContext *s, TCGReg *addr_reg,
TCGReg *index_reg, tcg_target_long *disp)
{
@@ -1980,7 +2027,11 @@
#else
TCGReg index_reg;
tcg_target_long disp;
+ unsigned a_bits = get_alignment_bits(opc);
+ if (a_bits) {
+ tcg_out_test_alignment(s, true, addr_reg, a_bits);
+ }
tcg_prepare_user_ldst(s, &addr_reg, &index_reg, &disp);
tcg_out_qemu_ld_direct(s, opc, data_reg, addr_reg, index_reg, disp);
#endif
@@ -2007,7 +2058,11 @@
#else
TCGReg index_reg;
tcg_target_long disp;
+ unsigned a_bits = get_alignment_bits(opc);
+ if (a_bits) {
+ tcg_out_test_alignment(s, false, addr_reg, a_bits);
+ }
tcg_prepare_user_ldst(s, &addr_reg, &index_reg, &disp);
tcg_out_qemu_st_direct(s, opc, data_reg, addr_reg, index_reg, disp);
#endif
diff --git a/tcg/s390x/tcg-target.h b/tcg/s390x/tcg-target.h
index 527ada0..69217d9 100644
--- a/tcg/s390x/tcg-target.h
+++ b/tcg/s390x/tcg-target.h
@@ -178,9 +178,7 @@
/* no need to flush icache explicitly */
}
-#ifdef CONFIG_SOFTMMU
#define TCG_TARGET_NEED_LDST_LABELS
-#endif
#define TCG_TARGET_NEED_POOL_LABELS
#endif
diff --git a/tcg/sparc/tcg-target.c.inc b/tcg/sparc/tcg-target.c.inc
index 0c062c6..72d9552 100644
--- a/tcg/sparc/tcg-target.c.inc
+++ b/tcg/sparc/tcg-target.c.inc
@@ -211,6 +211,7 @@
#define ARITH_ADD (INSN_OP(2) | INSN_OP3(0x00))
#define ARITH_ADDCC (INSN_OP(2) | INSN_OP3(0x10))
#define ARITH_AND (INSN_OP(2) | INSN_OP3(0x01))
+#define ARITH_ANDCC (INSN_OP(2) | INSN_OP3(0x11))
#define ARITH_ANDN (INSN_OP(2) | INSN_OP3(0x05))
#define ARITH_OR (INSN_OP(2) | INSN_OP3(0x02))
#define ARITH_ORCC (INSN_OP(2) | INSN_OP3(0x12))
@@ -323,15 +324,26 @@
switch (type) {
case R_SPARC_WDISP16:
- assert(check_fit_ptr(pcrel >> 2, 16));
+ if (!check_fit_ptr(pcrel >> 2, 16)) {
+ return false;
+ }
insn &= ~INSN_OFF16(-1);
insn |= INSN_OFF16(pcrel);
break;
case R_SPARC_WDISP19:
- assert(check_fit_ptr(pcrel >> 2, 19));
+ if (!check_fit_ptr(pcrel >> 2, 19)) {
+ return false;
+ }
insn &= ~INSN_OFF19(-1);
insn |= INSN_OFF19(pcrel);
break;
+ case R_SPARC_13:
+ if (!check_fit_ptr(value, 13)) {
+ return false;
+ }
+ insn &= ~INSN_IMM13(-1);
+ insn |= INSN_IMM13(value);
+ break;
default:
g_assert_not_reached();
}
@@ -413,15 +425,31 @@
tcg_out_arithi(s, ret, TCG_REG_G0, arg, ARITH_OR);
}
+static void tcg_out_movi_imm32(TCGContext *s, TCGReg ret, int32_t arg)
+{
+ if (check_fit_i32(arg, 13)) {
+ /* A 13-bit constant sign-extended to 64-bits. */
+ tcg_out_movi_imm13(s, ret, arg);
+ } else {
+ /* A 32-bit constant zero-extended to 64 bits. */
+ tcg_out_sethi(s, ret, arg);
+ if (arg & 0x3ff) {
+ tcg_out_arithi(s, ret, ret, arg & 0x3ff, ARITH_OR);
+ }
+ }
+}
+
static void tcg_out_movi_int(TCGContext *s, TCGType type, TCGReg ret,
- tcg_target_long arg, bool in_prologue)
+ tcg_target_long arg, bool in_prologue,
+ TCGReg scratch)
{
tcg_target_long hi, lo = (int32_t)arg;
tcg_target_long test, lsb;
- /* Make sure we test 32-bit constants for imm13 properly. */
- if (type == TCG_TYPE_I32) {
- arg = lo;
+ /* A 32-bit constant, or 32-bit zero-extended to 64-bits. */
+ if (type == TCG_TYPE_I32 || arg == (uint32_t)arg) {
+ tcg_out_movi_imm32(s, ret, arg);
+ return;
}
/* A 13-bit constant sign-extended to 64-bits. */
@@ -439,15 +467,6 @@
}
}
- /* A 32-bit constant, or 32-bit zero-extended to 64-bits. */
- if (type == TCG_TYPE_I32 || arg == (uint32_t)arg) {
- tcg_out_sethi(s, ret, arg);
- if (arg & 0x3ff) {
- tcg_out_arithi(s, ret, ret, arg & 0x3ff, ARITH_OR);
- }
- return;
- }
-
/* A 32-bit constant sign-extended to 64-bits. */
if (arg == lo) {
tcg_out_sethi(s, ret, ~arg);
@@ -455,38 +474,47 @@
return;
}
- /* A 21-bit constant, shifted. */
+ /* A 32-bit constant, shifted. */
lsb = ctz64(arg);
test = (tcg_target_long)arg >> lsb;
- if (check_fit_tl(test, 13)) {
- tcg_out_movi_imm13(s, ret, test);
- tcg_out_arithi(s, ret, ret, lsb, SHIFT_SLLX);
- return;
- } else if (lsb > 10 && test == extract64(test, 0, 21)) {
+ if (lsb > 10 && test == extract64(test, 0, 21)) {
tcg_out_sethi(s, ret, test << 10);
tcg_out_arithi(s, ret, ret, lsb - 10, SHIFT_SLLX);
return;
+ } else if (test == (uint32_t)test || test == (int32_t)test) {
+ tcg_out_movi_int(s, TCG_TYPE_I64, ret, test, in_prologue, scratch);
+ tcg_out_arithi(s, ret, ret, lsb, SHIFT_SLLX);
+ return;
+ }
+
+ /* Use the constant pool, if possible. */
+ if (!in_prologue && USE_REG_TB) {
+ new_pool_label(s, arg, R_SPARC_13, s->code_ptr,
+ tcg_tbrel_diff(s, NULL));
+ tcg_out32(s, LDX | INSN_RD(ret) | INSN_RS1(TCG_REG_TB));
+ return;
}
/* A 64-bit constant decomposed into 2 32-bit pieces. */
if (check_fit_i32(lo, 13)) {
hi = (arg - lo) >> 32;
- tcg_out_movi(s, TCG_TYPE_I32, ret, hi);
+ tcg_out_movi_imm32(s, ret, hi);
tcg_out_arithi(s, ret, ret, 32, SHIFT_SLLX);
tcg_out_arithi(s, ret, ret, lo, ARITH_ADD);
} else {
hi = arg >> 32;
- tcg_out_movi(s, TCG_TYPE_I32, ret, hi);
- tcg_out_movi(s, TCG_TYPE_I32, TCG_REG_T2, lo);
+ tcg_out_movi_imm32(s, ret, hi);
+ tcg_out_movi_imm32(s, scratch, lo);
tcg_out_arithi(s, ret, ret, 32, SHIFT_SLLX);
- tcg_out_arith(s, ret, ret, TCG_REG_T2, ARITH_OR);
+ tcg_out_arith(s, ret, ret, scratch, ARITH_OR);
}
}
static void tcg_out_movi(TCGContext *s, TCGType type,
TCGReg ret, tcg_target_long arg)
{
- tcg_out_movi_int(s, type, ret, arg, false);
+ tcg_debug_assert(ret != TCG_REG_T2);
+ tcg_out_movi_int(s, type, ret, arg, false, TCG_REG_T2);
}
static void tcg_out_ldst_rr(TCGContext *s, TCGReg data, TCGReg a1,
@@ -795,7 +823,7 @@
if (use_vis3_instructions && !is_sub) {
/* Note that ADDXC doesn't accept immediates. */
if (bhconst && bh != 0) {
- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_T2, bh);
+ tcg_out_movi_imm13(s, TCG_REG_T2, bh);
bh = TCG_REG_T2;
}
tcg_out_arith(s, rh, ah, bh, ARITH_ADDXC);
@@ -811,9 +839,13 @@
tcg_out_movcc(s, TCG_COND_GEU, MOVCC_XCC, rh, ah, 0);
}
} else {
- /* Otherwise adjust BH as if there is carry into T2 ... */
+ /*
+ * Otherwise adjust BH as if there is carry into T2.
+ * Note that constant BH is constrained to 11 bits for the MOVCC,
+ * so the adjustment fits 12 bits.
+ */
if (bhconst) {
- tcg_out_movi(s, TCG_TYPE_I64, TCG_REG_T2, bh + (is_sub ? -1 : 1));
+ tcg_out_movi_imm13(s, TCG_REG_T2, bh + (is_sub ? -1 : 1));
} else {
tcg_out_arithi(s, TCG_REG_T2, bh, 1,
is_sub ? ARITH_SUB : ARITH_ADD);
@@ -827,6 +859,19 @@
tcg_out_mov(s, TCG_TYPE_I64, rl, tmp);
}
+static void tcg_out_jmpl_const(TCGContext *s, const tcg_insn_unit *dest,
+ bool in_prologue, bool tail_call)
+{
+ uintptr_t desti = (uintptr_t)dest;
+
+ /* Be careful not to clobber %o7 for a tail call. */
+ tcg_out_movi_int(s, TCG_TYPE_PTR, TCG_REG_T1,
+ desti & ~0xfff, in_prologue,
+ tail_call ? TCG_REG_G2 : TCG_REG_O7);
+ tcg_out_arithi(s, tail_call ? TCG_REG_G0 : TCG_REG_O7,
+ TCG_REG_T1, desti & 0xfff, JMPL);
+}
+
static void tcg_out_call_nodelay(TCGContext *s, const tcg_insn_unit *dest,
bool in_prologue)
{
@@ -835,10 +880,7 @@
if (disp == (int32_t)disp) {
tcg_out32(s, CALL | (uint32_t)disp >> 2);
} else {
- uintptr_t desti = (uintptr_t)dest;
- tcg_out_movi_int(s, TCG_TYPE_PTR, TCG_REG_T1,
- desti & ~0xfff, in_prologue);
- tcg_out_arithi(s, TCG_REG_O7, TCG_REG_T1, desti & 0xfff, JMPL);
+ tcg_out_jmpl_const(s, dest, in_prologue, false);
}
}
@@ -929,11 +971,10 @@
/* Set the retaddr operand. */
tcg_out_mov(s, TCG_TYPE_PTR, ra, TCG_REG_O7);
- /* Set the env operand. */
- tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O0, TCG_AREG0);
/* Tail call. */
- tcg_out_call_nodelay(s, qemu_ld_helpers[i], true);
- tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O7, ra);
+ tcg_out_jmpl_const(s, qemu_ld_helpers[i], true, true);
+ /* delay slot -- set the env argument */
+ tcg_out_mov_delay(s, TCG_REG_O0, TCG_AREG0);
}
for (i = 0; i < ARRAY_SIZE(qemu_st_helpers); ++i) {
@@ -975,14 +1016,46 @@
if (ra >= TCG_REG_O6) {
tcg_out_st(s, TCG_TYPE_PTR, TCG_REG_O7, TCG_REG_CALL_STACK,
TCG_TARGET_CALL_STACK_OFFSET);
- ra = TCG_REG_G1;
+ } else {
+ tcg_out_mov(s, TCG_TYPE_PTR, ra, TCG_REG_O7);
}
- tcg_out_mov(s, TCG_TYPE_PTR, ra, TCG_REG_O7);
- /* Set the env operand. */
- tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O0, TCG_AREG0);
+
/* Tail call. */
- tcg_out_call_nodelay(s, qemu_st_helpers[i], true);
- tcg_out_mov(s, TCG_TYPE_PTR, TCG_REG_O7, ra);
+ tcg_out_jmpl_const(s, qemu_st_helpers[i], true, true);
+ /* delay slot -- set the env argument */
+ tcg_out_mov_delay(s, TCG_REG_O0, TCG_AREG0);
+ }
+}
+#else
+static const tcg_insn_unit *qemu_unalign_ld_trampoline;
+static const tcg_insn_unit *qemu_unalign_st_trampoline;
+
+static void build_trampolines(TCGContext *s)
+{
+ for (int ld = 0; ld < 2; ++ld) {
+ void *helper;
+
+ while ((uintptr_t)s->code_ptr & 15) {
+ tcg_out_nop(s);
+ }
+
+ if (ld) {
+ helper = helper_unaligned_ld;
+ qemu_unalign_ld_trampoline = tcg_splitwx_to_rx(s->code_ptr);
+ } else {
+ helper = helper_unaligned_st;
+ qemu_unalign_st_trampoline = tcg_splitwx_to_rx(s->code_ptr);
+ }
+
+ if (!SPARC64 && TARGET_LONG_BITS == 64) {
+ /* Install the high part of the address. */
+ tcg_out_arithi(s, TCG_REG_O1, TCG_REG_O2, 32, SHIFT_SRLX);
+ }
+
+ /* Tail call. */
+ tcg_out_jmpl_const(s, helper, true, true);
+ /* delay slot -- set the env argument */
+ tcg_out_mov_delay(s, TCG_REG_O0, TCG_AREG0);
}
}
#endif
@@ -1013,7 +1086,8 @@
#ifndef CONFIG_SOFTMMU
if (guest_base != 0) {
- tcg_out_movi_int(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG, guest_base, true);
+ tcg_out_movi_int(s, TCG_TYPE_PTR, TCG_GUEST_BASE_REG,
+ guest_base, true, TCG_REG_T1);
tcg_regset_set_reg(s->reserved_regs, TCG_GUEST_BASE_REG);
}
#endif
@@ -1034,9 +1108,7 @@
/* delay slot */
tcg_out_movi_imm13(s, TCG_REG_O0, 0);
-#ifdef CONFIG_SOFTMMU
build_trampolines(s);
-#endif
}
static void tcg_out_nop_fill(tcg_insn_unit *p, int count)
@@ -1121,18 +1193,22 @@
static const int qemu_ld_opc[(MO_SSIZE | MO_BSWAP) + 1] = {
[MO_UB] = LDUB,
[MO_SB] = LDSB,
+ [MO_UB | MO_LE] = LDUB,
+ [MO_SB | MO_LE] = LDSB,
[MO_BEUW] = LDUH,
[MO_BESW] = LDSH,
[MO_BEUL] = LDUW,
[MO_BESL] = LDSW,
[MO_BEUQ] = LDX,
+ [MO_BESQ] = LDX,
[MO_LEUW] = LDUH_LE,
[MO_LESW] = LDSH_LE,
[MO_LEUL] = LDUW_LE,
[MO_LESL] = LDSW_LE,
[MO_LEUQ] = LDX_LE,
+ [MO_LESQ] = LDX_LE,
};
static const int qemu_st_opc[(MO_SIZE | MO_BSWAP) + 1] = {
@@ -1151,11 +1227,12 @@
MemOpIdx oi, bool is_64)
{
MemOp memop = get_memop(oi);
+ tcg_insn_unit *label_ptr;
+
#ifdef CONFIG_SOFTMMU
unsigned memi = get_mmuidx(oi);
TCGReg addrz, param;
const tcg_insn_unit *func;
- tcg_insn_unit *label_ptr;
addrz = tcg_out_tlb_load(s, addr, memi, memop,
offsetof(CPUTLBEntry, addr_read));
@@ -1219,13 +1296,99 @@
*label_ptr |= INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr));
#else
+ TCGReg index = (guest_base ? TCG_GUEST_BASE_REG : TCG_REG_G0);
+ unsigned a_bits = get_alignment_bits(memop);
+ unsigned s_bits = memop & MO_SIZE;
+ unsigned t_bits;
+
if (SPARC64 && TARGET_LONG_BITS == 32) {
tcg_out_arithi(s, TCG_REG_T1, addr, 0, SHIFT_SRL);
addr = TCG_REG_T1;
}
- tcg_out_ldst_rr(s, data, addr,
- (guest_base ? TCG_GUEST_BASE_REG : TCG_REG_G0),
+
+ /*
+ * Normal case: alignment equal to access size.
+ */
+ if (a_bits == s_bits) {
+ tcg_out_ldst_rr(s, data, addr, index,
+ qemu_ld_opc[memop & (MO_BSWAP | MO_SSIZE)]);
+ return;
+ }
+
+ /*
+ * Test for at least natural alignment, and assume most accesses
+ * will be aligned -- perform a straight load in the delay slot.
+ * This is required to preserve atomicity for aligned accesses.
+ */
+ t_bits = MAX(a_bits, s_bits);
+ tcg_debug_assert(t_bits < 13);
+ tcg_out_arithi(s, TCG_REG_G0, addr, (1u << t_bits) - 1, ARITH_ANDCC);
+
+ /* beq,a,pt %icc, label */
+ label_ptr = s->code_ptr;
+ tcg_out_bpcc0(s, COND_E, BPCC_A | BPCC_PT | BPCC_ICC, 0);
+ /* delay slot */
+ tcg_out_ldst_rr(s, data, addr, index,
qemu_ld_opc[memop & (MO_BSWAP | MO_SSIZE)]);
+
+ if (a_bits >= s_bits) {
+ /*
+ * Overalignment: A successful alignment test will perform the memory
+ * operation in the delay slot, and failure need only invoke the
+ * handler for SIGBUS.
+ */
+ TCGReg arg_low = TCG_REG_O1 + (!SPARC64 && TARGET_LONG_BITS == 64);
+ tcg_out_call_nodelay(s, qemu_unalign_ld_trampoline, false);
+ /* delay slot -- move to low part of argument reg */
+ tcg_out_mov_delay(s, arg_low, addr);
+ } else {
+ /* Underalignment: load by pieces of minimum alignment. */
+ int ld_opc, a_size, s_size, i;
+
+ /*
+ * Force full address into T1 early; avoids problems with
+ * overlap between @addr and @data.
+ */
+ tcg_out_arith(s, TCG_REG_T1, addr, index, ARITH_ADD);
+
+ a_size = 1 << a_bits;
+ s_size = 1 << s_bits;
+ if ((memop & MO_BSWAP) == MO_BE) {
+ ld_opc = qemu_ld_opc[a_bits | MO_BE | (memop & MO_SIGN)];
+ tcg_out_ldst(s, data, TCG_REG_T1, 0, ld_opc);
+ ld_opc = qemu_ld_opc[a_bits | MO_BE];
+ for (i = a_size; i < s_size; i += a_size) {
+ tcg_out_ldst(s, TCG_REG_T2, TCG_REG_T1, i, ld_opc);
+ tcg_out_arithi(s, data, data, a_size, SHIFT_SLLX);
+ tcg_out_arith(s, data, data, TCG_REG_T2, ARITH_OR);
+ }
+ } else if (a_bits == 0) {
+ ld_opc = LDUB;
+ tcg_out_ldst(s, data, TCG_REG_T1, 0, ld_opc);
+ for (i = a_size; i < s_size; i += a_size) {
+ if ((memop & MO_SIGN) && i == s_size - a_size) {
+ ld_opc = LDSB;
+ }
+ tcg_out_ldst(s, TCG_REG_T2, TCG_REG_T1, i, ld_opc);
+ tcg_out_arithi(s, TCG_REG_T2, TCG_REG_T2, i * 8, SHIFT_SLLX);
+ tcg_out_arith(s, data, data, TCG_REG_T2, ARITH_OR);
+ }
+ } else {
+ ld_opc = qemu_ld_opc[a_bits | MO_LE];
+ tcg_out_ldst_rr(s, data, TCG_REG_T1, TCG_REG_G0, ld_opc);
+ for (i = a_size; i < s_size; i += a_size) {
+ tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, a_size, ARITH_ADD);
+ if ((memop & MO_SIGN) && i == s_size - a_size) {
+ ld_opc = qemu_ld_opc[a_bits | MO_LE | MO_SIGN];
+ }
+ tcg_out_ldst_rr(s, TCG_REG_T2, TCG_REG_T1, TCG_REG_G0, ld_opc);
+ tcg_out_arithi(s, TCG_REG_T2, TCG_REG_T2, i * 8, SHIFT_SLLX);
+ tcg_out_arith(s, data, data, TCG_REG_T2, ARITH_OR);
+ }
+ }
+ }
+
+ *label_ptr |= INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr));
#endif /* CONFIG_SOFTMMU */
}
@@ -1233,11 +1396,12 @@
MemOpIdx oi)
{
MemOp memop = get_memop(oi);
+ tcg_insn_unit *label_ptr;
+
#ifdef CONFIG_SOFTMMU
unsigned memi = get_mmuidx(oi);
TCGReg addrz, param;
const tcg_insn_unit *func;
- tcg_insn_unit *label_ptr;
addrz = tcg_out_tlb_load(s, addr, memi, memop,
offsetof(CPUTLBEntry, addr_write));
@@ -1274,13 +1438,93 @@
*label_ptr |= INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr));
#else
+ TCGReg index = (guest_base ? TCG_GUEST_BASE_REG : TCG_REG_G0);
+ unsigned a_bits = get_alignment_bits(memop);
+ unsigned s_bits = memop & MO_SIZE;
+ unsigned t_bits;
+
if (SPARC64 && TARGET_LONG_BITS == 32) {
tcg_out_arithi(s, TCG_REG_T1, addr, 0, SHIFT_SRL);
addr = TCG_REG_T1;
}
- tcg_out_ldst_rr(s, data, addr,
- (guest_base ? TCG_GUEST_BASE_REG : TCG_REG_G0),
+
+ /*
+ * Normal case: alignment equal to access size.
+ */
+ if (a_bits == s_bits) {
+ tcg_out_ldst_rr(s, data, addr, index,
+ qemu_st_opc[memop & (MO_BSWAP | MO_SIZE)]);
+ return;
+ }
+
+ /*
+ * Test for at least natural alignment, and assume most accesses
+ * will be aligned -- perform a straight store in the delay slot.
+ * This is required to preserve atomicity for aligned accesses.
+ */
+ t_bits = MAX(a_bits, s_bits);
+ tcg_debug_assert(t_bits < 13);
+ tcg_out_arithi(s, TCG_REG_G0, addr, (1u << t_bits) - 1, ARITH_ANDCC);
+
+ /* beq,a,pt %icc, label */
+ label_ptr = s->code_ptr;
+ tcg_out_bpcc0(s, COND_E, BPCC_A | BPCC_PT | BPCC_ICC, 0);
+ /* delay slot */
+ tcg_out_ldst_rr(s, data, addr, index,
qemu_st_opc[memop & (MO_BSWAP | MO_SIZE)]);
+
+ if (a_bits >= s_bits) {
+ /*
+ * Overalignment: A successful alignment test will perform the memory
+ * operation in the delay slot, and failure need only invoke the
+ * handler for SIGBUS.
+ */
+ TCGReg arg_low = TCG_REG_O1 + (!SPARC64 && TARGET_LONG_BITS == 64);
+ tcg_out_call_nodelay(s, qemu_unalign_st_trampoline, false);
+ /* delay slot -- move to low part of argument reg */
+ tcg_out_mov_delay(s, arg_low, addr);
+ } else {
+ /* Underalignment: store by pieces of minimum alignment. */
+ int st_opc, a_size, s_size, i;
+
+ /*
+ * Force full address into T1 early; avoids problems with
+ * overlap between @addr and @data.
+ */
+ tcg_out_arith(s, TCG_REG_T1, addr, index, ARITH_ADD);
+
+ a_size = 1 << a_bits;
+ s_size = 1 << s_bits;
+ if ((memop & MO_BSWAP) == MO_BE) {
+ st_opc = qemu_st_opc[a_bits | MO_BE];
+ for (i = 0; i < s_size; i += a_size) {
+ TCGReg d = data;
+ int shift = (s_size - a_size - i) * 8;
+ if (shift) {
+ d = TCG_REG_T2;
+ tcg_out_arithi(s, d, data, shift, SHIFT_SRLX);
+ }
+ tcg_out_ldst(s, d, TCG_REG_T1, i, st_opc);
+ }
+ } else if (a_bits == 0) {
+ tcg_out_ldst(s, data, TCG_REG_T1, 0, STB);
+ for (i = 1; i < s_size; i++) {
+ tcg_out_arithi(s, TCG_REG_T2, data, i * 8, SHIFT_SRLX);
+ tcg_out_ldst(s, TCG_REG_T2, TCG_REG_T1, i, STB);
+ }
+ } else {
+ /* Note that ST*A with immediate asi must use indexed address. */
+ st_opc = qemu_st_opc[a_bits + MO_LE];
+ tcg_out_ldst_rr(s, data, TCG_REG_T1, TCG_REG_G0, st_opc);
+ for (i = a_size; i < s_size; i += a_size) {
+ tcg_out_arithi(s, TCG_REG_T2, data, i * 8, SHIFT_SRLX);
+ tcg_out_arithi(s, TCG_REG_T1, TCG_REG_T1, a_size, ARITH_ADD);
+ tcg_out_ldst_rr(s, TCG_REG_T2, TCG_REG_T1, TCG_REG_G0, st_opc);
+ }
+ }
+ }
+
+ *label_ptr |= INSN_OFF19(tcg_ptr_byte_diff(s->code_ptr, label_ptr));
#endif /* CONFIG_SOFTMMU */
}
diff --git a/tcg/tci.c b/tcg/tci.c
index 336af59..fe92b5d 100644
--- a/tcg/tci.c
+++ b/tcg/tci.c
@@ -292,11 +292,11 @@
static uint64_t tci_qemu_ld(CPUArchState *env, target_ulong taddr,
MemOpIdx oi, const void *tb_ptr)
{
- MemOp mop = get_memop(oi) & (MO_BSWAP | MO_SSIZE);
+ MemOp mop = get_memop(oi);
uintptr_t ra = (uintptr_t)tb_ptr;
#ifdef CONFIG_SOFTMMU
- switch (mop) {
+ switch (mop & (MO_BSWAP | MO_SSIZE)) {
case MO_UB:
return helper_ret_ldub_mmu(env, taddr, oi, ra);
case MO_SB:
@@ -326,10 +326,14 @@
}
#else
void *haddr = g2h(env_cpu(env), taddr);
+ unsigned a_mask = (1u << get_alignment_bits(mop)) - 1;
uint64_t ret;
set_helper_retaddr(ra);
- switch (mop) {
+ if (taddr & a_mask) {
+ helper_unaligned_ld(env, taddr);
+ }
+ switch (mop & (MO_BSWAP | MO_SSIZE)) {
case MO_UB:
ret = ldub_p(haddr);
break;
@@ -377,11 +381,11 @@
static void tci_qemu_st(CPUArchState *env, target_ulong taddr, uint64_t val,
MemOpIdx oi, const void *tb_ptr)
{
- MemOp mop = get_memop(oi) & (MO_BSWAP | MO_SSIZE);
+ MemOp mop = get_memop(oi);
uintptr_t ra = (uintptr_t)tb_ptr;
#ifdef CONFIG_SOFTMMU
- switch (mop) {
+ switch (mop & (MO_BSWAP | MO_SIZE)) {
case MO_UB:
helper_ret_stb_mmu(env, taddr, val, oi, ra);
break;
@@ -408,9 +412,13 @@
}
#else
void *haddr = g2h(env_cpu(env), taddr);
+ unsigned a_mask = (1u << get_alignment_bits(mop)) - 1;
set_helper_retaddr(ra);
- switch (mop) {
+ if (taddr & a_mask) {
+ helper_unaligned_st(env, taddr);
+ }
+ switch (mop & (MO_BSWAP | MO_SIZE)) {
case MO_UB:
stb_p(haddr, val);
break;
diff --git a/tests/qemu-iotests/245 b/tests/qemu-iotests/245
index 24ac43f..8cbed78 100755
--- a/tests/qemu-iotests/245
+++ b/tests/qemu-iotests/245
@@ -1138,12 +1138,13 @@
self.assertEqual(self.get_node('hd1'), None)
self.assert_qmp(self.get_node('hd2'), 'ro', True)
- def run_test_iothreads(self, iothread_a, iothread_b, errmsg = None):
- opts = hd_opts(0)
+ def run_test_iothreads(self, iothread_a, iothread_b, errmsg = None,
+ opts_a = None, opts_b = None):
+ opts = opts_a or hd_opts(0)
result = self.vm.qmp('blockdev-add', conv_keys = False, **opts)
self.assert_qmp(result, 'return', {})
- opts2 = hd_opts(2)
+ opts2 = opts_b or hd_opts(2)
result = self.vm.qmp('blockdev-add', conv_keys = False, **opts2)
self.assert_qmp(result, 'return', {})
@@ -1194,6 +1195,35 @@
def test_iothreads_switch_overlay(self):
self.run_test_iothreads('', 'iothread0')
+ def test_iothreads_with_throttling(self):
+ # Create a throttle-group object
+ opts = { 'qom-type': 'throttle-group', 'id': 'group0',
+ 'limits': { 'iops-total': 1000 } }
+ result = self.vm.qmp('object-add', conv_keys = False, **opts)
+ self.assert_qmp(result, 'return', {})
+
+ # Options with a throttle filter between format and protocol
+ opts = [
+ {
+ 'driver': iotests.imgfmt,
+ 'node-name': f'hd{idx}',
+ 'file' : {
+ 'node-name': f'hd{idx}-throttle',
+ 'driver': 'throttle',
+ 'throttle-group': 'group0',
+ 'file': {
+ 'driver': 'file',
+ 'node-name': f'hd{idx}-file',
+ 'filename': hd_path[idx],
+ },
+ },
+ }
+ for idx in (0, 2)
+ ]
+
+ self.run_test_iothreads('iothread0', 'iothread0', None,
+ opts[0], opts[1])
+
if __name__ == '__main__':
iotests.activate_logging()
iotests.main(supported_fmts=["qcow2"],
diff --git a/tests/qemu-iotests/245.out b/tests/qemu-iotests/245.out
index 4eced19..a4e04a3 100644
--- a/tests/qemu-iotests/245.out
+++ b/tests/qemu-iotests/245.out
@@ -17,8 +17,8 @@
read 1/1 bytes at offset 262160
1 bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
-...............
+................
----------------------------------------------------------------------
-Ran 25 tests
+Ran 26 tests
OK
diff --git a/tests/tcg/multiarch/sigbus.c b/tests/tcg/multiarch/sigbus.c
new file mode 100644
index 0000000..8134c5f
--- /dev/null
+++ b/tests/tcg/multiarch/sigbus.c
@@ -0,0 +1,68 @@
+#define _GNU_SOURCE 1
+
+#include <assert.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <endian.h>
+
+
+unsigned long long x = 0x8877665544332211ull;
+void * volatile p = (void *)&x + 1;
+
+void sigbus(int sig, siginfo_t *info, void *uc)
+{
+ assert(sig == SIGBUS);
+ assert(info->si_signo == SIGBUS);
+#ifdef BUS_ADRALN
+ assert(info->si_code == BUS_ADRALN);
+#endif
+ assert(info->si_addr == p);
+ exit(EXIT_SUCCESS);
+}
+
+int main()
+{
+ struct sigaction sa = {
+ .sa_sigaction = sigbus,
+ .sa_flags = SA_SIGINFO
+ };
+ int allow_fail = 0;
+ int tmp;
+
+ tmp = sigaction(SIGBUS, &sa, NULL);
+ assert(tmp == 0);
+
+ /*
+ * Select an operation that's likely to enforce alignment.
+ * On many guests that support unaligned accesses by default,
+ * this is often an atomic operation.
+ */
+#if defined(__aarch64__)
+ asm volatile("ldxr %w0,[%1]" : "=r"(tmp) : "r"(p) : "memory");
+#elif defined(__alpha__)
+ asm volatile("ldl_l %0,0(%1)" : "=r"(tmp) : "r"(p) : "memory");
+#elif defined(__arm__)
+ asm volatile("ldrex %0,[%1]" : "=r"(tmp) : "r"(p) : "memory");
+#elif defined(__powerpc__)
+ asm volatile("lwarx %0,0,%1" : "=r"(tmp) : "r"(p) : "memory");
+#elif defined(__riscv_atomic)
+ asm volatile("lr.w %0,(%1)" : "=r"(tmp) : "r"(p) : "memory");
+#else
+ /* No insn known to fault unaligned -- try for a straight load. */
+ allow_fail = 1;
+ tmp = *(volatile int *)p;
+#endif
+
+ assert(allow_fail);
+
+ /*
+ * We didn't see a signal.
+ * We might as well validate the unaligned load worked.
+ */
+ if (BYTE_ORDER == LITTLE_ENDIAN) {
+ assert(tmp == 0x55443322);
+ } else {
+ assert(tmp == 0x77665544);
+ }
+ return EXIT_SUCCESS;
+}