Merge branch 'feature-paging' into develop
Completed paging feature.
This commit is contained in:
commit
60c857324f
|
@ -2,6 +2,7 @@ bin/
|
|||
dep/
|
||||
build/
|
||||
tmp/
|
||||
.vscode/
|
||||
|
||||
# ---> C++
|
||||
# Compiled Object files
|
||||
|
|
19
Makefile
19
Makefile
|
@ -30,7 +30,7 @@ CPPSOURCES := $(shell find $(SRCDIR) -type f -name "*.$(CPPSRCEXT)")
|
|||
OBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(CSOURCES:.$(CSRCEXT)=.o)) $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(CPPSOURCES:.$(CPPSRCEXT)=.o))
|
||||
|
||||
#Get assembly source files and create objects from them
|
||||
ASSOURCES := $(shell find $(SRCDIR) -type f -name "*.$(ASSRCEXT)")
|
||||
ASSOURCES := $(shell find $(SRCDIR) -name global-$(ARCH) -prune -false -o -type f -name "*.$(ASSRCEXT)" -print)
|
||||
ASOBJECTS := $(patsubst $(SRCDIR)/%,$(BUILDDIR)/%,$(ASSOURCES:.$(ASSRCEXT)=.o))
|
||||
|
||||
#Find dependencies from C and C++ source files
|
||||
|
@ -48,7 +48,7 @@ FLAGS := -O2 -Wall -Wextra -g -D__is_kernel -ffreestanding -fstack-protector
|
|||
#Specific flags
|
||||
CFLAGS := $(FLAGS) -std=gnu99
|
||||
CXXFLAGS := $(FLAGS) -std=c++17
|
||||
ASFLAGS :=
|
||||
ASFLAGS := -g --gstabs+ --gdwarf-5
|
||||
|
||||
#Make sure certain directories are made
|
||||
$(shell mkdir -p $(BUILDDIR) $(DEPDIR) bin/)
|
||||
|
@ -61,27 +61,28 @@ $(shell mkdir -p $(patsubst $(SRCDIR)/%, $(DEPDIR)/%, $(TREE)))
|
|||
GLOBALARCHDIR := $(BUILDDIR)/arch/global-$(ARCH)
|
||||
|
||||
#Define/create the global constructor objects
|
||||
CRTBEGINOBJ := $($(C) $(CFLAGS) -print-file-name=crtbegin.o)
|
||||
CRTENDOBJ := $($(C) $(CFLAGS) -print-file-name=crtend.o)
|
||||
CRTBEGINOBJ := $(shell $(C) $(CFLAGS) -print-file-name=crtbegin.o)
|
||||
CRTENDOBJ := $(shell $(C) $(CFLAGS) -print-file-name=crtend.o)
|
||||
|
||||
CRTBEGIN := $(GLOBALARCHDIR)/crti.o $(CRTBEGINOBJ)
|
||||
CRTEND := $(CRTENDOBJ) $(GLOBALARCHDIR)/crtn.o
|
||||
|
||||
MAKEOBJS := $(GLOBALARCHDIR)/crti.o $(GLOBALARCHDIR)/crtn.o $(SRCDIR)/linker.ld $(OBJECTS) $(ASOBJECTS)
|
||||
|
||||
#Order the objects to prevent weird gcc bugs with global constructors
|
||||
MAINOBJS := $(CRTBEGIN) $(OBJECTS) $(ASOBJECTS) $(CRTEND)
|
||||
|
||||
#Compile Target
|
||||
bin/ZoarialBareOS.iso: bin/ZoarialBareOS.bin bin/grub.cfg
|
||||
grub2-file --is-x86-multiboot bin/ZoarialBareOS.bin
|
||||
mkdir -p $(BUILDDIR)/isodir/boot/grub
|
||||
cp bin/ZoarialBareOS.bin $(BUILDDIR)/isodir/boot/
|
||||
cp $(SRCDIR)/grub.cfg $(BUILDDIR)/isodir/boot/grub/grub.cfg
|
||||
grub2-mkrescue -o $@ $(BUILDDIR)/isodir
|
||||
|
||||
bin/ZoarialBareOS.bin: $(MAINOBJS)
|
||||
bin/ZoarialBareOS.bin: $(MAKEOBJS)
|
||||
@echo " Linking... $(MAINOBJS)"
|
||||
$(C) -T $(SRCDIR)/linker.ld $^ -o $@ -ffreestanding -O2 -nostdlib -lgcc
|
||||
grub2-file --is-x86-multiboot $@
|
||||
mkdir -p $(BUILDDIR)/isodir/boot/grub
|
||||
|
||||
$(C) -T $(SRCDIR)/linker.ld $(MAINOBJS) -o $@ -ffreestanding -O2 -nostdlib -lgcc
|
||||
|
||||
bin/grub.cfg: $(SRCDIR)/grub.cfg
|
||||
cp $(SRCDIR)/grub.cfg bin/grub.cfg
|
||||
|
|
|
@ -12,11 +12,17 @@ search for this signature in the first 8 KiB of the kernel file, aligned at a
|
|||
32-bit boundary. The signature is in its own section so the header can be
|
||||
forced to be within the first 8 KiB of the kernel file.
|
||||
*/
|
||||
.section .multiboot
|
||||
.section .multiboot.data, "aw", @progbits
|
||||
.align 4
|
||||
.long MAGIC
|
||||
.long FLAGS
|
||||
.long CHECKSUM
|
||||
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
.long 0
|
||||
|
||||
/*
|
||||
The multiboot standard does not define the value of the stack pointer register
|
||||
|
@ -30,18 +36,29 @@ System V ABI standard and de-facto extensions. The compiler will assume the
|
|||
stack is properly aligned and failure to align the stack will result in
|
||||
undefined behavior.
|
||||
*/
|
||||
.section .bss
|
||||
.section .bootstrap_stack, "aw", @nobits
|
||||
.align 16
|
||||
stack_bottom:
|
||||
.skip 16384 # 16 KiB
|
||||
stack_top:
|
||||
|
||||
# Preallocate pages used for paging. Don't hard-code addresses and assume they
|
||||
# are available, as the bootloader might have loaded its multiboot structures or
|
||||
# modules there. This lets the bootloader know it must avoid the addresses.
|
||||
.section .bss, "aw", @nobits
|
||||
.align 4096
|
||||
boot_page_directory:
|
||||
.skip 4096
|
||||
boot_page_table1:
|
||||
.skip 4096
|
||||
# Further page tables may be required if the kernel grows beyond 3 MiB.
|
||||
|
||||
/*
|
||||
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. It
|
||||
doesn't make sense to return from this function as the bootloader is gone.
|
||||
*/
|
||||
.section .text
|
||||
.section .paging.setup.text, "ax", @progbits
|
||||
.global _start
|
||||
.type _start, @function
|
||||
_start:
|
||||
|
@ -57,7 +74,80 @@ _start:
|
|||
itself. It has absolute and complete power over the
|
||||
machine.
|
||||
*/
|
||||
# Physical address of boot_page_table1.
|
||||
# TODO: I recall seeing some assembly that used a macro to do the
|
||||
# conversions to and from physical. Maybe this should be done in this
|
||||
# code as well?
|
||||
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 4f, %ecx
|
||||
jmp *%ecx
|
||||
|
||||
.section .text
|
||||
|
||||
4:
|
||||
# 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
|
||||
|
||||
/*
|
||||
To set up a stack, we set the esp register to point to the top of the
|
||||
stack (as it grows downwards on x86 systems). This is necessarily done
|
||||
|
@ -107,4 +197,4 @@ _start:
|
|||
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
|
||||
# .size _start, . - _start
|
||||
|
|
|
@ -37,7 +37,7 @@ void terminal_initialize(void)
|
|||
terminal_row = 0;
|
||||
terminal_column = 0;
|
||||
terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
|
||||
terminal_buffer = (uint16_t*) 0xB8000;
|
||||
terminal_buffer = (uint16_t*) 0xC03FF000;
|
||||
for (size_t y = 0; y < VGA_HEIGHT; y++) {
|
||||
for (size_t x = 0; x < VGA_WIDTH; x++) {
|
||||
const size_t index = y * VGA_WIDTH + x;
|
||||
|
|
|
@ -13,31 +13,46 @@ SECTIONS
|
|||
/* 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.
|
||||
Next we'll put the .text section. */
|
||||
.text BLOCK(4K) : ALIGN(4K)
|
||||
|
||||
_kernel_start = .;
|
||||
.multiboot.data ALIGN(4K) :
|
||||
{
|
||||
*(.multiboot.data)
|
||||
}
|
||||
|
||||
.paging.setup.text :
|
||||
{
|
||||
*(.paging.setup.text)
|
||||
}
|
||||
|
||||
. += 0xC0000000;
|
||||
|
||||
.text ALIGN(4K) : AT (ADDR (.text) - 0xC0000000)
|
||||
{
|
||||
*(.multiboot)
|
||||
*(.text)
|
||||
}
|
||||
|
||||
|
||||
/* Read-only data. */
|
||||
.rodata BLOCK(4K) : ALIGN(4K)
|
||||
.rodata ALIGN(4K) : AT (ADDR (.rodata) - 0xC0000000)
|
||||
{
|
||||
*(.rodata)
|
||||
}
|
||||
|
||||
/* Read-write data (initialized) */
|
||||
.data BLOCK(4K) : ALIGN(4K)
|
||||
.data ALIGN(4K) : AT (ADDR (.data) - 0xC0000000)
|
||||
{
|
||||
*(.data)
|
||||
}
|
||||
|
||||
/* Read-write data (uninitialized) and stack */
|
||||
.bss BLOCK(4K) : ALIGN(4K)
|
||||
.bss ALIGN(4K) : AT (ADDR (.bss) - 0xC0000000)
|
||||
{
|
||||
*(COMMON)
|
||||
*(.bss)
|
||||
*(.bootstrap_stack)
|
||||
}
|
||||
|
||||
/* The compiler may produce other sections, by default it will put them in
|
||||
a segment with the same name. Simply add stuff here as needed. */
|
||||
_kernel_end = .;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue