#![no_std]
#![cfg_attr(feature = "rustc-dep-of-std", feature(staged_api))]
#![recursion_limit="128"]
#![warn(unused)]
#![warn(missing_debug_implementations)]
#![allow(unused_unsafe)]
#![allow(unreachable_code)]
#![allow(dead_code)]
#![cfg_attr(test, allow(unused_imports))]
#![allow(non_upper_case_globals)]
#![warn(missing_docs)]
#![deny(intra_doc_link_resolution_failure)]
#[macro_use]
extern crate sunrise_libutils;
#[macro_use]
extern crate bitflags;
#[macro_use]
extern crate lazy_static;
pub mod error;
use core::fmt;
use static_assertions::assert_eq_size;
use core::mem::size_of;
pub mod process;
bitflags! {
#[derive(Default)]
pub struct MemoryState: u32 {
const TY = 0xFF;
const PERMISSION_CHANGE_ALLOWED = 1 << 8;
const FORCE_READ_WRITABLE_BY_DEBUG_SYSCALLS = 1 << 9;
const IPC_SEND_ALLOWED = 1 << 10;
const NON_DEVICE_IPC_SEND_ALLOWED = 1 << 11;
const NON_SECURE_IPC_SEND_ALLOWED = 1 << 12;
const PROCESS_PERMISSION_CHANGE_ALLOWED = 1 << 14;
const MAP_ALLOWED = 1 << 15;
const UNMAP_PROCESS_CODE_MEMORY_ALLOWED = 1 << 16;
const TRANSFER_MEMORY_ALLOWED = 1 << 17;
const QUERY_PHYSICAL_ADDRESS_ALLOWED = 1 << 18;
const MAP_DEVICE_ALLOWED = 1 << 19;
const MAP_DEVICE_ALIGNED_ALLOWED = 1 << 20;
const IPC_BUFFER_ALLOWED = 1 << 21;
const IS_REFERENCE_COUNTED = 1 << 22;
const MAP_PROCESS_ALLOWED = 1 << 23;
const ATTRIBUTE_CHANGE_ALLOWED = 1 << 24;
const CODE_MEMORY_ALLOWED = 1 << 25;
const ALL_IPC_SEND_ALLOWED = Self::IPC_SEND_ALLOWED.bits |
Self::NON_DEVICE_IPC_SEND_ALLOWED.bits |
Self::NON_SECURE_IPC_SEND_ALLOWED.bits;
const CAN_IOMMU = Self::QUERY_PHYSICAL_ADDRESS_ALLOWED.bits |
Self::MAP_DEVICE_ALLOWED.bits |
Self::MAP_DEVICE_ALIGNED_ALLOWED.bits;
}
}
impl MemoryState {
pub fn ty(self) -> MemoryType {
match self.bits & Self::TY.bits {
0x00 => MemoryType::Unmapped,
0x01 => MemoryType::Io,
0x02 => MemoryType::Normal,
0x03 => MemoryType::CodeStatic,
0x04 => MemoryType::CodeMutable,
0x05 => MemoryType::Heap,
0x06 => MemoryType::SharedMemory,
0x07 => MemoryType::Alias,
0x08 => MemoryType::ModuleCodeStatic,
0x09 => MemoryType::ModuleCodeMutable,
0x0A => MemoryType::Ipc,
0x0B => MemoryType::Stack,
0x0C => MemoryType::ThreadLocal,
0x0D => MemoryType::TransferMemoryIsolated,
0x0E => MemoryType::TransferMemory,
0x0F => MemoryType::ProcessMemory,
0x10 => MemoryType::Reserved,
0x11 => MemoryType::NonSecureIpc,
0x12 => MemoryType::NonDeviceIpc,
0x13 => MemoryType::KernelStack,
0x14 => MemoryType::CodeReadOnly,
0x15 => MemoryType::CodeWritable,
_ => MemoryType::Reserved,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MemoryType {
Unmapped = 0,
Io = 1,
Normal = 2,
CodeStatic = 3,
CodeMutable = 4,
Heap = 5,
SharedMemory = 6,
Alias = 7,
ModuleCodeStatic = 8,
ModuleCodeMutable = 9,
Ipc = 0xA,
Stack = 0xB,
ThreadLocal = 0xC,
TransferMemoryIsolated = 0xD,
TransferMemory = 0xE,
ProcessMemory = 0xF,
Reserved = 0x10,
NonSecureIpc = 0x11,
NonDeviceIpc = 0x12,
KernelStack = 0x13,
CodeReadOnly = 0x14,
CodeWritable = 0x15,
}
impl MemoryType {
pub fn get_memory_state(self) -> MemoryState {
match self {
MemoryType::Unmapped => MemoryState::from_bits_truncate(0x00000000),
MemoryType::Io => MemoryState::from_bits_truncate(0x00002001),
MemoryType::Normal => MemoryState::from_bits_truncate(0x00042002),
MemoryType::CodeStatic => MemoryState::from_bits_truncate(0x00DC7E03),
MemoryType::CodeMutable => MemoryState::from_bits_truncate(0x03FEBD04),
MemoryType::Heap => MemoryState::from_bits_truncate(0x037EBD05),
MemoryType::SharedMemory => MemoryState::from_bits_truncate(0x00402006),
MemoryType::Alias => MemoryState::from_bits_truncate(0x00482907),
MemoryType::ModuleCodeStatic => MemoryState::from_bits_truncate(0x00DD7E08),
MemoryType::ModuleCodeMutable => MemoryState::from_bits_truncate(0x03FFBD09),
MemoryType::Ipc => MemoryState::from_bits_truncate(0x005C3C0A),
MemoryType::Stack => MemoryState::from_bits_truncate(0x005C3C0B),
MemoryType::ThreadLocal => MemoryState::from_bits_truncate(0x0040200C),
MemoryType::TransferMemoryIsolated => MemoryState::from_bits_truncate(0x015C3C0D),
MemoryType::TransferMemory => MemoryState::from_bits_truncate(0x005C380E),
MemoryType::ProcessMemory => MemoryState::from_bits_truncate(0x0040380F),
MemoryType::Reserved => MemoryState::from_bits_truncate(0x00000010),
MemoryType::NonSecureIpc => MemoryState::from_bits_truncate(0x005C3811),
MemoryType::NonDeviceIpc => MemoryState::from_bits_truncate(0x004C2812),
MemoryType::KernelStack => MemoryState::from_bits_truncate(0x00002013),
MemoryType::CodeReadOnly => MemoryState::from_bits_truncate(0x00402214),
MemoryType::CodeWritable => MemoryState::from_bits_truncate(0x00402015),
}
}
}
bitflags! {
#[derive(Default)]
pub struct MemoryAttributes : u32 {
const BORROWED = 1 << 0;
const IPC_MAPPED = 1 << 0;
const DEVICE_MAPPED = 1 << 2;
const UNCACHED = 1 << 3;
}
}
bitflags! {
#[derive(Default)]
pub struct MemoryPermissions : u32 {
const READABLE = 1 << 0;
const WRITABLE = 1 << 1;
const EXECUTABLE = 1 << 2;
const RO = MemoryPermissions::READABLE.bits();
const RW = MemoryPermissions::READABLE.bits() | MemoryPermissions::WRITABLE.bits();
const RX = MemoryPermissions::READABLE.bits() | MemoryPermissions::EXECUTABLE.bits();
}
}
impl MemoryPermissions {
pub fn check(self) -> Result<(), error::KernelError> {
if 1 << self.bits() & 0x2B != 0 {
Ok(())
} else {
Err(error::KernelError::InvalidMemPerms)
}
}
}
#[repr(C)]
#[derive(Debug, Default)]
pub struct MemoryInfo {
pub baseaddr: usize,
pub size: usize,
pub memtype: MemoryState,
pub memattr: MemoryAttributes,
pub perms: MemoryPermissions,
pub ipc_ref_count: u32,
pub device_ref_count: u32,
}
pub type IpcBuffer = [u8; 0x100];
#[repr(C, align(16))]
pub struct TLS {
pub ptr_self: *mut TLS,
_reserved0: [u8; 16 - size_of::<*mut TLS>()],
pub ipc_command_buffer: IpcBuffer,
_reserved1: [u8; 0x200 - 16 - size_of::<IpcBuffer>() - size_of::<usize>()],
pub ptr_thread_context: usize,
}
impl fmt::Debug for TLS {
fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
f.debug_struct("TLS")
.field("ipc_command_buffer_address", &(&self.ipc_command_buffer as *const u8))
.field("ptr_thread_context", &(self.ptr_thread_context as *const u8))
.finish()
}
}
assert_eq_size!(TLS, [u8; 0x200]);
macro_rules! syscalls {
(
static $byname:ident;
mod $byid:ident;
$($name:ident = $id:expr,)*
---
$max_svc_ident:ident = $max_svc_id:expr
) => {
#[cfg_attr(feature = "rustc-dep-of-std", stable(feature = "rust1", since = "1.0.0"))]
pub mod $byid {
#![allow(missing_docs)]
$(
#[allow(non_upper_case_globals)]
#[cfg_attr(feature = "rustc-dep-of-std", stable(feature = "rust1", since = "1.0.0"))]
pub const $name: usize = $id;
)*
#[allow(non_upper_case_globals)]
#[cfg_attr(feature = "rustc-dep-of-std", stable(feature = "rust1", since = "1.0.0"))]
pub const $max_svc_ident: usize = $max_svc_id;
}
lazy_static! {
pub static ref $byname: [&'static str; $max_svc_id + 1] = {
let mut arr = ["Unknown"; $max_svc_id + 1];
$(arr[$id] = stringify!($name);)*
arr
};
}
}
}
syscalls! {
static SYSCALL_NAMES;
mod nr;
SetHeapSize = 0x01,
SetMemoryPermission = 0x02,
SetMemoryAttribute = 0x03,
MapMemory = 0x04,
UnmapMemory = 0x05,
QueryMemory = 0x06,
ExitProcess = 0x07,
CreateThread = 0x08,
StartThread = 0x09,
ExitThread = 0x0A,
SleepThread = 0x0B,
GetThreadPriority = 0x0C,
SetThreadPriority = 0x0D,
GetThreadCoreMask = 0x0E,
SetThreadCoreMask = 0x0F,
GetCurrentProcessorNumber = 0x10,
SignalEvent = 0x11,
ClearEvent = 0x12,
MapSharedMemory = 0x13,
UnmapSharedMemory = 0x14,
CreateTransferMemory = 0x15,
CloseHandle = 0x16,
ResetSignal = 0x17,
WaitSynchronization = 0x18,
CancelSynchronization = 0x19,
ArbitrateLock = 0x1A,
ArbitrateUnlock = 0x1B,
WaitProcessWideKeyAtomic = 0x1C,
SignalProcessWideKey = 0x1D,
GetSystemTick = 0x1E,
ConnectToNamedPort = 0x1F,
SendSyncRequestLight = 0x20,
SendSyncRequest = 0x21,
SendSyncRequestWithUserBuffer = 0x22,
SendAsyncRequestWithUserBuffer = 0x23,
GetProcessId = 0x24,
GetThreadId = 0x25,
Break = 0x26,
OutputDebugString = 0x27,
ReturnFromException = 0x28,
GetInfo = 0x29,
FlushEntireDataCache = 0x2A,
FlushDataCache = 0x2B,
MapPhysicalMemory = 0x2C,
UnmapPhysicalMemory = 0x2D,
GetFutureThreadInfo = 0x2E,
GetLastThreadInfo = 0x2F,
GetResourceLimitLimitValue = 0x30,
GetResourceLimitCurrentValue = 0x31,
SetThreadActivity = 0x32,
GetThreadContext3 = 0x33,
WaitForAddress = 0x34,
SignalToAddress = 0x35,
DumpInfo = 0x3C,
DumpInfoNew = 0x3D,
CreateSession = 0x40,
AcceptSession = 0x41,
ReplyAndReceiveLight = 0x42,
ReplyAndReceive = 0x43,
ReplyAndReceiveWithUserBuffer = 0x44,
CreateEvent = 0x45,
MapPhysicalMemoryUnsafe = 0x48,
UnmapPhysicalMemoryUnsafe = 0x49,
SetUnsafeLimit = 0x4A,
CreateCodeMemory = 0x4B,
ControlCodeMemory = 0x4C,
SleepSystem = 0x4D,
ReadWriteRegister = 0x4E,
SetProcessActivity = 0x4F,
CreateSharedMemory = 0x50,
MapTransferMemory = 0x51,
UnmapTransferMemory = 0x52,
CreateInterruptEvent = 0x53,
QueryPhysicalAddress = 0x54,
QueryIoMapping = 0x55,
CreateDeviceAddressSpace = 0x56,
AttachDeviceAddressSpace = 0x57,
DetachDeviceAddressSpace = 0x58,
MapDeviceAddressSpaceByForce = 0x59,
MapDeviceAddressSpaceAligned = 0x5A,
MapDeviceAddressSpace = 0x5B,
UnmapDeviceAddressSpace = 0x5C,
InvalidateProcessDataCache = 0x5D,
StoreProcessDataCache = 0x5E,
FlushProcessDataCache = 0x5F,
DebugActiveProcess = 0x60,
BreakDebugProcess = 0x61,
TerminateDebugProcess = 0x62,
GetDebugEvent = 0x63,
ContinueDebugEvent = 0x64,
GetProcessList = 0x65,
GetThreadList = 0x66,
GetDebugThreadContext = 0x67,
SetDebugThreadContext = 0x68,
QueryDebugProcessMemory = 0x69,
ReadDebugProcessMemory = 0x6A,
WriteDebugProcessMemory = 0x6B,
SetHardwareBreakPoint = 0x6C,
GetDebugThreadParam = 0x6D,
GetSystemInfo = 0x6F,
CreatePort = 0x70,
ManageNamedPort = 0x71,
ConnectToPort = 0x72,
SetProcessMemoryPermission = 0x73,
MapProcessMemory = 0x74,
UnmapProcessMemory = 0x75,
QueryProcessMemory = 0x76,
MapProcessCodeMemory = 0x77,
UnmapProcessCodeMemory = 0x78,
CreateProcess = 0x79,
StartProcess = 0x7A,
TerminateProcess = 0x7B,
GetProcessInfo = 0x7C,
CreateResourceLimit = 0x7D,
SetResourceLimitLimitValue = 0x7E,
CallSecureMonitor = 0x7F,
MapFramebuffer = 0x80,
StartProcessEntrypoint = 0x81,
MapMmioRegion = 0x82,
SetThreadArea = 0x83,
---
MaxSvc = 0x83
}