aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/fs/psp/psp-stream.h32
-rw-r--r--backends/module.mk12
-rw-r--r--backends/platform/ds/arm7/source/main.cpp4
-rw-r--r--backends/platform/ds/arm9/makefile79
-rw-r--r--backends/platform/ds/arm9/source/dsmain.cpp5
-rw-r--r--backends/platform/ds/arm9/source/fat/io_nmmc.c10
-rw-r--r--backends/platform/gp2x/graphics.cpp5
-rw-r--r--backends/platform/gp2xwiz/gp2xwiz-graphics.cpp5
-rw-r--r--backends/platform/gp2xwiz/gp2xwiz-main.cpp3
-rw-r--r--backends/platform/gp2xwiz/module.mk3
-rw-r--r--backends/platform/linuxmoto/linuxmoto-graphics.cpp5
-rw-r--r--backends/platform/ps2/Makefile.ps298
-rw-r--r--backends/platform/ps2/elf32.h209
-rw-r--r--backends/platform/ps2/module.mk3
-rw-r--r--backends/platform/ps2/systemps2.cpp9
-rw-r--r--backends/platform/psp/Makefile10
-rw-r--r--backends/platform/psp/audio.cpp4
-rw-r--r--backends/platform/psp/audio.h4
-rw-r--r--backends/platform/psp/cursor.cpp4
-rw-r--r--backends/platform/psp/default_display_client.h4
-rw-r--r--backends/platform/psp/display_client.cpp4
-rw-r--r--backends/platform/psp/display_manager.cpp4
-rw-r--r--backends/platform/psp/display_manager.h4
-rw-r--r--backends/platform/psp/input.cpp4
-rw-r--r--backends/platform/psp/psploader.cpp732
-rw-r--r--backends/platform/psp/thread.cpp4
-rw-r--r--backends/platform/psp/thread.h4
-rw-r--r--backends/platform/samsungtv/main.cpp2
-rw-r--r--backends/platform/sdl/graphics.cpp5
-rw-r--r--backends/platform/sdl/main.cpp2
-rw-r--r--backends/platform/sdl/sdl.cpp8
-rw-r--r--backends/platform/sdl/sdl.h2
-rw-r--r--backends/plugins/arm-loader.cpp169
-rw-r--r--backends/plugins/arm-loader.h37
-rw-r--r--backends/plugins/ds/ds-provider.cpp45
-rw-r--r--backends/plugins/ds/ds-provider.h32
-rw-r--r--backends/plugins/ds/plugin.ld218
-rw-r--r--backends/plugins/elf-loader.cpp413
-rw-r--r--backends/plugins/elf-loader.h67
-rw-r--r--backends/plugins/elf-provider.cpp105
-rw-r--r--backends/plugins/elf-provider.h70
-rw-r--r--backends/plugins/elf32.h229
-rw-r--r--backends/plugins/mips-loader.cpp351
-rw-r--r--backends/plugins/mips-loader.h46
-rw-r--r--backends/plugins/plugin.syms (renamed from backends/platform/psp/plugin.syms)0
-rw-r--r--backends/plugins/ps2/main_prog.ld99
-rw-r--r--backends/plugins/ps2/plugin.ld94
-rw-r--r--backends/plugins/ps2/ps2-provider.cpp44
-rw-r--r--backends/plugins/ps2/ps2-provider.h31
-rw-r--r--backends/plugins/psp/plugin.ld (renamed from backends/platform/psp/plugin.ld)0
-rw-r--r--backends/plugins/psp/psp-provider.cpp76
-rw-r--r--backends/plugins/psp/psp-provider.h8
-rw-r--r--backends/plugins/shorts-segment-manager.cpp89
-rw-r--r--backends/plugins/shorts-segment-manager.h (renamed from backends/platform/psp/psploader.h)76
-rw-r--r--backends/saves/default/default-saves.cpp4
-rw-r--r--base/main.cpp15
-rw-r--r--base/plugins.cpp81
-rw-r--r--base/plugins.h9
-rw-r--r--engines/metaengine.h1
-rw-r--r--engines/sci/engine/script.cpp2
-rw-r--r--engines/sci/engine/script_patches.cpp70
-rw-r--r--engines/sci/engine/workarounds.cpp5
-rw-r--r--engines/sci/graphics/animate.cpp26
-rw-r--r--engines/sci/graphics/animate.h1
-rw-r--r--engines/sci/graphics/view.cpp2
-rw-r--r--gui/launcher.cpp7
-rw-r--r--gui/options.cpp2
-rw-r--r--test/common/str.h24
-rw-r--r--tools/create_msvc/create_msvc.cpp3
-rw-r--r--tools/md5table.c4
-rw-r--r--tools/module.mk6
-rw-r--r--tools/scumm-md5.txt3
72 files changed, 2767 insertions, 1080 deletions
diff --git a/backends/fs/psp/psp-stream.h b/backends/fs/psp/psp-stream.h
index 9fd1ad0470..673630b685 100644
--- a/backends/fs/psp/psp-stream.h
+++ b/backends/fs/psp/psp-stream.h
@@ -35,39 +35,25 @@
*/
class PSPIoStream : public StdioStream, public Suspendable {
protected:
- Common::String _path;
- int _fileSize;
- bool _writeMode; // for resuming in the right mode
- int _physicalPos; // position in the real file
- int _pos; // position. Sometimes virtual
- bool _inCache; // whether we're in cache (virtual) mode
- bool _eos; // EOS flag
-
+ Common::String _path; /* Need to maintain for reopening after suspend */
+ bool _writeMode; /* "" */
+ int _pos; /* "" */
+ mutable int _ferror; /* Save file ferror */
+ mutable bool _feof; /* and eof */
+
enum {
SuspendError = 2,
ResumeError = 3
};
- enum {
- CACHE_SIZE = 1024,
- MIN_READ_SIZE = 1024 // reading less than 1024 takes exactly the same time as 1024
- };
-
- // For caching
- char *_cache;
- int _cacheStartOffset; // starting offset of the cache. -1 when cache is invalid
-
- mutable int _ferror; // file error state
- int _errorSuspend; // for debugging
+ int _errorSuspend;
mutable int _errorSource;
+
+ // Error checking
int _errorPos;
void * _errorHandle;
int _suspendCount;
- bool synchronizePhysicalPos(); // synchronize the physical and virtual positions
- bool isOffsetInCache(uint32 pos); // check if an offset is found in cache
- bool isCacheValid() { return _cacheStartOffset != -1; }
-
public:
/**
diff --git a/backends/module.mk b/backends/module.mk
index e0a3f4c683..c0457d8062 100644
--- a/backends/module.mk
+++ b/backends/module.mk
@@ -22,6 +22,12 @@ MODULE_OBJS := \
midi/timidity.o \
midi/dmedia.o \
midi/windows.o \
+ plugins/elf-loader.o \
+ plugins/mips-loader.o \
+ plugins/shorts-segment-manager.o \
+ plugins/arm-loader.o \
+ plugins/elf-provider.o \
+ plugins/dc/dc-provider.o \
plugins/posix/posix-provider.o \
plugins/sdl/sdl-provider.o \
plugins/win32/win32-provider.o \
@@ -43,7 +49,8 @@ endif
ifeq ($(BACKEND),ds)
MODULE_OBJS += \
fs/ds/ds-fs-factory.o \
- fs/ds/ds-fs.o
+ fs/ds/ds-fs.o \
+ plugins/ds/ds-provider.o
endif
ifeq ($(BACKEND),n64)
@@ -54,7 +61,8 @@ endif
ifeq ($(BACKEND),ps2)
MODULE_OBJS += \
- fs/ps2/ps2-fs-factory.o
+ fs/ps2/ps2-fs-factory.o \
+ plugins/ps2/ps2-provider.o
endif
ifeq ($(BACKEND),psp)
diff --git a/backends/platform/ds/arm7/source/main.cpp b/backends/platform/ds/arm7/source/main.cpp
index bcaaf8e936..75f7012ed0 100644
--- a/backends/platform/ds/arm7/source/main.cpp
+++ b/backends/platform/ds/arm7/source/main.cpp
@@ -40,7 +40,7 @@
#include <system.h>
#include <stdlib.h>
#include <string.h>
-#include <registers_alt.h> // Needed for SOUND_CR
+#include <registers_alt.h> // Needed for SOUND_CR
#include <NDS/scummvm_ipc.h>
//////////////////////////////////////////////////////////////////////
#ifdef USE_DEBUGGER
@@ -592,7 +592,7 @@ int main(int argc, char ** argv) {
IPC->reset = false;
- //fifoInit();
+ //fifoInit();
for (int r = 0; r < 8; r++) {
IPC->adpcm.arm7Buffer[r] = (u8 *) malloc(512);
diff --git a/backends/platform/ds/arm9/makefile b/backends/platform/ds/arm9/makefile
index eedf75c256..c9a665c442 100644
--- a/backends/platform/ds/arm9/makefile
+++ b/backends/platform/ds/arm9/makefile
@@ -1,10 +1,13 @@
srcdir ?= .
DEPDIR := .deps
-#DYNAMIC_MODULES = 1
+VERBOSE_BUILD = 1
+DYNAMIC_MODULES = 1
libndsdir = $(DEVKITPRO)/libnds
#libndsdir = /home/neil/devkitpror21/libnds
+ENABLED = DYNAMIC_PLUGIN
+
# Select the build by setting SCUMM_BUILD to a,b,c,d,e,f or g.
# Anything else gets build a.
@@ -12,7 +15,7 @@ ifeq ($(SCUMM_BUILD),k)
DS_BUILD_K = 1
else
ifeq ($(SCUMM_BUILD),j)
- DS_BUILD_J = 1
+ DS_BUILD_J = 1
else
ifeq ($(SCUMM_BUILD),i)
DS_BUILD_I = 1
@@ -64,9 +67,7 @@ ifdef DS_BUILD_F
else
ifdef DS_BUILD_E
# TODO: Inherit the earth uses so much RAM that I have removed libmad in order to
- # claw some back.
-
-
+ # claw some back.
else
ifdef DS_BUILD_I
@@ -75,7 +76,7 @@ else
ifdef DS_BUILD_K
else
- # USE_MAD = 1
+ #USE_MAD = 1
endif
endif
endif
@@ -112,7 +113,7 @@ USE_ARM_COSTUME_ASM = 1
ifdef DS_BUILD_A
DEFINES = -DDS_BUILD_A -DUSE_ARM_GFX_ASM -DUSE_ARM_COSTUME_ASM
LOGO = logoa.bmp
- ENABLE_SCUMM = STATIC_PLUGIN
+ ENABLE_SCUMM = $(ENABLED)
USE_ARM_GFX_ASM = 1
BUILD=scummvm-A
endif
@@ -120,66 +121,66 @@ endif
ifdef DS_BUILD_B
DEFINES = -DDS_BUILD_B
LOGO = logob.bmp
- ENABLE_SKY = STATIC_PLUGIN
- ENABLE_QUEEN = STATIC_PLUGIN
+ ENABLE_SKY = $(ENABLED)
+ ENABLE_QUEEN = $(ENABLED)
BUILD=scummvm-B
endif
ifdef DS_BUILD_C
DEFINES = -DDS_BUILD_C
LOGO = logoc.bmp
- ENABLE_AGOS = STATIC_PLUGIN
+ ENABLE_AGOS = $(ENABLED)
BUILD=scummvm-C
endif
ifdef DS_BUILD_D
DEFINES = -DDS_BUILD_D
LOGO = logod.bmp
- ENABLE_GOB = STATIC_PLUGIN
- ENABLE_CINE = STATIC_PLUGIN
- ENABLE_AGI = STATIC_PLUGIN
+ ENABLE_GOB = $(ENABLED)
+ ENABLE_CINE = $(ENABLED)
+ ENABLE_AGI = $(ENABLED)
BUILD=scummvm-D
endif
ifdef DS_BUILD_E
DEFINES = -DDS_BUILD_E
LOGO = logoe.bmp
- ENABLE_SAGA = STATIC_PLUGIN
+ ENABLE_SAGA = $(ENABLED)
BUILD=scummvm-E
endif
ifdef DS_BUILD_F
DEFINES = -DDS_BUILD_F
LOGO = logof.bmp
- ENABLE_KYRA = STATIC_PLUGIN
+ ENABLE_KYRA = $(ENABLED)
BUILD=scummvm-F
endif
ifdef DS_BUILD_G
DEFINES = -DDS_BUILD_G
LOGO = logog.bmp
- ENABLE_LURE = STATIC_PLUGIN
+ ENABLE_LURE = $(ENABLED)
BUILD=scummvm-G
endif
ifdef DS_BUILD_H
DEFINES = -DDS_BUILD_H
LOGO = logoh.bmp
- ENABLE_PARALLACTION = STATIC_PLUGIN
+ ENABLE_PARALLACTION = $(ENABLED)
BUILD=scummvm-H
endif
ifdef DS_BUILD_I
DEFINES = -DDS_BUILD_I
LOGO = logoi.bmp
- ENABLE_MADE = STATIC_PLUGIN
+ ENABLE_MADE = $(ENABLED)
BUILD=scummvm-I
endif
ifdef DS_BUILD_K
DEFINES = -DDS_BUILD_K
LOGO = logok.bmp
- ENABLE_CRUISE = STATIC_PLUGIN
+ ENABLE_CRUISE = $(ENABLED)
BUILD=scummvm-K
endif
@@ -187,18 +188,18 @@ endif
#ifdef DS_BUILD_L
# DEFINES = -DDS_BUILD_L
# LOGO = logog.bmp
-# ENABLE_DRASCULA = STATIC_PLUGIN
+# ENABLE_DRASCULA = $(ENABLED)
# BUILD=scummvm-K
#endif
#ifdef DS_BUILD_M
# DEFINES = -DDS_BUILD_M
# LOGO = logog.bmp
-# ENABLE_TUCKER = STATIC_PLUGIN
+# ENABLE_TUCKER = $(ENABLED)
# BUILD=scummvm-K
#endif
-ARM7BIN := -7 $(CURDIR)/../../arm7/arm7.bin
+ARM7BIN := -7 $(CURDIR)/../arm7/arm7.bin
CC = arm-eabi-gcc
CXX = arm-eabi-g++
@@ -236,14 +237,14 @@ CXXFLAGS= $(CFLAGS) -Wno-non-virtual-dtor -Wno-unknown-pragmas -Wno-reorder \
ASFLAGS = -mcpu=arm9tdmi -mthumb-interwork
-DEFINES += -D__DS__ -DNDS -DARM9 -DNONSTANDARD_PORT -DDISABLE_FANCY_THEMES -DVECTOR_RENDERER_FORMAT=1555 -DDISABLE_DOSBOX_OPL -DDISABLE_DEFAULT_SAVEFILEMANAGER -DARM
+DEFINES += -D__DS__ -DNDS -DARM9 -DNONSTANDARD_PORT -DDISABLE_FANCY_THEMES -DVECTOR_RENDERER_FORMAT=1555 -DDISABLE_DOSBOX_OPL -DDISABLE_DEFAULT_SAVEFILEMANAGER -DELF_LOADER_TARGET -DARM -DARM_TARGET#-DNEW_PLUGIN_DESIGN_FIRST_REFINEMENT
ifdef USE_MAD
DEFINES += -DUSE_MAD
endif
DEFINES += -DREDUCE_MEMORY_USAGE
-LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -mno-fpu -Wl,-Map,map.txt -Wl,--gc-sections
+LDFLAGS = -specs=ds_arm9.specs -mthumb-interwork -mno-fpu -Wl,--target1-abs,-Map,map.txt#-Wl,--gc-sections
ifdef WRAP_MALLOC
LDFLAGS += -Wl,--wrap,malloc
@@ -252,12 +253,11 @@ endif
BACKEND := ds
-INCLUDES= -I$(portdir)/$(BUILD) -I$(srcdir) -I$(srcdir)/engines \
+INCLUDES= -I$(portdir) -I$(srcdir) -I$(srcdir)/engines \
-I$(portdir)/data -I$(portdir)/../commoninclude \
-I$(portdir)/source -I$(portdir)/source/mad \
-I$(libndsdir)/include -include $(srcdir)/common/scummsys.h
-
LIBS = -lm -L$(libndsdir)/lib -L$(portdir)/lib -lnds9
ifdef USE_MAD
LIBS += -lmad
@@ -266,7 +266,19 @@ ifdef USE_DEBUGGER
LIBS += -ldsdebugger -ldswifi9
endif
+ifeq ($(DYNAMIC_MODULES),1)
+DEFINES += -DDYNAMIC_MODULES
+PRE_OBJS_FLAGS = -Wl,--whole-archive
+POST_OBJS_FLAGS = -Wl,--no-whole-archive
+endif
+
EXECUTABLE = scummvm.elf
+
+PLUGIN_PREFIX =
+PLUGIN_SUFFIX = .plg
+PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/ds/plugin.ld $(srcdir)/backends/plugins/plugin.syms $(EXECUTABLE)
+PLUGIN_LDFLAGS += -nostartfiles -Wl,-q,--target1-abs,--just-symbols,$(EXECUTABLE),-T$(srcdir)/backends/plugins/ds/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/plugin.syms -lstdc++ -lc -mthumb-interwork -mno-fpu#-Wl,--gc-sections -mno-crt0 $(DEVKITPRO)/devkitARM/arm-eabi/lib/ds_arm9_crt0.o
+
MKDIR = mkdir -p
RM = rm -f
RM_REC = rm -rf
@@ -340,12 +352,13 @@ OPT_SIZE := -Os -mthumb
OBJS := $(DATA_OBJS) $(PORT_OBJS) $(FAT_OBJS)
-
MODULE_DIRS += .
-ndsall:
- @[ -d $(BUILD) ] || mkdir -p $(BUILD)
- make -C ./$(BUILD) -f ../makefile scummvm.nds scummvm.ds.gba
+#ndsall: plugins
+# make -f makefile scummvm.nds
+
+ndsall: plugins
+ make -f makefile scummvm.nds scummvm.ds.gba
include $(srcdir)/Makefile.common
@@ -354,11 +367,10 @@ semiclean:
clean:
$(RM) $(OBJS) $(EXECUTABLE)
- rm -fr $(BUILD)
+ rm -rf *.h engines plugins scummvm.nds scummvm.ds.gba
dist : SCUMMVM.BIN plugins plugin_dist
-
#---------------------------------------------------------------------------------
# canned command sequence for binary data
#---------------------------------------------------------------------------------
@@ -400,13 +412,14 @@ endef
#---------------------------------------------------------------------------------
%.nds: %.bin
- ndstool -c $@ -9 $< $(ARM7BIN) -b ../../$(LOGO) "$(@F);ScummVM $(VERSION);DS Port"
+ ndstool -c $@ -9 $< $(ARM7BIN) -b ../$(LOGO) "$(@F);ScummVM $(VERSION);DS Port"
%.ds.gba: %.nds
dsbuild $< -o $@ -l $(portdir)/ndsloader.bin
padbin 16 $@
#---------------------------------------------------------------------------------
+
%.bin: %.elf
$(OBJCOPY) -S -O binary $< $@
diff --git a/backends/platform/ds/arm9/source/dsmain.cpp b/backends/platform/ds/arm9/source/dsmain.cpp
index 95bfdfe40a..4c7d6b89ae 100644
--- a/backends/platform/ds/arm9/source/dsmain.cpp
+++ b/backends/platform/ds/arm9/source/dsmain.cpp
@@ -105,6 +105,8 @@
#endif
#include "engine.h"
+#include "backends/plugins/ds/ds-provider.h"
+#include "backends/plugins/elf-provider.h"
#include "backends/fs/ds/ds-fs.h"
#include "base/version.h"
#include "common/util.h"
@@ -3213,6 +3215,9 @@ int main(void) {
const char *argv[] = {"/scummvmds"};
#endif
+#ifdef DYNAMIC_MODULES
+ PluginManager::instance().addPluginProvider(new DSPluginProvider());
+#endif
while (1) {
scummvm_main(ARRAYSIZE(argv), (char **) &argv);
diff --git a/backends/platform/ds/arm9/source/fat/io_nmmc.c b/backends/platform/ds/arm9/source/fat/io_nmmc.c
index 6c996f5de1..261096a27b 100644
--- a/backends/platform/ds/arm9/source/fat/io_nmmc.c
+++ b/backends/platform/ds/arm9/source/fat/io_nmmc.c
@@ -170,7 +170,7 @@ bool NMMC_IsInserted(void) {
Neo_EnableMMC( true ); // Open SPI port to MMC card
Neo_SendMMCCommand(MMC_SEND_CSD, 0);
- if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occurred
+ if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
Neo_EnableMMC( false );
return false;
}
@@ -227,14 +227,14 @@ bool NMMC_StartUp(void) {
// Set block length
Neo_SendMMCCommand(MMC_SET_BLOCKLEN, BYTE_PER_READ );
- if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occurred
+ if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
Neo_EnableMMC( false );
return false;
}
// Check if we can use a higher SPI frequency
Neo_SendMMCCommand(MMC_SEND_CSD, 0);
- if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occurred
+ if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
Neo_EnableMMC( false );
return false;
}
@@ -268,7 +268,7 @@ bool NMMC_WriteSectors (u32 sector, u8 numSecs, void* buffer)
Neo_EnableMMC( true ); // Open SPI port to MMC card
Neo_SendMMCCommand( 25, sector );
- if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occurred
+ if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
Neo_EnableMMC( false );
return false;
}
@@ -318,7 +318,7 @@ bool NMMC_ReadSectors (u32 sector, u8 numSecs, void* buffer)
while (totalSecs--) {
Neo_SendMMCCommand(MMC_READ_BLOCK, sector );
- if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occurred
+ if( Neo_CheckMMCResponse( 0x00, 0xFF ) == false ) { // Make sure no errors occured
Neo_EnableMMC( false );
return false;
}
diff --git a/backends/platform/gp2x/graphics.cpp b/backends/platform/gp2x/graphics.cpp
index 4a3c668c52..1888cbe47c 100644
--- a/backends/platform/gp2x/graphics.cpp
+++ b/backends/platform/gp2x/graphics.cpp
@@ -1405,6 +1405,7 @@ void OSystem_GP2X::drawMouse() {
SDL_Rect zoomdst;
SDL_Rect dst;
int scale;
+ int width, height;
int hotX, hotY;
int tmpScreenWidth, tmpScreenHeight;
@@ -1425,12 +1426,16 @@ void OSystem_GP2X::drawMouse() {
if (!_overlayVisible) {
scale = _videoMode.scaleFactor;
+ width = _videoMode.screenWidth;
+ height = _videoMode.screenHeight;
dst.w = _mouseCurState.vW;
dst.h = _mouseCurState.vH;
hotX = _mouseCurState.vHotX;
hotY = _mouseCurState.vHotY;
} else {
scale = 1;
+ width = _videoMode.overlayWidth;
+ height = _videoMode.overlayHeight;
dst.w = _mouseCurState.rW;
dst.h = _mouseCurState.rH;
hotX = _mouseCurState.rHotX;
diff --git a/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp b/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp
index f6ad226d42..921558131a 100644
--- a/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp
+++ b/backends/platform/gp2xwiz/gp2xwiz-graphics.cpp
@@ -149,6 +149,7 @@ void OSystem_GP2XWIZ::drawMouse() {
SDL_Rect dst;
int scale;
+ int width, height;
int hotX, hotY;
if (_videoMode.mode == GFX_HALF && !_overlayVisible){
@@ -161,12 +162,16 @@ void OSystem_GP2XWIZ::drawMouse() {
if (!_overlayVisible) {
scale = _videoMode.scaleFactor;
+ width = _videoMode.screenWidth;
+ height = _videoMode.screenHeight;
dst.w = _mouseCurState.vW;
dst.h = _mouseCurState.vH;
hotX = _mouseCurState.vHotX;
hotY = _mouseCurState.vHotY;
} else {
scale = 1;
+ width = _videoMode.overlayWidth;
+ height = _videoMode.overlayHeight;
dst.w = _mouseCurState.rW;
dst.h = _mouseCurState.rH;
hotX = _mouseCurState.rHotX;
diff --git a/backends/platform/gp2xwiz/gp2xwiz-main.cpp b/backends/platform/gp2xwiz/gp2xwiz-main.cpp
index 394c3090c3..8c95a94639 100644
--- a/backends/platform/gp2xwiz/gp2xwiz-main.cpp
+++ b/backends/platform/gp2xwiz/gp2xwiz-main.cpp
@@ -42,7 +42,6 @@
#include "base/main.h"
#include "backends/saves/default/default-saves.h"
-
#include "backends/timer/default/default-timer.h"
#include "sound/mixer_intern.h"
@@ -64,7 +63,7 @@ int main(int argc, char *argv[]) {
#ifdef DYNAMIC_MODULES
PluginManager::instance().addPluginProvider(new POSIXPluginProvider());
-#endif
+#endif /* DYNAMIC_MODULES */
// Invoke the actual ScummVM main entry point:
int res = scummvm_main(argc, argv);
diff --git a/backends/platform/gp2xwiz/module.mk b/backends/platform/gp2xwiz/module.mk
index edf2f2a717..c76238f679 100644
--- a/backends/platform/gp2xwiz/module.mk
+++ b/backends/platform/gp2xwiz/module.mk
@@ -4,7 +4,8 @@ MODULE_OBJS := \
gp2xwiz-events.o \
gp2xwiz-graphics.o \
gp2xwiz-hw.o \
- gp2xwiz-main.o
+ gp2xwiz-main.o \
+ gp2xwiz-loader.o
# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
diff --git a/backends/platform/linuxmoto/linuxmoto-graphics.cpp b/backends/platform/linuxmoto/linuxmoto-graphics.cpp
index a39416ebc4..d66d41dfab 100644
--- a/backends/platform/linuxmoto/linuxmoto-graphics.cpp
+++ b/backends/platform/linuxmoto/linuxmoto-graphics.cpp
@@ -168,6 +168,7 @@ void OSystem_LINUXMOTO::drawMouse() {
SDL_Rect dst;
int scale;
+ int width, height;
int hotX, hotY;
if (_videoMode.mode == GFX_HALF && !_overlayVisible) {
@@ -180,12 +181,16 @@ void OSystem_LINUXMOTO::drawMouse() {
if (!_overlayVisible) {
scale = _videoMode.scaleFactor;
+ width = _videoMode.screenWidth;
+ height = _videoMode.screenHeight;
dst.w = _mouseCurState.vW;
dst.h = _mouseCurState.vH;
hotX = _mouseCurState.vHotX;
hotY = _mouseCurState.vHotY;
} else {
scale = 1;
+ width = _videoMode.overlayWidth;
+ height = _videoMode.overlayHeight;
dst.w = _mouseCurState.rW;
dst.h = _mouseCurState.rH;
hotX = _mouseCurState.rHotX;
diff --git a/backends/platform/ps2/Makefile.ps2 b/backends/platform/ps2/Makefile.ps2
index d2a8d210e4..f836bd3eaa 100644
--- a/backends/platform/ps2/Makefile.ps2
+++ b/backends/platform/ps2/Makefile.ps2
@@ -1,22 +1,45 @@
# $Header: Exp $
include $(PS2SDK)/Defs.make
-PS2_EXTRA = /works/devel/ps2/sdk-extra
+PS2_EXTRA = /home/tony/GSOC/ps2/sdk-extra
PS2_EXTRA_INCS = /zlib/include /libmad/ee/include /SjPcm/ee/src /tremor
PS2_EXTRA_LIBS = /zlib/lib /libmad/ee/lib /SjPcm/ee/lib /tremor/tremor
-ENABLED=STATIC_PLUGIN
+# Set to 1 to enable, 0 to disable dynamic modules
+DYNAMIC_MODULES = 1
+# Set to 1 to enable, 0 to disable more detailed printing of gcc commands
+VERBOSE_BUILD=0
+
+# Test for dynamic plugins
+ifeq ($(DYNAMIC_MODULES),1)
+ENABLED = DYNAMIC_PLUGIN
+DEFINES = -DDYNAMIC_MODULES
+PRE_OBJS_FLAGS = -Wl,--whole-archive
+POST_OBJS_FLAGS = -Wl,--no-whole-archive
+else
+ENABLED = STATIC_PLUGIN
+endif
+
+#control build
+DISABLE_SCALERS = true
+DISABLE_HQ_SCALERS = true
ENABLE_SCUMM = $(ENABLED)
ENABLE_SCUMM_7_8 = $(ENABLED)
ENABLE_HE = $(ENABLED)
ENABLE_AGI = $(ENABLED)
ENABLE_AGOS = $(ENABLED)
+ENABLE_AGOS2 = $(ENABLED)
ENABLE_CINE = $(ENABLED)
ENABLE_CRUISE = $(ENABLED)
+ENABLE_DRACI = $(ENABLED)
ENABLE_DRASCULA = $(ENABLED)
ENABLE_GOB = $(ENABLED)
+ENABLE_GROOVIE = $(ENABLED)
+# ENABLE_GROOVIE2 = $(ENABLED)
+ENABLE_IHNM = $(ENABLED)
ENABLE_KYRA = $(ENABLED)
+# ENABLE_LOL = $(ENABLED)
ENABLE_LURE = $(ENABLED)
# ENABLE_M4 = $(ENABLED)
ENABLE_MADE = $(ENABLED)
@@ -24,16 +47,18 @@ ENABLE_PARALLACTION = $(ENABLED)
ENABLE_QUEEN = $(ENABLED)
ENABLE_SAGA = $(ENABLED)
ENABLE_SAGA2 = $(ENABLED)
-ENABLE_IHNM = $(ENABLED)
+ENABLE_SCI = $(ENABLED)
+# ENABLE_SCI32 = $(ENABLED)
ENABLE_SKY = $(ENABLED)
ENABLE_SWORD1 = $(ENABLED)
ENABLE_SWORD2 = $(ENABLED)
-# ENABLE_TINSEL = $(ENABLED)
+ENABLE_TEENAGENT = $(ENABLED)
+ENABLE_TINSEL = $(ENABLED)
ENABLE_TOUCHE = $(ENABLED)
+ENABLE_TUCKER = $(ENABLED)
HAVE_GCC3 = true
-
-CC = ee-gcc
+CC = ee-gcc
CXX = ee-g++
AS = ee-gcc
LD = ee-gcc
@@ -42,51 +67,62 @@ RANLIB = ee-ranlib
STRIP = ee-strip
MKDIR = mkdir -p
RM = rm -f
+RM_REC = rm -rf
+MODULE_DIRS = ./
srcdir = ../../..
VPATH = $(srcdir)
INCDIR = ../../../
-# DEPDIR = .deps
+DEPDIR = .deps
-DEFINES = -DUSE_VORBIS -DUSE_TREMOR -DUSE_MAD -DUSE_ZLIB -DFORCE_RTL -D_EE -D__PLAYSTATION2__ -O2 -Wall -Wno-multichar
+TARGET = elf/scummvm.elf
+DEFINES += -DUSE_VORBIS -DUSE_TREMOR -DUSE_MAD -DUSE_ZLIB -DFORCE_RTL -DDISABLE_SAVEGAME_SORTING -D_EE -D__PLAYSTATION2__ -G2 -O2 -Wall -Wno-multichar -fno-rtti -fno-exceptions -DNO_ADAPTOR
+DEFINES += -DELF_LOADER_TARGET -DMIPS_TARGET#-DNEW_PLUGIN_DESIGN_FIRST_REFINEMENT
INCLUDES = $(addprefix -I$(PS2_EXTRA),$(PS2_EXTRA_INCS))
INCLUDES += -I $(PS2SDK)/ee/include -I $(PS2SDK)/common/include -I ./common -I . -I $(srcdir) -I $(srcdir)/engines
-TARGET = elf/scummvm.elf
+CXX_UPDATE_DEP_FLAG = -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP
+
+# Variables for dynamic plugin building
+PLUGIN_PREFIX =
+PLUGIN_SUFFIX = .plg
+PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/plugin.syms elf/scummvm.elf
+PLUGIN_LDFLAGS += -mno-crt0 $(PS2SDK)/ee/startup/crt0.o
+PLUGIN_LDFLAGS += -nostartfiles -Wl,-q,--just-symbols,elf/scummvm.elf,-T$(srcdir)/backends/plugins/ps2/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/plugin.syms -lstdc++ -lc
-OBJS := backends/platform/ps2/DmaPipe.o \
- backends/platform/ps2/Gs2dScreen.o \
- backends/platform/ps2/irxboot.o \
- backends/platform/ps2/ps2input.o \
- backends/platform/ps2/ps2pad.o \
- backends/platform/ps2/savefilemgr.o \
- backends/platform/ps2/fileio.o \
- backends/platform/ps2/asyncfio.o \
- backends/platform/ps2/icon.o \
- backends/platform/ps2/cd.o \
- backends/platform/ps2/eecodyvdfs.o \
- backends/platform/ps2/rpckbd.o \
- backends/platform/ps2/systemps2.o \
- backends/platform/ps2/ps2mutex.o \
- backends/platform/ps2/ps2time.o \
- backends/platform/ps2/ps2debug.o
-
-MODULE_DIRS += .
BACKEND := ps2
include $(srcdir)/Makefile.common
-LDFLAGS += -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -T $(PS2SDK)/ee/startup/linkfile
+LDFLAGS = -mno-crt0 $(PS2SDK)/ee/startup/crt0.o -T $(srcdir)/backends/plugins/ps2/main_prog.ld
LDFLAGS += -L $(PS2SDK)/ee/lib -L .
-LDFLAGS += $(addprefix -L$(PS2_EXTRA),$(PS2_EXTRA_LIBS))
+LDFLAGS += $(addprefix -L$(PS2_EXTRA),$(PS2_EXTRA_LIBS))
LDFLAGS += -lmc -lpad -lmouse -lhdd -lpoweroff -lsjpcm -lmad -ltremor -lz -lm -lc -lfileXio -lkernel -lstdc++
-LDFLAGS += -s
+
+OBJS := $(srcdir)/backends/platform/ps2/DmaPipe.o \
+ $(srcdir)/backends/platform/ps2/Gs2dScreen.o \
+ $(srcdir)/backends/platform/ps2/irxboot.o \
+ $(srcdir)/backends/platform/ps2/ps2input.o \
+ $(srcdir)/backends/platform/ps2/ps2pad.o \
+ $(srcdir)/backends/platform/ps2/savefilemgr.o \
+ $(srcdir)/backends/platform/ps2/fileio.o \
+ $(srcdir)/backends/platform/ps2/asyncfio.o \
+ $(srcdir)/backends/platform/ps2/icon.o \
+ $(srcdir)/backends/platform/ps2/cd.o \
+ $(srcdir)/backends/platform/ps2/eecodyvdfs.o \
+ $(srcdir)/backends/platform/ps2/rpckbd.o \
+ $(srcdir)/backends/platform/ps2/systemps2.o \
+ $(srcdir)/backends/platform/ps2/ps2mutex.o \
+ $(srcdir)/backends/platform/ps2/ps2time.o \
+ $(srcdir)/backends/platform/ps2/ps2debug.o
+
+include $(srcdir)/Makefile.common
all: $(TARGET)
$(TARGET): $(OBJS)
- $(LD) $^ $(LDFLAGS) -o $@
+ $(LD) $(PRE_OBJS_FLAGS) $(OBJS) $(POST_OBJS_FLAGS) $(LDFLAGS) -o $@
diff --git a/backends/platform/ps2/elf32.h b/backends/platform/ps2/elf32.h
new file mode 100644
index 0000000000..616cc4b4d2
--- /dev/null
+++ b/backends/platform/ps2/elf32.h
@@ -0,0 +1,209 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_ELF_H
+#define BACKENDS_ELF_H
+
+/* ELF stuff */
+
+typedef unsigned short Elf32_Half, Elf32_Section;
+typedef unsigned int Elf32_Word, Elf32_Addr, Elf32_Off;
+typedef signed int Elf32_Sword;
+typedef Elf32_Half Elf32_Versym;
+
+#define EI_NIDENT (16)
+#define SELFMAG 6
+
+/* ELF File format structures. Look up ELF structure for more details */
+
+// ELF header (contains info about the file)
+typedef struct {
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf32_Half e_type; /* Object file type */
+ Elf32_Half e_machine; /* Architecture */
+ Elf32_Word e_version; /* Object file version */
+ Elf32_Addr e_entry; /* Entry point virtual address */
+ Elf32_Off e_phoff; /* Program header table file offset */
+ Elf32_Off e_shoff; /* Section header table file offset */
+ Elf32_Word e_flags; /* Processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size in bytes */
+ Elf32_Half e_phentsize; /* Program header table entry size */
+ Elf32_Half e_phnum; /* Program header table entry count */
+ Elf32_Half e_shentsize; /* Section header table entry size */
+ Elf32_Half e_shnum; /* Section header table entry count */
+ Elf32_Half e_shstrndx; /* Section header string table index */
+} Elf32_Ehdr;
+
+// Should be in e_ident
+#define ELFMAG "\177ELF\1\1" /* ELF Magic number */
+
+// e_type values
+#define ET_NONE 0 /* no file type */
+#define ET_REL 1 /* relocatable */
+#define ET_EXEC 2 /* executable */
+#define ET_DYN 3 /* shared object */
+#define ET_CORE 4 /* core file */
+
+// e_machine values
+#define EM_MIPS 8
+
+
+// Program header (contains info about segment)
+typedef struct {
+ Elf32_Word p_type; /* Segment type */
+ Elf32_Off p_offset; /* Segment file offset */
+ Elf32_Addr p_vaddr; /* Segment virtual address */
+ Elf32_Addr p_paddr; /* Segment physical address */
+ Elf32_Word p_filesz; /* Segment size in file */
+ Elf32_Word p_memsz; /* Segment size in memory */
+ Elf32_Word p_flags; /* Segment flags */
+ Elf32_Word p_align; /* Segment alignment */
+} Elf32_Phdr;
+
+// p_type values
+#define PT_NULL 0 /* ignored */
+#define PT_LOAD 1 /* loadable segment */
+#define PT_DYNAMIC 2 /* dynamic linking info */
+#define PT_INTERP 3 /* info about interpreter */
+#define PT_NOTE 4 /* note segment */
+#define PT_SHLIB 5 /* reserved */
+#define PT_PHDR 6 /* Program header table */
+#define PT_MIPS_REGINFO 0x70000000 /* register usage info */
+
+// p_flags value
+#define PF_X 1 /* execute */
+#define PF_W 2 /* write */
+#define PF_R 4 /* read */
+
+// Section header (contains info about section)
+typedef struct {
+ Elf32_Word sh_name; /* Section name (string tbl index) */
+ Elf32_Word sh_type; /* Section type */
+ Elf32_Word sh_flags; /* Section flags */
+ Elf32_Addr sh_addr; /* Section virtual addr at execution */
+ Elf32_Off sh_offset; /* Section file offset */
+ Elf32_Word sh_size; /* Section size in bytes */
+ Elf32_Word sh_link; /* Link to another section */
+ Elf32_Word sh_info; /* Additional section information */
+ Elf32_Word sh_addralign; /* Section alignment */
+ Elf32_Word sh_entsize; /* Entry size if section holds table */
+} Elf32_Shdr;
+
+// sh_type values
+#define SHT_NULL 0 /* Inactive section */
+#define SHT_PROGBITS 1 /* Proprietary */
+#define SHT_SYMTAB 2 /* Symbol table */
+#define SHT_STRTAB 3 /* String table */
+#define SHT_RELA 4 /* Relocation entries with addend */
+#define SHT_HASH 5 /* Symbol hash table */
+#define SHT_DYNAMIC 6 /* Info for dynamic linking */
+#define SHT_NOTE 7 /* Note section */
+#define SHT_NOBITS 8 /* Occupies no space */
+#define SHT_REL 9 /* Relocation entries without addend */
+#define SHT_SHLIB 10 /* Reserved */
+#define SHT_DYNSYM 11 /* Minimal set of dynamic linking symbols */
+#define SHT_MIPS_LIBLSIT 0x70000000 /* Info about dynamic shared object libs */
+#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicts btw executables and shared objects */
+#define SHT_MIPS_GPTAB 0x70000003 /* Global pointer table */
+
+// sh_flags values
+#define SHF_WRITE 0 /* writable section */
+#define SHF_ALLOC 2 /* section occupies memory */
+#define SHF_EXECINSTR 4 /* machine instructions */
+#define SHF_MIPS_GPREL 0x10000000 /* Must be made part of global data area */
+
+
+// Symbol entry (contain info about a symbol)
+typedef struct {
+ Elf32_Word st_name; /* Symbol name (string tbl index) */
+ Elf32_Addr st_value; /* Symbol value */
+ Elf32_Word st_size; /* Symbol size */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ Elf32_Section st_shndx; /* Section index */
+} Elf32_Sym;
+
+// Extract from the st_info
+#define SYM_TYPE(x) ((x)&0xF)
+#define SYM_BIND(x) ((x)>>4)
+
+
+// Symbol binding values from st_info
+#define STB_LOCAL 0 /* Symbol not visible outside object */
+#define STB_GLOBAL 1 /* Symbol visible to all object files */
+#define STB_WEAK 2 /* Similar to STB_GLOBAL */
+
+// Symbol type values from st_info
+#define STT_NOTYPE 0 /* Not specified */
+#define STT_OBJECT 1 /* Data object e.g. variable */
+#define STT_FUNC 2 /* Function */
+#define STT_SECTION 3 /* Section */
+#define STT_FILE 4 /* Source file associated with object file */
+
+// Special section header index values from st_shndex
+#define SHN_UNDEF 0
+#define SHN_LOPROC 0xFF00 /* Extended values */
+#define SHN_ABS 0xFFF1 /* Absolute value: don't relocate */
+#define SHN_COMMON 0xFFF2 /* Common block. Not allocated yet */
+#define SHN_HIPROC 0xFF1F
+#define SHN_HIRESERVE 0xFFFF
+
+// Relocation entry (info about how to relocate)
+typedef struct {
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+} Elf32_Rel;
+
+// Access macros for the relocation info
+#define REL_TYPE(x) ((x)&0xFF) /* Extract relocation type */
+#define REL_INDEX(x) ((x)>>8) /* Extract relocation index into symbol table */
+
+// MIPS relocation types
+#define R_MIPS_NONE 0
+#define R_MIPS_16 1
+#define R_MIPS_32 2
+#define R_MIPS_REL32 3
+#define R_MIPS_26 4
+#define R_MIPS_HI16 5
+#define R_MIPS_LO16 6
+#define R_MIPS_GPREL16 7
+#define R_MIPS_LITERAL 8
+#define R_MIPS_GOT16 9
+#define R_MIPS_PC16 10
+#define R_MIPS_CALL16 11
+#define R_MIPS_GPREL32 12
+#define R_MIPS_GOTHI16 13
+#define R_MIPS_GOTLO16 14
+#define R_MIPS_CALLHI16 15
+#define R_MIPS_CALLLO16 16
+
+// Mock function to get value of global pointer
+#define getGP() ({ \
+ unsigned int __valgp; \
+ __asm__ ("add %0, $gp, $0" : "=r"(__valgp) : ); \
+ __valgp; \
+})
+
+#endif /* BACKENDS_ELF_H */
diff --git a/backends/platform/ps2/module.mk b/backends/platform/ps2/module.mk
index bf95a5501d..a12d10771f 100644
--- a/backends/platform/ps2/module.mk
+++ b/backends/platform/ps2/module.mk
@@ -16,7 +16,8 @@ MODULE_OBJS := \
systemps2.o \
ps2mutex.o \
ps2time.o \
- ps2debug.o
+ ps2debug.o \
+ ps2loader.o
# We don't use rules.mk but rather manually update OBJS and MODULE_DIRS.
MODULE_OBJS := $(addprefix $(MODULE)/, $(MODULE_OBJS))
diff --git a/backends/platform/ps2/systemps2.cpp b/backends/platform/ps2/systemps2.cpp
index 7659d5194d..357404c5c4 100644
--- a/backends/platform/ps2/systemps2.cpp
+++ b/backends/platform/ps2/systemps2.cpp
@@ -59,6 +59,8 @@
#include "backends/platform/ps2/ps2debug.h"
#include "backends/fs/ps2/ps2-fs-factory.h"
+#include "backends/plugins/ps2/ps2-provider.h"
+
#include "backends/saves/default/default-saves.h"
#include "common/config-manager.h"
@@ -105,7 +107,6 @@ extern "C" int scummvm_main(int argc, char *argv[]);
extern "C" int main(int argc, char *argv[]) {
SifInitRpc(0);
-
ee_thread_t thisThread;
int tid = GetThreadId();
ReferThreadStatus(tid, &thisThread);
@@ -130,8 +131,11 @@ extern "C" int main(int argc, char *argv[]) {
sioprintf("Creating system\n");
g_system = g_systemPs2 = new OSystem_PS2(argv[0]);
- g_systemPs2->init();
+#ifdef DYNAMIC_MODULES
+ PluginManager::instance().addPluginProvider(new PS2PluginProvider());
+#endif
+ g_systemPs2->init();
sioprintf("init done. starting ScummVM.\n");
int res = scummvm_main(argc, argv);
sioprintf("scummvm_main terminated: %d\n", res);
@@ -337,6 +341,7 @@ OSystem_PS2::OSystem_PS2(const char *elfPath) {
}
void OSystem_PS2::init(void) {
+ //msgPrintf(FOREVER, "got to init! Now restart your console... %d\n", res);
sioprintf("Timer...\n");
_scummTimerManager = new DefaultTimerManager();
_scummMixer = new Audio::MixerImpl(this, 48000);
diff --git a/backends/platform/psp/Makefile b/backends/platform/psp/Makefile
index 617ef7c8cc..9c011220b8 100644
--- a/backends/platform/psp/Makefile
+++ b/backends/platform/psp/Makefile
@@ -67,7 +67,7 @@ endif
# Variables for common Scummvm makefile
CXX = psp-g++
CXXFLAGS = -O3 -Wall -Wno-multichar -fno-exceptions -fno-rtti
-DEFINES = -D__PSP__ -DNONSTANDARD_PORT -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DUSE_ZLIB -DDISABLE_DOSBOX_OPL -DUSE_RGB_COLOR
+DEFINES = -D__PSP__ -DNONSTANDARD_PORT -DDISABLE_TEXT_CONSOLE -DDISABLE_COMMAND_LINE -DUSE_ZLIB -DDISABLE_DOSBOX_OPL -DUSE_RGB_COLOR -DELF_LOADER_TARGET -DMIPS_TARGET
LDFLAGS :=
INCDIR := $(srcdir) . $(srcdir)/engines/ $(PSPSDK)/include
@@ -87,8 +87,8 @@ CXX_UPDATE_DEP_FLAG = -Wp,-MMD,"$(*D)/$(DEPDIR)/$(*F).d",-MQ,"$@",-MP
# Variables for dynamic plugin building
PLUGIN_PREFIX =
PLUGIN_SUFFIX = .plg
-PLUGIN_EXTRA_DEPS = plugin.syms scummvm-psp.elf
-PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-Tplugin.ld,--retain-symbols-file,plugin.syms -lstdc++ -lc
+PLUGIN_EXTRA_DEPS = $(srcdir)/backends/plugins/plugin.syms scummvm-psp.elf
+PLUGIN_LDFLAGS = -nostartfiles -Wl,-q,--just-symbols=scummvm-psp.org.elf,-T$(srcdir)/backends/plugins/psp/plugin.ld,--retain-symbols-file,$(srcdir)/backends/plugins/plugin.syms -lstdc++ -lc
# PSP-specific variables
STRIP = psp-strip
@@ -125,8 +125,7 @@ endif
# PSP LIBS
PSPLIBS = -lpspprof -lpspvfpu -lpspdebug -lpspgu -lpspge -lpspdisplay -lpspctrl -lpspsdk \
- -lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspaudiocodec \
- -lpspkernel
+ -lpsputility -lpspuser -lpsppower -lpsphprm -lpspsdk -lpsprtc -lpspaudio -lpspkernel
# Add in PSPSDK includes and libraries.
LIBS += -lpng -lz -lstdc++ -lc -lm $(PSPLIBS)
@@ -150,6 +149,7 @@ OBJS := powerman.o \
mp3.o \
tests.o
+
BACKEND := psp
# Include common Scummvm makefile
diff --git a/backends/platform/psp/audio.cpp b/backends/platform/psp/audio.cpp
index e540733162..14691befee 100644
--- a/backends/platform/psp/audio.cpp
+++ b/backends/platform/psp/audio.cpp
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/audio.h b/backends/platform/psp/audio.h
index eeba598fed..07f70cec7d 100644
--- a/backends/platform/psp/audio.h
+++ b/backends/platform/psp/audio.h
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/cursor.cpp b/backends/platform/psp/cursor.cpp
index ae3b8f0050..cf879e095a 100644
--- a/backends/platform/psp/cursor.cpp
+++ b/backends/platform/psp/cursor.cpp
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.h $
- * $Id: osys_psp.h 46120 2009-11-24 10:33:30Z Bluddy $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/default_display_client.h b/backends/platform/psp/default_display_client.h
index 716e6fcc35..2e33632eb1 100644
--- a/backends/platform/psp/default_display_client.h
+++ b/backends/platform/psp/default_display_client.h
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/trace.h $
- * $Id: trace.h 44276 2009-09-23 16:11:23Z joostp $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/display_client.cpp b/backends/platform/psp/display_client.cpp
index 71b505ec7c..6360772c96 100644
--- a/backends/platform/psp/display_client.cpp
+++ b/backends/platform/psp/display_client.cpp
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 46126 2009-11-24 14:18:46Z fingolfin $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/display_manager.cpp b/backends/platform/psp/display_manager.cpp
index 5037543f12..544e5a1b25 100644
--- a/backends/platform/psp/display_manager.cpp
+++ b/backends/platform/psp/display_manager.cpp
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 47541 2010-01-25 01:39:44Z lordhoto $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/display_manager.h b/backends/platform/psp/display_manager.h
index 1f7320902c..72f252faae 100644
--- a/backends/platform/psp/display_manager.h
+++ b/backends/platform/psp/display_manager.h
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 47541 2010-01-25 01:39:44Z lordhoto $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/input.cpp b/backends/platform/psp/input.cpp
index 4fe7cb3f92..2a91ce455a 100644
--- a/backends/platform/psp/input.cpp
+++ b/backends/platform/psp/input.cpp
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.cpp $
- * $Id: osys_psp.cpp 43618 2009-08-21 22:44:49Z joostp $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/psploader.cpp b/backends/platform/psp/psploader.cpp
deleted file mode 100644
index 464e20770c..0000000000
--- a/backends/platform/psp/psploader.cpp
+++ /dev/null
@@ -1,732 +0,0 @@
-/* ScummVM - Graphic Adventure Engine
- *
- * ScummVM is the legal property of its developers, whose names
- * are too numerous to list here. Please refer to the COPYRIGHT
- * file distributed with this source distribution.
- *
- * 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.
- *
- * $URL$
- * $Id$
- *
- */
-
-#if defined(DYNAMIC_MODULES) && defined(__PSP__)
-
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <malloc.h>
-#include <unistd.h>
-#include <sys/_default_fcntl.h>
-
-#include <psputils.h>
-
-#include "backends/platform/psp/psploader.h"
-#include "backends/platform/psp/powerman.h"
-
-//#define __PSP_DEBUG_FUNCS__ /* For debugging the stack */
-//#define __PSP_DEBUG_PRINT__
-
-#include "backends/platform/psp/trace.h"
-
-extern char __plugin_hole_start; // Indicates start of hole in program file for shorts
-extern char __plugin_hole_end; // Indicates end of hole in program file
-extern char _gp[]; // Value of gp register
-
-DECLARE_SINGLETON(ShortSegmentManager) // For singleton
-
-// Get rid of symbol table in memory
-void DLObject::discard_symtab() {
- DEBUG_ENTER_FUNC();
- free(_symtab);
- free(_strtab);
- _symtab = NULL;
- _strtab = NULL;
- _symbol_cnt = 0;
-}
-
-// Unload all objects from memory
-void DLObject::unload() {
- DEBUG_ENTER_FUNC();
- discard_symtab();
- free(_segment);
- _segment = NULL;
-
- if (_shortsSegment) {
- ShortsMan.deleteSegment(_shortsSegment);
- _shortsSegment = NULL;
- }
-}
-
-/**
- * Follow the instruction of a relocation section.
- *
- * @param fd File Descriptor
- * @param offset Offset into the File
- * @param size Size of relocation section
- * @param relSegment Base address of relocated segment in memory (memory offset)
- *
- */
-bool DLObject::relocate(int fd, unsigned long offset, unsigned long size, void *relSegment) {
- DEBUG_ENTER_FUNC();
- Elf32_Rel *rel = NULL; // relocation entry
-
- // Allocate memory for relocation table
- if (!(rel = (Elf32_Rel *)malloc(size))) {
- PSP_ERROR("Out of memory.");
- return false;
- }
-
- // Read in our relocation table
- if (lseek(fd, offset, SEEK_SET) < 0 ||
- read(fd, rel, size) != (ssize_t)size) {
- PSP_ERROR("Relocation table load failed.");
- free(rel);
- return false;
- }
-
- // Treat each relocation entry. Loop over all of them
- int cnt = size / sizeof(*rel);
-
- PSP_DEBUG_PRINT("Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment);
-
- bool seenHi16 = false; // For treating HI/LO16 commands
- int firstHi16 = -1; // Mark the point of the first hi16 seen
- Elf32_Addr ahl = 0; // Calculated addend
- int a = 0; // Addend: taken from the target
-
- unsigned int *lastTarget = 0; // For processing hi16 when lo16 arrives
- unsigned int relocation = 0;
- int debugRelocs[10] = {0}; // For debugging
- int extendedHi16 = 0; // Count extended hi16 treatments
- Elf32_Addr lastHiSymVal = 0;
- bool hi16InShorts = false;
-
-#define DEBUG_NUM 2
-
- // Loop over relocation entries
- for (int i = 0; i < cnt; i++) {
- // Get the symbol this relocation entry is referring to
- Elf32_Sym *sym = (Elf32_Sym *)(_symtab) + (REL_INDEX(rel[i].r_info));
-
- // Get the target instruction in the code
- unsigned int *target = (unsigned int *)((char *)relSegment + rel[i].r_offset);
-
- PSP_DEBUG_DO(unsigned int origTarget = *target); // Save for debugging
-
- // Act differently based on the type of relocation
- switch (REL_TYPE(rel[i].r_info)) {
-
- case R_MIPS_HI16: // Absolute addressing.
- if (sym->st_shndx < SHN_LOPROC && // Only shift for plugin section (ie. has a real section index)
- firstHi16 < 0) { // Only process first in block of HI16s
- firstHi16 = i; // Keep the first Hi16 we saw
- seenHi16 = true;
- ahl = (*target & 0xffff) << 16; // Take lower 16 bits shifted up
-
- lastHiSymVal = sym->st_value;
- hi16InShorts = (ShortsMan.inGeneralSegment((char *)sym->st_value)); // Fix for problem with switching btw segments
- if (debugRelocs[0]++ < DEBUG_NUM) // Print only a set number
- PSP_DEBUG_PRINT("R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x\n",
- i, rel[i].r_offset, ahl, *target);
- }
- break;
-
- case R_MIPS_LO16: // Absolute addressing. Needs a HI16 to come before it
- if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. (ie. has a real section index)
- if (!seenHi16) { // We MUST have seen HI16 first
- PSP_ERROR("R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!\n", i);
- free(rel);
- return false;
- }
-
- // Fix: bug in gcc makes LO16s connect to wrong HI16s sometimes (shorts and regular segment)
- // Note that we can check the entire shorts segment because the executable's shorts don't belong to this plugin section
- // and will be screened out above
- bool lo16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value);
-
- // Correct the bug by getting the proper value in ahl (taken from the current symbol)
- if ((hi16InShorts && !lo16InShorts) || (!hi16InShorts && lo16InShorts)) {
- ahl -= (lastHiSymVal & 0xffff0000); // We assume gcc meant the same offset
- ahl += (sym->st_value & 0xffff0000);
- }
-
- ahl &= 0xffff0000; // Clean lower 16 bits for repeated LO16s
- a = *target & 0xffff; // Take lower 16 bits of the target
- a = (a << 16) >> 16; // Sign extend them
- ahl += a; // Add lower 16 bits. AHL is now complete
-
- // Fix: we can have LO16 access to the short segment sometimes
- if (lo16InShorts) {
- relocation = ahl + _shortsSegment->getOffset(); // Add in the short segment offset
- } else // It's in the regular segment
- relocation = ahl + (Elf32_Addr)_segment; // Add in the new offset for the segment
-
- if (firstHi16 >= 0) { // We haven't treated the HI16s yet so do it now
- for (int j = firstHi16; j < i; j++) {
- if (REL_TYPE(rel[j].r_info) != R_MIPS_HI16) continue; // Skip over non-Hi16s
-
- lastTarget = (unsigned int *)((char *)relSegment + rel[j].r_offset); // get hi16 target
- *lastTarget &= 0xffff0000; // Clear the lower 16 bits of the last target
- *lastTarget |= (relocation >> 16) & 0xffff; // Take the upper 16 bits of the relocation
- if (relocation & 0x8000)(*lastTarget)++; // Subtle: we need to add 1 to the HI16 in this case
- }
- firstHi16 = -1; // Reset so we'll know we treated it
- } else {
- extendedHi16++;
- }
-
- *target &= 0xffff0000; // Clear the lower 16 bits of current target
- *target |= relocation & 0xffff; // Take the lower 16 bits of the relocation
-
- if (debugRelocs[1]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n",
- i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target);
- if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n",
- i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target);
- }
- break;
-
- case R_MIPS_26: // Absolute addressing (for jumps and branches only)
- if (sym->st_shndx < SHN_LOPROC) { // Only relocate for main segment
- a = *target & 0x03ffffff; // Get 26 bits' worth of the addend
- a = (a << 6) >> 6; // Sign extend a
- relocation = ((a << 2) + (Elf32_Addr)_segment) >> 2; // a already points to the target. Subtract our offset
- *target &= 0xfc000000; // Clean lower 26 target bits
- *target |= (relocation & 0x03ffffff);
-
- if (debugRelocs[3]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n",
- i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target);
- } else {
- if (debugRelocs[4]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n",
- i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target);
- }
- break;
-
- case R_MIPS_GPREL16: // GP Relative addressing
- if (_shortsSegment->getOffset() != 0 && // Only relocate if we shift the shorts section
- ShortsMan.inGeneralSegment((char *)sym->st_value)) { // Only relocate things in the plugin hole
- a = *target & 0xffff; // Get 16 bits' worth of the addend
- a = (a << 16) >> 16; // Sign extend it
-
- relocation = a + _shortsSegment->getOffset();
-
- *target &= 0xffff0000; // Clear the lower 16 bits of the target
- *target |= relocation & 0xffff;
-
- if (debugRelocs[5]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, target=%x, offset=%x\n",
- i, a, _gpVal, origTarget, *target, _shortsSegment->getOffset());
- }
-
- break;
-
- case R_MIPS_32: // Absolute addressing
- if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section.
- a = *target; // Get full 32 bits of addend
-
- if (ShortsMan.inGeneralSegment((char *)sym->st_value)) // Check if we're in the shorts segment
- relocation = a + _shortsSegment->getOffset(); // Shift by shorts offset
- else // We're in the main section
- relocation = a + (Elf32_Addr)_segment; // Shift by main offset
- *target = relocation;
-
- if (debugRelocs[6]++ < DEBUG_NUM)
- PSP_DEBUG_PRINT("R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target);
- }
- break;
-
- default:
- PSP_ERROR("Unknown relocation type %x at relocation %d.\n", REL_TYPE(rel[i].r_info), i);
- free(rel);
- return false;
- }
- }
-
- PSP_DEBUG_PRINT("Done with relocation. extendedHi16=%d\n\n", extendedHi16);
-
- free(rel);
- return true;
-}
-
-bool DLObject::readElfHeader(int fd, Elf32_Ehdr *ehdr) {
- DEBUG_ENTER_FUNC();
- // Start reading the elf header. Check for errors
- if (read(fd, ehdr, sizeof(*ehdr)) != sizeof(*ehdr) ||
- memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || // Check MAGIC
- ehdr->e_type != ET_EXEC || // Check for executable
- ehdr->e_machine != EM_MIPS || // Check for MIPS machine type
- ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header
- ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header
- PSP_ERROR("Invalid file type.");
- return false;
- }
-
- PSP_DEBUG_PRINT("phoff = %d, phentsz = %d, phnum = %d\n",
- ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum);
-
- return true;
-}
-
-bool DLObject::readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num) {
- DEBUG_ENTER_FUNC();
- // Read program header
- if (lseek(fd, ehdr->e_phoff + sizeof(*phdr)*num, SEEK_SET) < 0 ||
- read(fd, phdr, sizeof(*phdr)) != sizeof(*phdr)) {
- PSP_ERROR("Program header load failed.");
- return false;
- }
-
- // Check program header values
- if (phdr->p_type != PT_LOAD || phdr->p_filesz > phdr->p_memsz) {
- PSP_ERROR("Invalid program header.");
- return false;
- }
-
- PSP_DEBUG_PRINT("offs = %x, filesz = %x, memsz = %x, align = %x\n",
- phdr->p_offset, phdr->p_filesz, phdr->p_memsz, phdr->p_align);
-
- return true;
-
-}
-
-bool DLObject::loadSegment(int fd, Elf32_Phdr *phdr) {
- DEBUG_ENTER_FUNC();
-
- char *baseAddress = 0;
-
- // We need to take account of non-allocated segment for shorts
- if (phdr->p_flags & PF_X) { // This is a relocated segment
-
- // Attempt to allocate memory for segment
- int extra = phdr->p_vaddr % phdr->p_align; // Get extra length TODO: check logic here
- PSP_DEBUG_PRINT("extra mem is %x\n", extra);
-
- if (phdr->p_align < 0x10000) phdr->p_align = 0x10000; // Fix for wrong alignment on e.g. AGI
-
- if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) {
- PSP_ERROR("Out of memory.\n");
- return false;
- }
- PSP_DEBUG_PRINT("allocated segment @ %p\n", _segment);
-
- // Get offset to load segment into
- baseAddress = (char *)_segment + phdr->p_vaddr;
- _segmentSize = phdr->p_memsz + extra;
- } else { // This is a shorts section.
- _shortsSegment = ShortsMan.newSegment(phdr->p_memsz, (char *)phdr->p_vaddr);
-
- baseAddress = _shortsSegment->getStart();
- PSP_DEBUG_PRINT("shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x\n",
- _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr, _shortsSegment->getOffset());
-
- }
-
- // Set bss segment to 0 if necessary (assumes bss is at the end)
- if (phdr->p_memsz > phdr->p_filesz) {
- PSP_DEBUG_PRINT("Setting %p to %p to 0 for bss\n", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz);
- memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
- }
- // Read the segment into memory
- if (lseek(fd, phdr->p_offset, SEEK_SET) < 0 ||
- read(fd, baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) {
- PSP_ERROR("Segment load failed.");
- return false;
- }
-
- return true;
-}
-
-
-Elf32_Shdr * DLObject::loadSectionHeaders(int fd, Elf32_Ehdr *ehdr) {
- DEBUG_ENTER_FUNC();
-
- Elf32_Shdr *shdr = NULL;
-
- // Allocate memory for section headers
- if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) {
- PSP_ERROR("Out of memory.");
- return NULL;
- }
-
- // Read from file into section headers
- if (lseek(fd, ehdr->e_shoff, SEEK_SET) < 0 ||
- read(fd, shdr, ehdr->e_shnum * sizeof(*shdr)) !=
- (ssize_t)(ehdr->e_shnum * sizeof(*shdr))) {
- PSP_ERROR("Section headers load failed.");
- return NULL;
- }
-
- return shdr;
-}
-
-int DLObject::loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
- DEBUG_ENTER_FUNC();
-
- // Loop over sections, looking for symbol table linked to a string table
- for (int i = 0; i < ehdr->e_shnum; i++) {
- PSP_DEBUG_PRINT("Section %d: type = %x, size = %x, entsize = %x, link = %x\n",
- i, shdr[i].sh_type, shdr[i].sh_size, shdr[i].sh_entsize, shdr[i].sh_link);
-
- if (shdr[i].sh_type == SHT_SYMTAB &&
- shdr[i].sh_entsize == sizeof(Elf32_Sym) &&
- shdr[i].sh_link < ehdr->e_shnum &&
- shdr[shdr[i].sh_link].sh_type == SHT_STRTAB &&
- _symtab_sect < 0) {
- _symtab_sect = i;
- }
- }
-
- // Check for no symbol table
- if (_symtab_sect < 0) {
- PSP_ERROR("No symbol table.");
- return -1;
- }
-
- PSP_DEBUG_PRINT("Symbol section at section %d, size %x\n", _symtab_sect, shdr[_symtab_sect].sh_size);
-
- // Allocate memory for symbol table
- if (!(_symtab = malloc(shdr[_symtab_sect].sh_size))) {
- PSP_ERROR("Out of memory.");
- return -1;
- }
-
- // Read symbol table into memory
- if (lseek(fd, shdr[_symtab_sect].sh_offset, SEEK_SET) < 0 ||
- read(fd, _symtab, shdr[_symtab_sect].sh_size) !=
- (ssize_t)shdr[_symtab_sect].sh_size) {
- PSP_ERROR("Symbol table load failed.");
- return -1;
- }
-
- // Set number of symbols
- _symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym);
- PSP_DEBUG_PRINT("Loaded %d symbols.\n", _symbol_cnt);
-
- return _symtab_sect;
-
-}
-
-bool DLObject::loadStringTable(int fd, Elf32_Shdr *shdr) {
- DEBUG_ENTER_FUNC();
-
- int string_sect = shdr[_symtab_sect].sh_link;
-
- // Allocate memory for string table
- if (!(_strtab = (char *)malloc(shdr[string_sect].sh_size))) {
- PSP_ERROR("Out of memory.");
- return false;
- }
-
- // Read string table into memory
- if (lseek(fd, shdr[string_sect].sh_offset, SEEK_SET) < 0 ||
- read(fd, _strtab, shdr[string_sect].sh_size) !=
- (ssize_t)shdr[string_sect].sh_size) {
- PSP_ERROR("Symbol table strings load failed.");
- return false;
- }
- return true;
-}
-
-void DLObject::relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset) {
- DEBUG_ENTER_FUNC();
-
- int shortsCount = 0, othersCount = 0;
- PSP_DEBUG_PRINT("Relocating symbols by %x. Shorts offset=%x\n", offset, shortsOffset);
-
- // Loop over symbols, add relocation offset
- Elf32_Sym *s = (Elf32_Sym *)_symtab;
- for (int c = _symbol_cnt; c--; s++) {
- // Make sure we don't relocate special valued symbols
- if (s->st_shndx < SHN_LOPROC) {
- if (!ShortsMan.inGeneralSegment((char *)s->st_value)) {
- othersCount++;
- s->st_value += offset;
- if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize)
- PSP_ERROR("Symbol out of bounds! st_value = %x\n", s->st_value);
- } else { // shorts section
- shortsCount++;
- s->st_value += shortsOffset;
- if (!_shortsSegment->inSegment((char *)s->st_value))
- PSP_ERROR("Symbol out of bounds! st_value = %x\n", s->st_value);
- }
-
- }
-
- }
-
- PSP_DEBUG_PRINT("Relocated %d short symbols, %d others.\n", shortsCount, othersCount);
-}
-
-bool DLObject::relocateRels(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
- DEBUG_ENTER_FUNC();
-
- // Loop over sections, finding relocation sections
- for (int i = 0; i < ehdr->e_shnum; i++) {
-
- Elf32_Shdr *curShdr = &(shdr[i]);
- //Elf32_Shdr *linkShdr = &(shdr[curShdr->sh_info]);
-
- if (curShdr->sh_type == SHT_REL && // Check for a relocation section
- curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size
- (int)curShdr->sh_link == _symtab_sect && // Check that the sh_link connects to our symbol table
- curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists
- (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory
- if (!ShortsMan.inGeneralSegment((char *)shdr[curShdr->sh_info].sh_addr)) { // regular segment
- if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, _segment)) {
- return false;
- }
- } else { // In Shorts segment
- if (!relocate(fd, curShdr->sh_offset, curShdr->sh_size, (void *)_shortsSegment->getOffset())) {
- return false;
- }
- }
-
- }
- }
-
- return true;
-}
-
-
-bool DLObject::load(int fd) {
- DEBUG_ENTER_FUNC();
-
- Elf32_Ehdr ehdr; // ELF header
- Elf32_Phdr phdr; // Program header
- Elf32_Shdr *shdr; // Section header
- bool ret = true;
-
- if (readElfHeader(fd, &ehdr) == false) {
- return false;
- }
-
- for (int i = 0; i < ehdr.e_phnum; i++) { // Load our 2 segments
- PSP_DEBUG_PRINT("Loading segment %d\n", i);
-
- if (readProgramHeaders(fd, &ehdr, &phdr, i) == false)
- return false;
-
- if (!loadSegment(fd, &phdr))
- return false;
- }
-
- if ((shdr = loadSectionHeaders(fd, &ehdr)) == NULL)
- ret = false;
-
- if (ret && ((_symtab_sect = loadSymbolTable(fd, &ehdr, shdr)) < 0))
- ret = false;
-
- if (ret && (loadStringTable(fd, shdr) == false))
- ret = false;
-
- if (ret)
- relocateSymbols((Elf32_Addr)_segment, _shortsSegment->getOffset()); // Offset by our segment allocated address
-
- if (ret && (relocateRels(fd, &ehdr, shdr) == false))
- ret = false;
-
- free(shdr);
-
- return ret;
-}
-
-bool DLObject::open(const char *path) {
- DEBUG_ENTER_FUNC();
- int fd;
- void *ctors_start, *ctors_end;
-
- PSP_DEBUG_PRINT("open(\"%s\")\n", path);
-
- // Get the address of the global pointer
- _gpVal = (unsigned int) & _gp;
- PSP_DEBUG_PRINT("_gpVal is %x\n", _gpVal);
-
- PowerMan.beginCriticalSection();
-
- if ((fd = ::open(path, O_RDONLY)) < 0) {
- PSP_ERROR("%s not found.", path);
- return false;
- }
-
- // Try to load and relocate
- if (!load(fd)) {
- ::close(fd);
- unload();
- return false;
- }
-
- ::close(fd);
-
- PowerMan.endCriticalSection();
-
- // flush data cache
- sceKernelDcacheWritebackAll();
-
- // Get the symbols for the global constructors and destructors
- ctors_start = symbol("___plugin_ctors");
- ctors_end = symbol("___plugin_ctors_end");
- _dtors_start = symbol("___plugin_dtors");
- _dtors_end = symbol("___plugin_dtors_end");
-
- if (ctors_start == NULL || ctors_end == NULL || _dtors_start == NULL ||
- _dtors_end == NULL) {
- PSP_ERROR("Missing ctors/dtors.");
- _dtors_start = _dtors_end = NULL;
- unload();
- return false;
- }
-
- PSP_DEBUG_PRINT("Calling constructors.\n");
- for (void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++)
- (**f)();
-
- PSP_DEBUG_PRINT("%s opened ok.\n", path);
- return true;
-}
-
-bool DLObject::close() {
- DEBUG_ENTER_FUNC();
- if (_dtors_start != NULL && _dtors_end != NULL)
- for (void (**f)(void) = (void (**)(void))_dtors_start; f != _dtors_end; f++)
- (**f)();
- _dtors_start = _dtors_end = NULL;
- unload();
- return true;
-}
-
-void *DLObject::symbol(const char *name) {
- DEBUG_ENTER_FUNC();
- PSP_DEBUG_PRINT("symbol(\"%s\")\n", name);
-
- if (_symtab == NULL || _strtab == NULL || _symbol_cnt < 1) {
- PSP_ERROR("No symbol table loaded.");
- return NULL;
- }
-
- Elf32_Sym *s = (Elf32_Sym *)_symtab;
- for (int c = _symbol_cnt; c--; s++) {
-
- // We can only import symbols that are global or weak in the plugin
- if ((SYM_BIND(s->st_info) == STB_GLOBAL || SYM_BIND(s->st_info) == STB_WEAK) &&
- /*_strtab[s->st_name] == '_' && */ // Try to make this more efficient
- !strcmp(name, _strtab + s->st_name)) {
-
- // We found the symbol
- PSP_DEBUG_PRINT("=> %p\n", (void*)s->st_value);
- return (void*)s->st_value;
- }
- }
-
- PSP_ERROR("Symbol \"%s\" not found.", name);
- return NULL;
-}
-
-
-
-ShortSegmentManager::ShortSegmentManager() {
- DEBUG_ENTER_FUNC();
- _shortsStart = &__plugin_hole_start ;
- _shortsEnd = &__plugin_hole_end;
-}
-
-ShortSegmentManager::Segment *ShortSegmentManager::newSegment(int size, char *origAddr) {
- DEBUG_ENTER_FUNC();
- char *lastAddress = origAddr;
- Common::List<Segment *>::iterator i;
-
- // Find a block that fits, starting from the beginning
- for (i = _list.begin(); i != _list.end(); ++i) {
- char *currAddress = (*i)->getStart();
-
- if ((int)(currAddress - lastAddress) >= size) break;
-
- lastAddress = (*i)->getEnd();
- }
-
- if ((Elf32_Addr)lastAddress & 3)
- lastAddress += 4 - ((Elf32_Addr)lastAddress & 3); // Round up to multiple of 4
-
- if (lastAddress + size > _shortsEnd) {
- PSP_ERROR("No space in shorts segment for %x bytes. Last address is %p, max address is %p.\n",
- size, lastAddress, _shortsEnd);
- return NULL;
- }
-
- Segment *seg = new Segment(lastAddress, size, origAddr); // Create a new segment
-
- if (lastAddress + size > _highestAddress) _highestAddress = lastAddress + size; // Keep track of maximum
-
- _list.insert(i, seg);
-
- PSP_DEBUG_PRINT("Shorts segment size %x allocated. End = %p. Remaining space = %x. Highest so far is %p.\n",
- size, lastAddress + size, _shortsEnd - _list.back()->getEnd(), _highestAddress);
-
- return seg;
-}
-
-void ShortSegmentManager::deleteSegment(ShortSegmentManager::Segment *seg) {
- DEBUG_ENTER_FUNC();
- PSP_DEBUG_PRINT("Deleting shorts segment from %p to %p.\n\n", seg->getStart(), seg->getEnd());
- _list.remove(seg);
- delete seg;
-}
-
-static char dlerr[MAXDLERRLEN];
-
-void *dlopen(const char *filename, int flags) {
- DLObject *obj = new DLObject(dlerr);
- if (obj->open(filename))
- return (void *)obj;
- delete obj;
- return NULL;
-}
-
-int dlclose(void *handle) {
- DLObject *obj = (DLObject *)handle;
- if (obj == NULL) {
- strcpy(dlerr, "Handle is NULL.");
- return -1;
- }
- if (obj->close()) {
- delete obj;
- return 0;
- }
- return -1;
-}
-
-void *dlsym(void *handle, const char *symbol) {
- if (handle == NULL) {
- strcpy(dlerr, "Handle is NULL.");
- return NULL;
- }
- return ((DLObject *)handle)->symbol(symbol);
-}
-
-const char *dlerror() {
- return dlerr;
-}
-
-void dlforgetsyms(void *handle) {
- if (handle != NULL)
- ((DLObject *)handle)->discard_symtab();
-}
-
-
-#endif /* DYNAMIC_MODULES && __PSP__ */
diff --git a/backends/platform/psp/thread.cpp b/backends/platform/psp/thread.cpp
index 916b1e553b..e757c2f575 100644
--- a/backends/platform/psp/thread.cpp
+++ b/backends/platform/psp/thread.cpp
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/osys_psp.h $
- * $Id: osys_psp.h 49173 2010-05-24 03:05:17Z bluddy $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/psp/thread.h b/backends/platform/psp/thread.h
index de1c10a2aa..44394af40a 100644
--- a/backends/platform/psp/thread.h
+++ b/backends/platform/psp/thread.h
@@ -18,8 +18,8 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
- * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/backends/platform/psp/portdefs.h $
- * $Id: portdefs.h 38687 2009-02-21 12:08:52Z joostp $
+ * $URL$
+ * $Id$
*
*/
diff --git a/backends/platform/samsungtv/main.cpp b/backends/platform/samsungtv/main.cpp
index 2c025b750c..a6b8376912 100644
--- a/backends/platform/samsungtv/main.cpp
+++ b/backends/platform/samsungtv/main.cpp
@@ -43,7 +43,7 @@ extern "C" int Game_Main(char *path, char *) {
// Invoke the actual ScummVM main entry point:
int res = scummvm_main(0, 0);
- ((OSystem_SDL *)g_system)->deinit();
+ g_system->quit(); // TODO: Consider removing / replacing this!
return res;
}
diff --git a/backends/platform/sdl/graphics.cpp b/backends/platform/sdl/graphics.cpp
index a97a153f3c..aec90d1352 100644
--- a/backends/platform/sdl/graphics.cpp
+++ b/backends/platform/sdl/graphics.cpp
@@ -1693,6 +1693,7 @@ void OSystem_SDL::drawMouse() {
SDL_Rect dst;
int scale;
+ int width, height;
int hotX, hotY;
dst.x = _mouseCurState.x;
@@ -1700,12 +1701,16 @@ void OSystem_SDL::drawMouse() {
if (!_overlayVisible) {
scale = _videoMode.scaleFactor;
+ width = _videoMode.screenWidth;
+ height = _videoMode.screenHeight;
dst.w = _mouseCurState.vW;
dst.h = _mouseCurState.vH;
hotX = _mouseCurState.vHotX;
hotY = _mouseCurState.vHotY;
} else {
scale = 1;
+ width = _videoMode.overlayWidth;
+ height = _videoMode.overlayHeight;
dst.w = _mouseCurState.rW;
dst.h = _mouseCurState.rH;
hotX = _mouseCurState.rHotX;
diff --git a/backends/platform/sdl/main.cpp b/backends/platform/sdl/main.cpp
index 52bbb59165..ef95a6d256 100644
--- a/backends/platform/sdl/main.cpp
+++ b/backends/platform/sdl/main.cpp
@@ -64,7 +64,7 @@ int main(int argc, char *argv[]) {
// Invoke the actual ScummVM main entry point:
int res = scummvm_main(argc, argv);
- ((OSystem_SDL *)g_system)->deinit();
+ g_system->quit(); // TODO: Consider removing / replacing this!
return res;
}
diff --git a/backends/platform/sdl/sdl.cpp b/backends/platform/sdl/sdl.cpp
index 6686249416..5c50a43daf 100644
--- a/backends/platform/sdl/sdl.cpp
+++ b/backends/platform/sdl/sdl.cpp
@@ -483,7 +483,7 @@ bool OSystem_SDL::getFeatureState(Feature f) {
}
}
-void OSystem_SDL::deinit() {
+void OSystem_SDL::quit() {
if (_cdrom) {
SDL_CDStop(_cdrom);
SDL_CDClose(_cdrom);
@@ -505,14 +505,10 @@ void OSystem_SDL::deinit() {
SDL_Quit();
- // Event Manager requires save manager for storing
+ // Even Manager requires save manager for storing
// recorded events
delete getEventManager();
delete _savefile;
-}
-
-void OSystem_SDL::quit() {
- deinit();
#if !defined(SAMSUNGTV)
exit(0);
diff --git a/backends/platform/sdl/sdl.h b/backends/platform/sdl/sdl.h
index 5c901ba711..ace07f349e 100644
--- a/backends/platform/sdl/sdl.h
+++ b/backends/platform/sdl/sdl.h
@@ -202,8 +202,6 @@ public:
// Quit
virtual void quit(); // overloaded by CE backend
- void deinit();
-
virtual void getTimeAndDate(TimeDate &t) const;
virtual Common::TimerManager *getTimerManager();
diff --git a/backends/plugins/arm-loader.cpp b/backends/plugins/arm-loader.cpp
new file mode 100644
index 0000000000..7e8269220b
--- /dev/null
+++ b/backends/plugins/arm-loader.cpp
@@ -0,0 +1,169 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(ARM_TARGET)
+
+#include "backends/fs/ds/ds-fs.h"
+#include "elf-loader.h"
+#include "dsmain.h"
+#include "arm-loader.h"
+
+#define __DEBUG_PLUGINS__
+
+#ifdef __DEBUG_PLUGINS__
+#define DBG(x,...) consolePrintf(x, ## __VA_ARGS__)
+#else
+#define DBG(x,...)
+#endif
+
+#define seterror(x,...) consolePrintf(x, ## __VA_ARGS__)
+
+/**
+ * Follow the instruction of a relocation section.
+ *
+ * @param DLFile SeekableReadStream of File
+ * @param offset Offset into the File
+ * @param size Size of relocation section
+ *
+ */
+bool ARMDLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) {
+ Elf32_Rel *rel = NULL; //relocation entry
+
+ // Allocate memory for relocation table
+ if (!(rel = (Elf32_Rel *)malloc(size))) {
+ seterror("Out of memory.");
+ return false;
+ }
+
+ // Read in our relocation table
+ if (DLFile->seek(offset, SEEK_SET) < 0 ||
+ DLFile->read(rel, size) != (ssize_t)size) {
+ seterror("Relocation table load failed.");
+ free(rel);
+ return false;
+ }
+
+ // Treat each relocation entry. Loop over all of them
+ int cnt = size / sizeof(*rel);
+
+ DBG("Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment);
+
+ int a = 0;
+ unsigned int relocation = 0;
+
+ // Loop over relocation entries
+ for (int i = 0; i < cnt; i++) {
+
+ // Get the symbol this relocation entry is referring to
+ Elf32_Sym *sym = (Elf32_Sym *)(_symtab) + (REL_INDEX(rel[i].r_info));
+
+ // Get the target instruction in the code
+ unsigned int *target = (unsigned int *)((char *)relSegment + rel[i].r_offset);
+
+ unsigned int origTarget = *target; //Save for debugging
+
+ // Act differently based on the type of relocation
+ switch (REL_TYPE(rel[i].r_info)) {
+
+ case R_ARM_ABS32:
+ if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section.
+ a = *target; // Get full 32 bits of addend
+ relocation = a + (Elf32_Addr)_segment; // Shift by main offset
+
+ *target = relocation;
+
+ DBG("R_ARM_ABS32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target);
+ }
+ break;
+
+ case R_ARM_THM_CALL:
+ DBG("R_ARM_THM_CALL: PC-relative jump, ld takes care of necessary relocation work for us.\n");
+ break;
+
+ case R_ARM_CALL:
+ DBG("R_ARM_CALL: PC-relative jump, ld takes care of necessary relocation work for us.\n");
+ break;
+
+ case R_ARM_JUMP24:
+ DBG("R_ARM_JUMP24: PC-relative jump, ld takes care of all relocation work for us.\n");
+ break;
+
+ case R_ARM_TARGET1:
+ if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section.
+ a = *target; // Get full 32 bits of addend
+ relocation = a + (Elf32_Addr)_segment; // Shift by main offset
+
+ *target = relocation;
+
+ DBG("R_ARM_TARGET1: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target);
+ DBG("Make sure --target1-abs is a flag to LD!\n");
+ }
+ break;
+
+ case R_ARM_V4BX:
+ DBG("R_ARM_V4BX: No relocation calculation necessary.\n");
+ break;
+
+ default:
+ seterror("Unknown relocation type %d.", REL_TYPE(rel[i].r_info));
+ free(rel);
+ return false;
+ }
+
+ }
+
+ free(rel);
+ return true;
+}
+
+bool ARMDLObject::relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
+
+ // Loop over sections, finding relocation sections
+ for (int i = 0; i < ehdr->e_shnum; i++) {
+
+ Elf32_Shdr *curShdr = &(shdr[i]);
+
+ if ((curShdr->sh_type == SHT_REL || curShdr->sh_type == SHT_RELA) && // Check for a relocation section
+ curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size
+ (int)curShdr->sh_link == _symtab_sect && // Check that the sh_link connects to our symbol table
+ curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists
+ (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory
+
+ if (curShdr->sh_type == SHT_RELA) {
+ seterror("RELA entries not supported yet!\n");
+ return false;
+ }
+
+ if (!relocate(DLFile, curShdr->sh_offset, curShdr->sh_size, _segment)) {
+ return false;
+ }
+
+ }
+ }
+
+ return true;
+}
+
+#endif /* defined(DYNAMIC_MODULES) && defined(ARM_TARGET) */
diff --git a/backends/plugins/arm-loader.h b/backends/plugins/arm-loader.h
new file mode 100644
index 0000000000..7f7a1f7f4b
--- /dev/null
+++ b/backends/plugins/arm-loader.h
@@ -0,0 +1,37 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "backends/fs/ds/ds-fs.h"
+#include "elf-loader.h"
+#include "dsmain.h"
+
+class ARMDLObject : public DLObject {
+protected:
+ bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment);
+ bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
+
+public:
+ ARMDLObject() : DLObject() {}
+};
diff --git a/backends/plugins/ds/ds-provider.cpp b/backends/plugins/ds/ds-provider.cpp
new file mode 100644
index 0000000000..7365a2e6e9
--- /dev/null
+++ b/backends/plugins/ds/ds-provider.cpp
@@ -0,0 +1,45 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(__DS__)
+
+#include "backends/plugins/arm-loader.h"
+#include "backends/plugins/elf-provider.h"
+#include "backends/plugins/ds/ds-provider.h"
+
+
+class DSPlugin : public ELFPlugin {
+public:
+ DSPlugin(const Common::String &filename) : ELFPlugin(filename) {}
+
+ DLObject *makeDLObject() { return new ARMDLObject(); }
+};
+
+Plugin* DSPluginProvider::createPlugin(const Common::FSNode &node) const {
+ return new DSPlugin(node.getPath());
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
+
diff --git a/backends/plugins/ds/ds-provider.h b/backends/plugins/ds/ds-provider.h
new file mode 100644
index 0000000000..462c3e3b63
--- /dev/null
+++ b/backends/plugins/ds/ds-provider.h
@@ -0,0 +1,32 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "backends/plugins/elf-provider.h"
+
+class DSPluginProvider : public ELFPluginProvider {
+ Plugin* createPlugin(const Common::FSNode &node) const;
+};
+
+
diff --git a/backends/plugins/ds/plugin.ld b/backends/plugins/ds/plugin.ld
new file mode 100644
index 0000000000..2b2bca9745
--- /dev/null
+++ b/backends/plugins/ds/plugin.ld
@@ -0,0 +1,218 @@
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",
+ "elf32-littlearm")
+OUTPUT_ARCH(arm)
+
+/* PHDRS specifies ELF Program Headers (or segments) to the plugin linker */
+PHDRS {
+ plugin PT_LOAD ; /* Specifies that the plugin segment should be loaded from file */
+}
+
+SECTIONS
+{
+ /* Read-only sections, merged into text segment: */
+ . = 0;
+ .interp : { *(.interp) } : plugin
+ .note.gnu.build-id : { *(.note.gnu.build-id) }
+ .hash : { *(.hash) }
+ .gnu.hash : { *(.gnu.hash) }
+ .dynsym : { *(.dynsym) }
+ .dynstr : { *(.dynstr) }
+ .gnu.version : { *(.gnu.version) }
+ .gnu.version_d : { *(.gnu.version_d) }
+ .gnu.version_r : { *(.gnu.version_r) }
+ .rel.dyn :
+ {
+ *(.rel.init)
+ *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)
+ *(.rel.fini)
+ *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)
+ *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)
+ *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)
+ *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)
+ *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)
+ *(.rel.ctors)
+ *(.rel.dtors)
+ *(.rel.got)
+ *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)
+ PROVIDE_HIDDEN (__rel_iplt_start = .);
+ *(.rel.iplt)
+ PROVIDE_HIDDEN (__rel_iplt_end = .);
+ PROVIDE_HIDDEN (__rela_iplt_start = .);
+ PROVIDE_HIDDEN (__rela_iplt_end = .);
+ }
+ .rela.dyn :
+ {
+ *(.rela.init)
+ *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
+ *(.rela.fini)
+ *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
+ *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
+ *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
+ *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
+ *(.rela.ctors)
+ *(.rela.dtors)
+ *(.rela.got)
+ *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
+ PROVIDE_HIDDEN (__rel_iplt_start = .);
+ PROVIDE_HIDDEN (__rel_iplt_end = .);
+ PROVIDE_HIDDEN (__rela_iplt_start = .);
+ *(.rela.iplt)
+ PROVIDE_HIDDEN (__rela_iplt_end = .);
+ }
+ .rel.plt :
+ {
+ *(.rel.plt)
+ }
+ .rela.plt :
+ {
+ *(.rela.plt)
+ }
+ .init :
+ {
+ KEEP (*(.init))
+ } =0
+ .plt : { *(.plt) }
+ .iplt : { *(.iplt) }
+ .text :
+ {
+ *(.text.unlikely .text.*_unlikely)
+ *(.text .stub .text.* .gnu.linkonce.t.*)
+ /* .gnu.warning sections are handled specially by elf32.em. */
+ *(.gnu.warning)
+ *(.glue_7t) *(.glue_7) *(.vfp11_veneer) *(.v4_bx)
+ } =0
+ .fini :
+ {
+ KEEP (*(.fini))
+ } =0
+ PROVIDE (__etext = .);
+ PROVIDE (_etext = .);
+ PROVIDE (etext = .);
+ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
+ .rodata1 : { *(.rodata1) }
+ .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }
+ __exidx_start = .;
+ .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }
+ __exidx_end = .;
+ .eh_frame_hdr : { *(.eh_frame_hdr) }
+ .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }
+ /* Adjust the address for the data segment. We want to adjust up to
+ the same address within the page on the next page up. */
+ . = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1));
+ /* Exception handling */
+ .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
+ .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
+ /* Thread Local Storage sections */
+ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
+ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
+ .preinit_array :
+ {
+ PROVIDE_HIDDEN (__preinit_array_start = .);
+ KEEP (*(.preinit_array))
+ PROVIDE_HIDDEN (__preinit_array_end = .);
+ }
+ .init_array :
+ {
+ PROVIDE_HIDDEN (__init_array_start = .);
+ KEEP (*(SORT(.init_array.*)))
+ KEEP (*(.init_array))
+ PROVIDE_HIDDEN (__init_array_end = .);
+ }
+ .fini_array :
+ {
+ PROVIDE_HIDDEN (__fini_array_start = .);
+ KEEP (*(.fini_array))
+ KEEP (*(SORT(.fini_array.*)))
+ PROVIDE_HIDDEN (__fini_array_end = .);
+ }
+ .ctors :
+ {
+ ___plugin_ctors = .;
+ KEEP (*(SORT(.ctors.*)))
+ KEEP (*(.ctors))
+ ___plugin_ctors_end = .;
+ }
+ .dtors :
+ {
+ ___plugin_dtors = .;
+ KEEP (*(SORT(.dtors.*)))
+ KEEP (*(.dtors))
+ ___plugin_dtors_end = .;
+ }
+ .jcr : { KEEP (*(.jcr)) }
+ .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }
+ .dynamic : { *(.dynamic) }
+ .got : { *(.got.plt) *(.igot.plt) *(.got) *(.igot) }
+ .data :
+ {
+ __data_start = . ;
+ *(.data .data.* .gnu.linkonce.d.*)
+ SORT(CONSTRUCTORS)
+ }
+ .data1 : { *(.data1) }
+ _edata = .; PROVIDE (edata = .);
+ __bss_start = .;
+ __bss_start__ = .;
+ .bss :
+ {
+ *(.dynbss)
+ *(.bss .bss.* .gnu.linkonce.b.*)
+ *(COMMON)
+ /* Align here to ensure that the .bss section occupies space up to
+ _end. Align after .bss to ensure correct alignment even if the
+ .bss section disappears because there are no input sections.
+ FIXME: Why do we need it? When there is no .bss section, we don't
+ pad the .data section. */
+ . = ALIGN(. != 0 ? 32 / 8 : 1);
+ }
+ _bss_end__ = . ; __bss_end__ = . ;
+ . = ALIGN(32 / 8);
+ . = ALIGN(32 / 8);
+ __end__ = . ;
+ _end = .; PROVIDE (end = .);
+ /* Stabs debugging sections. */
+ .stab 0 : { *(.stab) }
+ .stabstr 0 : { *(.stabstr) }
+ .stab.excl 0 : { *(.stab.excl) }
+ .stab.exclstr 0 : { *(.stab.exclstr) }
+ .stab.index 0 : { *(.stab.index) }
+ .stab.indexstr 0 : { *(.stab.indexstr) }
+ .comment 0 : { *(.comment) }
+ /* DWARF debug sections.
+ Symbols in the DWARF debugging sections are relative to the beginning
+ of the section so we begin them at 0. */
+ /* DWARF 1 */
+ .debug 0 : { *(.debug) }
+ .line 0 : { *(.line) }
+ /* GNU DWARF 1 extensions */
+ .debug_srcinfo 0 : { *(.debug_srcinfo) }
+ .debug_sfnames 0 : { *(.debug_sfnames) }
+ /* DWARF 1.1 and DWARF 2 */
+ .debug_aranges 0 : { *(.debug_aranges) }
+ .debug_pubnames 0 : { *(.debug_pubnames) }
+ /* DWARF 2 */
+ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
+ .debug_abbrev 0 : { *(.debug_abbrev) }
+ .debug_line 0 : { *(.debug_line) }
+ .debug_frame 0 : { *(.debug_frame) }
+ .debug_str 0 : { *(.debug_str) }
+ .debug_loc 0 : { *(.debug_loc) }
+ .debug_macinfo 0 : { *(.debug_macinfo) }
+ /* SGI/MIPS DWARF 2 extensions */
+ .debug_weaknames 0 : { *(.debug_weaknames) }
+ .debug_funcnames 0 : { *(.debug_funcnames) }
+ .debug_typenames 0 : { *(.debug_typenames) }
+ .debug_varnames 0 : { *(.debug_varnames) }
+ /* DWARF 3 */
+ .debug_pubtypes 0 : { *(.debug_pubtypes) }
+ .debug_ranges 0 : { *(.debug_ranges) }
+ .stack 0x80000 :
+ {
+ _stack = .;
+ *(.stack)
+ }
+ .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }
+ .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }
+ /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
+}
diff --git a/backends/plugins/elf-loader.cpp b/backends/plugins/elf-loader.cpp
new file mode 100644
index 0000000000..9787c880ae
--- /dev/null
+++ b/backends/plugins/elf-loader.cpp
@@ -0,0 +1,413 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
+
+#include <string.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <malloc.h> // for memalign() (Linux specific)
+#include <unistd.h>
+#include <sys/fcntl.h>
+#include <sys/_default_fcntl.h> // FIXME: Why do we need this DevKitPro specific header?
+
+#include "common/file.h"
+#include "common/fs.h"
+#include "elf-loader.h"
+
+#ifdef __PSP__
+#include "backends/platform/psp/powerman.h"
+#include "psputils.h"
+#endif
+
+#ifdef __DS__
+#include <nds.h>
+#endif
+
+#define __DEBUG_PLUGINS__
+
+#ifdef __DEBUG_PLUGINS__
+#define DBG(x,...) printf(x, ## __VA_ARGS__)
+#else
+#define DBG(x,...)
+#endif
+
+#define seterror(x,...) printf(x, ## __VA_ARGS__)
+
+/**
+ * Flushes the data cache (Platform Specific).
+ */
+static void flushDataCache() {
+#ifdef __DS__
+ DC_FlushAll();
+#endif
+#ifdef __PLAYSTATION2__
+ FlushCache(0);
+ FlushCache(2);
+#endif
+#ifdef __PSP__
+ sceKernelDcacheWritebackAll();
+#endif
+}
+
+// Expel the symbol table from memory
+void DLObject::discard_symtab() {
+ free(_symtab);
+ free(_strtab);
+ _symtab = NULL;
+ _strtab = NULL;
+ _symbol_cnt = 0;
+}
+
+// Unload all objects from memory
+void DLObject::unload() {
+ discard_symtab();
+ free(_segment);
+ _segment = NULL;
+}
+
+bool DLObject::readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) {
+
+ // Start reading the elf header. Check for errors
+ if (DLFile->read(ehdr, sizeof(*ehdr)) != sizeof(*ehdr) ||
+ memcmp(ehdr->e_ident, ELFMAG, SELFMAG) || // Check MAGIC
+ ehdr->e_type != ET_EXEC || // Check for executable
+#ifdef ARM_TARGET
+ ehdr->e_machine != EM_ARM || // Check for ARM machine type
+#endif
+#ifdef MIPS_TARGET
+ ehdr->e_machine != EM_MIPS || // Check for MIPS machine type
+#endif
+ ehdr->e_phentsize < sizeof(Elf32_Phdr) || // Check for size of program header
+ ehdr->e_shentsize != sizeof(Elf32_Shdr)) { // Check for size of section header
+ seterror("Invalid file type.");
+ return false;
+ }
+
+ DBG("phoff = %d, phentsz = %d, phnum = %d\n",
+ ehdr->e_phoff, ehdr->e_phentsize, ehdr->e_phnum);
+
+ return true;
+}
+
+bool DLObject::readProgramHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num) {
+
+ // Read program header
+ if (DLFile->seek(ehdr->e_phoff + sizeof(*phdr)*num, SEEK_SET) < 0 ||
+ DLFile->read(phdr, sizeof(*phdr)) != sizeof(*phdr)) {
+ seterror("Program header load failed.");
+ return false;
+ }
+
+ // Check program header values
+ if (phdr->p_type != PT_LOAD || phdr->p_filesz > phdr->p_memsz) {
+ seterror("Invalid program header.");
+ return false;
+ }
+
+ DBG("offs = %x, filesz = %x, memsz = %x, align = %x\n",
+ phdr->p_offset, phdr->p_filesz, phdr->p_memsz, phdr->p_align);
+
+ return true;
+
+}
+
+bool DLObject::loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr) {
+
+ char *baseAddress = 0;
+
+ // Attempt to allocate memory for segment
+ int extra = phdr->p_vaddr % phdr->p_align; // Get extra length TODO: check logic here
+ DBG("extra mem is %x\n", extra);
+
+ if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) {
+ seterror("Out of memory.\n");
+ return false;
+ }
+
+ DBG("allocated segment @ %p\n", _segment);
+
+ // Get offset to load segment into
+ baseAddress = (char *)_segment + phdr->p_vaddr;
+ _segmentSize = phdr->p_memsz + extra;
+
+ // Set bss segment to 0 if necessary (assumes bss is at the end)
+ if (phdr->p_memsz > phdr->p_filesz) {
+ DBG("Setting %p to %p to 0 for bss\n", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz);
+ memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
+ }
+
+ DBG("Reading the segment into memory\n");
+
+ // Read the segment into memory
+ if (DLFile->seek(phdr->p_offset, SEEK_SET) < 0 ||
+ DLFile->read(baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) {
+ seterror("Segment load failed.");
+ return false;
+ }
+
+ DBG("Segment has been read into memory\n");
+
+ return true;
+}
+
+Elf32_Shdr * DLObject::loadSectionHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) {
+
+ Elf32_Shdr *shdr = NULL;
+
+ // Allocate memory for section headers
+ if (!(shdr = (Elf32_Shdr *)malloc(ehdr->e_shnum * sizeof(*shdr)))) {
+ seterror("Out of memory.");
+ return NULL;
+ }
+
+ // Read from file into section headers
+ if (DLFile->seek(ehdr->e_shoff, SEEK_SET) < 0 ||
+ DLFile->read(shdr, ehdr->e_shnum * sizeof(*shdr)) !=
+ (ssize_t)(ehdr->e_shnum * sizeof(*shdr))) {
+ seterror("Section headers load failed.");
+ return NULL;
+ }
+
+ return shdr;
+}
+
+int DLObject::loadSymbolTable(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
+
+ // Loop over sections, looking for symbol table linked to a string table
+ for (int i = 0; i < ehdr->e_shnum; i++) {
+ if (shdr[i].sh_type == SHT_SYMTAB &&
+ shdr[i].sh_entsize == sizeof(Elf32_Sym) &&
+ shdr[i].sh_link < ehdr->e_shnum &&
+ shdr[shdr[i].sh_link].sh_type == SHT_STRTAB &&
+ _symtab_sect < 0) {
+ _symtab_sect = i;
+ }
+ }
+
+ // Check for no symbol table
+ if (_symtab_sect < 0) {
+ seterror("No symbol table.");
+ return -1;
+ }
+
+ DBG("Symbol section at section %d, size %x\n", _symtab_sect, shdr[_symtab_sect].sh_size);
+
+ // Allocate memory for symbol table
+ if (!(_symtab = malloc(shdr[_symtab_sect].sh_size))) {
+ seterror("Out of memory.");
+ return -1;
+ }
+
+ // Read symbol table into memory
+ if (DLFile->seek(shdr[_symtab_sect].sh_offset, SEEK_SET) < 0 ||
+ DLFile->read(_symtab, shdr[_symtab_sect].sh_size) !=
+ (ssize_t)shdr[_symtab_sect].sh_size) {
+ seterror("Symbol table load failed.");
+ return -1;
+ }
+
+ // Set number of symbols
+ _symbol_cnt = shdr[_symtab_sect].sh_size / sizeof(Elf32_Sym);
+ DBG("Loaded %d symbols.\n", _symbol_cnt);
+
+ return _symtab_sect;
+
+}
+
+bool DLObject::loadStringTable(Common::SeekableReadStream* DLFile, Elf32_Shdr *shdr) {
+
+ int string_sect = shdr[_symtab_sect].sh_link;
+
+ // Allocate memory for string table
+ if (!(_strtab = (char *)malloc(shdr[string_sect].sh_size))) {
+ seterror("Out of memory.");
+ return false;
+ }
+
+ // Read string table into memory
+ if (DLFile->seek(shdr[string_sect].sh_offset, SEEK_SET) < 0 ||
+ DLFile->read(_strtab, shdr[string_sect].sh_size) !=
+ (ssize_t)shdr[string_sect].sh_size) {
+ seterror("Symbol table strings load failed.");
+ return false;
+ }
+
+ return true;
+}
+
+void DLObject::relocateSymbols(Elf32_Addr offset) {
+
+ int mainCount = 0;
+ int shortsCount= 0;
+
+ // Loop over symbols, add relocation offset
+ Elf32_Sym *s = (Elf32_Sym *)_symtab;
+ for (int c = _symbol_cnt; c--; s++) {
+
+ // Make sure we don't relocate special valued symbols
+ if (s->st_shndx < SHN_LOPROC) {
+ mainCount++;
+ s->st_value += offset;
+ if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize)
+ seterror("Symbol out of bounds! st_value = %x\n", s->st_value);
+ }
+ }
+}
+
+bool DLObject::load(Common::SeekableReadStream* DLFile) {
+ Elf32_Ehdr ehdr;
+ Elf32_Phdr phdr;
+ Elf32_Shdr *shdr;
+ bool ret = true;
+
+ if (readElfHeader(DLFile, &ehdr) == false) {
+ return false;
+ }
+
+ for (int i = 0; i < ehdr.e_phnum; i++) { //Load our segments
+
+ DBG("Loading segment %d\n", i);
+
+ if (readProgramHeaders(DLFile, &ehdr, &phdr, i) == false)
+ return false;
+
+ if (!loadSegment(DLFile, &phdr))
+ return false;
+ }
+
+ if ((shdr = loadSectionHeaders(DLFile, &ehdr)) == NULL)
+ ret = false;
+
+ if (ret && ((_symtab_sect = loadSymbolTable(DLFile, &ehdr, shdr)) < 0))
+ ret = false;
+
+ if (ret && (loadStringTable(DLFile, shdr) == false))
+ ret = false;
+
+ if (ret)
+ relocateSymbols((Elf32_Addr)_segment); // Offset by our segment allocated address
+
+ if (ret && (relocateRels(DLFile, &ehdr, shdr) == false))
+ ret = false;
+
+ free(shdr);
+
+ return ret;
+
+}
+
+bool DLObject::open(const char *path) {
+
+ Common::SeekableReadStream* DLFile;
+ void *ctors_start, *ctors_end;
+
+#ifdef __PSP__
+ PowerMan.beginCriticalSection();
+#endif
+
+ DBG("open(\"%s\")\n", path);
+
+ Common::FSNode file(path);
+
+ if (!(DLFile = file.createReadStream())) {
+ seterror("%s not found.", path);
+ return false;
+ }
+
+ DBG("%s found!\n", path);
+
+ /*Try to load and relocate*/
+ if (!load(DLFile)) {
+ unload();
+ return false;
+ }
+
+ DBG("loaded!/n");
+
+#ifdef __PSP__
+ PowerMan.endCriticalSection();
+#endif
+
+ flushDataCache();
+
+ ctors_start = symbol("___plugin_ctors");
+ ctors_end = symbol("___plugin_ctors_end");
+ _dtors_start = symbol("___plugin_dtors");
+ _dtors_end = symbol("___plugin_dtors_end");
+
+ if (ctors_start == NULL || ctors_end == NULL || _dtors_start == NULL ||
+ _dtors_end == NULL) {
+ seterror("Missing ctors/dtors.");
+ _dtors_start = _dtors_end = NULL;
+ unload();
+ return false;
+ }
+
+ DBG(("Calling constructors.\n"));
+ for (void (**f)(void) = (void (**)(void))ctors_start; f != ctors_end; f++)
+ (**f)();
+
+ DBG(("%s opened ok.\n", path));
+
+ return true;
+}
+
+bool DLObject::close() {
+ if (_dtors_start != NULL && _dtors_end != NULL)
+ for (void (**f)(void) = (void (**)(void))_dtors_start; f != _dtors_end; f++)
+ (**f)();
+ _dtors_start = _dtors_end = NULL;
+ unload();
+ return true;
+}
+
+void *DLObject::symbol(const char *name) {
+ DBG(("symbol(\"%s\")\n", name));
+
+ if (_symtab == NULL || _strtab == NULL || _symbol_cnt < 1) {
+ seterror("No symbol table loaded.");
+ return NULL;
+ }
+
+ Elf32_Sym *s = (Elf32_Sym *)_symtab;
+ for (int c = _symbol_cnt; c--; s++)
+
+ // We can only import symbols that are global or weak in the plugin
+ if ((SYM_BIND(s->st_info) == STB_GLOBAL || SYM_BIND(s->st_info) == STB_WEAK) &&
+ !strcmp(name, _strtab + s->st_name)) {
+
+ // We found the symbol
+ DBG("=> %p\n", (void*)s->st_value);
+ return (void*)s->st_value;
+ }
+
+ // We didn't find the symbol
+ seterror("Symbol \"%s\" not found.", name);
+ return NULL;
+}
+
+#endif /* defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET) */
+
diff --git a/backends/plugins/elf-loader.h b/backends/plugins/elf-loader.h
new file mode 100644
index 0000000000..1d30aa0c3b
--- /dev/null
+++ b/backends/plugins/elf-loader.h
@@ -0,0 +1,67 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef ELF_LOADER_H
+#define ELF_LOADER_H
+
+#include "elf32.h"
+#include "common/stream.h"
+#include "backends/plugins/dynamic-plugin.h"
+
+class DLObject {
+protected:
+ void *_segment, *_symtab;
+ char *_strtab;
+ int _symbol_cnt;
+ int _symtab_sect;
+ void *_dtors_start, *_dtors_end;
+
+ int _segmentSize;
+
+ //void seterror(const char *fmt, ...);
+ virtual void unload();
+ virtual bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) = 0;
+ bool load(Common::SeekableReadStream* DLFile);
+
+ bool readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr);
+ bool readProgramHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num);
+ virtual bool loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr);
+ Elf32_Shdr *loadSectionHeaders(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr);
+ int loadSymbolTable(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
+ bool loadStringTable(Common::SeekableReadStream* DLFile, Elf32_Shdr *shdr);
+ virtual void relocateSymbols(Elf32_Addr offset);
+ virtual bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) = 0;
+
+public:
+ bool open(const char *path);
+ bool close();
+ void *symbol(const char *name);
+ void discard_symtab();
+
+ DLObject() : _segment(NULL), _symtab(NULL), _strtab(NULL), _symbol_cnt(0),
+ _symtab_sect(-1), _dtors_start(NULL), _dtors_end(NULL), _segmentSize(0) {}
+};
+
+#endif /* ELF_LOADER_H */
diff --git a/backends/plugins/elf-provider.cpp b/backends/plugins/elf-provider.cpp
new file mode 100644
index 0000000000..e6edd4c578
--- /dev/null
+++ b/backends/plugins/elf-provider.cpp
@@ -0,0 +1,105 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
+
+#include "backends/plugins/elf-provider.h"
+#include "backends/plugins/dynamic-plugin.h"
+#include "common/fs.h"
+
+#include "backends/plugins/elf-loader.h"
+
+DynamicPlugin::VoidFunc ELFPlugin::findSymbol(const char *symbol) {
+ void *func;
+ bool handleNull;
+ if (_dlHandle == NULL) {
+ func = NULL;
+ handleNull = true;
+ } else {
+ func = _dlHandle->symbol(symbol);
+ }
+ if (!func) {
+ if (handleNull) {
+ warning("Failed loading symbol '%s' from plugin '%s' (Handle is NULL)", symbol, _filename.c_str());
+ } else {
+ warning("Failed loading symbol '%s' from plugin '%s'", symbol, _filename.c_str());
+ }
+ }
+
+ // FIXME HACK: This is a HACK to circumvent a clash between the ISO C++
+ // standard and POSIX: ISO C++ disallows casting between function pointers
+ // and data pointers, but dlsym always returns a void pointer. For details,
+ // see e.g. <http://www.trilithium.com/johan/2004/12/problem-with-dlsym/>.
+ assert(sizeof(VoidFunc) == sizeof(func));
+ VoidFunc tmp;
+ memcpy(&tmp, &func, sizeof(VoidFunc));
+ return tmp;
+}
+
+bool ELFPlugin::loadPlugin() {
+ assert(!_dlHandle);
+ DLObject *obj = makeDLObject();
+ if (obj->open(_filename.c_str())) {
+ _dlHandle = obj;
+ } else {
+ delete obj;
+ _dlHandle = NULL;
+ }
+
+ if (!_dlHandle) {
+ warning("Failed loading plugin '%s'", _filename.c_str());
+ return false;
+ }
+
+ bool ret = DynamicPlugin::loadPlugin();
+
+ if (ret && _dlHandle) {
+ _dlHandle->discard_symtab();
+ }
+
+ return ret;
+};
+
+void ELFPlugin::unloadPlugin() {
+ DynamicPlugin::unloadPlugin();
+ if (_dlHandle) {
+ if (!_dlHandle->close()) {
+ warning("Failed unloading plugin '%s'", _filename.c_str());
+ }
+ delete _dlHandle;
+ _dlHandle = 0;
+ }
+}
+
+bool ELFPluginProvider::isPluginFilename(const Common::FSNode &node) const {
+ // Check the plugin suffix
+ Common::String filename = node.getName();
+ if (!filename.hasSuffix(".PLG") && !filename.hasSuffix(".plg") && !filename.hasSuffix(".PLUGIN") && !filename.hasSuffix(".plugin")) {
+ return false;
+ }
+ return true;
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
diff --git a/backends/plugins/elf-provider.h b/backends/plugins/elf-provider.h
new file mode 100644
index 0000000000..e0382c3e45
--- /dev/null
+++ b/backends/plugins/elf-provider.h
@@ -0,0 +1,70 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_PLUGINS_ELF_PROVIDER_H
+#define BACKENDS_PLUGINS_ELF_PROVIDER_H
+
+#include "base/plugins.h"
+#include "backends/plugins/dynamic-plugin.h"
+#include "common/fs.h"
+
+#include "backends/plugins/elf-loader.h"
+
+#if defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
+
+class ELFPlugin : public DynamicPlugin {
+protected:
+ DLObject *_dlHandle;
+ Common::String _filename;
+
+ virtual VoidFunc findSymbol(const char *symbol);
+
+public:
+ ELFPlugin(const Common::String &filename)
+ : _dlHandle(0), _filename(filename) {}
+
+ ~ELFPlugin() {
+ if (_dlHandle)
+ unloadPlugin();
+ }
+
+ virtual DLObject *makeDLObject() = 0;
+
+ bool loadPlugin();
+ void unloadPlugin();
+
+};
+
+class ELFPluginProvider : public FilePluginProvider {
+protected:
+ virtual Plugin* createPlugin(const Common::FSNode &node) const = 0;
+
+ bool isPluginFilename(const Common::FSNode &node) const;
+
+};
+
+#endif // defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
+
+#endif /* BACKENDS_PLUGINS_ELF_PROVIDER_H */
diff --git a/backends/plugins/elf32.h b/backends/plugins/elf32.h
new file mode 100644
index 0000000000..5dec1d2e58
--- /dev/null
+++ b/backends/plugins/elf32.h
@@ -0,0 +1,229 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#ifndef BACKENDS_ELF_H
+#define BACKENDS_ELF_H
+
+/* ELF stuff */
+
+typedef unsigned short Elf32_Half, Elf32_Section;
+typedef unsigned int Elf32_Word, Elf32_Addr, Elf32_Off;
+typedef signed int Elf32_Sword;
+typedef Elf32_Half Elf32_Versym;
+
+#define EI_NIDENT (16)
+#define SELFMAG 6
+
+/* ELF File format structures. Look up ELF structure for more details */
+
+// ELF header (contains info about the file)
+typedef struct {
+ unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
+ Elf32_Half e_type; /* Object file type */
+ Elf32_Half e_machine; /* Architecture */
+ Elf32_Word e_version; /* Object file version */
+ Elf32_Addr e_entry; /* Entry point virtual address */
+ Elf32_Off e_phoff; /* Program header table file offset */
+ Elf32_Off e_shoff; /* Section header table file offset */
+ Elf32_Word e_flags; /* Processor-specific flags */
+ Elf32_Half e_ehsize; /* ELF header size in bytes */
+ Elf32_Half e_phentsize; /* Program header table entry size */
+ Elf32_Half e_phnum; /* Program header table entry count */
+ Elf32_Half e_shentsize; /* Section header table entry size */
+ Elf32_Half e_shnum; /* Section header table entry count */
+ Elf32_Half e_shstrndx; /* Section header string table index */
+} Elf32_Ehdr;
+
+// Should be in e_ident
+#define ELFMAG "\177ELF\1\1" /* ELF Magic number */
+
+// e_type values
+#define ET_NONE 0 /* no file type */
+#define ET_REL 1 /* relocatable */
+#define ET_EXEC 2 /* executable */
+#define ET_DYN 3 /* shared object */
+#define ET_CORE 4 /* core file */
+
+// e_machine values
+#define EM_MIPS 8
+#define EM_ARM 40
+
+// Program header (contains info about segment)
+typedef struct {
+ Elf32_Word p_type; /* Segment type */
+ Elf32_Off p_offset; /* Segment file offset */
+ Elf32_Addr p_vaddr; /* Segment virtual address */
+ Elf32_Addr p_paddr; /* Segment physical address */
+ Elf32_Word p_filesz; /* Segment size in file */
+ Elf32_Word p_memsz; /* Segment size in memory */
+ Elf32_Word p_flags; /* Segment flags */
+ Elf32_Word p_align; /* Segment alignment */
+} Elf32_Phdr;
+
+// p_type values
+#define PT_NULL 0 /* ignored */
+#define PT_LOAD 1 /* loadable segment */
+#define PT_DYNAMIC 2 /* dynamic linking info */
+#define PT_INTERP 3 /* info about interpreter */
+#define PT_NOTE 4 /* note segment */
+#define PT_SHLIB 5 /* reserved */
+#define PT_PHDR 6 /* Program header table */
+#define PT_MIPS_REGINFO 0x70000000 /* Register usage info for MIPS */
+#define PT_ARM_ARCHEXT 0x70000000 /* Platform architecture compatibility info for ARM */
+#define PT_ARM_EXIDX 0x70000001 /* Exception unwind tables for ARM */
+
+// p_flags value
+#define PF_X 1 /* execute */
+#define PF_W 2 /* write */
+#define PF_R 4 /* read */
+
+// Section header (contains info about section)
+typedef struct {
+ Elf32_Word sh_name; /* Section name (string tbl index) */
+ Elf32_Word sh_type; /* Section type */
+ Elf32_Word sh_flags; /* Section flags */
+ Elf32_Addr sh_addr; /* Section virtual addr at execution */
+ Elf32_Off sh_offset; /* Section file offset */
+ Elf32_Word sh_size; /* Section size in bytes */
+ Elf32_Word sh_link; /* Link to another section */
+ Elf32_Word sh_info; /* Additional section information */
+ Elf32_Word sh_addralign; /* Section alignment */
+ Elf32_Word sh_entsize; /* Entry size if section holds table */
+} Elf32_Shdr;
+
+// sh_type values
+#define SHT_NULL 0 /* Inactive section */
+#define SHT_PROGBITS 1 /* Proprietary */
+#define SHT_SYMTAB 2 /* Symbol table */
+#define SHT_STRTAB 3 /* String table */
+#define SHT_RELA 4 /* Relocation entries with addend */
+#define SHT_HASH 5 /* Symbol hash table */
+#define SHT_DYNAMIC 6 /* Info for dynamic linking */
+#define SHT_NOTE 7 /* Note section */
+#define SHT_NOBITS 8 /* Occupies no space */
+#define SHT_REL 9 /* Relocation entries without addend */
+#define SHT_SHLIB 10 /* Reserved */
+#define SHT_DYNSYM 11 /* Minimal set of dynamic linking symbols */
+#define SHT_MIPS_LIBLSIT 0x70000000 /* Info about dynamic shared object libs for MIPS*/
+#define SHT_MIPS_CONFLICT 0x70000002 /* Conflicts btw executables and shared objects for MIPS */
+#define SHT_MIPS_GPTAB 0x70000003 /* Global pointer table for MIPS*/
+#define SHT_ARM_EXIDX 0x70000001 /* Exception Index table for ARM*/
+#define SHT_ARM_PREEMPTMAP 0x70000002 /* BPABI DLL dynamic linking pre-emption map for ARM */
+#define SHT_ARM_ATTRIBUTES 0x70000003 /* Object file compatibility attributes for ARM*/
+
+// sh_flags values
+#define SHF_WRITE 0 /* writable section */
+#define SHF_ALLOC 2 /* section occupies memory */
+#define SHF_EXECINSTR 4 /* machine instructions */
+#define SHF_MIPS_GPREL 0x10000000 /* Must be made part of global data area for MIPS */
+
+// Symbol entry (contain info about a symbol)
+typedef struct {
+ Elf32_Word st_name; /* Symbol name (string tbl index) */
+ Elf32_Addr st_value; /* Symbol value */
+ Elf32_Word st_size; /* Symbol size */
+ unsigned char st_info; /* Symbol type and binding */
+ unsigned char st_other; /* Symbol visibility */
+ Elf32_Section st_shndx; /* Section index */
+} Elf32_Sym;
+
+// Extract from the st_info
+#define SYM_TYPE(x) ((x)&0xF)
+#define SYM_BIND(x) ((x)>>4)
+
+// Symbol binding values from st_info
+#define STB_LOCAL 0 /* Symbol not visible outside object */
+#define STB_GLOBAL 1 /* Symbol visible to all object files */
+#define STB_WEAK 2 /* Similar to STB_GLOBAL */
+
+// Symbol type values from st_info
+#define STT_NOTYPE 0 /* Not specified */
+#define STT_OBJECT 1 /* Data object e.g. variable */
+#define STT_FUNC 2 /* Function */
+#define STT_SECTION 3 /* Section */
+#define STT_FILE 4 /* Source file associated with object file */
+
+// Special section header index values from st_shndex
+#define SHN_UNDEF 0
+#define SHN_LOPROC 0xFF00 /* Extended values */
+#define SHN_ABS 0xFFF1 /* Absolute value: don't relocate */
+#define SHN_COMMON 0xFFF2 /* Common block. Not allocated yet */
+#define SHN_HIPROC 0xFF1F
+#define SHN_HIRESERVE 0xFFFF
+
+// Relocation entry with implicit addend (info about how to relocate)
+typedef struct {
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+} Elf32_Rel;
+
+// Relocation entry with explicit addend (info about how to relocate)
+typedef struct
+{
+ Elf32_Addr r_offset; /* Address */
+ Elf32_Word r_info; /* Relocation type and symbol index */
+ Elf32_Sword r_addend; /* Addend */
+} Elf32_Rela;
+
+// Access macros for the relocation info
+#define REL_TYPE(x) ((unsigned char) (x)) /* Extract relocation type */
+#define REL_INDEX(x) ((x)>>8) /* Extract relocation index into symbol table */
+
+//MIPS relocation types
+#define R_MIPS_NONE 0
+#define R_MIPS_16 1
+#define R_MIPS_32 2
+#define R_MIPS_REL32 3
+#define R_MIPS_26 4
+#define R_MIPS_HI16 5
+#define R_MIPS_LO16 6
+#define R_MIPS_GPREL16 7
+#define R_MIPS_LITERAL 8
+#define R_MIPS_GOT16 9
+#define R_MIPS_PC16 10
+#define R_MIPS_CALL16 11
+#define R_MIPS_GPREL32 12
+#define R_MIPS_GOTHI16 13
+#define R_MIPS_GOTLO16 14
+#define R_MIPS_CALLHI16 15
+#define R_MIPS_CALLLO16 16
+
+// ARM relocation types
+#define R_ARM_NONE 0
+#define R_ARM_ABS32 2
+#define R_ARM_THM_CALL 10
+#define R_ARM_CALL 28
+#define R_ARM_JUMP24 29
+#define R_ARM_TARGET1 38
+#define R_ARM_V4BX 40
+
+// Mock function to get value of global pointer for MIPS
+#define getGP() ({ \
+ unsigned int __valgp; \
+ __asm__ ("add %0, $gp, $0" : "=r"(__valgp) : ); \
+ __valgp; \
+})
+
+#endif /* BACKENDS_ELF_H */
diff --git a/backends/plugins/mips-loader.cpp b/backends/plugins/mips-loader.cpp
new file mode 100644
index 0000000000..7b59a2cffa
--- /dev/null
+++ b/backends/plugins/mips-loader.cpp
@@ -0,0 +1,351 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(MIPS_TARGET)
+
+#include "mips-loader.h"
+
+#define __DEBUG_PLUGINS__
+
+#ifdef __DEBUG_PLUGINS__
+#define DBG(x,...) printf(x, ## __VA_ARGS__)
+#else
+#define DBG(x,...)
+#endif
+
+#define seterror(x,...) printf(x, ## __VA_ARGS__)
+
+/**
+ * Follow the instruction of a relocation section.
+ *
+ * @param DLFile SeekableReadStream of File
+ * @param offset Offset into the File
+ * @param size Size of relocation section
+ * @param relSegment Base address of relocated segment in memory (memory offset)
+ *
+ */
+bool MIPSDLObject::relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment) {
+ Elf32_Rel *rel = NULL; // relocation entry
+
+ // Allocate memory for relocation table
+ if (!(rel = (Elf32_Rel *)malloc(size))) {
+ seterror("Out of memory.");
+ return false;
+ }
+
+ // Read in our relocation table
+ if (DLFile->seek(offset, SEEK_SET) < 0 ||
+ DLFile->read(rel, size) != (ssize_t)size) {
+ seterror("Relocation table load failed.");
+ free(rel);
+ return false;
+ }
+
+ // Treat each relocation entry. Loop over all of them
+ int cnt = size / sizeof(*rel);
+
+ DBG("Loaded relocation table. %d entries. base address=%p\n", cnt, relSegment);
+
+ bool seenHi16 = false; // For treating HI/LO16 commands
+ int firstHi16 = -1; // Mark the point of the first hi16 seen
+ Elf32_Addr ahl = 0; // Calculated addend
+ int a = 0; // Addend: taken from the target
+
+ unsigned int *lastTarget = 0; // For processing hi16 when lo16 arrives
+ unsigned int relocation = 0;
+ int debugRelocs[10] = {0}; // For debugging
+ int extendedHi16 = 0; // Count extended hi16 treatments
+ Elf32_Addr lastHiSymVal = 0;
+ bool hi16InShorts = false;
+
+#define DEBUG_NUM 2
+
+ // Loop over relocation entries
+ for (int i = 0; i < cnt; i++) {
+ // Get the symbol this relocation entry is referring to
+ Elf32_Sym *sym = (Elf32_Sym *)(_symtab) + (REL_INDEX(rel[i].r_info));
+
+ // Get the target instruction in the code
+ unsigned int *target = (unsigned int *)((char *)relSegment + rel[i].r_offset);
+
+ unsigned int origTarget = *target; // Save for debugging
+
+ // Act differently based on the type of relocation
+ switch (REL_TYPE(rel[i].r_info)) {
+
+ case R_MIPS_HI16: // Absolute addressing.
+ if (sym->st_shndx < SHN_LOPROC && // Only shift for plugin section (ie. has a real section index)
+ firstHi16 < 0) { // Only process first in block of HI16s
+ firstHi16 = i; // Keep the first Hi16 we saw
+ seenHi16 = true;
+ ahl = (*target & 0xffff) << 16; // Take lower 16 bits shifted up
+
+ lastHiSymVal = sym->st_value;
+ hi16InShorts = (ShortsMan.inGeneralSegment((char *)sym->st_value)); // Fix for problem with switching btw segments
+ if (debugRelocs[0]++ < DEBUG_NUM) // Print only a set number
+ DBG("R_MIPS_HI16: i=%d, offset=%x, ahl = %x, target = %x\n",
+ i, rel[i].r_offset, ahl, *target);
+ }
+ break;
+
+ case R_MIPS_LO16: // Absolute addressing. Needs a HI16 to come before it
+ if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section. (ie. has a real section index)
+ if (!seenHi16) { // We MUST have seen HI16 first
+ seterror("R_MIPS_LO16 w/o preceding R_MIPS_HI16 at relocation %d!\n", i);
+ free(rel);
+ return false;
+ }
+
+ // Fix: bug in gcc makes LO16s connect to wrong HI16s sometimes (shorts and regular segment)
+ // Note that we can check the entire shorts segment because the executable's shorts don't belong to this plugin section
+ // and will be screened out above
+ bool lo16InShorts = ShortsMan.inGeneralSegment((char *)sym->st_value);
+
+ // Correct the bug by getting the proper value in ahl (taken from the current symbol)
+ if ((hi16InShorts && !lo16InShorts) || (!hi16InShorts && lo16InShorts)) {
+ ahl -= (lastHiSymVal & 0xffff0000); // We assume gcc meant the same offset
+ ahl += (sym->st_value & 0xffff0000);
+ }
+
+ ahl &= 0xffff0000; // Clean lower 16 bits for repeated LO16s
+ a = *target & 0xffff; // Take lower 16 bits of the target
+ a = (a << 16) >> 16; // Sign extend them
+ ahl += a; // Add lower 16 bits. AHL is now complete
+
+ // Fix: we can have LO16 access to the short segment sometimes
+ if (lo16InShorts) {
+ relocation = ahl + _shortsSegment->getOffset(); // Add in the short segment offset
+ } else // It's in the regular segment
+ relocation = ahl + (Elf32_Addr)_segment; // Add in the new offset for the segment
+
+ if (firstHi16 >= 0) { // We haven't treated the HI16s yet so do it now
+ for (int j = firstHi16; j < i; j++) {
+ if (REL_TYPE(rel[j].r_info) != R_MIPS_HI16) continue; // Skip over non-Hi16s
+
+ lastTarget = (unsigned int *)((char *)relSegment + rel[j].r_offset); // get hi16 target
+ *lastTarget &= 0xffff0000; // Clear the lower 16 bits of the last target
+ *lastTarget |= (relocation >> 16) & 0xffff; // Take the upper 16 bits of the relocation
+ if (relocation & 0x8000)(*lastTarget)++; // Subtle: we need to add 1 to the HI16 in this case
+ }
+ firstHi16 = -1; // Reset so we'll know we treated it
+ } else {
+ extendedHi16++;
+ }
+
+ *target &= 0xffff0000; // Clear the lower 16 bits of current target
+ *target |= relocation & 0xffff; // Take the lower 16 bits of the relocation
+
+ if (debugRelocs[1]++ < DEBUG_NUM)
+ DBG("R_MIPS_LO16: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n",
+ i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target);
+ if (lo16InShorts && debugRelocs[2]++ < DEBUG_NUM)
+ DBG("R_MIPS_LO16s: i=%d, offset=%x, a=%x, ahl = %x, lastTarget = %x, origt = %x, target = %x\n",
+ i, rel[i].r_offset, a, ahl, *lastTarget, origTarget, *target);
+ }
+ break;
+
+ case R_MIPS_26: // Absolute addressing (for jumps and branches only)
+ if (sym->st_shndx < SHN_LOPROC) { // Only relocate for main segment
+ a = *target & 0x03ffffff; // Get 26 bits' worth of the addend
+ a = (a << 6) >> 6; // Sign extend a
+ relocation = ((a << 2) + (Elf32_Addr)_segment) >> 2; // a already points to the target. Subtract our offset
+ *target &= 0xfc000000; // Clean lower 26 target bits
+ *target |= (relocation & 0x03ffffff);
+
+ if (debugRelocs[3]++ < DEBUG_NUM)
+ DBG("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n",
+ i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target);
+ } else {
+ if (debugRelocs[4]++ < DEBUG_NUM)
+ DBG("R_MIPS_26: i=%d, offset=%x, symbol=%d, stinfo=%x, a=%x, origTarget=%x, target=%x\n",
+ i, rel[i].r_offset, REL_INDEX(rel[i].r_info), sym->st_info, a, origTarget, *target);
+ }
+ break;
+
+ case R_MIPS_GPREL16: // GP Relative addressing
+ if (_shortsSegment->getOffset() != 0 && // Only relocate if we shift the shorts section
+ ShortsMan.inGeneralSegment((char *)sym->st_value)) { // Only relocate things in the plugin hole
+ a = *target & 0xffff; // Get 16 bits' worth of the addend
+ a = (a << 16) >> 16; // Sign extend it
+
+ relocation = a + _shortsSegment->getOffset();
+
+ *target &= 0xffff0000; // Clear the lower 16 bits of the target
+ *target |= relocation & 0xffff;
+
+ if (debugRelocs[5]++ < DEBUG_NUM)
+ DBG("R_MIPS_GPREL16: i=%d, a=%x, gpVal=%x, origTarget=%x, target=%x, offset=%x\n",
+ i, a, _gpVal, origTarget, *target, _shortsSegment->getOffset());
+ }
+
+ break;
+
+ case R_MIPS_32: // Absolute addressing
+ if (sym->st_shndx < SHN_LOPROC) { // Only shift for plugin section.
+ a = *target; // Get full 32 bits of addend
+
+ if (ShortsMan.inGeneralSegment((char *)sym->st_value)) // Check if we're in the shorts segment
+ relocation = a + _shortsSegment->getOffset(); // Shift by shorts offset
+ else // We're in the main section
+ relocation = a + (Elf32_Addr)_segment; // Shift by main offset
+ *target = relocation;
+
+ if (debugRelocs[6]++ < DEBUG_NUM)
+ DBG("R_MIPS_32: i=%d, a=%x, origTarget=%x, target=%x\n", i, a, origTarget, *target);
+ }
+ break;
+
+ default:
+ seterror("Unknown relocation type %x at relocation %d.\n", REL_TYPE(rel[i].r_info), i);
+ free(rel);
+ return false;
+ }
+ }
+
+ DBG("Done with relocation. extendedHi16=%d\n\n", extendedHi16);
+
+ free(rel);
+ return true;
+}
+
+bool MIPSDLObject::relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) {
+
+ // Loop over sections, finding relocation sections
+ for (int i = 0; i < ehdr->e_shnum; i++) {
+
+ Elf32_Shdr *curShdr = &(shdr[i]);
+ //Elf32_Shdr *linkShdr = &(shdr[curShdr->sh_info]);
+
+ if (curShdr->sh_type == SHT_REL && // Check for a relocation section
+ curShdr->sh_entsize == sizeof(Elf32_Rel) && // Check for proper relocation size
+ (int)curShdr->sh_link == _symtab_sect && // Check that the sh_link connects to our symbol table
+ curShdr->sh_info < ehdr->e_shnum && // Check that the relocated section exists
+ (shdr[curShdr->sh_info].sh_flags & SHF_ALLOC)) { // Check if relocated section resides in memory
+ if (!ShortsMan.inGeneralSegment((char *)shdr[curShdr->sh_info].sh_addr)) { // regular segment
+ if (!relocate(DLFile, curShdr->sh_offset, curShdr->sh_size, _segment)) {
+ return false;
+ }
+ } else { // In Shorts segment
+ if (!relocate(DLFile, curShdr->sh_offset, curShdr->sh_size, (void *)_shortsSegment->getOffset())) {
+ return false;
+ }
+ }
+
+ }
+ }
+
+ return true;
+}
+
+void MIPSDLObject::relocateSymbols(Elf32_Addr offset) {
+
+ int mainCount = 0;
+ int shortsCount= 0;
+
+ // Loop over symbols, add relocation offset
+ Elf32_Sym *s = (Elf32_Sym *)_symtab;
+ for (int c = _symbol_cnt; c--; s++) {
+
+ // Make sure we don't relocate special valued symbols
+ if (s->st_shndx < SHN_LOPROC) {
+ if (!ShortsMan.inGeneralSegment((char *)s->st_value)) {
+ mainCount++;
+ s->st_value += offset;
+ if (s->st_value < (Elf32_Addr)_segment || s->st_value > (Elf32_Addr)_segment + _segmentSize)
+ seterror("Symbol out of bounds! st_value = %x\n", s->st_value);
+ } else { // shorts section
+ shortsCount++;
+ s->st_value += _shortsSegment->getOffset();
+ if (!_shortsSegment->inSegment((char *)s->st_value))
+ seterror("Symbol out of bounds! st_value = %x\n", s->st_value);
+ }
+
+ }
+ }
+}
+
+bool MIPSDLObject::loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr) {
+
+ char *baseAddress = 0;
+
+ // We need to take account of non-allocated segment for shorts
+ if (phdr->p_flags & PF_X) { // This is a relocated segment
+
+ // Attempt to allocate memory for segment
+ int extra = phdr->p_vaddr % phdr->p_align; // Get extra length TODO: check logic here
+ DBG("extra mem is %x\n", extra);
+
+ if (phdr->p_align < 0x10000) phdr->p_align = 0x10000; // Fix for wrong alignment on e.g. AGI
+
+ if (!(_segment = (char *)memalign(phdr->p_align, phdr->p_memsz + extra))) {
+ seterror("Out of memory.\n");
+ return false;
+ }
+ DBG("allocated segment @ %p\n", _segment);
+
+ // Get offset to load segment into
+ baseAddress = (char *)_segment + phdr->p_vaddr;
+ _segmentSize = phdr->p_memsz + extra;
+ } else { // This is a shorts section.
+ _shortsSegment = ShortsMan.newSegment(phdr->p_memsz, (char *)phdr->p_vaddr);
+
+ baseAddress = _shortsSegment->getStart();
+ DBG("shorts segment @ %p to %p. Segment wants to be at %x. Offset=%x\n",
+ _shortsSegment->getStart(), _shortsSegment->getEnd(), phdr->p_vaddr, _shortsSegment->getOffset());
+ }
+
+ // Set bss segment to 0 if necessary (assumes bss is at the end)
+ if (phdr->p_memsz > phdr->p_filesz) {
+ DBG("Setting %p to %p to 0 for bss\n", baseAddress + phdr->p_filesz, baseAddress + phdr->p_memsz);
+ memset(baseAddress + phdr->p_filesz, 0, phdr->p_memsz - phdr->p_filesz);
+ }
+
+ DBG("Reading the segment into memory\n");
+
+ // Read the segment into memory
+ if (DLFile->seek(phdr->p_offset, SEEK_SET) < 0 ||
+ DLFile->read(baseAddress, phdr->p_filesz) != (ssize_t)phdr->p_filesz) {
+ seterror("Segment load failed.");
+ return false;
+ }
+
+ DBG("Segment has been read into memory\n");
+
+ return true;
+}
+
+// Unload all objects from memory
+void MIPSDLObject::unload() {
+ discard_symtab();
+ free(_segment);
+ _segment = NULL;
+
+ if (_shortsSegment) {
+ ShortsMan.deleteSegment(_shortsSegment);
+ _shortsSegment = NULL;
+ }
+}
+
+#endif /* defined(DYNAMIC_MODULES) && defined(MIPS_TARGET) */
diff --git a/backends/plugins/mips-loader.h b/backends/plugins/mips-loader.h
new file mode 100644
index 0000000000..eb22e368f4
--- /dev/null
+++ b/backends/plugins/mips-loader.h
@@ -0,0 +1,46 @@
+
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "elf-loader.h"
+#include "shorts-segment-manager.h"
+
+class MIPSDLObject : public DLObject {
+protected:
+ ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges
+ unsigned int _gpVal; // Value of Global Pointer
+
+ bool relocate(Common::SeekableReadStream* DLFile, unsigned long offset, unsigned long size, void *relSegment);
+ bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
+ void relocateSymbols(Elf32_Addr offset);
+ bool loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr);
+ void unload();
+
+public:
+ MIPSDLObject() : DLObject() {
+ _shortsSegment = NULL;
+ _gpVal = 0;
+ }
+};
diff --git a/backends/platform/psp/plugin.syms b/backends/plugins/plugin.syms
index 24ee1a19dc..24ee1a19dc 100644
--- a/backends/platform/psp/plugin.syms
+++ b/backends/plugins/plugin.syms
diff --git a/backends/plugins/ps2/main_prog.ld b/backends/plugins/ps2/main_prog.ld
new file mode 100644
index 0000000000..9dba69c50e
--- /dev/null
+++ b/backends/plugins/ps2/main_prog.ld
@@ -0,0 +1,99 @@
+ENTRY(_start);
+
+SECTIONS {
+ .text 0x00100000: {
+ _ftext = . ;
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t*)
+ KEEP(*(.init))
+ KEEP(*(.fini))
+ QUAD(0)
+ }
+
+ PROVIDE(_etext = .);
+ PROVIDE(etext = .);
+
+ .reginfo : { *(.reginfo) }
+
+ /* Global/static constructors and deconstructors. */
+ .ctors ALIGN(16): {
+ KEEP(*crtbegin*.o(.ctors))
+ KEEP(*(EXCLUDE_FILE(*crtend*.o) .ctors))
+ KEEP(*(SORT(.ctors.*)))
+ KEEP(*(.ctors))
+ }
+ .dtors ALIGN(16): {
+ KEEP(*crtbegin*.o(.dtors))
+ KEEP(*(EXCLUDE_FILE(*crtend*.o) .dtors))
+ KEEP(*(SORT(.dtors.*)))
+ KEEP(*(.dtors))
+ }
+
+ /* Static data. */
+ .rodata ALIGN(128): {
+ *(.rodata)
+ *(.rodata.*)
+ *(.gnu.linkonce.r*)
+ }
+
+ .data ALIGN(128): {
+ _fdata = . ;
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d*)
+ SORT(CONSTRUCTORS)
+ }
+
+ .rdata ALIGN(128): { *(.rdata) }
+ .gcc_except_table ALIGN(128): { *(.gcc_except_table) }
+
+ _gp = ALIGN(128) + 0x7ff0;
+ .lit4 ALIGN(128): { *(.lit4) }
+ .lit8 ALIGN(128): { *(.lit8) }
+
+ .sdata ALIGN(128): {
+ *(.sdata)
+ *(.sdata.*)
+ *(.gnu.linkonce.s*)
+ }
+
+ _edata = .;
+ PROVIDE(edata = .);
+
+ /* Uninitialized data. */
+ .sbss ALIGN(128) : {
+ _fbss = . ;
+ *(.sbss)
+ *(.sbss.*)
+ *(.gnu.linkonce.sb*)
+ *(.scommon)
+ }
+
+ /*This "plugin hole" is so the plugins can all have global small data
+ in the same place.*/
+ __plugin_hole_start = .;
+ . = _gp + 0x7ff0;
+ __plugin_hole_end = .;
+
+ COMMON :
+ {
+ *(COMMON)
+ }
+ . = ALIGN(128);
+
+ .bss ALIGN(128) : {
+ *(.bss)
+ *(.bss.*)
+ *(.gnu.linkonce.b*)
+ }
+ _end_bss = .;
+
+ _end = . ;
+ PROVIDE(end = .);
+
+ /* Symbols needed by crt0.s. */
+ PROVIDE(_heap_size = -1);
+ PROVIDE(_stack = -1);
+ PROVIDE(_stack_size = 128 * 1024);
+}
diff --git a/backends/plugins/ps2/plugin.ld b/backends/plugins/ps2/plugin.ld
new file mode 100644
index 0000000000..9879413b98
--- /dev/null
+++ b/backends/plugins/ps2/plugin.ld
@@ -0,0 +1,94 @@
+/* PHDRS specifies ELF Program Headers (or segments) to the plugin linker */
+PHDRS {
+ plugin PT_LOAD ; /* Specifies that the plugin segment should be loaded from file */
+ shorts PT_LOAD ; /* Specifies that the shorts segment should be loaded from file */
+}
+SECTIONS {
+ .text 0: {
+ _ftext = . ;
+ *(.text)
+ *(.text.*)
+ *(.gnu.linkonce.t*)
+ KEEP(*(.init))
+ KEEP(*(.fini))
+ QUAD(0)
+ } : plugin /*The ": plugin" tells the linker to assign this and
+ the following sections to the "plugin" segment*/
+ PROVIDE(_etext = .);
+ PROVIDE(etext = .);
+
+ .reginfo : { *(.reginfo) }
+
+ /* Global/static constructors and deconstructors. */
+ .ctors ALIGN(16): {
+ ___plugin_ctors = .;
+ KEEP(*(SORT(.ctors.*)))
+ KEEP(*(.ctors))
+ ___plugin_ctors_end = .;
+ }
+ .dtors ALIGN(16): {
+ ___plugin_dtors = .;
+ KEEP(*(SORT(.dtors.*)))
+ KEEP(*(.dtors))
+ ___plugin_dtors_end = .;
+ }
+
+ /* Static data. */
+ .rodata ALIGN(128): {
+ *(.rodata)
+ *(.rodata.*)
+ *(.gnu.linkonce.r*)
+ }
+
+ .data ALIGN(128): {
+ _fdata = . ;
+ *(.data)
+ *(.data.*)
+ *(.gnu.linkonce.d*)
+ SORT(CONSTRUCTORS)
+ }
+
+ .rdata ALIGN(128): { *(.rdata) }
+ .gcc_except_table ALIGN(128): { *(.gcc_except_table) }
+
+ .bss ALIGN(128) : {
+ *(.bss)
+ *(.bss.*)
+ *(.gnu.linkonce.b*)
+ *(COMMON)
+ }
+ _end_bss = .;
+
+ _end = . ;
+ PROVIDE(end = .);
+
+ /* Symbols needed by crt0.s. */
+ PROVIDE(_heap_size = -1);
+ PROVIDE(_stack = -1);
+ PROVIDE(_stack_size = 128 * 1024);
+
+ /*We assign the output location counter to the plugin hole made
+ in main_prog.ld, then assign the small data sections to the shorts segment*/
+ . = __plugin_hole_start;
+ .lit4 ALIGN(128): { *(.lit4) } : shorts
+ .lit8 ALIGN(128): { *(.lit8) }
+
+ .sdata ALIGN(128): {
+ *(.sdata)
+ *(.sdata.*)
+ *(.gnu.linkonce.s*)
+ }
+
+ _edata = .;
+ PROVIDE(edata = .);
+
+ /* Uninitialized data. */
+ .sbss ALIGN(128) : {
+ _fbss = . ;
+ *(.sbss)
+ *(.sbss.*)
+ *(.gnu.linkonce.sb*)
+ *(.scommon)
+ }
+
+}
diff --git a/backends/plugins/ps2/ps2-provider.cpp b/backends/plugins/ps2/ps2-provider.cpp
new file mode 100644
index 0000000000..096c6d4050
--- /dev/null
+++ b/backends/plugins/ps2/ps2-provider.cpp
@@ -0,0 +1,44 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(__PLAYSTATION2__)
+
+#include "backends/plugins/mips-loader.h"
+#include "backends/plugins/elf-provider.h"
+#include "backends/plugins/ps2/ps2-provider.h"
+
+
+class PS2Plugin : public ELFPlugin {
+public:
+ PS2Plugin(const Common::String &filename) : ELFPlugin(filename) {}
+
+ DLObject *makeDLObject() { return new MIPSDLObject(); }
+};
+
+Plugin* PS2PluginProvider::createPlugin(const Common::FSNode &node) const {
+ return new PS2Plugin(node.getPath());
+}
+
+#endif // defined(DYNAMIC_MODULES) && defined(ELF_LOADER_TARGET)
diff --git a/backends/plugins/ps2/ps2-provider.h b/backends/plugins/ps2/ps2-provider.h
new file mode 100644
index 0000000000..28a2321c29
--- /dev/null
+++ b/backends/plugins/ps2/ps2-provider.h
@@ -0,0 +1,31 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "backends/plugins/elf-provider.h"
+
+class PS2PluginProvider : public ELFPluginProvider {
+ Plugin* createPlugin(const Common::FSNode &node) const;
+};
+
diff --git a/backends/platform/psp/plugin.ld b/backends/plugins/psp/plugin.ld
index db4df45264..db4df45264 100644
--- a/backends/platform/psp/plugin.ld
+++ b/backends/plugins/psp/plugin.ld
diff --git a/backends/plugins/psp/psp-provider.cpp b/backends/plugins/psp/psp-provider.cpp
index 5760424cbf..99aa33c123 100644
--- a/backends/plugins/psp/psp-provider.cpp
+++ b/backends/plugins/psp/psp-provider.cpp
@@ -25,86 +25,20 @@
#if defined(DYNAMIC_MODULES) && defined(__PSP__)
+#include "backends/plugins/mips-loader.h"
+#include "backends/plugins/elf-provider.h"
#include "backends/plugins/psp/psp-provider.h"
-#include "backends/plugins/dynamic-plugin.h"
-#include "common/fs.h"
-#include "backends/platform/psp/psploader.h"
-
-#include "backends/platform/psp/trace.h"
-
-
-class PSPPlugin : public DynamicPlugin {
-protected:
- void *_dlHandle;
- Common::String _filename;
-
- virtual VoidFunc findSymbol(const char *symbol) {
- void *func = dlsym(_dlHandle, symbol);
- if (!func)
- warning("Failed loading symbol '%s' from plugin '%s' (%s)", symbol, _filename.c_str(), dlerror());
-
- // FIXME HACK: This is a HACK to circumvent a clash between the ISO C++
- // standard and POSIX: ISO C++ disallows casting between function pointers
- // and data pointers, but dlsym always returns a void pointer. For details,
- // see e.g. <http://www.trilithium.com/johan/2004/12/problem-with-dlsym/>.
- assert(sizeof(VoidFunc) == sizeof(func));
- VoidFunc tmp;
- memcpy(&tmp, &func, sizeof(VoidFunc));
- return tmp;
- }
+class PSPPlugin : public ELFPlugin {
public:
- PSPPlugin(const Common::String &filename)
- : _dlHandle(0), _filename(filename) {}
-
- ~PSPPlugin() {
- if (_dlHandle) unloadPlugin();
- }
-
- bool loadPlugin() {
- assert(!_dlHandle);
- _dlHandle = dlopen(_filename.c_str(), RTLD_LAZY);
-
- if (!_dlHandle) {
- warning("Failed loading plugin '%s' (%s)", _filename.c_str(), dlerror());
- return false;
- }
+ PSPPlugin(const Common::String &filename) : ELFPlugin(filename) {}
- bool ret = DynamicPlugin::loadPlugin();
-
- if (ret)
- dlforgetsyms(_dlHandle);
-
- return ret;
- }
-
- void unloadPlugin() {
- DynamicPlugin::unloadPlugin();
- if (_dlHandle) {
- if (dlclose(_dlHandle) != 0)
- warning("Failed unloading plugin '%s' (%s)", _filename.c_str(), dlerror());
- _dlHandle = 0;
- }
- }
+ DLObject *makeDLObject() { return new MIPSDLObject(); }
};
-
Plugin* PSPPluginProvider::createPlugin(const Common::FSNode &node) const {
return new PSPPlugin(node.getPath());
}
-bool PSPPluginProvider::isPluginFilename(const Common::FSNode &node) const {
- // Check the plugin suffix
- Common::String filename = node.getName();
- PSP_DEBUG_PRINT("Testing name %s", filename.c_str());
- if (!filename.hasSuffix(".PLG") && !filename.hasSuffix(".plg")) {
- PSP_DEBUG_PRINT(" fail.\n");
- return false;
- }
-
- PSP_DEBUG_PRINT(" success!\n");
- return true;
-}
-
#endif // defined(DYNAMIC_MODULES) && defined(__PSP__)
diff --git a/backends/plugins/psp/psp-provider.h b/backends/plugins/psp/psp-provider.h
index d6c44c5a85..c4debc7997 100644
--- a/backends/plugins/psp/psp-provider.h
+++ b/backends/plugins/psp/psp-provider.h
@@ -26,16 +26,12 @@
#ifndef BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H
#define BACKENDS_PLUGINS_PSP_PSP_PROVIDER_H
-#include "base/plugins.h"
+#include "backends/plugins/elf-provider.h"
#if defined(DYNAMIC_MODULES) && defined(__PSP__)
-class PSPPluginProvider : public FilePluginProvider {
-protected:
+class PSPPluginProvider : public ELFPluginProvider {
Plugin* createPlugin(const Common::FSNode &node) const;
-
- bool isPluginFilename(const Common::FSNode &node) const;
-
};
#endif // defined(DYNAMIC_MODULES) && defined(__PSP__)
diff --git a/backends/plugins/shorts-segment-manager.cpp b/backends/plugins/shorts-segment-manager.cpp
new file mode 100644
index 0000000000..2376759919
--- /dev/null
+++ b/backends/plugins/shorts-segment-manager.cpp
@@ -0,0 +1,89 @@
+/* ScummVM - Graphic Adventure Engine
+ *
+ * ScummVM is the legal property of its developers, whose names
+ * are too numerous to list here. Please refer to the COPYRIGHT
+ * file distributed with this source distribution.
+ *
+ * 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.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#if defined(DYNAMIC_MODULES) && defined(MIPS_TARGET)
+
+#include "shorts-segment-manager.h"
+
+extern char __plugin_hole_start; // Indicates start of hole in program file for shorts
+extern char __plugin_hole_end; // Indicates end of hole in program file
+extern char _gp[]; // Value of gp register
+
+#ifdef DEBUG_PLUGINS
+#define DBG(x,...) printf(x, ## __VA_ARGS__)
+#else
+#define DBG(x,...)
+#endif
+
+#define seterror(x,...) printf(x, ## __VA_ARGS__)
+
+DECLARE_SINGLETON(ShortSegmentManager); // For singleton
+
+ShortSegmentManager::ShortSegmentManager() {
+ _shortsStart = &__plugin_hole_start ; //shorts segment begins at the plugin hole we made when linking
+ _shortsEnd = &__plugin_hole_end; //and ends at the end of that hole.
+}
+
+ShortSegmentManager::Segment *ShortSegmentManager::newSegment(int size, char *origAddr) {
+ char *lastAddress = origAddr;
+ Common::List<Segment *>::iterator i;
+
+ // Find a block that fits, starting from the beginning
+ for (i = _list.begin(); i != _list.end(); ++i) {
+ char *currAddress = (*i)->getStart();
+
+ if ((int)(currAddress - lastAddress) >= size) break;
+
+ lastAddress = (*i)->getEnd();
+ }
+
+ if ((Elf32_Addr)lastAddress & 3)
+ lastAddress += 4 - ((Elf32_Addr)lastAddress & 3); // Round up to multiple of 4
+
+ if (lastAddress + size > _shortsEnd) {
+ seterror("Error. No space in shorts segment for %x bytes. Last address is %p, max address is %p.\n",
+ size, lastAddress, _shortsEnd);
+ return NULL;
+ }
+
+ Segment *seg = new Segment(lastAddress, size, origAddr); // Create a new segment
+
+ if (lastAddress + size > _highestAddress) _highestAddress = lastAddress + size; // Keep track of maximum
+
+ _list.insert(i, seg);
+
+ DBG("Shorts segment size %x allocated. End = %p. Remaining space = %x. Highest so far is %p.\n",
+ size, lastAddress + size, _shortsEnd - _list.back()->getEnd(), _highestAddress);
+
+ return seg;
+}
+
+void ShortSegmentManager::deleteSegment(ShortSegmentManager::Segment *seg) {
+ DBG("Deleting shorts segment from %p to %p.\n\n", seg->getStart(), seg->getEnd());
+ _list.remove(seg);
+ delete seg;
+}
+
+#endif /* DYNAMIC_MODULES && MIPS_TARGET */
diff --git a/backends/platform/psp/psploader.h b/backends/plugins/shorts-segment-manager.h
index 13dcf6ef98..54a13d88e1 100644
--- a/backends/platform/psp/psploader.h
+++ b/backends/plugins/shorts-segment-manager.h
@@ -23,17 +23,21 @@
*
*/
-#ifndef PSPLOADER_H
-#define PSPLOADER_H
+#ifndef SHORTS_SEGMENT_MANAGER_H
+#define SHORTS_SEGMENT_MANAGER_H
-#include "elf32.h"
-#include "common/list.h"
#include "common/singleton.h"
+#include "common/list.h"
+#include "elf32.h"
-#define MAXDLERRLEN 80
-
-#define ShortsMan ShortSegmentManager::instance()
+#define ShortsMan ShortSegmentManager::instance()
+/**
+ * Manages the segments of small data put in the gp-relative area for MIPS processors,
+ * and lets these segments be handled differently in the ELF loader.
+ * Since there's no true dynamic linker to change the GP register between plugins and the main engine,
+ * custom linker scripts ensure the GP-area is in the same place for both.
+ */
class ShortSegmentManager : public Common::Singleton<ShortSegmentManager> {
private:
char *_shortsStart;
@@ -43,6 +47,8 @@ public:
char *getShortsStart() {
return _shortsStart;
}
+
+ // Returns whether or not an absolute address is in the GP-relative section.
bool inGeneralSegment(char *addr) {
return ((char *)addr >= _shortsStart && (char *)addr < _shortsEnd);
}
@@ -80,58 +86,4 @@ private:
char *_highestAddress;
};
-
-
-
-class DLObject {
-protected:
- char *_errbuf; /* For error messages, at least MAXDLERRLEN in size */
-
- ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges
- void *_segment, *_symtab;
- char *_strtab;
- int _symbol_cnt;
- int _symtab_sect;
- void *_dtors_start, *_dtors_end;
-
- unsigned int _gpVal; // Value of Global Pointer
- int _segmentSize;
-
- void seterror(const char *fmt, ...);
- void unload();
- bool relocate(int fd, unsigned long offset, unsigned long size, void *);
- bool load(int fd);
-
- bool readElfHeader(int fd, Elf32_Ehdr *ehdr);
- bool readProgramHeaders(int fd, Elf32_Ehdr *ehdr, Elf32_Phdr *phdr, int num);
- bool loadSegment(int fd, Elf32_Phdr *phdr);
- Elf32_Shdr *loadSectionHeaders(int fd, Elf32_Ehdr *ehdr);
- int loadSymbolTable(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
- bool loadStringTable(int fd, Elf32_Shdr *shdr);
- void relocateSymbols(Elf32_Addr offset, Elf32_Addr shortsOffset);
- bool relocateRels(int fd, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr);
-
-public:
- bool open(const char *path);
- bool close();
- void *symbol(const char *name);
- void discard_symtab();
-
- DLObject(char *errbuf = NULL) : _errbuf(_errbuf), _shortsSegment(NULL), _segment(NULL), _symtab(NULL),
- _strtab(NULL), _symbol_cnt(0), _symtab_sect(-1), _dtors_start(NULL), _dtors_end(NULL), _gpVal(0) ,
- _segmentSize(0) {}
-};
-
-
-
-#define RTLD_LAZY 0
-
-extern "C" {
- void *dlopen(const char *filename, int flags);
- int dlclose(void *handle);
- void *dlsym(void *handle, const char *symbol);
- const char *dlerror();
- void dlforgetsyms(void *handle);
-}
-
-#endif /* PSPLOADER_H */
+#endif /* SHORTS_SEGMENT_MANAGER_H */
diff --git a/backends/saves/default/default-saves.cpp b/backends/saves/default/default-saves.cpp
index 1ab898d2d6..55aa469309 100644
--- a/backends/saves/default/default-saves.cpp
+++ b/backends/saves/default/default-saves.cpp
@@ -131,11 +131,11 @@ bool DefaultSaveFileManager::removeSavefile(const Common::String &filename) {
// There is a nicely portable workaround, too: Make this method overloadable.
if (remove(file.getPath().c_str()) != 0) {
#ifndef _WIN32_WCE
- if (errno == EACCES)
+ if (errno == EACCES)
setError(Common::kWritePermissionDenied, "Search or write permission denied: "+file.getName());
if (errno == ENOENT)
- setError(Common::kPathDoesNotExist, "removeSavefile: '"+file.getName()+"' does not exist or path is invalid");
+ setError(Common::kPathDoesNotExist, "removeSavefile: '"+file.getName()+"' does not exist or path is invalid");
#endif
return false;
} else {
diff --git a/base/main.cpp b/base/main.cpp
index e651456ace..8564d64c26 100644
--- a/base/main.cpp
+++ b/base/main.cpp
@@ -105,7 +105,12 @@ static const EnginePlugin *detectPlugin() {
// Query the plugins and find one that will handle the specified gameid
printf("User picked target '%s' (gameid '%s')...\n", ConfMan.getActiveDomainName().c_str(), gameid.c_str());
printf("%s", " Looking for a plugin supporting this gameid... ");
- GameDescriptor game = EngineMan.findGame(gameid, &plugin);
+
+#if defined(NEW_PLUGIN_DESIGN_FIRST_REFINEMENT) && defined(DYNAMIC_MODULES)
+ GameDescriptor game = EngineMan.findGameOnePlugAtATime(gameid, &plugin);
+#else
+ GameDescriptor game = EngineMan.findGame(gameid, &plugin);
+#endif
if (plugin == 0) {
printf("failed\n");
@@ -339,8 +344,12 @@ extern "C" int scummvm_main(int argc, const char * const argv[]) {
settings.erase("debugflags");
}
- // Load the plugins.
- PluginManager::instance().loadPlugins();
+#if defined(NEW_PLUGIN_DESIGN_FIRST_REFINEMENT) && defined(DYNAMIC_MODULES) //note: I'm going to refactor this name later :P
+ // Don't load the plugins initially in this case.
+#else
+ // Load the plugins.
+ PluginManager::instance().loadPlugins();
+#endif
// If we received an invalid music parameter via command line we check this here.
// We can't check this before loading the music plugins.
diff --git a/base/plugins.cpp b/base/plugins.cpp
index 5d0be11065..61cc747a41 100644
--- a/base/plugins.cpp
+++ b/base/plugins.cpp
@@ -302,6 +302,31 @@ void PluginManager::addPluginProvider(PluginProvider *pp) {
_providers.push_back(pp);
}
+bool PluginManager::loadFirstPlugin() { //TODO: only deal with engine plugins here, and have a separate "loadNonEnginePlugins" function.
+ unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL);
+ PluginList plugs;
+ for (ProviderList::iterator pp = _providers.begin();
+ pp != _providers.end();
+ ++pp) {
+ PluginList pl((*pp)->getPlugins());
+ for (PluginList::iterator p = pl.begin(); p != pl.end(); ++p) {
+ plugs.push_back(*p);
+ }
+ }
+ _pluginsEnd = plugs.end();
+ _currentPlugin = plugs.begin();
+ if (plugs.empty()) return false; //return false if there are no plugins to load.
+ return tryLoadPlugin(*_currentPlugin);
+}
+
+bool PluginManager::loadNextPlugin() {
+ // To ensure only one engine plugin is loaded at a time, we unload all engine plugins before loading a new one.
+ unloadPluginsExcept(PLUGIN_TYPE_ENGINE, NULL);
+ ++_currentPlugin;
+ if (_currentPlugin == _pluginsEnd) return false; //return false if already reached the end of list of plugins.
+ return tryLoadPlugin(*_currentPlugin);
+}
+
void PluginManager::loadPlugins() {
for (ProviderList::iterator pp = _providers.begin();
pp != _providers.end();
@@ -309,7 +334,6 @@ void PluginManager::loadPlugins() {
PluginList pl((*pp)->getPlugins());
Common::for_each(pl.begin(), pl.end(), Common::bind1st(Common::mem_fun(&PluginManager::tryLoadPlugin), this));
}
-
}
void PluginManager::unloadPlugins() {
@@ -340,7 +364,7 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) {
// The plugin is valid, see if it provides the same module as an
// already loaded one and should replace it.
bool found = false;
-
+ printf("Plugin loaded is %s\n", plugin->getName());
PluginList::iterator pl = _plugins[plugin->getType()].begin();
while (!found && pl != _plugins[plugin->getType()].end()) {
if (!strcmp(plugin->getName(), (*pl)->getName())) {
@@ -366,13 +390,24 @@ bool PluginManager::tryLoadPlugin(Plugin *plugin) {
}
}
-
// Engine plugins
#include "engines/metaengine.h"
DECLARE_SINGLETON(EngineManager)
+GameDescriptor EngineManager::findGameOnePlugAtATime(const Common::String &gameName, const EnginePlugin **plugin) const {
+ GameDescriptor result;
+ PluginManager::instance().loadFirstPlugin();
+ do {
+ result = findGame(gameName, plugin);
+ if (!result.gameid().empty()) {
+ break;
+ }
+ } while (PluginManager::instance().loadNextPlugin());
+ return result;
+}
+
GameDescriptor EngineManager::findGame(const Common::String &gameName, const EnginePlugin **plugin) const {
// Find the GameDescriptor for this target
const EnginePlugin::List &plugins = getPlugins();
@@ -381,30 +416,36 @@ GameDescriptor EngineManager::findGame(const Common::String &gameName, const Eng
if (plugin)
*plugin = 0;
- EnginePlugin::List::const_iterator iter = plugins.begin();
- for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
- result = (**iter)->findGame(gameName.c_str());
- if (!result.gameid().empty()) {
- if (plugin)
- *plugin = *iter;
- break;
+ EnginePlugin::List::const_iterator iter;
+
+ for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
+ result = (**iter)->findGame(gameName.c_str());
+ if (!result.gameid().empty()) {
+ if (plugin)
+ *plugin = *iter;
+ return result;
+ }
}
- }
return result;
}
GameList EngineManager::detectGames(const Common::FSList &fslist) const {
GameList candidates;
-
- const EnginePlugin::List &plugins = getPlugins();
-
- // Iterate over all known games and for each check if it might be
- // the game in the presented directory.
+ EnginePlugin::List plugins;
EnginePlugin::List::const_iterator iter;
- for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
- candidates.push_back((**iter)->detectGames(fslist));
- }
-
+#if defined(NEW_PLUGIN_DESIGN_FIRST_REFINEMENT) && defined(DYNAMIC_MODULES)
+ PluginManager::instance().loadFirstPlugin();
+ do {
+#endif
+ plugins = getPlugins();
+ // Iterate over all known games and for each check if it might be
+ // the game in the presented directory.
+ for (iter = plugins.begin(); iter != plugins.end(); ++iter) {
+ candidates.push_back((**iter)->detectGames(fslist));
+ }
+#if defined(NEW_PLUGIN_DESIGN_FIRST_REFINEMENT) && defined(DYNAMIC_MODULES)
+ } while (PluginManager::instance().loadNextPlugin());
+#endif
return candidates;
}
diff --git a/base/plugins.h b/base/plugins.h
index a4c7f114f9..975c815783 100644
--- a/base/plugins.h
+++ b/base/plugins.h
@@ -275,9 +275,11 @@ class PluginManager : public Common::Singleton<PluginManager> {
private:
PluginList _plugins[PLUGIN_TYPE_MAX];
ProviderList _providers;
-
+ PluginList::iterator _currentPlugin;
+ PluginList::iterator _pluginsEnd;
+
bool tryLoadPlugin(Plugin *plugin);
-
+
friend class Common::Singleton<SingletonBaseType>;
PluginManager();
@@ -286,6 +288,9 @@ public:
void addPluginProvider(PluginProvider *pp);
+ bool loadFirstPlugin();
+ bool loadNextPlugin();
+
void loadPlugins();
void unloadPlugins();
void unloadPluginsExcept(PluginType type, const Plugin *plugin);
diff --git a/engines/metaengine.h b/engines/metaengine.h
index 7519feaaa4..964eee071c 100644
--- a/engines/metaengine.h
+++ b/engines/metaengine.h
@@ -231,6 +231,7 @@ private:
friend class Common::Singleton<SingletonBaseType>;
public:
+ GameDescriptor findGameOnePlugAtATime(const Common::String &gameName, const EnginePlugin **plugin = NULL) const;
GameDescriptor findGame(const Common::String &gameName, const EnginePlugin **plugin = NULL) const;
GameList detectGames(const Common::FSList &fslist) const;
const EnginePlugin::List &getPlugins() const;
diff --git a/engines/sci/engine/script.cpp b/engines/sci/engine/script.cpp
index 3ba550adf9..4c940804b8 100644
--- a/engines/sci/engine/script.cpp
+++ b/engines/sci/engine/script.cpp
@@ -332,6 +332,8 @@ uint16 Script::validateExportFunc(int pubfunct) {
if (offset == 0) {
// Check if the game has a second export table (e.g. script 912 in Camelot)
// Fixes bug #3039785
+ if (g_sci->getGameId() == GID_ECOQUEST) // cheap fix in here for eco quest 1, [md5] plz look into this TODO FIXME
+ return offset;
const uint16 *secondExportTable = (const uint16 *)findBlock(SCI_OBJ_EXPORTS, 0);
if (secondExportTable) {
diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp
index ef7b7dcb41..5fc93421cd 100644
--- a/engines/sci/engine/script_patches.cpp
+++ b/engines/sci/engine/script_patches.cpp
@@ -51,6 +51,70 @@ struct SciScriptSignature {
// - if not EOS, an adjust offset and the actual bytes
// - rinse and repeat
+// stayAndHelp::changeState (0) is called when ego swims to the left or right
+// boundaries of room 660. Normally a textbox is supposed to get on screen
+// but the call is wrong, so not only do we get an error message the script
+// is also hanging because the cue won't get sent out
+// This also happens in sierra sci - ffs. bug #3038387
+const byte ecoquest1SignatureStayAndHelp[] = {
+ 40,
+ 0x3f, 0x01, // link 01
+ 0x87, 0x01, // lap param[1]
+ 0x65, 0x14, // aTop state
+ 0x36, // push
+ 0x3c, // dup
+ 0x35, 0x00, // ldi 00
+ 0x1a, // eq?
+ 0x31, 0x1c, // bnt [next state]
+ 0x76, // push0
+ 0x45, 0x01, 0x00, // callb export1 from script 0 (switching control off)
+ 0x38, 0x22, 0x01, // pushi 0122
+ 0x78, // push1
+ 0x76, // push0
+ 0x81, 0x00, // lag global[0]
+ 0x4a, 0x06, // send 06 - ego::setMotion(0)
+ 0x39, 0x6e, // pushi 6e (selector init)
+ 0x39, 0x04, // pushi 04
+ 0x76, // push0
+ 0x76, // push0
+ 0x39, 0x17, // pushi 17
+ 0x7c, // pushSelf
+ 0x51, 0x82, // class EcoNarrator
+ 0x4a, 0x0c, // send 0c - EcoNarrator::init(0, 0, 23, self) (BADLY BROKEN!)
+ 0x33, // jmp [end]
+ 0
+};
+
+const uint16 ecoquest1PatchStayAndHelp[] = {
+ 0x87, 0x01, // lap param[1]
+ 0x65, 0x14, // aTop state
+ 0x36, // push
+ 0x2f, 0x22, // bt [next state] (this optimization saves 6 bytes)
+ 0x39, 0x00, // pushi 0 (wasting 1 byte here)
+ 0x45, 0x01, 0x00, // callb export1 from script 0 (switching control off)
+ 0x38, 0x22, 0x01, // pushi 0122
+ 0x78, // push1
+ 0x76, // push0
+ 0x81, 0x00, // lag global[0]
+ 0x4a, 0x06, // send 06 - ego::setMotion(0)
+ 0x39, 0x6e, // pushi 6e (selector init)
+ 0x39, 0x06, // pushi 06
+ 0x39, 0x02, // pushi 02 (additional 2 bytes)
+ 0x76, // push0
+ 0x76, // push0
+ 0x39, 0x17, // pushi 17
+ 0x7c, // pushSelf
+ 0x38, 0x80, 0x02, // pushi 280 (additional 3 bytes)
+ 0x51, 0x82, // class EcoNarrator
+ 0x4a, 0x10, // send 10 - EcoNarrator::init(2, 0, 0, 23, self, 640)
+ PATCH_END
+};
+
+// script, description, magic DWORD, adjust
+const SciScriptSignature ecoquest1Signatures[] = {
+ { 660, "CD: bad messagebox and freeze", PATCH_MAGICDWORD(0x38, 0x22, 0x01, 0x78), -17, ecoquest1SignatureStayAndHelp, ecoquest1PatchStayAndHelp },
+ { 0, NULL, 0, 0, NULL, NULL }
+};
// daySixBeignet::changeState (4) is called when the cop goes out and sets cycles to 220.
// this is not enough time to get to the door, so we patch that to 23 seconds
@@ -85,7 +149,7 @@ const byte gk1SignatureDay6PoliceSleep[] = {
0x35, 0x08, // ldi 08
0x1a, // eq?
0x31, // bnt [next state check]
- +1, 5, // [skip 1 byte, offset of bnt]
+ +1, 6, // [skip 1 byte, offset of bnt]
0x34, 0xdc, 0x00, // ldi 220
0x65, 0x1a, // aTop cycles
0x32, // jmp [end]
@@ -346,6 +410,8 @@ int32 Script::findSignature(const SciScriptSignature *signature, const byte *scr
void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) {
const SciScriptSignature *signatureTable = NULL;
+ if (g_sci->getGameId() == GID_ECOQUEST)
+ signatureTable = ecoquest1Signatures;
if (g_sci->getGameId() == GID_GK1)
signatureTable = gk1Signatures;
// hoyle4 now works due workaround inside GfxPorts
@@ -362,7 +428,7 @@ void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uin
int32 foundOffset = findSignature(signatureTable, scriptData, scriptSize);
if (foundOffset != -1) {
// found, so apply the patch
- warning("matched %s on script %d offset %d", signatureTable->description, scriptNr, foundOffset);
+ warning("matched and patched %s on script %d offset %d", signatureTable->description, scriptNr, foundOffset);
applyPatch(signatureTable->patch, scriptData, scriptSize, foundOffset);
}
}
diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp
index 4dc4ae93d8..013858dbcc 100644
--- a/engines/sci/engine/workarounds.cpp
+++ b/engines/sci/engine/workarounds.cpp
@@ -114,6 +114,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_JONES, 764, 255, 0, "", "export 0", -1, 14, { WORKAROUND_FAKE, 0 } }, // jones/ega&vga only - called when the game starts
{ GID_KQ5, -1, 0, 0, "", "export 29", -1, 3, { WORKAROUND_FAKE, 0 } }, // called when playing harp for the harpies or when aborting dialog in toy shop, is used for kDoAudio - bug #3034700
{ GID_KQ5, 25, 25, 0, "rm025", "doit", -1, 0, { WORKAROUND_FAKE, 0 } }, // inside witch forest, when going to the room where the walking rock is
+ { GID_KQ5, 55, 55, 0, "helpScript", "doit", -1, 0, { WORKAROUND_FAKE, 0 } }, // when giving the tambourine to the monster in the labyrinth (only happens at one of the locations) - bug #3041262
{ GID_KQ6, -1, 30, 0, "rats", "changeState", -1, -1, { WORKAROUND_FAKE, 0 } }, // rats in the catacombs (temps 1 - 5) - bugs #3034597, #3035495, #3035824
{ GID_KQ6, 210, 210, 0, "rm210", "scriptCheck", -1, 0, { WORKAROUND_FAKE, 1 } }, // using inventory in that room - bug #3034565
{ GID_KQ6, 500, 500, 0, "rm500", "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // going to island of the beast
@@ -124,8 +125,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_LAURABOW, -1, 967, 0, "myIcon", "cycle", -1, 1, { WORKAROUND_FAKE, 0 } }, // having any portrait conversation coming up (initial bug #3034985)
{ GID_LAURABOW2, -1, 24, 0, "gcWin", "open", -1, 5, { WORKAROUND_FAKE, 0xf } }, // is used as priority for game menu
{ GID_LAURABOW2, -1, 21, 0, "dropCluesCode", "doit", -1, 1, { WORKAROUND_FAKE, 0x7fff } }, // when asking some questions (e.g. the reporter about the burglary, or the policeman about Ziggy). Must be big, as the game scripts perform lt on it and start deleting journal entries - bugs #3035068, #3036274
- { GID_LAURABOW2, -1, 90, 0, "aTut", "init", -1, 6, { WORKAROUND_FAKE, 0 } }, // Random actors in museum (bug #3041257)
- { GID_LAURABOW2, -1, 90, 0, "aZiggy", "init", -1, 6, { WORKAROUND_FAKE, 0 } }, // Random actors in museum (bug #3041257)
+ { GID_LAURABOW2, -1, 90, 1, "MuseumActor", "init", -1, 6, { WORKAROUND_FAKE, 0 } }, // Random actors in museum (bug #3041257)
{ GID_LAURABOW2, 240, 240, 0, "sSteveAnimates", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // Steve Dorian's idle animation at the docks - bug #3036291
{ GID_LONGBOW, -1, 213, 0, "clear", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // When giving an answer using the druid hand sign code in any room
{ GID_LONGBOW, -1, 213, 0, "letter", "handleEvent", 0xa8, 1, { WORKAROUND_FAKE, 0 } }, // When using the druid hand sign code in any room - bug #3036601
@@ -155,6 +155,7 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = {
{ GID_QFG3, 330, 330, -1, "Teller", "doChild", -1, -1, { WORKAROUND_FAKE, 0 } }, // when talking to King Rajah about "Rajah" (bug #3036390, temp 1) or "Tarna" (temp 0), or when clicking on yourself and saying "Greet" (bug #3039774, temp 1)
{ GID_QFG3, 700, 700, -1, "monsterIsDead", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // in the jungle, after winning any fight, bug #3040624
{ GID_QFG3, 470, 470, -1, "rm470", "notify", -1, 0, { WORKAROUND_FAKE, 0 } }, // closing the character screen in the Simbani village in the room with the bridge, bug #3040565
+ { GID_QFG3, 490, 490, -1, "computersMove", "changeState", -1, 0, { WORKAROUND_FAKE, 0 } }, // when finishing awari game, bug #3040579
{ GID_QFG4, -1, 15, -1, "charInitScreen", "dispatchEvent", -1, 5, { WORKAROUND_FAKE, 0 } }, // floppy version, when viewing the character screen
{ GID_QFG4, -1, 64917, -1, "controlPlane", "setBitmap", -1, 3, { WORKAROUND_FAKE, 0 } }, // floppy version, when entering the game menu
{ GID_QFG4, -1, 64917, -1, "Plane", "setBitmap", -1, 3, { WORKAROUND_FAKE, 0 } }, // floppy version, happen sometimes in fights
diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp
index ab4362cda9..913b369790 100644
--- a/engines/sci/graphics/animate.cpp
+++ b/engines/sci/graphics/animate.cpp
@@ -243,6 +243,8 @@ void GfxAnimate::fill(byte &old_picNotValid) {
}
}
+ //warning("%s", _s->_segMan->getObjectName(curObject));
+
if (!view->isScaleable()) {
// Laura Bow 2 (especially floppy) depends on this, some views are not supposed to be scaleable
// this "feature" was removed in later versions of SCI1.1
@@ -516,6 +518,19 @@ void GfxAnimate::reAnimate(Common::Rect rect) {
}
}
+void GfxAnimate::preprocessAddToPicList() {
+ AnimateList::iterator it;
+ const AnimateList::iterator end = _list.end();
+
+ for (it = _list.begin(); it != end; ++it) {
+ if (it->priority == -1)
+ it->priority = _ports->kernelCoordinateToPriority(it->y);
+
+ // Do not allow priority to get changed by fill()
+ it->signal |= kSignalFixedPriority;
+ }
+}
+
void GfxAnimate::addToPicDrawCels() {
reg_t curObject;
GfxView *view = NULL;
@@ -525,17 +540,11 @@ void GfxAnimate::addToPicDrawCels() {
for (it = _list.begin(); it != end; ++it) {
curObject = it->object;
- if (it->priority == -1)
- it->priority = _ports->kernelCoordinateToPriority(it->y);
-
// Get the corresponding view
view = _cache->getView(it->viewId);
- // Create rect according to coordinates and given cel
- view->getCelRect(it->loopNo, it->celNo, it->x, it->y, it->z, it->celRect);
-
// draw corresponding cel
- _paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo);
+ _paint16->drawCel(it->viewId, it->loopNo, it->celNo, it->celRect, it->priority, it->paletteNo, it->scaleX, it->scaleY);
if ((it->signal & kSignalIgnoreActor) == 0) {
it->celRect.top = CLIP<int16>(_ports->kernelPriorityToCoordinate(it->priority) - 1, it->celRect.top, it->celRect.bottom - 1);
_paint16->fillRect(it->celRect, GFX_SCREEN_MASK_CONTROL, 0, 0, 15);
@@ -679,6 +688,7 @@ void GfxAnimate::addToPicSetPicNotValid() {
void GfxAnimate::kernelAddToPicList(reg_t listReference, int argc, reg_t *argv) {
List *list;
+ byte tempPicNotValid = 0;
_ports->setPort((Port *)_ports->_picWind);
@@ -687,6 +697,8 @@ void GfxAnimate::kernelAddToPicList(reg_t listReference, int argc, reg_t *argv)
error("kAddToPic called with non-list as parameter");
makeSortedList(list);
+ preprocessAddToPicList();
+ fill(tempPicNotValid);
addToPicDrawCels();
addToPicSetPicNotValid();
diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h
index 7e82187eed..c2101e5384 100644
--- a/engines/sci/graphics/animate.h
+++ b/engines/sci/graphics/animate.h
@@ -100,6 +100,7 @@ public:
void updateScreen(byte oldPicNotValid);
void restoreAndDelete(int argc, reg_t *argv);
void reAnimate(Common::Rect rect);
+ void preprocessAddToPicList();
void addToPicDrawCels();
void addToPicDrawView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 leftPos, int16 topPos, int16 priority, int16 control);
diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp
index 1c865f6bcf..5f48574dcb 100644
--- a/engines/sci/graphics/view.cpp
+++ b/engines/sci/graphics/view.cpp
@@ -256,6 +256,8 @@ void GfxView::initData(GuiResourceId resourceId) {
cel->scriptHeight = cel->height = READ_SCI11ENDIAN_UINT16(celData + 2);
cel->displaceX = READ_SCI11ENDIAN_UINT16(celData + 4);
cel->displaceY = READ_SCI11ENDIAN_UINT16(celData + 6);
+ if (cel->displaceY < 0)
+ cel->displaceY += 255; // sierra did this adjust in their sci1.1 getCelRect() - not sure about sci32
assert(cel->width && cel->height);
diff --git a/gui/launcher.cpp b/gui/launcher.cpp
index d50e7ce578..bc5debd9cd 100644
--- a/gui/launcher.cpp
+++ b/gui/launcher.cpp
@@ -733,7 +733,7 @@ void LauncherDialog::addGame() {
// ...so let's determine a list of candidates, games that
// could be contained in the specified directory.
GameList candidates(EngineMan.detectGames(files));
-
+
int idx;
if (candidates.empty()) {
// No game was found in the specified directory
@@ -874,7 +874,12 @@ void LauncherDialog::loadGame(int item) {
gameId = _domains[item];
const EnginePlugin *plugin = 0;
+
+#if defined(NEW_PLUGIN_DESIGN_FIRST_REFINEMENT) && defined(DYNAMIC_MODULES)
+ EngineMan.findGameOnePlugAtATime(gameId, &plugin);
+#else
EngineMan.findGame(gameId, &plugin);
+#endif
String target = _domains[item];
target.toLowercase();
diff --git a/gui/options.cpp b/gui/options.cpp
index 072b20b393..d1901e9219 100644
--- a/gui/options.cpp
+++ b/gui/options.cpp
@@ -770,7 +770,7 @@ void OptionsDialog::addMT32Controls(GuiObject *boss, const Common::String &prefi
_mt32DevicePopUp->setEnabled(false);
}
- _enableMIDISettings = true;
+ _enableMT32Settings = true;
}
// The function has an extra slider range parameter, since both the launcher and SCUMM engine
diff --git a/test/common/str.h b/test/common/str.h
index 6581c37cdb..16fb0859db 100644
--- a/test/common/str.h
+++ b/test/common/str.h
@@ -118,30 +118,6 @@ class StringTestSuite : public CxxTest::TestSuite
TS_ASSERT_EQUALS(foo3, "fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd""fooasdkadklasdjklasdjlkasjdlkasjdklasjdlkjasdasd");
}
- void test_refCount5() {
- // using external storage
- Common::String foo1("HelloHelloHelloHelloAndHi");
- Common::String foo2(foo1);
-
- for (Common::String::iterator i = foo2.begin(); i != foo2.end(); ++i)
- *i = 'h';
-
- TS_ASSERT_EQUALS(foo1, "HelloHelloHelloHelloAndHi");
- TS_ASSERT_EQUALS(foo2, "hhhhhhhhhhhhhhhhhhhhhhhhh");
- }
-
- void test_refCount6() {
- // using internal storage
- Common::String foo1("Hello");
- Common::String foo2(foo1);
-
- for (Common::String::iterator i = foo2.begin(); i != foo2.end(); ++i)
- *i = 'h';
-
- TS_ASSERT_EQUALS(foo1, "Hello");
- TS_ASSERT_EQUALS(foo2, "hhhhh");
- }
-
void test_self_asignment() {
Common::String foo1("12345678901234567890123456789012");
foo1 = foo1.c_str() + 2;
diff --git a/tools/create_msvc/create_msvc.cpp b/tools/create_msvc/create_msvc.cpp
index 1c395b01aa..fcae638c50 100644
--- a/tools/create_msvc/create_msvc.cpp
+++ b/tools/create_msvc/create_msvc.cpp
@@ -512,6 +512,8 @@ int main(int argc, char *argv[]) {
// 4103 (alignment changed after including header, may be due to missing #pragma pack(pop))
// used by pack-start / pack-end
//
+ // 4121 (alignment of a member was sensitive to packing)
+ //
// 4127 (conditional expression is constant)
// used in a lot of engines
//
@@ -565,6 +567,7 @@ int main(int argc, char *argv[]) {
projectWarnings["lure"] = "4189;4355";
projectWarnings["kyra"] = "4355";
projectWarnings["m4"] = "4355";
+ projectWarnings["mohawk"] = "4121";
ProjectProvider *provider = NULL;
diff --git a/tools/md5table.c b/tools/md5table.c
index 7d76b7541d..cb2959ed88 100644
--- a/tools/md5table.c
+++ b/tools/md5table.c
@@ -222,7 +222,7 @@ int main(int argc, char *argv[])
const int entrySize = 256;
int numEntries = 0, maxEntries = 1;
- char *entriesBuffer = (char *)malloc(maxEntries * entrySize);
+ char *entriesBuffer = malloc(maxEntries * entrySize);
typedef enum {
kCPPOutput,
@@ -295,7 +295,7 @@ int main(int argc, char *argv[])
} else if (entry.md5) {
if (numEntries >= maxEntries) {
maxEntries *= 2;
- entriesBuffer = (char *)realloc(entriesBuffer, maxEntries * entrySize);
+ entriesBuffer = realloc(entriesBuffer, maxEntries * entrySize);
}
if (0 == strcmp(entry.variant, "-"))
entry.variant = "";
diff --git a/tools/module.mk b/tools/module.mk
index 2c62e427ea..5248454382 100644
--- a/tools/module.mk
+++ b/tools/module.mk
@@ -36,15 +36,15 @@ clean-tools:
tools/convbdf$(EXEEXT): $(srcdir)/tools/convbdf.c
$(QUIET)$(MKDIR) tools/$(DEPDIR)
- $(QUIET_LINK)$(LD) $(CFLAGS) -Wall -o $@ $<
+ $(QUIET_LINK)$(CC) $(CFLAGS) -Wall -o $@ $<
tools/md5table$(EXEEXT): $(srcdir)/tools/md5table.c
$(QUIET)$(MKDIR) tools/$(DEPDIR)
- $(QUIET_LINK)$(LD) $(CFLAGS) -Wall -o $@ $<
+ $(QUIET_LINK)$(CC) $(CFLAGS) -Wall -o $@ $<
tools/make-scumm-fontdata$(EXEEXT): $(srcdir)/tools/make-scumm-fontdata.c
$(QUIET)$(MKDIR) tools/$(DEPDIR)
- $(QUIET_LINK)$(LD) $(CFLAGS) -Wall -o $@ $<
+ $(QUIET_LINK)$(CC) $(CFLAGS) -Wall -o $@ $<
#
# Rules to explicitly rebuild the credits / MD5 tables.
diff --git a/tools/scumm-md5.txt b/tools/scumm-md5.txt
index c3e48d6c5a..b379bc837e 100644
--- a/tools/scumm-md5.txt
+++ b/tools/scumm-md5.txt
@@ -591,7 +591,6 @@ catalog Humongous Interactive Catalog
airport Let's Explore the Airport with Buzzy
d6334a5a9b61afe18c368540fdf522ca -1 en Mac - - - Joachim Eberhard
07433205acdca3bc553d0e731588b35f -1 en Windows - - - Kirben
- 3e861421f494711bc6f619d4aba60285 93231 ru Windows - - - sev
7ea2da67ebabea4ac20cee9f4f9d2934 -1 en Mac - Demo - khalek
8ffd618a776a4c0d8922bb28b09f8ce8 -1 en Windows - Demo - khalek
@@ -603,7 +602,6 @@ farm Let's Explore the Farm with Buzzy
a5c5388da9bf0e6662fdca8813a79d13 86962 en Windows - - - George Kormendi
a85856675429fe88051744f755b72f93 -1 en Windows - - - Kirben
a2386da005672cbd5136f4f27a626c5f 87061 nl Windows - - - George Kormendi
- 5dda73606533d66a4c3f4f9ea6e842af 87061 ru Windows - - - sev
39fd6db10d0222d817025c4d3346e3b4 -1 en Mac - Demo - Joachim Eberhard
bf8b52fdd9a69c67f34e8e9fec72661c -1 en Windows HE 71 Demo - khalek, sev
@@ -715,7 +713,6 @@ puttmoon Putt-Putt Goes to the Moon
697c9b7c55a05d8199c48b48e379d2c8 -1 he DOS - - - sev
9dc02577bf50d4cfaf3de3fbac06fbe2 -1 en Mac - - - khalek
9c92eeaf517a31b7221ec2546ab669fd -1 en Windows HE 70 - - khalek
- 3c4c471342bd95505a42334367d8f127 12161 ru Windows HE 70 - - sev
aa6a91b7f6f119d1b7b1f2a4c9e24d59 6233 en DOS - Demo -
4af4a6b248103c1fe9edef619677f540 -1 en Mac - Demo - khalek