xref: /kvm-unit-tests/x86/pks.c (revision fdae60923708e2d995c44f9e653ee5fdd3bdbaf8)
1*fdae6092SChenyi Qiang #include "libcflat.h"
2*fdae6092SChenyi Qiang #include <alloc_page.h>
3*fdae6092SChenyi Qiang #include "x86/desc.h"
4*fdae6092SChenyi Qiang #include "x86/processor.h"
5*fdae6092SChenyi Qiang #include "x86/vm.h"
6*fdae6092SChenyi Qiang #include "x86/msr.h"
7*fdae6092SChenyi Qiang 
8*fdae6092SChenyi Qiang #define CR0_WP_MASK      (1UL << 16)
9*fdae6092SChenyi Qiang #define PTE_PKEY_BIT     59
10*fdae6092SChenyi Qiang #define SUPER_BASE        (1 << 23)
11*fdae6092SChenyi Qiang #define SUPER_VAR(v)      (*((__typeof__(&(v))) (((unsigned long)&v) + SUPER_BASE)))
12*fdae6092SChenyi Qiang 
13*fdae6092SChenyi Qiang volatile int pf_count = 0;
14*fdae6092SChenyi Qiang volatile unsigned save;
15*fdae6092SChenyi Qiang volatile unsigned test;
16*fdae6092SChenyi Qiang 
17*fdae6092SChenyi Qiang static void set_cr0_wp(int wp)
18*fdae6092SChenyi Qiang {
19*fdae6092SChenyi Qiang     unsigned long cr0 = read_cr0();
20*fdae6092SChenyi Qiang 
21*fdae6092SChenyi Qiang     cr0 &= ~CR0_WP_MASK;
22*fdae6092SChenyi Qiang     if (wp)
23*fdae6092SChenyi Qiang         cr0 |= CR0_WP_MASK;
24*fdae6092SChenyi Qiang     write_cr0(cr0);
25*fdae6092SChenyi Qiang }
26*fdae6092SChenyi Qiang 
27*fdae6092SChenyi Qiang void do_pf_tss(unsigned long error_code);
28*fdae6092SChenyi Qiang void do_pf_tss(unsigned long error_code)
29*fdae6092SChenyi Qiang {
30*fdae6092SChenyi Qiang     printf("#PF handler, error code: 0x%lx\n", error_code);
31*fdae6092SChenyi Qiang     pf_count++;
32*fdae6092SChenyi Qiang     save = test;
33*fdae6092SChenyi Qiang     wrmsr(MSR_IA32_PKRS, 0);
34*fdae6092SChenyi Qiang }
35*fdae6092SChenyi Qiang 
36*fdae6092SChenyi Qiang extern void pf_tss(void);
37*fdae6092SChenyi Qiang 
38*fdae6092SChenyi Qiang asm ("pf_tss: \n\t"
39*fdae6092SChenyi Qiang #ifdef __x86_64__
40*fdae6092SChenyi Qiang     // no task on x86_64, save/restore caller-save regs
41*fdae6092SChenyi Qiang     "push %rax; push %rcx; push %rdx; push %rsi; push %rdi\n"
42*fdae6092SChenyi Qiang     "push %r8; push %r9; push %r10; push %r11\n"
43*fdae6092SChenyi Qiang     "mov 9*8(%rsp), %rdi\n"
44*fdae6092SChenyi Qiang #endif
45*fdae6092SChenyi Qiang     "call do_pf_tss \n\t"
46*fdae6092SChenyi Qiang #ifdef __x86_64__
47*fdae6092SChenyi Qiang     "pop %r11; pop %r10; pop %r9; pop %r8\n"
48*fdae6092SChenyi Qiang     "pop %rdi; pop %rsi; pop %rdx; pop %rcx; pop %rax\n"
49*fdae6092SChenyi Qiang #endif
50*fdae6092SChenyi Qiang     "add $"S", %"R "sp\n\t" // discard error code
51*fdae6092SChenyi Qiang     "iret"W" \n\t"
52*fdae6092SChenyi Qiang     "jmp pf_tss\n\t"
53*fdae6092SChenyi Qiang     );
54*fdae6092SChenyi Qiang 
55*fdae6092SChenyi Qiang static void init_test(void)
56*fdae6092SChenyi Qiang {
57*fdae6092SChenyi Qiang     pf_count = 0;
58*fdae6092SChenyi Qiang 
59*fdae6092SChenyi Qiang     invlpg(&test);
60*fdae6092SChenyi Qiang     invlpg(&SUPER_VAR(test));
61*fdae6092SChenyi Qiang     wrmsr(MSR_IA32_PKRS, 0);
62*fdae6092SChenyi Qiang     set_cr0_wp(0);
63*fdae6092SChenyi Qiang }
64*fdae6092SChenyi Qiang 
65*fdae6092SChenyi Qiang int main(int ac, char **av)
66*fdae6092SChenyi Qiang {
67*fdae6092SChenyi Qiang     unsigned long i;
68*fdae6092SChenyi Qiang     unsigned int pkey = 0x2;
69*fdae6092SChenyi Qiang     unsigned int pkrs_ad = 0x10;
70*fdae6092SChenyi Qiang     unsigned int pkrs_wd = 0x20;
71*fdae6092SChenyi Qiang 
72*fdae6092SChenyi Qiang     if (!this_cpu_has(X86_FEATURE_PKS)) {
73*fdae6092SChenyi Qiang         printf("PKS not enabled\n");
74*fdae6092SChenyi Qiang         return report_summary();
75*fdae6092SChenyi Qiang     }
76*fdae6092SChenyi Qiang 
77*fdae6092SChenyi Qiang     setup_vm();
78*fdae6092SChenyi Qiang     setup_alt_stack();
79*fdae6092SChenyi Qiang     set_intr_alt_stack(14, pf_tss);
80*fdae6092SChenyi Qiang     wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_LMA);
81*fdae6092SChenyi Qiang 
82*fdae6092SChenyi Qiang     if (reserve_pages(SUPER_BASE, SUPER_BASE >> 12))
83*fdae6092SChenyi Qiang         report_abort("Could not reserve memory");
84*fdae6092SChenyi Qiang 
85*fdae6092SChenyi Qiang     for (i = 0; i < SUPER_BASE; i += PAGE_SIZE) {
86*fdae6092SChenyi Qiang         *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) |= ((unsigned long)pkey << PTE_PKEY_BIT);
87*fdae6092SChenyi Qiang         invlpg((void *)i);
88*fdae6092SChenyi Qiang     }
89*fdae6092SChenyi Qiang 
90*fdae6092SChenyi Qiang     // Present the same 16MB as supervisor pages in the 16MB-32MB range
91*fdae6092SChenyi Qiang     for (i = SUPER_BASE; i < 2 * SUPER_BASE; i += PAGE_SIZE) {
92*fdae6092SChenyi Qiang         *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) &= ~SUPER_BASE;
93*fdae6092SChenyi Qiang         *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) &= ~PT_USER_MASK;
94*fdae6092SChenyi Qiang         *get_pte(phys_to_virt(read_cr3()), phys_to_virt(i)) |= ((unsigned long)pkey << PTE_PKEY_BIT);
95*fdae6092SChenyi Qiang         invlpg((void *)i);
96*fdae6092SChenyi Qiang     }
97*fdae6092SChenyi Qiang 
98*fdae6092SChenyi Qiang     write_cr4(read_cr4() | X86_CR4_PKS);
99*fdae6092SChenyi Qiang     write_cr3(read_cr3());
100*fdae6092SChenyi Qiang 
101*fdae6092SChenyi Qiang     init_test();
102*fdae6092SChenyi Qiang     set_cr0_wp(1);
103*fdae6092SChenyi Qiang     wrmsr(MSR_IA32_PKRS, pkrs_ad);
104*fdae6092SChenyi Qiang     SUPER_VAR(test) = 21;
105*fdae6092SChenyi Qiang     report(pf_count == 1 && test == 21 && save == 0,
106*fdae6092SChenyi Qiang            "write to supervisor page when pkrs is ad and wp == 1");
107*fdae6092SChenyi Qiang 
108*fdae6092SChenyi Qiang     init_test();
109*fdae6092SChenyi Qiang     set_cr0_wp(0);
110*fdae6092SChenyi Qiang     wrmsr(MSR_IA32_PKRS, pkrs_ad);
111*fdae6092SChenyi Qiang     SUPER_VAR(test) = 22;
112*fdae6092SChenyi Qiang     report(pf_count == 1 && test == 22 && save == 21,
113*fdae6092SChenyi Qiang            "write to supervisor page when pkrs is ad and wp == 0");
114*fdae6092SChenyi Qiang 
115*fdae6092SChenyi Qiang     init_test();
116*fdae6092SChenyi Qiang     set_cr0_wp(1);
117*fdae6092SChenyi Qiang     wrmsr(MSR_IA32_PKRS, pkrs_wd);
118*fdae6092SChenyi Qiang     SUPER_VAR(test) = 23;
119*fdae6092SChenyi Qiang     report(pf_count == 1 && test == 23 && save == 22,
120*fdae6092SChenyi Qiang            "write to supervisor page when pkrs is wd and wp == 1");
121*fdae6092SChenyi Qiang 
122*fdae6092SChenyi Qiang     init_test();
123*fdae6092SChenyi Qiang     set_cr0_wp(0);
124*fdae6092SChenyi Qiang     wrmsr(MSR_IA32_PKRS, pkrs_wd);
125*fdae6092SChenyi Qiang     SUPER_VAR(test) = 24;
126*fdae6092SChenyi Qiang     report(pf_count == 0 && test == 24,
127*fdae6092SChenyi Qiang            "write to supervisor page when pkrs is wd and wp == 0");
128*fdae6092SChenyi Qiang 
129*fdae6092SChenyi Qiang     init_test();
130*fdae6092SChenyi Qiang     set_cr0_wp(0);
131*fdae6092SChenyi Qiang     wrmsr(MSR_IA32_PKRS, pkrs_wd);
132*fdae6092SChenyi Qiang     test = 25;
133*fdae6092SChenyi Qiang     report(pf_count == 0 && test == 25,
134*fdae6092SChenyi Qiang            "write to user page when pkrs is wd and wp == 0");
135*fdae6092SChenyi Qiang 
136*fdae6092SChenyi Qiang     init_test();
137*fdae6092SChenyi Qiang     set_cr0_wp(1);
138*fdae6092SChenyi Qiang     wrmsr(MSR_IA32_PKRS, pkrs_wd);
139*fdae6092SChenyi Qiang     test = 26;
140*fdae6092SChenyi Qiang     report(pf_count == 0 && test == 26,
141*fdae6092SChenyi Qiang            "write to user page when pkrs is wd and wp == 1");
142*fdae6092SChenyi Qiang 
143*fdae6092SChenyi Qiang     init_test();
144*fdae6092SChenyi Qiang     wrmsr(MSR_IA32_PKRS, pkrs_ad);
145*fdae6092SChenyi Qiang     (void)((__typeof__(&(test))) (((unsigned long)&test)));
146*fdae6092SChenyi Qiang     report(pf_count == 0, "read from user page when pkrs is ad");
147*fdae6092SChenyi Qiang 
148*fdae6092SChenyi Qiang     return report_summary();
149*fdae6092SChenyi Qiang }
150