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