Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
22OsC wrote:After a few tweaks the only Page Fault I get now is CR2=0000000000900041.
You might be using a physical address somewhere instead of a virtual address. (This is why it's a good idea to use uintptr_t for physical addresses instead of a pointer.)
22OsC wrote:I made the mapping be similar as possible.
Since I can't see your current code, all I have for reference is your earlier code where you definitely were not setting up the HHDM area the same way the bootloader did.
22OsC wrote:Where I should place my heap then? Sorry if I sound stupid but I'm not sure where I can place it. The heap can be anywhere? Like I don't have to use a canonical address or stuff like that?
You can pick any canonical address that isn't already being used for something else. Make sure there's enough unused virtual address space for your heap to grow.
If you don't want a HHDM area, you don't need to have one, but it means it'll be harder to access arbitrary physical addresses.
well... I did what I could, this is the PML4
i see that "info mem" it's different, I must have it the same?
22OsC wrote:i see that "info mem" it's different, I must have it the same?
The only differences are the page R/W/X attributes. Making it the same will improve security and maybe help catch bugs, but it will work fine the way it is now.
22OsC wrote:and also my uintptr_t implementation is
in stdint.h is like this but on some forums it was void* and I'm not sure if it's right.
You should use the stdint.h provided by your cross-compiler instead of trying to implement your own.
It doesn't really make a difference whether you use uintptr_t or void*, but it's easier to keep physical and virtual addresses separate if physical addresses are always uintptr_t and virtual addresses are always void*.
22OsC wrote:i see that "info mem" it's different, I must have it the same?
The only differences are the page R/W/X attributes. Making it the same will improve security and maybe help catch bugs, but it will work fine the way it is now.
22OsC wrote:and also my uintptr_t implementation is
in stdint.h is like this but on some forums it was void* and I'm not sure if it's right.
You should use the stdint.h provided by your cross-compiler instead of trying to implement your own.
It doesn't really make a difference whether you use uintptr_t or void*, but it's easier to keep physical and virtual addresses separate if physical addresses are always uintptr_t and virtual addresses are always void*.
For now I won't add any page attributes only the required ones, but I mentioned earlier the problem that I have now:
22OsC wrote:I made the mapping be similar as possible. I did the kernel mapping the same as how bootloader did but, the CR2 address is 0000000000900041. And this is happening after I changed the PML4 in bitmap get function. Before this, it wasn't a problem. Do I have to re-initialize the bitmap after applying the new PML4?
if the problem is not about re-initializing the bitmap, then the bitmap initialization is broken (maybe?)
Ethin wrote:So I have absolutely no idea how to catch Limine altering CR3 or anything because I'll always end up catching the firmware doing it first.
Hold on, back up. Why are you trying to catch Limine altering CR3? The triple fault is happening after Limine hands control to your kernel, isn't it?
Yes, it is. I was trying to determine if my page tables changed after my kernel booted, because they shouldn't be changing, and if they are, that would explain the triple fault. But even if that test yields nothing, it still doesn't resolve my initial problem of GDB hardware breakpoints not functioning.
Ethin wrote:I was trying to determine if my page tables changed after my kernel booted, because they shouldn't be changing, and if they are, that would explain the triple fault.
I would expect memory corruption before a stray write to CR3. Have you tried using "info registers" or "info mem" in the QEMU console after the CPU triple faults? (Or disabling KVM acceleration so QEMU will provide accurate exception logs.)
Ethin wrote:But even if that test yields nothing, it still doesn't resolve my initial problem of GDB hardware breakpoints not functioning.
This might be due to KVM acceleration, or it might be a QEMU/GDB bug where hardware breakpoints have to be set in long mode if you want the CPU to hit them in long mode.
Ethin wrote:I was trying to determine if my page tables changed after my kernel booted, because they shouldn't be changing, and if they are, that would explain the triple fault.
I would expect memory corruption before a stray write to CR3. Have you tried using "info registers" or "info mem" in the QEMU console after the CPU triple faults? (Or disabling KVM acceleration so QEMU will provide accurate exception logs.)
I just did. Here's what Qemu says:
info registers:
For some reason, info mem returns nothing -- it waits for a while, maxes out my CPU for a bit and then returns me to the qemu monitor.
Octocontrabass wrote:
Ethin wrote:But even if that test yields nothing, it still doesn't resolve my initial problem of GDB hardware breakpoints not functioning.
This might be due to KVM acceleration, or it might be a QEMU/GDB bug where hardware breakpoints have to be set in long mode if you want the CPU to hit them in long mode.
Ethin wrote:For some reason, info mem returns nothing -- it waits for a while, maxes out my CPU for a bit and then returns me to the qemu monitor.
Does "info tlb" do the same thing? It sounds an awful lot like you've zero-filled your page tables.
Where is your stack, how big is it, and why isn't it aligned correctly?
The "info tlb" command doesn't do the same thing; it returns a fully populated TLB with over 2000 entries. I followed the stivale bear bones for declaring the stack, so I have it declared like so:
I can't apply the repr attribute to specify an alignment of a raw array. I could put it in a struct, and align it that way.
Edit: just redeclared the stack like so:
What is the address of your STACK array? What is the stack address in your Stivale2 header? The addresses in your register dump look a bit funny, and I'm not talking about the alignment.
Octocontrabass wrote:What is the address of your STACK array? What is the stack address in your Stivale2 header? The addresses in your register dump look a bit funny, and I'm not talking about the alignment.
So I told my kernel to print the location of STACK.0, STACK, and the stack in the header. All of them are at FFFFFFFF99100A50h this run (they change every time the kernel boots as a part of KASLR).
Ethin wrote:So I told my kernel to print the location of STACK.0, STACK, and the stack in the header. All of them are at FFFFFFFF99100A50h this run (they change every time the kernel boots as a part of KASLR).
If it changes every time, then I can't compare it to the addresses in the earlier QEMU log to see if your stack has overflowed and overwritten your kernel.
However, if you really do have the address of the bottom of the stack in your stivale2 header instead of the address of the top of your stack, then the stack is definitely overwriting your kernel.
Ethin wrote:So I told my kernel to print the location of STACK.0, STACK, and the stack in the header. All of them are at FFFFFFFF99100A50h this run (they change every time the kernel boots as a part of KASLR).
If it changes every time, then I can't compare it to the addresses in the earlier QEMU log to see if your stack has overflowed and overwritten your kernel.
However, if you really do have the address of the bottom of the stack in your stivale2 header instead of the address of the top of your stack, then the stack is definitely overwriting your kernel.
Damn, I didn't think of that. As a sample run, I changed it to this:
#[link_section = ".stivale2hdr"]
#[used]
static BOOT_LOADER_HEADER: StivaleHeader = StivaleHeader::new()
.stack(&STACK.0[MAX_STACK_SIZE - 1] as *const u8)
.flags(0x1E)
.tags(&FB_TAG as *const StivaleFramebufferHeaderTag as *const ());
And then I had it (once again) print stack information. The information plus exception and register info is as follows:
Stack locations: bottom: 0xffffffffb9920a50, top: 0xFFFFFFFFB9960A4F
Registers:
The odd thing is that I (think) that ffffffffb99008c7h is beyond my stack, and I don't understand why. I've even reserved it properly in my linker script (I think):
OUTPUT_FORMAT(elf64-x86-64)
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
/* Define the program headers we want so the bootloader gives us the right */
/* MMU permissions */
PHDRS
{
null PT_NULL FLAGS(0);
text PT_LOAD FLAGS(0x5);
rodata PT_LOAD FLAGS(0x4);
data PT_LOAD FLAGS(0x6);
}
SECTIONS
{
/* We wanna be placed in the topmost 2GiB of the address space, for optimizations */
/* and because that is what the stivale2 spec mandates. */
. = 0xffffffff80000000;
.text : {
*(.text .text.*)
} :text
/* Move to the next memory page for .rodata */
. += CONSTANT(MAXPAGESIZE);
/* We place the .stivale2hdr section containing the header in its own section, */
/* and we use the KEEP directive on it to make sure it doesn't get discarded. */
.stivale2hdr : {
KEEP(*(.stivale2hdr))
} :rodata
.rodata : {
*(.rodata .rodata.*)
} :rodata
/* Move to the next memory page for .data */
. += CONSTANT(MAXPAGESIZE);
.data : {
*(.data .data.*)
} :data
.bss : {
*(COMMON)
*(.bss .bss.*)
} :data
}
Subtracting 1 results in a value that's 1 below what you should use for the stack pointer, and misaligns your stack. I don't know if Rust allows pointers past the end of an array the way C does, but that's basically what you need here.
It looks like your stack will be correctly 16-byte aligned once you fix that.
Ethin wrote:The odd thing is that I (think) that ffffffffb99008c7h is beyond my stack, and I don't understand why. I've even reserved it properly in my linker script (I think):
Other than the off-by-one error above, it looks like everything is set up correctly. Your stack just isn't big enough for whatever it is you're doing. You could make it bigger, but I'm really curious why 256kB isn't enough already.