在 8259A PIC 触发中断后收到页面错误

问题描述 投票:0回答:0

我正在学习如何使用 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 持有一个可疑的线性地址,我不认为它与页面错误有关。

这可能是竞争条件还是什么?

assembly x86-64 interrupt osdev page-fault
© www.soinside.com 2019 - 2024. All rights reserved.