Page 1 of 2

Initializing paging not working, what have I forgotten?

Posted: Fri Jan 23, 2004 2:14 pm
by frank
I've been trying to enable paging for a while,
but my cpu keeps crashing.

The code I have:

Code: Select all

   mem = (unsigned int *) 0x300000;                        /* Page Directory Entry */
    mem[0] = (0x300000 + 0x1000)  | 3;   
    mem = (unsigned int *) 0x301000 ;                        /* Page Table Entry */
    mem[0] =  (0x302000) | 3;
    asm("movl $0x300000,%eax");                     /* Put the Page-Directory Base address in  eax */      
    asm("movl %eax,%cr3");                              /* Set the pointer to the 1st Page-Directory Base in CR3 (Controll Register 3 / PDBR) */
   asm("movl %cr0,%eax");                              
    asm("addl $2147483648,%eax");         
   asm("movl %eax,%cr0");                              /* Set bit 31 of CR0 (Controll Register 0,  paging bit) */
   asm("jmp $0x08,$pagingdone");
    asm("pagingdone:");
I'm wondering what I have forgotten or not done?
I've read the intel manual and k.j. tutorial btw.

Thanks in advance,
Frank

Re:Initializing paging not working, what have I forgotten?

Posted: Fri Jan 23, 2004 2:55 pm
by Phil
I'm fairly new to this, but I'll give it a shot...

1) I think you need to fill in all the other entries in the Page Directory and set them to "Not Present" if you don't want to actually initialize them.

2) Same thing for the Page Table entries.

3) It appears that you are mapping physical address 0x302000 to be linear address 0x00000000. Are all your segments and currently running code designed to work that way? And are they located starting at physical address 0x302000?

Like I said, I'm new to this stuff. I could be way off. Good luck either way.

Phil

Re:Initializing paging not working, what have I forgotten?

Posted: Fri Jan 23, 2004 2:57 pm
by Phil
One more thought - check out this web page for an EXCELLENT example of getting paging going.

http://osdev.neopages.net/tutorials/pag ... ?the_id=43

Re:Initializing paging not working, what have I forgotten?

Posted: Fri Jan 23, 2004 4:02 pm
by frank
1) I think you need to fill in all the other entries in the Page Directory and set them to "Not Present" if you don't want to actually initialize them.

2) Same thing for the Page Table entries.
Ok, I changed that. The cpu crashes though.
3) It appears that you are mapping physical address 0x302000 to be linear address 0x00000000. Are all your segments and currently running code designed to work that way? And are they located starting at physical address 0x302000?
Should I set the linear address of the page in 0x302000?
That would make the size of a page not 4096 bytes.. right?

I haven't set up the segments/code to work that way.
How can I do this?
My code is running at 0x100000.

Re:Initializing paging not working, what have I forgotten?

Posted: Fri Jan 23, 2004 9:34 pm
by Neo
are you linking your kernel to run at whatever virtual address you plan to use? (i think thats 0x302000) is your linker script right?

Re:Initializing paging not working, what have I forgotten?

Posted: Sat Jan 24, 2004 4:13 am
by frank
are you linking your kernel to run at whatever virtual address you plan to use? (i think thats 0x302000) is your linker script right?
It currently uses 0x100000, should I change it?
The entry is defined as -e main in my Makefile btw.

Code: Select all

 
OUTPUT_FORMAT("elf32-i386")
ENTRY(entry)
Virtual = 0x100000;
Physical = 0x100000;
SECTIONS
{
   .text   Virtual : AT(Physical)
   {
      code = .;
      *(.text)
      *(.rodata*)         
      . = ALIGN(4096);
   }
   .data : AT(Physical + (data - code))
   {
      data = .;
      *(.data)
      . = ALIGN(4096);
   }
   .bss : AT(Physical + (bss - code))
   {
      bss = .;
      *(.bss)
      . = ALIGN(4096);
   }
   end = .;
   _end = .;
}



Re:Initializing paging not working, what have I forgotten?

Posted: Sun Jan 25, 2004 2:54 pm
by frank
Correct me if I'm wrong about this:
To initialize paging:
[sup]
1. The cpu needs 1024 Page Directory Entries. Each should point to a physical address of a Page Table Entry. (4k aligned)
2. It needs 1024 Page Table Entries, each pointing to the physical address of the Page Table. (4k aligned)
3. It needs the physical address of the first Page Directory in cr3 (Page Directory Base Address)
4. After that set bit 31 of cr0 (enable paging) and paging is initialized
[/sup]

Re:Initializing paging not working, what have I forgotten?

Posted: Sun Jan 25, 2004 3:36 pm
by Tim
2a. At least the page containing the code that enables paging must be mapped. It's easy to map the entire bottom 4MB.

Re:Initializing paging not working, what have I forgotten?

Posted: Sun Jan 25, 2004 4:40 pm
by Curufir
frank wrote: [sup]
1. The cpu needs 1024 Page Directory Entries. Each should point to a physical address of a Page Table Entry. (4k aligned)
[/sup]
Just for the sake of precision :).

In the page directory only the entries for page tables that are marked as present actually need to contain an address. Any entires that are marked as not-present can use the top 31 bits in any way you see fit. For example you might keep some virtual memory information there.

Re:Initializing paging not working, what have I forgotten?

Posted: Tue Jan 27, 2004 5:16 am
by frank
2a. At least the page containing the code that enables paging must be mapped. It's easy to map the entire bottom 4MB.
Would it be ok if my page directory would start at 0xFE000, my page table at 0xFF000 and my kernel at 0x100000?
Should the paging intialize code start at 0x100000?

I don't know what goes wrong (apart that it crashes at mov cr0,eax) 'cause I'm using vmware. (I can not use bochs)
The code I have now

Code: Select all

   unsigned int * mem;
   unsigned int i = 0;

   mem = (unsigned int *) 0xFE000;                                          /* Page Directory start */
   for (i=1; i<1024; i++)                                                            /* Make 1024 Page Directory Entries */
   {
      mem[i] = 0;
      mem[i] = mem[i]   | 2; 
   }
   mem[0] = (unsigned int) 0xFF000;
   mem[0] = mem[0] | 3;
   
   mem = (unsigned int *) 0xFF000;                                          /* Page Table start */
   for (i=0; i<1024; i++)                                                            /* Make 1024 Page Table Entries */
   {
      mem[i] = (unsigned int*) ((unsigned int) (0xFF000  + (i*4096)) );
      mem[i] = mem[i] | 3;      
   }
            
   asm("movl $0xFE000,%eax");                                       /* Put the Page-Directory Base address in  eax */      
    asm("movl %eax,%cr3");                                                /* Set the pointer to the 1st Page-Directory Base in CR3 (Controll Register 3 / PDBR) */
   asm("movl %cr0,%eax");                              
   asm("addl $0x80000000,%eax");         
   asm("movl %eax,%cr0");                                                /* Set bit 31 of CR0 (Controll Register 0,  paging bit) */


Re:Initializing paging not working, what have I forgotten?

Posted: Tue Jan 27, 2004 5:58 am
by Candy
frank wrote:
2a. At least the page containing the code that enables paging must be mapped. It's easy to map the entire bottom 4MB.
Would it be ok if my page directory would start at 0xFE000, my page table at 0xFF000 and my kernel at 0x100000?
Should the paging intialize code start at 0x100000?
I am quite happy you didn't try this on a real computer. 0xA0000-0xFFFFF is the SYSTEM HARDWARE area (or some name similar), and it is ROM. That means, it is NOT memory, and you can NOT use it as such. Place it somewhere else(hint: try int15/ax=e820).

Re:Initializing paging not working, what have I forgotten?

Posted: Tue Jan 27, 2004 6:15 am
by frank
I moved it to 0x100000, the cpu crashes.
I have not a clue why though..

Code: Select all


void VM_Pages()
{
   unsigned int * mem;
   unsigned int i = 0;

   mem = (unsigned int *) 0x100000;                                          /* Page Directory start */
   for (i=1; i<1024; i++)                                                            /* Make 1024 Page Directory Entries */
   {
      mem[i] = 0;
      mem[i] = mem[i]   | 2; 
   }
   mem[0] = (unsigned int) 0x101000;
   mem[0] = mem[0] | 3;
   
   mem = (unsigned int *) 0x101000;                                          /* Page Table start */
   for (i=0; i<1024; i++)                                                            /* Make 1024 Page Table Entries */
   {
      mem[i] = (unsigned int*) ((unsigned int) (0x102000  + (i*4096)) );
      mem[i] = mem[i] | 3;      
   }
            
   asm("movl $0x100000,%eax");                                       /* Put the Page-Directory Base address in  eax */      
    asm("movl %eax,%cr3");                                             /* Set the pointer to the 1st Page-Directory Base in CR3 (Controll Register 3 / PDBR) */
   asm("movl %cr0,%eax");                              
   asm("addl $0x80000000,%eax");         
   asm("movl %eax,%cr0");                                             /* Set bit 31 of CR0 (Controll Register 0,  paging bit) */
}
I also changed my linker script

Code: Select all

OUTPUT_FORMAT("elf32-i386")
ENTRY(entry)
Virtual = 0x102000;
Physical = 0x102000;
SECTIONS
{
   .text   Virtual : AT(Physical)
   {
      code = .;
      *(.text)
      *(.rodata*)         
      . = ALIGN(4096);
   }
   .data : AT(Physical + (data - code))
   {
      data = .;
      *(.data)
      . = ALIGN(4096);
   }
   .bss : AT(Physical + (bss - code))
   {
      bss = .;
      *(.bss)
      . = ALIGN(4096);
   }
   end = .;
   _end = .;
}

Re:Initializing paging not working, what have I forgotten?

Posted: Tue Jan 27, 2004 6:22 am
by Pype.Clicker
what about trying it in bochs ?? it could give you more informations about what crashed and why ... it could provide you register states at crash time, the trace of last executed instructions etc.

Think in the bochs ...

Re:Initializing paging not working, what have I forgotten?

Posted: Tue Jan 27, 2004 6:33 am
by Pype.Clicker

Code: Select all

  asm("movl $0x100000,%eax"); 
   asm("movl %eax,%cr3");       
   asm("movl %cr0,%eax");                              
   asm("addl $0x80000000,%eax");         
   asm("movl %eax,%cr0");          
There are some things i dislike in these ASM statements (and that the compiler might dislike aswell:
- you're refering to registers with a simple '%eax', which is their AS name, but you should double-quote the '%' and thus refer registers as %%eax and %%cr0
- you didn't said your instruction were volatile (so the compiler could optimize them by not issuing them as it doesn't see how they help generating correct C function)
- there's nothing that prevents the compiler from modifying the content of the EAX register between "asm(mov 0x10000,eax); and asm(mov eax,cr3) instruction. If you don't want the compiler to mess with your asm instructions, either write them in asm (in a separate file, i mean) or as a single asm("mov 0x10000,eax ; mov eax,cr3") command ...

imho, giving a look at the code generated for your inline asm would worth the effort (objdump -drS vm.o may help)

Re:Initializing paging not working, what have I forgotten?

Posted: Tue Jan 27, 2004 7:13 am
by frank
Ok, I changed it, but the cpu crashes..
Bochs would make it a lot easier, but..
what about trying it in bochs ?? it could give you more informations about what crashed and why ... it could provide you register states at crash time, the trace of last executed instructions etc.
the problem with trying it in bochs is that I don't have a floppy drive and I'm using grub.
afaik it's impossible to let bochs boot from /dev/hda
- you're refering to registers with a simple '%eax', which is their AS name, but you should double-quote the '%' and thus refer registers as %%eax and %%cr0
If I give them the names %%eax and so I get the error:
"Error: Bad Register name `%%eax'"
- you didn't said your instruction were volatile (so the compiler could optimize them by not issuing them as it doesn't see how they help generating correct C function)
- there's nothing that prevents the compiler from modifying the content of the EAX register between "asm(mov 0x10000,eax); and asm(mov eax,cr3) instruction. If you don't want the compiler to mess with your asm instructions, either write them in asm (in a separate file, i mean) or as a single asm("mov 0x10000,eax ; mov eax,cr3") command ...

imho, giving a look at the code generated for your inline asm would worth the effort (objdump -drS vm.o may help)
Ok, I changed it

Code: Select all

   asm volatile("movl $0x100000,%%eax;" \
                       "movl %eax,%cr3;" \
                     "movl %cr0,%eax;" \
                     "addl $0x80000000,%eax;" \
                     "movl %eax,%cr0");                                             
objdump gives me the output:

Code: Select all

  c7:   81 fa ff 03 00 00       cmp    $0x3ff,%edx
  cd:   76 e5                   jbe    b4 <VM_Pages+0x30>
  cf:   b8 00 00 10 00          mov    $0x100000,%eax
  d4:   0f 22 d8                mov    %eax,%cr3
  d7:   0f 20 c0                mov    %cr0,%eax
  da:   05 00 00 00 80          add    $0x80000000,%eax
  df:   0f 22 c0                mov    %eax,%cr0
  e2:   c9                      leave
  e3:   c3                      ret