2010-03-23 19 views
5

Linux 2.6.26 çekirdek sürümü kullanıyorum ve bir çekirdek modülü kullanarak kesme tanımlayıcı tablosunu değiştirmeye çalışıyorum. Sadece sayfa hata tablosu girişini değiştirmeye çalışıyorum. Bu yüzden orijinal IDT'nin bir kopyasını alıyorum ve sadece sayfa hata tablosu girişinde değişiklikler yapıyorum. ISR'nin amacı, orijinal Sayfa hata işleyicisini çağırmadan önce sayfa hatasının bilgilerini yazdırmaktır. Ama çekirdeği insmod ile yükledikten sonra çöker, özellikle "loadIDTR" fonksiyonu ile çöktü. Daha fazla hata ayıklama ile IDTR'yi yüklerseniz herhangi bir girişi değiştirmemenin iyi çalıştığını öğrendim. Fikirlerim tükendi.Kesme tanımlayıcısını değiştirme Tablo

Ben senin tuzak kapısı açıklayıcıda

#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

da http://stackoverflow.com/questions/5302392 öğrenin - ve aşağıdaki amrzar cevabı. Çekirdek zaten tanımlayıcı tablolarındaki ve/veya tüm tablolardaki belirli girdileri değiştirmek için yardımcı işlevler sağlar. Bu konuda düşük seviyeli bir korsanlık nadiren iyi bir fikir. –

+0

neden C fonksiyonumda printk kullandığımda sistem seg hatası yaratıyor? – Jianchen

cevap

1

Segment seçicinin aşağıdaki kodu yapıştırdıysanız 0x0010, için kodlanmış görünmektedir o (Ben 2.6.26 çekirdek kaynaklarında 0x0060 olan __KERNEL_CS olması gerekirken).

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 

Sen (__KERNEL_CS fix ile) için aşağı basitleştirmek olabilir:

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

Hakkınız hakkında .. Teşekkürler ... Ama sonra kod my_intrept işlevinin içinde çöküyor. Burada bir soruyu nasıl takip edeceğimi bilmiyorum ... –

+0

Sadece yeni bir soru gönderin. – caf

+0

Neden C fonksiyonumda printk kullandığımda, sistem seg hatası üretir? – Jianchen

5

Neden çekirdek işlevini yerine kullanmayın arada

, bu güzel barok olduğunu elle biti ile uğraşmak! kontrol (o başlatma modülü fonk):

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; 

bunun işe yaradığını test ettim!

İlgili konular