The frame buffer base address is 0x4000000000 and a 32-bit write to the base address includes the addresses 0x4000000000-0x4000000003.
The linear addresses give the following information:
Code: Select all
pml4e = 0
pdpte = 256
pde = 0
pte = 0
offset = 0 to 3
Below is the code for setting up the paging structures and enabling paging:
paging.h
Code: Select all
#include <stdint.h>
// using M = 50
typedef struct _pml4_table {
uint64_t p :1;
uint64_t rw :1;
uint64_t us :1;
uint64_t pwt :1;
uint64_t pcd :1;
uint64_t a :1;
uint64_t avl_1 :1;
uint64_t reserved_zero_1 :1;
uint64_t avl_2:4;
uint64_t pdpt_phy_addr :38;
uint64_t reserved_zero_2 :2;
uint64_t avl_3 :11;
uint64_t xd :1;
}__attribute__((packed)) pml4_table_t;
typedef struct _pae_page_directory_pointer_table{
uint64_t p :1;
uint64_t rw :1;
uint64_t us :1;
uint64_t pwt :1;
uint64_t pcd :1;
uint64_t a :1;
uint64_t avl_1 :1;
uint64_t ps_zero :1;
uint64_t avl_2 :4;
uint64_t pd_phy_addr :38;
uint64_t reserved_zero_1 :2;
uint64_t avl_3 :11;
uint64_t xd :1;
}__attribute__((packed)) pae_page_directory_pointer_table_t;
typedef struct _pae_page_directory_table {
uint64_t p :1;
uint64_t rw :1;
uint64_t us :1;
uint64_t pwt :1;
uint64_t pcd :1;
uint64_t a :1;
uint64_t avl_1 :1;
uint64_t ps_zero :1;
uint64_t avl_2 :4;
uint64_t pt_phy_addr :38;
uint64_t reserved_zero_1 :2;
uint64_t avl_3 :11;
uint64_t xd :1;
}__attribute__((packed)) pae_page_directory_table_t;
typedef struct _pae_page_table {
uint64_t p :1;
uint64_t rw :1;
uint64_t us :1;
uint64_t pwt :1;
uint64_t pcd :1;
uint64_t a :1;
uint64_t d :1;
uint64_t pat :1;
uint64_t g :1;
uint64_t avl_1 :3;
uint64_t page_4k_phy_addr :38;
uint64_t reserved_zero_1 :2;
uint64_t avl_2 :7;
uint64_t pk :4;
uint64_t xd :1;
}__attribute__((packed)) pae_page_table_t;
boot.c
Code: Select all
void setup_and_enable_paging(void)
{
volatile char *addr_1 = (void *) find_first_4096_byte_aligned_address(sys_var_ptr);
volatile pml4_table_t *pml4e = (pml4_table_t *)addr_1;
volatile pae_page_directory_pointer_table_t *pdpt_base = (pae_page_directory_pointer_table_t*) ((char *) pml4e + 0x1000);
volatile pae_page_directory_pointer_table_t *pdpte = (pae_page_directory_pointer_table_t*) ((char *) pdpt_base + (256 * 8));
volatile pae_page_directory_table_t *pde = (pae_page_directory_table_t *) ((char *) pdpt_base + 0x1000);
volatile pae_page_table_t *pte = (pae_page_table_t *) ((char *) pde + 0x1000);
unsigned long addr_2;
uint32_t cpu_edx, cpu_eax;
pml4e->p = 1;
pml4e->rw = 1;
pml4e->us = 1;
addr_2 = (unsigned long) pdpt_base;
pml4e->pdpt_phy_addr = (addr_2 >> 12) & 0x3FFFFFFFFF;
pdpte->p = 1;
pdpte->rw = 1;
pdpte->us = 1;
unsigned long addr_3;
addr_3 = (unsigned long) pde;
pdpte->pd_phy_addr = (addr_3 >> 12) & 0x3FFFFFFFFF;
pde->p = 1;
pde->rw = 1;
pde->us = 1;
// unsigned long addr_4 = (unsigned long) pt_base;
unsigned long addr_4 = (unsigned long) pte;
pde->pt_phy_addr = (addr_4 >> 12) & 0x3FFFFFFFFF;
pte->p = 1;
pte->rw = 1;
pte->us = 1;
unsigned long addr_5 = (unsigned long) 0x4000000000;
pte->page_4k_phy_addr = (addr_5 >> 12) & 0x3FFFFFFFFF;
__asm__ __volatile__("cli");
/* enable paging */
__asm__("mov r8, %0\n\t"
"call enable_paging"
::"m" (pml4e):"r8");
__asm__ __volatile__("sti");
}
volatile uint64_t *find_first_4096_byte_aligned_address(char *sys_var_ptr)
{
volatile char *addr = sys_var_ptr;
while((uint64_t) addr % 4096 != 0) {
addr++;
}
return (volatile uint64_t *) addr;
}
paging.asm
Code: Select all
; written in FASM assembly
format elf64
public enable_paging
section '.text' executable
; the first parameter pml4e is in r8 register
enable_paging:
; firstly, deactivate paging while in long mode
mov rbx, cr0
and ebx, 01111111111111111111111111111111b ; clear the PG bit (bit #31)
mov cr0, rbx
; flush the TLB
mov rcx, 0x0
mov cr3, rcx
; enable PAE
mov rdx, cr4
or edx, 100000b
mov cr4, rdx
; Set LME (long mode enable)
mov ecx, 0xC0000080
rdmsr
or eax, 100000000b
wrmsr
; point the CR3 register to the base address of pml4 table
mov cr3, r8
; enable paging
or ebx, 10000000000000000000000000000000b
mov cr0, rbx
ret
tty_io.c
Code: Select all
void put_red_pixel(void)
{
volatile uint32_t* addr = frame_buffer.frame_buffer_base;
*addr = 0xff0000;
}
Edits:
1. Updated the paging structures in `paging.h` according to osdev wiki's. Earlier I was using the structures from the Intel manual but I think I will use osdev wiki instructions for easiness.