Page 1 of 1

Page fault handler causes read data to be corrupt?

Posted: Thu Dec 28, 2017 10:12 am
by kc9zda
It seems after I map a page in my page fault handler, the data at the paged address is corrupt on the first read, but fine on the second.

Here is my page fault handler:

Code: Select all

.globl  exception_page_fault
.align  4

exception_page_fault:
    cld
    push %esp
    call pg_fault	
    add $0x08,%esp # 4 bytes for error code, 4 bytes for saved ESP
    iret
The signature for pg_fault in C:

Code: Select all

void pg_fault(uint32_t esp, uint32_t ec); // esp = ESP upon entry to fault handler; ec = error code
Currently, when pg_fault is called, it identity maps the page that isn't present. It's a temporary solution so I can read ACPI tables while paging.

I have a test that shows that shows the Length field in the RSDT table:

Code: Select all

printf("first try: %u\n", acpi_rsdt->length);
printf("second try: %u\n", acpi_rsdt->length);
The first try triggers a page fault, which identity maps the page. The first read attempt returns something resembling a real mode address in the ROM (like a vector in the IVT). The second try returns the correct value. I would expect both of these to be the same. It even reads fine in the page handler right after reloading CR3 and calling INVLPG on the address. I'm pretty sure there is something wrong with my assembly page fault handler, but I can't tell what it is. I'm using Virtualbox 4.3.10.

Re: Page fault handler causes read data to be corrupt?

Posted: Thu Dec 28, 2017 10:34 am
by Korona
The ABI does not guarantee that all registers are saved by pg_fault(). You need to look up which registers are caller-saved in your ABI and manually save and restore them.

Re: Page fault handler causes read data to be corrupt?

Posted: Thu Dec 28, 2017 10:35 am
by xenos
I would assume that your interrupt handler corrupts the interrupted code's registers. Where do you save / restore them?

Re: Page fault handler causes read data to be corrupt?

Posted: Thu Dec 28, 2017 10:58 am
by kc9zda
I did not consider saving registers. I am using the sysV ABI (i686-elf), which saves EBX, ESI, EDI, EBP, and ESP. I found that if I do a PUSHA at the beginning and a POPA before the IRET and stack adjustment (for error codes), it works fine. Thanks