Reference reference
All memory translation requests finally invokes a callback func env->tlb->map_address
Example code:
// target/mips/helper.c
static int get_seg_physical_address(CPUMIPSState *env, hwaddr *physical,
int *prot, target_ulong real_address,
int rw, int access_type, int mmu_idx,
unsigned int am, bool eu,
target_ulong segmask,
hwaddr physical_base)
{
int ret;
int mapped = is_seg_am_mapped(am, eu, mmu_idx);
if (mapped < 0) {
/* is_seg_am_mapped can report TLBRET_BADADDR */
return mapped;
} else if (mapped) {
/* The segment is TLB mapped */
ret = env->tlb->map_address(env, physical, prot, real_address, rw,
access_type);
} else {
/* The segment is unmapped */
*physical = physical_base | (real_address & segmask);
*prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
ret = TLBRET_MATCH;
}
return ret;
}
env->tlb->map_address
is assigned in translate_init.inc.c
:
// target/mips/translate_init.inc.c
static void r4k_mmu_init (CPUMIPSState *env, const mips_def_t *def)
{
env->tlb->nb_tlb = 1 + ((def->CP0_Config1 >> CP0C1_MMU) & 63);
env->tlb->map_address = &r4k_map_address;
env->tlb->helper_tlbwi = r4k_helper_tlbwi;
env->tlb->helper_tlbwr = r4k_helper_tlbwr;
env->tlb->helper_tlbp = r4k_helper_tlbp;
env->tlb->helper_tlbr = r4k_helper_tlbr;
env->tlb->helper_tlbinv = r4k_helper_tlbinv;
env->tlb->helper_tlbinvf = r4k_helper_tlbinvf;
qemu_printf("env->tlb->map_address = &r4k_map_address;\n");
}
definition of r4k_map_address
in MIPS helper.c
:
// target/mips/helper.c
/* MIPS32/MIPS64 R4000-style MMU emulation */
int r4k_map_address(CPUMIPSState *env, hwaddr *physical, int *prot,
target_ulong address, int rw, int access_type)
{
uint16_t ASID = env->CP0_EntryHi & env->CP0_EntryHi_ASID_mask;
uint32_t MMID = env->CP0_MemoryMapID;
bool mi = !!((env->CP0_Config5 >> CP0C5_MI) & 1);
uint32_t tlb_mmid;
int i;
MMID = mi ? MMID : (uint32_t) ASID;
#if defined(TARGET_CHERI)
unsigned gclg_bit;
if (address < 0x4000000000000000) {
/* useg, xuseg */
gclg_bit = CP0EnHi_CLGU;
} else if (address < 0x8000000000000000) {
/* xsseg */
gclg_bit = CP0EnHi_CLGS;
} else if (address < 0xFFFFFFFFC0000000) {
/* xkphys (won't be called), xkseg, kseg0, kseg1 */
gclg_bit = CP0EnHi_CLGK;
} else if (address < 0xFFFFFFFFE0000000) {
/* sseg */
gclg_bit = CP0EnHi_CLGS;
} else {
/* kseg3 */
gclg_bit = CP0EnHi_CLGK;
}
bool gclg = !!(env->CP0_EntryHi & (1UL << gclg_bit));
#endif
for (i = 0; i < env->tlb->tlb_in_use; i++) {
r4k_tlb_t *tlb = &env->tlb->mmu.r4k.tlb[i];
/* 1k pages are not supported. */
target_ulong mask = tlb->PageMask | ~(TARGET_PAGE_MASK << 1);
target_ulong tag = address & ~mask;
target_ulong VPN = tlb->VPN & ~mask;
#if defined(TARGET_MIPS64)
tag &= env->SEGMask;
#endif
/* Check ASID/MMID, virtual page number & size */
tlb_mmid = mi ? tlb->MMID : (uint32_t) tlb->ASID;
if ((tlb->G == 1 || tlb_mmid == MMID) && VPN == tag && !tlb->EHINV) {
/* TLB match */
int n = !!(address & mask & ~(mask >> 1));
/* Check access rights */
if (!(n ? tlb->V1 : tlb->V0)) {
return TLBRET_INVALID;
}
#if defined(TARGET_CHERI)
if (rw == MMU_DATA_CAP_STORE) {
/*
* If we're trying to do a cap-store, first check for the
* dirty/store-permitted bit before looking at the the
* store-capability inhibit.
*/
if (!(n ? tlb->D1 : tlb->D0)) {
// printf("failed checking the dirty/store-permitted bit in TLB\n");
return TLBRET_DIRTY;
}
if (n ? tlb->S1 : tlb->S0) {
// printf("failed checking the dirty/store-permitted bit in TLB\n");
return TLBRET_S;
}
}
#else
if (rw == MMU_INST_FETCH && (n ? tlb->XI1 : tlb->XI0)) {
return TLBRET_XI;
}
if (rw == MMU_DATA_LOAD && (n ? tlb->RI1 : tlb->RI0)) {
return TLBRET_RI;
}
#endif /* TARGET_CHERI */
if (( (rw != MMU_DATA_STORE)
#if defined(TARGET_CHERI)
&& (rw != MMU_DATA_CAP_STORE)
#endif
) || (n ? tlb->D1 : tlb->D0)) {
*physical = tlb->PFN[n] | (address & (mask >> 1));
*prot = PAGE_READ;
if (n ? tlb->D1 : tlb->D0) {
*prot |= PAGE_WRITE;
}
#if !defined(TARGET_CHERI)
if (!(n ? tlb->XI1 : tlb->XI0)) {
#else
if (true) {
#endif
*prot |= PAGE_EXEC;
}
#if defined(TARGET_CHERI)
if (n ? tlb->L1 : tlb->L0) {
*prot |= PAGE_LC_CLEAR;
}
bool pclg = n ? tlb->CLG1 : tlb->CLG0;
if (pclg != gclg) {
*prot |= PAGE_LC_TRAP;
}
#endif
return TLBRET_MATCH;
}
return TLBRET_DIRTY;
}
}
return TLBRET_NOMATCH;
}
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?