Finished implementing paging init and long mode switch

This commit is contained in:
2022-12-13 22:22:04 +00:00
parent 3402207602
commit 766667a6ad
5 changed files with 219 additions and 24 deletions

View File

@@ -15,6 +15,11 @@ SRC_DIRS := core
KERNEL_C_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c)) KERNEL_C_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c))
KERNEL_OBJ := $(addprefix $(BUILDDIR)/,$(KERNEL_C_FILES:.c=.o)) KERNEL_OBJ := $(addprefix $(BUILDDIR)/,$(KERNEL_C_FILES:.c=.o))
BUILD_ID := $(shell tools/generate_build_id.py --arch $(ARCH))
CFLAGS := -DBUILD_ID=\"$(BUILD_ID)\"
ASMFLAGS := -DBUILD_ID=\"$(BUILD_ID)\"
$(BUILDDIR)/$(KERNEL_EXEC): $(KERNEL_OBJ) $(ARCH_OBJ) $(BUILDDIR)/$(KERNEL_EXEC): $(KERNEL_OBJ) $(ARCH_OBJ)
@echo " \033[1;36mLINK\033[0m \033[1m$@\033[0m" @echo " \033[1;36mLINK\033[0m \033[1m$@\033[0m"
@mkdir -p $(@D) @mkdir -p $(@D)

View File

@@ -18,4 +18,6 @@ run: $(BUILDDIR)/$(KERNEL_EXEC) $(BUILDDIR)/$(KERNEL_EXEC).elf32
debug: $(BUILDDIR)/$(KERNEL_EXEC) $(BUILDDIR)/$(KERNEL_EXEC).elf32 debug: $(BUILDDIR)/$(KERNEL_EXEC) $(BUILDDIR)/$(KERNEL_EXEC).elf32
@echo " \033[1;93mBOOT\033[0m $<" @echo " \033[1;93mBOOT\033[0m $<"
@$(QEMU) -kernel $(BUILDDIR)/$(KERNEL_EXEC).elf32 -S -s @$(QEMU) \
-kernel $(BUILDDIR)/$(KERNEL_EXEC).elf32 -S -s \
-monitor stdio

View File

@@ -6,6 +6,8 @@
.set CHECKSUM, -(MAGIC + FLAGS) .set CHECKSUM, -(MAGIC + FLAGS)
/* the amount of memory to allocate for bootstrap page directories. */ /* the amount of memory to allocate for bootstrap page directories. */
/* with buffer size 0x1000 (enough for exactly one page directory)
/* we can map 1 GiB of virtual memory */
#define BOOTSTRAP_PDIR_SIZE 0x1000 #define BOOTSTRAP_PDIR_SIZE 0x1000
.extern start_64 # defined in start_64.S .extern start_64 # defined in start_64.S
@@ -13,12 +15,41 @@
.code32 .code32
.section .boot.rodata, "a", @progbits .section .boot.rodata, "a", @progbits
/*******
ERROR MESSAGE STRINGS
*******/
no_long_mode_err: no_long_mode_err:
.asciz "This system is not 64-bit. Press any key to reboot." .asciz "This system is not 64-bit. Press any key to reboot."
unsupported_cpu_err: unsupported_cpu_err:
.asciz "Your CPU is not supported by Magenta. Press any key to reboot." .asciz "Your CPU is not supported by Magenta. Press any key to reboot."
/*******
LONG MDOE BOOSTRAP GDT
*******/
bootstrap_gdt:
/* 0x00: null descriptor */
.long 0x0
.long 0x0
/* 0x08: kernel code segment */
.long 0x0000ffff
.long 0x002f9a00
/* 0x10: kernel data segment */
.long 0x0000ffff
.long 0x002f9200
bootstrap_gdt_ptr:
.word 24 /* 8 bytes for each entry in bootstrap_gdt */
.long bootstrap_gdt
/*******
LONG MODE BOOTSTRAP PAGING STRUCTURES
*******/
.section .boot.bss, "aw", @nobits .section .boot.bss, "aw", @nobits
bootstrap_pml4t: # a single PML4T bootstrap_pml4t: # a single PML4T
.skip 0x1000 .skip 0x1000
@@ -30,6 +61,9 @@ bootstrap_stack_bottom:
.skip 0x1000 .skip 0x1000
bootstrap_stack_top: bootstrap_stack_top:
/*******
MULTIBOOT HEADER
*******/
.section .boot.text, "ax", @progbits .section .boot.text, "ax", @progbits
.align 4 .align 4
.long MAGIC .long MAGIC
@@ -94,6 +128,8 @@ unsupported_cpu:
cli cli
hlt hlt
.global init_page_tables
.type init_page_tables, @function
init_page_tables: init_page_tables:
/* STEP 1: add an entry in the PML4T pointing to the PDPT. /* STEP 1: add an entry in the PML4T pointing to the PDPT.
NOTE that we actually add two entries in the PML4T that both point to the same PDPT. NOTE that we actually add two entries in the PML4T that both point to the same PDPT.
@@ -103,7 +139,7 @@ init_page_tables:
mov $bootstrap_pdpt, %esi mov $bootstrap_pdpt, %esi
# in %ESI, build a PML4T entry containing the base address of the PDPT # in %ESI, build a PML4T entry containing the base address of the PDPT
xor $0xFFF, %esi and $0xFFFFF000, %esi
or $0x3, %esi or $0x3, %esi
# add the PML4T entries at PML4T[0] and PML4T[511] # add the PML4T entries at PML4T[0] and PML4T[511]
@@ -111,8 +147,7 @@ init_page_tables:
add $0xFF8, %edi add $0xFF8, %edi
mov %esi, (%edi) mov %esi, (%edi)
/* STEP 2: initialise the PDPT. /* STEP 2: write the pgdir entries to the BEGINNING of the PDPT */
We need to create an entry in the PDPT for every page directory we intend to use. */
# BOOTSTRAP_PDIR_SIZE contains the total size of the page directory buffer. # BOOTSTRAP_PDIR_SIZE contains the total size of the page directory buffer.
# use it to calculate the number of page directories we're using. # use it to calculate the number of page directories we're using.
@@ -129,22 +164,61 @@ init_page_tables:
%EBX is where we build the PDPT entry. */ %EBX is where we build the PDPT entry. */
1: 1:
mov %esi, %ebx mov %esi, %ebx
xor $0xFFF, %ebx and $0xFFFFF000, %ebx
or $0x3, %ebx or $0x3, %ebx
# skip the first 4 bytes of the 8-byte entry, leaving them zero.
add $0x4, %edi
mov %ebx, (%edi) mov %ebx, (%edi)
add $0x1000, %esi add $0x1000, %esi
add $0x4, %edi add $0x8, %edi
sub $0x1, %eax sub $0x1, %eax
cmp $0x0, %eax cmp $0x0, %eax
jne 1b jne 1b
/* STEP 3: initialise the page directories. /* STEP 3: write the pgdir entries to the END of the PDPT */
Each page directory can be used to map 2MiB of virtual memory.
# BOOTSTRAP_PDIR_SIZE contains the total size of the page directory buffer.
# use it to calculate the number of page directories we're using.
mov $0, %edx
mov $BOOTSTRAP_PDIR_SIZE, %eax
mov $0x1000, %ebx
idiv %ebx
mov $bootstrap_pdpt, %edi
mov $bootstrap_pdir_buf, %esi
/* with the number of page directories in %EAX, calculate the starting index into the PDPT.
we need to duplicate the pgdir entries here to map the kernel at vaddr 0xffffffff80000000 and up */
mov %eax, %ecx
mov $0x8, %edx
mul %edx
xchg %eax, %ecx
add $0x1000, %edi
sub %ecx, %edi
sub $0x08, %edi # subtract one from the index here, otherwise the mapping will be at 0xffffffffc0000000
# (each entry in the array is 8 bytes long)
/* %ESI is a pointer into the pagedir buffer.
%EDI is a pointer into the PDPT.
%EAX is the total number of page directories.
%EBX is where we build the PDPT entry. */
2:
mov %esi, %ebx
and $0xFFFFF000, %ebx
or $0x3, %ebx
mov %ebx, (%edi)
add $0x1000, %esi
add $0x8, %edi
sub $0x1, %eax
cmp $0x0, %eax
jne 2b
/* STEP 4: initialise the page directories.
Each page directory entry can be used to map 2MiB of virtual memory.
The exact number of page directories in use is determined by BOOTSTRAP_PDIR_SIZE */ The exact number of page directories in use is determined by BOOTSTRAP_PDIR_SIZE */
/* the total number of page directory entries is stored in %EAX */ /* the total number of page directory entries is stored in %EAX */
@@ -160,24 +234,55 @@ init_page_tables:
%EAX is the total number of page directories. %EAX is the total number of page directories.
%EBX is where we build the pagedir entry. */ %EBX is where we build the pagedir entry. */
2: 3:
mov %esi, %ebx mov %esi, %ebx
xor $0xFFF, %ebx and $0xFFFFF000, %ebx
or $0x3, %ebx or $0x83, %ebx
# skip the first 4 bytes of the 8-byte entry, leaving them zero.
add $0x4, %edi
mov %ebx, (%edi) mov %ebx, (%edi)
add $0x200000, %esi add $0x200000, %esi
add $0x4, %edi add $0x8, %edi
dec %eax sub $0x1, %eax
jnz 2b
cmp $0x0, %eax
jne 3b
ret ret
.global long_mode_switch
.type long_mode_switch, @function
long_mode_switch: long_mode_switch:
ret /* load %CR3 with the physical address of the PML4T */
mov $bootstrap_pml4t, %eax
mov %eax, %cr3
/* enable long mode and the syscall/sysret instructions */
movl $0xC0000080, %ecx
rdmsr
orl $0x00000101, %eax
wrmsr
lgdt (bootstrap_gdt_ptr)
mov %cr4, %ecx
orl $0x00000020, %ecx
mov %ecx, %cr4
mov %cr0, %ecx
orl $0x8000002a, %ecx
mov %ecx, %cr0
mov $0x10, %ax
mov %ax, %ds
mov %ax, %es
mov %ax, %fs
mov %ax, %gs
ljmpl $0x08, $start_64
cli
hlt
.global _start .global _start
.type _start, @function .type _start, @function

View File

@@ -1,10 +1,57 @@
.code64
.section .boot.rodata, "a", @progbits
/*******
ERROR MESSAGE STRINGS
*******/
kernel_identifier:
.asciz " Socks kernel version " BUILD_ID " "
.section .boot.text, "ax", @progbits .section .boot.text, "ax", @progbits
.code64 print_kernel_identifier:
/* line 1: empty padding line */
mov $kernel_identifier, %rsi
mov $0xb8000, %rdi
1:
movw $0x7000, (%rdi) # black text on white background.
add $0x02, %rdi
inc %rsi
cmpb $0, (%rsi)
jne 1b
/* line 2: kernel identiifer */
mov $kernel_identifier, %rsi
mov $0xb80A0, %rdi
2:
movsb
movb $0x70, (%rdi) # black text on white background
inc %rdi
cmpb $0, (%rsi)
jne 2b
/* line 3: empty padding line */
mov $kernel_identifier, %rsi
mov $0xb8140, %rdi
1:
movw $0x7000, (%rdi) # black text on white background.
add $0x02, %rdi
inc %rsi
cmpb $0, (%rsi)
jne 1b
ret
.global start_64 .global start_64
.type start_64, @function .type start_64, @function
start_64: start_64:
mov $0xb8000, %rax call print_kernel_identifier
movb $77, (%rax)
inc %rax cli
movb $0xF, (%rax) hlt

36
tools/generate_build_id.py Executable file
View File

@@ -0,0 +1,36 @@
#!/usr/bin/env python3
import subprocess
import sys
def is_arg_set(name):
for arg in sys.argv:
if arg == '--{}'.format(name):
return True
return False
def get_arg(name):
ret_next = False
for arg in sys.argv:
if ret_next:
return arg
if arg == '--{}'.format(name):
ret_next = True
return ''
arch = get_arg('arch')
build_type = 'debug'
if is_arg_set('release'):
build_type = 'release'
current_tag = subprocess.check_output(['git', 'describe', '--tags', '--abbrev=0']).decode('utf-8').strip()
current_tag = current_tag[1:]
build_id = '{}/{}_{}'.format(current_tag, build_type, arch)
print('{}'.format(build_id.upper()))