@@ -13,6 +13,7 @@
#include "exec/breakpoint.h"
#include "exec/hwaddr.h"
#include "exec/memattrs.h"
+#include "exec/memop.h"
#include "exec/mmu-access-type.h"
#include "exec/vaddr.h"
@@ -131,6 +132,21 @@ struct TCGCPUOps {
* same function signature.
*/
bool (*cpu_exec_halt)(CPUState *cpu);
+
+ /**
+ * @tlb_fill_align: Handle a softmmu tlb miss, and alignment fault
+ *
+ * If the access is valid, call tlb_set_page and return true;
+ * if the access is invalid and probe is true, return false;
+ * otherwise raise an exception and do not return.
+ *
+ * The alignment check is deferred to this hook, so that the
+ * target can choose to recognize either before or after the
+ * permission check.
+ */
+ bool (*tlb_fill_align)(CPUState *cpu, vaddr address, MemOp mop, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr);
/**
* @tlb_fill: Handle a softmmu tlb miss
*
@@ -234,6 +250,15 @@ void cpu_check_watchpoint(CPUState *cpu, vaddr addr, vaddr len,
*/
int cpu_watchpoint_address_matches(CPUState *cpu, vaddr addr, vaddr len);
+/*
+ * tlb_fill_align_first:
+ *
+ * Prioritize alignment faults over page faults.
+ */
+bool tlb_fill_align_first(CPUState *cpu, vaddr address, MemOp mop, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr);
+
#endif
#endif /* TCG_CPU_OPS_H */
@@ -1565,6 +1565,25 @@ bool tlb_plugin_lookup(CPUState *cpu, vaddr addr, int mmu_idx,
}
#endif
+
+/*
+ * Generic implementation of tlb_fill_align which recognizes
+ * alignment faults before page faults.
+ */
+bool tlb_fill_align_first(CPUState *cpu, vaddr addr, MemOp mop, int size,
+ MMUAccessType access_type, int mmu_idx,
+ bool probe, uintptr_t retaddr)
+{
+ unsigned a_bits = memop_alignment_bits(mop);
+
+ if (unlikely(addr & ((1 << a_bits) - 1))) {
+ cpu_unaligned_access(cpu, addr, access_type, mmu_idx, retaddr);
+ }
+
+ return cpu->cc->tcg_ops->tlb_fill(cpu, addr, size, access_type,
+ mmu_idx, probe, retaddr);
+}
+
/*
* Probe for a load/store operation.
* Return the host address and into @flags.
@@ -217,6 +217,7 @@ static const TCGCPUOps alpha_tcg_ops = {
.record_sigsegv = alpha_cpu_record_sigsegv,
.record_sigbus = alpha_cpu_record_sigbus,
#else
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = alpha_cpu_tlb_fill,
.cpu_exec_interrupt = alpha_cpu_exec_interrupt,
.cpu_exec_halt = alpha_cpu_has_work,
@@ -2663,6 +2663,7 @@ static const TCGCPUOps arm_tcg_ops = {
.record_sigsegv = arm_cpu_record_sigsegv,
.record_sigbus = arm_cpu_record_sigbus,
#else
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = arm_cpu_tlb_fill,
.cpu_exec_interrupt = arm_cpu_exec_interrupt,
.cpu_exec_halt = arm_cpu_exec_halt,
@@ -242,6 +242,7 @@ static const TCGCPUOps arm_v7m_tcg_ops = {
.record_sigsegv = arm_cpu_record_sigsegv,
.record_sigbus = arm_cpu_record_sigbus,
#else
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = arm_cpu_tlb_fill,
.cpu_exec_interrupt = arm_v7m_cpu_exec_interrupt,
.cpu_exec_halt = arm_cpu_exec_halt,
@@ -211,6 +211,7 @@ static const TCGCPUOps avr_tcg_ops = {
.restore_state_to_opc = avr_restore_state_to_opc,
.cpu_exec_interrupt = avr_cpu_exec_interrupt,
.cpu_exec_halt = avr_cpu_has_work,
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = avr_cpu_tlb_fill,
.do_interrupt = avr_cpu_do_interrupt,
};
@@ -226,6 +226,7 @@ static const TCGCPUOps hppa_tcg_ops = {
.restore_state_to_opc = hppa_restore_state_to_opc,
#ifndef CONFIG_USER_ONLY
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = hppa_cpu_tlb_fill,
.cpu_exec_interrupt = hppa_cpu_exec_interrupt,
.cpu_exec_halt = hppa_cpu_has_work,
@@ -117,6 +117,7 @@ static const TCGCPUOps x86_tcg_ops = {
.record_sigsegv = x86_cpu_record_sigsegv,
.record_sigbus = x86_cpu_record_sigbus,
#else
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = x86_cpu_tlb_fill,
.do_interrupt = x86_cpu_do_interrupt,
.cpu_exec_halt = x86_cpu_exec_halt,
@@ -755,6 +755,7 @@ static const TCGCPUOps loongarch_tcg_ops = {
.restore_state_to_opc = loongarch_restore_state_to_opc,
#ifndef CONFIG_USER_ONLY
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = loongarch_cpu_tlb_fill,
.cpu_exec_interrupt = loongarch_cpu_exec_interrupt,
.cpu_exec_halt = loongarch_cpu_has_work,
@@ -534,6 +534,7 @@ static const TCGCPUOps m68k_tcg_ops = {
.restore_state_to_opc = m68k_restore_state_to_opc,
#ifndef CONFIG_USER_ONLY
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = m68k_cpu_tlb_fill,
.cpu_exec_interrupt = m68k_cpu_exec_interrupt,
.cpu_exec_halt = m68k_cpu_has_work,
@@ -411,6 +411,7 @@ static const TCGCPUOps mb_tcg_ops = {
.restore_state_to_opc = mb_restore_state_to_opc,
#ifndef CONFIG_USER_ONLY
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = mb_cpu_tlb_fill,
.cpu_exec_interrupt = mb_cpu_exec_interrupt,
.cpu_exec_halt = mb_cpu_has_work,
@@ -553,6 +553,7 @@ static const TCGCPUOps mips_tcg_ops = {
.restore_state_to_opc = mips_restore_state_to_opc,
#if !defined(CONFIG_USER_ONLY)
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = mips_cpu_tlb_fill,
.cpu_exec_interrupt = mips_cpu_exec_interrupt,
.cpu_exec_halt = mips_cpu_has_work,
@@ -231,6 +231,7 @@ static const TCGCPUOps openrisc_tcg_ops = {
.restore_state_to_opc = openrisc_restore_state_to_opc,
#ifndef CONFIG_USER_ONLY
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = openrisc_cpu_tlb_fill,
.cpu_exec_interrupt = openrisc_cpu_exec_interrupt,
.cpu_exec_halt = openrisc_cpu_has_work,
@@ -7482,6 +7482,7 @@ static const TCGCPUOps ppc_tcg_ops = {
#ifdef CONFIG_USER_ONLY
.record_sigsegv = ppc_cpu_record_sigsegv,
#else
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = ppc_cpu_tlb_fill,
.cpu_exec_interrupt = ppc_cpu_exec_interrupt,
.cpu_exec_halt = ppc_cpu_has_work,
@@ -137,6 +137,7 @@ static const TCGCPUOps riscv_tcg_ops = {
.restore_state_to_opc = riscv_restore_state_to_opc,
#ifndef CONFIG_USER_ONLY
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = riscv_cpu_tlb_fill,
.cpu_exec_interrupt = riscv_cpu_exec_interrupt,
.cpu_exec_halt = riscv_cpu_has_work,
@@ -188,6 +188,7 @@ static const TCGCPUOps rx_tcg_ops = {
.initialize = rx_translate_init,
.synchronize_from_tb = rx_cpu_synchronize_from_tb,
.restore_state_to_opc = rx_restore_state_to_opc,
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = rx_cpu_tlb_fill,
#ifndef CONFIG_USER_ONLY
@@ -363,6 +363,7 @@ static const TCGCPUOps s390_tcg_ops = {
.record_sigsegv = s390_cpu_record_sigsegv,
.record_sigbus = s390_cpu_record_sigbus,
#else
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = s390_cpu_tlb_fill,
.cpu_exec_interrupt = s390_cpu_exec_interrupt,
.cpu_exec_halt = s390_cpu_has_work,
@@ -252,6 +252,7 @@ static const TCGCPUOps superh_tcg_ops = {
.restore_state_to_opc = superh_restore_state_to_opc,
#ifndef CONFIG_USER_ONLY
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = superh_cpu_tlb_fill,
.cpu_exec_interrupt = superh_cpu_exec_interrupt,
.cpu_exec_halt = superh_cpu_has_work,
@@ -924,6 +924,7 @@ static const TCGCPUOps sparc_tcg_ops = {
.restore_state_to_opc = sparc_restore_state_to_opc,
#ifndef CONFIG_USER_ONLY
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = sparc_cpu_tlb_fill,
.cpu_exec_interrupt = sparc_cpu_exec_interrupt,
.cpu_exec_halt = sparc_cpu_has_work,
@@ -173,6 +173,7 @@ static const TCGCPUOps tricore_tcg_ops = {
.initialize = tricore_tcg_init,
.synchronize_from_tb = tricore_cpu_synchronize_from_tb,
.restore_state_to_opc = tricore_restore_state_to_opc,
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = tricore_cpu_tlb_fill,
.cpu_exec_interrupt = tricore_cpu_exec_interrupt,
.cpu_exec_halt = tricore_cpu_has_work,
@@ -232,6 +232,7 @@ static const TCGCPUOps xtensa_tcg_ops = {
.restore_state_to_opc = xtensa_restore_state_to_opc,
#ifndef CONFIG_USER_ONLY
+ .tlb_fill_align = tlb_fill_align_first,
.tlb_fill = xtensa_cpu_tlb_fill,
.cpu_exec_interrupt = xtensa_cpu_exec_interrupt,
.cpu_exec_halt = xtensa_cpu_has_work,
Add the hook to struct TCGCPUOps. Add a default implementation that recognizes alignment faults before page faults. Populate all TCGCPUOps structures with the default implementation. Signed-off-by: Richard Henderson <richard.henderson@linaro.org> --- include/hw/core/tcg-cpu-ops.h | 25 +++++++++++++++++++++++++ accel/tcg/cputlb.c | 19 +++++++++++++++++++ target/alpha/cpu.c | 1 + target/arm/cpu.c | 1 + target/arm/tcg/cpu-v7m.c | 1 + target/avr/cpu.c | 1 + target/hppa/cpu.c | 1 + target/i386/tcg/tcg-cpu.c | 1 + target/loongarch/cpu.c | 1 + target/m68k/cpu.c | 1 + target/microblaze/cpu.c | 1 + target/mips/cpu.c | 1 + target/openrisc/cpu.c | 1 + target/ppc/cpu_init.c | 1 + target/riscv/tcg/tcg-cpu.c | 1 + target/rx/cpu.c | 1 + target/s390x/cpu.c | 1 + target/sh4/cpu.c | 1 + target/sparc/cpu.c | 1 + target/tricore/cpu.c | 1 + target/xtensa/cpu.c | 1 + 21 files changed, 63 insertions(+)