Я использую версию ядра 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);