Compare commits
28 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b7a4a90e63 | |||
| 41578c29d6 | |||
| d42fc79c25 | |||
| b44e1924ed | |||
| 4909e40cb1 | |||
| 7102edfa5a | |||
| 47735bb1bd | |||
| 2f58f64175 | |||
| 4e10985909 | |||
| c72dbc763c | |||
| 02b36283a5 | |||
| e21f5ef52f | |||
| 2be7d3bd46 | |||
| 02dc35f0df | |||
| ee67cef4f8 | |||
| c30d57d06e | |||
| 4e6794a6c2 | |||
| e63983c95d | |||
| e323e91dac | |||
| 52d0bfeaae | |||
| ae7e1a91d0 | |||
| c5741374cd | |||
| 385b7d7a13 | |||
| 3f95b6d282 | |||
| 92aaa47435 | |||
| caf2d2b4a8 | |||
| 888bc5abdd | |||
| 9c103218d0 |
@@ -1,7 +1,9 @@
|
|||||||
.cache
|
.cache
|
||||||
|
.vscode
|
||||||
build*
|
build*
|
||||||
.venv
|
.venv
|
||||||
initrd/image.cpio
|
initrd/image.cpio
|
||||||
initramfs/*
|
initramfs/*
|
||||||
|
|
||||||
target
|
target
|
||||||
|
Cargo.lock
|
||||||
+1
-1
@@ -3,7 +3,7 @@ build
|
|||||||
.venv
|
.venv
|
||||||
kernel/data
|
kernel/data
|
||||||
*.md
|
*.md
|
||||||
tools/
|
|
||||||
bootloader/
|
bootloader/
|
||||||
bootloader/src/uefi
|
bootloader/src/uefi
|
||||||
initramfs/
|
initramfs/
|
||||||
|
kernel/inc/Data
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
project(termOS_Bootloader LANGUAGES C ASM)
|
project(termOS_Bootloader LANGUAGES C ASM)
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
set(CMAKE_C_LINK_FLAGS "")
|
||||||
|
endif()
|
||||||
|
|
||||||
set(UEFI_COMPILE_OPTIONS
|
set(UEFI_COMPILE_OPTIONS
|
||||||
-std=c23
|
-std=c23
|
||||||
-target x86_64-unknown-windows-msvc
|
-target x86_64-unknown-windows-msvc
|
||||||
@@ -20,14 +24,15 @@ set(POSIX_UEFI_SOURCES
|
|||||||
src/uefi/unistd.c
|
src/uefi/unistd.c
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(posix_uefi_lib STATIC ${POSIX_UEFI_SOURCES})
|
add_library(posix_uefi_lib OBJECT ${POSIX_UEFI_SOURCES})
|
||||||
target_compile_options(posix_uefi_lib PRIVATE ${UEFI_COMPILE_OPTIONS})
|
target_compile_options(posix_uefi_lib PRIVATE ${UEFI_COMPILE_OPTIONS})
|
||||||
target_include_directories(posix_uefi_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/uefi)
|
target_include_directories(posix_uefi_lib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/src/uefi)
|
||||||
|
|
||||||
add_executable(BOOTX64 src/main.c)
|
add_executable(BOOTX64 src/main.c)
|
||||||
target_compile_options(BOOTX64 PRIVATE ${UEFI_COMPILE_OPTIONS})
|
target_compile_options(BOOTX64 PRIVATE ${UEFI_COMPILE_OPTIONS})
|
||||||
|
target_sources(BOOTX64 PRIVATE $<TARGET_OBJECTS:posix_uefi_lib>)
|
||||||
|
|
||||||
target_link_libraries(BOOTX64 PRIVATE posix_uefi_lib)
|
target_include_directories(BOOTX64 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src/uefi)
|
||||||
|
|
||||||
target_link_options(BOOTX64 PRIVATE
|
target_link_options(BOOTX64 PRIVATE
|
||||||
-fuse-ld=lld
|
-fuse-ld=lld
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// Copyright (c) 2025 0xKarinyash
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
#include "uefi.h" // IWYU pragma: keep
|
#include "uefi.h" // IWYU pragma: keep
|
||||||
#include "../../common/bootinfo.h"
|
#include "../../common/bootinfo.h"
|
||||||
@@ -78,11 +78,11 @@ int main()
|
|||||||
efi_file_handle_t* initramfs_file;
|
efi_file_handle_t* initramfs_file;
|
||||||
uintn_t iinfo_size = 0;
|
uintn_t iinfo_size = 0;
|
||||||
efi_file_info_t* ifile_info = nullptr;
|
efi_file_info_t* ifile_info = nullptr;
|
||||||
status = root->Open(root, &initramfs_file, L"initramfs.cpio", EFI_FILE_MODE_READ, 0);
|
status = root->Open(root, &initramfs_file, L"StartupVolume.cpio", EFI_FILE_MODE_READ, 0);
|
||||||
|
|
||||||
if (EFI_ERROR(status)) {
|
if (EFI_ERROR(status)) {
|
||||||
print_initramfs_warning(L"initramfs.cpio is missing");
|
print_initramfs_warning(L"StartupVolume.cpio is missing");
|
||||||
boot_info->initramfs.addr = nullptr;
|
boot_info->initramfs.address = nullptr;
|
||||||
boot_info->initramfs.size = 0;
|
boot_info->initramfs.size = 0;
|
||||||
} else {
|
} else {
|
||||||
status = initramfs_file->GetInfo(initramfs_file, &fi_guid, &iinfo_size, nullptr);
|
status = initramfs_file->GetInfo(initramfs_file, &fi_guid, &iinfo_size, nullptr);
|
||||||
@@ -105,14 +105,14 @@ int main()
|
|||||||
// just fucking kill me
|
// just fucking kill me
|
||||||
uintn_t initramfs_size_read = (uintn_t)initramfs_size;
|
uintn_t initramfs_size_read = (uintn_t)initramfs_size;
|
||||||
initramfs_file->Read(initramfs_file, &initramfs_size_read, (void*)initramfs_addr);
|
initramfs_file->Read(initramfs_file, &initramfs_size_read, (void*)initramfs_addr);
|
||||||
boot_info->initramfs.addr = (void*)initramfs_addr;
|
boot_info->initramfs.address = (void*)initramfs_addr;
|
||||||
boot_info->initramfs.size = initramfs_size;
|
boot_info->initramfs.size = initramfs_size;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boot_info->framebuffer.base = (uint32_t*)gop->Mode->FrameBufferBase;
|
boot_info->framebuffer.base = (uint32_t*)gop->Mode->FrameBufferBase;
|
||||||
boot_info->framebuffer.base_size = gop->Mode->FrameBufferSize;
|
boot_info->framebuffer.baseSize = gop->Mode->FrameBufferSize;
|
||||||
boot_info->framebuffer.height = gop->Mode->Information->VerticalResolution;
|
boot_info->framebuffer.height = gop->Mode->Information->VerticalResolution;
|
||||||
boot_info->framebuffer.width = gop->Mode->Information->HorizontalResolution;
|
boot_info->framebuffer.width = gop->Mode->Information->HorizontalResolution;
|
||||||
boot_info->framebuffer.pitch = gop->Mode->Information->PixelsPerScanLine;
|
boot_info->framebuffer.pitch = gop->Mode->Information->PixelsPerScanLine;
|
||||||
@@ -139,11 +139,11 @@ int main()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
boot_info->mem.descriptor_size = desc_size;
|
boot_info->memoryMap.descriptorSize = desc_size;
|
||||||
boot_info->mem.descriptor_version = desc_version;
|
boot_info->memoryMap.descriptorVersion = desc_version;
|
||||||
boot_info->mem.map_size = map_size;
|
boot_info->memoryMap.mapSize = map_size;
|
||||||
boot_info->mem.map_key = map_key;
|
boot_info->memoryMap.mapKey = map_key;
|
||||||
boot_info->mem.map = map;
|
boot_info->memoryMap.map = map;
|
||||||
|
|
||||||
status = gBS->ExitBootServices(IM, map_key);
|
status = gBS->ExitBootServices(IM, map_key);
|
||||||
if (status == EFI_SUCCESS) {
|
if (status == EFI_SUCCESS) {
|
||||||
@@ -46,7 +46,7 @@ void __stdio_cleanup(void)
|
|||||||
BS->FreePool(__argvutf8);
|
BS->FreePool(__argvutf8);
|
||||||
#endif
|
#endif
|
||||||
if(__blk_devs) {
|
if(__blk_devs) {
|
||||||
free(__blk_devs);
|
MemoryFree(__blk_devs);
|
||||||
__blk_devs = NULL;
|
__blk_devs = NULL;
|
||||||
__blk_ndevs = 0;
|
__blk_ndevs = 0;
|
||||||
}
|
}
|
||||||
@@ -127,7 +127,7 @@ int fclose (FILE *__stream)
|
|||||||
if(__stream == (FILE*)__blk_devs[i].bio)
|
if(__stream == (FILE*)__blk_devs[i].bio)
|
||||||
return 1;
|
return 1;
|
||||||
status = __stream->Close(__stream);
|
status = __stream->Close(__stream);
|
||||||
free(__stream);
|
MemoryFree(__stream);
|
||||||
return !EFI_ERROR(status);
|
return !EFI_ERROR(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +188,7 @@ err: __stdio_seterrno(status);
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
/* no need for fclose(f); */
|
/* no need for fclose(f); */
|
||||||
free(f);
|
MemoryFree(f);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -250,7 +250,7 @@ FILE *fopen (const char_t *__filename, const char_t *__modes)
|
|||||||
/* workaround a bug in TianoCore, it reports zero size even though the data is in the buffer */
|
/* workaround a bug in TianoCore, it reports zero size even though the data is in the buffer */
|
||||||
if(handle_size < 1)
|
if(handle_size < 1)
|
||||||
handle_size = (uintn_t)sizeof(handles) / sizeof(efi_handle_t);
|
handle_size = (uintn_t)sizeof(handles) / sizeof(efi_handle_t);
|
||||||
__blk_devs = (block_file_t*)malloc(handle_size * sizeof(block_file_t));
|
__blk_devs = (block_file_t*)MemoryAllocate(handle_size * sizeof(block_file_t));
|
||||||
if(__blk_devs) {
|
if(__blk_devs) {
|
||||||
memset(__blk_devs, 0, handle_size * sizeof(block_file_t));
|
memset(__blk_devs, 0, handle_size * sizeof(block_file_t));
|
||||||
for(i = __blk_ndevs = 0; i < handle_size; i++)
|
for(i = __blk_ndevs = 0; i < handle_size; i++)
|
||||||
@@ -276,7 +276,7 @@ FILE *fopen (const char_t *__filename, const char_t *__modes)
|
|||||||
errno = ENODEV;
|
errno = ENODEV;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
ret = (FILE*)malloc(sizeof(FILE));
|
ret = (FILE*)MemoryAllocate(sizeof(FILE));
|
||||||
if(!ret) return NULL;
|
if(!ret) return NULL;
|
||||||
/* normally write means read,write,create. But for remove (internal '*' mode), we need read,write without create
|
/* normally write means read,write,create. But for remove (internal '*' mode), we need read,write without create
|
||||||
* also mode 'w' in POSIX means write-only (without read), but that's not working on certain firmware, we must
|
* also mode 'w' in POSIX means write-only (without read), but that's not working on certain firmware, we must
|
||||||
@@ -292,16 +292,16 @@ FILE *fopen (const char_t *__filename, const char_t *__modes)
|
|||||||
__modes[1] == CL('d') ? EFI_FILE_DIRECTORY : 0);
|
__modes[1] == CL('d') ? EFI_FILE_DIRECTORY : 0);
|
||||||
if(EFI_ERROR(status)) {
|
if(EFI_ERROR(status)) {
|
||||||
err: __stdio_seterrno(status);
|
err: __stdio_seterrno(status);
|
||||||
free(ret); return NULL;
|
MemoryFree(ret); return NULL;
|
||||||
}
|
}
|
||||||
if(__modes[0] == CL('*')) return ret;
|
if(__modes[0] == CL('*')) return ret;
|
||||||
status = ret->GetInfo(ret, &infGuid, &fsiz, &info);
|
status = ret->GetInfo(ret, &infGuid, &fsiz, &info);
|
||||||
if(EFI_ERROR(status)) goto err;
|
if(EFI_ERROR(status)) goto err;
|
||||||
if(__modes[1] == CL('d') && !(info.Attribute & EFI_FILE_DIRECTORY)) {
|
if(__modes[1] == CL('d') && !(info.Attribute & EFI_FILE_DIRECTORY)) {
|
||||||
ret->Close(ret); free(ret); errno = ENOTDIR; return NULL;
|
ret->Close(ret); MemoryFree(ret); errno = ENOTDIR; return NULL;
|
||||||
}
|
}
|
||||||
if(__modes[1] != CL('d') && (info.Attribute & EFI_FILE_DIRECTORY)) {
|
if(__modes[1] != CL('d') && (info.Attribute & EFI_FILE_DIRECTORY)) {
|
||||||
ret->Close(ret); free(ret); errno = EISDIR; return NULL;
|
ret->Close(ret); MemoryFree(ret); errno = EISDIR; return NULL;
|
||||||
}
|
}
|
||||||
if(__modes[0] == CL('a')) fseek(ret, 0, SEEK_END);
|
if(__modes[0] == CL('a')) fseek(ret, 0, SEEK_END);
|
||||||
if(__modes[0] == CL('w')) {
|
if(__modes[0] == CL('w')) {
|
||||||
@@ -713,7 +713,7 @@ int sprintf(char_t *dst, const char_t* fmt, ...)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int snprintf(char_t *dst, size_t maxlen, const char_t* fmt, ...)
|
int StringFormat(char_t *dst, size_t maxlen, const char_t* fmt, ...)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
__builtin_va_list args;
|
__builtin_va_list args;
|
||||||
@@ -738,7 +738,7 @@ int vprintf(const char_t* fmt, __builtin_va_list args)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int printf(const char_t* fmt, ...)
|
int ConsolePrint(const char_t* fmt, ...)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
__builtin_va_list args;
|
__builtin_va_list args;
|
||||||
@@ -800,7 +800,7 @@ int getchar_ifany (void)
|
|||||||
return EFI_ERROR(status) ? 0 : key.UnicodeChar;
|
return EFI_ERROR(status) ? 0 : key.UnicodeChar;
|
||||||
}
|
}
|
||||||
|
|
||||||
int getchar (void)
|
int ConsoleGetCharacter (void)
|
||||||
{
|
{
|
||||||
uintn_t idx;
|
uintn_t idx;
|
||||||
BS->WaitForEvent(1, &ST->ConIn->WaitForKey, &idx);
|
BS->WaitForEvent(1, &ST->ConIn->WaitForKey, &idx);
|
||||||
@@ -77,7 +77,7 @@ int64_t strtol (const char_t *s, char_t **__endptr, int __base)
|
|||||||
return v * sign;
|
return v * sign;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *malloc (size_t __size)
|
void *MemoryAllocate (size_t __size)
|
||||||
{
|
{
|
||||||
void *ret = NULL;
|
void *ret = NULL;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
@@ -106,20 +106,20 @@ void *malloc (size_t __size)
|
|||||||
|
|
||||||
void *calloc (size_t __nmemb, size_t __size)
|
void *calloc (size_t __nmemb, size_t __size)
|
||||||
{
|
{
|
||||||
void *ret = malloc(__nmemb * __size);
|
void *ret = MemoryAllocate(__nmemb * __size);
|
||||||
if(ret) memset(ret, 0, __nmemb * __size);
|
if(ret) memset(ret, 0, __nmemb * __size);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *realloc (void *__ptr, size_t __size)
|
void *MemoryReallocate (void *__ptr, size_t __size)
|
||||||
{
|
{
|
||||||
void *ret = NULL;
|
void *ret = NULL;
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
#ifndef UEFI_NO_TRACK_ALLOC
|
#ifndef UEFI_NO_TRACK_ALLOC
|
||||||
uintn_t i;
|
uintn_t i;
|
||||||
#endif
|
#endif
|
||||||
if(!__ptr) return malloc(__size);
|
if(!__ptr) return MemoryAllocate(__size);
|
||||||
if(!__size) { free(__ptr); return NULL; }
|
if(!__size) { MemoryFree(__ptr); return NULL; }
|
||||||
#ifndef UEFI_NO_TRACK_ALLOC
|
#ifndef UEFI_NO_TRACK_ALLOC
|
||||||
/* get the slot which stores the old size for this buffer */
|
/* get the slot which stores the old size for this buffer */
|
||||||
for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != (uintptr_t)__ptr; i += 2);
|
for(i = 0; i < __stdlib_numallocs && __stdlib_allocs[i] != (uintptr_t)__ptr; i += 2);
|
||||||
@@ -145,7 +145,7 @@ void *realloc (void *__ptr, size_t __size)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void free (void *__ptr)
|
void MemoryFree (void *__ptr)
|
||||||
{
|
{
|
||||||
efi_status_t status;
|
efi_status_t status;
|
||||||
#ifndef UEFI_NO_TRACK_ALLOC
|
#ifndef UEFI_NO_TRACK_ALLOC
|
||||||
@@ -341,7 +341,7 @@ uint8_t *getenv(char_t *name, uintn_t *len)
|
|||||||
#else
|
#else
|
||||||
status = RT->GetVariable(name, &globGuid, &attr, len, &tmp);
|
status = RT->GetVariable(name, &globGuid, &attr, len, &tmp);
|
||||||
#endif
|
#endif
|
||||||
if(EFI_ERROR(status) || *len < 1 || !(ret = malloc((*len) + 1))) {
|
if(EFI_ERROR(status) || *len < 1 || !(ret = MemoryAllocate((*len) + 1))) {
|
||||||
*len = 0;
|
*len = 0;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -116,7 +116,7 @@ void *memrmem(const void *haystack, size_t hl, const void *needle, size_t nl)
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char_t *strcpy(char_t *dst, const char_t *src)
|
char_t *StringCopy(char_t *dst, const char_t *src)
|
||||||
{
|
{
|
||||||
char_t *s = dst;
|
char_t *s = dst;
|
||||||
if(src && dst && src != dst) {
|
if(src && dst && src != dst) {
|
||||||
@@ -178,7 +178,7 @@ int strncmp(const char_t *s1, const char_t *s2, size_t n)
|
|||||||
char_t *strdup(const char_t *s)
|
char_t *strdup(const char_t *s)
|
||||||
{
|
{
|
||||||
size_t i = (strlen(s)+1) * sizeof(char_t);
|
size_t i = (strlen(s)+1) * sizeof(char_t);
|
||||||
char_t *s2 = (char_t *)malloc(i);
|
char_t *s2 = (char_t *)MemoryAllocate(i);
|
||||||
if(s2 != NULL) memcpy(s2, (const void*)s, i);
|
if(s2 != NULL) memcpy(s2, (const void*)s, i);
|
||||||
return s2;
|
return s2;
|
||||||
}
|
}
|
||||||
@@ -1314,10 +1314,10 @@ typedef int (*__compar_fn_t) (const void *, const void *);
|
|||||||
extern int atoi (const char_t *__nptr);
|
extern int atoi (const char_t *__nptr);
|
||||||
extern int64_t atol (const char_t *__nptr);
|
extern int64_t atol (const char_t *__nptr);
|
||||||
extern int64_t strtol (const char_t *__nptr, char_t **__endptr, int __base);
|
extern int64_t strtol (const char_t *__nptr, char_t **__endptr, int __base);
|
||||||
extern void *malloc (size_t __size);
|
extern void *MemoryAllocate (size_t __size);
|
||||||
extern void *calloc (size_t __nmemb, size_t __size);
|
extern void *calloc (size_t __nmemb, size_t __size);
|
||||||
extern void *realloc (void *__ptr, size_t __size);
|
extern void *MemoryReallocate (void *__ptr, size_t __size);
|
||||||
extern void free (void *__ptr);
|
extern void MemoryFree (void *__ptr);
|
||||||
extern void abort (void);
|
extern void abort (void);
|
||||||
extern void exit (int __status);
|
extern void exit (int __status);
|
||||||
/* exit Boot Services function. Returns 0 on success. */
|
/* exit Boot Services function. Returns 0 on success. */
|
||||||
@@ -1355,14 +1355,14 @@ extern int fseek (FILE *__stream, long int __off, int __whence);
|
|||||||
extern long int ftell (FILE *__stream);
|
extern long int ftell (FILE *__stream);
|
||||||
extern int feof (FILE *__stream);
|
extern int feof (FILE *__stream);
|
||||||
extern int fprintf (FILE *__stream, const char_t *__format, ...);
|
extern int fprintf (FILE *__stream, const char_t *__format, ...);
|
||||||
extern int printf (const char_t *__format, ...);
|
extern int ConsolePrint (const char_t *__format, ...);
|
||||||
extern int sprintf (char_t *__s, const char_t *__format, ...);
|
extern int sprintf (char_t *__s, const char_t *__format, ...);
|
||||||
extern int vfprintf (FILE *__s, const char_t *__format, __builtin_va_list __arg);
|
extern int vfprintf (FILE *__s, const char_t *__format, __builtin_va_list __arg);
|
||||||
extern int vprintf (const char_t *__format, __builtin_va_list __arg);
|
extern int vprintf (const char_t *__format, __builtin_va_list __arg);
|
||||||
extern int vsprintf (char_t *__s, const char_t *__format, __builtin_va_list __arg);
|
extern int vsprintf (char_t *__s, const char_t *__format, __builtin_va_list __arg);
|
||||||
extern int snprintf (char_t *__s, size_t __maxlen, const char_t *__format, ...);
|
extern int StringFormat (char_t *__s, size_t __maxlen, const char_t *__format, ...);
|
||||||
extern int vsnprintf (char_t *__s, size_t __maxlen, const char_t *__format, __builtin_va_list __arg);
|
extern int vsnprintf (char_t *__s, size_t __maxlen, const char_t *__format, __builtin_va_list __arg);
|
||||||
extern int getchar (void);
|
extern int ConsoleGetCharacter (void);
|
||||||
/* non-blocking, only returns UNICODE if there's any key pressed, 0 otherwise */
|
/* non-blocking, only returns UNICODE if there's any key pressed, 0 otherwise */
|
||||||
extern int getchar_ifany (void);
|
extern int getchar_ifany (void);
|
||||||
extern int putchar (int __c);
|
extern int putchar (int __c);
|
||||||
@@ -1376,7 +1376,7 @@ extern void *memchr(const void *__s, int __c, size_t __n);
|
|||||||
extern void *memrchr(const void *__s, int __c, size_t __n);
|
extern void *memrchr(const void *__s, int __c, size_t __n);
|
||||||
void *memmem(const void *haystack, size_t hl, const void *needle, size_t nl);
|
void *memmem(const void *haystack, size_t hl, const void *needle, size_t nl);
|
||||||
void *memrmem(const void *haystack, size_t hl, const void *needle, size_t nl);
|
void *memrmem(const void *haystack, size_t hl, const void *needle, size_t nl);
|
||||||
extern char_t *strcpy (char_t *__dest, const char_t *__src);
|
extern char_t *StringCopy (char_t *__dest, const char_t *__src);
|
||||||
extern char_t *strncpy (char_t *__dest, const char_t *__src, size_t __n);
|
extern char_t *strncpy (char_t *__dest, const char_t *__src, size_t __n);
|
||||||
extern char_t *strcat (char_t *__dest, const char_t *__src);
|
extern char_t *strcat (char_t *__dest, const char_t *__src);
|
||||||
extern char_t *strncat (char_t *__dest, const char_t *__src, size_t __n);
|
extern char_t *strncat (char_t *__dest, const char_t *__src, size_t __n);
|
||||||
+27
-28
@@ -10,7 +10,7 @@ find_program(MCOPY_EXE mcopy)
|
|||||||
find_program(MKFS_EXE mkfs.fat)
|
find_program(MKFS_EXE mkfs.fat)
|
||||||
find_program(CPIO_EXE cpio)
|
find_program(CPIO_EXE cpio)
|
||||||
find_program(QEMU_EXE qemu-system-x86_64)
|
find_program(QEMU_EXE qemu-system-x86_64)
|
||||||
set(OVMF_PATH "/usr/share/edk2/ovmf/OVMF_CODE.fd" CACHE FILEPATH "Path to OVMF bios")
|
set(OVMF_PATH "/usr/share/edk2/x64/OVMF.4m.fd" CACHE FILEPATH "Path to OVMF bios")
|
||||||
|
|
||||||
execute_process(
|
execute_process(
|
||||||
COMMAND git describe --tags --always --dirty
|
COMMAND git describe --tags --always --dirty
|
||||||
@@ -26,48 +26,47 @@ endif()
|
|||||||
message(STATUS "Building termOS version: ${KERNEL_VERSION}")
|
message(STATUS "Building termOS version: ${KERNEL_VERSION}")
|
||||||
add_compile_definitions(TERMOS_VERSION=\"${KERNEL_VERSION}\")
|
add_compile_definitions(TERMOS_VERSION=\"${KERNEL_VERSION}\")
|
||||||
|
|
||||||
add_subdirectory(bootloader)
|
add_subdirectory(Boot)
|
||||||
add_subdirectory(kernel)
|
add_subdirectory(System)
|
||||||
add_subdirectory(userspace)
|
add_subdirectory(Runtime)
|
||||||
|
|
||||||
|
set(SYSTEM_SERVICES
|
||||||
|
init
|
||||||
|
debug
|
||||||
|
termosh
|
||||||
|
rtest
|
||||||
|
)
|
||||||
|
|
||||||
|
set(VOLUME_ROOT "${CMAKE_BINARY_DIR}/StartupVolume")
|
||||||
|
set(INITRAMFS_CPIO_FILE "${CMAKE_BINARY_DIR}/StartupVolume.cpio")
|
||||||
|
set(IMG_FILE "${CMAKE_BINARY_DIR}/termOS.img")
|
||||||
|
|
||||||
if(MCOPY_EXE AND MKFS_EXE AND CPIO_EXE)
|
if(MCOPY_EXE AND MKFS_EXE AND CPIO_EXE)
|
||||||
set(IMG_FILE "${CMAKE_BINARY_DIR}/termOS.img")
|
add_custom_target(image ALL
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory ${VOLUME_ROOT}
|
||||||
set(INITRAMFS_SRC_DIR "${CMAKE_SOURCE_DIR}/initramfs")
|
|
||||||
set(INITRAMFS_CPIO_FILE "${CMAKE_BINARY_DIR}/initramfs.cpio")
|
|
||||||
file(GLOB_RECURSE INIT_FILES "${INITRAMFS_SRC_DIR}/*")
|
|
||||||
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${INITRAMFS_CPIO_FILE}
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}
|
|
||||||
COMMAND sh -c "find . -mindepth 1 ! -name '*.cpio' -print0 | ${CPIO_EXE} --null -ov -H newc > \"${INITRAMFS_CPIO_FILE}\""
|
COMMAND sh -c "find . -mindepth 1 ! -name '*.cpio' -print0 | ${CPIO_EXE} --null -ov -H newc > \"${INITRAMFS_CPIO_FILE}\""
|
||||||
WORKING_DIRECTORY ${INITRAMFS_SRC_DIR}
|
|
||||||
DEPENDS ${INIT_FILES} init_elf
|
|
||||||
VERBATIM
|
|
||||||
COMMENT "Packing initramfs to cpio..."
|
|
||||||
)
|
|
||||||
|
|
||||||
add_custom_command(
|
|
||||||
OUTPUT ${IMG_FILE}
|
|
||||||
COMMAND dd if=/dev/zero of=${IMG_FILE} bs=1M count=64 status=none
|
COMMAND dd if=/dev/zero of=${IMG_FILE} bs=1M count=64 status=none
|
||||||
COMMAND ${MKFS_EXE} -F 32 ${IMG_FILE}
|
COMMAND ${MKFS_EXE} -F 32 ${IMG_FILE}
|
||||||
COMMAND mmd -i ${IMG_FILE} ::/EFI ::/EFI/BOOT
|
COMMAND mmd -i ${IMG_FILE} ::/EFI ::/EFI/BOOT
|
||||||
COMMAND ${MCOPY_EXE} -i ${IMG_FILE} $<TARGET_FILE:BOOTX64> ::/EFI/BOOT/BOOTX64.EFI
|
COMMAND ${MCOPY_EXE} -i ${IMG_FILE} $<TARGET_FILE:BOOTX64> ::/EFI/BOOT/BOOTX64.EFI
|
||||||
COMMAND ${MCOPY_EXE} -i ${IMG_FILE} ${CMAKE_BINARY_DIR}/bin/kernel.bin ::/kernel.bin
|
COMMAND ${MCOPY_EXE} -i ${IMG_FILE} ${CMAKE_BINARY_DIR}/bin/kernel.bin ::/kernel.bin
|
||||||
COMMAND ${MCOPY_EXE} -i ${IMG_FILE} ${INITRAMFS_CPIO_FILE} ::/initramfs.cpio
|
COMMAND ${MCOPY_EXE} -i ${IMG_FILE} ${INITRAMFS_CPIO_FILE} ::/StartupVolume.cpio
|
||||||
DEPENDS BOOTX64 kernel ${INITRAMFS_CPIO_FILE}
|
|
||||||
VERBATIM
|
|
||||||
COMMENT "Generating bootable image: ${IMG_FILE}"
|
|
||||||
)
|
|
||||||
|
|
||||||
add_custom_target(image ALL DEPENDS ${IMG_FILE})
|
WORKING_DIRECTORY ${VOLUME_ROOT}
|
||||||
|
DEPENDS BOOTX64 kernel ${SYSTEM_SERVICES}
|
||||||
|
VERBATIM
|
||||||
|
COMMENT "Packing initramfs and generating bootable image: ${IMG_FILE}"
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(QEMU_EXE)
|
if(QEMU_EXE)
|
||||||
add_custom_target(run
|
add_custom_target(run
|
||||||
COMMAND ${QEMU_EXE}
|
COMMAND ${QEMU_EXE}
|
||||||
-enable-kvm
|
#-enable-kvm
|
||||||
-bios ${OVMF_PATH}
|
$<$<BOOL:${APPLE}>:-machine> $<$<BOOL:${APPLE}>:q35>
|
||||||
|
$<$<BOOL:${APPLE}>:-drive> $<$<BOOL:${APPLE}>:if=pflash,format=raw,readonly=on,file=${OVMF_PATH}>
|
||||||
|
$<$<NOT:$<BOOL:${APPLE}>>:-bios> $<$<NOT:$<BOOL:${APPLE}>>:${OVMF_PATH}>
|
||||||
-drive file=${IMG_FILE},format=raw
|
-drive file=${IMG_FILE},format=raw
|
||||||
-vga std
|
-vga std
|
||||||
-net none
|
-net none
|
||||||
|
|||||||
@@ -4,6 +4,39 @@
|
|||||||
<img src='assets/logo.png'>
|
<img src='assets/logo.png'>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
Just a hobby, won't be big and professional like Linux
|
> "Just a hobby, won't be big and professional like Linux."
|
||||||
|
> — *Linus Torvalds (and now me)*
|
||||||
|
|
||||||
Really WIP. And really just a hobby.
|
**termOS** is a 64-bit, UNIX-hating, bespoke operating system written from scratch in C.
|
||||||
|
|
||||||
|
Current Kernel: **Dewar** (v0.6.x)
|
||||||
|
|
||||||
|
## Philosophy
|
||||||
|
|
||||||
|
- **Zero Bloat:** We don't port libraries; we write them.
|
||||||
|
- **Custom Everything:** Why use ELF when you can invent **HOT!**? Why use GRUB when you can write your own bootloader?
|
||||||
|
|
||||||
|
## Features (v0.6.*)
|
||||||
|
|
||||||
|
- **Architecture:** x86_64 / UEFI.
|
||||||
|
- **Memory Management:** PMM (Bitmap), VMM (PML4 + Higher Half Direct Map), Kernel Heap.
|
||||||
|
- **Multitasking:** Preemptive scheduler with Round Robin.
|
||||||
|
- **Isolation:** Ring 0 (Kernel) / Ring 3 (Userspace) protection.
|
||||||
|
- **Binaries:** Custom **HOT!** executable format (parsed via custom `elf2hot` toolchain).
|
||||||
|
- **Filesystem:** VFS abstraction with CPIO Initramfs support.
|
||||||
|
- **Graphics:** linear framebuffer driver.
|
||||||
|
- **Shell:** `termosh`
|
||||||
|
|
||||||
|
## 🔥 The HOT! Format
|
||||||
|
|
||||||
|
termOS uses its own executable format called **HOT!**.
|
||||||
|
Because parsing ELF headers is too mainstream. HOT! is a flat, segment-based format designed specifically for the Dewar kernel loader.
|
||||||
|
Made only because ELF is *Not-invented-here*
|
||||||
|
|
||||||
|
## Roadmap
|
||||||
|
|
||||||
|
See [ROADMAP.md](ROADMAP.md) for the detailed plan of world domination (or at least self-hosting).
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
**GPL-3.0-or-later**.
|
||||||
+103
@@ -0,0 +1,103 @@
|
|||||||
|
# termOS Roadmap
|
||||||
|
|
||||||
|
## Legend
|
||||||
|
- ✅ **Done**: Implemented and working.
|
||||||
|
- 🚧 **WIP**: Currently under active development.
|
||||||
|
- 📅 **Planned**: Scheduled for future releases.
|
||||||
|
- 🤔 **Vision**: Long-term goals for v1.0.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Current Status: v0.5.3 (Alpha)
|
||||||
|
*Where we are now.*
|
||||||
|
- **Core:** Ring 0 / Ring 3 isolation implemented.
|
||||||
|
- **Mem:** PMM (bitmap), VMM (PML4, HHDM).
|
||||||
|
- **Exec:** Custom **HOT!** executable format (static loader).
|
||||||
|
- **FS:** VFS + Initramfs (CPIO, read-only).
|
||||||
|
- **User:** Basic jump to userspace (hardcoded stack, no heap yet).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📅 Phase 1
|
||||||
|
*Goal: Transform the decorative userspace into a functional mechanism.*
|
||||||
|
|
||||||
|
### v0.5.4 (The Shell Update)
|
||||||
|
*Focus: Interactive Userspace*
|
||||||
|
- [x] **Userspace Shell (`termosh`)**
|
||||||
|
- Porting `ksh` logic into a standalone `.hot` binary.
|
||||||
|
- Standard I/O abstraction (stdin/stdout) to pass keyboard input to active process.
|
||||||
|
- [ ] ~~**Basic Utils** (`ls`, `cat`, `echo`)~~ *(Moved to v0.6.1 — awaiting Apple-style API)*
|
||||||
|
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📅 Phase 2
|
||||||
|
*Goal: Total independence from external libraries and architectural hygiene.*
|
||||||
|
|
||||||
|
### v0.6.0 (Architecture Overhaul)
|
||||||
|
- [ ] **System-wide Naming & API Refactoring (Apple-style)**
|
||||||
|
- Replace generic types with PascalCase branding (`u64` -> `UInt64`, `i32` -> `Int32`).
|
||||||
|
- Standardize system prefixes: `VM` for Virtual Memory, `OS` for Core, `CPU` for HAL.
|
||||||
|
- Transition from `snake_case` to `PascalCase` for all kernel functions and structures.
|
||||||
|
- Implement `OSReturn` status codes for unified error handling.
|
||||||
|
- [ ] **Bootloader Independence**
|
||||||
|
- Remove `posix-uefi` library.
|
||||||
|
- Write custom UEFI entry point (pure PE).
|
||||||
|
- Kernel itself becomes a valid `.hot` executable.
|
||||||
|
- [ ] **HOT! Format Hardening**
|
||||||
|
- Fix segment alignment (Page Alignment) in `elf2hot` and kernel loader.
|
||||||
|
- Add metadata headers (stack size, permissions).
|
||||||
|
- [ ] **Concurrency Fixes**
|
||||||
|
- Implement spinlocks (`spinlock`).
|
||||||
|
- Protect allocator and process lists from interrupt race conditions.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📅 Phase 3
|
||||||
|
*Goal: Prepare the environment for self-hosting. We cannot compile on a Read-Only FS.*
|
||||||
|
|
||||||
|
### v0.7.0 (Filesystem & Input)
|
||||||
|
- [ ] **Write Support**
|
||||||
|
- Storage driver (NVMe/AHCI or Writable RAMDisk).
|
||||||
|
- Writable Filesystem (FAT32 or custom simple FS).
|
||||||
|
- [ ] **Input Subsystem**
|
||||||
|
- Input buffering, Pipe (`|`) support in shell.
|
||||||
|
- Basic TTY/PTY abstraction.
|
||||||
|
|
||||||
|
### v0.8.0 (The Editor)
|
||||||
|
- [ ] **Text Editor**
|
||||||
|
- Write a simple editor (nano-like) in userspace.
|
||||||
|
- Capabilities: Open, Edit, Save files.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📅 Phase 4
|
||||||
|
*Goal: Self-Hosting.*
|
||||||
|
|
||||||
|
### v0.9.0 (The Toolchain)
|
||||||
|
- [ ] **Linker (`hld`)**
|
||||||
|
- Native linker capable of outputting `.hot` files (running inside termOS).
|
||||||
|
- [ ] **Compiler Port**
|
||||||
|
- Port **TCC (Tiny C Compiler)** to termOS.
|
||||||
|
- Adapt libc headers for the OS environment.
|
||||||
|
|
||||||
|
### 🤔 v1.0.0 (Self-Hosting)
|
||||||
|
- [ ] **Bootstrapping**
|
||||||
|
- Compile the Dewar kernel *inside* termOS.
|
||||||
|
- Boot from the newly compiled kernel.
|
||||||
|
- Total victory.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📜 History
|
||||||
|
|
||||||
|
| Version | Date | Key Features |
|
||||||
|
| :--- | :--- | :--- |
|
||||||
|
| **v0.5.3** | 2026-01-30 | `sys_mem`, `sys_spawn`, `sys_wait`, `sys_exit` |
|
||||||
|
| **v0.5.2** | 2026-01-30 | **HOT!** format, Ring 3 isolation, VFS, CPIO parsing. |
|
||||||
|
| **v0.5.1** | 2026-01-29 | Initial userspace jumps, syscall mechanics. |
|
||||||
|
| **v0.5.0** | 2026-01-29 | Kernel officially named "Dewar". Versioning standardized. |
|
||||||
|
| **v0.4.x** | 2026-01-28 | Basic VFS, Shell improvements, basic multitasking. |
|
||||||
|
| **v0.3.x** | 2025-12-30 | Scheduler, ~~Composer~~, Heap manager. |
|
||||||
|
| **v0.2.x** | 2025-12-28 | `ksh`, Keyboard driver, HHDM, PMM/VMM. |
|
||||||
|
| **v0.1.x** | 2025-12-21 | First boot, GDT/IDT, Serial/Console, Panic handler. |
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
project(termOSuserspace LANGUAGES C ASM_NASM)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 23)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_C_EXTENSIONS OFF)
|
||||||
|
|
||||||
|
message(STATUS "Building termOS's userspace")
|
||||||
|
|
||||||
|
set(TERMOS_OBJCOPY objcopy)
|
||||||
|
if(APPLE)
|
||||||
|
find_program(TERMOS_LD_LLD NAMES ld.lld HINTS /usr/local/bin /opt/homebrew/bin REQUIRED)
|
||||||
|
find_program(TERMOS_OBJCOPY NAMES llvm-objcopy objcopy HINTS /usr/local/opt/llvm/bin /opt/homebrew/opt/llvm/bin REQUIRED)
|
||||||
|
set(CMAKE_C_LINK_FLAGS "")
|
||||||
|
set(CMAKE_ASM_NASM_COMPILE_OBJECT
|
||||||
|
"<CMAKE_ASM_NASM_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -MD <DEP_FILE> -MT <DEP_TARGET> -f elf64 -o <OBJECT> <SOURCE>")
|
||||||
|
set(CMAKE_C_LINK_EXECUTABLE
|
||||||
|
"${TERMOS_LD_LLD} <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(libterm)
|
||||||
|
add_subdirectory(init)
|
||||||
|
add_subdirectory(rust)
|
||||||
|
add_subdirectory(debug)
|
||||||
|
add_subdirectory(termosh)
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
project(termOSdbg LANGUAGES C)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE debug_SOURCES "src/*.c")
|
||||||
|
|
||||||
|
add_termos_executable(debug "${debug_SOURCES}")
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
#include <termOS.h>
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
ConsolePrint("Test test test \n Meow meow meow \n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
project(termOSinit LANGUAGES C)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE INIT_SOURCES "src/*.c")
|
||||||
|
|
||||||
|
add_termos_executable(init "${INIT_SOURCES}")
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#include <termOS.h>
|
||||||
|
|
||||||
|
// TODO: read .cfg and spawn what stated there
|
||||||
|
int main() {
|
||||||
|
while (1) {
|
||||||
|
Int32 pid = ProcessSpawn("/System/CoreServices/termosh");
|
||||||
|
if (pid < 0) return pid;
|
||||||
|
ProcessWait(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
project(libterm LANGUAGES C ASM_NASM)
|
||||||
|
|
||||||
|
set(USER_C_FLAGS
|
||||||
|
-ffreestanding
|
||||||
|
-fno-builtin
|
||||||
|
-Wno-incompatible-library-redeclaration # stfu
|
||||||
|
-nostdlib
|
||||||
|
-nostdinc
|
||||||
|
-fno-stack-protector
|
||||||
|
-fno-pic
|
||||||
|
-fno-pie
|
||||||
|
-m64
|
||||||
|
-mno-red-zone
|
||||||
|
-mcmodel=small
|
||||||
|
-Wall
|
||||||
|
-Wextra
|
||||||
|
-Werror
|
||||||
|
-O2
|
||||||
|
)
|
||||||
|
|
||||||
|
if(APPLE)
|
||||||
|
list(APPEND USER_C_FLAGS --target=x86_64-none-elf)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(USER_C_FLAGS "${USER_C_FLAGS}" PARENT_SCOPE)
|
||||||
|
|
||||||
|
set(CMAKE_ASM_NASM_OBJECT_FORMAT elf64)
|
||||||
|
|
||||||
|
set(LIBTERM_SOURCES
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/OSServices.asm
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Console.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Memory.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/String.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Character.c
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Process.c
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(term STATIC ${LIBTERM_SOURCES})
|
||||||
|
set_target_properties(term PROPERTIES NASM_OBJ_FORMAT elf64)
|
||||||
|
|
||||||
|
target_compile_options(term PRIVATE $<$<COMPILE_LANGUAGE:C>:${USER_C_FLAGS}>)
|
||||||
|
|
||||||
|
target_include_directories(term PUBLIC inc)
|
||||||
|
|
||||||
|
add_library(RuntimeEntryObject OBJECT src/RuntimeEntry.asm)
|
||||||
|
set_target_properties(RuntimeEntryObject PROPERTIES NASM_OBJ_FORMAT elf64)
|
||||||
|
target_compile_options(RuntimeEntryObject PRIVATE $<$<COMPILE_LANGUAGE:C>:${USER_C_FLAGS}>)
|
||||||
|
|
||||||
|
function(add_termos_executable NAME SOURCES)
|
||||||
|
add_executable(${NAME} ${SOURCES})
|
||||||
|
|
||||||
|
target_sources(${NAME} PRIVATE $<TARGET_OBJECTS:RuntimeEntryObject>)
|
||||||
|
|
||||||
|
target_compile_options(${NAME} PRIVATE $<$<COMPILE_LANGUAGE:C>:${USER_C_FLAGS}>
|
||||||
|
-fno-stack-protector) # fixme: what the fuck. ugly this works user_c_flags apparently not
|
||||||
|
target_link_libraries(${NAME} PRIVATE term)
|
||||||
|
|
||||||
|
target_link_options(${NAME} PRIVATE
|
||||||
|
-T ${libterm_SOURCE_DIR}/linker.ld
|
||||||
|
-nostdlib
|
||||||
|
-static
|
||||||
|
)
|
||||||
|
|
||||||
|
set(ELF2HOT_DIR "${CMAKE_SOURCE_DIR}/tools/elf2hot")
|
||||||
|
set(STARTUP_VOLUME_DIR "${CMAKE_BINARY_DIR}/StartupVolume/System/CoreServices")
|
||||||
|
file(MAKE_DIRECTORY "${STARTUP_VOLUME_DIR}")
|
||||||
|
set(FINAL_HOT_PATH "${STARTUP_VOLUME_DIR}/${NAME}")
|
||||||
|
|
||||||
|
add_custom_command(TARGET ${NAME} POST_BUILD
|
||||||
|
COMMAND cargo run --release --quiet -- $<TARGET_FILE:${NAME}> ${FINAL_HOT_PATH}
|
||||||
|
WORKING_DIRECTORY ${ELF2HOT_DIR}
|
||||||
|
COMMENT "elf2hot: Converting ${NAME} to HOT! format..."
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <Types.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kConsoleInput = 0,
|
||||||
|
kConsoleOutput = 1,
|
||||||
|
kConsoleEOF = -1,
|
||||||
|
kConsoleDefaultBufferSize = 1024
|
||||||
|
};
|
||||||
|
|
||||||
|
Int32 ConsolePrintString(const char* string);
|
||||||
|
Int32 ConsolePrint(const char* format, ...);
|
||||||
|
Int32 StringFormat(char* destination, UInt64 size, const char* format, ...);
|
||||||
|
Int32 ConsoleGetCharacter();
|
||||||
|
char* ConsoleReadLine(char* string, UInt64 size);
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <Types.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kMemoryBlockMagic = 0x1CE1CE,
|
||||||
|
kMemoryAlignment = 16,
|
||||||
|
kMemoryPageSize = 4096
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct MemoryBlockHeader {
|
||||||
|
UInt64 magic;
|
||||||
|
struct MemoryBlockHeader* next;
|
||||||
|
struct MemoryBlockHeader* previous;
|
||||||
|
UInt64 size;
|
||||||
|
bool isFree;
|
||||||
|
} MemoryBlockHeader;
|
||||||
|
|
||||||
|
void* MemoryAllocate(UInt64 size);
|
||||||
|
void MemoryFree(void* pointer);
|
||||||
|
void* MemoryReallocate(void* pointer, UInt64 newSize);
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <Types.h>
|
||||||
|
|
||||||
|
Int32 ProcessSpawn(const char* path);
|
||||||
|
Int32 ProcessWait(UInt64 pid);
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <Types.h>
|
||||||
|
|
||||||
|
void* MemorySet(void* destination, UInt8 value, UInt64 count);
|
||||||
|
void* MemoryCopy(void* destination, const void* source, UInt64 count);
|
||||||
|
Int32 StringCompare(const char* firstString, const char* secondString);
|
||||||
|
Int32 StringCompareWithLimit(const char* firstString, const char* secondString, UInt64 limit);
|
||||||
|
char* StringCopy(char* destination, const char* source);
|
||||||
|
char* StringCopyWithLimit(char* destination, const char* source, UInt64 limit);
|
||||||
|
UInt64 StringGetLength(const char* string);
|
||||||
|
UInt64 StringGetInitialSpan(const char* string, const char* characterSet);
|
||||||
|
char* StringFindFirstCharacterFromSet(const char* string, const char* accept);
|
||||||
|
char* StringTokenize(char *s, const char* delim);
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef unsigned char UInt8;
|
||||||
|
typedef unsigned short UInt16;
|
||||||
|
typedef unsigned int UInt32;
|
||||||
|
typedef unsigned long long UInt64;
|
||||||
|
|
||||||
|
typedef signed char Int8;
|
||||||
|
typedef signed short Int16;
|
||||||
|
typedef signed int Int32;
|
||||||
|
typedef signed long long Int64;
|
||||||
|
|
||||||
|
typedef UInt64 usize;
|
||||||
|
typedef UInt64 uintptr_t;
|
||||||
|
|
||||||
|
#ifndef __cplusplus
|
||||||
|
#define bool _Bool
|
||||||
|
#define true 1
|
||||||
|
#define false 0
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef __builtin_va_list va_list;
|
||||||
|
|
||||||
|
#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 va_copy(d, s) __builtin_va_copy(d, s)
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Console.h>
|
||||||
|
#include <Memory.h>
|
||||||
|
#include <Process.h>
|
||||||
|
#include <String.h>
|
||||||
|
#include <Varargs.h>
|
||||||
|
#include <Types.h>
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
ENTRY(start)
|
ENTRY(_start)
|
||||||
|
|
||||||
SECTIONS
|
SECTIONS
|
||||||
{
|
{
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#include <Console.h>
|
||||||
|
#include <Varargs.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
extern UInt64 OSServiceIORead(UInt64 fileDescriptor, void* buffer, UInt64 length);
|
||||||
|
extern UInt64 OSServiceIOWrite(UInt64 fileDescriptor, const void* buffer, UInt64 length);
|
||||||
|
|
||||||
|
static void sConsoleWriteCharacter(char character) {
|
||||||
|
OSServiceIOWrite(kConsoleOutput, &character, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void sConsoleBufferAdd(char* string, UInt64 size, UInt64* written, char character) {
|
||||||
|
if (*written < size - 1 && size > 0) {
|
||||||
|
string[*written] = character;
|
||||||
|
}
|
||||||
|
(*written)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Int32 sStringFormatVariadic(char* string, UInt64 size, const char* format, va_list args) {
|
||||||
|
UInt64 written = 0;
|
||||||
|
for (UInt32 i = 0; format[i] != '\0'; i++) {
|
||||||
|
if (format[i] == '%') {
|
||||||
|
i++;
|
||||||
|
if (format[i] == '\0') break;
|
||||||
|
switch (format[i]) {
|
||||||
|
case 's': {
|
||||||
|
const char* vaArgString = va_arg(args, const char*);
|
||||||
|
if (!vaArgString) vaArgString = "(null)";
|
||||||
|
while (*vaArgString) sConsoleBufferAdd(string, size, &written, *vaArgString++);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'c': {
|
||||||
|
char character = (char)va_arg(args, int);
|
||||||
|
sConsoleBufferAdd(string, size, &written, character);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'd': {
|
||||||
|
Int64 number = va_arg(args, int);
|
||||||
|
if (number < 0) {
|
||||||
|
sConsoleBufferAdd(string, size, &written, '-');
|
||||||
|
number = -number;
|
||||||
|
}
|
||||||
|
UInt64 unsignedNumber = (UInt64)number;
|
||||||
|
char tempBuffer[32];
|
||||||
|
Int32 position = 0;
|
||||||
|
if (unsignedNumber == 0) tempBuffer[position++] = '0';
|
||||||
|
while (unsignedNumber > 0) {
|
||||||
|
tempBuffer[position++] = (unsignedNumber % 10) + '0';
|
||||||
|
unsignedNumber /= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (position > 0) sConsoleBufferAdd(string, size, &written, tempBuffer[--position]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'x':
|
||||||
|
case 'X': {
|
||||||
|
UInt64 unsignedNumber = va_arg(args, unsigned long long);
|
||||||
|
UInt8 padding = (format[i] == 'X') ? 16 : 0;
|
||||||
|
|
||||||
|
char tempBuffer[32];
|
||||||
|
int position = 0;
|
||||||
|
const char* hex = "0123456789ABCDEF";
|
||||||
|
|
||||||
|
if (unsignedNumber == 0 && padding == 0) tempBuffer[position++] = '0';
|
||||||
|
while (unsignedNumber > 0) {
|
||||||
|
tempBuffer[position++] = hex[unsignedNumber % 16];
|
||||||
|
unsignedNumber /= 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (position < padding) tempBuffer[position++] = '0';
|
||||||
|
while (position > 0) sConsoleBufferAdd(string, size, &written, tempBuffer[--position]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case '%': {
|
||||||
|
sConsoleBufferAdd(string, size, &written, '%');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
sConsoleBufferAdd(string, size, &written, '%');
|
||||||
|
sConsoleBufferAdd(string, size, &written, format[i]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sConsoleBufferAdd(string, size, &written, format[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (size > 0) {
|
||||||
|
if (written < size) string[written] = '\0';
|
||||||
|
else string[size - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (int)written;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32 StringFormat(char* destination, usize size, const char* format, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
int returnValue = sStringFormatVariadic(destination, size, format, args);
|
||||||
|
va_end(args);
|
||||||
|
return returnValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32 ConsolePrintString(const char* string) {
|
||||||
|
return OSServiceIOWrite(kConsoleOutput, string, StringGetLength(string));
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32 ConsolePrint(const char *format, ...) {
|
||||||
|
char buffer[kConsoleDefaultBufferSize];
|
||||||
|
va_list args;
|
||||||
|
va_start(args, format);
|
||||||
|
|
||||||
|
int length = sStringFormatVariadic(buffer, sizeof(buffer), format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
UInt64 writeLength = ((UInt64)length < sizeof(buffer)) ? length : (sizeof(buffer) - 1);
|
||||||
|
OSServiceIOWrite(kConsoleOutput, buffer, writeLength);
|
||||||
|
|
||||||
|
return (int)writeLength;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32 ConsoleGetCharacter() {
|
||||||
|
char character;
|
||||||
|
UInt64 serviceCallResult = OSServiceIORead(kConsoleInput, &character, 1);
|
||||||
|
if (serviceCallResult <= 0) return kConsoleEOF;
|
||||||
|
return (int)(unsigned char)character;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* ConsoleReadLine(char* string, UInt64 size) {
|
||||||
|
if (size == 0) return string;
|
||||||
|
|
||||||
|
UInt64 i = 0;
|
||||||
|
int character;
|
||||||
|
|
||||||
|
while (i < size - 1) {
|
||||||
|
character = ConsoleGetCharacter();
|
||||||
|
if (character == kConsoleEOF || character == '\n' || character == '\r') break;
|
||||||
|
if (character == '\b') {
|
||||||
|
if (i > 0) {
|
||||||
|
i--;
|
||||||
|
ConsolePrint("\b \b");
|
||||||
|
}
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[i++] = (char)character;
|
||||||
|
|
||||||
|
sConsoleWriteCharacter(character);
|
||||||
|
}
|
||||||
|
|
||||||
|
string[i] = '\0';
|
||||||
|
sConsoleWriteCharacter('\n');
|
||||||
|
|
||||||
|
return string;
|
||||||
|
}
|
||||||
@@ -0,0 +1,104 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
// brutally copypasting from kernel/mm/heap.c
|
||||||
|
|
||||||
|
#include <Memory.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
static MemoryBlockHeader* sMemoryHeapListHead = nullptr;
|
||||||
|
extern UInt64 OSServiceMemoryAllocate(UInt64 size);
|
||||||
|
|
||||||
|
static void sMemoryCombineForward(MemoryBlockHeader* current) {
|
||||||
|
if (!current->next || !current->next->isFree) return;
|
||||||
|
current->size += sizeof(MemoryBlockHeader) + current->next->size;
|
||||||
|
current->next = current->next->next;
|
||||||
|
if (current->next) current->next->previous = current;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* MemoryAllocate(UInt64 size) {
|
||||||
|
if (size == 0) return nullptr;
|
||||||
|
UInt64 alignedSize = (size + (kMemoryAlignment-1)) & ~(kMemoryAlignment - 1);
|
||||||
|
|
||||||
|
MemoryBlockHeader* current = sMemoryHeapListHead;
|
||||||
|
MemoryBlockHeader* lastBlock = nullptr;
|
||||||
|
|
||||||
|
while (current) {
|
||||||
|
if (current->isFree && current->size >= alignedSize) {
|
||||||
|
if (current->size > alignedSize + sizeof(MemoryBlockHeader) + kMemoryAlignment) {
|
||||||
|
MemoryBlockHeader* newBlock = (MemoryBlockHeader*)((UInt64)current + sizeof(MemoryBlockHeader) + alignedSize);
|
||||||
|
newBlock->size = current->size - alignedSize - sizeof(MemoryBlockHeader);
|
||||||
|
newBlock->isFree = true;
|
||||||
|
newBlock->next = current->next;
|
||||||
|
newBlock->previous = current;
|
||||||
|
newBlock->magic = kMemoryBlockMagic;
|
||||||
|
|
||||||
|
if (current->next) current->next->previous = newBlock;
|
||||||
|
current->next = newBlock;
|
||||||
|
current->size = alignedSize;
|
||||||
|
}
|
||||||
|
current->isFree = false;
|
||||||
|
return (void*)((UInt64)current + sizeof(MemoryBlockHeader));
|
||||||
|
}
|
||||||
|
lastBlock = current;
|
||||||
|
current = current->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64 sizeNeededToAllocate = alignedSize + sizeof(MemoryBlockHeader);
|
||||||
|
|
||||||
|
UInt64 pageAlignedSize = (sizeNeededToAllocate + (kMemoryPageSize-1)) & ~(kMemoryPageSize-1);
|
||||||
|
|
||||||
|
UInt64 newMemoryAddress = OSServiceMemoryAllocate(pageAlignedSize);
|
||||||
|
if (newMemoryAddress == 0) return nullptr;
|
||||||
|
|
||||||
|
MemoryBlockHeader* newBlock = (MemoryBlockHeader*)newMemoryAddress;
|
||||||
|
newBlock->size = pageAlignedSize - sizeof(MemoryBlockHeader);
|
||||||
|
newBlock->isFree = true;
|
||||||
|
newBlock->magic = kMemoryBlockMagic;
|
||||||
|
newBlock->next = nullptr;
|
||||||
|
newBlock->previous = lastBlock;
|
||||||
|
|
||||||
|
if (lastBlock) {
|
||||||
|
lastBlock->next = newBlock;
|
||||||
|
} else {
|
||||||
|
sMemoryHeapListHead = newBlock;
|
||||||
|
}
|
||||||
|
|
||||||
|
return MemoryAllocate(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MemoryFree(void* pointer) {
|
||||||
|
if (!pointer) return;
|
||||||
|
|
||||||
|
MemoryBlockHeader* current = (MemoryBlockHeader*)((UInt64)pointer - sizeof(MemoryBlockHeader));
|
||||||
|
if (current->magic != kMemoryBlockMagic) return;
|
||||||
|
|
||||||
|
current->isFree = true;
|
||||||
|
if (current->next && current->next->isFree) sMemoryCombineForward(current);
|
||||||
|
if (current->previous && current->previous->isFree) sMemoryCombineForward(current->previous);
|
||||||
|
}
|
||||||
|
|
||||||
|
void* MemoryReallocate(void* pointer, UInt64 newSize) {
|
||||||
|
if (!pointer) return MemoryAllocate(newSize);
|
||||||
|
if (newSize == 0) {
|
||||||
|
MemoryFree(pointer);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryBlockHeader* current = (MemoryBlockHeader*)((UInt64)pointer - sizeof(MemoryBlockHeader));
|
||||||
|
if (current->size >= newSize) return pointer;
|
||||||
|
|
||||||
|
if (current->next &&
|
||||||
|
current->next->isFree &&
|
||||||
|
(current->size + sizeof(MemoryBlockHeader) + current->next->size) >= newSize) {
|
||||||
|
sMemoryCombineForward(current);
|
||||||
|
return pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* newPointer = MemoryAllocate(newSize);
|
||||||
|
if (!newPointer) return nullptr;
|
||||||
|
|
||||||
|
MemoryCopy(newPointer, pointer, current->size);
|
||||||
|
MemoryFree(pointer);
|
||||||
|
|
||||||
|
return newPointer;
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
; Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
bits 64
|
||||||
|
|
||||||
|
section .text
|
||||||
|
|
||||||
|
global OSServiceProcessExit
|
||||||
|
global OSServiceProcessSpawn
|
||||||
|
global OSServiceMemoryAllocate
|
||||||
|
global OSServiceIOWrite
|
||||||
|
global OSServiceIORead
|
||||||
|
global OSServiceProcessWait
|
||||||
|
|
||||||
|
OSServiceProcessExit:
|
||||||
|
mov rax, 0
|
||||||
|
syscall
|
||||||
|
ret
|
||||||
|
|
||||||
|
OSServiceProcessSpawn:
|
||||||
|
mov rax, 1
|
||||||
|
syscall
|
||||||
|
ret
|
||||||
|
|
||||||
|
OSServiceMemoryAllocate:
|
||||||
|
mov rax, 2
|
||||||
|
syscall
|
||||||
|
ret
|
||||||
|
|
||||||
|
OSServiceIOWrite:
|
||||||
|
mov rax, 3
|
||||||
|
syscall
|
||||||
|
ret
|
||||||
|
|
||||||
|
OSServiceIORead:
|
||||||
|
mov rax, 4
|
||||||
|
syscall
|
||||||
|
ret
|
||||||
|
|
||||||
|
OSServiceProcessWait:
|
||||||
|
mov rax, 5
|
||||||
|
syscall
|
||||||
|
ret
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#include <Process.h>
|
||||||
|
|
||||||
|
extern Int32 OSServiceProcessSpawn(const char* path);
|
||||||
|
extern Int32 OSServiceProcessWait(UInt64 pid);
|
||||||
|
|
||||||
|
Int32 ProcessSpawn(const char* path) {
|
||||||
|
return OSServiceProcessSpawn(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32 ProcessWait(UInt64 pid) {
|
||||||
|
return OSServiceProcessWait(pid);
|
||||||
|
}
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
; SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
; Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
[bits 64]
|
||||||
|
|
||||||
|
section .text
|
||||||
|
global _start
|
||||||
|
extern main
|
||||||
|
extern OSServiceProcessExit
|
||||||
|
|
||||||
|
_start:
|
||||||
|
call main
|
||||||
|
mov rdi, rax
|
||||||
|
call OSServiceProcessExit
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
static char* olds;
|
||||||
|
|
||||||
|
void* MemorySet(void* destination, UInt8 value, UInt64 count) {
|
||||||
|
UInt8* bytePointer = (UInt8*) destination;
|
||||||
|
while (count--) {
|
||||||
|
*bytePointer++ = (UInt8)value;
|
||||||
|
}
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
void* MemoryCopy(void* destination, const void* source, UInt64 count) {
|
||||||
|
UInt8* destinationBuffer = (UInt8*)destination;
|
||||||
|
const UInt8* sourceBuffer = (const UInt8*)source;
|
||||||
|
|
||||||
|
while (count >= 8) {
|
||||||
|
*(UInt64*)destinationBuffer = *(const UInt64*)sourceBuffer;
|
||||||
|
destinationBuffer += 8;
|
||||||
|
sourceBuffer += 8;
|
||||||
|
count -= 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (count > 0) {
|
||||||
|
*destinationBuffer++ = *sourceBuffer++;
|
||||||
|
count--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32 StringCompare(const char* firstString, const char* secondString) {
|
||||||
|
while (*firstString && (*firstString == *secondString)) {
|
||||||
|
firstString++;
|
||||||
|
secondString++;
|
||||||
|
}
|
||||||
|
return *(const unsigned char*)firstString - *(const unsigned char*)secondString;
|
||||||
|
}
|
||||||
|
|
||||||
|
Int32 StringCompareWithLimit(const char* firstString, const char* secondString, UInt64 limit) {
|
||||||
|
while (limit > 0) {
|
||||||
|
if (*firstString != *secondString) return *(unsigned char*)firstString - *(unsigned char*)secondString;
|
||||||
|
if (*firstString == '\0') return 0;
|
||||||
|
firstString++;
|
||||||
|
secondString++;
|
||||||
|
limit--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* StringCopy(char* destination, const char* source) {
|
||||||
|
char* saved = destination;
|
||||||
|
while (*source) *destination++ = *source++;
|
||||||
|
*destination = 0;
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* StringCopyWithLimit(char* destination, const char* source, UInt64 limit) {
|
||||||
|
char* saved = destination;
|
||||||
|
while (*source && limit > 0) {
|
||||||
|
*destination++ = *source++;
|
||||||
|
limit--;
|
||||||
|
}
|
||||||
|
while (limit > 0) {
|
||||||
|
*destination++ = 0;
|
||||||
|
limit--;
|
||||||
|
}
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64 StringGetLength(const char* string) {
|
||||||
|
UInt64 result = 0;
|
||||||
|
for (result = 0; string[result]; result++);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int sStringIsInSet(char character, const char* set) {
|
||||||
|
while (*set) {
|
||||||
|
if (*set == character) return 1;
|
||||||
|
set++;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64 StringGetInitialSpan(const char* string, const char* characterSet) {
|
||||||
|
UInt64 count = 0;
|
||||||
|
while (*string && sStringIsInSet(*string, characterSet)) {
|
||||||
|
count++;
|
||||||
|
string++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* StringFindFirstCharacterFromSet(const char* string, const char* set) {
|
||||||
|
while (*string) {
|
||||||
|
if (sStringIsInSet(*string, set)) {
|
||||||
|
return (char*)string;
|
||||||
|
}
|
||||||
|
string++;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// took from https://github.com/walac/glibc/blob/master/string/strtok.c
|
||||||
|
char* StringTokenize(char* string, const char* delimiters) {
|
||||||
|
char* token;
|
||||||
|
if (string == nullptr) string = olds;
|
||||||
|
string += StringGetInitialSpan(string, delimiters);
|
||||||
|
if (*string == '\0') {
|
||||||
|
olds = string;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
token = string;
|
||||||
|
string = StringFindFirstCharacterFromSet(token, delimiters);
|
||||||
|
if (string == nullptr) olds = token + StringGetLength(token);
|
||||||
|
else {
|
||||||
|
*string = '\0';
|
||||||
|
olds = string + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return token;
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
[env]
|
||||||
|
RUST_TARGET_PATH = { value = ".", relative = true }
|
||||||
|
|
||||||
|
[build]
|
||||||
|
target = "x86_64-termos"
|
||||||
|
|
||||||
|
[unstable]
|
||||||
|
build-std =["core", "alloc", "compiler_builtins"]
|
||||||
|
build-std-features = ["compiler-builtins-mem"]
|
||||||
|
|
||||||
|
[target.x86_64-termos]
|
||||||
|
rustflags =[
|
||||||
|
"-Z", "unstable-options",
|
||||||
|
"-C", "link-arg=-Tlinker.ld"
|
||||||
|
]
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
project(rustApps NONE)
|
||||||
|
|
||||||
|
function(add_rust_app NAME)
|
||||||
|
set(RUST_TARGET "x86_64-termos")
|
||||||
|
set(RUST_TARGET_DIR "${CMAKE_CURRENT_SOURCE_DIR}/target")
|
||||||
|
set(RUST_ELF_FILE "${RUST_TARGET_DIR}/${RUST_TARGET}/release/${NAME}")
|
||||||
|
|
||||||
|
set(STARTUP_VOLUME_DIR "${CMAKE_BINARY_DIR}/StartupVolume/System/CoreServices")
|
||||||
|
set(FINAL_HOT_PATH "${STARTUP_VOLUME_DIR}/${NAME}")
|
||||||
|
set(STRIPPED_ELF "${CMAKE_CURRENT_BINARY_DIR}/${NAME}.stripped")
|
||||||
|
set(ELF2HOT_DIR "${CMAKE_SOURCE_DIR}/tools/elf2hot")
|
||||||
|
|
||||||
|
file(MAKE_DIRECTORY "${STARTUP_VOLUME_DIR}")
|
||||||
|
|
||||||
|
add_custom_target(${NAME} ALL
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E env
|
||||||
|
"CARGO_TARGET_DIR=${RUST_TARGET_DIR}"
|
||||||
|
cargo build --package ${NAME} --release --target ${RUST_TARGET}
|
||||||
|
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E env
|
||||||
|
"PATH=/usr/local/opt/llvm/bin:/opt/homebrew/opt/llvm/bin:$ENV{PATH}"
|
||||||
|
llvm-objcopy --strip-all ${RUST_ELF_FILE} ${STRIPPED_ELF}
|
||||||
|
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E chdir ${ELF2HOT_DIR} cargo run --release --quiet -- ${STRIPPED_ELF} ${FINAL_HOT_PATH}
|
||||||
|
|
||||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
|
COMMENT "Building, stripping and packing ${NAME} to initramfs..."
|
||||||
|
VERBATIM
|
||||||
|
)
|
||||||
|
endfunction()
|
||||||
|
|
||||||
|
add_rust_app(rtest)
|
||||||
Generated
+50
@@ -0,0 +1,50 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "linked_list_allocator"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2b23ac50abb8261cb38c6e2a7192d3302e0836dac1628f6a93b82b4fad185897"
|
||||||
|
dependencies = [
|
||||||
|
"spinning_top",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "lock_api"
|
||||||
|
version = "0.4.14"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
|
||||||
|
dependencies = [
|
||||||
|
"scopeguard",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rtest"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"std",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scopeguard"
|
||||||
|
version = "1.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "spinning_top"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5b9eb1a2f4c41445a3a0ff9abc5221c5fcd28e1f13cd7c0397706f9ac938ddb0"
|
||||||
|
dependencies = [
|
||||||
|
"lock_api",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "std"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"linked_list_allocator",
|
||||||
|
]
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
[workspace]
|
||||||
|
members = ["std", "apps/rtest"]
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
strip = true
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "rtest"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
std = { path = "../../std" }
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
fn main() {
|
||||||
|
let anus = "jopa";
|
||||||
|
println!("meow");
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
ENTRY(_start)
|
||||||
|
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
. = 0x400000;
|
||||||
|
|
||||||
|
.text : {
|
||||||
|
*(.text)
|
||||||
|
}
|
||||||
|
|
||||||
|
.rodata : {
|
||||||
|
*(.rodata)
|
||||||
|
}
|
||||||
|
|
||||||
|
.data : {
|
||||||
|
*(.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
.bss : {
|
||||||
|
*(.bss)
|
||||||
|
*(COMMON)
|
||||||
|
}
|
||||||
|
|
||||||
|
/DISCARD/ : {
|
||||||
|
*(.note.gnu.build-id)
|
||||||
|
*(.note.GNU-stack)
|
||||||
|
*(.note.gnu.property)
|
||||||
|
*(.comment)
|
||||||
|
*(.interp)
|
||||||
|
*(.dynsym)
|
||||||
|
*(.dynstr)
|
||||||
|
*(.hash)
|
||||||
|
*(.gnu.hash)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
[toolchain]
|
||||||
|
channel = "nightly"
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "std"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
linked_list_allocator = "0.10.6"
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
extern crate alloc;
|
||||||
|
|
||||||
|
use core::alloc::{GlobalAlloc, Layout};
|
||||||
|
use linked_list_allocator::LockedHeap;
|
||||||
|
|
||||||
|
#[global_allocator]
|
||||||
|
static ALLOCATOR: LockedHeap = LockedHeap::empty();
|
||||||
|
|
||||||
|
pub unsafe fn init_heap() {
|
||||||
|
let heap_size = 1024 * 1024;
|
||||||
|
let heap_start = crate::syscall::memory_allocate(heap_size);
|
||||||
|
|
||||||
|
ALLOCATOR.lock().init(heap_start as *mut u8, heap_size);
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
use core::fmt::{self, Write};
|
||||||
|
|
||||||
|
pub struct Stdout;
|
||||||
|
|
||||||
|
impl Write for Stdout {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
crate::syscall::io_write(1, s.as_ptr(), s.len());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn _print(args: core::fmt::Arguments) {
|
||||||
|
let mut stdout = crate::io::Stdout;
|
||||||
|
let _ = core::fmt::Write::write_fmt(&mut stdout, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! print {
|
||||||
|
($($arg:tt)*) => ($crate::io::_print(core::format_args!($($arg)*)));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! println {
|
||||||
|
() => ($crate::print!("\n"));
|
||||||
|
($($arg:tt)*) => {
|
||||||
|
$crate::print!($($arg)*);
|
||||||
|
$crate::print!("\n");
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#![no_std]
|
||||||
|
#![feature(lang_items)]
|
||||||
|
|
||||||
|
pub use core::*;
|
||||||
|
extern crate alloc;
|
||||||
|
pub use alloc::*;
|
||||||
|
|
||||||
|
pub mod allocator;
|
||||||
|
pub mod io;
|
||||||
|
pub mod panic;
|
||||||
|
pub mod syscall;
|
||||||
|
|
||||||
|
|
||||||
|
pub mod prelude {
|
||||||
|
pub mod rust_2024 {
|
||||||
|
pub use core::prelude::rust_2024::*;
|
||||||
|
pub use alloc::string::{String, ToString};
|
||||||
|
pub use alloc::vec::Vec;
|
||||||
|
pub use alloc::vec;
|
||||||
|
pub use alloc::format;
|
||||||
|
pub use crate::{print, println};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
core::arch::global_asm!(
|
||||||
|
".global _start",
|
||||||
|
"_start:",
|
||||||
|
"and rsp, ~0xF",
|
||||||
|
"xor rdi, rdi",
|
||||||
|
"xor rsi, rsi",
|
||||||
|
"call main",
|
||||||
|
"mov rdi, rax",
|
||||||
|
"mov rax, 0",
|
||||||
|
"syscall"
|
||||||
|
);
|
||||||
|
|
||||||
|
#[lang = "start"]
|
||||||
|
fn lang_start<T>(
|
||||||
|
user_main: fn() -> T,
|
||||||
|
_argc: isize,
|
||||||
|
_argv: *const *const u8,
|
||||||
|
_sigpipe: u8,
|
||||||
|
) -> isize {
|
||||||
|
unsafe { crate::allocator::init_heap() };
|
||||||
|
|
||||||
|
user_main();
|
||||||
|
|
||||||
|
crate::syscall::process_exit(0);
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
use core::panic::PanicInfo;
|
||||||
|
use crate::println;
|
||||||
|
|
||||||
|
#[panic_handler]
|
||||||
|
fn panic(info: &PanicInfo) -> ! {
|
||||||
|
println!("{}", info);
|
||||||
|
|
||||||
|
crate::syscall::process_exit(1);
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
use core::arch::asm;
|
||||||
|
|
||||||
|
pub const SYS_EXIT: usize = 0;
|
||||||
|
pub const SYS_SPAWN: usize = 1;
|
||||||
|
pub const SYS_ALLOC: usize = 2;
|
||||||
|
pub const SYS_WRITE: usize = 3;
|
||||||
|
pub const SYS_READ: usize = 4;
|
||||||
|
pub const SYS_WAIT: usize = 5;
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn syscall1(num: usize, arg1: usize) -> usize {
|
||||||
|
let ret: usize;
|
||||||
|
unsafe {
|
||||||
|
asm!(
|
||||||
|
"syscall",
|
||||||
|
inout("rax") num => ret,
|
||||||
|
in("rdi") arg1,
|
||||||
|
out("rcx") _,
|
||||||
|
out("r11") _,
|
||||||
|
options(nostack, preserves_flags)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
unsafe fn syscall3(num: usize, arg1: usize, arg2: usize, arg3: usize) -> usize {
|
||||||
|
let ret: usize;
|
||||||
|
core::arch::asm!(
|
||||||
|
"syscall",
|
||||||
|
in("rax") num,
|
||||||
|
in("rdi") arg1,
|
||||||
|
in("rsi") arg2,
|
||||||
|
in("rdx") arg3,
|
||||||
|
lateout("rax") ret,
|
||||||
|
out("rcx") _,
|
||||||
|
out("r11") _,
|
||||||
|
options(nostack)
|
||||||
|
);
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_exit(code: usize) -> ! {
|
||||||
|
unsafe { syscall1(SYS_EXIT, code) };
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_spawn(path: usize) -> usize {
|
||||||
|
unsafe { syscall1(SYS_SPAWN, path) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn process_wait(pid: usize) -> usize {
|
||||||
|
unsafe { syscall1(SYS_WAIT, pid) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn memory_allocate(size: usize) -> usize {
|
||||||
|
unsafe { syscall1(SYS_ALLOC, size) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn io_write(fd: usize, buf: *const u8, len: usize) -> usize {
|
||||||
|
unsafe { syscall3(SYS_WRITE, fd, buf as usize, len) }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn io_read(fd: usize, buf: *const u8, len: usize) -> usize {
|
||||||
|
unsafe { syscall3(SYS_READ, fd, buf as usize, len) }
|
||||||
|
}
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"llvm-target": "x86_64-unknown-none",
|
||||||
|
"data-layout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128",
|
||||||
|
"arch": "x86_64",
|
||||||
|
"target-endian": "little",
|
||||||
|
"target-pointer-width": 64,
|
||||||
|
"target-c-int-width": 32,
|
||||||
|
"os": "termos",
|
||||||
|
"executables": true,
|
||||||
|
"linker-flavor": "ld.lld",
|
||||||
|
"linker": "rust-lld",
|
||||||
|
"panic-strategy": "abort",
|
||||||
|
"position-independent-executables": true,
|
||||||
|
"relocation-model": "pic"
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
cmake_minimum_required(VERSION 3.20)
|
||||||
|
project(termOSh LANGUAGES C)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE TERMOSH_SOURCES "src/*.c")
|
||||||
|
|
||||||
|
add_termos_executable(termosh "${TERMOSH_SOURCES}")
|
||||||
|
target_include_directories(termosh PRIVATE
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/inc"
|
||||||
|
)
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
void not_implemented_yet();
|
||||||
|
void cmd_spawn(const char* path);
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "tokens.h"
|
||||||
|
|
||||||
|
termosh_token char2token(char* token);
|
||||||
|
int tokenize(char* buffer, char* tokens[], int max_tokens);
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
TOKEN_EMPTY,
|
||||||
|
TOKEN_NULL,
|
||||||
|
TOKEN_ILLEGAL,
|
||||||
|
|
||||||
|
TOKEN_QUIT,
|
||||||
|
TOKEN_CLEAR,
|
||||||
|
TOKEN_HELP,
|
||||||
|
TOKEN_SPAWN,
|
||||||
|
|
||||||
|
} termosh_token;
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
#include <termOS.h>
|
||||||
|
|
||||||
|
void not_implemented_yet() {
|
||||||
|
ConsolePrint("Not implemented yet!\n");
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
#include "handlers.h"
|
||||||
|
#include <termOS.h>
|
||||||
|
|
||||||
|
void cmd_spawn(const char* path) {
|
||||||
|
Int32 pid = ProcessSpawn(path);
|
||||||
|
if (pid < 0) {
|
||||||
|
switch (pid) {
|
||||||
|
case -1: ConsolePrint("\"%s\" not found.\n", path); break;
|
||||||
|
default: ConsolePrint("failed to spawn (%d)\n", pid); break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ProcessWait(pid);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#include <termOS.h>
|
||||||
|
#include "parser.h"
|
||||||
|
#include "handlers.h"
|
||||||
|
|
||||||
|
#define BUFFER_SIZE 512
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
while (true) {
|
||||||
|
ConsolePrint("termosh_> ");
|
||||||
|
char cmdbuff[BUFFER_SIZE];
|
||||||
|
ConsoleReadLine(cmdbuff, BUFFER_SIZE);
|
||||||
|
char* tokens[BUFFER_SIZE];
|
||||||
|
int tokens_count = tokenize(cmdbuff, tokens, BUFFER_SIZE);
|
||||||
|
if (tokens_count < 1) continue;
|
||||||
|
termosh_token token = char2token(tokens[0]);
|
||||||
|
switch (token) {
|
||||||
|
case TOKEN_QUIT: return 0;
|
||||||
|
case TOKEN_CLEAR: not_implemented_yet(); break;
|
||||||
|
case TOKEN_HELP: not_implemented_yet(); break;
|
||||||
|
case TOKEN_SPAWN: if (tokens_count >= 2) cmd_spawn(tokens[1]); break;
|
||||||
|
default: {
|
||||||
|
char buff[256];
|
||||||
|
StringFormat(buff, sizeof(buff), "/System/CoreServices/%s", tokens[0]);
|
||||||
|
cmd_spawn(buff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
#include <termOS.h>
|
||||||
|
|
||||||
|
#include "parser.h"
|
||||||
|
#include "tokens.h"
|
||||||
|
|
||||||
|
static const char* delim = " \t\r\n";
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char* str;
|
||||||
|
termosh_token token;
|
||||||
|
} termosh_token_map;
|
||||||
|
|
||||||
|
static const termosh_token_map token_map[] = {
|
||||||
|
{"q", TOKEN_QUIT},
|
||||||
|
{"quit", TOKEN_QUIT},
|
||||||
|
{"exit", TOKEN_QUIT},
|
||||||
|
|
||||||
|
{"clear", TOKEN_CLEAR},
|
||||||
|
|
||||||
|
{"help", TOKEN_HELP},
|
||||||
|
{"spawn", TOKEN_SPAWN},
|
||||||
|
|
||||||
|
{nullptr, TOKEN_NULL}
|
||||||
|
};
|
||||||
|
|
||||||
|
termosh_token char2token(char* token) {
|
||||||
|
for (int i = 0; token_map[i].str != nullptr; i++) {
|
||||||
|
if (StringCompare(token, token_map[i].str) == 0) {
|
||||||
|
return token_map[i].token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return TOKEN_ILLEGAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tokenize(char* buffer, char* tokens[], int max_tokens) {
|
||||||
|
char* token = StringTokenize(buffer, delim);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while (token != nullptr && i < max_tokens) {
|
||||||
|
tokens[i] = token;
|
||||||
|
token = StringTokenize(nullptr, delim);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return i;
|
||||||
|
}
|
||||||
@@ -11,6 +11,17 @@ endif()
|
|||||||
|
|
||||||
message(STATUS "Dewar kernel: Building for architecture '${ARCH}'")
|
message(STATUS "Dewar kernel: Building for architecture '${ARCH}'")
|
||||||
|
|
||||||
|
set(TERMOS_OBJCOPY objcopy)
|
||||||
|
if(APPLE)
|
||||||
|
find_program(TERMOS_LD_LLD NAMES ld.lld HINTS /usr/local/bin /opt/homebrew/bin REQUIRED)
|
||||||
|
find_program(TERMOS_OBJCOPY NAMES llvm-objcopy objcopy HINTS /usr/local/opt/llvm/bin /opt/homebrew/opt/llvm/bin REQUIRED)
|
||||||
|
set(CMAKE_C_LINK_FLAGS "")
|
||||||
|
set(CMAKE_ASM_NASM_COMPILE_OBJECT
|
||||||
|
"<CMAKE_ASM_NASM_COMPILER> <DEFINES> <INCLUDES> <FLAGS> -MD <DEP_FILE> -MT <DEP_TARGET> -f elf64 -o <OBJECT> <SOURCE>")
|
||||||
|
set(CMAKE_C_LINK_EXECUTABLE
|
||||||
|
"${TERMOS_LD_LLD} <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS> -o <TARGET> <LINK_LIBRARIES>")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
|
||||||
file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS
|
file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS
|
||||||
"src/kmain.c"
|
"src/kmain.c"
|
||||||
@@ -18,26 +29,30 @@ file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS
|
|||||||
"src/arch/${ARCH}/*.c"
|
"src/arch/${ARCH}/*.c"
|
||||||
"src/arch/${ARCH}/*.asm"
|
"src/arch/${ARCH}/*.asm"
|
||||||
|
|
||||||
"src/core/*.c"
|
"src/OS/*.c"
|
||||||
"src/drivers/*.c"
|
"src/OS/Exec/*.c"
|
||||||
"src/mm/*.c"
|
"src/OS/Services/*.c"
|
||||||
"src/shell/*.c"
|
"src/lib/*.c"
|
||||||
"src/fs/*.c"
|
"src/IO/*.c"
|
||||||
|
"src/VM/*.c"
|
||||||
|
"src/FS/*.c"
|
||||||
|
|
||||||
"data/*.c"
|
"Data/*.c"
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(kernel ${KERNEL_SOURCES})
|
add_executable(kernel ${KERNEL_SOURCES})
|
||||||
|
set_target_properties(kernel PROPERTIES NASM_OBJ_FORMAT elf64)
|
||||||
|
|
||||||
target_include_directories(kernel PRIVATE
|
target_include_directories(kernel PRIVATE
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/../common"
|
"${CMAKE_CURRENT_SOURCE_DIR}/../common"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/inc"
|
"${CMAKE_CURRENT_SOURCE_DIR}/inc"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/inc/arch/${ARCH}"
|
"${CMAKE_CURRENT_SOURCE_DIR}/inc/arch/${ARCH}"
|
||||||
"${CMAKE_CURRENT_SOURCE_DIR}/data"
|
"${CMAKE_CURRENT_SOURCE_DIR}/Data"
|
||||||
)
|
)
|
||||||
|
|
||||||
target_compile_options(kernel PRIVATE
|
target_compile_options(kernel PRIVATE
|
||||||
$<$<COMPILE_LANGUAGE:C>:
|
$<$<COMPILE_LANGUAGE:C>:
|
||||||
|
$<$<BOOL:${APPLE}>:--target=x86_64-none-elf>
|
||||||
-ffreestanding
|
-ffreestanding
|
||||||
-mno-red-zone
|
-mno-red-zone
|
||||||
-fno-stack-protector
|
-fno-stack-protector
|
||||||
@@ -45,7 +60,9 @@ target_compile_options(kernel PRIVATE
|
|||||||
-Wall -Wextra
|
-Wall -Wextra
|
||||||
-mcmodel=kernel
|
-mcmodel=kernel
|
||||||
-g
|
-g
|
||||||
|
-mno-sse -mno-sse2 -msoft-float
|
||||||
>
|
>
|
||||||
|
$<$<AND:$<BOOL:${APPLE}>,$<COMPILE_LANGUAGE:ASM>>:--target=x86_64-none-elf>
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_options(kernel PRIVATE
|
target_link_options(kernel PRIVATE
|
||||||
@@ -62,6 +79,8 @@ set_target_properties(kernel PROPERTIES
|
|||||||
)
|
)
|
||||||
|
|
||||||
add_custom_command(TARGET kernel POST_BUILD
|
add_custom_command(TARGET kernel POST_BUILD
|
||||||
COMMAND objcopy -O binary $<TARGET_FILE:kernel> $<TARGET_FILE_DIR:kernel>/kernel.bin
|
COMMAND ${CMAKE_COMMAND} -E env
|
||||||
|
"PATH=/usr/local/opt/llvm/bin:/opt/homebrew/opt/llvm/bin:$ENV{PATH}"
|
||||||
|
llvm-objcopy -O binary $<TARGET_FILE:kernel> $<TARGET_FILE_DIR:kernel>/kernel.bin
|
||||||
COMMENT "Generating raw binary kernel.bin..."
|
COMMENT "Generating raw binary kernel.bin..."
|
||||||
)
|
)
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
// font8x16 bitmap font
|
#pragma once
|
||||||
// Source: https://github.com/hubenchang0515/font8x16
|
#include <types.h>
|
||||||
// License: MIT
|
|
||||||
|
|
||||||
unsigned char font8x16[][16] = {
|
|
||||||
|
unsigned char VGAFont[][16] = {
|
||||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, //0x00,
|
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, }, //0x00,
|
||||||
{ 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, }, //0x01,
|
{ 0x00, 0x00, 0x7E, 0x81, 0xA5, 0x81, 0x81, 0xBD, 0x99, 0x81, 0x81, 0x7E, 0x00, 0x00, 0x00, 0x00, }, //0x01,
|
||||||
{ 0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00, }, //0x02,
|
{ 0x00, 0x00, 0x7E, 0xFF, 0xDB, 0xFF, 0xFF, 0xC3, 0xE7, 0xFF, 0xFF, 0x7E, 0x00, 0x00, 0x00, 0x00, }, //0x02,
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// Copyright (c) 2025 0xKarinyash
|
// Copyright (c) 2026 0xKarinyash
|
||||||
// cats licensed to their authors
|
// cats licensed to their authors
|
||||||
// i took it from https://www.asciiart.eu/animals/cats
|
// i took it from https://www.asciiart.eu/animals/cats
|
||||||
|
|
||||||
@@ -1,14 +1,14 @@
|
|||||||
// Huge thanks to https://t.me/kinolenta2004 for this amazing logo
|
// Huge thanks to https://t.me/kinolenta2004 for this amazing logo
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// Copyright (c) 2025 0xKarinyash
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <drivers/shitgui.h>
|
#include <IO/IOGraphics.h>
|
||||||
|
|
||||||
#define LOGO_TRANSPARENCY_KEY 0xFF00FF
|
#define LOGO_TRANSPARENCY_KEY 0xFF00FF
|
||||||
|
|
||||||
// Image: 100x100
|
// Image: 100x100
|
||||||
static const u32 logo_data[] = {
|
static const UInt32 logo_data[] = {
|
||||||
0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF,
|
0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF,
|
||||||
0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF,
|
0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF,
|
||||||
0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF,
|
0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF,
|
||||||
@@ -1261,8 +1261,7 @@ static const u32 logo_data[] = {
|
|||||||
0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF,
|
0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF, 0xFF00FF,
|
||||||
};
|
};
|
||||||
|
|
||||||
static SG_Image logo_img = {
|
static IOGraphicsImage logoImage = {
|
||||||
.width = 100,
|
.size = {100, 100},
|
||||||
.height = 100,
|
.buffer = (UInt32*)logo_data
|
||||||
.buffer = (u32*)logo_data
|
|
||||||
};
|
};
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
#include <FS/VFS.h>
|
||||||
|
|
||||||
|
UInt64 FSCPIORead(FSVNode* node, UInt64 offset, UInt64 size, UInt8* buffer);
|
||||||
|
FSVNode* FSCPIOMount(void* baseAddress, UInt64 totalSize);
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
typedef enum FSVNodeFlags {
|
||||||
|
kFSVNodeFlagFile = 0x01,
|
||||||
|
kFSVNodeFlagDirectory = 0x02,
|
||||||
|
} FSVNodeFlags;
|
||||||
|
|
||||||
|
typedef struct FSVNode FSVNode;
|
||||||
|
|
||||||
|
typedef struct FSVNodeOperations {
|
||||||
|
UInt64 (*read)(FSVNode* node, UInt64 offset, UInt64 size, UInt8* buffer);
|
||||||
|
UInt64 (*write)(FSVNode* node, UInt64 offset, UInt64 size, UInt8* buffer);
|
||||||
|
void (*open)(FSVNode* node);
|
||||||
|
void (*close)(FSVNode* node);
|
||||||
|
FSVNode* (*findDirectory)(FSVNode* node, char* name);
|
||||||
|
} FSVNodeOperations;
|
||||||
|
|
||||||
|
typedef struct FSVNode {
|
||||||
|
char name[256];
|
||||||
|
UInt32 protectionMask;
|
||||||
|
UInt32 ownerIdentifier;
|
||||||
|
UInt32 groupIdentifier;
|
||||||
|
UInt32 flags;
|
||||||
|
UInt32 inodeIdentifier;
|
||||||
|
UInt64 dataLength;
|
||||||
|
|
||||||
|
FSVNodeOperations* operations;
|
||||||
|
void* implementationData;
|
||||||
|
|
||||||
|
struct FSVNode* mountPoint;
|
||||||
|
struct FSVNode* childNode;
|
||||||
|
struct FSVNode* nextNode;
|
||||||
|
} FSVNode;
|
||||||
|
|
||||||
|
void FSVirtualFileSystemInitialize(FSVNode* rootNode);
|
||||||
|
UInt64 FSVNodeRead(FSVNode* node, UInt64 offset, UInt64 size, UInt8* buffer);
|
||||||
|
FSVNode* FSVirtualFileSystemOpenPath(const char* path);
|
||||||
|
void FSVNodeClose(FSVNode* node);
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <IO/IOGraphics.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kIOConsoleColorRed = 0xFF5555,
|
||||||
|
kIOConsoleColorVeryRed = 0xFF0000,
|
||||||
|
kIOConsoleColorGreen = 0x08bf39,
|
||||||
|
kIOConsoleColorVeryGreen = 0x00FF00,
|
||||||
|
kIOConsoleColorTurqoise = 0x5effaf,
|
||||||
|
kIOConsoleColorBlue = 0x5555FF,
|
||||||
|
kIOConsoleColorVeryBlue = 0x0000FF,
|
||||||
|
kIOConsoleColorLightBlue = 0x3890e8,
|
||||||
|
kIOConsoleColorYellow = 0xFFFF55,
|
||||||
|
kIOConsoleColorCyan = 0x55FFFF,
|
||||||
|
kIOConsoleColorMagneta = 0xFF55FF,
|
||||||
|
kIOConsoleColorBlack = 0x000000,
|
||||||
|
kIOConsoleColorWhite = 0xFFFFFF,
|
||||||
|
kIOConsoleColorPink = 0xFFA3B1,
|
||||||
|
};
|
||||||
|
|
||||||
|
void IOConsoleInit(IOGraphicsContext* context);
|
||||||
|
UInt64 IOConsoleGetColors();
|
||||||
|
void IOConsoleClear(IOGraphicsColor color);
|
||||||
|
IOGraphicsContext* IOConsoleGetGraphicsContext();
|
||||||
|
IOGraphicsSize IOConsoleGetDimensions();
|
||||||
|
void IOConsoleSetForegroundColor(IOGraphicsColor color);
|
||||||
|
void IOConsoleSetDefaultForegroundColor(UInt32 color);
|
||||||
|
void IOConsoleSetCursorPosition(IOGraphicsPoint* point);
|
||||||
|
void IOConsoleReadLine(char* buffer, UInt32 limit);
|
||||||
|
void IOConsolePutcharacter(char character);
|
||||||
|
void IOConsolePrint(const char *string);
|
||||||
|
void IOConsoleLog(const char *fmt, ...);
|
||||||
@@ -0,0 +1,50 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
// RIP shitgui -- you started it all
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
typedef UInt32 IOGraphicsColor;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UInt32 x;
|
||||||
|
UInt32 y;
|
||||||
|
} IOGraphicsPoint;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UInt32 width;
|
||||||
|
UInt32 height;
|
||||||
|
} IOGraphicsSize;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
volatile UInt32* framebuffer;
|
||||||
|
IOGraphicsSize dimensions;
|
||||||
|
UInt32 pixelsPerScanLine;
|
||||||
|
} IOGraphicsContext;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
IOGraphicsColor* buffer;
|
||||||
|
IOGraphicsSize size;
|
||||||
|
} IOGraphicsImage;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
IOGraphicsSize size;
|
||||||
|
const unsigned char* baseAddress;
|
||||||
|
} IOGraphicsFont;
|
||||||
|
|
||||||
|
|
||||||
|
UInt32 IOGraphicsGetPixel(IOGraphicsContext* context, IOGraphicsPoint* point);
|
||||||
|
|
||||||
|
void IOGraphicsDrawImage(IOGraphicsContext* context, IOGraphicsPoint* point, IOGraphicsImage* image);
|
||||||
|
|
||||||
|
void IOGraphicsDrawRectangle(IOGraphicsContext* context, IOGraphicsPoint* point,
|
||||||
|
IOGraphicsSize* size, IOGraphicsColor color);
|
||||||
|
|
||||||
|
void IOGraphicsDrawCharacter(
|
||||||
|
IOGraphicsContext* context,
|
||||||
|
IOGraphicsPoint* point,
|
||||||
|
char character,
|
||||||
|
IOGraphicsColor color,
|
||||||
|
IOGraphicsFont* font
|
||||||
|
);
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
#include <OS/OSSpinlock.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kIOKeyboardBufferSize = 256,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
OSSpinlock lock;
|
||||||
|
char buffer[kIOKeyboardBufferSize];
|
||||||
|
volatile UInt16 head;
|
||||||
|
volatile UInt16 tail;
|
||||||
|
} IOKeyboardController;
|
||||||
|
|
||||||
|
extern IOKeyboardController gIOKeyboardController;
|
||||||
|
|
||||||
|
void IOKeyboardInterruptsHandler();
|
||||||
|
char IOKeyboardGetCharacter();
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
int IOSerialInit();
|
||||||
|
void IOSerialWriteChar(char character);
|
||||||
|
void IOSerialWrite(const char *string);
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
void IOTimerInitialize(UInt32 freq);
|
||||||
|
UInt64 IOTimerInterruptsHandler(CPURegisters *regs);
|
||||||
|
UInt64 IOTimerGetTicks();
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
#include <OS/OSScheduler.h>
|
||||||
|
|
||||||
|
UInt64 HOTLoad(OSProcess* process, UInt8* data);
|
||||||
@@ -4,7 +4,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
#include <core/scheduler.h>
|
|
||||||
|
|
||||||
bool exec_init(process* p, const char* path);
|
Int32 OSLoaderProcessSpawn(const char* executablePath, const char* processName);
|
||||||
void init_task_entry();
|
void initTask();
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
__attribute__((noreturn)) void OSPanicException(CPURegisters* frame);
|
||||||
|
__attribute__((noreturn)) void OSPanic(const char* msg);
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
typedef enum OSProcessState {
|
||||||
|
kOSProcessStateDead,
|
||||||
|
kOSProcessStateRunning,
|
||||||
|
kOSProcessStateReady,
|
||||||
|
kOSProcessStateBlocked,
|
||||||
|
kOSProcessStateSleeping,
|
||||||
|
} OSProcessState;
|
||||||
|
|
||||||
|
typedef struct OSProcess {
|
||||||
|
UInt64 processId;
|
||||||
|
OSProcessState state;
|
||||||
|
UInt64 physicalPML4;
|
||||||
|
struct OSProcess* parent;
|
||||||
|
char name[32];
|
||||||
|
UInt64 heapStartPointer;
|
||||||
|
UInt64 heapCurrentPointer;
|
||||||
|
} OSProcess;
|
||||||
|
|
||||||
|
typedef struct OSTask {
|
||||||
|
UInt64 stackPointer;
|
||||||
|
struct OSTask* next;
|
||||||
|
UInt32 id;
|
||||||
|
UInt32 sleepTicks;
|
||||||
|
OSProcessState taskState; // reusing process_state cuz wn
|
||||||
|
UInt64 kernelStackTop;
|
||||||
|
void* kernelStackBase;
|
||||||
|
OSProcess* process;
|
||||||
|
Int32 waitingForProcess;
|
||||||
|
} OSTask;
|
||||||
|
|
||||||
|
void OSSchedulerInitialize();
|
||||||
|
OSTask* OSSchedulerSpawn(void(*entry)(), OSProcess* owner, Boolean isUser, UInt64 fixedUserStackPointer);
|
||||||
|
UInt64 OSSchedulerNext(UInt64 currentStackPointer);
|
||||||
|
void OSSchedulerYield(UInt64 ticks);
|
||||||
|
void OSSchedulerBlock(UInt32 processID);
|
||||||
|
void OSSchedulerWakeup(UInt32 processID);
|
||||||
|
void OSSchedulerTerminate(); // suicide
|
||||||
|
|
||||||
|
extern OSTask* gOSSchedulerCurrentTask;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
typedef struct OSSpinlock {
|
||||||
|
volatile UInt32 lockValue;
|
||||||
|
} OSSpinlock;
|
||||||
|
|
||||||
|
typedef struct OSSpinlockState {
|
||||||
|
Boolean interruptsEnabled;
|
||||||
|
} OSSpinlockState;
|
||||||
|
|
||||||
|
void OSSpinlockLock(OSSpinlock* lock);
|
||||||
|
void OSSpinlockUnlock(OSSpinlock* lock);
|
||||||
|
void OSSpinlockLockIRQ(OSSpinlock* lock, OSSpinlockState* state);
|
||||||
|
void OSSpinlockUnlockIRQ(OSSpinlock *lock, OSSpinlockState* state);
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
UInt64 OSServiceIOWrite(UInt64 fileDescriptor, UInt64 buffer, UInt64 length);
|
||||||
|
UInt64 OSServiceIORead(UInt64 fileDescriptor, UInt64 buffer, UInt64 count);
|
||||||
@@ -3,6 +3,5 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
#include <core/scheduler.h>
|
|
||||||
|
|
||||||
u64 load_hot(process* proc, u8* data);
|
UInt64 OSServiceMemoryAllocate(UInt64 size);
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
Int32 OSServiceProcessExit(Int32 code);
|
||||||
|
Int32 OSServiceProcessSpawn(const char* path);
|
||||||
|
Int32 OSServiceProcessWait(UInt64 pid);
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kVMKernelHeapStart = 0xFFFFFFFFC0000000,
|
||||||
|
kVMHeapSizePages = 1024,
|
||||||
|
kVMHeapBlockHeaderMagic = 0x1CE
|
||||||
|
};
|
||||||
|
|
||||||
|
#define PHYS_TO_HEAP(phys) ((phys) + KERNEL_HEAP_START)
|
||||||
|
#define HEAP_TO_PHYS(phys) ((phys) - KERNEL_HEAP_START)
|
||||||
|
typedef struct VMHeapBlockHeader {
|
||||||
|
UInt64 magic;
|
||||||
|
struct VMHeapBlockHeader* next;
|
||||||
|
struct VMHeapBlockHeader* previous;
|
||||||
|
UInt64 size;
|
||||||
|
bool isFree;
|
||||||
|
} VMHeapBlockHeader;
|
||||||
|
|
||||||
|
void VMHeapInitialize();
|
||||||
|
void* VMHeapAllocate(UInt64 size);
|
||||||
|
void VMHeapFree(void* ptr);
|
||||||
|
void* VMHeapResize(void* ptr, UInt64 newSize);
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "bootinfo.h"
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
#define kVMPageSize 4096
|
||||||
|
#define kVMSafeSpaceStartAddress 0x100000
|
||||||
|
#define kVMBlocksPerByte 8
|
||||||
|
|
||||||
|
#define BITMAP_BYTE_INDEX(address) ((address / kVMPageSize) / kVMBlocksPerByte)
|
||||||
|
#define BITMAP_BIT_OFFSET(address) ((address / kVMPageSize) % kVMBlocksPerByte)
|
||||||
|
#define BITMAP_TEST(bitmap, address) (bitmap[BITMAP_BYTE_INDEX(address)] & (1 << BITMAP_BIT_OFFSET(address)))
|
||||||
|
#define BITMAP_SET(bitmap, address) (bitmap[BITMAP_BYTE_INDEX(address)] |= (1 << BITMAP_BIT_OFFSET(address)))
|
||||||
|
#define BITMAP_UNSET(bitmap, address) (bitmap[BITMAP_BYTE_INDEX(address)] &= ~(1 << BITMAP_BIT_OFFSET(address)))
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UInt32 type;
|
||||||
|
UInt32 padding;
|
||||||
|
UInt64 physicalStart;
|
||||||
|
UInt64 virtualStart;
|
||||||
|
UInt64 pageCount;
|
||||||
|
UInt64 attributes;
|
||||||
|
} __attribute__((packed)) OSMemoryDescriptor;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kOSMemoryTypeReserved,
|
||||||
|
kOSMemoryTypeLoaderCode,
|
||||||
|
kOSMemoryTypeLoaderData,
|
||||||
|
kOSMemoryTypeBootServicesCode,
|
||||||
|
kOSMemoryTypeBootServicesData,
|
||||||
|
kOSMemoryTypeRuntimeServicesCode,
|
||||||
|
kOSMemoryTypeRuntimeServicesData,
|
||||||
|
kOSMemoryTypeConventional,
|
||||||
|
kOSMemoryTypeUnusable,
|
||||||
|
kOSMemoryTypeACPIReclaim,
|
||||||
|
kOSMemoryTypeACPINonVolatile,
|
||||||
|
kOSMemoryTypeMappedIO,
|
||||||
|
kOSMemoryTypeMappedIOPortSpace,
|
||||||
|
kOSMemoryTypePalCode,
|
||||||
|
kOSMemoryTypePersistent,
|
||||||
|
kOSMemoryTypeMax
|
||||||
|
} OSMemoryType;
|
||||||
|
|
||||||
|
UInt64 VMPhysicalMemoryGetTotalMemorySize();
|
||||||
|
void VMPhysicalMemoryInitialize(BIMemoryMap* mmap);
|
||||||
|
void* VMPhysicalMemoryAllocatePage();
|
||||||
|
void VMPhysicalMemoryFreePage(void* addr);
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// Copyright (c) 2025 0xKarinyash
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "bootinfo.h"
|
#include "bootinfo.h"
|
||||||
@@ -35,9 +35,10 @@
|
|||||||
#define HHDM_TO_PHYS(virt) ((virt) - HHDM_OFFSET)
|
#define HHDM_TO_PHYS(virt) ((virt) - HHDM_OFFSET)
|
||||||
|
|
||||||
|
|
||||||
void vmm_init(Bootinfo* info);
|
void VMVirtualMemoryInitialize(Bootinfo* info);
|
||||||
u64* vmm_map_page(u64* pml4, u64 phys, u64 virt, u64 flags);
|
UInt64* VMVirtualMemoryMapPage(UInt64* PML4, UInt64 physical, UInt64 virtual, UInt64 flags);
|
||||||
u64 vmm_create_address_space();
|
void* VMVirtualMemoryGetOrAllocatePage(UInt64* PML4, UInt64 virtual, UInt64 flags);
|
||||||
u64 vmm_get_current_cr3();
|
UInt64 VMVirtualMemoryCreateAddressSpace();
|
||||||
void load_cr3(u64 pml4_addr);
|
UInt64 VMGetCurrentCR3();
|
||||||
void vmm_setup_user_stack(u64* pml4_phys);
|
void VMLoadCR3(UInt64 PML4Address);
|
||||||
|
void VMVirtualMemorySetupUserStack(UInt64* physicalPML4);
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
#define kHALGDTEntries 7
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UInt16 limitLow;
|
||||||
|
UInt16 baseLow;
|
||||||
|
UInt8 baseMiddle;
|
||||||
|
UInt8 access;
|
||||||
|
UInt8 granularity;
|
||||||
|
UInt8 baseHigh;
|
||||||
|
} __attribute__((packed)) HALGlobalDescriptorTable;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UInt16 limit;
|
||||||
|
UInt64 base;
|
||||||
|
} __attribute__((packed)) HALGlobalDescriptorTablePointer;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UInt32 reserved0;
|
||||||
|
UInt64 rsp0;
|
||||||
|
UInt64 rsp1;
|
||||||
|
UInt64 rsp2;
|
||||||
|
UInt64 reserved1;
|
||||||
|
UInt64 ist1;
|
||||||
|
UInt64 ist2;
|
||||||
|
UInt64 ist3;
|
||||||
|
UInt64 ist4;
|
||||||
|
UInt64 ist5;
|
||||||
|
UInt64 ist6;
|
||||||
|
UInt64 ist7;
|
||||||
|
UInt64 reserved2;
|
||||||
|
UInt16 reserved3;
|
||||||
|
UInt16 iomapBase;
|
||||||
|
} __attribute__((packed)) HALTaskStateSegment;
|
||||||
|
|
||||||
|
|
||||||
|
extern HALTaskStateSegment gHALTaskStateSegment;
|
||||||
|
|
||||||
|
void HALGlobalDescriptorTableInitialize();
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UInt16 offsetLow;
|
||||||
|
UInt16 selector;
|
||||||
|
UInt8 ist;
|
||||||
|
UInt8 attributes;
|
||||||
|
UInt16 offsetMid;
|
||||||
|
UInt32 offsetHigh;
|
||||||
|
UInt32 reserved;
|
||||||
|
} __attribute__((packed)) HALInterruptsDescriptorTableEntry;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UInt16 limit;
|
||||||
|
UInt64 base;
|
||||||
|
} __attribute__((packed)) HALInterruptsDescriptorTablePointer;
|
||||||
|
|
||||||
|
void HALInterruptsDescriptorTableInitialize();
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kIOMasterCommand = 0x20,
|
||||||
|
kIOMasterData = 0x21,
|
||||||
|
kIOSlaveCommand = 0xA0,
|
||||||
|
kIOSlaveData = 0xA1,
|
||||||
|
kIOPortWaitAddress = 0x80
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline void IOPortWrite8(UInt16 port, UInt8 val) {
|
||||||
|
__asm__ volatile(
|
||||||
|
"outb %0, %1"
|
||||||
|
:
|
||||||
|
: "a"(val),
|
||||||
|
"Nd"(port) );
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline unsigned char IOPortRead8(UInt16 port) {
|
||||||
|
unsigned char ret;
|
||||||
|
__asm__ volatile(
|
||||||
|
"inb %1, %0"
|
||||||
|
: "=a"(ret)
|
||||||
|
: "Nd"(port)
|
||||||
|
);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// sending junk to 0x80 (unused) to skip few tacts
|
||||||
|
// not ideal i know
|
||||||
|
static inline void IOSynchronizeBus() {
|
||||||
|
IOPortWrite8(kIOPortWaitAddress, 0x0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void IOPortWrite8WithWait(UInt16 port, UInt8 val) {
|
||||||
|
IOPortWrite8(port, val);
|
||||||
|
IOSynchronizeBus();
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
kCPUFeatureFPU = (1ULL << 0),
|
||||||
|
kCPUFeatureTSC = (1ULL << 1),
|
||||||
|
kCPUFeatureMSR = (1ULL << 2),
|
||||||
|
kCPUFeatureAPIC = (1ULL << 3),
|
||||||
|
kCPUFeatureMTRR = (1ULL << 4),
|
||||||
|
kCPUFeaturePAE = (1ULL << 5),
|
||||||
|
|
||||||
|
kCPUFeatureSSE = (1ULL << 10),
|
||||||
|
kCPUFeatureSSE2 = (1ULL << 11),
|
||||||
|
kCPUFeatureSSE3 = (1ULL << 12),
|
||||||
|
kCPUFeatureSSSE3 = (1ULL << 13),
|
||||||
|
kCPUFeatureSSE4_1 = (1ULL << 14),
|
||||||
|
kCPUFeatureSSE4_2 = (1ULL << 15),
|
||||||
|
|
||||||
|
kCPUFeatureAVX = (1ULL << 20),
|
||||||
|
kCPUFeatureF16C = (1ULL << 21),
|
||||||
|
kCPUFeatureRDRAND = (1ULL << 22),
|
||||||
|
|
||||||
|
kCPUFeatureHypervisor = (1ULL << 30)
|
||||||
|
} OSCPUFeature;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UInt64 userStackPointer;
|
||||||
|
UInt64 kernelStackPointer;
|
||||||
|
UInt64 selfAddress;
|
||||||
|
|
||||||
|
UInt64 features;
|
||||||
|
char vendorID[13];
|
||||||
|
UInt32 family;
|
||||||
|
UInt32 model;
|
||||||
|
} OSCPUData;
|
||||||
|
|
||||||
|
extern OSCPUData gOSBootCPU;
|
||||||
|
|
||||||
|
void OSCPUInitialize(UInt64 kernelStackTop);
|
||||||
|
Boolean OSCPUHasFeature(OSCPUFeature feature);
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// Copyright (c) 2025 0xKarinyash
|
// Copyright (c) 2026 0xKarinyash
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
u16 pic_remap();
|
UInt16 HALLegacyInterruptControllerRemap();
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kHALModelSpecificRegisterExtendedFeatureEnable = 0xC0000080, // EFER
|
||||||
|
kHALModelSpecificRegisterSystemCallTarget = 0xC0000081, // STAR
|
||||||
|
kHALModelSpecificRegisterLongSystemCallTarget = 0xC0000082, // LSTAR
|
||||||
|
kHALModelSpecificRegisterSystemCallFlagMask = 0xC0000084, // FMASK
|
||||||
|
kHALModelSpecificRegisterGSBase = 0xC0000101, // GS_BASE
|
||||||
|
kHALModelSpecificRegisterKernelGSBase = 0xC0000102 // KERNEL_GS_BASE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kHALEFERSystemCallExtensionsEnable = 0x01 // SCE
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
SYS_EXIT,
|
||||||
|
SYS_SPAWN,
|
||||||
|
SYS_MEM,
|
||||||
|
SYS_WRITE,
|
||||||
|
SYS_READ,
|
||||||
|
SYS_WAIT,
|
||||||
|
} Services;
|
||||||
|
|
||||||
|
void OSServicesInitialize();
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// Copyright (c) 2025 0xKarinyash
|
// Copyright (c) 2026 0xKarinyash
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
@@ -13,7 +13,7 @@ static inline int abs(int n) {
|
|||||||
return (n < 0) ? -n : n;
|
return (n < 0) ? -n : n;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline i64 i64abs(i64 n) {
|
static inline Int64 i64abs(Int64 n) {
|
||||||
return (n < 0) ? -n : n;
|
return (n < 0) ? -n : n;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
// Copyright (c) 2025 0xKarinyash
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
u64 debug();
|
void RandInitialize();
|
||||||
|
UInt64 Rand();
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <IO/IOGraphics.h>
|
||||||
|
|
||||||
|
void SplashShow(IOGraphicsContext* IOGraphicsContextPointer);
|
||||||
|
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
void* MemorySet(void* destination, UInt8 value, UInt64 count);
|
||||||
|
void* MemoryCopy(void* destination, const void* source, UInt64 count);
|
||||||
|
Int32 StringCompare(const char* firstString, const char* secondString);
|
||||||
|
Int32 StringCompareWithLimit(const char* firstString, const char* secondString, UInt64 limit);
|
||||||
|
char* StringCopy(char* destination, const char* source);
|
||||||
|
char* StringCopyWithLimit(char* destination, const char* source, UInt64 limit);
|
||||||
|
UInt64 StringGetLength(const char* string);
|
||||||
|
const char* StringFindLastOccurrenceOfCharacter(const char* string, char separator);
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
typedef unsigned char UInt8;
|
||||||
|
typedef unsigned short UInt16;
|
||||||
|
typedef unsigned int UInt32;
|
||||||
|
typedef unsigned long long UInt64;
|
||||||
|
|
||||||
|
typedef signed char Int8;
|
||||||
|
typedef signed short Int16;
|
||||||
|
typedef signed int Int32;
|
||||||
|
typedef signed long long Int64;
|
||||||
|
|
||||||
|
typedef UInt64 Size;
|
||||||
|
typedef UInt64 uintptr_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
UInt64 rax, rbx, rcx, rdx, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15; // Pushed by us
|
||||||
|
UInt64 interruptNumber, errorCode; // Pushed by macro
|
||||||
|
UInt64 rip, cs, rflags, rsp, ss; // Pushed by CPU
|
||||||
|
} CPURegisters;
|
||||||
|
|
||||||
|
|
||||||
|
#define Boolean _Bool
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/* SPDX-License-Identifier: GPL-3.0-or-later
|
/* SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
Copyright (c) 2025 0xKarinyash */
|
Copyright (c) 2026 0xKarinyash */
|
||||||
|
|
||||||
ENTRY(_start)
|
ENTRY(_start)
|
||||||
|
|
||||||
@@ -0,0 +1,122 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <FS/CPIO.h>
|
||||||
|
#include <FS/VFS.h>
|
||||||
|
#include <lib/String.h>
|
||||||
|
#include <OS/OSPanic.h>
|
||||||
|
#include <VM/Heap.h>
|
||||||
|
#include <IO/IOConsole.h>
|
||||||
|
|
||||||
|
#define FSCPIO_ALIGN4(x) (((x) + 3) & ~3)
|
||||||
|
|
||||||
|
typedef struct FSCPIOHeader {
|
||||||
|
char magic[6];
|
||||||
|
char inode[8];
|
||||||
|
char mode[8];
|
||||||
|
char userIdentifier[8];
|
||||||
|
char groupIdentifier[8];
|
||||||
|
char linkCount[8];
|
||||||
|
char modificationTime[8];
|
||||||
|
char fileLength[8];
|
||||||
|
char deviceMajor[8];
|
||||||
|
char deviceMinor[8];
|
||||||
|
char remoteDeviceMajor[8];
|
||||||
|
char remoteDeviceMinor[8];
|
||||||
|
char nameLength[8];
|
||||||
|
char checkSum[8];
|
||||||
|
} FSCPIOHeader;
|
||||||
|
|
||||||
|
static FSVNodeOperations gFSCPIOOperations = {
|
||||||
|
.read = FSCPIORead,
|
||||||
|
.write = nullptr,
|
||||||
|
.open = nullptr,
|
||||||
|
.close = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
static UInt64 sFSCPIOHexadecimalToUInt64(const char* string, Int32 length) {
|
||||||
|
UInt64 result = 0;
|
||||||
|
for (Int32 i = 0; i < length; i++) {
|
||||||
|
char character = string[i];
|
||||||
|
result <<= 4;
|
||||||
|
if (character >= '0' && character <= '9') result += (character - '0');
|
||||||
|
else if (character >= 'A' && character <= 'F') result += (character - 'A' + 10);
|
||||||
|
else if (character >= 'a' && character <= 'f') result += (character - 'a' + 10);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64 FSCPIORead(FSVNode* node, UInt64 offset, UInt64 size, UInt8* buffer) {
|
||||||
|
if (offset > node->dataLength) return 0;
|
||||||
|
if ((offset + size) > node->dataLength) size = node->dataLength - offset;
|
||||||
|
|
||||||
|
MemoryCopy(buffer, (char*)node->implementationData + offset, size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
FSVNode* FSCPIOMount(void* baseAddress, UInt64 totalSize) {
|
||||||
|
UInt8* currentPointer = (UInt8*)baseAddress;
|
||||||
|
UInt8* endPointer = currentPointer + totalSize;
|
||||||
|
|
||||||
|
FSVNode* rootNode = (FSVNode*)VMHeapAllocate(sizeof(FSVNode));
|
||||||
|
if (!rootNode) OSPanic("CPIO: Failed to allocate memory for root node");
|
||||||
|
|
||||||
|
MemorySet(rootNode, 0, sizeof(FSVNode));
|
||||||
|
StringCopy(rootNode->name, "/");
|
||||||
|
rootNode->flags = kFSVNodeFlagDirectory;
|
||||||
|
rootNode->operations = &gFSCPIOOperations;
|
||||||
|
|
||||||
|
FSVNode* tailNode = nullptr;
|
||||||
|
|
||||||
|
while (currentPointer < endPointer) {
|
||||||
|
FSCPIOHeader* header = (FSCPIOHeader*)currentPointer;
|
||||||
|
|
||||||
|
if (StringCompareWithLimit(header->magic, "070701", 6) != 0) {
|
||||||
|
OSPanic("CPIO: Invalid magic detected in StartupVolume");
|
||||||
|
}
|
||||||
|
|
||||||
|
UInt64 nameSize = sFSCPIOHexadecimalToUInt64(header->nameLength, 8);
|
||||||
|
UInt64 fileSize = sFSCPIOHexadecimalToUInt64(header->fileLength, 8);
|
||||||
|
|
||||||
|
char* fileName = (char*)(currentPointer + sizeof(FSCPIOHeader));
|
||||||
|
if (StringCompare(fileName, "TRAILER!!!") == 0) break;
|
||||||
|
|
||||||
|
UInt64 headerAndNameLength = sizeof(FSCPIOHeader) + nameSize;
|
||||||
|
UInt64 offsetToData = FSCPIO_ALIGN4(headerAndNameLength);
|
||||||
|
void* fileContent = (void*)(currentPointer + offsetToData);
|
||||||
|
|
||||||
|
FSVNode* newNode = (FSVNode*)VMHeapAllocate(sizeof(FSVNode));
|
||||||
|
if (!newNode) OSPanic("CPIO: Failed to allocate memory for new node");
|
||||||
|
|
||||||
|
MemorySet(newNode, 0, sizeof(FSVNode));
|
||||||
|
StringCopyWithLimit(newNode->name, fileName, sizeof(newNode->name) - 1);
|
||||||
|
|
||||||
|
newNode->dataLength = fileSize;
|
||||||
|
newNode->inodeIdentifier = sFSCPIOHexadecimalToUInt64(header->inode, 8);
|
||||||
|
newNode->operations = &gFSCPIOOperations;
|
||||||
|
newNode->implementationData = fileContent;
|
||||||
|
|
||||||
|
UInt64 mode = sFSCPIOHexadecimalToUInt64(header->mode, 8);
|
||||||
|
if ((mode & 0xF000) == 0x4000) {
|
||||||
|
newNode->flags = kFSVNodeFlagDirectory;
|
||||||
|
} else {
|
||||||
|
newNode->flags = kFSVNodeFlagFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rootNode->childNode == nullptr) {
|
||||||
|
rootNode->childNode = newNode;
|
||||||
|
} else if (tailNode) {
|
||||||
|
tailNode->nextNode = newNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
tailNode = newNode;
|
||||||
|
|
||||||
|
IOConsoleLog("^bCPIO^!: Found object '^y%s^!' (size: ^y%d^!) at ^y0x%x^!\n", fileName, fileSize, fileContent);
|
||||||
|
|
||||||
|
UInt64 dataLengthAligned = FSCPIO_ALIGN4(fileSize);
|
||||||
|
currentPointer += offsetToData + dataLengthAligned;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rootNode;
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user