PSP Emulator

From Vita Developer wiki
Revision as of 11:03, 5 November 2023 by Kozarovv (talk | contribs)
Jump to navigation Jump to search

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