[MODERN FEATURES] ACPI tables
This commit is contained in:
parent
d801e0fd6c
commit
56d5fea388
2
emul
2
emul
@ -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
117
kernel/arch/acpi.c
Normal 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
|
||||
|
||||
}
|
@ -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);
|
||||
|
@ -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
63
kernel/include/acpi.h
Normal 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();
|
@ -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;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user