From fa1b35bf188f7eb7eef51b853789336ea8ba4c0b Mon Sep 17 00:00:00 2001 From: Matheus Date: Fri, 5 Aug 2022 23:33:54 -0300 Subject: [PATCH] basic apic + fix some stupid issues created an initial stub implementation of the apic driver, added the madt to acpi, fixed an issue with the strncmp, made the pmm set only free pages rather than used ones --- src/arch/x86_64/acpi.c | 8 +- src/arch/x86_64/apic.c | 225 ++++++++++++++++++++++++++++ src/arch/x86_64/include/arch/acpi.h | 8 + src/arch/x86_64/include/arch/apic.h | 8 + src/arch/x86_64/main.c | 9 +- src/include/string/strncmp.c | 2 +- src/sys/mm/pmm.c | 10 +- 7 files changed, 255 insertions(+), 15 deletions(-) create mode 100644 src/arch/x86_64/apic.c create mode 100644 src/arch/x86_64/include/arch/apic.h diff --git a/src/arch/x86_64/acpi.c b/src/arch/x86_64/acpi.c index 330b3f4c..55f2f57d 100644 --- a/src/arch/x86_64/acpi.c +++ b/src/arch/x86_64/acpi.c @@ -16,13 +16,12 @@ static volatile struct limine_rsdp_request rsdpreq = { .revision = 0 }; -static bool checksumok(sdt_t* table){ +bool acpi_checksumok(sdt_t* table){ uint8_t sum; uint8_t* ptr = (uint8_t*)table; for(size_t i = 0; i < table->length; ++i) sum += *ptr++; - return sum == 0; } @@ -35,12 +34,11 @@ void* acpi_gettable(char* sig, size_t n){ for(size_t i = 0; i < sdtentrycount; ++i){ sdt_t* table = usersdt ? (*(uint32_t*)ptr & 0xFFFFFFFF) : *(uint64_t*)ptr; - table = (uint8_t*)table + (size_t)limine_hhdm_offset; if(!strncmp(sig, table->signature, 4)){ if(n-- == 0) - return (uint8_t*)table + (size_t) limine_hhdm_offset; + return table; } @@ -76,7 +74,7 @@ void acpi_init(){ printf("Root System Description Table address: %p with %lu tables\n", sdt, sdtentrycount); - if(!checksumok(sdt)) + if(!acpi_checksumok(sdt)) _panic("Invalid RSDT checksum!", 0); } diff --git a/src/arch/x86_64/apic.c b/src/arch/x86_64/apic.c new file mode 100644 index 00000000..b583a02f --- /dev/null +++ b/src/arch/x86_64/apic.c @@ -0,0 +1,225 @@ +#include +#include +#include +#include +#include +#include + + +#define TYPE_LAPIC 0 +#define TYPE_IOAPIC 1 +#define TYPE_OVERRIDE 2 +#define TYPE_IOAPICNMI 3 +#define TYPE_LAPICNMI 4 +#define TYPE_ADDROVERRIDE 5 +#define TYPE_X2APIC 9 + +typedef struct{ + uint8_t type; + uint8_t length; +} __attribute__((packed)) entry_head; + +typedef struct{ + entry_head header; + uint8_t acpi_id; + uint8_t apicid; + uint32_t flags; +} __attribute__((packed)) lapic_entry; + +typedef struct{ + entry_head header; + uint8_t id; + uint8_t reserved; + uint32_t address; + uint32_t gsibase; +} __attribute__((packed)) ioapic_entry; + +typedef struct{ + entry_head header; + uint8_t bus; + uint8_t irq; + uint32_t gsi; + uint16_t flags; + +} __attribute__((packed)) override_entry; + +typedef struct{ + entry_head header; + uint8_t source; + uint8_t reserved; + uint16_t flags; + uint32_t gsi; +} __attribute__((packed)) ioapicnmi_entry; + +typedef struct{ + entry_head header; + uint8_t acpi_id; + uint16_t flags; + uint8_t lint; +} __attribute__((packed)) lapicnmi_entry; + +typedef struct{ + entry_head header; + uint16_t reserved; + uint64_t addr; +} __attribute__((packed)) overrideaddr_entry; + +typedef struct{ + entry_head header; + uint16_t reserved; + uint32_t x2apicid; + uint32_t flags; + uint32_t acpi_id; +} __attribute__((packed)) x2apic_entry; + +typedef struct{ + int id; + int gsi; + volatile void* address; + size_t mre; +} ioapic_descriptor; + +static size_t lapic_count = 0; +static size_t ioapic_count = 0; +static size_t override_count = 0; +static size_t ionmi_count = 0; +static size_t localnmi_count = 0; +static size_t x2apic_count = 0; + +void* lapicaddr; +ioapic_descriptor* ioapics; + +void* tablestart; +void* tableend; + +static inline entry_head* next(entry_head* entry){ + return (void*)entry + entry->length; +} + +static void* findstructure(size_t type, size_t n){ + + entry_head* entry = tablestart; + + + while(entry < tableend){ + if(entry->type == type){ + if(n-- == 0) + return entry; + } + + entry = next(entry); + } + + return NULL; + +} + +static inline void ioapic_writereg(ioapic_descriptor* ioapic, uint32_t offset, uint32_t data){ + volatile uint32_t* reg = ioapic->address; + *reg = offset; // select + *(reg + 4) = data; // data +} + +static inline uint32_t ioapic_readreg(ioapic_descriptor* ioapic, uint32_t offset){ + volatile uint32_t* reg = ioapic->address; + *reg = offset; // select + return *(reg + 4); // data + + +} + +static void ioapic_writeiored(ioapic_descriptor* ioapic, uint8_t irq, uint8_t vector, uint8_t delivery, uint8_t destmode, uint8_t polarity, uint8_t irr, uint8_t mode, uint8_t mask, uint8_t dest){ + uint32_t val = vector; + val |= (delivery & 0b111) << 8; + val |= (destmode & 1) << 11; + val |= (polarity & 1) << 13; + val |= (irr & 1) << 14; + val |= (mode & 1) << 15; + val |= (mask & 1) << 16; + + ioapic_writereg(ioapic, 0x10 + irq * 2, val & 0xFFFFFFFF); + ioapic_writereg(ioapic, 0x10 + irq * 2 + 1, dest << 24); + +} + +void apic_init(){ + + // first get some cool info about the apic in the system + + madt_t* apic = acpi_gettable("APIC", 0); + + if(!apic) + _panic("No MADT found", 0); + + printf("MADT at %p\n", apic); + + lapicaddr = apic->apicaddr; + + // get the count of relevant entries + + size_t len = apic->header.length - sizeof(madt_t); + void* start = (void*)apic + sizeof(madt_t); + void* end = start + len; + entry_head* entry = start; + tablestart = start; + tableend = end; + while(entry < end){ + switch(entry->type){ + case TYPE_LAPIC: + ++lapic_count; + break; + case TYPE_IOAPIC: + ++ioapic_count; + break; + case TYPE_OVERRIDE: + ++override_count; + break; + case TYPE_IOAPICNMI: + ++ionmi_count; + break; + case TYPE_LAPICNMI: + ++localnmi_count; + break; + case TYPE_ADDROVERRIDE: + lapicaddr = ((overrideaddr_entry*)entry)->addr; + break; + case TYPE_X2APIC: + ++x2apic_count; + break; + + } + entry = next(entry); + } + + printf("MADT info:\nLocal APIC count: %lu\nIO APIC count: %lu\noverride count: %lu\nIO NMI count: %lu\nLocal NMI count: %lu\nX2APIC count: %lu\nLocal apic address: %p\n", lapic_count, ioapic_count, override_count, ionmi_count, localnmi_count, x2apic_count, lapicaddr); + + // map the local apic into memory (sea bios doesn't pass this to the limine map for some reason? I know my laptop UEFI firmware passes it) + + void* tmp = vmm_alloc(1, 0); + if(!tmp) _panic("Out of memory", 0); + vmm_map(lapicaddr, tmp, 1, ARCH_MMU_MAP_READ | ARCH_MMU_MAP_WRITE); + lapicaddr = tmp; + + // now set up the IO apic + + ioapics = alloc(sizeof(ioapic_descriptor)*ioapic_count); + + for(size_t i = 0; i < ioapic_count; ++i){ + + ioapic_entry* entry = findstructure(TYPE_IOAPIC, i); + void* tmp = vmm_alloc(1, 0); + if(!tmp) _panic("Out of memory", 0); + vmm_map(entry->address, tmp, 1, ARCH_MMU_MAP_READ | ARCH_MMU_MAP_WRITE); + + ioapics[i].address = tmp; + ioapics[i].gsi = entry->gsibase; + ioapics[i].id = entry->id; + ioapics[i].mre = (ioapic_readreg(&ioapics[i], 1) >> 16) & 0xFF; + + for(size_t j = 0; j <= ioapics[i].mre; ++j) + ioapic_writeiored(&ioapics[i], j, 0, 0, 0, 0, 0, 0, 1, 0); + } + + + +} diff --git a/src/arch/x86_64/include/arch/acpi.h b/src/arch/x86_64/include/arch/acpi.h index 0cd24ace..92152343 100644 --- a/src/arch/x86_64/include/arch/acpi.h +++ b/src/arch/x86_64/include/arch/acpi.h @@ -3,6 +3,7 @@ #include #include +#include typedef struct { char signature[8]; @@ -38,7 +39,14 @@ typedef struct { uint32_t pointers[]; } __attribute__((packed)) rsdt_t; +typedef struct { + sdt_t header; + uint32_t apicaddr; + uint32_t flags; +} __attribute__((packed)) madt_t; + void* acpi_gettable(char* sig, size_t n); void acpi_init(); +bool acpi_checksumok(sdt_t* table); #endif diff --git a/src/arch/x86_64/include/arch/apic.h b/src/arch/x86_64/include/arch/apic.h new file mode 100644 index 00000000..3ef03abb --- /dev/null +++ b/src/arch/x86_64/include/arch/apic.h @@ -0,0 +1,8 @@ +#ifndef _APIC_H_INCLUDE +#define _APIC_H_INCLUDE + + + +void apic_init(); + +#endif diff --git a/src/arch/x86_64/main.c b/src/arch/x86_64/main.c index b357fcfc..317d6752 100644 --- a/src/arch/x86_64/main.c +++ b/src/arch/x86_64/main.c @@ -9,6 +9,9 @@ #include #include #include +#include +#include +#include static volatile struct limine_terminal_request liminettyr = { .id = LIMINE_TERMINAL_REQUEST, @@ -38,10 +41,6 @@ void kmain(){ pmm_init(); - //set from 0xA0000 to 0x100000 as used - //as sometimes the bootloader doesn't pass this region as being used - - pmm_setused((void*)0xA0000, 0x60); arch_mmu_init(); @@ -59,6 +58,8 @@ void kmain(){ initrd_parse(); acpi_init(); + + apic_init(); _panic("End of kmain()", 0); diff --git a/src/include/string/strncmp.c b/src/include/string/strncmp.c index cb7c7636..9d31e9fa 100644 --- a/src/include/string/strncmp.c +++ b/src/include/string/strncmp.c @@ -4,7 +4,7 @@ int strncmp(const char *a, const char *b, size_t c){ int diff = 0; - while(c--) + while(c-- && diff == 0) diff += *a++ - *b++; diff --git a/src/sys/mm/pmm.c b/src/sys/mm/pmm.c index 8e12bd7b..d2265dd6 100644 --- a/src/sys/mm/pmm.c +++ b/src/sys/mm/pmm.c @@ -7,8 +7,8 @@ #define PAGE_SIZE 4096 -#define STATE_USED 1 -#define STATE_FREE 0 +#define STATE_USED 0 +#define STATE_FREE 1 void* limine_hhdm_offset; @@ -219,7 +219,7 @@ void pmm_init(){ memset(bitmap, 0, bitmapsize); - // mark needed entries as used now + // mark needed entries as free now printf("Ranges: \n"); @@ -236,9 +236,9 @@ void pmm_init(){ if(i % 2) printf("\n\033[0m"); - if(current->type == LIMINE_MEMMAP_USABLE) continue; + if(!current->type == LIMINE_MEMMAP_USABLE) continue; - pmm_setused((void*)current->base, current->length / PAGE_SIZE + 1); + pmm_free((void*)current->base, current->length / PAGE_SIZE + 1); }