Sto usando la versione del kernel Linux 2.6.26 e sto provando a cambiare la tabella dei descrittori degli interrupt utilizzando un modulo del kernel. Sto solo provando a cambiare la voce della tabella errori di pagina qui. Quindi faccio una copia dell'ID originale e apporto le modifiche solo alla voce della tabella errori di pagina. L'obiettivo dell'ISR è stampare le informazioni sull'errore di pagina prima di chiamare il gestore degli errori di pagina originale. Ma il kernel si blocca appena una volta lo carico con insmod che si è spezzato in modo specifico con la funzione "loadIDTR". Con ulteriori debug, ho scoperto che non cambiando nessuna voce se carico l'IDTR funziona bene. Non ho più idee.Modifica del descrittore di interrupt Tabella
ho incollato il codice qui sotto
#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);
Vedi anche http://stackoverflow.com/questions/5302392 - e la risposta di amrzar sotto. Il kernel fornisce già funzioni di utilità per sostituire voci specifiche nelle tabelle dei descrittori e/o nelle intere tabelle. L'hacking di basso livello è raramente una buona idea. –
perché quando uso printk nella mia funzione C, il sistema genera un errore del segmento ?? – Jianchen