From 340220760205600de02bb7168216ce078cf783e5 Mon Sep 17 00:00:00 2001 From: Max Wash Date: Tue, 13 Dec 2022 20:21:28 +0000 Subject: [PATCH] Added build system and some core boot files --- .gitignore | 149 ++++++++++++++++------ Makefile | 44 +++++++ arch/x86_64/config.mk | 2 + arch/x86_64/extra.mk | 21 ++++ arch/x86_64/layout.ld | 56 +++++++++ arch/x86_64/start_32.S | 213 ++++++++++++++++++++++++++++++++ arch/x86_64/start_64.S | 10 ++ core/main.c | 4 + tools/make/clang-generic.mk | 5 + tools/make/gcc-cross-compile.mk | 8 ++ 10 files changed, 472 insertions(+), 40 deletions(-) create mode 100644 Makefile create mode 100644 arch/x86_64/config.mk create mode 100644 arch/x86_64/extra.mk create mode 100644 arch/x86_64/layout.ld create mode 100644 arch/x86_64/start_32.S create mode 100644 arch/x86_64/start_64.S create mode 100644 core/main.c create mode 100644 tools/make/clang-generic.mk create mode 100644 tools/make/gcc-cross-compile.mk diff --git a/.gitignore b/.gitignore index 55e98e4..846532f 100644 --- a/.gitignore +++ b/.gitignore @@ -1,50 +1,59 @@ -# Created by https://www.gitignore.io/api/c++,vim,linux,cmake,windows +# Created by https://www.toptal.com/developers/gitignore/api/vim,macos,windows,linux,rust,c +# Edit at https://www.toptal.com/developers/gitignore?templates=vim,macos,windows,linux,rust,c -### C++ ### +### C ### # Prerequisites *.d -# Compiled Object files -*.slo -*.lo +# Object files *.o +*.ko *.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp # Precompiled Headers *.gch *.pch -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Fortran module files -*.mod -*.smod - -# Compiled Static libraries -*.lai -*.la -*.a +# Libraries *.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib # Executables *.exe *.out *.app +*.i*86 +*.x86_64 +*.hex -### CMake ### -CMakeCache.txt -CMakeFiles -CMakeScripts -Testing -Makefile -cmake_install.cmake -install_manifest.txt -compile_commands.json -CTestTestfile.cmake -build +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf ### Linux ### *~ @@ -61,25 +70,86 @@ build # .nfs files are created when an open file is removed but is still being accessed .nfs* +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Rust ### +# Generated by Cargo +# will have compiled files and executables +debug/ +target/ + +# Remove Cargo.lock from gitignore if creating an executable, leave it for libraries +# More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html +Cargo.lock + +# These are backup files generated by rustfmt +**/*.rs.bk + +# MSVC Windows builds of rustc generate these, which store debugging information + ### Vim ### -# swap -.sw[a-p] -.*.sw[a-p] -# session +# Swap +[._]*.s[a-v][a-z] +!*.svg # comment out if you don't need vector files +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session Session.vim -# temporary +Sessionx.vim + +# Temporary .netrwhist -# auto-generated tag files +# Auto-generated tag files tags +# Persistent undo +[._]*.un~ ### Windows ### # Windows thumbnail cache files Thumbs.db +Thumbs.db:encryptable ehthumbs.db ehthumbs_vista.db +# Dump file +*.stackdump + # Folder config file -Desktop.ini +[Dd]esktop.ini # Recycle Bin used on file shares $RECYCLE.BIN/ @@ -87,15 +157,14 @@ $RECYCLE.BIN/ # Windows Installer files *.cab *.msi +*.msix *.msm *.msp # Windows shortcuts *.lnk +# End of https://www.toptal.com/developers/gitignore/api/vim,macos,windows,linux,rust,c -# End of https://www.gitignore.io/api/c++,vim,linux,cmake,windows - -.DS_Store +build .clang-format -.ccls-cache diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..91114a0 --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ +KERNEL_EXEC := socks_kernel + +ARCH := x86_64 + +include tools/make/gcc-cross-compile.mk +include arch/$(ARCH)/config.mk + +BUILDDIR := build + +ARCH_C_FILES := $(wildcard arch/$(ARCH)/*.c) +ARCH_ASM_FILES := $(wildcard arch/$(ARCH)/*.S) +ARCH_OBJ := $(addprefix $(BUILDDIR)/,$(ARCH_C_FILES:.c=.o) $(ARCH_ASM_FILES:.S=.o)) + +SRC_DIRS := core +KERNEL_C_FILES := $(foreach dir,$(SRC_DIRS),$(wildcard $(dir)/*.c)) +KERNEL_OBJ := $(addprefix $(BUILDDIR)/,$(KERNEL_C_FILES:.c=.o)) + +$(BUILDDIR)/$(KERNEL_EXEC): $(KERNEL_OBJ) $(ARCH_OBJ) + @echo " \033[1;36mLINK\033[0m \033[1m$@\033[0m" + @mkdir -p $(@D) + @$(LD) $^ -o $@ $(LDFLAGS) $(ARCH_LDFLAGS) + +$(BUILDDIR)/%.o: %.S + @echo " \033[1;32mASM\033[0m $<" + @mkdir -p $(@D) + @$(ASM) $< -o $@ -c $(ASMFLAGS) $(ARCH_ASMFLAGS) + +$(BUILDDIR)/%.o: %.c + @echo " \033[1;32mCC\033[0m $<" + @mkdir -p $(@D) + @$(CC) $< -o $@ -c $(CFLAGS) $(ARCH_CFLAGS) + +clean: + @echo " \033[1;93mCLEAN\033[0m Deleting build artefacts." + @rm -rf $(BUILDDIR) + + +all: $(BUILDDIR)/$(KERNEL_EXEC) + +include arch/$(ARCH)/extra.mk + +.PHONY: all + +.INTERMEDIATE: $(ARCH_TEMP_FILES) diff --git a/arch/x86_64/config.mk b/arch/x86_64/config.mk new file mode 100644 index 0000000..e4a432a --- /dev/null +++ b/arch/x86_64/config.mk @@ -0,0 +1,2 @@ +ARCH_CFLAGS := -z max-page-size=0x1000 -m64 -mcmodel=large -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -D_64BIT -DBYTE_ORDER=1234 +ARCH_LDFLAGS := -z max-page-size=0x1000 -T arch/x86_64/layout.ld diff --git a/arch/x86_64/extra.mk b/arch/x86_64/extra.mk new file mode 100644 index 0000000..a085868 --- /dev/null +++ b/arch/x86_64/extra.mk @@ -0,0 +1,21 @@ +QEMU := qemu-system-x86_64 + +ARCH_TEMP_FILES := $(BUILDDIR)/$(KERNEL_EXEC).elf32 + +# qemu refuses to boot ELF64 binaries. this creates a patched version of the kernel +# binary to trick qemu into thinking its an ELF32. +# this has no effect on the kernel itself; the x86_64 kernel's +# entry point is 32-bit machine code. +$(BUILDDIR)/$(KERNEL_EXEC).elf32: $(BUILDDIR)/$(KERNEL_EXEC) + @cp $(BUILDDIR)/$(KERNEL_EXEC) $(BUILDDIR)/$(KERNEL_EXEC).elf32 + @printf '\x03\x00' | dd of=$(BUILDDIR)/$(KERNEL_EXEC).elf32 bs=1 seek=18 count=2 conv=notrunc 2> /dev/null + +run: $(BUILDDIR)/$(KERNEL_EXEC) $(BUILDDIR)/$(KERNEL_EXEC).elf32 + @echo " \033[1;93mBOOT\033[0m $<" + + @$(QEMU) -kernel $(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 diff --git a/arch/x86_64/layout.ld b/arch/x86_64/layout.ld new file mode 100644 index 0000000..0faa7c4 --- /dev/null +++ b/arch/x86_64/layout.ld @@ -0,0 +1,56 @@ +ENTRY(_start) + +KERNEL_LMA = 1M; +KERNEL_VMA = 0xFFFFFFFF80000000; + +SECTIONS { + . = KERNEL_LMA; + + .boot.text ALIGN(4K) : { + *(.boot.text) + *(.boot.rodata) + } + + .boot.bss ALIGN(4K) : { + *(.boot.bss) + } + + . += KERNEL_VMA; + + .text ALIGN(4K) : AT(ADDR(.text) - KERNEL_VMA) + { + *(.text) + } + + .data ALIGN(4K) : AT(ADDR(.data) - KERNEL_VMA) + { + _data = .; + *(.data) + } + + .eh_frame ALIGN(4K) : AT(ADDR(.eh_frame) - KERNEL_VMA) + { + _ehframe = .; + *(.eh_frame) + } + + .bss ALIGN(4K) : AT(ADDR(.bss) - KERNEL_VMA) + { + _bss = .; + *(.bss) + + */ + /* + * You usually need to include generated COMMON symbols + * under kernel BSS section or use gcc's -fno-common + */ + *(COMMON) + } + + _end = .; + + /DISCARD/ : + { + *(.comment) + } +} diff --git a/arch/x86_64/start_32.S b/arch/x86_64/start_32.S new file mode 100644 index 0000000..45879df --- /dev/null +++ b/arch/x86_64/start_32.S @@ -0,0 +1,213 @@ +.set ALIGN, 1 << 0 +.set MEMINFO, 1 << 1 +.set VIDMODE, 1 << 2 +.set FLAGS, ALIGN | MEMINFO +.set MAGIC, 0x1BADB002 +.set CHECKSUM, -(MAGIC + FLAGS) + +/* the amount of memory to allocate for bootstrap page directories. */ +#define BOOTSTRAP_PDIR_SIZE 0x1000 + +.extern start_64 # defined in start_64.S + +.code32 + +.section .boot.rodata, "a", @progbits +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." + +.section .boot.bss, "aw", @nobits +bootstrap_pml4t: # a single PML4T + .skip 0x1000 +bootstrap_pdpt: # a single PDPT + .skip 0x1000 +bootstrap_pdir_buf: # a buffer of page directories. each pdir entry can be used to map 2MB of virtual memory. + .skip BOOTSTRAP_PDIR_SIZE +bootstrap_stack_bottom: + .skip 0x1000 +bootstrap_stack_top: + +.section .boot.text, "ax", @progbits +.align 4 +.long MAGIC +.long FLAGS +.long CHECKSUM + +# Print an error message and wait for RETURN if the system's CPU doesn't support long mode. +no_long_mode: + # print error message + mov $no_long_mode_err, %esi + + mov $0xb8000, %edi +1: + movsb + movb $12, (%edi) + incl %edi + cmpb $0, (%esi) + jne 1b + +2: + inb $0x64, %al + test $0x01, %al + jz 3f + inb $0x60, %al + jmp 2b + +3: + inb $0x64, %al + test $0x01, %al + jz 3b + + int $0xff + cli + hlt + +# Print an error message and wait for RETURN if the system's CPU isn't supported. +unsupported_cpu: + # print error message + mov $unsupported_cpu_err, %esi + + mov $0xb8000, %edi +1: + movsb + movb $12, (%edi) + incl %edi + cmpb $0, (%esi) + jne 1b + +2: + inb $0x64, %al + test $0x01, %al + jz 3f + inb $0x60, %al + jmp 2b + +3: + inb $0x64, %al + test $0x01, %al + jz 3b + + int $0xff + cli + hlt + +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. + This allows us to map the kernel at both vaddr 0x0 AND vaddr 0xffffffff80000000 using the same PDPT */ + + mov $bootstrap_pml4t, %edi + mov $bootstrap_pdpt, %esi + + # in %ESI, build a PML4T entry containing the base address of the PDPT + xor $0xFFF, %esi + or $0x3, %esi + + # add the PML4T entries at PML4T[0] and PML4T[511] + mov %esi, (%edi) + 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. */ + + # 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 + /* %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. */ +1: + mov %esi, %ebx + xor $0xFFF, %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 + 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. + 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 */ + mov $0, %edx + mov $BOOTSTRAP_PDIR_SIZE, %eax + mov $0x8, %ebx + idiv %ebx + + mov $0x0, %esi + mov $bootstrap_pdir_buf, %edi + /* %EDI is a pointer into the pagedir buffer. + %ESI is the physical address being mapped. must be a multiple of 2MiB. + %EAX is the total number of page directories. + %EBX is where we build the pagedir entry. */ + +2: + mov %esi, %ebx + xor $0xFFF, %ebx + or $0x3, %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 + + ret + +long_mode_switch: + ret + +.global _start +.type _start, @function + +_start: + mov $bootstrap_stack_top, %esp + + push %ebx # store the pointer to the multiboot info block. + + # check if long mode is supported + movl $0x80000000, %eax # Extended-function 80000000h. + cpuid # Is largest extended function + cmpl $0x80000000, %eax # any function > 80000000h? + jbe no_long_mode # If not, no long mode. + movl $0x80000001, %eax # Extended-function 80000001h. + cpuid # Now EDX = extended-features flags. + btl $29, %edx # Test if long mode is supported. + jnc no_long_mode # Exit if not supported. + + movl $1, %eax + cpuid + btl $3, %edx + + mov $0xb8000, %eax + movb $76, (%eax) + inc %eax + movb $0xF, (%eax) + + call init_page_tables + call long_mode_switch # calls start_64, does not return + + cli + hlt diff --git a/arch/x86_64/start_64.S b/arch/x86_64/start_64.S new file mode 100644 index 0000000..bc71982 --- /dev/null +++ b/arch/x86_64/start_64.S @@ -0,0 +1,10 @@ +.section .boot.text, "ax", @progbits + +.code64 +.global start_64 +.type start_64, @function +start_64: + mov $0xb8000, %rax + movb $77, (%rax) + inc %rax + movb $0xF, (%rax) diff --git a/core/main.c b/core/main.c new file mode 100644 index 0000000..599bbeb --- /dev/null +++ b/core/main.c @@ -0,0 +1,4 @@ +void kernel_init() +{ + +} diff --git a/tools/make/clang-generic.mk b/tools/make/clang-generic.mk new file mode 100644 index 0000000..3d08e57 --- /dev/null +++ b/tools/make/clang-generic.mk @@ -0,0 +1,5 @@ +LD := ld.lld +CC := clang + +CFLAGS := -fuse-ld=$(LD) -target x86_64-linux-elf -nostdlib -nostdinc -ffreestanding -Wl,-nostdlib -Wno-unused-command-line-argument +LDFLAGS := -nostdlib diff --git a/tools/make/gcc-cross-compile.mk b/tools/make/gcc-cross-compile.mk new file mode 100644 index 0000000..164f733 --- /dev/null +++ b/tools/make/gcc-cross-compile.mk @@ -0,0 +1,8 @@ +LD := $(ARCH)-elf-gcc +CC := $(ARCH)-elf-gcc +ASM := $(ARCH)-elf-gcc + +CFLAGS := -nostdlib -nostdinc -ffreestanding -Wl,-nostdlib +ASMFLAGS := $(CFLAGS) +LDFLAGS := -nostdlib +