add /IGNORE:4216 to HAL link step, add writing and directory listing to the FAT32 driver, add the concept of current working directory to the VFS, add writing to the VFS, more operations in the shell, rename KeCurrentThread to KeGetCurrentThread and add KeGetCurrentProcess, add STATUS_NO_MORE_FILES, change KeFault* to KePanic, add syscalls for writing to files, add a proper syscall to writing to the console, move Screen.Clear to after memory status debug print, add ObjectTypeDir to OBJECT_TYPE, extend kernel32 by file operations and upgrade user32 (and add gdi32) to match windows a bit more closely, change CreateProcessA to accept the first argument as NULL.
This commit is contained in:
1 parent
a5f0acfac8
commit
8c7564d5e1
33 files changed
+2343
-429
No files matched your search
+283
-16
@@ -1,6 +1,7 @@
|
||||
// io_file.c - VFS dispatch layer
|
||||
#include <string.h>
|
||||
#include <ke_list.h>
|
||||
#include <ke_process.h>
|
||||
#include <io_file.h>
|
||||
#include <mm_virt.h>
|
||||
#include <ob_object.h>
|
||||
@@ -14,6 +15,142 @@ typedef struct {
|
||||
|
||||
static VOLUME_ENTRY gVolumes[MAX_DRIVES];
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Current Working Directory (drive 0 relative, no trailing backslash)
|
||||
// e.g. "" = root, "apps" = root\apps, "apps\\data" = nested
|
||||
// ---------------------------------------------------------------------------
|
||||
#define CWD_MAX 512
|
||||
|
||||
__declspec(dllexport) KSTATUS IoGetCwd(char* buf, size_t size) {
|
||||
if (!buf || size == 0) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
PROCESS* proc = KeGetCurrentProcess();
|
||||
if (!proc) return STATUS_ACCESS_DENIED;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&proc->CwdLock);
|
||||
size_t cwdLen = strlen(proc->CurrentDirectory);
|
||||
if (cwdLen + 1 > size) {
|
||||
KeReleaseSpinlock(&proc->CwdLock, flags);
|
||||
return STATUS_BUFFER_TOO_SMALL;
|
||||
}
|
||||
memcpy(buf, proc->CurrentDirectory, cwdLen + 1);
|
||||
KeReleaseSpinlock(&proc->CwdLock, flags);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Resolve a possibly-relative path component against the CWD.
|
||||
// Writes the fully-resolved, drive-stripped relative path into 'resolved'
|
||||
// (caller supplies buf of at least CWD_MAX bytes).
|
||||
// Returns the drive index.
|
||||
static uint8_t ResolvePath(const char* path, char* resolved, size_t resolvedSize) {
|
||||
// Strip explicit drive prefix "N:\"
|
||||
uint8_t drive = 0;
|
||||
if (path[0] >= '0' && path[0] <= '7' &&
|
||||
path[1] == ':' && (path[2] == '\\' || path[2] == '/')) {
|
||||
drive = (uint8_t)(path[0] - '0');
|
||||
path = path + 3;
|
||||
}
|
||||
|
||||
char work[CWD_MAX * 2];
|
||||
work[0] = '\0';
|
||||
|
||||
// Initialize our working base
|
||||
if (path[0] == '\\' || path[0] == '/') {
|
||||
// Absolute path: start from the root (empty work buffer)
|
||||
// The segment loop below will automatically skip the leading separators.
|
||||
} else {
|
||||
// Relative path: start from the current process's CWD
|
||||
PROCESS* proc = KeGetCurrentProcess();
|
||||
if (proc) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&proc->CwdLock);
|
||||
size_t wlen = strlen(proc->CurrentDirectory);
|
||||
if (wlen >= sizeof(work)) wlen = sizeof(work) - 1;
|
||||
memcpy(work, proc->CurrentDirectory, wlen);
|
||||
work[wlen] = '\0';
|
||||
KeReleaseSpinlock(&proc->CwdLock, flags);
|
||||
}
|
||||
}
|
||||
|
||||
// Segment-by-segment canonicalization
|
||||
const char* p = path;
|
||||
while (*p) {
|
||||
// Skip separators
|
||||
while (*p == '\\' || *p == '/') p++;
|
||||
if (!*p) break;
|
||||
|
||||
// Read next component
|
||||
char comp[256];
|
||||
int clen = 0;
|
||||
while (*p && *p != '\\' && *p != '/' && clen < 255)
|
||||
comp[clen++] = *p++;
|
||||
comp[clen] = '\0';
|
||||
|
||||
if (clen == 0) continue;
|
||||
|
||||
if (strcmp(comp, ".") == 0) {
|
||||
// Stay in place
|
||||
} else if (strcmp(comp, "..") == 0) {
|
||||
// Remove last component from work
|
||||
int i = (int)strlen(work) - 1;
|
||||
while (i >= 0 && work[i] != '\\' && work[i] != '/') i--;
|
||||
if (i < 0) i = 0;
|
||||
work[i] = '\0';
|
||||
} else {
|
||||
// Append separator + component
|
||||
size_t wl = strlen(work);
|
||||
if (wl > 0 && work[wl-1] != '\\' && work[wl-1] != '/') {
|
||||
if (wl + 1 < sizeof(work)) { work[wl] = '\\'; work[wl+1] = '\0'; }
|
||||
}
|
||||
size_t wl2 = strlen(work);
|
||||
if (wl2 + clen + 1 < sizeof(work)) {
|
||||
memcpy(work + wl2, comp, clen);
|
||||
work[wl2 + clen] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Output the final canonicalized, drive-stripped path
|
||||
size_t finalLen = strlen(work);
|
||||
if (finalLen + 1 > resolvedSize) finalLen = resolvedSize - 1;
|
||||
memcpy(resolved, work, finalLen);
|
||||
resolved[finalLen] = '\0';
|
||||
|
||||
return drive;
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS IoSetCwd(const char* path) {
|
||||
if (!path) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
PROCESS* proc = KeGetCurrentProcess();
|
||||
if (!proc) return STATUS_ACCESS_DENIED;
|
||||
|
||||
// Resolve the new path (this also validates ".." navigation).
|
||||
// Note: ResolvePath already uses proc->CurrentDirectory internally!
|
||||
char resolved[CWD_MAX];
|
||||
uint8_t drive = ResolvePath(path, resolved, sizeof(resolved));
|
||||
|
||||
// Validate: try to open the directory to confirm it actually exists on disk
|
||||
IO_FILESYSTEM* fs = gVolumes[drive].Fs;
|
||||
if (!fs) return STATUS_NOT_FOUND;
|
||||
if (!fs->OpenDir) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
void* dirCtx = NULL;
|
||||
KSTATUS s = fs->OpenDir(fs, resolved, &dirCtx);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
fs->CloseDir(fs, dirCtx);
|
||||
|
||||
// Commit the new CWD to the process block
|
||||
size_t len = strlen(resolved);
|
||||
if (len + 1 > sizeof(proc->CurrentDirectory)) return STATUS_BUFFER_TOO_SMALL;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&proc->CwdLock);
|
||||
memcpy(proc->CurrentDirectory, resolved, len + 1);
|
||||
KeReleaseSpinlock(&proc->CwdLock, flags);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Registration
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -29,20 +166,6 @@ __declspec(dllexport) KSTATUS IoRegisterFilesystem(uint8_t volumeIndex,
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Path parsing - "0:\apps\shell.exe" or just "apps\shell.exe" (drive 0)
|
||||
// ---------------------------------------------------------------------------
|
||||
static uint8_t ParseDrive(const char* path, const char **pathOut) {
|
||||
// Accept "N:\..." prefix, otherwise default to drive 0.
|
||||
if (path[0] >= '0' && path[0] <= '7' &&
|
||||
path[1] == ':' && (path[2] == '\\' || path[2] == '/')) {
|
||||
*pathOut = path + 3;
|
||||
return (uint8_t)(path[0] - '0');
|
||||
}
|
||||
*pathOut = path;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Destructor
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -57,8 +180,8 @@ static void FileDestroy(OBJECT* obj) {
|
||||
__declspec(dllexport) KSTATUS IoOpenFile(const char* path, FILE_OBJECT **out) {
|
||||
if (!path || !out) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
const char* relPath;
|
||||
uint8_t drive = ParseDrive(path, &relPath);
|
||||
char relPath[CWD_MAX];
|
||||
uint8_t drive = ResolvePath(path, relPath, sizeof(relPath));
|
||||
|
||||
IO_FILESYSTEM* fs = gVolumes[drive].Fs;
|
||||
if (!fs) return STATUS_NOT_FOUND;
|
||||
@@ -97,6 +220,90 @@ __declspec(dllexport) KSTATUS IoReadFile(FILE_OBJECT* file, void* buf, size_t si
|
||||
return s;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// IoWriteFile - sequential write at current offset
|
||||
// ---------------------------------------------------------------------------
|
||||
__declspec(dllexport) KSTATUS IoWriteFile(FILE_OBJECT* file, const void* buf,
|
||||
size_t size, size_t* bytesWritten) {
|
||||
if (!file || !buf || !bytesWritten) return STATUS_INVALID_PARAMETER;
|
||||
if (!file->Fs->Write) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
size_t written = 0;
|
||||
KSTATUS s = file->Fs->Write(file->Fs, file->FileCtx,
|
||||
file->Offset, buf, size, &written);
|
||||
if (KSUCCESS(s)) {
|
||||
file->Offset += written;
|
||||
// Keep the cached size in sync if the file grew.
|
||||
if (file->Offset > file->Size)
|
||||
file->Size = file->Offset;
|
||||
}
|
||||
*bytesWritten = written;
|
||||
return s;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// IoCreateFile - create a new file and return it open for writing
|
||||
// ---------------------------------------------------------------------------
|
||||
__declspec(dllexport) KSTATUS IoCreateFile(const char* path, FILE_OBJECT** out) {
|
||||
if (!path || !out) 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->Create) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
void* fileCtx;
|
||||
KSTATUS s = fs->Create(fs, relPath, &fileCtx);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
FILE_OBJECT* f = (FILE_OBJECT*)ObAllocateObject(ObjectTypeFile,
|
||||
sizeof(FILE_OBJECT));
|
||||
if (!f) { fs->Close(fs, fileCtx); return STATUS_NO_MEMORY; }
|
||||
f->Header.Destroy = FileDestroy;
|
||||
f->Fs = fs;
|
||||
f->FileCtx = fileCtx;
|
||||
f->Size = 0;
|
||||
f->Offset = 0;
|
||||
|
||||
*out = f;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// IoDeleteFile - delete a file by path (does not require an open handle)
|
||||
// ---------------------------------------------------------------------------
|
||||
__declspec(dllexport) KSTATUS IoDeleteFile(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->Delete) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
return fs->Delete(fs, relPath);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// IoTruncateFile - resize the file; updates the cached Size on success
|
||||
// ---------------------------------------------------------------------------
|
||||
__declspec(dllexport) KSTATUS IoTruncateFile(FILE_OBJECT* file, uint64_t newSize) {
|
||||
if (!file) return STATUS_INVALID_PARAMETER;
|
||||
if (!file->Fs->Truncate) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
KSTATUS s = file->Fs->Truncate(file->Fs, file->FileCtx, newSize);
|
||||
if (KSUCCESS(s)) {
|
||||
file->Size = newSize;
|
||||
// Pull the file pointer back if it now sits past EOF.
|
||||
if (file->Offset > file->Size)
|
||||
file->Offset = file->Size;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
__declspec(dllexport) KSTATUS IoSeekFile(FILE_OBJECT* file, uint64_t offset) {
|
||||
if (!file) return STATUS_INVALID_PARAMETER;
|
||||
@@ -111,3 +318,63 @@ __declspec(dllexport) uint64_t IoGetFileSize(FILE_OBJECT* file) {
|
||||
__declspec(dllexport) void IoCloseFile(FILE_OBJECT* file) {
|
||||
if (file) ObDereferenceObject(&file->Header);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Directory enumeration
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
static void DirDestroy(OBJECT* obj) {
|
||||
DIR_OBJECT* d = (DIR_OBJECT*)obj; // Header is first member
|
||||
if (d->Fs && d->DirCtx) d->Fs->CloseDir(d->Fs, d->DirCtx);
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS IoOpenDir(const char* dirPath, DIR_OBJECT** out) {
|
||||
if (!out) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
// NULL or empty path means the CWD itself
|
||||
char relPath[CWD_MAX];
|
||||
uint8_t drive;
|
||||
|
||||
if (!dirPath || dirPath[0] == '\0') {
|
||||
PROCESS* proc = KeGetCurrentProcess();
|
||||
if (!proc) return STATUS_ACCESS_DENIED;
|
||||
|
||||
uintptr_t flags = KeAcquireSpinlock(&proc->CwdLock);
|
||||
memcpy(relPath, proc->CurrentDirectory, strlen(proc->CurrentDirectory) + 1);
|
||||
KeReleaseSpinlock(&proc->CwdLock, flags);
|
||||
|
||||
// Note: For now, this assumes drive 0. If you add multi-drive support
|
||||
// later, you should add a CurrentDrive field to the PROCESS struct.
|
||||
drive = 0;
|
||||
} else {
|
||||
drive = ResolvePath(dirPath, relPath, sizeof(relPath));
|
||||
}
|
||||
|
||||
IO_FILESYSTEM* fs = gVolumes[drive].Fs;
|
||||
if (!fs) return STATUS_NOT_FOUND;
|
||||
if (!fs->OpenDir) return STATUS_NOT_SUPPORTED;
|
||||
|
||||
void* dirCtx = NULL;
|
||||
KSTATUS s = fs->OpenDir(fs, relPath, &dirCtx);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
DIR_OBJECT* d = (DIR_OBJECT*)ObAllocateObject(ObjectTypeDir, sizeof(DIR_OBJECT));
|
||||
if (!d) { fs->CloseDir(fs, dirCtx); return STATUS_NO_MEMORY; }
|
||||
|
||||
d->Header.Destroy = DirDestroy;
|
||||
d->Fs = fs;
|
||||
d->DirCtx = dirCtx;
|
||||
|
||||
*out = d;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
__declspec(dllexport) KSTATUS IoReadDir(DIR_OBJECT* dir, KDIR_ENTRY* entryOut) {
|
||||
if (!dir || !entryOut) return STATUS_INVALID_PARAMETER;
|
||||
if (!dir->Fs->ReadDir) return STATUS_NOT_SUPPORTED;
|
||||
return dir->Fs->ReadDir(dir->Fs, dir->DirCtx, entryOut);
|
||||
}
|
||||
|
||||
__declspec(dllexport) void IoCloseDir(DIR_OBJECT* dir) {
|
||||
if (dir) ObDereferenceObject(&dir->Header);
|
||||
}
|
||||
@@ -7,6 +7,18 @@
|
||||
#include <ke_status.h>
|
||||
#include <ob_object.h>
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// KDIR_ENTRY - one directory entry returned by ReadDir / SYS_READ_DIR
|
||||
// Attribute flags match FAT32/Win32: ATTR_DIRECTORY=0x10, ATTR_ARCHIVE=0x20
|
||||
// ---------------------------------------------------------------------------
|
||||
#define KDIR_NAME_MAX 260
|
||||
|
||||
typedef struct KDIR_ENTRY {
|
||||
char Name[KDIR_NAME_MAX]; // null-terminated filename
|
||||
uint8_t Attr; // FAT attribute byte (0x10=dir, 0x20=file)
|
||||
uint32_t FileSize; // 0 for directories
|
||||
} KDIR_ENTRY;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Filesystem driver vtable - filled in by fat32.sys (or any future fs driver)
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -22,6 +34,21 @@ typedef struct IO_FILESYSTEM {
|
||||
uint64_t offset, void* buf,
|
||||
size_t size, size_t* bytesRead);
|
||||
|
||||
KSTATUS (*Write)(struct IO_FILESYSTEM* fs, void* fileCtx,
|
||||
uint64_t offset, const void* buf,
|
||||
size_t size, size_t* bytesWritten);
|
||||
|
||||
// Create a new file at 'path'; returns an open fileCtx on success.
|
||||
KSTATUS (*Create)(struct IO_FILESYSTEM* fs, const char* path,
|
||||
void** fileCtx);
|
||||
|
||||
// Delete the file at 'path'.
|
||||
KSTATUS (*Delete)(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);
|
||||
|
||||
// Return the file size in bytes.
|
||||
uint64_t (*GetSize)(struct IO_FILESYSTEM* fs, void* fileCtx);
|
||||
|
||||
@@ -30,6 +57,24 @@ typedef struct IO_FILESYSTEM {
|
||||
|
||||
// Optional driver-private data.
|
||||
void* DriverCtx;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Directory enumeration (optional - may be NULL if not supported)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
// Open a directory iterator for 'dirPath' (relative or drive-prefixed).
|
||||
// Returns an opaque per-iteration driver cookie in *dirCtx.
|
||||
KSTATUS (*OpenDir)(struct IO_FILESYSTEM* fs,
|
||||
const char* dirPath, void** dirCtx);
|
||||
|
||||
// Advance to the next entry.
|
||||
// Fills 'out' with name, attributes, and size.
|
||||
// Returns STATUS_NO_MORE_FILES when the directory is exhausted.
|
||||
KSTATUS (*ReadDir)(struct IO_FILESYSTEM* fs, void* dirCtx,
|
||||
struct KDIR_ENTRY* out);
|
||||
|
||||
// Release resources allocated by OpenDir.
|
||||
void (*CloseDir)(struct IO_FILESYSTEM* fs, void* dirCtx);
|
||||
} IO_FILESYSTEM;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -43,6 +88,15 @@ typedef struct FILE_OBJECT {
|
||||
uint64_t Offset; // current position for sequential reads
|
||||
} FILE_OBJECT;
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// DIR_OBJECT - kernel object for an open directory iterator
|
||||
// ---------------------------------------------------------------------------
|
||||
typedef struct DIR_OBJECT {
|
||||
OBJECT Header; // must be first
|
||||
IO_FILESYSTEM* Fs;
|
||||
void* DirCtx; // driver cookie (opaque iteration state)
|
||||
} DIR_OBJECT;
|
||||
|
||||
typedef struct IO_VOLUME_PARAMS {
|
||||
uint8_t DiskIndex; // which disk in HAL_DISK table
|
||||
uint64_t PartitionLba; // starting LBA of this partition
|
||||
@@ -61,6 +115,24 @@ __declspec(dllexport) KSTATUS IoRegisterFilesystem(uint8_t driveIndex, IO_FILESY
|
||||
__declspec(dllexport) KSTATUS IoOpenFile(const char* path, FILE_OBJECT **out);
|
||||
__declspec(dllexport) KSTATUS IoReadFile(FILE_OBJECT* file, void* buf,
|
||||
size_t size, size_t* bytesRead);
|
||||
__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 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);
|
||||
__declspec(dllexport) void IoCloseFile(FILE_OBJECT* file);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Directory enumeration API
|
||||
// ---------------------------------------------------------------------------
|
||||
__declspec(dllexport) KSTATUS IoOpenDir (const char* dirPath, DIR_OBJECT** out);
|
||||
__declspec(dllexport) KSTATUS IoReadDir (DIR_OBJECT* dir, KDIR_ENTRY* entryOut);
|
||||
__declspec(dllexport) void IoCloseDir(DIR_OBJECT* dir);
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Current Working Directory
|
||||
// ---------------------------------------------------------------------------
|
||||
__declspec(dllexport) KSTATUS IoSetCwd(const char* path);
|
||||
__declspec(dllexport) KSTATUS IoGetCwd(char* buf, size_t size);
|
||||
@@ -53,3 +53,12 @@ __declspec(dllexport) _Noreturn void KePanic(const char *fmt, ...) {
|
||||
// Halt it!
|
||||
while (true) __halt();
|
||||
}
|
||||
|
||||
// KePrintConsole - write user-visible console text in white-on-black.
|
||||
// Used by SYS_WRITE_CONSOLE so user programs get a distinct colour from
|
||||
// kernel debug output (green) and panic output (red).
|
||||
__declspec(dllexport) void KePrintConsole(const char* buf, size_t len) {
|
||||
if (!buf || !PrintChar) return;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
PrintChar(buf[i], 0xFFFFFF, 0x000000);
|
||||
}
|
||||
@@ -4,7 +4,8 @@
|
||||
#include <stdint.h>
|
||||
|
||||
void KeInitDebug(void (*PrintPtr)(char, uint32_t, uint32_t), int v);
|
||||
__declspec(dllexport) void DbgPrint(const char* fmt, ...);
|
||||
__declspec(dllexport) void DbgPrint(const char* fmt, ...);
|
||||
__declspec(dllexport) void KePrintConsole(const char* buf, size_t len);
|
||||
__declspec(dllexport) void KePanic(const char *fmt, ...);
|
||||
|
||||
#endif // KE_DEBUG_H
|
||||
@@ -55,7 +55,7 @@ __declspec(dllexport) void KeClearEvent(EVENT* event) {
|
||||
|
||||
__declspec(dllexport) KSTATUS KeWaitForEvent(EVENT* event) {
|
||||
if (!event) return STATUS_INVALID_PARAMETER;
|
||||
THREAD* self = KeCurrentThread();
|
||||
THREAD* self = KeGetCurrentThread();
|
||||
|
||||
while (true) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&event->Lock);
|
||||
|
||||
@@ -22,7 +22,7 @@ KSTATUS MutexCreate(MUTEX **out) {
|
||||
|
||||
KSTATUS KeAcquireMutex(MUTEX* mutex) {
|
||||
if (!mutex) return STATUS_INVALID_PARAMETER;
|
||||
THREAD* self = KeCurrentThread();
|
||||
THREAD* self = KeGetCurrentThread();
|
||||
|
||||
while (true) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&mutex->Lock);
|
||||
@@ -39,7 +39,7 @@ KSTATUS KeAcquireMutex(MUTEX* mutex) {
|
||||
|
||||
KSTATUS KeTryAcquireMutex(MUTEX* mutex) {
|
||||
if (!mutex) return STATUS_INVALID_PARAMETER;
|
||||
THREAD* self = KeCurrentThread();
|
||||
THREAD* self = KeGetCurrentThread();
|
||||
uintptr_t flags = KeAcquireSpinlock(&mutex->Lock);
|
||||
if (!mutex->Owner) {
|
||||
mutex->Owner = self;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <intrin.h>
|
||||
#include <ke_process.h>
|
||||
#include <ke_thread.h>
|
||||
#include <ke_sched.h>
|
||||
#include <ke_event.h>
|
||||
#include <mm_virt.h>
|
||||
#include <ob_object.h>
|
||||
@@ -27,6 +28,14 @@ LIST_ENTRY* KeGetProcessList(void) {
|
||||
return &gProcessList;
|
||||
}
|
||||
|
||||
PROCESS* KeGetCurrentProcess(void) {
|
||||
THREAD* currentThread = KeGetCurrentThread();
|
||||
if (currentThread) {
|
||||
return currentThread->Owner;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Destructor (called by ObDereferenceObject when RefCount hits zero)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -16,6 +16,9 @@ typedef struct PROCESS {
|
||||
uint32_t ProcessId;
|
||||
char Name[PROCESS_NAME_MAX]; /* UTF-8 */
|
||||
|
||||
char CurrentDirectory[512];
|
||||
SPINLOCK CwdLock;
|
||||
|
||||
/* Thread list. */
|
||||
LIST_ENTRY ThreadList; /* links THREAD.ProcessLink */
|
||||
uint32_t ThreadCount;
|
||||
@@ -23,7 +26,7 @@ typedef struct PROCESS {
|
||||
/* Handle table.
|
||||
Index 0 is always NULL (the invalid handle).
|
||||
Entries are OBJECT pointers, each holding a reference. */
|
||||
OBJECT* Handles[HANDLE_TABLE_SIZE];
|
||||
OBJECT* Handles[HANDLE_TABLE_SIZE];
|
||||
SPINLOCK HandleLock;
|
||||
|
||||
int ExitCode;
|
||||
@@ -46,3 +49,4 @@ OBJECT* KeLookupHandle(PROCESS* process, uint32_t handle);
|
||||
|
||||
/* Return the global process list head (kernel-internal). */
|
||||
LIST_ENTRY* KeGetProcessList(void);
|
||||
PROCESS* KeGetCurrentProcess(void);
|
||||
@@ -22,7 +22,7 @@ KSTATUS QueueCreate(QUEUE **out) {
|
||||
|
||||
KSTATUS KeSendMessage(QUEUE* queue, const QUEUE_MESSAGE* msg, bool blocking) {
|
||||
if (!queue || !msg) return STATUS_INVALID_PARAMETER;
|
||||
THREAD* self = KeCurrentThread();
|
||||
THREAD* self = KeGetCurrentThread();
|
||||
|
||||
while (true) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&queue->Lock);
|
||||
@@ -54,7 +54,7 @@ KSTATUS KeSendMessage(QUEUE* queue, const QUEUE_MESSAGE* msg, bool blocking) {
|
||||
|
||||
KSTATUS KeReceiveMessage(QUEUE* queue, QUEUE_MESSAGE* msg, bool blocking) {
|
||||
if (!queue || !msg) return STATUS_INVALID_PARAMETER;
|
||||
THREAD* self = KeCurrentThread();
|
||||
THREAD* self = KeGetCurrentThread();
|
||||
|
||||
while (true) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&queue->Lock);
|
||||
|
||||
@@ -17,8 +17,8 @@ static THREAD* gIdleThread;
|
||||
static THREAD* gOutgoingThread;
|
||||
static uint32_t gAgingCounter = 0;
|
||||
|
||||
THREAD* KeCurrentThread(void) { return gCurrentThread; }
|
||||
void KeSetCurrentThread(THREAD* t){ gCurrentThread = t; }
|
||||
THREAD* KeGetCurrentThread(void) { return gCurrentThread; }
|
||||
void KeSetCurrentThread(THREAD* t) { gCurrentThread = t; }
|
||||
|
||||
static void IdleLoop(void) {
|
||||
while (true) { __halt(); }
|
||||
@@ -60,7 +60,7 @@ void KeInitializeScheduler(void) {
|
||||
|
||||
// Safely release the lock and clean up any dead threads natively post-switch
|
||||
void KeSchedulerPostSwitch(void) {
|
||||
THREAD* cur = KeCurrentThread();
|
||||
THREAD* cur = KeGetCurrentThread();
|
||||
KeReleaseSpinlock(&gSchedLock, cur->SchedLockFlags);
|
||||
|
||||
if (gOutgoingThread && gOutgoingThread->State == ThreadDead) {
|
||||
|
||||
@@ -19,7 +19,7 @@ void KeSchedulerTick(void);
|
||||
__declspec(dllexport) void KeYield(void);
|
||||
|
||||
// Returns the thread currently running on this CPU (reads GS:[0]).
|
||||
THREAD* KeCurrentThread(void);
|
||||
THREAD* KeGetCurrentThread(void);
|
||||
|
||||
// Set the current-thread GS slot. Called once per CPU at boot.
|
||||
void KeSetCurrentThread(THREAD* thread);
|
||||
@@ -23,7 +23,7 @@ __declspec(dllexport) KSTATUS KeSemaphoreCreate(int32_t initial, int32_t max, SE
|
||||
|
||||
__declspec(dllexport) KSTATUS KeWaitSemaphore(SEMAPHORE* sem) {
|
||||
if (!sem) return STATUS_INVALID_PARAMETER;
|
||||
THREAD* self = KeCurrentThread();
|
||||
THREAD* self = KeGetCurrentThread();
|
||||
|
||||
while (true) {
|
||||
uintptr_t flags = KeAcquireSpinlock(&sem->Lock);
|
||||
|
||||
@@ -24,6 +24,7 @@ typedef uint32_t KSTATUS;
|
||||
#define STATUS_ACCESS_DENIED ((KSTATUS)0x0021)
|
||||
#define STATUS_NOT_FOUND ((KSTATUS)0x0022)
|
||||
#define STATUS_ALREADY_EXISTS ((KSTATUS)0x0023)
|
||||
#define STATUS_OBJECT_NAME_COLLISION ((KSTATUS)0x0024)
|
||||
|
||||
// --- State & Lifecycle (0x0030) ---
|
||||
#define STATUS_OBJECT_DEAD ((KSTATUS)0x0030)
|
||||
@@ -33,4 +34,6 @@ typedef uint32_t KSTATUS;
|
||||
// --- Hardware & External (0x0040) ---
|
||||
#define STATUS_DEVICE_ERROR ((KSTATUS)0x0040)
|
||||
|
||||
#define STATUS_NO_MORE_FILES ((KSTATUS)0x0050)
|
||||
|
||||
#define KSUCCESS(s) ((s) == STATUS_SUCCESS)
|
||||
@@ -76,7 +76,7 @@ KeSwitchContext ENDP
|
||||
; We load RCX from the stack (first arg per MS x64), then IRETQ.
|
||||
; -------------------------------------------------------------------------
|
||||
EXTERN KeSchedulerPostSwitch : PROC
|
||||
EXTERN KeCurrentThread : PROC
|
||||
EXTERN KeGetCurrentThread : PROC
|
||||
EXTERN KeExitThread : PROC
|
||||
|
||||
KeThreadEntry PROC
|
||||
@@ -115,7 +115,7 @@ KeKernelThreadEntry PROC
|
||||
|
||||
; Thread function returned -- exit cleanly.
|
||||
sub rsp, 32
|
||||
call KeCurrentThread ; rax = current THREAD*
|
||||
call KeGetCurrentThread ; rax = current THREAD*
|
||||
add rsp, 32
|
||||
mov rcx, rax ; arg1 = thread*
|
||||
xor edx, edx ; arg2 = exitCode 0
|
||||
|
||||
@@ -39,7 +39,7 @@ KeSyscallEntry ENDP
|
||||
; ---------------------------------------------------------------------------
|
||||
; Fault stubs - print a message and halt. A real kernel would do a bugcheck.
|
||||
; ---------------------------------------------------------------------------
|
||||
EXTERN DbgPrint:PROC
|
||||
EXTERN KePanic:PROC
|
||||
|
||||
FaultMsg DB "KERNEL FAULT: vector %d at RIP %016llx", 0Ah, 0
|
||||
|
||||
@@ -48,10 +48,7 @@ KeFaultDE PROC
|
||||
lea rcx, FaultMsg
|
||||
mov rdx, 0
|
||||
pop r8 ; RIP from the fault frame
|
||||
call DbgPrint
|
||||
add rsp, 28h
|
||||
@@: hlt
|
||||
jmp @B
|
||||
call KePanic
|
||||
KeFaultDE ENDP
|
||||
|
||||
KeFaultGP PROC
|
||||
@@ -60,10 +57,7 @@ KeFaultGP PROC
|
||||
mov rdx, 13
|
||||
pop rax ; error code
|
||||
pop r8 ; RIP
|
||||
call DbgPrint
|
||||
add rsp, 28h
|
||||
@@: hlt
|
||||
jmp @B
|
||||
call KePanic
|
||||
KeFaultGP ENDP
|
||||
|
||||
KeFaultPF PROC
|
||||
@@ -72,10 +66,7 @@ KeFaultPF PROC
|
||||
mov rdx, 14
|
||||
pop rax ; error code
|
||||
pop r8 ; RIP
|
||||
call DbgPrint
|
||||
add rsp, 28h
|
||||
@@: hlt
|
||||
jmp @B
|
||||
call KePanic
|
||||
KeFaultPF ENDP
|
||||
|
||||
EXTERN KeIrqDispatch:PROC
|
||||
|
||||
+185
-21
@@ -58,7 +58,7 @@ void KeSyscallSetHal(const HAL_API* hal) { gHal = hal; }
|
||||
// Helper: get the current process, or NULL if unavailable.
|
||||
// ---------------------------------------------------------------------------
|
||||
static inline PROCESS* CurrentProcess(void) {
|
||||
THREAD* t = KeCurrentThread();
|
||||
THREAD* t = KeGetCurrentThread();
|
||||
return t ? t->Owner : NULL;
|
||||
}
|
||||
|
||||
@@ -102,7 +102,7 @@ static KSTATUS AllocHandleForCurrent(OBJECT* obj, uint32_t* handleOut) {
|
||||
static uint64_t SyscallExitProcess(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;
|
||||
THREAD* t = KeCurrentThread();
|
||||
THREAD* t = KeGetCurrentThread();
|
||||
PROCESS* proc = t ? t->Owner : NULL;
|
||||
if (proc) KeExitProcess(proc, (int)a0);
|
||||
if (t) KeExitThread(t, (int)a0);
|
||||
@@ -115,7 +115,7 @@ static uint64_t SyscallExitProcess(uint64_t a0, uint64_t a1, uint64_t a2,
|
||||
static uint64_t SyscallExitThread(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;
|
||||
THREAD* t = KeCurrentThread();
|
||||
THREAD* t = KeGetCurrentThread();
|
||||
if (t) KeExitThread(t, (int)a0);
|
||||
while (true) ;
|
||||
}
|
||||
@@ -144,7 +144,7 @@ static uint64_t SyscallCreateThread(uint64_t a0, uint64_t a1, uint64_t a2,
|
||||
static uint64_t SyscallGetCurrentTid(uint64_t a0, uint64_t a1, uint64_t a2,
|
||||
uint64_t a3, uint64_t a4, uint64_t a5) {
|
||||
(void)a0; (void)a1; (void)a2; (void)a3; (void)a4; (void)a5;
|
||||
THREAD* t = KeCurrentThread();
|
||||
THREAD* t = KeGetCurrentThread();
|
||||
return t ? t->ThreadId : 0;
|
||||
}
|
||||
|
||||
@@ -188,7 +188,7 @@ static uint64_t SyscallSetThreadPriority(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;
|
||||
if (a0 >= PriorityCount) return STATUS_INVALID_PARAMETER;
|
||||
THREAD* t = KeCurrentThread();
|
||||
THREAD* t = KeGetCurrentThread();
|
||||
if (!t) return STATUS_FAILURE;
|
||||
t->Priority = (THREAD_PRIORITY)a0;
|
||||
return STATUS_SUCCESS;
|
||||
@@ -492,6 +492,78 @@ static uint64_t SyscallReadFile(uint64_t a0, uint64_t a1, uint64_t a2,
|
||||
return s;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SYS_WRITE_FILE (43) a0=handle a1=buf a2=size a3=*bytesWrittenOut
|
||||
// ---------------------------------------------------------------------------
|
||||
static uint64_t SyscallWriteFile(uint64_t a0, uint64_t a1, uint64_t a2,
|
||||
uint64_t a3, uint64_t a4, uint64_t a5) {
|
||||
(void)a4; (void)a5;
|
||||
if (!a1) return STATUS_INVALID_PARAMETER;
|
||||
FILE_OBJECT* file = (FILE_OBJECT*)HandleToObject((uint32_t)a0, ObjectTypeFile);
|
||||
if (!file) return STATUS_NOT_FOUND;
|
||||
size_t written = 0;
|
||||
KSTATUS s = IoWriteFile(file, (const void*)(uintptr_t)a1, (size_t)a2, &written);
|
||||
if (a3) *(size_t*)(uintptr_t)a3 = written;
|
||||
ObDereferenceObject(&file->Header);
|
||||
return s;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SYS_CREATE_FILE (44) a0=*path a1=*handleOut
|
||||
// ---------------------------------------------------------------------------
|
||||
static uint64_t SyscallCreateFile(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;
|
||||
if (!a0 || !a1) return STATUS_INVALID_PARAMETER;
|
||||
FILE_OBJECT* file = NULL;
|
||||
KSTATUS s = IoCreateFile((const char*)(uintptr_t)a0, &file);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
uint32_t h = 0;
|
||||
s = AllocHandleForCurrent(&file->Header, &h);
|
||||
if (!KSUCCESS(s)) {
|
||||
ObDereferenceObject(&file->Header);
|
||||
return s;
|
||||
}
|
||||
*(uint32_t*)(uintptr_t)a1 = h;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SYS_DELETE_FILE (45) a0=*path
|
||||
// ---------------------------------------------------------------------------
|
||||
static uint64_t SyscallDeleteFile(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;
|
||||
if (!a0) return STATUS_INVALID_PARAMETER;
|
||||
return IoDeleteFile((const char*)(uintptr_t)a0);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SYS_TRUNCATE_FILE (46) a0=handle a1=newSize
|
||||
// ---------------------------------------------------------------------------
|
||||
static uint64_t SyscallTruncateFile(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;
|
||||
FILE_OBJECT* file = (FILE_OBJECT*)HandleToObject((uint32_t)a0, ObjectTypeFile);
|
||||
if (!file) return STATUS_NOT_FOUND;
|
||||
KSTATUS s = IoTruncateFile(file, (uint64_t)a1);
|
||||
ObDereferenceObject(&file->Header);
|
||||
return s;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SYS_GET_FILE_POS (47) a0=handle -> current seek offset
|
||||
// ---------------------------------------------------------------------------
|
||||
static uint64_t SyscallGetFilePos(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;
|
||||
FILE_OBJECT* file = (FILE_OBJECT*)HandleToObject((uint32_t)a0, ObjectTypeFile);
|
||||
if (!file) return (uint64_t)-1;
|
||||
uint64_t pos = file->Offset;
|
||||
ObDereferenceObject(&file->Header);
|
||||
return pos;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SYS_SEEK_FILE (29) a0=handle a1=offset
|
||||
// ---------------------------------------------------------------------------
|
||||
@@ -704,6 +776,88 @@ static uint64_t SyscallGetProcessExitCode(uint64_t a0, uint64_t a1, uint64_t a2,
|
||||
return s;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SYS_WRITE_CONSOLE (48) a0=*buf a1=len
|
||||
// Writes user console text in white; distinct from green SYS_DEBUG_PRINT.
|
||||
// ---------------------------------------------------------------------------
|
||||
static uint64_t SyscallWriteConsole(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* buf = (const char*)(uintptr_t)a0;
|
||||
size_t len = (size_t)a1;
|
||||
if (buf && len) KePrintConsole(buf, len);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SYS_OPEN_DIR (49) a0=*dirPath a1=*handleOut
|
||||
// ---------------------------------------------------------------------------
|
||||
static uint64_t SyscallOpenDir(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* dirPath = (const char*)(uintptr_t)a0;
|
||||
uint32_t* handleOut = (uint32_t*)(uintptr_t)a1;
|
||||
|
||||
if (!handleOut) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
DIR_OBJECT* dir = NULL;
|
||||
KSTATUS s = IoOpenDir(dirPath, &dir);
|
||||
if (!KSUCCESS(s)) return s;
|
||||
|
||||
// Put the object in the handle table and get a valid index (1-255)
|
||||
s = KeAllocateHandle(KeGetCurrentProcess(), &dir->Header, handleOut);
|
||||
|
||||
// Drop the reference KeAllocateHandle took, so that when user space
|
||||
// calls CloseHandle, the refcount drops to 0 and the object is destroyed.
|
||||
ObDereferenceObject(&dir->Header);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SYS_READ_DIR (50) a0=handle a1=*KDIR_ENTRY
|
||||
// Returns STATUS_NO_MORE_FILES when the directory is exhausted.
|
||||
// ---------------------------------------------------------------------------
|
||||
static uint64_t SyscallReadDir(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;
|
||||
|
||||
// a0 = handle from user mode
|
||||
// a1 = KDIR_ENTRY* buffer
|
||||
|
||||
// Look up a DIR_OBJECT using ObjectTypeDir (not ObjectTypeFile)
|
||||
DIR_OBJECT* dir = (DIR_OBJECT*)HandleToObject((uint32_t)a0, ObjectTypeDir);
|
||||
if (!dir) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
KSTATUS s = IoReadDir(dir, (void*)(uintptr_t)a1);
|
||||
|
||||
ObDereferenceObject(&dir->Header); // Drop the ref taken by HandleToObject
|
||||
return s;
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SYS_SET_CWD (51) a0=*path
|
||||
// ---------------------------------------------------------------------------
|
||||
static uint64_t SyscallSetCwd(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 IoSetCwd(path);
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SYS_GET_CWD (52) a0=*buf a1=size
|
||||
// ---------------------------------------------------------------------------
|
||||
static uint64_t SyscallGetCwd(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;
|
||||
char* buf = (char*)(uintptr_t)a0;
|
||||
size_t size = (size_t)a1;
|
||||
if (!buf || size == 0) return STATUS_INVALID_PARAMETER;
|
||||
return IoGetCwd(buf, size);
|
||||
}
|
||||
|
||||
// ===========================================================================
|
||||
// Dispatch table - index must match SYS_* in syscall_nr.h exactly.
|
||||
// ===========================================================================
|
||||
@@ -738,22 +892,32 @@ static const SYSCALL_HANDLER gSyscallTable[SYS_MAX] = {
|
||||
/* 24 SYS_QUEUE_SEND */ SyscallQueueSend,
|
||||
/* 25 SYS_QUEUE_RECV */ SyscallQueueRecv,
|
||||
/* 26 SYS_CLOSE_HANDLE */ SyscallCloseHandle,
|
||||
/* 27 SYS_OPEN_FILE */ SyscallOpenFile,
|
||||
/* 28 SYS_READ_FILE */ SyscallReadFile,
|
||||
/* 29 SYS_SEEK_FILE */ SyscallSeekFile,
|
||||
/* 30 SYS_GET_FILE_SIZE */ SyscallGetFileSize,
|
||||
/* 31 SYS_SCREEN_BLIT */ SyscallScreenBlit,
|
||||
/* 32 SYS_SCREEN_CLEAR */ SyscallScreenClear,
|
||||
/* 33 SYS_SCREEN_GET_SIZE */ SyscallScreenGetSize,
|
||||
/* 34 SYS_SCREEN_PUT_CHAR */ SyscallScreenPutChar,
|
||||
/* 35 SYS_KB_POLL */ SyscallKbPoll,
|
||||
/* 36 SYS_KB_READ_CHAR */ SyscallKbReadChar,
|
||||
/* 37 SYS_KB_READ_SCANCODE */ SyscallKbReadScancode,
|
||||
/* 38 SYS_GET_TICK */ SyscallGetTick,
|
||||
/* 39 SYS_DEBUG_PRINT */ SyscallDebugPrint,
|
||||
/* 40 SYS_CREATE_PROCESS */ SyscallCreateProcess,
|
||||
/* 41 SYS_WAIT_FOR_PROCESS */ SyscallWaitForProcess,
|
||||
/* 42 SYS_GET_PROCESS_EXIT_CODE */ SyscallGetProcessExitCode,
|
||||
/* 27 SYS_OPEN_FILE */ SyscallOpenFile,
|
||||
/* 28 SYS_READ_FILE */ SyscallReadFile,
|
||||
/* 29 SYS_SEEK_FILE */ SyscallSeekFile,
|
||||
/* 30 SYS_GET_FILE_SIZE */ SyscallGetFileSize,
|
||||
/* 31 SYS_SCREEN_BLIT */ SyscallScreenBlit,
|
||||
/* 32 SYS_SCREEN_CLEAR */ SyscallScreenClear,
|
||||
/* 33 SYS_SCREEN_GET_SIZE */ SyscallScreenGetSize,
|
||||
/* 34 SYS_SCREEN_PUT_CHAR */ SyscallScreenPutChar,
|
||||
/* 35 SYS_KB_POLL */ SyscallKbPoll,
|
||||
/* 36 SYS_KB_READ_CHAR */ SyscallKbReadChar,
|
||||
/* 37 SYS_KB_READ_SCANCODE */ SyscallKbReadScancode,
|
||||
/* 38 SYS_GET_TICK */ SyscallGetTick,
|
||||
/* 39 SYS_DEBUG_PRINT */ SyscallDebugPrint,
|
||||
/* 40 SYS_CREATE_PROCESS */ SyscallCreateProcess,
|
||||
/* 41 SYS_WAIT_FOR_PROCESS */ SyscallWaitForProcess,
|
||||
/* 42 SYS_GET_PROCESS_EXIT_CODE */ SyscallGetProcessExitCode,
|
||||
/* 43 SYS_WRITE_FILE */ SyscallWriteFile,
|
||||
/* 44 SYS_CREATE_FILE */ SyscallCreateFile,
|
||||
/* 45 SYS_DELETE_FILE */ SyscallDeleteFile,
|
||||
/* 46 SYS_TRUNCATE_FILE */ SyscallTruncateFile,
|
||||
/* 47 SYS_GET_FILE_POS */ SyscallGetFilePos,
|
||||
/* 48 SYS_WRITE_CONSOLE */ SyscallWriteConsole,
|
||||
/* 49 SYS_OPEN_DIR */ SyscallOpenDir,
|
||||
/* 50 SYS_READ_DIR */ SyscallReadDir,
|
||||
/* 51 SYS_SET_CWD */ SyscallSetCwd,
|
||||
/* 52 SYS_GET_CWD */ SyscallGetCwd,
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
@@ -137,7 +137,7 @@ __declspec(dllexport) KSTATUS KeCreateKernelThread(uintptr_t fn, uintptr_t arg,
|
||||
THREAD_PRIORITY priority, THREAD **out) {
|
||||
// Kernel threads are owned by the idle process. We need a PROCESS* for
|
||||
// the owner field; grab it from the idle/init thread that already exists.
|
||||
THREAD* idleThread = KeCurrentThread(); // safe to call before scheduler starts
|
||||
THREAD* idleThread = KeGetCurrentThread(); // safe to call before scheduler starts
|
||||
PROCESS* owner = idleThread ? idleThread->Owner : (PROCESS*)0;
|
||||
if (!owner) return STATUS_INVALID_PARAMETER;
|
||||
if (priority >= PriorityCount) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
@@ -41,7 +41,7 @@ typedef struct THREAD {
|
||||
// Quanta consumed without blocking - used by the MLFQ for demotion.
|
||||
uint32_t QuantaConsumed;
|
||||
|
||||
struct PROCESS* Owner;
|
||||
PROCESS* Owner;
|
||||
LIST_ENTRY ProcessLink; /* node in Owner->ThreadList */
|
||||
LIST_ENTRY SchedulerLink; /* node in run queue or wait list */
|
||||
|
||||
|
||||
+2
-2
@@ -310,14 +310,14 @@ void SystemInitThread(void* arg) {
|
||||
// (e.g., win32.dll resolving its imports against syscall.dll)
|
||||
ResolveSystemImports(args->bootInfo);
|
||||
|
||||
args->hal->Screen.Clear(0x000000);
|
||||
|
||||
// Print memory status now that the system is fully alive
|
||||
DbgPrint("Memory Status:\n");
|
||||
DbgPrint(" -> Free (PMM): %.2f MB\n", (float)MmFreeFrameCount() * PAGE_SIZE / (1024.0f * 1024.0f));
|
||||
DbgPrint(" -> Kernel Pool: %.2f MB\n", (float)MmGetKernelPoolUsage() / (1024.0f * 1024.0f));
|
||||
DbgPrint(" -> User Heap: %.2f MB\n", (float)MmGetUserHeapUsage() / (1024.0f * 1024.0f));
|
||||
|
||||
args->hal->Screen.Clear(0x000000);
|
||||
|
||||
// Launch User-Mode Shell (this will trigger AHCI & FAT32 which CAN safely block now)
|
||||
PROCESS* shellProc = LaunchUserProcess(args->bootInfo->CommandLine);
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ typedef enum OBJECT_TYPE {
|
||||
ObjectTypeEvent = 5,
|
||||
ObjectTypeQueue = 6,
|
||||
ObjectTypeFile = 7,
|
||||
ObjectTypeDir = 8,
|
||||
} OBJECT_TYPE;
|
||||
|
||||
typedef struct OBJECT {
|
||||
|
||||
@@ -74,6 +74,11 @@
|
||||
#define SYS_READ_FILE 28 // (uint32_t handle, void* buf, size_t size, size_t* bytesReadOut) -> KSTATUS
|
||||
#define SYS_SEEK_FILE 29 // (uint32_t handle, uint64_t offset) -> KSTATUS
|
||||
#define SYS_GET_FILE_SIZE 30 // (uint32_t handle) -> uint64_t
|
||||
#define SYS_WRITE_FILE 43
|
||||
#define SYS_CREATE_FILE 44
|
||||
#define SYS_DELETE_FILE 45
|
||||
#define SYS_TRUNCATE_FILE 46
|
||||
#define SYS_GET_FILE_POS 47
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Screen / Graphics
|
||||
@@ -107,7 +112,25 @@
|
||||
#define SYS_WAIT_FOR_PROCESS 41 // (uint32_t handle) -> KSTATUS
|
||||
#define SYS_GET_PROCESS_EXIT_CODE 42 // (uint32_t handle, int* exitCodeOut) -> KSTATUS
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Console output (white text, distinct from green SYS_DEBUG_PRINT)
|
||||
// ---------------------------------------------------------------------------
|
||||
#define SYS_WRITE_CONSOLE 48 // (const char* buf, size_t len) -> void
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Directory enumeration
|
||||
// (Close the handle via SYS_CLOSE_HANDLE like any other object.)
|
||||
// ---------------------------------------------------------------------------
|
||||
#define SYS_OPEN_DIR 49 // (const char* dirPath, uint32_t* handleOut) -> KSTATUS
|
||||
#define SYS_READ_DIR 50 // (uint32_t handle, KDIR_ENTRY* entryOut) -> KSTATUS
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Current Working Directory
|
||||
// ---------------------------------------------------------------------------
|
||||
#define SYS_SET_CWD 51 // (const char* path) -> KSTATUS
|
||||
#define SYS_GET_CWD 52 // (char* buf, size_t size) -> KSTATUS
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Sentinel
|
||||
// ---------------------------------------------------------------------------
|
||||
#define SYS_MAX 43
|
||||
#define SYS_MAX 53
|
||||
Reference in new issue
Block a user