Finished refactoring.
This commit is contained in:
parent
52a16fc519
commit
ba983c45b2
158 changed files with 106 additions and 28213 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -29,3 +29,6 @@
|
|||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
|
||||
# Boot Images
|
||||
*.img
|
24
documentation/supervm-syscalls.md
Normal file
24
documentation/supervm-syscalls.md
Normal 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:
|
24
documentation/supervm-system.md
Normal file
24
documentation/supervm-system.md
Normal 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.
|
||||
|
|
@ -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 |
|
||||
|-------------|-------------------|------|------------------------------------------|
|
||||
|
@ -278,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.
|
||||
|
@ -289,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:
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
||||
$(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
|
|
@ -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
|
|
@ -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. |
|
|
@ -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:
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
||||
};
|
|
@ -1,13 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void compat_call_ctors();
|
||||
|
||||
void compat_call_dtors();
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
|
@ -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);
|
||||
};
|
|
@ -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.");
|
|
@ -1,12 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
namespace driver
|
||||
{
|
||||
class Driver
|
||||
{
|
||||
protected:
|
||||
Driver() = default;
|
||||
public:
|
||||
virtual void install() = 0;
|
||||
};
|
||||
}
|
|
@ -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;
|
||||
};
|
||||
}
|
|
@ -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();
|
||||
};
|
||||
}
|
|
@ -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));
|
||||
}
|
|
@ -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; \
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
enum class Error
|
||||
{
|
||||
#define ERROR(num, ident, desc) ident = num,
|
||||
#include "errors.lst"
|
||||
#undef ERROR
|
||||
};
|
|
@ -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
|
||||
};
|
|
@ -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);
|
||||
};
|
|
@ -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();
|
||||
|
||||
};
|
|
@ -1,7 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include "asm.hpp"
|
||||
|
||||
// Import functions into global namespace
|
||||
using ASM::inb;
|
||||
using ASM::outb;
|
|
@ -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);
|
||||
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -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");
|
|
@ -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");
|
|
@ -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;
|
|
@ -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();
|
||||
};
|
|
@ -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.");
|
|
@ -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];
|
||||
}
|
||||
};
|
|
@ -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);
|
||||
};
|
|
@ -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.");
|
||||
}
|
||||
}
|
|
@ -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
|
|
@ -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 = .;
|
||||
}
|
|
@ -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.)
|
|
@ -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)
|
|
@ -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)
|
|
@ -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)
|
|
@ -1,10 +0,0 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
[0-1] GB Kernel Space
|
||||
|
||||
[1-4] GB User Space
|
||||
Entry Point: 0x40000000
|
||||
Stack Start: 0xFFFFFFFF
|
|
@ -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
|
|
@ -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);
|
||||
}
|
|
@ -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()
|
||||
{
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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:");
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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! ";
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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 = ' ';
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
Loading…
Reference in a new issue