Initializing Paging from within the kernel

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

Initializing Paging from within the kernel

Post by shad »

Can I initialize paging after my C kernel has started, and been linked at 0x100000? Or do i have to initialize it before and link it to a virtual address. Also, ive written a working physical memory allocator with the help of Tim's tutorial, what i dont understand is, once paging is enabled, how does the physical allocator work? Wont the addresses all be virtual?
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 from within the kernel

Post by Pype.Clicker »

It is possible to handle the paging initialization either before or within the "C" part of the kernel. However, when paging is enabled within the C kernel, it is preferable to keep the kernel region identically mapped (so that you can still use the same logical addresses for the kernel with or without paging).

If you want to load your kernel in high addresses like 0xC000.0000 .. 0xFFFF.FFFF like Linux does, it is probably easier to initialize paging before you execute the kernel - as these addresses are unlikely to be valid memory without paging...

If you see nothing wrong with having your kernel located in the low memory range (either real mode area or just starting at 1Mb), then you can just keep the same mapping.

As people might want to keep 1MB area free for the use of VM86 programs, the "kernel in low area" seems not to be in the mood.

What you could also do is
1. load your kernel in physical memory starting at 1MB.
2. have no paging at start-up, but a kernel code & data segment that have a base such as 1MB == 3GB (0xC000.0000)
3. Enable paging mapping logical linear address 0xC000.0000 -> ... to physical addresses 0x0010.0000 -> ...)
4. Reset the base of kernel code & data segment so that you have a flat-mode kernel.

From a "programming" point of view, everything remains at the same address and using the same physical memory. You just played on the 2 aspects of the MMU to keep the same translation before and after paging enabling.

Keeping cs.base!=0 is not wishable as it usually prevent the use of fast system calls, etc.

may the CR3 be with You, Use it wisely :)
shad

Re:Initializing Paging from within the kernel

Post by shad »

ok i get it
shad

Re:Initializing Paging from within the kernel

Post by shad »

If paging is enabled before the IDT is loaded, should it be loaded with a virtual address or a physical one?
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 from within the kernel

Post by Pype.Clicker »

IDTR.base should always be loaded with a physical address, as GDTR.base and CR3 ...
pskyboy

Re:Initializing Paging from within the kernel

Post by pskyboy »

Im sure it says in the intel manuals that the GDT and IDT use virtual addresses to find there locations?

Peter
Curufir

Re:Initializing Paging from within the kernel

Post by Curufir »

pskyboy wrote: Im sure it says in the intel manuals that the GDT and IDT use virtual addresses to find there locations?

Peter
Nope, it's physical, plain and simple. That's why there is no selector associated with the GDT/IDT registers.

Think of it logically. If the base is a virtual address then how can you load the GDT/IDT register in pmode without a GDT already being present, there would be nowhere to lookup a selector.
distantvoices
Member
Member
Posts: 1600
Joined: Wed Oct 18, 2006 11:59 am
Location: Vienna/Austria
Contact:

Re:Initializing Paging from within the kernel

Post by distantvoices »

*where are lizards? ... ah there is one sofa lizard*

GDT/IDT registers have to be provided with PHYSICAL Adresses. Everything clear?

Prior to enabling paging, it is very wise to have idt up and running - with exception handlers installed.
... the osdever formerly known as beyond infinity ...
BlueillusionOS iso image
Tim

Re:Initializing Paging from within the kernel

Post by Tim »

Not physical -- linear. If you use LGDT or LIDT with paging enabled, you must use a virtual address. Paging applies to LGDT and LIDT but segment base addresses don't.
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 from within the kernel

Post by Pype.Clicker »

Tim Robinson wrote: Not physical -- linear. If you use LGDT or LIDT with paging enabled, you must use a virtual address. Paging applies to LGDT and LIDT but segment base addresses don't.
woow ? so if i enable paging and if i don't have identity mapping for the pages where GDT and IDT are, i must reload GDTR and IDTR in order to have the new virtual address (still referring to the same old physical address) loaded ?
Tim

Re:Initializing Paging from within the kernel

Post by Tim »

I'm not sure on this.

This works:
  • Set up GDT and switch to protected mode
  • Enable paging
  • Reload segment registers
And so does this:
  • Enable pmode, paging, etc.
  • Set up a new GDT (e.g. replacing the old one GRUB set up)
  • Use LGDT with virtual (paged) address
This doesn't:
  • Enable pmode, paging, etc.
  • Set up a new GDT
  • Use LGDT with physical (RAM) address
I had this situation when I started enabling paging in the assembly code stub of my kernel. It surprised me at the time until I figured out that LGDT was subject to page translation. I haven't looked it up in the Intel manuals but this sounds like the correct explanation. I guess LGDT caches the 'real' (physical) base address.
Curufir

Re:Initializing Paging from within the kernel

Post by Curufir »

Hmm, actually things get kinda odd once you start using paging and thinking about these instructions.

The intel manuals specificly state that GDTR/IDTR contain a linear base address and a limit.

Now without paging that's quite simple, linear = physical.

With paging enabled linear != physical though.

LGDT and LIDT also use a linear address, not logical. So they skip the selector:offset translation step.

Now with paging enabled those linear addresses get translated into physical via the page tables. So changing the page tables would screw up the GDT, which obviously doesn't happen.

Guess Tim's right and the physical address is cached in GDTR/IDTR, not the linear address.

Very confusing little area, and the manual isn't exactly transparent on the subject.

BTW, am I the only one confused by this. I always thought memory translation went:
Logical -> Linear -> Physical

So when people are using the term virtual do they mean linear?
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 from within the kernel

Post by Pype.Clicker »

Tim Robinson wrote: I guess LGDT caches the 'real' (physical) base address.
I don't feel so ... the GDT can span accross several pages, and i don't remember to have seen any constraints like "all the pages of the GDT must be physically contiguous in memory", which advocates for a paging-translated access to the GDT.

There is of course a cache of the physical base address ... but in the Translation Lookaside Buffers ...
Curufir

Re:Initializing Paging from within the kernel

Post by Curufir »

No way Pype, I just don't buy it.

Let's say your kernel reallocates the page the GDT was contained in, changing linear->physical address calculation. Now that would break your GDT/IDT completely because it would be being translated to the wrong physical address. Then there's the simple cost of translation (Why bother with it if you don't need it?) and for selector loading you simply don't need it.

Guess the only way to know about this for sure is to get paging working properly, load a new gdt, remap the page tables and flush the TLBs. I'm just not convinced that the GDT relies on that base address translation remaining valid after loading.
drizzt

Re:Initializing Paging from within the kernel

Post by drizzt »

Tim Robinson wrote: Not physical -- linear. If you use LGDT or LIDT with paging enabled, you must use a virtual address. Paging applies to LGDT and LIDT but segment base addresses don't.
That's true! I do it... I load my GDT & IDT after enbling paging with:

__asm__ __volatile__ ("lgdtl (%0)" : : "r"((dword)&gdt_ptr));

__asm__("lidtl (%0)" : : "r"((dword)&idt_ptr));

...where &gdt_ptr and &idt_ptr are virtual addresses.
Post Reply