#Zinnia
1 messages ยท Page 7 of 1
how?
you're bump allocating
you don't have aligned memory unless you skip over a bunch of unaligned memory
yeah you can do that, just have to keep track of it
or start bumping from the largest region of memory, and track the offset you started at
its not pretty but it works
which is not pretty, and you can only keep track of so much without a proper allocator in place
or, well, you can throw away a bunch of .bss for that
you can also modify the memory in-place if you want
and you can reclaim it later
you dont need to know about all those reserved memory regions 
you can also just separate the physical allocator from the page allocator and you can use the physical allocator during init to create page tables, only downside is that you don't get page struct pointers at this point yet but i think adapting from physical addresses to page structs shouldnt be too hard
if I may though, I dont know if its worth supporting bigger translation sizes for something like struct page, because you'll end up including memory for small gaps in the memory map. With 4K mappings, you might have saved a page or two, but a single 2M mapping would cover all of it.
I was trying to make use of 2M (and 1G lol) mappings myself for this, but it didnt seem worth it imo, especially with the added complexity of finding 2M chunks of physical memory early on.
as i said, i might have overthought it
eh maybe (and maybe not), I've also just had a thought: I mostly test with < 256M of ram allocated to qemu, so there is probably some benefit to 2M mappings for larger amounts of ram, for the inevitable big block of memory you end up with.
i test with 2G ram
it's mostly a trade off between code complexity and memory usage
i don't really mind losing a few MBs, but i don't want to lose too much to simple code
simpler*
well you would potentially waste more using 2M mappings
what about the hhdm? that too with 4k?
well, you don't allocate memory for the hhdm lol
but for the pages you should use 1GiB pages if possible
I was thinking more about the increased number of page table walks, since there's more translations with 4K mappings
yea i already use 1g pages for the hhdm
i just map from 0 - limit including the holes
@hoary cave you're in vc tonight, right?
if i feel liek it, sure
would be cool if we can do some brainstorming, i'm literally blocked by this shit
i can't do anything else
i have a bunch of things that i want to implement but it's all brought to a stop by the allocator being a POS
i will use the following method:
take the highest continous memory area (with size > ? pages), calculate the needed amount of memory for the buddy allocator, take pages out of the memory area to create the needed page table entries, build the buddy there and mark the used pages as allocated. Allocate and build all remaining buddy allocators.
okay, i'll do a bootstrap bump allocator to get page tables and early allocs running
then switch over to the buddy allocator after the new pt is live
when fun and funny aren't the same
well at this point it's just not practical
but would be cool to have an interface for it
what the fuck man
Your code?
yes
that's not the same
I know, but it's more than one symbol stuck together
i understand though how it got to &&&
it's an iterator over a reference to a slice of &Entry
i don't think the ref to a slice makes a difference here
you could theoretically avoid this by doing that
.iter() should make it an iterator over &Entry
which it is
i mean, what's the point?
idk
it's a non issue yea
just funny looking
just funny inlay hints
btw i might actually have to make the memory map take owned memory
i think
or i could just not reclaim limine structures
i guess that saves me like 1 or 2 pages at most
eh not worth it
idk how you can bear with this language
my name says I program in C++ but I saw some absolutely incomprehensible C++ code yesterday which ruined my day
skill issue
it doesn't really affect my code
hyprland be like
well not really incomprehensible
just bad
wow, yes, blame the language and not the programmer :^)
tbh maybe if i had learned rust at 14 or 15 i might be proficient in it
well the programmer was to blame for that bit of c++ i mentioned
bruh?
but i dont understand rust as a whole, like, the referencing system and borrow checker and things like that
it kinda goes over my head
you have to work a bit in it
i'm so used to writing code in one way that rust is a paradigm shift to me
you have references in c++ too
but maybe i should give it a shot
oh did i say references
if i have to choose rust vs c++ ill choose rust any time, but rust vs C, rust just can't compete
i meant lifetimes
I never undestood C > C++
C++ is just C but with more stuff
more ways to blow your foot off? :^)
c++ does what c does but fucks it up every time
I meant a feature in C++
#1287456798407790684 message
how is it not related?
so i can just use c and not have to deal with it
it's a matter of knowing a language
no
generics in C: 
knowing a language doesn't mean memorising every stl function and the syntax
mf called LIST(name, typ)
it means knowing how to actually use it
criminal
but you know what's worse?
void hashmap_insert(struct hashmap *hm, void *key, void *item);
map[key] = item;
i know how to use it, and i still don't like it
i know how to use it
skill issue
that means that I doubt it
I "know" rust but not well enough to actually like and use it
let me put it this way
c++ has no features that i'd use that c doesn't have
yes, generics are cool, but not a hard requirement
and most of the stl things are just wrappers around the same concepts
duh
yes almost every compiler is a wrapper around execve(/usr/bin/as, ...) if you think about it
real
not even classes?
and the general 9 yards about OOP
classes are structs
structs with field protection types and methods
constructors are glorified __attribute((section(".init_array")) void foo();
(well structs in c++ can have methods too, but i am purely contrasting to c)
but you'd use these features if you wrote C++ right
sure
or would you just write C in C++
do you know what orthodox c++ is
something about the right way to write c++?
that's what i'd write
my c++ opinion has been influenced a lot by company code
and yes, this may be a skill issue
most of my C++ code respects these rules actually ๐
based
rtti
kernel
?
who said anything about a kernel
thats pretty much how i end up writing C++ ngl
but anyway the exceptions are, well, exceptions (my protobuf impl uses those), and cstdio, cstdlib, cstring etc
???
it's literally
code running at the end of a scope
i looked into making rtti in kernel
its really not that bad lol
im pretty sure RTTI means runtime type information
๐
dynamic_cast can fail without exceptions
you thought of RAII
i am thinking RAII
oh yea i agree with that
RAII is awesome
RTTI is kinda shite but it's whatever
dont count not using the STL which uses memory allocation because i do not care about memory management
exceptions are dookie
it comes in handy
and it says "dont use STL functions which use memory allocation unless you dont care about memory management"
my personal policy is to avoid the STL at all costs
that includes implementing my own version of <concepts>
i should try writing my own common C++ library with sanityโข๏ธ baked in
that's true but generally you don't really need it
need no
nice to have yes
also it helps reverse engineering because now you have rtti metadata in vtables :^)
real
the only place where i disagree is that i want to misuse Boost.PFR
because its cool
i don't use boost at all
boost.pfr is standalone
a
if the answer to most SO answers is "use boost", you really gotta start thinking if your stdlib is good
i felt that so much during game engine dev
and you end up with "wonderful" generated code like this
who doesnt like that
and of course count is another bit of wonderful code
that i think i codegened wrong lol
what the fuck
bro
lmao i thought i was insane
lol this is the right version
fun fact i cant write code
even if its python code
if you can't then i'm giving up programming
which i will do regardless because i can't get the brainpower together to calculate the amount of pages to reserve for my allocator
just allocate some
and hope its fine

okay pitust i dont think you saw the discussion
you just link some code from gcc and boom
no
yes
without linking gcc code
obviously lol
linking gcc code is easy and therefore cheating
by gcc I don't mean the compiler
but i was thinking of starting with a bump allocator to bootstrap the kernel page table and buddy allocator
clang is better yes
all my homies link llvm
yeah thats the actually good solution lol
question is
should i bother with trying to calculate the amount of pages i need beforehand
or just pray that the next free memory region big enough???
oh wait i can just get the largest entry ๐ฟ
MM_Allocator MM_init(MAP_MemoryMap* map) {
MM_Allocator alloc;
alloc.addr = 0;
alloc.size = 0;
alloc.size_orig = 0;
for (usize i = 0; i < map->num_entries; i++) {
if (map->entries[i].type != kUsable) continue;
if (map->entries[i].size < alloc.size) continue;
alloc.addr = map->entries[i].base;
alloc.size = map->entries[i].size;
alloc.size_orig = map->entries[i].size;
}
return alloc;
}
u64 MM_alloc(MM_Allocator* alloc, u64 size, u64 align) {
u64 target_base = align_down(alloc->addr + alloc->size - size, align);
assert(alloc->size >= size, "MM: out of memory");
assert(target_base >= alloc->addr, "MM: out of memory");
alloc->size = target_base - alloc->addr;
return target_base;
}
void MM_finish(MM_Allocator* alloc, MAP_MemoryMap* map) {
MAP_add_entry(map, kLoaderPrivatePageTables, alloc->addr + alloc->size, alloc->size_orig - alloc->size);
MAP_cleanup(map);
}
answer 3: steal shkwve code :^)

all you need to do is to implement the easy MAP_cleanup function :^)
idk what it entails
in my impl, sorting and merging entries
you can also just shrink the memory map entry in place tho
i do it this way because idfk lol
i think because i already implement a memory map cleanup function and this was easier
sort by what?
my memory map is already guaranteed to be sorted by base
my impl sorts all endpoints
then for each pair of endpoints figures out the right type
and builds a memory map out of that
yea you dont actually need to do that you can just store a pointer to the entry you are allocating from
and bump alloc out of it
i wanted to make it reclaimable later which means i need to do accounting for it
ah
also i have fdt support so i needed this shit anyway
i use limine
yeah then it doesnt matter
and tbh for a bootloader rust is actually overkill
a kernel has much more complex things going on
how goes shkwve for that matter?
same
extra points if it can load menix
but i cant focus on projects
unfortunately i just had an even worse idea than using C++ and so now ill probably be rewriting it again
ada
lol
yes
but actually i mean gclang good
and swift is a gclang with reference counting
therefore, swift is a great fit for a kernel
there is a clear connection there 
okay maybe i wont use swift thats just stupid
oh yeah i remember what i got stuck on last
the best gclang is still go
C++ async crap
yeah 100%
but i dont like gclangs to begin with
there is potential in a kernel where (most of) it is written in a gc lang
but i cant use go in shkwve
yet
im insane but im not that insane
theres tinygo but its not really usable for this iirc
SPIN from the 90s was one (modula-3, has both unsafe untraced and safe traced pointers; loadable modules have to be safe)
while the MIT pdos group did a kernel in go
i dislike that both of these however had a fixed-size, unexpandable/unshrinkable gc'd heap (i understand why it was much easier this way, but it's still a big price to pay)
i mean if you want to have any real progress in a short amount of time you should stick with C/C++
yea tinygo has that problem too
yep
im still not having a lot of progress because of other issues but yk
the main problem is that i am too skill issued to design a good device abstraction
the problem is that its a really fucking hard problem i think
idk what rustisms i want to do for my abstraction
imo none
or minimal at least
well I'd have a device trait
so i can get display name and so on
have some sysfs stuff
i had a special version of Rc<T> which also can get you at the header
which has a pointer to the metadata which is used for all the dynamic dispatch stuff
then i have a tree of devices
each device node has some set of parents
which are just struct fields + a function that turns any device handle into the parent rc
through the power of codegen magic
#[device(traits = [InterruptController])]
pub struct GIC2 {
parent: DeviceRc<fdt::Node>,
#[prop(addr)]
addr: usize,
#[prop(addr)]
addr_cpu: usize,
}
impl InterruptController for GIC2 {
// logic
}
// setup
pub fn probe_gic_from_dt(node: &Device<fdt::Node>) -> Result<()> {
// ...
DeviceRc::new(GIC2 {
parent: node.dup(),
addr: gic_addr,
addr_cpu: cpuif_addr,
}).poke();
}
ish
i switched from rust mostly because of annoyances around async and ownership
then i also had this insanely cursed query macro which could perform regexes against the device tree ```rs
let gics = query!(> as driver::gic2::GIC2);
would not recommend but it was fun to implement
let cpu = query!(>(type: "fdt-node" compatible: "riscv") as fdt::Node)
.into_iter()
.find(|n| {
n.node
.get("reg")
.ok()
.and_then(|h| h.u32())
.map_or(false, |hartid| hartid == boothartid())
})
.ok_or(Status::PLATFORM_ERROR)?;
``` so you can do shit like this
for idev in query!(self(irq: irq) as dyn Interrupt) {
if let Err(err) = idev.irq_deliver(irq) {
log::error!("plic: failed delivering irq {irq}: {err}");
} else {
return;
}
}
``` or this
i think that's right, yes
however, the cost is that rust essentially takes the whole async function + all the async functions that it awaits as a generic parameter and monomorphizes it into a single object
interesting
you can emulate that in C++ by putting everything in headers or by using LTO :^)
i wonder how much dynamic linking affects all of this
for rust?
probably not at all
Rust's futures are concrete types
whereas C++ coroutines are type erased
i'd assume that dynamic linking + generics = something similar to templates in headers or dynamic dispatch
C++ coroutines are the equivalent of Box<dyn Future>
with some extra magic to elide allocations
whereas in Rust, it's the executor's job to take an impl Future and store it somewhere
i know that using generic functions across dylib boundaries causes code duplication (duh)
yeah that's expected i guess
swift can do it 
just like templates in headers in c++
which makes sense
so can c#, kinda, i guess
or .net in general
sometimes (e.g., in tokio) you see patterns such as fn poll_read(self: Pin<&mut Self>, ctx: &mut Context) -> Poll<usize>
agree
it only gives me headaches in debugging
which allow you to "reconstruct" a Future implementation
while avoiding the monomorphization
:^)
is the Pin<&mut Self> what does the magic here?
honestly idk how that works or what the point is
well, this just allows you to create an object that implements future
i would need to take a good look at it
and then you can await it
swift does insane shit to make it work
and .net isn't even native, it's bytecode
though there's nativeaot
but idk how that works wrt generic across assemblies
nativeaot cant dynamically link
ah
you can use this convenience function
Creates a future that wraps a function returning Poll.
to turn a poll function into a future
yeah
so all assemblies are just squashed into a single native executable?
it also can't do runtime reflection
i think it can do some reflection
i said runtime
it can
yes
unity's il2cpp can also do quite a lot of reflection
and its doing the same thing
its the same kind of thing
also whats the problem with it?
idk if it changed, but in core 7 aot you could only do static reflection or the reflection methods would return null
i mean apart from closed
the codegen is absolute dogshit iirc
so this allows you to do async rust without the overhead of monomorphization but at the cost of making your code ugly af
:^)
functionย > looks
and it's not really generating code instead of CIL, it's generating code from the CIL
yes duh
thats the good way to do it
lol no
yes
i bet async recursion needs some very ugly hacking in the compiler
okay
idk if i even want async rust in the kernel to begin with
async io sounds funny
wait, it is just not allowed?
it is allowed
you just need to box the future lol
and yes that has about as much performance impact as youd expect
oh and because futures are polled at the root future, and not at the leaf future like in C++
performance is horrible
you cant
lovely
but you can write rs async fn foo() { bar().await; } async fn bar() { Box::new(foo()).await; }
ngl that's ugly
yes
so it's probably unexpected to most people who just try to write some simple async app
its not like you use rust specifically when you want to maximize performance
C++ also has all of this?
What's wrong with that, my kernel used rtti and exceptions 
borrow checker? lifetimes?
Move semantics
they're not like rust
yes the C++ move semantics are garbage
they essentially empty out an object leaving only a shell behind, to put the data in another object
it gets optimized away by the compiler anyway
@hoary cave bruh rust macros are fucking goated
wdym i can just do this shit
that's cool af
do i need atomics to read pointers? or is that guaranteed to be an atomic operation on x86_64?
for the task pointer in the percpu block
Br0 why wasn't I following teh Marvin thread
:)
Well now I am
gib โญ
lol sure
๐
Now I ask you to return the favour for Lily-CC :P
i'm currently converting a bunch of "by convention" apis that i made into static traits
like the architecture specific stuff
i belive you wont get torn reads for 8 byte reads as long as they're aligned to an 8 byte boundary, but you might not get the current actual value without using atomics
how do you get thread local stuff working without std?
so just copy pasta mostly?
you copy .percpu section per core?
yes
sounds complicated
two symbols for start end of .percpu and then memcpy?
why do you create a new interrupt handler table per cpu?
here i saw you do this
why?
so you have more interrupts?
you need more than 256?
replace that with gs relative load and its free of static vars and supports non continous apic ids easily
have you heard of nvme?
how many does it use?
that's what it does
just to setup
with nvme each drive can have up to 64k of io queues and each of them should have its own msi-x vector by spec
eh, no controller supports that really
like the CAP structure tells you how many queues you can actually make
but yes, in theory you could have 64k queues
we all know hw devs, somewhere at some time a hw dev will yolo and allow 64k queues
how do i balance interrupts btw?
they are used for native command queueing, same as with sata just extended for flash memory
like, rn i have a static handler vector, so in theory the cpu that receives the interrupt will execute that handler
but i have 256 max
what is line 68 for exactly?
what do you mean?
gs:0 would return the base address of the gs segment, and when initializing the tls, set each threads gs to a different address to the base of its tls area that you allocated somewhere (heap, page,...)
bro what
[gs:0] literally does *(void*)(gs_base + 0)
and there is a pointer to itself
so instead of rdmsr gsbase you can do that
also when defining multiple tls statics maybe you could get their offset in the tls area and use that gs:[offset]
at least of archs that have such relative address semantics for their tls register
is your tls code already pushed?
it seems i can copy rusts default tls with only a single change
yea
like rusts full version
how
if im not wrong, LocalPointer stores/represents the the LocalKey (ptr) and its marked with a attribute which is used by the compiler to place it into the elf tls template section and stuff
https://github.com/rust-lang/rust/blob/master/library/std/src/sys/thread_local/native/mod.rs
like if my assumtion is right, all you have to do is replace LocalPointer with something that does gs relative accesses and the rest should just work out of the box
no but you replace the entire LocalPointer implementation
is it possible to have variables that only exist at compile time? like a atomic counter with fetch_add that only exist on const evaluation?
but its side effects persist?
is the const evaluation race free as in i can throw around a counter and it behaves like a atomic one without actually beeing atomic?
like the counter for index calculations of the tls fields?
well tls only assumes a single cpu at all times
that's kind of the whole point
at least my tls does
i mean at compile time
Isn't TLS supposed to be per kernel thread?
per hart
Then it's CPU local storage, and you can still have race conditions?
my idea was that LocalPointer contains a const eval only counter that increments each constructor call and passes the counter value with it so that it can be used as a index into the tls area
who said that
I don't get it
im confused
You load different gsbase per kernel thread, right?
yes
yes
Oh, then it's fine
there shouldn't be any race conditions
I don't
My kernel is nonpreemptive
guh
So there is no typical context switching
don't you want that in a microkernel
Idk
like if a server hangs doesn't that just lock up the entire system lol
I mean the one that's used by kernel, not by userspace
Why is x86 so confusing?
you mean as long as you dont support any extension?
doesnt RV mean no atomics?
RV means nothing
the most ocmmon impl is rv64gc
which is imafdc_zicsr_zihintpause_zifencei
excuse me?
i know that from the top of my head
integer, multiplication, atomics, float, double, compressed, CSR access instructions, PAUSE instruction and FENCE.I instruction
that's what GC is
G meaning general purpose
i will also support Vector though
given that const eval is race free/single threaded i can replace all instances of #[thread_local] with a wrapper type that derefs to its inner value with gs:offset where offset is the current offset into the thread local storage area
yes that's what i do pretty much
and a counter is passed around and each time the wrapper type is constructed the counter is used to determine its offset
i mean what i do is just take the offset of the static var relative to the start of the percpu section
but that only works with a single struct?
no
basically, PerCpuData has a dummy variable for storage
that lets the compiler know a specific address
i calculate the offset here
FP was kinda annoying because you've got to catch invalid instruction exception (or whatever is its name) and parse it instead of a separate thing on x86 to do lazy fp context switching
But PerCpu โ thread_local?
i think I'll do an actual prekernel
that can bootstrap the structures and pass control to the kernel
there are apparently some u-boot systems that only do linux protocol boot
and i want to be multiprotocol anyways
but that's for after the alloc PR
use eir 
lol
i could make a rust eir
eir?
the managarm prekernel
based flanterm user
the allocator ub waiting to create race conditions
yea
what allocator ub 
i just filled my VMM with spinlocks
lol
(and i managed to cause a deadlock bc i was returning before unlocking it, lol)
adding spinlocks to prevent race conditions, causes race conditions by adding spinlocks
XD
@somber solar you mentioned the BFS algorithm before
do you know what kind of data structure that is?
intrusive linked list?
i can see that it's a weighted round robin basically
description said a doubly linked list
I looked at it again and saw this
apparently O(n) for lookup and O(1) for insertion becomes O(1) and O(logn)
hm
Not recommended for 4096 cpus.
lol
hm
so either bfs or cfs
cfs doesn't seem that complicated
as long as you don't look at linux sources
i have plans
i think next week i'll have pcie and drivers running again
now that most of the allocation bullshit is done
uacpi score is up to 3.6mil
@near tartan how's bfs going?
i've been moving from spin to my own sync impls
I want to implement something else other than round-robin I currently have
hm?
bfs is supposed to be simpler
rust crate ig
yes
just primitives like mutex, rwlock, etc
i'm rolling my own now
thank you clippy
asm!("nop");
all the sane architectures have it
this is cool
dont u need tons of unsafe for a kernel
that's why i'm trying to keep it to a minimum
it's not a hard requirement, but a linter check
whenever you use unsafe you better give a good reason why
it's mostly for the low level bits
@near tartan you said, you have rk3588. Orange pi5 (plus)? Haven't you installed edk2 to it?
not orange pi
i have a radxa 5b+
with edk2
@grave peak i need 182 unsafe's atm
and many of those are for uacpi and so on
minimise the number of unsafes to make your kernel safer
put everything in one big unsafe
Ah, good boards. I had such - Rock Pi 4B. The very Tom Cubie gave it to me. Couldn't you please test my code on the board? It's a quick test. rk3588 is the only one SoC left untested and the most desirable to get this jump into kernel test.
https://ant-upptech.sourceforge.io/doc/Try.htm#downloads
It would work without display attached, but the kernel can't yet print into uart, so the success wouldn't be visible. So if you will test it, attaching a monitor is necessary. Thank you in advance. I'm not "pushing" ๐ just asking for a favor.
if you can give me an image i can flash it
Damn
it's not too bad
most of the time it's willingly done
where i want to keep the semantic of something being "unsafe" at its core
welp I made my scheduler fair (with just a b-tree and a vruntime thingy)
I don't know if it's completely fair, but it seems to be at least a bit fair
The archive contains 2 dirs: efi and Lybid, unpack it to any FAT partition on a storage device, you can connect to the board (USB stick, SD card, eMMC) so these 2 dirs are in the root dir of the partition, no need to format anything. This code doesn't write to any storage, just reads from these 2 dirs. Launch it via either UEFI shell fsN:\efi\Upptech\antload.efi or via UEFI Boot Manager's "Boot from file". If you can take the pic, please do it. Especially of interest is EL in which edk2 runs, since so far I tested edk2 only with OVMF, all real hardware tests were with uboot. ๐
For some reason I couldn't get mainline Ubuntu to boot on it in DTB mode
i'll get to it on the weekend
I can try it as well...
having a really hard time figuring out this sparse struct page shit
this is what i have so far but it seems wrong
what are you storing in your page struct?
buddy stuff
ah the github may be a bit out of date
ye
i was going to say if its only flags and a refcount you can share page structs between multiple pages
did you look at the main branch?
ah github search only works on the main branch
actually even if you're storing buddy order only its probably worth using the same page struct for adjacent pages
alot of the time many adjacent pages will have the same refcount
if a subset is referenced or dereferenced you can split the page struct into segments
this is totally not incredibly painful to get right 
that sounds like mega double aids
definetly not dont worry about it
wtf
on the bright side my pmm uses less than a page to track the entirety of the systems memory
which i think is pretty good with 384GB of ram
sure bro
i imagine the worst case memory complexity is higher if every process decided to map single 4k pages in a tight loop but for 95% of cases its much better
only a spoonful
i really recommend having some nice formatting for common units
more like it
everytime i have to read some gnu tool output that contains 100237543kb my eyes glaze over
you really want to write a massively complex page metadata tracker 
you should definetly do it
i need a link to that pmm
my pmm?
i wanna see
thinking back, what exactly was wrong with using a bitmap as a pmm?
because my buddy impl is causing me brain damage
it was also faster than the buddy allocator
bitmap is more complex (if only slightly) and slower than the actual good option (freelist)
why a buddy for pmm?
hm
freelist is basically the only good option for pmm
i have a good implementation if you want
bruh
yeah
vmm has the mapping impl too
and the allocator uses a linked list
it can allocate any size
i plan to add a small "defragmentation" to merge the free list entries too, but that's super simple
even if they don't use up any memory, but if i need multi page allocation it will be needed
Buddy can give you contiguous allocations
yeah, but why on pmm
dma
can't that be faster than freelist?
where you alloc in 4kb chunks
what if you need a framebuffer for the gpu?
Like doing one allocation for memory chunks for slabs or whatever
freelist can too
My kernel uses some segregated fit weirdness, which is O(1) for allocations and frees, and gives contiguous memory
no matter what allocator you use allocating more than one page at a time is going to be slow during normal operation because to make it reliable you need to have a mechanism to defragment the physical address space
but you need to scan all of it, so it's very slow and impractical
relying on physical memory to not be too fragmented is a recipe for disaster
but you can fall back to multiple allocations
bitmap is super fast until you reach the end of the memory region
then it's slow
Buddy (or similar) naturally allocate smaller sizes first, so the memory kinda defragments itself unless it's almost full
You don't rely on it, but use as an optimization
The problem with buddy is memory splitting, right?
buddy can be slow sometimes
Like if you allocate 1 page out of 1MB chunk, you have to split it 8 times
for me, i find that freelist is the best for pmm
no mem usage, very fast, and easy to implement / manage
hm
@cyan nexus do you happen to know a little bit of rust
i'm pretty sure i've translated the algorithm correctly, but i keep getting really odd behavior
lol
oh wait don't tell me this is a fucking zeroing issue again
you don't happen to zero out physical memory, right?
this is what i do
bro wtf is that
๐ bro dw
it's the translation of this thing
idk if i'm doing something wrong
i have triple checked it but i can't spot what's wrong
it tries to read garbage at one point
wtf ๐ญ
it seems to be handing out the last page, even though it stores its metadata there
@cyan nexus did you double triple check that what you're doing is 100% correct?
or rather, with how much memory do you test your kernel?
because mine crashes with this qemu command line:
qemu-system-x86_64 \
-m 2G \
-serial stdio \
-smp 4 \
-no-reboot \
-no-shutdown \
-netdev user,id=net0 \
-device virtio-net,disable-modern=on,netdev=net0 \
-drive if=pflash,unit=0,format=raw,file=ovmf/ovmf-code-x86_64.fd,readonly=on \
-device virtio-gpu \
-cpu host,migratable=off \
-accel kvm -machine q35,smm=off \
-drive format=raw,file=menix.img,if=none,id=disk \
-device nvme,serial=FAKE_SERIAL_ID,drive=disk
works with 4G
I do know a bit
It works on mine, and can alloc correctly
how much are you allocating in qemu?
8G
because on 2G memory it panics
What does it say?
well it overwrites memory
and as far as i understand it, retAddress is not updated here
so it still points to the last entry you just said is free
which then gets overwritten, thus losing the metadata
Hmm
what qemu do you have?
maybe the same happens for you on 2G mem
because that causes a small region at the end of memory to spawn
or rather, can you please test if you ever hit cur_entry->count == 1 when allocating?
hmm
can you unhook the free function?
i think that is a bug
lol
thx for showing me that XD
trying to think about what is supposed to happen 
ret_address should be updated to something different
oh yea true
it's this->listPtr that should change
prob setting it to the prev entry if it exists
else to the next
something like this should work
what the hell is this even supposed to be
pmm
i couldn't get buddy to work
i want to get it working first, then i'll rustify it
that is literally so broken but okay
also this code seems so overcomplicated
idk why ur copying someone elses code
wdym so broken?
copying c/c++ into rust without writing it as idiomatic rust
does this fix that bug btw?
because he will have to rewrite it entirely anyway
ah yes
are you going to kill me if i tell you something
probably
i've never looked at how a freelist works
XD
it's just a linked list
yea but my brain always shuts down when i try to read any impl of it
idk what it's supposed to do, like what's the tldr of its operation
to keep a list of free entries bro
bro i get that
yea :3
well, it should point to free mem entries, and say how many pages they have
when you alloc it, the entry gets overwritten
so no memory is actually used
so how do you free shit? hook an entry between it?
you just append it to the list
or prepend if you're usinbg a singly linekd list
(set the count to how many pages you freed tho)
marvin most complicated alloc pages speedrun
:(
i swear linuxes impl is simpler
what does linux do
mine is pretty simple too
just had a bug that somehow never happened on my OS
idk how
XD
it will help you understand it better
struct page { page *next = nullptr; }
page head;
// init
page *cur;
for (pgaddr in memmap_pages)
{
pgaddr += hhdm;
if head.next == nullptr
{
head.next = pgaddr;
cur = head.next;
}
else
{
cur.next = pgaddr;
cur = cur.next;
}
}
// alloc
ret = head.next - hhdm;
head.next = head.next.next;
return ret
I haven't written a freelist allocator before but probably it's something like this
prob store the amount of free pages in the entry too
one entry == one page
so you can have less of them
if you set the count into an entry, it will go faster
and easier when allocating multiple pages
you generally don't need to allocate multiple pages
unless you're doing something wrong or dma
i do
for what?
i just made mine for that, just in case
then why are you doing a freelist?
do buddy
or even bitmap
freelist with multiple page allocation support is unnecessarily overcomplicated
no?
bro saying no doesn't invalidate someone's statement
it's not that diff from the single entry one tho
because different people are telling me different things ๐
monkuous
what did he say?
I'd rank freelist right after bump
.
bitmap isn't more complex than a multiple page freelist
but it uses memory
i dont really mind that#
I dislike it
it's fast, and you don't need more lol
a bitmap is way worse tho
bitmap is slow by default
u can make it faster but it's always gonna be slower than a freelist
buddy is also slower
I don't doubt that
that tend to outweigh the performance
so yeah, you decide if you want speed or buddy
-# (do buddy)
i am still surprised that the bug i had did not nuke my memory smh
i found a good one
then i need to redo buddy allocation because the impl i have right now is not coping with a single struct page region
(maybe can help if you want)
send it
pseudo rust free list https://gist.github.com/48cf/8928ada29766f6853e6f4e1ce0434e3e
tbh i just want to have working allocations again ๐ญ this shit is taking up so much of my time
found this nice visualization
I already know how it works in theory ๐ญ
i dont
I'm missing implementation details
i searched too, but couldn't find a lot of good stuff on it lol
i just went for a linked list for my heap alloc
that can alloc the size i want
you have multiple freelists for each 0x1000*2^n sizes
when you run out of one size, you take one page from n+1 and split it into two, allocate one, put the other in n freelist
when you free, you just put it back into those lists
if you want to take a look at my implementation i can link it
it's pretty simple
but where would I store metadata

