Changing the Interrupt descriptor Table

久未见 提交于 2019-12-03 15:06:36

Your segment selector in your trap gate descriptor appears to be hardcoded to 0x0010, when it should be __KERNEL_CS (which is 0x0060 in the 2.6.26 kernel sources I have).

By the way, this is pretty baroque:

gate_desc_orig1 = (unsigned long)isr0x0E;
gate_desc = gate_desc_orig1 & 0x00000000FFFFFFFF;

gate_desc = gate_desc | ( gate_desc << 32 );
gate_desc1= 0xFFFF0000;
gate_desc1= gate_desc1 << 32;
gate_desc1= gate_desc1 | 0x0000FFFF;
gate_desc = gate_desc & gate_desc1;
gate_desc2= 0x0000EF00;
gate_desc2= gate_desc2 <<32;
gate_desc2= gate_desc2 | 0x00100000;
gate_desc = gate_desc | gate_desc2; // trap-gate

You could simplify that down to (with the __KERNEL_CS fix):

gate_desc = (unsigned long long)isr0x0E * 0x100000001ULL;
gate_desc &= 0xFFFF00000000FFFFULL;
gate_desc |= 0x0000EF0000000000ULL; // trap-gate
gate_desc |= (unsigned long long)__KERNEL_CS << 16;
amrzar

Why don't you use kernel function instead of fiddling with bits manually! check it (it is initialization module func):

struct desc_ptr newidtr;
gate_desc *oldidt, *newidt;

store_idt(&__IDT_register);
oldidt = (gate_desc *)__IDT_register.address;

__IDT_page =__get_free_page(GFP_KERNEL);
if(!__IDT_page)
    return -1;

newidtr.address = __IDT_page;
newidtr.size = __IDT_register.size;
newidt = (gate_desc *)newidtr.address;

memcpy(newidt, oldidt, __IDT_register.size);

pack_gate(&newidt[PGFAULT_NR], GATE_INTERRUPT, (unsigned long)isr0x0E, 0, 0, __KERNEL_CS);

__load_idt((void *)&newidtr);
smp_call_function(__load_idt, &newidtr, 0, 1);

return 0;

I have tested it it works!

For reference, here is a working implementation of a custom page fault handler for the Linux x86_64 architecture. I just tested this module myself with kernel 3.2, it works perfectly.

https://github.com/RichardUSTC/intercept-page-fault-handler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!