@ -8,6 +8,7 @@
# include "common/assert.h"
# include "common/assert.h"
# include "common/logging/log.h"
# include "common/logging/log.h"
# include "core/core.h"
# include "core/core.h"
# include "core/hle/kernel/k_event.h"
# include "core/hle/kernel/k_process.h"
# include "core/hle/kernel/k_process.h"
# include "core/hle/service/nvdrv/core/container.h"
# include "core/hle/service/nvdrv/core/container.h"
# include "core/hle/service/nvdrv/core/nvmap.h"
# include "core/hle/service/nvdrv/core/nvmap.h"
@ -161,11 +162,114 @@ NvResult nvhost_gpu::ZCullBind(IoctlZCullBind& params) {
}
}
NvResult nvhost_gpu : : SetErrorNotifier ( IoctlSetErrorNotifier & params ) {
NvResult nvhost_gpu : : SetErrorNotifier ( IoctlSetErrorNotifier & params ) {
LOG_WARNING ( Service_NVDRV , " (STUBBED) called, offset={:X}, size={:X}, mem={:X} " , params . offset ,
params . size , params . mem ) ;
LOG_DEBUG ( Service_NVDRV , " called, offset={:#X}, size={:#X}, mem={:#X} " ,
params . offset , params . size , params . mem ) ;
if ( ! params . mem | | ! params . size ) {
std : : scoped_lock lk ( channel_mutex ) ;
if ( ! channel_state - > initialized ) {
LOG_CRITICAL ( Service_NVDRV , " No address space bound for setting up error notifier! " ) ;
return NvResult : : NotInitialized ;
}
error_notifier_params = { } ;
LOG_DEBUG ( Service_NVDRV , " Error notifier disabled! " ) ;
return NvResult : : Success ;
}
constexpr u64 error_notification_size = sizeof ( IoctlGetErrorNotification ) ;
if ( params . size < error_notification_size ) {
LOG_ERROR ( Service_NVDRV , " Error notification size: {:#X} is too small. Need at least {:#X} " , params . size ,
error_notification_size ) ;
return NvResult : : InvalidSize ;
}
auto handle = nvmap . GetHandle ( static_cast < NvCore : : NvMap : : Handle : : Id > ( params . mem ) ) ;
if ( ! handle ) {
LOG_ERROR ( Service_NVDRV , " Unknown nvmap handle id {:#X} " , params . mem ) ;
return NvResult : : BadParameter ;
}
if ( params . offset > handle - > size | | params . size > ( handle - > size - params . offset ) ) {
LOG_ERROR ( Service_NVDRV , " Error notifier out of bounds: offset={:#X} size={:#X} handle size={:#X} " , params . offset ,
params . size , handle - > size ) ;
return NvResult : : InvalidSize ;
}
u64 write_address , write_offset , handle_id ;
{
std : : scoped_lock lk ( channel_mutex ) ;
if ( ! channel_state - > initialized ) {
LOG_CRITICAL ( Service_NVDRV , " No address space bound for setting up error notifier! " ) ;
return NvResult : : NotInitialized ;
}
error_notifier_params = params ;
write_address = handle - > address ;
write_offset = params . offset ;
handle_id = handle - > id ;
}
if ( write_address ) {
IoctlGetErrorNotification error_notification { } ;
error_notification . status = static_cast < u16 > ( NotifierStatus : : NoError ) ;
system . ApplicationMemory ( ) . WriteBlock ( write_address + write_offset , & error_notification , sizeof ( error_notification ) ) ;
} else {
LOG_WARNING ( Service_NVDRV ,
" nvmap handle id {:#X} has no virtual address assigned; "
" skipping initialization write for error notification! " ,
handle_id ) ;
}
return NvResult : : Success ;
return NvResult : : Success ;
}
}
void nvhost_gpu : : PostErrorNotification ( u32 info32 , u16 info16 , NotifierStatus status ) {
IoctlSetErrorNotifier error_notifier_params_snapshot { } ;
Kernel : : KEvent * error_notifier_event_snapshot { } ;
{
std : : scoped_lock lk ( channel_mutex ) ;
error_notifier_params_snapshot = error_notifier_params ;
error_notifier_event_snapshot = error_notifier_event ;
}
if ( ! error_notifier_params_snapshot . mem | | error_notifier_params_snapshot . size < sizeof ( IoctlGetErrorNotification ) ) {
LOG_DEBUG ( Service_NVDRV , " PostErrorNotification: notifier not configured or too small! " ) ;
return ;
}
auto handle = nvmap . GetHandle ( static_cast < NvCore : : NvMap : : Handle : : Id > ( error_notifier_params_snapshot . mem ) ) ;
if ( ! handle | | ! handle - > address ) {
LOG_ERROR ( Service_NVDRV , " PostErrorNotification: invalid handle or virtual address! " ) ;
return ;
}
IoctlGetErrorNotification error_init { } ;
error_init . info32 = info32 ;
error_init . info16 = info16 ;
error_init . status = static_cast < u16 > ( status ) ;
const u64 write_size = std : : min < u64 > ( sizeof ( IoctlGetErrorNotification ) ,
error_notifier_params_snapshot . size ) ;
if ( error_notifier_params_snapshot . offset > = handle - > size | |
write_size > ( handle - > size - error_notifier_params_snapshot . offset ) ) {
LOG_ERROR ( Service_NVDRV , " PostErrorNotification: bounds check failed! " ) ;
return ;
}
const u64 virtual_address = handle - > address + error_notifier_params_snapshot . offset ;
if ( virtual_address < handle - > address ) {
LOG_ERROR ( Service_NVDRV , " PostErrorNotification: virtual address overflow! " ) ;
return ;
}
auto & application_memory = system . ApplicationMemory ( ) ;
application_memory . WriteBlock ( virtual_address , & error_init , write_size ) ;
if ( error_notifier_event_snapshot ) {
error_notifier_event_snapshot - > Signal ( ) ;
}
}
NvResult nvhost_gpu : : SetChannelPriority ( IoctlChannelSetPriority & params ) {
NvResult nvhost_gpu : : SetChannelPriority ( IoctlChannelSetPriority & params ) {
channel_priority = params . priority ;
channel_priority = params . priority ;
LOG_INFO ( Service_NVDRV , " called, priority={:X} " , channel_priority ) ;
LOG_INFO ( Service_NVDRV , " called, priority={:X} " , channel_priority ) ;
@ -278,7 +382,7 @@ NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) {
params . flags = allowed_mask ;
params . flags = allowed_mask ;
}
}
s32_le ctx_class_number_index =
s32_le ctx_class_number_index =
GetObjectContextClassNumberIndex ( static_cast < CtxClasses > ( params . class_num ) ) ;
GetObjectContextClassNumberIndex ( static_cast < CtxClasses > ( params . class_num ) ) ;
if ( ctx_class_number_index < 0 ) {
if ( ctx_class_number_index < 0 ) {
LOG_ERROR ( Service_NVDRV , " Invalid class number for object context: {:#X} " ,
LOG_ERROR ( Service_NVDRV , " Invalid class number for object context: {:#X} " ,
@ -357,6 +461,7 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL
if ( flags . fence_wait . Value ( ) ) {
if ( flags . fence_wait . Value ( ) ) {
if ( flags . increment_value . Value ( ) ) {
if ( flags . increment_value . Value ( ) ) {
PostErrorNotification ( flags . raw , 0 , NotifierStatus : : GenericError ) ;
return NvResult : : BadParameter ;
return NvResult : : BadParameter ;
}
}
@ -390,7 +495,11 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL
NvResult nvhost_gpu : : SubmitGPFIFOBase1 ( IoctlSubmitGpfifo & params ,
NvResult nvhost_gpu : : SubmitGPFIFOBase1 ( IoctlSubmitGpfifo & params ,
std : : span < Tegra : : CommandListHeader > commands , bool kickoff ) {
std : : span < Tegra : : CommandListHeader > commands , bool kickoff ) {
if ( params . num_entries > commands . size ( ) ) {
if ( params . num_entries > commands . size ( ) ) {
UNIMPLEMENTED ( ) ;
LOG_ERROR ( Service_NVDRV ,
" SubmitGPFIFO: num_entries={:#X} > provided commands={:#X} " ,
params . num_entries , commands . size ( ) ) ;
PostErrorNotification ( params . num_entries , 0 , NotifierStatus : : BadGpfifo ) ;
return NvResult : : InvalidSize ;
return NvResult : : InvalidSize ;
}
}
@ -409,7 +518,7 @@ NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params,
NvResult nvhost_gpu : : SubmitGPFIFOBase2 ( IoctlSubmitGpfifo & params ,
NvResult nvhost_gpu : : SubmitGPFIFOBase2 ( IoctlSubmitGpfifo & params ,
std : : span < const Tegra : : CommandListHeader > commands ) {
std : : span < const Tegra : : CommandListHeader > commands ) {
if ( params . num_entries > commands . size ( ) ) {
if ( params . num_entries > commands . size ( ) ) {
UNIMPLEMENTED ( ) ;
PostErrorNotification ( params . num_entries , 0 , NotifierStatus : : BadGpfifo ) ;
return NvResult : : InvalidSize ;
return NvResult : : InvalidSize ;
}
}