No way of setting up 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.
abcd
Posts: 7
Joined: Mon Oct 21, 2019 11:38 am

No way of setting up paging

Post by abcd »

Hi all,
I have an higher half kernel, so the code is executing at 0xC0000000 and paging is enabled from the bootloader.
Now I want to create a new, let's say, real page directory.
So my steps are:
1) save registers and disable interrupts
2) allocate a page from the physical memory manager for the page directory
3) create the self referenced entry (asking a physical address)
4) create the kernel 4MB entry (asking a physical address)
5) set CR3
6) restore registers and renable interrupts

I think I got it right, but the code still throws a page fault when accessing the allocated page directory, however that is right because it is a physical address and not a virtual one.
I already checked other questions but I couldn't get it to work, so can you please explain what other steps should I take before accessing new pd?

Here's my code to understand better:

Code: Select all

void vmm_init() {
    uint32_t eflags = interrupt_save_disable();
	uint32_t *pd = pAllocPage();

    uint32_t *self_pde __attribute__((aligned(4096))) = (uint32_t)pAllocPage();
    memset(self_pde, 0, sizeof(self_pde));
	*self_pde = (uint32_t)pd | BIT_PD_PT_PRESENT | BIT_PD_PT_RW;
	pd[PAGE_DIRECTORY_INDEX(PD_VADDR)] = self_pde;

	uint32_t *kernel_pde __attribute__((aligned(4096))) = (uint32_t)pAllocPage();
	memset(kernel_pde, 0, sizeof(kernel_pde));
	*kernel_pde = (_start_addr_phys & 0xFFFFF000) | BIT_PD_PAGE_SIZE | BIT_PD_PT_PRESENT | BIT_PD_PT_RW;
	pdv[PAGE_DIRECTORY_INDEX(KERNEL_VIRTUAL_BASE)] = kernel_pde;

	set_cr3(pd);
	interrupt_restore(eflags);
}
User avatar
iansjack
Member
Member
Posts: 4812
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: No way of setting up paging

Post by iansjack »

You seem to be making the usual mistake of trying to access table entries with physical addresses (e.g. pd[]). This has been addressed several times in these forums.
linguofreak
Member
Member
Posts: 510
Joined: Wed Mar 09, 2011 3:55 am

Re: No way of setting up paging

Post by linguofreak »

abcd wrote: I think I got it right, but the code still throws a page fault when accessing the allocated page directory, however that is right because it is a physical address and not a virtual one.
I already checked other questions but I couldn't get it to work, so can you please explain what other steps should I take before accessing new pd?
When you're telling the CPU where to find a given paging structure (i.e, putting the page directory address in CR3 or writing a page table entry to the page directory) you must use the physical address.

When telling your code where to find a given paging structure, you need to use the virtual address.

Physical addresses are put into paging structures, virtual addresses are used to access them.
abcd
Posts: 7
Joined: Mon Oct 21, 2019 11:38 am

Re: No way of setting up paging

Post by abcd »

Thank you, but I already knew the problem. I just don't know how to solve it, and I couldn't find any solution on the internet.
In fact, every time I find a recursive paging tutorial the page directory is presumed to be setted up.
Octocontrabass
Member
Member
Posts: 5873
Joined: Mon Mar 25, 2013 7:01 pm

Re: No way of setting up paging

Post by Octocontrabass »

abcd wrote:In fact, every time I find a recursive paging tutorial the page directory is presumed to be setted up.
abcd wrote:paging is enabled from the bootloader.
Why doesn't the bootloader set up recursive paging?
User avatar
iansjack
Member
Member
Posts: 4812
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: No way of setting up paging

Post by iansjack »

What bootloader are you using that enables paging? You set up your initial page table, including a means to convert the physical addresses that it uses to virtual ones, before enabling paging.

Ignore my first post as I now realize that your code is before you enable paging. If the page table that you create doesn't work then it simply means that you haven't constructed it properly. Use a debugger to halt before you enable paging and inspect the page table. It should then be obvious where the error is and it should be easy enough to determine why. If necessary, single-step through your code to see exactly what is happening.
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Re: No way of setting up paging

Post by ~ »

You can reserve special visor pages and map the page table entries only, where they are, needed for physically remapping them in a static way via simple variables to the page tables containing the visor pages. Then modify the rest of the paging structures and memory through them. You would need to center on mapping the page table that will contain the visor pages, then you can view the rest of mapped or unmapped memory through those pages easily. Once you map a page table of your kernel, you have 1024 entries to physical pages that you can modify as you want in your kernel without disabling paging. You could reserve 4096 bytes in a kernel variable, align them to 4096 bytes, and call the variable kernel_visor_page_table -- Then you are free to modify the rest of the system through indirection with this variable.

Or, note that in 32-bit mode, if you disable/enable paging constantly, you don't even need to map paging structures back anywhere. You just disable paging, manipulate paging structures, and reenable it when ready.
Last edited by ~ on Tue Oct 22, 2019 9:20 am, edited 2 times in total.
User avatar
iansjack
Member
Member
Posts: 4812
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: No way of setting up paging

Post by iansjack »

Disabling paging is probably not a good idea with a higher-half kernel. (BANG!!!)

It's probably not a good idea in any case.
abcd
Posts: 7
Joined: Mon Oct 21, 2019 11:38 am

Re: No way of setting up paging

Post by abcd »

Octocontrabass wrote:Why doesn't the bootloader set up recursive paging?
Because it's a pain in the @$$ to do that... I mean here's the page directory that I set up:

Code: Select all

BootingPageDirectory:
    ; Identity mapped 4MB memory
    dd 0x00000083
    times(767) dd 0

    ; This page directory defines a 4MB page containing the kernel
    dd 0x00000083
    times(1024 - 767) dd 0
Now, at the end I should put the recursive entry, but in assembly I can't do something like:

Code: Select all

BootingPageDirectory:
    ; Identity mapped 4MB memory
    dd 0x00000083
    times(767) dd 0

    ; This page directory defines a 4MB page containing the kernel
    dd 0x00000083
    times(1024 - 767 - 1) dd 0
    dd BootingPageDirectory | 0x3 ; For the flags
Anyways, I want to replace it with a new one (I'm not sure if it's aligned well or allocated at the right place).
~ wrote:You can reserve special visor pages and map the page table entries only, where they are, needed for physically remapping them in a static way via simple variables to the page tables containing the visor pages. Then modify the rest of the paging structures and memory through them. You would need to center on mapping the page table that will contain the visor pages, then you can view the rest of mapped or unmapped memory through those pages easily. Once you map a page table of your kernel, you have 1024 entries to physical pages that you can modify as you want in your kernel without disabling paging. You could reserve 4096 bytes in a kernel variable, align them to 4096 bytes, and call the variable kernel_visor_page_table -- Then you are free to modify the rest of the system through indirection with this variable.
Yes... is there a better method though? I didn't understand it too well but I don't really like the idea of some static mapping, even if it can be change at every process switch or idk.
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Re: No way of setting up paging

Post by ~ »

If you want to be able to remap stuff around in your paging structures without page faults in the easiest way, you can do this:

Create a 4096-byte aligned variable called kernel_visor_page_table set to all zeroes on startup, also 4096-byte sized. It has to point to 4096 bytes.

Your page directory has 1024 entries. Your kernel will take a certain number of those. If it just takes the first Megabyte and a few Kilobytes, it will only take 1 page directory entry.

In your kernel, you can make that first page directory entry point to your 4096-byte-aligned kernel_visor_page_table so that it becomes a page table.

If you modify its entries, you can modify any unmapped pages.

But in this case, it will have a certain number of entries taken by
the kernel. You have to ensure that some of those entries are always free (for example the very last 16 entries of the page table) because you will need them as pointers to any other pages, specially page directories and page tables that now you no longer need to map anywhere else.

Think that now, with just that kernel-accessible page table:

- Your base page table is within the kernel.

- You have the last 16 entries.

- Your kernel contents must skip them for being able to be bigger than 4 Megabytes.

- With those 16 same pointers, you can remap them to access anything.

In NASM, it could be (skip 4096 for the page directory, and the next 4096 will be our mapped page table):

Code: Select all

;With this label variable we can freely
;manage the rest of memory without
;disabling paging if we reserve the last
;few page table entries as special visor pages,
;but then we also need labels for static
;pointers to those page table entries for
;immediate access to them from the kernel.
;More than 1 entry will only be useful for
;a proper multitasking environment that
;can modify page tables from several processes
;without disabling interrups (it's probably
;always unstable to do as seen by OSes
;like Windows, Linux...).
;;
align 4096
kernel_visor_page_table times 4096 db 0   ;Base address of page table

kernel_visor_pagetable0 equ kernel_visor_page_table+(4096-4)   ;Pointer to mapped page table entry to remap
kernel_visor_page0_ptr  equ (0000000000b<<22)|(1111111111b<<12)|(000000000000b)  ;const virtual base address of our remappeable physical page


Then to write the otherwise unmapped 4K physical page:

Code: Select all

;Point to last entry of the visor page table
;via visor page #0 const pointer
;(in C it should be kernel_visor_pagetable[0]):
;;
 mov widesi,kernel_visor_pagetable0

;Set it up mapping to test Megabyte #200:
;;
 mov dword[widesi],(1048576*120)|_FLAG_x86_32_pageDirectoryEntry_Bit0_Present_TRUE|_FLAG_x86_32_pageDirectoryEntry_Bit1_ReadWrite|_FLAG_x86_32_pageDirectoryEntry_Bit2_SupervisorLevel

;Write the start of Megabyte #200
;through this visor page (if you
;examine the emulator memory
;it will contain the string "TEST"
;at physical address 209715200):
;;
 mov dword[kernel_visor_page0_ptr],"TSET"     ;FINAL

abcd
Posts: 7
Joined: Mon Oct 21, 2019 11:38 am

Re: No way of setting up paging

Post by abcd »

Thank you. Now I get it better.
But how do you manage all the page tables then?
User avatar
~
Member
Member
Posts: 1228
Joined: Tue Mar 06, 2007 11:17 am
Libera.chat IRC: ArcheFire

Re: No way of setting up paging

Post by ~ »

You can zero out all structures when created, and then make your code treat any entry with all bits to 0 as free, so you need to always keep them coherent.

Also, you can use the AVL field of page tables as a page block marker (it can take 8 different values so 2 or 3 adjacent blocks from different allocations should keep different values).

You can only free when passing the allocated pointer to a free() function (with the colored blocks via the AVL field), or when getting rid of a virtual space by terminating a process.
abcd
Posts: 7
Joined: Mon Oct 21, 2019 11:38 am

Re: No way of setting up paging

Post by abcd »

Yeah, I lost you... sorry! :?
I just want to create a page directory, load it and set it.
Is there a way with paging enabled? Like when creating one for a new process, how should you create another pd without faulting?
User avatar
iansjack
Member
Member
Posts: 4812
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: No way of setting up paging

Post by iansjack »

Perhaps you should read this recent thread: viewtopic.php?f=1&t=35110
abcd
Posts: 7
Joined: Mon Oct 21, 2019 11:38 am

Re: No way of setting up paging

Post by abcd »

iansjack wrote:Perhaps you should read this recent thread: viewtopic.php?f=1&t=35110
Thank you for the suggestion, but it still doesn’t cover how to allocate a new page directory...
Post Reply