mirror of
https://github.com/joel16/VitaShell.git
synced 2025-02-25 22:56:44 +00:00
763 lines
19 KiB
C
763 lines
19 KiB
C
/*
|
|
VitaShell
|
|
Copyright (C) 2015-2016, TheFloW
|
|
|
|
This program is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "main.h"
|
|
#include "init.h"
|
|
#include "file.h"
|
|
#include "utils.h"
|
|
#include "module.h"
|
|
#include "elf_types.h"
|
|
|
|
// sceKernelGetThreadmgrUIDClass is not available
|
|
// suspend/resume for vm returns 0x80020008
|
|
|
|
// sceKernelDeleteMutex not resolved by UVL
|
|
|
|
/*
|
|
TODO:
|
|
- Unload prxs
|
|
- Delete semaphores, events, callbacks, msg pipes, rw locks
|
|
*/
|
|
|
|
typedef struct {
|
|
char *library;
|
|
uint32_t nid;
|
|
void *function;
|
|
} PatchNID;
|
|
|
|
#define MAX_AUDIO_PORTS 3
|
|
#define MAX_SYNC_OBJECTS 3
|
|
#define MAX_GXM_PRGRAMS 16
|
|
#define MAX_UIDS 32
|
|
|
|
#define INVALID_UID -1
|
|
|
|
static int force_exit = 0;
|
|
|
|
static SceUID exit_thid = INVALID_UID;
|
|
|
|
static SceUID UVLTemp_id = INVALID_UID, UVLHomebrew_id = INVALID_UID;
|
|
static uint32_t hb_text_addr = 0;
|
|
static SceModuleInfo hb_mod_info;
|
|
|
|
static SceUID hb_fds[MAX_UIDS];
|
|
static SceUID hb_dfds[MAX_UIDS];
|
|
static SceUID hb_thids[MAX_UIDS];
|
|
static SceUID hb_semaids[MAX_UIDS];
|
|
static SceUID hb_mutexids[MAX_UIDS];
|
|
static SceUID hb_blockids[MAX_UIDS];
|
|
|
|
static int hb_audio_ports[MAX_AUDIO_PORTS];
|
|
|
|
static SceGxmContext *hb_gxm_context = NULL;
|
|
static SceGxmRenderTarget *hb_gxm_render = NULL;
|
|
static SceGxmShaderPatcher *hb_shader_patcher = NULL;
|
|
|
|
static SceGxmSyncObject *hb_sync_objects[MAX_SYNC_OBJECTS];
|
|
|
|
static SceGxmFragmentProgram *hb_fragment_programs[MAX_GXM_PRGRAMS];
|
|
static SceGxmShaderPatcherId hb_fragment_program_ids[MAX_GXM_PRGRAMS];
|
|
|
|
static SceGxmVertexProgram *hb_vertex_programs[MAX_GXM_PRGRAMS];
|
|
static SceGxmShaderPatcherId hb_vertex_program_ids[MAX_GXM_PRGRAMS];
|
|
|
|
int isValidElf(char *file) {
|
|
Elf32_Ehdr header;
|
|
ReadFile(file, &header, sizeof(Elf32_Ehdr));
|
|
if (header.e_magic != ELF_MAGIC || header.e_type != 0xFE04 || header.e_machine != 40) {
|
|
return 0;
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
SceModuleInfo *getElfModuleInfo(void *buf) {
|
|
Elf32_Ehdr *header = (Elf32_Ehdr *)buf;
|
|
Elf32_Phdr *program = (Elf32_Phdr *)((uint32_t)header + header->e_phoff);
|
|
|
|
uint32_t index = ((uint32_t)header->e_entry & 0xC0000000) >> 30;
|
|
uint32_t offset = (uint32_t)header->e_entry & 0x3FFFFFFF;
|
|
|
|
return (SceModuleInfo *)((uint32_t)buf + program[index].p_offset + offset);
|
|
}
|
|
|
|
void initHomebrewPatch() {
|
|
force_exit = 0;
|
|
|
|
exit_thid = INVALID_UID;
|
|
|
|
UVLTemp_id = INVALID_UID;
|
|
UVLHomebrew_id = INVALID_UID;
|
|
hb_text_addr = 0;
|
|
memset((void *)&hb_mod_info, 0, sizeof(SceModuleInfo));
|
|
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
hb_fds[i] = INVALID_UID;
|
|
hb_dfds[i] = INVALID_UID;
|
|
hb_thids[i] = INVALID_UID;
|
|
hb_semaids[i] = INVALID_UID;
|
|
hb_mutexids[i] = INVALID_UID;
|
|
hb_blockids[i] = INVALID_UID;
|
|
}
|
|
|
|
memset(hb_audio_ports, 0, sizeof(hb_audio_ports));
|
|
|
|
hb_gxm_context = NULL;
|
|
hb_gxm_render = NULL;
|
|
hb_shader_patcher = NULL;
|
|
|
|
memset(hb_sync_objects, 0, sizeof(hb_sync_objects));
|
|
memset(hb_fragment_programs, 0, sizeof(hb_fragment_programs));
|
|
memset(hb_fragment_program_ids, 0, sizeof(hb_fragment_program_ids));
|
|
memset(hb_vertex_programs, 0, sizeof(hb_vertex_programs));
|
|
memset(hb_vertex_program_ids, 0, sizeof(hb_vertex_program_ids));
|
|
}
|
|
|
|
void waitVblankStart() {
|
|
int i;
|
|
for (i = 0; i < 10; i++) {
|
|
sceDisplayWaitVblankStart();
|
|
}
|
|
}
|
|
|
|
void finishGxm() {
|
|
int i;
|
|
|
|
// Wait until rendering is done
|
|
sceGxmFinish(hb_gxm_context);
|
|
/*
|
|
// THIS CRASHES, WHY???
|
|
// Clean up allocations
|
|
for (i = 0; i < MAX_GXM_PRGRAMS; i++) {
|
|
if (hb_fragment_programs[i] != NULL)
|
|
sceGxmShaderPatcherReleaseFragmentProgram(hb_shader_patcher, hb_fragment_programs[i]);
|
|
|
|
if (hb_vertex_programs[i] != NULL)
|
|
sceGxmShaderPatcherReleaseVertexProgram(hb_shader_patcher, hb_vertex_programs[i]);
|
|
}
|
|
*/
|
|
// Wait until display queue is finished before deallocating display buffers
|
|
sceGxmDisplayQueueFinish();
|
|
|
|
// Clean up display queue
|
|
for (i = 0; i < MAX_SYNC_OBJECTS; i++) {
|
|
// Destroy the sync object
|
|
if (hb_sync_objects[i] != NULL)
|
|
sceGxmSyncObjectDestroy(hb_sync_objects[i]);
|
|
}
|
|
/*
|
|
// Unregister programs and destroy shader patcher
|
|
for (i = 0; i < MAX_GXM_PRGRAMS; i++) {
|
|
if (hb_fragment_program_ids[i] != NULL)
|
|
sceGxmShaderPatcherUnregisterProgram(hb_shader_patcher, hb_fragment_program_ids[i]);
|
|
|
|
if (hb_vertex_program_ids[i] != NULL)
|
|
sceGxmShaderPatcherUnregisterProgram(hb_shader_patcher, hb_vertex_program_ids[i]);
|
|
}
|
|
|
|
sceGxmShaderPatcherDestroy(hb_shader_patcher);
|
|
*/
|
|
// Destroy the render target
|
|
sceGxmDestroyRenderTarget(hb_gxm_render);
|
|
|
|
// Destroy the context
|
|
sceGxmDestroyContext(hb_gxm_context);
|
|
|
|
// Terminate libgxm
|
|
sceGxmTerminate();
|
|
}
|
|
|
|
void releaseAudioPorts() {
|
|
int i;
|
|
for (i = 0; i < MAX_AUDIO_PORTS; i++) {
|
|
sceAudioOutReleasePort(hb_audio_ports[i]);
|
|
}
|
|
}
|
|
|
|
void closeFileDescriptors() {
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_fds[i] >= 0)
|
|
sceIoClose(hb_fds[i]);
|
|
|
|
if (hb_dfds[i] >= 0)
|
|
sceIoDclose(hb_dfds[i]);
|
|
}
|
|
}
|
|
|
|
// TODO: delete sema
|
|
void signalSema() {
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_semaids[i] >= 0) {
|
|
int res = sceKernelSignalSema(hb_semaids[i], 1);
|
|
debugPrintf("Signal sema 0x%08X: 0x%08X\n", hb_semaids[i], res);
|
|
res = sceKernelDeleteSema(hb_semaids[i]);
|
|
debugPrintf("Delete sema 0x%08X: 0x%08X\n", hb_semaids[i], res);
|
|
}
|
|
}
|
|
}
|
|
|
|
// TODO: delete mutex
|
|
void unlockMutex() {
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_mutexids[i] >= 0) {
|
|
int res = sceKernelUnlockMutex(hb_mutexids[i], 1);
|
|
debugPrintf("Unlock mutex 0x%08X: 0x%08X\n", hb_mutexids[i], res);
|
|
}
|
|
}
|
|
}
|
|
|
|
void waitThreadEnd() {
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_thids[i] >= 0) {
|
|
//debugPrintf("Wait for 0x%08X\n", hb_thids[i]);
|
|
sceKernelWaitThreadEnd(hb_thids[i], NULL, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
int exitThread() {
|
|
debugPrintf("Exiting 0x%08X...\n", sceKernelGetThreadId());
|
|
signalSema();
|
|
unlockMutex();
|
|
debugPrintf("Wait for threads...\n");
|
|
waitThreadEnd();
|
|
waitVblankStart();
|
|
return sceKernelExitDeleteThread(0);
|
|
}
|
|
|
|
PatchNID patches_exit[] = {
|
|
{ "SceAudio", 0x02DB3F5F, exitThread }, // sceAudioOutOutput // crashes mGBA
|
|
|
|
{ "SceCtrl", 0x104ED1A7, exitThread }, // sceCtrlPeekBufferNegative
|
|
{ "SceCtrl", 0x15F96FB0, exitThread }, // sceCtrlReadBufferNegative
|
|
{ "SceCtrl", 0x67E7AB83, exitThread }, // sceCtrlReadBufferPositive
|
|
{ "SceCtrl", 0xA9C3CED6, exitThread }, // sceCtrlPeekBufferPositive
|
|
|
|
{ "SceGxm", 0x8734FF4E, exitThread }, // sceGxmBeginScene
|
|
|
|
//{ "SceDisplay", 0x5795E898, exitThread }, // sceDisplayWaitVblankStart
|
|
|
|
{ "SceLibKernel", 0x0C7B834B, exitThread }, // sceKernelWaitSema
|
|
{ "SceLibKernel", 0x174692B4, exitThread }, // sceKernelWaitSemaCB
|
|
{ "SceLibKernel", 0x1D8D7945, exitThread }, // sceKernelLockMutex
|
|
{ "SceLibKernel", 0x72FC1F54, exitThread }, // sceKernelTryLockMutex
|
|
{ "SceLibKernel", 0xE6B761D1, exitThread }, // sceKernelSignalSema
|
|
|
|
{ "SceThreadmgr", 0x1A372EC8, exitThread }, // sceKernelUnlockMutex
|
|
//{ "SceThreadmgr", 0x4B675D05, exitThread }, // sceKernelDelayThread
|
|
};
|
|
|
|
// TODO: maybe patch all imports?
|
|
void PatchHomebrew() {
|
|
int i;
|
|
for (i = 0; i < (sizeof(patches_exit) / sizeof(PatchNID)); i++) {
|
|
makeFunctionStub(findModuleImportByInfo(&hb_mod_info, hb_text_addr, patches_exit[i].library, patches_exit[i].nid), patches_exit[i].function);
|
|
}
|
|
|
|
force_exit = 1;
|
|
}
|
|
|
|
int exit_thread(SceSize args, void *argp) {
|
|
while (1) {
|
|
SceCtrlData pad;
|
|
sceCtrlPeekBufferPositive(0, &pad, 1);
|
|
|
|
if (holdButtons(&pad, SCE_CTRL_START, 1 * 1000 * 1000)) {
|
|
PatchHomebrew();
|
|
break;
|
|
}
|
|
|
|
sceKernelDelayThread(10 * 1000);
|
|
}
|
|
|
|
return sceKernelExitDeleteThread(0);
|
|
}
|
|
|
|
void loadElf(char *file) {
|
|
// Finish vita2dlib
|
|
finishVita2dLib();
|
|
/*
|
|
// Empty lists
|
|
fileListEmpty(©_list);
|
|
fileListEmpty(&mark_list);
|
|
fileListEmpty(&file_list);
|
|
*/
|
|
/*
|
|
// Free language container
|
|
freeLanguageContainer();
|
|
|
|
// Free heap
|
|
_free_vita_heap();
|
|
*/
|
|
// Init
|
|
initHomebrewPatch();
|
|
/*
|
|
scePowerSetBusClockFrequency(166); // that's actually gpu
|
|
scePowerSetConfigurationMode(0x00010880);
|
|
*/
|
|
// Load
|
|
uvl_load(file);
|
|
|
|
// Wait...otherwise it crashes
|
|
waitVblankStart();
|
|
|
|
// Clean up
|
|
if (force_exit) {
|
|
// Wait for exit thread to end
|
|
sceKernelWaitThreadEnd(exit_thid, NULL, NULL);
|
|
|
|
// Finish gxm
|
|
finishGxm();
|
|
|
|
// Release audio ports
|
|
releaseAudioPorts();
|
|
|
|
// Close file descriptors
|
|
closeFileDescriptors();
|
|
}
|
|
|
|
// Unmap gxm memories and free blocks
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_blockids[i] >= 0) {
|
|
int res;
|
|
|
|
void *mem = NULL;
|
|
if (sceKernelGetMemBlockBase(hb_blockids[i], &mem) < 0)
|
|
continue;
|
|
|
|
if (force_exit) {
|
|
res = sceGxmUnmapMemory(mem);
|
|
if (res < 0)
|
|
sceGxmUnmapVertexUsseMemory(mem);
|
|
if (res < 0)
|
|
sceGxmUnmapFragmentUsseMemory(mem);
|
|
}
|
|
|
|
res = sceKernelFreeMemBlock(hb_blockids[i]);
|
|
// debugPrintf("free 0x%08X (0x%08X): 0x%08X\n", mem, hb_blockids[i], res);
|
|
}
|
|
}
|
|
|
|
/*
|
|
// Init heap
|
|
_init_vita_heap();
|
|
|
|
// Load language
|
|
loadLanguage(language);
|
|
*/
|
|
// Reset lists
|
|
// resetFileLists();
|
|
|
|
// Init vita2dlib
|
|
initVita2dLib();
|
|
}
|
|
|
|
int sceKernelExitProcessPatchedHB(int res) {
|
|
// debugPrintf("%s\n", __FUNCTION__);
|
|
return 0;
|
|
}
|
|
|
|
int sceAudioOutOpenPortPatchedHB(int type, int len, int freq, int mode) {
|
|
int port = sceAudioOutOpenPort(type, len, freq, mode);
|
|
|
|
if (type < MAX_AUDIO_PORTS)
|
|
hb_audio_ports[type] = port;
|
|
|
|
return port;
|
|
}
|
|
|
|
int sceGxmCreateContextPatchedHB(const SceGxmContextParams *params, SceGxmContext **context) {
|
|
int res = sceGxmCreateContext(params, context);
|
|
hb_gxm_context = *context;
|
|
// debugPrintf("%s 0x%08X\n", __FUNCTION__, hb_gxm_context);
|
|
return res;
|
|
}
|
|
|
|
int sceGxmCreateRenderTargetPatchedHB(const SceGxmRenderTargetParams *params, SceGxmRenderTarget **renderTarget) {
|
|
int res = sceGxmCreateRenderTarget(params, renderTarget);
|
|
hb_gxm_render = *renderTarget;
|
|
// debugPrintf("%s 0x%08X\n", __FUNCTION__, hb_gxm_render);
|
|
return res;
|
|
}
|
|
|
|
int sceGxmShaderPatcherCreateVertexProgramPatchedHB(SceGxmShaderPatcher *shaderPatcher, SceGxmShaderPatcherId programId, const SceGxmVertexAttribute *attributes, unsigned int attributeCount, const SceGxmVertexStream *streams, unsigned int streamCount, SceGxmVertexProgram **vertexProgram) {
|
|
int res = sceGxmShaderPatcherCreateVertexProgram(shaderPatcher, programId, attributes, attributeCount, streams, streamCount, vertexProgram);
|
|
|
|
// debugPrintf("%s 0x%08X 0x%08X\n", __FUNCTION__, programId, *vertexProgram);
|
|
|
|
if (hb_shader_patcher == NULL)
|
|
hb_shader_patcher = shaderPatcher;
|
|
|
|
int i;
|
|
for (i = 0; i < MAX_GXM_PRGRAMS; i++) {
|
|
if (hb_vertex_program_ids[i] == NULL) {
|
|
hb_vertex_program_ids[i] = programId;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < MAX_GXM_PRGRAMS; i++) {
|
|
if (hb_vertex_programs[i] == NULL) {
|
|
hb_vertex_programs[i] = *vertexProgram;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
int sceGxmShaderPatcherCreateFragmentProgramPatchedHB(SceGxmShaderPatcher *shaderPatcher, SceGxmShaderPatcherId programId, SceGxmOutputRegisterFormat outputFormat, SceGxmMultisampleMode multisampleMode, const SceGxmBlendInfo *blendInfo, const SceGxmProgram *vertexProgram, SceGxmFragmentProgram **fragmentProgram) {
|
|
int res = sceGxmShaderPatcherCreateFragmentProgram(shaderPatcher, programId, outputFormat, multisampleMode, blendInfo, vertexProgram, fragmentProgram);
|
|
|
|
// debugPrintf("%s 0x%08X 0x%08X\n", __FUNCTION__, programId, *fragmentProgram);
|
|
|
|
if (hb_shader_patcher == NULL)
|
|
hb_shader_patcher = shaderPatcher;
|
|
|
|
int i;
|
|
for (i = 0; i < MAX_GXM_PRGRAMS; i++) {
|
|
if (hb_fragment_program_ids[i] == NULL) {
|
|
hb_fragment_program_ids[i] = programId;
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < MAX_GXM_PRGRAMS; i++) {
|
|
if (hb_fragment_programs[i] == NULL) {
|
|
hb_fragment_programs[i] = *fragmentProgram;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
int sceGxmSyncObjectCreatePatchedHB(SceGxmSyncObject **syncObject) {
|
|
int res = sceGxmSyncObjectCreate(syncObject);
|
|
|
|
int i;
|
|
for (i = 0; i < MAX_SYNC_OBJECTS; i++) {
|
|
if (hb_sync_objects[i] == NULL) {
|
|
// debugPrintf("%s 0x%08X %d\n", __FUNCTION__, *syncObject, i);
|
|
hb_sync_objects[i] = *syncObject;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
int sceKernelExitDeleteThreadPatchedHB(int status) {
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_thids[i] == sceKernelGetThreadId()) {
|
|
hb_thids[i] = INVALID_UID;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return sceKernelExitDeleteThread(status);
|
|
}
|
|
|
|
SceUID sceKernelCreateThreadPatchedHB(const char *name, SceKernelThreadEntry entry, int initPriority, int stackSize, SceUInt attr, int cpuAffinityMask, const SceKernelThreadOptParam *option) {
|
|
SceUID thid = sceKernelCreateThread(name, entry, initPriority, stackSize, attr, cpuAffinityMask, option);
|
|
|
|
// debugPrintf("%s 0x%08X\n", name, thid);
|
|
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_thids[i] < 0) {
|
|
hb_thids[i] = thid;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return thid;
|
|
}
|
|
|
|
SceUID sceKernelAllocMemBlockPatchedHB(const char *name, SceKernelMemBlockType type, int size, void *optp) {
|
|
SceUID blockid = sceKernelAllocMemBlock(name, type, size, optp);
|
|
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_blockids[i] < 0) {
|
|
hb_blockids[i] = blockid;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return blockid;
|
|
}
|
|
|
|
int sceKernelFreeMemBlockPatchedHB(SceUID uid) {
|
|
int res = sceKernelFreeMemBlock(uid);
|
|
|
|
if (res >= 0) {
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_blockids[i] == uid) {
|
|
hb_blockids[i] = INVALID_UID;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
SceUID sceIoOpenPatchedHB(const char *file, int flags, SceMode mode) {
|
|
SceUID fd = sceIoOpen(file, flags, mode);
|
|
|
|
if (fd >= 0) {
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_fds[i] < 0) {
|
|
hb_fds[i] = fd;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return fd;
|
|
}
|
|
|
|
int sceIoClosePatchedHB(SceUID fd) {
|
|
int res = sceIoClose(fd);
|
|
|
|
if (res >= 0) {
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_fds[i] == fd) {
|
|
hb_fds[i] = INVALID_UID;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
SceUID sceIoDopenPatchedHB(const char *dirname) {
|
|
SceUID dfd = sceIoDopen(dirname);
|
|
|
|
if (dfd >= 0) {
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_fds[i] < 0) {
|
|
hb_fds[i] = dfd;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return dfd;
|
|
}
|
|
|
|
int sceIoDclosePatchedHB(SceUID fd) {
|
|
int res = sceIoDclose(fd);
|
|
|
|
if (res >= 0) {
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_dfds[i] == fd) {
|
|
hb_dfds[i] = INVALID_UID;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
SceUID sceKernelCreateSemaPatchedHB(const char *name, SceUInt attr, int initVal, int maxVal, SceKernelSemaOptParam *option) {
|
|
SceUID semaid = sceKernelCreateSema(name, attr, initVal, maxVal, option);
|
|
|
|
if (semaid >= 0) {
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_semaids[i] < 0) {
|
|
hb_semaids[i] = semaid;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return semaid;
|
|
}
|
|
|
|
int sceKernelDeleteSemaPatchedHB(SceUID semaid) {
|
|
int res = sceKernelDeleteSema(semaid);
|
|
|
|
if (res >= 0) {
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_semaids[i] == semaid) {
|
|
hb_semaids[i] = INVALID_UID;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
SceUID sceKernelCreateMutexPatchedHB(const char *name, SceUInt attr, int initCount, SceKernelMutexOptParam *option) {
|
|
SceUID mutexid = sceKernelCreateMutex(name, attr, initCount, option);
|
|
|
|
if (mutexid >= 0) {
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_mutexids[i] < 0) {
|
|
hb_mutexids[i] = mutexid;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return mutexid;
|
|
}
|
|
|
|
int sceKernelDeleteMutexPatchedHB(SceUID mutexid) {
|
|
int res = sceKernelDeleteMutex(mutexid);
|
|
|
|
if (res >= 0) {
|
|
int i;
|
|
for (i = 0; i < MAX_UIDS; i++) {
|
|
if (hb_mutexids[i] == mutexid) {
|
|
hb_mutexids[i] = INVALID_UID;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
PatchNID patches_init[] = {
|
|
{ "SceAudio", 0x5BC341E4, sceAudioOutOpenPortPatchedHB },
|
|
|
|
{ "SceGxm", 0x207AF96B, sceGxmCreateRenderTargetPatchedHB },
|
|
{ "SceGxm", 0x4ED2E49D, sceGxmShaderPatcherCreateFragmentProgramPatchedHB },
|
|
{ "SceGxm", 0x6A6013E1, sceGxmSyncObjectCreatePatchedHB },
|
|
{ "SceGxm", 0xB7BBA6D5, sceGxmShaderPatcherCreateVertexProgramPatchedHB },
|
|
{ "SceGxm", 0xE84CE5B4, sceGxmCreateContextPatchedHB },
|
|
|
|
{ "SceIofilemgr", 0x422A221A, sceIoDclosePatchedHB },
|
|
{ "SceIofilemgr", 0xC70B8886, sceIoClosePatchedHB },
|
|
|
|
{ "SceLibKernel", 0x1BD67366, sceKernelCreateSemaPatchedHB },
|
|
{ "SceLibKernel", 0x1D17DECF, sceKernelExitDeleteThreadPatchedHB },
|
|
{ "SceLibKernel", 0x6C60AC61, sceIoOpenPatchedHB },
|
|
{ "SceLibKernel", 0x7595D9AA, sceKernelExitProcessPatchedHB },
|
|
{ "SceLibKernel", 0xA9283DD0, sceIoDopenPatchedHB },
|
|
{ "SceLibKernel", 0xC5C11EE7, sceKernelCreateThreadPatchedHB },
|
|
{ "SceLibKernel", 0xCB78710D, sceKernelDeleteMutexPatchedHB },
|
|
{ "SceLibKernel", 0xDB32948A, sceKernelDeleteSemaPatchedHB },
|
|
{ "SceLibKernel", 0xED53334A, sceKernelCreateMutexPatchedHB },
|
|
|
|
{ "SceSysmem", 0xA91E15EE, sceKernelFreeMemBlockPatchedHB },
|
|
{ "SceSysmem", 0xB9D5EBDE, sceKernelAllocMemBlockPatchedHB },
|
|
};
|
|
|
|
SceUID sceKernelCreateThreadPatchedUVL(const char *name, SceKernelThreadEntry entry, int initPriority, int stackSize, SceUInt attr, int cpuAffinityMask, const SceKernelThreadOptParam *option) {
|
|
exit_thid = sceKernelCreateThread("exit_thread", (SceKernelThreadEntry)exit_thread, 0x10000100, 0x1000, 0, 0, NULL);
|
|
if (exit_thid >= 0)
|
|
sceKernelStartThread(exit_thid, 0, NULL);
|
|
|
|
int i;
|
|
for (i = 0; i < (sizeof(patches_init) / sizeof(PatchNID)); i++) {
|
|
makeFunctionStub(findModuleImportByInfo(&hb_mod_info, hb_text_addr, patches_init[i].library, patches_init[i].nid), patches_init[i].function);
|
|
}
|
|
|
|
// debugPrintf("Module name: %s\n", hb_mod_info.name);
|
|
|
|
if (strcmp(hb_mod_info.name, "VitaShell.elf") == 0) {
|
|
_free_vita_heap();
|
|
}
|
|
|
|
return sceKernelCreateThread(name, entry, initPriority, stackSize, attr, cpuAffinityMask, option);
|
|
}
|
|
|
|
SceUID sceKernelAllocMemBlockPatchedUVL(const char *name, SceKernelMemBlockType type, int size, void *optp) {
|
|
SceUID blockid = sceKernelAllocMemBlock(name, type, size, optp);
|
|
|
|
// debugPrintf("%s %s: 0x%08X\n", __FUNCTION__, name, blockid);
|
|
|
|
if (strcmp(name, "UVLTemp") == 0) {
|
|
UVLTemp_id = blockid;
|
|
} else if (strcmp(name, "UVLHomebrew") == 0) {
|
|
UVLHomebrew_id = blockid;
|
|
|
|
void *buf = NULL;
|
|
int res = sceKernelGetMemBlockBase(UVLTemp_id, &buf);
|
|
// debugPrintf("sceKernelGetMemBlockBase: 0x%08X\n", res);
|
|
memcpy((void *)&hb_mod_info, (void *)getElfModuleInfo(buf), sizeof(SceModuleInfo));
|
|
}
|
|
|
|
return blockid;
|
|
}
|
|
|
|
int sceKernelGetMemBlockBasePatchedUVL(SceUID uid, void **basep) {
|
|
int res = sceKernelGetMemBlockBase(uid, basep);
|
|
|
|
if (uid != UVLTemp_id && uid != UVLHomebrew_id) {
|
|
hb_text_addr = (uint32_t)*basep;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
void PatchUVL() {
|
|
uint32_t sceKernelAllocMemBlockSyscall = extractSyscallStub((uint32_t)&sceKernelAllocMemBlock);
|
|
uint32_t sceKernelGetMemBlockBaseSyscall = extractSyscallStub((uint32_t)&sceKernelGetMemBlockBase);
|
|
uint32_t sceKernelCreateThreadFunction = extractFunctionStub((uint32_t)&sceKernelCreateThread);
|
|
|
|
uint32_t text_addr = ALIGN(extractFunctionStub((uint32_t)&uvl_load), 0x100000) - 0x100000;
|
|
|
|
int count = 0;
|
|
|
|
uint32_t i = 0;
|
|
while (i < 0x10000 && count < 3) {
|
|
uint32_t addr = text_addr + i;
|
|
uint32_t syscall = extractSyscallStub(addr);
|
|
uint32_t function = extractFunctionStub(addr);
|
|
|
|
if (syscall == sceKernelAllocMemBlockSyscall) {
|
|
makeFunctionStub(addr, sceKernelAllocMemBlockPatchedUVL);
|
|
count++;
|
|
} else if (syscall == sceKernelGetMemBlockBaseSyscall) {
|
|
makeFunctionStub(addr, sceKernelGetMemBlockBasePatchedUVL);
|
|
count++;
|
|
} else if (function == sceKernelCreateThreadFunction) {
|
|
makeFunctionStub(addr, sceKernelCreateThreadPatchedUVL);
|
|
count++;
|
|
}
|
|
|
|
if (syscall != -1 || function != -1) {
|
|
i += 0x10;
|
|
} else {
|
|
i += 4;
|
|
}
|
|
}
|
|
} |