mirror of
https://git.stationery.faith/corn/corn.git
synced 2024-11-25 15:50:02 +00:00
acpi + lib
This commit is contained in:
parent
89ecedfceb
commit
2747693fdb
4 changed files with 272 additions and 0 deletions
23
include/acpi.h
Normal file
23
include/acpi.h
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
enum acpi_status {
|
||||||
|
ACPI_SUCCESS = 0,
|
||||||
|
ACPI_FAILURE = -1,
|
||||||
|
ACPI_MALFORMED_TABLE = -2,
|
||||||
|
ACPI_OLD_VERSION = -4,
|
||||||
|
ACPI_S5_PARSE_ERROR = -5,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the ACPI tables
|
||||||
|
* https://en.wikipedia.org/wiki/ACPI
|
||||||
|
* @param rsdp - pointer to the Root System Description Pointer
|
||||||
|
* usually passed from the bootlater
|
||||||
|
* @returns ACPI_SUCCESS on success
|
||||||
|
*/
|
||||||
|
int acpi_init(void *rsdp);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdowns down the system
|
||||||
|
* @returns ACPI_FAILURE on failure
|
||||||
|
*/
|
||||||
|
int acpi_shutdown(void);
|
12
include/lib.h
Normal file
12
include/lib.h
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The strcmp() function compares the two strings s1 and s2. The locale is not taken into account
|
||||||
|
* (for a locale-aware comparison, see strcoll(3)). The comparison is done using unsigned characters.
|
||||||
|
*/
|
||||||
|
int strncmp(const char *s1, const char *s2, unsigned long n);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The memcmp() function compares the first n bytes (each interpreted as unsigned char) of the memory
|
||||||
|
* areas s1 and s2.
|
||||||
|
*/
|
||||||
|
int memcmp(const void *s1, const void *s2, unsigned long n);
|
223
src/arch/amd64/acpi.c
Normal file
223
src/arch/amd64/acpi.c
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
#include "arch/amd64/bindings.h"
|
||||||
|
#include <acpi.h>
|
||||||
|
#include <lib.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
/* global state, idk a better way rn */
|
||||||
|
struct acpi_state state;
|
||||||
|
|
||||||
|
struct acpi_header {
|
||||||
|
char signature[4];
|
||||||
|
uint32_t length;
|
||||||
|
uint8_t revision;
|
||||||
|
uint8_t checksum;
|
||||||
|
char oem_id[6];
|
||||||
|
char oem_table_id[8];
|
||||||
|
uint32_t oem_revision;
|
||||||
|
uint32_t creator_id;
|
||||||
|
uint32_t creator_revision;
|
||||||
|
};
|
||||||
|
|
||||||
|
// eXtended system descriptor pointer
|
||||||
|
struct xsdp {
|
||||||
|
char signature[8];
|
||||||
|
uint8_t checksum;
|
||||||
|
char oemid[6];
|
||||||
|
uint8_t revision;
|
||||||
|
uint32_t rsdt_addr;
|
||||||
|
|
||||||
|
uint32_t length;
|
||||||
|
uint64_t xsdt_addr;
|
||||||
|
uint8_t extendeid_checksum;
|
||||||
|
uint8_t reserved[3];
|
||||||
|
} __attribute__((packed));
|
||||||
|
|
||||||
|
|
||||||
|
// eXtended system descriptor table
|
||||||
|
struct xsdt {
|
||||||
|
struct acpi_header h;
|
||||||
|
uint64_t sdt_pointers[];
|
||||||
|
};
|
||||||
|
|
||||||
|
// generic address structure
|
||||||
|
struct gas {
|
||||||
|
uint8_t address_space;
|
||||||
|
uint8_t bit_width;
|
||||||
|
uint8_t bit_offset;
|
||||||
|
uint8_t access_size;
|
||||||
|
uint64_t address;
|
||||||
|
};
|
||||||
|
|
||||||
|
// fixed acpi description table
|
||||||
|
struct fadt {
|
||||||
|
struct acpi_header h;
|
||||||
|
uint32_t firmware_ctrl;
|
||||||
|
uint32_t dsdt;
|
||||||
|
|
||||||
|
// field used in ACPI 1.0; no longer in use, for compatibility only
|
||||||
|
uint8_t reserved;
|
||||||
|
|
||||||
|
uint8_t preferred_power_management_profile;
|
||||||
|
uint16_t sci_interrupt;
|
||||||
|
uint32_t smi_command_port;
|
||||||
|
uint8_t acpi_enable;
|
||||||
|
uint8_t acpi_disable;
|
||||||
|
uint8_t s4bios_req;
|
||||||
|
uint8_t pstate_control;
|
||||||
|
uint32_t pm1_a_event_block;
|
||||||
|
uint32_t pm1_b_event_block;
|
||||||
|
uint32_t pm1_a_control_block;
|
||||||
|
uint32_t pm1_b_control_block;
|
||||||
|
uint32_t pm2_control_block;
|
||||||
|
uint32_t pm_timer_block;
|
||||||
|
uint32_t gpe0_block;
|
||||||
|
uint32_t gpe1_block;
|
||||||
|
uint8_t pm1_event_length;
|
||||||
|
uint8_t pm1_control_length;
|
||||||
|
uint8_t pm2_control_length;
|
||||||
|
uint8_t pm_timer_length;
|
||||||
|
uint8_t gpe0_length;
|
||||||
|
uint8_t gpe1_length;
|
||||||
|
uint8_t gpe1_base;
|
||||||
|
uint8_t cstate_control;
|
||||||
|
uint16_t worst_c2_latency;
|
||||||
|
uint16_t worst_c3_latency;
|
||||||
|
uint16_t flush_size;
|
||||||
|
uint16_t flush_stride;
|
||||||
|
uint8_t duty_offset;
|
||||||
|
uint8_t duty_width;
|
||||||
|
uint8_t day_alarm;
|
||||||
|
uint8_t month_alarm;
|
||||||
|
uint8_t century;
|
||||||
|
|
||||||
|
// reserved in ACPI 1.0; used since ACPI 2.0+
|
||||||
|
uint16_t boot_architecture_flags;
|
||||||
|
|
||||||
|
uint8_t reserved_2;
|
||||||
|
uint32_t flags;
|
||||||
|
|
||||||
|
// 12 byte structure; see below for details
|
||||||
|
struct gas reset_reg;
|
||||||
|
|
||||||
|
uint8_t reset_value;
|
||||||
|
uint8_t reserved_3[3];
|
||||||
|
|
||||||
|
// 64bit pointers - Available on ACPI 2.0+
|
||||||
|
uint64_t x_firmware_control;
|
||||||
|
uint64_t x_dsdt;
|
||||||
|
|
||||||
|
struct gas x_pm1_a_event_block;
|
||||||
|
struct gas x_pm1_b_event_block;
|
||||||
|
struct gas x_pm1_a_control_block;
|
||||||
|
struct gas x_pm1_b_control_block;
|
||||||
|
struct gas x_pm2_control_block;
|
||||||
|
struct gas x_pm_timer_block;
|
||||||
|
struct gas x_gpe0_block;
|
||||||
|
struct gas x_gpe1_block;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct acpi_state {
|
||||||
|
struct fadt fadt;
|
||||||
|
uint16_t SLP_TYPa;
|
||||||
|
uint16_t SLP_TYPb;
|
||||||
|
uint16_t SLP_EN;
|
||||||
|
uint16_t SCI_EN;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool checksum(uint8_t *data, size_t len) {
|
||||||
|
unsigned char sum = 0;
|
||||||
|
for (size_t i = 0; i < len; i++)
|
||||||
|
sum += data[i];
|
||||||
|
return sum == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int read_s5_addr(struct acpi_state *state) {
|
||||||
|
uintptr_t ptr = state->fadt.dsdt;
|
||||||
|
char *s5_addr = (void*) (ptr + 36);
|
||||||
|
|
||||||
|
int dsdt_len = *((int*) (ptr+1)) - 36;
|
||||||
|
while (0 < dsdt_len--) {
|
||||||
|
if ( memcmp(s5_addr, "_S5_", 4) == 0)
|
||||||
|
break;
|
||||||
|
s5_addr++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dsdt_len > 0) {
|
||||||
|
// check for valid AML structure
|
||||||
|
if ( ( *(s5_addr-1) == 0x08 || ( *(s5_addr-2) == 0x08 && *(s5_addr-1) == '\\') ) && *(s5_addr+4) == 0x12 ) {
|
||||||
|
s5_addr += 5;
|
||||||
|
s5_addr += ((*s5_addr &0xC0)>>6) +2; // calculate PkgLength size
|
||||||
|
|
||||||
|
if (*s5_addr == 0x0A)
|
||||||
|
s5_addr++; // skip byteprefix
|
||||||
|
state->SLP_TYPa = *(s5_addr)<<10;
|
||||||
|
s5_addr++;
|
||||||
|
|
||||||
|
if (*s5_addr == 0x0A)
|
||||||
|
s5_addr++; // skip byteprefix
|
||||||
|
state->SLP_TYPb = *(s5_addr)<<10;
|
||||||
|
|
||||||
|
state->SLP_EN = 1<<13;
|
||||||
|
state->SCI_EN = 1;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return ACPI_S5_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return ACPI_S5_PARSE_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ACPI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void *acpi_find_table(struct xsdt *xsdt, const char *identifier, int ident_len) {
|
||||||
|
int entries = (xsdt->h.length - sizeof(xsdt->h)) / 8;
|
||||||
|
|
||||||
|
for (int i = 0; i < entries; i++) {
|
||||||
|
struct acpi_header *h = (struct acpi_header *) (uintptr_t) xsdt->sdt_pointers[i];
|
||||||
|
if (!strncmp(h->signature, identifier, ident_len))
|
||||||
|
return (void *)h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TABLE NOT FOUND
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int acpi_init(void *rootsdp) {
|
||||||
|
struct xsdp *xsdp = (struct xsdp *) rootsdp;
|
||||||
|
|
||||||
|
if (!checksum((uint8_t *)xsdp, sizeof(struct xsdp)))
|
||||||
|
return ACPI_MALFORMED_TABLE;
|
||||||
|
|
||||||
|
if (xsdp->revision != 2)
|
||||||
|
return ACPI_OLD_VERSION;
|
||||||
|
|
||||||
|
struct xsdt *xsdt = (struct xsdt *) (uintptr_t) xsdp->xsdt_addr;
|
||||||
|
if (!checksum((uint8_t *) &xsdt->h, xsdt->h.length))
|
||||||
|
return ACPI_MALFORMED_TABLE;
|
||||||
|
|
||||||
|
struct fadt *fadt = acpi_find_table(xsdt, "FACP", 4);
|
||||||
|
if (!fadt)
|
||||||
|
return ACPI_MALFORMED_TABLE;
|
||||||
|
|
||||||
|
if (!checksum((uint8_t *) &fadt->h, fadt->h.length))
|
||||||
|
return ACPI_MALFORMED_TABLE;
|
||||||
|
|
||||||
|
state.fadt = *fadt;
|
||||||
|
|
||||||
|
int ret = read_s5_addr(&state);
|
||||||
|
if (!ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
outb(state.fadt.smi_command_port,state.fadt.acpi_enable);
|
||||||
|
|
||||||
|
return ACPI_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
int acpi_shutdown(void) {
|
||||||
|
outw((unsigned int) state.fadt.pm1_a_control_block, state.SLP_TYPb | state.SLP_EN);
|
||||||
|
return ACPI_FAILURE;
|
||||||
|
}
|
14
src/lib.c
Normal file
14
src/lib.c
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#include <lib.h>
|
||||||
|
|
||||||
|
int strncmp(const char *lhs, const char *rhs, unsigned long n) {
|
||||||
|
const unsigned char *l=(void *)lhs, *r=(void *)rhs;
|
||||||
|
if (!n--) return 0;
|
||||||
|
for (; *l && *r && n && *l == *r ; l++, r++, n--);
|
||||||
|
return *l - *r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int memcmp(const void *vl, const void *vr, unsigned long n) {
|
||||||
|
const unsigned char *l = vl, *r = vr;
|
||||||
|
for (; n && *l == *r; n--, l++, r++);
|
||||||
|
return n ? *l-*r : 0;
|
||||||
|
}
|
Loading…
Reference in a new issue