2010-03-23 13 views
5

Ich benutze Linux 2.6.26 Kernel-Version und ich versuche, die Interrupt-Deskriptor-Tabelle mit einem Kernel-Modul zu ändern. Ich versuche nur den Seitenfehlertabelleneintrag hier zu ändern. Also erstelle ich eine Kopie des ursprünglichen IDT und führe nur Änderungen am Eintrag der Fehlertabelle durch. Das Ziel des ISR besteht darin, Informationen des Seitenfehlers auszudrucken, bevor der ursprüngliche Seitenfehlerhandler aufgerufen wird. Aber der Kernel stürzt einfach ab, wenn ich ihn mit insmod geladen habe, d. H. Er ist speziell mit der "loadIDTR" -Funktion abgestürzt. Beim weiteren Debugging habe ich herausgefunden, dass es funktioniert, wenn ich keinen Eintrag ändere, wenn ich den IDTR lade. Ich habe keine Ideen mehr.Ändern des Interrupt-Deskriptors Tabelle

klebte ich habe den Code unten

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

Siehe auch http://stackoverflow.com/questions/5302392 - und unterhalb Antwort des amrzar. Der Kernel stellt bereits Dienstprogrammfunktionen bereit, um bestimmte Einträge in den Deskriptor-Tabellen und/oder den gesamten Tabellen zu ersetzen. Low-Level-Hacking ist selten eine gute Idee. –

+0

Warum, wenn ich printk in meiner C-Funktion verwende, erzeugt das System Seg-Fehler ?? – Jianchen

Antwort

1

Ihr Segment-Selektor in die Falle Gatedeskriptor scheint 0x0010 fest einprogrammiert werden, wenn es sollte __KERNEL_CS sein (was 0x0060 in den 2.6.26 Kernel-Quellen ist, ich habe).

By the way, das ist ziemlich barock:

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 

Sie könnten, dass auf (mit dem __KERNEL_CS fix) vereinfachen unten:

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

Ihr Recht darüber .. Danke ... Aber dann stürzt der Code in der Funktion my_intrept ab. Ich bin mir nicht sicher, wie ich hier eine Frage beantworten soll ... –

+0

Einfach eine neue Frage stellen. – caf

+0

Warum, wenn ich printk in meiner C-Funktion verwende, erzeugt das System Seg-Fehler ?? – Jianchen

5

Warum Sie Kernel-Funktion nicht verwenden, statt Mit Bits manuell hantieren! überprüfen Sie es (es ist Initialisierungsmodul 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; 

Ich habe es getestet es funktioniert!