Изменение таблицы дескрипторов прерываний

Я использую версию ядра Linux 2.6.26 и пытаюсь изменить таблицу дескрипторов прерываний с помощью модуля ядра. Я только пытаюсь изменить запись таблицы сбоев страницы здесь. Поэтому я делаю копию оригинальной IDT и вносю изменения только в запись таблицы ошибок страницы. Задача ISR - распечатать информацию о сбое страницы перед вызовом исходного обработчика сбоя страницы. Но ядро ​​просто вылетает, как только я загружаю его с помощью insmod, то есть оно конкретно падает с помощью функции «loadIDTR». При дальнейшей отладке я обнаружил, что, не меняя какую-либо запись, если я загружаю IDTR, она работает нормально. У меня нет идей.

Я вставил код ниже

#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);

Ответы на вопрос(3)

Ваш ответ на вопрос