Question about paging
Question about paging
First of all, I'm loading my kernel from GRUB at 0x00100000. My entry point is some assembly which basically sets up a stack and calls main(). I've finally gotten to the point where my kernel does a few interesting things so I want to get paging working. My question is this:
Without setting up the page table for the kernel to map virtual addresses 0x00100000 -> whatever to those physical pages, how do I keep things working after enabling paging? Can I relocate the kernel's addresses on the fly (I'm guessing no here)? How do other kernel's do this? (I know, I know look at the source, but all of the kernel's I can read and understand fairly quickly either don't use paging or don't do what I want to do)
Without setting up the page table for the kernel to map virtual addresses 0x00100000 -> whatever to those physical pages, how do I keep things working after enabling paging? Can I relocate the kernel's addresses on the fly (I'm guessing no here)? How do other kernel's do this? (I know, I know look at the source, but all of the kernel's I can read and understand fairly quickly either don't use paging or don't do what I want to do)
Re:Question about paging
As far as I know you have to set up your page tables, set up the page directory and load cr3 before enabling paging.
Curufir
Curufir
Re:Question about paging
Here is the code that I came up with when I was learning paging, this was just to get into a paging environment, there is alot to be done after this however it was what I got done, I am not ready to fully implement paging in my OS so I have never taken this code further. This code will Identity Map the first 12MB of RAM, when the Kernel goes into paging mode it must be running at a physical address that has the same linear address. I hope you can understand this, I cannot explain it very well, it took me about a week to work it out and get it actually working, that was spending at least 4 hours a day on it aswell.
Anyway here it is, I hope it helps you.
Anyway here it is, I hope it helps you.
Code: Select all
; ===================================================
; Initialize Paging
; ===================================================
; Page Directory Address = 0x300000
; Page Table 0 = 0x301000
; Page Table 1 = 0x302000
; Page Table 2 = 0x303000
; ===================================================
; Format Page Directory Area
mov ax, 0x10 ; Load the Data Segment
mov es, ax ; Load the Segment Descriptor into ES
xor edi, edi ; Clear EDI
mov edi, 0x300000 ; Starting Offset = 4MB
mov eax, 0x00000002 ; Table Address = 0, Supervisor, Read/Write, Not Present
mov cx, 0x400 ; Store 1024 DWORDs (EAX)
cld ; Force EDI to be Incremented
rep stosd ; Store the Data
; Setup the Page Directory
mov dword [0x300000], 0x301003 ; Store Table0 Address, Supervisor, Read/Write, Present
mov dword [0x300004], 0x302003 ; Store Table1 Address, Supervisor, Read/Write, Present
mov dword [0x300008], 0x303003 ; Store Table2 Address, Supervisor, Read/Write, Present
; Indentity Map (0MB - 12MB)
xor edi, edi ; Clear EDI
mov edi, 0x301000 ; Table0 Absolute Address
mov eax, 0x00000003 ; Starting Base Address = 0, Supervisor, Read/Write, Present
mov cx, 0xC00 ; Store 3072 DWORDs (EAX)
cld ; Force EDI to be Incremented
Map12MB:
stosd ; EAX -> ES:EDI
add eax, 0x1000 ; Next Page Base Address
loop Map12MB ; Do Next Store
; Install the Page Directory
mov eax, 0x300000
mov cr3, eax
; Turn Paging On
mov eax, cr0
or eax, 0x80000000
mov cr0, eax
; Jump into Paging Environment
jmp Paging
Paging:
- Pype.Clicker
- Member
- Posts: 5964
- Joined: Wed Oct 18, 2006 2:31 am
- Location: In a galaxy, far, far away
- Contact:
Re:Question about paging
why do you pretend to have "starting offset = 4MB" while you initialise your table with 0x300000 ?
Re:Question about paging
Because memory is zero based, the first megabyte starts at 0, the 2nd at 0x100000, the 3rd at 0x200000 and the 4th at 0x300000, no pretending, just saying what I am doing.
Sorry for the confusion.
Sorry for the confusion.
Re:Question about paging
I can set up the pagetables fine, but after enabling paging all of the addresses will be different (and therefore not work) unless I map the kernel's pagetables to where it is loaded in memory. I'm trying to avoid this because it sort of limits where I can have the kernel mapped into address spaces. There must be a way around too because Linux for example maps the kernel into the upper 2G of address space. I'm wondering how they do this.Curufir wrote: As far as I know you have to set up your page tables, set up the page directory and load cr3 before enabling paging.
Curufir
Avery
Re:Question about paging
I completely understand what you're saying, but it's exactly what I'm trying to avoid. I don't want the kernel's pagetables to correspond to where it's loaded in physical memory (ie I want the pre-MMU addresses to be different from the post-MMU addresses). The problem is that I need my kernel to run fine both before and after enabling paging. How would I do this?PlayOS wrote: Here is the code that I came up with when I was learning paging, this was just to get into a paging environment, there is alot to be done after this however it was what I got done, I am not ready to fully implement paging in my OS so I have never taken this code further. This code will Identity Map the first 12MB of RAM, when the Kernel goes into paging mode it must be running at a physical address that has the same linear address. I hope you can understand this, I cannot explain it very well, it took me about a week to work it out and get it actually working, that was spending at least 4 hours a day on it aswell.
Anyway here it is, I hope it helps you.
Avery
Re:Question about paging
Copy the kernel to it's eventual resting place in physical memory before you setup the tables probably (If you're moving it around then you should could do this as you load it in after Pmode anyway). Then setup the virtual->physical page tables and go from there. So long as the virtual addresses match what the kernel code is expecting there's no problem.
There's probably a large number of ways to do this, I'd imagine linux just links the kernel's memory references (Isn't it an elf file?) to the upper 2GB on the fly, or something similar.
Curufir
There's probably a large number of ways to do this, I'd imagine linux just links the kernel's memory references (Isn't it an elf file?) to the upper 2GB on the fly, or something similar.
Curufir
Re:Question about paging
Just had another thought on this, and I'm not sure it would actually work (Maybe someone else with a bit more knowledge could say).
For a really simple relocation couldn't you have a variable tucked away in memory at a predefined physical address that points to the base address of the kernel code. Then simply have all memory references, jumps, calls etc add this variable before performing the operation. I'd imagine it would slow your code down horribly because of the extra additions (And I've no idea how you'd pull it off in C), but I think in theory you might be able to get away with doing it like that if you wanted a quick hack in assembly.
Err...of course I could be overcomplicating here :-[. Is there some reason you can't use a selector with its base set to 2gb? The internal addresses of the kernel code would be using offsets, the processor first translates the selector:offset into a linear address which then gets sent to the paging unit. So you'd end up using addresses offset to 2gb which your page tables would translate to physical addresses and everything would (Unless I'm completely wrong...and I'm not confident I'm not ) keep working just fine after you switch the selectors. So you'd set up directories, page tables, cr3, turn on paging, do a far jump to your new cs:eip, load the new selectors, and carry on running.
Curufir
For a really simple relocation couldn't you have a variable tucked away in memory at a predefined physical address that points to the base address of the kernel code. Then simply have all memory references, jumps, calls etc add this variable before performing the operation. I'd imagine it would slow your code down horribly because of the extra additions (And I've no idea how you'd pull it off in C), but I think in theory you might be able to get away with doing it like that if you wanted a quick hack in assembly.
Err...of course I could be overcomplicating here :-[. Is there some reason you can't use a selector with its base set to 2gb? The internal addresses of the kernel code would be using offsets, the processor first translates the selector:offset into a linear address which then gets sent to the paging unit. So you'd end up using addresses offset to 2gb which your page tables would translate to physical addresses and everything would (Unless I'm completely wrong...and I'm not confident I'm not ) keep working just fine after you switch the selectors. So you'd set up directories, page tables, cr3, turn on paging, do a far jump to your new cs:eip, load the new selectors, and carry on running.
Curufir
Re:Question about paging
Just go and check out Tim Robinsons memory management tutorials, he addresses this and provides a simple solution.
http://www.cyberscriptorium.com/osjourn ... ic&topic=2
hope this helps.
http://www.cyberscriptorium.com/osjourn ... ic&topic=2
hope this helps.
Re:Question about paging
Thanks. That's exactly what I was looking for. Now, hopefully I'll be able to implement it correctly.PlayOS wrote: Just go and check out Tim Robinsons memory management tutorials, he addresses this and provides a simple solution.
http://www.cyberscriptorium.com/osjourn ... ic&topic=2
hope this helps.
Avery