From 32ff1b81922209059e474268f2288328f2fac743 Mon Sep 17 00:00:00 2001 From: andromeda Date: Wed, 21 Oct 2026 23:03:26 -0400 Subject: initial acpi support --- lib/acpi.c3l/acpi.c3 | 170 ++++++++++++++++++++++++++++++++++++++++ lib/acpi.c3l/manifest.json | 9 +++ main.c3 | 189 ++++++++++++++++++++++++++++++++++++++++++++- project.json | 4 +- scripts/run.sh | 4 +- 5 files changed, 370 insertions(+), 6 deletions(-) create mode 100644 lib/acpi.c3l/acpi.c3 create mode 100644 lib/acpi.c3l/manifest.json diff --git a/lib/acpi.c3l/acpi.c3 b/lib/acpi.c3l/acpi.c3 new file mode 100644 index 0000000..26021dc --- /dev/null +++ b/lib/acpi.c3l/acpi.c3 @@ -0,0 +1,170 @@ +module acpi; + +import c3os::util; + +extern fn int memcmp(void*, void*, usz); + +alias Oemid = char[6]; + +excuse INVALID_DESCRIPTION_HEADER; + +enum DescriptionHeaderSignature +{ + AEST, + AGDI, + APIC, + APMT, + ASPT, + BDAT, + BERT, + BGRT, + BOOT, + CCEL, + CEDT, + CPEP, + CSRT, + DBGP, + DBG2, + DMAR, + DRTM, + DSDT, + DTPR, + ECDT, + EINJ, + ERST, + ETDT, + FACP, + FACS, + FPDT, + GTDT, + HEST, + HPET, + IBFT, + IERS, + IORT, + IOVT, + IRDT, + IVRS, + KEYP, + LPIT, + MCFG, + MCHI, + MHSP, + MISC, + MPAM, + MPST, + MSCT, + MSDM, + NBFT, + NFIT, + NHLT, + PCCT, + PHAT, + PMTT, + PPTT, + PRMT, + PSDT, + RASF, + RAS2, + RGRT, + RHCT, + RIMT, + RQSC, + RSDT, + SBST, + SDEI, + SDEV, + SLIC, + SLIT, + SPCR, + SPMI, + SRAT, + SSDT, + STAO, + SVKL, + SWFT, + TCPA, + TPM2, + UEFI, + WAET, + WDAT, + WDDT, + WDRT, + WPBT, + WSMT, + XENV, + XSDT, +} + +$assert(DescriptionHeader::size == 36); +$assert(RootSystemDescriptionPointer::size == 35); +struct RootSystemDescriptionPointer @packed +{ + char[8] signature; + char checksum; + Oemid oemid; + char revision; + uint rsdtAddress; + uint length; + ExtendedSystemDescriptionTable* xsdtAddress; + char[3] _res; +} + +fn bool RootSystemDescriptionPointer.is_valid(&self) +{ + if (memcmp(&self.signature, "RSD PTR ", 8) != 0) return false; + if (self.revision != 2) return false; + char sum = 0; + for (int i = 0; i < 20; i++) sum += ((char*)self)[i]; + if (sum != 0) return false; + for (int i = 0; i < RootSystemDescriptionPointer::size; i++) sum += ((char*)self)[i]; + return (sum == 0); +} + +$assert(ExtendedSystemDescriptionTable::size == 36); +struct ExtendedSystemDescriptionTable @packed +{ + inline DescriptionHeader header; + ulong[*] descriptionHeaders; +} + +fn bool ExtendedSystemDescriptionTable.is_valid(&self) +{ + if (memcmp(&self.signature, "XSDT", 4) != 0) return false; + if (self.revision != 1) return false; + char sum = 0; + for (uint i = 0; i < self.length; i++) sum += ((char*)self)[i]; + if (sum != 0) return false; + return true; +} + +struct DescriptionHeader @packed +{ + char[4] signature; + uint length; + char revision; + char checksum; + Oemid oemid; + char[8] oemTableId; + uint oemRevision; + uint creatorId; + uint creatorRevision; +} + +fn bool DescriptionHeader.is_valid(&self) +{ + if (catch excuse = self.sig()) return false; + char sum = 0; + for (uint i = 0; i < self.length; i++) sum += ((char*)self)[i]; + if (sum != 0) return false; + return true; +} + +fn DescriptionHeaderSignature? DescriptionHeader.sig(&self) +{ + foreach (i, name : DescriptionHeaderSignature::names) + { + if (memcmp(name, &self.signature, 4) == 0) return (DescriptionHeaderSignature)i; + } + return INVALID_DESCRIPTION_HEADER~; +} diff --git a/lib/acpi.c3l/manifest.json b/lib/acpi.c3l/manifest.json new file mode 100644 index 0000000..f2a0965 --- /dev/null +++ b/lib/acpi.c3l/manifest.json @@ -0,0 +1,9 @@ +{ + "provides": "acpi", + "sources": [ + "**" + ], + "targets": { + "windows-x64": {} + } +} diff --git a/main.c3 b/main.c3 index 286b4fe..0e0340b 100644 --- a/main.c3 +++ b/main.c3 @@ -16,7 +16,14 @@ module c3os; +import acpi; + import uefi; +import uefi::guid; +import uefi::protocol::mem; + +const MDESCS_LEN = 8192; +macro String version() => "0.1.0"; EfiHandle eh; SystemTable* st; @@ -25,19 +32,195 @@ fn EfiStatus efi_main(EfiHandle image_handle, SystemTable* system_table) @export { eh = image_handle; st = system_table; + BootServices* bs = st.bootServices; + + util::puts("welcome to c3os version "); + util::puts(version()); + util::puts("\r\n"); + util::puts("c3os copyright (c) 2026 andromeda \r\n"); + util::puts("This program comes with ABSOLUTELY NO WARRANTY.\r\n"); + util::puts("This is free software, and you are welcome to redistribute it\r\n"); + util::puts("under certain conditions; see ./LICENSE for details.\r\n"); + + log::info("UEFI vendor: "); + st.conOut._output_string(st.conOut, st.firmwareVendor); + util::puts(" revision "); + util::puti(st.firmwareRevision); + util::puts("\r\n"); + + usz mdescs_len = MDESCS_LEN; + MemoryDescriptor[MDESCS_LEN / MemoryDescriptor::size] mdescs = { }; + usz mdescs_map_key = 0; + usz mdescs_descriptor_size = 0; + uint mdescs_descriptor_version = 0; + bs.get_memory_map(&mdescs_len, &mdescs, &mdescs_map_key, &mdescs_descriptor_size, &mdescs_descriptor_version); + + usz acpi_index; + for (usz i = 0; i < st.numberOfTableEntries; i++) + { + if (guid::@compare(st.configurationTable[i].vendorGuid, guid::ACPI_20_TABLE)) + { + acpi_index = i; + } + } + + if (acpi_index == 0 || !guid::@compare(st.configurationTable[acpi_index].vendorGuid, guid::ACPI_20_TABLE)) + { + log::fatal("acpi table not found"); + spin(); + } + + RootSystemDescriptionPointer* rsdp = st.configurationTable[acpi_index].vendorTable; + + if (!rsdp.is_valid()) + { + log::fatal("checksum verification for root system description pointer failed\r\n"); + spin(); + } + + ExtendedSystemDescriptionTable* xsdt = rsdp.xsdtAddress; + + if (!xsdt.is_valid()) + { + log::fatal("checksum verification for extended system description table failed\r\n"); + spin(); + } + + uint num_entries = (xsdt.length - ExtendedSystemDescriptionTable::size) / ulong::size; + + for (usz i = 0; i < num_entries; i++) + { + DescriptionHeader* dh = (DescriptionHeader*)(uptr)xsdt.descriptionHeaders[i]; - st.conOut.@output_string("Hello World!\n"); + if (dh.is_valid()) + { + log::info("valid signature: "); + util::putbs(&dh.signature, 4); + util::puts("\r\n"); + } + else + { + log::info("invalid signature: "); + util::putbs(&dh.signature, 4); + util::puts("\r\n"); + } + } + + util::puts("done\r\n"); spin(); return SUCCESS; } alias PanicFn = fn void(String message, String file, String function, int line); -PanicFn panicfn = &_panicfn; -fn void _panicfn(String reason, String file = "", String func = "", int line = 0) => spin(); +PanicFn panicfn = &panic; + +fn void panic(String message = "test", String file = "", String function = "", int line = 0) +{ + util::puts("PANIC: "); + util::puts(message); + util::puts("\r\nfunc "); + util::puts(function); + util::puts(" in file "); + util::puts(file); + util::puts(" at line "); + util::puti((usz)line); + util::puts("\r\n"); + spin(); +} fn void spin() { asm("cli"); asm("hlt"); } + +module c3os::log; + +import c3os::util; + +fn void fatal(String s) +{ + util::puts("[fatal]: "); + util::puts(s); +} + +fn void info(String s) +{ + util::puts("[info]: "); + util::puts(s); +} + +fn void warn(String s) +{ + util::puts("[warn]: "); + util::puts(s); +} + +module c3os::util; + +import uefi; + +fn int memcmp(void* b1, void* b2, usz len) @export("memcmp") @nostrip +{ + for (usz i = 0; i < len; i++) + { + if (((char*)b1)[i] < ((char*)b2)[i]) return -1; + if (((char*)b1)[i] > ((char*)b2)[i]) return 1; + } + return 0; +} + +fn void* memcpy(void* dst, void* src, usz len) @export("memcpy") @nostrip +{ + for (usz i = 0; i < len; i++) ((char*)dst)[i] = ((char*)src)[i]; + return dst; +} + +fn void* memset(void* b, int c, usz len) @export("memset") @nostrip +{ + for (usz i = 0; i < len; i++) + { + ((char*)b)[i] = (char)c; + } + return b; +} + +fn void puts(String s) => putbs(s, s.len); + +fn void putbs(char[] s, int n) +{ + ushort[1024] buf = { }; + for (int i = 0;; i++) + { + if (i == n || i == buf.len - 1) + { + buf[i] = '\0'; + break; + } + buf[i] = s[i]; + } + putw((EfiString)&buf); +} + +fn void putw(EfiString w) => c3os::st.conOut._output_string(c3os::st.conOut, w); + +fn void puti(usz i) +{ + usz place = 1; + usz index = 0; + ushort[48] buf = { }; + while (i / place > 0) + { + buf[buf.len - 2 - index] = '0' + (char)((i / place) % 10); + place *= 10; + index += 1; + } + if (i == 0) + { + buf[buf.len - 2] = '0'; + index += 1; + } + buf[buf.len - 1] = '\0'; + putw((EfiString)&buf[buf.len - 1 - index]); +} diff --git a/project.json b/project.json index fb9305c..ab92cd3 100644 --- a/project.json +++ b/project.json @@ -1,7 +1,7 @@ { "warnings": [ "no-unused" ], "dependency-search-paths": [ "lib" ], - "dependencies": [ "uefi" ], + "dependencies": [ "acpi", "uefi" ], "authors": [ "Andromeda " ], "version": "0.1.0", "sources": [ "main.c3" ], @@ -14,6 +14,8 @@ "extension": ".efi", "target": "windows-x64", "no-entry": true, + "stack-protector": "none", + "stack-probe": "none", "use-stdlib": false, "link-libc": false, "win-subsystem": "efi-app", diff --git a/scripts/run.sh b/scripts/run.sh index f2d359c..c09104b 100755 --- a/scripts/run.sh +++ b/scripts/run.sh @@ -2,6 +2,7 @@ set -x +rm -r build c3c build mkdir -p ./build/root/EFI/BOOT/ @@ -19,7 +20,6 @@ rm disk.qcow2 vmctl create -s 10G disk.qcow2 qemu-system-x86_64 \ -drive if=pflash,readonly=yes,file=/usr/local/share/qemu/edk2-x86_64-code.fd \ - -cdrom ./build/c3os.iso - + -cdrom ./build/c3os.iso $* set +x -- cgit v1.3.1