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