[MODERN FEATURES] ACPI tables

This commit is contained in:
Thomas Lovén 2016-11-20 00:22:13 +01:00
parent d801e0fd6c
commit 56d5fea388
6 changed files with 193 additions and 5 deletions

2
emul
View File

@ -58,7 +58,7 @@ function main() {
make all || exit 1
util/build_iso.sh || exit 1
echo > serial.log
emulator="qemu-system-x86_64 -cdrom mittos64.iso -serial file:serial.log ${EMULPARAM[@]}"
emulator="qemu-system-x86_64 -cdrom mittos64.iso -serial file:serial.log -smp 4 ${EMULPARAM[@]}"
debugger=$(which x86_64-elf-linux-gdb)
if [[ (-n ${EMULVNC}) ]]; then

117
kernel/arch/acpi.c Normal file
View File

@ -0,0 +1,117 @@
#include <acpi.h>
#include <stdint.h>
#include <debug.h>
#include <mem.h>
#include <string.h>
#include <multiboot.h>
RSDP_st *find_rsdp()
{
// The Root System Description Pointer (RSDP) should be found either
// - in the first 1 KB of the EBDA
// - between 0xE0000 and 0xFFFFF
// We'll only try the second alternative for now
uintptr_t start = KERNEL_OFFSET + 0xE0000;
uintptr_t end = KERNEL_OFFSET + 0xFFFFF;
uint8_t *p = (void *)start;
while((uintptr_t)p < end)
{
// The RSDP is identified by a signature string
if(!(memcmp(p, "RSD PTR ", 8)))
{
// Make sure we got it right by calculating the checksum
uint8_t checksum = 0;
for(int i = 0; i < 20; i++)
checksum += p[i];
if(!checksum)
break;
}
// The RSDP must be 16-byte aligned
p = incptr(p, 16);
}
if((uintptr_t)p >= end)
return 0;
return (void *)p;
}
SDT_header *find_SDT(RSDP_st *rsdp, char *signature)
{
// Scan through the RSDT or XSDT for a header with the wanted signature
// Read RSDT if revision <= 1.0
// else read XSDT
unsigned int bpp = (!rsdp->revision)?4:8;
SDT_header *rsdt = (bpp == 4) ? P2V(rsdp->RSDT_p) : P2V(rsdp->XSDT_p);
int entries = (rsdt->length - sizeof(SDT_header))/bpp;
for(int i = 0; i < entries; i++)
{
// 32 bit pointers if revision <= 1.0
// otherwise 64 bit pointers
SDT_header *h = (bpp == 4) ?
P2V(*(uint32_t*)&rsdt->data[i*bpp]) :
P2V(*(uint64_t*)&rsdt->data[i*bpp]);
// Return pointer if signature is correct
if(!memcmp(h->signature, signature, 4))
return h;
}
return 0;
}
void parse_MADT(SDT_header *header)
{
MADT_header *madt = (MADT_header *)header->data;
// Save the memory mapping of the local APIC
// TODO: In bochs, there are MADT entries with 0 length. I assume parsing should stop here.
// TODO: Look this up
for(MADT_field *f = (void*)madt->fields;
(uintptr_t)f < (uintptr_t)madt + header->length && f->length;
f = incptr(f, f->length))
{
switch(f->type)
{
case 0: // Processor Local APIC entry
debug_info("ACPI - Processor id:%x LAPIC:%x", f->proc.proc_ID, f->proc.APIC_ID);
if(f->proc.flags & 0x1)
{
debug(" enabled");
}
debug("\n");
break;
case 1: // I/O APIC entry
debug_info("ACPI - IOAPIC id:%x address:%x\n", f->IOAPIC.APIC_ID, f->IOAPIC.address);
break;
case 2: // Interrupt Source Override
debug_info("ACPI - Interrupt source override %x->%x\n", f->ISO.irq, f->ISO.interrupt);
break;
default:
break;
}
}
}
void acpi_init()
{
RSDP_st *rsdp;
if(!(rsdp = mboot_data.rsdp))
{
if(!(rsdp = find_rsdp()))
{
debug_error("PANIC: ACPI - No RSDP found!");
for(;;);
}
}
debug_info("ACPI - ACPI version %s\n", (rsdp->revision)?"2.0":"1.0");
// Scan for MADT
SDT_header *madt = find_SDT(rsdp, "APIC");
// Read processor info from MADT
parse_MADT(madt);
// Ignore all other tables for now
}

View File

@ -7,6 +7,7 @@
#include <thread.h>
#include <process.h>
#include <cpuid.h>
#include <acpi.h>
void thread_function()
{
@ -31,11 +32,8 @@ int kmain(uint64_t multiboot_magic, void *multiboot_data)
gdt_init();
scheduler_init();
pic_init();
acpi_init();
debug_info("CPUID - max function number: Normal:%x, Extended:%x\n", cpuid_max, cpuid_maxx);
debug_info("CPUID - has MSR:%d\n", CPUID_FEATURE_MSR);
debug_info("CPUID - has APIC:%d\n", CPUID_FEATURE_APIC);
debug_info("CPUID - has SYSCALL:%d\n", CPUID_FEATURE_SYSCALL);
process_t *p1 = process_spawn(0);
process_t *p2 = process_spawn(p1);

View File

@ -70,6 +70,11 @@ void parse_multiboot2()
mboot_data.mmap = tag->data;
debug_ok("MBOOT2 - handle ");
break;
case MBOOT2_ACPI_V1:
case MBOOT2_ACPI_V2:
mboot_data.rsdp = &tag->data;
debug_ok("[MBOOT2] %x handle ", mboot_data.rsdp);
break;
default:
debug_warning("MBOOT2 - ignore ");
break;
@ -129,6 +134,8 @@ int multiboot_page_used(uintptr_t addr)
mboot2_tags_head *data = mboot_data.data;
if(overlapsz(addr, PAGE_SIZE, V2P(data), data->total_size))
return 1;
if(mboot_data.rsdp && overlapsz(addr, PAGE_SIZE, mboot_data.rsdp, 1))
return 1;
}
return 0;
}

63
kernel/include/acpi.h Normal file
View File

@ -0,0 +1,63 @@
#pragma once
#include <stdint.h>
typedef struct RSDP_st
{
unsigned char signature[8];
uint8_t checksum;
unsigned char OEMID[6];
uint8_t revision;
uint32_t RSDT_p;
// The following are only available if revision != 0
uint32_t length;
uint64_t XSDT_p;
uint8_t checksum2;
uint8_t reserved[3];
}__attribute__ ((packed)) RSDP_st;
typedef struct SDT_header
{
unsigned char signature[4];
uint32_t length;
uint8_t revision;
uint8_t checksum;
unsigned char OEMID[6];
unsigned char OEMtable[8];
uint32_t OEMrevision;
uint32_t CreatorID;
uint32_t CreatorRevision;
uint8_t data[];
}__attribute__ ((packed)) SDT_header;
typedef struct MADT_header
{
uint32_t LCA;
uint32_t flags;
uint8_t fields[];
}__attribute__((packed)) MADT_header;
typedef struct MADT_field
{
uint8_t type;
uint8_t length;
union{
struct{
uint8_t proc_ID;
uint8_t APIC_ID;
uint32_t flags;
}__attribute__((packed)) proc;
struct {
uint8_t APIC_ID;
uint8_t reserved;
uint32_t address;
uint32_t base;
}__attribute__((packed)) IOAPIC;
struct {
uint8_t bus;
uint8_t irq;
uint32_t interrupt;
uint16_t flags;
}__attribute__((packed)) ISO;
};
}__attribute__((packed)) MADT_field;
void acpi_init();

View File

@ -80,6 +80,8 @@ typedef struct {
#define MBOOT2_CMDLINE 1
#define MBOOT2_BOOTLOADER 2
#define MBOOT2_MMAP 6
#define MBOOT2_ACPI_V1 14
#define MBOOT2_ACPI_V2 15
// Multiboot tags are padded to a multiple of 8 bytes
#define next_tag(tag) ((void *)((((uintptr_t)tag) + tag->size + 7) & ~0x7))
@ -92,6 +94,7 @@ typedef struct {
char *bootloader;
void *mmap;
uint32_t mmap_size;
void *rsdp;
};
extern struct mboot_data_st mboot_data;