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