Ryujinx uses High-Level Emulation (HLE) to simulate Nintendo Switch system services and the Horizon operating system. Instead of emulating the entire OS at the binary level, HLE reimplements OS functionality in C#, providing:
Performance
Direct C# implementations are faster than emulating ARM OS code
Compatibility
Handles version differences and missing firmware gracefully
Features
Enhanced functionality beyond real hardware (save states, cheats, mods)
// Each server processes IPC messages on dedicated threadSmServer = new ServerBase(KernelContext, "SmServer");FsServer = new ServerBase(KernelContext, "FsServer");HidServer = new ServerBase(KernelContext, "HidServer");
Shared Memory
Direct memory sharing between guest and services:
// HID shared memory for controller input (256 KB)HidSharedMem = CreateSharedMemory(hidPa, HidSize);// Font shared memory for text rendering (17 MB)FontSharedMem = CreateSharedMemory(fontPa, FontSize);
// From src/Ryujinx.HLE/HOS/Ipc/IpcMessage.cspublic class IpcMessage{ public IpcMessageType Type { get; set; } public List<IpcBuffDesc> BuffDescs { get; } // Buffer descriptors public List<IpcPtrBuffDesc> PtrBuffDescs { get; } // Pointer buffers public List<IpcRecvListBuffDesc> RecvListBuffs { get; } // Receive lists public List<int> ObjectIds { get; } // Domain object IDs public IpcHandleDesc HandleDesc { get; set; } // Handle transfer public byte[] RawData { get; set; } // Command data}
Message types:
public enum IpcMessageType{ Request = 4, // Standard service request Control = 5, // Control commands (convert to domain, etc.) CloseSession = 6, // Close service session RequestWithContext = 8 // Request with additional context}
Services can be converted to “domains” for efficient object management:
public int ConvertToDomain(){ if (_selfId == -1) { _selfId = _domainObjects.Add(this); } _isDomain = true; return _selfId;}public void CallCmifMethod(ServiceCtx context){ IpcService service = this; if (_isDomain) { int domainWord0 = context.RequestData.ReadInt32(); int domainObjId = context.RequestData.ReadInt32(); int domainCmd = (domainWord0 >> 0) & 0xff; if (domainCmd == 1) // Close object { _domainObjects.Delete(domainObjId); return; } // Route to specific domain object service = _domainObjects.GetObject<IpcService>(domainObjId); } // Invoke command on service int cmdId = context.Request.CommandId; // ...}
public class KThread : KSynchronizationObject{ public int ThreadId { get; } public KProcess Owner { get; } public ThreadState State { get; set; } public long LastScheduledTime { get; set; } private int _priority; public int Priority { get => _priority; set { if (_priority != value) { int oldPriority = _priority; _priority = value; Context.PriorityQueue.ChangePriority(this, oldPriority); } } } public ExecutionContext Context { get; } public ulong EntryPoint { get; set; }}
Scheduler implementation:
Preemptive multitasking
Priority-based scheduling (0-63, lower is higher priority)
public class VirtualFileSystem{ // Real file system paths public string BasePath { get; } public string SdCardPath { get; } // Virtual mounts public IFileSystem RomFs { get; set; } // Game RomFS public IFileSystem SaveData { get; set; } // Save data public IFileSystem SystemSaveData { get; set; } // System saves // Content management public void LoadRomFs(string path) { // Mount game RomFS from NSP/XCI/directory } public void CreateSaveData(ulong titleId, SaveDataType type) { // Create save data container }}
public struct ResultCode{ public uint Value { get; } public int Module => (int)((Value >> 0) & 0x1FF); public int Description => (int)((Value >> 9) & 0x1FFF); public static ResultCode Success => new ResultCode(0); // Common results public static ResultCode ModuleNotFound => new ResultCode(0x202); public static ResultCode OutOfMemory => new ResultCode(0xC2); public static ResultCode InvalidAddress => new ResultCode(0xCC);}