Init IOAPIC nad LAPICs
This commit is contained in:
@ -374,11 +374,12 @@ If you want to contribute:
|
||||
| [ilobilix](https://github.com/ilobilo/ilobilix) | Yet another monolithic Linux clone wannabe. Currently under a rewrite | 8,703,286 | AMD Ryzen 9 9950X3D |
|
||||
| [Crescent2](https://github.com/Qwinci/crescent2) | An NT driver compatible kernel and userspace | 6,818,418 | Intel Core i5-13600K |
|
||||
| [davix](https://github.com/dbstream/davix) | Yet another unix-like by some bored nerd | 6,364,623 | Intel Core i7-13700K |
|
||||
| [Ironclad](https://ironclad-os.org) | Formally verified, hard real-time capable kernel written in SPARK and Ada | 6,196,937 | Intel Core i9-13900KS |
|
||||
| [Managarm](https://github.com/managarm/managarm) | Pragmatic microkernel-based OS with fully asynchronous I/O | 5,618,646 | Intel Core i7-14700K |
|
||||
| [ChronOS](https://github.com/BUGO07/chronos) | Another basic hobby os held together by duct tape, made in rust | 5,416,703 | Intel Core Ultra 7 265KF |
|
||||
| [pmOS](https://gitlab.com/mishakov/pmos) | Microkernel-based operating system written from scratch with uACPI running in userspace | 5,354,445 | AMD Ryzen 9 5900X |
|
||||
| [menix](https://github.com/menix-os/menix) | A minimal and expandable Unix-like operating system | 5,239,043 | Intel Core Ultra 7 265KF |
|
||||
| [Ironclad](https://ironclad.nongnu.org) | Formally verified, hard real-time capable kernel written in SPARK and Ada | 4,802,816 | Intel Core i9-13900KS |
|
||||
| [Orange](https://github.com/cpplover0/orange) | Unix-like x86_64 OS with some microkernel features | 4,204,053 | AMD Ryzen 5 3600 |
|
||||
| [Astral](https://github.com/mathewnd/astral) | Operating system written in C which aims be POSIX-compliant | 4,189,189 | Intel Core i5-13600K |
|
||||
| [Keyronex](https://github.com/Keyronex/Keyronex) | Layered kernel with fundamentally asynchronous I/O and working set model-based memory management | 4,013,691 | AMD Ryzen 5800X |
|
||||
| [Orange](https://github.com/cppLover0/Orange) | x86_64 Unix-like OS | 2,377,330 | AMD Ryzen 5 3600 |
|
||||
@ -387,6 +388,7 @@ If you want to contribute:
|
||||
| [ElysiumOS](https://github.com/imwux/elysium-os) | Hybrid Unix-like kernel | 1,737,654 | AMD Ryzen 7 5800X3D |
|
||||
| [imaginarium](https://github.com/Khitiara/imaginarium) | Ziggy osdev experiments inspired by the NT kernel (using the zig general purpose allocator) | 1,504,436 | AMD Ryzen 7 3700X |
|
||||
| [BadgerOS](https://github.com/badgeteam/BadgerOS) | A monolithic lightweight UNIX clone | 1,018,518 | AMD Ryzen 5 3600 |
|
||||
| [Retro Rocket](https://github.com/brainboxdotcc/retro-rocket) | A BASIC _powered_ 64-bit SMP multitasking OS | 441,329 | Intel Xeon E5-2680 |
|
||||
| [Hyra](https://github.com/sigsegv7/Hyra) | Monolithic UNIX-like OS by [OSMORA.ORG](https://osmora.org) | 199,873 | Intel Core i3-3220 |
|
||||
|
||||
## License
|
||||
|
@ -9,6 +9,8 @@ extern "C" {
|
||||
|
||||
// Forward-declared to avoid including the entire acpi.h here
|
||||
struct acpi_fadt;
|
||||
struct acpi_entry_hdr;
|
||||
struct acpi_sdt_hdr;
|
||||
|
||||
typedef struct uacpi_table_identifiers {
|
||||
uacpi_object_name signature;
|
||||
@ -136,6 +138,30 @@ uacpi_status uacpi_set_table_installation_handler(
|
||||
uacpi_table_installation_handler handler
|
||||
);
|
||||
|
||||
typedef uacpi_iteration_decision (*uacpi_subtable_iteration_callback)
|
||||
(uacpi_handle, struct acpi_entry_hdr*);
|
||||
|
||||
/*
|
||||
* Iterate every subtable of a table such as MADT or SRAT.
|
||||
*
|
||||
* 'hdr' is the pointer to the main table, 'hdr_size' is the number of bytes in
|
||||
* the table before the beginning of the subtable records. 'cb' is the callback
|
||||
* invoked for each subtable with the 'user' context pointer passed for every
|
||||
* invocation.
|
||||
*
|
||||
* Example usage:
|
||||
* uacpi_table tbl;
|
||||
*
|
||||
* uacpi_table_find_by_signature(ACPI_MADT_SIGNATURE, &tbl);
|
||||
* uacpi_for_each_subtable(
|
||||
* tbl.hdr, sizeof(struct acpi_madt), parse_madt, NULL
|
||||
* );
|
||||
*/
|
||||
uacpi_status uacpi_for_each_subtable(
|
||||
struct acpi_sdt_hdr *hdr, size_t hdr_size,
|
||||
uacpi_subtable_iteration_callback cb, void *user
|
||||
);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -29,7 +29,13 @@ typedef enum uacpi_iteration_decision {
|
||||
UACPI_ITERATION_DECISION_CONTINUE = 0,
|
||||
UACPI_ITERATION_DECISION_BREAK,
|
||||
|
||||
// Only applicable for uacpi_namespace_for_each_child
|
||||
/*
|
||||
* Ignore all of the children of the current node and proceed directly to
|
||||
* its peer nodes.
|
||||
*
|
||||
* Only applicable for API that interacts with the AML namespace such as
|
||||
* uacpi_namespace_for_each_child, uacpi_find_deivces, etc.
|
||||
*/
|
||||
UACPI_ITERATION_DECISION_NEXT_PEER,
|
||||
} uacpi_iteration_decision;
|
||||
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <uacpi/namespace.h>
|
||||
|
||||
#define UACPI_MAJOR 3
|
||||
#define UACPI_MINOR 0
|
||||
#define UACPI_MINOR 1
|
||||
#define UACPI_PATCH 0
|
||||
|
||||
#ifdef UACPI_REDUCED_HARDWARE
|
||||
|
@ -1398,3 +1398,52 @@ uacpi_status uacpi_table_fadt(struct acpi_fadt **out_fadt)
|
||||
*out_fadt = &g_uacpi_rt_ctx.fadt;
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
uacpi_status uacpi_for_each_subtable(
|
||||
struct acpi_sdt_hdr *hdr, size_t hdr_size,
|
||||
uacpi_subtable_iteration_callback cb, void *user
|
||||
)
|
||||
{
|
||||
void *cursor;
|
||||
size_t bytes_left;
|
||||
|
||||
cursor = UACPI_PTR_ADD(hdr, hdr_size);
|
||||
bytes_left = hdr->length - hdr_size;
|
||||
|
||||
if (uacpi_unlikely(bytes_left > hdr->length))
|
||||
return UACPI_STATUS_INVALID_TABLE_LENGTH;
|
||||
|
||||
while (bytes_left > sizeof(struct acpi_entry_hdr)) {
|
||||
struct acpi_entry_hdr *subtable_hdr = cursor;
|
||||
|
||||
if (uacpi_unlikely(subtable_hdr->length > bytes_left ||
|
||||
subtable_hdr->length < sizeof(*subtable_hdr))) {
|
||||
uacpi_error(
|
||||
"corrupted '%.4s' subtable length: %u (%zu bytes left)\n",
|
||||
hdr->signature, subtable_hdr->length, bytes_left
|
||||
);
|
||||
return UACPI_STATUS_INVALID_TABLE_LENGTH;
|
||||
}
|
||||
|
||||
switch (cb(user, subtable_hdr)) {
|
||||
case UACPI_ITERATION_DECISION_CONTINUE:
|
||||
break;
|
||||
case UACPI_ITERATION_DECISION_BREAK:
|
||||
return UACPI_STATUS_OK;
|
||||
default:
|
||||
return UACPI_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
cursor = UACPI_PTR_ADD(cursor, subtable_hdr->length);
|
||||
bytes_left -= subtable_hdr->length;
|
||||
}
|
||||
|
||||
if (uacpi_unlikely(bytes_left != 0)) {
|
||||
uacpi_warn(
|
||||
"found %zu stray bytes in table '%.4s'\n",
|
||||
bytes_left, hdr->signature
|
||||
);
|
||||
}
|
||||
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
@ -464,6 +464,7 @@ def main() -> int:
|
||||
bare_cases: List[TestCase] = [
|
||||
BarebonesTestCase("basic-operation"),
|
||||
BarebonesTestCase("table-installation"),
|
||||
BarebonesTestCase("foreach-subtable"),
|
||||
]
|
||||
|
||||
with TestHeaderFooter("Barebones Mode Tests"):
|
||||
|
@ -54,6 +54,33 @@ static uint8_t test_mcfg[] = {
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
/*
|
||||
* 4 Local APICs [0, 1, 2, 3]
|
||||
* 2 IOAPICs [4, 5]
|
||||
* 2 ISOs [0->2, 9->9]
|
||||
* 4 NMIs [0, 1, 2, 3]
|
||||
*/
|
||||
static uint8_t test_apic[] = {
|
||||
0x41, 0x50, 0x49, 0x43, 0x90, 0x00, 0x00, 0x00,
|
||||
0x03, 0x1a, 0x48, 0x50, 0x51, 0x4f, 0x45, 0x4d,
|
||||
0x53, 0x4c, 0x49, 0x43, 0x2d, 0x4d, 0x50, 0x43,
|
||||
0x01, 0x00, 0x00, 0x00, 0x48, 0x50, 0x20, 0x20,
|
||||
0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0xe0, 0xfe,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x01, 0x01,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x02, 0x02,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x08, 0x03, 0x03,
|
||||
0x01, 0x00, 0x00, 0x00, 0x01, 0x0c, 0x04, 0x00,
|
||||
0x00, 0x00, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x00,
|
||||
0x01, 0x0c, 0x05, 0x00, 0x00, 0x10, 0xc0, 0xfe,
|
||||
0x18, 0x00, 0x00, 0x00, 0x02, 0x0a, 0x00, 0x00,
|
||||
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x0a,
|
||||
0x00, 0x09, 0x09, 0x00, 0x00, 0x00, 0x0f, 0x00,
|
||||
0x04, 0x06, 0x00, 0x05, 0x00, 0x01, 0x04, 0x06,
|
||||
0x01, 0x05, 0x00, 0x01, 0x04, 0x06, 0x02, 0x05,
|
||||
0x00, 0x01, 0x04, 0x06, 0x03, 0x05, 0x00, 0x01
|
||||
};
|
||||
|
||||
static void ensure_signature_is(const char *signature, uacpi_table tbl)
|
||||
{
|
||||
if (strncmp(tbl.hdr->signature, signature, 4) == 0)
|
||||
@ -105,12 +132,123 @@ static void test_table_installation(void)
|
||||
uacpi_table_unref(&tbl);
|
||||
}
|
||||
|
||||
static uacpi_iteration_decision check_madt(
|
||||
uacpi_handle user, struct acpi_entry_hdr *hdr
|
||||
)
|
||||
{
|
||||
size_t *idx = user;
|
||||
struct acpi_madt_lapic *lapic;
|
||||
struct acpi_madt_ioapic *ioapic;
|
||||
struct acpi_madt_interrupt_source_override *iso;
|
||||
struct acpi_madt_lapic_nmi *nmi;
|
||||
|
||||
switch (*idx) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
if (hdr->type != ACPI_MADT_ENTRY_TYPE_LAPIC)
|
||||
goto out_unexpected;
|
||||
lapic = (struct acpi_madt_lapic*)hdr;
|
||||
if (lapic->id != *idx)
|
||||
error("unexpected LAPIC id %d (idx %d)\n", lapic->id, *idx);
|
||||
break;
|
||||
case 4:
|
||||
case 5:
|
||||
if (hdr->type != ACPI_MADT_ENTRY_TYPE_IOAPIC)
|
||||
goto out_unexpected;
|
||||
ioapic = (struct acpi_madt_ioapic*)hdr;
|
||||
if (ioapic->id != *idx)
|
||||
error("unexpected IOAPIC id %d (idx %d)\n", ioapic->id, *idx);
|
||||
break;
|
||||
case 6:
|
||||
case 7:
|
||||
if (hdr->type != ACPI_MADT_ENTRY_TYPE_INTERRUPT_SOURCE_OVERRIDE)
|
||||
goto out_unexpected;
|
||||
iso = (struct acpi_madt_interrupt_source_override*)hdr;
|
||||
if ((*idx == 6 && iso->source != 0) ||
|
||||
(*idx == 7 && iso->source != 9))
|
||||
error("unexpected ISO source %d (idx %d)\n", iso->source, *idx);
|
||||
break;
|
||||
case 8:
|
||||
case 9:
|
||||
case 10:
|
||||
case 11:
|
||||
if (hdr->type != ACPI_MADT_ENTRY_TYPE_LAPIC_NMI)
|
||||
goto out_unexpected;
|
||||
nmi = (struct acpi_madt_lapic_nmi*)hdr;
|
||||
if (nmi->uid != (*idx - 8))
|
||||
error("unexpected LAPIC NMI uid %d (idx %d)\n", nmi->uid, *idx);
|
||||
break;
|
||||
default:
|
||||
goto out_unexpected;
|
||||
}
|
||||
|
||||
(*idx)++;
|
||||
return UACPI_ITERATION_DECISION_CONTINUE;
|
||||
|
||||
out_unexpected:
|
||||
error("unexpected MADT entry type %d (idx = %zu)\n", hdr->type, *idx);
|
||||
return UACPI_ITERATION_DECISION_BREAK;
|
||||
}
|
||||
|
||||
#define CHECK_SUBTEST_FAILED \
|
||||
if (st != UACPI_STATUS_INVALID_TABLE_LENGTH) \
|
||||
error("unexpected status %s\n", uacpi_status_to_string(st));
|
||||
|
||||
#define CHECK_SUBTEST_SUCCEEDED \
|
||||
if (idx != 12) \
|
||||
error("invalid number of iterations: %zu\n", idx);
|
||||
|
||||
#define FOREACH_SUBTEST(check_cond) \
|
||||
idx = 0; \
|
||||
st = uacpi_for_each_subtable( \
|
||||
tbl.hdr, sizeof(struct acpi_madt), check_madt, &idx \
|
||||
); \
|
||||
check_cond; \
|
||||
|
||||
static void test_foreach_subtable(void)
|
||||
{
|
||||
uacpi_status st;
|
||||
uacpi_table tbl;
|
||||
size_t idx = 0;
|
||||
|
||||
st = uacpi_table_install(test_apic, &tbl);
|
||||
ensure_ok_status(st);
|
||||
ensure_signature_is(ACPI_MADT_SIGNATURE, tbl);
|
||||
uacpi_table_unref(&tbl);
|
||||
|
||||
FOREACH_SUBTEST(CHECK_SUBTEST_SUCCEEDED);
|
||||
|
||||
// Make the size slightly larger, make sure we don't crash
|
||||
test_apic[4] += 1;
|
||||
FOREACH_SUBTEST(CHECK_SUBTEST_SUCCEEDED);
|
||||
|
||||
// Change the size to 1 byte and make sure we don't crash
|
||||
test_apic[4] = 1;
|
||||
FOREACH_SUBTEST(CHECK_SUBTEST_FAILED);
|
||||
|
||||
// Cutoff subtable
|
||||
test_apic[4] = sizeof(struct acpi_madt) + sizeof(struct acpi_entry_hdr) + 1;
|
||||
FOREACH_SUBTEST(CHECK_SUBTEST_FAILED);
|
||||
|
||||
test_apic[4] = sizeof(test_apic);
|
||||
// Out-of-bounds subtable
|
||||
test_apic[sizeof(test_apic) - 5]++;
|
||||
FOREACH_SUBTEST(CHECK_SUBTEST_FAILED);
|
||||
|
||||
// all pass
|
||||
test_apic[sizeof(test_apic) - 5]--;
|
||||
uacpi_table_unref(&tbl);
|
||||
}
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
void (*func)(void);
|
||||
} test_cases[] = {
|
||||
{ "basic-operation", test_basic_operation },
|
||||
{ "table-installation", test_table_installation },
|
||||
{ "foreach-subtable", test_foreach_subtable },
|
||||
};
|
||||
|
||||
static arg_spec_t TEST_CASE_ARG = ARG_POS("test-case", "name of the test case");
|
||||
|
@ -20,6 +20,8 @@ NORETURN static inline void error(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
fprintf(stderr, "unexpected error: ");
|
||||
va_start(args, format);
|
||||
vfprintf(stderr, format, args);
|
||||
|
Reference in New Issue
Block a user