sceKernelCanReleaseLibrary code

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
johnmph
Posts: 119
Joined: Sat Jul 23, 2005 11:48 pm

sceKernelCanReleaseLibrary code

Post by johnmph »

I tried some reverse engineering with sceKernelCanReleaseLibrary function.

Here what i found :

Structures (temporary name) :

Code: Select all

typedef struct ModuleLibRelease		// Module Library Release
{
 u32 unk1;							// ?
 struct ModuleLibRelease *next;		// Next structure
 u32 unk2;							// ?
 u16 unk3;							// ?
 u16 unk4;							// sceKernelCanReleaseLibrary verification (unk4 & 0x8)
} ModuleLibRelease;

typedef struct ModuleLib			// Module Library
{
 struct ModuleLib *next;			// Next structure
 u32 unk1[4];
 SceLibraryEntryTable *lib;			// Library pointer
 ModuleLibRelease *release;			// ModuleLibRelease pointer
} ModuleLib;

Functions :

mfic, mtic opcode informations based on http://forums.ps2dev.org/viewtopic.php?t=4598 post

Code: Select all


u32 sceKernelSuspendInterrupts (void)
{
 u32 i;


 asm(
		"mfic %0, $0\n"
		"mtic $0, $0\n"
		"nop\n"                               // For uncached (7 nop)
		"nop\n"
		"nop\n"
		"nop\n"
		"nop\n"
		"nop\n"
		"nop\n"
		: "=r"(i)
	);

 return i;
}

void sceKernelResumeInterrupts (u32 i)
{
 u32 temp;


 asm(
		"mtic %1, $0\n"
		"nop\n"                           // For uncached (7 nop)
		"nop\n"
		"nop\n"
		"nop\n"
		"nop\n"
		"nop\n"
		"nop\n"
		: "=r"(temp)
		: "r"(i)
	);
}

u32 sceKernelCanReleaseLibrary (SceLibraryEntryTable *lib)

// Reverse engineering of sceKernelCanReleaseLibrary function
// Return 0x0 if library lib can be release else error code

{
 ModuleLib *modLib;
 ModuleLibRelease *release;
 u32 i;


 // Suspend interrupts
 i = sceKernelSuspendInterrupts();


 modLib = (ModuleLib *) 0x8801AF40;		// Address of first structure in 1.50 version

 // Browse array
 while (modLib)
 {
  if (modLib->lib == lib) break;		// If library found, break

  modLib = modLib->next;			// Next structure
 }

 // If not found, exit
 if (!(modLib))
 {
  // Resume interrupts
  sceKernelResumeInterrupts(i);

  // OK
  return 0;
 }

 // Get the "release array"
 release = modLib->release;

 // Browse the array
 while (release)
 {
  if (!(release->unk4 & 0x8))			// Error, exit with error message and kprintf
  {
   kprintf("sceKernelCanReleaseLibrary : %s ...",lib->libname);

   // Resume interrupts
   sceKernelResumeInterrupts(i);

   return 0x8002013E;
  }

  release = release->next;			// Next structure
 }

 // Resume interrupts
 sceKernelResumeInterrupts(i);

 // OK
 return 0;
}


If you want unload a module which normally can not be unloaded, set modLib->release to NULL (for each library in module).

After you will be able to release the module (stop and unload).
hubevolution
Posts: 32
Joined: Wed Mar 17, 2004 6:59 pm

Post by hubevolution »

this will allow module unloading without patching it even if the module has the no_stop flag set on ?
johnmph
Posts: 119
Joined: Sat Jul 23, 2005 11:48 pm

Post by johnmph »

hubevolution wrote:this will allow module unloading without patching it even if the module has the no_stop flag set on ?
Yes you can but you must also patch the flag, this is a small function to unload a module :

Code: Select all


u32 modulePatchLibraryForRelease (SceLibraryEntryTable *lib)
{
 ModuleLib *modLib;
 u32 i;


 // Suspend interrups
 i = sceKernelSuspendInterrupts();


 modLib = (ModuleLib *) 0x8801AF40;		// Address of first structure in 1.50 version

 // Browse array
 while (modLib)
 {
  if (modLib->lib == lib) break;		// If library found, break

  modLib = modLib->next;				// Next structure
 }

 // If found, patch release pointer
 if (modLib) modLib->release = NULL;

 // Resume interrupts
 sceKernelResumeInterrupts(i);

 // OK
 return 0;
}

u32 modulePatchForRelease (const char *name)
{
 SceModule *mod;
 SceLibraryEntryTable *entryTable, *entryEnd;


 // Find module address
 mod = sceKernelFindModuleByName(name);

 // If bad module
 if ((((long) mod) & 0xFF000000) != 0x88000000) return 1;
 if &#40;&#40;mod->stub_top - mod->ent_top&#41; < 40&#41; return 1;

 // Patch attributes
 mod->attribute = 0x1006;

 // Find entry table info
 entryTable = &#40;SceLibraryEntryTable *&#41; &#40;&#40;u32 *&#41; mod->ent_top&#41;;
 entryEnd = &#40;SceLibraryEntryTable *&#41; &#40;&#40;&#40;u8 *&#41; mod->ent_top&#41; + mod->ent_size&#41;;

 // Entry loop
 while &#40;entryTable < entryEnd&#41;
 &#123;
  if &#40;entryTable->libname&#41;
  &#123;
   // Patch library for release
   modulePatchLibraryForRelease&#40;entryTable&#41;;
  &#125;

  // Next entry
  entryTable = &#40;SceLibraryEntryTable *&#41; &#40;&#40;&#40;u32 *&#41; entryTable&#41; + entryTable->len&#41;;
 &#125;

 return 0;
&#125;

u32 moduleUnload &#40;const char *name&#41;
&#123;
 SceModule *mod;
 SceUID modid;
 u32 ret;


 // Patch module
 modulePatchForRelease&#40;name&#41;;

 // Find module address
 mod = sceKernelFindModuleByName&#40;name&#41;;

 // If not found, exit
 if &#40;!&#40;mod&#41;&#41; return SCE_KERNEL_ERROR_UNKNOWN_MODULE;

 // Stop module
 modid = mod->modid;

 ret = sceKernelStopModule&#40;modid,0,NULL,NULL,NULL&#41;;
 if &#40;!&#40;ret & 0x80000000&#41;&#41; ret = sceKernelUnloadModule&#40;modid&#41;;

 return ret;
&#125;

I tried with sceVaudio_driver module and it works.
hubevolution
Posts: 32
Joined: Wed Mar 17, 2004 6:59 pm

Post by hubevolution »

well great work at least a clean method to unload modules !
hubevolution
Posts: 32
Joined: Wed Mar 17, 2004 6:59 pm

Post by hubevolution »

I tried to unload sysmem.prx (sceSystemMemoryManager) but when I realod it from a simulated flash0: (mounted on the memstick) psp crashes ... I can unload and reload many other modules but sysmem.prx seems that cannot be unloaded ... even tried to do the unload/reload between disabling/reenabling interrupts but no way ... any clue ?
Fanjita
Posts: 217
Joined: Wed Sep 28, 2005 9:31 am

Post by Fanjita »

hubevolution wrote:I tried to unload sysmem.prx (sceSystemMemoryManager) but when I realod it from a simulated flash0: (mounted on the memstick) psp crashes ... I can unload and reload many other modules but sysmem.prx seems that cannot be unloaded ... even tried to do the unload/reload between disabling/reenabling interrupts but no way ... any clue ?
PResumably that module holds some state info about the memory allocation in the system, and you'd need to find some way to save / reinject that state into the new module?
Got a v2.0-v2.80 firmware PSP? Download the eLoader here to run homebrew on it!
The PSP Homebrew Database needs you!
hubevolution
Posts: 32
Joined: Wed Mar 17, 2004 6:59 pm

Post by hubevolution »

that means that unloading the module will cause the previous memory allocation "tables/infos" to be lost ... and when reloading the module it will start from scratch without knowing that there was previously allocated memory corrupting it and failing access to that when requested ... that sounds realistic !
Mirko-psp
Posts: 6
Joined: Tue Mar 14, 2006 5:15 am

Post by Mirko-psp »

hey hube ;)

MPH you have load the sysmem.prx on mph gameloader???
Post Reply