#Maestro - Linux-compatible-ish OS in Rust

1 messages ยท Page 6 of 1

young ermine
#

yeah i was just curious, i personally find that part very nice to work with

late oar
#

I just wasn't expecting to have to use so many registers

late oar
#
  • update Rust
  • kernel modules don't build anymore
    ๐Ÿ’ค๐Ÿ’ค๐Ÿ’ค๐Ÿ’ค๐Ÿ’ค๐Ÿ’ค๐Ÿ’ค๐Ÿ’ค๐Ÿ’ค๐Ÿ’ค
late oar
inner pilot
#

what exactly is broken?

#

the build?

late oar
# inner pilot what exactly is broken?
$ ../build
   Compiling ps2 v0.1.0 (/home/luc/Desktop/dev/maestro/mod/ps2)
error: linking with `x86_64-elf-ld` failed: exit status: 1
  |
  = note:  "x86_64-elf-ld" "--version-script=/home/luc/Desktop/dev/maestro/mod/ps2/target/x86_64/debug/deps/rustcnzzO0n/list" "--no-undefined-version" "/home/luc/Desktop/dev/maestro/mod/ps2/target/x86_64/debug/deps/rustcnzzO0n/symbols.o" "<31 object files omitted>" "/home/luc/Desktop/dev/maestro/mod/ps2/target/x86_64/debug/deps/rustcnzzO0n/rmeta.o" "--as-needed" "-Bstatic" "/home/luc/Desktop/dev/maestro/kernel/target/x86_64/debug/libkernel.rlib" "/home/luc/Desktop/dev/maestro/kernel/target/x86_64/debug/deps/libcore-0ea7efbfa1b40ef8.rlib" "-L" "/home/luc/Desktop/dev/maestro/mod/ps2/target/x86_64/debug/deps/rustcnzzO0n/raw-dylibs" "-Bdynamic" "--eh-frame-hdr" "-z" "noexecstack" "-L" "/home/luc/Desktop/dev/maestro/kernel/target/x86_64/debug/deps" "-L" "/home/luc/Desktop/dev/maestro/kernel/target/debug/deps" "-o" "/home/luc/Desktop/dev/maestro/mod/ps2/target/x86_64/debug/deps/libps2.so" "-shared" "-soname=libps2.so"
  = note: some arguments are omitted. use `--verbose` to show all linker arguments
  = note: x86_64-elf-ld: /home/luc/Desktop/dev/maestro/kernel/target/x86_64/debug/libkernel.rlib(kernel-1a6ff93b310e3a7e.9ihszl50ykblvwpc6ktwsaep5.0am2d36.rcgu.o): relocation R_X86_64_32 against symbol `multiboot_entry' can not be used when making a shared object; recompile with -fPIC
          x86_64-elf-ld: failed to set dynamic section sizes: bad value
          

error: could not compile `ps2` (lib) due to 1 previous error
silent lava
#

That's what causes this

inner pilot
#

mfw assembly

late oar
#

currently writing that blog article

late oar
#

can't put the current context to sleep in the NVMe driver when reading the disk before the PID 1 process been created because putting the context to sleep requires to be in a process

#

๐Ÿ’ค๐Ÿ’ค๐Ÿ’ค

#

I need to put it to sleep to wait for an interrupt after adding something to the submission queue

solid rose
#
if (this_process) {
    put_process_to_sleep();
} else {
    busy_wait();
}
late oar
#

or should I create the PID 1 process before any disk access?

#

that means I cannot immediately open stdin/stdout/stderr, but I can add them later I guess?

solid rose
late oar
# solid rose why?

when creating the PID 1 process I do:

let tty_path = PathBuf::try_from(TTY_DEVICE_PATH.as_bytes())?;
let tty_ent = vfs::get_file_from_path(&tty_path, true)?;
let tty_file = File::open(tty_ent, O_RDWR)?;
let (stdin_fd_id, _) = fd_table.create_fd(0, tty_file)?;
shell tusk
late oar
#

putting the idle thread to sleep is a bad idea

#

should I have a kernel thread while booting?

solid rose
solid rose
late oar
#

how do you handle that? @shell tusk do you have a kernel thread from the very beginning?

solid rose
late oar
solid rose
#

hmm

shell tusk
#

before that it doesnt sleep at all (controlled by init dependencies and shit) and after that it can sleep

late oar
shell tusk
#

yeah

nimble grove
#

my 2 cents are that initializing the scheduler, in particular the idle threads (one for each core), then switching into an initialization thread (which can safely block, because it is not an idle thread), is literally the very first thing done by the kernel proper in NT

#

(aside from basic architectural initialization)

#

this is done long before any drivers are up

#

or other subsystems

late oar
#

sounds like I should do that then

#

*cracking knuckles sound*

nimble grove
#

OH MY GOD ALL OF YOUR FINGERS ARE BENT THE WRONG WAY WHAT THE HELL HAPPENED

#

DO YOU NEED AN AMBULANCE

tough onyx
# nimble grove or other subsystems

what I do is I initialize my equivalent of Ex in a thread and that's done after SMP bringup and kernel initialization, but smp bringup requires memory allocation so a portion of the vmm is also initialized there so it's probably not as clear of a distinction as NT

late oar
#

lmao

nimble grove
tough onyx
#

to allocate per-cpu data

nimble grove
#

chads do this in the bootloader/prekernel

tough onyx
#

I dont have that

#

so theres no real other way of doing it

#

i have an early vmm init

#

then I do full vmm init in ex_init

#

(which includes the per-cpu caching portion of the slab allocator)

silent lava
silent lava
tough onyx
#

I think that's what I do too

#

well

#

no

silent lava
#

Like rustc, my CPU-local data is just heap allocated

tough onyx
#

I mean i do the early vmm init before the scheduler

silent lava
#

Does your complete VMM init depend on your scheduler, then?

inner pilot
#

my percpu data is only partially allocated at runtime

#

the bsp always has its percpu data as part of the kernel binary, and is only extended by modules

tough onyx
#

well yeah the bsp is statically allocated

late oar
late oar
#

maybe I should make log messages prettier by adding colors, a status (info, warning, error, etc...) and the uptime before them

inner pilot
late oar
#

@inner pilot you can't get the uptime before initializing clocks, right? do you just display messages without uptime before you init those?

inner pilot
#

linux does too iirc

late oar
#

makes sense

#

thx

late oar
#

with github making you pay for self-hosted runners I am now considering using something else than github actions for this project

young ermine
#

pretty sure they rolled it back

#

because it makes no sense

solid rose
late oar
young ermine
#

it works

late oar
#

I have written a 2025 retrospective blogpost for Maestro, now I just need to make a banner for it and I'm ready to post it. tomorrow I guess unless I find something wrong in it

late oar
#

quick banner I made for the blog article (not sure for the font)

#

will reuse it for the next years

late oar
late oar
young ermine
#

the 30 line vibe coded program ๐Ÿ™

inner pilot
silent lava
#

You laugh but for programming this kind of "quick'n'dirty" thing is exactly what LLMs are good at.

inner pilot
#

i am not pretending like i wouldn't do that

young ermine
#

i am not pretending either, because i wouldn't

#

especially when there's literally a crate for it

late oar
young ermine
#

you used it

#

or rather, the AI used it

#

converting between color spaces is the (arguably) hard part

late oar
#

i thought you were saying "there's a crate specifically to turn oklch to hex in svg files"

young ermine
#

oh no lol

#

that would be insane

#

but again, it's rust, what hasn't been done

late oar
#

tons of things have been done but badly

young ermine
#

that's the beauty of it

#

you google waht you are looking for

#

and find a shitty crate

#

that depends on nothing but still pulls in std and for some reason it hasnt been updated for 10 years

late oar
#

I never trust crates that don't have many downloads or haven't been updated for more than a few months

young ermine
#

mfw "there's a crate for everything" but it turns out there are no crates for nothing so u gotta write everything urself

desert hearth
late oar
#

Drew DeVault emailed me to congratulate me for my last blog article. This is the second time he emails me so I guess he's following my blog

late oar
#

so, I need to figure out how interrupts and PCI work together

#

for my NVMe driver

#

so that I can get an interrupt when something completes

inner pilot
late oar
#

like, I don't even need a NVMe driver, I could just use IDE halfmemeright

magic cloud
desert hearth
#

Iirc the nvme spec requires MSIs to be supported, so no need for the legacy interrupt goop

inner pilot
#

right?

desert hearth
#

I can't remember off the top of my head

#

It says something about the msi capabilities no longer extensions, but individual capabilities are still opt-in?

inner pilot
#
PCI Express permits devices to use these legacy interrupt messages, retaining software compatibility with PCI drivers, but they are required to also support MSI or MSI-X in the PCI layer.
desert hearth
#

Oh nice

#

I mean still permits legacy behaviour

#

So kind of useless but nice that they encourage it

inner pilot
#

yeah but msis are mandatory which is what you want

late oar
#

I support only PCI and not PCIe. Is PCI still worth it or should I switch to PCIe only?
Also, do I need PCIe for NVMe with interrupts or is PCI fine?

magic cloud
#

pci is fine

#

and support both pci and pcie

errant venture
#

pcie is backwards compatible with pci

#

unless you wanted to say ECAM

#

in which case you only need it for more advanced features and it also allows you to avoid locking around pci accesses

late oar
#

nice

late oar
#

I do be implementing MSI and MSI-X right now

late oar
#

been looking at PCIe and it looks easy to implement once you have PCI

late oar
#

my NVMe on QEMU doesn't seem to have the capability for MSI? Is there an option to add on QEMU or is it an issue on my side? I am re-checking my capabilities enumeration to make sure it is correct

inner pilot
#

or also msi-x

late oar
#

alright guys I'm stoopid

#

the capability for MSI-X is 0x11, not 11

late oar
#

on the NVMe driver I have the fatal status flag set after init (but before identify), I am searching why

late oar
#

can't work, busy playing clair obscur

inner pilot
#

๐Ÿ˜ญ ofc you are playing that

late oar
#

Best game I've played in a while btw, I highly recommend it

tough onyx
#

Amazing game

#

Lune pronounced loonay tho ๐Ÿ˜ญ

inner pilot
#

bruh

late oar
#

now I am trying to send a command and I get no interrupt for completion, searching why

#

I didn't even try polling though, maybe I should do that first to help me figure out where it comes from

inner pilot
inner pilot
#

you have to tell the nvme controller what interrupt it should fire

late oar
inner pilot
#

do you use these registers

late oar
inner pilot
#

you should meme

late oar
#

how

inner pilot
#

bro is copying astral code smh

late oar
#

@shell tusk how

inner pilot
#

you apparently need it for MSI

late oar
shell tusk
#

and thus:

late oar
#

right

#

well I am using MSI-X right now so I don't need those

#

probably means my MSI-X stuff is broken I guess

shell tusk
#

qemu nvme tracing to the rescue

late oar
shell tusk
#

yes

#

--trace nvme* or w/e

#

it prints a bunch of info about what nvme is doing

#

including if it is raising an irq etc iirc

late oar
#

no fucking way

shell tusk
#

qemu also has trace msi I think

#

its very handy for debugging

late oar
#

that would probably have saved me entire days if I knew about this feature before halfmemeright

#

alright I've got pci_nvme_irq_msix raising MSI-X IRQ vector 0

#

no interrupt received for now though

shell tusk
#

your msix code is borked then

late oar
late oar
magic cloud
#

cring

late oar
magic cloud
#

no u

late oar
#

Interrupt handlers are now FnMut instead of fn. Meaning I can now use closures that capture stuff

late oar
#

I can now identify the controller and list namespaces on it

#

Now, trying to identify individual namespaces. I am looking in the spec for the structure it returns

late oar
#

alright, now let's create the I/O submission/completion queues

late oar
#

dead project

#

ima still working on it (nvme in particular), but im slow

inner pilot
#

you get a fosdem pass

late oar
#

i do be willing to have a desktop env

#

once I'm done with nvme, I'm starting the port of xorg

late oar
#

should I assume (at least for now), that filesystem blocks size = page size (4096), and if this is not the case, mouting the filesystem fails?

#

also, should filesystem data be memory-mapped in kernel space? because I don't have a mechanism for memory-mapping a block device in kernel space. that works only for userspace

nimble grove
#

to overuse a cliche that sounds like xy problem

#

the first thing

#

whats making you afraid of filesystem block size being less than the page size

late oar
#

no the opposite. having blocks larger than a page size

nimble grove
#

did you mean <= rather than =

#

and yes that assumption is currently made in all modern vmms that im aware of

#

wait wait wait

#

SECTOR SIZE <= page size is commonly assumed

#

as in the minimum addressible block on disk

#

filesystem block size <= page size is not

#

and is regularly violated by things like fat32 which can have clusters (blocks) up to 64kb or something

#

in that case you just read partial fs blocks into page cache pages

late oar
#

should the page cache store only chunks the size of a page? because my struggle is about having different sizes in there

#

let's say the sector size is 4096, and the filesystem block size is 8192.
Someone reads from the block device directly -> that inserts a 4096 bytes entry in the page cache
now the filesystem attempts to read the same location from the page cache. The entry is 4096 bytes large, when it requires 8192

#

I am probably over-thinking something. I think the solution to this problem is probably a lot simpler than I imagine

late oar
nimble grove
#

the fractional fs blocks you read will be composed of an integral number of disk sectors so

#

theres no complication

late oar
nimble grove
#

i have implemented this so im not talking out of my ass

nimble grove
#

if thats an on-disk file then ideally you can DMA directly into the cache pages

#

a page cache page contains file data for a consecutive run of bytes within the file

#

so the underlying sectors could be at random locations on the disk

late oar
nimble grove
late oar
nimble grove
#

see my response in #filesystems

regal lantern
late oar
#

I'm working with a friend to put github actions to trash and potentially use drone ci instead

#

Also I am struggling to refactor my page cache

late oar
#

If I setup a second interrupt with msi-x, the previous one isn't working anymore, so I think I fucked something up

late oar
#

I am realizing my kernel really doesn't have enough logs

late oar
#

mistral AI actually managed to find the cause of an issue in my kernel

#

incredible

late oar
#

when I try to read a page at LBA 0 or 8 it's alright, but when I attempt LBA 536 I don't get any completion interrupt (even though --trace on QEMU tells me an interrupt has been sent)

#

weird

magic cloud
#

like perhaps you forgot to clear status bits or something

#

causing it to not send any further IRQs

#

unless i misunderstood the situation

late oar
#

alright I think it doesn't actually have a relationship with the LBA. The issue arises at the 3rd read regardless of the LBA

late oar
#

alright Im stoopid

#

I am removing the nvme controller's interrupt handler once it is initialized because I am dropping the controller's structure, because I didn't keep it anywhere once initialization is done

#

so that's why I don't get interrupts anymore

late oar
#

I am close to having the nvme work.
The last issue I am having is the following:
When I exec the ELF for the PID 1 process, I create a new virtual memory context onto which I build the programme image from the ELF.
To build this image, I temporarily switch to this memory context. This temporary switch enters a critical section, which is exited when getting back to the original context.
In the new memory context, I map the ELF at the required locations, and I fill the requires parts with zeros.
Filling with zeros triggers a page fault, and the handler reads the content of the ELF to put it into memory.
Reading from the file uses the NVMe driver, which puts the process to sleep until the operation is completed.
The operation completes, but the process cannot resume since we are still in a critical section -> the kernel is stuck

#

maybe I should have a debug_assert in the reschedule function to check we are not in a critical section?

nimble grove
#

what is a critical section here

#

a spinlock?

late oar
nimble grove
#

yeah generally speaking you cannot take a page fault while preemption is disabled

#

a page fault may inherently lead to blocking which defeats the purpose

#

so youll need to find some other way to do that

late oar
#

alright

#

that wasn't an issue before because I only had PATA with polling halfmemeright

#

also I should probably write something to allocate interrupt IDs, because right now I am using hardcoded ones

inner pilot
#

when framebuffer

late oar
late oar
#

I am removing the thing to temporarily switch to another memory context, but that means I have to rewrite the function to read from another process's memory (required for /proc/<pid>/mem and stuff)

#

that's annoying

late oar
# nimble grove why remove that entirely

Doing it without a critical section fucks up context switching because when restoring the context, it would be using the process's virtual memory instead of the one we temporarily switched to

nimble grove
late oar
#

I think I've managed to run the init program, but it's extremely slow. Way more than when using PATA

late oar
#

Alright, time for that moment in my life where I start to think I am a total failure

late oar
#

I guess I'll attempt using uftrace today to figure out what's wrong

late oar
#

So, the tracing tells me one of the issue (maybe the whole issue?) is the following:
When waiting for the nvme interrupt to come, we put the process to sleep and switch to the idle task (so far so good), but when the interrupt comes, we handle it and wake up the corresponding process, and then instead of switching back to the process directly, the kernel keeps looping on the idle task until the next tick indicating we must switch context

#

I have that function (preempt_check_resched, same name under Linux) I call at the end of every interrupt handler, where I check if a tick was received, and if we are not in a critical section (disabled preemption), in which case I reschedule. Should I modify this function to reschedule if we are running the idle task and another process is waiting for CPU time, even if the tick hasn't been received yet?

#

now that I think about it, this may also be the reason why pipes are so slow

late oar
#

fixed, see #schedulers message

late oar
#

The next issue is that interrupts handler are behind a spinlock because they are not per-core yet. That produces a deadlock when there is a nested interrupt.
As a solution, I will make them per-core

balmy plume
#

do you support interrupt priorities?

#

if not, there should be no nested interrupts

#

and if yes, there should still be no nested interrupts for the same irq

late oar
balmy plume
#

by assigning a priority to each interrupt and blocking all interrupts below the current priority

#

for example by using cr8 on x86

#

but if you don't have it, you also shouldn't have nested interrupts

#

since nested interrupts without any limit will potentially stack overflow

late oar
#

the fact that I do the End Of Interrupt before unlocking the spinlock probably is an issue

balmy plume
late oar
#

right

late oar
#

okay I think this is not actually a nested interrupt, but rather:

  • Process 1 page faults, locking the IRQ handler's spinlock. We use the NVMe controller to read the page from disk, we put it to sleep until we get the completion
  • Process 2 resumes
  • Completion for process 1 arrives, we enqueue it to run at the next scheduler tick
  • Process 2 page faults, attempts to lock the IRQ handler's spinlock -> deadlock
balmy plume
#

you should not sleep with spinlocks taken

late oar
#

yeah this spinlock's gonna go

#

i'm making it per-cpu

silent lava
#

Why is there a spinlock for the concept of page faulting on a process anyway? Seems to me that you'd rather have some locks in the memory map?

late oar
silent lava
late oar
silent lava
pastel summit
late oar
late oar
#

So I wanted to have interrupts per-core. So that when I register an interrupt handler, I can just disable interrupts during the insertion so that I don't need a spinlock. That works, but only allows to register/unregister interrupts on the current core.
However I just realized this might be a problem when registering an interrupt in a kernel module.
When I do finit_module, the init function of the module is called on the running process's core (same for delete_module). In this init function I sometimes register interrupt handlers.
The issue is: if I unregister that interrupt handler when calling delete_module, it might be a different core than the one where the interrupt handler was registered.
How do I handle that?

pastel summit
#

also helpful as on some architectures there is one IPI vector only

late oar
#

I have something to defer a function call to another core using IPIs, that I could use to register the handler on another core, but that seemed a bit overkill

late oar
#

need to find motivation to do stuff

inner pilot
#

dont we all

solid rose
#

yup

pastel summit
#

it comes in bursts of several months for me

#

then it fades and something else cycles in

deft sonnet
late oar
#

NVMe working ๐ŸŽ‰

#

I'm making sure the CI passes. I'll probably do a few modifications (like change the interrupt ID being used, by allocating some dynamically) and then I'll merge that into master I guess

#

@teal dock u alive???

#

also I'll write a blog article about NVMe

teal dock
late oar
late oar
#

after NVMe, the next step is graphicsโ€ผ๏ธ

#

@inner pilot how do I display stuff on screen?

inner pilot
#

you write pixels to an fb

late oar
#

no like, the part in between the kernel and hardware. not the part in between the userspace and kernel

#

no need to do VGA I guess?

teal dock
#

you get a framebuffer from vbe or gop

#

or write a gpu driver :P

late oar
#

right

#

gpu driver might be a bit too much work for now

inner pilot
#

EFI GOP is the magic word

#

it's a framebuffer that's mapped by the firmware

late oar
#

EFI Grand Old Party

#

btw I have a friend switching my CI towards Jenkins

#

fuck github actions

inner pilot
#

limine when

inner pilot
#

@late oar you should just bite the bullet

#

or write a uefi loader yourself

#

but fuck mb2

#

it's utter trash

silent lava
#

mb2 flobsh

inner pilot
#

megabad2

late oar
#

idk if I don't support mb that means I can't boot from grub, right?

inner pilot
#

fuck grub

silent lava
#

grub suck

late oar
#

yeah but that's what people use

inner pilot
#

for linux lol

late oar
#

fuck discord but that's where people are

silent lava
#

ok so? this is your OS, not theirs

inner pilot
#

bro is making linux 2

#

just support linux protocol

#

like bruh

#

multiboot is genuinely dog shit

#

if you want to boot with grub you can do efi chainloading

silent lava
#

Even for Linux, Limine is just a better bootloader

inner pilot
#

i use limine on all my pcs

solid rose
# late oar gpu driver might be a bit too much work for now

for a multiboot2 framebuffer, add a tag like this:

dd MB2_MAGIC
dd MB2_ARCH
dd MB2_LENGTH
dd MB2_CHECKSUM
align 8
dd MB2_TAG_TYPE_FRAMEBUFFER ; 5
dd MB2_TAG_FRAMEBUFFER_SIZE ; 20
dd 0  ; width (0 means default)
dd 0  ; height
dd 32 ; bpp
align 8
dd MB2_TAG_TYPE_END
dd MB2_TAG_SIZE_END

and then to get the address, search for tag type 8 and parse it

late oar
#

btw I haven't started the framebuffer yet. The CI doesn't pass for some reason. I broke SMP, and there's another issue with NVMe that I haven't figured out yet, that happens only on the CI and not on my computer

solid rose
#

โ™ซ 99 little bugs in the code โ™ซ
โ™ซ 99 little bugs โ™ซ
โ™ซ take one down, patch it around โ™ซ
โ™ซ 137 little bugs in the code โ™ซ

late oar
#

lmao

teal dock
solid rose
#

^

late oar
late oar
#

I still have the SMP issue. Trying to figure this out

#

I didn't work much on this during the week. I am in Paris hanging out with friends

late oar
balmy plume
#

huh

#

why is this ever needed?

late oar
late oar
#

Can anyone help me figure out what's wrong with my NVMe driver pwease? UwU ๐Ÿ‘‰๐Ÿ‘ˆ
When I have more than one CPU core on the system, I have a concurrency issue that makes the kernel panic. I suspect this may be the NVMe controller writing somewhere it should not
This issue does not happen when I use IDE instead of NVMe so I am fairly certain it comes from the NVMe driver

After looking closely with gdb, I suspect the issue happens systematically after the first process forks, when the parent resumes, if it has been migrated to another CPU core, on the second read operation it attempts after resuming (this line might be difficult to understand and maybe not very useful, sorry)

This is the function to enqueue a command: https://github.com/maestro-os/maestro/blob/e58a7eb6e8501b49129b24e180200cbbdf8acb0c/kernel/src/device/storage/nvme.rs#L796
This is my submission entry to read a page (writing is just below): https://github.com/maestro-os/maestro/blob/e58a7eb6e8501b49129b24e180200cbbdf8acb0c/kernel/src/device/storage/nvme.rs#L535
This is the location where I handle NVMe interrupts: https://github.com/maestro-os/maestro/blob/e58a7eb6e8501b49129b24e180200cbbdf8acb0c/kernel/src/device/storage/nvme.rs#L838

Could you guys tell me if you see anything suspicious? I am clueless

balmy plume
#

are you writing to userspace pages directly? if yes, my guess would be memory locking / copy on write bug

late oar
late oar
#

The driver allocates the physical page it writes to, and then it inserts it in the page cache. This page is then mapped to userspace

fringe pike
#

before and after the command write_volatile you need an empty asm block to make sure the commands are all written out by the compiler

balmy plume
#

cow + direct writes to user w/o mlock-equivalent (not really exact mlock semantics, but locking the physical addresses during the read()) sounds like a recipe to get corruption

fringe pike
#

thats probably not the issue tho

#

but idk

#

actually it could be something like that, with a tricky sync issue

fringe pike
#

so that only one read can proceed at a time

fringe pike
balmy plume
#

can't you use sync::atomic::compiler_fence() or is not that available in no_std?

fringe pike
fringe pike
#

volatile cant be used to sync against other threads

fringe pike
late oar
#

adding the asm before and after does not change much either

shell tusk
#

Ah I thought you mean like it could still optimize away a read/write

fringe pike
balmy plume
fringe pike
#

but surrounding writes could be removed

fringe pike
#

and can be read by other threads

balmy plume
#

why not?

fringe pike
#

why is compiler_fence not enough?

#

you cant use fences of any kind to make volatile ops atomic and hw is modeled as a different thread

balmy plume
#

the rust compiler has to assume that a signal can occur immediately and read the value written by the volatile store, followed by reading the non-volatile data

#

so it has to order the writes before the fence

fringe pike
#

volatile ops are not enough to sync against signals

balmy plume
#

ah true

#

yeah you're right

#

if this was relaxed atomic, it'd be enough

fringe pike
#

yes but you dont want to use an atomic because then that could be merged with other ops and isnt guaranteed to be one instruction

#

or an instruction suitable for mmio

balmy plume
#

does rust even guarantee that volatile is suitable for mmio?

balmy plume
#

i'd just make my own inline asm based accessors

#

like we do in libarch

late oar
fringe pike
late oar
#

sometimes a gpf happenning while printing the panic message for the page fault halfmemeright

late oar
#

*general

fringe pike
#

also, what happens if you just add like a 10ms sleep in various places

balmy plume
fringe pike
#

surely you dont make pages accessible to userspace before a read completes though?

late oar
fringe pike
#

and then write a python script which determines if something has the kernel code pointer vibe

#

and pass all such pointers to addr2line

#

its like the easy way to do very fault tolerant stack traces

balmy plume
late oar
#

writing directly to pages mapped to userspace happens only when the file is mmap-ed

balmy plume
#

okay that sounds unproblematic w.r.t. fork() etc

late oar
#

here are the logs of the kernel running, interlaced with the logs given by QEMU's --trace pci_nvme_*

#

(the kernel panic does not show much info because it deadlocks. that's an issue I have to fix)

#

alright I think I'll stop for today. I've spent the whole day on this and I'm tired

inner pilot
fringe pike
late oar
#

so I will have to figure that x2apic thing

#

and that nvme bug too

#

and implement pcie (currently have only pci)

#

and get MINECRAFT to run

coral wing
shell tusk
late oar
#

Tomorrow firefox running on Maestro fr

regal lantern
#

(Firefox does literally hundreds of unnecessary redraws, killing any hopes of fast remote X without at least probably X compression and definitely some config tweaking on Firefox's end)

shell tusk
#

Oooor

#

Step 1) git clone linux
step 2) sed s/linux/maestro
step 3) profit

late oar
#

so, back to trying to figure out why this shitty nvme driver doesn't work

teal dock
#

just don't write bugs

late oar
late oar
#

adding compiler_fence in some places seem to help (decreases the likelihood of the issue happenning), but do not eliminate it

inner pilot
#

what do you need compiler fences for?

late oar
inner pilot
#

bruh

#

ok so

#

i didn't read the backlog

#

what's the problem in the first place?

#

are you manually writing to mmio addresses?

late oar
#

I have a concurrency issue in my nvme driver that happens only when I have more than 1 CPU core

#

and no idea where it comes from

inner pilot
#

in qemu?

#

or real hw

late oar
#

in qemu

#

see #1191856876787335268 message

late oar
#

starting to think maybe I should propose giving money to someone so they figure the issue for me flesh

inner pilot
#

give me money

#

i need to buy ram

tawny drum
#

@late oar if you want me to test it i can

#

to see compliance with the x2APIC enabled by default

late oar
tawny drum
#

when you have support lol

late oar
#

yeah

#

thx!

tawny drum
#

it's not hard

#

really

#

it's technically simpler than xAPIC unless you care about sending interrupts to CPUs with lapic IDs >=256

errant venture
inner pilot
#

no but qemu

tawny drum
errant venture
#

Ah

balmy plume
#

just don't use the weird flat clustering mode (actually, that doesn't exist for x2apic anyway)

#

logical addressing without optimizing for multiple destinations is fine (there's still only one address for each CPU)

#

i've implemented this for the virtual machine monitor in our commercial product and it was not very hard

#

the way logical addressing works with the x2apic is that you have a cluster ID (= the upper 28 bits of the logical apic id) and then a 16-bit bitmask that selects targets within the cluster

#

so basically to send to logical APIC id x, so need to program the logical destination register to ((x >> 4) << 16) | (1 << (x & 15)

#

and if you really want to, you can send to multiple apics at the same time by setting more than one of the lower 16 bits

late oar
#

or the functions it uses

#
/// `f` is executed in a critical section to prevent the temporary memory space from being
/// replaced by the scheduler.

this isn't even true anymore. gotta remove this

#

I modified this function for the nvme driver to remove the critical section, so that I could make the process sleep while handling a page fault, because the page fault might need to read the page from disk

#

But maybe I fucked up the refactor

late oar
#

still troubleshooting nvme

#

feels like I've been on this nvme driver for years

silent lava
#

Didn't you already have SATA working? I heard NVMe was supposed to be easier

silent lava
#

oh

#

still a form of ATA I guess

late oar
silent lava
#

rip interrupts

late oar
#

I had my TLB shootdown interrupt tied to the same vector as the one I use for preemption. I untied those but it does not fix the issue

late oar
#

however, making the tlb shootdown to all cores and making it flush the whole virtual memory seems to change a lot of things. Now it does not crash at the same place, and the new crash seems to be a double free

balmy plume
#

If your shootdown code is correct, it shouldn't matter which interrupt vector you use for it

late oar
balmy plume
#

Whether shootdown is delayed or not shouldn't make a difference

#

for correctness

late oar
#
qemu-system-x86_64: Record/replay: Record/replay is not supported with multiple CPUs

:(

errant venture
#

The record replay system is buggy af as is lol

late oar
#

idk if it supports more than one core though

teal dock
late oar
#

nice

teal dock
#

parsing the data is difficult though

#

perfetto is quite slow, at least on my machine

late oar
#

I already managed to do it once, with only one core though

#

I had to add swap memory to my system because otherwise the browser was OOMing halfmemeright

teal dock
#

there's also eclipse trace compass that I think supports uftrace

#

it's a java program

#

you can also run perfetto cli and connect it to the web ui

late oar
#

I think I might have found where the issue is
When I submit a command to NVMe, I put the process to sleep until woken up by doing:

process::set_state(State::Sleeping);
schedule();

set_state removes the process from the current core's scheduler's run queue
Once this is done, I call schedule to switch context to another process (this function returns when the process resumes)
However, I think the other CPU core is resuming the process before schedule has finished. So it resumes even though it is still running on the first core, and with invalid register state (since schedule saves registers, but we haven't reached this yet)

#

Now I have to figure how to fix this issue

teal dock
late oar
#

the process is inserted in the run queue of the other core at the moment it is woken up (when completion is received from the NVMe)

late oar
late oar
#

@shell tusk is this the reason why you have a sleeplock in your process structure?

shell tusk
#

I have not touched that in probably 2 years I forgot what it does

#

I guess that is?

shell tusk
#

Ultimately you could probably get away with a cas loop

late oar
#

cas loop?

shell tusk
#

__atomic_compare_exchange

#

(not related to your issue but for accessing the state or w/e)

#

Your issue in specific I kind of solved by switching to a sort of intermediary context inbetween switches

#

Where I add to queue

shell tusk
#

"whatever"

late oar
#

okay I might have fixed that panic but my solution seems to deadlock. Investigating

#

I have two contexts acquiring two locks in the opposite order

late oar
#

turns out uftrace is very very very efficient at helping me figure out concurrency issues

inner pilot
#

woe but i thought rust was concurrency safe

late oar
#

I have to remind myself to use it directly each time I have a concurrency issue

inner pilot
#

(is my ragebait working?)

late oar
#

then I look at what's happening precisely. I put markers to help me

late oar
#

currently working on making a website for Maestro, with help from @fringe needle

late oar
#

claude managed to figure out a bug again (I think, I'll be sure when I have a fix)
see: #osdev-misc-1 message

late oar
#

In order to fix this issue, I am implementing mprotect

late oar
#

ci passed for the first time in 3 months letsgo

late oar
#

I think NVMe is finally done. I'll review everything and merge it
That also means, I can now start working on graphics and porting xorgโ€ผ๏ธ

#

how do I display shit on the screen? VESA?

late oar
inner pilot
#

based

#

idk if mb2 gives you a pointer to the screen

late oar
inner pilot
#

32 bit only right?

late oar
late oar
inner pilot
#

no but if it's in 64 bit memory you might be able to see it

#

ah nvm

#

it's 64

late oar
#

GOP isn't mentionned in the multiboot2 doc. But VBE is

inner pilot
#

that's why i use limine

#

it gives you the gop directly

late oar
#

mmmmmh

shell tusk
late oar
#

@inner pilot can you have vsync with gop?

inner pilot
#

no

#

there's no syncing, it's just a dumb linear buffer

#

if you want e.g. 60hz you'll have to time page flips yourself

late oar
inner pilot
#

no

#

the gop draws at some unspecified refresh rate

#

because nothing is accelerated,the rendering is done on the cpu

#

the gpu only displays it on the screen

late oar
#

now I am wondering if I should have the console in userspace or kernelspace

#

like, I don't exactly feel like having font rendering in kernelspace

teal dock
late oar
late oar
#

there's a possibility I attempt to make my own fonts for my OS

solid rose
#

although on my laptop it will default to 1024x768, so i have to go to the grub console and force it to be 1920x1080

#

unlike limine where it does the correct resolution by default

late oar
#

qemu's window changed shape, so I guess I've got a framebufferโ€ผ๏ธ

#

exciting time to be alive

shell tusk
#

Xorg in 72h

#

Dont u already have sockets and all

late oar
late oar
# shell tusk Xorg in 72h

probably not. tomorrow I'm going to buy groceries, I'll be cooking during the weekend, and there are elections in France on Sunday

#

โ€ผ๏ธ

#

poke @fringe needle

late oar
#

yellow

teal dock
late oar
#

I am currently writing the code to have a /dev/fb0, and I'll reuse it for the init console I think

late oar
fringe needle
late oar
shell tusk
#

__ensure(!"Not implemented!");

late oar
#

I am currently not working on video stuff. Instead I am reworking the tools to build a bootable image so that it's easier to make demos (currently I have to rebuild everything by hand)

late oar
#

I am going to Paris with my laptop for the week end. I didn't commit my video code and it stayed on my home computer, so no video this week end I guess

#

I'll continue working on the bootable image instead

late oar
#

I am trying to build a script to turn a ttf into a binary file that has each char rasterized into it, to see how it renders

late oar
#

looks kinda shit ngl

late oar
#

I need to remap the framebuffer with write-through, right? That means I need to have all the memory management stuff initialized before I can display shit on the screen

#

so if there's an error while initializing memory, I can't display it

#

I just realized I also need to do this remap when using text mode and I don't do it at the beginning

errant venture
#

so that writes are only released to mmio when the cache line fills up

#

so u write 64 byte bursts instead of 4

#

this speeds up your drawing 16 times

late oar
#

Ah I didn't know the difference

errant venture
#

write back -> written data is not flushed to ram at all unless the cache fills up etc (this is the default for normal memory)
write through -> data is written to both cache and ram at the same time (can be used for prefetchable PCI aka where reads have no side effects)
uncached -> cache is not used at all
write combining -> explained above

teal dock
errant venture
#

probably yes

#

it's the next best thing for gpu memory bars after WC

#

or rather, for aperture-like things

balmy plume
#

you can only do that if the BARs are only manipulated by the CPU though

#

so doing it in general is probably not a good idea

#

WT is only useful in very limited scenarios

#

you usually want either WB, UC or WC

teal dock
#

I have it as UC now

balmy plume
#

setting prefetchable BARs to WC is safe in general but setting them to WT is not

late oar
#

I guess Im just gonna use unifont

solid rose
#

decent choice

teal dock
#

indeed, I use it as well

late oar
#

currently implementing the thing to read from the unifont .hex file, turn it into a format that consumes less memory, and include it in the kernel

inner pilot
#

what's a unifont

late oar
#

easy to use font

teal dock
inner pilot
#

huh

teal dock
#

vt

inner pilot
#

why do you need this?

#

especially in the kernel

teal dock
#

to draw text

teal dock
late oar
#

huh, same thing I guess?

inner pilot
teal dock
#

wdym why

inner pilot
#

a bitmap is enough no?

teal dock
#

it's just a font

#

it can be in any format you want

inner pilot
#

do you need chinese or what

teal dock
#

bro

#

"unifont" is the name of the font

#

not some format for unicode or something

late oar
#

one does not need to include all characters in the font

inner pilot
#

ah

late oar
#

first attempt at displaying text

late oar
#

getting close

#

โ€ผ๏ธ

#

(and then I think I am getting a kernel panic in the font display function or something)

#

alright, it's working correctly but it's so fucking slow, and the screen clear is very slow and visible too (waiting for it to finish printing stuff before making a screenshot)

#

I have to avoid clearing and redrawing the whole screen each time I write something

teal dock
#

writing a terminal is an entire project by itself

late oar
tough onyx
#

You could say writing a memory manager is an entire project by itself

teal dock
teal dock
tough onyx
#

Yes, so why bother having a good one

#

have a shitty homemade one in the kernel and good user one

teal dock
#

fair enough but maestro is linux compatible

late oar
#

fun

late oar
#

I have finally made it! I am now running KDE Plasma, Firefox, Discord and RustRover on Maestro! It is now production-ready.

I am also proud to announce the project has been acquired by Microsoft. Sources won't be publicly available anymore, and a license will cost only 299.99โ‚ฌ per month.
We will also shorty integrate AIโ„ข in every feature of the OS, and Maestro will be renamed to Microsoft Maestro Office 365 Copilot.

Thank you for your support!

#

Microsoft Maestro Office 365 Copilot - Linux-compatible-ish OS in Rust, powered by AI

inner pilot
#

windows abi compat

late oar
regal lantern
inner pilot
#

E = mcยฒ+AI

late oar
late oar
teal dock
solid rose
late oar
#

Maestro - Linux-compatible-ish OS in Rust

inner pilot
late oar
late oar
#

How do I implement /dev/dmesg?
I need to save logs somewhere in memory but I don't exactly feel like mallocing for each new log message

fringe pike
#

usually you do this by making a ringbuffer

errant venture
#

Log ring

inner pilot
#

do you mean kmsg?

errant venture
#

Also it's called /dev/kmsg

late oar
#

also I resent this message in #osdev-misc-1 so the convo is there

late oar
#

now using full screen size

errant venture
#

Needs more mangling

inner pilot
#

imagine having no demangling

shell tusk
#

Imagine using a language which mangles

inner pilot
#

smh

teal dock
#

do you just compile in a demangler?

#

doesn't that need memory allocation?

inner pilot
#

rustc_demangle

inner pilot
teal dock
#

interesting

late oar
#

implementing a tty is fun

late oar
teal dock
# inner pilot no

looks like abseil has a no allocation demangler as well. the catch is that it doesn't do function parameter types and template arguments

inner pilot
#

i'm using this

#

it's the official one

#

and only needs allocation when you want to store it in a string

late oar
#

now with a cursorโ„ข

#

colours coming soon

late oar
#

โ€ผ๏ธ

#

(don't pay attention to the filenames, it's a trashy image I just use for testing)

#

I know some of those should not be there

solid rose
#

neofetch in the root dir KEKW

late oar
#

(it doesn't even work anymore)

#

I guess the next step is to add /dev/fb0, finish the implementation of unix sockets, and then I'll attempt porting xorg

forest cairn
#

very impressive, ive been looking at this for a while

#

cool to see the progress

inner pilot
#

hm

#

doesn't this allocate?

#

i avoid allocations in my panic handler

#

hopefully

inner pilot
#

yeah you're doing str::from_utf8 no?

#

doesn't that allocate

late oar
#

that's not allocating

#

it uses the same memory as the slice you're giving it

inner pilot
#

idk from the top of my head

late oar
inner pilot
#

nevermind

#

the diff looks weird on mobile

#

i thought you were calling that on the result of rustc demangle

late oar
#

on the other hand, String::from_utf8 is allocating memory

inner pilot
#

the inline diff view kinda sucks

late oar
#

github overall sucks

teal dock
late oar
late oar
#

/dev/fb0 popped up. Not working yet, figuring out why

#

also why the fuck do I have both sda and nvme0n1 present when I only plugged a NVMe in???

#

โ€ผ๏ธ

#

(idk why the whole screen hasn't filled)

late oar
#

alright, now let's check how to port xorg

solid rose
late oar
solid rose
#

oh jeez lol

teal dock
#

maestro is 56 years old

late oar
#

@shell tusk can I cross-compile xorg or do I need to have gcc, autoconf and all that stuff to build it on my os directly?

shell tusk
#

You can cross compile it obv

#

The super annoying package to cross compile is perl but you can get a 3rd party configure script to do it for you

#

And I dont think xorg needs perl at all so

#

(if you went the compiling it yourself in maestro route you would need it tho cuz autotools are written in perl)

late oar
#

alright, now I have to figure out how to cross compile Xorg

teal dock
#

I really don't want to do distro dev

#

I'm thinking of pulling fishix

shell tusk
teal dock
#

nah

late oar
# teal dock I really don't want to do distro dev

I wanna do it because I want to see if I can make one that does not require python installed by default (aside from building packages. Like you may need meson for building some packages, but maybe you won't need python at runtime)

#

also if I could remove perl too it would be nice

late oar
magic cloud
#

writing all the necessary xorg recipes was the worst fucking experience of my life

regal lantern
#

there's so many of them lol, even if you already have all the deps and just need to install the actual xorg software

magic cloud
#

it was 90% fighting with autotools 5% copy pasting recipes and 3% changing package names and repo links and 2% patching

#

like pretty much every libx* recipe is stemmed from like one library

#

and getting the right dependencies in each recipe was also painful

#

i had to search through astral's recipes, even went in the arch linux repos to figure out dependency lists of packages

late oar
shell tusk
#

cp -r gloire/recipes myos/recipes

teal dock
#

s/gloire/myos

late oar
#

rn I am wondering if my package manager should have something to install build dependencies in a directory and chroot into it in order to build packages

#

@shell tusk what are you using to build your packages and does it chroot?

shell tusk
late oar
late oar
#

after way too long, I started writing a blog article about nvme

wheat wave
#

its 10 times easier

#

and yea writing recepie is so fucking annoying considering theres like 30 dependencies

#

btw if its linux binary compatible why dont you steal packages from like alpine

#

thats what cavos and naos did

late oar
#

dead project

late oar
#

๐Ÿ‘€

#

oh wow it's been a long time since I have worked on this

#

I have to test it, but for this I need to rebuild my bash package which has apparently been built against glibc instead of musl

late oar
teal dock
late oar
teal dock
#

no caching or wt

#

why would you use write combining?

errant venture
#

Writethrough definitely wouldn't work lol

#

It only works for bars where u are the only one modifying the data

#

For this one only uncached and nothing else

#

WC is not only wrong but UB I think

#

Since it doesn't expect to see 64 byte writes

teal dock
errant venture
#

Depends, any prefetchable bar works, a common case is gpu bars for framebuffers ofc, since reading from it is slow af and with writethrough it gets faster since you cache the data locally, but for that purpose u can just do double buffering for example

#

Also obviously it doesn't work if you use gpu helpers for modifying it since those bypass the cpu

errant venture
balmy plume
#

WC on non prefetchable bars just simply won't work

errant venture
#

I guess it works on qemu

late oar
#

it does indeed. imma fix that

balmy plume
#

neither WT nor WC will work (reliably) on non prefetchable bars for the reason that infy mentioned. Devices will simply not be prepared to handle 64 byte block writes to their registers

#

They may ignore the writes / only execute a subset of them / raise SErr instead of behaving correctly

errant venture
#

did u test this driver on real hw btw

errant venture
#

damn

late oar
#

the only computers i have with nvme in them aren't really computers I feel installing maestro on for now halfmemeright

errant venture
#

cant u just boot it off of a usb drive?

late oar
#

I could, but what if my thing is actually buggy and it corrupts the system I have on my nvme?

errant venture
#

i guess its possible in theory, but u could just not do any writes

late oar
#

alright guys I'm back trying to cross compile the X server

late oar
#

while doing so I realized my cross compilation toolchain was broken from the beginning

late oar
#

turns out packaging stuff is a lot funnier once you don't have to bother about cross compiling gcc anymore flesh

late oar
#

currently attempting to package python because xorg requires meson to be built

wheat wave
#

wait what is he not using host meson?

late oar
inner pilot
#

just give it a cross file with your sysroot

late oar
inner pilot
#

have you used meson before?

shell tusk
#

all packages astral can run do not need chrooting

#

closest one would be perl but theres a third party script that comes in clutch for that

late oar
inner pilot
#

a cross file determines your sysroot, cross compiler, etc

late oar
#

forgot to ask for memory leaks too

solid rose
#

jeez it didn't need to make everything bold lol

late oar
#

side quest: I have built Vim for Maestro and now I have to add support for file locks (which means I have to understand what they do first)

#

alright, easy

late oar
#

I tried telling claude code to implement flock and he's stoopid. imma do it myself

silent lava
soft depot
wheat wave
#

did you not use the arc from alloc

late oar
wheat wave
#

is it because back when you started there is no core/alloc

#

only std

late oar
late oar
late oar
#

flock implemented. Now Vim wants membarrier

fringe pike
#

vim???

late oar
fringe pike
#

first because membarrier is very new

#

second because it doesnt appear in the code lmao

#

third because it doesnt show up on strace -ff

#

flock also doesnt

late oar
#

mmmmh

late oar
fringe pike
#

ohhh

#

okay sure

late oar
#

i don't feel like implementing membarrier so I guess I'll try to return ENOSYS and see what happens

balmy plume
#

the simplest form of membarrier is just

for(int i = 0; i < numCpus(); ++i)
    onCpu(i, [] { atomic_thread_fence(); })
late oar
#

imma implement it then

#

atomic_thread_fence is just a mfence instruction?

fringe pike
late oar
fringe pike
little escarp
#

why -64?

fringe pike
little escarp
#

ah makes sense

#

i wouldn't expect the stack to be very contended anyway

fringe pike
#

hm

late oar
fringe pike
#

yes

late oar
#

I have to admit I am not very good at using atomic ordering stuff

fringe pike
#

fence(seqcst)

late oar
#

thx

balmy plume
fringe pike
balmy plume
#

Anything else would probably be silly, yes

#

But i think membarrier() is a seqcst fence? I might be wrong though

fringe pike
#

anyway on x86 and arm, i think acqrel==seqcst

solid rose
late oar
solid rose
#

ah

#

i don't think you should be sending sigsys anyway tho?

late oar
#

I implement membarrier and fixed a bug in mprotect. Now it seems Vim wants futex

late oar
#

buggy. The TTY very likely misses some ansi escape codes

solid rose
late oar
solid rose
#

lol

late oar
#

a bit better, but still missing stuff

forest cairn
#

Emacs when troll

late oar
late oar
#

fixed a bug that made the kernel crash when booting in release mode (stack overflow)

#

I am using a larger kernel stack in debug mode because Rust

late oar
#

also running the kernel under kvm seems to work now (it didn't before)

#

and gcc stopped working

#

I really need more integration tests (soon)

teal dock
#

I have no tests

late oar
teal dock
#

because having tests require setting up tests

late oar
#

yes

#

setting this up takes time but it will save you a lot more time later

#

investment

#

I am tired of having deadlocks because my print stuff isn't reentrant so I have started implementing a lockless ring buffer for it. That will make debugging easier

teal dock
#

do you use rust's #[test]?

late oar
#

useful for running tests in kernelspace

#

for userspace tests (in a separate library), I do use #[test]

#

for integration tests I have a script that builds an image with a program in it, trying to create, edit, remove files and do other stuff to do basic tests on system calls

#

and I run all of that in the CI

late oar
late oar
late oar
#

tried running Xorg

#

smh

teal dock
#

I got "unable to start udev" or something similar meme

#

haven't tried since

#

obviously I need to implement netlink first trl

late oar
#

it seems to want epoll_create1. Does it make sense or did I do something wrong?

teal dock
#

it does make sense

late oar
#

nice

teal dock
#

you can compile it without epoll afaik

wheat wave
#

do you not have epoll?

#

if so then you probably need it

shell tusk
#

Ewwwpoll

#

Kqueue >>>

late oar
inner pilot
#

if you don't it won't

late oar
solid rose
#

you can patch its meson.build to disable epoll even if it detects it

teal dock
#

systemd needs it trl

#

and you can build it with musl

#

also, why not just use glibc?

late oar
late oar
late oar
#

alright, how about I start implementing the epoll interface?

teal dock
#

hey lukgpt implement epoll make no mistakes

#

implement eventfd first

#

it's way simpler and it'll give you an idea on how the interface should work

balmy plume
#

eventfd is independent from epoll though

teal dock
#

yes but the general framework for it is similar

#

at least in my kernel