Persistent paging/multitasking problem
Posted: Fri Feb 27, 2009 6:59 am
Hello,
For quite some time I've been having this problem now. At first I presumed it was my heap, which was coded quickly and not all too well. But now, after fully rewriting my kernel, I still have the same problem; as soon as I copy a page directory (to keep the kernel one consistent so I can enable multitasking later) and switch to that copy, my kernel triple faults (Bochs reports 3rd exception (14) with no resolution). I've checked my code over and over again, but it still doesn't work. I'm also using JamesM's tuts as a guide (I'm using the downloadable, mostly fixed, source-code instead of the on-site code). So I was hoping someone can stop some error somewhere that causes this strange issue.
Here's the code for respectively the CopyPhysicalFrame, ClonePageTable and ClonePageDirectory functions:
And last, but not least, my function that initializes paging.
As you can see in the code, the very last line is causing the triple fault. I've tried about everything; numerous times of running over the code, replacing my code with JamesM's code, but nothing seems to work. I am using C++ in my kernel, which shouldn't be a problem, but maybe it's somehow interfering?
Thanks for your time and effort,
Creature
For quite some time I've been having this problem now. At first I presumed it was my heap, which was coded quickly and not all too well. But now, after fully rewriting my kernel, I still have the same problem; as soon as I copy a page directory (to keep the kernel one consistent so I can enable multitasking later) and switch to that copy, my kernel triple faults (Bochs reports 3rd exception (14) with no resolution). I've checked my code over and over again, but it still doesn't work. I'm also using JamesM's tuts as a guide (I'm using the downloadable, mostly fixed, source-code instead of the on-site code). So I was hoping someone can stop some error somewhere that causes this strange issue.
Here's the code for respectively the CopyPhysicalFrame, ClonePageTable and ClonePageDirectory functions:
Code: Select all
; ========================================
; CopyPhysicalPage
; - Copies the contents of the source page frame address
; to the destination page frame address.
; ========================================
[GLOBAL CopyPhysicalPage]
CopyPhysicalPage:
push ebx ; Save the contents of EBX.
pushf ; Push common registers (including EFLAGS, to re-enable interrupts).
cli ; Disable interrupts.
mov ebx, [ESP + 12] ; Grab source address (sourceAddress).
mov ecx, [ESP + 16] ; Grab destination address (destAddress).
mov edx, CR0 ; |
and edx, 0x7FFFFFFF ; |> Use CR0 to disable paging.
mov CR0, edx ; |
mov edx, 1024 ; Make sure the loop runs 1024 times (using 4 bytes each time = 4096 bytes = 0x1000 bytes).
.Loop:
mov eax, [EBX] ; Grab 16-bits from the source address.
mov [ECX], eax ; Put it in the 16-bits from the destination address.
add ebx, 4 ; Increment the source address with sizeof(dword)
add ecx, 4 ; Increment the destination address with sizeof(dword)
dec edx ; Decrement edx (used by the loop).
jnz .Loop ; If edx is not zero yet, start back at '.Loop:'.
mov edx, CR0 ; |
or edx, 0x80000000 ; |> Use CR0 to enable paging again.
mov CR0, edx ; |
popf ; Pop common registers (including EFLAGS, to re-enable interrupts).
pop ebx ; Pop ebx (pushed in the beginning).
ret ; All done!
Code: Select all
/*
* ClonePageTable
* Clones the specified page table.
*/
static PageTable *ClonePageTable(PageTable *source, unsigned *physAddr)
{
/* Create a new page table (page-aligned). */
PageTable *Ret = (PageTable *) MM->AllocAlignGetPhys(sizeof(PageTable), physAddr);
MM->Set(Ret, 0, sizeof(PageTable));//For some reason, JamesM uses sizeof(PageDir) here.
for(int i(0); i < 1024; ++i)
{
/* If there is a frame address available. */
if(source->PageArray[i].FrameAddress)
{
/* Create a new frame, clone the flags and physically copy the data. */
AllocateFrame(&Ret->PageArray[i], false, false);
/*
* Use these if-statements because if a field should be clear,
* it must not have been written to. So only write if necessary.
*/
if(source->PageArray[i].Present) Ret->PageArray[i].Present = 1;
if(source->PageArray[i].ReadWrite) Ret->PageArray[i].ReadWrite = 1;
if(source->PageArray[i].UserMode) Ret->PageArray[i].UserMode = 1;
if(source->PageArray[i].Accessed) Ret->PageArray[i].Accessed = 1;
if(source->PageArray[i].Dirty) Ret->PageArray[i].Dirty = 1;
CopyPhysicalPage(source->PageArray[i].FrameAddress * HEAP_PAGESIZE, Ret->PageArray[i].FrameAddress * HEAP_PAGESIZE);
}
}
return Ret;
}
Code: Select all
/*
* ClonePageDir
* Clones the specified paging directory.
*/
PageDir *ClonePageDir(PageDir *source)
{
unsigned PhysAddr;
/* Create a new page directory (page-aligned). */
PageDir *Ret = (PageDir *) MM->AllocAlignGetPhys(sizeof(PageDir), &PhysAddr);
MM->Set(Ret, 0, sizeof(PageDir));
/* Grab the offset of 'TablesPhys' starting from the paging directory. */
unsigned Offset = (unsigned) Ret->TablesPhys - (unsigned) Ret;
/* This is the physical address of the tables. */
Ret->Address = (PhysAddr + Offset);
/*
* Search for the page table in the kernel directory, if
* it is already there, it does not need to be copied.
*/
for(int i(0); i < 1024; ++i)
{
/* Null pointer? Skip. */
if(!source->PageTables[i])
continue;
/* Does the entry already exist in the kernel directory? */
if(KernelDir->PageTables[i] == source->PageTables[i])
{
/* Point to that table. */
Ret->PageTables[i] = source->PageTables[i];
Ret->TablesPhys[i] = source->TablesPhys[i];
}
else
{
/* It isn't, copy the table. */
unsigned PhysAddress;
Ret->PageTables[i] = ClonePageTable(source->PageTables[i], &PhysAddress);
Ret->TablesPhys[i] = PhysAddress | 0x07; /* 0x07 = Present, Read-Write and User-mode. */
}
}
return Ret;
}
Code: Select all
/*
* InitPaging
* Initializes paging.
*/
void InitPaging()
{
/* Physical memory size, GRUB detects this in kB, we need bytes. */
size_t MemSize = GRUB->HigherMem * 1024;
FrameCount = MemSize / HEAP_PAGESIZE;
Frames = (unsigned *) MM->Alloc(GET_ID_FROM_BIT(FrameCount));
MM->Set(Frames, 0, GET_ID_FROM_BIT(FrameCount));
/* Make a page directory. */
//James also puts an 'unsigned phys' variable here which is never used?
KernelDir = (PageDir *) MM->AllocAlign(sizeof(PageDir));
MM->Set(KernelDir, 0, sizeof(PageDir));
KernelDir->Address = (unsigned) KernelDir->TablesPhys;
//CurrentDir = KernelDir;
unsigned i;
/* Map kernel heap pages, creating them if necessary. */
for(i = HEAP_START; i < HEAP_START + HEAP_STARTSIZE; i += HEAP_PAGESIZE)
GetPage(i, true, KernelDir);
i = 0;
/* Identity map. */
while(i < CurAddress + HEAP_PAGESIZE)
{
AllocateFrame(GetPage(i, true, KernelDir), false, false);
i += HEAP_PAGESIZE;
}
/* Allocate previously mapped pages (now that everything is identity mapped). */
for(i = HEAP_START; i < HEAP_START + HEAP_STARTSIZE; i += HEAP_PAGESIZE)
AllocateFrame(GetPage(i, true, KernelDir), false, false);
/* Switch page directories and enable paging. */
SwitchPageDir(KernelDir);
/* Create the kernel heap. */
KernelHeap = CreateHeap(HEAP_START, HEAP_START + HEAP_STARTSIZE, 0xCFFFF000, false, false);
/* Clone the kernel directory, so it can remain constant. Then switch to the cloned directory. */
CurrentDir = ClonePageDir(KernelDir);
SwitchPageDir(CurrentDir); //<--- This is what causes the crash.
}
Thanks for your time and effort,
Creature