Issues with paging and virtual memory
Posted: Fri Oct 27, 2023 7:36 am
Hello everyone! I'm having issues with virtual memory and paging... I'm trying to map physical address 0x0 to virtual 0x0 (as a test)... I attached my paging source file, and linking script (grub, multiboot2 as bootloader). My main assembly file is like so:
The C file:
The link.ld file:
On the commented line which tries to access virtual memory location 0x0, a pagefault probably appears and the whole thing comes crashing down... Any help is largely appreciated, this thing has been bugging me for some time.
Code: Select all
; Kernel boot file
; Copyright (C) 2023 Panagiotis
MBOOT_HEADER_MAGIC equ 0xE85250D6
MBOOT_ARCH equ 0x00000000
KERNEL_STACK_SIZE equ 4096
global KERNEL_VIRTUAL_BASE
KERNEL_VIRTUAL_BASE equ 0xC0000000 ; 3GB
KERNEL_PAGE_NUMBER equ (KERNEL_VIRTUAL_BASE >> 22) ; Page directory index of kernel's 4MB PTE.
; Legacy from multiboot 1
; MBOOT_PAGE_ALIGN equ 1 << 0
; MBOOT_MEM_INFO equ 1 << 1
; MBOOT_GRAPH_MODE equ 1 << 2
; MBOOT_HEADER_FLAGS equ MBOOT_ARCH | MBOOT_HEADER_LEN
; MBOOT_CHECKSUM equ -(MBOOT_HEADER_MAGIC + MBOOT_HEADER_FLAGS)
bits 32
section .multiboot_header
header_start:
dd MBOOT_HEADER_MAGIC
dd MBOOT_ARCH
dd header_end - header_start
dd 0x100000000 - (MBOOT_HEADER_MAGIC + MBOOT_ARCH + (header_end - header_start))
; best -> 1024x768x32
align 8
dw 5
dw 1
dd 20
dd 1024
dd 768
dd 32
align 8
dw 0
dw 0
dd 8
header_end:
; setup stack
global boot_pagetab1
section .bss
align 4
stack_bottom:
resb KERNEL_STACK_SIZE ; 4 kib
stack_top:
section .boot
global _start
_start:
mov ecx, (BootPageDirectory - KERNEL_VIRTUAL_BASE) ; 0x104000
mov cr3, ecx ; Load Page Directory Base Register.
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
lea ecx, [higher_half]
jmp ecx
section .text
higher_half:
; Unmap the identity-mapped first 4MB of physical address space. It should not be needed
; anymore.
mov dword [BootPageDirectory], 0
invlpg [0]
mov esp, stack_bottom
add ebx, KERNEL_VIRTUAL_BASE ; make the address virtual
; add eax, KERNEL_VIRTUAL_BASE
push ebx
push eax
; push ebx ; multiboot mem info pointer
extern kmain
call kmain
global asmEnablePaging
asmEnablePaging:
; load page directory (eax has the address of the page directory)
mov eax, [esp+4]
mov cr3, eax
; enable 4MBpage
; mov ebx, cr4 ; read current cr4
; or ebx, 0x00000010 ; set PSE - enable 4MB page
; mov cr4, ebx ; update cr4
; enable paging
mov ebx, cr0 ; read current cr0
or ebx, 0x80000000 ; set PG . set pages as read-only for both userspace and supervisor, replace 0x80000000 above with 0x80010000, which also sets the WP bit.
mov cr0, ebx ; update cr0
ret ; now paging is enabled
halt:
hlt
jmp halt
section .data
align 0x1000
global BootPageDirectory
BootPageDirectory:
; This page directory entry identity-maps the first 4MB of the 32-bit physical address space.
; All bits are clear except the following:
; bit 7: PS The kernel page is 4MB.
; bit 1: RW The kernel page is read/write.
; bit 0: P The kernel page is present.
; This entry must be here -- otherwise the kernel will crash immediately after paging is
; enabled because it can't fetch the next instruction! It's ok to unmap this page later.
dd 0x00000083
times (KERNEL_PAGE_NUMBER - 1) dd 0 ; Pages before kernel space.
; This page directory entry defines a 4MB page containing the kernel.
dd 0x00000083
times (1024 - KERNEL_PAGE_NUMBER - 1) dd 0 ; Pages after the kernel image.
Code: Select all
#include "../../include/paging.h"
#include "../../include/types.h"
#include "../../include/util.h"
// Paging system thing
// Copyright (C) 2023 Panagiotis
enum page_size_t { FOUR_KB, FOUR_MB };
enum page_privilege_t { SUPERVISOR, USER };
enum page_permissions_t { READ_ONLY, READ_WRITE };
void invlpg(uint32_t addr) {
asm volatile("invlpg (%0)" : : "b"(addr) : "memory");
}
uint32_t make_page_directory_entry(uint32_t page_table_address,
enum page_size_t page_size,
bool cache_disabled, bool write_through,
enum page_privilege_t privelage,
enum page_permissions_t permissions,
bool present) {
uint32_t entry = page_table_address;
entry |= page_size << 7;
entry |= cache_disabled << 4;
entry |= write_through << 3;
entry |= privelage << 2;
entry |= permissions << 1;
entry |= present;
return entry;
}
uint32_t make_page_table_entry(uint32_t page_frame_address, bool global,
bool cache_disabled, bool write_through,
enum page_privilege_t privelage,
enum page_permissions_t permissions,
bool present) {
uint32_t entry = page_frame_address;
entry |= global << 8;
entry |= cache_disabled << 6;
entry |= write_through << 3;
entry |= privelage << 2;
entry |= permissions << 1;
entry |= present;
return entry;
}
extern void asmEnablePaging(uint32_t loc);
uint32_t *initialize_page_directory() {
uint32_t page_dir_virt_addr = &BootPageDirectory;
uint32_t page_dir_phys_addr = (uint32_t)&BootPageDirectory - 0xC0000000;
uint32_t page_table_virt_addr = &boot_pagetab1;
uint32_t page_table_phys_addr = (uint32_t)&boot_pagetab1 - 0xC0000000;
debugf("[pagedir] virt=%x phys=%x\n[pagetab] virt=%x phys=%x\n",
page_dir_virt_addr, page_dir_phys_addr, page_table_virt_addr,
page_table_phys_addr);
uint32_t *page_dir_ptr = (uint32_t *)page_dir_virt_addr;
uint32_t *page_table_ptr = (uint32_t *)page_table_virt_addr;
page_dir_ptr[0] = make_page_directory_entry(
page_table_phys_addr, FOUR_KB, false, true, SUPERVISOR, READ_WRITE, true);
page_table_ptr = make_page_table_entry(0x0, true, false, true, SUPERVISOR,
READ_WRITE, true);
page_dir_ptr[1023] = (uint32_t)make_page_directory_entry(
page_dir_phys_addr, FOUR_KB, false, false, SUPERVISOR, READ_WRITE, true);
debugf("enabling paging...\n");
asmEnablePaging(page_dir_phys_addr);
// debugf("hi? the var you asked for: [%x]\n", *(uint32_t *)(0x0));
uint32_t cr3;
asm volatile("mov %%cr3, %0" : "=r"(cr3));
debugf("scanned pagedir physical addr: %x\n", cr3);
return page_dir_ptr;
}
Code: Select all
ENTRY(_start)
SECTIONS {
. = 0x00100000;
kernel_start = .;
.multiboot_header ALIGN(4K) : {
*(.multiboot)
}
.boot ALIGN(4K) : {
*(.boot)
}
. += 0xC0000000;
.text ALIGN(4K) : AT(ADDR(.text) - 0xC0000000) {
*(.text)
}
.rodata ALIGN(4K) : AT(ADDR(.rodata) - 0xC0000000) {
*(.rodata)
}
.data ALIGN(4K) : AT(ADDR(.data) - 0xC0000000) {
*(.data)
}
.bss ALIGN(4K) : AT(ADDR(.bss) - 0xC0000000) {
*(COMMON)
*(.bss)
}
kernel_end = .;
}