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