summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar bunnei2016-04-01 10:50:36 -0400
committerGravatar bunnei2016-04-01 10:50:36 -0400
commit9d7028bcfba061c6e7b305be3d972b9ea2a3d299 (patch)
treea48352b8bddfa01963711898d6d3fb7ebb74ea20 /src
parentMerge pull request #1622 from JayFoxRox/fix-warnings (diff)
parentGSP: Return proper error codes for register writes (diff)
downloadyuzu-9d7028bcfba061c6e7b305be3d972b9ea2a3d299.tar.gz
yuzu-9d7028bcfba061c6e7b305be3d972b9ea2a3d299.tar.xz
yuzu-9d7028bcfba061c6e7b305be3d972b9ea2a3d299.zip
Merge pull request #1390 from purpasmart96/citra_gsp_error_codes
GSP: Return proper error codes for register writes
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/result.h1
-rw-r--r--src/core/hle/service/gsp_gpu.cpp174
-rw-r--r--src/core/hle/service/gsp_gpu.h2
3 files changed, 97 insertions, 80 deletions
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index 0cb76ba1c..2d22652d9 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -24,6 +24,7 @@ enum class ErrorDescription : u32 {
24 FS_InvalidOpenFlags = 230, 24 FS_InvalidOpenFlags = 230,
25 FS_NotAFile = 250, 25 FS_NotAFile = 250,
26 FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive 26 FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
27 OutofRangeOrMisalignedAddress = 513, // TODO(purpasmart): Check if this name fits its actual usage
27 FS_InvalidPath = 702, 28 FS_InvalidPath = 702,
28 InvalidSection = 1000, 29 InvalidSection = 1000,
29 TooLarge = 1001, 30 TooLarge = 1001,
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 11fff7b18..0c655395e 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -31,6 +31,13 @@ const static u32 REGS_BEGIN = 0x1EB00000;
31 31
32namespace GSP_GPU { 32namespace GSP_GPU {
33 33
34const ResultCode ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED(ErrorDescription::OutofRangeOrMisalignedAddress, ErrorModule::GX,
35 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E02A01
36const ResultCode ERR_GSP_REGS_MISALIGNED(ErrorDescription::MisalignedSize, ErrorModule::GX,
37 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E02BF2
38const ResultCode ERR_GSP_REGS_INVALID_SIZE(ErrorDescription::InvalidSize, ErrorModule::GX,
39 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E02BEC
40
34/// Event triggered when GSP interrupt has been signalled 41/// Event triggered when GSP interrupt has been signalled
35Kernel::SharedPtr<Kernel::Event> g_interrupt_event; 42Kernel::SharedPtr<Kernel::Event> g_interrupt_event;
36/// GSP shared memoryings 43/// GSP shared memoryings
@@ -59,47 +66,87 @@ static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
59} 66}
60 67
61/** 68/**
62 * Checks if the parameters in a register write call are valid and logs in the case that 69 * Writes sequential GSP GPU hardware registers using an array of source data
63 * they are not 70 *
64 * @param base_address The first address in the sequence of registers that will be written 71 * @param base_address The address of the first register in the sequence
65 * @param size_in_bytes The number of registers that will be written 72 * @param size_in_bytes The number of registers to update (size of data)
66 * @return true if the parameters are valid, false otherwise 73 * @param data A pointer to the source data
74 * @return RESULT_SUCCESS if the parameters are valid, error code otherwise
67 */ 75 */
68static bool CheckWriteParameters(u32 base_address, u32 size_in_bytes) { 76static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
69 // TODO: Return proper error codes 77 // This magic number is verified to be done by the gsp module
70 if (base_address + size_in_bytes >= 0x420000) { 78 const u32 max_size_in_bytes = 0x80;
71 LOG_ERROR(Service_GSP, "Write address out of range! (address=0x%08x, size=0x%08x)", 79
80 if (base_address & 3 || base_address >= 0x420000) {
81 LOG_ERROR(Service_GSP, "Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)",
72 base_address, size_in_bytes); 82 base_address, size_in_bytes);
73 return false; 83 return ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED;
74 } 84 } else if (size_in_bytes <= max_size_in_bytes) {
85 if (size_in_bytes & 3) {
86 LOG_ERROR(Service_GSP, "Misaligned size 0x%08x", size_in_bytes);
87 return ERR_GSP_REGS_MISALIGNED;
88 } else {
89 while (size_in_bytes > 0) {
90 HW::Write<u32>(base_address + REGS_BEGIN, *data);
91
92 size_in_bytes -= 4;
93 ++data;
94 base_address += 4;
95 }
96 return RESULT_SUCCESS;
97 }
75 98
76 // size should be word-aligned 99 } else {
77 if ((size_in_bytes % 4) != 0) { 100 LOG_ERROR(Service_GSP, "Out of range size 0x%08x", size_in_bytes);
78 LOG_ERROR(Service_GSP, "Invalid size 0x%08x", size_in_bytes); 101 return ERR_GSP_REGS_INVALID_SIZE;
79 return false;
80 } 102 }
81
82 return true;
83} 103}
84 104
85/** 105/**
86 * Writes sequential GSP GPU hardware registers using an array of source data 106 * Updates sequential GSP GPU hardware registers using parallel arrays of source data and masks.
107 * For each register, the value is updated only where the mask is high
87 * 108 *
88 * @param base_address The address of the first register in the sequence 109 * @param base_address The address of the first register in the sequence
89 * @param size_in_bytes The number of registers to update (size of data) 110 * @param size_in_bytes The number of registers to update (size of data)
90 * @param data A pointer to the source data 111 * @param data A pointer to the source data to use for updates
112 * @param masks A pointer to the masks
113 * @return RESULT_SUCCESS if the parameters are valid, error code otherwise
91 */ 114 */
92static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) { 115static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* data, const u32* masks) {
93 // TODO: Return proper error codes 116 // This magic number is verified to be done by the gsp module
94 if (!CheckWriteParameters(base_address, size_in_bytes)) 117 const u32 max_size_in_bytes = 0x80;
95 return;
96 118
97 while (size_in_bytes > 0) { 119 if (base_address & 3 || base_address >= 0x420000) {
98 HW::Write<u32>(base_address + REGS_BEGIN, *data); 120 LOG_ERROR(Service_GSP, "Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)",
121 base_address, size_in_bytes);
122 return ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED;
123 } else if (size_in_bytes <= max_size_in_bytes) {
124 if (size_in_bytes & 3) {
125 LOG_ERROR(Service_GSP, "Misaligned size 0x%08x", size_in_bytes);
126 return ERR_GSP_REGS_MISALIGNED;
127 } else {
128 while (size_in_bytes > 0) {
129 const u32 reg_address = base_address + REGS_BEGIN;
130
131 u32 reg_value;
132 HW::Read<u32>(reg_value, reg_address);
133
134 // Update the current value of the register only for set mask bits
135 reg_value = (reg_value & ~*masks) | (*data | *masks);
136
137 HW::Write<u32>(reg_address, reg_value);
138
139 size_in_bytes -= 4;
140 ++data;
141 ++masks;
142 base_address += 4;
143 }
144 return RESULT_SUCCESS;
145 }
99 146
100 size_in_bytes -= 4; 147 } else {
101 ++data; 148 LOG_ERROR(Service_GSP, "Out of range size 0x%08x", size_in_bytes);
102 base_address += 4; 149 return ERR_GSP_REGS_INVALID_SIZE;
103 } 150 }
104} 151}
105 152
@@ -120,39 +167,7 @@ static void WriteHWRegs(Service::Interface* self) {
120 167
121 u32* src = (u32*)Memory::GetPointer(cmd_buff[4]); 168 u32* src = (u32*)Memory::GetPointer(cmd_buff[4]);
122 169
123 WriteHWRegs(reg_addr, size, src); 170 cmd_buff[1] = WriteHWRegs(reg_addr, size, src).raw;
124}
125
126/**
127 * Updates sequential GSP GPU hardware registers using parallel arrays of source data and masks.
128 * For each register, the value is updated only where the mask is high
129 *
130 * @param base_address The address of the first register in the sequence
131 * @param size_in_bytes The number of registers to update (size of data)
132 * @param data A pointer to the source data to use for updates
133 * @param masks A pointer to the masks
134 */
135static void WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* data, const u32* masks) {
136 // TODO: Return proper error codes
137 if (!CheckWriteParameters(base_address, size_in_bytes))
138 return;
139
140 while (size_in_bytes > 0) {
141 const u32 reg_address = base_address + REGS_BEGIN;
142
143 u32 reg_value;
144 HW::Read<u32>(reg_value, reg_address);
145
146 // Update the current value of the register only for set mask bits
147 reg_value = (reg_value & ~*masks) | (*data | *masks);
148
149 HW::Write<u32>(reg_address, reg_value);
150
151 size_in_bytes -= 4;
152 ++data;
153 ++masks;
154 base_address += 4;
155 }
156} 171}
157 172
158/** 173/**
@@ -174,7 +189,7 @@ static void WriteHWRegsWithMask(Service::Interface* self) {
174 u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]); 189 u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]);
175 u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]); 190 u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]);
176 191
177 WriteHWRegsWithMask(reg_addr, size, src_data, mask_data); 192 cmd_buff[1] = WriteHWRegsWithMask(reg_addr, size, src_data, mask_data).raw;
178} 193}
179 194
180/// Read a GSP GPU hardware register 195/// Read a GSP GPU hardware register
@@ -206,27 +221,27 @@ static void ReadHWRegs(Service::Interface* self) {
206 } 221 }
207} 222}
208 223
209void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { 224ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
210 u32 base_address = 0x400000; 225 u32 base_address = 0x400000;
211 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); 226 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
212 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); 227 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
213 if (info.active_fb == 0) { 228 if (info.active_fb == 0) {
214 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4, 229 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)),
215 &phys_address_left); 230 4, &phys_address_left);
216 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4, 231 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)),
217 &phys_address_right); 232 4, &phys_address_right);
218 } else { 233 } else {
219 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4, 234 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)),
220 &phys_address_left); 235 4, &phys_address_left);
221 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4, 236 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)),
222 &phys_address_right); 237 4, &phys_address_right);
223 } 238 }
224 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4, 239 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)),
225 &info.stride); 240 4, &info.stride);
226 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4, 241 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)),
227 &info.format); 242 4, &info.format);
228 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4, 243 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)),
229 &info.shown_fb); 244 4, &info.shown_fb);
230 245
231 if (Pica::g_debug_context) 246 if (Pica::g_debug_context)
232 Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr); 247 Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr);
@@ -234,6 +249,8 @@ void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
234 if (screen_id == 0) { 249 if (screen_id == 0) {
235 MicroProfileFlip(); 250 MicroProfileFlip();
236 } 251 }
252
253 return RESULT_SUCCESS;
237} 254}
238 255
239/** 256/**
@@ -251,9 +268,8 @@ static void SetBufferSwap(Service::Interface* self) {
251 u32* cmd_buff = Kernel::GetCommandBuffer(); 268 u32* cmd_buff = Kernel::GetCommandBuffer();
252 u32 screen_id = cmd_buff[1]; 269 u32 screen_id = cmd_buff[1];
253 FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2]; 270 FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2];
254 SetBufferSwap(screen_id, *fb_info);
255 271
256 cmd_buff[1] = 0; // No error 272 cmd_buff[1] = SetBufferSwap(screen_id, *fb_info).raw;
257} 273}
258 274
259/** 275/**
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h
index 0e2f7a21e..55a993bb8 100644
--- a/src/core/hle/service/gsp_gpu.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -194,7 +194,7 @@ public:
194 */ 194 */
195void SignalInterrupt(InterruptId interrupt_id); 195void SignalInterrupt(InterruptId interrupt_id);
196 196
197void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info); 197ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info);
198 198
199/** 199/**
200 * Retrieves the framebuffer info stored in the GSP shared memory for the 200 * Retrieves the framebuffer info stored in the GSP shared memory for the