How to get to paging?

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.
Post Reply
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

How to get to paging?

Post by onlyonemac »

I don't quite know what it's called, but the question is how do I get the CPU into whatever mode it needs to be in in order to use paging? I know that I need to set up the page directories and tables, and then set something in the control registers, but is there anything else that I should do first? Do I need to be in protected mode? If so, what must go in my GDT? Should I just use a flat memory map until I'm ready to enable paging? Once I set the bit in the control register to enable paging, must I perform a far jump as with entering protected mode? Where should the jump go? Can I set cr3 first, before I enable paging? etc.

Basically what I need is a code snippet, or at least a pseudocode snippit, for getting from real mode to whatever you call the mode where paging is used, minus of course the details of setting up the page tables as I think I can handle that myself.
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: How to get to paging?

Post by iansjack »

1. You need to be in Protected Mode.

2. Set up a GDT to support a flat address space.

3. Set up your Page Tables. You'll probably want to make the page that you are running in identity mapped to avoid problems when paging is enabled.

4. Load CR3 with the (physical) address of your Page Table.

5. Set the paging bit in CR0.

No jumps needed - you are now running with paging enabled and all addresses are virtual addresses. Almost certainly you will have done something wrong (getting the correct entries in the Page Table can be tricky at first) so you will probably get an instant exception. I'd recommend running under a debugger (AMD's SimNow is my favourite for this low-level debugging of boot code), single-stepping through the bit where you enable paging, and carefully inspect your Page Table to see that it contains the entries it should. A Page Fault will always push an error code telling you exactly what caused the fault and puts the faulting address in CR2 which helps to determine the problem. It's a good idea to set up exception handlers as soon as possible to make life easier when GPFs and PFs occur; mine dumps the stack frame and the values of the general purpose registers to the screen, plus registers CR2 and CR3, and then halts the processor. Later you will refine these, particularly the handler for a Page Fault, to do something more useful.

Remember that, from now on, you still need to use physical addresses when manipulating Page Tables, so you need some way of mapping those physical addresses to logical addresses. A simple solution is to produce a mapping that the kernel can use of all physical RAM (which is not as wasteful as it might at first appear to be); otherwise you can just create temporary mappings of individual pages as you need to or use recursive Page Tables (although this can be a bit difficult to get your head round at first).
Octocontrabass
Member
Member
Posts: 5588
Joined: Mon Mar 25, 2013 7:01 pm

Re: How to get to paging?

Post by Octocontrabass »

iansjack wrote:3. Set up your Page Tables. You'll probably want to make the page that you are running in identity mapped to avoid problems when paging is enabled.
There's no "probably" here; the code that enables paging must be identity-mapped. If you're still using the 80386 manual, it's time for an update.
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: How to get to paging?

Post by iansjack »

Octocontrabass wrote:
iansjack wrote:3. Set up your Page Tables. You'll probably want to make the page that you are running in identity mapped to avoid problems when paging is enabled.
There's no "probably" here; the code that enables paging must be identity-mapped. If you're still using the 80386 manual, it's time for an update.
There is a "probably" (IMO). The programmer could have chosen to copy the code to the location pointed to by the Page Table before enabling paging, in which case it would still work. But it's probably not the best way to do it (IMO).

Edit: Having read your link more carefully I guess you may be right. You let's say that the page must be identity mapped and you must jump immediately after enabling paging. I've always used identity mapping here so I've never come across this problem.
Octocontrabass
Member
Member
Posts: 5588
Joined: Mon Mar 25, 2013 7:01 pm

Re: How to get to paging?

Post by Octocontrabass »

If paging is enabled, the code for the MOV CR0 instruction and the JMP or CALL instruction must come from a page that is identity mapped (that is, the linear address before the jump is the same as the physical address after paging and protected mode is enabled). The target instruction for the JMP or CALL instruction does not need to be identity mapped.
Intel® 64 and IA-32 Architectures Software Developer’s Manual, volume 3, section 9.9.1
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Re: How to get to paging?

Post by onlyonemac »

@iansjack: Thanks for your explanation, it was very helpful. However I still have a few questions. Firstly, why must I enter protected mode before setting up the identity-mapped GDT; I normally used to set my GDT up beforehand then enter protected mode. Secondly, I am wanting to use a higher-half kernel. You said that it is necessary to initially set my page tables up to identity-map the kernel - how do I then get the kernel mapped to the higher half? Must I initially map the kernel in both places - the identitty-mapped low memory where I have loaded the kernel AND the high memory area, then perform a far jump?
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
onlyonemac
Member
Member
Posts: 1146
Joined: Sat Mar 01, 2014 2:59 pm

Re: How to get to paging?

Post by onlyonemac »

I just realised that I guess I could identity-map the bootloader (which is where I will be setting up paging) and map the kernel only in the higher-half, then perform the far jump from the identity-mapped bootloader into the kernel's entry point in the high memory area. Then I can unmap the bootloader. Would this work?
When you start writing an OS you do the minimum possible to get the x86 processor in a usable state, then you try to get as far away from it as possible.

Syntax checkup:
Wrong: OS's, IRQ's, zero'ing
Right: OSes, IRQs, zeroing
Octocontrabass
Member
Member
Posts: 5588
Joined: Mon Mar 25, 2013 7:01 pm

Re: How to get to paging?

Post by Octocontrabass »

onlyonemac wrote:Firstly, why must I enter protected mode before setting up the identity-mapped GDT; I normally used to set my GDT up beforehand then enter protected mode.
If your GDT is already set up for a flat address space, then you don't have to do anything for step 2. In fact, you can switch to protected mode and enable paging at the same time.
onlyonemac wrote:Would this work?
Yes.
User avatar
iansjack
Member
Member
Posts: 4706
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: How to get to paging?

Post by iansjack »

Sorry, I didn't mean to imply that you have to be in Protected Mode before setting up the data structures. If they are within the addressable range of real mode you can set them up there. Most people tend to use Grub, or some similar bootloader, that set up the basics for you and put you into Protected Mode. I just meant that you need to be in Protected Mode before you can enable paging.
Post Reply