Fixes bug with .ctors and .init_array, adds old base project as os-init
This commit is contained in:
parent
236ea33c61
commit
75b89dc1e0
28 changed files with 1586 additions and 22 deletions
|
@ -4,10 +4,16 @@
|
|||
|
||||
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)
|
||||
$(PROJECTS):
|
||||
$(KERNELS): $(LIBS)
|
||||
make -C $@ $(ARGS)
|
||||
|
||||
$(LIBS):
|
||||
make -C $@ $(ARGS)
|
||||
|
||||
boot.img: $(PROJECTS)
|
||||
|
@ -24,4 +30,4 @@ boot.img: $(PROJECTS)
|
|||
mdir -i boot.img ::
|
||||
|
||||
run: boot.img
|
||||
qemu-system-i386 boot.img
|
||||
qemu-system-i386 boot.img -serial stdio
|
|
@ -4,33 +4,33 @@
|
|||
|
||||
INCLUDE_DIRS += ../include/ /opt/lib/gcc/i686-elf/6.1.0/include/
|
||||
|
||||
FLAGS = -ffreestanding -mno-sse -Werror -Wall -iquote include $(addprefix -I, $(INCLUDE_DIRS)) -O3 -g
|
||||
ASFLAGS = $(FLAGS)
|
||||
CFLAGS = $(FLAGS)
|
||||
CXXFLAGS = $(FLAGS) -std=c++14 -fno-rtti -fno-exceptions -fno-leading-underscore -fno-use-cxa-atexit -nostdlib -fno-builtin
|
||||
LDFLAGS = -L../libs/
|
||||
FLAGS += -ffreestanding -mno-sse -Werror -Wall -iquote include $(addprefix -I, $(INCLUDE_DIRS)) -O3 -g
|
||||
ASFLAGS += $(FLAGS)
|
||||
CFLAGS += $(FLAGS)
|
||||
CXXFLAGS += $(FLAGS) -std=c++14 -fno-rtti -fno-exceptions -fno-leading-underscore -fno-use-cxa-atexit -nostdlib -fno-builtin
|
||||
LDFLAGS += -L../libs/
|
||||
|
||||
SRCS = $(shell find -regextype egrep -regex '.*/.*\.(cpp|S|c)')
|
||||
OBJS = $(addsuffix .o, $(notdir $(basename $(SRCS))))
|
||||
SRCS += $(shell find -regextype egrep -regex '.*/.*\.(cpp|S|c)')
|
||||
OBJS += $(addsuffix .o, $(notdir $(basename $(SRCS))))
|
||||
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(CXXFLAGS) -c -o obj/$@ $<
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(ASFLAGS) -c -o obj/$@ $<
|
||||
$(CC) $(CFLAGS) -c -o obj/$@ $<
|
||||
|
||||
%.o: %.S
|
||||
$(AS) $(CFLAGS) -c -o obj/$@ $<
|
||||
$(AS) $(ASFLAGS) -c -o obj/$@ $<
|
||||
|
||||
%.o: src/%.cpp
|
||||
$(CXX) $(CXXFLAGS) -c -o obj/$@ $<
|
||||
|
||||
%.o: src/%.c
|
||||
$(CC) $(ASFLAGS) -c -o obj/$@ $<
|
||||
$(CC) $(CFLAGS) -c -o obj/$@ $<
|
||||
|
||||
%.o: src/%.S
|
||||
$(AS) $(CFLAGS) -c -o obj/$@ $<
|
||||
$(AS) $(ASFLAGS) -c -o obj/$@ $<
|
||||
|
||||
builddir:
|
||||
mkdir -p ./obj/
|
12
prototypes-rework/include/driver/driver.hpp
Normal file
12
prototypes-rework/include/driver/driver.hpp
Normal file
|
@ -0,0 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
namespace driver
|
||||
{
|
||||
class Driver
|
||||
{
|
||||
protected:
|
||||
Driver() = default;
|
||||
public:
|
||||
virtual void install() = 0;
|
||||
};
|
||||
}
|
18
prototypes-rework/include/driver/keyboard.hpp
Normal file
18
prototypes-rework/include/driver/keyboard.hpp
Normal 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;
|
||||
};
|
||||
}
|
20
prototypes-rework/include/driver/timer.hpp
Normal file
20
prototypes-rework/include/driver/timer.hpp
Normal 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();
|
||||
};
|
||||
}
|
|
@ -3,6 +3,6 @@
|
|||
enum class Error
|
||||
{
|
||||
#define ERROR(num, ident, desc) ident = num,
|
||||
#include "errors.lst"
|
||||
#include "lists/errors.lst"
|
||||
#undef ERROR
|
||||
};
|
|
@ -5,6 +5,6 @@
|
|||
enum class Exception
|
||||
{
|
||||
#define EXCEPTION(num, shorthand, ident, desc, type) ident = num,
|
||||
#include "exceptions.lst"
|
||||
#include "lists/exceptions.lst"
|
||||
#undef EXCEPTION
|
||||
};
|
|
@ -58,9 +58,11 @@ public:
|
|||
explicit Interrupt(Handler handler);
|
||||
};
|
||||
|
||||
extern "C" CpuState * interrupt_dispatch(CpuState *cpu);
|
||||
|
||||
class IDT
|
||||
{
|
||||
friend CpuState * interrupt_dispatch(CpuState *cpu);
|
||||
public:
|
||||
static const uint32_t length = 256;
|
||||
|
||||
|
|
29
prototypes-rework/include/new
Normal file
29
prototypes-rework/include/new
Normal 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
|
|
@ -2,8 +2,8 @@
|
|||
|
||||
typedef void (*constructor)();
|
||||
|
||||
constructor start_ctors;
|
||||
constructor end_ctors;
|
||||
extern constructor start_ctors;
|
||||
extern constructor end_ctors;
|
||||
|
||||
void compat_call_ctors()
|
||||
{
|
||||
|
|
|
@ -14,8 +14,8 @@ SECTIONS
|
|||
}
|
||||
.data ALIGN(4096) : {
|
||||
start_ctors = .;
|
||||
KEEP(*( .init_array ));
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY( .init_array.* )));
|
||||
KEEP(*( .ctors ));
|
||||
KEEP(*(SORT_BY_INIT_PRIORITY( .ctors.* )));
|
||||
end_ctors = .;
|
||||
|
||||
start_dtors = .;
|
||||
|
|
14
prototypes-rework/os-init/Makefile
Normal file
14
prototypes-rework/os-init/Makefile
Normal 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
|
323
prototypes-rework/os-init/init.cpp
Normal file
323
prototypes-rework/os-init/init.cpp
Normal 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.");
|
||||
}
|
||||
}
|
||||
*/
|
28
prototypes-rework/os-init/multiboot.S
Normal file
28
prototypes-rework/os-init/multiboot.S
Normal 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
|
70
prototypes-rework/os-init/src/Makefile
Normal file
70
prototypes-rework/os-init/src/Makefile
Normal 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
|
83
prototypes-rework/os-init/src/bsod.cpp
Normal file
83
prototypes-rework/os-init/src/bsod.cpp
Normal 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);
|
||||
}
|
237
prototypes-rework/os-init/src/console.cpp
Normal file
237
prototypes-rework/os-init/src/console.cpp
Normal 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);
|
||||
}
|
58
prototypes-rework/os-init/src/gdt.cpp
Normal file
58
prototypes-rework/os-init/src/gdt.cpp
Normal 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:");
|
||||
}
|
125
prototypes-rework/os-init/src/idt.cpp
Normal file
125
prototypes-rework/os-init/src/idt.cpp
Normal 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;
|
||||
}
|
58
prototypes-rework/os-init/src/interrupts.S
Normal file
58
prototypes-rework/os-init/src/interrupts.S
Normal 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
|
21
prototypes-rework/os-init/src/keyboard.cpp
Normal file
21
prototypes-rework/os-init/src/keyboard.cpp
Normal 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! ";
|
||||
}
|
||||
}
|
133
prototypes-rework/os-init/src/numeric.cpp
Normal file
133
prototypes-rework/os-init/src/numeric.cpp
Normal 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);
|
||||
}
|
||||
}
|
29
prototypes-rework/os-init/src/pic.cpp
Normal file
29
prototypes-rework/os-init/src/pic.cpp
Normal 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);
|
||||
}
|
116
prototypes-rework/os-init/src/pmm.cpp
Normal file
116
prototypes-rework/os-init/src/pmm.cpp
Normal 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;
|
||||
}
|
19
prototypes-rework/os-init/src/screen.cpp
Normal file
19
prototypes-rework/os-init/src/screen.cpp
Normal 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 = ' ';
|
||||
}
|
||||
}
|
28
prototypes-rework/os-init/src/timer.cpp
Normal file
28
prototypes-rework/os-init/src/timer.cpp
Normal 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;
|
||||
}
|
||||
|
||||
}
|
129
prototypes-rework/os-init/src/vmm.cpp
Normal file
129
prototypes-rework/os-init/src/vmm.cpp
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,11 +6,17 @@ MENU AUTOBOOT Starting DasOS in # seconds
|
|||
TIMEOUT 300
|
||||
TOTALTIMEOUT 9000
|
||||
|
||||
LABEL dasos
|
||||
LABEL das-os
|
||||
MENU DEFAULT
|
||||
MENU LABEL DasOS
|
||||
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
|
||||
MENU LABEL VBE Video Test
|
||||
|
|
Loading…
Reference in a new issue