Paging triplefaults real computer
Posted: Fri Aug 19, 2005 9:42 pm
I had said, hurrah, hurrah, I've got paging working. The physical memory manager works (on a real machine, too), page table and directory are filled correctly, IRQs were disabled, paging was set and the segments changed after the IDT is set with the new code segment, IRQs are reenabled. Identity mapping is used at the correct times. Yay. Except that when I put this thing on a real computer it triplefaults.
BootstrapIDT() and BootstrapIRQs() merely reset the IDT with the new code segment, and other than that every function does what it says. This all works fine on Bochs, but on a real machine it triplefaults somewhere during this function.
Code: Select all
function BootstrapKernelPaging(): integer;
var
i: integer;
begin
{Set result to the default error code.}
BootstrapKernelPaging:= -1;
pPageDirectory:= nil;
{Get a page to be page directory.}
i:= AllocatePage();
if i > 0 then
pPageDirectory:= PLongword(Longword(i * 4096 - Longword(@SegmentationVirtualBase)))
else
begin
{Set the page directory pointer to nil. IMPORTANT.}
pPageDirectory:= nil;
Write(PChar('AllocatePage for the page directory failed with error '));
WriteIntLn(i);
{-2 means the page directory couldn't be allocated.}
BootstrapKernelPaging:= -2;
Exit;
end;
{This is equivalent to pPageDirectory[all]:= SetPageEntry(0,false,false,false).}
FillDWord(pPageDirectory^,1024,0);
{Get another page to be the first page table.}
i:= AllocatePage();
if i > 0 then
pPageTable:= PLongword(Longword(i * 4096 - Longword(@SegmentationVirtualBase)))
else
begin
{Free the page directory. VERY IMPORTANT.}
FreePage(Longword(pPageDirectory) div 4096);
{Set the page directory pointer to nil. IMPORTANT.}
pPageDirectory:= nil;
Write(PChar('AllocatePage for the first page table failed with error '));
WriteIntLn(i);
{-3 means the first page table couldn't be allocated.}
BootstrapKernelPaging:= -3;
Exit;
end;
{This is equivalent to pPageTable[all]:= SetPageEntry(0,false,false,false).}
FillDWord(pPageTable^,1024,0);
{Set every page in the first page table to supervisor, writable and present.}
{This will map the first 4 MB of memory to its place.}
{For now it is assumed that 4 MB is enough to map the entire kernel area.}
i:= KernelZoneEnd + Longword(@SegmentationVirtualBase);
{Map video memory.}
pPageTable[$B8]:= SetPageEntry(Pointer($B8000),false,true,true);
{Address $100 = $100000 div $1000 (page). The kernel's load point is the first page to get mapped.}
{BIOS and such aren't mapped because they break at the high addresses.}
for i:= $100 to (i div 4096) - 1 do
pPageTable[i]:= SetPageEntry(Pointer(i * 4096),false,true,true);
{Map the page table and page directory to new locations since they were allocated dynamically.}
{These new locations will allow for planning of page table/directory and kernel heap locations.}
i:= KernelZoneEnd + (4096 - (KernelZoneEnd mod 4096)) + Longword(@SegmentationVirtualBase);
pPageTable[i div 4096]:= SetPageEntry(Pointer(i),false,true,true);
i:= i + 4096;
pPageTable[i div 4096]:= SetPageEntry(Pointer(i),false,true,true);
{Map that page table to virtual address $C0000000.}
i:= Longword(pPageTable) + Longword(@SegmentationVirtualBase);
{Address $300 = $C0000000 div 4096 (page) div 1024 (superpage) and superpage = page directory entry.}
pPageDirectory[$300]:= SetPageEntry(Pointer(i),false,true,true);
{Identity map the page table. This keeps the kernel from crashing before the segment base can be changed.}
pPageDirectory[0]:= SetPageEntry(Pointer(i),false,true,true);
{Put the address of the page directory into the proper CPU register.}
i:= Longword(pPageDirectory) + Longword(@SegmentationVirtualBase);
SetPageDirectory(Pointer(i));
{If an IRQ fires while paging is on but before the IDT is refilled with exceptions and IRQ handlers there will be a triplefault, so disable IRQs.}
DisableInterrupts();
{Enable paging. DANGEROUS.}
SetPaging(true);
{With paging enabled set these variables to their new virtual addresses.}
pPageDirectory:= PLongword(KernelZoneEnd + Longword(4096 - (KernelZoneEnd mod 4096)));
pPageTable:= pPageDirectory + 1024;
{The exceptions and IRQs in the IDT need to be bootstrapped for paging.}
BootstrapIDT($20);
BootstrapIRQs($20);
{Now that everything knows what the new environment is, switch the segment registers.}
SetSegmentRegisters($18,$20);
{Now that everything knows the new environment, reenable IRQs.}
EnableInterrupts();
{Now that the segments are changed there is no more need for identity mapping.}
{The page directory and page table must be mapped in their higher half places correctly for this assignment to work.}
pPageDirectory[0]:= 0;
WriteLn(PChar('Kernel now paged to virtual address $C010000.'));
BootstrapKernelPaging:= 1;
end;