#uACPI - a portable and easy-to-integrate ACPI implementation
1 messages ยท Page 7 of 1
nothing really supports ia64 emulation
there's ski, but it's kinda iffy
simics used to support it partially, but was missing key parts
qemu-ia64 was part of a summer of code thingy
and then chickenes made a fork semi-recently to work on it more
people think it's impossible to properly emulate ia64 (they're stupid imo)
How come do they think that? (Im clueless about ia64)
not really sure, I think it's because it's VLIW
Ah
the main issue is no one has really been motivated enough to implement one that's fully functional
Interesting how its less supported than Amiga lol
I guess its way more complex
And its only for server hardware thats hard to come across
not quite, it was intended to support consumer use, it just wasn't popular enough
there are systems like the Zx2000 or Zx6000 which could've made great consumer systems, but due to how unpopular and expensive Itanium was they were only really used as workstations
there were also attempts at mobile Itanium chips which could've been great for things like laptops, or low-power systems but those didn't get super far
I believe @heady pewter mentioned that there was a cancelled project for a mobile Itanium implementation
I'm not super sure that early Itanium chips were massively expensive, I would like to note that
the reason I assume they were is how expensive recent chips were, often being thousands at retail price iirc
yes, there doesn't seem to be anything about it on the Internet
I'll have to see if I can track down the original architect and see if he is willing to comment
I think Zx6000s are still sometimes sold on Ebay, and recently I saw a lovely Zx2000, sadly couldn't afford it
If you can I'd love to see what he has to say
Itaniums were cheap from HP, because Intel had to supply them at cost ๐
Yeah same
wdym? like the Hondo implementation?
oh that, did it reduce the cost of Itanium chips?
for HP ๐
Ok that makes sense
There was a Google Summer of Code project years ago to add IA64 support to qemu, but the person really didn't get all that far. I actually didn't realize how primitive it was until AFTER I managed to apply 13 years of QEMU changes
I ended up ignoring everything and building a new skeleton, dumping every bit of GSoC code...but that was on top of the original git repo, not qemu's, so I need to apply the changes/additions to qemu master...and I got distracted by other things before I did the latter 
The GSoC thing had like a handful of instructions and the instruction decoder was hacked in from a BSD licensed debugger that I believe was already a dead project in 2011 lmao
ski is a good reference, but it's missing a fair bit.
@fiery turtle I got ownership of the uacpi-rs repository
Lmao
Daamn
Thats big
uacpi_state_reset vs uacpi_tear_down?
acpica does acpi_terminate which is horrible imo, its ambiguous whether it's related to power states
for reference, this is what it does:
also can't believe i didnt have this check before
uacpi_state_reset
uacpi_implode_all
you forgot the second argument
adding __attribute__((format(printf, 1, 2))) to uacpi_warn would've issued a warning in this case :^)
yes yes i noticed right after i sent it 
been a thing for a while
found a new collection of AML dumps
This feels like pokemon
Gotta catch them all
All the broken blobs
because it is
I think this should work for non-recursive wipe of the entire namespace
void uacpi_namespace_deinitialize(void)
{
uacpi_namespace_node *current, *next = UACPI_NULL;
uacpi_u32 depth = 1;
current = uacpi_namespace_root();
while (depth) {
next = next == UACPI_NULL ? current->child : next->next;
/*
* The previous value of 'next' was the last child of this subtree,
* we can now remove the entire scope of 'current->child'
*/
if (next == UACPI_NULL) {
depth--;
// Wipe the subtree
while (current->child != UACPI_NULL)
uacpi_node_uninstall(current->child);
// Reset the pointers back as if this iteration never happened
next = current;
current = current->parent;
continue;
}
/*
* We have more nodes to process, proceed to the next one, either the
* child of the 'next' node, if one exists, or its peer
*/
if (next->child) {
depth++;
current = next;
next = UACPI_NULL;
}
// This node has no children, move on to its peer
}
}
okay im back from my minecraft hiatus
first off now the initialization is atomic, meaning you can't end up with partially initialized uACPI due to some error
as a bonus i also added public api to reset api back to initial state
this much is still to do in terms of locks
only OSI and tables are threads safe right now
okay uhh some large tests are now failing due to memory leaks
this happens because i now reset uACPI after every run
this probably uncovered a preexisting bug where i would leak a reference or something
but never encountered it because nodes would always still be alive on program exit
okay so as far as i can see its related to how deep object copy is handled, which is only used by NameOp...
but i cant come up with a repro atm, will have to dig deeper and actually look at the dsdts
only 700 cases of Name to look through in the reporducer blob...
okay uhh this fixes all leaks and all tests pass...
has the oberrow curse gotten to the reaches of the original thing that cursed obos (uacpi)
nah its a bug thats always been there, just never showed itself because the global namespace was never freed before
basically a reference leak somewhere
anyway i need to figure out wtf is going on and for that i need a way to reproduce the leak
also i lied the bug didnt go anywhere, only the symptoms changed
aka the source of the leak changed
so it wasnt the deep copy thats at fault here
could it be the alias i wonder
Nope, the reporducer blob only has aliases to processors and the leaked object is a buffer
โฏ runner/build-linux-64bits/test-runner bin/large-tests/tablet_microsoft_surface_surface_laptop_3_4e426ab8062d/dsdt.dat --log-level warning
[uACPI][ERROR] unable to lookup named object 'EPCS' within (or above) scope '\_SB_.EPC_._STA': not found
[uACPI][ERROR] aborting method invocation due to previous error: AML referenced an undefined object
[uACPI][ERROR] #0 in \_SB_.EPC_._STA()
[uACPI][ERROR] failed to disable fixed event 0
=================================================================
==11399==ERROR: LeakSanitizer: detected memory leaks
Direct leak of 32 byte(s) in 1 object(s) allocated from:
okay found a blob with exactly one leak
this will hopefully help track it down
i have invented an absolutely genius object leak track down
technique
now i know exactly which node is responsible for the leak
because of the leak size
...aaand its a field connection
actual genius debug strat
and sure enough that was missing there
the only reason why i never saw this leak before was because no blob ever creates a temporary field unit with a connection
@north holly curse solved (also do u like my debug strat?)
yes
thanks
also i kinda hate that this is unrefed recursively
but the connection must be a buffer object so
it cant recurse further
oh yeah its typechecked
so its not going to recurse
thats two more things off the checklist
whats the next todo you plan to do?
the thing we talked about, aka the last box in the checklist
Now that i can cleanly reset global state i can literally run the same test twice and they all pass!
not a single leak or variable i forgot to reinitialize
Nice work
Thanks!
wake up babe new uACPI kernel api just dropped
this time its optional and just convenience stuff
i dont like the name of this define
because its only part of what it does
but idk of a better idea
what does it?
e.g. in managarm https://github.com/managarm/managarm/blob/67656190ccb7846f3e04be2f550126ad0bbdb520/kernel/thor/system/acpi/madt.cpp#L336 this wouldnt have to be done manually anymore
and wouldnt have to be exported anywhere
as uACPI would call it on its own
basically if your glue needs any initialization or state, this will allow for automatic initialization of that
aka just init hook
added some description on top
or maybe i should reword that to "glue code that needs global constructable state in order to work"
weak symbols
@fiery turtle is it possible for uacpi to use after free while being accessed in a multithreaded context?
I'm asking because I get a use after free in uACPI in types.c:1065 (uacpi_unwrap_internal_reference)
and the call stack goes down to uacpi_find_devices
while another CPU was running uacpi_get_pci_routing_table
yeah it's something to do with thread safety
Day one of waiting for uACPI thread safety
(I plan on saying that every day in this thread until uACPI is thread safe)
It is possible yes
Thats my number one priority
Aka just wrapping uacpi up for a 1.0 release
Rn you can just wrap any uacpi invocation that might race under one mutex
ok
I can't immediately think how that would race with anything, but possible probably
Day two of waiting for uacpi thread safety
Lmao
he REALLY REALLY wants it
.
(when it finally is, I will start saying "Day n of uACPI thread safety) /j
day three of waiting for uACPI thread safety
Rookie numbers, I've been waiting for a few months
Add a global lock
And later you add an optimization release that magically improves the multi-threaf performance
i think we should have UNfine locking everywhere
the OS should completely lock whenever a core enters supervisor mode
!!!!!!!!!!!!!!!!!!!!!!!!!!!
a global kernel lock is relatively common for older kernels espeically when a lot of cores werent common
ya, but it's a bad idea on SMP systems, which tend to be the most common in modern desktop/server systems
yeah
maybe
all the BSDs (and Linux too) had one within recent memory
that's how they started to smp'ify
freebsd's one has had limited use for long time though
I think the Linux one was removed in like Linux 2.6.30 or something
I remember freebsd still has their gil but not for everything
https://github.com/search?q=repo%3Afreebsd%2Ffreebsd-src+path%3Asys+"mtx_lock(%26Giant)%3B"&type=code these appear to be the remaining uses of the giant lock in freebsd
kernel module loading/unloading, some keyboard drivers, a few random drivers, smb (the network fs?), some terminal stuff
Yeah
god forbid my keyboard LED event races with module loading
this is known to kill people
Exactly
mach had one called the unix funnel
later the bsd funnel
like the cake
openbsd still does it, mostly
iirc they got rid of Giant entirely a while back
now they just have like 3 massive locks
openbsd is moving very slowly to wreck their giant locking (which they call the kernel lock or mp lock)
a lot of the netbsd inheritance was already equipped with fairly fine-grained locking (like UVM) but they've trashed it and are reconstructing it gradually, e.g. in https://github.com/openbsd/src/commit/19dcab733a71ecac0688127acdc039e90a471eba
day four of waiting for uACPI thread safety
Same
Be the change you want to see 
Lmao
maybe I shoudl take a shit ton of weed and submit a PR with my own thread safety
Day 5 of waiting for uacpi thread safety
that last patch there is a fix for a bug i found in lai lol
Oops
it wasn't really being maintained before that either :^)
Thanks, will fix
day 6 of waiting for uacpi thread safety
i should take a look at my storport shim again some day
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/storport/nf-storport-storportinvokeacpimethod this would be fun to implement
yeah sounds interesting
hey does uacpi have rust bindings?
yea fair point
yes, see this repo
although last commit there is may
developement is planned but currently halted
understandable
i will start once i need it for my kernel, which can be anywhere between next week and next year ๐
lol
๐ญ ๐ญ
maybe nyaux gets there before u
will do
would you be open to PRs?
in the future yes, but atm its likely that i will restructure the code from the ground up which will break pr code
its in a state in which i wouldnt recommend creating prs
but ideas are always welcome
Noticed that ACPICA has an oversight where the kernel api initialization hook is only called once during early init, which is not enough because different stages of init need different APIs, e.g. work queues don't become available until later
so linux had to invent their own acpi_os_initialize1 to combat this oversight and then call into it manually
Thats why i decided to make the notion of uacpi_init_level public, as well as call the kernel init hook for each level when appropriate
basically this
and this is now public
nice, sounds handy
Thanks, I know im definitely going to use it in Astral
thanks, fixed and gave u credit in the commit description
ah not necessary, but thank you anyway ๐
where is that repo
i dont care if its not mantained i need to use it like right now
thank you
and ig all of those sysdep functions might not be needed anymore, didn't you add a lot of default impls to uacpi?
@rustic compass is there documentation
for the crate
nvm i know how to set it up
fn install_interrupt_handler(&self, irq: u32, handler: Box<dyn Fn()>)
-> Result<uacpi::Handle, uacpi::Status> {
unimplemented!()
}
box is not defined???
???
what is this trait
box isnt defined
Resources:
- Documentation on the wiki: https://osdev.wiki/wiki/UACPI
- Read the headers!
- Rust bindings (incomplete): https://github.com/Shinribo/uacpi-rs
uACPI is a portable and easy-to-integrate implementation of the Advanced Configuration and Power Interface (ACPI).
Its main focuses are full NT compatibility, safety, and minimization of stack usage by avoiding recursion entirely.
Extra documentation can be found in the project's GitHub repo.
what issue are you having with it
Box is in alloc
i cannot use Box
box is not defined
i defined a global allocator
but i still cannot use box
what error does it give? I assume you have use alloc::boxed::Box;
yep
that gives me a error
no such thing as boxed
in core::alloc
Yea it works now
there ya go
okay soo.. back to work
im looking at how ACPICA implements early table access again
and as always its very awkward api
if u want early tables u have to do mental gymnastics that could've been done for you implicitly
oops I page faulted because uACPI wasn't thread safe and it took a long time to reboot
day n of waiting for uacpi thread safety
what's it you've got to do?
Anyway here's my plan:
- make table mappings have refcount again, so introduce
uacpi_table_{ref,unref} - introduce
uacpi_kernel_get_rsdpas it may now be requested from multiple places - introduce
uacpi_setup_early_table_access(initial_buffer, buffer_capacity, may_reallocate)whereinitial_bufferwill be used by uacpi to store initial table descriptors - make
uacpi_initializereallocate the descriptors frominitial_bufferinto a normal resizable heap array if early table access was requested, otherwise work as it did before
uacpi_initialize will also error out if any early tables are still mapped at this point
basically it forces you to call AcpiReallocateRootTable to tell it that your heap is available otherwise the tables are stuck in the fixed buffer
which it already assumes heap availability in AcpiInitializeSubsystem anyway
one thing i would find a bit dirty on the part of acpica
real chads just find the tables themself
mapping tables being done with the same callback as mapping stuff that ought to be mapped differently
thats an interesting thought, can u elaborate on that a bit?
in my case a) i anticipate using the SLIT, SLAT, SLOT, whatever it's called that has NUMA locality information in it ahead of being able to map pages other than those found in the direct map b) if mmio is mapped i want to be able to map it with appropriate cache/shareability attributes, because aarch64 won't forgive me getting that wrong, and i don't want to map tables as if they're MMIO
i don't know if uacpi actually does need to map anything MMIO at any time
lemme give u some context for these
i'm just thinking of the delayed bootup i had when uacpi_kernel_map mapped cacheable
wait it's supposed to map uncached?
a) Yes, this is the problem i want to solve iwth uacpi_setup_early_table_access
b) That's the thing, even uACPI doesnt know which cacheability attribute should be used for a mapping, as AML is allowed to map absolutely any physical address. What Linux does is scan the memory map and the decide the attributes based on that. On x86 it just does high half mapping for everything i think
So basically if u want b u have to solve it yourself
by finding the range AML wants to map in the memory map
e.g. if its normal ram u just map cached, if its reserved u map uncached, etc
b is not unreasonable
i can do that, will need to keep the memory map in persisted form but that's sensible anyway
yeah i guess
For a) i need some elaboration from you as to what specific problem you want solved
will uacpi call uacpi_kernel_map() when dealing in early table access?
i can always set a flag to decide between "return hhdm offset" and "map it properly" if need be
and set that flag after i'm done with early tables and have set up the memory manager
will this work for you @jaunty fox
// ------------ acpi.c
// acpi_early_init
static uint8_t buffer[4096];
// automatically calls uacpi_kernel_get_rsdp() and maps it
uacpi_setup_early_table_access(buffer, sizeof(buffer), false);
// ------------ pmm.c
// pmm_init
uacpi_table_find("SLIT", ...);
// do init
uacpi_table_unref(table);
// ------------ uacpi_glue.c
void *uacpi_kernel_map(addr, ...) {
if (uacpi_get_init_level() == UACPI_INIT_LEVEL_EARLY)
return addr + hhdm;
return vmm_map(addr);
}
void uacpi_kernel_unmap(addr, ...) {
if (uacpi_get_init_level() == UACPI_INIT_LEVEL_EARLY)
// no-op, hhdm mapping
return;
vmm_unmap(addr);
}
it certainly will
uacpi_get_init_level is already a thing
so i think it can be used for this very effectively
ok cool
this is what linux does btw, it has a lot of hackish things like that to work around acpica limitations
acpica has no notion of init levels, its either early or not
and thats a private global variable
Elixir Cross Referencer - source file of Linux (version v6.10.8). Browsed file: /drivers/acpi/osl.c
if (!acpi_permanent_mmap)
return __acpi_map_table((unsigned long)phys, size);
on x86 it just does early_remap
and then acpi_permanent_mmap is set to true during later init
right before the call to acpi_initialize_subsystem();
which on uacpi would bump the init level to UACPI_INIT_LEVEL_SUBSYSTEM_INITIALIZED
found a very important bug in uacpi which was actually hiding another bug and thus making it not really a bug
thanks to this screenshot #1061407633745125397 message
what it says in the warning is, under the \_GPE namespace it already found a handler for event 8 called _L08 so it won't rebind it to _L08
but thats impossible since you cant have two nodes with the same name
under the same namespace
that would've been caught at init time earlier
Looking at the DSDT dump from that laptop, it indeed has two _L08 methods, but the second one is under a completely unrelated namespace
that should've never been reached
Anyway long story short
uacpi_namespace_for_each_node_depth_first had a bug where it would escape outside of the provided initial node and would iterate its peers
the fix was pretty simple
damn
this also uncovered another bug, which is the _REG running code for some reason started iterating at the child node
this used to work simply because of this bug
Now im wondering
Would u expect uacpi_namespace_for_each_node_depth_first(node) to also visit node
or would u only expect it to visit the children of node
im tempted to just not make it visit the node
if i had to guess i'd say only children?
thats what ACPICA does
so probably
its purely a matter of taste, initially i thought well for each means for each so the node is also one of the each
now im not so sure, i dont think it should
if u do for_each_node(_GPE) for example, u dont need _GPE visited, its the parent liek u dont really care
so ill probably change that, idk
this might be why the power button on your laptop didnt work, maybe we ended up calling some _REG thing multiple times because of this
or called something at the wrong time because of this
yeah i was wondering about it again
also out of curiosity had a look if there are any gpes and it seems like there were but the bios patches them out? there's \_GPE.XL{08,0E,19} and the bios patches out nodes by replacing the first underscore with an X for _S3 as well
for _S3 i saw the code that patches the dsdt to turn it into XS3 in a 100% legit ami source code leak
is it available anywhere 
like seriously they had to make the bios patch it instead of just doing
if (SUPP(3)) {
Name (_S3, ...)
}
like im sure it just reads some io reg or whatever
alright the people have spoken, i changed uacpi_namespace_for_each_node_depth_first to start its iteration at the first child and fixed the bug
@hollow elm hey uhh i know its a lot to ask but maybe if u have the time u could rebase managarm to latest uacpi and try running it on your hardware and see if anything changed or regressed (i currently dont have a working build of it), there's a chance that the power button works now
im waiting for the CI to finish and ill merge it
i can try in a moment yeah
does it change anything for the one time I use it in my kernel for pnp:
uacpi_namespace_for_each_node_depth_first(
uacpi_namespace_root(),
acpi_enumerate_callback,
&udata
);```
i'll also see if my current xhci changes broke it or if it still works
that would be big
oh yeah
u havent tested your xhci changes on your hardware yet?
previously the callback would receive the root node as the first node
now it doesnt receive it at all
TLDR: no
ohh nice
i should recheck on my hw as well
maybe my pc/laptop xhci works now
managarm xhci works now??
well theres a chance
there is at least one more change i have stashed but it'll require some refactoring (ideally in the generic usb code so all the controllers don't need to reimplement the functionality)
if it does I will try managarm on my computers
nice
i still haven't figured out why the usb hub doesn't work though
hubs are the worst part
it theoretically should work but maybe i'm missing some step that qemu doesn't care about
it's like really close to working too, i start initializing the device behind the hub and the first control transfer fails with a usb transaction error
its so close i can feel my hubs working already
:^)
it should yeah
nice
theoretically hubs with xhci are easy enough, when you set up a new device there are some fields that point to the hub device and which hub port the device is connected to and that should be it
theoretically 
@fiery turtle do you have implementations for the new kernel functions that uacpi needs?
i think its get_thread_id, which i just returned the pointer to current coroutine i think
also spinlock functions
that one should be identical to mutex helpers, just return frg::construct<spinlock>(*kernelAlloc)
makes sense
even simpler because acquire is not timed
i think i had the patch for that but mightve lost it
yeah i recall you sent some patch and i'm looking rn :^)
i remember literally posting the implementation of get_thread_id
for managarm
i cant find it lmao
yeah same
i think its correct
well with the exception that locking is supposed to turn off interrupts and return the previous state
there are 4 helpers
- create
- lock
- unlock
- free
this is create, free is the same but destruct
lock does return previous state
but i think the state is stored internally in managarm spinlock so u can just return 0
well depends on what type i use
actually, we don't have a combined spinlock + irq disabling
nvm it's litereally called IrqSpinlock
i remembered IrqMutex and looked at that
but that only handles recursively turning irqs on/off
ohh
yeah that makes sense
btw why is the naming not consistent?
{acquire,release}_mutex vs spinlock_{lock,unlock}
acquire vs lock?
that and the order of subject and verb
the latter is definitely wrong
acquire vs lock, idk
lock because it does so unconditionally, whereas acquire is more of a try to acquire based on the timeout
makes sense
but i should fix that, thanks for spotting
break every implementation so far to keep the naming consistent 
do it while you still have time to do so 
yeah i mean i have a warning in my readme
that things will break as this is pre 1.0
i have some more
one ivb and 3 with some older cpus (around 2008 i think?)
one of the older ones has managarm installed on the hard drive and it actually works :^)
on the ivb laptop i think it should boot
it was the first machine i got xhci working on :^)
Please inform me in this project you have here! Tail wags
Sorry?
nice
oh i actually have one more laptop i forgot about
i don't rememeber what cpu gen it is but it's a bit newer than the ivb laptop
maybe haswell?
anyways im procastinating on nyaux
while waiting for the image to write to the usb stick i can think about how i'm gonna refactor the usb code :^)
does this image already contain usb refactors as well?
it has the code cleanup but it's gonna fail with a babble error i'm pretty sure
ah
because we assume that for usb fs the ep0 max packet size is 8, but it's 64, so the device sends an overlong packet
i see
i plan on getting that fixed along with the refactor
which is basically making more of the enumeration logic generic
and doing what linux does when addressing the device
i hope u figure out the hub stuff eventually as well
so: read device descriptor, and only after that issue SET_ADDRESS
yeah it'd be great to have them working as well
perhaps i just need to stare at the linux code harder
indeed
@fiery turtle unfortunately no change in the power button not working
everything else seemed the same
I believe in u
tbh i dont think its a bug in uacpi, it probably isnt
either init order incorrect, or some driver managarm is missing that firmware expects to have been initialized
because everything initializes and works on that laptop, e.g. lid events arrive via EC just fine etc
but for whatever reason it probably assumes we're an old os and dont support ec power button events
Should uacpi_namespace_for_each_node_depth_first(node) also visit node
6
11
2
No, it should start iteration at first child of node
interesting how much divide there is
i think logically yes makes more sense, but in reality u dont need it
I agree.
Maybe change the name to for_each_child if it doesn't visit the initial node?
i agree
my feeling is the function should probably start visiting from the node itself
i would have a look at what acpica's analogous api does and imitate that
AcpiNsWalkNamespace
and that visits only children
odd, netbsd doesn't seem to call it
that would be easy but there are thousands of usages of public acpica api, so too many places to change
fair
makes sense
something i want to do in the future
as well as the devicekit tree proper, a second plane for a tree of acpi device nodes
this will help clean up the pci routing logic a little
sounds interesting, maybe something to steal for my kernel if i ever get to it with all my plans 
i stole the concept from iokit
interesting
uacpi_kernel_create_mutex being called very early might be problematic
(i am looking for table access before i can allocate memory)
i don't have an immediate proposal on a good alternative though
I think I wont be constructing one if early table access was requested all the way until uacpi_initialize
Do you need that like right now?
if you're offering to facilitate it then i certainly won't turn you down
i can always hack around it myself if i must
Out of curiosity what do you need it for right now?
identify numa topology prior to initialising pmm
Are you actually implementing numa support for keyronex? Wow
It was the next thing on my list so yeah, if you can hack around it for now that'd be cool, although im not sure how you would do it
as goddess intended tbh
come to think of it i'll need to be able to support allocating before numa setup if i want to support openfirmware
why is that
not a must-must i don't think but usually people find it less obnoxious to reconstitute the blob into a tree
i wonder how linux handles it
anyways i am going to work on early table access rn, not sure when ill get it done, but soon hopefully
looks like it instantiates nodes by allocating with what it calls the MemBlock allocator
ah, im guessing that one is not numa aware?
also im guessing this is not the only problem with mutexes at early init, since that stuff needs a working scheduler as well
being able to allocate them is only part of the problem
it just bumps the offset stored in the structs describing the available physical memory
makes sense
in my case no, it will still work
only the blocking case is a problem (i don't smp or multithread that early so that can only be erroneous)
but i can't say whether it would be the same on other kernels
actually it wont use get_thread_id, thats only needed for recursive mutexes which are only for AML
so maybe u would be fine
ill implement early tables anyway i think, seems like a useful feature, and all kernels are different
started working on this, will continue tomorrow
Alright uhh.. back from the oss so hopefully back to work soon
Although I have tons of shit to do for work next week
Open source software?
Open source summit
O
Should've gone to plumbers tbh
should've gone to gnu cauldron :^)
Lmao
would've had a chance to meet arsen
Would it be useful to add a pageable/nonpageable hint to uacpi_kernel_alloc?
most allocations should be pageable but not all of them
yes
yes
are u a uacpi user
If I stop procastinating I will be
lol
but I can't imagine it not being useful
do u have a progress report thing
If it's not too much trouble, it would be nice. Even if most don't use the extra info it'd be handy to a few.
if you have no demand paging in your kernel just ignore the flag
ill make it optional at compile time same as sized frees ofc
not yet :(
currently obos allocates all uacpi memory as pageable
which I think is around a megabyte?
idk
this might be correct tbh, im not sure if uh
as long as all events and spinlocks are non pageable
should be fine i think
It depends on the system, I've seen it use 300MiB on my laptop lol
well on qemu
Granted it's a fairly new system, I imagine there's a lot going on
im currently working on UACPI_BAREBONES_MODE or such, this will only leave logging and map/unmap callbacks as host dependency and will allow to utilize table search api without aml execution etc
this might be useful for u
so u can start transitioning to full uacpi when able to but without having to roll your own skeleton table parsing
like i said only the table subsystem
nah
I'm currently planning on switching to Rust, how far are the rust bindings?
and I was like "uKernel?!?!?1"
it will straight up strip most of uacpi out
and leave only the table stuff
without mutexes and such
last time i checked they worked fine albeit not fully implemented
still don't know why people can't just parse the tables themself
were they manual ones?
code duplication
pinned message
fair
why write boileplate yourself if you're going to switch later on anyway
it could be useful
I just don't look back at the boilerplate code I write
especially since uacpi has a robust impl for that that handles firmware quirks and stuff
the exact semantics of what can and can't be pageable will vary between kernels (keyronex mutexes, semaphores, etc can't be - but when keyronex has turnstiles, turnstile-backed rwlocks might be)
or actually these bindings are outdated i think, qwinci had a newer fork
@mortal yoke can u link those pls
thats true, thats why event/mutex etc allocation is not done via uacpi_kernel_alloc
thanks!
updated the pins with your link
yes, the current abstraction for it is very good
thanks
in general i have no objections to the uacpi api as it is today, pageable allocations could be a nice addition, and of course early table access
how much memory is it used anyways on average?
I'd say so
worst case scenario if someone doesn't want potential paging in uacpi they can just not have the kernel API include paged memory
im working hard on the latter atm!
good question, idk
really need to measure that
i know most of it is never accessed again so its nice to be able to page it
So close to having table refcounting work
the only thing left is now solving test runner mental gymnastics around whats a real physical address and whats a fake one
previously it was derivable from just the point at which kernel_map is called during init
now it may be called to map a table way later on
as long as its not referenced
rn the way it works is kinda dumb
void* uacpi_kernel_map(uacpi_phys_addr addr, uacpi_size size)
{
if (!g_expect_virtual_addresses) {
auto it = phys_to_virt.find(addr);
if (it != phys_to_virt.end()) {
auto mapping_it = it->second.find({ nullptr, size });
if (mapping_it != it->second.end()) {
virt_to_phys_and_refcount[mapping_it->virt].second++;
return mapping_it->virt;
}
std::printf("WARN: remapping physical 0x%016" PRIX64
" with size %zu\n", addr, size);
}
void *virt = std::calloc(size, 1);
mapping m = { virt, size };
virt_to_phys_and_refcount[virt] = { addr, 1 };
phys_to_virt[addr].insert(m);
return virt;
}
return reinterpret_cast<void*>(addr);
}
ill just take the easy route and make the test runner bump refcount to the DSDT/SSDT itself so they're not unmapped
this should cut it
few new apis and some behavior change
(this is all work towards early table access)
early tables managed to break exactly 2 completely random tests
not bad
and ofc why would asan say anything
nvm its not a memory bug
DSDT revision was getting overwritten by late init code, since its now initialized earlier
Alright, early table access is basically done (all tests pass on all platforms)! I will do a bit of additional testing before merging it ofc, but please be my guest to test it if you have a use case for it: https://github.com/UltraOS/uACPI/pull/92
Feedback also welcome since i changed quite a bit of other related API
CC: @jaunty fox
This project is pretty nice, I'm gonna integrate it into my OS, especially for the device self-discovery.
My old code xd:
RSDT* rsdt = (RSDT*) memmgr_get_from_physical(rsdp->RsdtAddress);
if(!doChecksum(&rsdt->h)) {
printf("Warning: ACPI XSDT wrong checksum");
return;
}
uintptr_t entries = (rsdt->h.Length - sizeof(rsdt->h)) / 4;
for(uintptr_t i = 0; i < entries; i++) {
ACPISDTHeader *h = (ACPISDTHeader *) memmgr_get_from_physical(rsdt->PointerToOtherSDT[i]);
if (!strncmp(h->Signature, "MCFG", 4)) {
MCFG* mcfg = (MCFG*) memmgr_get_from_physical(rsdt->PointerToOtherSDT[i]);
if(!doChecksum(&mcfg->h)) {
printf("Warning: ACPI MCFG wrong checksum");
return;
}
uintptr_t mcfgEntries = (mcfg->h.Length - 44) / 16;
for(uintptr_t j = 0; j < mcfgEntries; j++) {
printf("PCIe base address: %x\n", mcfg->csba[j].base);
pciBase = (uint8_t *) memmgr_get_from_physical(mcfg->csba[j].base);
}
}
}
thanks
yeah uacpi has helpers for this ofc and structs for most used tables
what happens if the allocated buffer is to small?
and why does: static uacpi_status initialize_from_rxsdt(uacpi_phys_addr rxsdt_addr, uacpi_size entry_size) take a size parameter? rxsdt_addr is the pointer to the rsdt so a size parameter shouldnt be needed?
Its the size of an individual entry
4 or 8 bytes
Xsdt or rsdt
Warning and OUT_OF_MEMORY
This is very old code btw, just moved to a different file
but shouldnt uacpi figure that out?
this is an internal function called by uacpi
woops
nvm decided to go even further here and optimize it so uacpi maps as little as possible when initializing the tables
will probably make checksum validation lazy
unless overridden by a flag
now it should be mapping one page at a time at max
at least at init time
also found a bug in that PR anyway
What is the intended path to recover from a OOM buffer error in the pre heap Phase?
none really, because its a very very unlikely path
since user controls the buffer size, they can increase it
in the edge case that its needed
but i expect like a page to be enough
4096 byte buffer can currently store 73 table descriptors
i dont think ive even seen a machine with that many tables
I mean can i reset uacpi and try again with more memory?
yeah ofc
it will auto-reset if init fails
but u can do uacpi_state_reset manually
๐
Elixir Cross Referencer - source file of Linux (version v6.11). Browsed file: /drivers/acpi/tables.c
seems like 128 is enough as a hardcoded value for linux
if u give uacpi a page for early table heap u get 90 tables
also added this flag
previosuly this was the default behavior
Code for retrieving battery info using uACPI: https://pastebin.com/PKVNpSGA
TODO: convert to a proper example to use for wiki
have you tried setting up a handler for battery notifications?
did you also get a distinction between Notify(BAT0, 0x01) and Notify(BAT0, 0x80) et al
wdym by that?
0x80 is status change iirc, so u should re-read it
0x01 idk to be honest
what is this
qemu 
how would Iย log that tho
when qemu generated a notify
like in qemu or managarm
is the u64 value I get in the notification handler the 0x01/0x80/0x81?
yup
hmm
guess I'll try to debug mammogram on my test machine and try it there
might just be a qemu limitation
which values do u get?
only 0x01
yes and I do not understand how notifications are generated lol
Iย tried looking at a DSDT dump too, no idea
let me see
this is what Iย get when plugging and unplugging
its a bug in this guys code
ah ok, good
ahem, in correct dutch it's balkanker, not ballkanker
but i mean maybe linux does a re-read for 0x01 as well
prolly does, same for windoze
it updates the status if u boot into linux?
Elixir Cross Referencer - source file of Linux (version v6.11). Browsed file: /drivers/acpi/battery.c
looks like it does it unconditionally
yeah, the mailing list post says it updates correctly on linux and windoze
if (event == ACPI_BATTERY_NOTIFY_INFO)
acpi_battery_refresh(battery);
it checks 0x80 only for this
looks like its correct
0x80 refreshes literally everything about the battery
0x01 would just re-read its state
ok
u can just look at that code i linked
acpi_battery_update unconditionally on notify
acpi_battery_refresh on 0x80
battery.c:284
alright
(in qemu)
did u try
I tried, I can enumerate the battery but before I can get any more info it hangs on some unrelated shizz
F
Cant wait to have a more proper fleshed out interface to give uacpi some more attention in astral
that would be based
i need to rebase either managarm or astral to test the latest uacpi pr
and also wait until fadanoid does numa stuff
I can test obos if you want
Not now though, as I need to get ready
Actually I could test it
Rn
Pretty quick
sure
bruh uacpi_initialize api changes
simplifications yes
just uacpi_initialize(0)
and ill probably make it take in a void
sooner rather than later
uacpi_kernel_get_rsdp
lol
the nice thing aobut this api is retrieving the rsdp is arch specific anyway
so u can implement that part of the glue in arch specific place
limine<3 handles it for me
It just returns the limine provided ptr 
@fiery turtle obos boots with the new limine revision on qemu
okay nice that tells me at least i didnt fuck it up too much
i basically rewrote all of table init
I'm testing real hw
u can try uacpi_setup_early_table_access as well if u want
I need to go soon
aight thanks for testing
np
also
limine revision?
limine?
uacpi
lmao
sametyhing for me
limine and uacpi are the same thing, yes
ubootloadwe
anyways thanks for testing
nice
Atm
the init for kernels that don't use the hh for mapping tables (like astral) should be faster now too
hh?
hhdm
Yeah I realized that
uacpi stable api when?
noice
aight time to merge early table support, i tested it in astral and oberrow tested in in his kernel
then ill proceed to the thing ive been procrastinating on
which is thread safety
@vagrant hull sorry for ping but is there any way i can detect whether __popcountdi2 is natively available at build time?
Isn't there a builtin popcount?
yeah i use it atm
but the problem is it generates undefined references to that thing for the default amd64 target
I mean, you can maybe make a weak impl for it or something
It also doesn't support builtin_popcount lel
uacpi_u8 uacpi_popcount(uacpi_u64 value)
{
#ifdef _MSC_VER
#ifdef _WIN64
return __popcnt64(value);
#else
return __popcnt(value) + __popcnt(value >> 32);
#endif
#else
return __builtin_popcountll(value);
#endif
}
yeah i do this atm
Looks good enough tbh
If you need a compiler rt then link against it
Same for all the 64bit math things for 32bit
yeah like i can do that fine, its just extra annoyance for the users of uacpi ig
It's the exact same for 64 math tho, unless you don't use it ig
i had to do this in astral https://github.com/Mathewnd/Astral/blob/167a0dc2ba74b0f3d6d1429c89ac54ae97b71d3f/kernel-src/io/acpi/glue.c#L168
its not a problem since 64-bit math is natively available for the default x86_64 thing, but popcount is x86_64-v1 or whatever
oh yeah
Like I feel like the correct thing is to link against the compiler rt if it's needed 
GCC/clang assumes they exist
its probably the correct thing yeah
Exactly the same as memset/memcpy
i guess i can just add a weak implementation under an ifdef GCC
check that if you build with x86_64-v1 it turns into a single popcount instruction automatically
define "natively available"?
i can think of running autoconf tests or whatever the cmake equivalent is
all my kernels link against https://github.com/osdev0/cc-runtime
compiler-rt as provided by llvm is annoying to use and not gcc friendly
this is just dump in the source tree and forget
Like would be expanded into a popcnt instruction
Instead of a call to this
yeah i am not sure if there is a way to do that with gcc natively that isn't a hack
unlucky ig
but if i do like __attribute__((weak)) __popcountdi2 that would be fine?
like ship my own
why?
what is the use case exactly?
the correct solution would be for whatever kernel using uACPI to use cc-runtime or link with libgcc/compiler-rt
i dont want people to copy paste this cc-runtime thing every time
its very annoying
does the default libgcc for 64 bit ship it?
it should
hmm
maybe it depends
on whether the target needs it
for base x86-64 i assume it has it
since popcount isn't guaranteed to exist
take libgcc.a and check
i checked
it has it
_popcountsi2.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <__popcountdi2>:
0: f3 0f 1e fa endbr64
4: 48 ba 55 55 55 55 55 movabs rdx,0x5555555555555555
b: 55 55 55
e: 48 89 f8 mov rax,rdi
11: 48 d1 e8 shr rax,1
14: 48 21 d0 and rax,rdx
17: 48 29 c7 sub rdi,rax
1a: 48 b8 33 33 33 33 33 movabs rax,0x3333333333333333
21: 33 33 33
24: 48 89 fa mov rdx,rdi
27: 48 c1 ef 02 shr rdi,0x2
2b: 48 21 c2 and rdx,rax
2e: 48 21 c7 and rdi,rax
31: 48 01 fa add rdx,rdi
34: 48 89 d0 mov rax,rdx
37: 48 c1 e8 04 shr rax,0x4
3b: 48 01 d0 add rax,rdx
3e: 48 ba 0f 0f 0f 0f 0f movabs rdx,0xf0f0f0f0f0f0f0f
45: 0f 0f 0f
48: 48 21 d0 and rax,rdx
4b: 48 ba 01 01 01 01 01 movabs rdx,0x101010101010101
52: 01 01 01
55: 48 0f af c2 imul rax,rdx
59: 48 c1 e8 38 shr rax,0x38
5d: c3 ret```
i see
fwiw mlibc also depends on a few libgcc functions and we are certainly not having it ship weak versions of them just to attend those who do not wanna link against a libgcc equivalent
just only have the naive one, popcount won't ever be a perf bottleneck there
Fair as well
If the compiler is smart enough it will recognize what you do and optimize it :^)
also if it becomes a problem maybe use a function pointer stored in a mut static and update it at first run to call the software emulation or the hardware instruction
unless the call overhead becomes even more problematic
Call overhead is definitely more expensive
Okay here are my plans for thread safety of (namespace vs interpreter):
- the namespace and modification of nodes is guarded by a rw mutex lock
- interpreter always takes the write lock (because it's allowed to modify the namespace and randomly update nodes from AML)
- (public api for) iterating the namespace, finding a node etc takes a read lock
- iterating the namespace publically will skip temporary nodes (created inside methods)
- getting the object from a namespace node directly is not allowed.
uacpi_eval()must be used, which takes the read lock, makes a deep copy, then returns the object - updating a namespace node from public api will be done via
uacpi_namespace_node_update(), which will take the write lock
this is the biggest part that needed thread safety, the rest should be easier
getting the object from a namespace node directly is not allowed. uacpi_eval() must be used, which takes the read lock, makes a deep copy, then returns the object
Although this could be fine as long as reference chain is incremented with the write lock taken
it is theoretically possible to make it way more granular and get rid of the GIL, but that would increase memory overhead per node 2x and code complexity by an order of magnitude
so im definitely not doing it now, not for 1.0 anyway
maybe if i have infinite time on my hands at some point
ret = uacpi_reboot();
if(uacpi_unlikely_error(ret))
infoLogger() << "thor: ACPI reset failed: " << uacpi_status_to_string(ret) << frg::endlog;
returning ACPI reset failed: not found in qemu. Known? @fiery turtle
so that's https://github.com/UltraOS/uACPI/blob/9036f48cc29c4c4f75661f093311dcb69414d1fa/source/sleep.c#L532-L544C5 this case then
A portable and easy-to-integrate implementation of the Advanced Configuration and Power Interface (ACPI) - UltraOS/uACPI
but I'd assume this should just workโข๏ธ in qemu
not known, no. did u pass -no-reboot to qemu by any chance?
nope
tools/host-qemu/bin/qemu-system-x86_64 -s -m 8192 -name 'Managarm x86_64' -enable-kvm -debugcon stdio -cpu host,migratable=no -smp 4 -device piix3-usb-uhci,id=uhci -device usb-ehci,id=ehci -device qemu-xhci,id=xhci -drive id=boot-drive,file=image,format=raw,if=none -device virtio-blk-pci,drive=boot-drive -netdev user,id=net0 -device virtio-net,disable-modern=on,netdev=net0 -vga vmware -device usb-kbd,bus=xhci.0 -device usb-tablet,bus=xhci.0 -chardev file,id=ostrace,path=ostrace.bin -device dmalog,chardev=ostrace,tag=ostrace -chardev file,id=kernel-profile,path=kernel-profile.bin -device dmalog,chardev=kernel-profile,tag=kernel-profile -chardev file,id=kernel-alloc-trace,path=kernel-alloc-trace.bin -device dmalog,chardev=kernel-alloc-trace,tag=kernel-alloc-trace -chardev socket,id=gdbsocket,host=0.0.0.0,port=5678,server=on,wait=no -device dmalog,chardev=gdbsocket,tag=kernel-gdbserver -chardev socket,id=posix-gdbsocket,host=0.0.0.0,port=5679,server=on,wait=off -serial chardev:posix-gdbsocket
that's the full qemu command
i just booted astral like yesterday and reboot definitely worked
so it must be one of these command line options
oh it works (with the ps2 reset
)
shutdown works fine btw
and the prepare to enter S5 thing no issues on that either
sure
https://github.com/qemu/qemu/blob/423be09ab9492735924e73a2d36069784441ebc6/hw/i386/acpi-build.c#L219
Official QEMU mirror. Please see https://www.qemu.org/contribute/ for how to submit changes to QEMU. Pull Requests are ignored. Please only use release tarballs from the QEMU website. - qemu/qemu
trimmed to nuke all the gdbsocket memes
tools/host-qemu/bin/qemu-system-x86_64 -s -m 8192 -name 'Managarm x86_64' -enable-kvm -debugcon stdio -cpu host,migratable=no -smp 4 -device piix3-usb-uhci,id=uhci -device usb-ehci,id=ehci -device qemu-xhci,id=xhci -drive id=boot-drive,file=image,format=raw,if=none -device virtio-blk-pci,drive=boot-drive -netdev user,id=net0 -device virtio-net,disable-modern=on,netdev=net0 -vga vmware -device usb-kbd,bus=xhci.0 -device usb-tablet,bus=xhci.0
in qemu its iffed under LPC
are we missing some -m flag?
good question
Official QEMU mirror. Please see https://www.qemu.org/contribute/ for how to submit changes to QEMU. Pull Requests are ignored. Please only use release tarballs from the QEMU website. - qemu/qemu
yeah its only created for Q35
aha
good to know
(also good to know that ahci breaks on q35
)
not that that's used
but the driver dies
ye
so I'll propose that Managarm does the same
spicy

what could go wrong
lol
Assert(!unplug);
just unplug the CPU with the unplug thread running 5head
can't assert if the thread that's checking it is gone
I think it might be used in large clusters? but I'm not really sure
my plan for OpenItanic, and subsequently IFOS, is to provide a CPU hotswap mechanism if ACPI properly allows it (I am yet to fully understand ACPI, but one day I will)
the hotswap would be primarily for testing the limits of the processor interconnect, but might be useful if I'm running tests and have a part fail
Interesting
I've thought of what BadgerOS might do about it and I'm not supporting it for now but...
... the current codebase is very much lenient to such shenanigans happening, if you use the proper mutexes.
Smhsmh
lol
Virtual machines
Alot of auto-scaling will allow for cpu hot plugging
Sometimes even supporting transferring the VM to a larger machine, which then will add it's cores as well
also i just remembered there isnt even a \_PTS on QEMU so its a no-op there anyway lol
yeah this mostly matters for quirky laptops
In vms at least you can use the hypervisors for some services like monotonic clocks that dont get out of sync with the hot plug (cough tsc sucks)
You don't bad mouth tsc it's awesome
finally went ahead with this change
also decided i'd expand on how to treat timeout
(well this change is part of a giant thread safety pr im working on)
How usable is uACPI as of now? I saw that the repo says it isn't production ready because of some thread safety stuff but is it close if it's only used in a single thread?
Its in a good enough state that plenty people here have used it for various things
other than thread safety its production quality
everything is implemented and stable
That's perfect! My kernel is in Rust but I want to use it via FFI since it looks like a better solution than any other I could find and certainly more so than anything I could spin up from scratch.
I'll take a look and maybe see if I can help with that as way to give back.
more than acpica in a lot of ways
lol thanks saga
That's kind of crazy to think about. That you guys made something that's better than the reference implementation.
thats because the reference implementation doesnt try to follow the real reference implementation which is NT
How can you when it's closed source?
and uacpi is built as if NT is the reference implementation
#1217009725711847465 message
That makes sense. Since that's what it looks like the FW vendors seem to target. I honestly hate ACPI but what I hate more is all the ARM and RV boards that don't provide it and go off and use other things like SMC and SBI.
TLDR: feed arbitrary AML to windows and see how it works with it
windbg has a way to enable tracing for every aml opcode that is executed
so u can see what it outputs at any point
!amli set traceon dbgbrkon errbrkon spewon;g
yeah
That's interesting. I assume that's all done in a VM so the firmware can be messed around with. So just a question if you don't mind, how does Linux handle firmware that's made for Windows if it uses ACPICA which doesn't follow Windows?
poorly, or not at all
acpica had to adapt a lot of workarounds throughout its lifetime
some things still dont work
generally it just screams loudly on dmesg but it works anyways
it tries to pretend to do things like nt with hacks
but its fundumentally incompatible
pretty much
Thanks for answering all my dumb questions and you guys are all awesome for making this project! It is much needed.
people have collected tons and tons of bug reports throughout the years where most important incompatibilities have been fixed with hacks in acpica, the rest are small things that generally are not that imporant
thanks and np!
if ur interested to see some examples look at my readme
Will do!
i wonder if it's possible to shove uacpi in linux
maybe in the userspace
its 100% possible to shove it into the kernel directly, especially since a lot of public uacpi api mimics acpica, but there are thousands of files that use acpica api directly, so all of those would need to be rewritten
so its just a lot of work
What if you just
