⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 access.c

📁 kvm 源代码
💻 C
字号:
#include "smp.h"#include "printf.h"typedef unsigned long pt_element_t;#define PAGE_SIZE ((pt_element_t)4096)#define PAGE_MASK (~(PAGE_SIZE-1))#define PT_BASE_ADDR_MASK ((pt_element_t)((((pt_element_t)1 << 40) - 1) & PAGE_MASK))#define PT_PRESENT_MASK    ((pt_element_t)1 << 0)#define PT_WRITABLE_MASK   ((pt_element_t)1 << 1)#define PT_USER_MASK       ((pt_element_t)1 << 2)#define PT_ACCESSED_MASK   ((pt_element_t)1 << 5)#define PT_DIRTY_MASK      ((pt_element_t)1 << 6)#define CR0_WP_MASK (1UL << 16)#define PFERR_PRESENT_MASK (1U << 0)#define PFERR_WRITE_MASK (1U << 1)#define PFERR_USER_MASK (1U << 2)/* * page table access check tests */enum {    AC_PTE_PRESENT,    AC_PTE_WRITABLE,    AC_PTE_USER,    AC_PTE_ACCESSED,    AC_PTE_DIRTY,    // AC_PTE_NX,    AC_ACCESS_USER,    AC_ACCESS_WRITE,    // AC_ACCESS_FETCH,    // AC_ACCESS_PTE,    // AC_CPU_EFER_NX,    AC_CPU_CR0_WP,    NR_AC_FLAGS};const char *ac_names[] = {    [AC_PTE_PRESENT] = "pte.p",    [AC_PTE_ACCESSED] = "pte.a",    [AC_PTE_WRITABLE] = "pte.rw",    [AC_PTE_USER] = "pte.user",    [AC_PTE_DIRTY] = "pte.d",    [AC_ACCESS_WRITE] = "write",    [AC_ACCESS_USER] = "user",    [AC_CPU_CR0_WP] = "cr0.wp",};static inline void *va(pt_element_t phys){    return (void *)phys;}static unsigned long read_cr0(){    unsigned long cr0;    asm volatile ("mov %%cr0, %0" : "=r"(cr0));    return cr0;}static void write_cr0(unsigned long cr0){    asm volatile ("mov %0, %%cr0" : : "r"(cr0));}typedef struct {    unsigned short offset0;    unsigned short selector;    unsigned short ist : 3;    unsigned short : 5;    unsigned short type : 4;    unsigned short : 1;    unsigned short dpl : 2;    unsigned short p : 1;    unsigned short offset1;    unsigned offset2;    unsigned reserved;} idt_entry_t;typedef struct {    unsigned flags[NR_AC_FLAGS];    void *virt;    pt_element_t phys;    pt_element_t pt_pool;    pt_element_t *ptep;    pt_element_t expected_pte;    int expected_fault;    unsigned expected_error;    idt_entry_t idt[256];} ac_test_t;typedef struct {    unsigned short limit;    unsigned long linear_addr;} __attribute__((packed)) descriptor_table_t;void lidt(idt_entry_t *idt, int nentries){    descriptor_table_t dt;        dt.limit = nentries * sizeof(*idt) - 1;    dt.linear_addr = (unsigned long)idt;    asm volatile ("lidt %0" : : "m"(dt));}void memset(void *a, unsigned char v, int n){    unsigned char *x = a;    while (n--)	*x++ = v;}unsigned short read_cs(){    unsigned short r;    asm volatile ("mov %%cs, %0" : "=r"(r));}void set_idt_entry(idt_entry_t *e, void *addr, int dpl){    memset(e, 0, sizeof *e);    e->offset0 = (unsigned long)addr;    e->selector = read_cs();    e->ist = 0;    e->type = 14;    e->dpl = dpl;    e->p = 1;    e->offset1 = (unsigned long)addr >> 16;    e->offset2 = (unsigned long)addr >> 32;}void set_cr0_wp(int wp){    unsigned long cr0 = read_cr0();    cr0 &= ~CR0_WP_MASK;    if (wp)	cr0 |= CR0_WP_MASK;    write_cr0(cr0);}void ac_test_init(ac_test_t *at){    set_cr0_wp(1);    for (int i = 0; i < NR_AC_FLAGS; ++i)	at->flags[i] = 0;    at->virt = (void *)(0x123400000000 + 16 * smp_id());    at->phys = 32 * 1024 * 1024;    at->pt_pool = 33 * 1024 * 1024;    memset(at->idt, 0, sizeof at->idt);    lidt(at->idt, 256);    extern char page_fault, kernel_entry;    set_idt_entry(&at->idt[14], &page_fault, 0);    set_idt_entry(&at->idt[0x20], &kernel_entry, 3);}int ac_test_bump(ac_test_t *at){    for (int i = 0; i < NR_AC_FLAGS; ++i)	if (!at->flags[i]) {	    at->flags[i] = 1;	    return 1;	} else	    at->flags[i] = 0;    return 0;}unsigned long read_cr3(){    unsigned long cr3;    asm volatile ("mov %%cr3, %0" : "=r"(cr3));    return cr3;}void invlpg(void *addr){    asm volatile ("invlpg (%0)" : : "r"(addr));}pt_element_t ac_test_alloc_pt(ac_test_t *at){    pt_element_t ret = at->pt_pool;    at->pt_pool += PAGE_SIZE;    return ret;}void ac_test_setup_pte(ac_test_t *at){    unsigned long root = read_cr3();    for (int i = 4; i >= 1; --i) {	pt_element_t *vroot = va(root & PT_BASE_ADDR_MASK);	unsigned index = ((unsigned long)at->virt >> (12 + (i-1) * 9)) & 511;	pt_element_t pte;	if (i != 1) {	    pte = vroot[index];	    if (!(pte & PT_PRESENT_MASK))		pte = ac_test_alloc_pt(at) | PT_PRESENT_MASK;	    pte |= PT_WRITABLE_MASK | PT_USER_MASK;	} else {	    pte = at->phys & PT_BASE_ADDR_MASK;	    if (at->flags[AC_PTE_PRESENT])		pte |= PT_PRESENT_MASK;	    if (at->flags[AC_PTE_WRITABLE])		pte |= PT_WRITABLE_MASK;	    if (at->flags[AC_PTE_USER])		pte |= PT_USER_MASK;	    if (at->flags[AC_PTE_ACCESSED])		pte |= PT_ACCESSED_MASK;	    if (at->flags[AC_PTE_DIRTY])		pte |= PT_DIRTY_MASK;	    at->ptep = &vroot[index];	}	vroot[index] = pte;	root = vroot[index];    }    invlpg(at->virt);    at->expected_pte = *at->ptep;    at->expected_fault = 0;    at->expected_error = 0;    if (!at->flags[AC_PTE_PRESENT])	at->expected_fault = 1;    else	at->expected_error |= PFERR_PRESENT_MASK;    if (at->flags[AC_ACCESS_USER]) {	at->expected_error |= PFERR_USER_MASK;	if (!at->flags[AC_PTE_USER])	    at->expected_fault = 1;    }    if (at->flags[AC_ACCESS_WRITE]) {	at->expected_error |= PFERR_WRITE_MASK;	if (!at->flags[AC_PTE_WRITABLE]	    && (at->flags[AC_CPU_CR0_WP] || at->flags[AC_ACCESS_USER])) {	    at->expected_fault = 1;	} else if (!at->expected_fault) {	    at->expected_pte |= PT_DIRTY_MASK;	}    }    if (!at->expected_fault) {	at->expected_pte |= PT_ACCESSED_MASK;    }}int ac_test_do_access(ac_test_t *at){    static unsigned unique = 42;    int fault = 0;    unsigned e;    static unsigned char user_stack[4096];    unsigned long rsp;    ++unique;    unsigned r = unique;    set_cr0_wp(at->flags[AC_CPU_CR0_WP]);    asm volatile ("mov %%rsp, %%rdx \n\t"		  "cmp $0, %[user] \n\t"		  "jz do_access \n\t"		  "push %%rax; mov %[user_ds], %%ax; mov %%ax, %%ds; pop %%rax  \n\t"		  "pushq %[user_ds] \n\t"		  "pushq %[user_stack_top] \n\t"		  "pushfq \n\t"		  "pushq %[user_cs] \n\t"		  "pushq $do_access \n\t"		  "iretq \n"		  "do_access: \n\t"		  "cmp $0, %[write] \n\t"		  "jnz 1f \n\t"		  "mov (%[addr]), %[reg] \n\t"		  "jmp done \n\t"		  "1: mov %[reg], (%[addr]) \n\t"		  "done: \n"		  "fixed1: \n"		  "int %[kernel_entry_vector] \n\t"		  "back_to_kernel:"		  : [reg]"+r"(r), "+a"(fault), "=b"(e), "=&d"(rsp)		  : [addr]"r"(at->virt),		    [write]"r"(at->flags[AC_ACCESS_WRITE]),		    [user]"r"(at->flags[AC_ACCESS_USER]),		    [user_ds]"i"(32+3),		    [user_cs]"i"(24+3),		    [user_stack_top]"r"(user_stack + sizeof user_stack),		    [kernel_entry_vector]"i"(0x20));    asm volatile (".section .text.pf \n\t"		  "page_fault: \n\t"		  "pop %rbx \n\t"		  "movq $fixed1, (%rsp) \n\t"		  "movl $1, %eax \n\t"		  "iretq \n\t"		  ".section .text");    asm volatile (".section .text.entry \n\t"		  "kernel_entry: \n\t"		  "mov %rdx, %rsp \n\t"		  "jmp back_to_kernel \n\t"		  ".section .text");    if (fault && !at->expected_fault) {	printf("unexpected fault\n");	return 0;    }    if (!fault && at->expected_fault) {	printf("unexpected access\n");	return 0;    }    if (fault && e != at->expected_error) {	printf("error code %x expected %x\n", e, at->expected_fault);	return 0;    }    if (*at->ptep != at->expected_pte) {	printf("pte %x expected %x\n", *at->ptep, at->expected_pte);	return 0;    }    printf("OK\n");    return 1;}void ac_test_exec(ac_test_t *at){    int r;    printf("test");    for (int i = 0; i < NR_AC_FLAGS; ++i)	if (at->flags[i])	    printf(" %s", ac_names[i]);    printf(": ");    ac_test_setup_pte(at);    r = ac_test_do_access(at);}void ac_test_run(){    static ac_test_t at;    printf("run\n");    ac_test_init(&at);    do {	ac_test_exec(&at);    } while (ac_test_bump(&at));}int main(){    printf("starting test\n\n");    smp_init(ac_test_run);    ac_test_run();    return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -