#uACPI - a portable and easy-to-integrate ACPI implementation
1 messages · Page 16 of 1
i will implement a magazines layer for keyronex
Same, mine varies a lot
also worth noting that this is a single-processor kernel, so spinlocks only have to disable irqs instead of having an extra atomic op. don't know if it'd make a difference but well
wow 3m even on my cpu
are you using the kvm clock?
not on this build yet but it shouldn't be too hard to add
what are you using?
right now i just ignore the invtsc bit (except for printing a simple warning)
lol 4.7mil on my machine
interesting
are you absolutely positive the timer is fine though lol
@hollow crescent you should try
the idea is that invtsc is old enough that i'm not gonna bother supporting anything that doesn't have it, but i didn't want to outright panic if the bit isn't set since you can't set it when using TCG
looking at all these reminds me that obos' performance is dogshit
tbh this is the best way to do it
i can leap up to
[uacpi]: successfully loaded 1 AML blob, 1705 ops in 0ms (avg 2620798/s)
with no spinlocking/ipl adjustment around slab allocatio
pretty sure yeah:
uint64_t threshold = read_time() + tsc_freq;
for (int i = 0;; i++) {
sched_stop(threshold); // sched_stop times out when tsc >= threshold
threshold += tsc_freq;
uint64_t cur_time = timeconv_apply(tsc2ns_conv, read_time());
printk("iter %d, %U.%9U seconds since boot\n", i, cur_time / 1000000000, cur_time % 1000000000);
}```
i doubt they are cheating
speedrunner caught cheating in uacpi any%
i can make it open source if you want lol it's nothing special yet, the only reason i haven't is that i usually like to get a bit further than this before going open
more so there is a chance they are making a mistake
i think muonkous is in the right
though i would see how it would look if it were SMP-safe
true
i do wonder how much that'd change things
so just to be clear: https://github.com/mintsuki/cynix/commit/f675511119cd39b5f4379f4b27635759b12e8d89 this is correct now, right?
wait isn't there speedrun.com or something
add uacpi there 
yeah
it should be mostly SMP-safe already, i'd just need to add spinlocks to some areas that right now only use irq guards (off the top of my head: printk, uacpi deferred work, scheduler, idt, mutex slow path, semaphore, timer events)
alright ty
oh and ioapic state is also only locked by an irq guard
but other than that everything should work fine
although the scheduler is obviously Not Optimal for an SMP kernel given that it's a global queue
lmao
namespace load any%
w/ stubs
the hard limit i can get to at the moment by simple optimisations is 2.6mil (monkuous gets 3.6mil on my system)
literal beast
try mine
i mean it's probably gonna be less than 2.5mil so don't bother actually
i can try anyway if you throw an ISO
what i think i can identify in the meantime is that the current limiting factors for me are probably:
- IPL management
- slab allocator
fadanoid could you test this please? #1217009725711847465 message
one paradox, i'm faster with freeing enabled than with no-op freeing!
testing now
how is that even possible
function segments for LTO?
maybe freeing makes the allocator less fragmented
or smth
ah
if the pattern of freeing tends to result in lots of allocs and frees being "paired" temporally
then a trip to the page allocator is avoided
I see
i'm getting 0% benefit by noping free
that's my hypothesis anyway
IDA my beloved
i haven't tested it
other possibiltiies are odd changes to code generation
different cache characteristics and such
it's a promising observation anyway
because it means that i am likely to get huge gains from introducing a magazine layer to the slab allocator
the operations that can be served from the CPU layer can be coded such to avoid the IPL management overhead by simply disabling interrupts instead
yeah, with an ida license nothing is truly closed source 
:(
for --gc-sections yeah
mostly just because i got into a habit of doing so
https://github.com/proxima-os/proxima i've polished it up a bit and published the source
turns out i did everything except for actually making the repo public, fixed now
nah, just a hobby
but you're still an SE right?
i'm only 18 lol i'm not anything
do you want to be mentioned now that its open source?
sure
took the top spot
congrats, very talented work
could you add a comment to the pr please?
less talent and more "has had a chronic case of way-too-eager-to-rewrite-stuff for years and now knows good approaches for a lot of stuff"
nice
done
very nice
so yeah i do about 4 million now
i enfattened my slab
what does that mean
made slabs larger, allowed for larger allocations through slabs, but mainly made slabs larger
thats it?
yup
lock: spin for 40 iters (cmpxchg MUTEX_UNLOCKED->MUTEX_LOCKED_NOQUEUE), disable irqs, check state again to see if it was just unlocked, set state to MUTEX_LOCKED_QUEUED, puts the task on the list of waiting tasks, stops the task
unlock: cmpxchg MUTEX_LOCKED_NOQUEUE->MUTEX_UNLOCKED, if successful early exit, disables irqs, pops the first waiting task off the list, sets state to MUTEX_LOCKED_NOQUEUE if the queue is now empty, starts the task
so u avoid work that other implementations do
yes it's fine, you don't need to include it
the fast path for mutex lock/unlock is a few nanoseconds i believe
my mutexes are no-ops, but i don't foresee them being such a major issue
in terms of knocking down the score i mean
probably, should just be a few atomic ops if not contended technically
yeah
what is you overall plan for the kernel
linux compat or just posix layer or
posix compatibility (well, mostly - the goal is to implement enough that doing the rest in userspace has 0 performance penalty)
any goals for ports?
for the os as a whole, NIH all the way to desktop, but that's a very far out goal that will likely never happen (i'm way too eager to rewrite things)
ports not sure, maybe java to run a minecraft server or something, and doom ofc
oh and i'd like to be able to do the whole self-hosting thing but that's honestly the easiest of those goals
does that mean we'll see your own ACPI subsystem 
i did test
1.1mil or so
[00:00:00.011864] [info] uacpi: successfully loaded 1 AML blob, 1705 ops in 1ms (avg 1125196/s)
maybe eventually, for now i decided to treat it the same as the bootloader (i eventually want to add a custom implementation of the limine boot protocol too)
makes sense
the big future gains for me will be whenever i add a magazines frontend to the slab allocator
that's something i'd want primarily for SMP to decontend the allocator, but it should help here too
honestly I probably need to revisit my mutexes and actually make a proper implementation
this is replacing it with a spinlock_acqurie and spinlock_release
funny how my processor is like the oldest there
get qwinci to run your stuff
when I finally optimize obos I can make a pr to change that value, right
yeah ofc
nah it's fine
I am waiting for the submission to put obos in the 3rd last position 
but seriously I gotta optimize that
wanted to try it on my machine, is there a step missing from the build instructions in the readme?
you're on master right?
yeah
ah
yeah btw your cmake is bogus, idk why you're calling that command
its a uacpi-internal cmake function to add sources lol
lmao
..huh
wut the hell
can't u just send over an iso?
I can
that'd work yeah
Signed-off-by: Daniil Tatianin [email protected]
that commit exists
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
wait infy
did u checkout a wip-pr?
wtf
lol
idk maybe
I indeed did
was testing something out for you
yeah
alright i merged the leaderboard for now, will update as people optimize their stuff further
damn it infy
as soon as I change obos to use master's commit
and am about to commit the change
you do that
That shouldn't change your numbers lol
ik
it's just a minor inconvinence
@gentle peak I fixed it
git pull && rm dependencies/needs_download.cmake
one second, gotta install docker so that i don't clog up my path with x86_64-elf-*
you do you
Just send over the damn ISO lol
alright ty
Inb4 5 mil
yes 100%
38761/s
465911/s
Not bad
yeah because it uses a bump allocator and sets the irql to dispatch during uacpi init
otherwise it would be the same old
obos
Find every string that says proxima and replace with obos
and that will hopefully boost perf
i'm pretty sure the kernel image actually doesn't have the string 'proxima' at all
since the kernel itself is called hydrogen
Fuck
and also optimize my memory mapping
I feel like that could be made faster
what happens if I take two of them and push them together with a lot of force
explosion
memory mapping is bottlenecked by the allocator, and the allocator is probably bottlenecked by the memory mapping
or well
Uranium kernel when
not explosion on our scale
I have an idea
release of a significant amount of energy relative to the energy of the resulting helium nucleus
how about that
if nyaux ever surpasses me in perf
I will rewrite obos /j
Lmao
oh god if i did that i'd be somewhere around vanadium right now
Now thats a based kernel name
my biggest trouble is my slow ass mutex
36.6k loc down the drain because of one silly kernel
which is why I am looking into getting a real lock
I have 7x more code than comments
cant believe I'm trying this hard to optimise for a fucking fake number on a table
probably not that different from my corporate job
or a 1831:261 ratio
Still the only hobby os that can build gcc
Lmao
tbf considering the main performance impact comes from allocator/string funcs any improvement here will probably result in noticeable performance improvement kernel-wide
once I rewrite my scheduler I will use it as a stress test
Good idea
Very true yeah
my og stress test was neofetch, then running configure
Lol
how is neofetch a stress test?
Neofetch stress test
what does it do that's so stressful
Exists
my kernel was so buggy it didnt handle opening a lot of processes like neofetch does
trust, obos definitely won't die when you blow on it as soon as I get userspace
(my manhood has been challenged
(((unless you don't count the kernel as a process)))
Stability first then speed is the right approach
((((then only one process has ever ran in obos))))
Port doom
good idea
who's doing the benchmarking now?
monkuous
Monkuous is our leader now
havent tried, but I dont see why Ironclad wouldnt be able to
Configure scripts
it configures fine itself, I can configure ironclad inside ironclad
Oh nice
Then you might be able to as well
But your os is not hobby
You get paid for it
you should do it I wanna see the funny seal do things
is this what it feels to be denied hobbyhood
Yup
I feel empty
Youre a corporation now
when will ironclad run on airplanes?
considering it uses ada
@strong heath hire me I will accept very low pay and write ada
should be pretty safe
I wish a foundating didnt need 30k starting capital to be funded, else I might have had an ironclad fundation
just ahve to learn it fist
Lmao
True
I cannot hire anyone without a legal organization
Hire nyaux as well
ironclad stability 📉
hire with an illegal organization
fair enough
Lmao
somehow nyaux managed to make something less stable than obos
true
(obos' fourth rewrite, the worst one)
And hydrogen
((I should remove it from existance, it was terrible))
It was gonna be closed source
Lmao
the proxima one?
imagine calling an OS after the lightest element
Yeah
real
if you are gonna name an OS, name it after lead
it seems a reasonable name when you put it that way
floats like a butterfly, stings like a bee
^
I should name my os after alexander fleming
Aml is scared of this os
does it exterminate bacteria?
yes
I named obos because well
I like astrals theme

best human invention: cheese
Oberrow os
but yeah, I know how I can (probably) improve astral's ops/sec by 20%-50%
I know obos lore
now into the grind

the stone age of obos: first and second rewrite
iron age: third rewrite
middle ages: fourth rewrite
modern time: current rewrite
future: next rewrite??
Pls no
jk
crazy how this obos rewrite started -1 days ago
(/j)
-1 days ago means
in one day 
in 3 rewrites you will do it in astral because it will already be the year of the astral desktop
2029 will be the year of the obos desktop
yes.
my christmas break starts next week
so I can rather go outside
or smth
or work on obos
what should I try?
But do you completely change the goal and design of the kernel each time you rewrite :^)
the latency of rep movsb is still pretty high (at least on some CPUs), so you should only do that for large regions
that's slow, even my CPU gets 1.5 mil
what flags for qemu?
no 2029 is the year of the nyaux desktop
2024 was the year of getting managarm desktop somewhat daily drivable
2025 will be the year of the managarm desktop
1000000000 % confirmed
should i pin this
kmanagarm with plasma 6 in 2025
Managarm will replace windows
/*
* Safely mask the event before we modify its handlers.
*
* This makes sure we can't get an IRQ in the middle of modifying this
* event's structures.
*/
static uacpi_bool gpe_mask_safe(struct gp_event *event)
{
uacpi_u8 this_mask;
uacpi_bool was_masked;
this_mask = gpe_get_mask(event);
// No need to flush or do anything if it's not currently enabled
if (!(event->reg->current_mask & this_mask))
return UACPI_FALSE;
if (gpe_masked(event)) {
/*
* This GPE is masked, but there still might be pending work involving
* its handlers. Wait in case it was masked very recently.
*/
uacpi_kernel_wait_for_work_completion();
return UACPI_FALSE;
}
// 1. Mask the GPE, this makes sure its state is no longer modifyable
gpe_mask_unmask(event, UACPI_TRUE);
/*
* 2. Wait for in-flight work & IRQs to finish, these might already
* be past the respective "if (masked)" check and therefore may
* try to re-enable a masked GPE.
*/
uacpi_kernel_wait_for_work_completion();
/*
* 3. Now that this GPE's state is unmodifyable and we know that currently
* in-flight IRQs will see the masked state, we can safely disable this
* event knowing it won't be re-enabled by a racing IRQ.
*/
set_gpe_state(event, GPE_STATE_DISABLED);
/*
* 4. Wait for the last possible IRQ to finish, now that this event is
* disabled.
*/
uacpi_kernel_wait_for_work_completion();
return UACPI_TRUE;
}
Mental gymnastics to make GPE modification thread-safe
/*
* Waits for two types of work to finish:
* 1. All in-flight interrupts installed via uacpi_kernel_install_interrupt_handler
* 2. All work scheduled via uacpi_kernel_schedule_work
*
* Note that the waits must be done in this order specifically.
*/
uacpi_status uacpi_kernel_wait_for_work_completion(void);
And this is what is now expected from wait_for_work_completion
linux already does this for acpica as well:
void acpi_os_wait_events_complete(void)
{
/*
* Make sure the GPE handler or the fixed event handler is not used
* on another CPU after removal.
*/
if (acpi_sci_irq_valid())
synchronize_hardirq(acpi_sci_irq);
flush_workqueue(kacpid_wq);
flush_workqueue(kacpi_notify_wq);
}
although it doesnt bother masking it because they dont care i guess
Doing the uacpi benchmark thing
we have this leaderboard now: https://github.com/UltraOS/uACPI?tab=readme-ov-file#notable-projects-using-uacpi--performance-leaderboards
I don't even have userspace why would you want me to port uACPI
Basically we have this to compare kernels' speeds
Using a new log added to uacpi
Also I don't see how uacpi and userspace go together
They don't, I just have a set of priorities
First, finish the userspace memory manager, then start userspace
Then worry about other things like uACPI
Although a lot of things that are requisites of user space, are also not done
if u only want table parsing then uacpi doesnt need anything besides map/unmap
so technically doesnt matter
practically there are bigger fish to fry
the fact I'm not frying any of them is part 2
i will integrate it first thing so that i dont have to duplicate table parsing for stuff like hpet or madt
does the benchmark requires uacpi to run in kernelspace or can it run in userspace?
i mean you're putting yourself at a disadvantage
and pmos already runs it in userspace
so no doesnt matter at all
wow I also get less points with no free()
you laugh but large parts of KDE6 are already ported
I was 70% serious tbh
Managram in mainline clang when
What do you do without swap though
Hm?
wat
Alright the final uACPI thread safety (part 3) PR is basically done, waiting for CI and merging

Big
This means that uACPI is basically ready for 1.0, although I still wanted to add support for exotic opregions before declaring it
release 1.0 and then immediately api break with uapi 
Merged & issue closed
I will push to implement support for exotic opregions in the coming days and release uACPI 1.0
that shouldnt be too hard I think
that should put me mostly at feature parity with acpica
what opregions do you want to support?
im guessing all of them
UACPI_ADDRESS_SPACE_SMBUS = 4,
UACPI_ADDRESS_SPACE_IPMI = 7,
UACPI_ADDRESS_SPACE_GENERAL_PURPOSE_IO = 8,
UACPI_ADDRESS_SPACE_GENERIC_SERIAL_BUS = 9,
UACPI_ADDRESS_SPACE_PCC = 0x0A,
UACPI_ADDRESS_SPACE_PRM = 0x0B,
UACPI_ADDRESS_SPACE_FFIXEDHW = 0x7F,
all of these require special handling
i assume they also require special os support?
yeah, via uacpi_install_address_space_handler
no hobby os with such drivers yet
but still important to get these done
linux does support all of them
basically all of these are similar to EC
What's generic serial? Com ports?
its used by surface3_power.c lol
status = acpi_install_address_space_handler(adev->handle,
ACPI_ADR_SPACE_GSBUS,
&mshw0011_space_handler,
NULL,
data);
if (ACPI_FAILURE(status)) {
dev_err(&client->dev, "Error installing i2c space handler\n");
acpi_bus_detach_private_data(adev->handle);
kfree(data);
return -ENOMEM;
}
yeah thats the only user in the entire kernel
OperationRegion (OR01, GenericSerialBus, Zero, 0x0100)
Field (OR01, BufferAcc, NoLock, Preserve)
{
Connection (I2Z0),
AccessAs (BufferAcc, AttribRawProcessBytes (0x02)),
SAN0, 8
}
/*
* _REG methods for global address space handlers (installed to root)
* get called during the namespace initialization, no reason
* to call them here manually as that will be done later by init code
* anyway. Just delay that work until later.
*/
if (device_node == uacpi_namespace_root() &&
g_uacpi_rt_ctx.init_level == UACPI_INIT_LEVEL_NAMESPACE_LOADED)
goto out;
Least dumb uACPI code
I think this breaks early EC registration
in theory
i wonder if i should get rid of uacpi_kernel_raw_* helpers
and just map io/mem manually
the idea there was that the kernel can keep a cache like linux
but i think its just annoying to have 9999 extra helpers
to implement in the kernel
so like uacpi_gas_read currently does this:
if (gas->address_space_id == UACPI_ADDRESS_SPACE_SYSTEM_IO) {
ret = uacpi_kernel_raw_io_read(
address, access_byte_width, &data
);
} else {
ret = uacpi_kernel_raw_memory_read(
address, access_byte_width, &data
);
}
if i get rid of raw stuff it will call map, read, unmap
there's already a precedent for this anyway since i handle SystemMemory opregions myself and not via kernel raw_read/write
You can make it optional (?)
im tired of introducing entropy for no reason
pls vote
this
less shit to implement = better
if these are removed uacpi will instead do map(), io_read/write, unmap() and for memory it will do the IO itself completely
I initially stole the raw* helpers idea from ACPICA but now i think it just sucks
ok looks like people hate the raw api anyway lmao
but ill wait for the vote to finish
this makes me wonder, what caching requirements do opregions have
it can either be mmio or just ram (e.g. nvs)
and on arm etc it matters since there arent mtrrs to set it for you
i believe the intended way to determine caching mode is to check the memory map, but on x86 at least it's fine to rely on mtrrs
^
how does it help? acpi reclaimable & nvs => normal ram, reserved,not in mmap => device memory?
yeah basically
feels a bit iffy since reserved does not imply !ram (to me at least)
but if thats the intended way then so be it
there aren't really better options, i don't think aml specifies the caching mode so it's not like uacpi can tell you how to map it
map + write + unmap is slow af
It's probably two orders of magnitude slower than a raw write
Especially for proper SMP OSes that implement TLB shootdown
unmap requires an IPI to all CPUs and blocking for the other cpus to react
No, a raw write can use a direct mapping
you can use direct mapping with the map fn too
If you get rid of the helpers, you could keep the cache in uacpi such that you only ever map once
Not necessarily
well not on all platforms but with like x86_64 or whatever
A direct mapping for raw writes must be contiguous at the granularity of the largest possible write
which is 8 in practice
Mapping via direct map must be contiguous at an arbitrary granularity
Well on ARM you can map as nGnEnR
i don't like it either
not one bit
but since linux is doing it i assume it's the only way
And on rv the memory controller is supposed to handle cacheability transparently
what does that mean
kernel_map will be called with the size of the write
so i dont see any difference in this case
I guess you could distinguish between single page and multi page mappings, that's true
Then it's not that bad
does uacpi unmap the io even if it needs it in the future again or will it only unmap if it doesnt need it anymore?
it can't really know whether it needs it in the future
what it does rn afaik for eg. op regions is mapping it once
good enough
did i see right that you were building linux with uacpi yesterday? or am i tripping
i saw some messages with linker error that referenced uacpi and vmlinuz.o 
i was wondering how that went/how it's going
on opregion destruction, or in case of FADT register writes, right away
in case im misunderstanding, is there any realistic thing for the map/unmap io functions to do on x86? id assumed they were mostly there for mmio on other architectures etc
yeah, for microkernels to request io permissions from the kernel
ahhh ok
@@ -564,13 +581,30 @@ uacpi_status uacpi_gas_write(const struct acpi_gas *gas, uacpi_u64 in_value)
uacpi_u64 address = gas->address + (index * access_byte_width);
if (gas->address_space_id == UACPI_ADDRESS_SPACE_SYSTEM_IO) {
- ret = uacpi_kernel_raw_io_write(
- address, access_byte_width, data
- );
+ uacpi_handle handle;
+
+ ret = uacpi_kernel_io_map(address, access_byte_width, &handle);
+ if (uacpi_unlikely_error(ret))
+ return ret;
+
+ ret = uacpi_kernel_io_write(handle, 0, access_byte_width, data);
+ uacpi_kernel_io_unmap(handle);
} else {
- ret = uacpi_kernel_raw_memory_write(
- address, access_byte_width, data
- );
+ void *virt;
+
+ virt = uacpi_kernel_map(address, access_byte_width);
+ if (uacpi_unlikely(virt == UACPI_NULL))
+ return UACPI_STATUS_MAPPING_FAILED;
+
+ ret = uacpi_system_memory_write(virt, access_byte_width, data);
+ uacpi_kernel_unmap(virt, access_bit_width);
}
Now that raw helpers are gone, uacpi_gas_write is going to look like this
kinda bulky but at least its less stuff for kernel to implement
actually I just made an abstraction around io r/w
uacpi_status uacpi_system_io_read(
uacpi_io_addr address, uacpi_u8 width, uacpi_u64 *out
);
uacpi_status uacpi_system_io_write(
uacpi_io_addr address, uacpi_u8 width, uacpi_u64 in
);
Maybe I could implement a transparent LRU cache around it if the need arises
(this is internal api)
that's 4 less kernel_api functions to implement
I think that's pretty good
yes 
switch to mamogram
ASSERT FAILED

made some small opts and i'm now on 1.5 mil in the benchmark
Nice, but did you fix the stack corruption
Yeah idk, id printf the shit out of it
#1287456798407790684 message
maybe i can clear the TSS?
not sure if that does anything
The Gnu debugger of course
Kvm is debuggable under gdb tho
hbreak
i keep forgetting
you were correct
Why didnt it break on tcg
tcg doesn't check some stuff
^
there should be something like -accel tcg,fortify=on or something
thats slow but actually checks stuff
should be => I want that feature
i worder that poorly
Add it 
@fiery turtle 😢
yes
i have whatever ubuntu 20 ships with
damn
build from source 
oh damn why does -smp tank so much performance on the uacpi bench
woe
okay new record is 1.5mil
it's bottlenecked by the not fair scheduler and slab of shit
can u copy paste all warnings and send a pastebin or something
i did already
hm?
.
thx
I literally have a comment right above it lmao
this is literally what gcc is complaning about
oh well
welp
nice, its forcing me to zero a 64-byte struct
= {0} 
I think there was an attribute for this?
ill think of a solution
The other option is to init to 0 on error just to shut GCC up, while not impacting performance too much because it's unlikely to happen.
There's already a return on error above it in the switch, but apparently thats not enough
@fiery turtle is it normal to get a shit ton of warnings on real hw?
something about a scope not found
Do you implement all kernel api?
no
How does windows treat the scope not found and alike?
I think skips as well but id have to double check
I might have to pre-map all IO registers from FADT
otherwise i leak a mapping if it shuts down or suspends too fast
which is probably a good idea anyway
Lmao
or option 2
remove io mapping abstractions entirely
because so far everyone just stubs them out anyway
since im doing kernel_api simplifications anyway..
ill make a poll
#polls message
yeah
Even if stubbed I think it's still the correct and most versatile abstraction
thing is
Could also make it optional
u can still keep a cache internally and map if needed, like for the raw helper before
thing is this abstraction adds a ton of extra complexity
Even tho for io it probably doesn't matter
i cant make it optional and not leak at the same time for example
or I can but its not trivial
idk
Tbh
Because of how acpi is
It's probably fine to keep the mapping forever
Even tho 32bit might not like it
Ooooo
Yeah for port io it probably doesn't matter
Or well, like you said 32bit arm
Hmmmm
then again i think SystemIO is used only on x86 even though technically they could use it for arm
Yeah for io I think lazy mapping for whoever needs it is enough
And for the once in a blue moon it happens on arm they can handle it
mmio?
inb/outb etc
SystemMemory includes MMIO
^
SystemIO is purely io ports
On arm/riscv they will be memory mapped too because no instructions
ACPICA has a check for SystemIO like > 0xFFFF die() or something
so its probably not used for arm
Other than very legacy devices it's not really needed
yeah
Like, sure alot of devices have port io for simpler reg access, but no one actually is going to access them like that since you have a full address space anyways
It's mostly meant for legacy bioses running real mode and don't want unreal mode
true
acpi_status acpi_os_read_port(acpi_io_address port, u32 *value, u32 width)
{
u32 dummy;
if (!IS_ENABLED(CONFIG_HAS_IOPORT)) {
/*
* set all-1 result as if reading from non-existing
* I/O port
*/
*value = GENMASK(width, 0);
return AE_NOT_IMPLEMENTED;
}
if (value)
*value = 0;
else
value = &dummy;
if (width <= 8) {
*value = inb(port);
} else if (width <= 16) {
*value = inw(port);
} else if (width <= 32) {
*value = inl(port);
} else {
pr_debug("%s: Access width %d not supported\n", __func__, width);
return AE_BAD_PARAMETER;
}
return AE_OK;
}
<= there is weird
acpica passes misaligned bit count unlike uacpi
uacpi aligns up to byte count to make it less confusing
but whats funny is aarch64 selects CONFIG_HAS_IOPORT 
imo the pio map/unmap should stay, they're helpful for microkernels that use iopb and for monolithic ones and microkernels that use iopl you can just cast the base address to a pointer and back
Yeah but you can also iopb on demand
we have pmos as an example and it just toggles the IOPL bit 
also this
or if you're lazy u can map() do_io() unmap()
that's true
true actually
yeah thats actually a smart thought
because the firmware might write to any io port
u dont know which one does what
Like, Linux only has a tiny blacklist iirc
CMOS, PCI and some others
the blacklist is actually built into acpica
oh
and I think windows also has a blacklist for ports
Does windows have a blacklist?
ill have to implement that in uacpi as well probably
ye
/*
* Protected I/O ports. Some ports are always illegal, and some are
* conditionally illegal. This table must remain ordered by port address.
*
* The table is used to implement the Microsoft port access rules that
* first appeared in Windows XP. Some ports are always illegal, and some
* ports are only illegal if the BIOS calls _OSI with nothing newer than
* the specific _OSI strings.
*
* This provides ACPICA with the desired port protections and
* Microsoft compatibility.
*
* Description of port entries:
* DMA: DMA controller
* PIC0: Programmable Interrupt Controller (8259A)
* PIT1: System Timer 1
* PIT2: System Timer 2 failsafe
* RTC: Real-time clock
* CMOS: Extended CMOS
* DMA1: DMA 1 page registers
* DMA1L: DMA 1 Ch 0 low page
* DMA2: DMA 2 page registers
* DMA2L: DMA 2 low page refresh
* ARBC: Arbitration control
* SETUP: Reserved system board setup
* POS: POS channel select
* PIC1: Cascaded PIC
* IDMA: ISA DMA
* ELCR: PIC edge/level registers
* PCI: PCI configuration space
*/
static const ACPI_PORT_INFO AcpiProtectedPorts[] =
{
{"DMA", 0x0000, 0x000F, ACPI_OSI_WIN_XP},
{"PIC0", 0x0020, 0x0021, ACPI_ALWAYS_ILLEGAL},
{"PIT1", 0x0040, 0x0043, ACPI_OSI_WIN_XP},
{"PIT2", 0x0048, 0x004B, ACPI_OSI_WIN_XP},
{"RTC", 0x0070, 0x0071, ACPI_OSI_WIN_XP},
{"CMOS", 0x0074, 0x0076, ACPI_OSI_WIN_XP},
{"DMA1", 0x0081, 0x0083, ACPI_OSI_WIN_XP},
{"DMA1L", 0x0087, 0x0087, ACPI_OSI_WIN_XP},
{"DMA2", 0x0089, 0x008B, ACPI_OSI_WIN_XP},
{"DMA2L", 0x008F, 0x008F, ACPI_OSI_WIN_XP},
{"ARBC", 0x0090, 0x0091, ACPI_OSI_WIN_XP},
{"SETUP", 0x0093, 0x0094, ACPI_OSI_WIN_XP},
{"POS", 0x0096, 0x0097, ACPI_OSI_WIN_XP},
{"PIC1", 0x00A0, 0x00A1, ACPI_ALWAYS_ILLEGAL},
{"IDMA", 0x00C0, 0x00DF, ACPI_OSI_WIN_XP},
{"ELCR", 0x04D0, 0x04D1, ACPI_ALWAYS_ILLEGAL},
{"PCI", 0x0CF8, 0x0CFF, ACPI_OSI_WIN_XP}
};
I mean, tbh it's mostly superficial and to discourage bugs
PCI is technically legal even
Damn
u just have to _OSI("Windows XP")
Lol
thats kinda strange but okay i guess
earlier versions of aml might do nasty stuff ig?
I wonder if windows does the same
it says so in the comment above at least
Yeah but is windows doing the same check or is just that winxp didn't check
The table is used to implement the Microsoft port access rules that
first appeared in Windows XP
Ig?
Hmmmm
/* Port illegality may depend on the _OSI calls made by the BIOS */
if (PortInfo->OsiDependency == ACPI_ALWAYS_ILLEGAL ||
AcpiGbl_OsiData == PortInfo->OsiDependency)
{
ACPI_DEBUG_PRINT ((ACPI_DB_VALUES,
"Denied AML access to port 0x%8.8X%8.8X/%X (%s 0x%.4X-0x%.4X)\n",
ACPI_FORMAT_UINT64 (Address), ByteWidth, PortInfo->Name,
PortInfo->Start, PortInfo->End));
return_ACPI_STATUS (AE_AML_ILLEGAL_ADDRESS);
}
this check looks bogus as well
AcpiGbl_OsiData == PortInfo->OsiDependency since its an ==
esentially if latest_requested_win ==
so disallowed for XP
but allowed for e.g. windows vista?
how does this make sense
@gentle peak btw did we convince you to vote for option 1 instead?
you can change your vote?
anyway yeah I didn't think it through fully, didn't realize you'd need the equivalent of iopl3 even in microkernels
nice
actually im not sure how u could even run it in userspace and support suspend for example
like it wakes up in real mode
then you have to do full hw re-init
or i guess u would have to split responsibilities somehow
idk
Alright time to implement support for these
UACPI_ADDRESS_SPACE_SMBUS = 4,
UACPI_ADDRESS_SPACE_SYSTEM_CMOS = 5,
UACPI_ADDRESS_SPACE_PCI_BAR_TARGET = 6,
UACPI_ADDRESS_SPACE_IPMI = 7,
UACPI_ADDRESS_SPACE_GENERAL_PURPOSE_IO = 8,
UACPI_ADDRESS_SPACE_GENERIC_SERIAL_BUS = 9,
UACPI_ADDRESS_SPACE_PCC = 0x0A,
UACPI_ADDRESS_SPACE_PRM = 0x0B,
UACPI_ADDRESS_SPACE_FFIXEDHW = 0x7F,
i'll start with PCC
it should be simple
each opregion represents a buffer, writes copy into it, reads copy from it, write at a specific offset invokes the user handler
what the fuck is a pcc
Elixir Cross Referencer - source code of Linux v6.12.6: drivers/acpi/acpi_pcc.c
* The PCC Address Space also referred as PCC Operation Region pertains to the
* region of PCC subspace that succeeds the PCC signature. The PCC Operation
* Region works in conjunction with the PCC Table(Platform Communications
* Channel Table). PCC subspaces that are marked for use as PCC Operation
* Regions must not be used as PCC subspaces for the standard ACPI features
* such as CPPC, RASF, PDTT and MPST. These standard features must always use
* the PCC Table instead.
*
* This driver sets up the PCC Address Space and installs an handler to enable
* handling of PCC OpRegion in the firmware.
idk
PCC is PCC what don't you understand
Do a lot of PCs use it?
judging by the fact it wasn't an immediate priority for uacpi, my guess would be no
I mean GPIO spec says it's for reduced hardware platforms, and it turned out that new laptops wire power buttons through them
Btw, I think the macbook is doing some stuff with AHCI controller when turning off
I recently noticed that if I force shutdown my PC using the power button some of the LEDs stay on, while with normal acpi shutdown they get turned off
Idk, but my AHCI driver gets a bunch of interrupts when it turns off
possible
L firmware i guess
Can ACPI write to GPIO?
yes
Fun fact, it used to be that acpi shutdown from windows also left the LEDs on, but after a bios update it was fixed :^)
lol
GPIO doesn't have to be done from the GPIO address space, it might be accessed by acpi using the pch directly
I can try implementing that in my driver then
that's what I seen a lot of server hardware do at least, accessing random GPIO regs in the pch when doing stuff
yeah
thats what they do for SMBus
yet they dont do it for EC for whatever reason
even though there's an SMBUS address space opregion
(technically supported)
Could they be doing that if there's no driver?
I think it's just that they use the EC driver from one of their drivers while not needing the smbus for one of their drivers
Or they just race :^)
yeah
some firmware drops into SMM if EC is not available
and reads EC via that
is it?
I think so, the Intel smbus controlled changed between chipsets
Same for the Intel GPIO controller
Especially with some of the Intel socs
L
Where they also have GPIO/smbus as a feature for the board
Some even have uart dma :^)
bruh
switch (region->space) {
case UACPI_ADDRESS_SPACE_PCC: {
uacpi_u8 *cursor;
cursor = region->internal_buffer + offset;
/*
* Reads from PCC just return the current contents of the internal
* buffer.
*/
if (op == UACPI_REGION_OP_READ) {
uacpi_memcpy(in_out, cursor, byte_width);
goto out;
}
uacpi_memcpy(cursor, in_out, byte_width);
// Dispatch a PCC send command if this was a write to the command field
if (offset >= 12 && offset < 16) {
uacpi_region_pcc_send_data data = {
.region_context = region->user_context,
.handler_context = handler->user_context,
.buffer = region->internal_buffer,
.length = region->length,
};
op = UACPI_REGION_OP_PCC_SEND;
uacpi_namespace_write_unlock();
ret = handler->callback(op, &data);
uacpi_namespace_write_lock();
}
break;
}
default: {
uacpi_region_rw_data data = {
.region_context = region->user_context,
.handler_context = handler->user_context,
.byte_width = byte_width,
.offset = offset,
};
if (op == UACPI_REGION_OP_WRITE) {
data.value = *in_out;
uacpi_trace_region_io(
region_node, space, op, abs_offset,
byte_width, *in_out
);
}
uacpi_namespace_write_unlock();
ret = handler->callback(op, &data);
uacpi_namespace_write_lock();
if (uacpi_unlikely_error(ret))
break;
if (op == UACPI_REGION_OP_READ) {
*in_out = data.value;
uacpi_trace_region_io(
region_node, space, op, data.offset,
byte_width, data.value
);
}
break;
}
}
Alright I guess this is the framework of how I will be adding support for other address spaces
the only thing that worries me is I think GCC would allocate all stack space needed for all switch cases in debug mode
causing a larger stack usage
which is annoying
Especially if it's constant size and not in a loop
yup
Infy your uacpi api isn't liked by the rust chat
#592856094527848449 message
here we go with the vtable stuff again
not biased opinion at all
look ill add vtable mode some time in the future
The current api is fine I just had some trouble with the rust-rust interface
#592856094527848449 message
you mean it's not liked by one person

I would have used the linker for rust-rust too but extern rust isn't exactly stable, apparently even when just using a crate from crates.io
thats not how the rust mind works 
imo maintaining two apis is unnecessary for basically no added benefit
either we only do vtables or only linker
i agree but as long as it's easy to make it work with uacpi and some people benefit from it, wahtever
and as long as its optional ofc
hm
ill just make something like #define uacpi_kernel_alloc(size) g_kapi->alloc(size)
okay
do we even want a vtable mode for uapi?
i don't mind
okay period. can we just summarize in one message what the upsides and downsides are for both approaches. i hate having to scroll between 5 discussions
u can summarize in udrm for now sure
i personally prefer the way it currently works because it allows LTO to inline kernel APIs
same
i didnt want to pay any perf price just because i decided to make a generic library
the main argument I've seen in favor of vtables is that it allows you to easily swap implementations depending on what's available, but I don't see why you couldn't just do that yourself in the kernel api impls
what's stopping the rusties from just having a c shim (which is actually the kernel api) that calls into their rust vtables
or smth
yeah exactly
yup
that kinda thing is a bit more annoying due to rust's whole "static mut is unsafe" thing but I'm pretty sure it has atomic pointers
fuck, implementing support for GPIO and other crap will be difficult
since they change the meaning of every field
bit offset is now the pin number, length doesnt matter whatsoever, Connection attribute resets pin offset
why couldnt they invent a different mechanism for this...
OperationRegion (GPOP, GeneralPurposeIo, Zero, 0x0C)
Field (GPOP, ByteAcc, NoLock, Preserve)
{
Connection (
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
"\\_SB.GPO0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0035
}
),
BTD3, 1,
Connection (
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
"\\_SB.GPO0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x003A
}
),
SUSB, 1,
Connection (
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
"\\_SB.GPO0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x003B
}
),
SHD3, 1,
Connection (
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
"\\_SB.GPO0", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x003C
}
),
TCD3, 1
}
}
Example
Desktop/Dell/G5/G5 5090/67C667DAE80A
Desktop/Dell/XPS/XPS 8940/9B79A7439313
Mini Pc/AMI/Aptio/Aptio CRB/259F9FDD46E2
Notebook/Aava Mobile Oy/INARI8/INARI8-LTBN-1/A658B5B6E0CB
Notebook/BBEN/z/z10/65E372FCAFD3
Notebook/Fujitsu/LIFEBOOK/LIFEBOOK U938/71F4D08280F4
Notebook/Hewlett-Packard/Pavilion/Pavilion x2 Detachable/5850EA215153
Notebook/ilife/S/S806/7AF027A015B2
Notebook/Insyde/BayTrail/BayTrail/9F287627613B
Notebook/Lenovo/Flex/Flex 2-15/8F84E14F5157
Notebook/Lenovo/IdeaPad/IdeaPad 100S-11IBY 80R2/EE707040AC1A
Notebook/Others/Others/Others/A2330B5932DB
Tablet/Hewlett-Packard/Pavilion/Pavilion x2 Detachable/3FE302D11C0A
Tablet/Lenovo/MIIX/MIIX 3-1030 80HV/04FF5A51E4B0
Tablet/Microsoft/Surface/Surface Laptop 3/4E426AB8062D
Tablet/Microsoft/Surface/Surface Pro/773032238BB5
Tablet/Microsoft/Surface/Surface Pro 3/074C5C2E091B
quite a lot of users of this crap too
others/others/others
the acpi spec really wants to delay 1.0 as far as possible 
Does my laptop have this?
now I have to carefully port the collection of ACPICA hacks to make this work in a clean way
lets see
That's boring
get one of those laptops
I'm sad my spectre x360 died
why?
It's probably interesting
yeah
My sister had dell xps
But she lives on a different continent now...
unlucky
I have stuff like this ```
Method (_CRS, 0, NotSerialized) // _CRS: Current Resource Settings
{
Name (RBUF, ResourceTemplate ()
{
I2cSerialBusV2 (0x0014, ControllerInitiated, 0x00061A80,
AddressingMode7Bit, "\_SB.I2CB",
0x00, ResourceConsumer, , Exclusive,
)
GpioInt (Level, ActiveLow, Exclusive, PullUp, 0x0000,
"\SB.GPIO", 0x00, ResourceConsumer, ,
)
{ // Pin list
0x0005
}
})
Return (RBUF) /* _SB.I2CB.TPNL._CRS.RBUF */
}
Maybe I want to write i2c driver...
yeah
vtables are slightly easier if ops are optional
Does uacpi have any optional bindings?
You are supposed to just stub and return not implemented error
nope
Tbh linker gives the most flexibility, and it's like a 20 line file to make a vtable shim
well if u count "can gracefully handle lack of" an optional binding then yes
yeah
it would be unsafe either way
because the vtable would contain extern "C" fn()s
good point
the binding difficulty is pretty much the same for zig with either vtable or linker so I'm not impacted by that debate at least
maybe a bit less work to make linker bindings but not easier per se just less typing
just wish I could propogate error returns from callbacks but that's whatever tbh
what would need to be done to allow that
it's zig abi
so i guess you would need to allow for custom return types for the kernel api functions
but i don't think you can pass error unions across C boundary anyway
you couldn't on may 10 and i don't think it's gonna change any time soon https://stackoverflow.com/a/78459524
best you can do is wrap the actual implementation in a function returning an error union and then c export fn uacpi_some_kernel_api(...) uacpi_status { some_kernel_api_wrapped(...) catch |e| return error_to_uacpi_status(e); return UACPI_STATUS_SUCCESS; // or whatever it is }
or just catch return UACPI_SOME_ERROR; instead of trying in the actual kernel api
what ive got rn is functions that convert between a zig error set and the uacpi_status enum and i use the user context pointer to store the actual zig error
and then whatever calls the extern function can detect that error being in the context later and return it instead of the default InternalError i use
also in this case youd be able to use the int-error conversion because while the numeric mapping of zig errors isnt guaranteed across recompiles its guaranteed within the same zig compilation unit and everything is statically linked here
the biggest issue is not being able to make error return traces marshal through but theres nothing that can be done about that given how those are implemented in zig
for reference, every zig function that returns an error takes a secret extra parameter that is an optional pointer to the stack trace which it then uses a builtin function to add its address to whenever it calls an error-returning function or returns an error directly
and the size of the buffer used for the traces there is determined either by just giving it a default or by static analysis
but afaik you cant (or shouldnt) overwrite the pointer to marshal it across so i dont think i can marshal it properly
what ive currently got is just a wrapper around a callback type that wraps the user context pointer in another struct that contains an optional error and the first pointer and then pass that around and use some other wrapper code. it works but its ugly af
(it returns iteration decision break for iteration callbacks instead of internal error for status-returning callbacks)
i even found a zig compiler bug in that process lmao
but yeah no zig error returns are part of zig's own ABI and cant be done directly through C, and zig's ABI is not meant to work across link-boundaries because zig libraries are meant to be distributed as source and included directly rather than as libraries to be linked
@hasty plinth could u elaborate a bit on your poll vote
getting rid of io mapping makes it impossible to use uacpi in userspace
imho aiming for minimal API is not a good idea if it impacts the functionality
we said that iopl makes more sense for acpi runtime anyways, either that or premapping everything or lazy mapping as needed
i think that's a decision that the OS should do
i don't buy that getting rid of these functions makes anything easier (just stub them to do nothing)
while it definitely makes some stuff harder for some ppl
tbh the stub is pretty simple, *handle = (uacpi_handle_t)base, and then just (size_t)*handle + offset when accessing
currently there's one such user and they do IOPL
also definitely not impossible, just less convenient
tbh given the stub is pretty simple, I don't think its that big of a deal
that stub adds a ton of extra complexity to uacpi is the issue tbh
not needing both the raw and mapping is a big enough of a simplification
I mean, isn't it similar to the system memory tho?
and for facs you can premap
i dont buy this as well tbh, the os doesnt get to control what firmware does, it must blindly perform wahtever IO it's told, besides a few blacklisted registers
and these are blacklisted mostly by windows and not by spec :^)
yeah
well its not i guess
mmio would be the same if you were guaranteed a certain mapping from phys->virtual address
or at least thats my impression
well, on arm io is mapped as mmio
ig the main diff is that io is pretty much always limited to a 64k address space (I think infy said acpica even asserts that)
so even on 32bit you can fully mmap it
ig my question is if arm acpi tables still use system io address space or just already do the mmio conversion
because if they already convert then the argument about arm port io being mmio doesnt really apply here imo
since this is for when acpi tables want to do io
io ports on arm are mainly for pci compatibility
so acpi hardware on arm won't use it (if you eve have non-acpi reduced hardware)
I think SystemIO is an x86 thing on acpi
and therefore the systemio map/unmap handlers being discussed here will never be called on arm and thus the in/out instructions are always a valid implementation, no?
you don't even need io ports on arm
thats kind of my point
but then microkernels and stuff etc etc
was koronas argument
Another reason I've used iopl is that my io ports stuff is per thread, and I didn't know if io map functions would get called from gpe handlers
its unspecified
tbh my opinion is that stuff like the io map functions etc - stuff only or primarily meant to be called to implement AML operations - should have a correspondence to a thing aml does. if aml has a thing that corresponds to needing a function like that then let the os implement it, if not then dont
basically if the obvious 99% implementation is a no-op then why bother
thats basically my thinking
actually, a compromise idea here:
when does acpi logically ever unmap an io region? encountering a systemio region is enough to say it might be used and you arent likely to ever stop needing it anyway, therefore:
why not provide an optional callback when a systemio region is discovered for the first time?
basically go hey fyi we encountered an io region of port 0x348..0x350
tbh its not about regions
its about FADT registers for the most part
regions are mapped on first access and umapped when destroyed
so basically either never or when function exits
i feel like FADT registers should be mapped once on initial load and unmapped once on uninitialize
perhaps
mhm
for abstraction that on 100% current implementations does nothing
I can try implementing this to see what happens
acpica doesnt have such abstractions for pio for example
big brain
have uacpi always call the io map function once
mapping an entire 64k range
:^)
lmao
uacpi is compileable by msvc and clang right?
ye
ok currently having trouble compiling uacpi-rs as it aparently aborts as it cant find gcc
what compiler flags do you use to compile uacpi with msvc?
uacpi-rs doesnt build as either the wrapper.h or the compiler flags are incompatible with msvc
tests/CMakeLists.txt
the current flags in uacpi-rs are gcc/clang specific yeah
i cant find it
/runner
which set of these do i need to have the equivalent to the clang ones? /W3 /WX
/wd4200 /wd4267 /wd4244
I don't think any of those are equivalent for them, those are for warnings
idk what would be the msvc equivalents of the flags used in uacpi-rs, you'd have to look them up (but also F msvc, who uses that for a kernel when you have clang/mingw gcc if you want to target pe)
I compile pmOS with clang
these are just warnings yeah
what msvc flags do i need to compile uacpi like the flags used for clang?
default ones
are these msvc flags
so you mean i can just ignore these flags when compiling uacpi with msvc?
"-fno-stack-protector"
"-mgeneral-regs-only"
"-nostdlib"
"-ffreestanding"
i dont think that that will work properly
i found a solution for msvc incompetence to support gcc/clangs compiler flags:
if cc.get_compiler().is_like_msvc() {
compile_error!("uACPI does not support MSVC");
}
not true btw
well
cc.files(sources)
.include(format!("{uacpi_path_str}/include"))
.define("UACPI_SIZED_FREES", "1")
.flag("-fno-stack-protector")
.flag("-mgeneral-regs-only")
.flag("-nostdlib")
.flag("-ffreestanding");
this doesnt work with msvc, it fails to build and ignores all flags