diff options
Diffstat (limited to 'hw/intc')
-rw-r--r-- | hw/intc/arm_gicv3_its.c | 49 |
1 files changed, 32 insertions, 17 deletions
diff --git a/hw/intc/arm_gicv3_its.c b/hw/intc/arm_gicv3_its.c index a2a4e3d..e7e1769 100644 --- a/hw/intc/arm_gicv3_its.c +++ b/hw/intc/arm_gicv3_its.c @@ -397,6 +397,19 @@ static ItsCmdResult lookup_cte(GICv3ITSState *s, const char *who, return CMD_CONTINUE_OK; } +static ItsCmdResult process_its_cmd_phys(GICv3ITSState *s, const ITEntry *ite, + int irqlevel) +{ + CTEntry cte; + ItsCmdResult cmdres; + + cmdres = lookup_cte(s, __func__, ite->icid, &cte); + if (cmdres != CMD_CONTINUE_OK) { + return cmdres; + } + gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite->intid, irqlevel); + return CMD_CONTINUE_OK; +} /* * This function handles the processing of following commands based on @@ -410,34 +423,36 @@ static ItsCmdResult do_process_its_cmd(GICv3ITSState *s, uint32_t devid, uint32_t eventid, ItsCmdType cmd) { DTEntry dte; - CTEntry cte; ITEntry ite; ItsCmdResult cmdres; + int irqlevel; cmdres = lookup_ite(s, __func__, devid, eventid, &ite, &dte); if (cmdres != CMD_CONTINUE_OK) { return cmdres; } - if (ite.inttype != ITE_INTTYPE_PHYSICAL) { - qemu_log_mask(LOG_GUEST_ERROR, - "%s: invalid command attributes: invalid ITE\n", - __func__); - return CMD_CONTINUE; - } - - cmdres = lookup_cte(s, __func__, ite.icid, &cte); - if (cmdres != CMD_CONTINUE_OK) { - return cmdres; - } + irqlevel = (cmd == CLEAR || cmd == DISCARD) ? 0 : 1; - if ((cmd == CLEAR) || (cmd == DISCARD)) { - gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid, 0); - } else { - gicv3_redist_process_lpi(&s->gicv3->cpu[cte.rdbase], ite.intid, 1); + switch (ite.inttype) { + case ITE_INTTYPE_PHYSICAL: + cmdres = process_its_cmd_phys(s, &ite, irqlevel); + break; + case ITE_INTTYPE_VIRTUAL: + if (!its_feature_virtual(s)) { + /* Can't happen unless guest is illegally writing to table memory */ + qemu_log_mask(LOG_GUEST_ERROR, + "%s: invalid type %d in ITE (table corrupted?)\n", + __func__, ite.inttype); + return CMD_CONTINUE; + } + /* The GICv4 virtual interrupt handling will go here */ + g_assert_not_reached(); + default: + g_assert_not_reached(); } - if (cmd == DISCARD) { + if (cmdres == CMD_CONTINUE_OK && cmd == DISCARD) { ITEntry ite = {}; /* remove mapping from interrupt translation table */ ite.valid = false; |