diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/hle/kernel/process.cpp | 6 | ||||
-rw-r--r-- | src/core/hle/kernel/process.h | 1 | ||||
-rw-r--r-- | src/core/hle/result.h | 58 | ||||
-rw-r--r-- | src/core/hle/service/ac_u.cpp | 19 | ||||
-rw-r--r-- | src/core/hle/service/cam/cam.cpp | 282 | ||||
-rw-r--r-- | src/core/hle/service/cam/cam.h | 262 | ||||
-rw-r--r-- | src/core/hle/service/cam/cam_u.cpp | 39 | ||||
-rw-r--r-- | src/core/hle/service/dsp_dsp.cpp | 223 | ||||
-rw-r--r-- | src/core/loader/ncch.cpp | 3 | ||||
-rw-r--r-- | src/core/memory.cpp | 2 |
10 files changed, 776 insertions, 119 deletions
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 16eb972fb..24b266eae 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp @@ -130,9 +130,11 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) { Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority); } +VAddr Process::GetLinearHeapAreaAddress() const { + return kernel_version < 0x22C ? Memory::LINEAR_HEAP_VADDR : Memory::NEW_LINEAR_HEAP_VADDR; +} VAddr Process::GetLinearHeapBase() const { - return (kernel_version < 0x22C ? Memory::LINEAR_HEAP_VADDR : Memory::NEW_LINEAR_HEAP_VADDR) - + memory_region->base; + return GetLinearHeapAreaAddress() + memory_region->base; } VAddr Process::GetLinearHeapLimit() const { diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 60e17f251..6d2ca96a2 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h @@ -143,6 +143,7 @@ public: /// Bitmask of the used TLS slots std::bitset<300> used_tls_slots; + VAddr GetLinearHeapAreaAddress() const; VAddr GetLinearHeapBase() const; VAddr GetLinearHeapLimit() const; diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 0fce5988b..69613fbbb 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -269,7 +269,6 @@ public: : result_code(error_code) { ASSERT(error_code.IsError()); - UpdateDebugPtr(); } /** @@ -287,40 +286,37 @@ public: : result_code(o.result_code) { if (!o.empty()) { - new (&storage) T(*o.GetPointer()); + new (&object) T(o.object); } - UpdateDebugPtr(); } ResultVal(ResultVal&& o) : result_code(o.result_code) { if (!o.empty()) { - new (&storage) T(std::move(*o.GetPointer())); + new (&object) T(std::move(o.object)); } - UpdateDebugPtr(); } ~ResultVal() { if (!empty()) { - GetPointer()->~T(); + object.~T(); } } ResultVal& operator=(const ResultVal& o) { if (!empty()) { if (!o.empty()) { - *GetPointer() = *o.GetPointer(); + object = o.object; } else { - GetPointer()->~T(); + object.~T(); } } else { if (!o.empty()) { - new (&storage) T(*o.GetPointer()); + new (&object) T(o.object); } } result_code = o.result_code; - UpdateDebugPtr(); return *this; } @@ -333,11 +329,10 @@ public: void emplace(ResultCode success_code, Args&&... args) { ASSERT(success_code.IsSuccess()); if (!empty()) { - GetPointer()->~T(); + object.~T(); } - new (&storage) T(std::forward<Args>(args)...); + new (&object) T(std::forward<Args>(args)...); result_code = success_code; - UpdateDebugPtr(); } /// Returns true if the `ResultVal` contains an error code and no value. @@ -350,15 +345,15 @@ public: ResultCode Code() const { return result_code; } - const T& operator* () const { return *GetPointer(); } - T& operator* () { return *GetPointer(); } - const T* operator->() const { return GetPointer(); } - T* operator->() { return GetPointer(); } + const T& operator* () const { return object; } + T& operator* () { return object; } + const T* operator->() const { return &object; } + T* operator->() { return &object; } /// Returns the value contained in this `ResultVal`, or the supplied default if it is missing. template <typename U> T ValueOr(U&& value) const { - return !empty() ? *GetPointer() : std::move(value); + return !empty() ? object : std::move(value); } /// Asserts that the result succeeded and returns a reference to it. @@ -372,31 +367,10 @@ public: } private: - typedef typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type StorageType; - - StorageType storage; + // A union is used to allocate the storage for the value, while allowing us to construct and + // destruct it at will. + union { T object; }; ResultCode result_code; -#ifdef _DEBUG - // The purpose of this pointer is to aid inspecting the type with a debugger, eliminating the - // need to cast `storage` to a pointer or pay attention to `result_code`. - const T* debug_ptr; -#endif - - void UpdateDebugPtr() { -#ifdef _DEBUG - debug_ptr = empty() ? nullptr : static_cast<const T*>(static_cast<const void*>(&storage)); -#endif - } - - const T* GetPointer() const { - ASSERT(!empty()); - return static_cast<const T*>(static_cast<const void*>(&storage)); - } - - T* GetPointer() { - ASSERT(!empty()); - return static_cast<T*>(static_cast<void*>(&storage)); - } }; /** diff --git a/src/core/hle/service/ac_u.cpp b/src/core/hle/service/ac_u.cpp index c48259e13..d67325506 100644 --- a/src/core/hle/service/ac_u.cpp +++ b/src/core/hle/service/ac_u.cpp @@ -22,12 +22,27 @@ static void GetWifiStatus(Service::Interface* self) { // TODO(purpasmart96): This function is only a stub, // it returns a valid result without implementing full functionality. - cmd_buff[1] = 0; // No error + cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = 0; // Connection type set to none LOG_WARNING(Service_AC, "(STUBBED) called"); } +/** + * AC_U::IsConnected service function + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : bool, is connected + */ +static void IsConnected(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = false; // Not connected to ac:u service + + LOG_WARNING(Service_AC, "(STUBBED) called"); +} + const Interface::FunctionInfo FunctionTable[] = { {0x00010000, nullptr, "CreateDefaultConfig"}, {0x00040006, nullptr, "ConnectAsync"}, @@ -44,7 +59,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x002D0082, nullptr, "SetRequestEulaVersion"}, {0x00300004, nullptr, "RegisterDisconnectEvent"}, {0x003C0042, nullptr, "GetAPSSIDList"}, - {0x003E0042, nullptr, "IsConnected"}, + {0x003E0042, IsConnected, "IsConnected"}, {0x00400042, nullptr, "SetClientVersion"}, }; diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp index 360bcfca4..4d714037f 100644 --- a/src/core/hle/service/cam/cam.cpp +++ b/src/core/hle/service/cam/cam.cpp @@ -4,16 +4,287 @@ #include "common/logging/log.h" -#include "core/hle/service/service.h" +#include "core/hle/kernel/event.h" #include "core/hle/service/cam/cam.h" #include "core/hle/service/cam/cam_c.h" #include "core/hle/service/cam/cam_q.h" #include "core/hle/service/cam/cam_s.h" #include "core/hle/service/cam/cam_u.h" +#include "core/hle/service/service.h" namespace Service { namespace CAM { +static const u32 TRANSFER_BYTES = 5 * 1024; + +static Kernel::SharedPtr<Kernel::Event> completion_event_cam1; +static Kernel::SharedPtr<Kernel::Event> completion_event_cam2; +static Kernel::SharedPtr<Kernel::Event> interrupt_error_event; +static Kernel::SharedPtr<Kernel::Event> vsync_interrupt_error_event; + +void StartCapture(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u8 port = cmd_buff[1] & 0xFF; + + cmd_buff[0] = IPC::MakeHeader(0x1, 1, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port); +} + +void StopCapture(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u8 port = cmd_buff[1] & 0xFF; + + cmd_buff[0] = IPC::MakeHeader(0x2, 1, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port); +} + +void GetVsyncInterruptEvent(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u8 port = cmd_buff[1] & 0xFF; + + cmd_buff[0] = IPC::MakeHeader(0x5, 1, 2); + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = IPC::MoveHandleDesc(); + cmd_buff[3] = Kernel::g_handle_table.Create(vsync_interrupt_error_event).MoveFrom(); + + LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port); +} + +void GetBufferErrorInterruptEvent(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u8 port = cmd_buff[1] & 0xFF; + + cmd_buff[0] = IPC::MakeHeader(0x6, 1, 2); + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = IPC::MoveHandleDesc(); + cmd_buff[3] = Kernel::g_handle_table.Create(interrupt_error_event).MoveFrom(); + + LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port); +} + +void SetReceiving(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + VAddr dest = cmd_buff[1]; + u8 port = cmd_buff[2] & 0xFF; + u32 image_size = cmd_buff[3]; + u16 trans_unit = cmd_buff[4] & 0xFFFF; + + Kernel::Event* completion_event = (Port)port == Port::Cam2 ? + completion_event_cam2.get() : completion_event_cam1.get(); + + completion_event->Signal(); + + cmd_buff[0] = IPC::MakeHeader(0x7, 1, 2); + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = IPC::MoveHandleDesc(); + cmd_buff[3] = Kernel::g_handle_table.Create(completion_event).MoveFrom(); + + LOG_WARNING(Service_CAM, "(STUBBED) called, addr=0x%X, port=%d, image_size=%d, trans_unit=%d", + dest, port, image_size, trans_unit); +} + +void SetTransferLines(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u8 port = cmd_buff[1] & 0xFF; + u16 transfer_lines = cmd_buff[2] & 0xFFFF; + u16 width = cmd_buff[3] & 0xFFFF; + u16 height = cmd_buff[4] & 0xFFFF; + + cmd_buff[0] = IPC::MakeHeader(0x9, 1, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d, lines=%d, width=%d, height=%d", + port, transfer_lines, width, height); +} + +void GetMaxLines(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u16 width = cmd_buff[1] & 0xFFFF; + u16 height = cmd_buff[2] & 0xFFFF; + + cmd_buff[0] = IPC::MakeHeader(0xA, 2, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = TRANSFER_BYTES / (2 * width); + + LOG_WARNING(Service_CAM, "(STUBBED) called, width=%d, height=%d, lines = %d", + width, height, cmd_buff[2]); +} + +void GetTransferBytes(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u8 port = cmd_buff[1] & 0xFF; + + cmd_buff[0] = IPC::MakeHeader(0xC, 2, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = TRANSFER_BYTES; + + LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d", port); +} + +void SetTrimming(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u8 port = cmd_buff[1] & 0xFF; + bool trim = (cmd_buff[2] & 0xFF) != 0; + + cmd_buff[0] = IPC::MakeHeader(0xE, 1, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d, trim=%d", port, trim); +} + +void SetTrimmingParamsCenter(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u8 port = cmd_buff[1] & 0xFF; + s16 trimW = cmd_buff[2] & 0xFFFF; + s16 trimH = cmd_buff[3] & 0xFFFF; + s16 camW = cmd_buff[4] & 0xFFFF; + s16 camH = cmd_buff[5] & 0xFFFF; + + cmd_buff[0] = IPC::MakeHeader(0x12, 1, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_CAM, "(STUBBED) called, port=%d, trimW=%d, trimH=%d, camW=%d, camH=%d", + port, trimW, trimH, camW, camH); +} + +void Activate(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u8 cam_select = cmd_buff[1] & 0xFF; + + cmd_buff[0] = IPC::MakeHeader(0x13, 1, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d", + cam_select); +} + +void FlipImage(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u8 cam_select = cmd_buff[1] & 0xFF; + u8 flip = cmd_buff[2] & 0xFF; + u8 context = cmd_buff[3] & 0xFF; + + cmd_buff[0] = IPC::MakeHeader(0x1D, 1, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, flip=%d, context=%d", + cam_select, flip, context); +} + +void SetSize(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u8 cam_select = cmd_buff[1] & 0xFF; + u8 size = cmd_buff[2] & 0xFF; + u8 context = cmd_buff[3] & 0xFF; + + cmd_buff[0] = IPC::MakeHeader(0x1F, 1, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, size=%d, context=%d", + cam_select, size, context); +} + +void SetFrameRate(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u8 cam_select = cmd_buff[1] & 0xFF; + u8 frame_rate = cmd_buff[2] & 0xFF; + + cmd_buff[0] = IPC::MakeHeader(0x20, 1, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_CAM, "(STUBBED) called, cam_select=%d, frame_rate=%d", + cam_select, frame_rate); +} + +void GetStereoCameraCalibrationData(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // Default values taken from yuriks' 3DS. Valid data is required here or games using the + // calibration get stuck in an infinite CPU loop. + StereoCameraCalibrationData data = {}; + data.isValidRotationXY = 0; + data.scale = 1.001776f; + data.rotationZ = 0.008322907f; + data.translationX = -87.70484f; + data.translationY = -7.640977f; + data.rotationX = 0.0f; + data.rotationY = 0.0f; + data.angleOfViewRight = 64.66875f; + data.angleOfViewLeft = 64.76067f; + data.distanceToChart = 250.0f; + data.distanceCameras = 35.0f; + data.imageWidth = 640; + data.imageHeight = 480; + + cmd_buff[0] = IPC::MakeHeader(0x2B, 17, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + memcpy(&cmd_buff[2], &data, sizeof(data)); + + LOG_TRACE(Service_CAM, "called"); +} + +void GetSuitableY2rStandardCoefficient(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[0] = IPC::MakeHeader(0x36, 2, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; + + LOG_WARNING(Service_CAM, "(STUBBED) called"); +} + +void PlayShutterSound(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u8 sound_id = cmd_buff[1] & 0xFF; + + cmd_buff[0] = IPC::MakeHeader(0x38, 1, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_CAM, "(STUBBED) called, sound_id=%d", sound_id); +} + +void DriverInitialize(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + completion_event_cam1->Clear(); + completion_event_cam2->Clear(); + interrupt_error_event->Clear(); + vsync_interrupt_error_event->Clear(); + + cmd_buff[0] = IPC::MakeHeader(0x39, 1, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_CAM, "(STUBBED) called"); +} + +void DriverFinalize(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[0] = IPC::MakeHeader(0x3A, 1, 0); + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_CAM, "(STUBBED) called"); +} + void Init() { using namespace Kernel; @@ -21,9 +292,18 @@ void Init() { AddService(new CAM_Q_Interface); AddService(new CAM_S_Interface); AddService(new CAM_U_Interface); + + completion_event_cam1 = Kernel::Event::Create(RESETTYPE_ONESHOT, "CAM_U::completion_event_cam1"); + completion_event_cam2 = Kernel::Event::Create(RESETTYPE_ONESHOT, "CAM_U::completion_event_cam2"); + interrupt_error_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "CAM_U::interrupt_error_event"); + vsync_interrupt_error_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "CAM_U::vsync_interrupt_error_event"); } void Shutdown() { + completion_event_cam1 = nullptr; + completion_event_cam2 = nullptr; + interrupt_error_event = nullptr; + vsync_interrupt_error_event = nullptr; } } // namespace CAM diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h index 23d0c9c59..2f4923728 100644 --- a/src/core/hle/service/cam/cam.h +++ b/src/core/hle/service/cam/cam.h @@ -4,7 +4,12 @@ #pragma once +#include "common/common_funcs.h" #include "common/common_types.h" +#include "common/swap.h" + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" namespace Service { namespace CAM { @@ -140,6 +145,26 @@ enum class OutputFormat : u8 { RGB565 = 1 }; +/// Stereo camera calibration data. +struct StereoCameraCalibrationData { + u8 isValidRotationXY; ///< Bool indicating whether the X and Y rotation data is valid. + INSERT_PADDING_BYTES(3); + float_le scale; ///< Scale to match the left camera image with the right. + float_le rotationZ; ///< Z axis rotation to match the left camera image with the right. + float_le translationX; ///< X axis translation to match the left camera image with the right. + float_le translationY; ///< Y axis translation to match the left camera image with the right. + float_le rotationX; ///< X axis rotation to match the left camera image with the right. + float_le rotationY; ///< Y axis rotation to match the left camera image with the right. + float_le angleOfViewRight; ///< Right camera angle of view. + float_le angleOfViewLeft; ///< Left camera angle of view. + float_le distanceToChart; ///< Distance between cameras and measurement chart. + float_le distanceCameras; ///< Distance between left and right cameras. + s16_le imageWidth; ///< Image width. + s16_le imageHeight; ///< Image height. + INSERT_PADDING_BYTES(16); +}; +static_assert(sizeof(StereoCameraCalibrationData) == 64, "StereoCameraCalibrationData structure size is wrong"); + struct PackageParameterCameraSelect { CameraSelect camera; s8 exposure; @@ -165,6 +190,243 @@ struct PackageParameterCameraSelect { static_assert(sizeof(PackageParameterCameraSelect) == 28, "PackageParameterCameraSelect structure size is wrong"); +/** + * Unknown + * Inputs: + * 0: 0x00010040 + * 1: u8 Camera port (`Port` enum) + * Outputs: + * 0: 0x00010040 + * 1: ResultCode + */ +void StartCapture(Service::Interface* self); + +/** + * Unknown + * Inputs: + * 0: 0x00020040 + * 1: u8 Camera port (`Port` enum) + * Outputs: + * 0: 0x00020040 + * 1: ResultCode + */ +void StopCapture(Service::Interface* self); + +/** + * Unknown + * Inputs: + * 0: 0x00050040 + * 1: u8 Camera port (`Port` enum) + * Outputs: + * 0: 0x00050042 + * 1: ResultCode + * 2: Descriptor: Handle + * 3: Event handle + */ +void GetVsyncInterruptEvent(Service::Interface* self); + +/** + * Unknown + * Inputs: + * 0: 0x00060040 + * 1: u8 Camera port (`Port` enum) + * Outputs: + * 0: 0x00060042 + * 1: ResultCode + * 2: Descriptor: Handle + * 3: Event handle + */ +void GetBufferErrorInterruptEvent(Service::Interface* self); + +/** + * Sets the target buffer to receive a frame of image data and starts the transfer. Each camera + * port has its own event to signal the end of the transfer. + * + * Inputs: + * 0: 0x00070102 + * 1: Destination address in calling process + * 2: u8 Camera port (`Port` enum) + * 3: Image size (in bytes?) + * 4: u16 Transfer unit size (in bytes?) + * 5: Descriptor: Handle + * 6: Handle to destination process + * Outputs: + * 0: 0x00070042 + * 1: ResultCode + * 2: Descriptor: Handle + * 3: Handle to event signalled when transfer finishes + */ +void SetReceiving(Service::Interface* self); + +/** + * Unknown + * Inputs: + * 0: 0x00090100 + * 1: u8 Camera port (`Port` enum) + * 2: u16 Number of lines to transfer + * 3: u16 Width + * 4: u16 Height + * Outputs: + * 0: 0x00090040 + * 1: ResultCode + */ +void SetTransferLines(Service::Interface* self); + +/** + * Unknown + * Inputs: + * 0: 0x000A0080 + * 1: u16 Width + * 2: u16 Height + * Outputs: + * 0: 0x000A0080 + * 1: ResultCode + * 2: Maximum number of lines that fit in the buffer(?) + */ +void GetMaxLines(Service::Interface* self); + +/** + * Unknown + * Inputs: + * 0: 0x000C0040 + * 1: u8 Camera port (`Port` enum) + * Outputs: + * 0: 0x000C0080 + * 1: ResultCode + * 2: Total number of bytes for each frame with current settings(?) + */ +void GetTransferBytes(Service::Interface* self); + +/** + * Unknown + * Inputs: + * 0: 0x000E0080 + * 1: u8 Camera port (`Port` enum) + * 2: u8 bool Enable trimming if true + * Outputs: + * 0: 0x000E0040 + * 1: ResultCode + */ +void SetTrimming(Service::Interface* self); + +/** + * Unknown + * Inputs: + * 0: 0x00120140 + * 1: u8 Camera port (`Port` enum) + * 2: s16 Trim width(?) + * 3: s16 Trim height(?) + * 4: s16 Camera width(?) + * 5: s16 Camera height(?) + * Outputs: + * 0: 0x00120040 + * 1: ResultCode + */ +void SetTrimmingParamsCenter(Service::Interface* self); + +/** + * Selects up to two physical cameras to enable. + * Inputs: + * 0: 0x00130040 + * 1: u8 Cameras to activate (`CameraSelect` enum) + * Outputs: + * 0: 0x00130040 + * 1: ResultCode + */ +void Activate(Service::Interface* self); + +/** + * Unknown + * Inputs: + * 0: 0x001D00C0 + * 1: u8 Camera select (`CameraSelect` enum) + * 2: u8 Type of flipping to perform (`Flip` enum) + * 3: u8 Context (`Context` enum) + * Outputs: + * 0: 0x001D0040 + * 1: ResultCode + */ +void FlipImage(Service::Interface* self); + +/** + * Unknown + * Inputs: + * 0: 0x001F00C0 + * 1: u8 Camera select (`CameraSelect` enum) + * 2: u8 Camera frame resolution (`Size` enum) + * 3: u8 Context id (`Context` enum) + * Outputs: + * 0: 0x001F0040 + * 1: ResultCode + */ +void SetSize(Service::Interface* self); + +/** + * Unknown + * Inputs: + * 0: 0x00200080 + * 1: u8 Camera select (`CameraSelect` enum) + * 2: u8 Camera framerate (`FrameRate` enum) + * Outputs: + * 0: 0x00200040 + * 1: ResultCode + */ +void SetFrameRate(Service::Interface* self); + +/** + * Returns calibration data relating the outside cameras to eachother, for use in AR applications. + * + * Inputs: + * 0: 0x002B0000 + * Outputs: + * 0: 0x002B0440 + * 1: ResultCode + * 2-17: `StereoCameraCalibrationData` structure with calibration values + */ +void GetStereoCameraCalibrationData(Service::Interface* self); + +/** + * Unknown + * Inputs: + * 0: 0x00360000 + * Outputs: + * 0: 0x00360080 + * 1: ResultCode + * 2: ? + */ +void GetSuitableY2rStandardCoefficient(Service::Interface* self); + +/** + * Unknown + * Inputs: + * 0: 0x00380040 + * 1: u8 Sound ID + * Outputs: + * 0: 0x00380040 + * 1: ResultCode + */ +void PlayShutterSound(Service::Interface* self); + +/** + * Initializes the camera driver. Must be called before using other functions. + * Inputs: + * 0: 0x00390000 + * Outputs: + * 0: 0x00390040 + * 1: ResultCode + */ +void DriverInitialize(Service::Interface* self); + +/** + * Shuts down the camera driver. + * Inputs: + * 0: 0x003A0000 + * Outputs: + * 0: 0x003A0040 + * 1: ResultCode + */ +void DriverFinalize(Service::Interface* self); + /// Initialize CAM service(s) void Init(); diff --git a/src/core/hle/service/cam/cam_u.cpp b/src/core/hle/service/cam/cam_u.cpp index 9d59c55fb..a1070ebb2 100644 --- a/src/core/hle/service/cam/cam_u.cpp +++ b/src/core/hle/service/cam/cam_u.cpp @@ -2,31 +2,32 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "core/hle/service/cam/cam.h" #include "core/hle/service/cam/cam_u.h" namespace Service { namespace CAM { const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, nullptr, "StartCapture"}, - {0x00020040, nullptr, "StopCapture"}, + {0x00010040, StartCapture, "StartCapture"}, + {0x00020040, StopCapture, "StopCapture"}, {0x00030040, nullptr, "IsBusy"}, {0x00040040, nullptr, "ClearBuffer"}, - {0x00050040, nullptr, "GetVsyncInterruptEvent"}, - {0x00060040, nullptr, "GetBufferErrorInterruptEvent"}, - {0x00070102, nullptr, "SetReceiving"}, + {0x00050040, GetVsyncInterruptEvent, "GetVsyncInterruptEvent"}, + {0x00060040, GetBufferErrorInterruptEvent, "GetBufferErrorInterruptEvent"}, + {0x00070102, SetReceiving, "SetReceiving"}, {0x00080040, nullptr, "IsFinishedReceiving"}, - {0x00090100, nullptr, "SetTransferLines"}, - {0x000A0080, nullptr, "GetMaxLines"}, + {0x00090100, SetTransferLines, "SetTransferLines"}, + {0x000A0080, GetMaxLines, "GetMaxLines"}, {0x000B0100, nullptr, "SetTransferBytes"}, - {0x000C0040, nullptr, "GetTransferBytes"}, + {0x000C0040, GetTransferBytes, "GetTransferBytes"}, {0x000D0080, nullptr, "GetMaxBytes"}, - {0x000E0080, nullptr, "SetTrimming"}, + {0x000E0080, SetTrimming, "SetTrimming"}, {0x000F0040, nullptr, "IsTrimming"}, {0x00100140, nullptr, "SetTrimmingParams"}, {0x00110040, nullptr, "GetTrimmingParams"}, - {0x00120140, nullptr, "SetTrimmingParamsCenter"}, - {0x00130040, nullptr, "Activate"}, + {0x00120140, SetTrimmingParamsCenter, "SetTrimmingParamsCenter"}, + {0x00130040, Activate, "Activate"}, {0x00140080, nullptr, "SwitchContext"}, {0x00150080, nullptr, "SetExposure"}, {0x00160080, nullptr, "SetWhiteBalance"}, @@ -36,10 +37,10 @@ const Interface::FunctionInfo FunctionTable[] = { {0x001A0040, nullptr, "IsAutoExposure"}, {0x001B0080, nullptr, "SetAutoWhiteBalance"}, {0x001C0040, nullptr, "IsAutoWhiteBalance"}, - {0x001D00C0, nullptr, "FlipImage"}, + {0x001D00C0, FlipImage, "FlipImage"}, {0x001E0200, nullptr, "SetDetailSize"}, - {0x001F00C0, nullptr, "SetSize"}, - {0x00200080, nullptr, "SetFrameRate"}, + {0x001F00C0, SetSize, "SetSize"}, + {0x00200080, SetFrameRate, "SetFrameRate"}, {0x00210080, nullptr, "SetPhotoMode"}, {0x002200C0, nullptr, "SetEffect"}, {0x00230080, nullptr, "SetContrast"}, @@ -50,7 +51,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00280080, nullptr, "SetNoiseFilter"}, {0x00290080, nullptr, "SynchronizeVsyncTiming"}, {0x002A0080, nullptr, "GetLatestVsyncTiming"}, - {0x002B0000, nullptr, "GetStereoCameraCalibrationData"}, + {0x002B0000, GetStereoCameraCalibrationData, "GetStereoCameraCalibrationData"}, {0x002C0400, nullptr, "SetStereoCameraCalibrationData"}, {0x002D00C0, nullptr, "WriteRegisterI2c"}, {0x002E00C0, nullptr, "WriteMcuVariableI2c"}, @@ -61,11 +62,11 @@ const Interface::FunctionInfo FunctionTable[] = { {0x003302C0, nullptr, "SetPackageParameterWithoutContext"}, {0x00340140, nullptr, "SetPackageParameterWithContext"}, {0x003501C0, nullptr, "SetPackageParameterWithContextDetail"}, - {0x00360000, nullptr, "GetSuitableY2rStandardCoefficient"}, + {0x00360000, GetSuitableY2rStandardCoefficient, "GetSuitableY2rStandardCoefficient"}, {0x00370202, nullptr, "PlayShutterSoundWithWave"}, - {0x00380040, nullptr, "PlayShutterSound"}, - {0x00390000, nullptr, "DriverInitialize"}, - {0x003A0000, nullptr, "DriverFinalize"}, + {0x00380040, PlayShutterSound, "PlayShutterSound"}, + {0x00390000, DriverInitialize, "DriverInitialize"}, + {0x003A0000, DriverFinalize, "DriverFinalize"}, {0x003B0000, nullptr, "GetActivatedCamera"}, {0x003C0000, nullptr, "GetSleepCamera"}, {0x003D0040, nullptr, "SetSleepCamera"}, diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp index 15d3274ec..3ba24d466 100644 --- a/src/core/hle/service/dsp_dsp.cpp +++ b/src/core/hle/service/dsp_dsp.cpp @@ -2,8 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cinttypes> + #include "audio_core/hle/pipe.h" +#include "common/hash.h" #include "common/logging/log.h" #include "core/hle/kernel/event.h" @@ -55,18 +58,18 @@ static void ConvertProcessAddressFromDspDram(Service::Interface* self) { u32 addr = cmd_buff[1]; - cmd_buff[1] = 0; // No error + cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = (addr << 1) + (Memory::DSP_RAM_VADDR + 0x40000); - LOG_TRACE(Service_DSP, "addr=0x%08X", addr); + LOG_DEBUG(Service_DSP, "addr=0x%08X", addr); } /** * DSP_DSP::LoadComponent service function * Inputs: * 1 : Size - * 2 : Unknown (observed only half word used) - * 3 : Unknown (observed only half word used) + * 2 : Program mask (observed only half word used) + * 3 : Data mask (observed only half word used) * 4 : (size << 4) | 0xA * 5 : Buffer address * Outputs: @@ -77,18 +80,28 @@ static void LoadComponent(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 size = cmd_buff[1]; - u32 unk1 = cmd_buff[2]; - u32 unk2 = cmd_buff[3]; - u32 new_size = cmd_buff[4]; + u32 prog_mask = cmd_buff[2]; + u32 data_mask = cmd_buff[3]; + u32 desc = cmd_buff[4]; u32 buffer = cmd_buff[5]; - cmd_buff[1] = 0; // No error + cmd_buff[0] = IPC::MakeHeader(0x11, 2, 2); + cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = 1; // Pretend that we actually loaded the DSP firmware + cmd_buff[3] = desc; + cmd_buff[4] = buffer; // TODO(bunnei): Implement real DSP firmware loading - LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%X, unk1=0x%08X, unk2=0x%08X, new_size=0x%X, buffer=0x%08X", - size, unk1, unk2, new_size, buffer); + ASSERT(Memory::GetPointer(buffer) != nullptr); + ASSERT(size > 0x37C); + + LOG_INFO(Service_DSP, "Firmware hash: %#" PRIx64, Common::ComputeHash64(Memory::GetPointer(buffer), size)); + // Some versions of the firmware have the location of DSP structures listed here. + LOG_INFO(Service_DSP, "Structures hash: %#" PRIx64, Common::ComputeHash64(Memory::GetPointer(buffer) + 0x340, 60)); + + LOG_WARNING(Service_DSP, "(STUBBED) called size=0x%X, prog_mask=0x%08X, data_mask=0x%08X, buffer=0x%08X", + size, prog_mask, data_mask, buffer); } /** @@ -129,8 +142,7 @@ static void FlushDataCache(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_DEBUG(Service_DSP, "(STUBBED) called address=0x%08X, size=0x%X, process=0x%08X", - address, size, process); + LOG_TRACE(Service_DSP, "called address=0x%08X, size=0x%X, process=0x%08X", address, size, process); } /** @@ -154,14 +166,14 @@ static void RegisterInterruptEvents(Service::Interface* self) { if (evt) { interrupt_events[std::make_pair(interrupt, channel)] = evt; cmd_buff[1] = RESULT_SUCCESS.raw; - LOG_WARNING(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); + LOG_INFO(Service_DSP, "Registered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); } else { - cmd_buff[1] = -1; - LOG_ERROR(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); + LOG_CRITICAL(Service_DSP, "Invalid event handle! interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); + ASSERT(false); // This should really be handled at a IPC translation layer. } } else { interrupt_events.erase(std::make_pair(interrupt, channel)); - LOG_WARNING(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); + LOG_INFO(Service_DSP, "Unregistered interrupt=%u, channel=%u, event_handle=0x%08X", interrupt, channel, event_handle); } } @@ -175,7 +187,7 @@ static void RegisterInterruptEvents(Service::Interface* self) { static void SetSemaphore(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - cmd_buff[1] = 0; // No error + cmd_buff[1] = RESULT_SUCCESS.raw; // No error LOG_WARNING(Service_DSP, "(STUBBED) called"); } @@ -194,21 +206,12 @@ static void SetSemaphore(Service::Interface* self) { static void WriteProcessPipe(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 channel = cmd_buff[1]; - u32 size = cmd_buff[2]; - u32 buffer = cmd_buff[4]; + DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]); + u32 size = cmd_buff[2]; + u32 buffer = cmd_buff[4]; - if (IPC::StaticBufferDesc(size, 1) != cmd_buff[3]) { - LOG_ERROR(Service_DSP, "IPC static buffer descriptor failed validation (0x%X). channel=%u, size=0x%X, buffer=0x%08X", cmd_buff[3], channel, size, buffer); - cmd_buff[1] = -1; // TODO - return; - } - - if (!Memory::GetPointer(buffer)) { - LOG_ERROR(Service_DSP, "Invalid Buffer: channel=%u, size=0x%X, buffer=0x%08X", channel, size, buffer); - cmd_buff[1] = -1; // TODO - return; - } + ASSERT_MSG(IPC::StaticBufferDesc(size, 1) == cmd_buff[3], "IPC static buffer descriptor failed validation (0x%X). pipe=%u, size=0x%X, buffer=0x%08X", cmd_buff[3], pipe, size, buffer); + ASSERT_MSG(Memory::GetPointer(buffer) != nullptr, "Invalid Buffer: pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer); std::vector<u8> message(size); @@ -216,11 +219,11 @@ static void WriteProcessPipe(Service::Interface* self) { message[i] = Memory::Read8(buffer + i); } - DSP::HLE::PipeWrite(channel, message); + DSP::HLE::PipeWrite(pipe, message); cmd_buff[1] = RESULT_SUCCESS.raw; // No error - LOG_TRACE(Service_DSP, "channel=%u, size=0x%X, buffer=0x%08X", channel, size, buffer); + LOG_DEBUG(Service_DSP, "pipe=%u, size=0x%X, buffer=0x%08X", pipe, size, buffer); } /** @@ -232,7 +235,7 @@ static void WriteProcessPipe(Service::Interface* self) { * 1 : Pipe Number * 2 : Unknown * 3 : Size in bytes of read (observed only lower half word used) - * 0x41 : Virtual address to read from DSP pipe to in memory + * 0x41 : Virtual address of memory buffer to write pipe contents to * Outputs: * 1 : Result of function, 0 on success, otherwise error code * 2 : Number of bytes read from pipe @@ -240,25 +243,82 @@ static void WriteProcessPipe(Service::Interface* self) { static void ReadPipeIfPossible(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 pipe = cmd_buff[1]; - u32 unk2 = cmd_buff[2]; - u32 size = cmd_buff[3] & 0xFFFF;// Lower 16 bits are size + DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]); + u32 unknown = cmd_buff[2]; + u32 size = cmd_buff[3] & 0xFFFF; // Lower 16 bits are size VAddr addr = cmd_buff[0x41]; - if (!Memory::GetPointer(addr)) { - LOG_ERROR(Service_DSP, "Invalid addr: pipe=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", pipe, unk2, size, addr); - cmd_buff[1] = -1; // TODO - return; + ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr); + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + if (DSP::HLE::GetPipeReadableSize(pipe) >= size) { + std::vector<u8> response = DSP::HLE::PipeRead(pipe, size); + + Memory::WriteBlock(addr, response.data(), response.size()); + + cmd_buff[2] = static_cast<u32>(response.size()); + } else { + cmd_buff[2] = 0; // Return no data } - std::vector<u8> response = DSP::HLE::PipeRead(pipe, size); + LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, size, addr, cmd_buff[2]); +} - Memory::WriteBlock(addr, response.data(), response.size()); +/** + * DSP_DSP::ReadPipe service function + * Inputs: + * 1 : Pipe Number + * 2 : Unknown + * 3 : Size in bytes of read (observed only lower half word used) + * 0x41 : Virtual address of memory buffer to write pipe contents to + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Number of bytes read from pipe + */ +static void ReadPipe(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]); + u32 unknown = cmd_buff[2]; + u32 size = cmd_buff[3] & 0xFFFF; // Lower 16 bits are size + VAddr addr = cmd_buff[0x41]; + + ASSERT_MSG(Memory::GetPointer(addr) != nullptr, "Invalid addr: pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X", pipe, unknown, size, addr); - cmd_buff[1] = 0; // No error - cmd_buff[2] = (u32)response.size(); + if (DSP::HLE::GetPipeReadableSize(pipe) >= size) { + std::vector<u8> response = DSP::HLE::PipeRead(pipe, size); - LOG_TRACE(Service_DSP, "pipe=0x%08X, unk2=0x%08X, size=0x%X, buffer=0x%08X", pipe, unk2, size, addr); + Memory::WriteBlock(addr, response.data(), response.size()); + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = static_cast<u32>(response.size()); + } else { + // No more data is in pipe. Hardware hangs in this case; this should never happen. + UNREACHABLE(); + } + + LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, size=0x%X, buffer=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, size, addr, cmd_buff[2]); +} + +/** + * DSP_DSP::GetPipeReadableSize service function + * Inputs: + * 1 : Pipe Number + * 2 : Unknown + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Number of bytes readable from pipe + */ +static void GetPipeReadableSize(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + DSP::HLE::DspPipe pipe = static_cast<DSP::HLE::DspPipe>(cmd_buff[1]); + u32 unknown = cmd_buff[2]; + + cmd_buff[1] = RESULT_SUCCESS.raw; // No error + cmd_buff[2] = DSP::HLE::GetPipeReadableSize(pipe); + + LOG_DEBUG(Service_DSP, "pipe=0x%08X, unknown=0x%08X, return cmd_buff[2]=0x%08X", pipe, unknown, cmd_buff[2]); } /** @@ -293,12 +353,73 @@ static void GetHeadphoneStatus(Service::Interface* self) { cmd_buff[1] = RESULT_SUCCESS.raw; // No error cmd_buff[2] = 0; // Not using headphones? - LOG_DEBUG(Service_DSP, "(STUBBED) called"); + LOG_WARNING(Service_DSP, "(STUBBED) called"); +} + +/** + * DSP_DSP::RecvData service function + * This function reads a value out of a DSP register. + * Inputs: + * 1 : Register Number + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : Value in the register + * Notes: + * This function has only been observed being called with a register number of 0. + */ +static void RecvData(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u32 register_number = cmd_buff[1]; + + ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number); + + // Application reads this after requesting DSP shutdown, to verify the DSP has indeed shutdown or slept. + + cmd_buff[1] = RESULT_SUCCESS.raw; + switch (DSP::HLE::GetDspState()) { + case DSP::HLE::DspState::On: + cmd_buff[2] = 0; + break; + case DSP::HLE::DspState::Off: + case DSP::HLE::DspState::Sleeping: + cmd_buff[2] = 1; + break; + default: + UNREACHABLE(); + break; + } + + LOG_DEBUG(Service_DSP, "register_number=%u", register_number); +} + +/** + * DSP_DSP::RecvDataIsReady service function + * This function checks whether a DSP register is ready to be read. + * Inputs: + * 1 : Register Number + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : non-zero == ready + * Note: + * This function has only been observed being called with a register number of 0. + */ +static void RecvDataIsReady(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + u32 register_number = cmd_buff[1]; + + ASSERT_MSG(register_number == 0, "Unknown register_number %u", register_number); + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 1; // Ready to read + + LOG_DEBUG(Service_DSP, "register_number=%u", register_number); } const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, nullptr, "RecvData"}, - {0x00020040, nullptr, "RecvDataIsReady"}, + {0x00010040, RecvData, "RecvData"}, + {0x00020040, RecvDataIsReady, "RecvDataIsReady"}, {0x00030080, nullptr, "SendData"}, {0x00040040, nullptr, "SendDataIsEmpty"}, {0x000500C2, nullptr, "SendFifoEx"}, @@ -310,8 +431,8 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000B0000, nullptr, "CheckSemaphoreRequest"}, {0x000C0040, ConvertProcessAddressFromDspDram, "ConvertProcessAddressFromDspDram"}, {0x000D0082, WriteProcessPipe, "WriteProcessPipe"}, - {0x000E00C0, nullptr, "ReadPipe"}, - {0x000F0080, nullptr, "GetPipeReadableSize"}, + {0x000E00C0, ReadPipe, "ReadPipe"}, + {0x000F0080, GetPipeReadableSize, "GetPipeReadableSize"}, {0x001000C0, ReadPipeIfPossible, "ReadPipeIfPossible"}, {0x001100C2, LoadComponent, "LoadComponent"}, {0x00120000, nullptr, "UnloadComponent"}, diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp index 68b3f546e..93f21bec2 100644 --- a/src/core/loader/ncch.cpp +++ b/src/core/loader/ncch.cpp @@ -255,7 +255,8 @@ ResultStatus AppLoader_NCCH::Load() { priority = exheader_header.arm11_system_local_caps.priority; resource_limit_category = exheader_header.arm11_system_local_caps.resource_limit_category; - LOG_INFO(Loader, "Name: %s" , exheader_header.codeset_info.name); + LOG_INFO(Loader, "Name: %s" , exheader_header.codeset_info.name); + LOG_INFO(Loader, "Program ID: %016X" , ncch_header.program_id); LOG_DEBUG(Loader, "Code compressed: %s" , is_compressed ? "yes" : "no"); LOG_DEBUG(Loader, "Entry point: 0x%08X", entry_point); LOG_DEBUG(Loader, "Code size: 0x%08X", code_size); diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 4753c63a7..7de5bd15d 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -291,7 +291,7 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) { } else if (addr >= VRAM_PADDR && addr < VRAM_PADDR_END) { return addr - VRAM_PADDR + VRAM_VADDR; } else if (addr >= FCRAM_PADDR && addr < FCRAM_PADDR_END) { - return addr - FCRAM_PADDR + Kernel::g_current_process->GetLinearHeapBase(); + return addr - FCRAM_PADDR + Kernel::g_current_process->GetLinearHeapAreaAddress(); } else if (addr >= DSP_RAM_PADDR && addr < DSP_RAM_PADDR_END) { return addr - DSP_RAM_PADDR + DSP_RAM_VADDR; } else if (addr >= IO_AREA_PADDR && addr < IO_AREA_PADDR_END) { |