diff options
Diffstat (limited to 'src/core/hle/service')
43 files changed, 727 insertions, 543 deletions
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 1b1c8190e..f21553644 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -3,11 +3,13 @@ #include <algorithm> #include <array> + #include "common/common_types.h" #include "common/fs/file.h" #include "common/fs/path_util.h" #include "common/logging/log.h" #include "common/polyfill_ranges.h" +#include "common/stb.h" #include "common/string_util.h" #include "common/swap.h" #include "core/constants.h" @@ -38,9 +40,36 @@ static std::filesystem::path GetImagePath(const Common::UUID& uuid) { fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormattedString()); } -static constexpr u32 SanitizeJPEGSize(std::size_t size) { +static void JPGToMemory(void* context, void* data, int len) { + std::vector<u8>* jpg_image = static_cast<std::vector<u8>*>(context); + unsigned char* jpg = static_cast<unsigned char*>(data); + jpg_image->insert(jpg_image->end(), jpg, jpg + len); +} + +static void SanitizeJPEGImageSize(std::vector<u8>& image) { constexpr std::size_t max_jpeg_image_size = 0x20000; - return static_cast<u32>(std::min(size, max_jpeg_image_size)); + constexpr int profile_dimensions = 256; + int original_width, original_height, color_channels; + + const auto plain_image = + stbi_load_from_memory(image.data(), static_cast<int>(image.size()), &original_width, + &original_height, &color_channels, STBI_rgb); + + // Resize image to match 256*256 + if (original_width != profile_dimensions || original_height != profile_dimensions) { + // Use vector instead of array to avoid overflowing the stack + std::vector<u8> out_image(profile_dimensions * profile_dimensions * STBI_rgb); + stbir_resize_uint8_srgb(plain_image, original_width, original_height, 0, out_image.data(), + profile_dimensions, profile_dimensions, 0, STBI_rgb, 0, + STBIR_FILTER_BOX); + image.clear(); + if (!stbi_write_jpg_to_func(JPGToMemory, &image, profile_dimensions, profile_dimensions, + STBI_rgb, out_image.data(), 0)) { + LOG_ERROR(Service_ACC, "Failed to resize the user provided image."); + } + } + + image.resize(std::min(image.size(), max_jpeg_image_size)); } class IManagerForSystemService final : public ServiceFramework<IManagerForSystemService> { @@ -339,19 +368,20 @@ protected: LOG_WARNING(Service_ACC, "Failed to load user provided image! Falling back to built-in backup..."); ctx.WriteBuffer(Core::Constants::ACCOUNT_BACKUP_JPEG); - rb.Push(SanitizeJPEGSize(Core::Constants::ACCOUNT_BACKUP_JPEG.size())); + rb.Push(static_cast<u32>(Core::Constants::ACCOUNT_BACKUP_JPEG.size())); return; } - const u32 size = SanitizeJPEGSize(image.GetSize()); - std::vector<u8> buffer(size); + std::vector<u8> buffer(image.GetSize()); if (image.Read(buffer) != buffer.size()) { LOG_ERROR(Service_ACC, "Failed to read all the bytes in the user provided image."); } + SanitizeJPEGImageSize(buffer); + ctx.WriteBuffer(buffer); - rb.Push<u32>(size); + rb.Push(static_cast<u32>(buffer.size())); } void GetImageSize(HLERequestContext& ctx) { @@ -365,10 +395,18 @@ protected: if (!image.IsOpen()) { LOG_WARNING(Service_ACC, "Failed to load user provided image! Falling back to built-in backup..."); - rb.Push(SanitizeJPEGSize(Core::Constants::ACCOUNT_BACKUP_JPEG.size())); - } else { - rb.Push(SanitizeJPEGSize(image.GetSize())); + rb.Push(static_cast<u32>(Core::Constants::ACCOUNT_BACKUP_JPEG.size())); + return; } + + std::vector<u8> buffer(image.GetSize()); + + if (image.Read(buffer) != buffer.size()) { + LOG_ERROR(Service_ACC, "Failed to read all the bytes in the user provided image."); + } + + SanitizeJPEGImageSize(buffer); + rb.Push(static_cast<u32>(buffer.size())); } void Store(HLERequestContext& ctx) { diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 98765b81a..cc643ea09 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -23,6 +23,7 @@ #include "core/hle/service/am/applets/applet_cabinet.h" #include "core/hle/service/am/applets/applet_mii_edit_types.h" #include "core/hle/service/am/applets/applet_profile_select.h" +#include "core/hle/service/am/applets/applet_software_keyboard_types.h" #include "core/hle/service/am/applets/applet_web_browser.h" #include "core/hle/service/am/applets/applets.h" #include "core/hle/service/am/idle.h" @@ -31,6 +32,7 @@ #include "core/hle/service/apm/apm_controller.h" #include "core/hle/service/apm/apm_interface.h" #include "core/hle/service/bcat/backend/backend.h" +#include "core/hle/service/caps/caps_su.h" #include "core/hle/service/caps/caps_types.h" #include "core/hle/service/filesystem/filesystem.h" #include "core/hle/service/ipc_helpers.h" @@ -702,9 +704,17 @@ void ISelfController::SetAlbumImageTakenNotificationEnabled(HLERequestContext& c void ISelfController::SaveCurrentScreenshot(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; - const auto album_report_option = rp.PopEnum<Capture::AlbumReportOption>(); + const auto report_option = rp.PopEnum<Capture::AlbumReportOption>(); - LOG_WARNING(Service_AM, "(STUBBED) called. album_report_option={}", album_report_option); + LOG_INFO(Service_AM, "called, report_option={}", report_option); + + const auto screenshot_service = + system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>( + "caps:su"); + + if (screenshot_service) { + screenshot_service->CaptureAndSaveScreenshot(report_option); + } IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -796,7 +806,9 @@ ILockAccessor::ILockAccessor(Core::System& system_) lock_event = service_context.CreateEvent("ILockAccessor::LockEvent"); } -ILockAccessor::~ILockAccessor() = default; +ILockAccessor::~ILockAccessor() { + service_context.CloseEvent(lock_event); +}; void ILockAccessor::TryLock(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; @@ -909,7 +921,9 @@ ICommonStateGetter::ICommonStateGetter(Core::System& system_, msg_queue->PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); } -ICommonStateGetter::~ICommonStateGetter() = default; +ICommonStateGetter::~ICommonStateGetter() { + service_context.CloseEvent(sleep_lock_event); +}; void ICommonStateGetter::GetBootMode(HLERequestContext& ctx) { LOG_DEBUG(Service_AM, "called"); @@ -1558,7 +1572,7 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) {16, nullptr, "GetMainAppletStorageId"}, {17, nullptr, "GetCallerAppletIdentityInfoStack"}, {18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"}, - {19, nullptr, "GetDesirableKeyboardLayout"}, + {19, &ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout, "GetDesirableKeyboardLayout"}, {20, nullptr, "PopExtraStorage"}, {25, nullptr, "GetPopExtraStorageEvent"}, {30, nullptr, "UnpopInData"}, @@ -1577,7 +1591,7 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) {120, nullptr, "GetLaunchStorageInfoForDebug"}, {130, nullptr, "GetGpuErrorDetectedSystemEvent"}, {140, nullptr, "SetApplicationMemoryReservation"}, - {150, nullptr, "ShouldSetGpuTimeSliceManually"}, + {150, &ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually, "ShouldSetGpuTimeSliceManually"}, }; // clang-format on RegisterHandlers(functions); @@ -1592,6 +1606,9 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_) case Applets::AppletId::PhotoViewer: PushInShowAlbum(); break; + case Applets::AppletId::SoftwareKeyboard: + PushInShowSoftwareKeyboard(); + break; default: break; } @@ -1668,6 +1685,14 @@ void ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(HLERequestContext& rb.PushRaw(applet_info); } +void ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(0); +} + void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& ctx) { const Service::Account::ProfileManager manager{}; bool is_empty{true}; @@ -1687,6 +1712,14 @@ void ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(HLERequestContext& rb.Push(user_count); } +void ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(HLERequestContext& ctx) { + LOG_WARNING(Service_AM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + rb.Push<u8>(0); +} + void ILibraryAppletSelfAccessor::PushInShowAlbum() { const Applets::CommonArguments arguments{ .arguments_version = Applets::CommonArgumentVersion::Version3, @@ -1755,6 +1788,61 @@ void ILibraryAppletSelfAccessor::PushInShowMiiEditData() { queue_data.emplace_back(std::move(argument_data)); } +void ILibraryAppletSelfAccessor::PushInShowSoftwareKeyboard() { + const Applets::CommonArguments arguments{ + .arguments_version = Applets::CommonArgumentVersion::Version3, + .size = Applets::CommonArgumentSize::Version3, + .library_version = static_cast<u32>(Applets::SwkbdAppletVersion::Version524301), + .theme_color = Applets::ThemeColor::BasicBlack, + .play_startup_sound = true, + .system_tick = system.CoreTiming().GetClockTicks(), + }; + + std::vector<char16_t> initial_string(0); + + const Applets::SwkbdConfigCommon swkbd_config{ + .type = Applets::SwkbdType::Qwerty, + .ok_text{}, + .left_optional_symbol_key{}, + .right_optional_symbol_key{}, + .use_prediction = false, + .key_disable_flags{}, + .initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start, + .header_text{}, + .sub_text{}, + .guide_text{}, + .max_text_length = 500, + .min_text_length = 0, + .password_mode = Applets::SwkbdPasswordMode::Disabled, + .text_draw_type = Applets::SwkbdTextDrawType::Box, + .enable_return_button = true, + .use_utf8 = false, + .use_blur_background = true, + .initial_string_offset{}, + .initial_string_length = static_cast<u32>(initial_string.size()), + .user_dictionary_offset{}, + .user_dictionary_entries{}, + .use_text_check = false, + }; + + Applets::SwkbdConfigNew swkbd_config_new{}; + + std::vector<u8> argument_data(sizeof(arguments)); + std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); + std::vector<u8> work_buffer(swkbd_config.initial_string_length * sizeof(char16_t)); + + std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); + std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config)); + std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new, + sizeof(Applets::SwkbdConfigNew)); + std::memcpy(work_buffer.data(), initial_string.data(), + swkbd_config.initial_string_length * sizeof(char16_t)); + + queue_data.emplace_back(std::move(argument_data)); + queue_data.emplace_back(std::move(swkbd_data)); + queue_data.emplace_back(std::move(work_buffer)); +} + IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_) : ServiceFramework{system_, "IAppletCommonFunctions"} { // clang-format off diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 64b3f3fe2..8f8cb8a9e 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -347,11 +347,14 @@ private: void GetLibraryAppletInfo(HLERequestContext& ctx); void ExitProcessAndReturn(HLERequestContext& ctx); void GetCallerAppletIdentityInfo(HLERequestContext& ctx); + void GetDesirableKeyboardLayout(HLERequestContext& ctx); void GetMainAppletAvailableUsers(HLERequestContext& ctx); + void ShouldSetGpuTimeSliceManually(HLERequestContext& ctx); void PushInShowAlbum(); void PushInShowCabinetData(); void PushInShowMiiEditData(); + void PushInShowSoftwareKeyboard(); std::deque<std::vector<u8>> queue_data; }; diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index 19ed184e8..b379dadeb 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -25,7 +25,9 @@ Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent"); } -Cabinet::~Cabinet() = default; +Cabinet::~Cabinet() { + service_context.CloseEvent(availability_change_event); +}; void Cabinet::Initialize() { Applet::Initialize(); diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp index 1c9a1dc29..b0ea2b381 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.cpp +++ b/src/core/hle/service/am/applets/applet_web_browser.cpp @@ -330,8 +330,7 @@ void WebBrowser::ExtractOfflineRomFS() { LOG_DEBUG(Service_AM, "Extracting RomFS to {}", Common::FS::PathToUTF8String(offline_cache_dir)); - const auto extracted_romfs_dir = - FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard); + const auto extracted_romfs_dir = FileSys::ExtractRomFS(offline_romfs); const auto temp_dir = system.GetFilesystem()->CreateDirectory( Common::FS::PathToUTF8String(offline_cache_dir), FileSys::Mode::ReadWrite); diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index f02bbc450..0bf2598b7 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -69,6 +69,30 @@ enum class AppletId : u32 { MyPage = 0x1A, }; +enum class AppletProgramId : u64 { + QLaunch = 0x0100000000001000ull, + Auth = 0x0100000000001001ull, + Cabinet = 0x0100000000001002ull, + Controller = 0x0100000000001003ull, + DataErase = 0x0100000000001004ull, + Error = 0x0100000000001005ull, + NetConnect = 0x0100000000001006ull, + ProfileSelect = 0x0100000000001007ull, + SoftwareKeyboard = 0x0100000000001008ull, + MiiEdit = 0x0100000000001009ull, + Web = 0x010000000000100Aull, + Shop = 0x010000000000100Bull, + OverlayDisplay = 0x010000000000100Cull, + PhotoViewer = 0x010000000000100Dull, + Settings = 0x010000000000100Eull, + OfflineWeb = 0x010000000000100Full, + LoginShare = 0x0100000000001010ull, + WebAuth = 0x0100000000001011ull, + Starter = 0x0100000000001012ull, + MyPage = 0x0100000000001013ull, + MaxProgramId = 0x0100000000001FFFull, +}; + enum class LibraryAppletMode : u32 { AllForeground = 0, Background = 1, diff --git a/src/core/hle/service/caps/caps_manager.cpp b/src/core/hle/service/caps/caps_manager.cpp index 7d733eb54..96b225d5f 100644 --- a/src/core/hle/service/caps/caps_manager.cpp +++ b/src/core/hle/service/caps/caps_manager.cpp @@ -228,12 +228,14 @@ Result AlbumManager::LoadAlbumScreenShotThumbnail( Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, - std::span<const u8> image_data, u64 aruid) { - return SaveScreenShot(out_entry, attribute, {}, image_data, aruid); + AlbumReportOption report_option, std::span<const u8> image_data, + u64 aruid) { + return SaveScreenShot(out_entry, attribute, report_option, {}, image_data, aruid); } Result AlbumManager::SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, + AlbumReportOption report_option, const ApplicationData& app_data, std::span<const u8> image_data, u64 aruid) { const u64 title_id = system.GetApplicationProcessProgramID(); @@ -407,10 +409,14 @@ Result AlbumManager::LoadImage(std::span<u8> out_image, const std::filesystem::p return ResultSuccess; } -static void PNGToMemory(void* context, void* png, int len) { +void AlbumManager::FlipVerticallyOnWrite(bool flip) { + stbi_flip_vertically_on_write(flip); +} + +static void PNGToMemory(void* context, void* data, int len) { std::vector<u8>* png_image = static_cast<std::vector<u8>*>(context); - png_image->reserve(len); - std::memcpy(png_image->data(), png, len); + unsigned char* png = static_cast<unsigned char*>(data); + png_image->insert(png_image->end(), png, png + len); } Result AlbumManager::SaveImage(ApplicationAlbumEntry& out_entry, std::span<const u8> image, diff --git a/src/core/hle/service/caps/caps_manager.h b/src/core/hle/service/caps/caps_manager.h index 44d85117f..e20c70c7b 100644 --- a/src/core/hle/service/caps/caps_manager.h +++ b/src/core/hle/service/caps/caps_manager.h @@ -59,14 +59,17 @@ public: const ScreenShotDecodeOption& decoder_options) const; Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, - std::span<const u8> image_data, u64 aruid); - Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, - const ApplicationData& app_data, std::span<const u8> image_data, + AlbumReportOption report_option, std::span<const u8> image_data, u64 aruid); + Result SaveScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, + AlbumReportOption report_option, const ApplicationData& app_data, + std::span<const u8> image_data, u64 aruid); Result SaveEditedScreenShot(ApplicationAlbumEntry& out_entry, const ScreenShotAttribute& attribute, const AlbumFileId& file_id, std::span<const u8> image_data); + void FlipVerticallyOnWrite(bool flip); + private: static constexpr std::size_t NandAlbumFileLimit = 1000; static constexpr std::size_t SdAlbumFileLimit = 10000; diff --git a/src/core/hle/service/caps/caps_ss.cpp b/src/core/hle/service/caps/caps_ss.cpp index 1ba2b7972..eab023568 100644 --- a/src/core/hle/service/caps/caps_ss.cpp +++ b/src/core/hle/service/caps/caps_ss.cpp @@ -34,7 +34,7 @@ void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { ScreenShotAttribute attribute{}; - u32 report_option{}; + AlbumReportOption report_option{}; INSERT_PADDING_BYTES(0x4); u64 applet_resource_user_id{}; }; @@ -49,13 +49,16 @@ void IScreenShotService::SaveScreenShotEx0(HLERequestContext& ctx) { parameters.applet_resource_user_id); ApplicationAlbumEntry entry{}; - const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer, - parameters.applet_resource_user_id); + manager->FlipVerticallyOnWrite(false); + const auto result = + manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option, + image_data_buffer, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 10}; rb.Push(result); rb.PushRaw(entry); } + void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { @@ -83,6 +86,7 @@ void IScreenShotService::SaveEditedScreenShotEx1(HLERequestContext& ctx) { image_data_buffer.size(), thumbnail_image_data_buffer.size()); ApplicationAlbumEntry entry{}; + manager->FlipVerticallyOnWrite(false); const auto result = manager->SaveEditedScreenShot(entry, parameters.attribute, parameters.file_id, image_data_buffer); diff --git a/src/core/hle/service/caps/caps_su.cpp b/src/core/hle/service/caps/caps_su.cpp index e85625ee4..296b07b00 100644 --- a/src/core/hle/service/caps/caps_su.cpp +++ b/src/core/hle/service/caps/caps_su.cpp @@ -2,10 +2,12 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/logging/log.h" +#include "core/core.h" #include "core/hle/service/caps/caps_manager.h" #include "core/hle/service/caps/caps_su.h" #include "core/hle/service/caps/caps_types.h" #include "core/hle/service/ipc_helpers.h" +#include "video_core/renderer_base.h" namespace Service::Capture { @@ -58,8 +60,10 @@ void IScreenShotApplicationService::SaveScreenShotEx0(HLERequestContext& ctx) { parameters.applet_resource_user_id); ApplicationAlbumEntry entry{}; - const auto result = manager->SaveScreenShot(entry, parameters.attribute, image_data_buffer, - parameters.applet_resource_user_id); + manager->FlipVerticallyOnWrite(false); + const auto result = + manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option, + image_data_buffer, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 10}; rb.Push(result); @@ -88,13 +92,43 @@ void IScreenShotApplicationService::SaveScreenShotEx1(HLERequestContext& ctx) { ApplicationAlbumEntry entry{}; ApplicationData app_data{}; std::memcpy(&app_data, app_data_buffer.data(), sizeof(ApplicationData)); + manager->FlipVerticallyOnWrite(false); const auto result = - manager->SaveScreenShot(entry, parameters.attribute, app_data, image_data_buffer, - parameters.applet_resource_user_id); + manager->SaveScreenShot(entry, parameters.attribute, parameters.report_option, app_data, + image_data_buffer, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 10}; rb.Push(result); rb.PushRaw(entry); } +void IScreenShotApplicationService::CaptureAndSaveScreenshot(AlbumReportOption report_option) { + auto& renderer = system.Renderer(); + Layout::FramebufferLayout layout = + Layout::DefaultFrameLayout(screenshot_width, screenshot_height); + + const Capture::ScreenShotAttribute attribute{ + .unknown_0{}, + .orientation = Capture::AlbumImageOrientation::None, + .unknown_1{}, + .unknown_2{}, + }; + + renderer.RequestScreenshot( + image_data.data(), + [attribute, report_option, this](bool invert_y) { + // Convert from BGRA to RGBA + for (std::size_t i = 0; i < image_data.size(); i += bytes_per_pixel) { + const u8 temp = image_data[i]; + image_data[i] = image_data[i + 2]; + image_data[i + 2] = temp; + } + + Capture::ApplicationAlbumEntry entry{}; + manager->FlipVerticallyOnWrite(invert_y); + manager->SaveScreenShot(entry, attribute, report_option, image_data, {}); + }, + layout); +} + } // namespace Service::Capture diff --git a/src/core/hle/service/caps/caps_su.h b/src/core/hle/service/caps/caps_su.h index 89e71f506..21912e95f 100644 --- a/src/core/hle/service/caps/caps_su.h +++ b/src/core/hle/service/caps/caps_su.h @@ -10,6 +10,7 @@ class System; } namespace Service::Capture { +enum class AlbumReportOption : s32; class AlbumManager; class IScreenShotApplicationService final : public ServiceFramework<IScreenShotApplicationService> { @@ -18,11 +19,19 @@ public: std::shared_ptr<AlbumManager> album_manager); ~IScreenShotApplicationService() override; + void CaptureAndSaveScreenshot(AlbumReportOption report_option); + private: + static constexpr std::size_t screenshot_width = 1280; + static constexpr std::size_t screenshot_height = 720; + static constexpr std::size_t bytes_per_pixel = 4; + void SetShimLibraryVersion(HLERequestContext& ctx); void SaveScreenShotEx0(HLERequestContext& ctx); void SaveScreenShotEx1(HLERequestContext& ctx); + std::array<u8, screenshot_width * screenshot_height * bytes_per_pixel> image_data; + std::shared_ptr<AlbumManager> manager; }; diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index bc822f19e..21695bda2 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -1108,9 +1108,9 @@ Result Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { shared_memory->sixaxis_dual_right_properties.raw = 0; shared_memory->sixaxis_left_properties.raw = 0; shared_memory->sixaxis_right_properties.raw = 0; - shared_memory->battery_level_dual = 0; - shared_memory->battery_level_left = 0; - shared_memory->battery_level_right = 0; + shared_memory->battery_level_dual = Core::HID::NpadBatteryLevel::Empty; + shared_memory->battery_level_left = Core::HID::NpadBatteryLevel::Empty; + shared_memory->battery_level_right = Core::HID::NpadBatteryLevel::Empty; shared_memory->fullkey_color = { .attribute = ColorAttribute::NoController, .fullkey = {}, diff --git a/src/core/hle/service/hid/controllers/palma.cpp b/src/core/hle/service/hid/controllers/palma.cpp index 14c67e454..73a2a2b91 100644 --- a/src/core/hle/service/hid/controllers/palma.cpp +++ b/src/core/hle/service/hid/controllers/palma.cpp @@ -19,7 +19,9 @@ Controller_Palma::Controller_Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent"); } -Controller_Palma::~Controller_Palma() = default; +Controller_Palma::~Controller_Palma() { + service_context.CloseEvent(operation_complete_event); +}; void Controller_Palma::OnInit() {} diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 4d70006c1..1d4101be9 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -1353,7 +1353,7 @@ void Hid::IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx) { void Hid::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; struct Parameters { - bool unintended_home_button_input_protection; + bool is_enabled; INSERT_PADDING_BYTES_NOINIT(3); Core::HID::NpadIdType npad_id; u64 applet_resource_user_id; @@ -1364,13 +1364,11 @@ void Hid::EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx) { auto& controller = GetAppletResource()->GetController<Controller_NPad>(HidController::NPad); const auto result = controller.SetUnintendedHomeButtonInputProtectionEnabled( - parameters.unintended_home_button_input_protection, parameters.npad_id); + parameters.is_enabled, parameters.npad_id); - LOG_WARNING(Service_HID, - "(STUBBED) called, unintended_home_button_input_protection={}, npad_id={}," - "applet_resource_user_id={}", - parameters.unintended_home_button_input_protection, parameters.npad_id, - parameters.applet_resource_user_id); + LOG_DEBUG(Service_HID, + "(STUBBED) called, is_enabled={}, npad_id={}, applet_resource_user_id={}", + parameters.is_enabled, parameters.npad_id, parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); @@ -2757,6 +2755,10 @@ public: joy_detach_event = service_context.CreateEvent("HidSys::JoyDetachEvent"); } + ~HidSys() { + service_context.CloseEvent(joy_detach_event); + }; + private: void ApplyNpadSystemCommonPolicy(HLERequestContext& ctx) { LOG_WARNING(Service_HID, "called"); diff --git a/src/core/hle/service/hid/hidbus/hidbus_base.cpp b/src/core/hle/service/hid/hidbus/hidbus_base.cpp index ee522c36e..8c44f93e8 100644 --- a/src/core/hle/service/hid/hidbus/hidbus_base.cpp +++ b/src/core/hle/service/hid/hidbus/hidbus_base.cpp @@ -13,7 +13,10 @@ HidbusBase::HidbusBase(Core::System& system_, KernelHelpers::ServiceContext& ser : system(system_), service_context(service_context_) { send_command_async_event = service_context.CreateEvent("hidbus:SendCommandAsyncEvent"); } -HidbusBase::~HidbusBase() = default; + +HidbusBase::~HidbusBase() { + service_context.CloseEvent(send_command_async_event); +}; void HidbusBase::ActivateDevice() { if (is_activated) { diff --git a/src/core/hle/service/hid/ring_lifo.h b/src/core/hle/service/hid/ring_lifo.h index 65eb7ea02..0816784e0 100644 --- a/src/core/hle/service/hid/ring_lifo.h +++ b/src/core/hle/service/hid/ring_lifo.h @@ -32,15 +32,15 @@ struct Lifo { } std::size_t GetPreviousEntryIndex() const { - return static_cast<size_t>((buffer_tail + total_buffer_count - 1) % total_buffer_count); + return static_cast<size_t>((buffer_tail + max_buffer_size - 1) % max_buffer_size); } std::size_t GetNextEntryIndex() const { - return static_cast<size_t>((buffer_tail + 1) % total_buffer_count); + return static_cast<size_t>((buffer_tail + 1) % max_buffer_size); } void WriteNextEntry(const State& new_state) { - if (buffer_count < total_buffer_count - 1) { + if (buffer_count < static_cast<s64>(max_buffer_size) - 1) { buffer_count++; } buffer_tail = GetNextEntryIndex(); diff --git a/src/core/hle/service/kernel_helpers.cpp b/src/core/hle/service/kernel_helpers.cpp index 6a313a03b..f51e63564 100644 --- a/src/core/hle/service/kernel_helpers.cpp +++ b/src/core/hle/service/kernel_helpers.cpp @@ -21,10 +21,8 @@ ServiceContext::ServiceContext(Core::System& system_, std::string name_) // Create the process. process = Kernel::KProcess::Create(kernel); - ASSERT(Kernel::KProcess::Initialize(process, system_, std::move(name_), - Kernel::KProcess::ProcessType::KernelInternal, - kernel.GetSystemResourceLimit()) - .IsSuccess()); + ASSERT(R_SUCCEEDED(process->Initialize(Kernel::Svc::CreateProcessParameter{}, + kernel.GetSystemResourceLimit(), false))); // Register the process. Kernel::KProcess::Register(kernel, process); diff --git a/src/core/hle/service/nvdrv/devices/ioctl_serialization.h b/src/core/hle/service/nvdrv/devices/ioctl_serialization.h new file mode 100644 index 000000000..b12bcd138 --- /dev/null +++ b/src/core/hle/service/nvdrv/devices/ioctl_serialization.h @@ -0,0 +1,159 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <span> +#include <vector> + +#include "common/concepts.h" +#include "core/hle/service/nvdrv/devices/nvdevice.h" + +namespace Service::Nvidia::Devices { + +struct IoctlOneArgTraits { + template <typename T, typename R, typename A, typename... B> + static A GetFirstArgImpl(R (T::*)(A, B...)); +}; + +struct IoctlTwoArgTraits { + template <typename T, typename R, typename A, typename B, typename... C> + static A GetFirstArgImpl(R (T::*)(A, B, C...)); + + template <typename T, typename R, typename A, typename B, typename... C> + static B GetSecondArgImpl(R (T::*)(A, B, C...)); +}; + +struct Null {}; + +// clang-format off + +template <typename FixedArg, typename VarArg, typename InlInVarArg, typename InlOutVarArg, typename F> +NvResult WrapGeneric(F&& callable, std::span<const u8> input, std::span<const u8> inline_input, std::span<u8> output, std::span<u8> inline_output) { + constexpr bool HasFixedArg = !std::is_same_v<FixedArg, Null>; + constexpr bool HasVarArg = !std::is_same_v<VarArg, Null>; + constexpr bool HasInlInVarArg = !std::is_same_v<InlInVarArg, Null>; + constexpr bool HasInlOutVarArg = !std::is_same_v<InlOutVarArg, Null>; + + // Declare the fixed-size input value. + FixedArg fixed{}; + size_t var_offset = 0; + + if constexpr (HasFixedArg) { + // Read the fixed-size input value. + var_offset = std::min(sizeof(FixedArg), input.size()); + if (var_offset > 0) { + std::memcpy(&fixed, input.data(), var_offset); + } + } + + // Read the variable-sized inputs. + const size_t num_var_args = HasVarArg ? ((input.size() - var_offset) / sizeof(VarArg)) : 0; + std::vector<VarArg> var_args(num_var_args); + if constexpr (HasVarArg) { + if (num_var_args > 0) { + std::memcpy(var_args.data(), input.data() + var_offset, num_var_args * sizeof(VarArg)); + } + } + + const size_t num_inl_in_var_args = HasInlInVarArg ? (inline_input.size() / sizeof(InlInVarArg)) : 0; + std::vector<InlInVarArg> inl_in_var_args(num_inl_in_var_args); + if constexpr (HasInlInVarArg) { + if (num_inl_in_var_args > 0) { + std::memcpy(inl_in_var_args.data(), inline_input.data(), num_inl_in_var_args * sizeof(InlInVarArg)); + } + } + + // Construct inline output data. + const size_t num_inl_out_var_args = HasInlOutVarArg ? (inline_output.size() / sizeof(InlOutVarArg)) : 0; + std::vector<InlOutVarArg> inl_out_var_args(num_inl_out_var_args); + + // Perform the call. + NvResult result = callable(fixed, var_args, inl_in_var_args, inl_out_var_args); + + // Copy outputs. + if constexpr (HasFixedArg) { + if (output.size() > 0) { + std::memcpy(output.data(), &fixed, std::min(output.size(), sizeof(FixedArg))); + } + } + + if constexpr (HasVarArg) { + if (num_var_args > 0 && output.size() > var_offset) { + const size_t max_var_size = output.size() - var_offset; + std::memcpy(output.data() + var_offset, var_args.data(), std::min(max_var_size, num_var_args * sizeof(VarArg))); + } + } + + // Copy inline outputs. + if constexpr (HasInlOutVarArg) { + if (num_inl_out_var_args > 0) { + std::memcpy(inline_output.data(), inl_out_var_args.data(), num_inl_out_var_args * sizeof(InlOutVarArg)); + } + } + + // We're done. + return result; +} + +template <typename Self, typename F, typename... Rest> +NvResult WrapFixed(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) { + using FixedArg = typename std::remove_reference_t<decltype(IoctlOneArgTraits::GetFirstArgImpl(callable))>; + + const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult { + return (self->*callable)(fixed, std::forward<Rest>(rest)...); + }; + + return WrapGeneric<FixedArg, Null, Null, Null>(std::move(Callable), input, {}, output, {}); +} + +template <typename Self, typename F, typename... Rest> +NvResult WrapFixedInlOut(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, std::span<u8> inline_output, Rest&&... rest) { + using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>; + using InlOutVarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type; + + const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult { + return (self->*callable)(fixed, inl_out, std::forward<Rest>(rest)...); + }; + + return WrapGeneric<FixedArg, Null, Null, InlOutVarArg>(std::move(Callable), input, {}, output, inline_output); +} + +template <typename Self, typename F, typename... Rest> +NvResult WrapVariable(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) { + using VarArg = typename std::remove_reference_t<decltype(IoctlOneArgTraits::GetFirstArgImpl(callable))>::value_type; + + const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult { + return (self->*callable)(var, std::forward<Rest>(rest)...); + }; + + return WrapGeneric<Null, VarArg, Null, Null>(std::move(Callable), input, {}, output, {}); +} + +template <typename Self, typename F, typename... Rest> +NvResult WrapFixedVariable(Self* self, F&& callable, std::span<const u8> input, std::span<u8> output, Rest&&... rest) { + using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>; + using VarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type; + + const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult { + return (self->*callable)(fixed, var, std::forward<Rest>(rest)...); + }; + + return WrapGeneric<FixedArg, VarArg, Null, Null>(std::move(Callable), input, {}, output, {}); +} + +template <typename Self, typename F, typename... Rest> +NvResult WrapFixedInlIn(Self* self, F&& callable, std::span<const u8> input, std::span<const u8> inline_input, std::span<u8> output, Rest&&... rest) { + using FixedArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetFirstArgImpl(callable))>; + using InlInVarArg = typename std::remove_reference_t<decltype(IoctlTwoArgTraits::GetSecondArgImpl(callable))>::value_type; + + const auto Callable = [&](auto& fixed, auto& var, auto& inl_in, auto& inl_out) -> NvResult { + return (self->*callable)(fixed, inl_in, std::forward<Rest>(rest)...); + }; + + return WrapGeneric<FixedArg, Null, InlInVarArg, Null>(std::move(Callable), input, inline_input, output, {}); +} + +// clang-format on + +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index 7d7bb8687..6b3639008 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp @@ -11,6 +11,7 @@ #include "core/core.h" #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/nvmap.h" +#include "core/hle/service/nvdrv/devices/ioctl_serialization.h" #include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" #include "core/hle/service/nvdrv/nvdrv.h" @@ -33,21 +34,21 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> i case 'A': switch (command.cmd) { case 0x1: - return BindChannel(input, output); + return WrapFixed(this, &nvhost_as_gpu::BindChannel, input, output); case 0x2: - return AllocateSpace(input, output); + return WrapFixed(this, &nvhost_as_gpu::AllocateSpace, input, output); case 0x3: - return FreeSpace(input, output); + return WrapFixed(this, &nvhost_as_gpu::FreeSpace, input, output); case 0x5: - return UnmapBuffer(input, output); + return WrapFixed(this, &nvhost_as_gpu::UnmapBuffer, input, output); case 0x6: - return MapBufferEx(input, output); + return WrapFixed(this, &nvhost_as_gpu::MapBufferEx, input, output); case 0x8: - return GetVARegions(input, output); + return WrapFixed(this, &nvhost_as_gpu::GetVARegions1, input, output); case 0x9: - return AllocAsEx(input, output); + return WrapFixed(this, &nvhost_as_gpu::AllocAsEx, input, output); case 0x14: - return Remap(input, output); + return WrapVariable(this, &nvhost_as_gpu::Remap, input, output); default: break; } @@ -72,7 +73,8 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i case 'A': switch (command.cmd) { case 0x8: - return GetVARegions(input, output, inline_output); + return WrapFixedInlOut(this, &nvhost_as_gpu::GetVARegions3, input, output, + inline_output); default: break; } @@ -87,10 +89,7 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i void nvhost_as_gpu::OnOpen(DeviceFD fd) {} void nvhost_as_gpu::OnClose(DeviceFD fd) {} -NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::span<u8> output) { - IoctlAllocAsEx params{}; - std::memcpy(¶ms, input.data(), input.size()); - +NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) { LOG_DEBUG(Service_NVDRV, "called, big_page_size=0x{:X}", params.big_page_size); std::scoped_lock lock(mutex); @@ -141,10 +140,7 @@ NvResult nvhost_as_gpu::AllocAsEx(std::span<const u8> input, std::span<u8> outpu return NvResult::Success; } -NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::span<u8> output) { - IoctlAllocSpace params{}; - std::memcpy(¶ms, input.data(), input.size()); - +NvResult nvhost_as_gpu::AllocateSpace(IoctlAllocSpace& params) { LOG_DEBUG(Service_NVDRV, "called, pages={:X}, page_size={:X}, flags={:X}", params.pages, params.page_size, params.flags); @@ -194,7 +190,6 @@ NvResult nvhost_as_gpu::AllocateSpace(std::span<const u8> input, std::span<u8> o .big_pages = params.page_size != VM::YUZU_PAGESIZE, }; - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } @@ -222,10 +217,7 @@ void nvhost_as_gpu::FreeMappingLocked(u64 offset) { mapping_map.erase(offset); } -NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::span<u8> output) { - IoctlFreeSpace params{}; - std::memcpy(¶ms, input.data(), input.size()); - +NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) { LOG_DEBUG(Service_NVDRV, "called, offset={:X}, pages={:X}, page_size={:X}", params.offset, params.pages, params.page_size); @@ -264,18 +256,11 @@ NvResult nvhost_as_gpu::FreeSpace(std::span<const u8> input, std::span<u8> outpu return NvResult::BadValue; } - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } -NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::span<u8> output) { - const auto num_entries = input.size() / sizeof(IoctlRemapEntry); - - LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); - - std::scoped_lock lock(mutex); - entries.resize_destructive(num_entries); - std::memcpy(entries.data(), input.data(), input.size()); +NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries) { + LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", entries.size()); if (!vm.initialised) { return NvResult::BadValue; @@ -317,14 +302,10 @@ NvResult nvhost_as_gpu::Remap(std::span<const u8> input, std::span<u8> output) { } } - std::memcpy(output.data(), entries.data(), output.size()); return NvResult::Success; } -NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::span<u8> output) { - IoctlMapBufferEx params{}; - std::memcpy(¶ms, input.data(), input.size()); - +NvResult nvhost_as_gpu::MapBufferEx(IoctlMapBufferEx& params) { LOG_DEBUG(Service_NVDRV, "called, flags={:X}, nvmap_handle={:X}, buffer_offset={}, mapping_size={}" ", offset={}", @@ -421,14 +402,10 @@ NvResult nvhost_as_gpu::MapBufferEx(std::span<const u8> input, std::span<u8> out mapping_map[params.offset] = mapping; } - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } -NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::span<u8> output) { - IoctlUnmapBuffer params{}; - std::memcpy(¶ms, input.data(), input.size()); - +NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) { LOG_DEBUG(Service_NVDRV, "called, offset=0x{:X}", params.offset); std::scoped_lock lock(mutex); @@ -464,9 +441,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(std::span<const u8> input, std::span<u8> out return NvResult::Success; } -NvResult nvhost_as_gpu::BindChannel(std::span<const u8> input, std::span<u8> output) { - IoctlBindChannel params{}; - std::memcpy(¶ms, input.data(), input.size()); +NvResult nvhost_as_gpu::BindChannel(IoctlBindChannel& params) { LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); auto gpu_channel_device = module.GetDevice<nvhost_gpu>(params.fd); @@ -493,10 +468,7 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) { }; } -NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output) { - IoctlGetVaRegions params{}; - std::memcpy(¶ms, input.data(), input.size()); - +NvResult nvhost_as_gpu::GetVARegions1(IoctlGetVaRegions& params) { LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr, params.buf_size); @@ -508,15 +480,10 @@ NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> ou GetVARegionsImpl(params); - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } -NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> output, - std::span<u8> inline_output) { - IoctlGetVaRegions params{}; - std::memcpy(¶ms, input.data(), input.size()); - +NvResult nvhost_as_gpu::GetVARegions3(IoctlGetVaRegions& params, std::span<VaRegion> regions) { LOG_DEBUG(Service_NVDRV, "called, buf_addr={:X}, buf_size={:X}", params.buf_addr, params.buf_size); @@ -528,9 +495,10 @@ NvResult nvhost_as_gpu::GetVARegions(std::span<const u8> input, std::span<u8> ou GetVARegionsImpl(params); - std::memcpy(output.data(), ¶ms, output.size()); - std::memcpy(inline_output.data(), ¶ms.regions[0], sizeof(VaRegion)); - std::memcpy(inline_output.data() + sizeof(VaRegion), ¶ms.regions[1], sizeof(VaRegion)); + const size_t num_regions = std::min(params.regions.size(), regions.size()); + for (size_t i = 0; i < num_regions; i++) { + regions[i] = params.regions[i]; + } return NvResult::Success; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h index 2af3e1260..932997e75 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h @@ -139,18 +139,17 @@ private: static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2, "IoctlGetVaRegions is incorrect size"); - NvResult AllocAsEx(std::span<const u8> input, std::span<u8> output); - NvResult AllocateSpace(std::span<const u8> input, std::span<u8> output); - NvResult Remap(std::span<const u8> input, std::span<u8> output); - NvResult MapBufferEx(std::span<const u8> input, std::span<u8> output); - NvResult UnmapBuffer(std::span<const u8> input, std::span<u8> output); - NvResult FreeSpace(std::span<const u8> input, std::span<u8> output); - NvResult BindChannel(std::span<const u8> input, std::span<u8> output); + NvResult AllocAsEx(IoctlAllocAsEx& params); + NvResult AllocateSpace(IoctlAllocSpace& params); + NvResult Remap(std::span<IoctlRemapEntry> params); + NvResult MapBufferEx(IoctlMapBufferEx& params); + NvResult UnmapBuffer(IoctlUnmapBuffer& params); + NvResult FreeSpace(IoctlFreeSpace& params); + NvResult BindChannel(IoctlBindChannel& params); void GetVARegionsImpl(IoctlGetVaRegions& params); - NvResult GetVARegions(std::span<const u8> input, std::span<u8> output); - NvResult GetVARegions(std::span<const u8> input, std::span<u8> output, - std::span<u8> inline_output); + NvResult GetVARegions1(IoctlGetVaRegions& params); + NvResult GetVARegions3(IoctlGetVaRegions& params, std::span<VaRegion> regions); void FreeMappingLocked(u64 offset); @@ -213,7 +212,6 @@ private: bool initialised{}; } vm; std::shared_ptr<Tegra::MemoryManager> gmmu; - Common::ScratchBuffer<IoctlRemapEntry> entries; // s32 channel{}; // u32 big_page_size{VM::DEFAULT_BIG_PAGE_SIZE}; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp index 4d55554b4..b8dd34e24 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp @@ -14,6 +14,7 @@ #include "core/hle/kernel/k_event.h" #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h" +#include "core/hle/service/nvdrv/devices/ioctl_serialization.h" #include "core/hle/service/nvdrv/devices/nvhost_ctrl.h" #include "video_core/gpu.h" #include "video_core/host1x/host1x.h" @@ -40,19 +41,19 @@ NvResult nvhost_ctrl::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inp case 0x0: switch (command.cmd) { case 0x1b: - return NvOsGetConfigU32(input, output); + return WrapFixed(this, &nvhost_ctrl::NvOsGetConfigU32, input, output); case 0x1c: - return IocCtrlClearEventWait(input, output); + return WrapFixed(this, &nvhost_ctrl::IocCtrlClearEventWait, input, output); case 0x1d: - return IocCtrlEventWait(input, output, true); + return WrapFixed(this, &nvhost_ctrl::IocCtrlEventWait, input, output, true); case 0x1e: - return IocCtrlEventWait(input, output, false); + return WrapFixed(this, &nvhost_ctrl::IocCtrlEventWait, input, output, false); case 0x1f: - return IocCtrlEventRegister(input, output); + return WrapFixed(this, &nvhost_ctrl::IocCtrlEventRegister, input, output); case 0x20: - return IocCtrlEventUnregister(input, output); + return WrapFixed(this, &nvhost_ctrl::IocCtrlEventUnregister, input, output); case 0x21: - return IocCtrlEventUnregisterBatch(input, output); + return WrapFixed(this, &nvhost_ctrl::IocCtrlEventUnregisterBatch, input, output); } break; default: @@ -79,25 +80,19 @@ void nvhost_ctrl::OnOpen(DeviceFD fd) {} void nvhost_ctrl::OnClose(DeviceFD fd) {} -NvResult nvhost_ctrl::NvOsGetConfigU32(std::span<const u8> input, std::span<u8> output) { - IocGetConfigParams params{}; - std::memcpy(¶ms, input.data(), sizeof(params)); +NvResult nvhost_ctrl::NvOsGetConfigU32(IocGetConfigParams& params) { LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), params.param_str.data()); return NvResult::ConfigVarNotFound; // Returns error on production mode } -NvResult nvhost_ctrl::IocCtrlEventWait(std::span<const u8> input, std::span<u8> output, - bool is_allocation) { - IocCtrlEventWaitParams params{}; - std::memcpy(¶ms, input.data(), sizeof(params)); +NvResult nvhost_ctrl::IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_allocation) { LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_allocation={}", params.fence.id, params.fence.value, params.timeout, is_allocation); bool must_unmark_fail = !is_allocation; const u32 event_id = params.value.raw; SCOPE_EXIT({ - std::memcpy(output.data(), ¶ms, sizeof(params)); if (must_unmark_fail) { events[event_id].fails = 0; } @@ -231,9 +226,7 @@ NvResult nvhost_ctrl::FreeEvent(u32 slot) { return NvResult::Success; } -NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::span<u8> output) { - IocCtrlEventRegisterParams params{}; - std::memcpy(¶ms, input.data(), sizeof(params)); +NvResult nvhost_ctrl::IocCtrlEventRegister(IocCtrlEventRegisterParams& params) { const u32 event_id = params.user_event_id; LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id); if (event_id >= MaxNvEvents) { @@ -252,9 +245,7 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(std::span<const u8> input, std::span< return NvResult::Success; } -NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::span<u8> output) { - IocCtrlEventUnregisterParams params{}; - std::memcpy(¶ms, input.data(), sizeof(params)); +NvResult nvhost_ctrl::IocCtrlEventUnregister(IocCtrlEventUnregisterParams& params) { const u32 event_id = params.user_event_id & 0x00FF; LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id); @@ -262,9 +253,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(std::span<const u8> input, std::spa return FreeEvent(event_id); } -NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input, std::span<u8> output) { - IocCtrlEventUnregisterBatchParams params{}; - std::memcpy(¶ms, input.data(), sizeof(params)); +NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(IocCtrlEventUnregisterBatchParams& params) { u64 event_mask = params.user_events; LOG_DEBUG(Service_NVDRV, " called, event_mask: {:X}", event_mask); @@ -280,10 +269,7 @@ NvResult nvhost_ctrl::IocCtrlEventUnregisterBatch(std::span<const u8> input, std return NvResult::Success; } -NvResult nvhost_ctrl::IocCtrlClearEventWait(std::span<const u8> input, std::span<u8> output) { - IocCtrlEventClearParams params{}; - std::memcpy(¶ms, input.data(), sizeof(params)); - +NvResult nvhost_ctrl::IocCtrlClearEventWait(IocCtrlEventClearParams& params) { u32 event_id = params.event_id.slot; LOG_DEBUG(Service_NVDRV, "called, event_id: {:X}", event_id); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h index 2efed4862..992124b60 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h @@ -186,12 +186,12 @@ private: static_assert(sizeof(IocCtrlEventUnregisterBatchParams) == 8, "IocCtrlEventKill is incorrect size"); - NvResult NvOsGetConfigU32(std::span<const u8> input, std::span<u8> output); - NvResult IocCtrlEventWait(std::span<const u8> input, std::span<u8> output, bool is_allocation); - NvResult IocCtrlEventRegister(std::span<const u8> input, std::span<u8> output); - NvResult IocCtrlEventUnregister(std::span<const u8> input, std::span<u8> output); - NvResult IocCtrlEventUnregisterBatch(std::span<const u8> input, std::span<u8> output); - NvResult IocCtrlClearEventWait(std::span<const u8> input, std::span<u8> output); + NvResult NvOsGetConfigU32(IocGetConfigParams& params); + NvResult IocCtrlEventRegister(IocCtrlEventRegisterParams& params); + NvResult IocCtrlEventUnregister(IocCtrlEventUnregisterParams& params); + NvResult IocCtrlEventUnregisterBatch(IocCtrlEventUnregisterBatchParams& params); + NvResult IocCtrlEventWait(IocCtrlEventWaitParams& params, bool is_allocation); + NvResult IocCtrlClearEventWait(IocCtrlEventClearParams& params); NvResult FreeEvent(u32 slot); diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 6081d92e9..61a2df121 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -6,6 +6,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/core_timing.h" +#include "core/hle/service/nvdrv/devices/ioctl_serialization.h" #include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" #include "core/hle/service/nvdrv/nvdrv.h" @@ -27,23 +28,23 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> case 'G': switch (command.cmd) { case 0x1: - return ZCullGetCtxSize(input, output); + return WrapFixed(this, &nvhost_ctrl_gpu::ZCullGetCtxSize, input, output); case 0x2: - return ZCullGetInfo(input, output); + return WrapFixed(this, &nvhost_ctrl_gpu::ZCullGetInfo, input, output); case 0x3: - return ZBCSetTable(input, output); + return WrapFixed(this, &nvhost_ctrl_gpu::ZBCSetTable, input, output); case 0x4: - return ZBCQueryTable(input, output); + return WrapFixed(this, &nvhost_ctrl_gpu::ZBCQueryTable, input, output); case 0x5: - return GetCharacteristics(input, output); + return WrapFixed(this, &nvhost_ctrl_gpu::GetCharacteristics1, input, output); case 0x6: - return GetTPCMasks(input, output); + return WrapFixed(this, &nvhost_ctrl_gpu::GetTPCMasks1, input, output); case 0x7: - return FlushL2(input, output); + return WrapFixed(this, &nvhost_ctrl_gpu::FlushL2, input, output); case 0x14: - return GetActiveSlotMask(input, output); + return WrapFixed(this, &nvhost_ctrl_gpu::GetActiveSlotMask, input, output); case 0x1c: - return GetGpuTime(input, output); + return WrapFixed(this, &nvhost_ctrl_gpu::GetGpuTime, input, output); default: break; } @@ -65,9 +66,11 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> case 'G': switch (command.cmd) { case 0x5: - return GetCharacteristics(input, output, inline_output); + return WrapFixedInlOut(this, &nvhost_ctrl_gpu::GetCharacteristics3, input, output, + inline_output); case 0x6: - return GetTPCMasks(input, output, inline_output); + return WrapFixedInlOut(this, &nvhost_ctrl_gpu::GetTPCMasks3, input, output, + inline_output); default: break; } @@ -82,10 +85,8 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> void nvhost_ctrl_gpu::OnOpen(DeviceFD fd) {} void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {} -NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::span<u8> output) { +NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) { LOG_DEBUG(Service_NVDRV, "called"); - IoctlCharacteristics params{}; - std::memcpy(¶ms, input.data(), input.size()); params.gc.arch = 0x120; params.gc.impl = 0xb; params.gc.rev = 0xa1; @@ -123,15 +124,13 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::spa params.gc.gr_compbit_store_base_hw = 0x0; params.gpu_characteristics_buf_size = 0xA0; params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::span<u8> output, - std::span<u8> inline_output) { +NvResult nvhost_ctrl_gpu::GetCharacteristics3( + IoctlCharacteristics& params, std::span<IoctlGpuCharacteristics> gpu_characteristics) { LOG_DEBUG(Service_NVDRV, "called"); - IoctlCharacteristics params{}; - std::memcpy(¶ms, input.data(), input.size()); + params.gc.arch = 0x120; params.gc.impl = 0xb; params.gc.rev = 0xa1; @@ -169,70 +168,47 @@ NvResult nvhost_ctrl_gpu::GetCharacteristics(std::span<const u8> input, std::spa params.gc.gr_compbit_store_base_hw = 0x0; params.gpu_characteristics_buf_size = 0xA0; params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) - - std::memcpy(output.data(), ¶ms, output.size()); - std::memcpy(inline_output.data(), ¶ms.gc, inline_output.size()); + if (!gpu_characteristics.empty()) { + gpu_characteristics.front() = params.gc; + } return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::span<u8> output) { - IoctlGpuGetTpcMasksArgs params{}; - std::memcpy(¶ms, input.data(), input.size()); +NvResult nvhost_ctrl_gpu::GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params) { LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); if (params.mask_buffer_size != 0) { params.tcp_mask = 3; } - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetTPCMasks(std::span<const u8> input, std::span<u8> output, - std::span<u8> inline_output) { - IoctlGpuGetTpcMasksArgs params{}; - std::memcpy(¶ms, input.data(), input.size()); +NvResult nvhost_ctrl_gpu::GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span<u32> tpc_mask) { LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); if (params.mask_buffer_size != 0) { params.tcp_mask = 3; } - std::memcpy(output.data(), ¶ms, output.size()); - std::memcpy(inline_output.data(), ¶ms.tcp_mask, inline_output.size()); + if (!tpc_mask.empty()) { + tpc_mask.front() = params.tcp_mask; + } return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetActiveSlotMask(std::span<const u8> input, std::span<u8> output) { +NvResult nvhost_ctrl_gpu::GetActiveSlotMask(IoctlActiveSlotMask& params) { LOG_DEBUG(Service_NVDRV, "called"); - IoctlActiveSlotMask params{}; - if (input.size() > 0) { - std::memcpy(¶ms, input.data(), input.size()); - } params.slot = 0x07; params.mask = 0x01; - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } -NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(std::span<const u8> input, std::span<u8> output) { +NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(IoctlZcullGetCtxSize& params) { LOG_DEBUG(Service_NVDRV, "called"); - - IoctlZcullGetCtxSize params{}; - if (input.size() > 0) { - std::memcpy(¶ms, input.data(), input.size()); - } params.size = 0x1; - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } -NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::span<u8> output) { +NvResult nvhost_ctrl_gpu::ZCullGetInfo(IoctlNvgpuGpuZcullGetInfoArgs& params) { LOG_DEBUG(Service_NVDRV, "called"); - - IoctlNvgpuGpuZcullGetInfoArgs params{}; - - if (input.size() > 0) { - std::memcpy(¶ms, input.data(), input.size()); - } - params.width_align_pixels = 0x20; params.height_align_pixels = 0x20; params.pixel_squares_by_aliquots = 0x400; @@ -243,53 +219,28 @@ NvResult nvhost_ctrl_gpu::ZCullGetInfo(std::span<const u8> input, std::span<u8> params.subregion_width_align_pixels = 0x20; params.subregion_height_align_pixels = 0x40; params.subregion_count = 0x10; - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } -NvResult nvhost_ctrl_gpu::ZBCSetTable(std::span<const u8> input, std::span<u8> output) { +NvResult nvhost_ctrl_gpu::ZBCSetTable(IoctlZbcSetTable& params) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); - - IoctlZbcSetTable params{}; - std::memcpy(¶ms, input.data(), input.size()); // TODO(ogniK): What does this even actually do? - - // Prevent null pointer being passed as arg 1 - if (output.empty()) { - LOG_WARNING(Service_NVDRV, "Avoiding passing null pointer to memcpy"); - } else { - std::memcpy(output.data(), ¶ms, output.size()); - } return NvResult::Success; } -NvResult nvhost_ctrl_gpu::ZBCQueryTable(std::span<const u8> input, std::span<u8> output) { +NvResult nvhost_ctrl_gpu::ZBCQueryTable(IoctlZbcQueryTable& params) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); - - IoctlZbcQueryTable params{}; - std::memcpy(¶ms, input.data(), input.size()); - // TODO : To implement properly - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } -NvResult nvhost_ctrl_gpu::FlushL2(std::span<const u8> input, std::span<u8> output) { +NvResult nvhost_ctrl_gpu::FlushL2(IoctlFlushL2& params) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); - - IoctlFlushL2 params{}; - std::memcpy(¶ms, input.data(), input.size()); - // TODO : To implement properly - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } -NvResult nvhost_ctrl_gpu::GetGpuTime(std::span<const u8> input, std::span<u8> output) { +NvResult nvhost_ctrl_gpu::GetGpuTime(IoctlGetGpuTime& params) { LOG_DEBUG(Service_NVDRV, "called"); - - IoctlGetGpuTime params{}; - std::memcpy(¶ms, input.data(), input.size()); params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count()); - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index 97995551c..d170299bd 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -151,21 +151,20 @@ private: }; static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); - NvResult GetCharacteristics(std::span<const u8> input, std::span<u8> output); - NvResult GetCharacteristics(std::span<const u8> input, std::span<u8> output, - std::span<u8> inline_output); - - NvResult GetTPCMasks(std::span<const u8> input, std::span<u8> output); - NvResult GetTPCMasks(std::span<const u8> input, std::span<u8> output, - std::span<u8> inline_output); - - NvResult GetActiveSlotMask(std::span<const u8> input, std::span<u8> output); - NvResult ZCullGetCtxSize(std::span<const u8> input, std::span<u8> output); - NvResult ZCullGetInfo(std::span<const u8> input, std::span<u8> output); - NvResult ZBCSetTable(std::span<const u8> input, std::span<u8> output); - NvResult ZBCQueryTable(std::span<const u8> input, std::span<u8> output); - NvResult FlushL2(std::span<const u8> input, std::span<u8> output); - NvResult GetGpuTime(std::span<const u8> input, std::span<u8> output); + NvResult GetCharacteristics1(IoctlCharacteristics& params); + NvResult GetCharacteristics3(IoctlCharacteristics& params, + std::span<IoctlGpuCharacteristics> gpu_characteristics); + + NvResult GetTPCMasks1(IoctlGpuGetTpcMasksArgs& params); + NvResult GetTPCMasks3(IoctlGpuGetTpcMasksArgs& params, std::span<u32> tpc_mask); + + NvResult GetActiveSlotMask(IoctlActiveSlotMask& params); + NvResult ZCullGetCtxSize(IoctlZcullGetCtxSize& params); + NvResult ZCullGetInfo(IoctlNvgpuGpuZcullGetInfoArgs& params); + NvResult ZBCSetTable(IoctlZbcSetTable& params); + NvResult ZBCQueryTable(IoctlZbcQueryTable& params); + NvResult FlushL2(IoctlFlushL2& params); + NvResult GetGpuTime(IoctlGetGpuTime& params); EventInterface& events_interface; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 46a25fcab..b0395c2f0 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -8,6 +8,7 @@ #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/nvmap.h" #include "core/hle/service/nvdrv/core/syncpoint_manager.h" +#include "core/hle/service/nvdrv/devices/ioctl_serialization.h" #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/memory.h" @@ -52,7 +53,7 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu case 0x0: switch (command.cmd) { case 0x3: - return GetWaitbase(input, output); + return WrapFixed(this, &nvhost_gpu::GetWaitbase, input, output); default: break; } @@ -60,25 +61,25 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu case 'H': switch (command.cmd) { case 0x1: - return SetNVMAPfd(input, output); + return WrapFixed(this, &nvhost_gpu::SetNVMAPfd, input, output); case 0x3: - return ChannelSetTimeout(input, output); + return WrapFixed(this, &nvhost_gpu::ChannelSetTimeout, input, output); case 0x8: - return SubmitGPFIFOBase(input, output, false); + return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, false); case 0x9: - return AllocateObjectContext(input, output); + return WrapFixed(this, &nvhost_gpu::AllocateObjectContext, input, output); case 0xb: - return ZCullBind(input, output); + return WrapFixed(this, &nvhost_gpu::ZCullBind, input, output); case 0xc: - return SetErrorNotifier(input, output); + return WrapFixed(this, &nvhost_gpu::SetErrorNotifier, input, output); case 0xd: - return SetChannelPriority(input, output); + return WrapFixed(this, &nvhost_gpu::SetChannelPriority, input, output); case 0x1a: - return AllocGPFIFOEx2(input, output); + return WrapFixed(this, &nvhost_gpu::AllocGPFIFOEx2, input, output); case 0x1b: - return SubmitGPFIFOBase(input, output, true); + return WrapFixedVariable(this, &nvhost_gpu::SubmitGPFIFOBase1, input, output, true); case 0x1d: - return ChannelSetTimeslice(input, output); + return WrapFixed(this, &nvhost_gpu::ChannelSetTimeslice, input, output); default: break; } @@ -86,9 +87,9 @@ NvResult nvhost_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu case 'G': switch (command.cmd) { case 0x14: - return SetClientData(input, output); + return WrapFixed(this, &nvhost_gpu::SetClientData, input, output); case 0x15: - return GetClientData(input, output); + return WrapFixed(this, &nvhost_gpu::GetClientData, input, output); default: break; } @@ -104,7 +105,8 @@ NvResult nvhost_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> inpu case 'H': switch (command.cmd) { case 0x1b: - return SubmitGPFIFOBase(input, inline_input, output); + return WrapFixedInlIn(this, &nvhost_gpu::SubmitGPFIFOBase2, input, inline_input, + output); } break; } @@ -121,63 +123,45 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu void nvhost_gpu::OnOpen(DeviceFD fd) {} void nvhost_gpu::OnClose(DeviceFD fd) {} -NvResult nvhost_gpu::SetNVMAPfd(std::span<const u8> input, std::span<u8> output) { - IoctlSetNvmapFD params{}; - std::memcpy(¶ms, input.data(), input.size()); +NvResult nvhost_gpu::SetNVMAPfd(IoctlSetNvmapFD& params) { LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); nvmap_fd = params.nvmap_fd; return NvResult::Success; } -NvResult nvhost_gpu::SetClientData(std::span<const u8> input, std::span<u8> output) { +NvResult nvhost_gpu::SetClientData(IoctlClientData& params) { LOG_DEBUG(Service_NVDRV, "called"); - - IoctlClientData params{}; - std::memcpy(¶ms, input.data(), input.size()); user_data = params.data; return NvResult::Success; } -NvResult nvhost_gpu::GetClientData(std::span<const u8> input, std::span<u8> output) { +NvResult nvhost_gpu::GetClientData(IoctlClientData& params) { LOG_DEBUG(Service_NVDRV, "called"); - - IoctlClientData params{}; - std::memcpy(¶ms, input.data(), input.size()); params.data = user_data; - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } -NvResult nvhost_gpu::ZCullBind(std::span<const u8> input, std::span<u8> output) { - std::memcpy(&zcull_params, input.data(), input.size()); +NvResult nvhost_gpu::ZCullBind(IoctlZCullBind& params) { + zcull_params = params; LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, zcull_params.mode); - - std::memcpy(output.data(), &zcull_params, output.size()); return NvResult::Success; } -NvResult nvhost_gpu::SetErrorNotifier(std::span<const u8> input, std::span<u8> output) { - IoctlSetErrorNotifier params{}; - std::memcpy(¶ms, input.data(), input.size()); +NvResult nvhost_gpu::SetErrorNotifier(IoctlSetErrorNotifier& params) { LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, params.size, params.mem); - - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } -NvResult nvhost_gpu::SetChannelPriority(std::span<const u8> input, std::span<u8> output) { - std::memcpy(&channel_priority, input.data(), input.size()); +NvResult nvhost_gpu::SetChannelPriority(IoctlChannelSetPriority& params) { + channel_priority = params.priority; LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); - return NvResult::Success; } -NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> output) { - IoctlAllocGpfifoEx2 params{}; - std::memcpy(¶ms, input.data(), input.size()); +NvResult nvhost_gpu::AllocGPFIFOEx2(IoctlAllocGpfifoEx2& params) { LOG_WARNING(Service_NVDRV, "(STUBBED) called, num_entries={:X}, flags={:X}, unk0={:X}, " "unk1={:X}, unk2={:X}, unk3={:X}", @@ -193,18 +177,14 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> out params.fence_out = syncpoint_manager.GetSyncpointFence(channel_syncpoint); - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } -NvResult nvhost_gpu::AllocateObjectContext(std::span<const u8> input, std::span<u8> output) { - IoctlAllocObjCtx params{}; - std::memcpy(¶ms, input.data(), input.size()); +NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) { LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, params.flags); params.obj_id = 0x0; - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } @@ -248,8 +228,7 @@ static boost::container::small_vector<Tegra::CommandHeader, 512> BuildIncrementW return result; } -NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> output, - Tegra::CommandList&& entries) { +NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries) { LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, params.num_entries, params.flags.raw); @@ -290,65 +269,55 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> o flags.raw = 0; - std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); return NvResult::Success; } -NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<u8> output, - bool kickoff) { - if (input.size() < sizeof(IoctlSubmitGpfifo)) { +NvResult nvhost_gpu::SubmitGPFIFOBase1(IoctlSubmitGpfifo& params, + std::span<Tegra::CommandListHeader> commands, bool kickoff) { + if (params.num_entries > commands.size()) { UNIMPLEMENTED(); return NvResult::InvalidSize; } - IoctlSubmitGpfifo params{}; - std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); - Tegra::CommandList entries(params.num_entries); + Tegra::CommandList entries(params.num_entries); if (kickoff) { system.ApplicationMemory().ReadBlock(params.address, entries.command_lists.data(), params.num_entries * sizeof(Tegra::CommandListHeader)); } else { - std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], + std::memcpy(entries.command_lists.data(), commands.data(), params.num_entries * sizeof(Tegra::CommandListHeader)); } - return SubmitGPFIFOImpl(params, output, std::move(entries)); + return SubmitGPFIFOImpl(params, std::move(entries)); } -NvResult nvhost_gpu::SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline, - std::span<u8> output) { - if (input.size() < sizeof(IoctlSubmitGpfifo)) { +NvResult nvhost_gpu::SubmitGPFIFOBase2(IoctlSubmitGpfifo& params, + std::span<const Tegra::CommandListHeader> commands) { + if (params.num_entries > commands.size()) { UNIMPLEMENTED(); return NvResult::InvalidSize; } - IoctlSubmitGpfifo params{}; - std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); + Tegra::CommandList entries(params.num_entries); - std::memcpy(entries.command_lists.data(), input_inline.data(), input_inline.size()); - return SubmitGPFIFOImpl(params, output, std::move(entries)); + std::memcpy(entries.command_lists.data(), commands.data(), + params.num_entries * sizeof(Tegra::CommandListHeader)); + return SubmitGPFIFOImpl(params, std::move(entries)); } -NvResult nvhost_gpu::GetWaitbase(std::span<const u8> input, std::span<u8> output) { - IoctlGetWaitbase params{}; - std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); +NvResult nvhost_gpu::GetWaitbase(IoctlGetWaitbase& params) { LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); params.value = 0; // Seems to be hard coded at 0 - std::memcpy(output.data(), ¶ms, output.size()); return NvResult::Success; } -NvResult nvhost_gpu::ChannelSetTimeout(std::span<const u8> input, std::span<u8> output) { - IoctlChannelSetTimeout params{}; - std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); +NvResult nvhost_gpu::ChannelSetTimeout(IoctlChannelSetTimeout& params) { LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); return NvResult::Success; } -NvResult nvhost_gpu::ChannelSetTimeslice(std::span<const u8> input, std::span<u8> output) { - IoctlSetTimeslice params{}; - std::memcpy(¶ms, input.data(), sizeof(IoctlSetTimeslice)); +NvResult nvhost_gpu::ChannelSetTimeslice(IoctlSetTimeslice& params) { LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); channel_timeslice = params.timeslice; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 529c20526..88fd228ff 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h @@ -186,23 +186,24 @@ private: u32_le channel_priority{}; u32_le channel_timeslice{}; - NvResult SetNVMAPfd(std::span<const u8> input, std::span<u8> output); - NvResult SetClientData(std::span<const u8> input, std::span<u8> output); - NvResult GetClientData(std::span<const u8> input, std::span<u8> output); - NvResult ZCullBind(std::span<const u8> input, std::span<u8> output); - NvResult SetErrorNotifier(std::span<const u8> input, std::span<u8> output); - NvResult SetChannelPriority(std::span<const u8> input, std::span<u8> output); - NvResult AllocGPFIFOEx2(std::span<const u8> input, std::span<u8> output); - NvResult AllocateObjectContext(std::span<const u8> input, std::span<u8> output); - NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::span<u8> output, - Tegra::CommandList&& entries); - NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<u8> output, - bool kickoff = false); - NvResult SubmitGPFIFOBase(std::span<const u8> input, std::span<const u8> input_inline, - std::span<u8> output); - NvResult GetWaitbase(std::span<const u8> input, std::span<u8> output); - NvResult ChannelSetTimeout(std::span<const u8> input, std::span<u8> output); - NvResult ChannelSetTimeslice(std::span<const u8> input, std::span<u8> output); + NvResult SetNVMAPfd(IoctlSetNvmapFD& params); + NvResult SetClientData(IoctlClientData& params); + NvResult GetClientData(IoctlClientData& params); + NvResult ZCullBind(IoctlZCullBind& params); + NvResult SetErrorNotifier(IoctlSetErrorNotifier& params); + NvResult SetChannelPriority(IoctlChannelSetPriority& params); + NvResult AllocGPFIFOEx2(IoctlAllocGpfifoEx2& params); + NvResult AllocateObjectContext(IoctlAllocObjCtx& params); + + NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandList&& entries); + NvResult SubmitGPFIFOBase1(IoctlSubmitGpfifo& params, + std::span<Tegra::CommandListHeader> commands, bool kickoff = false); + NvResult SubmitGPFIFOBase2(IoctlSubmitGpfifo& params, + std::span<const Tegra::CommandListHeader> commands); + + NvResult GetWaitbase(IoctlGetWaitbase& params); + NvResult ChannelSetTimeout(IoctlChannelSetTimeout& params); + NvResult ChannelSetTimeslice(IoctlSetTimeslice& params); EventInterface& events_interface; NvCore::Container& core; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index a174442a6..f43914e1b 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -6,6 +6,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/devices/ioctl_serialization.h" #include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" #include "video_core/renderer_base.h" @@ -25,18 +26,18 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in if (!host1x_file.fd_to_id.contains(fd)) { host1x_file.fd_to_id[fd] = host1x_file.nvdec_next_id++; } - return Submit(fd, input, output); + return WrapFixedVariable(this, &nvhost_nvdec::Submit, input, output, fd); } case 0x2: - return GetSyncpoint(input, output); + return WrapFixed(this, &nvhost_nvdec::GetSyncpoint, input, output); case 0x3: - return GetWaitbase(input, output); + return WrapFixed(this, &nvhost_nvdec::GetWaitbase, input, output); case 0x7: - return SetSubmitTimeout(input, output); + return WrapFixed(this, &nvhost_nvdec::SetSubmitTimeout, input, output); case 0x9: - return MapBuffer(input, output); + return WrapFixedVariable(this, &nvhost_nvdec::MapBuffer, input, output); case 0xa: - return UnmapBuffer(input, output); + return WrapFixedVariable(this, &nvhost_nvdec::UnmapBuffer, input, output); default: break; } @@ -44,7 +45,7 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in case 'H': switch (command.cmd) { case 0x1: - return SetNVMAPfd(input); + return WrapFixed(this, &nvhost_nvdec::SetNVMAPfd, input, output); default: break; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 61649aa4a..74c701b95 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -29,6 +29,9 @@ std::size_t SliceVectors(std::span<const u8> input, std::vector<T>& dst, std::si return 0; } const size_t bytes_copied = count * sizeof(T); + if (input.size() < offset + bytes_copied) { + return 0; + } std::memcpy(dst.data(), input.data() + offset, bytes_copied); return bytes_copied; } @@ -41,6 +44,9 @@ std::size_t WriteVectors(std::span<u8> dst, const std::vector<T>& src, std::size return 0; } const size_t bytes_copied = src.size() * sizeof(T); + if (dst.size() < offset + bytes_copied) { + return 0; + } std::memcpy(dst.data() + offset, src.data(), bytes_copied); return bytes_copied; } @@ -63,18 +69,14 @@ nvhost_nvdec_common::~nvhost_nvdec_common() { core.Host1xDeviceFile().syncpts_accumulated.push_back(channel_syncpoint); } -NvResult nvhost_nvdec_common::SetNVMAPfd(std::span<const u8> input) { - IoctlSetNvmapFD params{}; - std::memcpy(¶ms, input.data(), sizeof(IoctlSetNvmapFD)); +NvResult nvhost_nvdec_common::SetNVMAPfd(IoctlSetNvmapFD& params) { LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); nvmap_fd = params.nvmap_fd; return NvResult::Success; } -NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std::span<u8> output) { - IoctlSubmit params{}; - std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit)); +NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, DeviceFD fd) { LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); // Instantiate param buffers @@ -85,12 +87,12 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std std::vector<u32> fence_thresholds(params.fence_count); // Slice input into their respective buffers - std::size_t offset = sizeof(IoctlSubmit); - offset += SliceVectors(input, command_buffers, params.cmd_buffer_count, offset); - offset += SliceVectors(input, relocs, params.relocation_count, offset); - offset += SliceVectors(input, reloc_shifts, params.relocation_count, offset); - offset += SliceVectors(input, syncpt_increments, params.syncpoint_count, offset); - offset += SliceVectors(input, fence_thresholds, params.fence_count, offset); + std::size_t offset = 0; + offset += SliceVectors(data, command_buffers, params.cmd_buffer_count, offset); + offset += SliceVectors(data, relocs, params.relocation_count, offset); + offset += SliceVectors(data, reloc_shifts, params.relocation_count, offset); + offset += SliceVectors(data, syncpt_increments, params.syncpoint_count, offset); + offset += SliceVectors(data, fence_thresholds, params.fence_count, offset); auto& gpu = system.GPU(); if (gpu.UseNvdec()) { @@ -108,72 +110,51 @@ NvResult nvhost_nvdec_common::Submit(DeviceFD fd, std::span<const u8> input, std cmdlist.size() * sizeof(u32)); gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist); } - std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmit)); // Some games expect command_buffers to be written back - offset = sizeof(IoctlSubmit); - offset += WriteVectors(output, command_buffers, offset); - offset += WriteVectors(output, relocs, offset); - offset += WriteVectors(output, reloc_shifts, offset); - offset += WriteVectors(output, syncpt_increments, offset); - offset += WriteVectors(output, fence_thresholds, offset); + offset = 0; + offset += WriteVectors(data, command_buffers, offset); + offset += WriteVectors(data, relocs, offset); + offset += WriteVectors(data, reloc_shifts, offset); + offset += WriteVectors(data, syncpt_increments, offset); + offset += WriteVectors(data, fence_thresholds, offset); return NvResult::Success; } -NvResult nvhost_nvdec_common::GetSyncpoint(std::span<const u8> input, std::span<u8> output) { - IoctlGetSyncpoint params{}; - std::memcpy(¶ms, input.data(), sizeof(IoctlGetSyncpoint)); +NvResult nvhost_nvdec_common::GetSyncpoint(IoctlGetSyncpoint& params) { LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); - - // const u32 id{NvCore::SyncpointManager::channel_syncpoints[static_cast<u32>(channel_type)]}; params.value = channel_syncpoint; - std::memcpy(output.data(), ¶ms, sizeof(IoctlGetSyncpoint)); - return NvResult::Success; } -NvResult nvhost_nvdec_common::GetWaitbase(std::span<const u8> input, std::span<u8> output) { - IoctlGetWaitbase params{}; +NvResult nvhost_nvdec_common::GetWaitbase(IoctlGetWaitbase& params) { LOG_CRITICAL(Service_NVDRV, "called WAITBASE"); - std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); params.value = 0; // Seems to be hard coded at 0 - std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase)); return NvResult::Success; } -NvResult nvhost_nvdec_common::MapBuffer(std::span<const u8> input, std::span<u8> output) { - IoctlMapBuffer params{}; - std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); - std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); - - SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer)); - - for (auto& cmd_buffer : cmd_buffer_handles) { - cmd_buffer.map_address = nvmap.PinHandle(cmd_buffer.map_handle); +NvResult nvhost_nvdec_common::MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries) { + const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size())); + for (size_t i = 0; i < num_entries; i++) { + entries[i].map_address = nvmap.PinHandle(entries[i].map_handle); } - std::memcpy(output.data(), ¶ms, sizeof(IoctlMapBuffer)); - std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(), - cmd_buffer_handles.size() * sizeof(MapBufferEntry)); return NvResult::Success; } -NvResult nvhost_nvdec_common::UnmapBuffer(std::span<const u8> input, std::span<u8> output) { - IoctlMapBuffer params{}; - std::memcpy(¶ms, input.data(), sizeof(IoctlMapBuffer)); - std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); - - SliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer)); - for (auto& cmd_buffer : cmd_buffer_handles) { - nvmap.UnpinHandle(cmd_buffer.map_handle); +NvResult nvhost_nvdec_common::UnmapBuffer(IoctlMapBuffer& params, + std::span<MapBufferEntry> entries) { + const size_t num_entries = std::min(params.num_entries, static_cast<u32>(entries.size())); + for (size_t i = 0; i < num_entries; i++) { + nvmap.UnpinHandle(entries[i].map_handle); + entries[i] = {}; } - std::memset(output.data(), 0, output.size()); + params = {}; return NvResult::Success; } -NvResult nvhost_nvdec_common::SetSubmitTimeout(std::span<const u8> input, std::span<u8> output) { - std::memcpy(&submit_timeout, input.data(), input.size()); +NvResult nvhost_nvdec_common::SetSubmitTimeout(u32 timeout) { LOG_WARNING(Service_NVDRV, "(STUBBED) called"); return NvResult::Success; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index 9bb573bfe..7ce748e18 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -107,13 +107,13 @@ protected: static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); /// Ioctl command implementations - NvResult SetNVMAPfd(std::span<const u8> input); - NvResult Submit(DeviceFD fd, std::span<const u8> input, std::span<u8> output); - NvResult GetSyncpoint(std::span<const u8> input, std::span<u8> output); - NvResult GetWaitbase(std::span<const u8> input, std::span<u8> output); - NvResult MapBuffer(std::span<const u8> input, std::span<u8> output); - NvResult UnmapBuffer(std::span<const u8> input, std::span<u8> output); - NvResult SetSubmitTimeout(std::span<const u8> input, std::span<u8> output); + NvResult SetNVMAPfd(IoctlSetNvmapFD&); + NvResult Submit(IoctlSubmit& params, std::span<u8> input, DeviceFD fd); + NvResult GetSyncpoint(IoctlGetSyncpoint& params); + NvResult GetWaitbase(IoctlGetWaitbase& params); + NvResult MapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries); + NvResult UnmapBuffer(IoctlMapBuffer& params, std::span<MapBufferEntry> entries); + NvResult SetSubmitTimeout(u32 timeout); Kernel::KEvent* QueryEvent(u32 event_id) override; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index a05c8cdae..9e6b86458 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp @@ -5,6 +5,7 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "core/hle/service/nvdrv/devices/ioctl_serialization.h" #include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h" namespace Service::Nvidia::Devices { @@ -18,7 +19,7 @@ NvResult nvhost_nvjpg::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in case 'H': switch (command.cmd) { case 0x1: - return SetNVMAPfd(input, output); + return WrapFixed(this, &nvhost_nvjpg::SetNVMAPfd, input, output); default: break; } @@ -46,9 +47,7 @@ NvResult nvhost_nvjpg::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> in void nvhost_nvjpg::OnOpen(DeviceFD fd) {} void nvhost_nvjpg::OnClose(DeviceFD fd) {} -NvResult nvhost_nvjpg::SetNVMAPfd(std::span<const u8> input, std::span<u8> output) { - IoctlSetNvmapFD params{}; - std::memcpy(¶ms, input.data(), input.size()); +NvResult nvhost_nvjpg::SetNVMAPfd(IoctlSetNvmapFD& params) { LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); nvmap_fd = params.nvmap_fd; diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h index 5623e0d47..790c97f6a 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h @@ -33,7 +33,7 @@ private: s32_le nvmap_fd{}; - NvResult SetNVMAPfd(std::span<const u8> input, std::span<u8> output); + NvResult SetNVMAPfd(IoctlSetNvmapFD& params); }; } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index c0b8684c3..87f8d7c22 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp @@ -5,6 +5,7 @@ #include "common/logging/log.h" #include "core/core.h" #include "core/hle/service/nvdrv/core/container.h" +#include "core/hle/service/nvdrv/devices/ioctl_serialization.h" #include "core/hle/service/nvdrv/devices/nvhost_vic.h" #include "video_core/renderer_base.h" @@ -25,16 +26,16 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu if (!host1x_file.fd_to_id.contains(fd)) { host1x_file.fd_to_id[fd] = host1x_file.vic_next_id++; } - return Submit(fd, input, output); + return WrapFixedVariable(this, &nvhost_vic::Submit, input, output, fd); } case 0x2: - return GetSyncpoint(input, output); + return WrapFixed(this, &nvhost_vic::GetSyncpoint, input, output); case 0x3: - return GetWaitbase(input, output); + return WrapFixed(this, &nvhost_vic::GetWaitbase, input, output); case 0x9: - return MapBuffer(input, output); + return WrapFixedVariable(this, &nvhost_vic::MapBuffer, input, output); case 0xa: - return UnmapBuffer(input, output); + return WrapFixedVariable(this, &nvhost_vic::UnmapBuffer, input, output); default: break; } @@ -42,7 +43,7 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu case 'H': switch (command.cmd) { case 0x1: - return SetNVMAPfd(input); + return WrapFixed(this, &nvhost_vic::SetNVMAPfd, input, output); default: break; } diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 968eaa175..71b2e62ec 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -13,6 +13,7 @@ #include "core/hle/kernel/k_process.h" #include "core/hle/service/nvdrv/core/container.h" #include "core/hle/service/nvdrv/core/nvmap.h" +#include "core/hle/service/nvdrv/devices/ioctl_serialization.h" #include "core/hle/service/nvdrv/devices/nvmap.h" #include "core/memory.h" @@ -31,17 +32,17 @@ NvResult nvmap::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, case 0x1: switch (command.cmd) { case 0x1: - return IocCreate(input, output); + return WrapFixed(this, &nvmap::IocCreate, input, output); case 0x3: - return IocFromId(input, output); + return WrapFixed(this, &nvmap::IocFromId, input, output); case 0x4: - return IocAlloc(input, output); + return WrapFixed(this, &nvmap::IocAlloc, input, output); case 0x5: - return IocFree(input, output); + return WrapFixed(this, &nvmap::IocFree, input, output); case 0x9: - return IocParam(input, output); + return WrapFixed(this, &nvmap::IocParam, input, output); case 0xe: - return IocGetId(input, output); + return WrapFixed(this, &nvmap::IocGetId, input, output); default: break; } @@ -69,9 +70,7 @@ NvResult nvmap::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, st void nvmap::OnOpen(DeviceFD fd) {} void nvmap::OnClose(DeviceFD fd) {} -NvResult nvmap::IocCreate(std::span<const u8> input, std::span<u8> output) { - IocCreateParams params; - std::memcpy(¶ms, input.data(), sizeof(params)); +NvResult nvmap::IocCreate(IocCreateParams& params) { LOG_DEBUG(Service_NVDRV, "called, size=0x{:08X}", params.size); std::shared_ptr<NvCore::NvMap::Handle> handle_description{}; @@ -85,13 +84,10 @@ NvResult nvmap::IocCreate(std::span<const u8> input, std::span<u8> output) { params.handle = handle_description->id; LOG_DEBUG(Service_NVDRV, "handle: {}, size: 0x{:X}", handle_description->id, params.size); - std::memcpy(output.data(), ¶ms, sizeof(params)); return NvResult::Success; } -NvResult nvmap::IocAlloc(std::span<const u8> input, std::span<u8> output) { - IocAllocParams params; - std::memcpy(¶ms, input.data(), sizeof(params)); +NvResult nvmap::IocAlloc(IocAllocParams& params) { LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.address); if (!params.handle) { @@ -133,14 +129,10 @@ NvResult nvmap::IocAlloc(std::span<const u8> input, std::span<u8> output) { handle_description->size, Kernel::KMemoryPermission::None, true, false) .IsSuccess()); - std::memcpy(output.data(), ¶ms, sizeof(params)); return result; } -NvResult nvmap::IocGetId(std::span<const u8> input, std::span<u8> output) { - IocGetIdParams params; - std::memcpy(¶ms, input.data(), sizeof(params)); - +NvResult nvmap::IocGetId(IocGetIdParams& params) { LOG_DEBUG(Service_NVDRV, "called"); // See the comment in FromId for extra info on this function @@ -157,14 +149,10 @@ NvResult nvmap::IocGetId(std::span<const u8> input, std::span<u8> output) { } params.id = handle_description->id; - std::memcpy(output.data(), ¶ms, sizeof(params)); return NvResult::Success; } -NvResult nvmap::IocFromId(std::span<const u8> input, std::span<u8> output) { - IocFromIdParams params; - std::memcpy(¶ms, input.data(), sizeof(params)); - +NvResult nvmap::IocFromId(IocFromIdParams& params) { LOG_DEBUG(Service_NVDRV, "called, id:{}", params.id); // Handles and IDs are always the same value in nvmap however IDs can be used globally given the @@ -188,16 +176,12 @@ NvResult nvmap::IocFromId(std::span<const u8> input, std::span<u8> output) { return result; } params.handle = handle_description->id; - std::memcpy(output.data(), ¶ms, sizeof(params)); return NvResult::Success; } -NvResult nvmap::IocParam(std::span<const u8> input, std::span<u8> output) { +NvResult nvmap::IocParam(IocParamParams& params) { enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; - IocParamParams params; - std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_DEBUG(Service_NVDRV, "called type={}", params.param); if (!params.handle) { @@ -237,14 +221,10 @@ NvResult nvmap::IocParam(std::span<const u8> input, std::span<u8> output) { return NvResult::BadValue; } - std::memcpy(output.data(), ¶ms, sizeof(params)); return NvResult::Success; } -NvResult nvmap::IocFree(std::span<const u8> input, std::span<u8> output) { - IocFreeParams params; - std::memcpy(¶ms, input.data(), sizeof(params)); - +NvResult nvmap::IocFree(IocFreeParams& params) { LOG_DEBUG(Service_NVDRV, "called"); if (!params.handle) { @@ -267,7 +247,6 @@ NvResult nvmap::IocFree(std::span<const u8> input, std::span<u8> output) { // This is possible when there's internal dups or other duplicates. } - std::memcpy(output.data(), ¶ms, sizeof(params)); return NvResult::Success; } diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h index 4c0cc71cd..049c11028 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.h +++ b/src/core/hle/service/nvdrv/devices/nvmap.h @@ -99,12 +99,12 @@ public: }; static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); - NvResult IocCreate(std::span<const u8> input, std::span<u8> output); - NvResult IocAlloc(std::span<const u8> input, std::span<u8> output); - NvResult IocGetId(std::span<const u8> input, std::span<u8> output); - NvResult IocFromId(std::span<const u8> input, std::span<u8> output); - NvResult IocParam(std::span<const u8> input, std::span<u8> output); - NvResult IocFree(std::span<const u8> input, std::span<u8> output); + NvResult IocCreate(IocCreateParams& params); + NvResult IocAlloc(IocAllocParams& params); + NvResult IocGetId(IocGetIdParams& params); + NvResult IocFromId(IocFromIdParams& params); + NvResult IocParam(IocParamParams& params); + NvResult IocFree(IocFreeParams& params); private: /// Id to use for the next handle that is created. diff --git a/src/core/hle/service/nvnflinger/buffer_queue_core.cpp b/src/core/hle/service/nvnflinger/buffer_queue_core.cpp index 2dbe29616..ed66f6f5b 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvnflinger/buffer_queue_core.cpp @@ -41,7 +41,7 @@ bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) s32 BufferQueueCore::GetMinUndequeuedBufferCountLocked(bool async) const { // If DequeueBuffer is allowed to error out, we don't have to add an extra buffer. if (!use_async_buffer) { - return max_acquired_buffer_count; + return 0; } if (dequeue_buffer_cannot_block || async) { @@ -52,7 +52,7 @@ s32 BufferQueueCore::GetMinUndequeuedBufferCountLocked(bool async) const { } s32 BufferQueueCore::GetMinMaxBufferCountLocked(bool async) const { - return GetMinUndequeuedBufferCountLocked(async) + 1; + return GetMinUndequeuedBufferCountLocked(async); } s32 BufferQueueCore::GetMaxBufferCountLocked(bool async) const { @@ -61,7 +61,7 @@ s32 BufferQueueCore::GetMaxBufferCountLocked(bool async) const { if (override_max_buffer_count != 0) { ASSERT(override_max_buffer_count >= min_buffer_count); - max_buffer_count = override_max_buffer_count; + return override_max_buffer_count; } // Any buffers that are dequeued by the producer or sitting in the queue waiting to be consumed diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp index dc6917d5d..6e7a49658 100644 --- a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp @@ -134,7 +134,7 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, St const s32 max_buffer_count = core->GetMaxBufferCountLocked(async); if (async && core->override_max_buffer_count) { if (core->override_max_buffer_count < max_buffer_count) { - LOG_ERROR(Service_Nvnflinger, "async mode is invalid with buffer count override"); + *found = BufferQueueCore::INVALID_BUFFER_SLOT; return Status::BadValue; } } @@ -142,7 +142,8 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, St // Free up any buffers that are in slots beyond the max buffer count for (s32 s = max_buffer_count; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) { ASSERT(slots[s].buffer_state == BufferState::Free); - if (slots[s].graphic_buffer != nullptr) { + if (slots[s].graphic_buffer != nullptr && slots[s].buffer_state == BufferState::Free && + !slots[s].is_preallocated) { core->FreeBufferLocked(s); *return_flags |= Status::ReleaseAllBuffers; } diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp index 2e29bc848..6dc327b8b 100644 --- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp +++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp @@ -71,24 +71,17 @@ Result AllocateIoForProcessAddressSpace(Common::ProcessAddress* out_map_address, R_SUCCEED(); } -template <typename T> -std::span<u8> SerializeIoc(T& params) { - return std::span(reinterpret_cast<u8*>(std::addressof(params)), sizeof(T)); -} - Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, u32 size) { // Create a handle. - Nvidia::Devices::nvmap::IocCreateParams create_in_params{ + Nvidia::Devices::nvmap::IocCreateParams create_params{ .size = size, .handle = 0, }; - Nvidia::Devices::nvmap::IocCreateParams create_out_params{}; - R_UNLESS(nvmap.IocCreate(SerializeIoc(create_in_params), SerializeIoc(create_out_params)) == - Nvidia::NvResult::Success, + R_UNLESS(nvmap.IocCreate(create_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed); // Assign the output handle. - *out_nv_map_handle = create_out_params.handle; + *out_nv_map_handle = create_params.handle; // We succeeded. R_SUCCEED(); @@ -96,13 +89,10 @@ Result CreateNvMapHandle(u32* out_nv_map_handle, Nvidia::Devices::nvmap& nvmap, Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) { // Free the handle. - Nvidia::Devices::nvmap::IocFreeParams free_in_params{ + Nvidia::Devices::nvmap::IocFreeParams free_params{ .handle = handle, }; - Nvidia::Devices::nvmap::IocFreeParams free_out_params{}; - R_UNLESS(nvmap.IocFree(SerializeIoc(free_in_params), SerializeIoc(free_out_params)) == - Nvidia::NvResult::Success, - VI::ResultOperationFailed); + R_UNLESS(nvmap.IocFree(free_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed); // We succeeded. R_SUCCEED(); @@ -111,7 +101,7 @@ Result FreeNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle) { Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::ProcessAddress buffer, u32 size) { // Assign the allocated memory to the handle. - Nvidia::Devices::nvmap::IocAllocParams alloc_in_params{ + Nvidia::Devices::nvmap::IocAllocParams alloc_params{ .handle = handle, .heap_mask = 0, .flags = {}, @@ -119,10 +109,7 @@ Result AllocNvMapHandle(Nvidia::Devices::nvmap& nvmap, u32 handle, Common::Proce .kind = 0, .address = GetInteger(buffer), }; - Nvidia::Devices::nvmap::IocAllocParams alloc_out_params{}; - R_UNLESS(nvmap.IocAlloc(SerializeIoc(alloc_in_params), SerializeIoc(alloc_out_params)) == - Nvidia::NvResult::Success, - VI::ResultOperationFailed); + R_UNLESS(nvmap.IocAlloc(alloc_params) == Nvidia::NvResult::Success, VI::ResultOperationFailed); // We succeeded. R_SUCCEED(); diff --git a/src/core/hle/service/nvnflinger/nvnflinger.cpp b/src/core/hle/service/nvnflinger/nvnflinger.cpp index a07c621d9..bebb45eae 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.cpp +++ b/src/core/hle/service/nvnflinger/nvnflinger.cpp @@ -66,7 +66,6 @@ Nvnflinger::Nvnflinger(Core::System& system_, HosBinderDriverServer& hos_binder_ "ScreenComposition", [this](std::uintptr_t, s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { - { const auto lock_guard = Lock(); } vsync_signal.Set(); return std::chrono::nanoseconds(GetNextTicks()); }); @@ -99,6 +98,7 @@ Nvnflinger::~Nvnflinger() { } ShutdownLayers(); + vsync_thread = {}; if (nvdrv) { nvdrv->Close(disp_fd); @@ -106,6 +106,7 @@ Nvnflinger::~Nvnflinger() { } void Nvnflinger::ShutdownLayers() { + const auto lock_guard = Lock(); for (auto& display : displays) { for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) { display.GetLayer(layer).Core().NotifyShutdown(); @@ -229,16 +230,6 @@ VI::Layer* Nvnflinger::FindLayer(u64 display_id, u64 layer_id) { return display->FindLayer(layer_id); } -const VI::Layer* Nvnflinger::FindLayer(u64 display_id, u64 layer_id) const { - const auto* const display = FindDisplay(display_id); - - if (display == nullptr) { - return nullptr; - } - - return display->FindLayer(layer_id); -} - VI::Layer* Nvnflinger::FindOrCreateLayer(u64 display_id, u64 layer_id) { auto* const display = FindDisplay(display_id); @@ -288,7 +279,6 @@ void Nvnflinger::Compose() { auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>(disp_fd); ASSERT(nvdisp); - guard->unlock(); Common::Rectangle<int> crop_rect{ static_cast<int>(buffer.crop.Left()), static_cast<int>(buffer.crop.Top()), static_cast<int>(buffer.crop.Right()), static_cast<int>(buffer.crop.Bottom())}; @@ -299,7 +289,6 @@ void Nvnflinger::Compose() { buffer.fence.fences, buffer.fence.num_fences); MicroProfileFlip(); - guard->lock(); swap_interval = buffer.swap_interval; diff --git a/src/core/hle/service/nvnflinger/nvnflinger.h b/src/core/hle/service/nvnflinger/nvnflinger.h index 14c783582..959d8b46b 100644 --- a/src/core/hle/service/nvnflinger/nvnflinger.h +++ b/src/core/hle/service/nvnflinger/nvnflinger.h @@ -117,9 +117,6 @@ private: /// Finds the layer identified by the specified ID in the desired display. [[nodiscard]] VI::Layer* FindLayer(u64 display_id, u64 layer_id); - /// Finds the layer identified by the specified ID in the desired display. - [[nodiscard]] const VI::Layer* FindLayer(u64 display_id, u64 layer_id) const; - /// Finds the layer identified by the specified ID in the desired display, /// or creates the layer if it is not found. /// To be used when the system expects the specified ID to already exist. diff --git a/src/core/hle/service/pctl/pctl_module.cpp b/src/core/hle/service/pctl/pctl_module.cpp index 938330dd0..6a7fd72bc 100644 --- a/src/core/hle/service/pctl/pctl_module.cpp +++ b/src/core/hle/service/pctl/pctl_module.cpp @@ -141,6 +141,12 @@ public: service_context.CreateEvent("IParentalControlService::RequestSuspensionEvent"); } + ~IParentalControlService() { + service_context.CloseEvent(synchronization_event); + service_context.CloseEvent(unlinked_event); + service_context.CloseEvent(request_suspension_event); + }; + private: bool CheckFreeCommunicationPermissionImpl() const { if (states.temporary_unlocked) { diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index f9cf2dda3..d92499f05 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp @@ -37,7 +37,7 @@ std::optional<Kernel::KProcess*> SearchProcessList( void GetApplicationPidGeneric(HLERequestContext& ctx, const std::vector<Kernel::KProcess*>& process_list) { const auto process = SearchProcessList(process_list, [](const auto& proc) { - return proc->GetProcessId() == Kernel::KProcess::ProcessIDMin; + return proc->GetProcessId() == Kernel::KProcess::ProcessIdMin; }); IPC::ResponseBuilder rb{ctx, 4}; diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index 85849d5f3..dd652ca42 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -39,6 +39,18 @@ bool IsConnectionBased(Type type) { } } +template <typename T> +T GetValue(std::span<const u8> buffer) { + T t{}; + std::memcpy(&t, buffer.data(), std::min(sizeof(T), buffer.size())); + return t; +} + +template <typename T> +void PutValue(std::span<u8> buffer, const T& t) { + std::memcpy(buffer.data(), &t, std::min(sizeof(T), buffer.size())); +} + } // Anonymous namespace void BSD::PollWork::Execute(BSD* bsd) { @@ -316,22 +328,12 @@ void BSD::SetSockOpt(HLERequestContext& ctx) { const s32 fd = rp.Pop<s32>(); const u32 level = rp.Pop<u32>(); const OptName optname = static_cast<OptName>(rp.Pop<u32>()); - - const auto buffer = ctx.ReadBuffer(); - const u8* optval = buffer.empty() ? nullptr : buffer.data(); - size_t optlen = buffer.size(); - - std::array<u64, 2> values; - if ((optname == OptName::SNDTIMEO || optname == OptName::RCVTIMEO) && buffer.size() == 8) { - std::memcpy(values.data(), buffer.data(), sizeof(values)); - optlen = sizeof(values); - optval = reinterpret_cast<const u8*>(values.data()); - } + const auto optval = ctx.ReadBuffer(); LOG_DEBUG(Service, "called. fd={} level={} optname=0x{:x} optlen={}", fd, level, - static_cast<u32>(optname), optlen); + static_cast<u32>(optname), optval.size()); - BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optlen, optval)); + BuildErrnoResponse(ctx, SetSockOptImpl(fd, level, optname, optval)); } void BSD::Shutdown(HLERequestContext& ctx) { @@ -521,18 +523,19 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<const u8> read_buffer, s32 nfds, s32 timeout) { - if (write_buffer.size() < nfds * sizeof(PollFD)) { - return {-1, Errno::INVAL}; - } - - if (nfds == 0) { + if (nfds <= 0) { // When no entries are provided, -1 is returned with errno zero return {-1, Errno::SUCCESS}; } + if (read_buffer.size() < nfds * sizeof(PollFD)) { + return {-1, Errno::INVAL}; + } + if (write_buffer.size() < nfds * sizeof(PollFD)) { + return {-1, Errno::INVAL}; + } - const size_t length = std::min(read_buffer.size(), write_buffer.size()); std::vector<PollFD> fds(nfds); - std::memcpy(fds.data(), read_buffer.data(), length); + std::memcpy(fds.data(), read_buffer.data(), nfds * sizeof(PollFD)); if (timeout >= 0) { const s64 seconds = timeout / 1000; @@ -580,7 +583,7 @@ std::pair<s32, Errno> BSD::PollImpl(std::vector<u8>& write_buffer, std::span<con for (size_t i = 0; i < num; ++i) { fds[i].revents = Translate(host_pollfds[i].revents); } - std::memcpy(write_buffer.data(), fds.data(), length); + std::memcpy(write_buffer.data(), fds.data(), nfds * sizeof(PollFD)); return Translate(result); } @@ -608,8 +611,7 @@ std::pair<s32, Errno> BSD::AcceptImpl(s32 fd, std::vector<u8>& write_buffer) { new_descriptor.is_connection_based = descriptor.is_connection_based; const SockAddrIn guest_addr_in = Translate(result.sockaddr_in); - const size_t length = std::min(sizeof(guest_addr_in), write_buffer.size()); - std::memcpy(write_buffer.data(), &guest_addr_in, length); + PutValue(write_buffer, guest_addr_in); return {new_fd, Errno::SUCCESS}; } @@ -619,8 +621,7 @@ Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) { return Errno::BADF; } ASSERT(addr.size() == sizeof(SockAddrIn)); - SockAddrIn addr_in; - std::memcpy(&addr_in, addr.data(), sizeof(addr_in)); + auto addr_in = GetValue<SockAddrIn>(addr); return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in))); } @@ -631,8 +632,7 @@ Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) { } UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn)); - SockAddrIn addr_in; - std::memcpy(&addr_in, addr.data(), sizeof(addr_in)); + auto addr_in = GetValue<SockAddrIn>(addr); return Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in))); } @@ -650,7 +650,7 @@ Errno BSD::GetPeerNameImpl(s32 fd, std::vector<u8>& write_buffer) { ASSERT(write_buffer.size() >= sizeof(guest_addrin)); write_buffer.resize(sizeof(guest_addrin)); - std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin)); + PutValue(write_buffer, guest_addrin); return Translate(bsd_errno); } @@ -667,7 +667,7 @@ Errno BSD::GetSockNameImpl(s32 fd, std::vector<u8>& write_buffer) { ASSERT(write_buffer.size() >= sizeof(guest_addrin)); write_buffer.resize(sizeof(guest_addrin)); - std::memcpy(write_buffer.data(), &guest_addrin, sizeof(guest_addrin)); + PutValue(write_buffer, guest_addrin); return Translate(bsd_errno); } @@ -725,7 +725,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& o optval.size() == sizeof(Errno), { return Errno::INVAL; }, "Incorrect getsockopt option size"); optval.resize(sizeof(Errno)); - memcpy(optval.data(), &translated_pending_err, sizeof(Errno)); + PutValue(optval, translated_pending_err); } return Translate(getsockopt_err); } @@ -735,7 +735,7 @@ Errno BSD::GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& o } } -Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval) { +Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval) { if (!IsFileDescriptorValid(fd)) { return Errno::BADF; } @@ -748,17 +748,15 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, con Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); if (optname == OptName::LINGER) { - ASSERT(optlen == sizeof(Linger)); - Linger linger; - std::memcpy(&linger, optval, sizeof(linger)); + ASSERT(optval.size() == sizeof(Linger)); + auto linger = GetValue<Linger>(optval); ASSERT(linger.onoff == 0 || linger.onoff == 1); return Translate(socket->SetLinger(linger.onoff != 0, linger.linger)); } - ASSERT(optlen == sizeof(u32)); - u32 value; - std::memcpy(&value, optval, sizeof(value)); + ASSERT(optval.size() == sizeof(u32)); + auto value = GetValue<u32>(optval); switch (optname) { case OptName::REUSEADDR: @@ -862,7 +860,7 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess } else { ASSERT(addr.size() == sizeof(SockAddrIn)); const SockAddrIn result = Translate(addr_in); - std::memcpy(addr.data(), &result, sizeof(result)); + PutValue(addr, result); } } @@ -886,8 +884,7 @@ std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> mes Network::SockAddrIn* p_addr_in = nullptr; if (!addr.empty()) { ASSERT(addr.size() == sizeof(SockAddrIn)); - SockAddrIn guest_addr_in; - std::memcpy(&guest_addr_in, addr.data(), sizeof(guest_addr_in)); + auto guest_addr_in = GetValue<SockAddrIn>(addr); addr_in = Translate(guest_addr_in); p_addr_in = &addr_in; } diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index 161f22b9b..4f69d382c 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h @@ -163,7 +163,7 @@ private: Errno ListenImpl(s32 fd, s32 backlog); std::pair<s32, Errno> FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg); Errno GetSockOptImpl(s32 fd, u32 level, OptName optname, std::vector<u8>& optval); - Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, const void* optval); + Errno SetSockOptImpl(s32 fd, u32 level, OptName optname, std::span<const u8> optval); Errno ShutdownImpl(s32 fd, s32 how); std::pair<s32, Errno> RecvImpl(s32 fd, u32 flags, std::vector<u8>& message); std::pair<s32, Errno> RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& message, |