#Zinnia
1 messages ยท Page 6 of 1
the problem is that i want the read of thread to be atomic
otherwise i'd just return gs:0 and cast the struct
but that's not atomic afaict
huh
why bother with gs:0 then
if you can just get a pointer to per cpu data
and grab the arc out of it yourself
well that's not atomic, no?
i guess
this is what i'm working on rn
O_O
get_per_cpu works, but get_thread doesn't (because trash code)
yeah i guess you could just Arc::into_raw to leak it and then Arc::from_raw
don't forget to drop(Arc::from_raw(...)) when replacing the current thread pointer :^)
duh
okay fuck
i need a better way of setting up percpu data
uacpi wants to read the current thread id, but there is no thread running at that point
i do:
- uacpi init
- cpu init using madt
you should have a "main kernel thread"
realistically it's the first thing you should do 
and current thread shouldn't be an Option tbh
i guess
you can't not be running any thread
you always are running within the context of a thread
how do i initialize it though
i have no scheduler running :P
you can have a static percpu
maybe some section hack can do?
just use whatever your main kernel thread id will be
or just random value
that might work for the time being, but in the future this won't be sufficient
^
i would rather just have the scheduler with a static thread to start with
just initialize your bsp idle thread from a static variable and when you initialize everything repurpose _start as it's idle loop
that would be bsp's current thread when you initialize the bsp per cpu data
(you can also do that from a static)
ideally you'd do that before anything else
i.e first thing after reaching _start
hm then i need to rip a lot of this code out
woe
i think it would be better if we can look at this together tonight
i'm probably going to fuck this up in some way lol
like
ideally i would like the scheduler to be ready ASAP
i mean i can try to help but i'm not sure i'm more capable of doing this than yourself 
2 > 1
yep
the scheduler should be setup statically, if that's even possible
maybe some const fn hacks
oh shit, arc allocates memory
yes
no good
but you definitely want to refcount your threads
that could work but
that requires a memory allocator to be up
well menix initializes in stages
early, memory and init
everything relevant happens in init
ideally the per cpu data would be initialized early...
we can set it up after the memory stage
btw it would be very funny if we could do something like managarm stages
maybe @marble salmon can explain how it works
i have tried
but i'm not sure if it fits well into the rust type system
with like
borrow checking and all 
thought i think there aren't any cyclic references
so it should be fine
@hoary cave do you think we should use an Arc for the page table as well?
it would be nice
cuz currently it just does this
to be able to refcount the page tables
which is obviously a violation
the small problem with using an Arc for the [PageTableEntry; 512] thing is that it is already 4096 bytes big
at least on x86_64
and you doing Arc<[...; 4096], PageAlloc> would alloc two pages per page table
since it needs to allocate metadata too
which.. sucks
i think there needs to be a better solution for phys mem alloc
so i suggest Arc'ing the wrapper around page tables
i don't think we should rely on an allocator crate tbh
and deallocating the actual page table page in Drop
why do you need to refcount page tables?
i guess so you don't drop a thread's page table when it's still being worked on
@hoary cave i ended up changing all uses of VirtAddr and PhysAddr to be like what maestro does
i.e. transparent structs with a usize field
that way you can't accidentally use a physaddr in place of a virtual one
(i found 2 places where this happened)
i think it's time to do the scheduler
what are you planning for it?
nothing too fancy yet
round robin probably
a CFS would be nice
i do have to nuke/redo the per cpu init code
because it won't work as i intended
it basically combined cpu setup + tcb setup which is suboptimal
its alternative BFS looks interesting as well
if i want to be very fancy, i might even abstract the algorithm away behind a cargo feature
tcb?
ah
idk how to design the api properly
oh damn i also need to do the website at some point ๐
for menix?
i'm a brainlet
same
i changed the kernel boot order so instead of
limine -> arch init -> main
it does
arch init -> main -> limine -> main
but i forgot that limine calls the kernel itself
so it kept initializing itself

what's "present" for
push
i had the deranged idea of having some way to "remove" cpus
but for now it's unused
i guess i can add it later
lol
i mean qemu supports cpu hotplug
wha
I guess that could be useful for multi socket servers
most machines don't allow you to do this (because coolers and so on), but it's still funny
its for ec2 and azure
you can scale an instance up and down as demand changes
until one guy caches the result of std::thread::hardware_concurrency() at which point you can now not scale
huh?
has there been any real hardware that supports cpu hotplug?
s390 
yes
does linux support it?
yes
(or windows server for that matter)
thats crazy
thats also a way to upgrade a server without downtike ih
ig*
fair point
Windows server can do hotplug but not unplug
And it produces some really fucky thread groups when you do hotplug
How do you even know that?
because they say it in their whitepaper on hotplug support?
They have a whitepaper on cpu hotplug support?
mostly marketing fluf but yes
also you can literally download windows server and run it
https://www.microsoft.com/en-us/evalcenter/download-windows-server-2025 idk what more you could want really
Windows Server 2025 delivers next-generation security improvements, and hybrid cloud capabilities into a modernized and future ready platform.
Why would i do that if i could download linux instead?
None
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
i think i finally figured out why i keep getting page faults
i swap away the gsbase ๐ฟ
but not back
how did i not see this
OH MY FUCKING GOD
i swapped the pop and push registers
they pop/push in the same order
instead of opposite order
wow so cool now i don't get random allocation failures
hell yes
can confirm that everything is working as intended now
even runs flawlessly on all my laptops
so the only thing left to do is to switch to my own allocator
correction: almost all laptops
but that's fixable
stupid ass hp envy
btw, can you send a link for that whitepaper pls?
@near tartan shouldn't all these use p_filesz
yes
there may be zeroed memory
if it's zeroed memory, what's the point of iterating over it
it's basically "allocate more, read less, iterate over more"
null tag could be done like that 
also don't forget that the dynamic segment may contain other things than tags (although that's probably not correct)
^ but it's just goes over the memory that was returned from kmalloc and not touched by read()
so I don't see how it's related to elf contents
that alloc should be a zeroing alloc
it still doesn't make any sense, because no case would match in that switch to zeroed memory
ah good catch, there should be a break in there if a DT_NULL is hit
wait if it's just zero after p_filesz and you know it'll be matched, why even allocate and read memsz
spec shenanigans, the other PT headers like PT_LOAD do the same
I am become confucius, master at being confused
like, this is how the .bss works
yes but the allocated memory isn't used anywhere
filesz 0, but memsz !0

if filesz is 0, nothing is read() and nothing is done
just memory and cycles wasted
learning menix

same here lol
finally
@hoary cave progress
i made the decision to always ignore memory below 64KiB so i can do the trampoline shit without a worry in the world
What did you change?
allocators
have my own now instead of using a crate
but it's still dying a little bit
yes
L but lfg
Its a huge project that's true
i fixed the bug...
allocator works now
i accidentally didn't update the phys base of a region so it gave out the metadata as usable memory ๐ฟ
No struct page skill issue
Letsgo
need to think of a way how to best do virtual memory allocations
right now i just have bump allocation
but that doesn't sound like a great idea
ok. why that environment is always "unsound"? I've already used to see this print, looking over screenshots here. Still have no idea what does it mean though.
unsound means something like insecure#
like, something has messed up the state in a way that's not supposed to happen
I see, thanks. Is it rust related in this context or more general?
just in general, but it is to say "something in unsafe code has caused wrong behavior"
@grave peak ooooooof
pain
to be fair, there's a shit ton of things still left to optimize here
i have to hook up my fast memcpy, the regular malloc impl just uses the physical allocator + hhdm (no caching whatsoever)
From 5,239,043 to 235,000. Was that number achieved with rust btw?
5M was in C
235k is rust
but it's not because of rust
the entire code base is different
the allocator i have now is missing a lot
i'm sure once i add my slab allocation back in, this score is going to get much better
Genuinely interested to see the results between functionally on pair implementations in C and rust.
i've replaced the rust mem* functions with my own (primitive) ones, and it's already a bit faster
the most part is still going to be the allocator
bruh it triple faults on real hw
i think something is not mapped
I don't even get to the fbcon
i gotta check the mapping again
Old nyaux perf
okay nevermind
@grave peak kernel crashes because of something uacpi does
idk yet what exactly
but if i turn acpi off it doesn't triple fault
99% your bug 
i didnt say it's an uacpi bug
just said that uacpi is doing something that's not nice to my interfaces
real and true
it's probably a virt memory bug
fucking hell
wish i could debug with serial
i wonder what the issue is
yooo lets go i got access to a server with com1
lfg
@grave peak lol?
[ 0.000000] acpi: Initializing...
[ 0.004574] acpi: FACS 0x00000000A890D000 00000040
[ 0.097220] error: acpi: unable to attach (PCI_Config) operation region \_SB_.PC00.PMC1.PMCB: unimplemented
[ 0.111672] error: acpi: aborting method invocation due to previous error: unimplemented
[ 0.123506] error: acpi: #0 in \PMB1()
[ 0.128822] error: acpi: Op 0x5B80 ('OpRegionOp'): invalid argument type: Uninitialized, expected a Operand := TermArg => Integer
[ 0.146356] error: acpi: aborting table load due to previous error: incompatible AML object type
[ 0.159183] error: acpi: #0 in \()
[ 0.163971] error: acpi: failed to load 'DSDT' (OEM ID 'LENOVO' OEM Table ID 'THINKSYS'): incompatible AML object type
[ 0.180268] error: Kernel panic - Environment is unsound!
[ 0.187921] error: at kernel/src/generic/platform/acpi/uacpi.rs:63:56
[ 0.196679] error: "called `Result::unwrap()` on an `Err` value: Utf8Error { valid_up_to: 26, error_len: Some(1) }"
whats going on here
why is your print function trying to print invalid data tho
idk, more info needed
whats the string that it prints
not a valid c string apparently
doubt
could the allocator be to blame for this?
if you give me a backtrace i could tell you
the error means that after 26 characters it encountered a non utf-8 char
don't have that yet 
that test machine is super flaky
but yes, it's probably my allocator
woe
lol
i need to put more asserts in my allocator
(and probably actually do slab allocation)

could i interest you in tlsf allocation instead
two level segregated fit allocation
and its got very good fragmentation, and has O(1) allocation and free
https://ricefields.me/2024/04/20/tlsf-allocator.html this is about a zig version but im sure its not too hard to translate to crust
its what vulkanmemoryallocator and d3d12ma use as their internal allocator, so plenty of prior art
This is copied from jemalloc but worse 
It's also not O(1)
Or am i missing something
its O(1) if you use the good fit algorithm rather than exhaustive best fit
its a couple of bitmap tests and then either segmenting the null block or another free block
if you do best fit you walk the freelist for 1 or 2 buckets
http://www.gii.upv.es/tlsf/files/papers/ecrts04_tlsf.pdf heres the original paper
lol
@grave peakup to 1mil again
oh wow yea this really is because i have no real malloc
using buddy allocation for that is bad it seems
Nice
i expect this to go up a lot
i ran with 128M
if i put e.g. 4G ram in qemu then performance tanks
hell yea i just got access to a two socket thinkcentre
after i finish malloc I'm going to do smp spinup
that'll be fun
the claim that this is O(1) is just wrong
how so?
it needs to walk the bucket list to find a non-empty bucket
that's O(number of buckets)
which is O(log n) if the buckets are exponentially in size
also, the experiments only compare against bad algorithms
the established theory and practice is that first fit (or algorithms similar to first fit) performs best in practice
so it'd be very surprising if this "buddy like" strategy outperforms first fit
they only compared against a first fit which walks the free list
which is just stupid
Also, the fragmentation properties are quite bad
this allocator can run OOM despite there being a large enough free chunk available
this can't happen with first fit
that's because each bucket stores blocks with variables sizes that are within a certain range depending on the bucket
during allocation it only considers the bucket that has blocks that are guaranteed to be large enough for the allocation
but there may actually be large enough blocks in the next smaller bucket as well
depends on what you mean by slab, there is not a single slab allocator design
mimalloc is an actually good algorithm and rather simple to implement
i just went with linked list
way more flexible
honestly unless you actually care about designing your own allocator i'd find a crate to do it for you
btw, if you want you can see how mine works
well its rust
it's pretty easy to understand
and you can allocate a flexible size
and it can request more pages if it needs + dealloc pages if not needed anymore
you could wrap mimalloc, snmalloc, or any other C library
theres no shame in not doing everything from scratch
something is dying very early during boot
before i get to init the fbcon
i might have to build an earlyfbcon that lives right until the switch to the kernel page table happens
without a backbuffer
i dont have serial on any machine sadly
i have two machines with serial, one amd phanon x4? and one dell r730dx
damn
i just need a disk image or cd image
i hope that the ipmi interface passes through serial
keyboard passthrough didnt quite work last time i checked
i would have more if my father didnt throw out a lot of his machines a decade ago
like 8086 and up, nearly every major generation
up to athlon 64
it should
i have to add iso building to bootstrap
he said "its just junk, its old nothing works with it anymore what do you even want such old stuff for"
i can attach a disk virtually directly
it's 1gb big :(
unless you can build the image yourself
i can try
if you run install-minimal it'll only build the necessary stuff of the toolchain
but you could just get away with building limine + menix
does it work on win11?
To build the distribution you will need the following tools installed on your system:
A POSIX-compatible shell
GNU make
curl
To create a bootable image you will additionally need:
dosfstools (for mkfs.vfat)
e2fsprogs (for mkfs.ext2)
parted (for partitioning the image)
sounds like wsl
you need native linux to run jinx
so there's that
wsl1 won't work
i don't think it emulated linux user namespaces
bruh
lol
that's crazy
Could you send me the image directly? Setting up WSL and stuff will take sometime
sure
I'll add iso build support and send you one later
or @hoary cave could add iso support ๐ฅบ
i am doing linux sooo
probably not helpful
i mean it is still cross-compilation so ig
Or make your build system portable, but that will probably take way longer than setting up wsl
tell that to mint
Nice discord lag, thought I continued my last message
lol
Because of limine?
????
Jinx needs Linux
it's a hard dependency
WSL2 counts as Linux
if you're on macOS you can get yourself a linux VM and then run Jinx in there
windows is a lost cause anyways
i should probably document tho that you can use wsl2
but why
what does it use that is linux only and no other unix-like
no one uses WSL1 anymore anyways
objectively untrue
well
of course it's objectively untrue, but like
problem solved
lol
so like
basically
if you want to do reproducibility and encapsulation in any reasonable way
you need to choose on an OS
i use wsl1 because i need to also use vmware/virtualbox vms and they're slow as shit if wsl2 is usable
and i tried hyper-v as well and it sucks too
also Vmmem is a ram hog even if i don't use wsl at the moment
i just dual boot windows 
indeed that is a good solution
i got a 2TB SSD recently, i have no more excuse to not consider installing linux
i just dont know which distro and i dont have much free time
CachyOS
cauchy os
or maybe arch
CachyOS is like #3 on distrowatch, i'd call it mainstream enough
but im trying to lose weight not gain
arch or opensuse is what I'd recommend
๐ณ
ur mom has outdated packages
because she runs debian 8

thread 'main' panicked at /base_dir/.jinx-cache/cargo-home/registry/src/index.crates.io-1949cf8c6b5b557f/system-deps-7.0.3/src/lib.rs:966:94:
TARGET x86_64-unknown-linux-mlibc is not a builtin target, and it could not be parsed as a valid triplet: Unrecognized environment: mlibc
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace```
getting her to use that was a pain i wish upon nobody tho
yeah but it uses cfg-expr to try and parse the target
and it fails because cfg-expr doesn't know about our target lol
this shit's so annoying
that's the pain of not being upstream
also cfg-expr by embark??? https://github.com/EmbarkStudios/cfg-expr
crazy
๐ฟ
I will probably use rust build.rs as a buildsystem, truly portable and you need a rusttoolchain anyway if you want to compile the code os yourself
debain unstable has packages made in the last decade 
i still build everything from source anyway though lol
i should just use gentoo tbh
tbh you should try opensuse
#paidshill
what a good way to manage virtual memory allocations? do i just reuse my phys allocator?
how i feel rn
thats what i did, so theres probably a better way ๐ซ
but to start with im sure its fine
okay i hacked in a super early fb console
lets see what's happening...
?????????
wtf do you mean level out of range
me still waiting for the iso
nah no stress
if necesarry i can download it to my nas, ~7TB free
nice windows can extract xz compressed stuff
install 7z
well it worked out of the box
yes
like start selected entry after x seconds?
could you send a image without autostart?
oh nice right on the day switch
with the last image i had lying around limine ignored the keyboard and just autostarted which prevented me from figuring it out how to pass through the keyboard
WAIT NO
NON ONONONONONONOONON
PLEASE DONT TELL ME THIS IS A FUCKING ZEROING ISSUE
๐ brooooo
i probably don't zero allocated physical memory...
oof
that's why the page tables get corrupted on real hw but not qemu
why on real hw yes but not qemu?
because qemu probably zeroes memory itself
im going to use limines randomize memory function to test this
lol
I have a flag that I pass to the page allocator (__ALLOC_ZERO) that if set, causes alloc_page to memset it to zero upon allocation.
?
it will randomize the mem as it would be on a real machine
i already have
because i fixed it 
did you enable it after the fix?
yes
hm it doesn't even get to the early fb on my framework though...
the only thing i can think of is the serial code blocking infinitely
gdb time
yes it was indeed serial
lol
A LOT
oof
takes a solid minute
how much ram?
both devices have 64gb of ddr5
i still need to understand how to correctly init APICs and X2APICs
this is my brothers pc
jesus 31 blobs
framework moment
try it on every suse owned pc 
if you dont have numa support multisocket will be slow af tho
I don't have smp yet anyways
the new allocator can give out 16-bit memory
i wonder how aids x86 smp actually is
the setup at least
its pretty good
why self?
or like
ipi the cpu u want to wake
honestly if you have atleast a half-decent kernel, booting CPUs via INIT-SIPI-SIPI isn't too bad.
- you load the trampoline somewhere in the lower 1MiB of memory.
for each CPU: - INIT level assert
- a very tiny microsecond delay
- INIT level deassert
- another very tiny microsecond delay
- send SIPI(vector=trampoline addr>>12), this is why it has to be in the lower 1MiB
- loop until the CPU says it is online or some number of microseconds have passed
- repeat 6 and 7 once
- if the CPU doesn't say it is online, SMP bringup failed
what's that init level assert?
with limine it's even simpler
I don't want to use limine smp
yeah we know
oh k
i also want to support other protocols so ic can't rely on that
how do you tell the other cpus the trampoline location btw
the "correct" thing to do is to refer to whatever the old Intel MP specification says. the sane thing to do is to refer to Linux sources
he said vector= addr >> 12
vector number in the startup IPI
the sdms also document how you're supposed to start the APs
will look at that
do you happen to know which volume?
i have the amd64 manual in book form
I'm pretty sure there are slight differences between modern AMD and Intel, but the old Intel MP stuff should work on both.
damn
i have obtained a souvenir
thats crazy
lmfao
that did not work out as intended
๐ why is it so slow
nvm
my old slab impl was fucked
Damn, acpi on an NES
fyi this was the worst scenario i could be in
kvm off, debugger on, unoptimized debug build, slab allocator allocates page wise with buddy alloc as a backing allocator
Lol
okay that's MUCH better
still much more shit than before
sadge
okay now the module loader fails for some reason???
cant find symbols
ok bro
this speed kinda sucks :(
wonder if it's actually because i used a bitmap before
not another allocator issue....
I thought rust was blazingly fast
idk what it is
most likely actually the buddy allocator
that's the only thing that's different from the C version
Not off the top of my head, formulate ots somewhere eslry in volume 3 (something about multi processor init), for AMD I'd have to check.
Oh lol
FUCKING RUST
OMFG WHO DOES THAT
KEEP YOURSELF SAFE BRO
@grave peak I'M GETTING SOMEWHERE
i can optimize this a lot still
time to write phd memcpy/set impls
Nice
me waiting to instantly copy them
Nice
I will try to use mimalloc in my kernel, hopefully it's faster than alternatives
I'm still sitting at the basics
Jumping between them each time I discover that a previous assumption was wrong/suboptimal
At least the spinlocks look solid
Until I have to debug them at least
mimalloc is insanely fast, but you have to ask yourself whether or not you want to import 10k lines for it
Proxima malloc is 200 lines and takes 100ns per allocation
All it requires is a struct page
What could possibly go wrong
How do you even measure 100ns
data structure?
in reply to this oops
i dont understand the question
data structure
structured data
how do you keep track of allocated memory
per page linked lists?
just a field in struct page
lol
what is this
seems like github scans cargo files
i use talc atm for allocations, but it lacks support for an underlying allocator
ah
and if i split up the phys allocation to use my own allocator, then i'm going to have some issues with that
there is a wip branch which adds that
i may actually be stupid
instead of trying to atomically load a thread pointer i can just get the thread id atomically and use that to get the thread pointer
right?
more context needed
also i should probably just make my own spinlock primitives
mine should be on github
but they are ticket based
as i never plan to have queued threads > hardware threads
else the ticket approach fails spectacular
as you cant preemt the thread
except for independent very short interrupts like msi interrupts
my locks should work โข๏ธ
they are untested
well i tested them in my head
yeah
although thats slow
is it?
in my old kernel i just loaded lapic id and then indexed by it in the array lol
well atomically loading what u need from a per-cpu block is faster
well sure, but wouldn't i have to do locking anyways while i work on the thread data
preempt disable as in cli?
it can be that if u want
but no, most of the time it just prevents preemption but not interrupts
in nt terms that would be a raiseirql
to dispatch or higher
Just curious why you don't want to go a gs relative load for this? (or equivalent on other others)
hard to do safely in rust
Ah lol
no shame in just disabling preemption
it can be a simple refcounter and an if check in schedule()
and in preempt_enable() just go into schedule() if refcount is now 0
there is shame
rust copium 
i mean i can store a raw Rc in the percpu struct
which gets assembled/disassembled by the scheduler
well it's a bit pointless if i just do C-isms everywhere
it's a learning experience after all
i don't write a kernel because i think it'll be usable/successful
yeah im just internally accumulating reasons as for why rust shouldnt be used as a systems language 
this is bad and slow
u can have a preempt pending bit if u want to be fancy
what's good and fast
my apologies im trying to learn to be more diplomatic
Your provided solution is known to be suboptimal
did u want this solution?
yeah
essentially
per-cpu bit that says "the current thread has been preempted but this was deferred due to preempt_disable"
yeah basically if your timer irq "tried" to preempt you but couldnt because you're in a preempt_disable it can set this bit basically
which is how most people do it i think
ah
or any other case of preemption
like a higher priority thread being readied (unblocked) by an io completion interrupt
yea
i think i can use this
then just store the thread pointer directly in the percpu block
i forgor
eh it should be fine
how does the Arc even do the conversion
it does inner + sizeof(Inner) for into_raw
and from_raw does ptr - sizeof(Inner)
or, well
inner structure of Arc is
struct {
Rc rc;
T data;
}```
so, really, all it's returning is a pointer to your data
ah
and from_raw just does container_of
yeah it is, of course
i can live with that
into_raw keeps the ref count alive so as long as you have a matching from_raw it's fine
async?? holy
it doesn't make a whole lot of sense to treat futures as full blown kernel tasks
they don't need their own register state etc.
but i'm not sure how it should be done so idk why i even talk ๐
idk either
lol
well i think i can allocate a worker thread per irq?
then just have an irqaction defer to a future
or idk
async is rust is pretty funny
do you have any idea how it works? or none at all
i still don't know how it works fully but i do have some idea since i worked with it when writing the hel bindings
only from userspace
with smol
well, i'm talking about all the language elements, not about writing async code
Future, Waker etc
well, the Waker interface is pretty funny
nah no idea
actually idk if rust async in kernel will be good
i wonder if you can get away without most of the allocations
it's kinda annoying you need at least an allocation per future but idk if any other language does it better
that's why im doing it
trying to see if it's feasible
if it doesn't work out ill just drop it
one thing i know is a bit shitty is that they don't get an AsyncDrop or anything similar
which sucks if you have resource clean up that needs to be async
but it's not really something that only sucks in-kernel, also sucks in userspace
rfc when
i can send you my design for thread/core local stuff
do
DO.
What do you want to use async rust for in your kernel
Doubt it
async io or something like that
pub struct CoreLocalPointer();
impl Deref for CoreLocalPointer {
type Target = CoreLocalData;
fn deref(&self) -> &CoreLocalData {
unsafe { &*cpu::get_cl_pointer() }
}
}
impl DerefMut for CoreLocalPointer {
fn deref_mut(&mut self) -> &mut CoreLocalData {
unsafe { &mut *cpu::get_cl_pointer() }
}
}
pub struct CoreLocalData {
pub(super) arch_data: [u8; 64], //TODO move it into a concrete type definded in arch::*
pub core_id: u64,
pub core_csprng: CSPRNG,
pub system_plm_offset: VirtLv1PageAddress,
pub process_plm_offset: VirtLv1PageAddress, //Move to a dedicated struct later
pub global_data: Arc<GlobalData>,
pub thread_data: TlsData,
//pub process_data
}
impl Drop for CoreLocalData {
fn drop(&mut self) {
panic!("Undroppable Value Dropped")
}
}
pub struct TlsData {
pub process_id: u32,
pub local_heap: ProcessNumaHeapAllocator,
pub held_locks: AtomicUsize,
pub yield_to_scheduler: AtomicBool,
pub current_plm_offset: VirtLv1PageAddress,
}
maybe i should wrap TlsData wit Arc<> tbh
but TlsData isnt supposed to be accessed from outside the owning thread
They don't use rust async in the kernel
i mean if you grep for co_await you'll find it in the kernel as well
not rust async, no, but c++ async yes
using rust async wouldn't make a lot of sense given the kernel is not written in rust
glad we agree
which is what i was actually talking about
hm
when?
i thought all the allocations you needed was the Box around the future if you want to store it since it's a trait
afaik Rust explicitly doesnt do implicit allocations for a lot of things including Futures
@hoary cave didnt you say that there's no asyncdrop?
i don't think there is
is that an rfc?
behind a feature flag
hm
idk if that will work very well but you are free to try
but it seems to be an accepted feature that's being worked on
seems like its a bad idea
youre basically building the world so i dont understand the use of something designed to hide the world from you
idk if it's a good choice for kernel code
in a kernel context, most things are "async" by definition
like irq handlers
so if that works with normal functions I don't see the need
seems like a pointless abstraction
how should i store struct pages for multiple memory regions? do i have an array per memory region or just store one big array (even if it contains holes)?
like, if there's some huge holes in memory between two usable regions, how do i represent that?
by not allocating the backing physical memory for this virtually contiguous array
oh duh I'm stupid
could've thought of that
so i assume i would also need an allocator for virtual memory, right?
maybe, this "big array" can just be statically placed somewhere
hm
i don't think you can allocate memory without a physical allocator first though
so at a fixed address like 0xffff_9000_0000_0000?
yeah, well, the problem is also aligning the memory for page tables i guess
hm?
what i could do is having a bootstrap page table with the single purpose of building the actual kernel page table
e.g. in the limine-specific init code
hm that's getting quite close to having an eir-ish prekernel
the hhdm is pretty much limine specific
well, yes, but do you want to map any memory you access in your kernel manually?
for certain things it's easier to access physical memory through a direct memory map
you need to allocate the page tables needed when mapping the page array
but this is a calculation i can do beforehand, right?
maybe, but i don't think it's so simple
you might wanna map some of that memory using 2MiB pages
i guess it is a pretty simple calculation after all
maybe i was overthinking it
as i understand it, i just subtract the amount of pages needed to build the pt from a region with free memory?
or what are you thinking of
the amount of pages needed to build the page tables + the amount of memory needed for the page array itself
keep in mind 2MiB pages need to be 2MiB aligned
that slightly complicates the process of reserving memory
how so
because it's annoying, assuming you can either "skip" over the non-2MiB aligned memory in the free entry in which case you basically throw away a lot of memory, or do what i did in my shitty kernel, which is ugly
you can, but you're wasting memory
you need to allocate a quite a few page tables you otherwise wouldn't have to
yes, but it doesn't guarantee you'll end up with 2MiB alignment afterwards
what i think is the best way to do this is
let me write some code for that
pseudo code of course
typedef struct { bootstrap_page *next } bootstrap_page_t;
bootstrap_page_t *first_4kib = NULL;
bootstrap_page_t *first_2mib = NULL;
#define LIST_PUSH(head, item) \
do { \
item->next = *(head); \
*(head) = item; \
} while(0)
void do_the_thing(memory_entry_t *entry) {
for(size_t i = 0; i < entry->length;) {
uintptr_t addr = entry->base + i * PAGE_SIZE;
bootstrap_page *page = (bootstrap_page *)addr;
if(is_aligned(addr, PAGE_SIZE_2MIB)) {
LIST_PUSH(&first_2mib, page);
i += PAGE_SIZE_2MIB;
}else{
LIST_PUSH(&first_4kib, page);
i += PAGE_SIZE;
}
}
}
do_the_thing(biggest_entry);
do_the_thing(second_biggest_entry);
you could just have this bootstrap discount buddy allocator before you initialize your actual physical memory allocator
sort them into two buckets, 4KiB and 2MiB
if you run out of 4KiB pages you can take a 2MiB one and split it up into 4KiB pages
or you could do what managarm does, initialize a buddy allocator with all of your physical memory in eir, use it to allocate whatever you need and just pass through the buddy allocator structures to thor
a prekernel could work
you don't necessarily need a prekernel for that
like an init function then?
good question, i have no clue how to nicely do this, sorry
i guess you could split your physical allocator into two parts
lol
the buddy allocator that you could initialize early that handles handing out physical addresses and the one that hands out struct pages
you can do a bump allocator over the memory map for early physical allocations
but no clue if that's good or not
since you're unlikely to free any of it
same goes for virtual allocations
you're not going to reclaim memory/address space used by struct page and co
we want to be able to do 2MiB aligned physical allocations

