Finished refactoring.

This commit is contained in:
Felix Queißner 2016-06-26 18:48:36 +02:00
parent 52a16fc519
commit ba983c45b2
158 changed files with 106 additions and 28213 deletions

3
.gitignore vendored
View file

@ -29,3 +29,6 @@
*.exe *.exe
*.out *.out
*.app *.app
# Boot Images
*.img

View file

@ -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:

View file

@ -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.

View file

@ -1,20 +1,21 @@
# SuperVM # SuperVM SPU Mark I
SuperVM is a stack machine with a simple, but flexible command The *SPU Mark I* is a stack machine with a simple, but flexible command
set. 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 ## Purpose of this document
This document is meant to give a complete overview over the concepts and abstract 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 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 ## 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 registers operations take their operands from the stack and push their results to
it. 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. of 6 local variables per function call.
### Data Memory ### Data Memory
SuperVM also provides a memory model that allows storing persistent data that is *SPU Mark I* also provides a memory model that allows storing RAM data that is
accessed by different parts of the code. accessible by different parts of the code.
The data memory is byte accessible and can be written or read. 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 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 sparse memory with different sections, it could utilize a software-implemented paging
process or just be a flat chunk of memory. 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 Every pointer that accesses data memory (e.g. via `store` and `load`) contains the
address of a byte in memory, starting with zero. address of a byte in memory, starting with zero.
## Registers and Flags ## 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 registers that can be set with special instructions. The registers mainly
control stack access or control flow. control stack access or control flow.
@ -108,7 +106,7 @@ code pointer is equivalent to a jump operation.
## Instructions ## Instructions
An SuperVM instruction is composed of multiple components: An *SPU Mark I* instruction is composed of multiple components:
| Component | Range | Size | Function | | Component | Range | Size | Function |
|-------------|-------------------|------|------------------------------------------| |-------------|-------------------|------|------------------------------------------|
@ -278,7 +276,7 @@ as a value source for the first input value.
## Function Calls ## 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. functions conform to this convention.
To call a function, it is required that the return address is pushed to the stack. To call a function, it is required that the return address is pushed to the stack.
@ -289,7 +287,7 @@ After this, a jump is taken to the function address.
jmp @function ; Jumps to the function jmp @function ; Jumps to the function
returnPoint: 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 second next instruction which resembles the code above. This behaviour allows position
independent code: independent code:

View file

@ -1,37 +0,0 @@
##
# Build all projects
##
PROJECTS = $(shell ls --file-type --ignore=libs --ignore=kernels --ignore=include | grep / | sed "s|/||")
LIBS = $(filter lib%, $(PROJECTS))
KERNELS = $(filter-out lib%, $(PROJECTS))
all: $(KERNELS) boot.img
.PHONY: $(PROJECTS)
$(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 ::
run: boot.img
qemu-system-i386 boot.img -serial stdio

View file

@ -1,13 +0,0 @@
##
# 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

View file

@ -1,28 +0,0 @@
.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

View file

@ -1,8 +1,37 @@
##
# 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) .PHONY: $(PROJECTS)
$(PROJECTS): $(KERNELS): dirs $(LIBS)
make -C $@ $(ARGS) 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 ::
run: boot.img
qemu-system-i386 boot.img -serial stdio

View file

@ -1,70 +0,0 @@
AS=gcc
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
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))))
LIBS = $(LIBGCC) $(LIBSTD) $(LIBVM)
all: kernel-base.ker
kernel-base.ker: $(OBJS)
$(LD) -melf_i386 -Tlinker.ld -o kernel-base.ker $(addprefix obj/, $^) $(LIBS)
%.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/$@ $<
# Linux/Multiboot boot specific:
# -kernel bzImage use 'bzImage' as kernel image
# -append cmdline use 'cmdline' as kernel command line
# -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 \
-d cpu_reset,int \
-no-reboot \
-no-shutdown \
-serial stdio \
-initrd `pwd`/../supervm-asm/testcode.bin
insight:
objdump -d kernel-base.ker | c++filt | less
bnr: kernel-base.ker run
deploy: kernel-base.ker
cp kernel-base.ker /srv/tftp/kernel-base.ker

View file

@ -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. |

View file

@ -1,23 +0,0 @@
.section .text
.extern init
.extern compat_call_ctors
.extern compat_call_dtors
.global _start
_start:
mov $kernel_stack, %esp
push %ebx
call compat_call_ctors
call init
call compat_call_dtors
_stop:
cli
hlt
jmp _stop
.section .bss
.space 8192
kernel_stack:

View file

@ -1,50 +0,0 @@
#pragma once
#include <stddef.h>
#include <inttypes.h>
#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));
namespace ASM
{
static inline void sti()
{
__asm__ volatile ("sti");
}
static inline void cli()
{
__asm__ volatile ("cli");
}
static inline void outb(uint16_t port, uint8_t data)
{
asm volatile ("outb %0, %1" : : "a" (data), "Nd" (port));
}
static inline uint8_t inb(uint16_t port)
{
uint8_t data;
asm volatile ("inb %1, %0" : "=a" (data) : "d" (port));
return data;
}
static inline void invlpg(void* m)
{
/* Clobber memory to avoid optimizer re-ordering access before invlpg, which may cause nasty bugs. */
asm volatile ( "invlpg (%0)" : : "b"(m) : "memory" );
}
static inline void lidt(void *idt, size_t length)
{
struct {
uint16_t limit;
void* pointer;
} __attribute__((packed)) idtp = {
.limit = uint16_t(length * 8 - 1),
.pointer = idt,
};
asm volatile("lidt %0" : : "m" (idtp));
}
}

View file

@ -1,26 +0,0 @@
#pragma once
#include "errors.hpp"
#include "cpustate.hpp"
/**
* This class provides the blue screen of death.
* Discaimer: Color may vary!
*/
class BSOD
{
private:
BSOD() = delete;
public:
/**
* Dies with a simple message and error code display.
*/
static void die(Error code, const char *msg);
/**
* Dies with a simple message and error code display.
*/
static void die(Error code, const char *msg, CpuState *cpu);
};

View file

@ -1,13 +0,0 @@
#pragma once
#if defined(__cplusplus)
extern "C" {
#endif
void compat_call_ctors();
void compat_call_dtors();
#if defined(__cplusplus)
}
#endif

View file

@ -1,188 +0,0 @@
#pragma once
#include "screen.hpp"
#include "pointer.hpp"
struct FColor
{
FColor() : color(Color::White) { }
FColor(Color color) : color(color) { }
Color color;
};
struct BColor
{
BColor() : color(Color::Black) { }
BColor(Color color) : color(color) { }
Color color;
};
template<typename T>
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 console_tools
{
template<typename T>
auto hex(T value) { return NumericFormat<T>(value, 16); }
template<typename T>
auto dec(T value) { return NumericFormat<T>(value, 10); }
template<typename T>
auto oct(T value) { return NumericFormat<T>(value, 8); }
template<typename T>
auto bin(T value) { return NumericFormat<T>(value, 2); }
template<typename T>
auto nbase(T value, uint32_t base) { return NumericFormat<T>(value, base); }
template<typename T>
auto pad(NumericFormat<T> value, int32_t padding, char c = ' ') {
value.padding = padding;
return value;
}
template<typename T>
auto pad(T value, int32_t padding, char c = ' ') {
return pad(NumericFormat<T>(value), padding, c);
}
}
class Console
{
public:
static Console main;
private:
Screen * const screen;
int x;
int y;
Color fg, bg;
bool caretEnabled;
private:
/**
* Moves the hardware caret.
*/
void updateCaret();
/**
* 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:
Console(Screen *screen);
/**
* Clears the console.
*/
void clear();
/**
* Puts a character on the screen.
*/
void put(char c);
/**
* Inserts a line break and returns the cursor to the start.
*/
void newline();
/**
* Scrolls screen a line upwards
*/
void scroll();
/**
* Moves the cursor to the given position
*/
void setCursor(int x, int y);
/**
* Sets the visibility of the caret.
*/
void setCaretVisible(bool visible = true);
/**
* Sets the text foreground color
*/
void setForeground(Color c) {
this->fg = c;
}
/**
* Sets the text background color
*/
void setBackground(Color c) {
this->bg = c;
}
/**
* Sets the text colors.
*/
void setColors(Color bg, Color fg) {
this->fg = fg;
this->bg = bg;
}
inline Console & operator << (char c)
{
this->put(c);
return *this;
}
inline Console & operator << (const char *str)
{
while(*str) {
*this << *str++;
}
return *this;
}
inline Console & operator << (const FColor &color)
{
this->fg = color.color;
return *this;
}
inline Console & operator << (const BColor &color)
{
this->bg = color.color;
return *this;
}
Console & operator << (uint32_t value);
Console & operator << (int32_t value);
Console & operator << (void *value);
Console & operator << (bool value);
template<typename T>
Console & operator << (pointer<T> ptr);
template<typename T>
Console & operator << (const NumericFormat<T> &fmt);
};

View file

@ -1,25 +0,0 @@
#pragma once
#include <inttypes.h>
struct CpuState
{
uint32_t eax;
uint32_t ebx;
uint32_t ecx;
uint32_t edx;
uint32_t esi;
uint32_t edi;
uint32_t ebp;
uint32_t interrupt;
uint32_t error;
uint32_t eip;
uint32_t cs;
uint32_t eflags;
uint32_t esp;
uint32_t ss;
} __attribute__((packed));
static_assert(sizeof(CpuState) == 56, "CpuState must be 56 bytes large.");

View file

@ -1,12 +0,0 @@
#pragma once
namespace driver
{
class Driver
{
protected:
Driver() = default;
public:
virtual void install() = 0;
};
}

View file

@ -1,18 +0,0 @@
#pragma once
#include "driver.hpp"
#include "cpustate.hpp"
namespace driver
{
class Keyboard :
public Driver
{
private:
static void dispatchIRQ(CpuState *&cpu);
public:
Keyboard();
void install() override;
};
}

View file

@ -1,20 +0,0 @@
#pragma once
#include <inttypes.h>
#include "driver.hpp"
namespace driver
{
class Timer :
public Driver
{
public:
Timer();
void install() override;
void reset();
uint32_t count();
};
}

View file

@ -1,36 +0,0 @@
#pragma once
#include <inttypes.h>
namespace elf
{
static const uint32_t MAGIC = 0x464C457F;
struct Header {
uint32_t magic;
uint32_t version;
uint64_t reserved;
uint64_t version2;
uint32_t entry;
uint32_t ph_offset;
uint32_t sh_offset;
uint32_t flags;
uint16_t header_size;
uint16_t ph_entry_size;
uint16_t ph_entry_count;
uint16_t sh_entry_size;
uint16_t sh_entry_count;
uint16_t sh_str_table_index;
} __attribute__((packed));
struct ProgramHeader {
uint32_t type;
uint32_t offset;
uint32_t virt_addr;
uint32_t phys_addr;
uint32_t file_size;
uint32_t mem_size;
uint32_t flags;
uint32_t alignment;
} __attribute__((packed));
}

View file

@ -1,18 +0,0 @@
#pragma once
#define ENUM_CLASS_OPERATORS(type) static inline type operator | (type lhs, type rhs) { \
return static_cast<type>(static_cast<uint32_t>(lhs) | static_cast<uint32_t>(rhs)); \
} \
static inline type operator & (type lhs, type rhs) { \
return static_cast<type>(static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs)); \
} \
static inline bool operator * (type lhs, type rhs) { \
return (static_cast<uint32_t>(lhs) & static_cast<uint32_t>(rhs)) != 0; \
} \
static inline type & operator |=(type & lhs, type rhs) { \
reinterpret_cast<uint32_t&>(lhs) |= static_cast<uint32_t>(rhs); \
return lhs; \
}

View file

@ -1,8 +0,0 @@
#pragma once
enum class Error
{
#define ERROR(num, ident, desc) ident = num,
#include "errors.lst"
#undef ERROR
};

View file

@ -1,10 +0,0 @@
#pragma once
#include "enums.hpp"
enum class Exception
{
#define EXCEPTION(num, shorthand, ident, desc, type) ident = num,
#include "exceptions.lst"
#undef EXCEPTION
};

View file

@ -1,118 +0,0 @@
#pragma once
#include <inttypes.h>
#include "enums.hpp"
enum class SegmentAccess : uint8_t
{
None = 0,
Accessed = (1<<0),
Readable = (1<<1),
Writeable = (1<<1),
Direction = (1<<2),
Conforming = (1<<2),
Executable = (1<<3),
Segment = (1<<4),
Ring0 = 0,
Ring1 = (1<<5),
Ring2 = (1<<6),
Ring3 = (1<<5) | (1<<6),
Present = (1<<7),
};
ENUM_CLASS_OPERATORS(SegmentAccess)
enum class SegmentFlags : uint8_t
{
None = 0,
Available = (1<<0),
LongMode = (1<<1),
Use32Bit = (1<<2),
Use4KSize = (1<<3),
};
ENUM_CLASS_OPERATORS(SegmentFlags)
struct SegmentDescriptor
{
uint16_t limit0;
uint16_t base0;
uint8_t base1;
SegmentAccess access;
uint8_t limit1 : 4;
uint8_t flags0 : 4;
uint8_t base2;
SegmentDescriptor() :
limit0(0), base0(0), base1(0),
access(SegmentAccess::None),
limit1(0), flags0(0), base2(0)
{
}
SegmentDescriptor(
uint32_t base,
uint32_t length,
SegmentAccess access,
SegmentFlags flags) :
access(access)
{
this->setBase(base);
this->setFlags(flags);
if(this->flags() * SegmentFlags::Use4KSize) {
this->setLimit(length >> 12);
} else {
this->setLimit(length);
}
}
void setFlags(SegmentFlags flags)
{
this->flags0 = static_cast<uint8_t>(flags) & 0x0F;
}
SegmentFlags flags() const
{
return static_cast<SegmentFlags>(this->flags0);
}
uint32_t limit() const
{
return this->limit0 | (this->limit1 << 16);
}
void setLimit(uint32_t value)
{
this->limit0 = (value & 0x0FFFF) >> 0;
this->limit1 = (value & 0xFFFFF) >> 16;
}
uint32_t base() const
{
return this->base0 | (this->base1 << 16) | (this->base2 << 24);
}
void setBase(uint32_t value)
{
this->base0 = (value & 0x0000FFFF) >> 0;
this->base1 = (value & 0x00FF0000) >> 16;
this->base2 = (value & 0xFF000000) >> 24;
}
} __attribute__((packed));
static_assert(sizeof(SegmentDescriptor) == 8, "SegmentDescriptor must be 8 bytes large.");
class GDT
{
public:
static const uint32_t length = 8;
private:
static SegmentDescriptor descriptors[length];
GDT() = delete;
public:
static void initialize();
static SegmentDescriptor & descriptor(uint32_t index);
};

View file

@ -1,92 +0,0 @@
#pragma once
#include <inttypes.h>
#include "enums.hpp"
#include "cpustate.hpp"
enum class InterruptFlags : uint8_t
{
None = 0x00,
Interrupt = 0x06,
TrapGate = 0x07,
TaskGate = 0x05,
Use32Bit = 0x08,
Ring0 = 0x00,
Ring1 = 0x20,
Ring2 = 0x40,
Ring3 = 0x60,
Present = 0x80,
};
ENUM_CLASS_OPERATORS(InterruptFlags)
struct InterruptDescriptor
{
uint16_t offset0;
uint16_t selector;
uint8_t zero;
InterruptFlags flags;
uint16_t offset1;
InterruptDescriptor();
InterruptDescriptor(uint32_t offset, uint32_t selector, InterruptFlags flags);
uint32_t offset() const;
void setOffset(uint32_t offset);
} __attribute__((packed));
static_assert(sizeof(InterruptDescriptor) == 8, "InterruptDescriptor must be 8 byte large.");
/**
* An interrupt that specifies
* a handler and if the interrupt is
* enabled. Any non-enabled interrupt
* causes a BSOD.
*/
class Interrupt
{
friend class IDT;
using Handler = void (*)(CpuState * & cpu);
private:
bool isEnabled;
Handler handler;
public:
Interrupt();
explicit Interrupt(Handler handler);
};
class IDT
{
public:
static const uint32_t length = 256;
static Interrupt interrupts[length];
private:
static InterruptDescriptor descriptors[length];
IDT() = delete;
static CpuState * dispatch(CpuState *cpu);
static void setupPIC();
public:
/**
* Accessor to an interrupt handler.
*/
static Interrupt & interrupt(uint32_t index);
/**
* Gets an interrupt descriptor
*/
static InterruptDescriptor & descriptor(uint32_t idx);
/**
* Initializes the interrupt table and sets up the PIC.
*/
static void initialize();
};

View file

@ -1,7 +0,0 @@
#pragma once
#include "asm.hpp"
// Import functions into global namespace
using ASM::inb;
using ASM::outb;

View file

@ -1,168 +0,0 @@
#pragma once
#include <inttypes.h>
#include "pointer.hpp"
#define MB_MEMSIZE (1<<0)
#define MB_BOOTDEVICE (1<<1)
#define MB_COMMANDLINE (1<<2)
#define MB_MODULES (1<<3)
#define MB_SYMS_AOUT (1<<4)
#define MB_SYMS_ELF (1<<5)
#define MB_MEMORYMAP (1<<6)
#define MB_DRIVES (1<<7)
#define MB_CONFIG_TABLE (1<<8)
#define MB_BOOTLOADER_NAME (1<<9)
#define MB_APS_TABLE (1<<10)
#define MB_VBE (1<<11)
#define MB_ASSERT_SIZE(type, len) static_assert(sizeof(type) == len, "multiboot::" #type " must be " #len " bytes large.")
namespace multiboot
{
template<typename T>
class mbarray
{
public:
const uint32_t length;
private:
T *data;
mbarray() = delete;
public:
T const & operator [](size_t idx) const {
return this->data[idx];
}
const T *begin() const {
return &data[0];
}
const T *end() const {
return &data[length];
}
} __attribute__((packed));
// Make sure the size is not dependend on the template parameter
MB_ASSERT_SIZE(mbarray<uint8_t>, 8);
MB_ASSERT_SIZE(mbarray<uint32_t>, 8);
struct MemoryMap
{
uint32_t entry_size;
uint64_t base;
uint64_t length;
uint32_t type;
bool isFree() const {
return this->type == 1;
}
} __attribute__((packed));
MB_ASSERT_SIZE(MemoryMap, 24);
struct Module
{
physical_t start;
physical_t end;
const char * name;
uint32_t reserved;
uint32_t size() const {
return this->end.numeric() - this->start.numeric();
}
} __attribute__((packed));
MB_ASSERT_SIZE(Module, 16);
struct Drive
{
uint32_t size;
uint8_t number;
uint8_t mode;
uint16_t cylinders;
uint8_t heads;
uint8_t sectors;
// 0x10 size-0x10 drive_ports I/O-Ports, die von diesem Gerät benutzt werden
// uint16_t ports[0];
/**
* Gets the number of ports used by this drive.
*/
uint32_t portCount() const {
return (this->size - 0x10) / sizeof(uint16_t);
}
/**
* Gets the given port.
* @return The port #idx or 0 if out of range.
*/
uint16_t port(size_t idx) const {
uint16_t const * ports = reinterpret_cast<uint16_t const *>(reinterpret_cast<uint8_t const *>(this) + 0x10);
if(idx >= this->portCount()) {
return 0;
}
return ports[idx];
}
} __attribute__((packed));
static_assert(sizeof(Drive) >= 10, "multiboot::Drive must be at least 12 bytes large.");
struct APMTable
{
uint16_t version;
uint16_t cseg;
uint32_t offset;
uint16_t cseg_16;
uint16_t dseg;
uint16_t flags;
uint16_t cseg_len;
uint16_t cseg_16_len;
uint16_t dseg_len;
} __attribute__((packed));
MB_ASSERT_SIZE(APMTable, 20);
struct Structure
{
uint32_t flags;
physical_t memLower;
physical_t memUpper;
uint32_t bootDevice;
const char * commandline;
mbarray<Module> modules;
union {
struct {
uint32_t tabsize;
uint32_t strsize;
uint32_t addr;
uint32_t reserved;
} __attribute__((packed)) symsAssemblerOut;
struct {
uint32_t num;
uint32_t size;
uintptr_t addr;
uintptr_t shndx;
} __attribute__((packed)) symsELF;
};
mbarray<MemoryMap> memoryMaps;
mbarray<Drive> drives;
physical_t configTable;
const char * bootLoaderName;
const APMTable * apmTable;
struct {
uint32_t ontrolInfo;
uint32_t modeInfo;
uint16_t mode;
uint16_t interfaceSegment;
uint16_t interfaceOffset;
uint16_t interfaceLength;
} __attribute__((packed)) vbe;
} __attribute__((packed));
MB_ASSERT_SIZE(Structure, 88);
}

View file

@ -1,49 +0,0 @@
#pragma once
#include <inttypes.h>
#include <stddef.h>
class Numeric
{
private:
Numeric() = delete;
public:
/**
* Converts an unsigned number to a string.
* @param buffer The target buffer where the string should be stored.
* @param length The length of the buffer.
* @param number The number that should be converted.
* @param radix The numeric base for the printed number.
* @return The length of the converted strings.
*/
static size_t toString(
char *buffer,
size_t length,
uint32_t number,
uint32_t radix = 10);
static size_t toString(
char *buffer,
size_t length,
uint64_t number,
uint32_t radix = 10);
/**
* Converts a signed number to a string.
* @param buffer The target buffer where the string should be stored.
* @param length The length of the buffer.
* @param number The number that should be converted.
* @param radix The numeric base for the printed number.
* @return The length of the converted strings.
*/
static size_t toString(
char *buffer,
size_t length,
int32_t number,
uint32_t radix = 10);
static size_t toString(
char *buffer,
size_t length,
int64_t number,
uint32_t radix = 10);
};

View file

@ -1,18 +0,0 @@
#pragma once
#include "pagetable.hpp"
class PageDirectory
{
private:
uint32_t tables[1024];
public:
PageDirectory();
~PageDirectory();
uint32_t & table(uint32_t index) {
return this->tables[index];
}
};
static_assert(sizeof(PageDirectory) == 4096, "PageDirectory must be 4096 bytes large");

View file

@ -1,17 +0,0 @@
#pragma once
class PageTable
{
private:
uint32_t pages[1024];
public:
PageTable();
~PageTable();
uint32_t & pageDescriptor(uint32_t pageIndex)
{
return this->pages[pageIndex];
}
};
static_assert(sizeof(PageTable) == 4096, "PageDirectory must be 4096 bytes large");

View file

@ -1,28 +0,0 @@
#pragma once
#include <inttypes.h>
class PIC
{
private:
uint16_t port;
public:
PIC(uint16_t port);
/**
* Sends an initialization code to the PIC.s
*/
void initialize(uint16_t irqBase, uint16_t icw3, uint16_t icw4);
/**
* Disables all interrupts where the corresponding bit in mask is set.
*/
void maskInterrupts(uint8_t mask);
/**
* Sends an end-of-interrupt to the PIC.
*/
void sendEndOfInterrupt();
};
extern PIC masterPIC, slavePIC;

View file

@ -1,38 +0,0 @@
#pragma once
#include "pointer.hpp"
/**
* Physical memory management tool.
*/
class PMM
{
private:
PMM() = delete;
public:
/**
* Marks a page as free by external memory management.
*/
static void markFree(physical_t page);
/**
* Marks a page as used by external memory management.
*/
static void markUsed(physical_t page);
/**
* Allocates a single page.
* @remarks This method will either return a valid value or die with a BSOD if out of memory.
*/
static physical_t alloc();
/**
* Frees a given page by pointer.
*/
static void free(physical_t page);
/**
* Returns the free memory.
*/
static uint32_t getFreeMemory();
};

View file

@ -1,116 +0,0 @@
#pragma once
#include <inttypes.h>
/**
* Provides a strong pointer wrapper which can be used to address
* different memory types (physical, virtual, ...) and preventing
* a wrong assignment.
* @remarks The pointer size is fixed to 32 bits.
*/
template<typename TIdent>
class pointer
{
public:
/**
* A value that declares the pointer invalid.
*/
static pointer invalid;
private:
uint32_t ptr;
public:
/**
* Creates the pointer by giving a raw pointer.
*/
explicit pointer(void *ptr) :
ptr(reinterpret_cast<uint32_t>(ptr))
{
}
/**
* Creates the pointer by giving an integer value.
*/
explicit pointer(uint32_t value) :
ptr(value)
{
}
pointer(const pointer &) = default;
pointer(pointer &&) = default;
~pointer() = default;
pointer & operator = (const pointer & other) {
this->ptr = other.ptr;
return *this;
}
/**
* Returns the numeric integer value of the pointer.
*/
uint32_t numeric() const {
return this->ptr;
}
/**
* Returns the pointer as a raw pointer.
*/
void * data() const {
return reinterpret_cast<void*>(this->ptr);
}
/**
* Returns the pointer as a raw typed pointer.
*/
template<typename T>
T * data () const {
return reinterpret_cast<T*>(this->ptr);
}
/**
* Allow explicit conversion to a raw pointer.
*/
explicit operator void * () const {
return this->data();
}
/**
* Returns an aligned version of the pointer.
* Rounds the pointer to the memory bottom.
*/
pointer alignLower(uint32_t alignment) {
if(alignment == 0) return pointer::invalid;
return pointer(this->ptr & ~(alignment - 1));
}
/**
* Returns an aligned version of the pointer.
* Rounds the pointer to the memory top.
*/
pointer alignUpper(uint32_t alignment) {
if(alignment == 0) return pointer::invalid;
return pointer((this->ptr + (alignment - 1)) & ~(alignment - 1));
}
} __attribute__((packed));
template <class T>
pointer<T> pointer<T>::invalid(uint32_t(0xFFFFFFFF));
struct physical_t_ident;
struct virtual_t_ident;
// Add different memory pointer types here....
/**
* A pointer pointing to physical memory.
*/
using physical_t = pointer<physical_t_ident>;
/**
* A pointer pointing to virtual memory.
*/
using virtual_t = pointer<virtual_t_ident>;
static_assert(sizeof(physical_t) == 4, "pointer is not 4 byte wide.");

View file

@ -1,64 +0,0 @@
#pragma once
#include <inttypes.h>
enum class Color : uint8_t
{
Black = 0,
Blue = 1,
Green = 2,
Cyan = 3,
Red = 4,
Magenta = 5,
Brown = 6,
LightGray = 7,
Gray = 8,
LightBlue = 9,
LightGreen = 10,
LightCyan = 11,
LightRed = 12,
LightMagenta = 13,
Yellow = 14,
White = 15,
};
using ColorInteger = uint8_t;
struct ScreenChar
{
char c;
struct {
ColorInteger fg : 4;
ColorInteger bg : 4;
};
};
class Screen
{
private:
static ScreenChar outOfScreen;
public:
static Screen main;
private:
ScreenChar * const buffer;
public:
const int width;
const int height;
public:
Screen(ScreenChar *buffer, int width, int height);
void clear();
ScreenChar & operator ()(int x, int y) {
if(x < 0 || y < 0 || x >= this->width || y >= this->height) {
return Screen::outOfScreen;
}
return this->buffer[this->width * y + x];
}
ScreenChar const & operator ()(int x, int y) const {
if(x < 0 || y < 0 || x >= this->width || y >= this->height) {
return Screen::outOfScreen;
}
return this->buffer[this->width * y + x];
}
};

View file

@ -1,62 +0,0 @@
#pragma once
#include "pmm.hpp"
#include "enums.hpp"
#include "pagedirectory.hpp"
enum class VMMFlags
{
None = 0,
Present = (1<<0),
Writable = (1<<1),
UserSpace = (1<<2),
SystemAllocated = (1<<3),
};
ENUM_CLASS_OPERATORS(VMMFlags)
class VMMContext
{
friend class VMM;
private:
PageDirectory *directory;
/**
* Gets the uint32_t that describes the given virtual address
*/
uint32_t & getPageDescriptor(virtual_t virt);
public:
VMMContext();
~VMMContext();
/**
* Maps an arbitrary page into the virtual memory.
*/
void provide(virtual_t virt, VMMFlags flags);
/**
* Maps a given page into the virtual memory.
*/
void map(virtual_t virt, physical_t phys, VMMFlags flags);
/**
* Unmaps a given page from the virtual memory.
*/
void unmap(virtual_t virt);
};
class VMM
{
private:
VMM() = delete;
public:
/**
* Enables paging
*/
static void enable();
/**
* Sets the given context as the current context.
*/
static void activate(VMMContext & context);
};

View file

@ -1,319 +0,0 @@
#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 "asm.hpp"
#include "driver/timer.hpp"
#include "driver/keyboard.hpp"
#include <inttypes.h>
#include <new>
#include <string.h>
namespace vm {
#include <vm.h>
}
using namespace multiboot;
using namespace console_tools;
struct dummy;
// Symbols generated by linker, no useful content in there...
extern dummy kernelStartMarker;
extern dummy kernelEndMarker;
driver::Timer timer;
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<elf::Header>();
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 strcpy(char *dst, const char *src)
{
while((*dst++ = *src++));
}
static void initializePMM(Structure const & data)
{
for(auto &mmap : data.memoryMaps) {
if(mmap.length == 0) {
continue;
}
if(mmap.isFree() == false) {
continue;
}
//Console::main
//<< "mmap: "
//<< "start: " << hex(mmap.base) << ", length: " << hex(mmap.length)
//<< ", " << mmap.entry_size
//<< ", " << sizeof(mmap)
//<< "\n";
if(mmap.base > 0xFFFFFFFF) {
//Console::main << "mmap out of 4 gigabyte range." << "\n";
continue;
}
if(mmap.isFree()) {
// Mark all free memory free...
physical_t lower = physical_t(mmap.base).alignUpper(4096);
physical_t upper = physical_t(mmap.base + mmap.length).alignLower(4096);
uint32_t ptr = lower.numeric();
while (ptr < upper.numeric()) {
PMM::markFree(physical_t(ptr));
ptr += 0x1000;
}
}
}
// Mark all memory used by the kernel used...
physical_t lower = physical_t(&kernelStartMarker).alignLower(4096);
physical_t upper = physical_t(&kernelEndMarker).alignUpper(4096);
uint32_t ptr = lower.numeric();
while (ptr < upper.numeric()) {
PMM::markUsed(physical_t(ptr));
ptr += 0x1000;
}
// nullptr is not valid.
PMM::markUsed(physical_t(nullptr));
// Mark the video memory as used.
PMM::markUsed(physical_t(0xB8000));
}
extern "C" void init(Structure const & data)
{
Console::main
<< "Hello World!\n"
<< FColor(Color::Yellow) << "Hello color!" << FColor() << "\n"
<< BColor(Color::Blue) << "Hello blue!" << BColor() << "\n"
<< "Hello default color.\n";
GDT::initialize();
Console::main
<< "bootloader name: " << data.bootLoaderName << "\n"
<< "command line: " << data.commandline << "\n"
<< "count of modules: " << data.modules.length << "\n"
<< "count of mmaps: " << data.memoryMaps.length << "\n";
initializePMM(data);
auto freeMemory = PMM::getFreeMemory();
Console::main
<< "Free: "
<< (freeMemory >> 20) << "MB, "
<< (freeMemory >> 10) << "KB, "
<< (freeMemory >> 0) << "B, "
<< (freeMemory >> 12) << "Pages\n";
IDT::initialize();
Console::main << "Interrupts set up.\n";
Console::main << "Creating VMM Context...\n";
kernelContext = new (PMM::alloc().data()) VMMContext();
Console::main << "Mapping memory...\n";
for(uint32_t addr = 0; addr < 4096 * 1024; addr += 0x1000) {
kernelContext->map(
virtual_t(addr),
physical_t(addr),
VMMFlags::Writable | VMMFlags::UserSpace);
}
kernelContext->map(
virtual_t(kernelContext),
physical_t(kernelContext),
VMMFlags::Writable);
Console::main << "Active Context...\n";
VMM::activate(*kernelContext);
Console::main << "Active Paging...\n";
VMM::enable();
Console::main << "Virtual Memory Management ready.\n";
timer.install();
keyboardDriver.install();
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<elf::Header>());
// run_program0(data.modules[0]);
vm::Module module = {
.code = reinterpret_cast<vm::Instruction*>(data.modules[0].start.data()),
.length = data.modules[0].size() / sizeof(vm::Instruction),
};
Console::main << "Loaded instructions: " << module.length << "\n";
uint8_t page0[64];
uint8_t page1[64];
strcpy((char*)page0, "Hallo Welt!\nDies ist die erste Ausgabe durch die VM.");
uint8_t *pages[2];
pages[0] = page0;
pages[1] = page1;
vm::VirtualMemoryMap mmap = {
.pageSize = 64,
.length = 2,
.pages = pages,
};
vm::Process process = {
.module = &module,
.tag = (void*)1,
.codePointer = 0,
.stackPointer = 0,
.basePointer = 0,
.flags = 0,
.stack = { 0 },
.mmap = mmap,
};
auto *p = &process;
while(vm::vm_step_process(p) && p->tag) {
//Console::main << "?";
// dump_proc(p);
}
}
while(true);
}
static_assert(sizeof(void*) == 4, "Target platform is not 32 bit.");
namespace vm
{
extern "C" void vm_assert(int assertion, const char *msg)
{
if(assertion != 0)
return;
BSOD::die(Error::VMError, msg);
}
extern "C" void vm_syscall(Process *p, CommandInfo *info)
{
switch(info->additional)
{
case 0: // EXIT
p->tag = NULL;
break;
case 1:
Console::main << (char)info->input0;
break;
case 2:
Console::main << info->input0;
break;
default:
Console::main << "[SYSCALL " << info->additional << "]";
break;
}
}
extern "C" void vm_hwio(Process *p, CommandInfo *info)
{
BSOD::die(Error::VMError, "hwio not implemented yet.");
}
}

View file

@ -1,58 +0,0 @@
.macro isr_stub nr
.global isr_\nr
isr_\nr:
pushl $0
pushl $\nr
jmp isr_handler
.endm
.macro isr_stub_with_err nr
.global isr_\nr
isr_\nr:
pushl $\nr
jmp isr_handler
.endm
#define ISR(num) isr_stub num
#define ISR_ERR(num) isr_stub_with_err num
#include "interrupts.lst"
#undef ISR
#undef ISR_ERR
#if !defined(IDT_DISPATCH)
#error "IDT_DISPATCH must be defined!"
#endif
.extern IDT_DISPATCH
isr_handler:
// Store CPU State
push %ebp
push %edi
push %esi
push %edx
push %ecx
push %ebx
push %eax
// Calls interrupt handler with CPU state as argument
push %esp
call IDT_DISPATCH
// add $4, %esp
mov %eax, %esp
// Restore CPU State
pop %eax
pop %ebx
pop %ecx
pop %edx
pop %esi
pop %edi
pop %ebp
// Remove error code and interrupt number
add $8, %esp
iret

View file

@ -1,37 +0,0 @@
ENTRY(_start)
OUTPUT_FORMAT(elf32-i386)
OUTPUT_ARCH(i386:i386)
SECTIONS
{
. = 0x100000;
kernelStartMarker = .;
.text : {
*(multiboot)
*(.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 the end of the kernel to the page size */
. = ALIGN(4096);
kernelEndMarker = .;
}

View file

@ -1,7 +0,0 @@
ERROR(0, Success, Nothing went wrong. This should never encounter.)
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.)
ERROR(6, VMError, The virtual machine has failed.)

View file

@ -1,32 +0,0 @@
EXCEPTION(0x00, DE, DiviceByZero, Divide by Zero, Fault)
EXCEPTION(0x01, DB, Debug, Debug, Fault | Trap)
EXCEPTION(0x02, NMI, NonMaskableInterrupt, Non Maskable Interrupt, None)
EXCEPTION(0x03, BP, Breakpoint, Breakpoint, Trap)
EXCEPTION(0x04, OF, Overflow, Overflow, Trap)
EXCEPTION(0x05, BR, BoundRange, Bound Range, Fault)
EXCEPTION(0x06, UD, InvalidOpcode, Invalid Opcode, Fault)
EXCEPTION(0x07, NM, DeviceNotAvailable, Device Not Available, Fault)
EXCEPTION(0x08, DF, DoubleFault, Double Fault, Abort)
EXCEPTION(0x09, CSO, CoprocessorSegmentOverrun, Coprocessor Segment Overrun, None)
EXCEPTION(0x0a, TS, InvalidTSS, Invalid TSS, Fault)
EXCEPTION(0x0b, NP, SegmentNotPresent, Segment not Present, Fault)
EXCEPTION(0x0c, SS, StackFault, Stack Fault, Fault)
EXCEPTION(0x0d, GP, GeneralProtectionFault, General Protection, Fault)
EXCEPTION(0x0e, PF, PageFault, Page Fault, Fault)
EXCEPTION(0x0f, XX, Reserved0, Reserved, None)
EXCEPTION(0x10, MF, x87FloatingPoint, x87 Floating Point, Fault)
EXCEPTION(0x11, AC, AlignmentCheck, Alignment Check, Fault)
EXCEPTION(0x12, MC, MachineCheck, Machine Check, Abort)
EXCEPTION(0x13, XF, SIMDFloatingPoint, SIMD Floating Point, Fault)
EXCEPTION(0x14, XX, Reserved1, Reserved, None)
EXCEPTION(0x15, XX, Reserved2, Reserved, None)
EXCEPTION(0x16, XX, Reserved3, Reserved, None)
EXCEPTION(0x17, XX, Reserved4, Reserved, None)
EXCEPTION(0x18, XX, Reserved5, Reserved, None)
EXCEPTION(0x19, XX, Reserved6, Reserved, None)
EXCEPTION(0x1a, XX, Reserved7, Reserved, None)
EXCEPTION(0x1b, XX, Reserved8, Reserved, None)
EXCEPTION(0x1c, XX, Reserved9, Reserved, None)
EXCEPTION(0x1d, XX, Reserved10, Reserved, None)
EXCEPTION(0x1e, SX, SecuritySensitive, Security-sensitive event in Host, Fault)
EXCEPTION(0x1f, XX, Reserved11, Reserved, None)

View file

@ -1,257 +0,0 @@
ISR(0)
ISR(1)
ISR(2)
ISR(3)
ISR(4)
ISR(5)
ISR(6)
ISR(7)
ISR_ERR(8)
ISR(9)
ISR_ERR(10)
ISR_ERR(11)
ISR_ERR(12)
ISR_ERR(13)
ISR_ERR(14)
ISR(15)
ISR(16)
ISR_ERR(17)
ISR(18)
ISR(19)
ISR(20)
ISR(21)
ISR(22)
ISR(23)
ISR(24)
ISR(25)
ISR(26)
ISR(27)
ISR(28)
ISR(29)
ISR(30)
ISR(31)
ISR(32)
ISR(33)
ISR(34)
ISR(35)
ISR(36)
ISR(37)
ISR(38)
ISR(39)
ISR(40)
ISR(41)
ISR(42)
ISR(43)
ISR(44)
ISR(45)
ISR(46)
ISR(47)
ISR(48)
ISR(49)
ISR(50)
ISR(51)
ISR(52)
ISR(53)
ISR(54)
ISR(55)
ISR(56)
ISR(57)
ISR(58)
ISR(59)
ISR(60)
ISR(61)
ISR(62)
ISR(63)
ISR(64)
ISR(65)
ISR(66)
ISR(67)
ISR(68)
ISR(69)
ISR(70)
ISR(71)
ISR(72)
ISR(73)
ISR(74)
ISR(75)
ISR(76)
ISR(77)
ISR(78)
ISR(79)
ISR(80)
ISR(81)
ISR(82)
ISR(83)
ISR(84)
ISR(85)
ISR(86)
ISR(87)
ISR(88)
ISR(89)
ISR(90)
ISR(91)
ISR(92)
ISR(93)
ISR(94)
ISR(95)
ISR(96)
ISR(97)
ISR(98)
ISR(99)
ISR(100)
ISR(101)
ISR(102)
ISR(103)
ISR(104)
ISR(105)
ISR(106)
ISR(107)
ISR(108)
ISR(109)
ISR(110)
ISR(111)
ISR(112)
ISR(113)
ISR(114)
ISR(115)
ISR(116)
ISR(117)
ISR(118)
ISR(119)
ISR(120)
ISR(121)
ISR(122)
ISR(123)
ISR(124)
ISR(125)
ISR(126)
ISR(127)
ISR(128)
ISR(129)
ISR(130)
ISR(131)
ISR(132)
ISR(133)
ISR(134)
ISR(135)
ISR(136)
ISR(137)
ISR(138)
ISR(139)
ISR(140)
ISR(141)
ISR(142)
ISR(143)
ISR(144)
ISR(145)
ISR(146)
ISR(147)
ISR(148)
ISR(149)
ISR(150)
ISR(151)
ISR(152)
ISR(153)
ISR(154)
ISR(155)
ISR(156)
ISR(157)
ISR(158)
ISR(159)
ISR(160)
ISR(161)
ISR(162)
ISR(163)
ISR(164)
ISR(165)
ISR(166)
ISR(167)
ISR(168)
ISR(169)
ISR(170)
ISR(171)
ISR(172)
ISR(173)
ISR(174)
ISR(175)
ISR(176)
ISR(177)
ISR(178)
ISR(179)
ISR(180)
ISR(181)
ISR(182)
ISR(183)
ISR(184)
ISR(185)
ISR(186)
ISR(187)
ISR(188)
ISR(189)
ISR(190)
ISR(191)
ISR(192)
ISR(193)
ISR(194)
ISR(195)
ISR(196)
ISR(197)
ISR(198)
ISR(199)
ISR(200)
ISR(201)
ISR(202)
ISR(203)
ISR(204)
ISR(205)
ISR(206)
ISR(207)
ISR(208)
ISR(209)
ISR(210)
ISR(211)
ISR(212)
ISR(213)
ISR(214)
ISR(215)
ISR(216)
ISR(217)
ISR(218)
ISR(219)
ISR(220)
ISR(221)
ISR(222)
ISR(223)
ISR(224)
ISR(225)
ISR(226)
ISR(227)
ISR(228)
ISR(229)
ISR(230)
ISR(231)
ISR(232)
ISR(233)
ISR(234)
ISR(235)
ISR(236)
ISR(237)
ISR(238)
ISR(239)
ISR(240)
ISR(241)
ISR(242)
ISR(243)
ISR(244)
ISR(245)
ISR(246)
ISR(247)
ISR(248)
ISR(249)
ISR(250)
ISR(251)
ISR(252)
ISR(253)
ISR(254)
ISR(255)

View file

@ -1,16 +0,0 @@
IRQ(0, Timer, Programmable Interval Timer)
IRQ(1, PrimaryPS2, First PS/2 port / Keyboard Controller)
IRQ(2, SecondaryPIC, Connection to secondary PIC)
IRQ(3, RS232Even, RS-232 Port 2/4)
IRQ(4, RS232Odd, RS-232 Port 1/3)
IRQ(5, SecondaryLPT, LPT 2)
IRQ(6, Floppy, Floppy Disk Controller)
IRQ(7, PrimaryLPT, LPT 1 / Spurious Interrupt)
IRQ(8, RTC, RTC (CMOS Real Time Clock))
IRQ(9, Free, Free)
IRQ(10, FourthIDE, Fourth ATA/ATAPI/(E)IDE)
IRQ(11, ThirdIDE, Third ATA/ATAPI/(E)IDE)
IRQ(12, SecondaryPS2, Second PS/2 Port / Mouse Controller)
IRQ(13, FPU, FPU)
IRQ(14, PrimaryIDE, Primary ATA/ATAPI/(E)IDE)
IRQ(15, SecondaryIDE, Secundary ATA/ATAPI/(E)IDE / Spurious Interrupt)

View file

@ -1,10 +0,0 @@
[0-1] GB Kernel Space
[1-4] GB User Space
Entry Point: 0x40000000
Stack Start: 0xFFFFFFFF

View file

@ -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

View file

@ -1,83 +0,0 @@
#include "bsod.hpp"
#include "console.hpp"
#include "exceptions.hpp"
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"
#undef EXCEPTION
default: return "Unknown Exception";
}
}
if(interrupt >= 0x20 && interrupt <= 0x2F) {
switch(interrupt - 0x20) {
#define IRQ(num, ident, desc) case num: return #desc;
#include "irqs.lst"
#undef IRQ
}
}
return "Unknown Interrupt";
};
void BSOD::die(Error code, const char *msg)
{
BSOD::die(code, msg, nullptr);
}
/**
* Dies with a simple message and error code display.
*/
void BSOD::die(Error code, const char *msg, CpuState *cpu)
{
using namespace console_tools;
FColor Y(Color::Yellow);
FColor W(Color::White);
asm volatile ("cli");
uint32_t cr0 = 0xBADEAFFE, cr1 = 0xBADEAFFE, cr2 = 0xBADEAFFE, cr3 = 0xBADEAFFE;
asm volatile("mov %%cr0, %0" : "=r" (cr0));
// asm volatile("mov %%cr1, %0" : "=r" (cr1));
asm volatile("mov %%cr2, %0" : "=r" (cr2));
asm volatile("mov %%cr3, %0" : "=r" (cr3));
Console::main << FColor(Color::White) << BColor(Color::Red);
Console::main.clear();
Console::main
<< " ___ __ __ ___ " << "\n"
<< " / _ \\| \\/ |/ __|" << "\n"
<< " | (_) | |\\/| | (_ |" << "\n"
<< " \\___/|_| |_|\\___|" << "\n"
<< "\n";
Console::main
<< "DasOS crashed!\n"
<< "\n"
<< "CODE: " << Y;
switch(code) {
#define ERROR(num, ident, desc) case Error::ident: Console::main << #ident << " / " << #desc << "\n"; break;
#include "errors.lst"
#undef ERROR
}
Console::main
<< W << "MSG: " << Y
<< msg << W << "\n"
<< "\n"
<< "CPU State:\n";
Console::main
<< W << "eax = " << Y << pad(hex(cpu->eax), 10) << W << " esi = " << Y << pad(hex(cpu->esi), 10) << W << " edx = " << Y << pad(hex(cpu->edx), 10) << W << " esp = " << Y << pad(hex(cpu->esp), 10) << "\n"
<< W << "ebx = " << Y << pad(hex(cpu->ebx), 10) << W << " edi = " << Y << pad(hex(cpu->edi), 10) << W << " eip = " << Y << pad(hex(cpu->eip), 10) << W << " flg = " << Y << bin(cpu->eflags) << "\n"
<< W << "ecx = " << Y << pad(hex(cpu->ecx), 10) << W << " ebp = " << Y << pad(hex(cpu->ebp), 10) << W << " cs = " << Y << pad(hex(cpu->cs), 10) << W << " ss = " << Y << pad(hex(cpu->ss), 10) << "\n"
<< W << "cr0 = " << Y << pad(hex(cr0), 10) << W << " cr1 = " << Y << pad(hex(cr1), 10) << W << " cr2 = " << Y << pad(hex(cr2), 10) << W << " cr3 = " << Y << pad(hex(cr3), 10) << W << "\n"
<< W << "int = " << Y << pad(cpu->interrupt, 10) << W << " err = " << Y << pad(cpu->error, 10) << W << " " << toString(cpu->interrupt);
asm volatile ("hlt");
while(true);
}

View file

@ -1,17 +0,0 @@
#include "compat.h"
typedef void (*constructor)();
constructor start_ctors;
constructor end_ctors;
void compat_call_ctors()
{
for (constructor* i = &start_ctors;i != &end_ctors;++i)
(*i)();
}
void compat_call_dtors()
{
}

View file

@ -1,237 +0,0 @@
#include "console.hpp"
#include "numeric.hpp"
#include "io.hpp"
Console Console::main(&Screen::main);
Console::Console(Screen *screen) :
screen(screen),
x(0), y(0),
fg(Color::White), bg(Color::Black),
caretEnabled(true)
{
this->updateCaret();
}
void Console::clear()
{
for(int y = 0; y < this->screen->height; y++) {
for(int x = 0; x < this->screen->width; x++) {
auto &c = (*this->screen)(x, y);
c.c = ' ';
c.fg = (int)this->fg;
c.bg = (int)this->bg;
}
}
this->x = 0;
this->y = 0;
this->updateCaret();
}
// Prüft, ob man bereits schreiben kann
static uint8_t is_transmit_empty(uint16_t base) {
return inb(base+5) & 0x20;
}
// Byte senden
static void write_com(uint16_t base, uint8_t chr) {
while (is_transmit_empty(base)==0);
outb(base,chr);
}
void Console::put(char c)
{
write_com(0x3F8, c);
switch(c) {
case '\0': return;
case '\r': break; /* ignore \r */
case '\n':
this->newline();
break;
default:
ScreenChar &sc = (*this->screen)(this->x++, this->y);
sc.c = c;
sc.fg = (int)this->fg;
sc.bg = (int)this->bg;
break;
}
if(this->x >= this->screen->width) {
this->newline();
}
this->updateCaret();
}
void Console::newline() {
this->x = 0;
this->y += 1;
if(this->y >= this->screen->height) {
this->scroll();
}
this->updateCaret();
}
void Console::scroll() {
if(this->y <= 0) {
return;
}
for(int i = 0; i <= this->y; i++) {
for(int j = 0; j < this->screen->width; j++) {
(*this->screen)(j, i) = (*this->screen)(j, i + 1);
}
}
this->y -= 1;
this->updateCaret();
}
void Console::setCursor(int x, int y)
{
if(x < 0)
x = 0;
else if(x >= this->screen->width)
x = this->screen->width - 1;
if(y < 0)
y = 0;
else if(y >= this->screen->height)
y = this->screen->height - 1;
this->x = x;
this->y = y;
this->updateCaret();
}
void Console::updateCaret()
{
uint16_t tmp;
if(this->caretEnabled) {
tmp = this->y * this->screen->width + this->x;
} else {
tmp = this->screen->height * this->screen->width;
}
outb(0x3D4, 14);
outb(0x3D5, tmp >> 8);
outb(0x3D4, 15);
outb(0x3D5, tmp);
}
void Console::setCaretVisible(bool visible)
{
this->caretEnabled = visible;
this->updateCaret();
}
Console & Console::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->put(buffer[i]);
}
return *this;
}
Console & Console::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->put(buffer[i]);
}
return *this;
}
Console & Console::operator << (void *value)
{
char buffer[13];
size_t len = Numeric::toString(buffer, sizeof(buffer), reinterpret_cast<uint32_t>(value), 16);
for(size_t i = 0; i < len; i++) {
this->put(buffer[i]);
}
return *this;
}
Console & Console::operator << (bool value)
{
if(value == true) {
*this << "true";
} else {
*this << "false";
}
return *this;
}
template<>
Console & Console::operator << <physical_t_ident>(physical_t ptr)
{
*this << "physical(0x" << ptr.data() << ")";
return *this;
}
template<>
Console & Console::operator << <virtual_t_ident>(virtual_t ptr)
{
*this << "virtual(0x" << ptr.data() << ")";
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->put(buffer[i]); \
} \
if(fmt.padding > 0 && delta < fmt.padding) { \
this->putrep(fmt.padchar, fmt.padding - delta); \
} \
return *this
template<>
Console & Console::operator << <uint32_t>(const NumericFormat<uint32_t> & fmt)
{
NUMERIC_FMT_HANDLER;
}
template<>
Console & Console::operator << <int32_t>(const NumericFormat<int32_t> & fmt)
{
NUMERIC_FMT_HANDLER;
}
template<>
Console & Console::operator << <uint64_t>(const NumericFormat<uint64_t> & fmt)
{
NUMERIC_FMT_HANDLER;
}
template<>
Console & Console::operator << <int64_t>(const NumericFormat<int64_t> & fmt)
{
NUMERIC_FMT_HANDLER;
}
uint32_t Console::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 Console::putrep(char c, uint32_t repetitions)
{
for(uint32_t i = 0; i < repetitions; i++)
this->put(c);
}

View file

@ -1,58 +0,0 @@
#include "gdt.hpp"
static SegmentDescriptor invalid;
SegmentDescriptor GDT::descriptors[GDT::length];
SegmentDescriptor & GDT::descriptor(uint32_t index)
{
if(index >= GDT::length) {
return invalid;
}
return GDT::descriptors[index];
}
void GDT::initialize()
{
// Null descriptor
GDT::descriptor(0) = SegmentDescriptor();
GDT::descriptor(1) = SegmentDescriptor(
0x00000000,
0xFFFFFFFF,
SegmentAccess::Present | SegmentAccess::Executable | SegmentAccess::Segment | SegmentAccess::Ring0,
SegmentFlags::Use4KSize | SegmentFlags::Use32Bit);
GDT::descriptor(2) = SegmentDescriptor(
0x00000000,
0xFFFFFFFF,
SegmentAccess::Present | SegmentAccess::Writeable | SegmentAccess::Segment | SegmentAccess::Ring0,
SegmentFlags::Use4KSize | SegmentFlags::Use32Bit);
GDT::descriptor(3) = SegmentDescriptor(
0x00000000,
0xFFFFFFFF,
SegmentAccess::Present | SegmentAccess::Executable | SegmentAccess::Segment | SegmentAccess::Ring3,
SegmentFlags::Use4KSize | SegmentFlags::Use32Bit);
GDT::descriptor(4) = SegmentDescriptor(
0x00000000,
0xFFFFFFFF,
SegmentAccess::Present | SegmentAccess::Writeable | SegmentAccess::Segment | SegmentAccess::Ring3,
SegmentFlags::Use4KSize | SegmentFlags::Use32Bit);
struct
{
uint16_t limit;
void* pointer;
} __attribute__((packed)) gdtp =
{
.limit = GDT::length *sizeof(SegmentDescriptor) - 1,
.pointer = &GDT::descriptors,
};
asm volatile("lgdt %0" : : "m" (gdtp));
asm volatile("mov $0x10, %ax");
asm volatile("mov %ax, %ds");
asm volatile("mov %ax, %es");
asm volatile("mov %ax, %fs");
asm volatile("mov %ax, %gs");
asm volatile("mov %ax, %ss");
asm volatile("ljmp $0x8, $.1");
asm volatile(".1:");
}

View file

@ -1,120 +0,0 @@
#include "idt.hpp"
#include "asm.hpp"
#include "bsod.hpp"
#include "pic.hpp"
#define ISR(num) extern "C" void isr_##num();
#define ISR_ERR(num) ISR(num)
#include "interrupts.lst"
#undef ISR
#undef ISR_ERR
static InterruptDescriptor invalidDesc;
static Interrupt invalidIntr;
InterruptDescriptor IDT::descriptors[length];
Interrupt IDT::interrupts[length];
InterruptDescriptor & IDT::descriptor(uint32_t idx)
{
if(idx >= IDT::length) {
return invalidDesc;
}
return IDT::descriptors[idx];
}
Interrupt & IDT::interrupt(uint32_t index)
{
if(index >= IDT::length) {
return invalidIntr;
}
return IDT::interrupts[index];
}
void IDT::initialize()
{
#define ISR(num) IDT::descriptor(num) = InterruptDescriptor( \
uint32_t(&isr_##num), \
0x08, \
InterruptFlags::Interrupt | InterruptFlags::Use32Bit | InterruptFlags::Ring0 | InterruptFlags::Present);
#define ISR_ERR(num) ISR(num)
#include "interrupts.lst"
#undef ISR
#undef ISR_ERR
ASM::lidt(IDT::descriptors, IDT::length);
IDT::setupPIC();
}
void IDT::setupPIC()
{
masterPIC.initialize(0x20, 0x04, 0x01);
slavePIC.initialize(0x28, 0x02, 0x01);
masterPIC.maskInterrupts(0x00);
slavePIC.maskInterrupts(0x00);
}
CpuState * IDT::dispatch(CpuState *cpu)
{
bool ackMaster = cpu->interrupt >= 0x20 && cpu->interrupt <= 0x2F;
bool ackSlave = cpu->interrupt >= 0x28;
Interrupt &intr = IDT::interrupts[cpu->interrupt];
if(intr.isEnabled) {
(*intr.handler)(cpu);
} else {
BSOD::die(Error::UnhandledException, "Unhandled Interrupt!", cpu);
}
// ACK interrupts
if (ackMaster) {
if(ackSlave) {
slavePIC.sendEndOfInterrupt();
}
masterPIC.sendEndOfInterrupt();
}
return cpu;
}
Interrupt::Interrupt() :
isEnabled(false),
handler(nullptr)
{
}
Interrupt::Interrupt(Handler handler) :
isEnabled(true),
handler(handler)
{
}
InterruptDescriptor::InterruptDescriptor() :
offset0(0), selector(0), zero(0), flags(InterruptFlags::None), offset1(0)
{
}
InterruptDescriptor::InterruptDescriptor(uint32_t offset, uint32_t selector, InterruptFlags flags) :
offset0(0), selector(selector), zero(0), flags(flags), offset1(0)
{
this->setOffset(offset);
}
uint32_t InterruptDescriptor::offset() const
{
return this->offset0 | (this->offset1 << 16);
}
void InterruptDescriptor::setOffset(uint32_t offset)
{
this->offset0 = (offset & 0x0000FFFF) >> 0;
this->offset1 = (offset & 0xFFFF0000) >> 16;
}

View file

@ -1,21 +0,0 @@
#include "driver/keyboard.hpp"
#include "idt.hpp"
#include "console.hpp"
namespace driver
{
Keyboard::Keyboard()
{
}
void Keyboard::install()
{
IDT::interrupt(0x21) = Interrupt(Keyboard::dispatchIRQ);
}
void Keyboard::dispatchIRQ(CpuState *&cpu)
{
Console::main << "keyboard! ";
}
}

View file

@ -1,133 +0,0 @@
#include "numeric.hpp"
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<uint32_t>(-number), radix) + 1;
}
else {
return Numeric::toString(buffer, length, static_cast<uint32_t>(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<uint64_t>(-number), radix) + 1;
}
else {
return Numeric::toString(buffer, length, static_cast<uint64_t>(number), radix);
}
}

View file

@ -1,29 +0,0 @@
#include "pic.hpp"
#include "io.hpp"
PIC masterPIC(0x20);
PIC slavePIC(0xA0);
PIC::PIC(uint16_t port) :
port(port)
{
}
void PIC::initialize(uint16_t irqBase, uint16_t icw3, uint16_t icw4)
{
outb(this->port + 0x00, 0x11);
outb(this->port + 0x01, irqBase);
outb(this->port + 0x01, icw3);
outb(this->port + 0x01, icw4);
}
void PIC::maskInterrupts(uint8_t mask)
{
outb(this->port + 0x01, mask);
}
void PIC::sendEndOfInterrupt()
{
outb(this->port + 0x00, 0x20);
}

View file

@ -1,116 +0,0 @@
#include <inttypes.h>
#include <stddef.h>
#include "pmm.hpp"
#include "bsod.hpp"
/**
* Number stored of pages in the bitmap
*/
static const uint32_t BitmapSize = 1048576; /* 4 GB */
/**
* Number of 32-bit tuples in the bitmap.
*/
static const uint32_t BitmapLength = BitmapSize / 32;
/**
* Bitmap that stores the page status.
* A set bit marks a page as free.
* An unset bit marks a page as used.
*/
static uint32_t bitmap[BitmapLength];
/**
* Checks if an interger is 4096-aligned
*/
static bool isAligned(uint32_t ptr)
{
return (ptr % 4096) == 0;
}
void PMM::markFree(physical_t page)
{
uint32_t ptr = page.numeric();
if(!isAligned(ptr))
; // Do something about it!
uint32_t pageId = ptr / 4096;
uint32_t idx = pageId / 32;
uint32_t bit = pageId % 32;
bitmap[idx] |= (1<<bit);
}
void PMM::markUsed(physical_t page)
{
uint32_t ptr = page.numeric();
if(!isAligned(ptr))
; // Do something about it!
uint32_t pageId = ptr / 4096;
uint32_t idx = pageId / 32;
uint32_t bit = pageId % 32;
bitmap[idx] &= ~(1<<bit);
}
physical_t PMM::alloc()
{
for(uint32_t idx = 0; idx < BitmapLength; idx++) {
// fast skip when no bit is set
if(bitmap[idx] == 0) {
continue;
}
for(uint32_t bit = 0; bit < 32; bit++) {
uint32_t mask = (1<<bit);
if((bitmap[idx] & mask) == 0) {
// If bit is not set, ignore the bit.
continue;
}
// Mark the selected bit as used.
bitmap[idx] &= ~mask;
uint32_t pageId = 32 * idx + bit;
uint32_t ptr = 4096 * pageId;
return physical_t(ptr);
}
}
BSOD::die(Error::OutOfMemory, "Out of physical memory!");
return physical_t::invalid;
}
void PMM::free(physical_t page)
{
uint32_t ptr = page.numeric();
if(!isAligned(ptr))
; // Do something about it!
uint32_t pageId = ptr / 4096;
uint32_t idx = pageId / 32;
uint32_t bit = pageId % 32;
// Mark the selected bit as free.
bitmap[idx] |= (1<<bit);
}
uint32_t PMM::getFreeMemory()
{
uint32_t freeMemory = 0;
for(uint32_t idx = 0; idx < BitmapLength; idx++) {
// fast skip when no bit is set
if(bitmap[idx] == 0) {
continue;
}
for(uint32_t bit = 0; bit < 32; bit++) {
uint32_t mask = (1<<bit);
if((bitmap[idx] & mask) == 0) {
// If bit is not set, ignore the bit.
continue;
}
freeMemory += 0x1000;
}
}
return freeMemory;
}

View file

@ -1,19 +0,0 @@
#include <inttypes.h>
#include "screen.hpp"
ScreenChar Screen::outOfScreen;
Screen Screen::main((ScreenChar*)0xb8000, 80, 25);
Screen::Screen(ScreenChar *buffer, int width, int height) :
buffer(buffer),
width(width),
height(height)
{
this->clear();
}
void Screen::clear() {
for(int i = 0; i < this->width * this->height; i++) {
this->buffer[i].c = ' ';
}
}

View file

@ -1,28 +0,0 @@
#include "driver/timer.hpp"
#include "idt.hpp"
namespace driver
{
static volatile uint32_t counter = 0;
Timer::Timer()
{
}
void Timer::install()
{
IDT::interrupt(0x20) = Interrupt([](auto *&) { counter++; });
}
void Timer::reset()
{
counter = 0;
}
uint32_t count()
{
return counter;
}
}

View file

@ -1,129 +0,0 @@
#include "vmm.hpp"
#include <new>
#include "console.hpp"
#include "asm.hpp"
void VMM::enable()
{
uint32_t val;
ASM_READ_REG(cr0, val);
val |= (1 << 31);
ASM_WRITE_REG(cr0, val);
}
void VMM::activate(VMMContext & context)
{
ASM_WRITE_REG(cr3, context.directory);
}
VMMContext::VMMContext() :
directory(PMM::alloc().data<PageDirectory>())
{
new (this->directory) PageDirectory();
}
VMMContext::~VMMContext()
{
this->directory->~PageDirectory();
}
uint32_t & VMMContext::getPageDescriptor(virtual_t v)
{
uint32_t virt = v.numeric();
uint32_t directoryIndex = (virt >> 12) / 1024;
uint32_t tableIndex = (virt >> 12) % 1024;
uint32_t & tableDesc = this->directory->table(directoryIndex);
if((tableDesc & 0x01) == 0)
{
auto pageMemory = PMM::alloc();
tableDesc =
pageMemory.numeric() |
static_cast<uint32_t>(
VMMFlags::Present |
VMMFlags::Writable |
VMMFlags::UserSpace |
VMMFlags::SystemAllocated);
PageTable *table = reinterpret_cast<PageTable*>(tableDesc & 0xFFFFF000);
new (table) PageTable();
}
PageTable *table = reinterpret_cast<PageTable*>(tableDesc & 0xFFFFF000);
auto & entry = table->pageDescriptor(tableIndex);
/*
Console::main <<
v << " -> " << directoryIndex << "/" << tableIndex << ": " << tableDesc << "/" << entry << "\n";
//*/
return entry;
}
/**
* Maps an arbitrary page into the virtual memory.
*/
void VMMContext::provide(virtual_t virt, VMMFlags flags)
{
this->map(virt, PMM::alloc(), flags | VMMFlags::SystemAllocated);
}
/**
* Maps a given page into the virtual memory.
*/
void VMMContext::map(virtual_t virt, physical_t phys, VMMFlags flags)
{
using namespace console_tools;
flags |= VMMFlags::Present;
uint32_t & pageDesc = this->getPageDescriptor(virt);
pageDesc =
phys.numeric() |
static_cast<uint32_t>(flags);
/*
Console::main <<
"Mapping " << virt << " -> " << phys << " [" << bin(static_cast<int>(flags)) << "]: " << hex(pageDesc) << "\n";
//*/
ASM::invlpg(virt.data());
}
/**
* Unmaps a given page from the virtual memory.
*/
void VMMContext::unmap(virtual_t virt)
{
}
PageDirectory::PageDirectory()
{
for(uint32_t i = 0; i < 1024; i++) {
this->tables[i] = 0;
}
}
PageDirectory::~PageDirectory()
{
for(uint32_t i = 0; i < 1024; i++) {
if(this->tables[i] & 0x01) {
PMM::free(physical_t(this->tables[i] & 0xFFFFF000));
}
}
}
PageTable::PageTable()
{
for(uint32_t i = 0; i < 1024; i++) {
this->pages[i] = 0;
}
}
PageTable::~PageTable()
{
for(uint32_t i = 0; i < 1024; i++) {
if(this->pages[i] & static_cast<uint32_t>(VMMFlags::SystemAllocated)) {
PMM::free(physical_t(this->pages[i] & 0xFFFFF000));
}
}
}

Some files were not shown because too many files have changed in this diff Show more