Dependency-free, single header AML and FDT parser in ANSI C
bzt fa8e277c5f More bullet-proof AML parsing | 9 months ago | |
---|---|---|
docs | 9 months ago | |
LICENSE | 1 year ago | |
README.md | 9 months ago | |
hwdet.h | 9 months ago | |
test.c | 10 months ago |
The hwdet library is an easily embeddable, single header hardware resource detection library.
memcmp
and memset
).NOTE: if GPL license does not suit your use case, then you can use a command line utility to convert AML and DTB blobs into GUDT, and embed the single header gudt.h library in your kernel which is MIT licensed.
You include hwdet.h
in exactly one of your source files. But before you do that, you must tell the hook functions with two defines:
#define HWDET_RESVMEM mem_exclude
#define HWDET_RESOURCE drv_resource
#include "hwdet.h"
Then you pass a list of data pointers to the one and only function. These should point to either ACPI DSDT/SSDT/MADT tables, FDT or GUDT blobs.
void hwdet(int num, uint8_t **ds);
This iterates on num
blobs, parses their bytecode and calls the first hook whenever an unusable memory region found.
void HWDET_RESVMEM(uint64_t base, uint64_t size);
In your hook, you should exclude this region from your free memory list in your PMM. The region starts at base
and it is size
bytes in length.
The second hook is called whenever a resource is found.
void HWDET_RESOURCE(char *name, char *driver, char *altdriver, int type, uint64_t arg1, uint64_t arg2);
In your hook, you should pass these to your driver manager. The name
contains a unique device name, driver
is the type of the
device, aka. the name of the driver that can drive the device. If possible, then altdriver
is also reported, which is the name of
an alternative compatible driver. The type
is a resource code, that determines how arg1
and arg2
is used:
HWDET_NONE
no arguments.HWDET_CPU
arg1
is the spin-lock release address, arg2
is the unique id of the core (lAPIC id on x86).HWDET_IO
, arg1
is an IO port number, arg2
is length in bytes.HWDET_IRQ
, arg1
is an IRQ number, arg2
is the affinity level.HWDET_DMA
, arg1
is a DMA number, arg2
is the transfer width.HWDET_MMIO
, arg1
is a memory address, arg2
is length in bytes.HWDET_PCI
, arg1
and arg2
describes an address to PCI configuration space.HWDET_EC
, arg1
is an Embedded Control address, arg2
is length in bytes.HWDET_SMB
, arg1
is a System Management Bus address, arg2
is length in bytes.HWDET_CMOS
, arg1
is a CMOS address, arg2
is length in bytes.NOTE: multiple calls might be made with the same name
if multiple resources belong to that device. But because of buggy firmware,
always be prepared that you might get multiple calls with exactly the same arguments. See docs for real life examples.
That's all. Simplicity is the ultimate sophistication!
No need really. But if you want, you can specify the minimum number of AML nodes with AML_MINNODES
to make a fix sized stack.
This is just to make place for method calls, if more static nodes needed by a certain DSDT, then stack will be expanded as
necessary. An average DSDT declares 300-400 nodes, hwdet detects this and by default adds space for 128 more should dynamic method
calls create temporary nodes. The number of supported nested nodes (scopes) and method calls can be configured with the
AML_MAXLEVEL
define, being 32 by default.
No library dependency of any kind. You only have to provide two memory related functions from libc, memcmp
and memset
.
Provide some kind of printf
and define AML_DEBUG
before the include to generate debug messages. Define it as 2
to get a full
dump of all parsed opcodes and their positions.
Licensed under the terms of the copyleft GNU General Public License version 3 or any later version.
Cheers, bzt