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