Merge remote-tracking branch 'Kernel/memory-test' into Kernel-memory-test

This commit is contained in:
EnderIce2
2024-11-20 05:16:21 +02:00
189 changed files with 37283 additions and 0 deletions

73
Kernel/include/abi.h Normal file
View File

@ -0,0 +1,73 @@
#ifndef __FENNIX_KERNEL_ABI_H__
#define __FENNIX_KERNEL_ABI_H__
#include <types.h>
#define AT_NULL 0
#define AT_IGNORE 1
#define AT_EXECFD 2
#define AT_PHDR 3
#define AT_PHENT 4
#define AT_PHNUM 5
#define AT_PAGESZ 6
#define AT_BASE 7
#define AT_FLAGS 8
#define AT_ENTRY 9
#define AT_NOTELF 10
#define AT_UID 11
#define AT_EUID 12
#define AT_GID 13
#define AT_EGID 14
#define AT_PLATFORM 15
#define AT_HWCAP 16
#define AT_CLKTCK 17
#define AT_SECURE 23
#define AT_BASE_PLATFORM 24
#define AT_RANDOM 25
#define AT_HWCAP2 26
#define AT_EXECFN 31
#define AT_SYSINFO 32
#define AT_SYSINFO_EHDR 33
#define AT_L1I_CACHESHAPE 34
#define AT_L1D_CACHESHAPE 35
#define AT_L2_CACHESHAPE 36
#define AT_L3_CACHESHAPE 37
#define AT_L1I_CACHESIZE 40
#define AT_L1I_CACHEGEOMETRY 41
#define AT_L1D_CACHESIZE 42
#define AT_L1D_CACHEGEOMETRY 43
#define AT_L2_CACHESIZE 44
#define AT_L2_CACHEGEOMETRY 45
#define AT_L3_CACHESIZE 46
#define AT_L3_CACHEGEOMETRY 47
#define AT_MINSIGSTKSZ 51
typedef struct
{
uint32_t a_type;
union
{
uint32_t a_val;
} a_un;
} Elf32_auxv_t;
typedef struct
{
uint64_t a_type;
union
{
uint64_t a_val;
} a_un;
} Elf64_auxv_t;
typedef struct
{
#if defined(__amd64__)
Elf64_auxv_t archaux;
#elif defined(__i386__)
Elf32_auxv_t archaux;
#elif defined(__aarch64__)
#endif
} AuxiliaryVector;
#endif // !__FENNIX_KERNEL_ABI_H__

35
Kernel/include/assert.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef __FENNIX_KERNEL_ASSERT_H__
#define __FENNIX_KERNEL_ASSERT_H__
#include <types.h>
#include <debug.h>
#define assert(x) \
do \
{ \
if (!(x)) \
{ \
void *CallerAddress = __builtin_extract_return_addr(__builtin_return_address(0)); \
error("Assertion failed! [%s] [%#lx => %s:%s:%d]", #x, CallerAddress, __FILE__, __FUNCTION__, __LINE__); \
while (1) \
; \
} \
} while (0)
#define assert_allow_continue(x) \
do \
{ \
if (!(x)) \
{ \
void *CallerAddress = __builtin_extract_return_addr(__builtin_return_address(0)); \
error("Assertion failed! [%s] [%#lx => %s:%s:%d]", #x, CallerAddress, __FILE__, __FUNCTION__, __LINE__); \
} \
} while (0)
#define static_assert(x) \
switch (x) \
case 0: \
case (x):
#endif // !__FENNIX_KERNEL_ASSERT_H__

125
Kernel/include/atomic.hpp Normal file
View File

@ -0,0 +1,125 @@
#ifndef __FENNIX_KERNEL_ATOMIC_H__
#define __FENNIX_KERNEL_ATOMIC_H__
#define _Atomic(T) T
#define builtin_atomic(name) __atomic_##name##_n
namespace
{
enum MemoryBorder
{
Relaxed = __ATOMIC_RELAXED,
Acquire = __ATOMIC_ACQUIRE,
Release = __ATOMIC_RELEASE,
AcqRel = __ATOMIC_ACQ_REL,
SeqCst = __ATOMIC_SEQ_CST
};
template <typename T>
class Atomic
{
_Atomic(T) Value;
public:
Atomic(T Init) : Value(Init) {}
T Load(MemoryBorder Order = MemoryBorder::SeqCst)
{
return builtin_atomic(load)(&Value, Order);
}
void Store(T v, MemoryBorder Order = MemoryBorder::SeqCst)
{
return builtin_atomic(store)(&Value, v, Order);
}
T Exchange(T v, MemoryBorder Order = MemoryBorder::SeqCst)
{
return builtin_atomic(exchange)(&Value, v, Order);
}
bool CompareExchange(T &Expected, T Desired, MemoryBorder Order = MemoryBorder::SeqCst)
{
return builtin_atomic(compare_exchange)(&Value, &Expected, Desired, true, Order, Order);
}
T FetchAdd(T v, MemoryBorder Order = MemoryBorder::SeqCst)
{
return builtin_atomic(fetch_add)(&Value, v, Order);
}
T FetchSub(T v, MemoryBorder Order = MemoryBorder::SeqCst)
{
return builtin_atomic(fetch_sub)(&Value, v, Order);
}
T FetchAnd(T v, MemoryBorder Order = MemoryBorder::SeqCst)
{
return builtin_atomic(fetch_and)(&Value, v, Order);
}
T FetchOr(T v, MemoryBorder Order = MemoryBorder::SeqCst)
{
return builtin_atomic(fetch_or)(&Value, v, Order);
}
T FetchXor(T v, MemoryBorder Order = MemoryBorder::SeqCst)
{
return builtin_atomic(fetch_xor)(&Value, v, Order);
}
T operator++()
{
return FetchAdd(1) + 1;
}
T operator++(int)
{
return FetchAdd(1);
}
T operator--()
{
return FetchSub(1) - 1;
}
T operator--(int)
{
return FetchSub(1);
}
T operator+=(T v)
{
return FetchAdd(v) + v;
}
T operator-=(T v)
{
return FetchSub(v) - v;
}
T operator&=(T v)
{
return FetchAnd(v) & v;
}
T operator|=(T v)
{
return FetchOr(v) | v;
}
T operator^=(T v)
{
return FetchXor(v) ^ v;
}
T operator=(T v)
{
Store(v);
return v;
}
};
}
#undef builtin_atomic
#endif // !__FENNIX_KERNEL_ATOMIC_H__

12
Kernel/include/bitmap.hpp Normal file
View File

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

121
Kernel/include/boot/binfo.h Normal file
View File

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

View File

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

187
Kernel/include/cargs.h Normal file
View File

@ -0,0 +1,187 @@
/*
MIT License
Copyright (c) 2022 Leonard Iklé
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.
*/
#pragma once
/**
* This is a simple alternative cross-platform implementation of getopt, which
* is used to parse argument strings submitted to the executable (argc and argv
* which are received in the main function).
*/
#ifndef CAG_LIBRARY_H
#define CAG_LIBRARY_H
#include <types.h>
typedef unsigned int FILE; // TODO: Implement FILE
#if defined(_WIN32) || defined(__CYGWIN__)
#define CAG_EXPORT __declspec(dllexport)
#define CAG_IMPORT __declspec(dllimport)
#elif __GNUC__ >= 4
#define CAG_EXPORT __attribute__((visibility("default")))
#define CAG_IMPORT __attribute__((visibility("default")))
#else
#define CAG_EXPORT
#define CAG_IMPORT
#endif
#if defined(CAG_SHARED)
#if defined(CAG_EXPORTS)
#define CAG_PUBLIC CAG_EXPORT
#else
#define CAG_PUBLIC CAG_IMPORT
#endif
#else
#define CAG_PUBLIC
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/**
* An option is used to describe a flag/argument option submitted when the
* program is run.
*/
typedef struct cag_option
{
const char identifier;
const char *access_letters;
const char *access_name;
const char *value_name;
const char *description;
} cag_option;
/**
* A context is used to iterate over all options provided. It stores the parsing
* state.
*/
typedef struct cag_option_context
{
const struct cag_option *options;
size_t option_count;
int argc;
char **argv;
int index;
int inner_index;
bool forced_end;
char identifier;
char *value;
} cag_option_context;
/**
* This is just a small macro which calculates the size of an array.
*/
#define CAG_ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
/**
* @brief Prints all options to the terminal.
*
* This function prints all options to the terminal. This can be used to
* generate the output for a "--help" option.
*
* @param options The options which will be printed.
* @param option_count The option count which will be printed.
* @param destination The destination where the output will be printed.
*/
CAG_PUBLIC void cag_option_print(const cag_option *options, size_t option_count,
FILE *destination);
/**
* @brief Prepare argument options context for parsing.
*
* This function prepares the context for iteration and initializes the context
* with the supplied options and arguments. After the context has been prepared,
* it can be used to fetch arguments from it.
*
* @param context The context which will be initialized.
* @param options The registered options which are available for the program.
* @param option_count The amount of options which are available for the
* program.
* @param argc The amount of arguments the user supplied in the main function.
* @param argv A pointer to the arguments of the main function.
*/
CAG_PUBLIC void cag_option_prepare(cag_option_context *context,
const cag_option *options, size_t option_count, int argc, char **argv);
/**
* @brief Fetches an option from the argument list.
*
* This function fetches a single option from the argument list. The context
* will be moved to that item. Information can be extracted from the context
* after the item has been fetched.
* The arguments will be re-ordered, which means that non-option arguments will
* be moved to the end of the argument list. After all options have been
* fetched, all non-option arguments will be positioned after the index of
* the context.
*
* @param context The context from which we will fetch the option.
* @return Returns true if there was another option or false if the end is
* reached.
*/
CAG_PUBLIC bool cag_option_fetch(cag_option_context *context);
/**
* @brief Gets the identifier of the option.
*
* This function gets the identifier of the option, which should be unique to
* this option and can be used to determine what kind of option this is.
*
* @param context The context from which the option was fetched.
* @return Returns the identifier of the option.
*/
CAG_PUBLIC char cag_option_get(const cag_option_context *context);
/**
* @brief Gets the value from the option.
*
* This function gets the value from the option, if any. If the option does not
* contain a value, this function will return NULL.
*
* @param context The context from which the option was fetched.
* @return Returns a pointer to the value or NULL if there is no value.
*/
CAG_PUBLIC const char *cag_option_get_value(const cag_option_context *context);
/**
* @brief Gets the current index of the context.
*
* This function gets the index within the argv arguments of the context. The
* context always points to the next item which it will inspect. This is
* particularly useful to inspect the original argument array, or to get
* non-option arguments after option fetching has finished.
*
* @param context The context from which the option was fetched.
* @return Returns the current index of the context.
*/
CAG_PUBLIC int cag_option_get_index(const cag_option_context *context);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

75
Kernel/include/convert.h Normal file
View File

@ -0,0 +1,75 @@
#pragma once
#include <types.h>
#ifdef __cplusplus
extern "C"
{
#endif
int isdigit(int c);
int isspace(int c);
int isempty(char *str);
int isalpha(int c);
int isupper(int c);
unsigned int isdelim(char c, char *delim);
int abs(int i);
void swap(char *x, char *y);
char *reverse(char *Buffer, int i, int j);
void backspace(char s[]);
void append(char s[], char n);
int atoi(const char *String);
double atof(const char *String);
char *itoa(int Value, char *Buffer, int Base);
char *ltoa(long Value, char *Buffer, int Base);
char *ultoa(unsigned long Value, char *Buffer, int Base);
void *memcpy_unsafe(void *dest, const void *src, size_t n);
void *memset_unsafe(void *dest, int c, size_t n);
void *memmove_unsafe(void *dest, const void *src, size_t n);
int memcmp(const void *vl, const void *vr, size_t n);
long unsigned strlen(const char s[]);
int strncmp(const char *s1, const char *s2, unsigned long n);
char *strcat_unsafe(char *destination, const char *source);
char *strcpy_unsafe(char *destination, const char *source);
char *strncpy(char *destination, const char *source, unsigned long num);
int strcmp(const char *l, const char *r);
char *strstr(const char *haystack, const char *needle);
char *strdup(const char *String);
char *strchr(const char *String, int Char);
char *strrchr(const char *String, int Char);
int strncasecmp(const char *lhs, const char *rhs, long unsigned int Count);
int strcasecmp(const char *lhs, const char *rhs);
char *strtok(char *src, const char *delim);
long int strtol(const char *str, char **endptr, int base);
void *__memcpy_chk(void *dest, const void *src, size_t len, size_t slen);
void *__memset_chk(void *dest, int val, size_t len, size_t slen);
void *__memmove_chk(void *dest, const void *src, size_t len, size_t slen);
char *__strcat_chk(char *dest, const char *src, size_t slen);
char *__strcpy_chk(char *dest, const char *src, size_t slen);
#ifdef __cplusplus
}
#endif
#undef memcpy
#define memcpy(dest, src, n) \
__memcpy_chk(dest, src, n, __builtin_object_size(dest, 0))
#undef memset
#define memset(dest, c, n) \
__memset_chk(dest, c, n, __builtin_object_size(dest, 0))
#undef memmove
#define memmove(dest, src, n) \
__memmove_chk(dest, src, n, __builtin_object_size(dest, 0))
#undef strcat
#define strcat(dest, src) \
__strcat_chk(dest, src, __builtin_object_size(dest, 0))
#undef strcpy
#define strcpy(dest, src) \
__strcpy_chk(dest, src, __builtin_object_size(dest, 0))

3433
Kernel/include/cpu.hpp Normal file

File diff suppressed because it is too large Load Diff

8
Kernel/include/crc32.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef __FENNIX_KERNEL_CRC32_H__
#define __FENNIX_KERNEL_CRC32_H__
#include <types.h>
EXTERNC uint32_t crc32(const uint8_t *Buffer, int Length);
#endif // !__FENNIX_KERNEL_CRC32_H__

2
Kernel/include/cstring Normal file
View File

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

521
Kernel/include/cwalk.h Normal file
View File

@ -0,0 +1,521 @@
/*
MIT License
Copyright (c) 2020 Leonard Iklé
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.
*/
#pragma once
#ifndef CWK_LIBRARY_H
#define CWK_LIBRARY_H
#include <types.h>
#if defined(_WIN32) || defined(__CYGWIN__)
#define CWK_EXPORT __declspec(dllexport)
#define CWK_IMPORT __declspec(dllimport)
#elif __GNUC__ >= 4
#define CWK_EXPORT __attribute__((visibility("default")))
#define CWK_IMPORT __attribute__((visibility("default")))
#else
#define CWK_EXPORT
#define CWK_IMPORT
#endif
#if defined(CWK_SHARED)
#if defined(CWK_EXPORTS)
#define CWK_PUBLIC CWK_EXPORT
#else
#define CWK_PUBLIC CWK_IMPORT
#endif
#else
#define CWK_PUBLIC
#endif
#ifdef __cplusplus
extern "C"
{
#endif
/**
* A segment represents a single component of a path. For instance, on linux a
* path might look like this "/var/log/", which consists of two segments "var"
* and "log".
*/
struct cwk_segment
{
const char *path;
const char *segments;
const char *begin;
const char *end;
size_t size;
};
/**
* The segment type can be used to identify whether a segment is a special
* segment or not.
*
* CWK_NORMAL - normal folder or file segment
* CWK_CURRENT - "./" current folder segment
* CWK_BACK - "../" relative back navigation segment
*/
enum cwk_segment_type
{
CWK_NORMAL,
CWK_CURRENT,
CWK_BACK
};
/**
* @brief Determines the style which is used for the path parsing and
* generation.
*/
enum cwk_path_style
{
CWK_STYLE_WINDOWS,
CWK_STYLE_UNIX
};
/**
* @brief Generates an absolute path based on a base.
*
* This function generates an absolute path based on a base path and another
* path. It is guaranteed to return an absolute path. If the second submitted
* path is absolute, it will override the base path. The result will be
* written to a buffer, which might be truncated if the buffer is not large
* enough to hold the full path. However, the truncated result will always be
* null-terminated. The returned value is the amount of characters which the
* resulting path would take if it was not truncated (excluding the
* null-terminating character).
*
* @param base The absolute base path on which the relative path will be
* applied.
* @param path The relative path which will be applied on the base path.
* @param buffer The buffer where the result will be written to.
* @param buffer_size The size of the result buffer.
* @return Returns the total amount of characters of the new absolute path.
*/
CWK_PUBLIC size_t cwk_path_get_absolute(const char *base, const char *path,
char *buffer, size_t buffer_size);
/**
* @brief Generates a relative path based on a base.
*
* This function generates a relative path based on a base path and another
* path. It determines how to get to the submitted path, starting from the
* base directory. The result will be written to a buffer, which might be
* truncated if the buffer is not large enough to hold the full path. However,
* the truncated result will always be null-terminated. The returned value is
* the amount of characters which the resulting path would take if it was not
* truncated (excluding the null-terminating character).
*
* @param base_directory The base path from which the relative path will
* start.
* @param path The target path where the relative path will point to.
* @param buffer The buffer where the result will be written to.
* @param buffer_size The size of the result buffer.
* @return Returns the total amount of characters of the full path.
*/
CWK_PUBLIC size_t cwk_path_get_relative(const char *base_directory,
const char *path, char *buffer, size_t buffer_size);
/**
* @brief Joins two paths together.
*
* This function generates a new path by combining the two submitted paths. It
* will remove double separators, and unlike cwk_path_get_absolute it permits
* the use of two relative paths to combine. The result will be written to a
* buffer, which might be truncated if the buffer is not large enough to hold
* the full path. However, the truncated result will always be
* null-terminated. The returned value is the amount of characters which the
* resulting path would take if it was not truncated (excluding the
* null-terminating character).
*
* @param path_a The first path which comes first.
* @param path_b The second path which comes after the first.
* @param buffer The buffer where the result will be written to.
* @param buffer_size The size of the result buffer.
* @return Returns the total amount of characters of the full, combined path.
*/
CWK_PUBLIC size_t cwk_path_join(const char *path_a, const char *path_b,
char *buffer, size_t buffer_size);
/**
* @brief Joins multiple paths together.
*
* This function generates a new path by joining multiple paths together. It
* will remove double separators, and unlike cwk_path_get_absolute it permits
* the use of multiple relative paths to combine. The last path of the
* submitted string array must be set to NULL. The result will be written to a
* buffer, which might be truncated if the buffer is not large enough to hold
* the full path. However, the truncated result will always be
* null-terminated. The returned value is the amount of characters which the
* resulting path would take if it was not truncated (excluding the
* null-terminating character).
*
* @param paths An array of paths which will be joined.
* @param buffer The buffer where the result will be written to.
* @param buffer_size The size of the result buffer.
* @return Returns the total amount of characters of the full, combined path.
*/
CWK_PUBLIC size_t cwk_path_join_multiple(const char **paths, char *buffer,
size_t buffer_size);
/**
* @brief Determines the root of a path.
*
* This function determines the root of a path by finding its length. The
* root always starts at the submitted path. If the path has no root, the
* length will be set to zero.
*
* @param path The path which will be inspected.
* @param length The output of the root length.
*/
CWK_PUBLIC void cwk_path_get_root(const char *path, size_t *length);
/**
* @brief Changes the root of a path.
*
* This function changes the root of a path. It does not normalize the result.
* The result will be written to a buffer, which might be truncated if the
* buffer is not large enough to hold the full path. However, the truncated
* result will always be null-terminated. The returned value is the amount of
* characters which the resulting path would take if it was not truncated
* (excluding the null-terminating character).
*
* @param path The original path which will get a new root.
* @param new_root The new root which will be placed in the path.
* @param buffer The output buffer where the result is written to.
* @param buffer_size The size of the output buffer where the result is
* written to.
* @return Returns the total amount of characters of the new path.
*/
CWK_PUBLIC size_t cwk_path_change_root(const char *path, const char *new_root,
char *buffer, size_t buffer_size);
/**
* @brief Determine whether the path is absolute or not.
*
* This function checks whether the path is an absolute path or not. A path is
* considered to be absolute if the root ends with a separator.
*
* @param path The path which will be checked.
* @return Returns true if the path is absolute or false otherwise.
*/
CWK_PUBLIC bool cwk_path_is_absolute(const char *path);
/**
* @brief Determine whether the path is relative or not.
*
* This function checks whether the path is a relative path or not. A path is
* considered to be relative if the root does not end with a separator.
*
* @param path The path which will be checked.
* @return Returns true if the path is relative or false otherwise.
*/
CWK_PUBLIC bool cwk_path_is_relative(const char *path);
/**
* @brief Gets the basename of a file path.
*
* This function gets the basename of a file path. A pointer to the beginning
* of the basename will be returned through the basename parameter. This
* pointer will be positioned on the first letter after the separator. The
* length of the file path will be returned through the length parameter. The
* length will be set to zero and the basename to NULL if there is no basename
* available.
*
* @param path The path which will be inspected.
* @param basename The output of the basename pointer.
* @param length The output of the length of the basename. This may be
* null if not required.
*/
CWK_PUBLIC void cwk_path_get_basename(const char *path, const char **basename,
size_t *length);
/**
* @brief Changes the basename of a file path.
*
* This function changes the basename of a file path. This function will not
* write out more than the specified buffer can contain. However, the
* generated string is always null-terminated - even if not the whole path is
* written out. The function returns the total number of characters the
* complete buffer would have, even if it was not written out completely. The
* path may be the same memory address as the buffer.
*
* @param path The original path which will be used for the modified path.
* @param new_basename The new basename which will replace the old one.
* @param buffer The buffer where the changed path will be written to.
* @param buffer_size The size of the result buffer where the changed path is
* written to.
* @return Returns the size which the complete new path would have if it was
* not truncated.
*/
CWK_PUBLIC size_t cwk_path_change_basename(const char *path,
const char *new_basename, char *buffer, size_t buffer_size);
/**
* @brief Gets the dirname of a file path.
*
* This function determines the dirname of a file path and returns the length
* up to which character is considered to be part of it. If no dirname is
* found, the length will be set to zero. The beginning of the dirname is
* always equal to the submitted path pointer.
*
* @param path The path which will be inspected.
* @param length The length of the dirname.
*/
CWK_PUBLIC void cwk_path_get_dirname(const char *path, size_t *length);
/**
* @brief Gets the extension of a file path.
*
* This function extracts the extension portion of a file path. A pointer to
* the beginning of the extension will be returned through the extension
* parameter if an extension is found and true is returned. This pointer will
* be positioned on the dot. The length of the extension name will be returned
* through the length parameter. If no extension is found both parameters
* won't be touched and false will be returned.
*
* @param path The path which will be inspected.
* @param extension The output of the extension pointer.
* @param length The output of the length of the extension.
* @return Returns true if an extension is found or false otherwise.
*/
CWK_PUBLIC bool cwk_path_get_extension(const char *path, const char **extension,
size_t *length);
/**
* @brief Determines whether the file path has an extension.
*
* This function determines whether the submitted file path has an extension.
* This will evaluate to true if the last segment of the path contains a dot.
*
* @param path The path which will be inspected.
* @return Returns true if the path has an extension or false otherwise.
*/
CWK_PUBLIC bool cwk_path_has_extension(const char *path);
/**
* @brief Changes the extension of a file path.
*
* This function changes the extension of a file name. The function will
* append an extension if the basename does not have an extension, or use the
* extension as a basename if the path does not have a basename. This function
* will not write out more than the specified buffer can contain. However, the
* generated string is always null-terminated - even if not the whole path is
* written out. The function returns the total number of characters the
* complete buffer would have, even if it was not written out completely. The
* path may be the same memory address as the buffer.
*
* @param path The path which will be used to make the change.
* @param new_extension The extension which will be placed within the new
* path.
* @param buffer The output buffer where the result will be written to.
* @param buffer_size The size of the output buffer where the result will be
* written to.
* @return Returns the total size which the output would have if it was not
* truncated.
*/
CWK_PUBLIC size_t cwk_path_change_extension(const char *path,
const char *new_extension, char *buffer, size_t buffer_size);
/**
* @brief Creates a normalized version of the path.
*
* This function creates a normalized version of the path within the specified
* buffer. This function will not write out more than the specified buffer can
* contain. However, the generated string is always null-terminated - even if
* not the whole path is written out. The function returns the total number of
* characters the complete buffer would have, even if it was not written out
* completely. The path may be the same memory address as the buffer.
*
* The following will be true for the normalized path:
* 1) "../" will be resolved.
* 2) "./" will be removed.
* 3) double separators will be fixed with a single separator.
* 4) separator suffixes will be removed.
*
* @param path The path which will be normalized.
* @param buffer The buffer where the new path is written to.
* @param buffer_size The size of the buffer.
* @return The size which the complete normalized path has if it was not
* truncated.
*/
CWK_PUBLIC size_t cwk_path_normalize(const char *path, char *buffer,
size_t buffer_size);
/**
* @brief Finds common portions in two paths.
*
* This function finds common portions in two paths and returns the number
* characters from the beginning of the base path which are equal to the other
* path.
*
* @param path_base The base path which will be compared with the other path.
* @param path_other The other path which will compared with the base path.
* @return Returns the number of characters which are common in the base path.
*/
CWK_PUBLIC size_t cwk_path_get_intersection(const char *path_base,
const char *path_other);
/**
* @brief Gets the first segment of a path.
*
* This function finds the first segment of a path. The position of the
* segment is set to the first character after the separator, and the length
* counts all characters until the next separator (excluding the separator).
*
* @param path The path which will be inspected.
* @param segment The segment which will be extracted.
* @return Returns true if there is a segment or false if there is none.
*/
CWK_PUBLIC bool cwk_path_get_first_segment(const char *path,
struct cwk_segment *segment);
/**
* @brief Gets the last segment of the path.
*
* This function gets the last segment of a path. This function may return
* false if the path doesn't contain any segments, in which case the submitted
* segment parameter is not modified. The position of the segment is set to
* the first character after the separator, and the length counts all
* characters until the end of the path (excluding the separator).
*
* @param path The path which will be inspected.
* @param segment The segment which will be extracted.
* @return Returns true if there is a segment or false if there is none.
*/
CWK_PUBLIC bool cwk_path_get_last_segment(const char *path,
struct cwk_segment *segment);
/**
* @brief Advances to the next segment.
*
* This function advances the current segment to the next segment. If there
* are no more segments left, the submitted segment structure will stay
* unchanged and false is returned.
*
* @param segment The current segment which will be advanced to the next one.
* @return Returns true if another segment was found or false otherwise.
*/
CWK_PUBLIC bool cwk_path_get_next_segment(struct cwk_segment *segment);
/**
* @brief Moves to the previous segment.
*
* This function moves the current segment to the previous segment. If the
* current segment is the first one, the submitted segment structure will stay
* unchanged and false is returned.
*
* @param segment The current segment which will be moved to the previous one.
* @return Returns true if there is a segment before this one or false
* otherwise.
*/
CWK_PUBLIC bool cwk_path_get_previous_segment(struct cwk_segment *segment);
/**
* @brief Gets the type of the submitted path segment.
*
* This function inspects the contents of the segment and determines the type
* of it. Currently, there are three types CWK_NORMAL, CWK_CURRENT and
* CWK_BACK. A CWK_NORMAL segment is a normal folder or file entry. A
* CWK_CURRENT is a "./" and a CWK_BACK a "../" segment.
*
* @param segment The segment which will be inspected.
* @return Returns the type of the segment.
*/
CWK_PUBLIC enum cwk_segment_type cwk_path_get_segment_type(
const struct cwk_segment *segment);
/**
* @brief Changes the content of a segment.
*
* This function overrides the content of a segment to the submitted value and
* outputs the whole new path to the submitted buffer. The result might
* require less or more space than before if the new value length differs from
* the original length. The output is truncated if the new path is larger than
* the submitted buffer size, but it is always null-terminated. The source of
* the segment and the submitted buffer may be the same.
*
* @param segment The segment which will be modifier.
* @param value The new content of the segment.
* @param buffer The buffer where the modified path will be written to.
* @param buffer_size The size of the output buffer.
* @return Returns the total size which would have been written if the output
* was not truncated.
*/
CWK_PUBLIC size_t cwk_path_change_segment(struct cwk_segment *segment,
const char *value, char *buffer, size_t buffer_size);
/**
* @brief Checks whether the submitted pointer points to a separator.
*
* This function simply checks whether the submitted pointer points to a
* separator, which has to be null-terminated (but not necessarily after the
* separator). The function will return true if it is a separator, or false
* otherwise.
*
* @param symbol A pointer to a string.
* @return Returns true if it is a separator, or false otherwise.
*/
CWK_PUBLIC bool cwk_path_is_separator(const char *str);
/**
* @brief Guesses the path style.
*
* This function guesses the path style based on a submitted path-string. The
* guessing will look at the root and the type of slashes contained in the
* path and return the style which is more likely used in the path.
*
* @param path The path which will be inspected.
* @return Returns the style which is most likely used for the path.
*/
CWK_PUBLIC enum cwk_path_style cwk_path_guess_style(const char *path);
/**
* @brief Configures which path style is used.
*
* This function configures which path style is used. The following styles are
* currently supported.
*
* CWK_STYLE_WINDOWS: Use backslashes as a separator and volume for the root.
* CWK_STYLE_UNIX: Use slashes as a separator and a slash for the root.
*
* @param style The style which will be used from now on.
*/
CWK_PUBLIC void cwk_path_set_style(enum cwk_path_style style);
/**
* @brief Gets the path style configuration.
*
* This function gets the style configuration which is currently used for the
* paths. This configuration determines how paths are parsed and generated.
*
* @return Returns the current path style configuration.
*/
CWK_PUBLIC enum cwk_path_style cwk_path_get_style(void);
#ifdef __cplusplus
} // extern "C"
#endif
#endif

49
Kernel/include/debug.h Normal file
View File

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

137
Kernel/include/disk.hpp Normal file
View File

@ -0,0 +1,137 @@
#ifndef __FENNIX_KERNEL_DISK_H__
#define __FENNIX_KERNEL_DISK_H__
#include <types.h>
#include <vector.hpp>
namespace Disk
{
#define MBR_MAGIC0 0x55
#define MBR_MAGIC1 0xAA
// "EFI PART"
#define GPT_MAGIC 0x5452415020494645ULL
enum PartitionStyle
{
Unknown,
MBR,
GPT
};
enum PartitionFlags
{
Present,
Bootable,
EFISystemPartition
};
struct MasterBootRecordPartition
{
uint8_t Flags;
uint8_t CHSFirst[3];
uint8_t Type;
uint8_t CHSLast[3];
uint32_t LBAFirst;
uint32_t Sectors;
} __attribute__((packed));
struct MasterBootRecord
{
uint8_t Bootstrap[440];
uint32_t UniqueID;
uint16_t Reserved;
MasterBootRecordPartition Partitions[4];
uint8_t Signature[2];
} __attribute__((packed));
struct GUIDPartitionTablePartition
{
uint64_t TypeLow;
uint64_t TypeHigh;
uint64_t GUIDLow;
uint64_t GUIDHigh;
uint64_t StartLBA;
uint64_t EndLBA;
uint64_t Attributes;
char Label[72];
} __attribute__((packed));
struct GUIDPartitionTable
{
uint64_t Signature;
uint32_t Revision;
uint32_t HdrSize;
uint32_t HdrCRC32;
uint32_t Reserved;
uint64_t LBA;
uint64_t ALTLBA;
uint64_t FirstBlock;
uint64_t LastBlock;
uint64_t GUIDLow;
uint64_t GUIDHigh;
uint64_t PartLBA;
uint32_t PartCount;
uint32_t EntrySize;
uint32_t PartCRC32;
} __attribute__((packed));
struct PartitionTable
{
MasterBootRecord MBR;
GUIDPartitionTable GPT;
};
class Partition
{
public:
char Label[72] = "Unidentified Partition";
uint64_t StartLBA = 0xdeadbeef;
uint64_t EndLBA = 0xdeadbeef;
uint64_t Sectors = 0xdeadbeef;
uint64_t Flags = 0xdeadbeef;
unsigned char Port = 0;
PartitionStyle Style = PartitionStyle::Unknown;
size_t Index = 0;
uint64_t Read(uint64_t Offset, uint64_t Count, uint8_t *Buffer) { return 0; }
uint64_t Write(uint64_t Offset, uint64_t Count, uint8_t *Buffer) { return 0; }
Partition() {}
~Partition() {}
};
class Drive
{
public:
char Name[64] = "Unidentified Drive";
uint8_t *Buffer = nullptr;
PartitionTable Table;
PartitionStyle Style = PartitionStyle::Unknown;
Vector<Partition *> Partitions;
bool MechanicalDisk = false;
uint64_t UniqueIdentifier = 0xdeadbeef;
uint64_t Read(uint64_t Offset, uint64_t Count, uint8_t *Buffer) { return 0; }
uint64_t Write(uint64_t Offset, uint64_t Count, uint8_t *Buffer) { return 0; }
Drive()
{ // TODO: Allocate buffer
}
~Drive() {}
};
class Manager
{
private:
unsigned char AvailablePorts = 0;
int BytesPerSector = 0;
Vector<Drive *> drives;
public:
void FetchDisks(unsigned long DriverUID);
Manager();
~Manager();
};
}
#endif // !__FENNIX_KERNEL_DISK_H__

201
Kernel/include/display.hpp Normal file
View File

@ -0,0 +1,201 @@
#ifndef __FENNIX_KERNEL_DISPLAY_H__
#define __FENNIX_KERNEL_DISPLAY_H__
#include <types.h>
#include <boot/binfo.h>
#include <memory.hpp>
#include <debug.h>
#include <cstring>
namespace Video
{
#define PSF1_MAGIC0 0x36
#define PSF1_MAGIC1 0x04
#define PSF2_MAGIC0 0x72
#define PSF2_MAGIC1 0xb5
#define PSF2_MAGIC2 0x4a
#define PSF2_MAGIC3 0x86
struct PSF1_HEADER
{
uint8_t magic[2];
uint8_t mode;
uint8_t charsize;
};
struct PSF2_HEADER
{
uint8_t magic[4];
uint32_t version;
uint32_t headersize;
uint32_t flags;
uint32_t length;
uint32_t charsize;
uint32_t height, width;
};
typedef struct _PSF1_FONT
{
PSF1_HEADER *Header;
void *GlyphBuffer;
} PSF1_FONT;
typedef struct _PSF2_FONT
{
PSF2_HEADER *Header;
void *GlyphBuffer;
} PSF2_FONT;
enum FontType
{
None,
PCScreenFont1,
PCScreenFont2
};
struct FontInfo
{
uint64_t *StartAddress;
uint64_t *EndAddress;
PSF1_FONT *PSF1Font;
PSF2_FONT *PSF2Font;
uint32_t Width, Height;
FontType Type;
};
class Font
{
private:
FontInfo Info;
public:
FontInfo GetInfo() { return Info; }
Font(uint64_t *Start, uint64_t *End, FontType Type);
~Font();
};
struct ScreenBuffer
{
void *Buffer = nullptr;
uint32_t Width, Height;
uint64_t Size;
uint32_t Color;
uint32_t CursorX, CursorY;
long Checksum;
};
class Display
{
private:
BootInfo::FramebufferInfo framebuffer;
Font *CurrentFont;
ScreenBuffer *Buffers[256];
bool ColorIteration = false;
int ColorPickerIteration = 0;
public:
Font *GetCurrentFont() { return CurrentFont; }
void SetCurrentFont(Font *Font) { CurrentFont = Font; }
void CreateBuffer(uint32_t Width, uint32_t Height, int Index)
{
if (Width == 0 && Height == 0)
{
Width = this->framebuffer.Width;
Height = this->framebuffer.Height;
debug("No width and height specified, using %ldx%lld", Width, Height);
}
uint64_t Size = this->framebuffer.Pitch * Height;
if (!this->Buffers[Index])
{
if (this->Buffers[Index]->Checksum != 0xDEAD5C9EE7)
{
ScreenBuffer *buffer = new ScreenBuffer;
buffer->Buffer = KernelAllocator.RequestPages(TO_PAGES(Size));
buffer->Width = Width;
buffer->Height = Height;
buffer->Size = Size;
buffer->Color = 0xFFFFFF;
buffer->CursorX = 0;
buffer->CursorY = 0;
this->Buffers[Index] = buffer;
memset(this->Buffers[Index]->Buffer, 0, Size);
this->Buffers[Index]->Checksum = 0xDEAD5C9EE7;
}
else
warn("Buffer %d already exists, skipping creation", Index);
}
else
warn("Buffer %d already exists, skipping creation", Index);
}
void SetBuffer(int Index) { memcpy(this->framebuffer.BaseAddress, this->Buffers[Index]->Buffer, this->Buffers[Index]->Size); }
ScreenBuffer *GetBuffer(int Index) { return this->Buffers[Index]; }
void ClearBuffer(int Index) { memset(this->Buffers[Index]->Buffer, 0, this->Buffers[Index]->Size); }
void DeleteBuffer(int Index)
{
if (this->Buffers[Index] == nullptr)
return;
KernelAllocator.FreePages(this->Buffers[Index]->Buffer, TO_PAGES(this->Buffers[Index]->Size));
this->Buffers[Index]->Checksum = 0; // Making sure that the buffer is not used anymore
delete this->Buffers[Index];
}
void SetBufferCursor(int Index, uint32_t X, uint32_t Y)
{
this->Buffers[Index]->CursorX = X;
this->Buffers[Index]->CursorY = Y;
}
void GetBufferCursor(int Index, uint32_t *X, uint32_t *Y)
{
*X = this->Buffers[Index]->CursorX;
*Y = this->Buffers[Index]->CursorY;
}
void SetPixel(uint32_t X, uint32_t Y, uint32_t Color, int Index)
{
if (X >= this->Buffers[Index]->Width)
X = this->Buffers[Index]->Width - 1;
if (Y >= this->Buffers[Index]->Height)
Y = this->Buffers[Index]->Height - 1;
uint32_t *Pixel = (uint32_t *)((uint64_t)this->Buffers[Index]->Buffer + (Y * this->Buffers[Index]->Width + X) * (this->framebuffer.BitsPerPixel / 8));
*Pixel = Color;
}
uint32_t GetPixel(uint32_t X, uint32_t Y, int Index)
{
if (X >= this->Buffers[Index]->Width || Y >= this->Buffers[Index]->Height)
return 0;
uint32_t *Pixel = (uint32_t *)((uint64_t)this->Buffers[Index]->Buffer + (Y * this->Buffers[Index]->Width + X) * (this->framebuffer.BitsPerPixel / 8));
return *Pixel;
}
void Scroll(int Index, int Lines)
{
if (Lines == 0)
return;
if (Lines > 0)
{
for (uint32_t i = 0; i < this->CurrentFont->GetInfo().Height; i++) // TODO: Make this more efficient.
{
memmove(this->Buffers[Index]->Buffer,
(uint8_t *)this->Buffers[Index]->Buffer + (this->Buffers[Index]->Width * (this->framebuffer.BitsPerPixel / 8) * Lines),
this->Buffers[Index]->Size - (this->Buffers[Index]->Width * (this->framebuffer.BitsPerPixel / 8) * Lines));
memset((uint8_t *)this->Buffers[Index]->Buffer + (this->Buffers[Index]->Size - (this->Buffers[Index]->Width * (this->framebuffer.BitsPerPixel / 8) * Lines)),
0,
this->Buffers[Index]->Width * (this->framebuffer.BitsPerPixel / 8) * Lines);
}
}
}
char Print(char Char, int Index, bool WriteToUART = false);
Display(BootInfo::FramebufferInfo Info, bool LoadDefaultFont = true);
~Display();
};
}
#endif // !__FENNIX_KERNEL_DISPLAY_H__

69
Kernel/include/driver.hpp Normal file
View File

@ -0,0 +1,69 @@
#ifndef __FENNIX_KERNEL_DRIVER_H__
#define __FENNIX_KERNEL_DRIVER_H__
#include <types.h>
#include <interrupts.hpp>
#include <vector.hpp>
#include <debug.h>
#include <cpu.hpp>
namespace Driver
{
enum DriverCode
{
ERROR,
OK,
INVALID_FEX_HEADER,
INVALID_DRIVER_DATA,
NOT_DRIVER,
DRIVER_RETURNED_ERROR,
UNKNOWN_DRIVER_TYPE,
PCI_DEVICE_NOT_FOUND
};
class DriverInterruptHook : public Interrupts::Handler
{
private:
void *Handle;
void *Data;
#if defined(__amd64__)
void OnInterruptReceived(CPU::x64::TrapFrame *Frame);
#elif defined(__i386__)
void OnInterruptReceived(void *Frame);
#elif defined(__aarch64__)
void OnInterruptReceived(void *Frame);
#endif
public:
DriverInterruptHook(int Interrupt, void *Address, void *ParamData);
virtual ~DriverInterruptHook() = default;
};
struct DriverFile
{
unsigned long DriverUID;
void *Address;
DriverInterruptHook *InterruptHook[16];
};
class Driver
{
private:
Vector<DriverFile *> Drivers;
unsigned long DriverUIDs = 0;
DriverCode CallDriverEntryPoint(void *fex);
public:
Vector<DriverFile *> GetDrivers() { return Drivers; }
int IOCB(unsigned long DUID, /* KernelCallback */ void *KCB);
DriverCode LoadDriver(uint64_t DriverAddress, uint64_t Size);
DriverCode StartDrivers();
Driver();
~Driver();
};
}
#endif // !__FENNIX_KERNEL_DRIVER_H__

View File

@ -0,0 +1,8 @@
#ifndef __FENNIX_LIB_DUMPER_H__
#define __FENNIX_LIB_DUMPER_H__
#include <types.h>
void DumpData(const char *Description, void *Address, unsigned long Length);
#endif // !__FENNIX_LIB_DUMPER_H__

339
Kernel/include/elf.h Normal file
View File

@ -0,0 +1,339 @@
#ifndef __FENNIX_KERNEL_ELF_H__
#define __FENNIX_KERNEL_ELF_H__
#include <types.h>
// https://wiki.osdev.org/ELF_Tutorial
// https://github.com/torvalds/linux/blob/master/include/uapi/linux/elf.h
/* 32-bit ELF base types. */
typedef uint32_t Elf32_Addr;
typedef uint64_t Elf32_Half;
typedef uint32_t Elf32_Off;
typedef int32_t Elf32_Sword;
typedef uint32_t Elf32_Word;
/* 64-bit ELF base types. */
typedef uint64_t Elf64_Addr;
typedef uint16_t Elf64_Half;
typedef int16_t Elf64_SHalf;
typedef uint64_t Elf64_Off;
typedef int32_t Elf64_Sword;
typedef uint32_t Elf64_Word;
typedef uint64_t Elf64_Xword;
typedef int64_t Elf64_Sxword;
#define EI_NIDENT 16
typedef struct elf32_hdr
{
unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
Elf32_Half e_type;
Elf32_Half e_machine;
Elf32_Word e_version;
Elf32_Addr e_entry; /* Entry point virtual address */
Elf32_Off e_phoff; /* Program header table file offset */
Elf32_Off e_shoff; /* Section header table file offset */
Elf32_Word e_flags;
Elf32_Half e_ehsize;
Elf32_Half e_phentsize;
Elf32_Half e_phnum;
Elf32_Half e_shentsize;
Elf32_Half e_shnum;
Elf32_Half e_shstrndx;
} Elf32_Ehdr;
typedef struct elf64_hdr
{
unsigned char e_ident[EI_NIDENT]; /* ELF "magic number" */
Elf64_Half e_type;
Elf64_Half e_machine;
Elf64_Word e_version;
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags;
Elf64_Half e_ehsize;
Elf64_Half e_phentsize;
Elf64_Half e_phnum;
Elf64_Half e_shentsize;
Elf64_Half e_shnum;
Elf64_Half e_shstrndx;
} Elf64_Ehdr;
typedef struct elf32_shdr
{
Elf32_Word sh_name;
Elf32_Word sh_type;
Elf32_Word sh_flags;
Elf32_Addr sh_addr;
Elf32_Off sh_offset;
Elf32_Word sh_size;
Elf32_Word sh_link;
Elf32_Word sh_info;
Elf32_Word sh_addralign;
Elf32_Word sh_entsize;
} Elf32_Shdr;
typedef struct elf64_shdr
{
Elf64_Word sh_name; /* Section name, index in string tbl */
Elf64_Word sh_type; /* Type of section */
Elf64_Xword sh_flags; /* Miscellaneous section attributes */
Elf64_Addr sh_addr; /* Section virtual addr at execution */
Elf64_Off sh_offset; /* Section file offset */
Elf64_Xword sh_size; /* Size of section in bytes */
Elf64_Word sh_link; /* Index of another section */
Elf64_Word sh_info; /* Additional section information */
Elf64_Xword sh_addralign; /* Section alignment */
Elf64_Xword sh_entsize; /* Entry size if section holds table */
} Elf64_Shdr;
typedef struct
{
Elf64_Word p_type;
Elf64_Word p_flags;
Elf64_Off p_offset;
Elf64_Addr p_vaddr;
Elf64_Addr p_paddr;
Elf64_Xword p_filesz;
Elf64_Xword p_memsz;
Elf64_Xword p_align;
} Elf64_Phdr;
typedef struct elf32_rel
{
Elf32_Addr r_offset;
Elf32_Word r_info;
} Elf32_Rel;
typedef struct elf64_rel
{
Elf64_Addr r_offset; /* Location at which to apply the action */
Elf64_Xword r_info; /* index and type of relocation */
} Elf64_Rel;
typedef struct elf32_sym
{
Elf32_Word st_name;
Elf32_Addr st_value;
Elf32_Word st_size;
unsigned char st_info;
unsigned char st_other;
Elf32_Half st_shndx;
} Elf32_Sym;
typedef struct elf64_sym
{
Elf64_Word st_name; /* Symbol name, index in string tbl */
unsigned char st_info; /* Type and binding attributes */
unsigned char st_other; /* No defined meaning, 0 */
Elf64_Half st_shndx; /* Associated section index */
Elf64_Addr st_value; /* Value of the symbol */
Elf64_Xword st_size; /* Associated symbol size */
} Elf64_Sym;
enum Elf_Ident
{
EI_MAG0 = 0, // 0x7F
EI_MAG1 = 1, // 'E'
EI_MAG2 = 2, // 'L'
EI_MAG3 = 3, // 'F'
EI_CLASS = 4, // Architecture (32/64)
EI_DATA = 5, // Byte Order
EI_VERSION = 6, // ELF Version
EI_OSABI = 7, // OS Specific
EI_ABIVERSION = 8, // OS Specific
EI_PAD = 9 // Padding
};
enum Elf_OSABI
{
ELFOSABI_NONE = 0,
ELFOSABI_HPUX = 1,
ELFOSABI_NETBSD = 2,
ELFOSABI_LINUX = 3,
ELFOSABI_HURD = 4,
ELFOSABI_SOLARIS = 6,
ELFOSABI_AIX = 7,
ELFOSABI_IRIX = 8,
ELFOSABI_FREEBSD = 9,
ELFOSABI_TRU64 = 10,
ELFOSABI_MODESTO = 11,
ELFOSABI_OPENBSD = 12,
ELFOSABI_OPENVMS = 13,
ELFOSABI_NSK = 14,
ELFOSABI_AROS = 15,
ELFOSABI_FENIXOS = 16, /* Wait... what? */
ELFOSABI_CLOUDABI = 17,
ELFOSABI_OPENVOS = 18,
ELFOSABI_C6000_ELFABI = 64,
ELFOSABI_C6000_LINUX = 65,
ELFOSABI_ARM = 97,
ELFOSABI_STANDALONE = 255
};
enum Elf_Type
{
ET_NONE = 0, // Unknown Type
ET_REL = 1, // Relocatable File
ET_EXEC = 2, // Executable File
ET_DYN = 3, // Shared Object File
ET_CORE = 4, // Core File
ET_LOPROC = 0xff00, // Processor Specific
ET_HIPROC = 0xffff // Processor Specific
};
enum RtT_Types
{
R_386_NONE = 0, // No relocation
R_386_32 = 1, // Symbol + Offset
R_386_PC32 = 2 // Symbol + Offset - Section Offset
};
enum StT_Bindings
{
/**
* @brief Local symbol. Symbol is not visible outside the object file.
*/
STB_LOCAL = 0,
/**
* @brief Global symbol. These symbols are visible to all object files being combined.
*/
STB_GLOBAL = 1,
/**
* @brief Weak symbols. These symbols are like global symbols, but their definitions are not required. Weak symbols are not visible outside the object file containing their definition.
*/
STB_WEAK = 2,
/**
* @brief Values in this inclusive range are reserved for operating system-specific semantics.
*/
STB_LOOS = 10,
/**
* @brief Values in this inclusive range are reserved for operating system-specific semantics.
*/
STB_HIOS = 12,
/**
* @brief Values in this inclusive range are reserved for processor-specific semantics.
*/
STB_LOPROC = 13,
/**
* @brief Values in this inclusive range are reserved for processor-specific semantics.
*/
STB_HIPROC = 15
};
enum StT_Types
{
STT_NOTYPE = 0, // No type
STT_OBJECT = 1, // Variables, arrays, etc.
STT_FUNC = 2 // Methods or functions
};
enum SegmentTypes
{
PT_NULL = 0,
PT_LOAD = 1,
PT_DYNAMIC = 2,
PT_INTERP = 3,
PT_NOTE = 4,
PT_SHLIB = 5,
PT_PHDR = 6,
PT_LOSUNW = 0x6ffffffa,
PT_SUNWBSS = 0x6ffffffb,
PT_SUNWSTACK = 0x6ffffffa,
PT_HISUNW = 0x6fffffff,
PT_LOPROC = 0x70000000,
PT_HIPROC = 0x7fffffff
};
// used for Elf64_Sym st_info
#define ELF32_ST_BIND(info) ((info) >> 4)
#define ELF32_ST_TYPE(info) ((info)&0xf)
#define ELF32_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf))
#define ELF64_ST_BIND(info) ((info) >> 4)
#define ELF64_ST_TYPE(info) ((info)&0xf)
#define ELF64_ST_INFO(bind, type) (((bind) << 4) + ((type)&0xf))
// used for Elf64_Sym st_other
#define ELF32_ST_VISIBILITY(o) ((o)&0x3)
#define ELF64_ST_VISIBILITY(o) ((o)&0x3)
#define DO_386_32(S, A) ((S) + (A))
#define DO_386_PC32(S, A, P) ((S) + (A) - (P))
#define DO_64_64(S, A) ((S) + (A))
#define DO_64_PC32(S, A, P) ((S) + (A) - (P))
#define ELF32_R_SYM(INFO) ((INFO) >> 8)
#define ELF32_R_TYPE(INFO) ((uint8_t)(INFO))
#define ELF64_R_SYM(INFO) ((INFO) >> 8)
#define ELF64_R_TYPE(INFO) ((uint8_t)(INFO))
#define SHN_UNDEF 0
#define SHN_ABS 0xfff1
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHF_WRITE 0x1
#define SHF_ALLOC 0x2
#define EM_386 (3) // x86 Machine Type
#define EM_AMD64 (0x3E) // 64bit
#define EM_AARCH64 (0xb7) // ARM64
#define EV_CURRENT (1) // ELF Current Version
#define ELFMAG0 0x7F // e_ident[EI_MAG0]
#define ELFMAG1 'E' // e_ident[EI_MAG1]
#define ELFMAG2 'L' // e_ident[EI_MAG2]
#define ELFMAG3 'F' // e_ident[EI_MAG3]
#define ELFDATANONE 0 /* e_ident[EI_DATA] */
#define ELFDATA2LSB 1
#define ELFDATA2MSB 2
#define ELFCLASSNONE 0 /* EI_CLASS */
#define ELFCLASS32 1
#define ELFCLASS64 2
#define ELFCLASSNUM 3
#define SHT_NULL 0 /* Section header table entry unused */
#define SHT_PROGBITS 1 /* Program data */
#define SHT_SYMTAB 2 /* Symbol table */
#define SHT_STRTAB 3 /* String table */
#define SHT_RELA 4 /* Relocation entries with addends */
#define SHT_HASH 5 /* Symbol hash table */
#define SHT_DYNAMIC 6 /* Dynamic linking information */
#define SHT_NOTE 7 /* Notes */
#define SHT_NOBITS 8 /* Program space with no data (bss) */
#define SHT_REL 9 /* Relocation entries, no addends */
#define SHT_SHLIB 10 /* Reserved */
#define SHT_DYNSYM 11 /* Dynamic linker symbol table */
#define SHT_INIT_ARRAY 14 /* Array of constructors */
#define SHT_FINI_ARRAY 15 /* Array of destructors */
#define SHT_PREINIT_ARRAY 16 /* Array of pre-constructors */
#define SHT_GROUP 17 /* Section group */
#define SHT_SYMTAB_SHNDX 18 /* Extended section indeces */
#define SHT_NUM 19 /* Number of defined types. */
#define SHT_LOOS 0x60000000 /* Start OS-specific. */
#define SHT_GNU_ATTRIBUTES 0x6ffffff5 /* Object attributes. */
#define SHT_GNU_HASH 0x6ffffff6 /* GNU-style hash table. */
#define SHT_GNU_LIBLIST 0x6ffffff7 /* Prelink library list */
#define SHT_CHECKSUM 0x6ffffff8 /* Checksum for DSO content. */
#define SHT_LOSUNW 0x6ffffffa /* Sun-specific low bound. */
#define SHT_SUNW_move 0x6ffffffa
#define SHT_SUNW_COMDAT 0x6ffffffb
#define SHT_SUNW_syminfo 0x6ffffffc
#define SHT_GNU_verdef 0x6ffffffd /* Version definition section. */
#define SHT_GNU_verneed 0x6ffffffe /* Version needs section. */
#define SHT_GNU_versym 0x6fffffff /* Version symbol table. */
#define SHT_HISUNW 0x6fffffff /* Sun-specific high bound. */
#define SHT_HIOS 0x6fffffff /* End OS-specific type */
#define SHT_LOPROC 0x70000000 /* Start of processor-specific */
#define SHT_HIPROC 0x7fffffff /* End of processor-specific */
#define SHT_LOUSER 0x80000000 /* Start of application-specific */
#define SHT_HIUSER 0x8fffffff /* End of application-specific */
#endif // !__FENNIX_KERNEL_ELF_H__

48
Kernel/include/exec.hpp Normal file
View File

@ -0,0 +1,48 @@
#ifndef __FENNIX_KERNEL_FILE_EXECUTE_H__
#define __FENNIX_KERNEL_FILE_EXECUTE_H__
#include <types.h>
#include <task.hpp>
#include <elf.h>
namespace Execute
{
enum BinaryType
{
BinTypeInvalid,
BinTypeFex,
BinTypeELF,
BinTypePE,
BinTypeNE,
BinTypeMZ,
BinTypeUnknown
};
enum ExStatus
{
OK,
Unknown,
Unsupported,
InvalidFile,
InvalidFileFormat,
InvalidFileHeader,
InvalidFileData,
InvalidFileEntryPoint,
InvalidFilePath
};
struct SpawnData
{
ExStatus Status;
Tasking::PCB *Process;
Tasking::TCB *Thread;
};
BinaryType GetBinaryType(char *Path);
SpawnData Spawn(char *Path, const char **argv, const char **envp);
void *ELFLoadRel(Elf64_Ehdr *Header);
}
#endif // !__FENNIX_KERNEL_FILE_EXECUTE_H__

View File

@ -0,0 +1,167 @@
#ifndef __FENNIX_KERNEL_FILESYSTEM_H__
#define __FENNIX_KERNEL_FILESYSTEM_H__
#include <types.h>
#include <vector.hpp>
// show debug messages
// #define DEBUG_FILESYSTEM 1
#ifdef DEBUG_FILESYSTEM
#define vfsdbg(m, ...) debug(m, ##__VA_ARGS__)
#else
#define vfsdbg(m, ...)
#endif
namespace FileSystem
{
#define FILENAME_LENGTH 256
struct FileSystemNode;
typedef uint64_t (*OperationMount)(const char *, unsigned long, const void *);
typedef uint64_t (*OperationUmount)(int);
typedef uint64_t (*OperationRead)(FileSystemNode *Node, uint64_t Offset, uint64_t Size, uint8_t *Buffer);
typedef uint64_t (*OperationWrite)(FileSystemNode *Node, uint64_t Offset, uint64_t Size, uint8_t *Buffer);
typedef void (*OperationOpen)(FileSystemNode *Node, uint8_t Mode, uint8_t Flags);
typedef void (*OperationClose)(FileSystemNode *Node);
typedef uint64_t (*OperationSync)(void);
typedef void (*OperationCreate)(FileSystemNode *Node, char *Name, uint16_t NameLength);
typedef void (*OperationMkdir)(FileSystemNode *Node, char *Name, uint16_t NameLength);
#define MountFSFunction(name) uint64_t name(const char *unknown0, unsigned long unknown1, const uint8_t *unknown2)
#define UMountFSFunction(name) uint64_t name(int unknown0)
#define ReadFSFunction(name) uint64_t name(FileSystem::FileSystemNode *Node, uint64_t Offset, uint64_t Size, uint8_t *Buffer)
#define WriteFSFunction(name) uint64_t name(FileSystem::FileSystemNode *Node, uint64_t Offset, uint64_t Size, uint8_t *Buffer)
#define OpenFSFunction(name) void name(FileSystem::FileSystemNode *Node, uint8_t Mode, uint8_t Flags)
#define CloseFSFunction(name) void name(FileSystem::FileSystemNode *Node)
#define SyncFSFunction(name) uint64_t name(void)
#define CreateFSFunction(name) void name(FileSystem::FileSystemNode *Node, char *Name, uint16_t NameLength)
#define MkdirFSFunction(name) void name(FileSystem::FileSystemNode *Node, char *Name, uint16_t NameLength)
enum FileStatus
{
OK = 0,
NOT_FOUND = 1,
ACCESS_DENIED = 2,
INVALID_NAME = 3,
INVALID_PARAMETER = 4,
INVALID_HANDLE = 5,
INVALID_PATH = 6,
INVALID_FILE = 7,
INVALID_DEVICE = 8,
NOT_EMPTY = 9,
NOT_SUPPORTED = 10,
INVALID_DRIVE = 11,
VOLUME_IN_USE = 12,
TIMEOUT = 13,
NO_MORE_FILES = 14,
END_OF_FILE = 15,
FILE_EXISTS = 16,
PIPE_BUSY = 17,
PIPE_DISCONNECTED = 18,
MORE_DATA = 19,
NO_DATA = 20,
PIPE_NOT_CONNECTED = 21,
MORE_ENTRIES = 22,
DIRECTORY_NOT_EMPTY = 23,
NOT_A_DIRECTORY = 24,
FILE_IS_A_DIRECTORY = 25,
DIRECTORY_NOT_ROOT = 26,
DIRECTORY_NOT_EMPTY_2 = 27,
END_OF_MEDIA = 28,
NO_MEDIA = 29,
UNRECOGNIZED_MEDIA = 30,
SECTOR_NOT_FOUND = 31
};
enum NodeFlags
{
FS_ERROR = 0x0,
FS_FILE = 0x01,
FS_DIRECTORY = 0x02,
FS_CHARDEVICE = 0x03,
FS_BLOCKDEVICE = 0x04,
FS_PIPE = 0x05,
FS_SYMLINK = 0x06,
FS_MOUNTPOINT = 0x08
};
struct FileSystemOperations
{
char Name[FILENAME_LENGTH];
OperationMount Mount = nullptr;
OperationUmount Umount = nullptr;
OperationRead Read = nullptr;
OperationWrite Write = nullptr;
OperationOpen Open = nullptr;
OperationClose Close = nullptr;
OperationCreate Create = nullptr;
OperationMkdir MakeDirectory = nullptr;
};
struct FileSystemNode
{
char Name[FILENAME_LENGTH];
uint64_t IndexNode = 0;
uint64_t Mask = 0;
uint64_t Mode = 0;
uint64_t Flags = NodeFlags::FS_ERROR;
uint64_t UserIdentifier = 0, GroupIdentifier = 0;
uint64_t Address = 0;
uint64_t Length = 0;
FileSystemNode *Parent = nullptr;
FileSystemOperations *Operator = nullptr;
/* For root node:
0 - root "/"
1 - etc
...
*/
Vector<FileSystemNode *> Children;
};
struct FILE
{
const char *Name;
FileStatus Status;
FileSystemNode *Node;
};
/* Manage / etc.. */
class Virtual
{
private:
FileSystemNode *FileSystemRoot = nullptr;
public:
FileSystemNode *GetRootNode() { return FileSystemRoot; }
FILE *ConvertNodeToFILE(FileSystemNode *Node)
{
FILE *File = new FILE;
File->Name = Node->Name;
File->Status = FileStatus::OK;
File->Node = Node;
return File;
}
char *GetPathFromNode(FileSystemNode *Node);
FileSystemNode *GetNodeFromPath(FileSystemNode *Parent, const char *Path);
char *NormalizePath(FileSystemNode *Parent, const char *Path);
FileStatus FileExists(FileSystemNode *Parent, const char *Path);
FILE *Mount(FileSystemOperations *Operator, const char *Path);
FileStatus Unmount(FILE *File);
FILE *Open(const char *Path, FileSystemNode *Parent = nullptr);
uint64_t Read(FILE *File, uint64_t Offset, uint8_t *Buffer, uint64_t Size);
uint64_t Write(FILE *File, uint64_t Offset, uint8_t *Buffer, uint64_t Size);
FileStatus Close(FILE *File);
FileSystemNode *CreateRoot(FileSystemOperations *Operator, const char *RootName);
FileSystemNode *Create(FileSystemNode *Parent, const char *Path);
Virtual();
~Virtual();
};
}
#endif // !__FENNIX_KERNEL_FILESYSTEM_H__

View File

@ -0,0 +1,74 @@
#ifndef __FENNIX_KERNEL_FILESYSTEM_EXT2_H__
#define __FENNIX_KERNEL_FILESYSTEM_EXT2_H__
#include <types.h>
#include <filesystem.hpp>
namespace FileSystem
{
class EXT2
{
public:
struct SuperBlock
{
uint32_t Inodes;
uint32_t Blocks;
uint32_t ReservedBlocks;
uint32_t FreeBlock;
uint32_t FreeInodes;
uint32_t FirstDataBlock;
uint32_t LogBlockSize;
uint32_t LogFragSize;
uint32_t BlocksPerGroup;
uint32_t FragsPerGroup;
uint32_t InodesPerGroup;
uint32_t LastMountTime;
uint32_t LastWrittenTime;
uint16_t MountedTimes;
uint16_t MaximumMountedTimes;
uint16_t Magic;
uint16_t State;
uint16_t Errors;
uint16_t MinorRevLevel;
uint32_t LastCheck;
uint32_t CheckInternval;
uint32_t SystemID;
uint32_t RevLevel;
uint16_t ReservedBlocksUserID;
uint16_t ReservedBlocksGroupID;
uint32_t FirstInode;
uint16_t InodeSize;
uint16_t BlockGroups;
uint32_t FeatureCompatibility;
uint32_t FeatureIncompatibility;
uint32_t FeatureRoCompatibility;
uint8_t UUID[16];
char VolumeName[16];
char LastMounted[64];
uint32_t BitmapAlogrithm;
uint8_t PreallocatedBlocks;
uint8_t PreallocatedDirectoryBlocks;
uint16_t Padding;
uint8_t JournalUUID[16];
uint32_t JournalInum;
uint32_t JournalDev;
uint32_t LastOrphan;
uint32_t HashSeed[4];
uint8_t DefHashVersion;
uint8_t ReservedCharPad;
uint16_t ReservedWordPad;
uint32_t DefaultMountOptions;
uint32_t FirstMetaBg;
uint32_t Reserved[190];
};
EXT2(void *partition);
~EXT2();
};
}
#endif // !__FENNIX_KERNEL_FILESYSTEM_EXT2_H__

View File

@ -0,0 +1,60 @@
#ifndef __FENNIX_KERNEL_FILESYSTEM_FAT_H__
#define __FENNIX_KERNEL_FILESYSTEM_FAT_H__
#include <types.h>
#include <filesystem.hpp>
namespace FileSystem
{
class FAT
{
public:
enum FatType
{
Unknown,
FAT12,
FAT16,
FAT32
};
/* https://wiki.osdev.org/FAT */
struct BIOSParameterBlock
{
/** @brief The first three bytes EB 3C 90 disassemble to JMP SHORT 3C NOP. (The 3C value may be different.) The reason for this is to jump over the disk format information (the BPB and EBPB). Since the first sector of the disk is loaded into ram at location 0x0000:0x7c00 and executed, without this jump, the processor would attempt to execute data that isn't code. Even for non-bootable volumes, code matching this pattern (or using the E9 jump opcode) is required to be present by both Windows and OS X. To fulfil this requirement, an infinite loop can be placed here with the bytes EB FE 90. */
uint8_t JumpBoot[3];
/** @brief OEM identifier. The first 8 Bytes (3 - 10) is the version of DOS being used. The next eight Bytes 29 3A 63 7E 2D 49 48 and 43 read out the name of the version. The official FAT Specification from Microsoft says that this field is really meaningless and is ignored by MS FAT Drivers, however it does recommend the value "MSWIN4.1" as some 3rd party drivers supposedly check it and expect it to have that value. Older versions of dos also report MSDOS5.1, linux-formatted floppy will likely to carry "mkdosfs" here, and FreeDOS formatted disks have been observed to have "FRDOS5.1" here. If the string is less than 8 bytes, it is padded with spaces. */
uint8_t OEM[8];
/** @brief The number of Bytes per sector (remember, all numbers are in the little-endian format). */
uint16_t BytesPerSector;
/** @brief Number of sectors per cluster. */
uint8_t SectorsPerCluster;
/** @brief Number of reserved sectors. The boot record sectors are included in this value. */
uint16_t ReservedSectors;
/** @brief Number of File Allocation Tables (FAT's) on the storage media. Often this value is 2. */
uint8_t NumberOfFATs;
/** @brief Number of root directory entries (must be set so that the root directory occupies entire sectors). */
uint16_t RootDirectoryEntries;
/** @brief The total sectors in the logical volume. If this value is 0, it means there are more than 65535 sectors in the volume, and the actual count is stored in the Large Sector Count entry at 0x20. */
uint16_t Sectors16;
/** @brief This Byte indicates the media descriptor type. */
uint8_t Media;
/** @brief Number of sectors per FAT. FAT12/FAT16 only. */
uint16_t SectorsPerFAT;
/** @brief Number of sectors per track. */
uint16_t SectorsPerTrack;
/** @brief Number of heads or sides on the storage media. */
uint16_t NumberOfHeads;
/** @brief Number of hidden sectors. (i.e. the LBA of the beginning of the partition). */
uint32_t HiddenSectors;
/** @brief Large sector count. This field is set if there are more than 65535 sectors in the volume, resulting in a value which does not fit in the Number of Sectors entry at 0x13. */
uint32_t Sectors32;
} __attribute__((__packed__));
FatType GetFATType(BIOSParameterBlock *bpb);
FAT(void *partition);
~FAT();
};
}
#endif // !__FENNIX_KERNEL_FILESYSTEM_FAT_H__

View File

@ -0,0 +1,31 @@
#ifndef __FENNIX_KERNEL_FILESYSTEM_INITRD_H__
#define __FENNIX_KERNEL_FILESYSTEM_INITRD_H__
#include <types.h>
#include <filesystem.hpp>
namespace FileSystem
{
class Initrd
{
public:
struct InitrdHeader
{
uint32_t nfiles;
};
struct InitrdFileHeader
{
uint8_t magic;
char name[64];
uint32_t offset;
uint32_t length;
};
Initrd(uint64_t Address);
~Initrd();
};
}
#endif // !__FENNIX_KERNEL_FILESYSTEM_INITRD_H__

View File

@ -0,0 +1,97 @@
#ifndef __FENNIX_KERNEL_FILESYSTEM_DEV_H__
#define __FENNIX_KERNEL_FILESYSTEM_DEV_H__
#include <types.h>
#include <filesystem.hpp>
namespace FileSystem
{
/* Manage /system/dev */
class Device
{
public:
FileSystemNode *AddFileSystem(FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
Device();
~Device();
};
/* Manage /system/mnt */
class Mount
{
public:
FileSystemNode *MountFileSystem(FileSystemOperations *Operator, uint64_t Mode, const char *Name);
void DetectAndMountFS(void *drive);
Mount();
~Mount();
};
/* Manage /system/prc */
class Process
{
public:
Process();
~Process();
};
/* Manage /system/drv */
class Driver
{
public:
FileSystemNode *AddDriver(struct FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
Driver();
~Driver();
};
/* Manage /system/net */
class Network
{
public:
FileSystemNode *AddNetworkCard(struct FileSystemOperations *Operator, uint64_t Mode, const char *Name, int Flags);
Network();
~Network();
};
/* Manage /system/dev/serialX */
class Serial
{
public:
Serial();
~Serial();
};
/* Manage /system/dev/random */
class Random
{
public:
Random();
~Random();
};
/* Manage /system/dev/null */
class Null
{
public:
Null();
~Null();
};
/* Manage /system/dev/zero */
class Zero
{
public:
Zero();
~Zero();
};
/* Manage /system/dev/fbX */
class FB
{
public:
void SetFrameBufferData(uint64_t Address, uint64_t Size, uint32_t Width, uint32_t Height, uint32_t PixelsPerScanLine);
FB();
~FB();
};
}
#endif // !__FENNIX_KERNEL_FILESYSTEM_DEV_H__

View File

@ -0,0 +1,71 @@
#ifndef __FENNIX_KERNEL_FILESYSTEM_USTAR_H__
#define __FENNIX_KERNEL_FILESYSTEM_USTAR_H__
#include <types.h>
#include <filesystem.hpp>
namespace FileSystem
{
class USTAR
{
enum FileType
{
REGULAR_FILE = '0',
HARDLINK = '1',
SYMLINK = '2',
CHARDEV = '3',
BLOCKDEV = '4',
DIRECTORY = '5',
FIFO = '6'
};
struct FileHeader
{
char name[100];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char chksum[8];
char typeflag[1];
char link[100];
char signature[6];
char version[2];
char owner[32];
char group[32];
char dev_maj[8];
char dev_min[8];
char prefix[155];
char pad[12];
};
private:
uint32_t getsize(const char *s)
{
uint64_t ret = 0;
while (*s)
{
ret *= 8;
ret += *s - '0';
s++;
}
return ret;
}
int string2int(const char *str)
{
int res = 0;
for (int i = 0; str[i] != '\0'; ++i)
res = res * 10 + str[i] - '0';
return res;
}
public:
USTAR(uint64_t Address, Virtual *vfs);
~USTAR();
};
}
#endif // !__FENNIX_KERNEL_FILESYSTEM_USTAR_H__

View File

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

View File

@ -0,0 +1,52 @@
#ifndef __FENNIX_KERNEL_INTERRUPTS_H__
#define __FENNIX_KERNEL_INTERRUPTS_H__
#include <types.h>
#include <cpu.hpp>
namespace Interrupts
{
#ifdef DEBUG // For performance reasons
#define INT_FRAMES_MAX 512
#else
#define INT_FRAMES_MAX 8
#endif
#if defined(__amd64__)
/* APIC::APIC */ extern void *apic[256]; // MAX_CPU
/* APIC::Timer */ extern void *apicTimer[256]; // MAX_CPU
#elif defined(__i386__)
/* APIC::APIC */ extern void *apic[256]; // MAX_CPU
/* APIC::Timer */ extern void *apicTimer[256]; // MAX_CPU
#elif defined(__aarch64__)
#endif
extern void *InterruptFrames[INT_FRAMES_MAX];
void Initialize(int Core);
void Enable(int Core);
void InitializeTimer(int Core);
void RemoveAll();
class Handler
{
private:
int InterruptNumber;
protected:
void SetInterruptNumber(int InterruptNumber) { this->InterruptNumber = InterruptNumber; }
int GetInterruptNumber() { return InterruptNumber; }
Handler(int InterruptNumber);
~Handler();
public:
#if defined(__amd64__)
virtual void OnInterruptReceived(CPU::x64::TrapFrame *Frame);
#elif defined(__i386__)
virtual void OnInterruptReceived(void *Frame);
#elif defined(__aarch64__)
virtual void OnInterruptReceived(void *Frame);
#endif
};
}
#endif // !__FENNIX_KERNEL_INTERRUPTS_H__

220
Kernel/include/io.h Normal file
View File

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

76
Kernel/include/ipc.hpp Normal file
View File

@ -0,0 +1,76 @@
#ifndef __FENNIX_KERNEL_IPC_H__
#define __FENNIX_KERNEL_IPC_H__
#include <types.h>
#include <lock.hpp>
namespace InterProcessCommunication
{
typedef int IPCPort;
enum IPCOperationType
{
IPCOperationNone,
IPCOperationWrite,
IPCOperationRead
};
enum IPCErrorCode
{
IPCUnknown,
IPCSuccess,
IPCNotListening,
IPCTimeout,
IPCInvalidPort,
IPCPortInUse,
IPCPortNotRegistered,
IPCIDNotFound
};
typedef struct
{
int ID;
long Length;
uint8_t *Buffer;
bool Listening;
IPCOperationType Operation;
IPCErrorCode Error;
LockClass Lock;
} IPCHandle;
typedef struct
{
int ID;
long Length;
IPCOperationType Operation;
IPCErrorCode Error;
uint8_t *Buffer;
// Reserved
IPCHandle *HandleBuffer;
} __attribute__((packed)) IPCSyscallHandle;
struct IPCError
{
uint64_t ErrorCode;
};
class IPC
{
private:
public:
IPC();
~IPC();
IPCHandle *RegisterHandle(IPCPort Port);
IPCError Listen(IPCPort Port);
IPCHandle *Wait(IPCPort Port);
IPCError Read(unsigned long /* Tasking::UPID */ ID, IPCPort Port, uint8_t *&Buffer, long &Size);
IPCError Write(unsigned long /* Tasking::UPID */ ID, IPCPort Port, uint8_t *Buffer, long Size);
};
}
extern InterProcessCommunication::IPC *ipc;
#endif // !__FENNIX_KERNEL_IPC_H__

View File

@ -0,0 +1,20 @@
#ifndef __FENNIX_KERNEL_KERNEL_CONFIG_H__
#define __FENNIX_KERNEL_KERNEL_CONFIG_H__
#include <types.h>
#include <memory.hpp>
struct KernelConfig
{
Memory::MemoryAllocatorType AllocatorType;
bool SchedulerType;
char DriverDirectory[256];
char InitPath[256];
bool InterruptsOnCrash;
int Cores;
bool UnlockDeadLock;
};
KernelConfig ParseConfig(char *Config);
#endif // !__FENNIX_KERNEL_KERNEL_CONFIG_H__

119
Kernel/include/limits.h Normal file
View File

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

100
Kernel/include/lock.hpp Normal file
View File

@ -0,0 +1,100 @@
#ifndef __FENNIX_KERNEL_LOCK_H__
#define __FENNIX_KERNEL_LOCK_H__
#include <types.h>
#include <cpu.hpp>
#ifdef __cplusplus
/** @brief Please use this macro to create a new lock. */
class LockClass
{
struct SpinLockData
{
uint64_t LockData = 0x0;
const char *CurrentHolder = "(nul)";
const char *AttemptingToGet = "(nul)";
uint64_t Count = 0;
long Core = 0;
};
void DeadLock(SpinLockData Lock);
private:
SpinLockData LockData;
bool IsLocked = false;
unsigned long DeadLocks = 0;
public:
SpinLockData *GetLockData() { return &LockData; }
int Lock(const char *FunctionName);
int Unlock();
};
/** @brief Please use this macro to create a new smart lock. */
class SmartLockClass
{
private:
LockClass *LockPointer = nullptr;
public:
SmartLockClass(LockClass &Lock, const char *FunctionName)
{
this->LockPointer = &Lock;
this->LockPointer->Lock(FunctionName);
}
~SmartLockClass() { this->LockPointer->Unlock(); }
};
/** @brief Please use this macro to create a new smart critical section lock. */
class SmartLockCriticalSectionClass
{
private:
LockClass *LockPointer = nullptr;
bool InterruptsEnabled = false;
public:
SmartLockCriticalSectionClass(LockClass &Lock, const char *FunctionName)
{
if (CPU::Interrupts(CPU::Check))
InterruptsEnabled = true;
CPU::Interrupts(CPU::Disable);
this->LockPointer = &Lock;
this->LockPointer->Lock(FunctionName);
}
~SmartLockCriticalSectionClass()
{
if (InterruptsEnabled)
CPU::Interrupts(CPU::Enable);
this->LockPointer->Unlock();
}
};
/** @brief Please use this macro to create a new critical section. */
class SmartCriticalSectionClass
{
private:
bool InterruptsEnabled = false;
public:
bool IsInterruptsEnabled() { return InterruptsEnabled; }
SmartCriticalSectionClass()
{
if (CPU::Interrupts(CPU::Check))
InterruptsEnabled = true;
CPU::Interrupts(CPU::Disable);
}
~SmartCriticalSectionClass()
{
if (InterruptsEnabled)
CPU::Interrupts(CPU::Enable);
}
};
/** @brief Create a new lock (can be used with SmartCriticalSection). */
#define NewLock(Name) LockClass Name
/** @brief Simple lock that is automatically released when the scope ends. */
#define SmartLock(LockClassName) SmartLockClass CONCAT(lock##_, __COUNTER__)(LockClassName, __FUNCTION__)
/** @brief Simple critical section that is automatically released when the scope ends and interrupts are restored if they were enabled. */
#define SmartCriticalSection(LockClassName) SmartLockCriticalSectionClass CONCAT(lock##_, __COUNTER__)(LockClassName, __FUNCTION__)
/** @brief Automatically disable interrupts and restore them when the scope ends. */
#define CriticalSection SmartCriticalSectionClass
#endif // __cplusplus
#endif // !__FENNIX_KERNEL_LOCK_H__

37
Kernel/include/md5.h Normal file
View File

@ -0,0 +1,37 @@
#ifndef __FENNIX_KERNEL_MD5_H__
#define __FENNIX_KERNEL_MD5_H__
#include <types.h>
/*
https://github.com/Zunawe/md5-c
*/
START_EXTERNC
typedef struct
{
uint64_t size; // Size of input in bytes
uint32_t buffer[4]; // Current accumulation of hash
uint8_t input[64]; // Input to be used in the next step
uint8_t digest[16]; // Result of algorithm
} MD5Context;
void md5Init(MD5Context *ctx);
void md5Update(MD5Context *ctx, uint8_t *input, size_t input_len);
void md5Finalize(MD5Context *ctx);
void md5Step(uint32_t *buffer, uint32_t *input);
uint8_t *md5String(char *input);
uint8_t *md5File(uint8_t *buffer, size_t input_len);
uint32_t F(uint32_t X, uint32_t Y, uint32_t Z);
uint32_t G(uint32_t X, uint32_t Y, uint32_t Z);
uint32_t H(uint32_t X, uint32_t Y, uint32_t Z);
uint32_t I(uint32_t X, uint32_t Y, uint32_t Z);
uint32_t rotateLeft(uint32_t x, uint32_t n);
END_EXTERNC
#endif // !__FENNIX_KERNEL_MD5_H__

668
Kernel/include/memory.hpp Normal file
View File

@ -0,0 +1,668 @@
#ifndef __FENNIX_KERNEL_INTERNAL_MEMORY_H__
#define __FENNIX_KERNEL_INTERNAL_MEMORY_H__
#ifdef __cplusplus
#include <boot/binfo.h>
#include <bitmap.hpp>
#include <lock.hpp>
#endif // __cplusplus
#include <types.h>
#ifdef __cplusplus
extern uint64_t _kernel_start, _kernel_end;
extern uint64_t _kernel_text_end, _kernel_data_end, _kernel_rodata_end;
// kilobyte
#define TO_KB(d) (d / 1024)
// megabyte
#define TO_MB(d) (d / 1024 / 1024)
// gigabyte
#define TO_GB(d) (d / 1024 / 1024 / 1024)
// terabyte
#define TO_TB(d) (d / 1024 / 1024 / 1024 / 1024)
// petabyte
#define TO_PB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024)
// exobyte
#define TO_EB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
// zettabyte
#define TO_ZB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
// yottabyte
#define TO_YB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
// brontobyte
#define TO_BB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
// geopbyte
#define TO_GPB(d) (d / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024 / 1024)
#define PAGE_SIZE 0x1000 // 4KB
#define STACK_SIZE 0x4000 // 16kb
#define USER_STACK_SIZE 0x2000 // 8kb
// to pages
#define TO_PAGES(d) (d / PAGE_SIZE + 1)
// from pages
#define FROM_PAGES(d) (d * PAGE_SIZE - 1)
#define NORMAL_VMA_OFFSET 0xFFFF800000000000
#define KERNEL_VMA_OFFSET 0xFFFFFFFF80000000
/**
* @brief KERNEL_HEAP_BASE is the base address of the kernel heap
*/
#define KERNEL_HEAP_BASE 0xFFFFA00000000000
/**
* @brief USER_HEAP_BASE is the base address of the user heap allocated by the kernel
*/
#define USER_HEAP_BASE 0xFFFFB00000000000
/**
* @brief USER_STACK_BASE is the base address of the user stack
*/
#define USER_STACK_BASE 0xFFFFEFFFFFFF0000
namespace Memory
{
enum MemoryAllocatorType
{
None,
Pages,
XallocV1,
liballoc11
};
/**
* @brief https://wiki.osdev.org/images/4/41/64-bit_page_tables1.png
* @brief https://wiki.osdev.org/images/6/6b/64-bit_page_tables2.png
*/
enum PTFlag
{
/** @brief Present */
P = 1 << 0,
/** @brief Read/Write */
RW = 1 << 1,
/** @brief User/Supervisor */
US = 1 << 2,
/** @brief Write-Through */
PWT = 1 << 3,
/** @brief Cache Disable */
PCD = 1 << 4,
/** @brief Accessed */
A = 1 << 5,
/** @brief Dirty */
D = 1 << 6,
/** @brief Page Size */
PS = 1 << 7,
/** @brief Global */
G = 1 << 8,
/** @brief Available 0 */
AVL0 = 1 << 9,
/** @brief Available 1 */
AVL1 = 1 << 10,
/** @brief Available 2 */
AVL2 = 1 << 11,
/** @brief Page Attribute Table */
PAT = 1 << 12,
/** @brief Available 3 */
AVL3 = (uint64_t)1 << 52,
/** @brief Available 4 */
AVL4 = (uint64_t)1 << 53,
/** @brief Available 5 */
AVL5 = (uint64_t)1 << 54,
/** @brief Available 6 */
AVL6 = (uint64_t)1 << 55,
/** @brief Available 7 */
AVL7 = (uint64_t)1 << 56,
/** @brief Available 8 */
AVL8 = (uint64_t)1 << 57,
/** @brief Available 9 */
AVL9 = (uint64_t)1 << 58,
/** @brief Protection Key 0 */
PK0 = (uint64_t)1 << 59,
/** @brief Protection Key 1 */
PK1 = (uint64_t)1 << 60,
/** @brief Protection Key 2 */
PK2 = (uint64_t)1 << 61,
/** @brief Protection Key 3 */
PK3 = (uint64_t)1 << 62,
/** @brief Execute Disable */
XD = (uint64_t)1 << 63
};
/* 2.2 Paging in IA-32e Mode - https://composter.com.ua/documents/TLBs_Paging-Structure_Caches_and_Their_Invalidation.pdf */
union __attribute__((packed)) PageTableEntry
{
struct
{
bool Present : 1; // 0
bool ReadWrite : 1; // 1
bool UserSupervisor : 1; // 2
bool WriteThrough : 1; // 3
bool CacheDisable : 1; // 4
bool Accessed : 1; // 5
bool Dirty : 1; // 6
bool PageAttributeTable : 1; // 7
bool Global : 1; // 8
uint8_t Available0 : 3; // 9-11
uint64_t Address : 40; // 12-51
uint32_t Available1 : 7; // 52-58
bool ProtectionKey : 4; // 59-62
bool ExecuteDisable : 1; // 63
};
uint64_t raw;
/** @brief Set Address */
void SetAddress(uint64_t _Address)
{
#if defined(__amd64__)
_Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12);
#elif defined(__i386__)
_Address &= 0x000FFFFF;
this->raw &= 0xFFC00003;
this->raw |= (_Address << 12);
#elif defined(__aarch64__)
_Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12);
#endif
}
/** @brief Get Address */
uint64_t GetAddress()
{
#if defined(__amd64__)
return (this->raw & 0x000FFFFFFFFFF000) >> 12;
#elif defined(__i386__)
return (this->raw & 0x003FFFFF000) >> 12;
#elif defined(__aarch64__)
return (this->raw & 0x000FFFFFFFFFF000) >> 12;
#endif
}
};
struct __attribute__((packed)) PageTableEntryPtr
{
PageTableEntry Entries[511];
};
union __attribute__((packed)) PageDirectoryEntry
{
struct
{
bool Present : 1; // 0
bool ReadWrite : 1; // 1
bool UserSupervisor : 1; // 2
bool WriteThrough : 1; // 3
bool CacheDisable : 1; // 4
bool Accessed : 1; // 5
bool Available0 : 1; // 6
bool PageSize : 1; // 7
uint8_t Available1 : 4; // 8-11
uint64_t Address : 40; // 12-51
uint32_t Available2 : 11; // 52-62
bool ExecuteDisable : 1; // 63
};
uint64_t raw;
/** @brief Set PageTableEntryPtr address */
void SetAddress(uint64_t _Address)
{
#if defined(__amd64__)
_Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12);
#elif defined(__i386__)
_Address &= 0x000FFFFF;
this->raw &= 0xFFC00003;
this->raw |= (_Address << 12);
#elif defined(__aarch64__)
_Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12);
#endif
}
/** @brief Get PageTableEntryPtr address */
uint64_t GetAddress()
{
#if defined(__amd64__)
return (this->raw & 0x000FFFFFFFFFF000) >> 12;
#elif defined(__i386__)
return (this->raw & 0x003FFFFF000) >> 12;
#elif defined(__aarch64__)
return (this->raw & 0x000FFFFFFFFFF000) >> 12;
#endif
}
};
struct __attribute__((packed)) PageDirectoryEntryPtr
{
PageDirectoryEntry Entries[511];
};
union __attribute__((packed)) PageDirectoryPointerTableEntry
{
struct
{
bool Present : 1; // 0
bool ReadWrite : 1; // 1
bool UserSupervisor : 1; // 2
bool WriteThrough : 1; // 3
bool CacheDisable : 1; // 4
bool Accessed : 1; // 5
bool Available0 : 1; // 6
bool PageSize : 1; // 7
uint8_t Available1 : 4; // 8-11
uint64_t Address : 40; // 12-51
uint32_t Available2 : 11; // 52-62
bool ExecuteDisable : 1; // 63
};
uint64_t raw;
/** @brief Set PageDirectoryEntryPtr address */
void SetAddress(uint64_t _Address)
{
#if defined(__amd64__)
_Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12);
#elif defined(__i386__)
_Address &= 0x000FFFFF;
this->raw &= 0xFFC00003;
this->raw |= (_Address << 12);
#elif defined(__aarch64__)
_Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12);
#endif
}
/** @brief Get PageDirectoryEntryPtr address */
uint64_t GetAddress()
{
#if defined(__amd64__)
return (this->raw & 0x000FFFFFFFFFF000) >> 12;
#elif defined(__i386__)
return (this->raw & 0x003FFFFF000) >> 12;
#elif defined(__aarch64__)
return (this->raw & 0x000FFFFFFFFFF000) >> 12;
#endif
}
};
struct __attribute__((packed)) PageDirectoryPointerTableEntryPtr
{
PageDirectoryPointerTableEntry Entries[511];
};
union __attribute__((packed)) PageMapLevel4
{
struct
{
bool Present : 1; // 0
bool ReadWrite : 1; // 1
bool UserSupervisor : 1; // 2
bool WriteThrough : 1; // 3
bool CacheDisable : 1; // 4
bool Accessed : 1; // 5
bool Available0 : 1; // 6
bool Reserved0 : 1; // 7
uint8_t Available1 : 4; // 8-11
uint64_t Address : 40; // 12-51
uint32_t Available2 : 11; // 52-62
bool ExecuteDisable : 1; // 63
};
uint64_t raw;
/** @brief Set PageDirectoryPointerTableEntryPtr address */
void SetAddress(uint64_t _Address)
{
#if defined(__amd64__)
_Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12);
#elif defined(__i386__)
_Address &= 0x000FFFFF;
this->raw &= 0xFFC00003;
this->raw |= (_Address << 12);
#elif defined(__aarch64__)
_Address &= 0x000000FFFFFFFFFF;
this->raw &= 0xFFF0000000000FFF;
this->raw |= (_Address << 12);
#endif
}
/** @brief Get PageDirectoryPointerTableEntryPtr address */
uint64_t GetAddress()
{
#if defined(__amd64__)
return (this->raw & 0x000FFFFFFFFFF000) >> 12;
#elif defined(__i386__)
return (this->raw & 0x003FFFFF000) >> 12;
#elif defined(__aarch64__)
return (this->raw & 0x000FFFFFFFFFF000) >> 12;
#endif
}
};
struct PageTable4
{
PageMapLevel4 Entries[511];
} __attribute__((aligned(0x1000)));
struct __attribute__((packed)) PageMapLevel5
{
/* FIXME: NOT IMPLEMENTED! */
};
struct PageTable5
{
PageMapLevel5 Entries[511];
} __attribute__((aligned(0x1000)));
class Physical
{
private:
NewLock(MemoryLock);
uint64_t TotalMemory = 0;
uint64_t FreeMemory = 0;
uint64_t ReservedMemory = 0;
uint64_t UsedMemory = 0;
uint64_t PageBitmapIndex = 0;
Bitmap PageBitmap;
void ReservePage(void *Address);
void ReservePages(void *Address, uint64_t PageCount);
void UnreservePage(void *Address);
void UnreservePages(void *Address, uint64_t PageCount);
public:
Bitmap GetPageBitmap() { return PageBitmap; }
/**
* @brief Get Total Memory
*
* @return uint64_t
*/
uint64_t GetTotalMemory();
/**
* @brief Get Free Memory
*
* @return uint64_t
*/
uint64_t GetFreeMemory();
/**
* @brief Get Reserved Memory
*
* @return uint64_t
*/
uint64_t GetReservedMemory();
/**
* @brief Get Used Memory
*
* @return uint64_t
*/
uint64_t GetUsedMemory();
/**
* @brief Swap page
*
* @param Address Address of the page
* @return true if swap was successful
* @return false if swap was unsuccessful
*/
bool SwapPage(void *Address);
/**
* @brief Swap pages
*
* @param Address Address of the pages
* @param PageCount Number of pages
* @return true if swap was successful
* @return false if swap was unsuccessful
*/
bool SwapPages(void *Address, uint64_t PageCount);
/**
* @brief Unswap page
*
* @param Address Address of the page
* @return true if unswap was successful
* @return false if unswap was unsuccessful
*/
bool UnswapPage(void *Address);
/**
* @brief Unswap pages
*
* @param Address Address of the pages
* @param PageCount Number of pages
* @return true if unswap was successful
* @return false if unswap was unsuccessful
*/
bool UnswapPages(void *Address, uint64_t PageCount);
/**
* @brief Lock page
*
* @param Address Address of the page
*/
void LockPage(void *Address);
/**
* @brief Lock pages
*
* @param Address Address of the pages
* @param PageCount Number of pages
*/
void LockPages(void *Address, uint64_t PageCount);
/**
* @brief Request page
*
* @return void* Allocated page address
*/
void *RequestPage();
/**
* @brief Request pages
*
* @param PageCount Number of pages
* @return void* Allocated pages address
*/
void *RequestPages(uint64_t Count);
/**
* @brief Free page
*
* @param Address Address of the page
*/
void FreePage(void *Address);
/**
* @brief Free pages
*
* @param Address Address of the pages
* @param PageCount Number of pages
*/
void FreePages(void *Address, uint64_t Count);
/** @brief Do not use. */
void Init(BootInfo *Info);
/** @brief Do not use. */
Physical();
/** @brief Do not use. */
~Physical();
};
class Virtual
{
private:
NewLock(MemoryLock);
PageTable4 *Table = nullptr;
public:
class PageMapIndexer
{
public:
uint64_t PMLIndex = 0;
uint64_t PDPTEIndex = 0;
uint64_t PDEIndex = 0;
uint64_t PTEIndex = 0;
PageMapIndexer(uint64_t VirtualAddress);
};
/**
* @brief Check if page is present
*
* @param VirtualAddress Virtual address of the page
* @param Flag Flag to check
* @return true if page is present
* @return false if page is not present
*/
bool Check(void *VirtualAddress, PTFlag Flag = PTFlag::P);
/**
* @brief Map page.
*
* @param VirtualAddress Virtual address of the page.
* @param PhysicalAddress Physical address of the page.
* @param Flags Flags of the page. Check PTFlag enum.
*/
void Map(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags);
/**
* @brief Map multiple pages.
*
* @param VirtualAddress First virtual address of the page.
* @param PhysicalAddress First physical address of the page.
* @param PageCount Number of pages.
* @param Flags Flags of the page. Check PTFlag enum.
*/
void Map(void *VirtualAddress, void *PhysicalAddress, uint64_t PageCount, uint64_t Flags);
/**
* @brief Unmap page.
*
* @param VirtualAddress Virtual address of the page.
*/
void Unmap(void *VirtualAddress);
/**
* @brief Unmap multiple pages.
*
* @param VirtualAddress First virtual address of the page.
* @param PageCount Number of pages.
*/
void Unmap(void *VirtualAddress, uint64_t PageCount);
/**
* @brief Remap page.
*
* @param VirtualAddress Virtual address of the page.
* @param PhysicalAddress Physical address of the page.
* @param Flags Flags of the page. Check PTFlag enum.
*/
void Remap(void *VirtualAddress, void *PhysicalAddress, uint64_t Flags);
/**
* @brief Construct a new Virtual object
*
* @param Table Page table. If null, it will use the current page table.
*/
Virtual(PageTable4 *Table = nullptr);
/**
* @brief Destroy the Virtual object
*
*/
~Virtual();
};
class StackGuard
{
private:
void *StackBottom = nullptr;
void *StackTop = nullptr;
void *SGB = nullptr;
void *SGT = nullptr;
uint64_t Size = 0;
bool UserMode = false;
PageTable4 *Table = nullptr;
public:
/** @brief For general info */
void *GetStackBottom() { return StackBottom; }
/** @brief For RSP */
void *GetStackTop() { return StackTop; }
/** @brief Called by exception handler */
bool Expand(uint64_t FaultAddress);
/**
* @brief Construct a new Stack Guard object
* @param User Stack for user mode?
*/
StackGuard(bool User, PageTable4 *Table);
/**
* @brief Destroy the Stack Guard object
*/
~StackGuard();
};
}
/**
* @brief // stub namespace for std::align_val_t and new operator
* @note // Found on https://gcc.gnu.org/legacy-ml/gcc-patches/2016-09/msg00628.html for "_ZnwmSt11align_val_t" compiler error
*/
namespace std
{
typedef __SIZE_TYPE__ size_t;
enum class align_val_t : std::size_t
{
};
}
void InitializeMemoryManagement(BootInfo *Info);
void *operator new(size_t Size);
void *operator new[](size_t Size);
void *operator new(size_t Size, std::align_val_t Alignment);
void operator delete(void *Pointer);
void operator delete[](void *Pointer);
void operator delete(void *Pointer, long unsigned int Size);
void operator delete[](void *Pointer, long unsigned int Size);
extern Memory::Physical KernelAllocator;
extern Memory::PageTable4 *KernelPageTable;
extern Memory::PageTable4 *UserspaceKernelOnlyPageTable;
#endif // __cplusplus
EXTERNC void *HeapMalloc(uint64_t Size);
EXTERNC void *HeapCalloc(uint64_t n, uint64_t Size);
EXTERNC void *HeapRealloc(void *Address, uint64_t Size);
EXTERNC void HeapFree(void *Address);
#define kmalloc(Size) HeapMalloc(Size)
#define kcalloc(n, Size) HeapCalloc(n, Size)
#define krealloc(Address, Size) HeapRealloc(Address, Size)
#define kfree(Address) HeapFree(Address)
#endif // !__FENNIX_KERNEL_INTERNAL_MEMORY_H__

231
Kernel/include/msexec.h Normal file
View File

@ -0,0 +1,231 @@
#ifndef __FENNIX_KERNEL_MSEXEC_H__
#define __FENNIX_KERNEL_MSEXEC_H__
#include <types.h>
// some of the code is from: https://github.com/dotnet/llilc/blob/main/include/clr/ntimage.h
#define near /* __near */
#define far /* __far */
#define NEAR near
#define FAR far
#define CONST const
typedef char CHAR;
typedef unsigned char UCHAR;
typedef wchar_t WCHAR;
typedef unsigned short USHORT;
typedef long LONG;
typedef unsigned long DWORD;
typedef int BOOL;
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef float FLOAT;
typedef FLOAT *PFLOAT;
typedef BOOL near *PBOOL;
typedef BOOL far *LPBOOL;
typedef BYTE near *PBYTE;
typedef BYTE far *LPBYTE;
typedef int near *PINT;
typedef int far *LPINT;
typedef WORD near *PWORD;
typedef WORD far *LPWORD;
typedef long far *LPLONG;
typedef DWORD near *PDWORD;
typedef DWORD far *LPDWORD;
typedef void far *LPVOID;
typedef CONST void far *LPCVOID;
typedef int INT;
typedef unsigned int UINT;
typedef unsigned int *PUINT;
typedef short SHORT;
typedef DWORD ULONG;
typedef double DOUBLE;
#define IMAGE_DOS_SIGNATURE 0x5A4D /* MZ */
#define IMAGE_OS2_SIGNATURE 0x454E /* NE */
#define IMAGE_OS2_SIGNATURE_LE 0x454C /* LE */
#define IMAGE_NT_SIGNATURE 0x00004550 /* PE00 */
#define IMAGE_EDOS_SIGNATURE 0x44454550 /* PEED */
#define IMAGE_SIZEOF_FILE_HEADER 20
#define IMAGE_FILE_MACHINE_UNKNOWN 0
#define IMAGE_FILE_MACHINE_I860 0x14d
#define IMAGE_FILE_MACHINE_I386 0x14c
#define IMAGE_FILE_MACHINE_R3000 0x162
#define IMAGE_FILE_MACHINE_R4000 0x166
#define IMAGE_FILE_MACHINE_R10000 0x0168
#define IMAGE_FILE_MACHINE_ALPHA 0x184
#define IMAGE_FILE_MACHINE_POWERPC 0x01F0
#define IMAGE_FILE_MACHINE_POWERPCBE 0x01F2
#define IMAGE_FILE_MACHINE_SH3 0x01a2
#define IMAGE_FILE_MACHINE_SH3E 0x01a4
#define IMAGE_FILE_MACHINE_SH4 0x01a6
#define IMAGE_FILE_MACHINE_ARM 0x01c0
#define IMAGE_FILE_MACHINE_THUMB 0x01c2
#define IMAGE_FILE_MACHINE_IA64 0x0200
#define IMAGE_FILE_MACHINE_MIPS16 0x0266
#define IMAGE_FILE_MACHINE_MIPSFPU 0x0366
#define IMAGE_FILE_MACHINE_MIPSFPU16 0x0466
#define IMAGE_FILE_MACHINE_ALPHA64 0x0284
#define IMAGE_FILE_MACHINE_AXP64 IMAGE_FILE_MACHINE_ALPHA64
#define IMAGE_FILE_MACHINE_AMD64 0x8664
#define IMAGE_FILE_MACHINE_CEF 0xC0EF
#define IMAGE_NUMBEROF_DIRECTORY_ENTRIES 16
#define IMAGE_DIRECTORY_ENTRY_EXPORT 0
#define IMAGE_DIRECTORY_ENTRY_IMPORT 1
#define IMAGE_DIRECTORY_ENTRY_RESOURCE 2
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION 3
#define IMAGE_DIRECTORY_ENTRY_SECURITY 4
#define IMAGE_DIRECTORY_ENTRY_BASERELOC 5
#define IMAGE_DIRECTORY_ENTRY_DEBUG 6
#define IMAGE_DIRECTORY_ENTRY_ARCHITECTURE 7
#define IMAGE_DIRECTORY_ENTRY_GLOBALPTR 8
#define IMAGE_DIRECTORY_ENTRY_TLS 9
#define IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG 10
#define IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT 11
#define IMAGE_DIRECTORY_ENTRY_IAT 12
#define IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT 13
#define IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR 14
typedef struct _IMAGE_DOS_HEADER // DOS .EXE header
{
USHORT e_magic; // Magic number
USHORT e_cblp; // Bytes on last page of file
USHORT e_cp; // Pages in file
USHORT e_crlc; // Relocations
USHORT e_cparhdr; // Size of header in paragraphs
USHORT e_minalloc; // Minimum extra paragraphs needed
USHORT e_maxalloc; // Maximum extra paragraphs needed
USHORT e_ss; // Initial (relative) SS value
USHORT e_sp; // Initial SP value
USHORT e_csum; // Checksum
USHORT e_ip; // Initial IP value
USHORT e_cs; // Initial (relative) CS value
USHORT e_lfarlc; // File address of relocation table
USHORT e_ovno; // Overlay number
USHORT e_res[4]; // Reserved words
USHORT e_oemid; // OEM identifier (for e_oeminfo)
USHORT e_oeminfo; // OEM information; e_oemid specific
USHORT e_res2[10]; // Reserved words
USHORT e_lfanew; // File address of new exe header
} IMAGE_DOS_HEADER, *PIMAGE_DOS_HEADER;
typedef struct _IMAGE_OS2_HEADER // OS/2 .EXE header
{
USHORT ne_magic; // Magic number
UCHAR ne_ver; // Version number
UCHAR ne_rev; // Revision number
USHORT ne_enttab; // Offset of Entry Table
USHORT ne_cbenttab; // Number of bytes in Entry Table
UINT ne_crc; // Checksum of whole file
USHORT ne_flags; // Flag word
USHORT ne_autodata; // Automatic data segment number
USHORT ne_heap; // Initial heap allocation
USHORT ne_stack; // Initial stack allocation
UINT ne_csip; // Initial CS:IP setting
UINT ne_sssp; // Initial SS:SP setting
USHORT ne_cseg; // Count of file segments
USHORT ne_cmod; // Entries in Module Reference Table
USHORT ne_cbnrestab; // Size of non-resident name table
USHORT ne_segtab; // Offset of Segment Table
USHORT ne_rsrctab; // Offset of Resource Table
USHORT ne_restab; // Offset of resident name table
USHORT ne_modtab; // Offset of Module Reference Table
USHORT ne_imptab; // Offset of Imported Names Table
UINT ne_nrestab; // Offset of Non-resident Names Table
USHORT ne_cmovent; // Count of movable entries
USHORT ne_align; // Segment alignment shift count
USHORT ne_cres; // Count of resource segments
UCHAR ne_exetyp; // Target Operating system
UCHAR ne_flagsothers; // Other .EXE flags
USHORT ne_pretthunks; // offset to return thunks
USHORT ne_psegrefbytes; // offset to segment ref. bytes
USHORT ne_swaparea; // Minimum code swap area size
USHORT ne_expver; // Expected Windows version number
} IMAGE_OS2_HEADER, *PIMAGE_OS2_HEADER;
typedef struct _IMAGE_SECTION_HEADER
{
#define IMAGE_SIZEOF_SHORT_NAME 8
uint8_t Name[IMAGE_SIZEOF_SHORT_NAME];
union
{
uint32_t PhysicalAddress;
uint32_t VirtualSize;
} Misc;
uint32_t VirtualAddress;
uint32_t SizeOfRawData;
uint32_t PointerToRawData;
uint32_t PointerToRelocations;
uint32_t PointerToLinenumbers;
uint16_t NumberOfRelocations;
uint16_t NumberOfLinenumbers;
uint32_t Characteristics;
} IMAGE_SECTION_HEADER, *PIMAGE_SECTION_HEADER;
typedef struct _IMAGE_FILE_HEADER
{
uint16_t Machine;
uint16_t NumberOfSections;
uint32_t TimeDateStamp;
uint32_t PointerToSymbolTable;
uint32_t NumberOfSymbols;
uint16_t SizeOfOptionalHeader;
uint16_t Characteristics;
} IMAGE_FILE_HEADER, *PIMAGE_FILE_HEADER;
typedef struct _IMAGE_DATA_DIRECTORY
{
uint32_t VirtualAddress;
uint32_t Size;
} IMAGE_DATA_DIRECTORY, *PIMAGE_DATA_DIRECTORY;
typedef struct _IMAGE_OPTIONAL_HEADER
{
uint16_t Magic;
uint8_t MajorLinkerVersion;
uint8_t MinorLinkerVersion;
uint32_t SizeOfCode;
uint32_t SizeOfInitializedData;
uint32_t SizeOfUninitializedData;
uint32_t AddressOfEntryPoint;
uint32_t BaseOfCode;
uint32_t BaseOfData;
uint32_t ImageBase;
uint32_t SectionAlignment;
uint32_t FileAlignment;
uint16_t MajorOperatingSystemVersion;
uint16_t MinorOperatingSystemVersion;
uint16_t MajorImageVersion;
uint16_t MinorImageVersion;
uint16_t MajorSubsystemVersion;
uint16_t MinorSubsystemVersion;
uint32_t Win32VersionValue;
uint32_t SizeOfImage;
uint32_t SizeOfHeaders;
uint32_t CheckSum;
uint16_t Subsystem;
uint16_t DllCharacteristics;
uint32_t SizeOfStackReserve;
uint32_t SizeOfStackCommit;
uint32_t SizeOfHeapReserve;
uint32_t SizeOfHeapCommit;
uint32_t LoaderFlags;
uint32_t NumberOfRvaAndSizes;
IMAGE_DATA_DIRECTORY DataDirectory[IMAGE_NUMBEROF_DIRECTORY_ENTRIES];
} IMAGE_OPTIONAL_HEADER, *PIMAGE_OPTIONAL_HEADER;
typedef struct _IMAGE_NT_HEADERS
{
uint32_t Signature;
IMAGE_FILE_HEADER FileHeader;
IMAGE_OPTIONAL_HEADER OptionalHeader;
} IMAGE_NT_HEADERS, *PIMAGE_NT_HEADERS;
#endif // !__FENNIX_KERNEL_MSEXEC_H__

157
Kernel/include/pci.hpp Normal file
View File

@ -0,0 +1,157 @@
#ifndef __FENNIX_KERNEL_PCI_H__
#define __FENNIX_KERNEL_PCI_H__
#include <types.h>
#include <vector.hpp>
#include <debug.h>
namespace PCI
{
namespace Descriptors
{
enum PCIVendors
{
SymbiosLogic = 0x1000,
RedHat = 0x1AF4,
REDHat2 = 0x1B36,
Realtek = 0x10EC,
VirtualBox = 0x80EE,
Ensoniq = 0x1274,
QEMU = 0x1234,
VMware = 0x15AD,
IntelCorporation = 0x8086,
AdvancedMicroDevices = 0x1022,
NVIDIACorporation = 0x10DE
};
const char *const DeviceClasses[]{
"Unclassified",
"Mass Storage Controller",
"Network Controller",
"Display Controller",
"Multimedia Controller",
"Memory Controller",
"Bridge Device",
"Simple Communication Controller",
"Base System Peripheral",
"Input Device Controller",
"Docking Station",
"Processor",
"Serial Bus Controller",
"Wireless Controller",
"Intelligent Controller",
"Satellite Communication Controller",
"Encryption Controller",
"Signal Processing Controller",
"Processing Accelerator",
"Non Essential Instrumentation"};
const char *MassStorageControllerSubclassName(uint8_t SubclassCode);
const char *NetworkControllerSubclassName(uint8_t SubclassCode);
const char *DisplayControllerSubclassName(uint8_t SubclassCode);
const char *CommunicationControllerSubclassName(uint8_t SubclassCode);
const char *BaseSystemPeripheralSubclassName(uint8_t SubclassCode);
const char *SerialBusControllerSubclassName(uint8_t SubclassCode);
const char *BridgeDeviceSubclassName(uint8_t SubclassCode);
const char *WirelessControllerSubclassName(uint8_t SubclassCode);
const char *GetVendorName(uint32_t VendorID);
const char *GetDeviceName(uint32_t VendorID, uint32_t DeviceID);
const char *GetSubclassName(uint8_t ClassCode, uint8_t SubclassCode);
const char *GetProgIFName(uint8_t ClassCode, uint8_t SubclassCode, uint8_t ProgIF);
}
/* https://sites.uclouvain.be/SystInfo/usr/include/linux/pci_regs.h.html */
enum PCICommands
{
/** @brief Enable response in I/O space */
PCI_COMMAND_IO = 0x1,
/** @brief Enable response in Memory space */
PCI_COMMAND_MEMORY = 0x2,
/** @brief Enable bus mastering */
PCI_COMMAND_MASTER = 0x4,
/** @brief Enable response to special cycles */
PCI_COMMAND_SPECIAL = 0x8,
/** @brief Use memory write and invalidate */
PCI_COMMAND_INVALIDATE = 0x10,
/** @brief Enable palette snooping */
PCI_COMMAND_VGA_PALETTE = 0x20,
/** @brief Enable parity checking */
PCI_COMMAND_PARITY = 0x40,
/** @brief Enable address/data stepping */
PCI_COMMAND_WAIT = 0x80,
/** @brief Enable SERR */
PCI_COMMAND_SERR = 0x100,
/** @brief Enable back-to-back writes */
PCI_COMMAND_FAST_BACK = 0x200,
/** @brief INTx Emulation Disable */
PCI_COMMAND_INTX_DISABLE = 0x400
};
struct PCIDeviceHeader
{
uint16_t VendorID;
uint16_t DeviceID;
uint16_t Command;
uint16_t Status;
uint8_t RevisionID;
uint8_t ProgIF;
uint8_t Subclass;
uint8_t Class;
uint8_t CacheLineSize;
uint8_t LatencyTimer;
uint8_t HeaderType;
uint8_t BIST;
};
struct PCIHeader0
{
PCIDeviceHeader Header;
uint32_t BAR0;
uint32_t BAR1;
uint32_t BAR2;
uint32_t BAR3;
uint32_t BAR4;
uint32_t BAR5;
uint32_t CardbusCISPtr;
uint16_t SubsystemVendorID;
uint16_t SubsystemID;
uint32_t ExpansionROMBaseAddr;
uint8_t CapabilitiesPtr;
uint8_t Rsv0;
uint16_t Rsv1;
uint32_t Rsv2;
uint8_t InterruptLine;
uint8_t InterruptPin;
uint8_t MinGrant;
uint8_t MaxLatency;
};
struct DeviceConfig
{
uint64_t BaseAddress;
uint16_t PCISegGroup;
uint8_t StartBus;
uint8_t EndBus;
uint32_t Reserved;
} __attribute__((packed));
class PCI
{
private:
Vector<PCIDeviceHeader *> Devices;
public:
Vector<PCIDeviceHeader *> &GetDevices() { return Devices; }
void EnumerateFunction(uint64_t DeviceAddress, uint64_t Function);
void EnumerateDevice(uint64_t BusAddress, uint64_t Device);
void EnumerateBus(uint64_t BaseAddress, uint64_t Bus);
Vector<PCIDeviceHeader *> FindPCIDevice(uint8_t Class, uint8_t Subclass, uint8_t ProgIF);
Vector<PCIDeviceHeader *> FindPCIDevice(int VendorID, int DeviceID);
PCI();
~PCI();
};
}
#endif // !__FENNIX_KERNEL_PCI_H__

53
Kernel/include/power.hpp Normal file
View File

@ -0,0 +1,53 @@
#ifndef __FENNIX_KERNEL_POWER_H__
#define __FENNIX_KERNEL_POWER_H__
#include <types.h>
namespace Power
{
class Power
{
private:
void *acpi = nullptr;
void *dsdt = nullptr;
void *madt = nullptr;
public:
/**
* @brief Get Advanced Configuration and Power Interface. (Available only on x32 and x64)
*
* @return void* (ACPI::ACPI *)
*/
void *GetACPI() { return this->acpi; }
/**
* @brief Get Differentiated System Description Table. (Available only on x32 and x64)
*
* @return void* (ACPI::DSDT *)
*/
void *GetDSDT() { return this->dsdt; }
/**
* @brief Get Multiple APIC Description Table. (Available only on x32 and x64)
*
* @return void* (ACPI::MADT *)
*/
void *GetMADT() { return this->madt; }
/**
* @brief Reboot the system.
*/
void Reboot();
/**
* @brief Shutdown the system.
*/
void Shutdown();
void InitDSDT();
Power();
~Power();
};
}
#endif // !__FENNIX_KERNEL_POWER_H__

194
Kernel/include/printf.h Normal file
View File

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

14
Kernel/include/rand.hpp Normal file
View File

@ -0,0 +1,14 @@
#ifndef __FENNIX_KERNEL_RANDOM_H__
#define __FENNIX_KERNEL_RANDOM_H__
#include <types.h>
namespace Random
{
uint16_t rand16();
uint32_t rand32();
uint64_t rand64();
void changeseed(uint64_t CustomSeed);
}
#endif // !__FENNIX_KERNEL_RANDOM_H__

View File

@ -0,0 +1,11 @@
#ifndef __FENNIX_KERNEL_RECOVERY_H__
#define __FENNIX_KERNEL_RECOVERY_H__
#include <types.h>
namespace Recovery
{
}
#endif // !__FENNIX_KERNEL_RECOVERY_H__

154
Kernel/include/smartptr.hpp Normal file
View File

@ -0,0 +1,154 @@
#ifndef __FENNIX_KERNEL_SMART_POINTER_H__
#define __FENNIX_KERNEL_SMART_POINTER_H__
#include <types.h>
#include <debug.h>
// show debug messages
// #define DEBUG_SMARTPOINTERS 1
#ifdef DEBUG_SMARTPOINTERS
#define spdbg(m, ...) debug(m, ##__VA_ARGS__)
#else
#define spdbg(m, ...)
#endif
/**
* @brief A smart pointer class
*
* This class is a smart pointer class. It is used to manage the lifetime of
* objects. It is a reference counted pointer, so when the last reference to
* the object is removed, the object is deleted.
*
* Basic Usage:
* smart_ptr<char> pointer(new char());
* *pointer = 'a';
* printf("%c", *pointer); // Prints "a"
*/
template <class T>
class smart_ptr
{
T *RealPointer;
public:
explicit smart_ptr(T *p = nullptr)
{
spdbg("Smart pointer created (%#lx)", RealPointer);
RealPointer = p;
}
~smart_ptr()
{
spdbg("Smart pointer deleted (%#lx)", RealPointer);
delete (RealPointer);
}
T &operator*()
{
spdbg("Smart pointer dereferenced (%#lx)", RealPointer);
return *RealPointer;
}
T *operator->()
{
spdbg("Smart pointer dereferenced (%#lx)", RealPointer);
return RealPointer;
}
};
template <class T>
class auto_ptr
{
};
template <class T>
class unique_ptr
{
};
template <typename T>
class shared_ptr
{
private:
class Counter
{
private:
unsigned int RefCount{};
public:
Counter() : RefCount(0){};
Counter(const Counter &) = delete;
Counter &operator=(const Counter &) = delete;
~Counter() {}
void Reset() { RefCount = 0; }
unsigned int Get() { return RefCount; }
void operator++() { RefCount++; }
void operator++(int) { RefCount++; }
void operator--() { RefCount--; }
void operator--(int) { RefCount--; }
};
Counter *ReferenceCounter;
T *RealPointer;
public:
explicit shared_ptr(T *Pointer = nullptr)
{
spdbg("Shared pointer created (%#lx)", RealPointer);
RealPointer = Pointer;
ReferenceCounter = new Counter();
if (Pointer)
(*ReferenceCounter)++;
}
shared_ptr(shared_ptr<T> &SPtr)
{
spdbg("Shared pointer copied (%#lx)", RealPointer);
RealPointer = SPtr.RealPointer;
ReferenceCounter = SPtr.ReferenceCounter;
(*ReferenceCounter)++;
}
~shared_ptr()
{
spdbg("Shared pointer deleted (%#lx)", RealPointer);
(*ReferenceCounter)--;
if (ReferenceCounter->Get() == 0)
{
delete ReferenceCounter;
delete RealPointer;
}
}
unsigned int GetCount()
{
spdbg("Shared pointer count (%#lx)", RealPointer);
return ReferenceCounter->Get();
}
T *Get()
{
spdbg("Shared pointer get (%#lx)", RealPointer);
return RealPointer;
}
T &operator*()
{
spdbg("Shared pointer dereference (%#lx)", RealPointer);
return *RealPointer;
}
T *operator->()
{
spdbg("Shared pointer dereference (%#lx)", RealPointer);
return RealPointer;
}
};
template <class T>
class weak_ptr
{
};
#endif // !__FENNIX_KERNEL_SMART_POINTER_H__

56
Kernel/include/smp.hpp Normal file
View File

@ -0,0 +1,56 @@
#ifndef __FENNIX_KERNEL_SMP_H__
#define __FENNIX_KERNEL_SMP_H__
#include <types.h>
#include <task.hpp>
/** @brief Maximum supported number of CPU cores by the kernel */
#define MAX_CPU 256
#define CPU_DATA_CHECKSUM 0xC0FFEE
struct CPUArchData
{
#if defined(__amd64__)
int stub;
/* TODO */
#elif defined(__i386__)
#elif defined(__aarch64__)
#endif
};
struct CPUData
{
/** @brief Used by syscall handler */
uint8_t *SystemCallStack; /* gs+0x0 */
/** @brief Used by syscall handler */
uint64_t TempStack; /* gs+0x8 */
/** @brief Used by CPU */
uint64_t Stack;
/** @brief CPU ID. */
long ID;
/** @brief Local CPU error code. */
long ErrorCode;
/** @brief Is CPU online? */
bool IsActive;
/** @brief Current running process */
Tasking::PCB *CurrentProcess;
/** @brief Current running thread */
Tasking::TCB *CurrentThread;
/** @brief Architecture-specific data. */
CPUArchData *Data;
/** @brief Checksum. Used to verify the integrity of the data. Must be equal to CPU_DATA_CHECKSUM (0xC0FFEE). */
int Checksum;
} __attribute__((packed));
CPUData *GetCurrentCPU();
CPUData *GetCPU(long ID);
namespace SMP
{
extern int CPUCores;
void Initialize(void *madt);
}
#endif // !__FENNIX_KERNEL_SMP_H__

6
Kernel/include/stdint.h Normal file
View File

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

View File

@ -0,0 +1,21 @@
#pragma once
#include <types.h>
namespace SymbolResolver
{
class Symbols
{
public:
struct SymbolTable
{
uint64_t Address;
char *FunctionName;
};
Symbols(uint64_t Address);
~Symbols();
const char *GetSymbolFromAddress(uint64_t Address);
};
}
extern SymbolResolver::Symbols *SymTbl;

14
Kernel/include/sys.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef __FENNIX_KERNEL_SYSTEM_H__
#define __FENNIX_KERNEL_SYSTEM_H__
#include <types.h>
#include <cpu.hpp>
// TODO: Add actual panic screen
#define panic(msg) \
{ \
error(msg); \
CPU::Stop(); \
}
#endif // !__FENNIX_KERNEL_SYSTEM_H__

View File

@ -0,0 +1,27 @@
#ifndef __FENNIX_KERNEL_SYSCALLS_H__
#define __FENNIX_KERNEL_SYSCALLS_H__
#include <types.h>
typedef struct SyscallsFrame
{
#if defined(__amd64__)
uint64_t r15, r14, r13, r12, r11, r10, r9, r8;
uint64_t rbp, rdi, rsi, rdx, rcx, rbx, rax;
uint64_t InterruptNumber, ErrorCode, rip, cs, rflags, rsp, ss;
#elif defined(__i386__)
uint64_t ebp, edi, esi, edx, ecx, ebx, eax;
uint64_t InterruptNumber, ErrorCode, eip, cs, eflags, esp, ss;
#elif defined(__aarch64__)
#endif
} SyscallsFrame;
uint64_t HandleNativeSyscalls(SyscallsFrame *Frame);
uint64_t HandleLinuxSyscalls(SyscallsFrame *Frame);
/**
* @brief Initialize syscalls for the current CPU. (Function is available on x32, x64 & aarch64)
*/
void InitializeSystemCalls();
#endif // !__FENNIX_KERNEL_SYSCALLS_H__

276
Kernel/include/task.hpp Normal file
View File

@ -0,0 +1,276 @@
#ifndef __FENNIX_KERNEL_TASKING_H__
#define __FENNIX_KERNEL_TASKING_H__
#include <types.h>
#include <interrupts.hpp>
#include <vector.hpp>
#include <memory.hpp>
#include <hashmap.hpp>
#include <ipc.hpp>
#include <debug.h>
#include <abi.h>
namespace Tasking
{
typedef unsigned long IP;
typedef unsigned long IPOffset;
typedef unsigned long UPID;
typedef unsigned long UTID;
typedef unsigned long Token;
enum TaskArchitecture
{
UnknownArchitecture,
x32,
x64,
ARM,
ARM64
};
enum TaskCompatibility
{
UnknownPlatform,
Native,
Linux,
Windows
};
enum TaskTrustLevel
{
UnknownElevation,
Kernel,
System,
Idle,
User
};
enum TaskStatus
{
UnknownStatus,
Ready,
Running,
Sleeping,
Waiting,
Stopped,
Terminated
};
struct TaskSecurity
{
TaskTrustLevel TrustLevel;
Token UniqueToken;
bool IsCritical;
};
struct TaskInfo
{
uint64_t SpawnTime = 0;
uint64_t OldUserTime = 0, CurrentUserTime = 0;
uint64_t OldKernelTime = 0, CurrentKernelTime = 0;
uint64_t KernelTime = 0, UserTime = 0;
uint64_t Year, Month, Day, Hour, Minute, Second;
uint64_t Usage[256]; // MAX_CPU
bool Affinity[256]; // MAX_CPU
int Priority;
TaskArchitecture Architecture;
TaskCompatibility Compatibility;
};
struct TCB
{
UTID ID;
char Name[256];
struct PCB *Parent;
IP EntryPoint;
IPOffset Offset;
int ExitCode;
Memory::StackGuard *Stack;
TaskStatus Status;
#if defined(__amd64__)
CPU::x64::TrapFrame Registers;
uint64_t GSBase, FSBase;
#elif defined(__i386__)
uint32_t Registers; // TODO
#elif defined(__aarch64__)
uint64_t Registers; // TODO
#endif
TaskSecurity Security;
TaskInfo Info;
char FXRegion[512] __attribute__((aligned(16)));
void Rename(const char *name)
{
CriticalSection cs;
if (!Name[0])
{
warn("Tried to rename thread %d to NULL", ID);
return;
}
trace("Renaming thread %s to %s", Name, name);
for (int i = 0; i < 256; i++)
{
Name[i] = name[i];
if (name[i] == '\0')
break;
}
}
void SetPriority(int priority)
{
CriticalSection cs;
trace("Setting priority of thread %s to %d", Name, priority);
Info.Priority = priority;
}
int GetExitCode() { return ExitCode; }
void SetCritical(bool critical)
{
CriticalSection cs;
trace("Setting criticality of thread %s to %s", Name, critical ? "true" : "false");
Security.IsCritical = critical;
}
};
struct PCB
{
UPID ID;
char Name[256];
PCB *Parent;
int ExitCode;
TaskStatus Status;
TaskSecurity Security;
TaskInfo Info;
Vector<TCB *> Threads;
Vector<PCB *> Children;
HashMap<InterProcessCommunication::IPCPort, uint64_t> *IPCHandles;
Memory::PageTable4 *PageTable;
};
enum TokenTrustLevel
{
UnknownTrustLevel,
Untrusted,
Trusted,
TrustedByKernel
};
class Security
{
public:
Token CreateToken();
bool TrustToken(Token token,
TokenTrustLevel TrustLevel);
bool UntrustToken(Token token);
bool DestroyToken(Token token);
Security();
~Security();
};
class Task : public Interrupts::Handler
{
private:
Security SecurityManager;
InterProcessCommunication::IPC *IPCManager = nullptr;
UPID NextPID = 0;
UTID NextTID = 0;
Vector<PCB *> ListProcess;
PCB *IdleProcess = nullptr;
TCB *IdleThread = nullptr;
bool InvalidPCB(PCB *pcb);
bool InvalidTCB(TCB *tcb);
void RemoveThread(TCB *tcb);
void RemoveProcess(PCB *pcb);
void UpdateUserTime(TaskInfo *Info);
void UpdateKernelTime(TaskInfo *Info);
void UpdateUsage(TaskInfo *Info, int Core);
bool FindNewProcess(void *CPUDataPointer);
bool GetNextAvailableThread(void *CPUDataPointer);
bool GetNextAvailableProcess(void *CPUDataPointer);
void SchedulerCleanupProcesses();
bool SchedulerSearchProcessThread(void *CPUDataPointer);
#if defined(__amd64__)
void Schedule(CPU::x64::TrapFrame *Frame);
void OnInterruptReceived(CPU::x64::TrapFrame *Frame);
#elif defined(__i386__)
void Schedule(void *Frame);
void OnInterruptReceived(void *Frame);
#elif defined(__aarch64__)
void Schedule(void *Frame);
void OnInterruptReceived(void *Frame);
#endif
bool StopScheduler = false;
public:
void InitIPC()
{
static int once = 0;
if (!once++)
this->IPCManager = new InterProcessCommunication::IPC();
}
Vector<PCB *> GetProcessList() { return ListProcess; }
void Panic() { StopScheduler = true; }
void Schedule();
long GetUsage(int Core)
{
if (IdleProcess)
return 100 - IdleProcess->Info.Usage[Core];
else
return 0;
}
void KillThread(TCB *tcb, int Code)
{
tcb->Status = TaskStatus::Terminated;
tcb->ExitCode = Code;
}
void KillProcess(PCB *pcb, int Code)
{
pcb->Status = TaskStatus::Terminated;
pcb->ExitCode = Code;
}
/**
* @brief Get the Current Process object
* @return PCB*
*/
PCB *GetCurrentProcess();
/**
* @brief Get the Current Thread object
* @return TCB*
*/
TCB *GetCurrentThread();
/** @brief Wait for process to terminate */
void WaitForProcess(PCB *pcb);
/** @brief Wait for thread to terminate */
void WaitForThread(TCB *tcb);
PCB *CreateProcess(PCB *Parent,
const char *Name,
TaskTrustLevel TrustLevel);
TCB *CreateThread(PCB *Parent,
IP EntryPoint,
const char **argv,
const char **envp,
Vector<AuxiliaryVector> &auxv,
IPOffset Offset = 0,
TaskArchitecture Architecture = TaskArchitecture::x64,
TaskCompatibility Compatibility = TaskCompatibility::Native);
Task(const IP EntryPoint);
~Task();
};
}
#endif // !__FENNIX_KERNEL_TASKING_H__

43
Kernel/include/time.hpp Normal file
View File

@ -0,0 +1,43 @@
#ifndef __FENNIX_KERNEL_TIME_H__
#define __FENNIX_KERNEL_TIME_H__
#include <types.h>
namespace Time
{
struct Clock
{
uint64_t Year, Month, Day, Hour, Minute, Second;
uint64_t Counter;
};
Clock ReadClock();
class time
{
private:
struct HPET
{
uint64_t GeneralCapabilities;
uint64_t Reserved0;
uint64_t GeneralConfiguration;
uint64_t Reserved1;
uint64_t GeneralIntStatus;
uint64_t Reserved2;
uint64_t Reserved3[24];
uint64_t MainCounterValue;
uint64_t Reserved4;
};
void *acpi;
void *hpet;
uint32_t clk = 0;
public:
void Sleep(uint64_t Milliseconds);
time(void *acpi);
~time();
};
}
#endif // !__FENNIX_KERNEL_TIME_H__

268
Kernel/include/types.h Normal file
View File

@ -0,0 +1,268 @@
#ifndef __FENNIX_KERNEL_TYPES_H__
#define __FENNIX_KERNEL_TYPES_H__
#ifdef __cplusplus
#define EXTERNC extern "C"
#define START_EXTERNC \
EXTERNC \
{
#define END_EXTERNC \
}
#else
#define EXTERNC
#define START_EXTERNC
#define END_EXTERNC
#endif
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#define bool _Bool
#endif
#define asm __asm__
#define asmv __asm__ volatile
#define true 1
#define false 0
#ifdef __cplusplus
#define foreach for
#define in :
#endif
#define UNUSED(x) (void)(x)
#define CONCAT(x, y) x##y
#define toupper(c) ((c)-0x20 * (((c) >= 'a') && ((c) <= 'z')))
#define tolower(c) ((c) + 0x20 * (((c) >= 'A') && ((c) <= 'Z')))
#ifndef __va_list__
typedef __builtin_va_list va_list;
#endif
#define va_start(v, l) __builtin_va_start(v, l)
#define va_end(v) __builtin_va_end(v)
#define va_arg(v, l) __builtin_va_arg(v, l)
#define ALIGN_UP(x, align) ((__typeof__(x))(((uint64_t)(x) + ((align)-1)) & (~((align)-1))))
#define ALIGN_DOWN(x, align) ((__typeof__(x))((x) & (~((align)-1))))
#define offsetof(type, member) __builtin_offsetof(type, member)
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define VPOKE(type, address) (*((volatile type *)(address)))
#define POKE(type, address) (*((type *)(address)))
#ifndef __cplusplus
#ifdef __STDC__
#ifdef __STDC_VERSION__
#if (__STDC_VERSION__ >= 201710L)
#define C_LANGUAGE_STANDARD 2018
#elif (__STDC_VERSION__ >= 201112L)
#define C_LANGUAGE_STANDARD 2011
#elif (__STDC_VERSION__ >= 199901L)
#define C_LANGUAGE_STANDARD 1999
#elif (__STDC_VERSION__ >= 199409L)
#define C_LANGUAGE_STANDARD 1995
#endif
#else
#define C_LANGUAGE_STANDARD 1990
#endif
#else
#define C_LANGUAGE_STANDARD 1972
#endif
#else
#ifdef __STDC__
#ifdef __cplusplus
#if (__cplusplus >= 202100L)
#define CPP_LANGUAGE_STANDARD 2023
#elif (__cplusplus >= 202002L)
#define CPP_LANGUAGE_STANDARD 2020
#elif (__cplusplus >= 201703L)
#define CPP_LANGUAGE_STANDARD 2017
#elif (__cplusplus >= 201402L)
#define CPP_LANGUAGE_STANDARD 2014
#elif (__cplusplus >= 201103L)
#define CPP_LANGUAGE_STANDARD 2011
#elif (__cplusplus >= 199711L)
#define CPP_LANGUAGE_STANDARD 1998
#endif
#else
#define CPP_LANGUAGE_STANDARD __cplusplus
#endif
#else
#define CPP_LANGUAGE_STANDARD __cplusplus
#endif
#endif // __cplusplus
typedef __INT8_TYPE__ int8_t;
typedef __INT16_TYPE__ int16_t;
typedef __INT32_TYPE__ int32_t;
typedef __INT64_TYPE__ int64_t;
typedef __UINT8_TYPE__ uint8_t;
typedef __UINT16_TYPE__ uint16_t;
typedef __UINT32_TYPE__ uint32_t;
typedef __UINT64_TYPE__ uint64_t;
typedef __INT_LEAST8_TYPE__ int_least8_t;
typedef __INT_LEAST16_TYPE__ int_least16_t;
typedef __INT_LEAST32_TYPE__ int_least32_t;
typedef __INT_LEAST64_TYPE__ int_least64_t;
typedef __UINT_LEAST8_TYPE__ uint_least8_t;
typedef __UINT_LEAST16_TYPE__ uint_least16_t;
typedef __UINT_LEAST32_TYPE__ uint_least32_t;
typedef __UINT_LEAST64_TYPE__ uint_least64_t;
typedef __INT_FAST8_TYPE__ int_fast8_t;
typedef __INT_FAST16_TYPE__ int_fast16_t;
typedef __INT_FAST32_TYPE__ int_fast32_t;
typedef __INT_FAST64_TYPE__ int_fast64_t;
typedef __UINT_FAST8_TYPE__ uint_fast8_t;
typedef __UINT_FAST16_TYPE__ uint_fast16_t;
typedef __UINT_FAST32_TYPE__ uint_fast32_t;
typedef __UINT_FAST64_TYPE__ uint_fast64_t;
typedef __INTPTR_TYPE__ intptr_t;
typedef __UINTPTR_TYPE__ uintptr_t;
typedef __INTMAX_TYPE__ intmax_t;
typedef __UINTMAX_TYPE__ uintmax_t;
typedef __PTRDIFF_TYPE__ ptrdiff_t;
typedef __SIZE_TYPE__ size_t;
#define INT8_MAX __INT8_MAX__
#define INT8_MIN (-INT8_MAX - 1)
#define UINT8_MAX __UINT8_MAX__
#define INT16_MAX __INT16_MAX__
#define INT16_MIN (-INT16_MAX - 1)
#define UINT16_MAX __UINT16_MAX__
#define INT32_MAX __INT32_MAX__
#define INT32_MIN (-INT32_MAX - 1)
#define UINT32_MAX __UINT32_MAX__
#define INT64_MAX __INT64_MAX__
#define INT64_MIN (-INT64_MAX - 1)
#define UINT64_MAX __UINT64_MAX__
#define INT_LEAST8_MAX __INT_LEAST8_MAX__
#define INT_LEAST8_MIN (-INT_LEAST8_MAX - 1)
#define UINT_LEAST8_MAX __UINT_LEAST8_MAX__
#define INT_LEAST16_MAX __INT_LEAST16_MAX__
#define INT_LEAST16_MIN (-INT_LEAST16_MAX - 1)
#define UINT_LEAST16_MAX __UINT_LEAST16_MAX__
#define INT_LEAST32_MAX __INT_LEAST32_MAX__
#define INT_LEAST32_MIN (-INT_LEAST32_MAX - 1)
#define UINT_LEAST32_MAX __UINT_LEAST32_MAX__
#define INT_LEAST64_MAX __INT_LEAST64_MAX__
#define INT_LEAST64_MIN (-INT_LEAST64_MAX - 1)
#define UINT_LEAST64_MAX __UINT_LEAST64_MAX__
#define INT_FAST8_MAX __INT_FAST8_MAX__
#define INT_FAST8_MIN (-INT_FAST8_MAX - 1)
#define UINT_FAST8_MAX __UINT_FAST8_MAX__
#define INT_FAST16_MAX __INT_FAST16_MAX__
#define INT_FAST16_MIN (-INT_FAST16_MAX - 1)
#define UINT_FAST16_MAX __UINT_FAST16_MAX__
#define INT_FAST32_MAX __INT_FAST32_MAX__
#define INT_FAST32_MIN (-INT_FAST32_MAX - 1)
#define UINT_FAST32_MAX __UINT_FAST32_MAX__
#define INT_FAST64_MAX __INT_FAST64_MAX__
#define INT_FAST64_MIN (-INT_FAST64_MAX - 1)
#define UINT_FAST64_MAX __UINT_FAST64_MAX__
#define INTPTR_MAX __INTPTR_MAX__
#define INTPTR_MIN (-INTPTR_MAX - 1)
#define UINTPTR_MAX __UINTPTR_MAX__
#define INTMAX_MAX __INTMAX_MAX__
#define INTMAX_MIN (-INTMAX_MAX - 1)
#define UINTMAX_MAX __UINTMAX_MAX__
#define PTRDIFF_MAX __PTRDIFF_MAX__
#define PTRDIFF_MIN (-PTRDIFF_MAX - 1)
#define SIG_ATOMIC_MAX __SIG_ATOMIC_MAX__
#define SIG_ATOMIC_MIN __SIG_ATOMIC_MIN__
#define SIZE_MAX __SIZE_MAX__
#define WCHAR_MAX __WCHAR_MAX__
#define WCHAR_MIN __WCHAR_MIN__
#define WINT_MAX __WINT_MAX__
#define WINT_MIN __WINT_MIN__
#define b4(x) ((x & 0x0F) << 4 | (x & 0xF0) >> 4)
#define b8(x) ((x)&0xFF)
#define b16(x) __builtin_bswap16(x)
#define b32(x) __builtin_bswap32(x)
#define b48(x) (((((x)&0x0000000000ff) << 40) | (((x)&0x00000000ff00) << 24) | (((x)&0x000000ff0000) << 8) | (((x)&0x0000ff000000) >> 8) | (((x)&0x00ff00000000) >> 24) | (((x)&0xff0000000000) >> 40)))
#define b64(x) __builtin_bswap64(x)
#define O0 __attribute__((optimize("O0")))
#define O1 __attribute__((optimize("O1")))
#define O2 __attribute__((optimize("O2")))
#define O3 __attribute__((optimize("O3")))
#define Os __attribute__((optimize("Os")))
#define Ofast __attribute__((optimize("Ofast")))
/** @brief dbg */
#define OPTMZ O0
#define __unused __attribute__((unused))
#define __packed __attribute__((packed))
#define __naked __attribute__((naked))
#define __aligned(x) __attribute__((aligned(x)))
#define __section(x) __attribute__((section(x)))
#define __noreturn __attribute__((noreturn))
#define __weak __attribute__((weak))
#define __alias(x) __attribute__((alias(x)))
#define __always_inline __attribute__((always_inline))
#define __noinline __attribute__((noinline))
#define __pure __attribute__((pure))
#define __const __attribute__((const))
#define __malloc __attribute__((malloc))
#define __returns_twice __attribute__((returns_twice))
#define __used __attribute__((used))
#define __deprecated __attribute__((deprecated))
#define __deprecated_msg(x) __attribute__((deprecated(x)))
#define __weakref(x) __attribute__((weakref(x)))
#define __weakrefalias(x) __attribute__((weakref(#x)))
#define __visibility(x) __attribute__((visibility(x)))
#define __constructor __attribute__((constructor))
#define __destructor __attribute__((destructor))
#define __cleanup(x) __attribute__((cleanup(x)))
#define __fallthrough __attribute__((fallthrough))
#define __nonnull(x) __attribute__((nonnull x))
#define __nonnull_all __attribute__((nonnull))
#define __returns_nonnull __attribute__((returns_nonnull))
#define __sentinel __attribute__((sentinel))
#define __sentinel_all __attribute__((sentinel(0)))
#define __format(x, y, z) __attribute__((format(x, y, z)))
#define __format_arg(x) __attribute__((format_arg(x)))
#define __nonnull_params(x) __attribute__((nonnull x))
#define __nonnull_all __attribute__((nonnull))
#define __warn_unused_result __attribute__((warn_unused_result))
#define __no_stack_protector __attribute__((no_stack_protector))
#define __no_instrument_function __attribute__((no_instrument_function))
// sanitizer
#define __no_sanitize_address __attribute__((no_sanitize_address))
#define __no_sanitize_undefined __attribute__((no_sanitize_undefined))
#define __no_address_safety_analysis __attribute__((no_address_safety_analysis))
#define __no_sanitize_thread __attribute__((no_sanitize_thread))
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#define SafeFunction __no_stack_protector __no_sanitize_address __no_sanitize_undefined __no_address_safety_analysis __no_sanitize_thread
#endif // !__FENNIX_KERNEL_TYPES_H__

71
Kernel/include/uart.hpp Normal file
View File

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

167
Kernel/include/vector.hpp Normal file
View File

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