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