#Boron (not vibecoded)
1 messages · Page 2 of 1
this is one for the rest of us targeting the 68ks to keep in mind, since we all test almost all the time in qemu which is 68040
well, not that qemu would emulate this either way
what does XIXT stand for? (like PIPT, VIVT etc)
x-indexed x-tagged
indexing & tagging
ah
theres also VIPT
but what is tagging in this case?
and PIVT
you compare the tag with the key to make sure its a match
so like
aarch64 i wondered initially if my big problems trere could be a result of aliased cache lines as i think both the d and i cache can be virtually indexed
say you have virtual address 0x1234 and its mapped to physical address 0x3242, and its a VIPT cache with 16 cache lines that are each a byte, youd index it with like 0x1234 & 0xF = 4 and then when youve looked up cache line 4 you compare the tag with physical address 0x3242 to make sure it has the data youre looking for
but they don't permit aliases
if it does you got it, otherwise its a miss and you replace cache line 4 with the data you want
in a VIPT cache the tag is just the physical address of the cache line basically
the reason youd do this is so that you can look up the cache and TLB in parallel
by the time the cache lookup is done, the TLB lookup has also completed and the physical address is available for you to compare with the cache line tag
in PIPT caches you have to wait fo rthe TLB lookup to complete before you can look up the cache
VIPT caches have "aliasing" issues if they are larger than a page size
because imagine you have two neighboring virtual pages
which are both mapped to the same page frame
and you access cache line 0 in each
you now have two cache lines which are for the same physical data
which is bad!
you will write to one and then be really confused why the other didnt update
this isnt possible if the VIPT cache is a page size or smaller
but theres another way to get them larger which is to increase the number of "ways" for each set
basically you have the virtual index select a "set" of cache lines
and any line from that set can match with the physical tag
so if you have a 2-way VIPT cache and 4k page size you can get a 8k VIPT cache without aliasing issues
at the expense of extra circuitry
thats why modern processor L1 caches are all like 32-way
because they are VIPT and want to avoid aliasing
so they only have like a page worth of cache sets and each set has 32 lines so the cache can be like 32x a page size or whatever
that was a tangent but hopefully informative.
PIPT is nice because you can arbitrarily specify cache parameters and never worry about aliasing or anything, at the expense of serializing it with the TLB lookup; VIVT is nice because you dont have to look up the TLB at all on a cache hit! but at the expense of nearly unresolvable problems with aliasing that are so evil its considered the province of shitty little microcontrollers with special purpose operating systems
dont ask what PIVT is for apparently it exists but i cant imagine why
Wikipedia says that MIPS r6000 is the only known implementation, and gives the extremely esoteric reason: Even a TLB would be too large to implement in Emitter-Coupled Logic, so they implement a TLB slice to just translate enough bits for a physical index. Given that limitation, PIPT and VIPT were not options, and they decided to go PIVT instead of VIVT.
dont know what that means
I dont know what I should work on
There's a lot to work on
Maybe I should start on some kind of tmpfs system?
damn. I really don't know what to work on
maybe tomorrow I'll figure it out
im not sure if this is the right time to start on this
but i think it might be time to write a page cache data structure (cache control block) for FCBs
im trying to implement the cache control block and im giving it a very hard think
but im not sure how it will integrate with the IO system
other than, like, each FCB having a cache block if caching is enabled, and IoRead/IoWriteFile using it preferentially
i think i will take a break
hopefully in the meantime i can figure out what i should do and how i should do it
0xffff800000000000 --- HHDM Area
0xffffa00000000000 --- Page Frame Database
0xffffa08000000000 --- Pool Space
0xffffa10000000000 --- Recursive Paging Space
0xfffff00000000000 --- Kernel Module Loader Base Address
0xffffffff80000000 --- -2 GiB. Kernel loaded around here
these are the currently used memory regions
for my reference
todo: figure out why in the fuck I am unlocking the handle table before I modify one last thing about it https://github.com/iProgramMC/Boron/blob/master/boron/source/ex/handtab.c#L275
https://github.com/iProgramMC/Boron/blob/master/boron/source/ex/handtab.c#L302 clarify this comment too
https://github.com/iProgramMC/Boron/blob/master/drivers/halx86/source/pci.c#L12 fix this date because Boron wasn't around on July 4th, 2023
you were time travelling
nanoshell64 was around at the time but it didn't have file headers like this
i was thinking of partition objects and i thought that maybe they can be generalized
partition objects as in, partition of a disk volume
they wouldn't have a cache of their own, instead passing all IO (cached or not) through to the disk, with the specified offset
that’s exactly how everyone (or at least me) does it ;p
my previous idea was close to this one actually i just decided they'd piggyback off of the host disk's cache now
ok i implemented at least a little bit of the cache control block
that being the entry retrieval function
tomorrow i'd like to add a function called BSTATUS ObDuplicateHandle(PHANDLE OutHandle, HANDLE Handle);
which duplicates a handle
and continue work on the MM
bruh why the fuck is the IPL randomly >=IPL_DPC at page fault time???
I thought it might have something to do with the race condition I recently found with the KeGetCurrentThread func
damn
i also found a deadlock
yeah deadlock
one of them was interrupted while trying to do a tlb shootdown
this is a classic deadlock
thread a locks a then b
thread b locks b then a
sigh
why the fuck is PRCB 1's Ipl being set to IPL_DPC
i bet theres a bug in my raiseipl
ok there is
hows it possible???!
the TOCTTOU that i discovered yesterday is materializing in more places than one now!
are you fucking kidding me
oh i was freeing the stack with dispatcher lock held
L
so basically i need to rearchitect a lot of things
frankly before continuing with the MM i should flesh out PS
and its management of threads
have a thread be the reaper of threads & shit
well those are fixed now..
tomorrow methinks I will start working on Ps
and yank out all the Mm references from Ke
In my ps/2 driver, in my init function, I have a hack
specifically this one
it might be superfluous now as that test rig doesnt seem to do that
this is what it looks like in nanoshell
and this is what it looked like in nanoshell's predecessor, confusingly also named nanoshell
interesting - btw I like the style of boron's codebase.
Same
thanks
Ok I've done a bunch of cleanup work
Now instead of IA32_KERNEL_GS_BASE which I was actually using erroneously, I'm using IA32_GS_BASE
I removed the segment reloading from the interrupt exit/enter and context switch in/out code
and I've inlined the current thread and current IPL operations into single GS relative accesses
also inlined 3 intrinsics which for some reason were regular functions and have thrown me off before: KeWaitForNextInterrupt, KeSpinningHint and KeInvalidatePage
I should consider working on Ps now
please excuse my apparent disappearance
on another note,
bug!
how is 0x1 getting in the handle table?
its supposed to be overwritten
oh I was writing the wrong index
KiTestTrap
#1
DbgLookUpRoutineNameByAddressExact
ObpRemoveObjectFromDirectoryLocked
ObpNormalizeParentDirectoryAndName
#2
MmGetSmallestSlabSizeThatFitsSize
#3
ExiDisposeCopiedObjectAttributes
MiGetUserDataFromPoolSpaceHandle (used to be the longest last time I checked)
pretty cool
I forgot to remove the word "test" from these functions
they're called "test" because they WERE tests when I refactored my interrupt handling system
some more changes to boron
i've removed the old thread detachment system (you could detach a thread and it'd be automatically cleaned up by the system) in favor of the process manager
you can call PsCreateSystemThread and it features automatic cleanup of the thread if you simply close the handle
aint that cool?
this is once again lifted from NT
with that, very little of the kernel core actually "calls up" into the memory manager anymore
just the init stuff basically
successfully ported boron's fireworks test to m*ntia2
@glass heart can I ask what is your relation with Mintia? Not only because I recall you mentioning it a few times, like above, but also because to me it seems that you are trying to also use NT concepts, and not only Unix
can you define "relation with mintia?"
yes I do regularly talk in hyenasky's server
and I have read mintia a little bit
does this answer your question?
yes
Mintia has a server right? Or rather it is a xr station server
it does
the latter yeah
yea sure
thx!
Is it fast
yeah
Nice
decently fast I think
this is 7 or 8 processors running at like 25 mhz doing this stuff
more impressive than my own
If only it was available on a real architecture
fpga?
fixed a bug today
a really nasty bug
it turns out that the expirytick key might collide when setting a timer
so the later timer is just dropped
the firework test once again revealed this
i didnt think much of it but this bug is insidious as fuck
my current fix is to just add 1 until the function can add it, but i'm thinking of a more proper fix
looks cool
apologies for my lack of progress
xd
i've been busy at uni + working on something different
https://github.com/iProgramMC/Boron/blob/master/drivers/i8042prt/source/kbd.c#L196 where the fuck am i unmapping the buffer
the biggest roadblock that I have, i feel, is the memory manager. specifically i'd like to have some relatively advanced features such as file mapping, symmetric/asymmetric CoW and paging
I mean that's not too hard
My vmm supports those
And is only ~3k loc
Also never forget dirty and standby lists
You don't have swap thp
*tho
Which is one of the features he wanted
maybe but I want to get them right tbh
part of the reason I'm still not working on it is that I've been making an NES game but there's that reason too
eh maybe I don't need swapping initially but I should design with it in mind
mine is 2kloc and I only support symmetric cow
daily reminder that loc isn't a good measure of anything
empty lines are the way to measure code quality 
just found out about this, good luck on it :3
‼️
thank you 😄
i mentioned this and ill mention it again. when i decide i dont want to work on my NES game anymore i will start working on this again
but yeah
uni, and my nes game, have been draining most of my time
boron is a kurzgesagt reference confirmed?
lmfao
is this real
does anyone have any references for NT like vmms that I can bunch up so I can read them in the future
I still haven't decided to come back to this project, but I'll give continuing it a shot someday this year
I was recently recommended the book "What Makes It Page"
so I'm passing this recommendation along to you
so i got a copy of what makes it page
at least, so it seems
i hope that that book will help out
The man didn't have an editor
he just REd the Windows 7 memory manager and wrote a book about it in ms word with the default formatting
ah so this is reverse engineering work
well hes probably smarter, and definitely more experienced, than I am
I actually did some work on boron again today! (only a small amount)
Right now I'm working on the memory manager
Planning how the main system calls (system services) are going to be implemented
nice to see boron continuing
mm progress is actually kind of going now
i got anonymous commit memory working (so basically demand paging)
next is decommitting and then integrating them into some simple APIs
and then eventually memory mapped file I/O
i'll have a basic vm system working in no time okay no it's going to take a while still
but its going so far
people might lynch me for this but i kinda wanted to see how Windows would handle the case where you reserve memory with VirtualAlloc MEM_RESERVE | MEM_COMMIT and then decommit the middle of that range
here's the code i used to test things
checking the PTE for this process at those addresses reveals that there is actually no PDE allocated for the middle of that range
however, once I run VirtualFree, that's when the PTE appears
so they literally allocate memory when you decommit a region
how nonsensical is that?
does this make more sense than allocating all of the page mapping levels (PDs on x86 32) when passing MEM_RESERVE | MEM_COMMIT
(note for the naysayers: VirtualAlloc is basically just a Win32ified NtAllocateVirtualMemory, likewise with VirtualFree)
@mossy thicket i don't know if you handle memory reservation in a similar enough fashion in mintia1/2 but i would like your input for this
tbh looking at your plans you might thing that this whole entire thing sucks because your new plan is to have fully disposable page tables
also i bet they improved on this substantially until windows 11
If you're thinking "commit" here means to allocate pages immediately then you're wrong
And this isn't enough info to tell me what's really going on here tbh
Of course not
So basically I reserve an area of memory with VirtualAlloc which creates a VAD 4000 pages long
Then I decommit half of it in the middle
Notice that I don't actually access any of it so nothing is allocated
Before I do the VirtualFree though I run the command !pte on the start of the allocated region and the start of the region to deallocate
The latter PTE doesn't even have a PDE associated with it.
However, after running VirtualFree, suddenly that latter address' PTE exists (because its PDE was created) and it's marked decommitted
What virtualalloc with MEM_RESERVE | MEM_COMMIT does is it creates the VAD but doesn't actually mark any of the PTEs as "committed"; they're left at 0 and the flag within the VAD called "MemCommit" is set to 1
So the TL;DR of it all is that VirtualFree, when called inside a VAD that was completely reserved at creation (which doesn't initialize any PTEs at all), actually allocates PTs to place the "decommitted" flag in the PTEs corresponding to that region of memory that got freed
Here's the relevant VAD
The start VA of the VAD has a PDE associated with it (because other things are mapped within the range vovered by the PDE)
the VAD doesn't change at all after VirtualFree however
but it does allocate the PDEs
beginning of the explanation^^
well in any case if Windows XP behaves like that it makes me less ashamed to do something similar
work on boron is slowly progressing
some simple tests work
i should do more complicated tests
maybe i'll keep working on it for a while instead of chiming in now and giving up on it in 5 days. but so far i think i have anonymous private memory working (ranges of memory can be reserved, and things can be committed into those ranges, and it works with demand paging too)
dont you just love the win32 API sometimes
- MapViewOfFile
- MapViewOfFile2
- MapViewOfFile3
- MapViewOfFileNuma
- MapViewOfFileNuma2
- MapViewOfFileEx
- MapViewOfFileExNuma
- MapViewOfFileFromApp
- MapViewOfFile3FromApp
- UnmapViewOfFile
- UnmapViewOfFile2
- UnmapViewOfFileEx
- VirtualAlloc
- VirtualAlloc2
- VirtualAllocEx
- VirtualAllocExNuma
oof, file, file_2, file_2_new, etc
@undone sky remember that convo about Ex and Ex2?
the anonymous memory APIs are almost complete
soon i should begin working on file backed memory mapping support
for boron i kinda wanna expose some files already but i dont wanna build a file system driver so im going to add support for the boot files (ones you add to limine's cmd line) to be exposed
now the vm APIs I plan on exposing to userspace dont really map well to mmap
which sucks 😦
i might add some mmap support functions though because with only those APIs it seems like a pain to implement
if you look at the implementation for most of them they all just forward with extra args to a single one usually
aside from the windows store ones, those are strange
perhaps read only tarfs and an in memory filesystem
sure
an in memory file system yes
tarfs not yet
parsing tar files even with error handling is like 100 lines
its worth it to make getting test data into your os easier imo
i know lol
i have such a thing in nanoshell
it's funny
nanoshell vs boron will be a lot like windows 9x vs windows nt
except my OSes will be both somewhat worse than their respective windows
from a glance, and by glance I mean a small test, the APIs OSAllocateVirtualMemory and OSFreeVirtualMemory seem to work
the page fault performance is... not great, it seems. but i'll work on that at some point
(it takes about half a second to fault in 40 MB of pages or 9766 pages)
(which is kinda trash)
tomorrow or saturday i will start working on file backed memory aka memory mapped files
also im thinking about the best time to deallocate empty PTEs and I think it's when a VAD is being freed
note: between the time when the VAD is removed from the VAD list and when it's added to the free list
there are three locks that operate in total, im not sure if its good design
theres the address space lock which guards, you guessed it, the address space (page tables). then theres the VAD list which guards the VADs. and then theres the free list lock which guards the free lists
so freeing a VAD would behave something like this. first erase the VAD from the VAD list (holding only the VAD list lock). then start erasing the PTEs covered by this VAD, guarded using the address space lock. also clear unused PTs. then issue a TLB shootdown request. and finally add the free range into the free list.
each segment of memory is under custody of either a VAD or a free list segment so if it's part of neither, nobody can touch it (currently)
except for threads that fault on that memory. they'll end up in the page fault handler and lock the address space lock before doing anything
when they finally reach the guarded region they'll see only empty/nonexistent PTEs as far as the eye can see
and subsequently raise an access violation status
also im thinking to have a mutex or something for each VAD so I don't have to hold the VAD list mutex while modifying the VAD
although this could cause issues if the VAD's place in the tree needs to be modified by a rebalance
maybe not
okay the unused PTs seem to be getting cleared as intended
the amount of physical pages available before and after my test is the same
okay i said it too soon
what is this 😭
i know its a failure in the access of a goddamn recursive paging area
okay its fixed
^ yay
now im thinking
where should i put the page cache
should i associate it with the fcb
i think so
should it be like an ext2 "direct and indirect" type structure? as in, the first N pages are directly indexed and then no longer?
if the pages arent mapped in but someone calls ReadFile how should i handle caching
should i map small views of the file to make caching fast or
theres a lot of design actually
btw any plans for an aml interpreter in boron
yes
in the far future i would like to import uacpi
cool
I might already be able to but I'd rather wait a bit
i was curious if u would roll your own since u have tons of acpi code for table parsing
nah
that code is mainly there to detect the HPET, if I remember correctly
it may be replaced with uACPI code if it simplifies the code
yeah it can be replaced with a one liner if u use uacpi
uacpi also has a header with all those tables
also your pm timer code can be replaced with uacpi_map_gas + uacpi_gas_read_mapped etc
i had an idea that i'd be placing it in a different uacpi.sys module tbh, so integration with the hal would be unlikely unless i design around it
maybe i can make uacpi.sys load right after hal.sys instead of anytime later
you can depend on acpi.sys for pm timer and stuff
Currently drivers can't link with each other
i mean nt drivers dont link to each other usually right
they do regularly
they have callbacks or whatever
many of the NT .sys files are just dynamic libraries in kernel space
linked to by other modules
i will probably just embed uacpi in my kernel binary
when i get there
it will go in the "integral system driver" for amd64 pc platform
acpi is usually like a very core driver so it makes sense
and u need it at early boot to do numa prep
which is basically my name for all the platform-specific stuff for devices that are invariant to a platform
i stopped having the HAL be a separate binary so it didnt make sense for those to be either (since kernel binaries are already platform-dependent) so it all just goes in the kernel now
how far away from the amd64 port are we
damn
my plan for the hal was that I'd use it for different raspberry pi models or something
mintia2 is still pretty early
like i could port to the pi 3 in 2026 and then to the pi 4 in 2027
idk
otherwise i would probably have built it into the kernel
well that's fun
i guess i gotta implement that in my OS
or maybe not
i like this structure and may probably adopt it
mintia2 is doing this already
it optimizes small files while also allowing for larger files
oh really
well i have a single structure very speculatively sketched out which does that lol
cause i didnt know will reached that part of his design
i think that might be where i got it from actually
for your anonymous objects of course, you were planning a traditional AVL tree for the file pages
tbh i took a long break since september 2024 and everything is exactly as i left it
so theres little bits of a premature design that i have to look at and decide what to keep
i think that part is fine
but anyway i had some questions about file caching earlier
here
this is what i did
to be exact i put it in a "cache info block" which only gets allocated when you actually read/write a file
which saves a ton of space in FCBs that were only created to like query a file
but its logically just part of the FCB
i think it does have a lifetime independent of the FCB in one weird instance involving the lazy writer
but i forget details
i have discrete vm objects but they have an unpleasant relationship with vnodes where their lifetime is basically tied to their vnode and they make refcount adjustments to ensure this (++refcmt on furst dirt page, -- on last dirty page written)
i struggled to remember what file objects were used for but i remember now
iirc NT has the concept of a "section" which you have to go through to map stuff
i just flush dirty pages before deleting
yeah idk why it does that i just map the file object directly
like you cant map views of files, you have to create a section of that file first
is that somewhat analogous to your "vm objects"?
at that point youre guaranteed that no new ones will be made
so if you just flush whats there then you can purge and delete safely
i think some comparison can be made, i don't understand what's the roles of NT section and segment and control-area objects though
if youre worried about IO failures and you want dirty data to stay in memory if you fail to write it out at deletion time, you could enqueue this to a worker thread and each time the flush fails, it just logs this and delays trying again for like 5 seconds, and it only purges and deletes once it succeeds
they are some kind of innovation particular to NT or maybe to VMS or some other predecessor, but not really present in mach tradition which influenced my model
honestly it seems mostly like a weird mica-ism that was meant to support mica virtual memory features that NT didnt even end up having or ended up doing differently
they have some use in executable mapping but that's all i know
so i consider all that stuff to be probably just redundant and strange
bc i never encountered even a hint of a need for it despite doing most stuff in an NTy way
one of the mica workbook drafts the chm digitized for me goes into extreme detail in the virtual memory workings
and i think it elucidated the original intent of some of these things
but i dont remember
maybe here
also about file caching when you dont intend to map parts of a file
what do i do
do i just keep the pages in standby in the page cache and copy from the page cache directly
(this would allow them to get purged if necessary but it seems inefficient)
pages stay faulted into the system working set until trimmed
so repeated cached file IO just becomes a straight memcpy
how does it operate though, how big are the mapped views of files? when are they mapped? what if you fill the space theyre designed to take?
u can read the code
if i wanted to read the code i would probably have already read the code
i guess youll never know then
what the fuck
so i found a heisenbug
it doesnt trigger when the debug is attached but it consistently triggers without it?!
and this dumb fucking stack trace
this all started because i was running out of memory for some reason even though this test shouldnt cause any memory to be allocated without freeing it
okay so i managed to coerce it to proceed with gdb (it was getting stuck in two spin loops)
oh thats in the kernel
maybe it's a function within an init page
yeah
why the fuck is this in init
okay finally
see i love this stack trace format ❤️
but fuck
maybe i have a memory leak in the MDL stuff
now it looks like ive hit yet another stupid bug
whys it failing to acquire the tlbs lock
the other threads arent in a fucking tlb shootdown
be calm. all will be revealed.
preach
im going to solve it eventually
all i wanted to debug was a memory leak though why did it have to throw this conundrum...
okay tomorrow time
now that my journey of porting a program across 32 years of 32-bit Windows is complete, I have no excuse
I will get memory mapped files working
I already got started in some unpushed commits
i'm going to take a look at this later
this only happens when the system is given critically low memory (like 4.2 megabytes)
it's not. I mentioned another project I was working on that involved being ported to old Windows versions
Not this one
Although you could say its code style is inspired from Windows..
relatively famous (among a small group of weird nerds) string that seems to have been a debug print during initial bringup of the NT kernel back in 1989
nah theyre like 19 or something i think
im unsure who proliferated the knowledge of it but ik this about it
also im not the author by the way im just answering questions ik the answer to, since he's offline
its just cool because it may be one of the earliest things the windows kernel ever spaketh
a friend asked me to print this out and only told me "I found this in an early beta of Windows NT"
at the time I wasn't exactly aware of the fact it's part of leaked code
but i guess that's where he got it from
I'm not
love the nt style stack trace stuff :3
progress update: I can now read from an NVMe drive using cached memory!
thanks!
here is a dump of the first 1kb of the nvme file
and now here is the read operation
note: the offset is 20
and only one actual NVMe operation! (even though the exact same test is performed 3 times! the rest of the times the data is mapped in from the page cache)
now writes don't work right now and it'll be a lot of effort to get them working as well
with the modified page writer and things like that
one thing i will provide for mapped files/devices is the ability to have them directly backed by physical memory
(this is pretty much only useful for framebuffer type devices or an in memory file system)
the MM will recognize that this is possible and just bypass the whole cache machinery
this commit implements everything
technically this and CoW is all I need to start implementing userspace
(and of course some code to setup an in memory fs, probably from a tar)
this sounds like DAX (https://www.kernel.org/doc/html/latest/filesystems/dax.html)
similar idea yeah
though using it for a framebuffer device or similar differs quite a bit from how Linux does it (Linux has VM_PFNMAP for that type of mapping)
Now what I don't understand is why this would be needed for tmpfs-like filesystems, as those can simply have their backing storage be the page cache itself, no?
that's kinda an inversion of what I was thinking
instead of having the tmpfs files be backed by memory and bypassing the cache machinery, let's use the cache machinery to keep track of the pages and just keep those pages permanently mapped
it's just a matter of which kind of machinery i use, either the direct map one or the page cache one
or you make them the same 
e.g. Linux can have struct pages for direct access memory
non RAM pages aren't opted in into the page frame database in boron currently
this might change but that's how it is right now
(lmk if you don't want to get pinged in the future)
@uncut lance @primal gorge @fast prism @mossy thicket
(ping spam) Possible spam detected for user: iProgramInCpp. Please contact a moderator to be unmuted.
I'm okay with being pinged
cool
i'm also happy to be
thank you!
it turns out i am dealing with a page frame reference leak
leading to pages not being purged from the standby list when they should under (simulated) memory pressure
one of the reasons is that i was using __atomic_clear which for some weird ass reason only operates on bools and chars but i was trying to use it on a uint64_t
the other is that i was using a stale pointer to a pte and writing to it, when mapping newly loaded pages, inadvertently writing to something completely unrelated
it works great now
these are only the first steps but boy is it satisfying for everything to tie together
I check all the threads without needing 2 be pinged
kk, so I will not ping you when anything major happens
a big problem: I want borondll to map things into the processes it creates. However, my system calls aren't designed with an additional Process parameter and they use recursive PTEs heavily
So I was thinking that the system calls would temporarily switch into a process' address space and detach afterwards
I already have functions to pull this off however I'm not sure how code decayed they are
Some more things I might need for user space in Boron include a file system that includes the boron layer DLL, an exposure of the screen and debug consoles as a file, and a way to create a shared library that is actually fixed at an address
(Although thinking about it, the lattermost item might not be necessary)
(I'd be avoiding performing relocations in the kernel though)
What I'm thinking for the OS startup: first, the kernel starts up, then a new process is created and borondll (actually will be called libboron.so) is mapped into it. Then, that new process is given a thread which jumps to user mode at the boron DLL's entry point
This ephemeral process' only job is to start up init.exe or whatever I'll call it
BoronDLL will include the "advanced" ELF loader, the kernel will only include a stub which is enough to map borondll
thats what i was doing but i realized for the new kernel ill need more robust loading & linking capabilities inside the kernel itself, bc of loadable drivers
Finally, init.exe initializes the rest of the system, launches a console login prompt, etc.
boron will end up with two ELF loaders which share the same struct definitions and some utils
the first will deal with driver loading and doesn't deal with any user adjacent APIs
and the second will deal with mapping borondll into every new process
something that im looking to try, but i might realize later on that this is a futile goal, is that user processes are completely in control of their own address space
meaning they'll be able to unmap everything, including the PEB/TEBs and borondll
this took like 3 minutes to post because the OSdev forums are probably getting abused by ChatGPT/other AI bots
chase should really start fighting off these stupid bots
this deep ass stack trace
20 items deep it seems
mate that page is present what the fuck
oh wait what the hell
its not marked writable
so THATS what the NVMe assertion MDL_IS_WRITE was for
and yep that seems to be the test.sys driver mapped into the user half of memory and working like it should! 😄
im thinking of how the POSIX/UNIX style file system will be exposed
i think this could be done in osdll/borondll
it would append \PsxRoot to the path name if absolute
also about / or \
I could do a last min change and switch to /
or I could make borondll translate the path replacing all / with \
PsxRoot or PosixRoot or UnixRoot or Root or whatever the hell
will be a symbolic link to either the init-root (exposes all the kernel modules) or to the boot volume selected by command line
heck maybe mlibc can handle that
maybe i should use tar or something
instead of loading every module separately
the problem with that is that data isn't aligned to 4 kbyte boundaries
but to 512 bytes afair
path seperators shouldnt be text imo
wdym
a path is a list of names right, not a single string
a path is as much [ 'home', 'elliot', 'documents' ] as it is /home/elliot/documents conceptually
afaik linux just passes paths directly as slash separated names
linux does it wrong 
i'm not sure what windows does but i think it does something similar
windows also does it wrong ngl
really the path seperator shouldnt even be in memory
you can support one when like formatting for an error message or parsing in userland, but a path should be agnostic to whatever seperator is used
i'd do something like that if i didn't already invest loads of time into creating path lookup machinery and i hadn't started the project so long ago
i bet alot of that path lookup machinery boils down to some form of for name in path: folder = parent.lookup(name)
https://github.com/iProgramMC/Boron/blob/master/boron/source/ob/dir.c#L203 it looks something like this
its one less thing to go wrong if you expect an actual data structure of a list of names rather than an unstructured string
hmm that's true
one thing i do plan on doing is to make userspace give strings and their length so the kernel doesn't have to go scrubbing for the zero terminator
but currently the kernel does use zero terminated strings quite a bit
i make the userspace provide a begin and end pointer for a null terminated list of names
so the kernel gets Users\0Guest\0Documents and a pointer to the front and back
the greeting text at startup, the object manager directories' names etc
the \0 are nuls rather than the text \0
i could do something similar, but again, i have never seen this before and don't feel like implementing it this way here
fair enough
it sounds like a very good idea though
i do it mostly for the principle of it rather than it being significantly easier
i really recommend taking begin and end pointers rather than base + size, it means you dont need to do overflow checking when sanitizing userspace data
in this case you just need to check if begin < end and if end < userspacelimit
yeah, but you'd need to do the second check anyway
although it might partially be because i use c++ in the kernel which all works on begin end pointers 
this change i could consider doing though
for one simple reason
because it makes parameter validation faster
and also I didn't do almost anything regarding syscall specification
I mean, even if you take begin and end pointers, you still need to check begin <= end
Which is exactly the same check you do for overflow
So it really just saves a single add
overflow checking in C is kinda painful which doesnt help
not really?
if they're unsigned you just add them together and check if the result is greater than or equal to either of the inputs
if so, there's no overflow
oh, yeah i suppose
i dont think so?
like both quantities (begin and size) are unsigned
just check if begin + size > end
so i am running into a bug
where for some reason, sometimes, page references are being leaked
idk why
the last time this happened was because of a stale PTE pointer
you may be wondering "okay but how can a pointer to a PTE be stale?"
it's because I was using the old interface which fetches the physical page with the HHDM offset, where the PTE resides
but the pointer can go stale if you unlock the address space lock and then relock it
modifying the code that modifies the PTEs to use the recursive paging thing does nothing
well it does something
instead of leaking everything it keeps faulting over and over again
ffffa150a8542000: 00000000001b6000 which matches cr3
also it has worked 2x so why isnt it working the third time?!
ok so i fixed that bug
why did it happen
it happened because i wasnt invalidating the TLB regions within the recursive page map which caused the pf handler to use stale TLB entries and write to the wrong pages
now i am invalidating them. in the wrong place probably (because i think i am supposed to do it in MiFreeUnusedMappingLevelsInCurrentMap but i really do it every time someone wants the PTE pointer in MmGetPteLocation) but still
@uncut lance how does keyronex handle freeing upper page map levels? (like, PTs, PDs, PDPTs etc)
or does it not?
in what way handling?
it does get rid of them
like yeah does it get rid of them
oh, it does, there is a non-zero PTE count in the page struct
and when that reaches 0 the table is thrown out
https://github.com/iProgramMC/Boron/blob/master/boron/source/mm/amd64/ptfree.c i tackle that here but there's a problem
or maybe was
which is that i'm not invalidating the recursive page maps corresponding to the upper page table levels
so i added a hack to invalidate them whenever someone calls MmGetPteLocation
that's smart
currently i just scan all of the entries
i don't think this is a totally insane approach because i don't want to have to do accounting when writing *PtePtr = MM_DPTE_DECOMMITTED; or *PtePtr = 0;
there are so many things i would like to work on now
and i will get to work on them someday
i think tomorrow or so i will continue the road to userspace
i won't implement any write support anywhere just yet but that will be implemented soon
actually i could do this first
and then userspace
my plan is to indeed just do my userspace with the ELF format
the init process will literally be run from the system DLL so it wont even need to dynamically link against anything
the kernel's elf loader can be as simple as possible
now, i will need to introduce something else, which is a way to create a process, and then pass it into OSAllocateVirtualMemory/OSFreeVirtualMemory/etc
since these functions are written to use the Fast PTE tech I will need to do something a bit hacky, which is to literally switch process
these functions will be modified to call a new function, something like PsGetAttachedProcess()
which will return either the current process, if you aren't modifying another's address space, or the modified process' address space
progress "seems" glacial right now but i am working on it!!
i made OSAllocateVirtualMemory/OSFreeVirtualMemory take in a process handle
you can also pass special hardcoded magic numbers (using a define) that lead to referencing the current process (-1) and the current thread (-2)
What's the diff for -1 and -2 in this case?
-1 means current process
-2 means current thread
you cannot use -2 to refer to the current process and you cannot refer to -1 to refer to the current thread
this is mostly for system calls where a handle can refer to either
i cant think of any rn though
i mean for OSAllocateVirtualMemory
you can't use -2
you have to use -1
actually theyre given proper names like CURRENT_PROCESS_HANDLE and CURRENT_THREAD_HANDLE so
Hmm id expect them to work the same in this case
you cant allocate virtual memory into a thread so
hmm yes
a backup of the original PMM in boron, from 19 August 2023
before I decided to not just rewrite NanoShell64 but just do it as a new thing entirely
ffffffff800102e2 T MiGetUserDataFromPoolSpaceHandle
ffffffff8000cda4 t MmpHandleFaultCommittedMappedPage
ffffffff800105ca T MmGetSmallestSlabSizeThatFitsSize
ffffffff80008e21 t KepGetNextProcessorToStealWorkFrom
ffffffff800096f3 T DbgLookUpRoutineNameByAddressExact
ffffffff80012574 T ObpRemoveObjectFromDirectoryLocked
ffffffff80012cba T ObpNormalizeParentDirectoryAndName
ffffffff8000912f t KepGetProcessToSwitchAddressSpaceTo
ffffffff8000bd57 T MiFreeUnusedMappingLevelsInCurrentMap
ffffffff8000be99 t MmpFreeUnusedMappingLevelsInCurrentMapPML```
as a fun fact here are the top 10 longest symbol names in boron
c0172ac4 r CplColorsWndProc.s_ColorComboItems
c012a2d0 T KeUnsuspendTasksWaitingForPipeWrite
c0144650 T UpdateControlsBasedOnAnchoringModes
c0149a20 T WidgetColorPicker_SubDrawHueValRect
c0149c20 T WidgetColorPicker_DrawSatPickerRect
c014a370 T WidgetColorPicker_DrawPropertyField
c013aa50 T TaskbarRecalculateGraphRectsIfNeeded
c01331c0 T CabinetDetermineResourceLaunchFailure
c0158460 T WindowBlitTakingIntoAccountOcclusions
for posterity here is the same top for nanoshell
Don't forget to port Mario 64 to it again as well! 😛
i might end up making the nanoshell build work on boron
Though at ring 3 with actual memory protection, right?
Private Mm functions should kind off be prefixed with Mi not Mmp. You use both.
As far as I'm aware, NT uses both too
Yep
Though I may be wrong
In Boron there is Mi and Mmp. Mi is for memory internals that are shared and Mmp is for memory internals that aren't shared, and are static to one compile unit
MiFreeUnusedMappingLevelsInCurrentMap is usable within the context of the MM but MmpFreeUnusedMappingLevelsInCurrentMapPML is only used by the former
Compare to Ki and Kep
fyi this isnt running in user mode YET
still have some hellish issues regarding improper mapping of segments
but im out so ill fix them later
status update
its calling my syscall handler
but then triple fault
oh
lol
it was forcing a sysret to user mode with cs=0 ss=8
duh
maybe i should switch to user mode first
reeeeeeeeeee
this infinite page fault loop is killing me
WHY are you page faulting when trying to fetch the instruction within user mode
you at least seem to be smoothly returning to kernel mode :3
am debugging YET ANOTHER issue
WHY in the mother of ass is CS being set to 0x2B
after what seems like an innocent page fault
we in user mode 🎉
Nice
Are you trying to make this compatible with Windows NT drivers, or is it just heavily inspired by Windows NT?
Only the latter
great minds think alike because i also wanted to keep the first 6 args in the same registers as the sysv abi except for RCX
ok so i have bugs in my process teardown procedure
now the process is torn down if all threads exit
I suppose I should work on some kind of pseudo terminal next
?!
why did it work with rax==0 but not now
oh
me dumb
now with the actual dummy system calls working
cause it was resetting rax to zero and hiding some problems
so over the coming days i will figure out how i should do certain things
im thinking i could have a common include and rtl source folder
this common include would be includable by both boron-kernel and libboron
and it'd have definitions for structs used in syscalls as well as prototypes for those syscalls
as for rtl well i wonder if i could make it work so that the kernel rtl is symlinked to the libboron rtl
will windows explode if i add a symlink to a directory? (because I do all my work on an NTFS drive within WSL1)
hopefully not
then i should also get started with an actual userspace starting with init.exe
there's a lot of other things i need to do though. first of all, a lot of writing behavior has not been implemented, so no modified page writer, not even any way to write to pages aside from CoW
and there is nothing you can write to
so perhaps i should work on a file system implementation, maybe ext2 again, porting a lot of code from nanoshell but with way less constricted locking (nanoshell has a Giant File System Lock which Sucks)
the thing i wanna finish before any of that though is the system call exposure
in the future i would also like to start working on a security subsystem
i think it's a very useful thing to do
leaning on 9p and virtio-fuse meant i didn't have to address the problems of disk filesystems which have interesting requirements
incredible progress btw
thank you!
can i preach the good word of our lord and saviour RCU
also implement zfs 
i don't know what that is
i dont know what that is

rcu is a way to reduce locking on a filesystem
it deffers reclaimation of nodes so you dont need to guard as much stuff with global locks
zfs is a good filesystem
durable, journaling, multi-disk volumes, resilient to power outages, all the things really
i love zfs but independently reimplementing it is probably as much work as implementing the rest of an OS
porting it seems hardish but feasible though
yeah thats fair, ext2 is probably alot easier lol
although the zfs spec is pretty comprehensive, and theres good tooling for verifying that you've done stuff right
although since this is NT inspired fat32 or exfat would stick to the theme better 
sun were on fire at the time it was implemented
getting jeff bonwick (inventor of the slab allocator) to work on a filesystem was a masterstroke
he brought fresh thinking
No, it wouldn't
If anything implementing NTFS would stick to the theme better
admirably enough I remember banging out nanoshell's ext2 driver within two weeks with a few hours of school every day
two weeks of pain because the OS was pretty much broken most of the time and wouldn't really get a GUI or anything
or no wait it did
im misremembering
the MM overhaul I did in mid 2022 in nanoshell was so comprehensive it took me several days to write in a wholly new project and a few more days to port it to nanoshell proper
(that's how trash the old old MM was)
anyway. I predict that in 3 months, if I keep up consistent work, I might be able to get nanoshell applications and the environment running on boron
for that I'd need to create like a special edition of libboron just for nanoshell to call into
i cannot overstate how valuable unit tests are to stop this kind of stuff happening
even if they're kinda poor quality being able to test a single bit of code without starting up the full os is useful
did i say two months
i meant two weeks
two weeks it took me, start to finish, to get the ext2 driver working
two months i would have died of boredom lol
tests are nice either way, especially for stuff like filesystems that should be deterministic
sure
i do have some tests, they're not really "unit" tests because they require the full OS to boot which takes like 4 seconds (since its just the kernel)
of which 2 are the qemu seabios and 1 is pressing enter in limine
more like integration tests
the closest thing to a unit test is probably boron/source/ke/tests.c which i should actually remove because its a giant anachronism
it survived many battles
you're running qemu inside wsl2 right? i've found enabling kvm if you can really speeds up boot times
and you can set the limine boot timeout to 0 to instantly boot
no
qemu on windows
hm nvm then
it's a batch script run from wsl(1) that runs qemu-system-x86_64.exe
Honestly probably the oldest script in boron
idk what the state of qemu on windows is like, is haxm or hyperv an option?
nanoshells run script is a direct ancestor to borons
you can use whpx but nanoshell has never worked on there
idk why
probably worth fixing lol
for reasons unknown to me, hyperv actually validates alot of stuff that other vms dont
and from time to time also other vms and real hw
hell its closer to the x86 spec in some ways than my actual cpu is lol
honestly hyperv sucks ass in terms of performance
i tried installing XP on it
horribly slow
does it do a vmexit for each pixel that XP writes or what
nanoshell isnt much better on HV either
i personally havent had issues, but that might be because i use server hardware
actually its not bad on my laptop either so idk
yknow i have a friend and i was using a linux vm in vbox and he said
and im not joking
"how is it so snappy"
"i have tons of lag in vbox"
what version of windows are you using? i know its performance has improved alot in recent versions of 11
ouch
11 22h2
what cpu do you have?
though i got a new ssd and im planning to move to a new install of 11 24h2 ltsc
ryzen 5 5600
my old r5 1400 ran vms pretty decently
cursed windows install
my entire old youtube channel was made with it
it was about screwing windows xp up
perf was very acceptable
I know haxm is supported in qemu.
Virtualbox and qemu on my Linux machine is really fucking fast, and I'm using a Core i5-7500, nothing special at all.
i should look into a bug where for some reason, if i make it spawn like max 60 explodeable threads in the firework test instead of max 2, then the firework spawner thread stops
which is annoying
i think it might just be having trouble spawning anything
several seconds in between each spawning message
what the hell is it waiting for
perhaps it's contending against the handle table lock?!
wow
it's contending against the handle table lock
"but iprogram! why is it contending against the handle lock!"
well it's because i am using the object manager backed PsCreateSystemThread to create threads instead of allocating them from pool and stuff
for their ref counting capabilities
i have an idea for handle table optimization
to use a rwlock
to create a handle, first, acquire the rwlock shared, and perform an atomic compare exchange over every slot. if there are no free slots, then unlock shared and lock exclusive, scan again, and if there are really no slots, expand and create a slot.
to delete, simply lock shared and atomically clear the handle spot
the handle table currently doesnt employ any fancy tricks to optimize handle creation so in effect its O(n)
so i could either do this locking optimization or perhaps try something new
or you can have two locks:
- a rwlock that readers take shared and writers take exclusive only when expansion is needed
- a plain mutex that writers always hold but readers don't care about
yeah, if the number of handles is growing very large and you are contending a lot on the handle table lock, this might be why
it doesn't, ive only seen it grow up to 48
because the firework test creates a thread, the function that creates the thread returns a handle which is derefed
and then the handle is closed
and only the object remains
a big roundabout
i should just create the object and thats it
I suspect that writer starvation is happening. If you have a rwlock where there are lots of readers such that, with high probability, at any point in time at least one reader is holding the lock, then (depending on implementation) the writer side will be completely starved from execution.
creating an object with ObCreateObject does not require any locks except for the pool allocator lock
whoops I misread
im literally CRYING
bawling my eyes out
WHO THE FUCK is corrupting my threads' stacks
31186248059 30979535763 4 2: Thread ffffa080000bc8a0 -> StackPointer ffffa080000c9b18 | R15=0000000000000000 R14=0000000000000000 R13=ffffa080000fdc28 R12=0000000000000004 RBX=000000072b926f3e RBP=ffffa080000c9bf8 RFLAGS=0000000000000083 RIP=ffffffff80009b7b
31286475908 31245270129 4 2: Thread ffffa080000bc8a0 -> StackPointer ffffa080000c9b18 | R15=ffffa080000c9b28 R14=00000000004c4b40 R13=ffffa080000c9b48 R12=fffff0000000d3a5 RBX=ffffa08000108ed0 RBP=00000000004c4b40 RFLAGS=ffffa080000c9b68 RIP=ffffffff80002c27```
two different instances that have the same sp
not out of the ordinary
what is out of the ordinary though is the fucking SP
what the absolute FUCK
the bug will not trigger with gdb hooked in
just never
it will never trigger
maybe if i hook gdb later?
Red zone, maybe?
I disabled it
i have an idea
i wonder if the crash is caused by a thread being transitioned to a different CPU
and it's using stale TLB entries
the answer is probably not
also i dont think the PTE backing the SP is changing
i spotted something weird
it seems to be scheduling the thread in without having a previous switch?!
12794793622 12791571375 0 2: Thread ffffa080000be0a0 -> StackPointer ffffa080000c5c48 | R15=ffffa080000c5c58 R14=ffffffff800047c9 R13=ffffa080000c5c68 R12=ffffffff80009e49 RBX=ffffa080000c5c98 RBP=ffffffff80005a4a RFLAGS=fffff00000004555 RIP=0000000480009a1d PTE=000000000040a363 OTH=ffffa080000be8a0
omg
i found the bug
fuck
this is what happens when you dont extensively test everything
i think
what if OldThread and NewThread are the same
no, i think this bug is fixed actually
https://github.com/iProgramMC/Boron/commits/master/ 15 whole commits today
all of these were uncommitted yesterday
like
i manually git staged everything
if this were 2022 i probably would've just made it one commit
nanoshell had many a huge commit
i quashed a few more bugs
made borondll relocate itself instead of the kernel relocating it
fixed the bad IA32_STAR value that was used
good night
I probably broke some records on my profile with this amount of commits
btw this is still not totally stable. I have some freezes in qemu sometimes
also im starting to think of future ports again
x86_64 SMP (now), then i386 UP (later), and ARM/AArch64 (later) are the planned ports
cool
i fixed another bug
this time in the rwlock implementation
if (!Exclusive)
{
// We were holding onto it shared, so try to grant exclusive access.
Access = true;
}
else if (Lock->SharedWaiterCount)
{
// We were holding it exclusive, and there are no shared waiters.
// Have to grant exclusive access.
Access = true;
}
this
was supposed to be this
if (!Exclusive)
{
// We were holding onto it shared, so try to grant exclusive access.
Access = true;
}
else if (!Lock->SharedWaiterCount)
{
// We were holding it exclusive, and there are no shared waiters.
// Have to grant exclusive access.
Access = true;
}
with that we should have pretty much stable userspace ™️
on 1 core this wasnt a problem because.. uh, reasons
idk why actually
💀
ironically this isnt even supposed to have the VAD mutex or something locked
ah no thats not the VAD mutex
what the fuck is this mutex
oh
handle table lock
okay... i think the VAD and heap locks should be a bigger level then
works
but now i have another problem
sometimes one of these addresses is corrupted
Nope
I was using a kernel address legitimately
There were a class of other issues tho
i wonder how i should organize everything now that i want to start creating userspace applications potentially
apps/* maybe?
I could do something like that
Nanoshell did it like that
i think it makes perfect sense with the current structure
But there'd probably be quite a few in there
that's fine
I didn't say anything about keeping the current structure
Also I'm not sure with the "common" include idea. I mean it seems nice
If it helps me in the long run, yeah, why not
Borondll and the kernel have the common/include dir as an additional include dir
For structure definitions that they share
maybe i can create a github organization
instead of it all being one monorepo
however i will want a different name for this OS
yuh so as it turns out
my kernel ELF loader was actually Broken
I was not supposed to just blindly add the image base to every GOT entry. As it turns out the RELA and PLTREL tables took care of that for me!
And I finally fixed the long standing bug where if you did something like
PIO_DISPATCH_TABLE Dispatch = {
.Mount = MyMount
};```
then the table's entries wouldn't be relocated
no updates in a while
probably because of finals season
but i am thinking of the next thing which is to introduce a way to map files into system space (the upper half of va space)
this is so that a view caching mechanism can be used
i think the view cache views should be tied to the FCB or something but the page cache is already tied to it
the plan is merely to use the view cache as a way to speed up regular IO operations (read(), write() etc) by performing them on cached versions instead
even if a user process didnt mmap the file in its own va space the system will do that in its own half
yes this is very similar to how mintia does this, this isnt very original at all
but im wondering like
how should i make the fileobject or fcb to viewcache address ranges linkage
should i give the fcb a tree? indirection pointers ext2 style?
Have you read Russinovich's Windows Internals? He describes the Cache Manager (this is what you are talking about).
would this really make those ops faster compared to just going through the page cache? afaict it'd need to do the exact same things plus some more
going through page cache:
- look up the backing page
- copy data into it
- advance position
- if you have more data to copy, goto 1
view caching: - find an address to map it to and create the mapping
- [in the page fault handler] look up the backing page
- [in memcpy] copy data into it
- [in memcpy] advance position
- [in memcpy] if you have more data to copy, goto 2
- unmap range
i suppose if you'd keep the mapping around between calls it might be faster depending on how you find existing mappings
Yes, I think it would
First of all it would make it significantly easier because all I would have to do is a memcpy from the views (which can be substantially bigger than one page)
And it would be significantly faster because the pages would be already mapped in
Yes that's exactly what I'm talking about
On 64-bit these views could be like 8 MB because I have plenty of space (512 GB or so)
But on 32-bit these views could be a bit more restrained like 128K or something
yeah the keeping the mapping around part, I'd need to benchmark it to be sure but it sounds like the kind of thing where if "look up the backing page" is fast enough it'd be hard to make up for the overhead of looking up the view
that's just intuition though, might be completely wrong
Looking up the backing page is pretty fast because I use indirection pointers ext2 style for that
However having to do this every time for frequently accessed data, even if it's already been accessed before, sounds like a giant pain (mapping views of the file into memory solves this problem by virtue of the sections of the file already being mapped)
I use a radix tree for it in such a way that if the page is already cached the only "lock" that needs to be taken is an rcu critical section
ehh, to me it sounds like you'd need to have the exact same logic with view caching, just on a larger granularity
to account for the fact that part of the range might not have a view yet
This larger granularity should help, I think
Maybe I can benchmark this but that would require me to implement it both ways
using a very simple benchmark (pwrite(fd, buffer, 8MiB, 0) in a loop to write 1 TiB) and a very simple (and faster than realistic) view cache implementation (map the range if it doesn't match the last mapped range) i get 14.1 GiB/s with direct-through-page-cache and 26.2 GiB/s with view caching
that's much better than i expected tbh
the difference would no doubt be less with a better direct-through-page-cache implementation (i have to copy the data twice because copying into the page cache has to be in an rcu critical section where i can't page fault) and a realistic view cache implementation (which would have more overhead for looking up the views and such), but still
just tested this and wow, if i copy directly from userspace buffer into page cache (due to the aforementioned rcu critical section stuff this is incorrect for anything but tmpfs and breaks if the file is truncated during the write but shh) direct-through-page-cache is 37.2 GiB/s
unfortunately I will not be able to benchmark scalability with this setup because anything but the original direct-through-page-cache implementation has incorrect locking and a bunch of race conditions
what exactly are you testing in btw
in qemu+kvm
i see
the file is on tmpfs (I haven't implemented any other filesystems yet) and there is no memory pressure or lock contention
oh and the test view cache implementation maps into userspace instead of kernel space because my kernel space isn't demand paged
how does the copy into page cache look like?
https://github.com/proxima-os/hydrogen/blob/a4de67f705773de480b98b9dfb301d0b22dcead8/kernel/mem/vmm.c#L1297 this does the actual copying
https://github.com/proxima-os/hydrogen/blob/a4de67f705773de480b98b9dfb301d0b22dcead8/kernel/fs/vfs.c#L1318 this is the "driver" function
https://github.com/proxima-os/hydrogen/blob/main/kernel/mem/object/anonymous.c and this has the implementation for get_page (this function is called both by mem_object_write and by the page fault handler)
this file forgotten by time
// Boron64 - Exception handling
#ifndef NS64_EXCEPT_H
#define NS64_EXCEPT_H
#include <main.h>
void KeOnUnknownInterrupt(PKREGISTERS);
void KeOnDoubleFault(PKREGISTERS);
void KeOnProtectionFault(PKREGISTERS);
void KeOnPageFault(PKREGISTERS);
#endif//NS64_EXCEPT_H
it even lacks a proper header and makes references to nanoshell64
so anyway i was also thinking if it's worth using the same "pool space" as the rest of the kernel or if i should make a totally separate thing with fixed size entries and a bitmap allocator
(because i dont think i will need to allocate views of different sizes for the cache manager)
the trouble with the pool space allocator is that if i use too much pool space for views (which are disposable) i might run out of it for other purposes
VA range for the Cache is separate from pools in NT. I'm going to do it the same. But it's up to the author how to do it in their design. You use bitmaps for physical allocation, not working set lists. Also why fixed size chunks for views? Shouldn't they be subject to demand paging? Committed as much as requested but wired (to ram) on demand basis.
These "fixed size views" occupy a fixed size in VA space however these views would be subject to regular paging just like userspace file views
But for each however many kb/mb in the file there is a separate view
The goal of the cache manager is to allow standard non-mmap read/write operations to be implemented in terms of mmap-like calls, as far as I understand it
But these views would have to serve normal file io operations. So if one user wants to read 2MB of a file and the other one would want to read 128 bytes, how fixed size chunks are going to be useful here? Why Cc would have to create say 2MB view for the the latter request?