blob: bda15efc546da006f0c659a23f5ff86bec4ea236 [file] [log] [blame]
Chenyi Qiangfdae6092020-11-05 16:18:05 +08001#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
Chenyi Qiangfdae6092020-11-05 16:18:05 +08008#define PTE_PKEY_BIT 59
9#define SUPER_BASE (1 << 23)
10#define SUPER_VAR(v) (*((__typeof__(&(v))) (((unsigned long)&v) + SUPER_BASE)))
11
12volatile int pf_count = 0;
13volatile unsigned save;
14volatile unsigned test;
15
16static void set_cr0_wp(int wp)
17{
18 unsigned long cr0 = read_cr0();
19
Mathias Krause3ba5c212023-04-04 09:53:32 -070020 cr0 &= ~X86_CR0_WP;
Chenyi Qiangfdae6092020-11-05 16:18:05 +080021 if (wp)
Mathias Krause3ba5c212023-04-04 09:53:32 -070022 cr0 |= X86_CR0_WP;
Chenyi Qiangfdae6092020-11-05 16:18:05 +080023 write_cr0(cr0);
24}
25
26void do_pf_tss(unsigned long error_code);
27void 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
35extern void pf_tss(void);
36
37asm ("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
54static 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
64int 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);
Chenyi Qiangfdae6092020-11-05 16:18:05 +080079
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}