diff options
author | Bastien Bouclet | 2019-12-01 17:19:50 +0100 |
---|---|---|
committer | Bastien Bouclet | 2019-12-01 17:19:50 +0100 |
commit | 34e835a20ca648b0fd2e67cefc84511c1dab6217 (patch) | |
tree | 97ba9b239a8fd9c9d8bba925b21262314de2f2c2 /backends/plugins/3ds | |
parent | a51c23abd3a667811b01e90b0c8c53505021950a (diff) | |
download | scummvm-rg350-34e835a20ca648b0fd2e67cefc84511c1dab6217.tar.gz scummvm-rg350-34e835a20ca648b0fd2e67cefc84511c1dab6217.tar.bz2 scummvm-rg350-34e835a20ca648b0fd2e67cefc84511c1dab6217.zip |
3DS: Implement dynamic plugins
Allows a full build to run on old generation devices
Diffstat (limited to 'backends/plugins/3ds')
-rw-r--r-- | backends/plugins/3ds/3ds-provider.cpp | 127 | ||||
-rw-r--r-- | backends/plugins/3ds/3ds-provider.h | 37 | ||||
-rw-r--r-- | backends/plugins/3ds/plugin.ld | 179 |
3 files changed, 343 insertions, 0 deletions
diff --git a/backends/plugins/3ds/3ds-provider.cpp b/backends/plugins/3ds/3ds-provider.cpp new file mode 100644 index 0000000000..fd813669a5 --- /dev/null +++ b/backends/plugins/3ds/3ds-provider.cpp @@ -0,0 +1,127 @@ +/* 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. + * + */ + +#define FORBIDDEN_SYMBOL_ALLOW_ALL +#include "common/scummsys.h" + +#if defined(DYNAMIC_MODULES) && defined(__3DS__) + +#include "backends/plugins/3ds/3ds-provider.h" +#include "backends/plugins/elf/arm-loader.h" + +#include "common/debug.h" + +#include <3ds.h> + +extern uint32 __end__; // End of the main program in memory. Set by the linker. + +static uint32 alignUp(uint32 ptr, uint32 align) { + return (ptr + align - 1) & ~(align - 1); +} + +class CTRDLObject : public ARMDLObject { +public: + CTRDLObject(): + ARMDLObject(), + _segmentHeapAddress(0) { + } + +protected: + static const uint32 kPageSize = 0x1000; + + uint32 _segmentHeapAddress; + + void flushDataCache(void *ptr, uint32 len) const override { + svcFlushProcessDataCache(CUR_PROCESS_HANDLE, ptr, len); + } + + void protectMemory(void *ptr, uint32 len, int prot) const override { + debug(2, "elfloader: Protecting memory at %p, len %d with %d", ptr, len, prot); + + uint32 ctrFlags = 0; + if (prot & PF_R) ctrFlags |= MEMPERM_READ; + if (prot & PF_W) ctrFlags |= MEMPERM_WRITE; + if (prot & PF_X) ctrFlags |= MEMPERM_EXECUTE; + + // The kernel expects the range to be aligned to page boundaries + len = alignUp(len, kPageSize); + + Handle currentHandle; + svcDuplicateHandle(¤tHandle, CUR_PROCESS_HANDLE); + svcControlProcessMemory(currentHandle, (uint32)ptr, 0, len, MEMOP_PROT, ctrFlags); + svcCloseHandle(currentHandle); + } + + void *allocateMemory(uint32 align, uint32 size) override { + assert(!_segmentHeapAddress); // At the moment we can only load a single segment + + _segmentHeapAddress = (uint32)ARMDLObject::allocateMemory(align, size); + if (!_segmentHeapAddress) { + return nullptr; + } + + size = alignUp(size, kPageSize); + + // The plugin needs to be loaded near the main executable for PC-relative calls + // to resolve. The segment is allocated on the heap which not in the +/-32 MB + // range of the main executable. So here we map the segment address in the heap + // to a virtual address just after the main executable. + uint32 segmentNearAddress = alignUp((uint32)&__end__, kPageSize) + kPageSize; + + Handle currentHandle; + svcDuplicateHandle(¤tHandle, CUR_PROCESS_HANDLE); + Result mapResult = svcControlProcessMemory(currentHandle, segmentNearAddress, _segmentHeapAddress, size, MEMOP_MAP, MemPerm(MEMPERM_READ | MEMPERM_WRITE)); + svcCloseHandle(currentHandle); + + if (mapResult != 0) { + warning("elfloader: unable to map segment memory (%x) near the excutable (%x)", _segmentHeapAddress, segmentNearAddress); + + ARMDLObject::deallocateMemory((void *)_segmentHeapAddress, size); + _segmentHeapAddress = 0; + return nullptr; + } + + return (void *)segmentNearAddress; + } + + void deallocateMemory(void *ptr, uint32 size) override { + assert(_segmentHeapAddress); + + uint32 alignedSize = alignUp(size, kPageSize); + + Handle currentHandle; + svcDuplicateHandle(¤tHandle, CUR_PROCESS_HANDLE); + svcControlProcessMemory(currentHandle, (uint32)ptr, _segmentHeapAddress, alignedSize, MEMOP_UNMAP, MemPerm(MEMPERM_READ | MEMPERM_WRITE)); + svcCloseHandle(currentHandle); + + ARMDLObject::deallocateMemory((void *)_segmentHeapAddress, size); + + _segmentHeapAddress = 0; + } + +}; + +Plugin *CTRPluginProvider::createPlugin(const Common::FSNode &node) const { + return new TemplatedELFPlugin<CTRDLObject>(node.getPath()); +} + +#endif // defined(DYNAMIC_MODULES) && defined(__3DS__) diff --git a/backends/plugins/3ds/3ds-provider.h b/backends/plugins/3ds/3ds-provider.h new file mode 100644 index 0000000000..c0125e8aec --- /dev/null +++ b/backends/plugins/3ds/3ds-provider.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. + * + */ + +#if defined(DYNAMIC_MODULES) && defined(__3DS__) + +#ifndef BACKENDS_PLUGINS_3DS_PROVIDER_H +#define BACKENDS_PLUGINS_3DS_PROVIDER_H + +#include "backends/plugins/elf/elf-provider.h" + +class CTRPluginProvider : public ELFPluginProvider { +public: + Plugin *createPlugin(const Common::FSNode &node) const; +}; + +#endif // BACKENDS_PLUGINS_3DS_PROVIDER_H + +#endif // defined(DYNAMIC_MODULES) && defined(__3DS__) diff --git a/backends/plugins/3ds/plugin.ld b/backends/plugins/3ds/plugin.ld new file mode 100644 index 0000000000..ae83a7ac2e --- /dev/null +++ b/backends/plugins/3ds/plugin.ld @@ -0,0 +1,179 @@ +OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") +OUTPUT_ARCH(arm) +ENTRY(_start) + +PHDRS +{ + /* ScummVM's elf loader only allows a single segment, at the moment. */ + plugin PT_LOAD FLAGS(7) /* Read | Write | Execute */; +} + +SECTIONS +{ + /* =========== CODE section =========== */ + + . = 0; + + .text ALIGN(0x1000) : + { + /* .text */ + *(.text) + *(.text.*) + *(.glue_7) + *(.glue_7t) + *(.stub) + *(.gnu.warning) + *(.gnu.linkonce.t*) + . = ALIGN(4); + } : plugin + + /* =========== RODATA section =========== */ + + . = ALIGN(0x1000); + + .rodata : + { + *(.rodata) + *(.roda) + *(.rodata.*) + *all.rodata*(*) + *(.gnu.linkonce.r*) + SORT(CONSTRUCTORS) + . = ALIGN(4); + } : plugin + + .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } : plugin + __exidx_start = .; + ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } : plugin + __exidx_end = .; + + /* =========== DATA section =========== */ + + . = ALIGN(0x1000); + + .data : + { + *(.data) + *(.data.*) + *(.gnu.linkonce.d*) + CONSTRUCTORS + . = ALIGN(4); + } : plugin + + .tdata ALIGN(4) : + { + __tdata_lma = .; + *(.tdata) + *(.tdata.*) + *(.gnu.linkonce.td.*) + . = ALIGN(4); + __tdata_lma_end = .; + } : plugin + + .tbss ALIGN(4) : + { + *(.tbss) + *(.tbss.*) + *(.gnu.linkonce.tb.*) + *(.tcommon) + . = ALIGN(4); + } : plugin + + .preinit_array ALIGN(4) : + { + PROVIDE (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE (__preinit_array_end = .); + } : plugin + + .init_array ALIGN(4) : + { + PROVIDE (__init_array_start = .); + KEEP (*(SORT(.init_array.*))) + KEEP (*(.init_array)) + PROVIDE (__init_array_end = .); + } : plugin + + .fini_array ALIGN(4) : + { + PROVIDE (__fini_array_start = .); + KEEP (*(.fini_array)) + KEEP (*(SORT(.fini_array.*))) + PROVIDE (__fini_array_end = .); + } : plugin + + .ctors ALIGN(4) : + { + ___plugin_ctors = .; + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + ___plugin_ctors_end = .; + } : plugin + + .dtors ALIGN(4) : + { + ___plugin_dtors = .; + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + ___plugin_dtors_end = .; + } : plugin + + __bss_start__ = .; + .bss ALIGN(4) : + { + *(.dynbss) + *(.bss) + *(.bss.*) + *(.gnu.linkonce.b*) + *(COMMON) + . = ALIGN(4); + + /* Reserve space for the TLS segment of the main thread */ + __tls_start = .; + . += + SIZEOF(.tdata) + SIZEOF(.tbss); + __tls_end = .; + } : plugin + __bss_end__ = .; + + __end__ = ABSOLUTE(.) ; + + /* ================== + ==== Metadata ==== + ================== */ + + /* Discard sections that difficult post-processing */ + /DISCARD/ : { *(.group .comment .note) } + + /* 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) } + + /* 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) } + .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) } +} |