shortcut definition
Code: Select all
#ifndef __sect
#define __sect(S) __attribute__((section(#S)))
#endif
#define __early __sect(.early)
#define __earlydata __sect(.earlydata)
Code: Select all
#ifndef __PAGING_H_
#define __PAGING_H_
#include <stddef.h>
#include "../ktypedef.h"
#define ENTRY_MASK 0xFFFFFFFFFF000UL // 1111 1111 1111 1111 1111 1111 1111 1111 1111 1111 0000 0000 0000
#define PDPTR_MASK 0xC0000000 // 1100 0000 0000 0000 0000 0000 0000 0000
#define PD_MASK 0x3FE00000 // 0011 1111 1110 0000 0000 0000 0000 0000
#define PT_MASK 0x001FF000 // 0000 0000 0001 1111 1111 0000 0000 0000
#define PO_MASK 0x00000FFF // 0000 0000 0000 0000 0000 1111 1111 1111
#define PAGE_SIZE 0x00001000 // 4 KIB
#define ENTRY_SIZE 0x00000200 // 512 entries
#define PT_SIZE_IN_BYTE (ENTRY_SIZE * sizeof(uint64_t))
#define PD_SIZE_IN_BYTE (ENTRY_SIZE * PT_SIZE_IN_BYTE)
#define KERNEL_VIRTUAL_BASE 0xC0100000
#define KERNEL_PHYSICAL_BASE 0x00100000
typedef struct kernel_mem_info {
uint32_t physical_start;
uint32_t physical_end;
uint32_t virtual_start;
uint32_t virtual_end;
} kernel_mem_info_t;
void __early map_page(vaddr_t from, size_t count, paddr_t physical);
void __early early_init_paging(kernel_mem_info_t kmem_info, uint32_t mb2_addr);
#endif // __PAGING_H_
Code: Select all
#include "paging.h"
#include "../asm.h"
uint32_t __earlydata _magic;
uint32_t __earlydata _addr;
uint64_t __earlydata *last_page_dir;
uint64_t __earlydata *last_page_tab;
uint64_t __earlydata page_dir_ptr_tab[4];
uint64_t __align(0x1000) __earlydata page_dir[ENTRY_SIZE * 4]; // must be aligned to page boundry
uint64_t __align(0x1000) __earlydata page_tab[ENTRY_SIZE * ENTRY_SIZE * 4];
#define ROUNDUP(x, y) (x % y ? x + (y - (x % y)) : x)
#define ROUNDDW(x, y) x - (x % y)
#define __to_entry(x) ((uint64_t)((uint32_t)x & ENTRY_MASK))
#define __tabn(x) (uint32_t)(((x & PT_MASK) >> 9) & ~3)
#define __dirn(x) (uint32_t)(((x & PD_MASK) >> 18) & ~3)
#define __ptrn(x) (uint32_t)((x & PDPTR_MASK) >> 30)
#define __pfn(x) (uint32_t)(x & 0xFFF)
#define __getd(x, y) (uint64_t *)(uint32_t)((x & ENTRY_MASK) | __dirn(y))
#define __gett(x, y) (uint64_t *)(uint32_t)((x & ENTRY_MASK) | __tabn(y))
#define __getp(x, y) (paddr_t)((x & ENTRY_MASK) | __pfn(y))
void __early map_page(vaddr_t from, size_t count, paddr_t physical) {
size_t c = count;
// Page schema for 32 bits PAE set, PSE unset:
// 2 | 9 | 9 | 12
for (; c > 0; from += 0x1000, physical += 0x1000, c -= 0x1000) {
uint32_t p = (from & PDPTR_MASK) >> 30; // _ptrn(from & PDPTR_MASK);
uint64_t pdpte_i = page_dir_ptr_tab[p];
// check PDPTEi, if P flag is not 1, or pdpte is zero
if (!(pdpte_i & 1) || !(pdpte_i & ENTRY_MASK)) {
pdpte_i = page_dir_ptr_tab[p] = __to_entry(last_page_dir) | 1;
last_page_dir += ENTRY_SIZE;
}
// retrieve page dir entry base on dir first element and [from]
uint64_t *pg_dir_entry = __getd(pdpte_i, from);
// Page table should not be zero
if (!(*pg_dir_entry & 1) || !(*pg_dir_entry & ENTRY_MASK)) {
*pg_dir_entry = __to_entry(last_page_tab) | 3;
last_page_tab += ENTRY_SIZE;
}
uint64_t *pg_tab_entry = __gett(*pg_dir_entry, from);
*pg_tab_entry = __to_entry(physical) | 3;
}
}
static paddr_t __early virt_to_phys(vaddr_t vaddr) {
uint64_t pdptr_e = page_dir_ptr_tab[__ptrn(vaddr)];
if ((pdptr_e & 1) == 0) { // directory not present
return 0;
}
uint64_t *pg_dir = __getd(pdptr_e, vaddr);
if ((*pg_dir & 1) == 0) {
return 0;
}
uint64_t *pg_tab = __gett(*pg_dir, vaddr);
if ((*pg_tab & 1) == 0) {
return 0;
}
paddr_t ret = __getp(*pg_tab, vaddr);
return ret;
}
void __early early_init_paging(kernel_mem_info_t kmem_info, uint32_t mb2_addr) {
last_page_dir = page_dir;
last_page_tab = page_tab;
uint32_t ksize = kmem_info.physical_end - kmem_info.physical_start;
// identity map first 1 MiB + kernel size.
// round up to nearest page boundry
uint32_t offset = ROUNDUP(0x100000 + ksize, 4096);
map_page((vaddr_t)0, offset, (paddr_t)0);
if (virt_to_phys(0x130000) != 0x130000) {
while (1) {
} // error
}
// identity map multiboot info loaded address.
uint32_t mb2_loaded = ROUNDDW(mb2_addr, 4096);
uint32_t size = *((uint32_t *)((void *)mb2_addr));
offset = ROUNDUP(size, 4096);
map_page((vaddr_t)mb2_loaded, offset, (paddr_t)mb2_loaded);
// map higher half to page, start from 0xC0100000
offset = ROUNDUP((kmem_info.physical_end - kmem_info.physical_start) + 0xB00000, 4096); // + 0x100000;
vaddr_t kvb = (vaddr_t)ROUNDUP(KERNEL_VIRTUAL_BASE, 4096);
paddr_t pss = (paddr_t)ROUNDUP(kmem_info.physical_start, 4096);
map_page(kvb, offset, pss);
if (virt_to_phys(KERNEL_VIRTUAL_BASE) != kmem_info.physical_start) {
while (1) {
} //error
}
if (virt_to_phys(0xc0403c4c) != 0x00403c4c) {
while (1) {
} // error
}
// move PDPTR to CR3
set_cr3((uint32_t)&page_dir_ptr_tab);
// set CR4.PAE bit
uint32_t cr4 = get_cr4();
cr4 |= 0x20;
set_cr4(cr4);
// set CR0.PG bit
uint32_t cr0 = get_cr0();
cr0 |= 0x80000000;
set_cr0(cr0);
}
Code: Select all
obj/paging.o: file format elf32-i386
Disassembly of section .text:
00000000 <get_cr0>:
...
f: c9 leave
10: c3 ret
00000011 <set_cr0>:
...
1c: c3 ret
0000001d <set_cr3>:
...
27: 5d pop %ebp
28: c3 ret
00000029 <get_cr4>:
...
38: c9 leave
39: c3 ret
0000003a <set_cr4>:
...
44: 5d pop %ebp
45: c3 ret
00000046 <map_page>:
46: 55 push %ebp
47: 89 e5 mov %esp,%ebp
...
2ed: 5d pop %ebp
2ee: c3 ret
000002ef <virt_to_phys>:
2ef: 55 push %ebp
2f0: 89 e5 mov %esp,%ebp
...
429: 5d pop %ebp
42a: c3 ret
0000042b <early_init_paging>:
42b: 55 push %ebp
42c: 89 e5 mov %esp,%ebp
...
5c7: c9 leave
5c8: c3 ret
EDIT:
Sub Makefile:
Code: Select all
NASM=nasm
GCC=i686-elf-gcc
ROOT := ~/projects/qios
OBJDIR := $(ROOT)/obj
SRCDIR := $(ROOT)/src
INC := $(SRCDIR)/include
SRC := $(wildcard *.asm)
CSRC := $(wildcard *.c)
OBJ := $(patsubst %.asm,$(OBJDIR)/%.o,$(SRC))
OBJ += $(patsubst %.c,$(OBJDIR)/%.o,$(CSRC))
ASFLAGS = -felf32 -g
CFLAGS=-std=c11 -ffreestanding -Wall -Wextra -Werror -masm=intel -g -O0 --verbose -I $(INC)
.PHONY: all clean
all : $(OBJ)
$(OBJDIR)/%.o : %.asm
$(NASM) $(ASFLAGS) -o $@ $<
$(OBJDIR)/%.o : %.c
$(GCC) -c $< -o $@ $(CFLAGS)
debug:
echo $(SRC)
echo $(Obj)
clean:
rm -f $(OBJ)
Code: Select all
make: Entering directory '/home/xxxxxx/projects/qios/src/arch/x86/boot'
rm -f ~/projects/qios/obj/load.o ~/projects/qios/obj/paging.o ~/projects/qios/obj/kernel.o
nasm -felf32 -g -o /home/xxxxxx/projects/qios/obj/load.o load.asm
load.asm:44: warning: dword data exceeds bounds [-w+number-overflow]
i686-elf-gcc -c paging.c -o /home/xxxxxx/projects/qios/obj/paging.o -std=c11 -ffreestanding -Wall -Wextra -Werror -masm=intel -g -O0 --verbose -I ~/projects/qios/src/include
Using built-in specs.
COLLECT_GCC=i686-elf-gcc
Target: i686-elf
Configured with: ../gcc-7.2.0/configure --target=i686-elf --prefix=/home/xxxxxx/opt/cross --disable-nls --enable-languages=c,c++ --without-headers
Thread model: single
gcc version 7.2.0 (GCC)
COLLECT_GCC_OPTIONS='-c' '-o' '/home/xxxxxx/projects/qios/obj/paging.o' '-std=c11' '-ffreestanding' '-Wall' '-Wextra' '-Werror' '-masm=intel' '-g' '-O0' '-v' '-I' '/home/xxxxxx/projects/qios/src/include' '-mtune=generic' '-march=pentiumpro'
/home/xxxxxx/opt/cross/libexec/gcc/i686-elf/7.2.0/cc1 -quiet -v -I /home/xxxxxx/projects/qios/src/include paging.c -quiet -dumpbase paging.c -masm=intel -mtune=generic -march=pentiumpro -auxbase-strip /home/xxxxxx/projects/qios/obj/paging.o -g -O0 -Wall -Wextra -Werror -std=c11 -version -ffreestanding -o /tmp/ccoajh9T.s
GNU C11 (GCC) version 7.2.0 (i686-elf)
compiled by GNU C version 7.2.0, GMP version 6.1.2, MPFR version 3.1.6, MPC version 1.0.3, isl version isl-0.18-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/../../../../i686-elf/sys-include"
ignoring nonexistent directory "/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/../../../../i686-elf/include"
#include "..." search starts here:
#include <...> search starts here:
/home/xxxxxx/projects/qios/src/include
/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/include
/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/include-fixed
End of search list.
GNU C11 (GCC) version 7.2.0 (i686-elf)
compiled by GNU C version 7.2.0, GMP version 6.1.2, MPFR version 3.1.6, MPC version 1.0.3, isl version isl-0.18-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 01f7fd9f29241f2582c96ff0f48ee445
COLLECT_GCC_OPTIONS='-c' '-o' '/home/xxxxxx/projects/qios/obj/paging.o' '-std=c11' '-ffreestanding' '-Wall' '-Wextra' '-Werror' '-masm=intel' '-g' '-O0' '-v' '-I' '/home/xxxxxx/projects/qios/src/include' '-mtune=generic' '-march=pentiumpro'
/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/../../../../i686-elf/bin/as -o /home/xxxxxx/projects/qios/obj/paging.o /tmp/ccoajh9T.s
COMPILER_PATH=/home/xxxxxx/opt/cross/libexec/gcc/i686-elf/7.2.0/:/home/xxxxxx/opt/cross/libexec/gcc/i686-elf/7.2.0/:/home/xxxxxx/opt/cross/libexec/gcc/i686-elf/:/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/:/home/xxxxxx/opt/cross/lib/gcc/i686-elf/:/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/../../../../i686-elf/bin/
LIBRARY_PATH=/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/:/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/../../../../i686-elf/lib/
COLLECT_GCC_OPTIONS='-c' '-o' '/home/xxxxxx/projects/qios/obj/paging.o' '-std=c11' '-ffreestanding' '-Wall' '-Wextra' '-Werror' '-masm=intel' '-g' '-O0' '-v' '-I' '/home/xxxxxx/projects/qios/src/include' '-mtune=generic' '-march=pentiumpro'
i686-elf-gcc -c kernel.c -o /home/xxxxxx/projects/qios/obj/kernel.o -std=c11 -ffreestanding -Wall -Wextra -Werror -masm=intel -g -O0 --verbose -I ~/projects/qios/src/include
Using built-in specs.
COLLECT_GCC=i686-elf-gcc
Target: i686-elf
Configured with: ../gcc-7.2.0/configure --target=i686-elf --prefix=/home/xxxxxx/opt/cross --disable-nls --enable-languages=c,c++ --without-headers
Thread model: single
gcc version 7.2.0 (GCC)
COLLECT_GCC_OPTIONS='-c' '-o' '/home/xxxxxx/projects/qios/obj/kernel.o' '-std=c11' '-ffreestanding' '-Wall' '-Wextra' '-Werror' '-masm=intel' '-g' '-O0' '-v' '-I' '/home/xxxxxx/projects/qios/src/include' '-mtune=generic' '-march=pentiumpro'
/home/xxxxxx/opt/cross/libexec/gcc/i686-elf/7.2.0/cc1 -quiet -v -I /home/xxxxxx/projects/qios/src/include kernel.c -quiet -dumpbase kernel.c -masm=intel -mtune=generic -march=pentiumpro -auxbase-strip /home/xxxxxx/projects/qios/obj/kernel.o -g -O0 -Wall -Wextra -Werror -std=c11 -version -ffreestanding -o /tmp/ccRfYOyW.s
GNU C11 (GCC) version 7.2.0 (i686-elf)
compiled by GNU C version 7.2.0, GMP version 6.1.2, MPFR version 3.1.6, MPC version 1.0.3, isl version isl-0.18-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
ignoring nonexistent directory "/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/../../../../i686-elf/sys-include"
ignoring nonexistent directory "/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/../../../../i686-elf/include"
#include "..." search starts here:
#include <...> search starts here:
/home/xxxxxx/projects/qios/src/include
/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/include
/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/include-fixed
End of search list.
GNU C11 (GCC) version 7.2.0 (i686-elf)
compiled by GNU C version 7.2.0, GMP version 6.1.2, MPFR version 3.1.6, MPC version 1.0.3, isl version isl-0.18-GMP
GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
Compiler executable checksum: 01f7fd9f29241f2582c96ff0f48ee445
COLLECT_GCC_OPTIONS='-c' '-o' '/home/xxxxxx/projects/qios/obj/kernel.o' '-std=c11' '-ffreestanding' '-Wall' '-Wextra' '-Werror' '-masm=intel' '-g' '-O0' '-v' '-I' '/home/xxxxxx/projects/qios/src/include' '-mtune=generic' '-march=pentiumpro'
/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/../../../../i686-elf/bin/as -o /home/xxxxxx/projects/qios/obj/kernel.o /tmp/ccRfYOyW.s
COMPILER_PATH=/home/xxxxxx/opt/cross/libexec/gcc/i686-elf/7.2.0/:/home/xxxxxx/opt/cross/libexec/gcc/i686-elf/7.2.0/:/home/xxxxxx/opt/cross/libexec/gcc/i686-elf/:/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/:/home/xxxxxx/opt/cross/lib/gcc/i686-elf/:/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/../../../../i686-elf/bin/
LIBRARY_PATH=/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/:/home/xxxxxx/opt/cross/lib/gcc/i686-elf/7.2.0/../../../../i686-elf/lib/
COLLECT_GCC_OPTIONS='-c' '-o' '/home/xxxxxx/projects/qios/obj/kernel.o' '-std=c11' '-ffreestanding' '-Wall' '-Wextra' '-Werror' '-masm=intel' '-g' '-O0' '-v' '-I' '/home/xxxxxx/projects/qios/src/include' '-mtune=generic' '-march=pentiumpro'
make: Leaving directory '/home/xxxxxx/projects/qios/src/arch/x86/boot'