aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAqua-sama <aqua@iserlohn-fortress.net>2021-03-08 22:39:16 +0200
committerAqua-sama <aqua@iserlohn-fortress.net>2021-03-09 10:13:26 +0200
commit170f3c0fe5def46c4d287a385e2354536fc5f693 (patch)
tree790bb4fc6b796894b1d1df3bf5d33f09d198bc1c
parentMove multiboot header to its own section (diff)
downloadkernel.cpp-170f3c0fe5def46c4d287a385e2354536fc5f693.tar.xz
Map kernel to higher half
-rw-r--r--drivers/cga.cc3
-rw-r--r--linker.ld26
-rw-r--r--makefile2
-rw-r--r--src/boot.S89
-rw-r--r--src/gdt.cc11
-rw-r--r--src/kernel.cc8
-rw-r--r--src/scheduler.cc4
7 files changed, 113 insertions, 30 deletions
diff --git a/drivers/cga.cc b/drivers/cga.cc
index 0646ff7..6589cee 100644
--- a/drivers/cga.cc
+++ b/drivers/cga.cc
@@ -21,8 +21,7 @@ constexpr uint8_t cursor_addr_l = 15; // 0xf
* 1 1 | blink fast
*/
constexpr uint8_t cursor_hide = 0b00100000;
-
-constexpr uint32_t address = 0xB8000;
+constexpr uint32_t address = 0xc03ff000;
CGA::CGA() {
buffer = reinterpret_cast<Entry*>(address);
diff --git a/linker.ld b/linker.ld
index cd4139c..5ff3b62 100644
--- a/linker.ld
+++ b/linker.ld
@@ -1,31 +1,36 @@
ENTRY(_start)
OUTPUT_FORMAT(elf32-i386)
+VADDR_BASE = 0xc0000000;
+
SECTIONS
{
- /* Begin putting sections at 1 MiB */
- . = 1M;
-
- /* First put the multiboot header, as it is required to be put very early
+ /*
+ * First put the multiboot header, as it is required to be put very early
* early in the image or the bootloader won't recognize the file format.
*/
+ . = 0;
+ _kernel_start = .;
.multiboot : {
*(.multiboot.header)
*(.multiboot.text)
}
- .text : {
+ /* Begin putting sections at 1 MiB */
+ . = VADDR_BASE + 1M;
+
+ .text ALIGN(4K) : AT(ADDR(.text) - VADDR_BASE) {
*(.text*)
}
/* Read-only data. */
- .rodata : {
+ .rodata ALIGN(4K) : AT(ADDR(.rodata) - VADDR_BASE) {
*(.rodata*)
}
/* Read-write data (initialized) */
- .data : {
- start_ctors = .;
+ .data ALIGN(4K) : AT(ADDR(.data) - VADDR_BASE) {
+ begin_ctors = .;
KEEP(*(.init_array)); /* global constructors */
end_ctors = .;
@@ -37,9 +42,10 @@ SECTIONS
}
/* Read-write data (uninitialized) and stack */
- .bss : {
+ .bss ALIGN(4K) : AT(ADDR(.bss) - VADDR_BASE) {
+ *(.pages)
*(.bss)
*(.stack)
}
-
+ _kernel_end = .;
}
diff --git a/makefile b/makefile
index afbe1d1..a7379d1 100644
--- a/makefile
+++ b/makefile
@@ -55,5 +55,5 @@ glitch.iso: glitch.elf grub/grub.cfg
@$(GRUB_MKRESCUE) -o $@ isodir
run: glitch.iso
- @$(EMU) $<
+ @$(EMU) $< -no-reboot -no-shutdown -d guest_errors -monitor stdio
diff --git a/src/boot.S b/src/boot.S
index b17aea3..635b38f 100644
--- a/src/boot.S
+++ b/src/boot.S
@@ -36,17 +36,95 @@ stack_bottom:
.skip 16 * 1024
stack_top:
+.section .pages, "aw", @nobits
+.align 4096
+boot_page_directory:
+ .skip 4096
+boot_page_table1:
+ .skip 4096
+
+
/*
The linker script specifies _start as the entry point to the kernel and the
bootloader will jump to this position once the kernel has been loaded.
*/
.section .multiboot.text, "ax"
-.extern kernel_constructors
-.extern kernel_main
.global _start
.type _start, @function
_start:
- mov $stack_bottom, %ebp
+ # Physical address of boot_page_table1.
+ movl $(boot_page_table1 - 0xC0000000), %edi
+ # First address to map is address 0.
+ # TODO: Start at the first kernel page instead. Alternatively map the first
+ # 1 MiB as it can be generally useful, and there's no need to
+ # specially map the VGA buffer.
+ movl $0, %esi
+ # Map 1023 pages. The 1024th will be the VGA text buffer.
+ movl $1023, %ecx
+
+1:
+ # Only map the kernel.
+ cmpl $_kernel_start, %esi
+ jl 2f
+ cmpl $(_kernel_end - 0xC0000000), %esi
+ jge 3f
+
+ # Map physical address as "present, writable". Note that this maps
+ # .text and .rodata as writable. Mind security and map them as non-writable.
+ movl %esi, %edx
+ orl $0x003, %edx
+ movl %edx, (%edi)
+
+2:
+ # Size of page is 4096 bytes.
+ addl $4096, %esi
+ # Size of entries in boot_page_table1 is 4 bytes.
+ addl $4, %edi
+ # Loop to the next entry if we haven't finished.
+ loop 1b
+
+3:
+ # Map VGA video memory to 0xC03FF000 as "present, writable".
+ movl $(0x000B8000 | 0x003), boot_page_table1 - 0xC0000000 + 1023 * 4
+
+ # The page table is used at both page directory entry 0 (virtually from 0x0
+ # to 0x3FFFFF) (thus identity mapping the kernel) and page directory entry
+ # 768 (virtually from 0xC0000000 to 0xC03FFFFF) (thus mapping it in the
+ # higher half). The kernel is identity mapped because enabling paging does
+ # not change the next instruction, which continues to be physical. The CPU
+ # would instead page fault if there was no identity mapping.
+
+ # Map the page table to both virtual addresses 0x00000000 and 0xC0000000.
+ movl $(boot_page_table1 - 0xC0000000 + 0x003), boot_page_directory - 0xC0000000 + 0
+ movl $(boot_page_table1 - 0xC0000000 + 0x003), boot_page_directory - 0xC0000000 + 768 * 4
+
+ # Set cr3 to the address of the boot_page_directory.
+ movl $(boot_page_directory - 0xC0000000), %ecx
+ movl %ecx, %cr3
+
+ # Enable paging and the write-protect bit.
+ movl %cr0, %ecx
+ orl $0x80010000, %ecx
+ movl %ecx, %cr0
+
+ # Jump to higher half with an absolute jump.
+ lea (kinit), %ecx
+ jmp *%ecx
+
+.section .text
+.extern kernel_constructors
+.extern kernel_main
+kinit:
+ # At this point, paging is fully set up and enabled.
+
+ # Unmap the identity mapping as it is now unnecessary.
+ movl $0, boot_page_directory + 0
+
+ # Reload crc3 to force a TLB flush so the changes to take effect.
+ movl %cr3, %ecx
+ movl %ecx, %cr3
+
+ #mov $stack_bottom, %ebp
mov $stack_top, %esp # point the stack pointer to the stack
/*
@@ -90,8 +168,3 @@ _start:
hang: hlt
jmp hang
-/*
-Set the size of the _start symbol to the current location '.' minus its start.
-This is useful when debugging or when you implement call tracing.
-*/
-.size _start, . - _start
diff --git a/src/gdt.cc b/src/gdt.cc
index cb210a2..0712187 100644
--- a/src/gdt.cc
+++ b/src/gdt.cc
@@ -6,12 +6,17 @@ using seg = GDT::SegmentDescriptor;
static_assert(sizeof(GDT::Pointer) == 6);
constexpr uint32_t null_sz = 0;
-constexpr uint32_t kseg_sz = 64 * 1024 * 1024 + 0xfff;
+
+/* TODO kcode should only contain the .text segment
+ * TODO kdata should contain the other segments
+ * */
+constexpr uint32_t kseg_start = 0;
+constexpr uint32_t kseg_sz = 0xffffffff;
static GDT::SegmentDescriptor segments[256]{
[GDT::null0] = seg::make<null_sz>(0, {}),
- [GDT::kcode] = seg::make<kseg_sz>(0, {.r_w = true, .exe = true, .segment = true, .present = true}),
- [GDT::kdata] = seg::make<kseg_sz>(0, {.r_w = true, .segment = true, .present = true}),
+ [GDT::kcode] = seg::make<kseg_sz>(kseg_start, {.r_w = true, .exe = true, .segment = true, .present = true}),
+ [GDT::kdata] = seg::make<kseg_sz>(kseg_start, {.r_w = true, .segment = true, .present = true}),
};
GDT::GDT() {
diff --git a/src/kernel.cc b/src/kernel.cc
index 372b5bb..33282db 100644
--- a/src/kernel.cc
+++ b/src/kernel.cc
@@ -24,10 +24,10 @@ typedef void (*constructor)();
extern "C" {
-constructor start_ctors;
+constructor begin_ctors;
constructor end_ctors;
void kernel_constructors() {
- for (constructor* i = &start_ctors; i != &end_ctors; ++i) (*i)();
+ for (constructor* i = &begin_ctors; i != &end_ctors; ++i) (*i)();
}
void dump_multiboot(uint32_t mb_magic, uint32_t mb_addr);
@@ -43,9 +43,9 @@ void kernel_main([[maybe_unused]] uint32_t mb_magic, [[maybe_unused]] uint32_t m
if constexpr (video0_console) Console::set(&video0);
#endif
- // printk("Hello, kernel World!\n");
+ printk("Hello, kernel World!\n");
- // dump_multiboot(mb_magic, mb_addr);
+ dump_multiboot(mb_magic, mb_addr + 0xc0000000);
// dump_gdt();
GDT gdt;
diff --git a/src/scheduler.cc b/src/scheduler.cc
index 4de9fff..cce15a8 100644
--- a/src/scheduler.cc
+++ b/src/scheduler.cc
@@ -19,8 +19,8 @@ Scheduler::Scheduler(uint16_t cs) : InterruptHandler(0x00) {
printk("add_task: ", add_task(stack_b, cs, task_b), '\n');
printk("add_task: ", add_task(stack_a, cs, task_a), '\n');
- printk("task0 eip: ", uhex{tasks[0]->eip}, '\n');
- printk("task1 eip: ", uhex{tasks[1]->eip}, '\n');
+ printk("task0 eip: ", uhex{tasks[1]->eip}, '\n');
+ printk("task1 eip: ", uhex{tasks[2]->eip}, '\n');
}
uint16_t Scheduler::add_task(uint8_t* stack, uint16_t cs, void (*entry)()) {