diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..71e1e9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cursor.h": "c" + } +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..71e1e9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cursor.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 9c8a6fb..e4f6439 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,19 @@ CC = i686-elf-gcc -CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../src/kernel +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I src/kernel LD = i686-elf-ld -LDFLAGS = AS = nasm -ASFLAGS = -felf32 +ASFlAGS = -felf32 GENISO = genisoimage GENISOFLAGS = -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -input-charset utf8 -quiet -boot-info-table -A tree-os EMU = qemu-system-x86_64 EMUFLAGS = -m 256M -cdrom -default: run clean +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find src -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +default: run run: tree-os.iso $(EMU) $(EMUFLAGS) $^ @@ -17,17 +21,23 @@ tree-os.iso: iso/boot/tree-os.elf $(GENISO) $(GENISOFLAGS) -o $@ iso -iso/boot/tree-os.elf: compile/boot.o compile/kernelFull.o - $(LD) $(LDFLAGS) -o $@ $^ +iso/boot/tree-os.elf: linker.ld $(OBJS) + $(LD) -T linker.ld -o $@ $(OBJS) -compile/boot.o: src/multiboot/boot.asm compile - $(AS) $(ASFLAGS) -o $@ $< +$(BUILD_FOLDER)/%.asm.o: %.asm + mkdir -p $(dir $@) + $(AS) $(ASFlAGS) $< -o $@ -compile/kernelFull.o: compile - cd compile && all=$$(find ../src/kernel -name *.c) && $(CC) $(CCFLAGS) $$all && all=$$(find . -name '*.o') && $(LD) $(LDFLAGS) -r -o kernelFull.o $$all +$(BUILD_FOLDER)/%.c.o: %.c + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ -compile: - mkdir compile +$(BUILD_FOLDER)/%.s.o: %.s + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ clean: - rm -r compile \ No newline at end of file + rm -r $(BUILD_FOLDER) + +cleanELF: + rm iso/boot/tree-os.elf \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..71e1e9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cursor.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 9c8a6fb..e4f6439 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,19 @@ CC = i686-elf-gcc -CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../src/kernel +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I src/kernel LD = i686-elf-ld -LDFLAGS = AS = nasm -ASFLAGS = -felf32 +ASFlAGS = -felf32 GENISO = genisoimage GENISOFLAGS = -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -input-charset utf8 -quiet -boot-info-table -A tree-os EMU = qemu-system-x86_64 EMUFLAGS = -m 256M -cdrom -default: run clean +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find src -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +default: run run: tree-os.iso $(EMU) $(EMUFLAGS) $^ @@ -17,17 +21,23 @@ tree-os.iso: iso/boot/tree-os.elf $(GENISO) $(GENISOFLAGS) -o $@ iso -iso/boot/tree-os.elf: compile/boot.o compile/kernelFull.o - $(LD) $(LDFLAGS) -o $@ $^ +iso/boot/tree-os.elf: linker.ld $(OBJS) + $(LD) -T linker.ld -o $@ $(OBJS) -compile/boot.o: src/multiboot/boot.asm compile - $(AS) $(ASFLAGS) -o $@ $< +$(BUILD_FOLDER)/%.asm.o: %.asm + mkdir -p $(dir $@) + $(AS) $(ASFlAGS) $< -o $@ -compile/kernelFull.o: compile - cd compile && all=$$(find ../src/kernel -name *.c) && $(CC) $(CCFLAGS) $$all && all=$$(find . -name '*.o') && $(LD) $(LDFLAGS) -r -o kernelFull.o $$all +$(BUILD_FOLDER)/%.c.o: %.c + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ -compile: - mkdir compile +$(BUILD_FOLDER)/%.s.o: %.s + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ clean: - rm -r compile \ No newline at end of file + rm -r $(BUILD_FOLDER) + +cleanELF: + rm iso/boot/tree-os.elf \ No newline at end of file diff --git a/linker.ld b/linker.ld index 3a3d2c0..b3c2db3 100644 --- a/linker.ld +++ b/linker.ld @@ -1,26 +1,242 @@ +/* Script for -z combreloc -z separate-code */ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +/* file generated with ld --verbose */ +OUTPUT_ARCH(i386) ENTRY(_start) - -SECTIONS { - . = 0x00100000; /* load code at 1 MB */ - - .text ALIGN (0x1000): +SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib"); +SECTIONS +{ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { - *(.text) + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) } - - .rodata ALIGN (0x1000): + .rela.plt : { - *(.rodata*) + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } +.plt.got : { *(.plt.got) } +.plt.sec : { *(.plt.sec) } + _kernel_start = .; - .data ALIGN (0x1000): - { - *(.data) - } - - .bss ALIGN (0x1000): - { - *(COMMON) - *(.bss) - } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + _kernel_end = .; + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..71e1e9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cursor.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 9c8a6fb..e4f6439 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,19 @@ CC = i686-elf-gcc -CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../src/kernel +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I src/kernel LD = i686-elf-ld -LDFLAGS = AS = nasm -ASFLAGS = -felf32 +ASFlAGS = -felf32 GENISO = genisoimage GENISOFLAGS = -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -input-charset utf8 -quiet -boot-info-table -A tree-os EMU = qemu-system-x86_64 EMUFLAGS = -m 256M -cdrom -default: run clean +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find src -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +default: run run: tree-os.iso $(EMU) $(EMUFLAGS) $^ @@ -17,17 +21,23 @@ tree-os.iso: iso/boot/tree-os.elf $(GENISO) $(GENISOFLAGS) -o $@ iso -iso/boot/tree-os.elf: compile/boot.o compile/kernelFull.o - $(LD) $(LDFLAGS) -o $@ $^ +iso/boot/tree-os.elf: linker.ld $(OBJS) + $(LD) -T linker.ld -o $@ $(OBJS) -compile/boot.o: src/multiboot/boot.asm compile - $(AS) $(ASFLAGS) -o $@ $< +$(BUILD_FOLDER)/%.asm.o: %.asm + mkdir -p $(dir $@) + $(AS) $(ASFlAGS) $< -o $@ -compile/kernelFull.o: compile - cd compile && all=$$(find ../src/kernel -name *.c) && $(CC) $(CCFLAGS) $$all && all=$$(find . -name '*.o') && $(LD) $(LDFLAGS) -r -o kernelFull.o $$all +$(BUILD_FOLDER)/%.c.o: %.c + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ -compile: - mkdir compile +$(BUILD_FOLDER)/%.s.o: %.s + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ clean: - rm -r compile \ No newline at end of file + rm -r $(BUILD_FOLDER) + +cleanELF: + rm iso/boot/tree-os.elf \ No newline at end of file diff --git a/linker.ld b/linker.ld index 3a3d2c0..b3c2db3 100644 --- a/linker.ld +++ b/linker.ld @@ -1,26 +1,242 @@ +/* Script for -z combreloc -z separate-code */ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +/* file generated with ld --verbose */ +OUTPUT_ARCH(i386) ENTRY(_start) - -SECTIONS { - . = 0x00100000; /* load code at 1 MB */ - - .text ALIGN (0x1000): +SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib"); +SECTIONS +{ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { - *(.text) + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) } - - .rodata ALIGN (0x1000): + .rela.plt : { - *(.rodata*) + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } +.plt.got : { *(.plt.got) } +.plt.sec : { *(.plt.sec) } + _kernel_start = .; - .data ALIGN (0x1000): - { - *(.data) - } - - .bss ALIGN (0x1000): - { - *(COMMON) - *(.bss) - } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + _kernel_end = .; + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 4ebc650..558dd66 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -2,10 +2,21 @@ #include #include #include +#include +#include +#include + +extern uint32_t _kernel_end; void kernelMain() { clearScreen(); setTextStyle(0x0F); printf(logo); - printf("Hello World! Tree OS is alive!"); + initMemoryAllocation(0x100000); // initializing stacks after the kernel seems to not work :( otherwise, _kernel_end should be passed here + printf("Hello World!\nTree OS is alive!\n"); + initOSTasks(); + printf("Switching to otherTask... \n"); + yields(); + printf("Returned to mainTask!\n"); + yield(); } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..71e1e9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cursor.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 9c8a6fb..e4f6439 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,19 @@ CC = i686-elf-gcc -CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../src/kernel +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I src/kernel LD = i686-elf-ld -LDFLAGS = AS = nasm -ASFLAGS = -felf32 +ASFlAGS = -felf32 GENISO = genisoimage GENISOFLAGS = -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -input-charset utf8 -quiet -boot-info-table -A tree-os EMU = qemu-system-x86_64 EMUFLAGS = -m 256M -cdrom -default: run clean +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find src -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +default: run run: tree-os.iso $(EMU) $(EMUFLAGS) $^ @@ -17,17 +21,23 @@ tree-os.iso: iso/boot/tree-os.elf $(GENISO) $(GENISOFLAGS) -o $@ iso -iso/boot/tree-os.elf: compile/boot.o compile/kernelFull.o - $(LD) $(LDFLAGS) -o $@ $^ +iso/boot/tree-os.elf: linker.ld $(OBJS) + $(LD) -T linker.ld -o $@ $(OBJS) -compile/boot.o: src/multiboot/boot.asm compile - $(AS) $(ASFLAGS) -o $@ $< +$(BUILD_FOLDER)/%.asm.o: %.asm + mkdir -p $(dir $@) + $(AS) $(ASFlAGS) $< -o $@ -compile/kernelFull.o: compile - cd compile && all=$$(find ../src/kernel -name *.c) && $(CC) $(CCFLAGS) $$all && all=$$(find . -name '*.o') && $(LD) $(LDFLAGS) -r -o kernelFull.o $$all +$(BUILD_FOLDER)/%.c.o: %.c + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ -compile: - mkdir compile +$(BUILD_FOLDER)/%.s.o: %.s + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ clean: - rm -r compile \ No newline at end of file + rm -r $(BUILD_FOLDER) + +cleanELF: + rm iso/boot/tree-os.elf \ No newline at end of file diff --git a/linker.ld b/linker.ld index 3a3d2c0..b3c2db3 100644 --- a/linker.ld +++ b/linker.ld @@ -1,26 +1,242 @@ +/* Script for -z combreloc -z separate-code */ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +/* file generated with ld --verbose */ +OUTPUT_ARCH(i386) ENTRY(_start) - -SECTIONS { - . = 0x00100000; /* load code at 1 MB */ - - .text ALIGN (0x1000): +SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib"); +SECTIONS +{ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { - *(.text) + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) } - - .rodata ALIGN (0x1000): + .rela.plt : { - *(.rodata*) + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } +.plt.got : { *(.plt.got) } +.plt.sec : { *(.plt.sec) } + _kernel_start = .; - .data ALIGN (0x1000): - { - *(.data) - } - - .bss ALIGN (0x1000): - { - *(COMMON) - *(.bss) - } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + _kernel_end = .; + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 4ebc650..558dd66 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -2,10 +2,21 @@ #include #include #include +#include +#include +#include + +extern uint32_t _kernel_end; void kernelMain() { clearScreen(); setTextStyle(0x0F); printf(logo); - printf("Hello World! Tree OS is alive!"); + initMemoryAllocation(0x100000); // initializing stacks after the kernel seems to not work :( otherwise, _kernel_end should be passed here + printf("Hello World!\nTree OS is alive!\n"); + initOSTasks(); + printf("Switching to otherTask... \n"); + yields(); + printf("Returned to mainTask!\n"); + yield(); } \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.c b/src/kernel/lib/memory/alloc.c new file mode 100644 index 0000000..1c4d023 --- /dev/null +++ b/src/kernel/lib/memory/alloc.c @@ -0,0 +1,15 @@ +#include +#include +#include + +uint32_t currentPosition; + +void initMemoryAllocation(uint32_t kernelEnd) { + currentPosition = kernelEnd; +} + +void* malloc(uint32_t size) { + uint32_t result = currentPosition; + currentPosition += size; + return (void*) result; +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..71e1e9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cursor.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 9c8a6fb..e4f6439 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,19 @@ CC = i686-elf-gcc -CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../src/kernel +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I src/kernel LD = i686-elf-ld -LDFLAGS = AS = nasm -ASFLAGS = -felf32 +ASFlAGS = -felf32 GENISO = genisoimage GENISOFLAGS = -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -input-charset utf8 -quiet -boot-info-table -A tree-os EMU = qemu-system-x86_64 EMUFLAGS = -m 256M -cdrom -default: run clean +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find src -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +default: run run: tree-os.iso $(EMU) $(EMUFLAGS) $^ @@ -17,17 +21,23 @@ tree-os.iso: iso/boot/tree-os.elf $(GENISO) $(GENISOFLAGS) -o $@ iso -iso/boot/tree-os.elf: compile/boot.o compile/kernelFull.o - $(LD) $(LDFLAGS) -o $@ $^ +iso/boot/tree-os.elf: linker.ld $(OBJS) + $(LD) -T linker.ld -o $@ $(OBJS) -compile/boot.o: src/multiboot/boot.asm compile - $(AS) $(ASFLAGS) -o $@ $< +$(BUILD_FOLDER)/%.asm.o: %.asm + mkdir -p $(dir $@) + $(AS) $(ASFlAGS) $< -o $@ -compile/kernelFull.o: compile - cd compile && all=$$(find ../src/kernel -name *.c) && $(CC) $(CCFLAGS) $$all && all=$$(find . -name '*.o') && $(LD) $(LDFLAGS) -r -o kernelFull.o $$all +$(BUILD_FOLDER)/%.c.o: %.c + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ -compile: - mkdir compile +$(BUILD_FOLDER)/%.s.o: %.s + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ clean: - rm -r compile \ No newline at end of file + rm -r $(BUILD_FOLDER) + +cleanELF: + rm iso/boot/tree-os.elf \ No newline at end of file diff --git a/linker.ld b/linker.ld index 3a3d2c0..b3c2db3 100644 --- a/linker.ld +++ b/linker.ld @@ -1,26 +1,242 @@ +/* Script for -z combreloc -z separate-code */ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +/* file generated with ld --verbose */ +OUTPUT_ARCH(i386) ENTRY(_start) - -SECTIONS { - . = 0x00100000; /* load code at 1 MB */ - - .text ALIGN (0x1000): +SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib"); +SECTIONS +{ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { - *(.text) + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) } - - .rodata ALIGN (0x1000): + .rela.plt : { - *(.rodata*) + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } +.plt.got : { *(.plt.got) } +.plt.sec : { *(.plt.sec) } + _kernel_start = .; - .data ALIGN (0x1000): - { - *(.data) - } - - .bss ALIGN (0x1000): - { - *(COMMON) - *(.bss) - } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + _kernel_end = .; + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 4ebc650..558dd66 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -2,10 +2,21 @@ #include #include #include +#include +#include +#include + +extern uint32_t _kernel_end; void kernelMain() { clearScreen(); setTextStyle(0x0F); printf(logo); - printf("Hello World! Tree OS is alive!"); + initMemoryAllocation(0x100000); // initializing stacks after the kernel seems to not work :( otherwise, _kernel_end should be passed here + printf("Hello World!\nTree OS is alive!\n"); + initOSTasks(); + printf("Switching to otherTask... \n"); + yields(); + printf("Returned to mainTask!\n"); + yield(); } \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.c b/src/kernel/lib/memory/alloc.c new file mode 100644 index 0000000..1c4d023 --- /dev/null +++ b/src/kernel/lib/memory/alloc.c @@ -0,0 +1,15 @@ +#include +#include +#include + +uint32_t currentPosition; + +void initMemoryAllocation(uint32_t kernelEnd) { + currentPosition = kernelEnd; +} + +void* malloc(uint32_t size) { + uint32_t result = currentPosition; + currentPosition += size; + return (void*) result; +} \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.h b/src/kernel/lib/memory/alloc.h new file mode 100644 index 0000000..bd195ae --- /dev/null +++ b/src/kernel/lib/memory/alloc.h @@ -0,0 +1,9 @@ +#ifndef ALLOC_H +#define ALLOC_H + +#include + +extern void initMemoryAllocation(uint32_t kernelEnd); +extern void* malloc(uint32_t size); + +#endif \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..71e1e9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cursor.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 9c8a6fb..e4f6439 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,19 @@ CC = i686-elf-gcc -CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../src/kernel +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I src/kernel LD = i686-elf-ld -LDFLAGS = AS = nasm -ASFLAGS = -felf32 +ASFlAGS = -felf32 GENISO = genisoimage GENISOFLAGS = -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -input-charset utf8 -quiet -boot-info-table -A tree-os EMU = qemu-system-x86_64 EMUFLAGS = -m 256M -cdrom -default: run clean +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find src -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +default: run run: tree-os.iso $(EMU) $(EMUFLAGS) $^ @@ -17,17 +21,23 @@ tree-os.iso: iso/boot/tree-os.elf $(GENISO) $(GENISOFLAGS) -o $@ iso -iso/boot/tree-os.elf: compile/boot.o compile/kernelFull.o - $(LD) $(LDFLAGS) -o $@ $^ +iso/boot/tree-os.elf: linker.ld $(OBJS) + $(LD) -T linker.ld -o $@ $(OBJS) -compile/boot.o: src/multiboot/boot.asm compile - $(AS) $(ASFLAGS) -o $@ $< +$(BUILD_FOLDER)/%.asm.o: %.asm + mkdir -p $(dir $@) + $(AS) $(ASFlAGS) $< -o $@ -compile/kernelFull.o: compile - cd compile && all=$$(find ../src/kernel -name *.c) && $(CC) $(CCFLAGS) $$all && all=$$(find . -name '*.o') && $(LD) $(LDFLAGS) -r -o kernelFull.o $$all +$(BUILD_FOLDER)/%.c.o: %.c + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ -compile: - mkdir compile +$(BUILD_FOLDER)/%.s.o: %.s + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ clean: - rm -r compile \ No newline at end of file + rm -r $(BUILD_FOLDER) + +cleanELF: + rm iso/boot/tree-os.elf \ No newline at end of file diff --git a/linker.ld b/linker.ld index 3a3d2c0..b3c2db3 100644 --- a/linker.ld +++ b/linker.ld @@ -1,26 +1,242 @@ +/* Script for -z combreloc -z separate-code */ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +/* file generated with ld --verbose */ +OUTPUT_ARCH(i386) ENTRY(_start) - -SECTIONS { - . = 0x00100000; /* load code at 1 MB */ - - .text ALIGN (0x1000): +SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib"); +SECTIONS +{ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { - *(.text) + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) } - - .rodata ALIGN (0x1000): + .rela.plt : { - *(.rodata*) + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } +.plt.got : { *(.plt.got) } +.plt.sec : { *(.plt.sec) } + _kernel_start = .; - .data ALIGN (0x1000): - { - *(.data) - } - - .bss ALIGN (0x1000): - { - *(COMMON) - *(.bss) - } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + _kernel_end = .; + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 4ebc650..558dd66 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -2,10 +2,21 @@ #include #include #include +#include +#include +#include + +extern uint32_t _kernel_end; void kernelMain() { clearScreen(); setTextStyle(0x0F); printf(logo); - printf("Hello World! Tree OS is alive!"); + initMemoryAllocation(0x100000); // initializing stacks after the kernel seems to not work :( otherwise, _kernel_end should be passed here + printf("Hello World!\nTree OS is alive!\n"); + initOSTasks(); + printf("Switching to otherTask... \n"); + yields(); + printf("Returned to mainTask!\n"); + yield(); } \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.c b/src/kernel/lib/memory/alloc.c new file mode 100644 index 0000000..1c4d023 --- /dev/null +++ b/src/kernel/lib/memory/alloc.c @@ -0,0 +1,15 @@ +#include +#include +#include + +uint32_t currentPosition; + +void initMemoryAllocation(uint32_t kernelEnd) { + currentPosition = kernelEnd; +} + +void* malloc(uint32_t size) { + uint32_t result = currentPosition; + currentPosition += size; + return (void*) result; +} \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.h b/src/kernel/lib/memory/alloc.h new file mode 100644 index 0000000..bd195ae --- /dev/null +++ b/src/kernel/lib/memory/alloc.h @@ -0,0 +1,9 @@ +#ifndef ALLOC_H +#define ALLOC_H + +#include + +extern void initMemoryAllocation(uint32_t kernelEnd); +extern void* malloc(uint32_t size); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.c b/src/kernel/lib/task/osTasks.c new file mode 100644 index 0000000..407709a --- /dev/null +++ b/src/kernel/lib/task/osTasks.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +Task mainTask; +Task testTask; + +void testMain() { + printf("Hello from another task!\n"); + yield(); +} + +void initOSTasks() { + setRunningTask(&mainTask); + createTask(&testTask, (uint32_t) testMain, 0x0, 0x0); + schedule(&testTask); +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..71e1e9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cursor.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 9c8a6fb..e4f6439 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,19 @@ CC = i686-elf-gcc -CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../src/kernel +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I src/kernel LD = i686-elf-ld -LDFLAGS = AS = nasm -ASFLAGS = -felf32 +ASFlAGS = -felf32 GENISO = genisoimage GENISOFLAGS = -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -input-charset utf8 -quiet -boot-info-table -A tree-os EMU = qemu-system-x86_64 EMUFLAGS = -m 256M -cdrom -default: run clean +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find src -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +default: run run: tree-os.iso $(EMU) $(EMUFLAGS) $^ @@ -17,17 +21,23 @@ tree-os.iso: iso/boot/tree-os.elf $(GENISO) $(GENISOFLAGS) -o $@ iso -iso/boot/tree-os.elf: compile/boot.o compile/kernelFull.o - $(LD) $(LDFLAGS) -o $@ $^ +iso/boot/tree-os.elf: linker.ld $(OBJS) + $(LD) -T linker.ld -o $@ $(OBJS) -compile/boot.o: src/multiboot/boot.asm compile - $(AS) $(ASFLAGS) -o $@ $< +$(BUILD_FOLDER)/%.asm.o: %.asm + mkdir -p $(dir $@) + $(AS) $(ASFlAGS) $< -o $@ -compile/kernelFull.o: compile - cd compile && all=$$(find ../src/kernel -name *.c) && $(CC) $(CCFLAGS) $$all && all=$$(find . -name '*.o') && $(LD) $(LDFLAGS) -r -o kernelFull.o $$all +$(BUILD_FOLDER)/%.c.o: %.c + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ -compile: - mkdir compile +$(BUILD_FOLDER)/%.s.o: %.s + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ clean: - rm -r compile \ No newline at end of file + rm -r $(BUILD_FOLDER) + +cleanELF: + rm iso/boot/tree-os.elf \ No newline at end of file diff --git a/linker.ld b/linker.ld index 3a3d2c0..b3c2db3 100644 --- a/linker.ld +++ b/linker.ld @@ -1,26 +1,242 @@ +/* Script for -z combreloc -z separate-code */ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +/* file generated with ld --verbose */ +OUTPUT_ARCH(i386) ENTRY(_start) - -SECTIONS { - . = 0x00100000; /* load code at 1 MB */ - - .text ALIGN (0x1000): +SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib"); +SECTIONS +{ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { - *(.text) + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) } - - .rodata ALIGN (0x1000): + .rela.plt : { - *(.rodata*) + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } +.plt.got : { *(.plt.got) } +.plt.sec : { *(.plt.sec) } + _kernel_start = .; - .data ALIGN (0x1000): - { - *(.data) - } - - .bss ALIGN (0x1000): - { - *(COMMON) - *(.bss) - } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + _kernel_end = .; + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 4ebc650..558dd66 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -2,10 +2,21 @@ #include #include #include +#include +#include +#include + +extern uint32_t _kernel_end; void kernelMain() { clearScreen(); setTextStyle(0x0F); printf(logo); - printf("Hello World! Tree OS is alive!"); + initMemoryAllocation(0x100000); // initializing stacks after the kernel seems to not work :( otherwise, _kernel_end should be passed here + printf("Hello World!\nTree OS is alive!\n"); + initOSTasks(); + printf("Switching to otherTask... \n"); + yields(); + printf("Returned to mainTask!\n"); + yield(); } \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.c b/src/kernel/lib/memory/alloc.c new file mode 100644 index 0000000..1c4d023 --- /dev/null +++ b/src/kernel/lib/memory/alloc.c @@ -0,0 +1,15 @@ +#include +#include +#include + +uint32_t currentPosition; + +void initMemoryAllocation(uint32_t kernelEnd) { + currentPosition = kernelEnd; +} + +void* malloc(uint32_t size) { + uint32_t result = currentPosition; + currentPosition += size; + return (void*) result; +} \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.h b/src/kernel/lib/memory/alloc.h new file mode 100644 index 0000000..bd195ae --- /dev/null +++ b/src/kernel/lib/memory/alloc.h @@ -0,0 +1,9 @@ +#ifndef ALLOC_H +#define ALLOC_H + +#include + +extern void initMemoryAllocation(uint32_t kernelEnd); +extern void* malloc(uint32_t size); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.c b/src/kernel/lib/task/osTasks.c new file mode 100644 index 0000000..407709a --- /dev/null +++ b/src/kernel/lib/task/osTasks.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +Task mainTask; +Task testTask; + +void testMain() { + printf("Hello from another task!\n"); + yield(); +} + +void initOSTasks() { + setRunningTask(&mainTask); + createTask(&testTask, (uint32_t) testMain, 0x0, 0x0); + schedule(&testTask); +} \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.h b/src/kernel/lib/task/osTasks.h new file mode 100644 index 0000000..880cedb --- /dev/null +++ b/src/kernel/lib/task/osTasks.h @@ -0,0 +1,9 @@ +#ifndef OS_TASKS_H +#define OS_TASKS_H + +#include + +extern void testMain(); +extern void initOSTasks(); + +#endif \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..71e1e9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cursor.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 9c8a6fb..e4f6439 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,19 @@ CC = i686-elf-gcc -CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../src/kernel +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I src/kernel LD = i686-elf-ld -LDFLAGS = AS = nasm -ASFLAGS = -felf32 +ASFlAGS = -felf32 GENISO = genisoimage GENISOFLAGS = -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -input-charset utf8 -quiet -boot-info-table -A tree-os EMU = qemu-system-x86_64 EMUFLAGS = -m 256M -cdrom -default: run clean +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find src -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +default: run run: tree-os.iso $(EMU) $(EMUFLAGS) $^ @@ -17,17 +21,23 @@ tree-os.iso: iso/boot/tree-os.elf $(GENISO) $(GENISOFLAGS) -o $@ iso -iso/boot/tree-os.elf: compile/boot.o compile/kernelFull.o - $(LD) $(LDFLAGS) -o $@ $^ +iso/boot/tree-os.elf: linker.ld $(OBJS) + $(LD) -T linker.ld -o $@ $(OBJS) -compile/boot.o: src/multiboot/boot.asm compile - $(AS) $(ASFLAGS) -o $@ $< +$(BUILD_FOLDER)/%.asm.o: %.asm + mkdir -p $(dir $@) + $(AS) $(ASFlAGS) $< -o $@ -compile/kernelFull.o: compile - cd compile && all=$$(find ../src/kernel -name *.c) && $(CC) $(CCFLAGS) $$all && all=$$(find . -name '*.o') && $(LD) $(LDFLAGS) -r -o kernelFull.o $$all +$(BUILD_FOLDER)/%.c.o: %.c + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ -compile: - mkdir compile +$(BUILD_FOLDER)/%.s.o: %.s + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ clean: - rm -r compile \ No newline at end of file + rm -r $(BUILD_FOLDER) + +cleanELF: + rm iso/boot/tree-os.elf \ No newline at end of file diff --git a/linker.ld b/linker.ld index 3a3d2c0..b3c2db3 100644 --- a/linker.ld +++ b/linker.ld @@ -1,26 +1,242 @@ +/* Script for -z combreloc -z separate-code */ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +/* file generated with ld --verbose */ +OUTPUT_ARCH(i386) ENTRY(_start) - -SECTIONS { - . = 0x00100000; /* load code at 1 MB */ - - .text ALIGN (0x1000): +SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib"); +SECTIONS +{ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { - *(.text) + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) } - - .rodata ALIGN (0x1000): + .rela.plt : { - *(.rodata*) + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } +.plt.got : { *(.plt.got) } +.plt.sec : { *(.plt.sec) } + _kernel_start = .; - .data ALIGN (0x1000): - { - *(.data) - } - - .bss ALIGN (0x1000): - { - *(COMMON) - *(.bss) - } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + _kernel_end = .; + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 4ebc650..558dd66 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -2,10 +2,21 @@ #include #include #include +#include +#include +#include + +extern uint32_t _kernel_end; void kernelMain() { clearScreen(); setTextStyle(0x0F); printf(logo); - printf("Hello World! Tree OS is alive!"); + initMemoryAllocation(0x100000); // initializing stacks after the kernel seems to not work :( otherwise, _kernel_end should be passed here + printf("Hello World!\nTree OS is alive!\n"); + initOSTasks(); + printf("Switching to otherTask... \n"); + yields(); + printf("Returned to mainTask!\n"); + yield(); } \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.c b/src/kernel/lib/memory/alloc.c new file mode 100644 index 0000000..1c4d023 --- /dev/null +++ b/src/kernel/lib/memory/alloc.c @@ -0,0 +1,15 @@ +#include +#include +#include + +uint32_t currentPosition; + +void initMemoryAllocation(uint32_t kernelEnd) { + currentPosition = kernelEnd; +} + +void* malloc(uint32_t size) { + uint32_t result = currentPosition; + currentPosition += size; + return (void*) result; +} \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.h b/src/kernel/lib/memory/alloc.h new file mode 100644 index 0000000..bd195ae --- /dev/null +++ b/src/kernel/lib/memory/alloc.h @@ -0,0 +1,9 @@ +#ifndef ALLOC_H +#define ALLOC_H + +#include + +extern void initMemoryAllocation(uint32_t kernelEnd); +extern void* malloc(uint32_t size); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.c b/src/kernel/lib/task/osTasks.c new file mode 100644 index 0000000..407709a --- /dev/null +++ b/src/kernel/lib/task/osTasks.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +Task mainTask; +Task testTask; + +void testMain() { + printf("Hello from another task!\n"); + yield(); +} + +void initOSTasks() { + setRunningTask(&mainTask); + createTask(&testTask, (uint32_t) testMain, 0x0, 0x0); + schedule(&testTask); +} \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.h b/src/kernel/lib/task/osTasks.h new file mode 100644 index 0000000..880cedb --- /dev/null +++ b/src/kernel/lib/task/osTasks.h @@ -0,0 +1,9 @@ +#ifndef OS_TASKS_H +#define OS_TASKS_H + +#include + +extern void testMain(); +extern void initOSTasks(); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/task.c b/src/kernel/lib/task/task.c new file mode 100644 index 0000000..5b177fe --- /dev/null +++ b/src/kernel/lib/task/task.c @@ -0,0 +1,48 @@ +#include +#include +#include + +Task *runningTask; + +void createTask(Task *task, uint32_t mainFunction, uint32_t flags, uint32_t *pagedir) { + task->registers.eax = 0; + task->registers.ebx = 0; + task->registers.ecx = 0; + task->registers.edx = 0; + task->registers.esi = 0; + task->registers.edi = 0; + task->registers.eflags = flags; + task->registers.eip = mainFunction; + task->registers.cr3 = (uint32_t) pagedir; + task->registers.esp = 0xF000 + (uint32_t) malloc(0xF000); + task->nextTask = 0; +} + +void yield() { + Task* last = runningTask; + runningTask = runningTask->nextTask; + if (runningTask == 0x00) { + printf("No more tasks to run, halting . . .\n"); + asm("hlt"); + } + last->nextTask = 0x00; + switchTask(&(last->registers), &(runningTask->registers)); +} + +void schedule(Task* task) { + Task* test = runningTask; + while (test->nextTask != 0x0) { + test = test->nextTask; + } + printf("scheduling Task %x after task %x\n", task, test); + test->nextTask = task; +} + +void setRunningTask(Task* task) { + runningTask = task; +} + +void yields() { + schedule(runningTask); + yield(); +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..71e1e9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cursor.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 9c8a6fb..e4f6439 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,19 @@ CC = i686-elf-gcc -CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../src/kernel +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I src/kernel LD = i686-elf-ld -LDFLAGS = AS = nasm -ASFLAGS = -felf32 +ASFlAGS = -felf32 GENISO = genisoimage GENISOFLAGS = -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -input-charset utf8 -quiet -boot-info-table -A tree-os EMU = qemu-system-x86_64 EMUFLAGS = -m 256M -cdrom -default: run clean +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find src -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +default: run run: tree-os.iso $(EMU) $(EMUFLAGS) $^ @@ -17,17 +21,23 @@ tree-os.iso: iso/boot/tree-os.elf $(GENISO) $(GENISOFLAGS) -o $@ iso -iso/boot/tree-os.elf: compile/boot.o compile/kernelFull.o - $(LD) $(LDFLAGS) -o $@ $^ +iso/boot/tree-os.elf: linker.ld $(OBJS) + $(LD) -T linker.ld -o $@ $(OBJS) -compile/boot.o: src/multiboot/boot.asm compile - $(AS) $(ASFLAGS) -o $@ $< +$(BUILD_FOLDER)/%.asm.o: %.asm + mkdir -p $(dir $@) + $(AS) $(ASFlAGS) $< -o $@ -compile/kernelFull.o: compile - cd compile && all=$$(find ../src/kernel -name *.c) && $(CC) $(CCFLAGS) $$all && all=$$(find . -name '*.o') && $(LD) $(LDFLAGS) -r -o kernelFull.o $$all +$(BUILD_FOLDER)/%.c.o: %.c + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ -compile: - mkdir compile +$(BUILD_FOLDER)/%.s.o: %.s + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ clean: - rm -r compile \ No newline at end of file + rm -r $(BUILD_FOLDER) + +cleanELF: + rm iso/boot/tree-os.elf \ No newline at end of file diff --git a/linker.ld b/linker.ld index 3a3d2c0..b3c2db3 100644 --- a/linker.ld +++ b/linker.ld @@ -1,26 +1,242 @@ +/* Script for -z combreloc -z separate-code */ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +/* file generated with ld --verbose */ +OUTPUT_ARCH(i386) ENTRY(_start) - -SECTIONS { - . = 0x00100000; /* load code at 1 MB */ - - .text ALIGN (0x1000): +SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib"); +SECTIONS +{ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { - *(.text) + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) } - - .rodata ALIGN (0x1000): + .rela.plt : { - *(.rodata*) + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } +.plt.got : { *(.plt.got) } +.plt.sec : { *(.plt.sec) } + _kernel_start = .; - .data ALIGN (0x1000): - { - *(.data) - } - - .bss ALIGN (0x1000): - { - *(COMMON) - *(.bss) - } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + _kernel_end = .; + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 4ebc650..558dd66 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -2,10 +2,21 @@ #include #include #include +#include +#include +#include + +extern uint32_t _kernel_end; void kernelMain() { clearScreen(); setTextStyle(0x0F); printf(logo); - printf("Hello World! Tree OS is alive!"); + initMemoryAllocation(0x100000); // initializing stacks after the kernel seems to not work :( otherwise, _kernel_end should be passed here + printf("Hello World!\nTree OS is alive!\n"); + initOSTasks(); + printf("Switching to otherTask... \n"); + yields(); + printf("Returned to mainTask!\n"); + yield(); } \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.c b/src/kernel/lib/memory/alloc.c new file mode 100644 index 0000000..1c4d023 --- /dev/null +++ b/src/kernel/lib/memory/alloc.c @@ -0,0 +1,15 @@ +#include +#include +#include + +uint32_t currentPosition; + +void initMemoryAllocation(uint32_t kernelEnd) { + currentPosition = kernelEnd; +} + +void* malloc(uint32_t size) { + uint32_t result = currentPosition; + currentPosition += size; + return (void*) result; +} \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.h b/src/kernel/lib/memory/alloc.h new file mode 100644 index 0000000..bd195ae --- /dev/null +++ b/src/kernel/lib/memory/alloc.h @@ -0,0 +1,9 @@ +#ifndef ALLOC_H +#define ALLOC_H + +#include + +extern void initMemoryAllocation(uint32_t kernelEnd); +extern void* malloc(uint32_t size); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.c b/src/kernel/lib/task/osTasks.c new file mode 100644 index 0000000..407709a --- /dev/null +++ b/src/kernel/lib/task/osTasks.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +Task mainTask; +Task testTask; + +void testMain() { + printf("Hello from another task!\n"); + yield(); +} + +void initOSTasks() { + setRunningTask(&mainTask); + createTask(&testTask, (uint32_t) testMain, 0x0, 0x0); + schedule(&testTask); +} \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.h b/src/kernel/lib/task/osTasks.h new file mode 100644 index 0000000..880cedb --- /dev/null +++ b/src/kernel/lib/task/osTasks.h @@ -0,0 +1,9 @@ +#ifndef OS_TASKS_H +#define OS_TASKS_H + +#include + +extern void testMain(); +extern void initOSTasks(); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/task.c b/src/kernel/lib/task/task.c new file mode 100644 index 0000000..5b177fe --- /dev/null +++ b/src/kernel/lib/task/task.c @@ -0,0 +1,48 @@ +#include +#include +#include + +Task *runningTask; + +void createTask(Task *task, uint32_t mainFunction, uint32_t flags, uint32_t *pagedir) { + task->registers.eax = 0; + task->registers.ebx = 0; + task->registers.ecx = 0; + task->registers.edx = 0; + task->registers.esi = 0; + task->registers.edi = 0; + task->registers.eflags = flags; + task->registers.eip = mainFunction; + task->registers.cr3 = (uint32_t) pagedir; + task->registers.esp = 0xF000 + (uint32_t) malloc(0xF000); + task->nextTask = 0; +} + +void yield() { + Task* last = runningTask; + runningTask = runningTask->nextTask; + if (runningTask == 0x00) { + printf("No more tasks to run, halting . . .\n"); + asm("hlt"); + } + last->nextTask = 0x00; + switchTask(&(last->registers), &(runningTask->registers)); +} + +void schedule(Task* task) { + Task* test = runningTask; + while (test->nextTask != 0x0) { + test = test->nextTask; + } + printf("scheduling Task %x after task %x\n", task, test); + test->nextTask = task; +} + +void setRunningTask(Task* task) { + runningTask = task; +} + +void yields() { + schedule(runningTask); + yield(); +} \ No newline at end of file diff --git a/src/kernel/lib/task/task.h b/src/kernel/lib/task/task.h new file mode 100644 index 0000000..6a617cd --- /dev/null +++ b/src/kernel/lib/task/task.h @@ -0,0 +1,27 @@ +#ifndef TASK_H +#define TASK_H + +#include + +extern void initTasking(); + +typedef struct { + uint32_t eax, ebx, ecx, edx, esi, edi, esp, ebp, eip, eflags, cr3; +} Registers; + +typedef struct Task { + Registers registers; + struct Task *nextTask; // linked list of tasks that need to be done +} Task; + +extern void initTasking(); +extern void createTask(Task *task, uint32_t mainFunction, uint32_t flags, uint32_t *pagedir); + +extern void yield(); +extern void yields(); // yield, but first schedule the currently running task +extern void switchTask(Registers *old, Registers *new); +extern void schedule(Task* task); + +extern void setRunningTask(Task* task); + +#endif \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..71e1e9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cursor.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 9c8a6fb..e4f6439 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,19 @@ CC = i686-elf-gcc -CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../src/kernel +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I src/kernel LD = i686-elf-ld -LDFLAGS = AS = nasm -ASFLAGS = -felf32 +ASFlAGS = -felf32 GENISO = genisoimage GENISOFLAGS = -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -input-charset utf8 -quiet -boot-info-table -A tree-os EMU = qemu-system-x86_64 EMUFLAGS = -m 256M -cdrom -default: run clean +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find src -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +default: run run: tree-os.iso $(EMU) $(EMUFLAGS) $^ @@ -17,17 +21,23 @@ tree-os.iso: iso/boot/tree-os.elf $(GENISO) $(GENISOFLAGS) -o $@ iso -iso/boot/tree-os.elf: compile/boot.o compile/kernelFull.o - $(LD) $(LDFLAGS) -o $@ $^ +iso/boot/tree-os.elf: linker.ld $(OBJS) + $(LD) -T linker.ld -o $@ $(OBJS) -compile/boot.o: src/multiboot/boot.asm compile - $(AS) $(ASFLAGS) -o $@ $< +$(BUILD_FOLDER)/%.asm.o: %.asm + mkdir -p $(dir $@) + $(AS) $(ASFlAGS) $< -o $@ -compile/kernelFull.o: compile - cd compile && all=$$(find ../src/kernel -name *.c) && $(CC) $(CCFLAGS) $$all && all=$$(find . -name '*.o') && $(LD) $(LDFLAGS) -r -o kernelFull.o $$all +$(BUILD_FOLDER)/%.c.o: %.c + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ -compile: - mkdir compile +$(BUILD_FOLDER)/%.s.o: %.s + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ clean: - rm -r compile \ No newline at end of file + rm -r $(BUILD_FOLDER) + +cleanELF: + rm iso/boot/tree-os.elf \ No newline at end of file diff --git a/linker.ld b/linker.ld index 3a3d2c0..b3c2db3 100644 --- a/linker.ld +++ b/linker.ld @@ -1,26 +1,242 @@ +/* Script for -z combreloc -z separate-code */ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +/* file generated with ld --verbose */ +OUTPUT_ARCH(i386) ENTRY(_start) - -SECTIONS { - . = 0x00100000; /* load code at 1 MB */ - - .text ALIGN (0x1000): +SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib"); +SECTIONS +{ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { - *(.text) + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) } - - .rodata ALIGN (0x1000): + .rela.plt : { - *(.rodata*) + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } +.plt.got : { *(.plt.got) } +.plt.sec : { *(.plt.sec) } + _kernel_start = .; - .data ALIGN (0x1000): - { - *(.data) - } - - .bss ALIGN (0x1000): - { - *(COMMON) - *(.bss) - } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + _kernel_end = .; + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 4ebc650..558dd66 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -2,10 +2,21 @@ #include #include #include +#include +#include +#include + +extern uint32_t _kernel_end; void kernelMain() { clearScreen(); setTextStyle(0x0F); printf(logo); - printf("Hello World! Tree OS is alive!"); + initMemoryAllocation(0x100000); // initializing stacks after the kernel seems to not work :( otherwise, _kernel_end should be passed here + printf("Hello World!\nTree OS is alive!\n"); + initOSTasks(); + printf("Switching to otherTask... \n"); + yields(); + printf("Returned to mainTask!\n"); + yield(); } \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.c b/src/kernel/lib/memory/alloc.c new file mode 100644 index 0000000..1c4d023 --- /dev/null +++ b/src/kernel/lib/memory/alloc.c @@ -0,0 +1,15 @@ +#include +#include +#include + +uint32_t currentPosition; + +void initMemoryAllocation(uint32_t kernelEnd) { + currentPosition = kernelEnd; +} + +void* malloc(uint32_t size) { + uint32_t result = currentPosition; + currentPosition += size; + return (void*) result; +} \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.h b/src/kernel/lib/memory/alloc.h new file mode 100644 index 0000000..bd195ae --- /dev/null +++ b/src/kernel/lib/memory/alloc.h @@ -0,0 +1,9 @@ +#ifndef ALLOC_H +#define ALLOC_H + +#include + +extern void initMemoryAllocation(uint32_t kernelEnd); +extern void* malloc(uint32_t size); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.c b/src/kernel/lib/task/osTasks.c new file mode 100644 index 0000000..407709a --- /dev/null +++ b/src/kernel/lib/task/osTasks.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +Task mainTask; +Task testTask; + +void testMain() { + printf("Hello from another task!\n"); + yield(); +} + +void initOSTasks() { + setRunningTask(&mainTask); + createTask(&testTask, (uint32_t) testMain, 0x0, 0x0); + schedule(&testTask); +} \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.h b/src/kernel/lib/task/osTasks.h new file mode 100644 index 0000000..880cedb --- /dev/null +++ b/src/kernel/lib/task/osTasks.h @@ -0,0 +1,9 @@ +#ifndef OS_TASKS_H +#define OS_TASKS_H + +#include + +extern void testMain(); +extern void initOSTasks(); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/task.c b/src/kernel/lib/task/task.c new file mode 100644 index 0000000..5b177fe --- /dev/null +++ b/src/kernel/lib/task/task.c @@ -0,0 +1,48 @@ +#include +#include +#include + +Task *runningTask; + +void createTask(Task *task, uint32_t mainFunction, uint32_t flags, uint32_t *pagedir) { + task->registers.eax = 0; + task->registers.ebx = 0; + task->registers.ecx = 0; + task->registers.edx = 0; + task->registers.esi = 0; + task->registers.edi = 0; + task->registers.eflags = flags; + task->registers.eip = mainFunction; + task->registers.cr3 = (uint32_t) pagedir; + task->registers.esp = 0xF000 + (uint32_t) malloc(0xF000); + task->nextTask = 0; +} + +void yield() { + Task* last = runningTask; + runningTask = runningTask->nextTask; + if (runningTask == 0x00) { + printf("No more tasks to run, halting . . .\n"); + asm("hlt"); + } + last->nextTask = 0x00; + switchTask(&(last->registers), &(runningTask->registers)); +} + +void schedule(Task* task) { + Task* test = runningTask; + while (test->nextTask != 0x0) { + test = test->nextTask; + } + printf("scheduling Task %x after task %x\n", task, test); + test->nextTask = task; +} + +void setRunningTask(Task* task) { + runningTask = task; +} + +void yields() { + schedule(runningTask); + yield(); +} \ No newline at end of file diff --git a/src/kernel/lib/task/task.h b/src/kernel/lib/task/task.h new file mode 100644 index 0000000..6a617cd --- /dev/null +++ b/src/kernel/lib/task/task.h @@ -0,0 +1,27 @@ +#ifndef TASK_H +#define TASK_H + +#include + +extern void initTasking(); + +typedef struct { + uint32_t eax, ebx, ecx, edx, esi, edi, esp, ebp, eip, eflags, cr3; +} Registers; + +typedef struct Task { + Registers registers; + struct Task *nextTask; // linked list of tasks that need to be done +} Task; + +extern void initTasking(); +extern void createTask(Task *task, uint32_t mainFunction, uint32_t flags, uint32_t *pagedir); + +extern void yield(); +extern void yields(); // yield, but first schedule the currently running task +extern void switchTask(Registers *old, Registers *new); +extern void schedule(Task* task); + +extern void setRunningTask(Task* task); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/task.s b/src/kernel/lib/task/task.s new file mode 100644 index 0000000..bb6d076 --- /dev/null +++ b/src/kernel/lib/task/task.s @@ -0,0 +1,49 @@ +.section .text +.global switchTask +switchTask: + pusha + pushf + mov %cr3, %eax #Push CR3 + push %eax + mov 44(%esp), %eax #The first argument, where to save + mov %ebx, 4(%eax) + mov %ecx, 8(%eax) + mov %edx, 12(%eax) + mov %esi, 16(%eax) + mov %edi, 20(%eax) + mov 36(%esp), %ebx #EAX + mov 40(%esp), %ecx #IP + mov 20(%esp), %edx #ESP + add $4, %edx #Remove the return value ;) + mov 16(%esp), %esi #EBP + mov 4(%esp), %edi #EFLAGS + mov %ebx, (%eax) + mov %edx, 24(%eax) + mov %esi, 28(%eax) + mov %ecx, 32(%eax) + mov %edi, 36(%eax) + pop %ebx #CR3 + mov %ebx, 40(%eax) + push %ebx #Goodbye again ;) + mov 48(%esp), %eax #Now it is the new object + mov 4(%eax), %ebx #EBX + mov 8(%eax), %ecx #ECX + mov 12(%eax), %edx #EDX + mov 16(%eax), %esi #ESI + mov 20(%eax), %edi #EDI + mov 28(%eax), %ebp #EBP + push %eax + mov 36(%eax), %eax #EFLAGS + push %eax + popf + pop %eax + mov 24(%eax), %esp #ESP + push %eax + mov 40(%eax), %eax #CR3 + mov %eax, %cr3 + pop %eax + push %eax + mov 32(%eax), %eax #EIP + xchg (%esp), %eax #We do not have any more registers to use as tmp storage + mov (%eax), %eax #EAX + ret diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..71e1e9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cursor.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 9c8a6fb..e4f6439 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,19 @@ CC = i686-elf-gcc -CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../src/kernel +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I src/kernel LD = i686-elf-ld -LDFLAGS = AS = nasm -ASFLAGS = -felf32 +ASFlAGS = -felf32 GENISO = genisoimage GENISOFLAGS = -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -input-charset utf8 -quiet -boot-info-table -A tree-os EMU = qemu-system-x86_64 EMUFLAGS = -m 256M -cdrom -default: run clean +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find src -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +default: run run: tree-os.iso $(EMU) $(EMUFLAGS) $^ @@ -17,17 +21,23 @@ tree-os.iso: iso/boot/tree-os.elf $(GENISO) $(GENISOFLAGS) -o $@ iso -iso/boot/tree-os.elf: compile/boot.o compile/kernelFull.o - $(LD) $(LDFLAGS) -o $@ $^ +iso/boot/tree-os.elf: linker.ld $(OBJS) + $(LD) -T linker.ld -o $@ $(OBJS) -compile/boot.o: src/multiboot/boot.asm compile - $(AS) $(ASFLAGS) -o $@ $< +$(BUILD_FOLDER)/%.asm.o: %.asm + mkdir -p $(dir $@) + $(AS) $(ASFlAGS) $< -o $@ -compile/kernelFull.o: compile - cd compile && all=$$(find ../src/kernel -name *.c) && $(CC) $(CCFLAGS) $$all && all=$$(find . -name '*.o') && $(LD) $(LDFLAGS) -r -o kernelFull.o $$all +$(BUILD_FOLDER)/%.c.o: %.c + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ -compile: - mkdir compile +$(BUILD_FOLDER)/%.s.o: %.s + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ clean: - rm -r compile \ No newline at end of file + rm -r $(BUILD_FOLDER) + +cleanELF: + rm iso/boot/tree-os.elf \ No newline at end of file diff --git a/linker.ld b/linker.ld index 3a3d2c0..b3c2db3 100644 --- a/linker.ld +++ b/linker.ld @@ -1,26 +1,242 @@ +/* Script for -z combreloc -z separate-code */ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +/* file generated with ld --verbose */ +OUTPUT_ARCH(i386) ENTRY(_start) - -SECTIONS { - . = 0x00100000; /* load code at 1 MB */ - - .text ALIGN (0x1000): +SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib"); +SECTIONS +{ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { - *(.text) + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) } - - .rodata ALIGN (0x1000): + .rela.plt : { - *(.rodata*) + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } +.plt.got : { *(.plt.got) } +.plt.sec : { *(.plt.sec) } + _kernel_start = .; - .data ALIGN (0x1000): - { - *(.data) - } - - .bss ALIGN (0x1000): - { - *(COMMON) - *(.bss) - } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + _kernel_end = .; + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 4ebc650..558dd66 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -2,10 +2,21 @@ #include #include #include +#include +#include +#include + +extern uint32_t _kernel_end; void kernelMain() { clearScreen(); setTextStyle(0x0F); printf(logo); - printf("Hello World! Tree OS is alive!"); + initMemoryAllocation(0x100000); // initializing stacks after the kernel seems to not work :( otherwise, _kernel_end should be passed here + printf("Hello World!\nTree OS is alive!\n"); + initOSTasks(); + printf("Switching to otherTask... \n"); + yields(); + printf("Returned to mainTask!\n"); + yield(); } \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.c b/src/kernel/lib/memory/alloc.c new file mode 100644 index 0000000..1c4d023 --- /dev/null +++ b/src/kernel/lib/memory/alloc.c @@ -0,0 +1,15 @@ +#include +#include +#include + +uint32_t currentPosition; + +void initMemoryAllocation(uint32_t kernelEnd) { + currentPosition = kernelEnd; +} + +void* malloc(uint32_t size) { + uint32_t result = currentPosition; + currentPosition += size; + return (void*) result; +} \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.h b/src/kernel/lib/memory/alloc.h new file mode 100644 index 0000000..bd195ae --- /dev/null +++ b/src/kernel/lib/memory/alloc.h @@ -0,0 +1,9 @@ +#ifndef ALLOC_H +#define ALLOC_H + +#include + +extern void initMemoryAllocation(uint32_t kernelEnd); +extern void* malloc(uint32_t size); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.c b/src/kernel/lib/task/osTasks.c new file mode 100644 index 0000000..407709a --- /dev/null +++ b/src/kernel/lib/task/osTasks.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +Task mainTask; +Task testTask; + +void testMain() { + printf("Hello from another task!\n"); + yield(); +} + +void initOSTasks() { + setRunningTask(&mainTask); + createTask(&testTask, (uint32_t) testMain, 0x0, 0x0); + schedule(&testTask); +} \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.h b/src/kernel/lib/task/osTasks.h new file mode 100644 index 0000000..880cedb --- /dev/null +++ b/src/kernel/lib/task/osTasks.h @@ -0,0 +1,9 @@ +#ifndef OS_TASKS_H +#define OS_TASKS_H + +#include + +extern void testMain(); +extern void initOSTasks(); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/task.c b/src/kernel/lib/task/task.c new file mode 100644 index 0000000..5b177fe --- /dev/null +++ b/src/kernel/lib/task/task.c @@ -0,0 +1,48 @@ +#include +#include +#include + +Task *runningTask; + +void createTask(Task *task, uint32_t mainFunction, uint32_t flags, uint32_t *pagedir) { + task->registers.eax = 0; + task->registers.ebx = 0; + task->registers.ecx = 0; + task->registers.edx = 0; + task->registers.esi = 0; + task->registers.edi = 0; + task->registers.eflags = flags; + task->registers.eip = mainFunction; + task->registers.cr3 = (uint32_t) pagedir; + task->registers.esp = 0xF000 + (uint32_t) malloc(0xF000); + task->nextTask = 0; +} + +void yield() { + Task* last = runningTask; + runningTask = runningTask->nextTask; + if (runningTask == 0x00) { + printf("No more tasks to run, halting . . .\n"); + asm("hlt"); + } + last->nextTask = 0x00; + switchTask(&(last->registers), &(runningTask->registers)); +} + +void schedule(Task* task) { + Task* test = runningTask; + while (test->nextTask != 0x0) { + test = test->nextTask; + } + printf("scheduling Task %x after task %x\n", task, test); + test->nextTask = task; +} + +void setRunningTask(Task* task) { + runningTask = task; +} + +void yields() { + schedule(runningTask); + yield(); +} \ No newline at end of file diff --git a/src/kernel/lib/task/task.h b/src/kernel/lib/task/task.h new file mode 100644 index 0000000..6a617cd --- /dev/null +++ b/src/kernel/lib/task/task.h @@ -0,0 +1,27 @@ +#ifndef TASK_H +#define TASK_H + +#include + +extern void initTasking(); + +typedef struct { + uint32_t eax, ebx, ecx, edx, esi, edi, esp, ebp, eip, eflags, cr3; +} Registers; + +typedef struct Task { + Registers registers; + struct Task *nextTask; // linked list of tasks that need to be done +} Task; + +extern void initTasking(); +extern void createTask(Task *task, uint32_t mainFunction, uint32_t flags, uint32_t *pagedir); + +extern void yield(); +extern void yields(); // yield, but first schedule the currently running task +extern void switchTask(Registers *old, Registers *new); +extern void schedule(Task* task); + +extern void setRunningTask(Task* task); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/task.s b/src/kernel/lib/task/task.s new file mode 100644 index 0000000..bb6d076 --- /dev/null +++ b/src/kernel/lib/task/task.s @@ -0,0 +1,49 @@ +.section .text +.global switchTask +switchTask: + pusha + pushf + mov %cr3, %eax #Push CR3 + push %eax + mov 44(%esp), %eax #The first argument, where to save + mov %ebx, 4(%eax) + mov %ecx, 8(%eax) + mov %edx, 12(%eax) + mov %esi, 16(%eax) + mov %edi, 20(%eax) + mov 36(%esp), %ebx #EAX + mov 40(%esp), %ecx #IP + mov 20(%esp), %edx #ESP + add $4, %edx #Remove the return value ;) + mov 16(%esp), %esi #EBP + mov 4(%esp), %edi #EFLAGS + mov %ebx, (%eax) + mov %edx, 24(%eax) + mov %esi, 28(%eax) + mov %ecx, 32(%eax) + mov %edi, 36(%eax) + pop %ebx #CR3 + mov %ebx, 40(%eax) + push %ebx #Goodbye again ;) + mov 48(%esp), %eax #Now it is the new object + mov 4(%eax), %ebx #EBX + mov 8(%eax), %ecx #ECX + mov 12(%eax), %edx #EDX + mov 16(%eax), %esi #ESI + mov 20(%eax), %edi #EDI + mov 28(%eax), %ebp #EBP + push %eax + mov 36(%eax), %eax #EFLAGS + push %eax + popf + pop %eax + mov 24(%eax), %esp #ESP + push %eax + mov 40(%eax), %eax #CR3 + mov %eax, %cr3 + pop %eax + push %eax + mov 32(%eax), %eax #EIP + xchg (%esp), %eax #We do not have any more registers to use as tmp storage + mov (%eax), %eax #EAX + ret diff --git a/src/kernel/lib/textMode/stdio.c b/src/kernel/lib/textMode/stdio.c index 00cf2a0..41ad6f4 100644 --- a/src/kernel/lib/textMode/stdio.c +++ b/src/kernel/lib/textMode/stdio.c @@ -51,6 +51,7 @@ } char HEX_PREFIX[] = "0x"; +char HEX_CHARS[] = "0123456789ABCDEF"; void putHex(uint32_t x) { uint8_t alreadyWriting = 0; @@ -63,10 +64,7 @@ if (! alreadyWriting) { continue; } - if (nibble > 0x0A) { - nibble += 7; - } - putChar(nibble + 48); + putChar(HEX_CHARS[nibble]); } } diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..71e1e9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cursor.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 9c8a6fb..e4f6439 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,19 @@ CC = i686-elf-gcc -CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../src/kernel +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I src/kernel LD = i686-elf-ld -LDFLAGS = AS = nasm -ASFLAGS = -felf32 +ASFlAGS = -felf32 GENISO = genisoimage GENISOFLAGS = -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -input-charset utf8 -quiet -boot-info-table -A tree-os EMU = qemu-system-x86_64 EMUFLAGS = -m 256M -cdrom -default: run clean +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find src -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +default: run run: tree-os.iso $(EMU) $(EMUFLAGS) $^ @@ -17,17 +21,23 @@ tree-os.iso: iso/boot/tree-os.elf $(GENISO) $(GENISOFLAGS) -o $@ iso -iso/boot/tree-os.elf: compile/boot.o compile/kernelFull.o - $(LD) $(LDFLAGS) -o $@ $^ +iso/boot/tree-os.elf: linker.ld $(OBJS) + $(LD) -T linker.ld -o $@ $(OBJS) -compile/boot.o: src/multiboot/boot.asm compile - $(AS) $(ASFLAGS) -o $@ $< +$(BUILD_FOLDER)/%.asm.o: %.asm + mkdir -p $(dir $@) + $(AS) $(ASFlAGS) $< -o $@ -compile/kernelFull.o: compile - cd compile && all=$$(find ../src/kernel -name *.c) && $(CC) $(CCFLAGS) $$all && all=$$(find . -name '*.o') && $(LD) $(LDFLAGS) -r -o kernelFull.o $$all +$(BUILD_FOLDER)/%.c.o: %.c + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ -compile: - mkdir compile +$(BUILD_FOLDER)/%.s.o: %.s + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ clean: - rm -r compile \ No newline at end of file + rm -r $(BUILD_FOLDER) + +cleanELF: + rm iso/boot/tree-os.elf \ No newline at end of file diff --git a/linker.ld b/linker.ld index 3a3d2c0..b3c2db3 100644 --- a/linker.ld +++ b/linker.ld @@ -1,26 +1,242 @@ +/* Script for -z combreloc -z separate-code */ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +/* file generated with ld --verbose */ +OUTPUT_ARCH(i386) ENTRY(_start) - -SECTIONS { - . = 0x00100000; /* load code at 1 MB */ - - .text ALIGN (0x1000): +SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib"); +SECTIONS +{ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { - *(.text) + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) } - - .rodata ALIGN (0x1000): + .rela.plt : { - *(.rodata*) + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } +.plt.got : { *(.plt.got) } +.plt.sec : { *(.plt.sec) } + _kernel_start = .; - .data ALIGN (0x1000): - { - *(.data) - } - - .bss ALIGN (0x1000): - { - *(COMMON) - *(.bss) - } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + _kernel_end = .; + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 4ebc650..558dd66 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -2,10 +2,21 @@ #include #include #include +#include +#include +#include + +extern uint32_t _kernel_end; void kernelMain() { clearScreen(); setTextStyle(0x0F); printf(logo); - printf("Hello World! Tree OS is alive!"); + initMemoryAllocation(0x100000); // initializing stacks after the kernel seems to not work :( otherwise, _kernel_end should be passed here + printf("Hello World!\nTree OS is alive!\n"); + initOSTasks(); + printf("Switching to otherTask... \n"); + yields(); + printf("Returned to mainTask!\n"); + yield(); } \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.c b/src/kernel/lib/memory/alloc.c new file mode 100644 index 0000000..1c4d023 --- /dev/null +++ b/src/kernel/lib/memory/alloc.c @@ -0,0 +1,15 @@ +#include +#include +#include + +uint32_t currentPosition; + +void initMemoryAllocation(uint32_t kernelEnd) { + currentPosition = kernelEnd; +} + +void* malloc(uint32_t size) { + uint32_t result = currentPosition; + currentPosition += size; + return (void*) result; +} \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.h b/src/kernel/lib/memory/alloc.h new file mode 100644 index 0000000..bd195ae --- /dev/null +++ b/src/kernel/lib/memory/alloc.h @@ -0,0 +1,9 @@ +#ifndef ALLOC_H +#define ALLOC_H + +#include + +extern void initMemoryAllocation(uint32_t kernelEnd); +extern void* malloc(uint32_t size); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.c b/src/kernel/lib/task/osTasks.c new file mode 100644 index 0000000..407709a --- /dev/null +++ b/src/kernel/lib/task/osTasks.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +Task mainTask; +Task testTask; + +void testMain() { + printf("Hello from another task!\n"); + yield(); +} + +void initOSTasks() { + setRunningTask(&mainTask); + createTask(&testTask, (uint32_t) testMain, 0x0, 0x0); + schedule(&testTask); +} \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.h b/src/kernel/lib/task/osTasks.h new file mode 100644 index 0000000..880cedb --- /dev/null +++ b/src/kernel/lib/task/osTasks.h @@ -0,0 +1,9 @@ +#ifndef OS_TASKS_H +#define OS_TASKS_H + +#include + +extern void testMain(); +extern void initOSTasks(); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/task.c b/src/kernel/lib/task/task.c new file mode 100644 index 0000000..5b177fe --- /dev/null +++ b/src/kernel/lib/task/task.c @@ -0,0 +1,48 @@ +#include +#include +#include + +Task *runningTask; + +void createTask(Task *task, uint32_t mainFunction, uint32_t flags, uint32_t *pagedir) { + task->registers.eax = 0; + task->registers.ebx = 0; + task->registers.ecx = 0; + task->registers.edx = 0; + task->registers.esi = 0; + task->registers.edi = 0; + task->registers.eflags = flags; + task->registers.eip = mainFunction; + task->registers.cr3 = (uint32_t) pagedir; + task->registers.esp = 0xF000 + (uint32_t) malloc(0xF000); + task->nextTask = 0; +} + +void yield() { + Task* last = runningTask; + runningTask = runningTask->nextTask; + if (runningTask == 0x00) { + printf("No more tasks to run, halting . . .\n"); + asm("hlt"); + } + last->nextTask = 0x00; + switchTask(&(last->registers), &(runningTask->registers)); +} + +void schedule(Task* task) { + Task* test = runningTask; + while (test->nextTask != 0x0) { + test = test->nextTask; + } + printf("scheduling Task %x after task %x\n", task, test); + test->nextTask = task; +} + +void setRunningTask(Task* task) { + runningTask = task; +} + +void yields() { + schedule(runningTask); + yield(); +} \ No newline at end of file diff --git a/src/kernel/lib/task/task.h b/src/kernel/lib/task/task.h new file mode 100644 index 0000000..6a617cd --- /dev/null +++ b/src/kernel/lib/task/task.h @@ -0,0 +1,27 @@ +#ifndef TASK_H +#define TASK_H + +#include + +extern void initTasking(); + +typedef struct { + uint32_t eax, ebx, ecx, edx, esi, edi, esp, ebp, eip, eflags, cr3; +} Registers; + +typedef struct Task { + Registers registers; + struct Task *nextTask; // linked list of tasks that need to be done +} Task; + +extern void initTasking(); +extern void createTask(Task *task, uint32_t mainFunction, uint32_t flags, uint32_t *pagedir); + +extern void yield(); +extern void yields(); // yield, but first schedule the currently running task +extern void switchTask(Registers *old, Registers *new); +extern void schedule(Task* task); + +extern void setRunningTask(Task* task); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/task.s b/src/kernel/lib/task/task.s new file mode 100644 index 0000000..bb6d076 --- /dev/null +++ b/src/kernel/lib/task/task.s @@ -0,0 +1,49 @@ +.section .text +.global switchTask +switchTask: + pusha + pushf + mov %cr3, %eax #Push CR3 + push %eax + mov 44(%esp), %eax #The first argument, where to save + mov %ebx, 4(%eax) + mov %ecx, 8(%eax) + mov %edx, 12(%eax) + mov %esi, 16(%eax) + mov %edi, 20(%eax) + mov 36(%esp), %ebx #EAX + mov 40(%esp), %ecx #IP + mov 20(%esp), %edx #ESP + add $4, %edx #Remove the return value ;) + mov 16(%esp), %esi #EBP + mov 4(%esp), %edi #EFLAGS + mov %ebx, (%eax) + mov %edx, 24(%eax) + mov %esi, 28(%eax) + mov %ecx, 32(%eax) + mov %edi, 36(%eax) + pop %ebx #CR3 + mov %ebx, 40(%eax) + push %ebx #Goodbye again ;) + mov 48(%esp), %eax #Now it is the new object + mov 4(%eax), %ebx #EBX + mov 8(%eax), %ecx #ECX + mov 12(%eax), %edx #EDX + mov 16(%eax), %esi #ESI + mov 20(%eax), %edi #EDI + mov 28(%eax), %ebp #EBP + push %eax + mov 36(%eax), %eax #EFLAGS + push %eax + popf + pop %eax + mov 24(%eax), %esp #ESP + push %eax + mov 40(%eax), %eax #CR3 + mov %eax, %cr3 + pop %eax + push %eax + mov 32(%eax), %eax #EIP + xchg (%esp), %eax #We do not have any more registers to use as tmp storage + mov (%eax), %eax #EAX + ret diff --git a/src/kernel/lib/textMode/stdio.c b/src/kernel/lib/textMode/stdio.c index 00cf2a0..41ad6f4 100644 --- a/src/kernel/lib/textMode/stdio.c +++ b/src/kernel/lib/textMode/stdio.c @@ -51,6 +51,7 @@ } char HEX_PREFIX[] = "0x"; +char HEX_CHARS[] = "0123456789ABCDEF"; void putHex(uint32_t x) { uint8_t alreadyWriting = 0; @@ -63,10 +64,7 @@ if (! alreadyWriting) { continue; } - if (nibble > 0x0A) { - nibble += 7; - } - putChar(nibble + 48); + putChar(HEX_CHARS[nibble]); } } diff --git a/src/kernel/multiboot.h b/src/kernel/multiboot.h new file mode 100644 index 0000000..c6f5ff8 --- /dev/null +++ b/src/kernel/multiboot.h @@ -0,0 +1,274 @@ +/* multiboot.h - Multiboot header file. */ +/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY + * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MULTIBOOT_HEADER +#define MULTIBOOT_HEADER 1 + +/* How many bytes from the start of the file we search for the header. */ +#define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_HEADER_ALIGN 4 + +/* The magic field should contain this. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* This should be in %eax. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* Alignment of multiboot modules. */ +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +/* Alignment of the multiboot info structure. */ +#define MULTIBOOT_INFO_ALIGN 0x00000004 + +/* Flags set in the ’flags’ member of the multiboot header. */ + +/* Align all boot modules on i386 page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must pass memory information to OS. */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* Must pass video information to OS. */ +#define MULTIBOOT_VIDEO_MODE 0x00000004 + +/* This flag indicates the use of the address fields in the header. */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 + +/* Flags to be set in the ’flags’ member of the multiboot info structure. */ + +/* is there basic lower/upper memory information? */ +#define MULTIBOOT_INFO_MEMORY 0x00000001 +/* is there a boot device set? */ +#define MULTIBOOT_INFO_BOOTDEV 0x00000002 +/* is the command-line defined? */ +#define MULTIBOOT_INFO_CMDLINE 0x00000004 +/* are there modules to do something with? */ +#define MULTIBOOT_INFO_MODS 0x00000008 + +/* These next two are mutually exclusive */ + +/* is there a symbol table loaded? */ +#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010 +/* is there an ELF section header table? */ +#define MULTIBOOT_INFO_ELF_SHDR 0X00000020 + +/* is there a full memory map? */ +#define MULTIBOOT_INFO_MEM_MAP 0x00000040 + +/* Is there drive info? */ +#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080 + +/* Is there a config table? */ +#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 + +/* Is there a boot loader name? */ +#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 + +/* Is there a APM table? */ +#define MULTIBOOT_INFO_APM_TABLE 0x00000400 + +/* Is there video information? */ +#define MULTIBOOT_INFO_VBE_INFO 0x00000800 +#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 + +#ifndef ASM_FILE + +typedef unsigned char multiboot_uint8_t; +typedef unsigned short multiboot_uint16_t; +typedef unsigned int multiboot_uint32_t; +typedef unsigned long long multiboot_uint64_t; + +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC - see above. */ + multiboot_uint32_t magic; + + /* Feature flags. */ + multiboot_uint32_t flags; + + /* The above fields plus this one must equal 0 mod 2^32. */ + multiboot_uint32_t checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + multiboot_uint32_t header_addr; + multiboot_uint32_t load_addr; + multiboot_uint32_t load_end_addr; + multiboot_uint32_t bss_end_addr; + multiboot_uint32_t entry_addr; + + /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ + multiboot_uint32_t mode_type; + multiboot_uint32_t width; + multiboot_uint32_t height; + multiboot_uint32_t depth; +}; + +/* The symbol table for a.out. */ +struct multiboot_aout_symbol_table +{ + multiboot_uint32_t tabsize; + multiboot_uint32_t strsize; + multiboot_uint32_t addr; + multiboot_uint32_t reserved; +}; +typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; + +/* The section header table for ELF. */ +struct multiboot_elf_section_header_table +{ + multiboot_uint32_t num; + multiboot_uint32_t size; + multiboot_uint32_t addr; + multiboot_uint32_t shndx; +}; +typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; + +struct multiboot_info +{ + /* Multiboot info version number */ + multiboot_uint32_t flags; + + /* Available memory from BIOS */ + multiboot_uint32_t mem_lower; + multiboot_uint32_t mem_upper; + + /* "root" partition */ + multiboot_uint32_t boot_device; + + /* Kernel command line */ + multiboot_uint32_t cmdline; + + /* Boot-Module list */ + multiboot_uint32_t mods_count; + multiboot_uint32_t mods_addr; + + union + { + multiboot_aout_symbol_table_t aout_sym; + multiboot_elf_section_header_table_t elf_sec; + } u; + + /* Memory Mapping buffer */ + multiboot_uint32_t mmap_length; + multiboot_uint32_t mmap_addr; + + /* Drive Info buffer */ + multiboot_uint32_t drives_length; + multiboot_uint32_t drives_addr; + + /* ROM configuration table */ + multiboot_uint32_t config_table; + + /* Boot Loader Name */ + multiboot_uint32_t boot_loader_name; + + /* APM table */ + multiboot_uint32_t apm_table; + + /* Video */ + multiboot_uint32_t vbe_control_info; + multiboot_uint32_t vbe_mode_info; + multiboot_uint16_t vbe_mode; + multiboot_uint16_t vbe_interface_seg; + multiboot_uint16_t vbe_interface_off; + multiboot_uint16_t vbe_interface_len; + + multiboot_uint64_t framebuffer_addr; + multiboot_uint32_t framebuffer_pitch; + multiboot_uint32_t framebuffer_width; + multiboot_uint32_t framebuffer_height; + multiboot_uint8_t framebuffer_bpp; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + multiboot_uint8_t framebuffer_type; + union + { + struct + { + multiboot_uint32_t framebuffer_palette_addr; + multiboot_uint16_t framebuffer_palette_num_colors; + }; + struct + { + multiboot_uint8_t framebuffer_red_field_position; + multiboot_uint8_t framebuffer_red_mask_size; + multiboot_uint8_t framebuffer_green_field_position; + multiboot_uint8_t framebuffer_green_mask_size; + multiboot_uint8_t framebuffer_blue_field_position; + multiboot_uint8_t framebuffer_blue_mask_size; + }; + }; +}; +typedef struct multiboot_info multiboot_info_t; + +struct multiboot_color +{ + multiboot_uint8_t red; + multiboot_uint8_t green; + multiboot_uint8_t blue; +}; + +struct multiboot_mmap_entry +{ + multiboot_uint32_t size; + multiboot_uint64_t addr; + multiboot_uint64_t len; +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 + multiboot_uint32_t type; +} __attribute__((packed)); +typedef struct multiboot_mmap_entry multiboot_memory_map_t; + +struct multiboot_mod_list +{ + /* the memory used goes from bytes ’mod_start’ to ’mod_end-1’ inclusive */ + multiboot_uint32_t mod_start; + multiboot_uint32_t mod_end; + + /* Module command line */ + multiboot_uint32_t cmdline; + + /* padding to take it to 16 bytes (must be zero) */ + multiboot_uint32_t pad; +}; +typedef struct multiboot_mod_list multiboot_module_t; + +/* APM BIOS info. */ +struct multiboot_apm_info +{ + multiboot_uint16_t version; + multiboot_uint16_t cseg; + multiboot_uint32_t offset; + multiboot_uint16_t cseg_16; + multiboot_uint16_t dseg; + multiboot_uint16_t flags; + multiboot_uint16_t cseg_len; + multiboot_uint16_t cseg_16_len; + multiboot_uint16_t dseg_len; +}; + +#endif /* ! ASM_FILE */ + +#endif /* ! MULTIBOOT_HEADER */ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..71e1e9b --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.associations": { + "cursor.h": "c" + } +} \ No newline at end of file diff --git a/Makefile b/Makefile index 9c8a6fb..e4f6439 100644 --- a/Makefile +++ b/Makefile @@ -1,15 +1,19 @@ CC = i686-elf-gcc -CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I ../src/kernel +CCFLAGS = -m32 -mtune=generic -ffreestanding -nostdlib -c -I src/kernel LD = i686-elf-ld -LDFLAGS = AS = nasm -ASFLAGS = -felf32 +ASFlAGS = -felf32 GENISO = genisoimage GENISOFLAGS = -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -input-charset utf8 -quiet -boot-info-table -A tree-os EMU = qemu-system-x86_64 EMUFLAGS = -m 256M -cdrom -default: run clean +BUILD_FOLDER = build + +SOURCE_FILES := $(shell find src -name *.c -or -name *.asm -or -name *.s) +OBJS := $(SOURCE_FILES:%=$(BUILD_FOLDER)/%.o) + +default: run run: tree-os.iso $(EMU) $(EMUFLAGS) $^ @@ -17,17 +21,23 @@ tree-os.iso: iso/boot/tree-os.elf $(GENISO) $(GENISOFLAGS) -o $@ iso -iso/boot/tree-os.elf: compile/boot.o compile/kernelFull.o - $(LD) $(LDFLAGS) -o $@ $^ +iso/boot/tree-os.elf: linker.ld $(OBJS) + $(LD) -T linker.ld -o $@ $(OBJS) -compile/boot.o: src/multiboot/boot.asm compile - $(AS) $(ASFLAGS) -o $@ $< +$(BUILD_FOLDER)/%.asm.o: %.asm + mkdir -p $(dir $@) + $(AS) $(ASFlAGS) $< -o $@ -compile/kernelFull.o: compile - cd compile && all=$$(find ../src/kernel -name *.c) && $(CC) $(CCFLAGS) $$all && all=$$(find . -name '*.o') && $(LD) $(LDFLAGS) -r -o kernelFull.o $$all +$(BUILD_FOLDER)/%.c.o: %.c + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ -compile: - mkdir compile +$(BUILD_FOLDER)/%.s.o: %.s + mkdir -p $(dir $@) + $(CC) $(CCFLAGS) -r $< -o $@ clean: - rm -r compile \ No newline at end of file + rm -r $(BUILD_FOLDER) + +cleanELF: + rm iso/boot/tree-os.elf \ No newline at end of file diff --git a/linker.ld b/linker.ld index 3a3d2c0..b3c2db3 100644 --- a/linker.ld +++ b/linker.ld @@ -1,26 +1,242 @@ +/* Script for -z combreloc -z separate-code */ +/* Copyright (C) 2014-2020 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +/* file generated with ld --verbose */ +OUTPUT_ARCH(i386) ENTRY(_start) - -SECTIONS { - . = 0x00100000; /* load code at 1 MB */ - - .text ALIGN (0x1000): +SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/x86_64-linux-gnu/lib"); +SECTIONS +{ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + .interp : { *(.interp) } + .note.gnu.build-id : { *(.note.gnu.build-id) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : { - *(.text) + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*) + *(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*) + *(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*) + *(.rela.ifunc) } - - .rodata ALIGN (0x1000): + .rela.plt : { - *(.rodata*) + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); } + . = ALIGN(CONSTANT (MAXPAGESIZE)); + .init : + { + KEEP (*(SORT_NONE(.init))) + } + .plt : { *(.plt) *(.iplt) } +.plt.got : { *(.plt.got) } +.plt.sec : { *(.plt.sec) } + _kernel_start = .; - .data ALIGN (0x1000): - { - *(.data) - } - - .bss ALIGN (0x1000): - { - *(COMMON) - *(.bss) - } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + . = ALIGN(CONSTANT (MAXPAGESIZE)); + /* Adjust the address for the rodata segment. We want to adjust up to + the same address within the page on the next page up. */ + . = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1))); + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; PROVIDE (edata = .); + . = .; + __bss_start = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that the .bss section occupies space up to + _end. Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + .lbss : + { + *(.dynlbss) + *(.lbss .lbss.* .gnu.linkonce.lb.*) + *(LARGE_COMMON) + } + . = ALIGN(64 / 8); + . = SEGMENT_START("ldata-segment", .); + .lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.lrodata .lrodata.* .gnu.linkonce.lr.*) + } + .ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) : + { + *(.ldata .ldata.* .gnu.linkonce.l.*) + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + . = ALIGN(64 / 8); + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 : { *(.comment) } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1 */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2 */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2 */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3 */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF Extension. */ + .debug_macro 0 : { *(.debug_macro) } + .debug_addr 0 : { *(.debug_addr) } + .gnu.attributes 0 : { KEEP (*(.gnu.attributes)) } + _kernel_end = .; + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) } } \ No newline at end of file diff --git a/src/kernel/kernel.c b/src/kernel/kernel.c index 4ebc650..558dd66 100644 --- a/src/kernel/kernel.c +++ b/src/kernel/kernel.c @@ -2,10 +2,21 @@ #include #include #include +#include +#include +#include + +extern uint32_t _kernel_end; void kernelMain() { clearScreen(); setTextStyle(0x0F); printf(logo); - printf("Hello World! Tree OS is alive!"); + initMemoryAllocation(0x100000); // initializing stacks after the kernel seems to not work :( otherwise, _kernel_end should be passed here + printf("Hello World!\nTree OS is alive!\n"); + initOSTasks(); + printf("Switching to otherTask... \n"); + yields(); + printf("Returned to mainTask!\n"); + yield(); } \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.c b/src/kernel/lib/memory/alloc.c new file mode 100644 index 0000000..1c4d023 --- /dev/null +++ b/src/kernel/lib/memory/alloc.c @@ -0,0 +1,15 @@ +#include +#include +#include + +uint32_t currentPosition; + +void initMemoryAllocation(uint32_t kernelEnd) { + currentPosition = kernelEnd; +} + +void* malloc(uint32_t size) { + uint32_t result = currentPosition; + currentPosition += size; + return (void*) result; +} \ No newline at end of file diff --git a/src/kernel/lib/memory/alloc.h b/src/kernel/lib/memory/alloc.h new file mode 100644 index 0000000..bd195ae --- /dev/null +++ b/src/kernel/lib/memory/alloc.h @@ -0,0 +1,9 @@ +#ifndef ALLOC_H +#define ALLOC_H + +#include + +extern void initMemoryAllocation(uint32_t kernelEnd); +extern void* malloc(uint32_t size); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.c b/src/kernel/lib/task/osTasks.c new file mode 100644 index 0000000..407709a --- /dev/null +++ b/src/kernel/lib/task/osTasks.c @@ -0,0 +1,18 @@ +#include +#include +#include +#include + +Task mainTask; +Task testTask; + +void testMain() { + printf("Hello from another task!\n"); + yield(); +} + +void initOSTasks() { + setRunningTask(&mainTask); + createTask(&testTask, (uint32_t) testMain, 0x0, 0x0); + schedule(&testTask); +} \ No newline at end of file diff --git a/src/kernel/lib/task/osTasks.h b/src/kernel/lib/task/osTasks.h new file mode 100644 index 0000000..880cedb --- /dev/null +++ b/src/kernel/lib/task/osTasks.h @@ -0,0 +1,9 @@ +#ifndef OS_TASKS_H +#define OS_TASKS_H + +#include + +extern void testMain(); +extern void initOSTasks(); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/task.c b/src/kernel/lib/task/task.c new file mode 100644 index 0000000..5b177fe --- /dev/null +++ b/src/kernel/lib/task/task.c @@ -0,0 +1,48 @@ +#include +#include +#include + +Task *runningTask; + +void createTask(Task *task, uint32_t mainFunction, uint32_t flags, uint32_t *pagedir) { + task->registers.eax = 0; + task->registers.ebx = 0; + task->registers.ecx = 0; + task->registers.edx = 0; + task->registers.esi = 0; + task->registers.edi = 0; + task->registers.eflags = flags; + task->registers.eip = mainFunction; + task->registers.cr3 = (uint32_t) pagedir; + task->registers.esp = 0xF000 + (uint32_t) malloc(0xF000); + task->nextTask = 0; +} + +void yield() { + Task* last = runningTask; + runningTask = runningTask->nextTask; + if (runningTask == 0x00) { + printf("No more tasks to run, halting . . .\n"); + asm("hlt"); + } + last->nextTask = 0x00; + switchTask(&(last->registers), &(runningTask->registers)); +} + +void schedule(Task* task) { + Task* test = runningTask; + while (test->nextTask != 0x0) { + test = test->nextTask; + } + printf("scheduling Task %x after task %x\n", task, test); + test->nextTask = task; +} + +void setRunningTask(Task* task) { + runningTask = task; +} + +void yields() { + schedule(runningTask); + yield(); +} \ No newline at end of file diff --git a/src/kernel/lib/task/task.h b/src/kernel/lib/task/task.h new file mode 100644 index 0000000..6a617cd --- /dev/null +++ b/src/kernel/lib/task/task.h @@ -0,0 +1,27 @@ +#ifndef TASK_H +#define TASK_H + +#include + +extern void initTasking(); + +typedef struct { + uint32_t eax, ebx, ecx, edx, esi, edi, esp, ebp, eip, eflags, cr3; +} Registers; + +typedef struct Task { + Registers registers; + struct Task *nextTask; // linked list of tasks that need to be done +} Task; + +extern void initTasking(); +extern void createTask(Task *task, uint32_t mainFunction, uint32_t flags, uint32_t *pagedir); + +extern void yield(); +extern void yields(); // yield, but first schedule the currently running task +extern void switchTask(Registers *old, Registers *new); +extern void schedule(Task* task); + +extern void setRunningTask(Task* task); + +#endif \ No newline at end of file diff --git a/src/kernel/lib/task/task.s b/src/kernel/lib/task/task.s new file mode 100644 index 0000000..bb6d076 --- /dev/null +++ b/src/kernel/lib/task/task.s @@ -0,0 +1,49 @@ +.section .text +.global switchTask +switchTask: + pusha + pushf + mov %cr3, %eax #Push CR3 + push %eax + mov 44(%esp), %eax #The first argument, where to save + mov %ebx, 4(%eax) + mov %ecx, 8(%eax) + mov %edx, 12(%eax) + mov %esi, 16(%eax) + mov %edi, 20(%eax) + mov 36(%esp), %ebx #EAX + mov 40(%esp), %ecx #IP + mov 20(%esp), %edx #ESP + add $4, %edx #Remove the return value ;) + mov 16(%esp), %esi #EBP + mov 4(%esp), %edi #EFLAGS + mov %ebx, (%eax) + mov %edx, 24(%eax) + mov %esi, 28(%eax) + mov %ecx, 32(%eax) + mov %edi, 36(%eax) + pop %ebx #CR3 + mov %ebx, 40(%eax) + push %ebx #Goodbye again ;) + mov 48(%esp), %eax #Now it is the new object + mov 4(%eax), %ebx #EBX + mov 8(%eax), %ecx #ECX + mov 12(%eax), %edx #EDX + mov 16(%eax), %esi #ESI + mov 20(%eax), %edi #EDI + mov 28(%eax), %ebp #EBP + push %eax + mov 36(%eax), %eax #EFLAGS + push %eax + popf + pop %eax + mov 24(%eax), %esp #ESP + push %eax + mov 40(%eax), %eax #CR3 + mov %eax, %cr3 + pop %eax + push %eax + mov 32(%eax), %eax #EIP + xchg (%esp), %eax #We do not have any more registers to use as tmp storage + mov (%eax), %eax #EAX + ret diff --git a/src/kernel/lib/textMode/stdio.c b/src/kernel/lib/textMode/stdio.c index 00cf2a0..41ad6f4 100644 --- a/src/kernel/lib/textMode/stdio.c +++ b/src/kernel/lib/textMode/stdio.c @@ -51,6 +51,7 @@ } char HEX_PREFIX[] = "0x"; +char HEX_CHARS[] = "0123456789ABCDEF"; void putHex(uint32_t x) { uint8_t alreadyWriting = 0; @@ -63,10 +64,7 @@ if (! alreadyWriting) { continue; } - if (nibble > 0x0A) { - nibble += 7; - } - putChar(nibble + 48); + putChar(HEX_CHARS[nibble]); } } diff --git a/src/kernel/multiboot.h b/src/kernel/multiboot.h new file mode 100644 index 0000000..c6f5ff8 --- /dev/null +++ b/src/kernel/multiboot.h @@ -0,0 +1,274 @@ +/* multiboot.h - Multiboot header file. */ +/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY + * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR + * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef MULTIBOOT_HEADER +#define MULTIBOOT_HEADER 1 + +/* How many bytes from the start of the file we search for the header. */ +#define MULTIBOOT_SEARCH 8192 +#define MULTIBOOT_HEADER_ALIGN 4 + +/* The magic field should contain this. */ +#define MULTIBOOT_HEADER_MAGIC 0x1BADB002 + +/* This should be in %eax. */ +#define MULTIBOOT_BOOTLOADER_MAGIC 0x2BADB002 + +/* Alignment of multiboot modules. */ +#define MULTIBOOT_MOD_ALIGN 0x00001000 + +/* Alignment of the multiboot info structure. */ +#define MULTIBOOT_INFO_ALIGN 0x00000004 + +/* Flags set in the ’flags’ member of the multiboot header. */ + +/* Align all boot modules on i386 page (4KB) boundaries. */ +#define MULTIBOOT_PAGE_ALIGN 0x00000001 + +/* Must pass memory information to OS. */ +#define MULTIBOOT_MEMORY_INFO 0x00000002 + +/* Must pass video information to OS. */ +#define MULTIBOOT_VIDEO_MODE 0x00000004 + +/* This flag indicates the use of the address fields in the header. */ +#define MULTIBOOT_AOUT_KLUDGE 0x00010000 + +/* Flags to be set in the ’flags’ member of the multiboot info structure. */ + +/* is there basic lower/upper memory information? */ +#define MULTIBOOT_INFO_MEMORY 0x00000001 +/* is there a boot device set? */ +#define MULTIBOOT_INFO_BOOTDEV 0x00000002 +/* is the command-line defined? */ +#define MULTIBOOT_INFO_CMDLINE 0x00000004 +/* are there modules to do something with? */ +#define MULTIBOOT_INFO_MODS 0x00000008 + +/* These next two are mutually exclusive */ + +/* is there a symbol table loaded? */ +#define MULTIBOOT_INFO_AOUT_SYMS 0x00000010 +/* is there an ELF section header table? */ +#define MULTIBOOT_INFO_ELF_SHDR 0X00000020 + +/* is there a full memory map? */ +#define MULTIBOOT_INFO_MEM_MAP 0x00000040 + +/* Is there drive info? */ +#define MULTIBOOT_INFO_DRIVE_INFO 0x00000080 + +/* Is there a config table? */ +#define MULTIBOOT_INFO_CONFIG_TABLE 0x00000100 + +/* Is there a boot loader name? */ +#define MULTIBOOT_INFO_BOOT_LOADER_NAME 0x00000200 + +/* Is there a APM table? */ +#define MULTIBOOT_INFO_APM_TABLE 0x00000400 + +/* Is there video information? */ +#define MULTIBOOT_INFO_VBE_INFO 0x00000800 +#define MULTIBOOT_INFO_FRAMEBUFFER_INFO 0x00001000 + +#ifndef ASM_FILE + +typedef unsigned char multiboot_uint8_t; +typedef unsigned short multiboot_uint16_t; +typedef unsigned int multiboot_uint32_t; +typedef unsigned long long multiboot_uint64_t; + +struct multiboot_header +{ + /* Must be MULTIBOOT_MAGIC - see above. */ + multiboot_uint32_t magic; + + /* Feature flags. */ + multiboot_uint32_t flags; + + /* The above fields plus this one must equal 0 mod 2^32. */ + multiboot_uint32_t checksum; + + /* These are only valid if MULTIBOOT_AOUT_KLUDGE is set. */ + multiboot_uint32_t header_addr; + multiboot_uint32_t load_addr; + multiboot_uint32_t load_end_addr; + multiboot_uint32_t bss_end_addr; + multiboot_uint32_t entry_addr; + + /* These are only valid if MULTIBOOT_VIDEO_MODE is set. */ + multiboot_uint32_t mode_type; + multiboot_uint32_t width; + multiboot_uint32_t height; + multiboot_uint32_t depth; +}; + +/* The symbol table for a.out. */ +struct multiboot_aout_symbol_table +{ + multiboot_uint32_t tabsize; + multiboot_uint32_t strsize; + multiboot_uint32_t addr; + multiboot_uint32_t reserved; +}; +typedef struct multiboot_aout_symbol_table multiboot_aout_symbol_table_t; + +/* The section header table for ELF. */ +struct multiboot_elf_section_header_table +{ + multiboot_uint32_t num; + multiboot_uint32_t size; + multiboot_uint32_t addr; + multiboot_uint32_t shndx; +}; +typedef struct multiboot_elf_section_header_table multiboot_elf_section_header_table_t; + +struct multiboot_info +{ + /* Multiboot info version number */ + multiboot_uint32_t flags; + + /* Available memory from BIOS */ + multiboot_uint32_t mem_lower; + multiboot_uint32_t mem_upper; + + /* "root" partition */ + multiboot_uint32_t boot_device; + + /* Kernel command line */ + multiboot_uint32_t cmdline; + + /* Boot-Module list */ + multiboot_uint32_t mods_count; + multiboot_uint32_t mods_addr; + + union + { + multiboot_aout_symbol_table_t aout_sym; + multiboot_elf_section_header_table_t elf_sec; + } u; + + /* Memory Mapping buffer */ + multiboot_uint32_t mmap_length; + multiboot_uint32_t mmap_addr; + + /* Drive Info buffer */ + multiboot_uint32_t drives_length; + multiboot_uint32_t drives_addr; + + /* ROM configuration table */ + multiboot_uint32_t config_table; + + /* Boot Loader Name */ + multiboot_uint32_t boot_loader_name; + + /* APM table */ + multiboot_uint32_t apm_table; + + /* Video */ + multiboot_uint32_t vbe_control_info; + multiboot_uint32_t vbe_mode_info; + multiboot_uint16_t vbe_mode; + multiboot_uint16_t vbe_interface_seg; + multiboot_uint16_t vbe_interface_off; + multiboot_uint16_t vbe_interface_len; + + multiboot_uint64_t framebuffer_addr; + multiboot_uint32_t framebuffer_pitch; + multiboot_uint32_t framebuffer_width; + multiboot_uint32_t framebuffer_height; + multiboot_uint8_t framebuffer_bpp; +#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0 +#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1 +#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2 + multiboot_uint8_t framebuffer_type; + union + { + struct + { + multiboot_uint32_t framebuffer_palette_addr; + multiboot_uint16_t framebuffer_palette_num_colors; + }; + struct + { + multiboot_uint8_t framebuffer_red_field_position; + multiboot_uint8_t framebuffer_red_mask_size; + multiboot_uint8_t framebuffer_green_field_position; + multiboot_uint8_t framebuffer_green_mask_size; + multiboot_uint8_t framebuffer_blue_field_position; + multiboot_uint8_t framebuffer_blue_mask_size; + }; + }; +}; +typedef struct multiboot_info multiboot_info_t; + +struct multiboot_color +{ + multiboot_uint8_t red; + multiboot_uint8_t green; + multiboot_uint8_t blue; +}; + +struct multiboot_mmap_entry +{ + multiboot_uint32_t size; + multiboot_uint64_t addr; + multiboot_uint64_t len; +#define MULTIBOOT_MEMORY_AVAILABLE 1 +#define MULTIBOOT_MEMORY_RESERVED 2 +#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3 +#define MULTIBOOT_MEMORY_NVS 4 +#define MULTIBOOT_MEMORY_BADRAM 5 + multiboot_uint32_t type; +} __attribute__((packed)); +typedef struct multiboot_mmap_entry multiboot_memory_map_t; + +struct multiboot_mod_list +{ + /* the memory used goes from bytes ’mod_start’ to ’mod_end-1’ inclusive */ + multiboot_uint32_t mod_start; + multiboot_uint32_t mod_end; + + /* Module command line */ + multiboot_uint32_t cmdline; + + /* padding to take it to 16 bytes (must be zero) */ + multiboot_uint32_t pad; +}; +typedef struct multiboot_mod_list multiboot_module_t; + +/* APM BIOS info. */ +struct multiboot_apm_info +{ + multiboot_uint16_t version; + multiboot_uint16_t cseg; + multiboot_uint32_t offset; + multiboot_uint16_t cseg_16; + multiboot_uint16_t dseg; + multiboot_uint16_t flags; + multiboot_uint16_t cseg_len; + multiboot_uint16_t cseg_16_len; + multiboot_uint16_t dseg_len; +}; + +#endif /* ! ASM_FILE */ + +#endif /* ! MULTIBOOT_HEADER */ \ No newline at end of file diff --git a/src/multiboot/boot.asm b/src/multiboot/boot.asm index 5f668d8..965b8e1 100644 --- a/src/multiboot/boot.asm +++ b/src/multiboot/boot.asm @@ -2,8 +2,7 @@ MAGIC_NUMBER equ 0x1BADB002 ; 1 bad boot FLAGS equ 0x0 CHECKSUM equ -MAGIC_NUMBER - ; (magic number + checksum + flags should equal 0) -section .text: +section .text align 4 dd MAGIC_NUMBER dd FLAGS @@ -11,8 +10,9 @@ extern kernelMain KERNEL_STACK_SIZE equ 4096 ; 4kb of stack +global _start _start: - ; setup stack + ; setup stack for kernel main function mov esp, stack + KERNEL_STACK_SIZE ; call main function call kernelMain