Addr Trans

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;
}

More

Created Aug 12, 2020 // Last Updated May 18, 2021

If you could revise
the fundmental principles of
computer system design
to improve security...

... what would you change?