Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions AML/uACPI
Submodule uACPI added at f5f6cc
10 changes: 6 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@ KERNEL_SRC ?= $(abspath $(ACPI_DIR)/../src)

CFLAGS := -std=c11 -Wall -Wextra -O2 -ffreestanding -fno-stack-protector \
-fno-pic -m64 -mno-red-zone -mcmodel=kernel -mgeneral-regs-only \
-I$(ACPI_DIR)/include -I$(KERNEL_SRC)
-I$(ACPI_DIR)/include -I$(KERNEL_SRC) -I$(ACPI_DIR)/AML/uACPI/include

BIN_DIR ?= $(ACPI_DIR)/build
MODULE_DIR := $(BIN_DIR)/modules
BUILD := $(ACPI_DIR)/build/obj

SOURCES := src/acpi.c src/acpi_s5.c src/acpi_power.c
MOD_OBJS := $(SOURCES:src/%.c=$(BUILD)/%.k.o)
UACPI_SOURCES := $(wildcard $(ACPI_DIR)/AML/uACPI/source/*.c)
UACPI_SOURCES := $(UACPI_SOURCES:$(ACPI_DIR)/%=%)
SOURCES := src/acpi.c src/acpi_s5.c src/acpi_power.c src/uacpi_glue.c src/uacpi_heap.c src/acpi_ec.c src/acpi_battery.c $(UACPI_SOURCES)
MOD_OBJS := $(SOURCES:%.c=$(BUILD)/%.k.o)
MOD_ELF := $(MODULE_DIR)/acpi.elf
MOD_KO := $(MODULE_DIR)/acpi.ko

Expand All @@ -30,7 +32,7 @@ check:

module: $(MOD_ELF) $(MOD_KO)

$(BUILD)/%.k.o: $(ACPI_DIR)/src/%.c
$(BUILD)/%.k.o: $(ACPI_DIR)/%.c
@mkdir -p $(@D)
$(CC) $(CFLAGS) -MMD -MP -c $< -o $@

Expand Down
43 changes: 43 additions & 0 deletions include/acpi/acpi.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,49 @@ int acpi_init(void *rsdp_address, uint64_t hhdm_offset);
bool acpi_is_ready(void);
void acpi_dump_tables(void);
void *acpi_find_table(const char *signature);
typedef void (*acpi_table_visitor)(const char *sig, void *table, uint32_t len, void *ctx);
void acpi_for_each_table(const char *signature, acpi_table_visitor visitor, void *ctx);
#define ACPI_MADT_MAX_CPUS 16
struct acpi_madt_info {
bool present;
uint32_t lapic_base;
uint32_t enabled_cpus;
uint32_t total_cpus;
uint32_t ioapic_count;
uint32_t iso_count;
uint32_t nmi_count;
uint32_t lapic_nmi_count;
uint32_t override_count;
uint32_t ioapic_first_addr;
uint8_t lapic_ids[ACPI_MADT_MAX_CPUS];
};
bool acpi_get_madt(struct acpi_madt_info *out);
bool acpi_get_sci_irq(uint16_t *out);
void uacpi_glue_set_rsdp(void *rsdp_virt, uint64_t hhdm);
int acpi_uacpi_early_init(void);
int acpi_uacpi_full_init(void);
bool acpi_uacpi_tables_ready(void);
bool acpi_uacpi_full_ready(void);
bool acpi_uacpi_find_table(const char *sig, void **out_ptr, uint32_t *out_len);
void acpi_uacpi_dump(void);
void acpi_uacpi_rescan_tables(void);
void acpi_scan_blob(const uint8_t *data, uint32_t len, const char *tname);
void acpi_ec_init(void);
bool acpi_ec_ready(void);
bool acpi_ec_read(uint8_t offset, uint8_t *out);
bool acpi_ec_write(uint8_t offset, uint8_t value);
struct acpi_battery_live {
bool valid;
bool present;
uint32_t percent;
uint32_t charging;
uint32_t voltage_mv;
uint32_t current_ma;
uint32_t remaining_min;
char model[16];
};
bool acpi_battery_refresh(struct acpi_battery_live *out);
bool acpi_battery_present_in_namespace(void);
bool acpi_get_slp_typ(uint16_t *slp_typa, uint16_t *slp_typb);
bool acpi_has_battery(void);
int acpi_battery_count(void);
Expand Down
2 changes: 2 additions & 0 deletions include/acpi/acpi_priv.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ struct acpi_fadt_cache {
uint8_t reset_value;
bool has_reset_reg;
int reset_reg_off;
uint16_t sci_int;
bool has_sci_int;
};

extern struct acpi_fadt_cache g_acpi_fadt;
Expand Down
178 changes: 154 additions & 24 deletions src/acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct sdt_header {

#define FADT_DSDT 40u
#define FADT_X_DSDT 140u
#define FADT_SCI_INT 46u
#define FADT_SMI_CMD 48u
#define FADT_ACPI_ENABLE 52u
#define FADT_ACPI_DISABLE 53u
Expand Down Expand Up @@ -251,6 +252,115 @@ void *acpi_get_dsdt(void) {
return acpi_find_table("DSDT");
}

void acpi_for_each_table(const char *signature, acpi_table_visitor visitor, void *ctx) {
if (!visitor)
return;
struct sdt_header *xsdt = NULL, *rsdt = NULL;
acpi_root_tables(&xsdt, &rsdt);
struct sdt_header *roots[2] = {xsdt, rsdt};
for (int t = 0; t < 2; t++) {
struct sdt_header *root = roots[t];
if (!root || root->length < sizeof(struct sdt_header))
continue;
bool wide = (root == xsdt);
uint32_t stride = wide ? 8u : 4u;
uint32_t entries = (root->length - sizeof(struct sdt_header)) / stride;
const uint8_t *base = (const uint8_t *)root + sizeof(struct sdt_header);
for (uint32_t i = 0; i < entries; i++) {
uint64_t addr = 0;
if (wide) {
for (int b = 7; b >= 0; b--)
addr = (addr << 8) | base[i * 8 + (uint32_t)b];
} else {
for (int b = 3; b >= 0; b--)
addr = (addr << 8) | base[i * 4 + (uint32_t)b];
}
if (!addr)
continue;
struct sdt_header *tbl = (struct sdt_header *)acpi_map_phys(addr);
if (!tbl || tbl->length < sizeof(struct sdt_header))
continue;
if (!acpi_table_valid(tbl, tbl->length))
continue;
if (signature && memcmp(tbl->signature, signature, 4) != 0)
continue;
visitor(tbl->signature, tbl, tbl->length, ctx);
}
}
}

static struct acpi_madt_info g_madt_cache;
static bool g_madt_parsed = false;

static void madt_parse_into(struct acpi_madt_info *out) {
memset(out, 0, sizeof(*out));
struct sdt_header *madt = (struct sdt_header *)acpi_find_table("APIC");
if (!madt || madt->length < 44)
return;
const uint8_t *m = (const uint8_t *)madt;
out->lapic_base = (uint32_t)m[36] | ((uint32_t)m[37] << 8) |
((uint32_t)m[38] << 16) | ((uint32_t)m[39] << 24);
out->present = true;
uint32_t off = 44;
while (off + 2 <= madt->length) {
uint8_t type = m[off], len = m[off + 1];
if (len < 2 || off + len > madt->length)
break;
switch (type) {
case 0:
out->total_cpus++;
if (len >= 8 && (m[off + 4] & 0x01)) {
if (out->enabled_cpus < ACPI_MADT_MAX_CPUS)
out->lapic_ids[out->enabled_cpus] = m[off + 3];
out->enabled_cpus++;
}
break;
case 1:
if (len >= 12) {
uint32_t addr = (uint32_t)m[off + 4] | ((uint32_t)m[off + 5] << 8) |
((uint32_t)m[off + 6] << 16) | ((uint32_t)m[off + 7] << 24);
if (out->ioapic_count == 0)
out->ioapic_first_addr = addr;
out->ioapic_count++;
}
break;
case 2:
out->iso_count++;
break;
case 3:
out->nmi_count++;
break;
case 4:
out->lapic_nmi_count++;
break;
case 5:
out->override_count++;
break;
default:
break;
}
off += len;
}
}

bool acpi_get_sci_irq(uint16_t *out) {
if (!out || !g_acpi_fadt.has_sci_int)
return false;
*out = g_acpi_fadt.sci_int;
return true;
}

bool acpi_get_madt(struct acpi_madt_info *out) {
if (!out)
return false;
if (!g_madt_parsed) {
madt_parse_into(&g_madt_cache);
g_madt_parsed = true;
}
*out = g_madt_cache;
return g_madt_cache.present;
}

static void fadt_parse(struct sdt_header *fadt) {
memset(&g_acpi_fadt, 0, sizeof(g_acpi_fadt));
g_acpi_fadt.reset_reg_off = -1;
Expand All @@ -264,6 +374,12 @@ static void fadt_parse(struct sdt_header *fadt) {
g_acpi_fadt.dsdt = fadt_u32(f, FADT_DSDT);
if (len >= FADT_X_DSDT + 8)
g_acpi_fadt.x_dsdt = fadt_u64(f, FADT_X_DSDT);
if (len > FADT_SCI_INT + 1) {
g_acpi_fadt.sci_int =
(uint16_t)((uint16_t)f[FADT_SCI_INT] |
((uint16_t)f[FADT_SCI_INT + 1] << 8));
g_acpi_fadt.has_sci_int = true;
}
if (len > FADT_SMI_CMD)
g_acpi_fadt.smi_cmd = fadt_u32(f, FADT_SMI_CMD);
if (len > FADT_ACPI_ENABLE)
Expand Down Expand Up @@ -341,11 +457,19 @@ static bool mem_has_str(const uint8_t *data, uint32_t len, const char *s) {
return false;
}

static void scan_aml_blob(const uint8_t *data, uint32_t len,
const char *tname);

void acpi_scan_blob(const uint8_t *data, uint32_t len, const char *tname) {
scan_aml_blob(data, len, tname);
}

static void scan_aml_blob(const uint8_t *data, uint32_t len, const char *tname) {
if (!data || len < 36)
return;
static const char *bat_names[] = {"BAT0", "BAT1", "BAT2", "BAT3"};
for (unsigned b = 0; b < 4; b++) {
static const char *bat_names[] = {"BAT0", "BAT1", "BAT2", "BAT3",
"BATT", "BATC"};
for (unsigned b = 0; b < 6; b++) {
if (mem_has_str(data, len, bat_names[b])) {
if (!(g_battery_seen & (uint8_t)(1u << b))) {
g_battery_seen |= (uint8_t)(1u << b);
Expand Down Expand Up @@ -484,6 +608,8 @@ int acpi_init(void *rsdp_address, uint64_t hhdm_offset) {
g_acpi_rsdp = rsdp_address;
g_acpi_hhdm = hhdm_offset;
g_ready = false;
g_madt_parsed = false;
memset(&g_madt_cache, 0, sizeof(g_madt_cache));
memset(&g_acpi_fadt, 0, sizeof(g_acpi_fadt));
g_acpi_fadt.reset_reg_off = -1;

Expand Down Expand Up @@ -520,9 +646,10 @@ int acpi_init(void *rsdp_address, uint64_t hhdm_offset) {
return -3;
}
fadt_parse(fadt);
klogf(KLOG_INFO, "acpi: FADT rev=%u len=%u dsdt=0x%x pm1a_cnt=0x%x pm1b_cnt=0x%x",
klogf(KLOG_INFO, "acpi: FADT rev=%u len=%u dsdt=0x%x pm1a_cnt=0x%x pm1b_cnt=0x%x sci=%u",
g_acpi_fadt.rev, fadt->length, g_acpi_fadt.dsdt,
g_acpi_fadt.pm1a_cnt, g_acpi_fadt.pm1b_cnt);
g_acpi_fadt.pm1a_cnt, g_acpi_fadt.pm1b_cnt,
g_acpi_fadt.has_sci_int ? g_acpi_fadt.sci_int : 0xFFFF);
if (g_acpi_fadt.has_reset_reg)
klogf(KLOG_INFO, "acpi: ResetReg validated at FADT+%d space=%u width=%u addr=0x%llx val=0x%x",
g_acpi_fadt.reset_reg_off, g_acpi_fadt.reset_reg.space,
Expand All @@ -535,6 +662,25 @@ int acpi_init(void *rsdp_address, uint64_t hhdm_offset) {
acpi_s5_parse();
battery_probe();

uacpi_glue_set_rsdp(g_acpi_rsdp, g_acpi_hhdm);
if (acpi_uacpi_early_init() == 0) {
if (acpi_uacpi_full_init() == 0) {
klog(KLOG_OK, "acpi: uACPI full mode active");
acpi_ec_init();
acpi_uacpi_rescan_tables();
if (!g_battery_present &&
acpi_battery_present_in_namespace()) {
g_battery_present = true;
if (!g_battery_name[0] || g_battery_name[0] == '-')
memcpy(g_battery_name, "BAT", 3);
klog(KLOG_INFO, "acpi: battery found via namespace walk");
}
} else
klog(KLOG_WARN, "acpi: uACPI full init failed, tables only");
acpi_uacpi_dump();
} else
klog(KLOG_WARN, "acpi: uACPI early table access failed, using manual parser");

g_ready = true;
klog(KLOG_OK, "acpi: subsystem ready");
return 0;
Expand Down Expand Up @@ -616,26 +762,10 @@ void acpi_dump_tables(void) {
}
}
}
struct sdt_header *madt = (struct sdt_header *)acpi_find_table("APIC");
if (madt && madt->length >= 44) {
const uint8_t *m = (const uint8_t *)madt;
uint32_t lapic = (uint32_t)m[36] | ((uint32_t)m[37] << 8) |
((uint32_t)m[38] << 16) | ((uint32_t)m[39] << 24);
uint32_t counts[6] = {0, 0, 0, 0, 0, 0};
uint32_t off = 44;
uint32_t cpus = 0;
while (off + 2 <= madt->length) {
uint8_t type = m[off], len = m[off + 1];
if (len < 2 || off + len > madt->length)
break;
if (type < 6)
counts[type]++;
if (type == 0 && len >= 8 && (m[off + 4] & 0x01))
cpus++;
off += len;
}
klogf(KLOG_INFO, "acpi: MADT lapic_base=0x%x enabled_cpus=%u ioapic=%u iso=%u nmi=%u lapic_nmi=%u lapic_override=%u",
lapic, cpus, counts[1], counts[2], counts[3], counts[4], counts[5]);
struct acpi_madt_info mi;
if (acpi_get_madt(&mi)) {
klogf(KLOG_INFO, "acpi: MADT lapic_base=0x%x enabled_cpus=%u total_cpus=%u ioapic=%u iso=%u nmi=%u lapic_nmi=%u lapic_override=%u ioapic_addr=0x%x",
mi.lapic_base, mi.enabled_cpus, mi.total_cpus, mi.ioapic_count, mi.iso_count, mi.nmi_count, mi.lapic_nmi_count, mi.override_count, mi.ioapic_first_addr);
} else {
klog(KLOG_WARN, "acpi: MADT (APIC) not found");
}
Expand Down
Loading
Loading