Update files

This commit is contained in:
Alex 2022-10-08 04:33:53 +03:00
parent 6d5f7e9372
commit 8652d781ce
Signed by untrusted user who does not match committer: enderice2
GPG Key ID: EACC3AD603BAB4DD
53 changed files with 7413 additions and 10 deletions

5
.gitignore vendored
View File

@ -1 +1,4 @@
*.o
*.o
*.map
*.fsys
*.log

20
.vscode/c_boilerplates.code-snippets vendored Normal file
View File

@ -0,0 +1,20 @@
{
"Fennix Kernel Header": {
"scope": "c",
"prefix": [
"head",
],
"body": [
"#ifndef __FENNIX_KERNEL_${2:header}_H__",
"#define __FENNIX_KERNEL_${2:header}_H__",
"",
"#include <types.h>",
"",
"$0",
"",
"#endif // !__FENNIX_KERNEL_${2:header}_H__",
""
],
"description": "Create kernel header."
}
}

40
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,40 @@
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/include/**"
],
"defines": [
"KERNEL_NAME=\"Fennix\"",
"KERNEL_VERSION=\"1.0\"",
"GIT_COMMIT=\"0000000000000000000000000000000000000000\"",
"GIT_COMMIT_SHORT=\"0000000\"",
"DEBUG=\"1\""
],
"compilerPath": "/usr/bin/gcc",
"cStandard": "c17",
"cppStandard": "c++20",
"intelliSenseMode": "gcc-x64",
"configurationProvider": "ms-vscode.makefile-tools",
"compilerArgs": [
"-fno-rtti",
"-fexceptions",
"-fno-pic",
"-fno-pie",
"-mno-80387",
"-mno-mmx",
"-mno-3dnow",
"-mno-red-zone",
"-mno-sse",
"-mno-sse2",
"-march=nehalem",
"-pipe",
"-mcmodel=kernel",
"-msoft-float",
"-fno-builtin"
]
}
],
"version": 4
}

16
.vscode/extensions.json vendored Normal file
View File

@ -0,0 +1,16 @@
{
"recommendations": [
"pejmannikram.vscode-auto-scroll",
"aaron-bond.better-comments",
"ms-vscode.cpptools",
"streetsidesoftware.code-spell-checker",
"naumovs.color-highlight",
"cschlosser.doxdocgen",
"ferrierbenjamin.fold-unfold-all-icone",
"ajshort.include-autocomplete",
"zixuanwang.linkerscript",
"ibm.output-colorizer",
"christian-kohler.path-intellisense",
"Gruntfuggly.todo-tree"
]
}

40
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,40 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Attach to a running QEMU instance",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceRoot}/kernel.fsys",
"cwd": "${workspaceRoot}",
"args": [],
"targetArchitecture": "x64",
"MIMode": "gdb",
"miDebuggerPath": "/usr/bin/gdb",
"miDebuggerArgs": "",
"externalConsole": false,
"additionalSOLibSearchPath": "${workspaceRoot}",
"customLaunchSetupCommands": [
{
"text": "target remote localhost:1234",
"description": "Connect to QEMU remote debugger"
}
],
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
{
"text": "set breakpoint pending on",
"description": "Make breakpoint pending on future shared library load."
},
{
"text": "file ${workspaceRoot}/kernel.fsys",
"description": "Load binary."
},
]
}
]
}

12
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,12 @@
{
"C_Cpp.errorSquiggles": "Enabled",
"C_Cpp.autocompleteAddParentheses": true,
"C_Cpp.codeAnalysis.clangTidy.enabled": true,
"C_Cpp.clang_format_style": "Visual Studio",
"C_Cpp.default.intelliSenseMode": "gcc-x64",
"C_Cpp.default.cStandard": "c17",
"C_Cpp.default.cppStandard": "c++20",
"C_Cpp.intelliSenseMemoryLimit": 16384,
"editor.smoothScrolling": true,
"editor.cursorSmoothCaretAnimation": true
}

View File

@ -0,0 +1,16 @@
{
"folders": [
{
"path": "."
}
],
"settings": {
"debug.allowBreakpointsEverywhere": true,
"files.associations": {
"limine.h": "c",
"types.h": "c",
"binfo.h": "c",
"liballoc_1_1.h": "c"
}
}
}

View File

@ -1,6 +1,30 @@
#include "kernel.h"
extern "C" void kernel_entry(void *Data)
#include <memory.hpp>
#include <string.h>
#include <debug.h>
BootInfo *bInfo = nullptr;
EXTERNC void kernel_aarch64_entry(uint64_t dtb_ptr32, uint64_t x1, uint64_t x2, uint64_t x3)
{
trace("Hello, World!");
while (1)
;
CPU::Halt();
}
EXTERNC void kernel_entry(BootInfo *Info)
{
InitializeMemoryManagement(Info);
trace("Hello, World!");
bInfo = (BootInfo *)KernelAllocator.RequestPages(TO_PAGES(sizeof(BootInfo)));
memcpy(bInfo, Info, sizeof(BootInfo));
debug("BootInfo structure is at %p", bInfo);
while (1)
CPU::Halt();
}
// TODO: Implement screen printing
extern "C" void putchar(int a, int b)
{
}

155
Makefile
View File

@ -1,5 +1,156 @@
prepare:
# Config file
include ../Makefile.conf
build:
KERNEL_FILENAME = kernel.fsys
CC = ../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc
CPP = ../$(COMPILER_PATH)/$(COMPILER_ARCH)g++
LD = ../$(COMPILER_PATH)/$(COMPILER_ARCH)ld
AS = ../$(COMPILER_PATH)/$(COMPILER_ARCH)as
NM = ../$(COMPILER_PATH)/$(COMPILER_ARCH)nm
OBJCOPY = ../$(COMPILER_PATH)/$(COMPILER_ARCH)objcopy
OBJDUMP = ../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump
GDB = ../$(COMPILER_PATH)/$(COMPILER_ARCH)gdb
NASM = /usr/bin/nasm
GIT_COMMIT = $(shell git rev-parse HEAD)
GIT_COMMIT_SHORT = $(shell git rev-parse --short HEAD)
BMP_SOURCES = $(shell find ./ -type f -name '*.bmp')
PSF_SOURCES = $(shell find ./ -type f -name '*.psf')
ifeq ($(OSARCH), amd64)
ASM_SOURCES = $(shell find ./ -type f -name '*.asm' -not -path "./arch/i686/*" -not -path "./arch/aarch64/*")
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/i686/*" -not -path "./arch/aarch64/*")
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/i686/*" -not -path "./arch/aarch64/*")
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/i686/*" -not -path "./arch/aarch64/*")
else ifeq ($(OSARCH), i686)
ASM_SOURCES = $(shell find ./ -type f -name '*.asm' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*")
else ifeq ($(OSARCH), aarch64)
ASM_SOURCES = $(shell find ./ -type f -name '*.asm' -not -path "./arch/amd64/*" -not -path "./arch/i686/*")
S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/i686/*")
C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/i686/*")
CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/i686/*")
endif
HEADERS = $(sort $(dir $(wildcard ./include/*)))
OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o)
INCLUDE_DIR = ./include
LDFLAGS := -Wl,-Map kernel.map -shared -nostdlib -nodefaultlibs -nolibc
# Disable all warnings by adding "-w" in WARNCFLAG and if you want to treat the warnings as errors, add "-Werror"
WARNCFLAG = -Wall -Wextra
# https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
CFLAGS := \
-I$(INCLUDE_DIR) \
-DKERNEL_NAME='"$(OSNAME)"' \
-DKERNEL_VERSION='"$(KERNEL_VERSION)"' \
-DGIT_COMMIT='"$(GIT_COMMIT)"' \
-DGIT_COMMIT_SHORT='"$(GIT_COMMIT_SHORT)"'
ifeq ($(OSARCH), amd64)
CFLAGS += -fno-pic -fno-pie -mno-80387 -mno-mmx -mno-3dnow \
-mno-red-zone -mno-sse -mno-sse2 \
-march=x86-64 -pipe \
-mcmodel=kernel -msoft-float -fno-builtin
CFLAG_STACK_PROTECTOR := -fstack-protector-all
LDFLAGS += -Tarch/amd64/linker.ld \
-fno-pic -fno-pie \
-Wl,-static,--no-dynamic-linker,-ztext \
-nostdlib -nodefaultlibs -nolibc \
-zmax-page-size=0x1000 \
-Wl,-Map kernel.map -shared
else ifeq ($(OSARCH), i686)
CFLAGS += -fno-pic -fno-pie -mno-80387 -mno-mmx -mno-3dnow \
-mno-red-zone -mno-sse -mno-sse2 \
-march=i686 -pipe -msoft-float -fno-builtin
CFLAG_STACK_PROTECTOR := -fstack-protector-all
LDFLAGS += -Tarch/i686/linker.ld \
-fno-pic -fno-pie \
-Wl,-static,--no-dynamic-linker,-ztext \
-nostdlib -nodefaultlibs -nolibc \
-zmax-page-size=0x1000 \
-Wl,-Map kernel.map -shared
else ifeq ($(OSARCH), aarch64)
CFLAGS += -pipe -fno-builtin -fPIC -mgeneral-regs-only
CFLAG_STACK_PROTECTOR := -fstack-protector-all
LDFLAGS += -Tarch/aarch64/linker.ld -fPIC
endif
ifeq ($(DEBUG), 1)
CFLAGS += -DDEBUG -ggdb -O0 -fdiagnostics-color=always
LDFLAGS += -ggdb -O0 -g
NASMFLAGS += -F dwarf -g
WARNCFLAG += -Wno-unused-function -Wno-maybe-uninitialized -Wno-builtin-declaration-mismatch -Wno-unknown-pragmas -Wno-unused-parameter -Wno-unused-variable
ifeq ($(TESTING), 1)
CFLAGS += -DTESTING
endif
endif
default:
$(error Please specify a target)
# TODO: complete this
prepare:
$(info Nothing to prepare)
build: $(KERNEL_FILENAME)
$(OBJDUMP) -D -d $(KERNEL_FILENAME) > kernel_dump.map
$(KERNEL_FILENAME): $(OBJ)
$(CC) $(LDFLAGS) $(OBJ) -o $@
%.o: %.c $(HEADERS)
$(info Compiling $<)
$(CC) $(CFLAGS) $(CFLAG_STACK_PROTECTOR) $(WARNCFLAG) -std=c17 -c $< -o $@
# https://gcc.gnu.org/projects/cxx-status.html
%.o: %.cpp $(HEADERS)
$(info Compiling $<)
$(CPP) $(CFLAGS) $(CFLAG_STACK_PROTECTOR) $(WARNCFLAG) -std=c++20 -fexceptions -c $< -o $@ -fno-rtti
%.o: %.asm
$(info Compiling $<)
$(NASM) $< $(NASMFLAGS) -o $@
%.o: %.S
$(info Compiling $<)
ifeq ($(OSARCH), amd64)
$(AS) -c $< -o $@
else ifeq ($(OSARCH), i686)
$(AS) -c $< -o $@
else ifeq ($(OSARCH), aarch64)
$(AS) -c $< -o $@
endif
%.o: %.psf
ifeq ($(OSARCH), amd64)
$(OBJCOPY) -O elf64-x86-64 -I binary $< $@
else ifeq ($(OSARCH), i686)
$(OBJCOPY) -O elf32-i386 -I binary $< $@
else ifeq ($(OSARCH), aarch64)
$(OBJCOPY) -O elf64-bigaarch64 -I binary $< $@
endif
$(NM) $@
%.o: %.bmp
ifeq ($(OSARCH), amd64)
$(OBJCOPY) -O elf64-x86-64 -I binary $< $@
else ifeq ($(OSARCH), i686)
$(OBJCOPY) -O elf32-i386 -I binary $< $@
else ifeq ($(OSARCH), aarch64)
$(OBJCOPY) -O elf64-bigaarch64 -I binary $< $@
endif
$(NM) $@
clean:
rm -f *.bin *.o *.elf *.sym kernel.map kernel_dump.map initrd.tar.gz $(OBJ) $(KERNEL_FILENAME)

63
arch/CPU.cpp Normal file
View File

@ -0,0 +1,63 @@
#include <cpu.hpp>
namespace CPU
{
void Pause()
{
#if defined(__amd64__) || defined(__i386__)
asmv("pause");
#elif defined(__aarch64__)
asmv("yield");
#endif
}
void Halt()
{
#if defined(__amd64__) || defined(__i386__)
asmv("hlt");
#elif defined(__aarch64__)
asmv("wfe");
#endif
}
bool Interrupts(InterruptsType Type)
{
switch (Type)
{
case Check:
{
#if defined(__amd64__) || defined(__i386__)
uint64_t rflags;
asmv("pushfq");
asmv("popq %0"
: "=r"(rflags));
return rflags & (1 << 9);
#elif defined(__aarch64__)
uint64_t daif;
asmv("mrs %0, daif"
: "=r"(daif));
return !(daif & (1 << 2));
#endif
}
case Enable:
{
#if defined(__amd64__) || defined(__i386__)
asmv("sti");
#elif defined(__aarch64__)
asmv("msr daifclr, #2");
#endif
return true;
}
case Disable:
{
#if defined(__amd64__) || defined(__i386__)
asmv("cli");
#elif defined(__aarch64__)
asmv("msr daifset, #2");
#endif
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,101 @@
#include <uart.hpp>
#include <vector.hpp>
#include <debug.h>
#include <io.h>
namespace UniversalAsynchronousReceiverTransmitter
{
#define SERIAL_ENABLE_DLAB 0x80
#define SERIAL_RATE_38400_LO 0x03
#define SERIAL_RATE_38400_HI 0x00
#define SERIAL_BUFFER_EMPTY 0x20
volatile bool serialports[8] = {false, false, false, false, false, false, false, false};
Vector<Events *> RegisteredEvents;
UART::UART(SerialPorts Port)
{
#if defined(__amd64__) || defined(__i386__)
if (Port == COMNULL)
return;
this->Port = Port;
if (serialports[Port])
return;
// Initialize the serial port
outb(Port + 1, 0x00); // Disable all interrupts
outb(Port + 3, SERIAL_ENABLE_DLAB); // Enable DLAB (set baud rate divisor)
outb(Port + 0, SERIAL_RATE_38400_LO); // Set divisor to 3 (lo byte) 38400 baud
outb(Port + 1, SERIAL_RATE_38400_HI); // (hi byte)
outb(Port + 3, 0x03); // 8 bits, no parity, one stop bit
outb(Port + 2, 0xC7); // Enable FIFO, clear them, with 14-byte threshold
outb(Port + 4, 0x0B); // IRQs enabled, RTS/DSR set
// Check if the serial port is faulty.
if (inb(Port + 0) != 0xAE)
{
static int once = 0;
if (!once++)
warn("Serial port %#lx is faulty.", Port);
// serialports[Port] = false; // ignore for now
// return;
}
// Set to normal operation mode.
outb(Port + 4, 0x0F);
serialports[Port] = true;
#endif
}
UART::~UART() {}
void UART::Write(uint8_t Char)
{
#if defined(__amd64__) || defined(__i386__)
while ((inb(Port + 5) & SERIAL_BUFFER_EMPTY) == 0)
;
outb(Port, Char);
#endif
foreach (auto e in RegisteredEvents)
if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL)
e->OnSent(Char);
}
uint8_t UART::Read()
{
#if defined(__amd64__) || defined(__i386__)
while ((inb(Port + 5) & 1) == 0)
;
return inb(Port);
#endif
foreach (auto e in RegisteredEvents)
{
if (e->GetRegisteredPort() == Port || e->GetRegisteredPort() == COMNULL)
{
#if defined(__amd64__) || defined(__i386__)
e->OnReceived(inb(Port));
#endif
}
}
}
Events::Events(SerialPorts Port)
{
this->Port = Port;
RegisteredEvents.push_back(this);
}
Events::~Events()
{
for (uint64_t i = 0; i < RegisteredEvents.size(); i++)
if (RegisteredEvents[i] == this)
{
RegisteredEvents.remove(i);
return;
}
}
}

17
arch/aarch64/boot.S Normal file
View File

@ -0,0 +1,17 @@
.section ".text.boot"
.global _start
.org 0x80000
_start:
ldr x5, =_start
mov sp, x5
ldr x5, =_kernel_rodata_end
ldr w6, =_bss_size
1: cbz w6, 2f
str xzr, [x5], #8
sub w6, w6, #1
cbnz w6, 1b
2: bl kernel_aarch64_entry
Halt:
wfe
b Halt

42
arch/aarch64/linker.ld Normal file
View File

@ -0,0 +1,42 @@
ENTRY(_start)
SECTIONS
{
. = 0x80000;
_kernel_start = .;
.text :
{
KEEP(*(.text.boot))
*(.text .text.*)
}
. = ALIGN(4096);
_kernel_text_end = .;
.data :
{
*(.data .data.*)
}
. = ALIGN(4096);
_kernel_data_end = .;
.rodata :
{
*(.rodata .rodata.*)
}
. = ALIGN(4096);
_kernel_rodata_end = .;
.bss :
{
*(.bss .bss.*)
}
. = ALIGN(4096);
_kernel_end = .;
_bss_size = _kernel_end - _kernel_rodata_end;
/DISCARD/ :
{
*(.eh_frame)
*(.note .note.*)
}
}

233
arch/amd64/Limine.c Normal file
View File

@ -0,0 +1,233 @@
#include <boot/protocols/limine.h>
#include <boot/binfo.h>
#include <types.h>
#include <debug.h>
#include <string.h>
#include "../../kernel.h"
void init_limine();
static volatile struct limine_entry_point_request EntryPointRequest = {
.id = LIMINE_ENTRY_POINT_REQUEST,
.revision = 0,
.response = NULL,
.entry = init_limine};
static volatile struct limine_bootloader_info_request BootloaderInfoRequest = {
.id = LIMINE_BOOTLOADER_INFO_REQUEST,
.revision = 0};
static volatile struct limine_terminal_request TerminalRequest = {
.id = LIMINE_TERMINAL_REQUEST,
.revision = 0};
static volatile struct limine_framebuffer_request FramebufferRequest = {
.id = LIMINE_FRAMEBUFFER_REQUEST,
.revision = 0};
static volatile struct limine_memmap_request MemmapRequest = {
.id = LIMINE_MEMMAP_REQUEST,
.revision = 0};
static volatile struct limine_kernel_address_request KernelAddressRequest = {
.id = LIMINE_KERNEL_ADDRESS_REQUEST,
.revision = 0};
static volatile struct limine_rsdp_request RsdpRequest = {
.id = LIMINE_RSDP_REQUEST,
.revision = 0};
static volatile struct limine_kernel_file_request KernelFileRequest = {
.id = LIMINE_KERNEL_FILE_REQUEST,
.revision = 0};
static volatile struct limine_module_request ModuleRequest = {
.id = LIMINE_MODULE_REQUEST,
.revision = 0};
void init_limine()
{
struct BootInfo binfo;
struct limine_bootloader_info_response *BootloaderInfoResponse = BootloaderInfoRequest.response;
info("Bootloader: %s %s", BootloaderInfoResponse->name, BootloaderInfoResponse->version);
struct limine_terminal_response *TerminalResponse = TerminalRequest.response;
if (TerminalResponse == NULL || TerminalResponse->terminal_count < 1)
{
warn("No terminal available.");
while (1)
asmv("hlt");
}
TerminalResponse->write(TerminalResponse->terminals[0], "Please wait... ", 15);
struct limine_framebuffer_response *FrameBufferResponse = FramebufferRequest.response;
struct limine_memmap_response *MemmapResponse = MemmapRequest.response;
struct limine_kernel_address_response *KernelAddressResponse = KernelAddressRequest.response;
struct limine_rsdp_response *RsdpResponse = RsdpRequest.response;
struct limine_kernel_file_response *KernelFileResponse = KernelFileRequest.response;
struct limine_module_response *ModuleResponse = ModuleRequest.response;
if (FrameBufferResponse == NULL || FrameBufferResponse->framebuffer_count < 1)
{
error("No framebuffer available [%p;%ld]", FrameBufferResponse,
(FrameBufferResponse == NULL) ? 0 : FrameBufferResponse->framebuffer_count);
TerminalResponse->write(TerminalResponse->terminals[0], "No framebuffer available", 24);
while (1)
asmv("hlt");
}
if (MemmapResponse == NULL || MemmapResponse->entry_count < 1)
{
error("No memory map available [%p;%ld]", MemmapResponse,
(MemmapResponse == NULL) ? 0 : MemmapResponse->entry_count);
TerminalResponse->write(TerminalResponse->terminals[0], "No memory map available", 23);
while (1)
asmv("hlt");
}
if (KernelAddressResponse == NULL)
{
error("No kernel address available [%p]", KernelAddressResponse);
TerminalResponse->write(TerminalResponse->terminals[0], "No kernel address available", 27);
while (1)
asmv("hlt");
}
if (RsdpResponse == NULL || RsdpResponse->address == 0)
{
error("No RSDP address available [%p;%p]", RsdpResponse,
(RsdpResponse == NULL) ? 0 : RsdpResponse->address);
TerminalResponse->write(TerminalResponse->terminals[0], "No RSDP address available", 25);
while (1)
asmv("hlt");
}
if (KernelFileResponse == NULL || KernelFileResponse->kernel_file == NULL)
{
error("No kernel file available [%p;%p]", KernelFileResponse,
(KernelFileResponse == NULL) ? 0 : KernelFileResponse->kernel_file);
TerminalResponse->write(TerminalResponse->terminals[0], "No kernel file available", 24);
while (1)
asmv("hlt");
}
if (ModuleResponse == NULL || ModuleResponse->module_count < 1)
{
error("No module information available [%p;%ld]", ModuleResponse,
(ModuleResponse == NULL) ? 0 : ModuleResponse->module_count);
TerminalResponse->write(TerminalResponse->terminals[0], "No module information available", 31);
while (1)
asmv("hlt");
}
for (uint64_t i = 0; i < FrameBufferResponse->framebuffer_count; i++)
{
struct limine_framebuffer *framebuffer = FrameBufferResponse->framebuffers[i];
binfo.Framebuffer[i].BaseAddress = framebuffer->address - 0xffff800000000000;
binfo.Framebuffer[i].Width = framebuffer->width;
binfo.Framebuffer[i].Height = framebuffer->height;
binfo.Framebuffer[i].Pitch = framebuffer->pitch;
binfo.Framebuffer[i].BitsPerPixel = framebuffer->bpp;
binfo.Framebuffer[i].MemoryModel = framebuffer->memory_model;
binfo.Framebuffer[i].RedMaskSize = framebuffer->red_mask_size;
binfo.Framebuffer[i].RedMaskShift = framebuffer->red_mask_shift;
binfo.Framebuffer[i].GreenMaskSize = framebuffer->green_mask_size;
binfo.Framebuffer[i].GreenMaskShift = framebuffer->green_mask_shift;
binfo.Framebuffer[i].BlueMaskSize = framebuffer->blue_mask_size;
binfo.Framebuffer[i].BlueMaskShift = framebuffer->blue_mask_shift;
binfo.Framebuffer[i].ExtendedDisplayIdentificationData = framebuffer->edid;
binfo.Framebuffer[i].EDIDSize = framebuffer->edid_size;
debug("Framebuffer %d: %dx%d %d bpp", i, framebuffer->width, framebuffer->height, framebuffer->bpp);
debug("More info:\nAddress: %p\nPitch: %ld\nMemoryModel: %d\nRedMaskSize: %d\nRedMaskShift: %d\nGreenMaskSize: %d\nGreenMaskShift: %d\nBlueMaskSize: %d\nBlueMaskShift: %d\nEDID: %p\nEDIDSize: %d",
framebuffer->address - 0xffff800000000000, framebuffer->pitch, framebuffer->memory_model, framebuffer->red_mask_size, framebuffer->red_mask_shift, framebuffer->green_mask_size, framebuffer->green_mask_shift, framebuffer->blue_mask_size, framebuffer->blue_mask_shift, framebuffer->edid, framebuffer->edid_size);
}
binfo.Memory.Entries = MemmapResponse->entry_count;
for (uint64_t i = 0; i < MemmapResponse->entry_count; i++)
{
if (MemmapResponse->entry_count > MAX_MEMORY_ENTRIES)
{
warn("Too many memory entries, skipping the rest...");
break;
}
struct limine_memmap_entry *entry = MemmapResponse->entries[i];
binfo.Memory.Size += entry->length;
switch (entry->type)
{
case LIMINE_MEMMAP_USABLE:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = Usable;
break;
case LIMINE_MEMMAP_RESERVED:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = Reserved;
break;
case LIMINE_MEMMAP_ACPI_RECLAIMABLE:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = ACPIReclaimable;
break;
case LIMINE_MEMMAP_ACPI_NVS:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = ACPINVS;
break;
case LIMINE_MEMMAP_BAD_MEMORY:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = BadMemory;
break;
case LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = BootloaderReclaimable;
break;
case LIMINE_MEMMAP_KERNEL_AND_MODULES:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = KernelAndModules;
break;
case LIMINE_MEMMAP_FRAMEBUFFER:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = Framebuffer;
break;
default:
binfo.Memory.Entry[i].BaseAddress = (void *)entry->base;
binfo.Memory.Entry[i].Length = entry->length;
binfo.Memory.Entry[i].Type = Unknown;
break;
}
}
for (uint64_t i = 0; i < ModuleResponse->module_count; i++)
{
if (i > MAX_MODULES)
{
warn("Too many modules, skipping the rest...");
break;
}
binfo.Modules[i].Address = ModuleResponse->modules[i]->address - 0xffff800000000000;
strcpy(binfo.Modules[i].Path, ModuleResponse->modules[i]->path);
strcpy(binfo.Modules[i].CommandLine, ModuleResponse->modules[i]->cmdline);
binfo.Modules[i].Size = ModuleResponse->modules[i]->size;
debug("Module %d:\nAddress: %p\nPath: %s\nCommand Line: %s\nSize: %ld", i,
ModuleResponse->modules[i]->address - 0xffff800000000000, ModuleResponse->modules[i]->path,
ModuleResponse->modules[i]->cmdline, ModuleResponse->modules[i]->size);
}
binfo.RSDP = (struct RSDPInfo *)(RsdpResponse->address - 0xffff800000000000);
trace("RSDP: %p(%p) [Signature: %.8s] [OEM: %.6s]",
RsdpResponse->address, binfo.RSDP, binfo.RSDP->Signature, binfo.RSDP->OEMID);
binfo.Kernel.PhysicalBase = (void *)KernelAddressResponse->physical_base;
binfo.Kernel.VirtualBase = (void *)KernelAddressResponse->virtual_base;
strcpy(binfo.Kernel.CommandLine, KernelFileResponse->kernel_file->cmdline);
binfo.Kernel.Size = KernelFileResponse->kernel_file->size;
trace("Kernel physical address: %p", KernelAddressResponse->physical_base);
trace("Kernel virtual address: %p", KernelAddressResponse->virtual_base);
strcpy(binfo.Bootloader.Name, BootloaderInfoResponse->name);
strcpy(binfo.Bootloader.Version, BootloaderInfoResponse->version);
// Call kernel entry point
kernel_entry(&binfo);
}

View File

@ -15,6 +15,13 @@ SECTIONS
_kernel_text_end = ALIGN(CONSTANT(MAXPAGESIZE));
. += CONSTANT(MAXPAGESIZE);
.data :
{
*(.data .data.*)
}
_kernel_data_end = ALIGN(CONSTANT(MAXPAGESIZE));
. += CONSTANT(MAXPAGESIZE);
.rodata :
{
*(.rodata .rodata.*)
@ -22,11 +29,6 @@ SECTIONS
_kernel_rodata_end = ALIGN(CONSTANT(MAXPAGESIZE));
. += CONSTANT(MAXPAGESIZE);
.data :
{
*(.data .data.*)
}
.bss :
{
*(COMMON)

View File

85
core/Debugger.cpp Normal file
View File

@ -0,0 +1,85 @@
#include <debug.h>
#include <uart.hpp>
#include <printf.h>
using namespace UniversalAsynchronousReceiverTransmitter;
static inline void uart_wrapper(char c, void *unused)
{
UART(COM1).Write(c);
(void)unused;
}
static inline void WritePrefix(DebugLevel Level, const char *File, int Line, const char *Function)
{
const char *DbgLvlString;
switch (Level)
{
case DebugLevelError:
DbgLvlString = "ERROR";
break;
case DebugLevelWarning:
DbgLvlString = "WARN ";
break;
case DebugLevelInfo:
DbgLvlString = "INFO ";
break;
case DebugLevelDebug:
DbgLvlString = "DEBUG";
break;
case DebugLevelTrace:
DbgLvlString = "TRACE";
break;
case DebugLevelFixme:
DbgLvlString = "FIXME";
break;
default:
DbgLvlString = "UNKNW";
break;
}
fctprintf(uart_wrapper, nullptr, "%s|%s->%s:%d: ", DbgLvlString, File, Function, Line);
}
namespace SysDbg
{
void Write(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{
WritePrefix(Level, File, Line, Function);
va_list args;
va_start(args, Format);
vfctprintf(uart_wrapper, nullptr, Format, args);
va_end(args);
}
void WriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{
WritePrefix(Level, File, Line, Function);
va_list args;
va_start(args, Format);
vfctprintf(uart_wrapper, nullptr, Format, args);
va_end(args);
uart_wrapper('\n', nullptr);
}
}
// C compatibility
extern "C" void SysDbgWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{
WritePrefix(Level, File, Line, Function);
va_list args;
va_start(args, Format);
vfctprintf(uart_wrapper, nullptr, Format, args);
va_end(args);
}
// C compatibility
extern "C" void SysDbgWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...)
{
WritePrefix(Level, File, Line, Function);
va_list args;
va_start(args, Format);
vfctprintf(uart_wrapper, nullptr, Format, args);
va_end(args);
uart_wrapper('\n', nullptr);
}

View File

@ -0,0 +1,205 @@
#include "Xalloc.hpp"
namespace Xalloc
{
class SmartSMAPClass
{
private:
AllocatorV1 *allocator = nullptr;
public:
SmartSMAPClass(AllocatorV1 *allocator)
{
this->allocator = allocator;
this->allocator->Xstac();
}
~SmartSMAPClass() { this->allocator->Xclac(); }
};
#define SmartSMAP SmartSMAPClass XALLOC_CONCAT(SmartSMAP##_, __COUNTER__)(this)
AllocatorV1::AllocatorV1(void *Address, bool UserMode, bool SMAPEnabled)
{
SmartSMAP;
void *Position = Address;
UserMapping = UserMode;
SMAPUsed = SMAPEnabled;
for (Xuint64_t i = 0; i < 0x20; i++)
{
void *Page = Xalloc_REQUEST_PAGE();
if (UserMapping)
Xalloc_MAP_MEMORY(Position, Page, Xalloc_MAP_MEMORY_READ_WRITE | Xalloc_MAP_MEMORY_USER);
else
Xalloc_MAP_MEMORY(Position, Page, Xalloc_MAP_MEMORY_READ_WRITE);
Xalloc_trace("Preallocate Heap Memory (%#llx-%#llx [%#llx])...", Position, (Xuint64_t)Position + Xalloc_PAGE_SIZE, Page);
Position = (void *)((Xuint64_t)Position + Xalloc_PAGE_SIZE);
}
Xuint64_t HeapLength = 16 * Xalloc_PAGE_SIZE;
this->HeapStart = Address;
this->HeapEnd = (void *)((Xuint64_t)this->HeapStart + HeapLength);
HeapSegment *StartSegment = (HeapSegment *)Address;
StartSegment->Length = HeapLength - sizeof(HeapSegment);
StartSegment->Next = nullptr;
StartSegment->Last = nullptr;
StartSegment->IsFree = true;
this->LastSegment = StartSegment;
}
AllocatorV1::~AllocatorV1()
{
SmartSMAP;
Xalloc_trace("Destructor not implemented yet.");
}
void AllocatorV1::ExpandHeap(Xuint64_t Length)
{
if (Length % Xalloc_PAGE_SIZE)
{
Length -= Length % Xalloc_PAGE_SIZE;
Length += Xalloc_PAGE_SIZE;
}
Xuint64_t PageCount = Length / Xalloc_PAGE_SIZE;
HeapSegment *NewSegment = (HeapSegment *)this->HeapEnd;
for (Xuint64_t i = 0; i < PageCount; i++)
{
void *Page = Xalloc_REQUEST_PAGE();
if (UserMapping)
Xalloc_MAP_MEMORY(this->HeapEnd, Page, Xalloc_MAP_MEMORY_READ_WRITE | Xalloc_MAP_MEMORY_USER);
else
Xalloc_MAP_MEMORY(this->HeapEnd, Page, Xalloc_MAP_MEMORY_READ_WRITE);
// Xalloc_trace("Expanding Heap Memory (%#llx-%#llx [%#llx])...", this->HeapEnd, (Xuint64_t)this->HeapEnd + Xalloc_PAGE_SIZE, Page);
this->HeapEnd = (void *)((Xuint64_t)this->HeapEnd + Xalloc_PAGE_SIZE);
}
NewSegment->IsFree = true;
NewSegment->Last = this->LastSegment;
this->LastSegment->Next = NewSegment;
this->LastSegment = NewSegment;
NewSegment->Next = nullptr;
NewSegment->Length = Length - sizeof(HeapSegment);
NewSegment->CombineBackward(this->LastSegment);
}
void *AllocatorV1::Malloc(Xuint64_t Size)
{
SmartSMAP;
if (this->HeapStart == nullptr)
{
Xalloc_err("Memory allocation not initialized yet!");
return 0;
}
if (Size < 0x10)
{
// Xalloc_warn("Allocation size is too small, using 0x10 instead!");
Size = 0x10;
}
// #ifdef DEBUG
// if (Size < 1024)
// debug("Allocating %dB", Size);
// else if (TO_KB(Size) < 1024)
// debug("Allocating %dKB", TO_KB(Size));
// else if (TO_MB(Size) < 1024)
// debug("Allocating %dMB", TO_MB(Size));
// else if (TO_GB(Size) < 1024)
// debug("Allocating %dGB", TO_GB(Size));
// #endif
if (Size % 0x10 > 0) // it is not a multiple of 0x10
{
Size -= (Size % 0x10);
Size += 0x10;
}
if (Size == 0)
{
return nullptr;
}
HeapSegment *CurrentSegment = (HeapSegment *)this->HeapStart;
while (true)
{
if (CurrentSegment->IsFree)
{
if (CurrentSegment->Length > Size)
{
CurrentSegment->Split(Size, this->LastSegment);
CurrentSegment->IsFree = false;
return (void *)((Xuint64_t)CurrentSegment + sizeof(HeapSegment));
}
if (CurrentSegment->Length == Size)
{
CurrentSegment->IsFree = false;
return (void *)((Xuint64_t)CurrentSegment + sizeof(HeapSegment));
}
}
if (CurrentSegment->Next == nullptr)
break;
CurrentSegment = CurrentSegment->Next;
}
ExpandHeap(Size);
return this->Malloc(Size);
}
void AllocatorV1::Free(void *Address)
{
SmartSMAP;
if (this->HeapStart == nullptr)
{
Xalloc_err("Memory allocation not initialized yet!");
return;
}
HeapSegment *Segment = (HeapSegment *)Address - 1;
Segment->IsFree = true;
Segment->CombineForward(this->LastSegment);
Segment->CombineBackward(this->LastSegment);
}
void *AllocatorV1::Calloc(Xuint64_t NumberOfBlocks, Xuint64_t Size)
{
SmartSMAP;
if (this->HeapStart == nullptr)
{
Xalloc_err("Memory allocation not initialized yet!");
return 0;
}
if (Size < 0x10)
{
// Xalloc_warn("Allocation size is too small, using 0x10 instead!");
Size = 0x10;
}
void *Block = this->Malloc(NumberOfBlocks * Size);
if (Block)
Xmemset(Block, 0, NumberOfBlocks * Size);
return Block;
}
void *AllocatorV1::Realloc(void *Address, Xuint64_t Size)
{
SmartSMAP;
if (this->HeapStart == nullptr)
{
Xalloc_err("Memory allocation not initialized yet!");
return 0;
}
if (!Address && Size == 0)
{
this->Free(Address);
return nullptr;
}
else if (!Address)
{
return this->Calloc(Size, sizeof(char));
}
if (Size < 0x10)
{
// Xalloc_warn("Allocation size is too small, using 0x10 instead!");
Size = 0x10;
}
void *newAddress = this->Calloc(Size, sizeof(char));
Xmemcpy(newAddress, Address, Size);
return newAddress;
}
}

View File

@ -0,0 +1,180 @@
#pragma once
#include <memory.hpp>
#include <debug.h>
// Functions defines
// Page allocation functions
#define Xalloc_REQUEST_PAGE() KernelAllocator.RequestPage()
#define Xalloc_REQUEST_PAGES(Pages) KernelAllocator.RequestPages(Pages)
#define Xalloc_FREE_PAGE(Address) KernelAllocator.FreePage(Address)
#define Xalloc_FREE_PAGES(Address, Pages) KernelAllocator.FreePages(Address, Pages)
#define Xalloc_MAP_MEMORY(VirtualAddress, PhysicalAddress, Flags) Memory::Virtual(KernelPageTable).Map(VirtualAddress, PhysicalAddress, Flags)
#define Xalloc_UNMAP_MEMORY(VirtualAddress) Memory::Virtual(KernelPageTable).Unmap(VirtualAddress)
#define Xalloc_MAP_MEMORY_READ_WRITE Memory::PTFlag::RW
#define Xalloc_MAP_MEMORY_USER Memory::PTFlag::US
#define Xalloc_PAGE_SIZE PAGE_SIZE
#define Xalloc_trace(m, ...) trace(m, ##__VA_ARGS__)
#define Xalloc_warn(m, ...) warn(m, ##__VA_ARGS__)
#define Xalloc_err(m, ...) error(m, ##__VA_ARGS__)
#define XALLOC_CONCAT(x, y) x##y
typedef long unsigned Xuint64_t;
namespace Xalloc
{
class AllocatorV1
{
private:
struct HeapSegment
{
Xuint64_t Length;
HeapSegment *Next;
HeapSegment *Last;
bool IsFree;
HeapSegment *Split(Xuint64_t SplitLength, HeapSegment *LastSegment)
{
if (SplitLength < 0x10)
return nullptr;
int64_t SplitSegmentLength = Length - SplitLength - (sizeof(HeapSegment));
if (SplitSegmentLength < 0x10)
return nullptr;
HeapSegment *NewSplitHdr = (HeapSegment *)((Xuint64_t)this + SplitLength + sizeof(HeapSegment));
Next->Last = NewSplitHdr;
NewSplitHdr->Next = Next;
Next = NewSplitHdr;
NewSplitHdr->Last = this;
NewSplitHdr->Length = SplitSegmentLength;
NewSplitHdr->IsFree = IsFree;
Length = SplitLength;
if (LastSegment == this)
LastSegment = NewSplitHdr;
return NewSplitHdr;
}
void CombineForward(HeapSegment *LastSegment)
{
if (Next == nullptr)
return;
if (Next->IsFree == false)
return;
if (Next == LastSegment)
LastSegment = this;
if (Next->Next != nullptr)
Next->Next->Last = this;
Length = Length + Next->Length + sizeof(HeapSegment);
Next = Next->Next;
}
void CombineBackward(HeapSegment *LastSegment)
{
if (Last != nullptr && Last->IsFree)
Last->CombineForward(LastSegment);
}
} __attribute__((aligned(16)));
void *HeapStart = nullptr;
void *HeapEnd = nullptr;
HeapSegment *LastSegment = nullptr;
bool UserMapping = false;
bool SMAPUsed = false;
void ExpandHeap(Xuint64_t Length);
// TODO: Change memcpy with an optimized version
static inline void *Xmemcpy(void *__restrict__ Destination, const void *__restrict__ Source, Xuint64_t Length)
{
unsigned char *dst = (unsigned char *)Destination;
const unsigned char *src = (const unsigned char *)Source;
for (Xuint64_t i = 0; i < Length; i++)
dst[i] = src[i];
return Destination;
}
// TODO: Change memset with an optimized version
static inline void *Xmemset(void *__restrict__ Destination, int Data, Xuint64_t Length)
{
unsigned char *Buffer = (unsigned char *)Destination;
for (Xuint64_t i = 0; i < Length; i++)
Buffer[i] = (unsigned char)Data;
return Destination;
}
public:
inline void Xstac()
{
if (this->SMAPUsed)
{
#if defined(__amd64__) || defined(__i386__)
asm volatile("stac" ::
: "cc");
#endif
}
}
inline void Xclac()
{
if (this->SMAPUsed)
{
#if defined(__amd64__) || defined(__i386__)
asm volatile("clac" ::
: "cc");
#endif
}
}
/**
* @brief Construct a new Allocator V1 object
*
* @param Address Virtual address to allocate.
* @param UserMode Map the new pages with USER flag?
* @param SMAPEnabled Does the kernel has Supervisor Mode Access Prevention enabled?
*/
AllocatorV1(void *Address, bool UserMode, bool SMAPEnabled);
/**
* @brief Destroy the Allocator V 1 object
*
*/
~AllocatorV1();
/**
* @brief Allocate a new memory block
*
* @param Size Size of the block to allocate.
* @return void* Pointer to the allocated block.
*/
void *Malloc(Xuint64_t Size);
/**
* @brief Free a previously allocated block
*
* @param Address Address of the block to free.
*/
void Free(void *Address);
/**
* @brief Allocate a new memory block
*
* @param NumberOfBlocks Number of blocks to allocate.
* @param Size Size of the block to allocate.
* @return void* Pointer to the allocated block.
*/
void *Calloc(Xuint64_t NumberOfBlocks, Xuint64_t Size);
/**
* @brief Reallocate a previously allocated block
*
* @param Address Address of the block to reallocate.
* @param Size New size of the block.
* @return void* Pointer to the reallocated block.
*/
void *Realloc(void *Address, Xuint64_t Size);
};
}

215
core/Memory/Memory.cpp Normal file
View File

@ -0,0 +1,215 @@
#include <memory.hpp>
#include <string.h>
#include <debug.h>
#include "HeapAllocators/Xalloc.hpp"
#include "../lib/liballoc_1_1.h"
using namespace Memory;
Physical KernelAllocator;
PageTable *KernelPageTable = nullptr;
enum MemoryAllocatorType
{
None,
Pages,
XallocV1,
liballoc11
};
static MemoryAllocatorType AllocatorType = MemoryAllocatorType::None;
Xalloc::AllocatorV1 *XallocV1Allocator = nullptr;
#ifdef DEBUG
void tracepagetable(PageTable *pt)
{
for (int i = 0; i < 512; i++)
{
if (pt->Entries[i].Value.Present)
debug("Entry %d: %x %x %x %x %x %x %x %x %x %x %x %p-%#lx", i,
pt->Entries[i].Value.Present, pt->Entries[i].Value.ReadWrite,
pt->Entries[i].Value.UserSupervisor, pt->Entries[i].Value.WriteThrough,
pt->Entries[i].Value.CacheDisable, pt->Entries[i].Value.Accessed,
pt->Entries[i].Value.Dirty, pt->Entries[i].Value.PageSize,
pt->Entries[i].Value.Global, pt->Entries[i].Value.PageAttributeTable,
pt->Entries[i].Value.ExecuteDisable, pt->Entries[i].GetAddress(),
pt->Entries[i].Value);
}
}
#endif
void InitializeMemoryManagement(BootInfo *Info)
{
trace("Initializing Physical Memory Manager");
KernelAllocator = Physical();
KernelAllocator.Init(Info);
debug("Memory Info: %dMB / %dMB (%dMB reserved)",
TO_MB(KernelAllocator.GetUsedMemory()),
TO_MB(KernelAllocator.GetTotalMemory()),
TO_MB(KernelAllocator.GetReservedMemory()));
AllocatorType = MemoryAllocatorType::Pages;
trace("Initializing Virtual Memory Manager");
KernelPageTable = (PageTable *)KernelAllocator.RequestPage();
memset(KernelPageTable, 0, PAGE_SIZE);
Virtual kva = Virtual(KernelPageTable);
uint64_t KernelStart = (uint64_t)&_kernel_start;
uint64_t KernelTextEnd = (uint64_t)&_kernel_text_end;
uint64_t KernelDataEnd = (uint64_t)&_kernel_data_end;
uint64_t KernelRoDataEnd = (uint64_t)&_kernel_rodata_end;
uint64_t KernelEnd = (uint64_t)&_kernel_end;
uint64_t VirtualOffsetNormalVMA = NORMAL_VMA_OFFSET;
uint64_t BaseKernelMapAddress = (uint64_t)Info->Kernel.PhysicalBase;
for (uint64_t t = 0; t < Info->Memory.Size; t += PAGE_SIZE)
{
kva.Map((void *)t, (void *)t, PTFlag::RW);
kva.Map((void *)VirtualOffsetNormalVMA, (void *)t, PTFlag::RW);
VirtualOffsetNormalVMA += PAGE_SIZE;
}
/* Mapping Framebuffer address */
int itrfb = 0;
while (1)
{
if (!Info->Framebuffer[itrfb].BaseAddress)
break;
for (uint64_t fb_base = (uint64_t)Info->Framebuffer[itrfb].BaseAddress;
fb_base < ((uint64_t)Info->Framebuffer[itrfb].BaseAddress + ((Info->Framebuffer[itrfb].Pitch * Info->Framebuffer[itrfb].Height) + PAGE_SIZE));
fb_base += PAGE_SIZE)
kva.Map((void *)(fb_base + NORMAL_VMA_OFFSET), (void *)fb_base, PTFlag::RW | PTFlag::US);
itrfb++;
}
/* Kernel mapping */
for (uint64_t k = KernelStart; k < KernelTextEnd; k += PAGE_SIZE)
{
kva.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::RW);
KernelAllocator.LockPage((void *)BaseKernelMapAddress);
BaseKernelMapAddress += PAGE_SIZE;
}
for (uint64_t k = KernelTextEnd; k < KernelDataEnd; k += PAGE_SIZE)
{
kva.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::RW);
KernelAllocator.LockPage((void *)BaseKernelMapAddress);
BaseKernelMapAddress += PAGE_SIZE;
}
for (uint64_t k = KernelDataEnd; k < KernelRoDataEnd; k += PAGE_SIZE)
{
kva.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::P);
KernelAllocator.LockPage((void *)BaseKernelMapAddress);
BaseKernelMapAddress += PAGE_SIZE;
}
for (uint64_t k = KernelRoDataEnd; k < KernelEnd; k += PAGE_SIZE)
{
kva.Map((void *)k, (void *)BaseKernelMapAddress, PTFlag::RW);
KernelAllocator.LockPage((void *)BaseKernelMapAddress);
BaseKernelMapAddress += PAGE_SIZE;
}
debug("\nStart: %#llx - Text End: %#llx - RoEnd: %#llx - End: %#llx\nStart Physical: %#llx - End Physical: %#llx",
KernelStart, KernelTextEnd, KernelRoDataEnd, KernelEnd, Info->Kernel.PhysicalBase, BaseKernelMapAddress - PAGE_SIZE);
/* KernelStart KernelTextEnd KernelRoDataEnd KernelEnd
Kernel Start & Text Start ------ Text End ------ Kernel Rodata End ------ Kernel Data End & Kernel End
*/
trace("Applying new page table from address %p", KernelPageTable);
#ifdef DEBUG
tracepagetable(KernelPageTable);
#endif
#if defined(__amd64__) || defined(__i386__)
asm volatile("mov %0, %%cr3" ::"r"(KernelPageTable));
#elif defined(__aarch64__)
asm volatile("msr ttbr0_el1, %0" ::"r"(KernelPageTable));
#endif
if (strstr(Info->Kernel.CommandLine, "xallocv1"))
{
XallocV1Allocator = new Xalloc::AllocatorV1((void *)KERNEL_HEAP_BASE, false, false);
AllocatorType = MemoryAllocatorType::XallocV1;
trace("XallocV1 Allocator initialized (%p)", XallocV1Allocator);
}
else if (strstr(Info->Kernel.CommandLine, "liballoc11"))
{
AllocatorType = MemoryAllocatorType::liballoc11;
}
}
void *HeapMalloc(uint64_t Size)
{
switch (AllocatorType)
{
case MemoryAllocatorType::Pages:
return KernelAllocator.RequestPages(TO_PAGES(Size));
case MemoryAllocatorType::XallocV1:
return XallocV1Allocator->Malloc(Size);
case MemoryAllocatorType::liballoc11:
return PREFIX(malloc)(Size);
default:
throw;
}
}
void *HeapCalloc(uint64_t n, uint64_t Size)
{
switch (AllocatorType)
{
case MemoryAllocatorType::Pages:
return KernelAllocator.RequestPages(TO_PAGES(n * Size));
case MemoryAllocatorType::XallocV1:
return XallocV1Allocator->Calloc(n, Size);
case MemoryAllocatorType::liballoc11:
return PREFIX(calloc)(n, Size);
default:
throw;
}
}
void *HeapRealloc(void *Address, uint64_t Size)
{
switch (AllocatorType)
{
case MemoryAllocatorType::Pages:
return KernelAllocator.RequestPages(TO_PAGES(Size)); // WARNING: Potential memory leak
case MemoryAllocatorType::XallocV1:
return XallocV1Allocator->Realloc(Address, Size);
case MemoryAllocatorType::liballoc11:
return PREFIX(realloc)(Address, Size);
default:
throw;
}
}
void HeapFree(void *Address)
{
switch (AllocatorType)
{
case MemoryAllocatorType::Pages:
KernelAllocator.FreePage(Address); // WARNING: Potential memory leak
break;
case MemoryAllocatorType::XallocV1:
XallocV1Allocator->Free(Address);
break;
case MemoryAllocatorType::liballoc11:
PREFIX(free)
(Address);
break;
default:
throw;
}
}
void *operator new(uint64_t Size) { return HeapMalloc(Size); }
void *operator new[](uint64_t Size) { return HeapMalloc(Size); }
void operator delete(void *Pointer) { HeapFree(Pointer); }
void operator delete[](void *Pointer) { HeapFree(Pointer); }
void operator delete(void *Pointer, long unsigned int Size) { HeapFree(Pointer); }
void operator delete[](void *Pointer, long unsigned int Size) { HeapFree(Pointer); }

View File

@ -0,0 +1,266 @@
#include <memory.hpp>
#include <debug.h>
namespace Memory
{
uint64_t Physical::GetTotalMemory()
{
SMARTLOCK(this->MemoryLock);
return this->TotalMemory;
}
uint64_t Physical::GetFreeMemory()
{
SMARTLOCK(this->MemoryLock);
return this->FreeMemory;
}
uint64_t Physical::GetReservedMemory()
{
SMARTLOCK(this->MemoryLock);
return this->ReservedMemory;
}
uint64_t Physical::GetUsedMemory()
{
SMARTLOCK(this->MemoryLock);
return this->UsedMemory;
}
bool Physical::SwapPage(void *Address)
{
fixme("%p", Address);
return false;
}
bool Physical::SwapPages(void *Address, uint64_t PageCount)
{
for (uint64_t i = 0; i < PageCount; i++)
if (!this->SwapPage((void *)((uint64_t)Address + (i * PAGE_SIZE))))
return false;
return false;
}
bool Physical::UnswapPage(void *Address)
{
fixme("%p", Address);
return false;
}
bool Physical::UnswapPages(void *Address, uint64_t PageCount)
{
for (uint64_t i = 0; i < PageCount; i++)
if (!this->UnswapPage((void *)((uint64_t)Address + (i * PAGE_SIZE))))
return false;
return false;
}
void *Physical::RequestPage()
{
SMARTLOCK(this->MemoryLock);
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
{
if (PageBitmap[PageBitmapIndex] == true)
continue;
this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE));
return (void *)(PageBitmapIndex * PAGE_SIZE);
}
if (this->SwapPage((void *)(PageBitmapIndex * PAGE_SIZE)))
{
this->LockPage((void *)(PageBitmapIndex * PAGE_SIZE));
return (void *)(PageBitmapIndex * PAGE_SIZE);
}
error("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", TO_MB(FreeMemory), TO_MB(UsedMemory), TO_MB(ReservedMemory));
while (1)
CPU::Halt();
return nullptr;
}
void *Physical::RequestPages(uint64_t Count)
{
SMARTLOCK(this->MemoryLock);
for (; PageBitmapIndex < PageBitmap.Size * 8; PageBitmapIndex++)
{
if (PageBitmap[PageBitmapIndex] == true)
continue;
for (uint64_t Index = PageBitmapIndex; Index < PageBitmap.Size * 8; Index++)
{
if (PageBitmap[Index] == true)
continue;
for (uint64_t i = 0; i < Count; i++)
if (PageBitmap[Index + i] == true)
goto NextPage;
this->LockPages((void *)(Index * PAGE_SIZE), Count);
return (void *)(Index * PAGE_SIZE);
NextPage:
Index += Count;
continue;
}
}
if (this->SwapPages((void *)(PageBitmapIndex * PAGE_SIZE), Count))
{
this->LockPages((void *)(PageBitmapIndex * PAGE_SIZE), Count);
return (void *)(PageBitmapIndex * PAGE_SIZE);
}
error("Out of memory! (Free: %ldMB; Used: %ldMB; Reserved: %ldMB)", TO_MB(FreeMemory), TO_MB(UsedMemory), TO_MB(ReservedMemory));
while (1)
CPU::Halt();
return nullptr;
}
void Physical::FreePage(void *Address)
{
SMARTLOCK(this->MemoryLock);
if (Address == nullptr)
{
warn("Null pointer passed to FreePage.");
return;
}
uint64_t Index = (uint64_t)Address / PAGE_SIZE;
if (PageBitmap[Index] == false)
return;
if (PageBitmap.Set(Index, false))
{
FreeMemory += PAGE_SIZE;
UsedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index)
PageBitmapIndex = Index;
}
}
void Physical::FreePages(void *Address, uint64_t Count)
{
if (Address == nullptr || Count == 0)
{
warn("%s%s passed to FreePages.", Address == nullptr ? "Null pointer" : "", Count == 0 ? "Zero count" : "");
return;
}
for (uint64_t t = 0; t < Count; t++)
this->FreePage((void *)((uint64_t)Address + (t * PAGE_SIZE)));
}
void Physical::LockPage(void *Address)
{
if (Address == nullptr)
warn("Trying to lock null address.");
uint64_t Index = (uint64_t)Address / PAGE_SIZE;
if (PageBitmap[Index] == true)
return;
if (PageBitmap.Set(Index, true))
{
FreeMemory -= PAGE_SIZE;
UsedMemory += PAGE_SIZE;
}
}
void Physical::LockPages(void *Address, uint64_t PageCount)
{
if (Address == nullptr || PageCount == 0)
warn("Trying to lock %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
for (uint64_t i = 0; i < PageCount; i++)
this->LockPage((void *)((uint64_t)Address + (i * PAGE_SIZE)));
}
void Physical::ReservePage(void *Address)
{
if (Address == nullptr)
warn("Trying to reserve null address.");
uint64_t Index = (uint64_t)Address / PAGE_SIZE;
if (PageBitmap[Index] == true)
return;
if (PageBitmap.Set(Index, true))
{
FreeMemory -= PAGE_SIZE;
ReservedMemory += PAGE_SIZE;
}
}
void Physical::ReservePages(void *Address, uint64_t PageCount)
{
if (Address == nullptr || PageCount == 0)
warn("Trying to reserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
for (uint64_t t = 0; t < PageCount; t++)
this->ReservePage((void *)((uint64_t)Address + (t * PAGE_SIZE)));
}
void Physical::UnreservePage(void *Address)
{
if (Address == nullptr)
warn("Trying to unreserve null address.");
uint64_t Index = (uint64_t)Address / PAGE_SIZE;
if (PageBitmap[Index] == false)
return;
if (PageBitmap.Set(Index, false))
{
FreeMemory += PAGE_SIZE;
ReservedMemory -= PAGE_SIZE;
if (PageBitmapIndex > Index)
PageBitmapIndex = Index;
}
}
void Physical::UnreservePages(void *Address, uint64_t PageCount)
{
if (Address == nullptr || PageCount == 0)
warn("Trying to unreserve %s%s.", Address ? "null address" : "", PageCount ? "0 pages" : "");
for (uint64_t t = 0; t < PageCount; t++)
this->UnreservePage((void *)((uint64_t)Address + (t * PAGE_SIZE)));
}
void Physical::Init(BootInfo *Info)
{
SMARTLOCK(this->MemoryLock);
void *LargestFreeMemorySegment = nullptr;
uint64_t LargestFreeMemorySegmentSize = 0;
uint64_t MemorySize = Info->Memory.Size;
for (uint64_t i = 0; i < Info->Memory.Entries; i++)
if (Info->Memory.Entry[i].Type == Usable)
if (Info->Memory.Entry[i].Length > LargestFreeMemorySegmentSize)
{
LargestFreeMemorySegment = (void *)Info->Memory.Entry[i].BaseAddress;
LargestFreeMemorySegmentSize = Info->Memory.Entry[i].Length;
debug("Largest free memory segment: %p (%dKB)",
(void *)Info->Memory.Entry[i].BaseAddress,
TO_KB(Info->Memory.Entry[i].Length));
}
TotalMemory = MemorySize;
FreeMemory = MemorySize;
uint64_t BitmapSize = ALIGN_UP((MemorySize / 0x1000) / 8, 0x1000);
trace("Initializing Bitmap (%p %dKB)", LargestFreeMemorySegment, TO_KB(BitmapSize));
PageBitmap.Size = BitmapSize;
PageBitmap.Buffer = (uint8_t *)LargestFreeMemorySegment;
for (uint64_t i = 0; i < BitmapSize; i++)
*(uint8_t *)(PageBitmap.Buffer + i) = 0;
this->ReservePages(0, MemorySize / PAGE_SIZE + 1);
for (uint64_t i = 0; i < Info->Memory.Entries; i++)
if (Info->Memory.Entry[i].Type == Usable)
this->UnreservePages((void *)Info->Memory.Entry[i].BaseAddress, Info->Memory.Entry[i].Length / PAGE_SIZE + 1);
this->ReservePages(0, 0x100); // Reserve between 0 and 0x100000
this->LockPages(PageBitmap.Buffer, PageBitmap.Size / PAGE_SIZE + 1);
}
Physical::Physical() {}
Physical::~Physical() {}
}

View File

@ -0,0 +1,123 @@
#include <memory.hpp>
#include <string.h>
#include <debug.h>
namespace Memory
{
void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags)
{
SMARTLOCK(this->MemoryLock);
if (!this->Table)
{
error("No page table");
return;
}
PageMapIndexer Index = PageMapIndexer((uint64_t)VirtualAddress);
PageDirectoryEntry PDE = this->Table->Entries[Index.PDP_i];
PageTable *PDP;
if (!PDE.GetFlag(PTFlag::P))
{
PDP = (PageTable *)KernelAllocator.RequestPage();
memset(PDP, 0, PAGE_SIZE);
PDE.SetAddress((uint64_t)PDP >> 12);
PDE.SetFlag(PTFlag::P, true);
PDE.AddFlag(Flags);
this->Table->Entries[Index.PDP_i] = PDE;
}
else
PDP = (PageTable *)((uint64_t)PDE.GetAddress() << 12);
PDE = PDP->Entries[Index.PD_i];
PageTable *PD;
if (!PDE.GetFlag(PTFlag::P))
{
PD = (PageTable *)KernelAllocator.RequestPage();
memset(PD, 0, PAGE_SIZE);
PDE.SetAddress((uint64_t)PD >> 12);
PDE.SetFlag(PTFlag::P, true);
PDE.AddFlag(Flags);
PDP->Entries[Index.PD_i] = PDE;
}
else
PD = (PageTable *)((uint64_t)PDE.GetAddress() << 12);
PDE = PD->Entries[Index.PT_i];
PageTable *PT;
if (!PDE.GetFlag(PTFlag::P))
{
PT = (PageTable *)KernelAllocator.RequestPage();
memset(PT, 0, PAGE_SIZE);
PDE.SetAddress((uint64_t)PT >> 12);
PDE.SetFlag(PTFlag::P, true);
PDE.AddFlag(Flags);
PD->Entries[Index.PT_i] = PDE;
}
else
PT = (PageTable *)((uint64_t)PDE.GetAddress() << 12);
PDE = PT->Entries[Index.P_i];
PDE.SetAddress((uint64_t)PhysicalAddress >> 12);
PDE.SetFlag(PTFlag::P, true);
PDE.AddFlag(Flags);
PT->Entries[Index.P_i] = PDE;
#if defined(__amd64__) || defined(__i386__)
asmv("invlpg (%0)"
:
: "r"(VirtualAddress)
: "memory");
#elif defined(__aarch64__)
asmv("dsb sy");
asmv("tlbi vae1is, %0"
:
: "r"(VirtualAddress)
: "memory");
asmv("dsb sy");
asmv("isb");
#endif
}
void Virtual::Map(void *VirtualAddress, void *PhysicalAddress, uint64_t PageCount, uint64_t Flags)
{
for (uint64_t i = 0; i < PageCount; i++)
this->Map((void *)((uint64_t)VirtualAddress + (i * PAGE_SIZE)), (void *)((uint64_t)PhysicalAddress + (i * PAGE_SIZE)), Flags);
}
void Virtual::Unmap(void *VirtualAddress)
{
SMARTLOCK(this->MemoryLock);
if (!this->Table)
{
error("No page table");
return;
}
PageMapIndexer Index = PageMapIndexer((uint64_t)VirtualAddress);
PageDirectoryEntry PDE = this->Table->Entries[Index.PDP_i];
PDE.ClearFlags();
#if defined(__amd64__) || defined(__i386__)
asmv("invlpg (%0)"
:
: "r"(VirtualAddress)
: "memory");
#elif defined(__aarch64__)
asmv("dsb sy");
asmv("tlbi vae1is, %0"
:
: "r"(VirtualAddress)
: "memory");
asmv("dsb sy");
asmv("isb");
#endif
}
void Virtual::Unmap(void *VirtualAddress, uint64_t PageCount)
{
for (uint64_t i = 0; i < PageCount; i++)
this->Unmap((void *)((uint64_t)VirtualAddress + (i * PAGE_SIZE)));
}
Virtual::Virtual(PageTable *Table) { this->Table = Table; }
Virtual::~Virtual() {}
}

58
core/StackGuard.c Normal file
View File

@ -0,0 +1,58 @@
#include <types.h>
#include <debug.h>
#ifndef STACK_CHK_GUARD_VALUE
#if UINTPTR_MAX == UINT32_MAX
#define STACK_CHK_GUARD_VALUE 0x25F6CC8D
#else
#define STACK_CHK_GUARD_VALUE 0xBADFE2EC255A8572
#endif
#endif
__attribute__((weak)) uintptr_t __stack_chk_guard = 0;
__attribute__((weak)) uintptr_t __stack_chk_guard_init(void)
{
return STACK_CHK_GUARD_VALUE;
}
static void __attribute__((constructor, no_stack_protector)) __construct_stk_chk_guard()
{
if (__stack_chk_guard == 0)
__stack_chk_guard = __stack_chk_guard_init();
}
// https://opensource.apple.com/source/xnu/xnu-1504.7.4/libkern/stack_protector.c.auto.html
// static void __guard_setup(void) __attribute__((constructor));
// static void __guard_setup(void)
// {
// read_random(__stack_chk_guard, sizeof(__stack_chk_guard));
// }
__attribute__((weak, noreturn, no_stack_protector)) void __stack_chk_fail(void)
{
error("Stack smashing detected!", false);
for (;;)
{
#if defined(__amd64__) || defined(__i386__)
asmv("hlt");
#elif defined(__aarch64__)
asmv("wfe");
#endif
}
}
// https://github.com/gcc-mirror/gcc/blob/master/libssp/ssp.c
__attribute__((weak, noreturn, no_stack_protector)) void __chk_fail(void)
{
error("Buffer overflow detected!", false);
for (;;)
{
#if defined(__amd64__) || defined(__i386__)
asmv("hlt");
#elif defined(__aarch64__)
asmv("wfe");
#endif
}
}

View File

12
include/bitmap.hpp Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <types.h>
class Bitmap
{
public:
size_t Size;
uint8_t *Buffer;
bool operator[](uint64_t index);
bool Set(uint64_t index, bool value);
bool Get(uint64_t index);
};

120
include/boot/binfo.h Normal file
View File

@ -0,0 +1,120 @@
#ifndef __FENNIX_KERNEL_BOOT_INFO_H__
#define __FENNIX_KERNEL_BOOT_INFO_H__
#include <types.h>
enum MemoryType
{
Usable,
Reserved,
ACPIReclaimable,
ACPINVS,
BadMemory,
BootloaderReclaimable,
KernelAndModules,
Framebuffer,
Unknown
};
#define MAX_FRAMEBUFFERS 16
#define MAX_MEMORY_ENTRIES 256
#define MAX_MODULES 16
struct BootInfo
{
struct FramebufferInfo
{
void *BaseAddress;
uint64_t Width;
uint64_t Height;
uint64_t Pitch;
uint16_t BitsPerPixel;
uint8_t MemoryModel;
uint8_t RedMaskSize;
uint8_t RedMaskShift;
uint8_t GreenMaskSize;
uint8_t GreenMaskShift;
uint8_t BlueMaskSize;
uint8_t BlueMaskShift;
void *ExtendedDisplayIdentificationData;
uint64_t EDIDSize;
} Framebuffer[MAX_FRAMEBUFFERS];
struct MemoryInfo
{
struct MemoryEntryInfo
{
void *BaseAddress;
uint64_t Length;
enum MemoryType Type;
} Entry[MAX_MEMORY_ENTRIES];
uint64_t Entries;
uint64_t Size;
} Memory;
struct ModuleInfo
{
void *Address;
char Path[256];
char CommandLine[256];
uint64_t Size;
} Modules[MAX_MODULES];
struct RSDPInfo
{
/**
* @brief Signature
*/
unsigned char Signature[8];
/**
* @brief Checksum
*/
uint8_t Checksum;
/**
* @brief OEM ID
*/
uint8_t OEMID[6];
/**
* @brief Revision
*/
uint8_t Revision;
/**
* @brief Address of the Root System Description Table
*/
uint32_t RSDTAddress;
/* END OF RSDP 1.0 */
/**
* @brief Length
*/
uint32_t Length;
/**
* @brief Extended System Descriptor Table
*/
uint64_t XSDTAddress;
/**
* @brief Extended checksum
*/
uint8_t ExtendedChecksum;
/**
* @brief Reserved
*/
uint8_t Reserved[3];
} __attribute__((packed)) * RSDP;
struct KernelInfo
{
void *PhysicalBase;
void *VirtualBase;
char CommandLine[256];
uint64_t Size;
} Kernel;
struct BootloaderInfo
{
char Name[256];
char Version[64];
} Bootloader;
};
#endif // !__FENNIX_KERNEL_BOOT_INFO_H__

View File

@ -0,0 +1,420 @@
#ifndef _LIMINE_H
#define _LIMINE_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include <types.h>
/* Misc */
#ifdef LIMINE_NO_POINTERS
# define LIMINE_PTR(TYPE) uint64_t
#else
# define LIMINE_PTR(TYPE) TYPE
#endif
#define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b
struct limine_uuid {
uint32_t a;
uint16_t b;
uint16_t c;
uint8_t d[8];
};
#define LIMINE_MEDIA_TYPE_GENERIC 0
#define LIMINE_MEDIA_TYPE_OPTICAL 1
#define LIMINE_MEDIA_TYPE_TFTP 2
struct limine_file {
uint64_t revision;
LIMINE_PTR(void *) address;
uint64_t size;
LIMINE_PTR(char *) path;
LIMINE_PTR(char *) cmdline;
uint32_t media_type;
uint32_t unused;
uint32_t tftp_ip;
uint32_t tftp_port;
uint32_t partition_index;
uint32_t mbr_disk_id;
struct limine_uuid gpt_disk_uuid;
struct limine_uuid gpt_part_uuid;
struct limine_uuid part_uuid;
};
/* Boot info */
#define LIMINE_BOOTLOADER_INFO_REQUEST { LIMINE_COMMON_MAGIC, 0xf55038d8e2a1202f, 0x279426fcf5f59740 }
struct limine_bootloader_info_response {
uint64_t revision;
LIMINE_PTR(char *) name;
LIMINE_PTR(char *) version;
};
struct limine_bootloader_info_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_bootloader_info_response *) response;
};
/* Stack size */
#define LIMINE_STACK_SIZE_REQUEST { LIMINE_COMMON_MAGIC, 0x224ef0460a8e8926, 0xe1cb0fc25f46ea3d }
struct limine_stack_size_response {
uint64_t revision;
};
struct limine_stack_size_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_stack_size_response *) response;
uint64_t stack_size;
};
/* HHDM */
#define LIMINE_HHDM_REQUEST { LIMINE_COMMON_MAGIC, 0x48dcf1cb8ad2b852, 0x63984e959a98244b }
struct limine_hhdm_response {
uint64_t revision;
uint64_t offset;
};
struct limine_hhdm_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_hhdm_response *) response;
};
/* Framebuffer */
#define LIMINE_FRAMEBUFFER_REQUEST { LIMINE_COMMON_MAGIC, 0x9d5827dcd881dd75, 0xa3148604f6fab11b }
#define LIMINE_FRAMEBUFFER_RGB 1
struct limine_framebuffer {
LIMINE_PTR(void *) address;
uint64_t width;
uint64_t height;
uint64_t pitch;
uint16_t bpp;
uint8_t memory_model;
uint8_t red_mask_size;
uint8_t red_mask_shift;
uint8_t green_mask_size;
uint8_t green_mask_shift;
uint8_t blue_mask_size;
uint8_t blue_mask_shift;
uint8_t unused[7];
uint64_t edid_size;
LIMINE_PTR(void *) edid;
};
struct limine_framebuffer_response {
uint64_t revision;
uint64_t framebuffer_count;
LIMINE_PTR(struct limine_framebuffer **) framebuffers;
};
struct limine_framebuffer_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_framebuffer_response *) response;
};
/* Terminal */
#define LIMINE_TERMINAL_REQUEST { LIMINE_COMMON_MAGIC, 0xc8ac59310c2b0844, 0xa68d0c7265d38878 }
#define LIMINE_TERMINAL_CB_DEC 10
#define LIMINE_TERMINAL_CB_BELL 20
#define LIMINE_TERMINAL_CB_PRIVATE_ID 30
#define LIMINE_TERMINAL_CB_STATUS_REPORT 40
#define LIMINE_TERMINAL_CB_POS_REPORT 50
#define LIMINE_TERMINAL_CB_KBD_LEDS 60
#define LIMINE_TERMINAL_CB_MODE 70
#define LIMINE_TERMINAL_CB_LINUX 80
#define LIMINE_TERMINAL_CTX_SIZE ((uint64_t)(-1))
#define LIMINE_TERMINAL_CTX_SAVE ((uint64_t)(-2))
#define LIMINE_TERMINAL_CTX_RESTORE ((uint64_t)(-3))
#define LIMINE_TERMINAL_FULL_REFRESH ((uint64_t)(-4))
struct limine_terminal;
typedef void (*limine_terminal_write)(struct limine_terminal *, const char *, uint64_t);
typedef void (*limine_terminal_callback)(struct limine_terminal *, uint64_t, uint64_t, uint64_t, uint64_t);
struct limine_terminal {
uint64_t columns;
uint64_t rows;
LIMINE_PTR(struct limine_framebuffer *) framebuffer;
};
struct limine_terminal_response {
uint64_t revision;
uint64_t terminal_count;
LIMINE_PTR(struct limine_terminal **) terminals;
LIMINE_PTR(limine_terminal_write) write;
};
struct limine_terminal_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_terminal_response *) response;
LIMINE_PTR(limine_terminal_callback) callback;
};
/* 5-level paging */
#define LIMINE_5_LEVEL_PAGING_REQUEST { LIMINE_COMMON_MAGIC, 0x94469551da9b3192, 0xebe5e86db7382888 }
struct limine_5_level_paging_response {
uint64_t revision;
};
struct limine_5_level_paging_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_5_level_paging_response *) response;
};
/* SMP */
#define LIMINE_SMP_REQUEST { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 }
struct limine_smp_info;
typedef void (*limine_goto_address)(struct limine_smp_info *);
#if defined (__x86_64__) || defined (__i386__)
#define LIMINE_SMP_X2APIC (1 << 0)
struct limine_smp_info {
uint32_t processor_id;
uint32_t lapic_id;
uint64_t reserved;
LIMINE_PTR(limine_goto_address) goto_address;
uint64_t extra_argument;
};
struct limine_smp_response {
uint64_t revision;
uint32_t flags;
uint32_t bsp_lapic_id;
uint64_t cpu_count;
LIMINE_PTR(struct limine_smp_info **) cpus;
};
#elif defined (__aarch64__)
struct limine_smp_info {
uint32_t processor_id;
uint32_t gic_iface_no;
uint64_t mpidr;
uint64_t reserved;
LIMINE_PTR(limine_goto_address) goto_address;
uint64_t extra_argument;
};
struct limine_smp_response {
uint64_t revision;
uint32_t flags;
uint64_t bsp_mpidr;
uint64_t cpu_count;
LIMINE_PTR(struct limine_smp_info **) cpus;
};
#else
#error Unknown architecture
#endif
struct limine_smp_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_smp_response *) response;
uint64_t flags;
};
/* Memory map */
#define LIMINE_MEMMAP_REQUEST { LIMINE_COMMON_MAGIC, 0x67cf3d9d378a806f, 0xe304acdfc50c3c62 }
#define LIMINE_MEMMAP_USABLE 0
#define LIMINE_MEMMAP_RESERVED 1
#define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2
#define LIMINE_MEMMAP_ACPI_NVS 3
#define LIMINE_MEMMAP_BAD_MEMORY 4
#define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5
#define LIMINE_MEMMAP_KERNEL_AND_MODULES 6
#define LIMINE_MEMMAP_FRAMEBUFFER 7
struct limine_memmap_entry {
uint64_t base;
uint64_t length;
uint64_t type;
};
struct limine_memmap_response {
uint64_t revision;
uint64_t entry_count;
LIMINE_PTR(struct limine_memmap_entry **) entries;
};
struct limine_memmap_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_memmap_response *) response;
};
/* Entry point */
#define LIMINE_ENTRY_POINT_REQUEST { LIMINE_COMMON_MAGIC, 0x13d86c035a1cd3e1, 0x2b0caa89d8f3026a }
typedef void (*limine_entry_point)(void);
struct limine_entry_point_response {
uint64_t revision;
};
struct limine_entry_point_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_entry_point_response *) response;
LIMINE_PTR(limine_entry_point) entry;
};
/* Kernel File */
#define LIMINE_KERNEL_FILE_REQUEST { LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69 }
struct limine_kernel_file_response {
uint64_t revision;
LIMINE_PTR(struct limine_file *) kernel_file;
};
struct limine_kernel_file_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_kernel_file_response *) response;
};
/* Module */
#define LIMINE_MODULE_REQUEST { LIMINE_COMMON_MAGIC, 0x3e7e279702be32af, 0xca1c4f3bd1280cee }
struct limine_module_response {
uint64_t revision;
uint64_t module_count;
LIMINE_PTR(struct limine_file **) modules;
};
struct limine_module_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_module_response *) response;
};
/* RSDP */
#define LIMINE_RSDP_REQUEST { LIMINE_COMMON_MAGIC, 0xc5e77b6b397e7b43, 0x27637845accdcf3c }
struct limine_rsdp_response {
uint64_t revision;
LIMINE_PTR(void *) address;
};
struct limine_rsdp_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_rsdp_response *) response;
};
/* SMBIOS */
#define LIMINE_SMBIOS_REQUEST { LIMINE_COMMON_MAGIC, 0x9e9046f11e095391, 0xaa4a520fefbde5ee }
struct limine_smbios_response {
uint64_t revision;
LIMINE_PTR(void *) entry_32;
LIMINE_PTR(void *) entry_64;
};
struct limine_smbios_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_smbios_response *) response;
};
/* EFI system table */
#define LIMINE_EFI_SYSTEM_TABLE_REQUEST { LIMINE_COMMON_MAGIC, 0x5ceba5163eaaf6d6, 0x0a6981610cf65fcc }
struct limine_efi_system_table_response {
uint64_t revision;
LIMINE_PTR(void *) address;
};
struct limine_efi_system_table_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_efi_system_table_response *) response;
};
/* Boot time */
#define LIMINE_BOOT_TIME_REQUEST { LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893 }
struct limine_boot_time_response {
uint64_t revision;
int64_t boot_time;
};
struct limine_boot_time_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_boot_time_response *) response;
};
/* Kernel address */
#define LIMINE_KERNEL_ADDRESS_REQUEST { LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487 }
struct limine_kernel_address_response {
uint64_t revision;
uint64_t physical_base;
uint64_t virtual_base;
};
struct limine_kernel_address_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_kernel_address_response *) response;
};
/* Device Tree Blob */
#define LIMINE_DTB_REQUEST { LIMINE_COMMON_MAGIC, 0xb40ddb48fb54bac7, 0x545081493f81ffb7 }
struct limine_dtb_response {
uint64_t revision;
LIMINE_PTR(void *) dtb_ptr;
};
struct limine_dtb_request {
uint64_t id[4];
uint64_t revision;
LIMINE_PTR(struct limine_dtb_response *) response;
};
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,417 @@
/* multiboot2.h - Multiboot 2 header file. */
/* Copyright (C) 1999,2003,2007,2008,2009,2010 Free Software Foundation, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
* DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
* IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef MULTIBOOT_HEADER
#define MULTIBOOT_HEADER 1
/* How many bytes from the start of the file we search for the header. */
#define MULTIBOOT_SEARCH 32768
#define MULTIBOOT_HEADER_ALIGN 8
/* The magic field should contain this. */
#define MULTIBOOT2_HEADER_MAGIC 0xe85250d6
/* This should be in %eax. */
#define MULTIBOOT2_BOOTLOADER_MAGIC 0x36d76289
/* Alignment of multiboot modules. */
#define MULTIBOOT_MOD_ALIGN 0x00001000
/* Alignment of the multiboot info structure. */
#define MULTIBOOT_INFO_ALIGN 0x00000008
/* Flags set in the 'flags' member of the multiboot header. */
#define MULTIBOOT_TAG_ALIGN 8
#define MULTIBOOT_TAG_TYPE_END 0
#define MULTIBOOT_TAG_TYPE_CMDLINE 1
#define MULTIBOOT_TAG_TYPE_BOOT_LOADER_NAME 2
#define MULTIBOOT_TAG_TYPE_MODULE 3
#define MULTIBOOT_TAG_TYPE_BASIC_MEMINFO 4
#define MULTIBOOT_TAG_TYPE_BOOTDEV 5
#define MULTIBOOT_TAG_TYPE_MMAP 6
#define MULTIBOOT_TAG_TYPE_VBE 7
#define MULTIBOOT_TAG_TYPE_FRAMEBUFFER 8
#define MULTIBOOT_TAG_TYPE_ELF_SECTIONS 9
#define MULTIBOOT_TAG_TYPE_APM 10
#define MULTIBOOT_TAG_TYPE_EFI32 11
#define MULTIBOOT_TAG_TYPE_EFI64 12
#define MULTIBOOT_TAG_TYPE_SMBIOS 13
#define MULTIBOOT_TAG_TYPE_ACPI_OLD 14
#define MULTIBOOT_TAG_TYPE_ACPI_NEW 15
#define MULTIBOOT_TAG_TYPE_NETWORK 16
#define MULTIBOOT_TAG_TYPE_EFI_MMAP 17
#define MULTIBOOT_TAG_TYPE_EFI_BS 18
#define MULTIBOOT_TAG_TYPE_EFI32_IH 19
#define MULTIBOOT_TAG_TYPE_EFI64_IH 20
#define MULTIBOOT_TAG_TYPE_LOAD_BASE_ADDR 21
#define MULTIBOOT_HEADER_TAG_END 0
#define MULTIBOOT_HEADER_TAG_INFORMATION_REQUEST 1
#define MULTIBOOT_HEADER_TAG_ADDRESS 2
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS 3
#define MULTIBOOT_HEADER_TAG_CONSOLE_FLAGS 4
#define MULTIBOOT_HEADER_TAG_FRAMEBUFFER 5
#define MULTIBOOT_HEADER_TAG_MODULE_ALIGN 6
#define MULTIBOOT_HEADER_TAG_EFI_BS 7
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI32 8
#define MULTIBOOT_HEADER_TAG_ENTRY_ADDRESS_EFI64 9
#define MULTIBOOT_HEADER_TAG_RELOCATABLE 10
#define MULTIBOOT_ARCHITECTURE_I386 0
#define MULTIBOOT_ARCHITECTURE_MIPS32 4
#define MULTIBOOT_HEADER_TAG_OPTIONAL 1
#define MULTIBOOT_LOAD_PREFERENCE_NONE 0
#define MULTIBOOT_LOAD_PREFERENCE_LOW 1
#define MULTIBOOT_LOAD_PREFERENCE_HIGH 2
#define MULTIBOOT_CONSOLE_FLAGS_CONSOLE_REQUIRED 1
#define MULTIBOOT_CONSOLE_FLAGS_EGA_TEXT_SUPPORTED 2
#ifndef ASM_FILE
typedef unsigned char multiboot_uint8_t;
typedef unsigned short multiboot_uint16_t;
typedef unsigned int multiboot_uint32_t;
typedef unsigned long long multiboot_uint64_t;
struct multiboot_header
{
/* Must be MULTIBOOT_MAGIC - see above. */
multiboot_uint32_t magic;
/* ISA */
multiboot_uint32_t architecture;
/* Total header length. */
multiboot_uint32_t header_length;
/* The above fields plus this one must equal 0 mod 2^32. */
multiboot_uint32_t checksum;
};
struct multiboot_header_tag
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
};
struct multiboot_header_tag_information_request
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t requests[0];
};
struct multiboot_header_tag_address
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t header_addr;
multiboot_uint32_t load_addr;
multiboot_uint32_t load_end_addr;
multiboot_uint32_t bss_end_addr;
};
struct multiboot_header_tag_entry_address
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t entry_addr;
};
struct multiboot_header_tag_console_flags
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t console_flags;
};
struct multiboot_header_tag_framebuffer
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t width;
multiboot_uint32_t height;
multiboot_uint32_t depth;
};
struct multiboot_header_tag_module_align
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
};
struct multiboot_header_tag_relocatable
{
multiboot_uint16_t type;
multiboot_uint16_t flags;
multiboot_uint32_t size;
multiboot_uint32_t min_addr;
multiboot_uint32_t max_addr;
multiboot_uint32_t align;
multiboot_uint32_t preference;
};
struct multiboot_color
{
multiboot_uint8_t red;
multiboot_uint8_t green;
multiboot_uint8_t blue;
};
struct multiboot_mmap_entry
{
multiboot_uint64_t addr;
multiboot_uint64_t len;
#define MULTIBOOT_MEMORY_AVAILABLE 1
#define MULTIBOOT_MEMORY_RESERVED 2
#define MULTIBOOT_MEMORY_ACPI_RECLAIMABLE 3
#define MULTIBOOT_MEMORY_NVS 4
#define MULTIBOOT_MEMORY_BADRAM 5
multiboot_uint32_t type;
multiboot_uint32_t zero;
};
typedef struct multiboot_mmap_entry multiboot_memory_map_t;
struct multiboot_tag
{
multiboot_uint32_t type;
multiboot_uint32_t size;
};
struct multiboot_tag_string
{
multiboot_uint32_t type;
multiboot_uint32_t size;
char string[0];
};
struct multiboot_tag_module
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t mod_start;
multiboot_uint32_t mod_end;
char cmdline[0];
};
struct multiboot_tag_basic_meminfo
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t mem_lower;
multiboot_uint32_t mem_upper;
};
struct multiboot_tag_bootdev
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t biosdev;
multiboot_uint32_t slice;
multiboot_uint32_t part;
};
struct multiboot_tag_mmap
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t entry_size;
multiboot_uint32_t entry_version;
struct multiboot_mmap_entry entries[0];
};
struct multiboot_vbe_info_block
{
multiboot_uint8_t external_specification[512];
};
struct multiboot_vbe_mode_info_block
{
multiboot_uint8_t external_specification[256];
};
struct multiboot_tag_vbe
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint16_t vbe_mode;
multiboot_uint16_t vbe_interface_seg;
multiboot_uint16_t vbe_interface_off;
multiboot_uint16_t vbe_interface_len;
struct multiboot_vbe_info_block vbe_control_info;
struct multiboot_vbe_mode_info_block vbe_mode_info;
};
struct multiboot_tag_framebuffer_common
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint64_t framebuffer_addr;
multiboot_uint32_t framebuffer_pitch;
multiboot_uint32_t framebuffer_width;
multiboot_uint32_t framebuffer_height;
multiboot_uint8_t framebuffer_bpp;
#define MULTIBOOT_FRAMEBUFFER_TYPE_INDEXED 0
#define MULTIBOOT_FRAMEBUFFER_TYPE_RGB 1
#define MULTIBOOT_FRAMEBUFFER_TYPE_EGA_TEXT 2
multiboot_uint8_t framebuffer_type;
multiboot_uint16_t reserved;
};
struct multiboot_tag_framebuffer
{
struct multiboot_tag_framebuffer_common common;
union
{
struct
{
multiboot_uint16_t framebuffer_palette_num_colors;
struct multiboot_color framebuffer_palette[0];
};
struct
{
multiboot_uint8_t framebuffer_red_field_position;
multiboot_uint8_t framebuffer_red_mask_size;
multiboot_uint8_t framebuffer_green_field_position;
multiboot_uint8_t framebuffer_green_mask_size;
multiboot_uint8_t framebuffer_blue_field_position;
multiboot_uint8_t framebuffer_blue_mask_size;
};
};
};
struct multiboot_tag_elf_sections
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t num;
multiboot_uint32_t entsize;
multiboot_uint32_t shndx;
char sections[0];
};
struct multiboot_tag_apm
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint16_t version;
multiboot_uint16_t cseg;
multiboot_uint32_t offset;
multiboot_uint16_t cseg_16;
multiboot_uint16_t dseg;
multiboot_uint16_t flags;
multiboot_uint16_t cseg_len;
multiboot_uint16_t cseg_16_len;
multiboot_uint16_t dseg_len;
};
struct multiboot_tag_efi32
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t pointer;
};
struct multiboot_tag_efi64
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint64_t pointer;
};
struct multiboot_tag_smbios
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t major;
multiboot_uint8_t minor;
multiboot_uint8_t reserved[6];
multiboot_uint8_t tables[0];
};
struct multiboot_tag_old_acpi
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t rsdp[0];
};
struct multiboot_tag_new_acpi
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t rsdp[0];
};
struct multiboot_tag_network
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint8_t dhcpack[0];
};
struct multiboot_tag_efi_mmap
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t descr_size;
multiboot_uint32_t descr_vers;
multiboot_uint8_t efi_mmap[0];
};
struct multiboot_tag_efi32_ih
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t pointer;
};
struct multiboot_tag_efi64_ih
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint64_t pointer;
};
struct multiboot_tag_load_base_addr
{
multiboot_uint32_t type;
multiboot_uint32_t size;
multiboot_uint32_t load_base_addr;
};
#endif /* ! ASM_FILE */
#endif /* ! MULTIBOOT_HEADER */

134
include/cpu.hpp Normal file
View File

@ -0,0 +1,134 @@
#ifndef __FENNIX_KERNEL_CPU_H__
#define __FENNIX_KERNEL_CPU_H__
#include <types.h>
/**
* @brief CPU related functions.
*/
namespace CPU
{
/**
* @brief Enum for CPU::Interrupts() function.
*/
enum InterruptsType
{
/**
* @brief Check if interrupts are enabled.
*/
Check,
/**
* @brief Enable interrupts.
*/
Enable,
/**
* @brief Disable interrupts.
*/
Disable
};
/**
* @brief Pause the CPU
*/
void Pause();
/**
* @brief Halt the CPU
*/
void Halt();
/**
* @brief Check if interrupts are enabled
*
* @return true If InterruptsType::Check and interrupts are enabled, or if other InterruptsType were executed successfully
* @return false If InterruptsType::Check and interrupts are disabled, or if other InterruptsType failed
*/
bool Interrupts(InterruptsType Type = Check);
namespace MemBar
{
static inline void Barrier()
{
#if defined(__amd64__) || defined(__i386__)
asmv("" ::
: "memory");
#elif defined(__aarch64__)
asmv("dmb ish" ::
: "memory");
#endif
}
static inline void Fence()
{
#if defined(__amd64__) || defined(__i386__)
asmv("mfence" ::
: "memory");
#elif defined(__aarch64__)
asmv("dmb ish" ::
: "memory");
#endif
}
static inline void StoreFence()
{
#if defined(__amd64__) || defined(__i386__)
asmv("sfence" ::
: "memory");
#elif defined(__aarch64__)
asmv("dmb ishst" ::
: "memory");
#endif
}
static inline void LoadFence()
{
#if defined(__amd64__) || defined(__i386__)
asmv("lfence" ::
: "memory");
#elif defined(__aarch64__)
asmv("dmb ishld" ::
: "memory");
#endif
}
}
namespace x86
{
static inline void lgdt(void *gdt)
{
#if defined(__amd64__) || defined(__i386__)
asmv("lgdt (%0)"
:
: "r"(gdt));
#endif
}
static inline void lidt(void *idt)
{
#if defined(__amd64__) || defined(__i386__)
asmv("lidt (%0)"
:
: "r"(idt));
#endif
}
static inline void ltr(uint16_t Segment)
{
#if defined(__amd64__) || defined(__i386__)
asmv("ltr %0"
:
: "r"(Segment));
#endif
}
static inline void invlpg(void *Address)
{
#if defined(__amd64__) || defined(__i386__)
asmv("invlpg (%0)"
:
: "r"(Address)
: "memory");
#endif
}
}
}
#endif // !__FENNIX_KERNEL_CPU_H__

2
include/cstring Normal file
View File

@ -0,0 +1,2 @@
#pragma once
#include <string.h>

46
include/debug.h Normal file
View File

@ -0,0 +1,46 @@
#ifndef __FENNIX_KERNEL_DEBUGGER_H__
#define __FENNIX_KERNEL_DEBUGGER_H__
#include <types.h>
enum DebugLevel
{
DebugLevelNone = 0,
DebugLevelError = 1,
DebugLevelWarning = 2,
DebugLevelInfo = 3,
DebugLevelDebug = 4,
DebugLevelTrace = 5,
DebugLevelFixme = 6
};
#ifdef __cplusplus
namespace SysDbg
{
void Write(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...);
void WriteLine(DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...);
}
#define error(Format, ...) SysDbg::WriteLine(DebugLevelError, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__)
#define warn(Format, ...) SysDbg::WriteLine(DebugLevelWarning, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__)
#define info(Format, ...) SysDbg::WriteLine(DebugLevelInfo, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__)
#define debug(Format, ...) SysDbg::WriteLine(DebugLevelDebug, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__)
#define trace(Format, ...) SysDbg::WriteLine(DebugLevelTrace, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__)
#define fixme(Format, ...) SysDbg::WriteLine(DebugLevelFixme, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__)
#else
void SysDbgWrite(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...);
void SysDbgWriteLine(enum DebugLevel Level, const char *File, int Line, const char *Function, const char *Format, ...);
#define error(Format, ...) SysDbgWriteLine(DebugLevelError, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__)
#define warn(Format, ...) SysDbgWriteLine(DebugLevelWarning, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__)
#define info(Format, ...) SysDbgWriteLine(DebugLevelInfo, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__)
#define debug(Format, ...) SysDbgWriteLine(DebugLevelDebug, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__)
#define trace(Format, ...) SysDbgWriteLine(DebugLevelTrace, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__)
#define fixme(Format, ...) SysDbgWriteLine(DebugLevelFixme, __FILE__, __LINE__, __FUNCTION__, Format, ##__VA_ARGS__)
#endif // __cplusplus
#endif // !__FENNIX_KERNEL_DEBUGGER_H__

93
include/hashmap.hpp Normal file
View File

@ -0,0 +1,93 @@
#pragma once
template <typename K, typename V>
class HashNode
{
public:
V Value;
K Key;
HashNode(K Key, V Value)
{
this->Value = Value;
this->Key = Key;
}
};
template <typename K, typename V>
class HashMap
{
int HashMapSize;
int HashMapCapacity;
HashNode<K, V> **Nodes;
HashNode<K, V> *DummyNode;
public:
HashMap()
{
HashMapCapacity = 20;
HashMapSize = 0;
Nodes = new HashNode<K, V> *[HashMapCapacity];
for (int i = 0; i < HashMapCapacity; i++)
Nodes[i] = nullptr;
DummyNode = new HashNode<K, V>(-1, -1);
}
int HashCode(K Key) { return Key % HashMapCapacity; }
void AddNode(K Key, V Value)
{
HashNode<K, V> *tmp = new HashNode<K, V>(Key, Value);
int Index = HashCode(Key);
while (Nodes[Index] != nullptr && Nodes[Index]->Key != Key && Nodes[Index]->Key != -1)
{
Index++;
Index %= HashMapCapacity;
}
if (Nodes[Index] == nullptr || Nodes[Index]->Key == -1)
HashMapSize++;
Nodes[Index] = tmp;
}
V DeleteNode(int Key)
{
int Index = HashCode(Key);
while (Nodes[Index] != nullptr)
{
if (Nodes[Index]->Key == Key)
{
HashNode<K, V> *tmp = Nodes[Index];
Nodes[Index] = DummyNode;
HashMapSize--;
return tmp->Value;
}
Index++;
Index %= HashMapCapacity;
}
return nullptr;
}
V Get(int Key)
{
int Index = HashCode(Key);
int Iterate = 0;
while (Nodes[Index] != nullptr)
{
if (Iterate++ > HashMapCapacity)
return 0;
if (Nodes[Index]->Key == Key)
return Nodes[Index]->Value;
Index++;
Index %= HashMapCapacity;
}
return 0;
}
int Size() { return HashMapSize; }
bool IsEmpty() { return HashMapSize == 0; }
};

220
include/io.h Normal file
View File

@ -0,0 +1,220 @@
#ifndef __FENNIX_KERNEL_IO_H__
#define __FENNIX_KERNEL_IO_H__
#include <types.h>
#if defined(__amd64__) || defined(__i386__)
#ifdef __cplusplus
extern "C"
{
#endif
static inline uint8_t inportb(uint16_t Port)
{
uint8_t Result;
asm("in %%dx, %%al"
: "=a"(Result)
: "d"(Port));
return Result;
}
static inline uint16_t inportw(uint16_t Port)
{
uint16_t Result;
asm("in %%dx, %%ax"
: "=a"(Result)
: "d"(Port));
return Result;
}
static inline uint32_t inportl(uint16_t Port)
{
uint32_t Result;
asmv("inl %1, %0"
: "=a"(Result)
: "dN"(Port));
return Result;
}
static inline void outportb(uint16_t Port, uint8_t Data)
{
asmv("out %%al, %%dx"
:
: "a"(Data), "d"(Port));
}
static inline void outportw(uint16_t Port, uint16_t Data)
{
asmv("out %%ax, %%dx"
:
: "a"(Data), "d"(Port));
}
static inline void outportl(uint16_t Port, uint32_t Data)
{
asmv("outl %1, %0"
:
: "dN"(Port), "a"(Data));
}
static inline uint8_t mmioin8(uint64_t Address)
{
asmv("" ::
: "memory");
uint8_t Result = *(volatile uint8_t *)Address;
asmv("" ::
: "memory");
return Result;
}
static inline uint16_t mmioin16(uint64_t Address)
{
asmv("" ::
: "memory");
uint16_t Result = *(volatile uint16_t *)Address;
asmv("" ::
: "memory");
return Result;
}
static inline uint32_t mmioin32(uint64_t Address)
{
asmv("" ::
: "memory");
uint32_t Result = *(volatile uint32_t *)Address;
asmv("" ::
: "memory");
return Result;
}
static inline uint64_t mmioin64(uint64_t Address)
{
asmv("" ::
: "memory");
uint64_t Result = *(volatile uint64_t *)Address;
asmv("" ::
: "memory");
return Result;
}
static inline void mmioout8(uint64_t Address, uint8_t Data)
{
asmv("" ::
: "memory");
*(volatile uint8_t *)Address = Data;
asmv("" ::
: "memory");
}
static inline void mmioout16(uint64_t Address, uint16_t Data)
{
asmv("" ::
: "memory");
*(volatile uint16_t *)Address = Data;
asmv("" ::
: "memory");
}
static inline void mmioout32(uint64_t Address, uint32_t Data)
{
asmv("" ::
: "memory");
*(volatile uint32_t *)Address = Data;
asmv("" ::
: "memory");
}
static inline void mmioout64(uint64_t Address, uint64_t Data)
{
asmv("" ::
: "memory");
*(volatile uint64_t *)Address = Data;
asmv("" ::
: "memory");
}
static inline void mmoutb(void *Address, uint8_t Value)
{
asmv("mov %1, %0"
: "=m"((*(uint8_t *)(Address)))
: "r"(Value)
: "memory");
}
static inline void mmoutw(void *Address, uint16_t Value)
{
asmv("mov %1, %0"
: "=m"((*(uint16_t *)(Address)))
: "r"(Value)
: "memory");
}
static inline void mmoutl(void *Address, uint32_t Value)
{
asmv("mov %1, %0"
: "=m"((*(uint32_t *)(Address)))
: "r"(Value)
: "memory");
}
static inline void mmoutq(void *Address, uint64_t Value)
{
asmv("mov %1, %0"
: "=m"((*(uint64_t *)(Address)))
: "r"(Value)
: "memory");
}
static inline uint8_t mminb(void *Address)
{
uint8_t Result;
asmv("mov %1, %0"
: "=r"(Result)
: "m"((*(uint8_t *)(Address)))
: "memory");
return Result;
}
static inline uint16_t mminw(void *Address)
{
uint16_t Result;
asmv("mov %1, %0"
: "=r"(Result)
: "m"((*(uint16_t *)(Address)))
: "memory");
return Result;
}
static inline uint32_t mminl(void *Address)
{
uint32_t Result;
asmv("mov %1, %0"
: "=r"(Result)
: "m"((*(uint32_t *)(Address)))
: "memory");
return Result;
}
static inline uint64_t mminq(void *Address)
{
uint64_t Result;
asmv("mov %1, %0"
: "=r"(Result)
: "m"((*(uint64_t *)(Address)))
: "memory");
return Result;
}
#ifdef __cplusplus
}
#endif
#define inb(Port) inportb(Port)
#define inw(Port) inportw(Port)
#define inl(Port) inportl(Port)
#define outb(Port, Data) outportb(Port, Data)
#define outw(Port, Data) outportw(Port, Data)
#define outl(Port, Data) outportl(Port, Data)
#endif // defined(__amd64__) || defined(__i386__)
#endif // !__FENNIX_KERNEL_IO_H__

119
include/limits.h Normal file
View File

@ -0,0 +1,119 @@
#ifndef __FENNIX_KERNEL_LIMITS_H__
#define __FENNIX_KERNEL_LIMITS_H__
#undef CHAR_BIT
#define CHAR_BIT __CHAR_BIT__
#ifndef MB_LEN_MAX
#define MB_LEN_MAX 1
#endif
#undef SCHAR_MIN
#define SCHAR_MIN (-SCHAR_MAX - 1)
#undef SCHAR_MAX
#define SCHAR_MAX __SCHAR_MAX__
#undef UCHAR_MAX
#if __SCHAR_MAX__ == __INT_MAX__
#define UCHAR_MAX (SCHAR_MAX * 2U + 1U)
#else
#define UCHAR_MAX (SCHAR_MAX * 2 + 1)
#endif
#ifdef __CHAR_UNSIGNED__
#undef CHAR_MIN
#if __SCHAR_MAX__ == __INT_MAX__
#define CHAR_MIN 0U
#else
#define CHAR_MIN 0
#endif
#undef CHAR_MAX
#define CHAR_MAX UCHAR_MAX
#else
#undef CHAR_MIN
#define CHAR_MIN SCHAR_MIN
#undef CHAR_MAX
#define CHAR_MAX SCHAR_MAX
#endif
#undef SHRT_MIN
#define SHRT_MIN (-SHRT_MAX - 1)
#undef SHRT_MAX
#define SHRT_MAX __SHRT_MAX__
#undef USHRT_MAX
#if __SHRT_MAX__ == __INT_MAX__
#define USHRT_MAX (SHRT_MAX * 2U + 1U)
#else
#define USHRT_MAX (SHRT_MAX * 2 + 1)
#endif
#undef INT_MIN
#define INT_MIN (-INT_MAX - 1)
#undef INT_MAX
#define INT_MAX __INT_MAX__
#undef UINT_MAX
#define UINT_MAX (INT_MAX * 2U + 1U)
#undef LONG_MIN
#define LONG_MIN (-LONG_MAX - 1L)
#undef LONG_MAX
#define LONG_MAX __LONG_MAX__
#undef ULONG_MAX
#define ULONG_MAX (LONG_MAX * 2UL + 1UL)
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
#undef LLONG_MIN
#define LLONG_MIN (-LLONG_MAX - 1LL)
#undef LLONG_MAX
#define LLONG_MAX __LONG_LONG_MAX__
#undef ULLONG_MAX
#define ULLONG_MAX (LLONG_MAX * 2ULL + 1ULL)
#endif
#if defined(__GNU_LIBRARY__) ? defined(__USE_GNU) : !defined(__STRICT_ANSI__)
#undef LONG_LONG_MIN
#define LONG_LONG_MIN (-LONG_LONG_MAX - 1LL)
#undef LONG_LONG_MAX
#define LONG_LONG_MAX __LONG_LONG_MAX__
#undef ULONG_LONG_MAX
#define ULONG_LONG_MAX (LONG_LONG_MAX * 2ULL + 1ULL)
#endif
#if (defined __STDC_WANT_IEC_60559_BFP_EXT__ || (defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L))
#undef CHAR_WIDTH
#define CHAR_WIDTH __SCHAR_WIDTH__
#undef SCHAR_WIDTH
#define SCHAR_WIDTH __SCHAR_WIDTH__
#undef UCHAR_WIDTH
#define UCHAR_WIDTH __SCHAR_WIDTH__
#undef SHRT_WIDTH
#define SHRT_WIDTH __SHRT_WIDTH__
#undef USHRT_WIDTH
#define USHRT_WIDTH __SHRT_WIDTH__
#undef INT_WIDTH
#define INT_WIDTH __INT_WIDTH__
#undef UINT_WIDTH
#define UINT_WIDTH __INT_WIDTH__
#undef LONG_WIDTH
#define LONG_WIDTH __LONG_WIDTH__
#undef ULONG_WIDTH
#define ULONG_WIDTH __LONG_WIDTH__
#undef LLONG_WIDTH
#define LLONG_WIDTH __LONG_LONG_WIDTH__
#undef ULLONG_WIDTH
#define ULLONG_WIDTH __LONG_LONG_WIDTH__
#endif
#if defined(__STDC_VERSION__) && __STDC_VERSION__ > 201710L
#undef BOOL_MAX
#define BOOL_MAX 1
#undef BOOL_WIDTH
#define BOOL_WIDTH 1
#endif
#endif // !__FENNIX_KERNEL_LIMITS_H__

53
include/lock.hpp Normal file
View File

@ -0,0 +1,53 @@
#ifndef __FENNIX_KERNEL_LOCK_H__
#define __FENNIX_KERNEL_LOCK_H__
#include <types.h>
#include <cpu.hpp>
#ifdef __cplusplus
class LockClass
{
private:
bool IsLocked = false;
public:
int Lock()
{
while (!__sync_bool_compare_and_swap(&IsLocked, false, true))
CPU::Pause();
__sync_synchronize();
return 0;
}
int Unlock()
{
__sync_synchronize();
__atomic_store_n(&IsLocked, false, __ATOMIC_SEQ_CST);
IsLocked = false;
return 0;
}
};
#define NEWLOCK(Name) LockClass Name
class SmartLock
{
private:
LockClass *LockPointer = nullptr;
public:
SmartLock(LockClass &Lock)
{
this->LockPointer = &Lock;
this->LockPointer->Lock();
}
~SmartLock() { this->LockPointer->Unlock(); }
};
#define SL_CONCAT(x, y) x##y
#define SMARTLOCK(LockClassName) SmartLock SL_CONCAT(lock##_, __COUNTER__)(LockClassName)
#endif
#endif // !__FENNIX_KERNEL_LOCK_H__

432
include/memory.hpp Normal file
View File

@ -0,0 +1,432 @@
#ifndef __FENNIX_KERNEL_INTERNAL_MEMORY_H__
#define __FENNIX_KERNEL_INTERNAL_MEMORY_H__
#include <boot/binfo.h>
#include <bitmap.hpp>
#include <lock.hpp>
#include <types.h>
extern uint64_t _kernel_start, _kernel_end;
extern uint64_t _kernel_text_end, _kernel_data_end, _kernel_rodata_end;
// kilobyte
#define TO_KB(d) (d / 1024)
// megabyte
#define TO_MB(d) (d / 1024 / 1024)
// gigabyte
#define TO_GB(d) (d / 1024 / 1024 / 1024)
// terabyte
#define TO_TB(d) (d / 1024 / 1024 / 1024 / 1024)
// petabyte
#define TO_PB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024)
// exobyte
#define TO_EB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
// zettabyte
#define TO_ZB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
// yottabyte
#define TO_YB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
// brontobyte
#define TO_BB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
// geopbyte
#define TO_GPB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
#define PAGE_SIZE 0x1000
// to pages
#define TO_PAGES(d) (d / PAGE_SIZE + 1)
// from pages
#define FROM_PAGES(d) (d * PAGE_SIZE - 1)
#define NORMAL_VMA_OFFSET 0xFFFF800000000000
#define KERNEL_VMA_OFFSET 0xFFFFFFFF80000000
/**
* @brief KERNEL_HEAP_BASE is the base address of the kernel heap
*/
#define KERNEL_HEAP_BASE 0xFFFFC00000000000
/**
* @brief USER_HEAP_BASE is the base address of the user heap allocated by the kernel
*/
#define USER_HEAP_BASE 0xFFFFD00000000000
namespace Memory
{
/**
* @brief https://wiki.osdev.org/images/4/41/64-bit_page_tables1.png
* @brief https://wiki.osdev.org/images/6/6b/64-bit_page_tables2.png
*/
enum PTFlag
{
/** @brief Present */
P = 1 << 0,
/** @brief Read/Write */
RW = 1 << 1,
/** @brief User/Supervisor */
US = 1 << 2,
/** @brief Write-Through */
PWT = 1 << 3,
/** @brief Cache Disable */
PCD = 1 << 4,
/** @brief Accessed */
A = 1 << 5,
/** @brief Dirty */
D = 1 << 6,
/** @brief Page Size */
PS = 1 << 7,
/** @brief Global */
G = 1 << 8,
/** @brief Available 0 */
AVL0 = 1 << 9,
/** @brief Available 1 */
AVL1 = 1 << 10,
/** @brief Available 2 */
AVL2 = 1 << 11,
/** @brief Page Attribute Table */
PAT = 1 << 12,
/** @brief Available 3 */
AVL3 = (uint64_t)1 << 52,
/** @brief Available 4 */
AVL4 = (uint64_t)1 << 53,
/** @brief Available 5 */
AVL5 = (uint64_t)1 << 54,
/** @brief Available 6 */
AVL6 = (uint64_t)1 << 55,
/** @brief Available 7 */
AVL7 = (uint64_t)1 << 56,
/** @brief Available 8 */
AVL8 = (uint64_t)1 << 57,
/** @brief Available 9 */
AVL9 = (uint64_t)1 << 58,
/** @brief Protection Key 0 */
PK0 = (uint64_t)1 << 59,
/** @brief Protection Key 1 */
PK1 = (uint64_t)1 << 60,
/** @brief Protection Key 2 */
PK2 = (uint64_t)1 << 61,
/** @brief Protection Key 3 */
PK3 = (uint64_t)1 << 62,
/** @brief Execute Disable */
XD = (uint64_t)1 << 63
};
typedef union __attribute__((packed))
{
struct
{
bool Present : 1;
bool ReadWrite : 1;
bool UserSupervisor : 1;
bool WriteThrough : 1;
bool CacheDisable : 1;
bool Accessed : 1;
bool Dirty : 1;
bool PageSize : 1;
bool Global : 1;
uint8_t Available1 : 3;
bool PageAttributeTable : 1;
uint64_t Reserved : 39;
uint32_t Available2 : 7;
uint16_t ProtectionKey : 4;
bool ExecuteDisable : 1;
};
uint64_t raw;
} PDEData;
struct __attribute__((packed)) PageDirectoryEntry
{
PDEData Value;
void AddFlag(uint64_t Flag) { this->Value.raw |= Flag; }
void RemoveFlags(uint64_t Flag) { this->Value.raw &= ~Flag; }
void ClearFlags() { this->Value.raw = 0; }
void SetFlag(uint64_t Flag, bool Enabled)
{
this->Value.raw &= ~Flag;
if (Enabled)
this->Value.raw |= Flag;
}
bool GetFlag(uint64_t Flag) { return (this->Value.raw & Flag) > 0 ? true : false; }
uint64_t GetFlag() { return this->Value.raw; }
void SetAddress(uint64_t Address)
{
#if defined(__amd64__)
Address &= 0x000000FFFFFFFFFF;
this->Value.raw &= 0xFFF0000000000FFF;
this->Value.raw |= (Address << 12);
#elif defined(__i386__)
Address &= 0x000FFFFF;
this->Value.raw &= 0xFFC00003;
this->Value.raw |= (Address << 12);
#elif defined(__aarch64__)
Address &= 0x000000FFFFFFFFFF;
this->Value.raw &= 0xFFF0000000000FFF;
this->Value.raw |= (Address << 12);
#endif
}
uint64_t GetAddress()
{
#if defined(__amd64__)
return (this->Value.raw & 0x000FFFFFFFFFF000) >> 12;
#elif defined(__i386__)
return (this->Value.raw & 0x003FFFFF000) >> 12;
#elif defined(__aarch64__)
return (this->Value.raw & 0x000FFFFFFFFFF000) >> 12;
#endif
}
};
struct PageTable
{
PageDirectoryEntry Entries[512];
} __attribute__((aligned(0x1000)));
class Physical
{
private:
NEWLOCK(MemoryLock);
uint64_t TotalMemory = 0;
uint64_t FreeMemory = 0;
uint64_t ReservedMemory = 0;
uint64_t UsedMemory = 0;
uint64_t PageBitmapIndex = 0;
Bitmap PageBitmap;
void ReservePage(void *Address);
void ReservePages(void *Address, uint64_t PageCount);
void UnreservePage(void *Address);
void UnreservePages(void *Address, uint64_t PageCount);
public:
/**
* @brief Get Total Memory
*
* @return uint64_t
*/
uint64_t GetTotalMemory();
/**
* @brief Get Free Memory
*
* @return uint64_t
*/
uint64_t GetFreeMemory();
/**
* @brief Get Reserved Memory
*
* @return uint64_t
*/
uint64_t GetReservedMemory();
/**
* @brief Get Used Memory
*
* @return uint64_t
*/
uint64_t GetUsedMemory();
/**
* @brief Swap page
*
* @param Address Address of the page
* @return true if swap was successful
* @return false if swap was unsuccessful
*/
bool SwapPage(void *Address);
/**
* @brief Swap pages
*
* @param Address Address of the pages
* @param PageCount Number of pages
* @return true if swap was successful
* @return false if swap was unsuccessful
*/
bool SwapPages(void *Address, uint64_t PageCount);
/**
* @brief Unswap page
*
* @param Address Address of the page
* @return true if unswap was successful
* @return false if unswap was unsuccessful
*/
bool UnswapPage(void *Address);
/**
* @brief Unswap pages
*
* @param Address Address of the pages
* @param PageCount Number of pages
* @return true if unswap was successful
* @return false if unswap was unsuccessful
*/
bool UnswapPages(void *Address, uint64_t PageCount);
/**
* @brief Lock page
*
* @param Address Address of the page
*/
void LockPage(void *Address);
/**
* @brief Lock pages
*
* @param Address Address of the pages
* @param PageCount Number of pages
*/
void LockPages(void *Address, uint64_t PageCount);
/**
* @brief Request page
*
* @return void* Allocated page address
*/
void *RequestPage();
/**
* @brief Request pages
*
* @param PageCount Number of pages
* @return void* Allocated pages address
*/
void *RequestPages(uint64_t Count);
/**
* @brief Free page
*
* @param Address Address of the page
*/
void FreePage(void *Address);
/**
* @brief Free pages
*
* @param Address Address of the pages
* @param PageCount Number of pages
*/
void FreePages(void *Address, uint64_t Count);
/** @brief Do not use. */
void Init(BootInfo *Info);
/** @brief Do not use. */
Physical();
/** @brief Do not use. */
~Physical();
};
class Virtual
{
private:
NEWLOCK(MemoryLock);
PageTable *Table = nullptr;
class PageMapIndexer
{
public:
uint64_t PDP_i;
uint64_t PD_i;
uint64_t PT_i;
uint64_t P_i;
PageMapIndexer(uint64_t VirtualAddress)
{
#if defined(__amd64__)
PDP_i = (VirtualAddress & ((uint64_t)0x1FF << 39)) >> 39;
PD_i = (VirtualAddress & ((uint64_t)0x1FF << 30)) >> 30;
PT_i = (VirtualAddress & ((uint64_t)0x1FF << 21)) >> 21;
P_i = (VirtualAddress & ((uint64_t)0x1FF << 12)) >> 12;
#elif defined(__i386__)
PD_i = (VirtualAddress & ((uint64_t)0x3FF << 22)) >> 22;
PT_i = (VirtualAddress & ((uint64_t)0x3FF << 12)) >> 12;
P_i = (VirtualAddress & ((uint64_t)0xFFF << 0)) >> 0;
#elif defined(__aarch64__)
PD_i = (VirtualAddress & ((uint64_t)0x1FF << 30)) >> 30;
PT_i = (VirtualAddress & ((uint64_t)0x1FF << 21)) >> 21;
P_i = (VirtualAddress & ((uint64_t)0x1FF << 12)) >> 12;
#endif
}
};
public:
/**
* @brief Map page.
*
* @param VirtualAddress Virtual address of the page.
* @param PhysicalAddress Physical address of the page.
* @param Flags Flags of the page. Check PTFlag enum.
*/
void Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags);
/**
* @brief Map multiple pages.
*
* @param VirtualAddress First virtual address of the page.
* @param PhysicalAddress First physical address of the page.
* @param PageCount Number of pages.
* @param Flags Flags of the page. Check PTFlag enum.
*/
void Map(void *VirtualAddress, void *PhysicalAddress, uint64_t PageCount, uint64_t Flags);
/**
* @brief Unmap page.
*
* @param VirtualAddress Virtual address of the page.
*/
void Unmap(void *VirtualAddress);
/**
* @brief Unmap multiple pages.
*
* @param VirtualAddress First virtual address of the page.
* @param PageCount Number of pages.
*/
void Unmap(void *VirtualAddress, uint64_t PageCount);
/**
* @brief Construct a new Virtual object
*
* @param Table Page table
*/
Virtual(PageTable *Table);
/**
* @brief Destroy the Virtual object
*
*/
~Virtual();
};
}
void InitializeMemoryManagement(BootInfo *Info);
void *operator new(uint64_t Size);
void *operator new[](uint64_t Size);
void operator delete(void *Pointer);
void operator delete[](void *Pointer);
void operator delete(void *Pointer, long unsigned int Size);
void operator delete[](void *Pointer, long unsigned int Size);
void *HeapMalloc(uint64_t Size);
void *HeapCalloc(uint64_t n, uint64_t Size);
void *HeapRealloc(void *Address, uint64_t Size);
void HeapFree(void *Address);
#define kmalloc(Size) HeapMalloc(Size)
#define kcalloc(n, Size) HeapCalloc(n, Size)
#define krealloc(Address, Size) HeapRealloc(Address, Size)
#define kfree(Address) HeapFree(Address)
extern Memory::Physical KernelAllocator;
extern Memory::PageTable *KernelPageTable;
#endif // !__FENNIX_KERNEL_INTERNAL_MEMORY_H__

199
include/printf.h Normal file
View File

@ -0,0 +1,199 @@
/**
* @author (c) Eyal Rozenberg <eyalroz1@gmx.com>
* 2021-2022, Haifa, Palestine/Israel
* @author (c) Marco Paland (info@paland.com)
* 2014-2019, PALANDesign Hannover, Germany
*
* @note Others have made smaller contributions to this file: see the
* contributors page at https://github.com/eyalroz/printf/graphs/contributors
* or ask one of the authors.
*
* @brief Small stand-alone implementation of the printf family of functions
* (`(v)printf`, `(v)s(n)printf` etc., geared towards use on embedded systems with
* a very limited resources.
*
* @note the implementations are thread-safe; re-entrant; use no functions from
* the standard library; and do not dynamically allocate any memory.
*
* @license The MIT License (MIT)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#ifndef PRINTF_H_
#define PRINTF_H_
# include <stdarg.h>
# include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __GNUC__
# define ATTR_PRINTF(one_based_format_index, first_arg) \
__attribute__((format(__printf__, (one_based_format_index), (first_arg))))
# define ATTR_VPRINTF(one_based_format_index) ATTR_PRINTF((one_based_format_index), 0)
#else
# define ATTR_PRINTF((one_based_format_index), (first_arg))
# define ATTR_VPRINTF(one_based_format_index)
#endif
#ifndef PRINTF_ALIAS_STANDARD_FUNCTION_NAMES
#define PRINTF_ALIAS_STANDARD_FUNCTION_NAMES 0
#endif
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES
# define printf_ printf
# define sprintf_ sprintf
# define vsprintf_ vsprintf
# define snprintf_ snprintf
# define vsnprintf_ vsnprintf
# define vprintf_ vprintf
#endif
// If you want to include this implementation file directly rather than
// link against, this will let you control the functions' visibility,
// e.g. make them static so as not to clash with other objects also
// using them.
#ifndef PRINTF_VISIBILITY
#define PRINTF_VISIBILITY
#endif
/**
* Prints/send a single character to some opaque output entity
*
* @note This function is not implemented by the library, only declared; you must provide an
* implementation if you wish to use the @ref printf / @ref vprintf function (and possibly
* for linking against the library, if your toolchain does not support discarding unused functions)
*
* @note The output could be as simple as a wrapper for the `write()` system call on a Unix-like
* system, or even libc's @ref putchar , for replicating actual functionality of libc's @ref printf
* function; but on an embedded system it may involve interaction with a special output device,
* like a UART, etc.
*
* @note in libc's @ref putchar, the parameter type is an int; this was intended to support the
* representation of either a proper character or EOF in a variable - but this is really not
* meaningful to pass into @ref putchar and is discouraged today. See further discussion in:
* @link https://stackoverflow.com/q/17452847/1593077
*
* @param c the single character to print
*/
PRINTF_VISIBILITY
void putchar(char c);
/**
* An implementation of the C standard's printf/vprintf
*
* @note you must implement a @ref putchar_ function for using this function - it invokes @ref putchar_
* rather than directly performing any I/O (which insulates it from any dependence on the operating system
* and external libraries).
*
* @param format A string specifying the format of the output, with %-marked specifiers of how to interpret
* additional arguments.
* @param arg Additional arguments to the function, one for each %-specifier in @p format string
* @return The number of characters written into @p s, not counting the terminating null character
*/
///@{
PRINTF_VISIBILITY
int printf_(const char* format, ...) ATTR_PRINTF(1, 2);
PRINTF_VISIBILITY
int vprintf_(const char* format, va_list arg) ATTR_VPRINTF(1);
///@}
/**
* An implementation of the C standard's sprintf/vsprintf
*
* @note For security considerations (the potential for exceeding the buffer bounds), please consider using
* the size-constrained variant, @ref snprintf / @ref vsnprintf , instead.
*
* @param s An array in which to store the formatted string. It must be large enough to fit the formatted
* output!
* @param format A string specifying the format of the output, with %-marked specifiers of how to interpret
* additional arguments.
* @param arg Additional arguments to the function, one for each specifier in @p format
* @return The number of characters written into @p s, not counting the terminating null character
*/
///@{
PRINTF_VISIBILITY
int sprintf_(char* s, const char* format, ...) ATTR_PRINTF(2, 3);
PRINTF_VISIBILITY
int vsprintf_(char* s, const char* format, va_list arg) ATTR_VPRINTF(2);
///@}
/**
* An implementation of the C standard's snprintf/vsnprintf
*
* @param s An array in which to store the formatted string. It must be large enough to fit either the
* entire formatted output, or at least @p n characters. Alternatively, it can be NULL, in which case
* nothing will be printed, and only the number of characters which _could_ have been printed is
* tallied and returned.
* @param n The maximum number of characters to write to the array, including a terminating null character
* @param format A string specifying the format of the output, with %-marked specifiers of how to interpret
* additional arguments.
* @param arg Additional arguments to the function, one for each specifier in @p format
* @return The number of characters that COULD have been written into @p s, not counting the terminating
* null character. A value equal or larger than @p n indicates truncation. Only when the returned value
* is non-negative and less than @p n, the null-terminated string has been fully and successfully printed.
*/
///@{
PRINTF_VISIBILITY
int snprintf_(char* s, size_t count, const char* format, ...) ATTR_PRINTF(3, 4);
PRINTF_VISIBILITY
int vsnprintf_(char* s, size_t count, const char* format, va_list arg) ATTR_VPRINTF(3);
///@}
/**
* printf/vprintf with user-specified output function
*
* An alternative to @ref printf_, in which the output function is specified dynamically
* (rather than @ref putchar_ being used)
*
* @param out An output function which takes one character and a type-erased additional parameters
* @param extra_arg The type-erased argument to pass to the output function @p out with each call
* @param format A string specifying the format of the output, with %-marked specifiers of how to interpret
* additional arguments.
* @param arg Additional arguments to the function, one for each specifier in @p format
* @return The number of characters for which the output f unction was invoked, not counting the terminating null character
*
*/
PRINTF_VISIBILITY
int fctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, ...) ATTR_PRINTF(3, 4);
PRINTF_VISIBILITY
int vfctprintf(void (*out)(char c, void* extra_arg), void* extra_arg, const char* format, va_list arg) ATTR_VPRINTF(3);
#if PRINTF_ALIAS_STANDARD_FUNCTION_NAMES
# undef printf_
# undef sprintf_
# undef vsprintf_
# undef snprintf_
# undef vsnprintf_
# undef vprintf_
#endif
#ifdef __cplusplus
}
#endif
#endif // PRINTF_H_

33
include/string.h Normal file
View File

@ -0,0 +1,33 @@
#pragma once
#include <types.h>
#ifdef __cplusplus
extern "C"
{
#endif
int isdigit(int c);
int isspace(int c);
int isempty(char *str);
unsigned int isdelim(char c, char *delim);
void *memcpy(void *dest, const void *src, size_t n);
void *memset(void *dest, int data, size_t nbytes);
void *memmove(void *dest, const void *src, size_t n);
int memcmp(const void *vl, const void *vr, size_t n);
long unsigned strlen(const char s[]);
int strncmp(const char *s1, const char *s2, unsigned long n);
char *strcat(char *destination, const char *source);
char *strcpy(char *destination, const char *source);
char *strncpy(char *destination, const char *source, unsigned long num);
int strcmp(const char *l, const char *r);
char *strstr(const char *haystack, const char *needle);
char *strdup(const char *String);
char *strchr(const char *String, int Char);
char *strrchr(const char *String, int Char);
int strncasecmp(const char *lhs, const char *rhs, long unsigned int Count);
int strcasecmp(const char *lhs, const char *rhs);
char *strtok(char *src, const char *delim);
#ifdef __cplusplus
}
#endif

8
include/sys.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef __FENNIX_KERNEL_SYSTEM_H__
#define __FENNIX_KERNEL_SYSTEM_H__
#include <types.h>
#endif // !__FENNIX_KERNEL_SYSTEM_H__

143
include/types.h Normal file
View File

@ -0,0 +1,143 @@
#ifndef __FENNIX_KERNEL_TYPES_H__
#define __FENNIX_KERNEL_TYPES_H__
#ifdef __cplusplus
#define EXTERNC extern "C"
#define START_EXTERNC \
EXTERNC \
{
#define END_EXTERNC \
}
#else
#define EXTERNC
#define START_EXTERNC
#define END_EXTERNC
#endif
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#define bool _Bool
#endif
#define asm __asm__
#define asmv __asm__ volatile
#define true 1
#define false 0
#ifdef __cplusplus
#define foreach for
#define in :
#endif
#ifndef __va_list__
typedef __builtin_va_list va_list;
#endif
#define va_start(v, l) __builtin_va_start(v, l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v, l) __builtin_va_arg(v, l)
#define ALIGN_UP(x, align) ((__typeof__(x))(((uint64_t)(x) + ((align)-1)) & (~((align)-1))))
#define ALIGN_DOWN(x, align) ((__typeof__(x))((x) & (~((align)-1))))
typedef __INT8_TYPE__ int8_t;
typedef __INT16_TYPE__ int16_t;
typedef __INT32_TYPE__ int32_t;
typedef __INT64_TYPE__ int64_t;
typedef __UINT8_TYPE__ uint8_t;
typedef __UINT16_TYPE__ uint16_t;
typedef __UINT32_TYPE__ uint32_t;
typedef __UINT64_TYPE__ uint64_t;
typedef __INT_LEAST8_TYPE__ int_least8_t;
typedef __INT_LEAST16_TYPE__ int_least16_t;
typedef __INT_LEAST32_TYPE__ int_least32_t;
typedef __INT_LEAST64_TYPE__ int_least64_t;
typedef __UINT_LEAST8_TYPE__ uint_least8_t;
typedef __UINT_LEAST16_TYPE__ uint_least16_t;
typedef __UINT_LEAST32_TYPE__ uint_least32_t;
typedef __UINT_LEAST64_TYPE__ uint_least64_t;
typedef __INT_FAST8_TYPE__ int_fast8_t;
typedef __INT_FAST16_TYPE__ int_fast16_t;
typedef __INT_FAST32_TYPE__ int_fast32_t;
typedef __INT_FAST64_TYPE__ int_fast64_t;
typedef __UINT_FAST8_TYPE__ uint_fast8_t;
typedef __UINT_FAST16_TYPE__ uint_fast16_t;
typedef __UINT_FAST32_TYPE__ uint_fast32_t;
typedef __UINT_FAST64_TYPE__ uint_fast64_t;
typedef __INTPTR_TYPE__ intptr_t;
typedef __UINTPTR_TYPE__ uintptr_t;
typedef __INTMAX_TYPE__ intmax_t;
typedef __UINTMAX_TYPE__ uintmax_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __SIZE_TYPE__ size_t;
#define INT8_MAX __INT8_MAX__
#define INT8_MIN (-INT8_MAX - 1)
#define UINT8_MAX __UINT8_MAX__
#define INT16_MAX __INT16_MAX__
#define INT16_MIN (-INT16_MAX - 1)
#define UINT16_MAX __UINT16_MAX__
#define INT32_MAX __INT32_MAX__
#define INT32_MIN (-INT32_MAX - 1)
#define UINT32_MAX __UINT32_MAX__
#define INT64_MAX __INT64_MAX__
#define INT64_MIN (-INT64_MAX - 1)
#define UINT64_MAX __UINT64_MAX__
#define INT_LEAST8_MAX __INT_LEAST8_MAX__
#define INT_LEAST8_MIN (-INT_LEAST8_MAX - 1)
#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__
#define INT_LEAST16_MAX __INT_LEAST16_MAX__
#define INT_LEAST16_MIN (-INT_LEAST16_MAX - 1)
#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__
#define INT_LEAST32_MAX __INT_LEAST32_MAX__
#define INT_LEAST32_MIN (-INT_LEAST32_MAX - 1)
#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__
#define INT_LEAST64_MAX __INT_LEAST64_MAX__
#define INT_LEAST64_MIN (-INT_LEAST64_MAX - 1)
#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__
#define INT_FAST8_MAX __INT_FAST8_MAX__
#define INT_FAST8_MIN (-INT_FAST8_MAX - 1)
#define UINT_FAST8_MAX __UINT_FAST8_MAX__
#define INT_FAST16_MAX __INT_FAST16_MAX__
#define INT_FAST16_MIN (-INT_FAST16_MAX - 1)
#define UINT_FAST16_MAX __UINT_FAST16_MAX__
#define INT_FAST32_MAX __INT_FAST32_MAX__
#define INT_FAST32_MIN (-INT_FAST32_MAX - 1)
#define UINT_FAST32_MAX __UINT_FAST32_MAX__
#define INT_FAST64_MAX __INT_FAST64_MAX__
#define INT_FAST64_MIN (-INT_FAST64_MAX - 1)
#define UINT_FAST64_MAX __UINT_FAST64_MAX__
#define INTPTR_MAX __INTPTR_MAX__
#define INTPTR_MIN (-INTPTR_MAX - 1)
#define UINTPTR_MAX __UINTPTR_MAX__
#define INTMAX_MAX __INTMAX_MAX__
#define INTMAX_MIN (-INTMAX_MAX - 1)
#define UINTMAX_MAX __UINTMAX_MAX__
#define PTRDIFF_MAX __PTRDIFF_MAX__
#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
#define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
#define SIG_ATOMIC_MIN __SIG_ATOMIC_MIN__
#define SIZE_MAX __SIZE_MAX__
#define WCHAR_MAX __WCHAR_MAX__
#define WCHAR_MIN __WCHAR_MIN__
#define WINT_MAX __WINT_MAX__
#define WINT_MIN __WINT_MIN__
#endif // !__FENNIX_KERNEL_TYPES_H__

71
include/uart.hpp Normal file
View File

@ -0,0 +1,71 @@
#ifndef __FENNIX_KERNEL_UART_H__
#define __FENNIX_KERNEL_UART_H__
#include <types.h>
namespace UniversalAsynchronousReceiverTransmitter
{
/**
* @brief Serial ports. (if available)
*/
enum SerialPorts
{
COMNULL = 0,
COM1 = 0x3F8,
COM2 = 0x2F8,
COM3 = 0x3E8,
COM4 = 0x2E8,
COM5 = 0x5F8,
COM6 = 0x4F8,
COM7 = 0x5E8,
COM8 = 0x4E8
};
class UART
{
private:
SerialPorts Port;
public:
UART(SerialPorts Port = COMNULL);
~UART();
void Write(uint8_t Char);
uint8_t Read();
};
class Events
{
private:
SerialPorts Port;
protected:
/**
* @brief UART events.
* @param Port if none, all ports are registered for events.
*/
Events(SerialPorts Port = COMNULL);
~Events();
public:
/**
* @brief Get the Registered Port object
* @return SerialPorts
*/
SerialPorts GetRegisteredPort() { return this->Port; }
/**
* @brief Called when a character is sent.
* @param Char the sent character.
*/
virtual void OnSent(uint8_t Char) {}
/**
* @brief Called when a character is received.
* @param Char the received character.
*/
virtual void OnReceived(uint8_t Char) {}
};
}
#endif // !__FENNIX_KERNEL_UART_H__

162
include/vector.hpp Normal file
View File

@ -0,0 +1,162 @@
#pragma once
#include <types.h>
#include <cstring>
template <class T>
class Vector
{
private:
uint64_t VectorSize = 0;
uint64_t VectorCapacity = 0;
T *VectorBuffer = nullptr;
public:
typedef T *iterator;
Vector()
{
VectorCapacity = 0;
VectorSize = 0;
VectorBuffer = 0;
}
Vector(uint64_t Size)
{
VectorCapacity = Size;
VectorSize = Size;
#ifdef DEBUG_MEM_ALLOCATION
debug("VECTOR ALLOCATION: Vector( %ld )", Size);
#endif
VectorBuffer = new T[Size];
}
Vector(uint64_t Size, const T &Initial)
{
VectorSize = Size;
VectorCapacity = Size;
#ifdef DEBUG_MEM_ALLOCATION
debug("VECTOR ALLOCATION: Vector( %ld %llx )", Size, Initial);
#endif
VectorBuffer = new T[Size];
for (uint64_t i = 0; i < Size; i++)
VectorBuffer[i] = Initial;
}
Vector(const Vector<T> &Vector)
{
VectorSize = Vector.VectorSize;
VectorCapacity = Vector.VectorCapacity;
#ifdef DEBUG_MEM_ALLOCATION
debug("VECTOR ALLOCATION: Vector( <vector> )->Size: %ld", VectorSize);
#endif
VectorBuffer = new T[VectorSize];
for (uint64_t i = 0; i < VectorSize; i++)
VectorBuffer[i] = Vector.VectorBuffer[i];
}
~Vector()
{
#ifdef DEBUG_MEM_ALLOCATION
debug("VECTOR ALLOCATION: ~Vector( ~%lx )", VectorBuffer);
#endif
delete[] VectorBuffer;
}
void remove(uint64_t Position)
{
if (Position >= VectorSize)
return;
memset(&*(VectorBuffer + Position), 0, sizeof(T));
for (uint64_t i = 0; i < VectorSize - 1; i++)
{
*(VectorBuffer + Position + i) = *(VectorBuffer + Position + i + 1);
}
VectorSize--;
}
uint64_t capacity() const { return VectorCapacity; }
uint64_t size() const { return VectorSize; }
bool empty() const;
iterator begin() { return VectorBuffer; }
iterator end() { return VectorBuffer + size(); }
T &front() { return VectorBuffer[0]; }
T &back() { return VectorBuffer[VectorSize - 1]; }
void push_back(const T &Value)
{
if (VectorSize >= VectorCapacity)
reserve(VectorCapacity + 5);
VectorBuffer[VectorSize++] = Value;
}
void pop_back() { VectorSize--; }
void reverse()
{
if (VectorSize <= 1)
return;
for (uint64_t i = 0, j = VectorSize - 1; i < j; i++, j--)
{
T c = *(VectorBuffer + i);
*(VectorBuffer + i) = *(VectorBuffer + j);
*(VectorBuffer + j) = c;
}
}
void reserve(uint64_t Capacity)
{
if (VectorBuffer == 0)
{
VectorSize = 0;
VectorCapacity = 0;
}
#ifdef DEBUG_MEM_ALLOCATION
debug("VECTOR ALLOCATION: reverse( %ld )", Capacity);
#endif
T *Newbuffer = new T[Capacity];
uint64_t _Size = Capacity < VectorSize ? Capacity : VectorSize;
for (uint64_t i = 0; i < _Size; i++)
Newbuffer[i] = VectorBuffer[i];
VectorCapacity = Capacity;
#ifdef DEBUG_MEM_ALLOCATION
debug("VECTOR ALLOCATION: reverse( <Capacity> )->Buffer:~%ld", VectorBuffer);
#endif
delete[] VectorBuffer;
VectorBuffer = Newbuffer;
}
void resize(uint64_t Size)
{
reserve(Size);
VectorSize = Size;
}
T &operator[](uint64_t Index) { return VectorBuffer[Index]; }
Vector<T> &operator=(const Vector<T> &Vector)
{
delete[] VectorBuffer;
VectorSize = Vector.VectorSize;
VectorCapacity = Vector.VectorCapacity;
#ifdef DEBUG_MEM_ALLOCATION
debug("VECTOR ALLOCATION: operator=( <vector> )->Size:%ld", VectorSize);
#endif
VectorBuffer = new T[VectorSize];
for (uint64_t i = 0; i < VectorSize; i++)
VectorBuffer[i] = Vector.VectorBuffer[i];
return *this;
}
void clear()
{
VectorCapacity = 0;
VectorSize = 0;
VectorBuffer = 0;
}
};

BIN
kernel.fsys Normal file → Executable file

Binary file not shown.

11
kernel.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef __FENNIX_KERNEL_KERNEL_H__
#define __FENNIX_KERNEL_KERNEL_H__
#include <types.h>
#include <boot/binfo.h>
extern struct BootInfo *bInfo;
EXTERNC void kernel_entry(struct BootInfo *Info);
#endif // !__FENNIX_KERNEL_KERNEL_H__

View File

28
lib/Bitmap.cpp Normal file
View File

@ -0,0 +1,28 @@
#include <bitmap.hpp>
bool Bitmap::operator[](uint64_t index) { return Get(index); }
bool Bitmap::Get(uint64_t index)
{
if (index > Size * 8)
return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex;
if ((Buffer[byteIndex] & bitIndexer) > 0)
return true;
return false;
}
bool Bitmap::Set(uint64_t index, bool value)
{
if (index > Size * 8)
return false;
uint64_t byteIndex = index / 8;
uint8_t bitIndex = index % 8;
uint8_t bitIndexer = 0b10000000 >> bitIndex;
Buffer[byteIndex] &= ~bitIndexer;
if (value)
Buffer[byteIndex] |= bitIndexer;
return true;
}

159
lib/String.c Normal file
View File

@ -0,0 +1,159 @@
#include <string.h>
#include <types.h>
void *memcpy(void *dest, const void *src, size_t n)
{
unsigned char *d = (unsigned char *)dest;
const unsigned char *c = (const unsigned char *)src;
for (size_t i = 0; i < n; i++)
d[i] = c[i];
return dest;
}
void *memset(void *dest, int data, size_t nbytes)
{
unsigned char *buf = (unsigned char *)dest;
for (size_t i = 0; i < nbytes; i++)
buf[i] = (unsigned char)data;
return dest;
}
void *memmove(void *dest, const void *src, size_t n)
{
unsigned char *dst = (unsigned char *)dest;
const unsigned char *srcc = (const unsigned char *)src;
if (dst < srcc)
{
for (size_t i = 0; i < n; i++)
dst[i] = srcc[i];
}
else
{
for (size_t i = n; i != 0; i--)
dst[i - 1] = srcc[i - 1];
}
return dest;
}
int memcmp(const void *vl, const void *vr, size_t n)
{
const unsigned char *l = vl, *r = vr;
for (; n && *l == *r; n--, l++, r++)
;
return n ? *l - *r : 0;
}
int strncmp(const char *s1, const char *s2, size_t n)
{
for (size_t i = 0; i < n; i++)
{
char c1 = s1[i], c2 = s2[i];
if (c1 != c2)
return c1 - c2;
if (!c1)
return 0;
}
return 0;
}
long unsigned strlen(const char s[])
{
long unsigned i = 0;
while (s[i] != '\0')
++i;
return i;
}
char *strcat(char *destination, const char *source)
{
if ((destination == NULL) && (source == NULL))
return NULL;
char *start = destination;
while (*start != '\0')
{
start++;
}
while (*source != '\0')
{
*start++ = *source++;
}
*start = '\0';
return destination;
}
char *strcpy(char *destination, const char *source)
{
if (destination == NULL)
return NULL;
char *ptr = destination;
while (*source != '\0')
{
*destination = *source;
destination++;
source++;
}
*destination = '\0';
return ptr;
}
char *strncpy(char *destination, const char *source, unsigned long num)
{
if (destination == NULL)
return NULL;
char *ptr = destination;
while (*source && num--)
{
*destination = *source;
destination++;
source++;
}
*destination = '\0';
return ptr;
}
int strcmp(const char *l, const char *r)
{
for (; *l == *r && *l; l++, r++)
;
return *(unsigned char *)l - *(unsigned char *)r;
}
char *strstr(const char *haystack, const char *needle)
{
const char *a = haystack, *b = needle;
while (1)
{
if (!*b)
return (char *)haystack;
if (!*a)
return NULL;
if (*a++ != *b++)
{
a = ++haystack;
b = needle;
}
}
}
int isdigit(int c)
{
return c >= '0' && c <= '9';
}
int isspace(int c)
{
return c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '\f' || c == '\v';
}
int isempty(char *str)
{
if (strlen(str) == 0)
return 1;
while (*str != '\0')
{
if (!isspace(*str))
return 0;
str++;
}
return 1;
}

140
lib/cxxabi.cpp Normal file
View File

@ -0,0 +1,140 @@
#include <types.h>
#include <debug.h>
// TODO: complete implementation for everything
// TODO: https://wiki.osdev.org/C%2B%2B
#define ATEXIT_MAX_FUNCS 128
typedef unsigned uarch_t;
struct atexit_func_entry_t
{
/*
* Each member is at least 4 bytes large. Such that each entry is 12bytes.
* 128 * 12 = 1.5KB exact.
**/
void (*destructor_func)(void *);
void *obj_ptr;
void *dso_handle;
};
typedef enum
{
_URC_NO_REASON = 0,
_URC_FOREIGN_EXCEPTION_CAUGHT = 1,
_URC_FATAL_PHASE2_ERROR = 2,
_URC_FATAL_PHASE1_ERROR = 3,
_URC_NORMAL_STOP = 4,
_URC_END_OF_STACK = 5,
_URC_HANDLER_FOUND = 6,
_URC_INSTALL_CONTEXT = 7,
_URC_CONTINUE_UNWIND = 8
} _Unwind_Reason_Code;
struct _Unwind_Context;
typedef unsigned _Unwind_Exception_Class __attribute__((__mode__(__DI__)));
typedef unsigned _Unwind_Word __attribute__((__mode__(__unwind_word__)));
typedef void (*_Unwind_Exception_Cleanup_Fn)(_Unwind_Reason_Code, struct _Unwind_Exception *);
typedef int _Unwind_Action;
struct _Unwind_Exception
{
_Unwind_Exception_Class exception_class;
_Unwind_Exception_Cleanup_Fn exception_cleanup;
#if !defined(__USING_SJLJ_EXCEPTIONS__) && defined(__SEH__)
_Unwind_Word private_[6];
#else
_Unwind_Word private_1;
_Unwind_Word private_2;
#endif
} __attribute__((__aligned__));
extern void *__dso_handle = 0;
atexit_func_entry_t __atexit_funcs[ATEXIT_MAX_FUNCS];
uarch_t __atexit_func_count = 0;
extern "C" int __cxa_atexit(void (*f)(void *), void *objptr, void *dso)
{
fixme("__cxa_atexit( %p %p %p ) triggered.", f, objptr, dso);
if (__atexit_func_count >= ATEXIT_MAX_FUNCS)
return -1;
__atexit_funcs[__atexit_func_count].destructor_func = f;
__atexit_funcs[__atexit_func_count].obj_ptr = objptr;
__atexit_funcs[__atexit_func_count].dso_handle = dso;
__atexit_func_count++;
return 0;
}
extern "C" void __cxa_finalize(void *f)
{
fixme("__cxa_finalize( %p ) triggered.", f);
uarch_t i = __atexit_func_count;
if (!f)
{
while (i--)
if (__atexit_funcs[i].destructor_func)
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
return;
}
while (i--)
if (__atexit_funcs[i].destructor_func == f)
{
(*__atexit_funcs[i].destructor_func)(__atexit_funcs[i].obj_ptr);
__atexit_funcs[i].destructor_func = 0;
}
}
extern "C" _Unwind_Reason_Code __gxx_personality_v0(int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, _Unwind_Exception *ue_header, _Unwind_Context *context)
{
fixme("__gxx_personality_v0( %d %p %p %p %p ) triggered.", version, actions, exception_class, ue_header, context);
return _URC_NO_REASON;
}
extern "C" void _Unwind_Resume(struct _Unwind_Exception *exc) { fixme("_Unwind_Resume( %p ) triggered.", exc); }
extern "C" void *__cxa_allocate_exception(uint64_t thrown_size) throw()
{
fixme("__cxa_allocate_exception( %#llu ) triggered.", thrown_size);
return (void *)0;
}
extern "C" void __cxa_throw(void *thrown_object, void *tinfo, void (*dest)(void *)) { fixme("__cxa_throw( %p %p %p ) triggered.", thrown_object, tinfo, dest); }
extern "C" void __cxa_rethrow() { fixme("__cxa_rethrow() triggered."); }
extern "C" void __cxa_pure_virtual() { fixme("__cxa_pure_virtual() triggered."); }
extern "C" void __cxa_throw_bad_array_new_length() { fixme("__cxa_throw_bad_array_new_length() triggered."); }
extern "C" void __cxa_free_exception(void *thrown_exception) { fixme("__cxa_free_exception( %p ) triggered.", thrown_exception); }
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4)
extern "C" void *__cxa_begin_catch(void *e) throw()
#else
extern "C" void *__cxa_begin_catch(void *e)
#endif
{
fixme("__cxa_begin_catch( %p ) triggered.", e);
return (void *)0;
}
extern "C" void __cxa_end_catch() { fixme("__cxa_end_catch() triggered."); }
__extension__ typedef int __guard __attribute__((mode(__DI__)));
extern "C" int __cxa_guard_acquire(__guard *g)
{
fixme("__cxa_guard_acquire( %p ) triggered.", g);
return !*(char *)(g);
}
extern "C" void __cxa_guard_release(__guard *g)
{
fixme("__cxa_guard_release( %p ) triggered.", g);
*(char *)g = 1;
}
extern "C" void __cxa_guard_abort(__guard *g) { fixme("__cxa_guard_abort( %p ) triggered.", g); }

790
lib/liballoc_1_1.c Normal file
View File

@ -0,0 +1,790 @@
#include "liballoc_1_1.h"
/** Durand's Amazing Super Duper Memory functions. */
#define VERSION "1.1"
#define ALIGNMENT 16ul // 4ul ///< This is the byte alignment that memory must be allocated on. IMPORTANT for GTK and other stuff.
#define ALIGN_TYPE char /// unsigned char[16] /// unsigned short
#define ALIGN_INFO sizeof(ALIGN_TYPE) * 16 ///< Alignment information is stored right before the pointer. This is the number of bytes of information stored there.
#define USE_CASE1
#define USE_CASE2
#define USE_CASE3
#define USE_CASE4
#define USE_CASE5
/** This macro will conveniently align our pointer upwards */
#define ALIGN(ptr) \
if (ALIGNMENT > 1) \
{ \
uintptr_t diff; \
ptr = (void *)((uintptr_t)ptr + ALIGN_INFO); \
diff = (uintptr_t)ptr & (ALIGNMENT - 1); \
if (diff != 0) \
{ \
diff = ALIGNMENT - diff; \
ptr = (void *)((uintptr_t)ptr + diff); \
} \
*((ALIGN_TYPE *)((uintptr_t)ptr - ALIGN_INFO)) = \
diff + ALIGN_INFO; \
}
#define UNALIGN(ptr) \
if (ALIGNMENT > 1) \
{ \
uintptr_t diff = *((ALIGN_TYPE *)((uintptr_t)ptr - ALIGN_INFO)); \
if (diff < (ALIGNMENT + ALIGN_INFO)) \
{ \
ptr = (void *)((uintptr_t)ptr - diff); \
} \
}
#define LIBALLOC_MAGIC 0xc001c0de
#define LIBALLOC_DEAD 0xdeaddead
// #define LIBALLOCDEBUG 1
#define LIBALLOCINFO 1
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
// #include <stdio.h>
// #include <stdlib.h>
#include <debug.h>
// #define FLUSH() fflush(stdout)
#define FLUSH()
#define atexit(x)
#define printf(m, ...) trace(m, ##__VA_ARGS__)
#endif
/** A structure found at the top of all system allocated
* memory blocks. It details the usage of the memory block.
*/
struct liballoc_major
{
struct liballoc_major *prev; ///< Linked list information.
struct liballoc_major *next; ///< Linked list information.
unsigned int pages; ///< The number of pages in the block.
unsigned int size; ///< The number of pages in the block.
unsigned int usage; ///< The number of bytes used in the block.
struct liballoc_minor *first; ///< A pointer to the first allocated memory in the block.
};
/** This is a structure found at the beginning of all
* sections in a major block which were allocated by a
* malloc, calloc, realloc call.
*/
struct liballoc_minor
{
struct liballoc_minor *prev; ///< Linked list information.
struct liballoc_minor *next; ///< Linked list information.
struct liballoc_major *block; ///< The owning block. A pointer to the major structure.
unsigned int magic; ///< A magic number to idenfity correctness.
unsigned int size; ///< The size of the memory allocated. Could be 1 byte or more.
unsigned int req_size; ///< The size of memory requested.
};
static struct liballoc_major *l_memRoot = NULL; ///< The root memory block acquired from the system.
static struct liballoc_major *l_bestBet = NULL; ///< The major with the most free memory.
static unsigned int l_pageSize = 4096; ///< The size of an individual page. Set up in liballoc_init.
static unsigned int l_pageCount = 16; ///< The number of pages to request per chunk. Set up in liballoc_init.
static unsigned long long l_allocated = 0; ///< Running total of allocated memory.
static unsigned long long l_inuse = 0; ///< Running total of used memory.
static long long l_warningCount = 0; ///< Number of warnings encountered
static long long l_errorCount = 0; ///< Number of actual errors
static long long l_possibleOverruns = 0; ///< Number of possible overruns
// *********** HELPER FUNCTIONS *******************************
static void *liballoc_memset(void *s, int c, size_t n)
{
unsigned int i;
for (i = 0; i < n; i++)
((char *)s)[i] = c;
return s;
}
static void *liballoc_memcpy(void *s1, const void *s2, size_t n)
{
char *cdest;
char *csrc;
unsigned int *ldest = (unsigned int *)s1;
unsigned int *lsrc = (unsigned int *)s2;
while (n >= sizeof(unsigned int))
{
*ldest++ = *lsrc++;
n -= sizeof(unsigned int);
}
cdest = (char *)ldest;
csrc = (char *)lsrc;
while (n > 0)
{
*cdest++ = *csrc++;
n -= 1;
}
return s1;
}
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
static void liballoc_dump()
{
#ifdef LIBALLOCDEBUG
struct liballoc_major *maj = l_memRoot;
struct liballoc_minor *min = NULL;
#endif
printf("liballoc: ------ Memory data ---------------\n");
printf("liballoc: System memory allocated: %i bytes\n", l_allocated);
printf("liballoc: Memory in used (malloc'ed): %i bytes\n", l_inuse);
printf("liballoc: Warning count: %i\n", l_warningCount);
printf("liballoc: Error count: %i\n", l_errorCount);
printf("liballoc: Possible overruns: %i\n", l_possibleOverruns);
#ifdef LIBALLOCDEBUG
while (maj != NULL)
{
printf("liballoc: %x: total = %i, used = %i\n",
maj,
maj->size,
maj->usage);
min = maj->first;
while (min != NULL)
{
printf("liballoc: %x: %i bytes\n",
min,
min->size);
min = min->next;
}
maj = maj->next;
}
#endif
FLUSH();
}
#endif
// ***************************************************************
static struct liballoc_major *allocate_new_page(unsigned int size)
{
unsigned int st;
struct liballoc_major *maj;
// This is how much space is required.
st = size + sizeof(struct liballoc_major);
st += sizeof(struct liballoc_minor);
// Perfect amount of space?
if ((st % l_pageSize) == 0)
st = st / (l_pageSize);
else
st = st / (l_pageSize) + 1;
// No, add the buffer.
// Make sure it's >= the minimum size.
if (st < l_pageCount)
st = l_pageCount;
maj = (struct liballoc_major *)liballoc_alloc(st);
if (maj == NULL)
{
l_warningCount += 1;
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
printf("liballoc: WARNING: liballoc_alloc( %i ) return NULL\n", st);
FLUSH();
#endif
return NULL; // uh oh, we ran out of memory.
}
maj->prev = NULL;
maj->next = NULL;
maj->pages = st;
maj->size = st * l_pageSize;
maj->usage = sizeof(struct liballoc_major);
maj->first = NULL;
l_allocated += maj->size;
#ifdef LIBALLOCDEBUG
printf("liballoc: Resource allocated %x of %i pages (%i bytes) for %i size.\n", maj, st, maj->size, size);
printf("liballoc: Total memory usage = %i KB\n", (int)((l_allocated / (1024))));
FLUSH();
#endif
return maj;
}
void *PREFIX(malloc)(size_t req_size)
{
int startedBet = 0;
unsigned long long bestSize = 0;
void *p = NULL;
uintptr_t diff;
struct liballoc_major *maj;
struct liballoc_minor *min;
struct liballoc_minor *new_min;
unsigned long size = req_size;
// For alignment, we adjust size so there's enough space to align.
if (ALIGNMENT > 1)
{
size += ALIGNMENT + ALIGN_INFO;
}
// So, ideally, we really want an alignment of 0 or 1 in order
// to save space.
liballoc_lock();
if (size == 0)
{
l_warningCount += 1;
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
printf("liballoc: WARNING: alloc( 0 ) called from %x\n",
__builtin_return_address(0));
FLUSH();
#endif
liballoc_unlock();
return PREFIX(malloc)(1);
}
if (l_memRoot == NULL)
{
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
#ifdef LIBALLOCDEBUG
printf("liballoc: initialization of liballoc " VERSION "\n");
#endif
atexit(liballoc_dump);
FLUSH();
#endif
// This is the first time we are being used.
l_memRoot = allocate_new_page(size);
if (l_memRoot == NULL)
{
liballoc_unlock();
#ifdef LIBALLOCDEBUG
printf("liballoc: initial l_memRoot initialization failed\n", p);
FLUSH();
#endif
return NULL;
}
#ifdef LIBALLOCDEBUG
printf("liballoc: set up first memory major %x\n", l_memRoot);
FLUSH();
#endif
}
#ifdef LIBALLOCDEBUG
printf("liballoc: %x PREFIX(malloc)( %i ): ",
__builtin_return_address(0),
size);
FLUSH();
#endif
// Now we need to bounce through every major and find enough space....
maj = l_memRoot;
startedBet = 0;
// Start at the best bet....
if (l_bestBet != NULL)
{
bestSize = l_bestBet->size - l_bestBet->usage;
if (bestSize > (size + sizeof(struct liballoc_minor)))
{
maj = l_bestBet;
startedBet = 1;
}
}
while (maj != NULL)
{
diff = maj->size - maj->usage;
// free memory in the block
if (bestSize < diff)
{
// Hmm.. this one has more memory then our bestBet. Remember!
l_bestBet = maj;
bestSize = diff;
}
#ifdef USE_CASE1
// CASE 1: There is not enough space in this major block.
if (diff < (size + sizeof(struct liballoc_minor)))
{
#ifdef LIBALLOCDEBUG
printf("CASE 1: Insufficient space in block %x\n", maj);
FLUSH();
#endif
// Another major block next to this one?
if (maj->next != NULL)
{
maj = maj->next; // Hop to that one.
continue;
}
if (startedBet == 1) // If we started at the best bet,
{ // let's start all over again.
maj = l_memRoot;
startedBet = 0;
continue;
}
// Create a new major block next to this one and...
maj->next = allocate_new_page(size); // next one will be okay.
if (maj->next == NULL)
break; // no more memory.
maj->next->prev = maj;
maj = maj->next;
// .. fall through to CASE 2 ..
}
#endif
#ifdef USE_CASE2
// CASE 2: It's a brand new block.
if (maj->first == NULL)
{
maj->first = (struct liballoc_minor *)((uintptr_t)maj + sizeof(struct liballoc_major));
maj->first->magic = LIBALLOC_MAGIC;
maj->first->prev = NULL;
maj->first->next = NULL;
maj->first->block = maj;
maj->first->size = size;
maj->first->req_size = req_size;
maj->usage += size + sizeof(struct liballoc_minor);
l_inuse += size;
p = (void *)((uintptr_t)(maj->first) + sizeof(struct liballoc_minor));
ALIGN(p);
#ifdef LIBALLOCDEBUG
printf("CASE 2: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(); // release the lock
return p;
}
#endif
#ifdef USE_CASE3
// CASE 3: Block in use and enough space at the start of the block.
diff = (uintptr_t)(maj->first);
diff -= (uintptr_t)maj;
diff -= sizeof(struct liballoc_major);
if (diff >= (size + sizeof(struct liballoc_minor)))
{
// Yes, space in front. Squeeze in.
maj->first->prev = (struct liballoc_minor *)((uintptr_t)maj + sizeof(struct liballoc_major));
maj->first->prev->next = maj->first;
maj->first = maj->first->prev;
maj->first->magic = LIBALLOC_MAGIC;
maj->first->prev = NULL;
maj->first->block = maj;
maj->first->size = size;
maj->first->req_size = req_size;
maj->usage += size + sizeof(struct liballoc_minor);
l_inuse += size;
p = (void *)((uintptr_t)(maj->first) + sizeof(struct liballoc_minor));
ALIGN(p);
#ifdef LIBALLOCDEBUG
printf("CASE 3: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(); // release the lock
return p;
}
#endif
#ifdef USE_CASE4
// CASE 4: There is enough space in this block. But is it contiguous?
min = maj->first;
// Looping within the block now...
while (min != NULL)
{
// CASE 4.1: End of minors in a block. Space from last and end?
if (min->next == NULL)
{
// the rest of this block is free... is it big enough?
diff = (uintptr_t)(maj) + maj->size;
diff -= (uintptr_t)min;
diff -= sizeof(struct liballoc_minor);
diff -= min->size;
// minus already existing usage..
if (diff >= (size + sizeof(struct liballoc_minor)))
{
// yay....
min->next = (struct liballoc_minor *)((uintptr_t)min + sizeof(struct liballoc_minor) + min->size);
min->next->prev = min;
min = min->next;
min->next = NULL;
min->magic = LIBALLOC_MAGIC;
min->block = maj;
min->size = size;
min->req_size = req_size;
maj->usage += size + sizeof(struct liballoc_minor);
l_inuse += size;
p = (void *)((uintptr_t)min + sizeof(struct liballoc_minor));
ALIGN(p);
#ifdef LIBALLOCDEBUG
printf("CASE 4.1: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(); // release the lock
return p;
}
}
// CASE 4.2: Is there space between two minors?
if (min->next != NULL)
{
// is the difference between here and next big enough?
diff = (uintptr_t)(min->next);
diff -= (uintptr_t)min;
diff -= sizeof(struct liballoc_minor);
diff -= min->size;
// minus our existing usage.
if (diff >= (size + sizeof(struct liballoc_minor)))
{
// yay......
new_min = (struct liballoc_minor *)((uintptr_t)min + sizeof(struct liballoc_minor) + min->size);
new_min->magic = LIBALLOC_MAGIC;
new_min->next = min->next;
new_min->prev = min;
new_min->size = size;
new_min->req_size = req_size;
new_min->block = maj;
min->next->prev = new_min;
min->next = new_min;
maj->usage += size + sizeof(struct liballoc_minor);
l_inuse += size;
p = (void *)((uintptr_t)new_min + sizeof(struct liballoc_minor));
ALIGN(p);
#ifdef LIBALLOCDEBUG
printf("CASE 4.2: returning %x\n", p);
FLUSH();
#endif
liballoc_unlock(); // release the lock
return p;
}
} // min->next != NULL
min = min->next;
} // while min != NULL ...
#endif
#ifdef USE_CASE5
// CASE 5: Block full! Ensure next block and loop.
if (maj->next == NULL)
{
#ifdef LIBALLOCDEBUG
printf("CASE 5: block full\n");
FLUSH();
#endif
if (startedBet == 1)
{
maj = l_memRoot;
startedBet = 0;
continue;
}
// we've run out. we need more...
maj->next = allocate_new_page(size); // next one guaranteed to be okay
if (maj->next == NULL)
break; // uh oh, no more memory.....
maj->next->prev = maj;
}
#endif
maj = maj->next;
} // while (maj != NULL)
liballoc_unlock(); // release the lock
#ifdef LIBALLOCDEBUG
printf("All cases exhausted. No memory available.\n");
FLUSH();
#endif
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
printf("liballoc: WARNING: PREFIX(malloc)( %i ) returning NULL.\n", size);
liballoc_dump();
FLUSH();
#endif
return NULL;
}
void PREFIX(free)(void *ptr)
{
struct liballoc_minor *min;
struct liballoc_major *maj;
if (ptr == NULL)
{
l_warningCount += 1;
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
printf("liballoc: WARNING: PREFIX(free)( NULL ) called from %x\n",
__builtin_return_address(0));
FLUSH();
#endif
return;
}
UNALIGN(ptr);
liballoc_lock(); // lockit
min = (struct liballoc_minor *)((uintptr_t)ptr - sizeof(struct liballoc_minor));
if (min->magic != LIBALLOC_MAGIC)
{
l_errorCount += 1;
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
if (
((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) ||
((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) ||
((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF)))
{
l_possibleOverruns += 1;
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
printf("liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n",
min->magic,
LIBALLOC_MAGIC);
FLUSH();
#endif
}
if (min->magic == LIBALLOC_DEAD)
{
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
printf("liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
ptr,
__builtin_return_address(0));
FLUSH();
#endif
}
else
{
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
printf("liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n",
ptr,
__builtin_return_address(0));
FLUSH();
#endif
}
// being lied to...
liballoc_unlock(); // release the lock
return;
}
#ifdef LIBALLOCDEBUG
printf("liballoc: %x PREFIX(free)( %x ): ",
__builtin_return_address(0),
ptr);
FLUSH();
#endif
maj = min->block;
l_inuse -= min->size;
maj->usage -= (min->size + sizeof(struct liballoc_minor));
min->magic = LIBALLOC_DEAD; // No mojo.
if (min->next != NULL)
min->next->prev = min->prev;
if (min->prev != NULL)
min->prev->next = min->next;
if (min->prev == NULL)
maj->first = min->next;
// Might empty the block. This was the first
// minor.
// We need to clean up after the majors now....
if (maj->first == NULL) // Block completely unused.
{
if (l_memRoot == maj)
l_memRoot = maj->next;
if (l_bestBet == maj)
l_bestBet = NULL;
if (maj->prev != NULL)
maj->prev->next = maj->next;
if (maj->next != NULL)
maj->next->prev = maj->prev;
l_allocated -= maj->size;
liballoc_free(maj, maj->pages);
}
else
{
if (l_bestBet != NULL)
{
int bestSize = l_bestBet->size - l_bestBet->usage;
int majSize = maj->size - maj->usage;
if (majSize > bestSize)
l_bestBet = maj;
}
}
#ifdef LIBALLOCDEBUG
printf("OK\n");
FLUSH();
#endif
liballoc_unlock(); // release the lock
}
void *PREFIX(calloc)(size_t nobj, size_t size)
{
int real_size;
void *p;
real_size = nobj * size;
p = PREFIX(malloc)(real_size);
liballoc_memset(p, 0, real_size);
return p;
}
void *PREFIX(realloc)(void *p, size_t size)
{
void *ptr;
struct liballoc_minor *min;
unsigned int real_size;
// Honour the case of size == 0 => free old and return NULL
if (size == 0)
{
PREFIX(free)
(p);
return NULL;
}
// In the case of a NULL pointer, return a simple malloc.
if (p == NULL)
return PREFIX(malloc)(size);
// Unalign the pointer if required.
ptr = p;
UNALIGN(ptr);
liballoc_lock(); // lockit
min = (struct liballoc_minor *)((uintptr_t)ptr - sizeof(struct liballoc_minor));
// Ensure it is a valid structure.
if (min->magic != LIBALLOC_MAGIC)
{
l_errorCount += 1;
// Check for overrun errors. For all bytes of LIBALLOC_MAGIC
if (
((min->magic & 0xFFFFFF) == (LIBALLOC_MAGIC & 0xFFFFFF)) ||
((min->magic & 0xFFFF) == (LIBALLOC_MAGIC & 0xFFFF)) ||
((min->magic & 0xFF) == (LIBALLOC_MAGIC & 0xFF)))
{
l_possibleOverruns += 1;
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
printf("liballoc: ERROR: Possible 1-3 byte overrun for magic %x != %x\n",
min->magic,
LIBALLOC_MAGIC);
FLUSH();
#endif
}
if (min->magic == LIBALLOC_DEAD)
{
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
printf("liballoc: ERROR: multiple PREFIX(free)() attempt on %x from %x.\n",
ptr,
__builtin_return_address(0));
FLUSH();
#endif
}
else
{
#if defined LIBALLOCDEBUG || defined LIBALLOCINFO
printf("liballoc: ERROR: Bad PREFIX(free)( %x ) called from %x\n",
ptr,
__builtin_return_address(0));
FLUSH();
#endif
}
// being lied to...
liballoc_unlock(); // release the lock
return NULL;
}
// Definitely a memory block.
real_size = min->req_size;
if (real_size >= size)
{
min->req_size = size;
liballoc_unlock();
return p;
}
liballoc_unlock();
// If we got here then we're reallocating to a block bigger than us.
ptr = PREFIX(malloc)(size); // We need to allocate new memory
liballoc_memcpy(ptr, p, real_size);
PREFIX(free)
(p);
return ptr;
}

74
lib/liballoc_1_1.h Normal file
View File

@ -0,0 +1,74 @@
#ifndef _LIBALLOC_H
#define _LIBALLOC_H
#include <types.h>
/** \defgroup ALLOCHOOKS liballoc hooks
*
* These are the OS specific functions which need to
* be implemented on any platform that the library
* is expected to work on.
*/
/** @{ */
// If we are told to not define our own size_t, then we skip the define.
//#define _HAVE_UINTPTR_T
// typedef unsigned long uintptr_t;
// This lets you prefix malloc and friends
#define PREFIX(func) kliballoc_##func
#ifdef __cplusplus
extern "C"
{
#endif
/** This function is supposed to lock the memory data structures. It
* could be as simple as disabling interrupts or acquiring a spinlock.
* It's up to you to decide.
*
* \return 0 if the lock was acquired successfully. Anything else is
* failure.
*/
extern int liballoc_lock();
/** This function unlocks what was previously locked by the liballoc_lock
* function. If it disabled interrupts, it enables interrupts. If it
* had acquiried a spinlock, it releases the spinlock. etc.
*
* \return 0 if the lock was successfully released.
*/
extern int liballoc_unlock();
/** This is the hook into the local system which allocates pages. It
* accepts an integer parameter which is the number of pages
* required. The page size was set up in the liballoc_init function.
*
* \return NULL if the pages were not allocated.
* \return A pointer to the allocated memory.
*/
extern void *liballoc_alloc(size_t);
/** This frees previously allocated memory. The void* parameter passed
* to the function is the exact same value returned from a previous
* liballoc_alloc call.
*
* The integer value is the number of pages to free.
*
* \return 0 if the memory was successfully freed.
*/
extern int liballoc_free(void *, size_t);
extern void *PREFIX(malloc)(size_t); ///< The standard function.
extern void *PREFIX(realloc)(void *, size_t); ///< The standard function.
extern void *PREFIX(calloc)(size_t, size_t); ///< The standard function.
extern void PREFIX(free)(void *); ///< The standard function.
#ifdef __cplusplus
}
#endif
/** @} */
#endif

14
lib/liballocimpl.cpp Normal file
View File

@ -0,0 +1,14 @@
#include <types.h>
#include <lock.hpp>
#include <memory.hpp>
NEWLOCK(liballocLock);
EXTERNC int liballoc_lock() { return liballocLock.Lock(); }
EXTERNC int liballoc_unlock() { return liballocLock.Unlock(); }
EXTERNC void *liballoc_alloc(size_t Pages) { return KernelAllocator.RequestPages(Pages); }
EXTERNC int liballoc_free(void *Address, size_t Pages)
{
KernelAllocator.FreePages(Address, Pages);
return 0;
}

1591
lib/printf.c Normal file

File diff suppressed because it is too large Load Diff