#tabula imaginarium: osdev experiments in zig

1 messages Β· Page 5 of 1

haughty cipher
#

which i couldnt fit in the screenshot

#

but its literally svc (0xC400_0003, cpuid, entrypoint, arg0) and you get an int back

#

and this is the status codes for it

#

and the MADT tells you which of smc or hvc instructions to use

#

the defined state has the mmu off so the entry point has to be physical

#

invalid parameters is if you pass an id for a processor it cant turn on, invalid address if the hypervisor/securemonitor can tell in advance your entry point is bullshit, already_on, on_pending, internal_failure are self-explanatory, and denied is if the firmware policy says you cant use that core

#

they guarantee the new core has the same endianness as the core that calls cpu_on, interrupts are masked, stage 1 mmu and caches disabled, cntfreq for the timer is guaranteed correct, and the arg0 you passed is in x0 on the new core

#

it slaps actually

#

tbh thats why i dont have it implemented yet, it seems so simple im being lazy about it

#

anyway the debate for what to do now basically comes down to:

  • scheduler
  • rework buddy to do physically contiguous blocks
  • irq abstraction rework again to be hierarchical
  • storage drivers and/or vfs abstraction work
  • something else that i cant think of but someone might suggest
#

could also work on some cleanups/refactoring for zuacpi, theres some badly organized stuff in there that ive been putting off working on

#

anyone got suggestions for which?

polar pilot
#

scheduler !!!!!

haughty cipher
polar pilot
#

hell yeah

#

do u have an idea of how your scheduler will work?

#

i wanna do something inspired by ule in my kernel

haughty cipher
#

not a ton of idea yet tbh, though ive got context switching fully functional atm

polar pilot
#

that's usually good to have, yes

#

i should do that ☠️

haughty cipher
#

and i think i want to use tsc/arm generic timer for tracking quantum rather than just ticking down by one whenever a timer interrupt happens

polar pilot
#

that is good, i plan to have a per-cpu "nearest deadline" timestamp that can either be a timer or the scheduler deadline

#

and whenever you schedule or arm a timer you update it to whatever is earliest

#

i believe some people refer to this as "tickless"

haughty cipher
#

yeah thats how im leaning too, but not 100% sure either way yet

haughty cipher
#

my main timer interrupt is once per ms though so if i dont do true sleeps tighter than 1ms then i wont need tickless

#

oh right i forgot i suck at figuring out which way to multiply this shit lmao

#

i think the correct way to get "tsc counts per clock interrupt" is interrupt frequency divided by tsc frequency?

#

but i might have that backwards

#

yep backwards whee

#

the part my brain is now struggling at is how to do this division without overflowing

#

in the multiplication part

#

ok that number is now looking right

#

so i can start actually maybe using it

haughty cipher
haughty cipher
#

ok timer interrupt is now hooked up to preempt, we'll see if it works

#

thats a nope

#

i do know what the issue is though, its starting the timer before the dispatcher is online

polar pilot
#

woah those pointers look like hex

#

what happened

#

where octal

haughty cipher
#

lmao

polar pilot
#

did you realize it was a bit unhinged tf

haughty cipher
#

interrupt frame printer is older than when i swapped to octal, and also it cant know what is or isnt a pointer

#

i may make the tsp and rip prints use octal tho

#

mostly i like octal for debugging paging issues tho

#

doesnt matter a ton for other stuff

polar pilot
#

stack traces with dwarf info are so sexy

#

i need to do them as well

haughty cipher
#

yeah its great

#

can you tell where i told it to fuck off and stop because the log spam was annoying πŸ˜‚

polar pilot
#

what is the (krnl) at the end of symbol names?

haughty cipher
#

the zig module

polar pilot
#

ahh

#

i thought it was for stuff like actual loadable modules lol

haughty cipher
#

the other ones ive got are "target" which is literally just my target feature config flags, "zuacpi" (obvious), "config" (other configs) and "std" (the zig std)

#

yeah no not loadable

#

anyway we got timer preempting now

last pebble
haughty cipher
#

i made the commit message "tick tock its my turn now"

polar pilot
#

sadly im not using zig :(

haughty cipher
last pebble
polar pilot
#

because c++ is a thing

last pebble
#

Lol

#

Feel free to steal my code if u want

haughty cipher
#

the actual dwarf cfi stuff in in std but the debug info loading that wraps it relies on normal file system stuff so i had to override that part to load the elf from the mapped file the bootloader gives me

last pebble
#

Btw what happened to the log ring?

haughty cipher
#

i use it still

last pebble
#

Did you hook it up?

haughty cipher
#

dont have much with it atm because i dont have non-debugcon outputs for it

#

but all log messages are getting put in it

last pebble
#

Ah cool

#

Nice it see it works for you

#

The true potential unlocks at smp

haughty cipher
#

ye its working ok i think (hard to test before i get an output console for it)

#

now ive got a scheduler i might be able to hook it up to real outputs sometime

#

rn my log function pushes to the ring and then does the normal locked debugcon output anyway KEKW

last pebble
#

Why not hook it up to debugcon also

polar pilot
#

😭

last pebble
polar pilot
#

right as i was getting comfortable with c++, i even wrote my stupid shitty rbtree

haughty cipher
last pebble
haughty cipher
polar pilot
#

when i get something going more than an rbtree test

last pebble
polar pilot
#

i wanna do a shitty linux clone

last pebble
#

Oh nice

#

So same project as me then

haughty cipher
#

oh speaking of clankers i finally got around to writing up in my repo my strict no-ai no-llm policy for imaginarium

last pebble
polar pilot
#

more shitty and less overengineered log ring and everything else, but yeah "same as you" kekw

last pebble
#

That supercip made

haughty cipher
#

lemme go find that to add it then, unless you already got a link ready so i dont need to search

last pebble
haughty cipher
#

whereas ill never get kde working on imaginarium because i hate fork(), devfs, and sysfs so much that ive completely thrown out any possibility of ever having posix compat

polar pilot
#

there's more to osdev than running kde

#

and i think whatever you're doing is infinitely more creative and fun lol

last pebble
#

If you think its more fun why are you making a Linux clone KEKW

polar pilot
#

i kinda want to try to write a driver stack as well

#

or, actually, i think it's more of an io stack rather than a driver stack

#

i might use c++ coroutines for continuations

last pebble
#

Like streams?

polar pilot
#

i have no idea how streams work, assuming we're talking about the thing that fadanoid implemented in keyronex recently

haughty cipher
#

the more i develop around it the more i actually love the NT driver stack architecture

polar pilot
#

no idea then, but i'm thinking about implementing something similar to the nt driver/io stack but use coroutines for driver calls/completions

#

anyway time to stop clobbering this thread πŸ˜…

last pebble
#

Ah I see

haughty cipher
#

struggling to figure out that is

last pebble
#

I can show you my code tomorrow

haughty cipher
#

would appreciate that yeah

last pebble
#

But tldr is you flush the consoles after every write, each console has a seq number, you iterate all records until no further seq numbers exist for each console

haughty cipher
#

(the other part i struggle with is the bootstrap problem - ie i want logs output to debugcon before threading and smp are available, and also i kinda want to skip the bootloader logs but still put them in the ring)

haughty cipher
last pebble
#

If you're doing smp flushing can be done synchronosuly or deferred via a thread depending on context where the message was logged from, you do need a spinlock for it ofc, also Linux makes the last writer takeover flushing if they can so that first writer doesn't sit there flushing records forever if everyone is spamming the ring

haughty cipher
#

yeah its the bootstrapping before i can get a thread up to do the flushing thats throwing me off. once i get a thread up i can just have a thread sit on an auto reset event that gets signalled by writers

#

or use a dpc for it

#

also an option

last pebble
#

A normal preemptible or just early context can do flushing synchronosuly I really dont see a problem there

haughty cipher
#

ig yeah

#

ill need a bool somewhere to tell it to swap over

#

i wish there was a branch hint option for "this will start with this value and change exactly once"

last pebble
#

If (!preempt_enabled() || ! sched_online()) flush()

haughty cipher
#

yeah

#

i might cheat and make the starting seqnum for readers not be the actual starting seqnum for some of them

#

so the console ones can skip the stuff that the bootloader already output there with its own console/serial stuff

last pebble
#

Sure, there's an api to fetch the last seq num

haughty cipher
#

yeah

last pebble
#

U can just assign that to the console

#

Linux has a flag for that when registering a console

haughty cipher
#

neat

last pebble
#

Whether it wants to see the entire backlog

haughty cipher
#

id still like to see your code for flush at some point tomorrow or whenever just to get a more concrete idea but this is starting to make sense

last pebble
#

Sure, but keep in mind its throwaway basically just to make it work until I have more proper infra, so its more of an api usage example

haughty cipher
#

yeah

#

api usage example would def help rn also tbf

#

(ill also probs look at the linux code its just that linux code is a hot mess sometimes lmao)

last pebble
#

Yeah

#

There's many layers of abstractions to consoles there so it may be harder

haughty cipher
#

yeah

haughty cipher
#

gonna wrap up for tonight by giving drivers pub named references in a namespace so there can be autodocs for them even if that wont be that helpful really

haughty cipher
#

oh btw @last pebble since there was talk about ap startup earlier, did you know that theres a uefi protocol for multiprocessor stuff with a startupaps method, and you can even use it for os ap startup purposes? it doesnt return until all the aps return control back to the firmware

placid swallow
#

iirc that protocol got removed at some point

#

I remember looking it while wanting to write a game that ran under uefi πŸ˜›

#

looks like the MP protocol is uefi 1 only ok nvm they did a nvme and put it in a separate spec.

last pebble
last pebble
#

technically its wrong too since it should do con->log_seq_num = rec.seq_num + 1

haughty cipher
#

thanks!

haughty cipher
last pebble
#

i would definitely do that if i had smp

#

this is throwaway slop code for now

haughty cipher
#

alrighty

polar pilot
#

throw away slop code in ultra? impossible

haughty cipher
#

lmao

last pebble
#

the slop is just temporary downstream stuff so i can at least see some output lmfao

haughty cipher
#

yeah makes sense

last pebble
#

might even add a temporary flanterm thing

polar pilot
#

BASED

last pebble
#

im kind of interested in making a parser for that stuff myself

polar pilot
#

uVTE

last pebble
#

lol

#

i doubt its gonna be a library, just ultra specific stuff

#

i wouldnt try to take flanterms space on the market

haughty cipher
#

yeah same

#

on both counts

haughty cipher
last pebble
#

yeah i guess

haughty cipher
#

maybe > instead of >=

#

may still need a sched_online tho

#

for super early boot

last pebble
#

depends how early you connect the consoles

haughty cipher
#

the debugcon is connecting instantly because im still paranoid about my early init sometimes

last pebble
#

at super super early boot it just puts the messages into the ring without any consoles to flush to

#

at least for me

#

then a bit later it parses the early command line params

#

where x86 defines an earlycon option

last pebble
#

i just didnt find a clean way to do it

haughty cipher
#

my plan atm is on initial startup if its x86 then install the debugcon right after getting info from the bootlaoder (just so debugcon can skip the bootloader logs that it already does its own thing for)

#

and then during acpi early tables we parse the DBG2 table and replace debugcon with that if it exists (or just use it wholesale on aarch64)

#

and then during driver init the serial driver takes over whatever DBG2 was giving

#

(and add a log to file option at some point when i get there)

last pebble
#

fair

haughty cipher
#

ok, while im still ruminating on this

#

plan is to have log outputs provide one required and one optional function

#

required function "write" - writes to the output immediately, in any non-nmi context, no questions asked or answered

#

optional function "defer" - copies the message into a device queue, used preferentially over write in no-preempt situations after the scheduler is alive, if available

#

so write will be used if the scheduler is preinit or the log happens in a thread-ish context

#

still not 100% sure yet on this design tho

#

mostly because taking the spinlock on the outputs list requires disabling interrupts ideally

haughty cipher
#

alright here heckin goes

#

turned the debugcon into a log ring output

#

it doesnt compile lmao

#

ah i see the issue now

last pebble
haughty cipher
#

well it seems to work

#

* the device tree print is still locking debugcon manually cause that shit is far too long for a logmessage

#

normal logging is working tho

last pebble
#

well the log ring has pr_cont if u want to utilize that

#

or rather, has api to add support for that

haughty cipher
#

i didnt but also device tree being printed here specifically is 100% a debugging thing so i dont care that much

#

adding a second processor is making it hang now though

last pebble
#

lol

#

lockless log ring
hangs with multiple cpus

haughty cipher
#

ikr

#

(i dont think its the logging actually, i havent tested smp in a hot minute atm)

#

theres a bunch of stuff thats been added between the last log statement im getting and when it calls ap startup too

#

i think this is actually due to the ap startup getting preempted lmao

#

huh

#

this is very odd

#

it crashes way earlier on tcg πŸ’€

#

im so confused now

#

its triple faulting on a page fault to the pfmdb entry for page FEE00

#

which is a uh familiar looking number KEKW

#

found that bug now i think

#

i got so used to testing with x2apic that i forgot tcg doesnt do it and hadnt tested that in a while lmao

#

bro does qemu tcg ignore the mask bit on the timer lvt??

#

hello???

#

ok no its fine it just is such a train wreck timing wise since ive got no calibration for it that the timers swamp everything

kindred isle
#

What I do is I setup all non xAPIC timers to poll

#

And then pick the best one to calibrate the xAPIC

#

(Or x2

haughty cipher
#

i dont have timer calibration

#

at all

#

i trust the hypervisor or i do nothin

#

ok the hang on whpx is somewhere in here

#

the first log prints, the second doesnt

#

oh the .create returned

#

next spot

#

printf debugging so fun lmao

#

ok hang on

#

no that wasnt it hmm

#

so the first log here goes off

#

and the second does not

#

wait no im stupid

#

my flush is going off before the publish whoops

#

so i might be off by 1

#

its hanging in the sending of the ipi

#

oh lmao

#

ok

#

this was stupid

#

turns out theres no pending bit on the icr in x2apic

#

so my icr code for sending the init ipi was hanging

#

wait no that didnt fix it either

#

going to attempt something stupid on a whim

#

because i keep forgetting this weird detail about apic shit

#

yall wanna see the diff that fixed it?

#

im mad

#

cc @last pebble

#

log ring debugcon output is hooked up now and working on smp

#

mostly theres some bugs in my ap startup still

#

(namely im not copying apic base register over so the ap doesnt have x2apic on lmao)

#

fascinating that the self-dpc isnt working for some reason

haughty cipher
#

oh i think i know why the self-dpc is being lost

#

i forgot that cli/sti drops interrupts instead of delaying them

haughty cipher
# last pebble Nice

in that log the test dpc fired on bit is running on the ap and the only sync is the log ring

#

so a dpc is being dropped definitely

#

which is weird

#

its self-dpcs specifically too

#

hmm

last pebble
haughty cipher
#

oh true i could

#

i need to sync panics lol

last pebble
#

how is it possible for them to be out of sync?

haughty cipher
#

the panic doesnt use the log ring

last pebble
#

ah

haughty cipher
#

but also doesnt synchronize with the other cpus

#

gonna quickly add that for at least x86

#

ok if i try to use a broadcast nmi here then whpx bails out

#

and tcg freezes

#

i think thats my not waiting on all aps before trying shit tho\

#

oh lmao

#

ok thats one error down

#

next up

#

ok for some reason it just never fires on the bsp

#

welp the log output is fucked on aarch64 apparently

#

hang on if this is the issue... KEKW

#

ok no that wasnt it

#

??????

#

WHAT THE FUCK????

#

im so confused 😭

#

ok so

#

@last pebble you might have some idea i dont here

enabling the apic timer on the bsp causes it to not get DPCs from anything else
all other processors get dpcs fine even with the timer enabled

#

the thing i dont get is why this is only impacting the bsp

last pebble
#

Nope, none

#

Did u try enabling apic traces?

#

β€”trace apic* or smth

haughty cipher
#

ill do that in a bit, dunno if it works with an accel tho

last pebble
#

Does it only break with accel

haughty cipher
#

ill check that in a bit too

#

the timer is fucked without accel anyway though

#

because i dont have calibration other than trusting the hypervisor

#

oh wait hang on i think i just lucked into it

#

yup

#

idk why this did it

#

but it did

#

and i aint gonna complain about having it fixed ig

#

now i gotta figure out why the log ring straight up isnt working on aarch64

#

which smells of atomic ordering

last pebble
#

what was the issue?

last pebble
haughty cipher
# last pebble what was the issue?

i was restoring the irql flag twice in the dispatch yield dpc if the yield got short-circuited because of no lower prio thread to swap to

haughty cipher
#

the worst part about debugging printf is you cant use printf debugging KEKW

#

i hate that i cant tell if the issue is reading or writing

#

literally going to start using panic statements to printf debug

#

wait wtf

#

ok the issue is reading

#

uhhh

#

why is register never getting called

#

OH LMAOOOOOOO

#

passing the actual head of the bootloader protocol linked list to kmain is probably a good idea huh

#

aarch64 was just never getting the fuckin bootloader logs, which means it never called register

#

turns out the log doesnt output if you never tell it where to output foreheadthinking

#

alright we good

#

@last pebble got your log ring ported to zig, working fully on both x86_64 and aarch64, with smp-safe debugcon output on both

#

officially

#

alright next up thing to do options:

  • rework buddy to do physically contiguous blocks
  • irq abstraction rework again to be hierarchical
  • storage drivers and/or vfs abstraction work
  • bunch of boring work to make zuacpi a bit more idiomatic
  • something else that i cant think of but someone might suggest
  • aarch64 smp startup
#

id post a poll but i dont feel like posting it in the big polls channel and cant post one here lmao

#

oh yeah i dont have framebuffers yet, i could work on that

#

or work on docs more

haughty cipher
last pebble
#

ok thats really fkn annoying

#

i cant copy paste stuff while making a poll lol

haughty cipher
#

lmao

#

smh discord

last pebble
#

ill add options manually then

#

how many hours?

haughty cipher
#

12 if thats an option, im gettin tired so probably done for today

#

i always forget the options lol

last pebble
#

theres 4 and 8 and then 24

haughty cipher
#

then 8

#

knew there was some memory making me unsure if 12 was an option (and also why the fuck isnt it an option discord)

last pebble
haughty cipher
#

thanks!

last pebble
#

np πŸ™‚

last pebble
#

just let me enter the exact amount of time i want

haughty cipher
#

i think every single time ive gone to make a poll ive been like "12 hours is about right wait why cant i pick 12"

#

(i also think there should be an option to do permissions for the op of a post in a forums setup like this in addition to normal roles)

last pebble
#

yeah

haughty cipher
#

let post ops pinning things be an option discord dangit lmao

#

ah well

#

also dont forget to vote on that if you got opinions @last pebble

last pebble
#

sure

kindred isle
haughty cipher
# kindred isle Timer calibration

tbh that shouldnt be too bad, ive got tsc calibration from the bootloader using efi stall, just need to translate that into apic timer calibration

#

i just so cant be bothered rn KEKW

kindred isle
#

Or use PIT/HPET/ACPI

haughty cipher
#

but i dont think theres really any constant speed timers on tcg

kindred isle
#

It can do invtsc if you enable it fwiw

#

Well IIRC

haughty cipher
kindred isle
#

Damn

kindred isle
haughty cipher
#

it might actually be doing constant

#

but it says not supported and doesnt set the cpuid bit

kindred isle
#

They are very easy to poll

#

Which you want for a calibration loop

haughty cipher
#

yeah ig

kindred isle
#

I mean it’s what I do

haughty cipher
#

mhm

#

you got source btw? i was going to look at how obos does calibration but he does it in full asm and that scared me off for now lmao

kindred isle
#

And IIRC somebody made me rework my PIT driver to be polling which is surprisingly more annoying than you think

haughty cipher
#

i think acpi pm timer is guaranteed on x86? if so ill use that, i aint touching anything PIT related if i can help it

haughty cipher
#

could always use hpet too ig

kindred isle
#

All of my code is in C

#

I keep as much as possible out of ASM

#

And I keep it clean

#

I find OBOS codes style horrid πŸ’€

haughty cipher
#

lol

kindred isle
#

This is where I calibrate it where needed

#

If it can’t do TSC deadline mode

#

You just need a blocking sleepMS function

haughty cipher
#

mhm

kindred isle
#

Which all my timers implement

#

I just set the right function pointer for the current timer source etc

#

But it’s pretty basic

haughty cipher
#

mhm

#

tbh i should probably check for and prefer tsc deadline mode lmao

kindred isle
#

If it’s there and you have a constant TSC use it

#

No reason not to

#

And I don’t like normal deadline mode :p

#

I hope my code is readable for you >ww<

#

Some of it I’m not too proud of

haughty cipher
#

it is so far

kindred isle
#

This code works on every machine I have tried

haughty cipher
#

nice

kindred isle
#

It somtimes fucks up but very rarely and I CBA to fond out

#

Worst case it’s been off 20%??

#

I assume it’s a hardware issue

#

And I can just do more rounds of calibration across cores with SMP :p

last pebble
# last pebble
poll_question_text

what to do next

victor_answer_votes

3

total_votes

11

haughty cipher
#

well one of the things tied for the lead will be relevant for the other so ig ill start with the irq abstraction rework when i work on imaginarium next

haughty cipher
#

actual thing i work on today will either be non-programming or maybe reviving my old PR to fix zig on wsl that needs a rebase and clenaup

haughty cipher
haughty cipher
finite ether
#

@haughty cipher how do you do context switching in zig if the ABI is not stable?

#

do you force C callconv

haughty cipher
finite ether
#

because you need to save/restore callee-saved registers?

haughty cipher
finite ether
#

that sucks

haughty cipher
#

why?

#

its working great for me actually atm

finite ether
#

why would I save everything when I can avoid doing so?

haughty cipher
#

because context switching doesnt necessarily have to be cleanly inside a function?

#

it often happens from interrupt contexts with preempts yknow

finite ether
#

no

#

you should be able to context switch from anywhere

haughty cipher
#

exactly

#

so you dont know where in the reg saving of a function it switches

finite ether
#

?

haughty cipher
#

the callee/caller saved regs are handled by the function prolog/epilog, and if you can context switch from anywhere you can context switch during those

#

you could context switch in the middle of a caller saving its regs

finite ether
#

well no because in this case a context switch acts like a function call

finite ether
#

or something

haughty cipher
#

i mean if you want context switch to act like a function call but only save callee registers you can make just that one function be callconv(.sysv) or whatever

finite ether
#
amd64_context_switch:
    ; Save callee-saved registers
    push r15
    push r14
    push r13
    push r12
    push rbx
    push rbp

    mov [rdi], rsp ; Save stack
    mov rsp, [rsi] ; Load next thread's stack
    mov rax, rdi   ; Save prev thread in rax

    xor rbx, rbx            
    xchg [rdi+72], rbx   ; Unlock previous thread


    ; Restore next thread's registers
    pop rbp
    pop rbx
    pop r12
    pop r13
    pop r14
    pop r15
    ret
#

this is what i do currently

haughty cipher
#

different functions can have different callconvs on zig after all

finite ether
#

I can't do that in zig since abi is unstable

haughty cipher
#

you could use that exact function and just declare the extern of it in zig as callconv(.whatever_explicit_callconv)

finite ether
#

no?? because it can call into any code

#

unless I mark every function as callconv sysv it wouldnt work

#

can I do that?

haughty cipher
finite ether
#

wha

haughty cipher
#

if a context is swapped away using that function, then the saved IP is in that function

#

no?

finite ether
#

wdym

haughty cipher
#

i basically do what you have, except instead of saving a passed IP i save the address of a local label

finite ether
#

ah you mean it'll be back in context_switch

haughty cipher
#

in that function

#

so when it resumes its back in context switch

#

yeah exactly

finite ether
#

I'm not sure that changes anything though

#

I think I'd have to save every register like you say

#

which I kinda dont wanna do

haughty cipher
#

the only other cases are thread start, where you also know exactly where it ends up, and thread terminate, where it just never goes back into running ever and you also dont care

finite ether
#

wait

#
export fn context_switch(old_sp: **anyopaque, new_sp: *anyopaque) callconv(.Naked) void {
    asm volatile (
        \\  push %%rbp
        \\  push %%rbx
        \\  push %%r12
        \\  push %%r13
        \\  push %%r14
        \\  push %%r15
        \\
        \\  mov %%rsp, (%%rdi)
        \\
        \\  mov %%rsi, %%rsp
        \\
        \\  pop %%r15
        \\  pop %%r14
        \\  pop %%r13
        \\  pop %%r12
        \\  pop %%rbx
        \\  pop %%rbp
        \\
        \\  ret
    );
}
#

i think this then you expose it as sysv

#

I think you're right

haughty cipher
#

youre actually missing one thing from that in that you cant pick a new IP with yours

#

so thread start is gonna be hard

finite ether
#

cant you just push the IP

#

it's popped by ret

#

mhm dunno if it would work here tho

haughty cipher
#

yes its just annoying to set up that stack like that

finite ether
#

ah well I already do that

haughty cipher
#

yeah if you already are then its fine

finite ether
#


void ke_thread_init_context(struct ke_thread *thread, vaddr_t stack_base,
                            size_t stack_size, void (*entry)(void *), void *arg)
{
    vaddr_t stack = (stack_base + stack_size);

    if (stack % 16) {
        stack -= (stack % 16);
    }

    struct arch_thread_regs *sp =
        (struct arch_thread_regs *)(stack - sizeof(struct arch_thread_regs));

    memset(sp, 0, sizeof(*sp));

    thread->ctx.rsp = (uintptr_t)sp;
    sp->rip = (uintptr_t)amd64_asm_thread_entry;
    sp->r12 = (uintptr_t)entry;
    sp->r13 = (uintptr_t)arg;
}
haughty cipher
#

youll need to push the callee saved manually onto this too, no?

finite ether
#

no it happens on the first switch

haughty cipher
#

oh right i see what youre doing now

finite ether
#

im considering rewriting in zig but idk

haughty cipher
#

unless thats just what arch_thread_regs is doing in which case fine

finite ether
#

mhm?

#

this literally works btw idk what you mean

haughty cipher
finite ether
#
struct PACKED arch_thread_regs {
    uint64_t rbp, rbx, r12, r13, r14, r15, rip;
    uint64_t padding;
};
#

this is the struct

haughty cipher
#

so i didnt realise that the stack space that context_switch pops would get taken up by the struct yeah

haughty cipher
#

lmao

haughty cipher
finite ether
#

how is zig with types?

#

can I add a Vaddr with a Paddr or something

haughty cipher
#

ye

finite ether
#

ok so it's not that strongly typed

haughty cipher
#

you could make it strongly typed

#

the standard in zig for "an int but distinct typed" is to make a non-exhaustive enum backed by that int and use @enumFromInt/@intFromEnum but i personally prefer making it a packed union with a single field of that int instead

finite ether
#

mhm I don't really care about that, though it is nice

haughty cipher
#

yeah i dont really either lmao

#

i just use aliases for those

#

the big things in zig for osdev is the first-class bitfields imo, which you can even put bitint-backed enums into which slaps

finite ether
#

you mean like u<N>?

haughty cipher
#

when i say bitints yeah

#

when i say bitfields i mean what zig calls "packed structs" (and c calls bitfields) which are structs where bit-ints get packed to the bit and the whole thing is considered interchangeable with a bigger int of the total bit size

finite ether
#

ahh yeah

#

like

#
const Lol = packed struct { flag: bool; something_else: bool; }

would be over a byte

haughty cipher
#

thatd be two bits

finite ether
#

well yeah but it'd need to be a byte

haughty cipher
#

if its used on its own itd be yeah

finite ether
#

yeah that's what I meant

#

that is really cool

#

tho I'm kinda scared because yesterday I was playing around with it and already got a compiler bug lol

#

but that's on the self-hosted backend

haughty cipher
#

yeah

#

self-hosted dies if you ask it to softfloat or use a linkerscript atm so its not ready for osdev, i just use llvm backend for the actual os

finite ether
#

it was a userspace program

haughty cipher
#

#1312232715193683988 message anyway if youre wondering about some of zigs niceties for osdev start here and scroll up and around a bit

finite ether
#

it wasnt even that complex lol

haughty cipher
#

either way self-hosted is still fairly new and you can always make it use llvm instead*

* except for the build scripts themselves, which is part of why you straight cant use zig on mounted windows partitions under wsl rn, im workin on fixing that when i got time

#

(albeit workin on fixing that by fixing the actual bug, not by letting you pick llvm for the build scripts)

finite ether
#

what is tempting me the most is the nicer type system

#

I'd use C++ but zig is simpler

#

which I like

haughty cipher
#

yeah

finite ether
#

I dont like the naming convention though

#

camelCase my ass meme

haughty cipher
#

my project is mostly snake_case because fuck camelCase

#

I use PascalCase for types tho

#

there was a debate a hot minute ago about whether to swap zig to snake_case but i dont think anything ever came of it lmao

finite ether
haughty cipher
#

i say mostly snake_case because im terrible at actually being consistent and sometimes i need to name things in a certain way to make zig detect them as overriding std features (like my debug info stuff)

#

ill be honest one of the nicest things with zig is how lazy it is lmao

#

(as in lazy evaluation)

#

which is why the std can have ntdll imports, posix libc imports, linux syscalls, and whatever the fuck macos does, and all at the same time, and only compile the ones it needs for a particular program

finite ether
#

i think a nice thing is modules as well

#

so it can do cross-compile unit optimizations

haughty cipher
#

yeah

#

yep

#

minor downside of it being hard to do dynamic linking/loading stuff but upside of everything is optimized for your exact target

#

also ngl even if i was using c id be sorely tempted to still use zig for the build system lmao

kindred isle
#

I am planning a build system rework soon…

#

Could I use zig for that?

#

Instead of meson or whatever

haughty cipher
#

yup

kindred isle
#

I wonder how that may look

#

And in terms of speed

haughty cipher
#

if you use WSL at all id wait for my fix to get polished up and land but you can absolutely use zig as a build system for C

haughty cipher
kindred isle
#

My kernel dosnt even run under gcc

#

Tripe faults right away

haughty cipher
#

nice lmao

kindred isle
#

I cannot be assed to figure it out

#

Esp when I use clang overloadavle a good bit now

haughty cipher
#

iirc zig defaults to the strictest undefined behavior flags it can when building C also

#

thats one of the original motivators for zig iirc was how much undefined behavior C has

kindred isle
#

Fair fair

#

UBSAN crashes my kernel way before it should

#

πŸ₯€

#

It hates my PFNDB shit

#

Megan though it works fine

#

I do some fuckery with it

haughty cipher
#

maybe you should fix that troll

kindred isle
#

Yeah I’m gonna redo my PMM at some point

#

And il do a virtually sparse PFNdb too

#

And just init it after the PMM

haughty cipher
#

virtually sparse pfndb slaps

#

thats actually what my PMM is as a whole

#

is a virtually sparse pfndb

kindred isle
#

I can just not track pages that are part of it after they get added because I won’t ever free them?

#

I think

#

I’m also gonna improve my freelist

haughty cipher
#

bootstrapped off of the biggest block of memory in the memmap

kindred isle
#

I will use scatter gather DMA because I target modern hardware and I don’t care about speed of older hardware

#

Only matters it runs

haughty cipher
#

mhm

#

yeah the thing i still need to fix with my buddy/pmm is making it physically contiguous

#

rn its a free list of single physical pages and i then make virtually contiguous ranges for the buddy

kindred isle
#

You don’t need physical contiguous FWIW

haughty cipher
#

i think i do for the GIC ITS on aarch64

kindred isle
#

You can tell a DMA device to switch together pages

#

Fuuuuuuckkkkkk

haughty cipher
#

i dont think the gic its can be behind an iommu

kindred isle
#

You could also just pre reserve things

haughty cipher
#

yeah thats the alternative im considering KEKW

kindred isle
#

Like oh I need a GIC chunk our 2mb for contiguous things

#

I mean on x86 you need memory in the lower 1mb anyways reserved so

#

Not the worst idea to have support for reserving chunks with various constraints per arch

haughty cipher
#

most of the gic stuff is just boring mmio, but the MSI stuff using the GIC ITS you need to allocate your own tables for and the "page size" of the tables is 64k and required physically contiguous

kindred isle
#

What would a build script look like in zig for a kernel tho?

kindred isle
#

What’s the point 😭

#

Why arm

#

You could also hear me out

haughty cipher
kindred isle
#

Use 64kb page sizes on arm

haughty cipher
kindred isle
#

Still TECHNICSLY counts

haughty cipher
#

well technically two buts thats because i preemptively throw out the physical 0 page for some reason i forget

haughty cipher
kindred isle
haughty cipher
kindred isle
#

I just panic on OOM and page zero gets used depending on how I do things

#

Because my pfndb is cursed

haughty cipher
#

though i dont do enough real mode shit for the physical 0 page to really matter

kindred isle
#

And carves out chunks from memory regions

#

And uses that for the PFNdb

#

πŸ’€

haughty cipher
#

i mean im doing that too

kindred isle
#

Yeah but it’s not virtually continuous stuff

#

For virtually contiguous I would demand allocate too. If I allocate a page and it isn’t found in the PFNdb though a safe fault function it will allocate it with a function that skips the PFNdb

haughty cipher
kindred isle
#

Or virtually sparse idk

#

I’m bad at English

#

πŸ’€

haughty cipher
#

me too sometimes

kindred isle
#

It’s my native language and I mix shit up so much

finite ether
haughty cipher
#

oh btw if you use a virtually sparse pfmdb i do recommend making a bitmap for the presence of entries so you dont page fault if something tries to access the entry for some mmio thing that isnt in it

kindred isle
#

That fault and return an error code

#

So I can add probe functions for pfndb things

#

Like β€œprobe deference”

haughty cipher
#

for a kernel zig as the build system isnt really giving as much benefit as it might on a normal xplat project yeah, the biggest thing for zig build for c is that it can take a simple target triple and the rest just worksβ„’

kindred isle
#

And if it faults I get a pointer to -1 I can check for etc

haughty cipher
kindred isle
#

The way I do it is very simple

haughty cipher
#

on aarch64 i think theres literally an instruction for "try translating this address but dont fault" too

kindred isle
#

I make primatives in assembly

#

Like memcpy or strlen

#

And then I make a bunch of wrappers in C

#

That add extra guards but don’t touch bad things

#

Then on fault it checks if the RIP was inside of the assembly primatives

#

And if it is it changes the RIP

finite ether
#

so I can use kconfig

haughty cipher
haughty cipher
finite ether
#

nah its great

#

here's mine

haughty cipher
#

zig build has a step for config headers btw, supports cmakedefine, autoconf #undef, autoconf @FOO@, and blank starts that can output either nasm-style asm or c #defines for the config options you give it btw

#

but yeah you can still run arbitrary programs at build for whatever purpose

#

if you want to do it at configure time theres the run function on the build object that takes an argv and returns the stdout from the child process

#

if you want to do it at make time theres the Run step

#

(theres also a fallible version of run for configure time that returns an error and the out code of the process instead of aborting the build if it doesnt exit with 0)

finite ether
#

or I can just generate a C header and import it directly

haughty cipher
#

yeah

#

LazyPath slaps in zig build (thanks @hoary aurora iirc you came up with that)

#

all path things in zig build are represented using LazyPath, which can be generated by a step

#

and if you use addOutputFileArg on a Run step then you give it a basename and it gives you a lazypath

#

and using that as input for a different step automatically adds dependencies etc

#

and caching for those also works generally

finite ether
#

what would be cool if I do it in zig too is I think I would be one of the first ones to do an actually proper kernel

#

not throwing shade at you, you're doing it too

haughty cipher
#

one of the first yeah

finite ether
#

but most other projects I've seen are shit

haughty cipher
#

you me and a scant few others

haughty cipher
finite ether
#

the most popular one seems to be pluto

#

doesnt seem very good

haughty cipher
#

is that one even still being worked on?

finite ether
#

I don't think so

haughty cipher
#

a lot of zig osdev projects out there are abandoned

#

ive got a one-file executable written in zig that hashes the kernel in case i want to pass that along to the bootloader, a different one-file executable that generates the bootloader config file, i use dimmer to generate the disk image at build time which is another tool that gets built by zig, obv the kernel and bootloader get built by zig lmao, and then a run step to run qemu

finite ether
#

and zig supports every arch llvm does right

haughty cipher
#

if you use llvm backend yeah

finite ether
#

the temptation is strong...

haughty cipher
#

(theres very alpha self-hosted for aarch64 and x86_64 and i think maybe riscv but im not sure on that one. oh and a self-hosted backend that outputs c code but thats more for bootstrapping zig itself than anything)

#

the only things you need installed to build my kernel is zig master (because im tracking master instead of tags) and qemu

#

its great

finite ether
#

huh well excluding platform code and other goodies my kernel is like 4-5k lines

#

a rewrite is doable

haughty cipher
#

mhm

#

zig also has a build step that takes a c header and outputs a file with externs to link to that c thing

#

so you can interop well with c

#

id say i do that for uacpi but i actually wrote all the extern bindings for that by hand lmao

kindred isle
finite ether
#

@haughty cipher last question

#

if I dont know zig

#

is it doable

#

like is there a lot of idiomatic stuff I need to learn

#

yesterday I did write a bit of zig code and liked it

haughty cipher
haughty cipher
finite ether
#

but like I dont need to be a zig master

haughty cipher
#

if you know osdev and have done some zig youll be fine

haughty cipher
#

it took me two years but that was mostly me struggling with osdev concepts lmao

#

(and its not even close to done yet after those two years lmao)

finite ether
#

yeah I can just rewrite my current thing pretty much 1:1 I think

haughty cipher
#

the big thing with zig in terms of idiomatic stuff is to optimize for readability wherever possible

#

rather than optimizing for how fast you can write it or how compact it is

finite ether
#

I'm kinda scared of having too many abstractions

haughty cipher
#

theres a big emphasis on make the code easier to read than to write

kindred isle
#

i wonder how this may look fore pure C? or how you may add all the TUs and linking steps

last pebble
finite ether
#

kinda

#

not really since he said he's busy atm

#

and I wrote all the code anyway

#

so trl

haughty cipher
#

and you give it all the source files

#

and theres also addIncludePath

kindred isle
#

and i presume similar for linker scripts?

haughty cipher
#

my build script uses a linkerscript for zig code lol

#

so yeah

kindred isle
#

so i could say. hey zig. glob all these fliles except these ones based on arch and the compile to an elf with a linker script

#

and then it just workβ„’

#

and i can add a bunch of other steps and hooks for deps i may need

finite ether
#

can I do something like export the same functions from two modules

#

like I say I have some generic platform abstraction

kindred isle
#

in a non crappy langage?

haughty cipher
finite ether
#

how do I avoid having to do amd64.function and just do platform.function or something

kindred isle
#

lowk i wana try and make this build with zig

#

would mean i can drop python and other similar things?

#

can the zig.build include other zig files too lmfao?

#

to make things cleaner

haughty cipher
haughty cipher
finite ether
#

yeah ok that I dont get

pub const system = switch (tag) {
    inline else => |a| @field(arch, @tagName(a)),
};
#

wtf is that

haughty cipher
#

thats me being a bit silly

#

inline else means compiler please make separate branches for each option

#

which means the captured a becomes known at comptime

kindred isle
#

500 line build file

#

i may just mess with meson tbh

haughty cipher
#

so thats equivalent to

pub const system = switch(tag) {
  .x86_64 => x86_64,
  .aarch64 => aarch64,
}
finite ether
#

ok perfect

#

that's good

haughty cipher
#

and because zig is lazy and tag is a compile time constant whichever branch isnt used is literally just dropped and never compiled in

#

i just did it with inline else and @field so if i add more arches theyll get their own switch cases added automatically

#

@field(a, "b") is equivalent to a.b except b is a compile-time string instead of having to be a literal identifier

finite ether
#

okok I get it

#

strings are kinda weird tho

#

fieldParentPtr or whatever takes a string

haughty cipher
#

fieldParentPtr is just container_of

finite ether
#

yeah I know

haughty cipher
#

it takes a string because theres no macros, only compile-time interpreted stuff

#

so @offsetOf also takes a string etc

#

its a bit weird at first but you get used to it

finite ether
#

yk what I'm gonna try it and see

#

worst case I dont like it and go back to my C code

haughty cipher
#

yeah

haughty cipher
finite ether
#

is zag a good name trl

haughty cipher
#

good to me but theres probably already something called that lmao

finite ether
haughty cipher
#

oh js shit fuck them then

finite ether
#

I also found a zig kernel named zag on github but it has 0 stars and hasnt been worked on in a while

#

so I think I'm fine trl

haughty cipher
#

ye

finite ether
#

another consideration was something like bowie or stardust, but stardust sounds ass

haughty cipher
#

yeah

finite ether
#

(because of the ziggy stardust album)

hoary aurora
finite ether
#

meson + make + kconfig + scripts

#

It's nice to work with

hoary aurora
#

Imagine your whole project setup is literally "install zig, run zig build"

hoary aurora
finite ether
#

it's python scripts

hoary aurora
#

ah okay, so i need python as a dependency πŸ˜„

finite ether
#

why are you randomly roasting my build system

hoary aurora
#

na, just curious πŸ™‚

finite ether
#

you need python anyway as it uses meson

hoary aurora
#

right

finite ether
#

and kconfig is done through python

#

for me it works fine and the build system hasnt really been a pain point

hoary aurora
#

okay, so basically python + $compiler as a dependency

#

that's also nice!

finite ether
#

python + meson + ninja + compiler

hoary aurora
#

you know, i've seen projects where a build starts with "sudo make" πŸ™ˆ

finite ether
#

I have a makefile as well but it's more used as a command runner

#

and i could avoid it

hoary aurora
finite ether
#

I'm aware

#

but everyone has make

#

not everyone has just

hoary aurora
#

i have just, but not make πŸ˜„

haughty cipher
#

i dont have either technically

#

i do have msbuild and ninja though which ig ninja counts as a make?

#

on wsl i have make tho

#

also i knew there had to be some reason for me to have this itch to not even be looking at meson, if its python thatd be why lmao

#

im a python hater

#

there are very very few things in programming i hate more than python

haughty cipher
#

ok, so, first thoughts on irq abstraction things

#

an interrupt domain (using that name even though not taking the linux model) has some fixed number of input ports that can each be routed to ports on other controllers, and the type of the id for the port varies by controller

#

some vectors can get given a piece of data if the controller supports it

#

something like an ioapic has one port per redirection entry that takes no extra data, a cpu has one port that takes whatever the vector number/arm intid is as its data

#

a GIC ITS has 2^32 input ports and a 32-bit data channel, and can send to one output port with a 24-bit data field

#

the GICD has one input port that takes a 24-bit data field and is restricted to not change the data field in routing

#

not fully decided yet if this is how i want to do it tho

haughty cipher
#

Definitely more of a formalism I'll use to conceptualize this though, the impl will have to basically be backwards from that

haughty cipher
#

side quest because i still cant figure out how the fuck im going to do irq abstraction:
rig up some writer stuff to normalize line endings

#

one bonus thing i can do if i make a custom writer is make one that buffers up and then discards extra for counting

#

idk

#

because log ring as long as i add an extra count for each instance of newline i can normalize endings in place anyway

haughty cipher
#

ok so making the base lowest-level interrupt domain percpu will actually make so much of this shit cleaner

#

just how the hell do i actually do the data structures for forwarding

#

def gonna need to give the irq object some notion of port vs vector though

#

just to be able to keep the internals even slightly separated here

#

probably still keep a context pointer and isr for each irq object, and irqdomains will just be required to have a forward function you can use for that

#

(since if some irqs need an irs pointer then they all have that pointer of space anyway so may as well use it)

#

so an irqdomain will have a function reserve that returns irq objects, which can then have their ISRs set and vectors queried for setting up higher level things etc

#

and an irqdomain will have a forward function that operates as an ISR and routes an IRQ to the next level upward

#

and enable/disable optional functions probably

#

and reserve can take a fixed vector in the context of that irqdomain in case the firmware or whatever specifies it, or a list of options actually makes more sense, and probably also a cpu affinity thing as well? im still waffling on whether i want to go full percpu irq tables

#

as an example here, a device enumerated in acpi tables says it can have any of 8 different GSI numbers (call them 24-31 for example why not)

#

so it calls reserve on the gsi domain using those 8 options

#

the gsi domain then goes through the ioapics until it finds a free redirection table entry with one of those GSIs

#

it then calls reserve on the x86 vector irqdomain to reserve a vector for that io redirect table entry

#

the x86 vector irqdomain looks at the provided IRQL and affinity and goes through cpus looking for a cpu with a free vector of that priority

#

if that fails it then loops through looking for a vector with exactly one irq, and again for 2 or less, then 4 or less etc (thanks @floral prawn for that idea)

#

once the x86 vector irqdomain finds a vector/cpu pair that can handle the new irq, it returns it to the gsi irqdomain

#

the gsi irqdomain then plugs that info into the redirection table for the gsi it reserved and returns that gsi as an irq object

#

and then the device that got enumerated by acpi (and had an interrupt in its _PRS) puts its ISR into the new irq object and puts the "vector" of that IRQ (which for the gsi domain is a GSI) into the acpi resource and calls _SRS

#

a device that has an MSI would call the x86 msi domain, which would use the same x86 vector domain to get a cpu and vector, and then return an irq object with the port changed to the msi address and the vector changed to the msi data

#

and as an aarch64 example

#

the actual processor side is way simpler, theres no vectors, only attempts to load-balance

#

so a device requests an irq from the GSI domain using a fixed vector from the acpi tables and all reserve has to do is pick a processor for it

#

or for MSI, a device requests from the gic msi domain.
the gic msi domain requests from the LPI domain, which probably uses some tree system for allocating them
the gic msi domain then figures out what cpu to route the msi to and invokes the MAPI command on the ITS for the source deviceid, allocated lpi, and target processor

#

and then it returns the GIC_TRANSLATER its address as the port and the eventid it allocated for the vector

haughty cipher
#

why is my brain only able to figure out ideas for these design challenges why im half-asleep and delirious from exhaustion in my bed at midnight

haughty cipher
#

why am i out here reading the fuckin "intel virtualization technology for directed io" spec πŸ’€

#

(found a bug in my ioapic shit thats why)

#

it was going to crash if i ever tried to set the destination affinity of an interrupt to not be processor id 0

#

the thing is the only thing im installing with ioapics so far is the SCI

#

which goes to the BSP

#

which is generally pid 0

#

(clarification, it would crash if the processor id overflowed a u8, which the legacy-style xapic id is left shifted 24 so on my small-enough-to-not-x2apic-by-default tests that would be true for everything excecpt the bsp)

last pebble
#

are u designing your irq interface?

haughty cipher
#

slowly but surely yeah

#

got distracted by baking cookies atm but ill be back on the grind later

#

its similar to linux irqdomains but i dont have global interrupt numbers

#

so if you want a unique number you use the pointer to the irq struct

last pebble
#

Interesting

haughty cipher
#

that and the internal per-domain interrupt number is two numbers not one

#

(the paper calls the two numbers port and vector and gives examples of what they mean for a bunch of different irq domains)

haughty cipher
#

ok here goes nothing

#

and found the first stupid bug

#

i was trying to install the timer interrupt before setting gs_base

#

new irq abstraction is working on x86_64

#

(apart from MSIs which i still dont have yet but will be so so so so much easier with this abstraction anyway)

last pebble
#

whats the tldr of the abstraction?

haughty cipher
#
    pub const Domain = struct {
        pub const VTable = struct {
            reserve: *const fn (*Domain, ReserveOptions) ReserveError!*Irq,
            move: ?*const fn (*Domain, *Irq, from: Id, to: Id) MoveError!void = null,
            mask: ?*const fn (*Domain, *Irq) MaskError!void = null,
            unmask: ?*const fn (*Domain, *Irq) MaskError!void = null,
            destroy: *const fn (*Domain, *Irq) void,
        };
#

this

#

is basically the tldr

#

and each domain can reserve from other domains

last pebble
#

is domain also an abstraction for the irq controller?

haughty cipher
#

so theres a domain for x86 vectors that lets you get a vector on a specific or any cpu, theres a domain for GSIs that handles ioapic redirection, theres a domain for the local apic stuff that does lint and timer etc

#

the irq controller will provide one or more domains

#

for example the apic provides two: one for GSIs that routes through ioapics and one for the LVT stuff

last pebble
#

so irq controller owns a list of domains?

haughty cipher
#

(both of which call into the x86 architectural one that handles x86 vector allocation)

haughty cipher
last pebble
#

How would generic code allocate interrupts?

#

How would it know what domain to call into

haughty cipher
#

the requirement i have rn is an (architecture, irq controller) pair is requried to provide a domain for GSI routing and one for IPI routing

#

so rn my uacpi shim calls into the gsi_irqdomain which is swapped out based on the combo of arch and irq controller (rn theres only one implemented pair because ive not done arm for this yet)

last pebble
#

so there are like fixed domains all arches must implement?

haughty cipher
#

yeah

#

three of them in design, two rn because i havent done MSI yet

last pebble
#

so legacy/msi/ipi are three domains?

haughty cipher
#

yep

last pebble
#

or the three domains there will be in total

haughty cipher
#

there are more but those are mostly internal, and devices can stack others on top

#

a gpio controller will probably provide its own domain which reserves a GSI and then has a vector for each pin

last pebble
#

yeah that makes snese

haughty cipher
#

as an example

#

and then internally theres the x86 vector domain, which just reserves vectors on processors and is called into by the main ones

last pebble
#

is the client code expected to always know the top most domain it wants to allocate from?

haughty cipher
#

yes and no, the actual allocation will be handled by the IO manager's resource allocation

#

which has MSIs and GSIs as types of resources

last pebble
#

i see

haughty cipher
#

but in general the client code will know what domain it wants to allocate from because thats either fixed by the context (an IPI will always use the IPI domain, etc) or discovered by enumeration (a gpioint resource tells you to get the domain from a gpio controller, a basic acpi interrupt resource tells you to get from the GSI domain, the pci(e) msi capabilities tell you to get from the MSI domain, etc)

#

yknow hang on i should test this with smp

#

ive only tested uniprocessor so far

haughty cipher
#

ok yeah good i tested with smp

last pebble
#
  • pci interrupts will be requested by generic pci code so it knows the domain, u could even have a pci domain maybe?
  • msi interrupts will be requested by msi aware driver specific code
  • legacy/generic interrupts will be requested by isa devices on x86, this also partially overlaps with pci but thats x86 specific probably
#

when requesting an interrupt within the domain u do tell it a number or no?

#

E.g. for pci i want a specific GSI, whereas for MSI i dont

#

how is that handled

haughty cipher
#

and itll give you the first option that isnt taken

last pebble
#

what are ReserveOptions

haughty cipher
#

force_cpu is a temporary hack until i get cpu masks set up properly

last pebble
#

so allowed is like a list of desired vectors?

haughty cipher
#

yep

last pebble
#

i assume for msi u can leave that as null?

haughty cipher
#

correct

last pebble
#

interesting

haughty cipher
#

even for GSI i might eventually let you make that null and have it just pick any GSI but im not sure about that

last pebble
#

i mean for pci interrupts u must use whatever gsi acpi told u

haughty cipher
#

the idea with it being a list instead of a single value is that acpi already gives a list of alternatives for its irq descriptors so may as well bake that concept into this

haughty cipher
last pebble
#

what even is the use case for take any gsi?

#

both isa and pci have hardcoded irqs no?

haughty cipher
#

i dont think there actually is one, the type allowing it is more for other domains

last pebble
#

yeah

haughty cipher
#

if i find one i can add it, rn asking for take any gsi errors

#

the other thing btw that probably seems weird at first is that the interrupt number within a domain is actually a pair of numbers

#

for the GSI domain one of the two numbers is always 0, but having two numbers simplifies a lot with the internal domains

#

(for the base x86 vector domain one number is processor id and the other is vector, for ipi and lvt domains one number is processor id and the other is an enum, for MSI domains one number will be address and one number will be data)

last pebble
#

so its just a pre-reserved priv field

#

so to speak

haughty cipher
#

effectively yeah

#

the pair is whats unique within a domain, rather than either single number being unique

#

theyre both u32 so i could just pack them into a u64

last pebble
#

one thing i dont like about these papers is they never have damn code examples

haughty cipher
#

but whatever

last pebble
#

so this two number thing is duplicated per domain per irq allocation?

haughty cipher
last pebble
#

yeah but u may have nested domains right

haughty cipher
#

yeah

#

the irq object can have a parent irq object

last pebble
#

oh so the object is nested also

haughty cipher
#

which is the information for it in the context of the nested domain yeah

last pebble
haughty cipher
#

lol

last pebble
#

is that even remotely correct?

haughty cipher
#

maybe? idk

last pebble
#

wait so

/*
 * Globally unique port identifier (paper: assign a globally unique id to all
 * ports in the decoding net).
 */

Is this true?

haughty cipher
#

port is one of the two numbers

#

idk where the thing came up with making it global, i dont remember seeing that in the paper

last pebble
#

so its not actually global

#

ah

haughty cipher
#

i did diverge from the paper somewhat

#

in making the pair global

#

in the paper there are ports which can receive an irq with a vector as attached data

last pebble
#

What does your irq struct look like?

haughty cipher
#

i found it easier to just treat it as a pair being a key

#
domain: *Domain,
id: Id,
/// the interrupt's polarity
polarity: pic.Polarity = undefined,
/// the interrupts trigger mode. the architectural interrupt controller SHALL ensure EOI signals are properly sent
/// for level-signalled interrupts.
trigger: pic.Trigger = undefined,
/// the priority of this interrupt, which is also the lowest IRQL which will mask this interrupt. set during
/// register based on the fixed or found vector and should not be modified directly outside of the
/// interrupt dispatcher/manager
priority: Irql = undefined,
/// whether the interrupt has a fixed vector number. set based on the target passed to register, and should not
/// be modified directly outside of the interrupt dispatcher/manager
fixed: bool = undefined,
/// check callback. called for all IRQs on a shared interrupt vector, and handler is only called if check returns true.
/// NOTE: if an irq is installed as sharable, check SHALL NOT be null
/// NOTE: if an irq is installed as non-sharable, check MAY be null and the handler SHALL be run if check is null
/// NOTE: edge-triggered irqs are never installed as sharable, even if specified as such in the register options
check: ?CheckFn = null,
/// the actual handler function, required
handler: IrqHandler,
/// the affinity of the interrupt, ie the cpus on which it is allowed to be run. ignored for the SGI domain
dest_affinity: ?u32 = null, // TODO cpu mask
/// the driver that installed this IRQ gets up to three userdata pointers for whatever it wants to get in callbacks
userdata: [3]UserValue = @splat(.empty),
parent: ?*Irq = null,
#

fields

last pebble
#

makes sense

#

I think what it means by this global port id is like 0 -> pci, 1 -> msi etc

#

u can use struct pointers instead

haughty cipher
#

the clanker or the paper?

last pebble
#

both

haughty cipher
#

i dont remember seeing global port ids in the paper at all, and they are clear about examples using port the way i use it

last pebble
#

this part here

haughty cipher
#

ah ok

#

theres multiple ports per domain

#

or can be

#

unless theyre overloading the term

#

for some reason

last pebble
#

hmm

#

yeah idk

#

ill need to read it properly

haughty cipher
#

honestly the main thing i took from the paper is the two numbers per irq within a domain bit

last pebble
#

yeah i get the overall idea

haughty cipher
#

oh damn i see my bug

#

oh nope

#

didnt fix

#

ok yeah i see now

#

going to take more pain to solve properly

#

fuckin x86 startup bullshit

#

@last pebble did you know that whether you need to shift the destination register of the ICR over 24 bits doesnt depend on if the current processor is in x2apic mode, it depends on if the target processor is in x2apic mode?

#

which means that for startup you have to do the shift sometimes anyway even in x2apic mode?

last pebble
#

how do u even know the state of destination

haughty cipher
#

you dont πŸ˜„

#

but when in x2apic mode i dont shift the apic id over 24 and then it never sends the fuckin init and sipi to the right AP unless i force do that shift in my ap startup

last pebble
#

πŸ€”

haughty cipher
#

but once the AP starts up and switches to x2apic mode the ipi doesnt send if i do the shift

#

it might actually correlate with whether its a lapic or x2apic entry in the MADT

last pebble
#

maybe worth looking at linux

haughty cipher
#

yeah