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
prime_icache(u32 * code,u32 insn)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
check_code_generation(bool dcache_clean,bool icache_inval)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
main(int argc,char ** argv)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