#Zinnia

1 messages · Page 16 of 1

near tartan
#

@distant cypress hell yes, i finally got to try mounting stuff

#

works like a charm

distant cypress
near tartan
#

init now has /dev/console as a stdio device

distant cypress
#

niiiiice

mental tinsel
#

will we get womenix or a menix rewrite #3 that goes back to rust first trl

near tartan
#

i fixed the scheduler issues somewhat

near tartan
#

hell yes

#

idk why mlibc is crying

#

turns out it was actually userspace crashing

near tartan
#

working on real hw again

#

still gotta fix tsc overflow

#

funky

#

for some reason the fb on this device is SOOO slow

#

even limine is struggling

#

it's less than 1fps for an entire scroll

grave peak
#

poor uacpi

near tartan
#

poor uacpi

#

gigabyte makes the worst firmware in the industry

grave peak
#

not gigabyte's fault

#

this is all because u dont have PCI implemented lol

near tartan
#

no it's not

#

linux has the same issues

grave peak
#

most of these errors are

near tartan
#

sure the errors are

grave peak
#

because it simply stops loading the DSDT

#

just implemnet it lol

near tartan
#

i need to get to that first

grave peak
near tartan
#

i think i got stuck on the scheduler memes

storm bobcat
near tartan
#

wdym

storm bobcat
#

what does it mean and how does it work

near tartan
#

it's an initgraph

storm bobcat
#

Why

grave peak
#

managarm larp

near tartan
#

no cuz it's cool

storm bobcat
#

why do you need this

near tartan
#

to init the kernel

storm bobcat
#

Can't you just print init... Ok like unironically

near tartan
#

huh

storm bobcat
#

Is there an actual advantage of having this is my question I guess

grave peak
#

well this is cleaner in some way

near tartan
#

well it lets you dynamically add init functions

storm bobcat
#

ah so it's not just prints

near tartan
#

without having a central main() where you call everything by hand

near tartan
#

no it's a tree of init functions

storm bobcat
#

Yea I was asking what it was doing

grave peak
#

its an init graph

near tartan
#

you declare dependencies and a display name

#

then it runs those in a way so everything gets initialized in the correct order

#

like, adding /dev/null requires devtmpfs to be mounted

storm bobcat
#

Ah that's cool

near tartan
#

you can also visualize it

#
#

it's from an older tree

#

it requires a few hacks in rust, so @hoary cave made it into a proc macro

storm bobcat
#

Ah maybe I'll look into this

near tartan
grave peak
#

whats a proc macro

near tartan
#

a macro that gives you a stream of tokens

#

and you can do with it whatever you want

storm bobcat
#

Macro with custom syntax

near tartan
#

pretty much

#

normal macros can also do that but with proc macros you get way more depth into the AST

#

for most things regular macros are fine, like per_cpu!()

hoary cave
#

with proc macros you get the token stream instead of composing the input from predefined rust syntax constructs

#

so you can parse it however you need to

grave peak
#

thats some crazy shit

near tartan
#

this is one of the things where rust really shines imo

hoary cave
#

it's pretty cool if you want to do some fancy stuff like we did

storm bobcat
#

Wait till you see lisp macros

near tartan
#

you can build some really nice abstractions

#

but building them is aids

storm bobcat
#

or elixir macros

hoary cave
#

syn makes parsing really nice

#

you just input.parse()?

near tartan
#

i have not yet managed to write one on my own

mental tinsel
#

gotta love rust's compile time const computation, I managed to train my neural network purely during comptime even though it took over 5 times as just training it during runtime 🤪

miri moment

marble salmon
#

tbh compile time computation is one of the things that I dislike most in Rust

#

C++'s constexpr is one or two decades ahead compared to Rust's const

#

and it gets even worse when you look at const generics

#

which are basically impossible to use w/o nightly features

#

(for all interesting applications at least)

near tartan
#

@vast lotus dumb question, how exactly does proxima do fork

#

i don't see where the fpu state is copied

#

i can see that you create a new thread on a clone, but never copy the fpu state?

vast lotus
#

A new xsave context is initialized by doing xsave

#

The xsave context for the new thread is created by the caller of fork and thus contains the fpu state of the caller of fork

near tartan
#

then i'm doing something really wrong

#

what about user fs/gsbase?

#

nvm i see where it is set

vast lotus
#

In general the extended state of a new thread is initialized to that of its caller

unkempt vigil
#

Rust toolchain love equality i must say ☠️

marble salmon
#

except for some control bits

vast lotus
#

the syscall abi preserves it though right

near tartan
#

my fork is finally working

#
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#include <sys/wait.h>

int main() {
    write(1, "Hello, world!\n", 14);

    int forked = fork();
    if (forked) {
        printf("I am the parent, child is %i\n", forked);
    } else {
        printf("I am the child\n");
        printf("I like being a child\n");
    }

    printf("And this is shared!\n");

    while(1) {
        asm volatile("pause");
    }
    return 0;
}
#

this is the code being ran

sick flax
#

Baller

#

Now where systemd

near tartan
#

in the far future

#

gotta stay realistic bro

sick flax
#

:(

#

But true

#

Menix the second hobby OS to run systemd

near tartan
#

i have to optimize the mapping logic because atm for private mappings it creates one memory object per page

sick flax
#

Unless beaten by nyaux of course

late bramble
near tartan
#

no

#

my scheduler was broken for too long

#

and the page cache bullshit was blocking me as well

near tartan
#

fixed the fd allocation again

fast mirage
#

yoooo

#

also wont openrc krill itself without pipe

#

i would know this

#

it does on nyaux

near tartan
#

guess what

fast mirage
#

what

#

vro is not telling me what

near tartan
#

forking kinda works now

#

i still get that weird mlibc bug with the recursion counter

fast mirage
#

lets go

near tartan
#

c is a perfect language

mental tinsel
#

and other lies you can tell yourself

near tartan
#

lol

idle flower
#

if c is perfect, why was c++ invented?

near tartan
#

job security

#

unsigned int c = 255;

near tartan
#

@lofty copper i heard you like to shill microkernels

lofty copper
#

I do

#

Just write a microkernel

near tartan
#

what implications does having a microkernel have vs a monolith

#

HOW much different is it actually

#

my major concern is if there's any aids things i should know about

lofty copper
#

Idk I've never written a monolith

near tartan
#

hm

#

like

lofty copper
#

It's a lot more work I guess?

near tartan
#

like protocol stuff for example

lofty copper
#

Because you have to think about IPC and stuff?

#

Yeah

near tartan
#

hm

near tartan
#

and how do you access phys mem

lofty copper
#

It depends

lofty copper
near tartan
#

for drivers

lofty copper
#

I'd assume it's the same

#

I have a syscall for mapping phys memory

near tartan
#

like, do you just say that drivers have to have a certain cap to be able to access phmem

lofty copper
#

I guess you can do the same in Linux by mapping /dev/mem

lofty copper
#

I've been thinking about representing devices as memory objects or something

#

Basically capabilities system

#

But idk how much it matters with devices that do DMA and stuff

#

(unless you have iommu)

near tartan
#

iommu drivers are easy enough i guess

lofty copper
#

Like at the moment my kernel just lets userspace map any physical memory it wants

#

And I have a syscall for getting phys address from pointers for DMA

lofty copper
near tartan
#

so you do scheduling and process management in kernel?

#

or threads in kernel and processes are a user structure?

lofty copper
#

But idk if it makes a lot of sense

near tartan
#

depends on how you manage address spaces

lofty copper
#

My memory management is in kernel

#

So I guess threads sharing the same address space can kinda represent a process

near tartan
#

yeah

#

that's good enough

lofty copper
#

But then I have a separate server which keeps track of POSIX processes and stuff

#

So idk

near tartan
#

yea if i were to go witha µ design i would probably have all the posix stuff in its own server

grave peak
#

uMenix

near tartan
#

lol

#

µnix

#

micronix

#

nanonix

lofty copper
#

munix

lofty copper
#

Which I've also used to share capabilities between threads

lofty copper
near tartan
#

minus the addrspace

lofty copper
#

But a thread can be in multiple groups

#

So multiple processes can share things

near tartan
#

but does that make sense?

lofty copper
#

Idk

near tartan
#

in my head a thread only ever belongs to one process

#

because having two owners means something is off

lofty copper
#

My filesystem is also represented by task groups

#

So when I'm forking a process, I clone the filesystem by creating a new group, cloning the file descriptors, and giving it to the new thread/process

#

So at that time the thread that calls fork has two file tables

#

Idr what's the right name for it

near tartan
#

fd tables

lofty copper
#

Yeah

near tartan
#

designing a microkernel sounds kinda fun

#

because everything is just opaque objects passed around

lofty copper
#

So like if the userspace decides to, you can have multiple threads in the same process have different fd tables or something

lofty copper
near tartan
#

btw i saw you are polling for messages in some of the servers

#

my idea would've been to have an infinite loop and do something akin to sigaction

#

where you can register handlers for certain syscall numbers

#

like

lofty copper
#

So my plan for handling signals was also to have a thread which polls for messages and changes other threads from userspace

#

So the kernel doesn't have to touch the userspace's registers

near tartan
#
menix_handler_ret_t my_beef_handler(menix_source_t src, menix_msg_t msg);

int main() {
    menix_register_handler(0xDEADBEEF, my_beef_handler);
    menix_hiber();
}
#

something like this

near tartan
#

hiber is noreturn

lofty copper
#

I don't remember where I've used it

#

It's also what managarm does

#

I think?

distant cypress
#

DEFINE_SYSCALL(sys_beef)

#

sys_beef should be like some debugging syscall or something

distant cypress
near tartan
#

yes

#

i mean that's what servers are no?

#

they init themselves then wfi

lofty copper
#

That's what I do at least

#

Idk I need to get back to working on my OS

#

I haven't touched it for almost 2 months now

near tartan
#

are your servers also freestanding?

lofty copper
#

No

#

Nothing is freestanding except the kernel

near tartan
#

static linking?

#

i mean i wouldn't see how it would work otherwise

lofty copper
#

Yes, but that's because I haven't bothered implementing dynamic linking

#

I should port mlibc

near tartan
#

yes you should

#

please do actually

#

it'd be the only other source for a microkernel sysdep

lofty copper
#

My libc is not that good

lofty copper
#

Idk

#

I think managarm had dynamic linking in the kernel or something?

#

My init server acts as a filesystem so I can probably do dynamic linking in there

near tartan
#

how do you open files if posix doesn't exist yet

#

like

lofty copper
#

Do you need to open files?

near tartan
#

yes thats how dynamic linking works

lofty copper
#

It's just mmap

near tartan
#

yea but how do you reference the files

#

they are stored in paths

lofty copper
#

My files are represented by memory objects in kernel

lofty copper
#

I haven't thought about it

near tartan
#

like, a dynamic executable will name a path to a ld.so which loads the shared libraries

#

which all assume a file path

lofty copper
#

Then I guess the init server + filesystem server or whatever will need to be statically linked

near tartan
#

i would solve this by compiling posix as freestanding

lofty copper
#

I don't like the idea of not having libc

near tartan
#

well, posix is essentially the backing part of libc

lofty copper
#

My libc talks to other servers lazily

#

So if you don't use open() then there is no issue with it

near tartan
#

i mean that's what happens in mlibc kind of

lofty copper
#

But I guess it could be freestanding now that I think of it

near tartan
#

you can implement mlibc::sys_open however you want

lofty copper
#

But my POSIX server is written in C++ and I use libc++ in it and it requires libc

near tartan
#

you could do like if (this.id == POSIX_ID) { ...

lofty copper
#

But I think it's a bit of a sloppy way to do it

#

But yeah

near tartan
#

would be really nice if pmos was in mlibc

lofty copper
#

I've been thinking about weak symbols or something

near tartan
#

for what?

lofty copper
near tartan
#

i'd use weak symbols for libmenix

#

or mostly vdso

lofty copper
#

I've been thinking about using vdso for syscalls

lofty copper
#

Just have a special libmenix

#

For POSIX server or whatever

near tartan
#

well my idea is to have libmenix implemented as a vdso actually

lofty copper
#

But like since it's a POSIX server, you can just not use POSIX functions inside it, and talk to servers directly

#

However you want it

lofty copper
near tartan
#

i mean you definitely need to open files

#

how you do that is on you

sick flax
near tartan
#

oh?

#

that's interesting

#

is the api the same or is it a special one for that case

sick flax
storm bobcat
#

a microkernel is typically much more complex

near tartan
storm bobcat
#

Have you ever made a shitty unix clone

#

That can run like bash and friends

near tartan
#

well i got to the bash prompt

storm bobcat
#

Basically you should have an idea of what a kernel entails before making a microkernel

#

Idk if that makes sense

near tartan
#

i'd like to believe that i do

late bramble
near tartan
#

i dunno man

near tartan
#

@lofty copper what kinds of things should i consider when designing a microkernel system?

#

just categories

lofty copper
#

IPC probably

#

Also you kinda need to decide what you want to have in the kernel vs userspace

#

I guess

near tartan
#

do you have uacpi in user space

grave peak
near tartan
#

damn

#

how does that work with smp?

grave peak
#

Wdym?

near tartan
#

does he just have the table structs in the header

#

so he can parse the madt

grave peak
#

He has a separate parser in the kernel for tables I think

near tartan
#

makes sense

grave peak
#

Same as nt for example

#

Without the acpi.sys driver it still has a table parser

#

For the core stuff

#

uACPI has a barebones mode for that

near tartan
#

i should design the entire system layout before i start writing code i think

#

if i actually follow through with this

grave peak
#

For a microkernel probably you should

storm bobcat
#

Do the NT thing and write a design book

near tartan
#

an entire book?

storm bobcat
#

Yea

#

I was joking tho

near tartan
#

hm

storm bobcat
#

Having a general design is good tho

#

Planned

near tartan
#

i guess i should touch on task management, object passing, data passing, privilege management and initialization

#

also abi

grave peak
#

Anyone who attempts nt stuff is based

near tartan
#

nt is cool except for the coding style

storm bobcat
#

The only thing that sucks about it is the typenames

grave peak
#

Yep

mental tinsel
#

or would it be Ke

#

I can never tell that all the prefixes mean

storm bobcat
#

there's also p for private

mental tinsel
#

internal external

#

ohh

storm bobcat
#

no

#

Ke is kernel

mental tinsel
mental tinsel
storm bobcat
#

its one of the various prefixes

#

you have Mm

#

Ob

mental tinsel
#

Ps

nocturne rampart
#

NtReadFile

#

NtCreateSection

mental tinsel
#

Old Technology Read File

nocturne rampart
#

In the kernel side it's referred to as Zw

#

ZwReadFile or ZwCreateSection

mental tinsel
# nocturne rampart ZwReadFile or ZwCreateSection

they're just naming it random letters 🙏🙏🙏

Introducing the Sybau subsystem

it features synchronization primitives like SybauWaitForSingleObject, as well as memory management functions like SybauAllocatePool

nocturne rampart
#

But the prefix makes sense

#

Po is power

#

Se is security

mental tinsel
mental tinsel
#

maybe make the Y stand for something else

fast mirage
#

so um

#

menix pipes when

ionic lava
nocturne rampart
ionic lava
nocturne rampart
#

Interesting

#

I've read that it means Zero Wait as well

#

Since it skips all the parameter validation that's done

ionic lava
modern hamlet
nocturne rampart
#

Fair point

modern hamlet
#

Also I'm not sure how they do this, but in the source code (as far as I've been able to hear from others), the functions are defined with the Nt prefix

#

How come they're exported as Zw

near tartan
#

im just gonna prefix everything with marvin_

autumn jasper
near tartan
#

yoooo

ionic lava
near tartan
#

just use MSFT lol

#

or PE64

eternal wharf
near tartan
#

yeah

#

Marvins Evil NIX

#

I've been meaning to find a backronym for menix

#

originally it stood for modular expandable unix

#

but that sounds a bit weird

modern hamlet
#

cant you just call those functions directly in kernel mode??

#

without going through any system call dispatching code

late bramble
near tartan
late bramble
near tartan
#

i know

#

no time

#

check out my personal """blog"""

late bramble
near tartan
#

lol

#

yea my domain only points to gh pages

fast mirage
near tartan
#

i should think of a cool name for the kernel

mental tinsel
near tartan
near tartan
#

#polls message

#

please vote :D

fast mirage
#

voted

idle flower
#

menix-kernel

ionic lava
near tartan
#

bruh

late bramble
#

@near tartan why Menix btw?

near tartan
#

originally stood for minmal expandable unix

late bramble
#

my kernel and OS are both called Maestro

near tartan
#

but i feel like that acronym kinda sounds like shit

late bramble
#

nah it's fine

vast lotus
#

it doesn't have to be an acronym

#

menix itself sounds fine

mental tinsel
#

freanix

near tartan
#

marvin's evil unix

ionic lava
#

Marvelix.

fast mirage
#

nyaux stands for

nya-ux

#

i.e
nya-unix

#

kitty unix idk

late bramble
#

maestro stands for maestro

marsh holly
#

astral stands for Astral aStral asTral astrRal astrAl astraL

mental tinsel
#

i think it stands for something idk

late bramble
#

works like a charm

near tartan
#

works like a os

mental tinsel
#

breaking news github now renders markdown in commit message headers? idk maybe this is an old thing

#

havent seen this before with the codeblock markdown

#

only with emojis

near tartan
#

i don't know if i like the concept of mbus

#

i think i might put named objects/properties in the kernel

distant cypress
#

named objects

that's called a filesystem.

near tartan
#

not really something structured

#

just named data that can be passed around

#

stuff like "acpi.rsdp"

distant cypress
distant cypress
near tartan
#

also this thing needs to work without a vfs running

distant cypress
#

you don't need a VFS to have file handles :-)

#

well

#

"file"

near tartan
#

i am going to follow the object capability model for most things

#

so i could just use objects for properties

near tartan
#

small diff

mental tinsel
#

miniscule

#

pales in comparison to pull request 447 to torvalds/linux

fiery marlin
near tartan
#

true

fiery marlin
#

apparently its a solvent

idle flower
#

it dissolves your sanity and free time

near tartan
#

ok sad news

#

I can't do vdso for libmenix because i want the system to be buildable with a freestanding compiler

modern hamlet
near tartan
#

wdym

modern hamlet
#

why are these two features mutually exclusive

near tartan
#

i could have libmenix be an entry point which loads the vdso and calls main()

#

mlibc ld.so depends on some hosted functions that I don't think i have access to at that point

near tartan
#

@lofty copper how does your ipc work on a theoretical level?

#

you create a port and send a message, right?

#

i'm assuming it's

port_create();
port_name("myport");

...

auto p = port_open("myport");
msg_t msg = malloc(sizeof(msg_t));
while(1) {
    port_read(p, &msg);
    switch (msg.num) { ... }
}
#

how would you pass e.g. a memory object between processes?

#

are object handles globally unique for every process?

lofty copper
#

I create a port, which has 1 owner thread that can receive messages, and everyone else can send messages to it

#

(At the moment it's everyone who knows the port id, but I've added rights/handles to it, which can be used as a permission system)

near tartan
lofty copper
#

Though I think it makes sense to also make memory objects rights as well now that I have that system

#

It's kinda expired by Mach I guess

near tartan
#

im looking a lot at fuchsia and zircon

lofty copper
#

I haven't looked into them

near tartan
#

and they basically move object handles through channels

lofty copper
#

Yeah, it makes sense

#

My rights are also basically handles I guess

near tartan
#

oh

#

so moving a handle from pid 1 to pid 2

#

does it transfer the right

lofty copper
#

Yeah

#

The sender looses the right and the reciever gets it when recieving the message

#

Getting a new id in the scope of its namespace

near tartan
#

so if i did

send(foo);
...
receive(&bar);
#

then the receiver has to send it back?

lofty copper
#

?

near tartan
#

like

#

how do you do shared memory

#

if i create a memory object in pid1 and move it to pid2

lofty copper
#

through memory objects

lofty copper
#

Idr

#

I don't really use shared memory

near tartan
near tartan
lofty copper
#

I think it had reference counting

#

It's a separate system from message rights at the moment

#

And it's a bit messed up

near tartan
#

i guess you need shared memory at least for posix MAP_SHARED

lofty copper
#

Yeah, but I haven't used it

#

And I think I had a capability to create shared mappings through fork?

#

I mean no

#

I do use shared memory for process creation and stuff

#

And CoW

#

I'm gonna disappear for an hour or so

lofty copper
near tartan
#

lol

near tartan
#

i wonder if its possible to do mostly shared memory IPC

#

i assume it could work for synchronous calls, but as soon as you need a queue the thing kind of falls apart

#

the idea i have atm is this

status_t link_create(link_t* out0, link_t* out1, size_t max_msg_size);
status_t link_connect(link_t link, const void** out_receiver, void** out_sender, uint8_t* out_doorbell);
status_t link_await(link_t);
  • link_create returns two endpoints
  • one endpoint gets transferred to the child process
  • link_connect maps a RO memory region for receiving and a RW region for sending, as well as a doorbell that can be rung to notify the receiver of a new message
  • link_await blocks until the sender has rung a doorbell
#

i'm not too sure about the doorbell thing, i haven't thought too much about how that would actually work without going through the kernel

#

link_await might just be a userspace function, waiting for something like msg_head.finished

#

damn this might explode without any form of synchronization primitive

lofty copper
#

I think

#

(maybe)

lofty copper
#

Because you have to think about scheduling

#

And servers and stuff

near tartan
#

yeah, i would probably have to have some form of notifying when you can read/write the queues

#

or i could say there's no such concept as a queue and make the user processes figure it out themselves

lofty copper
#

You could I guess

near tartan
#

I'd rather have speed over reliability, as weird as it sounds

lofty copper
#

My queues are in kernel

#

So to send a message it is copied to a kernel buffer, pushed to the message queue, and then copied into the receiving thread

#

The interface is more straightforward I guess and it's probably ok for small data

near tartan
#

yes that sounds fine

#

I don't even need doorbells or mutexes lol

#

i can just read the recv buffer on the sender side and wait for a reply

lofty copper
#

My mutexes are currently implemented with IPC

#

Yeah

#

The issue is with priorities in the scheduler and stuff

#

And also that mutex_unblock may fail if there is not enough memory to send a message

near tartan
#

that's where shared memory might be nicer since the queue is already allocated

#

i do have to think about how to do this stuff asynchronously

lofty copper
#

I think there are kernels which only do synchronous IPC

near tartan
#

that would make a lot of things easier

#

i mean technically speaking shared memory ipc is inherently async

#

i don't have to wait for a reply if I don't want to

#

i only need to manage queues somehow

#

@lofty copper do you have a max message size?

lofty copper
#

No trl

#

But I probably should

#

It was a semi-temporary solution

near tartan
#

i could say something like "every message is 128 bytes big"

lofty copper
#

But I've kinda stuck with it

near tartan
#

then queues would be very easy

lofty copper
#

Because fixing the size and preallocating the buffer makes things easier

#

At the moment I just kmalloc the buffer to the size that's requested by userspace

#

And like I've been thinking about it, but the only "problem" for now is performance

#

(which isn't really an issue at the moment)

lofty copper
near tartan
#

actually, yeah I don't even need queues

lofty copper
#

Minix has a queue of 1 element I think, and it blocks otherwise

#

You can probably do some notification thing?

near tartan
#

okay technically i don't need any notification mechanism

#

this can be handled by the user

lofty copper
#

Idk I think you need some mechanism for blocking if there's nothing to do

near tartan
#

oh yes, but that doesn't have to be part of the ipc

#

a semaphore for example

lofty copper
#

And at the same time you want something to wake up servers and potentially scheduling then immediately

#

Like sched_yield is not it

#

I guess it can be something simple and you can have nice userspace abstractions...

lofty copper
#

I think

near tartan
#

hm true

#

yea they are

lofty copper
#

So like semaphores + shared memory can work as a primary IPC mechanism I think

near tartan
#

yeah i think so

#

that would really cut down on time spent moving memory around i think

#

and is simple to implement in the kernel

#

because all it has to do is map memory

near tartan
storm bobcat
#

if you move through registers

near tartan
#

sure, but you make the shared page once and then you can basically write a stream to it

storm bobcat
#

Also fuchsia/zircon is basically mach reinvented

#

So its IPC is pretty similar to mach

storm bobcat
#

Most IPC is simple RPCs

near tartan
#

hm

storm bobcat
#

tho shared memory is very useful

near tartan
#

yea ofc

storm bobcat
#

I wouldn't use it for small messages

near tartan
#

but is it really faster to do a supercall vs just writing it to memory?

#

since you have two context switches

storm bobcat
near tartan
#

what project?

storm bobcat
#

The kernel Ethan and I were working on

near tartan
#

ah

near tartan
#

the idea was kind of to leave most of the actual ipc management up to the servers

storm bobcat
#

I guess you could setup a shared page per client on the server

near tartan
#

the kernel only establishes the link

near tartan
storm bobcat
#

And if the client does multiple calls you just reuse the page

near tartan
#

you create a link pair with send/recv buffers

storm bobcat
#

I'd look at sel4 IPC

#

They have a very small fastpath

near tartan
#

l4 does a lot of shmem ipc i've read

storm bobcat
#

their fastpath is through registers afaik

lofty copper
#

(probably)

near tartan
#

duh

#

nvm

near tartan
#

oh no i just realized i have to care about port permissions too now

marble salmon
#

if you're using names instead of capabilities, you're probably doing something wrong™

near tartan
#

what is this in response to?

marble salmon
#

just a general remark about how to design ipc systems

near tartan
#

ah

marble salmon
#

and permissions

near tartan
#

my plan was something like the posix api, where you get a pair of descriptors that a child can inherit

#

and handles having capabilities that control what you can do with them

#

korona you're probably the most qualified person to ask that i know meme, but how dumb is doing only shared memory IPC

marble salmon
#

if you want an L4 style IPC mechanism I'd look at NOVA

#

although NOVA can't transfer capabilities through IPC

#

but it'd be possible to add that on top

lofty copper
#

But the interface is the same?

near tartan
#

doesn't that mean that arbitrary clients can open connections to your server

lofty copper
#

If the server wants to, yes

#

But it's not really connections

#

You get a right to a port to talk to a server from the bootstrap server

#

You then talk to that server giving it a reply right

#

Like so it can reply to your IPC messages, send more capabilities and so on

near tartan
#

what exactly are capabilities and why does one send them around?

#

i thought capabilities are related to an object(handle)

lofty copper
#

A right to send messages to ports

#

Or handles to objects I guess

#

Like handles to ports?

#

So you can't just start sending random stuff to random processes

near tartan
#

yeah

storm bobcat
marble salmon
#

well, capabilities are handles plus permissions

#

there are also handles without permissions

#

for example, pidfd on linux is not a capability

#

because to send a signal to a process, you still need ambient authorization (= same uid/gid or root or CAP_SYS_ADMIN or similar)

#

but e.g., a unix socket fd is more like a real capability because if you have access to the fd, you can also send/receive

marble salmon
#

the issue with names is that you need an extra permission system on top

near tartan
#

what are some usual capabilities? RWX, movable, clonable?

idle flower
#

file, network, software services (zip ...)

lofty copper
magic charm
#

FreeBSD procdescs are true capabilities

near tartan
#

how does a microkernel normally handle cpu exceptions? managarm does something with observations, but i don't really understand it yet

storm bobcat
#

Wdym

near tartan
#

like, how do i get from an exception to e.g. a posix signal

storm bobcat
#

I'd just send a message to POSIX along with the thread handle or something with the exception

near tartan
#

directly from the kernel?

storm bobcat
#

Yes

#

Why not

near tartan
#

dunno

storm bobcat
#

You need kernel<->userspace communication for things like swapping anyways

near tartan
#

hm

#

another question is how i want servers to find each other

storm bobcat
#

bootstrap server

near tartan
#

how would that look? e.g. if i want to open an ipc connection to posix, could i do

object_t posix;
supercall(0, BOOTSTRAP_FIND, "posix", &posix);
object_t posix_link;
supercall(posix, POSIX_ESTABLISH_LINK, &posix_link);
link_connect(posix_link, ...);
#

i like this kind of interface

#

but not sure if this is "correct"

storm bobcat
#

tf is a supercall

#

you should really read about existing microkernels

storm bobcat
near tartan
#

is it that bad 💀

storm bobcat
#

Managarm? No, but you should study actual research kernels vs hobby stuff

near tartan
#

no i'm talking about my example

#

like this is the most straightforward thing i can think of, you make an rpc call to another server to request further operations

storm bobcat
#

In practice you have an IDL

near tartan
#

in this case creating a channel or whatever

storm bobcat
#

That does it for you

near tartan
#

i kind of wanted to go in blind, because this is a hobby project, but i don't see that many differences tbh

#

i guess minix is a bad example

#

they don't use an IDL

#

and i don't like that either really

near tartan
#

without much research

#

but i guess there's no way around it

#

usually stuff that i could find are just random slides without any context

storm bobcat
#

What you want is papers

near tartan
#

what topics should i look for? just ipc?

#

because i guess ipc is the thing that makes or breaks a µkernel

storm bobcat
near tartan
#

fair enough KEKW

#

gonna look into l4

lofty copper
#

I think Mach does something like this as well

near tartan
#

yeah see the snippet right below

#

i hope i'm on the right path, because i don't really want to just copy another kernel's logic

#

sure i can """"inspire"""" myself, but coming up with things myself feels infinitely more rewarding

#

w/e

lofty copper
#

But my kernel doesn't have links

#

Like my ports are unidirectional

near tartan
#

then you have a reply port i see

lofty copper
#

But like you can pass the handle to another process and stuff

#

(in theory)

#

(so idk if I like having an explicit reply port)

near tartan
#

my idea with links is that there's exactly one pair for every connection

#

so you can't pass handles to other processes directly, you'd have to go through syscalls first to transfer them

lofty copper
#

So basically pipes

lofty copper
near tartan
#

well yes in your case, but not mine

near tartan
#

you ask the target server to allow a connection, if it accepts, it gives you the other end of the link

#

which you can then connect to

storm bobcat
#

Why wouldn't it accept

near tartan
#

oom? just theoretically

storm bobcat
#

What

#

If there's OOM the kernel will notice first

near tartan
#

no like, for example if you request a shared memory region with a bogus value

storm bobcat
#

Why would the server sanitize that?

#

And why would the memory address be exposed?

near tartan
#

the kernel will return an error to posix, which in turn makes the call return an error

storm bobcat
#

or just return an error in the program directly

near tartan
#

in the calling program?

#

im so fucking confused lol

storm bobcat
#

If it tries to do a shitty syscall it's the kernels job to stop it not the server

storm bobcat
#

Not the server

#

So the kernel returns the error

#

The server never has knowledge of it if there's an error

near tartan
#

i know that, but it's just propagating it back to the client. when you create a shared memory region you get two endpoints. you want one handle on the posix side, and one on the client side. you ask posix for a new connection, which makes posix do the syscall and return back a handle to one of the endpoints.

#

if the syscall in posix fails, it returns that error from the rpc call

#

maybe I'm thinking about it wrong, but i don't see why this is so terrible

storm bobcat
near tartan
#

maybe I'm missing something

storm bobcat
#

Yes

near tartan
#

how am i supposed to move handles between processes if I'm not allowed to arbitrarily request things from a server

#

because somehow both the server and client need to know about the shared memory region

storm bobcat
#

This doesn't make sense

near tartan
#

like if you ask for a region of size -1

storm bobcat
#

Why would the client doing establish_link(POSIX, whatever, crap) cause an error in POSIX?

near tartan
#

i believe i see the issue. i said that the client asks posix to create the link (where the syscall may fail), and then returns back one handle, but the client can also create the link by itself and just send one handle to posix?

#

does that explain what I'm trying to do?

storm bobcat
#

Why doesn't the client just get a handle to POSIX then sends messages along with a reply handle or something

near tartan
#

that's just message passing then. the example i was trying to show was for setting up shared memory ipc buffers

storm bobcat
#

Shared memory is a form of message passing

near tartan
#

okay so

near tartan
#

the one that goes through the kernel

#

because i will likely need both forms

lofty copper
#

There's shared memory and there's message passing

hoary cave
#

also there isn't a single way to implement that either

storm bobcat
near tartan
#

true

storm bobcat
#

anyway I still dont understand what you mean

near tartan
#

i want a shared region between posix and a client

#

how

storm bobcat
#

client:

handle posix_handle = get_posix_handle();
setup_link(posix_handle);

// Why do you need this and why would this ever fail!?
posix_set_up_connection(posix_handle);
lofty copper
storm bobcat
#

you can synchronize on shared memory

lofty copper
#

But I think those were 2 fundamental ways to do IPC

storm bobcat
#

message passing just typically means its copied

near tartan
#

and to actually get a writable address, you "connect" to a link

storm bobcat
#

but setup_link is a syscall

#

so the kernel handles shit parameters

near tartan
#

okay I'm going to revise this example

handle posix = get_posix_handle();
handle link1, link2;
if (link_create(0x1000, &link1, &link2)) {
    panic();
}

// How do i best move one of the link endpoints over?
send_msg(posix, POSIX_FOO_MSG, link1);
storm bobcat
#

yeah that is fine

storm bobcat
#

how can you send a message to posix if you dont have a handle to it/the link isnt set up

hoary cave
#

you can't

near tartan
#

probably brainfart cuz it's late, but the above example would've looked like this (very roughly)

handle posix = get_posix_handle();
handle link;
// posix server runs the syscall to create the shared memory
send_msg(posix, POSIX_ESTABLISH_CON, link);
recv_msg(&link);
#

but that's just more effort than the one above

storm bobcat
#

how do you send a message if shared memory isnt setup yet

#

this doesnt make sense

near tartan
#

that's where i wanted to use supercalls before (like signal handlers that a server would register beforehand)

near tartan
#

the problem i have is literally just "how do i move the link handle to the other process, if i need the link to send messages"

storm bobcat
#

yes

#

so this is a bad design

near tartan
#

but how is this possible? if you have no way of talking to another process, how can you bootstrap anything nooo

#

something similar to fork() could work, where the children of the bootstrap server inherit the handles

#

but then I couldn't arbitrarily connect to a server

storm bobcat
#

this is literally how it works

#

you have a permanent handle to bootstrap

#

and ask it to get an handle to posix

#

which posix registered beforehand

near tartan
#

okay so there is always a link to the bootstrap server at least

#

yeah I'm a brainlet confirmed

near tartan
#

or is shared memory also allowed to have multiple writers? that sounds weird

near tartan
hoary cave
#

where do you get the posix handle from

near tartan
#

bootstrap server

hoary cave
#

okay

#

instead of returning a handle to posix you can just make it set up a link for you

near tartan
#

oh

hoary cave
#

and how is posix going to receive if it doesnt have the other end?

#

bootstrap should give you one end of the link and posix the other end with some sort of message maybe

#

idk

#

idk how your "links" are supposed to work but yeah

#

is it just a pipe for messages?

#

meaning what you put() on one end can be get() on the other?

near tartan
#

links are just shared memory kernel objects that you can map

hoary cave
#

wtf

near tartan
#

why wtf

hoary cave
#

idk seems like a bit weird of a name

#

i'd expect a link to be a pipe lol

near tartan
#

what would you call it

near tartan
hoary cave
near tartan
#

my idea was that you create it and you have two endpoints. one you keep, the other gets moved. you can "connect" to a link, which gives you a pointer to RW memory for sending and a pointer to RO memory for receiving.

#

so you have some sort of bidirectional communication via shared memory

#

maybe it's braindead, I can't tell

hoary cave
#

i like what managarm does with hel queues but i'm not sure if or how that works across processes

#

it's kinda similar to what you're saying but not exactly, you can helCreateQueue with some parameters that describe the in-memory layout of it and then you get a handle which you can use to map the queue in memory and from here you use futex to communicate with the kernel when you put something on the queue

#

i think that's a nice way to handle async ipc

#

each element on the queue carries some data, and if the data isn't too much you can embed it directly in the queue element

near tartan
#

yea for synchronization i was going to use futexes too

hoary cave
#

there's some ref counting done on each element to make sure it isn't reused by the kernel before you are done reading from it etc

near tartan
#

so each queue element is fixed size?

hoary cave
#

no

#

you can have smaller elements if they don't need much data

#

like a simple result that says "ok or error"

#

you can transfer data inline in a queue element too if you want

#

or just pass a pointer if it's a lot of data and it'd be better for the kernel to copy it instead

#

i'm 90% sure that queues are used for message passing and lanes actually let you talk to difference servers

#

you basically put a message on the queue with a lane handle and the kernel fulfills a request on the other side of the lane

#

so if one server puts a "receive" on the queue and you "send" then that completes the request

near tartan
#

so wait the queue itself lives in userspace but the kernel accesses it?

hoary cave
#

no

#

it's a kernel object

#

and a thread can map it to access it

near tartan
#

right

#

rw or readonly?

hoary cave
#

read write

#

that's why you can't bind to hel queue safely in rust

#

:^)

near tartan
#

then does it work like

auto q = create_queue();
map_queue(q, &whatever);
*whatever = message_t {123};
queue_submit(q);
hoary cave
#

far from that but sure

near tartan
#

bruh

#

im too stupid

hoary cave
#

okay sorry, i kinda trolled

#

the actual message submission is done using a syscall

#

there's a few helSubmit* syscalls

near tartan
#

i saw that you can submit an array

hoary cave
#

the one used for actual message passing is helSubmitAsync

#

that's the one you probably saw

#

because it takes a bunch of actions

#

the queue is used for notifying user space of completions

#

the kernel will put a completion on the queue and then futex_wake you

near tartan
#

ohhhh

#

that makes more sense

hoary cave
#

here's an example of submitting something

#

what that does is it creates an async operation on the kernel side, it waits until the time reaches provided timestamp and it submits a completion to the provided queue, the context is an arbitrary pointer sized value

#

i'm not sure how exactly it works on the kernel side so i can't say much

#

but still, that's a neat way to do async ipc

near tartan
#

true

#

would you flame me if i said that totally async ipc may be overkill

hoary cave
#

nah i don't really care

near tartan
#

like, i could write a message to the send buffer, move on and until i want to send another message i can do whatever without waiting for a response

#

that's technically asynchronous, although limited

storm bobcat
#

so fully async isnt needed

hoary cave
#

async is cool though,,,

mental tinsel
#

you get more brownie points for async IPC

marble salmon
#

re shared memory: one issue with shared memory only is that you have to be really careful when using shared memory with untrusted clients

#

as they may corrupt the shared memory data structures

marble salmon
#

but it's interface is quite centered around async IPC so if you want to do sync IPC, there's certainly stuff that you'd want to do differently

stiff stream
near tartan
#

i don't think i can do anything to prevent that from happening, so i just need to assertos more

marble salmon
#

well, the solution is to not assume that the shared memory data structure is in a sane state

near tartan
#

does it make sense to combine the bootstrap server and the posix server? one issue i could think of is if something crashes posix, it takes bootstrap with it, stalling the entire system

#

though if posix crashes the system might as well be stalled

marble salmon
#

it depends on what your goal is

near tartan
#

i'm just experimenting. if many calls end up going through bootstrap just to go to posix and back, it would probably be faster if they're one server.

#

if the only thing i have to do is creating a link, then it's fine

hoary cave
#

any kind of proxy like that would probably be a result of a bad design

idle flower
#

I plan to ensure correct shared memory ring buffer control datastructures by having two sets of of them per client-server pair (not per connection) and one is mapped as readonly for the other

#

These pages contain all data for all connections/channels between the specific client-server pair

#

And a third one that's ro for both that specifies the ringbuffer size and stuff

#

Also the sender view for the ringbuffer is mapped as WT on x86

#

One connection consists of two Uni directional ring buffers

near tartan
marble salmon
near tartan
#

i don't get how it protects anything

marble salmon
#

It doesn't help a lot because the only thing that it ensures is that the write side can be sure what changes it made to the buffer

#

but it doesn't allow you to remove any checks from the read side

#

and the write side is usually not a problem anyway because it doesn't need to store state inside the buffer

marble salmon
#

WT doesn't have any advantages over WB for normal RAM

idle flower
idle flower
idle flower
#

So no cache pollution for the writer while still allowing a cache to cache path for the data

idle flower
marble salmon
#

x86 caches are physically tagged so this also means that the data are not in the cache when the reader wants to read them

idle flower
#

The reader will issue L1 and L2 prefetches before reading

#

L2 prefetch for further away cache lines and L1 prefetch for the next few lines

marble salmon
#

This is 100% going to be slower than WB

#

Have you actually tried it out?

#

It's only ever going to be faster if the reader doesn't run immediately after the writer

#

So it's only fast on the path where you don't care so much about latency

#

Prefetching sequential accesses has not helped on x86 for the past 10 years or so

#

since the cpu prefetcher does that already

#

In the best case you gain a few % on the code path where latency is not important, in the worst case you're slowing down the communication by 10%+ due to the increased bus traffic from the WT

marble salmon
#

Besides, you can achieve the same thing without messing with WT if you use non temporal stores or movdir64b

storm bobcat
#

Tho it's not published by a university

near tartan
#

university = woke

#

smh

storm bobcat
#

Unless it is and I'm missing it

marble salmon
#

It is published

#

At a small (but properly peer reviewed) symposium

idle flower
marble salmon
#

that is true

#

But in the case where the line is already cached, WT is useless anyway

#

Or rather, simply inferior to WB

#

since WT generates extra bus traffic for no gain in that case

#

the only reason to use WT is if you want to read from memory that has write side effects

near tartan
#

iretq said calling shmem ipc a "link" is misleading, what would be a better name for it?

hybrid island
#

I haven't heard it called anything other than shared memory IPC or some contraction of it.

near tartan
#

i need a name that's not totally annoying to type out

#

menix_shmem_create();?

#

oh right another issue, how do you transfer object handles with only shmem ipc

#

sure you can send the handle value, but that doesn't send the actual object reference i think

hybrid island
#

If you mean a kernel-managed object like FDs for example I'm not sure you can even share those over IPC?

near tartan
#

in zircon, there's an extra ipc mechanism just for sending handles

#

maybe i need an extra syscall for that

hybrid island
#

Also the way Linux does shared memory is to do mmap on some file with MAP_SHARED. IIRC there's even a specific file type so you don't have to allocate actual disk space.

near tartan
#

?

#

i fail to see how that's relevant here

hybrid island
near tartan
#

for ipc between servers

hybrid island
#

Wait are you gonna microkernel?

near tartan
#

trying my hardest to...

hybrid island
#

I see what you're trying to do now

#

But yes, you'd need a discrete IPC type for sharing/sending handles like this

#

And use shared memory for faster transfers of bulk data ofc

near tartan
#

so could i have a dedicated handle transport

#

or a supercall that allows the transfer of x handles together with a message

#

wait a minute that's just exactly what zircon channels are

hybrid island
#

Then knowing the ID is the authorization to use it.

#

Not saying this is a good idea necessarily

near tartan
#

then you'd have a global list of handles meme

hybrid island
#

Yes

hybrid island
#

And also hope you like having a receiving process suddenly lose the handle when the sender closes trl

lofty copper
storm bobcat
#

cant you just predetermine an area in shared memory where handles transfer could occur

#

or something

mental tinsel
#

hardcode it trl

near tartan
#

i could do something like io_uring?

#

where you prepare a buffer of operations and submit them

near tartan
#

i guess i could handle this with page faults

storm bobcat
#

no this is stupid

near tartan
#

like a doorbell, where writing to the region triggers an operation

storm bobcat
#

dont do it

near tartan
#

woe