Ready. Set. Go!

This commit is contained in:
apio 2022-09-05 16:13:51 +02:00
commit 1b727a66ea
87 changed files with 2883 additions and 0 deletions

12
.clang-format Normal file
View File

@ -0,0 +1,12 @@
---
BasedOnStyle: Microsoft
CompactNamespaces: 'false'
FixNamespaceComments: 'false'
NamespaceIndentation: All
AllowShortBlocksOnASingleLine: 'true'
AllowShortCaseLabelsOnASingleLine: 'true'
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Always
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: 'true'
PointerAlignment: Left

6
.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
Luna.iso
toolchain/
.vscode/
**/*.o
initrd/boot/moon.elf
kernel/bin/moon.elf

7
Makefile Normal file
View File

@ -0,0 +1,7 @@
build: $(LUNA_ROOT)/kernel/bin/moon.elf
clean: moon-clean
install: $(LUNA_ROOT)/initrd/boot/moon.elf
include kernel/Makefile

BIN
initrd/boot/font.psf Normal file

Binary file not shown.

3
initrd/sys/config Normal file
View File

@ -0,0 +1,3 @@
screen=1024x768
kernel=boot/moon.elf
serial=1

60
kernel/Makefile Normal file
View File

@ -0,0 +1,60 @@
MOON_DIR := $(realpath $(dir $(abspath $(lastword $(MAKEFILE_LIST)))))
MOON_SRC := $(MOON_DIR)/src
MOON_OBJ := $(MOON_DIR)/lib
MOON_BIN := $(MOON_DIR)/bin
CC := x86_64-elf-gcc
CXX := x86_64-elf-g++
AS := x86_64-elf-as
NASM := nasm
CFLAGS := -Wall -Wextra -Werror -Os -ffreestanding -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -fshort-wchar -mcmodel=kernel -I$(MOON_DIR)/include -isystem $(MOON_DIR)/include/std
CXXFLAGS := -fno-rtti -fno-exceptions
NASMFLAGS := -felf64
ASFLAGS :=
LDFLAGS := -T$(MOON_DIR)/moon.ld -nostdlib -lgcc -Wl,--build-id=none -z max-page-size=0x1000
rwildcard=$(foreach d,$(wildcard $(1:=/*)),$(call rwildcard,$d,$2) $(filter $(subst *,%,$2),$d))
CXX_SRC = $(call rwildcard,$(MOON_SRC),*.cpp)
C_SRC = $(call rwildcard,$(MOON_SRC),*.c)
AS_SRC = $(call rwildcard,$(MOON_SRC),*.S)
NASM_SRC = $(call rwildcard,$(MOON_SRC),*.asm)
OBJS = $(patsubst $(MOON_SRC)/%.cpp, $(MOON_OBJ)/%.cpp.o, $(CXX_SRC))
OBJS += $(patsubst $(MOON_SRC)/%.c, $(MOON_OBJ)/%.c.o, $(C_SRC))
OBJS += $(patsubst $(MOON_SRC)/%.S, $(MOON_OBJ)/%.S.o, $(AS_SRC))
OBJS += $(patsubst $(MOON_SRC)/%.asm, $(MOON_OBJ)/%.asm.o, $(NASM_SRC))
default: $(MOON_BIN)/moon.elf
$(MOON_OBJ)/interrupts/handlers.cpp.o: $(MOON_SRC)/interrupts/handlers.cpp
@mkdir -p $(@D)
$(CXX) $(CFLAGS) -mgeneral-regs-only $(CXXFLAGS) -o $@ -c $^
$(MOON_OBJ)/%.cpp.o: $(MOON_SRC)/%.cpp
@mkdir -p $(@D)
$(CXX) $(CFLAGS) $(CXXFLAGS) -o $@ -c $^
$(MOON_OBJ)/%.c.o: $(MOON_SRC)/%.c
@mkdir -p $(@D)
$(CC) $(CFLAGS) -o $@ -c $^
$(MOON_OBJ)/%.S.o: $(MOON_SRC)/%.S
@mkdir -p $(@D)
$(AS) $(ASFLAGS) -o $@ $^
$(MOON_OBJ)/%.asm.o: $(MOON_SRC)/%.asm
@mkdir -p $(@D)
$(NASM) $(NASMFLAGS) -o $@ $^
$(MOON_BIN)/moon.elf: $(OBJS)
@mkdir -p $(@D)
$(CC) $(OBJS) $(CFLAGS) $(LDFLAGS) -o $@
moon-clean:
rm -rf $(MOON_OBJ)/*
$(LUNA_ROOT)/initrd/boot/moon.elf: $(MOON_BIN)/moon.elf
@mkdir -p $(@D)
cp $^ $@

View File

@ -0,0 +1,35 @@
#pragma once
#include <stdint.h>
namespace ACPI
{
struct SDTHeader
{
char Signature[4];
uint32_t Length;
uint8_t Revision;
uint8_t Checksum;
char OEMID[6];
char OEMTableID[8];
uint32_t OEMRevision;
uint32_t CreatorID;
uint32_t CreatorRevision;
};
struct XSDT
{
SDTHeader header;
uint64_t PointerToOtherSDT[1];
};
struct RSDT
{
SDTHeader header;
uint32_t PointerToOtherSDT[1];
};
SDTHeader* GetRSDTOrXSDT();
bool ValidateSDTHeader(SDTHeader* header);
void* FindTable(SDTHeader* rootSDT, const char* signature);
}

9
kernel/include/assert.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include "log/Log.h"
extern bool __call_assert_fail(const char* function, const char* message);
#define __assert_fail(prefix, message) __call_assert_fail(__FUNCTION__, prefix message)
#define ASSERT(expr) (void)((expr) || __assert_fail("Assertion failed: ", #expr))
#define TODO(message) __assert_fail("TODO: ", message)

162
kernel/include/bootboot.h Normal file
View File

@ -0,0 +1,162 @@
/*
* bootboot.h
* https://gitlab.com/bztsrc/bootboot
*
* Copyright (C) 2017 - 2021 bzt (bztsrc@gitlab)
*
* 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.
*
* This file is part of the BOOTBOOT Protocol package.
* @brief The BOOTBOOT structure
*
*/
#ifndef _BOOTBOOT_H_
#define _BOOTBOOT_H_
#include <stdint.h>
#ifdef __cplusplus
extern "C"
{
#endif
#ifndef _MSC_VER
#define _pack __attribute__((packed))
#else
#define _pack
#pragma pack(push)
#pragma pack(1)
#endif
#define BOOTBOOT_MAGIC "BOOT"
/* default virtual addresses for level 0 and 1 static loaders */
#define BOOTBOOT_MMIO 0xfffffffff8000000 /* memory mapped IO virtual address */
#define BOOTBOOT_FB 0xfffffffffc000000 /* frame buffer virtual address */
#define BOOTBOOT_INFO 0xffffffffffe00000 /* bootboot struct virtual address */
#define BOOTBOOT_ENV 0xffffffffffe01000 /* environment string virtual address */
#define BOOTBOOT_CORE 0xffffffffffe02000 /* core loadable segment start */
/* minimum protocol level:
* hardcoded kernel name, static kernel memory addresses */
#define PROTOCOL_MINIMAL 0
/* static protocol level:
* kernel name parsed from environment, static kernel memory addresses */
#define PROTOCOL_STATIC 1
/* dynamic protocol level:
* kernel name parsed, kernel memory addresses from ELF or PE symbols */
#define PROTOCOL_DYNAMIC 2
/* big-endian flag */
#define PROTOCOL_BIGENDIAN 0x80
/* loader types, just informational */
#define LOADER_BIOS (0 << 2)
#define LOADER_UEFI (1 << 2)
#define LOADER_RPI (2 << 2)
#define LOADER_COREBOOT (3 << 2)
/* framebuffer pixel format, only 32 bits supported */
#define FB_ARGB 0
#define FB_RGBA 1
#define FB_ABGR 2
#define FB_BGRA 3
/* mmap entry, type is stored in least significant tetrad (half byte) of size
* this means size described in 16 byte units (not a problem, most modern
* firmware report memory in pages, 4096 byte units anyway). */
typedef struct
{
uint64_t ptr;
uint64_t size;
} _pack MMapEnt;
#define MMapEnt_Ptr(a) ((a)->ptr)
#define MMapEnt_Size(a) ((a)->size & 0xFFFFFFFFFFFFFFF0)
#define MMapEnt_Type(a) ((a)->size & 0xF)
#define MMapEnt_IsFree(a) (((a)->size & 0xF) == 1)
#define MMAP_USED 0 /* don't use. Reserved or unknown regions */
#define MMAP_FREE 1 /* usable memory */
#define MMAP_ACPI 2 /* acpi memory, volatile and non-volatile as well */
#define MMAP_MMIO 3 /* memory mapped IO region */
#define INITRD_MAXSIZE 16 /* Mb */
typedef struct
{
/* first 64 bytes is platform independent */
uint8_t magic[4]; /* 'BOOT' magic */
uint32_t size; /* length of bootboot structure, minimum 128 */
uint8_t protocol; /* 1, static addresses, see PROTOCOL_* and LOADER_* above */
uint8_t fb_type; /* framebuffer type, see FB_* above */
uint16_t numcores; /* number of processor cores */
uint16_t bspid; /* Bootsrap processor ID (Local APIC Id on x86_64) */
int16_t timezone; /* in minutes -1440..1440 */
uint8_t datetime[8]; /* in BCD yyyymmddhhiiss UTC (independent to timezone) */
uint64_t initrd_ptr; /* ramdisk image position and size */
uint64_t initrd_size;
uint64_t fb_ptr; /* framebuffer pointer and dimensions */
uint32_t fb_size;
uint32_t fb_width;
uint32_t fb_height;
uint32_t fb_scanline;
/* the rest (64 bytes) is platform specific */
union {
struct
{
uint64_t acpi_ptr;
uint64_t smbi_ptr;
uint64_t efi_ptr;
uint64_t mp_ptr;
uint64_t unused0;
uint64_t unused1;
uint64_t unused2;
uint64_t unused3;
} x86_64;
struct
{
uint64_t acpi_ptr;
uint64_t mmio_ptr;
uint64_t efi_ptr;
uint64_t unused0;
uint64_t unused1;
uint64_t unused2;
uint64_t unused3;
uint64_t unused4;
} aarch64;
} arch;
/* from 128th byte, MMapEnt[], more records may follow */
MMapEnt mmap;
/* use like this:
* MMapEnt *mmap_ent = &bootboot.mmap; mmap_ent++;
* until you reach bootboot->size, while(mmap_ent < bootboot + bootboot->size) */
} _pack BOOTBOOT;
#ifdef _MSC_VER
#pragma pack(pop)
#endif
#ifdef __cplusplus
}
#endif
#endif

12
kernel/include/cpu/CPU.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include "cpu/Features.h"
#include <stdint.h>
namespace CPU
{
const char* get_vendor_string();
const char* get_brand_string();
uint64_t get_feature_bitmask();
uint64_t get_initial_apic_id();
bool has_feature(CPU::Features);
}

View File

@ -0,0 +1,72 @@
#pragma once
namespace CPU
{
enum class Features
{
FPU,
VME,
DE,
PSE,
TSC,
MSR,
PAE,
MCE,
CX8,
APIC,
UNUSED1,
SEP,
MTRR,
PGE,
MCA,
CMOV,
PAT,
PSE36,
PSN,
CLFLUSH,
UNUSED2,
DS,
ACPI,
MMX,
FXSR,
SSE,
SSE2,
SS,
HTT,
TM,
IA64,
PBE,
SSE3,
PCLMUL,
DTES64,
MONITOR,
DS_CPL,
VMX,
SMX,
EST,
TM2,
SSSE3,
CID,
SDBG,
FMA,
CX16,
XTPR,
PDCM,
UNUSED3,
PCID,
DCA,
SSE4_1,
SSE4_2,
X2APIC,
MOVBE,
POPCNT,
TSC_2,
AES,
XSAVE,
OSXSAVE,
AVX,
F16C,
RDRAND,
HYPERVISOR,
};
}

31
kernel/include/debug.h Normal file
View File

@ -0,0 +1,31 @@
#pragma once
#include "render/BBRenderer.h"
#include "render/Color.h"
namespace Debug
{
struct DebugStatus
{
static DebugStatus* the();
void Init();
void ThrowException(int exception);
void StartBootStage(Color stage);
void PassBootStage(Color stage);
void FailBootStage();
void DebugTick();
void DebugKey(char key);
private:
int x = 0;
int y = 0;
int errx = 0;
int erry = 30;
BBRenderer renderer;
static DebugStatus s_main;
};
}

View File

@ -0,0 +1,34 @@
#pragma once
#include <stdint.h>
namespace Ext2
{
struct Superblock
{
uint32_t fs_inodes; // Total number of inodes in file system
uint32_t fs_blocks; // Total number of blocks in file system
uint32_t su_blocks; // Number of blocks reserved for superuser
uint32_t free_blocks; // Total number of unallocated blocks
uint32_t free_inodes; // Total number of unallocated inodes
uint32_t superblock_number; // Block number of the block containing the superblock
uint32_t block_size; // log2(block size) - 10
uint32_t frag_size; // log2(fragment size) - 10
uint32_t num_blocks; // Number of blocks in each block group
uint32_t num_frag; // Number of fragments in each block group
uint32_t num_inodes; // Number of inodes in each block group
uint32_t mount_time; // Last mount time (in POSIX time)
uint32_t write_time; // Last written time (in POSIX time)
uint16_t fsck_mounts; // Number of times the volume has been mounted since its last consistency check
uint16_t fsck_mounts_allowed; // Number of mounts allowed before a consistency check must be done
uint16_t signature; // Ext2 signature (0xef53)
uint16_t fs_state; // File system state
uint16_t error_action; // What to do when an error is detected
uint16_t version_minor; // Minor portion of version
uint32_t fsck_time; // POSIX time of last consistency check
uint32_t fsck_interval; // Interval (in POSIX time) between forced consistency checks
uint32_t os_id; // Operating system ID from which the filesystem on this volume was created
uint32_t version_major; // Major portion of version
uint16_t su_uid; // User ID that can use reserved blocks (superuser)
uint16_t su_gid; // Group ID that can use reserved blocks
};
}

6
kernel/include/gdt/GDT.h Normal file
View File

@ -0,0 +1,6 @@
#pragma once
namespace GDT
{
void load();
}

View File

@ -0,0 +1,8 @@
#pragma once
namespace Init
{
void check_magic();
void disable_smp();
void early_init();
}

View File

@ -0,0 +1,44 @@
#pragma once
#define TAR_MAGIC "ustar"
#define TAR_BLOCKSIZE 512
namespace InitRD
{
struct TarHeader
{ /* byte offset */
char name[100]; /* 0 */
char mode[8]; /* 100 */
char uid[8]; /* 108 */
char gid[8]; /* 116 */
char size[12]; /* 124 */
char mtime[12]; /* 136 */
char chksum[8]; /* 148 */
char typeflag; /* 156 */
char linkname[100]; /* 157 */
char magic[6]; /* 257 */
char version[2]; /* 263 */
char uname[32]; /* 265 */
char gname[32]; /* 297 */
char devmajor[8]; /* 329 */
char devminor[8]; /* 337 */
char prefix[155]; /* 345 */
/* 500 */
} __attribute__((packed));
struct File
{
char name[100];
int size;
int size_in_blocks;
void* addr;
};
int get_total_blocks();
File get_file(TarHeader* header);
TarHeader* get_block(int block_index);
bool is_valid_header(TarHeader* header);
File find_file(const char* filename);
void for_each(void (*callback)(File& file));
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <stdint.h>
#define IDT_TA_InterruptGate 0b10001110
#define IDT_TA_CallGate 0b10001100
#define IDT_TA_TrapGate 0b10001111
namespace IDT
{
void add_handler(short interrupt_number, void* handler, uint8_t type_attr);
void load();
}

View File

@ -0,0 +1,7 @@
#pragma once
#include "SavedContext.h"
namespace IRQ
{
void interrupt_handler(SavedContext* context);
}

View File

@ -0,0 +1,7 @@
#pragma once
#include <stdint.h>
namespace Interrupts
{
void install();
}

View File

@ -0,0 +1,7 @@
#pragma once
namespace Interrupts
{
void enable();
void disable();
}

View File

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
struct SavedContext
{
uint64_t cr2;
uint64_t ds;
uint64_t r15, r14, r13, r12, r11, r10, r9, r8, rsi, rdi, rbp, rdx, rcx, rbx, rax;
uint64_t number;
union {
uint64_t error_code;
uint64_t irq_number;
};
uint64_t rip, cs, rflags, rsp, ss;
};

13
kernel/include/io/IO.h Normal file
View File

@ -0,0 +1,13 @@
#pragma once
#include <stdint.h>
namespace IO
{
uint8_t inb(uint16_t);
void outb(uint16_t, uint8_t);
uint16_t inw(uint16_t);
void outw(uint16_t, uint16_t);
uint32_t inl(uint16_t);
void outl(uint16_t, uint32_t);
void delay();
}

12
kernel/include/io/PIC.h Normal file
View File

@ -0,0 +1,12 @@
#pragma once
#include <stdint.h>
namespace PIC
{
void remap();
void end_slave();
void end_master();
void enable_master(uint8_t mask);
void enable_slave(uint8_t mask);
void send_eoi(unsigned char irq);
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "render/Color.h"
#include <stddef.h>
namespace Serial
{
void wait();
void write(const char* string, size_t size);
void print(const char* string);
void println(const char* string);
void set_color(Color& color);
void reset_color();
}

23
kernel/include/log/Log.h Normal file
View File

@ -0,0 +1,23 @@
#pragma once
enum class LogLevel
{
INFO,
WARN,
ERROR
};
namespace KernelLog
{
void log(const char* function, const char* message, LogLevel level);
void logln(const char* function, const char* message, LogLevel level);
}
#define kinternalcall(func, function, message, level) KernelLog::func(function, message, level)
#define kinfo(message) kinternalcall(log, __FUNCTION__, message, LogLevel::INFO)
#define kinfoln(message) kinternalcall(logln, __FUNCTION__, message, LogLevel::INFO)
#define kwarn(message) kinternalcall(log, __FUNCTION__, message, LogLevel::WARN)
#define kwarnln(message) kinternalcall(logln, __FUNCTION__, message, LogLevel::WARN)
#define kerror(message) kinternalcall(log, __FUNCTION__, message, LogLevel::ERROR)
#define kerrorln(message) kinternalcall(logln, __FUNCTION__, message, LogLevel::ERROR)

View File

@ -0,0 +1,11 @@
#pragma once
#include <stdint.h>
namespace KernelHeap
{ // Virtual memory allocator for the kernel, goes from -128MB to -64MB
uint64_t request_virtual_page();
uint64_t request_virtual_pages(uint64_t count);
void free_virtual_page(uint64_t address);
void free_virtual_pages(uint64_t address, uint64_t count);
}

View File

@ -0,0 +1,25 @@
#pragma once
#include <stdint.h>
namespace Paging
{
struct PageDirectoryEntry
{
bool Present : 1;
bool ReadWrite : 1;
bool UserSuper : 1;
bool WriteThrough : 1;
bool CacheDisabled : 1;
bool Accessed : 1;
bool ignore0 : 1;
bool LargerPages : 1;
bool ignore1 : 1;
uint8_t Available : 3;
uint64_t Address : 52;
};
struct PageTable
{
PageDirectoryEntry entries[512];
} __attribute__((aligned(0x1000)));
}

View File

@ -0,0 +1,17 @@
#pragma once
#include "memory/Paging.h"
namespace Paging
{
class VirtualMemoryManager
{
void Init(); // fetch page table from cr3
void Init(PageTable* PML4);
void Map(uint64_t virtualAddress, uint64_t physicalAddress);
void Unmap(uint64_t virtualAddress);
private:
PageTable* PML4;
};
}

View File

@ -0,0 +1,4 @@
#pragma once
void hang();
void halt();

17
kernel/include/psf2.h Normal file
View File

@ -0,0 +1,17 @@
#pragma once
#include <stdint.h>
#define PSF_FONT_MAGIC 0x864ab572
typedef struct
{
uint32_t magic;
uint32_t version;
uint32_t headersize;
uint32_t flags;
uint32_t numglyph;
uint32_t bytesperglyph;
uint32_t height;
uint32_t width;
uint8_t glyphs;
} __attribute__((packed)) psf2_t;

View File

@ -0,0 +1,13 @@
#pragma once
#include "render/BaseRenderer.h"
class BBRenderer : public BaseRenderer
{
public:
bool init() override;
void set_pixel(uint32_t x, uint32_t y, Color color) override;
Color get_pixel(uint32_t x, uint32_t y) override;
void paint_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color color) override;
void paint_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color* colors) override;
void clear(Color color) override;
};

View File

@ -0,0 +1,13 @@
#pragma once
#include "render/Color.h"
class BaseRenderer
{
public:
virtual bool init();
virtual void set_pixel(uint32_t x, uint32_t y, Color color);
virtual Color get_pixel(uint32_t x, uint32_t y);
virtual void paint_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color color);
virtual void paint_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color* colors);
virtual void clear(Color color);
};

View File

@ -0,0 +1,20 @@
#pragma once
#include <stdint.h>
struct Color
{
uint8_t blue;
uint8_t green;
uint8_t red;
uint8_t alpha;
static Color White;
static Color Black;
static Color Red;
static Color Green;
static Color Blue;
static Color Yellow;
static Color Cyan;
static Color Magenta;
static Color Gray;
} __attribute__((packed)); // to reinterpret this as a uint32_t AARRGGBB (in reversed order here because endianness)

View File

@ -0,0 +1,8 @@
#pragma once
#include "render/BaseRenderer.h"
namespace Draw
{
bool try_initialize();
BaseRenderer* renderer();
}

View File

@ -0,0 +1,13 @@
#pragma once
#include "render/Color.h"
#include <stddef.h>
namespace TextRenderer
{
void putchar(char chr);
void write(const char* str, size_t size);
void set_text_color(Color& col);
void set_bg_color(Color& col);
bool try_initialize();
bool is_initialized();
}

View File

@ -0,0 +1,11 @@
#pragma once
#include <stdint.h>
namespace PIT
{
extern volatile uint64_t ms_since_boot;
const uint64_t base_frequency = 1193182;
void initialize(uint64_t frequency);
uint64_t frequency();
void tick();
}

View File

@ -0,0 +1,10 @@
#pragma once
#include <stdarg.h>
#include <stddef.h>
int printf(const char* fmt, ...);
int sprintf(char* __s, const char* fmt, ...);
int snprintf(char* __s, size_t max, const char* fmt, ...);
int vprintf(const char* fmt, va_list ap);
int vsprintf(char* __s, const char* fmt, va_list ap);
int vsnprintf(char* __s, size_t max, const char* fmt, va_list ap);

View File

@ -0,0 +1,7 @@
#pragma once
#include <stdint.h>
char* itoa(int number, char* arr, int base);
char* utoa(unsigned int number, char* arr, int base);
void sleep(uint64_t ms);

View File

@ -0,0 +1,17 @@
#pragma once
#include <stddef.h>
size_t strlen(const char* __s);
__attribute__((deprecated)) char* strcpy(char* dest, const char* src);
__attribute__((deprecated)) int strcmp(const char* s1, const char* s2);
__attribute__((deprecated)) char* strcat(char* dest, const char* src);
char* strncpy(char* dest, const char* src, size_t n);
int strncmp(const char* s1, const char* s2, size_t n);
char* strncat(char* dest, const char* src, size_t n);
void* memcpy(void* dest, const void* src, size_t n);
void* memset(void* dest, int c, size_t n);
int memcmp(const void* a, const void* b, size_t n);
void* memmove(void* dest, void* src, size_t n);

4
kernel/include/utils.h Normal file
View File

@ -0,0 +1,4 @@
#pragma once
#include <stdint.h>
#define hex64(bit64num) (uint64_t) bit64num >> 32, (uint64_t)bit64num & 0xFFFFFFFF

31
kernel/moon.ld Normal file
View File

@ -0,0 +1,31 @@
ENTRY(_start)
OUTPUT_FORMAT(elf64-x86-64)
mmio = 0xfffffffff8000000; /* these are configurable for level 2 loaders */
fb = 0xfffffffffc000000;
bootboot = 0xffffffffffe00000;
environment = 0xffffffffffe01000;
/* initstack = 1024; */
PHDRS
{
boot PT_LOAD; /* one single loadable segment */
}
SECTIONS
{
. = 0xffffffffffe02000;
kernel_start = .;
.text : {
KEEP(*(.text.boot)) *(.text .text.*) /* code */
*(.rodata .rodata.*) /* data */
*(.data .data.*)
} :boot
.bss (NOLOAD) : { /* bss */
. = ALIGN(16);
*(.bss .bss.*)
*(COMMON)
} :boot
kernel_end = .;
/DISCARD/ : { *(.eh_frame) *(.comment) }
}

40
kernel/src/acpi/RSDT.cpp Normal file
View File

@ -0,0 +1,40 @@
#include "acpi/RSDT.h"
#include "bootboot.h"
#include "std/stdio.h"
#include "std/string.h"
extern BOOTBOOT bootboot;
ACPI::SDTHeader* ACPI::GetRSDTOrXSDT()
{
return (SDTHeader*)bootboot.arch.x86_64.acpi_ptr;
}
bool ACPI::ValidateSDTHeader(ACPI::SDTHeader* header)
{
uint8_t sum = 0;
for (uint32_t i = 0; i < header->Length; i++) { sum += ((char*)header)[i]; }
return sum == 0;
}
void* ACPI::FindTable(ACPI::SDTHeader* rootSDT, const char* signature)
{
bool isXSDT = strncmp(rootSDT->Signature, "XSDT", 4);
int entries = (rootSDT->Length - sizeof(SDTHeader)) / isXSDT ? 8 : 4;
printf("%d entries in root SDT\n", entries);
for (int i = 0; i < entries; i++)
{
printf("Trying this entry\n");
SDTHeader* h;
if (isXSDT) h = (SDTHeader*)((XSDT*)rootSDT)->PointerToOtherSDT[i];
else
h = (SDTHeader*)(uint64_t)((RSDT*)rootSDT)->PointerToOtherSDT[i];
if (strncmp(h->Signature, signature, 4) == 0) return (void*)h;
}
return NULL;
}

10
kernel/src/assert.cpp Normal file
View File

@ -0,0 +1,10 @@
#include "assert.h"
#include "log/Log.h"
#include "panic/hang.h"
bool __call_assert_fail(const char* function, const char* message)
{
KernelLog::logln(function, message, LogLevel::ERROR);
hang();
return true;
}

82
kernel/src/cpu/CPU.cpp Normal file
View File

@ -0,0 +1,82 @@
#include "cpu/CPU.h"
#include <cpuid.h>
#include <string.h>
const char* CPU::get_vendor_string()
{
static bool cached = false;
static char vendor[13];
if (cached) { return vendor; }
else
{
unsigned int unused, ebx, ecx, edx;
__get_cpuid(0, &unused, &ebx, &ecx, &edx);
memcpy(vendor, &ebx, 4);
memcpy(&vendor[4], &edx, 4);
memcpy(&vendor[8], &ecx, 4);
vendor[12] = 0;
cached = true;
return vendor;
}
}
const char* CPU::get_brand_string()
{
static bool cached = false;
static char brand[49];
if (cached) { return brand; }
else
{
unsigned int eax, ebx, ecx, edx;
__get_cpuid(0x80000002, &eax, &ebx, &ecx, &edx);
memcpy(brand, &eax, 4);
memcpy(&brand[4], &ebx, 4);
memcpy(&brand[8], &ecx, 4);
memcpy(&brand[12], &edx, 4);
__get_cpuid(0x80000003, &eax, &ebx, &ecx, &edx);
memcpy(&brand[16], &eax, 4);
memcpy(&brand[16 + 4], &ebx, 4);
memcpy(&brand[16 + 8], &ecx, 4);
memcpy(&brand[16 + 12], &edx, 4);
__get_cpuid(0x80000004, &eax, &ebx, &ecx, &edx);
memcpy(&brand[32], &eax, 4);
memcpy(&brand[32 + 4], &ebx, 4);
memcpy(&brand[32 + 8], &ecx, 4);
memcpy(&brand[32 + 12], &edx, 4);
brand[48] = 0;
cached = true;
return brand;
}
}
uint64_t CPU::get_feature_bitmask()
{
static uint64_t bitmask = 0;
static bool cached = false;
if (cached) return bitmask;
unsigned int unused;
unsigned int ecx = 0;
unsigned int edx = 0;
__get_cpuid(1, &unused, &unused, &ecx, &edx);
bitmask = ((uint64_t)ecx << 32) | (uint64_t)edx;
cached = true;
return bitmask;
}
static bool _has_feature(int feature)
{
return (CPU::get_feature_bitmask() & (uint64_t)(1 << feature)) > 0;
}
bool CPU::has_feature(CPU::Features feature)
{
return _has_feature((int)feature);
}
uint64_t CPU::get_initial_apic_id()
{
unsigned int unused;
unsigned int ebx = 0;
__get_cpuid(1, &unused, &ebx, &unused, &unused);
return ebx >> 24;
}

61
kernel/src/debug.cpp Normal file
View File

@ -0,0 +1,61 @@
#include "debug.h"
#include "assert.h"
#include "scheduling/PIT.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
namespace Debug
{
DebugStatus DebugStatus::s_main;
void DebugStatus::Init()
{
ASSERT(renderer.init());
}
void DebugStatus::StartBootStage(Color stage)
{
renderer.paint_rect(x, y, 10, 10, stage);
y += 11;
}
void DebugStatus::PassBootStage(Color stage)
{
renderer.paint_rect(x, y, 10, 10, stage);
y -= 11;
x += 11;
}
void DebugStatus::FailBootStage()
{
renderer.paint_rect(x, y, 10, 10, Color::Red);
y -= 11;
x += 11;
}
void DebugStatus::DebugTick()
{
uint8_t blue = (PIT::ms_since_boot / 10) % 255;
renderer.paint_rect(0, 200, 10, 10, Color{blue, 0x00, 0x00, 0xFF});
}
void DebugStatus::DebugKey(char key)
{
renderer.paint_rect(0, 215, 10, 10, Color{0x00, (uint8_t)key, 0x00, 0xFF});
}
void DebugStatus::ThrowException(int exception)
{
uint8_t red = (uint8_t)(exception * 8);
renderer.paint_rect(errx, erry, 10, 10, Color{0x00, 0x00, red, 0xFF});
errx += 11;
}
DebugStatus* DebugStatus::the()
{
return &s_main;
}
}
#pragma GCC diagnostic pop

16
kernel/src/gdt/GDT.asm Normal file
View File

@ -0,0 +1,16 @@
global load_gdt
load_gdt:
cli
lgdt [rdi]
mov ax, 0x10
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
push 0x08
lea rax, [rel .reload_CS]
push rax
retfq
.reload_CS:
ret

43
kernel/src/gdt/GDT.cpp Normal file
View File

@ -0,0 +1,43 @@
#include "gdt/GDT.h"
#include <stdint.h>
struct GDTR
{
uint16_t size;
uint64_t offset;
} __attribute__((packed));
struct GDTEntry
{
uint16_t limit0;
uint16_t base0;
uint8_t base1;
uint8_t access;
uint8_t limit1_flags;
uint8_t base2;
} __attribute__((packed));
struct InternalGDT
{
GDTEntry null;
GDTEntry kernel_code;
GDTEntry kernel_data;
GDTEntry user_null;
GDTEntry user_code;
GDTEntry user_data;
} __attribute__((packed)) __attribute((aligned(0x1000)));
__attribute__((aligned(0x1000))) static InternalGDT internal_gdt = {
{0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00}, {0xffff, 0x0000, 0x00, 0x9a, 0xaf, 0x00},
{0xffff, 0x0000, 0x00, 0x92, 0xcf, 0x00}, {0x0000, 0x0000, 0x00, 0x00, 0x00, 0x00},
{0xffff, 0x0000, 0x00, 0xfa, 0xaf, 0x00}, {0xffff, 0x0000, 0x00, 0xf2, 0xcf, 0x00}};
extern "C" void load_gdt(GDTR* gdtr);
void GDT::load()
{
static GDTR gdtr;
gdtr.offset = (uint64_t)&internal_gdt;
gdtr.size = sizeof(InternalGDT);
load_gdt(&gdtr);
}

32
kernel/src/init/Init.cpp Normal file
View File

@ -0,0 +1,32 @@
#include "init/Init.h"
#include "assert.h"
#include "bootboot.h"
#include "cpu/CPU.h"
#include "interrupts/Interrupts.h"
#include "io/Serial.h"
#include "panic/hang.h"
#include "render/Draw.h"
#include "render/TextRenderer.h"
#include <string.h>
extern BOOTBOOT bootboot;
void Init::check_magic()
{
ASSERT(strncmp((char*)bootboot.magic, BOOTBOOT_MAGIC, 4) == 0);
}
void Init::disable_smp()
{
if (CPU::get_initial_apic_id() != bootboot.bspid) { hang(); }
return;
}
void Init::early_init()
{
Interrupts::disable();
asm volatile("cld");
ASSERT(Draw::try_initialize());
// ASSERT(TextRenderer::try_initialize());
}

View File

@ -0,0 +1,81 @@
#include "init/InitRD.h"
#include "bootboot.h"
#include "io/Serial.h"
#include "std/stdlib.h"
#include <string.h>
extern BOOTBOOT bootboot;
static inline int get_file_size_in_blocks(InitRD::File f)
{
return f.size_in_blocks;
}
inline int InitRD::get_total_blocks()
{
return bootboot.initrd_size / TAR_BLOCKSIZE;
}
inline InitRD::TarHeader* InitRD::get_block(int block_index)
{
return (TarHeader*)(bootboot.initrd_ptr + block_index * TAR_BLOCKSIZE);
}
inline bool InitRD::is_valid_header(TarHeader* header)
{
return strncmp(header->magic, TAR_MAGIC, 5) == 0;
}
InitRD::File InitRD::get_file(TarHeader* header)
{
File result;
result.size = 0;
memcpy(result.name, header->name, 100);
result.addr = (void*)(header + TAR_BLOCKSIZE);
int multiplier =
1; // why they decided to store the size as an octal-encoded string instead of an integer is beyond me
for (int i = 10; i >= 0; i--)
{
result.size += (multiplier * (header->size[i] - 48));
multiplier *= 8;
}
result.size_in_blocks = result.size / TAR_BLOCKSIZE + 1;
return result;
}
InitRD::File InitRD::find_file(const char* filename)
{
int block = 0;
int total_blocks = get_total_blocks();
while (block < total_blocks)
{
TarHeader* hdr = get_block(block);
block++;
if (hdr->typeflag == 53) { continue; } // Directory
if (!is_valid_header(hdr)) { continue; }
auto f = get_file(hdr);
if (strncmp(hdr->name, filename, strlen(filename)) == 0) { return f; }
block += get_file_size_in_blocks(f);
}
File nullFile;
nullFile.addr = NULL;
nullFile.size = 0;
memcpy(nullFile.name, "NULL", 5);
return nullFile;
}
void InitRD::for_each(void (*callback)(File& f))
{
int block = 0;
int total_blocks = get_total_blocks();
while (block < total_blocks)
{
TarHeader* hdr = get_block(block);
block++;
if (hdr->typeflag == 53) { continue; } // Directory
if (!is_valid_header(hdr)) { continue; }
auto f = get_file(hdr);
block += get_file_size_in_blocks(f);
callback(f);
}
}

View File

@ -0,0 +1,19 @@
#include "debug.h"
#include "interrupts/IRQ.h"
#include "interrupts/SavedContext.h"
#include "panic/hang.h"
#include "std/stdio.h"
extern "C" void common_handler(SavedContext* context)
{
if (context->number < 0x20) { Debug::DebugStatus::the()->ThrowException(context->number); }
if (context->number == 13)
{
printf("General protection fault at %x%x, %d, %d, %x%x, %d, %x%x\n", context->rip >> 32,
context->rip & 0xFFFFFFFF, context->cs, context->ss, context->rsp >> 32, context->rsp & 0xFFFFFFFF,
context->error_code, context->cr2 >> 32, context->cr2 & 0xFFFFFFFF);
while (1) halt();
}
if (context->number >= 0x20 && context->number < 0x30) { IRQ::interrupt_handler(context); }
return;
}

View File

@ -0,0 +1,57 @@
#include "interrupts/IDT.h"
#include "assert.h"
struct IDTEntry
{
uint16_t offset0;
uint16_t selector;
uint8_t ist;
uint8_t type_attr;
uint16_t offset1;
uint32_t offset2;
uint32_t ignore;
void set_offset(uint64_t offset);
uint64_t get_offset();
};
struct IDTR
{
uint16_t limit;
uint64_t offset;
} __attribute__((packed));
static IDTEntry entries[256];
void IDTEntry::set_offset(uint64_t offset)
{
offset0 = (uint16_t)(offset & 0x000000000000ffff);
offset1 = (uint16_t)((offset & 0x00000000ffff0000) >> 16);
offset2 = (uint32_t)((offset & 0xffffffff00000000) >> 32);
}
uint64_t IDTEntry::get_offset()
{
uint64_t offset = 0;
offset |= (uint64_t)offset0;
offset |= (uint64_t)offset1 << 16;
offset |= (uint64_t)offset2 << 32;
return offset;
}
void IDT::add_handler(short interrupt_number, void* handler, uint8_t type_attr)
{
ASSERT(handler != nullptr);
ASSERT(interrupt_number < 256);
IDTEntry* entry_for_handler = &entries[interrupt_number];
entry_for_handler->selector = 0x08;
entry_for_handler->type_attr = type_attr;
entry_for_handler->set_offset((uint64_t)handler);
}
IDTR idtr;
void IDT::load()
{
idtr.limit = 0x0FFF;
idtr.offset = (uint64_t)entries;
asm("lidt %0" : : "m"(idtr));
}

View File

@ -0,0 +1,26 @@
#include "interrupts/IRQ.h"
#include "debug.h"
#include "io/IO.h"
#include "io/PIC.h"
#include "scheduling/PIT.h"
#include "std/stdio.h"
void IRQ::interrupt_handler(SavedContext* context)
{
switch (context->irq_number)
{
case 0:
PIT::tick();
Debug::DebugStatus::the()->DebugTick();
break;
case 1: {
volatile unsigned char scancode = IO::inb(0x60);
Debug::DebugStatus::the()->DebugKey(scancode);
printf("Keyboard key pressed, seconds since boot: %d\n", PIT::ms_since_boot / 1000);
break;
}
default: printf("Unhandled IRQ: %d", context->irq_number); break;
}
PIC::send_eoi(context->irq_number);
return;
}

View File

@ -0,0 +1,106 @@
#include "interrupts/Install.h"
#include "interrupts/IDT.h"
extern "C"
{
void unused();
void isr0();
void isr1();
void isr2();
void isr3();
void isr4();
void isr5();
void isr6();
void isr7();
void isr8();
void isr10();
void isr11();
void isr12();
void isr13();
void isr14();
void isr16();
void isr17();
void isr18();
void isr19();
void isr20();
void isr21();
void isr28();
void isr29();
void isr30();
void isr31();
void isr32();
void isr33();
void isr34();
void isr35();
void isr36();
void isr37();
void isr38();
void isr39();
void isr40();
void isr41();
void isr42();
void isr43();
void isr44();
void isr45();
void isr46();
void isr47();
void isr48();
}
#define INSTALL_TRAP(x) IDT::add_handler(x, (void*)&isr##x, IDT_TA_TrapGate)
#define INSTALL_UNUSED(x) IDT::add_handler(x, (void*)&unused, IDT_TA_InterruptGate)
#define INSTALL_ISR(x) IDT::add_handler(x, (void*)&isr##x, IDT_TA_InterruptGate)
void Interrupts::install()
{
INSTALL_TRAP(0);
INSTALL_TRAP(1);
INSTALL_TRAP(2);
INSTALL_TRAP(3);
INSTALL_TRAP(4);
INSTALL_TRAP(5);
INSTALL_TRAP(6);
INSTALL_TRAP(7);
INSTALL_TRAP(8);
INSTALL_UNUSED(9);
INSTALL_TRAP(10);
INSTALL_TRAP(11);
INSTALL_TRAP(12);
INSTALL_TRAP(13);
INSTALL_TRAP(14);
INSTALL_UNUSED(15);
INSTALL_TRAP(16);
INSTALL_TRAP(17);
INSTALL_TRAP(18);
INSTALL_TRAP(19);
INSTALL_TRAP(20);
INSTALL_TRAP(21);
INSTALL_UNUSED(22);
INSTALL_UNUSED(23);
INSTALL_UNUSED(24);
INSTALL_UNUSED(25);
INSTALL_UNUSED(26);
INSTALL_UNUSED(27);
INSTALL_TRAP(28);
INSTALL_TRAP(29);
INSTALL_TRAP(30);
INSTALL_UNUSED(31);
INSTALL_ISR(32);
INSTALL_ISR(33);
INSTALL_ISR(34);
INSTALL_ISR(35);
INSTALL_ISR(36);
INSTALL_ISR(37);
INSTALL_ISR(38);
INSTALL_ISR(39);
INSTALL_ISR(40);
INSTALL_ISR(41);
INSTALL_ISR(42);
INSTALL_ISR(43);
INSTALL_ISR(44);
INSTALL_ISR(45);
INSTALL_ISR(46);
INSTALL_ISR(47);
INSTALL_ISR(48);
for (int i = 49; i < 256; i++) { INSTALL_UNUSED(i); }
}

View File

@ -0,0 +1,136 @@
%macro ISR 1
global isr%1
isr%1:
push byte 0
push byte %1
jmp asm_common
%endmacro
%macro ISR_ERROR 1
global isr%1
isr%1:
push byte %1
jmp asm_common
%endmacro
%macro IRQ 2
global isr%1
isr%1:
push byte %2
push byte %1
jmp asm_common
%endmacro
%macro SOFT 1
global isr%1
isr%1:
push byte 0
push byte %1
jmp asm_common
%endmacro
global unused
unused:
push byte 0
push 256
jmp asm_common
extern common_handler
global asm_common
asm_common:
cld
push rax
push rbx
push rcx
push rdx
push rbp
push rdi
push rsi
push r8
push r9
push r10
push r11
push r12
push r13
push r14
push r15
mov r8, ds
push r8
mov r8, 0x10
mov ds, r8
mov es, r8
mov r8, cr2
push r8
mov rdi, rsp
call common_handler
add rsp, 8
pop r8
mov ds, r8
mov es, r8
pop r15
pop r14
pop r13
pop r12
pop r11
pop r10
pop r9
pop r8
pop rsi
pop rdi
pop rbp
pop rdx
pop rcx
pop rbx
pop rax
add rsp, 16
iretq
ISR 0
ISR 1
ISR 2
ISR 3
ISR 4
ISR 5
ISR 6
ISR 7
ISR_ERROR 8
ISR_ERROR 10
ISR_ERROR 11
ISR_ERROR 12
ISR_ERROR 13
ISR_ERROR 14
ISR 16
ISR_ERROR 17
ISR 18
ISR 19
ISR 20
ISR_ERROR 21
ISR 28
ISR_ERROR 29
ISR_ERROR 30
IRQ 32, 0
IRQ 33, 1
IRQ 34, 2
IRQ 35, 3
IRQ 36, 4
IRQ 37, 5
IRQ 38, 6
IRQ 39, 7
IRQ 40, 8
IRQ 41, 9
IRQ 42, 10
IRQ 43, 11
IRQ 44, 12
IRQ 45, 13
IRQ 46, 14
IRQ 47, 15
SOFT 48

View File

@ -0,0 +1,11 @@
#include "interrupts/Interrupts.h"
void Interrupts::disable()
{
asm volatile("cli");
}
void Interrupts::enable()
{
asm volatile("sti");
}

42
kernel/src/io/IO.cpp Normal file
View File

@ -0,0 +1,42 @@
#include "io/IO.h"
uint8_t IO::inb(uint16_t port)
{
uint8_t result;
asm volatile("inb %1, %0" : "=a"(result) : "Nd"(port));
return result;
}
void IO::outb(uint16_t port, uint8_t value)
{
asm volatile("outb %0, %1" : : "a"(value), "Nd"(port));
}
uint16_t IO::inw(uint16_t port)
{
uint16_t result;
asm volatile("inw %1, %0" : "=a"(result) : "Nd"(port));
return result;
}
void IO::outw(uint16_t port, uint16_t value)
{
asm volatile("outw %0, %1" : : "a"(value), "Nd"(port));
}
uint32_t IO::inl(uint16_t port)
{
uint32_t result;
asm volatile("inl %1, %0" : "=a"(result) : "Nd"(port));
return result;
}
void IO::outl(uint16_t port, uint32_t value)
{
asm volatile("outl %0, %1" : : "a"(value), "Nd"(port));
}
void IO::delay()
{
asm volatile("outb %%al, $0x80" : : "a"(0));
}

74
kernel/src/io/PIC.cpp Normal file
View File

@ -0,0 +1,74 @@
#include "io/PIC.h"
#include "io/IO.h"
#define PIC1_COMMAND 0x20
#define PIC1_DATA 0x21
#define PIC2_COMMAND 0xA0
#define PIC2_DATA 0xA1
#define PIC_EOI 0x20
#define ICW1_INIT 0x10
#define ICW1_ICW4 0x01
#define ICW4_8086 0x01
void PIC::remap()
{
uint8_t a1, a2;
a1 = IO::inb(PIC1_DATA);
IO::delay();
a2 = IO::inb(PIC2_DATA);
IO::delay();
IO::outb(PIC1_COMMAND, ICW1_INIT | ICW1_ICW4);
IO::delay();
IO::outb(PIC2_COMMAND, ICW1_INIT | ICW1_ICW4);
IO::delay();
IO::outb(PIC1_DATA, 0x20);
IO::delay();
IO::outb(PIC2_DATA, 0x28);
IO::delay();
IO::outb(PIC1_DATA, 4);
IO::delay();
IO::outb(PIC2_DATA, 2);
IO::delay();
IO::outb(PIC1_DATA, ICW4_8086);
IO::delay();
IO::outb(PIC2_DATA, ICW4_8086);
IO::delay();
IO::outb(PIC1_DATA, a1);
IO::delay();
IO::outb(PIC2_DATA, a2);
}
void PIC::enable_master(uint8_t mask)
{
IO::outb(PIC1_DATA, mask);
}
void PIC::enable_slave(uint8_t mask)
{
IO::outb(PIC2_DATA, mask);
}
void PIC::end_master()
{
IO::outb(PIC1_COMMAND, PIC_EOI);
}
void PIC::end_slave()
{
IO::outb(PIC2_COMMAND, PIC_EOI);
IO::outb(PIC1_COMMAND, PIC_EOI);
}
void PIC::send_eoi(unsigned char irq)
{
if (irq >= 8) end_slave();
else
end_master();
}

49
kernel/src/io/Serial.cpp Normal file
View File

@ -0,0 +1,49 @@
#include "io/Serial.h"
#include "io/IO.h"
#include <stdio.h>
#include <string.h>
#define COM1 0x3f8
void Serial::wait()
{
while (!(IO::inb(COM1 + 5) & 0x20)) { asm volatile("pause"); }
}
void Serial::write(const char* string, size_t size)
{
for (size_t i = 0; i < size; i++)
{
wait();
IO::outb(COM1, *(string + i));
}
}
void Serial::print(const char* string)
{
Serial::write(string, strlen(string));
}
void Serial::println(const char* string)
{
Serial::write(string, strlen(string));
wait();
IO::outb(COM1, '\n');
}
static const char* format_color(Color& color)
{
static char output[20];
snprintf(output, sizeof(output), "\x1b[38;2;%d;%d;%dm", color.red, color.green, color.blue);
return output;
}
void Serial::set_color(Color& color)
{
Serial::print(format_color(color));
}
void Serial::reset_color()
{
Serial::print("\x1b[0m");
}

24
kernel/src/log/Log.cpp Normal file
View File

@ -0,0 +1,24 @@
#include "log/Log.h"
#include "io/Serial.h"
#include "std/stdio.h"
void KernelLog::log(const char* function, const char* message, LogLevel level)
{
Serial::reset_color();
Serial::print(function);
Serial::print(": ");
switch (level)
{
case LogLevel::WARN: Serial::set_color(Color::Yellow); break;
case LogLevel::ERROR: Serial::set_color(Color::Red); break;
default: break;
}
printf("%s", message);
Serial::reset_color();
}
void KernelLog::logln(const char* function, const char* message, LogLevel level)
{
log(function, message, level);
Serial::print("\n");
}

136
kernel/src/main.cpp Normal file
View File

@ -0,0 +1,136 @@
#include "acpi/RSDT.h"
#include "assert.h"
#include "bootboot.h"
#include "cpu/CPU.h"
#include "debug.h"
#include "gdt/GDT.h"
#include "init/Init.h"
#include "init/InitRD.h"
#include "interrupts/IDT.h"
#include "interrupts/Install.h"
#include "interrupts/Interrupts.h"
#include "io/PIC.h"
#include "io/Serial.h"
#include "log/Log.h"
#include "memory/KernelHeap.h"
#include "panic/hang.h"
#include "render/BBRenderer.h"
#include "render/Draw.h"
#include "render/TextRenderer.h"
#include "scheduling/PIT.h"
#include "std/stdio.h"
#include "std/stdlib.h"
#include "std/string.h"
#include "utils.h"
extern BOOTBOOT bootboot;
extern "C" void _start()
{
Init::check_magic();
Init::disable_smp(); // Put all other cores except the bootstrap one in an infinite loop
Debug::DebugStatus::the()->Init();
Debug::DebugStatus::the()->StartBootStage(Color::White);
Init::early_init();
Debug::DebugStatus::the()->PassBootStage(Color::White);
InitRD::for_each(
[](InitRD::File& f) { printf("%s: %d bytes, starts with 0x%x%x\n", f.name, f.size, *(uint64_t*)f.addr); });
kinfoln("Hello World!");
Debug::DebugStatus::the()->StartBootStage(Color::Gray);
GDT::load();
Debug::DebugStatus::the()->PassBootStage(Color::Gray);
kinfoln("Loaded GDT");
Debug::DebugStatus::the()->StartBootStage(Color::Cyan);
Interrupts::install();
Debug::DebugStatus::the()->PassBootStage(Color::Cyan);
Debug::DebugStatus::the()->StartBootStage(Color::Blue);
IDT::load();
Debug::DebugStatus::the()->PassBootStage(Color::Blue);
kinfoln("Loaded IDT");
Debug::DebugStatus::the()->StartBootStage(Color::Green);
PIC::remap();
PIC::enable_master(0b11111100); // enable keyboard and PIT
PIC::enable_slave(0b11111111);
Debug::DebugStatus::the()->PassBootStage(Color::Green);
kinfoln("Prepared PIC");
Debug::DebugStatus::the()->StartBootStage(Color::Magenta);
PIT::initialize(100); // 100 times per second
Debug::DebugStatus::the()->PassBootStage(Color::Magenta);
kinfoln("Prepared PIT");
Debug::DebugStatus::the()->StartBootStage(Color::Yellow);
Interrupts::enable();
Debug::DebugStatus::the()->PassBootStage(Color::Yellow);
kinfoln("Interrupts enabled");
Debug::DebugStatus::the()->StartBootStage(Color{0x33, 0x33, 0x00, 0xFF});
ACPI::SDTHeader* rootSDT = ACPI::GetRSDTOrXSDT();
bool isXSDT = false;
if (strncmp(rootSDT->Signature, "XSDT", 4) != 0)
{
if (strncmp(rootSDT->Signature, "RSDT", 4) != 0)
{
kerrorln("Invalid RootSDT signature");
Debug::DebugStatus::the()->FailBootStage();
while (1) halt();
}
}
else
isXSDT = true;
if (ACPI::ValidateSDTHeader(rootSDT))
{
kinfoln(isXSDT ? "XSDT is valid" : "RSDT is valid");
Debug::DebugStatus::the()->PassBootStage(Color{0x33, 0x33, 0x00, 0xFF});
}
else
{
kinfoln(isXSDT ? "Invalid XSDT :(" : "Invalid RSDT :(");
Debug::DebugStatus::the()->FailBootStage();
while (1) halt();
}
Debug::DebugStatus::the()->StartBootStage(Color{0x00, 0x66, 0xCC, 0xFF});
ACPI::SDTHeader* fadt = (ACPI::SDTHeader*)ACPI::FindTable(rootSDT, "FACP");
if (!fadt)
{
kerrorln("FADT not found");
Debug::DebugStatus::the()->FailBootStage();
while (1) halt();
}
if (strncmp(fadt->Signature, "FACP", 4) != 0)
{
kerrorln("Invalid FADT signature");
Debug::DebugStatus::the()->FailBootStage();
while (1) halt();
}
else
{
if (ACPI::ValidateSDTHeader(fadt))
{
kinfoln("FADT is valid");
Debug::DebugStatus::the()->PassBootStage(Color{0x00, 0x66, 0xCC, 0xFF});
}
else
{
kinfoln("Invalid FADT :(");
Debug::DebugStatus::the()->FailBootStage();
while (1) halt();
}
}
while (1) halt();
loop:
goto loop;
}

View File

@ -0,0 +1,79 @@
#include "memory/KernelHeap.h"
#include "assert.h"
static uint8_t page_bitmap[2048];
#define ALLOC_BASE 0xfffffffff8000000
#define ALLOC_END 0xfffffffffc000000
static uint64_t start_index = 0;
static bool bitmap_read(uint64_t index)
{
return (page_bitmap[index / 8] & (0b10000000 >> (index % 8))) > 0;
}
static void bitmap_set(uint64_t index, bool value)
{
uint64_t byteIndex = index / 8;
uint8_t bitIndexer = 0b10000000 >> (index % 8);
page_bitmap[byteIndex] &= ~bitIndexer;
if (value) { page_bitmap[byteIndex] |= bitIndexer; }
}
uint64_t KernelHeap::request_virtual_page()
{
for (uint64_t index = start_index; index < sizeof(page_bitmap) * 8; index++)
{
if (bitmap_read(index)) continue;
bitmap_set(index, true);
start_index = index + 1;
return ALLOC_BASE + (index * 4096);
}
return 0;
}
uint64_t KernelHeap::request_virtual_pages(uint64_t count)
{
uint64_t contiguous = 0;
uint64_t contiguous_start = 0;
for (uint64_t index = start_index; index < sizeof(page_bitmap) * 8; index++)
{
if (bitmap_read(index))
{
contiguous = 0;
continue;
}
if (contiguous == 0)
{
contiguous_start = index;
contiguous++;
}
else
contiguous++;
if (contiguous == count)
{
for (uint64_t i = 0; i < count; i++) bitmap_set(contiguous_start + i, true);
return ALLOC_BASE + (contiguous_start * 4096);
}
}
return 0;
}
void KernelHeap::free_virtual_page(uint64_t address)
{
ASSERT(address >= ALLOC_BASE && address < ALLOC_END);
uint64_t index = (address - ALLOC_BASE) / 4096;
bitmap_set(index, false);
if (start_index > index) start_index = index;
}
void KernelHeap::free_virtual_pages(uint64_t address, uint64_t count)
{
ASSERT(address >= ALLOC_BASE && address < ALLOC_END);
uint64_t index = (address - ALLOC_BASE) / 4096;
for (uint64_t i = 0; i < count; i++) { bitmap_set(index + i, false); }
if (start_index > index) start_index = index;
}

57
kernel/src/memory/VMM.cpp Normal file
View File

@ -0,0 +1,57 @@
#include "memory/VMM.h"
namespace Paging
{
void VirtualMemoryManager::Init()
{
asm volatile("mov %%cr3, %0" : "=r"(PML4));
}
void VirtualMemoryManager::Init(PageTable* PML4)
{
this->PML4 = PML4;
}
void VirtualMemoryManager::Unmap(uint64_t virtualAddress)
{
virtualAddress >>= 12;
uint64_t P_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PT_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PD_i = virtualAddress & 0x1ff;
virtualAddress >>= 9;
uint64_t PDP_i = virtualAddress & 0x1ff;
PageDirectoryEntry PDE;
PDE = PML4->entries[PDP_i];
PageTable* PDP;
if (!PDE.Present)
{
return; // Already unmapped
}
else { PDP = (PageTable*)((uint64_t)PDE.Address << 12); }
PDE = PDP->entries[PD_i];
PageTable* PD;
if (!PDE.Present)
{
return; // Already unmapped
}
else { PD = (PageTable*)((uint64_t)PDE.Address << 12); }
PDE = PD->entries[PT_i];
PageTable* PT;
if (!PDE.Present)
{
return; // Already unmapped
}
else { PT = (PageTable*)((uint64_t)PDE.Address << 12); }
PDE = PT->entries[P_i];
PDE.Present = false;
PDE.ReadWrite = false;
PT->entries[P_i] = PDE;
}
}

14
kernel/src/panic/hang.cpp Normal file
View File

@ -0,0 +1,14 @@
#include "panic/hang.h"
void hang()
{
asm volatile("cli");
end:
halt();
goto end;
}
void halt()
{
asm volatile("hlt");
}

View File

@ -0,0 +1,48 @@
#include "render/BBRenderer.h"
#include "assert.h"
#include "bootboot.h"
extern BOOTBOOT bootboot;
extern uint8_t fb[4];
bool BBRenderer::init()
{
// FIXME: Support more framebuffer types
return bootboot.fb_type == FB_ARGB;
}
void BBRenderer::set_pixel(uint32_t x, uint32_t y, Color color)
{
*(uint32_t*)(fb + bootboot.fb_scanline * y + x * 4) = *(uint32_t*)&color;
}
Color BBRenderer::get_pixel(uint32_t x, uint32_t y)
{
return *(Color*)(fb + bootboot.fb_scanline * y + x * 4);
}
void BBRenderer::clear(Color color)
{
paint_rect(0, 0, bootboot.fb_width, bootboot.fb_height, color);
}
void BBRenderer::paint_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color color)
{
for (uint32_t i = y; i < (y + h); i++)
{
uint64_t addr = (uint64_t)(fb + (bootboot.fb_scanline * i) + (x * 4));
for (uint64_t addr_current = addr; addr_current < (addr + w * 4); addr_current += 4)
{
*(uint32_t*)addr_current = *(uint32_t*)&color;
}
}
}
void BBRenderer::paint_rect(uint32_t x, uint32_t y, uint32_t w, uint32_t h, Color* colors)
{
uint32_t j;
for (uint32_t l = j = 0; l < h; l++)
{
for (uint32_t i = 0; i < w; i++, j++) { set_pixel(x + i, y + l, colors[j]); }
}
}

View File

@ -0,0 +1,33 @@
#include "render/BaseRenderer.h"
bool BaseRenderer::init()
{
return false;
}
void BaseRenderer::set_pixel([[maybe_unused]] uint32_t x, [[maybe_unused]] uint32_t y, [[maybe_unused]] Color color)
{
return;
}
Color BaseRenderer::get_pixel([[maybe_unused]] uint32_t x, [[maybe_unused]] uint32_t y)
{
return Color::Black;
}
void BaseRenderer::paint_rect([[maybe_unused]] uint32_t x, [[maybe_unused]] uint32_t y, [[maybe_unused]] uint32_t w,
[[maybe_unused]] uint32_t h, [[maybe_unused]] Color color)
{
return;
}
void BaseRenderer::paint_rect([[maybe_unused]] uint32_t x, [[maybe_unused]] uint32_t y, [[maybe_unused]] uint32_t w,
[[maybe_unused]] uint32_t h, [[maybe_unused]] Color* colors)
{
return;
}
void BaseRenderer::clear([[maybe_unused]] Color color)
{
return;
}

View File

@ -0,0 +1,11 @@
#include "render/Color.h"
Color Color::White = {0xFF, 0xFF, 0xFF, 0xFF};
Color Color::Black = {0x00, 0x00, 0x00, 0xFF};
Color Color::Red = {0x00, 0x00, 0xFF, 0xFF};
Color Color::Green = {0x00, 0xFF, 0x00, 0xFF};
Color Color::Blue = {0xFF, 0x00, 0x00, 0xFF};
Color Color::Yellow = {0x00, 0xFF, 0xFF, 0xFF};
Color Color::Cyan = {0xFF, 0xFF, 0x00, 0xFF};
Color Color::Magenta = {0xFF, 0x00, 0xFF, 0xFF};
Color Color::Gray = {0x80, 0x80, 0x80, 0xFF};

View File

@ -0,0 +1,20 @@
#include "render/Draw.h"
#include "render/BBRenderer.h"
static BaseRenderer* s_renderer;
BBRenderer bbRenderer;
bool Draw::try_initialize()
{
if (bbRenderer.init())
{
s_renderer = &bbRenderer;
return true;
}
return false;
}
BaseRenderer* Draw::renderer()
{
return s_renderer;
}

View File

@ -0,0 +1,107 @@
#include "render/TextRenderer.h"
#include "bootboot.h"
#include "init/InitRD.h"
#include "io/Serial.h"
#include "psf2.h"
#include "render/BBRenderer.h"
#include "std/stdio.h"
#include "std/string.h"
extern BOOTBOOT bootboot;
static psf2_t* font;
static BBRenderer textRenderer;
static Color bgColor = Color::Black;
static Color fgColor = Color::White;
static uint32_t xpos = 0;
static uint32_t ypos = 0;
bool TextRenderer::try_initialize()
{
if (!textRenderer.init())
{
Serial::println("Failed to initialize BBRenderer");
return false;
}
InitRD::File font_file = InitRD::find_file("boot/font.psf");
if (!font_file.addr)
{
Serial::println("Failed to load boot/font.psf from initrd");
return false;
}
font = (psf2_t*)font_file.addr;
if (font->magic != PSF_FONT_MAGIC)
{
Serial::println("Font magic does not match PSF font magic");
return false;
}
return true;
}
bool TextRenderer::is_initialized()
{
return font; // if font is NULL, not initialized, else yes
}
static void putchar_at_offset(char c, int cx, int cy, Color& fg, Color& bg)
{
uint8_t* glyph =
(uint8_t*)font + font->headersize + (c > 0 && (uint32_t)c < font->numglyph ? c : 0) * font->bytesperglyph;
int mask;
for (uint32_t y = 0; y < font->height; y++)
{
mask = 1 << (font->width - 1);
for (uint32_t x = 0; x < font->width; x++)
{
textRenderer.set_pixel(cx + x, cy + y, *((uint32_t*)glyph) & mask ? fg : bg);
mask >>= 1;
}
}
}
void TextRenderer::putchar(char chr)
{
switch (chr)
{
case '\n':
ypos += font->height;
if ((ypos + font->height) >= bootboot.fb_height)
{
memcpy((void*)bootboot.fb_ptr, (uint32_t*)bootboot.fb_ptr + (bootboot.fb_scanline * font->height),
bootboot.fb_size - (sizeof(uint32_t) * bootboot.fb_scanline * font->height));
ypos -= font->height;
textRenderer.paint_rect(0, ypos, bootboot.fb_width, font->height, Color::Black);
}
xpos = 0;
break;
case '\r': xpos = 0; break;
case '\b':
if (xpos != 0)
{
xpos -= font->width + 1;
textRenderer.paint_rect(xpos, ypos, font->width + 1, font->height, Color::Black);
}
break;
default:
putchar_at_offset(chr, xpos, ypos, fgColor, bgColor);
xpos += font->width + 1;
if ((xpos + font->width + 1) > bootboot.fb_width)
{
xpos = 0;
ypos += font->height;
if (ypos > bootboot.fb_height)
{
memcpy((void*)bootboot.fb_ptr, (uint32_t*)bootboot.fb_ptr + (bootboot.fb_scanline * font->height),
bootboot.fb_size - (sizeof(uint32_t) * bootboot.fb_scanline * font->height));
ypos -= font->height;
textRenderer.paint_rect(0, ypos, bootboot.fb_width, font->height, Color::Black);
}
}
break;
}
}
void TextRenderer::write(const char* str, size_t size)
{
for (size_t i = 0; i < size; i++) { putchar(str[i]); }
}

View File

@ -0,0 +1,26 @@
#include "scheduling/PIT.h"
#include "io/IO.h"
#define PIT_CHANNEL_0_PORT 0x40
volatile uint64_t PIT::ms_since_boot = 0;
uint16_t divisor = 65535;
void PIT::initialize(uint64_t frequency)
{
divisor = base_frequency / frequency;
if (divisor < 100) divisor = 100;
IO::outb(PIT_CHANNEL_0_PORT, (uint8_t)(divisor & 0xFF));
IO::delay();
IO::outb(PIT_CHANNEL_0_PORT, (uint8_t)((divisor & 0xFF00) >> 8));
}
uint64_t PIT::frequency()
{
return base_frequency / divisor;
}
void PIT::tick()
{
ms_since_boot += 1000 / frequency();
}

185
kernel/src/std/stdio.cpp Normal file
View File

@ -0,0 +1,185 @@
#include "std/stdio.h"
#include "io/Serial.h"
#include "std/stdlib.h"
#include <string.h>
typedef long int ssize_t;
template <typename PutString>
static int internal_printf(const char* format, PutString put_string_callback, ssize_t max, va_list ap)
{
char buffer[1025]; // 1024 with null terminator
size_t format_size = strlen(format);
size_t format_index = 0;
size_t buffer_insert_index = 0;
ssize_t max_remaining = max;
size_t written = 0;
auto flush_buffer = [&]() {
size_t buffer_length = buffer_insert_index;
written += buffer_length;
buffer_insert_index = 0;
if (max_remaining < 0)
{
buffer[buffer_length] = 0;
put_string_callback(buffer);
return;
}
if (max_remaining == 0) { return; }
if (buffer_length <= (size_t)max_remaining)
{
max_remaining -= buffer_length;
buffer[buffer_length] = 0;
put_string_callback(buffer);
}
else
{
buffer[max_remaining] = 0;
max_remaining = 0;
put_string_callback(buffer);
}
};
while (format_index < format_size)
{
char current_char = format[format_index];
if (current_char == '%')
{
if (format_index + 1 == format_size) // end of format string
{
continue;
}
else
{
format_index++;
current_char = format[format_index];
switch (current_char)
{
case 'c': {
buffer[buffer_insert_index++] = va_arg(ap, int);
if (buffer_insert_index == 1024) flush_buffer();
break;
}
case '%': {
buffer[buffer_insert_index++] = '%';
if (buffer_insert_index == 1024) flush_buffer();
break;
}
case 'd': {
char result[41];
itoa(va_arg(ap, int), result, 10);
if (buffer_insert_index + strlen(result) > 1024) flush_buffer();
memcpy(buffer + buffer_insert_index, result, strlen(result));
buffer_insert_index += strlen(result);
if (buffer_insert_index == 1024) flush_buffer();
break;
}
case 'x': {
char result[50];
utoa(va_arg(ap, unsigned int), result, 16);
if (buffer_insert_index + strlen(result) > 1024) flush_buffer();
memcpy(buffer + buffer_insert_index, result, strlen(result));
buffer_insert_index += strlen(result);
if (buffer_insert_index == 1024) flush_buffer();
break;
}
case 's': {
const char* str = va_arg(ap, const char*);
while (strlen(str) > 1024)
{
flush_buffer();
memcpy(buffer, str, 1024);
str += 1024;
buffer_insert_index = 1024;
}
if (buffer_insert_index + strlen(str) > 1024) flush_buffer();
memcpy(buffer + buffer_insert_index, str, strlen(str));
buffer_insert_index += strlen(str);
if (buffer_insert_index == 1024) flush_buffer();
break;
}
default: {
buffer[buffer_insert_index++] = '%';
if (buffer_insert_index == 1024) flush_buffer();
buffer[buffer_insert_index++] = current_char;
if (buffer_insert_index == 1024) flush_buffer();
break;
}
}
}
}
else
{
buffer[buffer_insert_index++] = current_char;
if (buffer_insert_index == 1024) flush_buffer();
}
format_index++;
}
if (buffer_insert_index > 0) flush_buffer();
return written;
}
int printf(const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int written = internal_printf(
fmt, [](const char* s) { Serial::print(s); }, -1, ap);
va_end(ap);
return written;
}
int sprintf(char* __s, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int written = internal_printf(
fmt,
[&](const char* s) {
if (__s) { strncat(__s, s, 1025); }
},
-1, ap);
va_end(ap);
return written;
}
int snprintf(char* __s, size_t max, const char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int written = internal_printf(
fmt,
[&](const char* s) {
if (__s) { strncat(__s, s, 1025); }
},
max == 0 ? 0 : max - 1, ap);
va_end(ap);
return written;
}
int vprintf(const char* fmt, va_list ap)
{
return internal_printf(
fmt, [](const char* s) { Serial::print(s); }, -1, ap);
}
int vsprintf(char* __s, const char* fmt, va_list ap)
{
return internal_printf(
fmt,
[&](const char* s) {
if (__s) { strncat(__s, s, 1025); }
},
-1, ap);
}
int vsnprintf(char* __s, size_t max, const char* fmt, va_list ap)
{
return internal_printf(
fmt,
[&](const char* s) {
if (__s) { strncat(__s, s, 1025); }
},
max == 0 ? 0 : max - 1, ap);
}

94
kernel/src/std/stdlib.cpp Normal file
View File

@ -0,0 +1,94 @@
#include "panic/hang.h"
#include "scheduling/PIT.h"
#include <stdlib.h>
static void strrev(char* arr, int start, int end)
{
char temp;
if (start >= end) return;
temp = *(arr + start);
*(arr + start) = *(arr + end);
*(arr + end) = temp;
start++;
end--;
strrev(arr, start, end);
}
char* itoa(int number, char* arr, int base)
{
int i = 0, r, negative = 0;
if (number == 0)
{
arr[i] = '0';
arr[i + 1] = '\0';
return arr;
}
if (number < 0 && base == 10)
{
number *= -1;
negative = 1;
}
while (number != 0)
{
r = number % base;
arr[i] = (r > 9) ? (r - 10) + 'a' : r + '0';
i++;
number /= base;
}
if (negative)
{
arr[i] = '-';
i++;
}
strrev(arr, 0, i - 1);
arr[i] = '\0';
return arr;
}
char* utoa(unsigned int number, char* arr, int base)
{
int i = 0, r;
if (number == 0)
{
arr[i] = '0';
arr[i + 1] = '\0';
return arr;
}
while (number != 0)
{
r = number % base;
arr[i] = (r > 9) ? (r - 10) + 'a' : r + '0';
i++;
number /= base;
}
strrev(arr, 0, i - 1);
arr[i] = '\0';
return arr;
}
#pragma GCC push_options
#pragma GCC optimize("O0")
void sleep(uint64_t ms)
{
volatile uint64_t start = PIT::ms_since_boot;
volatile uint64_t end = (uint64_t)(start + ms);
while (PIT::ms_since_boot < end) { asm volatile("hlt"); }
}
#pragma GCC pop_options

104
kernel/src/std/string.cpp Normal file
View File

@ -0,0 +1,104 @@
#include <string.h>
size_t strlen(const char* __s)
{
const char* i = __s;
for (; *i; ++i)
;
return (i - __s);
}
char* strcpy(char* dest, const char* src)
{
memcpy(dest, src, strlen(src) + 1);
return dest;
}
char* strncpy(char* dest, const char* src, size_t n)
{
size_t src_len = strlen(src) + 1; // NULL byte
memcpy(dest, src, src_len > n ? n : src_len);
return dest;
}
int strcmp(const char* s1, const char* s2)
{
while (*s1 && (*s1 == *s2))
{
s1++;
s2++;
}
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
}
int strncmp(const char* s1, const char* s2, size_t n)
{
const char* base = s1;
while (*s1 && (*s1 == *s2) && (size_t)(s1 - base) < (n - 1))
{
s1++;
s2++;
}
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
}
char* strncat(char* dest, const char* src, size_t n)
{
size_t dest_len = strlen(dest);
size_t i;
for (i = 0; i < n && *(src + i); i++) *(char*)(dest + dest_len + i) = *(char*)(src + i);
*(char*)(dest + dest_len + i) = '\0';
return dest;
}
char* strcat(char* dest, const char* src)
{
size_t dest_len = strlen(dest);
size_t i;
for (i = 0; *(src + i); i++) *(char*)(dest + dest_len + i) = *(char*)(src + i);
*(char*)(dest + dest_len + i) = '\0';
return dest;
}
void* memcpy(void* dest, const void* src, size_t n)
{
for (size_t i = 0; i < n; ++i) { *((char*)dest + i) = *((char*)src + i); }
return dest;
}
void* memset(void* dest, int c, size_t n)
{
for (size_t i = 0; i < n; ++i) { *((char*)dest + i) = (char)c; }
return dest;
}
int memcmp(const void* a, const void* b, size_t n)
{
const char* a_uchar = (const char*)a;
const char* b_uchar = (const char*)b;
for (; n && a_uchar == b_uchar; n--, a_uchar++, b_uchar++)
;
if (!n) return 0;
if (*a_uchar > *b_uchar) return 1;
return -1;
}
void* memmove(void* dest, void* src, size_t n)
{
if (dest == src) return dest;
if (dest > src)
{
for (long i = n - 1; i >= 0; i++) { *((char*)dest + i) = *((char*)src + i); }
}
else
{
for (long i = 0; i < (long)n; i++) { *((char*)dest + i) = *((char*)src + i); }
}
return dest;
}

18
luna.json Normal file
View File

@ -0,0 +1,18 @@
{
"diskguid": "00000000-0000-0000-0000-000000000000",
"disksize": 128,
"align": 1024,
"iso9660": true,
"config": "initrd/sys/config",
"initrd": {
"type": "tar",
"gzip": true,
"directory": "initrd"
},
"partitions": [
{
"type": "boot",
"size": 16
}
]
}

13
tools/build-iso.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/sh
set -e
source $(dirname $0)/env.sh
cd $LUNA_ROOT
tools/setup.sh
make -j$(nproc)
make install
mkbootimg luna.json Luna.iso

10
tools/build.sh Executable file
View File

@ -0,0 +1,10 @@
#!/bin/sh
set -e
source $(dirname $0)/env.sh
cd $LUNA_ROOT
tools/setup.sh
make -j$(nproc)

8
tools/clean.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
set -e
source $(dirname $0)/env.sh
cd $LUNA_ROOT
make clean

8
tools/debug.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
set -e
source $(dirname $0)/env.sh
tools/build-iso.sh
qemu-system-x86_64 -cdrom Luna.iso -smp 1 -m 256M -serial stdio -d int,cpu_reset -s

3
tools/env.sh Executable file
View File

@ -0,0 +1,3 @@
#!/bin/sh
export LUNA_ROOT=$(realpath $(dirname $0)/..)
export PATH=$LUNA_ROOT/toolchain/x86-64-elf/bin:$LUNA_ROOT/toolchain/dist:$PATH

8
tools/install.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
set -e
source $(dirname $0)/env.sh
cd $LUNA_ROOT
make install

8
tools/run.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
set -e
source $(dirname $0)/env.sh
tools/build-iso.sh
qemu-system-x86_64 -cdrom Luna.iso -smp 1 -m 256M -serial stdio -enable-kvm

34
tools/setup-binutils.sh Executable file
View File

@ -0,0 +1,34 @@
#!/bin/sh
set -e
source $(dirname $0)/setup-env.sh
cd $LUNA_ROOT
mkdir -p toolchain/tarballs
mkdir -p toolchain/build
if [ ! -f toolchain/tarballs/binutils-$LUNA_BINUTILS_VERSION_REQUIRED.tar.xz ]; then
echo Downloading Binutils...
wget -Otoolchain/tarballs/binutils-$LUNA_BINUTILS_VERSION_REQUIRED.tar.xz https://ftp.gnu.org/gnu/binutils/binutils-$LUNA_BINUTILS_VERSION_REQUIRED.tar.xz
fi
echo Extracting Binutils...
tar xf toolchain/tarballs/binutils-$LUNA_BINUTILS_VERSION_REQUIRED.tar.xz -C toolchain/build/
echo Configuring Binutils...
mkdir -p toolchain/build/binutils
cd toolchain/build/binutils
../binutils-$LUNA_BINUTILS_VERSION_REQUIRED/configure --prefix="$PREFIX" --target=$TARGET --disable-nls --with-sysroot --disable-werror
echo Building Binutils...
make -j$(nproc)
echo Installing Binutils...
make install

8
tools/setup-env.sh Executable file
View File

@ -0,0 +1,8 @@
#!/bin/sh
source $(dirname $0)/env.sh
export LUNA_GCC_VERSION_REQUIRED=12.1.0
export LUNA_BINUTILS_VERSION_REQUIRED=2.38
export PREFIX=$LUNA_ROOT/toolchain/x86-64-elf
export TARGET=x86_64-elf

42
tools/setup-gcc.sh Executable file
View File

@ -0,0 +1,42 @@
#!/bin/sh
set -e
source $(dirname $0)/setup-env.sh
cd $LUNA_ROOT
if [ ! -x $(command -v x86_64-elf-as) ]
then
echo Binutils should be cross-built before GCC.
exit 1
fi
mkdir -p toolchain/tarballs
mkdir -p toolchain/build
if [ ! -f toolchain/tarballs/gcc-$LUNA_GCC_VERSION_REQUIRED.tar.xz ]; then
echo Downloading GCC...
wget -Otoolchain/tarballs/gcc-$LUNA_GCC_VERSION_REQUIRED.tar.xz https://ftp.gnu.org/gnu/gcc/gcc-$LUNA_GCC_VERSION_REQUIRED/gcc-$LUNA_GCC_VERSION_REQUIRED.tar.xz
fi
echo Extracting GCC...
tar xf toolchain/tarballs/gcc-$LUNA_GCC_VERSION_REQUIRED.tar.xz -C toolchain/build/
echo Configuring GCC...
mkdir -p toolchain/build/gcc
cd toolchain/build/gcc
../gcc-$LUNA_GCC_VERSION_REQUIRED/configure --prefix="$PREFIX" --target=$TARGET --disable-nls --enable-languages=c,c++ --without-headers
echo Building GCC...
make all-gcc -j$(nproc)
make all-target-libgcc -j$(nproc) CFLAGS_FOR_TARGET='-g -O2 -mcmodel=large -mno-red-zone'
echo Installing GCC...
make install-gcc
make install-target-libgcc

19
tools/setup-mkbootimg.sh Executable file
View File

@ -0,0 +1,19 @@
#!/bin/sh
set -e
source $(dirname $0)/env.sh
cd $LUNA_ROOT
mkdir -p toolchain/dist
cd toolchain
git clone https://gitlab.com/bztsrc/bootboot.git
cd bootboot/mkbootimg
make -j$(nproc)
cp ./mkbootimg ../../dist/mkbootimg
rm ../mkbootimg-*.zip

20
tools/setup.sh Executable file
View File

@ -0,0 +1,20 @@
#!/bin/sh
set -e
if ! $(dirname $0)/test-binutils.sh
then
echo Building Binutils...
$(dirname $0)/setup-binutils.sh
fi
if ! $(dirname $0)/test-gcc.sh
then
echo Building GCC..
$(dirname $0)/setup-gcc.sh
fi
if ! [ -f $(dirname $0)/../toolchain/dist/mkbootimg ]
then
echo Building mkbootimg...
$(dirname $0)/setup-mkbootimg.sh
fi

15
tools/test-binutils.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/sh
set -e
source $(dirname $0)/setup-env.sh
if [ -x "$(command -v x86_64-elf-ar)" ]
then
if [ "$(x86_64-elf-ar --version | head -n 1 | awk '{ print $5 }')" == "$LUNA_BINUTILS_VERSION_REQUIRED" ]
then
exit 0
else
exit 1
fi
else
exit 1
fi

15
tools/test-gcc.sh Executable file
View File

@ -0,0 +1,15 @@
#!/bin/sh
set -e
source $(dirname $0)/setup-env.sh
if [ -x "$(command -v x86_64-elf-gcc)" ]
then
if [ "$(x86_64-elf-gcc --version | head -n 1 | awk '{ print $3 }')" == "$LUNA_GCC_VERSION_REQUIRED" ]
then
exit 0
else
exit 1
fi
else
exit 1
fi