/*
    * Syscall.cpp
    * SYSCALL/SYSRET setup and number-based dispatch
    * Copyright (c) 2025 Daniel Hammer
*/

#include "Syscall.hpp"
#include <Terminal/Terminal.hpp>
#include <Hal/MSR.hpp>
#include <Hal/GDT.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, SYS_NETSTATUS
#include "Power.hpp"      // SYS_RESET, SYS_SHUTDOWN, SYS_SUSPEND
#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, SYS_DISKINFO
#include "Input.hpp"      // SYS_INPUT_WAIT
#include "Storage.hpp"    // SYS_PARTLIST, SYS_DISKREAD, SYS_DISKWRITE
#include "Window.hpp"     // SYS_WINCREATE, SYS_WINDESTROY, SYS_WINPRESENT, SYS_WINPOLL, SYS_WINENUM, SYS_WINMAP, SYS_WINSENDEVENT, SYS_WINRESIZE, SYS_WINSETSCALE, SYS_WINGETSCALE
#include "Audio.hpp"      // SYS_AUDIOOPEN, SYS_AUDIOCLOSE, SYS_AUDIOWRITE, SYS_AUDIOCTL
#include "BluetoothSyscall.hpp" // SYS_BTSCAN, SYS_BTCONNECT, SYS_BTDISCONNECT, SYS_BTLIST, SYS_BTINFO
#include "IpcSyscall.hpp" // SYS_DUPHANDLE, SYS_WAIT_HANDLE, SYS_STREAM_CREATE, SYS_STREAM_READ, SYS_STREAM_WRITE, SYS_MAILBOX_CREATE, SYS_MAILBOX_SEND, SYS_MAILBOX_RECV, SYS_WAITSET_CREATE, SYS_WAITSET_ADD, SYS_WAITSET_REMOVE, SYS_WAITSET_WAIT, SYS_PROC_OPEN, SYS_SURFACE_CREATE, SYS_SURFACE_MAP, SYS_SURFACE_RESIZE
#include "LibSyscall.hpp" // SYS_LOAD_LIB, SYS_UNLOAD_LIB, SYS_DLSYM
#include "CrashReportSyscall.hpp" // SYS_CRASH_REPORT
#include "Clipboard.hpp" // SYS_CLIPBOARD_*
#include "UserMemory.hpp"

// Assembly entry point
extern "C" void SyscallEntry();

namespace Montauk {

    static constexpr uint64_t kMaxPrintableStringBytes = 4096;
    static constexpr uint64_t kMaxPathBytes = 256;
    static constexpr uint64_t kMaxArgsBytes = 256;
    static constexpr uint64_t kMaxWindowTitleBytes = 256;
    static constexpr uint64_t kMaxHostnameBytes = 256;
    static constexpr uint64_t kMaxUserNameBytes = 32;

    // ---- Dispatch ----

    extern "C" int64_t SyscallDispatch(SyscallFrame* frame) {
        switch (frame->syscall_nr) {
            case SYS_EXIT: {
                Sys_Exit((int)frame->arg1);
                return 0;
            }
            case SYS_YIELD:
                Sys_Yield();
                return 0;
            case SYS_SLEEP_MS:
                Sys_SleepMs(frame->arg1);
                return 0;
            case SYS_GETPID:
                return (int64_t)Sys_GetPid();
            case SYS_PRINT:
                if (!UserMemory::String(frame->arg1, kMaxPrintableStringBytes)) return -1;
                Sys_Print((const char*)frame->arg1);
                return 0;
            case SYS_PUTCHAR:
                Sys_Putchar((char)frame->arg1);
                return 0;
            case SYS_OPEN:
                if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
                return (int64_t)Sys_Open((const char*)frame->arg1);
            case SYS_READ:
                if (!UserMemory::Range(frame->arg2, frame->arg4, true)) return -1;
                return (int64_t)Sys_Read((int)frame->arg1, (uint8_t*)frame->arg2,
                                         frame->arg3, frame->arg4);
            case SYS_GETSIZE:
                return (int64_t)Sys_GetSize((int)frame->arg1);
            case SYS_CLOSE:
                Sys_Close((int)frame->arg1);
                return 0;
            case SYS_READDIR:
                if ((int64_t)frame->arg3 < 0) return -1;
                if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
                if (!UserMemory::Range(frame->arg2,
                                       (uint64_t)((frame->arg3 > 256) ? 256 : frame->arg3) * sizeof(const char*),
                                       true)) {
                    return -1;
                }
                return (int64_t)Sys_ReadDir((const char*)frame->arg1,
                                            (const char**)frame->arg2,
                                            (int)frame->arg3);
            case SYS_ALLOC:
                return (int64_t)Sys_Alloc(frame->arg1);
            case SYS_FREE:
                Sys_Free(frame->arg1);
                return 0;
            case SYS_GETTICKS:
                return (int64_t)Sys_GetTicks();
            case SYS_GETMILLISECONDS:
                return (int64_t)Sys_GetMilliseconds();
            case SYS_GETINFO:
                if (!UserMemory::Writable<SysInfo>(frame->arg1)) return -1;
                Sys_GetInfo((SysInfo*)frame->arg1);
                return 0;
            case SYS_ISKEYAVAILABLE:
                return (int64_t)Sys_IsKeyAvailable();
            case SYS_GETKEY:
                if (!UserMemory::Writable<KeyEvent>(frame->arg1)) return -1;
                Sys_GetKey((KeyEvent*)frame->arg1);
                return 0;
            case SYS_GETCHAR:
                return (int64_t)Sys_GetChar();
            case SYS_PING:
                return (int64_t)Sys_Ping((uint32_t)frame->arg1, (uint32_t)frame->arg2);
            case SYS_SPAWN:
                if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
                if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return -1;
                return (int64_t)Sys_Spawn((const char*)frame->arg1,
                                          UserMemory::IsUserPtr(frame->arg2) ? (const char*)frame->arg2 : nullptr);
            case SYS_WAITPID:
                Sys_WaitPid((int)frame->arg1);
                return 0;
            case SYS_FBINFO:
                if (!UserMemory::Writable<FbInfo>(frame->arg1)) return -1;
                Sys_FbInfo((FbInfo*)frame->arg1);
                return 0;
            case SYS_FBMAP:
                return (int64_t)Sys_FbMap();
            case SYS_TERMSIZE:
                return (int64_t)Sys_TermSize();
            case SYS_GETARGS:
                if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
                return (int64_t)Sys_GetArgs((char*)frame->arg1, frame->arg2);
            case SYS_RESET:
                Sys_Reset();
                return 0;
            case SYS_SHUTDOWN:
                Sys_Shutdown();
                return 0;
            case SYS_GETTIME:
                if (!UserMemory::Writable<DateTime>(frame->arg1)) return -1;
                Sys_GetTime((DateTime*)frame->arg1);
                return 0;
            case SYS_SOCKET:
                return (int64_t)Sys_Socket((int)frame->arg1);
            case SYS_CONNECT:
                return (int64_t)Sys_Connect((int)frame->arg1, (uint32_t)frame->arg2, (uint16_t)frame->arg3);
            case SYS_BIND:
                return (int64_t)Sys_Bind((int)frame->arg1, (uint16_t)frame->arg2);
            case SYS_LISTEN:
                return (int64_t)Sys_Listen((int)frame->arg1);
            case SYS_ACCEPT:
                return (int64_t)Sys_Accept((int)frame->arg1);
            case SYS_SEND:
                if (!UserMemory::Range(frame->arg2, frame->arg3, false)) return -1;
                return (int64_t)Sys_Send((int)frame->arg1, (const uint8_t*)frame->arg2, (uint32_t)frame->arg3);
            case SYS_RECV:
                if (!UserMemory::Range(frame->arg2, frame->arg3, true)) return -1;
                return (int64_t)Sys_Recv((int)frame->arg1, (uint8_t*)frame->arg2, (uint32_t)frame->arg3);
            case SYS_CLOSESOCK:
                Sys_CloseSock((int)frame->arg1);
                return 0;
            case SYS_GETNETCFG:
                if (!UserMemory::Writable<NetCfg>(frame->arg1)) return -1;
                Sys_GetNetCfg((NetCfg*)frame->arg1);
                return 0;
            case SYS_SETNETCFG:
                if (!UserMemory::Readable<NetCfg>(frame->arg1)) return -1;
                return (int64_t)Sys_SetNetCfg((const NetCfg*)frame->arg1);
            case SYS_NETSTATUS:
                if (!UserMemory::Writable<NetStatus>(frame->arg1)) return -1;
                Sys_NetStatus((NetStatus*)frame->arg1);
                return 0;
            case SYS_SENDTO:
                if (!UserMemory::Range(frame->arg2, frame->arg3, false)) return -1;
                return (int64_t)Sys_SendTo((int)frame->arg1, (const uint8_t*)frame->arg2,
                                           (uint32_t)frame->arg3, (uint32_t)frame->arg4,
                                           (uint16_t)frame->arg5);
            case SYS_RECVFROM:
                if (!UserMemory::Range(frame->arg2, frame->arg3, true)) return -1;
                if (!UserMemory::OptionalRange(frame->arg4, sizeof(uint32_t), true)) return -1;
                if (!UserMemory::OptionalRange(frame->arg5, sizeof(uint16_t), true)) return -1;
                return (int64_t)Sys_RecvFrom((int)frame->arg1, (uint8_t*)frame->arg2,
                                             (uint32_t)frame->arg3,
                                             UserMemory::IsUserPtr(frame->arg4) ? (uint32_t*)frame->arg4 : nullptr,
                                             UserMemory::IsUserPtr(frame->arg5) ? (uint16_t*)frame->arg5 : nullptr);
            case SYS_FWRITE:
                if (!UserMemory::Range(frame->arg2, frame->arg4, false)) return -1;
                return (int64_t)Sys_FWrite((int)frame->arg1, (const uint8_t*)frame->arg2,
                                           frame->arg3, frame->arg4);
            case SYS_FCREATE:
                if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
                return (int64_t)Sys_FCreate((const char*)frame->arg1);
            case SYS_FDELETE:
                if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
                return (int64_t)Sys_FDelete((const char*)frame->arg1);
            case SYS_FMKDIR:
                if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
                return (int64_t)Sys_FMkdir((const char*)frame->arg1);
            case SYS_FRENAME:
                if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
                if (!UserMemory::String(frame->arg2, kMaxPathBytes)) return -1;
                return (int64_t)Sys_FRename((const char*)frame->arg1, (const char*)frame->arg2);
            case SYS_DRIVELIST:
                if ((int64_t)frame->arg2 < 0) return -1;
                if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(int), true)) return -1;
                return (int64_t)Sys_DriveList((int*)frame->arg1, (int)frame->arg2);
            case SYS_DRIVELABEL:
                if ((int64_t)frame->arg3 <= 0) return -1;
                if (!UserMemory::Range(frame->arg2, frame->arg3, true)) return -1;
                return (int64_t)Sys_DriveLabel((int)frame->arg1, (char*)frame->arg2, (int)frame->arg3);
            case SYS_TERMSCALE:
                return Sys_TermScale(frame->arg1, frame->arg2);
            case SYS_RESOLVE:
                if (!UserMemory::String(frame->arg1, kMaxHostnameBytes)) return -1;
                return Sys_Resolve((const char*)frame->arg1);
            case SYS_GETRANDOM:
                if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
                return Sys_GetRandom((uint8_t*)frame->arg1, frame->arg2);
            case SYS_KLOG:
                if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
                return Kt::ReadKernelLog((char*)frame->arg1, frame->arg2);
            case SYS_MOUSESTATE:
                if (!UserMemory::Writable<MouseState>(frame->arg1)) return -1;
                Sys_MouseState((MouseState*)frame->arg1);
                return 0;
            case SYS_SETMOUSEBOUNDS:
                Sys_SetMouseBounds((int32_t)frame->arg1, (int32_t)frame->arg2);
                return 0;
            case SYS_SPAWN_REDIR:
                if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
                if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return -1;
                return (int64_t)Sys_SpawnRedir((const char*)frame->arg1,
                                               UserMemory::IsUserPtr(frame->arg2) ? (const char*)frame->arg2 : nullptr);
            case SYS_CHILDIO_READ:
                if ((int64_t)frame->arg3 < 0) return -1;
                if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, true)) return -1;
                return (int64_t)Sys_ChildIoRead((int)frame->arg1, (char*)frame->arg2, (int)frame->arg3);
            case SYS_CHILDIO_WRITE:
                if ((int64_t)frame->arg3 < 0) return -1;
                if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, false)) return -1;
                return (int64_t)Sys_ChildIoWrite((int)frame->arg1, (const char*)frame->arg2, (int)frame->arg3);
            case SYS_CHILDIO_WRITEKEY:
                if (!UserMemory::Readable<KeyEvent>(frame->arg2)) return -1;
                return (int64_t)Sys_ChildIoWriteKey((int)frame->arg1, (const KeyEvent*)frame->arg2);
            case SYS_CHILDIO_SETTERMSZ:
                return (int64_t)Sys_ChildIoSetTermsz((int)frame->arg1, (int)frame->arg2, (int)frame->arg3);
            case SYS_WINCREATE:
                if (!UserMemory::String(frame->arg1, kMaxWindowTitleBytes)) return -1;
                if (!UserMemory::Writable<WinCreateResult>(frame->arg4)) return -1;
                return (int64_t)Sys_WinCreate((const char*)frame->arg1, (int)frame->arg2,
                                              (int)frame->arg3, (WinCreateResult*)frame->arg4);
            case SYS_WINDESTROY:
                return (int64_t)Sys_WinDestroy((int)frame->arg1);
            case SYS_WINPRESENT:
                return (int64_t)Sys_WinPresent((int)frame->arg1);
            case SYS_WINPOLL:
                if (!UserMemory::Writable<WinEvent>(frame->arg2)) return -1;
                return (int64_t)Sys_WinPoll((int)frame->arg1, (WinEvent*)frame->arg2);
            case SYS_WINENUM:
                if ((int64_t)frame->arg2 < 0) return -1;
                if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(WinInfo), true)) return -1;
                return (int64_t)Sys_WinEnum((WinInfo*)frame->arg1, (int)frame->arg2);
            case SYS_WINMAP:
                return (int64_t)Sys_WinMap((int)frame->arg1);
            case SYS_WINUNMAP:
                return (int64_t)Sys_WinUnmap((int)frame->arg1);
            case SYS_WINSENDEVENT:
                if (!UserMemory::Readable<WinEvent>(frame->arg2)) return -1;
                return (int64_t)Sys_WinSendEvent((int)frame->arg1, (const WinEvent*)frame->arg2);
            case SYS_WINRESIZE:
                return (int64_t)Sys_WinResize((int)frame->arg1, (int)frame->arg2, (int)frame->arg3);
            case SYS_PROCLIST:
                if ((int64_t)frame->arg2 < 0) return -1;
                if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(ProcInfo), true)) return -1;
                return (int64_t)Sys_ProcList((ProcInfo*)frame->arg1, (int)frame->arg2);
            case SYS_KILL:
                return (int64_t)Sys_Kill((int)frame->arg1);
            case SYS_DEVLIST:
                if ((int64_t)frame->arg2 < 0) return -1;
                if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(DevInfo), true)) return -1;
                return (int64_t)Sys_DevList((DevInfo*)frame->arg1, (int)frame->arg2);
            case SYS_DISKINFO:
                if (!UserMemory::Writable<DiskInfo>(frame->arg1)) return -1;
                return (int64_t)Sys_DiskInfo((DiskInfo*)frame->arg1, (int)frame->arg2);
            case SYS_WINSETSCALE:
                return (int64_t)Sys_WinSetScale((int)frame->arg1);
            case SYS_WINGETSCALE:
                return (int64_t)Sys_WinGetScale();
            case SYS_WINSETCURSOR:
                return (int64_t)Sys_WinSetCursor((int)frame->arg1, (int)frame->arg2);
            case SYS_MEMSTATS:
                if (!UserMemory::Writable<MemStats>(frame->arg1)) return -1;
                Sys_MemStats((MemStats*)frame->arg1);
                return 0;
            case SYS_PARTLIST:
                if ((int64_t)frame->arg2 < 0) return -1;
                if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(PartInfo), true)) return -1;
                return (int64_t)Sys_PartList((PartInfo*)frame->arg1, (int)frame->arg2);
            case SYS_DISKREAD:
                return (int64_t)Sys_DiskRead((int)frame->arg1, frame->arg2,
                                             (uint32_t)frame->arg3, (void*)frame->arg4);
            case SYS_DISKWRITE:
                return (int64_t)Sys_DiskWrite((int)frame->arg1, frame->arg2,
                                              (uint32_t)frame->arg3, (const void*)frame->arg4);
            case SYS_GPTINIT:
                return (int64_t)Sys_GptInit((int)frame->arg1);
            case SYS_GPTADD:
                if (!UserMemory::Readable<GptAddParams>(frame->arg1)) return -1;
                return (int64_t)Sys_GptAdd((const GptAddParams*)frame->arg1);
            case SYS_FSMOUNT:
                return (int64_t)Sys_FsMount((int)frame->arg1, (int)frame->arg2);
            case SYS_FSFORMAT:
                if (!UserMemory::Readable<FsFormatParams>(frame->arg1)) return -1;
                return (int64_t)Sys_FsFormat((const FsFormatParams*)frame->arg1);
            case SYS_AUDIOOPEN:
                return Sys_AudioOpen((uint32_t)frame->arg1, (uint8_t)frame->arg2, (uint8_t)frame->arg3);
            case SYS_AUDIOCLOSE:
                return Sys_AudioClose((int)frame->arg1);
            case SYS_AUDIOWRITE:
                if (!UserMemory::Range(frame->arg2, frame->arg3, false)) return -1;
                return Sys_AudioWrite((int)frame->arg1, (const uint8_t*)frame->arg2, (uint32_t)frame->arg3);
            case SYS_AUDIOCTL:
                return Sys_AudioCtl((int)frame->arg1, (int)frame->arg2, (int)frame->arg3);
            case SYS_BTSCAN:
                if ((int64_t)frame->arg2 < 0) return -1;
                if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(BtScanResult), true)) return -1;
                return Sys_BtScan((BtScanResult*)frame->arg1, (int)frame->arg2, (uint32_t)frame->arg3);
            case SYS_BTCONNECT:
                if (!UserMemory::Range(frame->arg1, 6, false)) return -1;
                return Sys_BtConnect((const uint8_t*)frame->arg1);
            case SYS_BTDISCONNECT:
                if (!UserMemory::Range(frame->arg1, 6, false)) return -1;
                return Sys_BtDisconnect((const uint8_t*)frame->arg1);
            case SYS_BTLIST:
                if ((int64_t)frame->arg2 < 0) return -1;
                if (!UserMemory::Range(frame->arg1, (uint64_t)frame->arg2 * sizeof(BtDevInfo), true)) return -1;
                return Sys_BtList((BtDevInfo*)frame->arg1, (int)frame->arg2);
            case SYS_BTINFO:
                if (!UserMemory::Writable<BtAdapterInfo>(frame->arg1)) return -1;
                return Sys_BtInfo((BtAdapterInfo*)frame->arg1);
            case SYS_SUSPEND:
                return Sys_Suspend();
            case SYS_SETTZ:
                return Sys_SetTZ((int32_t)frame->arg1);
            case SYS_GETTZ:
                return Sys_GetTZ();
            case SYS_SETUSER:
                if (!UserMemory::String(frame->arg2, kMaxUserNameBytes)) return -1;
                return Sys_SetUser((int)frame->arg1, (const char*)frame->arg2);
            case SYS_GETUSER:
                if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
                return Sys_GetUser((char*)frame->arg1, frame->arg2);
            case SYS_GETCWD:
                if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
                return Sys_GetCwd((char*)frame->arg1, frame->arg2);
            case SYS_CHDIR:
                if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
                return Sys_Chdir((const char*)frame->arg1);
            case SYS_DUPHANDLE:
                return Sys_DupHandle((int)frame->arg1);
            case SYS_WAIT_HANDLE:
                return (int64_t)Sys_WaitHandle((int)frame->arg1, (uint32_t)frame->arg2, frame->arg3);
            case SYS_STREAM_CREATE:
                if (!UserMemory::Writable<int>(frame->arg1) || !UserMemory::Writable<int>(frame->arg2)) return -1;
                return Sys_StreamCreate((int*)frame->arg1, (int*)frame->arg2, (uint32_t)frame->arg3);
            case SYS_STREAM_READ:
                if ((int64_t)frame->arg3 < 0) return -1;
                if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, true)) return -1;
                return Sys_StreamRead((int)frame->arg1, (uint8_t*)frame->arg2, (int)frame->arg3);
            case SYS_STREAM_WRITE:
                if ((int64_t)frame->arg3 < 0) return -1;
                if (!UserMemory::Range(frame->arg2, (uint64_t)frame->arg3, false)) return -1;
                return Sys_StreamWrite((int)frame->arg1, (const uint8_t*)frame->arg2, (int)frame->arg3);
            case SYS_MAILBOX_CREATE:
                if (!UserMemory::Writable<int>(frame->arg1) || !UserMemory::Writable<int>(frame->arg2)) return -1;
                return Sys_MailboxCreate((int*)frame->arg1, (int*)frame->arg2);
            case SYS_MAILBOX_SEND:
                if (frame->arg4 > 0 && !UserMemory::Range(frame->arg3, frame->arg4, false)) return -1;
                return Sys_MailboxSend((int)frame->arg1, (uint32_t)frame->arg2,
                                       (const void*)frame->arg3, (uint16_t)frame->arg4,
                                       (int)frame->arg5);
            case SYS_MAILBOX_RECV:
                if (!UserMemory::Writable<uint16_t>(frame->arg4)) return -1;
                if (frame->arg2 != 0 && !UserMemory::Writable<uint32_t>(frame->arg2)) return -1;
                if (frame->arg3 != 0) {
                    uint16_t maxCopy = *(uint16_t*)frame->arg4;
                    if (!UserMemory::Range(frame->arg3, maxCopy, true)) return -1;
                }
                if (frame->arg5 != 0 && !UserMemory::Writable<int>(frame->arg5)) return -1;
                return Sys_MailboxRecv((int)frame->arg1,
                                       UserMemory::IsUserPtr(frame->arg2) ? (uint32_t*)frame->arg2 : nullptr,
                                       UserMemory::IsUserPtr(frame->arg3) ? (void*)frame->arg3 : nullptr,
                                       (uint16_t*)frame->arg4,
                                       UserMemory::IsUserPtr(frame->arg5) ? (int*)frame->arg5 : nullptr);
            case SYS_WAITSET_CREATE:
                return Sys_WaitsetCreate();
            case SYS_WAITSET_ADD:
                return Sys_WaitsetAdd((int)frame->arg1, (int)frame->arg2, (uint32_t)frame->arg3);
            case SYS_WAITSET_REMOVE:
                return Sys_WaitsetRemove((int)frame->arg1, (int)frame->arg2);
            case SYS_WAITSET_WAIT:
                if (frame->arg2 != 0 && !UserMemory::Writable<IpcWaitResult>(frame->arg2)) return -1;
                return Sys_WaitsetWait((int)frame->arg1,
                                       UserMemory::IsUserPtr(frame->arg2) ? (IpcWaitResult*)frame->arg2 : nullptr,
                                       frame->arg3);
            case SYS_PROC_OPEN:
                return Sys_ProcOpen((int)frame->arg1);
            case SYS_SURFACE_CREATE:
                return Sys_SurfaceCreate(frame->arg1);
            case SYS_SURFACE_MAP:
                return (int64_t)Sys_SurfaceMap((int)frame->arg1);
            case SYS_SURFACE_RESIZE:
                return Sys_SurfaceResize((int)frame->arg1, frame->arg2);
            case SYS_LOAD_LIB:
                if (!UserMemory::String(frame->arg1, 128)) return 0;
                return (int64_t)Sys_LoadLib((const char*)frame->arg1);
            case SYS_UNLOAD_LIB:
                return Sys_UnloadLib(frame->arg1);
            case SYS_DLSYM:
                return (int64_t)Sys_DLSym(frame->arg1, frame->arg2);
            case SYS_GETLIBBASE:
                return (int64_t)Sys_GetLibBase(frame->arg1);
            case SYS_CRASH_REPORT:
                if (!UserMemory::Writable<CrashReportInfo>(frame->arg1)) return -1;
                return Sys_CrashReport((CrashReportInfo*)frame->arg1);
            case SYS_CLIPBOARD_SET_TEXT:
                if (frame->arg2 > 0 && !UserMemory::Range(frame->arg1, frame->arg2, false)) return -1;
                return Sys_ClipboardSetText((const char*)frame->arg1, (uint32_t)frame->arg2);
            case SYS_CLIPBOARD_GET_INFO:
                if (!UserMemory::Writable<ClipboardInfo>(frame->arg1)) return -1;
                return Sys_ClipboardGetInfo((ClipboardInfo*)frame->arg1);
            case SYS_CLIPBOARD_GET_TEXT:
                if (frame->arg2 > 0 && !UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
                if (!UserMemory::Writable<uint32_t>(frame->arg3)) return -1;
                if (frame->arg4 != 0 && !UserMemory::Writable<uint64_t>(frame->arg4)) return -1;
                return Sys_ClipboardGetText(UserMemory::IsUserPtr(frame->arg1) ? (char*)frame->arg1 : nullptr,
                                           (uint32_t)frame->arg2,
                                           (uint32_t*)frame->arg3,
                                           UserMemory::IsUserPtr(frame->arg4) ? (uint64_t*)frame->arg4 : nullptr);
            case SYS_CLIPBOARD_CLEAR:
                return Sys_ClipboardClear();
            case SYS_INPUT_WAIT:
                return (int64_t)Sys_InputWait(frame->arg1, frame->arg2);
            default:
                return -1;
        }
    }

    // ---- SYSCALL MSR initialization ----

    void InitializeSyscalls() {
        // Enable SYSCALL/SYSRET in EFER
        uint64_t efer = Hal::ReadMSR(Hal::IA32_EFER);
        efer |= 1;  // SCE bit (Syscall Enable)
        Hal::WriteMSR(Hal::IA32_EFER, efer);

        // STAR: kernel CS in [47:32], sysret base in [63:48]
        // SYSCALL: CS=0x08, SS=0x10
        // SYSRET:  CS=0x10+16=0x20|RPL3=0x23, SS=0x10+8=0x18|RPL3=0x1B
        uint64_t star = (0x0010ULL << 48) | (0x0008ULL << 32);
        Hal::WriteMSR(Hal::IA32_STAR, star);

        // LSTAR: SYSCALL entry point
        Hal::WriteMSR(Hal::IA32_LSTAR, (uint64_t)SyscallEntry);

        // FMASK: mask IF on SYSCALL entry (bit 9 = IF)
        Hal::WriteMSR(Hal::IA32_FMASK, 0x200);

        Kt::KernelLogStream(Kt::OK, "Syscall") << "SYSCALL/SYSRET initialized (LSTAR="
            << kcp::hex << (uint64_t)SyscallEntry << kcp::dec << ", 124 syscall slots)";
    }

}
