mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	GSP: Return proper error codes for register writes
This commit is contained in:
		
							parent
							
								
									644fbbeb13
								
							
						
					
					
						commit
						abe5c6efec
					
				@ -24,6 +24,7 @@ enum class ErrorDescription : u32 {
 | 
				
			|||||||
    FS_InvalidOpenFlags = 230,
 | 
					    FS_InvalidOpenFlags = 230,
 | 
				
			||||||
    FS_NotAFile = 250,
 | 
					    FS_NotAFile = 250,
 | 
				
			||||||
    FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
 | 
					    FS_NotFormatted = 340, ///< This is used by the FS service when creating a SaveData archive
 | 
				
			||||||
 | 
					    OutofRangeOrMisalignedAddress = 513, // TODO(purpasmart): Check if this name fits its actual usage
 | 
				
			||||||
    FS_InvalidPath = 702,
 | 
					    FS_InvalidPath = 702,
 | 
				
			||||||
    InvalidSection = 1000,
 | 
					    InvalidSection = 1000,
 | 
				
			||||||
    TooLarge = 1001,
 | 
					    TooLarge = 1001,
 | 
				
			||||||
 | 
				
			|||||||
@ -31,6 +31,13 @@ const static u32 REGS_BEGIN = 0x1EB00000;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace GSP_GPU {
 | 
					namespace GSP_GPU {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const ResultCode ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED(ErrorDescription::OutofRangeOrMisalignedAddress, ErrorModule::GX,
 | 
				
			||||||
 | 
					    ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E02A01
 | 
				
			||||||
 | 
					const ResultCode ERR_GSP_REGS_MISALIGNED(ErrorDescription::MisalignedSize, ErrorModule::GX,
 | 
				
			||||||
 | 
					    ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E02BF2
 | 
				
			||||||
 | 
					const ResultCode ERR_GSP_REGS_INVALID_SIZE(ErrorDescription::InvalidSize, ErrorModule::GX,
 | 
				
			||||||
 | 
					    ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E02BEC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Event triggered when GSP interrupt has been signalled
 | 
					/// Event triggered when GSP interrupt has been signalled
 | 
				
			||||||
Kernel::SharedPtr<Kernel::Event> g_interrupt_event;
 | 
					Kernel::SharedPtr<Kernel::Event> g_interrupt_event;
 | 
				
			||||||
/// GSP shared memoryings
 | 
					/// GSP shared memoryings
 | 
				
			||||||
@ -58,42 +65,27 @@ static inline InterruptRelayQueue* GetInterruptRelayQueue(u32 thread_id) {
 | 
				
			|||||||
    return reinterpret_cast<InterruptRelayQueue*>(ptr);
 | 
					    return reinterpret_cast<InterruptRelayQueue*>(ptr);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Checks if the parameters in a register write call are valid and logs in the case that
 | 
					 | 
				
			||||||
 * they are not
 | 
					 | 
				
			||||||
 * @param base_address The first address in the sequence of registers that will be written
 | 
					 | 
				
			||||||
 * @param size_in_bytes The number of registers that will be written
 | 
					 | 
				
			||||||
 * @return true if the parameters are valid, false otherwise
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static bool CheckWriteParameters(u32 base_address, u32 size_in_bytes) {
 | 
					 | 
				
			||||||
    // TODO: Return proper error codes
 | 
					 | 
				
			||||||
    if (base_address + size_in_bytes >= 0x420000) {
 | 
					 | 
				
			||||||
        LOG_ERROR(Service_GSP, "Write address out of range! (address=0x%08x, size=0x%08x)",
 | 
					 | 
				
			||||||
                  base_address, size_in_bytes);
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    // size should be word-aligned
 | 
					 | 
				
			||||||
    if ((size_in_bytes % 4) != 0) {
 | 
					 | 
				
			||||||
        LOG_ERROR(Service_GSP, "Invalid size 0x%08x", size_in_bytes);
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return true;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Writes sequential GSP GPU hardware registers using an array of source data
 | 
					 * Writes sequential GSP GPU hardware registers using an array of source data
 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * @param base_address The address of the first register in the sequence
 | 
					 * @param base_address The address of the first register in the sequence
 | 
				
			||||||
 * @param size_in_bytes The number of registers to update (size of data)
 | 
					 * @param size_in_bytes The number of registers to update (size of data)
 | 
				
			||||||
 * @param data A pointer to the source data
 | 
					 * @param data A pointer to the source data
 | 
				
			||||||
 | 
					 * @return RESULT_SUCCESS if the parameters are valid, error code otherwise
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
 | 
					static ResultCode WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
 | 
				
			||||||
    // TODO: Return proper error codes
 | 
					    // This magic number is verified to be done by the gsp module
 | 
				
			||||||
    if (!CheckWriteParameters(base_address, size_in_bytes))
 | 
					    const u32 max_size_in_bytes = 0x80;
 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (base_address & 3 || base_address >= 0x420000) {
 | 
				
			||||||
 | 
					        LOG_ERROR(Service_GSP, "Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)",
 | 
				
			||||||
 | 
					                  base_address, size_in_bytes);
 | 
				
			||||||
 | 
					        return ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED;
 | 
				
			||||||
 | 
					    } else if (size_in_bytes <= max_size_in_bytes) {
 | 
				
			||||||
 | 
					        if (size_in_bytes & 3) {
 | 
				
			||||||
 | 
					            LOG_ERROR(Service_GSP, "Misaligned size 0x%08x", size_in_bytes);
 | 
				
			||||||
 | 
					            return ERR_GSP_REGS_MISALIGNED;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
            while (size_in_bytes > 0) {
 | 
					            while (size_in_bytes > 0) {
 | 
				
			||||||
                HW::Write<u32>(base_address + REGS_BEGIN, *data);
 | 
					                HW::Write<u32>(base_address + REGS_BEGIN, *data);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -101,6 +93,61 @@ static void WriteHWRegs(u32 base_address, u32 size_in_bytes, const u32* data) {
 | 
				
			|||||||
                ++data;
 | 
					                ++data;
 | 
				
			||||||
                base_address += 4;
 | 
					                base_address += 4;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 | 
					            return RESULT_SUCCESS;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        LOG_ERROR(Service_GSP, "Out of range size 0x%08x", size_in_bytes);
 | 
				
			||||||
 | 
					        return ERR_GSP_REGS_INVALID_SIZE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Updates sequential GSP GPU hardware registers using parallel arrays of source data and masks.
 | 
				
			||||||
 | 
					 * For each register, the value is updated only where the mask is high
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * @param base_address The address of the first register in the sequence
 | 
				
			||||||
 | 
					 * @param size_in_bytes The number of registers to update (size of data)
 | 
				
			||||||
 | 
					 * @param data A pointer to the source data to use for updates
 | 
				
			||||||
 | 
					 * @param masks A pointer to the masks
 | 
				
			||||||
 | 
					 * @return RESULT_SUCCESS if the parameters are valid, error code otherwise
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					static ResultCode WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* data, const u32* masks) {
 | 
				
			||||||
 | 
					    // This magic number is verified to be done by the gsp module
 | 
				
			||||||
 | 
					    const u32 max_size_in_bytes = 0x80;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (base_address & 3 || base_address >= 0x420000) {
 | 
				
			||||||
 | 
					        LOG_ERROR(Service_GSP, "Write address was out of range or misaligned! (address=0x%08x, size=0x%08x)",
 | 
				
			||||||
 | 
					                  base_address, size_in_bytes);
 | 
				
			||||||
 | 
					        return ERR_GSP_REGS_OUTOFRANGE_OR_MISALIGNED;
 | 
				
			||||||
 | 
					    } else if (size_in_bytes <= max_size_in_bytes) {
 | 
				
			||||||
 | 
					        if (size_in_bytes & 3) {
 | 
				
			||||||
 | 
					            LOG_ERROR(Service_GSP, "Misaligned size 0x%08x", size_in_bytes);
 | 
				
			||||||
 | 
					            return ERR_GSP_REGS_MISALIGNED;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            while (size_in_bytes > 0) {
 | 
				
			||||||
 | 
					                const u32 reg_address = base_address + REGS_BEGIN;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                u32 reg_value;
 | 
				
			||||||
 | 
					                HW::Read<u32>(reg_value, reg_address);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                // Update the current value of the register only for set mask bits
 | 
				
			||||||
 | 
					                reg_value = (reg_value & ~*masks) | (*data | *masks);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                HW::Write<u32>(reg_address, reg_value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                size_in_bytes -= 4;
 | 
				
			||||||
 | 
					                ++data;
 | 
				
			||||||
 | 
					                ++masks;
 | 
				
			||||||
 | 
					                base_address += 4;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return RESULT_SUCCESS;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					        LOG_ERROR(Service_GSP, "Out of range size 0x%08x", size_in_bytes);
 | 
				
			||||||
 | 
					        return ERR_GSP_REGS_INVALID_SIZE;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -120,39 +167,7 @@ static void WriteHWRegs(Service::Interface* self) {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    u32* src = (u32*)Memory::GetPointer(cmd_buff[4]);
 | 
					    u32* src = (u32*)Memory::GetPointer(cmd_buff[4]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WriteHWRegs(reg_addr, size, src);
 | 
					    cmd_buff[1] = WriteHWRegs(reg_addr, size, src).raw;
 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/**
 | 
					 | 
				
			||||||
 * Updates sequential GSP GPU hardware registers using parallel arrays of source data and masks.
 | 
					 | 
				
			||||||
 * For each register, the value is updated only where the mask is high
 | 
					 | 
				
			||||||
 *
 | 
					 | 
				
			||||||
 * @param base_address The address of the first register in the sequence
 | 
					 | 
				
			||||||
 * @param size_in_bytes The number of registers to update (size of data)
 | 
					 | 
				
			||||||
 * @param data A pointer to the source data to use for updates
 | 
					 | 
				
			||||||
 * @param masks A pointer to the masks
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
static void WriteHWRegsWithMask(u32 base_address, u32 size_in_bytes, const u32* data, const u32* masks) {
 | 
					 | 
				
			||||||
    // TODO: Return proper error codes
 | 
					 | 
				
			||||||
    if (!CheckWriteParameters(base_address, size_in_bytes))
 | 
					 | 
				
			||||||
        return;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    while (size_in_bytes > 0) {
 | 
					 | 
				
			||||||
        const u32 reg_address = base_address + REGS_BEGIN;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        u32 reg_value;
 | 
					 | 
				
			||||||
        HW::Read<u32>(reg_value, reg_address);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // Update the current value of the register only for set mask bits
 | 
					 | 
				
			||||||
        reg_value = (reg_value & ~*masks) | (*data | *masks);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        HW::Write<u32>(reg_address, reg_value);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        size_in_bytes -= 4;
 | 
					 | 
				
			||||||
        ++data;
 | 
					 | 
				
			||||||
        ++masks;
 | 
					 | 
				
			||||||
        base_address += 4;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -174,7 +189,7 @@ static void WriteHWRegsWithMask(Service::Interface* self) {
 | 
				
			|||||||
    u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]);
 | 
					    u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]);
 | 
				
			||||||
    u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]);
 | 
					    u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    WriteHWRegsWithMask(reg_addr, size, src_data, mask_data);
 | 
					    cmd_buff[1] = WriteHWRegsWithMask(reg_addr, size, src_data, mask_data).raw;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Read a GSP GPU hardware register
 | 
					/// Read a GSP GPU hardware register
 | 
				
			||||||
@ -206,27 +221,27 @@ static void ReadHWRegs(Service::Interface* self) {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
 | 
					ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
 | 
				
			||||||
    u32 base_address = 0x400000;
 | 
					    u32 base_address = 0x400000;
 | 
				
			||||||
    PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
 | 
					    PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
 | 
				
			||||||
    PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
 | 
					    PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
 | 
				
			||||||
    if (info.active_fb == 0) {
 | 
					    if (info.active_fb == 0) {
 | 
				
			||||||
        WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4,
 | 
					        WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)),
 | 
				
			||||||
                &phys_address_left);
 | 
					                    4, &phys_address_left);
 | 
				
			||||||
        WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4,
 | 
					        WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)),
 | 
				
			||||||
                &phys_address_right);
 | 
					                    4, &phys_address_right);
 | 
				
			||||||
    } else {
 | 
					    } else {
 | 
				
			||||||
        WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4,
 | 
					        WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)),
 | 
				
			||||||
                &phys_address_left);
 | 
					                    4, &phys_address_left);
 | 
				
			||||||
        WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4,
 | 
					        WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)),
 | 
				
			||||||
                &phys_address_right);
 | 
					                    4, &phys_address_right);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4,
 | 
					    WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)),
 | 
				
			||||||
            &info.stride);
 | 
					                4, &info.stride);
 | 
				
			||||||
    WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4,
 | 
					    WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)),
 | 
				
			||||||
            &info.format);
 | 
					                4, &info.format);
 | 
				
			||||||
    WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4,
 | 
					    WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)),
 | 
				
			||||||
            &info.shown_fb);
 | 
					                4, &info.shown_fb);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (Pica::g_debug_context)
 | 
					    if (Pica::g_debug_context)
 | 
				
			||||||
        Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr);
 | 
					        Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr);
 | 
				
			||||||
@ -234,6 +249,8 @@ void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
 | 
				
			|||||||
    if (screen_id == 0) {
 | 
					    if (screen_id == 0) {
 | 
				
			||||||
        MicroProfileFlip();
 | 
					        MicroProfileFlip();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return RESULT_SUCCESS;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
@ -251,9 +268,8 @@ static void SetBufferSwap(Service::Interface* self) {
 | 
				
			|||||||
    u32* cmd_buff = Kernel::GetCommandBuffer();
 | 
					    u32* cmd_buff = Kernel::GetCommandBuffer();
 | 
				
			||||||
    u32 screen_id = cmd_buff[1];
 | 
					    u32 screen_id = cmd_buff[1];
 | 
				
			||||||
    FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2];
 | 
					    FrameBufferInfo* fb_info = (FrameBufferInfo*)&cmd_buff[2];
 | 
				
			||||||
    SetBufferSwap(screen_id, *fb_info);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    cmd_buff[1] = 0; // No error
 | 
					    cmd_buff[1] = SetBufferSwap(screen_id, *fb_info).raw;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 | 
				
			|||||||
@ -194,7 +194,7 @@ public:
 | 
				
			|||||||
 */
 | 
					 */
 | 
				
			||||||
void SignalInterrupt(InterruptId interrupt_id);
 | 
					void SignalInterrupt(InterruptId interrupt_id);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info);
 | 
					ResultCode SetBufferSwap(u32 screen_id, const FrameBufferInfo& info);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Retrieves the framebuffer info stored in the GSP shared memory for the
 | 
					 * Retrieves the framebuffer info stored in the GSP shared memory for the
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user