acpi table loading and shutdown works, plus mmap fix :3

This commit is contained in:
Freya Murphy 2024-02-03 21:38:57 -05:00
parent 85a9443704
commit 61e7fdf1eb
Signed by: freya
GPG key ID: 744AB800E383AE52
5 changed files with 140 additions and 126 deletions

View file

@ -9,12 +9,12 @@
#include "bindings.h" #include "bindings.h"
struct acpi_header { struct acpi_header {
char signature[4]; uint32_t signature;
uint32_t length; uint32_t length;
uint8_t revision; uint8_t revision;
uint8_t checksum; uint8_t checksum;
char oem_id[6]; uint8_t oem_id[6];
char oem_table_id[8]; uint8_t oem_table_id[8];
uint32_t oem_revision; uint32_t oem_revision;
uint32_t creator_id; uint32_t creator_id;
uint32_t creator_revision; uint32_t creator_revision;
@ -23,9 +23,9 @@ struct acpi_header {
// root system descriptor pointer // root system descriptor pointer
// ACPI 1.0 // ACPI 1.0
struct rsdp { struct rsdp {
char signature[8]; uint8_t signature[8];
uint8_t checksum; uint8_t checksum;
char oemid[6]; uint8_t oemid[6];
uint8_t revision; uint8_t revision;
uint32_t rsdt_addr; uint32_t rsdt_addr;
} __attribute__((packed)); } __attribute__((packed));
@ -38,11 +38,12 @@ struct xsdp {
char oemid[6]; char oemid[6];
uint8_t revision; uint8_t revision;
uint32_t rsdt_addr; uint32_t rsdt_addr;
struct {
uint32_t length; uint32_t length;
uint64_t xsdt_addr; uint64_t xsdt_addr;
uint8_t extendeid_checksum; uint8_t extendeid_checksum;
uint8_t reserved[3]; uint8_t reserved[3];
} ext;
} __attribute__((packed)); } __attribute__((packed));
// root system descriptor table // root system descriptor table
@ -50,14 +51,14 @@ struct xsdp {
struct rsdt { struct rsdt {
struct acpi_header h; struct acpi_header h;
uint32_t sdt_pointers[]; uint32_t sdt_pointers[];
}; } __attribute__((packed));
// eXtended system descriptor table // eXtended system descriptor table
// ACPI 2.0 // ACPI 2.0
struct xsdt { struct xsdt {
struct acpi_header h; struct acpi_header h;
uint64_t sdt_pointers[]; uint64_t sdt_pointers[];
}; } __attribute__((packed));
// generic address structure // generic address structure
@ -69,6 +70,27 @@ struct gas {
uint64_t address; uint64_t address;
}; };
// differentiated system description table
struct dsdt {
struct acpi_header h;
char s5_addr[];
} __attribute__((packed));
struct apic {
struct acpi_header h;
// todo
} __attribute__((packed));
struct hept {
struct acpi_header h;
// todo
} __attribute__((packed));
struct waet {
struct acpi_header h;
// todo
} __attribute__((packed));
// fixed acpi description table // fixed acpi description table
struct fadt { struct fadt {
struct acpi_header h; struct acpi_header h;
@ -135,15 +157,20 @@ struct fadt {
struct gas x_pm_timer_block; struct gas x_pm_timer_block;
struct gas x_gpe0_block; struct gas x_gpe0_block;
struct gas x_gpe1_block; struct gas x_gpe1_block;
}; } __attribute__((packed));
struct acpi_state { struct acpi_state {
union { union {
struct xsdt *xsdt; struct xsdt *xsdt;
struct rsdt *rsdt; struct rsdt *rsdt;
} dst; } sdt;
struct fadt *fadt;
struct dsdt *dsdt;
struct apic *apic;
struct hept *hept;
struct waet *waet;
uint8_t version; uint8_t version;
struct fadt fadt;
uint16_t SLP_TYPa; uint16_t SLP_TYPa;
uint16_t SLP_TYPb; uint16_t SLP_TYPb;
uint16_t SLP_EN; uint16_t SLP_EN;
@ -160,11 +187,10 @@ static bool checksum(uint8_t *data, size_t len) {
return sum == 0; return sum == 0;
} }
static int read_s5_addr(struct acpi_state *state) { static int read_s5_addr(struct dsdt *dsdt) {
uintptr_t ptr = state->fadt.dsdt; char *s5_addr = dsdt->s5_addr;
char *s5_addr = (void *) (ptr + 36); int dsdt_len = dsdt->h.length - sizeof(struct acpi_header);
int dsdt_len = *((int *) (ptr+1)) - 36;
while (0 < dsdt_len--) { while (0 < dsdt_len--) {
if (memcmp(s5_addr, "_S5_", 4) == 0) if (memcmp(s5_addr, "_S5_", 4) == 0)
break; break;
@ -179,15 +205,15 @@ static int read_s5_addr(struct acpi_state *state) {
if (*s5_addr == 0x0A) if (*s5_addr == 0x0A)
s5_addr++; // skip byteprefix s5_addr++; // skip byteprefix
state->SLP_TYPa = *(s5_addr)<<10; state.SLP_TYPa = *(s5_addr)<<10;
s5_addr++; s5_addr++;
if (*s5_addr == 0x0A) if (*s5_addr == 0x0A)
s5_addr++; // skip byteprefix s5_addr++; // skip byteprefix
state->SLP_TYPb = *(s5_addr)<<10; state.SLP_TYPb = *(s5_addr)<<10;
state->SLP_EN = 1<<13; state.SLP_EN = 1<<13;
state->SCI_EN = 1; state.SCI_EN = 1;
} else { } else {
return -1; return -1;
@ -199,129 +225,115 @@ static int read_s5_addr(struct acpi_state *state) {
return -1; return -1;
} }
static void *acpi_find_table_rsdt(struct rsdt *rsdt, const char *identifier, int ident_len) { static void acpi_load_table(uint64_t addr);
static void acpi_load_rsdt_tables(struct rsdt *rsdt) {
int entries = (rsdt->h.length - sizeof(rsdt->h)) / 4; int entries = (rsdt->h.length - sizeof(rsdt->h)) / 4;
for (int i = 0; i < entries; i++) { for (int i = 0; i < entries; i++) {
struct acpi_header *h = (struct acpi_header *) (uintptr_t) rsdt->sdt_pointers[i]; uint32_t addr = rsdt->sdt_pointers[i];
char buf[6]; acpi_load_table(addr);
memcpy(buf, h->signature, 4); }
buf[4] = '\n';
buf[5] = '\0';
kputs(buf);
if (!strncmp(h->signature, identifier, ident_len))
return (void *)h;
} }
// TABLE NOT FOUND static void acpi_load_xsdt_tables(struct xsdt *xsdt) {
return NULL;
}
static void *acpi_find_table_xsdt(struct xsdt *xsdt, const char *identifier, int ident_len) {
int entries = (xsdt->h.length - sizeof(xsdt->h)) / 8; int entries = (xsdt->h.length - sizeof(xsdt->h)) / 8;
for (int i = 0; i < entries; i++) { for (int i = 0; i < entries; i++) {
struct acpi_header *h = (struct acpi_header *) (uintptr_t) xsdt->sdt_pointers[i]; uint64_t addr = xsdt->sdt_pointers[i];
if (!strncmp(h->signature, identifier, ident_len)) acpi_load_table(addr);
return (void *)h; }
} }
// TABLE NOT FOUND #define SIG_RSDT 0x54445352
return NULL; #define SIG_XSDT 0x54445358
#define SIG_FACP 0x50434146
#define SIG_DSDT 0x54445344
#define SIG_APIC 0x43495041
#define SIG_HEPT 0x54455048
#define SIG_WAET 0x54454157
static void acpi_handle_table(struct acpi_header *header) {
switch (header->signature) {
case SIG_RSDT:
state.sdt.rsdt = (struct rsdt *) header;
acpi_load_rsdt_tables(state.sdt.rsdt);
break;
case SIG_XSDT:
state.sdt.xsdt = (struct xsdt *) header;
acpi_load_xsdt_tables(state.sdt.xsdt);
break;
case SIG_FACP:
state.fadt = (struct fadt *) header;
acpi_load_table(state.fadt->dsdt);
break;
case SIG_DSDT:
state.dsdt = (struct dsdt *) header;
read_s5_addr(state.dsdt);
break;
case SIG_APIC:
state.apic = (struct apic *) header;
break;
case SIG_HEPT:
state.hept = (struct hept *) header;
break;
case SIG_WAET:
state.waet = (struct waet *) header;
break;
default:
break;
}
} }
int acpi_init_rsdt(struct rsdt *rsdt) { static void acpi_load_table(uint64_t addr) {
struct acpi_header *temp, *mapped;
uint32_t length;
kprintf("RSDT: %#016lx\n", (size_t)rsdt); temp = (struct acpi_header * ) (uintptr_t) addr;
mapped = mmap(temp, sizeof(struct acpi_header));
rsdt = mmap(rsdt, sizeof(struct rsdt)); length = mapped->length;
unmap(mapped);
state.dst.rsdt = rsdt; mapped = mmap(temp, length);
state.version = 0; if (!checksum((uint8_t *) mapped, mapped->length)) {
unmap(mapped);
if (!checksum((uint8_t *) &rsdt->h, rsdt->h.length)) return;
return -1;
struct fadt *fadt = acpi_find_table_rsdt(rsdt, "FACP", 4);
if (!fadt)
return -1;
if (!checksum((uint8_t *) &fadt->h, fadt->h.length))
return -1;
state.fadt = *fadt;
return -1;
} }
kprintf("%.*s: %#016lx\n", 4, (char*)&mapped->signature, (size_t)temp);
int acpi_init_xsdt(struct xsdt *xsdt) { acpi_handle_table(mapped);
xsdt = mmap(xsdt, sizeof(struct xsdt));
return -1;
state.dst.xsdt = xsdt;
state.version = 2;
if (!checksum((uint8_t *) &xsdt->h, xsdt->h.length))
return -1;
struct fadt *fadt = acpi_find_table_xsdt(xsdt, "FACP", 4);
if (!fadt)
return -1;
if (!checksum((uint8_t *) &fadt->h, fadt->h.length))
return -1;
state.fadt = *fadt;
return 0;
} }
int acpi_init(void *rootsdp) { int acpi_init(void *rootsdp) {
memset(&state, 0, sizeof(struct acpi_state));
struct rsdp *rsdp = (struct rsdp *) rootsdp; struct rsdp *rsdp = (struct rsdp *) rootsdp;
if (!checksum((uint8_t *)rsdp, sizeof(struct rsdp))) if (!checksum((uint8_t *)rsdp, sizeof(struct rsdp)))
return -1; return -1;
if (strncmp(rsdp->signature, "RSD PTR ", 8) != 0) { if (memcmp(rsdp->signature, "RSD PTR ", 8) != 0) {
panic("invalid acpi rsdp signature: %.*s\n", 8, rsdp->signature); panic("invalid acpi rsdp signature: %.*s\n", 8, rsdp->signature);
} }
int res;
if (rsdp->revision == 0) { if (rsdp->revision == 0) {
state.version = 0;
kprintf("ACPI 1.0\n"); kprintf("ACPI 1.0\n");
kprintf("RSDP: %#016lx\n", (size_t)rsdp); acpi_load_table(rsdp->rsdt_addr);
res = acpi_init_rsdt(
(struct rsdt *) (uintptr_t) rsdp->rsdt_addr
);
} else if (rsdp->revision == 2) { } else if (rsdp->revision == 2) {
state.version = 2;
struct xsdp *xsdp = (struct xsdp *) rsdp; struct xsdp *xsdp = (struct xsdp *) rsdp;
kprintf("ACPI 2.0\n"); kprintf("ACPI 2.0\n");
kprintf("XSDP: %#016lx\n", (size_t)xsdp); acpi_load_table(xsdp->ext.xsdt_addr);
res = acpi_init_xsdt(
(struct xsdt *) (uintptr_t) xsdp->xsdt_addr
);
} else { } else {
panic("invalid acpi rev: %d\n", rsdp->revision); panic("invalid acpi rev: %d\n", rsdp->revision);
} }
if (res) { kprintf("\n");
kprintf("...acpi failed to load\n\n");
return res;
}
kprintf("\n\n"); outb(state.fadt->smi_command_port,state.fadt->acpi_enable);
int ret = read_s5_addr(&state);
if (!ret)
return ret;
outb(state.fadt.smi_command_port,state.fadt.acpi_enable);
return 0; return 0;
} }
int acpi_shutdown(void) { int acpi_shutdown(void) {
outw((unsigned int) state.fadt.pm1_a_control_block, state.SLP_TYPb | state.SLP_EN); outw((unsigned int) state.fadt->pm1_a_control_block, state.SLP_TYPb | state.SLP_EN);
return -1; return -1;
} }

View file

@ -135,7 +135,7 @@ void idt_exception_handler(uint64_t exception, uint64_t code, struct isr_regs *s
kprintf("Error code 0x%lX\n", code); kprintf("Error code 0x%lX\n", code);
if (exception == EX_PAGE_FAULT) { if (exception == EX_PAGE_FAULT) {
kprintf("Page fault address: 0x%lX\n", cr2); kprintf("Page fault address: %#016lx\n", cr2);
} }
kputs("\n"); kputs("\n");

View file

@ -539,20 +539,20 @@ void paging_init(void) {
static inline void *page_align(void *addr) { static inline void *page_align(void *addr) {
uintptr_t a = (uintptr_t) addr; uintptr_t a = (uintptr_t) addr;
a += PAGE_SIZE - 1;
a /= PAGE_SIZE; a /= PAGE_SIZE;
a *= PAGE_SIZE; a *= PAGE_SIZE;
return (void *) a; return (void *) a;
} }
void *mmap(void *addr, size_t len) { void *mmap(void *addr, size_t len) {
len += (long)addr % PAGE_SIZE; void *phys = page_align(addr);
long pages = (len + PAGE_SIZE - 1) / PAGE_SIZE; ptrdiff_t error = (char*)addr - (char*)phys;
len += error;
long pages = len / PAGE_SIZE + 1;
void *virt = virtaddr_alloc(pages); void *virt = virtaddr_alloc(pages);
if (virt == NULL) { if (virt == NULL) {
return NULL; return NULL;
} }
void *phys = page_align(addr);
if (map_pages( if (map_pages(
kernel_pml4, kernel_pml4,
virt, virt,
@ -563,7 +563,7 @@ void *mmap(void *addr, size_t len) {
virtaddr_free(virt); virtaddr_free(virt);
return NULL; return NULL;
} }
return virt; return (char*)virt + error;
} }
void unmap(void *addr) { void unmap(void *addr) {

View file

@ -15,12 +15,12 @@ void kmain(struct boot_info *info) {
kprintf("enterd kmain\n"); kprintf("enterd kmain\n");
//acpi_shutdown();
// pages are allocated on write :3 // pages are allocated on write :3
char *test = kalloc(5); char *test = kalloc(5);
*test = 1; *test = 1;
//log_backtrace();
while (1) { while (1) {
screen_redraw(); screen_redraw();
// loop so we dont halt // loop so we dont halt

View file

@ -95,6 +95,7 @@ static enum printtype conversion_to_printtype(enum format_conversion conversion)
return OCTAL; return OCTAL;
case FMT_HEX: case FMT_HEX:
case FMT_HEX_UPPER: case FMT_HEX_UPPER:
case FMT_PTR:
return HEX; return HEX;
default: default:
return NONE; return NONE;
@ -377,11 +378,12 @@ static void print_number_buffer(
const char *buf, // buffer containing the text we want to print const char *buf, // buffer containing the text we want to print
struct spacing spacing, // the spacing on the left right and middle struct spacing spacing, // the spacing on the left right and middle
enum printtype type, enum printtype type,
enum charcase cc enum charcase cc,
enum format_flag flags
) { ) {
// put the 0x at the start of the string // put the 0x at the start of the string
if (spacing.left && spacing.zero && type == HEX) { if (spacing.left && spacing.zero && type == HEX && (flags & FLG_ALTERNATE)) {
if (cc == UPPERCASE) { if (cc == UPPERCASE) {
kputs("0X"); kputs("0X");
} else { } else {
@ -389,7 +391,7 @@ static void print_number_buffer(
} }
} }
if ((!spacing.left || !spacing.zero) && type == OCTAL) { if ((!spacing.left || !spacing.zero) && type == OCTAL && (flags & FLG_ALTERNATE)) {
kputc('0'); kputc('0');
} }
@ -397,7 +399,7 @@ static void print_number_buffer(
spacing.zero ? kputc('0') : kputc(' '); spacing.zero ? kputc('0') : kputc(' ');
} }
if ((!spacing.left || !spacing.zero) && type == HEX) { if ((!spacing.left || !spacing.zero) && type == HEX && (flags & FLG_ALTERNATE)) {
if (cc == UPPERCASE) { if (cc == UPPERCASE) {
kputs("0X"); kputs("0X");
} else { } else {
@ -457,18 +459,18 @@ static struct spacing get_spacing(
} }
unsigned gap = 0; unsigned gap = 0;
if (max > length) { if (min > length) {
gap = max - length; gap = min - length;
} }
spacing.length = length; spacing.length = length;
if (flags & FLG_LEFT_ALIGN) { if (flags & FLG_LEFT_ALIGN) {
spacing.left = gap;
spacing.right = 0;
} else {
spacing.left = 0; spacing.left = 0;
spacing.right = gap; spacing.right = gap;
} else {
spacing.left = gap;
spacing.right = 0;
} }
spacing.zero = (flags & FLG_ZERO); spacing.zero = (flags & FLG_ZERO);
@ -574,7 +576,7 @@ static void print_signed_number(
unsigned length = strlen(ptr); unsigned length = strlen(ptr);
struct spacing spacing = struct spacing spacing =
get_spacing(width, precision, flags, length); get_spacing(width, precision, flags, length);
print_number_buffer(ptr, spacing, type, cc); print_number_buffer(ptr, spacing, type, cc, flags);
} }
static void print_unsigned_number( static void print_unsigned_number(
@ -591,7 +593,7 @@ static void print_unsigned_number(
unsigned length = strlen(ptr); unsigned length = strlen(ptr);
struct spacing spacing = struct spacing spacing =
get_spacing(width, precision, flags, length); get_spacing(width, precision, flags, length);
print_number_buffer(ptr, spacing, type, cc); print_number_buffer(ptr, spacing, type, cc, flags);
} }
static bool is_conversion_number(enum format_conversion conversion) { static bool is_conversion_number(enum format_conversion conversion) {