我正在学习如何使用 8259A PIC。然而,当我按下键盘时,页面错误处理程序被触发,正确的处理程序没有被调用。
下面是我的源代码片段和截图:
//file: main.c
void Start_Kernel(void) {
printf("kernel started, function %s running\n", __FUNCTION__);
RegisterHandlerIrq();
Register8259AIrq();
//int i=1/0;
while (1) {
;
}
return;
}
//file: 8259A_handler.c
extern void Register8259AIrq() {
printf("initializing 8259A controller\n");
//8259A master icw
SetMasterIcw(0x11, 0x20, 0x04, 0x01);
//8259A slave icw
SetSlaveIcw(0x11, 0x28, 0x02, 0x01);
//8259A ocw1
InitMasterOcw1(0xfd);
InitSlaveOcw1(0xff);
printf("registering irq for pic\n");
for (int i=0x20;i<0x30;i++) {
SetIdtEntry(i, Isr_8259A_General, 0x8, 0, 0xe, 1);
}
__asm__ __volatile__ ("sti":::"memory");
printf("done\n");
return;
}
extern void PicHandlerGeneral(unsigned long RegTablePtr, unsigned long nr) {
printf("%s just got invoked\n", __PRETTY_FUNCTION__);
out_b(PORT0_8259A_MASTER,0x20);
return;
}
//file: Isr_launcher.S
//call the function written in C
//set by host system--------
.set SREG_ES, 0x00
.set SREG_DS, 0x08
.set REG_R15, 0x10
.set REG_R14, 0x18
.set REG_R13, 0x20
.set REG_R12, 0x28
.set REG_R11, 0x30
.set REG_R10, 0x38
.set REG_R9, 0x40
.set REG_R8, 0x48
.set REG_RBP, 0x50
.set REG_RDI, 0x58
.set REG_RSI, 0x60
.set REG_RDX, 0x68
.set REG_RCX, 0x70
.set REG_RBX, 0x78
.set REG_RAX, 0x80
.set HANDLER_ADDR, 0x88
//--------------------------
//set by processor----------
.set ERRCODE, 0x90
.set REG_RIP, 0x98
.set SREG_CS, 0xa0
.set CREG_RFLAGS, 0xa8
.set REG_RSP_OLD, 0xb1
.set SREG_SS_OLD, 0xb8
//--------------------------
IsrLauncher:
//write the handler address into stack
xchgq %rax, (%rsp) //the error handler is filled with correct value (by caller, using leaq instruction) , and the old rax is back!
pushq %rax
pushq %rbx
pushq %rcx
pushq %rdx
pushq %rsi
pushq %rdi
pushq %rbp
pushq %r8
pushq %r9
pushq %r10
pushq %r11
pushq %r12
pushq %r13
pushq %r14
pushq %r15
//pushq %ds is invalid
movq %ds, %rax
pushq %rax
//pushq %es is invalid
movq %es, %rax
pushq %rax
//switch to kernel 64 bit data segment
movq $0x10, %rdi
movq %rdi, %ds
movq %rdi, %es
cld
//system V calling convention
movq ERRCODE(%rsp), %rsi
movq %rsp, %rdi
movq HANDLER_ADDR(%rsp), %rdx
callq *%rdx
popq %rax
popq %rbx
popq %rcx
popq %rdx
popq %rsi
popq %rdi
popq %rbp
popq %r8
popq %r9
popq %r10
popq %r11
popq %r12
popq %r13
popq %r14
popq %r15
//popq %ds is invalid
popq %rax
movq %rax, %ds
//popq %es is invalid
popq %rax
movq %rax, %es
//balance the stack (error code, handler)
//other stuff are maintain by the processor
addq $(0x8+0x8), %rsp
iretq
//file handler.c
typedef unsigned long reg_sz64;
extern void PF_handler(ERROR_STACK_PRAM) {
unsigned long reg_cr2;
reg_sz64 *rip = (unsigned long *)(rsp + 0x98);
reg_sz64 *es = (reg_sz64 *)(rsp + 0x00);
reg_sz64 *ds = (reg_sz64 *)(rsp + 0x08);
reg_sz64 *r15 = (reg_sz64 *)(rsp + 0x10);
reg_sz64 *r14 = (reg_sz64 *)(rsp + 0x18);
reg_sz64 *r13 = (reg_sz64 *)(rsp + 0x20);
reg_sz64 *r12 = (reg_sz64 *)(rsp + 0x28);
reg_sz64 *r11 = (reg_sz64 *)(rsp + 0x30);
reg_sz64 *r10 = (reg_sz64 *)(rsp + 0x38);
reg_sz64 *r9 = (reg_sz64 *)(rsp + 0x40);
reg_sz64 *r8 = (reg_sz64 *)(rsp + 0x48);
reg_sz64 *rbp = (reg_sz64 *)(rsp + 0x50);
reg_sz64 *rdi = (reg_sz64 *)(rsp + 0x58);
reg_sz64 *rsi = (reg_sz64 *)(rsp + 0x60);
reg_sz64 *rdx = (reg_sz64 *)(rsp + 0x68);
reg_sz64 *rcx = (reg_sz64 *)(rsp + 0x70);
reg_sz64 *rbx = (reg_sz64 *)(rsp + 0x78);
reg_sz64 *rax = (reg_sz64 *)(rsp + 0x80);
printf("%s sourced from %p, with error code %p and stack pointer %p\n", __PRETTY_FUNCTION__, *rip, errcode, rsp);
printf("reason: %s\n", ((errcode&0b1) ? "page protection violation" : "page not presented"));
printf(" activity: %s\n", ((errcode&0b10) ? "write attempted" : "read attemped"));
printf(" ring privillege: %s\n", ((errcode&0b100) ? "user (cpl = 3)" : "supervisor (cpl = 0)"));
asm volatile("mov %%cr2, %0" :"=r" (reg_cr2)::);
printf(" faulty address accessed (CR2): %p\n", reg_cr2);
if (errcode&0b1000) {
//if the reserved write: cr4.pse or cr4.pae and writing reserved field
printf(" INFORMATION: writing to reserved field attempted\n");
}
if (errcode&0b10000) {
printf(" INFORMATION: instruction fetch error, execution on NX pages\n");
}
if (errcode&0b100000) {
//check PKRU MSR (user mode) or PKRS MSR (system mode)
printf(" INFORMATION: protection key violation\n");
}
if (errcode&0b1000000) {
printf(" INFORMATION: error accessing shadow stack\n");
}
if (errcode&0b1000000000000000) {
//SGX violation has nothing to do with the oridinary page fault
printf(" INFORMATION: SGX (Software Guard eXtension) voilation\n");
}
printf( \
"\
GPREG:\n\
RAX: %p RBX: %p RCX: %p RDX: %p\n\
RSI: %p RDI: %p RBP: %p R8: %p\n\
R9: %p R10: %p R11: %p R12: %p\n\
R13: %p R14: %p R15: %p\n\
SREG:\n\
DS: %p ES: %p\n\
",\
*rax, *rbx, *rcx, *rdx, \
*rsi, *rdi, *rbp, *r8, \
*r9 , *r10, *r11, *r12, \
*r13, *r14, *r15, \
*ds, *es \
);
while(1);
}
0xffff800000104087处的指令是一个
nop;jmp -3
循环
这是我已经查看过的一些网站
https://forum.osdev.org/viewtopic.php?f=1&t=27370
https://wiki.osdev.org/I_Can't_Get_Interrupts_Working
我不认为这是双重故障或与 GDT 相关的问题。该页面也正确映射。
CR2 持有一个可疑的线性地址,我不认为它与页面错误有关。
这可能是竞争条件还是什么?