diff --git a/Makefile b/Makefile index 91114a0..2c7b451 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,11 @@ SRC_DIRS := core KERNEL_C_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c)) 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) @echo " \033[1;36mLINK\033[0m \033[1m$@\033[0m" @mkdir -p $(@D) diff --git a/arch/x86_64/extra.mk b/arch/x86_64/extra.mk index a085868..96054af 100644 --- a/arch/x86_64/extra.mk +++ b/arch/x86_64/extra.mk @@ -18,4 +18,6 @@ run: $(BUILDDIR)/$(KERNEL_EXEC) $(BUILDDIR)/$(KERNEL_EXEC).elf32 debug: $(BUILDDIR)/$(KERNEL_EXEC) $(BUILDDIR)/$(KERNEL_EXEC).elf32 @echo " \033[1;93mBOOT\033[0m $<" - @$(QEMU) -kernel $(BUILDDIR)/$(KERNEL_EXEC).elf32 -S -s + @$(QEMU) \ + -kernel $(BUILDDIR)/$(KERNEL_EXEC).elf32 -S -s \ + -monitor stdio diff --git a/arch/x86_64/start_32.S b/arch/x86_64/start_32.S index 45879df..a9a44df 100644 --- a/arch/x86_64/start_32.S +++ b/arch/x86_64/start_32.S @@ -6,6 +6,8 @@ .set CHECKSUM, -(MAGIC + FLAGS) /* 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 .extern start_64 # defined in start_64.S @@ -13,12 +15,41 @@ .code32 .section .boot.rodata, "a", @progbits + +/******* + ERROR MESSAGE STRINGS + *******/ no_long_mode_err: .asciz "This system is not 64-bit. Press any key to reboot." unsupported_cpu_err: .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 bootstrap_pml4t: # a single PML4T .skip 0x1000 @@ -30,6 +61,9 @@ bootstrap_stack_bottom: .skip 0x1000 bootstrap_stack_top: +/******* + MULTIBOOT HEADER + *******/ .section .boot.text, "ax", @progbits .align 4 .long MAGIC @@ -94,6 +128,8 @@ unsupported_cpu: cli hlt +.global init_page_tables +.type init_page_tables, @function init_page_tables: /* 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. @@ -103,7 +139,7 @@ init_page_tables: mov $bootstrap_pdpt, %esi # in %ESI, build a PML4T entry containing the base address of the PDPT - xor $0xFFF, %esi + and $0xFFFFF000, %esi or $0x3, %esi # add the PML4T entries at PML4T[0] and PML4T[511] @@ -111,8 +147,7 @@ init_page_tables: add $0xFF8, %edi mov %esi, (%edi) - /* STEP 2: initialise the PDPT. - We need to create an entry in the PDPT for every page directory we intend to use. */ + /* STEP 2: write the pgdir entries to the BEGINNING of the PDPT */ # BOOTSTRAP_PDIR_SIZE contains the total size of the page directory buffer. # 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. */ 1: mov %esi, %ebx - xor $0xFFF, %ebx + and $0xFFFFF000, %ebx or $0x3, %ebx - # skip the first 4 bytes of the 8-byte entry, leaving them zero. - add $0x4, %edi mov %ebx, (%edi) add $0x1000, %esi - add $0x4, %edi + add $0x8, %edi sub $0x1, %eax cmp $0x0, %eax jne 1b - /* STEP 3: initialise the page directories. - Each page directory can be used to map 2MiB of virtual memory. + /* STEP 3: write the pgdir entries to the END of the PDPT */ + + # 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 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. %EBX is where we build the pagedir entry. */ -2: +3: mov %esi, %ebx - xor $0xFFF, %ebx - or $0x3, %ebx + and $0xFFFFF000, %ebx + or $0x83, %ebx - # skip the first 4 bytes of the 8-byte entry, leaving them zero. - add $0x4, %edi mov %ebx, (%edi) add $0x200000, %esi - add $0x4, %edi - dec %eax - jnz 2b + add $0x8, %edi + sub $0x1, %eax + + cmp $0x0, %eax + jne 3b ret +.global long_mode_switch +.type long_mode_switch, @function 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 .type _start, @function diff --git a/arch/x86_64/start_64.S b/arch/x86_64/start_64.S index bc71982..5929e5f 100644 --- a/arch/x86_64/start_64.S +++ b/arch/x86_64/start_64.S @@ -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 -.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 .type start_64, @function start_64: - mov $0xb8000, %rax - movb $77, (%rax) - inc %rax - movb $0xF, (%rax) + call print_kernel_identifier + + cli + hlt diff --git a/tools/generate_build_id.py b/tools/generate_build_id.py new file mode 100755 index 0000000..1a0409c --- /dev/null +++ b/tools/generate_build_id.py @@ -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()))