feat: split syscalls into files, change max process ceiling

This commit is contained in:
2026-02-22 17:23:35 +01:00
parent 99f231acd2
commit 114aa37ef8
23 changed files with 1181 additions and 872 deletions
+28
View File
@@ -0,0 +1,28 @@
#pragma once
#include <Sched/Scheduler.hpp>
namespace Zenith {
// Find the process that owns the I/O ring buffers for a redirected process.
// If proc owns buffers itself (spawned via spawn_redir), returns proc.
// If proc inherited redirection (spawned via spawn from a redirected parent),
// follows parentPid to find the buffer owner.
static Sched::Process* GetRedirTarget(Sched::Process* proc) {
if (!proc || !proc->redirected) return nullptr;
if (proc->outBuf) return proc; // owns buffers
return Sched::GetProcessByPid(proc->parentPid);
}
static void RingWrite(uint8_t* buf, uint32_t& head, uint32_t /*tail*/, uint32_t size, uint8_t byte) {
buf[head] = byte;
head = (head + 1) % size;
}
static int RingRead(uint8_t* buf, uint32_t& head, uint32_t& tail, uint32_t size, uint8_t* out, int maxLen) {
int count = 0;
while (tail != head && count < maxLen) {
out[count++] = buf[tail];
tail = (tail + 1) % size;
}
return count;
}
}
+152
View File
@@ -0,0 +1,152 @@
/*
* Device.hpp
* SYS_DEVLIST syscall
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <cstdint>
#include <Hal/Apic/ApicInit.hpp>
#include <Drivers/PS2/PS2Controller.hpp>
#include <Drivers/USB/Xhci.hpp>
#include <Drivers/Net/E1000.hpp>
#include <Drivers/Net/E1000E.hpp>
#include <Drivers/Graphics/IntelGPU.hpp>
#include <Pci/Pci.hpp>
#include "Syscall.hpp"
namespace Zenith {
static void dl_strcpy(char* dst, const char* src, int max) {
int i = 0;
for (; i < max - 1 && src[i]; i++) dst[i] = src[i];
dst[i] = '\0';
}
static int dl_append(char* dst, int pos, const char* src, int max) {
for (int i = 0; src[i] && pos < max - 1; i++) dst[pos++] = src[i];
dst[pos] = '\0';
return pos;
}
static int dl_append_hex(char* dst, int pos, unsigned val, int digits, int max) {
const char* hex = "0123456789abcdef";
char tmp[8];
for (int i = digits - 1; i >= 0; i--) { tmp[i] = hex[val & 0xF]; val >>= 4; }
for (int i = 0; i < digits && pos < max - 1; i++) dst[pos++] = tmp[i];
dst[pos] = '\0';
return pos;
}
static int dl_append_dec(char* dst, int pos, int val, int max) {
if (val == 0) { if (pos < max - 1) dst[pos++] = '0'; dst[pos] = '\0'; return pos; }
char tmp[12]; int i = 0;
while (val > 0) { tmp[i++] = '0' + (val % 10); val /= 10; }
while (i > 0 && pos < max - 1) dst[pos++] = tmp[--i];
dst[pos] = '\0';
return pos;
}
static int Sys_DevList(DevInfo* buf, int maxCount) {
if (buf == nullptr || maxCount <= 0) return 0;
int count = 0;
auto add = [&](uint8_t cat, const char* name, const char* detail) {
if (count >= maxCount) return;
buf[count].category = cat;
buf[count]._pad[0] = 0; buf[count]._pad[1] = 0; buf[count]._pad[2] = 0;
dl_strcpy(buf[count].name, name, 48);
dl_strcpy(buf[count].detail, detail, 48);
count++;
};
// CPU cores (category 0)
int cpuCount = Hal::GetDetectedCpuCount();
if (cpuCount > 0) {
char detail[48];
int p = 0;
p = dl_append(detail, p, "x86_64, ", 48);
p = dl_append_dec(detail, p, cpuCount, 48);
p = dl_append(detail, p, " core(s)", 48);
add(0, "Processor", detail);
}
// Interrupt controllers (category 1)
add(1, "Local APIC", "");
add(1, "I/O APIC", "");
// Timer (category 2)
add(2, "LAPIC Timer", "Local APIC periodic timer");
// PS/2 Input (category 3)
add(3, "PS/2 Keyboard", "IRQ 1");
if (Drivers::PS2::IsDualChannel()) {
add(3, "PS/2 Mouse", "IRQ 12");
}
// USB devices (category 4)
if (Drivers::USB::Xhci::IsInitialized()) {
for (uint8_t slot = 1; slot <= Drivers::USB::Xhci::MAX_SLOTS && count < maxCount; slot++) {
auto* dev = Drivers::USB::Xhci::GetDevice(slot);
if (!dev || !dev->Active) continue;
const char* devName = "USB Device";
if (dev->InterfaceClass == 3) {
if (dev->InterfaceProtocol == 1) devName = "USB HID Keyboard";
else if (dev->InterfaceProtocol == 2) devName = "USB HID Mouse";
else devName = "USB HID Device";
} else if (dev->InterfaceClass == 8) {
devName = "USB Mass Storage";
} else if (dev->InterfaceClass == 9) {
devName = "USB Hub";
}
char detail[48];
int p = 0;
p = dl_append(detail, p, "Port ", 48);
p = dl_append_dec(detail, p, dev->PortId, 48);
p = dl_append(detail, p, ", VID:", 48);
p = dl_append_hex(detail, p, dev->VendorId, 4, 48);
p = dl_append(detail, p, " PID:", 48);
p = dl_append_hex(detail, p, dev->ProductId, 4, 48);
add(4, devName, detail);
}
}
// Network (category 5)
if (Drivers::Net::E1000::IsInitialized()) {
add(5, "Intel E1000", "Gigabit Ethernet (82540EM)");
}
if (Drivers::Net::E1000E::IsInitialized()) {
add(5, "Intel E1000E", "Gigabit Ethernet (82574L)");
}
// Display (category 6)
if (Drivers::Graphics::IntelGPU::IsInitialized()) {
auto* gpu = Drivers::Graphics::IntelGPU::GetGpuInfo();
if (gpu) {
add(6, gpu->name, "Intel Integrated Graphics");
}
}
// PCI devices (category 7)
auto& pciDevs = Pci::GetDevices();
for (int i = 0; i < (int)pciDevs.size() && count < maxCount; i++) {
auto& d = pciDevs[i];
const char* className = Pci::GetClassName(d.ClassCode, d.SubClass);
char detail[48];
int p = 0;
p = dl_append_hex(detail, p, d.Bus, 2, 48);
p = dl_append(detail, p, ":", 48);
p = dl_append_hex(detail, p, d.Device, 2, 48);
p = dl_append(detail, p, ".", 48);
p = dl_append_dec(detail, p, d.Function, 48);
p = dl_append(detail, p, " ", 48);
p = dl_append_hex(detail, p, d.VendorId, 4, 48);
p = dl_append(detail, p, ":", 48);
p = dl_append_hex(detail, p, d.DeviceId, 4, 48);
add(7, className, detail);
}
return count;
}
};
+75
View File
@@ -0,0 +1,75 @@
/*
* Filesystem.hpp
* SYS_OPEN, SYS_READ, SYS_GETSIZE, SYS_CLOSE, SYS_READDIR,
* SYS_FWRITE, SYS_FCREATE syscalls
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <Fs/Vfs.hpp>
#include <Sched/Scheduler.hpp>
#include <Memory/PageFrameAllocator.hpp>
#include <Memory/HHDM.hpp>
#include <Memory/Paging.hpp>
#include <Libraries/Memory.hpp>
namespace Zenith {
static int Sys_Open(const char* path) {
return Fs::Vfs::VfsOpen(path);
}
static int Sys_Read(int handle, uint8_t* buffer, uint64_t offset, uint64_t size) {
return Fs::Vfs::VfsRead(handle, buffer, offset, size);
}
static uint64_t Sys_GetSize(int handle) {
return Fs::Vfs::VfsGetSize(handle);
}
static void Sys_Close(int handle) {
Fs::Vfs::VfsClose(handle);
}
static int Sys_ReadDir(const char* path, const char** outNames, int maxEntries) {
// Get entries from VFS into a kernel-local array
const char* kernelNames[64];
int max = maxEntries;
if (max > 64) max = 64;
int count = Fs::Vfs::VfsReadDir(path, kernelNames, max);
if (count <= 0) return count;
// Allocate a user-accessible page for string data via process heap
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return -1;
void* page = Memory::g_pfa->AllocateZeroed();
if (page == nullptr) return -1;
uint64_t physAddr = Memory::SubHHDM((uint64_t)page);
uint64_t userVa = proc->heapNext;
proc->heapNext += 0x1000;
Memory::VMM::Paging::MapUserIn(proc->pml4Phys, physAddr, userVa);
// Copy strings into the user page and write pointers to outNames
uint64_t offset = 0;
uint8_t* pageBuf = (uint8_t*)Memory::HHDM(physAddr);
int copied = 0;
for (int i = 0; i < count; i++) {
int len = Lib::strlen(kernelNames[i]) + 1;
if (offset + len > 0x1000) break;
memcpy(pageBuf + offset, kernelNames[i], len);
outNames[i] = (const char*)(userVa + offset);
offset += len;
copied++;
}
return copied;
}
static int Sys_FWrite(int handle, const uint8_t* data, uint64_t offset, uint64_t size) {
return Fs::Vfs::VfsWrite(handle, data, offset, size);
}
static int Sys_FCreate(const char* path) {
return Fs::Vfs::VfsCreate(path);
}
};
+86
View File
@@ -0,0 +1,86 @@
/*
* Graphics.hpp
* SYS_FBINFO, SYS_FBMAP, SYS_TERMSIZE, SYS_TERMSCALE syscalls
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <cstdint>
#include <Sched/Scheduler.hpp>
#include <Memory/Paging.hpp>
#include <Memory/HHDM.hpp>
#include <Graphics/Cursor.hpp>
#include <Terminal/Terminal.hpp>
#include "Syscall.hpp"
#include "Common.hpp"
#include "../Libraries/flanterm/src/flanterm.h"
namespace Zenith {
static void Sys_FbInfo(FbInfo* out) {
if (out == nullptr) return;
out->width = Graphics::Cursor::GetFramebufferWidth();
out->height = Graphics::Cursor::GetFramebufferHeight();
out->pitch = Graphics::Cursor::GetFramebufferPitch();
out->bpp = 32;
out->userAddr = 0;
}
static uint64_t Sys_FbMap() {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return 0;
uint32_t* fbBase = Graphics::Cursor::GetFramebufferBase();
if (fbBase == nullptr) return 0;
uint64_t fbPhys = Memory::SubHHDM((uint64_t)fbBase);
uint64_t fbSize = Graphics::Cursor::GetFramebufferHeight()
* Graphics::Cursor::GetFramebufferPitch();
uint64_t numPages = (fbSize + 0xFFF) / 0x1000;
Kt::KernelLogStream(Kt::INFO, "FbMap") << "fbPhys=" << kcp::hex << fbPhys
<< " size=" << kcp::dec << fbSize
<< " pages=" << numPages
<< " (" << Graphics::Cursor::GetFramebufferWidth()
<< "x" << Graphics::Cursor::GetFramebufferHeight()
<< " pitch=" << Graphics::Cursor::GetFramebufferPitch() << ")";
// Map at a fixed user VA
constexpr uint64_t userVa = 0x50000000ULL;
for (uint64_t i = 0; i < numPages; i++) {
Memory::VMM::Paging::MapUserInWC(
proc->pml4Phys,
fbPhys + i * 0x1000,
userVa + i * 0x1000
);
}
return userVa;
}
static uint64_t Sys_TermSize() {
// If the process is redirected to a GUI terminal, return those dimensions
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
auto* target = GetRedirTarget(proc);
if (target && target->termCols > 0 && target->termRows > 0) {
return ((uint64_t)target->termRows << 32) | ((uint64_t)target->termCols & 0xFFFFFFFF);
}
}
size_t cols = 0, rows = 0;
flanterm_get_dimensions(Kt::ctx, &cols, &rows);
return (rows << 32) | (cols & 0xFFFFFFFF);
}
static int64_t Sys_TermScale(uint64_t scale_x, uint64_t scale_y) {
if (scale_x == 0) {
return (int64_t)((Kt::GetFontScaleY() << 32) | (Kt::GetFontScaleX() & 0xFFFFFFFF));
}
Kt::Rescale((size_t)scale_x, (size_t)scale_y);
size_t cols = 0, rows = 0;
flanterm_get_dimensions(Kt::ctx, &cols, &rows);
return (int64_t)((rows << 32) | (cols & 0xFFFFFFFF));
}
};
+39
View File
@@ -0,0 +1,39 @@
/*
* Heap.hpp
* SYS_ALLOC, SYS_FREE syscalls
* Copyright (c) 2026 Daniel Hammer
*/
#include <cstdint>
#include <Sched/Scheduler.hpp>
#include <Memory/Paging.hpp>
#include <Memory/HHDM.hpp>
#include <Memory/PageFrameAllocator.hpp>
namespace Zenith {
static uint64_t Sys_Alloc(uint64_t size) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return 0;
// Round up to page boundary
size = (size + 0xFFF) & ~0xFFFULL;
if (size == 0) size = 0x1000;
uint64_t userVa = proc->heapNext;
uint64_t numPages = size / 0x1000;
for (uint64_t i = 0; i < numPages; i++) {
void* page = Memory::g_pfa->AllocateZeroed();
if (page == nullptr) return 0;
uint64_t physAddr = Memory::SubHHDM((uint64_t)page);
Memory::VMM::Paging::MapUserIn(proc->pml4Phys, physAddr, userVa + i * 0x1000);
}
proc->heapNext += size;
return userVa;
}
static void Sys_Free(uint64_t) {
// TODO No-op for now (pages leak)
}
};
+28
View File
@@ -0,0 +1,28 @@
/*
* Info.hpp
* SYS_GETINFO syscall
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <Sched/Scheduler.hpp>
#include "Syscall.hpp"
namespace Zenith {
static void Sys_GetInfo(SysInfo* outInfo) {
if (outInfo == nullptr) return;
// Copy strings into fixed-size arrays (user-accessible)
const char* name = "ZenithOS";
const char* ver = "0.1.0";
for (int i = 0; name[i]; i++) outInfo->osName[i] = name[i];
outInfo->osName[8] = '\0';
for (int i = 0; ver[i]; i++) outInfo->osVersion[i] = ver[i];
outInfo->osVersion[5] = '\0';
outInfo->apiVersion = 2;
outInfo->maxProcesses = Sched::MaxProcesses;
}
};
+74
View File
@@ -0,0 +1,74 @@
/*
* IoRedir.hpp
* SYS_SPAWN_REDIR, SYS_CHILDIO_READ, SYS_CHILDIO_WRITE,
* SYS_CHILDIO_WRITEKEY, SYS_CHILDIO_SETTERMSZ syscalls
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <Sched/Scheduler.hpp>
#include <Memory/PageFrameAllocator.hpp>
#include "Syscall.hpp"
#include "Common.hpp"
namespace Zenith {
static int Sys_SpawnRedir(const char* path, const char* args) {
int childPid = Sched::Spawn(path, args);
if (childPid < 0) return -1;
auto* child = Sched::GetProcessByPid(childPid);
if (child == nullptr) return -1;
// Allocate ring buffers
void* outPage = Memory::g_pfa->AllocateZeroed();
void* inPage = Memory::g_pfa->AllocateZeroed();
if (!outPage || !inPage) return -1;
child->outBuf = (uint8_t*)outPage;
child->inBuf = (uint8_t*)inPage;
child->outHead = 0;
child->outTail = 0;
child->inHead = 0;
child->inTail = 0;
child->keyHead = 0;
child->keyTail = 0;
child->redirected = true;
child->parentPid = Sched::GetCurrentPid();
return childPid;
}
static int Sys_ChildIoRead(int childPid, char* buf, int maxLen) {
auto* child = Sched::GetProcessByPid(childPid);
if (child == nullptr || !child->redirected || !child->outBuf) return -1;
return RingRead(child->outBuf, child->outHead, child->outTail, Sched::Process::IoBufSize, (uint8_t*)buf, maxLen);
}
static int Sys_ChildIoWrite(int childPid, const char* data, int len) {
auto* child = Sched::GetProcessByPid(childPid);
if (child == nullptr || !child->redirected || !child->inBuf) return -1;
for (int i = 0; i < len; i++) {
RingWrite(child->inBuf, child->inHead, child->inTail, Sched::Process::IoBufSize, (uint8_t)data[i]);
}
return len;
}
static int Sys_ChildIoWriteKey(int childPid, const KeyEvent* key) {
if (key == nullptr) return -1;
auto* child = Sched::GetProcessByPid(childPid);
if (child == nullptr || !child->redirected) return -1;
child->keyBuf[child->keyHead] = *key;
child->keyHead = (child->keyHead + 1) % 64;
return 0;
}
static int Sys_ChildIoSetTermsz(int childPid, int cols, int rows) {
auto* child = Sched::GetProcessByPid(childPid);
if (child == nullptr || !child->redirected) return -1;
child->termCols = cols;
child->termRows = rows;
return 0;
}
};
+63
View File
@@ -0,0 +1,63 @@
/*
* Keyboard.hpp
* SYS_ISKEYAVAILABLE, SYS_GETKEY, SYS_GETCHAR syscalls
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <Sched/Scheduler.hpp>
#include <Drivers/PS2/Keyboard.hpp>
#include "Common.hpp"
namespace Zenith {
static bool Sys_IsKeyAvailable() {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
auto* target = GetRedirTarget(proc);
if (target) return target->keyHead != target->keyTail;
}
return Drivers::PS2::Keyboard::IsKeyAvailable();
}
static void Sys_GetKey(KeyEvent* outEvent) {
if (outEvent == nullptr) return;
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
auto* target = GetRedirTarget(proc);
if (target) {
// Wait for key in target's keyBuf ring
while (target->keyHead == target->keyTail) {
Sched::Schedule();
}
*outEvent = target->keyBuf[target->keyTail];
target->keyTail = (target->keyTail + 1) % 64;
return;
}
}
auto k = Drivers::PS2::Keyboard::GetKey();
outEvent->scancode = k.Scancode;
outEvent->ascii = k.Ascii;
outEvent->pressed = k.Pressed;
outEvent->shift = k.Shift;
outEvent->ctrl = k.Ctrl;
outEvent->alt = k.Alt;
}
static char Sys_GetChar() {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
auto* target = GetRedirTarget(proc);
if (target && target->inBuf) {
// Wait for data in target's inBuf ring
while (target->inTail == target->inHead) {
Sched::Schedule(); // yield until parent writes
}
uint8_t c = target->inBuf[target->inTail];
target->inTail = (target->inTail + 1) % Sched::Process::IoBufSize;
return (char)c;
}
}
return Drivers::PS2::Keyboard::GetChar();
}
};
+18
View File
@@ -0,0 +1,18 @@
/*
* MemInfo.hpp
* SYS_MEMSTATS syscall
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <Memory/PageFrameAllocator.hpp>
#include "Syscall.hpp"
namespace Zenith {
static void Sys_MemStats(MemStats* out) {
if (out == nullptr) return;
Memory::g_pfa->GetStats(out);
}
};
+26
View File
@@ -0,0 +1,26 @@
/*
* Mouse.hpp
* SYS_MOUSESTATE, SYS_SETMOUSEBOUNDS syscalls
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <Drivers/PS2/Mouse.hpp>
#include "Syscall.hpp"
namespace Zenith {
static void Sys_MouseState(MouseState* out) {
if (out == nullptr) return;
auto state = Drivers::PS2::Mouse::GetMouseState();
out->x = state.X;
out->y = state.Y;
out->scrollDelta = state.ScrollDelta;
out->buttons = state.Buttons;
}
static void Sys_SetMouseBounds(int32_t maxX, int32_t maxY) {
Drivers::PS2::Mouse::SetBounds(maxX, maxY);
}
};
+125
View File
@@ -0,0 +1,125 @@
/*
* Net.hpp
* Networking syscalls: SYS_PING, SYS_SOCKET, SYS_CONNECT, SYS_BIND,
* SYS_LISTEN, SYS_ACCEPT, SYS_SEND, SYS_RECV, SYS_CLOSESOCK,
* SYS_SENDTO, SYS_RECVFROM, SYS_GETNETCFG, SYS_SETNETCFG, SYS_RESOLVE
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <cstdint>
#include <Sched/Scheduler.hpp>
#include <Timekeeping/ApicTimer.hpp>
#include <Net/Icmp.hpp>
#include <Net/Dns.hpp>
#include <Net/Socket.hpp>
#include <Net/NetConfig.hpp>
#include <Drivers/Net/E1000.hpp>
#include <Drivers/Net/E1000E.hpp>
#include "Syscall.hpp"
namespace Zenith {
static uint16_t g_pingSeq = 0;
static constexpr uint16_t PING_ID = 0x2E01; // "ZE"
static int32_t Sys_Ping(uint32_t ipAddr, uint32_t timeoutMs) {
uint16_t seq = g_pingSeq++;
Net::Icmp::ResetReply();
Net::Icmp::SendEchoRequest(ipAddr, PING_ID, seq);
uint64_t start = Timekeeping::GetMilliseconds();
while (!Net::Icmp::HasReply(PING_ID, seq)) {
if (Timekeeping::GetMilliseconds() - start >= timeoutMs) {
return -1;
}
Sched::Schedule();
}
return (int32_t)(Timekeeping::GetMilliseconds() - start);
}
// ---- Socket syscalls ----
static int Sys_Socket(int type) {
return Net::Socket::Create(type, Sched::GetCurrentPid());
}
static int Sys_Connect(int fd, uint32_t ip, uint16_t port) {
return Net::Socket::Connect(fd, ip, port, Sched::GetCurrentPid());
}
static int Sys_Bind(int fd, uint16_t port) {
return Net::Socket::Bind(fd, port, Sched::GetCurrentPid());
}
static int Sys_Listen(int fd) {
return Net::Socket::Listen(fd, Sched::GetCurrentPid());
}
static int Sys_Accept(int fd) {
return Net::Socket::Accept(fd, Sched::GetCurrentPid());
}
static int Sys_Send(int fd, const uint8_t* data, uint32_t len) {
return Net::Socket::Send(fd, data, len, Sched::GetCurrentPid());
}
static int Sys_Recv(int fd, uint8_t* buf, uint32_t maxLen) {
return Net::Socket::Recv(fd, buf, maxLen, Sched::GetCurrentPid());
}
static void Sys_CloseSock(int fd) {
Net::Socket::Close(fd, Sched::GetCurrentPid());
}
static int Sys_SendTo(int fd, const uint8_t* data, uint32_t len,
uint32_t destIp, uint16_t destPort) {
return Net::Socket::SendTo(fd, data, len, destIp, destPort, Sched::GetCurrentPid());
}
static int Sys_RecvFrom(int fd, uint8_t* buf, uint32_t maxLen,
uint32_t* srcIp, uint16_t* srcPort) {
return Net::Socket::RecvFrom(fd, buf, maxLen, srcIp, srcPort, Sched::GetCurrentPid());
}
static void Sys_GetNetCfg(NetCfg* out) {
if (out == nullptr) return;
out->ipAddress = Net::GetIpAddress();
out->subnetMask = Net::GetSubnetMask();
out->gateway = Net::GetGateway();
const uint8_t* mac = nullptr;
if (Drivers::Net::E1000::IsInitialized()) {
mac = Drivers::Net::E1000::GetMacAddress();
} else if (Drivers::Net::E1000E::IsInitialized()) {
mac = Drivers::Net::E1000E::GetMacAddress();
}
if (mac) {
for (int i = 0; i < 6; i++) out->macAddress[i] = mac[i];
} else {
for (int i = 0; i < 6; i++) out->macAddress[i] = 0;
}
out->_pad[0] = 0;
out->_pad[1] = 0;
out->dnsServer = Net::GetDnsServer();
}
static int Sys_SetNetCfg(const NetCfg* in) {
if (in == nullptr) return -1;
Net::SetIpAddress(in->ipAddress);
Net::SetSubnetMask(in->subnetMask);
Net::SetGateway(in->gateway);
Net::SetDnsServer(in->dnsServer);
return 0;
}
// ---- DNS resolve ----
static int64_t Sys_Resolve(const char* hostname) {
uint32_t ip = Net::Dns::Resolve(hostname);
return (int64_t)ip;
}
};
+28
View File
@@ -0,0 +1,28 @@
/*
* Power.hpp
* SYS_RESET, SYS_SHUTDOWN syscalls
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <cstdint>
namespace Zenith {
static void Sys_Reset() {
/*
Triple fault for now; TODO: implement UEFI runtime function for clean reboot.
We implement the triple fault by loading a null IDT into the IDT register,
and then immediately triggering an interrupt.
This technique should pretty much work across the board but it's of course
better to use the UEFI runtime API as it has a method for this purpose,
along with shutdown.
*/
struct [[gnu::packed]] { uint16_t limit; uint64_t base; } nullIdt = {0, 0};
asm volatile("lidt %0; int $0x03" :: "m"(nullIdt));
__builtin_unreachable();
}
};
+114
View File
@@ -0,0 +1,114 @@
/*
* Process.hpp
* SYS_EXIT, SYS_YIELD, SYS_SLEEP_MS, SYS_GETPID,
* SYS_WAITPID, SYS_SPAWN, SYS_GETARGS, SYS_PROCLIST, SYS_KILL syscalls
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <Sched/Scheduler.hpp>
#include <Timekeeping/ApicTimer.hpp>
#include "Syscall.hpp"
#include "WinServer.hpp"
namespace Zenith {
static void Sys_Exit(int exitCode) {
(void)exitCode;
Sched::ExitProcess();
}
static void Sys_Yield() {
Sched::Schedule();
}
static void Sys_SleepMs(uint64_t ms) {
Timekeeping::Sleep(ms);
}
static int Sys_GetPid() {
return Sched::GetCurrentPid();
}
static void Sys_WaitPid(int pid) {
while (Sched::IsAlive(pid)) {
Sched::Schedule(); // yield until the process exits
}
}
static int Sys_Spawn(const char* path, const char* args) {
auto* parent = Sched::GetCurrentProcessPtr();
int childPid = Sched::Spawn(path, args);
if (childPid < 0) return childPid;
// Inherit I/O redirection: if the parent is redirected, the child
// is marked redirected too. It stores a parentPid pointing to the
// process that owns the actual ring buffers (the one spawned via
// spawn_redir). The child does NOT get its own buffers — Sys_Print
// et al. look up the buffer owner at write time.
if (parent && parent->redirected) {
auto* child = Sched::GetProcessByPid(childPid);
if (child) {
child->redirected = true;
// Point to the buffer owner: if parent owns buffers, target parent;
// if parent itself inherited, follow the chain.
child->parentPid = parent->outBuf ? parent->pid : parent->parentPid;
}
}
return childPid;
}
static int Sys_GetArgs(char* buf, uint64_t maxLen) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr || buf == nullptr || maxLen == 0) return -1;
int i = 0;
for (; i < (int)maxLen - 1 && proc->args[i]; i++) {
buf[i] = proc->args[i];
}
buf[i] = '\0';
return i;
}
static int Sys_ProcList(ProcInfo* buf, int maxCount) {
if (buf == nullptr || maxCount <= 0) return 0;
int count = 0;
for (int i = 0; i < Sched::MaxProcesses && count < maxCount; i++) {
auto* proc = Sched::GetProcessSlot(i);
if (!proc || proc->state == Sched::ProcessState::Free) continue;
buf[count].pid = (int32_t)proc->pid;
buf[count].parentPid = (int32_t)proc->parentPid;
buf[count].state = (uint8_t)proc->state;
buf[count]._pad[0] = 0;
buf[count]._pad[1] = 0;
buf[count]._pad[2] = 0;
{
int j = 0;
for (; j < 63 && proc->name[j]; j++)
buf[count].name[j] = proc->name[j];
buf[count].name[j] = '\0';
}
buf[count].heapUsed = (proc->heapNext > Sched::UserHeapBase)
? proc->heapNext - Sched::UserHeapBase : 0;
count++;
}
return count;
}
static int Sys_Kill(int pid) {
// Refuse to kill PID 0 (init)
if (pid == 0) return -1;
// Refuse to kill the caller's own process
if (pid == Sched::GetCurrentPid()) return -1;
auto* proc = Sched::GetProcessByPid(pid);
if (!proc) return -1;
// Clean up any windows owned by this process
WinServer::CleanupProcess(pid);
proc->state = Sched::ProcessState::Terminated;
return 0;
}
};
+39
View File
@@ -0,0 +1,39 @@
/*
* Random.hpp
* SYS_GETRANDOM syscall
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <cstdint>
namespace Zenith {
// ---- Random number generation ----
// Uses RDTSC mixed with xorshift64* PRNG for entropy.
// RDRAND is intentionally avoided: some firmware disables the RDRAND
// hardware unit while CPUID still advertises support (bit 30 of ECX),
// causing #UD on real hardware. RDTSC-based entropy is sufficient for
// seeding BearSSL's PRNG for TLS session keys.
static int64_t Sys_GetRandom(uint8_t* buf, uint64_t len) {
uint64_t tsc;
asm volatile("rdtsc; shl $32, %%rdx; or %%rdx, %%rax" : "=a"(tsc) :: "rdx");
uint64_t state = tsc;
for (uint64_t i = 0; i < len; i += 8) {
asm volatile("rdtsc; shl $32, %%rdx; or %%rdx, %%rax" : "=a"(tsc) :: "rdx");
state ^= tsc;
state ^= state >> 12;
state ^= state << 25;
state ^= state >> 27;
uint64_t val = state * 0x2545F4914F6CDD1DULL;
uint64_t remaining = len - i;
uint64_t toCopy = remaining < 8 ? remaining : 8;
for (uint64_t j = 0; j < toCopy; j++)
buf[i + j] = (uint8_t)(val >> (j * 8));
}
return (int64_t)len;
}
};
+21 -845
View File
@@ -5,860 +5,36 @@
*/
#include "Syscall.hpp"
#include <Timekeeping/Time.hpp>
#include <Terminal/Terminal.hpp>
#include <Fs/Vfs.hpp>
#include <Memory/Heap.hpp>
#include <Memory/PageFrameAllocator.hpp>
#include <Memory/Paging.hpp>
#include <Memory/HHDM.hpp>
#include <Timekeeping/ApicTimer.hpp>
#include <Sched/Scheduler.hpp>
#include <Libraries/Memory.hpp>
#include <Libraries/String.hpp>
#include <Drivers/PS2/Keyboard.hpp>
#include <Drivers/PS2/Mouse.hpp>
#include <Net/Icmp.hpp>
#include <Net/Dns.hpp>
#include <Net/Socket.hpp>
#include <Net/ByteOrder.hpp>
#include <Net/NetConfig.hpp>
#include <Drivers/Net/E1000.hpp>
#include <Drivers/Net/E1000E.hpp>
#include <Hal/MSR.hpp>
#include <Hal/GDT.hpp>
#include <Graphics/Cursor.hpp>
#include "../Libraries/flanterm/src/flanterm.h"
#include "WinServer.hpp"
#include <Pci/Pci.hpp>
#include <Drivers/USB/Xhci.hpp>
#include <Drivers/Graphics/IntelGPU.hpp>
#include <Drivers/PS2/PS2Controller.hpp>
#include <Hal/Apic/ApicInit.hpp>
/* For common functions used by multiple syscall implementations*/
#include "Common.hpp"
/* Syscall impl. includes */
#include "Process.hpp" // SYS_EXIT, SYS_YIELD, SYS_SLEEP_MS, SYS_GETPID, SYS_WAITPID, SYS_SPAWN, SYS_GETARGS, SYS_PROCLIST, SYS_KILL
#include "Terminal.hpp" // SYS_PRINT, SYS_PUTCHAR
#include "Filesystem.hpp" // SYS_OPEN, SYS_READ, SYS_GETSIZE, SYS_CLOSE, SYS_READDIR, SYS_FWRITE, SYS_FCREATE
#include "Heap.hpp" // SYS_ALLOC, SYS_FREE
#include "Time.hpp" // SYS_GETTICKS, SYS_GETMILLISECONDS, SYS_GETTIME
#include "Keyboard.hpp" // SYS_ISKEYAVAILABLE, SYS_GETKEY, SYS_GETCHAR
#include "Info.hpp" // SYS_GETINFO
#include "Graphics.hpp" // SYS_FBINFO, SYS_FBMAP, SYS_TERMSIZE, SYS_TERMSCALE
#include "Net.hpp" // SYS_PING, SYS_SOCKET, SYS_CONNECT, SYS_BIND, SYS_LISTEN, SYS_ACCEPT, SYS_SEND, SYS_RECV, SYS_CLOSESOCK, SYS_SENDTO, SYS_RECVFROM, SYS_GETNETCFG, SYS_SETNETCFG, SYS_RESOLVE
#include "Power.hpp" // SYS_RESET, SYS_SHUTDOWN
#include "Mouse.hpp" // SYS_MOUSESTATE, SYS_SETMOUSEBOUNDS
#include "IoRedir.hpp" // SYS_SPAWN_REDIR, SYS_CHILDIO_READ, SYS_CHILDIO_WRITE, SYS_CHILDIO_WRITEKEY, SYS_CHILDIO_SETTERMSZ
#include "Random.hpp" // SYS_GETRANDOM
#include "MemInfo.hpp" // SYS_MEMSTATS
#include "Device.hpp" // SYS_DEVLIST
#include "Window.hpp" // SYS_WINCREATE, SYS_WINDESTROY, SYS_WINPRESENT, SYS_WINPOLL, SYS_WINENUM, SYS_WINMAP, SYS_WINSENDEVENT, SYS_WINRESIZE, SYS_WINSETSCALE, SYS_WINGETSCALE
// Assembly entry point
extern "C" void SyscallEntry();
namespace Zenith {
// ---- Syscall implementations ----
static void Sys_Exit(int exitCode) {
(void)exitCode;
Sched::ExitProcess();
}
static void Sys_Yield() {
Sched::Schedule();
}
static void Sys_SleepMs(uint64_t ms) {
Timekeeping::Sleep(ms);
}
static int Sys_GetPid() {
return Sched::GetCurrentPid();
}
static void RingWrite(uint8_t* buf, uint32_t& head, uint32_t /*tail*/, uint32_t size, uint8_t byte) {
buf[head] = byte;
head = (head + 1) % size;
}
static int RingRead(uint8_t* buf, uint32_t& head, uint32_t& tail, uint32_t size, uint8_t* out, int maxLen) {
int count = 0;
while (tail != head && count < maxLen) {
out[count++] = buf[tail];
tail = (tail + 1) % size;
}
return count;
}
// Find the process that owns the I/O ring buffers for a redirected process.
// If proc owns buffers itself (spawned via spawn_redir), returns proc.
// If proc inherited redirection (spawned via spawn from a redirected parent),
// follows parentPid to find the buffer owner.
static Sched::Process* GetRedirTarget(Sched::Process* proc) {
if (!proc || !proc->redirected) return nullptr;
if (proc->outBuf) return proc; // owns buffers
return Sched::GetProcessByPid(proc->parentPid);
}
static void Sys_Print(const char* text) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
auto* target = GetRedirTarget(proc);
if (target && target->outBuf) {
for (int i = 0; text[i]; i++) {
RingWrite(target->outBuf, target->outHead, target->outTail, Sched::Process::IoBufSize, (uint8_t)text[i]);
}
return;
}
}
Kt::Print(text);
}
static void Sys_Putchar(char c) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
auto* target = GetRedirTarget(proc);
if (target && target->outBuf) {
RingWrite(target->outBuf, target->outHead, target->outTail, Sched::Process::IoBufSize, (uint8_t)c);
return;
}
}
Kt::Putchar(c);
}
static int Sys_Open(const char* path) {
return Fs::Vfs::VfsOpen(path);
}
static int Sys_Read(int handle, uint8_t* buffer, uint64_t offset, uint64_t size) {
return Fs::Vfs::VfsRead(handle, buffer, offset, size);
}
static uint64_t Sys_GetSize(int handle) {
return Fs::Vfs::VfsGetSize(handle);
}
static void Sys_Close(int handle) {
Fs::Vfs::VfsClose(handle);
}
static int Sys_ReadDir(const char* path, const char** outNames, int maxEntries) {
// Get entries from VFS into a kernel-local array
const char* kernelNames[64];
int max = maxEntries;
if (max > 64) max = 64;
int count = Fs::Vfs::VfsReadDir(path, kernelNames, max);
if (count <= 0) return count;
// Allocate a user-accessible page for string data via process heap
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return -1;
void* page = Memory::g_pfa->AllocateZeroed();
if (page == nullptr) return -1;
uint64_t physAddr = Memory::SubHHDM((uint64_t)page);
uint64_t userVa = proc->heapNext;
proc->heapNext += 0x1000;
Memory::VMM::Paging::MapUserIn(proc->pml4Phys, physAddr, userVa);
// Copy strings into the user page and write pointers to outNames
uint64_t offset = 0;
uint8_t* pageBuf = (uint8_t*)Memory::HHDM(physAddr);
int copied = 0;
for (int i = 0; i < count; i++) {
int len = Lib::strlen(kernelNames[i]) + 1;
if (offset + len > 0x1000) break;
memcpy(pageBuf + offset, kernelNames[i], len);
outNames[i] = (const char*)(userVa + offset);
offset += len;
copied++;
}
return copied;
}
static uint64_t Sys_Alloc(uint64_t size) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return 0;
// Round up to page boundary
size = (size + 0xFFF) & ~0xFFFULL;
if (size == 0) size = 0x1000;
uint64_t userVa = proc->heapNext;
uint64_t numPages = size / 0x1000;
for (uint64_t i = 0; i < numPages; i++) {
void* page = Memory::g_pfa->AllocateZeroed();
if (page == nullptr) return 0;
uint64_t physAddr = Memory::SubHHDM((uint64_t)page);
Memory::VMM::Paging::MapUserIn(proc->pml4Phys, physAddr, userVa + i * 0x1000);
}
proc->heapNext += size;
return userVa;
}
static void Sys_Free(uint64_t) {
// No-op for now (pages leak). Proper freeing can come later.
}
static uint64_t Sys_GetTicks() {
return Timekeeping::GetTicks();
}
static uint64_t Sys_GetMilliseconds() {
return Timekeeping::GetMilliseconds();
}
static void Sys_GetInfo(SysInfo* outInfo) {
if (outInfo == nullptr) return;
// Copy strings into fixed-size arrays (user-accessible)
const char* name = "ZenithOS";
const char* ver = "0.1.0";
for (int i = 0; name[i]; i++) outInfo->osName[i] = name[i];
outInfo->osName[8] = '\0';
for (int i = 0; ver[i]; i++) outInfo->osVersion[i] = ver[i];
outInfo->osVersion[5] = '\0';
outInfo->apiVersion = 2;
outInfo->maxProcesses = Sched::MaxProcesses;
}
static bool Sys_IsKeyAvailable() {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
auto* target = GetRedirTarget(proc);
if (target) return target->keyHead != target->keyTail;
}
return Drivers::PS2::Keyboard::IsKeyAvailable();
}
static void Sys_GetKey(KeyEvent* outEvent) {
if (outEvent == nullptr) return;
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
auto* target = GetRedirTarget(proc);
if (target) {
// Wait for key in target's keyBuf ring
while (target->keyHead == target->keyTail) {
Sched::Schedule();
}
*outEvent = target->keyBuf[target->keyTail];
target->keyTail = (target->keyTail + 1) % 64;
return;
}
}
auto k = Drivers::PS2::Keyboard::GetKey();
outEvent->scancode = k.Scancode;
outEvent->ascii = k.Ascii;
outEvent->pressed = k.Pressed;
outEvent->shift = k.Shift;
outEvent->ctrl = k.Ctrl;
outEvent->alt = k.Alt;
}
static char Sys_GetChar() {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
auto* target = GetRedirTarget(proc);
if (target && target->inBuf) {
// Wait for data in target's inBuf ring
while (target->inTail == target->inHead) {
Sched::Schedule(); // yield until parent writes
}
uint8_t c = target->inBuf[target->inTail];
target->inTail = (target->inTail + 1) % Sched::Process::IoBufSize;
return (char)c;
}
}
return Drivers::PS2::Keyboard::GetChar();
}
static uint16_t g_pingSeq = 0;
static constexpr uint16_t PING_ID = 0x2E01; // "ZE"
static void Sys_FbInfo(FbInfo* out) {
if (out == nullptr) return;
out->width = Graphics::Cursor::GetFramebufferWidth();
out->height = Graphics::Cursor::GetFramebufferHeight();
out->pitch = Graphics::Cursor::GetFramebufferPitch();
out->bpp = 32;
out->userAddr = 0;
}
static void Sys_WaitPid(int pid) {
while (Sched::IsAlive(pid)) {
Sched::Schedule(); // yield until the process exits
}
}
static uint64_t Sys_FbMap() {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return 0;
uint32_t* fbBase = Graphics::Cursor::GetFramebufferBase();
if (fbBase == nullptr) return 0;
uint64_t fbPhys = Memory::SubHHDM((uint64_t)fbBase);
uint64_t fbSize = Graphics::Cursor::GetFramebufferHeight()
* Graphics::Cursor::GetFramebufferPitch();
uint64_t numPages = (fbSize + 0xFFF) / 0x1000;
Kt::KernelLogStream(Kt::INFO, "FbMap") << "fbPhys=" << kcp::hex << fbPhys
<< " size=" << kcp::dec << fbSize
<< " pages=" << numPages
<< " (" << Graphics::Cursor::GetFramebufferWidth()
<< "x" << Graphics::Cursor::GetFramebufferHeight()
<< " pitch=" << Graphics::Cursor::GetFramebufferPitch() << ")";
// Map at a fixed user VA
constexpr uint64_t userVa = 0x50000000ULL;
for (uint64_t i = 0; i < numPages; i++) {
Memory::VMM::Paging::MapUserInWC(
proc->pml4Phys,
fbPhys + i * 0x1000,
userVa + i * 0x1000
);
}
return userVa;
}
static int32_t Sys_Ping(uint32_t ipAddr, uint32_t timeoutMs) {
uint16_t seq = g_pingSeq++;
Net::Icmp::ResetReply();
Net::Icmp::SendEchoRequest(ipAddr, PING_ID, seq);
uint64_t start = Timekeeping::GetMilliseconds();
while (!Net::Icmp::HasReply(PING_ID, seq)) {
if (Timekeeping::GetMilliseconds() - start >= timeoutMs) {
return -1;
}
Sched::Schedule();
}
return (int32_t)(Timekeeping::GetMilliseconds() - start);
}
static int Sys_Spawn(const char* path, const char* args) {
auto* parent = Sched::GetCurrentProcessPtr();
int childPid = Sched::Spawn(path, args);
if (childPid < 0) return childPid;
// Inherit I/O redirection: if the parent is redirected, the child
// is marked redirected too. It stores a parentPid pointing to the
// process that owns the actual ring buffers (the one spawned via
// spawn_redir). The child does NOT get its own buffers — Sys_Print
// et al. look up the buffer owner at write time.
if (parent && parent->redirected) {
auto* child = Sched::GetProcessByPid(childPid);
if (child) {
child->redirected = true;
// Point to the buffer owner: if parent owns buffers, target parent;
// if parent itself inherited, follow the chain.
child->parentPid = parent->outBuf ? parent->pid : parent->parentPid;
}
}
return childPid;
}
static int Sys_GetArgs(char* buf, uint64_t maxLen) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr || buf == nullptr || maxLen == 0) return -1;
int i = 0;
for (; i < (int)maxLen - 1 && proc->args[i]; i++) {
buf[i] = proc->args[i];
}
buf[i] = '\0';
return i;
}
static uint64_t Sys_TermSize() {
// If the process is redirected to a GUI terminal, return those dimensions
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
auto* target = GetRedirTarget(proc);
if (target && target->termCols > 0 && target->termRows > 0) {
return ((uint64_t)target->termRows << 32) | ((uint64_t)target->termCols & 0xFFFFFFFF);
}
}
size_t cols = 0, rows = 0;
flanterm_get_dimensions(Kt::ctx, &cols, &rows);
return (rows << 32) | (cols & 0xFFFFFFFF);
}
static void Sys_GetTime(DateTime* out) {
if (out == nullptr) return;
Timekeeping::DateTime dt = Timekeeping::GetDateTime();
out->Year = dt.Year;
out->Month = dt.Month;
out->Day = dt.Day;
out->Hour = dt.Hour;
out->Minute = dt.Minute;
out->Second = dt.Second;
}
// ---- Socket syscalls ----
static int Sys_Socket(int type) {
return Net::Socket::Create(type, Sched::GetCurrentPid());
}
static int Sys_Connect(int fd, uint32_t ip, uint16_t port) {
return Net::Socket::Connect(fd, ip, port, Sched::GetCurrentPid());
}
static int Sys_Bind(int fd, uint16_t port) {
return Net::Socket::Bind(fd, port, Sched::GetCurrentPid());
}
static int Sys_Listen(int fd) {
return Net::Socket::Listen(fd, Sched::GetCurrentPid());
}
static int Sys_Accept(int fd) {
return Net::Socket::Accept(fd, Sched::GetCurrentPid());
}
static int Sys_Send(int fd, const uint8_t* data, uint32_t len) {
return Net::Socket::Send(fd, data, len, Sched::GetCurrentPid());
}
static int Sys_Recv(int fd, uint8_t* buf, uint32_t maxLen) {
return Net::Socket::Recv(fd, buf, maxLen, Sched::GetCurrentPid());
}
static void Sys_CloseSock(int fd) {
Net::Socket::Close(fd, Sched::GetCurrentPid());
}
static int Sys_SendTo(int fd, const uint8_t* data, uint32_t len,
uint32_t destIp, uint16_t destPort) {
return Net::Socket::SendTo(fd, data, len, destIp, destPort, Sched::GetCurrentPid());
}
static int Sys_RecvFrom(int fd, uint8_t* buf, uint32_t maxLen,
uint32_t* srcIp, uint16_t* srcPort) {
return Net::Socket::RecvFrom(fd, buf, maxLen, srcIp, srcPort, Sched::GetCurrentPid());
}
static void Sys_GetNetCfg(NetCfg* out) {
if (out == nullptr) return;
out->ipAddress = Net::GetIpAddress();
out->subnetMask = Net::GetSubnetMask();
out->gateway = Net::GetGateway();
const uint8_t* mac = nullptr;
if (Drivers::Net::E1000::IsInitialized()) {
mac = Drivers::Net::E1000::GetMacAddress();
} else if (Drivers::Net::E1000E::IsInitialized()) {
mac = Drivers::Net::E1000E::GetMacAddress();
}
if (mac) {
for (int i = 0; i < 6; i++) out->macAddress[i] = mac[i];
} else {
for (int i = 0; i < 6; i++) out->macAddress[i] = 0;
}
out->_pad[0] = 0;
out->_pad[1] = 0;
out->dnsServer = Net::GetDnsServer();
}
static int Sys_SetNetCfg(const NetCfg* in) {
if (in == nullptr) return -1;
Net::SetIpAddress(in->ipAddress);
Net::SetSubnetMask(in->subnetMask);
Net::SetGateway(in->gateway);
Net::SetDnsServer(in->dnsServer);
return 0;
}
static void Sys_Reset() {
/*
Triple fault for now; TODO: implement UEFI runtime function for clean reboot.
We implement the triple fault by loading a null IDT into the IDT register,
and then immediately triggering an interrupt.
This technique should pretty much work across the board but it's of course
better to use the UEFI runtime API as it has a method for this purpose,
along with shutdown.
*/
struct [[gnu::packed]] { uint16_t limit; uint64_t base; } nullIdt = {0, 0};
asm volatile("lidt %0; int $0x03" :: "m"(nullIdt));
__builtin_unreachable();
}
// ---- File write/create ----
static int Sys_FWrite(int handle, const uint8_t* data, uint64_t offset, uint64_t size) {
return Fs::Vfs::VfsWrite(handle, data, offset, size);
}
static int Sys_FCreate(const char* path) {
return Fs::Vfs::VfsCreate(path);
}
// ---- Terminal scaling ----
static int64_t Sys_TermScale(uint64_t scale_x, uint64_t scale_y) {
if (scale_x == 0) {
return (int64_t)((Kt::GetFontScaleY() << 32) | (Kt::GetFontScaleX() & 0xFFFFFFFF));
}
Kt::Rescale((size_t)scale_x, (size_t)scale_y);
size_t cols = 0, rows = 0;
flanterm_get_dimensions(Kt::ctx, &cols, &rows);
return (int64_t)((rows << 32) | (cols & 0xFFFFFFFF));
}
// ---- DNS resolve ----
static int64_t Sys_Resolve(const char* hostname) {
uint32_t ip = Net::Dns::Resolve(hostname);
return (int64_t)ip;
}
// ---- Random number generation ----
// Uses RDTSC mixed with xorshift64* PRNG for entropy.
// RDRAND is intentionally avoided: some firmware disables the RDRAND
// hardware unit while CPUID still advertises support (bit 30 of ECX),
// causing #UD on real hardware. RDTSC-based entropy is sufficient for
// seeding BearSSL's PRNG for TLS session keys.
static int64_t Sys_GetRandom(uint8_t* buf, uint64_t len) {
uint64_t tsc;
asm volatile("rdtsc; shl $32, %%rdx; or %%rdx, %%rax" : "=a"(tsc) :: "rdx");
uint64_t state = tsc;
for (uint64_t i = 0; i < len; i += 8) {
asm volatile("rdtsc; shl $32, %%rdx; or %%rdx, %%rax" : "=a"(tsc) :: "rdx");
state ^= tsc;
state ^= state >> 12;
state ^= state << 25;
state ^= state >> 27;
uint64_t val = state * 0x2545F4914F6CDD1DULL;
uint64_t remaining = len - i;
uint64_t toCopy = remaining < 8 ? remaining : 8;
for (uint64_t j = 0; j < toCopy; j++)
buf[i + j] = (uint8_t)(val >> (j * 8));
}
return (int64_t)len;
}
// ---- Mouse syscalls ----
static void Sys_MouseState(MouseState* out) {
if (out == nullptr) return;
auto state = Drivers::PS2::Mouse::GetMouseState();
out->x = state.X;
out->y = state.Y;
out->scrollDelta = state.ScrollDelta;
out->buttons = state.Buttons;
}
static void Sys_SetMouseBounds(int32_t maxX, int32_t maxY) {
Drivers::PS2::Mouse::SetBounds(maxX, maxY);
}
// ---- I/O redirection syscalls ----
static int Sys_SpawnRedir(const char* path, const char* args) {
int childPid = Sched::Spawn(path, args);
if (childPid < 0) return -1;
auto* child = Sched::GetProcessByPid(childPid);
if (child == nullptr) return -1;
// Allocate ring buffers
void* outPage = Memory::g_pfa->AllocateZeroed();
void* inPage = Memory::g_pfa->AllocateZeroed();
if (!outPage || !inPage) return -1;
child->outBuf = (uint8_t*)outPage;
child->inBuf = (uint8_t*)inPage;
child->outHead = 0;
child->outTail = 0;
child->inHead = 0;
child->inTail = 0;
child->keyHead = 0;
child->keyTail = 0;
child->redirected = true;
child->parentPid = Sched::GetCurrentPid();
return childPid;
}
static int Sys_ChildIoRead(int childPid, char* buf, int maxLen) {
auto* child = Sched::GetProcessByPid(childPid);
if (child == nullptr || !child->redirected || !child->outBuf) return -1;
return RingRead(child->outBuf, child->outHead, child->outTail, Sched::Process::IoBufSize, (uint8_t*)buf, maxLen);
}
static int Sys_ChildIoWrite(int childPid, const char* data, int len) {
auto* child = Sched::GetProcessByPid(childPid);
if (child == nullptr || !child->redirected || !child->inBuf) return -1;
for (int i = 0; i < len; i++) {
RingWrite(child->inBuf, child->inHead, child->inTail, Sched::Process::IoBufSize, (uint8_t)data[i]);
}
return len;
}
static int Sys_ChildIoWriteKey(int childPid, const KeyEvent* key) {
if (key == nullptr) return -1;
auto* child = Sched::GetProcessByPid(childPid);
if (child == nullptr || !child->redirected) return -1;
child->keyBuf[child->keyHead] = *key;
child->keyHead = (child->keyHead + 1) % 64;
return 0;
}
static int Sys_ChildIoSetTermsz(int childPid, int cols, int rows) {
auto* child = Sched::GetProcessByPid(childPid);
if (child == nullptr || !child->redirected) return -1;
child->termCols = cols;
child->termRows = rows;
return 0;
}
// ---- Process listing / kill ----
static int Sys_ProcList(ProcInfo* buf, int maxCount) {
if (buf == nullptr || maxCount <= 0) return 0;
int count = 0;
for (int i = 0; i < Sched::MaxProcesses && count < maxCount; i++) {
auto* proc = Sched::GetProcessSlot(i);
if (!proc || proc->state == Sched::ProcessState::Free) continue;
buf[count].pid = (int32_t)proc->pid;
buf[count].parentPid = (int32_t)proc->parentPid;
buf[count].state = (uint8_t)proc->state;
buf[count]._pad[0] = 0;
buf[count]._pad[1] = 0;
buf[count]._pad[2] = 0;
{
int j = 0;
for (; j < 63 && proc->name[j]; j++)
buf[count].name[j] = proc->name[j];
buf[count].name[j] = '\0';
}
buf[count].heapUsed = (proc->heapNext > Sched::UserHeapBase)
? proc->heapNext - Sched::UserHeapBase : 0;
count++;
}
return count;
}
static int Sys_Kill(int pid) {
// Refuse to kill PID 0 (init)
if (pid == 0) return -1;
// Refuse to kill the caller's own process
if (pid == Sched::GetCurrentPid()) return -1;
auto* proc = Sched::GetProcessByPid(pid);
if (!proc) return -1;
// Clean up any windows owned by this process
WinServer::CleanupProcess(pid);
proc->state = Sched::ProcessState::Terminated;
return 0;
}
// ---- Device list ----
static void dl_strcpy(char* dst, const char* src, int max) {
int i = 0;
for (; i < max - 1 && src[i]; i++) dst[i] = src[i];
dst[i] = '\0';
}
static int dl_append(char* dst, int pos, const char* src, int max) {
for (int i = 0; src[i] && pos < max - 1; i++) dst[pos++] = src[i];
dst[pos] = '\0';
return pos;
}
static int dl_append_hex(char* dst, int pos, unsigned val, int digits, int max) {
const char* hex = "0123456789abcdef";
char tmp[8];
for (int i = digits - 1; i >= 0; i--) { tmp[i] = hex[val & 0xF]; val >>= 4; }
for (int i = 0; i < digits && pos < max - 1; i++) dst[pos++] = tmp[i];
dst[pos] = '\0';
return pos;
}
static int dl_append_dec(char* dst, int pos, int val, int max) {
if (val == 0) { if (pos < max - 1) dst[pos++] = '0'; dst[pos] = '\0'; return pos; }
char tmp[12]; int i = 0;
while (val > 0) { tmp[i++] = '0' + (val % 10); val /= 10; }
while (i > 0 && pos < max - 1) dst[pos++] = tmp[--i];
dst[pos] = '\0';
return pos;
}
static int Sys_DevList(DevInfo* buf, int maxCount) {
if (buf == nullptr || maxCount <= 0) return 0;
int count = 0;
auto add = [&](uint8_t cat, const char* name, const char* detail) {
if (count >= maxCount) return;
buf[count].category = cat;
buf[count]._pad[0] = 0; buf[count]._pad[1] = 0; buf[count]._pad[2] = 0;
dl_strcpy(buf[count].name, name, 48);
dl_strcpy(buf[count].detail, detail, 48);
count++;
};
// CPU cores (category 0)
int cpuCount = Hal::GetDetectedCpuCount();
if (cpuCount > 0) {
char detail[48];
int p = 0;
p = dl_append(detail, p, "x86_64, ", 48);
p = dl_append_dec(detail, p, cpuCount, 48);
p = dl_append(detail, p, " core(s)", 48);
add(0, "Processor", detail);
}
// Interrupt controllers (category 1)
add(1, "Local APIC", "Per-CPU interrupt controller");
add(1, "I/O APIC", "System interrupt router");
// Timer (category 2)
add(2, "LAPIC Timer", "Local APIC periodic timer");
// PS/2 Input (category 3)
add(3, "PS/2 Keyboard", "IRQ 1, scan code set 1");
if (Drivers::PS2::IsDualChannel()) {
add(3, "PS/2 Mouse", "IRQ 12, dual-channel 8042");
}
// USB devices (category 4)
if (Drivers::USB::Xhci::IsInitialized()) {
for (uint8_t slot = 1; slot <= Drivers::USB::Xhci::MAX_SLOTS && count < maxCount; slot++) {
auto* dev = Drivers::USB::Xhci::GetDevice(slot);
if (!dev || !dev->Active) continue;
const char* devName = "USB Device";
if (dev->InterfaceClass == 3) {
if (dev->InterfaceProtocol == 1) devName = "USB HID Keyboard";
else if (dev->InterfaceProtocol == 2) devName = "USB HID Mouse";
else devName = "USB HID Device";
} else if (dev->InterfaceClass == 8) {
devName = "USB Mass Storage";
} else if (dev->InterfaceClass == 9) {
devName = "USB Hub";
}
char detail[48];
int p = 0;
p = dl_append(detail, p, "Port ", 48);
p = dl_append_dec(detail, p, dev->PortId, 48);
p = dl_append(detail, p, ", VID:", 48);
p = dl_append_hex(detail, p, dev->VendorId, 4, 48);
p = dl_append(detail, p, " PID:", 48);
p = dl_append_hex(detail, p, dev->ProductId, 4, 48);
add(4, devName, detail);
}
}
// Network (category 5)
if (Drivers::Net::E1000::IsInitialized()) {
add(5, "Intel E1000", "Gigabit Ethernet (82540EM)");
}
if (Drivers::Net::E1000E::IsInitialized()) {
add(5, "Intel E1000E", "Gigabit Ethernet (82574L)");
}
// Display (category 6)
if (Drivers::Graphics::IntelGPU::IsInitialized()) {
auto* gpu = Drivers::Graphics::IntelGPU::GetGpuInfo();
if (gpu) {
add(6, gpu->name, "Intel Integrated Graphics");
}
}
// PCI devices (category 7)
auto& pciDevs = Pci::GetDevices();
for (int i = 0; i < (int)pciDevs.size() && count < maxCount; i++) {
auto& d = pciDevs[i];
const char* className = Pci::GetClassName(d.ClassCode, d.SubClass);
char detail[48];
int p = 0;
p = dl_append_hex(detail, p, d.Bus, 2, 48);
p = dl_append(detail, p, ":", 48);
p = dl_append_hex(detail, p, d.Device, 2, 48);
p = dl_append(detail, p, ".", 48);
p = dl_append_dec(detail, p, d.Function, 48);
p = dl_append(detail, p, " ", 48);
p = dl_append_hex(detail, p, d.VendorId, 4, 48);
p = dl_append(detail, p, ":", 48);
p = dl_append_hex(detail, p, d.DeviceId, 4, 48);
add(7, className, detail);
}
return count;
}
// ---- Kernel introspection syscalls ----
static void Sys_MemStats(MemStats* out) {
if (out == nullptr) return;
Memory::g_pfa->GetStats(out);
}
// ---- Window scale syscalls ----
static int Sys_WinSetScale(int scale) {
return WinServer::SetScale(scale);
}
static int Sys_WinGetScale() {
return WinServer::GetScale();
}
// ---- Window server syscalls ----
static int Sys_WinCreate(const char* title, int w, int h, WinCreateResult* result) {
if (result == nullptr || title == nullptr) return -1;
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return -1;
uint64_t outVa = 0;
int id = WinServer::Create(proc->pid, proc->pml4Phys, title, w, h,
proc->heapNext, outVa);
result->id = id;
result->pixelVa = (id >= 0) ? outVa : 0;
return id >= 0 ? 0 : -1;
}
static int Sys_WinDestroy(int windowId) {
return WinServer::Destroy(windowId, Sched::GetCurrentPid());
}
static uint64_t Sys_WinPresent(int windowId) {
return WinServer::Present(windowId, Sched::GetCurrentPid());
}
static int Sys_WinPoll(int windowId, WinEvent* outEvent) {
if (outEvent == nullptr) return -1;
return WinServer::Poll(windowId, Sched::GetCurrentPid(), outEvent);
}
static int Sys_WinEnum(WinInfo* outArray, int maxCount) {
if (outArray == nullptr || maxCount <= 0) return 0;
return WinServer::Enumerate(outArray, maxCount);
}
static uint64_t Sys_WinMap(int windowId) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return 0;
return WinServer::Map(windowId, proc->pid, proc->pml4Phys, proc->heapNext);
}
static int Sys_WinSendEvent(int windowId, const WinEvent* event) {
if (event == nullptr) return -1;
return WinServer::SendEvent(windowId, event);
}
static uint64_t Sys_WinResize(int windowId, int newW, int newH) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return 0;
uint64_t outVa = 0;
int r = WinServer::Resize(windowId, proc->pid, proc->pml4Phys, newW, newH,
proc->heapNext, outVa);
return (r == 0) ? outVa : 0;
}
// ---- Dispatch ----
extern "C" int64_t SyscallDispatch(SyscallFrame* frame) {
+71 -22
View File
@@ -11,35 +11,69 @@
namespace Zenith {
// Syscall numbers
/* Process.hpp */
static constexpr uint64_t SYS_EXIT = 0;
static constexpr uint64_t SYS_YIELD = 1;
static constexpr uint64_t SYS_SLEEP_MS = 2;
static constexpr uint64_t SYS_GETPID = 3;
/* Terminal.hpp */
static constexpr uint64_t SYS_PRINT = 4;
static constexpr uint64_t SYS_PUTCHAR = 5;
static constexpr uint64_t SYS_PUTCHAR = 5;
/* Filesystem.hpp */
static constexpr uint64_t SYS_OPEN = 6;
static constexpr uint64_t SYS_READ = 7;
static constexpr uint64_t SYS_GETSIZE = 8;
static constexpr uint64_t SYS_CLOSE = 9;
static constexpr uint64_t SYS_READDIR = 10;
/* Heap.hpp */
static constexpr uint64_t SYS_ALLOC = 11;
static constexpr uint64_t SYS_FREE = 12;
/* Time.hpp */
static constexpr uint64_t SYS_GETTICKS = 13;
static constexpr uint64_t SYS_GETMILLISECONDS = 14;
/* Info.hpp */
static constexpr uint64_t SYS_GETINFO = 15;
/* Keyboard.hpp */
static constexpr uint64_t SYS_ISKEYAVAILABLE = 16;
static constexpr uint64_t SYS_GETKEY = 17;
static constexpr uint64_t SYS_GETCHAR = 18;
/* Net.hpp */
static constexpr uint64_t SYS_PING = 19;
/* Process.hpp */
static constexpr uint64_t SYS_SPAWN = 20;
/* Graphics.hpp */
static constexpr uint64_t SYS_FBINFO = 21;
static constexpr uint64_t SYS_FBMAP = 22;
/* Process.hpp */
static constexpr uint64_t SYS_WAITPID = 23;
/* Graphics.hpp */
static constexpr uint64_t SYS_TERMSIZE = 24;
/* Process.hpp */
static constexpr uint64_t SYS_GETARGS = 25;
/* Power.hpp */
static constexpr uint64_t SYS_RESET = 26;
static constexpr uint64_t SYS_SHUTDOWN = 27;
/* Time.hpp */
static constexpr uint64_t SYS_GETTIME = 28;
/* Net.hpp */
static constexpr uint64_t SYS_SOCKET = 29;
static constexpr uint64_t SYS_CONNECT = 30;
static constexpr uint64_t SYS_BIND = 31;
@@ -48,25 +82,38 @@ namespace Zenith {
static constexpr uint64_t SYS_SEND = 34;
static constexpr uint64_t SYS_RECV = 35;
static constexpr uint64_t SYS_CLOSESOCK = 36;
static constexpr uint64_t SYS_GETNETCFG = 37;
static constexpr uint64_t SYS_SETNETCFG = 38;
static constexpr uint64_t SYS_SENDTO = 39;
static constexpr uint64_t SYS_RECVFROM = 40;
static constexpr uint64_t SYS_FWRITE = 41;
static constexpr uint64_t SYS_FCREATE = 42;
static constexpr uint64_t SYS_TERMSCALE = 43;
static constexpr uint64_t SYS_RESOLVE = 44;
static constexpr uint64_t SYS_GETRANDOM = 45;
static constexpr uint64_t SYS_GETNETCFG = 37;
static constexpr uint64_t SYS_SETNETCFG = 38;
static constexpr uint64_t SYS_SENDTO = 39;
static constexpr uint64_t SYS_RECVFROM = 40;
/* Filesystem.hpp */
static constexpr uint64_t SYS_FWRITE = 41;
static constexpr uint64_t SYS_FCREATE = 42;
/* Graphics.hpp */
static constexpr uint64_t SYS_TERMSCALE = 43;
/* Net.hpp */
static constexpr uint64_t SYS_RESOLVE = 44;
/* Random.hpp */
static constexpr uint64_t SYS_GETRANDOM = 45;
static constexpr uint64_t SYS_KLOG = 46;
static constexpr uint64_t SYS_MOUSESTATE = 47;
static constexpr uint64_t SYS_SETMOUSEBOUNDS = 48;
static constexpr uint64_t SYS_SPAWN_REDIR = 49;
static constexpr uint64_t SYS_CHILDIO_READ = 50;
static constexpr uint64_t SYS_CHILDIO_WRITE = 51;
static constexpr uint64_t SYS_CHILDIO_WRITEKEY = 52;
/* Mouse.hpp */
static constexpr uint64_t SYS_MOUSESTATE = 47;
static constexpr uint64_t SYS_SETMOUSEBOUNDS = 48;
/* IoRedir.hpp */
static constexpr uint64_t SYS_SPAWN_REDIR = 49;
static constexpr uint64_t SYS_CHILDIO_READ = 50;
static constexpr uint64_t SYS_CHILDIO_WRITE = 51;
static constexpr uint64_t SYS_CHILDIO_WRITEKEY = 52;
static constexpr uint64_t SYS_CHILDIO_SETTERMSZ = 53;
// Window server syscalls
/* Window.hpp */
static constexpr uint64_t SYS_WINCREATE = 54;
static constexpr uint64_t SYS_WINDESTROY = 55;
static constexpr uint64_t SYS_WINPRESENT = 56;
@@ -74,16 +121,18 @@ namespace Zenith {
static constexpr uint64_t SYS_WINENUM = 58;
static constexpr uint64_t SYS_WINMAP = 59;
static constexpr uint64_t SYS_WINSENDEVENT = 60;
static constexpr uint64_t SYS_WINRESIZE = 64;
static constexpr uint64_t SYS_WINSETSCALE = 65;
static constexpr uint64_t SYS_WINGETSCALE = 66;
static constexpr uint64_t SYS_WINRESIZE = 64;
static constexpr uint64_t SYS_WINSETSCALE = 65;
static constexpr uint64_t SYS_WINGETSCALE = 66;
// Process management syscalls
/* Process.hpp */
static constexpr uint64_t SYS_PROCLIST = 61;
static constexpr uint64_t SYS_KILL = 62;
/* Device.hpp */
static constexpr uint64_t SYS_DEVLIST = 63;
// Kernel introspection syscalls
/* MemInfo.hpp */
static constexpr uint64_t SYS_MEMSTATS = 67;
static constexpr int SOCK_TCP = 1;
+40
View File
@@ -0,0 +1,40 @@
/*
* Terminal.hpp
* SYS_PRINT, SYS_PUTCHAR syscalls
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <Sched/Scheduler.hpp>
#include <Terminal/Terminal.hpp>
#include "Common.hpp"
namespace Zenith {
static void Sys_Print(const char* text) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
auto* target = GetRedirTarget(proc);
if (target && target->outBuf) {
for (int i = 0; text[i]; i++) {
RingWrite(target->outBuf, target->outHead, target->outTail, Sched::Process::IoBufSize, (uint8_t)text[i]);
}
return;
}
}
Kt::Print(text);
}
static void Sys_Putchar(char c) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc && proc->redirected) {
auto* target = GetRedirTarget(proc);
if (target && target->outBuf) {
RingWrite(target->outBuf, target->outHead, target->outTail, Sched::Process::IoBufSize, (uint8_t)c);
return;
}
}
Kt::Putchar(c);
}
};
+32
View File
@@ -0,0 +1,32 @@
/*
* Time.hpp
* SYS_GETTICKS, SYS_GETMILLISECONDS, SYS_GETTIME syscalls
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <Timekeeping/ApicTimer.hpp>
#include <Timekeeping/Time.hpp>
#include "Syscall.hpp"
namespace Zenith {
static uint64_t Sys_GetTicks() {
return Timekeeping::GetTicks();
}
static uint64_t Sys_GetMilliseconds() {
return Timekeeping::GetMilliseconds();
}
static void Sys_GetTime(DateTime* out) {
if (out == nullptr) return;
Timekeeping::DateTime dt = Timekeeping::GetDateTime();
out->Year = dt.Year;
out->Month = dt.Month;
out->Day = dt.Day;
out->Hour = dt.Hour;
out->Minute = dt.Minute;
out->Second = dt.Second;
}
};
+75
View File
@@ -0,0 +1,75 @@
/*
* Window.hpp
* SYS_WINCREATE, SYS_WINDESTROY, SYS_WINPRESENT, SYS_WINPOLL,
* SYS_WINENUM, SYS_WINMAP, SYS_WINSENDEVENT, SYS_WINRESIZE,
* SYS_WINSETSCALE, SYS_WINGETSCALE syscalls
* Copyright (c) 2026 Daniel Hammer
*/
#pragma once
#include <Sched/Scheduler.hpp>
#include "Syscall.hpp"
#include "WinServer.hpp"
namespace Zenith {
static int Sys_WinCreate(const char* title, int w, int h, WinCreateResult* result) {
if (result == nullptr || title == nullptr) return -1;
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return -1;
uint64_t outVa = 0;
int id = WinServer::Create(proc->pid, proc->pml4Phys, title, w, h,
proc->heapNext, outVa);
result->id = id;
result->pixelVa = (id >= 0) ? outVa : 0;
return id >= 0 ? 0 : -1;
}
static int Sys_WinDestroy(int windowId) {
return WinServer::Destroy(windowId, Sched::GetCurrentPid());
}
static uint64_t Sys_WinPresent(int windowId) {
return WinServer::Present(windowId, Sched::GetCurrentPid());
}
static int Sys_WinPoll(int windowId, WinEvent* outEvent) {
if (outEvent == nullptr) return -1;
return WinServer::Poll(windowId, Sched::GetCurrentPid(), outEvent);
}
static int Sys_WinEnum(WinInfo* outArray, int maxCount) {
if (outArray == nullptr || maxCount <= 0) return 0;
return WinServer::Enumerate(outArray, maxCount);
}
static uint64_t Sys_WinMap(int windowId) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return 0;
return WinServer::Map(windowId, proc->pid, proc->pml4Phys, proc->heapNext);
}
static int Sys_WinSendEvent(int windowId, const WinEvent* event) {
if (event == nullptr) return -1;
return WinServer::SendEvent(windowId, event);
}
static uint64_t Sys_WinResize(int windowId, int newW, int newH) {
auto* proc = Sched::GetCurrentProcessPtr();
if (proc == nullptr) return 0;
uint64_t outVa = 0;
int r = WinServer::Resize(windowId, proc->pid, proc->pml4Phys, newW, newH,
proc->heapNext, outVa);
return (r == 0) ? outVa : 0;
}
static int Sys_WinSetScale(int scale) {
return WinServer::SetScale(scale);
}
static int Sys_WinGetScale() {
return WinServer::GetScale();
}
};
+1 -1
View File
@@ -10,7 +10,7 @@
namespace Sched {
static constexpr int MaxProcesses = 16;
static constexpr int MaxProcesses = 256;
static constexpr uint64_t StackPages = 4; // 16 KiB kernel stack per process
static constexpr uint64_t StackSize = StackPages * 0x1000;
static constexpr uint64_t UserStackPages = 4; // 16 KiB user stack