From 1b727a66ea8a3d45753f11deba50c375996b81d9 Mon Sep 17 00:00:00 2001 From: apio Date: Mon, 5 Sep 2022 16:13:51 +0200 Subject: [PATCH] Ready. Set. Go! --- .clang-format | 12 ++ .gitignore | 6 + Makefile | 7 + initrd/boot/font.psf | Bin 0 -> 4421 bytes initrd/sys/config | 3 + kernel/Makefile | 60 ++++++++ kernel/include/acpi/RSDT.h | 35 +++++ kernel/include/assert.h | 9 ++ kernel/include/bootboot.h | 162 ++++++++++++++++++++ kernel/include/cpu/CPU.h | 12 ++ kernel/include/cpu/Features.h | 72 +++++++++ kernel/include/debug.h | 31 ++++ kernel/include/fs/ext2/Superblock.h | 34 +++++ kernel/include/gdt/GDT.h | 6 + kernel/include/init/Init.h | 8 + kernel/include/init/InitRD.h | 44 ++++++ kernel/include/interrupts/IDT.h | 12 ++ kernel/include/interrupts/IRQ.h | 7 + kernel/include/interrupts/Install.h | 7 + kernel/include/interrupts/Interrupts.h | 7 + kernel/include/interrupts/SavedContext.h | 15 ++ kernel/include/io/IO.h | 13 ++ kernel/include/io/PIC.h | 12 ++ kernel/include/io/Serial.h | 13 ++ kernel/include/log/Log.h | 23 +++ kernel/include/memory/KernelHeap.h | 11 ++ kernel/include/memory/Paging.h | 25 +++ kernel/include/memory/VMM.h | 17 +++ kernel/include/panic/hang.h | 4 + kernel/include/psf2.h | 17 +++ kernel/include/render/BBRenderer.h | 13 ++ kernel/include/render/BaseRenderer.h | 13 ++ kernel/include/render/Color.h | 20 +++ kernel/include/render/Draw.h | 8 + kernel/include/render/TextRenderer.h | 13 ++ kernel/include/scheduling/PIT.h | 11 ++ kernel/include/std/stdio.h | 10 ++ kernel/include/std/stdlib.h | 7 + kernel/include/std/string.h | 17 +++ kernel/include/utils.h | 4 + kernel/moon.ld | 31 ++++ kernel/src/acpi/RSDT.cpp | 40 +++++ kernel/src/assert.cpp | 10 ++ kernel/src/cpu/CPU.cpp | 82 ++++++++++ kernel/src/debug.cpp | 61 ++++++++ kernel/src/gdt/GDT.asm | 16 ++ kernel/src/gdt/GDT.cpp | 43 ++++++ kernel/src/init/Init.cpp | 32 ++++ kernel/src/init/InitRD.cpp | 81 ++++++++++ kernel/src/interrupts/Entry.cpp | 19 +++ kernel/src/interrupts/IDT.cpp | 57 +++++++ kernel/src/interrupts/IRQ.cpp | 26 ++++ kernel/src/interrupts/Install.cpp | 106 +++++++++++++ kernel/src/interrupts/InterruptEntry.asm | 136 +++++++++++++++++ kernel/src/interrupts/Interrupts.cpp | 11 ++ kernel/src/io/IO.cpp | 42 +++++ kernel/src/io/PIC.cpp | 74 +++++++++ kernel/src/io/Serial.cpp | 49 ++++++ kernel/src/log/Log.cpp | 24 +++ kernel/src/main.cpp | 136 +++++++++++++++++ kernel/src/memory/KernelHeap.cpp | 79 ++++++++++ kernel/src/memory/VMM.cpp | 57 +++++++ kernel/src/panic/hang.cpp | 14 ++ kernel/src/render/BBRenderer.cpp | 48 ++++++ kernel/src/render/BaseRenderer.cpp | 33 ++++ kernel/src/render/Color.cpp | 11 ++ kernel/src/render/Draw.cpp | 20 +++ kernel/src/render/TextRenderer.cpp | 107 +++++++++++++ kernel/src/scheduling/PIT.cpp | 26 ++++ kernel/src/std/stdio.cpp | 185 +++++++++++++++++++++++ kernel/src/std/stdlib.cpp | 94 ++++++++++++ kernel/src/std/string.cpp | 104 +++++++++++++ luna.json | 18 +++ tools/build-iso.sh | 13 ++ tools/build.sh | 10 ++ tools/clean.sh | 8 + tools/debug.sh | 8 + tools/env.sh | 3 + tools/install.sh | 8 + tools/run.sh | 8 + tools/setup-binutils.sh | 34 +++++ tools/setup-env.sh | 8 + tools/setup-gcc.sh | 42 +++++ tools/setup-mkbootimg.sh | 19 +++ tools/setup.sh | 20 +++ tools/test-binutils.sh | 15 ++ tools/test-gcc.sh | 15 ++ 87 files changed, 2883 insertions(+) create mode 100644 .clang-format create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 initrd/boot/font.psf create mode 100644 initrd/sys/config create mode 100644 kernel/Makefile create mode 100644 kernel/include/acpi/RSDT.h create mode 100644 kernel/include/assert.h create mode 100644 kernel/include/bootboot.h create mode 100644 kernel/include/cpu/CPU.h create mode 100644 kernel/include/cpu/Features.h create mode 100644 kernel/include/debug.h create mode 100644 kernel/include/fs/ext2/Superblock.h create mode 100644 kernel/include/gdt/GDT.h create mode 100644 kernel/include/init/Init.h create mode 100644 kernel/include/init/InitRD.h create mode 100644 kernel/include/interrupts/IDT.h create mode 100644 kernel/include/interrupts/IRQ.h create mode 100644 kernel/include/interrupts/Install.h create mode 100644 kernel/include/interrupts/Interrupts.h create mode 100644 kernel/include/interrupts/SavedContext.h create mode 100644 kernel/include/io/IO.h create mode 100644 kernel/include/io/PIC.h create mode 100644 kernel/include/io/Serial.h create mode 100644 kernel/include/log/Log.h create mode 100644 kernel/include/memory/KernelHeap.h create mode 100644 kernel/include/memory/Paging.h create mode 100644 kernel/include/memory/VMM.h create mode 100644 kernel/include/panic/hang.h create mode 100644 kernel/include/psf2.h create mode 100644 kernel/include/render/BBRenderer.h create mode 100644 kernel/include/render/BaseRenderer.h create mode 100644 kernel/include/render/Color.h create mode 100644 kernel/include/render/Draw.h create mode 100644 kernel/include/render/TextRenderer.h create mode 100644 kernel/include/scheduling/PIT.h create mode 100644 kernel/include/std/stdio.h create mode 100644 kernel/include/std/stdlib.h create mode 100644 kernel/include/std/string.h create mode 100644 kernel/include/utils.h create mode 100644 kernel/moon.ld create mode 100644 kernel/src/acpi/RSDT.cpp create mode 100644 kernel/src/assert.cpp create mode 100644 kernel/src/cpu/CPU.cpp create mode 100644 kernel/src/debug.cpp create mode 100644 kernel/src/gdt/GDT.asm create mode 100644 kernel/src/gdt/GDT.cpp create mode 100644 kernel/src/init/Init.cpp create mode 100644 kernel/src/init/InitRD.cpp create mode 100644 kernel/src/interrupts/Entry.cpp create mode 100644 kernel/src/interrupts/IDT.cpp create mode 100644 kernel/src/interrupts/IRQ.cpp create mode 100644 kernel/src/interrupts/Install.cpp create mode 100644 kernel/src/interrupts/InterruptEntry.asm create mode 100644 kernel/src/interrupts/Interrupts.cpp create mode 100644 kernel/src/io/IO.cpp create mode 100644 kernel/src/io/PIC.cpp create mode 100644 kernel/src/io/Serial.cpp create mode 100644 kernel/src/log/Log.cpp create mode 100644 kernel/src/main.cpp create mode 100644 kernel/src/memory/KernelHeap.cpp create mode 100644 kernel/src/memory/VMM.cpp create mode 100644 kernel/src/panic/hang.cpp create mode 100644 kernel/src/render/BBRenderer.cpp create mode 100644 kernel/src/render/BaseRenderer.cpp create mode 100644 kernel/src/render/Color.cpp create mode 100644 kernel/src/render/Draw.cpp create mode 100644 kernel/src/render/TextRenderer.cpp create mode 100644 kernel/src/scheduling/PIT.cpp create mode 100644 kernel/src/std/stdio.cpp create mode 100644 kernel/src/std/stdlib.cpp create mode 100644 kernel/src/std/string.cpp create mode 100644 luna.json create mode 100755 tools/build-iso.sh create mode 100755 tools/build.sh create mode 100755 tools/clean.sh create mode 100755 tools/debug.sh create mode 100755 tools/env.sh create mode 100755 tools/install.sh create mode 100755 tools/run.sh create mode 100755 tools/setup-binutils.sh create mode 100755 tools/setup-env.sh create mode 100755 tools/setup-gcc.sh create mode 100755 tools/setup-mkbootimg.sh create mode 100755 tools/setup.sh create mode 100755 tools/test-binutils.sh create mode 100755 tools/test-gcc.sh diff --git a/.clang-format b/.clang-format new file mode 100644 index 00000000..0dc2c5dc --- /dev/null +++ b/.clang-format @@ -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 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..39b78a63 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +Luna.iso +toolchain/ +.vscode/ +**/*.o +initrd/boot/moon.elf +kernel/bin/moon.elf \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..8a03ac55 --- /dev/null +++ b/Makefile @@ -0,0 +1,7 @@ +build: $(LUNA_ROOT)/kernel/bin/moon.elf + +clean: moon-clean + +install: $(LUNA_ROOT)/initrd/boot/moon.elf + +include kernel/Makefile \ No newline at end of file diff --git a/initrd/boot/font.psf b/initrd/boot/font.psf new file mode 100644 index 0000000000000000000000000000000000000000..0054a2b4f3ed691ef2bcd72e08ad90c94e0ecdb5 GIT binary patch literal 4421 zcmeHJ>2nlC6d$&>sG%waBbBn&s#MslD+Ui-5FzNe%#O>t8xtX5yblBqyb%wA#syLF zLPbPGMdg-LQ9)5qs`mXS{1trr`CcEhJ;7L1KJ$|9nP0#Ab#K2}d#Zo4$CT$WNnUuG z#t#|3V5VlQsHu@V4$6g7^w0CJoYk1DWlQyXX-=b7Td1KntlxRg`o8kz`&n7b2Z72q2=W4%in(U4 z?VFh!cxaZHb2+wQS1vlAxtw8Tm8*O{iqt|F*ZP;Oj6=iqbG_oYY+x8?vVM@a)|y$L z6HJ7&9i7E$GpizIg=Q3uI^0}78s*=LwcN~T&xz$Ybhz?f&SY(no(eaK*+QG3#1!aC zDRUg34Uw_1SU@`pV}5V%U{|5CWN2vlV3ePs__<;n%THPhdmOODJZfM!S1F3}-3E?S znHN__43vDCZ9N+pIl8sDV0BqhT^)v7mMXXFoDpi*Dz4Votf^ORR1yS}byQh3+-OuP z6=N!1xvam&<_(leGTE}LbXa)|H=9uliraQnj-paWCS%i=BPL{Ywc*6Fz+y4kBMzw2 zXbi7Pgqg*~HLy}CbULOssACmv(A;iy^kvf3;*zT$fIe9xDh8Q!;e+0)F`9m;%fmet znjL1!e6;jC*FiE)_Sf^mIErjWyagE&6gWvfF)u`7Se0l29jBVv{SS*Ig4~4IsvY*JRbEi+=MRiSg zbzyfE28V_Q3tbn9>V+xOi}m94DdTW?xj8;7&6((DUfRmU5&tkRL0OXJlrKT@KSX4= z_%h&P<^%5J{0-IAeIe_oAb;Pu+_?iO$a~~+*^CR>?TlRS?B0?35)*;#-I5^tb(=N& zbs_t8AvQ&876XXG|(w#=U+O!}CyWf!t#7hW|p z1q+1~R5^2p?JSt=Cv_JVHyT5QFyaMHU)}7cYp^31a{4ah^j*k~#`JE}LdCF97*_{a zVL&5xfAp{yI=upFd?$y}m#@Ql6!E>jNx)on|e59VmVsD2^P+ zx~XQJ?%k~Ga#`1b(>waIZae0T+-9w!;^LTQt)gl}6;&HbH5gf86=WNFeERuTNj|r{ zOei1jYJb~1Y`-_m4jagh#BgjNTXvy64(0ThjQOHSgqaJR-?0rstrIez-@cQ_Rvue; zZ0B)St!`BFF2?(LoaAwg$0kuhYaftD4+^*%MO=fKxE8&bh3jxVZorM0jhj%y9L&Yd zn1@?19}Ccjg}4>BA;j${V-X@$5aSM1u^2Vni8>nS$6Xk}AnwKzEX5F(VL9%>Fz&^D zxE~MTK|F+q@dzHpV_1R5u@bBB1fIlGcp9tm44%bvcpfj{MZAPHco}Q)3SPx)cpd97 zg7tUJ15tvzV%m0Vl<(K>+EK~DS-T8H^@l*e%?gesvJYMqwpjCwr> z+6a0Zv$ hSI}>ulb} + +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); +} \ No newline at end of file diff --git a/kernel/include/assert.h b/kernel/include/assert.h new file mode 100644 index 00000000..46f745cd --- /dev/null +++ b/kernel/include/assert.h @@ -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) \ No newline at end of file diff --git a/kernel/include/bootboot.h b/kernel/include/bootboot.h new file mode 100644 index 00000000..8ac1207e --- /dev/null +++ b/kernel/include/bootboot.h @@ -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 + +#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 diff --git a/kernel/include/cpu/CPU.h b/kernel/include/cpu/CPU.h new file mode 100644 index 00000000..56813d00 --- /dev/null +++ b/kernel/include/cpu/CPU.h @@ -0,0 +1,12 @@ +#pragma once +#include "cpu/Features.h" +#include + +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); +} \ No newline at end of file diff --git a/kernel/include/cpu/Features.h b/kernel/include/cpu/Features.h new file mode 100644 index 00000000..c5e99053 --- /dev/null +++ b/kernel/include/cpu/Features.h @@ -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, + }; +} \ No newline at end of file diff --git a/kernel/include/debug.h b/kernel/include/debug.h new file mode 100644 index 00000000..71dc39a9 --- /dev/null +++ b/kernel/include/debug.h @@ -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; + }; +} \ No newline at end of file diff --git a/kernel/include/fs/ext2/Superblock.h b/kernel/include/fs/ext2/Superblock.h new file mode 100644 index 00000000..afd72150 --- /dev/null +++ b/kernel/include/fs/ext2/Superblock.h @@ -0,0 +1,34 @@ +#pragma once +#include + +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 + }; +} \ No newline at end of file diff --git a/kernel/include/gdt/GDT.h b/kernel/include/gdt/GDT.h new file mode 100644 index 00000000..297199ad --- /dev/null +++ b/kernel/include/gdt/GDT.h @@ -0,0 +1,6 @@ +#pragma once + +namespace GDT +{ + void load(); +} \ No newline at end of file diff --git a/kernel/include/init/Init.h b/kernel/include/init/Init.h new file mode 100644 index 00000000..3047d2c3 --- /dev/null +++ b/kernel/include/init/Init.h @@ -0,0 +1,8 @@ +#pragma once + +namespace Init +{ + void check_magic(); + void disable_smp(); + void early_init(); +} \ No newline at end of file diff --git a/kernel/include/init/InitRD.h b/kernel/include/init/InitRD.h new file mode 100644 index 00000000..e4275507 --- /dev/null +++ b/kernel/include/init/InitRD.h @@ -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)); +} \ No newline at end of file diff --git a/kernel/include/interrupts/IDT.h b/kernel/include/interrupts/IDT.h new file mode 100644 index 00000000..7bbd01d8 --- /dev/null +++ b/kernel/include/interrupts/IDT.h @@ -0,0 +1,12 @@ +#pragma once +#include + +#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(); +} \ No newline at end of file diff --git a/kernel/include/interrupts/IRQ.h b/kernel/include/interrupts/IRQ.h new file mode 100644 index 00000000..441f6d64 --- /dev/null +++ b/kernel/include/interrupts/IRQ.h @@ -0,0 +1,7 @@ +#pragma once +#include "SavedContext.h" + +namespace IRQ +{ + void interrupt_handler(SavedContext* context); +} \ No newline at end of file diff --git a/kernel/include/interrupts/Install.h b/kernel/include/interrupts/Install.h new file mode 100644 index 00000000..18d985b2 --- /dev/null +++ b/kernel/include/interrupts/Install.h @@ -0,0 +1,7 @@ +#pragma once +#include + +namespace Interrupts +{ + void install(); +} \ No newline at end of file diff --git a/kernel/include/interrupts/Interrupts.h b/kernel/include/interrupts/Interrupts.h new file mode 100644 index 00000000..5365e370 --- /dev/null +++ b/kernel/include/interrupts/Interrupts.h @@ -0,0 +1,7 @@ +#pragma once + +namespace Interrupts +{ + void enable(); + void disable(); +} \ No newline at end of file diff --git a/kernel/include/interrupts/SavedContext.h b/kernel/include/interrupts/SavedContext.h new file mode 100644 index 00000000..3b2af66f --- /dev/null +++ b/kernel/include/interrupts/SavedContext.h @@ -0,0 +1,15 @@ +#pragma once +#include + +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; +}; \ No newline at end of file diff --git a/kernel/include/io/IO.h b/kernel/include/io/IO.h new file mode 100644 index 00000000..883983ad --- /dev/null +++ b/kernel/include/io/IO.h @@ -0,0 +1,13 @@ +#pragma once +#include + +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(); +} \ No newline at end of file diff --git a/kernel/include/io/PIC.h b/kernel/include/io/PIC.h new file mode 100644 index 00000000..1aaf6079 --- /dev/null +++ b/kernel/include/io/PIC.h @@ -0,0 +1,12 @@ +#pragma once +#include + +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); +} \ No newline at end of file diff --git a/kernel/include/io/Serial.h b/kernel/include/io/Serial.h new file mode 100644 index 00000000..9d371563 --- /dev/null +++ b/kernel/include/io/Serial.h @@ -0,0 +1,13 @@ +#pragma once +#include "render/Color.h" +#include + +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(); +} \ No newline at end of file diff --git a/kernel/include/log/Log.h b/kernel/include/log/Log.h new file mode 100644 index 00000000..7ad2d646 --- /dev/null +++ b/kernel/include/log/Log.h @@ -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) \ No newline at end of file diff --git a/kernel/include/memory/KernelHeap.h b/kernel/include/memory/KernelHeap.h new file mode 100644 index 00000000..1aa3fd84 --- /dev/null +++ b/kernel/include/memory/KernelHeap.h @@ -0,0 +1,11 @@ +#pragma once +#include + +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); +} \ No newline at end of file diff --git a/kernel/include/memory/Paging.h b/kernel/include/memory/Paging.h new file mode 100644 index 00000000..faf67ea1 --- /dev/null +++ b/kernel/include/memory/Paging.h @@ -0,0 +1,25 @@ +#pragma once +#include + +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))); +} \ No newline at end of file diff --git a/kernel/include/memory/VMM.h b/kernel/include/memory/VMM.h new file mode 100644 index 00000000..9082789d --- /dev/null +++ b/kernel/include/memory/VMM.h @@ -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; + }; +} \ No newline at end of file diff --git a/kernel/include/panic/hang.h b/kernel/include/panic/hang.h new file mode 100644 index 00000000..14f0c124 --- /dev/null +++ b/kernel/include/panic/hang.h @@ -0,0 +1,4 @@ +#pragma once + +void hang(); +void halt(); \ No newline at end of file diff --git a/kernel/include/psf2.h b/kernel/include/psf2.h new file mode 100644 index 00000000..6e7c9672 --- /dev/null +++ b/kernel/include/psf2.h @@ -0,0 +1,17 @@ +#pragma once +#include + +#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; \ No newline at end of file diff --git a/kernel/include/render/BBRenderer.h b/kernel/include/render/BBRenderer.h new file mode 100644 index 00000000..d61bb7c1 --- /dev/null +++ b/kernel/include/render/BBRenderer.h @@ -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; +}; \ No newline at end of file diff --git a/kernel/include/render/BaseRenderer.h b/kernel/include/render/BaseRenderer.h new file mode 100644 index 00000000..cf8c7651 --- /dev/null +++ b/kernel/include/render/BaseRenderer.h @@ -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); +}; \ No newline at end of file diff --git a/kernel/include/render/Color.h b/kernel/include/render/Color.h new file mode 100644 index 00000000..fbb83386 --- /dev/null +++ b/kernel/include/render/Color.h @@ -0,0 +1,20 @@ +#pragma once +#include + +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) \ No newline at end of file diff --git a/kernel/include/render/Draw.h b/kernel/include/render/Draw.h new file mode 100644 index 00000000..c7123de3 --- /dev/null +++ b/kernel/include/render/Draw.h @@ -0,0 +1,8 @@ +#pragma once +#include "render/BaseRenderer.h" + +namespace Draw +{ + bool try_initialize(); + BaseRenderer* renderer(); +} \ No newline at end of file diff --git a/kernel/include/render/TextRenderer.h b/kernel/include/render/TextRenderer.h new file mode 100644 index 00000000..00e2b480 --- /dev/null +++ b/kernel/include/render/TextRenderer.h @@ -0,0 +1,13 @@ +#pragma once +#include "render/Color.h" +#include + +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(); +} \ No newline at end of file diff --git a/kernel/include/scheduling/PIT.h b/kernel/include/scheduling/PIT.h new file mode 100644 index 00000000..9151508f --- /dev/null +++ b/kernel/include/scheduling/PIT.h @@ -0,0 +1,11 @@ +#pragma once +#include + +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(); +} diff --git a/kernel/include/std/stdio.h b/kernel/include/std/stdio.h new file mode 100644 index 00000000..6563ab59 --- /dev/null +++ b/kernel/include/std/stdio.h @@ -0,0 +1,10 @@ +#pragma once +#include +#include + +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); \ No newline at end of file diff --git a/kernel/include/std/stdlib.h b/kernel/include/std/stdlib.h new file mode 100644 index 00000000..32327224 --- /dev/null +++ b/kernel/include/std/stdlib.h @@ -0,0 +1,7 @@ +#pragma once +#include + +char* itoa(int number, char* arr, int base); +char* utoa(unsigned int number, char* arr, int base); + +void sleep(uint64_t ms); \ No newline at end of file diff --git a/kernel/include/std/string.h b/kernel/include/std/string.h new file mode 100644 index 00000000..6ea5d3fb --- /dev/null +++ b/kernel/include/std/string.h @@ -0,0 +1,17 @@ +#pragma once +#include + +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); \ No newline at end of file diff --git a/kernel/include/utils.h b/kernel/include/utils.h new file mode 100644 index 00000000..732e866e --- /dev/null +++ b/kernel/include/utils.h @@ -0,0 +1,4 @@ +#pragma once +#include + +#define hex64(bit64num) (uint64_t) bit64num >> 32, (uint64_t)bit64num & 0xFFFFFFFF \ No newline at end of file diff --git a/kernel/moon.ld b/kernel/moon.ld new file mode 100644 index 00000000..65d26417 --- /dev/null +++ b/kernel/moon.ld @@ -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) } +} + diff --git a/kernel/src/acpi/RSDT.cpp b/kernel/src/acpi/RSDT.cpp new file mode 100644 index 00000000..4f62eb1e --- /dev/null +++ b/kernel/src/acpi/RSDT.cpp @@ -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; +} \ No newline at end of file diff --git a/kernel/src/assert.cpp b/kernel/src/assert.cpp new file mode 100644 index 00000000..9c94d7a0 --- /dev/null +++ b/kernel/src/assert.cpp @@ -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; +} \ No newline at end of file diff --git a/kernel/src/cpu/CPU.cpp b/kernel/src/cpu/CPU.cpp new file mode 100644 index 00000000..f98b6051 --- /dev/null +++ b/kernel/src/cpu/CPU.cpp @@ -0,0 +1,82 @@ +#include "cpu/CPU.h" +#include +#include + +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; +} diff --git a/kernel/src/debug.cpp b/kernel/src/debug.cpp new file mode 100644 index 00000000..4a240e40 --- /dev/null +++ b/kernel/src/debug.cpp @@ -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 \ No newline at end of file diff --git a/kernel/src/gdt/GDT.asm b/kernel/src/gdt/GDT.asm new file mode 100644 index 00000000..d09b90d7 --- /dev/null +++ b/kernel/src/gdt/GDT.asm @@ -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 \ No newline at end of file diff --git a/kernel/src/gdt/GDT.cpp b/kernel/src/gdt/GDT.cpp new file mode 100644 index 00000000..745cc05b --- /dev/null +++ b/kernel/src/gdt/GDT.cpp @@ -0,0 +1,43 @@ +#include "gdt/GDT.h" +#include + +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); +} \ No newline at end of file diff --git a/kernel/src/init/Init.cpp b/kernel/src/init/Init.cpp new file mode 100644 index 00000000..11009e44 --- /dev/null +++ b/kernel/src/init/Init.cpp @@ -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 + +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()); +} \ No newline at end of file diff --git a/kernel/src/init/InitRD.cpp b/kernel/src/init/InitRD.cpp new file mode 100644 index 00000000..b107fd3d --- /dev/null +++ b/kernel/src/init/InitRD.cpp @@ -0,0 +1,81 @@ +#include "init/InitRD.h" +#include "bootboot.h" +#include "io/Serial.h" +#include "std/stdlib.h" +#include + +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); + } +} \ No newline at end of file diff --git a/kernel/src/interrupts/Entry.cpp b/kernel/src/interrupts/Entry.cpp new file mode 100644 index 00000000..994669cd --- /dev/null +++ b/kernel/src/interrupts/Entry.cpp @@ -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; +} \ No newline at end of file diff --git a/kernel/src/interrupts/IDT.cpp b/kernel/src/interrupts/IDT.cpp new file mode 100644 index 00000000..9a3c6aa4 --- /dev/null +++ b/kernel/src/interrupts/IDT.cpp @@ -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)); +} \ No newline at end of file diff --git a/kernel/src/interrupts/IRQ.cpp b/kernel/src/interrupts/IRQ.cpp new file mode 100644 index 00000000..f0fb2729 --- /dev/null +++ b/kernel/src/interrupts/IRQ.cpp @@ -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; +} \ No newline at end of file diff --git a/kernel/src/interrupts/Install.cpp b/kernel/src/interrupts/Install.cpp new file mode 100644 index 00000000..163141d2 --- /dev/null +++ b/kernel/src/interrupts/Install.cpp @@ -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); } +} \ No newline at end of file diff --git a/kernel/src/interrupts/InterruptEntry.asm b/kernel/src/interrupts/InterruptEntry.asm new file mode 100644 index 00000000..04183b1c --- /dev/null +++ b/kernel/src/interrupts/InterruptEntry.asm @@ -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 \ No newline at end of file diff --git a/kernel/src/interrupts/Interrupts.cpp b/kernel/src/interrupts/Interrupts.cpp new file mode 100644 index 00000000..e295bc43 --- /dev/null +++ b/kernel/src/interrupts/Interrupts.cpp @@ -0,0 +1,11 @@ +#include "interrupts/Interrupts.h" + +void Interrupts::disable() +{ + asm volatile("cli"); +} + +void Interrupts::enable() +{ + asm volatile("sti"); +} \ No newline at end of file diff --git a/kernel/src/io/IO.cpp b/kernel/src/io/IO.cpp new file mode 100644 index 00000000..5eb75688 --- /dev/null +++ b/kernel/src/io/IO.cpp @@ -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)); +} \ No newline at end of file diff --git a/kernel/src/io/PIC.cpp b/kernel/src/io/PIC.cpp new file mode 100644 index 00000000..d0e1ed75 --- /dev/null +++ b/kernel/src/io/PIC.cpp @@ -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(); +} \ No newline at end of file diff --git a/kernel/src/io/Serial.cpp b/kernel/src/io/Serial.cpp new file mode 100644 index 00000000..753d368a --- /dev/null +++ b/kernel/src/io/Serial.cpp @@ -0,0 +1,49 @@ +#include "io/Serial.h" +#include "io/IO.h" +#include +#include + +#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"); +} \ No newline at end of file diff --git a/kernel/src/log/Log.cpp b/kernel/src/log/Log.cpp new file mode 100644 index 00000000..ac41b2a4 --- /dev/null +++ b/kernel/src/log/Log.cpp @@ -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"); +} \ No newline at end of file diff --git a/kernel/src/main.cpp b/kernel/src/main.cpp new file mode 100644 index 00000000..cfb43f39 --- /dev/null +++ b/kernel/src/main.cpp @@ -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; +} \ No newline at end of file diff --git a/kernel/src/memory/KernelHeap.cpp b/kernel/src/memory/KernelHeap.cpp new file mode 100644 index 00000000..357ccb94 --- /dev/null +++ b/kernel/src/memory/KernelHeap.cpp @@ -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; +} \ No newline at end of file diff --git a/kernel/src/memory/VMM.cpp b/kernel/src/memory/VMM.cpp new file mode 100644 index 00000000..833d9824 --- /dev/null +++ b/kernel/src/memory/VMM.cpp @@ -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; + } +} \ No newline at end of file diff --git a/kernel/src/panic/hang.cpp b/kernel/src/panic/hang.cpp new file mode 100644 index 00000000..e920c317 --- /dev/null +++ b/kernel/src/panic/hang.cpp @@ -0,0 +1,14 @@ +#include "panic/hang.h" + +void hang() +{ + asm volatile("cli"); +end: + halt(); + goto end; +} + +void halt() +{ + asm volatile("hlt"); +} \ No newline at end of file diff --git a/kernel/src/render/BBRenderer.cpp b/kernel/src/render/BBRenderer.cpp new file mode 100644 index 00000000..f8175e1c --- /dev/null +++ b/kernel/src/render/BBRenderer.cpp @@ -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]); } + } +} \ No newline at end of file diff --git a/kernel/src/render/BaseRenderer.cpp b/kernel/src/render/BaseRenderer.cpp new file mode 100644 index 00000000..27329fa9 --- /dev/null +++ b/kernel/src/render/BaseRenderer.cpp @@ -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; +} \ No newline at end of file diff --git a/kernel/src/render/Color.cpp b/kernel/src/render/Color.cpp new file mode 100644 index 00000000..737c9610 --- /dev/null +++ b/kernel/src/render/Color.cpp @@ -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}; \ No newline at end of file diff --git a/kernel/src/render/Draw.cpp b/kernel/src/render/Draw.cpp new file mode 100644 index 00000000..5243f62a --- /dev/null +++ b/kernel/src/render/Draw.cpp @@ -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; +} \ No newline at end of file diff --git a/kernel/src/render/TextRenderer.cpp b/kernel/src/render/TextRenderer.cpp new file mode 100644 index 00000000..2b26638f --- /dev/null +++ b/kernel/src/render/TextRenderer.cpp @@ -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]); } +} \ No newline at end of file diff --git a/kernel/src/scheduling/PIT.cpp b/kernel/src/scheduling/PIT.cpp new file mode 100644 index 00000000..657eeaa8 --- /dev/null +++ b/kernel/src/scheduling/PIT.cpp @@ -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(); +} \ No newline at end of file diff --git a/kernel/src/std/stdio.cpp b/kernel/src/std/stdio.cpp new file mode 100644 index 00000000..f140826e --- /dev/null +++ b/kernel/src/std/stdio.cpp @@ -0,0 +1,185 @@ +#include "std/stdio.h" +#include "io/Serial.h" +#include "std/stdlib.h" +#include + +typedef long int ssize_t; + +template +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); +} \ No newline at end of file diff --git a/kernel/src/std/stdlib.cpp b/kernel/src/std/stdlib.cpp new file mode 100644 index 00000000..fbf22fdb --- /dev/null +++ b/kernel/src/std/stdlib.cpp @@ -0,0 +1,94 @@ +#include "panic/hang.h" +#include "scheduling/PIT.h" +#include + +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 \ No newline at end of file diff --git a/kernel/src/std/string.cpp b/kernel/src/std/string.cpp new file mode 100644 index 00000000..31919154 --- /dev/null +++ b/kernel/src/std/string.cpp @@ -0,0 +1,104 @@ +#include + +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; +} \ No newline at end of file diff --git a/luna.json b/luna.json new file mode 100644 index 00000000..30bfcfad --- /dev/null +++ b/luna.json @@ -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 + } + ] +} \ No newline at end of file diff --git a/tools/build-iso.sh b/tools/build-iso.sh new file mode 100755 index 00000000..3686b8f7 --- /dev/null +++ b/tools/build-iso.sh @@ -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 \ No newline at end of file diff --git a/tools/build.sh b/tools/build.sh new file mode 100755 index 00000000..97e86c7a --- /dev/null +++ b/tools/build.sh @@ -0,0 +1,10 @@ +#!/bin/sh +set -e + +source $(dirname $0)/env.sh + +cd $LUNA_ROOT + +tools/setup.sh + +make -j$(nproc) \ No newline at end of file diff --git a/tools/clean.sh b/tools/clean.sh new file mode 100755 index 00000000..c7e348ed --- /dev/null +++ b/tools/clean.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +source $(dirname $0)/env.sh + +cd $LUNA_ROOT + +make clean \ No newline at end of file diff --git a/tools/debug.sh b/tools/debug.sh new file mode 100755 index 00000000..d05795a6 --- /dev/null +++ b/tools/debug.sh @@ -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 \ No newline at end of file diff --git a/tools/env.sh b/tools/env.sh new file mode 100755 index 00000000..879ab559 --- /dev/null +++ b/tools/env.sh @@ -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 \ No newline at end of file diff --git a/tools/install.sh b/tools/install.sh new file mode 100755 index 00000000..104badcb --- /dev/null +++ b/tools/install.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +source $(dirname $0)/env.sh + +cd $LUNA_ROOT + +make install \ No newline at end of file diff --git a/tools/run.sh b/tools/run.sh new file mode 100755 index 00000000..1c87ea26 --- /dev/null +++ b/tools/run.sh @@ -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 \ No newline at end of file diff --git a/tools/setup-binutils.sh b/tools/setup-binutils.sh new file mode 100755 index 00000000..5ff288cc --- /dev/null +++ b/tools/setup-binutils.sh @@ -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 \ No newline at end of file diff --git a/tools/setup-env.sh b/tools/setup-env.sh new file mode 100755 index 00000000..4b38b9be --- /dev/null +++ b/tools/setup-env.sh @@ -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 \ No newline at end of file diff --git a/tools/setup-gcc.sh b/tools/setup-gcc.sh new file mode 100755 index 00000000..f3750b5e --- /dev/null +++ b/tools/setup-gcc.sh @@ -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 \ No newline at end of file diff --git a/tools/setup-mkbootimg.sh b/tools/setup-mkbootimg.sh new file mode 100755 index 00000000..6e72e758 --- /dev/null +++ b/tools/setup-mkbootimg.sh @@ -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 \ No newline at end of file diff --git a/tools/setup.sh b/tools/setup.sh new file mode 100755 index 00000000..13460a7a --- /dev/null +++ b/tools/setup.sh @@ -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 \ No newline at end of file diff --git a/tools/test-binutils.sh b/tools/test-binutils.sh new file mode 100755 index 00000000..c8b52acd --- /dev/null +++ b/tools/test-binutils.sh @@ -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 \ No newline at end of file diff --git a/tools/test-gcc.sh b/tools/test-gcc.sh new file mode 100755 index 00000000..c41aba64 --- /dev/null +++ b/tools/test-gcc.sh @@ -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 \ No newline at end of file