1*2861c740SAlexandru Elisei #include <libcflat.h> 2*2861c740SAlexandru Elisei #include <alloc_page.h> 3*2861c740SAlexandru Elisei #include <asm/mmu.h> 4*2861c740SAlexandru Elisei #include <asm/processor.h> 5*2861c740SAlexandru Elisei 6*2861c740SAlexandru Elisei #define NTIMES (1 << 16) 7*2861c740SAlexandru Elisei 8*2861c740SAlexandru Elisei #define CTR_DIC (1UL << 29) 9*2861c740SAlexandru Elisei #define CTR_IDC (1UL << 28) 10*2861c740SAlexandru Elisei 11*2861c740SAlexandru Elisei #define CLIDR_LOC_SHIFT 24 12*2861c740SAlexandru Elisei #define CLIDR_LOC_MASK (7UL << CLIDR_LOC_SHIFT) 13*2861c740SAlexandru Elisei #define CLIDR_LOUU_SHIFT 27 14*2861c740SAlexandru Elisei #define CLIDR_LOUU_MASK (7UL << CLIDR_LOUU_SHIFT) 15*2861c740SAlexandru Elisei #define CLIDR_LOUIS_SHIFT 21 16*2861c740SAlexandru Elisei #define CLIDR_LOUIS_MASK (7UL << CLIDR_LOUIS_SHIFT) 17*2861c740SAlexandru Elisei 18*2861c740SAlexandru Elisei #define RET 0xd65f03c0 19*2861c740SAlexandru Elisei #define MOV_X0(x) (0xd2800000 | (((x) & 0xffff) << 5)) 20*2861c740SAlexandru Elisei 21*2861c740SAlexandru Elisei #define clean_dcache_pou(addr) \ 22*2861c740SAlexandru Elisei asm volatile("dc cvau, %0\n" :: "r" (addr) : "memory") 23*2861c740SAlexandru Elisei #define inval_icache_pou(addr) \ 24*2861c740SAlexandru Elisei asm volatile("ic ivau, %0\n" :: "r" (addr) : "memory") 25*2861c740SAlexandru Elisei 26*2861c740SAlexandru Elisei typedef int (*fn_t)(void); 27*2861c740SAlexandru Elisei 28*2861c740SAlexandru Elisei static inline void prime_icache(u32 *code, u32 insn) 29*2861c740SAlexandru Elisei { 30*2861c740SAlexandru Elisei *code = insn; 31*2861c740SAlexandru Elisei /* This is the sequence recommended in ARM DDI 0487E.a, page B2-136. */ 32*2861c740SAlexandru Elisei clean_dcache_pou(code); 33*2861c740SAlexandru Elisei dsb(ish); 34*2861c740SAlexandru Elisei inval_icache_pou(code); 35*2861c740SAlexandru Elisei dsb(ish); 36*2861c740SAlexandru Elisei isb(); 37*2861c740SAlexandru Elisei 38*2861c740SAlexandru Elisei ((fn_t)code)(); 39*2861c740SAlexandru Elisei } 40*2861c740SAlexandru Elisei 41*2861c740SAlexandru Elisei static void check_code_generation(bool dcache_clean, bool icache_inval) 42*2861c740SAlexandru Elisei { 43*2861c740SAlexandru Elisei u32 fn[] = {MOV_X0(0x42), RET}; 44*2861c740SAlexandru Elisei u32 *code = alloc_page(); 45*2861c740SAlexandru Elisei unsigned long sctlr; 46*2861c740SAlexandru Elisei int i, ret; 47*2861c740SAlexandru Elisei bool success; 48*2861c740SAlexandru Elisei 49*2861c740SAlexandru Elisei /* Make sure we can execute from a writable page */ 50*2861c740SAlexandru Elisei mmu_clear_user((unsigned long)code); 51*2861c740SAlexandru Elisei 52*2861c740SAlexandru Elisei sctlr = read_sysreg(sctlr_el1); 53*2861c740SAlexandru Elisei if (sctlr & SCTLR_EL1_WXN) { 54*2861c740SAlexandru Elisei sctlr &= ~SCTLR_EL1_WXN; 55*2861c740SAlexandru Elisei write_sysreg(sctlr, sctlr_el1); 56*2861c740SAlexandru Elisei isb(); 57*2861c740SAlexandru Elisei /* SCTLR_EL1.WXN is permitted to be cached in a TLB. */ 58*2861c740SAlexandru Elisei flush_tlb_all(); 59*2861c740SAlexandru Elisei } 60*2861c740SAlexandru Elisei 61*2861c740SAlexandru Elisei for (i = 0; i < ARRAY_SIZE(fn); i++) { 62*2861c740SAlexandru Elisei *(code + i) = fn[i]; 63*2861c740SAlexandru Elisei clean_dcache_pou(code + i); 64*2861c740SAlexandru Elisei dsb(ish); 65*2861c740SAlexandru Elisei inval_icache_pou(code + i); 66*2861c740SAlexandru Elisei } 67*2861c740SAlexandru Elisei dsb(ish); 68*2861c740SAlexandru Elisei isb(); 69*2861c740SAlexandru Elisei 70*2861c740SAlexandru Elisei /* Sanity check */ 71*2861c740SAlexandru Elisei ((fn_t)code)(); 72*2861c740SAlexandru Elisei 73*2861c740SAlexandru Elisei success = true; 74*2861c740SAlexandru Elisei for (i = 0; i < NTIMES; i++) { 75*2861c740SAlexandru Elisei prime_icache(code, MOV_X0(0x42)); 76*2861c740SAlexandru Elisei *code = MOV_X0(0x66); 77*2861c740SAlexandru Elisei if (dcache_clean) 78*2861c740SAlexandru Elisei clean_dcache_pou(code); 79*2861c740SAlexandru Elisei if (icache_inval) { 80*2861c740SAlexandru Elisei if (dcache_clean) 81*2861c740SAlexandru Elisei dsb(ish); 82*2861c740SAlexandru Elisei inval_icache_pou(code); 83*2861c740SAlexandru Elisei } 84*2861c740SAlexandru Elisei dsb(ish); 85*2861c740SAlexandru Elisei isb(); 86*2861c740SAlexandru Elisei 87*2861c740SAlexandru Elisei ret = ((fn_t)code)(); 88*2861c740SAlexandru Elisei success &= (ret == 0x66); 89*2861c740SAlexandru Elisei } 90*2861c740SAlexandru Elisei 91*2861c740SAlexandru Elisei report("code generation", success); 92*2861c740SAlexandru Elisei } 93*2861c740SAlexandru Elisei 94*2861c740SAlexandru Elisei int main(int argc, char **argv) 95*2861c740SAlexandru Elisei { 96*2861c740SAlexandru Elisei u64 ctr, clidr; 97*2861c740SAlexandru Elisei bool dcache_clean, icache_inval; 98*2861c740SAlexandru Elisei 99*2861c740SAlexandru Elisei report_prefix_push("IDC-DIC"); 100*2861c740SAlexandru Elisei 101*2861c740SAlexandru Elisei ctr = read_sysreg(ctr_el0); 102*2861c740SAlexandru Elisei dcache_clean = !(ctr & CTR_IDC); 103*2861c740SAlexandru Elisei icache_inval = !(ctr & CTR_DIC); 104*2861c740SAlexandru Elisei 105*2861c740SAlexandru Elisei if (dcache_clean) { 106*2861c740SAlexandru Elisei clidr = read_sysreg(clidr_el1); 107*2861c740SAlexandru Elisei if ((clidr & CLIDR_LOC_MASK) == 0) 108*2861c740SAlexandru Elisei dcache_clean = false; 109*2861c740SAlexandru Elisei if ((clidr & CLIDR_LOUU_MASK) == 0 && 110*2861c740SAlexandru Elisei (clidr & CLIDR_LOUIS_MASK) == 0) 111*2861c740SAlexandru Elisei dcache_clean = false; 112*2861c740SAlexandru Elisei } 113*2861c740SAlexandru Elisei 114*2861c740SAlexandru Elisei if (dcache_clean) 115*2861c740SAlexandru Elisei report_info("dcache clean to PoU required"); 116*2861c740SAlexandru Elisei if (icache_inval) 117*2861c740SAlexandru Elisei report_info("icache invalidation to PoU required"); 118*2861c740SAlexandru Elisei 119*2861c740SAlexandru Elisei check_code_generation(dcache_clean, icache_inval); 120*2861c740SAlexandru Elisei 121*2861c740SAlexandru Elisei return report_summary(); 122*2861c740SAlexandru Elisei } 123