diff options
| author | magh <magh@maghmogh.com> | 2023-03-06 18:44:55 -0600 |
|---|---|---|
| committer | magh <magh@maghmogh.com> | 2023-03-06 18:44:55 -0600 |
| commit | e80d9d8871b325a04b18f90a9ea4bb7fd148fb25 (patch) | |
| tree | 79dbdb8506b7ff1e92549188d1b94cfc0b3503ae /tools/src/hv_aic.c | |
Diffstat (limited to 'tools/src/hv_aic.c')
| -rw-r--r-- | tools/src/hv_aic.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/tools/src/hv_aic.c b/tools/src/hv_aic.c new file mode 100644 index 0000000..cc5406a --- /dev/null +++ b/tools/src/hv_aic.c @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: MIT */ + +#include "adt.h" +#include "aic.h" +#include "aic_regs.h" +#include "hv.h" +#include "uartproxy.h" +#include "utils.h" + +#define IRQTRACE_IRQ BIT(0) + +static u32 trace_hw_num[AIC_MAX_DIES][AIC_MAX_HW_NUM / 32]; + +static void emit_irqtrace(u16 die, u16 type, u16 num) +{ + struct hv_evt_irqtrace evt = { + .flags = IRQTRACE_IRQ, + .type = type, + .num = die * aic->max_irq + num, + }; + + hv_wdt_suspend(); + uartproxy_send_event(EVT_IRQTRACE, &evt, sizeof(evt)); + hv_wdt_resume(); +} + +static bool trace_aic_event(struct exc_info *ctx, u64 addr, u64 *val, bool write, int width) +{ + if (!hv_pa_rw(ctx, addr, val, write, width)) + return false; + + if (addr != (aic->base + aic->regs.event) || write || width != 2) { + return true; + } + + u16 die = FIELD_GET(AIC_EVENT_DIE, *val); + u16 type = FIELD_GET(AIC_EVENT_TYPE, *val); + u16 num = FIELD_GET(AIC_EVENT_NUM, *val); + + if (die > AIC_MAX_DIES) + return true; + + switch (type) { + case AIC_EVENT_TYPE_HW: + if (trace_hw_num[die][num / 32] & BIT(num & 31)) { + emit_irqtrace(die, type, num); + } + break; + default: + // ignore + break; + } + + return true; +} + +bool hv_trace_irq(u32 type, u32 num, u32 count, u32 flags) +{ + dprintf("HV: hv_trace_irq type: %u start: %u num: %u flags: 0x%x\n", type, num, count, flags); + if (type == AIC_EVENT_TYPE_HW) { + u32 die = num / aic->max_irq; + num %= AIC_MAX_HW_NUM; + if (die >= aic->max_irq || num >= AIC_MAX_HW_NUM || count > AIC_MAX_HW_NUM - num) { + printf("HV: invalid IRQ range: (%u, %u) for die %u\n", num, num + count, die); + return false; + } + for (u32 n = num; n < num + count; n++) { + switch (flags) { + case IRQTRACE_IRQ: + trace_hw_num[die][n / 32] |= BIT(n & 31); + break; + default: + trace_hw_num[die][n / 32] &= ~(BIT(n & 31)); + break; + } + } + } else { + printf("HV: not handling AIC event type: 0x%02x num: %u\n", type, num); + return false; + } + + if (!aic) { + printf("HV: AIC not initialized\n"); + return false; + } + + static bool hooked = false; + + if (aic && !hooked) { + hv_map_hook(aic->base, trace_aic_event, aic->regs.reg_size); + hooked = true; + } + + return true; +} |
