#HelixOS (ARM64 OS, not dead project!)
1 messages Β· Page 2 of 1
https://gist.github.com/tayoky/35380be499a4bf82f4aa48e232db0e6c this as all to make a vfs
note that you set the root node using chroot not using mount
Sounds good to me
Currently working on dynamic paging. Gonna be a long day working on the VMM.
I'm thinking I might need to setup two page tables. The first one being a "boostrap" page table so that I can map thee other othe into the reserved virtual range. Currently researching more about this.
Think I'm going to want to do something like this, but I'll need to rework the VMM for something like this...
okay I'm starting to get a little irritated with this. I can't think of a good way what so ever to handle mapping pages to a reserved region and not have to do recursive paging.
I don't want to map the entire physical region either.
I'll figure it out.
I'll probably need to divide my VMM code into different types of setup.
Rather than stress myself out trying to fit shit all into one thing
I'm going to need my PMM to return physcial address frames instead of virtual ones.
Tonight's going to be a hell of a lot of memory managment rework
Brtual night of VMM rework...
I think it's time I implement a kernel heap. I think it's a better approach instead of trying to allocate general purpose memory with the PMM.
I'm gonna start on this in the morning. I've burned my brain enough for tonight.
I'll check out how SerenityOS implements theirs and come up with my own based off that. I may implement a slab-based allocator for this.
Going to implement a kernel slab allocator kind of based off the current one I have, Then I can properly make kmalloc() use this.
And then I'll probably want to have my page tables allocated with this for easy management.
Hell this is probably what I should have did to begin with.
Time to implement the kernel heap.
goid
It'll be roughly based off of the general purpose one that I currently use for variable sized allcoations, but this one is for the kerenl heaep instead...
Well in this case my kernel heap will be a slab allocator implementation
It's going to have to be a bit more carefully crafted since I don't want to make any calls to pmm_alloc() for the slab objects themselves...
Might have to to take a different approach for the heap allocation stuff instead of trying to use a slab allocation method.
I realize trying to do that with a 16MB heap and no exsting calls to stuff like pmm_alloc() will be a pain in my ass
Or I can still do a slab allocation method, but do a linked list implementation
Had to rework the base a bit. Saw that Mint moved some stuff to codeberg, and wanted to ensure my base was cloning the correct repo's. This time I just forked them so if I need to make any edits for Helix I can do so
Currently reworking some suff.
Reworked the PMM ever so slightly, and I'm currently reworking my enitre VMM setup.
good
Had to rework some things haha
For now I've also removed the slab allocator. The initial PMM, slab allocator, and VMM was just to get the kernel going. Now that I have interrupt handling in place, and have a simple timerr, and serial driver I can focus more on improving this stuff.
I'll have to rethink the slab implementation later down the road, but for now I want to focus on my PMM setup.
Well and VMM of course
VMM is going to be undergoing a major rework to make it a bit more robust.
Or at least as robust as I can make it
For being able to keep track of page tables, etc, and being able to access them I've decided to take a chunk of the end of physical memory for this. During some of my research I learned that this is probably a better way of being able to track tables. I think 64MB is kind of overkill since only like 8MB is probably the most that's needed, but allows for a little wiggle room. I've got a simple vmm_pt_alloc() that just turned a pointer to the page table pool region which a given index, and uses the PMM as a fallback if the pool gets fully used up. It might get changed around a little bit, but this was a way for me to be able to handle being able to modify/unmap pages or entire tables.
how come
whats the reasoning
My original implementation would make calls to pmm_alloc() when a new frame was needed, but I struggled to implement a way to access the tables in virtual memory properly without falling into recursive page table mapping
I'm sure I could try again, and implement something though
whats so bad about recursive page table mapping
also are you on 64 bit
I was under the impression that recursive mapping was generally frowned upon.. but if it's not such a bad thing then I'll probably just go that route then
Sounds good!
I'll definitely make use of recursive mapping of the tables though. So that way if I need to modify an existing entry I can do so
I had eventual plans to implement a vmalloc() to handle continuous virtual memory allocations
but you dont need to do this if you have an hhdm
you can just access the page tables by their physical address plus the hhdm offset
That's true... My previous implementation didn't do a very good job of this, and I had ran into issues so I'll want to adjust that
It's good that I took time to clean things up a bit though. The last implementation was a bit of a mess, but at least it worked lol
That's very true..
I realize too I can always do page swapping when needed when I get more towards getting a disk drive, and filesystem in place so I shouldn't worry too much on it...
Working more on the VMM today. Currently improving my code to handle getting different page table levels, and also handling freeing of empty tables, etc.
static void vmm_map_table(page_table_t *table, uint64_t virt, uint64_t phys) {
vmm_map(table, virt, phys, PT_TABLE | PT_VALID);
}
void vmm_map(page_table_t *table, uint64_t virt, uint64_t phys, uint64_t flags) {
uint64_t l0_idx = PGD_IDX(virt);
uint64_t l1_idx = PUD_IDX(virt);
uint64_t l2_idx = PMD_IDX(virt);
uint64_t l3_idx = PTE_IDX(virt);
assert(table != NULL);
page_table_t *l0 = (page_table_t *)PHYS_TO_VIRT((uint64_t)table);
if (!(l0->entries[l0_idx] & PT_VALID)) {
page_table_t *l1 = pmm_alloc(1);
assert(l1 != NULL);
l0->entries[l0_idx] = (uint64_t)l1 | PT_TABLE | PT_VALID;
vmm_map_table(l0, PHYS_TO_VIRT((uint64_t)l0), (uint64_t)l0);
}
page_table_t *l1 = (page_table_t *)PHYS_TO_VIRT(l0->entries[l0_idx] & ~0xFFF);
if (!(l1->entries[l1_idx] & PT_VALID)) {
page_table_t *l2 = (page_table_t *)pmm_alloc(1);
assert(l2 != NULL);
l1->entries[l1_idx] = (uint64_t)l2 | PT_TABLE | PT_VALID;
vmm_map_table(l1, PHYS_TO_VIRT((uint64_t)l1), (uint64_t)l1);
}
page_table_t *l2 = (page_table_t *)PHYS_TO_VIRT(l1->entries[l1_idx] & ~0xFFF);
if (!(l2->entries[l2_idx] & PT_VALID)) {
page_table_t *l3 = (page_table_t *)pmm_alloc(1);
assert(l3 != NULL);
l2->entries[l2_idx] = (uint64_t)l3 | PT_TABLE | PT_VALID;
vmm_map_table(l2, PHYS_TO_VIRT((uint64_t)l2), (uint64_t)l2);
}
page_table_t *l3 = (page_table_t *)PHYS_TO_VIRT(l2->entries[l2_idx] & ~0xFFF);
if (!(l3->entries[l3_idx] & PT_VALID)) {
l3->entries[l3_idx] = (uint64_t)phys | flags;
}
}
Probably the ugliest way to recursive map page tables. I don't really want to map the entire usable memory at once if I don't need to.
I realize I already fucked up on mapping the tables.
lol
my map function
wasn't recursive
i think that's why it was troubling me
lol
I"m trying to make it so I can access my page tables from another virtual range to modifty/delete, etc, but I'm falling back into the same rabbit hole I went down before the VMM rewrite...
oh damn
im trying to do some other projects before getting onto my OS again
i did 1 commit today tho
but i just changed the makefile
That's better than nothing
Well it looks like I finally managed to do it. It's kind of an ugly way of doing it, but it works.
void vmm_map(page_table_t *table, uint64_t virt, uint64_t phys, uint64_t flags) {
uint64_t l0_idx = PGD_IDX(virt);
uint64_t l1_idx = PUD_IDX(virt);
uint64_t l2_idx = PMD_IDX(virt);
uint64_t l3_idx = PTE_IDX(virt);
assert(table != NULL);
page_table_t *l0 = (page_table_t *)PHYS_TO_VIRT((uint64_t)table);
if (!(l0->entries[l0_idx] & PT_VALID)) {
page_table_t *l1 = pmm_alloc(1);
assert(l1 != NULL);
l0->entries[l0_idx] = (uint64_t)l1 | PT_TABLE | PT_VALID;
vmm_map_table(pgd, PT_VIRT_BASE + l0_idx * PAGE_SIZE, (uint64_t)l0);
}
page_table_t *l1 = (page_table_t *)PHYS_TO_VIRT(l0->entries[l0_idx] & ~0xFFF);
if (!(l1->entries[l1_idx] & PT_VALID)) {
page_table_t *l2 = (page_table_t *)pmm_alloc(1);
assert(l2 != NULL);
l1->entries[l1_idx] = (uint64_t)l2 | PT_TABLE | PT_VALID;
vmm_map_table(pgd, PT_VIRT_BASE + l1_idx * PAGE_SIZE, (uint64_t)l1);
}
page_table_t *l2 = (page_table_t *)PHYS_TO_VIRT(l1->entries[l1_idx] & ~0xFFF);
if (!(l2->entries[l2_idx] & PT_VALID)) {
page_table_t *l3 = (page_table_t *)pmm_alloc(1);
assert(l3 != NULL);
l2->entries[l2_idx] = (uint64_t)l3 | PT_TABLE | PT_VALID;
vmm_map_table(pgd, PT_VIRT_BASE + l2_idx * PAGE_SIZE, (uint64_t)l2);
}
page_table_t *l3 = (page_table_t *)PHYS_TO_VIRT(l2->entries[l2_idx] & ~0xFFF);
if (!(l3->entries[l3_idx] & PT_VALID)) {
l3->entries[l3_idx] = (uint64_t)phys | flags;
}
}
I'll clean it up a bit, but at least this will allow me to access tables in the virtual address region I reserved for page table mappings.
It's a 64MB region since I only really need 8MB for a 4GB physical memory.
Okay that was a bad idea... I'll want to make it map to the same virtual address as it's physical address.
Ran into issues on that last one
I can't really access the page tables without mapping the entire physical space. I've not yet found a good solution to this.
I think I better solution is to just map the beginning of physical memory up to 1GB for the kernel, and leave the rest for the eventual userspace.
At least then I can access the page tables...
youre on 64 bit theres nothing wrong with mapping all of physical memory
note that you only need to create mappings for ram that actually exists
Well in this case I think I'll do so then, but I though doing so would cause trouble down the road for the eventual userspace mappings. But then again I realize this is where page swapping, etc, comes into play. And ARM64 the TTBR0_EL1 register holds userspace mappings where as TTBR1_EL1 holds the kernel space mappings
why does it cause trouble for userspace
That's just a thought that I had; I'm aware I can map the same physical addresses for different pages, but I assume I'd want to make userspace mappings non-global
what does any of this have to do with mapping all of phys mem
Fair enough.... I'lll just map the full physical region and be happy with it
That's what I have done now as well as the framebuffer, and some MMIO to handle serial, and interrupts, etc
Then I should be good then in that case, and will start working on my kernel heap allocator
Finally getting a new kernel heap allocator in place.
Then after I can start working on other parts of the kernel. I was thinking to maybe work on a VFS, implement a disk driver, and then work on a read-only EXT2 filesystem driver. Write support can always come later down the road
i think getting userspace is more important
dont give nonsense advice pls
okay
The kernel heap allocator will mostly end up being a simple slab allocator with a 4MB heap. Just to get things going..
I can always change this in the future, but for now this will work fine
just to know what happend if there is not engout memory ?
Memory isn't an issue at all.. I just wanted to have a separate kernel heap space
no like what happend if you call kmalloc and there aren't enought kheap and/or memory
For now because it's the initial implementation if the memory is to be completely used I can either:
-
- Increase the heap array size
-
- assert
But this is just a quick and dirt heap implementation for now...
How did you end up implementing yours?
my kheap is just a freelist of all segment (allocated or free) and when there aren't enought place i icrease the size (i trigger an kernel panic if not enought memory to increase the size
Not bad actually! Mine is basically just a slab allocator that uses a 4MB heap array as the backing store for slab objects..
Right now it's just a quick and dirty implementation to get the kernel going
i think slab allocator is better
I agree
this is fine
But if I really need to I can increase the size from 4MB up to 16MB if needed, but I felt that 4MB should be plenty for my needs for right now
if i remeber a slab allocator is something like a list of slab (memory segment) being full empty or paritial then you search a full or partial and find place in it
a slab is for a specific size if i remeber
Yes correct
just one question do you round anything ? like you round to a power of 2 or something (allocation of 6 become 8 allocation of 24 become 32) to reuse slab ?
have you push your slab allocator ?
Yes
I have some old commits of the original one that I implemented, but removed it. I'll be implementing a bit of a more improved version for the kernel heap, but will sort of be based off the original with additional improvments
okay good
The old version wasn't too good, and would often have to re-allocate a new slab for different sizes if the one requested didn't exist instead of trying to do a best-fit for the requested size
Decided to go ahead and get started on porting mlibc to HelixOS.
Got it to configure... now to start getting the other shit in place...
I kind of like the meson build system
I almost like it better than CMake to be honest
I'll worry about that later. Gonna continue working on the kernel.
Apparently my ADHD brain is taking over again.
Working on virtio MMIO.
Gotta fix a few slab allocator bugs
Seems to be fine for now. It's quick and dirty for now just to get things going. I plan to clean the allocator up later
Well apparently after resetting the virtio device for setting up features, etc, I never get the reset acknowldegment. It's kind of pissing me off.
Got it.
Turns out I was just doing it incorrectly.
virtio fot what ? disks ?
Yes
And maybe eventually networking, but not at this time
okay good
so you're going to make an virtio driver fot disk then GPT and/or MBR then FAT32 or ext2 i guess ?
Yes correct
have you a ramfs ?
Not right now. Once I get disk access going I planned to get a vfs going, then work on EXT2 and mount that instead
i say that because the "classic" way of doing things is to have an ramfs or initrd mount as root then you mount an ramfs as /dev
then you can scan all the drives and mount it as /dev/sda /dev/sdb /dev/hda /dev/hdb
then you mbr/gpt driver scan for all block devices in /dev and create /dev/sda1 /dev/sda2 /dev/hda1 ...
and then with your ext2 driver you can mount(or chroot) /dev/sda2 as your new root
I still do plan to get a ramdisk in place as well. I just really wanted to get disk access going
yesi just say you should do a ramfs so you can expose the disk easely
That's my plan eventually...
okay good
I gotta eventually figure out why my VMM doesn't map the first 1GB of physcial memory despie iterating the memory map. I have to manually do this outside of the four loop..
I'll worry about it tomorrow...
Do you have userspace and app loading?
the nice thing with virtio is the device-specific code is quite small, so once you have virtq stuff for one driver, you can very easily get others running.
virtio gpu is nice for having multiple framebuffers
So far I've gotten the device setup, initialized, and ready to go (debugging the register value in vscode showed a valid return code). I just need to learn to properly construct a device request and ensure the correct IRQ ID is setup too...
But the important thing is that I've gotten the device initialized...
I do hope to eventually take advantage of this feature I'm the future...
Since using the ramfb device isn't the best thing to use haha
I think I might have to re-implement my heap allocator
At that point might just bring back the old slab allocator...
Nah I'll just re-implement it...
Except I'm tired today so I probably won't get too much of it done.
After a good nap I'm getting back to work on this kernel heap allocator
I'm just going to fix the PMM, and bring back the old slab allocator for this.
Sick of making changes to the heap allocator, and end up with the exact same results
Let's hope the bitmap bug I had was setting the bitmap itself to 0xFF instead of 0x00.......
Yeah.... that happened
Okay no that was needed I forgot.
Gotta make sure I map the bitmap though...
Ended up having to bring back the old allocators I had before. What a bullshit day of debugging.
I guess if the old allocators aren't broke don't "fix" them.
Had to implement pmm_alloc_pages() for the slab allocator. Finally reached a stage where I need more than a single page frame...
It's not complete since I still need to implement pmm_free_pages() and handle a multi-page free. But right now this is just to get the virtio shit going.
At least to test and get the disk device geometry.
Well this is some major progress.
@unreal creek
realllly good
can you read the disk ?
That's actually what I'm about ti implement up next is disk reads/writes
I have to setup a descriptor request for it
cool
I need to cleanup some of the code though.... lol
lol it happens, but at least you have some more experience now.
do you?
how big are these slabs?
This is true! π It feels nice to gain that knowledge to be honest...
The slabs were no larger than the length of a single page to try and device that page into smaller chunks of memory... But since I've been working on the virtio driver, etc, the vring allocation ended up being significantly larger than expected so I had to finally handle multi-page allocations...
What's irritating though is that this virtio mmio doesn't fire off an IRQ. My other IRQ's are working fine, but for what ever reason the IRQ status stays zero, and nothing else happens despite setting up the test for a disk read several times to try different things.
Getting this device working has been a real pain in my ass.
I'll keep at it till I get my reward. The nice things about this though is that when memory allocator bugs manafest I can introduce a fix for them
Well one thing I do see if that the address of the QUEUE PFN is still virtual, and this expects a physical address.
Never mind it was a physical address, but wasn't properly aligned.
you should probably make a virt2phys to convery a virtual address to a physical address (and return NULL if it isen't mapped)
it can be useful in a lot of situation
I do have plans to implement it, and improve my VMM....
Getting disk access going has been no easy task. Even for the lagecy MMIO device it's got a lot involved...
Heads up, you can use at instruction, I suggest reading about it before you're writing this code
Will do!
So.... I've decided to go with the more well documented virtio device for disk access.....
so restarting from scratch ?
For the virtio driver? Yes...
okay
I'll be using the PCI device this time
okay good
Trying to get the lagacy stuff going proved to be way more difficult. Especally with the fact I can only find one document on it compared to the newer version of this device
The PCI configuration seems like it will be nice to work with...
I plan to spen several days reading the docs, and implementing what I'll need to get disk access going. Later down the road I'll look into the networking and GPU side of things
Welp I see there's a way to force QEMU to not use legacy mode.
So to force QEMU to use newer version fo the virtio mmio you'd do this:
-drive if=none,file=${HDD_IMG},format=raw,id=vda1 \
-device virtio-blk-device,drive=vda1,bus=virtio-mmio-bus.0 \
-global virtio-mmio.force-legacy=false \
V2 is now in use....
It'll be nice to take advantage of these features it provides.
Finally getting the device initialized, and ready to go...
This part is pretty easy
/*
* Device initialization:
*
* - Reset the device
* - Set the acknowledge bit
* - Set the driver status bit
* - Read the device features bits, and write a subset of them understood by the OS
* - Set the features_ok status bit, read-read to ensure the bit is till set (otherwise feature(s) are not supported)
* - Perform device-specific setup, includes virtqueues discovery, writing devices virtio configuration space, etc
* - Set the driver_ok status bit (device should now be "live")
*/
Device initalization process... I made a comment for this to help me remember, but it has to be done in this order.
As I study the documentation, and read existing sources for this I now am beginning to understand how the descripter queue, etc, works.
It's nice to gain some knowledge about how this stuff works
i will keep that if i need it some day
Although the documentation describes this setup process it's still nice to have a little reminder...
you should only need contiguous allocations if your queue size is massive. With a single page you could have 256 descriptors (which could be bigger I guess), but its still a decent amount.
ah you're dealing with the legacy interface, rip
aand you've sinced moved on to the 1.0+ interface lol - good progress π
I think I may need to adjust my alignment since Doing a max queue size of 128 just barely exceeds the 32K allowed by just a few kb π
Thank you good sir! I've learned a lot so far π
Right now I've been trying to test the device to see if I can read from the disk, but so far absolutely no change in status occurs...
change in status?
and the qemu trace events may be helpful here
you might get some hints as to where things are breaking down
This is very true actually! I didn't even think about using trace events... This will definitely be useful. I had to make use of them during the development of the GIC earlier on
I notice no IRQ is pending, and it doesn't seem to acknowledge the fact it has a descriptor either so yes I'll want to use trace events here..
So far according to the trace event logs it's doing exactly what it should be for pulling the deescriptors, etc. So that's a good sign
And the notify events are working too so this is also good
But... the IRQ's don't ever seem to fire though. Other IRQ's fire just fine so I'll want to look into this for a while
virtio_mmio_setting_irq virtio_mmio setting IRQ 0
According to the trace logs it apparently sets the IRQ, but from further research IRQ 0 is apparently resereved in QEMU?
virtio_queue_notify vdev 0x618b1343bf00 n 0 vq 0x722b180d3010
virtio_queue_notify vdev 0x618b1343bf00 n 0 vq 0x722b180d3010
virtio_blk_handle_read vdev 0x618b1343bf00 req 0x618b13761ca0 sector 0 nsectors 1
virtio_blk_rw_complete vdev 0x618b1343bf00 req 0x618b13761ca0 ret 0
virtio_blk_req_complete vdev 0x618b1343bf00 req 0x618b13761ca0 status 0
virtio_queue_notify vdev 0x618b1343bf00 n 0 vq 0x722b180d3010
virtio_blk_handle_read vdev 0x618b1343bf00 req 0x618b13761ca0 sector 1 nsectors 1
virtio_blk_rw_complete vdev 0x618b1343bf00 req 0x618b13761ca0 ret 0
virtio_blk_req_complete vdev 0x618b1343bf00 req 0x618b13761ca0 status 0
virtio_queue_notify vdev 0x618b1343bf00 n 0 vq 0x722b180d3010
virtio_blk_handle_read vdev 0x618b1343bf00 req 0x618b13761ca0 sector 2 nsectors 32
virtio_blk_rw_complete vdev 0x618b1343bf00 req 0x618b13761ca0 ret 0
virtio_blk_req_complete vdev 0x618b1343bf00 req 0x618b13761ca0 status 0
virtio_queue_notify vdev 0x618b1343bf00 n 0 vq 0x722b180d3010
virtio_blk_handle_read vdev 0x618b1343bf00 req 0x618b13761ca0 sector 8388607 nsectors 1
virtio_blk_rw_complete vdev 0x618b1343bf00 req 0x618b13761ca0 ret 0
virtio_blk_req_complete vdev 0x618b1343bf00 req 0x618b13761ca0 status 0
virtio_queue_notify vdev 0x618b1343bf00 n 0 vq 0x722b180d3010
virtio_blk_handle_read vdev 0x618b1343bf00 req 0x618b13761ca0 sector 8388575 nsectors 32
virtio_blk_rw_complete vdev 0x618b1343bf00 req 0x618b13761ca0 ret 0
virtio_blk_req_complete vdev 0x618b1343bf00 req 0x618b13761ca0 status 0
virtio_queue_notify vdev 0x618b1343bf00 n 0 vq 0x722b180d3010
virtio_blk_handle_read vdev 0x618b1343bf00 req 0x618b13761ca0 sector 2 nsectors 32
virtio_blk_rw_complete vdev 0x618b1343bf00 req 0x618b13761ca0 ret 0
virtio_blk_req_complete vdev 0x618b1343bf00 req 0x618b13761ca0 status 0
virtio_queue_notify vdev 0x618b1343bf00 n 0 vq 0x722b180d3010
virtio_blk_handle_read vdev 0x618b1343bf00 req 0x618b13761ca0 sector 2048 nsectors 1
This seems to show it's processing my request.
But still no IRQ so this is just strange. And again other IRQ's fire as normal so I'm not too sure what's going on here for the MMIO
Time to go RTFM for a while
Well I see I wasn't setting the queue_ready register after setting up the descriptors... whoops
qemu: virtio: bogus descriptor or out of resources
Well! That's certainly progress!!!!
I'll need to fix a few things, but this is good to see after many failed attempts...
I need to fix my alignment as I suspected. But I seem to have issues with trying to use larger queue lengths. Apparently this all needs to fit within a page. I did read that this expects a contiguous block of memory though, and that the max queue length can be 32K in size of needed
I realize now that each descriptor needs to be aligned within it's own page....
Well fuck me sideways
Well and the virtio desc, avail, and used structs must be aligned to cache sizes so I made some helpful macros for handling this...
#define VIRTIO_ALIGN(x, align) (((x) + align) & ~align)
#define VIRTIO_DESC_ALIGN(qsz) VIRTIO_ALIGN((qsz), 16)
#define VIRTIO_AVAIL_ALIGN(qsz) VIRTIO_ALIGN((qsz), 2)
#define VIRTIO_USED_ALIGN(qsz) VIRTIO_ALIGN((qsz), 4)
Alignment has been fixed. I can have my 128 queue size with a max size of 19K. Of course ensuring things are aligned on page boundaries
32K is the max allowed length as well so I can't exceed this
Also, the queue size itself MUST be a power of 2
this things with queue and that stuff make me think of nvme
Is nvme the same way?
yes you have submision queue where you send command
and then a response queue (it's not call like that)
in general a lot of "modern" (or well not even really that modern) hardware uses a similar mechanism with queues (high definition audio, xhci, nvme etc)
Well learning this now is virtio I'm sure will really help me in the future with implementing other queue-based drivers
MAJOR PROGRESS HAS BEEN MADE FOLKS
IRQ's FINALLY FIRE FOR THE DEVICE!!!
All that's left now is to track down what IRQ number this device is....
So it completes the request, fires the IRQ, etc... using the event traces for this has helped a ton!!!
Hmm I'm noticing that no IRQ ID's that I've enabled (0-1024) have shown up in my IRQ handler so far (it would tell me the particular IRQ ID is unregistered if it detects this)
YOOOOO LETS FUCKING GO I HAVE DISK ACCESS!!!!!
@frozen silo @unreal creek
I still need to figure out the IRQ ID for the handler to actually be called if this is the case, but otherwise it works!!!
0x55AA is the ending of the first sector.... and I can read the data!!!
@lime sapphire
Dude I'm excited as hell right now. I'll clean up the rest of the virtio driver today to better handle things, but for now this was a test to ensure the driver was working, and it is!!

It was well worth the effort to get it working π
Looks like the device configuration space might be where I need to handle setting this stuff up for IRQ's, etc.... time to look more into this. But hell yeah disk access is working!!! I gotta clean things up though....
Now that I understand how the device is setup as well I can even eventually inplement virtio-net support for networking...

What's kind of irritating though is the IRQ for this device is never fired. The device completes the request, I'm able to see that the buffer was populated, the IRQ status gets set from 0x0 to 0x1 indicating an IRQ asserstion was sent, but... nothing..
I've also tested, and enabled literally every IRQ possible and none for this device got called for that partiular PPI.
I just noticed the HHPIR register goes from 1023 -> 48... maybe this is my IRQ??
I FUCKING GOT IT BABY!!!!!!!!
IRQ 48 was the IRQ ID....
@tender acorn
Now I can work on properly handling the used descriptors, etc, after the device fires an IRQ
nice
Figured out the IRQ being fired by reading the HPPIR1 register... that told me what IRQ was being asserted, but wasn't being handled...
Fuck yeah I have disk access!!!
hell yeah
Now time to clean things up, and fixup my memory allocators... after that I'll work in a vfs, then implement vfat, and ext2
Currently working on some virtio stuff now that I know the driver works. Working on some helpers to handle descriptor allocations/freeing, and submitting requests to the device.
That sure as well was well worth the effort, and debugging it took to get it working...
Now that I have disk access I can cleanup my allocators a bit. It'll be good for my virtio driver...
very nice, congrats on the milestone
Thank you good sir!! π
awsome π
you should expose that on some kind of devfs i think (that's how most UNIX like system does
That's my plan once I get the vfs, etc implemented
how far are you with the vfs ?
I ended up removing it for now so I can cleanup my allocators; I plan to get started hopefully tonight or tomorrow
I'm reworking my slab allocator since the last implementation had a lot of bandaid "fixes" to test virtio lol
Getting disk access going was a huge goal of mine.... now that I've done it I feel really good about getting other thigns in place...
It's starting to feel like more of a kernel now hahahaha
when you start to have your first complexe driver it alaways look like a kernel (by complexe i mean more complexe than just a framebuffer or serial driver)
In this case the virtio driver; I do need to push the new commit once I finish my slab allocator, and test that the cleanup virtio stuff is working fine. But knowing that it works is great
i recommand you to commit (or at least stage) before cleanup (i alaways do that) so if your cleanup messed up something you can alaway go back and restart
I do already have the initial commit of it in the repo now (feel free to check it out, and tell me what you think). I've since cleaned things up a bit, and implemented some helper stuff. I also implemented some functions virtio_blk_read() and virtio_blk_write() to handle raw disk acceess
@unreal creek
okay
uhm. Did you fix this macro? Because it's wrong. Instead it should be
#define VIRTIO_ALIGN(x, align) (((x) + align - 1) & ~(align - 1))
but align must be a power of 2, so istead i'd define it as:
#define VIRTIO_ALIGN(x, alignlog) (((x) + (1 << alignlog) - 1) & ~((1 << alignlog) - 1))
I have no, but I will now... Thank you for the correction
It isn't wrong, they are using it wrong
alignlog of course is logarithm of your align. So to align at 512, you'd use `VIRTIO_ALIGN(x, 9)
if you dont want to fix the macro you can do it like
#define VIRTIO_DESC_ALIGN(qsz) VIRTIO_ALIGN((qsz), 15)
#define VIRTIO_AVAIL_ALIGN(qsz) VIRTIO_ALIGN((qsz), 1)
#define VIRTIO_USED_ALIGN(qsz) VIRTIO_ALIGN((qsz), 3)
Sounds good
but i recommend you just fix the macro
I went ahead and added the new change just to be on the safe side... I'll test to make sure things look fine, and then I can push the new change. I'm fixing my slab allocator right now since the previous implementation is a bit hackish...
Ended up making my new version of my slab allocator a first-fit/best-fit hybrid so far.
Might not be the best thing, but it's better than the last version. The last version was a bit trashy, and was basically allocation a new slab or different sizes of objects instead of doing my new approach...
Currently working on handling when I run out of object to allocate a new slab object, and add this to the list.
I've made some really great progress lately, and I'm quite proud.
The biggest goal for me was getting that virtio driver going.... I really wanted to have disk access implemented as soon as possible
good
I also decided to support a larger allocation size as well compared to the old version....
The pmm still needs to have pmm_free_pages() implemented though for handling multiple page frame deallocation
But after getting this stuff done the rest of the way tomorrow I'll get started on the VFS after testing the new virtio driver changes...
I'm looking forward to playing around with filesystem access
I want to take my time getting there of course.
you can take a look at my vfs it's a classic UNIX like vfs (it just don't support unmount) https://github.com/tayoky/stanix/blob/main/kernel%2Ffs%2Fvfs.c
An 64 bit OS made from scratch. Contribute to tayoky/stanix development by creating an account on GitHub.
I should never code when tired. I just noticed I crashed in my slab allocator before I can use the last object before needing to allocate a new, and this is because I was decrementing the freelist itself instead of the free object count... whoooops
Sounds good to me
Slab allocator rework is now completed, and tested...
It works quite well, and properly handles creating a new slab object as well as linking ONLY when we've run out of available objects..
And it returns the available objects accordingly properly too...
Now, to work on virtio a bit...
kmalloc() for now if lengths are larger than 4K it just falls back to the pmm to allocate X amount of frames... this will be changed in the future
Otherwise it uses the slab allocator
Looks like the virito driver will need lots of work if I'm going to properly handle used/free descriptors....
π
The virtio disk driver has been cleaned up, and works flawlessly!!! I now have disk read/write access!!
@unreal creek I'll be pushing the new driver update today
The only thing I notice is that I can't apparently reuse the same buffer for reads/writes which I've yet to figure out. So I had to use seperate buffers for now
New commit it live
I may have to implement something differet for buffers for the virtio stuff.... I'll work on that and the vfs both tonight so I can get the vfs started
The virtio very much isn't the best, and does have much work that needs to be done to improve it though.
Looks like I was able to fix the seperate buffer access.
Took me all day, but it works now...
Getting started on a minimum vfs implementation finally... this is what I was working on previously, but got some other things in place before hand. Now that I have disk access going I'm super excited to eventually implement ext2 and vfat support
good
you also need a tmpfs/ramfs
for your devfs
does this support multiples virtio disk ?
Currently no just one disk for now... later down the road I had plans to improve it to support multiple disks
Oh absolutely! Right now I'm working getting a simple VFS in place. Then I can work on a tmpfs, then go for the devtmpfs
Wanted to parse the MBR for the fun of it... @unreal creek
Disk access is working perfectly!!
Right now I'm just studying about the VFS a bit
The new virtio disk changes have been pushed so you're good to go check it out
Keep in mind it can probably be very much improved... but for now it's working great
tmpfs and devfs are the same thing you create a tmpfs mount it as /dev and then you mount device as /dev/hda , ...
that should be done via the vfs for abstractions
Ahhhh I see now!
Well yes of course! This was just for a quick test, but I'm slowly working on the VFS finally
so your mbr thing can work on virtio disk nvme ssd ata disk or whanever wihout taking care of the disk type
Once I'm ready to implement and expose devices, etc, to /dev I'll make my virtio disk drive /dev/vda like linux would
then your mbr can scan for all block device in /dev/ and try to find a mbr on it if it find one it create the partition devices /dev/XXX1 /dev/XXX2
That will be really nice
Once I get the vfs in place I'll implement tmpfs, then work on the /dev stuff, and then work on ext2. Later after that I'll work on vfat, but not at this time...
I planned to mount the EFI partiiton under the eventual /boot
so for the moment this won't work on real hardware (virtio)?
Unfortunately no since it relies on QEMU's virtio stuff... Maybe sometime down the road I can clean things up a bit, and make it so it can boot on things like a raspberry pi
I eventually also need to implement a DTB lib for the kernel...
for the raspberry pi it's an sdcard and it use device tree
Maybe down the road I should implement sd-card support haha
For right now though my kernel only boots off QEMU's virt board
The main task as of right now is to get the VFS in place, then get a tmpfs implemented
okay what you've got right now ?
Right now I'm just barely working on the VFS so not much. I've been reading documentation, etc, to get an understanding about how it abstracts from hardware, etc
So I'll be spending the next few weeks working on this now that I've got things in place for it...
I must say I'm super excited to finally get the virtual filesystem going...
@unreal creek For the vfs file struct should it contain anything for inodes? Or should it just conatin stuff like the file name, length, etc?
no inode is fs specific
so no
Sounds good!
you should have in your vnode a void pointer (so fs can store a pointer to their inode in this field)
This is what I have so far
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
okay i can see some problems
your node struct is really good
but first of all
vfs_inode_opts_t should not exist
vfs_file_t should not exist
and vfs_file_opts_t should be renamed to vfs_opts_t and contain function pointer for operation on file and directories
with something like this functions :
seek
read
write
close
lookup
readdir
symlink(optional)
setattr
getattr
readlink(optional)
also your node structure should have a pointer to the struct vfs it's mounted on
Ahh sounds good; I'll start making some adjustments
btw getattr is from update the info of the vnode (the fs go search the lasted info and umdate the one on the vnode) and setattr do the opposite (the fs take the metadata from the vnod and push it to the filesystem on the disk)
you might not need setattr
but the sun paper as it
i think it is used because there aren't chown and chmod
so you set the uid and gid on the vnode then use setattr to change the owner
tell me when you finish
And then flush those changes to the filesystem I'd assume
Will do!
yes maybee
i really like to see project starting from scratch
at the start there nothing then a PMM then a VMM then some drivers then a vfs
I remember when I was just barely getting Limine going, and what not haha
Pastebin.com is the number one paste tool since 2002. Pastebin is a website where you can store text online for a set period of time.
wayyyyyu better
just rename vfs_file_opts_t to vfs_opts_t
Sounds good!
and also you don't need all of your define and your dirent
just make a custom sys/stat.h that can be reuse later for userspace program
and then use struct dirent
I was thinking the VFS would need these flags, but now it makes more sense not having them the more I think about it haha
same for define with O_XXX they should be in a custom fcntl.h
that when you start to have to make custom libc header
Sound good to me! I'll just remvoe those definitions then
Once I get the VFS going I'll start on the tmpfs implementation
I noticed your VFS has this though:
#define VFS_MAX_NODE_NAME_LEN 256
#define VFS_MAX_MOUNT_POINT_NAME_LEN 128
#define VFS_MAX_PATH_LEN 256
#define VFS_FILE 0x01
#define VFS_DIR 0x02
#define VFS_LINK 0x04
#define VFS_DEV 0x08
#define VFS_MOUNT 0x10
#define VFS_CHAR 0x20
#define VFS_BLOCK 0x40
yep because flags in my vfs and in the userspace api are not the same
in syscall.c they get converted when using stat or fstat
Ahhh I see
and you can see it include <sys/stat.h>
wich is a custom stat.h that i made in my libc
Is this for the userspace libc?
sys/stat.h ?
nop sys/stat.h is a libc header
Ohh I see
How did you determine the permissions for your vfs if I may ask? Like to determine what's a flile, etc
i have flags that determinate the type
and i have a perm field in my vnode for permission
How did you determine them?
the perm?
In your VFS yes
the filesystem driver fill the field when creating the vnode
I was talking about these:
#define VFS_FILE 0x01
#define VFS_DIR 0x02
#define VFS_LINK 0x04
#define VFS_DEV 0x08
#define VFS_MOUNT 0x10
#define VFS_CHAR 0x20
#define VFS_BLOCK 0x40
I was wanting to see how you determined these so I could learn, and implement them as well
the file system fill the flag field
and VFS_MOUNT is set when using vfs_mount
it's when you do a lookup
wait let me show you for tmpfs
Ahhh I see
I understand now
so for exemple for you virtio you create a vnode and set the type to BLOCK
then you set the operation
and finally mount it as /dev/vda
that as simple as that
even better
you could make the data field point to the virtio_blk_dev_t
so you can have multiples virtio vnode
and so multiple virtio devices
Oooo that's actually not a bad idea! Because in the future I'd like to eventually support multiple disks
the basic stuff is ```c
ssize_t virtio_blk_read(vnode *node,void *buf,size_t count){
virtio_blk_dev_t *dev = node->data;
//do actual read
}
vfs_opts_t {
.read = virtio_blk_read
} virtio_blk_opts;
void virtio_init(){
char c = 'a' ;
//scan pci device
for each virtio found :
vnode *node = kmalloc(sizof(vnode));
virtio_blk_dev_t *dev= kmalloc(sizeof(virtio_blk_dev_t));
vnode->data = dev;
//init your dev or whanever and reset the device
node->opts = &virtio_blk_opt;
node->type = VFS_BLOCK
char path[20];
snprintf(path,"/dev/vd%c",c);
vfs_mount(path,node);
a++;
}```
and like that you can have multiples devices
avalible under /dev/vda /dev/vdb ...
up to 26
Ahh now I see how this would work
Wouldn't I so something like this when setting up for /dev?
Ahhh now I'm understanding
to setup your devfs you just do something like vfs_mkdir("/dev");vfs_mount("/dev",new_tmpfs());
Sounds good to me!!
the first step after vfs is to get a tmpfs
and then setup root with something like vfs_chroot(new_tmpfs());
if you don't now what is vfs_chroot() it's a bit special
normally on UNIX like system you can't mount anything as root instead you sue chroot to change the root directory to another vnode
but some OSes have special case where when you do vfs_mount("/",XXX) it do the job of chroot
the biggest difference between chroot and mount is that for root you just have a global variable vnode *root; and you change this variable
Which will make things a lot easier for switching roots
yes
most of the time you setup you initrd as your temporary root
then mount the new partition
and chroot it
In this case I was planning to mount the actual ext2 parititon as the root filesystem
I was wanting to do a ramdisk, but I was really just wasnign to mount the root partition directly
static vfs_root_t *vfs_root = NULL;
void vfs_init(void) {
if (!vfs_root) {
vfs_root = kmalloc(sizeof(vfs_root_t));
assert(vfs_root != NULL);
}
vfs_node_t *root_node = kmalloc(sizeof(vfs_node_t));
assert(root_node != NULL);
strncpy(root_node->name, "/", sizeof(root_node->name));
root_node->parent = NULL;
root_node->children = NULL;
root_node->siblings = NULL;
root_node->fs_opts = NULL;
root_node->uid = 0;
root_node->gid = 0;
strncpy(vfs_root->name, "root", VFS_MAX_NAME_LEN);
vfs_root->mount = root_node;
vfs_root->flags = VFS_TYPE_DIR;
}
So I believe this is how I can get the root node setup, right? This is what I at least remember from my old code. Well that, and trying to read docs, etc
actually you don't need to init anything
just do root = NULL;
the root will be set when you will do chroot(new_tmpfs());
From my research I absolutely have to initialize the root node
you can but it will be erase anyway
i just don't do it to save a bit of memory
I can always just free the memory when going to switch roots
i don't think
- chroot into a tmpfs
- cd into root
- mkdir test
- chroot into test
- you can still acces the old root via the cwd
static vfs_root_t *vfs_root = NULL;
void vfs_init(void) {
if (!vfs_root) {
vfs_root = kmalloc(sizeof(vfs_root_t));
assert(vfs_root != NULL);
}
vfs_node_t *root_node = kmalloc(sizeof(vfs_node_t));
assert(root_node != NULL);
strncpy(root_node->name, "/", sizeof(root_node->name));
root_node->parent = NULL;
root_node->children = NULL;
root_node->siblings = NULL;
root_node->fs_opts = NULL;
root_node->uid = 0;
root_node->gid = 0;
root_node->ino = 1;
root_node->nlink = 1;
root_node->length = 0;
root_node->atime = root_node->mtime = root_node->ctime = 0;
strncpy(vfs_root->name, "root", sizeof(vfs_root->name));
vfs_root->root = root_node;
vfs_root->flags = VFS_TYPE_DIR;
vfs_root->next = NULL;
printf("VFS: Initialized root on: %s\n", vfs_root->root->name);
}
Here's my vfs_root mount setup... Since I'm doing a linked list of mounts, etc...
that work
just never use open until you do chroot
cause your initial root don't have ops
Right... otherwise things would go horribly lol
I'm so happy to have disk access going
And then implemeneding the read, write, etc, functions is as simple as this I believe?
int vfs_read(vfs_node_t *node, void *buf, size_t length, uint64_t offset) {
if (node) {
if (node->fs_opts->read) {
return node->fs_opts->read(node, buf, length, offset);
}
}
return 0;
}
kinda
instead of returning 0 return a error code
Good call!
like -EISDIR if it's a dir and you try write on it
else just return -EBADF if it don't support the op
I don't currently have errno.h implemented, but I might want to
For the kernel
Ahh that makes sense
I mean it's implementation defined how do you want to propogate errors if you're not going for posix
I planned to have partial compatibility for it, but I don't currently have a libc, etc, since I'm getting the kernel going. I've gotten disk access going, and can now finally get the vfs going
Yeah it looks like a great progress! I'd stop and consider some design questions because until now its mostly the same, pmm and vmm doesn't have too many design choices rather then implementation choises imo.
You could think of an interface of the vfs, what functionally and how to signal errors etc.. quickly implementing things would very quickly restrict your options and if you'd want to change your design you would need to rewrite quite a lot of the implementation
I think that would be a really good idea to be honest.... I think it's time I spent some time thinking about this
Thank you as well!! Later down the road once I've gotten other things in place, etc, I eventully wanted to support multiple disks, but for now just one is fine
Sure, just think whether your interface works for the rest of your design of the kernel (micro services/monolithic etc..), quickly implementing stuff could put you in a tangle without considering everything
Oh absolutely!
For right now I'll spend some time learning, and implementing how I should signal errors in the vfs, etc.
So that if something fails I can return that specific error code. For example -EISDIR
I beleive my vfs_opts struct should also contain function pointers for things like mknod, mkdir, etc?
Doing some research, and thinking about the error handling stuff right now
I'll be taking my time with the vfs development
Now that I have disk access I can start looking into page-swapping
Well... at least from what I'm reading right now the tmpfs filesystem implementation in linux does this
yes for mkdir and create
but you can merge in one create
you don't need mknod
what ?
Ignore that it's something I thought of, won't actually be doing that right now. I'm currently working on some VFS stuff, and one things I'm trying to think about is how I'll mount the newly registered filesystem
before thinking about mounting you firdt need some little things
you need a vfs_lookup and vfs_open
then you need to setup a directory cache
I do have a simple vfs_lookup() right now, but I don't have vfs_open() yet so I might want to handle that first
yes
btw i really recommand you to do a vfs_openat
and make vfs_open wrap around it
vnode *vfs_open(const char *path){
if(path[0] == '/'){
return vfs_openat(root,path);
} else {
return vfs_openat(cwd,path);
}```
so you can do something like that to support relative path
also for the moment you can implement vfs_lookup the same as vfs_read ir vfs_write
but later you will need a more complexe lookup for directory cache
Oh absolutely!
btw you need at least 4 vnode pointer on a vnode
- parent
- child
- brother
- linker node (used for mount point)
btw have you a ref_count on your vnode
you are going to need that
Yes I have a reference count in my nose structure
This is what I had in mind:
int vfs_open(vfs_node_t *dir, const char *name, uint64_t mode) {
if (dir) {
if (dir->fs_opts && dir->fs_opts->open) {
return dir->fs_opts->open(dir, name, mode);
}
}
return -VFS_ENOENT;
}
what ?
there no open op
to implent open you take the path and cut it
like /"dev/vda" become "dev" "vda"
then you take the specified node
and you call lookup on it
you get the vnode of the dev foldet
and you call lookup on it
you get /dev/vda
The idea I had was having the registered filesystem handle this... so like tmpfs for example...
you cant do that
that would mean fs would have to implement itself mount point traversing
Isn't this what vfs_lookup() is normally used for...?
lookup do one depth only
look at my open : https://github.com/tayoky/stanix/blob/main/kernel%2Ffs%2Fvfs.c#L323
Ahh I see
Going to continue to work on the VFS
good
I do have stuff in my klibc like strtok() so that would make splitting the path into tokens a bit better
just do you know if ELF relocation have to be aligned ?
Not that I'm aware of, but I've not did anything with ELF relocations yet
Just program header loading, and section header parsing
i can't understand i single shit about relocation it's so weird
Yes, ELF relocations do need to be aligned, especially in the context of specific relocation types and architectures. While the general structure of an ELF file emphasizes natural size and alignment, some relocation types, like those designed for unaligned memory access, might require specific considerations at the relocation stage.
what but gcc make a elf object where with an reloaction with offset 9
this isen't aligned
is gcc bugged ?
No, I think you have to handle the aligment
what
gcc make a non aligned relocation
i can't really align it
I'm not too sure
LOL me too
i guess that normal
i just have to handle that
Slowly making progress...
Decided to get the the beginnings of tmpfs going, but wait to actually start development on it once I've got the vfs further developed.
Trying to understand how things should be mounted, etc, has been a pain.
good
you first need directory cache
If I may ask... what/how should this cache be created?
so that cache does have its uses, but you dont need it
the idea is you keep a map of directory names/paths to the vnodes they resolve to. So rather than the usual lookup sequence, you can skip straight to having the vnode.
thats handy for mount points because you can pin the root node for the mounted fs in the cache
I dont know if you've read the sunOS vfs paper yet, but I'll recommend it if you havent. There's a lot of good info packed into its few pages.
as for handling mountpoints: each node has space for a 'covered by' vnode, which would be root vnode for the fs thats mounted there. The root vnode also has a 'covering' vnode variable (these can be a union so save space, since you wont have both existing in the same place), which tracks the vnode covered by the fs root.
think of it like the tlb and page tables π
That's what I figured was that it's not really needed in this case. I have been looking for that SunOS paper, and came across something similar: https://www.minix3.org/theses/gerofi-minix-vfs.pdf
Not too sure if this also works out, but it'll be good to learn either way
When you put it that way it does actually make it seem much easier
lol I know that one too, also not a bad read
check the pins in #filesystems , the vnodes paper is linked there
there's also some stuff on namecache, which you might find interesting (but not essential to your implementation rn)
I've found the other pin for the kleiman86vnode documentation so I'll be giving both a read before I proceed further
that sounds right
I think that would be the wise thing to do lol
Time to read up more on the vnode stuff
int (*mount)(const char *target, const char *fs_name);
int (*unmount)(const char *target);
I feel like I need to change these to actually take in parameters.
Well... by that I mean a vfs_root_t struct or just a vfs_node_t.
what ?
you don't implement mount in the vfs itself
you leave it the the fs
i mean yeah of course you can do that
it's just duplicating code
cause all your futures fs will have to implement it
I realized I needed to change it, but I was thinking to have it take in a target to mount on, and provide a node that it setup during the filesystem setup faze...
also do you have a way of enumring pci devices?
Not currently since all I use for the disk access is the virtio mmio
Not the PCI part of it
okay
int vfs_mount(const char *target, const char *fs_name) {
vfs_root_t *curr = vfs_root;
vfs_node_t *mount_node = NULL;
int ret = 0;
if (!target || !fs_name) {
return -VFS_EINVAL;
}
if (!curr) {
return -VFS_EINTERNAL;
}
mount_node = vfs_lookup(vfs_root->root, target);
if (!mount_node) {
return -VFS_ENOENT;
}
while(curr && strcmp(curr->name, fs_name) != 0) {
curr = curr->next;
}
if (!curr || !curr->root || !curr->root->fs_opts) {
printf("VFS: FS type %s not found!\n", fs_name);
return -VFS_EINVAL;
}
if (!(curr->flags & VFS_TYPE_DIR) || !(curr->root->type & VFS_TYPE_DIR)) {
printf("VFS: Target %s not a directory!\n");
return -VFS_ENOTDIR;
}
return 0;
}
It's still a work-in-progress, but so far I'm able to locate the registered fs type. In this case the demo tmpfs I setup for testing...
void vfs_init(void) {
spinlock_init(&s);
vfs_root = kmalloc(sizeof(vfs_root_t));
assert(vfs_root != NULL);
strncpy(vfs_root->name, "root", VFS_MAX_NAME_LEN);
vfs_root->flags |= VFS_TYPE_DIR;
vfs_root->next = NULL;
vfs_node_t *root_node = vfs_node_alloc();
strncpy(root_node->name, "/", VFS_MAX_NAME_LEN);
vfs_root->root = root_node;
printf("VFS: Initialized!\n");
}
I setup an initial root node as well to mount on
mmm...
noramlly a vfs_mount a node to the specified path
I'm having a really hard time trying to design this properly
I was wanting to make it so I provide a path to mount on, then specify the fs type
And then it handles the lookup for it
int (*mount)(const char *target, vfs_node_t **node);
int (*unmount)(const char *target, vfs_node_t **node);
I guess I can always do something like this, and call the <root node>->fs_opts->mount(target, &node);
Still trying to understand how this should work.
I understand that the vfs_mount() should invoke the fs_opts mount, and that will in turn setup the filesystem mount point, etc.
At least this is what I'm understanding
I've got some design changes in mind I'm going to try out today...
ptr = (char *)name;
while(*ptr == '/') {
// Skip leading "/"
ptr++;
}
if (*ptr == '\0') {
// If no mounts like "/dev/" is provided then return the root node
return vfs_root->root;
}
Had to fix my vfs_lookup() to handle if the mountpoint provided was just "/"
Otherwise it would return NULL and cause issues...
https://wiki.deimos.fr/images/1/1e/Solaris_tmpfs.pdf
Came across this too...
Going to try something similar to Linux, and do some kind of vfs overlay mounting.
Slowly getting stuff in place. It's not perfect, but I've been working on the mount/unmount stuff. I plan to start getting the other stuff in place for symlinks, etc as well...
π
@unreal creek Slowly making some progress. I'll be taking my time with the vfs implementation of course...
But maaaan it's been brutal trying to think of a decent design lol
well i'm not sure of what you are doing with the vfs but if it work it work
There was a small change I decided to make, but I'm also using a fake tmpfs to test the vfs for now. So the tmfs right now doesn't do anything special
good
Currently just testing stuff, but so far so good.
@spring sonnet does your VFS follow a unix like design or is it custom?
@spring sonnet you donβt alloc virtual memory in kmalloc?
it's unix like
Alr, becuz i need references for making my own lmaoo
you can't take a look at it for the moment it isen't finished and not pushed to the repo
Alr, Iβm currently taking a peek at yours
Got some more progress going... had to fix the way I was linking nodes
Still gotta figure out why I'm still getting the leading "-//" though
should you realy be able to: mkdir("/abc/def") ?
wait
nvm
it says. Created dev/shm under / wouldnt it be: Created shm under /dev
Yes
good
It does, but my VMM pre-allocates the whole physical region, and makes use of a slab allocator to divide those pages into smaller chunks
hmm
For now anything larget than a single page it falls back to the PMM
so you map all memmap regions?
Yes; I eventually plan to do page swapping as well
its good that you map them to the kernel pagemap, but what about processors which has their own pagemaps, will they use a whole other allocator??
Right now I don't do any SMP, and only make use of a single CPU for now, but this may change in the future. I'd have to also adjust my GICv3 driver to handle this as well for setting up for multiple CPU's
well each process in a single CPU system would still have their own pagemaps, right?? (idk how it is on arm and shit)
Yes ARM64 tackles this with the use of two different translation table registers. One for user space, and one for kernel space
Working on vfs_create now, and then I'll start working on vfs_open() + vfs_close() after...
I've been taking my time with the design stuff, and doing a lot of testing..
Heyyy check that shit out!! Lol
I expected that to break to be honest...
I need to fix my permission checks though...
Welp... I have a bug in my permission checks in that anything in the root directory that gets it's permissions set to all zero it causes everything else to fail...... whoops
normally the root node as permsion just like any other node
btw what op need what permission
- read : r
- write : w
- lookup : e
- create : (w and e on the parent)
- unlink : w
- truncate : w
It's a bug in how I was checking root-level nodes permissions...
I'm currently working on fixing my create(), and open() functions. I'm able to create the new node for the test file I set to be /dev/null, but I need to fix my logic in how I'm handling locating/returning this node..
Got that worked out, but still need to work on permission checks. And by this I mean if I create a directory with 0000 (in octal) for exentually no access I don't currently have a check that prevents access to this
Which is not good
I also think I found the bug I had when trying to check permissions for creating dirs, files, etc in "/", etc.... it's because the rootfs itself didn't have permissions set
A more "pretty printed" directory tree layout...
Oh lovely of course it's now I discover a bug in how I print the permissions too..
you should be able to so that
so only root can access it
Oh absolutely
The VFS is far from finished, and has much work... I've decided to maybe begin implementing EXT2 for mounting over "/". After lots of studying previously I see that SerenityOS does this as well.
The VFS is in place enough to be able to create directories, and files as well as mount things so it's enough to test EXT2 and test directory lookups...
The VFS code, etc, won't be pushed anytime soon while I'm working on this though as I'd like for it to be mostly complete before I do
For now I need to fix mounting over directories before I can start.
is this tmpfs?
Yes; It's not fullly implemented, but has the ability to create directories, and files so far
epic
That part of development I've been making sure to take my time with
I did a test on my kernel to see how low of memory it boots on, and it actually boots on 256MB of RAM, but anything lower causes an exception...
But at least I know I can boot on lower amounts of RAM
So may VFS bugs to fix today.... turns out the filesystem overlay idea I was using before was a terrible idea, and that was causing issues
I've since removed that logic, and things are working a bit better now, but I still need to make sure I can mount sub-mount filesystems as well
Yeah I can't have sub-mounts on things like /dev yet....
So I can only mount things to root "/"
At least I properly fixed how path lookups are handled as well.
I think I got it......
Spent several days of debugging, and reworking everything for this, and I think I finally got it...
Doing some more tests... VFS is finally working properly now π
I don't actually have a devfs right now... I just did a quick test with mounts, but currently working on VFS and tmpfs more...
π
damn
that is some crazy ammount of work in a small time
Yes I've been pretty hard at work on it haha
I've got tons of free time right now too so I spend the day working on Helix
But I've been spending a lot of time with the vfs + tmpfs... I've been taking my time on this part to think about my design decisions
Had the idea to do some kind of mount overlay, and that ended up not being a good idea
Time to finish implementing the VFS.
I don't understand how I can read the MBR header fine, and get the information I need to locate the GPT, but when I parse the GPT everything is all zero.
Irritating as hell.
what do you need from the mbr to be able to locate the gpt? its always at the same place (though ofc you might want to verify that there is a protective mbr)
I read the mbr to verify whether or not the disk has a GPT table or not. I then attempt to read out the GPT header from lba 1, but seems that reading it results in all values being zero. Running hexdump over it showed that the GPT was in fact intact, but reading from disk says otherwise. I've even parsed the partitions manually, and those readout fine so I get to spend today figuring out what's going on
I believe I fixed my issue... turns out I needed to add a small wait in my virtio_blk_read() to wait for the status to change to indicate a completion, and now that seems to work properly. Now reading out sector 1 doesn't show all zeros
Better commit the change
I alsso need to ensure that the length passed to both read and write functions are 512 bytes minimum or it runs into IO errors
ah, nice
Thank you!! It was a simple oversite on my part, but at least now I've worked it out
Perfect!!!
Now I can continue with the rest of todays task...
great
Yeah MBR can be parsed too so this is good. I had to fix a small driver issue, and now I'm good
Working getting started on EXT2
you start EXT2 i heard it's a bit complexe but good luck !
I don't mind that at all... It'll be pretty fun haha
But it's really exciting to finally get started
Looks Like I do need to pad lengths on 512 bytes boundaries when reading from the disk....
Im pretty weak at virtio devices and disc in general, but are you reading how many bytes the disc read from the device ring?
Yeah I'm checking the length field of the virtq_used_elem struct after getting a used buffer from the ring, and this tells me how many bytes the device was able to transfer
Finally am able to parse partition entry information....
The EXT2 superblock information is stored 1024 bytes into the partition. So when I offset the LBA by 1024 to read this get zeros???
I've tried without offsetting too, and still nothing.
Lovely.
I think parts of my superblock structure are incorrectly setup.
I seem to have a correct number of inodes so this is a good sign.
I suspected this was the case anyways, but-
Apparently I forgot a single field, and that was the fuckin' fragments per group.
Apparently the signature is still showing zero, but my shit looks fine as per the wiki.
This is starting to piss me off a bit.
Was able to finally read it properly.
What's kind of rediculous is that I have to read out the first 2K of the partition to properly get the superblock (offset 1K from the buffer). But if I offset this from the lba address I get zero.... wtf
At least it works...
I understand how it was supposed to work so when I tried to offset it by 1K that was entirely incorrect.....
I kind of forgot about that when I was working on my original bootloader
Totally forgot about the lba2offset stuff.
@unreal creek Finally reading out the EXT2 superblock, and getting started with stuff.
good for you
For now I just planned to have a read-only ext2 driver.... just to get started
Yay! Good job!
Thank you good sir!!! π
I was properly able to read out and calulate the block descriptor table.
I previously wasn't taking into account that each table size is 32 bytes per entry
I guess the spec, and wiki talk about this, but I must of missed it before. Either way I've got that going finally
Since it's a freshly formatted partition I only have the one entry, but I finally get some information. I can see that I have directory number of three as well so that would mean ".", "..", and "lost+found".
What's starting to bug me a little is I'm not really sure how to get the inode count to use for the index. Like yeah the root directory is inode 2, but I want to understand how this is found/calulated.
Apparently I'm getting an inode size of zero, and this doesn't exactly make sense since the other superblock data is correct. Including the signature.
Small hack to make the shit work till I figure it out....
uint32_t ext2_get_inode_size(void) {
return sb->inode_structure_size ? sb->inode_structure_size : 128;
}
I'm going to spend some time looking over my stuff and see if I missed something. I don't think so, but you never know.
check if ==0
otherwise i think you are checking if the first bit is 0 or not
at least that is the behaivour on my -O3 compiles
The inode size in the superblock seems to be zero from when I last checked. I'm not too sure why right now, but just did a small workaround till then
Unless this is the expected behavior of the filesystem?
yeah i just said that you check with ==0 because this will return a bool behaviour by just checking the first bit
its the magic of c lmao
Yeah it's zero. I'm going to check the filesystem state and see what's up.
My superblock structure seems to be fine according to the wiki
now that you say that i might need to switch image builder someday
rn im using the queso fuego tool
that just makes a simple efi image
lmao
its minimal and that
but uhh
doesn't make fat partitions
or ext4
or any extra partitions
The partition seems to come out as clean... that's really strange
I just use qemu-img, and sgdisk to get the job done...
Oh absolutely!!
[ ! -e ${DISK_IMG} ] && qemu-img create -f raw ${DISK_IMG} 4G
It's a pretty simple too to make use of. And you can convert images from raw to qcow2, etc
Or vise versa...
Way faster than trying to DD an image too!
i mean i dont use dd because windows doesnt have it so uhh
i cant really mesure it
the tool im using does a couple miliseconds at least
heck i think the printing of it takes longer than the actual building
I think qemu-img should exist for windows...
It's super helpful
yeah it does
Hell yeah
i just wasnt aware of its existance
does it like
make the partitions?
or do you need another tool
Oh yes it's really useful to be honest; It's nice for being able to generate large disk sizes quickly, and can handle convertion from raw to one of it's supported formats
No just the image itself... I use sgdisk (scripted gdisk) to make the partitions
sgdisk \
--new 1:0:+512M \
--typecode 1:"ef00" \
--change-name 1:"EFI" \
--new 2:0:+ \
--typecode 2:"8300" \
--change-name 2:"Rootfs" \
${DISK_IMG} >/dev/null 2>&1
oh ok
i think i will roll out my own partition builder
because i think sgdisk doesnt exist lol
You never know it might exist for Windows
well maybe
i dont want to add more deppendencies for building tho
so i think a standalone one will be my way to go
Fair enough
So I think instead of trying to format the partition by it's offset.... I ended up needing to format it as root....
I can probably fix that later down the road, but for now I'll test and see if this fixes the inode issue
No.... no it does not wtf
I better make sure my struct is correct in this case.
FIXED IT
Inode size: 256....
Turns out I didn't need to pack the struct with the padding, and had a missing field + incorrect padding....
I was taking a glence at your repo, you often times don't use volatile when using a shared pointer with device, this would cause you problems once you change your -O0
I think I know of a few places in my virtio driver this needs to be done in...
I suggest to run with O2 and gdb, see if it works and if not where does it get stuck
It's not a sure way to find those cases of course, even moreso when its in qemu and not real hw, but it would get you going
be the danger and run with O3
So far I can tell the virtio does need some work on this, but I did make a todo for it... Did a test with -O2, and it seems to fail around this point after the device gets initialized
For now it can wait till after I get the ext2 driver going, and fix up the VFS....
I think my kernel would have a stroke on -O3 lmao
I don't think this second block group should have this many directory entries.....
I'm going to ignore it for now since I'm only interested in the root directory inode...
Well it looks like I was iterating the group block descriptor table incorrectly
fok
Okay nooooow I get the corret entries for the block group table including for the two directoriews I made in the filesystem
You'll want to invest in some macros/functions to access mmio properly, and use those instead.
Sounds good to me...
@hallow comet How did you manage to read the root directory inode from your EXT2 partition? Because no matter how I've tried to calculate anything or point the inode struct into the buffer I don't seem to get any good results. I'm doing this on a freshly formatted partition as well to keep things simple
It's slowly been driving me insane
I read out the superblock, then read out the full block descriptor table since it follows just after the superblock, and get the root directory entry from the very first entry of the descriptor table. So far no matter how I've tried to calculate or read the inode data I somehow end up with a type of it being a character device or something comepletely unknown
Uh, lemme check real quick
Take your time
Okay, so I calculate the block group and local inode index (the calculation is in the ext2 spec), then I read the Block Group Descriptor Table, and then I read the inode using the bg_inode_table field of the BGDT
I can send a link to my implementation of it if you want (warning it may be a bit messy lol)
That would be wonderful! I've been at it all day trying to debug and figure out what's going on
Okie dokie! Here ya go! https://github.com/BlueSillyDragon/AquaOS/blob/main/src/boot/efi/src/filesystem.c
the function is at line 100 I believe
Thank you so much!!!
np!
Duuuuude thank you so much!!! I finally freaking got it!!!!
Turns out I was calculating the inode stuff incorrectly.....
UID/GID is zero, type is directory, and all seems to be well finally...
YAY! π
That was really brutal trying to figure out lol
I owe it to you though! Bless your kind soul
Glad my janky code could help someone lol!
I'm so grateful hahaha
great
You were right the EXT2 filesystem is brutal lol
yep that why i start with FAT32
i dosen't have unix permission and file owner
but ourside that it's really good
and understood by basicly everything
Now that I understand how to get the inodes off the disk I can finally clean it up a bit.. I do eventually plan to work on the fat32 side of things later down the road
getting a readonly FAT32 driver is really easy
That's the goal of my EXT2 driver is getting read-only support going for now
good luck
Thank you!
Now I can move forward in learning about how I can use the direct data block pointers in the inode....
π @hallow comet @unreal creek
Ooooo
Apparently I didn't need to make the buffer 8K in size π
I'll wait till tommorrow to learn about the single, doubily, and triply linked stuff... apparnetly triply is only used if you have large files
good
Going to attempt to read a file from the disk.... I gotta try it before I head to bed lol
Man that was a major pain though getting the inode calculations correct...
And now that I can get entries finally I see that I can just kind of repeat the process on the inodes for them too
Never mind I'm going to bed... for some reason reading the test file's inode, and looking at the blocks in the inode show all zero which is not normal so I have no idea what's going on there
At least I got my reward of reading out the root directory contents
Today's task: figure out why that test files inode data shows zero...
Awesome!
Thank you!!!
I think the issue has to do with this line right here:
inode = (ext2_inode_t *)(buf + inode_byte_index);
I'll need to adjust some of this so that it copies the inode data into it's own buffer and returns that...
Hmm no that changed nothing it seems....
Wha'ts irritating is debugfs shows block[0] is 1024, but when I read this out and check it shows 0. And I'm able to read out the root direcetory just fine so what gives....
Have you already successfully read files inodes yet? I'm able to get the inode data for the file I placed in the root filesystem, but all blocks show to be zero, and according to debugfs the block 0 should be 1024...
Which don't really make sense since I'm able to read out the root directory inode, but trying to read the files inode data ends up showing zero for the blocks...
Unless I'm somehow not calculating something right again 
I'll debug for a while and recheck my stuff to see what's going on...
Yeah I have. That's weird, because all blocks should most certainly not be 0
That's strange... because I'm able to get the directory entry for the file in the root directory, and I read the inode for that file to get it's inode data, but apparently the entire inode ends up being zero?
Wtf I just now notice too it's reading again from the block descriptor region of the partition so I'm certain I'm calculating or reading something incorrectly here
oh yeah, you're right
I'll spend some time looking over everything, and see where I went wrong...
I'm glad I noticed that...
I'm wondering if it's how I'm reading the block descriptor table off the disk?
I'll want to check the values...
I'm just going to write a function that handles reading this off the disk when it's needed rather than trying to read the whole thing ahead of time...
My bgdt logic seems to be correct, but I still end up reading out zeros... 
oof π¦
Decided to print out the block descriptor information that I get for debug information, and see something here...
I notice that everything is basically the same except for the index....
huh, that is kind of weird
I'm not too sure if that's normal or not... or if my calculations are off a bit here, but I'll keep digging
It seems that that's normal since the test file is in the root of the directory...
when you get some ext2 to work let me know
Will do... I'm currently trying to resolve my test files inode data being zero, even though debugfs shows the correct info for it ...
So as I suspected when taking a look at debugfs I'm reading the inode correctly... fuck
I don't see how if I'm reading the root's inode just fine.
ext2_inode_t *ext2_read_inode(uint32_t inode_num) {
uint32_t ret = 0;
uint8_t *buf = NULL;
ext2_inode_t *inode = NULL;
uint32_t ext2_part_idx = gpt_partition_get_index("Rootfs");
uint32_t ext2_part_offset = gpt_partition_get_offset(ext2_part_idx);
uint32_t sectors_per_block = ext2_get_sectors_per_block();
ext2_block_group_t *bgdt = ext2_get_block_desc_for_inode(inode_num);
assert(bgdt != NULL);
uint32_t inode_size = ext2_get_inode_size();
uint32_t block_size = ext2_get_block_size();
uint32_t block_group = ext2_get_inode_block_group(inode_num);
uint32_t local_index = ext2_get_inode_index(inode_num);
uint32_t inode_table_start = bgdt->inode_table_start;
uint32_t inode_table_offset_bytes = inode_table_start * block_size;
uint32_t inode_offset_bytes = inode_table_offset_bytes + (local_index * inode_size);
uint32_t inode_lba = ext2_part_offset + ext2_offset_to_lba(inode_offset_bytes);
uint32_t inode_byte_index = inode_offset_bytes % block_size;
buf = kmalloc(block_size);
assert(buf != NULL);
ret = virtio_blk_read(buf, inode_lba, sectors_per_block);
assert(ret == 0);
inode = kmalloc(inode_size);
assert(inode != NULL);
// Copy inode data
memcpy(inode, buf + inode_byte_index, inode_size);
kfree(buf, block_size);
return inode;
}
@hallow comet Is there something I'm not calculating correctly? Because I'm able to read the root directory's inode just fine, but as soon as I go to read out the test fine I have which is inode 12 I end up with all zeros, and debugfs shows that block[0] = 1024
I've tried to re-caluclate this too many times, and have gotten no result
Lemme take a looksie
Take your time!
It seems like you're calculating everything correctly, at least I don't see anything wrong.
That's what I'm a bit confused on because I've re-calculated this a bunch, and have not gotten any results. I just think it's weird that debugfs shows something that I'm not getting, and that I can read the root inode fine, but reading the files inode ends up being zero...
I'll take a look at existing implementations and see what I can probably do better on
Good idea
I think so too; I'm pretty sure I'm doing something wrong with my inode calculation, so...
So it turns out I had a slight misalighment with my calculation that was causing me to read the wrong part of the partition. After fixing that I finally got my reward:
I can finally die happy
Yay! FINALLY!
You should of seen the face I made when I seen the contents of the file finally lol
Now to clean things up a bit, and work on the driver some more. The VFS will go through some changes as well now that I can properly read files off the partition
@unreal creek I know you wanted me to let you know on this as well. I did push the code to the repo as a safe-guard so I don't loose my progress, but it's very much unfinished, and just a test driver for now...
It'll also only be read-only for the mean time till I learn more about the filesystem
I'll be redoing the VFS as well.
My next plan is to start handling indirect blocks 0-11 for now. I planned to start getting a recursive lookup function going now that I understand how the inodes are read, etc, and I also plan to implement a lookup function for handling locating files, etc too...
But right now I plan to also redo the entire VFS from scratch
Or at least tomorrow I'll get a start on it...
But maaan I'm excited as hell to have a simple EXT2 driver going...
Currently playing around with path lookups:
ext2_inode_t *root_inode = ext2_read_inode(EXT2_ROOT_INODE);
assert(root_inode != NULL);
ext2_dirent_t *dev_dir = ext2_lookup(root_inode, "/dev");
printf("Dev dir name: %s\n", dev_dir->name);
printf("Dev dir inode: %lu\n", dev_dir->inode);
printf("Dev dir type: 0x%lx\n", dev_dir->type);
I'm having fun lol
Been playing around with inode lookups to get familiar with things, cleaned up a few things, and check this shit out....
okay i will take a look
Be warned it's extremely simple, and is unfinished... I wanted to keep a backup of the code so I don't loose it
And considering the branch of the repo is a development branch this made sense...
I've did some cleanup since the commit, but won't push them till later... I just learned how to perform subdirectory lookups, and read their data
okay
What do you think so far? It took me a few days to figure out why I wasn't able to read other inodes other than the root directory only to discover later that I had a misalignment...
mmm...
i think that you didn't use device abstractions via vfs
while you have a vfs
why ?
I planned to completely redo the VFS from scratch
For now I'm getting familiar with the EXT2 filesystem, and I'll be getting started with the VFS tomorrow
more you write your EXT2 wihout proper abstractions more you will have to rewrite
The goal right now was to test some things, and learn how to the filesystem works before I start the VFS redesign... That's why the EXT2 driver is incredibly simple...
btw i just made a new PMM and it is o(1) to allocate and o(1) to free and don't waste a single byte of memory !
mmm... okay
I really wanted to spend some time learned how to read different inodes, and how to perform recursive lookups, etc... now that I'm understanding its quite simple
I need to fix my allocators... I had to make my kmalloc() fallback to the pmm if the slab allocator fails
I have future plans to clean all that up too, but for now it's to get the kernel going
my new PMM is also small
about 60 lines
but it's so fast
I've gotta change mine out for a freelist allocator... The current one is a shitty bitmap allocator, but it works for now haha
I guess I could do some combination of the two
the best is the stack allocator
it's the fasted
I'll have to research about it because I'd like to start cleaning up my allocators... I also had some ideas for my kmalloc, and making use of paging, etc, for large allocations. The initial idea I have is since I do a direct mapping of all physical memory I could just take free pages that haven't already been marked as dirty and let kmalloc make use of them...
It's just my initial idea though
the stack use a lot of memory but with some modifications it can waste 0 bytes
I really think I should consider implementing a kernel heap and reserving a part of physical memory for it...
i think
have you not had a kernel heap yet
Right now my kernel just uses a combination of the pmm and slab allocator, but this all uses the lower region of physical memory
Not yet, but that's something I'm looking to do, and clean up my allocator methods..
also why would you need to reserve part of physical memory for it
sounds inflexible
That's something I thought I needed to do for the heap implementation
no you can just add a page frame to the heap when you need to and free one when you can
Then that means I can just rework my PMM for the job then it looks like. Or have an implementation that makes use of this
no
this would be a client of your pmm
it asks your pmm for page frames and returns them to the pmm when it no longer needs them
that doesnt mean it should be part of your pmm
that means its an excellent candidate for abstraction
That's what I had realized... I was thinking of something else for kmalloc() where if I needed larger allocations I just take non-dirty, free pages, and give those to kmalloc. This part was just an idea that I had though
its common to special case allocations above a certain size (this threshold is often somewhere between half a page size and a full page size)
and for those you pop whole page frames from the free list and map them consecutively somewhere in kernel space
and return a pointer to the base of that
these are often called page-aligned allocations
free can tell the difference between a page-aligned allocation and one that came from the smaller block heap by checking whether the page offset of the pointer it was given is equal to 0
this will never be the case for most designs of a smaller block heap because you have some small metadata header before the block which always offsets the pointer some small amount, whereas the base of page-aligned allocations will always have a page offset of 0 because, well, theyre page aligned
but you can do it however works
this is just an example
That's something I was wanting to do. Right now my kmalloc implementation just makes use of a slab allocator for lengths supporting all the way up to a single page, and if a larger size is needed it then calls to the pmm for page frames... It's ugly, and kind of hackish, but for now it works, and gets things going, but obviously I want to clean that up
Going to fix the slab allocator a bit, and then start working on the VFS a little
Yeah I think I'll be spending today working on the allocators instead. I just broke the slab allocator, and seen I'm running into some undefined behavior as well
I'm finally going to get this kernel heap implemented, and get rid of the shitty slab allocator
Maaan what the fuck 
All that because kfree() was missing a fucking parameter...
Forgot the closing parentheses, and the compiler apparently shat itself
Had a bug in my VMM that wasn't mapping the level 1 page table, but still somehow worked fine??
That happens. π Do you use 4 levels or 3?
I use four levels π
Planning to run servers? π I remember a funny incident with my paging function. I mistakenly put the line in which I applied page attributes and presence bit outside of the loop, that mapped pages. Once I sorted other bugs and my trampoline finally jumped into a kernel, I got data abort from accessing framebuffer. But the function accesses stack earlier and it worked! Both stack and framebuffer were mapped by tha same function in the loader, how could that happen that there it worked but didn't in the other place?!! And then I noticed that misplacement. The way it was written, it mapped only the last page. π what coincidentally is just fine for the stack, but not anything else.
Nope just working on the good ol' kernel haha; I'm glad that I'm not the only one this stuff happens to honest.... I just thought it was weird that things functioned just fine till I went to start working on the kenel heap, and mapping the page range(s) for it, and theeeeen discovered the bug π
Starting out with a 16MB kernel heap π
I'll be spending the day on designing, and testing to make sure things are good... It was time to get rid of the old crappy slab allocator, and calling back to PMM...
The slab worked great to get the kernel going, but the time has come for something better π
Doing a little heap testing and so far all is well! I'm really excited for this new change. It was very much needed especially with the fact that a lot of this kernel data was stored in the lower region of physical memory. This was due to the slab allocator and the fact that kmalloc() also would fallback to the PMM if either the allocation failed or was too large for the slab.....
The initial heap implementation is quite simple, but it's better to keep things simple, functional, etc, and improve upon it as needed