diff --git a/.gitignore b/.gitignore index 2c0df0c..1044c43 100644 --- a/.gitignore +++ b/.gitignore @@ -29,3 +29,6 @@ *.exe *.out *.app + +# Boot Images +*.img \ No newline at end of file diff --git a/documentation/supervm.md b/documentation/spu-mark-1.md similarity index 90% rename from documentation/supervm.md rename to documentation/spu-mark-1.md index c3410ac..19d099e 100644 --- a/documentation/supervm.md +++ b/documentation/spu-mark-1.md @@ -1,20 +1,21 @@ -# SuperVM +# SuperVM SPU Mark I -SuperVM is a stack machine with a simple, but flexible command -set. +The *SPU Mark I* is a stack machine with a simple, but flexible command +set. The abbreviation SPU stands for Stack Processing Unit, Mark I declares +that it is the first version of the SPU. ## Purpose of this document This document is meant to give a complete overview over the concepts and abstract -workings of SuperVM. +workings of the *SPU Mark I*. -It is targeted at uses who program SuperVM with the native assembly language, +It is targeted at uses who program the *SPU Mark I* with the native assembly language, system programmers who want to include the virtual machine in their system or -create their own SuperVM implementation. +create their own *SPU Mark I* implementation. ## Concepts -SuperVM is a virtual machine that emulates a 32 bit stack machine. Instead of utilizing +*SPU Mark I* is a virtual CPU that emulates a 32 bit stack machine. Instead of utilizing registers operations take their operands from the stack and push their results to it. @@ -44,23 +45,20 @@ least 1024 entries. This allows a fair recursive depth of 128 recursions with an of 6 local variables per function call. ### Data Memory -SuperVM also provides a memory model that allows storing persistent data that is -accessed by different parts of the code. +*SPU Mark I* also provides a memory model that allows storing RAM data that is +accessible by different parts of the code. The data memory is byte accessible and can be written or read. It is implementation defined how the memory is managed and accessible. It can be a sparse memory with different sections, it could utilize a software-implemented paging process or just be a flat chunk of memory. -As most programs require a minimum of global variables, the data memory should be -at least 16kB large. - Every pointer that accesses data memory (e.g. via `store` and `load`) contains the address of a byte in memory, starting with zero. ## Registers and Flags -The SuperVM virtual machine is a stack machine, but has also some control +The *SPU Mark I* is a stack machine, but has also some control registers that can be set with special instructions. The registers mainly control stack access or control flow. @@ -108,7 +106,7 @@ code pointer is equivalent to a jump operation. ## Instructions -An SuperVM instruction is composed of multiple components: +An *SPU Mark I* instruction is composed of multiple components: | Component | Range | Size | Function | |-------------|-------------------|------|------------------------------------------| @@ -213,6 +211,12 @@ The math command is a compound operator that contains all ALU operations. The ALU operation is selected by the `cmdinfo`. +If an ALU operation takes two operands, the right hand side is +defined by `input0`, the left hand side is defined by `input1`. +This allows a configuration such that the right hand side operand +is taken by the argument of the instruction instead of beeing popped +from the stack. + | cmdinfo | Operation | Forumla | |---------|-----------------------------|-----------------| | 0 | Addition | input1 + input0 | @@ -259,11 +263,12 @@ is set when the highest bit is set. ### Output Each instruction can emit an output value. The output can be used in the following ways: -| # | Output | Effect | -|---|---------|--------------------------------------------------------------| -| 0 | discard | The output value is discarded. | -| 1 | push | The output is pushed to the stack. | -| 2 | jump | The code pointer is set to the output, thus a jump is taken. | +| # | Output | Effect | +|---|---------|-----------------------------------------------------------------------------| +| 0 | discard | The output value is discarded. | +| 1 | push | The output is pushed to the stack. | +| 2 | jump | The code pointer is set to the output, thus a jump is taken. | +| 3 | jumpr | The code pointer is increased by the output, thus a relative jump is taken. | ### Argument The instruction argument can provide static input which can be used @@ -271,7 +276,7 @@ as a value source for the first input value. ## Function Calls -The following chapter defines the SuperVM calling convention. It is required that all +The following chapter defines the *SPU Mark I* calling convention. It is required that all functions conform to this convention. To call a function, it is required that the return address is pushed to the stack. @@ -282,7 +287,7 @@ After this, a jump is taken to the function address. jmp @function ; Jumps to the function returnPoint: -SuperVM provides the instruction `cpget` which pushes by default the address of the +*SPU Mark I* provides the instruction `cpget` which pushes by default the address of the second next instruction which resembles the code above. This behaviour allows position independent code: diff --git a/documentation/supervm-syscalls.md b/documentation/supervm-syscalls.md new file mode 100644 index 0000000..13a5d4c --- /dev/null +++ b/documentation/supervm-syscalls.md @@ -0,0 +1,24 @@ +# SuperVM Syscall Definition + +This document contains a list of pre-defined syscalls +for the SuperVM. + +## 0: Exit +This syscall quits the execution of the current program. +It takes no inputs and does not output any value. + +## 1: putc(char) +This syscalls prints a single ASCII character which is +stored in *Input0*. It has no outputs. + +## 2: puti(int) +This syscalls prints an unsigned integer which is stored +in *Input0*. It has no outputs. + +## 3: + +## 4: + +## 5: + +## 6: \ No newline at end of file diff --git a/documentation/supervm-system.md b/documentation/supervm-system.md new file mode 100644 index 0000000..96a6a34 --- /dev/null +++ b/documentation/supervm-system.md @@ -0,0 +1,24 @@ +# SuperVM System Documentation + +This document contains descriptions of the SuperVM host system which +utilized a SPU Mark I to execute code. + + +## Executable Program Format EXP + +SuperVM uses a simple format for storing its executables. + +The format is an archive which stores key-value-pairs for configuration +and sections containing code or data. + +### Sections +A section can be either code or data and has a defined memory position and length. + + +## System Memory +SuperVM provides access to up to 4 GBs of RAM with the x86 paging concept: + +The memory is organized in page tables and a page directories. The directory +contains pointers to a page table which then contains the pointers to 4096 byte +large pages. + diff --git a/documentation/virtual-device.md b/documentation/virtual-device.md new file mode 100644 index 0000000..91c1f72 --- /dev/null +++ b/documentation/virtual-device.md @@ -0,0 +1,115 @@ +# DasOS Virtual Device + +DasOS emulates a virtual device that is shared between +all platform implementations. This device provides a +uniform environment with fixed specifications of hardware +and software as well as syscalls. + +## Hardware + +This section describes the virtual hardware components. + +### CPU +The virtual device uses an *SPU Mark I* as the main processor. + +### RAM +The *CPU* has a 32 MB *RAM* connected. In this RAM, both +data and code resides and the RAM has no memory protection. + +### Screen +The screen connected to the *vGPU* has a resolution of +640x480 pixels and a color depth of 24 bits. + +### vGPU +The *vGPU* provides access to the *Screen* and allows the +manipulation of its contents. + +The gpu uses a double buffering system with a front and a +back buffer where as the front buffer is displayed on the +screen and the back buffer is modified by the CPU. + +The gpu provides functions for printing text to the screen +as well as drawing visual primitives and clearing or swapping +the back buffer. + +In addition to the features mentioned above, the back buffer is +accessible by a memory mapped area in the *RAM*. + +### Persistent Storage +Two persistent storage devices are connected to the virtual device. +Both storage devices behave like IDE block devices where as the first +device is a fixed device and the second device is hot-pluggable. + +The size and file format of the storage device is not specified. + +## Software +This section describes the basic software components and interfaces +of the virtual device. + +### BIOS +Each device implementation provides a *BIOS* that initialized +the device and provides host-dependant configuration. + +### Boot Sequence +The boot sequence is initiated by the *BIOS* of the device +and can only be changed with a BIOS configuration. + +- Determine existence of persistant storage devices + - Fixed device + - Swappable device +- Bootloading + - Searching for a fitting partition + - FAT32 formatted partition + - `/system.exp` must exist + - *Exploading* `/system.exp` into RAM +- Clearing *vGPU* text screen. +- Jump to *Entry Point* + +### Memory Areas + +#### Memory Mapped IO +The memory between `0x200000‬` and `0x‭400000‬` is reserved for +hardware use. + +#### Entry Point +After successfully initialization, the virtual device jumps +to the address `0x‭400000‬` which is equal to the instruction +index `0x‭100000‬`. + +### vGPU Interface + +#### Back Buffer +The back buffer of the vGPU is organized in n RGB24 format +where pixels are stored in a 24 bpp format with R as the first +byte, G as the second and B as the last. +It is 900 kB large and maps the full screen area of 640x480 pixels +as a linear frame buffer from `0x200000‬` to `0x2E1000`. + +#### MMIO Registers +The *vGPU* also uses some registers accessible via memory mapped io. + +| Register | Address | Type | Description | +|----------|----------|------|-----------------------------------------| +| COLOR | 0x2E1000 | u32 | The color used for any draw commands. | +| CURSORX | 0x2E1004 | u16 | The x position of the draw cursor | +| CURSORY | 0x2E1006 | u16 | The y position of the draw cursor | +| SPRITE | 0x2E1008 | ptr | The address of the sprite to copy | +| WIDTH | 0x2E100C | u16 | The width of the sprite. | +| HEIGHT | 0x2E101E | u16 | The height of the sprite. | +| PITCH | 0x2E1010 | u32 | The pitch (memory width) of the sprite. | + +#### HWIO Interface +The vGPU is controllable via the HWIO command of the SPU +with the command info >= `0x10000`. + +| Command | CmdInfo | Input0 | Input1 | Description | +|---------|---------|--------|--------|-----------------------------------------------------------| +| Clear | 0x10000 | y | x | Clears the screen and moves the cursor to (x,y) | +| Line | 0x10001 | y | x | Draws a line from the cursor to (x,y). | +| Rect | 0x10002 | y | x | Draws a rectangle between the cursor and (x,y). | +| Fill | 0x10003 | y | x | Fills a rectangle between the cursor and (x,y). | +| Copy | 0x10004 | y | x | Renders the current sprite at (x,y) and moves the cursor. | +| Pixel | 0x10005 | y | x | Sets the pixel at (x,y). | +| Move | 0x10006 | y | x | Moves the cursor to (x,y). | + +# TODO: Text Commands \ No newline at end of file diff --git a/prototypes/Makefile b/prototypes/Makefile index e00f0ea..5cf5e7c 100644 --- a/prototypes/Makefile +++ b/prototypes/Makefile @@ -1,8 +1,40 @@ +## +# Build all projects +## -PROJECTS = $(shell ls --file-type | grep / | sed "s|/||") +PROJECTS = $(shell ls --file-type --ignore=libs --ignore=kernels --ignore=include | grep / | sed "s|/||") -all: $(PROJECTS) +LIBS = $(filter lib%, $(PROJECTS)) +KERNELS = $(filter-out lib%, $(PROJECTS)) + +all: $(KERNELS) boot.img .PHONY: $(PROJECTS) -$(PROJECTS): - make -C $@ +$(KERNELS): dirs $(LIBS) + make -C $@ $(ARGS) + +$(LIBS): dirs + make -C $@ $(ARGS) + +dirs: + mkdir -p libs + mkdir -p kernels + +boot.img: $(PROJECTS) + mformat -C -f 1440 -v VIDEO -i boot.img :: + mcopy -i boot.img \ + kernels/* \ + syslinux.cfg \ + /boot/syslinux/libcom32.c32 \ + /boot/syslinux/libutil.c32 \ + /boot/syslinux/menu.c32 \ + /boot/syslinux/mboot.c32 \ + :: + syslinux boot.img + mdir -i boot.img :: + +deploy: $(KERNELS) + cp ./kernels/* /srv/tftp/ + +run: boot.img + qemu-system-i386 boot.img -serial stdio \ No newline at end of file diff --git a/prototypes/base/concepts.txt b/prototypes/base/concepts.txt deleted file mode 100644 index 581eac0..0000000 --- a/prototypes/base/concepts.txt +++ /dev/null @@ -1,45 +0,0 @@ - -# DasOS Concepts - -## Memory Layout - -| Start | Length | Length -h | Description | -|------------|------------|-----------|--------------------------------------------------------------------------| -| 0x00000000 | 0x40000000 | 1 GB | Kernel Space. This is where the kernel and its functionality is located. | -| 0x00100000 | ??? | ??? | Kernel entry point and load target. Here the kernel will be loaded. | -| 0x20000000 | 0x20000000 | 512 MB | Kernel Heap. This memory is used for dynamic allocations in the kernel. | -| 0x40000000 | 0xC0000000 | 3 GB | User Space. This is where Artifacts are loaded and executed. | - -### Kernel Heap - -A simple storage allocator. - -Storage of: -- Task Descriptions -- Memory Mapping Information -- Location of loaded artifacts -- ... - -## Starting a Task - -### Requirements - -- allocate task structure -- allocate mapping directory -- fill mapping directory with - - Lower End: Copy kernel mappings - - Upper End: Copy artifact data -- allocate task stack - -## Executables, Libraries and Stuff - -Artifact = Executable + Library + Shared Memory - -### Artifact Types - -| Type | Entry Point | Description | -|------------|-------------|--------------------------------------------------------------------------------------------------------------------------------------| -| Program | _main | A program targeted at user or system administrator. Can be executed with command line arguments. Uses stdin, stdout, stderr. | -| Library | _libmain | Can be loaded by other artifacts and allows utilization of a shared set of functions. | -| Service | _svcmain | A service is a background worker that won't be terminated when its main function returns. Can be 'woken up' by an external artifact. | -| Driver | _drvinit | A driver is loaded at system start and is allowed to request and dispatch interrupts. Can be used to create a flexible OS. | diff --git a/prototypes/base/memory.txt b/prototypes/base/memory.txt deleted file mode 100644 index 50daa6a..0000000 --- a/prototypes/base/memory.txt +++ /dev/null @@ -1,10 +0,0 @@ - - - - - -[0-1] GB Kernel Space - -[1-4] GB User Space - Entry Point: 0x40000000 - Stack Start: 0xFFFFFFFF diff --git a/prototypes/base/multiboot.S b/prototypes/base/multiboot.S deleted file mode 100644 index f96d476..0000000 --- a/prototypes/base/multiboot.S +++ /dev/null @@ -1,11 +0,0 @@ -.section multiboot - -#define MB_MAGIC 0x1badb002 -#define MB_FLAGS 0x0 -#define MB_CHECKSUM -(MB_MAGIC + MB_FLAGS) - -// Der Multiboot-Header -.align 4 -.int MB_MAGIC -.int MB_FLAGS -.int MB_CHECKSUM \ No newline at end of file diff --git a/prototypes/common.mk b/prototypes/common.mk new file mode 100644 index 0000000..b8e50f6 --- /dev/null +++ b/prototypes/common.mk @@ -0,0 +1,36 @@ +## +# DasOS common Makefile targets +## + +INCLUDE_DIRS += ../include/ /opt/lib/gcc/i686-elf/6.1.0/include/ + +FLAGS += -ffreestanding -mno-sse -Werror -Wall -iquote include $(addprefix -I, $(INCLUDE_DIRS)) -O3 -g +ASFLAGS += $(FLAGS) +CFLAGS += $(FLAGS) +CXXFLAGS += $(FLAGS) -std=c++14 -fno-rtti -fno-exceptions -fno-leading-underscore -fno-use-cxa-atexit -nostdlib -fno-builtin +LDFLAGS += -L../libs/ + +SRCS += $(shell find -regextype egrep -regex '.*/.*\.(cpp|S|c)') +OBJS += $(addsuffix .o, $(notdir $(basename $(SRCS)))) + + +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c -o obj/$@ $< + +%.o: %.c + $(CC) $(CFLAGS) -c -o obj/$@ $< + +%.o: %.S + $(AS) $(ASFLAGS) -c -o obj/$@ $< + +%.o: src/%.cpp + $(CXX) $(CXXFLAGS) -c -o obj/$@ $< + +%.o: src/%.c + $(CC) $(CFLAGS) -c -o obj/$@ $< + +%.o: src/%.S + $(AS) $(ASFLAGS) -c -o obj/$@ $< + +builddir: + mkdir -p ./obj/ \ No newline at end of file diff --git a/prototypes/config.mk b/prototypes/config.mk new file mode 100644 index 0000000..6519d76 --- /dev/null +++ b/prototypes/config.mk @@ -0,0 +1,12 @@ +## +# DasOS Makefile configuration +## + +# Configure for target platform +CC=/opt/bin/i686-elf-gcc +CXX=/opt/bin/i686-elf-g++ +LD=/opt/i686-elf/bin/ld +AR=/opt/i686-elf/bin/ar +AS=/opt/bin/i686-elf-gcc + +LIBS += -L/opt/lib/gcc/i686-elf/6.1.0/ \ No newline at end of file diff --git a/prototypes/base/include/asm.hpp b/prototypes/include/asm.hpp similarity index 97% rename from prototypes/base/include/asm.hpp rename to prototypes/include/asm.hpp index 4e42919..6073347 100644 --- a/prototypes/base/include/asm.hpp +++ b/prototypes/include/asm.hpp @@ -1,7 +1,7 @@ #pragma once #include -#include +#include #define ASM_READ_REG(reg, var) asm volatile("mov %%" #reg ", %0" : "=r" (var)); #define ASM_WRITE_REG(reg, var) asm volatile("mov %0, %%" #reg : : "r" (var)); diff --git a/prototypes/include/chardev.hpp b/prototypes/include/chardev.hpp new file mode 100644 index 0000000..f2e458b --- /dev/null +++ b/prototypes/include/chardev.hpp @@ -0,0 +1,94 @@ +#pragma once + +#include +#include + +template +struct NumericFormat +{ + T value; + uint32_t base; + + /** + * Applies a padding to the number. + * A positive number will apply padding the right side, + * a negative number will pad the left side. + */ + int32_t padding = 0; + + char padchar = ' '; + + NumericFormat(T value) : value(value), base(10) { } + NumericFormat(T value, uint32_t base) : value(value), base(base) { } +}; + +namespace utils +{ + template + auto hex(T value) { return NumericFormat(value, 16); } + + template + auto dec(T value) { return NumericFormat(value, 10); } + + template + auto oct(T value) { return NumericFormat(value, 8); } + + template + auto bin(T value) { return NumericFormat(value, 2); } + + template + auto nbase(T value, uint32_t base) { return NumericFormat(value, base); } + + template + auto pad(NumericFormat value, int32_t padding, char c = ' ') { + value.padding = padding; + return value; + } + + template + auto pad(T value, int32_t padding, char c = ' ') { + return pad(NumericFormat(value), padding, c); + } +} + +class CharacterDevice +{ +private: + /** + * Prints the prefix for a given numeric base. + * @returns the prefix length. + */ + uint32_t printNumericPrefix(uint32_t base); + + /** + * Prints a character several times. + */ + void putrep(char c, uint32_t repetitions); +public: + virtual void write(char c) = 0; + + inline CharacterDevice & operator << (char c) + { + this->write(c); + return *this; + } + + inline CharacterDevice & operator << (const char *str) + { + while(*str) { + *this << *str++; + } + return *this; + } + + CharacterDevice & operator << (uint32_t value); + + CharacterDevice & operator << (int32_t value); + + CharacterDevice & operator << (void *value); + + CharacterDevice & operator << (bool value); + + template + CharacterDevice & operator << (const NumericFormat &fmt); +}; \ No newline at end of file diff --git a/prototypes/base/include/compat.h b/prototypes/include/compat.h similarity index 100% rename from prototypes/base/include/compat.h rename to prototypes/include/compat.h diff --git a/prototypes/base/include/console.hpp b/prototypes/include/console.hpp similarity index 100% rename from prototypes/base/include/console.hpp rename to prototypes/include/console.hpp diff --git a/prototypes/base/include/cpustate.hpp b/prototypes/include/cpustate.hpp similarity index 94% rename from prototypes/base/include/cpustate.hpp rename to prototypes/include/cpustate.hpp index 94f1503..e2e907b 100644 --- a/prototypes/base/include/cpustate.hpp +++ b/prototypes/include/cpustate.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include struct CpuState { diff --git a/prototypes/base/include/driver/driver.hpp b/prototypes/include/driver/driver.hpp similarity index 100% rename from prototypes/base/include/driver/driver.hpp rename to prototypes/include/driver/driver.hpp diff --git a/prototypes/base/include/driver/keyboard.hpp b/prototypes/include/driver/keyboard.hpp similarity index 100% rename from prototypes/base/include/driver/keyboard.hpp rename to prototypes/include/driver/keyboard.hpp diff --git a/prototypes/base/include/pic.hpp b/prototypes/include/driver/pic.hpp similarity index 95% rename from prototypes/base/include/pic.hpp rename to prototypes/include/driver/pic.hpp index 6e2ab1a..f9adc58 100644 --- a/prototypes/base/include/pic.hpp +++ b/prototypes/include/driver/pic.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include class PIC { diff --git a/prototypes/include/driver/serial.hpp b/prototypes/include/driver/serial.hpp new file mode 100644 index 0000000..70fc2bc --- /dev/null +++ b/prototypes/include/driver/serial.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include +#include + +#define SERIAL_COM1 0x3F8 +#define SERIAL_COM2 0x2F8 +#define SERIAL_COM3 0x3E8 +#define SERIAL_COM4 0x2E8 + +enum class Partiy +{ + None = 0x0, + Even = 0x4, + Odd = 0x6, + High = 0x5, + Low = 0x7, +}; + +class SerialPort : + public CharacterDevice +{ +private: + uint16_t mBase; +public: + SerialPort( + uint32_t portBase, + uint32_t baud = 9600, + Partiy parity = Partiy::None, + uint8_t dataBits = 8); + + bool isTransmitEmpty() const; + + bool isReceiveEmpty() const; + + void write(char c) override; + + char read(); +}; \ No newline at end of file diff --git a/prototypes/base/include/driver/timer.hpp b/prototypes/include/driver/timer.hpp similarity index 89% rename from prototypes/base/include/driver/timer.hpp rename to prototypes/include/driver/timer.hpp index 92d973b..7c9279a 100644 --- a/prototypes/base/include/driver/timer.hpp +++ b/prototypes/include/driver/timer.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "driver.hpp" namespace driver diff --git a/prototypes/include/driver/video.hpp b/prototypes/include/driver/video.hpp new file mode 100644 index 0000000..fa33b20 --- /dev/null +++ b/prototypes/include/driver/video.hpp @@ -0,0 +1,56 @@ +#pragma once +#include + +#include + +#include "picture.hpp" + +class VideoScreen : + public Picture +{ +private: + static Pixel outOfScreen; +private: + Pixel *mFramebuffer; + uint32_t mPitch; +public: + const uint32_t mWidth, mHeight; +public: + VideoScreen(vbe::ModeInfo const & modeInfo); + + uint32_t width() const override { + return this->mWidth; + } + + uint32_t height() const override { + return this->mHeight; + } + + Pixel & operator() (uint32_t x, uint32_t y) override { + if(x >= this->mWidth || y >= this->mHeight) { + return VideoScreen::outOfScreen; + } else { + return this->scanline(y)[x]; + } + } + + Pixel const & operator() (uint32_t x, uint32_t y) const override { + if(x >= this->mWidth || y >= this->mHeight) { + return VideoScreen::outOfScreen; + } else { + return this->scanline(y)[x]; + } + } + +private: + Pixel * scanline(uint32_t y) { + return reinterpret_cast( + reinterpret_cast(this->mFramebuffer) + y * this->mPitch + ); + } + Pixel const * scanline(uint32_t y) const { + return reinterpret_cast( + reinterpret_cast(this->mFramebuffer) + y * this->mPitch + ); + } +}; \ No newline at end of file diff --git a/prototypes/base/include/elf.hpp b/prototypes/include/elf.hpp similarity index 97% rename from prototypes/base/include/elf.hpp rename to prototypes/include/elf.hpp index 717d880..9bd9834 100644 --- a/prototypes/base/include/elf.hpp +++ b/prototypes/include/elf.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include namespace elf { diff --git a/prototypes/base/include/enums.hpp b/prototypes/include/enums.hpp similarity index 100% rename from prototypes/base/include/enums.hpp rename to prototypes/include/enums.hpp diff --git a/prototypes/base/include/errors.hpp b/prototypes/include/errors.hpp similarity index 76% rename from prototypes/base/include/errors.hpp rename to prototypes/include/errors.hpp index 8e02797..310d86f 100644 --- a/prototypes/base/include/errors.hpp +++ b/prototypes/include/errors.hpp @@ -3,6 +3,6 @@ enum class Error { #define ERROR(num, ident, desc) ident = num, -#include "errors.lst" +#include "lists/errors.lst" #undef ERROR }; \ No newline at end of file diff --git a/prototypes/base/include/exceptions.hpp b/prototypes/include/exceptions.hpp similarity index 81% rename from prototypes/base/include/exceptions.hpp rename to prototypes/include/exceptions.hpp index c288ec6..1137b70 100644 --- a/prototypes/base/include/exceptions.hpp +++ b/prototypes/include/exceptions.hpp @@ -5,6 +5,6 @@ enum class Exception { #define EXCEPTION(num, shorthand, ident, desc, type) ident = num, -#include "exceptions.lst" +#include "lists/exceptions.lst" #undef EXCEPTION }; \ No newline at end of file diff --git a/prototypes/base/include/io.hpp b/prototypes/include/io.hpp similarity index 100% rename from prototypes/base/include/io.hpp rename to prototypes/include/io.hpp diff --git a/prototypes/base/include/bsod.hpp b/prototypes/include/kernel/bsod.hpp similarity index 100% rename from prototypes/base/include/bsod.hpp rename to prototypes/include/kernel/bsod.hpp diff --git a/prototypes/base/include/gdt.hpp b/prototypes/include/kernel/gdt.hpp similarity index 98% rename from prototypes/base/include/gdt.hpp rename to prototypes/include/kernel/gdt.hpp index 97ce581..77f55a1 100644 --- a/prototypes/base/include/gdt.hpp +++ b/prototypes/include/kernel/gdt.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "enums.hpp" enum class SegmentAccess : uint8_t diff --git a/prototypes/base/include/idt.hpp b/prototypes/include/kernel/idt.hpp similarity index 92% rename from prototypes/base/include/idt.hpp rename to prototypes/include/kernel/idt.hpp index 7654b10..0958409 100644 --- a/prototypes/base/include/idt.hpp +++ b/prototypes/include/kernel/idt.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include "enums.hpp" #include "cpustate.hpp" @@ -58,9 +58,11 @@ public: explicit Interrupt(Handler handler); }; +extern "C" CpuState * interrupt_dispatch(CpuState *cpu); class IDT { + friend CpuState * interrupt_dispatch(CpuState *cpu); public: static const uint32_t length = 256; diff --git a/prototypes/base/include/pagedirectory.hpp b/prototypes/include/kernel/pagedirectory.hpp similarity index 100% rename from prototypes/base/include/pagedirectory.hpp rename to prototypes/include/kernel/pagedirectory.hpp diff --git a/prototypes/base/include/pagetable.hpp b/prototypes/include/kernel/pagetable.hpp similarity index 100% rename from prototypes/base/include/pagetable.hpp rename to prototypes/include/kernel/pagetable.hpp diff --git a/prototypes/base/include/pmm.hpp b/prototypes/include/kernel/pmm.hpp similarity index 100% rename from prototypes/base/include/pmm.hpp rename to prototypes/include/kernel/pmm.hpp diff --git a/prototypes/base/include/vmm.hpp b/prototypes/include/kernel/vmm.hpp similarity index 100% rename from prototypes/base/include/vmm.hpp rename to prototypes/include/kernel/vmm.hpp diff --git a/prototypes/base/lists/errors.lst b/prototypes/include/lists/errors.lst similarity index 83% rename from prototypes/base/lists/errors.lst rename to prototypes/include/lists/errors.lst index 7e248b4..661dc88 100644 --- a/prototypes/base/lists/errors.lst +++ b/prototypes/include/lists/errors.lst @@ -3,4 +3,5 @@ ERROR(1, OutOfMemory, The system has run out of memory.) ERROR(2, UnhandledException, An unhandled exception has occurred.) ERROR(3, UnhandledInterrupt, An unhandled interrupt has occurred.) ERROR(4, DriverAlreadyInstalled, A driver was already installed.) -ERROR(5, InvalidELFImage, The file beeing loaded is not a valid ELF file.) \ No newline at end of file +ERROR(5, InvalidELFImage, The file beeing loaded is not a valid ELF file.) +ERROR(6, VMError, The virtual machine has failed.) \ No newline at end of file diff --git a/prototypes/base/lists/exceptions.lst b/prototypes/include/lists/exceptions.lst similarity index 100% rename from prototypes/base/lists/exceptions.lst rename to prototypes/include/lists/exceptions.lst diff --git a/prototypes/base/lists/interrupts.lst b/prototypes/include/lists/interrupts.lst similarity index 100% rename from prototypes/base/lists/interrupts.lst rename to prototypes/include/lists/interrupts.lst diff --git a/prototypes/base/lists/irqs.lst b/prototypes/include/lists/irqs.lst similarity index 100% rename from prototypes/base/lists/irqs.lst rename to prototypes/include/lists/irqs.lst diff --git a/prototypes/base/include/multiboot.hpp b/prototypes/include/multiboot.hpp similarity index 96% rename from prototypes/base/include/multiboot.hpp rename to prototypes/include/multiboot.hpp index 7005ab4..f062021 100644 --- a/prototypes/base/include/multiboot.hpp +++ b/prototypes/include/multiboot.hpp @@ -1,6 +1,7 @@ #pragma once -#include +#include +#include #include "pointer.hpp" #define MB_MEMSIZE (1<<0) @@ -18,6 +19,8 @@ #define MB_ASSERT_SIZE(type, len) static_assert(sizeof(type) == len, "multiboot::" #type " must be " #len " bytes large.") +#include "vbe.hpp" + namespace multiboot { template @@ -154,8 +157,8 @@ namespace multiboot const char * bootLoaderName; const APMTable * apmTable; struct { - uint32_t ontrolInfo; - uint32_t modeInfo; + uint32_t controlInfo; + vbe::ModeInfo const * modeInfo; uint16_t mode; uint16_t interfaceSegment; uint16_t interfaceOffset; diff --git a/prototypes/include/new b/prototypes/include/new new file mode 100644 index 0000000..fd05b8e --- /dev/null +++ b/prototypes/include/new @@ -0,0 +1,29 @@ +#ifndef _NEW +#define _NEW + +#include + +#pragma GCC visibility push(default) + +extern "C++" { +void* operator new(size_t) __attribute__((__externally_visible__)); +void* operator new[](size_t) __attribute__((__externally_visible__)); +void operator delete(void*) __attribute__((__externally_visible__)); +void operator delete[](void*) __attribute__((__externally_visible__)); + +#if __cpp_sized_deallocation +void operator delete(void*, size_t) __attribute__((__externally_visible__)); +void operator delete[](void*, size_t) __attribute__((__externally_visible__)); +#endif + +// Default placement versions of operator new. +inline void* operator new(size_t, void* __p) { return __p; } +inline void* operator new[](size_t, void* __p) { return __p; } + +// Default placement versions of operator delete. +inline void operator delete (void*, void*) { } +inline void operator delete[](void*, void*) { } + +} // extern "C++" + +#endif diff --git a/prototypes/base/include/numeric.hpp b/prototypes/include/numeric.hpp similarity index 98% rename from prototypes/base/include/numeric.hpp rename to prototypes/include/numeric.hpp index b9497f3..5ca83c7 100644 --- a/prototypes/base/include/numeric.hpp +++ b/prototypes/include/numeric.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include #include class Numeric diff --git a/prototypes/include/picture.hpp b/prototypes/include/picture.hpp new file mode 100644 index 0000000..79669e0 --- /dev/null +++ b/prototypes/include/picture.hpp @@ -0,0 +1,25 @@ +#pragma once +#include + +struct Pixel +{ + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t a; +} __attribute__((packed)); + +static inline Pixel COLOR(uint8_t r, uint8_t g, uint8_t b) +{ + return Pixel { b, g, r, 0xFF }; +} + +class Picture +{ +public: + virtual uint32_t width() const = 0; + virtual uint32_t height() const = 0; + + virtual Pixel & operator() (uint32_t x, uint32_t y) = 0; + virtual Pixel const & operator() (uint32_t x, uint32_t y) const = 0; +}; \ No newline at end of file diff --git a/prototypes/base/include/pointer.hpp b/prototypes/include/pointer.hpp similarity index 99% rename from prototypes/base/include/pointer.hpp rename to prototypes/include/pointer.hpp index 8f93c00..557e23b 100644 --- a/prototypes/base/include/pointer.hpp +++ b/prototypes/include/pointer.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include /** * Provides a strong pointer wrapper which can be used to address diff --git a/prototypes/base/include/screen.hpp b/prototypes/include/screen.hpp similarity index 98% rename from prototypes/base/include/screen.hpp rename to prototypes/include/screen.hpp index 314ee24..ab4c612 100644 --- a/prototypes/base/include/screen.hpp +++ b/prototypes/include/screen.hpp @@ -1,6 +1,6 @@ #pragma once -#include +#include enum class Color : uint8_t { diff --git a/prototypes/include/vbe.hpp b/prototypes/include/vbe.hpp new file mode 100644 index 0000000..3ea58d2 --- /dev/null +++ b/prototypes/include/vbe.hpp @@ -0,0 +1,39 @@ +#pragma once + +#include + +#define VBE_FAR(name) uint32_t name; + +namespace vbe +{ + struct ModeInfo + { + uint16_t attributes; + uint8_t winA,winB; + uint16_t granularity; + uint16_t winsize; + uint16_t segmentA, segmentB; + VBE_FAR(realFctPtr); + uint16_t pitch; // bytes per scanline + + struct { + uint16_t x; + uint16_t y; + } __attribute__ ((packed)) res; + uint8_t Wchar, Ychar; + uint8_t planes, bpp, banks; + uint8_t memoryModel, bankSize, imagePages; + uint8_t reserved0; + + uint8_t redMask, redPosition; + uint8_t greenMask, greenPosition; + uint8_t blueMask, bluePosition; + uint8_t rsvMask, rsvPosition; + uint8_t directcolor_attributes; + + uint32_t framebuffer; + uint32_t reserved1; + uint16_t reserved2; + } __attribute__((packed)); + +} \ No newline at end of file diff --git a/prototypes/kernel.mk b/prototypes/kernel.mk new file mode 100644 index 0000000..f51bd1e --- /dev/null +++ b/prototypes/kernel.mk @@ -0,0 +1,7 @@ + + +$(KERNEL): $(OBJS) + $(LD) -T../linker.ld -o ../kernels/$@ $(addprefix obj/, $^) $(LDFLAGS) $(LIBS) + +deploy: $(KERNEL) + cp ../kernels/$(KERNEL) /srv/tftp/$(KERNEL) diff --git a/prototypes/libbase/Makefile b/prototypes/libbase/Makefile new file mode 100644 index 0000000..1a28c46 --- /dev/null +++ b/prototypes/libbase/Makefile @@ -0,0 +1,12 @@ +## +# Build base library parts of the libc. +## + +include ../config.mk + +LIBRARY = libbase.a + +all: builddir $(LIBRARY) + +include ../common.mk +include ../library.mk \ No newline at end of file diff --git a/prototypes/libbase/numeric.cpp b/prototypes/libbase/numeric.cpp new file mode 100644 index 0000000..492e055 --- /dev/null +++ b/prototypes/libbase/numeric.cpp @@ -0,0 +1,133 @@ +#include + +static char getDigit(uint32_t i) +{ + if(i >= 0 && i <= 9) { + return '0' + i; + } + return 'A' + (i-10); +} + +size_t Numeric::toString( + char *buffer, + size_t length, + uint32_t number, + uint32_t radix) +{ + if(length == 0) { + return 0; + } + if(number == 0) { + buffer[0] = '0'; + return 1; + } + + size_t len = 0; + while(number > 0) + { + buffer[len++] = getDigit(number % radix); + if(len >= length) + break; + number /= radix; + } + + int half = len / 2; + for(int i = 0; i < half; i++) + { + char c = buffer[i]; + buffer[i] = buffer[len - i - 1]; + buffer[len - i - 1] = c; + } + + return len; +} + +size_t Numeric::toString( + char *buffer, + size_t length, + int32_t number, + uint32_t radix) +{ + if(length == 0) { + return 0; + } + if(number == 0) { + buffer[0] = '0'; + return 1; + } + if(number < 0) { + buffer[0] = '-'; + length -= 1; + if(length == 0) { + return 0; + } + return Numeric::toString(&buffer[1], length, static_cast(-number), radix) + 1; + } + else { + return Numeric::toString(buffer, length, static_cast(number), radix); + } +} + + + + + +size_t Numeric::toString( + char *buffer, + size_t length, + uint64_t number, + uint32_t radix) +{ + if(length == 0) { + return 0; + } + if(number == 0) { + buffer[0] = '0'; + return 1; + } + + size_t len = 0; + while(number > 0) + { + buffer[len++] = getDigit(number % radix); + if(len >= length) + break; + number /= radix; + } + + int half = len / 2; + for(int i = 0; i < half; i++) + { + char c = buffer[i]; + buffer[i] = buffer[len - i - 1]; + buffer[len - i - 1] = c; + } + + return len; +} + +size_t Numeric::toString( + char *buffer, + size_t length, + int64_t number, + uint32_t radix) +{ + if(length == 0) { + return 0; + } + if(number == 0) { + buffer[0] = '0'; + return 1; + } + if(number < 0) { + buffer[0] = '-'; + length -= 1; + if(length == 0) { + return 0; + } + return Numeric::toString(&buffer[1], length, static_cast(-number), radix) + 1; + } + else { + return Numeric::toString(buffer, length, static_cast(number), radix); + } +} \ No newline at end of file diff --git a/prototypes/libbase/string.c b/prototypes/libbase/string.c new file mode 100644 index 0000000..eb16ca2 --- /dev/null +++ b/prototypes/libbase/string.c @@ -0,0 +1,19 @@ + + + + +char * strcpy(char * dst, const char *src) +{ + char * tmp = dst; + while(((*tmp++) = (*src++))); + return dst; +} + +char *strcat(char * dst, const char *src) +{ + char * tmp = dst; + while(*tmp++); + tmp--; + while(((*tmp++) = (*src++))); + return dst; +} diff --git a/prototypes/libboot/Makefile b/prototypes/libboot/Makefile new file mode 100644 index 0000000..b1dddb0 --- /dev/null +++ b/prototypes/libboot/Makefile @@ -0,0 +1,12 @@ +## +# Build multiboot entry point library. +## + +include ../config.mk + +LIBRARY = libboot.a + +all: builddir $(LIBRARY) + +include ../common.mk +include ../library.mk \ No newline at end of file diff --git a/prototypes/base/src/compat.c b/prototypes/libboot/compat.c similarity index 74% rename from prototypes/base/src/compat.c rename to prototypes/libboot/compat.c index 1af8b91..326fd4a 100644 --- a/prototypes/base/src/compat.c +++ b/prototypes/libboot/compat.c @@ -2,8 +2,8 @@ typedef void (*constructor)(); -constructor start_ctors; -constructor end_ctors; +extern constructor start_ctors; +extern constructor end_ctors; void compat_call_ctors() { diff --git a/prototypes/base/entrypoint.S b/prototypes/libboot/entrypoint.S similarity index 100% rename from prototypes/base/entrypoint.S rename to prototypes/libboot/entrypoint.S diff --git a/prototypes/libchardev/Makefile b/prototypes/libchardev/Makefile new file mode 100644 index 0000000..a31923b --- /dev/null +++ b/prototypes/libchardev/Makefile @@ -0,0 +1,12 @@ +## +# Build libchardev. +## + +include ../config.mk + +LIBRARY = libchardev.a + +all: builddir $(LIBRARY) + +include ../common.mk +include ../library.mk \ No newline at end of file diff --git a/prototypes/libchardev/chardev.cpp b/prototypes/libchardev/chardev.cpp new file mode 100644 index 0000000..0418ca9 --- /dev/null +++ b/prototypes/libchardev/chardev.cpp @@ -0,0 +1,105 @@ +#include + +#include + + +CharacterDevice & CharacterDevice::operator << (uint32_t value) +{ + char buffer[12]; + size_t len = Numeric::toString(buffer, sizeof(buffer), value, 10); + for(size_t i = 0; i < len; i++) { + this->write(buffer[i]); + } + return *this; +} + +CharacterDevice & CharacterDevice::operator << (int32_t value) +{ + char buffer[13]; + size_t len = Numeric::toString(buffer, sizeof(buffer), value, 10); + for(size_t i = 0; i < len; i++) { + this->write(buffer[i]); + } + return *this; +} + +CharacterDevice & CharacterDevice::operator << (void *value) +{ + char buffer[13]; + size_t len = Numeric::toString(buffer, sizeof(buffer), reinterpret_cast(value), 16); + for(size_t i = 0; i < len; i++) { + this->write(buffer[i]); + } + return *this; +} + +CharacterDevice & CharacterDevice::operator << (bool value) +{ + if(value == true) { + *this << "true"; + } else { + *this << "false"; + } + return *this; +} + + +#define NUMERIC_FMT_HANDLER char buffer[13]; \ + size_t prefixlen = this->printNumericPrefix(fmt.base); \ + size_t len = Numeric::toString(buffer, sizeof(buffer), fmt.value, fmt.base); \ + int delta = prefixlen + len; \ + if(fmt.padding < 0 && delta < -fmt.padding) { \ + this->putrep(fmt.padchar, -fmt.padding - delta); \ + } \ + for(size_t i = 0; i < len; i++) { \ + this->write(buffer[i]); \ + } \ + if(fmt.padding > 0 && delta < fmt.padding) { \ + this->putrep(fmt.padchar, fmt.padding - delta); \ + } \ + return *this + +template<> +CharacterDevice & CharacterDevice::operator << (const NumericFormat & fmt) +{ + NUMERIC_FMT_HANDLER; +} + +template<> +CharacterDevice & CharacterDevice::operator << (const NumericFormat & fmt) +{ + NUMERIC_FMT_HANDLER; +} + +template<> +CharacterDevice & CharacterDevice::operator << (const NumericFormat & fmt) +{ + NUMERIC_FMT_HANDLER; +} + +template<> +CharacterDevice & CharacterDevice::operator << (const NumericFormat & fmt) +{ + NUMERIC_FMT_HANDLER; +} + +uint32_t CharacterDevice::printNumericPrefix(uint32_t base) +{ + switch(base) { + case 2: *this << "0b"; return 2; + case 8: *this << "0o"; return 2; + case 10: return 0; + case 16: *this << "0x"; return 2; + default: + *this << "[" << base << "]x"; + if(base < 10) return 4; + if(base < 100) return 5; + return 6; + } +} + +void CharacterDevice::putrep(char c, uint32_t repetitions) +{ + for(uint32_t i = 0; i < repetitions; i++) + this->write(c); +} \ No newline at end of file diff --git a/prototypes/library.mk b/prototypes/library.mk new file mode 100644 index 0000000..e5b1479 --- /dev/null +++ b/prototypes/library.mk @@ -0,0 +1,3 @@ + +$(LIBRARY): $(OBJS) + $(AR) rcs ../libs/$(LIBRARY) $(addprefix obj/, $^) \ No newline at end of file diff --git a/prototypes/libserial/Makefile b/prototypes/libserial/Makefile new file mode 100644 index 0000000..ff22aed --- /dev/null +++ b/prototypes/libserial/Makefile @@ -0,0 +1,12 @@ +## +# Build serial port library. +## + +include ../config.mk + +LIBRARY = libserial.a + +all: builddir $(LIBRARY) + +include ../common.mk +include ../library.mk \ No newline at end of file diff --git a/prototypes/libserial/serial.cpp b/prototypes/libserial/serial.cpp new file mode 100644 index 0000000..11f76ee --- /dev/null +++ b/prototypes/libserial/serial.cpp @@ -0,0 +1,66 @@ +#include +#include + +// Code adapted from: +// http://www.lowlevel.eu/wiki/Serielle_Schnittstelle + +#define IER 1 +#define IIR 2 +#define FCR 2 +#define LCR 3 +#define MCR 4 +#define LSR 5 +#define MSR 6 + +SerialPort::SerialPort(uint32_t portBase, uint32_t baud, Partiy parity, uint8_t dataBits) : + mBase(portBase) +{ + union { + uint8_t b[2]; + uint16_t w; + } divisor; + divisor.w = 115200 / baud; + + // Interrupt ausschalten + outb(this->mBase + IER, 0x00); + + // DLAB-Bit setzen + outb(this->mBase + LCR, 0x80); + + // Teiler (low) setzen + outb(this->mBase + 0, divisor.b[0]); + + // Teiler (high) setzen + outb(this->mBase + 1, divisor.b[1]); + + int iparity = (int)parity; + + // Anzahl Bits, Parität, usw setzen (DLAB zurücksetzen) + outb(this->mBase + LCR, ((iparity&0x7)<<3)|((dataBits-5)&0x3)); + + // Initialisierung abschließen + outb(this->mBase + FCR, 0xC7); + outb(this->mBase + MCR, 0x0B); +} + +bool SerialPort::isTransmitEmpty() const +{ + return inb(this->mBase + LSR) & 0x20; +} + +bool SerialPort::isReceiveEmpty() const +{ + return (inb(this->mBase + LSR) & 1) == 0; +} + +void SerialPort::write(char c) +{ + while (this->isTransmitEmpty() == false); + outb(this->mBase, c); +} + +char SerialPort::read() +{ + while (this->isReceiveEmpty()); + return inb(this->mBase); +} diff --git a/prototypes/libvideo/Makefile b/prototypes/libvideo/Makefile new file mode 100644 index 0000000..d9b6377 --- /dev/null +++ b/prototypes/libvideo/Makefile @@ -0,0 +1,12 @@ +## +# Build video library. +## + +include ../config.mk + +LIBRARY = libvideo.a + +all: builddir $(LIBRARY) + +include ../common.mk +include ../library.mk \ No newline at end of file diff --git a/prototypes/libvideo/src/video.cpp b/prototypes/libvideo/src/video.cpp new file mode 100644 index 0000000..1b61aec --- /dev/null +++ b/prototypes/libvideo/src/video.cpp @@ -0,0 +1,12 @@ +#include + +Pixel VideoScreen::outOfScreen; + +VideoScreen::VideoScreen(vbe::ModeInfo const & modeInfo) : + mFramebuffer((Pixel*)modeInfo.framebuffer), + mPitch(modeInfo.pitch), + mWidth(modeInfo.res.x), + mHeight(modeInfo.res.y) +{ + +} diff --git a/prototypes/base/linker.ld b/prototypes/linker.ld similarity index 86% rename from prototypes/base/linker.ld rename to prototypes/linker.ld index ed97bd5..4254ab0 100644 --- a/prototypes/base/linker.ld +++ b/prototypes/linker.ld @@ -14,8 +14,8 @@ SECTIONS } .data ALIGN(4096) : { start_ctors = .; - KEEP(*( .init_array )); - KEEP(*(SORT_BY_INIT_PRIORITY( .init_array.* ))); + KEEP(*( .ctors )); + KEEP(*(SORT_BY_INIT_PRIORITY( .ctors.* ))); end_ctors = .; start_dtors = .; diff --git a/prototypes/os-init/Makefile b/prototypes/os-init/Makefile new file mode 100644 index 0000000..45ee9d5 --- /dev/null +++ b/prototypes/os-init/Makefile @@ -0,0 +1,14 @@ +## +# Builds the os initialization kernel +## + +include ../config.mk + +KERNEL = os-init.ker +LIBS += -lbase -lgcc -lboot +FLAGS += -D IDT_DISPATCH=interrupt_dispatch + +all: builddir $(KERNEL) + +include ../common.mk +include ../kernel.mk \ No newline at end of file diff --git a/prototypes/base/init.cpp b/prototypes/os-init/init.cpp similarity index 60% rename from prototypes/base/init.cpp rename to prototypes/os-init/init.cpp index fee486b..7eb5cff 100644 --- a/prototypes/base/init.cpp +++ b/prototypes/os-init/init.cpp @@ -1,25 +1,23 @@ -#include "console.hpp" -#include "pmm.hpp" -#include "numeric.hpp" -#include "pointer.hpp" -#include "multiboot.hpp" -#include "gdt.hpp" -#include "idt.hpp" -#include "compat.h" -#include "io.hpp" -#include "vmm.hpp" -#include "elf.hpp" -#include "bsod.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include -#include "asm.hpp" +#include #include "driver/timer.hpp" #include "driver/keyboard.hpp" -#include +#include #include -#include using namespace multiboot; using namespace console_tools; @@ -35,76 +33,6 @@ driver::Keyboard keyboardDriver; VMMContext * kernelContext; -static const uint32_t entryPointAddress = 0x40000000; - -void run_program0(Module const & module) -{ - using namespace elf; - - const Header *header = module.start.data(); - - ProgramHeader *ph; - int i; - if (header->magic != MAGIC) { - BSOD::die(Error::InvalidELFImage, "Keine gueltige ELF-Magic!\n"); - return; - } - - ph = (ProgramHeader*)(((char*) header) + header->ph_offset); - for (i = 0; i < header->ph_entry_count; i++, ph++) { - void* dest = (void*) ph->virt_addr; - void* src = ((char*) header) + ph->offset; - - /* Nur Program Header vom Typ LOAD laden */ - if (ph->type != 1) { - continue; - } - - if(ph->virt_addr < entryPointAddress) { - BSOD::die(Error::InvalidELFImage, "A LOAD section tried to sneak into the kernel!"); - } - - for(uint32_t i = 0; i < ph->mem_size; i += 0x1000) { - kernelContext->provide( - virtual_t(ph->virt_addr + i), - VMMFlags::Writable | VMMFlags::UserSpace); - } - - memset(dest, 0, ph->mem_size); - memcpy(dest, src, ph->file_size); - } - - using EntryPoint = void (*)(); - EntryPoint ep = (EntryPoint)entryPointAddress; - ep(); -} - -static void dump_elf(elf::Header *header) -{ - using namespace elf; - ProgramHeader *ph; - int i; - - /* Ist es ueberhaupt eine ELF-Datei? */ - if (header->magic != MAGIC) { - BSOD::die(Error::InvalidELFImage, "Keine gueltige ELF-Magic!\n"); - return; - } - ph = (ProgramHeader*)(((char*) header) + header->ph_offset); - for (i = 0; i < header->ph_entry_count; i++, ph++) { - void* dest = (void*) ph->virt_addr; - void* src = ((char*) header) + ph->offset; - - Console::main - << "Header: " << ph->type << ", " - << "Source: " << src << ", " - << "Dest: " << dest << ", " - << "Memsize: " << ph->mem_size << ", " - << "Filesize: " << ph->file_size - << "\n"; - } -} - static void initializePMM(Structure const & data) { for(auto &mmap : data.memoryMaps) { @@ -157,6 +85,7 @@ static void initializePMM(Structure const & data) extern "C" void init(Structure const & data) { + Console::main.clear(); Console::main << "Hello World!\n" << FColor(Color::Yellow) << "Hello color!" << FColor() << "\n" @@ -210,18 +139,9 @@ extern "C" void init(Structure const & data) Console::main << "Drivers installed.\n"; - //asm volatile("sti"); ASM::sti(); - Console::main << "Interrupts enabled.\n"; - if(data.modules.length > 0) - { - Console::main << "ELF Modukle:\n"; - dump_elf(data.modules[0].start.data()); - run_program0(data.modules[0]); - } - while(true); } diff --git a/prototypes/os-init/multiboot.S b/prototypes/os-init/multiboot.S new file mode 100644 index 0000000..0c35043 --- /dev/null +++ b/prototypes/os-init/multiboot.S @@ -0,0 +1,28 @@ +.section multiboot + +#define MB_MAGIC 0x1badb002 +#define MB_FLAGS 0x00 +#define MB_CHECKSUM -(MB_MAGIC + MB_FLAGS) + +.align 4 + +// Offset Type Field Name Note +// 0 u32 magic required +// 4 u32 flags required +// 8 u32 checksum required +.int MB_MAGIC +.int MB_FLAGS +.int MB_CHECKSUM + +// 12 u32 header_addr if flags[16] is set +// 16 u32 load_addr if flags[16] is set +// 20 u32 load_end_addr if flags[16] is set +// 24 u32 bss_end_addr if flags[16] is set +// 28 u32 entry_addr if flags[16] is set +.int 0, 0, 0, 0, 0 + +// 32 u32 mode_type if flags[2] is set +// 36 u32 width if flags[2] is set +// 40 u32 height if flags[2] is set +// 44 u32 depth if flags[2] is set +.int 0, 0, 0, 0 \ No newline at end of file diff --git a/prototypes/base/Makefile b/prototypes/os-init/src/Makefile similarity index 84% rename from prototypes/base/Makefile rename to prototypes/os-init/src/Makefile index 88e8a29..d6de073 100644 --- a/prototypes/base/Makefile +++ b/prototypes/os-init/src/Makefile @@ -4,23 +4,27 @@ CC=gcc CXX=g++ LD=ld +LIBGCC = $(shell gcc -m32 -print-libgcc-file-name) +LIBSTD = ../stdlib/libstd.a +LIBVM = ../supervm/libvm.a + IDT_DISPATCH = _ZN3IDT8dispatchEP8CpuState -FLAGS = -mno-sse -DIDT_DISPATCH=$(IDT_DISPATCH) -ffreestanding -m32 -Werror -Wall -iquote include -iquote lists -I../stdlib/include -O3 -g +INCLUDE_DIRS = ../stdlib/include ../supervm/ + +FLAGS = -mno-sse -DIDT_DISPATCH=$(IDT_DISPATCH) -ffreestanding -m32 -Werror -Wall -iquote include -iquote lists $(addprefix -I, $(INCLUDE_DIRS)) -O3 -g ASFLAGS = $(FLAGS) CFLAGS = $(FLAGS) CXXFLAGS = $(FLAGS) -std=c++14 -fno-rtti -fno-exceptions -fno-leading-underscore -fno-use-cxa-atexit -nostdlib -fno-builtin SRCS = $(shell find -regextype egrep -regex '.*/.*\.(cpp|S|c)') OBJS = $(addsuffix .o, $(notdir $(basename $(SRCS)))) - -LIBGCC = $(shell gcc -m32 -print-libgcc-file-name) -LIBSTD = ../stdlib/libstd.a +LIBS = $(LIBGCC) $(LIBSTD) $(LIBVM) all: kernel-base.ker kernel-base.ker: $(OBJS) - $(LD) -melf_i386 -Tlinker.ld -o kernel-base.ker $(addprefix obj/, $^) $(LIBGCC) $(LIBSTD) + $(LD) -melf_i386 -Tlinker.ld -o kernel-base.ker $(addprefix obj/, $^) $(LIBS) %.o: %.cpp $(CXX) $(CXXFLAGS) -c -o obj/$@ $< @@ -46,8 +50,8 @@ kernel-base.ker: $(OBJS) # -initrd file use 'file' as initial ram disk # -dtb file use 'file' as device tree image - run: + echo `pwd` qemu-system-i386 \ -kernel kernel-base.ker \ -m 64 \ @@ -55,7 +59,7 @@ run: -no-reboot \ -no-shutdown \ -serial stdio \ - -initrd ../program0/program + -initrd `pwd`/../supervm-asm/testcode.bin insight: objdump -d kernel-base.ker | c++filt | less diff --git a/prototypes/base/src/bsod.cpp b/prototypes/os-init/src/bsod.cpp similarity index 94% rename from prototypes/base/src/bsod.cpp rename to prototypes/os-init/src/bsod.cpp index 1f20e6b..b808700 100644 --- a/prototypes/base/src/bsod.cpp +++ b/prototypes/os-init/src/bsod.cpp @@ -1,13 +1,13 @@ -#include "bsod.hpp" -#include "console.hpp" -#include "exceptions.hpp" +#include +#include +#include static const char *toString(int interrupt) { if(interrupt <= 0x1f) { switch(interrupt) { #define EXCEPTION(num, shorthand, ident, desc, type) case num: return #desc; -#include "exceptions.lst" +#include #undef EXCEPTION default: return "Unknown Exception"; } @@ -15,7 +15,7 @@ static const char *toString(int interrupt) if(interrupt >= 0x20 && interrupt <= 0x2F) { switch(interrupt - 0x20) { #define IRQ(num, ident, desc) case num: return #desc; -#include "irqs.lst" +#include #undef IRQ } } @@ -61,7 +61,7 @@ void BSOD::die(Error code, const char *msg, CpuState *cpu) << "CODE: " << Y; switch(code) { #define ERROR(num, ident, desc) case Error::ident: Console::main << #ident << " / " << #desc << "\n"; break; -#include "errors.lst" +#include #undef ERROR } Console::main diff --git a/prototypes/base/src/console.cpp b/prototypes/os-init/src/console.cpp similarity index 100% rename from prototypes/base/src/console.cpp rename to prototypes/os-init/src/console.cpp diff --git a/prototypes/base/src/gdt.cpp b/prototypes/os-init/src/gdt.cpp similarity index 98% rename from prototypes/base/src/gdt.cpp rename to prototypes/os-init/src/gdt.cpp index 5f12911..7fd57c8 100644 --- a/prototypes/base/src/gdt.cpp +++ b/prototypes/os-init/src/gdt.cpp @@ -1,4 +1,4 @@ -#include "gdt.hpp" +#include static SegmentDescriptor invalid; SegmentDescriptor GDT::descriptors[GDT::length]; diff --git a/prototypes/base/src/idt.cpp b/prototypes/os-init/src/idt.cpp similarity index 90% rename from prototypes/base/src/idt.cpp rename to prototypes/os-init/src/idt.cpp index f1d2985..f515e1b 100644 --- a/prototypes/base/src/idt.cpp +++ b/prototypes/os-init/src/idt.cpp @@ -1,11 +1,11 @@ -#include "idt.hpp" -#include "asm.hpp" -#include "bsod.hpp" -#include "pic.hpp" +#include +#include +#include +#include #define ISR(num) extern "C" void isr_##num(); #define ISR_ERR(num) ISR(num) -#include "interrupts.lst" +#include #undef ISR #undef ISR_ERR @@ -38,7 +38,7 @@ void IDT::initialize() 0x08, \ InterruptFlags::Interrupt | InterruptFlags::Use32Bit | InterruptFlags::Ring0 | InterruptFlags::Present); #define ISR_ERR(num) ISR(num) -#include "interrupts.lst" +#include #undef ISR #undef ISR_ERR @@ -56,6 +56,11 @@ void IDT::setupPIC() slavePIC.maskInterrupts(0x00); } +extern "C" CpuState * interrupt_dispatch(CpuState *cpu) +{ + return IDT::dispatch(cpu); +} + CpuState * IDT::dispatch(CpuState *cpu) { bool ackMaster = cpu->interrupt >= 0x20 && cpu->interrupt <= 0x2F; diff --git a/prototypes/base/interrupts.S b/prototypes/os-init/src/interrupts.S similarity index 96% rename from prototypes/base/interrupts.S rename to prototypes/os-init/src/interrupts.S index 8bb2215..2769e2a 100644 --- a/prototypes/base/interrupts.S +++ b/prototypes/os-init/src/interrupts.S @@ -16,7 +16,7 @@ isr_\nr: #define ISR(num) isr_stub num #define ISR_ERR(num) isr_stub_with_err num -#include "interrupts.lst" +#include #undef ISR #undef ISR_ERR diff --git a/prototypes/base/src/keyboard.cpp b/prototypes/os-init/src/keyboard.cpp similarity index 73% rename from prototypes/base/src/keyboard.cpp rename to prototypes/os-init/src/keyboard.cpp index d0e5114..92dab65 100644 --- a/prototypes/base/src/keyboard.cpp +++ b/prototypes/os-init/src/keyboard.cpp @@ -1,6 +1,6 @@ -#include "driver/keyboard.hpp" -#include "idt.hpp" -#include "console.hpp" +#include +#include +#include namespace driver { diff --git a/prototypes/base/src/numeric.cpp b/prototypes/os-init/src/numeric.cpp similarity index 100% rename from prototypes/base/src/numeric.cpp rename to prototypes/os-init/src/numeric.cpp diff --git a/prototypes/base/src/pic.cpp b/prototypes/os-init/src/pic.cpp similarity index 90% rename from prototypes/base/src/pic.cpp rename to prototypes/os-init/src/pic.cpp index 83a881c..a1256d1 100644 --- a/prototypes/base/src/pic.cpp +++ b/prototypes/os-init/src/pic.cpp @@ -1,5 +1,5 @@ -#include "pic.hpp" -#include "io.hpp" +#include +#include PIC masterPIC(0x20); PIC slavePIC(0xA0); diff --git a/prototypes/base/src/pmm.cpp b/prototypes/os-init/src/pmm.cpp similarity index 97% rename from prototypes/base/src/pmm.cpp rename to prototypes/os-init/src/pmm.cpp index ebe5e1e..19941a6 100644 --- a/prototypes/base/src/pmm.cpp +++ b/prototypes/os-init/src/pmm.cpp @@ -1,7 +1,7 @@ -#include +#include #include -#include "pmm.hpp" -#include "bsod.hpp" +#include +#include /** * Number stored of pages in the bitmap diff --git a/prototypes/base/src/screen.cpp b/prototypes/os-init/src/screen.cpp similarity index 88% rename from prototypes/base/src/screen.cpp rename to prototypes/os-init/src/screen.cpp index d41b853..f7b179e 100644 --- a/prototypes/base/src/screen.cpp +++ b/prototypes/os-init/src/screen.cpp @@ -1,5 +1,5 @@ -#include -#include "screen.hpp" +#include +#include ScreenChar Screen::outOfScreen; Screen Screen::main((ScreenChar*)0xb8000, 80, 25); diff --git a/prototypes/base/src/timer.cpp b/prototypes/os-init/src/timer.cpp similarity index 83% rename from prototypes/base/src/timer.cpp rename to prototypes/os-init/src/timer.cpp index 760b0f6..a555e7f 100644 --- a/prototypes/base/src/timer.cpp +++ b/prototypes/os-init/src/timer.cpp @@ -1,5 +1,5 @@ -#include "driver/timer.hpp" -#include "idt.hpp" +#include +#include namespace driver { diff --git a/prototypes/base/src/vmm.cpp b/prototypes/os-init/src/vmm.cpp similarity index 97% rename from prototypes/base/src/vmm.cpp rename to prototypes/os-init/src/vmm.cpp index 6a103a9..544f8f8 100644 --- a/prototypes/base/src/vmm.cpp +++ b/prototypes/os-init/src/vmm.cpp @@ -1,7 +1,7 @@ -#include "vmm.hpp" +#include #include -#include "console.hpp" -#include "asm.hpp" +#include +#include void VMM::enable() { diff --git a/prototypes/program0/Makefile b/prototypes/program0/Makefile deleted file mode 100644 index e367f30..0000000 --- a/prototypes/program0/Makefile +++ /dev/null @@ -1,43 +0,0 @@ - -AS=gcc -CC=gcc -CXX=g++ -LD=ld - -FLAGS = -mno-sse -DIDT_DISPATCH=$(IDT_DISPATCH) -ffreestanding -m32 -Werror -Wall -iquote include -iquote lists -O3 -g -ASFLAGS = $(FLAGS) -CFLAGS = $(FLAGS) -CXXFLAGS = $(FLAGS) -std=c++14 -fno-rtti -fno-exceptions -fno-leading-underscore -fno-use-cxa-atexit -nostdlib -fno-builtin - -ARTIFACT = program - -SRCS = $(shell find -regextype egrep -regex '.*/.*\.(cpp|S|c)') -OBJS = $(addsuffix .o, $(notdir $(basename $(SRCS)))) - -LIBGCC = $(shell gcc -m32 -print-libgcc-file-name) - -all: $(ARTIFACT) - -$(ARTIFACT): $(OBJS) - $(LD) -Tlinker.ld -o $(ARTIFACT) $(addprefix obj/, $^) $(LIBGCC) - -%.o: %.cpp - $(CXX) $(CXXFLAGS) -c -o obj/$@ $< - -%.o: %.c - $(CC) $(ASFLAGS) -c -o obj/$@ $< - -%.o: %.S - $(AS) $(CFLAGS) -c -o obj/$@ $< - -%.o: src/%.cpp - $(CXX) $(CXXFLAGS) -c -o obj/$@ $< - -%.o: src/%.c - $(CC) $(ASFLAGS) -c -o obj/$@ $< - -%.o: src/%.S - $(AS) $(CFLAGS) -c -o obj/$@ $< - -deploy: $(ARTIFACT) - cp $(ARTIFACT) /srv/tftp/$(ARTIFACT) \ No newline at end of file diff --git a/prototypes/program0/linker.ld b/prototypes/program0/linker.ld deleted file mode 100644 index b3694f5..0000000 --- a/prototypes/program0/linker.ld +++ /dev/null @@ -1,30 +0,0 @@ -ENTRY(_start) -OUTPUT_FORMAT(elf32-i386) -OUTPUT_ARCH(i386:i386) - -SECTIONS -{ - . = 0x40000000; - .text : { - *(.text) - } - .data ALIGN(4096) : { - start_ctors = .; - KEEP(*( .init_array )); - KEEP(*(SORT_BY_INIT_PRIORITY( .init_array.* ))); - end_ctors = .; - - start_dtors = .; - KEEP(*( .fini_array )); - end_dtors = .; - - *(.data) - } - .rodata ALIGN(4096) : { - *(.rodata) - } - .bss ALIGN(4096) : { - *(.bss) - } - . = ALIGN(4096); -} diff --git a/prototypes/program0/program b/prototypes/program0/program deleted file mode 100644 index 45d524d..0000000 Binary files a/prototypes/program0/program and /dev/null differ diff --git a/prototypes/program0/program.c b/prototypes/program0/program.c deleted file mode 100644 index ce530bd..0000000 --- a/prototypes/program0/program.c +++ /dev/null @@ -1,11 +0,0 @@ -#include - -uint16_t *video = (uint16_t*)0xB8000; - -void _start() -{ - for(int i = 0; i < 256; i++) { - video[i] = 0xF000 | i; - } - while(1); -} \ No newline at end of file diff --git a/prototypes/stdlib/Makefile b/prototypes/stdlib/Makefile deleted file mode 100644 index 95cf718..0000000 --- a/prototypes/stdlib/Makefile +++ /dev/null @@ -1,42 +0,0 @@ - -AS=gcc -CC=gcc -CXX=g++ -LD=ld -AR=ar - -FLAGS = -mno-sse -ffreestanding -m32 -Werror -Wall -iquote include -O3 -g -ASFLAGS = $(FLAGS) -CFLAGS = $(FLAGS) -CXXFLAGS = $(FLAGS) -std=c++14 -fno-rtti -fno-exceptions -fno-leading-underscore -fno-use-cxa-atexit -nostdlib -fno-builtin - -ARTIFACT = libstd.a - -SRCS = $(shell find -regextype egrep -regex '.*/.*\.(cpp|S|c)') -OBJS = $(addsuffix .o, $(notdir $(basename $(SRCS)))) - -all: $(ARTIFACT) - -$(ARTIFACT): $(OBJS) - $(AR) rcs $(ARTIFACT) $(addprefix obj/, $^) - -%.o: %.cpp - $(CXX) $(CXXFLAGS) -c -o obj/$@ $< - -%.o: %.c - $(CC) $(ASFLAGS) -c -o obj/$@ $< - -%.o: %.S - $(AS) $(CFLAGS) -c -o obj/$@ $< - -%.o: src/%.cpp - $(CXX) $(CXXFLAGS) -c -o obj/$@ $< - -%.o: src/%.c - $(CC) $(ASFLAGS) -c -o obj/$@ $< - -%.o: src/%.S - $(AS) $(CFLAGS) -c -o obj/$@ $< - -deploy: $(ARTIFACT) - cp $(ARTIFACT) /srv/tftp/$(ARTIFACT) \ No newline at end of file diff --git a/prototypes/stdlib/include/string.h b/prototypes/stdlib/include/string.h deleted file mode 100644 index 13d76e2..0000000 --- a/prototypes/stdlib/include/string.h +++ /dev/null @@ -1,16 +0,0 @@ -#pragma once - -#include - -#if defined(__cplusplus) -extern "C" { -#endif - -void * memcpy ( void * destination, const void * source, size_t num ); - -void * memset ( void * ptr, int value, size_t num ); - - -#if defined(__cplusplus) -} -#endif \ No newline at end of file diff --git a/prototypes/stdlib/src/string.c b/prototypes/stdlib/src/string.c deleted file mode 100644 index b1a1e93..0000000 --- a/prototypes/stdlib/src/string.c +++ /dev/null @@ -1,20 +0,0 @@ -#include "string.h" - -void * memcpy ( void * destination, const void * source, size_t num ) -{ - char *d = destination; - char const * s = source; - for(size_t i = 0; i < num; i++) { - d[i] = s[i]; - } - return destination; -} - -void * memset ( void * ptr, int value, size_t num ) -{ - char *p = ptr; - for(size_t i = 0; i < num; i++) { - p[i] = value; - } - return ptr; -} \ No newline at end of file diff --git a/prototypes/supervm-asm/.gitignore b/prototypes/supervm-asm/.gitignore deleted file mode 100644 index a8a0dce..0000000 --- a/prototypes/supervm-asm/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.bin diff --git a/prototypes/supervm-asm/Makefile b/prototypes/supervm-asm/Makefile deleted file mode 100644 index adf2346..0000000 --- a/prototypes/supervm-asm/Makefile +++ /dev/null @@ -1,7 +0,0 @@ - -CSC = mcs - -all: assembler.exe - -assembler.exe: assembler.cs - $(CSC) -out:$@ -target:exe $^ \ No newline at end of file diff --git a/prototypes/supervm-asm/assembler b/prototypes/supervm-asm/assembler deleted file mode 100644 index adbf642..0000000 --- a/prototypes/supervm-asm/assembler +++ /dev/null @@ -1 +0,0 @@ -#!/usr/bin/mono assembler.exe \ No newline at end of file diff --git a/prototypes/supervm-asm/assembler.cs b/prototypes/supervm-asm/assembler.cs deleted file mode 100644 index 7df30c8..0000000 --- a/prototypes/supervm-asm/assembler.cs +++ /dev/null @@ -1,493 +0,0 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using System.Threading.Tasks; - -namespace supervm_asm -{ - class Program - { - static void Main(string[] args) - { - if(args.Contains("-gen-code")) - { - MnemonicParser.GenerateFromDocumentation( - @"../supervm/supervm.md"); - return; - } - - foreach(var file in args.Where(a => !a.StartsWith("-") && Path.GetExtension(a) == ".asm")) - { - var output = Path.ChangeExtension(file, ".bin"); - var assembly = Assembler.Assemble(File.ReadAllText(file)); - - var code = assembly.Code; - - Console.WriteLine("{0}*{1}:", output, code.Count); - for (int i = 0; i < code.Count; i++) - { - Console.Write("; {0:D3} ", i); - PrintInstruction(code[i], assembly.Annotation[i]); - } - using(var fs = File.Open(output, FileMode.Create, FileAccess.Write)) - { - for(int i = 0; i < code.Count; i++) - { - var bits = BitConverter.GetBytes(code[i]); - if(BitConverter.IsLittleEndian == false) - { - bits = bits.Reverse().ToArray(); - } - fs.Write(bits, 0, bits.Length); - } - } - } - } - - static void PrintInstruction(ulong instr, string comment) - { - var str = Convert.ToString((long)instr, 2).PadLeft(64, '0'); - - var portions = new [] - { - new { Start = 0, Length = 32, Color = ConsoleColor.Red }, - new { Start = 32, Length = 2, Color = ConsoleColor.DarkGreen }, - new { Start = 34, Length = 1, Color = ConsoleColor.Green }, - new { Start = 35, Length = 16, Color = ConsoleColor.Magenta }, - new { Start = 51, Length = 6, Color = ConsoleColor.Yellow }, - new { Start = 57, Length = 1, Color = ConsoleColor.DarkCyan }, - new { Start = 58, Length = 2, Color = ConsoleColor.Cyan }, - new { Start = 60, Length = 2, Color = ConsoleColor.DarkBlue }, - new { Start = 62, Length = 2, Color = ConsoleColor.Blue }, - }; - - var fg = Console.ForegroundColor; - foreach(var portion in portions) - { - Console.ForegroundColor = portion.Color; - Console.Write("{0} ", str.Substring(portion.Start, portion.Length)); - } - Console.ForegroundColor = fg; - Console.WriteLine(" {0}", comment); - } - } - - public class VMAssembly - { - private readonly ulong[] code; - private readonly string[] origins; - - public VMAssembly(ulong[] code, string[] origins) - { - this.code = code; - this.origins = origins; - } - - public IReadOnlyList Code => this.code; - public IReadOnlyList Annotation => this.origins; - } - - public static class Assembler - { - static Regex annotationMatcher = new Regex(@"\[\s*(.*?)\s*\]", RegexOptions.Compiled); - static Regex labelMatcher = new Regex(@"^(\w+):\s*(.*)\s*$", RegexOptions.Compiled); - static Regex instructionMatcher = new Regex(@"(\w+)(?:\s+([@-]?\w+|'.'))?", RegexOptions.Compiled); - - public static VMAssembly Assemble(string src) - { - var lines = src.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); - var patches = new Dictionary(); - var labels = new Dictionary(); - - var code = new List(); - var source = new List(); - for (int i = 0; i < lines.Length; i++) - { - var line = lines[i].Trim(); - { // Process comments - var idx = line.IndexOf(';'); - if (idx >= 0) - line = line.Substring(0, idx); - } - - var uncommented = line; - - { // Process labels - var match = labelMatcher.Match(line); - if (match.Success) - { - var label = match.Groups[1].Value; - labels.Add(label, code.Count); - line = match.Groups[2].Value; - } - } - - if (string.IsNullOrWhiteSpace(line)) - continue; - - var annotations = new HashSet(); - line = annotationMatcher.Replace(line, (m) => - { - annotations.Add(m.Groups[1].Value.ToLower()); - return ""; - }); - line = line.Trim(); - - { - var match = instructionMatcher.Match(line); - if (match.Success == false) - throw new InvalidOperationException("Invalid instruction: " + line); - - var mnemonic = match.Groups[1].Value; - - uint argument = 0; - if (match.Groups[2].Length > 0) - { - var argstring = match.Groups[2].Value; - if (argstring.StartsWith("@")) - { - // Add patch note for labels. - patches.Add(code.Count, argstring.Substring(1)); - } - else if (argstring.StartsWith("'")) - { - argument = (uint)argstring[1]; - } - else if (argstring.StartsWith("0x")) - { - argument = Convert.ToUInt32(argstring.Substring(2), 16); - } - else if (argstring.StartsWith("0b")) - { - argument = Convert.ToUInt32(argstring.Substring(2), 10); - } - else if (argstring.StartsWith("0d")) - { - argument = Convert.ToUInt32(argstring.Substring(2), 10); - } - else - { - if(argstring.StartsWith("-")) - { - unchecked - { - argument = (uint)Convert.ToInt32(argstring, 10);; - } - } - else - argument = Convert.ToUInt32(argstring, 10); - } - } - - if(mnemonics.ContainsKey(mnemonic) == false) - { - throw new InvalidOperationException("Unknown mnemonic: " + mnemonic); - } - - var instruction = mnemonics[mnemonic]; - - foreach(var annotation in annotations) - { - if(annotation.StartsWith("ci:")) - { - instruction.CommandInfo = UInt16.Parse(annotation.Substring(3)); - continue; - } - - if (annotation.StartsWith("cmd:")) - { - instruction.Command = (Command)Enum.Parse(typeof(Command), annotation.Substring(4)); - continue; - } - - switch (annotation) - { - case "f:yes": - instruction.ModifyFlags = true; - break; - case "f:no": - instruction.ModifyFlags = false; - break; - case "r:discard": - instruction.Output = OutputType.Discard; - break; - case "r:push": - instruction.Output = OutputType.Push; - break; - case "r:jump": - instruction.Output = OutputType.Jump; - break; - case "i0:zero": - instruction.Input0 = InputType.Zero; - break; - case "i0:pop": - instruction.Input0 = InputType.Pop; - break; - case "i0:peek": - instruction.Input0 = InputType.Peek; - break; - case "i0:arg": - instruction.Input0 = InputType.Argument; - break; - case "i1:zero": - instruction.Input1 = InputType.Zero; - break; - case "i1:pop": - instruction.Input1 = InputType.Pop; - break; - case "ex(z)=x": - instruction.ExecutionZ = ExecutionMode.Always; - break; - case "ex(z)=0": - instruction.ExecutionZ = ExecutionMode.Zero; - break; - case "ex(z)=1": - instruction.ExecutionZ = ExecutionMode.One; - break; - case "ex(n)=x": - instruction.ExecutionN = ExecutionMode.Always; - break; - case "ex(n)=0": - instruction.ExecutionN = ExecutionMode.Zero; - break; - case "ex(n)=1": - instruction.ExecutionN = ExecutionMode.One; - break; - default: - throw new InvalidOperationException("Unrecognized annotation: " + annotation); - } - } - - ulong encoded = 0; - - encoded |= ((uint)(instruction.ExecutionZ) << 0); - encoded |= ((uint)(instruction.ExecutionN) << 2); - encoded |= ((uint)(instruction.Input0) << 4); - encoded |= ((uint)(instruction.Input1) << 6); - encoded |= ((uint)(instruction.Command) << 7); - encoded |= ((uint)(instruction.CommandInfo) << 13); - encoded |= ((uint)(instruction.ModifyFlags ? 1 : 0) << 29); - encoded |= ((uint)(instruction.Output) << 30); - encoded |= ((ulong)argument << 32); - - code.Add(encoded); - source.Add(uncommented); - } - } - - { // Install patches - foreach (var patch in patches) - { - var target = patch.Value; - var position = labels[target]; - code[patch.Key] = - (code[patch.Key] & 0xFFFFFFFF) | - ((ulong)position << 32); - } - } - - return new VMAssembly(code.ToArray(), source.ToArray()); - } - - - static Dictionary mnemonics = new Dictionary() - { -{ "nop", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Zero, Input1 = InputType.Zero, Command = Command.Copy, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Discard, Argument = 0, } }, -{ "push", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Argument, Input1 = InputType.Zero, Command = Command.Copy, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "drop", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Zero, Command = Command.Copy, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Discard, Argument = 0, } }, -{ "dup", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Peek, Input1 = InputType.Zero, Command = Command.Copy, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "jmp", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Argument, Input1 = InputType.Zero, Command = Command.Copy, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Jump, Argument = 0, } }, -{ "jmpi", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Zero, Command = Command.Copy, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Jump, Argument = 0, } }, -{ "ret", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Zero, Command = Command.Copy, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Jump, Argument = 0, } }, -{ "load", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Argument, Input1 = InputType.Zero, Command = Command.Load, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "loadi", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Zero, Command = Command.Load, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "store", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Argument, Input1 = InputType.Pop, Command = Command.Store, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Discard, Argument = 0, } }, -{ "storei", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Store, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Discard, Argument = 0, } }, -{ "get", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Argument, Input1 = InputType.Zero, Command = Command.Get, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "geti", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Zero, Command = Command.Get, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "set", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Argument, Input1 = InputType.Pop, Command = Command.Set, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Discard, Argument = 0, } }, -{ "seti", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Set, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Discard, Argument = 0, } }, -{ "bpget", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Zero, Input1 = InputType.Zero, Command = Command.BpGet, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "bpset", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Zero, Command = Command.BpSet, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Discard, Argument = 0, } }, -{ "spget", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Zero, Input1 = InputType.Zero, Command = Command.SpGet, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "spset", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Zero, Command = Command.SpSet, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Discard, Argument = 0, } }, -{ "cpget", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Zero, Input1 = InputType.Zero, Command = Command.CpGet, CommandInfo = 1, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "add", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "sub", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 1, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "cmp", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 1, ModifyFlags = true, Output = OutputType.Discard, Argument = 0, } }, -{ "mul", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 2, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "div", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 3, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "mod", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 4, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "and", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 5, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "or", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 6, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "xor", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 7, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "not", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Zero, Command = Command.Math, CommandInfo = 8, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "rol", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 9, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "ror", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 10, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "asl", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 11, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "asr", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 12, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "shl", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 13, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "shr", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Pop, Input1 = InputType.Pop, Command = Command.Math, CommandInfo = 14, ModifyFlags = false, Output = OutputType.Push, Argument = 0, } }, -{ "syscall", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Zero, Input1 = InputType.Zero, Command = Command.SysCall, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Discard, Argument = 0, } }, -{ "hwio", new Instruction() { ExecutionZ = ExecutionMode.Always, ExecutionN = ExecutionMode.Always, Input0 = InputType.Zero, Input1 = InputType.Zero, Command = Command.HwIO, CommandInfo = 0, ModifyFlags = false, Output = OutputType.Discard, Argument = 0, } }, - - }; - } - - class MnemonicParser - { - public static void GenerateFromDocumentation(string file) - { - var relevantLines = File - .ReadAllLines(file) - .SkipWhile(l => l != "## Assembler Mnemonics") - .Skip(1) - .SkipWhile(l => string.IsNullOrWhiteSpace(l)) - .TakeWhile(l => l.StartsWith("|")) - .Skip(2) - .ToArray(); - - - - var instructions = relevantLines - .Select(l => l - .Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries) - .Select(s => s.Trim()) - .ToArray()) - .ToDictionary(a => a[0], a => new Instruction() - { - ExecutionN = ExecutionMode.Always, - ExecutionZ = ExecutionMode.Always, - Input0 = ToInputMode(a[2]), - Input1 = ToInputMode(a[3]), - Command = ToCommand(a[4]), - CommandInfo = ushort.Parse(a[5]), - ModifyFlags = (a[7].ToLower() == "yes"), - Output = ToOutput(a[6]), - Argument = 0, - }); - - var fields = typeof(Instruction).GetFields(); - foreach (var item in instructions) - { - // { "a", new Instruction() { } }, - Console.Write("{{ \"{0}\", new Instruction() {{ ", item.Key); - - foreach (var field in fields) - { - var value = field.GetValue(item.Value); - if (field.FieldType.IsEnum) - Console.Write("{0} = {1}.{2}, ", field.Name, field.FieldType.Name, value); - else - Console.Write("{0} = {1}, ", field.Name, value.ToString().ToLower()); - } - - Console.WriteLine(" } },"); - } - } - - private static OutputType ToOutput(string v) - { - switch (v.ToLower()) - { - case "discard": return OutputType.Discard; - case "push": return OutputType.Push; - case "jump": return OutputType.Jump; - default: - throw new NotSupportedException(); - } - } - - private static Command ToCommand(string v) - { - return (Command)Enum.Parse(typeof(Command), v, true); - } - - private static InputType ToInputMode(string v) - { - switch (v.ToLower()) - { - case "zero": return InputType.Zero; - case "peek": return InputType.Peek; - case "pop": return InputType.Pop; - case "arg": return InputType.Argument; - default: - throw new NotSupportedException(); - } - } - } - - public struct Instruction - { - public ExecutionMode ExecutionZ; - public ExecutionMode ExecutionN; - public InputType Input0; - public InputType Input1; - public Command Command; - public ushort CommandInfo; - public bool ModifyFlags; - public OutputType Output; - public uint Argument; - } - - public enum MathCommand - { - Add = 0, - Subtract = 1, - Multiplicate = 2, - Divide = 3, - Modulo = 4, - And = 5, - Or = 6, - Xor = 7, - Not = 8, - RotShiftLeft = 9, - RotShiftRight = 10, - ArithmeticShiftLeft = 11, - ArithmeticShiftRight = 12, - LogicShiftLeft = 13, - LogicShiftRight = 14, - } - - public enum Command - { - Copy = 0, - Store = 1, - Load = 2, - Get = 3, - Set = 4, - BpGet = 5, - BpSet = 6, - CpGet = 7, - Math = 8, - SpGet = 9, - SpSet = 10, - SysCall = 11, - HwIO = 12, - } - - public enum OutputType - { - Discard = 0, - Push = 1, - Jump = 2, - } - - public enum ExecutionMode - { - Always = 0, - Zero = 2, - One = 3, - } - - public enum InputType - { - Zero = 0, - Pop = 1, - Peek = 2, - Argument = 3, - } -} diff --git a/prototypes/supervm-asm/testcode.asm b/prototypes/supervm-asm/testcode.asm deleted file mode 100644 index d6540dd..0000000 --- a/prototypes/supervm-asm/testcode.asm +++ /dev/null @@ -1,51 +0,0 @@ - - ; Just print a "START" flag - [i0:arg] syscall [ci:1] 'S' - - - push 0 ; pushs string pointer argument - cpget ; pushs return addr - jmp @print_str ; Calls print_str(0) - drop ; releases argument - - - ; Print the "END" marker - [i0:arg] syscall [ci:1] 'Q' - - ; End the program - syscall [ci:0] - -; void print_str(char *string); -print_str: - bpget ; enter function by - spget ; saving the parents base pointer - bpset ; and storing the current stack pointer - - - ; char *ptr = string; - get -2 ; get argument 0 into our local variable '#1' - - ; while(*ptr) { -print_str_loop: - [i0:peek] loadi [f:yes] ; write flags, also load result, don't discard pointer - [ex(z)=1] jmp @print_str_end_loop ; when *ptr == 0, then goto print_str_end_loop - ; char c = *ptr; // which is implicitly done by our while(*ptr) - - ; putc(c); - [i0:pop] syscall [ci:1] ; removes the loaded character and prints it - - ; ptr++; - [i0:arg] add 1 ; adds 1 to the stack top - - ; } - jmp @print_str_loop - -print_str_end_loop: - drop ; discard the result from loadi - drop ; discard our pointer - - ; return - bpget ; leave function - spset ; by restoring parent base pointer - bpset - jmpi ; and jumping back. diff --git a/prototypes/supervm/.gitignore b/prototypes/supervm/.gitignore deleted file mode 100644 index b34018e..0000000 --- a/prototypes/supervm/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -obj/* -vm diff --git a/prototypes/supervm/Makefile b/prototypes/supervm/Makefile deleted file mode 100644 index cc8fb57..0000000 --- a/prototypes/supervm/Makefile +++ /dev/null @@ -1,21 +0,0 @@ - -AS=gcc -CC=gcc -CXX=g++ -LD=ld -AR=ar - -FLAGS = -Werror -Wall -iquote include -O3 -g -VMFLAGS = $(FLAGS) -m32 -mno-sse -ffreestanding - -ARTIFACT = libvm.a -PROGRAM = vm - -all: $(ARTIFACT) $(PROGRAM) - -$(PROGRAM): main.c vm.c vm.h - $(CC) -o $@ $(FLAGS) main.c vm.c - -$(ARTIFACT): vm.c vm.h - $(CC) $(VMFLAGS) -c -o obj/vm.o.32 vm.c - $(AR) rcs $(ARTIFACT) obj/vm.o.32 diff --git a/prototypes/supervm/main.c b/prototypes/supervm/main.c deleted file mode 100644 index de06cd7..0000000 --- a/prototypes/supervm/main.c +++ /dev/null @@ -1,178 +0,0 @@ -#include "vm.h" - -#include -#include -#include - -void vm_assert(int assertion, const char *msg) -{ - if(assertion != 0) - return; - printf("Assertion failed: %s\n", msg); - exit(1); -} - -void vm_syscall(Process *p, CommandInfo *info) -{ - switch(info->additional) - { - case 0: // EXIT - p->tag = NULL; - break; - case 1: - printf("%c", info->input0); - break; - case 2: - printf("%d", info->input0); - break; - default: - printf("Some syscall: (%d, %d, %d, %d)\n", - info->input0, - info->input1, - info->argument, - info->additional); - break; - } -} - -void vm_hwio(Process *p, CommandInfo *info) -{ - printf("Some hardware IO: (%d, %d, %d, %d)\n", - info->input0, - info->input1, - info->argument, - info->additional); -} - - - -void dump_proc(Process *process) -{ - if(process->flags & VM_FLAG_Z) - printf("z"); - else - printf(" "); - - if(process->flags & VM_FLAG_N) - printf("n"); - else - printf(" "); - - printf( - "%2d %2d ", - process->codePointer, - process->basePointer); - - printf("[ "); - for(int i = 1; i <= process->stackPointer; i++) { - printf("%d ", process->stack[i]); - } - printf("]\n"); -} - -void dump_memory(Process *process) -{ - printf("Memory Dump:\n"); - - for(int i = 0; i < process->mmap.length; i++) { - printf("Page %d\n", i); - - // Just assume that pageSize is a multiple of 16 - for(int j = 0; j < process->mmap.pageSize; j++) { - if(j % 16 == 0) - printf("%3x ", j); - - printf("%2.2X ", process->mmap.pages[i][j]); - - if(j % 16 == 15) { - printf(" '"); - for(int x = 16*(j/16); x < 16*(j/16+1); x++) { - char c = process->mmap.pages[i][x]; - if(c < 0x20) c = '.'; - if(c > 0x7E) c = '.'; - printf("%c", c); - } - printf("'\n"); - } - } - } -} - -int main(int argc, const char **argv) -{ - if(argc < 2) { - printf("Usage: vm [binary]\n"); - printf(" [binary]: The file to be executed.\n"); - return 1; - } - Module module = { 0 }; - { // Read module - FILE *f = fopen(argv[1], "rb"); - fseek(f, 0, SEEK_END); - size_t len = ftell(f); - fseek(f, 0, SEEK_SET); - module.code = malloc(len); - module.length = len / sizeof(Instruction); - - char *ptr = (char*)module.code; - for(int p = 0; p < len; p += fread(&ptr[p], 1, sizeof(Instruction), f)); - - fclose(f); - } - printf("Loaded module %s with %d instructions.\n", argv[1], module.length); - for(int i = 0; i < module.length; i++) - { - Instruction c = module.code[i]; - printf( - "%3d: %10d %1d %1d %5d %3d %1d %1d %1d %1d\n", - i, - c.argument, - c.output, - c.flags, - c.cmdinfo, - c.command, - c.input1, - c.input0, - c.execN, - c.execZ); - } - - uint8_t page0[64]; - uint8_t page1[64]; - - strcpy((char*)page0, "Hallo Welt!"); - - uint8_t *mmapDirectory[2] = { - page0, - page1, - }; - - VirtualMemoryMap mmap = { - .pageSize = 64, - .length = 2, - .pages = mmapDirectory, - }; - - Process process = { - &module, - .codePointer = 0, - .stackPointer = 0, - .basePointer = 0, - .flags = 0, - .mmap = mmap, - }; - - Process *p = &process; - p->tag = p; - - dump_memory(p); - dump_proc(p); - - while(vm_step_process(p) && p->tag) { - dump_proc(p); - } - dump_proc(p); - dump_memory(p); - - return 0; -} diff --git a/prototypes/supervm/vm.c b/prototypes/supervm/vm.c deleted file mode 100644 index 920a106..0000000 --- a/prototypes/supervm/vm.c +++ /dev/null @@ -1,261 +0,0 @@ -#include "vm.h" - -#include - -static void cmd_copy(CommandInfo *info) -{ - info->output = info->input0; -} - -static void cmd_load(Process *p, CommandInfo *info) -{ - info->output = 0; - switch(info->additional) { - case 2: - info->output|=(uint32_t)(vm_read_byte(p, info->input0+3))<<24; - info->output|=(uint32_t)(vm_read_byte(p, info->input0+2))<<16; - case 1: - info->output|=(uint32_t)(vm_read_byte(p, info->input0+1))<< 8; - case 0: - info->output|=(uint32_t)(vm_read_byte(p, info->input0+0))<< 0; - break; - } -} - -static void cmd_store(Process *p, CommandInfo *info) -{ - switch(info->additional) { - case 2: - vm_write_byte(p, info->input0+3, info->input1>>24); - vm_write_byte(p, info->input0+2, info->input1>>16); - case 1: - vm_write_byte(p, info->input0+1, info->input1>>8); - case 0: - vm_write_byte(p, info->input0, info->input1); - break; - } - info->output = info->input1; -} - -static void cmd_spget(Process *p, CommandInfo *info) -{ - info->output = p->stackPointer; -} - -static void cmd_spset(Process *p, CommandInfo *info) -{ - info->output = p->stackPointer = info->input0; -} - -static void cmd_bpget(Process *p, CommandInfo *info) -{ - info->output = p->basePointer; -} - -static void cmd_bpset(Process *p, CommandInfo *info) -{ - info->output = p->basePointer = info->input0; -} - -static void cmd_cpget(Process *p, CommandInfo *info) -{ - info->output = p->codePointer + info->additional; -} - -static inline int16_t makeSigned(uint16_t val) -{ - return *((int16_t*)&val); -} - -static void cmd_get(Process *p, CommandInfo *info) -{ - info->output = p->stack[p->basePointer + makeSigned(info->input0)]; -} - -static void cmd_set(Process *p, CommandInfo *info) -{ - info->output = p->stack[p->basePointer + makeSigned(info->input0)] = info->input1; -} - -static void cmd_math(CommandInfo *info) -{ - switch(info->additional) - { - // IMPORTANT: - // input1 - input0 because then input0 can be a fixed value -#define S(name, op) case name: info->output = info->input1 op info->input0; break; - S(VM_MATH_ADD, +) - S(VM_MATH_SUB, -) - S(VM_MATH_MUL, *) - S(VM_MATH_DIV, /) - S(VM_MATH_MOD, %) - S(VM_MATH_AND, &) - S(VM_MATH_OR, |) - S(VM_MATH_XOR, ^) -#undef S - case VM_MATH_NOT: info->output = ~info->input0; break; - default: vm_assert(0, "Invalid instruction: MATH command not defined."); break; - } -} - -int vm_step_process(Process *process) -{ - vm_assert(process != NULL, "process must not be NULL."); - Instruction instr = process->module->code[process->codePointer++]; - - int exec = 1; - switch(instr.execZ) - { - case VM_EXEC_X: - /* Don't modify execution. */ - break; - case VM_EXEC_0: - if((process->flags & VM_FLAG_Z) != 0) - exec = 0; - break; - case VM_EXEC_1: - if((process->flags & VM_FLAG_Z) == 0) - exec = 0; - break; - default: - vm_assert(0, "Invalid instruction: execZ undefined."); - break; - } - - switch(instr.execN) - { - case VM_EXEC_X: - /* Don't modify execution. */ - break; - case VM_EXEC_0: - if((process->flags & VM_FLAG_N) != 0) - exec = 0; - break; - case VM_EXEC_1: - if((process->flags & VM_FLAG_N) == 0) - exec = 0; - break; - default: - vm_assert(0, "Invalid instruction: execN undefined."); - break; - } - - // Only do further instruction execution when - // the execution condition is met. - if(exec) - { - CommandInfo info = { 0 }; - switch(instr.input0) - { - case VM_INPUT_ZERO: info.input0 = 0; break; - case VM_INPUT_POP: info.input0 = vm_pop(process); break; - case VM_INPUT_PEEK: info.input0 = vm_peek(process); break; - case VM_INPUT_ARG: info.input0 = instr.argument; break; - default: vm_assert(0, "Invalid instruction: input0 undefined."); - } - - switch(instr.input1) - { - case VM_INPUT_ZERO: info.input1 = 0; break; - case VM_INPUT_POP: info.input1 = vm_pop(process); break; - default: vm_assert(0, "Invalid instruction: input1 undefined."); - } - - info.argument = instr.argument; - info.additional = instr.cmdinfo; - - switch(instr.command) - { - case VM_CMD_COPY: cmd_copy(&info); break; - case VM_CMD_STORE: cmd_store(process, &info); break; - case VM_CMD_LOAD: cmd_load(process, &info); break; - case VM_CMD_MATH: cmd_math(&info); break; - case VM_CMD_SYSCALL: vm_syscall(process, &info); break; - case VM_CMD_HWIO: vm_hwio(process, &info); break; - case VM_CMD_SPGET: cmd_spget(process, &info); break; - case VM_CMD_SPSET: cmd_spset(process, &info); break; - case VM_CMD_BPGET: cmd_bpget(process, &info); break; - case VM_CMD_BPSET: cmd_bpset(process, &info); break; - case VM_CMD_CPGET: cmd_cpget(process, &info); break; - case VM_CMD_GET: cmd_get(process, &info); break; - case VM_CMD_SET: cmd_set(process, &info); break; - default: vm_assert(0, "Invalid instruction: command undefined."); - } - - switch(instr.flags) - { - case VM_FLAG_YES: - process->flags = 0; - if(info.output == 0) - process->flags |= VM_FLAG_Z; - else if((info.output & (1<<31)) != 0) - process->flags |= VM_FLAG_N; - break; - case VM_FLAG_NO: break; - default: - vm_assert(0, "Invalid instruction: invalid flags."); - } - - switch(instr.output) - { - case VM_OUTPUT_DISCARD: break; - case VM_OUTPUT_PUSH: vm_push(process, info.output); break; - case VM_OUTPUT_JUMP: process->codePointer = info.output; break; - default: - vm_assert(0, "Invalid instruction: invalid output."); - } - } - - return process->codePointer < process->module->length; -} - -void vm_push(Process *process, uint32_t value) -{ - vm_assert(process != NULL, "process must not be NULL."); - vm_assert(process->stackPointer < VM_STACKSIZE, "Stack overflow"); - process->stack[++process->stackPointer] = value; -} - -uint32_t vm_pop(Process *process) -{ - vm_assert(process != NULL, "process must not be NULL."); - uint32_t psp = process->stackPointer; - uint32_t val = process->stack[process->stackPointer--]; - - // Underflow check works because unsigned overflow is defined ;) - vm_assert(psp >= process->stackPointer, "Stack underflow"); - - return val; -} - -uint32_t vm_peek(Process *process) -{ - vm_assert(process != NULL, "process must not be NULL."); - return process->stack[process->stackPointer]; -} - - - - - -uint8_t vm_read_byte(Process *process, uint32_t address) -{ - vm_assert(process != NULL, "process must not be NULL."); - - uint32_t page = address / process->mmap.pageSize; - uint32_t index = address % process->mmap.pageSize; - vm_assert(page < process->mmap.length, "Out of memory."); - - return process->mmap.pages[page][index]; -} - -void vm_write_byte(Process *process, uint32_t address, uint8_t value) -{ - vm_assert(process != NULL, "process must not be NULL."); - - uint32_t page = address / process->mmap.pageSize; - uint32_t index = address % process->mmap.pageSize; - vm_assert(page < process->mmap.length, "Out of memory."); - - process->mmap.pages[page][index] = value; -} diff --git a/prototypes/supervm/vm.h b/prototypes/supervm/vm.h deleted file mode 100644 index c97fb1d..0000000 --- a/prototypes/supervm/vm.h +++ /dev/null @@ -1,182 +0,0 @@ -#pragma once - -#include -#include - -#if defined(__cplusplus) -extern "C" { -#endif - -#if !defined(VM_STACKSIZE) -#define VM_STACKSIZE 512 -#endif - -// Binary Encoding : (enabled, value) -#define VM_EXEC_X 0 -#define VM_EXEC_0 2 -#define VM_EXEC_1 3 - -#define VM_INPUT_ZERO 0 -#define VM_INPUT_POP 1 -#define VM_INPUT_PEEK 2 -#define VM_INPUT_ARG 3 - -#define VM_CMD_COPY 0 -#define VM_CMD_STORE 1 -#define VM_CMD_LOAD 2 -#define VM_CMD_GET 3 -#define VM_CMD_SET 4 -#define VM_CMD_BPGET 5 -#define VM_CMD_BPSET 6 -#define VM_CMD_CPGET 7 -#define VM_CMD_MATH 8 -#define VM_CMD_SPGET 9 -#define VM_CMD_SPSET 10 -#define VM_CMD_SYSCALL 11 -#define VM_CMD_HWIO 12 - -#define VM_MATH_ADD 0 -#define VM_MATH_SUB 1 -#define VM_MATH_MUL 2 -#define VM_MATH_DIV 3 -#define VM_MATH_MOD 4 -#define VM_MATH_AND 5 -#define VM_MATH_OR 6 -#define VM_MATH_XOR 7 -#define VM_MATH_NOT 8 -#define VM_MATH_ROL 9 -#define VM_MATH_ROR 10 -#define VM_MATH_ASL 11 -#define VM_MATH_ASR 12 -#define VM_MATH_SHL 13 -#define VM_MATH_SHR 14 - -#define VM_FLAG_NO 0 -#define VM_FLAG_YES 1 - -#define VM_OUTPUT_DISCARD 0 -#define VM_OUTPUT_PUSH 1 -#define VM_OUTPUT_JUMP 2 - -#define VM_FLAG_Z (1<<0) -#define VM_FLAG_N (1<<1) - -typedef struct -{ - unsigned int execZ : 2; - unsigned int execN : 2; - unsigned int input0 : 2; - unsigned int input1 : 1; - unsigned int command : 6; - unsigned int cmdinfo : 16; - unsigned int flags : 1; - unsigned int output : 2; - uint32_t argument; -} __attribute__ ((packed)) Instruction; - -_Static_assert(sizeof(Instruction) == 8, "Instruction must be 8 bytes large."); -_Static_assert(offsetof(Instruction, argument) == 4, "Argument must be must be 8 bytes large."); - -typedef struct -{ - Instruction *code; - uint32_t length; -} Module; - -typedef struct -{ - uint32_t pageSize; - uint32_t length; - uint8_t **pages; -} VirtualMemoryMap; - -typedef struct -{ - Module *module; - void *tag; - - uint32_t codePointer; - uint32_t stackPointer; - uint32_t basePointer; - uint32_t flags; - - uint32_t stack[VM_STACKSIZE]; - - VirtualMemoryMap mmap; -} Process; - -typedef struct -{ - uint32_t input0; - uint32_t input1; - uint32_t argument; - uint32_t additional; - - uint32_t output; -} CommandInfo; - -/** - * @brief Steps a given process. - * - * Executes a single instruction and processes input and output. - * - * @param process The process to be stepped. - * @returns 1 if the process is still running or 0 if the process is terminated. - */ -int vm_step_process(Process *process); - -/** - * @brief Pushes a value onto the process' stack. - */ -void vm_push(Process *process, uint32_t value); - -/** - * @brief Pops a value from the process' stack. - */ -uint32_t vm_pop(Process *process); - -/** - * @brief Returns the top value of the process' stack. - */ -uint32_t vm_peek(Process *process); - -/** - * Reads a byte from process memory. - * @arg process - * @arg address The address to read from. - */ -uint8_t vm_read_byte(Process *process, uint32_t address); - -/** - * Writes a byte to process memory. - * @arg process - * @arg address The address to read from. - */ -void vm_write_byte(Process *process, uint32_t address, uint8_t value); - -// The following functions need to be host-implemented. - -/** - * An assertion the VM does. - * @param assertion If zero, the assertion failed. - * @param msg The message that should be shown when the assertion fails. - */ -void vm_assert(int assertion, const char *msg); - -/** - * The hosts syscall implementation. - * @param process The process that calls the syscall. - * @param info Additional information for the syscall. Contains arguments and results. - */ -void vm_syscall(Process *process, CommandInfo *info); - -/** - * The hosts hardware IO implementation. - * @param process The process that wants to do IO. - * @param info Additional information for the HWIO. Contains arguments and results. - */ -void vm_hwio(Process *process, CommandInfo *info); - -#if defined(__cplusplus) -} -#endif \ No newline at end of file diff --git a/prototypes/syslinux.cfg b/prototypes/syslinux.cfg new file mode 100644 index 0000000..3d15e92 --- /dev/null +++ b/prototypes/syslinux.cfg @@ -0,0 +1,28 @@ +DEFAULT menu.c32 +prompt 0 + +MENU TITLE DasOS Boot Menu +MENU AUTOBOOT Starting DasOS in # seconds +TIMEOUT 300 +TOTALTIMEOUT 9000 + +LABEL das-os + MENU DEFAULT + MENU LABEL DasOS + KERNEL mboot.c32 + APPEND das-os.ker + +LABEL os-init + MENU DEFAULT + MENU LABEL OS Initialization Test + KERNEL mboot.c32 + APPEND os-init.ker + +LABEL video + MENU LABEL VBE Video Test + KERNEL mboot.c32 + APPEND video.ker + +LABEL poweroff + MENU LABEL Poweroff + KERNEL poweroff.c32 diff --git a/prototypes/video/Makefile b/prototypes/video/Makefile new file mode 100644 index 0000000..592594a --- /dev/null +++ b/prototypes/video/Makefile @@ -0,0 +1,13 @@ +## +# Builds the video test kernel +## + +include ../config.mk + +KERNEL = video.ker +LIBS += -lboot -lvideo -lchardev -lserial -lbase -lgcc + +all: builddir $(KERNEL) + +include ../common.mk +include ../kernel.mk \ No newline at end of file diff --git a/prototypes/video/multiboot.S b/prototypes/video/multiboot.S new file mode 100644 index 0000000..f5af759 --- /dev/null +++ b/prototypes/video/multiboot.S @@ -0,0 +1,28 @@ +.section multiboot + +#define MB_MAGIC 0x1badb002 +#define MB_FLAGS 0x07 +#define MB_CHECKSUM -(MB_MAGIC + MB_FLAGS) + +.align 4 + +// Offset Type Field Name Note +// 0 u32 magic required +// 4 u32 flags required +// 8 u32 checksum required +.int MB_MAGIC +.int MB_FLAGS +.int MB_CHECKSUM + +// 12 u32 header_addr if flags[16] is set +// 16 u32 load_addr if flags[16] is set +// 20 u32 load_end_addr if flags[16] is set +// 24 u32 bss_end_addr if flags[16] is set +// 28 u32 entry_addr if flags[16] is set +.int 0, 0, 0, 0, 0 + +// 32 u32 mode_type if flags[2] is set +// 36 u32 width if flags[2] is set +// 40 u32 height if flags[2] is set +// 44 u32 depth if flags[2] is set +.int 0, 640, 480, 32 \ No newline at end of file diff --git a/prototypes/video/src/init.cpp b/prototypes/video/src/init.cpp new file mode 100644 index 0000000..cf7e03f --- /dev/null +++ b/prototypes/video/src/init.cpp @@ -0,0 +1,25 @@ +#include + +#include + +#include +#include + +extern "C" void init(multiboot::Structure const & data) +{ + SerialPort serial(SERIAL_COM1); + serial << "Hi!\n"; + + VideoScreen video(*data.vbe.modeInfo); + for(uint32_t y = 0; y < video.height(); y++) + { + for(uint32_t x = 0; x < video.width(); x++) + { + video(x,y) = COLOR(255, 0, 0); + } + } + + serial << "w=" << video.width() << " h=" << video.height() << "\n"; + + while(true); +}