2010-03-23 29 views
5

Tôi đang sử dụng phiên bản hạt nhân 2.6.26 của Linux và tôi đang cố gắng thay đổi bảng mô tả ngắt bằng mô-đun hạt nhân. Tôi chỉ cố gắng thay đổi mục bảng lỗi trang ở đây. Vì vậy, tôi tạo một bản sao của IDT gốc và thực hiện các thay đổi đối với mục nhập bảng lỗi trang. Mục tiêu của ISR là in ra thông tin về lỗi trang trước khi gọi trình xử lý lỗi trang gốc. Nhưng hạt nhân chỉ bị đổ vỡ khi tôi tải nó với insmod, tức là nó bị lỗi đặc biệt với hàm "loadIDTR". Với gỡ lỗi thêm, tôi phát hiện ra rằng bằng cách không thay đổi bất kỳ mục nhập nếu tôi tải IDTR nó hoạt động tốt. Tôi không có ý kiến.Thay đổi bộ mô tả ngắt Bảng

Tôi đã dán đoạn code dưới đây

#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

Xem thêm http://stackoverflow.com/questions/5302392 - và câu trả lời amrzar của bên dưới. Hạt nhân đã cung cấp các chức năng tiện ích để thay thế các mục cụ thể trong các bảng mô tả và/hoặc toàn bộ các bảng. Hacking cấp thấp xung quanh đó hiếm khi là một ý tưởng tốt. –

+0

lý do tại sao khi tôi sử dụng printk trong chức năng C của tôi, hệ thống tạo ra lỗi seg ?? – Jianchen

Trả lời

1

chọn phân khúc của bạn trong mô tả cổng bẫy của bạn dường như được hardcoded 0x0010, khi nó phải được __KERNEL_CS (đó là 0x0060 trong nguồn kernel 2.6.26 Tôi có).

Bằng cách này, điều này là khá baroque:

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 

Bạn có thể đơn giản hóa mà xuống (với những sửa chữa __KERNEL_CS):

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

Quyền của bạn về nó .. Cảm ơn ... Nhưng sau đó mã đang bị lỗi bên trong hàm my_intrept. Tôi không chắc chắn làm thế nào để theo dõi một câu hỏi ở đây ... –

+0

Chỉ cần đăng một câu hỏi mới. – caf

+0

lý do tại sao khi tôi sử dụng printk trong chức năng C của tôi, hệ thống tạo ra lỗi seg ?? – Jianchen

5

Tại sao bạn không sử dụng chức năng hạt nhân thay vì nghịch với bit bằng tay! kiểm tra xem nó (đây là mô-đun khởi tạo 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; 

Tôi đã thử nghiệm nó hoạt động!

Các vấn đề liên quan