1 #include <linux/module.h> 2 #include <linux/kernel.h> 3 #include <linux/errno.h> 4 #include <linux/types.h> 6 #include <asm/uaccess.h> 8 #include "traps-dummy.h" 9 #include <asm/desc_defs.h> 10 #include <linux/sched.h> 11 #include <linux/moduleparam.h> 13 #define X86_TRAP_PF 14 15 #if defined(CONFIG_X86_64) 16 #define PGFAULT_NR X86_TRAP_PF 18 #error This module is only for X86_64 kernel 21 static unsigned long new_idt_table_page;
22 static struct desc_ptr default_idtr;
25 static unsigned long addr_dft_page_fault = 0UL;
26 static unsigned long addr_dft_do_page_fault = 0UL;
27 static unsigned long addr_pv_irq_ops = 0UL;
28 static unsigned long addr_adjust_exception_frame;
29 static unsigned long addr_error_entry = 0UL;
30 static unsigned long addr_error_exit = 0UL;
32 module_param(addr_dft_page_fault, ulong, S_IRUGO);
33 module_param(addr_dft_do_page_fault, ulong, S_IRUGO);
34 module_param(addr_pv_irq_ops, ulong, S_IRUGO);
35 module_param(addr_error_entry, ulong, S_IRUGO);
36 module_param(addr_error_exit, ulong, S_IRUGO);
38 #define CHECK_PARAM(x) do{\ 40 printk(KERN_INFO "my_virt_drv: Error: need to set '%s'\n", #x);\ 43 printk(KERN_INFO "my_virt_drv: %s=0x%lx\n", #x, x);\ 46 typedef void (*do_page_fault_t)(
struct pt_regs*,
unsigned long);
48 extern void root_sim_page_fault(
struct pt_regs* regs,
long error_code, do_page_fault_t kernel_handler);
50 static int check_parameters(
void){
52 CHECK_PARAM(addr_dft_page_fault);
53 CHECK_PARAM(addr_dft_do_page_fault);
54 CHECK_PARAM(addr_pv_irq_ops);
55 CHECK_PARAM(addr_error_entry);
56 CHECK_PARAM(addr_error_exit);
60 void my_do_page_fault(
struct pt_regs* regs,
unsigned long error_code){
63 root_sim_page_fault(regs, error_code, (do_page_fault_t)addr_dft_do_page_fault);
66 asmlinkage
void my_page_fault(
void);
68 asm(
" .type my_page_fault,@function");
69 asm(
"my_page_fault:");
71 asm(
" xchg %ax, %ax");
72 asm(
" callq *addr_adjust_exception_frame");
73 asm(
" sub $0x78, %rsp");
74 asm(
" callq *addr_error_entry");
75 asm(
" mov %rsp, %rdi");
76 asm(
" mov 0x78(%rsp), %rsi");
77 asm(
" movq $0xffffffffffffffff, 0x78(%rsp)");
78 asm(
" callq my_do_page_fault");
79 asm(
" jmpq *addr_error_exit");
83 static inline void pack_gate(gate_desc *gate,
unsigned type,
unsigned long func,
84 unsigned dpl,
unsigned ist,
unsigned seg){
85 gate->offset_low = PTR_LOW(func);
86 gate->segment = __KERNEL_CS;
93 gate->offset_middle = PTR_MIDDLE(func);
94 gate->offset_high = PTR_HIGH(func);
97 static void my_load_idt(
void *info){
98 struct desc_ptr *idtr_ptr = (
struct desc_ptr *)info;
102 static int my_fault_init(
void){
104 if(check_parameters())
107 addr_adjust_exception_frame = *(
unsigned long *)(addr_pv_irq_ops + 0x30);
111 int register_my_page_fault_handler(
void){
112 struct desc_ptr idtr;
113 gate_desc *old_idt, *new_idt;
117 retval = my_fault_init();
122 store_idt(&default_idtr);
125 old_idt = (gate_desc *)default_idtr.address;
128 printk(KERN_INFO
"my_virt_drv: alloc a page to store new idt table.\n");
129 new_idt_table_page = __get_free_page(GFP_KERNEL);
130 if(!new_idt_table_page)
133 idtr.address = new_idt_table_page;
134 idtr.size = default_idtr.size;
137 new_idt = (gate_desc *)idtr.address;
138 memcpy(new_idt, old_idt, idtr.size);
139 pack_gate(&new_idt[PGFAULT_NR], GATE_INTERRUPT, (
unsigned long)my_page_fault, 0, 0, __KERNEL_CS);
142 printk(KERN_INFO
"my_virt_drv: load the new idt table.\n");
144 printk(KERN_INFO
"my_virt_drv: new idt table loaded.\n");
145 smp_call_function(my_load_idt, (
void *)&idtr, 1);
146 printk(KERN_INFO
"my_virt_drv: all CPUs have loaded the new idt table.\n");
150 void unregister_my_page_fault_handler(
void){
151 struct desc_ptr idtr;
154 if(idtr.address != default_idtr.address || idtr.size != default_idtr.size){
155 load_idt(&default_idtr);
156 smp_call_function(my_load_idt, (
void *)&default_idtr, 1);
157 free_page(new_idt_table_page);
161 MODULE_LICENSE(
"Dual BSD/GPL");