2020-04-19 23:04:05 +02:00
// SPDX-License-Identifier: MPL-2.0
2020-03-27 20:36:02 +01:00
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
2019-10-13 10:04:47 +02:00
# include <os.h>
2020-09-28 12:05:17 +02:00
# include <kernel/types/KProcess.h>
2020-11-20 19:27:53 +01:00
# include <vfs/npdm.h>
2020-09-03 20:43:52 +02:00
# include "results.h"
2020-03-26 15:33:19 +01:00
# include "svc.h"
2019-09-24 22:54:27 +02:00
namespace skyline : : kernel : : svc {
2020-10-10 17:53:14 +02:00
void SetHeapSize ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
u32 size { state . ctx - > gpr . w1 } ;
2020-03-25 18:59:37 +01:00
2020-04-22 19:02:27 +02:00
if ( ! util : : IsAligned ( size , 0x200000 ) ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidSize ;
state . ctx - > gpr . x1 = 0 ;
2020-03-25 18:59:37 +01:00
2019-11-17 21:19:01 +01:00
state . logger - > Warn ( " svcSetHeapSize: 'size' not divisible by 2MB: {} " , size ) ;
return ;
}
2020-03-25 18:59:37 +01:00
2020-09-26 07:17:57 +02:00
auto & heap { state . process - > heap } ;
2020-01-21 08:16:57 +01:00
heap - > Resize ( size ) ;
2020-03-25 18:59:37 +01:00
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
state . ctx - > gpr . x1 = reinterpret_cast < u64 > ( heap - > ptr ) ;
2020-03-25 18:59:37 +01:00
2020-10-17 13:38:27 +02:00
state . logger - > Debug ( " svcSetHeapSize: Allocated at 0x{:X} - 0x{:X} (0x{:X} bytes) " , heap - > ptr , heap - > ptr + heap - > size , heap - > size ) ;
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
}
2020-10-10 17:53:14 +02:00
void SetMemoryAttribute ( const DeviceState & state ) {
auto pointer { reinterpret_cast < u8 * > ( state . ctx - > gpr . x0 ) } ;
2020-10-04 20:18:34 +02:00
if ( ! util : : PageAligned ( pointer ) ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidAddress ;
2020-10-05 11:19:23 +02:00
state . logger - > Warn ( " svcSetMemoryAttribute: 'pointer' not page aligned: 0x{:X} " , pointer ) ;
2019-11-17 21:19:01 +01:00
return ;
}
2020-04-18 23:40:18 +02:00
2020-10-20 11:22:15 +02:00
size_t size { state . ctx - > gpr . x1 } ;
2020-04-17 23:19:19 +02:00
if ( ! util : : PageAligned ( size ) ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidSize ;
2020-01-21 08:16:57 +01:00
state . logger - > Warn ( " svcSetMemoryAttribute: 'size' {}: 0x{:X} " , size ? " not page aligned " : " is zero " , size ) ;
2019-11-17 21:19:01 +01:00
return ;
}
2020-04-18 23:40:18 +02:00
2020-10-10 17:53:14 +02:00
memory : : MemoryAttribute mask { . value = state . ctx - > gpr . w2 } ;
memory : : MemoryAttribute value { . value = state . ctx - > gpr . w3 } ;
2020-04-18 23:40:18 +02:00
2020-09-26 07:17:57 +02:00
auto maskedValue { mask . value | value . value } ;
2020-01-21 08:16:57 +01:00
if ( maskedValue ! = mask . value | | ! mask . isUncached | | mask . isDeviceShared | | mask . isBorrowed | | mask . isIpcLocked ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidCombination ;
2020-01-21 08:16:57 +01:00
state . logger - > Warn ( " svcSetMemoryAttribute: 'mask' invalid: 0x{:X}, 0x{:X} " , mask . value , value . value ) ;
2019-11-17 21:19:01 +01:00
return ;
}
2020-04-18 23:40:18 +02:00
2020-10-07 17:41:13 +02:00
auto chunk { state . process - > memory . Get ( pointer ) } ;
2020-10-04 18:40:52 +02:00
if ( ! chunk ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidAddress ;
2020-10-05 11:19:23 +02:00
state . logger - > Warn ( " svcSetMemoryAttribute: Cannot find memory region: 0x{:X} " , pointer ) ;
2020-01-21 08:16:57 +01:00
return ;
}
2020-04-18 23:40:18 +02:00
2020-03-25 18:59:37 +01:00
if ( ! chunk - > state . attributeChangeAllowed ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidState ;
2020-10-05 11:19:23 +02:00
state . logger - > Warn ( " svcSetMemoryAttribute: Attribute change not allowed for chunk: 0x{:X} " , pointer ) ;
2020-01-21 08:16:57 +01:00
return ;
}
2020-04-18 23:40:18 +02:00
2020-10-04 18:40:52 +02:00
auto newChunk { * chunk } ;
2020-10-04 20:18:34 +02:00
newChunk . ptr = pointer ;
2020-10-04 18:40:52 +02:00
newChunk . size = size ;
newChunk . attributes . isUncached = value . isUncached ;
2020-10-07 17:41:13 +02:00
state . process - > memory . InsertChunk ( newChunk ) ;
2020-04-18 23:40:18 +02:00
2020-12-22 14:38:37 +01:00
state . logger - > Debug ( " svcSetMemoryAttribute: Set CPU caching to {} at 0x{:X} - 0x{:X} (0x{:X} bytes) " , ! static_cast < bool > ( value . isUncached ) , pointer , pointer + size , size ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
2020-01-21 08:16:57 +01:00
}
2020-10-10 17:53:14 +02:00
void MapMemory ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
auto destination { reinterpret_cast < u8 * > ( state . ctx - > gpr . x0 ) } ;
auto source { reinterpret_cast < u8 * > ( state . ctx - > gpr . x1 ) } ;
size_t size { state . ctx - > gpr . x2 } ;
2020-04-18 23:40:18 +02:00
2020-04-17 23:19:19 +02:00
if ( ! util : : PageAligned ( destination ) | | ! util : : PageAligned ( source ) ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidAddress ;
2020-10-05 11:19:23 +02:00
state . logger - > Warn ( " svcMapMemory: Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) " , source , destination , size ) ;
2020-01-21 08:16:57 +01:00
return ;
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
}
2020-04-18 23:40:18 +02:00
2020-04-17 23:19:19 +02:00
if ( ! util : : PageAligned ( size ) ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidSize ;
2020-01-21 08:16:57 +01:00
state . logger - > Warn ( " svcMapMemory: 'size' {}: 0x{:X} " , size ? " not page aligned " : " is zero " , size ) ;
return ;
}
2020-04-18 23:40:18 +02:00
2020-10-07 17:41:13 +02:00
auto stack { state . process - > memory . stack } ;
2020-02-05 07:42:53 +01:00
if ( ! stack . IsInside ( destination ) ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidMemoryRegion ;
2020-10-05 11:19:23 +02:00
state . logger - > Warn ( " svcMapMemory: Destination not within stack region: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) " , source , destination , size ) ;
2020-01-21 08:16:57 +01:00
return ;
}
2020-03-25 19:57:05 +01:00
2020-10-07 17:41:13 +02:00
auto chunk { state . process - > memory . Get ( source ) } ;
2020-10-04 18:40:52 +02:00
if ( ! chunk ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidAddress ;
2020-10-05 11:19:23 +02:00
state . logger - > Warn ( " svcMapMemory: Source has no descriptor: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) " , source , destination , size ) ;
2020-01-21 08:16:57 +01:00
return ;
}
2020-10-04 18:40:52 +02:00
if ( ! chunk - > state . mapAllowed ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidState ;
2020-10-05 11:19:23 +02:00
state . logger - > Warn ( " svcMapMemory: Source doesn't allow usage of svcMapMemory: Source: 0x{:X}, Destination: 0x{:X}, Size: 0x{:X}, MemoryState: 0x{:X} " , source , destination , size , chunk - > state . value ) ;
2019-11-17 21:19:01 +01:00
return ;
}
2020-03-25 19:57:05 +01:00
2020-10-04 18:40:52 +02:00
state . process - > NewHandle < type : : KPrivateMemory > ( destination , size , chunk - > permission , memory : : states : : Stack ) ;
2020-11-22 10:41:01 +01:00
std : : memcpy ( destination , source , size ) ;
2020-03-25 19:57:05 +01:00
2020-09-26 07:17:57 +02:00
auto object { state . process - > GetMemoryObject ( source ) } ;
2020-02-05 07:42:53 +01:00
if ( ! object )
2020-10-05 11:19:23 +02:00
throw exception ( " svcMapMemory: Cannot find memory object in handle table for address 0x{:X} " , source ) ;
2020-02-01 16:51:32 +01:00
object - > item - > UpdatePermission ( source , size , { false , false , false } ) ;
2020-03-25 19:57:05 +01:00
2020-10-10 19:40:12 +02:00
state . logger - > Debug ( " svcMapMemory: Mapped range 0x{:X} - 0x{:X} to 0x{:X} - 0x{:X} (Size: 0x{:X} bytes) " , source , source + size , destination , destination + size , size ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
2019-09-24 22:54:27 +02:00
}
2020-10-10 17:53:14 +02:00
void UnmapMemory ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
auto source { reinterpret_cast < u8 * > ( state . ctx - > gpr . x0 ) } ;
auto destination { reinterpret_cast < u8 * > ( state . ctx - > gpr . x1 ) } ;
size_t size { state . ctx - > gpr . x2 } ;
2020-03-25 19:57:05 +01:00
2020-04-17 23:19:19 +02:00
if ( ! util : : PageAligned ( destination ) | | ! util : : PageAligned ( source ) ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidAddress ;
2020-02-01 16:51:32 +01:00
state . logger - > Warn ( " svcUnmapMemory: Addresses not page aligned: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) " , source , destination , size ) ;
return ;
}
2020-03-25 19:57:05 +01:00
2020-04-17 23:19:19 +02:00
if ( ! util : : PageAligned ( size ) ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidSize ;
2020-02-01 16:51:32 +01:00
state . logger - > Warn ( " svcUnmapMemory: 'size' {}: 0x{:X} " , size ? " not page aligned " : " is zero " , size ) ;
return ;
}
2020-03-25 19:57:05 +01:00
2020-10-07 17:41:13 +02:00
auto stack { state . process - > memory . stack } ;
2020-02-05 07:42:53 +01:00
if ( ! stack . IsInside ( source ) ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidMemoryRegion ;
2020-02-01 16:51:32 +01:00
state . logger - > Warn ( " svcUnmapMemory: Source not within stack region: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) " , source , destination , size ) ;
return ;
}
2020-03-25 19:57:05 +01:00
2020-10-07 17:41:13 +02:00
auto sourceChunk { state . process - > memory . Get ( source ) } ;
auto destChunk { state . process - > memory . Get ( destination ) } ;
2020-10-04 18:40:52 +02:00
if ( ! sourceChunk | | ! destChunk ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidAddress ;
2020-02-01 16:51:32 +01:00
state . logger - > Warn ( " svcUnmapMemory: Addresses have no descriptor: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) " , source , destination , size ) ;
return ;
}
2020-03-25 19:57:05 +01:00
2020-10-04 18:40:52 +02:00
if ( ! destChunk - > state . mapAllowed ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidState ;
2020-10-04 18:40:52 +02:00
state . logger - > Warn ( " svcUnmapMemory: Destination doesn't allow usage of svcMapMemory: Source: 0x{:X}, Destination: 0x{:X} (Size: 0x{:X} bytes) 0x{:X} " , source , destination , size , destChunk - > state . value ) ;
2020-02-01 16:51:32 +01:00
return ;
}
2020-03-25 19:57:05 +01:00
2020-09-26 07:17:57 +02:00
auto destObject { state . process - > GetMemoryObject ( destination ) } ;
2020-02-05 07:42:53 +01:00
if ( ! destObject )
2020-02-01 16:51:32 +01:00
throw exception ( " svcUnmapMemory: Cannot find destination memory object in handle table for address 0x{:X} " , destination ) ;
2020-03-25 19:57:05 +01:00
2020-10-04 18:40:52 +02:00
destObject - > item - > UpdatePermission ( destination , size , sourceChunk - > permission ) ;
2020-03-25 19:57:05 +01:00
2020-10-04 18:40:52 +02:00
std : : memcpy ( source , destination , size ) ;
2020-03-25 19:57:05 +01:00
2020-11-03 10:44:09 +01:00
auto sourceObject { state . process - > GetMemoryObject ( source ) } ;
2020-02-05 07:42:53 +01:00
if ( ! sourceObject )
2020-02-01 16:51:32 +01:00
throw exception ( " svcUnmapMemory: Cannot find source memory object in handle table for address 0x{:X} " , source ) ;
2020-03-25 19:57:05 +01:00
2020-09-28 12:05:17 +02:00
state . process - > CloseHandle ( sourceObject - > handle ) ;
2020-03-25 19:57:05 +01:00
2020-02-01 16:51:32 +01:00
state . logger - > Debug ( " svcUnmapMemory: Unmapped range 0x{:X} - 0x{:X} to 0x{:X} - 0x{:X} (Size: 0x{:X} bytes) " , source , source + size , destination , destination + size , size ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
2020-02-01 16:51:32 +01:00
}
2020-10-10 17:53:14 +02:00
void QueryMemory ( const DeviceState & state ) {
2020-01-01 14:11:25 +01:00
memory : : MemoryInfo memInfo { } ;
2020-03-25 19:57:05 +01:00
2020-10-20 11:22:15 +02:00
auto pointer { reinterpret_cast < u8 * > ( state . ctx - > gpr . x2 ) } ;
2020-10-07 17:41:13 +02:00
auto chunk { state . process - > memory . Get ( pointer ) } ;
2020-03-25 19:57:05 +01:00
2020-10-04 18:40:52 +02:00
if ( chunk ) {
2020-01-21 08:16:57 +01:00
memInfo = {
2020-10-04 18:40:52 +02:00
. address = reinterpret_cast < u64 > ( chunk - > ptr ) ,
. size = chunk - > size ,
. type = static_cast < u32 > ( chunk - > state . type ) ,
. attributes = chunk - > attributes . value ,
. permissions = static_cast < u32 > ( chunk - > permission . Get ( ) ) ,
2020-01-21 08:16:57 +01:00
. deviceRefCount = 0 ,
. ipcRefCount = 0 ,
} ;
2020-03-25 19:57:05 +01:00
2020-10-28 17:00:39 +01:00
state . logger - > Debug ( " svcQueryMemory: Address: 0x{:X}, Region Start: 0x{:X}, Size: 0x{:X}, Type: 0x{:X}, Is Uncached: {}, Permissions: {}{}{} " , pointer , memInfo . address , memInfo . size , memInfo . type , static_cast < bool > ( chunk - > attributes . isUncached ) , chunk - > permission . r ? ' R ' : ' - ' , chunk - > permission . w ? ' W ' : ' - ' , chunk - > permission . x ? ' X ' : ' - ' ) ;
2020-01-21 08:16:57 +01:00
} else {
2020-10-07 17:41:13 +02:00
auto addressSpaceEnd { reinterpret_cast < u64 > ( state . process - > memory . addressSpace . address + state . process - > memory . addressSpace . size ) } ;
2020-03-25 19:57:05 +01:00
2020-01-21 08:16:57 +01:00
memInfo = {
2020-07-05 22:21:08 +02:00
. address = addressSpaceEnd ,
. size = ~ addressSpaceEnd + 1 ,
. type = static_cast < u32 > ( memory : : MemoryType : : Reserved ) ,
2020-01-21 08:16:57 +01:00
} ;
2020-03-25 19:57:05 +01:00
2020-10-05 11:19:23 +02:00
state . logger - > Debug ( " svcQueryMemory: Trying to query memory outside of the application's address space: 0x{:X} " , pointer ) ;
2019-09-24 22:54:27 +02:00
}
2020-03-25 19:57:05 +01:00
2020-10-20 11:22:15 +02:00
* reinterpret_cast < memory : : MemoryInfo * > ( state . ctx - > gpr . x0 ) = memInfo ;
2020-03-25 19:57:05 +01:00
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
2019-09-24 22:54:27 +02:00
}
2020-10-10 17:53:14 +02:00
void ExitProcess ( const DeviceState & state ) {
2020-10-07 17:41:13 +02:00
state . logger - > Debug ( " svcExitProcess: Exiting process " ) ;
2020-11-03 10:44:09 +01:00
if ( state . thread - > id )
2020-11-17 01:48:41 +01:00
state . process - > Kill ( false ) ;
2020-11-03 10:44:09 +01:00
std : : longjmp ( state . thread - > originalCtx , true ) ;
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
}
2020-10-21 19:09:35 +02:00
constexpr i32 IdealCoreDontCare { - 1 } ;
constexpr i32 IdealCoreUseProcessValue { - 2 } ;
constexpr i32 IdealCoreNoUpdate { - 3 } ;
2020-10-10 17:53:14 +02:00
void CreateThread ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
auto entry { reinterpret_cast < void * > ( state . ctx - > gpr . x1 ) } ;
2020-10-10 17:53:14 +02:00
auto entryArgument { state . ctx - > gpr . x2 } ;
2020-10-20 11:22:15 +02:00
auto stackTop { reinterpret_cast < u8 * > ( state . ctx - > gpr . x3 ) } ;
auto priority { static_cast < i8 > ( static_cast < u32 > ( state . ctx - > gpr . w4 ) ) } ;
2020-10-21 19:09:35 +02:00
auto idealCore { static_cast < i8 > ( static_cast < u32 > ( state . ctx - > gpr . w5 ) ) } ;
idealCore = ( idealCore = = IdealCoreUseProcessValue ) ? state . process - > npdm . meta . idealCore : idealCore ;
if ( idealCore < 0 | | idealCore > = constant : : CoreCount ) {
state . ctx - > gpr . w0 = result : : InvalidCoreId ;
state . logger - > Warn ( " svcCreateThread: 'idealCore' invalid: {} " , idealCore ) ;
return ;
}
2020-03-25 19:57:05 +01:00
2020-11-20 19:27:53 +01:00
if ( ! state . process - > npdm . threadInfo . priority . Valid ( priority ) ) {
2020-10-21 19:09:35 +02:00
state . ctx - > gpr . w0 = result : : InvalidPriority ;
2019-11-22 15:59:50 +01:00
state . logger - > Warn ( " svcCreateThread: 'priority' invalid: {} " , priority ) ;
2019-11-17 21:19:01 +01:00
return ;
}
2020-03-25 19:57:05 +01:00
2020-10-07 17:41:13 +02:00
auto stack { state . process - > GetMemoryObject ( stackTop ) } ;
if ( ! stack )
throw exception ( " svcCreateThread: Cannot find memory object in handle table for thread stack: 0x{:X} " , stackTop ) ;
2020-10-21 19:09:35 +02:00
auto thread { state . process - > CreateThread ( entry , entryArgument , stackTop , priority , idealCore ) } ;
2020-11-17 01:48:41 +01:00
if ( thread ) {
2020-11-20 19:27:53 +01:00
state . logger - > Debug ( " svcCreateThread: Created thread #{} with handle 0x{:X} (Entry Point: 0x{:X}, Argument: 0x{:X}, Stack Pointer: 0x{:X}, Priority: {}, Ideal Core: {}) " , thread - > id , thread - > handle , entry , entryArgument , stackTop , priority , idealCore ) ;
2020-03-25 19:57:05 +01:00
2020-11-17 01:48:41 +01:00
state . ctx - > gpr . w1 = thread - > handle ;
state . ctx - > gpr . w0 = Result { } ;
} else {
state . ctx - > gpr . w1 = 0 ;
state . ctx - > gpr . w0 = result : : OutOfResource ;
}
2019-09-24 22:54:27 +02:00
}
2020-10-10 17:53:14 +02:00
void StartThread ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
KHandle handle { state . ctx - > gpr . w0 } ;
2019-11-17 21:19:01 +01:00
try {
2020-09-26 07:17:57 +02:00
auto thread { state . process - > GetHandle < type : : KThread > ( handle ) } ;
2020-12-22 14:38:37 +01:00
state . logger - > Debug ( " svcStartThread: Starting thread #{}: 0x{:X} " , thread - > id , handle ) ;
2019-11-17 21:19:01 +01:00
thread - > Start ( ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
2020-10-23 20:23:16 +02:00
} catch ( const std : : out_of_range & ) {
2019-11-17 21:19:01 +01:00
state . logger - > Warn ( " svcStartThread: 'handle' invalid: 0x{:X} " , handle ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidHandle ;
2019-11-17 21:19:01 +01:00
}
2019-09-24 22:54:27 +02:00
}
2020-10-10 17:53:14 +02:00
void ExitThread ( const DeviceState & state ) {
2020-12-15 19:54:08 +01:00
state . logger - > Debug ( " svcExitThread: Exiting current thread " ) ;
2020-11-03 10:44:09 +01:00
std : : longjmp ( state . thread - > originalCtx , true ) ;
2019-09-24 22:54:27 +02:00
}
2020-10-10 17:53:14 +02:00
void SleepThread ( const DeviceState & state ) {
2020-12-05 18:41:52 +01:00
constexpr i64 yieldWithoutCoreMigration { 0 } ;
constexpr i64 yieldWithCoreMigration { - 1 } ;
constexpr i64 yieldToAnyThread { - 2 } ;
2020-11-22 10:41:01 +01:00
i64 in { static_cast < i64 > ( state . ctx - > gpr . x0 ) } ;
2020-12-05 18:41:52 +01:00
if ( in > 0 ) {
state . logger - > Debug ( " svcSleepThread: Thread sleeping for {} ns " , in ) ;
struct timespec spec {
. tv_sec = static_cast < time_t > ( in / 1000000000 ) ,
. tv_nsec = static_cast < long > ( in % 1000000000 ) ,
} ;
2020-12-22 14:38:37 +01:00
SchedulerScopedLock schedulerLock ( state ) ;
2020-12-05 18:41:52 +01:00
nanosleep ( & spec , nullptr ) ;
2020-12-22 14:38:37 +01:00
} else {
switch ( in ) {
case yieldWithCoreMigration :
state . logger - > Debug ( " svcSleepThread: Waking any appropriate parked threads " ) ;
state . scheduler - > WakeParkedThread ( ) ;
case yieldWithoutCoreMigration :
state . logger - > Debug ( " svcSleepThread: Cooperative Yield " ) ;
state . scheduler - > Rotate ( ) ;
state . scheduler - > WaitSchedule ( ) ;
break ;
case yieldToAnyThread :
state . logger - > Debug ( " svcSleepThread: Parking current thread " ) ;
state . scheduler - > ParkThread ( ) ;
state . scheduler - > WaitSchedule ( false ) ;
break ;
default :
break ;
}
2019-10-13 10:04:47 +02:00
}
}
2020-10-10 17:53:14 +02:00
void GetThreadPriority ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
KHandle handle { state . ctx - > gpr . w1 } ;
2019-11-17 21:19:01 +01:00
try {
2020-10-21 19:09:35 +02:00
auto thread { state . process - > GetHandle < type : : KThread > ( handle ) } ;
2020-12-10 20:36:00 +01:00
u8 priority { thread - > priority } ;
2020-10-21 19:09:35 +02:00
state . logger - > Debug ( " svcGetThreadPriority: Retrieving thread #{}'s priority: {} " , thread - > id , priority ) ;
2020-03-25 19:57:05 +01:00
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w1 = priority ;
state . ctx - > gpr . w0 = Result { } ;
2020-10-23 20:23:16 +02:00
} catch ( const std : : out_of_range & ) {
2019-11-17 21:19:01 +01:00
state . logger - > Warn ( " svcGetThreadPriority: 'handle' invalid: 0x{:X} " , handle ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidHandle ;
2019-11-17 21:19:01 +01:00
}
2019-09-24 22:54:27 +02:00
}
2020-10-10 17:53:14 +02:00
void SetThreadPriority ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
KHandle handle { state . ctx - > gpr . w0 } ;
u32 priority { state . ctx - > gpr . w1 } ;
2020-11-20 19:27:53 +01:00
if ( ! state . process - > npdm . threadInfo . priority . Valid ( priority ) ) {
2020-10-21 19:09:35 +02:00
state . logger - > Warn ( " svcSetThreadPriority: 'priority' invalid: 0x{:X} " , priority ) ;
state . ctx - > gpr . w0 = result : : InvalidPriority ;
return ;
}
2019-11-17 21:19:01 +01:00
try {
2020-10-21 19:09:35 +02:00
auto thread { state . process - > GetHandle < type : : KThread > ( handle ) } ;
2020-12-22 14:38:37 +01:00
state . logger - > Debug ( " svcSetThreadPriority: Setting thread #{}'s priority to {} " , thread - > id , priority ) ;
2020-12-15 19:54:08 +01:00
if ( thread - > priority ! = priority ) {
thread - > priority = priority ;
state . scheduler - > UpdatePriority ( thread ) ;
}
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
2020-10-23 20:23:16 +02:00
} catch ( const std : : out_of_range & ) {
2019-11-17 21:19:01 +01:00
state . logger - > Warn ( " svcSetThreadPriority: 'handle' invalid: 0x{:X} " , handle ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidHandle ;
2019-11-17 21:19:01 +01:00
}
2019-09-24 22:54:27 +02:00
}
2020-10-21 19:09:35 +02:00
void GetThreadCoreMask ( const DeviceState & state ) {
KHandle handle { state . ctx - > gpr . w2 } ;
try {
auto thread { state . process - > GetHandle < type : : KThread > ( handle ) } ;
auto idealCore { thread - > idealCore } ;
auto affinityMask { thread - > affinityMask } ;
2020-12-22 14:38:37 +01:00
state . logger - > Debug ( " svcGetThreadCoreMask: Getting thread #{}'s Ideal Core ({}) + Affinity Mask ({}) " , thread - > id , idealCore , affinityMask ) ;
2020-10-21 19:09:35 +02:00
state . ctx - > gpr . x2 = affinityMask . to_ullong ( ) ;
state . ctx - > gpr . w1 = idealCore ;
state . ctx - > gpr . w0 = Result { } ;
2020-10-23 20:23:16 +02:00
} catch ( const std : : out_of_range & ) {
2020-10-21 19:09:35 +02:00
state . logger - > Warn ( " svcGetThreadCoreMask: 'handle' invalid: 0x{:X} " , handle ) ;
state . ctx - > gpr . w0 = result : : InvalidHandle ;
}
}
void SetThreadCoreMask ( const DeviceState & state ) {
KHandle handle { state . ctx - > gpr . w0 } ;
2020-12-10 20:36:00 +01:00
i32 idealCore { static_cast < i32 > ( state . ctx - > gpr . w1 ) } ;
2020-11-20 19:27:53 +01:00
CoreMask affinityMask { state . ctx - > gpr . x2 } ;
2020-10-21 19:09:35 +02:00
try {
auto thread { state . process - > GetHandle < type : : KThread > ( handle ) } ;
2020-12-10 20:36:00 +01:00
if ( idealCore = = IdealCoreUseProcessValue ) {
idealCore = state . process - > npdm . meta . idealCore ;
affinityMask . reset ( ) . set ( idealCore ) ;
} else if ( idealCore = = IdealCoreNoUpdate ) {
idealCore = thread - > idealCore ;
} else if ( idealCore = = IdealCoreDontCare ) {
idealCore = __builtin_ctzll ( affinityMask . to_ullong ( ) ) ; // The first enabled core in the affinity mask
2020-10-21 19:09:35 +02:00
}
2020-11-20 19:27:53 +01:00
auto processMask { state . process - > npdm . threadInfo . coreMask } ;
2020-11-21 16:25:57 +01:00
if ( ( processMask | affinityMask ) ! = processMask ) {
2020-11-20 19:27:53 +01:00
state . logger - > Warn ( " svcSetThreadCoreMask: 'affinityMask' invalid: {} (Process Mask: {}) " , affinityMask , processMask ) ;
state . ctx - > gpr . w0 = result : : InvalidCoreId ;
return ;
}
2020-12-10 20:36:00 +01:00
if ( affinityMask . none ( ) | | ! affinityMask . test ( idealCore ) ) {
state . logger - > Warn ( " svcSetThreadCoreMask: 'affinityMask' invalid: {} (Ideal Core: {}) " , affinityMask , idealCore ) ;
2020-10-21 19:09:35 +02:00
state . ctx - > gpr . w0 = result : : InvalidCombination ;
return ;
}
2020-12-22 14:38:37 +01:00
state . logger - > Debug ( " svcSetThreadCoreMask: Setting thread #{}'s Ideal Core ({}) + Affinity Mask ({}) " , thread - > id , idealCore , affinityMask ) ;
2020-10-21 19:09:35 +02:00
2020-12-10 20:36:00 +01:00
thread - > idealCore = idealCore ;
2020-10-21 19:09:35 +02:00
thread - > affinityMask = affinityMask ;
2020-12-10 20:36:00 +01:00
if ( ! affinityMask . test ( thread - > coreId ) ) {
2020-12-22 14:38:37 +01:00
state . logger - > Debug ( " svcSetThreadCoreMask: Migrating thread #{} to Ideal Core C{} -> C{} " , thread - > id , thread - > coreId , idealCore ) ;
if ( thread = = state . thread ) {
state . scheduler - > RemoveThread ( ) ;
state . scheduler - > InsertThread ( state . thread ) ;
state . scheduler - > WaitSchedule ( ) ;
} else if ( ! thread - > running ) {
thread - > coreId = idealCore ;
} else {
throw exception ( " svcSetThreadCoreMask: Migrating a running thread due to a new core mask is not supported " ) ;
}
2020-12-10 20:36:00 +01:00
}
2020-10-21 19:09:35 +02:00
state . ctx - > gpr . w0 = Result { } ;
2020-10-23 20:23:16 +02:00
} catch ( const std : : out_of_range & ) {
2020-10-21 19:09:35 +02:00
state . logger - > Warn ( " svcSetThreadCoreMask: 'handle' invalid: 0x{:X} " , handle ) ;
state . ctx - > gpr . w0 = result : : InvalidHandle ;
}
}
void GetCurrentProcessorNumber ( const DeviceState & state ) {
2020-12-15 19:54:08 +01:00
auto coreId { state . thread - > coreId } ;
2020-12-22 14:38:37 +01:00
state . logger - > Debug ( " svcGetCurrentProcessorNumber: C{} " , coreId ) ;
2020-12-15 19:54:08 +01:00
state . ctx - > gpr . w0 = coreId ;
2020-10-21 19:09:35 +02:00
}
2020-10-10 17:53:14 +02:00
void ClearEvent ( const DeviceState & state ) {
auto object { state . process - > GetHandle < type : : KEvent > ( state . ctx - > gpr . w0 ) } ;
2020-07-09 15:10:18 +02:00
object - > signalled = false ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
2020-07-09 15:10:18 +02:00
}
2020-10-10 17:53:14 +02:00
void MapSharedMemory ( const DeviceState & state ) {
2019-11-17 21:19:01 +01:00
try {
2020-10-10 17:53:14 +02:00
auto object { state . process - > GetHandle < type : : KSharedMemory > ( state . ctx - > gpr . w0 ) } ;
auto pointer { reinterpret_cast < u8 * > ( state . ctx - > gpr . x1 ) } ;
2020-03-25 19:57:05 +01:00
2020-10-04 20:18:34 +02:00
if ( ! util : : PageAligned ( pointer ) ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidAddress ;
2020-10-04 20:18:34 +02:00
state . logger - > Warn ( " svcMapSharedMemory: 'pointer' not page aligned: 0x{:X} " , pointer ) ;
2019-11-17 21:19:01 +01:00
return ;
}
2020-03-25 19:57:05 +01:00
2020-10-20 11:22:15 +02:00
size_t size { state . ctx - > gpr . x2 } ;
2020-04-17 23:19:19 +02:00
if ( ! util : : PageAligned ( size ) ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidSize ;
2020-01-21 08:16:57 +01:00
state . logger - > Warn ( " svcMapSharedMemory: 'size' {}: 0x{:X} " , size ? " not page aligned " : " is zero " , size ) ;
2019-11-17 21:19:01 +01:00
return ;
}
2020-03-25 19:57:05 +01:00
2020-11-22 19:21:35 +01:00
memory : : Permission permission ( state . ctx - > gpr . w3 ) ;
2019-11-17 21:19:01 +01:00
if ( ( permission . w & & ! permission . r ) | | ( permission . x & & ! permission . r ) ) {
2020-10-04 18:40:52 +02:00
state . logger - > Warn ( " svcMapSharedMemory: 'permission' invalid: {}{}{} " , permission . r ? ' R ' : ' - ' , permission . w ? ' W ' : ' - ' , permission . x ? ' X ' : ' - ' ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidNewMemoryPermission ;
2019-11-17 21:19:01 +01:00
return ;
}
2020-03-25 19:57:05 +01:00
2020-10-17 13:38:27 +02:00
state . logger - > Debug ( " svcMapSharedMemory: Mapping shared memory at 0x{:X} - 0x{:X} (0x{:X} bytes) ({}{}{}) " , pointer , pointer + size , size , permission . r ? ' R ' : ' - ' , permission . w ? ' W ' : ' - ' , permission . x ? ' X ' : ' - ' ) ;
2020-03-25 19:57:05 +01:00
2020-10-04 20:18:34 +02:00
object - > Map ( pointer , size , permission ) ;
2020-03-25 19:57:05 +01:00
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
2020-10-23 20:23:16 +02:00
} catch ( const std : : out_of_range & ) {
2020-10-20 11:22:15 +02:00
state . logger - > Warn ( " svcMapSharedMemory: 'handle' invalid: 0x{:X} " , static_cast < u32 > ( state . ctx - > gpr . w0 ) ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidHandle ;
2019-09-24 22:54:27 +02:00
}
}
2020-10-10 17:53:14 +02:00
void CreateTransferMemory ( const DeviceState & state ) {
auto pointer { reinterpret_cast < u8 * > ( state . ctx - > gpr . x1 ) } ;
2020-10-04 20:18:34 +02:00
if ( ! util : : PageAligned ( pointer ) ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidAddress ;
2020-10-04 20:18:34 +02:00
state . logger - > Warn ( " svcCreateTransferMemory: 'pointer' not page aligned: 0x{:X} " , pointer ) ;
2019-11-17 21:19:01 +01:00
return ;
}
2020-03-25 19:57:05 +01:00
2020-10-20 11:22:15 +02:00
size_t size { state . ctx - > gpr . x2 } ;
2020-04-17 23:19:19 +02:00
if ( ! util : : PageAligned ( size ) ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidSize ;
2020-01-21 08:16:57 +01:00
state . logger - > Warn ( " svcCreateTransferMemory: 'size' {}: 0x{:X} " , size ? " not page aligned " : " is zero " , size ) ;
2019-11-17 21:19:01 +01:00
return ;
}
2020-03-25 19:57:05 +01:00
2020-11-22 19:21:35 +01:00
memory : : Permission permission ( state . ctx - > gpr . w3 ) ;
2019-11-17 21:19:01 +01:00
if ( ( permission . w & & ! permission . r ) | | ( permission . x & & ! permission . r ) ) {
2020-10-04 18:40:52 +02:00
state . logger - > Warn ( " svcCreateTransferMemory: 'permission' invalid: {}{}{} " , permission . r ? ' R ' : ' - ' , permission . w ? ' W ' : ' - ' , permission . x ? ' X ' : ' - ' ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidNewMemoryPermission ;
2019-11-17 21:19:01 +01:00
return ;
}
2020-03-25 19:57:05 +01:00
2020-10-04 20:18:34 +02:00
auto tmem { state . process - > NewHandle < type : : KTransferMemory > ( pointer , size , permission ) } ;
2020-10-17 13:38:27 +02:00
state . logger - > Debug ( " svcCreateTransferMemory: Creating transfer memory at 0x{:X} - 0x{:X} (0x{:X} bytes) ({}{}{}) " , pointer , pointer + size , size , permission . r ? ' R ' : ' - ' , permission . w ? ' W ' : ' - ' , permission . x ? ' X ' : ' - ' ) ;
2020-03-25 19:57:05 +01:00
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
state . ctx - > gpr . w1 = tmem . handle ;
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
}
2020-10-10 17:53:14 +02:00
void CloseHandle ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
KHandle handle { static_cast < KHandle > ( state . ctx - > gpr . w0 ) } ;
2019-11-17 21:19:01 +01:00
try {
2020-09-28 12:05:17 +02:00
state . process - > CloseHandle ( handle ) ;
2019-11-17 21:19:01 +01:00
state . logger - > Debug ( " svcCloseHandle: Closing handle: 0x{:X} " , handle ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
2020-10-23 20:23:16 +02:00
} catch ( const std : : out_of_range & ) {
2019-11-17 21:19:01 +01:00
state . logger - > Warn ( " svcCloseHandle: 'handle' invalid: 0x{:X} " , handle ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidHandle ;
2019-11-17 21:19:01 +01:00
}
}
2020-10-10 17:53:14 +02:00
void ResetSignal ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
KHandle handle { state . ctx - > gpr . w0 } ;
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
try {
2020-10-07 17:41:13 +02:00
auto object { state . process - > GetHandle ( handle ) } ;
2019-11-17 21:19:01 +01:00
switch ( object - > objectType ) {
2020-04-22 19:02:27 +02:00
case type : : KType : : KEvent :
2019-11-17 21:19:01 +01:00
std : : static_pointer_cast < type : : KEvent > ( object ) - > ResetSignal ( ) ;
break ;
2020-03-25 19:57:05 +01:00
2020-04-22 19:02:27 +02:00
case type : : KType : : KProcess :
2019-11-17 21:19:01 +01:00
std : : static_pointer_cast < type : : KProcess > ( object ) - > ResetSignal ( ) ;
break ;
2020-03-25 19:57:05 +01:00
2019-11-17 21:19:01 +01:00
default : {
state . logger - > Warn ( " svcResetSignal: 'handle' type invalid: 0x{:X} ({}) " , handle , object - > objectType ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidHandle ;
2019-11-17 21:19:01 +01:00
return ;
}
}
2020-03-25 19:57:05 +01:00
2019-11-17 21:19:01 +01:00
state . logger - > Debug ( " svcResetSignal: Resetting signal: 0x{:X} " , handle ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
2020-01-11 05:52:25 +01:00
} catch ( const std : : out_of_range & ) {
2019-11-17 21:19:01 +01:00
state . logger - > Warn ( " svcResetSignal: 'handle' invalid: 0x{:X} " , handle ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidHandle ;
2019-11-17 21:19:01 +01:00
return ;
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
}
}
2020-10-10 17:53:14 +02:00
void WaitSynchronization ( const DeviceState & state ) {
2020-09-26 07:17:57 +02:00
constexpr u8 maxSyncHandles { 0x40 } ; // The total amount of handles that can be passed to WaitSynchronization
2020-03-25 19:57:05 +01:00
2020-10-20 11:22:15 +02:00
u32 numHandles { state . ctx - > gpr . w2 } ;
2020-03-25 18:59:37 +01:00
if ( numHandles > maxSyncHandles ) {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : OutOfHandles ;
2019-09-24 22:54:27 +02:00
return ;
}
2020-03-25 18:59:37 +01:00
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
std : : string handleStr ;
2020-03-25 18:59:37 +01:00
std : : vector < std : : shared_ptr < type : : KSyncObject > > objectTable ;
2020-10-20 11:22:15 +02:00
span waitHandles ( reinterpret_cast < KHandle * > ( state . ctx - > gpr . x1 ) , numHandles ) ;
2020-03-25 18:59:37 +01:00
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
for ( const auto & handle : waitHandles ) {
2020-11-17 01:48:41 +01:00
if ( Logger : : LogLevel : : Debug < = state . logger - > configLevel )
handleStr + = fmt : : format ( " * 0x{:X} \n " , handle ) ;
2020-03-25 18:59:37 +01:00
2020-10-07 17:41:13 +02:00
auto object { state . process - > GetHandle ( handle ) } ;
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
switch ( object - > objectType ) {
2019-10-13 10:04:47 +02:00
case type : : KType : : KProcess :
case type : : KType : : KThread :
case type : : KType : : KEvent :
case type : : KType : : KSession :
2020-12-20 15:09:36 +01:00
objectTable . push_back ( std : : static_pointer_cast < type : : KSyncObject > ( object ) ) ;
2019-10-13 10:04:47 +02:00
break ;
2020-03-25 18:59:37 +01:00
2019-11-15 15:19:24 +01:00
default : {
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidHandle ;
2019-10-13 10:04:47 +02:00
return ;
2019-11-15 15:19:24 +01:00
}
2019-10-13 10:04:47 +02:00
}
2020-01-11 05:52:25 +01:00
}
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
u64 timeout { state . ctx - > gpr . x3 } ;
2020-01-12 21:37:22 +01:00
state . logger - > Debug ( " svcWaitSynchronization: Waiting on handles: \n {}Timeout: 0x{:X} ns " , handleStr , timeout ) ;
2020-03-25 18:59:37 +01:00
2020-12-22 14:38:37 +01:00
SchedulerScopedLock schedulerLock ( state ) ;
2020-09-26 07:17:57 +02:00
auto start { util : : GetTimeNs ( ) } ;
2020-12-22 14:38:37 +01:00
while ( true ) {
if ( state . thread - > cancelSync ) {
state . thread - > cancelSync = false ;
state . ctx - > gpr . w0 = result : : Cancelled ;
return ;
}
2020-12-20 15:09:36 +01:00
2020-12-22 14:38:37 +01:00
u32 index { } ;
for ( const auto & object : objectTable ) {
if ( object - > signalled ) {
state . logger - > Debug ( " svcWaitSynchronization: Signalled handle: 0x{:X} " , waitHandles [ index ] ) ;
state . ctx - > gpr . w0 = Result { } ;
state . ctx - > gpr . w1 = index ;
2020-12-20 15:09:36 +01:00
return ;
}
2020-12-22 14:38:37 +01:00
index + + ;
2019-10-13 10:04:47 +02:00
}
2020-12-22 14:38:37 +01:00
if ( ( util : : GetTimeNs ( ) - start ) > = timeout ) {
state . logger - > Debug ( " svcWaitSynchronization: Wait has timed out " ) ;
state . ctx - > gpr . w0 = result : : TimedOut ;
return ;
}
}
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
}
2020-10-10 17:53:14 +02:00
void CancelSynchronization ( const DeviceState & state ) {
2020-02-01 16:51:32 +01:00
try {
2020-10-10 17:53:14 +02:00
state . process - > GetHandle < type : : KThread > ( state . ctx - > gpr . w0 ) - > cancelSync = true ;
2020-10-23 20:23:16 +02:00
} catch ( const std : : out_of_range & ) {
2020-10-20 11:22:15 +02:00
state . logger - > Warn ( " svcCancelSynchronization: 'handle' invalid: 0x{:X} " , static_cast < u32 > ( state . ctx - > gpr . w0 ) ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidHandle ;
2020-02-01 16:51:32 +01:00
}
}
2020-10-10 17:53:14 +02:00
void ArbitrateLock ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
auto pointer { reinterpret_cast < u32 * > ( state . ctx - > gpr . x1 ) } ;
2020-10-04 20:18:34 +02:00
if ( ! util : : WordAligned ( pointer ) ) {
2020-10-05 11:19:23 +02:00
state . logger - > Warn ( " svcArbitrateLock: 'pointer' not word aligned: 0x{:X} " , pointer ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidAddress ;
2019-11-17 21:19:01 +01:00
return ;
}
2020-03-25 19:57:05 +01:00
2020-10-05 11:19:23 +02:00
state . logger - > Debug ( " svcArbitrateLock: Locking mutex at 0x{:X} " , pointer ) ;
2020-03-25 19:57:05 +01:00
2020-12-20 15:09:36 +01:00
KHandle ownerHandle { state . ctx - > gpr . w0 } ;
KHandle requesterHandle { state . ctx - > gpr . w2 } ;
auto result { state . process - > MutexLock ( pointer , ownerHandle , requesterHandle ) } ;
2020-12-15 19:54:08 +01:00
if ( result = = Result { } )
2020-10-05 11:19:23 +02:00
state . logger - > Debug ( " svcArbitrateLock: Locked mutex at 0x{:X} " , pointer ) ;
2020-12-15 19:54:08 +01:00
else if ( result = = result : : InvalidHandle )
2020-12-20 15:09:36 +01:00
state . logger - > Warn ( " svcArbitrateLock: 'ownerHandle' invalid: 0x{:X} " , ownerHandle ) ;
2020-12-15 19:54:08 +01:00
else if ( result = = result : : InvalidCurrentMemory )
2020-10-05 11:19:23 +02:00
state . logger - > Debug ( " svcArbitrateLock: Owner handle did not match current owner for mutex or didn't have waiter flag at 0x{:X} " , pointer ) ;
2020-03-25 19:57:05 +01:00
2020-12-15 19:54:08 +01:00
state . ctx - > gpr . w0 = result ;
2019-10-16 14:41:30 +02:00
}
2020-10-10 17:53:14 +02:00
void ArbitrateUnlock ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
auto mutex { reinterpret_cast < u32 * > ( state . ctx - > gpr . x0 ) } ;
2020-10-04 20:18:34 +02:00
if ( ! util : : WordAligned ( mutex ) ) {
2020-10-10 19:40:12 +02:00
state . logger - > Warn ( " svcArbitrateUnlock: 'mutex' not word aligned: 0x{:X} " , mutex ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidAddress ;
2019-11-17 21:19:01 +01:00
return ;
}
2020-03-25 19:57:05 +01:00
2020-10-05 11:19:23 +02:00
state . logger - > Debug ( " svcArbitrateUnlock: Unlocking mutex at 0x{:X} " , mutex ) ;
2020-12-15 19:54:08 +01:00
state . process - > MutexUnlock ( mutex ) ;
state . logger - > Debug ( " svcArbitrateUnlock: Unlocked mutex at 0x{:X} " , mutex ) ;
2020-12-20 15:09:36 +01:00
2020-12-15 19:54:08 +01:00
state . ctx - > gpr . w0 = Result { } ;
2019-10-16 14:41:30 +02:00
}
2020-10-10 17:53:14 +02:00
void WaitProcessWideKeyAtomic ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
auto mutex { reinterpret_cast < u32 * > ( state . ctx - > gpr . x0 ) } ;
2020-10-04 20:18:34 +02:00
if ( ! util : : WordAligned ( mutex ) ) {
2020-10-10 19:40:12 +02:00
state . logger - > Warn ( " svcWaitProcessWideKeyAtomic: 'mutex' not word aligned: 0x{:X} " , mutex ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidAddress ;
2020-02-01 16:51:32 +01:00
return ;
}
2020-03-25 19:57:05 +01:00
2020-12-20 15:09:36 +01:00
auto conditional { reinterpret_cast < u32 * > ( state . ctx - > gpr . x1 ) } ;
KHandle requesterHandle { state . ctx - > gpr . w2 } ;
2020-03-25 19:57:05 +01:00
2020-12-20 15:09:36 +01:00
i64 timeout { static_cast < i64 > ( state . ctx - > gpr . x3 ) } ;
2020-12-22 14:38:37 +01:00
state . logger - > Debug ( " svcWaitProcessWideKeyAtomic: Mutex: 0x{:X}, Conditional-Variable: 0x{:X}, Timeout: {}ns " , mutex , conditional , timeout ) ;
2020-03-25 19:57:05 +01:00
2020-12-20 15:09:36 +01:00
auto result { state . process - > ConditionalVariableWait ( conditional , mutex , requesterHandle , timeout ) } ;
if ( result = = Result { } )
2020-12-22 14:38:37 +01:00
state . logger - > Debug ( " svcWaitProcessWideKeyAtomic: Waited for conditional variable (0x{:X}) and reacquired mutex " , conditional ) ;
2020-12-20 15:09:36 +01:00
else if ( result = = result : : TimedOut )
2020-12-22 14:38:37 +01:00
state . logger - > Debug ( " svcWaitProcessWideKeyAtomic: Wait has timed out ({}ns) for 0x{:X} " , timeout , conditional ) ;
2020-12-20 15:09:36 +01:00
state . ctx - > gpr . w0 = result ;
2019-10-16 14:41:30 +02:00
}
2020-10-10 17:53:14 +02:00
void SignalProcessWideKey ( const DeviceState & state ) {
2020-12-20 15:09:36 +01:00
auto key { reinterpret_cast < u32 * > ( state . ctx - > gpr . x0 ) } ;
2020-10-20 11:22:15 +02:00
KHandle count { state . ctx - > gpr . w1 } ;
2020-03-25 19:57:05 +01:00
2020-12-20 15:09:36 +01:00
state . logger - > Debug ( " svcSignalProcessWideKey: Signalling Conditional-Variable at 0x{:X} for {} " , key , count ) ;
state . process - > ConditionalVariableSignal ( key , count ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
2019-11-17 21:19:01 +01:00
}
2020-10-10 17:53:14 +02:00
void GetSystemTick ( const DeviceState & state ) {
2019-11-17 21:19:01 +01:00
u64 tick ;
asm ( " STR X1, [SP, #-16]! \n \t "
" MRS %0, CNTVCT_EL0 \n \t "
" MOV X1, #0xF800 \n \t "
" MOVK X1, #0x124, lsl #16 \n \t "
" MUL %0, %0, X1 \n \t "
" MRS X1, CNTFRQ_EL0 \n \t "
" UDIV %0, %0, X1 \n \t "
" LDR X1, [SP], #16 " : " =r " ( tick ) ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . x0 = tick ;
2019-09-24 22:54:27 +02:00
}
2020-10-10 17:53:14 +02:00
void ConnectToNamedPort ( const DeviceState & state ) {
2020-10-02 13:07:13 +02:00
constexpr u8 portSize = 0x8 ; //!< The size of a port name string
2020-10-20 11:22:15 +02:00
std : : string_view port ( span ( reinterpret_cast < char * > ( state . ctx - > gpr . x1 ) , portSize ) . as_string ( true ) ) ;
2020-03-25 18:59:37 +01:00
KHandle handle { } ;
if ( port . compare ( " sm: " ) > = 0 ) {
2020-09-02 23:11:28 +02:00
handle = state . process - > NewHandle < type : : KSession > ( std : : static_pointer_cast < service : : BaseService > ( state . os - > serviceManager . smUserInterface ) ) . handle ;
2020-02-15 10:38:17 +01:00
} else {
2019-11-17 21:19:01 +01:00
state . logger - > Warn ( " svcConnectToNamedPort: Connecting to invalid port: '{}' " , port ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : NotFound ;
2019-11-17 21:19:01 +01:00
return ;
}
2020-03-25 18:59:37 +01:00
2019-11-17 21:19:01 +01:00
state . logger - > Debug ( " svcConnectToNamedPort: Connecting to port '{}' at 0x{:X} " , port , handle ) ;
2020-03-25 18:59:37 +01:00
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w1 = handle ;
state . ctx - > gpr . w0 = Result { } ;
2019-09-24 22:54:27 +02:00
}
2020-10-10 17:53:14 +02:00
void SendSyncRequest ( const DeviceState & state ) {
state . os - > serviceManager . SyncRequestHandler ( static_cast < KHandle > ( state . ctx - > gpr . x0 ) ) ;
state . ctx - > gpr . w0 = Result { } ;
2019-09-24 22:54:27 +02:00
}
2020-10-10 17:53:14 +02:00
void GetThreadId ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
KHandle handle { state . ctx - > gpr . w1 } ;
2020-12-22 14:38:37 +01:00
size_t tid { state . process - > GetHandle < type : : KThread > ( handle ) - > id } ;
2020-03-25 18:59:37 +01:00
2020-12-22 14:38:37 +01:00
state . logger - > Debug ( " svcGetThreadId: Handle: 0x{:X}, TID: {} " , handle , tid ) ;
2020-03-25 18:59:37 +01:00
2020-12-22 14:38:37 +01:00
state . ctx - > gpr . x1 = tid ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
Framebuffer and NativeActivity
What was added:
* Framebuffer
* NativeActivity
* NV Services
* IOCTL Handler
* NV Devices:
* * /dev/nvmap - 0xC0080101, 0xC0080103, 0xC0200104, 0xC0180105, 0xC00C0109, 0xC008010E
* * /dev/nvhost-as-gpu
* * /dev/nvhost-channel - 0x40044801, 0xC0104809, 0xC010480B, 0xC018480C, 0x4004480D, 0xC020481A, 0x40084714
* * /dev/nvhost-ctrl
* * /dev/nvhost-ctrl-gpu - 0x80044701, 0x80284702, 0xC0184706, 0xC0B04705, 0x80084714
* SVCs:
* * SetMemoryAttribute
* * CreateTransferMemory
* * ResetSignal
* * GetSystemTick
* Addition of Compact Logger
What was fixed:
* SVCs:
* * SetHeapSize
* * SetMemoryAttribute
* * QueryMemory
* A release build would not set CMAKE_BUILD_TYPE to "RELEASE"
* The logger code was simplified
2019-11-13 21:09:31 +01:00
}
2020-10-10 17:53:14 +02:00
void OutputDebugString ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
auto debug { span ( reinterpret_cast < u8 * > ( state . ctx - > gpr . x0 ) , state . ctx - > gpr . x1 ) . as_string ( ) } ;
2020-03-25 19:57:05 +01:00
2020-01-11 05:52:25 +01:00
if ( debug . back ( ) = = ' \n ' )
2020-10-04 18:40:52 +02:00
debug . remove_suffix ( 1 ) ;
2020-03-25 19:57:05 +01:00
2020-12-15 19:54:08 +01:00
state . logger - > Info ( " svcOutputDebugString: {} " , debug ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = Result { } ;
2019-09-24 22:54:27 +02:00
}
2020-10-10 17:53:14 +02:00
void GetInfo ( const DeviceState & state ) {
2020-10-20 11:22:15 +02:00
enum class InfoState : u32 {
// 1.0.0+
2020-11-03 10:44:09 +01:00
AllowedCpuIdBitmask = 0 ,
AllowedThreadPriorityMask = 1 ,
AliasRegionBaseAddr = 2 ,
AliasRegionSize = 3 ,
HeapRegionBaseAddr = 4 ,
HeapRegionSize = 5 ,
TotalMemoryAvailable = 6 ,
TotalMemoryUsage = 7 ,
IsCurrentProcessBeingDebugged = 8 ,
ResourceLimit = 9 ,
IdleTickCount = 10 ,
RandomEntropy = 11 ,
2020-10-20 11:22:15 +02:00
// 2.0.0+
2020-11-03 10:44:09 +01:00
AddressSpaceBaseAddr = 12 ,
AddressSpaceSize = 13 ,
StackRegionBaseAddr = 14 ,
StackRegionSize = 15 ,
2020-10-20 11:22:15 +02:00
// 3.0.0+
2020-11-03 10:44:09 +01:00
TotalSystemResourceAvailable = 16 ,
TotalSystemResourceUsage = 17 ,
2020-11-20 19:27:53 +01:00
ProgramId = 18 ,
2020-10-20 11:22:15 +02:00
// 4.0.0+
2020-11-03 10:44:09 +01:00
PrivilegedProcessId = 19 ,
2020-10-20 11:22:15 +02:00
// 5.0.0+
2020-11-03 10:44:09 +01:00
UserExceptionContextAddr = 20 ,
2020-10-20 11:22:15 +02:00
// 6.0.0+
2020-10-23 20:23:16 +02:00
TotalMemoryAvailableWithoutSystemResource = 21 ,
2020-11-03 10:44:09 +01:00
TotalMemoryUsageWithoutSystemResource = 22 ,
2020-10-20 11:22:15 +02:00
} ;
InfoState info { static_cast < u32 > ( state . ctx - > gpr . w1 ) } ;
KHandle handle { state . ctx - > gpr . w2 } ;
u64 id1 { state . ctx - > gpr . x3 } ;
2020-03-25 18:59:37 +01:00
2020-09-26 07:17:57 +02:00
constexpr u64 totalPhysicalMemory { 0xF8000000 } ; // ~4 GB of RAM
2020-03-25 19:57:05 +01:00
2020-10-20 11:22:15 +02:00
u64 out { } ;
switch ( info ) {
case InfoState : : IsCurrentProcessBeingDebugged :
case InfoState : : PrivilegedProcessId :
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-11-20 19:27:53 +01:00
case InfoState : : AllowedCpuIdBitmask :
out = state . process - > npdm . threadInfo . coreMask . to_ullong ( ) ;
break ;
case InfoState : : AllowedThreadPriorityMask :
out = state . process - > npdm . threadInfo . priority . Mask ( ) ;
break ;
2020-10-20 11:22:15 +02:00
case InfoState : : AliasRegionBaseAddr :
2020-10-07 17:41:13 +02:00
out = state . process - > memory . alias . address ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
case InfoState : : AliasRegionSize :
2020-10-07 17:41:13 +02:00
out = state . process - > memory . alias . size ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
case InfoState : : HeapRegionBaseAddr :
2020-10-07 17:41:13 +02:00
out = state . process - > memory . heap . address ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
case InfoState : : HeapRegionSize :
2020-10-07 17:41:13 +02:00
out = state . process - > memory . heap . size ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
case InfoState : : TotalMemoryAvailable :
2020-11-21 16:25:57 +01:00
out = std : : min ( totalPhysicalMemory , state . process - > memory . heap . size ) ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
case InfoState : : TotalMemoryUsage :
2020-11-21 16:25:57 +01:00
out = state . process - > memory . GetUserMemoryUsage ( ) + state . process - > memory . GetSystemResourceUsage ( ) ;
2020-10-21 19:09:35 +02:00
break ;
case InfoState : : RandomEntropy :
out = util : : GetTimeTicks ( ) ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
case InfoState : : AddressSpaceBaseAddr :
2020-10-15 10:10:13 +02:00
out = state . process - > memory . base . address ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
case InfoState : : AddressSpaceSize :
2020-10-15 10:10:13 +02:00
out = state . process - > memory . base . size ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
case InfoState : : StackRegionBaseAddr :
2020-10-07 17:41:13 +02:00
out = state . process - > memory . stack . address ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
case InfoState : : StackRegionSize :
2020-10-07 17:41:13 +02:00
out = state . process - > memory . stack . size ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
case InfoState : : TotalSystemResourceAvailable :
2020-10-21 19:09:35 +02:00
out = state . process - > npdm . meta . systemResourceSize ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
case InfoState : : TotalSystemResourceUsage :
// A very rough approximation of what this should be on the Switch, the amount of memory allocated for storing the memory blocks (https://switchbrew.org/wiki/Kernel_objects#KMemoryBlockManager)
2020-11-21 16:25:57 +01:00
out = state . process - > memory . GetSystemResourceUsage ( ) ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-11-20 19:27:53 +01:00
case InfoState : : ProgramId :
out = state . process - > npdm . aci0 . programId ;
break ;
2020-10-20 11:22:15 +02:00
case InfoState : : TotalMemoryAvailableWithoutSystemResource :
2020-11-21 16:25:57 +01:00
out = std : : min ( totalPhysicalMemory , state . process - > memory . heap . size ) - state . process - > npdm . meta . systemResourceSize ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
case InfoState : : TotalMemoryUsageWithoutSystemResource :
2020-11-21 16:25:57 +01:00
out = state . process - > memory . GetUserMemoryUsage ( ) ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
case InfoState : : UserExceptionContextAddr :
2020-10-04 18:40:52 +02:00
out = reinterpret_cast < u64 > ( state . process - > tlsPages [ 0 ] - > Get ( 0 ) ) ;
2019-09-24 22:54:27 +02:00
break ;
2020-03-25 18:59:37 +01:00
2019-09-24 22:54:27 +02:00
default :
2020-10-20 11:22:15 +02:00
state . logger - > Warn ( " svcGetInfo: Unimplemented case ID0: {}, ID1: {} " , static_cast < u32 > ( info ) , id1 ) ;
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . w0 = result : : InvalidEnumValue ;
2019-09-24 22:54:27 +02:00
return ;
}
2020-03-25 18:59:37 +01:00
2020-10-20 11:22:15 +02:00
state . logger - > Debug ( " svcGetInfo: ID0: {}, ID1: {}, Out: 0x{:X} " , static_cast < u32 > ( info ) , id1 , out ) ;
2020-03-25 18:59:37 +01:00
2020-10-10 17:53:14 +02:00
state . ctx - > gpr . x1 = out ;
state . ctx - > gpr . w0 = Result { } ;
2019-09-24 22:54:27 +02:00
}
2020-10-20 11:22:15 +02:00
void MapPhysicalMemory ( const DeviceState & state ) {
auto pointer { reinterpret_cast < u8 * > ( state . ctx - > gpr . x0 ) } ;
size_t size { state . ctx - > gpr . x1 } ;
if ( ! util : : PageAligned ( pointer ) ) {
state . ctx - > gpr . w0 = result : : InvalidAddress ;
return ;
}
if ( ! size | | ! util : : PageAligned ( size ) ) {
state . ctx - > gpr . w0 = result : : InvalidSize ;
return ;
}
if ( ! state . process - > memory . alias . IsInside ( pointer ) | | ! state . process - > memory . alias . IsInside ( pointer + size ) ) {
state . ctx - > gpr . w0 = result : : InvalidMemoryRegion ;
return ;
}
state . process - > NewHandle < type : : KPrivateMemory > ( pointer , size , memory : : Permission { true , true , false } , memory : : states : : Heap ) ;
state . ctx - > gpr . w0 = Result { } ;
}
void UnmapPhysicalMemory ( const DeviceState & state ) {
auto pointer { reinterpret_cast < u8 * > ( state . ctx - > gpr . x0 ) } ;
size_t size { state . ctx - > gpr . x1 } ;
if ( ! util : : PageAligned ( pointer ) ) {
state . ctx - > gpr . w0 = result : : InvalidAddress ;
return ;
}
if ( ! size | | ! util : : PageAligned ( size ) ) {
state . ctx - > gpr . w0 = result : : InvalidSize ;
return ;
}
if ( ! state . process - > memory . alias . IsInside ( pointer ) | | ! state . process - > memory . alias . IsInside ( pointer + size ) ) {
state . ctx - > gpr . w0 = result : : InvalidMemoryRegion ;
return ;
}
auto end { pointer + size } ;
while ( pointer < end ) {
auto memory { state . process - > GetMemoryObject ( pointer ) } ;
if ( memory ) {
auto item { static_pointer_cast < type : : KPrivateMemory > ( memory - > item ) } ;
auto initialSize { item - > size } ;
if ( item - > memState = = memory : : states : : Heap ) {
if ( item - > ptr > = pointer ) {
if ( item - > size < = size ) {
item - > Resize ( 0 ) ;
state . process - > CloseHandle ( memory - > handle ) ;
} else {
item - > Remap ( pointer + size , item - > size - ( size + ( item - > ptr - pointer ) ) ) ;
}
} else if ( item - > ptr < pointer ) {
item - > Resize ( pointer - item - > ptr ) ;
}
}
pointer + = initialSize ;
size - = initialSize ;
} else {
auto block { * state . process - > memory . Get ( pointer ) } ;
pointer + = block . size ;
size - = block . size ;
}
}
state . ctx - > gpr . w0 = Result { } ;
}
2019-09-24 22:54:27 +02:00
}