rewrite init to restart failed processes, add file renaming, directory creation, directory renaming, directory removal, add process killing, unify shells, readme changes.

This commit is contained in:
maksw committed 2026-05-13 10:41:48 +02:00
1 parent f80e66ecde
commit ddb074f0e0
16 files changed
+476 -641

No files matched your search

Binary file not shown.
+29 -15
View File
@@ -53,23 +53,37 @@ void _start(const char* args)
uint32_t h = 0;
uint32_t s = 0;
SysDebugPrint("[init] starting\n");
s = SysCreateProcess(args, &h, NULL);
if (s != STATUS_SUCCESS) {
SysDebugPrint("[init] FATAL: failed to start!\n");
char buffer[12];
itoa(s, buffer);
SysDebugPrint(buffer); SysDebugPrint("\n");
SysExitProcess(1);
for (;;) {
SysDebugPrint("[init] starting\n");
s = SysCreateProcess(args, &h, NULL);
if (s != STATUS_SUCCESS) {
SysDebugPrint("[init] FATAL: failed to start!\n");
char buffer[12];
itoa(s, buffer);
SysDebugPrint(buffer);
SysDebugPrint("\n");
SysExitProcess(1);
}
SysDebugPrint("[init] waiting\n");
s = SysWaitForProcess(h);
if (s != STATUS_SUCCESS)
SysDebugPrint("[init] WARNING: SysWaitForProcess returned error\n");
int exitCode = 0;
if (SysGetProcessExitCode(h, &exitCode) != STATUS_SUCCESS) {
SysDebugPrint("[init] WARNING: failed to read exit code\n");
exitCode = 1;
}
SysCloseHandle(h);
if (exitCode == 0)
break;
SysDebugPrint("[init] child crashed, restarting\n");
}
SysDebugPrint("[init] waiting\n");
s = SysWaitForProcess(h);
if (s != STATUS_SUCCESS)
SysDebugPrint("[init] WARNING: SysWaitForProcess returned error\n");
SysCloseHandle(h);
SysDebugPrint("[init] done\n");
SysExitProcess(0);
}
+42
View File
@@ -289,6 +289,48 @@ __declspec(dllexport) KSTATUS IoDeleteFile(const char* path) {
return fs->Delete(fs, relPath);
}
__declspec(dllexport) KSTATUS IoRenameFile(const char* oldPath, const char* newPath) {
if (!oldPath || !newPath) return STATUS_INVALID_PARAMETER;
char oldRel[CWD_MAX];
char newRel[CWD_MAX];
uint8_t oldDrive = ResolvePath(oldPath, oldRel, sizeof(oldRel));
uint8_t newDrive = ResolvePath(newPath, newRel, sizeof(newRel));
if (oldDrive != newDrive) return STATUS_NOT_SUPPORTED;
IO_FILESYSTEM* fs = gVolumes[oldDrive].Fs;
if (!fs) return STATUS_NOT_FOUND;
if (!fs->Rename) return STATUS_NOT_SUPPORTED;
return fs->Rename(fs, oldRel, newRel);
}
__declspec(dllexport) KSTATUS IoCreateDir(const char* path) {
if (!path) return STATUS_INVALID_PARAMETER;
char relPath[CWD_MAX];
uint8_t drive = ResolvePath(path, relPath, sizeof(relPath));
IO_FILESYSTEM* fs = gVolumes[drive].Fs;
if (!fs) return STATUS_NOT_FOUND;
if (!fs->CreateDir) return STATUS_NOT_SUPPORTED;
return fs->CreateDir(fs, relPath);
}
__declspec(dllexport) KSTATUS IoRemoveDir(const char* path) {
if (!path) return STATUS_INVALID_PARAMETER;
char relPath[CWD_MAX];
uint8_t drive = ResolvePath(path, relPath, sizeof(relPath));
IO_FILESYSTEM* fs = gVolumes[drive].Fs;
if (!fs) return STATUS_NOT_FOUND;
if (!fs->RemoveDir) return STATUS_NOT_SUPPORTED;
return fs->RemoveDir(fs, relPath);
}
// ---------------------------------------------------------------------------
// IoTruncateFile - resize the file; updates the cached Size on success
// ---------------------------------------------------------------------------
+11
View File
@@ -45,6 +45,14 @@ typedef struct IO_FILESYSTEM {
// Delete the file at 'path'.
KSTATUS (*Delete)(struct IO_FILESYSTEM* fs, const char* path);
// Rename or move a file/directory within the same filesystem.
KSTATUS (*Rename)(struct IO_FILESYSTEM* fs,
const char* oldPath, const char* newPath);
// Create or remove directories.
KSTATUS (*CreateDir)(struct IO_FILESYSTEM* fs, const char* path);
KSTATUS (*RemoveDir)(struct IO_FILESYSTEM* fs, const char* path);
// Truncate or extend the file to exactly 'newSize' bytes.
KSTATUS (*Truncate)(struct IO_FILESYSTEM* fs, void* fileCtx,
uint64_t newSize);
@@ -119,6 +127,9 @@ __declspec(dllexport) KSTATUS IoWriteFile (FILE_OBJECT* file, const void* buf,
size_t size, size_t* bytesWritten);
__declspec(dllexport) KSTATUS IoCreateFile (const char* path, FILE_OBJECT** out);
__declspec(dllexport) KSTATUS IoDeleteFile (const char* path);
__declspec(dllexport) KSTATUS IoRenameFile (const char* oldPath, const char* newPath);
__declspec(dllexport) KSTATUS IoCreateDir (const char* path);
__declspec(dllexport) KSTATUS IoRemoveDir (const char* path);
__declspec(dllexport) KSTATUS IoTruncateFile(FILE_OBJECT* file, uint64_t newSize);
__declspec(dllexport) KSTATUS IoSeekFile(FILE_OBJECT* file, uint64_t offset);
__declspec(dllexport) uint64_t IoGetFileSize(FILE_OBJECT* file);
+17
View File
@@ -25,6 +25,7 @@ static void ProcessInit(void) {
}
LIST_ENTRY* KeGetProcessList(void) {
ProcessInit();
return &gProcessList;
}
@@ -36,6 +37,21 @@ PROCESS* KeGetCurrentProcess(void) {
return NULL;
}
size_t KeCopyProcessIds(uint32_t* pidsOut, size_t maxCount) {
ProcessInit();
uintptr_t flags = KeAcquireSpinlock(&gProcessListLock);
size_t count = 0;
LIST_ENTRY* head = &gProcessList;
for (LIST_ENTRY* node = head->Fwd; node != head; node = node->Fwd) {
PROCESS* p = CONTAINING_RECORD(node, PROCESS, GlobalLink);
if (pidsOut && count < maxCount) pidsOut[count] = p->ProcessId;
count++;
}
KeReleaseSpinlock(&gProcessListLock, flags);
return count;
}
// ---------------------------------------------------------------------------
// Destructor (called by ObDereferenceObject when RefCount hits zero)
// ---------------------------------------------------------------------------
@@ -206,6 +222,7 @@ OBJECT* KeLookupHandle(PROCESS* process, uint32_t handle) {
}
PROCESS* KeGetProcessById(uint32_t pid) {
ProcessInit();
uintptr_t flags = KeAcquireSpinlock(&gProcessListLock);
LIST_ENTRY* head = &gProcessList;
LIST_ENTRY* node = head->Fwd;
+2
View File
@@ -77,5 +77,7 @@ OBJECT* KeLookupHandle(PROCESS* process, uint32_t handle);
/* Return the global process list head (kernel-internal). */
LIST_ENTRY* KeGetProcessList(void);
PROCESS* KeGetCurrentProcess(void);
/* Copy a snapshot of process IDs into caller-provided storage. */
size_t KeCopyProcessIds(uint32_t* pidsOut, size_t maxCount);
/* Find a live process by its ProcessId. Bumps refcount; caller must ObDereferenceObject. */
PROCESS* KeGetProcessById(uint32_t pid);
+71
View File
@@ -1177,6 +1177,72 @@ static uint64_t SyscallNamedQueueOwnerPid(uint64_t a0, uint64_t a1, uint64_t a2,
return STATUS_NOT_FOUND;
}
static uint64_t SyscallKillProcess(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
(void)a2; (void)a3; (void)a4; (void)a5;
PROCESS* proc = KeGetProcessById((uint32_t)a0);
if (!proc) return STATUS_NOT_FOUND;
THREAD* self = KeGetCurrentThread();
int exitCode = (int)a1;
if (self && self->Owner == proc) {
KeExitProcess(proc, exitCode);
ObDereferenceObject(&proc->Header);
KeExitThread(self, exitCode);
while (true) ;
}
KeExitProcess(proc, exitCode);
ObDereferenceObject(&proc->Header);
return STATUS_SUCCESS;
}
// ---------------------------------------------------------------------------
// SYS_GET_PROCESS_LIST (65) a0=*pidsOut a1=maxCount a2=*countOut
// ---------------------------------------------------------------------------
static uint64_t SyscallGetProcessList(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
(void)a3; (void)a4; (void)a5;
uint32_t* pidsOut = (uint32_t*)(uintptr_t)a0;
size_t maxCount = (size_t)a1;
size_t* countOut = (size_t*)(uintptr_t)a2;
size_t count = KeCopyProcessIds(pidsOut, maxCount);
if (countOut) *countOut = count;
return STATUS_SUCCESS;
}
// ---------------------------------------------------------------------------
// SYS_RENAME_FILE (66) a0=*oldPath a1=*newPath
// ---------------------------------------------------------------------------
static uint64_t SyscallRenameFile(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
(void)a2; (void)a3; (void)a4; (void)a5;
const char* oldPath = (const char*)(uintptr_t)a0;
const char* newPath = (const char*)(uintptr_t)a1;
if (!oldPath || !newPath) return STATUS_INVALID_PARAMETER;
return IoRenameFile(oldPath, newPath);
}
// ---------------------------------------------------------------------------
// SYS_CREATE_DIR (67) a0=*path
// ---------------------------------------------------------------------------
static uint64_t SyscallCreateDir(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
const char* path = (const char*)(uintptr_t)a0;
if (!path) return STATUS_INVALID_PARAMETER;
return IoCreateDir(path);
}
// ---------------------------------------------------------------------------
// SYS_REMOVE_DIR (68) a0=*path
// ---------------------------------------------------------------------------
static uint64_t SyscallRemoveDir(uint64_t a0, uint64_t a1, uint64_t a2,
uint64_t a3, uint64_t a4, uint64_t a5) {
(void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
const char* path = (const char*)(uintptr_t)a0;
if (!path) return STATUS_INVALID_PARAMETER;
return IoRemoveDir(path);
}
// ===========================================================================
// Dispatch table - index must match SYS_* in syscall_nr.h exactly.
// ===========================================================================
@@ -1248,6 +1314,11 @@ static const SYSCALL_HANDLER gSyscallTable[SYS_MAX] = {
/* 61 SYS_OPEN_NAMED_QUEUE */ SyscallOpenNamedQueue,
/* 62 SYS_QUEUE_DUPLICATE */ SyscallQueueDuplicate,
/* 63 SYS_NAMED_QUEUE_OWNER_PID */ SyscallNamedQueueOwnerPid,
/* 64 SYS_KILL_PROCESS */ SyscallKillProcess,
/* 65 SYS_GET_PROCESS_LIST */ SyscallGetProcessList,
/* 66 SYS_RENAME_FILE */ SyscallRenameFile,
/* 67 SYS_CREATE_DIR */ SyscallCreateDir,
/* 68 SYS_REMOVE_DIR */ SyscallRemoveDir,
};
// ---------------------------------------------------------------------------
+18 -24
View File
@@ -303,21 +303,6 @@ static PROCESS* LaunchUserProcess(const char* filePath, const char* args) {
// Caller owns the reference returned by KeCreateProcess.
return proc;
}
// ---------------------------------------------------------------------------
// Kernel thread: wait for a process to exit, then log a message and shut down.
// Takes ownership of the PROCESS* reference passed as arg; releases it on exit.
// ---------------------------------------------------------------------------
static void ProcessWatcherThread(void* arg) {
PROCESS* proc = (PROCESS*)arg;
KeWaitForEvent(proc->ExitEvent);
DbgPrint("ProcessWatcherThread: Process \"%s\" (PID %u) exited with code %d.\n",
proc->Name, proc->ProcessId, proc->ExitCode);
ObDereferenceObject(&proc->Header);
DbgPrint("ProcessWatcherThread: Shutting down.\n");
gKmainHal->Power.Shutdown(); // does not return
}
static void PrintProcessList() {
LIST_ENTRY* listHead = KeGetProcessList();
LIST_ENTRY* current;
@@ -354,20 +339,29 @@ void SystemInitThread(void* arg) {
DbgPrint(" -> Kernel Pool: %.2f MB\n", (float)MmGetKernelPoolUsage() / (1024.0f * 1024.0f));
DbgPrint(" -> User Heap: %.2f MB\n", (float)MmGetUserHeapUsage() / (1024.0f * 1024.0f));
// Launch User-Mode Shell (this will trigger AHCI & FAT32 which CAN safely block now)
PROCESS* shellProc = LaunchUserProcess("system/init.exe", args->bootInfo->CommandLine);
if (shellProc) {
KSTATUS ws = KeCreateKernelThread((uintptr_t)ProcessWatcherThread,
(uintptr_t)shellProc,
PriorityNormal, (THREAD**)0);
if (!KSUCCESS(ws)) {
DbgPrint("SystemInitThread: Failed to create watcher thread (%d) -- leaking proc ref.\n", ws);
// Launch User-Mode init.exe and restart it until it exits cleanly.
while (true) {
PROCESS* shellProc = LaunchUserProcess("system/init.exe", args->bootInfo->CommandLine);
if (!shellProc) {
DbgPrint("SystemInitThread: Failed to start system/init.exe; retrying.\n");
KeYield();
continue;
}
KeWaitForEvent(shellProc->ExitEvent);
int exitCode = shellProc->ExitCode;
DbgPrint("SystemInitThread: init.exe exited with code %d.\n", exitCode);
ObDereferenceObject(&shellProc->Header);
if (exitCode == 0) break;
DbgPrint("SystemInitThread: Restarting init.exe.\n");
}
DbgPrint("SystemInitThread: init.exe completed successfully; shutting down.\n");
gKmainHal->Power.Shutdown();
MmFreePool(args);
}
// ---------------------------------------------------------------------------
// Main Kernel Entry
// ---------------------------------------------------------------------------
+14 -1
View File
@@ -162,4 +162,17 @@
#define SYS_QUEUE_DUPLICATE 62 // (uint32_t handle, uint32_t targetPid, uint32_t* handleOut) -> KSTATUS
#define SYS_NAMED_QUEUE_OWNER_PID 63 // (const char* name, uint32_t* pidOut) -> KSTATUS
#define SYS_MAX 64
// ---------------------------------------------------------------------------
// Process utilities
// ---------------------------------------------------------------------------
#define SYS_KILL_PROCESS 64 // (uint32_t pid, int exitCode) -> KSTATUS
#define SYS_GET_PROCESS_LIST 65 // (uint32_t* pidsOut, size_t maxCount, size_t* countOut) -> KSTATUS
// ---------------------------------------------------------------------------
// Filesystem mutations
// ---------------------------------------------------------------------------
#define SYS_RENAME_FILE 66 // (const char* oldPath, const char* newPath) -> KSTATUS
#define SYS_CREATE_DIR 67 // (const char* path) -> KSTATUS
#define SYS_REMOVE_DIR 68 // (const char* path) -> KSTATUS
#define SYS_MAX 69
+61 -146
View File
@@ -5,67 +5,37 @@
#include <syscall.h>
#include <io_file.h>
#define MAX_CMD 256
// ---------------------------------------------------------------------------
// Output helpers
// ---------------------------------------------------------------------------
static void print(const char* s) {
SysWriteConsole(s, strlen(s));
}
static void print(const char* s) { SysWriteConsole(s, strlen(s)); }
static void printUInt(uint32_t n) {
char buf[12];
int i = 0;
char buf[12]; int i = 0;
if (n == 0) { print("0"); return; }
while (n > 0) { buf[i++] = (char)('0' + n % 10); n /= 10; }
char rev[12];
int j = 0;
while (i > 0) rev[j++] = buf[--i];
rev[j] = '\0';
print(rev);
while (i > 0) { char c[2] = { buf[--i], '\0' }; print(c); }
}
static void printInt(int32_t n) {
if (n < 0) {
print("-");
printUInt((uint32_t)-(n + 1) + 1);
} else {
printUInt((uint32_t)n);
}
if (n < 0) { print("-"); printUInt((uint32_t)-(n + 1) + 1); }
else { printUInt((uint32_t)n); }
}
// ---------------------------------------------------------------------------
// Line editor
// ---------------------------------------------------------------------------
#define MAX_CMD 256
static void readLine(char* buf, int len) {
int pos = 0;
while (true) {
char c = SysKbReadChar();
if (!c) {
SysYield();
continue;
}
if (c == '\r' || c == '\n') {
print("\n");
break;
}
if ((c == '\b' || c == 127) && pos > 0) {
pos--;
print("\b \b");
continue;
}
if (c < 0x20 || c == 127)
continue;
if (pos < len - 1) {
buf[pos++] = c;
char echo[2] = { c, '\0' };
print(echo);
}
if (!c) { SysYield(); continue; }
if (c == '\r' || c == '\n') { print("\n"); break; }
if ((c == '\b' || c == 127) && pos > 0) { pos--; print("\b \b"); continue; }
if (c < 0x20 || c == 127) continue;
if (pos < len - 1) { buf[pos++] = c; char echo[2] = {c, '\0'}; print(echo); }
}
buf[pos] = '\0';
}
@@ -83,87 +53,74 @@ static char* trim(char* s) {
// ---------------------------------------------------------------------------
static void cmd_help() {
print("Available commands:\n"
" help - Show this list\n"
" dir - List files\n"
" cd <path> - Change directory\n"
" type <file> - Display file contents\n"
" del <file> - Delete a file\n"
" write <file> <tx> - Create a file with text\n"
" exit - Close the shell\n");
" help - Show this list\n"
" dir [path] - List directory contents\n"
" cd <path> - Change directory\n"
" type <file> - Display file contents\n"
" del <file> - Delete a file\n"
" write <file> <tx> - Create a file with text\n"
" clear - Clear the screen\n"
" exit - Close the shell\n");
}
static void cmd_write(const char* args) {
char filename[MAX_CMD];
int i = 0;
char filename[MAX_CMD]; int i = 0;
while (args[i] != ' ' && args[i] != '\0' && i < MAX_CMD - 1) {
filename[i] = args[i];
i++;
filename[i] = args[i]; i++;
}
filename[i] = '\0';
if (args[i] == '\0' || args[i+1] == '\0') {
print("write: usage: write <filename> <text>\n");
return;
}
if (args[i] == '\0' || args[i+1] == '\0') { print("write: usage: write <filename> <text>\n"); return; }
uint32_t hFile;
if (SysCreateFile(filename, &hFile) != 0) {
print("write: could not create file\n");
return;
}
const char* text = args + i + 1;
if (SysCreateFile(filename, &hFile) != 0) { print("write: could not create file\n"); return; }
size_t written;
SysWriteFile(hFile, text, strlen(text), &written);
SysWriteFile(hFile, args + i + 1, strlen(args + i + 1), &written);
SysCloseHandle(hFile);
print("File written successfully.\n");
}
static void cmd_dir(const char* path) {
uint32_t hDir;
const char* target = (path && *path != '\0') ? path : ".";
// Validate input
if (path == NULL || path[0] == '\0') {
path = "."; // Default to current directory if empty
if (SysOpenDir(target, &hDir) != 0) {
print("dir: failed to open directory\n");
return;
}
// SysOpenDir (Syscall 54) handles the const char* path directly
if (SysOpenDir(path, &hDir) != 0) {
SysDebugPrint("dir: failed to open directory\n");
return;
}
// Assuming KDIR_ENTRY is your structure for directory entries
KDIR_ENTRY ke;
// SysReadDir (Syscall 55) populates the buffer with entry data
// It typically returns 0 on success and non-zero (or error) when done
while (SysReadDir(hDir, &ke) == 0) {
// We assume ke.Name is a null-terminated string within the struct
// Skip hidden/system markers if desired (e.g., those starting with .)
if (ke.Name[0] == '.') continue;
// Corrected Attribute Check: 0x10 is the Directory bit in FAT
if (ke.Attr & 0x10) {
print("<DIR> ");
} else {
print(" ");
}
print(ke.Name);
// Optional: print file size for non-directories
if (!(ke.Attr & 0x10)) {
print(" (");
printUInt(ke.FileSize);
print(" bytes)");
}
print("\n");
}
// Always close the handle (Syscall 26) to prevent leaks
SysCloseHandle(hDir);
}
static void cmd_type(const char* filename) {
uint32_t hFile;
if (SysOpenFile(filename, &hFile) != 0) {
print("type: error opening file\n");
return;
}
char buffer[512];
size_t bytesRead;
if (SysOpenFile(filename, &hFile) != 0) { print("type: cannot open file\n"); return; }
char buffer[512]; size_t bytesRead;
while (SysReadFile(hFile, buffer, sizeof(buffer) - 1, &bytesRead) == 0 && bytesRead > 0) {
buffer[bytesRead] = '\0';
print(buffer);
buffer[bytesRead] = '\0'; print(buffer);
}
SysCloseHandle(hFile);
print("\n");
SysCloseHandle(hFile); print("\n");
}
// ---------------------------------------------------------------------------
@@ -171,76 +128,34 @@ static void cmd_type(const char* filename) {
// ---------------------------------------------------------------------------
static int runCommand(const char* cmd) {
if (!cmd || *cmd == '\0') return 0;
if (strcmp(cmd, "exit") == 0) return 1;
if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; }
if (strcmp(cmd, "clear") == 0) { SysScreenClear(0); return 0; }
if (strcmp(cmd, "crash") == 0) { *(int*)0 = 42; return 0; }
if (strcmp(cmd, "dir") == 0) {
cmd_dir(".");
return 0;
}
if (strncmp(cmd, "dir ", 4) == 0) {
cmd_dir(cmd + 4);
return 0;
}
if (strcmp(cmd, "clear") == 0) {
SysScreenClear(0x00000000);
return 0;
}
if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; }
if (strncmp(cmd, "dir ", 4) == 0) { cmd_dir(cmd + 4); return 0; }
if (strncmp(cmd, "cd ", 3) == 0) { SysSetCwd(cmd + 3); return 0; }
if (strncmp(cmd, "del ", 4) == 0) { SysDeleteFile(cmd + 4); return 0; }
if (strncmp(cmd, "type ", 5) == 0) { cmd_type(cmd + 5); return 0; }
if (strncmp(cmd, "write ", 6) == 0) { cmd_write(cmd + 6); return 0; }
if (strncmp(cmd, "cd ", 3) == 0) {
SysSetCwd(cmd + 3);
return 0;
}
if (strncmp(cmd, "del ", 4) == 0) {
SysDeleteFile(cmd + 4);
return 0;
}
if (strncmp(cmd, "type ", 5) == 0) {
cmd_type(cmd + 5);
return 0;
}
if (strncmp(cmd, "write ", 6) == 0) {
cmd_write(cmd + 6);
return 0;
}
// --- External Process Execution ---
uint32_t hProc;
if (SysCreateProcess(cmd, &hProc, cmd) == 0) {
SysWaitForProcess(hProc);
int exitCode = 0;
SysGetProcessExitCode(hProc, &exitCode);
SysCloseHandle(hProc);
while (SysKbPoll()) {
(void)SysKbReadChar();
}
} else {
print("shell: launch failed\n");
}
while (SysKbPoll()) (void)SysKbReadChar();
} else { print("shell: launch failed\n"); }
return 0;
}
// ---------------------------------------------------------------------------
// Entry point
// ---------------------------------------------------------------------------
int main(int argc, char** argv) {
char lineBuf[MAX_CMD];
print("shell: ready\n");
while (true) {
print("> ");
readLine(lineBuf, MAX_CMD);
if (runCommand(trim(lineBuf)))
break;
if (runCommand(trim(lineBuf))) break;
}
print("shell: goodbye\n");
SysExitProcess(0);
return 0;
+41 -131
View File
@@ -3,18 +3,11 @@
#include <stdbool.h>
#include <string.h>
#define MAX_CMD 256
#define NAME_MAX 259
typedef struct dirent {
char d_name[NAME_MAX + 1];
unsigned char d_type; // DT_REG or DT_DIR
} dirent;
typedef struct DIR {
uint32_t KHandle; // kernel DIR_OBJECT handle
dirent Current;
bool Valid;
} DIR;
typedef struct dirent { char d_name[NAME_MAX + 1]; unsigned char d_type; } dirent;
typedef struct DIR { uint32_t KHandle; dirent Current; bool Valid; } DIR;
extern int read(int fd, void *buf, size_t count);
extern int write(int fd, const void *buf, size_t count);
@@ -25,36 +18,21 @@ extern DIR* opendir(const char* path);
extern dirent* readdir(DIR* d);
extern int closedir(DIR* d);
extern int unlink(const char *pathname);
extern int posix_spawn(int *pid, const char *path, const void *file_act, const void *attr, char *const argv[], char *const envp[]);
extern int posix_spawn(int *pid, const char *path, const void *act, const void *attr, char *const argv[], char *const envp[]);
extern int waitpid(int pid, int *status, int options);
extern void exit(int status);
extern int ClearConsoleScreenBuffer(void* h);
extern void PosixFdInit(void);
extern int ClearConsoleScreenBuffer(void* hConsole);
// ---------------------------------------------------------------------------
// Global handles
// ---------------------------------------------------------------------------
static int hIn = 0; // stdin
static int hOut = 1; // stdout
static int hIn = 0; static int hOut = 1;
// ---------------------------------------------------------------------------
// Output helpers
// ---------------------------------------------------------------------------
static void print(const char* s) {
write(hOut, s, strlen(s));
}
static void print(const char* s) { write(hOut, s, strlen(s)); }
static void printUInt(uint32_t n) {
char buf[12];
int i = 0;
char buf[12]; int i = 0;
if (n == 0) { print("0"); return; }
while (n > 0) { buf[i++] = (char)('0' + n % 10); n /= 10; }
char rev[12];
int j = 0;
while (i > 0) rev[j++] = buf[--i];
rev[j] = '\0';
print(rev);
while (i > 0) { char c[2] = { buf[--i], '\0' }; print(c); }
}
static void printInt(int32_t n) {
@@ -62,28 +40,14 @@ static void printInt(int32_t n) {
printUInt((uint32_t)n);
}
// ---------------------------------------------------------------------------
// Line editor
// ---------------------------------------------------------------------------
#define MAX_CMD 256
static void readLine(char* buf, int len) {
int pos = 0;
while (true) {
char c;
if (read(hIn, &c, 1) <= 0) break;
char c; if (read(hIn, &c, 1) <= 0) break;
if (c == '\r' || c == '\n') { print("\n"); break; }
if ((c == '\b' || c == 127) && pos > 0) {
pos--;
print("\b \b");
continue;
}
if ((c == '\b' || c == 127) && pos > 0) { pos--; print("\b \b"); continue; }
if (c < 0x20 || c == 127) continue;
if (pos < len - 1) {
buf[pos++] = c;
char echo[2] = { c, '\0' };
print(echo);
}
if (pos < len - 1) { buf[pos++] = c; char echo[2] = {c, '\0'}; print(echo); }
}
buf[pos] = '\0';
}
@@ -96,136 +60,82 @@ static char* trim(char* s) {
return s;
}
// ---------------------------------------------------------------------------
// Built-in commands
// ---------------------------------------------------------------------------
static void cmd_help() {
print("Available commands:\n"
" help - Show this list\n"
" dir [path] - List directory contents\n"
" cd <path> - Change directory\n"
" type <file> - Display file contents\n"
" del <file> - Delete a file\n"
" write <file> <txt> - Create a file with text\n"
" exit - Close the shell\n");
" help - Show this list\n"
" dir [path] - List directory contents\n"
" cd <path> - Change directory\n"
" type <file> - Display file contents\n"
" del <file> - Delete a file\n"
" write <file> <txt> - Create a file with text\n"
" clear - Clear the screen\n"
" exit - Close the shell\n");
}
static void cmd_write(const char* args) {
char filename[MAX_CMD];
int i = 0;
char filename[MAX_CMD]; int i = 0;
while (args[i] != ' ' && args[i] != '\0' && i < MAX_CMD - 1) {
filename[i] = args[i];
i++;
filename[i] = args[i]; i++;
}
filename[i] = '\0';
if (args[i] == '\0' || args[i+1] == '\0') return;
// Open with O_WRONLY | O_CREAT | O_TRUNC (typical flags: 0x0001 | 0x0040 | 0x0200)
int fd = open(filename, 0x0241, 0644);
if (fd < 0) return;
if (args[i] == '\0' || args[i+1] == '\0') { print("write: usage: write <filename> <text>\n"); return; }
int fd = open(filename, 0x0241, 0644); // O_WRONLY | O_CREAT | O_TRUNC
if (fd < 0) { print("write: could not create file\n"); return; }
write(fd, args + i + 1, strlen(args + i + 1));
close(fd);
print("File written successfully.\n");
}
static void cmd_dir(const char* path) {
// If no path is provided, default to current directory
const char* target = (path && *path != '\0') ? path : ".";
DIR* d = opendir(target);
if (!d) {
print("dir: cannot access '");
print(target);
print("'\n");
return;
}
if (!d) { print("dir: cannot access directory\n"); return; }
dirent* entry;
while ((entry = readdir(d)) != NULL) {
// Filter out the current and parent directory markers
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
continue;
}
// Display type (Assuming 1=DIR, 2=REG based on common custom POSIX layouts)
if (entry->d_type == 1) {
print("<DIR> ");
} else {
print(" ");
}
print(entry->d_name);
print("\n");
if (entry->d_name[0] == '.') continue;
print(entry->d_type == 1 ? "<DIR> " : " ");
print(entry->d_name); print("\n");
}
closedir(d);
}
static void cmd_type(const char* filename) {
int fd = open(filename, 0); // O_RDONLY
if (fd < 0) return;
char buffer[512];
int n;
while ((n = read(fd, buffer, 511)) > 0) {
buffer[n] = '\0';
print(buffer);
}
close(fd);
print("\n");
if (fd < 0) { print("type: cannot open file\n"); return; }
char buffer[512]; int n;
while ((n = read(fd, buffer, 511)) > 0) { buffer[n] = '\0'; print(buffer); }
close(fd); print("\n");
}
// ---------------------------------------------------------------------------
// Run one command.
// ---------------------------------------------------------------------------
static int runCommand(const char* cmd) {
if (!cmd || *cmd == '\0') return 0;
if (strcmp(cmd, "exit") == 0) return 1;
if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; }
if (strcmp(cmd, "clear") == 0) { ClearConsoleScreenBuffer(0); return 0; }
if (strcmp(cmd, "crash") == 0) { *(int*)0 = 42; return 0; }
if (strcmp(cmd, "dir") == 0) {
cmd_dir(".");
return 0;
}
if (strncmp(cmd, "dir ", 4) == 0) {
cmd_dir(cmd + 4);
return 0;
}
if (strcmp(cmd, "clear") == 0) {
ClearConsoleScreenBuffer(0);
return 0;
}
if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; }
if (strncmp(cmd, "dir ", 4) == 0) { cmd_dir(cmd + 4); return 0; }
if (strncmp(cmd, "cd ", 3) == 0) { chdir(cmd + 3); return 0; }
if (strncmp(cmd, "del ", 4) == 0) { unlink(cmd + 4); return 0; }
if (strncmp(cmd, "type ", 5) == 0) { cmd_type(cmd + 5); return 0; }
if (strncmp(cmd, "write ", 6) == 0) { cmd_write(cmd + 6); return 0; }
// --- External Process Execution (No Fork) ---
int pid;
char *argv[] = {(char*)cmd, NULL};
int pid; char *argv[] = {(char*)cmd, NULL};
if (posix_spawn(&pid, cmd, NULL, NULL, argv, NULL) == 0) {
int status;
waitpid(pid, &status, 0);
} else {
print("shell: error launching\n");
}
int status; waitpid(pid, &status, 0);
} else { print("shell: launch failed\n"); }
return 0;
}
int main(const char* args) {
int main() {
PosixFdInit();
char lineBuf[MAX_CMD];
print("shell: ready\n");
while (true) {
print("> ");
readLine(lineBuf, MAX_CMD);
if (runCommand(trim(lineBuf))) break;
}
print("shell: goodbye\n");
exit(0);
}
+63 -258
View File
@@ -4,85 +4,42 @@
#include <stdbool.h>
#include <string.h>
// !Made-up! clear console api.
BOOL ClearConsoleScreenBuffer(HANDLE hConsole);
// ---------------------------------------------------------------------------
// Global handles
// ---------------------------------------------------------------------------
#define MAX_CMD 256
static HANDLE hIn = INVALID_HANDLE_VALUE;
static HANDLE hOut = INVALID_HANDLE_VALUE;
// ---------------------------------------------------------------------------
// Output helpers
// ---------------------------------------------------------------------------
// External/Custom API
BOOL ClearConsoleScreenBuffer(HANDLE hConsole);
// --- Output Helpers ---
static void print(const char* s) {
DWORD written;
// Write to the actual console window
if (hOut != INVALID_HANDLE_VALUE) {
WriteConsoleA(hOut, s, (DWORD)strlen(s), &written, 0);
} else {
OutputDebugStringA(s);
}
if (hOut != INVALID_HANDLE_VALUE) WriteConsoleA(hOut, s, (DWORD)strlen(s), &written, 0);
else OutputDebugStringA(s);
}
static void printUInt(uint32_t n) {
char buf[12];
int i = 0;
char buf[12]; int i = 0;
if (n == 0) { print("0"); return; }
while (n > 0) { buf[i++] = (char)('0' + n % 10); n /= 10; }
char rev[12];
int j = 0;
while (i > 0) rev[j++] = buf[--i];
rev[j] = '\0';
print(rev);
while (i > 0) { char c[2] = { buf[--i], '\0' }; print(c); }
}
static void printInt(int32_t n) {
char buf[12];
int i = 0;
uint32_t val = (n < 0) ? (print("-"), (uint32_t)-(n + 1) + 1) : (uint32_t)n;
if (val == 0) { print("0"); return; }
while (val > 0) {
buf[i++] = (char)('0' + (val % 10));
val /= 10;
}
while (i > 0) {
char c[2] = { buf[--i], '\0' };
print(c); // Assumes print() handles strings
}
if (n < 0) { print("-"); n = -n; }
printUInt((uint32_t)n);
}
// ---------------------------------------------------------------------------
// Line editor
// ---------------------------------------------------------------------------
#define MAX_CMD 256
// --- Line Editor ---
static void readLine(char* buf, int len) {
int pos = 0;
while (true) {
char c;
DWORD nRead;
char c; DWORD nRead;
ReadConsoleA(hIn, &c, 1, &nRead, 0);
if (!nRead) continue;
if (c == '\r' || c == '\n') {
print("\n");
break;
}
if ((c == '\b' || c == 127) && pos > 0) {
pos--;
print("\b \b");
continue;
}
if (c < 0x20 || c == 127)
continue;
if (c == '\r' || c == '\n') { print("\n"); break; }
if ((c == '\b' || c == 127) && pos > 0) { pos--; print("\b \b"); continue; }
if (c < 0x20 || c == 127) continue;
if (pos < len - 1) {
buf[pos++] = c;
char echo[2] = { c, '\0' };
@@ -100,253 +57,101 @@ static char* trim(char* s) {
return s;
}
// ---------------------------------------------------------------------------
// Built-in commands
// ---------------------------------------------------------------------------
// --- Built-in Commands ---
static void cmd_help() {
print("Available commands:\n"
" help - Show this list\n"
" dir - List files in current directory\n"
" cd <path> - Change directory\n"
" type <file> - Display file contents\n"
" del <file> - Delete a file\n"
" write <file> <tx> - Create a file with text\n"
" exit - Close the shell\n");
" help - Show this list\n"
" dir [path] - List directory contents\n"
" cd <path> - Change directory\n"
" type <file> - Display file contents\n"
" del <file> - Delete a file\n"
" write <file> <tx> - Create a file with text\n"
" clear - Clear the screen\n"
" exit - Close the shell\n");
}
static void cmd_write(const char* args) {
char filename[MAX_PATH];
int i = 0;
// Parse filename (up to first space)
char filename[MAX_PATH]; int i = 0;
while (args[i] != ' ' && args[i] != '\0' && i < MAX_PATH - 1) {
filename[i] = args[i];
i++;
filename[i] = args[i]; i++;
}
filename[i] = '\0';
if (args[i] == '\0' || args[i+1] == '\0') {
print("write: usage: write <filename> <text>\n");
return;
}
const char* text = args + i + 1; // Content starts after the space
HANDLE hFile = CreateFileA(filename, GENERIC_WRITE, 0, 0, CREATE_ALWAYS, 0, 0);
if (hFile == INVALID_HANDLE_VALUE) {
print("write: could not create file\n");
return;
}
if (hFile == INVALID_HANDLE_VALUE) { print("write: could not create file\n"); return; }
DWORD written;
if (!WriteFile(hFile, text, (DWORD)strlen(text), &written, 0)) {
print("write: error writing to file\n");
} else {
print("File written successfully.\n");
}
WriteFile(hFile, args + i + 1, (DWORD)strlen(args + i + 1), &written, 0);
CloseHandle(hFile);
print("File written successfully.\n");
}
static void cmd_dir(const char* path) {
WIN32_FIND_DATAA fd;
char search_path[MAX_PATH];
const char* target = (path && *path != '\0') ? path : ".";
size_t path_len = 0;
while (path[path_len] != '\0' && path_len < MAX_PATH) {
path_len++;
}
// Ensure we have room for the path + "\*" + null terminator
if (path_len + 3 > MAX_PATH) {
print("dir: path too long\n");
return;
}
// Manual concatenation
memcpy(search_path, path, path_len);
// Append the wildcard pattern
search_path[path_len] = '\\';
search_path[path_len + 1] = '*';
search_path[path_len + 2] = '\0';
size_t len = strlen(target);
if (len + 3 > MAX_PATH) { print("dir: path too long\n"); return; }
strcpy(search_path, target);
strcat(search_path, "\\*");
HANDLE hFind = FindFirstFileA(search_path, &fd);
if (hFind == INVALID_HANDLE_VALUE) {
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
return;
}
print("dir: failed to read directory\n");
return;
}
if (hFind == INVALID_HANDLE_VALUE) { print("dir: failed to read directory\n"); return; }
do {
// Skip the "." and ".." entries to keep output clean
if (path_len > 0 && fd.cFileName[0] == '.') {
if (fd.cFileName[1] == '\0' || (fd.cFileName[1] == '.' && fd.cFileName[2] == '\0')) {
continue;
}
}
if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
print("<DIR> ");
} else {
print(" ");
}
print(fd.cFileName);
print("\n");
if (fd.cFileName[0] == '.') continue; // Skip . and ..
print(fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ? "<DIR> " : " ");
print(fd.cFileName); print("\n");
} while (FindNextFileA(hFind, &fd));
FindClose(hFind);
}
static void cmd_type(const char* filename) {
HANDLE hFile = CreateFileA(filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if (hFile == INVALID_HANDLE_VALUE) {
print("type: could not open '");
print(filename);
print("'\n");
return;
}
char buffer[512];
DWORD bytesRead;
if (hFile == INVALID_HANDLE_VALUE) { print("type: cannot open file\n"); return; }
char buffer[512]; DWORD bytesRead;
while (ReadFile(hFile, buffer, sizeof(buffer) - 1, &bytesRead, 0) && bytesRead > 0) {
buffer[bytesRead] = '\0';
print(buffer);
buffer[bytesRead] = '\0'; print(buffer);
}
CloseHandle(hFile);
print("\n");
CloseHandle(hFile); print("\n");
}
// ---------------------------------------------------------------------------
// Run one command. Returns 1 if the shell should exit.
// ---------------------------------------------------------------------------
static int runCommand(const char* cmd) {
if (!cmd || *cmd == '\0')
return 0;
if (!cmd || *cmd == '\0') return 0;
if (strcmp(cmd, "exit") == 0) return 1;
if (strcmp(cmd, "help") == 0) { cmd_help(); return 0; }
if (strcmp(cmd, "clear") == 0) { ClearConsoleScreenBuffer(hOut); return 0; }
if (strcmp(cmd, "crash") == 0) { *(int*)0 = 42; return 0; }
if (strcmp(cmd, "dir") == 0) { cmd_dir("."); return 0; }
if (strncmp(cmd, "dir ", 4) == 0) { cmd_dir(cmd + 4); return 0; }
if (strncmp(cmd, "cd ", 3) == 0) { SetCurrentDirectoryA(cmd + 3); return 0; }
if (strncmp(cmd, "del ", 4) == 0) { DeleteFileA(cmd + 4); return 0; }
if (strncmp(cmd, "type ", 5) == 0) { cmd_type(cmd + 5); return 0; }
if (strncmp(cmd, "write ", 6) == 0) { cmd_write(cmd + 6); return 0; }
// --- Built-in commands ---
if (strcmp(cmd, "exit") == 0) {
return 1;
STARTUPINFOA si = { sizeof(si) }; PROCESS_INFORMATION pi;
char cmdBuf[MAX_CMD]; strncpy(cmdBuf, cmd, MAX_CMD-1);
if (CreateProcessA(NULL, cmdBuf, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess); CloseHandle(pi.hThread);
} else {
print("shell: launch failed\n");
}
if (strcmp(cmd, "help") == 0) {
cmd_help();
return 0;
}
if (strcmp(cmd, "crash") == 0) {
*(int*)0 = 42;
return 0;
}
if (strcmp(cmd, "clear") == 0) {
ClearConsoleScreenBuffer(hOut);
return 0;
}
if (strcmp(cmd, "dir") == 0) {
cmd_dir(".");
return 0;
}
if (strncmp(cmd, "dir ", 4) == 0) {
cmd_dir(cmd + 4);
return 0;
}
if (strncmp(cmd, "cd ", 3) == 0) {
const char* path = cmd + 3;
if (!SetCurrentDirectoryA(path)) {
print("cd: failed to change directory to '");
print(path);
print("'\n");
}
return 0;
}
if (strncmp(cmd, "del ", 4) == 0) {
const char* file = cmd + 4;
if (!DeleteFileA(file)) {
print("del: failed to delete '");
print(file);
print("'\n");
}
return 0;
}
if (strncmp(cmd, "type ", 5) == 0) {
cmd_type(cmd + 5);
return 0;
}
if (strncmp(cmd, "write ", 6) == 0) {
cmd_write(cmd + 6);
return 0;
}
// --- External Process Execution ---
STARTUPINFOA si;
PROCESS_INFORMATION pi;
unsigned char* p = (unsigned char*)&si;
for (size_t i = 0; i < sizeof(si); i++) p[i] = 0;
si.cb = (DWORD)sizeof(si);
// CreateProcessA requires a mutable buffer for the command line argument
char cmdBuf[MAX_CMD];
strncpy(cmdBuf, cmd, MAX_CMD - 1);
cmdBuf[MAX_CMD - 1] = '\0';
if (!CreateProcessA(0, cmdBuf, 0, 0, 0, 0, 0, 0, &si, &pi)) {
print("shell: could not launch '");
print(cmd);
print("', error code: ");
printUInt(GetLastError());
print("\n");
return 0;
}
WaitForSingleObject(pi.hProcess, INFINITE);
FlushConsoleInputBuffer(hOut);
DWORD exitCode = 0;
GetExitCodeProcess(pi.hProcess, &exitCode);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
if (exitCode != 0) {
print("shell: '");
print(cmd);
print("' exited with code ");
printInt(exitCode);
print("\n");
}
return 0;
}
// ---------------------------------------------------------------------------
// Entry point
// ---------------------------------------------------------------------------
int main(const char* cmdline) {
int main() {
hIn = GetStdHandle(STD_INPUT_HANDLE);
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
char lineBuf[MAX_CMD];
print("shell: ready\n");
print(cmdline);
print("\n");
while (true) {
print("> ");
readLine(lineBuf, MAX_CMD);
if (runCommand(trim(lineBuf)))
break;
if (runCommand(trim(lineBuf))) break;
}
print("shell: goodbye\n");
ExitProcess(0);
}
+11 -2
View File
@@ -82,7 +82,7 @@ uint64_t SysMouseRead(int* dx, int* dy, uint8_t* buttons); // 46
void SysMouseGetPos(int* x, int* y); // 47
// ---------------------------------------------------------------------------
// System Info & Process Management (48-53)
// System Info & Process Management (48-65)
// ---------------------------------------------------------------------------
uint64_t SysGetTick(void); // 48
uint32_t SysDebugPrint(const char* str); // 49
@@ -100,7 +100,7 @@ uint32_t SysSetCwd(const char* path); // 56
uint32_t SysGetCwd(char* buf, size_t size); // 57
// ---------------------------------------------------------------------------
// Process/Thread Helpers & Named Queues (58-63)
// Process/Thread Helpers & Named Queues (58-65)
// ---------------------------------------------------------------------------
uint32_t SysWaitThread(uint32_t tid); // 58
uint32_t SysGetProcessPid(uint32_t handle, uint32_t* pidOut); // 59
@@ -108,3 +108,12 @@ uint32_t SysPublishQueue(const char* name, uint32_t handle); // 60
uint32_t SysOpenNamedQueue(const char* name, uint32_t* handleOut); // 61
uint32_t SysQueueDuplicate(uint32_t handle, uint32_t targetPid, uint32_t* handleOut); // 62
uint32_t SysNamedQueueOwnerPid(const char* name, uint32_t* pidOut); // 63
uint32_t SysKillProcess(uint32_t pid, int exitCode); // 64
uint32_t SysGetProcessList(uint32_t* pidsOut, size_t maxCount, size_t* countOut); // 65
// ---------------------------------------------------------------------------
// Filesystem mutations (66-68)
// ---------------------------------------------------------------------------
uint32_t SysRenameFile(const char* oldPath, const char* newPath); // 66
uint32_t SysCreateDir(const char* path); // 67
uint32_t SysRemoveDir(const char* path); // 68
+6 -1
View File
@@ -64,5 +64,10 @@ SYS_PUBLISH_QUEUE EQU 60
SYS_OPEN_NAMED_QUEUE EQU 61
SYS_QUEUE_DUPLICATE EQU 62
SYS_NAMED_QUEUE_OWNER_PID EQU 63
SYS_KILL_PROCESS EQU 64
SYS_GET_PROCESS_LIST EQU 65
SYS_RENAME_FILE EQU 66
SYS_CREATE_DIR EQU 67
SYS_REMOVE_DIR EQU 68
SYS_MAX EQU 64
SYS_MAX EQU 69
+13
View File
@@ -199,4 +199,17 @@ SYSCALL_STUB2 OpenNamedQueue, SYS_OPEN_NAMED_QUEUE ; (const char* name, ui
SYSCALL_STUB2 QueueDuplicate, SYS_QUEUE_DUPLICATE ; (uint32_t handle, uint32_t targetPid, uint32_t* handleOut) -> KSTATUS
SYSCALL_STUB2 NamedQueueOwnerPid, SYS_NAMED_QUEUE_OWNER_PID ; (const char* name, uint32_t* pidOut) -> KSTATUS
; ---------------------------------------------------------------------------
; Process utilities
; ---------------------------------------------------------------------------
SYSCALL_STUB2 KillProcess, SYS_KILL_PROCESS ; (uint32_t pid, int exitCode) -> KSTATUS
SYSCALL_STUB2 GetProcessList, SYS_GET_PROCESS_LIST ; (uint32_t* pidsOut, size_t maxCount, size_t* countOut) -> KSTATUS
; ---------------------------------------------------------------------------
; Filesystem mutations
; ---------------------------------------------------------------------------
SYSCALL_STUB2 RenameFile, SYS_RENAME_FILE ; (const char* oldPath, const char* newPath) -> KSTATUS
SYSCALL_STUB2 CreateDir, SYS_CREATE_DIR ; (const char* path) -> KSTATUS
SYSCALL_STUB2 RemoveDir, SYS_REMOVE_DIR ; (const char* path) -> KSTATUS
END
+77 -63
View File
@@ -4,88 +4,93 @@ Boots. Runs processes. Mimics Windows to some extent.
## what is it?
A 64-bit operating system kernel written from scratch.
UEFI bootloader, physical and virtual memory managers, preemptive scheduler, HAL, VFS, PE loader, partial Win32 layer.
It boots into a shell.
~20k lines of C and assembly.
NT-Lite is a 64-bit operating system kernel written from scratch. It includes a UEFI bootloader, physical and virtual memory managers, a preemptive scheduler, a HAL, a VFS, a PE loader, and partial Win32 and POSIX layers. It boots into a shell.
The codebase is roughly 20k lines of C and assembly.
## features
- UEFI bootloader
- physical memory manager
- virtual memory manager with kernel pool
- HAL (screen, keyboard, mouse, timer, disk, PCI, APIC)
- HAL for screen, keyboard, mouse, timer, disk, PCI, and APIC
- preemptive scheduler with priority levels
- processes and threads
- VFS with IRPs
- drive-letter paths (`0:\apps\shell.exe`)
- drive-letter paths such as `0:\apps\shell.exe`
- INI-based boot and driver configuration
- PE import resolution and dynamic driver loading
- Win32 personality (partial)
- POSIX personality (partial)
- partial Win32 personality
- partial POSIX personality
## how 2 build
## architecture notes
* open vs x64 build tools as admin
* cd into this directory
* `mkimage.bat`
* `build.bat`
* `run.bat`(ide)/`rund.bat`(ide, debug)/`runa.bat`(ahci)/`runad.bat`(ahci, debug)
* enjoy
### memory layout
## how it looks when built
NT-Lite uses a single virtual address space per booted system rather than a fully separate kernel address space and user address space. The distinction between kernel and user mode comes from page permissions and CPU privilege checks, not from having a different page table for the kernel.
I have some strong opinions on OS design.
The kernel is mapped into the higher half of virtual memory and user processes only receive the regions they are explicitly granted. Kernel pages are marked supervisor-only, so user-mode code cannot read or write them directly. User pages are mapped with user permissions and are isolated from one another by the kernel’s allocator, VMM, and process creation path.
```
efi/boot/
bootx64.efi
boot.ini
hal.dll
colonel.exe
drivers/
drivers.ini
ide.sys
ahci.sys
fat32.sys
syscall.dll
win32.dll
posix.dll
shell.exe
video.exe
```
### boot chain
## driver model
The bootloader reads configuration, loads the core images, maps the higher-half layout, and hands control to `KernelMain`. After that, the kernel takes over interrupt setup, paging, scheduler bring-up, runtime driver loading, and user process launch.
drivers are PE32+ `.sys` files with an entry point preferably named DriverEntry accepting a constant pointer to HAL_API.
### drivers
drivers to be loaded have their path stored in `drivers.ini`, split into essential for boot (loaded by bootloader) and not required for boot (loaded by kernel).
Drivers are PE32+ `.sys` files with a conventional `DriverEntry` export that accepts a pointer to `HAL_API`.
a disk driver fills in a `DISK_DRIVER` vtable and calls `IoRegisterDisk(index, &driver)`.
a filesystem driver fills in an `IO_FILESYSTEM` vtable and calls `IoRegisterFilesystem(index, &fs, &vol)`.
Drivers are split into two groups:
currently shipping: AHCI (interrupts), IDE (PIO/DMA) and FAT32.
- essential boot drivers, which are loaded before the kernel starts doing real work
- runtime drivers, which are loaded later from disk once storage and the VFS are available
The driver model is intentionally small. Disk drivers expose a `DISK_DRIVER` vtable and register with `IoRegisterDisk(index, &driver)`. Filesystem drivers expose an `IO_FILESYSTEM` vtable and register with `IoRegisterFilesystem(index, &fs, &vol)`.
Currently shipping: AHCI (interrupts), IDE (PIO/DMA), and FAT32.
### I/O and filesystems
All file access flows through the VFS layer. That keeps disk access, filesystem parsing, and path translation separate instead of spreading storage logic across the rest of the kernel.
Paths are not interpreted as Windows paths by default. A drive such as `0:\` is a mounted namespace, while the Win32 and POSIX personalities translate their own path styles into the same underlying VFS.
### processes, threads, and syscalls
User processes are launched from PE images, imports are resolved before the first thread is queued, and the syscall layer provides the boundary between user code and kernel services. `syscall.dll` is the shared entry point for the supported personalities.
The scheduler is preemptive and priority-based, so threads do not depend on cooperative yielding to keep the system responsive. Process state is tracked separately from thread state, which allows a process to exit, be reaped, or be restarted by `init` without bringing down the rest of the system.
### personalities
The Win32 personality supports programs that expect drive letters, familiar process APIs, and a Windows-style runtime. The POSIX personality maps the same kernel primitives into a tree-shaped namespace and a different userspace contract.
## how it boots
1. UEFI loads `boot.ini`, reads `drivers.ini`
2. bootloader maps kernel, HAL, and boot drivers into the upper half
3. direct physical window at `0xFFFF880000000000`
4. jumps to `KernelMain`
5. PMM, VMM, GDT, IDT, HAL, IRQs, scheduler
6. loads runtime drivers from disk
7. launches `shell.exe`
1. UEFI loads `boot.ini` and reads `drivers.ini`
2. the bootloader maps the kernel, HAL, and boot drivers into the upper half
3. a direct physical window is mapped at `0xFFFF880000000000`
4. control passes to `KernelMain`
5. PMM, VMM, GDT, IDT, HAL, IRQs, and scheduler initialization run
6. runtime drivers are loaded from disk
7. `shell.exe` is launched
## paths (because they're different)
## how to build
```
"apps\shell.exe" -> current working directory
"0:\apps\shell.exe" -> drive 0
"2:\data\config.ini" -> drive 2
- open the VS x64 build tools as administrator
- change into this directory
- run `mkimage.bat`
- run `build.bat`
- use one of `run.bat` (IDE), `rund.bat` (IDE, debug), `runa.bat` (AHCI), or `runad.bat` (AHCI, debug)
## paths
```text
"apps\shell.exe" -> current working directory
"0:\apps\shell.exe" -> drive 0
"2:\data\config.ini" -> drive 2
```
Drives 0-7. A drive only works if a filesystem registered on it.
The Win32 personality translates drive letters to drive numbers, the POSIX personality maps drives onto a tree.
Drives 0-7 are available. A drive only works if a filesystem is registered on it. The Win32 personality translates drive letters to drive numbers, while the POSIX personality maps drives onto a tree.
## screenshots
@@ -93,7 +98,7 @@ The Win32 personality translates drive letters to drive numbers, the POSIX perso
<details><summary>Boot logs</summary>
```
```text
BdsDxe: loading Boot0001 "UEFI QEMU HARDDISK QM00005 " from PciRoot(0x0)/Pci(0x4,0x0)/Sata(0x0,0xFFFF,0x0)
BdsDxe: starting Boot0001 "UEFI QEMU HARDDISK QM00005 " from PciRoot(0x0)/Pci(0x4,0x0)/Sata(0x0,0xFFFF,0x0)
1
@@ -204,7 +209,7 @@ W_Init: Init WADfiles.
Shareware!
===========================================================================
M_Init: Init miscellaneous info.
R_Init: Init DOOM refresh daemon - [.. ]
R_Init: Init Doom refresh daemon - [.. ]
InitTextures
InitFlats........
InitSprites
@@ -239,7 +244,7 @@ Available commands:
type <file> - Display file contents
del <file> - Delete a file
write <file> <txt> - Create a file with text
exit - Close the shell
exit - Close the shell
> dir
System Volume Information
drivers
@@ -289,14 +294,23 @@ A: `doom.exe`
Q: Is the Win32 layer real?
A: Real enough to load binaries that expect it. Not real enough to run Notepad.
Q: Is the scheduler preemptive?
A: As much as it will ever be.
Q: Will it corrupt my data?
A: It shouldn't.
Q: Are processes isolated?
A: No. But IPC is free.
Q: Is this finished?
A: Not in the slightest.
A: No.
Will it corrupt my data?
A: It shouldn't.
Q: Why is the path syntax so weird?
A: It makes sense to me.
Q: Why are the logs so verbose?
A: How else do I debug it?
Q: What should I read first?
A: This document.
Q: Can I use this in production?
A: Don't.