0

I'm learning how to use 8259A PIC. however, when I press the key board, the page fault handler is triggered, the correct handler is not being called.

With my source code snippet and screenshot below:

//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);
}

the instruction at 0xffff800000104087 is a nop;jmp -3 loop

enter image description here

here's some websites I've already checked out

https://forum.osdev.org/viewtopic.php?f=1&t=27370

https://wiki.osdev.org/I_Can't_Get_Interrupts_Working

I don't think it's either a double fault or a GDT-related problem. The page is correctly map, too.

With the CR2 holding a suspicious linear address, i don't think it have something to do with page fault.

Could it be a race condition or something?

Raymond
  • 31
  • 1
  • 4
  • **Comments have been [moved to chat](https://chat.stackoverflow.com/rooms/253647/discussion-on-question-by-raymond-receiving-a-page-fault-after-interrupt-fired-b); please do not continue the discussion here.** Before posting a comment below this one, please review the [purposes of comments](/help/privileges/comment). Comments that do not request clarification or suggest improvements usually belong as an [answer](/help/how-to-answer), on [meta], or in [chat]. Comments continuing discussion may be removed. – Samuel Liew May 14 '23 at 09:34

0 Answers0