mirror of
https://github.com/AsahiLinux/m1n1
synced 2024-11-26 08:20:18 +00:00
hv: Log memory attribute & sharability info in mmiotrace
Signed-off-by: Asahi Lina <lina@asahilina.net>
This commit is contained in:
parent
5836db9305
commit
4274c9d74a
5 changed files with 31 additions and 20 deletions
|
@ -10,7 +10,9 @@ __all__ = [
|
|||
]
|
||||
|
||||
class MMIOTraceFlags(Register32):
|
||||
ATTR = 31, 24
|
||||
CPU = 23, 16
|
||||
SH = 15, 14
|
||||
WIDTH = 4, 0
|
||||
WRITE = 5
|
||||
MULTI = 6
|
||||
|
|
4
src/hv.h
4
src/hv.h
|
@ -10,7 +10,9 @@
|
|||
|
||||
typedef bool(hv_hook_t)(struct exc_info *ctx, u64 addr, u64 *val, bool write, int width);
|
||||
|
||||
#define MMIO_EVT_ATTR GENMASK(31, 24)
|
||||
#define MMIO_EVT_CPU GENMASK(23, 16)
|
||||
#define MMIO_EVT_SH GENMASK(15, 14)
|
||||
#define MMIO_EVT_MULTI BIT(6)
|
||||
#define MMIO_EVT_WRITE BIT(5)
|
||||
#define MMIO_EVT_WIDTH GENMASK(4, 0)
|
||||
|
@ -54,7 +56,7 @@ int hv_unmap(u64 from, u64 size);
|
|||
int hv_map_hw(u64 from, u64 to, u64 size);
|
||||
int hv_map_sw(u64 from, u64 to, u64 size);
|
||||
int hv_map_hook(u64 from, hv_hook_t *hook, u64 size);
|
||||
u64 hv_translate(u64 addr, bool s1only, bool w);
|
||||
u64 hv_translate(u64 addr, bool s1only, bool w, u64 *par_out);
|
||||
u64 hv_pt_walk(u64 addr);
|
||||
bool hv_handle_dabort(struct exc_info *ctx);
|
||||
bool hv_pa_write(struct exc_info *ctx, u64 addr, u64 *val, int width);
|
||||
|
|
|
@ -58,9 +58,9 @@ static void _hv_exc_proxy(struct exc_info *ctx, uartproxy_boot_reason_t reason,
|
|||
|
||||
u64 entry_time = mrs(CNTPCT_EL0);
|
||||
|
||||
ctx->elr_phys = hv_translate(ctx->elr, false, false);
|
||||
ctx->far_phys = hv_translate(ctx->far, false, false);
|
||||
ctx->sp_phys = hv_translate(from_el == 0 ? ctx->sp[0] : ctx->sp[1], false, false);
|
||||
ctx->elr_phys = hv_translate(ctx->elr, false, false, NULL);
|
||||
ctx->far_phys = hv_translate(ctx->far, false, false, NULL);
|
||||
ctx->sp_phys = hv_translate(from_el == 0 ? ctx->sp[0] : ctx->sp[1], false, false, NULL);
|
||||
ctx->extra = extra;
|
||||
|
||||
struct uartproxy_msg_start start = {
|
||||
|
|
36
src/hv_vm.c
36
src/hv_vm.c
|
@ -381,7 +381,7 @@ int hv_map_hook(u64 from, hv_hook_t *hook, u64 size)
|
|||
return hv_map(from, ((u64)hook) | FIELD_PREP(SPTE_TYPE, SPTE_HOOK), size, 0);
|
||||
}
|
||||
|
||||
u64 hv_translate(u64 addr, bool s1, bool w)
|
||||
u64 hv_translate(u64 addr, bool s1, bool w, u64 *par_out)
|
||||
{
|
||||
if (!(mrs(SCTLR_EL12) & SCTLR_M))
|
||||
return addr; // MMU off
|
||||
|
@ -416,6 +416,8 @@ u64 hv_translate(u64 addr, bool s1, bool w)
|
|||
}
|
||||
|
||||
u64 par = mrs(PAR_EL1);
|
||||
if (par_out)
|
||||
*par_out = par;
|
||||
msr(PAR_EL1, save);
|
||||
|
||||
if (par & PAR_F) {
|
||||
|
@ -927,13 +929,15 @@ bool hv_pa_rw(struct exc_info *ctx, u64 addr, u64 *val, bool write, int width)
|
|||
}
|
||||
|
||||
static bool hv_emulate_rw_aligned(struct exc_info *ctx, u64 pte, u64 vaddr, u64 ipa, u64 *val,
|
||||
bool is_write, u64 width, u64 elr)
|
||||
bool is_write, u64 width, u64 elr, u64 par)
|
||||
{
|
||||
assert(pte);
|
||||
assert(((ipa & 0x3fff) + (1 << width)) <= 0x4000);
|
||||
|
||||
u64 target = pte & PTE_TARGET_MASK_L4;
|
||||
u64 paddr = target | (vaddr & MASK(VADDR_L4_OFFSET_BITS));
|
||||
u64 flags = FIELD_PREP(MMIO_EVT_ATTR, FIELD_GET(PAR_ATTR, par)) |
|
||||
FIELD_PREP(MMIO_EVT_SH, FIELD_GET(PAR_SH, par));
|
||||
|
||||
// For split ops, treat hardware mapped pages as SPTE_MAP
|
||||
if (IS_HW(pte))
|
||||
|
@ -944,7 +948,7 @@ static bool hv_emulate_rw_aligned(struct exc_info *ctx, u64 pte, u64 vaddr, u64
|
|||
hv_wdt_breadcrumb('3');
|
||||
|
||||
if (pte & SPTE_TRACE_WRITE)
|
||||
emit_mmiotrace(elr, ipa, val, width, MMIO_EVT_WRITE, pte & SPTE_TRACE_UNBUF);
|
||||
emit_mmiotrace(elr, ipa, val, width, flags | MMIO_EVT_WRITE, pte & SPTE_TRACE_UNBUF);
|
||||
|
||||
hv_wdt_breadcrumb('4');
|
||||
|
||||
|
@ -972,7 +976,7 @@ static bool hv_emulate_rw_aligned(struct exc_info *ctx, u64 pte, u64 vaddr, u64
|
|||
case SPTE_PROXY_HOOK_W: {
|
||||
hv_wdt_breadcrumb('7');
|
||||
struct hv_vm_proxy_hook_data hook = {
|
||||
.flags = FIELD_PREP(MMIO_EVT_WIDTH, width) | MMIO_EVT_WRITE,
|
||||
.flags = FIELD_PREP(MMIO_EVT_WIDTH, width) | MMIO_EVT_WRITE | flags,
|
||||
.id = FIELD_GET(PTE_TARGET_MASK_L4, pte),
|
||||
.addr = ipa,
|
||||
.data = {0},
|
||||
|
@ -1011,7 +1015,7 @@ static bool hv_emulate_rw_aligned(struct exc_info *ctx, u64 pte, u64 vaddr, u64
|
|||
case SPTE_PROXY_HOOK_R: {
|
||||
hv_wdt_breadcrumb('6');
|
||||
struct hv_vm_proxy_hook_data hook = {
|
||||
.flags = FIELD_PREP(MMIO_EVT_WIDTH, width),
|
||||
.flags = FIELD_PREP(MMIO_EVT_WIDTH, width) | flags,
|
||||
.id = FIELD_GET(PTE_TARGET_MASK_L4, pte),
|
||||
.addr = ipa,
|
||||
};
|
||||
|
@ -1026,7 +1030,7 @@ static bool hv_emulate_rw_aligned(struct exc_info *ctx, u64 pte, u64 vaddr, u64
|
|||
|
||||
hv_wdt_breadcrumb('7');
|
||||
if (pte & SPTE_TRACE_READ)
|
||||
emit_mmiotrace(elr, ipa, val, width, 0, pte & SPTE_TRACE_UNBUF);
|
||||
emit_mmiotrace(elr, ipa, val, width, flags, pte & SPTE_TRACE_UNBUF);
|
||||
}
|
||||
|
||||
hv_wdt_breadcrumb('*');
|
||||
|
@ -1035,7 +1039,7 @@ static bool hv_emulate_rw_aligned(struct exc_info *ctx, u64 pte, u64 vaddr, u64
|
|||
}
|
||||
|
||||
static bool hv_emulate_rw(struct exc_info *ctx, u64 pte, u64 vaddr, u64 ipa, u8 *val, bool is_write,
|
||||
u64 bytes, u64 elr)
|
||||
u64 bytes, u64 elr, u64 par)
|
||||
{
|
||||
u64 aval[HV_MAX_RW_WORDS];
|
||||
memset(aval, 0, sizeof(aval));
|
||||
|
@ -1105,7 +1109,8 @@ bool hv_handle_dabort(struct exc_info *ctx)
|
|||
bool is_write = esr & ESR_ISS_DABORT_WnR;
|
||||
|
||||
u64 far = hv_get_far();
|
||||
u64 ipa = hv_translate(far, true, is_write);
|
||||
u64 par;
|
||||
u64 ipa = hv_translate(far, true, is_write, &par);
|
||||
|
||||
dprintf("hv_handle_abort(): stage 1 0x%0lx -> 0x%lx\n", far, ipa);
|
||||
|
||||
|
@ -1138,7 +1143,7 @@ bool hv_handle_dabort(struct exc_info *ctx)
|
|||
assert(IS_SW(pte));
|
||||
|
||||
u64 elr = ctx->elr;
|
||||
u64 elr_pa = hv_translate(elr, false, false);
|
||||
u64 elr_pa = hv_translate(elr, false, false, NULL);
|
||||
if (!elr_pa) {
|
||||
printf("HV: Failed to fetch instruction for data abort at 0x%lx\n", elr);
|
||||
return false;
|
||||
|
@ -1186,7 +1191,7 @@ bool hv_handle_dabort(struct exc_info *ctx)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!hv_emulate_rw(ctx, pte, vaddr, ipa, val, is_write, bytes, elr))
|
||||
if (!hv_emulate_rw(ctx, pte, vaddr, ipa, val, is_write, bytes, elr, par))
|
||||
return false;
|
||||
} else {
|
||||
// Oops, we're straddling a page boundary
|
||||
|
@ -1211,7 +1216,8 @@ bool hv_handle_dabort(struct exc_info *ctx)
|
|||
vaddr2 = vaddr;
|
||||
}
|
||||
|
||||
u64 ipa2 = hv_translate(vaddr2, true, esr & ESR_ISS_DABORT_WnR);
|
||||
u64 par2;
|
||||
u64 ipa2 = hv_translate(vaddr2, true, esr & ESR_ISS_DABORT_WnR, &par2);
|
||||
if (!ipa2) {
|
||||
printf("HV: %s half stage 1 translation failed at VA 0x%0lx\n", other, vaddr2);
|
||||
return false;
|
||||
|
@ -1235,15 +1241,15 @@ bool hv_handle_dabort(struct exc_info *ctx)
|
|||
|
||||
bool upper_ret;
|
||||
if (far == vaddr) {
|
||||
if (!hv_emulate_rw(ctx, pte, vaddr, ipa, val, is_write, off, elr))
|
||||
if (!hv_emulate_rw(ctx, pte, vaddr, ipa, val, is_write, off, elr, par))
|
||||
return false;
|
||||
upper_ret =
|
||||
hv_emulate_rw(ctx, pte2, vaddr2, ipa2, val + off, is_write, bytes - off, elr);
|
||||
hv_emulate_rw(ctx, pte2, vaddr2, ipa2, val + off, is_write, bytes - off, elr, par2);
|
||||
} else {
|
||||
if (!hv_emulate_rw(ctx, pte2, vaddr2, ipa2, val, is_write, off, elr))
|
||||
if (!hv_emulate_rw(ctx, pte2, vaddr2, ipa2, val, is_write, off, elr, par2))
|
||||
return false;
|
||||
upper_ret =
|
||||
hv_emulate_rw(ctx, pte, vaddrp1, ipa, val + off, is_write, bytes - off, elr);
|
||||
hv_emulate_rw(ctx, pte, vaddrp1, ipa, val + off, is_write, bytes - off, elr, par);
|
||||
}
|
||||
|
||||
if (!upper_ret) {
|
||||
|
|
|
@ -446,7 +446,8 @@ int proxy_process(ProxyRequest *request, ProxyReply *reply)
|
|||
hv_start((void *)request->args[0], &request->args[1]);
|
||||
break;
|
||||
case P_HV_TRANSLATE:
|
||||
reply->retval = hv_translate(request->args[0], request->args[1], request->args[2]);
|
||||
reply->retval = hv_translate(request->args[0], request->args[1], request->args[2],
|
||||
(void *)request->args[3]);
|
||||
break;
|
||||
case P_HV_PT_WALK:
|
||||
reply->retval = hv_pt_walk(request->args[0]);
|
||||
|
|
Loading…
Reference in a new issue