blob: 78075581e31a316882aebf73aa851052a033f4e2 (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
|
#include <panic.h>
#include <string.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <arch/i686/acpi.h>
#include <arch/i686/asm.h>
extern uintptr_t KERNEL_MAPPING;
static struct RootSystemDescriptionTable *rsdt;
static struct FixedACPIDescriptionTable *fadt;
static uint16_t SLP_TYPa;
static uint16_t SLP_TYPb;
static uint16_t SLP_EN;
static 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 void *find_fadt(void) {
int entries = (rsdt->header.length - sizeof(rsdt->header)) / 4;
for (int i = 0; i < entries; i++) {
uintptr_t sdt_ptr = rsdt->sdt_table[i];
struct SystemDescriptionTableHeader *h = (void*) sdt_ptr;
if (!strncmp(h->signature, "FACP", 4))
return (void *) h;
}
return NULL;
}
static void read_s5_addr(void) {
uintptr_t ptr = 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
SLP_TYPa = *(s5_addr)<<10;
s5_addr++;
if (*s5_addr == 0x0A)
s5_addr++; // skip byteprefix
SLP_TYPb = *(s5_addr)<<10;
SLP_EN = 1<<13;
SCI_EN = 1;
} else {
panic("\\_S5 parse error.");
}
} else {
panic("\\_S5 not present.");
}
}
void acpi_init(void *ptr) {
struct RootSystemDescriptionPointer *rsdp = ptr;
if (!checksum((uint8_t*) rsdp, sizeof(struct RootSystemDescriptionPointer))) {
panic("RSDP checksum failed to validate");
}
uintptr_t rsdt_ptr = rsdp->rsdt_address;
rsdt = (void *) rsdt_ptr;
if (!checksum((uint8_t*) &rsdt->header, rsdt->header.length)) {
panic("RSDT checksum failed to validate");
}
fadt = find_fadt();
if (fadt == NULL) {
panic("Could not find FADT");
}
if (!checksum((uint8_t*) &fadt->header, fadt->header.length)) {
panic("FADT checksum failed to validate");
}
read_s5_addr();
outb(fadt->smi_command_port,fadt->acpi_enable);
}
void acpi_poweroff(void) {
outw((unsigned int) fadt->pm1_a_control_block, SLP_TYPb | SLP_EN);
panic("failed to shutdown");
}
|