#uACPI - a portable and easy-to-integrate ACPI implementation
1 messages · Page 65 of 1
well yeah
ah
then I'll be the 3rd system to run uacpi in userland
yep
i wish i had actual hardware accel options for aarch64 (or real hardware) so i could post an actual aarch64 number too
rent an aws aarch64 bare metal server or smth 

if you want i can submit my 19218 on aarch64 qemu tcg under x86_64 on my ryzen 7 3700xt
true
yeah
wonder if i could somehow get qemu to run on my phone, that processor can run aarch64 (though i dont actually know if android uses aa64 or aa32) and its rooted
dunno if android has an accel option for android though lmao
write the drivers for your phone and run it bare metal
i doubt it has kvm yeah
you probably can't run kvm on your phone
since virtually all phone manufacturers run hypervisors already
true
i would be a tad worried about bricking this phone running bare metal is the only reason id want qemu support
also the phone doesnt have acpi
so uh
i mean technically without VHE your kernel is already a hypervisor
no uacpi benchmarking on it bare metal lmao
true
no, the phones don't let you boot in EL2
oh
what do they even run at el2 and why
hang on though, ive got a modded nintendo switch 1. also probably no acpi by default but that thing i know i can run linux on
there's typically some BS hypervisor on top
why not utilize el3 for their crap
stuff like https://github.com/quic/gunyah-hypervisor
because thats where firmware goes
el3 is for the "secure monitor" but ime most of the uses for it are sending syscalls to the firmware lmao
thats how you startup APs on aarch64, using an SMC instruction to syscall up to EL3
unless acpi tells you to use HVC instead
(or devicetree ig)
if you want kvm on aach64 you can run on a raspi4/5 or similar device
that would be dog slow
i dont have a raspi but again i do have a modded nintendo switch that i can put linux on, that might work
maybe an m2 chip with asahi
it's definitely faster than tcg 
i suppose
yeah
but i mean
u can run under the apple hypervisor
natively
its decently fast iirc
if u have any apple silicon computer
-accel hvc or whatever?
i am too poor for apple hardware lol
Managarm definitely boots way faster on a raspi than on tcg
more than an order of magnitude?
my build system does however natively support running using the apply hypervisor though, at least in theory, so if someone here has apple aarch64 hardware theyd be willing to test my os on once i push my latest work thats an option
i wanna get some form of testable interrupt set up (probably gonna be the generic timer to start with) and then i can push it, just need the latest zig master build and qemu installed to run it
nice thing if there was more aarch64 hardware available, qemu's aarch64 virt board is fairly complete and has acpi as an option that afaict is fully fleshed out
yeah
last time i used it was for checking my log ring memory barrier correctness and my bootloader aarch64 support
the only downside ive found to its acpi support is that the acpi namespace will never have the RTC unless you provide your own ssdt for that
it has an rtc but never in the tables
because of a chicken-and-egg problem that arises from how qemu interacts with firmware
that should be easily fixable by adding an aml generation hook to the rtc device in qemu
im sure upstream would appreciate it
they specifically removed it from the tables to fix an inconsistency when using uefi to boot
oh?
because the uefi firmware will remove the rtc from the DTB in favor of having the os use uefi runtime services for that
but the firmware cant remove it from the dsdt, because the firmware isnt actually the one providing the acpi tables, qemu is
thats why aml allows u to just return 0 from _STA
it could read some NVS region like real hw
but I guess that would require some edk2 integration
to actually write that there
and they couldnt be assed
pretty much
i use uefi anyway so it doesnt bother me that the rtc isnt in there in the first place because the firmware would be removing it in the real setup anyway and uefi runtime services are super convenient for the rtc anyway
yeah i guess
note that the firmware either cant or doesnt actually stop you from using the rtc directly if you hardcode the address lmao
what does uefi use internally?
the rtc device
lol
it has a driver for that then stays alive in the runtime services
whats even the point of the wrapper
and just provides the uefi standard interface
like if the os has a native driver why do they not want it to use that
no idea
so strange
it's specified like that in uefi
presumably because windows doesn't want to write rtc drivers
what's specified?
the existence of the wrapper is, havent seen anything specifying that it should try to hide the underlying device from the os though lol
Or does RTC being in acpi somehow break windows or something
the GetTime() runtime service
yeah but cant u have both a device in aml and the service
yeah the wrapper is always there
my current guess is that its to stop the device getting out of sync with internal state of the uefi runtime driver
only if there are two rtcs i guess
So it might have some lock or something to sync against smm
Now why smm would need it, idk
the assumption is the os will mess with it and its not ronly?
During runtime, if a PC-AT CMOS device is present in the platform the caller must synchronize access to the device before calling GetTime().
there is a special provision for x86
but not for aarch64
so probably sync things then yeah
SetTime()
i guess
Also you have index + data reg
true
So the access is not atomic
in principle the requirement to have a GetTime() runtime service is not that insane
Could also be for ensuring you have the correct ref for anything that returns a time in the firmware
I mean it is a useful service
They just took the lazy route of removing the device
the runtime service taking full ownership of the rtc also is the single biggest reason i wrote my own bootloader lmao
How does it help you in this case
remapping runtime services to a virtual address
Ah
which is supported
but limine doesnt do it and leaves uefi stuff unmapped
so id have to remap the 0-offset id map for uefi and then call the function and undo that
note limine also wouldnt be a good place to do that, since the function to move runtime services to virtual addresses can only be called once
so what id really want is some way to leave the uefi page tables up on uefi in order to do that, but instead i ended up just making my own bootloader and putting that early memory layout stuff in there
Im a little late to the discussion but I really suggest not to use tcg for any profiling, it has no correlation with how real hw runs - faster in tcg does not mean faster in hw
yeah im only using tcg for lack of alternatives for cross-arch testing, and have no intention of taking the number actually seriously in any way
The best option for this intriguing goal (arm64 uacpi phallometry) would be Radxa Orion O6 (or something) or Orange Pi 6. It's not phones, but they have acpi. Also Danct tried jared mcneil's edk2 port on Pinetab 2. The latter (port) was for Quartz64 board (same SoC). The board is around 60$ (4GB model, 80$ for 8GB one). All rockchip SoCs run fw in EL2, so with these you could run linux with kvm and your OS bare metal. However I don't know if linux runs well when edk is in "acpi" mode. And if it does, if it reports acpi to qemu. I mean such edk ports now report both fdt and acpi. linux apparently prefers the former. And I don't know what its kvm will report to the kvm payload.
tbh it doesn't actually need acpi for it to be good for benchmarking uacpi kernels, since you want to use a standard vm configuration that provides the acpi tables but on hardware that can run a hardware accelerator for the vm
if everyone used the same board you might be able to use the board provided acpi too but yknow
as long as it has uefi I could run my os bare metal, though id need to change the debug output stuff a bit
one thing I can and maybe will actually do though is parse dbg2 in the loader, since I'm using uefi for serial out during boot services but this would let me get non hardcoded debug output during runtime services but before getting full drivers up
yeah this cannot be unfucked cleanly
ill have to add a UACPI_ARCH_DISABLE_INTERRUPTS helper or something
that should be a kernel api function and not inline asm though
yeah perhaps, so it can preserve nesting
yeah
but now it will panic if you try to take sleeping locks with irqs disabled 
yeah thats a good thing to detect
fwiw linux etc will probably also panic, at least if lockdep is on
so this is worth fixing in uacpi imho
linux will panic even without lockdep i think
they have calls to __might_sleep in places like that
if panic for these warnings is enabled it will die
usually its disabled in prod but yeah still a warning is really bad
so yeah either i split this enter sleep into one more function or I introduce helpers for disabling/enabling interrupts
i think the latter is better and can be useful in the future also
technically uacpi_prepare_gpes_for_sleep(); is a good alternative to adding new kernel api
since like 99% of uacpi users dont even support suspend
so they might as well not even call this function
Personally, I don't have a preference here, IMO both solutions are fine
isnt it can be just inline
I need to properly implement it
this makes preserving nested interrupt disable invocations very difficult
apart from the failed assertion which is my fault, is that error normal?
assuming you have no ec driver, yes
ah fair enough
Yeah it expects that a modern os will have an ec driver and uses it unconditionally but its not fatal if you dont
makes sense
re EC: it's not clear to me how to fix https://github.com/managarm/managarm/issues/1248
The code here managarm/kernel/thor/system/acpi/ec.cpp Line 195 in a2692a7 auto *query = frg::construct<ECQuery>(*kernelAlloc); should not allocate since it runs in an irq context. Ideally it ...
the current code calls ecDevice->checkEvent() in interrupt context to obtain idx (which is the GPE index apparently?)
the problem is that passing this idx to non-interrupt context is currently done by using an allocation
can we alternatively read the GPE index outside of interrupt context or does that not work because it's required to ack the irq / could lead to races?
or, if that's not possible, can we just use a bitset or something like that to pass the idx to the worker? or do we need to preserve the exact sequence of EC queries?
AFAIK a lot of implementers fix this by actually handling the interrupts by resuming a thread
Instead of trying to deal with the problem of allocs from an interrupt context
that's what Managarm does as well
the problematic allocation was originally added to move data to a thread
Is there a reason why you can't temporarily mask the interrupt and just resume the thread?
Maybe atomically setting a flag of which interrupts have happened if you feel fancy
I don't think that model is currently supported by uacpi
yeah i think so
ec can work completely event driven
linux just does advance_transaction
which basically wakes up a thread
alternatively just move the entire interrupt into a software irq
does uacpi do the equivalent of acpi_clear_gpe automatically?
ah i guess that happens due to UACPI_GPE_REENABLE?
not for externally managed gpes like EC, but it has helpers for that ofc
yeah if it is set
Linux has a separate SCI handler for the one laptop per child thing, it just does
static u32 xo15_sci_gpe_handler(acpi_handle gpe_device, u32 gpe, void *context)
{
schedule_work(&sci_work);
return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
}
even this approach could work i suppose
so GPEs are edge triggered?
not all of them but the ec one is guaranteed to be edge triggered iirc
at least linux hardcodes edge triggering and so does managarm
alright
How do I fix this bug
11
11
2
Add new api: uacpi_kernel_{enable/disable}_interrupts
A shit ton of new uACPI features coming in the next release:
- Automatic handling of non-existent PCI device accesses from AML (just return UACPI_STATUS_NOT_FOUND from your pci_open API impl)
- A new
uacpi_is_platform_reduced_hardwarehelper - A new
uacpi_table_subsystem_availablehelper - Automatic handling of misaligned early table buffers
- New kernel api
uacpi_kernel_{disable/restore}_interrupts - Fixed a bug that caused a sleeping mutex to be grabbed during shutdown with interrupts disabled
- Fixed a bunch of event helpers that didnt check against reduced hardware which would produce a bogus error status
I pushed a new feature-drop branch, would appreciate some real hw testing before i merge it
especially shutdown etc
@north holly can u test it on obos rn?
yea sure
inb4 everything shits itself
oh
[cmake] fatal: unable to access 'https://github.ccom/uACPI/uACPI.git/': Could not resolve host: github.ccom```


oops
added an extra c to com
lol
thx
uacpi_interrupt_state uacpi_kernel_disable_interrupts(void)
{
return Core_RaiseIrql(IRQL_MASKED);
}
void uacpi_kernel_restore_interrupts(uacpi_interrupt_state state)
{
Core_LowerIrql(state);
}```
this is good, right?
it boots on qemu
which is a good sign
well
how do u handle multiple lowers on your kernel?
just theoretically
if u take a spinlock under a spinlock for example
well as long as the irql lowered to is <= current irql
there isn't a problem
yeah there shouldn't be a problem
there is on raise
because then it's lowered multiple times
but raised once in the outermost lower
ah wait u preserve the state
then yeah
yeah ive reviewed the uses of uacpi_kernel_disable_interrupts and it looks good to me
yeah should be fine
and u can remove the manual calls to cli when calling enter_sleep_state
ok
do u use early tables as well?
i think i set them up but i dont think i use them
ah ok
one day ill get rid of my stupid acpi table parsing code for x86 only
why did u react to your own comment
mistake
lol
im gonna test this on one of me old pcs and hope it works
lets hope
it worked
or at least it looks like it did
because this pc actually has bugged shutdown
grabbing the branch for testing now
Thanks!
it doesn't always shutdown when S5 is entered
What does it do instead
stay on forever
happens on windows and linux
Oh
it started a few years ago
sure
Btw what's the state of obos suspend
ok im a bit confused because it isnt erroring over the disable and restore interrupts shims not being there yet
maybe the linker is too good at gc lol
The functions that use them get optimized out perhaps?
Its a separate object file so if you dont use anything shutdown related you won't run into it
Wait thats a thing?
yep
Interesting
runtime services has a ResetSystem function, takes a reset type. options are cold (full system reset, equivalent to a power cycle), warm (not entirely sure what it actually means), shutdown (specified as "equivalent to the ACPI G2/S5 or G3 states") and platform-specific (lets you pass a guid that specifies a platform-specific bonus kind of reset)
doesnt do sleep but does to shutdown and reset
Ah
Warm reboot is a power cycle only to the cpu
Fun fact, cold reset doesn't always power cycle all PCI slots
Really depends on motherboard
mhm
one of these days ill set up actual acpi sleep but meh
got higher priorities atm
uacpi_is_platform_reduced_hardware is workin tho
thats nice
also i was already returning not_found for the pci open thing in that exact scenario mentioned, but i cant confirm if thats working because i dont have stuff to test with that relies on that behavior
thanks for testing nonetheless
I'll test on Managarm in a bit
broken on qemu
no clue why
no willpower to debug it
damn
do i need scheduled work implemented to use uacpi shutdown btw? if not i can probably whip up a test after dinner rq, thats the only kernel api i still have stubbed atm
u dont no
cool, ill look into doing that later then
@fiery turtle is it guaranteed that enter sleep state will never return ok? ie is it noreturn on success?
trying to figure out if the zuacpi version should be !noreturn or !void
alright shutdown is working for me now
No because there are other sleep states than 5
Some are designed to return back to the same place in the same state so it will return OK
Nice
@flat badge BTW did you have the chance to check if that fixes the managarm regression?
Not yet but i can ping you in a few h
sure thx
oh u can also remove the bool from eir now i guess
big, tyty
very nice
aight merging the PR then
4.0.0 is live
Cc @winter orbit, I think you ran into UACPI_STATUS_NOT_FOUND being a hard error
Oh nice
Oh also cc @strong heath, u can now get rid of the workaround
Also thanks to everyone who tested the PR
ah cool
out of curiosity, what is the purpose of splitting the prepare from the sleep? if it was just to get interrupts disabled that kinda doesn't need to be a thing anymore, but if there's other reasons I'd like to know so I can use it correctly when I get to that point
Yeah big boy osses do a lot of work between prepare and enter
prepare here eventually calls acpi prepare
and then enter is here https://elixir.bootlin.com/linux/v6.19.3/source/kernel/power/suspend.c#L468
if you're curious about specifics u can jump into the functions between
cool, thanks
if i have time today ill pull zuacpi up to uacpi 4.0.0, shouldnt be bad because i already did the work yesterday for the side branch and the only other new thing to add to it is the table subsystem available function
Nice thanks
also adding the prepare and enter sleep functions since I got those bound yesterday for testing anyway
Letsgo
To be honest you have a point, even though separate helpers can be needed, I can still add one that combines both for people that dont care about that stuff
Now that thats possible with the new api
yeah
also, should there be a way to use the protective table csum flag with early table access?
zuacpi for uacpi 4.0.0 is pushed
perhaps, yeah
changes from the last time i talked about what zuacpi had:
- updated from uACPI 2.1.0 to 4.0.0
- no im not joking it was really that behind a few weeks back lol
- added a zig-idiomatic iterator for the MADT
- fixed some incorrect values in the zig copy of the madt entry type enum
- added zig versions of GIC MADT entry types
- added the rest of uacpi_interrupt_model to the zig copy of the enum
- updated from zig 0.14.1 to zig master (currently prerelease ahead of zig 0.16.0)
- added packed structs for the flags in the FADT
- added prepare for and enter sleep state bindings (rest of sleep.h not done yet)
thats quite big
I just asked Gemini to come up with a uacpi kernel api implementation
It came up with some outdated version with raw_write etc lmfao
rip
How is ReactOS doing?
uacpi code is merged into master i think
but the new driver is being slowly worked on by the darkfire
since it basically requires unfucking a lot of other parts of the ros codebase
wasn't ros like surprisingly good NT compat?
considering it's an nt clone, yeah lol
it can run a lot if not most windows programs natively
there's even a crisis/fallout 4 demo
that's rad
was there already a PR on the haiku side?
btw re the discussion in lounge: we still have the issue that the uacpi benchmarks do not differentiate between single threaded and multi threaded and the first two entries run uacpi without multi threading support
yeah i suppose we could split/specify whether it's an assumed singlethreaded env or not
or make a * next to the name or something like that
a separate table is probably overkill
hey @fiery turtle could you test this iso on your cpu? (the one used for my previous score on the leaderboard)
qemu-system-x86_64 -serial stdio -cpu host,migratable=off -smp 4 -M q35 -accel kvm -m 1G -cdrom image.iso
(iso below)
this one is running uacpi init in the scheduler
with its worker threads
leaderboard cheats
without initramfs
I was thinking a separate column?
Yeah sure
Once im in front of my PC
Might be difficult to add this retroactively since I basically have to inspect every os source code lmao
Maybe only for the top 5 or something
yeah
And leave ?? For other
[00:00:00.065937] [info] uacpi: successfully loaded 1 AML blob, 1726 ops in 0ms (avg 7025513/s)
still quite good
still second place yeah
actually that makes it first place for multi threaded kernels
I wonder how my OS would perform, once I implement futex
I should take a day to microoptimize for the benchmark to see how well I would do
Not until I have at least ahci though, thats a much bigger priority because arcade
@fiery turtle so if we move the EC handling to a work queue, we should not pass UACPI_GPE_REENABLE from the irq, right?
I assume the equivalent of that is done in uacpi_finish_handling_gpe?
yeah
are u implementing that atm?
yeah
Would be really nice to have such an example
yeah there is like not a single hobby os with a proper event/irq driven EC driver
uacpi_finish_handling_gpe is also not IRQ safe
;D
as it calls uacpi_recursive_lock_acquire
that makes sense no?
maybe
since there's a GPE_REENABLE for irq handlers
Maybe a comment would still be good
To mention that
Also maybe i should also test managarm on my 9950x3d
Might yield a higher score

uacpi-info: successfully loaded 1 AML blob, 1708 ops in 0ms (avg 7942819/s)
uacpi-info: successfully loaded 1 AML blob, 1708 ops in 0ms (avg 8241254/s)
yeah 8 million is pretty consistent
i guess managarm is top 2 now
could you also try this one
Tmrw yeah
Initial minimal "usable version" is stable now, and people have been testing it. Going to open a draft after the 18th
here's uACPI allowing a new NVMe, and xHCI driver to work so
it's pretty good! we're pretty much ready to use it!
I'll update the uACPI version after in another PR, i'd rather just get it semi working first

What am I missing?
Oh I haven't seen your driver lol
Do u have irq driven transactions or burst mode
does it really count as polling if the polling happens inside the interrupt handler
Yeah, because when you submit an EC command you're supposed to wait for the data byte via an irq
So its a series of a few irqs you must process in a row all related to the same transaction
ah ok
I guess I could implement that sometime?
no difference
does uacpi really need fflush or could i just stub that?
fflush is only used for the test runner?
🥀
What the fuck ☠️
lmao
i was building tests too smh
but i actually wrote a small stdio.h impl for that shit
(atp i should just give up on osdev im so bad at it)
Docs dont tell u to recursively glob the root dir tho
well thats just something my kernel does
Oh
like it or not
everything in the /kernel folder gets built
That's not really a good build system lmao
generic timer description table GTDT has been added to zuacpi
(at least the base fields - got the structs for the subentries but not iterators or helpers there yet)
(and the base fields are confirmed working, ive got the timer ticking on aarch64 on my kernel now)
GDT 2.0? Dang Intel's cooking with Nova Lake
Nova Lake changelog:
- removed xAPIC
- removed GDT v1.0
- added GDT v2.0, now with falliable init so prepare your gdt logs
xD
GDT init... [FAIL]
GDT init falling back to older implementation... [WARN]
GDT init... [OK]
Lmfao
lmao
lmfao
lmfao
lmfao
lmfao
lmfao
My favorite kind of bug 
i really need to add uacpi_simple_enter_sleep_state or something
why is it split into two functions anyway?
#1217009725711847465 message
the biggest one is apparently you're supposed to execute _PTS and only then shut down the APs
well for e.g. S3 the os probably wants to save registers somewhere accessible and maybe do some other work before leaving the APs in a hlt loop
u mean ap shutdown?
thats just basically sending ipi and doing cli;hlt
but u can shut them down even before prepare probably
added a binding for namespace_node_parent to zuacpi
well once the push finishes i will have
Who even has so large of a stack? 
People who compile their kernel with a compiler that doesnt optimize switch case allocations on debug and have a gigantic switch case in their kernel
rust users
rust
me
i do
welp, my OS is rust-friendly
I had 8KB stacks, but it has overflown once, so now I just use use 32KB, but could probably get away with 16KB?
But I have 1* stack per CPU
*actually, 5
I don't think my kernel goes above 4k but I have 16k
But my kernel is in C++
(which probably shouldn't matter?)
Actually, I now remember why I chose 32K
I allocate large arrays on stack during TLB shootdowns and stuff like that
Compilers are pretty bad at switches even in release mode
Last time i checked, they were not smart enough to alias distinct types in distinct switch cases
im currently using 32k but thats because of my debug info parsing being poorly optimized wrt stack space (because it comes from the zig std that was originally meant for usermode where it gets uh more than that. someday ill fork that part out into my kernel and try to optimize it but meh)
(basically im fighting with libraries that assume the compiler will optimize the passed struct parameter into effectively a const pointer normally so that when the struct is spread across registers instead it can use those directly, but that optimization doesnt happen properly and/or was removed but the libraries werent updated and now its copying large structs on the stack 💀)
I do 64kb stacks just in case™ although before I always did 16k
And a long time ago I used 8k stacks
dont ask
keyboard mash
@fiery turtle i found a small mistake in uacpi
this should be UACPI_NULL
actually, there are a lot of usages of NULL throughout the codebase
thanks yeah thats an issue
🙏
yes
i just don't define NULL because i use nullptr exclusively
ill fix it
include/uacpi/internal/opcodes.h: * at decode_ops[pc + 1] is NULL.
include/uacpi/internal/resources.h: * native resource given the AML counterpart. This being NULL means no extra
include/uacpi/internal/resources.h: * AML. The 'aml_size' field is used if this is NULL.
include/uacpi/kernel_api.h: * 'mem' might be a NULL pointer. In this case, the call is assumed to be a
include/uacpi/namespace.h: * Either of the callbacks may be NULL, but not both at the same time.
include/uacpi/platform/types.h:#define UACPI_NULL NULL
include/uacpi/tables.h: * tbl.hdr, sizeof(struct acpi_madt), parse_madt, NULL
include/uacpi/uacpi.h: * A value of NULL for 'parent' implies uacpi_namespace_root() relative
source/default_handlers.c: if (uacpi_unlikely(ctx == NULL))
source/interpreter.c: // NULL target
source/opcodes.c: * expected to keep the item 0 as NULL, which is checked below to return
source/resources.c: "source string length is %zu but the pointer is NULL\n",
source/resources.c: "vendor_data_length is %d, but pointer is NULL\n",
source/tables.c: uacpi_error("both RSDT & XSDT tables are NULL!\n");
The only real one i see is default_handlers.c
@slim panther did i miss anything?
idk i just grepped for NULL in uacpi lol
but yeah that error is the only one i actually hit
well tests are normal userspace apps
then nvm
fixed in master
thanks
thx for reporting
mfw obscure setups 
i should really sandbox the env better in tests to catch stuff like that
but its not easy
are there any examples of using \_SB._OSC with uacpi out there that anyone knows of? or in general ig i can probably translate other stuff to uacpi
its very advanced stuff so i kinda doubt it
but acpica should be easy to translate
(from linux)
alrighty
i did end up digging in and at least on my laptop the bit id want to support isnt even supported by the firmware anyway lmao
what are you trying to enable?
resourcesource
no idea what that is lol
my laptop doesnt support it in firmware and my desktop doesnt even seem to have a global OSC method lmao
so like this is thoroughly a stretch goal
theres actually two fields to it, and if the relevant bit in osc is 0 then they are required to be 0 and empty-string respectively
or rather 0 and ignored-string
oh ok
then maybe thats the one i was thinking of
elixir doesnt let me search for strings lmao so i really dunno if linux uses it
search for acpi_run_osc
https://elixir.bootlin.com/linux/v6.19.3/source/drivers/acpi/bus.c#L370 found it, they do call the \_SB._OSC
ye
this thing also causes the firware to do Load() to load a whole bunch of new tables
https://elixir.bootlin.com/linux/v6.19.3/source/drivers/acpi/bus.c#L339 hey they even set the bit i was lookin at
cool cool
another thing i noticed
it's not an issue at all, but the version in the meson project is wrong
damn i missed the fact that leo added a new place that must be updated every time 😢
yeah ill fix that
fixed
lmao is it cancelled or not
microkernel is
nice
So you're what? Just making a monolithic one out of it?
yes
goddamn how is everyone so much faster than me at loading blobs lmao
didnt think my allocator was that bad
If I wanted to write monolithic I'd just fix BadgerOS then bruh
that's why i said you shouldn't work on zinnia it's a waste of time for you 😭
might be because marvin has 1841 ops
usually its like 1704 or something?
uACPI isn't supposed to be a benchmark anyway
wouldnt that mean i'm even faster?
those could be very lightweight ops so they skew the result down no?
could be
like its a relative value so it doesnt scale up with the number of ops
the biggest uacpi score that I have got is like 7.8M on the nt thing on my cpu, above that idk what would I have to do lol
the abi might also have some kind of effect on it, though I can't really easily test that on the same kernel
isnt ms abi generally worse
higher stack usage worse reg allocation due to struct passing rules etc
I think yeah
though it does allow the usage of sse but idk how much of an impact that makes in practice, that I can actually test disabling
in kernel?
yes because you only have to save like 6 regs on irqs + the rest on ctx switch
hm
doesn't look like it makes that big of a difference though, like a few hundred k at most
on msvc I don't think its even possible to disable it 
so u need an asm prekernel to set up sse?
a small one yes
so on every context switch and irq nt saves sse regs as well?
yeah but five times more kinda seems much lmao
im still happy with my 1.2m tho
on 64-bit I am pretty sure yeah unless there is something I have missed when reading some disasm + their docs (which state that drivers are allowed to use sse/sse2 in an interrupt context without needing to call a function to save/restore them)
damn, is this really worth it?
whats the diff?
sysv makes all sse regs caller-saved
so to use sse in kernel with sysv abi you need to save/restore all sse regs
instead of just a few
but you dont know which regs were touched when an irq happens right
you do know that the compiler preserves the non-volatile regs though
the point is that on ms abi most sse regs are callee saved
so the interrupt handler will preserve most sse regs
for the same reason that not all regular registers are callee saved
because it's more performant for leaf functions to have some caller saved registers
also some of them are used for params
Doesn't sysv literally also do this
no
oh so some of them are still not callee saved
on sysv all sse registers are caller-saved
lame
on msabi xmm0-xmm5 are caller-saved
why the hell did sysv do it like that
dumbassery
the aapcs abi is also funny
q0-q7 are used for passing args which is fine, but then q8-q15 are callee-saved, but only their lower 64-bits, not the full 128-bit register
yeah it has the funny partially saved regs where if the callee wants to use some of the regs only to hold floats/doubles it only needs to save the low 64 bits
💀
burh
why
i guess because only that part is used for float/double (non-simd) math?
Yeah but the upper half is still nuked when you do float ops, no?
you don't need to preserve the upper half
that was the cause of the first aarch64 abi break in mlibc when i was first porting managarm to aarch64
, i forgot to account for the lower half of q8-q15 in setjmp/longjmp
So if it's allocated as SIMD it's caller-saved but if not it's callee-saved
no, the lower 64-bits of q8-q15 is always callee-saved, regardless of what you or the caller does with the registers
that weirdness also makes it so that NT on aarch64 has to save all of the regs in all cases, if there would either be a way to only save the upper bits of the regs or they would be specified to be fully callee saved they could be skipped in some of the cases
idk
when an arch is so nice as to provide its own standard abi u gotta use it
unlike x86 where u do random bs
I think the concept of ABI on x86 was mostly because of what MS did
actually I don't think its fully the arm-specified abi
The 16-byte area immediately below the current stack pointer is reserved for use by analysis and dynamic patching scenarios. This area permits carefully generated code to be inserted which stores two registers at [sp, #-16] and temporarily uses them for arbitrary purposes. The Windows kernel guarantees that those 16 bytes aren't overwritten if an exception or interrupt is taken, in both user and kernel mode.
as I am pretty sure the arm abi doesn't specify a red zone
nop it doesn't
added memory24, memory32, and start_dependent resource types and binding for get_possible_resources to zuacpi
unfortunately struggling a bit to test on account of i have memory corruption in my kernel now that i cant seem to figure out lmao
nice
Lol
But nice
@calm latch DMAR looks good, u forgot a newline tho 
you mean at the end?
Idk if you get notifications about force pushes
thanks! merged
@calm latch your pr broke msvc 😢
how?
why no msvc CI?
everything not tested should be considered broken
this is a ci screenshot

But that I've seen entries[] above it
i just didnt run it on the pr because i assumed it would work
its my fault also so its fine
why doesn't CI just run on all PRs?
why do you need to approve it?
What if someone pushes an xz style trojan
ah it's for first time contributors
whats it even complaining about?
is making the string size [1] wrong also?
If you look at acpi_dmar_drhd for example, it has struct acpi_dmar_dss entries[];, which has uacpi_u16 path[]; in it
maybe path[1] is enough to fix it
Probably
But like this whole thing is dynamic arrays of dynamic arrays of dynamic arrays
yeah i mean you will always refer to it by a pointer anyway, so i think [1] is a safe solution to make msvc shut up
i can just force push i think
just don't have a member instead of adding [1]
that's what I meant to say
force push to master 💀
sometimes u gotta do that
no?
you have to do it anyway
somewhere
just push another commit to fix lol
no reason not to, no one is using this commit anyway
But I think commenting entries out is a better soultion, since you don't have to do pointer math for names (?)
Idk
wdym?
how do you know?
All of the dmar structs, which reference struct acpi_dmar_dss
it's just stupid to force push to a public branch
oh u mean comment out the root entries array
it looks inept, it breaks downstream CI etc
what downstream ci
it should be disabled in a branch protection rule (and for example for the Managarm repos, it is)
it is disabled
I mean you have a lot of stars
i just enable it temporarily if needed
that's stupid
u said that already
i remember one that limine did a force push to master and we had to deal with downstream bullshit because of that
thats why i have release tags, i'll never force push anything that's at or before a release tag
but unstable master is unstable
tbh it should probably be dev
unstable != incompetent maintenance
If you make a mistake, you own it by pushing a fix and not by hiding the mistake
ok pls stop
i get it
yeah path is the thing it was complaining about
@calm latch is the path guaranteed to be present?
I guess this means that 1 is always present?
If the ‘Path’ field length is 2 bytes (N=1), the Device Scope Entry identifies
a ‘Root-Complex Integrated Device’. The requester-id of ‘Root-Complex
Integrated Devices’ are static and not impacted by system software bus
rebalancing actions.If the ‘Path’ field length is more than 2 bytes (N > 1), the Device Scope
Entry identifies a device behind one or more system software visible PCIPCI
bridges. Bus rebalancing actions by system software modifying bus
assignments of the device’s parent bridge impacts the bus number portion
of device’s requester-id.
ubsan will complain about that
0x01-0x05 are possible entries
about what?
[1] is a pretty common thing to use for FAMs
u sure its not smart enough for that?
The device scope is not guaranteed to be present though
The Device Scope structure contains zero or more Device Scope Entries
that identify devices in the specified segment and under the scope of this
remapping hardware unit.
The Device Scope structure is described below.
acpica doesnt seem to have this member at all
fwiw this is how we did DMAR headers in managarm https://github.com/managarm/managarm/blob/master/kernel/thor/arch/x86/vt_d.cpp
Pragmatic microkernel-based OS with fully asynchronous I/O - managarm/managarm
hm, actually seems that it doesn't complain
Yeah, this seems to be the best solution since it can't be 0
to me*
ye
I mean idk, maybe you can look at acpi dumps 
imo [1] is worse than no member at all since it complicates address computations
which computations
u never do computations with the struct since its variable length
without this member u do have to do computations tho
(u16*)(struct + 1)
which is ugly imo
not as ugly as subtracting 2 to get the size of the header when checking against buffer overflow etc
But I think this implies that it's always at least 1
well it seems like its guaranteed to be at least 1, so u can include it in the check
i'm not even sure if it's not UB
thats literally how C FAMs used to work before normal FAMs were supported
acpica has that stuff all over iirc
that doesn't mean that it's well defined lol
🤷♂️
Ah, actually ubsan does catch it
with -ffstrict-flex-arrays=2
it's only supported for legacy reasons
At the 2022 Linux Security Summit Europe (LSS EU), Gustavo A. R. Silva reported in on work he h [...]
msvc doesnt like the union
so can only do ifdef in this case
which means the behavior differs between compilers, which is kinda annoying
sizeof
it has a size field
you still might want to verify whether the size field is sane
which I'd usually do by comparing against sizeof
to guard against truncated stuff for instance
why do you need a union?
yeah as as workaround for userspace consumers that already assume [1]
which is not a concern here
my point is to just drop the flex member if there are msvc issues with it
back to square one?
or #ifdef it behind GNU
yeah but then the struct size is different between msvc and gnu
wouldnt that be annoying for client code?
why does the flex member affect the struct size?
oh u mean drop it completely for msvc
thats still annoying for client code, maybe less so i guess
or have a UACPI_FLEX_ARRAY_SUBSCRIPT in compiler.h or whatever your equivalent is
which defines to empty on gnu so you get int whatever[] and 1 on msvc so you get int whatever[1]
yeah but then expect_sizeof would have to be tuned between ifdefs no?
ah true
well you could just drop the array part completely on all platforms because you can't use subscripts anyway with variable size entries
expect_sizeof_maybe_fam 
i think the entries are 2 * N bytes, so u can use subscript
the entire problem is that the entries have a variable size path right
so you can't use subscripts to get to any entry other than the first
ye, the u16 path[] field
no its like, a struct has a list of variable length structs, one of which may be a struct that contains a variable length path
yeah
so subscripts are useless on either
you can just do struct whatever first_whatever;
it's platform independent and equally useful
at least [1] kind of implies that its an array
and im not sold on it being useless, since its an array of u16s, so why cant u use subscripts?
I thought this was about an array of variable sized structs?
it's this
ahh ok nvm then
I thought the issue was that msvc complains about variable sized arrays of variable sized structs
It is the issue
well
example
UACPI_PACKED(struct acpi_dmar_atsr {
struct acpi_dmar_entry_hdr hdr;
uacpi_u8 flags;
uacpi_u8 rsvd;
uacpi_u16 segment;
struct acpi_dmar_dss entries[];
})
UACPI_EXPECT_SIZEOF(struct acpi_dmar_atsr, 8);
Because it's an array with structs with variable arrays with more structs with variable arrays
dss is the thing that contains the u16 path[1]
are you suggesting we get rid of entries[]?
For example
Yeah
That was what I was suggesting in the beginning as well
Turn it into first_entry
But entries can be empty
[1] is apparently just UB and just not exploited because -ffstrict-flex-arrays is zero by default
But it is handy for names
Does it explode with any of the compilers?
Since everyone was doing it anyway
/app/example.cpp:8:12: runtime error: index 5 out of bounds for type 'int[1]'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /app/example.cpp:8:12
no, it only explodes if you enable ubsan + strict flex arrays
maybe this 
#ifndef UACPI_COMPILER_HATES_NESTED_FAMS
union {
u16 unused;
u16 path[];
};
#else
u16 path[1];
#endif
this allows same sizeof at least
the same wrong sizeof 
its correct tho
since that one u16 is guaranteed to be there
fwiw (u16*)(struct + 1) is also ub no?
no
since its literally an aliasing violation
no it's not
the u16 doesn't alias anything
the compiler doesnt know that
wdym
it assumes u have an array of structs
no
u cant go out of bounds of
so struct + 1 is either also struct or UB
u can only bit_cast here
no, what matters for access is the runtime type, not the compile time type
int x;
*reinterpret_cast<int *>(reinterpret_cast<float *>(reinterpret_cast<FILE *>(&x))) = 42;
is not UB
right but we arent doing that
yes, you can
we are reading struct* as u16*
So what is this saying exactly
operations such as memcpy magically create the right types without even knowing what types to create (aside from the fact that they must be "implicit lifetime" types) 
Does this apply to the type punning we were talking about before?
this is unrelated to type punning
there is no type punning going on
in C++ whenever you access an object, the runtime type must match the type of the access
the runtime type in this case is u16 and the access is through a u16 *
so that is well defined
type punning (= UB) would only happen if the runtime type was different (say, a float)
struct foo {
int x;
float y;
int z;
};
foo f;
*reinterpret_cast<int *>(reinterpret_cast<char *>(&f) + 8); // no UB
*reinterpret_cast<int *>(reinterpret_cast<char *>(&f) + 4); // UB
Where would that u16 be in that struct
Its not part of the struct if we delete it
my point is that whether *reinterpret_cast<int *>(reinterpret_cast<char *>(&f) + 8); or similar is UB or not is not determined by any static type
Right yeah that part is true
it's determined by whether the runtime type at &f + 8 bytes is int or not
I was saying that deleting a u16 field entirely and then doing u16* struct + 1 is UB
It's not
if you write it as + 1, it's problematic but you can write it as (u8*)struct + sizeof(struct)
Why not?
The runtime type of that location is u16 even if that field doesn't exist at compile time
And the runtime type is what matters
Well the compiler doesn't know that no?
Yeah but that doesn't mean it's UB
Again, the runtime type matters
You get UB when the runtime type differs from what's used to access it
But who begins the lifetime of that u16 in the type system
If the compiler doesn't know what the runtime type is that doesn't matter
The firmware
It's not "oh, the compiler doesn't know what the type of this location is, so it's UB"
It's "the compiler can assume the type of this location matches what's used to access it"
So reading a struct from disk and type punning a buffer to inspect it is also not ub then?
The ub there is the type punning part
If you didn't use type punning it'd be fine yes
struct whatever x;
read(fd, &x, sizeof(x));
type punning is using multiple runtime types
this involves no type punning
So you're suggesting a bit cast
float f; *(int *)&f = 42;
I never said that was ub tho
The ub part is treating a struct pointer as a u16 pointer
You're not treating a struct pointer as a u16 pointer though
You're treating a u16 pointer as a u16 pointer
This is UB because it involves two runtime types
You just happened to derive the u16 pointer location from a struct pointer
Can you show how you would get the u16 from that struct in a ub free way
Like the C code
(u16 *)(struct + 1)
Well even korona said its problematic
It might be different in C++, I'm talking about C
Doing ptr + x is fine as long as x <= number of objects at ptr
And if x == number of objects at ptr, you have a one-past-the-end pointer, which is still perfectly fine but might have a different runtime type
🤔
I'd have to double check if the pointer arithmetic is allowed in C++ but what's definitely allowed is doing it on u8 *
Wouldn't u need launder or placement new or smth
no
you don't need placement new because you're not creating new objects. the objects are already there
I think in C++ you have to do the arithmetic on u8 *
or using uintptr_t or similar
because doing it on the struct would imply that it's part of an array of structs (which it isn't)
ok i still cant quite properly test it but now its because afaict my qemu testing setup doesnt actually use any of these in the aml lmao
this looks so wrong in my bindings but is objectively correct lmao
wtf
the memory24 resource type only stores the upper 16 bits of all of its 24-bit numbers
whereas memory32 stores all 32 bits of its
i did a double take when i realised it lmao
zuacpi has bindings for enable/disable_host_interface in osi.h and for the pci routing table stuff in utilities.h now
the osi stuff i am using so id consider that tested
PRT isnt tested yet though because i havent fully decided how im going to handle it in my os which makes it rather difficult to use lmao
@fiery turtle if the node is known to exist is there any way for get_pci_routing_table to return .not_found other than if the method doesnt exist?
my actual hardware has PRT at higher levels than just the root complex so id want to try it on every step of swizzling upward to shortcut wherever i run into it, so i want to know if i can rely on not_found for determining if the method just doesnt exist or if i need to check it ahead of time and just only try the call afterwards
i mean that should be the only way
like i mentioned before since that calls into the interpreter which calls into kernel api i cannot really limit the error codes
so as long as u dont produce those there isnt any code that can return not_found
if you want 100% certainty you can check that it exists at that level before calling the getter
just find(node, "_PRT") != NULL
alright, thanks
PSA i just realized linux enables ACPI mode only after loading the acpi namespace: https://github.com/torvalds/linux/commit/b064a8fa77dfead647564c46ac8fc5b13bd1ab73
dont know if it actually matters really but
they initially did it for some uefi reason(?)
ah actually no nvm
acpi mode is enabled very early actually, but the interrupt handler is installed after namespace load
basically u get the same behavior that uacpi has always had

@fiery turtle regarding uacpi-rs; can the uacpi_object_assign_integer and similar functions be used on arbitrary uACPIObjects? like a object with the type Mutex?
as i am thinking about encoding the object type into the object type on the rust side do allow or disallow certain operations on the object
Yeah thats the whole idea
It can be used on any object
and changes that object if im understanding these header comments right
part of me still wishes there was a way to just attach an arbitrary pointer to a namespace node so i can use the find functions given a namepath and still get back to my kernel device object
Yes
Hmm I mean its not hard to do
Maybe behind an option
yeah
i can also guarantee in my case that the node wont be derefed as long as the pointer im giving it is "alive" in that the deinit on the object whose pointer it gets happens to literally be where i call unref on the namespace node
which reminds me i gotta go check if my acpi namespace enumerator is handling node refcounts right, i always forget if the next function adds a ref to the node it returns
oh cool, even easier then
Or rather, uacpi won't allow you to get a non permanent node via public api since its only needed for the interpreter and temp nodes
👍
ig in the name of solving problems not symptoms, the thing i want this for is one possible approach to handling pci interrupt link devices
or even if i dont give those full device objects, the thing i want is to be able to use the find by nameseg thing to get a node for the link a PRT references, and then get from that node back to some structure of my own that can handle my kernel-side management of things
managing IRQ objects for it etc
there is one other thing i need the function to find a node by nameseg reference for, which is the DBG2 handling, but im not sure when in the init process ill do that and as a result there might not be a kernel object for that yet
i will be yeah, but ill still need a way to get from node back to whatever kernel structure i use to augment them
i could, but id need a map of namespace node (probably pointer to namespace node since theyre permanent and thus dont move) to kernel object
which is O(not constant) to look up
whereas by adding exactly one usize to the namespace node i can get that in O(1)
(technically it only needs one whole byte in this case because i could make it an array index actually but besides the point)
(pointer is more sane here esp since that allows making the default value 0 and then not having to have some other mechanism to check presence)
Ig
not a huge deal though, im only doing this during init, the kernel thing that manages the source of the reference can cache the result