Finding IOAPIC Base Address with MADT (Causes Triple Fault)

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
FunnyGuy9796
Member
Member
Posts: 61
Joined: Tue Sep 13, 2022 9:29 pm
Libera.chat IRC: FunnyGuy9796

Finding IOAPIC Base Address with MADT (Causes Triple Fault)

Post by FunnyGuy9796 »

I have successfully accessed the RSDT and retrieved it's address. Now I am trying to pass that to the MADT in order to find the address of the IOAPIC. I had taken the function from the MADT article on the Wiki and modified it a bit so that it only retrieved the IOAPIC.

madt.c

Code: Select all

#include "madt.h"
 
uint64_t detect_ioapic(RSDT *rsdt) {
    uint8_t *ptr, *ptr2;
    uint32_t len;
    uint64_t ioapic_ptr = 0;
    for(len = *((uint32_t*)(rsdt + 4)), ptr2 = rsdt + 36; ptr2 < rsdt + rsdt->h.Length; ptr2 += rsdt->h.Signature[0]=='X' ? 8 : 4) {
        ptr = (uint8_t*)(uintptr_t)(rsdt->h.Signature[0]=='X' ? *((uint64_t*)ptr2) : *((uint32_t*)ptr2));
        if(!memcmp(ptr, "APIC", 4)) {
            ptr2 = ptr + *((uint32_t*)(ptr + 4));
            for(ptr += 44; ptr < ptr2; ptr += ptr[1]) {
                if (ptr[0] == 1) {
                    ioapic_ptr = (uint64_t)*((uint32_t*)(ptr+4));
                    return ioapic_ptr;
                }
            }
            break;
        }
    }
}
However, any of the code within the first if statement triggers a triple fault (even only having the 'break;'). I am a little confused as to why this is happening. I know it may be a stupid mistake or error I am missing but help would be much appreciated.
Octocontrabass
Member
Member
Posts: 5562
Joined: Mon Mar 25, 2013 7:01 pm

Re: Finding IOAPIC Base Address with MADT (Causes Triple Fau

Post by Octocontrabass »

FunnyGuy9796 wrote:However, any of the code within the first if statement triggers a triple fault (even only having the 'break;').
It triggers some other fault, and your fault-handling (or lack thereof) triggers the triple fault. That "some other fault" will tell you what's going on.

Now would be a good time to set up exception handlers. They don't have to be too fancy - just dump the CPU registers to the screen or a serial port and halt.

If you don't want to do that right now, your virtual machine can give you that information. (For example, if you're using QEMU, add "-d int" to your command line.)
FunnyGuy9796
Member
Member
Posts: 61
Joined: Tue Sep 13, 2022 9:29 pm
Libera.chat IRC: FunnyGuy9796

Re: Finding IOAPIC Base Address with MADT (Causes Triple Fau

Post by FunnyGuy9796 »

Alright, thanks! I will definitely do that. I kind of just skipped implementing an exception handler mainly because I was being lazy :/

Thank you for the advice!
rdos
Member
Member
Posts: 3296
Joined: Wed Oct 01, 2008 1:55 pm

Re: Finding IOAPIC Base Address with MADT (Causes Triple Fau

Post by rdos »

I think the IOAPIC is at a fixed address, so no reason to search ACPI tables for it. :-)
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Finding IOAPIC Base Address with MADT (Causes Triple Fau

Post by iansjack »

rdos wrote:I think the IOAPIC is at a fixed address, so no reason to search ACPI tables for it. :-)
Whilst that may be true in practice for current computers, I don't think it's a given. It's probably safer to future proof by specifically finding the address.
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Finding IOAPIC Base Address with MADT (Causes Triple Fau

Post by iansjack »

FunnyGuy9796 wrote:I kind of just skipped implementing an exception handler mainly because I was being lazy :/
I'm afraid that's false laziness. It is so easy to implement trivial exception handlers (e.g. just "jmp ." which then allows you to investigate the machine state in your debugger), and the consequences of not doing so can be so baffling, that it should be the first thing that you implement.
rdos
Member
Member
Posts: 3296
Joined: Wed Oct 01, 2008 1:55 pm

Re: Finding IOAPIC Base Address with MADT (Causes Triple Fau

Post by rdos »

iansjack wrote:
rdos wrote:I think the IOAPIC is at a fixed address, so no reason to search ACPI tables for it. :-)
Whilst that may be true in practice for current computers, I don't think it's a given. It's probably safer to future proof by specifically finding the address.
I think the chance of a buggy BIOS providing the wrong address actually is higher than the chance this will ever be changed. It's part of Intel's & AMD's chipsets, and not the motherboard build.
FunnyGuy9796
Member
Member
Posts: 61
Joined: Tue Sep 13, 2022 9:29 pm
Libera.chat IRC: FunnyGuy9796

Re: Finding IOAPIC Base Address with MADT (Causes Triple Fau

Post by FunnyGuy9796 »

Ok, after some debugging I found that the reason the triple fault occurred was because the MADT could not be found. I am unsure as to why that is the case but it is at least a step in the right direction. Does anyone have any idea why the MADT could not be found for the APIC?

Here's the current code:

Code: Select all

uint64_t detect_ioapic(uint8_t *rsdt) {
    if (rsdt == NULL) {
        terminal_write("RSDT not found\n");
    }
    uint8_t *ptr, *ptr2;
    uint32_t len;
    for(len = *((uint32_t*)(rsdt + 4)), ptr2 = rsdt + 36; ptr2 < rsdt + len; ptr2 += rsdt[0]=='X' ? 8 : 4) {
        ptr = (uint8_t*)(uintptr_t)(rsdt[0]=='X' ? *((uint64_t*)ptr2) : *((uint32_t*)ptr2));
        if(!memcmp(ptr, "APIC", 4)) {
            uint32_t *ptr32 = (uint32_t*)((uint8_t*)ptr + 0x24);
            uint32_t val32 = *ptr32;
            uint64_t lapic_ptr = (uint64_t)val32;
            ptr2 = ptr + *((uint32_t*)(ptr + 4));
            for(ptr += 44; ptr < ptr2; ptr += ptr[1]) {
                if (ptr[0] == 1) {
                    uint64_t ioapic_ptr = (uint64_t)*((uint32_t*)(ptr+4));
                    return ioapic_ptr;
                }
            }
            break;
        } else {
            terminal_write("Could not locate IOAPIC\n");
            return;
        }
    }
}
It is able to retrieve the RSDT but gets trapped in an infinite loop looking for the MADT.
nullplan
Member
Member
Posts: 1789
Joined: Wed Aug 30, 2017 8:24 am

Re: Finding IOAPIC Base Address with MADT (Causes Triple Fau

Post by nullplan »

You know, that doesn't work unless the MADT is the first table found. If the memcmp() returns nonzero, you will immediately return from the function. Without a value, so the caller will have no defined value telling them the MADT was not found. Also, if you do manage to find the MADT there, you overwrite "ptr2", so now the outer loop will no longer work. Might I suggest adding a few structures to make that mess more readable?
Carpe diem!
FunnyGuy9796
Member
Member
Posts: 61
Joined: Tue Sep 13, 2022 9:29 pm
Libera.chat IRC: FunnyGuy9796

Re: Finding IOAPIC Base Address with MADT (Causes Triple Fau

Post by FunnyGuy9796 »

Thank you for the advice. I added the return instruction because without it the loop is infinite and therefore triggers a fault. I am really only using this function to locate the IOAPIC so exiting once it is found isn't really an issue in this situation. I did fix the rewriting of the variable. However, I am still stuck trying to figure out how to find the IOAPIC because, as I said, the loop seems to trigger a fault which makes me think I am searching for the MADT incorrectly or something along those lines.
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Finding IOAPIC Base Address with MADT (Causes Triple Fau

Post by iansjack »

rdos wrote:
iansjack wrote:
rdos wrote:I think the IOAPIC is at a fixed address, so no reason to search ACPI tables for it. :-)
Whilst that may be true in practice for current computers, I don't think it's a given. It's probably safer to future proof by specifically finding the address.
I think the chance of a buggy BIOS providing the wrong address actually is higher than the chance this will ever be changed. It's part of Intel's & AMD's chipsets, and not the motherboard build.
If you don’t search, how do know there is only one?
FunnyGuy9796
Member
Member
Posts: 61
Joined: Tue Sep 13, 2022 9:29 pm
Libera.chat IRC: FunnyGuy9796

Re: Finding IOAPIC Base Address with MADT (Causes Triple Fau

Post by FunnyGuy9796 »

Update: I found the address it is usually at and set that as a constant and now everything is working fine.

ioapic.c

Code: Select all

#include "ioapic.h"

static inline uint32_t ioapic_read(uint32_t reg) {
    volatile uint32_t* ioapic = (uint32_t*)IOAPIC_BASE;
    *ioapic = reg;
    return *(ioapic + 4);
}

static inline void ioapic_write(uint32_t reg, uint32_t val) {
    volatile uint32_t* ioapic = (uint32_t*)IOAPIC_BASE;
    *ioapic = reg;
    *(ioapic + 4) = val;
}

void ioapic_init() {
    uint32_t id = ioapic_read(IOAPIC_REG_ID);
    uint32_t ver = ioapic_read(IOAPIC_REG_VER);
    for (int i = 0; i < 24; i++) {
        ioapic_write(IOAPIC_REG_REDTBL + i * 2, 0x10000);
        ioapic_write(IOAPIC_REG_REDTBL + i * 2 + 1, 0);
    }
    terminal_write("IOAPIC: Initialized\n");
}
ioapic.h

Code: Select all

#ifndef IOAPIC_H_INCLUDED
#define IOAPIC_H_INCLUDED

#define IOAPICID          0x00
#define IOAPICVER         0x01
#define IOAPICARB         0x02
#define IOAPICREDTBL(n)   (0x10 + 2 * n)

#include <stdint.h>
#include "../terminal.h"

#define IOAPIC_BASE 0xFEC00000

#define IOAPIC_REG_ID     0x00
#define IOAPIC_REG_VER    0x01
#define IOAPIC_REG_ARB    0x02
#define IOAPIC_REG_REDTBL 0x10

typedef struct {
    uint32_t low;
    uint32_t high;
} ioapic_redtbl_entry_t;

void ioapic_init();

#endif
I know it's not the cleanest implementation and probably not the most efficient but at least it works.
Post Reply