diff --git a/042-osdev-08/README.md b/042-osdev-08/README.md new file mode 100644 index 0000000..99c3659 --- /dev/null +++ b/042-osdev-08/README.md @@ -0,0 +1,29 @@ +# Readme + +## Changes + +- added mode changing to 80x50 +- added terminal backend character attribute changing API +- added string formatting API (sorry, no floats) +- reworked source files to use makefile based build system + + +## Building + +Now building and cleaning everything is as simple as + +```bash +make clean && make build +``` + +In this configuration it uses qemu instead of bochs (which I find kinda slow anyway...). Adding bochs support is relative easy anyway. + + +## Panic Contest + +[![Image](http://i.imgur.com/qDneBv1.png)](http://i.imgur.com/qDneBv1.png "Preview") + + +## Author + +Karol Grzybowski (2017) \ No newline at end of file diff --git a/042-osdev-08/build.py b/042-osdev-08/build.py deleted file mode 100644 index cd28be0..0000000 --- a/042-osdev-08/build.py +++ /dev/null @@ -1,77 +0,0 @@ -#!/usr/bin/python -import os -import subprocess -from glob import glob - -def fix_stage1_size(): - stage2_size = os.stat("stage2").st_size - kernel_size = os.stat("kernel64").st_size - - stage2_size = (stage2_size + kernel_size + 511) / 512 - - if stage2_size >= 255: - raise Exception("stage2 & kernel are too large") - - with open("stage1", "rb+") as f: - d = f.read() - idx = d.index("\xb0\xcc\x90\x90") - d = bytearray(d) - d[idx+1] = stage2_size - f.seek(0) - f.write(d) - - -cmds_to_run = [] - -cc_flags = "-std=c99 -nostdlib -c -O0 -Wall -Wextra -masm=intel -ggdb" -ld_flags = "-std=c99 -nostdlib -o kernel64 -O0 -Wall -Wextra -masm=intel -ggdb" - -objfiles = [] - -for fname in glob("*.c"): - cmds_to_run.append("gcc %s %s" % (fname, cc_flags)) - objfiles.append("%s.o" % os.path.splitext(fname)[0]) - -as_flags = "-masm=intel -ggdb -c" - -for fname in glob("*.s"): - cmds_to_run.append("gcc %s %s" % (fname, as_flags)) - objfiles.append("%s.o" % os.path.splitext(fname)[0]) - -cmds_to_run.extend([ - "gcc %s %s" % (' '.join(objfiles), ld_flags), - "strip kernel64", - "nasm stage1.asm", - "nasm stage2.asm", - fix_stage1_size -]) - -files_to_img = [ - "stage1", - "stage2", - "kernel64" -] - -for cmd in cmds_to_run: - if type(cmd) is str: - print "Running:", cmd - print subprocess.check_output(cmd, shell=True) - else: - print "Calling:", cmd.func_name - cmd() - -buf = [] -for fn in files_to_img: - with open(fn, "rb") as f: - d = f.read() - buf.append(d) - - if len(d) % 512 == 0: - continue - - padding_size = 512 - len(d) % 512 - buf.append("\0" * padding_size); - -with open("floppy.bin", "wb") as f: - f.write(''.join(buf)) - diff --git a/042-osdev-08/build/build.py b/042-osdev-08/build/build.py new file mode 100644 index 0000000..6eabc7a --- /dev/null +++ b/042-osdev-08/build/build.py @@ -0,0 +1,46 @@ +#!/usr/bin/python +import os +import subprocess +from glob import glob + +def fix_stage1_size(): + stage2_size = os.stat("bootloader/stage2").st_size + kernel_size = os.stat("kernel/kernel64.elf").st_size + + stage2_size = (stage2_size + kernel_size + 511) / 512 + + if stage2_size >= 255: + raise Exception("stage2 & kernel are too large") + + with open("bootloader/stage1", "rb+") as f: + d = f.read() + idx = d.index("\xb0\xcc\x90\x90") + d = bytearray(d) + d[idx+1] = stage2_size + f.seek(0) + f.write(d) + +fix_stage1_size() + +files_to_img = [ + "bootloader/stage1", + "bootloader/stage2", + "kernel/kernel64.elf" +] + +buf = [] +for fn in files_to_img: + with open(fn, "rb") as f: + d = f.read() + print("length: " + str(len(d))) + buf.append(d) + + if len(d) % 512 == 0: + continue + + padding_size = 512 - len(d) % 512 + buf.append("\0" * padding_size); + +with open("floppy.bin", "wb") as f: + f.write(''.join(buf)) + diff --git a/042-osdev-08/build/makefile b/042-osdev-08/build/makefile new file mode 100644 index 0000000..6a5d02f --- /dev/null +++ b/042-osdev-08/build/makefile @@ -0,0 +1,28 @@ +include ../make/macros.mk + +clean: + $(host.rm) ./floppy.bin + +floppy.bin: + python ./build.py + + +QEMU_FLAGS = \ + -m 2048 \ + -cpu Haswell \ + -D qemu.log \ + -d cpu_reset,int,guest_errors \ + -vga std \ + -smp 4 + +QEMU_FLAGS_DEBUG = \ + -serial file:serial.log + +run-qemu: floppy.bin + qemu-system-x86_64 --fda $(<) $(QEMU_FLAGS) $(QEMU_FLAGS_DEBUG) + cat serial.log + +run-bochs: floppy.bin + +.PHONY: run-qemu run-bochs +build: run-qemu \ No newline at end of file diff --git a/042-osdev-08/osdev.bochsrc b/042-osdev-08/build/osdev.bochsrc similarity index 100% rename from 042-osdev-08/osdev.bochsrc rename to 042-osdev-08/build/osdev.bochsrc diff --git a/042-osdev-08/common.h b/042-osdev-08/common.h deleted file mode 100644 index 210b336..0000000 --- a/042-osdev-08/common.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once -#define UNUSED(a) (void)(a) - -typedef unsigned long long size_t; diff --git a/042-osdev-08/floppy.bin b/042-osdev-08/floppy.bin deleted file mode 100644 index 8b50ced..0000000 Binary files a/042-osdev-08/floppy.bin and /dev/null differ diff --git a/042-osdev-08/hal.c b/042-osdev-08/hal.c deleted file mode 100644 index 47e810e..0000000 --- a/042-osdev-08/hal.c +++ /dev/null @@ -1,14 +0,0 @@ -#include "hal.h" - -void HAL_PortOutByte(int port, unsigned char v) { - __asm("out dx, al\n" : : "a" (v), "d" (port)); -} - -void HAL_PortOutWord(int port, unsigned short v) { - __asm("out dx, ax\n" : : "a" (v), "d" (port)); -} - -void HAL_PortOutDword(int port, unsigned int v) { - __asm("out dx, eax\n" : : "a" (v), "d" (port)); -} - diff --git a/042-osdev-08/int_handlers.c b/042-osdev-08/int_handlers.c deleted file mode 100644 index e1611b4..0000000 --- a/042-osdev-08/int_handlers.c +++ /dev/null @@ -1,63 +0,0 @@ -#include "common.h" -#include "terminal.h" -#include "terminal_backend_b8000.h" - -// Thanks to Karol Grzybowski -typedef struct TrapFrame { - uint64_t r15; - uint64_t r14; - uint64_t r13; - uint64_t r12; - uint64_t r11; - uint64_t r10; - uint64_t r9; - uint64_t r8; - uint64_t rbp; - uint64_t rdi; - uint64_t rsi; - uint64_t rdx; - uint64_t rcx; - uint64_t rbx; - uint64_t rax; - uint64_t rsp; - - /*uint64_t trap_number; - uint64_t error_code;*/ - - uint64_t rip; - uint64_t segment_cs; - /*uint64_t rflags; - uint64_t rsp; - uint64_t segment_ss;*/ - -} TrapFrame; - -void GuruPanicOfDeath(const char *reason, TrapFrame *frame) { - TerminalBackend *con = TerminalBackendB8000(); - T_ClearScreen(con); - T_PutText(con, "Guru Panic Of Death!!!\n\n"); - T_Printf(con, "Reason: %s\n\n", reason); - T_PutText(con, "State:\n\n"); - - T_Printf(con, "RAX: %x\t\t R8: %x\n", frame->rax, frame->r8); - T_Printf(con, "RBX: %x\t\t R9: %x\n", frame->rbx, frame->r9); - T_Printf(con, "RCX: %x\t\t R10: %x\n", frame->rcx, frame->r10); - T_Printf(con, "RDX: %x\t\t R11: %x\n", frame->rdx, frame->r11); - T_Printf(con, "RSI: %x\t\t R12: %x\n", frame->rsi, frame->r12); - T_Printf(con, "RDI: %x\t\t R13: %x\n", frame->rdi, frame->r13); - T_Printf(con, "RBP: %x\t\t R14: %x\n", frame->rbp, frame->r14); - T_Printf(con, "RSP: %x\t\t R15: %x\n", frame->rsp, frame->r15); - - T_Printf(con, "CS:RIP: %x:%x\n\n", frame->segment_cs, frame->rip); - - - T_PutText(con, "System halt."); - - for (;;); -} - - -void Int_DE(TrapFrame *frame) { - GuruPanicOfDeath("DIVISION_ERROR", frame); -} - diff --git a/042-osdev-08/int_handlers.h b/042-osdev-08/int_handlers.h deleted file mode 100644 index 454e282..0000000 --- a/042-osdev-08/int_handlers.h +++ /dev/null @@ -1,3 +0,0 @@ -#pragma once -void Int_DE(void); - diff --git a/042-osdev-08/kernel64 b/042-osdev-08/kernel64 deleted file mode 100644 index f814b1c..0000000 Binary files a/042-osdev-08/kernel64 and /dev/null differ diff --git a/042-osdev-08/make/build.mk b/042-osdev-08/make/build.mk new file mode 100644 index 0000000..db59857 --- /dev/null +++ b/042-osdev-08/make/build.mk @@ -0,0 +1,635 @@ +#--------------------------------------------------------------------------------------------------- +# +# By Karol Grzybowski, 2017 +# +#--------------------------------------------------------------------------------------------------- +# +# Parameters: +# +# $(project.name) : [required] +# +# Provides a name of project in build system. +# +# $(project.uuid) : [optional] +# +# Provides project UUID to identify sub-builds. +# +# $(project.path) : [required] +# +# Provides path in build directory to where build target file. +# +# $(project.configuration) : [optional] +# +# Provides project specific configuration type. +# +# Available configuration types are: +# +# - `debug` +# +# Specifies a build configuration with optimizations disabled and +# assertions enabled. +# +# - `checked` +# +# Specifies a build configuration with both optimizations and +# assertions enabled. +# +# - `release` +# +# Specifies a build configuration with optimizations enabled and +# assertions disabled. +# +# +# $(project.component.major) : [required] +# +# Provides major component ID. +# +# $(project.component.minor) : [required] +# +# Provides minor component ID. +# +# $(project.type) : [required] +# +# Provides a project type. +# +# Available project types are: +# +# - `executable` +# +# Specifies an executable file project type. +# +# - `static` +# +# Specifies a static library project type. +# +# - `shared` +# +# Specifies a shared library project type. +# +# - `module` +# +# Specifies a shared kernel module project type. +# +# $(project.kind) : [required] +# +# Provides a project kind. +# +# - `target` +# +# Specifies that project uses target OS toolchain. +# +# - `native` +# +# Specifies that project uses native OS toolchain. +# +# $(project.sources) : [required] +# +# Provides a list of source files. +# +# $(project.defines) : [optional] +# +# Provides a list of compiler defines. +# +# $(project.includes) : [optional] +# +# Provides a list of additional project-specific include directories. +# +# $(project.libraries.static) : [optional] +# +# Provides a list of static libraries required to link project. +# +# $(project.libraries.shared) : [optional] +# +# Provides a list of shared libraries required to link project. +# +# $(project.flags.cc) +# $(project.flags.cc.{machine}) +# +# Provides a list of additional flags for C compiler. +# +# $(project.flags.cxx) +# $(project.flags.cxx.{machine}) +# +# Provides a list of additional flags for C++ compiler. +# +# $(project.flags.as) +# $(project.flags.as.{machine}) +# +# Provides a list of additional flags for assembler. +# +# $(project.flags.rc) +# $(project.flags.rc.{machine}) +# +# Provides a list of additional flags for resource compiler. +# +# $(project.flags.link) +# +# Provides a list of additional flags for linker. +# +#--------------------------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------------------------- +# +# Include base toolchain makefiles. +# +#--------------------------------------------------------------------------------------------------- +include $(BASE_DIRECTORY)/make/macros.mk +include $(BASE_DIRECTORY)/make/toolchain.mk + +#--------------------------------------------------------------------------------------------------- +# +# Validate required project parameters. +# +#--------------------------------------------------------------------------------------------------- + +ifndef project.name +$(error Variable project.name is required) +endif + +ifndef project.path +$(error Variable project.path is required) +endif + +ifndef project.component.major +$(error Variable project.component.minor is required) +endif + +ifndef project.component.minor +$(error Variable project.component.minor is required) +endif + +ifndef project.type +$(error Variable project.type is required) +endif + +ifndef project.sources +$(error Variable project.sources is required) +endif + +ifdef project.filename +$(error Project result filename can't be overriden) +endif + +#--------------------------------------------------------------------------------------------------- +# +# Apply defaults for optional project parameters. +# +#--------------------------------------------------------------------------------------------------- + +project.kind ?= target +project.uuid ?= $(project.name) +project.configuration ?= debug + +#--------------------------------------------------------------------------------------------------- +# +# Acquire C compiler flags. +# +#--------------------------------------------------------------------------------------------------- + +build.flags.cc := $(project.flags.cc) +build.flags.cc += $(project.flags.cc.${project.configuration}) +build.flags.cc += $(toolchain.flags.cc) +build.flags.cc += $(toolchain.flags.cc.${project.configuration}) +build.flags.cc += $(toolchain.${project.kind}.flags.cc) + +#--------------------------------------------------------------------------------------------------- +# +# Acquire C++ compiler flags. +# +#--------------------------------------------------------------------------------------------------- + +build.flags.cxx := $(project.flags.cxx) +build.flags.cxx += $(project.flags.cxx.${project.configuration}) +build.flags.cxx += $(toolchain.flags.cxx) +build.flags.cxx += $(toolchain.flags.cxx.${project.configuration}) +build.flags.cxx += $(toolchain.${project.kind}.flags.cxx) + +#--------------------------------------------------------------------------------------------------- +# +# Acquire Assembler flags. +# +#--------------------------------------------------------------------------------------------------- + +build.flags.as := $(project.flags.as) +build.flags.as += $(project.flags.as.${project.configuration}) +build.flags.as += $(toolchain.flags.as) +build.flags.as += $(toolchain.flags.as.${project.configuration}) +build.flags.as += $(toolchain.${project.kind}.flags.as) + +#--------------------------------------------------------------------------------------------------- +# +# Acquire resource compiler flags. +# +#--------------------------------------------------------------------------------------------------- + +build.flags.rc := $(project.flags.rc) +build.flags.rc += $(project.flags.rc.${project.configuration}) +build.flags.rc += $(toolchain.flags.rc) +build.flags.rc += $(toolchain.flags.rc.${project.configuration}) + +#--------------------------------------------------------------------------------------------------- +# +# Acquire link flags. +# +#--------------------------------------------------------------------------------------------------- + +build.flags.link := $(project.flags.link) +build.flags.link += $(project.flags.link.${project.configuration}) +build.flags.link += $(toolchain.flags.link) +build.flags.link += $(toolchain.flags.link.${project.configuration}) + +#--------------------------------------------------------------------------------------------------- +# +# Prepare include paths. +# +#--------------------------------------------------------------------------------------------------- + +build.includes := $(project.includes) +build.includes += $(toolchain.${project.kind}.includes) + +#--------------------------------------------------------------------------------------------------- +# +# Prepare compiler defines. +# +#--------------------------------------------------------------------------------------------------- + +build.defines := $(project.defines) +build.defines += $(toolchain.${project.kind}.defines) + +#--------------------------------------------------------------------------------------------------- +# +# Combine build path. +# +#--------------------------------------------------------------------------------------------------- + +build.path.target := $(global.path.build)/$(project.path) +build.path.object := obj/$(project.uuid) + +#--------------------------------------------------------------------------------------------------- +# +# Validate project type and choose type specific flags. +# +#--------------------------------------------------------------------------------------------------- +ifeq ($(project.type),executable) + +# +# Regular executable. +# + +build.filename := $(project.name).elf + +else ifeq ($(project.type),static) + +# +# Static library or kernel module. +# + +build.filename := lib$(project.name).a +build.flags.link += -static + +else ifeq ($(project.type),shared) + +# +# Shared library. +# + +build.filename := lib$(project.name).so +build.flags.link += -fPIC -shared +build.flags.cc += -fPIC +build.flags.as += -fPIC +build.flags.cxx += -fPIC +build.flags.rc += -fPIC + +else ifeq ($(project.type),module) + +# +# Loadable kernel module. +# + +build.filename := $(project.name).ko +build.flags.link += -r + +else + +$(error Unknown project type: $(project.type)) + +endif + +#--------------------------------------------------------------------------------------------------- +# +# This build system will use feature of compiler on which we specify directly which library we want +# to link instead of passing -l option. +# +# Process list of static link dependencies. +# +#--------------------------------------------------------------------------------------------------- + +build.libraries.static := $(foreach lib,$(project.libraries.static),$(dir $(global.path.build)/$(lib))lib$(notdir $(lib)).a) + +#--------------------------------------------------------------------------------------------------- +# +# Process list of shared link dependencies +# +#--------------------------------------------------------------------------------------------------- + +build.libraries.shared := $(foreach lib,$(project.libraries.shared),$(dir $(global.path.build)/$(lib))lib$(notdir $(lib)).so) + +build.libraries := $(addprefix -l,$(project.libraries)) + +#--------------------------------------------------------------------------------------------------- +# +# Prepare compiler list of include paths and defines. +# +#--------------------------------------------------------------------------------------------------- + +build.includes := $(addprefix -I,$(build.includes)) +build.defines := $(addprefix -D,$(build.defines)) + +#--------------------------------------------------------------------------------------------------- +# +# Clear list of objects. +# +#--------------------------------------------------------------------------------------------------- + +build.objects := + +#--------------------------------------------------------------------------------------------------- +# +# Convenient macro for making object file path from source path. +# +#--------------------------------------------------------------------------------------------------- + +build.make-object-path = $(strip $(subst ../,_/,$(build.path.object)/$(1).o)) + +#--------------------------------------------------------------------------------------------------- +# +# Description: +# +# Define rule for building .c files using toolchain C compiler. +# +# +# Parameters: +# +# $(1) - Provides a source file path. +# +# $(2) - Provides a target file path. +# +#--------------------------------------------------------------------------------------------------- +define rule.build.cc +build.objects += $(2) +$(2): $(1) + $(noecho)$(call make-dir,$(2)) + $(noecho)echo -e "CC: $(call echo.success,$(2))" + $(noecho)$(MAKEDEPEND) + $(noecho)$(toolchain.${project.kind}.cc) \ + -c $(1) \ + -o $(2) \ + $(build.flags.cc) \ + $(build.defines) \ + $(build.includes) \ + -MMD \ + -MP \ + -MT $(2) \ + -MF $(2:%o=%d) +endef + +#--------------------------------------------------------------------------------------------------- +# +# Description: +# +# Define rule for assembling .S files using toolchain assembler. +# +# +# Parameters: +# +# $(1) - Provides a source file path. +# +# $(2) - Provides a target file path. +# +#--------------------------------------------------------------------------------------------------- + +define rule.build.as +build.objects += $(2) +$(2): $(1) + $(noecho)$(call make-dir,$(2)) + $(noecho)echo -e "AS: $(call echo.success,$(2))" + $(noecho)$(MAKEDEPEND) + $(noecho)$(toolchain.${project.kind}.as) \ + -c $(1) \ + -o $(2) \ + $(build.flags.as) \ + $(build.defines) \ + $(build.includes) \ + -MMD \ + -MP \ + -MT $(2) \ + -MF $(2:%o=%d) +endef + +#--------------------------------------------------------------------------------------------------- +# +# Description: +# +# Define rule for assembling .S files using toolchain assembler. +# +# +# Parameters: +# +# $(1) - Provides a source file path. +# +# $(2) - Provides a target file path. +# +#--------------------------------------------------------------------------------------------------- + +define rule.build.asm +build.objects += $(2) +$(2): $(1) + $(noecho)$(call make-dir,$(2)) + $(noecho)echo -e "AS: $(call echo.success,$(2))" + $(noecho)$(MAKEDEPEND) + nasm \ + $(1) \ + -o $(2) \ + -f bin +endef + +#--------------------------------------------------------------------------------------------------- +# +# Description: +# +# Define rule for compiling .cxx files using C++ compiler. +# +# +# Parameters: +# +# $(1) - Provides a source file path. +# +# $(2) - Provides a target file path. +# +#--------------------------------------------------------------------------------------------------- + +define rule.build.cxx +build.objects += $(2) +$(2): $(1) + $(noecho)$(call make-dir,$(2)) + $(noecho)echo -e "CXX: $(call echo.success,$(2))" + $(noecho)$(MAKEDEPEND) + $(noecho)$(toolchain.${project.kind}.cxx) \ + -c $(1) \ + -o $(2) \ + $(build.flags.cxx) \ + $(build.defines) \ + $(build.includes) \ + -MMD \ + -MP \ + -MT $(2) \ + -MF $(2:%o=%d) +endef + +#--------------------------------------------------------------------------------------------------- +# +# TODO: Define rule for compiling .rc files. +# +#--------------------------------------------------------------------------------------------------- + + +#--------------------------------------------------------------------------------------------------- +# +# Filter source files by type. +# +#--------------------------------------------------------------------------------------------------- + +build.sources.cc := $(filter %.c,$(project.sources)) +build.sources.as := $(filter %.S,$(project.sources)) +build.sources.asm := $(filter %.asm,$(project.sources)) +build.sources.cxx := $(filter %.cxx,$(project.sources)) +build.sources.rc := $(filter %.rc,$(project.sources)) + +#--------------------------------------------------------------------------------------------------- +# +# Apply build rules. +# +#--------------------------------------------------------------------------------------------------- + +$(foreach src,$(build.sources.cc),$(eval $(call rule.build.cc,$(src),$(call build.make-object-path,$(src))))) +$(foreach src,$(build.sources.as),$(eval $(call rule.build.as,$(src),$(call build.make-object-path,$(src))))) +$(foreach src,$(build.sources.asm),$(eval $(call rule.build.asm,$(src),$(call build.make-object-path,$(src))))) +$(foreach src,$(build.sources.cxx),$(eval $(call rule.build.cxx,$(src),$(call build.make-object-path,$(src))))) + +#--------------------------------------------------------------------------------------------------- +# +# Combine build target. +# +#--------------------------------------------------------------------------------------------------- + +build.target := $(build.path.target)/$(build.filename) +build.target.hash := $(build.target).hash +build.target.sym := $(build.target).sym +build.target.rde := $(build.target).rde +build.target.lst := $(build.target).lst +build.target.dbg := $(build.target).dbg + +#--------------------------------------------------------------------------------------------------- +# +# Define main target. +# +#--------------------------------------------------------------------------------------------------- + +# +# Include dependencies for this project. +# +build.dependencies = $(build.objects:.o=.d) +-include $(build.dependencies) + + +# +# Use proper linker to build project. +# +ifeq ($(project.type),static) + +$(build.target): $(build.objects) + $(noecho)$(call make-dir,$(@)) + $(noecho)echo -e "LINK: $(call echo.success,$(@))" + $(noecho)$(toolchain.${project.kind}.ar) rcs $(@) $(^) + +else + +$(build.target): $(build.objects) + $(noecho)$(call make-dir,$(@)) + $(noecho)echo -e "LINK: $(call echo.success,$(@))" + $(noecho)$(toolchain.${project.kind}.link) $(^) -o $(@) $(build.libraries.static) $(build.libraries.shared) $(build.flags.link) $(build.libraries) + $(noecho)$(toolchain.${project.kind}.objcopy) --only-keep-debug $(@) $(@).dbg + $(noecho)$(toolchain.${project.kind}.objcopy) --strip-debug $(@) + $(noecho)$(toolchain.${project.kind}.objcopy) --add-gnu-debuglink=$(@).dbg $(@) + +endif + +#--------------------------------------------------------------------------------------------------- +# +# Define list of optional metadata targets. +# +#--------------------------------------------------------------------------------------------------- + +build.metadata-targets := + +ifeq ($(project.emit-metadata),true) + +build.metadata-targets += $(build.target.hash) +build.metadata-targets += $(build.target.sym) +build.metadata-targets += $(build.target.rde) +build.metadata-targets += $(build.target.lst) + +endif + +#--------------------------------------------------------------------------------------------------- +# +# Define other optional metadata targets builders. +# +#--------------------------------------------------------------------------------------------------- + +$(build.target.hash): $(build.target) + $(noecho)echo -e "SHA512: $(call echo.success,$(@))" + $(noecho)$(host.sha512sum) $(<) > $(@) + +$(build.target.sym): $(build.target) + $(noecho)echo -e "Symbols: $(call echo.success,$(@))" + $(noecho)$(toolchain.${project.kind}.nm) -C $(<) | sort > $(@) + +$(build.target.rde): $(build.target) + $(noecho)echo -e "Fileinfo: $(call echo.success,$(@))" + $(noecho)$(toolchain.${project.kind}.readelf) -aW $(<) > $(@) + +$(build.target.lst): $(build.target) + $(noecho)echo -e "Listing: $(call echo.success,$(@))" + $(noecho)$(toolchain.${project.kind}.objdump) --insn-width=14 -d $(<) > $(@) + +#--------------------------------------------------------------------------------------------------- +# +# Cleaning rule definition. +# +#--------------------------------------------------------------------------------------------------- + +clean: + $(noecho)echo -e "Removing: $(call echo.success,$(CURDIR)/obj)" + $(noecho)$(host.rmdir) ./obj + $(noecho)echo -e "Removing: $(call echo.success,$(build.target))" + $(noecho)$(host.rm) $(build.target) + $(noecho)echo -e "Removing: $(call echo.success,$(build.target.dbg))" + $(noecho)$(host.rm) $(build.target.dbg) + $(noecho)$(host.rm) $(build.metadata-targets) + +#--------------------------------------------------------------------------------------------------- +# +# Project configure rule definition. +# +#--------------------------------------------------------------------------------------------------- + +configure: + +#--------------------------------------------------------------------------------------------------- +# +# Build rule definition. +# +#--------------------------------------------------------------------------------------------------- + +build: $(build.target) $(build.metadata-targets) diff --git a/042-osdev-08/make/macros.mk b/042-osdev-08/make/macros.mk new file mode 100644 index 0000000..568e626 --- /dev/null +++ b/042-osdev-08/make/macros.mk @@ -0,0 +1,105 @@ +#--------------------------------------------------------------------------------------------------- +# +# By Karol Grzybowski, 2017 +# +#--------------------------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------------------------- +# +# Base paths. +# +#--------------------------------------------------------------------------------------------------- + +global.path.base = $(BASE_DIRECTORY) +global.path.make = $(global.path.base)/make +global.path.build = $(global.path.base)/build + +#--------------------------------------------------------------------------------------------------- +# +# Common defintions. +# +#--------------------------------------------------------------------------------------------------- + +empty := +space := $(empty) $(empty) +comma := , +colon := : + +#--------------------------------------------------------------------------------------------------- +# +# Host specific tools. +# +#--------------------------------------------------------------------------------------------------- + +host.path = $(1) +host.rm = rm -f $(1) +host.rmdir = rm -rf $(1) +host.mkdir = mkdir -p $(1) +host.ln = ln -s $(1) $(2) +host.cp = cp -f $(1) $(2) +host.mv = mv -f $(1) $(2) +host.install = cp -f $(1) $(2) +host.echo = echo -e +host.sha512sum = sha512sum + +#--------------------------------------------------------------------------------------------------- +# +# Makefile base tools. +# +#--------------------------------------------------------------------------------------------------- +parent-dir = $(patsubst %/,%,$(dir $(1:%/=%))) +make-dir = if [ ! -d $(1) ]; then mkdir -p $(dir $(1)); fi +link-dir = if [ ! -d $(1) ]; then ln $(1) $(2); fi +current-dir = $(call parent-dir,$(lastword $(MAKEFILE_LIST))) +current-makefile = $(lastword $(MAKEFILE_LIST)) + +#--------------------------------------------------------------------------------------------------- +# +# Host and build system information. +# +#--------------------------------------------------------------------------------------------------- + +host.get-username = $(shell whoami) +host.get-hostname = $(shell hostname) +host.timestamp = $(shell /bin/date "+%Y-%m-%dT%H:%M:%S") + +#--------------------------------------------------------------------------------------------------- +# +# DVCS commands for getting repository metadata. +# +#--------------------------------------------------------------------------------------------------- + +dvcs.command = $(shell which git) +dvcs.revision = $(shell $(dvcs.command) log -1 --format=%H) +dvcs.branch = $(shell $(dvcs.command) rev-parse --abbrev-ref HEAD) + +#--------------------------------------------------------------------------------------------------- +# +# Toggles command verbosity on demand. +# +#--------------------------------------------------------------------------------------------------- +ifeq ($(VERBOSE),true) +noecho = +else +noecho = @ +endif +export noecho + +#--------------------------------------------------------------------------------------------------- +# +# Base ASCII commands for chaning terminal colors. +# +#--------------------------------------------------------------------------------------------------- + +colors.success = \033[32;01m +colors.failure = \033[31;01m +colors.restore = \033[0m + +#--------------------------------------------------------------------------------------------------- +# +# Wrappers for colors. +# +#--------------------------------------------------------------------------------------------------- + +echo.success = $(colors.success)$(1)$(colors.restore) +echo.failure = $(colors.failure)$(1)$(colors.restore) diff --git a/042-osdev-08/make/recurse.mk b/042-osdev-08/make/recurse.mk new file mode 100644 index 0000000..438aa1c --- /dev/null +++ b/042-osdev-08/make/recurse.mk @@ -0,0 +1,43 @@ +#--------------------------------------------------------------------------------------------------- +# +# By Karol Grzybowski, 2017 +# +#--------------------------------------------------------------------------------------------------- + +ifneq ($(directories),) + +# +# Recurse over specified list of subdirectories. +# + +.PHONY: $(directories) recurse + +$(MAKECMDGOALS) recurse: $(directories) + +# +# Specify target for directories. +# +$(directories): + $(noecho)exec $(MAKE) --no-print-directory --directory=$(@) --makefile=dirs.mk $(MAKECMDGOALS) + +endif + +#--------------------------------------------------------------------------------------------------- + +ifneq ($(projects),) + +# +# Recurse over specified list of directories containing project.mk files. +# + +.PHONY: $(projects) recurse + +$(MAKECMDGOALS) recurse: $(projects) + +# +# Specify target for project.mk files. +# +$(projects): + $(noecho)exec $(MAKE) --no-print-directory --directory=$(@) --makefile=project.mk $(MAKECMDGOALS) --jobs $(shell nproc) + +endif \ No newline at end of file diff --git a/042-osdev-08/make/toolchain.mk b/042-osdev-08/make/toolchain.mk new file mode 100644 index 0000000..e39d549 --- /dev/null +++ b/042-osdev-08/make/toolchain.mk @@ -0,0 +1,195 @@ +#--------------------------------------------------------------------------------------------------- +# +# By Karol Grzybowski, 2017 +# +#--------------------------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------------------------- +# +# Toolchain cross-compiler path. +# +#--------------------------------------------------------------------------------------------------- + +toolchain.target.path := $(BASE_DIRECTORY)/build + + +#--------------------------------------------------------------------------------------------------- +# +# Native toolchain. +# +#--------------------------------------------------------------------------------------------------- + +toolchain.native.ar := ar +toolchain.native.as := gcc +toolchain.native.cc := gcc +toolchain.native.cxx := g++ +toolchain.native.link := g++ +toolchain.native.nm := nm +toolchain.native.objcopy := objcopy +toolchain.native.objdump := objdump +toolchain.native.ranlib := ranlib +toolchain.native.readelf := readelf +toolchain.native.strings := strings +toolchain.native.strip := strip + +toolchain.native.cflags := +toolchain.native.cxxflags := +toolchain.native.defines := + + +#--------------------------------------------------------------------------------------------------- +# +# Select proper target toolchain. +# +#--------------------------------------------------------------------------------------------------- + +#--------------------------------------------------------------------------------------------------- +# +# Crosscompile x86_64 +# +#--------------------------------------------------------------------------------------------------- + +toolchain.target.prefix := +toolchain.target.flags.as := -Wa,--divide +toolchain.target.flags.cc := -m64 -mtune=corei7 +toolchain.target.flags.cxx := -m64 -mtune=corei7 +toolchain.target.defines := + +#--------------------------------------------------------------------------------------------------- +# +# Apply target toolchain. +# +#--------------------------------------------------------------------------------------------------- + +toolchain.target.ar := $(toolchain.target.prefix)ar +toolchain.target.as := $(toolchain.target.prefix)gcc +toolchain.target.cc := $(toolchain.target.prefix)gcc +toolchain.target.cxx := $(toolchain.target.prefix)g++ +toolchain.target.link := $(toolchain.target.prefix)g++ +toolchain.target.nm := $(toolchain.target.prefix)nm +toolchain.target.objcopy := $(toolchain.target.prefix)objcopy +toolchain.target.objdump := $(toolchain.target.prefix)objdump +toolchain.target.ranlib := $(toolchain.target.prefix)ranlib +toolchain.target.readelf := $(toolchain.target.prefix)readelf +toolchain.target.strings := $(toolchain.target.prefix)strings +toolchain.target.strip := $(toolchain.target.prefix)strip + +#--------------------------------------------------------------------------------------------------- +# +# Configuration specific flags. +# +#--------------------------------------------------------------------------------------------------- + +toolchain.flags.cc.debug := -D_DEBUG -O0 -ggdb +toolchain.flags.cc.checked := -D_DEBUG -O3 +toolchain.flags.cc.release := -DNDEBUG -O3 + +toolchain.flags.cxx.debug := -D_DEBUG -O0 -ggdb +toolchain.flags.cxx.checked := -D_DEBUG -O3 +toolchain.flags.cxx.release := -DNDEBUG -O3 + +toolchain.flags.as.debug := +toolchain.flags.as.checked := +toolchain.flags.as.release := + +toolchain.flags.link.debug := +toolchain.flags.link.checked := +toolchain.flags.link.release := + +#--------------------------------------------------------------------------------------------------- +# +# Global toolchain flags. +# +#--------------------------------------------------------------------------------------------------- + +toolchain.flags.cc := \ + -std=c11 \ + -Wall \ + -Wextra \ + -Werror=implicit-function-declaration \ + -Wdouble-promotion \ + -Wbad-function-cast \ + -Wundef \ + -Wconversion \ + -Wwrite-strings \ + -Wno-conversion \ + -fstrict-aliasing \ + -Wstrict-aliasing=1 \ + -Werror=strict-aliasing \ + -Werror=address \ + -Werror \ + -Wmissing-format-attribute \ + -fdiagnostics-color \ + -fmax-errors=20 \ + -Wvla \ + -flto-odr-type-merging \ + -Wparentheses \ + -Wmissing-braces \ + -Wsequence-point \ + -Wlogical-op \ + -Wmissing-field-initializers \ + -Wundef \ + -Wfloat-equal \ + -Wshadow \ + -Wswitch \ + -Wunused \ + -Wuninitialized \ + -Wstrict-overflow=2 \ + -Wpointer-arith \ + -Wcast-align -Wformat=2 \ + -Winit-self \ + -Wunreachable-code \ + -fstack-protector-strong \ + -fvisibility=hidden \ + -Wno-format-zero-length + +# +# -Wno-implicit-fallthrough \ +# -Wno-bool-operation \ + +toolchain.flags.cxx := \ + -std=c++14 \ + -fmax-errors=20 \ + -fdiagnostics-color \ + -Wall \ + -Wextra \ + -Werror \ + -Werror=strict-aliasing \ + -Werror=address \ + -Werror=implicit-function-declaration \ + -Wdouble-promotion \ + -Wundef \ + -Wconversion \ + -Wwrite-strings \ + -Wstrict-aliasing=2 \ + -Wmissing-format-attribute \ + -Wfloat-equal \ + -Wshadow \ + -Wvla \ + -Wdisabled-optimization \ + -Wparentheses \ + -Wmissing-braces \ + -Wsequence-point \ + -Wswitch \ + -Wunused \ + -Wuninitialized \ + -Wstrict-overflow=2 \ + -Wpointer-arith \ + -Wlogical-op \ + -Wmissing-field-initializers \ + -Wcast-align \ + -Wcast-qual \ + -Wformat=2 \ + -Winit-self \ + -Winline \ + -Wunreachable-code \ + -flto-odr-type-merging \ + -fstack-protector-strong \ + -fvisibility=hidden \ + -Wno-format-zero-length + +#--------------------------------------------------------------------------------------------------- +# +# Predefined system includes +# +#--------------------------------------------------------------------------------------------------- diff --git a/042-osdev-08/makefile b/042-osdev-08/makefile new file mode 100644 index 0000000..afdecc7 --- /dev/null +++ b/042-osdev-08/makefile @@ -0,0 +1,15 @@ +BASE_DIRECTORY := $(shell pwd) + +export BASE_DIRECTORY + +include $(BASE_DIRECTORY)/make/macros.mk + +directories := source + +include $(BASE_DIRECTORY)/make/recurse.mk + +clean: + $(noecho)exec $(MAKE) --no-print-directory --directory=build $(MAKECMDGOALS) + +build: + $(noecho)exec $(MAKE) --no-print-directory --directory=build $(MAKECMDGOALS) \ No newline at end of file diff --git a/042-osdev-08/source/bootloader/project.mk b/042-osdev-08/source/bootloader/project.mk new file mode 100644 index 0000000..f5a632a --- /dev/null +++ b/042-osdev-08/source/bootloader/project.mk @@ -0,0 +1,20 @@ +include $(BASE_DIRECTORY)/make/macros.mk + +build.path.stage1 = $(global.path.build)/bootloader/stage1 +build.path.stage2 = $(global.path.build)/bootloader/stage2 + +$(build.path.stage1): source/stage1.asm + $(noecho)$(call make-dir,$(@)) + nasm $(<) -o $(@) + +$(build.path.stage2): source/stage2.asm + $(noecho)$(call make-dir,$(@)) + nasm $(<) -o $(@) + +clean: + $(host.rm) $(build.path.stage1) + $(host.rm) $(build.path.stage2) + + +build: $(build.path.stage1) $(build.path.stage2) + diff --git a/042-osdev-08/stage1.asm b/042-osdev-08/source/bootloader/source/stage1.asm similarity index 76% rename from 042-osdev-08/stage1.asm rename to 042-osdev-08/source/bootloader/source/stage1.asm index 567bee1..8489543 100644 --- a/042-osdev-08/stage1.asm +++ b/042-osdev-08/source/bootloader/source/stage1.asm @@ -16,6 +16,15 @@ start: ;mov word [es:di], 0x4141 ;jmp $ + ; + ; Change VGA mode to 80x50. Terminal_backend_b8000.c now rely on this screen dimensions. + ; + mov ax, 0003h + int 10h ;first set mode 03h + xor bx, bx + mov ax, 1112h + int 10h ;load 8x8 font + ; Load from floppy stage 2. ; DL == already set by BIOS ; AX -- 16 bits, AH AL -- 8 bits diff --git a/042-osdev-08/stage2.asm b/042-osdev-08/source/bootloader/source/stage2.asm similarity index 100% rename from 042-osdev-08/stage2.asm rename to 042-osdev-08/source/bootloader/source/stage2.asm diff --git a/042-osdev-08/source/dirs.mk b/042-osdev-08/source/dirs.mk new file mode 100644 index 0000000..535d7c5 --- /dev/null +++ b/042-osdev-08/source/dirs.mk @@ -0,0 +1,2 @@ +projects := bootloader kernel +include $(BASE_DIRECTORY)/make/recurse.mk \ No newline at end of file diff --git a/042-osdev-08/source/kernel/include/common.h b/042-osdev-08/source/kernel/include/common.h new file mode 100644 index 0000000..7fdb99d --- /dev/null +++ b/042-osdev-08/source/kernel/include/common.h @@ -0,0 +1,9 @@ +#pragma once +#define UNUSED(a) (void)(a) + +typedef unsigned long long size_t; +typedef signed long long ptrdiff_t; + +#if !defined(NULL) +#define NULL ((void*)0) +#endif \ No newline at end of file diff --git a/042-osdev-08/crt.h b/042-osdev-08/source/kernel/include/crt.h similarity index 100% rename from 042-osdev-08/crt.h rename to 042-osdev-08/source/kernel/include/crt.h diff --git a/042-osdev-08/hal.h b/042-osdev-08/source/kernel/include/hal.h similarity index 85% rename from 042-osdev-08/hal.h rename to 042-osdev-08/source/kernel/include/hal.h index 9a1ee70..7249dc8 100644 --- a/042-osdev-08/hal.h +++ b/042-osdev-08/source/kernel/include/hal.h @@ -2,4 +2,4 @@ void HAL_PortOutByte(int port, unsigned char v); void HAL_PortOutWord(int port, unsigned short v); void HAL_PortOutDword(int port, unsigned int v); - +void HAL_PauseKernel(); \ No newline at end of file diff --git a/042-osdev-08/idt.h b/042-osdev-08/source/kernel/include/idt.h similarity index 100% rename from 042-osdev-08/idt.h rename to 042-osdev-08/source/kernel/include/idt.h diff --git a/042-osdev-08/source/kernel/include/int_handlers.h b/042-osdev-08/source/kernel/include/int_handlers.h new file mode 100644 index 0000000..d3620b0 --- /dev/null +++ b/042-osdev-08/source/kernel/include/int_handlers.h @@ -0,0 +1,35 @@ +#pragma once + +// Thanks to Karol Grzybowski +typedef struct TrapFrame { + uint64_t r15; + uint64_t r14; + uint64_t r13; + uint64_t r12; + uint64_t r11; + uint64_t r10; + uint64_t r9; + uint64_t r8; + uint64_t rbp; + uint64_t rdi; + uint64_t rsi; + uint64_t rdx; + uint64_t rcx; + uint64_t rbx; + uint64_t rax; + uint64_t rsp; + + /*uint64_t trap_number; + uint64_t error_code;*/ + + uint64_t rip; + uint64_t segment_cs; + /*uint64_t rflags; + uint64_t rsp; + uint64_t segment_ss;*/ + +} TrapFrame; + +void Int_DE(TrapFrame *frame); + +void GuruPanicOfDeath(const char *reason, TrapFrame *frame); \ No newline at end of file diff --git a/042-osdev-08/terminal.h b/042-osdev-08/source/kernel/include/terminal.h similarity index 56% rename from 042-osdev-08/terminal.h rename to 042-osdev-08/source/kernel/include/terminal.h index 232d993..13eebb0 100644 --- a/042-osdev-08/terminal.h +++ b/042-osdev-08/source/kernel/include/terminal.h @@ -4,6 +4,25 @@ struct TerminalBackend; typedef struct TerminalBackend TerminalBackend; +typedef enum TerminalColor { + TerminalColor_Black = 0, + TerminalColor_Blue = 1, + TerminalColor_Green = 2, + TerminalColor_Cyan = 3, + TerminalColor_Red = 4, + TerminalColor_Magenta = 5, + TerminalColor_Brown = 6, + TerminalColor_LightGray = 7, + TerminalColor_Gray = 8, + TerminalColor_LightBlue = 9, + TerminalColor_LightGreen = 10, + TerminalColor_LightCyan = 11, + TerminalColor_LightRed = 12, + TerminalColor_LightMagenta = 13, + TerminalColor_LightYellow = 14, + TerminalColor_LightWhite = 15 +} TerminalColor; + // XXX on creation limit size to 32000x32000 typedef void (*TBfunc_SetCursorPosition)( @@ -11,6 +30,7 @@ typedef void (*TBfunc_SetCursorPosition)( typedef void (*TBfunc_GetCursorPosition)( TerminalBackend *tb, uint16_t *x, uint16_t *y); typedef void (*TBfunc_ClearScreen)(TerminalBackend *tb); +typedef void (*TBfunc_SetAttribute)(TerminalBackend *tb, TerminalColor bgcolor, TerminalColor fgcolor); typedef void (*TBfunc_PutCharacter)(TerminalBackend *tb, uint32_t ch); typedef void (*TBfunc_GetSize)(TerminalBackend *tb, uint16_t *w, uint16_t *h); @@ -20,6 +40,7 @@ struct TerminalBackend { TBfunc_SetCursorPosition func_set_cursor_position; TBfunc_GetCursorPosition func_get_cursor_position; TBfunc_ClearScreen func_clear_screen; + TBfunc_SetAttribute func_set_attribute; TBfunc_PutCharacter func_put_character; TBfunc_GetSize func_get_size; TBfunc_ScrollLine func_scroll_line; @@ -31,6 +52,7 @@ void T_SetCursorPosition( void T_GetCursorPosition( TerminalBackend *tb, uint16_t *x, uint16_t *y); void T_PutText(TerminalBackend *tb, const char *s); +void T_SetAttribute(TerminalBackend *tb, TerminalColor bgcolor, TerminalColor fgcolor); void T_ClearScreen(TerminalBackend *tb); void T_PutCharacter(TerminalBackend *tb, uint32_t ch); void T_GetSize(TerminalBackend *tb, uint16_t *w, uint16_t *h); diff --git a/042-osdev-08/terminal_backend_b8000.h b/042-osdev-08/source/kernel/include/terminal_backend_b8000.h similarity index 100% rename from 042-osdev-08/terminal_backend_b8000.h rename to 042-osdev-08/source/kernel/include/terminal_backend_b8000.h diff --git a/042-osdev-08/source/kernel/project.mk b/042-osdev-08/source/kernel/project.mk new file mode 100644 index 0000000..ab3bd71 --- /dev/null +++ b/042-osdev-08/source/kernel/project.mk @@ -0,0 +1,35 @@ + +project.name = kernel64 +project.type = executable +project.kind = target +project.path = kernel +project.component.major = boot +project.component.minor = kernel +project.emit-metadata = true +project.configuration = release + +project.sources = \ + $(wildcard source/*.S) \ + $(wildcard source/*.c) + +project.flags.cc = -ffreestanding -nostdlib -nostartfiles -masm=intel -mno-sse2 -mno-sse -mno-sse3 -mno-ssse3 -mno-sse4 +project.flags.as = -ffreestanding -nostdlib -nostartfiles -masm=intel -mno-sse2 -mno-sse -mno-sse3 -mno-ssse3 -mno-sse4 +project.flags.cxx = -ffreestanding -nostdlib -nostartfiles -masm=intel -mno-sse2 -mno-sse -mno-sse3 -mno-ssse3 -mno-sse4 + +project.flags.link = \ + -ffreestanding \ + -nostdlib \ + -Tsource/linker.lds \ + -Wl,-z,max-page-size=0x1000 \ + -Wl,-z,common-page-size=0x1000 + +project.flags.link.x86_64 = -mno-red-zone -mcmodel=kernel +project.flags.cc.x86_64 = -mno-red-zone -mcmodel=kernel +project.flags.cxx.x86_64 = -mno-red-zone -mcmodel=kernel + +project.libraries = gcc + +project.includes = \ + include + +include $(BASE_DIRECTORY)/make/build.mk diff --git a/042-osdev-08/crt.c b/042-osdev-08/source/kernel/source/crt.c similarity index 100% rename from 042-osdev-08/crt.c rename to 042-osdev-08/source/kernel/source/crt.c diff --git a/042-osdev-08/source/kernel/source/hal.c b/042-osdev-08/source/kernel/source/hal.c new file mode 100644 index 0000000..cc9d6e8 --- /dev/null +++ b/042-osdev-08/source/kernel/source/hal.c @@ -0,0 +1,22 @@ +#include "hal.h" + +void HAL_PortOutByte(int port, unsigned char v) { + __asm__("out dx, al\n" : : "a" (v), "d" (port)); +} + +void HAL_PortOutWord(int port, unsigned short v) { + __asm__("out dx, ax\n" : : "a" (v), "d" (port)); +} + +void HAL_PortOutDword(int port, unsigned int v) { + __asm__("out dx, eax\n" : : "a" (v), "d" (port)); +} + +void HAL_PauseKernel() { + // Disable interrupts, park CPU and wait for interrupt. Illogical, but doesn't burn VMs ;) + __asm__ __volatile__( + "cli\n" + "pause\n" + "hlt\n" + ); +} \ No newline at end of file diff --git a/042-osdev-08/idt.c b/042-osdev-08/source/kernel/source/idt.c similarity index 100% rename from 042-osdev-08/idt.c rename to 042-osdev-08/source/kernel/source/idt.c diff --git a/042-osdev-08/source/kernel/source/int_handlers.c b/042-osdev-08/source/kernel/source/int_handlers.c new file mode 100644 index 0000000..d8ee85f --- /dev/null +++ b/042-osdev-08/source/kernel/source/int_handlers.c @@ -0,0 +1,69 @@ +#include "common.h" +#include "terminal.h" +#include "terminal_backend_b8000.h" +#include "hal.h" +#include + +void GuruPanicOfDeath(const char *reason, TrapFrame *frame) { + TerminalBackend *con = TerminalBackendB8000(); + T_SetAttribute(con, TerminalColor_Black, TerminalColor_LightYellow); + T_ClearScreen(con); + T_PutText(con, "Homer Meditation of Donuts!!!\n\n"); + + T_PutText(con, "(credit: http://www.chris.com/ascii/index.php?art=cartoons/simpsons)\n\n"); + + + T_PutText(con, + " _ _,---._ \n" + " ,-',' `-.___ \n" + " /-;' `._ \n" + " /\\/ ._ _,'o \\ \n" + " ( /\\ _,--'\\,','\"`. ) \n" + " |\\ ,'o \' //\\ \n" + " | \\ / ,--'""`-. \n" + " : \\_ _/ ,-' `-._ \n" + " \\ `--' / ) \n" + " `. \\`._ ,' ________,',' \n" + " .--` ,' ,--` __\\___,;' \n" + " \\`.,-- ,' ,`_)--' /`.,' \n" + " \\( ; | | ) (`-/ \n" + " `--'| |) |-/ \n" + " | | | | | \n" + " | | |,.,-. | |_ \n" + " | `./ / )---` ) \n" + " _| / ,', ,-' \n" + " -hrr- ,'|_( /-<._,' |--, \n" + " | `--'---. \\/ \\ \n" + " | / \\ /\\ \\ \n" + " ,-^---._ | \\ / \\ \\ \n" + " ,-' \\----' \\/ \\--`. \n" + " / \\ \\ \\ \n" + "\n" + ); + + T_Printf(con, "Reason: %s\n", reason); + + if (frame != NULL) { + T_PutText(con, "State:\n"); + + T_Printf(con, " RAX: %016llx\tR8: %016llx\n", frame->rax, frame->r8); + T_Printf(con, " RBX: %016llx\tR9: %016llx\n", frame->rbx, frame->r9); + T_Printf(con, " RCX: %016llx\tR10: %016llx\n", frame->rcx, frame->r10); + T_Printf(con, " RDX: %016llx\tR11: %016llx\n", frame->rdx, frame->r11); + T_Printf(con, " RSI: %016llx\tR12: %016llx\n", frame->rsi, frame->r12); + T_Printf(con, " RDI: %016llx\tR13: %016llx\n", frame->rdi, frame->r13); + T_Printf(con, " RBP: %016llx\tR14: %016llx\n", frame->rbp, frame->r14); + T_Printf(con, " RSP: %016llx\tR15: %016llx\n", frame->rsp, frame->r15); + T_Printf(con, " CS:RIP: %04hx:%016llx\n\n", frame->segment_cs, frame->rip); + } + + T_PutText(con, "System halt."); + + HAL_PauseKernel(); +} + + +void Int_DE(TrapFrame *frame) { + GuruPanicOfDeath("DIVISION_ERROR", frame); +} + diff --git a/042-osdev-08/int_wrappers.s b/042-osdev-08/source/kernel/source/int_wrappers.S similarity index 100% rename from 042-osdev-08/int_wrappers.s rename to 042-osdev-08/source/kernel/source/int_wrappers.S diff --git a/042-osdev-08/kernel.c b/042-osdev-08/source/kernel/source/kernel.c similarity index 100% rename from 042-osdev-08/kernel.c rename to 042-osdev-08/source/kernel/source/kernel.c diff --git a/042-osdev-08/source/kernel/source/linker.lds b/042-osdev-08/source/kernel/source/linker.lds new file mode 100644 index 0000000..180211a --- /dev/null +++ b/042-osdev-08/source/kernel/source/linker.lds @@ -0,0 +1,39 @@ +ENTRY(_start) +OUTPUT_FORMAT(elf64-x86-64) + +SECTIONS +{ + . = 1M; + + .text ALIGN(0x1000): { + *(.text) + *(.text.*) + *(.gnu.linkonce.t*) + } + + .rodata ALIGN(0x1000): { + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r*) + } + + .data ALIGN(0x1000): { + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + } + + .bss ALIGN(0x1000): { + *(COMMON) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b*) + } + + /DISCARD/ : + { + *(.comment) + *(.eh_frame) /* C++ Exception Handler Frames are not required for kernel */ + } + +} diff --git a/042-osdev-08/source/kernel/source/rtl.c b/042-osdev-08/source/kernel/source/rtl.c new file mode 100644 index 0000000..c020899 --- /dev/null +++ b/042-osdev-08/source/kernel/source/rtl.c @@ -0,0 +1,1075 @@ +//-------------------------------------------------------------------------------------------------- +// +// By Karol Grzybowski, 2017 +// +//-------------------------------------------------------------------------------------------------- + +#include "common.h" +#include +#include +#include +#include + +const char rtl_string_digits_lowercase[] = "0123456789abcdefghijklmnopqrstuvwxyz"; +const char rtl_string_digits_uppercase[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +#define RTL_MIN(_X, _Y) (((_X) > (_Y)) ? (_Y) : (_X)) +#define RTL_MAX(_X, _Y) (((_X) > (_Y)) ? (_X) : (_Y)) +#define RTL_MAKE_FLAG(_Index) (1U << (_Index)) +#define RTL_FLAGS_SET(_Value, _Mask) ((_Value) | (_Mask)) +#define RTL_FLAGS_REF_SET(_Reference, _Mask) (((_Reference) |= (_Mask))) +#define RTL_FLAGS_UNSET(_Value, _Mask) ((_Value) & (~(_Mask))) +#define RTL_FLAGS_REF_UNSET(_Reference, _Mask) (((_Reference) &= ~(_Mask))) +#define RTL_FLAGS_HAS(_Value, _Mask) (((_Value) & (_Mask)) == (_Mask)) +#define RTL_FLAGS_ANY(_Value, _Mask) (((_Value) & (_Mask)) != 0) +#define RTL_FLAGS_NONE(_Value, _Mask) (((_Value) & (_Mask)) == 0) + + +#define FORMAT_FLAGS_NONE (0) +#define FORMAT_FLAGS_MINUS (1 << 0) +#define FORMAT_FLAGS_PLUS (1 << 1) +#define FORMAT_FLAGS_ALT (1 << 2) +#define FORMAT_FLAGS_SPACE (1 << 3) +#define FORMAT_FLAGS_ZERO (1 << 4) +#define FORMAT_FLAGS_DONE (1 << 5) +#define FORMAT_FLAGS_LOWERCASE (1 << 6) +#define FORMAT_FLAGS_WIDE (1 << 7) + +// +// Fundamental C integer types. +// + +#define FORMAT_TYPE_INT (0) +#define FORMAT_TYPE_CHAR (1) +#define FORMAT_TYPE_SHORT (2) +#define FORMAT_TYPE_LONG (3) +#define FORMAT_TYPE_LONGLONG (4) + +#define FORMAT_TYPE_LONGDOUBLE (5) + +#define FORMAT_TYPE_UNSIGNED (1U << 7) + +#define FORMAT_TYPE_NONE FORMAT_TYPE_INT + +#if defined(__x86_64__) + +#define FORMAT_TYPE_INTMAX FORMAT_TYPE_LONG +#define FORMAT_TYPE_PTRDIFF FORMAT_TYPE_LONG +#define FORMAT_TYPE_SIZE FORMAT_TYPE_LONG | FORMAT_TYPE_UNSIGNED +#define FORMAT_TYPE_UINTPTR FORMAT_TYPE_LONG | FORMAT_TYPE_UNSIGNED + +#elif defined(__aarch64__) + +#define FORMAT_TYPE_INTMAX FORMAT_TYPE_LONG +#define FORMAT_TYPE_PTRDIFF FORMAT_TYPE_LONG +#define FORMAT_TYPE_SIZE FORMAT_TYPE_LONG | FORMAT_TYPE_UNSIGNED +#define FORMAT_TYPE_UINTPTR FORMAT_TYPE_LONG | FORMAT_TYPE_UNSIGNED + +#else + +#error "Unknown architecture." + +#endif + +// +// Format state. +// +struct format_state { + // + // Integral number base. + // + uint32_t format_base; + + // + // Format flags. + // + uint32_t format_flags; + + // + // Format specifier type. + // + uint32_t format_type; + + // + // Format specifier width. + // + int32_t format_width; + + // + // Format specifier precision. + // + int32_t format_precision; + + // + // Buffer. + // + char* buffer; + + // + // Buffer capacity. + // + size_t buffer_capacity; + + // + // Number of total characters processed. + // + size_t processed; + + // + // Number of characters processed by current handler. + // + size_t current; + + // + // arglist iterator. + // + va_list arglist; +}; + +// Disable call to stdlib function (don't remember which one :D) +__attribute__((__optimize__("-fno-tree-loop-distribute-patterns"))) +static int +rtl_string_to_int32( + int32_t* result, + const char* string, + char** end_string, + int base +) +{ + if (result == NULL || string == NULL || end_string == NULL) + { + return -1; + } + + // + // Check integer base range. + // + if (base < 0 || base == 1 || base > 36) + { + (*end_string) = (char*)string; + (*result) = 0; + return -1; + } + + const char* it = string; + int character; + + // + // Skip whitespaces. + // + do + { + character = (int)(unsigned char)(*it++); + } while (character == ' '); + + // + // Check potential sign of value. + // + int is_negative; + if (character == '-') + { + is_negative = 1; + character = (int)(unsigned char)(*it++); + } + else + { + is_negative = 0; + if (character == '+') + { + character = (int)(unsigned char)(*it++); + } + } + + // + // Check string prefix. + // + if ((base == 0 || base == 16) && (character == '0' && (*it == 'x' || *it == 'X'))) + { + // + // This is hex string. + // + character = (int)(unsigned char)it[1]; + it += 2; + base = 16; + } + else if ((base == 0 || base == 2) && (character == '0' && (*it == 'b' || *it == 'B'))) + { + // + // Binary string. + // + character = (int)(unsigned char)it[1]; + it += 2; + base = 2; + } + + // + // Default to decimal or octal strings. + // + if (base == 0) + { + base = (character == '0') ? 8 : 10; + } + + // + // Compute string cutoff bounds. + // + int32_t cutoff = (is_negative ? INT32_MIN : INT32_MAX); + int32_t cutlim = cutoff % base; + cutoff /= base; + + // + // Adjust limits for negative ranges. + // + if (is_negative) + { + if (cutlim > 0) + { + cutlim -= base; + cutoff += 1; + } + cutlim = -cutlim; + } + + int32_t accumulator = 0; + int direction = 0; + + int status = 0; + + // + // Parse string. + // + for (;; character = (int)(unsigned char)(*it++)) + { + if ('0' <= character && character <= '9') + { + character -= '0'; + } + else if ('a' <= character && character <= 'z') + { + character -= 'a' - 10; + } + else if ('A' <= character && character <= 'Z') + { + character -= 'A' - 10; + } + else + { + // + // Invalid string range. + // + break; + } + + if (character >= base) + { + // + // Disallow digits larger than base. + // + break; + } + + if (direction < 0) + { + // + // Skip parsing until end of invalid / out of range number. + // + continue; + } + + if (is_negative) + { + if (accumulator < cutoff || (accumulator == cutoff && character > cutlim)) + { + // + // Value out of valid range. + // + direction = -1; + accumulator = INT32_MIN; + status = -1; + } + else + { + // + // Update accumulator. + // + direction = 1; + accumulator *= base; + accumulator -= character; + } + } + else + { + if (accumulator > cutoff || (accumulator == cutoff && character > cutlim)) + { + // + // Value ot of valid range. + // + direction = -1; + accumulator = INT32_MAX; + status = -1; + } + else + { + // + // Update accumulator. + // + direction = 1; + accumulator *= base; + accumulator += character; + } + } + } + + // + // Set result arguments. + // + (*end_string) = (char*)(direction ? (it - 1) : string); + (*result) = accumulator; + + return status; +} + +// +// Emits single character to format buffer. +// +static inline +void +rtlp_format_emit_char( + struct format_state* state, + int character, + size_t count +) +{ + size_t processed = 0; + + for (size_t i = 0; i < count; ++i) + { + if (state->processed < state->buffer_capacity) + { + ++processed; + state->buffer[state->processed] = (char)character; + } + + ++(state->processed); + } + + state->current += processed; +} + +static inline +void +rtlp_format_emit_string_n( + struct format_state* state, + const char* string, + size_t length +) +{ + size_t processed = 0; + + for (size_t i = 0; i < length; ++i) + { + if (state->processed < state->buffer_capacity) + { + ++processed; + state->buffer[state->processed] = string[i]; + } + + ++(state->processed); + } + + state->current += processed; +} + +static inline +void +format_emit_string( + struct format_state* state, + const char* string +) +{ + size_t processed = 0; + + for (; *string != '\0'; ++string) + { + if (state->processed < state->buffer_capacity) + { + ++processed; + state->buffer[state->processed] = *string; + } + + ++(state->processed); + } + + state->current += processed; +} + +static inline +void +rtlp_format_write_integer( + struct format_state* state, + uintmax_t value +) +{ + char sign = '\0'; + + if (!RTL_FLAGS_HAS(state->format_type, FORMAT_TYPE_UNSIGNED)) + { + const intmax_t svalue = (intmax_t)value; + const bool is_negative = svalue < 0; + + value = (is_negative ? ((uintmax_t)-svalue) : ((uintmax_t)svalue)); + + if (is_negative) + { + sign = '-'; + } + else if (RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_PLUS)) + { + sign = '+'; + } + else if (RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_SPACE)) + { + sign = ' '; + } + } + + enum { MAX_INTEGER_LENGTH = 96 }; + + char output_buffer[MAX_INTEGER_LENGTH]; + char* output_buffer_end = output_buffer + MAX_INTEGER_LENGTH; + + ptrdiff_t written = 0; + + const char* digits = RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_LOWERCASE) + ? rtl_string_digits_lowercase + : rtl_string_digits_uppercase; + + uintmax_t remaining = value; + + if ((state->format_precision != 0) || (remaining != 0)) + { + do + { + uintmax_t digit = remaining % state->format_base; + remaining /= state->format_base; + output_buffer_end[-++written] = digits[digit]; + } while (remaining != 0); + } + + while ((int32_t)written < state->format_precision) + { + output_buffer_end[-++written] = '0'; + } + + size_t padding = 0; + + if (!RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_MINUS) && RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_ZERO)) + { + while (written < (ptrdiff_t)state->format_width) + { + output_buffer_end[-++written] = '0'; + ++padding; + } + } + + if (sign != '\0') + { + if (padding == 0) + { + ++written; + } + + output_buffer_end[-written] = sign; + } + else if (RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_ALT)) + { + switch (state->format_base) + { + case 2: + { + written += (padding < 2) ? (2 - padding) : 0; + output_buffer_end[-written + 0] = '0'; + output_buffer_end[-written + 1] = RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_LOWERCASE) ? 'b' : 'B'; + break; + } + + case 8: + { + if (output_buffer_end[-written] != '0') + { + output_buffer_end[-++written] = '0'; + } + break; + } + + case 16: + { + written += (padding < 2) ? (2 - padding) : 0; + output_buffer_end[-written + 0] = '0'; + output_buffer_end[-written + 1] = RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_LOWERCASE) ? 'x': 'X'; + break; + } + + default: + { + break; + } + } + } + + if (!RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_MINUS)) + { + char leading = (!RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_MINUS) && RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_ZERO)) ? '0' : ' '; + + while (written < (ptrdiff_t)state->format_width) + { + output_buffer_end[-++written] = leading; + } + } + + rtlp_format_emit_string_n(state, output_buffer_end - written, (size_t)written); +} + +static inline +void +rtlp_format_write_char( + struct format_state* state, + int value +) +{ + if (RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_MINUS)) + { + rtlp_format_emit_char(state, value, 1); + + if ((size_t)(uint32_t)state->format_width > state->current) + { + rtlp_format_emit_char(state, ' ', (size_t)(uint32_t)state->format_width - state->current); + } + } + else + { + if (state->format_width != 0) + { + size_t adjust = (size_t)(uint32_t)state->format_width - state->current - 1; + + rtlp_format_emit_char(state, ' ', adjust); + } + + rtlp_format_emit_char(state, value, 1); + } +} + +// Disable call to strlen :) +__attribute__((__optimize__("-fno-tree-loop-distribute-patterns"))) +static size_t (strlen)(const char* _String) +{ + const char* eos = _String; + + while (*eos != '\0') + { + ++eos; + } + + return eos - _String; +} + +static inline +void +rtlp_format_write_string( + struct format_state* state, + const char* string +) +{ + size_t length = strlen(string); + + if (state->format_precision >= 0) + { + size_t precision = (size_t)(uint32_t)state->format_precision; + length = RTL_MIN(length, precision); + } + + if ((state->format_width == 0) || RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_MINUS)) + { + if (state->format_precision > 0) + { + size_t precision = (size_t)(uint32_t)state->format_precision; + length = RTL_MIN(length, precision); + } + + rtlp_format_emit_string_n(state, string, length); + + if ((size_t)(uint32_t)state->format_width > state->current) + { + length = (size_t)(uint32_t)state->format_width - state->current; + + rtlp_format_emit_char(state, ' ', length); + } + } + else + { + if ((size_t)(uint32_t)state->format_width > length) + { + size_t padding = (size_t)(uint32_t)state->format_width - length; + + rtlp_format_emit_char(state, ' ', padding); + } + + rtlp_format_emit_string_n(state, string, length); + } +} + +static inline int +rtlp_format_handle_specifier( + struct format_state* state, + const char* specifier, + size_t* processed +) +{ + int status = 0; + + const char* mark = specifier; + + if (*(++specifier) == '%') + { + rtlp_format_emit_char(state, *specifier, 1); + + ++specifier; + (*processed) = (size_t)(ptrdiff_t)(specifier - mark); + return status; + } + + state->format_flags = 0; + state->format_base = 0; + state->format_type = 0; + state->format_width = 0; + state->format_precision = -1; + state->current = 0; + + do + { + switch (*specifier++) + { + case '-': + { + state->format_flags |= FORMAT_FLAGS_MINUS; + break; + } + case '+': + { + state->format_flags |= FORMAT_FLAGS_PLUS; + break; + } + case '#': + { + state->format_flags |= FORMAT_FLAGS_ALT; + break; + } + case ' ': + { + state->format_flags |= FORMAT_FLAGS_SPACE; + break; + } + case '0': + { + state->format_flags |= FORMAT_FLAGS_ZERO; + break; + } + default: + { + state->format_flags |= FORMAT_FLAGS_DONE; + --specifier; + break; + } + } + } while (!RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_DONE)); + + if (*specifier == '*') + { + int32_t width = (int32_t)va_arg(state->arglist, int); + + if (width < 0) + { + state->format_flags |= FORMAT_FLAGS_MINUS; + width = -width; + } + + state->format_width = width; + ++specifier; + } + else + { + int32_t width = 0; + + status = rtl_string_to_int32(&width, specifier, (char**)&specifier, 10); + if (status != 0) + { + (*processed) = 0; + return status; + } + + state->format_width = width; + } + + if (*specifier == '.') + { + ++specifier; + + if (*specifier == '*') + { + state->format_precision = (int32_t)va_arg(state->arglist, int); + ++specifier; + } + else + { + int32_t precision = 0; + + status = rtl_string_to_int32(&precision, specifier, (char**)&specifier, 10); + if (status != 0) + { + (*processed) = 0; + return status; + } + + state->format_precision = precision; + } + + state->format_flags = RTL_FLAGS_UNSET(state->format_flags, FORMAT_FLAGS_ZERO); + } + + switch (*(specifier++)) + { + case 'h': + { + if (*specifier == 'h') + { + state->format_type = FORMAT_TYPE_CHAR; + ++specifier; + } + else + { + state->format_type = FORMAT_TYPE_SHORT; + } + break; + } + + case 'l': + { + if (*specifier == 'l') + { + state->format_type = FORMAT_TYPE_LONGLONG; + ++specifier; + } + else + { + state->format_type = FORMAT_TYPE_LONG; + } + break; + } + + case 'j': + { + state->format_type = FORMAT_TYPE_INTMAX; + break; + } + + case 'z': + { + state->format_type = FORMAT_TYPE_SIZE; + break; + } + + case 't': + { + state->format_type = FORMAT_TYPE_PTRDIFF; + break; + } + + case 'L': + { + state->format_type = FORMAT_TYPE_LONGDOUBLE; + break; + } + + default: + { + --specifier; + break; + } + } + + switch (*specifier) + { + case 'b': + { + state->format_flags |= FORMAT_FLAGS_LOWERCASE; + } + case 'B': + { + state->format_type |= FORMAT_TYPE_UNSIGNED; + state->format_base = 2; + break; + } + + case 'o': + { + state->format_type |= FORMAT_TYPE_UNSIGNED; + state->format_base = 8; + break; + } + + case 'u': + { + state->format_type |= FORMAT_TYPE_UNSIGNED; + } + case 'd': + case 'i': + { + state->format_base = 10; + break; + } + + case 'x': + { + state->format_flags |= FORMAT_FLAGS_LOWERCASE; + } + case 'X': + { + state->format_type |= FORMAT_TYPE_UNSIGNED; + state->format_base = 16; + break; + } + + case 'p': + { + state->format_flags |= FORMAT_FLAGS_LOWERCASE; + } + case 'P': + { + state->format_flags |= FORMAT_FLAGS_ALT; + state->format_type = FORMAT_TYPE_UINTPTR; + state->format_precision = sizeof(uintptr_t) * 2; + state->format_base = 16; + break; + } + + case 'a': + case 'e': + case 'f': + case 'g': + { + state->format_flags |= FORMAT_FLAGS_LOWERCASE; + } + case 'A': + case 'E': + case 'F': + case 'G': + { + return -1; + } + + case 'c': + { + int value = (int)va_arg(state->arglist, int); + rtlp_format_write_char(state, value); + + ++specifier; + (*processed) = (size_t)(ptrdiff_t)(specifier - mark); + return 0; + } + + case 's': + { + const char* value = (const char*)va_arg(state->arglist, const char*); + + if (value == NULL) + { + value = "(null)"; + } + + rtlp_format_write_string(state, value); + + ++specifier; + (*processed) = (size_t)(ptrdiff_t)(specifier - mark); + return 0; + } + + default: + { + (*processed) = 0; + return -1; + } + } + + // Integral output. + + if (state->format_base != 0) + { + uintmax_t value; + + switch (state->format_type) + { + case FORMAT_TYPE_CHAR: + value = (uintmax_t)(intmax_t)(char)va_arg(state->arglist, int); + break; + case FORMAT_TYPE_SHORT: + value = (uintmax_t)(intmax_t)(short)va_arg(state->arglist, int); + break; + case FORMAT_TYPE_INT: + value = (uintmax_t)(intmax_t)(int)va_arg(state->arglist, int); + break; + case FORMAT_TYPE_LONG: + value = (uintmax_t)(intmax_t)(long)va_arg(state->arglist, long); + break; + case FORMAT_TYPE_LONGLONG: + value = (uintmax_t)(intmax_t)(long long)va_arg(state->arglist, long long); + break; + case FORMAT_TYPE_UNSIGNED | FORMAT_TYPE_CHAR: + value = (uintmax_t)(unsigned char)va_arg(state->arglist, int); + break; + case FORMAT_TYPE_UNSIGNED | FORMAT_TYPE_SHORT: + value = (uintmax_t)(unsigned short)va_arg(state->arglist, int); + break; + case FORMAT_TYPE_UNSIGNED | FORMAT_TYPE_INT: + value = (uintmax_t)(unsigned int)va_arg(state->arglist, unsigned int); + break; + case FORMAT_TYPE_UNSIGNED | FORMAT_TYPE_LONG: + value = (uintmax_t)(unsigned long)va_arg(state->arglist, unsigned long); + break; + case FORMAT_TYPE_UNSIGNED | FORMAT_TYPE_LONGLONG: + value = (uintmax_t)(unsigned long long)va_arg(state->arglist, unsigned long long); + break; + default: + (*processed) = 0; + return -1; + } + + rtlp_format_write_integer(state, value); + + if (RTL_FLAGS_HAS(state->format_flags, FORMAT_FLAGS_MINUS) && (state->current - (size_t)(uint32_t)state->format_width) != 0) // Check: possible overrun + { + rtlp_format_emit_char(state, ' ', (size_t)(uint32_t)state->format_width - state->current); + } + } + + ++specifier; + + (*processed) = (size_t)(ptrdiff_t)(specifier - mark); + return status; +} + +int +rtl_string_format_v( + char* buffer, + size_t buffer_length, + size_t* processed, + const char* format, + va_list arglist +) +{ + if (format == NULL) + { + return -1; + } + + if ((buffer == NULL) && (buffer_length != 0)) + { + return -1; + } + + struct format_state state = { + .format_base = 0, + .format_flags = 0, + .format_type = 0, + .format_width = 0, + .format_precision = 0, + .buffer = buffer, + .buffer_capacity = buffer_length, + .processed = 0, + .current = 0, + }; + va_copy(state.arglist, arglist); + + int status = 0; + + while (*format != '\0') + { + const char* mark = format; + + while (*format != '\0' && *format != '%') + { + ++format; + } + + if (mark != format) + { + rtlp_format_emit_string_n(&state, mark, format - mark); + } + + if (*format == '%') + { + size_t consumed = 0; + status = rtlp_format_handle_specifier(&state, format, &consumed); + + if (status != 0) + { + if (processed != NULL) + { + (*processed) = 0; + } + return status; + } + + format += consumed; + + if (consumed == 0) + { + ++format; + rtlp_format_emit_char(&state, *format, 1); + } + } + } + + if (state.buffer != NULL) + { + if (state.processed < state.buffer_capacity) + { + state.buffer[state.processed] = '\0'; + } + else + { + state.buffer[state.buffer_capacity - 1] = '\0'; + } + } + + va_end(state.arglist); + + if (processed != NULL) + { + (*processed) = state.processed; + } + + return status; +} + +int +rtl_string_format( + char* buffer, + size_t buffer_length, + size_t* processed, + const char* format, + ... +) +{ + va_list arglist; + va_start(arglist, format); + int status = rtl_string_format_v( + buffer, + buffer_length, + processed, + format, + arglist + ); + va_end(arglist); + + return status; +} diff --git a/042-osdev-08/source/kernel/source/ssp.c b/042-osdev-08/source/kernel/source/ssp.c new file mode 100644 index 0000000..63f1021 --- /dev/null +++ b/042-osdev-08/source/kernel/source/ssp.c @@ -0,0 +1,18 @@ +#include "common.h" +#include + +#include + +void* __stack_chk_guard = NULL; + +void +__stack_chk_fail() +{ + GuruPanicOfDeath("STACK_FRAME_SMASHED", NULL); +} + +void +__chk_fail(void) +{ + GuruPanicOfDeath("STACK_FRAME_SMASHED", NULL); +} diff --git a/042-osdev-08/terminal.c b/042-osdev-08/source/kernel/source/terminal.c similarity index 72% rename from 042-osdev-08/terminal.c rename to 042-osdev-08/source/kernel/source/terminal.c index f16c5dd..5ae4cb4 100644 --- a/042-osdev-08/terminal.c +++ b/042-osdev-08/source/kernel/source/terminal.c @@ -1,6 +1,7 @@ #include #include "common.h" #include "terminal.h" +#include "hal.h" void T_SetCursorPosition( TerminalBackend *tb, uint16_t x, uint16_t y) { @@ -57,6 +58,10 @@ void T_ClearScreen(TerminalBackend *tb) { tb->func_clear_screen(tb); } +void T_SetAttribute(TerminalBackend *tb, TerminalColor bgcolor, TerminalColor fgcolor) { + tb->func_set_attribute(tb, bgcolor, fgcolor); +} + void T_PutCharacter(TerminalBackend *tb, uint32_t ch) { tb->func_put_character(tb, ch); } @@ -138,62 +143,36 @@ void T_PrintHex(TerminalBackend *tb, size_t n, int width) { } } +extern int +rtl_string_format_v( + char* buffer, + size_t buffer_length, + size_t* processed, + const char* format, + va_list arglist +); + void T_Printf(TerminalBackend *tb, const char *fmt, ...) { va_list args; va_start(args, fmt); - - const char *p = fmt; - - while (*p != '\0') { - if (*p != '%') { - T_PrintChar(tb, *p); - p++; - continue; - } - p++; - - switch(*p) { - case 'p': - T_PrintHex(tb, va_arg(args, size_t), 16); - p++; - continue; - - case 'c': - T_PrintChar(tb, va_arg(args, int)); - p++; - continue; - - case 'i': - case 'd': - T_PrintInt(tb, va_arg(args, int)); - p++; - continue; - - case 'u': - T_PrintUInt(tb, va_arg(args, size_t)); - p++; - continue; - - case 'x': - T_PrintHex(tb, va_arg(args, size_t), 0); - p++; - continue; - - case 's': - T_PutText(tb, va_arg(args, const char*)); - p++; - continue; - - case '%': - T_PrintChar(tb, *p); - p++; - continue; - - default: - break; - } + char buffer[512]; + + size_t processed = 0; + int result_code = rtl_string_format_v(buffer, sizeof(buffer), &processed, fmt, args); + + if (result_code == 0 && processed != 0) + { + T_PutText(tb, buffer); } + else + { + T_PutText(tb, "Internal Terminal Error\n"); + HAL_PauseKernel(); + } + + (void)result_code; + (void)processed; va_end(args); } diff --git a/042-osdev-08/terminal_backend_b8000.c b/042-osdev-08/source/kernel/source/terminal_backend_b8000.c similarity index 64% rename from 042-osdev-08/terminal_backend_b8000.c rename to 042-osdev-08/source/kernel/source/terminal_backend_b8000.c index 88dee1a..3fdf708 100644 --- a/042-osdev-08/terminal_backend_b8000.c +++ b/042-osdev-08/source/kernel/source/terminal_backend_b8000.c @@ -16,14 +16,23 @@ enum { static struct B8000_ContextStruct { unsigned short x; unsigned short y; -} B8000_Context; + unsigned short width; + unsigned short height; + unsigned char attribute; +} B8000_Context = { + .x = 0, + .y = 0, + .width = 80, + .height = 50, + .attribute = 0x1F +}; static void B8000_ScrollLine(TerminalBackend *tb); static void B8000_SetCursorPosition( TerminalBackend *tb, uint16_t x, uint16_t y) { UNUSED(tb); - unsigned int offset = y * 80 + x; + unsigned int offset = y * B8000_Context.width + x; // ASSERT(offset <= 0xffff); // ASSERT(offset <= 80 * 25) <--- w * h konsoli @@ -46,14 +55,23 @@ static void B8000_SetCursorPosition( static void B8000_ClearScreen(TerminalBackend *tb) { UNUSED(tb); unsigned char *textvram = (unsigned char*)0xB8000; - for (int i = 0; i < 80 * 25; i++) { + for (int i = 0; i < B8000_Context.width * B8000_Context.height; i++) { textvram[i * 2 + 0] = ' '; - textvram[i * 2 + 1] = 0x0A; + textvram[i * 2 + 1] = B8000_Context.attribute; } B8000_SetCursorPosition(tb, 0, 0); } +static void B8000_SetAttribute(TerminalBackend *tb, TerminalColor bgcolor, TerminalColor fgcolor) { + UNUSED(tb); + const unsigned char attr_bg = (unsigned char)(bgcolor & 0xF) << 4; + const unsigned char attr_fg = (unsigned char)(fgcolor & 0xF) << 0; + const unsigned char attribute = attr_bg | attr_fg; + + B8000_Context.attribute = attribute; +} + static void B8000_PutCharacter(TerminalBackend *tb, uint32_t ch) { UNUSED(tb); unsigned char *textvram = (unsigned char*)0xB8000; @@ -61,18 +79,18 @@ static void B8000_PutCharacter(TerminalBackend *tb, uint32_t ch) { unsigned short x = B8000_Context.x; unsigned short y = B8000_Context.y; - if (y == 25) { + if (y == B8000_Context.height) { B8000_ScrollLine(tb); x = B8000_Context.x; y = B8000_Context.y; } - unsigned int offset = x + y * 80; + unsigned int offset = x + y * B8000_Context.width; textvram[offset * 2 + 0] = (unsigned char)ch; - textvram[offset * 2 + 1] = 0x0A; + textvram[offset * 2 + 1] = B8000_Context.attribute; x += 1; - if (x == 80) { + if (x == B8000_Context.width) { x = 0; y += 1; } @@ -90,26 +108,27 @@ static void B8000_GetCursorPosition( static void B8000_GetSize(TerminalBackend *tb, uint16_t *w, uint16_t *h) { UNUSED(tb); - *w = 80; - *h = 25; + *w = B8000_Context.width; + *h = B8000_Context.height; } static void B8000_ScrollLine(TerminalBackend *tb) { unsigned char *textvram = (unsigned char*)0xB8000; - memmove(textvram, textvram + 80 * 2, 80 * (25 - 1) * 2); + memmove(textvram, textvram + B8000_Context.width * 2, B8000_Context.width * (B8000_Context.height - 1) * 2); - for (size_t i = 80 * (25 - 1) * 2; i < 80 * 25 * 2; i+= 2) { + for (size_t i = B8000_Context.width * (B8000_Context.height - 1) * 2; i < B8000_Context.width * B8000_Context.height * 2; i+= 2) { textvram[i + 0] = ' '; - textvram[i + 1] = 0x0A; + textvram[i + 1] = B8000_Context.attribute; } - B8000_SetCursorPosition(tb, 0, 25 - 1); + B8000_SetCursorPosition(tb, 0, B8000_Context.height - 1); } static const TerminalBackend B8000_Functions = { .func_set_cursor_position = B8000_SetCursorPosition, .func_get_cursor_position = B8000_GetCursorPosition, .func_clear_screen = B8000_ClearScreen, + .func_set_attribute = B8000_SetAttribute, .func_put_character = B8000_PutCharacter, .func_get_size = B8000_GetSize, .func_scroll_line = B8000_ScrollLine diff --git a/042-osdev-08/stage1 b/042-osdev-08/stage1 deleted file mode 100644 index 4f818b5..0000000 Binary files a/042-osdev-08/stage1 and /dev/null differ diff --git a/042-osdev-08/stage2 b/042-osdev-08/stage2 deleted file mode 100644 index d59e5f5..0000000 Binary files a/042-osdev-08/stage2 and /dev/null differ