2 * Jailhouse, a Linux-based partitioning hypervisor
4 * Copyright (c) ARM Limited, 2014
7 * Jean-Philippe Brucker <jean-philippe.brucker@arm.com>
9 * This work is licensed under the terms of the GNU GPL, version 2. See
10 * the COPYING file in the top-level directory.
13 #include <jailhouse/mmio.h>
14 #include <asm/bitops.h>
15 #include <asm/irqchip.h>
16 #include <asm/processor.h>
18 #include <asm/traps.h>
20 unsigned int arch_mmio_count_regions(struct cell *cell)
22 return irqchip_mmio_count_regions(cell) + smp_mmio_regions;
25 /* Taken from the ARM ARM pseudocode for taking a data abort */
26 static void arch_inject_dabt(struct trap_context *ctx, unsigned long addr)
28 unsigned int lr_offset;
33 arm_read_sysreg(SCTLR_EL1, sctlr);
34 arm_read_sysreg(TTBCR, ttbcr);
37 is_thumb = ctx->cpsr & PSR_T_BIT;
38 ctx->cpsr &= ~(PSR_MODE_MASK | PSR_IT_MASK(0xff) | PSR_T_BIT
39 | PSR_J_BIT | PSR_E_BIT);
40 ctx->cpsr |= (PSR_ABT_MODE | PSR_I_BIT | PSR_A_BIT);
41 if (sctlr & SCTLR_TE_BIT)
42 ctx->cpsr |= PSR_T_BIT;
43 if (sctlr & SCTLR_EE_BIT)
44 ctx->cpsr |= PSR_E_BIT;
46 lr_offset = (is_thumb ? 4 : 0);
47 arm_write_banked_reg(LR_abt, ctx->pc + lr_offset);
49 /* Branch to dabt vector */
50 if (sctlr & SCTLR_V_BIT)
53 arm_read_sysreg(VBAR, vbar);
54 ctx->pc = vbar + 0x10;
56 /* Signal a debug fault. DFSR layout depends on the LPAE bit */
58 arm_write_sysreg(DFSR, (1 << 9) | 0x22);
60 arm_write_sysreg(DFSR, 0x2);
61 arm_write_sysreg(DFAR, addr);
64 int arch_handle_dabt(struct trap_context *ctx)
66 enum mmio_result mmio_result;
67 struct mmio_access mmio;
70 /* Decode the syndrome fields */
71 u32 icc = ESR_ICC(ctx->esr);
73 u32 sas = icc >> 22 & 0x3;
74 u32 sse = icc >> 21 & 0x1;
75 u32 srt = icc >> 16 & 0xf;
76 u32 ea = icc >> 9 & 0x1;
77 u32 cm = icc >> 8 & 0x1;
78 u32 s1ptw = icc >> 7 & 0x1;
79 u32 is_write = icc >> 6 & 0x1;
82 arm_read_sysreg(HPFAR, hpfar);
83 arm_read_sysreg(HDFAR, hdfar);
84 mmio.address = hpfar << 8;
85 mmio.address |= hdfar & 0xfff;
87 this_cpu_data()->stats[JAILHOUSE_CPU_STAT_VMEXITS_MMIO]++;
90 * Invalid instruction syndrome means multiple access or writeback, there
91 * is nothing we can do.
93 if (!isv || size > sizeof(unsigned long))
96 /* Re-inject abort during page walk, cache maintenance or external */
97 if (s1ptw || ea || cm) {
98 arch_inject_dabt(ctx, hdfar);
103 /* Load the value to write from the src register */
104 access_cell_reg(ctx, srt, &mmio.value, true);
106 mmio.value = sign_extend(mmio.value, 8 * size);
110 mmio.is_write = is_write;
113 mmio_result = mmio_handle_access(&mmio);
114 if (mmio_result == MMIO_ERROR)
115 return TRAP_FORBIDDEN;
116 if (mmio_result == MMIO_UNHANDLED)
117 goto error_unhandled;
119 /* Put the read value into the dest register */
122 mmio.value = sign_extend(mmio.value, 8 * size);
123 access_cell_reg(ctx, srt, &mmio.value, false);
126 arch_skip_instruction(ctx);
130 panic_printk("Unhandled data %s at 0x%x(%d)\n",
131 (is_write ? "write" : "read"), mmio.address, size);
133 return TRAP_UNHANDLED;