Initializing paging not working, what have I forgotten?

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

Initializing paging not working, what have I forgotten?

Post 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
Phil

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

Post 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
Phil

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

Post 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
frank

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

Post 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.
User avatar
Neo
Member
Member
Posts: 842
Joined: Wed Oct 18, 2006 9:01 am

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

Post 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?
Only Human
frank

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

Post 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 = .;
}


frank

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

Post 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]
Tim

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

Post 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.
Curufir

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

Post 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.
frank

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

Post 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) */

User avatar
Candy
Member
Member
Posts: 3883
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

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

Post 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).
frank

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

Post 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 = .;
}
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

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

Post 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 ...
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

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

Post 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)
frank

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

Post 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
Post Reply