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:
1 parent
f80e66ecde
commit
ddb074f0e0
16 files changed
+476
-641
No files matched your search
Binary file not shown.
+29
-15
@@ -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);
|
||||
}
|
||||
@@ -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
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
@@ -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
@@ -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
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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.
|
||||
Reference in new issue
Block a user