Problems enabling paging (added questions)

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
User avatar
eino
Member
Member
Posts: 49
Joined: Fri Sep 16, 2011 10:00 am
Location: Finland

Problems enabling paging (added questions)

Post by eino »

Hi. Having troubles with enabling paging. I actually got one version working taken from a tutorial, but I ofcourse want to do it differently (thou this idea is propably widely used)

Anyways. Qemu freezes and once even paniced the host machine just when i 'boot' with grub.

Here's the code (it's actually splitted in couple of files ofcourse)

Code: Select all

typedef struct page
{
	
	unsigned int	present				: 1;
	unsigned int	rw					: 1;
	unsigned int	user_super			: 1;
	unsigned int	write_through		: 1;
	unsigned int	cache_disabled		: 1;
	unsigned int	accessed			: 1;
	unsigned int	zero				: 1;
	unsigned int	page_size			: 1;
	unsigned int	ignored				: 1;
	unsigned int	available			: 3;
	unsigned int	physical			: 20;
	
} t_page;

typedef struct page_table
{
	t_page			pages[1024];
	
} t_ptable;

typedef struct page_directory
{
	t_ptable		*tables[1024];
	unsigned int	tables_physical[1024];
	unsigned int	self_physical_address;
	
} t_pd;

t_pd *page_directory;

unsigned int kernel_malloc ( unsigned int amount ) {
	
	// always preserve page alignment
	if ( current_memory_placement & 0xFFFFF000 ) {
		current_memory_placement &= 0xFFFFF000;
		current_memory_placement += 0x1000;
	}
	
	unsigned int malloced = current_memory_placement;
	current_memory_placement += amount;
	return malloced;
	
}

void installPageDirectory () {
	
	current_memory_placement = 0;
	
	while ( current_memory_placement < &kernel_end ) {
		current_memory_placement = current_memory_placement + 0x1000;
	}
	
	current_memory_placement &= 0xFFFFF000;
	current_memory_placement += 0x1000;
	
	page_directory = (t_pd*)kernel_malloc(sizeof(t_pd));
	
	int i = 0;
	
	for( i = 0; i < 1024; i++ ) {
		
		t_ptable *page_table;
		page_table = (t_ptable*)kernel_malloc(sizeof(t_ptable));
		page_directory->tables[i] = page_table;
		
	}

}

/*copied from tutorial*/
void enablePaging () {
	//moves page_directory (which is a pointer) into the cr3 register.
	asm volatile("mov %0, %%cr3":: "b"(page_directory));
	
	//reads cr0, switches the "paging enable" bit, and writes it back.
	unsigned int cr0;
	asm volatile("mov %%cr0, %0": "=b"(cr0));
	cr0 |= 0x80000000;
	asm volatile("mov %0, %%cr0":: "b"(cr0));
}
Any ideas? I really want to write this myself instead of doing some copy paste.

edit:
crash happens when:

Code: Select all

cr0 |= 0x80000000;
asm volatile("mov %0, %%cr0":: "b"(cr0));
Last edited by eino on Sat Nov 26, 2011 10:35 am, edited 1 time in total.
I'm Eino Tuominen from Finland, a web software dev learning low level stuff and reading / trying out kernel dev
User avatar
Nessphoro
Member
Member
Posts: 308
Joined: Sat Apr 30, 2011 12:50 am

Re: Problems enabling paging

Post by Nessphoro »

You're passing the wrong thing into CR3. You need to the pass physical address of tables physical not the kernel structure
User avatar
eino
Member
Member
Posts: 49
Joined: Fri Sep 16, 2011 10:00 am
Location: Finland

Re: Problems enabling paging (added questions)

Post by eino »

Hi again. I've been reading quite alot about all of this now but there are just some blank holes I don't get about Paging, framing allocating etc.

Firstly when page directory and page tables are installed is the structure like this:

page directory
page table 1
page table 2
page table n
pages for table 1
pages for table 2
pages for table n

or

page directory
page table 1
pages for table 1
page table 2
pages for table 2
page table n
pages for table n

?


Also I'm quite lost with how to assign frame to a page. Bits 31 to 12 seems to hold the very physical address of a the "start of a frame" in physical memory. For instance 0 or 4096 and the rest of the bits are for the different flags. Now I've been trying to create an array that holds the addresses for every frame available. Lets say we have 16 megs of memory

Code: Select all

unsigned int frames[4096];			//addresses to physical frames
unsigned int number_of_frames;

number_of_frames = 0x1000000 / 0x1000;
	
unsigned int used_frames_count = 0;

unsigned int l = 1;
unsigned int next_addr = 0;
unsigned int counter = 0;
char tmp33;
unsigned int *memptr;

print_string ( "Used frames: " );

for ( l = 0; l < number_of_frames; l++ ) {
	frames[l] = next_addr;
	
	for ( counter = 0; counter < 0x1000; counter++ ) { //roll through the entire frame to see if it is empty or is it being used already by the loaded kernel or other stuff in memory... bios maymbe?
		memptr = frames[l] + counter;
		if ( *memptr != 0) {  // the * in front of a pointer is a "load" (?) that gives me the value at that memory location, right?
			used_frames_count++;
			einos_itoa ( tmp33,  l );
			print_string ( tmp33 );
			print_string ( "," );
			break;
		}
	
	}
	
	next_addr = next_addr + 0x1000;  //advance to the next frame
}
This ofcourse is no way near optimized to be fast but until I get this thing I like to keep this simple stupid.

Now when I want to assign a frame for a page I do something like this:

Code: Select all

unsigned int page = physical_address_of_frame << 12;
and then set the lower bits to the correct flags with some other code?

Now this page needs to be put to a page table? Or is the correct way to get 1024 new pages when ever a new page table is created?

Do I keep track of used frames in an array of structs maybe or do I set some bit on the physical memory for a frame (a header of some sort)?

Would it be any idea to start allocating frames beginning from 16 meg (after the 15meg hole…)?

Before paging is enabled should I move anything that is alreayd in memory to pages or just leave untouched?


Thank you so much in advance!
I'm Eino Tuominen from Finland, a web software dev learning low level stuff and reading / trying out kernel dev
User avatar
eryjus
Member
Member
Posts: 286
Joined: Fri Oct 21, 2011 9:47 pm
Libera.chat IRC: eryjus
Location: Tustin, CA USA

Re: Problems enabling paging (added questions)

Post by eryjus »

eino,

I know the tutorial. I had trouble as well. I do have a couple of comments:
  • You are allocating memory for 1024 page tables, but not initializing them. You may not need to allocate the page tables right away, depending on your needs (which is what the tutorial does).
  • I also believe there to be a bug in the malloc code (even from the tutorial). My version of the malloc code is offered below.

Code: Select all

#include "kernel.h"

extern uint32 end;

uint32 placeAddr = (uint32)(&end);

uint32 _kmalloc (uint32 sz, int16 align, uint32 * phys)
{
	if (0 != kheap) {
		void *addr = Alloc(sz, (uint8)align, kheap);
		
		if (0 != phys) {
			Page *page = GetPage((uint32)addr, 0, kernelDirectory);
			*phys = page->frame * 0x1000 + ((uint32)addr & 0x0fff);
		}
		
		return (uint32)addr;
	} else {
		if (1 == align && (placeAddr & 0x00000fff)) {
			placeAddr &= 0xfffff000;
			placeAddr += 0x1000;
		}

		if (phys) *phys = placeAddr;

		uint32 tmp = placeAddr;
		placeAddr += sz;
  
		return tmp;
	}
}
Please notice this block of code:

Code: Select all

		if (1 == align && (placeAddr & 0x00000fff)) {
			placeAddr &= 0xfffff000;
			placeAddr += 0x1000;
		}
A non page-aligned address will have a 1 in bits 0-11. Therefore, I have changed the comparison to check for these bits. Though the code from the tutorial will technically work, it "wastes" memory.

You may also want to review Intel's Software Developer's Manual.
Adam

The name is fitting: Century Hobby OS -- At this rate, it's gonna take me that long!
Read about my mistakes and missteps with this iteration: Journal

"Sometimes things just don't make sense until you figure them out." -- Phil Stahlheber
User avatar
eino
Member
Member
Posts: 49
Joined: Fri Sep 16, 2011 10:00 am
Location: Finland

Re: Problems enabling paging (added questions)

Post by eino »

Hi again.

As instructed I did read a couple of manuals over again (including the intel doc) and a few new ones too and I believe my paging is now working for the parts that are implemented:

- Physical allocator (allocates 4096kb frames and handles a bitmap of free/reserved frames)
- Paging init ( creates a page directory for the kernel, a PDE and 1024 PTE's also maps the 1024th PDE to 1st PDE
(does this look anywhere near a correct way? At least without this I get a page fault)

Code: Select all

page_directory[1023] = ( page_directory[0] & 0xFFFFF000 ) | 3;
- A function to get the PDE and PTE indexes from a virtual address
- Page mapping. Takes in a physical address (given by the phys allocator) and a desired virtual address)
- Getter for a physical address. Takes in the virtual address.

I have run a few tests with this where I allocate two pages to the same physical address, output test results, change the value/contents of one of the pages and check that the value in the other page changes too. All seems to be working as expected on QEMU and on real Intel Hardware.

Most of the code I wrote myself, some parts I copied from tutorials.


But questions arise:
- I haven't made any kind of identity mapping... How come even after enabling paging all my print_string functions that deal directly with video memory can work in anyway? I'm a bit confused with this one cause if all memory access goes through the MMU then how is it possible that this works...

- I enable paging after installing GDT, IDT, IRQ & ISR routines. Is this the prefered way or should I enable paging immediately when entering my kmain() ?


Thanks again. Hopefully I'm not asking anything too obvious again. But if the RTFM is coming at me, just keep it coming :wink:
I'm Eino Tuominen from Finland, a web software dev learning low level stuff and reading / trying out kernel dev
User avatar
Nessphoro
Member
Member
Posts: 308
Joined: Sat Apr 30, 2011 12:50 am

Re: Problems enabling paging (added questions)

Post by Nessphoro »

I hate doing it that way. You lose 256 MB of addressable space.
I'd do it as it suggests in JamesM's kernel development tutorials. Which only adds 4kb overhead
User avatar
neon
Member
Member
Posts: 1567
Joined: Sun Feb 18, 2007 7:28 pm
Contact:

Re: Problems enabling paging (added questions)

Post by neon »

Hello,
I haven't made any kind of identity mapping... How come even after enabling paging all my print_string functions that deal directly with video memory can work in anyway?
You might need to invalidate the pages in the TLB (INVLPG instruction). Some instructions may also flush the entire buffer as well.
I enable paging after installing GDT, IDT, IRQ & ISR routines. Is this the prefered way or should I enable paging immediately when entering my kmain()
The preferred way would be to enable paging as early as possible. If your ISR routines may require memory management functionality (as is most cases) then paging should be enabled before IRQs are enabled. It can be after or before GDT and IDT, however... really depends on what you design is.
OS Development Series | Wiki | os | ncc
char c[2]={"\x90\xC3"};int main(){void(*f)()=(void(__cdecl*)(void))(void*)&c;f();}
Post Reply