GRUB memory map page faults

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.
Post Reply
Xcp
Posts: 19
Joined: Wed Oct 17, 2018 9:56 am

GRUB memory map page faults

Post by Xcp »

Hello,

I'm going to get my memory map via GRUB.
Here in the linker file I put some symbols to get the start and the end of the kernel (I'm using an higher half kernel):

Code: Select all

...
/* lower half stuff */
    . += KERNEL_VIRTUAL_BASE;
    . = ALIGN (4096);
    start = .;
...
    . = ALIGN(4096);
    end = .;
}
Then in the initialization of the memory manager I get the RAM size checking the flags and summing it up:

Code: Select all

/**
 * Get and anylize the GRUB memory map to count the RAM size.
 */
unsigned int findRAMSize(multiboot_info_t* mbt) {
    uint32_t size = 0;

    /**
     * If the bit 0 is set, it is possible to safely refer to mbd->mem_lower for conventional memory and mbd->mem_upper for high memory.
     * Both are given in kibibytes, i.e. blocks of 1024 bytes each.
     */
    if(mbt->flags & 0x1)
        size = mbt->mem_lower + mbt->mem_upper;
    /**
     * Otherwise bit 6 in the flags uint16_t is set, then the mmap_* fields are valid, 
     * and indicate the address and length of a buffer containing a memory map of the machine provided by the BIOS
     */
    else if (mbt->flags & 0x20) {
        memory_map_t *mmap = mbt->mmap_addr;

        while ((unsigned int)mmap < (mbt->mmap_addr + mbt->mmap_length)) {
            size += mbt->mmap_length;
            mmap = (memory_map_t *)(mmap + mmap->size + sizeof(mmap->size));
        }
    }
    return size;
}
So in some kind it works.
Now I have to find the actual blocks. I set (I'm not sure if this is correct)

Code: Select all

stack = end
and then decrement both end and start:

Code: Select all

end -= 0xC0000000;
start -= 0xC0000000;
It is ok until here.
I use the code example in the Wiki https://wiki.osdev.org/Detecting_Memory ... Memory_Map but when it has to go to the next free block, it crashes with a page fault.

Code: Select all

    // Find out what addresses are free
    memory_map_t *mmap = mbt->mmap_addr;

    // TODO: Find kernel + stack start and end addresses

    while ((uint32_t)mmap < (mbt->mmap_addr + mbt->mmap_length)) {
        printf("mmap = 0x%x\n", mmap);

        mmap = (memory_map_t *)((uint32_t)mmap + mmap->size + sizeof(mmap->size));
    }
Do you have some advice?
Thank you to who will help in advance.
songziming
Member
Member
Posts: 71
Joined: Fri Jun 28, 2013 1:48 am
Contact:

Re: GRUB memory map page faults

Post by songziming »

In your linker script you defined two symbols:

Code: Select all

start = .;
...
end = .;
And in your C code you should add the external symbol as:

Code: Select all

extern char start;
extern char end;
Note they are char typed, if you want to get the address of those two symbols:

Code: Select all

size_t start_addr = &start;
size_t end_addr = &end;
You have to first get their address, or you are just changing the char value stored at those two memory location.
Reinventing the Wheel, code: https://github.com/songziming/wheel
Xcp
Posts: 19
Joined: Wed Oct 17, 2018 9:56 am

Re: GRUB memory map page faults

Post by Xcp »

Thank you for the suggestion! I fixed my error!

Now it only remains one problem, though.
I'm still getting a Page Fault while working with the memory map.

I get the address of it from GRUB:

Code: Select all

memory_map_t *mmap = mbt->mmap_addr;
Then following some Wiki advice I go with a while loop:

Code: Select all

    while ((uint32_t)mmap < (mbt->mmap_addr + mbt->mmap_length)) {
        // Gonna push every free block if it isn't in the kernel + stack space
        printf("mmap = 0x%x\n", mmap);
        printf("mmap->size = 0x%x\n", mmap->size);
        printf("mmap->type = 0x%x\n\n", mmap->type);

        printf("mmap->base_addr_low = 0x%x\n", mmap->base_addr_low);
        printf("mmap->length_low = 0x%x\n", mmap->length_low);
        printf("mmap->base_addr_high = 0x%x\n", mmap->base_addr_high);
        printf("mmap->length_high = 0x%x\n", mmap->length_high);

        mmap = (memory_map_t *)((uint32_t)mmap + mmap->size + sizeof(mmap->size));
    }
It just prints the first mmap, though.
The page fault comes even if I only reference the members. There's no need to "jump" (at the end of the while) to #PF...

Can you help me?
Octocontrabass
Member
Member
Posts: 5581
Joined: Mon Mar 25, 2013 7:01 pm

Re: GRUB memory map page faults

Post by Octocontrabass »

Xcp wrote:It just prints the first mmap, though.
The page fault comes even if I only reference the members.
What address does it print for the first mmap? Have you identity-mapped that address?
Xcp
Posts: 19
Joined: Wed Oct 17, 2018 9:56 am

Re: GRUB memory map page faults

Post by Xcp »

Oh f**k, sorry!
I enabled 4MB paging in the boot loader to load the kernel, but I want 4KB pages for the OS. Can I disable paging now and re-enable it with the init of the virtual memory manager?
Octocontrabass
Member
Member
Posts: 5581
Joined: Mon Mar 25, 2013 7:01 pm

Re: GRUB memory map page faults

Post by Octocontrabass »

You can switch between 4kB and 4MB pages without disabling paging.

If you want to disable and then re-enable paging, you need to make sure everything you want to access while paging is disabled is identity-mapped, including the code that's running and the stack.
Xcp
Posts: 19
Joined: Wed Oct 17, 2018 9:56 am

Re: GRUB memory map page faults

Post by Xcp »

Ok, so I'm gonna make a new Page Directory and Page Table where I map the first MB of the RAM (I'm pretty sure the IP register is executing at 3GB as the kernel is up there, though, right? So I'll need to map something like 0x0000000 - 0xC0000000 until 0x00010000 - 0xC0010000). Then I will switch from 4MB pages to 4KB ones setting the new Page Directory.

The mmap is at 0x100A8 address though, so can you please help me in mapping these addresses?
Theoretically just mapping 0 (physical) to 3GB (virtual) should work?
Octocontrabass
Member
Member
Posts: 5581
Joined: Mon Mar 25, 2013 7:01 pm

Re: GRUB memory map page faults

Post by Octocontrabass »

You'd know better than I do what address your kernel is executing at.

You can map the physical location of the memory map to any virtual location, as long as you also translate any pointers you're using the same way. If you map physical address 0 to virtual address 3GB, then you'd need to add 0xC0000000 to the pointer. Note that you may need to redefine the multiboot structures to contain integers rather than pointers: there is no way to translate a pointer without invoking undefined behavior in C (not even by casting to an integer and back to a pointer), but it's completely fine if the integer you cast to a pointer was not originally derived from a pointer.
Post Reply