首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >更改中断描述符表

更改中断描述符表
EN

Stack Overflow用户
提问于 2010-03-23 14:13:16
回答 3查看 4.4K关注 0票数 7

我使用的是Linux2.6.26内核版本,并且我正在尝试使用内核模块更改中断描述符表。在这里,我只是尝试更改页面故障表条目。因此,我复制了原始的IDT,并且只对页面故障表条目进行了更改。ISR的目标是在调用原始页面错误处理程序之前打印出页面错误信息。但是,一旦我用insmod加载内核,它就会崩溃,也就是说,它特别是用"loadIDTR“函数崩溃了。通过进一步的调试,我发现如果不更改任何条目,如果我加载IDTR,它就能正常工作。我已经没有主意了。

我已经粘贴了下面的代码

代码语言:javascript
运行
复制
#include <linux/module.h>   // for init_module() 
#include <linux/init.h>
#include <linux/mm.h>       // for get_free_page()
#include <linux/sched.h>
#include <linux/spinlock.h>

#define SUCCESS 0
#define PGFAULT_INT 0x0E

static char modname[] = "pgfaults";
static unsigned short oldidtr[3], newidtr[3];
static unsigned long long *oldidt, *newidt;
static unsigned long isr_orig, kpage;
static char *why[]={ "sra", "srp", "swa", "swp", "ura", "urp", "uwa", "uwp" };

unsigned long long gate_desc_orig,gate_desc_orig1;

static void my_intrept( unsigned long *tos )
{
    // stack-layout:
    // es,ds,edi,esi,ebp,esp,ebx,edx,ecx,eax,err,eip,cs,efl
    //  0  1   2   3   4   5   6   7   8   9  10  11 12  13  
    volatile unsigned long  vaddr;
    struct task_struct *task = current;
    unsigned long   err = tos[ 10 ];    
    unsigned long   eip = tos[ 11 ];
    static int  count = 0;
    int     exe, len = 0;
    char        msg[80]="";

    // get the faulting virtual address from register CR2
    asm(" mov %%cr2, %%eax ; movl %%eax, %0 " : "=m" (vaddr) ); 

    // construct the diagnostic message
    len += sprintf( msg+len, "#%-6d ", ++count );
    len += sprintf( msg+len, "%16s  ", task->comm );
    len += sprintf( msg+len, "pid=%-5d  ", task->pid );
    len += sprintf( msg+len, "CR2=%08X  ", (unsigned int) vaddr );
    len += sprintf( msg+len, "EIP=%08X  ", (unsigned int) eip );
    len += sprintf( msg+len, "%s ", why[ err ] );
    // note if an instruction-fetch caused the page-fault
    if ( vaddr == eip ) exe = 'x'; else exe = ' ';
    len += sprintf( msg+len, "%c ", exe );
    // print this diagnostic message to the kernel log
    printk( "<1>  %s \n", msg );
}




//----------  NEW PAGE-FAULT EXCEPTION-HANDLER  ---------//
asmlinkage void isr0x0E( void );
asm("   .text                       ");
asm("   .type   isr0x0E, @function          ");
asm("isr0x0E:                       ");
asm("   pushal                      ");
asm("   pushl   %ds                 "); 
asm("   pushl   %es                 ");
//
asm("   movl    %ss, %eax               "); 
asm("   movl    %eax, %ds               ");
asm("   movl    %eax, %es               ");
//
asm("   pushl   %esp                    "); 
asm("   call    my_intrept              ");
asm("   addl    $4, %esp                ");
//
asm("   popl    %es                 "); 
asm("   popl    %ds                 ");
asm("   popal                       ");
asm("   jmp *isr_orig               ");
//-------------------------------------------------------//



static void load_IDTR( void *regimage )
{
    asm(" lidt %0 " : : "m" (*(unsigned short*)regimage) );
}



int pgfault_init( void )
{
    int         i;
    unsigned long long gate_desc,gate_desc1,gate_desc2;

    spinlock_t lock =SPIN_LOCK_UNLOCKED;
    unsigned long flags;
    unsigned short selector1;

    // allocate a mapped kernel page for our new IDT
    kpage =__get_free_page( GFP_KERNEL);
    if ( !kpage ) return -ENOMEM;


    // initialize our other global variables

    asm(" sidt oldidtr ; sidt newidtr ");

    memcpy( newidtr+1, &kpage, sizeof( kpage ) );
    oldidt = (unsigned long long *)(*(unsigned long*)(oldidtr+1));
    newidt = (unsigned long long *)(*(unsigned long*)(newidtr+1));

    // extract and save entry-point to original page-pault handler
    gate_desc_orig = oldidt[ PGFAULT_INT ];
    gate_desc =gate_desc_orig & 0xFFFF00000000FFFF;

    gate_desc |= ( gate_desc >> 32 );
    isr_orig = (unsigned long)gate_desc;
    // initialize our new Interrupt Descriptor Table
    memcpy( newidt, oldidt, 256*sizeof( unsigned long long ) );

    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
    //Part which is most likely creating a fault when loading the idtr
    newidt[ PGFAULT_INT ] = gate_desc;
    //**********************************************
    // activate the new IDT

    spin_lock_irqsave(&lock,flags);
    load_IDTR( newidtr );
    spin_unlock_irqrestore(&lock,flags);

//  smp_call_function( load_IDTR, oldidtr, 1, 1 );
    return  SUCCESS;
}



void pgfault_exit( void )
{

    // reactivate the old IDT
    unsigned long flags;
    spinlock_t lock =SPIN_LOCK_UNLOCKED;
    spin_lock_irqsave(&lock,flags);
    load_IDTR( oldidtr );
    spin_unlock_irqrestore(&lock,flags);
//  smp_call_function( load_IDTR, oldidtr, 1, 1 );

    // release allocated kernel page 
    if ( kpage ) free_page( kpage );
}
EXPORT_SYMBOL_GPL(my_intrept);
MODULE_LICENSE("GPL"); 
module_init( pgfault_init);
module_exit( pgfault_exit);
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2010-03-24 16:43:16

您的陷阱门描述符中的段选择器似乎被硬编码为0x0010,而它应该是__KERNEL_CS (在我的2.6.26内核源代码中是0x0060 )。

顺便说一句,这很有巴洛克风格:

代码语言:javascript
运行
复制
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

您可以将其简化为(使用__KERNEL_CS修复):

代码语言:javascript
运行
复制
gate_desc = (unsigned long long)isr0x0E * 0x100000001ULL;
gate_desc &= 0xFFFF00000000FFFFULL;
gate_desc |= 0x0000EF0000000000ULL; // trap-gate
gate_desc |= (unsigned long long)__KERNEL_CS << 16;
票数 2
EN

Stack Overflow用户

发布于 2011-05-13 07:50:16

你为什么不使用内核函数,而不是手动摆弄bits!检查(是初始化模块func):

代码语言:javascript
运行
复制
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;

我已经测试过了,它是有效的!

票数 7
EN

Stack Overflow用户

发布于 2013-12-16 00:50:01

作为参考,这里是一个用于Linux x86_64体系结构的自定义页面错误处理程序的工作实现。我刚刚用内核3.2测试了这个模块,它工作得很好。

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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2497919

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档