12861c740SAlexandru Elisei #include <libcflat.h> 22861c740SAlexandru Elisei #include <alloc_page.h> 32861c740SAlexandru Elisei #include <asm/mmu.h> 42861c740SAlexandru Elisei #include <asm/processor.h> 52861c740SAlexandru Elisei 62861c740SAlexandru Elisei #define NTIMES (1 << 16) 72861c740SAlexandru Elisei 82861c740SAlexandru Elisei #define CTR_DIC (1UL << 29) 92861c740SAlexandru Elisei #define CTR_IDC (1UL << 28) 102861c740SAlexandru Elisei 112861c740SAlexandru Elisei #define CLIDR_LOC_SHIFT 24 122861c740SAlexandru Elisei #define CLIDR_LOC_MASK (7UL << CLIDR_LOC_SHIFT) 132861c740SAlexandru Elisei #define CLIDR_LOUU_SHIFT 27 142861c740SAlexandru Elisei #define CLIDR_LOUU_MASK (7UL << CLIDR_LOUU_SHIFT) 152861c740SAlexandru Elisei #define CLIDR_LOUIS_SHIFT 21 162861c740SAlexandru Elisei #define CLIDR_LOUIS_MASK (7UL << CLIDR_LOUIS_SHIFT) 172861c740SAlexandru Elisei 182861c740SAlexandru Elisei #define RET 0xd65f03c0 192861c740SAlexandru Elisei #define MOV_X0(x) (0xd2800000 | (((x) & 0xffff) << 5)) 202861c740SAlexandru Elisei 212861c740SAlexandru Elisei #define clean_dcache_pou(addr) \ 222861c740SAlexandru Elisei asm volatile("dc cvau, %0\n" :: "r" (addr) : "memory") 232861c740SAlexandru Elisei #define inval_icache_pou(addr) \ 242861c740SAlexandru Elisei asm volatile("ic ivau, %0\n" :: "r" (addr) : "memory") 252861c740SAlexandru Elisei 262861c740SAlexandru Elisei typedef int (*fn_t)(void); 272861c740SAlexandru Elisei 282861c740SAlexandru Elisei static inline void prime_icache(u32 *code, u32 insn) 292861c740SAlexandru Elisei { 302861c740SAlexandru Elisei *code = insn; 312861c740SAlexandru Elisei /* This is the sequence recommended in ARM DDI 0487E.a, page B2-136. */ 322861c740SAlexandru Elisei clean_dcache_pou(code); 332861c740SAlexandru Elisei dsb(ish); 342861c740SAlexandru Elisei inval_icache_pou(code); 352861c740SAlexandru Elisei dsb(ish); 362861c740SAlexandru Elisei isb(); 372861c740SAlexandru Elisei 382861c740SAlexandru Elisei ((fn_t)code)(); 392861c740SAlexandru Elisei } 402861c740SAlexandru Elisei 412861c740SAlexandru Elisei static void check_code_generation(bool dcache_clean, bool icache_inval) 422861c740SAlexandru Elisei { 432861c740SAlexandru Elisei u32 fn[] = {MOV_X0(0x42), RET}; 442861c740SAlexandru Elisei u32 *code = alloc_page(); 452861c740SAlexandru Elisei unsigned long sctlr; 462861c740SAlexandru Elisei int i, ret; 472861c740SAlexandru Elisei bool success; 482861c740SAlexandru Elisei 492861c740SAlexandru Elisei /* Make sure we can execute from a writable page */ 502861c740SAlexandru Elisei mmu_clear_user((unsigned long)code); 512861c740SAlexandru Elisei 522861c740SAlexandru Elisei sctlr = read_sysreg(sctlr_el1); 532861c740SAlexandru Elisei if (sctlr & SCTLR_EL1_WXN) { 542861c740SAlexandru Elisei sctlr &= ~SCTLR_EL1_WXN; 552861c740SAlexandru Elisei write_sysreg(sctlr, sctlr_el1); 562861c740SAlexandru Elisei isb(); 572861c740SAlexandru Elisei /* SCTLR_EL1.WXN is permitted to be cached in a TLB. */ 582861c740SAlexandru Elisei flush_tlb_all(); 592861c740SAlexandru Elisei } 602861c740SAlexandru Elisei 612861c740SAlexandru Elisei for (i = 0; i < ARRAY_SIZE(fn); i++) { 622861c740SAlexandru Elisei *(code + i) = fn[i]; 632861c740SAlexandru Elisei clean_dcache_pou(code + i); 642861c740SAlexandru Elisei dsb(ish); 652861c740SAlexandru Elisei inval_icache_pou(code + i); 662861c740SAlexandru Elisei } 672861c740SAlexandru Elisei dsb(ish); 682861c740SAlexandru Elisei isb(); 692861c740SAlexandru Elisei 702861c740SAlexandru Elisei /* Sanity check */ 712861c740SAlexandru Elisei ((fn_t)code)(); 722861c740SAlexandru Elisei 732861c740SAlexandru Elisei success = true; 742861c740SAlexandru Elisei for (i = 0; i < NTIMES; i++) { 752861c740SAlexandru Elisei prime_icache(code, MOV_X0(0x42)); 762861c740SAlexandru Elisei *code = MOV_X0(0x66); 772861c740SAlexandru Elisei if (dcache_clean) 782861c740SAlexandru Elisei clean_dcache_pou(code); 792861c740SAlexandru Elisei if (icache_inval) { 802861c740SAlexandru Elisei if (dcache_clean) 812861c740SAlexandru Elisei dsb(ish); 822861c740SAlexandru Elisei inval_icache_pou(code); 832861c740SAlexandru Elisei } 842861c740SAlexandru Elisei dsb(ish); 852861c740SAlexandru Elisei isb(); 862861c740SAlexandru Elisei 872861c740SAlexandru Elisei ret = ((fn_t)code)(); 882861c740SAlexandru Elisei success &= (ret == 0x66); 892861c740SAlexandru Elisei } 902861c740SAlexandru Elisei 91*a299895bSThomas Huth report(success, "code generation"); 922861c740SAlexandru Elisei } 932861c740SAlexandru Elisei 942861c740SAlexandru Elisei int main(int argc, char **argv) 952861c740SAlexandru Elisei { 962861c740SAlexandru Elisei u64 ctr, clidr; 972861c740SAlexandru Elisei bool dcache_clean, icache_inval; 982861c740SAlexandru Elisei 992861c740SAlexandru Elisei report_prefix_push("IDC-DIC"); 1002861c740SAlexandru Elisei 1012861c740SAlexandru Elisei ctr = read_sysreg(ctr_el0); 1022861c740SAlexandru Elisei dcache_clean = !(ctr & CTR_IDC); 1032861c740SAlexandru Elisei icache_inval = !(ctr & CTR_DIC); 1042861c740SAlexandru Elisei 1052861c740SAlexandru Elisei if (dcache_clean) { 1062861c740SAlexandru Elisei clidr = read_sysreg(clidr_el1); 1072861c740SAlexandru Elisei if ((clidr & CLIDR_LOC_MASK) == 0) 1082861c740SAlexandru Elisei dcache_clean = false; 1092861c740SAlexandru Elisei if ((clidr & CLIDR_LOUU_MASK) == 0 && 1102861c740SAlexandru Elisei (clidr & CLIDR_LOUIS_MASK) == 0) 1112861c740SAlexandru Elisei dcache_clean = false; 1122861c740SAlexandru Elisei } 1132861c740SAlexandru Elisei 1142861c740SAlexandru Elisei if (dcache_clean) 1152861c740SAlexandru Elisei report_info("dcache clean to PoU required"); 1162861c740SAlexandru Elisei if (icache_inval) 1172861c740SAlexandru Elisei report_info("icache invalidation to PoU required"); 1182861c740SAlexandru Elisei 1192861c740SAlexandru Elisei check_code_generation(dcache_clean, icache_inval); 1202861c740SAlexandru Elisei 1212861c740SAlexandru Elisei return report_summary(); 1222861c740SAlexandru Elisei } 123