Page 1 of 1

Paging questions

Posted: Wed Mar 28, 2007 2:58 am
by XCHG
I have started reading about paging and how I can implement it in my kernel. I have some questions though that I couldn’t find answers to in Intel Manuals. I’d really appreciate it if somebody could answer these for me.

1. Bits 12 to 31 of the Control Register 3 hold the base address of the page directory. Since this is a 20 bit field, does it mean that the page table address should be located somewhere between the beginning of the physical memory and up to the 1 megabyte boundary? Or is it possible to put the Page Directory Entries somewhere else in the memory?

2. Can paging be enabled once in protected mode or does it have to be enabled before setting the PE bit of the Control Register 0?

3. I don’t know if I am right about this or not but the Page Directory is 4 kilobytes long. Each Page Directory Entry is 32-bits long and thus we can have a total number of 128 Page Directory Entries in the Page Directory Table. Is that right? If yes, then why some tutorials mention that there are 1024 Page Directory Entries in the Page Directory?


Thanks in advance.

Posted: Wed Mar 28, 2007 3:03 am
by Andrew275
1. The page directory must be 4KB aligned, so therefore those low bits of the address would always be 0. You can put it anywhere in physical memory.

2. You can enable paging once in protected mode.

3. Your math is off. 32 bits is 4 bytes, so 4 KB divided by 4 bytes gives you 1024.

Posted: Wed Mar 28, 2007 5:08 am
by XCHG
Thank you so much. I appreciate it. And by the way, I am not bad in math I think I must have been sleepy or something. :D

Posted: Wed Mar 28, 2007 6:29 am
by muisei
This is quite a common phenomenon.I'm studying math all my life and yesterday I had to use my scintific calculator to solve 7*8. :oops:

Posted: Wed Mar 28, 2007 10:39 am
by Candy
muisei wrote:This is quite a common phenomenon.I'm studying math all my life and yesterday I had to use my scintific calculator to solve 7*8. :oops:
The amount of amazement that should cause depends on your age.

Posted: Thu Mar 29, 2007 12:18 am
by XCHG
I seem not to be able to enable paging. Well here is the situation. My kernel is located at the 1MB (0x00100000) and I tried putting the Page Directory Entries at the 6MB (0x00600000). I also put Page Directory Entries right after the Page Directory at 6MB + 4KB (0x00601000). I then put zero in all the 1024 entries for both the Page Directory and the Page Table. I then initialized only the first Page Directory Entry and just Page Table Entry but I get the below error message as soon as I modify the Control Register 0 (CR0):
Bochs wrote: 00003287942e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
Below is the code that I have written:

Code: Select all

; ------------------------------------
KERNELENTRY                     EQU       MEGABYTE(1)
PAGE_DIRECTORY_MEMLOCATION      EQU       MEGABYTE(6)
PAGE_TABLE_MEMLOCATION          EQU       MEGABYTE(6) + KILOBYTE(4)
PAGE_DIRECTORY_AND_TABLE_COUNT  EQU       KILOBYTE(4) / 4
PAGE_ENTRY_LEN                  EQU       0x00000004
; ------------------------------------
; 1) Clear all 1024 Page Directory Entires (PDEs) and Page Table Entries (PTEs)
MOV     EBX , PAGE_DIRECTORY_MEMLOCATION          ; *EBX = Pointer to Page Directory
MOV     EDX , PAGE_TABLE_MEMLOCATION              ; *EDX = Pointer to Page Table
MOV     ECX , PAGE_DIRECTORY_AND_TABLE_COUNT      ; *ECX = Number of entries to fill
XOR     EAX , EAX                                 ; *EAX = Put zero in entries
.ZeroDirectoryAndTable:                           ; The loop to fill PDEs and PTEs
  MOV     DWORD PTR [EBX] , EAX                   ; Put zero in the current PDE
  MOV     DWORD PTR [EDX] , EAX                   ; Put zero in the current PTE
  ADD     EBX , PAGE_ENTRY_LEN                    ; Move to the next PDE
  ADD     EDX , PAGE_ENTRY_LEN                    ; Move to the next PTE
  DEC     ECX                                     ; Decrement the counter
  JNZ     .ZeroDirectoryAndTable                  ; Keep doing this while ECX > 0
; ------------------------------------
; Make the first Page Directory Entry
MOV     EBX , PAGE_DIRECTORY_MEMLOCATION          ; *EBX = Pointer to Page Directory
MOV     EAX , 0x00000003 | PAGE_TABLE_MEMLOCATION ; Set the access bits and Memory Location
MOV     DWORD PTR [EBX] , EAX                     ; Set the first Page Directory Entry
; ------------------------------------
; Make the first Page Table Entry
MOV     EBX , PAGE_TABLE_MEMLOCATION              ; *EBX = Pointer to Page Table
MOV     EAX , 0x00000003 | KERNELENTRY            ; Set access bits and etc
MOV     DWORD PTR [EBX] , EAX                     ; Set the first Page Table Entry
; ------------------------------------
MOV     EAX , CR3                                 ; Read the Control Register 3
OR      EAX , PAGE_DIRECTORY_MEMLOCATION          ; Set the Page Directory Base
MOV     CR3 , EAX                                 ; Modify the Control Register 3
; ------------------------------------
MOV     EAX , CR0                                 ; Read the Control Register 0
OR      EAX , CR0_PG                              ; Set the Paging Bit (BIT#31)
MOV     CR0 , EAX                                 ; Enable Paging (BAM-ERROR!)
JMP     $                                         ; Don't go any further
; ------------------------------------
I'd appreciate it if somebody could tell me what I am doing wrong.

Posted: Thu Mar 29, 2007 1:51 am
by Combuster
the problem lies here:

Code: Select all

; Make the first Page Table Entry
MOV     EBX , PAGE_TABLE_MEMLOCATION              ; *EBX = Pointer to Page Table
MOV     EAX , 0x00000003 | KERNELENTRY            ; Set access bits and etc
MOV     DWORD PTR [EBX] , EAX 
as you see you fill only entry #1 of the page table. This covers
0x000000-0x001000 (4KB)
instead of
0x100000-0x10???? (your kernel at the 1MB mark)

Posted: Thu Mar 29, 2007 2:05 am
by XCHG
The first thing that I do when my kernel is loaded into the memory is that I set the Page Table Entries and Page Directory Entries. So these codes that I pasted here are the only codes that run when my kernel runs so shouldn't it work? I mean these codes when assembled don't cross a 4KB boundary.

Posted: Thu Mar 29, 2007 4:38 am
by Kevin McGuire
This is equivalent to what the CPU does when it wants to find out what physical address maps to what virtual address.

Code: Select all

KERNELENTRY                     EQU       MEGABYTE(1)
PAGE_DIRECTORY_MEMLOCATION      EQU       MEGABYTE(6)
PAGE_TABLE_MEMLOCATION          EQU       MEGABYTE(6) + KILOBYTE(4)
PAGE_DIRECTORY_AND_TABLE_COUNT  EQU       KILOBYTE(4) / 4
PAGE_ENTRY_LEN                  EQU       0x00000004 

ADDRESS_WANTED 

mov ebp, PAGE_DIRECTORY_MEMLOCATION
mov  eax, ADDRESS_WANTED
shr eax, 22
mov ebp, dword [ebp+eax*4]
and ebp, 0xFFFFF000
mov eax, ADDRESS_WANTED
shl eax, 10
shr eax, 22
mov ebp, dword[ebp+eax*4]
and ebp, 0xFFFFF000
mov eax, ADDRESS_WANTED
and eax, 0xFFF
or ebp, eax
; EBP holds the physical address for the virtual address ADDRESS_WANTED..
The CPU also checks the flags in each entry which I do not do.

Posted: Thu Mar 29, 2007 4:11 pm
by Combuster
your kernel is located from the 1MB mark. When you enable paging, the page table must contain entries that map the kernel area to physical memory. You do not provide any entries for that, so that when paging is enabled the processor looks up bogus values and crashes.

your reasoning goes wrong about here:
- you fill in entry 0 of page table 0. The processor looks this up when accessing memory from 0x00000000-0x00000fff, not where your code is located (which would be around the 256th entry)
- you make the page table entry point at 0x00000000. The real mode IVT is located here, not your kernel code.

You'll need to fix both problems before anything will work.

Posted: Thu Mar 29, 2007 11:31 pm
by XCHG
Oh so I must have gotten it wrong. This means that you can not map a linear address to a physical address beginning at a random place in the memory using the first or the second entry of the page table? So I have to find divide my kernel's entry point by 4KB and that will be entry in the page table that I have to fill. Is that close on being on the money?

How about the page directory? should I fill all the PDEs too? Thank you guys.


P.S: Oh now I get it. 1024 Page Directory Entires * 1024 Page Table Entries * Number of bytes that a Page Table covers (4096) = 1024*1024*4096 = 4294967296 which is the whole addressable memory. I'm a dingus!

Posted: Fri Mar 30, 2007 12:12 am
by XCHG
Okay I enabled paging, finally! I filled the first PTE and filled its corresponding 1024 PTEs. This allowed me to address the first 4 MBs of memory. Thank you everyone. Combuster, thank you so much. I appreciate your help.

Here is the code. It might help someone, someday:

Code: Select all

  ; ------------------------------------
  PAGE_DIRECTORY_MEMLOCATION      EQU       MEGABYTE(6)
  PAGE_TABLE_MEMLOCATION          EQU       MEGABYTE(6) + KILOBYTE(4)
  PAGE_DIRECTORY_AND_TABLE_COUNT  EQU       KILOBYTE(4) / 4
  PAGE_ENTRY_LEN                  EQU       0x00000004
  ; ------------------------------------
  INVOKE  __ZeroMemory, PAGE_DIRECTORY_MEMLOCATION, KILOBYTE(4)
  INVOKE  __ZeroMemory, PAGE_TABLE_MEMLOCATION, KILOBYTE(4)
  ; ------------------------------------
  ; Fill in the first Page Directory Entry
  MOV     EBX , PAGE_DIRECTORY_MEMLOCATION
  MOV     EAX , 0x00000003 | PAGE_TABLE_MEMLOCATION
  MOV     DWORD PTR [EBX] , EAX
  ; ------------------------------------
  ; Fill in all 1024 PTEs of the first PDE
  MOV     EBX , PAGE_TABLE_MEMLOCATION
  MOV     ECX , PAGE_DIRECTORY_AND_TABLE_COUNT
  XOR     EDX , EDX
  .FillPageTableEntries:
    MOV     EAX , EDX
    OR      EAX , 0x00000003
    MOV     DWORD PTR [EBX] , EAX
    ADD     EDX , KILOBYTE(4)
    ADD     EBX , 0x00000004
    DEC     ECX
    JNZ     .FillPageTableEntries  
  ; ------------------------------------
  MOV     EAX , CR3
  OR      EAX , PAGE_DIRECTORY_MEMLOCATION
  MOV     CR3 , EAX
  ; ------------------------------------
  MOV     EAX , CR0
  OR      EAX , CR0_PG
  MOV     CR0 , EAX
  ; ------------------------------------