mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-08 10:50:28 +00:00
[metal] Start parsing some ACPI AML
This commit is contained in:
parent
7dace0b171
commit
4eba5688ae
3 changed files with 337 additions and 14 deletions
|
@ -27,6 +27,7 @@
|
||||||
__static_yoink("vga_console");
|
__static_yoink("vga_console");
|
||||||
__static_yoink("_idt");
|
__static_yoink("_idt");
|
||||||
__static_yoink("_irq");
|
__static_yoink("_irq");
|
||||||
|
__static_yoink("_AcpiBootFlags");
|
||||||
__static_yoink("EfiMain");
|
__static_yoink("EfiMain");
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
|
|
|
@ -26,12 +26,263 @@
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/irq/acpi.internal.h"
|
#include "libc/irq/acpi.internal.h"
|
||||||
|
#include "libc/str/str.h"
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* lowest-level NameSeg of the most recent NameString/NamePath */
|
||||||
|
uint8_t name_seg[4];
|
||||||
|
} AmlParseState;
|
||||||
|
|
||||||
|
textstartup static void _AcpiCheckParseOverrun(const uint8_t *nxt,
|
||||||
|
const uint8_t *aml_end) {
|
||||||
|
if (nxt > aml_end) {
|
||||||
|
ACPI_FATAL("AML: parse overrun @ %p > %p", nxt, aml_end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup static void _AcpiCheckLeadNameChar(const uint8_t *aml, uint8_t c) {
|
||||||
|
if ((c >= 'A' && c <= 'Z') || c == '_') return;
|
||||||
|
ACPI_FATAL("AML: bad NameSeg %#x %#x %#x %#x @ %p",
|
||||||
|
(unsigned)aml[0], (unsigned)aml[1],
|
||||||
|
(unsigned)aml[2], (unsigned)aml[3], aml);
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup static void _AcpiCheckNameChar(const uint8_t *aml, uint8_t c) {
|
||||||
|
if (c >= '0' && c <= '9') return;
|
||||||
|
_AcpiCheckLeadNameChar(aml, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup static const uint8_t *_AcpiParseNameSeg(AmlParseState *parse,
|
||||||
|
const uint8_t *aml,
|
||||||
|
const uint8_t *aml_end) {
|
||||||
|
const uint8_t *nxt = aml + 4;
|
||||||
|
uint8_t c0 = aml[0], c1 = aml[1], c2 = aml[2], c3 = aml[3];
|
||||||
|
_AcpiCheckLeadNameChar(aml, c0);
|
||||||
|
_AcpiCheckNameChar(aml, c1);
|
||||||
|
_AcpiCheckNameChar(aml, c2);
|
||||||
|
_AcpiCheckNameChar(aml, c3);
|
||||||
|
parse->name_seg[0] = c0;
|
||||||
|
parse->name_seg[1] = c1;
|
||||||
|
parse->name_seg[2] = c2;
|
||||||
|
parse->name_seg[3] = c3;
|
||||||
|
return nxt;
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup static const uint8_t *_AcpiParseNameString(AmlParseState *parse,
|
||||||
|
const uint8_t *aml,
|
||||||
|
const uint8_t *aml_end)
|
||||||
|
{
|
||||||
|
const uint8_t *nxt = aml + 1;
|
||||||
|
unsigned seg_count;
|
||||||
|
switch (aml[0]) {
|
||||||
|
case kAmlNullName:
|
||||||
|
parse->name_seg[0] = '_';
|
||||||
|
parse->name_seg[1] = '_';
|
||||||
|
parse->name_seg[2] = '_';
|
||||||
|
parse->name_seg[3] = '_';
|
||||||
|
return nxt;
|
||||||
|
case kAmlDualNamePrefix:
|
||||||
|
nxt = _AcpiParseNameSeg(parse, nxt, aml_end);
|
||||||
|
nxt = _AcpiParseNameSeg(parse, nxt, aml_end);
|
||||||
|
return nxt;
|
||||||
|
case kAmlMultiNamePrefix:
|
||||||
|
++nxt;
|
||||||
|
seg_count = aml[1];
|
||||||
|
if (!seg_count) {
|
||||||
|
ACPI_FATAL("AML: MultiNamePath with zero SegCount @ %p", aml);
|
||||||
|
}
|
||||||
|
while (seg_count-- != 0) {
|
||||||
|
nxt = _AcpiParseNameSeg(parse, nxt, aml_end);
|
||||||
|
}
|
||||||
|
return nxt;
|
||||||
|
case kAmlRootPrefix:
|
||||||
|
case kAmlParentPrefix:
|
||||||
|
return _AcpiParseNameString(parse, nxt, aml_end);
|
||||||
|
default:
|
||||||
|
return _AcpiParseNameSeg(parse, aml, aml_end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup static const uint8_t *_AcpiParsePkgLength(const uint8_t *aml,
|
||||||
|
const uint8_t *aml_end,
|
||||||
|
uint32_t *pkg_length) {
|
||||||
|
uint8_t lead = aml[0];
|
||||||
|
uint32_t pl = 0;
|
||||||
|
const uint8_t *nxt = aml + 1 + (lead >> 6);
|
||||||
|
switch (lead >> 6) {
|
||||||
|
default:
|
||||||
|
pl = (uint32_t)aml[3] << 20; /* FALLTHRU */
|
||||||
|
case 2:
|
||||||
|
pl |= (uint32_t)aml[2] << 12; /* FALLTHRU */
|
||||||
|
case 1:
|
||||||
|
pl |= (uint32_t)aml[1] << 4;
|
||||||
|
pl |= lead & 0x0F;
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
pl = lead;
|
||||||
|
}
|
||||||
|
if (pkg_length) *pkg_length = pl;
|
||||||
|
return nxt;
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup static const uint8_t *_AcpiParseTermArg(AmlParseState *parse,
|
||||||
|
const uint8_t *aml,
|
||||||
|
const uint8_t *aml_end) {
|
||||||
|
const uint8_t *nxt = aml + 1;
|
||||||
|
switch (aml[0]) {
|
||||||
|
case kAmlZeroOp:
|
||||||
|
case kAmlOneOp:
|
||||||
|
case kAmlOnesOp:
|
||||||
|
return nxt;
|
||||||
|
case kAmlByteOp:
|
||||||
|
return nxt + 1;
|
||||||
|
case kAmlWordOp:
|
||||||
|
return nxt + 2;
|
||||||
|
case kAmlDwordOp:
|
||||||
|
return nxt + 4;
|
||||||
|
case kAmlQwordOp:
|
||||||
|
return nxt + 8;
|
||||||
|
case 'A' ... 'Z':
|
||||||
|
case '_':
|
||||||
|
case kAmlDualNamePrefix:
|
||||||
|
case kAmlMultiNamePrefix:
|
||||||
|
case kAmlRootPrefix:
|
||||||
|
case kAmlParentPrefix:
|
||||||
|
/* FIXME? */
|
||||||
|
nxt = _AcpiParseNameString(parse, aml, aml_end);
|
||||||
|
ACPI_WARN("AML: assuming ...%c%c%c%c @ %p not method call",
|
||||||
|
(int)parse->name_seg[0], (int)parse->name_seg[1],
|
||||||
|
(int)parse->name_seg[2], (int)parse->name_seg[3], aml);
|
||||||
|
return nxt;
|
||||||
|
case kAmlAddOp:
|
||||||
|
case kAmlConcatOp:
|
||||||
|
case kAmlSubtractOp:
|
||||||
|
case kAmlMultiplyOp:
|
||||||
|
case kAmlShiftLeftOp:
|
||||||
|
case kAmlShiftRightOp:
|
||||||
|
case kAmlAndOp:
|
||||||
|
case kAmlNandOp:
|
||||||
|
case kAmlOrOp:
|
||||||
|
case kAmlNorOp:
|
||||||
|
nxt = _AcpiParseTermArg(parse, nxt, aml_end);
|
||||||
|
nxt = _AcpiParseTermArg(parse, nxt, aml_end);
|
||||||
|
nxt = _AcpiParseNameString(parse, nxt, aml_end);
|
||||||
|
return nxt;
|
||||||
|
default:
|
||||||
|
ACPI_FATAL("AML: unknown TermArg type %#x @ %p", (unsigned)aml[0], aml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint8_t *_AcpiParseTermList(AmlParseState *,
|
||||||
|
const uint8_t *, const uint8_t *);
|
||||||
|
|
||||||
|
textstartup static const uint8_t *_AcpiParseTermObj(AmlParseState *parse,
|
||||||
|
const uint8_t *aml,
|
||||||
|
const uint8_t *aml_end) {
|
||||||
|
const uint8_t *nxt = aml + 1, *scope_end;
|
||||||
|
uint32_t pl;
|
||||||
|
_AcpiCheckParseOverrun(nxt, aml_end);
|
||||||
|
switch (aml[0]) {
|
||||||
|
case kAmlZeroOp:
|
||||||
|
case kAmlOneOp:
|
||||||
|
case kAmlOnesOp:
|
||||||
|
return nxt;
|
||||||
|
case kAmlAliasOp:
|
||||||
|
nxt = _AcpiParseNameString(parse, nxt, aml_end);
|
||||||
|
nxt = _AcpiParseNameString(parse, nxt, aml_end);
|
||||||
|
return nxt;
|
||||||
|
case kAmlNameOp:
|
||||||
|
nxt = _AcpiParseNameString(parse, nxt, aml_end);
|
||||||
|
nxt = _AcpiParseTermObj(parse, nxt, aml_end);
|
||||||
|
return nxt;
|
||||||
|
case kAmlByteOp:
|
||||||
|
return nxt + 1;
|
||||||
|
case kAmlWordOp:
|
||||||
|
return nxt + 2;
|
||||||
|
case kAmlDwordOp:
|
||||||
|
return nxt + 4;
|
||||||
|
case kAmlStringOp:
|
||||||
|
while (*nxt) ++nxt;
|
||||||
|
return nxt + 1;
|
||||||
|
case kAmlQwordOp:
|
||||||
|
return nxt + 8;
|
||||||
|
case kAmlScopeOp:
|
||||||
|
nxt = _AcpiParsePkgLength(nxt, aml_end, &pl);
|
||||||
|
scope_end = aml + 1 + pl;
|
||||||
|
nxt = _AcpiParseNameString(parse, nxt, scope_end);
|
||||||
|
nxt = _AcpiParseTermList(parse, nxt, scope_end);
|
||||||
|
return nxt;
|
||||||
|
case kAmlBufferOp:
|
||||||
|
case kAmlPackageOp:
|
||||||
|
case kAmlVariablePackageOp:
|
||||||
|
case kAmlMethodOp:
|
||||||
|
_AcpiParsePkgLength(nxt, aml_end, &pl);
|
||||||
|
/* ignore */
|
||||||
|
return nxt + pl;
|
||||||
|
case kAmlExtendedPrefix:
|
||||||
|
++nxt;
|
||||||
|
switch (aml[1]) {
|
||||||
|
case kAmlXMutexOp:
|
||||||
|
nxt = _AcpiParseNameString(parse, nxt, aml_end);
|
||||||
|
++nxt;
|
||||||
|
return nxt;
|
||||||
|
case kAmlXRegionOp:
|
||||||
|
nxt = _AcpiParseNameString(parse, nxt, aml_end);
|
||||||
|
++nxt;
|
||||||
|
nxt = _AcpiParseTermArg(parse, nxt, aml_end);
|
||||||
|
nxt = _AcpiParseTermArg(parse, nxt, aml_end);
|
||||||
|
return nxt;
|
||||||
|
case kAmlXFieldOp:
|
||||||
|
case kAmlXProcessorOp:
|
||||||
|
case kAmlXPowerResourceOp:
|
||||||
|
case kAmlXThermalZoneOp:
|
||||||
|
case kAmlXIndexFieldOp:
|
||||||
|
_AcpiParsePkgLength(nxt, aml_end, &pl);
|
||||||
|
/* ignore */
|
||||||
|
return nxt + pl;
|
||||||
|
case kAmlXDeviceOp:
|
||||||
|
ACPI_INFO("AML: DefDevice @ %p", aml);
|
||||||
|
_AcpiParsePkgLength(nxt, aml_end, &pl);
|
||||||
|
/* ignore */
|
||||||
|
return nxt + pl;
|
||||||
|
default:
|
||||||
|
ACPI_FATAL("AML: unknown TermObj type %#x %#x @ %p",
|
||||||
|
(unsigned)kAmlExtendedPrefix, (unsigned)aml[1], aml);
|
||||||
|
}
|
||||||
|
case kAmlCreateByteFieldOp:
|
||||||
|
case kAmlCreateWordFieldOp:
|
||||||
|
case kAmlCreateDwordFieldOp:
|
||||||
|
case kAmlCreateQwordFieldOp:
|
||||||
|
nxt = _AcpiParseTermArg(parse, nxt, aml_end);
|
||||||
|
nxt = _AcpiParseTermArg(parse, nxt, aml_end);
|
||||||
|
nxt = _AcpiParseNameString(parse, nxt, aml_end);
|
||||||
|
return nxt;
|
||||||
|
case kAmlIfOp:
|
||||||
|
ACPI_WARN("AML: skipping DefIfElse @ %p", aml);
|
||||||
|
_AcpiParsePkgLength(nxt, aml_end, &pl);
|
||||||
|
return nxt + pl;
|
||||||
|
default:
|
||||||
|
ACPI_FATAL("AML: unknown TermObj type %#x @ %p", (unsigned)aml[0], aml);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textstartup static const uint8_t *_AcpiParseTermList(AmlParseState *parse,
|
||||||
|
const uint8_t *aml,
|
||||||
|
const uint8_t *aml_end) {
|
||||||
|
const uint8_t *nxt = aml;
|
||||||
|
while (nxt != aml_end) {
|
||||||
|
nxt = _AcpiParseTermObj(parse, nxt, aml_end);
|
||||||
|
}
|
||||||
|
return nxt;
|
||||||
|
}
|
||||||
|
|
||||||
textstartup static void _AcpiDsdtInit(uintptr_t dsdt_phy) {
|
textstartup static void _AcpiDsdtInit(uintptr_t dsdt_phy) {
|
||||||
const AcpiTableDsdt *dsdt;
|
const AcpiTableDsdt *dsdt;
|
||||||
size_t length;
|
size_t length;
|
||||||
|
const uint8_t *aml, *aml_end;
|
||||||
|
AmlParseState parse;
|
||||||
if (!dsdt_phy) {
|
if (!dsdt_phy) {
|
||||||
ACPI_WARN("FADT: no DSDT");
|
ACPI_WARN("FADT: no DSDT");
|
||||||
return;
|
return;
|
||||||
|
@ -43,7 +294,12 @@ textstartup static void _AcpiDsdtInit(uintptr_t dsdt_phy) {
|
||||||
ACPI_WARN("DSDT: no AML?");
|
ACPI_WARN("DSDT: no AML?");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* TODO: parse AML to discover hardware configuration */
|
length -= offsetof(AcpiTableDsdt, Aml);
|
||||||
|
aml = dsdt->Aml;
|
||||||
|
aml_end = aml + length;
|
||||||
|
ACPI_INFO("AML @ %p,+%#zx", aml, length);
|
||||||
|
memset(&parse, 0, sizeof(parse));
|
||||||
|
_AcpiParseTermList(&parse, aml, aml_end);
|
||||||
}
|
}
|
||||||
|
|
||||||
textstartup void _AcpiFadtInit(void) {
|
textstartup void _AcpiFadtInit(void) {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#ifndef COSMOPOLITAN_LIBC_IRQ_ACPI_INTERNAL_H_
|
#ifndef COSMOPOLITAN_LIBC_IRQ_ACPI_INTERNAL_H_
|
||||||
#define COSMOPOLITAN_LIBC_IRQ_ACPI_INTERNAL_H_
|
#define COSMOPOLITAN_LIBC_IRQ_ACPI_INTERNAL_H_
|
||||||
|
#include "libc/dce.h"
|
||||||
#include "libc/intrin/bits.h"
|
#include "libc/intrin/bits.h"
|
||||||
#include "libc/intrin/kprintf.h"
|
#include "libc/intrin/kprintf.h"
|
||||||
#include "libc/log/color.internal.h"
|
#include "libc/log/color.internal.h"
|
||||||
|
@ -38,6 +39,67 @@
|
||||||
#define kAcpiMadtIoApic 1
|
#define kAcpiMadtIoApic 1
|
||||||
#define kAcpiMadtIntOverride 2
|
#define kAcpiMadtIntOverride 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* ACPI Machine Language (AML) opcodes.
|
||||||
|
*/
|
||||||
|
#define kAmlZeroOp 0x00
|
||||||
|
#define kAmlOneOp 0x01
|
||||||
|
#define kAmlAliasOp 0x06
|
||||||
|
#define kAmlNameOp 0x08
|
||||||
|
#define kAmlByteOp 0x0A
|
||||||
|
#define kAmlWordOp 0x0B
|
||||||
|
#define kAmlDwordOp 0x0C
|
||||||
|
#define kAmlStringOp 0x0D
|
||||||
|
#define kAmlQwordOp 0x0E
|
||||||
|
#define kAmlScopeOp 0x10
|
||||||
|
#define kAmlBufferOp 0x11
|
||||||
|
#define kAmlPackageOp 0x12
|
||||||
|
#define kAmlVariablePackageOp 0x13
|
||||||
|
#define kAmlMethodOp 0x14
|
||||||
|
#define kAmlExternalOp 0x15
|
||||||
|
#define kAmlExtendedPrefix 0x5B
|
||||||
|
#define kAmlAddOp 0x72
|
||||||
|
#define kAmlConcatOp 0x73
|
||||||
|
#define kAmlSubtractOp 0x74
|
||||||
|
#define kAmlMultiplyOp 0x77
|
||||||
|
#define kAmlShiftLeftOp 0x79
|
||||||
|
#define kAmlShiftRightOp 0x7A
|
||||||
|
#define kAmlAndOp 0x7B
|
||||||
|
#define kAmlNandOp 0x7C
|
||||||
|
#define kAmlOrOp 0x7D
|
||||||
|
#define kAmlNorOp 0x7E
|
||||||
|
#define kAmlCreateDwordFieldOp 0x8A
|
||||||
|
#define kAmlCreateWordFieldOp 0x8B
|
||||||
|
#define kAmlCreateByteFieldOp 0x8C
|
||||||
|
#define kAmlCreateBitFieldOp 0x8D
|
||||||
|
#define kAmlCreateQwordFieldOp 0x8F
|
||||||
|
#define kAmlIfOp 0xA0
|
||||||
|
#define kAmlOnesOp 0xFF
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* ACPI Machine Language (AML) opcodes prefixed with kAmlExtendedPrefix.
|
||||||
|
*/
|
||||||
|
#define kAmlXMutexOp 0x01
|
||||||
|
#define kAmlXRegionOp 0x80
|
||||||
|
#define kAmlXFieldOp 0x81
|
||||||
|
#define kAmlXDeviceOp 0x82
|
||||||
|
#define kAmlXProcessorOp 0x83
|
||||||
|
#define kAmlXPowerResourceOp 0x84
|
||||||
|
#define kAmlXThermalZoneOp 0x85
|
||||||
|
#define kAmlXIndexFieldOp 0x86
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @internal
|
||||||
|
* ACPI Machine Language (AML) name prefix codes.
|
||||||
|
*/
|
||||||
|
#define kAmlNullName 0x00
|
||||||
|
#define kAmlDualNamePrefix 0x2E
|
||||||
|
#define kAmlMultiNamePrefix 0x2F
|
||||||
|
#define kAmlRootPrefix 0x5C
|
||||||
|
#define kAmlParentPrefix 0x5E
|
||||||
|
|
||||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -234,17 +296,21 @@ forceinline AcpiStatus _AcpiGetTable(const char __sig[4], uint32_t __inst,
|
||||||
|
|
||||||
#define ACPI_INFO(FMT, ...) \
|
#define ACPI_INFO(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
|
if (!IsTiny()) { \
|
||||||
kprintf("%r%s%s:%d: " FMT "%s\n", \
|
kprintf("%r%s%s:%d: " FMT "%s\n", \
|
||||||
SUBTLE, __FILE__, __LINE__, ##__VA_ARGS__, RESET); \
|
SUBTLE, __FILE__, __LINE__, ##__VA_ARGS__, RESET); \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#define ACPI_WARN(FMT, ...) \
|
#define ACPI_WARN(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
kprintf("%r%s%s:%d: " FMT "%s\n", \
|
if (!IsTiny()) { \
|
||||||
|
kprintf("%r%swarn: %s:%d: " FMT "%s\n", \
|
||||||
BLUE1, __FILE__, __LINE__, ##__VA_ARGS__, RESET); \
|
BLUE1, __FILE__, __LINE__, ##__VA_ARGS__, RESET); \
|
||||||
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#define ACPI_FATAL(FMT, ...) \
|
#define ACPI_FATAL(FMT, ...) \
|
||||||
do { \
|
do { \
|
||||||
kprintf("%rfatal: %s%s:%d: " FMT "%s\n", \
|
kprintf("%r%sfatal: %s:%d: " FMT "%s\n", \
|
||||||
RED, __FILE__, __LINE__, ##__VA_ARGS__, RESET); \
|
RED, __FILE__, __LINE__, ##__VA_ARGS__, RESET); \
|
||||||
for (;;) asm volatile("cli\n\thlt"); \
|
for (;;) asm volatile("cli\n\thlt"); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue