#shkwve: an incomplete kernel/maybe bootloader/UEFI thing/maybe something else if i get bored again

1 messages · Page 7 of 1

untold basin
#

you create them together

#

well

#

you create a port with a queue attached

rose sonnet
#

My port is a queue

tawdry surge
#

So you create the queue first, right?

#

Ports to queues is many to one

rose sonnet
#

Idk, it's funny to me now that we've basically came up with the similar design independently

untold basin
tawdry surge
#

I see

rose sonnet
#

I just have one queue though

#

For me, port is a queue

#

Like 1 to 1

untold basin
#

but you have distinct send rights

rose sonnet
#

Yes

untold basin
#

so its the exact same thing

rose sonnet
#

But they go to the same queue

tawdry surge
#

I guess that can work but you probably need to be able to revoke ports if you design it like that

untold basin
#

but with different names

untold basin
#

i mean first of all you only need to be told when the last user of a port exits

rose sonnet
#

You can either delete the queue all together, or rewoke rights (from both sides) individually

#

Then also both sides get notified of that

untold basin
#

but yeah also making ports revokable isnt like crazy hard

tawdry surge
#

well yeah but you probably want the server to be able to force termination of a connection if a client misbehaves

rose sonnet
#

And all rights get deleted when the port gets deleted

untold basin
#

like send garbage?

#

you just say "no" and fail the request

rose sonnet
tawdry surge
#

Try to spam garbage, for example

rose sonnet
#

Yeah

untold basin
#

im planning to have limits on size anyway

rose sonnet
#

I haven't though of that

untold basin
#

(so that you can presize buffers properly)

rose sonnet
#

I mean there is an easy solution to that

untold basin
#

so like the worst you can do by spamming garbage is dos

#

which you can do in so many other ways

#

its a fifo queue too

rose sonnet
untold basin
#

yeah i have that kind of thing too

rose sonnet
#

E.g. in pmbus

untold basin
#

the solution is to just not have to ban individual clients

rose sonnet
#

But it can be easily solved by explicitly asking the clients to create new rights for each client

#

Then it can be more granular

untold basin
#

just dont ban meme

rose sonnet
untold basin
#

if the client crashes no

rose sonnet
#

So you get notified in both of the cases, or like don't have to wait

untold basin
#

if the server crashes that just means the server part got abandoned which is different

rose sonnet
#

As a server, you have to know you have no clients

#

So that you can free the internal state and stuff

untold basin
trim seal
#

Never looked into static branches

#

What's the idea there?

untold basin
#

you statically patch a nop into a branch if you decide at runtime whatever condition is met

#

if the condition changes very rarely this makes the common case faster

trim seal
#

Why does that need asm goto tho

untold basin
#

how would you do it otherwise

trim seal
#

No idea I just learned about its existence

untold basin
#

this is the other side tho

trim seal
#

Alternatives work by patching raw assembly

untold basin
untold basin
#

i dont notify on a port dying but i can fix that probably

trim seal
#

asm goto just means this assembly can jump somewhere else?

untold basin
#

yes

trim seal
#

Ah

untold basin
rose sonnet
#

The sender side is line 672

trim seal
untold basin
#

they can see that if you have code like if if something { true } else { false } { a } else { b } thats the same as if something { a } else { b }

#

and the return thing is enough for gcc/clang to turn it into a direct branch

#

and yes its better because it avoids a conditional branch

#

and its only a nop if the branch is not taken which is almost always way cheaper

#

e.g. on m1, a nop is 1 uop and you can retire 8 every cycle

trim seal
#

And what if the arch jump helpers are out of line

untold basin
#

a cond branch is also one uop, but its between 0.5 and 1 cycle

untold basin
#

its not actually a function

#

and yes making it an out of line function would make it awful and dumb

untold basin
trim seal
untold basin
#

but close enough

trim seal
#

Yeah, see korona msg

untold basin
#

anyway yeah

trim seal
#

Anyway... microkernel right KEKW

untold basin
#

yeah?

#

hmm copying is actually kinda annoying

trim seal
#

btw are you going to use the new acpi crate

untold basin
#

lol

trim seal
#

yeah

untold basin
#

im either gonna use uacpi or make my own

trim seal
#

own would be interesting to see

untold basin
#

generic spinlocks are uhhh certainly a design choice

trim seal
#

is that bad?

#

lol

untold basin
#

anyway they dont handle allocation failures so its as good as useless for me

trim seal
#

they dont??

untold basin
#

uh is uacpi robust to malloc saying "no u"

trim seal
#

ofc

untold basin
#

they just use the rust std containers

trim seal
#

every single allocation failure is handled gracefully in uacpi

trim seal
#

will have to talk to the author about it

untold basin
#

they are fine if you dont care about alloc failures

#

and there isnt like a great alternative other than "lol write your own collections"

trim seal
#

...which u kinda do for a kernel crate lol

untold basin
#

which understandably people dont want to do

trim seal
#

yeah it requires a phd in language theory

#

if u wanna write a rust vector

untold basin
trim seal
#

what about linked list or intrusive containers

untold basin
#

there is a crate for that

#

which is like fine

#

i use their rbtree

trim seal
#

ah

untold basin
#

because their linked lists arent fine trl

#

well the linked list iirc is fine but the singly linked list can only push at the front not at the back

#

even tho its trivial to make tailqueues work properly

trim seal
#

huh lol

untold basin
#

but anyway usually linked lists arent great

trim seal
#

so if u wanna push something u have to walk the entire list?

untold basin
#

for the singly linked list yeah

#

because they only have a stack

#

and not a tailqueue

open osprey
#

broadly speaking, what is the architecture of shkwve going to look like?

untold basin
open osprey
#

i can see there are some microkernel like primitives

#

and lots of async

untold basin
#

yeah its a microkernel thing

#

unless i get bored of that in which case it wont be a microkernel

#

and yeah i have some ipc rn and thats it

#

the userspace is extremely barebones

trim seal
#

is it going to be more advanced than managarm

untold basin
#

advanced in what way

trim seal
#

microkernel wise

untold basin
#

no im not going to get a bigger port collection

#

and probably also not more perf

trim seal
#

like the primitives etc

untold basin
#

although maybe

trim seal
#

async model

untold basin
#

its a completely different design so its not really comparable

trim seal
#

can u explain the difference in designs?

untold basin
#

i mean not rly? its just all different i think

#

the only similarity is that we both my kernel and managarm has refcounted handles

trim seal
#

lol

untold basin
#

i think

trim seal
#

isnt it all like

#

send data, get reply

untold basin
#

no

trim seal
#

lol

untold basin
open osprey
#

if i did a microkernel i would certainly use these for ipc

untold basin
#

slow

#

also not async

#

also really complicated to implement

open osprey
untold basin
#

sync ipc in general isnt that fast afaik

#

or well it has good latency but not throughput

open osprey
#

doors is

untold basin
#

its sync right?

open osprey
#

fully

untold basin
#

yeah

open osprey
#

it's thread-migrating IPC

#

in place of the thread you have a stack of activations in different contexts

untold basin
#

yeah i get that part

#

but yeah afaiu that has worse throughput

open osprey
#

the principal problem, i spoke of it before, is how it scales to complex, mutually-reentrant activation stacks

untold basin
#

like with my design its not conceptually very hard to allow you to queue up a bunch of operations in one syscall

open osprey
#

stack management becomes difficult

untold basin
#

and you can receive a bunch per syscall trivially

#

and with a doors-style system that cant really work

#

you have at least one syscall per ipc

#

and also your throughput is exactly the reciprocal of the latency (i.e. you couldnt possibly make it any worse except with a worse constant overhead meme)

#

anyway back to lock ordering issues

#

i cant copy while holding the queue lock

#

but i also need to hold the queue lock to prevent cancellation

trim seal
#

Do you have your own UEFI boot proto?

untold basin
#

no

untold basin
rose sonnet
#

just copy, then check if it's canceled..?

untold basin
rose sonnet
#

(except the smp problems)

untold basin
#

because then its a uaf

rose sonnet
#

just IPI the other CPU and disable syscalls while copying so it can't be canceled

untold basin
#

the copying on its own requires taking locks and possibly blocking

#

because you can copy from/to a pager

rose sonnet
#

weren't you copying to kernel's stack first?

untold basin
#

i mean i copy through kernel memory sure

#

i have a percpu for it but yeah

#

but the problem is still there

#

i dont want to reacquire the lock every time i do a little bit of a copy lol

rose sonnet
#

I mean I don't have this problem because my messages hold the buffers

#

while they are in the queue

untold basin
#

yeah but i dont want to do that because thats cancer

rose sonnet
#

it is what it is meme

#

just don't send large messages

untold basin
#

lol

#

anyway the solution is to put a second lock inside of the queue

#

which is what allows you to do cancellation on it

rose sonnet
#

yeah

#

don't you have a lock for rights already?

#

like this is the same issue as if the other side also cancels

untold basin
#

the queue has a lock yes

#

but you cant take that lock while doing a usercopy

tawdry surge
untold basin
#

how would you make a more advanced monolithic kernel design anyway

untold basin
#

well i could add an event that you have to wait on before you cancel

#

i think ill do that

#

hmm except that makes cancelling way more complicated lmao

#

actually better idea: i'll make an event you have to wait on before its actually complete

rose sonnet
#

but what if you rugpull and unmap memory, etc.?

untold basin
#

wdym unmap memory

#

then you get a fault

#

either an error code or just a full exception

rose sonnet
#

wait, do you get async pagefaults in the receiver?

untold basin
#

wdym

rose sonnet
#

I'm confused now to how your ipc works

#

Do both sides have to be calling the kernel at the same time for it to go though?

untold basin
#

no

#

you can asynchronously copy memory?

#

like copy memory from a different process

rose sonnet
#

so your recieve is async

untold basin
#

yes

#

my operations are all fully async except for reply-send which is sync

#

but reply-send is guaranteed to complete without waiting on anything except pagers

rose sonnet
#

but then, who gets the pagefault/error when the async recieve can't happen?

untold basin
#

or well probably the caller idk i havent decided yet

#

i could asynchronously deliver an exception

rose sonnet
#

my receive is synchronous...

untold basin
#

its not?

#

you can have many clients connected to a single recv

#

and you could have outgoing requests also use that afaiu

#

which is like the definition of async

rose sonnet
#

Then I'm confused

#

The things get placed to my queue asynchronously

#

But I do pop front synchronously, and it blocks if there are no messages

#

Doesn't it make it synchronous?

untold basin
#

not really?

#

i mean i guess kinda?

#

but like no id call it async io

rose sonnet
#

I mean I've been thinking about it, and I can make it fully async as an optimization, or whatever

#

Without changing the send API

untold basin
rose sonnet
#

(I mean I was also planning to make blocking send)

untold basin
#

make it so that you can receive from ports while you receive from ports?

#

lol

rose sonnet
untold basin
#

so batching?

untold basin
rose sonnet
#

Or like while doing other work

untold basin
#

thats what i have

rose sonnet
#

I mean sure, but do I need it?

untold basin
#

multirecv is most of the gain imo

rose sonnet
# rose sonnet Or like while doing other work

Like with rust futures for example, I can just make it set a flag in memory on completion, then in busy servers you'll just check the memory first, before calling into the kernel

#

Like full ring buffer kinda thing

rose sonnet
#

Since it would go into the buffer directly

#

Like what you're doing right now

#

Thinking of which, you can also make the cancelation async trl

untold basin
untold basin
#

okay now my kernel is getting very confused

#

its saying 0 bytes received

#

and it received data properly

#

i think my syscall code is fucked lmao

#

yeah

#

much better

#

userspace works!

#

oh oop its printing a random debug print lol

#

and it works with kasan too albeit more slowly

untold basin
#

im gonna try make gdb work better

rose sonnet
#

who needs gdb

untold basin
#

well i want to make gdb work at least kinda okay

#

instead of it working terribly

#

my plan is to write my own gdb client and server so that i can make a shim that sits between gdb and qemu and lies to gdb about my threads etc

rose sonnet
#

Somehow, I think I never really had problems with gdb

untold basin
#

gdb is the most robust program of all time

untold basin
#

"progress"

#

hardcoded that one

#

pwndbg doesnt really know what is going on it gets the perms wrong too

#

i imagine if i updated to latest it would help

#

lol im making so many errors that are like Data format error: invalid hex string: &{%!m(string=encoding/hex: odd length hex string)}].

#

ok i wrote a hack that makes it work properly

#

time to make it work but using the llvm debugserver's documented api, so that i can actually upstream it lmao

#

because i have a feeling that if i write a PR which calls an api thats like "qsk.plzz_give_memory_map_kthx" they wont really accept that

#

pwndbg-lldb is even better

tawdry surge
#

doesn't lldb support the gdb protocol as well?

untold basin
#

they do

#

thats what you get with the gdbserver protocol lmao

untold basin
#

except slightly different because of course it is

tawdry surge
#

ah i thought you meant something else due to:

llvm debugserver's documented api

untold basin
#

yeah i meant those magic extensions

#

lol

tawdry surge
#

ah

untold basin
#

also gdb is so absurdly picky when it comes to the xml you send ngl

#

if you have a union, then supply a size and also start/end values for the fields, you get an error that bitfields must have a specified size

#

which is lol

untold basin
#
python
import pwndbg.gdblib.vmmap
def get_known_maps_v2():
    if not pwndbg.aglib.proc.alive():
        return ()
    pages = list(pwndbg.gdblib.vmmap.info_proc_maps())
    pages.sort(key=lambda page: page.start)
    return tuple(pages)
pwndbg.gdblib.vmmap.get_known_maps = get_known_maps_v2
end
``` okay i have this awful hack
#

which makes pwndbg know how to do proc pid always

untold basin
#

i now have this awesome "flags" thing

#

oh yeah and i have a janky layer system

untold basin
#

and now i even made it so that it can pass through singlestepping

untold basin
#

gdb is so efficient

#

thats why every time you singlestep, it sends 120 packets

#

im not sure how much of it is pwndbg but like cmon

#

i might actually write a memory read cache atp

tawdry surge
#

ig they never optimized single step perf

untold basin
#

i imagine its pwndbg not being efficient

#

and gdb not doing caching at all

#

lldb has multimemread which makes it less bad at least

tawdry surge
#

caching would be quite hard as you'd need to be able to understand all possible side effects of an instruction

#

and there could be insane cases

#

such as memory access trapping to a higher EL with visible side effects meme

vapid echo
#

idr the name

#

ah KDP

untold basin
#

that means i can only use gdb

untold basin
#

i mean caching within one instruction

#

it might be pwndbg not gdb idk, but gdb should have caching for this imo. they send many overlapping reads, then send more, and they are very short (even though latency is a bigger cost than throughput here most likely)

tawdry surge
#

ah i see

untold basin
#

im gonna try adding some caching to see how much can be gained but i suspect the answer is "a lot"

tawdry surge
#

Why does it matter though

untold basin
#

its noticably slow (idk if thats the cause but like)

#

because each request is an ipc

#

so if every step you send like 120 rpcs, your perf isnt going to be great

tawdry surge
#

libstdc++'s unordered_map manages to actually lose against the extremely low effort frg::hash_map when testing random keys meme

#
BM_HashMap_Find_frg/1024           6361 ns         6360 ns       110181 items_per_second=161.006M/s
BM_HashMap_Find_frg/16384        212194 ns       212178 ns         3303 items_per_second=77.2181M/s
BM_HashMap_Find_frg/262144      6429989 ns      6428793 ns          110 items_per_second=40.7766M/s
BM_HashMap_Find_std/1024           8952 ns         8950 ns        77770 items_per_second=114.41M/s
BM_HashMap_Find_std/16384        271224 ns       271203 ns         2585 items_per_second=60.4122M/s
BM_HashMap_Find_std/262144      9164705 ns      9162696 ns           75 items_per_second=28.6099M/s
trim seal
tawdry surge
#

yes

#

but it doesn't have the bucket API

#

i didn't look into what it takes to impl that because it's stupid anyway

#

the open addressing with linear probing and overflow counters is substantially better in this benchmark (2-3x for small table sizes)

trim seal
#

how can u ensure iterator stability with open adressing

tawdry surge
#
BM_HashMap_Find_rcu/1024           2427 ns         2427 ns       284987 items_per_second=421.954M/s
BM_HashMap_Find_rcu/16384        129493 ns       129479 ns         5392 items_per_second=126.538M/s
BM_HashMap_Find_rcu/262144      4943796 ns      4943186 ns          138 items_per_second=53.0314M/s
#

you allocate once per element

tawdry surge
#

inserts are slightly slower (~15%) though because they need to maintain the counters

untold basin
#

ah wait yes

#

but it doesnt iterate in the correct order

#

libstdc++ is like awful though

untold basin
tawdry surge
#

no

untold basin
#

at least use the SWAR trick

untold basin
untold basin
#

which isnt rcu compatible but is a lot faster

vapid echo
#

Unless you put it behind openmp or something

untold basin
#

and get a bitmask

vapid echo
#

What is it

tawdry surge
#

then you need to restrict your overflow counters to 255 though

#

ig that's fine

untold basin
#

uhh idr youd have to check the code of any good hashtable

untold basin
tawdry surge
#

i assume it rehashes when it's exceeded?

untold basin
#

no

#

they make it sticky if it reaches 254

#

and never decrement it

tawdry surge
#

uh

untold basin
#

and you just hope its rare

tawdry surge
untold basin
#

and you make sure your hash function is good

#

if it is, you wont reach it

vapid echo
#

Ah that is what SWAR is

#

I just looked it up

#

I think I used that before

tawdry surge
#

or rather, i don't think a good hash function saves you

#

because no matter how good the hash function is, its range may be quite small

#

compared to the number of insertions/deletions

#

for tables that have small sizes but many updates

vapid echo
#

How do you do fine-grained locking in a hashmap?

#

Is it worth it to do something like sharding or should you do lockfree

untold basin
#

like it only produces values in [0, 2^32) or something?

#

the definition of a good hash function is that it produces values which are uniformly distributed over the whole interval required meme

tawdry surge
#

no, it only produces values in [0, 512] because the table is <= 512 entries but receives 1M updates per sec

untold basin
#

ah

#

ahhh yeah i get it

#

yeah maybe it could be problematic

untold basin
#

i think max(true value for overflow refc) = max(probe length), right?

tawdry surge
#

yeah

untold basin
#

so youd need to have a probe length of 254

tawdry surge
#

wait no

#

that's not true

untold basin
#

i think it is

tawdry surge
#

say you insert into slots 0, 1, 2, 3, 4 w/o collisions and then get a collision on insert into slot 0

untold basin
#

oh right

tawdry surge
#

overflow rc = 1 but proble length = 5

untold basin
#

so its ≤ max probe length

#

since you have overflow if an entry before has a continuous probing run from there to here

#

and you need at least {overflow refc} entries to get it that high

#

so if you have a count of 254 you have an entry for which the probe length is ≥ 254

#

which is already a problem

#

and the solution is to rehash at a load factor that prevents this from happening

#

especially for folly when you have 14-way probing this would be an absurdly bad probe length

tawdry surge
#

yeah true

untold basin
#

but yeah maybe you should rehash once this happens too much

#

maybe rehash every max(4*capacity, 16) insertions or something

#

or every capacity^2 insertions or whatever

#

you want to set the rehash interval to be a multiple of the capacity so that it still runs in amortized linear time

vapid echo
#

@untold basin do you know how folly hashtables compare to abseil?

#

I think abseil has the swiss table design which might only be good with SIMD

#

this might be relevant but they don't benchmark folly

#

verstable seems to be quite good

untold basin
#

also those results uhhhh do not look great

#

like you shouldnt be getting that much spikyness

#

and the string keyed benchmarks are entirely useless because the hash function used is fnv (which is really not great; in particular, for short strings, you kill the performance of all of the open addressed simd tables in many cases)

tawdry surge
#

0.875 is not that insane

#

That's the same that i used above for the frigg rcu table

#

(because 7/8 can be computed w/o division)

untold basin
#

the issue is changing the load factor from the default for whatever table you are using is uhhh

#

especially for tables which are using chaining like std thats really bad afaik

vapid echo
#

I think I will implement something like verstable

#

Seems pretty good

tawdry surge
untold basin
#

yeah i imagine its probably not like a huge diff

#

the bigger issue is the string hash is really bad + the results do not look good

#

like i know the stl is bad but its not quite that bad in terms of noise

#

unless you did something really dumb

#

e.g. if you only did one run per sample, or if you use the same input so every sample is the same

vapid echo
untold basin
#

it probably doesnt matter

#

unless you do something really dumb like one alloc per object

tawdry surge
#

yeah that variance looks sus indeed

untold basin
#

hmm i found out there are tools similar to gnatprove but for rust

#

and now i wonder if unis have a monopoly on formal verification tools

untold basin
#

okay so i have an idea

#

what if i remove refcounting entirely

#

because that would kinda solve a lot of the reference cycle issues i think

#

also i could have userspace explicitly allocate objects if i was careful in the api design

tawdry surge
#

you can use capability delegation trees as in seL4

untold basin
#

which is nice for accounting

tawdry surge
#

but the cost of that is extra book keeping

untold basin
#

i was thinking of just giving out rights

#

sort of like a mach send right

tawdry surge
#

is that just a weak pointer or how would it work?

untold basin
#

except without preserving the presence of the alloc

#

so a handle is the 3tuple {object ptr, object serial, object rights} (in the kernel ofc)

#

you allocate objects in a virtually mapped region

#

and if the page is mapped there it always contains objects

#

or i might use a global handle indirection table idk yet

#

the handle table approach has some advantages in terms of simplicity