Mapping memory out of kmalloc() to the kernel page directory.

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
haroldmann
Posts: 2
Joined: Fri Oct 18, 2024 11:47 pm

Mapping memory out of kmalloc() to the kernel page directory.

Post by haroldmann »

Hello all, I've been having this problem with my hobby OS and I'm at my wits end. I was hoping someone could help me out.

There are two functions involved, one is my memory manager. I'm using a buddy allocator with a minimum block size of 0x1000. I've pseudo coded them so you can get an idea of how they work. My heap starts at 0x40000000 and ends at 0xC0000000

Pseudocode:

Code: Select all

kmalloc(size)
	get block of size 0x1000 from the heap
	return address of block
The second function is map_page, which maps a virtual address to a physical one. Right now all I'm doing is identity mapping from the start of memory to the start of the heap.

Pseudocode:

Code: Select all

map_page(vaddr, paddr, page_directory)
	if (free_frame_at(paddr)
	{
		if (page_directory[page_directory_entry_of(vaddr)] not present)
		{
			addr = kmalloc(size of page table)
			initialize page table to 0 and set to present
			page_directory[page_directory_entry_of(vaddr)].address = addr
		}
			
		page_table = page_directory[page_directory_entry_of(vaddr)].address
		page = page_table[page_table_entry_of(vaddr)]
		
		page.flags = present
		page.addr = paddr
		
		mark_frame_as_used(paddr)
	}
The problem is that I want to alter kmalloc() so that it goes ahead and maps whatever memory you get from it to the kernel page directory. This is proving to be much more difficult than I thought.

My first thought was to do this:

Code: Select all

kmalloc(size)
	addr = get block of size 0x1000 from the heap
	map_page(addr, addr, kernel_page_directory)
	return address of block
But what would happen is:
1. identity map 0x0 to 0x0
2. Since there is no page table present for 0x0, we malloc one
3. Inside of malloc, we get address 0x40000000 and try to map it
4. Since there is no page table present for 0x40000000, we malloc a page table.
5. Malloc gives us 0x40001000 and tries to map it
6. Since there is no page table present for 0x40001000, we malloc a page table.
7. Steps 3-6 continue forever but the malloc address keeps increasing

My next change was so have map_page mark a page table as present before allocating it and unmarking it if malloc fails. So we have this:

Pseudocode:

Code: Select all

map_page(vaddr, paddr, page_directory)
	if (free_frame_at(paddr)
	{
		if (page_directory[page_directory_entry_of(vaddr)] not present)
		{
			set page table to present
			addr = kmalloc(size of page table)
			if (kmalloc didnt work)
				unmark page table and return
			
			initialize page table to 0
			page_directory[page_directory_entry_of(vaddr)].address = addr
		}
			
		page_table = page_directory[page_directory_entry_of(vaddr)].address
		page = page_table[page_table_entry_of(vaddr)]
		
		page.flags = present
		page.addr = paddr
		
		mark_frame_as_used(paddr)
	}
But then I encountered another problem.
1. We map 0x0 to kernel pd
2. No PT for 0x0, malloc
3. malloc gets and maps 0x40000000 to kernel pd
4. No PT for 0x40000000, we set the new pt pointer to whatever malloc returns
5. malloc gets and maps 0x40001000 to kernel pd
6. This succeeds and malloc returns 0x40001000
7. map_page initializes the memory at 0x40001000 to zero, unmapping 0x40001000 from the kernel PD
8. Trying to allocate more memory will cause kmalloc to map another block, so it will try to write to the page table at 0x40001000, which was initialized to zero, so we get a non-present page fault.

Another thought was to have kmalloc initialize all returned memory to zero and remove the initialization to zero from map_page

Code: Select all

kmalloc(size)
	addr = get block of size 0x1000 from the heap
	memset(addr, addr+0x1000, 0)
	map_page(addr, addr, kernel_page_directory)
	return address of block
(map_page is the same but we don't initialize the new page table to zero)

and though this seems like it should fix all of my issues, it is giving me the exact same page fault at 0x40001000 as last time. It seems 0x40001000 is still somehow being overwritten, though it seemingly shouldn't be possible this way.

My final thought was to immediately allocate all needed page tables at the start. That way map_page never needs to call kmalloc at all. However, when I eventually try to implement multitasking this will make every process 4MB in size immediately as I will need to allocate their entire page tables as well. I want to avoid this solution if possible.

Hopefully I've explained this well enough, any help will be greatly appreciated.
haroldmann
Posts: 2
Joined: Fri Oct 18, 2024 11:47 pm

Re: Mapping memory out of kmalloc() to the kernel page directory.

Post by haroldmann »

I'm actually going to try one last thing which is to not bother mapping at all inside of kmalloc() and only map the memory when we encounter a non-present page fault.
Post Reply