mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 13:30:02 +00:00
Merge remote-tracking branch 'origin/master' into armjit
Conflicts: Core/HLE/sceKernelThread.cpp
This commit is contained in:
commit
789c4781c0
@ -177,8 +177,6 @@ elseif(X86)
|
||||
Common/ABI.h
|
||||
Common/CPUDetect.cpp
|
||||
Common/CPUDetect.h
|
||||
Common/MathUtil.cpp
|
||||
Common/MathUtil.h
|
||||
Common/Thunk.cpp
|
||||
Common/Thunk.h
|
||||
Common/x64Analyzer.cpp
|
||||
@ -220,6 +218,8 @@ add_library(Common STATIC
|
||||
Common/IniFile.h
|
||||
Common/LogManager.cpp
|
||||
Common/LogManager.h
|
||||
Common/MathUtil.cpp
|
||||
Common/MathUtil.h
|
||||
Common/MemArena.cpp
|
||||
Common/MemArena.h
|
||||
Common/MemoryUtil.cpp
|
||||
|
@ -22,6 +22,10 @@
|
||||
#include <assert.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __SYMBIAN32__
|
||||
#include <e32std.h>
|
||||
#endif
|
||||
|
||||
namespace ArmGen
|
||||
{
|
||||
|
||||
@ -61,7 +65,11 @@ const u8 *ARMXEmitter::AlignCodePage()
|
||||
|
||||
void ARMXEmitter::FlushIcache()
|
||||
{
|
||||
#ifdef __SYMBIAN32__
|
||||
User::IMB_Range( startcode, code );
|
||||
#else
|
||||
__builtin___clear_cache (startcode, code);
|
||||
#endif
|
||||
SLEEP(0);
|
||||
}
|
||||
void ARMXEmitter::SetCC(CCFlags cond)
|
||||
@ -536,4 +544,4 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -261,7 +261,7 @@ public:
|
||||
case MODE_READ: x = (wchar_t*)*ptr; break;
|
||||
case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
|
||||
case MODE_MEASURE: break;
|
||||
case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break;
|
||||
case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break;
|
||||
}
|
||||
(*ptr) += stringLen;
|
||||
}
|
||||
|
@ -45,6 +45,12 @@
|
||||
#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK))
|
||||
#endif
|
||||
|
||||
#ifdef __SYMBIAN32__
|
||||
#include <e32std.h>
|
||||
#define SYMBIAN_CODECHUNCK_SIZE 1024*1024*17;
|
||||
static RChunk* g_code_chunk = NULL;
|
||||
static RHeap* g_code_heap = NULL;
|
||||
#endif
|
||||
|
||||
// This is purposely not a full wrapper for virtualalloc/mmap, but it
|
||||
// provides exactly the primitive operations that Dolphin needs.
|
||||
@ -54,9 +60,16 @@ void* AllocateExecutableMemory(size_t size, bool low)
|
||||
#if defined(_WIN32)
|
||||
void* ptr = VirtualAlloc(0, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||
#elif defined(__SYMBIAN32__)
|
||||
// On Symbian, we will need to create an RChunk and allocate with ->CreateLocalCode(size, size);
|
||||
static char *map_hint = 0;
|
||||
void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, -1, 0);
|
||||
//This function may be called more than once, and we want to create only one big
|
||||
//memory chunck for all the executable code for the JIT
|
||||
if( g_code_chunk == NULL && g_code_heap == NULL)
|
||||
{
|
||||
TInt minsize = SYMBIAN_CODECHUNCK_SIZE;
|
||||
TInt maxsize = SYMBIAN_CODECHUNCK_SIZE + 3*4096; //some offsets
|
||||
g_code_chunk->CreateLocalCode(minsize, maxsize);
|
||||
g_code_heap = UserHeap::ChunkHeap(*g_code_chunk, minsize, 1, maxsize);
|
||||
}
|
||||
void* ptr = (void*) g_code_heap->Alloc( size );
|
||||
#else
|
||||
static char *map_hint = 0;
|
||||
#if defined(__x86_64__) && !defined(MAP_32BIT)
|
||||
@ -143,7 +156,8 @@ void* AllocateAlignedMemory(size_t size,size_t alignment)
|
||||
// On Symbian, we will want to create an RChunk.
|
||||
ptr = malloc(size);
|
||||
#else
|
||||
posix_memalign(&ptr, alignment, size);
|
||||
if(posix_memalign(&ptr, alignment, size) != 0)
|
||||
ptr = NULL;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
@ -55,25 +55,30 @@ std::string StringFromFormat(const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
char *buf = NULL;
|
||||
std::string temp = "";
|
||||
#ifdef _WIN32
|
||||
int required = 0;
|
||||
|
||||
va_start(args, format);
|
||||
required = _vscprintf(format, args);
|
||||
buf = new char[required + 1];
|
||||
vsnprintf(buf, required, format, args);
|
||||
if(vsnprintf(buf, required, format, args) < 0)
|
||||
buf[0] = '\0';
|
||||
va_end(args);
|
||||
|
||||
buf[required] = '\0';
|
||||
std::string temp = buf;
|
||||
temp = buf;
|
||||
delete[] buf;
|
||||
#else
|
||||
va_start(args, format);
|
||||
vasprintf(&buf, format, args);
|
||||
if(vasprintf(&buf, format, args) < 0)
|
||||
buf = NULL;
|
||||
va_end(args);
|
||||
|
||||
std::string temp = buf;
|
||||
free(buf);
|
||||
if(buf != NULL) {
|
||||
temp = buf;
|
||||
free(buf);
|
||||
}
|
||||
#endif
|
||||
return temp;
|
||||
}
|
||||
|
@ -143,7 +143,10 @@ bool SymbolMap::LoadSymbolMap(const char *filename)
|
||||
while (!feof(f))
|
||||
{
|
||||
char line[512],temp[256];
|
||||
fgets(line,511,f);
|
||||
char *p = fgets(line,512,f);
|
||||
if(p == NULL)
|
||||
break;
|
||||
|
||||
if (strlen(line) < 4 || sscanf(line, "%s", temp) != 1)
|
||||
continue;
|
||||
|
||||
|
@ -123,7 +123,7 @@ void PSPOskDialog::RenderKeyboard()
|
||||
else
|
||||
temp[0] = '_';
|
||||
|
||||
PPGeDrawText(temp, previewLeftSide + (i * 16.0f), 40.0f, NULL, 0.5f, color);
|
||||
PPGeDrawText(temp, previewLeftSide + (i * 16.0f), 40.0f, 0, 0.5f, color);
|
||||
}
|
||||
for (int row = 0; row < NUMKEYROWS; ++row)
|
||||
{
|
||||
@ -134,10 +134,10 @@ void PSPOskDialog::RenderKeyboard()
|
||||
color = 0xFF7f7f7f;
|
||||
|
||||
temp[0] = oskKeys[row][col];
|
||||
PPGeDrawText(temp, keyboardLeftSide + (25.0f * col), 70.0f + (25.0f * row), NULL, 0.6f, color);
|
||||
PPGeDrawText(temp, keyboardLeftSide + (25.0f * col), 70.0f + (25.0f * row), 0, 0.6f, color);
|
||||
|
||||
if (selectedRow == row && col == selectedExtra)
|
||||
PPGeDrawText("_", keyboardLeftSide + (25.0f * col), 70.0f + (25.0f * row), NULL, 0.6f, 0xFFFFFFFF);
|
||||
PPGeDrawText("_", keyboardLeftSide + (25.0f * col), 70.0f + (25.0f * row), 0, 0.6f, 0xFFFFFFFF);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,9 @@ FileBlockDevice::~FileBlockDevice()
|
||||
bool FileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
|
||||
{
|
||||
fseek(f, blockNumber * GetBlockSize(), SEEK_SET);
|
||||
fread(outPtr, 2048, 1, f);
|
||||
if(fread(outPtr, 1, 2048, f) != 2048)
|
||||
DEBUG_LOG(LOADER, "Could not read 2048 bytes from block");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -80,10 +82,10 @@ CISOFileBlockDevice::CISOFileBlockDevice(std::string _filename)
|
||||
|
||||
f = fopen(_filename.c_str(), "rb");
|
||||
CISO_H hdr;
|
||||
fread(&hdr, 1, sizeof(CISO_H), f);
|
||||
if (memcmp(hdr.magic, "CISO", 4) != 0)
|
||||
size_t readSize = fread(&hdr, sizeof(CISO_H), 1, f);
|
||||
if (readSize != 1 || memcmp(hdr.magic, "CISO", 4) != 0)
|
||||
{
|
||||
//ARGH!
|
||||
WARN_LOG(LOADER, "Invalid CSO!");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -109,7 +111,8 @@ CISOFileBlockDevice::CISOFileBlockDevice(std::string _filename)
|
||||
int indexSize = numBlocks + 1;
|
||||
|
||||
index = new u32[indexSize];
|
||||
fread(index, 4, indexSize, f);
|
||||
if(fread(index, sizeof(u32), indexSize, f) != indexSize)
|
||||
memset(index, 0, indexSize * sizeof(u32));
|
||||
}
|
||||
|
||||
CISOFileBlockDevice::~CISOFileBlockDevice()
|
||||
@ -134,12 +137,12 @@ bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
|
||||
u32 compressedReadSize = idx2 - idx;
|
||||
|
||||
fseek(f, compressedReadPos, SEEK_SET);
|
||||
fread(inbuffer, compressedReadSize, 1, f);
|
||||
size_t readSize = fread(inbuffer, 1, compressedReadSize, f);
|
||||
|
||||
if (plain)
|
||||
{
|
||||
memset(outPtr, 0, 2048);
|
||||
memcpy(outPtr, inbuffer, compressedReadSize);
|
||||
memcpy(outPtr, inbuffer, readSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -152,7 +155,7 @@ bool CISOFileBlockDevice::ReadBlock(int blockNumber, u8 *outPtr)
|
||||
ERROR_LOG(LOADER, "deflateInit ERROR : %s\n", (z.msg) ? z.msg : "???");
|
||||
return 1;
|
||||
}
|
||||
z.avail_in = compressedReadSize;
|
||||
z.avail_in = readSize;
|
||||
z.next_out = outPtr;
|
||||
z.avail_out = blockSize;
|
||||
z.next_in = inbuffer;
|
||||
|
@ -201,6 +201,11 @@ template<u32 func(u32, int , int , int, int, int)> void WrapU_UIIIII() {
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int , int , int, u32)> void WrapU_UIIIU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int , int , int, int, int, int)> void WrapU_UIIIIII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5), PARAM(6));
|
||||
RETURN(retval);
|
||||
@ -211,6 +216,11 @@ template<u32 func(u32, u32)> void WrapU_UU() {
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, int)> void WrapU_UUI() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(const char *, u32, u32, u32)> void WrapU_CUUU() {
|
||||
u32 retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
@ -225,6 +235,11 @@ template<u32 func(u32, int, u32, int, int)> void WrapU_UIUII() {
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int, u32, u32)> void WrapU_UIUU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, int, int)> void WrapU_UII() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2));
|
||||
RETURN(retval);
|
||||
@ -439,6 +454,11 @@ template<u32 func(u32, u32, u32, int)> void WrapU_UUUI() {
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, u32, int, u32)> void WrapU_UUUIU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3), PARAM(4));
|
||||
RETURN(retval);
|
||||
}
|
||||
|
||||
template<u32 func(u32, u32, int, u32)> void WrapU_UUIU() {
|
||||
u32 retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3));
|
||||
RETURN(retval);
|
||||
|
@ -51,6 +51,7 @@ enum
|
||||
|
||||
static std::vector<HLEModule> moduleDB;
|
||||
static std::vector<Syscall> unresolvedSyscalls;
|
||||
static std::vector<Syscall> exportedCalls;
|
||||
static int hleAfterSyscall = HLE_AFTER_NOTHING;
|
||||
static char hleAfterSyscallReschedReason[512];
|
||||
|
||||
@ -63,6 +64,7 @@ void HLEDoState(PointerWrap &p)
|
||||
{
|
||||
Syscall sc = {0};
|
||||
p.Do(unresolvedSyscalls, sc);
|
||||
p.Do(exportedCalls, sc);
|
||||
p.DoMarker("HLE");
|
||||
}
|
||||
|
||||
@ -71,6 +73,7 @@ void HLEShutdown()
|
||||
hleAfterSyscall = HLE_AFTER_NOTHING;
|
||||
moduleDB.clear();
|
||||
unresolvedSyscalls.clear();
|
||||
exportedCalls.clear();
|
||||
}
|
||||
|
||||
void RegisterModule(const char *name, int numFunctions, const HLEFunction *funcTable)
|
||||
@ -124,15 +127,26 @@ const HLEFunction *GetFunc(const char *moduleName, u32 nib)
|
||||
|
||||
const char *GetFuncName(const char *moduleName, u32 nib)
|
||||
{
|
||||
_dbg_assert_msg_(HLE, moduleName != NULL, "Invalid module name.");
|
||||
|
||||
const HLEFunction *func = GetFunc(moduleName,nib);
|
||||
if (func)
|
||||
return func->name;
|
||||
else
|
||||
|
||||
// Was this function exported previously?
|
||||
static char temp[256];
|
||||
for (auto it = exportedCalls.begin(), end = exportedCalls.end(); it != end; ++it)
|
||||
{
|
||||
static char temp[256];
|
||||
sprintf(temp,"[UNK: 0x%08x ]",nib);
|
||||
return temp;
|
||||
if (!strcmp(it->moduleName, moduleName) && it->nid == nib)
|
||||
{
|
||||
sprintf(temp, "[EXP: 0x%08x]", nib);
|
||||
return temp;
|
||||
}
|
||||
}
|
||||
|
||||
// No good, we can't find it.
|
||||
sprintf(temp,"[UNK: 0x%08x]", nib);
|
||||
return temp;
|
||||
}
|
||||
|
||||
u32 GetSyscallOp(const char *moduleName, u32 nib)
|
||||
@ -173,17 +187,34 @@ void WriteSyscall(const char *moduleName, u32 nib, u32 address)
|
||||
}
|
||||
else
|
||||
{
|
||||
// Did another module export this already?
|
||||
for (auto it = exportedCalls.begin(), end = exportedCalls.end(); it != end; ++it)
|
||||
{
|
||||
if (!strcmp(it->moduleName, moduleName) && it->nid == nib)
|
||||
{
|
||||
Memory::Write_U32(MIPS_MAKE_J(it->symAddr), address); // j symAddr
|
||||
Memory::Write_U32(MIPS_MAKE_NOP(), address + 4); // nop (delay slot)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Module inexistent.. for now; let's store the syscall for it to be resolved later
|
||||
INFO_LOG(HLE,"Syscall (%s,%08x) unresolved, storing for later resolving", moduleName, nib);
|
||||
Syscall sysc = {"", address, nib};
|
||||
strncpy(sysc.moduleName, moduleName, 32);
|
||||
sysc.moduleName[31] = '\0';
|
||||
strncpy(sysc.moduleName, moduleName, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
sysc.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
|
||||
unresolvedSyscalls.push_back(sysc);
|
||||
|
||||
// Write a trap so we notice this func if it's called before resolving.
|
||||
Memory::Write_U32(MIPS_MAKE_JR_RA(), address); // jr ra
|
||||
Memory::Write_U32(GetSyscallOp("(invalid syscall)", nib), address + 4);
|
||||
}
|
||||
}
|
||||
|
||||
void ResolveSyscall(const char *moduleName, u32 nib, u32 address)
|
||||
{
|
||||
_dbg_assert_msg_(HLE, moduleName != NULL, "Invalid module name.");
|
||||
|
||||
for (size_t i = 0; i < unresolvedSyscalls.size(); i++)
|
||||
{
|
||||
Syscall *sysc = &unresolvedSyscalls[i];
|
||||
@ -196,6 +227,11 @@ void ResolveSyscall(const char *moduleName, u32 nib, u32 address)
|
||||
Memory::Write_U32(MIPS_MAKE_NOP(), sysc->symAddr + 4);
|
||||
}
|
||||
}
|
||||
|
||||
Syscall ex = {"", address, nib};
|
||||
strncpy(ex.moduleName, moduleName, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
ex.moduleName[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
|
||||
exportedCalls.push_back(ex);
|
||||
}
|
||||
|
||||
const char *GetFuncName(int moduleIndex, int func)
|
||||
|
@ -377,6 +377,7 @@ const HLEFunction sceAtrac3plus[] =
|
||||
{0x9CD7DE03,0,"sceAtracSetMOutHalfwayBufferAndGetID"},
|
||||
{0x5622B7C1,WrapI_UIIU<sceAtracSetAA3DataAndGetID>,"sceAtracSetAA3DataAndGetID"},
|
||||
{0x5DD66588,0,"sceAtracSetAA3HalfwayBufferAndGetID"},
|
||||
{0x231FC6B7,0,"_sceAtracGetContextAddress"},
|
||||
};
|
||||
|
||||
|
||||
|
@ -549,7 +549,7 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0x52089CA1,sceKernelGetThreadStackFreeSize,"sceKernelGetThreadStackFreeSize"},
|
||||
{0xFFC36A14,WrapU_UU<sceKernelReferThreadRunStatus>,"sceKernelReferThreadRunStatus"},
|
||||
{0x17c1684e,WrapU_UU<sceKernelReferThreadStatus>,"sceKernelReferThreadStatus"},
|
||||
{0x2C34E053,0,"sceKernelReleaseWaitThread"},
|
||||
{0x2C34E053,WrapI_I<sceKernelReleaseWaitThread>,"sceKernelReleaseWaitThread"},
|
||||
{0x75156e8f,sceKernelResumeThread,"sceKernelResumeThread"},
|
||||
{0x3ad58b8c,&WrapU_V<sceKernelSuspendDispatchThread>,"sceKernelSuspendDispatchThread"},
|
||||
{0x27e22ec2,&WrapU_U<sceKernelResumeDispatchThread>,"sceKernelResumeDispatchThread"},
|
||||
@ -560,7 +560,7 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0x9944f31f,sceKernelSuspendThread,"sceKernelSuspendThread"},
|
||||
{0x616403ba,WrapI_U<sceKernelTerminateThread>,"sceKernelTerminateThread"},
|
||||
{0x383f7bcc,WrapI_I<sceKernelTerminateDeleteThread>,"sceKernelTerminateDeleteThread"},
|
||||
{0x840E8133,sceKernelWaitThreadEndCB,"sceKernelWaitThreadEndCB"},
|
||||
{0x840E8133,WrapI_IU<sceKernelWaitThreadEndCB>,"sceKernelWaitThreadEndCB"},
|
||||
{0xd13bde95,sceKernelCheckThreadStack,"sceKernelCheckThreadStack"},
|
||||
|
||||
{0x94416130,WrapU_UUUU<sceKernelGetThreadmanIdList>,"sceKernelGetThreadmanIdList"},
|
||||
@ -586,7 +586,7 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0xE1619D7C,sceKernelSysClock2USecWide,"sceKernelSysClock2USecWide"},
|
||||
|
||||
{0x110dec9a,sceKernelUSec2SysClock,"sceKernelUSec2SysClock"},
|
||||
{0x278C0DF5,sceKernelWaitThreadEnd,"sceKernelWaitThreadEnd"},
|
||||
{0x278C0DF5,WrapI_IU<sceKernelWaitThreadEnd>,"sceKernelWaitThreadEnd"},
|
||||
{0xd59ead2f,sceKernelWakeupThread,"sceKernelWakeupThread"}, //AI Go, audio?
|
||||
|
||||
{0x0C106E53,0,"sceKernelRegisterThreadEventHandler"},
|
||||
|
@ -44,6 +44,22 @@ enum {
|
||||
PSP_THREAD_ATTR_USER = 0x80000000
|
||||
};
|
||||
|
||||
enum {
|
||||
// Function exports.
|
||||
NID_MODULE_START = 0xD632ACDB,
|
||||
NID_MODULE_STOP = 0xCEE8593C,
|
||||
NID_MODULE_REBOOT_BEFORE = 0x2F064FA6,
|
||||
NID_MODULE_REBOOT_PHASE = 0xADF12745,
|
||||
NID_MODULE_BOOTSTART = 0xD3744BE0,
|
||||
|
||||
// Variable exports.
|
||||
NID_MODULE_INFO = 0xF01D73A7,
|
||||
NID_MODULE_START_THREAD_PARAMETER = 0x0F7C276C,
|
||||
NID_MODULE_STOP_THREAD_PARAMETER = 0xCF0CC697,
|
||||
NID_MODULE_REBOOT_BEFORE_THREAD_PARAMETER = 0xF4F4299D,
|
||||
NID_MODULE_SDK_VERSION = 0x11B97506,
|
||||
};
|
||||
|
||||
static const char *blacklistedModules[] = {
|
||||
"sceATRAC3plus_Library",
|
||||
"sceFont_Library",
|
||||
@ -229,6 +245,7 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
{
|
||||
Module *module = new Module;
|
||||
kernelObjects.Create(module);
|
||||
memset(&module->nm, 0, sizeof(module->nm));
|
||||
|
||||
u8 *newptr = 0;
|
||||
if (*(u32*)ptr == 0x4543537e) { // "~SCE"
|
||||
@ -464,8 +481,68 @@ Module *__KernelLoadELFFromPtr(const u8 *ptr, u32 loadAddress, std::string *erro
|
||||
{
|
||||
u32 nid = residentPtr[j];
|
||||
u32 exportAddr = residentPtr[ent->fcount + ent->vcount + j];
|
||||
ResolveSyscall(name, nid, exportAddr);
|
||||
|
||||
switch (nid)
|
||||
{
|
||||
case NID_MODULE_START:
|
||||
module->nm.module_start_func = exportAddr;
|
||||
break;
|
||||
case NID_MODULE_STOP:
|
||||
module->nm.module_stop_func = exportAddr;
|
||||
break;
|
||||
case NID_MODULE_REBOOT_BEFORE:
|
||||
module->nm.module_reboot_before_func = exportAddr;
|
||||
break;
|
||||
case NID_MODULE_REBOOT_PHASE:
|
||||
module->nm.module_reboot_phase_func = exportAddr;
|
||||
break;
|
||||
case NID_MODULE_BOOTSTART:
|
||||
module->nm.module_bootstart_func = exportAddr;
|
||||
break;
|
||||
default:
|
||||
ResolveSyscall(name, nid, exportAddr);
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 j = 0; j < ent->vcount; j++)
|
||||
{
|
||||
u32 nid = residentPtr[ent->fcount + j];
|
||||
u32 exportAddr = residentPtr[ent->fcount + ent->vcount + ent->fcount + j];
|
||||
|
||||
switch (nid)
|
||||
{
|
||||
case NID_MODULE_INFO:
|
||||
break;
|
||||
case NID_MODULE_START_THREAD_PARAMETER:
|
||||
if (Memory::Read_U32(exportAddr) != 3)
|
||||
WARN_LOG(LOADER, "Strange value at module_start_thread_parameter export: %08x", Memory::Read_U32(exportAddr));
|
||||
module->nm.module_start_thread_priority = Memory::Read_U32(exportAddr + 4);
|
||||
module->nm.module_start_thread_stacksize = Memory::Read_U32(exportAddr + 8);
|
||||
module->nm.module_start_thread_attr = Memory::Read_U32(exportAddr + 12);
|
||||
break;
|
||||
case NID_MODULE_STOP_THREAD_PARAMETER:
|
||||
if (Memory::Read_U32(exportAddr) != 3)
|
||||
WARN_LOG(LOADER, "Strange value at module_stop_thread_parameter export: %08x", Memory::Read_U32(exportAddr));
|
||||
module->nm.module_stop_thread_priority = Memory::Read_U32(exportAddr + 4);
|
||||
module->nm.module_stop_thread_stacksize = Memory::Read_U32(exportAddr + 8);
|
||||
module->nm.module_stop_thread_attr = Memory::Read_U32(exportAddr + 12);
|
||||
break;
|
||||
case NID_MODULE_REBOOT_BEFORE_THREAD_PARAMETER:
|
||||
if (Memory::Read_U32(exportAddr) != 3)
|
||||
WARN_LOG(LOADER, "Strange value at module_reboot_before_thread_parameter export: %08x", Memory::Read_U32(exportAddr));
|
||||
module->nm.module_reboot_before_thread_priority = Memory::Read_U32(exportAddr + 4);
|
||||
module->nm.module_reboot_before_thread_stacksize = Memory::Read_U32(exportAddr + 8);
|
||||
module->nm.module_reboot_before_thread_attr = Memory::Read_U32(exportAddr + 12);
|
||||
break;
|
||||
case NID_MODULE_SDK_VERSION:
|
||||
DEBUG_LOG(LOADER, "Module SDK: %08x", Memory::Read_U32(exportAddr));
|
||||
break;
|
||||
default:
|
||||
DEBUG_LOG(LOADER, "Unexpected variable with nid: %08x", nid);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ent->size > 4)
|
||||
{
|
||||
ent = (PspLibEntEntry*)((u8*)ent + ent->size * 4);
|
||||
@ -562,6 +639,12 @@ Module *__KernelLoadModule(u8 *fileptr, SceKernelLMOption *options, std::string
|
||||
|
||||
void __KernelStartModule(Module *m, int args, const char *argp, SceKernelSMOption *options)
|
||||
{
|
||||
if (m->nm.module_start_func != 0 || m->nm.module_start_func != -1)
|
||||
{
|
||||
if (m->nm.module_start_func != m->nm.entry_addr)
|
||||
WARN_LOG(LOADER, "Main module has start func (%08x) different from entry (%08x)?", m->nm.module_start_func, m->nm.entry_addr);
|
||||
}
|
||||
|
||||
__KernelSetupRootThread(m->GetUID(), args, argp, options->priority, options->stacksize, options->attribute);
|
||||
mainModuleID = m->GetUID();
|
||||
//TODO: if current thread, put it in wait state, waiting for the new thread
|
||||
@ -621,6 +704,14 @@ bool __KernelLoadExec(const char *filename, SceKernelLoadExecParam *param, std::
|
||||
option.priority = 0x20;
|
||||
option.stacksize = 0x40000; // crazy? but seems to be the truth
|
||||
|
||||
// Replace start options with module-specified values if they exist.
|
||||
if (module->nm.module_start_thread_attr != 0)
|
||||
option.attribute = module->nm.module_start_thread_attr;
|
||||
if (module->nm.module_start_thread_priority != 0)
|
||||
option.priority = module->nm.module_start_thread_priority;
|
||||
if (module->nm.module_start_thread_stacksize != 0)
|
||||
option.stacksize = module->nm.module_start_thread_stacksize;
|
||||
|
||||
__KernelStartModule(module, (u32)strlen(filename) + 1, filename, &option);
|
||||
|
||||
__KernelStartIdleThreads();
|
||||
|
@ -412,7 +412,7 @@ public:
|
||||
// Utils
|
||||
bool isRunning() const { return (nt.status & THREADSTATUS_RUNNING) != 0; }
|
||||
bool isStopped() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
|
||||
bool isReady() const { return (nt.status & THREADSTATUS_DORMANT) != 0; }
|
||||
bool isReady() const { return (nt.status & THREADSTATUS_READY) != 0; }
|
||||
bool isWaiting() const { return (nt.status & THREADSTATUS_WAIT) != 0; }
|
||||
bool isSuspended() const { return (nt.status & THREADSTATUS_SUSPEND) != 0; }
|
||||
|
||||
@ -468,6 +468,7 @@ void __KernelExecuteMipsCallOnCurrentThread(int callId, bool reschedAfter);
|
||||
Thread *__KernelCreateThread(SceUID &id, SceUID moduleID, const char *name, u32 entryPoint, u32 priority, int stacksize, u32 attr);
|
||||
void __KernelResetThread(Thread *t);
|
||||
void __KernelCancelWakeup(SceUID threadID);
|
||||
void __KernelCancelThreadEndTimeout(SceUID threadID);
|
||||
bool __KernelCheckThreadCallbacks(Thread *thread, bool force);
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
@ -485,6 +486,7 @@ std::vector<ThreadCallback> threadEndListeners;
|
||||
SceUID threadIdleID[2];
|
||||
|
||||
int eventScheduledWakeup;
|
||||
int eventThreadEndTimeout;
|
||||
|
||||
bool dispatchEnabled = true;
|
||||
|
||||
@ -570,6 +572,7 @@ u32 __KernelInterruptReturnAddress()
|
||||
}
|
||||
|
||||
void hleScheduledWakeup(u64 userdata, int cyclesLate);
|
||||
void hleThreadEndTimeout(u64 userdata, int cyclesLate);
|
||||
|
||||
void __KernelThreadingInit()
|
||||
{
|
||||
@ -600,6 +603,7 @@ void __KernelThreadingInit()
|
||||
WriteSyscall("FakeSysCalls", NID_INTERRUPTRETURN, intReturnHackAddr);
|
||||
|
||||
eventScheduledWakeup = CoreTiming::RegisterEvent("ScheduledWakeup", &hleScheduledWakeup);
|
||||
eventThreadEndTimeout = CoreTiming::RegisterEvent("ThreadEndTimeout", &hleThreadEndTimeout);
|
||||
actionAfterMipsCall = __KernelRegisterActionType(ActionAfterMipsCall::Create);
|
||||
actionAfterCallback = __KernelRegisterActionType(ActionAfterCallback::Create);
|
||||
|
||||
@ -610,6 +614,7 @@ void __KernelThreadingInit()
|
||||
// These idle threads are later started in LoadExec, which calls __KernelStartIdleThreads below.
|
||||
|
||||
__KernelListenThreadEnd(__KernelCancelWakeup);
|
||||
__KernelListenThreadEnd(__KernelCancelThreadEndTimeout);
|
||||
}
|
||||
|
||||
void __KernelThreadingDoState(PointerWrap &p)
|
||||
@ -629,6 +634,8 @@ void __KernelThreadingDoState(PointerWrap &p)
|
||||
|
||||
p.Do(eventScheduledWakeup);
|
||||
CoreTiming::RestoreRegisterEvent(eventScheduledWakeup, "ScheduledWakeup", &hleScheduledWakeup);
|
||||
p.Do(eventThreadEndTimeout);
|
||||
CoreTiming::RestoreRegisterEvent(eventThreadEndTimeout, "ThreadEndTimeout", &hleThreadEndTimeout);
|
||||
p.Do(actionAfterMipsCall);
|
||||
__KernelRestoreActionType(actionAfterMipsCall, ActionAfterMipsCall::Create);
|
||||
p.Do(actionAfterCallback);
|
||||
@ -1066,6 +1073,34 @@ void __KernelCancelWakeup(SceUID threadID)
|
||||
CoreTiming::UnscheduleEvent(eventScheduledWakeup, threadID);
|
||||
}
|
||||
|
||||
void hleThreadEndTimeout(u64 userdata, int cyclesLate)
|
||||
{
|
||||
SceUID threadID = (SceUID) userdata;
|
||||
SceUID waitID = (SceUID) (userdata >> 32);
|
||||
|
||||
u32 error;
|
||||
// Just in case it was woken on its own.
|
||||
if (__KernelGetWaitID(threadID, WAITTYPE_THREADEND, error) == waitID)
|
||||
{
|
||||
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
|
||||
if (Memory::IsValidAddress(timeoutPtr))
|
||||
Memory::Write_U32(0, timeoutPtr);
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
void __KernelScheduleThreadEndTimeout(SceUID threadID, SceUID waitID, s64 usFromNow)
|
||||
{
|
||||
s64 cycles = usToCycles(usFromNow);
|
||||
CoreTiming::ScheduleEvent(cycles, eventThreadEndTimeout, (u64) threadID | ((u64) waitID << 32));
|
||||
}
|
||||
|
||||
void __KernelCancelThreadEndTimeout(SceUID threadID)
|
||||
{
|
||||
CoreTiming::UnscheduleEvent(eventThreadEndTimeout, threadID);
|
||||
}
|
||||
|
||||
void __KernelRemoveFromThreadQueue(Thread *t)
|
||||
{
|
||||
for (size_t i = 0; i < threadqueue.size(); i++)
|
||||
@ -1240,7 +1275,7 @@ void __KernelResetThread(Thread *t)
|
||||
t->nt.waitID = 0;
|
||||
memset(&t->waitInfo, 0, sizeof(t->waitInfo));
|
||||
|
||||
t->nt.exitStatus = 0;
|
||||
t->nt.exitStatus = SCE_KERNEL_ERROR_NOT_DORMANT;
|
||||
t->isProcessingCallbacks = false;
|
||||
// TODO: Is this correct?
|
||||
t->pendingMipsCalls.clear();
|
||||
@ -1273,7 +1308,7 @@ Thread *__KernelCreateThread(SceUID &id, SceUID moduleId, const char *name, u32
|
||||
t->nt.wakeupCount = 0;
|
||||
t->nt.initialStack = 0;
|
||||
t->nt.waitID = 0;
|
||||
t->nt.exitStatus = 0;
|
||||
t->nt.exitStatus = SCE_KERNEL_ERROR_DORMANT;
|
||||
t->nt.waitType = WAITTYPE_NONE;
|
||||
|
||||
if (moduleId)
|
||||
@ -1282,11 +1317,8 @@ Thread *__KernelCreateThread(SceUID &id, SceUID moduleId, const char *name, u32
|
||||
t->nt.gpreg = 0; // sceKernelStartThread will take care of this.
|
||||
t->moduleId = moduleId;
|
||||
|
||||
if (name) {
|
||||
strncpy(t->nt.name, name, 32);
|
||||
} else {
|
||||
ERROR_LOG(HLE, "Threads must have names!");
|
||||
}
|
||||
strncpy(t->nt.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
|
||||
t->nt.name[KERNELOBJECT_MAX_NAME_LENGTH] = '\0';
|
||||
return t;
|
||||
}
|
||||
|
||||
@ -1315,6 +1347,27 @@ void __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int pr
|
||||
|
||||
int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr)
|
||||
{
|
||||
if (threadName == NULL)
|
||||
{
|
||||
ERROR_LOG(HLE, "SCE_KERNEL_ERROR_ERROR = sceKernelCreateThread(): NULL name");
|
||||
return SCE_KERNEL_ERROR_ERROR;
|
||||
}
|
||||
|
||||
// TODO: PSP actually fails for many of these cases, but trying for compat.
|
||||
if (stacksize < 0x200 || stacksize >= 0x20000000)
|
||||
{
|
||||
WARN_LOG(HLE, "sceKernelCreateThread(name=\"%s\"): bogus stack size %08x, using 0x4000", threadName, stacksize);
|
||||
stacksize = 0x4000;
|
||||
}
|
||||
if (prio < 0x08 || prio > 0x77)
|
||||
WARN_LOG(HLE, "sceKernelCreateThread(name=\"%s\"): bogus priority %08x", threadName, prio);
|
||||
if (!Memory::IsValidAddress(entry))
|
||||
WARN_LOG(HLE, "sceKernelCreateThread(name=\"%s\"): invalid entry %08x", threadName, entry);
|
||||
|
||||
// We're assuming all threads created are user threads.
|
||||
if ((attr & PSP_THREAD_ATTR_KERNEL) == 0)
|
||||
attr |= PSP_THREAD_ATTR_USER;
|
||||
|
||||
SceUID id;
|
||||
__KernelCreateThread(id, curModule, threadName, entry, prio, stacksize, attr);
|
||||
INFO_LOG(HLE, "%i = sceKernelCreateThread(name=\"%s\", entry=%08x, prio=%x, stacksize=%i)", id, threadName, entry, prio, stacksize);
|
||||
@ -1426,16 +1479,14 @@ void __KernelReturnFromThread()
|
||||
thread->FreeStack();
|
||||
}
|
||||
|
||||
thread->nt.exitStatus = thread->context.r[2];
|
||||
thread->nt.exitStatus = currentMIPS->r[2];
|
||||
thread->nt.status = THREADSTATUS_DORMANT;
|
||||
__KernelFireThreadEnd(thread);
|
||||
|
||||
// TODO: Need to remove the thread from any ready queues.
|
||||
|
||||
// Find threads that waited for me
|
||||
// Wake them
|
||||
if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread()))
|
||||
hleReSchedule("return from thread");
|
||||
__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread(), thread->nt.exitStatus, true);
|
||||
hleReSchedule("thread returned");
|
||||
|
||||
// The stack will be deallocated when the thread is deleted.
|
||||
}
|
||||
@ -1450,10 +1501,8 @@ void sceKernelExitThread()
|
||||
thread->nt.exitStatus = PARAM(0);
|
||||
__KernelFireThreadEnd(thread);
|
||||
|
||||
//Find threads that waited for me
|
||||
// Wake them
|
||||
if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread()))
|
||||
hleReSchedule("exited thread");
|
||||
__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread(), thread->nt.exitStatus, true);
|
||||
hleReSchedule("thread exited");
|
||||
|
||||
// The stack will be deallocated when the thread is deleted.
|
||||
}
|
||||
@ -1468,10 +1517,8 @@ void _sceKernelExitThread()
|
||||
thread->nt.exitStatus = PARAM(0);
|
||||
__KernelFireThreadEnd(thread);
|
||||
|
||||
//Find threads that waited for this one
|
||||
// Wake them
|
||||
if (!__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread()))
|
||||
hleReSchedule("_exit thread");
|
||||
__KernelTriggerWait(WAITTYPE_THREADEND, __KernelGetCurThread(), thread->nt.exitStatus, true);
|
||||
hleReSchedule("thread _exited");
|
||||
|
||||
// The stack will be deallocated when the thread is deleted.
|
||||
}
|
||||
@ -1487,15 +1534,17 @@ void sceKernelExitDeleteThread()
|
||||
t->nt.status = THREADSTATUS_DORMANT;
|
||||
t->nt.exitStatus = PARAM(0);
|
||||
__KernelFireThreadEnd(t);
|
||||
// TODO: Why not?
|
||||
//userMemory.Free(currentThread->stackBlock);
|
||||
t->stackBlock = 0;
|
||||
|
||||
__KernelRemoveFromThreadQueue(t);
|
||||
currentThread = 0;
|
||||
|
||||
RETURN(kernelObjects.Destroy<Thread>(threadHandle));
|
||||
__KernelTriggerWait(WAITTYPE_THREADEND, threadHandle, t->nt.exitStatus, true);
|
||||
hleReSchedule("thead exited with delete");
|
||||
|
||||
__KernelTriggerWait(WAITTYPE_THREADEND, threadHandle);
|
||||
RETURN(kernelObjects.Destroy<Thread>(threadHandle));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1540,11 +1589,9 @@ int sceKernelDeleteThread(int threadHandle)
|
||||
__KernelRemoveFromThreadQueue(t);
|
||||
__KernelFireThreadEnd(t);
|
||||
|
||||
__KernelTriggerWait(WAITTYPE_THREADEND, threadHandle);
|
||||
// TODO: Should this reschedule ever? Probably no?
|
||||
__KernelTriggerWait(WAITTYPE_THREADEND, threadHandle, SCE_KERNEL_ERROR_THREAD_TERMINATED, true);
|
||||
|
||||
//TODO: should we really reschedule here?
|
||||
//if (!__KernelTriggerWait(WAITTYPE_THREADEND, threadHandle))
|
||||
// hleReSchedule("thread deleted");
|
||||
return kernelObjects.Destroy<Thread>(threadHandle);
|
||||
}
|
||||
|
||||
@ -1566,8 +1613,8 @@ int sceKernelTerminateDeleteThread(int threadno)
|
||||
INFO_LOG(HLE, "sceKernelTerminateDeleteThread(%i)", threadno);
|
||||
|
||||
//TODO: should we really reschedule here?
|
||||
if (!__KernelTriggerWait(WAITTYPE_THREADEND, threadno))
|
||||
hleReSchedule("termdeletethread");
|
||||
__KernelTriggerWait(WAITTYPE_THREADEND, threadno, SCE_KERNEL_ERROR_THREAD_TERMINATED, false);
|
||||
hleReSchedule("termdeletethread");
|
||||
|
||||
// TODO: Why not delete?
|
||||
return 0; //kernelObjects.Destroy<Thread>(threadno));
|
||||
@ -1589,9 +1636,11 @@ int sceKernelTerminateThread(u32 threadID)
|
||||
Thread *t = kernelObjects.Get<Thread>(threadID, error);
|
||||
if (t)
|
||||
{
|
||||
t->nt.exitStatus = SCE_KERNEL_ERROR_THREAD_TERMINATED;
|
||||
t->nt.status = THREADSTATUS_DORMANT;
|
||||
__KernelFireThreadEnd(t);
|
||||
__KernelTriggerWait(WAITTYPE_THREADEND, threadID);
|
||||
// TODO: Should this really reschedule?
|
||||
__KernelTriggerWait(WAITTYPE_THREADEND, threadID, t->nt.exitStatus, true);
|
||||
}
|
||||
// TODO: Return an error if it doesn't exist?
|
||||
return 0;
|
||||
@ -1811,47 +1860,84 @@ void sceKernelSleepThreadCB()
|
||||
__KernelCheckCallbacks();
|
||||
}
|
||||
|
||||
void sceKernelWaitThreadEnd()
|
||||
int sceKernelWaitThreadEnd(SceUID threadID, u32 timeoutPtr)
|
||||
{
|
||||
SceUID id = PARAM(0);
|
||||
DEBUG_LOG(HLE,"sceKernelWaitThreadEnd(%i)",id);
|
||||
DEBUG_LOG(HLE, "sceKernelWaitThreadEnd(%i, %08x)", threadID);
|
||||
if (threadID == 0 || threadID == currentThread)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_THID;
|
||||
|
||||
u32 error;
|
||||
Thread *t = kernelObjects.Get<Thread>(id, error);
|
||||
Thread *t = kernelObjects.Get<Thread>(threadID, error);
|
||||
if (t)
|
||||
{
|
||||
if (t->nt.status != THREADSTATUS_DORMANT) {
|
||||
__KernelWaitCurThread(WAITTYPE_THREADEND, id, 0, 0, false);
|
||||
} else {
|
||||
DEBUG_LOG(HLE,"sceKernelWaitThreadEnd - thread %i already ended. Doing nothing.", id);
|
||||
if (t->nt.status != THREADSTATUS_DORMANT)
|
||||
{
|
||||
if (Memory::IsValidAddress(timeoutPtr))
|
||||
__KernelScheduleThreadEndTimeout(currentThread, threadID, Memory::Read_U32(timeoutPtr));
|
||||
__KernelWaitCurThread(WAITTYPE_THREADEND, threadID, 0, timeoutPtr, false);
|
||||
}
|
||||
|
||||
return t->nt.exitStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE,"sceKernelWaitThreadEnd - bad thread %i", id);
|
||||
ERROR_LOG(HLE, "sceKernelWaitThreadEnd - bad thread %i", threadID);
|
||||
return error;
|
||||
}
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void sceKernelWaitThreadEndCB()
|
||||
int sceKernelWaitThreadEndCB(SceUID threadID, u32 timeoutPtr)
|
||||
{
|
||||
SceUID id = PARAM(0);
|
||||
DEBUG_LOG(HLE,"sceKernelWaitThreadEnd(%i)",id);
|
||||
DEBUG_LOG(HLE, "sceKernelWaitThreadEnd(%i)", threadID);
|
||||
if (threadID == 0 || threadID == currentThread)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_THID;
|
||||
|
||||
u32 error;
|
||||
Thread *t = kernelObjects.Get<Thread>(id, error);
|
||||
Thread *t = kernelObjects.Get<Thread>(threadID, error);
|
||||
if (t)
|
||||
{
|
||||
if (t->nt.status != THREADSTATUS_DORMANT) {
|
||||
__KernelWaitCurThread(WAITTYPE_THREADEND, id, 0, 0, true);
|
||||
} else {
|
||||
DEBUG_LOG(HLE,"sceKernelWaitThreadEnd - thread %i already ended. Doing nothing.", id);
|
||||
hleCheckCurrentCallbacks();
|
||||
if (t->nt.status != THREADSTATUS_DORMANT)
|
||||
{
|
||||
if (Memory::IsValidAddress(timeoutPtr))
|
||||
__KernelScheduleThreadEndTimeout(currentThread, threadID, Memory::Read_U32(timeoutPtr));
|
||||
__KernelWaitCurThread(WAITTYPE_THREADEND, threadID, 0, timeoutPtr, true);
|
||||
}
|
||||
__KernelCheckCallbacks();
|
||||
|
||||
return t->nt.exitStatus;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE,"sceKernelWaitThreadEnd - bad thread %i", id);
|
||||
ERROR_LOG(HLE, "sceKernelWaitThreadEnd - bad thread %i", threadID);
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
int sceKernelReleaseWaitThread(SceUID threadID)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelReleaseWaitThread(%i)", threadID);
|
||||
if (__KernelInCallback())
|
||||
WARN_LOG(HLE, "UNTESTED sceKernelReleaseWaitThread() might not do the right thing in a callback");
|
||||
|
||||
if (threadID == 0 || threadID == currentThread)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_THID;
|
||||
|
||||
u32 error;
|
||||
Thread *t = kernelObjects.Get<Thread>(threadID, error);
|
||||
if (t)
|
||||
{
|
||||
if (!t->isWaiting())
|
||||
return SCE_KERNEL_ERROR_NOT_WAIT;
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_RELEASE_WAIT);
|
||||
hleReSchedule("thread released from wait");
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(HLE, "sceKernelReleaseWaitThread - bad thread %i", threadID);
|
||||
return error;
|
||||
}
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
void sceKernelSuspendThread()
|
||||
@ -2113,7 +2199,10 @@ void __KernelSwitchContext(Thread *target, const char *reason)
|
||||
__KernelSaveContext(&cur->context);
|
||||
oldPC = currentMIPS->pc;
|
||||
oldUID = cur->GetUID();
|
||||
oldName = cur->GetName();
|
||||
|
||||
// Profile on Windows shows this takes time, skip it.
|
||||
if (DEBUG_LEVEL <= MAX_LOGLEVEL)
|
||||
oldName = cur->GetName();
|
||||
}
|
||||
currentThread = target->GetUID();
|
||||
__KernelLoadContext(&target->context);
|
||||
|
@ -40,9 +40,10 @@ void sceKernelGetThreadCurrentPriority();
|
||||
int sceKernelStartThread(SceUID threadToStartID, u32 argSize, u32 argBlockPtr);
|
||||
u32 sceKernelSuspendDispatchThread();
|
||||
u32 sceKernelResumeDispatchThread(u32 suspended);
|
||||
void sceKernelWaitThreadEnd();
|
||||
int sceKernelWaitThreadEnd(SceUID threadID, u32 timeoutPtr);
|
||||
u32 sceKernelReferThreadStatus(u32 uid, u32 statusPtr);
|
||||
u32 sceKernelReferThreadRunStatus(u32 uid, u32 statusPtr);
|
||||
int sceKernelReleaseWaitThread(SceUID threadID);
|
||||
void sceKernelChangeCurrentThreadAttr();
|
||||
void sceKernelRotateThreadReadyQueue();
|
||||
void sceKernelCheckThreadStack();
|
||||
@ -52,7 +53,7 @@ void sceKernelWakeupThread();
|
||||
void sceKernelCancelWakeupThread();
|
||||
int sceKernelTerminateDeleteThread(int threadno);
|
||||
int sceKernelTerminateThread(u32 threadID);
|
||||
void sceKernelWaitThreadEndCB();
|
||||
int sceKernelWaitThreadEndCB(SceUID threadID, u32 timeoutPtr);
|
||||
void sceKernelGetThreadExitStatus();
|
||||
u32 sceKernelGetThreadmanIdType(u32);
|
||||
u32 sceKernelGetThreadmanIdList(u32 type, u32 readBufPtr, u32 readBufSize, u32 idCountPtr);
|
||||
|
@ -28,17 +28,25 @@ static bool useMediaEngine;
|
||||
|
||||
// MPEG AVC elementary stream.
|
||||
static const int MPEG_AVC_ES_SIZE = 2048; // MPEG packet size.
|
||||
|
||||
// MPEG ATRAC elementary stream.
|
||||
static const int MPEG_ATRAC_ES_SIZE = 2112;
|
||||
static const int MPEG_ATRAC_ES_OUTPUT_SIZE = 8192;
|
||||
|
||||
// MPEG PCM elementary stream.
|
||||
static const int MPEG_PCM_ES_SIZE = 320;
|
||||
static const int MPEG_PCM_ES_OUTPUT_SIZE = 320;
|
||||
|
||||
// MPEG Userdata elementary stream.
|
||||
static const int MPEG_DATA_ES_SIZE = 0xA0000;
|
||||
static const int MPEG_DATA_ES_OUTPUT_SIZE = 0xA0000;
|
||||
|
||||
// MPEG analysis results.
|
||||
static const int MPEG_VERSION_0012 = 0;
|
||||
static const int MPEG_VERSION_0013 = 1;
|
||||
static const int MPEG_VERSION_0014 = 2;
|
||||
static const int MPEG_VERSION_0015 = 3;
|
||||
|
||||
// MPEG streams.
|
||||
static const int MPEG_AVC_STREAM = 0;
|
||||
static const int MPEG_ATRAC_STREAM = 1;
|
||||
@ -69,6 +77,9 @@ static const int NUM_ES_BUFFERS = 2;
|
||||
|
||||
static const int PSP_ERROR_MPEG_NO_DATA = 0x80618001;
|
||||
|
||||
static const int TPSM_PIXEL_STORAGE_MODE_16BIT_BGR5650 = 0X00;
|
||||
static const int TPSM_PIXEL_STORAGE_MODE_32BIT_ABGR8888 = 0X03;
|
||||
|
||||
int getMaxAheadTimestamp(const SceMpegRingBuffer &ringbuf) {
|
||||
return std::max(40000, ringbuf.packets * 700); // empiric value from JPCSP, thanks!
|
||||
}
|
||||
@ -82,9 +93,10 @@ struct AvcContext {
|
||||
};
|
||||
|
||||
struct StreamInfo
|
||||
{
|
||||
{
|
||||
int type;
|
||||
int num;
|
||||
int sid;
|
||||
};
|
||||
|
||||
typedef std::map<u32, StreamInfo> StreamInfoMap;
|
||||
@ -114,6 +126,10 @@ struct MpegContext {
|
||||
p.Do(avcRegistered);
|
||||
p.Do(atracRegistered);
|
||||
p.Do(pcmRegistered);
|
||||
p.Do(dataRegistered);
|
||||
p.Do(ignoreAtrac);
|
||||
p.Do(ignorePcm);
|
||||
p.Do(ignoreAvc);
|
||||
p.Do(isAnalyzed);
|
||||
p.Do<StreamInfo>(streamMap);
|
||||
mediaengine->DoState(p);
|
||||
@ -143,6 +159,11 @@ struct MpegContext {
|
||||
bool avcRegistered;
|
||||
bool atracRegistered;
|
||||
bool pcmRegistered;
|
||||
bool dataRegistered;
|
||||
|
||||
bool ignoreAtrac;
|
||||
bool ignorePcm;
|
||||
bool ignoreAvc;
|
||||
|
||||
bool isAnalyzed;
|
||||
|
||||
@ -322,23 +343,22 @@ void __MpegShutdown() {
|
||||
mpegMap.clear();
|
||||
}
|
||||
|
||||
void sceMpegInit()
|
||||
u32 sceMpegInit()
|
||||
{
|
||||
WARN_LOG(HLE, "sceMpegInit()");
|
||||
|
||||
RETURN(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceMpegRingbufferQueryMemSize(int packets)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceMpegRingbufferQueryMemSize(%i)", packets);
|
||||
return packets * (104 + 2048);
|
||||
int size = packets * (104 + 2048);
|
||||
return size;
|
||||
}
|
||||
|
||||
u32 sceMpegRingbufferConstruct(u32 ringbufferAddr, u32 numPackets, u32 data, u32 size, u32 callbackAddr, u32 callbackArg)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceMpegRingbufferConstruct(%08x, %i, %08x, %i, %08x, %i)",
|
||||
ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg);
|
||||
DEBUG_LOG(HLE, "sceMpegRingbufferConstruct(%08x, %i, %08x, %i, %08x, %i)", ringbufferAddr, numPackets, data, size, callbackAddr, callbackArg);
|
||||
SceMpegRingBuffer ring;
|
||||
InitRingbuffer(&ring, numPackets, data, size, callbackAddr, callbackArg);
|
||||
Memory::WriteStruct(ringbufferAddr, &ring);
|
||||
@ -384,6 +404,10 @@ u32 sceMpegCreate(u32 mpegAddr, u32 dataPtr, u32 size, u32 ringbufferAddr, u32 f
|
||||
ctx->avcRegistered = false;
|
||||
ctx->atracRegistered = false;
|
||||
ctx->pcmRegistered = false;
|
||||
ctx->dataRegistered = false;
|
||||
ctx->ignoreAtrac = false;
|
||||
ctx->ignorePcm = false;
|
||||
ctx->ignoreAvc = false;
|
||||
ctx->defaultFrameWidth = frameWidth;
|
||||
for (int i = 0; i < NUM_ES_BUFFERS; i++) {
|
||||
ctx->esBuffers[i] = false;
|
||||
@ -428,12 +452,17 @@ int sceMpegAvcDecodeMode(u32 mpeg, u32 modeAddr)
|
||||
if (Memory::IsValidAddress(modeAddr)) {
|
||||
int mode = Memory::Read_U32(modeAddr);
|
||||
int pixelMode = Memory::Read_U32(modeAddr + 4);
|
||||
ctx->videoPixelMode = pixelMode;
|
||||
return 0;
|
||||
if (pixelMode >= TPSM_PIXEL_STORAGE_MODE_16BIT_BGR5650 && pixelMode <= TPSM_PIXEL_STORAGE_MODE_32BIT_ABGR8888) {
|
||||
ctx->videoPixelMode = pixelMode;
|
||||
} else {
|
||||
ERROR_LOG(HLE, "sceMpegAvcDecodeMode(%i, %i): unknown pixelMode ", mode, pixelMode);
|
||||
}
|
||||
} else {
|
||||
WARN_LOG(HLE, "sceMpegAvcDecodeMode(%08x, %08x): invalid modeAddr", mpeg, modeAddr);
|
||||
return -1;
|
||||
ERROR_LOG(HLE, "sceMpegAvcDecodeMode(%08x, %08x): invalid modeAddr", mpeg, modeAddr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceMpegQueryStreamOffset(u32 mpeg, u32 bufferAddr, u32 offsetAddr)
|
||||
@ -451,13 +480,13 @@ int sceMpegQueryStreamOffset(u32 mpeg, u32 bufferAddr, u32 offsetAddr)
|
||||
|
||||
if (ctx->mpegMagic != PSMF_MAGIC) {
|
||||
ERROR_LOG(HLE, "sceMpegQueryStreamOffset: Bad PSMF magic");
|
||||
return -1; //ERROR_MPEG_INVALID_VALUE
|
||||
return ERROR_MPEG_INVALID_VALUE;
|
||||
} else if (ctx->mpegVersion < 0) {
|
||||
ERROR_LOG(HLE, "sceMpegQueryStreamOffset: Bad version");
|
||||
return -1; //ERROR_MPEG_BAD_VERSION
|
||||
return ERROR_MPEG_BAD_VERSION;
|
||||
} else if ((ctx->mpegOffset & 2047) != 0 || ctx->mpegOffset == 0) {
|
||||
ERROR_LOG(HLE, "sceMpegQueryStreamOffset: Bad offset");
|
||||
return -1; //ERROR_MPEG_INVALID_VALUE
|
||||
return ERROR_MPEG_INVALID_VALUE;
|
||||
}
|
||||
Memory::Write_U32(ctx->mpegOffset, offsetAddr);
|
||||
return 0;
|
||||
@ -510,6 +539,12 @@ int sceMpegRegistStream(u32 mpeg, u32 streamType, u32 streamNum)
|
||||
case MPEG_PCM_STREAM:
|
||||
ctx->pcmRegistered = true;
|
||||
break;
|
||||
case MPEG_DATA_STREAM:
|
||||
ctx->dataRegistered = true;
|
||||
break;
|
||||
default :
|
||||
DEBUG_LOG(HLE, "sceMpegRegistStream(%i) : unknown stream type", streamType);
|
||||
break;
|
||||
}
|
||||
// ...
|
||||
u32 sid = streamIdGen++;
|
||||
@ -664,16 +699,50 @@ u32 sceMpegAvcDecode(u32 mpeg, u32 auAddr, u32 frameWidth, u32 bufferAddr, u32 i
|
||||
|
||||
u32 sceMpegAvcDecodeStop(u32 mpeg, u32 frameWidth, u32 bufferAddr, u32 statusAddr)
|
||||
{
|
||||
WARN_LOG(HLE, "HACK sceMpegAvcDecodeStop(%08x, %08x, %08x, statusAddr=%08x)",
|
||||
mpeg, frameWidth, bufferAddr, statusAddr);
|
||||
|
||||
ERROR_LOG(HLE, "sceMpegAvcDecodeStop(%08x, %08x, %08x, %08x)", mpeg, frameWidth, bufferAddr, statusAddr);
|
||||
if (Memory::IsValidAddress(statusAddr)) {
|
||||
Memory::Write_U32(0,statusAddr);
|
||||
} else {
|
||||
ERROR_LOG(HLE, "sceMpegAvcDecodeStop(%08x, %08x): invalid statusAddr", mpeg, statusAddr);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceMpegUnRegistStream()
|
||||
u32 sceMpegUnRegistStream(u32 mpeg, int streamUid)
|
||||
{
|
||||
WARN_LOG(HLE, "HACK sceMpegUnRegistStream(...)");
|
||||
RETURN(0);
|
||||
MpegContext *ctx = getMpegCtx(mpeg);
|
||||
if (!ctx)
|
||||
{
|
||||
WARN_LOG(HLE, "sceMpegUnRegistStream(%08x, %i, %i): bad mpeg handle", mpeg, streamUid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
StreamInfo info;
|
||||
|
||||
switch (info.type) {
|
||||
case MPEG_AVC_STREAM:
|
||||
ctx->avcRegistered = false;
|
||||
break;
|
||||
case MPEG_AUDIO_STREAM:
|
||||
case MPEG_ATRAC_STREAM:
|
||||
ctx->atracRegistered = false;
|
||||
break;
|
||||
case MPEG_PCM_STREAM:
|
||||
ctx->pcmRegistered = false;
|
||||
break;
|
||||
case MPEG_DATA_STREAM:
|
||||
ctx->dataRegistered = false;
|
||||
break;
|
||||
default :
|
||||
DEBUG_LOG(HLE, "sceMpegUnRegistStream(%i) : unknown streamID ", streamUid);
|
||||
break;
|
||||
}
|
||||
ctx->streamMap[streamUid] = info;
|
||||
info.type = -1;
|
||||
info.sid = -1 ;
|
||||
ctx->isAnalyzed = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceMpegAvcDecodeDetail(u32 mpeg, u32 detailAddr)
|
||||
@ -704,21 +773,25 @@ int sceMpegAvcDecodeDetail(u32 mpeg, u32 detailAddr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceMpegAvcDecodeStopYCbCr()
|
||||
u32 sceMpegAvcDecodeStopYCbCr(u32 mpeg, u32 bufferAddr, u32 statusAddr)
|
||||
{
|
||||
WARN_LOG(HLE, "HACK sceMpegAvcDecodeStopYCbCr(...)");
|
||||
RETURN(0);
|
||||
ERROR_LOG(HLE, "UNIMPL sceMpegAvcDecodeStopYCbCr(%08x, %08x, %08x)", mpeg, bufferAddr, statusAddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceMpegAvcDecodeYCbCr(u32 mpeg, u32 auAddr, u32 bufferAddr, u32 initAddr)
|
||||
{
|
||||
WARN_LOG(HLE, "HACK sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x)", mpeg, auAddr, bufferAddr, initAddr);
|
||||
ERROR_LOG(HLE, "UNIMPL sceMpegAvcDecodeYCbCr(%08x, %08x, %08x, %08x)", mpeg, auAddr, bufferAddr, initAddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceMpegAvcDecodeFlush(u32 mpeg)
|
||||
{
|
||||
MpegContext *ctx = getMpegCtx(mpeg);
|
||||
ERROR_LOG(HLE, "UNIMPL sceMpegAvcDecodeFlush(%08x)", mpeg);
|
||||
if ( ctx->videoFrameCount > 0 || ctx->audioFrameCount > 0) {
|
||||
//__MpegFinish();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -781,9 +854,6 @@ int sceMpegRingbufferAvailableSize(u32 ringbufferAddr)
|
||||
return ringbuffer.packetsFree;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void PostPutAction::run(MipsCall &call) {
|
||||
SceMpegRingBuffer ringbuffer;
|
||||
Memory::ReadStruct(ringAddr_, &ringbuffer);
|
||||
@ -908,11 +978,11 @@ int sceMpegGetAvcAu(u32 mpeg, u32 streamId, u32 auAddr, u32 attrAddr)
|
||||
return result;
|
||||
}
|
||||
|
||||
void sceMpegFinish()
|
||||
u32 sceMpegFinish()
|
||||
{
|
||||
WARN_LOG(HLE, "sceMpegFinish(...)");
|
||||
ERROR_LOG(HLE, "sceMpegFinish(...)");
|
||||
//__MpegFinish();
|
||||
RETURN(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceMpegQueryMemSize()
|
||||
@ -973,47 +1043,103 @@ int sceMpegQueryPcmEsSize(u32 mpeg, u32 esSizeAddr, u32 outSizeAddr)
|
||||
}
|
||||
|
||||
|
||||
void sceMpegChangeGetAuMode()
|
||||
u32 sceMpegChangeGetAuMode(u32 mpeg, int streamUid, int mode)
|
||||
{
|
||||
WARN_LOG(HLE, "HACK sceMpegChangeGetAuMode(...)");
|
||||
RETURN(0);
|
||||
MpegContext *ctx = getMpegCtx(mpeg);
|
||||
if (!ctx) {
|
||||
WARN_LOG(HLE, "sceMpegChangeGetAuMode(%08x, %i, %i): bad mpeg handle", mpeg, streamUid, mode);
|
||||
return -1;
|
||||
}
|
||||
|
||||
StreamInfo info;
|
||||
info.sid = streamUid;
|
||||
if (info.sid) {
|
||||
switch (info.type) {
|
||||
case MPEG_AVC_STREAM:
|
||||
if(mode == MPEG_AU_MODE_DECODE) {
|
||||
ctx->ignoreAvc = false;
|
||||
} else if (mode == MPEG_AU_MODE_SKIP) {
|
||||
ctx->ignoreAvc = true;
|
||||
}
|
||||
break;
|
||||
case MPEG_AUDIO_STREAM:
|
||||
case MPEG_ATRAC_STREAM:
|
||||
if(mode == MPEG_AU_MODE_DECODE) {
|
||||
ctx->ignoreAtrac = false;
|
||||
} else if (mode == MPEG_AU_MODE_SKIP) {
|
||||
ctx->ignoreAtrac = true;
|
||||
}
|
||||
break;
|
||||
case MPEG_PCM_STREAM:
|
||||
if(mode == MPEG_AU_MODE_DECODE) {
|
||||
ctx->ignorePcm = false;
|
||||
} else if (mode == MPEG_AU_MODE_SKIP) {
|
||||
ctx->ignorePcm = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ERROR_LOG(HLE, "UNIMPL sceMpegChangeGetAuMode(%08x, %i): unkown streamID", mpeg, streamUid);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
ERROR_LOG(HLE, "UNIMPL sceMpegChangeGetAuMode(%08x, %i): unkown streamID", mpeg, streamUid);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceMpegGetPcmAu()
|
||||
u32 sceMpegChangeGetAvcAuMode(u32 mpeg, u32 stream_addr, int mode)
|
||||
{
|
||||
WARN_LOG(HLE, "HACK sceMpegGetPcmAu(...)");
|
||||
RETURN(0);
|
||||
ERROR_LOG(HLE, "UNIMPL sceMpegChangeGetAvcAuMode(%08x, %08x, %i)", mpeg, stream_addr, mode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceMpegRingbufferQueryPackNum()
|
||||
u32 sceMpegGetPcmAu(u32 mpeg, int streamUid, u32 auAddr, u32 attrAddr)
|
||||
{
|
||||
WARN_LOG(HLE, "HACK sceMpegRingbufferQueryPackNum(...)");
|
||||
RETURN(0);
|
||||
ERROR_LOG(HLE, "UNIMPL sceMpegGetPcmAu(%08x, %i, %08x, %08x)", mpeg, streamUid, auAddr, attrAddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceMpegFlushAllStream()
|
||||
u32 sceMpegRingbufferQueryPackNum(int memorySize)
|
||||
{
|
||||
WARN_LOG(HLE, "HACK sceMpegFlushAllStream(...)");
|
||||
RETURN(0);
|
||||
ERROR_LOG(HLE, "sceMpegRingbufferQueryPackNum(%i)", memorySize);
|
||||
int packets = memorySize / (2048 + 104);
|
||||
return packets;
|
||||
}
|
||||
|
||||
void sceMpegAvcCopyYCbCr()
|
||||
u32 sceMpegFlushAllStream(u32 mpeg)
|
||||
{
|
||||
WARN_LOG(HLE, "HACK sceMpegAvcCopyYCbCr(...)");
|
||||
RETURN(0);
|
||||
MpegContext *ctx = getMpegCtx(mpeg);
|
||||
ERROR_LOG(HLE, "UNIMPL sceMpegFlushAllStream(%08x)", mpeg);
|
||||
if ( ctx->videoFrameCount > 0 || ctx->audioFrameCount > 0) {
|
||||
//__MpegFinish();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceMpegAtracDecode()
|
||||
u32 sceMpegFlushStream(u32 mpeg, int stream_addr)
|
||||
{
|
||||
WARN_LOG(HLE, "HACK sceMpegAtracDecode(...)");
|
||||
RETURN(0);
|
||||
ERROR_LOG(HLE, "UNIMPL sceMpegFlushStream(%08x, %i)", mpeg , stream_addr);
|
||||
//__MpegFinish();
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceMpegAvcCopyYCbCr(u32 mpeg, u32 sourceAddr, u32 YCbCrAddr)
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceMpegAvcCopyYCbCr(%08x, %08x, %08x)", mpeg, sourceAddr, YCbCrAddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceMpegAtracDecode(u32 mpeg, u32 auAddr, u32 bufferAddr, int init)
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceMpegAtracDecode(%08x, %08x, %08x, %i)", mpeg, auAddr, bufferAddr, init);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// YCbCr -> RGB color space conversion
|
||||
void sceMpegAvcCsc()
|
||||
u32 sceMpegAvcCsc(u32 mpeg, u32 sourceAddr, u32 rangeAddr, int frameWidth, u32 destAddr)
|
||||
{
|
||||
WARN_LOG(HLE, "HACK sceMpegAvcCsc(...)");
|
||||
RETURN(0);
|
||||
ERROR_LOG(HLE, "UNIMPL sceMpegAvcCsc(%08x, %08x, %08x, %i, %08x)", mpeg, sourceAddr, rangeAddr, frameWidth, destAddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceMpegRingbufferDestruct(u32 ringbufferAddr)
|
||||
@ -1023,10 +1149,10 @@ u32 sceMpegRingbufferDestruct(u32 ringbufferAddr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void sceMpegAvcInitYCbCr()
|
||||
u32 sceMpegAvcInitYCbCr(u32 mpeg, int mode, int width, int height, u32 ycbcr_addr)
|
||||
{
|
||||
WARN_LOG(HLE, "HACK sceMpegAvcInitYCbCr(...)");
|
||||
RETURN(0);
|
||||
ERROR_LOG(HLE, "UNIMPL sceMpegAvcInitYCbCr(%08x, %i, %i, %i, %08x)", mpeg, mode, width, height, ycbcr_addr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceMpegAvcQueryYCbCrSize(u32 mpeg, u32 mode, u32 width, u32 height, u32 resultAddr)
|
||||
@ -1034,7 +1160,7 @@ int sceMpegAvcQueryYCbCrSize(u32 mpeg, u32 mode, u32 width, u32 height, u32 resu
|
||||
if ((width & 15) != 0 || (height & 15) != 0 || height > 272 || width > 480)
|
||||
{
|
||||
ERROR_LOG(HLE, "sceMpegAvcQueryYCbCrSize: bad w/h %i x %i", width, height);
|
||||
return -1;
|
||||
return ERROR_MPEG_INVALID_VALUE;
|
||||
}
|
||||
DEBUG_LOG(HLE, "sceMpegAvcQueryYCbCrSize(%08x, %i, %i, %i, %08x)", mpeg, mode, width, height, resultAddr);
|
||||
|
||||
@ -1043,6 +1169,36 @@ int sceMpegAvcQueryYCbCrSize(u32 mpeg, u32 mode, u32 width, u32 height, u32 resu
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceMp3Decode(u32 mp3, u32 outPcmPtr)
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceMp3Decoder(%08x,%08x)", mp3, outPcmPtr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceMp3ResetPlayPosition(u32 mp3)
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceMp3ResetPlayPosition(%08x)", mp3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sceMp3CheckStreamDataNeeded(u32 mp3)
|
||||
{
|
||||
ERROR_LOG(HLE, "UNIMPL sceMp3CheckStreamDataNeeded(%08x)", mp3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 sceMpegQueryUserdataEsSize(u32 mpeg, u32 esSizeAddr, u32 outSizeAddr)
|
||||
{
|
||||
if (Memory::IsValidAddress(esSizeAddr) && Memory::IsValidAddress(outSizeAddr)) {
|
||||
DEBUG_LOG(HLE, "sceMpegQueryUserdataEsSize(%08x, %08x, %08x)", mpeg, esSizeAddr, outSizeAddr);
|
||||
Memory::Write_U32(MPEG_DATA_ES_SIZE, esSizeAddr);
|
||||
Memory::Write_U32(MPEG_DATA_ES_OUTPUT_SIZE, outSizeAddr);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ERROR_LOG(HLE, "sceMpegQueryUserdataEsSize - bad pointers(%08x, %08x, %08x)", mpeg, esSizeAddr, outSizeAddr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const HLEFunction sceMpeg[] =
|
||||
{
|
||||
@ -1054,15 +1210,16 @@ const HLEFunction sceMpeg[] =
|
||||
{0x21ff80e4,WrapI_UUU<sceMpegQueryStreamOffset>,"sceMpegQueryStreamOffset"},
|
||||
{0x611e9e11,WrapU_UU<sceMpegQueryStreamSize>,"sceMpegQueryStreamSize"},
|
||||
{0x42560f23,WrapI_UUU<sceMpegRegistStream>,"sceMpegRegistStream"},
|
||||
{0x591a4aa2,sceMpegUnRegistStream,"sceMpegUnRegistStream"},
|
||||
{0x707b7629,sceMpegFlushAllStream,"sceMpegFlushAllStream"},
|
||||
{0x591a4aa2,WrapU_UI<sceMpegUnRegistStream>,"sceMpegUnRegistStream"},
|
||||
{0x707b7629,WrapU_U<sceMpegFlushAllStream>,"sceMpegFlushAllStream"},
|
||||
{0x500F0429,WrapU_UI<sceMpegFlushStream>,"sceMpegFlushStream"},
|
||||
{0xa780cf7e,WrapI_U<sceMpegMallocAvcEsBuf>,"sceMpegMallocAvcEsBuf"},
|
||||
{0xceb870b1,WrapI_UI<sceMpegFreeAvcEsBuf>,"sceMpegFreeAvcEsBuf"},
|
||||
{0x167afd9e,WrapI_UUU<sceMpegInitAu>,"sceMpegInitAu"},
|
||||
{0x682a619b,sceMpegInit,"sceMpegInit"},
|
||||
{0x682a619b,WrapU_V<sceMpegInit>,"sceMpegInit"},
|
||||
{0x606a4649,WrapI_U<sceMpegDelete>,"sceMpegDelete"},
|
||||
{0x874624d6,sceMpegFinish,"sceMpegFinish"},
|
||||
{0x800c44df,sceMpegAtracDecode,"sceMpegAtracDecode"},
|
||||
{0x874624d6,WrapU_V<sceMpegFinish>,"sceMpegFinish"},
|
||||
{0x800c44df,WrapU_UUUI<sceMpegAtracDecode>,"sceMpegAtracDecode"},
|
||||
{0x0e3c2e9d,&WrapU_UUUUU<sceMpegAvcDecode>,"sceMpegAvcDecode"},
|
||||
{0x740fccd1,&WrapU_UUUU<sceMpegAvcDecodeStop>,"sceMpegAvcDecodeStop"},
|
||||
{0x4571cc64,&WrapU_U<sceMpegAvcDecodeFlush>,"sceMpegAvcDecodeFlush"},
|
||||
@ -1073,23 +1230,25 @@ const HLEFunction sceMpeg[] =
|
||||
{0xb240a59e,WrapU_UUU<sceMpegRingbufferPut>,"sceMpegRingbufferPut"},
|
||||
{0xb5f6dc87,WrapI_U<sceMpegRingbufferAvailableSize>,"sceMpegRingbufferAvailableSize"},
|
||||
{0xd7a29f46,WrapU_I<sceMpegRingbufferQueryMemSize>,"sceMpegRingbufferQueryMemSize"},
|
||||
{0x769BEBB6,sceMpegRingbufferQueryPackNum,"sceMpegRingbufferQueryPackNum"},
|
||||
{0x769BEBB6,WrapU_I<sceMpegRingbufferQueryPackNum>,"sceMpegRingbufferQueryPackNum"},
|
||||
{0x211a057c,WrapI_UUUUU<sceMpegAvcQueryYCbCrSize>,"sceMpegAvcQueryYCbCrSize"},
|
||||
{0xf0eb1125,WrapI_UUUU<sceMpegAvcDecodeYCbCr>,"sceMpegAvcDecodeYCbCr"},
|
||||
{0xf2930c9c,sceMpegAvcDecodeStopYCbCr,"sceMpegAvcDecodeStopYCbCr"},
|
||||
{0x67179b1b,sceMpegAvcInitYCbCr,"sceMpegAvcInitYCbCr"},
|
||||
{0x0558B075,sceMpegAvcCopyYCbCr,"sceMpegAvcCopyYCbCr"},
|
||||
{0x31bd0272,sceMpegAvcCsc,"sceMpegAvcCsc"},
|
||||
{0x9DCFB7EA,sceMpegChangeGetAuMode,"sceMpegChangeGetAuMode"},
|
||||
{0x8C1E027D,sceMpegGetPcmAu,"sceMpegGetPcmAu"},
|
||||
{0xf2930c9c,WrapU_UUU<sceMpegAvcDecodeStopYCbCr>,"sceMpegAvcDecodeStopYCbCr"},
|
||||
{0x67179b1b,WrapU_UIIIU<sceMpegAvcInitYCbCr>,"sceMpegAvcInitYCbCr"},
|
||||
{0x0558B075,WrapU_UUU<sceMpegAvcCopyYCbCr>,"sceMpegAvcCopyYCbCr"},
|
||||
{0x31bd0272,WrapU_UUUIU<sceMpegAvcCsc>,"sceMpegAvcCsc"},
|
||||
{0x9DCFB7EA,WrapU_UII<sceMpegChangeGetAuMode>,"sceMpegChangeGetAuMode"},
|
||||
{0x8C1E027D,WrapU_UIUU<sceMpegGetPcmAu>,"sceMpegGetPcmAu"},
|
||||
{0xC02CF6B5,WrapI_UUU<sceMpegQueryPcmEsSize>,"sceMpegQueryPcmEsSize"},
|
||||
{0xC45C99CC,WrapU_UUU<sceMpegQueryUserdataEsSize>,"sceMpegQueryUserdataEsSize"},
|
||||
{0x234586AE,WrapU_UUI<sceMpegChangeGetAvcAuMode>,"sceMpegChangeGetAvcAuMode"},
|
||||
};
|
||||
|
||||
const HLEFunction sceMp3[] =
|
||||
{
|
||||
{0x07EC321A,0,"sceMp3ReserveMp3Handle"},
|
||||
{0x0DB149F4,0,"sceMp3NotifyAddStreamData"},
|
||||
{0x2A368661,0,"sceMp3ResetPlayPosition"},
|
||||
{0x2A368661,WrapI_U<sceMp3ResetPlayPosition>,"sceMp3ResetPlayPosition"},
|
||||
{0x354D27EA,0,"sceMp3GetSumDecodedSample"},
|
||||
{0x35750070,0,"sceMp3InitResource"},
|
||||
{0x3C2FA058,0,"sceMp3TermResource"},
|
||||
@ -1102,10 +1261,12 @@ const HLEFunction sceMp3[] =
|
||||
{0x8AB81558,0,"sceMp3StartEntry"},
|
||||
{0x8F450998,0,"sceMp3GetSamplingRate"},
|
||||
{0xA703FE0F,0,"sceMp3GetInfoToAddStreamData"},
|
||||
{0xD021C0FB,0,"sceMp3Decode"},
|
||||
{0xD0A56296,0,"sceMp3CheckStreamDataNeeded"},
|
||||
{0xD021C0FB,WrapI_UU<sceMp3Decode>,"sceMp3Decode"},
|
||||
{0xD0A56296,WrapI_U<sceMp3CheckStreamDataNeeded>,"sceMp3CheckStreamDataNeeded"},
|
||||
{0xD8F54A51,0,"sceMp3GetLoopNum"},
|
||||
{0xF5478233,0,"sceMp3ReleaseMp3Handle"},
|
||||
{0xAE6D2027,0,"sceMp3GetVersion"},
|
||||
{0x3548AEC8,0,"sceMp3GetFrameNum"},
|
||||
};
|
||||
|
||||
void Register_sceMpeg()
|
||||
|
@ -313,7 +313,7 @@ u32 scePsmfGetNumberOfStreams(u32 psmfStruct)
|
||||
ERROR_LOG(HLE, "scePsmfGetNumberOfStreams - invalid psmf");
|
||||
return ERROR_PSMF_NOT_FOUND;
|
||||
}
|
||||
INFO_LOG(HLE, "%i=scePsmfGetNumberOfStreams(%08x)", psmf->getNumStreams(), psmf);
|
||||
INFO_LOG(HLE, "%i=scePsmfGetNumberOfStreams(%08x)", psmf->getNumStreams(), psmfStruct);
|
||||
return psmf->getNumStreams();
|
||||
}
|
||||
|
||||
|
@ -38,8 +38,12 @@ EmuFileType Identify_File(const char *filename)
|
||||
return FILETYPE_ERROR;
|
||||
}
|
||||
u32 id;
|
||||
fread(&id,4,1,f);
|
||||
size_t readSize = fread(&id,4,1,f);
|
||||
fclose(f);
|
||||
|
||||
if(readSize != 1)
|
||||
return FILETYPE_ERROR;
|
||||
|
||||
if (id == 'FLE\x7F')
|
||||
{
|
||||
if (strstr(filename,".plf") || strstr(filename,"BOOT.BIN") || strstr(filename,".elf") || strstr(filename,".prx") )
|
||||
|
@ -351,7 +351,8 @@ namespace MIPSAnalyst
|
||||
{
|
||||
FILE *file = fopen(filename,"wb");
|
||||
u32 num = 0;
|
||||
fwrite(&num,4,1,file); //fill in later
|
||||
if(fwrite(&num,4,1,file) != 1) //fill in later
|
||||
WARN_LOG(CPU, "Could not store hash map %s", filename);
|
||||
|
||||
for (vector<Function>::iterator iter = functions.begin(); iter!=functions.end(); iter++)
|
||||
{
|
||||
@ -363,12 +364,16 @@ namespace MIPSAnalyst
|
||||
strcpy(temp.name, f.name);
|
||||
temp.hash=f.hash;
|
||||
temp.size=f.size;
|
||||
fwrite((char*)&temp,sizeof(temp),1,file);
|
||||
if(fwrite((char*)&temp,sizeof(temp),1,file) != 1) {
|
||||
WARN_LOG(CPU, "Could not store hash map %s", filename);
|
||||
break;
|
||||
}
|
||||
num++;
|
||||
}
|
||||
}
|
||||
fseek(file,0,SEEK_SET);
|
||||
fwrite(&num,4,1,file); //fill in later
|
||||
if(fwrite(&num,4,1,file) != 1) //fill in later
|
||||
WARN_LOG(CPU, "Could not store hash map %s", filename);
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
@ -380,25 +385,26 @@ namespace MIPSAnalyst
|
||||
|
||||
FILE *file = fopen(filename, "rb");
|
||||
int num;
|
||||
fread(&num,4,1,file);
|
||||
for (int i=0; i<num; i++)
|
||||
{
|
||||
HashMapFunc temp;
|
||||
fread(&temp,sizeof(temp),1,file);
|
||||
map<u32,Function*>::iterator iter = hashToFunction.find(temp.hash);
|
||||
if (iter != hashToFunction.end())
|
||||
if(fread(&num,4,1,file) == 1) {
|
||||
for (int i=0; i<num; i++)
|
||||
{
|
||||
//yay, found a function!
|
||||
Function &f = *(iter->second);
|
||||
if (f.size==temp.size)
|
||||
{
|
||||
strcpy(f.name, temp.name);
|
||||
f.hash=temp.hash;
|
||||
f.size=temp.size;
|
||||
HashMapFunc temp;
|
||||
if(fread(&temp,sizeof(temp),1,file) == 1) {
|
||||
map<u32,Function*>::iterator iter = hashToFunction.find(temp.hash);
|
||||
if (iter != hashToFunction.end())
|
||||
{
|
||||
//yay, found a function!
|
||||
Function &f = *(iter->second);
|
||||
if (f.size==temp.size)
|
||||
{
|
||||
strcpy(f.name, temp.name);
|
||||
f.hash=temp.hash;
|
||||
f.size=temp.size;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(file);
|
||||
}
|
||||
void CompileLeafs()
|
||||
|
@ -931,7 +931,7 @@ void MIPSInterpret(u32 op) //only for those rare ones
|
||||
// Try to disassemble it
|
||||
char disasm[256];
|
||||
MIPSDisAsm(op, currentMIPS->pc, disasm);
|
||||
_dbg_assert_msg_(CPU, 0, disasm);
|
||||
_dbg_assert_msg_(CPU, 0, "%s", disasm);
|
||||
currentMIPS->pc += 4;
|
||||
}
|
||||
}
|
||||
|
@ -16,13 +16,11 @@ arm {
|
||||
x86 {
|
||||
SOURCES += ../Common/ABI.cpp \
|
||||
../Common/CPUDetect.cpp \
|
||||
../Common/MathUtil.cpp \
|
||||
../Common/Thunk.cpp \
|
||||
../Common/x64Analyzer.cpp \
|
||||
../Common/x64Emitter.cpp
|
||||
HEADERS += ../Common/ABI.h \
|
||||
../Common/CPUDetect.h \
|
||||
../Common/MathUtil.h \
|
||||
../Common/Thunk.h \
|
||||
../Common/x64Analyzer.h \
|
||||
../Common/x64Emitter.h
|
||||
@ -47,10 +45,10 @@ SOURCES += ../Common/ColorUtil.cpp \
|
||||
../Common/Hash.cpp \
|
||||
../Common/IniFile.cpp \
|
||||
../Common/LogManager.cpp \
|
||||
../Common/MathUtil.cpp \
|
||||
../Common/MemArena.cpp \
|
||||
../Common/MemoryUtil.cpp \
|
||||
../Common/Misc.cpp \
|
||||
../Common/MathUtil.cpp \
|
||||
../Common/MsgHandler.cpp \
|
||||
../Common/StringUtil.cpp \
|
||||
../Common/Thread.cpp \
|
||||
@ -66,9 +64,9 @@ HEADERS += ../Common/ColorUtil.h \
|
||||
../Common/Hash.h \
|
||||
../Common/IniFile.h \
|
||||
../Common/LogManager.h \
|
||||
../Common/MathUtil.h \
|
||||
../Common/MemArena.h \
|
||||
../Common/MemoryUtil.h \
|
||||
../Common/MathUtil.h \
|
||||
../Common/MsgHandler.h \
|
||||
../Common/StringUtil.h \
|
||||
../Common/Thread.h \
|
||||
|
@ -1,4 +1,4 @@
|
||||
blackberry|symbian: CONFIG += mobile_platform
|
||||
blackberry|symbian|contains(MEEGO_EDITION,harmattan): CONFIG += mobile_platform
|
||||
unix:!blackberry:!symbian:!macx: CONFIG += linux
|
||||
|
||||
# Global specific
|
||||
@ -17,6 +17,7 @@ mobile_platform: DEFINES += USING_GLES2
|
||||
|
||||
|
||||
# Platform specific
|
||||
contains(MEEGO_EDITION,harmattan): DEFINES += MEEGO_EDITION_HARMATTAN "_SYS_UCONTEXT_H=1"
|
||||
blackberry: {
|
||||
# They try to force QCC with all mkspecs
|
||||
# QCC is 4.4.1, we need 4.6.3
|
||||
|
Loading…
Reference in New Issue
Block a user