#OBOS (not vibecoded)
1 messages Β· Page 4 of 1
I think the timer was running way too fast
Still got some bugs to fix
But then I can move onto the driver interface
Which consequencently means I implement uACPI
Yeah lol, average c++ stack trace: wider than it is deep
Yeah that still shouldn't cause panics tho
It causes everything to shit itself, including the host os 
meanwhile in c after breaking something you just get the same stack frame duped a few million times xD
Which of course have to do with stack corruption
The stack corruption was caused by a missing cli in the function to switch to another context
I added a watchdog timer after initializing the scheduler to make sure the LAPIC timer doesn't hang
Oof
Well there is a bug with the other CPUs hanging in the cpu entry point because their IRQL is 0xf
But it only happens to some CPUs
The whole irql concept sounds a bit bug prone
But itβs a nice flex once you got it right
It indeed is
I'll get it right eventually
I suspect the bug is with the IPI handler not lowering the IRQL
Somehow
It's not the IPI handler
So it's likely the scheduler
All I know is that an asynchronus context is raising the IRQL to 0xf and not lowering it
The bug was a missing LowerIRQL and the end of the irq dispatcher
It did lower the IRQL when calling the handler
But only then
So, if nothing recognized that interrupt, it would leave the IRQL at 0xf
I'll do one last test on the scheduler, then I'll commit and merge the branch
Why the fuck is there a stack trace with 790 frames
For future reference, do not put assertions in *IRQL functions
At least not this assertion:
OBOS_ASSERTP(arch::GetIRQL() == getIRQLVar(), "");
Now there is a bug with the IRQL not getting lowered from 0x2
Well I said that after implementing a fix
But the scheduler seems to be stable without any apparent bugs
Why
Now try at max frequency
Well, locks raise the IRQL, right?
The panic function calls vprintf which locks the printf lock
which therefore raises the irql
but, that assertion fails again
and that happens infinitely until the stack guard page is hit
Well, what is max frequency?
The previous bug with the timer being fast was because of a bug with the calibration function
I'll try at 1 khz
Shits itself
more like: it found a bug
Attempt to call LowerIRQL() with the irql 2, which is greater than the current IRQL, 15.
Stack trace:
0xffffffff8000acbb: _ZN4obos6logger13panicVariadicEPvPKcP13__va_list_tag+189
0xffffffff8000abfe: _ZN4obos6logger13panicVariadicEPvPKcP13__va_list_tag+0
0xffffffff8000adc0: _ZN4obos9LowerIRQLEhb+131
0xffffffff800016d0: _ZN4obos16pageFaultHandlerEPNS_15interrupt_frameE+343
0xffffffff80013b20: External Code
0x0000000000000003: External Code```
What
That makes no sense
if (newIRQL > getIRQLVar())
logger::panic(nullptr, "Attempt to call %s() with the irql %d, which is greater than the current IRQL, %d.\n", __func__, newIRQL, s_irql);
It triple faults because cr3=0 at 0.1 kHz
wait
I got my numbers backwards
*1 mHz
*0.1 mHz
I somehow crashed qemu at 10 kHz
[Log] KernelArchInit: Initializing scheduler.
**
ERROR:../../../system/cpus.c:504:qemu_mutex_lock_iothread_impl: assertion failed: (!qemu_mutex_iothread_locked())
Bail out! ERROR:../../../system/cpus.c:504:qemu_mutex_lock_iothread_impl: assertion failed: (!qemu_mutex_iothread_locked())```
I think keeping it at a couple kHz is a better choice
I'll keep it at 4kHz
I just need to fix the bug where cr3=nullptr
Then I can commit
Crashed qemu again 
A thread that wasn't fully setup yet was recognized by the scheduler
and tried to run before it's context was setup
g_threadPriorities[(int)thr->priority].Append(thr);
arch::SetupThreadContext(&thr->context, &thr->thread_stack, (uintptr_t)entry, 0, false, 0x10000, thr->addressSpace);
setup the thread before
Yeah I know
Now that there are no apparent bugs with the scheduler/irqs/context switching/whatever
I can commit
Committed the code
So now it's time to implement the driver interface
I'll start in a couple hours by porting uACPI
I got something to do now
Nice
Now it works at any frequency?
Qemu or your scheduler 
Both 
@flint idol FYI i just merged the branch with a bunch of improvements for uacpi
dont worry it doesnt change anything public facing
So unmasked?
normal dispatcher level
the normal irq level
it doesnt do much besides reading registers and potentially scheduling some events
whats IRQL 2?
IRQL 2 is used for the scheduler
sure why not
the scheduler is typically a DPC
acpi irq is not any different from any other device
also if u want to eventually implement support for EC u can refer to this https://github.com/managarm/managarm/blob/master/kernel/thor/system/acpi/ec.cpp
EC is used for anything like lid close/open events, charger plug/unplug, fn+sleep/brightness/wahtever
power button on some hardware as well
Oh and this is managarm's implementation of kernel api:
https://github.com/managarm/managarm/blob/master/kernel/thor/system/acpi/glue.cpp
might also be useful
Well I'd just be using my old kernel as a reference for that
sure
@real pecan what is uacpi_cpu_flags used for?
oh ok
I'm currently fighting with cmake and ld to properly link against the static library that has uACPI
It was because I didn't reference uACPI anywhere in the kernel
@flint idol BTW you're not allowed to use memcpy for raw memory r/w
I should really specify it in API description
I'd assume because the hardware might expect a write/read at a certain granularity
Yea
@real pecan is the mutex for the kernel api for uACPI recursive or not?
if only you read kernel_api.h 
oh yeah
didn't see that
so do you want me to hang or fail if the current thread already has taken the mutex?
Actually that's a bad question
@flint idol i fixed the PRIX64 thing
ok
..and an out of bounds found by qookie fuzzer
Do it
@real pecan
uACPI seems to be freeing an object that was rather:
- already freed
- never allocated
- gotten from a different source than
uacpi_kernel_alloc
Maybe the allocator expects the exact base address of the allocated address
And uACPI provided the base + some offset
UACPI frees by specifying the exact address that was given from malloc
well that's not the case then
Well if it works in managarm then I dont see why it wouldn't work here
Test managarm with this exact command line
I'll look into the allocator structures myself and see the allocator somehow missed the object in it's allocated list
It seems to be memory corruption in the allocator
Doubt it's uACPI
I'm probably providing an invalidly sized block

I just don't know why it would fail now out of all times
uACPI really stresses it probably
and tbf this allocator is only less than a month old and I'm stressing it with a whole-ass acpi library
The previous kernel's allocator was a couple months old, and stress tested a lot
or at least stressed a lot more
A very trivial slab cache for uACPI objects could really help here btw, ill probably make an optional interface for that
So, there's this one line
newNode->data = (char*)ROUND_UP(((uintptr_t)(newNode + 1) - sizeof(uintptr_t)), padding);
for setting the data pointer of a new node
I'm wondering, what is the point of the - sizeof(uintptr_t) after adding the offset to the node?
I remove it, and the entire kernel falls into shambles
The only thing I can think of it doing is making the pointer leak into the node structure, which isn't what happens with that line
Well it is rounding up
The node does indeed exist in the allocator's structures 
So, it's these lines that are causing the allocator to skip the region node containing the node:
if (!(base >= cregion->base && base < ((char*)cregion->base + cregion->regionSize)))
goto bottom;```
cregion->regionSize=0x280
cregion->base=0xffff8000fef98000
addr=0xffff8000fef982b0
the region size is incorrect
the region size is calculated without considering the region node size
Damn
I've fixed the bug in the allocator
and now uACPI initializes properly*
*except for PCI stuff, I don't support that yet
Nice
Might as well implement PCI register accesses now
Done:
Time to test shutdown and stuff
Then, I'm moving onto the module loader
Shutdown works
Reboot works
I'm not going to test anything else
Anyway time for a lot of copy+paste from the old kernel
Will a lot being the relocation code
But, before that, I'll push the new code
Despite my original plans for this kernel's driver interface (to just copy+paste the old one), I'm going to redo it
Awesome
Damn
thats a long time
It's not going to be complicated necessarily
I probably won't have that much time
bcuz school and stuff
I just tested on real hardware, it breaks while initializing the scheduler
Unitialized memory maybe?
Idk
I'll debug it later
On another computer, it pages faults in uACPI because of an invalid pointer from the allocator
So there's a bug with the allocator and the scheduler
||allocator bugs are the worst||
thats why you write userspace tests for your allocator instead of testing it against an actual kernel in runtime
No
Right so remember how I said I wouldn't test my allocator
It would be a lot easier to fix it if I just tested it
It'll be something like:
size_t passes = 2097152;
void* lastDiv16Pointer = nullptr;
for (size_t i = 0; i < passes; i++)
{
void* mem = allocator.Allocate(1 /* The allocator counts in chunks of the block size, not bytes. */);
if (i % 16)
{
if (lastDiv16Pointer)
allocator.Free(lastDiv16Pointer);
lastDiv16Pointer = mem;
}
}```
That will stress test the allocator with a lot of allocations, whilst only freeing some of the allocated pointers
To simulate the kernel's allocations
A lot aren't freed because they needn't be freed
or they're for drivers that the kernel needs
etc.
Actually I might as well use that code
it also allows me to break on the exact allocation that page faults or reports allocator corruption
because I can just break when i == (whatever index failed)
The allocator isn't randomized in any way
you should really randomize it tho
just generate a random seed and print it at the beginning
then feed it to the generator
then generate allocation sizes
they will be the same for the same seed so its reproducable
Why must the allocator not fail the one moment I need it to fail?
Maybe it's a problem with non-zeroed memory
I'll make limine randomize the memory and then try
object memfile or something like that idr, Google it
object memory-backend-file,id=mem,size=128K,mem-path /tmp/qemu.ram \
Perhaps its called something else now
Should work tho...
Show full command line
It doesn't
qemu-system-x86_64 ^
-drive file=out/obos.iso,format=raw ^
-m 1G ^
-gdb tcp:0.0.0.0:1234 -S ^
-accel tcg ^
-cpu "Haswell" ^
-M q35 ^
-monitor stdio ^
-debugcon file:CON ^
-serial tcp:0.0.0.0:1534,server,nowait ^
-smp cores=8,threads=1,sockets=1 ^
-d int ^
-D qemu_log.txt ^
-object memory-backend-file,id=mem1,share=on,mem-path=./memory.img,size=1G```
ok then to wsl I go
it is indeed linux only
and KVM fails with "KVM: entry failed, hardware error 0x0" upon initialization of my scheduler
rather right after initialization of the scheduler
Yah something is fucked in your kernel
Lol
Yeah only d int doesn't work
instead of fixing the underlying bug in my kernel that caused kvm to break, I used TCG
this is pretty slow
it took like a minute for 60000 of passes
I'll blame it on qemu tbh
qemu on wsl is pretty slow
Is your ram in tmp?
60000 passes on windows qemu took less than 20 seconds
yes
Wait this is TCG?
yes
yes
From dev random?
from /dev/urandom
Thats fine I guess
Is it allocating random amounts?
Well
Almost
it allocates i % 16 every time
and frees an object every 16 iterations
Anyway the way you're stressing it is too static to trigger a bug
The bug I'm trying to trigger is specifically a page fault that happens when the allocator gives out a region outside of a region's bounds
I'll just get a rand implementation
randread
rdseed?
That and then rdrand
well, haswell doesn't seem to have that
maybe I'm mistaken
nvm
I misread ecx as eax
How convinient 
It fails on the second iteration
nvm, allocate failed because of the size being zero
Lol
I don't even care about what I was doing before. I'm optimizing this allocator
Do it
Sorting lists on. every. single allocation is painfully slow
and bubble sort isn't neccessarily the fastest sorting algorithm
Wtf
Don't ask 
Anyway off to bed but good luck with your debugging
ty
@flint idol why is this returning a constant number?
uacpi_u64 uacpi_kernel_get_ticks(void)
{
return 2500; // 4000 hz -> 250000 ns = 2500 ticks.
}
We all love our magic numbers 
I saw what my previous kernel did and assumed it was right
Lol
I just woke up now so I'll fix it later
I think I should fix make it so my IRQ interface so that multiple handlers can be called for the same IRQ source
By default, if an IRQ comes, the first IRQ object to recognize the IRQ is chosen, and only that one
Which isn't ideal, especially for the timer interrupt
It technically isn't linked to the scheduler, but if it's the only handler that gets run, it basically is
What do you mean?
Are you going to have multiple interrupt handlers for one timer?
Kinda
It's more like a list for irq handlers for each irq object
and then the irq dispatcher would call/dispatch to them all to DPCs
I just said the timer IRQ as an example
This will allow for timer objects which have a callback
for example, because the scheduler won't be the only thing that can run off the timer interrupt
You might find it useful to abstract away the timer into a queue of events, which the timer drives. Your scheduler and other things can put things in the queue to expire at certain times.
That might be a better way to do what I wanted to
Well I just barely optimized the allocator
in terms of speed
20000 allocations with randomly sized allocations from 16-256 bytes
took a minute
Actually if anything, I slowed it down
By a lot
Why is the version that theoretically should be doing less work a lot slower
Ok well one difference is the newer code has one region node that has all the nodes
the other has 208 by the end
Wait that should be impossible
there are 4096 nodes preallocated
and by the 20,000th pass, there was only one region node
What kind of nodes are you referring to? For slab or smth?
Slab
So, for reasons unknown to mankind, the version that should be slower is faster than the one that should be faster
When all that was added was some booleans to skip doing work that was already done
or didn't need to be done
Nice
Out of interest, what did you do for page allocator? Didnt yet look at your repo but I like your project
PMM or VMM?
Phys
Freelist
If I ever get audio support on this os, this will be the first thing I play
So, there is no apparent bug with my allocator even with that test + randomized memory
So....
I really want to implement some sort of way of debugging a panic on real hardware
A recovery terminal of sorts on panic
To examine memory and stuff
tbf that wouldn't be too hard, it's just it would need to be very light, and that'd be hard when I need to check if a keyboard exists
specifically a ps/2 keyboard
It's too much work that isn't generally worth it
I'll make it be a random chance to free a pointer
and it hangs somewhere after the 20,000th pass
nvm
it was just slow
I think an optimization is storing the amount of free bytes in a region so the allocator doesn't have to loop every node checking for a free node
or the longest continuous node size
Yeah I think this is a lot faster
Just what could be a faster way to do this:
SlabNode* longestContinuousNode = nullptr;
for (SlabNode* node = region->freeNodes.tail; node;)
{
if (!longestContinuousNode || node->size > longestContinuousNode->size)
longestContinuousNode = node;
node = node->prev;
}
region->longestContinuousNode = longestContinuousNode;```
Of course without sorting the list in ascending order and using the last node
Wtf is this stack trace lol
IT'S 45 KIB
This is what I knew would happen if I used an allocator in the VMM and the VMM is the allocator
Some random shit like this would happen because the VMM needed to use the slab allocator to allocate a node, which needed to use the VMM to allocate a new region
Now I need to make some changes related to the nodes being allocated after the region is set up
I think if I just reserve the pages using vmm::Allocate() should setup the nodes in the context.
Then I just need to fix the page descriptors
to say the truth about the node
Youβd want to keep some number of descriptors always availabe
ah yes "450 lines left" π
It would be more if the stack were larger or there was no guard page for the stack
I finally got my test laptop working
Debugging on real hardware should be easier
There was an untested case with SMT on the laptop where the SMP code would do... funny things with the BSP because CPU 0 was used for the hyper threads of each CPU
and of course there is a bug where node == nullptr in the slab allocator whilst adding a slab region node
AllocateRegionNode is failing...
It only fails if the VMM fails to find a free page
or if the VMM fails to allocate...
In this case, vmm::RawAllocate seems to be failing
As the slab allocator object being called is the page node/descriptor allocator
Judging by the stack trace
vmm::RawAllocate cannot find a base address on it's own, the caller must
and in this case, the caller doesn't
I just got the 550 line stack trace crash again
It was because the AllocateRegionNode() function didn't add the newly region node before trying to reserved the pages
This time it should be fixed...
Nice
What about your other hardware
Well there is the other computer I use for testing
It's just it's not located close to my dev computer so it's annoying to test on unless I'm testing fixed code
or code that should work
There is the dev computer
Obviously I don't want to restart it on every change to the kernel I make to test it
I seem to have fixed the 550 line stack trace
Just I still have a crash related to that
Slab allocator should be fixed soon
The VMM is being a bitch and not making a page node after the pages are reserved
The Allocate() function isn't failing
There is no reason that the page node isn't being appended
Maybe it was a bug with IsAllocated?
if (InRange(node->pageDescriptors[0].virt,
node->pageDescriptors[node->nPageDescriptors - 1].virt + (node->pageDescriptors[node->nPageDescriptors - 1].isHugePage ? OBOS_HUGE_PAGE_SIZE : OBOS_PAGE_SIZE),
base) &&
InRange(node->pageDescriptors[0].virt,
node->pageDescriptors[node->nPageDescriptors - 1].virt + (node->pageDescriptors[node->nPageDescriptors - 1].isHugePage ? OBOS_HUGE_PAGE_SIZE : OBOS_PAGE_SIZE),
(uintptr_t)base + size-1))```
I don't think size should be decremented
Basically, the node could've been falsely marked as reserved but not committed
So Allocate() tried to commit that node
That wasn't it
Bruh
The page node is getting appended
According to the print statement
So where is it in the context?
Conclusion: This bug should also be impossible, yet it happened anyway.
github.com/AlDanial/cloc v 1.90 T=3.60 s (30.3 files/s, 3408.9 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
C++ 32 345 260 5363
C/C++ Header 57 486 870 3600
Assembly 8 124 53 787
CMake 7 46 23 227
Bourne Shell 3 4 7 27
Markdown 1 0 0 25
DOS Batch 1 4 6 17
-------------------------------------------------------------------------------
SUM: 109 1009 1219 10046
-------------------------------------------------------------------------------```
LOC update
114 text files
I think this bug is unfixable
There is no cause of it
This should be impossible
But yet it happened anyway
i doubt that
Well yeah
But it seems to be completely impossible
Unless data corruption happened
vmm::Allocate calls vmm::Context::AppendPageNode which calls vmm::g_pgNodeAllocator.Allocate
Which should have a region since a new one was allocated
So that shouldn't fail and return nullptr
and if it does there is an assert statement right after that preventing further code execution
Then the node is initialized
and appended to the list
of page nodes
Then, later, after the call to vmm::Allocate() to reserve the pages, it tries to get the page node that represents the newly reserved pages
Which fails because it's not in the list of nodes
Which I was able to confirm by dumping the list of nodes and examining them
The address is indeed aligned to 0x1000 so that shouldn't have caused a failure
The worst part about this bug is that this code path is only getting triggered on real hardware
Rather that or I haven't waited long enough on qemu for it to get triggered
Solution to not being able to debug on real hardware: Make a usb driver and gdb stub
Ok it just failed in qemu
After > 60000 passes
I have one chance to get this right
lol
thats gonna be hard
before I have to wait a couple minutes once again for 60000 passes to finish
yeah obviously
I'm more worried about the usb driver though if I did do that
this opportunity comes once in a lifetime
xhci has been the bane of my existence for a few years now
i can confirm
now it's not impossible i am just too stupid but it is quite a pain regardless
based
In case you couldn't infer what was happening, the page descriptors were freed or uninitialized
Most likely the former
wtf is this gui
xmotif goodness
Did you figure it out?
Well it was probably because of a free of the page descriptor
Otherwise it shouldn't be zeroed out
Interesting, the entire region node is zeroed out
It is initialized before the page descriptor is allocated
It has to have been zeroed out after the page descriptor, otherwise the allocator would've failed in other ways
The only thing I can think of is that the same virtual address was allocated before the node was allocated and appended
Which is very likely
Considering there is nothing stopping that from happening other than the node being present, and the node isn't present
I should just raise the IRQL and temporarily stop the other CPUs
To prevent that from happening
or at the very least raise the IRQL
Raising the IRQL doesn't fix it
But locking the vmm context might
problem is: I don't do that
Well, now is the time for me to do that
Well, it doesn't crash
Just I'm not sure whether it works
It seems to be hanging, likely on the spinlock
Better than crashing π€·
I added a spin variable that will print a stack trace if a lock has been hanging for too long
in the lock function
That didn't fix it

I had misordered the reserve call and the Unlock call so it hung
That's enough debugging for now
So I did end up doing further debugging, and I figured that the page was (somehow) zeroed in Allocate() while reserving the page
I'd need to do more debugging to find out why, although I think it could be because of the page being overwritten when Allocate calls the page node allocator
The bug was because I mixed the protection and flags parameters of vmm::Allocate
There are
How then
They're integers, right?
If you used enum class the compiler would warn you
wdym
It's not allowed to implicitly cast from an rnum class base type to the enum class or other way
You'd need to explicitly do (Enum) v, or (int) v
Yeah but the allocation flags and protection flags are bitfields
Don't need static cast for trivial things
So enum class wouldn't help because I'd need to cast
sure you can use C style casts for everything
but you can also use printf and malloc and whatnot, doesnt mean you should
Printf and malloc are better than cout and new 
not really
printf looks better than cout
That's why I have a flags type
and it also cant format custom types
It can with glibc
anyway std print exists in c++23
i dont consider non standard extensions part of the language
Printf is much faster than using cout
whats your source for that
Cout does sync on every write with <<, meanwhile printf is once
so you dont have a source
You don't always need a source, when you've tested yourself
well show me your results from your tests then
Not at home, nor do I keep track of every test I do
a quick google search doesnt show the same as what you have said
also i dont really see how the performance of printing to the console really matters
Now do that with many strings/ints/floats
And then tell me what happens when do have multiple threads writing out
there are plenty of solutions to that
I thought it was only with std::endl
Unless std::ios_base::sync_with_stdio(false) has been issued, it is safe to concurrently access these objects from multiple threads for both formatted and unformatted output.
That just disables the sync altogether
It's with each <<
But it flushes its internal buffer on endl
You can't use those as flags I don't think
Example?
we just saw an example how that lead to a multiple days of debugging
it was only one day of debugging
The other days spent were to try to optimize the allocator
enum class flag { one, two };
flag operator|(flag l, flag r) { return static_cast<flag>(static_cast<unsigned>(l) | static_cast<unsigned>(r); }
In fact, wouldn't it error if the invalid type is used
you'll figure it out

i actually wont
Survivorship bias or survival bias is the logical error of concentrating on entities that passed a selection process while overlooking those that did not. This can lead to incorrect conclusions because of incomplete data.
Survivorship bias is a form of selection bias that can lead to overly optimistic beliefs because multiple failures are over...
i dont think i would have gotten that even if i had thought about it
this plane is a pretty common meme so you would've run into it eventually
i believe its my first time seeing it
Yeah, think I can't even count the number of times on my hands and feet xD
lmao
Oberrow sees everything
Anyway, that's enough allocator testing
Time to test uACPI on test subject #3
Instant page fault 
Definitely a problem with my allocator or something similar
As this aml blob has been tested with my previous kernel and worked just fine
Nvm
A similar crash happens on qemu
Still a problem with my allocator though
i thought u fixed it 
Well
I did
Then another bug came
or maybe it's something else
I'll test on my previous kernel with the current uACPI version
do u assume its a uacpi regression lol
nvm, I can't test on my previous kernel
I don't want to make the new kernel api again
if anything i've fixed tons of fuzzing issues recently
All I know is that the allocator is giving a pointer that exceeds the boundaries of a region
Thus causing a page fault
Instead of finding the root cause, I'll just make the allocator detect this happening, and make it try allocating from the next region
like the allocation function is broken?
cant u track down why
Well for that I'd need to be able to break at the exact allocation that does that
As it doesn't happen for each allocation
just use liballoc at this point
At this point, I might as well use my old's kernel allocator
I mean ideally you'd just debug your allocator properly
in userspace
and testing it by replacing it in e.g gcc
#1141057599584878645 message
lol
Who knows
attach a debugger and add a breakpoint
Ok I fixed the bug
It was a node's size being incorrectly calculated at initialization
Welp, the allocator failed on one of uACPI's requested
With failed meaning: returned nullptr to signify error
That should be impossible though
Allocate() should never return nullptr
I'll log what it returns in uacpi_kernel_alloc
uacpi_namespace_load: aborting execution due to previous error: out of memory
the allocation before that is 0x39b0 bytes in size
anyway I'll be back in an hour to figure out why this fails
Well idk what happened, but now it's hanging somewhere
idk where
idk if it's in the allocator, while taking a lock
All I know is that it hangs somewhere
is gdb not allowed?
Not on real hardware
Unfortunately
Is there a way to make uACPI trace a lot more than the usual UACPI_LOG_TRACE option
yea
in the interpreter comment out #define UACPI_TRACE_OP or whatever its called
it will log every opcode thats gets executed
Well, now I know it hangs somewhere on the execution of a FieldOp
Looking at the interpreter code for processing FieldOp, there seem to be no calls to kernel api
They happen in the microcode
But add logs if unsure
The code you're looking at processes an already parsed opcode
I now got a bunch of print statements in most kernel api
Time to wait for the opcode to come up again
Why the hell is there a single opcode that has multiple pages of logging solely for allocations
It's not even done logging the allocations it's doing
Maybe that was the FieldOp
Fieldop is one of the more complex ops
Because there still hasn't been another opcode since then
It has a variable list of named objects that must be created
Unlucky
Is making the allocator hang
Possibly because of all the regions there are
Good thing I have a function called OptimizeAllocator which will hopefully do something here
So the allocator has something called region nodes
They represent a region of memory
There are probably so much, that in trying to find a free one, the allocator takes a stupidly long amount of time to find one
A lot of them might have no allocated nodes at all
OptimizeAllocator defragments the region nodes and removes any regions with no allocated nodes
I'll just make uacpi_kernel_alloc call it every few hundred allocations
Not a very good design lol
it'll be fine
I made the spin lock print something if it spins for a long time
and of course it's in OptimizeAllocator
recursive lock
oops
At this point if the allocator is causing so much trouble
I should rewrite it or use a different one
probably
definitely, yes
welp, time to nuke the allocator
This allocator will be nothing but git history now
Time to welcome back the old kernel's allocator
But heavily ported to fit this kernel's allocator structure
tbh I should've done this a lot earilier
Like before the scheduler
I've ported the allocator
I just need to do one more thing before it works
I did that thing
Time to test it
Immediate page fault
lol
Anyway time to debug
i wish i could say my kernel isnt cursed
new depended on the allocator being initialized
and new was called before the allocator was initialized
the return value of new is not checked once
so it page faulted trying to access the zero page
Some parts of my kernel are cursed because of some hacks to make inter-dependendent parts of the kernel work
Those parts are extremely fragile and can break if you modify them
Example: VMM initialization
Now instead of getting a page fault I get this:
Stack trace:
0xffffffff8000d4bb: Cannot get function name
0xffffffff8000d3fe: Cannot get function name
0xffffffff80010676: Cannot get function name
0xffffffff80010993: Cannot get function name
0xffffffff800102ba: Cannot get function name
0xffffffff80010348: Cannot get function name
0xffffffff8001150a: Cannot get function name
0xffffffff80000465: Cannot get function name
0x0000000000000000: Cannot get function name```
Which is good
Still doesn't work but better than page fault
It was because of the same reason as this #1141057599584878645 message
I fixed that and it hangs
Why does it hang
I'm trying to figure that out
Does it hang in qemu?
It was hanging in the allocator
not uACPI
Should've mentioned that
This is the same allocator as the previous kernel
The one that worked with uACPI
On all of my avaliable ASL blobs
it was hanging because the allocator was locked and vmm::Initialize was trying to call it
Recursive locking = bad
Does it not hang anymore
In general
Inb4 quadruple fault
Nah, instead a seemingly impossible code path was taken
nvm it's not impossible
// There must be something seriously wrong with this page block if this if statement is executed.
if (!current->firstBlock || !current->lastBlock)
{
current = current->next;
if (!current)
break;
if (!current->firstBlock && !current->lastBlock)
freePageBlock(current->prev);
continue;
}```
That if statement happened
To fix that, I just need to remove the if statement
It thinks that block is corrupted
Which it would be in normal cases
except this isn't a normal case
I fixed the hanging
Somehow something forgets to unlock the allocator
nvm
Just an oversight
now it should work
still hangs
Bruh
I'll just stop yapping in here for every bug I find and just say when I fix it
that should speed stuff up
Nah its fun to read
hold on, you enjoy this lol
it hangs in the demand page fault handler
Rather, it gets in an infinite loop because of it
I just realized at that point it doesn't exist
this time it should work
bruh
division error
But it at least got farther than vmm initialization
Function uacpi_kernel_free, line 318: free of object by uACPI not allocated by uACPI allocator. This is a bug, please report in some way.```
Welp, time to fix that
didn't get that with previous allocator, time to rollback
Just got this on reboot:
Function Allocate, File /mnt/c/Code/obos/src/oboskrnl/allocators/liballoc.cpp, Line 212: Assertion failed, "currentPageBlock->highestBlock->magic == MEMBLOCK_MAGIC". Kernel heap corruption detected for block 0xffff8000fee020a0, allocAddr: 0x0000000000000000, sizeBlock: 0x0000000000000000!```
Just rebooted and it disappeared
Unlucky
Memory corruption 
.
Lol
I decided to change the allocation method for the allocator to use a free list instead of basically bump off of the highest block
inb4 instant page fault
That is what happened at first, rather that or a hang
I fixed those bugs, and it got further into uACPI
Before page faulting again
because the allocator provided an invalidly sized memory block
0x20 bytes were requested and the pointer given was 0x10 bytes to a page boundary to a page that was unmapped
I should probably add guard pages to these page regions
At which point will you admit that you should have debugged and tested your allocator in userspace? 
this is the old kernel's allocator
the one that was supposed to work
and it did in the old kernel
and it is now
Big ouch
I just need to fix it...
It wasn't the allocator's fault
It was the kernel api's fault
in this case
That sounds like an easy fix then luckily
it did some wacky stuff to the size parameter
that it only needed to do with the other allocator
how does
block->next = nullptr;
block->prev = nullptr;```
Correlate to a page fault happening in the thread context switch function?
I think my kernel is cursed
My kernel is cursed.
time for rewrite 5
jk
I did something else, and now rather qemu bails out or uacpi magically makes qemu shutdown
qemu bails out
**
ERROR:../../../system/cpus.c:504:qemu_mutex_lock_iothread_impl: assertion failed: (!qemu_mutex_iothread_locked())
Bail out! ERROR:../../../system/cpus.c:504:qemu_mutex_lock_iothread_impl: assertion failed: (!qemu_mutex_iothread_locked())

A rebuild should fix it...
it doesn't
It's because the cpu_local pointer contains the IRQL, but it somehow wasn't demand paged it seems
nvm
it might be because of that
Lol
The triple fault is during the gdt initialization
*cpu-local gdt initialization
the gdt is null except for the tss
Maybe this is why 
memzero(g_cpuInfo, sizeof(cpu_local) * g_nCPUs);
Now it triple faults somewhere else
Seems as if the hhdm page tables are corrupted
How do I mess up that badly
More than the hhdm page tables
It triple faults around the free of an object
I wonder if I tested vmm::Free 
It's a bug with FreePageTables() 
hmmm
idk how but I freed the stack by accident
idk how it's still running after that, probably the TLB providing mappings
More than the stack in fact, everything after the HHDM
up until the kernel code
*framebuffer
*FreePageMapAt
Why does this bug have to come up now, idk
But time to fix it
well this is the only time that function gets to be called
I just love it when the VMM fails on an allocation of 8 pages with a whole-ass 48-bit address space
blk = (pageBlock*)vmm::Allocate(
&vmm::g_kernelContext,
nullptr,
nPages * OBOS_PAGE_SIZE,
vmm::FLAGS_GUARD_PAGE_LEFT|vmm::FLAGS_GUARD_PAGE_RIGHT,
0
);```
with all the parameters valid
out of physical memory should panic so that isn't the case
I'll run qemu with 1g instead of 512mib
same issue

The new allocator makes real hardware suddenly not work anymore

or well the old allocator
why is the page block 0xffffffffffffffff
what
maybe I forget to set something to zero
the os being cursed is not even a joke anymore
maybe a rewrite of some parts, or the entire thing would be sufficient to fix it
lol
Like I always say, the most cursed kernel I've written is the second kernel
It was unstable
and the code organization is π©
and it being unstable was unstable
so what happened with this rewrite
well
it started out uncursed
then uACPI came in
and made everything go to shit
not uACPI's fault
but everything went to shit after intergrating it
nah it's good allocator testing 
I'd rather have this now than in the middle of writing the driver interface
or even worse, vfs
#1141057599584878645 message
If you thought this was speedran, the previous kernel got the scheduler within the first week
lol
and it's just the allocator that's cursed at this point
everything else behaves
the allocator is like that one weird kid in a kindergarten classroom
they all behave except him
solution: rewrite the kernel allocator
I tried porting the one that worked
Barely worked
the one before that barely worked after days of debugging
but before I do that
I need to make sure I can't fix this bug
I already ported it, I don't want to be left with an even shittier allocator if the rewrite doesn't work
ye
and if none of them work, liballoc is my saviour
My favorite progress report
yeah none of the others have any detailed bug reports (because they don't have many bugs like I do)
or if they do there's are boring bugs
If I just make this allocator simple af, there should be no bugs, right?
Like if there is no room to fail, it shouldn't fail
Like if free just slaps a node to the free list
and allocate removes a node from the free list to the allocated list
and returns a pointer to that node's data
everyone's happy
reallocate just does some memcpying and freeing and allocation
imagine needing realloc
I don't think it's used anywhere
the entire linux code base has 138 usages
I just implement it just in case
There was a dynamic array class I was working on
Idk what happened to that
Well thats just the file count isnt it
Some files may use it multiple times
most files are one time use, some are 2 times
i also see one 3 time and one 4 time
#1141057599584878645 message
You're the third person to recommend him that
third time lucky

ok fine I will
I just finished writing the allocator, I'll test it tomorrow
I opened the project I had for testing things in visual studio, and to my surprise, I had an allocator
That I had tested
It seems to have been an allocator I was making for my second kernel
but ended up ditching because it was π©
I tested the allocator with allocations from 1-2048 over 100,000 passes
there were a couple small bugs that I fixed
in userspace this time
All the passes were done in under a minute
I'll run it with optimizations
nah π
msvc compiles out my allocator test function
I may or may not have written it in obos
and ported it over to windows
I just want to see how it works with optimizations
and with the rng seeded
it works
without problem
will you finally uncurse your kernel
If I figure out how it is other than the allocator, then yes
Probably the VMM
The VMM and allocator being interdependant probably wasn't a good idea
I've applied the changes
Time to test
Well, it works (kinda)
except for the fact the uacpi causes the allocator to fail massively
with a very, very, very long stack trace
lol
I think what I just did should fix it
nope
time to examine the stack trace
I'll test the allocator in user-space again but with a bigger range
for the size
uACPI allocates big objects
Lesson learnt: do not allocate one million passes of an allocator with the max size being 4 pages
unless you don't mind casually using 4 gib of memory
Your allocators high limit is 4 pages?
no
I just decided 4 pages max for the allocator tests
when choosing the random number
oh mb
It also rounds up sizes to a 4 page boundary when allocating a page region
Maximum allocation size for uACPI should be a few pages
Unless its some crazy recursive aml and stuff
A lot of memory is intentionally being leaked, so I'll fix that
Every three allocations, a block is freed
It works in userspace
even with bigger allocations
sooooooooooooooooooooooooooooooooooooooooooooooooooooo
I'll run the tests in kernel-mode
100,000 passes while testing the allocator finish successfully
and then uACPI faults?
in both kernel-mode and user-mode
wonder if uacpi triggers kasan in managarm
prob not
it was the allocator during uACPI that faulted
I mean you could always check
A region node has an invalid next pointer
It points to a dead block it seems
Which causes a page fault
irdk how
As that should be impossible
I'll examine the logs of freeing and allocations from uACPI
and since I made logging only go to port 0xe9 the logs are a lot faster
for some reason uACPI frees a lot of objects at the end of something which I think is weird
Mainly because uACPI mainly allocates
It's borrowing my resources and never giving them back >:(
After reading this thread, I realized that allocators are a real tricky thing to deal with
nope, just a skill issue on my side
mainly with my vmm
there is a weird interdependance
that was causing problems
bugs with allocators suck
to deal with
nah that's exactly how it works
all per-op items are freed at the end
Do you also use a GC as well?
no ofc not
that would be a huge overkill
objects are reference counted
Ah ok
I probably won't do much development on this today
After fixing the allocator, I feel like making a makeshift debugger inside the kernel
Won't be anything fancy
Just some step, examine, and register viewing commands
and exception handling
It would take a bit, but it'll be worth it for debugging real hardware
and possibly breakpoints
The only thing I can explain this bug with now is page table corruption
The region that wasn't mapped causing a page fault was never freed
unless...
The region before it in was freed
maybe somehow the region size was invalid
invalid as in too big
so it freed both
regions
It was a bug in the code for rounding up
π€¦ββοΈ
more specifically a typo
size += (size - (size % pageSize));
should've been
size += (pageSize - (size % pageSize));
Function allocateNewRegion, File /mnt/c/Code/obos/src/oboskrnl/allocators/basic_allocator.cpp, Line 308: Assertion failed, "res". Could not reserve page block.```
Now I got that
