Please help with PSE

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
Awe2K
Member
Member
Posts: 49
Joined: Sat Oct 24, 2015 3:14 am
Libera.chat IRC: awe2k

Please help with PSE

Post by Awe2K »

I'm following Higher Half kernel barebones tutorial.
So, my kernel is mapped to 0xFF000000 (phys. 0x100000)
But I have problem with creating page directory with PSE (4MB pages).
What am I doing wrong?

My paging.c:

Code: Select all

#include <stdint.h>
#define KERNEL_VIRTUAL_BASE 0xFF000000  // As in boot.s, where kernel will be mapped
#define KERNEL_PAGE_NUM KERNEL_VIRTUAL_BASE >> 22 // number of directory entry
#define PDE_PS 0b10000000	// Allows 4MB pages
#define PDE_PRESENT 0b1		// Tells that PDE exists
#define PDE_RW 0b10			// Tells that Page is R/W
#define PDE_US 0b100		// Tells that Page is User-Space

uint32_t page_directory[1024] __attribute__ ((aligned(0x1000)));
void setup_paging(void) {
        // Clear page_directory
	for (int i=0;i<1024;i++){
		page_directory[i]=0;	// Not present
	}

	// As in boot.s, map kernel to 0xFF000000
	// Flags: PS (4MB page), PRESENT, READ/WRITE
	page_directory[KERNEL_PAGE_NUM]=KERNEL_VIRTUAL_BASE|PDE_PS|PDE_PRESENT|PDE_RW;

        // Load new page directory
	__asm__ __volatile__ ("mov %0,%%cr3"::"r"(page_directory));
}

And boot.s:

Code: Select all

; vim:syntax=nasm
bits 32

; Definitions
KERNEL_CS equ 0x08
KERNEL_DS equ 0x10
USERMODE_CS equ 0x18
USERMODE_DS equ 0x20

STACK_SIZE          equ 0x1000 ; 4KB stack
THREAD_CONTEXT_SIZE equ 0x1000 ; 4KB just for thread struct

MBOOT_PAGE_ALIGN    equ 0x1
MBOOT_MEM_INFO      equ 0x2
MBOOT_USE_GFX       equ 0x4
MBOOT_HDR_MAGIC     equ 0x1BADB002
MBOOT_HDR_FLAGS     equ MBOOT_PAGE_ALIGN | MBOOT_MEM_INFO
MBOOT_CHECKSUM      equ -(MBOOT_HDR_MAGIC + MBOOT_HDR_FLAGS)

; 3GB offset for translating physical to virtual addresses
KERNEL_VIRTUAL_BASE equ 0xFF000000
; Page directory idx of kernel's 4MB PTE
KERNEL_PAGE_NUM     equ (KERNEL_VIRTUAL_BASE >> 22)

section .data
align 0x1000
; This PDE identity-maps the first 4MB of 32-bit physical address space
; bit 7: PS - kernel page is 4MB
; bit 1: RW - kernel page is R/W
; bit 0: P  - kernel page is present

;;;;;; HERE KERNEL IS MAPPED
;;; So, I'm just trying to clone these lines (except identity-mapping first 4MB) in C

boot_page_directory:
    dd 0x00000083   ; First 4MB, which will be unmapped later
    times (KERNEL_PAGE_NUM - 1) dd 0    ; Pages before kernel
    dd 0x00000083   ; Kernel 4MB at 3GB offset
    times (1024 - KERNEL_PAGE_NUM - 1) dd 0 ; Pages after kernel


section .text
align 4
; start of kernel image:
; Multiboot header
; note: you don't need Multiboot AOUT Kludge for an ELF kernel
multiboot:
    dd MBOOT_HDR_MAGIC
    dd MBOOT_HDR_FLAGS
    dd MBOOT_CHECKSUM
    ; Mem info (only valid if aout kludge flag set or ELF kernel)
    ;dd 0x00000000   ; header address
    ;dd 0x00000000   ; load address
    ;dd 0x00000000   ; load end address
    ;dd 0x00000000   ; bss end address
    ;dd 0x00000000   ; entry address
    ; Graphics requests (only valid if graphics flag set)
    ;dd 0x00000000   ; linear graphics
    ;dd 0            ; width
    ;dd 0            ; height
    ;dd 32           ; set to 32


extern kmain
global g_start
g_start:
    mov ecx, (boot_page_directory - KERNEL_VIRTUAL_BASE)
    mov cr3, ecx    ; Load page directory

    mov ecx, cr4
    or ecx, 0x00000010  ; Set PSE bit in CR4 to enable 4MB pages
    mov cr4, ecx

    mov ecx, cr0
    or ecx, 0x80000000  ; Set PG bit in CR0 to enable paging
    mov cr0, ecx

    ; EIP currently holds physical address, so we need a long jump to
    ; the correct virtual address to continue execution in kernel space
    lea ecx, [start_higher_half]
    jmp ecx     ; Absolute jump!!

start_higher_half:
    ; Unmap identity-mapped first 4MB of physical address space
    mov dword [boot_page_directory], 0
    invlpg [0]

    mov esp, kernel_stack_top ; set up stack pointer
    push eax    ; push header magic
    add ebx, KERNEL_VIRTUAL_BASE    ; make multiboot header pointer virtual
    push ebx    ; push header pointer (TODO: hopefully this isn't at an addr > 4MB)


    cli         ; disable interrupts
    call kmain

    cli
.hang:
    hlt
    jmp .hang

   main_thread_addr:
    resb THREAD_CONTEXT_SIZE    ; reserve 4KB for main kernel thread struct
kernel_stack_bottom:
    resb STACK_SIZE     ; reserve 4KB for kernel stack
kernel_stack_top:
Awe2K
Member
Member
Posts: 49
Joined: Sat Oct 24, 2015 3:14 am
Libera.chat IRC: awe2k

Re: Please help with PSE

Post by Awe2K »

So, now I simply can clone existing page directory and load it.

Is it dangerous to keep my page directory at address 0xFF000000?

Also, is it possible to keep 0xFF000000 page in all directories that will be used, to restore original?

Code: Select all

#include <stdint.h>
#define KERNEL_VIRTUAL_BASE 0xFF000000
#define KERNEL_PAGE_NUM KERNEL_VIRTUAL_BASE >> 22
#define PDE_PS 0b10000000	// Allows 4MB pages
#define PDE_PRESENT 0b1		// Tells that PDE exists
#define PDE_RW 0b10			// Tells that Page is R/W
#define PDE_US 0b100		// Tells that Page is User-Space

uint32_t* page_directory __attribute__ ((aligned(0x1000)));

void setup_paging(void) {

	page_directory=0xFF000000;     // Just give it static address. (DANGEROUS?)

	for (int i = 0; i < 1024; i++) {
		page_directory[i] = 0;	// Not present
	}

	uint32_t* old_page_directory;
	old_page_directory = read_cr3() + KERNEL_VIRTUAL_BASE;  // Obtain old pagedir address with offset
	for (int i = 0; i < 1024; i++) {
		sprint("[old] ");
		sprinth(i);                                                                   // Print some stuff into serial port (I'm using it for logging)
		sprint(" ");
		sprinth(old_page_directory[i]);
		sprint("\n");

		if (old_page_directory[i]!=0)                                            // Do not clone zero entries
		page_directory[i] = old_page_directory[i] ^ (0b1100000); // Strip dirty and accessed flags
	}

	// As in boot.s, kernel is at 0xFF100000
	// Flags: PS (4MB page), PRESENT, READ/WRITE
        // And page directory is at 0xFF000000

	old_page_directory=(unsigned int)old_page_directory-KERNEL_VIRTUAL_BASE;
	page_directory=(unsigned int)page_directory-KERNEL_VIRTUAL_BASE;

	__asm__ __volatile__ ("mov %0,%%cr3"::"r"(page_directory));  // Load that dir.
}

sebihepp
Member
Member
Posts: 190
Joined: Tue Aug 26, 2008 11:24 am
GitHub: https://github.com/sebihepp

Re: Please help with PSE

Post by sebihepp »

Is it dangerous to keep my page directory at address 0xFF000000?
You need to check, if that area of memory exists and if it is available. (not used by memory mapped io, etc.) If that's the case and you make sure you don't use the memory on that address, then you could use 0xFF000000 for one PageDir. But if you create a second copy, you will overwrite the first copy.

I would recommend using a static array of 1024 uint32_t variables as PageDir and create/copy other PageDirs only if I have a working memory manager.

You should also think about mapping the last PageDir Entry to Page Dir itself for easy access to all PageTables and the PageDir. See wiki for more information: http://wiki.osdev.org/Paging
Also, is it possible to keep 0xFF000000 page in all directories that will be used, to restore original?
Do you mean, if you can map the physical page 0xFF000000 in all PageDirs and PageTables? Yes, you may map this address in every PageDir and even for every virtual page.
Awe2K
Member
Member
Posts: 49
Joined: Sat Oct 24, 2015 3:14 am
Libera.chat IRC: awe2k

Re: Please help with PSE

Post by Awe2K »

sebihepp wrote:
Is it dangerous to keep my page directory at address 0xFF000000?
You need to check, if that area of memory exists and if it is available. (not used by memory mapped io, etc.) If that's the case and you make sure you don't use the memory on that address, then you could use 0xFF000000 for one PageDir. But if you create a second copy, you will overwrite the first copy.
I know that it may be used, another copies will be at other locations that differ from 0xFF000000.
I would recommend using a static array of 1024 uint32_t variables as PageDir and create/copy other PageDirs only if I have a working memory manager.

You should also think about mapping the last PageDir Entry to Page Dir itself for easy access to all PageTables and the PageDir. See wiki for more information: http://wiki.osdev.org/Paging
Also, is it possible to keep 0xFF000000 page in all directories that will be used, to restore original?
Do you mean, if you can map the physical page 0xFF000000 in all PageDirs and PageTables? Yes, you may map this address in every PageDir and even for every virtual page.
Okay.

About mapping last page dir entry to page dir: what if my page directory doesn't point to tables, but points directly to 4MB memory pages (then there's no need in tables, because they're all replaced by one big directory)?


Edit:

Here's my memory map, just how I see it needs to be done
(all addresses are virtual)
* 0x400000 - 0x800000 (4MB, may be bigger) - Memory chunk where applications are loaded.
* 0xFF000000 - 0xFF001000 - Page directory (static), all other directories (not only kernel) must point to this.
* 0xFF100000 - 0xFFF00000 - Kernel space chunk. (physically 0x100000 - for example, 0xE00000 (end of kernel)).
* 0xC0000000 - 0xC0100000 - Heap, or something like that (physically 0xE00000 (somewhere at the end of kernel) - 0xF00000)
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

Re: Please help with PSE

Post by BASICFreak »

Ok; as I do now want you to design something you may regret, take this into consideration:

Let's take a system with 4GB of ram - in which 3GB is usable (without PAE).
Now lets say your OS Code takes one 4MB page, OS Data another page, OS Stack another page.
and each "task" requires 3 pages, one for code, data, and stack (note these are minimum)

Now you can fit 1024 Page Directories in one page - which helps some here but:

The OS alone uses 3 pages
All the page directories use 1 page
And if each task is extremely small (3 pages each) you can only have a total of 254 tasks

Now, when you open task 255 - what do you do? You could:
Deny the task from starting
Kill another task to start a new one
or Cache another task to disk to free enough pages to start the task

Don't get me wrong you will always have a MAX tasks, just 4MB pages drops the number by about 1024 times. And unless you have (access to) large amounts of RAM [or each task uses (extremely) large amounts of RAM], PSE may become more trouble (overhead) than you thought.

Just remember:
sortie wrote:Paging is called paging because you need to draw it on pages in your notebook to succeed at it.

NOTE: I'm not telling you that you should not use PSE, I just want you to have some consideration on if you actually need to use PSE or not - as the reason to have just one table does not justify the use. (IMO)
BOS Source Thanks to GitHub
BOS Expanded Commentary
Both under active development!
Sortie wrote:
  • Don't play the role of an operating systems developer, be one.
  • Be truly afraid of undefined [behavior].
  • Your operating system should be itself, not fight what it is.
sebihepp
Member
Member
Posts: 190
Joined: Tue Aug 26, 2008 11:24 am
GitHub: https://github.com/sebihepp

Re: Please help with PSE

Post by sebihepp »

You may mix PSE with non PSE later.
For example: I use PSE in my first PageDir, so I don't need to set PageTables - But as soon as I am able to, I create a complete new PageDir without using PSE but PageTables.
Awe2K
Member
Member
Posts: 49
Joined: Sat Oct 24, 2015 3:14 am
Libera.chat IRC: awe2k

Re: Please help with PSE

Post by Awe2K »

BASICFreak wrote: Ok; as I do now want you to design something you may regret, take this into consideration:

Let's take a system with 4GB of ram - in which 3GB is usable (without PAE).
Now lets say your OS Code takes one 4MB page, OS Data another page, OS Stack another page.
and each "task" requires 3 pages, one for code, data, and stack (note these are minimum)

Now you can fit 1024 Page Directories in one page - which helps some here but:

The OS alone uses 3 pages
All the page directories use 1 page
And if each task is extremely small (3 pages each) you can only have a total of 254 tasks

Now, when you open task 255 - what do you do? You could:
Deny the task from starting
Kill another task to start a new one
or Cache another task to disk to free enough pages to start the task

Don't get me wrong you will always have a MAX tasks, just 4MB pages drops the number by about 1024 times. And unless you have (access to) large amounts of RAM [or each task uses (extremely) large amounts of RAM], PSE may become more trouble (overhead) than you thought.
As mentioned in Intel manual v3, you may choose two ways in PSE:
1. Page directory points directly to pages
2. Page directory points to tables, tables have references to pages.

So, I think after getting plain page directory to work, I will choose second way of paging.
User avatar
BASICFreak
Member
Member
Posts: 284
Joined: Fri Jan 16, 2009 8:34 pm
Location: Louisiana, USA

Re: Please help with PSE

Post by BASICFreak »

sebihepp wrote:You may mix PSE with non PSE later.
For example: I use PSE in my first PageDir, so I don't need to set PageTables - But as soon as I am able to, I create a complete new PageDir without using PSE but PageTables.
And I thought I mentioned that... Looking at my post I missed it... Thanks for the added info.
Awe2k wrote:As mentioned in Intel manual v3, you may choose two ways in PSE:
1. Page directory points directly to pages
2. Page directory points to tables, tables have references to pages.

So, I think after getting plain page directory to work, I will choose second way of paging.
Sounds like a good plan to me. I just wanted to make sure you were aware of possible issues if you used solely 4MB pages.

Anyways, good luck.
BOS Source Thanks to GitHub
BOS Expanded Commentary
Both under active development!
Sortie wrote:
  • Don't play the role of an operating systems developer, be one.
  • Be truly afraid of undefined [behavior].
  • Your operating system should be itself, not fight what it is.
Awe2K
Member
Member
Posts: 49
Joined: Sat Oct 24, 2015 3:14 am
Libera.chat IRC: awe2k

Re: Please help with PSE

Post by Awe2K »

BASICFreak wrote:
sebihepp wrote:You may mix PSE with non PSE later.
For example: I use PSE in my first PageDir, so I don't need to set PageTables - But as soon as I am able to, I create a complete new PageDir without using PSE but PageTables.
And I thought I mentioned that... Looking at my post I missed it... Thanks for the added info.
Awe2k wrote:As mentioned in Intel manual v3, you may choose two ways in PSE:
1. Page directory points directly to pages
2. Page directory points to tables, tables have references to pages.

So, I think after getting plain page directory to work, I will choose second way of paging.
Sounds like a good plan to me. I just wanted to make sure you were aware of possible issues if you used solely 4MB pages.

Anyways, good luck.
Thanks, I've already wrote simple virtual memory manager (maybe something like heap) - just allocates memory from address space.
Also, I forgot to say that you can use both ways:
Processor will use way (1) if PS bit of PDE is set, then PDE will point to page sized 4MB. If bit PS isn't set - it points to page table (way 2).
Post Reply