PSP Emulator
FLASH0
|-- codepage
| `-- cptbl.dat
|-- data
| `-- cert
| `-- CA_LIST.cer
|-- font
| |-- arib.pgf
| |-- gb3s1518.bwfon
| |-- imagefont.bin
| |-- jpn0.pgf
| |-- kr0.pgf
| |-- ltn0.pgf
| |-- ltn10.pgf
| |-- ltn11.pgf
| |-- ltn12.pgf
| |-- ltn13.pgf
| |-- ltn14.pgf
| |-- ltn15.pgf
| |-- ltn1.pgf
| |-- ltn2.pgf
| |-- ltn3.pgf
| |-- ltn4.pgf
| |-- ltn5.pgf
| |-- ltn6.pgf
| |-- ltn7.pgf
| |-- ltn8.pgf
| `-- ltn9.pgf
|-- kd
| |-- amctrl.prx
| |-- audiocodec_260.prx
| |-- avcodec.prx
| |-- cert_loader.prx
| |-- chkreg.prx
| |-- chnnlsv.prx
| |-- dmacman.prx
| |-- exceptionman.prx
| |-- exitgame.prx
| |-- g729.prx
| |-- ge_2.prx
| |-- ge.prx
| |-- http_storage.prx
| |-- ifhandle.prx
| |-- impose_kermit.prx
| |-- init.prx
| |-- interruptman.prx
| |-- iofilemgr_dnas.prx
| |-- iofilemgr.prx
| |-- isofs.prx
| |-- kermit_2.prx
| |-- kermit_audio.prx
| |-- kermit_ctrl.prx
| |-- kermit_display.prx
| |-- kermit_flashfs.prx
| |-- kermit_hpremote.prx
| |-- kermit_idstorage.prx
| |-- kermit_lowio.prx
| |-- kermit_me_wrapper.prx
| |-- kermit_msemu.prx
| |-- kermit_msfs.prx
| |-- kermit_netconf_dialog.prx
| |-- kermit_osk_plugin.prx
| |-- kermit_peripheral.prx
| |-- kermit_power.prx
| |-- kermit.prx
| |-- kermit_rtc.prx
| |-- kermit_usb.prx
| |-- kermit_utility.prx
| |-- kermit_wlan_2.prx
| |-- kermit_wlan.prx
| |-- libaac.prx
| |-- libasfparser.prx
| |-- libatrac3plus.prx
| |-- libaudiocodec2.prx
| |-- libdnas_core.prx
| |-- libdnas.prx
| |-- libgameupdate.prx
| |-- libhttp.prx
| |-- libmp3.prx
| |-- libmp4.prx
| |-- libparse_http.prx
| |-- libparse_uri.prx
| |-- libssl.prx
| |-- libupdown.prx
| |-- loadcore.prx
| |-- loadexec_01g.prx
| |-- mcctrl.prx
| |-- mediasync.prx
| |-- memab.prx
| |-- memlmd_01g_2.prx
| |-- memlmd_01g.prx
| |-- mesg_led_01g.prx
| |-- mgvideo.prx
| |-- modulemgr.prx
| |-- mp4msv.prx
| |-- mpegbase_260.prx
| |-- mpeg.prx
| |-- np9660.prx
| |-- np_auth.prx
| |-- np_commerce2.prx
| |-- np_commerce2_regcam.prx
| |-- np_commerce2_store.prx
| |-- np_core.prx
| |-- npdrm.prx
| |-- np_inst.prx
| |-- np_matching2.prx
| |-- np.prx
| |-- np_service.prx
| |-- openpsid.prx
| |-- psheet.prx
| |-- pspnet_adhoc_auth.prx
| |-- pspnet_adhocctl.prx
| |-- pspnet_adhoc_discover.prx
| |-- pspnet_adhoc_download.prx
| |-- pspnet_adhoc_matching.prx
| |-- pspnet_adhoc.prx
| |-- pspnet_adhoc_transfer_int.prx
| |-- pspnet_apctl_2.prx
| |-- pspnet_apctl.prx
| |-- pspnet_inet_2.prx
| |-- pspnet_inet.prx
| |-- pspnet.prx
| |-- pspnet_resolver.prx
| |-- pspnet_upnp.prx
| |-- pspnet_wispr.prx
| |-- registry.prx
| |-- resource
| | `-- impose_05g.rsc
| |-- sc_sascore.prx
| |-- sircs.prx
| |-- sysmem.prx
| |-- systimer.prx
| |-- threadman.prx
| |-- usbacc.prx
| |-- usbcam.prx
| |-- usbgps.prx
| |-- usbmic.prx
| |-- usbpspcm.prx
| |-- usersystemlib.prx
| |-- vaudio.prx
| `-- videocodec_260.prx
|-- pspbtcnf.bin
|-- reboot.bin
`-- vsh
|-- etc
| |-- index_01g.dat
| `-- version.txt
|-- module
| |-- auth_plugin.prx
| |-- auto_connect.prx
| |-- common_gui.prx
| |-- common_util.prx
| |-- dd_helper.prx
| |-- dd_helper_utility.prx
| |-- dialogmain.prx
| |-- dnas_plugin.prx
| |-- file_parser_base.prx
| |-- game_install_plugin.prx
| |-- htmlviewer_ui.prx
| |-- htmlviewer_utility.prx
| |-- hvauth_r.prx
| |-- libfont_hv.prx
| |-- libslim.prx
| |-- libwww.prx
| |-- msgdialog_plugin.prx
| |-- netconf_plugin.prx
| |-- netfront.prx
| |-- netplay_server2_utility.prx
| |-- netplay_server_plus_utility.prx
| |-- netplay_server_utility.prx
| |-- npinstaller_plugin.prx
| |-- npsignin_plugin.prx
| |-- npsignup_plugin.prx
| |-- pafmini.prx
| |-- ps3scan_plugin.prx
| |-- psn_utility.prx
| |-- savedata_auto_dialog.prx
| |-- savedata_utility.prx
| |-- screenshot_plugin.prx
| |-- store_browser_plugin.prx
| |-- store_checkout_plugin.prx
| `-- store_checkout_utility.prx
`-- resource
|-- auth_plugin.rco
|-- dd_helper.rco
|-- dnas_plugin.rco
|-- game_install_plugin.rco
|-- htmlviewer.res
|-- msgdialog_plugin.rco
|-- netconf_dialog.rco
|-- netplay_plugin.rco
|-- npinstaller_plugin.rco
|-- npsignin_plugin.rco
|-- npsignup_plugin.rco
|-- ps3scan_plugin.rco
|-- psn_plugin.rco
|-- savedata_utility.rco
|-- screenshot_plugin.rco
|-- store_browser_plugin.rco
|-- store_checkout_plugin.rco
`-- system_plugin.rco
FLASH0 1.80 changes
|-- font
| |-- arib.pgf removed
|-- kd
| |-- kermit_me_wrapper_2.prx added
| |-- pops_01g.prx added
| |-- popsman.prx added
|-- vsh
|-- module
|-- libpspvmc.prx added
Flash0 Dump code
Please use responsibly.
int kthread(SceSize args, void *argp)
{
// Find File Manager Module
SceModule2 * iofilemgr = _sceKernelFindModuleByName("sceIOFileManager");
// Find required Functions
KernelIOOpen = (void *)iofilemgr->text_addr + IOFILEMGR_IO_OPEN;
KernelIOWrite = (void *)iofilemgr->text_addr + IOFILEMGR_IO_WRITE;
KernelIOClose = (void *)iofilemgr->text_addr + IOFILEMGR_IO_CLOSE;
flashVitaDump( GAME_SAVE_PATH "h.bin"/*"flashVitaDump.zip"*/ );
return 0;
}
void initKernelThread(void)
{
SceModule2 *threadman = _sceKernelFindModuleByName("sceThreadManager");
_sceKernelCreateThread = (void *)((u32)threadman->text_addr + THREADMAN_CREATE_THREAD);
_sceKernelStartThread = (void *)((u32)threadman->text_addr + THREADMAN_START_THREAD);
SceUID kthreadID = _sceKernelCreateThread( "Kernel thread", KERNELIFY(kthread), 25, 0x10000, 0, NULL );
if (kthreadID >= 0) _sceKernelStartThread(kthreadID, 0, NULL);
else PRTSTR1("Error: sceKernelCreateThread -> 0x%08lX\n", kthreadID);
}
struct minZipHeader {
char pk[2];
unsigned nb;
char space[12];
unsigned fileSize;
unsigned fileSizeClone;
unsigned pathLen;
/*
path
data
*/
};
typedef struct{
char *name;
void *content;
u32 size;
}VitaFlashBufferFile;
unsigned addWriteFile( SceUID packFileID, void *data, unsigned size, char *name, u8 found_nb )
{
const char *root = "flash0";
char path[256];
strcpy(path, root);
// If file name has no / at first, add it
if ( name[0] != '/' )
path[strlen(path)+1] = 0, path[strlen(path)] = '/';
strcat(path, name);
// If file was already dumped, add custom name suffix
if ( found_nb > 1) strcat(path, ".bakX"), path[strlen(path)-1] = '0'+found_nb-2;
// Write Data
struct minZipHeader zHead;
strcpy(zHead.pk, "PK");
zHead.nb = 0x000A0403;
memset(zHead.space, 0, sizeof(zHead.space));
zHead.fileSize = size;
zHead.fileSizeClone = size;
zHead.pathLen = strlen(path);
KernelIOWrite(packFileID, &(zHead.pk), 2);
KernelIOWrite(packFileID, &(zHead.nb), sizeof(u32));
KernelIOWrite(packFileID, &(zHead.space), sizeof(zHead.space));
KernelIOWrite(packFileID, &(zHead.fileSize), sizeof(u32));
KernelIOWrite(packFileID, &(zHead.fileSizeClone), sizeof(u32));
KernelIOWrite(packFileID, &(zHead.pathLen), sizeof(u32));
KernelIOWrite(packFileID, path, zHead.pathLen);
unsigned written = KernelIOWrite(packFileID, data, size);
return written;
}
int findFlashIndex( const VitaFlashBufferFile *f0, void *origContent )
{
int flash0_filecount = 0;
while ( origContent != f0[flash0_filecount].content && f0[flash0_filecount].name != NULL )
++flash0_filecount;
if ( f0[flash0_filecount].name == NULL ) return -1;
else return flash0_filecount;
}
void flashVitaDump( char *packName )
{
uint32_t sonyF0 = 0x8B000000;
uint32_t sonyF0Backup = 0x8BF00000;
int flash0_fileindex = 0;
uint32_t totalwrite = 0;
int isValid, i;
int dummy_count = 0;
int backup_count = 0;
char *name = NULL;
u8 found_f0[512];
for ( i=0; i<sizeof(found_f0); ++i ) found_f0[i] = 0;
const VitaFlashBufferFile * f0 = (VitaFlashBufferFile *)sonyF0;
SceUID packFileID = KernelIOOpen(packName, PSP_O_WRONLY | PSP_O_CREAT, 0777);
if (packFileID)
{
setPrintColorRGB(255, 0, 0);
PRTSTR0("");
PRTSTR0("Dumping flash");
PRTSTR0("");
setPrintColorRGB(0, 255, 255);
// Write all found flash files
while ( f0[flash0_fileindex].name != NULL )
{
name = f0[flash0_fileindex].name;
isValid = 0;
if ( name[strlen(name)-3] == 'p' && name[strlen(name)-2] == 'r' && name[strlen(name)-1] == 'x' )
{
switch ( *((int*)f0[flash0_fileindex].content) )
{
case 0x5053507E:
isValid = 1;
break;
case 0:
dummy_count++;
break;
default:
PRTSTR0("Unknown prx : %08lX", name);
isValid = 1;
break;
}
}
else isValid = 1;
if ( isValid )
{
found_f0[flash0_fileindex]++;
PRTSTR0("Writing file ...");
totalwrite += addWriteFile( packFileID, f0[flash0_fileindex].content, f0[flash0_fileindex].size, name, found_f0[flash0_fileindex] );
PRTSTR0("File dumped");
}
else
{
//PRTSTR0("Invalid flash file : %08lX", name);
PRTSTR0("Dummied flash file");
}
++flash0_fileindex;
}
uint32_t *curf0Backup = sonyF0Backup;
setPrintColorRGB(255, 0, 0);
PRTSTR0("");
PRTSTR0("Dumping flash backup");
PRTSTR0("");
setPrintColorRGB(0, 255, 255);
// Write all found flash backups
while ( *curf0Backup != NULL )
{
uint32_t origContent = *curf0Backup;
flash0_fileindex = findFlashIndex(f0, origContent);
unsigned size = *(curf0Backup+1);
curf0Backup += 2;
if ( flash0_fileindex >= 0 )
{
found_f0[flash0_fileindex]++;
name = f0[flash0_fileindex].name;
PRTSTR0("Writing file ...");
totalwrite += addWriteFile( packFileID, curf0Backup, size, name, found_f0[flash0_fileindex] );
backup_count++;
PRTSTR0("File dumped");
}
else
{
PRTSTR0("%08lX not found", origContent);
// Quit because usually means a general error
break;
}
curf0Backup += size/4 + 1;
}
KernelIOClose(packFileID);
//PRTSTR0("Dummy files: %08lX, backup files: %08lX ", dummy_count, backup_count);
setPrintColorRGB(255, 0, 0);
PRTSTR0("");
PRTSTR0("Flash successfully dumped");
PRTSTR0("");
setPrintColorRGB(0, 255, 255);
}
}
PSP Memory Layout
Address
|
Size
|
Comments
|
0x00010000
|
0x4000
|
CPU Scratchpad
|
0x04000000
|
2 MB/4 MB
|
VRAM/Framebuffer
|
0x08000000
|
64 MB
|
Main Memory
|
0xBFC00000
|
0x1000
|
Shared SRAM
|
SceGrab
Address
|
Size
|
Comments
|
0xE8300120
|
4
|
Paddr of CDRAM base + 1, maps to 0x88000000?
|
0xE8300124
|
4
|
Paddr of CDRAM base + 0x1000000 + 1
|
0xE8300128
|
4
|
Paddr of CDRAM base + 0x2000000 + 1
|
0xE830012C
|
4
|
Paddr of flash0 in CDRAM (base + 0x3000000) + 1, maps to 0x3000000?
|
SceCompatLCDDMA
Address
|
Size
|
Comments
|
0xE5071004
|
4
|
set 1 when done
|
0xE5071024
|
4
|
0xFF0000
|
0xE5071028
|
4
|
0x0
|
0xE5071030
|
4
|
some status
|
0xE5071034
|
4
|
Width pixels
|
0xE5071038
|
4
|
0x0
|
0xE507103C
|
4
|
Hight pixels
|
0xE5071040
|
4
|
0x0
|
0xE507104C
|
4
|
DMA Paddr
|
0xE5071078
|
4
|
0x0
|
0xE5071084
|
4
|
0x0
|
0xE5071050
|
4
|
2048
|
0xE5071094
|
4
|
2
|
0xE5071098
|
4
|
1
|
0xE50710C0
|
4
|
busy status? (set 0x1000000 when done)
|
Compatibility Settings
Emulator file stores compatibility settings for 898 Title IDs (as of 3.65 firmware). Additionally, settings can be supplied by __sce_menuinfo or title_specific.bin files. Title IDs are hidden under simple hash, which Sony borrowed from PSP POPS. That's not only similarity between two compatibility systems. Same like on POPS single config entry have 4 bytes ID and 4 bytes value, also here Sony decided to start count from -1, so config ID are in range of -1 - 0x1F. Which gives 33 possible settings per game.
Warning! Current version of Vita Adrenaline seems to break internal table settings and use own values in ScePspemuInitTitleSpecificInfoPatched. This is probably reasoning why some games run better outside of Adrenaline (in ARK for example).
Title ID Hash generator
def checksum(string):
x = string[0:4].encode('ascii').hex()
x = int(x, 16)
#print(hex(x))
y = string[4:]
y = int(y, 16)
y = y + (y << 12)
#print(hex(y))
suma = x ^ y
print(hex(suma))
checksum("ULUS01986")
Compatibility Flags Values
Command ID |
Bitfield |
Notes
|
0xFFFFFFFF |
Yes |
Multi command
|
0x00 |
Unk |
|
0x01 |
Unk |
|
0x02 |
Unk |
|
0x03 |
Unk |
|
0x04 |
Unk |
|
0x05 |
Unk |
|
0x06 |
Unk |
|
0x07 |
Unk |
|
0x08 |
Unk |
|
0x09 |
Unk |
|
0x0A |
Unk |
|
0x0B |
No |
Game patches (info taken from Adrenaline)
0x01: UCUS98687 Twisted Metal: Head-On
0x02: UCES00018 Twisted Metal: Head-On
0x03: NPJG00115 INFLUENCE
0x04: ULJM05500 Monster Hunter Portable 2nd G
0x05: ULJM05800 Monster Hunter Portable 3rd
0x06: ULES00851 Monster Hunter Freedom 2
0x07: ULES01213 Monster Hunter Freedom Unite
0x08: UCES01563 Geronimo Stilton: Return to the Kingdom of Fantasy
0x09: NPUG80850 Geronimo Stilton: Return to the Kingdom of Fantasy
0x0A: NPJH00039 Hatsune Miku: Project Diva - Tsuika Gakkyoku Shuu Deluxe Pack 1 - Miku Uta, Okawar
0x0B: NPJH00040 Hatsune Miku: Project Diva - Tsuika Gakkyoku Shuu Deluxe Pack 2 - Motto Okawari Rin, Len, Luka
0x0C: NPJH50594 Jikkyou Powerful Pro Yakyuu 2012
0x0D: NPJH50708 Jikkyou Powerful Pro Yakyuu 2012 Ketteiban
0x0E: ULES00981 Star Wars: The Force Unleashed
0x0F: ULUS10345 Star Wars: The Force Unleashed
0x10: ULUS10088 Field Commander
0x11: NPUH10091 Pool Hall Pro
0x12: ULES00821 World of Pool
|
0x0C |
Unk |
|
0x0D |
Unk |
|
0x0E |
Unk |
|
0x0F |
Unk |
|
0x10 |
Unk |
|
0x11 |
Unk |
|
0x12 |
Unk |
|
0x13 |
Unk |
|
0x14 |
Unk |
|
0x15 |
Unk |
|
0x16 |
Unk |
|
0x17 |
Unk |
|
0x18 |
Unk |
|
0x19 |
Unk |
|
0x1A |
Unk |
|
0x1B |
Unk |
|
0x1C |
Unk |
|
0x1D |
Unk |
|
0x1E |
Yes |
|
0x1F |
Unk |
|