I am currently working on the ACPI code for my Ordo project. I am able to locate and identify the RSDP structure, and use that to find the RSDT (not the XSDT, as the SeaBIOS used in QEMU only supports ACPI 1.0). However, when I try to access the RSDT structure in order to validate it, I get a page fault.
I have instrumented the code for accessing both the RSDP and the RSDT to show each step, as well as to show the memory map retrieved from the BIOS. Based on this, I have concluded that the RSDT is indeed outside of the free memory, in a section of memory that I don't presently have page mapped (the page definitions in my boot loader can be seen here). This image shows the output with the QEMU memory set to 128M:
I've also checked the same with -m 512M to comfirm that the same behavior applies regardless of the memory map:
I assume that the solution is to add the firmware in question to the paged memory for the kernel, but I am concerned that I might be misreading the situation somehow. I am also not entirely clear how to alter the page mapping in the kernel, given that I am currently using the page map set up in the boot loader. Any advice on this would be appreciated.
Page fault on accessing RSDT
- Schol-R-LEA
- Member
- Posts: 1925
- Joined: Fri Oct 27, 2006 9:42 am
- Location: Athens, GA, USA
Page fault on accessing RSDT
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
- Schol-R-LEA
- Member
- Posts: 1925
- Joined: Fri Oct 27, 2006 9:42 am
- Location: Athens, GA, USA
Re: Page fault on accessing RSDT
I forgot to post the relevant code:
And:
Code: Select all
bool validate_sdt_checksum(struct ACPI_xSDT_Header *candidate)
{
int32_t checksum = 0;
uint8_t i;
int8_t* c_ptr = (int8_t *) candidate;
for (i = 0; i < sizeof(struct ACPI_xSDT_Header); i++)
{
checksum += c_ptr[i];
}
return (checksum == 0);
}
void init_acpi()
{
kprintf("\nSeeking RSDP... ");
rsdp = scan_rsdp_signature();
kprintf("RSDP candidate found\n");
kprintf("OEM ID: ");
for (unsigned int i = 0; i < 6; i++)
{
kprintc(rsdp->ver_1.OEM_ID[i], BLACK, WHITE);
}
kprintc('\n', GRAY, BLACK);
if (!validate_rsdp_checksum(rsdp))
{
kprints("Error: invalid RSDP", LT_RED, BLACK);
panic();
}
// Get the system descriptor table.
// While the specific link used depends on the ACPI version,
// the table structure is the same regardless of version.
kprintf("size of the SDT header ptr: %u\n", sizeof(struct ACPI_xSDT_Header *));
sdt = (struct ACPI_xSDT_Header *) (rsdp->ver_1.Revision == 0
? rsdp->ver_1.RsdtAddress
: (uint32_t) rsdp->XsdtAddress);
kprintf("xSDT candidate found at 0x%p\n", sdt);
for (uint8_t i = 0; i < 4; i++)
{
kprintc(sdt->Signature[i], WHITE, BLACK);
}
kprintf(" OEM ID: ");
for (uint8_t i = 0; i < 6; i++)
{
kprintc(sdt->OEM_ID[i], BLACK, WHITE);
}
kprintc('\n', GRAY, BLACK);
if (!validate_sdt_checksum(sdt))
{
kprints("Error: invalid SDT", LT_RED, BLACK);
panic();
}
kprintf("SDT checksum valid.\n");
}
Code: Select all
page_directory equ 0x0040000
page_table_0 equ page_directory + 0x1000
page_table_768 equ page_table_0 + 0x1000
init_page_directory:
mov ebx, dword page_directory
memset32 0, 0x0400, ebx ; clear the page dir table
; start by setting up the base page table
mov ebx, dword page_table_0 ; get index into the base page table
memset32 0, 0x0400, ebx ; clear the table entries
; entries 0-1024 - identity mapping the first 1 MiB of memory
mov ecx, 0x0100 ; 256 entries * 4KiB = 1 MiB
mov eax, 0
.pt_0_fill:
mov edx, eax
or edx, PTE_Present
mov [ebx], dword edx
add eax, 0x1000
add ebx, 4
loop .pt_0_fill
; set up the kernel code table
mov ebx, page_table_768 ; get index into the kernel code page table
memset32 0, 0x0400, ebx ; clear the table entries
; entries 0-4096 - mapping the start of higher half
mov ecx, 0x1000 ; 4096 entries * 4KiB = 4 MiB
mov eax, 0x00100000 ; the 1MiB entry point
.pt_768_fill:
mov edx, eax
or edx, PTE_Present
mov [ebx], dword edx
add eax, 0x1000
add ebx, 4
loop .pt_768_fill
.setup_directory:
mov ebx, page_directory
.pd_fill:
mov eax, page_table_0
or eax, PDE_Present
mov [ebx], eax
add ebx, 768 * 4
mov eax, page_table_768
or eax, PDE_Present
mov [ebx], eax
; set the page directory
mov eax, page_directory
mov cr3, eax
ret
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
-
- Member
- Posts: 5563
- Joined: Mon Mar 25, 2013 7:01 pm
Re: Page fault on accessing RSDT
You're correct. Important data (like ACPI tables) will be placed outside "free" memory so you don't accidentally overwrite it while allocating memory.Schol-R-LEA wrote:I assume that the solution is to add the firmware in question to the paged memory for the kernel, but I am concerned that I might be misreading the situation somehow.
This is one of those things where it's up to you, but you have two options: you can either create entirely new page tables or you can update the bootloader page tables.Schol-R-LEA wrote:I am also not entirely clear how to alter the page mapping in the kernel, given that I am currently using the page map set up in the boot loader. Any advice on this would be appreciated.
Either way, you need to know the addresses of the memory containing your kernel (to avoid overwriting it and ensure it remains mapped correctly) and the memory containing the bootloader's page tables (same except you can overwrite it once you're done using it). If you've chosen to identity map all usable memory, you can read CR3 and walk the current page tables yourself. Otherwise, you'll need some other way for your kernel to get that information.
Keep in mind that your kernel's virtual address may conflict with identity mapping. It's pretty common for there to be MMIO near physical address 0xC0000000, and there are some (rare?) chipsets that can even place RAM at physical address 0xC0000000. If you want, this could be your excuse to stop relying on identity mapping.
Also, this is completely unrelated, but your inb8 and outb8 inline assembly has an invalid "i" constraint. You should either use the "N" constraint by itself or delete those functions and use only your inb16 and outb16 functions.
- Schol-R-LEA
- Member
- Posts: 1925
- Joined: Fri Oct 27, 2006 9:42 am
- Location: Athens, GA, USA
Re: Page fault on accessing RSDT
I think it would make more sense at this stage to replace the existing page tables with ones that are in the kernel proper. I wasn't planning on tackling it quite this early, but as you said, this is a good point at which to start moving to a more flexible paging model.Octocontrabass wrote:This is one of those things where it's up to you, but you have two options: you can either create entirely new page tables or you can update the bootloader page tables.[...] If you want, this could be your excuse to stop relying on identity mapping.Schol-R-LEA wrote:I am also not entirely clear how to alter the page mapping in the kernel, given that I am currently using the page map set up in the boot loader. Any advice on this would be appreciated.
sigh OK, I wasn't certain if the i was needed there or not; I was overthinking things again. I will fix that shortly. I am aware that the byte-wise functions are strictly speaking redundant, so I will probably just drop them entirely.Octocontrabass wrote:Also, this is completely unrelated, but your inb8 and outb8 inline assembly has an invalid "i" constraint. You should either use the "N" constraint by itself or delete those functions and use only your inb16 and outb16 functions.
Rev. First Speaker Schol-R-LEA;2 LCF ELF JAM POEE KoR KCO PPWMTF
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.
Ordo OS Project
Lisp programmers tend to seem very odd to outsiders, just like anyone else who has had a religious experience they can't quite explain to others.