diff --git a/Makefile.ps3 b/Makefile.ps3 index 9331c1137f..becf79bee3 100644 --- a/Makefile.ps3 +++ b/Makefile.ps3 @@ -1,61 +1,79 @@ -# Makefile for SSNES PS3. Somewhat generic and avoids using the odd SDK examples. +SSNES_VERSION = "0.9.4.1" + +#which compiler to build with - GCC or SNC +#set to GCC for debug builds for use with debugger +CELL_BUILD_TOOLS = SNC +CELL_SDK ?= /usr/local/cell +CELL_GPU_TYPE = RSX +CELL_PSGL_VERSION = ultra-opt DEBUG = 0 -CELL_BUILD_TOOLS = GCC DOWNLOAD_SHADERS = 1 STRIPPING_ENABLE = 0 HAVE_SSNES_GL = 0 -ifeq ($(shell uname), Linux) - platform := linux - CELL_HOST_PATH = $(CELL_SDK)/host-linux -else - platform := win - CELL_HOST_PATH = $(CELL_SDK)/host-win32 -endif +CONTENT_ID_FULL = UP0001-SSNE10000_00-0000000000000001 +CONTENT_ID = SSNE10000 -ifeq ($(platform),win) - HOST_DIR := host-win32 - CELL_SDK := /c/usr/local/cell/ -else - HOST_DIR := host-linux - CELL_SDK := /usr/local/cell -endif +CELL_MK_DIR ?= $(CELL_SDK)/samples/mk +include $(CELL_MK_DIR)/sdk.makedef.mk -ifeq ($(CELL_BUILD_TOOLS),SNC) -CC = $(CELL_SDK)/$(HOST_DIR)/sn/bin/ps3ppusnc -CXX = $(CC) -LD = $(CELL_SDK)/$(HOST_DIR)/sn/bin/ps3ppuld -else -CC = $(CELL_SDK)/$(HOST_DIR)/ppu/bin/ppu-lv2-gcc -CXX = $(CELL_SDK)/$(HOST_DIR)/ppu/bin/ppu-lv2-g++ -LD = $(CELL_SDK)/$(HOST_DIR)/ppu/bin/ppu-lv2-g++ -endif -STRIP = $(CELL_SDK)/$(HOST_DIR)/ppu/bin/ppu-lv2-strip +PPU_TARGET = ssnes.elf +SALAMANDER_TARGET = ssnes-salamander.elf -PPU_TARGET := ssnes.elf -SALAMANDER_TARGET := ssnes-salamander.elf +EBOOT_PATH = ps3/pkg/USRDIR/EBOOT.BIN +CORE_PATH = ps3/pkg/USRDIR/cores/CORE.SELF LDDIRS = -L. -L$(CELL_SDK)/target/ppu/lib/PSGL/RSX/ultra-opt INCDIRS = -I. -Icommon -MAKE_FSELF_NPDRM = $(CELL_HOST_PATH)/bin/make_fself_npdrm -MAKE_PACKAGE_NPDRM = $(CELL_HOST_PATH)/bin/make_package_npdrm +MAKE_SELF = make_self_npdrm -OBJ = fifo_buffer.o ps3/cellframework2/fileio/file_browser.o ps3/ps3_audio.o ps3/menu.o console/main_wrap.o console/rom_ext.o ps3/ps3_input.o ps3/cellframework2/input/pad_input.o getopt.o ssnes.o driver.o file.o settings.o message.o rewind.o movie.o netplay.o netplay_compat.o gfx/gfx_common.o ps3/ps3_video_psgl.o gfx/shader_cg.o gfx/snes_state.o ups.o bps.o strl.o audio/hermite.o dynamic.o ps3/main.o audio/utils.o conf/config_file.o ps3/image.o +PKG_SCRIPT = ps3/ps3py/pkg.py +PKG_FINALIZE = package_finalize -SALAMANDER_CSRCS = ps3/salamander/main.c conf/config_file.c strl.c +PPU_SRCS = fifo_buffer.c \ + ps3/cellframework2/fileio/file_browser.c \ + ps3/ps3_audio.c \ + ps3/menu.c \ + console/main_wrap.c \ + console/rom_ext.c \ + ps3/ps3_input.c \ + ps3/cellframework2/input/pad_input.c \ + getopt.c \ + ssnes.c \ + driver.c \ + file.c \ + settings.c \ + message.c \ + rewind.c \ + movie.c \ + netplay.c \ + netplay_compat.c \ + gfx/gfx_common.c \ + ps3/ps3_video_psgl.c \ + gfx/shader_cg.c \ + gfx/snes_state.c \ + ups.c \ + bps.c \ + strl.c \ + audio/hermite.c \ + dynamic.c \ + ps3/main.c \ + audio/utils.c \ + conf/config_file.c \ + ps3/image.c ifeq ($(HAVE_SSNES_GL), 1) - DEFINES = -DHAVE_SSNES_GL - GL_LIBS := -lSSNESGL -lSSNESGLcgc +DEFINES = -DHAVE_SSNES_GL +GL_LIBS := -lSSNESGL -lSSNESGLcgc else - GL_LIBS := -lPSGL -lPSGLcgc +GL_LIBS := -L$(CELL_SDK)/target/ppu/lib/PSGL/RSX/ultra-opt -lPSGL -lPSGLcgc endif -LIBS = -ldbgfont $(GL_LIBS) -lcgc -lgcm_cmd -lgcm_sys_stub -lsnes -lresc_stub -lm -lio_stub -lfs_stub -lsysutil_stub -lsysutil_game_stub -lsysutil_screenshot_stub -lsysutil_np_stub -lpngdec_stub -ljpgdec_stub -lsysmodule_stub -laudio_stub -lnet_stub -lpthread +PPU_LDLIBS = -ldbgfont $(GL_LIBS) -lcgc -lgcm_cmd -lgcm_sys_stub -lsnes -lresc_stub -lm -lio_stub -lfs_stub -lsysutil_stub -lsysutil_game_stub -lsysutil_screenshot_stub -lsysutil_np_stub -lpngdec_stub -ljpgdec_stub -lsysmodule_stub -laudio_stub -lnet_stub -lpthread -DEFINES += -DSSNES_CONSOLE -DHAVE_OPENGL=1 -DHAVE_CG=1 -DHAVE_FBO=1 -D__CELLOS_LV2__ -DHAVE_CONFIGFILE=1 -DHAVE_NETPLAY=1 -DHAVE_SOCKET_LEGACY=1 -DPACKAGE_VERSION=\"0.9.4.1\" -DHAVE_SCREENSHOTS_BUILTIN=1 -Dmain=ssnes_main +DEFINES += -DSSNES_CONSOLE -DHAVE_OPENGL=1 -DHAVE_CG=1 -DHAVE_FBO=1 -D__CELLOS_LV2__ -DHAVE_CONFIGFILE=1 -DHAVE_NETPLAY=1 -DHAVE_SOCKET_LEGACY=1 -DPACKAGE_VERSION=\"$(SSNES_VERSION)\" -DHAVE_SCREENSHOTS_BUILTIN=1 -Dmain=ssnes_main ifeq ($(DEBUG), 1) PPU_OPTIMIZE_LV := -O0 -g @@ -63,38 +81,73 @@ else PPU_OPTIMIZE_LV := -O3 -g endif -CFLAGS = $(PPU_OPTIMIZE_LV) $(DEFINES) -CXXFLAGS = $(PPU_OPTIMIZE_LV) $(DEFINES) +PPU_CFLAGS = $(PPU_OPTIMIZE_LV) $(DEFINES) +PPU_CXXFLAGS = $(PPU_OPTIMIZE_LV) $(DEFINES) -all: pkg +EXIST_EBOOT_WILDCARD := $(wildcard $(EBOOT_PATH)) +EXIST_CORE_WILDCARD := $(wildcard $(CORE_PATH)) -$(PPU_TARGET): $(OBJ) - $(LD) -o $@ $(OBJ) $(LDFLAGS) $(LDDIRS) $(LIBS) -ifeq ($(STRIPPING_ENABLE),1) - $(STRIP) $(PPU_TARGET) +EBOOT_EXISTS = 1 +CORE_EXISTS = 1 + +ifneq ($(strip $(EXIST_EBOOT_WILDCARD)),) +EBOOT_EXISTS = 0 endif -%.o: %.c config.h - $(CC) $(INCDIRS) $(CFLAGS) -c -o $@ $< +ifneq ($(strip $(EXIST_CORE_WILDCARD)),) +CORE_EXISTS = 0 +endif -%.o: %.cpp config.h - $(CXX) $(INCDIRS) $(CXXFLAGS) -c -o $@ $< +include $(CELL_MK_DIR)/sdk.target.mk -pkg: $(PPU_TARGET) +.PHONY: create-selfs-npdrm create-npdrm-core create-core create-npdrm-salamander create-npdrm-salamander create-shaders clean-selfs + +create-npdrm-core: + $(MAKE_FSELF_NPDRM) $(PPU_TARGET) $(CORE_PATH) + +create-core: + $(MAKE_SELF) $(PPU_TARGET) $(CORE_PATH) $(CONTENT_ID) + +create-npdrm-salamander: + $(MAKE_FSELF_NPDRM) $(SALAMANDER_TARGET) $(EBOOT_PATH) + +create-salamander: + $(MAKE_SELF) $(SALAMANDER_TARGET) $(EBOOT_PATH) $(CONTENT_ID) + + +create-shaders: ifeq ($(DOWNLOAD_SHADERS),1) - rm -rf ps3/pkg/USRDIR/cores/shaders + $(RM) -rf ps3/pkg/USRDIR/cores/shaders git clone git://github.com/twinaphex/common-shaders.git ps3/pkg/USRDIR/cores/shaders endif - $(MAKE_FSELF_NPDRM) $(PPU_TARGET) ps3/pkg/USRDIR/cores/CORE.SELF - $(CC) -g -L. -ldbgfont -lgcm_cmd -lgcm_sys_stub -lm -lio_stub -lfs_stub -lsysutil_stub -lsysutil_game_stub -lsysutil_np_stub -lsysmodule_stub -lnet_stub $(SALAMANDER_CSRCS) -o $(SALAMANDER_TARGET) - $(MAKE_FSELF_NPDRM) $(SALAMANDER_TARGET) ps3/pkg/USRDIR/EBOOT.BIN + +pkg: $(PPU_TARGET) create-shaders create-salamander-npdrm create-npdrm-core $(MAKE_PACKAGE_NPDRM) ps3/pkg/package.conf ps3/pkg -clean: - rm -f $(SALAMANDER_TARGET) - rm -f $(PPU_TARGET) - rm -f $(OBJ) - rm -f *.pkg +pkg-signed: $(PPU_TARGET) create-shaders create-salamander create-npdrm-core + python2 $(PKG_SCRIPT) --contentid $(CONTENT_ID_FULL) ps3/pkg/ ssnes-ps3-cfw-$(SSNES_VERSION).pkg -.PHONY: all clean pkg +pkg-signed-standalone: $(PPU_TARGET) create-shaders create-core + $(MAKE_SELF) $(PPU_TARGET) $(EBOOT_PATH) $(CONTENT_ID) + python2 $(PKG_SCRIPT) --contentid $(CONTENT_ID_FULL) ps3/pkg/ ssnes-ps3-cfw-$(SSNES_VERSION).pkg +pkg-signed-cfw: $(PPU_TARGET) create-shaders create-salamander create-core + python2 $(PKG_SCRIPT) --contentid $(CONTENT_ID_FULL) ps3/pkg/ ssnes-ps3-cfw-$(SSNES_VERSION)-kmeaw.pkg + $(PKG_FINALIZE) ssnes-ps3-cfw-$(SSNES_VERSION)-kmeaw.pkg + +pkg-signed-cfw-standalone: $(PPU_TARGET) create-shaders create-core + $(MAKE_SELF) $(PPU_TARGET) $(EBOOT_PATH) $(CONTENT_ID) + python2 $(PKG_SCRIPT) --contentid $(CONTENT_ID_FULL) ps3/pkg/ ssnes-ps3-cfw-$(SSNES_VERSION).pkg + $(PKG_FINALIZE) ssnes-ps3-cfw-$(SSNES_VERSION)-kmeaw.pkg + +clean-selfs: +ifeq ($(EBOOT_EXISTS),1) + @echo "WARNING: Couldn't find file to delete: [$(EBOOT_PATH)], skipping this step." +else + rm $(EBOOT_PATH) +endif +ifeq ($(CORE_EXISTS),1) + @echo "WARNING: Couldn't find file to delete: [$(CORE_PATH)], skipping this step." +else + rm $(CORE_PATH) +endif diff --git a/Makefile.ps3.salamander b/Makefile.ps3.salamander new file mode 100644 index 0000000000..aa28346a1c --- /dev/null +++ b/Makefile.ps3.salamander @@ -0,0 +1,43 @@ +CELL_BUILD_TOOLS = SNC +CELL_SDK ?= /usr/local/cell +CELL_GPU_TYPE = RSX +CELL_PSGL_VERSION = opt +HAVE_LOGGER = 0 + +CELL_MK_DIR ?= $(CELL_SDK)/samples/mk +include $(CELL_MK_DIR)/sdk.makedef.mk + +MAKE_SELF = make_self_npdrm +PKG_SCRIPT = ps3/ps3py/pkg.py +PKG_FINALIZE = package_finalize + +STRIP = $(CELL_HOST_PATH)/ppu/bin/ppu-lv2-strip +COPY = cp +MOVE = mv +C = $(CELL_HOST_PATH)/ppu/bin/ppu-lv2-gcc +CC = $(CELL_HOST_PATH)/ppu/bin/ppu-lv2-g++ + +PPU_CFLAGS += -I. -O2 -g -DHAVE_EXITSPAWN_NPDRM +PPU_SRCS = ps3/salamander/main.c strl.c conf/config_file.c + +ifeq ($(HAVE_LOGGER), 1) +PPU_CFLAGS += -DHAVE_LOGGER +PPU_SRCS += ps3/cellframework2/fileio/logger.c +endif + +PPU_TARGET = ssnes-salamander.elf + +ifeq ($(CELL_BUILD_TOOLS),SNC) +PPU_CFLAGS += -Xbranchless=1 -Xfastmath=1 -Xassumecorrectsign=1 -Xassumecorrectalignment=1 \ + -Xunroll=1 -Xautovecreg=1 +PPU_CXXFLAGS += -Xbranchless=1 -Xfastmath=1 -Xassumecorrectsign=1 -Xassumecorrectalignment=1 \ + -Xunroll=1 -Xautovecreg=1 +else +PPU_CFLAGS += -funroll-loops +PPU_CXXFLAGS += -funroll-loops +endif + +PPU_OPTIMIZE_LV := -O2 +PPU_LDLIBS += -lpthread -lm -lnet_stub -lnetctl_stub -lm -ldbgfont_gcm -lgcm_cmd -lgcm_sys_stub -lio_stub -lsysmodule_stub -lsysutil_stub -lsysutil_game_stub -lfs_stub -lsysutil_np_stub + +include $(CELL_MK_DIR)/sdk.target.mk diff --git a/ps3/cellframework2/fileio/logger.c b/ps3/cellframework2/fileio/logger.c new file mode 100644 index 0000000000..0b86fbebac --- /dev/null +++ b/ps3/cellframework2/fileio/logger.c @@ -0,0 +1,128 @@ +/* -- Cellframework Mk.II - Open framework to abstract the common tasks related to + * PS3 application development. + * + * Copyright (C) 2010-2012 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2011-2012 - Daniel De Matteis + * + * Some code herein may be based on code found in BSNES. + * + * SSNES is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SSNES. + * If not, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "logger.h" + +#define PC_DEVELOPMENT_IP_ADDRESS "192.168.1.7" + +static int g_sid; +static int sock; +static struct sockaddr_in target; +static char sendbuf[4096]; + +static int if_up_with(int index) +{ + int timeout_count = 10; + int state; + int ret; + + (void)index; + ret = cellNetCtlInit(); + if (ret < 0) + { + printf("cellNetCtlInit() failed(%x)\n", ret); + return (-1); + } + + for (;;) + { + ret = cellNetCtlGetState(&state); + if (ret < 0) + { + printf("cellNetCtlGetState() failed(%x)\n", ret); + return (-1); + } + if (state == CELL_NET_CTL_STATE_IPObtained) + break; + sys_timer_usleep(500 * 1000); + timeout_count--; + if (index && timeout_count < 0) + { + printf("if_up_with(%d) timeout\n", index); + return (0); + } + } + + sock=socket(AF_INET,SOCK_DGRAM ,0); + + target.sin_family = AF_INET; + target.sin_port = htons(3490); + inet_pton(AF_INET, PC_DEVELOPMENT_IP_ADDRESS, &target.sin_addr); + + return (0); +} + +static int if_down(int sid) +{ + (void)sid; + cellNetCtlTerm(); + return (0); +} + +void logger_init (void) +{ + g_sid = if_up_with(1); +} + +void logger_shutdown (void) +{ + if_down(g_sid); +} + +void net_send(const char *__format,...) +{ + va_list args; + + va_start(args,__format); + vsnprintf(sendbuf,4000,__format, args); + va_end(args); + + int len=strlen(sendbuf); + sendto(sock,sendbuf,len,MSG_DONTWAIT,(const struct sockaddr*)&target,sizeof(target)); +} diff --git a/ps3/cellframework2/fileio/logger.h b/ps3/cellframework2/fileio/logger.h new file mode 100644 index 0000000000..055653f76f --- /dev/null +++ b/ps3/cellframework2/fileio/logger.h @@ -0,0 +1,51 @@ +/* -- Cellframework Mk.II - Open framework to abstract the common tasks related to + * PS3 application development. + * + * Copyright (C) 2010-2012 + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/* SSNES - A Super Nintendo Entertainment System (SNES) Emulator frontend for libsnes. + * Copyright (C) 2010-2012 - Hans-Kristian Arntzen + * Copyright (C) 2011-2012 - Daniel De Matteis + * + * Some code herein may be based on code found in BSNES. + * + * SSNES is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * SSNES is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with SSNES. + * If not, see . + */ + +#ifndef _LOGGER_H_ +#define _LOGGER_H_ + +#define BUFSIZE (64 * 1024) +#define TCPDUMP_FILE (SYS_APP_HOME "/tcpdump.dump") +#define TCPDUMP_STACKSIZE (16 * 1024) +#define TCPDUMP_PRIO (2048) + +void logger_init (void); +void logger_shutdown (void); +void net_send(const char *__format,...); + +#endif diff --git a/ps3/main.c b/ps3/main.c index b1088a8c89..921ffcc800 100644 --- a/ps3/main.c +++ b/ps3/main.c @@ -621,10 +621,10 @@ begin_shutdown: SceNpDrmKey * k_licensee = NULL; int ret = sceNpDrmProcessExitSpawn2(k_licensee, g_settings.libsnes, (const char** const)spawn_argv, NULL, (sys_addr_t)spawn_data, 256, 1000, SYS_PROCESS_PRIMARY_STACK_SIZE_1M); SSNES_LOG("Attempt to load SELF: [%s] (return code: [%x]).\n", g_settings.libsnes, ret); - if(ret == SCE_NP_DRM_ERROR_FORMAT) + if(ret < 0) { SSNES_LOG("SELF file is not of NPDRM type, trying another approach to boot it...\n"); - exitspawn(g_settings.libsnes, spawn_argv, NULL, NULL, 0, 1000, SYS_PROCESS_PRIMARY_STACK_SIZE_1M); + sys_game_process_exitspawn(g_settings.libsnes, NULL, NULL, NULL, 0, 1000, SYS_PROCESS_PRIMARY_STACK_SIZE_1M); } sceNpTerm(); diff --git a/ps3/menu.c b/ps3/menu.c index 07f323e689..4639045faf 100644 --- a/ps3/menu.c +++ b/ps3/menu.c @@ -371,7 +371,7 @@ static void browser_render(filebrowser_t * b) cellDbgFontDraw(); } -static void set_setting_label(menu * menu_obj, int currentsetting) +static void set_setting_label(menu * menu_obj, uint64_t currentsetting) { switch(currentsetting) { @@ -2108,8 +2108,6 @@ void menu_loop(void) g_console.menu_enable = true; - gl_t * gl = g_gl; - menu_reinit_settings(); if(g_console.emulator_initialized) diff --git a/ps3/ps3_video_psgl.c b/ps3/ps3_video_psgl.c index 575fe00960..ff61ce4185 100644 --- a/ps3/ps3_video_psgl.c +++ b/ps3/ps3_video_psgl.c @@ -719,53 +719,6 @@ static bool gl_frame(void *data, const void *frame, unsigned width, unsigned hei return true; } -static void gl_update_resize(void) -{ - gl_t * gl = g_gl; - - if(!gl) - return; - - if (!gl->render_to_tex) - set_viewport(gl, gl->win_width, gl->win_height, false); - else - { - // Check if we have to recreate our FBO textures. - for (int i = 0; i < gl->fbo_pass; i++) - { - // Check proactively since we might suddently get sizes of tex_w width or tex_h height. - if (gl->fbo_rect[i].max_img_width > gl->fbo_rect[i].width || - gl->fbo_rect[i].max_img_height > gl->fbo_rect[i].height) - { - unsigned img_width = gl->fbo_rect[i].max_img_width; - unsigned img_height = gl->fbo_rect[i].max_img_height; - unsigned max = img_width > img_height ? img_width : img_height; - unsigned pow2_size = next_pow2(max); - gl->fbo_rect[i].width = gl->fbo_rect[i].height = pow2_size; - - glBindFramebufferOES(GL_FRAMEBUFFER_OES, gl->fbo[i]); - glBindTexture(GL_TEXTURE_2D, gl->fbo_texture[i]); - glTexImage2D(GL_TEXTURE_2D, - 0, GL_ARGB_SCE, gl->fbo_rect[i].width, gl->fbo_rect[i].height, 0, GL_ARGB_SCE, - GL_UNSIGNED_INT_8_8_8_8, NULL); - - glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, gl->fbo_texture[i], 0); - - GLenum status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES); - if (status != GL_FRAMEBUFFER_COMPLETE_OES) - SSNES_WARN("Failed to reinit FBO texture.\n"); - - SSNES_LOG("Recreating FBO texture #%d: %ux%u\n", i, gl->fbo_rect[i].width, gl->fbo_rect[i].height); - } - } - - // Go back to what we're supposed to do, render to FBO #0 :D - glBindTexture(GL_TEXTURE_2D, gl->texture[gl->tex_index]); - glBindFramebufferOES(GL_FRAMEBUFFER_OES, gl->fbo[0]); - set_viewport(gl, gl->fbo_rect[0].img_width, gl->fbo_rect[0].img_height, true); - } -} - static void psgl_deinit(gl_t *gl) { glFinish(); diff --git a/ps3/ps3py/crypt.c b/ps3/ps3py/crypt.c new file mode 100644 index 0000000000..87a89039ca --- /dev/null +++ b/ps3/ps3py/crypt.c @@ -0,0 +1,97 @@ +#include + +static PyObject *sha1_callback = NULL; + +static void manipulate(uint8_t *key) { + uint64_t temp = key[0x38] << 56| + key[0x39] << 48| + key[0x3a] << 40| + key[0x3b] << 32| + key[0x3c] << 24| + key[0x3d] << 16| + key[0x3e] << 8| + key[0x3f]; + temp++; + key[0x38] = (temp >> 56) & 0xff; + key[0x39] = (temp >> 48) & 0xff; + key[0x3a] = (temp >> 40) & 0xff; + key[0x3b] = (temp >> 32) & 0xff; + key[0x3c] = (temp >> 24) & 0xff; + key[0x3d] = (temp >> 16) & 0xff; + key[0x3e] = (temp >> 8) & 0xff; + key[0x3f] = (temp >> 0) & 0xff; +} + +static PyObject* pkg_crypt(PyObject *self, PyObject *args) { + uint8_t *key, *input, *ret; + int key_length, input_length, length; + int remaining, i, offset=0; + + PyObject *arglist; + PyObject *result; + + if (!PyArg_ParseTuple(args, "s#s#i", &key, &key_length, &input, &input_length, &length)) + return NULL; + ret = malloc(length); + remaining = length; + + while (remaining > 0) { + int bytes_to_dump = remaining; + if (bytes_to_dump > 0x10) + bytes_to_dump = 0x10; + + // outhash = SHA1(listToString(key)[0:0x40]) + uint8_t *outHash; + { + arglist = Py_BuildValue("(s#)", key, 0x40); + result = PyObject_CallObject(sha1_callback, arglist); + Py_DECREF(arglist); + if (!result) return NULL; + int outHash_length; + if (!PyArg_Parse(result, "s#", &outHash, &outHash_length)) return NULL; + } + for(i = 0; i < bytes_to_dump; i++) { + ret[offset] = outHash[i] ^ input[offset]; + offset++; + } + Py_DECREF(result); + manipulate(key); + remaining -= bytes_to_dump; + } + + // Return the encrypted data + PyObject *py_ret = Py_BuildValue("s#", ret, length); + free(ret); + return py_ret; +} + +static PyObject *register_sha1_callback(PyObject *self, PyObject *args) { + PyObject *result = NULL; + PyObject *temp; + + if (PyArg_ParseTuple(args, "O:set_callback", &temp)) { + if (!PyCallable_Check(temp)) { + PyErr_SetString(PyExc_TypeError, "parameter must be callable"); + return NULL; + } + Py_XINCREF(temp); /* Add a reference to new callback */ + Py_XDECREF(sha1_callback); /* Dispose of previous callback */ + sha1_callback = temp; /* Remember new callback */ + /* Boilerplate to return "None" */ + Py_INCREF(Py_None); + result = Py_None; + } + return result; +} + +static PyMethodDef cryptMethods[] = { + {"pkgcrypt", pkg_crypt, METH_VARARGS, "C implementation of pkg.py's crypt function"}, + {"register_sha1_callback", register_sha1_callback, METH_VARARGS, "Register a callback to python's SHA1 function, so we don't have to bother with creating our own implementation."}, + {NULL, NULL, 0, NULL} +}; + +PyMODINIT_FUNC initpkgcrypt(void) { + (void) Py_InitModule("pkgcrypt", cryptMethods); +} + + diff --git a/ps3/ps3py/pkg.py b/ps3/ps3py/pkg.py new file mode 100644 index 0000000000..17cc1aeada --- /dev/null +++ b/ps3/ps3py/pkg.py @@ -0,0 +1,821 @@ +#!/usr/bin/env python +from __future__ import with_statement +import struct, sys + +class StructType(tuple): + def __getitem__(self, value): + return [self] * value + def __call__(self, value, endian='<'): + if isinstance(value, str): + return struct.unpack(endian + tuple.__getitem__(self, 0), value[:tuple.__getitem__(self, 1)])[0] + else: + return struct.pack(endian + tuple.__getitem__(self, 0), value) + +class Struct(object): + __slots__ = ('__attrs__', '__baked__', '__defs__', '__endian__', '__next__', '__sizes__', '__values__') + int8 = StructType(('b', 1)) + uint8 = StructType(('B', 1)) + + int16 = StructType(('h', 2)) + uint16 = StructType(('H', 2)) + + int32 = StructType(('l', 4)) + uint32 = StructType(('L', 4)) + + int64 = StructType(('q', 8)) + uint64 = StructType(('Q', 8)) + + float = StructType(('f', 4)) + + def string(cls, len, offset=0, encoding=None, stripNulls=False, value=''): + return StructType(('string', (len, offset, encoding, stripNulls, value))) + string = classmethod(string) + + LE = '<' + BE = '>' + __endian__ = '<' + + def __init__(self, func=None, unpack=None, **kwargs): + self.__defs__ = [] + self.__sizes__ = [] + self.__attrs__ = [] + self.__values__ = {} + self.__next__ = True + self.__baked__ = False + + if func == None: + self.__format__() + else: + sys.settrace(self.__trace__) + func() + for name in func.func_code.co_varnames: + value = self.__frame__.f_locals[name] + self.__setattr__(name, value) + + self.__baked__ = True + + if unpack != None: + if isinstance(unpack, tuple): + self.unpack(*unpack) + else: + self.unpack(unpack) + + if len(kwargs): + for name in kwargs: + self.__values__[name] = kwargs[name] + + def __trace__(self, frame, event, arg): + self.__frame__ = frame + sys.settrace(None) + + def __setattr__(self, name, value): + if name in self.__slots__: + return object.__setattr__(self, name, value) + + if self.__baked__ == False: + if not isinstance(value, list): + value = [value] + attrname = name + else: + attrname = '*' + name + + self.__values__[name] = None + + for sub in value: + if isinstance(sub, Struct): + sub = sub.__class__ + try: + if issubclass(sub, Struct): + sub = ('struct', sub) + except TypeError: + pass + type_, size = tuple(sub) + if type_ == 'string': + self.__defs__.append(Struct.string) + self.__sizes__.append(size) + self.__attrs__.append(attrname) + self.__next__ = True + + if attrname[0] != '*': + self.__values__[name] = size[3] + elif self.__values__[name] == None: + self.__values__[name] = [size[3] for val in value] + elif type_ == 'struct': + self.__defs__.append(Struct) + self.__sizes__.append(size) + self.__attrs__.append(attrname) + self.__next__ = True + + if attrname[0] != '*': + self.__values__[name] = size() + elif self.__values__[name] == None: + self.__values__[name] = [size() for val in value] + else: + if self.__next__: + self.__defs__.append('') + self.__sizes__.append(0) + self.__attrs__.append([]) + self.__next__ = False + + self.__defs__[-1] += type_ + self.__sizes__[-1] += size + self.__attrs__[-1].append(attrname) + + if attrname[0] != '*': + self.__values__[name] = 0 + elif self.__values__[name] == None: + self.__values__[name] = [0 for val in value] + else: + try: + self.__values__[name] = value + except KeyError: + raise AttributeError(name) + + def __getattr__(self, name): + if self.__baked__ == False: + return name + else: + try: + return self.__values__[name] + except KeyError: + raise AttributeError(name) + + def __len__(self): + ret = 0 + arraypos, arrayname = None, None + + for i in range(len(self.__defs__)): + sdef, size, attrs = self.__defs__[i], self.__sizes__[i], self.__attrs__[i] + + if sdef == Struct.string: + size, offset, encoding, stripNulls, value = size + if isinstance(size, str): + size = self.__values__[size] + offset + elif sdef == Struct: + if attrs[0] == '*': + if arrayname != attrs: + arrayname = attrs + arraypos = 0 + size = len(self.__values__[attrs[1:]][arraypos]) + size = len(self.__values__[attrs]) + + ret += size + + return ret + + def unpack(self, data, pos=0): + for name in self.__values__: + if not isinstance(self.__values__[name], Struct): + self.__values__[name] = None + elif self.__values__[name].__class__ == list and len(self.__values__[name]) != 0: + if not isinstance(self.__values__[name][0], Struct): + self.__values__[name] = None + + arraypos, arrayname = None, None + + for i in range(len(self.__defs__)): + sdef, size, attrs = self.__defs__[i], self.__sizes__[i], self.__attrs__[i] + + if sdef == Struct.string: + size, offset, encoding, stripNulls, value = size + if isinstance(size, str): + size = self.__values__[size] + offset + + temp = data[pos:pos+size] + if len(temp) != size: + raise StructException('Expected %i byte string, got %i' % (size, len(temp))) + + if encoding != None: + temp = temp.decode(encoding) + + if stripNulls: + temp = temp.rstrip('\0') + + if attrs[0] == '*': + name = attrs[1:] + if self.__values__[name] == None: + self.__values__[name] = [] + self.__values__[name].append(temp) + else: + self.__values__[attrs] = temp + pos += size + elif sdef == Struct: + if attrs[0] == '*': + if arrayname != attrs: + arrayname = attrs + arraypos = 0 + name = attrs[1:] + self.__values__[attrs][arraypos].unpack(data, pos) + pos += len(self.__values__[attrs][arraypos]) + arraypos += 1 + else: + self.__values__[attrs].unpack(data, pos) + pos += len(self.__values__[attrs]) + else: + values = struct.unpack(self.__endian__+sdef, data[pos:pos+size]) + pos += size + j = 0 + for name in attrs: + if name[0] == '*': + name = name[1:] + if self.__values__[name] == None: + self.__values__[name] = [] + self.__values__[name].append(values[j]) + else: + self.__values__[name] = values[j] + j += 1 + + return self + + def pack(self): + arraypos, arrayname = None, None + + ret = '' + for i in range(len(self.__defs__)): + sdef, size, attrs = self.__defs__[i], self.__sizes__[i], self.__attrs__[i] + + if sdef == Struct.string: + size, offset, encoding, stripNulls, value = size + if isinstance(size, str): + size = self.__values__[size]+offset + + if attrs[0] == '*': + if arrayname != attrs: + arraypos = 0 + arrayname = attrs + temp = self.__values__[attrs[1:]][arraypos] + arraypos += 1 + else: + temp = self.__values__[attrs] + + if encoding != None: + temp = temp.encode(encoding) + + temp = temp[:size] + ret += temp + ('\0' * (size - len(temp))) + elif sdef == Struct: + if attrs[0] == '*': + if arrayname != attrs: + arraypos = 0 + arrayname = attrs + ret += self.__values__[attrs[1:]][arraypos].pack() + arraypos += 1 + else: + ret += self.__values__[attrs].pack() + else: + values = [] + for name in attrs: + if name[0] == '*': + if arrayname != name: + arraypos = 0 + arrayname = name + values.append(self.__values__[name[1:]][arraypos]) + arraypos += 1 + else: + values.append(self.__values__[name]) + + ret += struct.pack(self.__endian__+sdef, *values) + return ret + + def __getitem__(self, value): + return [('struct', self.__class__)] * value + +class SelfHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.magic = Struct.uint32 + self.headerVer = Struct.uint32 + self.flags = Struct.uint16 + self.type = Struct.uint16 + self.meta = Struct.uint32 + self.headerSize = Struct.uint64 + self.encryptedSize = Struct.uint64 + self.unknown = Struct.uint64 + self.AppInfo = Struct.uint64 + self.elf = Struct.uint64 + self.phdr = Struct.uint64 + self.shdr = Struct.uint64 + self.phdrOffsets = Struct.uint64 + self.sceversion = Struct.uint64 + self.digest = Struct.uint64 + self.digestSize = Struct.uint64 + +class AppInfo(Struct): + __endian__ = Struct.BE + def __format__(self): + self.authid = Struct.uint64 + self.unknown = Struct.uint32 + self.appType = Struct.uint32 + self.appVersion = Struct.uint64 + +import struct +import sys +import hashlib +import os +import getopt +import ConfigParser +import io +import glob + +TYPE_NPDRMSELF = 0x1 +TYPE_RAW = 0x3 +TYPE_DIRECTORY = 0x4 + +TYPE_OVERWRITE_ALLOWED = 0x80000000 + +class EbootMeta(Struct): + __endian__ = Struct.BE + def __format__(self): + self.magic = Struct.uint32 + self.unk1 = Struct.uint32 + self.drmType = Struct.uint32 + self.unk2 = Struct.uint32 + self.contentID = Struct.uint8[0x30] + self.fileSHA1 = Struct.uint8[0x10] + self.notSHA1 = Struct.uint8[0x10] + self.notXORKLSHA1 = Struct.uint8[0x10] + self.nulls = Struct.uint8[0x10] +class MetaHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.unk1 = Struct.uint32 + self.unk2 = Struct.uint32 + self.drmType = Struct.uint32 + self.unk4 = Struct.uint32 + + self.unk21 = Struct.uint32 + self.unk22 = Struct.uint32 + self.unk23 = Struct.uint32 + self.unk24 = Struct.uint32 + + self.unk31 = Struct.uint32 + self.unk32 = Struct.uint32 + self.unk33 = Struct.uint32 + self.secondaryVersion = Struct.uint16 + self.unk34 = Struct.uint16 + + self.dataSize = Struct.uint32 + self.unk42 = Struct.uint32 + self.unk43 = Struct.uint32 + self.packagedBy = Struct.uint16 + self.packageVersion = Struct.uint16 +class DigestBlock(Struct): + __endian__ = Struct.BE + def __format__(self): + self.type = Struct.uint32 + self.size = Struct.uint32 + self.isNext = Struct.uint64 +class FileHeader(Struct): + __endian__ = Struct.BE + def __format__(self): + self.fileNameOff = Struct.uint32 + self.fileNameLength = Struct.uint32 + self.fileOff = Struct.uint64 + + self.fileSize = Struct.uint64 + self.flags = Struct.uint32 + self.padding = Struct.uint32 + def __str__(self): + out = "" + out += "[X] File Name: %s [" % self.fileName + if self.flags & 0xFF == TYPE_NPDRMSELF: + out += "NPDRM Self]" + elif self.flags & 0xFF == TYPE_DIRECTORY: + out += "Directory]" + elif self.flags & 0xFF == TYPE_RAW: + out += "Raw Data]" + else: + out += "Unknown]" + if (self.flags & TYPE_OVERWRITE_ALLOWED ) != 0: + out += " Overwrite allowed.\n" + else: + out += " Overwrite NOT allowed.\n" + out += "\n" + + out += "[X] File Name offset: %08x\n" % self.fileNameOff + out += "[X] File Name Length: %08x\n" % self.fileNameLength + out += "[X] Offset To File Data: %016x\n" % self.fileOff + + out += "[X] File Size: %016x\n" % self.fileSize + out += "[X] Flags: %08x\n" % self.flags + out += "[X] Padding: %08x\n\n" % self.padding + assert self.padding == 0, "I guess I was wrong, this is not padding." + + + return out + def __repr__(self): + return self.fileName + (" Size: 0x%016x" % self.fileSize) + def __init__(self): + Struct.__init__(self) + self.fileName = "" + +class Header(Struct): + __endian__ = Struct.BE + def __format__(self): + self.magic = Struct.uint32 + self.type = Struct.uint32 + self.pkgInfoOff = Struct.uint32 + self.unk1 = Struct.uint32 + + self.headSize = Struct.uint32 + self.itemCount = Struct.uint32 + self.packageSize = Struct.uint64 + + self.dataOff = Struct.uint64 + self.dataSize = Struct.uint64 + + self.contentID = Struct.uint8[0x30] + self.QADigest = Struct.uint8[0x10] + self.KLicensee = Struct.uint8[0x10] + + + + def __str__(self): + context = keyToContext(self.QADigest) + setContextNum(context, 0xFFFFFFFFFFFFFFFF) + licensee = crypt(context, listToString(self.KLicensee), 0x10) + + out = "" + out += "[X] Magic: %08x\n" % self.magic + out += "[X] Type: %08x\n" % self.type + out += "[X] Offset to package info: %08x\n" % self.pkgInfoOff + out += "[ ] unk1: %08x\n" % self.unk1 + + out += "[X] Head Size: %08x\n" % self.headSize + out += "[X] Item Count: %08x\n" % self.itemCount + out += "[X] Package Size: %016x\n" % self.packageSize + + out += "[X] Data Offset: %016x\n" % self.dataOff + out += "[X] Data Size: %016x\n" % self.dataSize + + out += "[X] ContentID: '%s'\n" % (nullterm(self.contentID)) + + out += "[X] QA_Digest: %s\n" % (nullterm(self.QADigest, True)) + out += "[X] K Licensee: %s\n" % licensee.encode('hex') + + + return out +def listToString(inlist): + if isinstance(inlist, list): + return ''.join(["%c" % el for el in inlist]) + else: + return "" +def nullterm(str_plus, printhex=False): + if isinstance(str_plus, list): + if printhex: + str_plus = ''.join(["%X" % el for el in str_plus]) + else: + str_plus = listToString(str_plus) + z = str_plus.find('\0') + if z != -1: + return str_plus[:z] + else: + return str_plus + +def keyToContext(key): + if isinstance(key, list): + key = listToString(key) + key = key[0:16] + largekey = [] + for i in range(0, 8): + largekey.append(ord(key[i])) + for i in range(0, 8): + largekey.append(ord(key[i])) + for i in range(0, 8): + largekey.append(ord(key[i+8])) + for i in range(0, 8): + largekey.append(ord(key[i+8])) + for i in range(0, 0x20): + largekey.append(0) + return largekey + +#Thanks to anonymous for the help with the RE of this part, +# the x86 mess of ands and ors made my head go BOOM headshot. +def manipulate(key): + if not isinstance(key, list): + return + tmp = listToString(key[0x38:]) + + + tmpnum = struct.unpack('>Q', tmp)[0] + tmpnum += 1 + tmpnum = tmpnum & 0xFFFFFFFFFFFFFFFF + setContextNum(key, tmpnum) +def setContextNum(key, tmpnum): + tmpchrs = struct.pack('>Q', tmpnum) + + key[0x38] = ord(tmpchrs[0]) + key[0x39] = ord(tmpchrs[1]) + key[0x3a] = ord(tmpchrs[2]) + key[0x3b] = ord(tmpchrs[3]) + key[0x3c] = ord(tmpchrs[4]) + key[0x3d] = ord(tmpchrs[5]) + key[0x3e] = ord(tmpchrs[6]) + key[0x3f] = ord(tmpchrs[7]) + +try: + import pkgcrypt +except: + print "" + print "-----------------" + print "SSNES BUILD ERROR" + print "-----------------" + print "Couldn't make PKG file. Go into the ps3py directory, and type the following:" + print "" + print "python2 setup.py build" + print "" + print "This should create a pkgcrypt.so file in the build/ directory. Move that file" + print "over to the root of the ps3py directory and try running this script again." + + +def crypt(key, inbuf, length): + if not isinstance(key, list): + return "" + return pkgcrypt.pkgcrypt(listToString(key), inbuf, length); + + # Original python (slow) implementation + ret = "" + offset = 0 + while length > 0: + bytes_to_dump = length + if length > 0x10: + bytes_to_dump = 0x10 + outhash = SHA1(listToString(key)[0:0x40]) + for i in range(0, bytes_to_dump): + ret += chr(ord(outhash[i]) ^ ord(inbuf[offset])) + offset += 1 + manipulate(key) + length -= bytes_to_dump + return ret +def SHA1(data): + m = hashlib.sha1() + m.update(data) + return m.digest() + +pkgcrypt.register_sha1_callback(SHA1) + +def getFiles(files, folder, original): + oldfolder = folder + foundFiles = glob.glob( os.path.join(folder, '*') ) + sortedList = [] + for filepath in foundFiles: + if not os.path.isdir(filepath): + sortedList.append(filepath) + for filepath in foundFiles: + if os.path.isdir(filepath): + sortedList.append(filepath) + for filepath in sortedList: + newpath = filepath.replace("\\", "/") + newpath = newpath[len(original):] + if os.path.isdir(filepath): + folder = FileHeader() + folder.fileName = newpath + folder.fileNameOff = 0 + folder.fileNameLength = len(folder.fileName) + folder.fileOff = 0 + + folder.fileSize = 0 + folder.flags = TYPE_OVERWRITE_ALLOWED | TYPE_DIRECTORY + folder.padding = 0 + files.append(folder) + getFiles(files, filepath, original) + else: + file = FileHeader() + file.fileName = newpath + file.fileNameOff = 0 + file.fileNameLength = len(file.fileName) + file.fileOff = 0 + file.fileSize = os.path.getsize(filepath) + file.flags = TYPE_OVERWRITE_ALLOWED | TYPE_RAW + if newpath == "USRDIR/EBOOT.BIN": + file.fileSize = ((file.fileSize - 0x30 + 63) & ~63) + 0x30 + file.flags = TYPE_OVERWRITE_ALLOWED | TYPE_NPDRMSELF + + file.padding = 0 + files.append(file) + +def pack(folder, contentid, outname=None): + + qadigest = hashlib.sha1() + + header = Header() + header.magic = 0x7F504B47 + header.type = 0x01 + header.pkgInfoOff = 0xC0 + header.unk1 = 0x05 + + header.headSize = 0x80 + header.itemCount = 0 + header.packageSize = 0 + + header.dataOff = 0x140 + header.dataSize = 0 + + for i in range(0, 0x30): + header.contentID[i] = 0 + + for i in range(0,0x10): + header.QADigest[i] = 0 + header.KLicensee[i] = 0 + + + metaBlock = MetaHeader() + metaBlock.unk1 = 1 #doesnt change output of --extract + metaBlock.unk2 = 4 #doesnt change output of --extract + metaBlock.drmType = 3 #1 = Network, 2 = Local, 3 = Free, anything else = unknown + metaBlock.unk4 = 2 + + metaBlock.unk21 = 4 + metaBlock.unk22 = 5 #5 == gameexec, 4 == gamedata + metaBlock.unk23 = 3 + metaBlock.unk24 = 4 + + metaBlock.unk31 = 0xE #packageType 0x10 == patch, 0x8 == Demo&Key, 0x0 == Demo&Key (AND UserFiles = NotOverWrite), 0xE == normal, use 0xE for gamexec, and 8 for gamedata + metaBlock.unk32 = 4 #when this is 5 secondary version gets used?? + metaBlock.unk33 = 8 #doesnt change output of --extract + metaBlock.secondaryVersion = 0 + metaBlock.unk34 = 0 + + metaBlock.dataSize = 0 + metaBlock.unk42 = 5 + metaBlock.unk43 = 4 + metaBlock.packagedBy = 0x1061 + metaBlock.packageVersion = 0 + + + files = [] + getFiles(files, folder, folder) + header.itemCount = len(files) + dataToEncrypt = "" + fileDescLength = 0 + fileOff = 0x20 * len(files) + for file in files: + alignedSize = (file.fileNameLength + 0x0F) & ~0x0F + file.fileNameOff = fileOff + fileOff += alignedSize + for file in files: + file.fileOff = fileOff + fileOff += (file.fileSize + 0x0F) & ~0x0F + dataToEncrypt += file.pack() + for file in files: + alignedSize = (file.fileNameLength + 0x0F) & ~0x0F + dataToEncrypt += file.fileName + dataToEncrypt += "\0" * (alignedSize-file.fileNameLength) + fileDescLength = len(dataToEncrypt) + for file in files: + if not file.flags & 0xFF == TYPE_DIRECTORY: + path = os.path.join(folder, file.fileName) + fp = open(path, 'rb') + fileData = fp.read() + qadigest.update(fileData) + fileSHA1 = SHA1(fileData) + fp.close() + if fileData[0:9] == "SCE\0\0\0\0\x02\x80": + fselfheader = SelfHeader() + fselfheader.unpack(fileData[0:len(fselfheader)]) + appheader = AppInfo() + appheader.unpack(fileData[fselfheader.AppInfo:fselfheader.AppInfo+len(appheader)]) + found = False + digestOff = fselfheader.digest + while not found: + digest = DigestBlock() + digest.unpack(fileData[digestOff:digestOff+len(digest)]) + if digest.type == 3: + found = True + else: + digestOff += digest.size + if digest.isNext != 1: + break + digestOff += len(digest) + if appheader.appType == 8 and found: + dataToEncrypt += fileData[0:digestOff] + + meta = EbootMeta() + meta.magic = 0x4E504400 + meta.unk1 = 1 + meta.drmType = metaBlock.drmType + meta.unk2 = 1 + for i in range(0,min(len(contentid), 0x30)): + meta.contentID[i] = ord(contentid[i]) + for i in range(0,0x10): + meta.fileSHA1[i] = ord(fileSHA1[i]) + meta.notSHA1[i] = (~meta.fileSHA1[i]) & 0xFF + if i == 0xF: + meta.notXORKLSHA1[i] = (1 ^ meta.notSHA1[i] ^ 0xAA) & 0xFF + else: + meta.notXORKLSHA1[i] = (0 ^ meta.notSHA1[i] ^ 0xAA) & 0xFF + meta.nulls[i] = 0 + dataToEncrypt += meta.pack() + dataToEncrypt += fileData[digestOff + 0x80:] + else: + dataToEncrypt += fileData + else: + dataToEncrypt += fileData + + dataToEncrypt += '\0' * (((file.fileSize + 0x0F) & ~0x0F) - len(fileData)) + header.dataSize = len(dataToEncrypt) + metaBlock.dataSize = header.dataSize + header.packageSize = header.dataSize + 0x1A0 + head = header.pack() + qadigest.update(head) + qadigest.update(dataToEncrypt[0:fileDescLength]) + QA_Digest = qadigest.digest() + + for i in range(0, 0x10): + header.QADigest[i] = ord(QA_Digest[i]) + + for i in range(0, min(len(contentid), 0x30)): + header.contentID[i] = ord(contentid[i]) + + context = keyToContext(header.QADigest) + setContextNum(context, 0xFFFFFFFFFFFFFFFF) + licensee = crypt(context, listToString(header.KLicensee), 0x10) + + for i in range(0, min(len(contentid), 0x10)): + header.KLicensee[i] = ord(licensee[i]) + + if outname != None: + outFile = open(outname, 'wb') + else: + outFile = open(contentid + ".pkg", 'wb') + outFile.write(header.pack()) + headerSHA = SHA1(header.pack())[3:19] + outFile.write(headerSHA) + + + metaData = metaBlock.pack() + metaBlockSHA = SHA1(metaData)[3:19] + metaBlockSHAPad = '\0' * 0x30 + + context = keyToContext([ord(c) for c in metaBlockSHA]) + metaBlockSHAPadEnc = crypt(context, metaBlockSHAPad, 0x30) + + context = keyToContext([ord(c) for c in headerSHA]) + metaBlockSHAPadEnc2 = crypt(context, metaBlockSHAPadEnc, 0x30) + outFile.write(metaBlockSHAPadEnc2) + outFile.write(metaData) + outFile.write(metaBlockSHA) + outFile.write(metaBlockSHAPadEnc) + + context = keyToContext(header.QADigest) + encData = crypt(context, dataToEncrypt, header.dataSize) + outFile.write(encData) + outFile.write('\0' * 0x60) + outFile.close() + print header + +def usage(): + print """usage: [based on revision 1061] + + python pkg.py target-directory [out-file] + + python pkg.py [options] npdrm-package + -l | --list list packaged files. + -x | --extract extract package. + + python pkg.py [options] + --version print revision. + --help print this message.""" + +def version(): + print """pkg.py 0.5""" + +def main(): + extract = False + list = False + contentid = None + try: + opts, args = getopt.getopt(sys.argv[1:], "hx:dvl:c:", ["help", "extract=", "version", "list=", "contentid="]) + except getopt.GetoptError: + usage() + sys.exit(2) + for opt, arg in opts: + if opt in ("-h", "--help"): + usage() + sys.exit(2) + elif opt in ("-v", "--version"): + version() + sys.exit(2) + elif opt in ("-x", "--extract"): + fileToExtract = arg + extract = True + elif opt in ("-l", "--list"): + fileToList = arg + list = True + elif opt in ("-c", "--contentid"): + contentid = arg + else: + usage() + sys.exit(2) + if extract: + unpack(fileToExtract) + else: + if len(args) == 1 and contentid != None: + pack(args[0], contentid) + elif len(args) == 2 and contentid != None: + pack(args[0], contentid, args[1]) + else: + usage() + sys.exit(2) +if __name__ == "__main__": + main() diff --git a/ps3/ps3py/setup.py b/ps3/ps3py/setup.py new file mode 100644 index 0000000000..c315b47e2d --- /dev/null +++ b/ps3/ps3py/setup.py @@ -0,0 +1,8 @@ +from distutils.core import setup, Extension + +module1 = Extension('pkgcrypt', sources = ['crypt.c']) + +setup (name = 'pkgcrypt', + version = '1.0', + description = 'C implementation of the crypt function from pkg.py', + ext_modules = [module1]) diff --git a/ps3/salamander/main.c b/ps3/salamander/main.c index 1833428567..26edac8a3f 100644 --- a/ps3/salamander/main.c +++ b/ps3/salamander/main.c @@ -20,9 +20,11 @@ #include #include #include +#ifdef HAVE_EXITSPAWN_NPDRM #include #include #include +#endif #include #include #include @@ -35,6 +37,12 @@ #define NP_POOL_SIZE (128*1024) #define MAX_PATH_LENGTH 1024 +#ifdef HAVE_LOGGER +#include "../cellframework2/fileio/logger.h" +#define SSNES_LOG(...) net_send("SSNES Salamander: " __VA_ARGS__); +#define SSNES_ERR(...) net_send("SSNES Salamander [ERROR] :: " __VA_ARGS__); +#define SSNES_WARN(...) net_send("SSNES Salamander [WARN] :: " __VA_ARGS__); +#else #define SSNES_LOG(...) do { \ fprintf(stderr, "SSNES Salamander: " __VA_ARGS__); \ fflush(stderr); \ @@ -49,8 +57,11 @@ fprintf(stderr, "SSNES Salamander [WARN] :: " __VA_ARGS__); \ fflush(stderr); \ } while (0) +#endif +#ifdef HAVE_EXITSPAWN_NPDRM static uint8_t np_pool[NP_POOL_SIZE]; +#endif char contentInfoPath[MAX_PATH_LENGTH]; char usrDirPath[MAX_PATH_LENGTH]; char LIBSNES_DIR_PATH[MAX_PATH_LENGTH]; @@ -263,19 +274,34 @@ static void get_environment_settings (void) int main(int argc, char *argv[]) { CellPadData pad_data; +#ifdef HAVE_EXITSPAWN_NPDRM char spawn_data[256], spawn_data_size[16]; SceNpDrmKey * k_licensee = NULL; +#endif int ret; cellSysmoduleLoadModule(CELL_SYSMODULE_IO); cellSysmoduleLoadModule(CELL_SYSMODULE_FS); cellSysmoduleLoadModule(CELL_SYSMODULE_SYSUTIL_GAME); +#if defined(HAVE_EXITSPAWN_NPDRM) || defined(HAVE_LOGGER) cellSysmoduleLoadModule(CELL_SYSMODULE_NET); +#endif + +#ifdef HAVE_EXITSPAWN_NPDRM cellSysmoduleLoadModule(CELL_SYSMODULE_SYSUTIL_NP); +#endif +#if defined(HAVE_EXITSPAWN_NPDRM) || defined(HAVE_LOGGER) sys_net_initialize_network(); +#endif +#ifdef HAVE_LOGGER + logger_init(); +#endif + +#ifdef HAVE_EXITSPAWN_NPDRM sceNpInit(NP_POOL_SIZE, np_pool); +#endif get_environment_settings(); @@ -297,6 +323,11 @@ int main(int argc, char *argv[]) cellPadEnd(); +#ifdef HAVE_LOGGER + logger_shutdown(); +#endif + +#ifdef HAVE_EXITSPAWN_NPDRM for(unsigned int i = 0; i < sizeof(spawn_data); ++i) spawn_data[i] = i & 0xff; @@ -310,17 +341,29 @@ int main(int argc, char *argv[]) }; ret = sceNpDrmProcessExitSpawn2(k_licensee, libsnes_path, (const char** const)spawn_argv, NULL, (sys_addr_t)spawn_data, 256, 1000, SYS_PROCESS_PRIMARY_STACK_SIZE_1M); - if(ret == SCE_NP_DRM_ERROR_FORMAT) + SSNES_LOG("Launch libsnes core: [%s] (return code: %x]).\n", libsnes_path, ret); + if(ret < 0) { SSNES_LOG("SELF file is not of NPDRM type, trying another approach to boot it...\n"); - exitspawn(libsnes_path, (const char** const)spawn_argv, NULL, NULL, 0, 1000, SYS_PROCESS_PRIMARY_STACK_SIZE_1M); + sys_game_process_exitspawn2(libsnes_path, NULL, NULL, NULL, 0, 1000, SYS_PROCESS_PRIMARY_STACK_SIZE_1M); } - SSNES_LOG("Launch libsnes core: [%s] (return code: %x]).\n", libsnes_path, ret); - sceNpTerm(); +#else + sys_game_process_exitspawn2((char*)libsnes_path, NULL, NULL, NULL, 0, 1000, SYS_PROCESS_PRIMARY_STACK_SIZE_1M); +#endif + +#if defined(HAVE_EXITSPAWN_NPDRM) || defined(HAVE_LOGGER) + sys_net_finalize_network(); +#endif + +#ifdef HAVE_EXITSPAWN_NPDRM cellSysmoduleUnloadModule(CELL_SYSMODULE_SYSUTIL_NP); +#endif + +#if defined(HAVE_EXITSPAWN_NPDRM) || defined(HAVE_LOGGER) cellSysmoduleUnloadModule(CELL_SYSMODULE_NET); +#endif cellSysmoduleUnloadModule(CELL_SYSMODULE_SYSUTIL_GAME); cellSysmoduleLoadModule(CELL_SYSMODULE_FS); cellSysmoduleLoadModule(CELL_SYSMODULE_IO);