Fixes bug with .ctors and .init_array, adds old base project as os-init

This commit is contained in:
Felix Queißner 2016-06-26 18:45:10 +02:00
parent 236ea33c61
commit 75b89dc1e0
28 changed files with 1586 additions and 22 deletions

View file

@ -4,10 +4,16 @@
PROJECTS = $(shell ls --file-type --ignore=libs --ignore=kernels --ignore=include | grep / | sed "s|/||") PROJECTS = $(shell ls --file-type --ignore=libs --ignore=kernels --ignore=include | grep / | sed "s|/||")
all: $(PROJECTS) boot.img LIBS = $(filter lib%, $(PROJECTS))
KERNELS = $(filter-out lib%, $(PROJECTS))
all: $(KERNELS) boot.img
.PHONY: $(PROJECTS) .PHONY: $(PROJECTS)
$(PROJECTS): $(KERNELS): $(LIBS)
make -C $@ $(ARGS)
$(LIBS):
make -C $@ $(ARGS) make -C $@ $(ARGS)
boot.img: $(PROJECTS) boot.img: $(PROJECTS)
@ -24,4 +30,4 @@ boot.img: $(PROJECTS)
mdir -i boot.img :: mdir -i boot.img ::
run: boot.img run: boot.img
qemu-system-i386 boot.img qemu-system-i386 boot.img -serial stdio

View file

@ -4,33 +4,33 @@
INCLUDE_DIRS += ../include/ /opt/lib/gcc/i686-elf/6.1.0/include/ INCLUDE_DIRS += ../include/ /opt/lib/gcc/i686-elf/6.1.0/include/
FLAGS = -ffreestanding -mno-sse -Werror -Wall -iquote include $(addprefix -I, $(INCLUDE_DIRS)) -O3 -g FLAGS += -ffreestanding -mno-sse -Werror -Wall -iquote include $(addprefix -I, $(INCLUDE_DIRS)) -O3 -g
ASFLAGS = $(FLAGS) ASFLAGS += $(FLAGS)
CFLAGS = $(FLAGS) CFLAGS += $(FLAGS)
CXXFLAGS = $(FLAGS) -std=c++14 -fno-rtti -fno-exceptions -fno-leading-underscore -fno-use-cxa-atexit -nostdlib -fno-builtin CXXFLAGS += $(FLAGS) -std=c++14 -fno-rtti -fno-exceptions -fno-leading-underscore -fno-use-cxa-atexit -nostdlib -fno-builtin
LDFLAGS = -L../libs/ LDFLAGS += -L../libs/
SRCS = $(shell find -regextype egrep -regex '.*/.*\.(cpp|S|c)') SRCS += $(shell find -regextype egrep -regex '.*/.*\.(cpp|S|c)')
OBJS = $(addsuffix .o, $(notdir $(basename $(SRCS)))) OBJS += $(addsuffix .o, $(notdir $(basename $(SRCS))))
%.o: %.cpp %.o: %.cpp
$(CXX) $(CXXFLAGS) -c -o obj/$@ $< $(CXX) $(CXXFLAGS) -c -o obj/$@ $<
%.o: %.c %.o: %.c
$(CC) $(ASFLAGS) -c -o obj/$@ $< $(CC) $(CFLAGS) -c -o obj/$@ $<
%.o: %.S %.o: %.S
$(AS) $(CFLAGS) -c -o obj/$@ $< $(AS) $(ASFLAGS) -c -o obj/$@ $<
%.o: src/%.cpp %.o: src/%.cpp
$(CXX) $(CXXFLAGS) -c -o obj/$@ $< $(CXX) $(CXXFLAGS) -c -o obj/$@ $<
%.o: src/%.c %.o: src/%.c
$(CC) $(ASFLAGS) -c -o obj/$@ $< $(CC) $(CFLAGS) -c -o obj/$@ $<
%.o: src/%.S %.o: src/%.S
$(AS) $(CFLAGS) -c -o obj/$@ $< $(AS) $(ASFLAGS) -c -o obj/$@ $<
builddir: builddir:
mkdir -p ./obj/ mkdir -p ./obj/

View file

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

View file

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

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

View file

@ -3,6 +3,6 @@
enum class Error enum class Error
{ {
#define ERROR(num, ident, desc) ident = num, #define ERROR(num, ident, desc) ident = num,
#include "errors.lst" #include "lists/errors.lst"
#undef ERROR #undef ERROR
}; };

View file

@ -5,6 +5,6 @@
enum class Exception enum class Exception
{ {
#define EXCEPTION(num, shorthand, ident, desc, type) ident = num, #define EXCEPTION(num, shorthand, ident, desc, type) ident = num,
#include "exceptions.lst" #include "lists/exceptions.lst"
#undef EXCEPTION #undef EXCEPTION
}; };

View file

@ -58,9 +58,11 @@ public:
explicit Interrupt(Handler handler); explicit Interrupt(Handler handler);
}; };
extern "C" CpuState * interrupt_dispatch(CpuState *cpu);
class IDT class IDT
{ {
friend CpuState * interrupt_dispatch(CpuState *cpu);
public: public:
static const uint32_t length = 256; static const uint32_t length = 256;

View file

@ -0,0 +1,29 @@
#ifndef _NEW
#define _NEW
#include <stddef.h>
#pragma GCC visibility push(default)
extern "C++" {
void* operator new(size_t) __attribute__((__externally_visible__));
void* operator new[](size_t) __attribute__((__externally_visible__));
void operator delete(void*) __attribute__((__externally_visible__));
void operator delete[](void*) __attribute__((__externally_visible__));
#if __cpp_sized_deallocation
void operator delete(void*, size_t) __attribute__((__externally_visible__));
void operator delete[](void*, size_t) __attribute__((__externally_visible__));
#endif
// Default placement versions of operator new.
inline void* operator new(size_t, void* __p) { return __p; }
inline void* operator new[](size_t, void* __p) { return __p; }
// Default placement versions of operator delete.
inline void operator delete (void*, void*) { }
inline void operator delete[](void*, void*) { }
} // extern "C++"
#endif

View file

@ -2,8 +2,8 @@
typedef void (*constructor)(); typedef void (*constructor)();
constructor start_ctors; extern constructor start_ctors;
constructor end_ctors; extern constructor end_ctors;
void compat_call_ctors() void compat_call_ctors()
{ {

View file

@ -14,8 +14,8 @@ SECTIONS
} }
.data ALIGN(4096) : { .data ALIGN(4096) : {
start_ctors = .; start_ctors = .;
KEEP(*( .init_array )); KEEP(*( .ctors ));
KEEP(*(SORT_BY_INIT_PRIORITY( .init_array.* ))); KEEP(*(SORT_BY_INIT_PRIORITY( .ctors.* )));
end_ctors = .; end_ctors = .;
start_dtors = .; start_dtors = .;

View file

@ -0,0 +1,14 @@
##
# Builds the os initialization kernel
##
include ../config.mk
KERNEL = os-init.ker
LIBS += -lbase -lgcc -lboot
FLAGS += -D IDT_DISPATCH=interrupt_dispatch
all: builddir $(KERNEL)
include ../common.mk
include ../kernel.mk

View file

@ -0,0 +1,323 @@
#include <console.hpp>
#include <kernel/pmm.hpp>
#include <numeric.hpp>
#include <pointer.hpp>
#include <multiboot.hpp>
#include <kernel/gdt.hpp>
#include <kernel/idt.hpp>
#include <io.hpp>
#include <kernel/vmm.hpp>
#include <elf.hpp>
#include <kernel/bsod.hpp>
#include <asm.hpp>
#include "driver/timer.hpp"
#include "driver/keyboard.hpp"
#include <stdint.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.clear();
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::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

@ -0,0 +1,28 @@
.section multiboot
#define MB_MAGIC 0x1badb002
#define MB_FLAGS 0x00
#define MB_CHECKSUM -(MB_MAGIC + MB_FLAGS)
.align 4
// Offset Type Field Name Note
// 0 u32 magic required
// 4 u32 flags required
// 8 u32 checksum required
.int MB_MAGIC
.int MB_FLAGS
.int MB_CHECKSUM
// 12 u32 header_addr if flags[16] is set
// 16 u32 load_addr if flags[16] is set
// 20 u32 load_end_addr if flags[16] is set
// 24 u32 bss_end_addr if flags[16] is set
// 28 u32 entry_addr if flags[16] is set
.int 0, 0, 0, 0, 0
// 32 u32 mode_type if flags[2] is set
// 36 u32 width if flags[2] is set
// 40 u32 height if flags[2] is set
// 44 u32 depth if flags[2] is set
.int 0, 0, 0, 0

View file

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

@ -0,0 +1,83 @@
#include <kernel/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 <lists/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 <lists/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 <lists/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

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

@ -0,0 +1,58 @@
#include <kernel/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

@ -0,0 +1,125 @@
#include <kernel/idt.hpp>
#include <asm.hpp>
#include <kernel/bsod.hpp>
#include <driver/pic.hpp>
#define ISR(num) extern "C" void isr_##num();
#define ISR_ERR(num) ISR(num)
#include <lists/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 <lists/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);
}
extern "C" CpuState * interrupt_dispatch(CpuState *cpu)
{
return IDT::dispatch(cpu);
}
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

@ -0,0 +1,58 @@
.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 <lists/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

@ -0,0 +1,21 @@
#include <driver/keyboard.hpp>
#include <kernel/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

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

@ -0,0 +1,29 @@
#include <driver/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

@ -0,0 +1,116 @@
#include <stdint.h>
#include <stddef.h>
#include <kernel/pmm.hpp>
#include <kernel/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

@ -0,0 +1,19 @@
#include <stdint.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

@ -0,0 +1,28 @@
#include <driver/timer.hpp>
#include <kernel/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

@ -0,0 +1,129 @@
#include <kernel/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));
}
}
}

View file

@ -6,11 +6,17 @@ MENU AUTOBOOT Starting DasOS in # seconds
TIMEOUT 300 TIMEOUT 300
TOTALTIMEOUT 9000 TOTALTIMEOUT 9000
LABEL dasos LABEL das-os
MENU DEFAULT MENU DEFAULT
MENU LABEL DasOS MENU LABEL DasOS
KERNEL mboot.c32 KERNEL mboot.c32
APPEND kernel-base.ker APPEND das-os.ker
LABEL os-init
MENU DEFAULT
MENU LABEL OS Initialization Test
KERNEL mboot.c32
APPEND os-init.ker
LABEL video LABEL video
MENU LABEL VBE Video Test MENU LABEL VBE Video Test