aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backends/plugins/elf-loader.cpp73
-rw-r--r--backends/plugins/elf-loader.h15
-rw-r--r--backends/plugins/mips-loader.cpp89
3 files changed, 109 insertions, 68 deletions
diff --git a/backends/plugins/elf-loader.cpp b/backends/plugins/elf-loader.cpp
index 3c66c765f6..9787c880ae 100644
--- a/backends/plugins/elf-loader.cpp
+++ b/backends/plugins/elf-loader.cpp
@@ -37,6 +37,11 @@
#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
@@ -62,6 +67,9 @@ static void flushDataCache() {
FlushCache(0);
FlushCache(2);
#endif
+#ifdef __PSP__
+ sceKernelDcacheWritebackAll();
+#endif
}
// Expel the symbol table from memory
@@ -78,13 +86,6 @@ void DLObject::unload() {
discard_symtab();
free(_segment);
_segment = NULL;
-
-#ifdef MIPS_TARGET
- if (_shortsSegment) {
- ShortsMan.deleteSegment(_shortsSegment);
- _shortsSegment = NULL;
- }
-#endif
}
bool DLObject::readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr) {
@@ -97,7 +98,7 @@ bool DLObject::readElfHeader(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehd
ehdr->e_machine != EM_ARM || // Check for ARM machine type
#endif
#ifdef MIPS_TARGET
- ehdr->e_machine != EM_MIPS ||
+ 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
@@ -137,33 +138,6 @@ bool DLObject::loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr)
char *baseAddress = 0;
-#ifdef MIPS_TARGET
- // 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());
- }
-#else
// 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);
@@ -178,7 +152,6 @@ bool DLObject::loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr)
// Get offset to load segment into
baseAddress = (char *)_segment + phdr->p_vaddr;
_segmentSize = phdr->p_memsz + extra;
-#endif
// Set bss segment to 0 if necessary (assumes bss is at the end)
if (phdr->p_memsz > phdr->p_filesz) {
@@ -294,33 +267,13 @@ void DLObject::relocateSymbols(Elf32_Addr offset) {
Elf32_Sym *s = (Elf32_Sym *)_symtab;
for (int c = _symbol_cnt; c--; s++) {
-#ifdef MIPS_TARGET
- // 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);
- }
-
- }
-#else
// 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);
-
}
-#endif
-
}
}
@@ -371,6 +324,10 @@ 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);
@@ -390,6 +347,10 @@ bool DLObject::open(const char *path) {
DBG("loaded!/n");
+#ifdef __PSP__
+ PowerMan.endCriticalSection();
+#endif
+
flushDataCache();
ctors_start = symbol("___plugin_ctors");
diff --git a/backends/plugins/elf-loader.h b/backends/plugins/elf-loader.h
index 7abe012003..56a9fa3767 100644
--- a/backends/plugins/elf-loader.h
+++ b/backends/plugins/elf-loader.h
@@ -30,10 +30,6 @@
#include "common/stream.h"
#include "backends/plugins/dynamic-plugin.h"
-#if defined(MIPS_TARGET)
-#include "shorts-segment-manager.h"
-#endif
-
class DLObject {
protected:
void *_segment, *_symtab;
@@ -44,23 +40,18 @@ protected:
int _segmentSize;
-#ifdef MIPS_TARGET
- ShortSegmentManager::Segment *_shortsSegment; // For assigning shorts ranges
- unsigned int _gpVal; // Value of Global Pointer
-#endif
-
//void seterror(const char *fmt, ...);
- void unload();
+ 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);
- bool loadSegment(Common::SeekableReadStream* DLFile, Elf32_Phdr *phdr);
+ 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);
- void relocateSymbols(Elf32_Addr offset);
+ virtual void relocateSymbols(Elf32_Addr offset);
virtual bool relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *ehdr, Elf32_Shdr *shdr) = 0;
public:
diff --git a/backends/plugins/mips-loader.cpp b/backends/plugins/mips-loader.cpp
index f537729197..7b59a2cffa 100644
--- a/backends/plugins/mips-loader.cpp
+++ b/backends/plugins/mips-loader.cpp
@@ -259,4 +259,93 @@ bool MIPSDLObject::relocateRels(Common::SeekableReadStream* DLFile, Elf32_Ehdr *
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) */