Ready. Set. Go!
This commit is contained in:
commit
1b727a66ea
12
.clang-format
Normal file
12
.clang-format
Normal 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
6
.gitignore
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
Luna.iso
|
||||
toolchain/
|
||||
.vscode/
|
||||
**/*.o
|
||||
initrd/boot/moon.elf
|
||||
kernel/bin/moon.elf
|
7
Makefile
Normal file
7
Makefile
Normal 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
BIN
initrd/boot/font.psf
Normal file
Binary file not shown.
3
initrd/sys/config
Normal file
3
initrd/sys/config
Normal file
@ -0,0 +1,3 @@
|
||||
screen=1024x768
|
||||
kernel=boot/moon.elf
|
||||
serial=1
|
60
kernel/Makefile
Normal file
60
kernel/Makefile
Normal 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 $^ $@
|
35
kernel/include/acpi/RSDT.h
Normal file
35
kernel/include/acpi/RSDT.h
Normal 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
9
kernel/include/assert.h
Normal 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
162
kernel/include/bootboot.h
Normal 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
12
kernel/include/cpu/CPU.h
Normal 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);
|
||||
}
|
72
kernel/include/cpu/Features.h
Normal file
72
kernel/include/cpu/Features.h
Normal 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
31
kernel/include/debug.h
Normal 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;
|
||||
};
|
||||
}
|
34
kernel/include/fs/ext2/Superblock.h
Normal file
34
kernel/include/fs/ext2/Superblock.h
Normal 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
6
kernel/include/gdt/GDT.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
namespace GDT
|
||||
{
|
||||
void load();
|
||||
}
|
8
kernel/include/init/Init.h
Normal file
8
kernel/include/init/Init.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
namespace Init
|
||||
{
|
||||
void check_magic();
|
||||
void disable_smp();
|
||||
void early_init();
|
||||
}
|
44
kernel/include/init/InitRD.h
Normal file
44
kernel/include/init/InitRD.h
Normal 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));
|
||||
}
|
12
kernel/include/interrupts/IDT.h
Normal file
12
kernel/include/interrupts/IDT.h
Normal 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();
|
||||
}
|
7
kernel/include/interrupts/IRQ.h
Normal file
7
kernel/include/interrupts/IRQ.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include "SavedContext.h"
|
||||
|
||||
namespace IRQ
|
||||
{
|
||||
void interrupt_handler(SavedContext* context);
|
||||
}
|
7
kernel/include/interrupts/Install.h
Normal file
7
kernel/include/interrupts/Install.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
namespace Interrupts
|
||||
{
|
||||
void install();
|
||||
}
|
7
kernel/include/interrupts/Interrupts.h
Normal file
7
kernel/include/interrupts/Interrupts.h
Normal file
@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
namespace Interrupts
|
||||
{
|
||||
void enable();
|
||||
void disable();
|
||||
}
|
15
kernel/include/interrupts/SavedContext.h
Normal file
15
kernel/include/interrupts/SavedContext.h
Normal 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
13
kernel/include/io/IO.h
Normal 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
12
kernel/include/io/PIC.h
Normal 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);
|
||||
}
|
13
kernel/include/io/Serial.h
Normal file
13
kernel/include/io/Serial.h
Normal 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
23
kernel/include/log/Log.h
Normal 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)
|
11
kernel/include/memory/KernelHeap.h
Normal file
11
kernel/include/memory/KernelHeap.h
Normal 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);
|
||||
}
|
25
kernel/include/memory/Paging.h
Normal file
25
kernel/include/memory/Paging.h
Normal 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)));
|
||||
}
|
17
kernel/include/memory/VMM.h
Normal file
17
kernel/include/memory/VMM.h
Normal 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;
|
||||
};
|
||||
}
|
4
kernel/include/panic/hang.h
Normal file
4
kernel/include/panic/hang.h
Normal file
@ -0,0 +1,4 @@
|
||||
#pragma once
|
||||
|
||||
void hang();
|
||||
void halt();
|
17
kernel/include/psf2.h
Normal file
17
kernel/include/psf2.h
Normal 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;
|
13
kernel/include/render/BBRenderer.h
Normal file
13
kernel/include/render/BBRenderer.h
Normal 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;
|
||||
};
|
13
kernel/include/render/BaseRenderer.h
Normal file
13
kernel/include/render/BaseRenderer.h
Normal 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);
|
||||
};
|
20
kernel/include/render/Color.h
Normal file
20
kernel/include/render/Color.h
Normal 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)
|
8
kernel/include/render/Draw.h
Normal file
8
kernel/include/render/Draw.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
#include "render/BaseRenderer.h"
|
||||
|
||||
namespace Draw
|
||||
{
|
||||
bool try_initialize();
|
||||
BaseRenderer* renderer();
|
||||
}
|
13
kernel/include/render/TextRenderer.h
Normal file
13
kernel/include/render/TextRenderer.h
Normal 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();
|
||||
}
|
11
kernel/include/scheduling/PIT.h
Normal file
11
kernel/include/scheduling/PIT.h
Normal 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();
|
||||
}
|
10
kernel/include/std/stdio.h
Normal file
10
kernel/include/std/stdio.h
Normal 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);
|
7
kernel/include/std/stdlib.h
Normal file
7
kernel/include/std/stdlib.h
Normal 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);
|
17
kernel/include/std/string.h
Normal file
17
kernel/include/std/string.h
Normal 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
4
kernel/include/utils.h
Normal 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
31
kernel/moon.ld
Normal 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
40
kernel/src/acpi/RSDT.cpp
Normal 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
10
kernel/src/assert.cpp
Normal 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
82
kernel/src/cpu/CPU.cpp
Normal 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
61
kernel/src/debug.cpp
Normal 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
16
kernel/src/gdt/GDT.asm
Normal 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
43
kernel/src/gdt/GDT.cpp
Normal 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
32
kernel/src/init/Init.cpp
Normal 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());
|
||||
}
|
81
kernel/src/init/InitRD.cpp
Normal file
81
kernel/src/init/InitRD.cpp
Normal 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);
|
||||
}
|
||||
}
|
19
kernel/src/interrupts/Entry.cpp
Normal file
19
kernel/src/interrupts/Entry.cpp
Normal 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;
|
||||
}
|
57
kernel/src/interrupts/IDT.cpp
Normal file
57
kernel/src/interrupts/IDT.cpp
Normal 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));
|
||||
}
|
26
kernel/src/interrupts/IRQ.cpp
Normal file
26
kernel/src/interrupts/IRQ.cpp
Normal 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;
|
||||
}
|
106
kernel/src/interrupts/Install.cpp
Normal file
106
kernel/src/interrupts/Install.cpp
Normal 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); }
|
||||
}
|
136
kernel/src/interrupts/InterruptEntry.asm
Normal file
136
kernel/src/interrupts/InterruptEntry.asm
Normal 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
|
11
kernel/src/interrupts/Interrupts.cpp
Normal file
11
kernel/src/interrupts/Interrupts.cpp
Normal 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
42
kernel/src/io/IO.cpp
Normal 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
74
kernel/src/io/PIC.cpp
Normal 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
49
kernel/src/io/Serial.cpp
Normal 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
24
kernel/src/log/Log.cpp
Normal 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
136
kernel/src/main.cpp
Normal 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;
|
||||
}
|
79
kernel/src/memory/KernelHeap.cpp
Normal file
79
kernel/src/memory/KernelHeap.cpp
Normal 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
57
kernel/src/memory/VMM.cpp
Normal 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
14
kernel/src/panic/hang.cpp
Normal file
@ -0,0 +1,14 @@
|
||||
#include "panic/hang.h"
|
||||
|
||||
void hang()
|
||||
{
|
||||
asm volatile("cli");
|
||||
end:
|
||||
halt();
|
||||
goto end;
|
||||
}
|
||||
|
||||
void halt()
|
||||
{
|
||||
asm volatile("hlt");
|
||||
}
|
48
kernel/src/render/BBRenderer.cpp
Normal file
48
kernel/src/render/BBRenderer.cpp
Normal 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]); }
|
||||
}
|
||||
}
|
33
kernel/src/render/BaseRenderer.cpp
Normal file
33
kernel/src/render/BaseRenderer.cpp
Normal 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;
|
||||
}
|
11
kernel/src/render/Color.cpp
Normal file
11
kernel/src/render/Color.cpp
Normal 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};
|
20
kernel/src/render/Draw.cpp
Normal file
20
kernel/src/render/Draw.cpp
Normal 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;
|
||||
}
|
107
kernel/src/render/TextRenderer.cpp
Normal file
107
kernel/src/render/TextRenderer.cpp
Normal 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]); }
|
||||
}
|
26
kernel/src/scheduling/PIT.cpp
Normal file
26
kernel/src/scheduling/PIT.cpp
Normal 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
185
kernel/src/std/stdio.cpp
Normal 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
94
kernel/src/std/stdlib.cpp
Normal 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
104
kernel/src/std/string.cpp
Normal 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
18
luna.json
Normal 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
13
tools/build-iso.sh
Executable 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
10
tools/build.sh
Executable 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
8
tools/clean.sh
Executable 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
8
tools/debug.sh
Executable 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
3
tools/env.sh
Executable 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
8
tools/install.sh
Executable 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
8
tools/run.sh
Executable 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
34
tools/setup-binutils.sh
Executable 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
8
tools/setup-env.sh
Executable 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
42
tools/setup-gcc.sh
Executable 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
19
tools/setup-mkbootimg.sh
Executable 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
20
tools/setup.sh
Executable 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
15
tools/test-binutils.sh
Executable 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
15
tools/test-gcc.sh
Executable 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
|
Loading…
Reference in New Issue
Block a user