Merge pull request #20114 from hrydgard/more-atrac-prep

Fix sceUtilityLoadModuleAv, allow browsing memory tags in the memory viewer
This commit is contained in:
Henrik Rydgård authored and GitHub committed 2025-03-15 18:25:40 +01:00
commit 60a2dd12bc
6 files changed
+121 -62

No files matched your search

+11 -2
View File
@@ -95,7 +95,11 @@ const AtracBase *__AtracGetCtx(int i, u32 *type) {
void __AtracInit() {
_assert_(sizeof(SceAtracContext) == 256);
atracInited = true;
atracLibVersion = 0;
atracLibCrc = 0;
atracInited = true; // TODO: This should probably only happen in __AtracNotifyLoadModule.
memset(atracContexts, 0, sizeof(atracContexts));
// Start with 2 of each in this order.
@@ -114,13 +118,18 @@ void __AtracShutdown() {
}
}
void __AtracLoadModule(int version, u32 crc, u32 bssAddr, int bssSize) {
void __AtracNotifyLoadModule(int version, u32 crc, u32 bssAddr, int bssSize) {
atracLibVersion = version;
atracLibCrc = crc;
INFO_LOG(Log::ME, "Atrac module loaded: atracLibVersion 0x%0x, atracLibcrc %x, bss: %x (%x bytes)", atracLibVersion, atracLibCrc, bssAddr, bssSize);
// Later, save bssAddr/bssSize and use them to return context addresses.
}
void __AtracNotifyUnloadModule() {
atracLibVersion = 0;
atracLibCrc = 0;
}
void __AtracDoState(PointerWrap &p) {
auto s = p.Section("sceAtrac", 1, 2);
if (!s)
+3 -1
View File
@@ -25,7 +25,9 @@ void Register_sceAtrac3plus();
void __AtracInit();
void __AtracDoState(PointerWrap &p);
void __AtracShutdown();
void __AtracLoadModule(int version, u32 crc, u32 bssAddr, int bssSize);
void __AtracNotifyLoadModule(int version, u32 crc, u32 bssAddr, int bssSize);
void __AtracNotifyUnloadModule();
enum AtracStatus : u8 {
ATRAC_STATUS_NO_DATA = 1,
+9 -6
View File
@@ -277,8 +277,9 @@ public:
const char *GetTypeName() override { return GetStaticTypeName(); }
static const char *GetStaticTypeName() { return "Module"; }
void GetQuickInfo(char *ptr, int size) override {
snprintf(ptr, size, "%sname=%s gp=%08x entry=%08x",
isFake ? "faked " : "",
snprintf(ptr, size, "%d.%d %sname=%s gp=%08x entry=%08x",
nm.version[1], nm.version[0],
isFake ? "(faked) " : "",
nm.name,
nm.gp_value,
nm.entry_addr);
@@ -480,7 +481,8 @@ public:
void PSPModule::GetLongInfo(char *ptr, int bufSize) const {
StringWriter w(ptr, bufSize);
w.F("%s: Version %d.%d. %d segments", nm.name, nm.version[0], nm.version[1], nm.nsegment).endl();
w.F("%s: Version %d.%d. %d segments", nm.name, nm.version[1], nm.version[0], nm.nsegment).endl();
w.F("Memory block: %08x (%08x/%d bytes)", memoryBlockAddr, memoryBlockSize, memoryBlockSize).endl();
for (int i = 0; i < nm.nsegment; i++) {
w.F(" %08x (%08x bytes)\n", nm.segmentaddr[i], nm.segmentsize[i]);
}
@@ -1340,7 +1342,6 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load
strncpy(module->nm.name, head->modname, ARRAY_SIZE(module->nm.name));
module->nm.entry_addr = -1;
module->nm.gp_value = -1;
module->nm.bss_size = head->bss_size;
// Let's still try to allocate it. It may use user memory.
u32 totalSize = 0;
@@ -1367,6 +1368,8 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load
module->memoryBlockAddr = addr;
module->memoryBlockSize = totalSize;
module->nm.text_addr = addr;
module->nm.bss_size = head->bss_size;
module->nm.nsegment = head->nsegments;
module->nm.version[0] = head->module_ver_hi;
module->nm.version[1] = head->module_ver_lo;
@@ -1389,7 +1392,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load
__PsmfPlayerLoadModule(devkitVersion, module->crc);
}
if (!strcmp(head->modname, "sceATRAC3plus_Library")) {
__AtracLoadModule(ver, module->crc, module->GetBSSAddr(), head->bss_size);
__AtracNotifyLoadModule(ver, module->crc, module->GetBSSAddr(), head->bss_size);
}
return module;
@@ -1775,7 +1778,7 @@ static PSPModule *__KernelLoadELFFromPtr(const u8 *ptr, size_t elfSize, u32 load
__PsmfPlayerLoadModule(devkitVersion, module->crc);
}
if (!strcmp(modinfo->name, "sceATRAC3plus_Library")) {
__AtracLoadModule(modinfo->moduleVersion, module->crc, module->GetBSSAddr(), module->nm.bss_size);
__AtracNotifyLoadModule(modinfo->moduleVersion, module->crc, module->GetBSSAddr(), module->nm.bss_size);
}
}
+59 -37
View File
@@ -87,7 +87,10 @@ static void NotifyLoadStatusAtrac(int state, u32 loadAddr, u32 totalSize) {
constexpr int version = 0x103;
constexpr int bssSize = 0x67C;
_dbg_assert_(bssSize <= totalSize);
__AtracLoadModule(version, 0, loadAddr, bssSize);
__AtracNotifyLoadModule(version, 0, loadAddr, bssSize);
} else if (state == -1) {
// Unload.
__AtracNotifyUnloadModule();
}
}
@@ -105,31 +108,31 @@ static const ModuleLoadInfo moduleLoadInfo[] = {
ModuleLoadInfo(0x104, 0x00002000, "net_parse_http"),
ModuleLoadInfo(0x105, 0x00028000, "net_http", httpModuleDeps),
ModuleLoadInfo(0x106, 0x00044000, "net_ssl", sslModuleDeps),
ModuleLoadInfo(0x107, 0x00010000, "0x107"),
ModuleLoadInfo(0x107, 0x00010000, "unk_0x107"),
ModuleLoadInfo(0x108, 0x00008000, "usb_pspcm", httpStorageModuleDeps),
ModuleLoadInfo(0x200, 0x00000000, "usb_mic"),
ModuleLoadInfo(0x201, 0x00000000, "usb_cam"),
ModuleLoadInfo(0x202, 0x00000000, "usb_gps"),
ModuleLoadInfo(0x203, 0x00000000, "0x203"),
ModuleLoadInfo(0x2ff, 0x00000000, "0x2ff"),
ModuleLoadInfo(0x203, 0x00000000, "usb_unk_0x203"),
ModuleLoadInfo(0x2ff, 0x00000000, "unk_0x2ff"),
ModuleLoadInfo(0x300, 0x00000000, "av_avcodec", &NotifyLoadStatusAvcodec),
ModuleLoadInfo(0x301, 0x00000000, "av_sascore"),
ModuleLoadInfo(0x302, 0x00008000, "av_atrac3plus", atrac3PlusModuleDeps, &NotifyLoadStatusAtrac), // TODO: 0x8000 is likely too large.
ModuleLoadInfo(0x302, 0x00004000, "av_atrac3plus", atrac3PlusModuleDeps, &NotifyLoadStatusAtrac), // TODO: 0x8000 is likely too large.
ModuleLoadInfo(0x303, 0x0000c000, "av_mpegbase", mpegBaseModuleDeps),
ModuleLoadInfo(0x304, 0x00004000, "av_mp3"),
ModuleLoadInfo(0x305, 0x0000a300, "av_vaudio"),
ModuleLoadInfo(0x306, 0x00004000, "av_aac"),
ModuleLoadInfo(0x307, 0x00000000, "av_g729"),
ModuleLoadInfo(0x308, 0x0003c000, "av_", mp4ModuleDeps),
ModuleLoadInfo(0x308, 0x0003c000, "av_mp4", mp4ModuleDeps),
ModuleLoadInfo(0x3fe, 0x00000000, "me_stuff"),
ModuleLoadInfo(0x3ff, 0x00000000, "me_core"), // ME Core?
ModuleLoadInfo(0x400, 0x0000c000, "np_common"),
ModuleLoadInfo(0x401, 0x00018000, "np_service"),
ModuleLoadInfo(0x402, 0x00048000, "np_matching2"),
ModuleLoadInfo(0x403, 0x0000e000, "0x403"),
ModuleLoadInfo(0x403, 0x0000e000, "np_unk_0x403"),
ModuleLoadInfo(0x500, 0x00000000, "np_drm"),
ModuleLoadInfo(0x600, 0x00000000, "irda"),
ModuleLoadInfo(0x601, 0x00000000, "0x601"),
ModuleLoadInfo(0x601, 0x00000000, "unk_0x601"),
};
// Only a single dialog is allowed at a time.
@@ -508,6 +511,9 @@ bool __UtilityModuleGetMemoryRange(int moduleID, u32 *startPtr, u32 *sizePtr) {
return true;
}
static int LoadModuleInternal(u32 module);
static int UnloadModuleInternal(u32 module);
// Same as sceUtilityLoadModule, just limited in categories.
// It seems this just loads module 0x300 + module & 0xFF..
static u32 sceUtilityLoadAvModule(u32 module) {
@@ -516,37 +522,61 @@ static u32 sceUtilityLoadAvModule(u32 module) {
return hleLogError(Log::sceUtility, SCE_ERROR_AV_MODULE_BAD_ID);
}
if (module == 0)
JpegNotifyLoadStatus(1);
return hleDelayResult(hleLogInfo(Log::sceUtility, 0), "utility av module loaded", 25000);
int result = LoadModuleInternal(0x300 | module);
return hleDelayResult(hleLogDebugOrError(Log::sceUtility, result), "utility av module loaded", 25000);
}
static u32 sceUtilityUnloadAvModule(u32 module) {
if (module == 0)
JpegNotifyLoadStatus(-1);
return hleDelayResult(hleLogInfo(Log::sceUtility, 0), "utility av module unloaded", 800);
if (module > 7) {
ERROR_LOG_REPORT(Log::sceUtility, "sceUtilityLoadAvModule(%i): invalid module id", module);
return hleLogError(Log::sceUtility, SCE_ERROR_AV_MODULE_BAD_ID);
}
int result = UnloadModuleInternal(0x300 | module);
return hleDelayResult(hleLogDebugOrError(Log::sceUtility, result), "utility av module unloaded", 800);
}
static u32 sceUtilityLoadModule(u32 module) {
int result = LoadModuleInternal(module);
// TODO: Each module has its own timing, technically, but this is a low-end.
if (module == 0x3FF) {
return hleDelayResult(hleLogDebugOrError(Log::sceUtility, result), "utility module loaded", 130);
} else {
return hleDelayResult(hleLogDebugOrError(Log::sceUtility, result), "utility module loaded", 25000);
}
}
static u32 sceUtilityUnloadModule(u32 module) {
int result = UnloadModuleInternal(module);
// TODO: Each module has its own timing, technically, but this is a low-end.
if (module == 0x3FF) {
return hleDelayResult(hleLogDebugOrError(Log::sceUtility, result), "utility module unloaded", 110);
} else {
return hleDelayResult(hleLogDebugOrError(Log::sceUtility, result), "utility module unloaded", 400);
}
}
static int LoadModuleInternal(u32 module) {
const ModuleLoadInfo *info = __UtilityModuleInfo(module);
if (!info) {
return hleReportError(Log::sceUtility, SCE_ERROR_MODULE_BAD_ID, "invalid module id");
return SCE_ERROR_MODULE_BAD_ID;
}
if (currentlyLoadedModules.find(module) != currentlyLoadedModules.end()) {
return hleLogError(Log::sceUtility, SCE_ERROR_MODULE_ALREADY_LOADED, "already loaded");
return SCE_ERROR_MODULE_ALREADY_LOADED;
}
// Some games, like Kamen Rider Climax Heroes OOO, require an error if dependencies aren't loaded yet.
for (const int *dep = info->dependencies; *dep != 0; ++dep) {
if (currentlyLoadedModules.find(*dep) == currentlyLoadedModules.end()) {
return hleDelayResult(hleLogError(Log::sceUtility, SCE_KERNEL_ERROR_LIBRARY_NOTFOUND, "dependent module %04x not loaded", *dep), "utility module load attempt", 25000);
return SCE_KERNEL_ERROR_LIBRARY_NOTFOUND;
}
}
u32 allocSize = info->size;
u32 address = 0;
char name[128];
snprintf(name, sizeof(name), "UtilityModule/%x", module);
snprintf(name, sizeof(name), "UtilityModule/%3x_%s", module, info->name);
if (allocSize != 0) {
address = userMemory.Alloc(allocSize, false, name);
}
@@ -554,36 +584,28 @@ static u32 sceUtilityLoadModule(u32 module) {
if (info->notify) {
info->notify(1, address, allocSize);
}
// TODO: Each module has its own timing, technically, but this is a low-end.
if (module == 0x3FF)
return hleDelayResult(hleLogInfo(Log::sceUtility, 0), "utility module loaded", 130);
else
return hleDelayResult(hleLogInfo(Log::sceUtility, 0), "utility module loaded", 25000);
return 0;
}
static u32 sceUtilityUnloadModule(u32 module) {
static int UnloadModuleInternal(u32 module) {
const ModuleLoadInfo *info = __UtilityModuleInfo(module);
if (!info) {
return hleReportError(Log::sceUtility, SCE_ERROR_MODULE_BAD_ID, "invalid module id");
return SCE_ERROR_MODULE_BAD_ID;
}
if (currentlyLoadedModules.find(module) == currentlyLoadedModules.end()) {
return hleLogWarning(Log::sceUtility, SCE_ERROR_MODULE_NOT_LOADED, "not yet loaded");
auto iter = currentlyLoadedModules.find(module);
if (iter == currentlyLoadedModules.end()) {
return SCE_ERROR_MODULE_NOT_LOADED;
}
if (currentlyLoadedModules[module] != 0) {
userMemory.Free(currentlyLoadedModules[module]);
if (iter->second != 0) {
userMemory.Free(iter->second);
}
currentlyLoadedModules.erase(module);
if (info->notify)
if (info->notify) {
info->notify(-1, 0, 0);
// TODO: Each module has its own timing, technically, but this is a low-end.
if (module == 0x3FF)
return hleDelayResult(hleLogInfo(Log::sceUtility, 0), "utility module unloaded", 110);
else
return hleDelayResult(hleLogInfo(Log::sceUtility, 0), "utility module unloaded", 400);
}
return 0;
}
static int sceUtilityMsgDialogInitStart(u32 paramAddr) {
+38 -16
View File
@@ -10,6 +10,7 @@
#include "Common/Log/LogManager.h"
#include "Core/Config.h"
#include "Core/System.h"
#include "Core/Debugger/MemBlockInfo.h"
#include "Core/RetroAchievements.h"
#include "Core/Core.h"
#include "Core/Debugger/DebugInterface.h"
@@ -21,7 +22,6 @@
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/Debugger/SymbolMap.h"
#include "Core/MemMap.h"
#include "Core/System.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/SocketManager.h"
#include "Core/HLE/NetInetConstants.h"
@@ -1575,6 +1575,10 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
}
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Core")) {
ImGui::MenuItem("Scheduler", nullptr, &cfg_.schedulerOpen);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("CPU")) {
ImGui::MenuItem("CPU debugger", nullptr, &cfg_.disasmOpen);
ImGui::MenuItem("GPR regs", nullptr, &cfg_.gprOpen);
@@ -1582,8 +1586,9 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
ImGui::MenuItem("VFPU regs", nullptr, &cfg_.vfpuOpen);
ImGui::MenuItem("Callstacks", nullptr, &cfg_.callstackOpen);
ImGui::MenuItem("Breakpoints", nullptr, &cfg_.breakpointsOpen);
ImGui::MenuItem("Scheduler", nullptr, &cfg_.schedulerOpen);
ImGui::Separator();
ImGui::EndMenu();
}
if (ImGui::BeginMenu("Memory")) {
for (int i = 0; i < 4; i++) {
char title[64];
snprintf(title, sizeof(title), "Memory %d", i + 1);
@@ -1592,7 +1597,7 @@ void ImDebugger::Frame(MIPSDebugInterface *mipsDebug, GPUDebugInterface *gpuDebu
ImGui::MenuItem("Memory Dumper", nullptr, &cfg_.memDumpOpen);
ImGui::EndMenu();
}
if (ImGui::BeginMenu("HLE")) {
if (ImGui::BeginMenu("OS HLE")) {
ImGui::MenuItem("File System Browser", nullptr, &cfg_.filesystemBrowserOpen);
ImGui::MenuItem("Kernel Objects", nullptr, &cfg_.kernelObjectsOpen);
ImGui::MenuItem("Threads", nullptr, &cfg_.threadsOpen);
@@ -1852,21 +1857,38 @@ void ImMemWindow::Draw(MIPSDebugInterface *mipsDebug, ImConfig &cfg, ImControl &
ImVec2 size(0, -ImGui::GetFrameHeightWithSpacing());
auto node = [&](const char *title, uint32_t start, uint32_t len) {
if (ImGui::TreeNode(title)) {
if (ImGui::Selectable("(start)", cfg.selectedMemoryBlock == start)) {
cfg.selectedMemoryBlock = start;
GotoAddr(start);
}
const std::vector<MemBlockInfo> info = FindMemInfo(start, len);
for (auto &iter : info) {
ImGui::PushID(iter.start);
if (ImGui::Selectable(iter.tag.c_str(), cfg.selectedMemoryBlock == iter.start)) {
cfg.selectedMemoryBlock = iter.start;
GotoAddr(iter.start);
}
ImGui::PopID();
}
const u32 end = start + len;
if (ImGui::Selectable("(end)", cfg.selectedMemoryBlock == end)) {
cfg.selectedMemoryBlock = end;
GotoAddr(end);
}
ImGui::TreePop();
}
};
// Main views - list of interesting addresses to the left, memory view to the right.
if (ImGui::BeginChild("addr_list", ImVec2(200.0f, size.y), ImGuiChildFlags_ResizeX)) {
if (ImGui::Selectable("Scratch")) {
GotoAddr(0x00010000);
}
if (ImGui::Selectable("Kernel RAM")) {
GotoAddr(0x08000000);
}
if (ImGui::Selectable("User RAM")) {
GotoAddr(0x08800000);
}
if (ImGui::Selectable("VRAM")) {
GotoAddr(0x04000000);
}
node("Scratch", 0x00010000, 0x00004000);
node("Kernel RAM", 0x08000000, 0x00800000);
node("User RAM" , 0x08800000, 0x01800000);
node("VRAM", 0x04000000, 0x00200000);
}
ImGui::EndChild();
ImGui::SameLine();
+1
View File
@@ -164,6 +164,7 @@ struct ImConfig {
int selectedBreakpoint = -1;
int selectedMemCheck = -1;
int selectedAtracCtx = 0;
u32 selectedMemoryBlock = 0;
uint64_t selectedTexAddr = 0;
bool realtimePixelPreview = false;