Page 1 of 1

VM Problems

Posted: Wed Jan 17, 2007 4:20 pm
by tigerfish
Something is wrong with this code (when I try to allocate a page, it Pagefaults). I don't know what it is. Can anyone fix it, please

[code]
extern unsigned char end;
#define VROFFSET(x) ((unsigned long)x & 0xFFF) // Phys Mem Offset // Lower 12 Bits
#define PTOFFSET(x) (((unsigned long)x & 0x003FF000) >> 12) // PT Offset // Middle 10
#define PDOFFSET(x) (((unsigned long)x & 0xFFC00000) >> 22) // PD Offset // High 10
#define TOVIRT(x) (( (unsigned long)(KeReadCR0() & 0x80000000 )!= 0) ? (unsigned long*)((x) + 0x80000000 ) : ((unsigned long*)(x)))

void KeMapAddress(unsigned long* phys, unsigned long* virt, unsigned long* pagedir, unsigned long flags) {
if(TOVIRT(pagedir)[PDOFFSET(virt)] == 0) {
TOVIRT(pagedir)[PDOFFSET(virt)] = (unsigned long)KeAllocPhysPage() | flags;

}
(TOVIRT(TOVIRT(pagedir)[PDOFFSET(virt)] & ~0xFFF))[PTOFFSET(virt)] = (unsigned long)phys | flags;

}

unsigned long* KeGetPhysAddress(unsigned long *virt, unsigned long* pagedir) {
if(TOVIRT(pagedir)[PDOFFSET(virt)] == 0)
return 0;
else
return (TOVIRT(TOVIRT(pagedir)[PDOFFSET(virt)] & ~0xFFF))[PTOFFSET(virt)] & ~0xFFF;
}



unsigned long* KeMakePageDirectory(unsigned long cpl, unsigned long memsize) {

unsigned long* pagedir = (unsigned long*)KeAllocPhysPage();
unsigned long i;

unsigned long rflags = cpl == 3 ? 5 : 1;
unsigned long rwflags = cpl == 3 ? 7 : 3;


for(i=0;i < ((unsigned long)&end / 4096 + 1) * 4096; i+= 4096) {
KeMapAddress((unsigned long*)i,(unsigned long*)i,pagedir,rwflags) ;
}
for(i=0;i < memsize && i < 0x80000000; i+= 4096) {
KeMapAddress((unsigned long*)i,(unsigned long*)i + 0x80000000,pagedir,rwflags) ; // Map first 2GB of memory into
// 80000000 area
}

return pagedir;
}

unsigned long* KeAllocPage(unsigned long* pagedir) {
if((unsigned long)pagedir == 0)
pagedir = (unsigned long*)KeReadCR3();
printf("%u",KeReadCR0() & 0x80000000 == 0);


unsigned char* curr = (unsigned char*)0x70000000;

while((((unsigned long)KeGetPhysAddress((unsigned long*)curr,pagedir)) & 1) == 0 && (unsigned long)curr < 0xE0000000)
curr += 4096;
if((unsigned long)curr == 0x80000000)
{
return 0;
}
else {
KeMapAddress(KeAllocPhysPage(),(unsigned long*)curr,pagedir, ((KeGetEFlags() & 0x3000) == 0) ? 3 : 7);
KeWriteCR3(pagedir); // Invalidates Page Directories
return (unsigned long*)curr;
}
}

void KeInitPaging(multiboot_info_t* info)
{
KeInitPhysPageMM(info->mem_lower + info->mem_upper);
unsigned long *pagedirectory=KeMakePageDirectory(0,info->mem_lower + info->mem_upper);



KeWriteCR3((unsigned long)pagedirectory);
KeWriteCR0(KeReadCR0() | 0x80000000);
}

[/code]

Posted: Wed Jan 17, 2007 11:14 pm
by fontknocker
Hi,

One thing I found very helpful when writing my memory manager was to set up a temporary handler for INT14 (Page Fault). Every time a page fault occurred I would dump CR2 to find the offending address and then dump the interrupt error code to work out what caused the page fault (instruction fetch failed, reserved bit set, non-mapped page, etc). Once everything worked, I removed the temporary handler. Worked like a charm.

That might help you work out why it page faults.

Posted: Fri Jan 19, 2007 4:31 pm
by tigerfish
I fixed up the code in the VM. Look Better?

Code: Select all

#include "krnl.h"
#include "mltiboot.h"
#include "paging.h"
#include "cstdlib.h"
#include "physmemmanager.h"



extern unsigned char end;
#define VROFFSET(x) ((unsigned long)x & 0xFFF) // Phys Mem Offset // Lower 12 Bits
#define PTOFFSET(x) (((unsigned long)x & 0x003FF000) >> 12) // PT Offset  // Middle 10
#define PDOFFSET(x) (((unsigned long)x & 0xFFC00000) >> 22) // PD Offset  // High 10
//#define TOVIRT(x) (( (unsigned long)(KeReadCR0() & 0x80000000 )!= 0) ?  (unsigned long*)((x) + 0x80000000 ) : ((unsigned long*)(x)))

unsigned long* TOVIRT(unsigned long x) {
	if( (KeReadCR0() & 0x80000000) != 0) {

		return (unsigned long*) (x + 0x80000000);
	} else
		return (unsigned long*)x;
}

void KeMapAddress(unsigned long* phys, unsigned long* virt, unsigned long* pagedir, unsigned long flags) {
	unsigned long* pagedir_v = TOVIRT(pagedir);
	if(pagedir_v[PDOFFSET(virt)] == 0) {
		pagedir_v[PDOFFSET(virt)] = (unsigned long)KeAllocPhysPage() | flags;
	

	}
	unsigned long* pagetable_v = TOVIRT( (pagedir_v[PDOFFSET(virt)]) & ~0xFFF );
	pagetable_v[PTOFFSET(virt)] = (unsigned long)phys | flags;

}

unsigned long KeGetVirtFlags(unsigned long *virt, unsigned long* pagedir) {
	unsigned long* pagedir_v = TOVIRT(pagedir);
	if(pagedir_v[PDOFFSET(virt)] == 0)
		return 0;
	else{
	
			unsigned long* pagetable_v = TOVIRT( (pagedir_v[PDOFFSET(virt)]) & ~0xFFF );
			return pagetable_v[PTOFFSET(virt)];
	}
}

unsigned long* KeGetPhysAddress(unsigned long *virt, unsigned long* pagedir) {
	return KeGetVirtFlags(virt,pagedir) & ~0xFFF;
}
	


unsigned long* KeMakePageDirectory(unsigned long cpl, unsigned long memsize)  {

	unsigned long* pagedir = (unsigned long*)KeAllocPhysPage();
	unsigned long i;

	unsigned long rflags = cpl == 3 ?  5 : 1;
	unsigned long rwflags = cpl == 3 ? 7 : 3;


	for(i=0;i < ((unsigned long)&end / 4096 + 1) * 4096; i+= 4096) {
		KeMapAddress((unsigned long*)i,(unsigned long*)i,pagedir,rwflags) ;
	}
	for(i=0;i < memsize && i < 0x80000000; i+= 4096) {
		KeMapAddress((unsigned long*)i,(unsigned long*)(i + 0x80000000),pagedir,rwflags) ; // Map first 2GB of memory into
		//	80000000 area
	}

	return pagedir;
}
	
unsigned long* KeAllocPage(unsigned long* pagedir) {
	if((unsigned long)pagedir == 0)
		pagedir = (unsigned long*)KeReadCR3();



	unsigned long curr = 0x70000000;
	
	while(KeGetVirtFlags((unsigned long*)curr,pagedir) != 0 && (unsigned long)curr < 0x80000000)
		curr += 4096;
	if(curr >= 0x80000000)
		return 0;
	else {
		KeMapAddress(KeAllocPhysPage(),(unsigned long*)curr,pagedir,  7);
		KeWriteCR3(pagedir); // Invalidates Page Directories
		return (unsigned long*)curr;
	}
}

void KeFreePage(unsigned long* page, unsigned long* pagedir) {
	unsigned long page_manip = (unsigned long)page;
	if(page_mainp % 4096 != 0)
		return;
	if((unsigned long)pagedir == 0)
		pagedir = (unsigned long*)KeReadCR3();

	KeMapAddress(0,page,pagedir,0);
	KeWriteCR3(pagedir);
}


void KeInitPaging(multiboot_info_t* info)
{
	KeInitPhysPageMM(1024 * (info->mem_lower + info->mem_upper));
	unsigned long *pagedirectory=KeMakePageDirectory(0,1024 * (info->mem_lower + info->mem_upper));


	
	KeWriteCR3((unsigned long)pagedirectory);
	KeWriteCR0(KeReadCR0() | 0x80000000);
}	

Posted: Fri Jan 19, 2007 4:58 pm
by tigerfish
I fixed up the code in the VM. Look Better?

Code: Select all

#include "krnl.h"
#include "mltiboot.h"
#include "paging.h"
#include "cstdlib.h"
#include "physmemmanager.h"



extern unsigned char end;
#define VROFFSET(x) ((unsigned long)x & 0xFFF) // Phys Mem Offset // Lower 12 Bits
#define PTOFFSET(x) (((unsigned long)x & 0x003FF000) >> 12) // PT Offset  // Middle 10
#define PDOFFSET(x) (((unsigned long)x & 0xFFC00000) >> 22) // PD Offset  // High 10
//#define TOVIRT(x) (( (unsigned long)(KeReadCR0() & 0x80000000 )!= 0) ?  (unsigned long*)((x) + 0x80000000 ) : ((unsigned long*)(x)))

unsigned long* TOVIRT(unsigned long x) {
	if( (KeReadCR0() & 0x80000000) != 0) {

		return (unsigned long*) (x + 0x80000000);
	} else
		return (unsigned long*)x;
}

void KeMapAddress(unsigned long* phys, unsigned long* virt, unsigned long* pagedir, unsigned long flags) {
	unsigned long* pagedir_v = TOVIRT(pagedir);
	if(pagedir_v[PDOFFSET(virt)] == 0) {
		pagedir_v[PDOFFSET(virt)] = (unsigned long)KeAllocPhysPage() | flags;
	

	}
	unsigned long* pagetable_v = TOVIRT( (pagedir_v[PDOFFSET(virt)]) & ~0xFFF );
	pagetable_v[PTOFFSET(virt)] = (unsigned long)phys | flags;

}

unsigned long KeGetVirtFlags(unsigned long *virt, unsigned long* pagedir) {
	unsigned long* pagedir_v = TOVIRT(pagedir);
	if(pagedir_v[PDOFFSET(virt)] == 0)
		return 0;
	else{
	
			unsigned long* pagetable_v = TOVIRT( (pagedir_v[PDOFFSET(virt)]) & ~0xFFF );
			return pagetable_v[PTOFFSET(virt)];
	}
}

unsigned long* KeGetPhysAddress(unsigned long *virt, unsigned long* pagedir) {
	return KeGetVirtFlags(virt,pagedir) & ~0xFFF;
}
	


unsigned long* KeMakePageDirectory(unsigned long cpl, unsigned long memsize)  {

	unsigned long* pagedir = (unsigned long*)KeAllocPhysPage();
	unsigned long i;

	unsigned long rflags = cpl == 3 ?  5 : 1;
	unsigned long rwflags = cpl == 3 ? 7 : 3;


	for(i=0;i < ((unsigned long)&end / 4096 + 1) * 4096; i+= 4096) {
		KeMapAddress((unsigned long*)i,(unsigned long*)i,pagedir,rwflags) ;
	}
	for(i=0;i < memsize && i < 0x80000000; i+= 4096) {
		KeMapAddress((unsigned long*)i,(unsigned long*)(i + 0x80000000),pagedir,rwflags) ; // Map first 2GB of memory into
		//	80000000 area
	}

	return pagedir;
}
	
unsigned long* KeAllocPage(unsigned long* pagedir) {
	if((unsigned long)pagedir == 0)
		pagedir = (unsigned long*)KeReadCR3();



	unsigned long curr = 0x70000000;
	
	while(KeGetVirtFlags((unsigned long*)curr,pagedir) != 0 && (unsigned long)curr < 0x80000000)
		curr += 4096;
	if(curr >= 0x80000000)
		return 0;
	else {
		KeMapAddress(KeAllocPhysPage(),(unsigned long*)curr,pagedir,  7);
		KeWriteCR3(pagedir); // Invalidates Page Directories
		return (unsigned long*)curr;
	}
}

void KeFreePage(unsigned long* page, unsigned long* pagedir) {
	unsigned long page_manip = (unsigned long)page;
	if(page_mainp % 4096 != 0)
		return;
	if((unsigned long)pagedir == 0)
		pagedir = (unsigned long*)KeReadCR3();

	KeMapAddress(0,page,pagedir,0);
	KeWriteCR3(pagedir);
}


void KeInitPaging(multiboot_info_t* info)
{
	KeInitPhysPageMM(1024 * (info->mem_lower + info->mem_upper));
	unsigned long *pagedirectory=KeMakePageDirectory(0,1024 * (info->mem_lower + info->mem_upper));


	
	KeWriteCR3((unsigned long)pagedirectory);
	KeWriteCR0(KeReadCR0() | 0x80000000);
}