mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-08-08 02:40: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("_idt");
|
||||
__static_yoink("_irq");
|
||||
__static_yoink("_AcpiBootFlags");
|
||||
__static_yoink("EfiMain");
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
|
|
@ -26,12 +26,263 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/irq/acpi.internal.h"
|
||||
#include "libc/str/str.h"
|
||||
|
||||
#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) {
|
||||
const AcpiTableDsdt *dsdt;
|
||||
size_t length;
|
||||
const uint8_t *aml, *aml_end;
|
||||
AmlParseState parse;
|
||||
if (!dsdt_phy) {
|
||||
ACPI_WARN("FADT: no DSDT");
|
||||
return;
|
||||
|
@ -43,7 +294,12 @@ textstartup static void _AcpiDsdtInit(uintptr_t dsdt_phy) {
|
|||
ACPI_WARN("DSDT: no AML?");
|
||||
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) {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef 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/kprintf.h"
|
||||
#include "libc/log/color.internal.h"
|
||||
|
@ -38,6 +39,67 @@
|
|||
#define kAcpiMadtIoApic 1
|
||||
#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)
|
||||
|
||||
/**
|
||||
|
@ -234,17 +296,21 @@ forceinline AcpiStatus _AcpiGetTable(const char __sig[4], uint32_t __inst,
|
|||
|
||||
#define ACPI_INFO(FMT, ...) \
|
||||
do { \
|
||||
if (!IsTiny()) { \
|
||||
kprintf("%r%s%s:%d: " FMT "%s\n", \
|
||||
SUBTLE, __FILE__, __LINE__, ##__VA_ARGS__, RESET); \
|
||||
} \
|
||||
} while (0)
|
||||
#define ACPI_WARN(FMT, ...) \
|
||||
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); \
|
||||
} \
|
||||
} while (0)
|
||||
#define ACPI_FATAL(FMT, ...) \
|
||||
do { \
|
||||
kprintf("%rfatal: %s%s:%d: " FMT "%s\n", \
|
||||
kprintf("%r%sfatal: %s:%d: " FMT "%s\n", \
|
||||
RED, __FILE__, __LINE__, ##__VA_ARGS__, RESET); \
|
||||
for (;;) asm volatile("cli\n\thlt"); \
|
||||
} while (0)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue