Full Code of DaveeFTW/Chronoswitch for AI

master c57a8b7d1039 cached
45 files
170.4 KB
72.8k tokens
134 symbols
1 requests
Download .txt
Repository: DaveeFTW/Chronoswitch
Branch: master
Commit: c57a8b7d1039
Files: 45
Total size: 170.4 KB

Directory structure:
gitextract_gl9obiy7/

├── README.md
└── src/
    ├── Makefile
    ├── Makefile.hbl
    ├── Makefile.signed
    ├── downgrade660_ctrl/
    │   ├── 660mapfile.txt
    │   ├── Makefile
    │   ├── decrypt.c
    │   ├── decrypt.h
    │   ├── exports.exp
    │   ├── extra_stubs.S
    │   ├── main.c
    │   ├── patch_table.c
    │   ├── patch_table.h
    │   ├── pspdecrypt.c
    │   ├── utils.c
    │   └── utils.h
    ├── downgrade_ctrl/
    │   ├── 631mapfile.txt
    │   ├── Makefile
    │   ├── decrypt.c
    │   ├── decrypt.h
    │   ├── exports.exp
    │   ├── extra_stubs.S
    │   ├── main.c
    │   ├── patch_table.c
    │   ├── patch_table.h
    │   ├── pspdecrypt.c
    │   ├── utils.c
    │   └── utils.h
    ├── extra_stubs.S
    ├── extras.S
    ├── include/
    │   ├── libinfinity.h
    │   └── systemctrl.h
    ├── kernel_exploit.c
    ├── kernel_exploit.h
    ├── kernel_land.c
    ├── kernel_land.h
    ├── lib/
    │   └── libpspsystemctrl_kernel.a
    ├── libasm/
    │   ├── libinfinityKernel.S
    │   └── libinfinityUser.S
    ├── main.c
    ├── patch_table.h
    ├── rebootex.c
    ├── rebootex.h
    ├── utils.c
    └── utils.h

================================================
FILE CONTENTS
================================================

================================================
FILE: README.md
================================================
# Chronoswitch Downgrader
Chronoswitch is a downgrader for the Playstation Portable (PSP).

## Installation
Download and extract the latest version from the releases on this github page. Copy the `PSP` folder from the extracted output to your memory stick. You will need the firmware update for version you wish to downgrade to. If you want to downgrade to 6.20, you will need the 6.20 official update. If you're downgrading a PSPgo, make sure you download the official firmware appropriate for that device.

Copy the official firmware update to `PSP/GAME/UPDATE/EBOOT.PBP` on your memory stick. If you're using a PSPgo, make sure this copied to the internal storage instead.

The downgrader is "signed", and can be launched without having a custom firmware installed. Once you run the application, follow the on-screen instructions.

## Changelog
### Version 7.0
* Added support for Infinity.
### Version 6.1
* Added support for downgrading 11g units to 6.60.
### Version 6.0
* Added support for 6.61.
### Version 5.0
* Added support for downgrading 09g units to 6.20.

## Thanks to
* some1
* bbtgp
* coyotebean
* kgsws
* Silverspring
* Bubbletune
* qwikrazor87

## Socials
Follow me on Twitter [@DaveeFTW](https://twitter.com/DaveeFTW), and check out [my blog](https://lolhax.org).


================================================
FILE: src/Makefile
================================================
all: clean clean_prx signed

clean: clean_prx
	make -f Makefile.signed clean

clean_prx:
	make -C downgrade_ctrl -f Makefile clean
	make -C downgrade660_ctrl -f Makefile clean
	
signed: clean_prx mk_downgrade_ctrl
	make -f Makefile.signed
	
hbl: clean_prx mk_downgrade_ctrl
	make -f Makefile.hbl
	
remove_dir:
	-rmdir /S /Q RELEASE

create_dir:
	-mkdir RELEASE
	-mkdir RELEASE\PSP
	-mkdir RELEASE\PSP\GAME
	-mkdir RELEASE\PSP\GAME\Downgrader
	-mkdir RELEASE\SRC
	
copy_src:
	cp -dpR downgrade_ctrl\.. RELEASE\SRC
	rmdir /S /Q RELEASE\SRC\RELEASE
	
mk_downgrade_ctrl:
	make -C downgrade_ctrl -f Makefile
	make -C downgrade660_ctrl -f Makefile

signed_release: clean clean_prx remove_dir create_dir copy_src signed
	cp EBOOT.PBP RELEASE\PSP\GAME\Downgrader\EBOOT.PBP
	
hbl_release: clean clean_prx remove_dir create_dir copy_src hbl
	cp EBOOT.PBP RELEASE\PSP\GAME\Downgrader\EBOOT.PBP

================================================
FILE: src/Makefile.hbl
================================================
TARGET = downgrader
OBJS = main.o kernel_exploit.o kernel_land.o rebootex.o utils.o extras.o extra_stubs.o

INCDIR = ../include
CFLAGS = -Os -G0 -Wall -DHBL_SUKKIRI
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS) -c
 
LIBDIR = ../lib
LIBS = -lpsppower

PSP_FW_VERSION = 271

EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = 6.35 Downgrader

BUILD_PRX = 1

PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak



================================================
FILE: src/Makefile.signed
================================================
release: all
	bin/prxEncrypter $(TARGET).prx
	pack-pbp $(EXTRA_TARGETS) PARAM.SFO icon0.png NULL NULL NULL NULL data.psp NULL
	rm -f data.psp
	rm -f downgrade_ctrl.h
	rm -f downgrade660_ctrl.h

TARGET = downgrader
OBJS = main.o kernel_exploit.o kernel_land.o rebootex.o utils.o extras.o extra_stubs.o libasm/libinfinityUser.o

INCDIR = ../include
CFLAGS = -Os -G0 -Wall
CXXFLAGS = $(CFLAGS) -fno-exceptions -fno-rtti
ASFLAGS = $(CFLAGS) -c
 
LIBDIR = ../lib
LIBS = -lpsppower

PSP_FW_VERSION = 271

EXTRA_TARGETS = EBOOT.PBP
PSP_EBOOT_TITLE = Chronoswitch Downgrader

BUILD_PRX = 1

PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak



================================================
FILE: src/downgrade660_ctrl/660mapfile.txt
================================================
@SysMemForKernel
0x55A40B2C:0xC4EEAF20 //NID RESOLVED
0x9697CD32:0x13F4A0DE //NID RESOLVED
0xB2C7AA36:0x83B5226D //NID RESOLVED
0x3FC9AE6A:0xC886B169 //NID RESOLVED
0x6373995D:0x07C586A1 //NID RESOLVED
@memlmd
0x7CF1CD3E:0xEF73E85B //NID RESOLVED
@LoadCoreForKernel
0xCF8A41B1:0xF6B1BF0F //NID RESOLVED
0xCCE4A157:0x40972E6E //NID RESOLVED
0xD8779AC6:0x8D46E9DF //NOT exported
@ModuleMgrForKernel
0x644395E2:0x303FAB7F //NID RESOLVED


================================================
FILE: src/downgrade660_ctrl/Makefile
================================================
release: all
	psp-fixup-imports -m $(PSP_FW_VERSION)mapfile.txt $(TARGET).prx
	psp-packer $(TARGET).prx
	bin2c $(TARGET).prx ../$(TARGET).h $(TARGET)
	
TARGET = downgrade660_ctrl
OBJS = main.o utils.o patch_table.o decrypt.o pspdecrypt.o extra_stubs.o ../libasm/libinfinityKernel.o

INCDIR = ../include
CFLAGS = -Os -G0 -Wall -fno-pic -fshort-wchar
ASFLAGS = $(CFLAGS)

BUILD_PRX = 1
PRX_EXPORTS = exports.exp

PSP_FW_VERSION = 660

USE_KERNEL_LIBS=1
USE_KERNEL_LIBC=1

LIBDIR = ../lib
LDFLAGS = -nostartfiles
LIBS = -lpspsystemctrl_kernel

PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak



================================================
FILE: src/downgrade660_ctrl/decrypt.c
================================================
/*
	Downgrade Control -> decrypt.c -> Responsible for decryption patches and hooks
	by Davee
	
	31/12/2010
*/

#include <pspkernel.h>
#include <pspsysmem_kernel.h>

#include <stdio.h>
#include <string.h>
#include <systemctrl.h>

#include "decrypt.h"
#include "patch_table.h"

int pspDecryptPRX(void *exec, u32 exec_size, u32 *out_size);

int (* sceMesgLed_driver_81F72B1F)(void *exec, u32 size, u32 *outsize) = NULL;
extern u32 g_spoof_ver;

int sceResmgr_9DC14891_patched(void *data, u32 datasize, u32 *outsize)
{
	/* call the original function to decrypt the index.dat */
	int res = sceResmgr_driver_9DC14891(data, datasize, outsize);
	
	/* if there is a firmware version, we will generate a version.txt to downgrade */
	if (g_spoof_ver)
	{
		sprintf( data,
				"release:%01X.%01X%01X:\n"
				"build:0000,0,3,1,0:builder@vsh-build6\n"
				"system:56422@release_%03X,0x%08X:\n"
				"vsh:p6576@release_%03X,v57929@release_%03X,20100625:\n"
				"target:1:WorldWide\n",
				/* first line, version (X.YZ) */ (g_spoof_ver >> 8) & 0xF, (g_spoof_ver >> 4) & 0xF, g_spoof_ver & 0xF,
				/* third line, release_XYZ + devkit */ g_spoof_ver, (((g_spoof_ver >> 8) & 0xF) << 24) | (((g_spoof_ver >> 4) & 0xF) << 16) | ((g_spoof_ver & 0xF) << 8) | 0x10,
				/* forth line, release_XYZ + release_XYZ */ g_spoof_ver, g_spoof_ver
				);
	}
	
	/* return the decryption result */
	return res;
}

void PatchMesgled(u32 text_addr)
{
	/* if firmware is >= 6.30 */
	if (sceKernelDevkitVersion() >= 0x06030010)
	{
		int model = sceKernelGetModel();
		if(model == 6 || model == 8)
		{
			model = 3;
		}
		
		/* Patch mesgled to allow older updaters to boot */
		_sw(0, text_addr + g_patch_table.new_updater_check[model]);
	}
}

int sceMesgLed_driver_81F72B1F_patched(void *exec, u32 exec_size, u32 *out_size)
{
	/* do sony decryption */
	int res = sceMesgLed_driver_81F72B1F(exec, exec_size, out_size);
	
	/* check for error */
	if (res != 0)
	{
		/* lets decrypt */
		res = pspDecryptPRX(exec, exec_size, out_size);
	}
	
	/* return result */
	return res;
}

int memlmd_7CF1CD3E_patched(void *exec, u32 exec_size, u32 *out_size)
{
	/* do sony decryption */
	int res = memlmd_7CF1CD3E(exec, exec_size, out_size);
	
	/* check for error */
	if (res != 0)
	{
		/* lets decrypt */
		res = pspDecryptPRX(exec, exec_size, out_size);
	}
	
	/* return result */
	return res;
}


================================================
FILE: src/downgrade660_ctrl/decrypt.h
================================================
/*
	Downgrade Control -> decrypt.h -> Provide API documentation and definitions
	by Davee
	
	31/12/2010
*/
#ifndef __DECRYPT_H__
#define __DECRYPT_H__

/* our functions */
void PatchMesgled(u32 text_addr);
int memlmd_7CF1CD3E_patched(void *exec, u32 exec_size, u32 *out_size);
int sceResmgr_9DC14891_patched(void *data, u32 datasize, u32 *outsize);
int sceMesgLed_driver_81F72B1F_patched(void *exec, u32 size, u32 *outsize);

extern int (* sceMesgLed_driver_81F72B1F)(void *exec, u32 size, u32 *outsize);

/* prototypes */
int memlmd_7CF1CD3E(void *exec, u32 exec_size, u32 *out_size);
int sceResmgr_driver_9DC14891(void *data, u32 datasize, u32 *outsize);
int sceUtilsBufferCopyWithRange(void *dst, u32 dst_size, void *src, u32 src_size, u32 cmd);
int sceUtilsBufferCopyByPollingWithRange(void *dst, u32 dst_size, void *src, u32 src_size, u32 cmd);
int sceKernelPowerLock(void);
int sceKernelPowerUnlock(void);

/* data structures */
typedef struct
{
	u32 tag;
	u8 key[16];
} mesgled_keys_struct;

typedef struct
{
	u32 signature; 		//0
	u16 mod_attribute; 	//4
	u16 comp_attribute;	//6
	u8 module_ver_lo;	//8
	u8 module_ver_hi;	//9
	char modname[28];	//0xA
	u8 mod_version;		//0x26
	u8 nsegments;		//0x27
	u32 elf_size;		//0x28
	u32 psp_size;		//0x2C
	u32 boot_entry;		//0x30
	u32 modinfo_offset; //0x34
	int bss_size;		//0x38
	u16 seg_align[4];	//0x3C
	u32 seg_address[4];	//0x44
	int seg_size[4];	//0x54
	u32 reserved[5];	//0x64
	u32 devkit_version;	//0x78
	u8 decrypt_mode;	//0x7C
	u8 padding;			//0x7D
	u16 overlap_size;	//0x7E
	u8 key_data[0x30];	//0x80
	u32 comp_size;		//0xB0
	int _80;			//0xB4
	u32 unk_B8;			//0xB8
	u32 unk_BC;			//0xBC
	u8 key_data2[0x10];	//0xC0
	u32 tag;			//0xD0
	u8 scheck[0x58];	//0xD4
	u8 sha1_hash[0x14];	//0x12C
	u8 key_data4[0x10]; //0x140
} PSP_Header2; //0x150

typedef struct
{
	u32 mode; //0
	u32 unk_4;
	u32 unk_8;
	u32 keyseed; //12
	u32 size; //16
} KIRK_CMD_HEADER; //20

#define KIRK_CMD_7		(7)
#define KIRK_CMD_SHA1	(0xB)

#endif /* __DECRYPT_H__ */


================================================
FILE: src/downgrade660_ctrl/exports.exp
================================================
# Define the exports for the prx
PSP_BEGIN_EXPORTS

# These four lines are mandatory (although you can add other functions like module_stop)
# syslib is a psynonym for the single mandatory export.
PSP_EXPORT_START(syslib, 0, 0x8000)
PSP_EXPORT_FUNC_NID(module_start,0xD3744BE0)
PSP_EXPORT_VAR_HASH(module_info)
PSP_EXPORT_END

PSP_END_EXPORTS


================================================
FILE: src/downgrade660_ctrl/extra_stubs.S
================================================
	.set noreorder

#include "pspstub.s"
	
	STUB_START	"sceResmgr_driver",0x00090011,0x00010005
	STUB_FUNC	0x9DC14891,sceResmgr_driver_9DC14891
	STUB_END
	
	STUB_START	"memlmd",0x00090011,0x00010005
	STUB_FUNC	0x7CF1CD3E,memlmd_7CF1CD3E
	STUB_END
	
	STUB_START	"semaphore",0x00090011,0x00020005
	STUB_FUNC	0x4C537C72,sceUtilsBufferCopyWithRange
	STUB_FUNC	0x77E97079,sceUtilsBufferCopyByPollingWithRange
	STUB_END

	STUB_START	"sceIdStorage_driver",0x00090011,0x00010005
	STUB_FUNC	0x6FE062D1,sceIdStorageLookup
	STUB_END

	STUB_START	"LoadCoreForKernel",0x00090011,0x00010005
	STUB_FUNC	0xBC99C625,_sceKernelFindModuleByAddress
	STUB_END


================================================
FILE: src/downgrade660_ctrl/main.c
================================================
/*
	Downgrade Control -> Restore kernel patches and enforce updater launch
	by Davee
	
	31/12/2010
*/

#include <pspkernel.h>
#include <pspidstorage.h>
#include <pspsysmem_kernel.h>

#include <stdio.h>
#include <string.h>
#include <systemctrl.h>
#include <libinfinity.h>

#include "utils.h"
#include "patch_table.h"
#include "decrypt.h"

PSP_MODULE_INFO("DowngraderCTRL", 0x3007, 1, 0);

/* function pointers */
int (* PrologueModule)(void *modmgr_param, SceModule2 *mod) = NULL;
STMOD_HANDLER previous = NULL;

typedef struct __attribute__((packed))
{
        int magic; // 0
        int version; // 4
        unsigned int keyofs; // 8
        unsigned int valofs; // 12
        int count; // 16
} SfoHeader;

typedef struct __attribute__((packed))
{
        unsigned short nameofs; // 0
        char alignment; // 2
        char type; // 3
        int valsize; // 4
        int totalsize; // 8
        unsigned short valofs; // 12
        short unknown; // 16
} SfoEntry;

u32 g_spoof_ver = 0;
u8 g_sfo_buffer[4 << 10];

int ApplyFirmware(SceModule2 *mod)
{
	int i;
	char *fw_data = NULL;
	u8 device_fw_ver[4];
	u32 pbp_header[0x28/4];
	SfoHeader *header = (SfoHeader *)g_sfo_buffer;
	SfoEntry *entries = (SfoEntry *)((char *)g_sfo_buffer + sizeof(SfoHeader));
	
	/* Lets open the updater */
	char *file = (sceKernelGetModel() == 4) ? ("ef0:/PSP/GAME/UPDATE/EBOOT.pbp") : ("ms0:/PSP/GAME/UPDATE/EBOOT.pbp");
	
	/* set k1 */
	u32 k1 = pspSdkSetK1(0);
	
	/* lets open the file */
	SceUID fd = sceIoOpen(file, PSP_O_RDONLY, 0777);
	
	/* check for failure */
	if (fd < 0)
	{
		/* rage */
		pspSdkSetK1(k1);
		return fd;
	}
	
	/* read the PBP header */
	sceIoRead(fd, pbp_header, sizeof(pbp_header));
	
	/* seek to the SFO */
	sceIoLseek32(fd, pbp_header[8/4], PSP_SEEK_SET);
	
	/* calculate the size of the SFO */
	u32 sfo_size = pbp_header[12/4] - pbp_header[8/4];
	
	/* check if greater than buffer size */
	if (sfo_size > sizeof(g_sfo_buffer))
	{
		/* too much */
		pspSdkSetK1(k1);
		return -2;
	}
	
	/* read the sfo */
	sceIoRead(fd, g_sfo_buffer, sizeof(g_sfo_buffer));
	
	/* close the file */
	sceIoClose(fd);
	
	/* now parse the SFO */
	for (i = 0; i < header->count; i++)
	{
		/* check this name */
		if (strcmp((char *)((char *)g_sfo_buffer + header->keyofs + entries[i].nameofs), "UPDATER_VER") == 0)
		{
			/* get the string */
			fw_data = (char *)((char *)g_sfo_buffer + header->valofs + entries[i].valofs);
			break;
		}
	}
	
	/* see if we went through all the data */
	if (i == header->count)
	{
		/* error */
		pspSdkSetK1(k1);
		return -3;
	}
	
	/* ok, we have the firmware version in the eboot. */
	u32 min_ver = 0;
	u32 updater_ver = (((fw_data[0] - '0') & 0xF) << 8) | (((fw_data[2] - '0') & 0xF) << 4) | (((fw_data[3] - '0') & 0xF) << 0);

	/* ok, now get the idstorage value */
	int res = sceIdStorageLookup(0x51, 0, device_fw_ver, 4);
	
	/* check for error */
	if (res < 0)
	{
		/* check model */
		if (sceKernelGetModel() != 0)
		{
			/* invalid error */
			return -4;
		}
		
		/* firmware 1.00 */
		min_ver = 0x100;
	}
	else
	{
		/* convert to hex */
		min_ver = (((device_fw_ver[0] - '0') & 0xF) << 8) | (((device_fw_ver[2] - '0') & 0xF) << 4) | (((device_fw_ver[3] - '0') & 0xF) << 0);
	}
	
	/* set the result to 0 */
	res = 0;
	
	/* check if the updater is less than the minimum version */
	if (updater_ver < min_ver)
	{
		/* ok, check for 6.35 and 09g */
		if ((min_ver != 0x630 && min_ver != 0x635) || sceKernelGetModel() != 8)
		{
			/* error */
			pspSdkSetK1(k1);
			return -5;
		}
		
		/* set result to 1 D: */
		res = 1;
	}

	//fix the issue with 6.61 -> 6.60
	if ((sceKernelDevkitVersion() == 0x06060110) && (updater_ver == 0x660)) {
		_sw(0x3C020606, 0x08801000); //lui	$v0, 0x606
		_sw(0x03E00008, 0x08801004); //jr	$ra
		_sw(0x34420010, 0x08801008); //ori	$v0, $v0, 0x10

		//redirect sceKernelDevkitVersion in updater module
		MAKE_JUMP(mod->text_addr + 0x123CD0, 0x08801000);
		_sw(0, mod->text_addr + 0x123CD4);

		ClearCaches();
	}

	/* do spoof! */
	g_spoof_ver = updater_ver;
	pspSdkSetK1(k1);
	return res;
}

#define INDEXFILE "flash0:/vsh/etc/index_04g.dat"
#define NEW_INDEXFILE "flash0:/vsh/etc/index_09g.dat"

SceUID sceIoOpenPatched(char *file, u32 mode, u32 mode2)
{
	/* check indexfile */
	if (strcmp(file, INDEXFILE) == 0)
	{
		/* if read mode, copy */
		if (mode == PSP_O_RDONLY)
		{
			strcpy(file, NEW_INDEXFILE);
		}
	}
	
	/* call original function */
	return sceIoOpen(file, mode, mode2);
}

int sceIoGetstatPatched(char *file, SceIoStat *stat)
{
	/* check indexfile */
	if (strcmp(file, INDEXFILE) == 0)
	{
		strcpy(file, NEW_INDEXFILE);
	}
	
	/* call original function */
	return sceIoGetstat(file, stat);
}

/* idstorage patching func */
int (* pspUtilsBufferCopyWithRange)(void *dst, u32 dst_size, void *src, u32 src_size, u32 cmd) = NULL;
int sceUtilsBufferCopyWithRangePatched(void *dst, u32 dst_size, void *src, u32 src_size, u32 cmd)
{
	u8 ids_cert[0xB8];
	
	/* if idstorage check */
	if (cmd == 0x12)
	{
		/* ok lets get the idstorage 0x100 key */
		int res = sceIdStorageLookup(0x100, 0x38, ids_cert, 0xB8);
		
		/* check for error */
		if (res < 0)
		{
			/* attempt with backup key */
			res = sceIdStorageLookup(0x120, 0x38, ids_cert, 0xB8);
			
			/* if error, exit */
			if (res < 0)
			{
				return res;
			}
		}
	
		/* yay its 0x100 key */
		/* change the model to 04g */
		ids_cert[7] = 6;
		
		/* copy the new certificate back */
		memcpy(src, ids_cert, sizeof(ids_cert));
		return 0;
	}
	
	/* return function */
	return pspUtilsBufferCopyWithRange(dst, dst_size, src, src_size, cmd);
}

int (* sceLflashFatfmtStartFatfmtOriginal)(int argc, char *argv[]) = NULL;

int sceLflashFatfmtStartFatfmtPatched(int argc, char *argv[])
{
    infSetRedirectionStatus(0);
    ClearCaches();
    
    return sceLflashFatfmtStartFatfmtOriginal(argc, argv);
}

int OnModuleStart(SceModule2 *mod)
{
	if (strcmp(mod->modname, "sceMesgLed") == 0)
	{
		PatchMesgled(mod->text_addr);
		ClearCaches();
	}
    
    else if (strcmp(mod->modname, "sceLflashFatfmtUpdater") == 0)
    {
        PatchSyscall(FindFunc("sceLflashFatfmtUpdater", "LflashFatfmt", 0xB7A424A4), sceLflashFatfmtStartFatfmtPatched);
        sceLflashFatfmtStartFatfmtOriginal = FindFunc("sceLflashFatfmtUpdater", "LflashFatfmt", 0xB7A424A4);
        ClearCaches();
    }
	
	else if (strcmp(mod->modname, "updater") == 0)
	{
		/* ok, lets see what we're doing here! */
		int res = ApplyFirmware(mod);
		
		/* check for success */
		if (res >= 0)
		{
			/* do these patches if we have 09g going to 6.XX */
			if (res == 1)
			{
				/* patch the IO */
				PatchSyscall(FindFunc("sceIOFileManager", "IoFileMgrForUser", 0x109F50BC), sceIoOpenPatched);
				PatchSyscall(FindFunc("sceIOFileManager", "IoFileMgrForUser", 0xACE946E8), sceIoGetstatPatched);
				
				/* find the function for idstorage verify */
				u32 func_address = FindFunc("sceMemlmd", "semaphore", 0x4C537C72);
				
				/* check if we have it... */
				if (func_address == 0)
				{
					/* ERROR */
					asm("break\n");
				}
				
				/* ok, lets patch it */
				KERNEL_HIJACK_FUNCTION(func_address, sceUtilsBufferCopyWithRangePatched, pspUtilsBufferCopyWithRange);
			}
			
			/* patch the version check on index.dat */
			PatchSyscall(FindFunc("sceMesgLed", "sceResmgr", 0x9DC14891), sceResmgr_9DC14891_patched);
			ClearCaches();	
		}
	}

	
	/* if there is a previous handler, call it */
	if (previous)
		return previous((SceModule2 *)mod);
	
	/* else just return 0 */
	return 0;
}

int PrologueModulePatched(void *modmgr_param, SceModule2 *mod)
{
	/* modmgr_param has changed from 1.50 so I have no included the structure defintion, for an updated version a re-reverse of 6.30 modulemgr is required */
	int res = PrologueModule(modmgr_param, mod);
	
	/* If this function errors, the module is shutdown so we better check for it */
	if (res >= 0)
	{
		/* Pass the module through the OnModuleStart chain */
		OnModuleStart(mod);
	}
	
	/* return success */
	return res;
}

static void PatchModuleManager(void)
{
	/* find the modulemgr module */
	SceModule2 *mod = (SceModule2 *)sceKernelFindModuleByName("sceModuleManager");
	u32 text_addr = mod->text_addr;
	
	/* link the original calls before hook */
	PrologueModule = (void *)(text_addr + g_patch_table.prologue_module_func);
	
	/* Patch call to PrologueModule from the StartModule function to allow a full coverage of loaded modules (even those without an entry point) */
	MAKE_CALL(text_addr + g_patch_table.prologue_module_call, PrologueModulePatched);
}

static void PatchLoadCore(void)
{
	/* Find the loadcore module */
	SceModule2 *mod = (SceModule2 *)sceKernelFindModuleByName("sceLoaderCore");
	u32 text_addr = mod->text_addr;
	
	/* Relink the memlmd calls (that reboot destroyed) */
	MAKE_CALL(text_addr + g_patch_table.memlmd_call[0], text_addr + g_patch_table.memlmd_stub[0]);
	MAKE_CALL(text_addr + g_patch_table.memlmd_call[1], text_addr + g_patch_table.memlmd_stub[1]);

	/* if >= 6.30 we need patches for the decryption */
	if (sceKernelDevkitVersion() >= 0x06030010)
	{
		/* we need to hook updater decryption */
		MAKE_CALL(text_addr + g_patch_table.memlmd_call[0], memlmd_7CF1CD3E_patched);
		MAKE_CALL(text_addr + g_patch_table.updater_decrypt_call, sceMesgLed_driver_81F72B1F_patched);
		
		sceMesgLed_driver_81F72B1F = (void *)(text_addr + g_patch_table.updater_decrypt_func);
	}
}

int module_start(SceSize argsize, void *argp)
{
	/* check if we're running as a plugin or in boot */
	if (sceKernelFindModuleByName("sceInit"))
	{
		/* plugin, assume we've got HEN (and an M33 nid resolver) */
		/* check for >= 6.30 */
		if (sceKernelDevkitVersion() >= 0x06030010)
		{
			/* this is firmware dependant :/ so not supported */
			return 0;
		}
		
		/* register with sctrl */
		previous = sctrlHENSetStartModuleHandler((STMOD_HANDLER)OnModuleStart);
	}
	else
	{
		/* boot */
		/* get patches and nids from loader */
		if (CopyPatchTable(&g_patch_table, (void *)PATCH_TABLE_ADDR_START, sceKernelDevkitVersion()) == 0)
		{
			/* no patches, no go */
			return 0;
		}
		
		/* perform main system patches */
		PatchLoadCore();
		PatchModuleManager();
	}

	/* Clear the caches and return success */
	ClearCaches();
	return 0;
}


================================================
FILE: src/downgrade660_ctrl/patch_table.c
================================================
/*
	Downgrade Control -> patch_table.c -> Responsible for searching and handling patch tables
	by Davee
	
	01/01/2011
*/

#include <pspkernel.h>
#include <pspsysmem_kernel.h>

#include <stdio.h>
#include <string.h>
#include <systemctrl.h>

#include "patch_table.h"

PatchTable g_patch_table;

int CopyPatchTable(PatchTable *dst_table, void *_src_table, u32 devkit)
{
	int i;
	
	/* get the number of entries in the table */
	u32 nentries = _lw((u32)_src_table);
	
	/* cast our pointer */
	PatchTable *src_table = (PatchTable *)(_src_table + 4);
	
	/* loop through the entries */
	for (i = 0; i < nentries; i++)
	{
		/* if same devkit */
		if (src_table->devkit == devkit)
		{
			/* copy over and return 1 for a complete transfer */
			memcpy(dst_table, src_table, sizeof(PatchTable));
			return 1;
		}
		
		/* increment */
		src_table++;
	}
	
	/* no transfer */
	return 0;
}


================================================
FILE: src/downgrade660_ctrl/patch_table.h
================================================
/*
	Downgrade Control -> patch_table.h -> Provide API documentation and definitions for the table patching
	by Davee
	
	01/01/2011
*/
#ifndef __PATCH_TABLE_H__
#define __PATCH_TABLE_H__

typedef struct
{
	u32 devkit;
	u32 new_updater_check[5];
	u32 updater_decrypt_call;
	u32 updater_decrypt_func;
/*	u32 new_updater_keys;
	u32 new_updater_t3_arg;
	u32 new_updater_seed;
	u32 new_updater_mode;
	u32 new_updater_stack_arg;*/
	u32 prologue_module_func;
	u32 prologue_module_call;
	u32 memlmd_call[2];
	u32 memlmd_stub[2];
} PatchTable;

#define PATCH_TABLE_ADDR_START	(0x88FC0000)

extern PatchTable g_patch_table;
int CopyPatchTable(PatchTable *dst_table, void *_src_table, u32 devkit);

#endif /* __PATCH_TABLE_H__ */


================================================
FILE: src/downgrade660_ctrl/pspdecrypt.c
================================================
#include <pspsdk.h>
#include <pspkernel.h>
#include <pspdebug.h>
//#include <pspcrypt.h>
#include <psputilsforkernel.h>
#include <pspthreadman_kernel.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "decrypt.h"
//#include <pspdecrypt.h>
//#include <systemctrl.h>


extern int UtilsForKernel_6C6887EE(void *, u32, void *, void *);

////////// Decryption 1 //////////

// use pre-calculated keys (step1 results)

u32 g_key0[] =
{
  0x7b21f3be, 0x299c5e1d, 0x1c9c5e71, 0x96cb4645, 0x3c9b1be0, 0xeb85de3d,
  0x4a7f2022, 0xc2206eaa, 0xd50b3265, 0x55770567, 0x3c080840, 0x981d55f2,
  0x5fd8f6f3, 0xee8eb0c5, 0x944d8152, 0xf8278651, 0x2705bafa, 0x8420e533,
  0x27154ae9, 0x4819aa32, 0x59a3aa40, 0x2cb3cf65, 0xf274466d, 0x3a655605,
  0x21b0f88f, 0xc5b18d26, 0x64c19051, 0xd669c94e, 0xe87035f2, 0x9d3a5909,
  0x6f4e7102, 0xdca946ce, 0x8416881b, 0xbab097a5, 0x249125c6, 0xb34c0872,
};

u32 g_key2[] =
{
  0xccfda932, 0x51c06f76, 0x046dcccf, 0x49e1821e, 0x7d3b024c, 0x9dda5865,
  0xcc8c9825, 0xd1e97db5, 0x6874d8cb, 0x3471c987, 0x72edb3fc, 0x81c8365d,
  0xe161e33a, 0xfc92db59, 0x2009b1ec, 0xb1a94ce4, 0x2f03696b, 0x87e236d8,
  0x3b2b8ce9, 0x0305e784, 0xf9710883, 0xb039db39, 0x893bea37, 0xe74d6805,
  0x2a5c38bd, 0xb08dc813, 0x15b32375, 0x46be4525, 0x0103fd90, 0xa90e87a2,
  0x52aba66a, 0x85bf7b80, 0x45e8ce63, 0x4dd716d3, 0xf5e30d2d, 0xaf3ae456,
};

u32 g_key3[] =
{
  0xa6c8f5ca, 0x6d67c080, 0x924f4d3a, 0x047ca06a, 0x08640297, 0x4fd4a758,
  0xbd685a87, 0x9b2701c2, 0x83b62a35, 0x726b533c, 0xe522fa0c, 0xc24b06b4,
  0x459d1cac, 0xa8c5417b, 0x4fea62a2, 0x0615d742, 0x30628d09, 0xc44fab14,
  0x69ff715e, 0xd2d8837d, 0xbeed0b8b, 0x1e6e57ae, 0x61e8c402, 0xbe367a06,
  0x543f2b5e, 0xdb3ec058, 0xbe852075, 0x1e7e4dcc, 0x1564ea55, 0xec7825b4,
  0xc0538cad, 0x70f72c7f, 0x49e8c3d0, 0xeda97ec5, 0xf492b0a4, 0xe05eb02a,
};

u32 g_key44[] =
{
  0xef80e005, 0x3a54689f, 0x43c99ccd, 0x1b7727be, 0x5cb80038, 0xdd2efe62,
  0xf369f92c, 0x160f94c5, 0x29560019, 0xbf3c10c5, 0xf2ce5566, 0xcea2c626,
  0xb601816f, 0x64e7481e, 0x0c34debd, 0x98f29cb0, 0x3fc504d7, 0xc8fb39f0,
  0x0221b3d8, 0x63f936a2, 0x9a3a4800, 0x6ecc32e3, 0x8e120cfd, 0xb0361623,
  0xaee1e689, 0x745502eb, 0xe4a6c61c, 0x74f23eb4, 0xd7fa5813, 0xb01916eb,
  0x12328457, 0xd2bc97d2, 0x646425d8, 0x328380a5, 0x43da8ab1, 0x4b122ac9,
};

u32 g_key20[] =
{
  0x33b50800, 0xf32f5fcd, 0x3c14881f, 0x6e8a2a95, 0x29feefd5, 0x1394eae3,
  0xbd6bd443, 0x0821c083, 0xfab379d3, 0xe613e165, 0xf5a754d3, 0x108b2952,
  0x0a4b1e15, 0x61eadeba, 0x557565df, 0x3b465301, 0xae54ecc3, 0x61423309,
  0x70c9ff19, 0x5b0ae5ec, 0x989df126, 0x9d987a5f, 0x55bc750e, 0xc66eba27,
  0x2de988e8, 0xf76600da, 0x0382dccb, 0x5569f5f2, 0x8e431262, 0x288fe3d3,
  0x656f2187, 0x37d12e9c, 0x2f539eb4, 0xa492998e, 0xed3958f7, 0x39e96523,
};

u32 g_key3A[] =
{
  0x67877069, 0x3abd5617, 0xc23ab1dc, 0xab57507d, 0x066a7f40, 0x24def9b9,
  0x06f759e4, 0xdcf524b1, 0x13793e5e, 0x0359022d, 0xaae7e1a2, 0x76b9b2fa,
  0x9a160340, 0x87822fba, 0x19e28fbb, 0x9e338a02, 0xd8007e9a, 0xea317af1,
  0x630671de, 0x0b67ca7c, 0x865192af, 0xea3c3526, 0x2b448c8e, 0x8b599254,
  0x4602e9cb, 0x4de16cda, 0xe164d5bb, 0x07ecd88e, 0x99ffe5f8, 0x768800c1,
  0x53b091ed, 0x84047434, 0xb426dbbc, 0x36f948bb, 0x46142158, 0x749bb492,
};

/* updaters keys */
u8 updaters_keys[0x90+0x14] = 
{
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x0B, 0x01, 0x1C, 0xE7, 0x31, 0x15, 0x6B, 0x83, 
	0x3E, 0x26, 0x0D, 0xCC, 0x69, 0x36, 0x12, 0xCB, 
	0xA7, 0xFD, 0x26, 0x66, 0x93, 0x2A, 0x6E, 0x1A, 
	0x91, 0x2E, 0xC6, 0xFC, 0xD8, 0x2F, 0x00, 0x13, 
	0x5A, 0xE2, 0xDF, 0xB6, 0xA2, 0xE4, 0x27, 0xC8, 
	0x18, 0xC3, 0x50, 0x50, 0xB7, 0xE9, 0x4A, 0xED, 
	0xCC, 0x3C, 0x30, 0xFD, 0x10, 0x6A, 0x2B, 0x0A, 
	0x22, 0xCB, 0xC6, 0xE0, 0x20, 0x65, 0x12, 0xEB, 
	0x7D, 0x4E, 0x2A, 0x37, 0x0B, 0x0A, 0xEF, 0x88, 
	0xDA, 0x06, 0x54, 0xD4, 0x30, 0xAF, 0xCD, 0xCA, 
	0x9A, 0xF9, 0xDA, 0x1A, 0xB0, 0x1B, 0xBB, 0x62, 
	0x0C, 0xDB, 0xF8, 0x44, 0x73, 0x56, 0x14, 0x8E, 
	0x93, 0xB1, 0x2C, 0xFD, 0x67, 0xE2, 0x5D, 0xCB, 
	0x48, 0x5B, 0xD9, 0xB3, 0x54, 0x14, 0xD7, 0x9F, 
	0x79, 0x9C, 0x24, 0xE9, 0xC2, 0x7A, 0x4E, 0x8C, 
	0x4D, 0x24, 0x19, 0x94, 0xFF, 0xC9, 0xC2, 0x2D, 
	0x23, 0x63, 0x51, 0xB8, 0xFA, 0xD6, 0x7F, 0xE6, 
	0x5E, 0xBC, 0x32, 0xB2, 0x02, 0x13, 0xC4, 0x76
};

/* locoroco, kazue, and maybe others demos keys */
u8 demo_keys0[0x90+0x14] = 
{
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x82, 0x4C, 0xA5, 0x18, 0xD3, 0xC8, 0x6E, 0xEA, 
	0x17, 0x41, 0x04, 0xDC, 0xEA, 0xC5, 0x01, 0xFC, 
	0x97, 0xB1, 0x94, 0x54, 0x71, 0x19, 0x22, 0xEE, 
	0xE0, 0x2D, 0xE9, 0x83, 0x3D, 0x64, 0x30, 0xE6, 
	0x42, 0x5C, 0x30, 0x5F, 0xEB, 0x41, 0xA0, 0xE0, 
	0x62, 0xC6, 0x63, 0xEE, 0x5D, 0xA5, 0x0D, 0x1E, 
	0xC2, 0x10, 0x14, 0x49, 0x06, 0xC6, 0x93, 0x84, 
	0x71, 0xA5, 0x42, 0x63, 0x13, 0xF0, 0xB6, 0xD5, 
	0x43, 0x51, 0x9E, 0xFA, 0x91, 0x0A, 0x7C, 0xE1, 
	0x58, 0x1B, 0x95, 0x25, 0x40, 0x11, 0xF1, 0x8D, 
	0xB1, 0x01, 0x8D, 0x04, 0x09, 0x54, 0x5C, 0x54, 
	0xF5, 0x53, 0x08, 0xB0, 0x53, 0x85, 0xB4, 0xCE, 
	0x0B, 0xF5, 0xC3, 0xFB, 0xC6, 0x55, 0x24, 0x0B, 
	0xF2, 0xC6, 0x2C, 0xE4, 0x0C, 0xF0, 0x05, 0x3C, 
	0xD7, 0x6C, 0x39, 0xD5, 0x87, 0x22, 0x09, 0xF7, 
	0x3D, 0xC5, 0xA2, 0xFD, 0x55, 0x92, 0x3F, 0xB1, 
	0xF6, 0xFE, 0xC8, 0x18, 0x1D, 0x6B, 0x04, 0x52, 
	0x5F, 0x8C, 0xE8, 0xE7, 0x26, 0x5A, 0x6E, 0x5A
};

typedef struct
{
    u32 tag; // 4 byte value at offset 0xD0 in the PRX file
    u8* key; // "step1_result" use for XOR step
    u8 code;
    u8 codeExtra;
} TAG_INFO;

static const TAG_INFO g_tagInfo[] =
{
    // 1.x PRXs
    { 0x00000000, (u8*)g_key0, 0x42 },
    { 0x02000000, (u8*)g_key2, 0x45 },
    { 0x03000000, (u8*)g_key3, 0x46 },

    // 2.0 PRXs
    { 0x4467415d, (u8*)g_key44, 0x59, 0x59 },
    { 0x207bbf2f, (u8*)g_key20, 0x5A, 0x5A },
    { 0x3ace4dce, (u8*)g_key3A, 0x5B, 0x5B },

	 // updaters
    { 0x0b000000, updaters_keys, 0x4E },
	
	// locoroco, kazue, demos	
	{ 0x0c000000, demo_keys0, 0x4F },
};

static TAG_INFO const* GetTagInfo(u32 tagFind)
{
    int iTag;
    for (iTag = 0; iTag < sizeof(g_tagInfo)/sizeof(TAG_INFO); iTag++)
        if (g_tagInfo[iTag].tag == tagFind)
            return &g_tagInfo[iTag];
    return NULL; // not found
}

static void ExtraV2Mangle(u8* buffer1, u8 codeExtra)
{
    static u8 g_dataTmp[20+0xA0] __attribute__((aligned(0x40)));
    u8* buffer2 = g_dataTmp; // aligned

    memcpy(buffer2+20, buffer1, 0xA0);
    u32* pl2 = (u32*)buffer2;
    pl2[0] = 5;
    pl2[1] = pl2[2] = 0;
    pl2[3] = codeExtra;
    pl2[4] = 0xA0;

    int ret = sceUtilsBufferCopyWithRange(buffer2, 20+0xA0, buffer2, 20+0xA0, 7);
    if (ret != 0)
        Kprintf("extra de-mangle returns %d\n", ret);
    // copy result back
    memcpy(buffer1, buffer2, 0xA0);
}

static int Scramble(u32 *buf, u32 size, u32 code)
{
	buf[0] = 5;
	buf[1] = buf[2] = 0;
	buf[3] = code;
	buf[4] = size;

	if (sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size+0x14, 7) < 0)
	{
		return -1;
	}

	return 0;
}

static int DecryptPRX1(const u8* pbIn, u8* pbOut, int cbTotal, u32 tag)
{
	int i, retsize;
	u8 bD0[0x80], b80[0x50], b00[0x80], bB0[0x20];
	
	TAG_INFO const* pti = GetTagInfo(tag);
    if (pti == NULL)
        return -1;

	retsize = *(u32*)&pbIn[0xB0];

	for (i = 0; i < 0x14; i++)
	{
		if (pti->key[i] != 0)
			break;
	}

	if (i == 0x14)
	{
		Scramble((u32 *)pti->key, 0x90, pti->code);
	}

    // build conversion into pbOut

	if (pbIn != pbOut)
		memcpy(pbOut, pbIn, cbTotal);

	memcpy(bD0, pbIn+0xD0, 0x80);
	memcpy(b80, pbIn+0x80, 0x50);
	memcpy(b00, pbIn+0x00, 0x80);
	memcpy(bB0, pbIn+0xB0, 0x20);
    
	memset(pbOut, 0, 0x150);
    memset(pbOut, 0x55, 0x40); // first $40 bytes ignored

    // step3 demangle in place
    u32* pl = (u32*)(pbOut+0x2C);
    pl[0] = 5; // number of ulongs in the header
    pl[1] = pl[2] = 0;
    pl[3] = pti->code; // initial seed for PRX
    pl[4] = 0x70;   // size

    // redo part of the SIG check (step2)
    u8 buffer1[0x150];
    memcpy(buffer1+0x00, bD0, 0x80);
    memcpy(buffer1+0x80, b80, 0x50);
    memcpy(buffer1+0xD0, b00, 0x80);
    if (pti->codeExtra != 0)
        ExtraV2Mangle(buffer1+0x10, pti->codeExtra);
    memcpy(pbOut+0x40 /* 0x2C+20 */, buffer1+0x40, 0x70);

    int ret;
    int iXOR;
    for (iXOR = 0; iXOR < 0x70; iXOR++)
        pbOut[0x40+iXOR] = pbOut[0x40+iXOR] ^ pti->key[0x14+iXOR];

    ret = sceUtilsBufferCopyWithRange(pbOut+0x2C, 20+0x70, pbOut+0x2C, 20+0x70, 7);
    if (ret != 0)
    {
        Kprintf("mangle#7 returned $%x\n", ret);
        return -1;
    }

    for (iXOR = 0x6F; iXOR >= 0; iXOR--)
        pbOut[0x40+iXOR] = pbOut[0x2C+iXOR] ^ pti->key[0x20+iXOR];

    memset(pbOut+0xA0, 0, 0x10); // $40 bytes kept, clean up
    pbOut[0xA0] = 1;
    // copy unscrambled parts from header
    memcpy(pbOut+0xB0, bB0, 0x20); // file size + lots of zeros
    memcpy(pbOut+0xD0, b00, 0x80); // ~PSP header

    // step4: do the actual decryption of code block
    //  point 0x40 bytes into the buffer to key info
    ret = sceUtilsBufferCopyWithRange(pbOut, cbTotal, pbOut+0x40, cbTotal-0x40, 0x1);
    if (ret != 0)
    {
		/* set ECDSA flag */
		pbOut[0xA4] = 1;
		
		/* attempt decrypt */
		ret = sceUtilsBufferCopyWithRange(pbOut, cbTotal, pbOut+0x40, cbTotal-0x40, 0x1);
		
		/* check for error */
		if (ret != 0)
		{
			Kprintf("mangle#1 returned $%x\n", ret);
			return -1;
		}
    }

    // return cbTotal - 0x150; // rounded up size
	return retsize; 
}

////////// Decryption 2 //////////

/* kernel modules 2.60-2.71 */
u8 keys260_0[0x10] =
{
	0xC3, 0x24, 0x89, 0xD3, 0x80, 0x87, 0xB2, 0x4E,
	0x4C, 0xD7, 0x49, 0xE4, 0x9D, 0x1D, 0x34, 0xD1

};

/* user modules 2.60-2.71 */
u8 keys260_1[0x10] =
{
	0xF3, 0xAC, 0x6E, 0x7C, 0x04, 0x0A, 0x23, 0xE7,
	0x0D, 0x33, 0xD8, 0x24, 0x73, 0x39, 0x2B, 0x4A
};

/* vshmain 2.60-2.71 */
u8 keys260_2[0x10] =
{
	0x72, 0xB4, 0x39, 0xFF, 0x34, 0x9B, 0xAE, 0x82,
	0x30, 0x34, 0x4A, 0x1D, 0xA2, 0xD8, 0xB4, 0x3C
};

/* kernel modules 2.80 */
u8 keys280_0[0x10] =
{
	0xCA, 0xFB, 0xBF, 0xC7, 0x50, 0xEA, 0xB4, 0x40,
	0x8E, 0x44, 0x5C, 0x63, 0x53, 0xCE, 0x80, 0xB1
};

/* user modules 2.80 */
u8 keys280_1[0x10] =
{
	0x40, 0x9B, 0xC6, 0x9B, 0xA9, 0xFB, 0x84, 0x7F,
	0x72, 0x21, 0xD2, 0x36, 0x96, 0x55, 0x09, 0x74
};

/* vshmain executable 2.80 */
u8 keys280_2[0x10] =
{
	0x03, 0xA7, 0xCC, 0x4A, 0x5B, 0x91, 0xC2, 0x07,
	0xFF, 0xFC, 0x26, 0x25, 0x1E, 0x42, 0x4B, 0xB5
};

/* kernel modules 3.00 */
u8 keys300_0[0x10] =
{
	0x9F, 0x67, 0x1A, 0x7A, 0x22, 0xF3, 0x59, 0x0B,
    0xAA, 0x6D, 0xA4, 0xC6, 0x8B, 0xD0, 0x03, 0x77

};

/* user modules 3.00 */
u8 keys300_1[0x10] =
{
	0x15, 0x07, 0x63, 0x26, 0xDB, 0xE2, 0x69, 0x34,
    0x56, 0x08, 0x2A, 0x93, 0x4E, 0x4B, 0x8A, 0xB2

};

/* vshmain 3.00 */
u8 keys300_2[0x10] =
{
	0x56, 0x3B, 0x69, 0xF7, 0x29, 0x88, 0x2F, 0x4C,
    0xDB, 0xD5, 0xDE, 0x80, 0xC6, 0x5C, 0xC8, 0x73

};

/* kernel modules 3.00 */
u8 keys303_0[0x10] =
{
	0x7b, 0xa1, 0xe2, 0x5a, 0x91, 0xb9, 0xd3, 0x13,
	0x77, 0x65, 0x4a, 0xb7, 0xc2, 0x8a, 0x10, 0xaf
};

/* kernel modules 3.10 */
u8 keys310_0[0x10] =
{
	0xa2, 0x41, 0xe8, 0x39, 0x66, 0x5b, 0xfa, 0xbb,
	0x1b, 0x2d, 0x6e, 0x0e, 0x33, 0xe5, 0xd7, 0x3f
};

/* user modules 3.10 */
u8 keys310_1[0x10] =
{
	0xA4, 0x60, 0x8F, 0xAB, 0xAB, 0xDE, 0xA5, 0x65,
	0x5D, 0x43, 0x3A, 0xD1, 0x5E, 0xC3, 0xFF, 0xEA
};

/* vshmain 3.10 */
u8 keys310_2[0x10] =
{
	0xE7, 0x5C, 0x85, 0x7A, 0x59, 0xB4, 0xE3, 0x1D,
	0xD0, 0x9E, 0xCE, 0xC2, 0xD6, 0xD4, 0xBD, 0x2B
};

/* reboot.bin 3.10 */
u8 keys310_3[0x10] =
{
    0x2E, 0x00, 0xF6, 0xF7, 0x52, 0xCF, 0x95, 0x5A,
    0xA1, 0x26, 0xB4, 0x84, 0x9B, 0x58, 0x76, 0x2F
};

/* kernel modules 3.30 */ 
u8 keys330_0[0x10] = 
{ 
	0x3B, 0x9B, 0x1A, 0x56, 0x21, 0x80, 0x14, 0xED,
	0x8E, 0x8B, 0x08, 0x42, 0xFA, 0x2C, 0xDC, 0x3A
};

/* user modules 3.30 */ 
u8 keys330_1[0x10] = 
{ 
    0xE8, 0xBE, 0x2F, 0x06, 0xB1, 0x05, 0x2A, 0xB9, 
    0x18, 0x18, 0x03, 0xE3, 0xEB, 0x64, 0x7D, 0x26 
}; 

/* vshmain 3.30 */ 
u8 keys330_2[0x10] = 
{ 
    0xAB, 0x82, 0x25, 0xD7, 0x43, 0x6F, 0x6C, 0xC1, 
    0x95, 0xC5, 0xF7, 0xF0, 0x63, 0x73, 0x3F, 0xE7 
}; 

/* reboot.bin 3.30 */ 
u8 keys330_3[0x10] = 
{ 
    0xA8, 0xB1, 0x47, 0x77, 0xDC, 0x49, 0x6A, 0x6F, 
    0x38, 0x4C, 0x4D, 0x96, 0xBD, 0x49, 0xEC, 0x9B 
}; 

/* stdio.prx 3.30 */
u8 keys330_4[0x10] =
{
	0xEC, 0x3B, 0xD2, 0xC0, 0xFA, 0xC1, 0xEE, 0xB9,
	0x9A, 0xBC, 0xFF, 0xA3, 0x89, 0xF2, 0x60, 0x1F
};

/* 3.60 common kernel modules */
u8 keys360_0[16] = 
{
	0x3C, 0x2B, 0x51, 0xD4, 0x2D, 0x85, 0x47, 0xDA, 
	0x2D, 0xCA, 0x18, 0xDF, 0xFE, 0x54, 0x09, 0xED
};

/* 3.60 specific slim kernel modules */
u8 keys360_1[16] = 
{
	0x31, 0x1F, 0x98, 0xD5, 0x7B, 0x58, 0x95, 0x45, 
	0x32, 0xAB, 0x3A, 0xE3, 0x89, 0x32, 0x4B, 0x34
};

/* 3.70 common and fat kernel modules */
u8 keys370_0[0x10] = 
{
	0x26, 0x38, 0x0A, 0xAC, 0xA5, 0xD8, 0x74, 0xD1, 
	0x32, 0xB7, 0x2A, 0xBF, 0x79, 0x9E, 0x6D, 0xDB
};

/* 3.70 slim specific kernel modules */
u8 keys370_1[0x10] = 
{
	0x53, 0xE7, 0xAB, 0xB9, 0xC6, 0x4A, 0x4B, 0x77, 
	0x92, 0x17, 0xB5, 0x74, 0x0A, 0xDA, 0xA9, 0xEA
};

/* some 3.70 slim user modules */
u8 keys370_2[16] = 
{
	0x71, 0x10, 0xF0, 0xA4, 0x16, 0x14, 0xD5, 0x93, 
	0x12, 0xFF, 0x74, 0x96, 0xDF, 0x1F, 0xDA, 0x89
};

/* 3.90 kernel */
u8 keys390_0[16] = 
{
	0x45, 0xEF, 0x5C, 0x5D, 0xED, 0x81, 0x99, 0x84, 
	0x12, 0x94, 0x8F, 0xAB, 0xE8, 0x05, 0x6D, 0x7D
};

/* 3.90 slim */
u8 keys390_1[16] = 
{
	0x70, 0x1B, 0x08, 0x25, 0x22, 0xA1, 0x4D, 0x3B, 
	0x69, 0x21, 0xF9, 0x71, 0x0A, 0xA8, 0x41, 0xA9
};

/* 5.00 kernel */
u8 keys500_0[16] = 
{
	0xEB, 0x1B, 0x53, 0x0B, 0x62, 0x49, 0x32, 0x58, 
	0x1F, 0x83, 0x0A, 0xF4, 0x99, 0x3D, 0x75, 0xD0
};

/* 5.00 kernel 2000 specific */
u8 keys500_1[16] = 
{
	0xBA, 0xE2, 0xA3, 0x12, 0x07, 0xFF, 0x04, 0x1B, 
	0x64, 0xA5, 0x11, 0x85, 0xF7, 0x2F, 0x99, 0x5B
};

/* 5.00 kernel 3000 specific */
u8 keys500_2[16] = 
{
	0x2C, 0x8E, 0xAF, 0x1D, 0xFF, 0x79, 0x73, 0x1A, 
 	0xAD, 0x96, 0xAB, 0x09, 0xEA, 0x35, 0x59, 0x8B
};

u8 keys500_c[16] = 
{
	0xA3, 0x5D, 0x51, 0xE6, 0x56, 0xC8, 0x01, 0xCA,
	0xE3, 0x77, 0xBF, 0xCD, 0xFF, 0x24, 0xDA, 0x4D
};

u8 keys505_a[16] =
{
	0x7B, 0x94, 0x72, 0x27, 0x4C, 0xCC, 0x54, 0x3B,
	0xAE, 0xDF, 0x46, 0x37, 0xAC, 0x01, 0x4D, 0x87
};

u8 keys505_0[16] =
{
	0x2E, 0x8E, 0x97, 0xA2, 0x85, 0x42, 0x70, 0x73,
	0x18, 0xDA, 0xA0, 0x8A, 0xF8, 0x62, 0xA2, 0xB0
};

u8 keys505_1[16] =
{
	0x58, 0x2A, 0x4C, 0x69, 0x19, 0x7B, 0x83, 0x3D,
	0xD2, 0x61, 0x61, 0xFE, 0x14, 0xEE, 0xAA, 0x11
};

/* for psp 2000 file table and ipl pre-decryption */
u8 keys02G_E[0x10] = 
{
	0x9D, 0x09, 0xFD, 0x20, 0xF3, 0x8F, 0x10, 0x69, 
	0x0D, 0xB2, 0x6F, 0x00, 0xCC, 0xC5, 0x51, 0x2E
};

/* for psp 3000 file table and ipl pre-decryption */
u8 keys03G_E[0x10] = 
{
	0x4F, 0x44, 0x5C, 0x62, 0xB3, 0x53, 0xC4, 0x30, 
	0xFC, 0x3A, 0xA4, 0x5B, 0xEC, 0xFE, 0x51, 0xEA
};

/* for psp go file table and ipl pre-decryption */
u8 keys05G_E[0x10] = 
{
	0x5D, 0xAA, 0x72, 0xF2, 0x26, 0x60, 0x4D, 0x1C,
	0xE7, 0x2D, 0xC8, 0xA3, 0x2F, 0x79, 0xC5, 0x54
};

/* 5.70 PSPgo kernel*/
u8 keys570_5k[0x10] =
{
	0x6D, 0x72, 0xA4, 0xBA, 0x7F, 0xBF, 0xD1, 0xF1,
	0xA9, 0xF3, 0xBB, 0x07, 0x1B, 0xC0, 0xB3, 0x66
};

/* 6.00-6.20 kernel and phat */
u8 keys620_0[0x10] = 
{
	0xD6, 0xBD, 0xCE, 0x1E, 0x12, 0xAF, 0x9A, 0xE6,
	0x69, 0x30, 0xDE, 0xDA, 0x88, 0xB8, 0xFF, 0xFB
};

/* 6.00-6.20 slim kernel */
u8 keys620_1[0x10] = 
{
	0x1D, 0x13, 0xE9, 0x50, 0x04, 0x73, 0x3D, 0xD2,
	0xE1, 0xDA, 0xB9, 0xC1, 0xE6, 0x7B, 0x25, 0xA7
};

u8 keys620_a[0x10] = 
{
	0xAC, 0x34, 0xBA, 0xB1, 0x97, 0x8D, 0xAE, 0x6F,
	0xBA, 0xE8, 0xB1, 0xD6, 0xDF, 0xDF, 0xF1, 0xA2
};

u8 keys620_e[0x10] = 
{
	0xB1, 0xB3, 0x7F, 0x76, 0xC3, 0xFB, 0x88, 0xE6,
	0xF8, 0x60, 0xD3, 0x35, 0x3C, 0xA3, 0x4E, 0xF3
};

/* PSPgo internal */
u8 keys620_5[0x10] =
{
	0xF1, 0xBC, 0x17, 0x07, 0xAE, 0xB7, 0xC8, 0x30,
	0xD8, 0x34, 0x9D, 0x40, 0x6A, 0x8E, 0xDF, 0x4E
};

/* 6.XX PSPgo kernel */
u8 keys620_5k[0x10] =
{
	0x41, 0x8A, 0x35, 0x4F, 0x69, 0x3A, 0xDF, 0x04,
	0xFD, 0x39, 0x46, 0xA2, 0x5C, 0x2D, 0xF2, 0x21
};

u8 keys620_5v[0x10] =
{
	0xF2, 0x8F, 0x75, 0xA7, 0x31, 0x91, 0xCE, 0x9E,
	0x75, 0xBD, 0x27, 0x26, 0xB4, 0xB4, 0x0C, 0x32
};

/* 6.30 phat kernel */ 
u8 keys630_k1[0x10] = {
	0x36, 0xB0, 0xDC, 0xFC, 0x59, 0x2A, 0x95, 0x1D, 
	0x80, 0x2D, 0x80, 0x3F, 0xCD, 0x30, 0xA0, 0x1B,
};

/* 6.30 phat kernel-2 */
u8 keys630_k2[0x10] = {
	0xd4, 0x35, 0x18, 0x02, 0x29, 0x68, 0xfb, 0xa0, 
	0x6a, 0xa9, 0xa5, 0xed, 0x78, 0xfd, 0x2e, 0x9d
};

u8 key_380280f0[0x10] =
{
	0x97, 0x09, 0x12, 0xD3, 0xDB, 0x02, 0xBD, 0xD8, 
	0xE7, 0x74, 0x51, 0xFE, 0xF0, 0xEA, 0x6C, 0x5C,
};

/* 6.30 slim kernel */
u8 keys630_k3[0x10] =
{
	0x23, 0x8D, 0x3D, 0xAE, 0x41, 0x50, 0xA0, 0xFA,
	0xF3, 0x2F, 0x32, 0xCE, 0xC7, 0x27, 0xCD, 0x50,
};

/* 6.30 slim pops */
u8 keys630_k4[0x10] = 
{
	0xAA, 0xA1, 0xB5, 0x7C, 0x93, 0x5A, 0x95, 0xBD,
	0xEF, 0x69, 0x16, 0xFC, 0x2B, 0x92, 0x31, 0xDD
};

u8 keys630_k5[0x10] = { 0x87,0x37,0x21,0xCC,0x65,0xAE,0xAA,0x5F,0x40,0xF6,0x6F,0x2A,0x86,0xC7,0xA1,0xC8 };
u8 keys630_k6[0x10] = { 0x8D,0xDB,0xDC,0x5C,0xF2,0x70,0x2B,0x40,0xB2,0x3D,0x00,0x09,0x61,0x7C,0x10,0x60 };
u8 keys630_k7[0x10] = { 0x77,0x1C,0x06,0x5F,0x53,0xEC,0x3F,0xFC,0x22,0xCE,0x5A,0x27,0xFF,0x78,0xA8,0x48 };
u8 keys630_k8[0x10] = { 0x81,0xD1,0x12,0x89,0x35,0xC8,0xEA,0x8B,0xE0,0x02,0x2D,0x2D,0x6A,0x18,0x67,0xB8 };

u8 keys636_k1[0x10] = { 0x07,0xE3,0x08,0x64,0x7F,0x60,0xA3,0x36,0x6A,0x76,0x21,0x44,0xC9,0xD7,0x06,0x83 };
u8 keys636_k2[0x10] = { 0x91,0xF2,0x02,0x9E,0x63,0x32,0x30,0xA9,0x1D,0xDA,0x0B,0xA8,0xB7,0x41,0xA3,0xCC };

u8 keys600_1[0x10] = { 0xE3,0x52,0x39,0x97,0x3B,0x84,0x41,0x1C,0xC3,0x23,0xF1,0xB8,0xA9,0x09,0x4B,0xF0 };
u8 keys600_2[0x10] = { 0xE1,0x45,0x93,0x2C,0x53,0xE2,0xAB,0x06,0x6F,0xB6,0x8F,0x0B,0x66,0x91,0xE7,0x1E };

u8 key_380283F0[0x10] = { 0x34,0x20,0x0C,0x8E,0xA1,0x86,0x79,0x84,0xAF,0x13,0xAE,0x34,0x77,0x6F,0xEA,0x89 };

u8 keys620_upd[0x10] = { 0xE2,0x03,0x8A,0x8C,0x33,0x81,0x4B,0x56,0x52,0x4E,0x1D,0xE5,0xA4,0x24,0x04,0xFF };

typedef struct
{
    u32 tag; // 4 byte value at offset 0xD0 in the PRX file
    u8  *key; // 16 bytes keys
    u8 code; // code for scramble
	u8 type;
} TAG_INFO2;

static TAG_INFO2 g_tagInfo2[] =
{
	{ 0xA6E328F0, keys620_upd, 0x5F }, // 5.70, 6.10, 6.20 PSPgo Updater
	
	{ 0x4C948AF0, keys636_k1, 0x43, 3}, // 6.36
	{ 0x4C948BF0, keys636_k2, 0x43, 3}, // 6.36 02g

	{ 0x457b80f0, keys630_k2, 0x5B, 3}, // 6.30
	{ 0x457B81F0, keys630_k4, 0x5B, 3}, // 6.30 02g
	{ 0x457B82F0, keys630_k5, 0x5B, 3}, // 6.30 03g 04g 07g 09g
	{ 0x457B83F0, keys630_k7, 0x5B, 3}, // 6.30 05g
	{ 0x4C9484F0, keys630_k1, 0x43, 3}, // 6.30
	{ 0x4C9485F0, keys630_k3, 0x43, 3}, // 6.30 02g
	{ 0x4C9486F0, keys630_k6, 0x43, 3}, // 6.30 03g 04g 07g 09g
	{ 0x4C9487F0, keys630_k8, 0x43, 3}, // 6.30 05g

	{ 0x380283F0, key_380283F0, 0x5A, 3}, // 6.30 vshmain 05g
	{ 0x380280f0, key_380280f0, 0x5A, 3}, // 6.30 vshmain
	
	{ 0x457B28F0, keys620_e, 0x5B },
	{ 0x457B0CF0, keys620_a, 0x5B },
	{ 0x380228F0, keys620_5v, 0x5A }, // PSPgo 6.XX vshmain
	{ 0x4C942AF0, keys620_5k, 0x43 }, // PSPgo 6.XX
	{ 0x4C9428F0, keys620_5 , 0x43 }, // PSPgo
	{ 0x4C9422F0, keys600_2, 0x43 }, // 6.00 03g 04g
	{ 0x4C941EF0, keys600_1, 0x43 },
	{ 0x4C941DF0, keys620_1, 0x43 },
	{ 0x4C941CF0, keys620_0, 0x43 },
	{ 0x4C9429F0, keys570_5k, 0x43 }, // PSPgo 5.70
	{ 0x4C9419F0, keys505_1, 0x43 },
	{ 0x4C9418F0, keys505_0, 0x43 },
	{ 0x457B0BF0, keys505_a, 0x5B },
	{ 0x457B1EF0, keys500_c, 0x5B },
	{ 0x4C941FF0, keys500_2, 0x43 },
	{ 0x4C9417F0, keys500_1, 0x43 },
	{ 0x4C9416F0, keys500_0, 0x43 },
	{ 0x4C9415F0, keys390_1, 0x43 },
	{ 0x4C9414F0, keys390_0, 0x43 },
	{ 0x4C9412F0, keys370_0, 0x43 },
	{ 0x4C9413F0, keys370_1, 0x43 },
	{ 0x457B10F0, keys370_2, 0x5B },
	
	{ 0xD82310F0, keys02G_E, 0x51 }, 
	{ 0xD8231EF0, keys03G_E, 0x51 },
	{ 0xD82328F0, keys05G_E, 0x51 },

	{ 0x4C940DF0, keys360_0, 0x43 },
	{ 0x4C9410F0, keys360_1, 0x43 },
	
	{ 0x4C940BF0, keys330_0, 0x43 }, 
	{ 0x457B0AF0, keys330_1, 0x5B }, 
	{ 0x38020AF0, keys330_2, 0x5A }, 
	{ 0x4C940AF0, keys330_3, 0x43 }, 
	{ 0x4C940CF0, keys330_4, 0x43 }, 

	{ 0xcfef09f0, keys310_0, 0x62 },
	{ 0x457b08f0, keys310_1, 0x5B },
	{ 0x380208F0, keys310_2, 0x5A },
	{ 0xcfef08f0, keys310_3, 0x62 },

	{ 0xCFEF07F0, keys303_0, 0x62 },
	{ 0xCFEF06F0, keys300_0, 0x62 },
	{ 0x457B06F0, keys300_1, 0x5B },
	{ 0x380206F0, keys300_2, 0x5A },
	
	{ 0xCFEF05F0, keys280_0, 0x62 },
	{ 0x457B05F0, keys280_1, 0x5B },
	{ 0x380205F0, keys280_2, 0x5A },
	{ 0x16D59E03, keys260_0, 0x62 },
	{ 0x76202403, keys260_1, 0x5B },
	{ 0x0F037303, keys260_2, 0x5A }
};


static TAG_INFO2 *GetTagInfo2(u32 tagFind)
{
    int iTag;

    for (iTag = 0; iTag < sizeof(g_tagInfo2) / sizeof(TAG_INFO2); iTag++)
	{
        if (g_tagInfo2[iTag].tag == tagFind)
		{
            return &g_tagInfo2[iTag];
		}
	}

	return NULL; // not found
}

static int DecryptPRX2(const u8 *inbuf, u8 *outbuf, u32 size, u32 tag)
{
	TAG_INFO2 * pti = GetTagInfo2(tag);

	if (!pti)
	{
		//Kprintf("Unknown tag 0x%08X.\n", tag);
		return -1;
	}	

	int retsize = *(int *)&inbuf[0xB0];
	u8	tmp1[0x150], tmp2[0x90+0x14], tmp3[0x60+0x14], tmp4[0x20];

	memset(tmp1, 0, 0x150);
	memset(tmp2, 0, 0x90+0x14);
	memset(tmp3, 0, 0x60+0x14);
	memset(tmp4, 0, 0x20);

	if (inbuf != outbuf)
		memcpy(outbuf, inbuf, size);

	if (size < 0x160)
	{
		Kprintf("Buffer not big enough.\n");
		return -2;
	}

	if (((u32)outbuf & 0x3F))
	{
		Kprintf("Buffer not aligned to 64 bytes.\n");
		return -3;
	}

	if ((size - 0x150) < retsize)
	{
		Kprintf("No enough data.\n");
		return -4;
	}

	memcpy(tmp1, outbuf, 0x150);

	int i, j;
	u8 *p = tmp2+0x14;

	for (i = 0; i < 9; i++)
	{
		for (j = 0; j < 0x10; j++)
		{
			p[(i << 4) + j] = pti->key[j]; 	
					
		}

		p[(i << 4)] = i;
	}

	if (Scramble((u32 *)tmp2, 0x90, pti->code) < 0)
	{
		Kprintf("Error in Scramble #1.\n");
		return -5;
	}

	memcpy(outbuf, tmp1+0xD0, 0x5C);
	memcpy(outbuf+0x5C, tmp1+0x140, 0x10);
	memcpy(outbuf+0x6C, tmp1+0x12C, 0x14);
	memcpy(outbuf+0x80, tmp1+0x080, 0x30);
	memcpy(outbuf+0xB0, tmp1+0x0C0, 0x10);
	memcpy(outbuf+0xC0, tmp1+0x0B0, 0x10);
	memcpy(outbuf+0xD0, tmp1+0x000, 0x80);

	memcpy(tmp3+0x14, outbuf+0x5C, 0x60);	

	if (Scramble((u32 *)tmp3, 0x60, pti->code) < 0)
	{
		Kprintf("Error in Scramble #2.\n");
		return -6;
	}

	memcpy(outbuf+0x5C, tmp3, 0x60);
	memcpy(tmp3, outbuf+0x6C, 0x14);
	memcpy(outbuf+0x70, outbuf+0x5C, 0x10);
	
	if(pti->type == 3)
	{
		memcpy(tmp4, outbuf+0x3C, 0x20);
		memcpy(outbuf+0x50, tmp4, 0x20);
		memset(outbuf+0x18, 0, 0x38);
	}else
		memset(outbuf+0x18, 0, 0x58);
	
	memcpy(outbuf+0x04, outbuf, 0x04);
	*((u32 *)outbuf) = 0x014C;
	memcpy(outbuf+0x08, tmp2, 0x10);
	
	/* sha-1 */

	if (sceUtilsBufferCopyWithRange(outbuf, 3000000, outbuf, 3000000, 0x0B) != 0)
	{
		Kprintf("Error in sceUtilsBufferCopyWithRange 0xB.\n");
		return -7;
	}

	if (memcmp(outbuf, tmp3, 0x14) != 0)
	{
		Kprintf("SHA-1 is incorrect.\n");
        return -8;
	}
	
	int iXOR;

	for (iXOR = 0; iXOR < 0x40; iXOR++)
	{
		tmp3[iXOR+0x14] = outbuf[iXOR+0x80] ^ tmp2[iXOR+0x10];
	}

	if (Scramble((u32 *)tmp3, 0x40, pti->code) != 0)
	{
		Kprintf("Error in Scramble #2.\n");
		return -9;
	}
	
	for (iXOR = 0x3F; iXOR >= 0; iXOR--)
	{
		outbuf[iXOR+0x40] = tmp3[iXOR] ^ tmp2[iXOR+0x50]; // uns 8
	}

	if (pti->type == 3)
	{
		memcpy(outbuf+0x80, tmp4, 0x20);
		memset(outbuf+0xA0, 0, 0x10);
		*(u32*)&outbuf[0xA4] = 1;
		*(u32*)&outbuf[0xA0] = 1;
	} else
	{
		memset(outbuf+0x80, 0, 0x30);
		*(u32*)&outbuf[0xA0] = 1;
	}

	memcpy(outbuf+0xB0, outbuf+0xC0, 0x10);
	memset(outbuf+0xC0, 0, 0x10);
	memcpy(outbuf+0xD0, outbuf+0xD0, 0x80);

	// The real decryption
	if (sceUtilsBufferCopyWithRange(outbuf, size, outbuf+0x40, size-0x40, 0x1) != 0)
	{
		Kprintf("Error in sceUtilsBufferCopyWithRange 0x1.\n");
		return -1;
	}

	if (retsize < 0x150)
	{
		// Fill with 0
		memset(outbuf+retsize, 0, 0x150-retsize);		
	}

	return retsize;
}

int pspDecryptPRX(u8 *data, u32 size, u32 *out_size)
{
	int retsize = DecryptPRX1(data, data, size, *(u32 *)&data[0xD0]);

	if (retsize <= 0)
	{
		retsize = DecryptPRX2(data, data, size, *(u32 *)&data[0xD0]);
	}
	
	if (retsize <= 0)
	{
		return -1;
	}

	out_size[0] = retsize;
	return 0;
}


================================================
FILE: src/downgrade660_ctrl/utils.c
================================================
/*
	Downgrade Control -> utils.c -> Responsible for providing common utilities interfacing the kernel
	by Davee
	
	30/12/2010
*/

#include <pspkernel.h>
#include <pspsysmem_kernel.h>

#include <stdio.h>
#include <string.h>
#include <systemctrl.h>

#include "utils.h"

void ClearCaches(void)
{
	sceKernelIcacheClearAll();
	sceKernelDcacheWritebackAll();
}

u32 FindFunc(const char *modname, const char *lib, u32 nid)
{
	int i = 0, u;
	
	/* try and find the module by name */
	SceModule2 *mod = (SceModule2 *)sceKernelFindModuleByName(modname);
	
	/* if fail */
	if (!mod)
	{
		/* fail */
		return 0;
	}
	
	/* copy over the structure data */
	u32 entry_size = mod->ent_size;
	u32 entry_start = (u32)mod->ent_top;
	
	/* loop until end of entry table */
	while (i < entry_size)
	{
		/* cast structure to memory */
		SceLibraryEntryTable *entry = (SceLibraryEntryTable *)(entry_start + i);
		
		/* if there is a libname, compare it to the lib else if there is no lib and there is no libname */
		if ((entry->libname && (strcmp(entry->libname, lib) == 0)) || (lib == NULL && entry->libname == NULL))
		{
			/* copy the table pointer and get the total number of entries */
			u32 *table = entry->entrytable;
			int total = entry->stubcount + entry->vstubcount;
			
			/* if there is some entries continue */
			if (total > 0)
			{ 
				/* loop through the entries */
				for (u = 0; u < total; u++)
				{
					/* if the nid matches */
					if (table[u] == nid)
					{
						/* return the pointer */
						return table[u + total];
					}
				} 
			} 	
		}
		
		/* increment the counter */
		i += (entry->len << 2);
	}
	
	/* could not find function */
	return 0;
}

void PatchSyscall(u32 addr, void *newaddr)
{
	u32 *vectors, i;
	
	/* get the vectors address from the co-processor */
	__asm__ volatile ("cfc0 %0, $12\n" "nop\n" : "=r" (vectors));
	
	/* loop through them */
	for (i = 0; i < 0x1000; i++)
	{
		/* if this is the address */
		if (vectors[i + 4] == addr)
		{
			/* then replace it :D */
			vectors[i + 4] = (u32)newaddr;
		}
	}
}


================================================
FILE: src/downgrade660_ctrl/utils.h
================================================
/*
	Downgrade Control -> utils.h -> Provide API documentation and definitions for utilities
	by Davee
	
	30/12/2010
*/
#ifndef __UTILS__H__
#define __UTILS__H__

#define U_EXTRACT_IMPORT(x) ((((u32)_lw((u32)x)) & ~0x08000000) << 2)
#define K_EXTRACT_IMPORT(x) (((((u32)_lw((u32)x)) & ~0x08000000) << 2) | 0x80000000)
#define U_EXTRACT_CALL(x) ((((u32)_lw((u32)x)) & ~0x0C000000) << 2)
#define K_EXTRACT_CALL(x) (((((u32)_lw((u32)x)) & ~0x0C000000) << 2) | 0x80000000)

#define MAKE_JUMP(a, f)					_sw(0x08000000 | (((u32)(f) >> 2)  & 0x03ffffff), a)
#define MAKE_CALL(a, f)					_sw(0x0C000000 | (((u32)(f) >> 2)  & 0x03ffffff), a)
#define REDIRECT_FUNCTION(a, f) 		{ u32 address = a; _sw(0x08000000 | (((u32)(f) >> 2)  & 0x03ffffff), address);  _sw(0, address+4); }

#define KERNEL_HIJACK_FUNCTION(a, f, ptr)	{ \
											static u32 patch_buffer[3]; \
											_sw(_lw(a + 0x00), (u32)patch_buffer + 0x00); \
											_sw(_lw(a + 0x04), (u32)patch_buffer + 0x08);\
											MAKE_JUMP((u32)patch_buffer + 0x04, a + 0x08); \
											REDIRECT_FUNCTION(a, f); \
											ptr = (void *)patch_buffer; \
										}
/**
	Clears both the instruction and data caches
*/
void ClearCaches(void);

/**
	Allows to modify the kernel address called when a specific syscall is initiated
	
	@param addr: the address of the kernel function syscall you want to control
	@param newaddr: the new address the syscall will call
*/
void PatchSyscall(u32 addr, void *newaddr);

/**
	Find an export within the system
	
	@param modname: the name of the module containing the export
	@param libname: the library the export belongs to
	@param nid: the nid of the export
	
	@return the address of export else 0 on error
*/
u32 FindFunc(const char *modname, const char *lib, u32 nid);

#endif /* __UTILS__H__ */


================================================
FILE: src/downgrade_ctrl/631mapfile.txt
================================================
@SysMemForKernel
0x55A40B2C:0xF5E82409 //NID RESOLVED
0x9697CD32:0xE10F21CF //NID RESOLVED
0xB2C7AA36:0x00E9A04A //NID RESOLVED
0x3FC9AE6A:0x5E8DCA05 //NID RESOLVED
0x6373995D:0x458A70B5 //NID RESOLVED
@memlmd
0x7CF1CD3E:0xE42AFE2E //NID RESOLVED
@LoadCoreForKernel
0xCF8A41B1:0xEF8A0BEA //NID RESOLVED
0xCCE4A157:0xED53894F //NID RESOLVED
0xD8779AC6:0x8D46E9DF //NID RESOLVED
@ModuleMgrForKernel
0x644395E2:0xA95C26C8 //NID RESOLVED


================================================
FILE: src/downgrade_ctrl/Makefile
================================================
release: all
	psp-fixup-imports -m $(PSP_FW_VERSION)mapfile.txt $(TARGET).prx
	psp-packer $(TARGET).prx
	bin2c $(TARGET).prx ../$(TARGET).h $(TARGET)
	
TARGET = downgrade_ctrl
OBJS = main.o utils.o patch_table.o decrypt.o pspdecrypt.o extra_stubs.o ../libasm/libinfinityKernel.o

INCDIR = ../include
CFLAGS = -Os -G0 -Wall -fno-pic -fshort-wchar
ASFLAGS = $(CFLAGS)

BUILD_PRX = 1
PRX_EXPORTS = exports.exp

PSP_FW_VERSION = 631

USE_KERNEL_LIBS=1
USE_KERNEL_LIBC=1

LIBDIR = ../lib
LDFLAGS = -nostartfiles
LIBS = -lpspsystemctrl_kernel

PSPSDK=$(shell psp-config --pspsdk-path)
include $(PSPSDK)/lib/build.mak



================================================
FILE: src/downgrade_ctrl/decrypt.c
================================================
/*
	Downgrade Control -> decrypt.c -> Responsible for decryption patches and hooks
	by Davee
	
	31/12/2010
*/

#include <pspkernel.h>
#include <pspsysmem_kernel.h>

#include <stdio.h>
#include <string.h>
#include <systemctrl.h>

#include "decrypt.h"
#include "patch_table.h"

int pspDecryptPRX(void *exec, u32 exec_size, u32 *out_size);

int (* sceMesgLed_driver_81F72B1F)(void *exec, u32 size, u32 *outsize) = NULL;
extern u32 g_spoof_ver;

int sceResmgr_9DC14891_patched(void *data, u32 datasize, u32 *outsize)
{
	/* call the original function to decrypt the index.dat */
	int res = sceResmgr_driver_9DC14891(data, datasize, outsize);
	
	/* if there is a firmware version, we will generate a version.txt to downgrade */
	if (g_spoof_ver)
	{
		sprintf( data,
				"release:%01X.%01X%01X:\n"
				"build:0000,0,3,1,0:builder@vsh-build6\n"
				"system:56422@release_%03X,0x%08X:\n"
				"vsh:p6576@release_%03X,v57929@release_%03X,20100625:\n"
				"target:1:WorldWide\n",
				/* first line, version (X.YZ) */ (g_spoof_ver >> 8) & 0xF, (g_spoof_ver >> 4) & 0xF, g_spoof_ver & 0xF,
				/* third line, release_XYZ + devkit */ g_spoof_ver, (((g_spoof_ver >> 8) & 0xF) << 24) | (((g_spoof_ver >> 4) & 0xF) << 16) | ((g_spoof_ver & 0xF) << 8) | 0x10,
				/* forth line, release_XYZ + release_XYZ */ g_spoof_ver, g_spoof_ver
				);
	}
	
	/* return the decryption result */
	return res;
}

void PatchMesgled(u32 text_addr)
{
	/* if firmware is >= 6.30 */
	if (sceKernelDevkitVersion() >= 0x06030010)
	{
		int model = sceKernelGetModel();
		if(model == 6 || model == 8)
		{
			model = 3;
		}
		
		/* Patch mesgled to allow older updaters to boot */
		_sw(0, text_addr + g_patch_table.new_updater_check[model]);
	}
}

int sceMesgLed_driver_81F72B1F_patched(void *exec, u32 exec_size, u32 *out_size)
{
	/* do sony decryption */
	int res = sceMesgLed_driver_81F72B1F(exec, exec_size, out_size);
	
	/* check for error */
	if (res != 0)
	{
		/* lets decrypt */
		res = pspDecryptPRX(exec, exec_size, out_size);
	}
	
	/* return result */
	return res;
}

int memlmd_7CF1CD3E_patched(void *exec, u32 exec_size, u32 *out_size)
{
	/* do sony decryption */
	int res = memlmd_7CF1CD3E(exec, exec_size, out_size);
	
	/* check for error */
	if (res != 0)
	{
		/* lets decrypt */
		res = pspDecryptPRX(exec, exec_size, out_size);
	}
	
	/* return result */
	return res;
}


================================================
FILE: src/downgrade_ctrl/decrypt.h
================================================
/*
	Downgrade Control -> decrypt.h -> Provide API documentation and definitions
	by Davee
	
	31/12/2010
*/
#ifndef __DECRYPT_H__
#define __DECRYPT_H__

/* our functions */
void PatchMesgled(u32 text_addr);
int memlmd_7CF1CD3E_patched(void *exec, u32 exec_size, u32 *out_size);
int sceResmgr_9DC14891_patched(void *data, u32 datasize, u32 *outsize);
int sceMesgLed_driver_81F72B1F_patched(void *exec, u32 size, u32 *outsize);

extern int (* sceMesgLed_driver_81F72B1F)(void *exec, u32 size, u32 *outsize);

/* prototypes */
int memlmd_7CF1CD3E(void *exec, u32 exec_size, u32 *out_size);
int sceResmgr_driver_9DC14891(void *data, u32 datasize, u32 *outsize);
int sceUtilsBufferCopyWithRange(void *dst, u32 dst_size, void *src, u32 src_size, u32 cmd);
int sceUtilsBufferCopyByPollingWithRange(void *dst, u32 dst_size, void *src, u32 src_size, u32 cmd);
int sceKernelPowerLock(void);
int sceKernelPowerUnlock(void);

/* data structures */
typedef struct
{
	u32 tag;
	u8 key[16];
} mesgled_keys_struct;

typedef struct
{
	u32 signature; 		//0
	u16 mod_attribute; 	//4
	u16 comp_attribute;	//6
	u8 module_ver_lo;	//8
	u8 module_ver_hi;	//9
	char modname[28];	//0xA
	u8 mod_version;		//0x26
	u8 nsegments;		//0x27
	u32 elf_size;		//0x28
	u32 psp_size;		//0x2C
	u32 boot_entry;		//0x30
	u32 modinfo_offset; //0x34
	int bss_size;		//0x38
	u16 seg_align[4];	//0x3C
	u32 seg_address[4];	//0x44
	int seg_size[4];	//0x54
	u32 reserved[5];	//0x64
	u32 devkit_version;	//0x78
	u8 decrypt_mode;	//0x7C
	u8 padding;			//0x7D
	u16 overlap_size;	//0x7E
	u8 key_data[0x30];	//0x80
	u32 comp_size;		//0xB0
	int _80;			//0xB4
	u32 unk_B8;			//0xB8
	u32 unk_BC;			//0xBC
	u8 key_data2[0x10];	//0xC0
	u32 tag;			//0xD0
	u8 scheck[0x58];	//0xD4
	u8 sha1_hash[0x14];	//0x12C
	u8 key_data4[0x10]; //0x140
} PSP_Header2; //0x150

typedef struct
{
	u32 mode; //0
	u32 unk_4;
	u32 unk_8;
	u32 keyseed; //12
	u32 size; //16
} KIRK_CMD_HEADER; //20

#define KIRK_CMD_7		(7)
#define KIRK_CMD_SHA1	(0xB)

#endif /* __DECRYPT_H__ */


================================================
FILE: src/downgrade_ctrl/exports.exp
================================================
# Define the exports for the prx
PSP_BEGIN_EXPORTS

# These four lines are mandatory (although you can add other functions like module_stop)
# syslib is a psynonym for the single mandatory export.
PSP_EXPORT_START(syslib, 0, 0x8000)
PSP_EXPORT_FUNC_NID(module_start,0xD3744BE0)
PSP_EXPORT_VAR_HASH(module_info)
PSP_EXPORT_END

PSP_END_EXPORTS


================================================
FILE: src/downgrade_ctrl/extra_stubs.S
================================================
	.set noreorder

#include "pspstub.s"
	
	STUB_START	"sceResmgr_driver",0x00090011,0x00010005
	STUB_FUNC	0x9DC14891,sceResmgr_driver_9DC14891
	STUB_END
	
	STUB_START	"memlmd",0x00090011,0x00010005
	STUB_FUNC	0x7CF1CD3E,memlmd_7CF1CD3E
	STUB_END
	
	STUB_START	"semaphore",0x00090011,0x00020005
	STUB_FUNC	0x4C537C72,sceUtilsBufferCopyWithRange
	STUB_FUNC	0x77E97079,sceUtilsBufferCopyByPollingWithRange
	STUB_END

	STUB_START	"sceIdStorage_driver",0x00090011,0x00010005
	STUB_FUNC	0x6FE062D1,sceIdStorageLookup
	STUB_END

================================================
FILE: src/downgrade_ctrl/main.c
================================================
/*
	Downgrade Control -> Restore kernel patches and enforce updater launch
	by Davee
	
	31/12/2010
*/

#include <pspkernel.h>
#include <pspidstorage.h>
#include <pspsysmem_kernel.h>

#include <stdio.h>
#include <string.h>
#include <systemctrl.h>
#include <libinfinity.h>

#include "utils.h"
#include "patch_table.h"
#include "decrypt.h"

PSP_MODULE_INFO("DowngraderCTRL", 0x3007, 1, 0);

/* function pointers */
int (* PrologueModule)(void *modmgr_param, SceModule *mod) = NULL;
STMOD_HANDLER previous = NULL;

typedef struct __attribute__((packed))
{
        int magic; // 0
        int version; // 4
        unsigned int keyofs; // 8
        unsigned int valofs; // 12
        int count; // 16
} SfoHeader;

typedef struct __attribute__((packed))
{
        unsigned short nameofs; // 0
        char alignment; // 2
        char type; // 3
        int valsize; // 4
        int totalsize; // 8
        unsigned short valofs; // 12
        short unknown; // 16
} SfoEntry;

u32 g_spoof_ver = 0;
u8 g_sfo_buffer[4 << 10];

int ApplyFirmware(void)
{
	int i;
	char *fw_data = NULL;
	u8 device_fw_ver[4];
	u32 pbp_header[0x28/4];
	SfoHeader *header = (SfoHeader *)g_sfo_buffer;
    SfoEntry *entries = (SfoEntry *)((char *)g_sfo_buffer + sizeof(SfoHeader));
	
	/* Lets open the updater */
	char *file = (sceKernelGetModel() == 4) ? ("ef0:/PSP/GAME/UPDATE/EBOOT.pbp") : ("ms0:/PSP/GAME/UPDATE/EBOOT.pbp");
	
	/* set k1 */
	u32 k1 = pspSdkSetK1(0);
	
	/* lets open the file */
	SceUID fd = sceIoOpen(file, PSP_O_RDONLY, 0777);
	
	/* check for failure */
	if (fd < 0)
	{
		/* rage */
		pspSdkSetK1(k1);
		return fd;
	}
	
	/* read the PBP header */
	sceIoRead(fd, pbp_header, sizeof(pbp_header));
	
	/* seek to the SFO */
	sceIoLseek32(fd, pbp_header[8/4], PSP_SEEK_SET);
	
	/* calculate the size of the SFO */
	u32 sfo_size = pbp_header[12/4] - pbp_header[8/4];
	
	/* check if greater than buffer size */
	if (sfo_size > sizeof(g_sfo_buffer))
	{
		/* too much */
		pspSdkSetK1(k1);
		return -2;
	}
	
	/* read the sfo */
	sceIoRead(fd, g_sfo_buffer, sizeof(g_sfo_buffer));
	
	/* close the file */
	sceIoClose(fd);
	
	/* now parse the SFO */
	for (i = 0; i < header->count; i++)
	{
		/* check this name */
		if (strcmp((char *)((char *)g_sfo_buffer + header->keyofs + entries[i].nameofs), "UPDATER_VER") == 0)
		{
			/* get the string */
			fw_data = (char *)((char *)g_sfo_buffer + header->valofs + entries[i].valofs);
			break;
		}
	}
	
	/* see if we went through all the data */
	if (i == header->count)
	{
		/* error */
		pspSdkSetK1(k1);
		return -3;
	}
	
	/* ok, we have the firmware version in the eboot. */
	u32 min_ver = 0;
	u32 updater_ver = (((fw_data[0] - '0') & 0xF) << 8) | (((fw_data[2] - '0') & 0xF) << 4) | (((fw_data[3] - '0') & 0xF) << 0);

	/* ok, now get the idstorage value */
	int res = sceIdStorageLookup(0x51, 0, device_fw_ver, 4);
	
	/* check for error */
	if (res < 0)
	{
		/* check model */
		if (sceKernelGetModel() != 0)
		{
			/* invalid error */
			return -4;
		}
		
		/* firmware 1.00 */
		min_ver = 0x100;
	}
	else
	{
		/* convert to hex */
		min_ver = (((device_fw_ver[0] - '0') & 0xF) << 8) | (((device_fw_ver[2] - '0') & 0xF) << 4) | (((device_fw_ver[3] - '0') & 0xF) << 0);
	}
	
	/* set the result to 0 */
	res = 0;
	
	/* check if the updater is less than the minimum version */
	if (updater_ver < min_ver)
	{
		/* ok, check for 6.35 and 09g */
		if ((min_ver != 0x630 && min_ver != 0x635) || sceKernelGetModel() != 8)
		{
			/* error */
			pspSdkSetK1(k1);
			return -5;
		}
		
		/* set result to 1 D: */
		res = 1;
	}

	/* do spoof! */
	g_spoof_ver = updater_ver;
	pspSdkSetK1(k1);
	return res;
}

#define INDEXFILE "flash0:/vsh/etc/index_04g.dat"
#define NEW_INDEXFILE "flash0:/vsh/etc/index_09g.dat"

SceUID sceIoOpenPatched(char *file, u32 mode, u32 mode2)
{
	/* check indexfile */
	if (strcmp(file, INDEXFILE) == 0)
	{
		/* if read mode, copy */
		if (mode == PSP_O_RDONLY)
		{
			strcpy(file, NEW_INDEXFILE);
		}
	}
	
	/* call original function */
	return sceIoOpen(file, mode, mode2);
}

int sceIoGetstatPatched(char *file, SceIoStat *stat)
{
	/* check indexfile */
	if (strcmp(file, INDEXFILE) == 0)
	{
		strcpy(file, NEW_INDEXFILE);
	}
	
	/* call original function */
	return sceIoGetstat(file, stat);
}

/* idstorage patching func */
int (* pspUtilsBufferCopyWithRange)(void *dst, u32 dst_size, void *src, u32 src_size, u32 cmd) = NULL;
int sceUtilsBufferCopyWithRangePatched(void *dst, u32 dst_size, void *src, u32 src_size, u32 cmd)
{
	u8 ids_cert[0xB8];
	
	/* if idstorage check */
	if (cmd == 0x12)
	{
		/* ok lets get the idstorage 0x100 key */
		int res = sceIdStorageLookup(0x100, 0x38, ids_cert, 0xB8);
		
		/* check for error */
		if (res < 0)
		{
			/* attempt with backup key */
			res = sceIdStorageLookup(0x120, 0x38, ids_cert, 0xB8);
			
			/* if error, exit */
			if (res < 0)
			{
				return res;
			}
		}
	
		/* yay its 0x100 key */
		/* change the model to 04g */
		ids_cert[7] = 6;
		
		/* copy the new certificate back */
		memcpy(src, ids_cert, sizeof(ids_cert));
		return 0;
	}
	
	/* return function */
	return pspUtilsBufferCopyWithRange(dst, dst_size, src, src_size, cmd);
}

int (* sceLflashFatfmtStartFatfmtOriginal)(int argc, char *argv[]) = NULL;

int sceLflashFatfmtStartFatfmtPatched(int argc, char *argv[])
{
    infSetRedirectionStatus(0);
    ClearCaches();
    
    return sceLflashFatfmtStartFatfmtOriginal(argc, argv);
}

int OnModuleStart(SceModule *mod)
{
	if (strcmp(mod->modname, "sceMesgLed") == 0)
	{
		PatchMesgled(mod->text_addr);
		ClearCaches();
	}
    
    else if (strcmp(mod->modname, "sceLflashFatfmtUpdater") == 0)
    {
        PatchSyscall(FindFunc("sceLflashFatfmtUpdater", "LflashFatfmt", 0xB7A424A4), sceLflashFatfmtStartFatfmtPatched);
        sceLflashFatfmtStartFatfmtOriginal = FindFunc("sceLflashFatfmtUpdater", "LflashFatfmt", 0xB7A424A4);
        ClearCaches();
    }
	
	else if (strcmp(mod->modname, "updater") == 0)
	{
		/* ok, lets see what we're doing here! */
		int res = ApplyFirmware();
		
		/* check for success */
		if (res >= 0)
		{
			/* do these patches if we have 09g going to 6.XX */
			if (res == 1)
			{
				/* patch the IO */
				PatchSyscall(FindFunc("sceIOFileManager", "IoFileMgrForUser", 0x109F50BC), sceIoOpenPatched);
				PatchSyscall(FindFunc("sceIOFileManager", "IoFileMgrForUser", 0xACE946E8), sceIoGetstatPatched);
				
				/* find the function for idstorage verify */
				u32 func_address = FindFunc("sceMemlmd", "semaphore", 0x4C537C72);
				
				/* check if we have it... */
				if (func_address == 0)
				{
					/* ERROR */
					asm("break\n");
				}
				
				/* ok, lets patch it */
				KERNEL_HIJACK_FUNCTION(func_address, sceUtilsBufferCopyWithRangePatched, pspUtilsBufferCopyWithRange);
			}
			
			/* patch the version check on index.dat */
			PatchSyscall(FindFunc("sceMesgLed", "sceResmgr", 0x9DC14891), sceResmgr_9DC14891_patched);
			ClearCaches();	
		}
	}

	
	/* if there is a previous handler, call it */
	if (previous)
		return previous((SceModule2 *)mod);
	
	/* else just return 0 */
	return 0;
}

int PrologueModulePatched(void *modmgr_param, SceModule *mod)
{
	/* modmgr_param has changed from 1.50 so I have no included the structure defintion, for an updated version a re-reverse of 6.30 modulemgr is required */
	int res = PrologueModule(modmgr_param, mod);
	
	/* If this function errors, the module is shutdown so we better check for it */
	if (res >= 0)
	{
		/* Pass the module through the OnModuleStart chain */
		OnModuleStart(mod);
	}
	
	/* return success */
	return res;
}

static void PatchModuleManager(void)
{
	/* find the modulemgr module */
	SceModule *mod = sceKernelFindModuleByName("sceModuleManager");
	u32 text_addr = mod->text_addr;
	
	/* link the original calls before hook */
	PrologueModule = (void *)(text_addr + g_patch_table.prologue_module_func);
	
	/* Patch call to PrologueModule from the StartModule function to allow a full coverage of loaded modules (even those without an entry point) */
	MAKE_CALL(text_addr + g_patch_table.prologue_module_call, PrologueModulePatched);
}

static void PatchLoadCore(void)
{
	/* Find the loadcore module */
	SceModule *mod = sceKernelFindModuleByName("sceLoaderCore");
	u32 text_addr = mod->text_addr;
	
	/* Relink the memlmd calls (that reboot destroyed) */
	MAKE_CALL(text_addr + g_patch_table.memlmd_call[0], text_addr + g_patch_table.memlmd_stub[0]);
	MAKE_CALL(text_addr + g_patch_table.memlmd_call[1], text_addr + g_patch_table.memlmd_stub[1]);

	/* if >= 6.30 we need patches for the decryption */
	if (sceKernelDevkitVersion() >= 0x06030010)
	{
		/* we need to hook updater decryption */
		MAKE_CALL(text_addr + g_patch_table.memlmd_call[0], memlmd_7CF1CD3E_patched);
		MAKE_CALL(text_addr + g_patch_table.updater_decrypt_call, sceMesgLed_driver_81F72B1F_patched);
		
		sceMesgLed_driver_81F72B1F = (void *)(text_addr + g_patch_table.updater_decrypt_func);
	}
}

int module_start(SceSize argsize, void *argp)
{
	/* check if we're running as a plugin or in boot */
	if (sceKernelFindModuleByName("sceInit"))
	{
		/* plugin, assume we've got HEN (and an M33 nid resolver) */
		/* check for >= 6.30 */
		if (sceKernelDevkitVersion() >= 0x06030010)
		{
			/* this is firmware dependant :/ so not supported */
			return 0;
		}
		
		/* register with sctrl */
		previous = sctrlHENSetStartModuleHandler((STMOD_HANDLER)OnModuleStart);
	}
	else
	{
		/* boot */
		/* get patches and nids from loader */
		if (CopyPatchTable(&g_patch_table, (void *)PATCH_TABLE_ADDR_START, sceKernelDevkitVersion()) == 0)
		{
			/* no patches, no go */
			return 0;
		}
		
		/* perform main system patches */
		PatchLoadCore();
		PatchModuleManager();
	}

	/* Clear the caches and return success */
	ClearCaches();
	return 0;
}


================================================
FILE: src/downgrade_ctrl/patch_table.c
================================================
/*
	Downgrade Control -> patch_table.c -> Responsible for searching and handling patch tables
	by Davee
	
	01/01/2011
*/

#include <pspkernel.h>
#include <pspsysmem_kernel.h>

#include <stdio.h>
#include <string.h>
#include <systemctrl.h>

#include "patch_table.h"

PatchTable g_patch_table;

int CopyPatchTable(PatchTable *dst_table, void *_src_table, u32 devkit)
{
	int i;
	
	/* get the number of entries in the table */
	u32 nentries = _lw((u32)_src_table);
	
	/* cast our pointer */
	PatchTable *src_table = (PatchTable *)(_src_table + 4);
	
	/* loop through the entries */
	for (i = 0; i < nentries; i++)
	{
		/* if same devkit */
		if (src_table->devkit == devkit)
		{
			/* copy over and return 1 for a complete transfer */
			memcpy(dst_table, src_table, sizeof(PatchTable));
			return 1;
		}
		
		/* increment */
		src_table++;
	}
	
	/* no transfer */
	return 0;
}


================================================
FILE: src/downgrade_ctrl/patch_table.h
================================================
/*
	Downgrade Control -> patch_table.h -> Provide API documentation and definitions for the table patching
	by Davee
	
	01/01/2011
*/
#ifndef __PATCH_TABLE_H__
#define __PATCH_TABLE_H__

typedef struct
{
	u32 devkit;
	u32 new_updater_check[5];
	u32 updater_decrypt_call;
	u32 updater_decrypt_func;
/*	u32 new_updater_keys;
	u32 new_updater_t3_arg;
	u32 new_updater_seed;
	u32 new_updater_mode;
	u32 new_updater_stack_arg;*/
	u32 prologue_module_func;
	u32 prologue_module_call;
	u32 memlmd_call[2];
	u32 memlmd_stub[2];
} PatchTable;

#define PATCH_TABLE_ADDR_START	(0x88FC0000)

extern PatchTable g_patch_table;
int CopyPatchTable(PatchTable *dst_table, void *_src_table, u32 devkit);

#endif /* __PATCH_TABLE_H__ */


================================================
FILE: src/downgrade_ctrl/pspdecrypt.c
================================================
#include <pspsdk.h>
#include <pspkernel.h>
#include <pspdebug.h>
//#include <pspcrypt.h>
#include <psputilsforkernel.h>
#include <pspthreadman_kernel.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#include "decrypt.h"
//#include <pspdecrypt.h>
//#include <systemctrl.h>


extern int UtilsForKernel_6C6887EE(void *, u32, void *, void *);

////////// Decryption 1 //////////

// use pre-calculated keys (step1 results)

u32 g_key0[] =
{
  0x7b21f3be, 0x299c5e1d, 0x1c9c5e71, 0x96cb4645, 0x3c9b1be0, 0xeb85de3d,
  0x4a7f2022, 0xc2206eaa, 0xd50b3265, 0x55770567, 0x3c080840, 0x981d55f2,
  0x5fd8f6f3, 0xee8eb0c5, 0x944d8152, 0xf8278651, 0x2705bafa, 0x8420e533,
  0x27154ae9, 0x4819aa32, 0x59a3aa40, 0x2cb3cf65, 0xf274466d, 0x3a655605,
  0x21b0f88f, 0xc5b18d26, 0x64c19051, 0xd669c94e, 0xe87035f2, 0x9d3a5909,
  0x6f4e7102, 0xdca946ce, 0x8416881b, 0xbab097a5, 0x249125c6, 0xb34c0872,
};

u32 g_key2[] =
{
  0xccfda932, 0x51c06f76, 0x046dcccf, 0x49e1821e, 0x7d3b024c, 0x9dda5865,
  0xcc8c9825, 0xd1e97db5, 0x6874d8cb, 0x3471c987, 0x72edb3fc, 0x81c8365d,
  0xe161e33a, 0xfc92db59, 0x2009b1ec, 0xb1a94ce4, 0x2f03696b, 0x87e236d8,
  0x3b2b8ce9, 0x0305e784, 0xf9710883, 0xb039db39, 0x893bea37, 0xe74d6805,
  0x2a5c38bd, 0xb08dc813, 0x15b32375, 0x46be4525, 0x0103fd90, 0xa90e87a2,
  0x52aba66a, 0x85bf7b80, 0x45e8ce63, 0x4dd716d3, 0xf5e30d2d, 0xaf3ae456,
};

u32 g_key3[] =
{
  0xa6c8f5ca, 0x6d67c080, 0x924f4d3a, 0x047ca06a, 0x08640297, 0x4fd4a758,
  0xbd685a87, 0x9b2701c2, 0x83b62a35, 0x726b533c, 0xe522fa0c, 0xc24b06b4,
  0x459d1cac, 0xa8c5417b, 0x4fea62a2, 0x0615d742, 0x30628d09, 0xc44fab14,
  0x69ff715e, 0xd2d8837d, 0xbeed0b8b, 0x1e6e57ae, 0x61e8c402, 0xbe367a06,
  0x543f2b5e, 0xdb3ec058, 0xbe852075, 0x1e7e4dcc, 0x1564ea55, 0xec7825b4,
  0xc0538cad, 0x70f72c7f, 0x49e8c3d0, 0xeda97ec5, 0xf492b0a4, 0xe05eb02a,
};

u32 g_key44[] =
{
  0xef80e005, 0x3a54689f, 0x43c99ccd, 0x1b7727be, 0x5cb80038, 0xdd2efe62,
  0xf369f92c, 0x160f94c5, 0x29560019, 0xbf3c10c5, 0xf2ce5566, 0xcea2c626,
  0xb601816f, 0x64e7481e, 0x0c34debd, 0x98f29cb0, 0x3fc504d7, 0xc8fb39f0,
  0x0221b3d8, 0x63f936a2, 0x9a3a4800, 0x6ecc32e3, 0x8e120cfd, 0xb0361623,
  0xaee1e689, 0x745502eb, 0xe4a6c61c, 0x74f23eb4, 0xd7fa5813, 0xb01916eb,
  0x12328457, 0xd2bc97d2, 0x646425d8, 0x328380a5, 0x43da8ab1, 0x4b122ac9,
};

u32 g_key20[] =
{
  0x33b50800, 0xf32f5fcd, 0x3c14881f, 0x6e8a2a95, 0x29feefd5, 0x1394eae3,
  0xbd6bd443, 0x0821c083, 0xfab379d3, 0xe613e165, 0xf5a754d3, 0x108b2952,
  0x0a4b1e15, 0x61eadeba, 0x557565df, 0x3b465301, 0xae54ecc3, 0x61423309,
  0x70c9ff19, 0x5b0ae5ec, 0x989df126, 0x9d987a5f, 0x55bc750e, 0xc66eba27,
  0x2de988e8, 0xf76600da, 0x0382dccb, 0x5569f5f2, 0x8e431262, 0x288fe3d3,
  0x656f2187, 0x37d12e9c, 0x2f539eb4, 0xa492998e, 0xed3958f7, 0x39e96523,
};

u32 g_key3A[] =
{
  0x67877069, 0x3abd5617, 0xc23ab1dc, 0xab57507d, 0x066a7f40, 0x24def9b9,
  0x06f759e4, 0xdcf524b1, 0x13793e5e, 0x0359022d, 0xaae7e1a2, 0x76b9b2fa,
  0x9a160340, 0x87822fba, 0x19e28fbb, 0x9e338a02, 0xd8007e9a, 0xea317af1,
  0x630671de, 0x0b67ca7c, 0x865192af, 0xea3c3526, 0x2b448c8e, 0x8b599254,
  0x4602e9cb, 0x4de16cda, 0xe164d5bb, 0x07ecd88e, 0x99ffe5f8, 0x768800c1,
  0x53b091ed, 0x84047434, 0xb426dbbc, 0x36f948bb, 0x46142158, 0x749bb492,
};

/* updaters keys */
u8 updaters_keys[0x90+0x14] = 
{
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x0B, 0x01, 0x1C, 0xE7, 0x31, 0x15, 0x6B, 0x83, 
	0x3E, 0x26, 0x0D, 0xCC, 0x69, 0x36, 0x12, 0xCB, 
	0xA7, 0xFD, 0x26, 0x66, 0x93, 0x2A, 0x6E, 0x1A, 
	0x91, 0x2E, 0xC6, 0xFC, 0xD8, 0x2F, 0x00, 0x13, 
	0x5A, 0xE2, 0xDF, 0xB6, 0xA2, 0xE4, 0x27, 0xC8, 
	0x18, 0xC3, 0x50, 0x50, 0xB7, 0xE9, 0x4A, 0xED, 
	0xCC, 0x3C, 0x30, 0xFD, 0x10, 0x6A, 0x2B, 0x0A, 
	0x22, 0xCB, 0xC6, 0xE0, 0x20, 0x65, 0x12, 0xEB, 
	0x7D, 0x4E, 0x2A, 0x37, 0x0B, 0x0A, 0xEF, 0x88, 
	0xDA, 0x06, 0x54, 0xD4, 0x30, 0xAF, 0xCD, 0xCA, 
	0x9A, 0xF9, 0xDA, 0x1A, 0xB0, 0x1B, 0xBB, 0x62, 
	0x0C, 0xDB, 0xF8, 0x44, 0x73, 0x56, 0x14, 0x8E, 
	0x93, 0xB1, 0x2C, 0xFD, 0x67, 0xE2, 0x5D, 0xCB, 
	0x48, 0x5B, 0xD9, 0xB3, 0x54, 0x14, 0xD7, 0x9F, 
	0x79, 0x9C, 0x24, 0xE9, 0xC2, 0x7A, 0x4E, 0x8C, 
	0x4D, 0x24, 0x19, 0x94, 0xFF, 0xC9, 0xC2, 0x2D, 
	0x23, 0x63, 0x51, 0xB8, 0xFA, 0xD6, 0x7F, 0xE6, 
	0x5E, 0xBC, 0x32, 0xB2, 0x02, 0x13, 0xC4, 0x76
};

/* locoroco, kazue, and maybe others demos keys */
u8 demo_keys0[0x90+0x14] = 
{
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
	0x00, 0x00, 0x00, 0x00,
	0x82, 0x4C, 0xA5, 0x18, 0xD3, 0xC8, 0x6E, 0xEA, 
	0x17, 0x41, 0x04, 0xDC, 0xEA, 0xC5, 0x01, 0xFC, 
	0x97, 0xB1, 0x94, 0x54, 0x71, 0x19, 0x22, 0xEE, 
	0xE0, 0x2D, 0xE9, 0x83, 0x3D, 0x64, 0x30, 0xE6, 
	0x42, 0x5C, 0x30, 0x5F, 0xEB, 0x41, 0xA0, 0xE0, 
	0x62, 0xC6, 0x63, 0xEE, 0x5D, 0xA5, 0x0D, 0x1E, 
	0xC2, 0x10, 0x14, 0x49, 0x06, 0xC6, 0x93, 0x84, 
	0x71, 0xA5, 0x42, 0x63, 0x13, 0xF0, 0xB6, 0xD5, 
	0x43, 0x51, 0x9E, 0xFA, 0x91, 0x0A, 0x7C, 0xE1, 
	0x58, 0x1B, 0x95, 0x25, 0x40, 0x11, 0xF1, 0x8D, 
	0xB1, 0x01, 0x8D, 0x04, 0x09, 0x54, 0x5C, 0x54, 
	0xF5, 0x53, 0x08, 0xB0, 0x53, 0x85, 0xB4, 0xCE, 
	0x0B, 0xF5, 0xC3, 0xFB, 0xC6, 0x55, 0x24, 0x0B, 
	0xF2, 0xC6, 0x2C, 0xE4, 0x0C, 0xF0, 0x05, 0x3C, 
	0xD7, 0x6C, 0x39, 0xD5, 0x87, 0x22, 0x09, 0xF7, 
	0x3D, 0xC5, 0xA2, 0xFD, 0x55, 0x92, 0x3F, 0xB1, 
	0xF6, 0xFE, 0xC8, 0x18, 0x1D, 0x6B, 0x04, 0x52, 
	0x5F, 0x8C, 0xE8, 0xE7, 0x26, 0x5A, 0x6E, 0x5A
};

typedef struct
{
    u32 tag; // 4 byte value at offset 0xD0 in the PRX file
    u8* key; // "step1_result" use for XOR step
    u8 code;
    u8 codeExtra;
} TAG_INFO;

static const TAG_INFO g_tagInfo[] =
{
    // 1.x PRXs
    { 0x00000000, (u8*)g_key0, 0x42 },
    { 0x02000000, (u8*)g_key2, 0x45 },
    { 0x03000000, (u8*)g_key3, 0x46 },

    // 2.0 PRXs
    { 0x4467415d, (u8*)g_key44, 0x59, 0x59 },
    { 0x207bbf2f, (u8*)g_key20, 0x5A, 0x5A },
    { 0x3ace4dce, (u8*)g_key3A, 0x5B, 0x5B },

	 // updaters
    { 0x0b000000, updaters_keys, 0x4E },
	
	// locoroco, kazue, demos	
	{ 0x0c000000, demo_keys0, 0x4F },
};

static TAG_INFO const* GetTagInfo(u32 tagFind)
{
    int iTag;
    for (iTag = 0; iTag < sizeof(g_tagInfo)/sizeof(TAG_INFO); iTag++)
        if (g_tagInfo[iTag].tag == tagFind)
            return &g_tagInfo[iTag];
    return NULL; // not found
}

static void ExtraV2Mangle(u8* buffer1, u8 codeExtra)
{
    static u8 g_dataTmp[20+0xA0] __attribute__((aligned(0x40)));
    u8* buffer2 = g_dataTmp; // aligned

    memcpy(buffer2+20, buffer1, 0xA0);
    u32* pl2 = (u32*)buffer2;
    pl2[0] = 5;
    pl2[1] = pl2[2] = 0;
    pl2[3] = codeExtra;
    pl2[4] = 0xA0;

    int ret = sceUtilsBufferCopyWithRange(buffer2, 20+0xA0, buffer2, 20+0xA0, 7);
    if (ret != 0)
        Kprintf("extra de-mangle returns %d\n", ret);
    // copy result back
    memcpy(buffer1, buffer2, 0xA0);
}

static int Scramble(u32 *buf, u32 size, u32 code)
{
	buf[0] = 5;
	buf[1] = buf[2] = 0;
	buf[3] = code;
	buf[4] = size;

	if (sceUtilsBufferCopyWithRange(buf, size+0x14, buf, size+0x14, 7) < 0)
	{
		return -1;
	}

	return 0;
}

static int DecryptPRX1(const u8* pbIn, u8* pbOut, int cbTotal, u32 tag)
{
	int i, retsize;
	u8 bD0[0x80], b80[0x50], b00[0x80], bB0[0x20];
	
	TAG_INFO const* pti = GetTagInfo(tag);
    if (pti == NULL)
        return -1;

	retsize = *(u32*)&pbIn[0xB0];

	for (i = 0; i < 0x14; i++)
	{
		if (pti->key[i] != 0)
			break;
	}

	if (i == 0x14)
	{
		Scramble((u32 *)pti->key, 0x90, pti->code);
	}

    // build conversion into pbOut

	if (pbIn != pbOut)
		memcpy(pbOut, pbIn, cbTotal);

	memcpy(bD0, pbIn+0xD0, 0x80);
	memcpy(b80, pbIn+0x80, 0x50);
	memcpy(b00, pbIn+0x00, 0x80);
	memcpy(bB0, pbIn+0xB0, 0x20);
    
	memset(pbOut, 0, 0x150);
    memset(pbOut, 0x55, 0x40); // first $40 bytes ignored

    // step3 demangle in place
    u32* pl = (u32*)(pbOut+0x2C);
    pl[0] = 5; // number of ulongs in the header
    pl[1] = pl[2] = 0;
    pl[3] = pti->code; // initial seed for PRX
    pl[4] = 0x70;   // size

    // redo part of the SIG check (step2)
    u8 buffer1[0x150];
    memcpy(buffer1+0x00, bD0, 0x80);
    memcpy(buffer1+0x80, b80, 0x50);
    memcpy(buffer1+0xD0, b00, 0x80);
    if (pti->codeExtra != 0)
        ExtraV2Mangle(buffer1+0x10, pti->codeExtra);
    memcpy(pbOut+0x40 /* 0x2C+20 */, buffer1+0x40, 0x40);

    int ret;
    int iXOR;
    for (iXOR = 0; iXOR < 0x70; iXOR++)
        pbOut[0x40+iXOR] = pbOut[0x40+iXOR] ^ pti->key[0x14+iXOR];

    ret = sceUtilsBufferCopyWithRange(pbOut+0x2C, 20+0x70, pbOut+0x2C, 20+0x70, 7);
    if (ret != 0)
    {
        Kprintf("mangle#7 returned $%x\n", ret);
        return -1;
    }

    for (iXOR = 0x6F; iXOR >= 0; iXOR--)
        pbOut[0x40+iXOR] = pbOut[0x2C+iXOR] ^ pti->key[0x20+iXOR];

    memset(pbOut+0x80, 0, 0x30); // $40 bytes kept, clean up
    pbOut[0xA0] = 1;
    // copy unscrambled parts from header
    memcpy(pbOut+0xB0, bB0, 0x20); // file size + lots of zeros
    memcpy(pbOut+0xD0, b00, 0x80); // ~PSP header

    // step4: do the actual decryption of code block
    //  point 0x40 bytes into the buffer to key info
    ret = sceUtilsBufferCopyWithRange(pbOut, cbTotal, pbOut+0x40, cbTotal-0x40, 0x1);
    if (ret != 0)
    {
        Kprintf("mangle#1 returned $%x\n", ret);
        return -1;
    }

    // return cbTotal - 0x150; // rounded up size
	return retsize; 
}

////////// Decryption 2 //////////

/* kernel modules 2.60-2.71 */
u8 keys260_0[0x10] =
{
	0xC3, 0x24, 0x89, 0xD3, 0x80, 0x87, 0xB2, 0x4E,
	0x4C, 0xD7, 0x49, 0xE4, 0x9D, 0x1D, 0x34, 0xD1

};

/* user modules 2.60-2.71 */
u8 keys260_1[0x10] =
{
	0xF3, 0xAC, 0x6E, 0x7C, 0x04, 0x0A, 0x23, 0xE7,
	0x0D, 0x33, 0xD8, 0x24, 0x73, 0x39, 0x2B, 0x4A
};

/* vshmain 2.60-2.71 */
u8 keys260_2[0x10] =
{
	0x72, 0xB4, 0x39, 0xFF, 0x34, 0x9B, 0xAE, 0x82,
	0x30, 0x34, 0x4A, 0x1D, 0xA2, 0xD8, 0xB4, 0x3C
};

/* kernel modules 2.80 */
u8 keys280_0[0x10] =
{
	0xCA, 0xFB, 0xBF, 0xC7, 0x50, 0xEA, 0xB4, 0x40,
	0x8E, 0x44, 0x5C, 0x63, 0x53, 0xCE, 0x80, 0xB1
};

/* user modules 2.80 */
u8 keys280_1[0x10] =
{
	0x40, 0x9B, 0xC6, 0x9B, 0xA9, 0xFB, 0x84, 0x7F,
	0x72, 0x21, 0xD2, 0x36, 0x96, 0x55, 0x09, 0x74
};

/* vshmain executable 2.80 */
u8 keys280_2[0x10] =
{
	0x03, 0xA7, 0xCC, 0x4A, 0x5B, 0x91, 0xC2, 0x07,
	0xFF, 0xFC, 0x26, 0x25, 0x1E, 0x42, 0x4B, 0xB5
};

/* kernel modules 3.00 */
u8 keys300_0[0x10] =
{
	0x9F, 0x67, 0x1A, 0x7A, 0x22, 0xF3, 0x59, 0x0B,
    0xAA, 0x6D, 0xA4, 0xC6, 0x8B, 0xD0, 0x03, 0x77

};

/* user modules 3.00 */
u8 keys300_1[0x10] =
{
	0x15, 0x07, 0x63, 0x26, 0xDB, 0xE2, 0x69, 0x34,
    0x56, 0x08, 0x2A, 0x93, 0x4E, 0x4B, 0x8A, 0xB2

};

/* vshmain 3.00 */
u8 keys300_2[0x10] =
{
	0x56, 0x3B, 0x69, 0xF7, 0x29, 0x88, 0x2F, 0x4C,
    0xDB, 0xD5, 0xDE, 0x80, 0xC6, 0x5C, 0xC8, 0x73

};

/* kernel modules 3.00 */
u8 keys303_0[0x10] =
{
	0x7b, 0xa1, 0xe2, 0x5a, 0x91, 0xb9, 0xd3, 0x13,
	0x77, 0x65, 0x4a, 0xb7, 0xc2, 0x8a, 0x10, 0xaf
};

/* kernel modules 3.10 */
u8 keys310_0[0x10] =
{
	0xa2, 0x41, 0xe8, 0x39, 0x66, 0x5b, 0xfa, 0xbb,
	0x1b, 0x2d, 0x6e, 0x0e, 0x33, 0xe5, 0xd7, 0x3f
};

/* user modules 3.10 */
u8 keys310_1[0x10] =
{
	0xA4, 0x60, 0x8F, 0xAB, 0xAB, 0xDE, 0xA5, 0x65,
	0x5D, 0x43, 0x3A, 0xD1, 0x5E, 0xC3, 0xFF, 0xEA
};

/* vshmain 3.10 */
u8 keys310_2[0x10] =
{
	0xE7, 0x5C, 0x85, 0x7A, 0x59, 0xB4, 0xE3, 0x1D,
	0xD0, 0x9E, 0xCE, 0xC2, 0xD6, 0xD4, 0xBD, 0x2B
};

/* reboot.bin 3.10 */
u8 keys310_3[0x10] =
{
    0x2E, 0x00, 0xF6, 0xF7, 0x52, 0xCF, 0x95, 0x5A,
    0xA1, 0x26, 0xB4, 0x84, 0x9B, 0x58, 0x76, 0x2F
};

/* kernel modules 3.30 */ 
u8 keys330_0[0x10] = 
{ 
	0x3B, 0x9B, 0x1A, 0x56, 0x21, 0x80, 0x14, 0xED,
	0x8E, 0x8B, 0x08, 0x42, 0xFA, 0x2C, 0xDC, 0x3A
};

/* user modules 3.30 */ 
u8 keys330_1[0x10] = 
{ 
    0xE8, 0xBE, 0x2F, 0x06, 0xB1, 0x05, 0x2A, 0xB9, 
    0x18, 0x18, 0x03, 0xE3, 0xEB, 0x64, 0x7D, 0x26 
}; 

/* vshmain 3.30 */ 
u8 keys330_2[0x10] = 
{ 
    0xAB, 0x82, 0x25, 0xD7, 0x43, 0x6F, 0x6C, 0xC1, 
    0x95, 0xC5, 0xF7, 0xF0, 0x63, 0x73, 0x3F, 0xE7 
}; 

/* reboot.bin 3.30 */ 
u8 keys330_3[0x10] = 
{ 
    0xA8, 0xB1, 0x47, 0x77, 0xDC, 0x49, 0x6A, 0x6F, 
    0x38, 0x4C, 0x4D, 0x96, 0xBD, 0x49, 0xEC, 0x9B 
}; 

/* stdio.prx 3.30 */
u8 keys330_4[0x10] =
{
	0xEC, 0x3B, 0xD2, 0xC0, 0xFA, 0xC1, 0xEE, 0xB9,
	0x9A, 0xBC, 0xFF, 0xA3, 0x89, 0xF2, 0x60, 0x1F
};

/* 3.60 common kernel modules */
u8 keys360_0[16] = 
{
	0x3C, 0x2B, 0x51, 0xD4, 0x2D, 0x85, 0x47, 0xDA, 
	0x2D, 0xCA, 0x18, 0xDF, 0xFE, 0x54, 0x09, 0xED
};

/* 3.60 specific slim kernel modules */
u8 keys360_1[16] = 
{
	0x31, 0x1F, 0x98, 0xD5, 0x7B, 0x58, 0x95, 0x45, 
	0x32, 0xAB, 0x3A, 0xE3, 0x89, 0x32, 0x4B, 0x34
};

/* 3.70 common and fat kernel modules */
u8 keys370_0[0x10] = 
{
	0x26, 0x38, 0x0A, 0xAC, 0xA5, 0xD8, 0x74, 0xD1, 
	0x32, 0xB7, 0x2A, 0xBF, 0x79, 0x9E, 0x6D, 0xDB
};

/* 3.70 slim specific kernel modules */
u8 keys370_1[0x10] = 
{
	0x53, 0xE7, 0xAB, 0xB9, 0xC6, 0x4A, 0x4B, 0x77, 
	0x92, 0x17, 0xB5, 0x74, 0x0A, 0xDA, 0xA9, 0xEA
};

/* some 3.70 slim user modules */
u8 keys370_2[16] = 
{
	0x71, 0x10, 0xF0, 0xA4, 0x16, 0x14, 0xD5, 0x93, 
	0x12, 0xFF, 0x74, 0x96, 0xDF, 0x1F, 0xDA, 0x89
};

/* 3.90 kernel */
u8 keys390_0[16] = 
{
	0x45, 0xEF, 0x5C, 0x5D, 0xED, 0x81, 0x99, 0x84, 
	0x12, 0x94, 0x8F, 0xAB, 0xE8, 0x05, 0x6D, 0x7D
};

/* 3.90 slim */
u8 keys390_1[16] = 
{
	0x70, 0x1B, 0x08, 0x25, 0x22, 0xA1, 0x4D, 0x3B, 
	0x69, 0x21, 0xF9, 0x71, 0x0A, 0xA8, 0x41, 0xA9
};

/* 5.00 kernel */
u8 keys500_0[16] = 
{
	0xEB, 0x1B, 0x53, 0x0B, 0x62, 0x49, 0x32, 0x58, 
	0x1F, 0x83, 0x0A, 0xF4, 0x99, 0x3D, 0x75, 0xD0
};

/* 5.00 kernel 2000 specific */
u8 keys500_1[16] = 
{
	0xBA, 0xE2, 0xA3, 0x12, 0x07, 0xFF, 0x04, 0x1B, 
	0x64, 0xA5, 0x11, 0x85, 0xF7, 0x2F, 0x99, 0x5B
};

/* 5.00 kernel 3000 specific */
u8 keys500_2[16] = 
{
	0x2C, 0x8E, 0xAF, 0x1D, 0xFF, 0x79, 0x73, 0x1A, 
 	0xAD, 0x96, 0xAB, 0x09, 0xEA, 0x35, 0x59, 0x8B
};

u8 keys500_c[16] = 
{
	0xA3, 0x5D, 0x51, 0xE6, 0x56, 0xC8, 0x01, 0xCA,
	0xE3, 0x77, 0xBF, 0xCD, 0xFF, 0x24, 0xDA, 0x4D
};

u8 keys505_a[16] =
{
	0x7B, 0x94, 0x72, 0x27, 0x4C, 0xCC, 0x54, 0x3B,
	0xAE, 0xDF, 0x46, 0x37, 0xAC, 0x01, 0x4D, 0x87
};

u8 keys505_0[16] =
{
	0x2E, 0x8E, 0x97, 0xA2, 0x85, 0x42, 0x70, 0x73,
	0x18, 0xDA, 0xA0, 0x8A, 0xF8, 0x62, 0xA2, 0xB0
};

u8 keys505_1[16] =
{
	0x58, 0x2A, 0x4C, 0x69, 0x19, 0x7B, 0x83, 0x3D,
	0xD2, 0x61, 0x61, 0xFE, 0x14, 0xEE, 0xAA, 0x11
};

/* for psp 2000 file table and ipl pre-decryption */
u8 keys02G_E[0x10] = 
{
	0x9D, 0x09, 0xFD, 0x20, 0xF3, 0x8F, 0x10, 0x69, 
	0x0D, 0xB2, 0x6F, 0x00, 0xCC, 0xC5, 0x51, 0x2E
};

/* for psp 3000 file table and ipl pre-decryption */
u8 keys03G_E[0x10] = 
{
	0x4F, 0x44, 0x5C, 0x62, 0xB3, 0x53, 0xC4, 0x30, 
	0xFC, 0x3A, 0xA4, 0x5B, 0xEC, 0xFE, 0x51, 0xEA
};

/* for psp go file table and ipl pre-decryption */
u8 keys05G_E[0x10] = 
{
	0x5D, 0xAA, 0x72, 0xF2, 0x26, 0x60, 0x4D, 0x1C,
	0xE7, 0x2D, 0xC8, 0xA3, 0x2F, 0x79, 0xC5, 0x54
};

/* 5.70 PSPgo kernel*/
u8 keys570_5k[0x10] =
{
	0x6D, 0x72, 0xA4, 0xBA, 0x7F, 0xBF, 0xD1, 0xF1,
	0xA9, 0xF3, 0xBB, 0x07, 0x1B, 0xC0, 0xB3, 0x66
};

/* 6.00-6.20 kernel and phat */
u8 keys620_0[0x10] = 
{
	0xD6, 0xBD, 0xCE, 0x1E, 0x12, 0xAF, 0x9A, 0xE6,
	0x69, 0x30, 0xDE, 0xDA, 0x88, 0xB8, 0xFF, 0xFB
};

/* 6.00-6.20 slim kernel */
u8 keys620_1[0x10] = 
{
	0x1D, 0x13, 0xE9, 0x50, 0x04, 0x73, 0x3D, 0xD2,
	0xE1, 0xDA, 0xB9, 0xC1, 0xE6, 0x7B, 0x25, 0xA7
};

u8 keys620_a[0x10] = 
{
	0xAC, 0x34, 0xBA, 0xB1, 0x97, 0x8D, 0xAE, 0x6F,
	0xBA, 0xE8, 0xB1, 0xD6, 0xDF, 0xDF, 0xF1, 0xA2
};

u8 keys620_e[0x10] = 
{
	0xB1, 0xB3, 0x7F, 0x76, 0xC3, 0xFB, 0x88, 0xE6,
	0xF8, 0x60, 0xD3, 0x35, 0x3C, 0xA3, 0x4E, 0xF3
};

/* PSPgo internal */
u8 keys620_5[0x10] =
{
	0xF1, 0xBC, 0x17, 0x07, 0xAE, 0xB7, 0xC8, 0x30,
	0xD8, 0x34, 0x9D, 0x40, 0x6A, 0x8E, 0xDF, 0x4E
};

/* 6.XX PSPgo kernel */
u8 keys620_5k[0x10] =
{
	0x41, 0x8A, 0x35, 0x4F, 0x69, 0x3A, 0xDF, 0x04,
	0xFD, 0x39, 0x46, 0xA2, 0x5C, 0x2D, 0xF2, 0x21
};

u8 keys620_5v[0x10] =
{
	0xF2, 0x8F, 0x75, 0xA7, 0x31, 0x91, 0xCE, 0x9E,
	0x75, 0xBD, 0x27, 0x26, 0xB4, 0xB4, 0x0C, 0x32
};

/* 6.30 phat kernel */ 
u8 keys630_k1[0x10] = {
	0x36, 0xB0, 0xDC, 0xFC, 0x59, 0x2A, 0x95, 0x1D, 
	0x80, 0x2D, 0x80, 0x3F, 0xCD, 0x30, 0xA0, 0x1B,
};

/* 6.30 phat kernel-2 */
u8 keys630_k2[0x10] = {
	0xd4, 0x35, 0x18, 0x02, 0x29, 0x68, 0xfb, 0xa0, 
	0x6a, 0xa9, 0xa5, 0xed, 0x78, 0xfd, 0x2e, 0x9d
};

u8 key_380280f0[0x10] =
{
	0x97, 0x09, 0x12, 0xD3, 0xDB, 0x02, 0xBD, 0xD8, 
	0xE7, 0x74, 0x51, 0xFE, 0xF0, 0xEA, 0x6C, 0x5C,
};

/* 6.30 slim kernel */
u8 keys630_k3[0x10] =
{
	0x23, 0x8D, 0x3D, 0xAE, 0x41, 0x50, 0xA0, 0xFA,
	0xF3, 0x2F, 0x32, 0xCE, 0xC7, 0x27, 0xCD, 0x50,
};

/* 6.30 slim pops */
u8 keys630_k4[0x10] = 
{
	0xAA, 0xA1, 0xB5, 0x7C, 0x93, 0x5A, 0x95, 0xBD,
	0xEF, 0x69, 0x16, 0xFC, 0x2B, 0x92, 0x31, 0xDD
};

u8 keys630_k5[0x10] = { 0x87,0x37,0x21,0xCC,0x65,0xAE,0xAA,0x5F,0x40,0xF6,0x6F,0x2A,0x86,0xC7,0xA1,0xC8 };
u8 keys630_k6[0x10] = { 0x8D,0xDB,0xDC,0x5C,0xF2,0x70,0x2B,0x40,0xB2,0x3D,0x00,0x09,0x61,0x7C,0x10,0x60 };
u8 keys630_k7[0x10] = { 0x77,0x1C,0x06,0x5F,0x53,0xEC,0x3F,0xFC,0x22,0xCE,0x5A,0x27,0xFF,0x78,0xA8,0x48 };
u8 keys630_k8[0x10] = { 0x81,0xD1,0x12,0x89,0x35,0xC8,0xEA,0x8B,0xE0,0x02,0x2D,0x2D,0x6A,0x18,0x67,0xB8 };

u8 keys636_k1[0x10] = { 0x07,0xE3,0x08,0x64,0x7F,0x60,0xA3,0x36,0x6A,0x76,0x21,0x44,0xC9,0xD7,0x06,0x83 };
u8 keys636_k2[0x10] = { 0x91,0xF2,0x02,0x9E,0x63,0x32,0x30,0xA9,0x1D,0xDA,0x0B,0xA8,0xB7,0x41,0xA3,0xCC };

u8 keys600_1[0x10] = { 0xE3,0x52,0x39,0x97,0x3B,0x84,0x41,0x1C,0xC3,0x23,0xF1,0xB8,0xA9,0x09,0x4B,0xF0 };
u8 keys600_2[0x10] = { 0xE1,0x45,0x93,0x2C,0x53,0xE2,0xAB,0x06,0x6F,0xB6,0x8F,0x0B,0x66,0x91,0xE7,0x1E };

u8 key_380283F0[0x10] = { 0x34,0x20,0x0C,0x8E,0xA1,0x86,0x79,0x84,0xAF,0x13,0xAE,0x34,0x77,0x6F,0xEA,0x89 };

u8 keys620_upd[0x10] = { 0xE2,0x03,0x8A,0x8C,0x33,0x81,0x4B,0x56,0x52,0x4E,0x1D,0xE5,0xA4,0x24,0x04,0xFF };

typedef struct
{
    u32 tag; // 4 byte value at offset 0xD0 in the PRX file
    u8  *key; // 16 bytes keys
    u8 code; // code for scramble
	u8 type;
} TAG_INFO2;

static TAG_INFO2 g_tagInfo2[] =
{
	{ 0xA6E328F0, keys620_upd, 0x5F }, // 5.70, 6.10, 6.20 PSPgo Updater
	
	{ 0x4C948AF0, keys636_k1, 0x43, 3}, // 6.36
	{ 0x4C948BF0, keys636_k2, 0x43, 3}, // 6.36 02g

	{ 0x457b80f0, keys630_k2, 0x5B, 3}, // 6.30
	{ 0x457B81F0, keys630_k4, 0x5B, 3}, // 6.30 02g
	{ 0x457B82F0, keys630_k5, 0x5B, 3}, // 6.30 03g 04g 07g 09g
	{ 0x457B83F0, keys630_k7, 0x5B, 3}, // 6.30 05g
	{ 0x4C9484F0, keys630_k1, 0x43, 3}, // 6.30
	{ 0x4C9485F0, keys630_k3, 0x43, 3}, // 6.30 02g
	{ 0x4C9486F0, keys630_k6, 0x43, 3}, // 6.30 03g 04g 07g 09g
	{ 0x4C9487F0, keys630_k8, 0x43, 3}, // 6.30 05g

	{ 0x380283F0, key_380283F0, 0x5A, 3}, // 6.30 vshmain 05g
	{ 0x380280f0, key_380280f0, 0x5A, 3}, // 6.30 vshmain
	
	{ 0x457B28F0, keys620_e, 0x5B },
	{ 0x457B0CF0, keys620_a, 0x5B },
	{ 0x380228F0, keys620_5v, 0x5A }, // PSPgo 6.XX vshmain
	{ 0x4C942AF0, keys620_5k, 0x43 }, // PSPgo 6.XX
	{ 0x4C9428F0, keys620_5 , 0x43 }, // PSPgo
	{ 0x4C9422F0, keys600_2, 0x43 }, // 6.00 03g 04g
	{ 0x4C941EF0, keys600_1, 0x43 },
	{ 0x4C941DF0, keys620_1, 0x43 },
	{ 0x4C941CF0, keys620_0, 0x43 },
	{ 0x4C9429F0, keys570_5k, 0x43 }, // PSPgo 5.70
	{ 0x4C9419F0, keys505_1, 0x43 },
	{ 0x4C9418F0, keys505_0, 0x43 },
	{ 0x457B0BF0, keys505_a, 0x5B },
	{ 0x457B1EF0, keys500_c, 0x5B },
	{ 0x4C941FF0, keys500_2, 0x43 },
	{ 0x4C9417F0, keys500_1, 0x43 },
	{ 0x4C9416F0, keys500_0, 0x43 },
	{ 0x4C9415F0, keys390_1, 0x43 },
	{ 0x4C9414F0, keys390_0, 0x43 },
	{ 0x4C9412F0, keys370_0, 0x43 },
	{ 0x4C9413F0, keys370_1, 0x43 },
	{ 0x457B10F0, keys370_2, 0x5B },
	
	{ 0xD82310F0, keys02G_E, 0x51 }, 
	{ 0xD8231EF0, keys03G_E, 0x51 },
	{ 0xD82328F0, keys05G_E, 0x51 },

	{ 0x4C940DF0, keys360_0, 0x43 },
	{ 0x4C9410F0, keys360_1, 0x43 },
	
	{ 0x4C940BF0, keys330_0, 0x43 }, 
	{ 0x457B0AF0, keys330_1, 0x5B }, 
	{ 0x38020AF0, keys330_2, 0x5A }, 
	{ 0x4C940AF0, keys330_3, 0x43 }, 
	{ 0x4C940CF0, keys330_4, 0x43 }, 

	{ 0xcfef09f0, keys310_0, 0x62 },
	{ 0x457b08f0, keys310_1, 0x5B },
	{ 0x380208F0, keys310_2, 0x5A },
	{ 0xcfef08f0, keys310_3, 0x62 },

	{ 0xCFEF07F0, keys303_0, 0x62 },
	{ 0xCFEF06F0, keys300_0, 0x62 },
	{ 0x457B06F0, keys300_1, 0x5B },
	{ 0x380206F0, keys300_2, 0x5A },
	
	{ 0xCFEF05F0, keys280_0, 0x62 },
	{ 0x457B05F0, keys280_1, 0x5B },
	{ 0x380205F0, keys280_2, 0x5A },
	{ 0x16D59E03, keys260_0, 0x62 },
	{ 0x76202403, keys260_1, 0x5B },
	{ 0x0F037303, keys260_2, 0x5A }
};


static TAG_INFO2 *GetTagInfo2(u32 tagFind)
{
    int iTag;

    for (iTag = 0; iTag < sizeof(g_tagInfo2) / sizeof(TAG_INFO2); iTag++)
	{
        if (g_tagInfo2[iTag].tag == tagFind)
		{
            return &g_tagInfo2[iTag];
		}
	}

	return NULL; // not found
}

static int DecryptPRX2(const u8 *inbuf, u8 *outbuf, u32 size, u32 tag)
{
	TAG_INFO2 * pti = GetTagInfo2(tag);

	if (!pti)
	{
		//Kprintf("Unknown tag 0x%08X.\n", tag);
		return -1;
	}	

	int retsize = *(int *)&inbuf[0xB0];
	u8	tmp1[0x150], tmp2[0x90+0x14], tmp3[0x60+0x14], tmp4[0x20];

	memset(tmp1, 0, 0x150);
	memset(tmp2, 0, 0x90+0x14);
	memset(tmp3, 0, 0x60+0x14);
	memset(tmp4, 0, 0x20);

	if (inbuf != outbuf)
		memcpy(outbuf, inbuf, size);

	if (size < 0x160)
	{
		Kprintf("Buffer not big enough.\n");
		return -2;
	}

	if (((u32)outbuf & 0x3F))
	{
		Kprintf("Buffer not aligned to 64 bytes.\n");
		return -3;
	}

	if ((size - 0x150) < retsize)
	{
		Kprintf("No enough data.\n");
		return -4;
	}

	memcpy(tmp1, outbuf, 0x150);

	int i, j;
	u8 *p = tmp2+0x14;

	for (i = 0; i < 9; i++)
	{
		for (j = 0; j < 0x10; j++)
		{
			p[(i << 4) + j] = pti->key[j]; 	
					
		}

		p[(i << 4)] = i;
	}

	if (Scramble((u32 *)tmp2, 0x90, pti->code) < 0)
	{
		Kprintf("Error in Scramble #1.\n");
		return -5;
	}

	memcpy(outbuf, tmp1+0xD0, 0x5C);
	memcpy(outbuf+0x5C, tmp1+0x140, 0x10);
	memcpy(outbuf+0x6C, tmp1+0x12C, 0x14);
	memcpy(outbuf+0x80, tmp1+0x080, 0x30);
	memcpy(outbuf+0xB0, tmp1+0x0C0, 0x10);
	memcpy(outbuf+0xC0, tmp1+0x0B0, 0x10);
	memcpy(outbuf+0xD0, tmp1+0x000, 0x80);

	memcpy(tmp3+0x14, outbuf+0x5C, 0x60);	

	if (Scramble((u32 *)tmp3, 0x60, pti->code) < 0)
	{
		Kprintf("Error in Scramble #2.\n");
		return -6;
	}

	memcpy(outbuf+0x5C, tmp3, 0x60);
	memcpy(tmp3, outbuf+0x6C, 0x14);
	memcpy(outbuf+0x70, outbuf+0x5C, 0x10);
	
	if(pti->type == 3)
	{
		memcpy(tmp4, outbuf+0x3C, 0x20);
		memcpy(outbuf+0x50, tmp4, 0x20);
		memset(outbuf+0x18, 0, 0x38);
	}else
		memset(outbuf+0x18, 0, 0x58);
	
	memcpy(outbuf+0x04, outbuf, 0x04);
	*((u32 *)outbuf) = 0x014C;
	memcpy(outbuf+0x08, tmp2, 0x10);
	
	/* sha-1 */

	if (sceUtilsBufferCopyWithRange(outbuf, 3000000, outbuf, 3000000, 0x0B) != 0)
	{
		Kprintf("Error in sceUtilsBufferCopyWithRange 0xB.\n");
		return -7;
	}

	if (memcmp(outbuf, tmp3, 0x14) != 0)
	{
		Kprintf("SHA-1 is incorrect.\n");
        return -8;
	}
	
	int iXOR;

	for (iXOR = 0; iXOR < 0x40; iXOR++)
	{
		tmp3[iXOR+0x14] = outbuf[iXOR+0x80] ^ tmp2[iXOR+0x10];
	}

	if (Scramble((u32 *)tmp3, 0x40, pti->code) != 0)
	{
		Kprintf("Error in Scramble #2.\n");
		return -9;
	}
	
	for (iXOR = 0x3F; iXOR >= 0; iXOR--)
	{
		outbuf[iXOR+0x40] = tmp3[iXOR] ^ tmp2[iXOR+0x50]; // uns 8
	}

	if (pti->type == 3)
	{
		memcpy(outbuf+0x80, tmp4, 0x20);
		memset(outbuf+0xA0, 0, 0x10);
		*(u32*)&outbuf[0xA4] = 1;
		*(u32*)&outbuf[0xA0] = 1;
	} else
	{
		memset(outbuf+0x80, 0, 0x30);
		*(u32*)&outbuf[0xA0] = 1;
	}

	memcpy(outbuf+0xB0, outbuf+0xC0, 0x10);
	memset(outbuf+0xC0, 0, 0x10);
	memcpy(outbuf+0xD0, outbuf+0xD0, 0x80);

	// The real decryption
	if (sceUtilsBufferCopyWithRange(outbuf, size, outbuf+0x40, size-0x40, 0x1) != 0)
	{
		Kprintf("Error in sceUtilsBufferCopyWithRange 0x1.\n");
		return -1;
	}

	if (retsize < 0x150)
	{
		// Fill with 0
		memset(outbuf+retsize, 0, 0x150-retsize);		
	}

	return retsize;
}

int pspDecryptPRX(u8 *data, u32 size, u32 *out_size)
{
	int retsize = DecryptPRX1(data, data, size, *(u32 *)&data[0xD0]);

	if (retsize <= 0)
	{
		retsize = DecryptPRX2(data, data, size, *(u32 *)&data[0xD0]);
	}
	
	if (retsize <= 0)
	{
		return -1;
	}

	out_size[0] = retsize;
	return 0;
}


================================================
FILE: src/downgrade_ctrl/utils.c
================================================
/*
	Downgrade Control -> utils.c -> Responsible for providing common utilities interfacing the kernel
	by Davee
	
	30/12/2010
*/

#include <pspkernel.h>
#include <pspsysmem_kernel.h>

#include <stdio.h>
#include <string.h>
#include <systemctrl.h>

#include "utils.h"

void ClearCaches(void)
{
	sceKernelIcacheClearAll();
	sceKernelDcacheWritebackAll();
}

u32 FindFunc(const char *modname, const char *lib, u32 nid)
{
	int i = 0, u;
	
	/* try and find the module by name */
	SceModule *mod = sceKernelFindModuleByName(modname);
	
	/* if fail */
	if (!mod)
	{
		/* fail */
		return 0;
	}
	
	/* copy over the structure data */
	u32 entry_size = mod->ent_size;
	u32 entry_start = (u32)mod->ent_top;
	
	/* loop until end of entry table */
	while (i < entry_size)
	{
		/* cast structure to memory */
		SceLibraryEntryTable *entry = (SceLibraryEntryTable *)(entry_start + i);
		
		/* if there is a libname, compare it to the lib else if there is no lib and there is no libname */
		if ((entry->libname && (strcmp(entry->libname, lib) == 0)) || (lib == NULL && entry->libname == NULL))
		{
			/* copy the table pointer and get the total number of entries */
			u32 *table = entry->entrytable;
			int total = entry->stubcount + entry->vstubcount;
			
			/* if there is some entries continue */
			if (total > 0)
			{ 
				/* loop through the entries */
				for (u = 0; u < total; u++)
				{
					/* if the nid matches */
					if (table[u] == nid)
					{
						/* return the pointer */
						return table[u + total];
					}
				} 
			} 	
		}
		
		/* increment the counter */
		i += (entry->len << 2);
	}
	
	/* could not find function */
	return 0;
}

void PatchSyscall(u32 addr, void *newaddr)
{
	u32 *vectors, i;
	
	/* get the vectors address from the co-processor */
	__asm__ volatile ("cfc0 %0, $12\n" "nop\n" : "=r" (vectors));
	
	/* loop through them */
	for (i = 0; i < 0x1000; i++)
	{
		/* if this is the address */
		if (vectors[i + 4] == addr)
		{
			/* then replace it :D */
			vectors[i + 4] = (u32)newaddr;
		}
	}
}


================================================
FILE: src/downgrade_ctrl/utils.h
================================================
/*
	Downgrade Control -> utils.h -> Provide API documentation and definitions for utilities
	by Davee
	
	30/12/2010
*/
#ifndef __UTILS__H__
#define __UTILS__H__

#define MAKE_JUMP(a, f)					_sw(0x08000000 | (((u32)(f) >> 2)  & 0x03ffffff), a)
#define MAKE_CALL(a, f)					_sw(0x0C000000 | (((u32)(f) >> 2)  & 0x03ffffff), a)
#define REDIRECT_FUNCTION(a, f) 		{ u32 address = a; _sw(0x08000000 | (((u32)(f) >> 2)  & 0x03ffffff), address);  _sw(0, address+4); }

#define KERNEL_HIJACK_FUNCTION(a, f, ptr)	{ \
											static u32 patch_buffer[3]; \
											_sw(_lw(a + 0x00), (u32)patch_buffer + 0x00); \
											_sw(_lw(a + 0x04), (u32)patch_buffer + 0x08);\
											MAKE_JUMP((u32)patch_buffer + 0x04, a + 0x08); \
											REDIRECT_FUNCTION(a, f); \
											ptr = (void *)patch_buffer; \
										}
/**
	Clears both the instruction and data caches
*/
void ClearCaches(void);

/**
	Allows to modify the kernel address called when a specific syscall is initiated
	
	@param addr: the address of the kernel function syscall you want to control
	@param newaddr: the new address the syscall will call
*/
void PatchSyscall(u32 addr, void *newaddr);

/**
	Find an export within the system
	
	@param modname: the name of the module containing the export
	@param libname: the library the export belongs to
	@param nid: the nid of the export
	
	@return the address of export else 0 on error
*/
u32 FindFunc(const char *modname, const char *lib, u32 nid);

#endif /* __UTILS__H__ */


================================================
FILE: src/extra_stubs.S
================================================
	.set noreorder

#include "pspstub.s"

	STUB_START "sceNetInet",0x00090000,0x00010005
	STUB_FUNC  0x1BDF5D13,sceNetInetInetAton
	STUB_END
	
	STUB_START "sceUtility_private",0x40090000,0x00020005
	STUB_FUNC  0xE65F37C8,sceUtilityPowerRegisterCallback
	STUB_FUNC  0x9ABAFCC5,sceUtilityPowerunRegisterCallback
	STUB_END

	STUB_START	"sceNetIfhandle_lib",0x40090000,0x00010005
	STUB_FUNC	0xE80F00A4, sceNetMPulldown
	STUB_END
	
	STUB_START "UtilsForUser",0x40000011,0x00020005
	STUB_FUNC  0x920F104A,sceKernelIcacheInvalidateAll
	STUB_FUNC  0xB435DEC5,sceKernelDcacheWritebackInvalidateAll
	STUB_END

================================================
FILE: src/extras.S
================================================
	.set noreorder

.global getPowerAddress
.ent    getPowerAddress
getPowerAddress:
	addiu $sp, $sp, -8
	sw $ra, 0($sp)
	move $a1, $a0
	jal sceUtilityPowerRegisterCallback
	move $a0, $0
	move $v0, $v1
	lw $ra, 0($sp)
	jr $ra
	addiu $sp, $sp, 8
.end getPowerAddress

================================================
FILE: src/include/libinfinity.h
================================================
/*

Copyright (C) 2015, David "Davee" Morgan

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

*/

#ifndef LIBINFINITY_H
#define LIBINFINITY_H

#ifdef __cplusplus
extern "C" {
#endif // __cplusplus

/**
    @return The version of the persistent aspect of Infinity.
*/
unsigned int infGetVersion(void);

/**
    @return The version of the bootloader.
*/
unsigned int infGetCoreVersion(void);

/**
    @return non-zero if redirection is enabled else redirection is disabled and the logical IO operations can be performed.
*/
int infGetRedirectionStatus(void);

/**
    Set whether to enable or disable redirection.
    By default redirection is enabled and is required for infinity to operate. By disabling you enable the ability to format flash0 and write to the bootloader of infinity. Ensure to re-enable redirection if you intend to warm-reboot.
*/
void infSetRedirectionStatus(int enabled);

#ifdef __cplusplus
}
#endif // __cplusplus

#endif // LIBINFINITY_H


================================================
FILE: src/include/systemctrl.h
================================================
#ifndef __SCTRLLIBRARY_H__
#define __SCTRLLIBRARY_H__

#include <pspsdk.h>
#include <pspkernel.h>
#include <psploadexec_kernel.h>
#include <pspinit.h>

enum BootLoadFlags
{
	BOOTLOAD_VSH = 1,
	BOOTLOAD_GAME = 2,
	BOOTLOAD_UPDATER = 4,
	BOOTLOAD_POPS = 8,
	BOOTLOAD_UMDEMU = 64, /* for original NP9660 */
	BOOTLOAD_MLNAPP = 128,
};

/**
 * Restart the vsh.
 *
 * @param param - Pointer to a ::SceKernelLoadExecVSHParam structure, or NULL
 *
 * @returns < 0 on some errors.
 *
*/
int sctrlKernelExitVSH(struct SceKernelLoadExecVSHParam *param);

/**
 * Executes a new executable from a disc.
 * It is the function used by the firmware to execute the EBOOT.BIN from a disc.
 *
 * @param file - The file to execute.
 * @param param - Pointer to a ::SceKernelLoadExecVSHParam structure, or NULL.
 *
 * @returns < 0 on some errors. 
*/
int sctrlKernelLoadExecVSHDisc(const char *file, struct SceKernelLoadExecVSHParam *param);

/**
 * Executes a new executable from a disc.
 * It is the function used by the firmware to execute an updater from a disc.
 *
 * @param file - The file to execute.
 * @param param - Pointer to a ::SceKernelLoadExecVSHParam structure, or NULL.
 *
 * @returns < 0 on some errors. 
*/
int sctrlKernelLoadExecVSHDiscUpdater(const char *file, struct SceKernelLoadExecVSHParam *param);

/**
 * Executes a new executable from a memory stick.
 * It is the function used by the firmware to execute an updater from a memory stick.
 *
 * @param file - The file to execute.
 * @param param - Pointer to a ::SceKernelLoadExecVSHParam structure, or NULL.
 *
 * @returns < 0 on some errors. 
*/
int sctrlKernelLoadExecVSHMs1(const char *file, struct SceKernelLoadExecVSHParam *param);

/**
 * Executes a new executable from a memory stick.
 * It is the function used by the firmware to execute games (and homebrew :P) from a memory stick.
 *
 * @param file - The file to execute.
 * @param param - Pointer to a ::SceKernelLoadExecVSHParam structure, or NULL.
 *
 * @returns < 0 on some errors. 
*/
int sctrlKernelLoadExecVSHMs2(const char *file, struct SceKernelLoadExecVSHParam *param);
int sctrlKernelLoadExecVSHEf2(const char *file, struct SceKernelLoadExecVSHParam *param);

/**
 * Executes a new executable from a memory stick.
 * It is the function used by the firmware to execute ... ?
 *
 * @param file - The file to execute.
 * @param param - Pointer to a ::SceKernelLoadExecVSHParam structure, or NULL.
 *
 * @returns < 0 on some errors. 
*/
int sctrlKernelLoadExecVSHMs3(const char *file, struct SceKernelLoadExecVSHParam *param);

/**
 * Executes a new executable from a memory stick.
 * It is the function used by the firmware to execute psx games
 *
 * @param file - The file to execute.
 * @param param - Pointer to a ::SceKernelLoadExecVSHParam structure, or NULL.
 *
 * @returns < 0 on some errors. 
*/
int sctrlKernelLoadExecVSHMs4(const char *file, struct SceKernelLoadExecVSHParam *param);


/**
 * Executes a new executable with the specified apitype
 *
 * @param apitype - The apitype
 * @param file - The file to execute.
 * @param param - Pointer to a ::SceKernelLoadExecVSHParam structure, or NULL.
 *
 * @returns < 0 on some errors. 
*/
int sctrlKernelLoadExecVSHWithApitype(int apitype, const char *file, struct SceKernelLoadExecVSHParam *param);

/**
 * Sets the api type 
 *
 * @param apitype - The apitype to set
 * @returns the previous apitype
 *
 * @Note - this will modify also the value of sceKernelBootFrom, since the value of
 * bootfrom is calculated from the apitype
*/
int sctrlKernelSetInitApitype(int apitype);

/**
 * Sets the filename of the launched executable.
 *
 * @param filename - The filename to set
 * @returns 0 on success
*/
int sctrlKernelSetInitFileName(char *filename);

/**
 * Sets the init key config
 *
 * @param key - The key code
 * @returns the previous key config
*/
int sctrlKernelSetInitKeyConfig(int key);

/**
 * Sets the user level of the current thread
 *
 * @param level - The user level
 * @return the previous user level on success
 */
int sctrlKernelSetUserLevel(int level);

/**
 * Sets the devkit version
 * 
 * @param version - The devkit version to set
 * @return the previous devkit version
 * 
*/
int sctrlKernelSetDevkitVersion(int version);

/**
 * Checks if we are in SE.
 *
 * @returns 1 if we are in SE-C or later, 0 if we are in HEN-D or later,
 * and < 0 (a kernel error code) in any other case
*/
int	sctrlHENIsSE();

/**
 * Checks if we are in Devhook.
 *
 * @returns 1 if we are in SE-C/HEN-D for devhook  or later, 0 if we are in normal SE-C/HEN-D or later,
 * and < 0 (a kernel error code) in any other case
*/
int	sctrlHENIsDevhook();

/**
 * Gets the HEN version
 *
 * @returns - The HEN version
 *
 * HEN D / SE-C :  0x00000400
 */
int sctrlHENGetVersion();

/**
 * Gets the HEN minor version
 *
 * @returns - The HEN minor version
 */
int sctrlHENGetMinorVersion();

/**
 * Finds a driver
 *
 * @param drvname - The name of the driver (without ":" or numbers)
 *
 * @returns the driver if found, NULL otherwise
 *
 */
PspIoDrv *sctrlHENFindDriver(char *drvname);

/** 
 * Finds a function.
 *
 * @param modname - The module where to search the function
 * @param libname - The library name
 * @nid - The nid of the function
 *
 * @returns - The function address or 0 if not found
 *
*/
u32 sctrlHENFindFunction(char *modname, char *libname, u32 nid);

typedef struct SceModule2 {
    struct SceModule2   *next;
    unsigned short      attribute;
    unsigned char       version[2];
    char                modname[27];
    char                terminal;
    unsigned int        unknown1;
    unsigned int        unknown2;
    SceUID              modid;
    unsigned int        unknown3[2];
    u32         mpid_text;  // 0x38
    u32         mpid_data; // 0x3C
    void *              ent_top;
    unsigned int        ent_size;
    void *              stub_top;
    unsigned int        stub_size;
    unsigned int        unknown4[5];
    unsigned int        entry_addr;
    unsigned int        gp_value;
    unsigned int        text_addr;
    unsigned int        text_size;
    unsigned int        data_size;
    unsigned int        bss_size;
    unsigned int        nsegment;
    unsigned int        segmentaddr[4];
    unsigned int        segmentsize[4];
} SceModule2;

typedef int (* STMOD_HANDLER)(SceModule2 *);

/**
 * Sets a function to be called just before module_start of a module is gonna be called (useful for patching purposes)
 *
 * @param handler - The function, that will receive the module structure before the module is started.
 *
 * @returns - The previous set function (NULL if none);
 * @Note: because only one handler function is handled by HEN, you should
 * call the previous function in your code.
 *
 * @Example: 
 *
 * STMOD_HANDLER previous = NULL;
 *
 * int OnModuleStart(SceModule2 *mod);
 *
 * void somepointofmycode()
 * {
 *		previous = sctrlHENSetStartModuleHandler(OnModuleStart);
 * }
 *
 * int OnModuleStart(SceModule2 *mod)
 * {
 *		if (strcmp(mod->modname, "vsh_module") == 0)
 *		{
 *			// Do something with vsh module here
 *		}
 *
 *		if (!previous)
 *			return 0;
 *
 *		// Call previous handler
 *
 *		return previous(mod);
 * }
 *
 * @Note2: The above example should be compiled with the flag -fno-pic
 *			in order to avoid problems with gp register that may lead to a crash.
 *
*/
STMOD_HANDLER sctrlHENSetStartModuleHandler(STMOD_HANDLER handler);

typedef int (* KDEC_HANDLER)(u32 *buf, int size, int *retSize, int m);
typedef int (* MDEC_HANDLER)(u32 *tag, u8 *keys, u32 code, u32 *buf, int size, int *retSize, int m, void *unk0, int unk1, int unk2, int unk3, int unk4);

/**
 * Sets the speed (only for kernel usage)
 *
 * @param cpu - The cpu speed
 * @param bus - The bus speed
*/
void sctrlHENSetSpeed(int cpu, int bus);

/**
 * Sets the partition 2 and 8  memory for next loadexec.
 *
 * @param p2 - The size in MB for the user partition. Must be > 0
 * @param p8 - The size in MB for partition 8. Can be 0.
 *
 * @returns 0 on success, < 0 on error.
 * This function is only available in the slim. The function will fail
 * if p2+p8 > 52 or p2 == 0
*/
int sctrlHENSetMemory(u32 p2, u32 p8);

void sctrlHENPatchSyscall(void *addr, void *newaddr);

int sctrlKernelQuerySystemCall(void *func_addr);

int sctrlKernelBootFrom(void);

/**
 * Patch module by offset
 *
 * @param modname - module name
 * @param inst  - instruction
 * @param offset - module patch offset
 *
 * @return < 0 on error
 */
int sctrlPatchModule(char *modname, u32 inst, u32 offset);

/**
 * Get module text address
 *
 * @param modname - module name
 * 
 * @return text address, or 0 if not found
 */
u32 sctrlModuleTextAddr(char *modname);

/**
 * Get sceInit module text address
 *
 * @note Only useful before sceInit exits
 *
 * @return text address, or 0 if not found
 */
u32 sctrlGetInitTextAddr(void);

/**
 * Set custom start module handler
 * It can be used to replace a system module
 *
 * @note: func returns -1 to ignore the module and load the original module. Or new modid if replace is done.
 */
void sctrlSetCustomStartModule(int (*func)(int modid, SceSize argsize, void *argp, int *modstatus, SceKernelSMOption *opt));

/**
 * Loads a module on next reboot. Only kernel mode.
 *
 * @param module_after - The path of the module which is loaded after the module to be loaded.
   The module passed to this function will be loaded just before that module.
 * @param buf - The buffer containing the module - Don't deallocate this one. It has to reside in kernel memory.
 * @param size - The size of the module
 * @param flags - The modes in which the module should be loaded, one of BootLoadFlags
 *
 * @Example:
 * sctrlHENLoadModuleOnReboot("/kd/usersystemlib.prx", module_buffer, module_size, BOOTLOAD_GAME | BOOTLOAD_POPS | BOOTLOAD_UMDEMU); 
 *
 * This will load the module contained in module_buffer just before /kd/usersystemlib.prx in the next reboot, if the mode of next reboot is game, pops or umdemu
 *
 * @Remarks: Don't use too early modules in first param like "/kd/init.prx" or "/kd/systemctrl.prx", or your module may not load properly
 * Only one module will be loaded on reboot with this function. 
 * If this function is called many times, only the last one will be considered.
 * By making a module to load itself using this function, and calling 
 * sctrlHENLoadModuleOnReboot on module_start, a prx can cause itself to be resident in the modes choosen by flags.
 * If all flags are selected, the module will stay resident until a psp shutdown, or until sctrlHENLoadModuleOnReboot is not called.
*/

void sctrlHENLoadModuleOnReboot(char *module_after, void *buf, int size, int flags);

/**
 * Enable/disable NID Resolver on particular library
 *
 * @param libname the name of the library to be enabled/disabled
 * @param enabled 0 - disabled, != 0 - enabled
 *
 * @Example:
 * sctrlKernelSetNidResolver("sceImpose_driver", 0); // disable sceImpose_driver resolving
 *
 * @return previous value if set, < 0 on error
 */
int sctrlKernelSetNidResolver(char *libname, u32 enabled);

/**
 * Get a random u32 key from PSP Kirk PRNG
 */
u32 sctrlKernelRand(void);

/**
 * Get the real unspoofed Ethernet (MAC) Address of the systems WLAN chip
 *
 * @param mac Out-Buffer (6B) for real MAC Address
 *
 * @return 0 on success, < 0 on error
 */
int sctrlGetRealEthernetAddress(uint8_t * mac);

#endif


================================================
FILE: src/kernel_exploit.c
================================================
/*
	Downgrade Launcher -> kernel_exploit.c -> Responsible for doin' sum epik lolhax on teh kurnal
	by Davee
	
	28/12/2010
*/

#include <pspkernel.h>
#include <pspsysmem_kernel.h>
#include <psputility.h>

#include <stdio.h>
#include <string.h>

#include "kernel_exploit.h"
#include "kernel_land.h"
#include "utils.h"
#include "rebootex.h"

int sceKernelPowerLock(void *ptr, u32 kexec_address);
u32 getPowerAddress(SceUID callback);
int sceNetMPulldown(sceKernelIfHandleParam *, int, int, void *);

/* function pointers */
int (* sceKernelUtilsMd5BlockInitHax)(u32 addr, u32 check_result, u32 unused2, u32 k1) = (void *)sceKernelUtilsMd5BlockInit;
int (* sceHttpStorageOpen) (u32 kaddrs, u32 unk, u32 unk2);

int sceUtilityPowerRegisterCallback(int slot, SceUID callback);

int sceUtilityPowerunRegisterCallback(int slot);

/* globals */
u32 g_kfunctions_resolved = 0;

int DummyCallback(void)
{
	return 0;
}

int pre_kernel(int (* kfunc)(void))
{
	int i;
	
	/* set $k1 */
	asm("move $k1, $0\n");
	
	/* check if we've resolved the kernel function pointers */
	if (g_kfunctions_resolved == 0)
	{
		/* Resolve the kernel function */
		/* Search kmem for the sceKernelFindModuleByName */
		for (i = 0x88000000; i < (0x88400000 - 0x54 - 4); i += 4)
		{
			if (_lw(i+0x00) == 0x27BDFFE0 && _lw(i+0x04) == 0xAFB40010 &&
				_lw(i+0x08) == 0xAFB3000C && _lw(i+0x0C) == 0xAFB20008 &&
				_lw(i+0x10) == 0x00009021 && _lw(i+0x14) == 0x02409821 &&
				_lw(i+0x54) == 0x0263202A)
			{
				/* found it, i = address of function */
				pspKernelFindModuleByName = (void *)i;
				break;
			}
		}
		
		/* find our functions */
		if((g_devkit_version == FIRMWARE_VERSION_660) || (g_devkit_version == FIRMWARE_VERSION_661))
		{
			pspKernelGetModel = (void *)FindProc("sceSystemMemoryManager", "SysMemForKernel", 0x07C586A1); //6.60
			pspKernelLoadExecVSHEf1 = (void *)FindProc("sceLoadExec", "LoadExecForKernel", 0x16A68007); //6.60
			pspKernelLoadExecVSHMs1 = (void *)FindProc("sceLoadExec", "LoadExecForKernel", 0x4FB44D27); //6.60
			
			pspSysconGetBaryonVersion = (void *)FindProc("sceSYSCON_Driver", "sceSyscon_driver", 0x7EC5A957);
			pspIoOpen = (void *)FindProc("sceIOFileManager", "IoFileMgrForKernel", 0x109F50BC);	
			pspIoWrite = (void *)FindProc("sceIOFileManager", "IoFileMgrForKernel", 0x42EC03AC);
			pspIoClose = (void *)FindProc("sceIOFileManager", "IoFileMgrForKernel", 0x810C4BC3);
		}
		else
		{
			pspKernelGetModel = (void *)FindProc("sceSystemMemoryManager", "SysMemForKernel", 0x458A70B5); //6.31/6.35
			pspKernelLoadExecVSHEf1 = (void *)FindProc("sceLoadExec", "LoadExecForKernel", 0xCEFE1100); //6.31/6.35
			pspKernelLoadExecVSHMs1 = (void *)FindProc("sceLoadExec", "LoadExecForKernel", 0x7286CF0B); //6.31/6.35
			
			pspSysconGetBaryonVersion = (void *)FindProc("sceSYSCON_Driver", "sceSyscon_driver", 0x7EC5A957);
			pspIoOpen = (void *)FindProc("sceIOFileManager", "IoFileMgrForKernel", 0x109F50BC);	
			pspIoWrite = (void *)FindProc("sceIOFileManager", "IoFileMgrForKernel", 0x42EC03AC);
			pspIoClose = (void *)FindProc("sceIOFileManager", "IoFileMgrForKernel", 0x810C4BC3);
		}

		/* set resolved flag */
		g_kfunctions_resolved = 1;
	}
	
	/* Clear the caches */
	KClearCaches();
	return kfunc();
}


int repairKernel631(void)
{
	/* repair the MD5 functionality */
	_sw(0x00003821, 0x88000000 + 0xF270);
	_sw(0x001B3AC0, 0x88000000 + 0xF274);
	_sw(0x3C068002, 0x88000000 + 0xF278);
	_sw(0x00E42824, 0x88000000 + 0xF27C);
	
	/* repair the suspend library */
	_sw(0x8CC54230, 0x88000000 + 0xCD38);
	_sw(0x00402021, 0x88000000 + 0xCD3C);
	_sw(0x24A20001, 0x88000000 + 0xCD40);
	_sw(0x0E0047EE, 0x88000000 + 0xCD44);
	_sw(0xACC24230, 0x88000000 + 0xCD48);
	_sw(0x0A003348, 0x88000000 + 0xCD4C);
	_sw(0x00001021, 0x88000000 + 0xCD50);
	
	return 0;
}

int repairKernel635(void)
{
	/* repair the MD5 functionality */
	_sw(0x00003821, 0x88000000 + 0xF150);
	_sw(0x001B3AC0, 0x88000000 + 0xF154);
	_sw(0x3C068002, 0x88000000 + 0xF158);
	_sw(0x00E42824, 0x88000000 + 0xF15C);
	
	/* repair the suspend library */
	_sw(0x8CC540F0, 0x88000000 + 0xCC18);
	_sw(0x00402021, 0x88000000 + 0xCC1C);
	_sw(0x24A20001, 0x88000000 + 0xCC20);
	_sw(0x0E0047A6, 0x88000000 + 0xCC24);
	_sw(0xACC240F0, 0x88000000 + 0xCC28);
	_sw(0x0A003300, 0x88000000 + 0xCC2C);
	_sw(0x00001021, 0x88000000 + 0xCC30);
	
	return 0;
}

int execKernelFunction631(void *kfunc)
{
	/* set a pointer sequence in order the comply with the exploits loading sequence */
	u32 kernel_exec_func = ((u32)pre_kernel) | 0x80000000;
	u32 kernel_exec_ptr = ((u32)&kernel_exec_func) - 16;
	
	/* syscall jump into kmode which will end up jumping to pre_kernel_entry function */
	int res = sceKernelPowerLock((void *)((u32)kfunc | 0x80000000), ((u32)&kernel_exec_ptr) - 0x4234);
	
	/* clear the caches and return the value from the kernel function */
	ClearCaches();
	return res;
}

int execKernelFunction635(void *kfunc)
{
	/* set a pointer sequence in order the comply with the exploits loading sequence */
	u32 kernel_exec_func = ((u32)pre_kernel) | 0x80000000;
	u32 kernel_exec_ptr = ((u32)&kernel_exec_func) - 16;
	
	/* syscall jump into kmode which will end up jumping to pre_kernel_entry function */
	int res = sceKernelPowerLock((void *)((u32)kfunc | 0x80000000), ((u32)&kernel_exec_ptr) - 0x40F4);
	
	/* clear the caches and return the value from the kernel function */
	ClearCaches();
	return res;
}

int execKernelFunction660(void *kfunc)
{
	/* set a pointer sequence in order the comply with the exploits loading sequence */
	u32 kernel_exec_func = ((u32)pre_kernel) | 0x80000000;
	u32 kernel_exec_ptr = ((u32)&kernel_exec_func) - 16;
	
	/* syscall jump into kmode which will end up jumping to pre_kernel_entry function */
	int res = sceKernelPowerLock((void *)((u32)kfunc | 0x80000000), ((u32)&kernel_exec_ptr) - 0x40F8);
	
	/* clear the caches and return the value from the kernel function */
	ClearCaches();
	return res;
}

int execKernelFunction(void *kfunc)
{
	/* execute kernel mode pending on the system version */
	if (sceKernelDevkitVersion() == FIRMWARE_VERSION_631)
	{
		/* 6.31 exploit */
		return execKernelFunction631(kfunc);
	}
	else if (sceKernelDevkitVersion() == FIRMWARE_VERSION_635 ||
			 sceKernelDevkitVersion() == FIRMWARE_VERSION_638 ||
			 sceKernelDevkitVersion() == FIRMWARE_VERSION_639)
	{
		/* 6.35 exploit */
		return execKernelFunction635(kfunc);
	}
	else if (sceKernelDevkitVersion() == FIRMWARE_VERSION_660)
	{
		return execKernelFunction660(kfunc);
	}
	else if (sceKernelDevkitVersion() == FIRMWARE_VERSION_661)
	{
		return execKernelFunction660(kfunc);
	}
	
	return 0;
}

SceLibraryStubTable *findLibraryByName(char *libname, u32 address)
{
	u32 i = 0;
	
	/* search through umem for the libname */
	for (i = address; i < (0x08800000 + (24 << 20)); i += 4)
	{
		/* cast a stub */
		SceLibraryStubTable *stub = (SceLibraryStubTable *)i;
		
		/* check for valid address */
		if ((stub->libname != libname) && isValidUserAddress((void *)stub->libname) && isValidUserAddress(stub->nidtable) && isValidUserAddress(stub->stubtable))
		{
			/* check libname */
			if (strcmp(libname, stub->libname) == 0)
			{
				/* found it */
				return stub;
			}
		}
	}
	
	/* error */
	ErrorExit(5000, "Error, could not find library %s\n", libname);
	return NULL;
}

void *getFunctionFromLibrary(SceLibraryStubTable *stub, u32 nid)
{
	int i;
	
	/* cast this so we're not always loading from stub struct */
	u32 *nids = stub->nidtable;
	
	/* loop through */
	for (i = 0; i < stub->stubcount; i++)
	{
		/* check for nid */
		if (nids[i] == nid)
		{
			/* we got it, pal */
			return (void *)((u32)stub->stubtable + (i << 3));
		}
	}
	
	/* error, not found */
	ErrorExit(5000, "Error, could not find nid 0x%08X in library %s\n", nid, stub->libname);
	return NULL;
}

void doKernelExploit631(void)
{
	u32 power_address = 0;

#ifdef HBL_SUKKIRI
	/* get proper MD5 imports (HBL does not resolve properly) */
	u32 address = (u32)findLibraryByName("sceNetIfhandle_lib", 0x08800000);
	SceLibraryStubTable *stub = findLibraryByName("UtilsForUser", address - 0x500);
	
	/* copy over the stubs */
	memcpy(sceKernelUtilsMd5BlockInit, getFunctionFromLibrary(stub, 0x9E5C5086), 8);
	memcpy(sceKernelUtilsMd5BlockUpdate, getFunctionFromLibrary(stub, 0x61E1E525), 8);
	memcpy(sceKernelUtilsMd5BlockResult, getFunctionFromLibrary(stub, 0xB8D24E78), 8);
	
	/* get our stub pointer */
	stub = findLibraryByName("sceUtility_private", 0x08800000);
	
	/* get our exploit functions */
	memcpy(sceUtilityPowerRegisterCallback, getFunctionFromLibrary(stub, 0xE65F37C8), 8); //6.31 nid
	memcpy(sceUtilityPowerunRegisterCallback, getFunctionFromLibrary(stub, 0x9ABAFCC5), 8); //6.31 nid
#endif

	/* create a callback */
	SceUID callback = sceKernelCreateCallback("Callback", (void *)DummyCallback, NULL);
	
	/* check for error */
	if (callback < 0)
	{
		return ErrorExit(5000, "Error creating callback\n");
	}
	
	/* register slot 0 (ignore error, use to ensure slot has a registered entry) */
	sceUtilityPowerRegisterCallback(0, callback);
	
	/* get the power address */
	power_address = getPowerAddress(callback);
	
	/* unregister again */
	sceUtilityPowerunRegisterCallback(0);
	
	/* bingo, we've got it! set sysmem addr to seek backwards from this address so when used in the callback func, it is directly at sysmem */
	u32 sysmem_addr = (~(power_address - 0x88000000) + 1) >> 4;

	/* unregister in order to remove any positive value ignore return value */
	sceUtilityPowerunRegisterCallback(sysmem_addr + 0xF27); //6.31
	
	/* commit changes */
	ClearCaches();
	
	/* call register callback in order to activate the exploit */
	int res = sceUtilityPowerRegisterCallback(sysmem_addr + 0xF27, callback); //6.31
	
	/* check for error */
	if (res < 0)
	{
		/* error activating exploit */
		return ErrorExit(5000, "Error 0x%08X activating kernel exploit\n", res);
	}
	
	/* delete the callback */
	sceKernelDeleteCallback(callback);
	
	/* clear caches */
	ClearCaches();
	
	/* now use the MD5 function to cause exploit */
	sceKernelUtilsMd5BlockInitHax(0x8800CD54 - 28, 0, 0, 0); //6.31

	/* clear caches, allow changes to commit */
	ClearCaches();
	
	/* now you can use the 6.31 kernel call */
	execKernelFunction631(repairKernel631);
}

void doKernelExploit635(void)
{
	u32 power_address = 0;

#ifdef HBL_SUKKIRI
	/* get proper MD5 imports (HBL does not resolve properly) */
	u32 address = (u32)findLibraryByName("sceNetIfhandle_lib", 0x08800000);
	SceLibraryStubTable *stub = findLibraryByName("UtilsForUser", address - 0x500);
	
	/* copy over the stubs */
	memcpy(sceKernelUtilsMd5BlockInit, getFunctionFromLibrary(stub, 0x9E5C5086), 8);
	memcpy(sceKernelUtilsMd5BlockUpdate, getFunctionFromLibrary(stub, 0x61E1E525), 8);
	memcpy(sceKernelUtilsMd5BlockResult, getFunctionFromLibrary(stub, 0xB8D24E78), 8);
	
	/* get our stub pointer */
	stub = findLibraryByName("sceUtility_private", 0x08800000);
	
	/* get our exploit functions */
	memcpy(sceUtilityPowerRegisterCallback, getFunctionFromLibrary(stub, 0xE65F37C8), 8); //6.31/6.35 nid
	memcpy(sceUtilityPowerunRegisterCallback, getFunctionFromLibrary(stub, 0x9ABAFCC5), 8); //6.31/6.35 nid
#endif

	/* create a callback */
	SceUID callback = sceKernelCreateCallback("Callback", (void *)DummyCallback, NULL);
	
	/* check for error */
	if (callback < 0)
	{
		return ErrorExit(5000, "Error creating callback\n");
	}
	
	/* register slot 0 (ignore error, use to ensure slot has a registered entry) */
	sceUtilityPowerRegisterCallback(0, callback);
	
	/* get the power address */
	power_address = getPowerAddress(callback);
	
	/* unregister again */
	sceUtilityPowerunRegisterCallback(0);
	
	/* bingo, we've got it! set sysmem addr to seek backwards from this address so when used in the callback func, it is directly at sysmem */
	u32 sysmem_addr = (~(power_address - 0x88000000) + 1) >> 4;

	/* unregister in order to remove any positive value ignore return value */
	sceUtilityPowerunRegisterCallback(sysmem_addr + 0xF15); //6.35
	
	/* commit changes */
	ClearCaches();
	
	/* call register callback in order to activate the exploit */
	int res = sceUtilityPowerRegisterCallback(sysmem_addr + 0xF15, callback); //6.35
	
	/* check for error */
	if (res < 0)
	{
		/* error activating exploit */
		return ErrorExit(5000, "Error 0x%08X activating kernel exploit\n", res);
	}
	
	/* delete the callback */
	sceKernelDeleteCallback(callback);
	
	/* clear caches */
	ClearCaches();
	
	/* now use the MD5 function to cause exploit */
	sceKernelUtilsMd5BlockInitHax(0x8800CC34 - 28, 0, 0, 0); //6.35

	/* clear caches, allow changes to commit */
	ClearCaches();
	
	/* now you can use the 6.35 kernel call */
	execKernelFunction635(repairKernel635);
}

int nopOut()
{
	_sw(0x00000000, 0x8800CC34);
	return 0;
}

void doKernelExploit638(void)
{
	int modid, i;
	
	/* Load necessary modules */
	for(i = 1; i < 7; i++)
		modid = sceUtilityLoadNetModule(i);
	
	SceLibraryStubTable *stub = findLibraryByName("sceHttpStorage", 0x08800000);
	sceHttpStorageOpen = (void *) getFunctionFromLibrary(stub, 0x700AAD44); 

	/* Overwrite the addition of a global, so I can write to a direct address */
	int ret = sceHttpStorageOpen(-0x990>>2, 0, 0);
	
	/* DelayThread fixes, REQUIRED */
	sceKernelDelayThread(1000000);
	ClearCaches();

	/* vsync 0xFFFF out powerLock */
	ret = sceHttpStorageOpen(0x8800CC34>>2, 0, 0);
	ClearCaches();

	/* use PowerLock to run the function nopOut in kmode, which nop's out the vsync, so now non vfpu enabled threads can use powerLock */
	execKernelFunction635(nopOut);

	/* Finally, Clear caches */
	ClearCaches();
	
	/* Unload Modules */
	for(i = 6; i > 0; i--)
		sceUtilityUnloadNetModule(i);
}

void doKernelExploit660(void)
{
	u32 val;
	sceKernelIfHandleParam param_top;
	sceKernelIfHandleParam param_sub;
	
	sceUtilityLoadNetModule(1);
	
	memset(&param_top, 0, sizeof(sceKernelIfHandleParam));
	memset(&param_sub, 0, sizeof(sceKernelIfHandleParam));
	
	val = 0;
	
	/* Fill sub structure */
	param_sub.unk_8 = (u32)&val;
	param_sub.unk_12 = sizeof(u32);
	
	/* Fill top structure */
	param_top.unk_0 = &param_sub;
	param_top.unk_12 = 1;
	param_top.unk_18 = 1;
	param_top.unk_68 = (u32)&param_top;
	param_top.unk_8 = 0x8800CBB8 - param_top.unk_12;
	param_top.unk_48 = 0x8800CBB8;
	param_top.unk_60 = sizeof(u32);
	
	sceNetMPulldown(&param_top, 0, param_top.unk_12 + sizeof(u32), NULL);
	
	ClearCaches();
}

void doKernelExploit(void)
{
	/* ok, lets check firmware version */
	if (sceKernelDevkitVersion() == FIRMWARE_VERSION_631)
	{
		/* do ksploit for 6.31 */
		doKernelExploit631();
	}
	else if (sceKernelDevkitVersion() == FIRMWARE_VERSION_635)
	{
		/* do ksploit for 6.35 */
		doKernelExploit635();
	}
	else if (sceKernelDevkitVersion() == FIRMWARE_VERSION_638 || sceKernelDevkitVersion() == FIRMWARE_VERSION_639)
	{
		/* do ksploit for 6.38 */
		doKernelExploit638();
	}
	else if (sceKernelDevkitVersion() == FIRMWARE_VERSION_660)
	{
		doKernelExploit660();
	}
	else if (sceKernelDevkitVersion() == FIRMWARE_VERSION_661)
	{
		doKernelExploit660();
	}
	else
	{
		/* not supported */
		ErrorExit(5000, "Error, your firmware is not supported.\n");
	}
}


================================================
FILE: src/kernel_exploit.h
================================================
/*
	Downgrade Launcher -> patch_table.h -> Provide API documentation and definitions for the table patching
	by Davee
	
	01/01/2011
*/
#ifndef __KERNEL_EXPLOIT_H__
#define __KERNEL_EXPLOIT_H__

/* prototypes */
void doKernelExploit(void);
int execKernelFunction(void *kfunc);

typedef struct sceKernelIfHandleParam
{
	struct sceKernelIfHandleParam *unk_0;
	u32 unk_4;
	u32 unk_8;
	u32 unk_12;
	u16 unk_16;
	u16 unk_18;
	u32 unk_20;
	u32 unk_24;
	u32 unk_28;
	u32 unk_32;
	u32 unk_36;
	u32 unk_40;
	u32 unk_44;
	u32 unk_48;
	u32 unk_52;
	u32 unk_56;
	u32 unk_60;
	u32 unk_64;
	u32 unk_68;
	u32 unk_72;
} sceKernelIfHandleParam;

#endif /* __KERNEL_EXPLOIT_H__ */


================================================
FILE: src/kernel_land.c
================================================
/*
	Downgrade Launcher -> kernel_land.c -> Responsible for containing code access in kernel mode
	by Davee
	
	28/12/2010
*/

#include <pspkernel.h>
#include <pspsysmem_kernel.h>
#include <psploadexec_kernel.h>

#include <stdio.h>
#include <string.h>

#include "kernel_land.h"
#include "rebootex.h"
#include "utils.h"
#include "downgrade_ctrl/patch_table.h"

/* function pointers */
int (* pspKernelGetModel)(void) = NULL;
int (* pspSysconGetBaryonVersion)(u32 *baryon) = NULL;
SceModule2 *(* pspKernelFindModuleByName)(const char *name) = NULL;
int (* pspKernelLoadExecVSHEf1)(const char *path, struct SceKernelLoadExecVSHParam *param) = NULL;
int (* pspKernelLoadExecVSHMs1)(const char *path, struct SceKernelLoadExecVSHParam *param) = NULL;
SceUID (* pspIoOpen)(char *file, int flags, SceMode mode) = NULL;
int (* pspIoWrite)(SceUID fd, void *data, u32 len) = NULL;
int (* pspIoClose)(SceUID fd) = NULL;

/* globals */
struct SceKernelLoadExecVSHParam g_exec_param;

u32 getBaryon(void)
{
	u32 baryon;
	
	/* get the baryon version */
	pspSysconGetBaryonVersion(&baryon);
	
	/* return it */
	return baryon;
}

int getModel(void)
{
	/* return the PSP model */
	return pspKernelGetModel();
}

int delete_resume_game(void)
{
	u8 _header[512+64];
	
	/* use a pointer for math ease */
	u8 *header = _header; 
	
	/* align to 64 */
	header = (u8 *)((u32)header & ~0x3F); header = (u8 *)((u32)header + 0x40);
	
	/* now clear it */
	memset(header, 0, 512);
	
	/* open hibernation fs */
	SceUID fd = pspIoOpen("eflash0a:__hibernation", 0x04000003, 0);
	
	/* check for error */
	if (fd < 0)
	{
		/* return error */
		return fd;
	}
	
	/* write the blank header */
	int written = pspIoWrite(fd, header, 512);
	
	/* check for error */
	if (written < 0)
	{
		/* close file */
		pspIoClose(fd);
		
		/* return the error code */
		return written;
	}
	
	/* return result */
	return pspIoClose(fd);
}

int patch_loadexec_phat(void)
{
	/* Find the LoadExec */
	SceModule2 *mod = pspKernelFindModuleByName("sceLoadExec");
	
	if(g_devkit_version == FIRMWARE_VERSION_638 || g_devkit_version == FIRMWARE_VERSION_639 || g_devkit_version == FIRMWARE_VERSION_660 || g_devkit_version == FIRMWARE_VERSION_661)
	{
		/* Patch the reboot process */
		MAKE_CALL(mod->text_addr + 0x2DAC, RebootEntryPatched); //6.38		
		/* get past the userlevel check */
		MAKE_RELATIVE_BRANCH(0x23D0, 0x2418, mod->text_addr); //6.38
	}
	else
	{
		/* Patch the reboot process */
		MAKE_CALL(mod->text_addr + 0x2D94, RebootEntryPatched); //6.31/6.35
		
		/* get past the userlevel check */
		MAKE_RELATIVE_BRANCH(0x23B8, 0x2400, mod->text_addr); //6.31/6.35
	}
	
	KClearCaches();
	
	/* just return 0 */
	return pspKernelLoadExecVSHMs1(OTHER_UPDATER_PATH, &g_exec_param);
}

int patch_loadexec_slim(void)
{
	/* Find the LoadExec */
	SceModule2 *mod = pspKernelFindModuleByName("sceLoadExec");
	
	if(g_devkit_version == FIRMWARE_VERSION_638 || g_devkit_version == FIRMWARE_VERSION_639 || g_devkit_version == FIRMWARE_VERSION_660 || g_devkit_version == FIRMWARE_VERSION_661)
	{
		/* Patch the reboot process */
		MAKE_CALL(mod->text_addr + 0x2DAC, RebootEntryPatched); //6.38		
		/* get past the userlevel check */
		MAKE_RELATIVE_BRANCH(0x23D0, 0x2418, mod->text_addr); //6.38
	}
	else
	{
		/* Patch the reboot process */
		MAKE_CALL(mod->text_addr + 0x2D94, RebootEntryPatched); //6.31/6.35
		
		/* get past the userlevel check */
		MAKE_RELATIVE_BRANCH(0x23B8, 0x2400, mod->text_addr); //6.31/6.35
	}
	
	KClearCaches();
	
	/* just return 0 */
	return pspKernelLoadExecVSHMs1(OTHER_UPDATER_PATH, &g_exec_param);
}

int patch_loadexec_3000(void)
{
	/* Find the LoadExec */
	SceModule2 *mod = pspKernelFindModuleByName("sceLoadExec");
	
	if(g_devkit_version == FIRMWARE_VERSION_638 || g_devkit_version == FIRMWARE_VERSION_639 || g_devkit_version == FIRMWARE_VERSION_660 || g_devkit_version == FIRMWARE_VERSION_661)
	{
		/* Patch the reboot process */
		MAKE_CALL(mod->text_addr + 0x2DAC, RebootEntryPatched); //6.38		
		/* get past the userlevel check */
		MAKE_RELATIVE_BRANCH(0x23D0, 0x2418, mod->text_addr); //6.38
	}
	else
	{
		/* Patch the reboot process */
		MAKE_CALL(mod->text_addr + 0x2D94, RebootEntryPatched); //6.31/6.35
		
		/* get past the userlevel check */
		MAKE_RELATIVE_BRANCH(0x23B8, 0x2400, mod->text_addr); //6.31/6.35
	}
	
	KClearCaches();
	
	/* just return 0 */
	return pspKernelLoadExecVSHMs1(OTHER_UPDATER_PATH, &g_exec_param);
}

int patch_loadexec_4000(void)
{
	/* Find the LoadExec */
	SceModule2 *mod = pspKernelFindModuleByName("sceLoadExec");
	
	if(g_devkit_version == FIRMWARE_VERSION_638 || g_devkit_version == FIRMWARE_VERSION_639 || g_devkit_version == FIRMWARE_VERSION_660 || g_devkit_version == FIRMWARE_VERSION_661)
	{
		/* Patch the reboot process */
		MAKE_CALL(mod->text_addr + 0x2DAC, RebootEntryPatched); //6.38		
		/* get past the userlevel check */
		MAKE_RELATIVE_BRANCH(0x23D0, 0x2418, mod->text_addr); //6.38
	}
	else
	{
		/* Patch the reboot process */
		MAKE_CALL(mod->text_addr + 0x2D94, RebootEntryPatched); //6.31/6.35
		
		/* get past the userlevel check */
		MAKE_RELATIVE_BRANCH(0x23B8, 0x2400, mod->text_addr); //6.31/6.35
	}
	
	KClearCaches();
	
	/* just return 0 */
	return pspKernelLoadExecVSHMs1(OTHER_UPDATER_PATH, &g_exec_param);
}

int patch_loadexec_pspgo(void)
{
	/* Find the LoadExec */
	SceModule2 *mod = pspKernelFindModuleByName("sceLoadExec");
	
	if(g_devkit_version == FIRMWARE_VERSION_638 || g_devkit_version == FIRMWARE_VERSION_639 || g_devkit_version == FIRMWARE_VERSION_660 || g_devkit_version == FIRMWARE_VERSION_661)
	{
		/* Patch the reboot process */
		MAKE_CALL(mod->text_addr + 0x2FF8, RebootEntryPatched); //6.38
		
		/* get past the userlevel checks for VSH */
		MAKE_RELATIVE_BRANCH(0x2624, 0x266C, mod->text_addr); //6.31/6.35
	}
	else
	{
		/* Patch the reboot process */
		MAKE_CALL(mod->text_addr + 0x2FE0, RebootEntryPatched); //6.31/6.35
		
		/* get past the userlevel checks for VSH */
		MAKE_RELATIVE_BRANCH(0x260C, 0x2658, mod->text_addr); //6.31/6.35
	}
	
	/* clear the caches */
	KClearCaches();

	/* reboot into the updater */
	return pspKernelLoadExecVSHEf1(PSPGO_UPDATER_PATH, &g_exec_param);
}

int patch_loadexec_street(void)
{
	/* Find the LoadExec */
	SceModule2 *mod = pspKernelFindModuleByName("sceLoadExec");
	
	if(g_devkit_version == FIRMWARE_VERSION_660 || g_devkit_version == FIRMWARE_VERSION_661)
	{
		/* Patch the reboot process */
		MAKE_CALL(mod->text_addr + 0x2DAC, RebootEntryPatched); //6.38		
		/* get past the userlevel check */
		MAKE_RELATIVE_BRANCH(0x23D0, 0x2418, mod->text_addr); //6.38
	}
	
	KClearCaches();
	
	/* just return 0 */
	return pspKernelLoadExecVSHMs1(OTHER_UPDATER_PATH, &g_exec_param);
}

int launch_updater(void)
{
	KClearCaches();
	
	int res = -1;
	
	/* clear our param */
	memset(&g_exec_param, 0, sizeof(struct SceKernelLoadExecVSHParam));
	
	/* fill the field */
	g_exec_param.size = sizeof(struct SceKernelLoadExecVSHParam);
	g_exec_param.argp = (pspKernelGetModel() == 4) ? (PSPGO_UPDATER_PATH) : (OTHER_UPDATER_PATH);
	g_exec_param.args = strlen(g_exec_param.argp) + 1;
	g_exec_param.key = "updater";
	g_exec_param.vshmain_args_size = 0;
	g_exec_param.vshmain_args = NULL;
	g_exec_param.configfile = NULL;
	g_exec_param.unk4 = 0;
	g_exec_param.unk5 = 0x10000;
	
	/* get the model */
	u32 model = pspKernelGetModel();
	
	if(model == 6 || model == 8)
	{
		model = 3;
	}
	
	/* launch a loadexec patch depending on model */
	switch (model)
	{
		/* PSP PHAT */
		case 0:
		{
			/* launch the updater and patch reboot */
			res = patch_loadexec_phat();
			break;
		}
		
		/* PSP SLIM */
		case 1:
		{
			/* launch the updater and patch reboot */
			res = patch_loadexec_slim();
			break;
		}
		
		/* PSP 3000 */
		case 2:
		{
			/* launch the updater and patch reboot */
			res = patch_loadexec_3000();
			break;
		}
		
		/* PSP 4000 */
		case 3:
		{
			/* launch the updater and patch reboot */
			res = patch_loadexec_4000();
			break;
		}
		
		/* PSP Go */
		case 4:
		{
			/* launch the updater and patch reboot */
			res = patch_loadexec_pspgo();
			break;
		}

		/* PSP E-1000 (Street) */
		case 10:
		{
			res = patch_loadexec_street();
			break;
		}
	}
	
	/* return result */
	return res;
}


================================================
FILE: src/kernel_land.h
================================================
/*
	Downgrade Launcher -> kernel_land.h -> Provide API documentation and definitions for the kernel operations
	by Davee
	
	28/12/2010
*/
#ifndef __KERNEL_LAND_H__
#define __KERNEL_LAND_H__

#include <psploadexec_kernel.h>
#include "include/systemctrl.h"

int getModel(void);
u32 getBaryon(void);
int launch_updater(void);
int delete_resume_game(void);

extern int (* pspKernelGetModel)(void);
extern int (* pspSysconGetBaryonVersion)(u32 *baryon);
extern SceModule2 *(* pspKernelFindModuleByName)(const char *name);
extern int (* pspKernelLoadExecVSHEf1)(const char *path, struct SceKernelLoadExecVSHParam *param);
extern int (* pspKernelLoadExecVSHMs1)(const char *path, struct SceKernelLoadExecVSHParam *param);
extern SceUID (* pspIoOpen)(char *file, int flags, SceMode mode);
extern int (* pspIoWrite)(SceUID fd, void *data, u32 len);
extern int (* pspIoClose)(SceUID fd);

#endif /* __KERNEL_LAND_H__ */


================================================
FILE: src/libasm/libinfinityKernel.S
================================================
.set noreorder

#include "pspstub.s"

STUB_START "libinfinityKernel",0x00090000,0x00040005
STUB_FUNC  0x0527FEC1,infGetVersion
STUB_FUNC  0xA69B7B7E,infGetCoreVersion
STUB_FUNC  0x3AE45BE1,infGetRedirectionStatus
STUB_FUNC  0xD81F887B,infSetRedirectionStatus
STUB_END


================================================
FILE: src/libasm/libinfinityUser.S
================================================
.set noreorder

#include "pspstub.s"

STUB_START "libinfinityUser",0x40090000,0x00040005
STUB_FUNC  0x0527FEC1,infGetVersion
STUB_FUNC  0xA69B7B7E,infGetCoreVersion
STUB_FUNC  0x3AE45BE1,infGetRedirectionStatus
STUB_FUNC  0xD81F887B,infSetRedirectionStatus
STUB_END


================================================
FILE: src/main.c
================================================
/*
    Downgrade Launcher R1
    by Davee
    
    Fin-rev 24/01/2011
*/

#include <pspkernel.h>
#include <pspsdk.h>
#include <psputility.h>
#include <pspctrl.h>

#include <pspsysmem_kernel.h>
#include <psploadexec_kernel.h>
#include <psploadcore.h>

#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <malloc.h>

#include "utils.h"
#include "kernel_land.h"
#include "kernel_exploit.h"
#include "rebootex.h"

PSP_MODULE_INFO("Chronoswitch", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(PSP_THREAD_ATTR_VFPU);
PSP_HEAP_SIZE_KB(3 << 10);

#define DOWNGRADER_VER    ("7.0")

typedef struct __attribute__((packed))
{
        int magic; // 0
        int version; // 4
        unsigned int keyofs; // 8
        unsigned int valofs; // 12
        int count; // 16
} SfoHeader;

typedef struct __attribute__((packed))
{
        unsigned short nameofs; // 0
        char alignment; // 2
        char type; // 3
        int valsize; // 4
        int totalsize; // 8
        unsigned short valofs; // 12
        short unknown; // 16
} SfoEntry;
    
u32 get_updater_version(u32 is_pspgo)
{
    int i;
    char *fw_data = NULL;
    u32 pbp_header[0x28/4];
    u8 sfo_buffer[4 << 10];
    SfoHeader *header = (SfoHeader *)sfo_buffer;
    SfoEntry *entries = (SfoEntry *)((char *)sfo_buffer + sizeof(SfoHeader));
    
    /* Lets open the updater */
    char *file = (is_pspgo) ? ("ef0:/PSP/GAME/UPDATE/EBOOT.PBP") : ("ms0:/PSP/GAME/UPDATE/EBOOT.PBP");
    
    /* open file */
    SceUID fd = sceIoOpen(file, PSP_O_RDONLY, 0777);
    
    /* check for failure */
    if (fd < 0)
    {
        /* error firmware */
        return 0xFFF;
    }
    
    /* read the PBP header */
    sceIoRead(fd, pbp_header, sizeof(pbp_header));
    
    /* seek to the SFO */
    sceIoLseek32(fd, pbp_header[8/4], PSP_SEEK_SET);
    
    /* calculate the size of the SFO */
    u32 sfo_size = pbp_header[12/4] - pbp_header[8/4];
    
    /* check if greater than buffer size */
    if (sfo_size > sizeof(sfo_buffer))
    {
        /* too much */
        sceIoClose(fd);
        return 0xFFF;
    }
    
    /* read the sfo */
    sceIoRead(fd, sfo_buffer, sizeof(sfo_buffer));
    
    /* close the file */
    sceIoClose(fd);
    
    /* now parse the SFO */
    for (i = 0; i < header->count; i++)
    {
        /* check this name */
        if (strcmp((char *)((char *)sfo_buffer + header->keyofs + entries[i].nameofs), "UPDATER_VER") == 0)
        {
            /* get the string */
            fw_data = (char *)((char *)sfo_buffer + header->valofs + entries[i].valofs);
            break;
        }
    }
    
    /* see if we went through all the data */
    if (i == header->count)
    {
        return 0xFFF;
    }
    
    /* return the firmware version */
    return (((fw_data[0] - '0') & 0xF) << 8) | (((fw_data[2] - '0') & 0xF) << 4) | (((fw_data[3] - '0') & 0xF) << 0);
}

int main(int argc, char *argv[])
{
    int res;
    SceCtrlData pad_data;
    u32 cur_buttons, prev_buttons = 0;

#ifdef HBL_SUKKIRI
    pspUtilityHtmlViewerParam html_param;
#endif
    
    /* initialise the PSP screen */
    pspDebugScreenInit();
    pspDebugScreenSetTextColor(0x00D05435);
    
    /* display welcome message */
    printf(
        "Chronoswitch Downgrader" "\n"
        "Version %s. Built %s %s" "\n" "\n"
        
        "Contributions:" "\n"
        "\t"    "6.31/6.35 Support added by Davee" "\n"
        "\t"    "6.38/6.39/6.60 Support added by some1" "\n"
        "\t"    "6.61 Support added by qwikrazor87" "\n" "\n"
        
        "Web:" "\n"
        "\t"    "https://lolhax.org" "\n" "\n"
        , DOWNGRADER_VER, __DATE__, __TIME__);

#ifdef HBL_SUKKIRI    
    /* Clear html param to 0 */
    memset(&html_param, 0, sizeof(pspUtilityHtmlViewerParam));
    
    /* set enough params in html viewer to get through to module loading */
    html_param.base.size = sizeof(pspUtilityHtmlViewerParam);
    html_param.base.accessThread = 0xF;
    
    /* call sceUtilityHtmlViewerInitStart to load the htmlviewer_utility.prx which imports sceutility/scepower exploit */
    res = sceUtilityHtmlViewerInitStart(&html_param);
    
    /* check error */
    if (res < 0)
    {
        /* this could be an HBL resolving issue... */
        ErrorExit(5000, "Error 0x%08X starting htmlviewer\n", res);
    }
    
    /* wait a second for htmlviewer to get loaded */
    sceKernelDelayThread(1 * 1000 * 1000);
#endif
    
    /* check firmware*/
    printf("Checking firmware... ");
    
    /* do the kernel exploit */
    doKernelExploit();
    
    /* printf ok message */
    printf("OK\n");
    
    /* set the devkit */
    g_devkit_version = sceKernelDevkitVersion();
    
    /* get the PSP model */
    int model = execKernelFunction(getModel);
    int true_model = model;
    
    /* check for real model if it claims it is a 04g (can be 09g) */
    if (model == 3)
    {
        /* get the baryon */
        u32 baryon = execKernelFunction(getBaryon);
        
        /* now get the determinating model */
        u32 det_model = (baryon >> 16) & 0xFF;
        
        /* now check if it is within range */
        if (det_model >= 0x2E && det_model < 0x30)
        {
            /* it's a 09g (or a sneaky 07g...) */
            if ((baryon >> 24) == 1)
            {
                /* 07g!! */
                true_model = 6;
            }
            else
            {
                /* 09g */
                true_model = 8;
            }
        }
    }
    
    /* display model */
    printf("Your PSP reports model %02ig.\n", model+1);
    
    /* check if real != true */
    if (true_model != model)
    {
        /* display */
        printf("Your PSP is originally a %02ig model.\n", true_model + 1);
        ErrorExit(10000, "Due to the experimental nature of the whole 09g to 04g downgrade, functionality to change firmware is prohibited through this program.");
    }
    
    /* delay the thread */
    sceKernelDelayThread(5*1000*1000);
    
    /* check for 09g, we treat this as a 04g */
    if(model == 8)
    {
        model = 3;
    }
    
    /* check for unsupported model */
    if (model != 0 &&            /* PSP PHAT */
        model != 1 &&            /* PSP SLIM */
        model != 2 &&            /* PSP 3000 */
        model != 3 &&            /* PSP 4000 */
        model != 4 &&            /* PSPgo */
        model != 10            /* PSP E-1000 (Street) */
    )
    {
        /* unsupported */
        ErrorExit(5000, "PSP %02ig not supported.\n", model+1);
    }
    
    /* check for pspgo */
    if (model == 4)
    {
        printf("\n" "Your PSPgo will require deletion of the [Resume Game] feature. Proceed? (X = Yes, R = No)\n");
        
        while (1)
        {
            sceCtrlPeekBufferPositive(&pad_data, 1);
            
            /* filter out previous buttons */
            cur_buttons = pad_data.Buttons & ~prev_buttons;
            prev_buttons = pad_data.Buttons;
            
            /* check for cross */
            if (cur_buttons & PSP_CTRL_CROSS)
            {
                break;
            }
            
            else if (cur_buttons & PSP_CTRL_RTRIGGER)
            {
                ErrorExit(5000, "Exiting in 5 seconds.\n");
            }
        }
        
        /* delete resume game */
        if (execKernelFunction(delete_resume_game) < 0)
        {
            /* ERROR */
            ErrorExit(5000, "Error deleting [Resume Game]. Exiting for safety reasons.\n");
        }
    }
    
    int isInfinity = !(infGetVersion() & 0x80000000);
    
    if (isInfinity)
    {
        printf("\n" "Your PSP is running Infinity and reflashing is slightly more risky. Proceed? (X = Yes, R = No)\n");
        
        while (1)
        {
            sceCtrlPeekBufferPositive(&pad_data, 1);
            
            /* filter out previous buttons */
            cur_buttons = pad_data.Buttons & ~prev_buttons;
            prev_buttons = pad_data.Buttons;
            
            /* check for cross */
            if (cur_buttons & PSP_CTRL_CROSS)
            {
                break;
            }
            
            else if (cur_buttons & PSP_CTRL_RTRIGGER)
            {
                ErrorExit(5000, "Exiting in 5 seconds.\n");
            }
        }
    }
    
    /* get the updater version */
    u32 upd_ver = get_updater_version(model == 4);

    if ((model == 10) && (upd_ver < 0x660)) {
        printf("This app does not support downgrading a PSP 11g below 6.60.\n");
        ErrorExit(5000, "Exiting in 5 seconds.\n");
    }
    
    /* do confirmation stuff */
    printf("Will attempt to Downgrade: %X.%X -> %X.%X.\n", (g_devkit_version >> 24) & 0xF, ((g_devkit_version >> 12) & 0xF0) | ((g_devkit_version >> 8) & 0xF), (upd_ver >> 8) & 0xF, upd_ver & 0xFF);
    printf("X to continue, R to exit.\n");
    
    /* get button */
    while (1)
    {
        sceCtrlPeekBufferPositive(&pad_data, 1);

        /* filter out previous buttons */
        cur_buttons = pad_data.Buttons & ~prev_buttons;
        prev_buttons = pad_data.Buttons;
        
        /* check for cross */
        if (cur_buttons & PSP_CTRL_CROSS)
        {
            break;
        }
        
        else if (cur_buttons & PSP_CTRL_RTRIGGER)
        {
            ErrorExit(5000, "Exiting in 5 seconds.\n");
        }
    }
    
    /* clear screen */
    pspDebugScreenClear();
    
    /* update should be OK, go for it */
    printf("By running this application and launching the SCE updater you accept all responsibility of any damage, temporary or permament, that may occur when using this application. This application has been tested with no loss of functionality or any damage to the system, however  it cannot be guaranteed to be completely safe." "\n" "BY RUNNING THIS APPLICATION YOU ACCEPT ALL THE RISK INVOLVED.\n\n" "Press X to start SCE updater. Press R to exit\n");
    
    while (1)
    {
        sceCtrlPeekBufferPositive(&pad_data, 1);

        /* filter out previous buttons */
        cur_buttons = pad_data.Buttons & ~prev_buttons;
        prev_buttons = pad_data.Buttons;
        
        /* check for cross */
        if (cur_buttons & PSP_CTRL_CROSS)
        {
            break;
        }
        
        else if (cur_buttons & PSP_CTRL_RTRIGGER)
        {
            ErrorExit(5000, "Exiting in 5 seconds.\n");
        }
    }

    printf("OK, good for launch\n");
    
    /* go go go go go */
    res = execKernelFunction(launch_updater);
    
    printf("loading SCE updater failed = 0x%08X\n", res);
    sceKernelDelayThread(5 *1000*1000);
    sceKernelExitGame();
    return 0;
}


================================================
FILE: src/patch_table.h
================================================
/*
	Downgrade Launcher -> patch_table.h -> Provide API documentation and definitions for the table patching
	by Davee
	
	01/01/2011
*/
#ifndef __PATCH_TABLE_H__
#define __PATCH_TABLE_H__

#include "utils.h"

typedef struct
{
	u32 devkit;
	u32 new_updater_check[5];
	u32 updater_decrypt_call;
	u32 updater_decrypt_func;
	u32 prologue_module_func;
	u32 prologue_module_call;
	u32 memlmd_call[2];
	u32 memlmd_stub[2];
} PatchTable;

PatchTable g_patch_table[] =
{
	{ 
		FIRMWARE_VERSION_631, 
		{ 0x0D78, 0x0D78, 0x0D78, 0x0D78, 0x0D78, },
		
		/* for 05g mesgled */
		0x6B44, //mesgled updater decrypt call
		0x83E8, //mesgled updater decrypt func
		
		0x8138, //prologue func
		0x705C, //prologue call
		
		{ 0x6930, 0x6954 }, //memlmd calls
		{ 0x8398, 0x8378 }, //memlmd stubs
	},
	
	{
		FIRMWARE_VERSION_635, 
		{ 0x0D78, 0x0D78, 0x0D78, 0x0D78, 0x0D78, },
		
		/* for 05g mesgled */
		0x5EB8, //mesgled updater decrypt call
		0x7B58, //mesgled updater decrypt func
		
		0x8134, //prologue func
		0x7058, //prologue call
		
		{ 0x5CA4, 0x5CC8 }, //memlmd calls
		{ 0x7B08, 0x7AE8 }, //memlmd stubs
	},
	
	{
		FIRMWARE_VERSION_638, 
		{ 0x0D78, 0x0D78, 0x0D78, 0x0D78, 0x0D78, },
		
		/* for 05g mesgled */
		0x5EB8, //mesgled updater decrypt call
		0x7B58, //mesgled updater decrypt func
		
		0x8134, //prologue func
		0x7058, //prologue call
		
		{ 0x5CA4, 0x5CC8 }, //memlmd calls
		{ 0x7B08, 0x7AE8 }, //memlmd stubs
	},
	
	{
		FIRMWARE_VERSION_639, 
		{ 0x0D78, 0x0D78, 0x0D78, 0x0D78, 0x0D78, },
		
		/* for 05g mesgled */
		0x5EB8, //mesgled updater decrypt call
		0x7B58, //mesgled updater decrypt func
		
		0x8130, //prologue func
		0x7054, //prologue call
		
		{ 0x5CA4, 0x5CC8 }, //memlmd calls
		{ 0x7B08, 0x7AE8 }, //memlmd stubs
	},
	
	{
		FIRMWARE_VERSION_660, 
		{ 0x0B24, 0x0B24, 0x0B24, 0x0B24, 0x0B24, },
		
		/* for 05g mesgled */
		0x5B84, //mesgled updater decrypt call
		0x78AC, //mesgled updater decrypt func
		
		0x8124, //prologue func
		0x7048, //prologue call
		
		{ 0x5970, 0x5994 }, //memlmd calls
		{ 0x783C, 0x7824 }, //memlmd stubs
	},

	{
		FIRMWARE_VERSION_661,
		{ 0x0B24, 0x0B24, 0x0B24, 0x0B24, 0x0B24, },
		
		/* for 05g mesgled */
		0x5B84, //mesgled updater decrypt call
		0x78AC, //mesgled updater decrypt func
		
		0x8124, //prologue func
		0x7048, //prologue call
		
		{ 0x5970, 0x5994 }, //memlmd calls
		{ 0x783C, 0x7824 }, //memlmd stubs
	},
};

#define PATCH_TABLE_ADDR_START	(0x88FC0000)

#endif /* __PATCH_TABLE_H__ */


================================================
FILE: src/rebootex.c
================================================
/*
	Downgrade Launcher -> rebootex.c -> Provide patches to the Sony reboot.bin to insert our downgrade controller
	by Davee
	
	28/12/2010
*/

#include <pspkernel.h>
#include <pspsysmem_kernel.h>

#include <stdio.h>
#include <string.h>

#include "utils.h"
#include "rebootex.h"
#include "patch_table.h"
#include "kernel_land.h"

#include "downgrade_ctrl.h"
#include "downgrade660_ctrl.h"

/* global variables */
u32 g_module_seek = 0;
u32 g_module_opened = 0;
void *g_module = NULL;
u32 g_devkit_version = 0;

/* function pointers */
int (* sceBootLfatOpen)(char *path) = NULL;
int (* sceBootLfatRead)(void *data, int size) = NULL;
int (* sceBootLfatClose)(void) = NULL;

u32 (* sceKernelCheckPspConfig)(void *btcnf_data, u32 size, int flag) = NULL;

int (* DecryptExecutable)(void *buffer, int size, int *outsize) = NULL;
int (* VerifySigncheck)(void *buffer, int size) = NULL;

/* The Sony Reboot */
int (* sceReboot)(void *reboot_param, void *exec_param, int api, int initial_rnd) = (void *)0x88600000;

int sceBootLfatOpenPatched(char *path)
{
	/* check the path for our virtual module */
	if (strcmp(path, "/chrono/strange.charm") == 0)
	{
		/* set seek to 0 and set to opened and return success */
		g_module_seek = 0;
		g_module_opened = 1;
		
		return 0;
	}

	/* return original function */
	return sceBootLfatOpen(path);
}

int sceBootLfatReadPatched(void *data, int size)
{
	/* check if the module is virtually opened */
	if (g_module_opened)
	{
		/* get the remaining size */
		u32 remain = size_downgrade_ctrl - g_module_seek;
		
		/* now do some math to calculate how much we will copy (as read is done in 32KiB chunks) */
		remain = (remain < (32 << 10)) ? (remain) : (32 << 10);
		
		/* copy over data */
		memcpy(data, downgrade_ctrl + g_module_seek, remain);
		
		/* increment the seek */
		g_module_seek += remain;
		
		/* returned copied size */
		return remain;
	}

	/* return the read data */
	return sceBootLfatRead(data, size);
}

int sceBootLfatReadPatched660(void *data, int size)
{
	/* check if the module is virtually opened */
	if (g_module_opened)
	{
		/* get the remaining size */
		u32 remain = size_downgrade660_ctrl - g_module_seek;
		
		/* now do some math to calculate how much we will copy (as read is done in 32KiB chunks) */
		remain = (remain < (32 << 10)) ? (remain) : (32 << 10);
		
		/* copy over data */
		memcpy(data, downgrade660_ctrl + g_module_seek, remain);
		
		/* increment the seek */
		g_module_seek += remain;
		
		/* returned copied size */
		return remain;
	}

	/* return the read data */
	return sceBootLfatRead(data, size);
}

int sceBootLfatClosePatched(void)
{
	/* check if the module is virtually opened */
	if (g_module_opened)
	{
		/* it is, interally close and return success */
		g_module_opened = 0;
		return 0;
	}

	/* return the original */
	return sceBootLfatClose();
}

/* BTCNF INJECION CODE BY BUBBLETUNE (bubbletune.x-fusion.co.uk) */
int InsertModuleBtcnf(char *new_mod, char *before_mod, BtcnfHeader *header, int *size, u16 flags)
{
	/* cast and declare our local variables */
	int i, j;
	ModeEntry *modes = (ModeEntry *)((u32)header + header->modestart);
	ModuleEntry *modules = (ModuleEntry *)((u32)header + header->modulestart);
	char *names = (char *)((u32)header + header->modnamestart);
	int len = strlen(new_mod) + 1;

	/* loop through the modules */
	for (i = 0; i < header->nmodules; i++)
	{
		/* if we find the module we want to insert before */
		if (memcmp(names + modules[i].stroffset, before_mod, strlen(before_mod) + 1) == 0)
		{
			/* found it! lets move the the whole section so we can fit another entry*/
			memmove(modules + i + 1, modules + i, (*size)-header->modulestart-(i*sizeof(ModuleEntry)));
			
			/* update all the header variables */
			header->modnamestart += sizeof(ModuleEntry);
			header->modnameend += sizeof(ModuleEntry);
			*size += sizeof(ModuleEntry);
			header->nmodules++;
			
			/* add the new information */
			modules[i].stroffset = header->modnameend-header->modnamestart;
			modules[i].flags = flags;
			
			/* copy the string over :P */
			memcpy((char *)header + header->modnameend, new_mod, len);
			
			/* update the new size and the header modname end */
			*size += len;
			header->modnameend += len;
			
			/* change the modes */
			for (j = 0; j < header->nmodes; j++)
			{
				modes[j].searchstart = 0;
				modes[j].maxsearch++;
			}
			
			/* return success */
			return 0;
		}
	}
	
	/* return fail */
	return -1;
}

u32 sceKernelCheckPspConfigPatched(void *btcnf_data, u32 size, int flag)
{
	/* cast our variables and declare */
	BtcnfHeader *header = (BtcnfHeader *)btcnf_data;
	
	/* decrypt the btcnf so we have the decrypted version */
	int nsize = sceKernelCheckPspConfig(btcnf_data, size, flag);
	
	/* check the signature is valid */
	if (header->signature == 0x0F803001)
	{
		/* insert the module path into the config */
		InsertModuleBtcnf("/chrono/strange.charm", "/kd/init.prx", btcnf_data, &nsize, (BOOTLOAD_VSH | BOOTLOAD_GAME | BOOTLOAD_POPS | BOOTLOAD_UPDATER | BOOTLOAD_UMDEMU | BOOTLOAD_MLNAPP));
	}
	
	/* return the new size */
	return nsize;
}

int DecryptExecutablePatched(void *header, int size, int *outsize)
{
	/* check for decryption tag */
	if (_lw((u32)header + 0x130) == 0x626F6F42)
	{
		*outsize = _lw((u32)header + 0xB0);
		memmove(header, header + 0x150, *outsize);
		return 0;
	}
	
	/* return the real decryption code */
	return DecryptExecutable(header, size, outsize);
}

int VerifySigncheckPatched(void *buffer, int size)
{
	int i;
	/* loop through the signcheck */
	for (i = 0; i < 0x58; i++)
	{
		/* if byte is 0 then call the signcheck removal */
		if (((u8 *)buffer)[0xD4 + i])
		{
			/* remove signcheck */
			return VerifySigncheck(buffer, size);
		}
	}
	
	/* return success :D */
	return 0;
}

int LoadCoreModuleStart631(int (* module_bootstart)(u32 argsize, void *argp), void *argp)
{
	/* get text_addr by substituting from module_bootstart address */
	u32 text_addr = ((u32)module_bootstart) - 0xBC4;
	
	/* assign our function pointers */
	DecryptExecutable = (void *)(text_addr + 0x8398);
	VerifySigncheck = (void *)(text_addr + 0x8378);
	
	/* patch the calls to the decryption */
	MAKE_CALL(text_addr + 0x6930, DecryptExecutablePatched);
	
	/* patch calls to the unsigncheck routines */
	MAKE_CALL(text_addr + 0x6954, VerifySigncheckPatched);
	
	KClearCaches();
    
	/* call the loadcore bootstart */
	return module_bootstart(8, argp);
}

int LoadCoreModuleStart635(int (* module_bootstart)(u32 argsize, void *argp), void *argp)
{
	/* get text_addr by substituting from module_bootstart address */
	u32 text_addr = ((u32)module_bootstart) - 0xBBC;
	
	/* assign our function pointers */
	DecryptExecutable = (void *)(text_addr + 0x7B08);
	VerifySigncheck = (void *)(text_addr + 0x7AE8);
	
	/* patch the calls to the decryption */
	MAKE_CALL(text_addr + 0x5CA4, DecryptExecutablePatched);
	
	/* patch calls to the unsigncheck routines */
	MAKE_CALL(text_addr + 0x5CC8, VerifySigncheckPatched);
	
	KClearCaches();
    
	/* call the loadcore bootstart */
	return module_bootstart(8, argp);
}

int LoadCoreModuleStart638(int (* module_bootstart)(u32 argsize, void *argp), void *argp)
{
	/* get text_addr by substituting from module_bootstart address */
	u32 text_addr = ((u32)module_bootstart) - 0xBBC;
	
	/* assign our function pointers */
	DecryptExecutable = (void *)(text_addr + 0x7B08);
	VerifySigncheck = (void *)(text_addr + 0x7AE8);
	
	/* patch the calls to the decryption */
	MAKE_CALL(text_addr + 0x5CA4, DecryptExecutablePatched);
	
	/* patch calls to the unsigncheck routines */
	MAKE_CALL(text_addr + 0x5CC8, VerifySigncheckPatched);
	
	KClearCaches();
    
	/* call the loadcore bootstart */
	return module_bootstart(8, argp);
}

int LoadCoreModuleStart660(int (* module_bootstart)(u32 argsize, void *argp), void *argp)
{
	/* get text_addr by substituting from module_bootstart address */
	u32 text_addr = ((u32)module_bootstart) - 0xAF8;
	
	/* assign our function pointers */
	DecryptExecutable = (void *)(text_addr + 0x783C);
	VerifySigncheck = (void *)(text_addr + 0x7824);
	
	/* patch the calls to the decryption */
	MAKE_CALL(text_addr + 0x5970, DecryptExecutablePatched);
	
	/* patch calls to the unsigncheck routines */
	MAKE_CALL(text_addr + 0x5994, VerifySigncheckPatched);
	
	KClearCaches();
	/* call the loadcore bootstart */
	return module_bootstart(8, argp);
}


int RebootEntryPatched(void *reboot_param, void *exec_param, u32 api, u32 initial_rnd)
{
	u32 model = _lw((u32)reboot_param + 44);
	
	if(model == 6 || model == 8)
	{
		model = 3;
	}
	
	/* Copy the patch table */
	_sw(sizeof(g_patch_table)/sizeof(PatchTable), PATCH_TABLE_ADDR_START);
	memcpy((void *)(PATCH_TABLE_ADDR_START + 4), g_patch_table, sizeof(g_patch_table));
	
	/* check the devkit */
	if (g_devkit_version == FIRMWARE_VERSION_631)
	{
		/* lets fixup our executable */
		_sw(TAG_631, (u32)downgrade_ctrl + 0xD0);
		_sw(MODULE_ID_TAG, (u32)downgrade_ctrl + 0x130);
		
		/* model specific patches */
		switch (model)
		{
			case 0:
			{
				/* link our function pointers */
				sceBootLfatOpen = (void *)0x88608624;
				sceBootLfatRead = (void *)0x88608798;
				sceBootLfatClose = (void *)0x8860873C;
				
				/* lets patch the IO drivers */
				MAKE_CALL(0x88602764, sceBootLfatOpenPatched);
				MAKE_CALL(0x886027D4, sceBootLfatReadPatched);
				MAKE_CALL(0x88602800, sceBootLfatClosePatched);
				
				/* link our function pointers */
				sceKernelCheckPspConfig = (void *)0x8860588C;
				
				/* patch the pspbtcnf.bin decryption */
				MAKE_CALL(0x88607348, sceKernelCheckPspConfigPatched);
				
				/* force removeByDebugSection success */
				_sw(0x03E00008, 0x8860389C);
				_sw(0x24020001, 0x886038A0);
				
				/* prevent sceBootLfatfsMount failing */
				_sw(0x00000000, 0x8860275C);
				
				/* prevent this lseek failure */
				_sw(0x00000000, 0x886027B0);
				_sw(0x00000000, 0x886027C8);
				
				/* btcnf module hash check */
				_sw(0x00000000, 0x88607648);
				
				/* patch loadcore.prx module_start */
				_sw(0x02202021, 0x88605758);
				MAKE_JUMP(0x88605760, LoadCoreModuleStart631);
				
				break;
			}
			
			case 1:
			case 2:
			case 3:
			case 4:
			{
				/* link our function pointers */
				sceBootLfatOpen = (void *)0x886086F0;
				sceBootLfatRead = (void *)0x88608864;
				sceBootLfatClose = (void *)0x88608808;
				
				/* lets patch the IO drivers */
				MAKE_CALL(0x88602834, sceBootLfatOpenPatched);
				MAKE_CALL(0x886028A4, sceBootLfatReadPatched);
				MAKE_CALL(0x886028D0, sceBootLfatClosePatched);	
				
				/* link our function pointers */
				sceKernelCheckPspConfig = (void *)0x8860595C;
				
				/* patch the pspbtcnf.bin decryption */
				MAKE_CALL(0x88607438, sceKernelCheckPspConfigPatched);
				
				/* force removeByDebugSection success */
				_sw(0x03E00008, 0x8860396C);
				_sw(0x24020001, 0x88603970);
				
				/* prevent sceBootLfatfsMount failing */
				_sw(0x00000000, 0x8860282C);
				
				/* prevent this lseek failure */
				_sw(0x00000000, 0x88602880);
				_sw(0x00000000, 0x88602898);
				
				/* btcnf module hash check */
				_sw(0x00000000, 0x88607714);
				
				/* patch loadcore.prx module_start */
				_sw(0x02202021, 0x88605828);
				MAKE_JUMP(0x88605830, LoadCoreModuleStart631);
				
				break;
			}
		}
	}
	
	/* check the devkit */
	else if (g_devkit_version == FIRMWARE_VERSION_635)
	{
		/* lets fixup our executable */
		_sw(TAG_635, (u32)downgrade_ctrl + 0xD0);
		_sw(MODULE_ID_TAG, (u32)downgrade_ctrl + 0x130);
		
		/* model specific patches */
		switch (model)
		{
			case 0:
			{
				/* link our function pointers */
				sceBootLfatOpen = (void *)0x88608624;
				sceBootLfatRead = (void *)0x88608798;
				sceBootLfatClose = (void *)0x8860873C;
				
				/* lets patch the IO drivers */
				MAKE_CALL(0x88602764, sceBootLfatOpenPatched);
				MAKE_CALL(0x886027D4, sceBootLfatReadPatched);
				MAKE_CALL(0x88602800, sceBootLfatClosePatched);
				
				/* link our function pointers */
				sceKernelCheckPspConfig = (void *)0x8860588C;
				
				/* patch the pspbtcnf.bin decryption */
				MAKE_CALL(0x88607348, sceKernelCheckPspConfigPatched);
				
				/* force removeByDebugSection success */
				_sw(0x03E00008, 0x8860389C);
				_sw(0x24020001, 0x886038A0);
				
				/* prevent sceBootLfatfsMount failing */
				_sw(0x00000000, 0x8860275C);
				
				/* prevent this lseek failure */
				_sw(0x00000000, 0x886027B0);
				_sw(0x00000000, 0x886027C8);
				
				/* btcnf module hash check */
				_sw(0x00000000, 0x88607648);
				
				/* patch loadcore.prx module_start */
				_sw(0x02202021, 0x88605758);
				MAKE_JUMP(0x88605760, LoadCoreModuleStart635);
				
				break;
			}
			
			case 1:		
			case 2:
			case 3:
			case 4:
			{
				/* link our function pointers */
				sceBootLfatOpen = (void *)0x886086F0;
				sceBootLfatRead = (void *)0x88608864;
				sceBootLfatClose = (void *)0x88608808;
				
				/* lets patch the IO drivers */
				MAKE_CALL(0x88602834, sceBootLfatOpenPatched);
				MAKE_CALL(0x886028A4, sceBootLfatReadPatched);
				MAKE_CALL(0x886028D0, sceBootLfatClosePatched);	
				
				/* link our function pointers */
				sceKernelCheckPspConfig = (void *)0x8860595C;
				
				/* patch the pspbtcnf.bin decryption */
				MAKE_CALL(0x88607438, sceKernelCheckPspConfigPatched);
				
				/* force removeByDebugSection success */
				_sw(0x03E00008, 0x8860396C);
				_sw(0x24020001, 0x88603970);
				
				/* prevent sceBootLfatfsMount failing */
				_sw(0x00000000, 0x8860282C);
				
				/* prevent this lseek failure */
				_sw(0x00000000, 0x88602880);
				_sw(0x00000000, 0x88602898);
				
				/* btcnf module hash check */
				_sw(0x00000000, 0x88607714);
				
				/* patch loadcore.prx module_start */
				_sw(0x02202021, 0x88605828);
				MAKE_JUMP(0x88605830, LoadCoreModuleStart635);
				break;
			}
		}
	}
	
	/* check the devkit */
	else if (g_devkit_version == FIRMWARE_VERSION_638)
	{
		/* lets fixup our executable */
		_sw(TAG_638, (u32)downgrade_ctrl + 0xD0);
		_sw(MODULE_ID_TAG, (u32)downgrade_ctrl + 0x130);
		
		/* model specific patches */
		switch (model)
		{
			case 0:
			{
				/* link our function pointers */
				sceBootLfatOpen = (void *)0x88608250;
				sceBootLfatRead = (void *)0x886083C4;
				sceBootLfatClose = (void *)0x88608368;
				
				/* lets patch the IO drivers */
				MAKE_CALL(0x88602768, sceBootLfatOpenPatched);
				MAKE_CALL(0x886027D8, sceBootLfatReadPatched);
				MAKE_CALL(0x88602804, sceBootLfatClosePatched);
				
				/* link our function pointers */
				sceKernelCheckPspConfig = (void *)0x8860569C;
				
				/* patch the pspbtcnf.bin decryption */
				MAKE_CALL(0x8860711C, sceKernelCheckPspConfigPatched);
				
				/* force removeByDebugSection success */
				_sw(0x03E00008, 0x88603848);
				_sw(0x24020001, 0x8860384C);
				
				/* prevent sceBootLfatfsMount failing */
				_sw(0x00000000, 0x88602760);
				
				/* prevent this lseek failure */
				_sw(0x00000000, 0x886027B4);
				_sw(0x00000000, 0x886027CC);
				
				/* btcnf module hash check */
				_sw(0x00000000, 0x886073B4);
				
				/* patch loadcore.prx module_start */
				_sw(0x02202021, 0x88605588);
				MAKE_JUMP(0x88605590, LoadCoreModuleStart638);
				
				break;
			}
			
			case 1:		
			case 2:
			case 3:
			case 4:
			{
				/* link our function pointers */
				sceBootLfatOpen = (void *)0x88608320;
				sceBootLfatRead = (void *)0x88608494;
				sceBootLfatClose = (void *)0x88608438;
				
				/* lets patch the IO drivers */
				MAKE_CALL(0x88602838, sceBootLfatOpenPatched);
				MAKE_CALL(0x886028A8, sceBootLfatReadPatched);
				MAKE_CALL(0x886028D4, sceBootLfatClosePatched);	
				
				/* link our function pointers */
				sceKernelCheckPspConfig = (void *)0x8860576C;
				
				/* patch the pspbtcnf.bin decryption */
				MAKE_CALL(0x886071EC, sceKernelCheckPspConfigPatched);
				
				/* force removeByDebugSection success */
				_sw(0x03E00008, 0x88603918);
				_sw(0x24020001, 0x8860391C);
				
				/* prevent sceBootLfatfsMount failing */
				_sw(0x00000000, 0x88602830);
				
				/* prevent this lseek failure */
				_sw(0x00000000, 0x88602884);
				_sw(0x00000000, 0x8860289C);
				
				/* btcnf module hash check */
				_sw(0x00000000, 0x88607484);
				
				/* patch loadcore.prx module_start */
				_sw(0x02202021, 0x88605658);
				MAKE_JUMP(0x88605660, LoadCoreModuleStart638);
				break;
			}
		}
	}
	
	else if (g_devkit_version == FIRMWARE_VERSION_639)
	{
		/* lets fixup our executable */
		_sw(TAG_638, (u32)downgrade_ctrl + 0xD0);
		_sw(MODULE_ID_TAG, (u32)downgrade_ctrl + 0x130);
		
		/* model specific patches */
		switch (model)
		{
			case 0:
			{
				/* link our function pointers */
				sceBootLfatOpen = (void *)0x88608250;
				sceBootLfatRead = (void *)0x886083C4;
				sceBootLfatClose = (void *)0x88608368;
				
				/* lets patch the IO drivers */
				MAKE_CALL(0x88602768, sceBootLfatOpenPatched);
				MAKE_CALL(0x886027D8, sceBootLfatReadPatched);
				MAKE_CALL(0x88602804, sceBootLfatClosePatched);
				
				/* link our function pointers */
				sceKernelCheckPspConfig = (void *)0x8860569C;
				
				/* patch the pspbtcnf.bin decryption */
				MAKE_CALL(0x8860711C, sceKernelCheckPspConfigPatched);
				
				/* force removeByDebugSection success */
				_sw(0x03E00008, 0x88603848);
				_sw(0x24020001, 0x8860384C);
				
				/* prevent sceBootLfatfsMount failing */
				_sw(0x00000000, 0x88602760);
				
				/* prevent this lseek failure */
				_sw(0x00000000, 0x886027B4);
				_sw(0x00000000, 0x886027CC);
				
				/* btcnf module hash check */
				_sw(0x00000000, 0x886073B4);
				
				/* patch loadcore.prx module_start */
				_sw(0x02202021, 0x88605588);
				MAKE_JUMP(0x88605590, LoadCoreModuleStart638);
				
				break;
			}
			
			case 1:		
			case 2:
			case 3:
			case 4:
			{
				/* link our function pointers */
				sceBootLfatOpen = (void *)0x88608320;
				sceBootLfatRead = (void *)0x88608494;
				sceBootLfatClose = (void *)0x88608438;
				
				/* lets patch the IO drivers */
				MAKE_CALL(0x88602838, sceBootLfatOpenPatched);
				MAKE_CALL(0x886028A8, sceBootLfatReadPatched);
				MAKE_CALL(0x886028D4, sceBootLfatClosePatched);	
				
				/* link our function pointers */
				sceKernelCheckPspConfig = (void *)0x8860576C;
				
				/* patch the pspbtcnf.bin decryption */
				MAKE_CALL(0x886071EC, sceKernelCheckPspConfigPatched);
				
				/* force removeByDebugSection success */
				_sw(0x03E00008, 0x88603918);
				_sw(0x24020001, 0x8860391C);
				
				/* prevent sceBootLfatfsMount failing */
				_sw(0x00000000, 0x88602830);
				
				/* prevent this lseek failure */
				_sw(0x00000000, 0x88602884);
				_sw(0x00000000, 0x8860289C);
				
				/* btcnf module hash check */
				_sw(0x00000000, 0x88607484);
				
				/* patch loadcore.prx module_start */
				_sw(0x02202021, 0x88605658);
				MAKE_JUMP(0x88605660, LoadCoreModuleStart638);
				break;
			}
		}
	}
	
	else if ((g_devkit_version == FIRMWARE_VERSION_660) || (g_devkit_version == FIRMWARE_VERSION_661))
	{
		/* lets fixup our executable */
		_sw(TAG_660, (u32)downgrade660_ctrl + 0xD0);
		_sw(MODULE_ID_TAG, (u32)downgrade660_ctrl + 0x130);
		
		/* model specific patches */
		switch (model)
		{
			case 0:
			{

				/* link our function pointers */
				if (g_devkit_version == FIRMWARE_VERSION_660) {
					sceBootLfatOpen = (void *)0x8860822C;
					sceBootLfatRead = (void *)0x886083A0;
					sceBootLfatClose = (void *)0x88608344;
				} else if (g_devkit_version == FIRMWARE_VERSION_661) {
					sceBootLfatOpen = (void *)0x8860B6C0;
					sceBootLfatRead = (void *)0x8860AD58;
					sceBootLfatClose = (void *)0x88609C78;
				}
				
				/* lets patch the IO drivers */
				MAKE_CALL(0x886027C4, sceBootLfatOpenPatched);
				MAKE_CALL(0x88602834, sceBootLfatReadPatched660);
				MAKE_CALL(0x88602860, sceBootLfatClosePatched);
				
				/* link our function pointers */
				sceKernelCheckPspConfig = (void *)0x8860574C;
				
				/* patch the pspbtcnf.bin decryption */
				MAKE_CALL(0x886070F8, sceKernelCheckPspConfigPatched);
				
				/* force removeByDebugSection success */
				_sw(0x03E00008, 0x88603880);
				_sw(0x24020001, 0x88603884);
				
				/* prevent sceBootLfatfsMount failing */
				_sw(0x00000000, 0x886027BC);
				
				/* prevent this lseek failure */
				_sw(0x00000000, 0x88602810);
				_sw(0x00000000, 0x88602828);
				
				/* btcnf module hash check */
				_sw(0x00000000, 0x88607390);
				
				/* patch loadcore.prx module_start */
				_sw(0x02202021, 0x88605638);
				MAKE_JUMP(0x88605640, LoadCoreModuleStart660);
				
				break;
			}
			
			case 1:
			case 2:
			case 3:
			case 4:
			case 10:
			{
				/* link our function pointers */
				if (g_devkit_version == FIRMWARE_VERSION_660) {
					sceBootLfatOpen = (void *)0x886082EC;
					sceBootLfatRead = (void *)0x88608460;
					sceBootLfatClose = (void *)0x88608404;
				} else if (g_devkit_version == FIRMWARE_VERSION_661) {
					sceBootLfatOpen = (void *)0x8860B780;
					sceBootLfatRead = (void *)0x8860AE18;
					sceBootLfatClose = (void *)0x88609D38;
				}
				
				/* lets patch the IO drivers */
				MAKE_CALL(0x8860288C, sceBootLfatOpenPatched);
				MAKE_CALL(0x886028FC, sceBootLfatReadPatched660);
				MAKE_CALL(0x88602928, sceBootLfatClosePatched);	
				
				/* link our function pointers */
				sceKernelCheckPspConfig = (void *)0x8860580C;
				
				/* patch the pspbtcnf.bin decryption */
				MAKE_CALL(0x886071B8, sceKernelCheckPspConfigPatched);
				
				/* force removeByDebugSection success */
				_sw(0x03E00008, 0x88603948);
				_sw(0x24020001, 0x8860394C);
				
				/* prevent sceBootLfatfsMount failing */
				_sw(0x00000000, 0x88602884);
				
				/* prevent this lseek failure */
				_sw(0x00000000, 0x886028D8);
				_sw(0x00000000, 0x886028F0);
				
				/* btcnf module hash check */
				_sw(0x00000000, 0x88607450);
				
				/* patch loadcore.prx module_start */
				_sw(0x02202021, 0x886056F8);
				MAKE_JUMP(0x88605700, LoadCoreModuleStart660);
				break;
			}
		}
	}
	
	/* Clear the caches */
	KClearCaches();
	
	/* lets start the reboot process */
	return sceReboot(reboot_param, exec_param, api, initial_rnd);
}


================================================
FILE: src/rebootex.h
================================================
/*
	Downgrade Launcher -> rebootex.h -> Provide API documentation and definitions for the reboot patching processes
	by Davee
	
	28/12/2010
*/
#ifndef __REBOOTEX_H__
#define __REBOOTEX_H__

#define TAG_631			(0x4C9484F0)
#define TAG_635			(0x4C9484F0)
#define TAG_638			(0x4C948AF0)
#define TAG_639			(0x4C948AF0)
#define TAG_660			(0x4C9494F0)
#define MODULE_ID_TAG	(0x626F6F42)

/* variables */
extern u32 g_devkit_version;

/* Functions */
int RebootEntryPatched(void *reboot_param, void *exec_param, u32 api, u32 initial_rnd);

typedef struct BtcnfHeader
{
	u32 signature; // 0
	u32 devkit;		// 4
	u32 unknown[2];  // 8
	u32 modestart;  // 0x10
	int nmodes;  // 0x14
	u32 unknown2[2];  // 0x18
	u32 modulestart; // 0x20
	int nmodules;  // 0x24
	u32 unknown3[2]; // 0x28
	u32 modnamestart; // 0x30
	u32 modnameend; // 0x34
	u32 unknown4[2]; // 0x38
}  __attribute__((packed)) BtcnfHeader;

typedef struct ModeEntry
{
	u16 maxsearch;
	u16 searchstart; //
	int mode1;
	int mode2;
	int reserved[5];
} __attribute__((packed)) ModeEntry;

typedef struct ModuleEntry
{
	u32 stroffset; // 0
	int reserved; // 4
	u16 flags; // 8
	u8 loadmode; // 10
	u8 signcheck; // 11
	int reserved2; // 12
	u8  hash[0x10]; // 16
} __attribute__((packed)) ModuleEntry; // 32

#endif /* __REBOOTEX_H__ */


================================================
FILE: src/utils.c
================================================
/*
	Downgrade Launcher -> utils.c -> Responsible for providing common utilities
	by Davee
	
	28/12/2010
*/

#include <pspkernel.h>
#include <pspsysmem_kernel.h>

#include <stdio.h>
#include <string.h>
#include <stdarg.h>

#include "utils.h"
#include "kernel_land.h"

void sceKernelIcacheInvalidateAll(void);

int isValidUserAddress(void *addr)
{
	return ((u32)((u32)addr - 0x08800000) < (24 << 20)) ? (1) : (0);
}

void KClearCaches(void)
{
	/* Clear the Icache */
	asm("\
	.word 0x40088000; .word 0x24091000; .word 0x7D081240;\
	.word 0x01094804; .word 0x4080E000; .word 0x4080E800;\
	.word 0x00004021; .word 0xBD010000; .word 0xBD030000;\
	.word 0x25080040; .word 0x1509FFFC; .word 0x00000000;\
	"::);
	
	/* Clear the dcache */
	asm("\
	.word 0x40088000; .word 0x24090800; .word 0x7D081180;\
	.word 0x01094804; .word 0x00004021; .word 0xBD140000;\
	.word 0xBD140000; .word 0x25080040; .word 0x1509FFFC;\
	.word 0x00000000; .word 0x0000000F; .word 0x00000000;\
	"::);
}

void ClearCaches(void)
{
	sceKernelDcacheWritebackInvalidateAll();
	sceKernelIcacheInvalidateAll();
}

u32 FindProc(char *modname, char *lib, u32 nid)
{
	/* declare our local vars */
	int i = 0, u;
	
	/* find the module */
	SceModule2 *mod = pspKernelFindModuleByName(modname);
	
	/* if no mod, error */
	if (mod == NULL)
	{
		return 0;
	}
	
	/* get the entry info */
	u32 entry_size = mod->ent_size;
	u32 entry_start = (u32)mod->ent_top;
	
	/* scan through the export list */
	while (i < entry_size)
	{
		/* point to the entry */
		SceLibraryEntryTable *entry = (SceLibraryEntryTable *)(entry_start + i);
		
		/* if there is a libname, check if it's the libname we want */
		if (entry->libname && (strcmp((char *)entry->libname, lib) == 0))
		{
			/* now lets scan through the stubs for our nid */
			u32 *table = entry->entrytable;
			int total = entry->stubcount + entry->vstubcount;
			
			/* if there is nids, lets continue */
			if (total > 0)
			{ 
				/* scan through the nidtable */
				for (u = 0; u < total; u++)
				{ 
					/* check if its the nid we're looking for */
					if (table[u] == nid)
					{
						/* our nid, let return the address */
						return table[u + total];
					}
				} 
			} 	
		}
		
		/* update entry counter */
		i += (entry->len << 2);
	}
	
	/* lib not found ): */
	return 0;
}

void ErrorExit(int millisecs, char *fmt, ...)
{
	va_list list;
	char msg[256];	

	/* collate args into string */
	va_start(list, fmt);
	vsprintf(msg, fmt, list);
	va_end(list);

	/* print string */
	printf(msg);
	
	sceKernelDelayThread(millisecs*1000);
	sceKernelExitGame();
}


================================================
FILE: src/utils.h
================================================
/*
	Downgrade Launcher -> utils.h -> Provide documentation for standard proceedures
	by Davee
	
	28/12/2010
*/
#ifndef __UTILS__H__
#define __UTILS__H__

#define MAKE_JUMP(a, f)					_sw(0x08000000 | (((u32)(f) >> 2)  & 0x03ffffff), a)
#define MAKE_CALL(a, f)					_sw(0x0C000000 | (((u32)(f) >> 2)  & 0x03ffffff), a)
#define REDIRECT_FUNCTION(a, f) 		{ u32 address = a; _sw(0x08000000 | (((u32)(f) >> 2)  & 0x03ffffff), address);  _sw(0, address+4); }
#define MAKE_RELATIVE_BRANCH(a, f, t)	_sw((0x10000000 | ((((f - a) >> 2) - 1) & 0xFFFF)), a + t)

#define FIRMWARE_VERSION_631	(0x06030110)
#define FIRMWARE_VERSION_635	(0x06030510)
#define FIRMWARE_VERSION_638	(0x06030810)
#define FIRMWARE_VERSION_639	(0x06030910)
#define FIRMWARE_VERSION_660	(0x06060010)
#define FIRMWARE_VERSION_661	(0x06060110)

#define PSPGO_UPDATER_PATH	"ef0:/PSP/GAME/UPDATE/EBOOT.PBP"
#define OTHER_UPDATER_PATH	"ms0:/PSP/GAME/UPDATE/EBOOT.PBP"

#define printf pspDebugScreenPrintf

/**
	Clears both the instruction and data caches USER MODE ONLY
*/
void ClearCaches(void);

/**
	Clears both the instruction and data caches KERNEL MODE ONLY
*/
void KClearCaches(void);

/**
	checks whether or not a pointer is a valid pointer into userspace
	
	@param addr: the pointer to check
	@return 1 on valid else 0 on invalid
*/
int isValidUserAddress(void *addr);

/**
	Find an export within the system
	
	@param modname: the name of the module containing the export
	@param libname: the library the export belongs to
	@param nid: the nid of the export
	
	@return the address of export else 0 on error
*/
u32 FindProc(char *modname, char *lib, u32 nid);

/**
	Display an error and exit game
	
	@param millisecs: the amount of time to delay before exiting (in milliseconds)
	@param fmt: a formattable string with args to follow
*/
void ErrorExit(int millisecs, char *fmt, ...);

/* internal prototypes */
void clearIcache(void);

#endif /* __UTILS__H__ */
Download .txt
gitextract_gl9obiy7/

├── README.md
└── src/
    ├── Makefile
    ├── Makefile.hbl
    ├── Makefile.signed
    ├── downgrade660_ctrl/
    │   ├── 660mapfile.txt
    │   ├── Makefile
    │   ├── decrypt.c
    │   ├── decrypt.h
    │   ├── exports.exp
    │   ├── extra_stubs.S
    │   ├── main.c
    │   ├── patch_table.c
    │   ├── patch_table.h
    │   ├── pspdecrypt.c
    │   ├── utils.c
    │   └── utils.h
    ├── downgrade_ctrl/
    │   ├── 631mapfile.txt
    │   ├── Makefile
    │   ├── decrypt.c
    │   ├── decrypt.h
    │   ├── exports.exp
    │   ├── extra_stubs.S
    │   ├── main.c
    │   ├── patch_table.c
    │   ├── patch_table.h
    │   ├── pspdecrypt.c
    │   ├── utils.c
    │   └── utils.h
    ├── extra_stubs.S
    ├── extras.S
    ├── include/
    │   ├── libinfinity.h
    │   └── systemctrl.h
    ├── kernel_exploit.c
    ├── kernel_exploit.h
    ├── kernel_land.c
    ├── kernel_land.h
    ├── lib/
    │   └── libpspsystemctrl_kernel.a
    ├── libasm/
    │   ├── libinfinityKernel.S
    │   └── libinfinityUser.S
    ├── main.c
    ├── patch_table.h
    ├── rebootex.c
    ├── rebootex.h
    ├── utils.c
    └── utils.h
Download .txt
SYMBOL INDEX (134 symbols across 24 files)

FILE: src/downgrade660_ctrl/decrypt.c
  function sceResmgr_9DC14891_patched (line 23) | int sceResmgr_9DC14891_patched(void *data, u32 datasize, u32 *outsize)
  function PatchMesgled (line 47) | void PatchMesgled(u32 text_addr)
  function sceMesgLed_driver_81F72B1F_patched (line 63) | int sceMesgLed_driver_81F72B1F_patched(void *exec, u32 exec_size, u32 *o...
  function memlmd_7CF1CD3E_patched (line 79) | int memlmd_7CF1CD3E_patched(void *exec, u32 exec_size, u32 *out_size)

FILE: src/downgrade660_ctrl/decrypt.h
  type mesgled_keys_struct (line 27) | typedef struct
  type PSP_Header2 (line 33) | typedef struct
  type KIRK_CMD_HEADER (line 68) | typedef struct

FILE: src/downgrade660_ctrl/main.c
  type SfoHeader (line 27) | typedef struct __attribute__((packed))
  type SfoEntry (line 36) | typedef struct __attribute__((packed))
  function ApplyFirmware (line 50) | int ApplyFirmware(SceModule2 *mod)
  function SceUID (line 185) | SceUID sceIoOpenPatched(char *file, u32 mode, u32 mode2)
  function sceIoGetstatPatched (line 201) | int sceIoGetstatPatched(char *file, SceIoStat *stat)
  function sceUtilsBufferCopyWithRangePatched (line 215) | int sceUtilsBufferCopyWithRangePatched(void *dst, u32 dst_size, void *sr...
  function sceLflashFatfmtStartFatfmtPatched (line 253) | int sceLflashFatfmtStartFatfmtPatched(int argc, char *argv[])
  function OnModuleStart (line 261) | int OnModuleStart(SceModule2 *mod)
  function PrologueModulePatched (line 320) | int PrologueModulePatched(void *modmgr_param, SceModule2 *mod)
  function PatchModuleManager (line 336) | static void PatchModuleManager(void)
  function PatchLoadCore (line 349) | static void PatchLoadCore(void)
  function module_start (line 370) | int module_start(SceSize argsize, void *argp)

FILE: src/downgrade660_ctrl/patch_table.c
  function CopyPatchTable (line 19) | int CopyPatchTable(PatchTable *dst_table, void *_src_table, u32 devkit)

FILE: src/downgrade660_ctrl/patch_table.h
  type PatchTable (line 10) | typedef struct

FILE: src/downgrade660_ctrl/pspdecrypt.c
  type TAG_INFO (line 134) | typedef struct
  function TAG_INFO (line 161) | static TAG_INFO const* GetTagInfo(u32 tagFind)
  function ExtraV2Mangle (line 170) | static void ExtraV2Mangle(u8* buffer1, u8 codeExtra)
  function Scramble (line 189) | static int Scramble(u32 *buf, u32 size, u32 code)
  function DecryptPRX1 (line 204) | static int DecryptPRX1(const u8* pbIn, u8* pbOut, int cbTotal, u32 tag)
  type TAG_INFO2 (line 653) | typedef struct
  function TAG_INFO2 (line 735) | static TAG_INFO2 *GetTagInfo2(u32 tagFind)
  function DecryptPRX2 (line 750) | static int DecryptPRX2(const u8 *inbuf, u8 *outbuf, u32 size, u32 tag)
  function pspDecryptPRX (line 907) | int pspDecryptPRX(u8 *data, u32 size, u32 *out_size)

FILE: src/downgrade660_ctrl/utils.c
  function ClearCaches (line 17) | void ClearCaches(void)
  function u32 (line 23) | u32 FindFunc(const char *modname, const char *lib, u32 nid)
  function PatchSyscall (line 78) | void PatchSyscall(u32 addr, void *newaddr)

FILE: src/downgrade_ctrl/decrypt.c
  function sceResmgr_9DC14891_patched (line 23) | int sceResmgr_9DC14891_patched(void *data, u32 datasize, u32 *outsize)
  function PatchMesgled (line 47) | void PatchMesgled(u32 text_addr)
  function sceMesgLed_driver_81F72B1F_patched (line 63) | int sceMesgLed_driver_81F72B1F_patched(void *exec, u32 exec_size, u32 *o...
  function memlmd_7CF1CD3E_patched (line 79) | int memlmd_7CF1CD3E_patched(void *exec, u32 exec_size, u32 *out_size)

FILE: src/downgrade_ctrl/decrypt.h
  type mesgled_keys_struct (line 27) | typedef struct
  type PSP_Header2 (line 33) | typedef struct
  type KIRK_CMD_HEADER (line 68) | typedef struct

FILE: src/downgrade_ctrl/main.c
  type SfoHeader (line 27) | typedef struct __attribute__((packed))
  type SfoEntry (line 36) | typedef struct __attribute__((packed))
  function ApplyFirmware (line 50) | int ApplyFirmware(void)
  function SceUID (line 172) | SceUID sceIoOpenPatched(char *file, u32 mode, u32 mode2)
  function sceIoGetstatPatched (line 188) | int sceIoGetstatPatched(char *file, SceIoStat *stat)
  function sceUtilsBufferCopyWithRangePatched (line 202) | int sceUtilsBufferCopyWithRangePatched(void *dst, u32 dst_size, void *sr...
  function sceLflashFatfmtStartFatfmtPatched (line 240) | int sceLflashFatfmtStartFatfmtPatched(int argc, char *argv[])
  function OnModuleStart (line 248) | int OnModuleStart(SceModule *mod)
  function PrologueModulePatched (line 307) | int PrologueModulePatched(void *modmgr_param, SceModule *mod)
  function PatchModuleManager (line 323) | static void PatchModuleManager(void)
  function PatchLoadCore (line 336) | static void PatchLoadCore(void)
  function module_start (line 357) | int module_start(SceSize argsize, void *argp)

FILE: src/downgrade_ctrl/patch_table.c
  function CopyPatchTable (line 19) | int CopyPatchTable(PatchTable *dst_table, void *_src_table, u32 devkit)

FILE: src/downgrade_ctrl/patch_table.h
  type PatchTable (line 10) | typedef struct

FILE: src/downgrade_ctrl/pspdecrypt.c
  type TAG_INFO (line 134) | typedef struct
  function TAG_INFO (line 161) | static TAG_INFO const* GetTagInfo(u32 tagFind)
  function ExtraV2Mangle (line 170) | static void ExtraV2Mangle(u8* buffer1, u8 codeExtra)
  function Scramble (line 189) | static int Scramble(u32 *buf, u32 size, u32 code)
  function DecryptPRX1 (line 204) | static int DecryptPRX1(const u8* pbIn, u8* pbOut, int cbTotal, u32 tag)
  type TAG_INFO2 (line 643) | typedef struct
  function TAG_INFO2 (line 725) | static TAG_INFO2 *GetTagInfo2(u32 tagFind)
  function DecryptPRX2 (line 740) | static int DecryptPRX2(const u8 *inbuf, u8 *outbuf, u32 size, u32 tag)
  function pspDecryptPRX (line 897) | int pspDecryptPRX(u8 *data, u32 size, u32 *out_size)

FILE: src/downgrade_ctrl/utils.c
  function ClearCaches (line 17) | void ClearCaches(void)
  function u32 (line 23) | u32 FindFunc(const char *modname, const char *lib, u32 nid)
  function PatchSyscall (line 78) | void PatchSyscall(u32 addr, void *newaddr)

FILE: src/include/systemctrl.h
  type BootLoadFlags (line 9) | enum BootLoadFlags
  type SceKernelLoadExecVSHParam (line 27) | struct SceKernelLoadExecVSHParam
  type SceKernelLoadExecVSHParam (line 38) | struct SceKernelLoadExecVSHParam
  type SceKernelLoadExecVSHParam (line 49) | struct SceKernelLoadExecVSHParam
  type SceKernelLoadExecVSHParam (line 60) | struct SceKernelLoadExecVSHParam
  type SceKernelLoadExecVSHParam (line 71) | struct SceKernelLoadExecVSHParam
  type SceKernelLoadExecVSHParam (line 72) | struct SceKernelLoadExecVSHParam
  type SceKernelLoadExecVSHParam (line 83) | struct SceKernelLoadExecVSHParam
  type SceKernelLoadExecVSHParam (line 94) | struct SceKernelLoadExecVSHParam
  type SceKernelLoadExecVSHParam (line 106) | struct SceKernelLoadExecVSHParam
  type SceModule2 (line 206) | typedef struct SceModule2 {

FILE: src/kernel_exploit.c
  function DummyCallback (line 35) | int DummyCallback(void)
  function pre_kernel (line 40) | int pre_kernel(int (* kfunc)(void))
  function repairKernel631 (line 99) | int repairKernel631(void)
  function repairKernel635 (line 119) | int repairKernel635(void)
  function execKernelFunction631 (line 139) | int execKernelFunction631(void *kfunc)
  function execKernelFunction635 (line 153) | int execKernelFunction635(void *kfunc)
  function execKernelFunction660 (line 167) | int execKernelFunction660(void *kfunc)
  function execKernelFunction (line 181) | int execKernelFunction(void *kfunc)
  function SceLibraryStubTable (line 208) | SceLibraryStubTable *findLibraryByName(char *libname, u32 address)
  function doKernelExploit631 (line 258) | void doKernelExploit631(void)
  function doKernelExploit635 (line 333) | void doKernelExploit635(void)
  function nopOut (line 408) | int nopOut()
  function doKernelExploit638 (line 414) | void doKernelExploit638(void)
  function doKernelExploit660 (line 447) | void doKernelExploit660(void)
  function doKernelExploit (line 478) | void doKernelExploit(void)

FILE: src/kernel_exploit.h
  type sceKernelIfHandleParam (line 14) | typedef struct sceKernelIfHandleParam

FILE: src/kernel_land.c
  type SceKernelLoadExecVSHParam (line 24) | struct SceKernelLoadExecVSHParam
  type SceKernelLoadExecVSHParam (line 25) | struct SceKernelLoadExecVSHParam
  type SceKernelLoadExecVSHParam (line 31) | struct SceKernelLoadExecVSHParam
  function u32 (line 33) | u32 getBaryon(void)
  function getModel (line 44) | int getModel(void)
  function delete_resume_game (line 50) | int delete_resume_game(void)
  function patch_loadexec_phat (line 90) | int patch_loadexec_phat(void)
  function patch_loadexec_slim (line 117) | int patch_loadexec_slim(void)
  function patch_loadexec_3000 (line 144) | int patch_loadexec_3000(void)
  function patch_loadexec_4000 (line 171) | int patch_loadexec_4000(void)
  function patch_loadexec_pspgo (line 198) | int patch_loadexec_pspgo(void)
  function patch_loadexec_street (line 227) | int patch_loadexec_street(void)
  function launch_updater (line 246) | int launch_updater(void)

FILE: src/kernel_land.h
  type SceKernelLoadExecVSHParam (line 21) | struct SceKernelLoadExecVSHParam
  type SceKernelLoadExecVSHParam (line 22) | struct SceKernelLoadExecVSHParam

FILE: src/main.c
  type SfoHeader (line 33) | typedef struct __attribute__((packed))
  type SfoEntry (line 42) | typedef struct __attribute__((packed))
  function u32 (line 53) | u32 get_updater_version(u32 is_pspgo)
  function main (line 120) | int main(int argc, char *argv[])

FILE: src/patch_table.h
  type PatchTable (line 12) | typedef struct

FILE: src/rebootex.c
  function sceBootLfatOpenPatched (line 41) | int sceBootLfatOpenPatched(char *path)
  function sceBootLfatReadPatched (line 57) | int sceBootLfatReadPatched(void *data, int size)
  function sceBootLfatReadPatched660 (line 82) | int sceBootLfatReadPatched660(void *data, int size)
  function sceBootLfatClosePatched (line 107) | int sceBootLfatClosePatched(void)
  function InsertModuleBtcnf (line 122) | int InsertModuleBtcnf(char *new_mod, char *before_mod, BtcnfHeader *head...
  function u32 (line 173) | u32 sceKernelCheckPspConfigPatched(void *btcnf_data, u32 size, int flag)
  function DecryptExecutablePatched (line 192) | int DecryptExecutablePatched(void *header, int size, int *outsize)
  function VerifySigncheckPatched (line 206) | int VerifySigncheckPatched(void *buffer, int size)
  function LoadCoreModuleStart631 (line 224) | int LoadCoreModuleStart631(int (* module_bootstart)(u32 argsize, void *a...
  function LoadCoreModuleStart635 (line 245) | int LoadCoreModuleStart635(int (* module_bootstart)(u32 argsize, void *a...
  function LoadCoreModuleStart638 (line 266) | int LoadCoreModuleStart638(int (* module_bootstart)(u32 argsize, void *a...
  function LoadCoreModuleStart660 (line 287) | int LoadCoreModuleStart660(int (* module_bootstart)(u32 argsize, void *a...
  function RebootEntryPatched (line 308) | int RebootEntryPatched(void *reboot_param, void *exec_param, u32 api, u3...

FILE: src/rebootex.h
  type BtcnfHeader (line 23) | typedef struct BtcnfHeader
  type ModeEntry (line 39) | typedef struct ModeEntry
  type ModuleEntry (line 48) | typedef struct ModuleEntry

FILE: src/utils.c
  function isValidUserAddress (line 20) | int isValidUserAddress(void *addr)
  function KClearCaches (line 25) | void KClearCaches(void)
  function ClearCaches (line 44) | void ClearCaches(void)
  function u32 (line 50) | u32 FindProc(char *modname, char *lib, u32 nid)
  function ErrorExit (line 105) | void ErrorExit(int millisecs, char *fmt, ...)
Condensed preview — 45 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (191K chars).
[
  {
    "path": "README.md",
    "chars": 1284,
    "preview": "# Chronoswitch Downgrader\nChronoswitch is a downgrader for the Playstation Portable (PSP).\n\n## Installation\nDownload and"
  },
  {
    "path": "src/Makefile",
    "chars": 882,
    "preview": "all: clean clean_prx signed\n\nclean: clean_prx\n\tmake -f Makefile.signed clean\n\nclean_prx:\n\tmake -C downgrade_ctrl -f Make"
  },
  {
    "path": "src/Makefile.hbl",
    "chars": 444,
    "preview": "TARGET = downgrader\nOBJS = main.o kernel_exploit.o kernel_land.o rebootex.o utils.o extras.o extra_stubs.o\n\nINCDIR = ../"
  },
  {
    "path": "src/Makefile.signed",
    "chars": 657,
    "preview": "release: all\n\tbin/prxEncrypter $(TARGET).prx\n\tpack-pbp $(EXTRA_TARGETS) PARAM.SFO icon0.png NULL NULL NULL NULL data.psp"
  },
  {
    "path": "src/downgrade660_ctrl/660mapfile.txt",
    "chars": 434,
    "preview": "@SysMemForKernel\n0x55A40B2C:0xC4EEAF20 //NID RESOLVED\n0x9697CD32:0x13F4A0DE //NID RESOLVED\n0xB2C7AA36:0x83B5226D //NID R"
  },
  {
    "path": "src/downgrade660_ctrl/Makefile",
    "chars": 615,
    "preview": "release: all\n\tpsp-fixup-imports -m $(PSP_FW_VERSION)mapfile.txt $(TARGET).prx\n\tpsp-packer $(TARGET).prx\n\tbin2c $(TARGET)"
  },
  {
    "path": "src/downgrade660_ctrl/decrypt.c",
    "chars": 2343,
    "preview": "/*\n\tDowngrade Control -> decrypt.c -> Responsible for decryption patches and hooks\n\tby Davee\n\t\n\t31/12/2010\n*/\n\n#include "
  },
  {
    "path": "src/downgrade660_ctrl/decrypt.h",
    "chars": 1998,
    "preview": "/*\n\tDowngrade Control -> decrypt.h -> Provide API documentation and definitions\n\tby Davee\n\t\n\t31/12/2010\n*/\n#ifndef __DEC"
  },
  {
    "path": "src/downgrade660_ctrl/exports.exp",
    "chars": 343,
    "preview": "# Define the exports for the prx\nPSP_BEGIN_EXPORTS\n\n# These four lines are mandatory (although you can add other functio"
  },
  {
    "path": "src/downgrade660_ctrl/extra_stubs.S",
    "chars": 636,
    "preview": "\t.set noreorder\n\n#include \"pspstub.s\"\n\t\n\tSTUB_START\t\"sceResmgr_driver\",0x00090011,0x00010005\n\tSTUB_FUNC\t0x9DC14891,sceRe"
  },
  {
    "path": "src/downgrade660_ctrl/main.c",
    "chars": 10183,
    "preview": "/*\n\tDowngrade Control -> Restore kernel patches and enforce updater launch\n\tby Davee\n\t\n\t31/12/2010\n*/\n\n#include <pspkern"
  },
  {
    "path": "src/downgrade660_ctrl/patch_table.c",
    "chars": 874,
    "preview": "/*\n\tDowngrade Control -> patch_table.c -> Responsible for searching and handling patch tables\n\tby Davee\n\t\n\t01/01/2011\n*/"
  },
  {
    "path": "src/downgrade660_ctrl/patch_table.h",
    "chars": 718,
    "preview": "/*\n\tDowngrade Control -> patch_table.h -> Provide API documentation and definitions for the table patching\n\tby Davee\n\t\n\t"
  },
  {
    "path": "src/downgrade660_ctrl/pspdecrypt.c",
    "chars": 24042,
    "preview": "#include <pspsdk.h>\n#include <pspkernel.h>\n#include <pspdebug.h>\n//#include <pspcrypt.h>\n#include <psputilsforkernel.h>\n"
  },
  {
    "path": "src/downgrade660_ctrl/utils.c",
    "chars": 2034,
    "preview": "/*\n\tDowngrade Control -> utils.c -> Responsible for providing common utilities interfacing the kernel\n\tby Davee\n\t\n\t30/12"
  },
  {
    "path": "src/downgrade660_ctrl/utils.h",
    "chars": 1794,
    "preview": "/*\n\tDowngrade Control -> utils.h -> Provide API documentation and definitions for utilities\n\tby Davee\n\t\n\t30/12/2010\n*/\n#"
  },
  {
    "path": "src/downgrade_ctrl/631mapfile.txt",
    "chars": 434,
    "preview": "@SysMemForKernel\n0x55A40B2C:0xF5E82409 //NID RESOLVED\n0x9697CD32:0xE10F21CF //NID RESOLVED\n0xB2C7AA36:0x00E9A04A //NID R"
  },
  {
    "path": "src/downgrade_ctrl/Makefile",
    "chars": 612,
    "preview": "release: all\n\tpsp-fixup-imports -m $(PSP_FW_VERSION)mapfile.txt $(TARGET).prx\n\tpsp-packer $(TARGET).prx\n\tbin2c $(TARGET)"
  },
  {
    "path": "src/downgrade_ctrl/decrypt.c",
    "chars": 2343,
    "preview": "/*\n\tDowngrade Control -> decrypt.c -> Responsible for decryption patches and hooks\n\tby Davee\n\t\n\t31/12/2010\n*/\n\n#include "
  },
  {
    "path": "src/downgrade_ctrl/decrypt.h",
    "chars": 1998,
    "preview": "/*\n\tDowngrade Control -> decrypt.h -> Provide API documentation and definitions\n\tby Davee\n\t\n\t31/12/2010\n*/\n#ifndef __DEC"
  },
  {
    "path": "src/downgrade_ctrl/exports.exp",
    "chars": 343,
    "preview": "# Define the exports for the prx\nPSP_BEGIN_EXPORTS\n\n# These four lines are mandatory (although you can add other functio"
  },
  {
    "path": "src/downgrade_ctrl/extra_stubs.S",
    "chars": 518,
    "preview": "\t.set noreorder\n\n#include \"pspstub.s\"\n\t\n\tSTUB_START\t\"sceResmgr_driver\",0x00090011,0x00010005\n\tSTUB_FUNC\t0x9DC14891,sceRe"
  },
  {
    "path": "src/downgrade_ctrl/main.c",
    "chars": 9723,
    "preview": "/*\n\tDowngrade Control -> Restore kernel patches and enforce updater launch\n\tby Davee\n\t\n\t31/12/2010\n*/\n\n#include <pspkern"
  },
  {
    "path": "src/downgrade_ctrl/patch_table.c",
    "chars": 874,
    "preview": "/*\n\tDowngrade Control -> patch_table.c -> Responsible for searching and handling patch tables\n\tby Davee\n\t\n\t01/01/2011\n*/"
  },
  {
    "path": "src/downgrade_ctrl/patch_table.h",
    "chars": 718,
    "preview": "/*\n\tDowngrade Control -> patch_table.h -> Provide API documentation and definitions for the table patching\n\tby Davee\n\t\n\t"
  },
  {
    "path": "src/downgrade_ctrl/pspdecrypt.c",
    "chars": 23848,
    "preview": "#include <pspsdk.h>\n#include <pspkernel.h>\n#include <pspdebug.h>\n//#include <pspcrypt.h>\n#include <psputilsforkernel.h>\n"
  },
  {
    "path": "src/downgrade_ctrl/utils.c",
    "chars": 2019,
    "preview": "/*\n\tDowngrade Control -> utils.c -> Responsible for providing common utilities interfacing the kernel\n\tby Davee\n\t\n\t30/12"
  },
  {
    "path": "src/downgrade_ctrl/utils.h",
    "chars": 1487,
    "preview": "/*\n\tDowngrade Control -> utils.h -> Provide API documentation and definitions for utilities\n\tby Davee\n\t\n\t30/12/2010\n*/\n#"
  },
  {
    "path": "src/extra_stubs.S",
    "chars": 595,
    "preview": "\t.set noreorder\n\n#include \"pspstub.s\"\n\n\tSTUB_START \"sceNetInet\",0x00090000,0x00010005\n\tSTUB_FUNC  0x1BDF5D13,sceNetInetI"
  },
  {
    "path": "src/extras.S",
    "chars": 262,
    "preview": "\t.set noreorder\n\n.global getPowerAddress\n.ent    getPowerAddress\ngetPowerAddress:\n\taddiu $sp, $sp, -8\n\tsw $ra, 0($sp)\n\tm"
  },
  {
    "path": "src/include/libinfinity.h",
    "chars": 1939,
    "preview": "/*\n\nCopyright (C) 2015, David \"Davee\" Morgan\n\nPermission is hereby granted, free of charge, to any person obtaining a\nco"
  },
  {
    "path": "src/include/systemctrl.h",
    "chars": 11353,
    "preview": "#ifndef __SCTRLLIBRARY_H__\n#define __SCTRLLIBRARY_H__\n\n#include <pspsdk.h>\n#include <pspkernel.h>\n#include <psploadexec_"
  },
  {
    "path": "src/kernel_exploit.c",
    "chars": 15064,
    "preview": "/*\n\tDowngrade Launcher -> kernel_exploit.c -> Responsible for doin' sum epik lolhax on teh kurnal\n\tby Davee\n\t\n\t28/12/201"
  },
  {
    "path": "src/kernel_exploit.h",
    "chars": 662,
    "preview": "/*\n\tDowngrade Launcher -> patch_table.h -> Provide API documentation and definitions for the table patching\n\tby Davee\n\t\n"
  },
  {
    "path": "src/kernel_land.c",
    "chars": 8185,
    "preview": "/*\n\tDowngrade Launcher -> kernel_land.c -> Responsible for containing code access in kernel mode\n\tby Davee\n\t\n\t28/12/2010"
  },
  {
    "path": "src/kernel_land.h",
    "chars": 910,
    "preview": "/*\n\tDowngrade Launcher -> kernel_land.h -> Provide API documentation and definitions for the kernel operations\n\tby Davee"
  },
  {
    "path": "src/libasm/libinfinityKernel.S",
    "chars": 268,
    "preview": ".set noreorder\n\n#include \"pspstub.s\"\n\nSTUB_START \"libinfinityKernel\",0x00090000,0x00040005\nSTUB_FUNC  0x0527FEC1,infGetV"
  },
  {
    "path": "src/libasm/libinfinityUser.S",
    "chars": 266,
    "preview": ".set noreorder\n\n#include \"pspstub.s\"\n\nSTUB_START \"libinfinityUser\",0x40090000,0x00040005\nSTUB_FUNC  0x0527FEC1,infGetVer"
  },
  {
    "path": "src/main.c",
    "chars": 10597,
    "preview": "/*\n    Downgrade Launcher R1\n    by Davee\n    \n    Fin-rev 24/01/2011\n*/\n\n#include <pspkernel.h>\n#include <pspsdk.h>\n#in"
  },
  {
    "path": "src/patch_table.h",
    "chars": 2470,
    "preview": "/*\n\tDowngrade Launcher -> patch_table.h -> Provide API documentation and definitions for the table patching\n\tby Davee\n\t\n"
  },
  {
    "path": "src/rebootex.c",
    "chars": 21990,
    "preview": "/*\n\tDowngrade Launcher -> rebootex.c -> Provide patches to the Sony reboot.bin to insert our downgrade controller\n\tby Da"
  },
  {
    "path": "src/rebootex.h",
    "chars": 1284,
    "preview": "/*\n\tDowngrade Launcher -> rebootex.h -> Provide API documentation and definitions for the reboot patching processes\n\tby "
  },
  {
    "path": "src/utils.c",
    "chars": 2564,
    "preview": "/*\n\tDowngrade Launcher -> utils.c -> Responsible for providing common utilities\n\tby Davee\n\t\n\t28/12/2010\n*/\n\n#include <ps"
  },
  {
    "path": "src/utils.h",
    "chars": 1923,
    "preview": "/*\n\tDowngrade Launcher -> utils.h -> Provide documentation for standard proceedures\n\tby Davee\n\t\n\t28/12/2010\n*/\n#ifndef _"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the DaveeFTW/Chronoswitch GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 45 files (170.4 KB), approximately 72.8k tokens, and a symbol index with 134 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!