hv: Log memory attribute & sharability info in mmiotrace

Signed-off-by: Asahi Lina <lina@asahilina.net>
This commit is contained in:
Asahi Lina 2022-10-12 21:03:50 +09:00 committed by Hector Martin
parent 5836db9305
commit 4274c9d74a
5 changed files with 31 additions and 20 deletions

View file

@ -10,7 +10,9 @@ __all__ = [
]
class MMIOTraceFlags(Register32):
ATTR = 31, 24
CPU = 23, 16
SH = 15, 14
WIDTH = 4, 0
WRITE = 5
MULTI = 6

View file

@ -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);

View file

@ -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 = {

View file

@ -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) {

View file

@ -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]);