Paging questions
Paging questions
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.
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.
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
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):
I'd appreciate it if somebody could tell me what I am doing wrong.
Below is the code that I have written:Bochs wrote: 00003287942e[CPU0 ] exception(): 3rd (13) exception with no resolution, shutdown status is 00h, resetting
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
; ------------------------------------
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
the problem lies here:
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)
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
0x000000-0x001000 (4KB)
instead of
0x100000-0x10???? (your kernel at the 1MB mark)
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.
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
- Kevin McGuire
- Member
- Posts: 843
- Joined: Tue Nov 09, 2004 12:00 am
- Location: United States
- Contact:
This is equivalent to what the CPU does when it wants to find out what physical address maps to what virtual address.
The CPU also checks the flags in each entry which I do not do.
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..
- Combuster
- Member
- Posts: 9301
- Joined: Wed Oct 18, 2006 3:45 am
- Libera.chat IRC: [com]buster
- Location: On the balcony, where I can actually keep 1½m distance
- Contact:
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.
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.
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!
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!
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.
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:
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
; ------------------------------------
On the field with sword and shield amidst the din of dying of men's wails. War is waged and the battle will rage until only the righteous prevails.