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]
VM Problems
- fontknocker
- Posts: 16
- Joined: Mon Dec 11, 2006 1:49 am
- Location: Canberra, Australia
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.
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.
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);
}
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);
}