Maybe something wrong with the BonaFide paging tutorial

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.
OSMAN

Maybe something wrong with the BonaFide paging tutorial

Post by OSMAN »

Hi,
I've tried to use the only simple paging enabling principle that's at Bona Fide. I've tried to change the physical memory values to anywhere outside the kernel, but always when write_cr3(page_directory) is executed, Bochs tells me the execution has become into "bogus memory". And it hangs.

Please, tell me whether these should be something else they seem to be:
CR0=0xe0000011 CR1=0x00000000 CR2=0x00000000
CR3=0x00200000 CR4=0x00000000
And my kernel is defined in linkerscript to be at 0x100000 and it is about 0xA410 bytes large there onwards.
YeXo

Re:Maybe something wrong with the BonaFide paging tutorial

Post by YeXo »

Since you don't seem to be writing a higher half kernel , you have to identety map the first four mb. That is, make sure everywhere in the first 4mb virtual address=physical address.
OSMAN

Re:Maybe something wrong with the BonaFide paging tutorial

Post by OSMAN »

My everything is physical so far (yet). I'm getting really confused about this since I've tried to solve the problem of few lines of code for about five hours now. And what I've found out, is that it becomes "running in bogus memory" when I enable the paging bit of CR0.

My kernel is loaded at 0x100 000, the kernel is 40.5 kb large, and I use the same values that are given in the BonaFide's tutorial, except I've tried to put the page directory pointer and the page table pointer anywhere so far, but Bochs always claims its running in bogus memory when I enable the bit!

Could you tell me better what might be going on if you knew, for me to save some -- maybe -- vain time?
mystran

Re:Maybe something wrong with the BonaFide paging tutorial

Post by mystran »

You need to (in order):

1. Construct a page directory, where you have the area where your kernel is "identity mapped" which means virtual == physical. Also make sure you set the pages present (or you'll get a fault).

2. Set CR3 to that page directory (physical address, ofcourse).

3. Enable paging.

Once you enable paging, you must already have a good value in CR3. Otherwise it'll start doing funny things.
raywill

Re:Maybe something wrong with the BonaFide paging tutorial

Post by raywill »

It seems that beginners always have the problem in understanding "identity-mapping".
Maybe we need to emphasize this in Wiki and give more explanation.
OSMAN

Re:Maybe something wrong with the BonaFide paging tutorial

Post by OSMAN »

I probed my disassembly and everything; and this is what I can claim:
the EIP points at the following instruction for setting paging bit to 1.
Hey, but I noticed here: how do I know whether that command exists at that address anymore -- I think it does physically -- but I don't know whether the final address is that as it now goes -- I think -- through MMU.

I think I've realized the principle from your talks. Could you tell me does the Bochs terminal show the real value -- the on gone through MMU -- of the EIP in the terminal when the emulation session ends?

PS. I want it not to be "running in bogus memory :)"
bkilgore

Re:Maybe something wrong with the BonaFide paging tutorial

Post by bkilgore »

Here's a short explanation of what he means by "identity mapping" and why you need to do it.

Here I'll use an example block of code from the disassembly of my kernel where paging is enabled:

Code: Select all

c0001519:       0f 20 c0                mov    %cr0,%eax
c000151c:       0d 00 00 01 c0          or     $0xc0010000,%eax
c0001521:       0f 22 c0                mov    %eax,%cr0
c0001524:       eb 00                   jmp    c0001526 <paging_enabled>

c0001526 <paging_enabled>:
c0001526:       b8 2d 15 00 c0          mov    $0xc000152d,%eax
c000152b:       ff e0                   jmp    *%eax

c000152d <virtual_addresses_enabled>:
So when the computer get's to the first line of that code, before paging is enabled, it's actually running with eip=0x00011519, since the kernel was loaded at 0x00010000. Since paging is not enabled, its going to load the next instruction to execute from the physical address 0x00011519.

The problem occurs after the execution of the address at 0x00011521, where paging is actually enabled. After this instruction, eip is incremented to 0x00011524, but since paging is enabled, instead of loading the instruction from that physical location it will use the page tables to find the physical address. This means you need to "identity map" this address: that is, tell the MMU that 0x00011524 linear is mapped to 0x00011524 physical, so that it will load the next instruction.

At some point, however (like in my case a few instructions later) you want to start running at the virtual address your kernel was compiled for (in my case, at base 0xc0000000). So you also need the high virtual address of the kernel mapped to the physical location. So you need to have two virtual address (the physical address where the kernel was loaded--the identity map--and the virtual address you want it to run at) mapped to the phyiscal address at the same time.

You actually only need the physical address identity mapped until you switch to the virtual address, which can be as short as a couple of instructions later, but it is vital that it is mapped that way during the instruction that enables paging.

Hope that helps.
OSMAN

Re:Maybe something wrong with the BonaFide paging tutorial

Post by OSMAN »

This should be so, I guess. But I've tried to get the kernel's location physical ly and logically the same (as in my linker script there is: phys=0x1000000, virt=0x1000000), and that doesn't seem to matter, then what seems to?

Code: Select all

This means you need to "identity map" this address: that is, [u]tell the MMU that 0x00011524 linear is mapped to 0x00011524 physical[/u], so that it will load the next instruction.
I had thought I had it this way; if not... then...
... Is that done through some ports? Or defined in the linker script?
bkilgore

Re:Maybe something wrong with the BonaFide paging tutorial

Post by bkilgore »

Neither, it's done through the page directory and page tables.

Linear address 0x10000 corresponds to page tables 0 in the page directory, and page 16 in that page table.

So if you have something like:

Code: Select all

unsigned long *page_dir = <where the page directory is>
unsigned long *page_table = <where the first page table is>
you need to make sure you map your kernel like:

Code: Select all

int i;
unsigned long addr = 0x10000;

page_dir[0] = page_table | 3
for (i = 16; i < 32; i++) {
    page_table[i] = addr | 3;
    addr += 0x1000;
}
Something like that. What you can't really see from that example because everything is hardcoded (I suggest some #define's to make it easier to understand your own code) is that it is telling the MMU that 0x10000 -> 0x10000, 0x11000 -> 0x11000, etc all the way to 0x1F000 -> 0x1F000 (I only mapped 64K in this case).

That's how you "identity-map" your kernel: Set up a page table that maps virtual addr X to physical addr X.
OSMAN

Re:Maybe something wrong with the BonaFide paging tutorial

Post by OSMAN »

Oh, I think I got it.
But aren't you filling into page_table the addresses between each 0x1000?; I think I read from the Intel Docs that only 0x4000 chunks would be possible pages for i486; is this true?

PS. Hardcoding makes me to go into.
mystran

Re:Maybe something wrong with the BonaFide paging tutorial

Post by mystran »

Only 0x1000 byte pages are possible for i486. Notice that 0x1000 is hexadecimal syntax in C, and would be the same as 4096 in decimal.
OSMAN

Re:Maybe something wrong with the BonaFide paging tutorial

Post by OSMAN »

Thanks for that; of course it's so.

I'd ask bkilgore that why do you start identity mapping from 0x10000?
Is my problem that I start it from 0x0?
Is there some memory that shouldn't be mapped? Can't the video memory be mapped?

And If I follow the BonaFide's tutorial, all the other page tables except the first are set not present in the first place, and that drives the system into real-mode and "floppy recall, panic, so on". Why?
OSMAN

Re:Maybe something wrong with the BonaFide paging tutorial

Post by OSMAN »

Okay here you can see what do I have:
Paging.c

Code: Select all

unsigned long *page_directory = (ulong*) 0x20c000;
unsigned long *page_table = (ulong*) 0x20d000; // the page table comes 0x1000 after the page directory

void set_pagedir()
{
   asm( "movl %%eax, %%cr3" :: "r" ( page_directory ) );
}

void paging_install(void)
{
   unsigned long address=0; // holds the physical address of where a page is
   uint i;
   
   // map just 4MB of memory
   for(i=0; i<1024; i++)
   {
      page_table[i] = address | 3; // attribute set to: supervisor level, read/write, present(011 in binary)
      address += 4096; // 4kb chunks
   };
   
   // fill the first entry of the page directory
   page_directory[0] = page_table; // attribute set to: supervisor level, read/write, present(011 in binary)
   page_directory[0] = page_directory[0] | 3;
   
   // For all the yet unused page tables
   for(i=1; i<1024; i++)
   {
      page_directory[i] = 0 | 3; // attribute set to: supervisor level, read/write, present(011 in binary)
   };
   
   // put that page directory address into CR3
   set_pagedir();
   // set the paging bit in CR0 to 1
   asm("movl %cr0, %eax");
   asm("orl $0x80000000, %eax");
   asm("movl %eax, %cr0");
   
   // PAGING "Should be" ENABLED
}
Maybe you notice something wrong with this; at least there should be, for I cannot get it work. (The asm things work fine). The problem is that it jumps into bogus memory when paging bit is set.
(The kernel should be at 0x1 000 000, and it all physical)
(I was wondering that doesn't the attributing with i.e. | 3 disturb the address?)

I'm looking forward for your precious advice.
Midas
Member
Member
Posts: 140
Joined: Sat Jun 24, 2006 4:40 pm
Location: Falkirk, Scotland
Contact:

Re:Maybe something wrong with the BonaFide paging tutorial

Post by Midas »

The address is stored as the upper 20 bits (or low 4 bits of the high word and high 20 bits of the low word, with PAE enabled) of a 32 bit (or 64 bit, with PAE enabled) entry, so the binary OR with 3 actually only sets the attribute fields (which, actually in this case will be set if the address contains bits in the lower 12 bits of the low word set).

These 20 bits are the upper 20 bits of the address - forcing the address to be 4kB aligned.
Regards,
Angus [Óengus] 'Midas' Lepper
OSMAN

Re:Maybe something wrong with the BonaFide paging tutorial

Post by OSMAN »

I just wanted to be sure; that wasn't my main question, but a thank anyway. Please help because I don't see anything wrong with that code myself. I'm stuck, and I've tried to search every place without clear results. :-[
Post Reply