282 lines
6.7 KiB
C
282 lines
6.7 KiB
C
#include "../include/acpi.h"
|
|
#include "../include/memory.h"
|
|
#include "../include/graphics.h"
|
|
#include "../include/io.h"
|
|
#include "../include/isr.h"
|
|
#include "../include/timer.h"
|
|
|
|
uint16_t SLP_TYPa;
|
|
uint16_t SLP_TYPb;
|
|
uint32_t SMI_CMD;
|
|
uint8_t ACPI_ENABLE;
|
|
uint8_t ACPI_DISABLE;
|
|
uint32_t *PM1a_CNT;
|
|
uint32_t *PM1b_CNT;
|
|
uint8_t PM1_CNT_LEN;
|
|
uint16_t SLP_EN;
|
|
uint16_t SCI_EN;
|
|
|
|
acpi_rsdt_t *rsdt; // root system descript table
|
|
acpi_facp_t *facp; // fixed ACPI table
|
|
|
|
int acpi_enable_flag;
|
|
uint8_t *rsdp_address;
|
|
|
|
int acpi_enable() {
|
|
int i;
|
|
|
|
// check if enable ACPI
|
|
if (io_in16((uint32_t) PM1a_CNT) & SCI_EN) {
|
|
printf("ACPI already enable!\n");
|
|
return 0;
|
|
}
|
|
|
|
if (SMI_CMD && ACPI_ENABLE) {
|
|
// send ACPI_ENABLE cmd
|
|
io_out8((uint16_t)
|
|
SMI_CMD, ACPI_ENABLE);
|
|
|
|
// wait enable
|
|
for (i = 0; i < 300; i++) {
|
|
if (io_in16((uint32_t) PM1a_CNT) & SCI_EN) {
|
|
break;
|
|
}
|
|
clock_sleep(5);
|
|
}
|
|
// wait enable
|
|
if (PM1b_CNT) {
|
|
for (i = 0; i < 300; i++) {
|
|
if (io_in16((uint32_t) PM1b_CNT) & SCI_EN) {
|
|
break;
|
|
}
|
|
clock_sleep(5);
|
|
}
|
|
}
|
|
// check enable status
|
|
if (i < 300) {
|
|
printf("[acpi]: Enable ACPI\n");
|
|
return 0;
|
|
} else {
|
|
printf("Counld't enable ACPI\n");
|
|
return -1;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
int acpi_disable() {
|
|
int i;
|
|
|
|
if (!io_in16((uint16_t)PM1a_CNT) &SCI_EN)
|
|
return 0;
|
|
|
|
if (SMI_CMD || ACPI_DISABLE) {
|
|
io_out8((uint16_t)
|
|
SMI_CMD, ACPI_DISABLE);
|
|
|
|
for (i = 0; i < 300; i++) {
|
|
if (!io_in16((uint16_t)PM1a_CNT) &SCI_EN)
|
|
break;
|
|
clock_sleep(5);
|
|
}
|
|
|
|
for (i = 0; i < 300; i++) {
|
|
if (!io_in16((uint16_t)PM1b_CNT) &SCI_EN)
|
|
break;
|
|
clock_sleep(5);
|
|
}
|
|
|
|
if (i < 300) {
|
|
printf("ACPI Disable!\n");
|
|
return 0;
|
|
} else {
|
|
printf("Could't disable ACPI\n");
|
|
return -1;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
uint8_t *AcpiGetRSDPtr() {
|
|
uint32_t *addr;
|
|
uint32_t *rsdt;
|
|
uint32_t ebda;
|
|
|
|
for (addr = (uint32_t *) 0x000E0000; addr < (uint32_t *) 0x00100000; addr += 0x10 / sizeof(addr)) {
|
|
rsdt = AcpiCheckRSDPtr(addr);
|
|
if (rsdt) {
|
|
return rsdt;
|
|
}
|
|
}
|
|
|
|
// search extented bios data area for the root system description pointer signature
|
|
ebda = *(uint16_t * )
|
|
0x40E;
|
|
ebda = ebda * 0x10 & 0xfffff;
|
|
for (addr = (uint32_t *) ebda; addr < (uint32_t * )(ebda + 1024); addr += 0x10 / sizeof(addr)) {
|
|
rsdt = AcpiCheckRSDPtr(addr);
|
|
if (rsdt) {
|
|
return rsdt;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void power_reset() {
|
|
uint8_t val;
|
|
if (!SCI_EN)
|
|
return;
|
|
while (1) {
|
|
// write ICH port
|
|
io_out8(0x92, 0x01);
|
|
// send RESET_VAL
|
|
io_out8((uint32_t) facp->RESET_REG.address, facp->RESET_VALUE);
|
|
}
|
|
}
|
|
|
|
void power_off() {
|
|
if (!SCI_EN)
|
|
return;
|
|
while (1) {
|
|
printf("[acpi] send power off command!\n");
|
|
io_out16((uint32_t) PM1a_CNT, SLP_TYPa | SLP_EN);
|
|
if (!PM1b_CNT) {
|
|
io_out16((uint32_t) PM1b_CNT, SLP_TYPb | SLP_EN);
|
|
}
|
|
}
|
|
}
|
|
|
|
int AcpiCheckHeader(void *ptr, uint8_t *sign) {
|
|
uint8_t * bptr = ptr;
|
|
uint32_t len = *(bptr + 4);
|
|
uint8_t checksum = 0;
|
|
|
|
if (!memcmp(bptr, sign, 4)) {
|
|
while (len-- > 0) {
|
|
checksum += *bptr++;
|
|
}
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
uint8_t *AcpiCheckRSDPtr(void *ptr) {
|
|
char *sign = "RSD PTR ";
|
|
acpi_rsdptr_t *rsdp = ptr;
|
|
uint8_t * bptr = ptr;
|
|
uint32_t i = 0;
|
|
uint8_t check = 0;
|
|
|
|
// check signature
|
|
if (!memcmp(sign, bptr, 8)) {
|
|
printf("[acpi] rsdp found at %0x\n", bptr);
|
|
rsdp_address = bptr;
|
|
for (i = 0; i < sizeof(acpi_rsdptr_t); i++) {
|
|
check += *bptr;
|
|
bptr++;
|
|
}
|
|
if (!check) {
|
|
return (uint8_t * )
|
|
rsdp->rsdt;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
uint32_t AcpiGetMadtBase() {
|
|
uint32_t entrys = rsdt->length - HEADER_SIZE / 4;
|
|
uint32_t **p = &(rsdt->entry);
|
|
acpi_madt_t *madt = NULL;
|
|
|
|
while (--entrys) {
|
|
if (!AcpiCheckHeader(*p, "APIC")) {
|
|
madt = (acpi_madt_t *) *p;
|
|
return madt;
|
|
}
|
|
p++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int AcpiSysInit() {
|
|
|
|
uint32_t **p;
|
|
uint32_t entrys;
|
|
uint32_t dsdtlen;
|
|
|
|
rsdt = (acpi_rsdt_t *) AcpiGetRSDPtr();
|
|
if (!rsdt || AcpiCheckHeader(rsdt, "RSDT") < 0) {
|
|
printf("No ACPI\n");
|
|
return -1;
|
|
}
|
|
|
|
entrys = rsdt->length - HEADER_SIZE / 4;
|
|
p = &(rsdt->entry);
|
|
while (entrys--) {
|
|
if (!AcpiCheckHeader(*p, "FACP")) {
|
|
facp = (acpi_facp_t *) *p;
|
|
|
|
ACPI_ENABLE = facp->ACPI_ENABLE;
|
|
ACPI_DISABLE = facp->ACPI_DISABLE;
|
|
|
|
SMI_CMD = facp->SMI_CMD;
|
|
|
|
PM1a_CNT = facp->PM1a_CNT_BLK;
|
|
PM1b_CNT = facp->PM1b_CNT_BLK;
|
|
|
|
PM1_CNT_LEN = facp->PM1_CNT_LEN;
|
|
|
|
SLP_EN = 1 << 13;
|
|
SCI_EN = 1;
|
|
|
|
uint8_t * S5Addr;
|
|
uint32_t dsdtlen;
|
|
|
|
if (!AcpiCheckHeader(facp->DSDT, "DSDT")) {
|
|
S5Addr = &(facp->DSDT->definition_block);
|
|
dsdtlen = facp->DSDT->length - HEADER_SIZE;
|
|
while (dsdtlen--) {
|
|
if (!memcmp(S5Addr, "_S5_", 4)) {
|
|
break;
|
|
}
|
|
S5Addr++;
|
|
}
|
|
|
|
if (dsdtlen) {
|
|
// check valid \_S5
|
|
if (*(S5Addr - 1) == 0x08 || (*(S5Addr - 2) == 0x08 && *(S5Addr - 1) == '\\')) {
|
|
S5Addr += 5;
|
|
S5Addr += ((*S5Addr & 0xC0) >> 6) + 2;
|
|
|
|
if (*S5Addr == 0x0A) {
|
|
S5Addr++;
|
|
}
|
|
SLP_TYPa = *(S5Addr) << 10;
|
|
S5Addr++;
|
|
if (*S5Addr == 0x0A) {
|
|
S5Addr++;
|
|
}
|
|
SLP_TYPb = *(S5Addr) << 10;
|
|
S5Addr++;
|
|
} else {
|
|
printf("[acpi] \\_S5 parse error!\n");
|
|
}
|
|
} else {
|
|
printf("[acpi] \\_S5 not present!\n");
|
|
}
|
|
} else {
|
|
printf("[acpi] no found DSDT table\n");
|
|
}
|
|
return 0;
|
|
}
|
|
++p;
|
|
}
|
|
printf("[acpi] No valid FACP present\n");
|
|
}
|
|
|
|
void acpi_install() {
|
|
AcpiSysInit();
|
|
acpi_enable_flag = !acpi_enable();
|
|
// power init
|
|
// AcpiPowerInit();
|
|
} |