Files
Operator-system/kernel.c
2026-02-27 21:04:56 +00:00

268 lines
9.7 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* kernel.c Kernel entry point and Starling Terminal task.
*
* kmain() is called by the loader (main.c) after the ELF kernel has been
* mapped into memory. It initialises subsystems (IDT, memory, tasks),
* prints a welcome banner, and then spawns the Starling Terminal as a
* dedicated task. The terminal task runs the interactive read-eval-print
* loop that dispatches typed commands via commands.c.
*
* While the terminal waits for keyboard input it yields to the cooperative
* scheduler so that background tasks can make progress.
*/
#include "kernel_types.h"
#include "boot_info.h"
#include "commands.h"
#include "idt.h"
#include "memory.h"
#include "task.h"
#include "string_utils.h"
/* Null-safe print helper used throughout the kernel. */
#define SAFE_PRINT(Boot, ...) \
do { \
if ((Boot) != NULL && (Boot)->print != NULL) { \
(Boot)->print(__VA_ARGS__); \
} \
} while (0)
/* Simple text attribute helper (modelled after UEFI TEXT_ATTR). */
#define TEXT_ATTR(fg, bg) (UINTN)(((fg) & 0x0F) | (((bg) & 0x0F) << 4))
/* Basic colour constants (compatible with UEFI's palette). */
#define COLOR_BLACK 0x0
#define COLOR_LIGHTGREEN 0xA
/* Simple context passed to each Starling Terminal instance. */
typedef struct {
BootInfo *Boot;
UINTN depth; /* 0 = top-level, 1+ = nested shells */
TaskPrivilege shell_priv; /* logical privilege for this shell */
} StarlingContext;
/* ================================================================
* Starling Terminal task interactive command loop
* ================================================================ */
static void starling_terminal_task(void *arg)
{
StarlingContext *ctx = (StarlingContext *)arg;
BootInfo *Boot = NULL;
KeyEvent Key;
KSTATUS Status;
UINTN read_errors = 0;
CHAR16 line[128];
UINTN len = 0;
UINTN depth = 0;
TaskPrivilege shell_priv;
if (ctx == NULL || ctx->Boot == NULL) {
return;
}
Boot = ctx->Boot;
depth = ctx->depth;
shell_priv = ctx->shell_priv;
SAFE_PRINT(Boot, L"\n\r[Starling Terminal depth %d, priv %d] ready.\n\r\n\r",
depth, (INT32)shell_priv);
SAFE_PRINT(Boot, L"starling> ");
while (TRUE) {
/* Try non-blocking read first; yield to other tasks while idle */
if (Boot->try_read_key != NULL) {
Status = Boot->try_read_key(&Key);
if (Status != 0) {
task_yield();
continue;
}
} else if (Boot->read_key != NULL) {
Status = Boot->read_key(&Key);
} else {
SAFE_PRINT(Boot, L"Console input unavailable.\n\r");
break;
}
if (Status != 0) {
read_errors++;
if (read_errors == 1 || (read_errors % 64) == 0) {
SAFE_PRINT(Boot, L"read_key failed (status=%ld)\n\r",
(UINT64)Status);
}
continue;
}
read_errors = 0;
if (Key.unicode_char == L'\r' || Key.unicode_char == L'\n') {
/* Enter pressed: execute the buffered command */
line[len] = L'\0';
SAFE_PRINT(Boot, L"\n\r");
trim_spaces_inplace(line);
/* Built-in terminal controls: exit / spawn nested Starling. */
if (ascii_streq_ci(line, L"exit")) {
if (depth == 0) {
SAFE_PRINT(Boot, L"Starling: cannot exit top-level terminal.\n\r");
SAFE_PRINT(Boot, L"starling> ");
} else {
SAFE_PRINT(Boot, L"Exiting Starling Terminal depth %d...\n\r", depth);
break;
}
} else if (ascii_streq_ci(line, L"starling")) {
StarlingContext *child_ctx;
Task *child_task;
child_ctx = (StarlingContext *)kmalloc(sizeof(StarlingContext));
if (child_ctx == NULL) {
SAFE_PRINT(Boot, L"Starling: failed to allocate nested terminal context.\n\r");
SAFE_PRINT(Boot, L"starling> ");
} else {
child_ctx->Boot = Boot;
child_ctx->depth = depth + 1;
child_ctx->shell_priv = shell_priv;
child_task = task_create_with_priv(L"starling-term",
starling_terminal_task,
child_ctx,
shell_priv);
if (child_task == NULL) {
SAFE_PRINT(Boot, L"Starling: failed to spawn nested terminal.\n\r");
kfree(child_ctx);
SAFE_PRINT(Boot, L"starling> ");
} else {
SAFE_PRINT(Boot, L"[starling] spawned nested terminal (PID %d, depth %d)\n\r",
child_task->pid, child_ctx->depth);
/* Block this shell until the child terminal exits. */
task_wait(child_task);
SAFE_PRINT(Boot, L"[starling] returned from nested terminal (depth %d)\n\r", depth);
SAFE_PRINT(Boot, L"starling> ");
}
}
} else {
Task *cmd_task = execute_command(Boot, line, shell_priv);
/* If a command task was spawned, wait for it to finish. */
if (cmd_task != NULL) {
task_wait(cmd_task);
}
/* Reset for next command */
len = 0;
SAFE_PRINT(Boot, L"starling> ");
}
} else if (Key.scan_code == 0x08 || Key.unicode_char == L'\b' || Key.unicode_char == 0x7F) {
/* Backspace */
if (len > 0) {
len--;
SAFE_PRINT(Boot, L"\b \b");
}
} else if (Key.unicode_char >= 32 && Key.unicode_char < 127) {
/* Printable ASCII */
if (len < (sizeof(line) / sizeof(line[0]) - 1)) {
line[len++] = Key.unicode_char;
SAFE_PRINT(Boot, L"%c", Key.unicode_char);
}
}
}
/* Free our context on exit (allocated by the spawner). */
kfree(ctx);
}
/* ================================================================
* Kernel entry point
* ================================================================ */
void kmain(BootInfo *Boot)
{
KSTATUS Status;
Task *terminal_task = NULL;
StarlingContext *ctx = NULL;
if (Boot == NULL) {
return;
}
if (Boot->clear_screen != NULL) {
Status = Boot->clear_screen();
if (Status != 0) {
SAFE_PRINT(Boot, L"clear_screen failed (status=%ld)\n\r",
(UINT64)Status);
}
}
if (Boot->set_attribute != NULL) {
Status = Boot->set_attribute(TEXT_ATTR(COLOR_LIGHTGREEN, COLOR_BLACK));
if (Status != 0) {
SAFE_PRINT(Boot, L"set_attribute failed (status=%ld)\n\r",
(UINT64)Status);
}
}
/* ---- Subsystem initialisation ---- */
idt_init(Boot);
memory_init(Boot);
task_init(Boot);
/* ---- Welcome banner ---- */
SAFE_PRINT(Boot, L" Welcome to Simple 64-bit Operating System!\n\r");
SAFE_PRINT(Boot, L"================================================\n\r");
SAFE_PRINT(Boot, L"\n\r");
SAFE_PRINT(Boot, L"System Information:\n\r");
if (Boot->firmware_vendor != NULL) {
SAFE_PRINT(Boot, L" Firmware Vendor: %s\n\r", Boot->firmware_vendor);
SAFE_PRINT(Boot, L" Firmware Revision: %d.%d\n\r",
Boot->firmware_major, Boot->firmware_minor);
} else {
SAFE_PRINT(Boot, L" Firmware information: Unavailable\n\r");
}
SAFE_PRINT(Boot, L"\n\r");
SAFE_PRINT(Boot, L"Available Services:\n\r");
SAFE_PRINT(Boot, L" - Console Input/Output: %s\n\r",
(Boot->read_key != NULL && Boot->print != NULL) ? L"Active" : L"Unavailable");
SAFE_PRINT(Boot, L" - Terminal: Starling Terminal\n\r");
SAFE_PRINT(Boot, L"\n\r");
SAFE_PRINT(Boot, L"Type 'help' for a list of commands.\n\r\n\r");
/* ---- Spawn Starling Terminal as its own task ---- */
ctx = (StarlingContext *)kmalloc(sizeof(StarlingContext));
if (ctx == NULL) {
SAFE_PRINT(Boot, L"Failed to allocate Starling Terminal context; starting inline.\n\r");
StarlingContext inline_ctx;
inline_ctx.Boot = Boot;
inline_ctx.depth = 0;
inline_ctx.shell_priv = TASK_PRIV_USER;
starling_terminal_task(&inline_ctx);
return;
}
ctx->Boot = Boot;
ctx->depth = 0;
ctx->shell_priv = TASK_PRIV_USER;
terminal_task = task_create_with_priv(L"starling-term",
starling_terminal_task,
ctx,
TASK_PRIV_USER);
if (terminal_task == NULL) {
SAFE_PRINT(Boot, L"Failed to start Starling Terminal task; falling back to kernel loop.\n\r");
/*
* Fall back to running the terminal loop directly in the core
* thread so the system remains usable even if task creation
* fails for some reason.
*/
starling_terminal_task(Boot);
return;
}
SAFE_PRINT(Boot, L"[core] Started Starling Terminal (PID %d).\n\r", terminal_task->pid);
/* Core thread becomes an idle loop, yielding to the terminal and others. */
while (TRUE) {
task_yield();
}
}