#Zinnia
1 messages · Page 24 of 1
also you might need to update the readme if you delete a task
(not that big of a deal but it might be confusing)
ok i updated that too
is the gpt overhead always the same value?
Yeah that's a fixed property of GPT-formatted things
ah
One block MBR, 33 at start and end for GPT
lmfao how am i meant to respond to this
Well you don't exactly put anything into /boot for me to test it
system-root/boot is empty for me
did you install the packages
oh right you don't have the aliases
alias xbi 'xbstrap install'
alias xbib 'xbstrap install --rebuild'
alias xbibt 'xbstrap install-tool --recom'
alias xbic 'xbstrap install --recon'
alias xbict 'xbstrap install-tool --recon'
alias xbit 'xbstrap install-tool'
alias xbr 'xbstrap run'
alias xbrt 'xbstrap runtool'
alias xbu 'xbstrap install --rebuild --reset -u'
alias xbut 'xbstrap install-tool --recompile --reset -u'
xbstrap has fish and bash completions
i use xbic for reconfigures and xbib for rebuilds
for host-tools you need to append a t
I just did all
Ran with QEMU, seems to work
I did however forget to rename one thing, pushed the working ver now
is this 3 line spacing some default formatting or something?
it's a very very very minor nit
I like to put additional newlines to visually separate parts of my code
Yes that's intentional
I moveth
emma vs spamming git reset HEAD~1 && git push -f
or that
you can disable force pushes on github
why would i do that
Yeah but this is not to main so don't care
this can be tempting
Yeah no idea why sgdisk takes that much longer
force pushes in a pr is fine
well yeah I have it disabled on master
But this isn't our main branch I was force pushing
marvin@aquaduct ~/r/z/build-x86_64 (main)> time xbr make-image
xbstrap: Running the following plan:
run make-image
xbstrap: run make-image [1/1]
xbstrap: Running ['@SOURCE_ROOT@/tasks/make-image.py', '@SYSROOT_DIR@', '@BUILD_ROOT@/zinnia.img'] (tools: [])
mke2fs 1.47.3 (8-Jul-2025)
Discarding device blocks: done
Creating filesystem with 1015799 4k blocks and 253952 inodes
Filesystem UUID: 1f832505-9515-4adb-b4f1-606c6c29f29d
Superblock backups stored on blocks:
32768, 98304, 163840, 229376, 294912, 819200, 884736
Allocating group tables: done
Writing inode tables: done
Copying files into the device: done
Writing superblocks and filesystem accounting information: done
Creating image from 2 partitions:
"EFI part", type 0x0700, size 134217728, offset 17408
"Root part", type 0x8300, size 4160715264, offset 134235136
Creating new GPT entries in memory.
Warning: The kernel is still using the old partition table.
The new table will be used at the next reboot or after you
run partprobe(8) or kpartx(8)
The operation has completed successfully.
262144+0 records in
262144+0 records out
134217728 bytes (134 MB, 128 MiB) copied, 0.0632966 s, 2.1 GB/s
8126397+0 records in
8126397+0 records out
4160715264 bytes (4.2 GB, 3.9 GiB) copied, 1.34642 s, 3.1 GB/s
________________________________________________________
Executed in 2.61 secs fish external
usr time 633.20 millis 0.75 millis 632.45 millis
sys time 968.36 millis 2.21 millis 966.15 millis
it's not the end of the world but idk if this scales well when you have a ton of files
It's sgdisk's doing so doesn't depend on file count
I have no idea why sgdisk takes long but it always has
Even for tiny disks
also, is this unconditionally copying over things?
or does it actually check files to be present already
actually no it can't
bruh
yeah this is going to be a problem
This is what you get for non-sudo. To my knowledge you can't do this without sudo but also copy files incrementally.
mmmmmmmmmm
The tools could be made but don't exist in mainstream distros.
this isn't really going to work tbh
i like this, but like
not mounting stuff is going to be horribly slow
and will kill iteration speeds
bc imagine you have an actual gcc + libc + maybe X11 in the sysroot
that's a shit ton of data
if you have to copy everything again on EVERY kernel/server recompile, it'll take infinitely longer
(the python script is a good idea regardless)
but not using mount is a mistake imo
The clanker tells me you can use debugfs to copy data in and out
And it's right of course
But can you rsync like that I wonder
never heard
debugfs is a standard tool, any distro has it
experiment with it as you please
if it works out, it's fine in my eyes
but i don't see it being a viable replacement
those are RO iirc
try
Ok I added 2.6 useless GiBs lets see
This was not as slow as I thought but it still took a bit
real 0m19.380s
user 0m2.225s
sys 0m15.831s
Most of that was actually the dd from the filesystem blob into the final image
2.7G image
i do a lot of recompiles when developing, and 20 seconds every time sounds like a nightmare
:/
Then I can't make it work without sudo without either spending a shitton of time making something
imo it's fine if you only put sudo in that one mount
the rest should work without (?)
This wouldn't even be a problem if I could more efficiently copy into the final image from the root part
Because then you'd only spend like 4 seconds
well managarm and menix for example only do rsyncs while it's mounted
it's very efficient for partial updates
yeah i get that
you can also use it to write to real block devices
the speedup vs dding a fresh image is insane
But ehhh if you can't live with it potentially being slow here you're gonna just have to revert
Because the old way did work
It would be nice if there was a standardised non-root way to mount like this, because it can be done safely
yeah
But that's just not a thing
i would actually keep the python script, but just adapt it back
i.e. replace the bash scripts with python because i do not trust the fragile integer logic of bash
fair
Still will need some uhm shenanigans
I'll see what I can do but it's a shame we can't get rid of sudo here
Actually what I can do is make an incremental mode that does that based on an env var if you're ok with adding export IDKSOMETHINGLOL=1 to your .bashrc
Then nonsudo for me, incremental for you
I'm allergic to sudo in my build pipelines because I had to fix build folders owned by root one too many times in the past
xbstrap tasks can take argv and env
you can just pass it there
like make-image-nosudo
Also for some reason this keeps crashing the python LSP
yeah happens for me too lmao
BTW the with sudo version is basically exactly your thing but it's in python now
Every single sudo is required in that old script
I'll check the rsync but you still have the root inode's permissions to contend with
Actually probably yeah you can
yeah and you have to copy files with absolute control over uid/gid
Well normal installation everything is owned by root, and mapping 0<->1000 means that you should get that with a normal rsync
hm
not everything is owned by root
case in point /home/foo
that's also part of the image
i had a really cursed idea for IPC
what if we used printf format strings to specify serialization formats 
ah shit
OK eh, we will just run the entire python script with sudo at that point because then literally every operation we want is root anyway
Uhhhhhhh I have no idea how to create that without sudo at all
Maybe with debugfs
Is /home/foo really part of the image? Doesn't the installer normally make those files?
what installer
this is a rootfs basically
afaik no hobby os has a proper installer
uhm
Then as soon as we start actually checking UIDs, this cannot possibly work because /home/foo will be owned by root
Like either way we did won't work
what's "this"? the current way or the old way
well rsync does the permissions
Yeah but it clones the perms from the sysroot dir
And all the UIDs in there are from whoever built it
So we can forget about the nonsudo approach in the first place as soon as we actually check uid and gid
rip
i think managarm does it by mounting /home/user for uid 1000
and the rest for uid 0
If it's just like 2 files we can get away with a super fugly call to debugfs to change the owner uid and gid
But much more becomes real ugly real quick
nah it'll be a ton of files
Everything in $HOME I take it?
yeah basically
mmm
shit
Well I guess we might end up removing the non-sudo approach later because I... Don't want to invoke a debugfs command where argc=2000
yikes
I'll fix something up for the incremental crap tomorrow, for now I think it's approaching sleepytime
ts is why all of our sleep schedules are fucked 
later today i want to start doing the initd connection broker
will review after lunch
@hybrid island could you auto format the script?
It doesn't even change anything when I format it
huh
Looks like I don't have a python formatter
(hint: you're supposed to tell me which formatter you use)
bruh it changes so much of the file it's a 95% rewrite now
here have your shitty formatted python script but don't ask me to update something that looks like THIS again
lol
terrible
let me see
Formatting is nice and all until you have one that doesn't agree with you on how code should look
I like clang format
yeah
Idk why some people hate it
coping
If you want it formatted then you should set it up properly.
fair point
I know someone who doesn't like it because he wants it to format how he likes by default and doesn't want to configure it
formatting isn't related to the functionality I changed here anyway
Bruh
and you accepted the last one without it
There's a website that makes it easy
yea
It has a couple annoying bugs, especially with compound initializers.
I don't really care about the formatting style, I just want it to be consistent
I think I use the Linux one but with 4 indent tabs
this
nothing worse than inconsistent style
managarm has this problem sometimes
inconsistent tab vs space indents
reeks of gnu
If you have the align assignment on and put a compound initializer afterward you get this fugly bullshit:
int alongname = 2;
struct foo bar = {
.a = 1,
.b = 2,
};
It looks so ugly to me I have actually shuffled code in e.g. Lily-CC many times to avoid this clang-format bug
// clang-format off 
compound initializers should probably be exempt entirely from the assignment alignment but you can't tell it that.
i only use it once for the IDT macro thing
I'm not putting 40 of those in c_compiler.c
Aligned assignments look so pretty though
wtf
burh
im krilling myseld
This is basically just your way but now using sgdisk instead of parted because I don't know parted
ok fuck the formatting
do it how you think it's best
but can you try using parted
it's much quicker
maybe we should restore the empty-image task
becasue it looks like creating the disk takes the longest time
when it only needs to mount the image and rsync
I don't really use compound initializers
Well I use C too
what do you use then
I mostly initialize members one-by-one
Problem is I can't get parted working
huh
I just don't know how to use it ok
maybe you should ask claude
Yeah but you wanted it to be the fancy fucking python script and I need to set specific offsets
hmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
If I still want the nonsudo thing to exist
also the clanker doesn't know parted either
let me try on top of the current diff
ok no something is horribly wrong with this code
it's so much slower even with parted
wth
For some reason setting the name of the partitions is failing but the rest is not
yeah im so confused
let me try doing the bash script again
i doubt that it's that
oh i know what it might be
there was a reason why the empty-image task was split
Is every single sudo just making it ultraslow?
This is so fucking stupid
parted exits with code 0 if you give it invalid arguments
At this point I see literally no reason to not just revert the whole python script idea
yep
They're all SO FUCKING UGLY
there you go
wth why did it open it as an edit view
idk
was that intended
whatever
Well that was a solid waste of like 8 hours of my time
I could've been making something actually useful like VMM
Can we hop in VC in a bit to set up clangd
okay
i have time rn
ruff is also a nice python formatter
it's arguable nicer than black
(but it's relatively new)
Wruff
ruff is pretty nice we use it at work
its also nice in that it replaces black, isort and flake8
yeah and it's way faster than black
@near tartan I see struct spinlock contains a single bool, but you can't do lockfree atomics on a single byte in RISC-V (without helper functions at least)
I suggest making it an atomic_int instead
Also you can make it an rwlock if it's an int
Which may turn out useful later
yeah that should be fine
most structs will force it to be aligned to sizeof(uintptr_t) anyways
why not?
Smallest atomics RISC-V defines is simply 4 bytes
And it has to be naturally aligned
has to be naturally aligned
you just take the whole word
and how does that work if it's only one byte
that seems like unnecessary overhead when you can just make it 4 bytes
didnt say that it wasn't
BTW I also fixed the code style of the doubly-linked list to match the rest of the structs
So that'll be struct dlist when I PR this
BTW @near tartan where do you want me to put user API stuff (e.g. PROT_*)
Since that's a common thing between the kernel and userspace
if it's used for syscalls, include/zinnia
ok
mem.h has some flags that are basically PROT_*
// Virtual memory flags.
enum zn_vm_flags {
ZN_VM_MAP_READ = 1 << 0,
ZN_VM_MAP_WRITE = 1 << 1,
ZN_VM_MAP_EXEC = 1 << 2,
ZN_VM_MAP_SHARED = 1 << 3,
ZN_VM_MAP_FIXED = 1 << 4,
};
I see
It's probably best to 1. not use an enum like this for compatibility reasons and 2. split prot and map flags because POSIX demands that anyway
compatibility with what?
but this is the syscall interface
libc/posixd handles the conversion from posix arguments
i.e. the actual PROT_* and MAP_* are part of the mlibc ABI
those bits would go in servers/posixd/include/uapi
ok
The current struct vmo shenanigans don't really match how UVM does stuff so I'll be replacing that as well
Mainly the part where I want vtable to be separate from the pointer so you can make a pager for random object handles without having to suddenly make them a struct vmo
but isn't that implied?
a vmo is a mappable memory object, regardless of the backing data
No I mean
You use a thin pointer
I will be using a fat pointer
Just like UVM, which uses fat pointers for this purpose
will you be keeping the functions mostly the same tho?
I don't care about the impl details, but i find being able to write directly to a vmo without mapping it very neat
I'll be keeping the basic idea of a pager the same
I see...
Hmmm
I suppose that would mean we need a bit more than just a single fat pointer to a pager
I'll see what I can do.
Because I get why you want to be able to do that to VMOs
what's the issue?
Well it would be a semi-significant difference from how UVM handles things
However I should be able to work with struct vmo with some minor changes:
- I need more protection for the page returned by
get_page(it could currently race if you concurrently read and flush writes for example) - I need a way to reference-count the
struct vmoto correctly implement vmm
i mean yeah vmos should be refcounted anyways
Do you have any refcounting infra at the moment?
no
I mean we could just steal rc_t from Lily-CC and rename it struct arc 
@lofty copper how good/bad is working with plain C headers for IPC?
since pmos doesn't use generated bindings
Depends on what exactly you mean by that
i mean exactly what i said
Like writing everything by hand?
Oh I thought you meant in terms of working, rather than being a PITA or not to write
nvm me im rarted 
BTW go join the invite link I sent u already
i think if you end up having similar code for every server you might as well make an idl
hm
@grave peak
using TCG
kvm is a bit better here
but no idea why it's so god damn slow tbh
isn't it like 5am for you
yeah
real
mfw no CoW
i would really like to know what is making it so slow
maybe the fact that it has to do a syscall to get the current time?
didn't you have vdso
i can imagine that the scheduler is also horribly unoptimized
i nuked it
too much effort to maintain
maybe i can provide the timer as a shared memory object
Is that in userspace
It's ok I guess
yes
i guess i can try using a bump allocator on a preallocated region to see what is causing the performance issues
because i doubt that it's the mlibc allocator itself, rather than the kernel
You can swap out the allocator in mlibc for sharded_slab
We should do that anyway as it's faster
I think the issue is that i have to do 2 syscalls atm to allocate anon memory
so there's already a bit of overhead
can i instruct mlibc to preallocate a certain amount of bytes at once?
which is redundant
i can just map the ZERO_VMO as non-shared
mlibc (or rather frigg) allocates in chunks of a specific super block size
iirc that is 256k
hm then it shouldn't be a syscall issue
that's weird
maybe my scheduler is just very slow?
Actually, it probably calls one per size class into the kernel allocator though
but why?
allocate and change protection or
also
- whats the typical score for uACPI (avg X/s)
- why are you trying to run ACPI in user-mode
create memory object + map in address space
menix got 5 million
and zinnia is a microkernel so it kind of makes sense to run in user mode
i don't think you should be able to map the zero vmo as writable lol
write faults on the zero vmo should not be possible
even if it's mapped private
the idea i thought you had with it is the same as managarm, which is just have a singleton vm object which you can map and have it provide a single zero page
i guess you could combine that + CoW but you still need to create a new vm object so atp you can just create a separate one instead
or i guess that's how anonymous shared memory works in managarm, CoW on top of ZeroMemory
then im curious how proxima got such a high score
who cares about the score make it run xorg bruh
hell yeah
Proxima is single threaded
And has no op spinlocks and mutexes
And a single threaded allocator that is not thread safe
ok that's a bit unfair
i pinged infy about it multiple times
¯_(ツ)_/¯

ig now my next goal is to comnect multiple servers via initd
no idea how I'm supposed to do that though
Proxima does this: https://github.com/proxima-os/proxima/blob/main/sources/proxima-devicesd/acpi/kernel-api.c#L602
(spinlocks and mutexes are no ops)
And this: https://github.com/proxima-os/proxima/blob/main/sources/proxima-devicesd/acpi/kernel-api.c#L332
(specialized single threaded allocator with no locks)
i thought 2 million wasnt bad?
And it allocates 2M for each power of two size class
If you're deliberately making people do two system calls to allocate memory, just eat the cost atp
Time to add an uacpi thread to astral to make benchmark go up
And then making a special purpose allocator for it
no? it's 4k per bucket allocation
but yeah it's not something you should compare other implementations to
@marble salmon in managarm, can there be multiple senders on a lane?
basically, im trying to figure out how to establish a messae channel betwen a new server and the init server
i could allocate a channel with multiple senders and initd on the other end, but I'm not sure if that's a good idea
another idea would be to notify initd of a new channel via ipc from the kernel
Managarm has this concept of offer/accept that allows you to spawn new streams in an ad-hoc way
In general, lanes are not thread bound on Managarm
but that doesn't mean that you can just pass a lane to many processes and expect it to work
Streams in Managarm are not general purpose byte transports
you can read the Managarm paper to understand how it works
senders and receivers on corresponding lanes must respect a common protocol (i.e. send compatible requests in the right sequence)
Otherwise, both sides fail
with kHelErrTransmissionMismatch
This IPC system is quite unique to Managarm though
okay then speaking in general, it's not a mistake to send messages from different peers to a common endpoint, right? (assuming the messages are designed for this, e.g. containing a peer handle/id)
I'd say the existence of a peer handle is questionable
sure
you should not have multiple things send stuff to the same channel
because then you end up not knowing who sent what
unless you add some sort of reply_handle to recv
or peer_handle
that's why i said the thing in parentheses
ah
ofc sending generic messages from an unknown peer will cause some chaos
With peer handles you're adding an unnecessary complication
And it opens up more questions than it answers
Like, what's the lifetime of a peer handle, how does access control work etc
what's the alternative?
i need a way to establish connections between servers that only know each other by name
the current idea is
srv0 -> initd "i want srv1"
initd -> srv1 "new connection, give me an endpoint"
srv1 -> initd "here's an endpoint to talk to me"
initd -> srv0 "here's a connection to srv1"
My kernel uses lazy mapping for basically everything, and was around that as well
that's what I did
also need to think about how to provide privileged data from the kernel to the servers
my current idea is (e.g. to get the RSDP)
- kernel starts initd
- kernel publishes the address as an object by writing a message to the initd channel
- kernel starts acpid
- acpid establishes connection to initd
- acpid requests the RSDP object
- done
im not sure if initd should store the bytes itself, or keep a connection open over which the bytes can be sent
this is the mach way
you send a "send-once" reply port right
idk what you mean by objects and stuff, I would just give the bootloader arguments or similar to initd
You just do??
in argv?
@hybrid island any progress so far?
on vmm you mean?
Yeah I've decided the final struct layouts to use already
The renaming is also finished
Now I wanted all the VMOs to be refcounted so there will be an API change there
Once I integrate that change it should be good for the interim so you can call the API in the new form (though the impl will still be the old one)
If you want I could make such an interim PR
yes
After that PR I'll likely have to take a break from programming for a bit since turns out I haven't had a week without any programming in the last year
let's stop programming for ever
argv 
(I'm doing it by passing a list of stuff from kernel, mapped into the process, and giving the address in one of the argument registers, but I think I'll replace it with auxvec)
true i could do it via auxvec
wait, what ipc do you have at the moment?
only sync messages and shared memory
and you want to do async?
this
I don't have sync ipc (but that's kinda irrelevant)
My init server stores the ports, and then anyone can ask it
Like named port -> right to it
I had it in the kernel initially, but moved it to userspace
So basically spiritually similar to mach
my idea is to have servers register themselves with the init server, providing a handle to talk with it
That's what I do
And since it's an init server, you can control the permissions and stuff
do you have a mechanism to share data between multiple servers?
Wdym?
if i understand managarm code correctly, mbus can store generic data and share it using names
I have an mbus clone
pmbus 
I've seen managarm use it to e.g. discover devices on pci bus
so a driver can query objects on mbus
Yeah
does pmbus do that too?
But it's just ipc, you get an mbus handle and talk to it
You can just get a pmbus object
I mean it's kinda not fully implemented yet
lol
ig my question is whether this object store should store the object in the server itself, or just forward the request to a server that provides the data
Both

I thought it was more of a discovery mechanism? So you store the stuff like PCI/ACPI ID there to be able to match the drivers, and then talk to PCI server or whatever to setup interrupts and whatnot
That's how I wanted to do it
yeah kind of
for the pci example
ig you'd do
struct pci_device dev = get_pci_device(0, 0x80, 0x14, 2);
if (dev.vendor != 0x8086)
return;
run_driver(&dev);
...
and that would be passed using attributes
struct obj dev = obj_create("pci/0000:80.14.2");
obj_add_prop(&dev, "vendor", cfg_space->vendor, sizeof(uint16_t));
obj_add_prop(&dev, "segment", 0, sizeof(uint32_t));
obj_add_prop(&dev, "bus", 0x80, sizeof(uint32_t));
...
gamging PCI
in my mind this makes sense
and that would allow the kernel to also publish some objects from its side
i wonder how i can restrict access to physical addresses
like conceptually
@lofty copper you have a pcid, right?
nvm you dont
you have devicesd
No
@hybrid island sorry to pester you, but do you mind making the PR anytime soon? i want to start writing a lot of code now and don't want to destroy your work
Part 1 here, only thing that has happened so far is adding types I'll use later and renaming, should still work the same. https://github.com/marv7000/Zinnia/pull/6
two things so far
this is missing a newline
and this is not needed
there is a CONTAINER_OF macro in common/utils.h
if you want you can move the static assert into there (and you can use the actual static_assert spelling because of C23)
actually, if you want you can replace my CONTAINER_OF with the one you wrote
it looks better
tho idk if you need the #ifndef, i think you could just do #else there?
could be wrong
You need nested #if to check for __has_builtin correctly
oh
i thought that can be #if a && b
then it's fine
but yeah this seems more robust than my impl
yeah my brain is still in c11 mode lol
maybe __builtin_types_compatible can be just abstracted via common/compiler.h
there you can make it eval to a noop if it's not defined
i already do it for __builtin_unreachable for example
Problem is that __builtin_types_compatible isn't really something you should do as a hint
So I'd advise against that
hm?
sure ig
it's not that deep anyways
if i ever add support for another non gnu-like compiler i'll refactor it
is this the same as {0}?
it's good, i just like to have the compiler/isa/platform abstractions in one place
unlike linux where it's all scattered across the codebase behind 10 levels of macros
yeah it is
No, all my generic containers just assume you know what type should be in there. As do most implementations of C containers I know of.
hm
I'm not against having these convey type information but I already had these and personally don't want to spend the time reinventing them
you don't have to
i'm just saying that it might be best to not do it for all containers
for intrusive linked lists it's totally fine
but i'd not do this for a vec or hashmap
(i say that as i am already not doing it lol)
right
ok merging
okay that was surprisingly painless
just had to change one thing in main.c
great
Actual API will look quite similar by the end
Though you will of course pass a struct rc * of a struct vmo
Instead of struct vmo *
yeah
weird
what is
IME the biggest type unsafety bugs I've had was my old vector impl I'm still wondering how to replace in Lily-CC
do you have a link?
This. https://github.com/robotman2412/lily-cc/blob/main/src/util/arrays.h <- This is bad. Do not use it.
A simple C compiler designed to generate decent binaries. - robotman2412/lily-cc
what the helly
😭 i scrolled down and the args increased even more
atp writing a few macros seems like heaven 
why is this like 300 lines
Comparatively it would
Because it's not just length capacity vector but also a bunch of other array-related utilities
// Clear all elements without freeing memory.
#define VEC_CLEAR(vec) ((vec)->length = 0)
This sounds like leaks waiting to happen @near tartan
ok nice i changed the channel impl so that the kernel can also act as a peer now
for physical memory access, does it make sense to "claim" physical memory?
for example, the acpi server would try to claim the acpi tables region and any other servers trying to access that physical memory would get an EPERM
I do for some stuff
I think it would be more reasonable to have whatever spawns drivers get elevated permission to map arbitrary physical memory and have it divy it up to the individual servers
what i would do is do it via handles
My kernel reclaims bootloader reclaimable memory 
you own an handle to some range of physical memory
yeah i mean that
but to create such a handle i mean
what I'd do:
- the root bus (acpi or devicetree) server has full access to the physical memory space excluding kernel-managed ram
- the root bus server manages resource conflicts and gives out handles to physical memory/io ranges that each device owns
But this is a way to do that
the init server would start with a handle (or multiple) ranging over the entire physical memory (minus the kernel), it would then carve it up and give it to the servers
You also have to think about IO ports...
yeah like monkuous said
IMO the kernel should magic an initial set into existance based on e.g. RSDP or DTB
i disagree
also when you design your DMA and pager interface make sure you do it in a way that allows you to implement iommu support later
But what is the difference between that and asking the server to do it for you. This just feels like delegating more stuff to the kernel
What if the memory is not contiguous, etc.
ok fine then just the entire physical memory
i have thought about doing this as well, but how do you determine which servers are privileged and which aren't
you dont
just everything that was launched via initrd?
Ask init server
You don't
The handle does
init gets a handle to the entirety of physical memory (except requests to map kernel managed ram are denied)
init gives this handle to acpi/devicetree then does nothing else with it
Also, when you launch a driver for the device, you can give it access to that memory (and set up iommu in your PCI server or whatever else)
I agree with this
Seems most reasonable to me
yeah thats what i said
Esp since our ACPI is gonna be userspace
But ACPI server can be trusted
i don't think userspace should be controlling the iommu
that sounds counter intuitive
Why not. It's just a design decision
yeah iommu is probably better fit for the kernel
Some kernels (minix?) have userspace control page tables
because (among other reasons) it's involved in interrupt remapping
minix is also not that good today 
another reason is that with userspace iommu drivers you'd need three context switches for each pagein/pageout (set up mapping, perform io, remove mapping)
I should look up what IOMMU actually gets used for
my understanding of what an iommu does is probably wrong
Yeah, I guess it should be in kernel then
sending interrupts to cpus with lapic id >= 256 (x86 only), DMA protection (ensuring drivers do not DMA to things they aren't allowed to DMA to), dealing with devices that can't DMA to high memory, virtualization guest device passthrough
But still, you can just ask someone to map memory for you
Ooooh
yes
even if you don't care about security or high cpu counts the iommu is important because it lets 32 bit devices DMA to 64 bit memory without bounce buffers
I mean, at this point, everything can just access everything in my os
I think this is a good idea in general and many microkernels do it like that but there are non trivial complications in practice
Definitely a kernel thing, IOMMU
see the Managarm system bus reconfiguration issue
I have a flag to allocate memory in userspace into lower 4GB
So the IOMMU creates a virtual address space shared by all DMA devices?
Or one each?
link?
each device has an iommu id and each iommu id has a separate address space
the TLDR is: cores (e.g., kernel framebuffer or kernel uart output) can concurrently write to PCIe BARs while decoding is being disabled to discover the BAR size
usually the iommu id is derived from the bus location, for example in pci it's just bus:device:function (although bridges can complicate this)
so you somehow need to synchronize this
i.e., BAR enumeration and the kernel writing to its framebuffer/uarts
i don't remember, do you need to read the bar size or isn't this something that can be done lazily
the problem doesn't go away if you do it lazily
Just don't have a framebuffer driver in kernel
how does linux manage this?
or does it just not
Linux doesn't do anything special afaict
maybe it doesn't write to the boot framebuffer from APs
not sure
in any case if this happens on real hw it causes essentially a full system hang because the bus timeouts are so long
maybe they rely on the initial pci bar enumeration (which would contain all boot resources) being done during an init phase where nothing else is running or generating interrupts?
maybe. APs start earlier than PCIe enum but maybe there's nothing interesting scheduled to them yet
i'll figure something out when the time comes
nice
i need to move the thread creation logic to mlibc though, otherwise it will keep crashing because of missing TLS data
made it so i can use standard C11 threads using mlibc
i can't really use plain syscalls to create new threads because that leaves me without thread local data and breaks a lot of things
Doesn't mlibc handle TLS?
yes that's what i said
if i only use plain syscalls to create a thread it works until you call some libc function
but if i do it via mlibc then it obviously works
ig I'll also need a way of waiting for a thread to finish
Huh
i mean is this surprising?
mlibc preallocates a Thread Control Block and passes it on the new thread's stack
Yes, but what are you doing before it?
wdym before it
I just don't get it, if mlibc does it for you, why do you have to worry about it
Or why can't you use that
Sorry if it's a dumb question
i AM using that
I didn't implement it before
in mlibc
Oh
the mach design
it sends a new channel handle back to the requester provided recv_handle

ah wait
so not sender IDs?
but the same capability mechanism that is also used for everything else?
yes
the find request contains a name and an answer channel
the client creates a channel and immediately moves an endpoint over
ah
yeah that makes sense
now just make it async, remove any buffering (if it exists) and compress it to a single syscall to obtain Managarm IPC
btw speaking of freya @hoary cave what if we make freya a library
that runs before ld.so
and spawns ld.so on a separate thread
and then handles the posix supercalls for that separate thread
Thor
|
| spawns |---------------------------|
↓ spawns | |
Freya ----------------> | loads |
^ | ld.so ------> server |
|---------------------| |
handles posix |---------------------------|
where freya + ld.so + the server are all in the same address space
but ld.so and the server are on separate threads from freya
wont that increase startup delays?
wow
tragic
for all the 5 servers that are started
keep in mind this is only for servers
whats freya
nothing yet, but soon to be a library that handles posix calls from servers
like a generic one?
it was supposed to be a server manager
ig thor could map all "files" (or the whole initrd, that was suggested by qookie) into freya and pass the address to that (or of some description struct) in rax (or similar)
also why is it called that?
currently there are some things which are implemented as "supercalls", im not sure on the details but i know that supercalls from servers are handled by the kernel, idk if the posix server handles them for normal userspace programs - that's because you can't call into posix from posix itself, since servers are dynamically linked and use the same libc.so as userspace you end up with this circular dependency which is satisfied by the kernel
norse mythology or something, idk
yeah posix handles supercalls of all apps
all application threads are owned by posix
i came up with that name for the init server in my rust kernel that was inspired by thor :^)
oh interesting
tbh the kernel used the eir boot protocol and implemented the hel api
so its going to be like a managarm project that all osses can use?
i don't think so
it was supposed to be so we can move server management out of the kernel
it's not like a userspace service manager like systemd or whatever
yeah kind of off topic lol

hm
i just noticed my channel ipc is suboptimal
i queue an unspecified amount of messages
something tells me that is a bad idea
actually i'm not even sure about that
@marble salmon maybe?
on every write to a channel i allocate a message buffer in the kernel
allocating an unbounded amount of kernel memory is obviously a bad idea
yeah sure
my question is whether i should be queueing messages with more than 1 slot
If everything is synchronous do you need a queue?
probably not
or mach ipc 
mach IPC is a bit different from what Managarm does at least
isnt managarm ipc very unique anyways
every ipc is unique I guess
not mine because i'm boring
if you're doing synchronous ipc i'd have the sender wait for a receiver to be ready and then directly copy the message to the receiver, no queue involved
isn't it potentially slower? Because you have to access the address space of the other process
this (what monkuous said). also, i'd probably use a utcb like concept to do it in a single copy for small messages
accessing another address space is unavoidable, the only question is whether the access is done implicitly or through a context switch
but if you have to context switch anyway
what Managarm does for large messages is it copies in the sender's thread to a page, sends the page to the receiver thread and the receiver copies out of it
this involves two copies of course
but there can be multiple in flight pages, so at least it's pipelined
and this is not to be confused with buffering: the transfer only happens when both sides are ready
it sounds very similar, you still have some memory buffer that's being moved (?)
i wonder how well just shared memory + futexes would work for this
right, but the buffers are only allocated in the kernel for the duration of the actual transfer
kinda the same I guess?
shared memory can achieve zero copy or single copy very easily
but it has a high setup cost
so it's worth it for persistent connections between servers
but not for one-off messaging
but this is already zero/1 copy
no, this is two copies
would e.g. mlibc talking to posixd be worth it?
sender -> kernel, kernel -> receiver
it depends
with shared memory, you can achieve one copy (sender -> receiver), or zero copy (sender writes to buffer that receiver uses in-place)
On Managarm, mlibc and POSIX do not exchange any significant amount of data
not even on write()?
does managarm have kernel memory objects or something?
how does it even do shared memory?
i guess there's one problem with shmem only, handles can't be transferred safely
wdym
Like any other handle transfer?
??
it's shared memory
there's no kernel involved
you could do some dumb shit like *buf = translate_handle(handle)
You cannot create shared memory without kernel involvement
yes
What kind of microkernel doesn't allow you to send handles?
just have several namespaces, and create a common namespace
omfg
That doesn't make any sense
between processes
bro
When you create the shared memory you get a handle
You can mitigate this by having a page per thread/endpoint that's shared with the kernel
And you share the handle to another process, which then maps it
that's not at all what i am talking about
i'm talking about sending handles to another namespace
that works with channels because the kernel translates it to the other namespace
No you can't send handles through shmem like that
this
You have to do it with the other messaging scheme
just move the handle to that namespace, write its id to the shmem
so shmem is purely data only
of course it is
and it will be correct for that process
I do that during the process initialization
But most of the IPC you'll want to do in reality will be data-only
In terms of total bytes sent
but what about reply handles
if you have ipc exclusively via shmem what i'd do for handles is make it so you can have a handle to a different namespace and use a syscall to 'copy' a handle from that namespace into yours (or another), then have a shared namespace in addition to a shared memory area
so senders would first copy a handle from their own namespace into the shared one, then write the shared handle into the shared memory area
that's what I just said
ah ok
i'll try this
but for what it's worth i don't think having shmem-only ipc is worth it
sure it might be for stuff like posix<->libc but that's not the only ipc
my ipc is just buffered in kernel
for a lot of things ipc will be a oneoff and setting up shared memory for that would be cumbersome
"dead simple"
yeah, this is a common design
just have a capability space that is a capability itself
such that you can attach it to two processes and let them copy in/out
although ofc copying in/out still needs a syscall
cheri 
but having every possible type of ipc implemented is also not good?
but yeah
ig channels for small messages and shmem for big data
It's common to have regular synchronous IPC and async shared memory
i mean handles is just another resource, like memory or io
Hmmm, I wonder under which conditions accessing a remote address space is faster than this
we did access remote address spaces in the past but then switched to this mechanism because it reduces locking etc
But now we have better locking mechanisms in place and we should be able to do remote page faults in a lock-free way so maybe it's time to re-evaluate this
but you still need to walk paging structures, map it somewhere, etc.
you don't map it but access it from the direct map
but yeah, this needs proper benchmarking
it could very well be slower than the pipelined copy that we do rn (since that lets the cpu do the page walk etc)
I do know that Managarm is not bottlenecked on large transfers
since if I bump copy chunk sizes in the kernel, microbenchmarks do improve while macro benchmarks (like mlibc compilation time or glxgears fps) don't
instead of page walking, I was thinking about storing a sepparate array of page mappings, so that the page tables can also be disposable
wdym by "so that the page tables can also be disposable"?
That's unrelated to remote copy afaict
But a separate mapping is almost certainly slower
it is unrelated, but it might be faster to get it from there than from page tables?
that sounds like a skill issue



can't be that bad