feat: implement initial CPIO parsing and shell improvements
- core: added CPIO parser (fs/cpio.c) and VFS structs - shell: refactored ksh, added 'help' command - lib: added string utils (strcpy, strncpy, strncmp) - wip: working on initramfs loading in kmain
This commit is contained in:
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
.cache
|
.cache
|
||||||
build*
|
build*
|
||||||
.venv
|
.venv
|
||||||
|
initrd/image.cpio
|
||||||
+19
-3
@@ -11,12 +11,27 @@ add_subdirectory(kernel)
|
|||||||
|
|
||||||
find_program(MCOPY_EXE mcopy)
|
find_program(MCOPY_EXE mcopy)
|
||||||
find_program(MKFS_EXE mkfs.fat)
|
find_program(MKFS_EXE mkfs.fat)
|
||||||
|
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/ovmf/OVMF_CODE.fd" CACHE FILEPATH "Path to OVMF bios")
|
||||||
|
|
||||||
if(MCOPY_EXE AND MKFS_EXE)
|
if(MCOPY_EXE AND MKFS_EXE AND CPIO_EXE)
|
||||||
set(IMG_FILE "${CMAKE_BINARY_DIR}/termOS.img")
|
set(IMG_FILE "${CMAKE_BINARY_DIR}/termOS.img")
|
||||||
|
|
||||||
|
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}\""
|
||||||
|
WORKING_DIRECTORY ${INITRAMFS_SRC_DIR}
|
||||||
|
DEPENDS ${INIT_FILES}
|
||||||
|
VERBATIM
|
||||||
|
COMMENT "Packing initramfs to cpio..."
|
||||||
|
)
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
OUTPUT ${IMG_FILE}
|
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
|
||||||
@@ -24,7 +39,9 @@ if(MCOPY_EXE AND MKFS_EXE)
|
|||||||
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
|
||||||
DEPENDS BOOTX64 kernel
|
COMMAND ${MCOPY_EXE} -i ${IMG_FILE} ${INITRAMFS_CPIO_FILE} ::/initramfs.cpio
|
||||||
|
DEPENDS BOOTX64 kernel ${INITRAMFS_CPIO_FILE}
|
||||||
|
VERBATIM
|
||||||
COMMENT "Generating bootable image: ${IMG_FILE}"
|
COMMENT "Generating bootable image: ${IMG_FILE}"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -41,7 +58,6 @@ if(QEMU_EXE)
|
|||||||
-net none
|
-net none
|
||||||
-serial stdio
|
-serial stdio
|
||||||
-m 512M
|
-m 512M
|
||||||
#-s -S
|
|
||||||
DEPENDS image
|
DEPENDS image
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
+73
-23
@@ -4,63 +4,113 @@
|
|||||||
#include "uefi.h" // IWYU pragma: keep
|
#include "uefi.h" // IWYU pragma: keep
|
||||||
#include "../../common/bootinfo.h"
|
#include "../../common/bootinfo.h"
|
||||||
|
|
||||||
|
void print(wchar_t* msg) {
|
||||||
|
ST->ConOut->OutputString(ST->ConOut, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_initramfs_warning(wchar_t* reason) {
|
||||||
|
print(L"WARNING: Failed to load initramfs file!! Only kernel emergency shell available..\r\nReason: ");
|
||||||
|
print(reason);
|
||||||
|
print(L"\r\n");
|
||||||
|
BS->Stall(2 * 1000 * 1000); // 2s
|
||||||
|
}
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
efi_gop_t *gop = nullptr;
|
efi_gop_t* gop = nullptr;
|
||||||
efi_guid_t gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
efi_guid_t gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
|
||||||
ST->BootServices->LocateProtocol(&gop_guid, 0, (void**)&gop);
|
ST->BootServices->LocateProtocol(&gop_guid, 0, (void**)&gop);
|
||||||
|
|
||||||
efi_loaded_image_protocol_t *loaded_image;
|
efi_loaded_image_protocol_t* loaded_image;
|
||||||
efi_guid_t lip_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
efi_guid_t lip_guid = EFI_LOADED_IMAGE_PROTOCOL_GUID;
|
||||||
gBS->HandleProtocol(IM, &lip_guid, (void**)&loaded_image);
|
gBS->HandleProtocol(IM, &lip_guid, (void**)&loaded_image);
|
||||||
|
|
||||||
efi_simple_file_system_protocol_t *fs;
|
efi_simple_file_system_protocol_t* fs;
|
||||||
efi_guid_t sfsp_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
|
efi_guid_t sfsp_guid = EFI_SIMPLE_FILE_SYSTEM_PROTOCOL_GUID;
|
||||||
gBS->HandleProtocol(loaded_image->DeviceHandle, &sfsp_guid, (void**)&fs);
|
gBS->HandleProtocol(loaded_image->DeviceHandle, &sfsp_guid, (void**)&fs);
|
||||||
|
|
||||||
efi_file_handle_t *root;
|
efi_file_handle_t* root;
|
||||||
|
efi_guid_t fi_guid = EFI_FILE_INFO_GUID;
|
||||||
fs->OpenVolume(fs, &root);
|
fs->OpenVolume(fs, &root);
|
||||||
|
|
||||||
efi_file_handle_t *kernel_file;
|
// kernel
|
||||||
efi_guid_t fi_guid = EFI_FILE_INFO_GUID;
|
|
||||||
uintn_t info_size = 0;
|
efi_file_handle_t* kernel_file;
|
||||||
efi_file_info_t *file_info = nullptr;
|
uintn_t kinfo_size = 0;
|
||||||
|
efi_file_info_t* kfile_info = nullptr;
|
||||||
efi_status_t status = root->Open(root, &kernel_file, L"kernel.bin", EFI_FILE_MODE_READ, 0);
|
efi_status_t status = root->Open(root, &kernel_file, L"kernel.bin", EFI_FILE_MODE_READ, 0);
|
||||||
if (EFI_ERROR(status)) {
|
if (EFI_ERROR(status)) {
|
||||||
ST->ConOut->OutputString(ST->ConOut, L"Kernel not found :(");
|
print(L"Kernel not found :(");
|
||||||
while (1);
|
while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = kernel_file->GetInfo(kernel_file, &fi_guid, &info_size, NULL);
|
status = kernel_file->GetInfo(kernel_file, &fi_guid, &kinfo_size, nullptr);
|
||||||
|
|
||||||
if (status == EFI_BUFFER_TOO_SMALL) {
|
if (status == EFI_BUFFER_TOO_SMALL) {
|
||||||
gBS->AllocatePool(EfiLoaderData, info_size, (void**)&file_info);
|
gBS->AllocatePool(EfiLoaderData, kinfo_size, (void**)&kfile_info);
|
||||||
status = kernel_file->GetInfo(kernel_file, &fi_guid, &info_size, file_info);
|
status = kernel_file->GetInfo(kernel_file, &fi_guid, &kinfo_size, kfile_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EFI_ERROR(status)) {
|
if (EFI_ERROR(status)) {
|
||||||
ST->ConOut->OutputString(ST->ConOut, L"Failed to allocate memory for buffer!!");
|
print(L"Failed to allocate memory for buffer!!");
|
||||||
while (1) __asm__("hlt");
|
while (1) __asm__("hlt");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t kernel_size = file_info->FileSize;
|
uint64_t kernel_size = kfile_info->FileSize;
|
||||||
uintn_t kernel_size_read = (uintn_t)kernel_size;
|
uintn_t kernel_size_read = (uintn_t)kernel_size;
|
||||||
efi_physical_address_t kernel_addr = 0x100000;
|
efi_physical_address_t kernel_addr = 0x100000;
|
||||||
uintn_t pages = (kernel_size + 0xFFF) / 0x1000 + 32;
|
uintn_t kernel_pages = (kernel_size + 0xFFF) / 0x1000 + 32;
|
||||||
|
|
||||||
status = gBS->AllocatePages(AllocateAddress, EfiLoaderData, pages, &kernel_addr);
|
status = gBS->AllocatePages(AllocateAddress, EfiLoaderData, kernel_pages, &kernel_addr);
|
||||||
if (EFI_ERROR(status)) {
|
if (EFI_ERROR(status)) {
|
||||||
ST->ConOut->OutputString(ST->ConOut, L"Memory 0x100000 busy!\r\n");
|
print(L"Memory 0x100000 busy!\r\n");
|
||||||
while (1);
|
while (1);
|
||||||
}
|
}
|
||||||
|
|
||||||
kernel_file->Read(kernel_file, &kernel_size_read, (void*)kernel_addr); // scary!
|
kernel_file->Read(kernel_file, &kernel_size_read, (void*)kernel_addr); // scary!
|
||||||
|
|
||||||
Bootinfo *boot_info = NULL;
|
// initramfs
|
||||||
|
Bootinfo* boot_info = nullptr;
|
||||||
status = gBS->AllocatePool(EfiLoaderData, sizeof(Bootinfo), (void**)&boot_info);
|
status = gBS->AllocatePool(EfiLoaderData, sizeof(Bootinfo), (void**)&boot_info);
|
||||||
|
|
||||||
|
boot_info->magic = BOOTINFO_MAGIC;
|
||||||
|
|
||||||
|
efi_file_handle_t* initramfs_file;
|
||||||
|
uintn_t iinfo_size = 0;
|
||||||
|
efi_file_info_t* ifile_info = nullptr;
|
||||||
|
status = root->Open(root, &initramfs_file, L"initramfs.cpio", EFI_FILE_MODE_READ, 0);
|
||||||
|
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
print_initramfs_warning(L"initramfs.cpio is missing");
|
||||||
|
boot_info->initramfs.addr = nullptr;
|
||||||
|
boot_info->initramfs.size = 0;
|
||||||
|
} else {
|
||||||
|
status = initramfs_file->GetInfo(initramfs_file, &fi_guid, &iinfo_size, nullptr);
|
||||||
|
if (status == EFI_BUFFER_TOO_SMALL) {
|
||||||
|
gBS->AllocatePool(EfiLoaderData, iinfo_size, (void**)&ifile_info);
|
||||||
|
status = initramfs_file->GetInfo(initramfs_file, &fi_guid, &iinfo_size, ifile_info);
|
||||||
|
}
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
print_initramfs_warning(L"failed to allocate memory for initramfs buffer!!");
|
||||||
|
} else {
|
||||||
|
// i hate that nesting
|
||||||
|
uint64_t initramfs_size = ifile_info->FileSize;
|
||||||
|
|
||||||
|
uintn_t initramfs_pages = (initramfs_size + 0xFFF) / 0x1000;
|
||||||
|
efi_physical_address_t initramfs_addr = 0;
|
||||||
|
status = gBS->AllocatePages(AllocateAnyPages, EfiLoaderData, initramfs_pages, &initramfs_addr);
|
||||||
|
if (EFI_ERROR(status)) {
|
||||||
|
print_initramfs_warning(L"failed to allocate memory for initramfs itself!!");
|
||||||
|
} else {
|
||||||
|
// just fucking kill me
|
||||||
|
uintn_t initramfs_size_read = (uintn_t)initramfs_size;
|
||||||
|
initramfs_file->Read(initramfs_file, &initramfs_size_read, (void*)initramfs_addr);
|
||||||
|
boot_info->initramfs.addr = (void*)initramfs_addr;
|
||||||
|
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.base_size = gop->Mode->FrameBufferSize;
|
||||||
boot_info->framebuffer.height = gop->Mode->Information->VerticalResolution;
|
boot_info->framebuffer.height = gop->Mode->Information->VerticalResolution;
|
||||||
@@ -68,19 +118,19 @@ int main()
|
|||||||
boot_info->framebuffer.pitch = gop->Mode->Information->PixelsPerScanLine;
|
boot_info->framebuffer.pitch = gop->Mode->Information->PixelsPerScanLine;
|
||||||
|
|
||||||
uintn_t map_size = 0;
|
uintn_t map_size = 0;
|
||||||
efi_memory_descriptor_t *map = NULL;
|
efi_memory_descriptor_t *map = nullptr;
|
||||||
uintn_t map_key;
|
uintn_t map_key;
|
||||||
uintn_t desc_size;
|
uintn_t desc_size;
|
||||||
uint32_t desc_version;
|
uint32_t desc_version;
|
||||||
|
|
||||||
ST->ConOut->OutputString(ST->ConOut, L"Almost ready to jump :D. Working with memory map\r\n");
|
print(L"Almost ready to jump :D. Working with memory map\r\n");
|
||||||
|
|
||||||
gBS->GetMemoryMap(&map_size, NULL, &map_key, &desc_size, &desc_version);
|
gBS->GetMemoryMap(&map_size, nullptr, &map_key, &desc_size, &desc_version);
|
||||||
map_size += 4096;
|
map_size += 4096;
|
||||||
// woah letsgoo
|
// woah letsgoo
|
||||||
status = gBS->AllocatePool(EfiLoaderData, map_size, (void**)&map);
|
status = gBS->AllocatePool(EfiLoaderData, map_size, (void**)&map);
|
||||||
if (EFI_ERROR(status)) {
|
if (EFI_ERROR(status)) {
|
||||||
ST->ConOut->OutputString(ST->ConOut, L"Failed to allocate pool");
|
print(L"Failed to allocate pool");
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
|||||||
+12
-3
@@ -7,7 +7,7 @@ typedef unsigned int bi_u32;
|
|||||||
typedef unsigned long long bi_u64;
|
typedef unsigned long long bi_u64;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
bi_u32 *base;
|
bi_u32* base;
|
||||||
bi_u64 base_size;
|
bi_u64 base_size;
|
||||||
bi_u64 width;
|
bi_u64 width;
|
||||||
bi_u64 height;
|
bi_u64 height;
|
||||||
@@ -15,7 +15,7 @@ typedef struct {
|
|||||||
} BI_Framebuffer;
|
} BI_Framebuffer;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void *map;
|
void* map;
|
||||||
bi_u64 map_size;
|
bi_u64 map_size;
|
||||||
bi_u64 descriptor_size;
|
bi_u64 descriptor_size;
|
||||||
bi_u32 map_key;
|
bi_u32 map_key;
|
||||||
@@ -23,6 +23,15 @@ typedef struct {
|
|||||||
} BI_MemoryMap;
|
} BI_MemoryMap;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
void* addr;
|
||||||
|
bi_u64 size;
|
||||||
|
} BI_Initramfs;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bi_u64 magic;
|
||||||
BI_Framebuffer framebuffer;
|
BI_Framebuffer framebuffer;
|
||||||
BI_MemoryMap mem;
|
BI_MemoryMap mem;
|
||||||
} Bootinfo;
|
BI_Initramfs initramfs;
|
||||||
|
} Bootinfo;
|
||||||
|
|
||||||
|
#define BOOTINFO_MAGIC 0x7E833055 // termOS
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Meow!!
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
Nyaaa
|
||||||
@@ -12,7 +12,7 @@ endif()
|
|||||||
message(STATUS "TermOS Kernel: Building for architecture '${ARCH}'")
|
message(STATUS "TermOS Kernel: Building for architecture '${ARCH}'")
|
||||||
|
|
||||||
|
|
||||||
file(GLOB_RECURSE KERNEL_SOURCES
|
file(GLOB_RECURSE KERNEL_SOURCES CMAKE_CONFIGURE_DEPENDS
|
||||||
"src/kmain.c"
|
"src/kmain.c"
|
||||||
|
|
||||||
"src/arch/${ARCH}/*.c"
|
"src/arch/${ARCH}/*.c"
|
||||||
@@ -22,6 +22,7 @@ file(GLOB_RECURSE KERNEL_SOURCES
|
|||||||
"src/drivers/*.c"
|
"src/drivers/*.c"
|
||||||
"src/mm/*.c"
|
"src/mm/*.c"
|
||||||
"src/shell/*.c"
|
"src/shell/*.c"
|
||||||
|
"src/fs/*.c"
|
||||||
|
|
||||||
"data/*.c"
|
"data/*.c"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -5,3 +5,6 @@
|
|||||||
#include <types.h>
|
#include <types.h>
|
||||||
|
|
||||||
i32 strcmp(const char* s1, const char* s2);
|
i32 strcmp(const char* s1, const char* s2);
|
||||||
|
i32 strncmp(const char* s1, const char* s2, u64 n);
|
||||||
|
char* strcpy(char* dest, const char* src);
|
||||||
|
char* strncpy(char* dest, const char* src, u64 n);
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
#include <fs/vfs.h>
|
||||||
|
|
||||||
|
u64 cpio_read(fs_node* node, u64 offset, u64 size, u8* buff);
|
||||||
|
fs_node* cpio_mount(void* base, u64 size);
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
#pragma once
|
||||||
|
#include <types.h>
|
||||||
|
|
||||||
|
#define FS_FILE 0x01
|
||||||
|
#define FS_DIR 0x02
|
||||||
|
|
||||||
|
struct fs_node;
|
||||||
|
typedef struct fs_node fs_node;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u64 (*read)(struct fs_node* node, u64 offset, u64 size, u8* buff);
|
||||||
|
u64 (*write)(struct fs_node* node, u64 offset, u64 size, u8* buff);
|
||||||
|
void (*open)(struct fs_node* node);
|
||||||
|
void (*close)(struct fs_node* node);
|
||||||
|
|
||||||
|
struct fs_node* (*finddir)(struct fs_node* node, char* name);
|
||||||
|
} fs_ops;
|
||||||
|
|
||||||
|
struct fs_node {
|
||||||
|
char name[256];
|
||||||
|
u32 mask;
|
||||||
|
u32 uid;
|
||||||
|
u32 gid;
|
||||||
|
u32 flags;
|
||||||
|
u32 inode;
|
||||||
|
u64 len;
|
||||||
|
fs_ops* ops;
|
||||||
|
void* impl_data;
|
||||||
|
struct fs_node* ptr;
|
||||||
|
struct fs_node* next;
|
||||||
|
};
|
||||||
@@ -100,14 +100,7 @@ void draw_panic_bg() {
|
|||||||
console_clear(0x000000);
|
console_clear(0x000000);
|
||||||
console_set_color(0xFFFFFF);
|
console_set_color(0xFFFFFF);
|
||||||
console_set_default_color(0xFFFFFF);
|
console_set_default_color(0xFFFFFF);
|
||||||
|
|
||||||
// SG_Point p = console_get_dimensions();
|
|
||||||
// p.x /= 2;
|
|
||||||
// p.y /= 2;
|
|
||||||
// p.y -= 200;
|
|
||||||
|
|
||||||
// console_set_cursor_pos(&p);
|
|
||||||
|
|
||||||
u64 msg_count = sizeof(fun_messages) / sizeof(fun_messages[0]);
|
u64 msg_count = sizeof(fun_messages) / sizeof(fun_messages[0]);
|
||||||
u8 rand_num = shitrand() % msg_count;
|
u8 rand_num = shitrand() % msg_count;
|
||||||
|
|
||||||
|
|||||||
@@ -9,4 +9,36 @@ i32 strcmp(const char *s1, const char *s2) {
|
|||||||
s2++;
|
s2++;
|
||||||
}
|
}
|
||||||
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
|
return *(const unsigned char*)s1 - *(const unsigned char*)s2;
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 strncmp(const char* s1, const char* s2, u64 n) {
|
||||||
|
while (n > 0) {
|
||||||
|
if (*s1 != *s2) return *(unsigned char*)s1 - *(unsigned char*)s2;
|
||||||
|
if (*s1 == '\0') return 0;
|
||||||
|
s1++;
|
||||||
|
s2++;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* strcpy(char* dest, const char* src) {
|
||||||
|
char* saved = dest;
|
||||||
|
while (*src) *dest++ = *src++;
|
||||||
|
*dest = 0;
|
||||||
|
return saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
char* strncpy(char* dest, const char* src, u64 n) {
|
||||||
|
char* saved = dest;
|
||||||
|
while (*src && n > 0) {
|
||||||
|
*dest++ = *src++;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
while (n > 0) {
|
||||||
|
*dest++ = 0;
|
||||||
|
n--;
|
||||||
|
}
|
||||||
|
return saved;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <fs/cpio.h>
|
||||||
|
#include <fs/vfs.h>
|
||||||
|
#include <core/string.h>
|
||||||
|
#include <core/panic.h>
|
||||||
|
#include <mm/memory.h>
|
||||||
|
#include <mm/heap.h>
|
||||||
|
#include <drivers/console.h>
|
||||||
|
|
||||||
|
#define ALIGN4(x) (((x) + 3) & ~3)
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char c_magic[6]; // "070701"
|
||||||
|
char c_ino[8];
|
||||||
|
char c_mode[8]; // type and flags
|
||||||
|
char c_uid[8];
|
||||||
|
char c_gid[8];
|
||||||
|
char c_nlink[8];
|
||||||
|
char c_mtime[8];
|
||||||
|
char c_filesize[8];
|
||||||
|
char c_devmajor[8];
|
||||||
|
char c_devminor[8];
|
||||||
|
char c_rdevmajor[8];
|
||||||
|
char c_rdevminor[8];
|
||||||
|
char c_namesize[8]; // including \0
|
||||||
|
char c_check[8]; // checksum (usually 0)
|
||||||
|
} cpio_header;
|
||||||
|
|
||||||
|
static fs_ops cpio_ops = {
|
||||||
|
.read = cpio_read,
|
||||||
|
.write = nullptr,
|
||||||
|
.open = nullptr,
|
||||||
|
.close = nullptr,
|
||||||
|
};
|
||||||
|
|
||||||
|
u64 hex_to_u64(const char* s, i32 len) {
|
||||||
|
u64 res = 0;
|
||||||
|
for (i32 i = 0; i < len; i++) {
|
||||||
|
char c = s[i];
|
||||||
|
res <<= 4;
|
||||||
|
if (c >= '0' && c <= '9') res += (c - '0');
|
||||||
|
else if (c >= 'A' && c <= 'F') res += (c - 'A' + 10);
|
||||||
|
else if (c >= 'a' && c <= 'f') res += (c - 'a' + 10);
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
u64 cpio_read(fs_node* node, u64 offset, u64 size, u8* buff) {
|
||||||
|
if (offset > node->len) return 0; // EOF
|
||||||
|
if ((offset + size) > node->len) size = node->len - offset;
|
||||||
|
memcpy(buff, (char*)node->impl_data + offset, size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs_node* cpio_mount(void* base, u64 size) {
|
||||||
|
u8* ptr = (u8*)base;
|
||||||
|
u8* end = ptr + size;
|
||||||
|
|
||||||
|
fs_node* root = malloc(sizeof(fs_node));
|
||||||
|
if (!root) panic("CPIO: Failed to malloc for root node!");
|
||||||
|
memset(root, 0, sizeof(fs_node));
|
||||||
|
strcpy(root->name, "/");
|
||||||
|
root->flags = FS_DIR;
|
||||||
|
root->ops = &cpio_ops;
|
||||||
|
|
||||||
|
while (ptr < end) {
|
||||||
|
cpio_header* header = (cpio_header*)ptr;
|
||||||
|
|
||||||
|
if (strncmp(header->c_magic, "070701", 6) != 0) panic("CPIO: Bad magic! Corrupted initramfs");
|
||||||
|
u64 namesize = hex_to_u64(header->c_namesize, 8);
|
||||||
|
u64 filesize = hex_to_u64(header->c_filesize, 8);
|
||||||
|
|
||||||
|
char* filename = (char*)(ptr + sizeof(cpio_header));
|
||||||
|
if (strcmp(filename, "TRAILER!!!") == 0) break;
|
||||||
|
|
||||||
|
u64 header_and_name_len = sizeof(cpio_header) + namesize;
|
||||||
|
u64 offset_to_data = ALIGN4(header_and_name_len);
|
||||||
|
void* file_content = (void*)(ptr + offset_to_data);
|
||||||
|
|
||||||
|
fs_node* new_node = malloc(sizeof(fs_node));
|
||||||
|
if (!new_node) panic("CPIO: Failed to malloc for new node!");
|
||||||
|
memset(new_node, 0, sizeof(fs_node));
|
||||||
|
strcpy(new_node->name, filename);
|
||||||
|
|
||||||
|
new_node->len = filesize;
|
||||||
|
new_node->inode = hex_to_u64(header->c_ino, 8);
|
||||||
|
new_node->ops = &cpio_ops;
|
||||||
|
new_node->impl_data = file_content;
|
||||||
|
|
||||||
|
u64 mode = hex_to_u64(header->c_mode, 8);
|
||||||
|
if ((mode & 0xF000) == 0x4000) new_node->flags = FS_DIR;
|
||||||
|
else new_node->flags = FS_FILE;
|
||||||
|
|
||||||
|
kprintf("^bCPIO^!: Found file '^y%s^!' (size ^y%d^!) at ^y%x^!\n", filename, filesize, &file_content);
|
||||||
|
|
||||||
|
u64 data_len = ALIGN4(filesize);
|
||||||
|
ptr += offset_to_data + data_len;
|
||||||
|
}
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
// Copyright (c) 2026 0xKarinyash
|
||||||
|
|
||||||
+9
-2
@@ -2,7 +2,6 @@
|
|||||||
// Copyright (c) 2025 0xKarinyash
|
// Copyright (c) 2025 0xKarinyash
|
||||||
|
|
||||||
#include "bootinfo.h"
|
#include "bootinfo.h"
|
||||||
#include "core/scheduler.h"
|
|
||||||
#include <shell/ksh.h>
|
#include <shell/ksh.h>
|
||||||
|
|
||||||
#include <types.h>
|
#include <types.h>
|
||||||
@@ -13,6 +12,7 @@
|
|||||||
#include <drivers/timer.h>
|
#include <drivers/timer.h>
|
||||||
|
|
||||||
#include <core/panic.h>
|
#include <core/panic.h>
|
||||||
|
#include <core/scheduler.h>
|
||||||
#include <core/splash.h>
|
#include <core/splash.h>
|
||||||
|
|
||||||
#include <gdt.h>
|
#include <gdt.h>
|
||||||
@@ -23,6 +23,8 @@
|
|||||||
#include <mm/vmm.h>
|
#include <mm/vmm.h>
|
||||||
#include <mm/heap.h>
|
#include <mm/heap.h>
|
||||||
|
|
||||||
|
#include <fs/cpio.h>
|
||||||
|
|
||||||
#define FG_COLOR 0xffffff
|
#define FG_COLOR 0xffffff
|
||||||
#define BG_COLOR 0x111111
|
#define BG_COLOR 0x111111
|
||||||
|
|
||||||
@@ -35,6 +37,8 @@ void kmain(Bootinfo* info) {
|
|||||||
|
|
||||||
console_init(&sg_ctx);
|
console_init(&sg_ctx);
|
||||||
|
|
||||||
|
if (info->magic != BOOTINFO_MAGIC) panic("Corrupt bootinfo!");
|
||||||
|
|
||||||
gdt_init();
|
gdt_init();
|
||||||
kprintf("GDT initialized\n");
|
kprintf("GDT initialized\n");
|
||||||
idt_init();
|
idt_init();
|
||||||
@@ -52,10 +56,12 @@ void kmain(Bootinfo* info) {
|
|||||||
sched_init();
|
sched_init();
|
||||||
kprintf("Scheduler initialized\n");
|
kprintf("Scheduler initialized\n");
|
||||||
sg_init(&sg_ctx);
|
sg_init(&sg_ctx);
|
||||||
kprintf("Shitgui initialized");
|
kprintf("Shitgui initialized\n");
|
||||||
|
|
||||||
info = (Bootinfo*)PHYS_TO_HHDM((u64)info);
|
info = (Bootinfo*)PHYS_TO_HHDM((u64)info);
|
||||||
|
|
||||||
|
cpio_mount(PHYS_TO_HHDM(info->initramfs.addr), info->initramfs.size);
|
||||||
|
|
||||||
u32 *fb = (u32*)info->framebuffer.base;
|
u32 *fb = (u32*)info->framebuffer.base;
|
||||||
if (!fb) return serial_write("No framebuffer found!!");
|
if (!fb) return serial_write("No framebuffer found!!");
|
||||||
|
|
||||||
@@ -72,6 +78,7 @@ void kmain(Bootinfo* info) {
|
|||||||
|
|
||||||
sched_spawn(composer_task);
|
sched_spawn(composer_task);
|
||||||
sched_spawn(ksh);
|
sched_spawn(ksh);
|
||||||
|
if (!info->initramfs.addr) kprintf("^rWARNING^!: Failed to load ^yinitramfs^!, VFS is empty.\n\n");
|
||||||
__asm__ volatile("sti");
|
__asm__ volatile("sti");
|
||||||
|
|
||||||
while (true) __asm__ volatile("hlt");
|
while (true) __asm__ volatile("hlt");
|
||||||
|
|||||||
@@ -49,8 +49,31 @@ void cmd_meow() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void cmd_help() {
|
void cmd_help() {
|
||||||
kprintf("\tWelcome to ^ptermOS^!'s kernel shell!\n");
|
kprintf("Welcome to ^ptermOS^!'s ^gk^!ernel ^gsh^!ell!\n");
|
||||||
kprintf("\tIt can almost nothing! yet.\n");
|
kprintf("It loads when userspace is failed to load and acts as a basic rescue environment\n");
|
||||||
|
kprintf("At this moment i dont have userspace so it loads always\n");
|
||||||
|
kprintf("Available commands:\n");
|
||||||
|
|
||||||
|
kprintf("\t^rDebug^!:\n");
|
||||||
|
kprintf("\t\t^ysleep^! \t\tSleep for 3seconds\n");
|
||||||
|
kprintf("\t\t^ydbg^! \t\tTest new stuff\n");
|
||||||
|
kprintf("\t\t^yregs^! \t\tPrint current regs\n");
|
||||||
|
kprintf("\t\t^yrectest^! \t\tTSS test\n");
|
||||||
|
kprintf("\t\t^ypanic^! \t\tPanics (lol)\n");
|
||||||
|
kprintf("\t\t^yud2^! \t\tPanics with #UD\n");
|
||||||
|
kprintf("\t\t^ypf^! \t\tPanics with #PF\n");
|
||||||
|
|
||||||
|
kprintf("\t^pFun^!:\n");
|
||||||
|
kprintf("\t\t^ysplash^! \t\tShows splash (works kinda unstable)\n");
|
||||||
|
kprintf("\t\t^ymeow^! \t\tcats!!!\n");
|
||||||
|
kprintf("\t\t^ykfetch^! \t\tr/unixporn compatible\n");
|
||||||
|
|
||||||
|
kprintf("\t^gCustomisation^!:\n");
|
||||||
|
kprintf("\t\t^yblinking^! \t\tDisable/Enable cursor blinking\n");
|
||||||
|
|
||||||
|
kprintf("\t^bMisc^!:\n");
|
||||||
|
kprintf("\t\t^yclear^! \t\tClear console\n");
|
||||||
|
kprintf("\t\t^yhelp^! \t\tShow this menu\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void cmd_regs() {
|
void cmd_regs() {
|
||||||
|
|||||||
+17
-14
@@ -35,7 +35,10 @@ typedef enum {
|
|||||||
TOKEN_PANIC_PF,
|
TOKEN_PANIC_PF,
|
||||||
|
|
||||||
TOKEN_CLEAR,
|
TOKEN_CLEAR,
|
||||||
TOKEN_BLINKING
|
TOKEN_BLINKING,
|
||||||
|
|
||||||
|
TOKEN_BACK,
|
||||||
|
TOKEN_FORWARD,
|
||||||
} ksh_token;
|
} ksh_token;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@@ -46,17 +49,10 @@ typedef struct {
|
|||||||
static const ksh_command_map token_map[] = {
|
static const ksh_command_map token_map[] = {
|
||||||
{"", TOKEN_EMPTY},
|
{"", TOKEN_EMPTY},
|
||||||
|
|
||||||
{"cls", TOKEN_CLEAR},
|
// customisation
|
||||||
{"clear", TOKEN_CLEAR},
|
|
||||||
{"blinking", TOKEN_BLINKING},
|
{"blinking", TOKEN_BLINKING},
|
||||||
|
|
||||||
{"meow", TOKEN_MEOW},
|
|
||||||
{"nya", TOKEN_MEOW},
|
|
||||||
{"splash", TOKEN_SPLASH},
|
|
||||||
{"kfetch", TOKEN_KFETCH},
|
|
||||||
{"fastfetch", TOKEN_KFETCH},
|
|
||||||
{"neofetch", TOKEN_KFETCH},
|
|
||||||
|
|
||||||
|
// debug
|
||||||
{"sleep", TOKEN_SLEEP},
|
{"sleep", TOKEN_SLEEP},
|
||||||
{"dbg", TOKEN_DEBUG},
|
{"dbg", TOKEN_DEBUG},
|
||||||
{"regs", TOKEN_REGS},
|
{"regs", TOKEN_REGS},
|
||||||
@@ -65,8 +61,14 @@ static const ksh_command_map token_map[] = {
|
|||||||
{"ud2", TOKEN_PANIC_UD2},
|
{"ud2", TOKEN_PANIC_UD2},
|
||||||
{"pf", TOKEN_PANIC_PF},
|
{"pf", TOKEN_PANIC_PF},
|
||||||
|
|
||||||
|
// fun
|
||||||
|
{"meow", TOKEN_MEOW},
|
||||||
|
{"splash", TOKEN_SPLASH},
|
||||||
|
{"kfetch", TOKEN_KFETCH},
|
||||||
|
|
||||||
|
// misc
|
||||||
{"help", TOKEN_HELP},
|
{"help", TOKEN_HELP},
|
||||||
|
{"clear", TOKEN_CLEAR},
|
||||||
{nullptr, TOKEN_NULL}
|
{nullptr, TOKEN_NULL}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -85,7 +87,10 @@ void ksh() {
|
|||||||
kgets(cmdbuff, 256);
|
kgets(cmdbuff, 256);
|
||||||
switch(char2token(cmdbuff)) {
|
switch(char2token(cmdbuff)) {
|
||||||
case TOKEN_EMPTY: continue;
|
case TOKEN_EMPTY: continue;
|
||||||
|
|
||||||
|
case TOKEN_CLEAR: console_clear((u32) console_get_colors() & 0xFFFFFFFF); break;
|
||||||
|
case TOKEN_BLINKING: console_toggle_cursor_blink(); break;
|
||||||
|
|
||||||
case TOKEN_SLEEP: cmd_sleep(); break;
|
case TOKEN_SLEEP: cmd_sleep(); break;
|
||||||
case TOKEN_DEBUG: cmd_debug(); break;
|
case TOKEN_DEBUG: cmd_debug(); break;
|
||||||
case TOKEN_REGS: cmd_regs(); break;
|
case TOKEN_REGS: cmd_regs(); break;
|
||||||
@@ -95,12 +100,10 @@ void ksh() {
|
|||||||
case TOKEN_PANIC_PF: u64* bad_ptr = (u64*)0xDEADBEEF; *bad_ptr = 666;
|
case TOKEN_PANIC_PF: u64* bad_ptr = (u64*)0xDEADBEEF; *bad_ptr = 666;
|
||||||
|
|
||||||
case TOKEN_SPLASH: show_splash(console_get_context()); break;
|
case TOKEN_SPLASH: show_splash(console_get_context()); break;
|
||||||
case TOKEN_CLEAR: console_clear((u32) console_get_colors() & 0xFFFFFFFF); break;
|
|
||||||
case TOKEN_HELP: cmd_help(); break;
|
|
||||||
case TOKEN_KFETCH: cmd_kfetch(); break;
|
case TOKEN_KFETCH: cmd_kfetch(); break;
|
||||||
case TOKEN_MEOW: cmd_meow(); break;
|
case TOKEN_MEOW: cmd_meow(); break;
|
||||||
case TOKEN_BLINKING: console_toggle_cursor_blink(); break;
|
|
||||||
|
|
||||||
|
case TOKEN_HELP: cmd_help(); break;
|
||||||
default: kprintf("Unknown command!!\n"); break;
|
default: kprintf("Unknown command!!\n"); break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user