target/hppa: fix access_id check

PA2.0 provides 8 instead of 4 PID registers.

Signed-off-by: Sven Schnelle <svens@stackframe.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Message-Id: <20240319161921.487080-4-svens@stackframe.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
This commit is contained in:
Sven Schnelle 2024-03-19 17:19:18 +01:00 committed by Richard Henderson
parent d37fad0ae5
commit ae157fc250

View File

@ -152,6 +152,49 @@ static HPPATLBEntry *hppa_alloc_tlb_ent(CPUHPPAState *env)
return ent;
}
#define ACCESS_ID_MASK 0xffff
/* Return the set of protections allowed by a PID match. */
static int match_prot_id_1(uint32_t access_id, uint32_t prot_id)
{
if (((access_id ^ (prot_id >> 1)) & ACCESS_ID_MASK) == 0) {
return (prot_id & 1
? PAGE_EXEC | PAGE_READ
: PAGE_EXEC | PAGE_READ | PAGE_WRITE);
}
return 0;
}
static int match_prot_id32(CPUHPPAState *env, uint32_t access_id)
{
int r, i;
for (i = CR_PID1; i <= CR_PID4; ++i) {
r = match_prot_id_1(access_id, env->cr[i]);
if (r) {
return r;
}
}
return 0;
}
static int match_prot_id64(CPUHPPAState *env, uint32_t access_id)
{
int r, i;
for (i = CR_PID1; i <= CR_PID4; ++i) {
r = match_prot_id_1(access_id, env->cr[i]);
if (r) {
return r;
}
r = match_prot_id_1(access_id, env->cr[i] >> 32);
if (r) {
return r;
}
}
return 0;
}
int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
int type, hwaddr *pphys, int *pprot,
HPPATLBEntry **tlb_entry)
@ -224,29 +267,30 @@ int hppa_get_physical_address(CPUHPPAState *env, vaddr addr, int mmu_idx,
break;
}
/* access_id == 0 means public page and no check is performed */
if (ent->access_id && MMU_IDX_TO_P(mmu_idx)) {
/* If bits [31:1] match, and bit 0 is set, suppress write. */
int match = ent->access_id * 2 + 1;
if (match == env->cr[CR_PID1] || match == env->cr[CR_PID2] ||
match == env->cr[CR_PID3] || match == env->cr[CR_PID4]) {
prot &= PAGE_READ | PAGE_EXEC;
if (type == PAGE_WRITE) {
ret = EXCP_DMPI;
goto egress;
}
}
}
/* No guest access type indicates a non-architectural access from
within QEMU. Bypass checks for access, D, B and T bits. */
/*
* No guest access type indicates a non-architectural access from
* within QEMU. Bypass checks for access, D, B, P and T bits.
*/
if (type == 0) {
goto egress;
}
/* access_id == 0 means public page and no check is performed */
if (ent->access_id && MMU_IDX_TO_P(mmu_idx)) {
int access_prot = (hppa_is_pa20(env)
? match_prot_id64(env, ent->access_id)
: match_prot_id32(env, ent->access_id));
if (unlikely(!(type & access_prot))) {
/* Not allowed -- Inst/Data Memory Protection Id Fault. */
ret = type & PAGE_EXEC ? EXCP_IMP : EXCP_DMPI;
goto egress;
}
/* Otherwise exclude permissions not allowed (i.e WD). */
prot &= access_prot;
}
if (unlikely(!(prot & type))) {
/* The access isn't allowed -- Inst/Data Memory Protection Fault. */
/* Not allowed -- Inst/Data Memory Access Rights Fault. */
ret = (type & PAGE_EXEC) ? EXCP_IMP : EXCP_DMAR;
goto egress;
}