diff options
35 files changed, 857 insertions, 385 deletions
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp index 89aae7ce6..76e0c68c3 100644 --- a/src/citra_qt/main.cpp +++ b/src/citra_qt/main.cpp @@ -23,6 +23,7 @@ #include "core/system.h" #include "core/loader.h" #include "core/core.h" +#include "core/arm/disassembler/load_symbol_map.h" #include "version.h" @@ -74,6 +75,7 @@ GMainWindow::GMainWindow() // Setup connections connect(ui.action_Load_File, SIGNAL(triggered()), this, SLOT(OnMenuLoadFile())); + connect(ui.action_Load_Symbol_Map, SIGNAL(triggered()), this, SLOT(OnMenuLoadSymbolMap())); connect(ui.action_Start, SIGNAL(triggered()), this, SLOT(OnStartGame())); connect(ui.action_Pause, SIGNAL(triggered()), this, SLOT(OnPauseGame())); connect(ui.action_Stop, SIGNAL(triggered()), this, SLOT(OnStopGame())); @@ -140,11 +142,17 @@ void GMainWindow::BootGame(const char* filename) void GMainWindow::OnMenuLoadFile() { - QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS homebrew (*.elf *.dat)")); + QString filename = QFileDialog::getOpenFileName(this, tr("Load file"), QString(), tr("3DS homebrew (*.elf *.dat *.bin)")); if (filename.size()) BootGame(filename.toLatin1().data()); } +void GMainWindow::OnMenuLoadSymbolMap() { + QString filename = QFileDialog::getOpenFileName(this, tr("Load symbol map"), QString(), tr("Symbol map (*)")); + if (filename.size()) + LoadSymbolMap(filename.toLatin1().data()); +} + void GMainWindow::OnStartGame() { render_window->GetEmuThread().SetCpuRunning(true); diff --git a/src/citra_qt/main.hxx b/src/citra_qt/main.hxx index b4b1c533c..fa122f76e 100644 --- a/src/citra_qt/main.hxx +++ b/src/citra_qt/main.hxx @@ -33,10 +33,11 @@ private: void closeEvent(QCloseEvent* event); private slots: - void OnStartGame(); - void OnPauseGame(); - void OnStopGame(); - void OnMenuLoadFile(); + void OnStartGame(); + void OnPauseGame(); + void OnStopGame(); + void OnMenuLoadFile(); + void OnMenuLoadSymbolMap(); void OnOpenHotkeysDialog(); void OnConfigure(); void ToggleWindowMode(); diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui index c0cb11a10..f3596716f 100644 --- a/src/citra_qt/main.ui +++ b/src/citra_qt/main.ui @@ -40,6 +40,7 @@ <string>&File</string> </property> <addaction name="action_Load_File"/> + <addaction name="action_Load_Symbol_Map"/> <addaction name="separator"/> <addaction name="action_Exit"/> </widget> @@ -72,12 +73,17 @@ <addaction name="menu_Help"/> </widget> <widget class="QStatusBar" name="statusbar"/> - <action name="action_Load_File"> - <property name="text"> - <string>Load file...</string> - </property> - </action> - <action name="action_Exit"> + <action name="action_Load_File"> + <property name="text"> + <string>Load file...</string> + </property> + </action> + <action name="action_Load_Symbol_Map"> + <property name="text"> + <string>Load symbol map...</string> + </property> + </action> + <action name="action_Exit"> <property name="text"> <string>E&xit</string> </property> diff --git a/src/citra_qt/ui_main.h b/src/citra_qt/ui_main.h index cd3906ecc..04979e5ab 100644 --- a/src/citra_qt/ui_main.h +++ b/src/citra_qt/ui_main.h @@ -27,6 +27,7 @@ class Ui_MainWindow { public: QAction *action_Load_File; + QAction *action_Load_Symbol_Map; QAction *action_Exit; QAction *action_Start; QAction *action_Pause; @@ -56,6 +57,8 @@ public: MainWindow->setDockNestingEnabled(true); action_Load_File = new QAction(MainWindow); action_Load_File->setObjectName(QString::fromUtf8("action_Load_File")); + action_Load_Symbol_Map = new QAction(MainWindow); + action_Load_Symbol_Map->setObjectName(QString::fromUtf8("action_Load_Symbol_Map")); action_Exit = new QAction(MainWindow); action_Exit->setObjectName(QString::fromUtf8("action_Exit")); action_Start = new QAction(MainWindow); @@ -101,6 +104,7 @@ public: menubar->addAction(menu_View->menuAction()); menubar->addAction(menu_Help->menuAction()); menu_File->addAction(action_Load_File); + menu_File->addAction(action_Load_Symbol_Map); menu_File->addSeparator(); menu_File->addAction(action_Exit); menu_Emulation->addAction(action_Start); @@ -123,6 +127,7 @@ public: { MainWindow->setWindowTitle(QApplication::translate("MainWindow", "Citra", 0, QApplication::UnicodeUTF8)); action_Load_File->setText(QApplication::translate("MainWindow", "Load file...", 0, QApplication::UnicodeUTF8)); + action_Load_Symbol_Map->setText(QApplication::translate("MainWindow", "Load symbol map...", 0, QApplication::UnicodeUTF8)); action_Exit->setText(QApplication::translate("MainWindow", "E&xit", 0, QApplication::UnicodeUTF8)); action_Start->setText(QApplication::translate("MainWindow", "&Start", 0, QApplication::UnicodeUTF8)); action_Pause->setText(QApplication::translate("MainWindow", "&Pause", 0, QApplication::UnicodeUTF8)); diff --git a/src/common/bit_field.h b/src/common/bit_field.h new file mode 100644 index 000000000..dfd00d198 --- /dev/null +++ b/src/common/bit_field.h @@ -0,0 +1,172 @@ +// Licensed under GPLv2 +// Refer to the license.txt file included. + + +// Copyright 2014 Tony Wasserka +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the owner nor the names of its contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +#pragma once + +#include <limits> +#include <type_traits> + +#include "common/common.h" + +/* + * Abstract bitfield class + * + * Allows endianness-independent access to individual bitfields within some raw + * integer value. The assembly generated by this class is identical to the + * usage of raw bitfields, so it's a perfectly fine replacement. + * + * For BitField<X,Y,Z>, X is the distance of the bitfield to the LSB of the + * raw value, Y is the length in bits of the bitfield. Z is an integer type + * which determines the sign of the bitfield. Z must have the same size as the + * raw integer. + * + * + * General usage: + * + * Create a new union with the raw integer value as a member. + * Then for each bitfield you want to expose, add a BitField member + * in the union. The template parameters are the bit offset and the number + * of desired bits. + * + * Changes in the bitfield members will then get reflected in the raw integer + * value and vice-versa. + * + * + * Sample usage: + * + * union SomeRegister + * { + * u32 hex; + * + * BitField<0,7,u32> first_seven_bits; // unsigned + * BitField<7,8,32> next_eight_bits; // unsigned + * BitField<3,15,s32> some_signed_fields; // signed + * }; + * + * This is equivalent to the little-endian specific code: + * + * union SomeRegister + * { + * u32 hex; + * + * struct + * { + * u32 first_seven_bits : 7; + * u32 next_eight_bits : 8; + * }; + * struct + * { + * u32 : 3; // padding + * s32 some_signed_fields : 15; + * }; + * }; + * + * + * Caveats: + * + * 1) + * BitField provides automatic casting from and to the storage type where + * appropriate. However, when using non-typesafe functions like printf, an + * explicit cast must be performed on the BitField object to make sure it gets + * passed correctly, e.g.: + * printf("Value: %d", (s32)some_register.some_signed_fields); + * + * 2) + * Not really a caveat, but potentially irritating: This class is used in some + * packed structures that do not guarantee proper alignment. Therefore we have + * to use #pragma pack here not to pack the members of the class, but instead + * to break GCC's assumption that the members of the class are aligned on + * sizeof(StorageType). + * TODO(neobrain): Confirm that this is a proper fix and not just masking + * symptoms. + */ +#pragma pack(1) +template<std::size_t position, std::size_t bits, typename T> +struct BitField +{ +private: + // This constructor might be considered ambiguous: + // Would it initialize the storage or just the bitfield? + // Hence, delete it. Use the assignment operator to set bitfield values! + BitField(T val) = delete; + +public: + // Force default constructor to be created + // so that we can use this within unions + BitField() = default; + + __forceinline BitField& operator=(T val) + { + storage = (storage & ~GetMask()) | ((val << position) & GetMask()); + return *this; + } + + __forceinline operator T() const + { + if (std::numeric_limits<T>::is_signed) + { + std::size_t shift = 8 * sizeof(T)-bits; + return (T)(((storage & GetMask()) << (shift - position)) >> shift); + } + else + { + return (T)((storage & GetMask()) >> position); + } + } + +private: + // StorageType is T for non-enum types and the underlying type of T if + // T is an enumeration. Note that T is wrapped within an enable_if in the + // former case to workaround compile errors which arise when using + // std::underlying_type<T>::type directly. + typedef typename std::conditional < std::is_enum<T>::value, + std::underlying_type<T>, + std::enable_if < true, T >> ::type::type StorageType; + + // Unsigned version of StorageType + typedef typename std::make_unsigned<StorageType>::type StorageTypeU; + + __forceinline StorageType GetMask() const + { + return ((~(StorageTypeU)0) >> (8 * sizeof(T)-bits)) << position; + } + + StorageType storage; + + static_assert(bits + position <= 8 * sizeof(T), "Bitfield out of range"); + + // And, you know, just in case people specify something stupid like bits=position=0x80000000 + static_assert(position < 8 * sizeof(T), "Invalid position"); + static_assert(bits <= 8 * sizeof(T), "Invalid number of bits"); + static_assert(bits > 0, "Invalid number of bits"); +}; +#pragma pack() diff --git a/src/common/common.vcxproj b/src/common/common.vcxproj index 5048bebff..5dc6ff790 100644 --- a/src/common/common.vcxproj +++ b/src/common/common.vcxproj @@ -157,6 +157,7 @@ <ClInclude Include="atomic.h" /> <ClInclude Include="atomic_gcc.h" /> <ClInclude Include="atomic_win32.h" /> + <ClInclude Include="bit_field.h" /> <ClInclude Include="break_points.h" /> <ClInclude Include="chunk_file.h" /> <ClInclude Include="common.h" /> diff --git a/src/common/common.vcxproj.filters b/src/common/common.vcxproj.filters index e9ea40022..268730228 100644 --- a/src/common/common.vcxproj.filters +++ b/src/common/common.vcxproj.filters @@ -39,6 +39,7 @@ <ClInclude Include="utf8.h" /> <ClInclude Include="symbols.h" /> <ClInclude Include="scm_rev.h" /> + <ClInclude Include="bit_field.h" /> </ItemGroup> <ItemGroup> <ClCompile Include="break_points.cpp" /> diff --git a/src/common/log.h b/src/common/log.h index 02db8bd55..d95f51f56 100644 --- a/src/common/log.h +++ b/src/common/log.h @@ -33,7 +33,7 @@ enum LOG_TYPE { EXPANSIONINTERFACE, GDB_STUB, ARM11, - GPFIFO, + GSP, OSHLE, MASTER_LOG, MEMMAP, @@ -54,7 +54,7 @@ enum LOG_TYPE { WII_IPC_FILEIO, WII_IPC_HID, WII_IPC_HLE, - WII_IPC_NET, + SVC, NDMA, HLE, RENDER, diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp index 8e56deb8f..80fd473b9 100644 --- a/src/common/log_manager.cpp +++ b/src/common/log_manager.cpp @@ -42,7 +42,7 @@ LogManager::LogManager() m_Log[LogTypes::STREAMINGINTERFACE] = new LogContainer("Stream", "StreamingInt"); m_Log[LogTypes::DSPINTERFACE] = new LogContainer("DSP", "DSPInterface"); m_Log[LogTypes::DVDINTERFACE] = new LogContainer("DVD", "DVDInterface"); - m_Log[LogTypes::GPFIFO] = new LogContainer("GP", "GPFifo"); + m_Log[LogTypes::GSP] = new LogContainer("GSP", "GSP"); m_Log[LogTypes::EXPANSIONINTERFACE] = new LogContainer("EXI", "ExpansionInt"); m_Log[LogTypes::GDB_STUB] = new LogContainer("GDB_STUB", "GDB Stub"); m_Log[LogTypes::AUDIO_INTERFACE] = new LogContainer("AI", "AudioInt"); @@ -66,7 +66,7 @@ LogManager::LogManager() m_Log[LogTypes::WII_IPC_FILEIO] = new LogContainer("WII_IPC_FILEIO", "WII IPC FILEIO"); m_Log[LogTypes::RENDER] = new LogContainer("RENDER", "RENDER"); m_Log[LogTypes::LCD] = new LogContainer("LCD", "LCD"); - m_Log[LogTypes::WII_IPC_NET] = new LogContainer("WII_IPC_NET", "WII IPC NET"); + m_Log[LogTypes::SVC] = new LogContainer("SVC", "Supervisor Call"); m_Log[LogTypes::NDMA] = new LogContainer("NDMA", "NDMA"); m_Log[LogTypes::HLE] = new LogContainer("HLE", "High Level Emulation"); m_Log[LogTypes::HW] = new LogContainer("HW", "Hardware"); @@ -147,7 +147,7 @@ LogContainer::LogContainer(const char* shortName, const char* fullName, bool ena { strncpy(m_fullName, fullName, 128); strncpy(m_shortName, shortName, 32); - m_level = LogTypes::LWARNING; + m_level = (LogTypes::LOG_LEVELS)MAX_LOGLEVEL; } // LogContainer diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 314f6e64c..eb4fef381 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -5,6 +5,7 @@ set(SRCS core.cpp mem_map_funcs.cpp system.cpp arm/disassembler/arm_disasm.cpp + arm/disassembler/load_symbol_map.cpp arm/interpreter/arm_interpreter.cpp arm/interpreter/armemu.cpp arm/interpreter/arminit.cpp @@ -18,7 +19,8 @@ set(SRCS core.cpp file_sys/directory_file_system.cpp file_sys/meta_file_system.cpp hle/hle.cpp - hle/mrc.cpp + hle/config_mem.cpp + hle/coprocessor.cpp hle/syscall.cpp hle/service/apt.cpp hle/service/gsp.cpp diff --git a/src/core/arm/disassembler/load_symbol_map.cpp b/src/core/arm/disassembler/load_symbol_map.cpp new file mode 100644 index 000000000..d7fc0a042 --- /dev/null +++ b/src/core/arm/disassembler/load_symbol_map.cpp @@ -0,0 +1,33 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include <string> +#include <vector> + +#include "common/symbols.h" +#include "common/common_types.h" +#include "common/file_util.h" + +#include "core/arm/disassembler/load_symbol_map.h" + +/* + * Loads a symbol map file for use with the disassembler + * @param filename String filename path of symbol map file + */ +void LoadSymbolMap(std::string filename) { + std::ifstream infile(filename); + + std::string address_str, function_name, line; + u32 size, address; + + while (std::getline(infile, line)) { + std::istringstream iss(line); + if (!(iss >> address_str >> size >> function_name)) { + break; // Error parsing + } + u32 address = std::stoul(address_str, nullptr, 16); + + Symbols::Add(address, function_name, size, 2); + } +} diff --git a/src/core/arm/disassembler/load_symbol_map.h b/src/core/arm/disassembler/load_symbol_map.h new file mode 100644 index 000000000..837cca99b --- /dev/null +++ b/src/core/arm/disassembler/load_symbol_map.h @@ -0,0 +1,13 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include <string> + +/* + * Loads a symbol map file for use with the disassembler + * @param filename String filename path of symbol map file + */ +void LoadSymbolMap(std::string filename); diff --git a/src/core/arm/interpreter/armemu.cpp b/src/core/arm/interpreter/armemu.cpp index a35c5c8dc..1af684fe3 100644 --- a/src/core/arm/interpreter/armemu.cpp +++ b/src/core/arm/interpreter/armemu.cpp @@ -5536,14 +5536,15 @@ Handle_Load_Double (ARMul_State * state, ARMword instr) addr = base; /* The address must be aligned on a 8 byte boundary. */ - if (addr & 0x7) { -#ifdef ABORTS - ARMul_DATAABORT (addr); -#else - ARMul_UndefInstr (state, instr); -#endif - return; - } + // FIX(Normatt): Disable strict alignment on LDRD/STRD +// if (addr & 0x7) { +//#ifdef ABORTS +// ARMul_DATAABORT (addr); +//#else +// ARMul_UndefInstr (state, instr); +//#endif +// return; +// } /* For pre indexed or post indexed addressing modes, check that the destination registers do not overlap @@ -5640,14 +5641,15 @@ Handle_Store_Double (ARMul_State * state, ARMword instr) addr = base; /* The address must be aligned on a 8 byte boundary. */ - if (addr & 0x7) { -#ifdef ABORTS - ARMul_DATAABORT (addr); -#else - ARMul_UndefInstr (state, instr); -#endif - return; - } + // FIX(Normatt): Disable strict alignment on LDRD/STRD +// if (addr & 0x7) { +//#ifdef ABORTS +// ARMul_DATAABORT (addr); +//#else +// ARMul_UndefInstr (state, instr); +//#endif +// return; +// } /* For pre indexed or post indexed addressing modes, check that the destination registers do not overlap @@ -6405,6 +6407,8 @@ handle_v6_insn (ARMul_State * state, ARMword instr) if (state->Aborted) { TAKEABORT; } + // FIX(Normmatt): Handle RD in STREX/STREXB + state->Reg[DESTReg] = 0; //Always succeed return 1; } @@ -6432,7 +6436,8 @@ handle_v6_insn (ARMul_State * state, ARMword instr) if (state->Aborted) { TAKEABORT; } - + // FIX(Normmatt): Handle RD in STREX/STREXB + state->Reg[DESTReg] = 0; //Always succeed //printf("In %s, strexb not implemented\n", __FUNCTION__); UNDEF_LSRBPC; /* WRITESDEST (dest); */ diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp index b2bbedc18..e531dceda 100644 --- a/src/core/arm/interpreter/armsupp.cpp +++ b/src/core/arm/interpreter/armsupp.cpp @@ -20,7 +20,7 @@ //#include "ansidecl.h" #include "skyeye_defs.h" -#include "core/hle/mrc.h" +#include "core/hle/coprocessor.h" #include "core/arm/disassembler/arm_disasm.h" unsigned xscale_cp15_cp_access_allowed (ARMul_State * state, unsigned reg, @@ -661,39 +661,40 @@ ARMul_STC (ARMul_State * state, ARMword instr, ARMword address) void ARMul_MCR (ARMul_State * state, ARMword instr, ARMword source) { - unsigned cpab; + HLE::CallMCR(instr, source); + //unsigned cpab; - //printf("SKYEYE ARMul_MCR, CPnum is %x, source %x\n",CPNum, source); - if (!CP_ACCESS_ALLOWED (state, CPNum)) { - //chy 2004-07-19 should fix in the future ????!!!! - //printf("SKYEYE ARMul_MCR, ACCESS_not ALLOWed, UndefinedInstr CPnum is %x, source %x\n",CPNum, source); - ARMul_UndefInstr (state, instr); - return; - } + ////printf("SKYEYE ARMul_MCR, CPnum is %x, source %x\n",CPNum, source); + //if (!CP_ACCESS_ALLOWED (state, CPNum)) { + // //chy 2004-07-19 should fix in the future ????!!!! + // //printf("SKYEYE ARMul_MCR, ACCESS_not ALLOWed, UndefinedInstr CPnum is %x, source %x\n",CPNum, source); + // ARMul_UndefInstr (state, instr); + // return; + //} - cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source); + //cpab = (state->MCR[CPNum]) (state, ARMul_FIRST, instr, source); - while (cpab == ARMul_BUSY) { - ARMul_Icycles (state, 1, 0); + //while (cpab == ARMul_BUSY) { + // ARMul_Icycles (state, 1, 0); - if (IntPending (state)) { - cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, - instr, 0); - return; - } - else - cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, - source); - } + // if (IntPending (state)) { + // cpab = (state->MCR[CPNum]) (state, ARMul_INTERRUPT, + // instr, 0); + // return; + // } + // else + // cpab = (state->MCR[CPNum]) (state, ARMul_BUSY, instr, + // source); + //} - if (cpab == ARMul_CANT) { - printf ("SKYEYE ARMul_MCR, CANT, UndefinedInstr %x CPnum is %x, source %x\n", instr, CPNum, source); - ARMul_Abort (state, ARMul_UndefinedInstrV); - } - else { - BUSUSEDINCPCN; - ARMul_Ccycles (state, 1, 0); - } + //if (cpab == ARMul_CANT) { + // printf ("SKYEYE ARMul_MCR, CANT, UndefinedInstr %x CPnum is %x, source %x\n", instr, CPNum, source); + // ARMul_Abort (state, ARMul_UndefinedInstrV); + //} + //else { + // BUSUSEDINCPCN; + // ARMul_Ccycles (state, 1, 0); + //} } /* This function does the Busy-Waiting for an MCRR instruction. */ @@ -739,7 +740,7 @@ ARMul_MRC (ARMul_State * state, ARMword instr) { unsigned cpab; - ARMword result = HLE::CallMRC((HLE::ARM11_MRC_OPERATION)BITS(20, 27)); + ARMword result = HLE::CallMRC(instr); ////printf("SKYEYE ARMul_MRC, CPnum is %x, instr %x\n",CPNum, instr); //if (!CP_ACCESS_ALLOWED (state, CPNum)) { diff --git a/src/core/arm/mmu/arm1176jzf_s_mmu.cpp b/src/core/arm/mmu/arm1176jzf_s_mmu.cpp index 7e7fbfbfa..a32f076b9 100644 --- a/src/core/arm/mmu/arm1176jzf_s_mmu.cpp +++ b/src/core/arm/mmu/arm1176jzf_s_mmu.cpp @@ -355,7 +355,7 @@ arm1176jzf_s_mmu_load_instr (ARMul_State *state, ARMword va, ARMword *instr) static int debug_count = 0; /* used for debug */ - DEBUG_LOG(ARM11, "va = %x\n", va); + //DEBUG_LOG(ARM11, "va = %x\n", va); va = mmu_pid_va_map (va); if (MMU_Enabled) { @@ -444,7 +444,7 @@ arm1176jzf_s_mmu_read (ARMul_State *state, ARMword va, ARMword *data, ARMword perm; /* physical addr access permissions */ int ap, sop; - DEBUG_LOG(ARM11, "va = %x\n", va); + //DEBUG_LOG(ARM11, "va = %x\n", va); va = mmu_pid_va_map (va); real_va = va; @@ -629,7 +629,7 @@ arm1176jzf_s_mmu_write (ARMul_State *state, ARMword va, ARMword data, } #endif - DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); + //DEBUG_LOG(ARM11, "va = %x, val = %x\n", va, data); va = mmu_pid_va_map (va); real_va = va; diff --git a/src/core/core.vcxproj b/src/core/core.vcxproj index be8448969..b56661e48 100644 --- a/src/core/core.vcxproj +++ b/src/core/core.vcxproj @@ -138,6 +138,7 @@ </ItemGroup> <ItemGroup> <ClCompile Include="arm\disassembler\arm_disasm.cpp" /> + <ClCompile Include="arm\disassembler\load_symbol_map.cpp" /> <ClCompile Include="arm\interpreter\armemu.cpp" /> <ClCompile Include="arm\interpreter\arminit.cpp" /> <ClCompile Include="arm\interpreter\armmmu.cpp" /> @@ -152,8 +153,9 @@ <ClCompile Include="elf\elf_reader.cpp" /> <ClCompile Include="file_sys\directory_file_system.cpp" /> <ClCompile Include="file_sys\meta_file_system.cpp" /> + <ClCompile Include="hle\config_mem.cpp" /> + <ClCompile Include="hle\coprocessor.cpp" /> <ClCompile Include="hle\hle.cpp" /> - <ClCompile Include="hle\mrc.cpp" /> <ClCompile Include="hle\service\apt.cpp" /> <ClCompile Include="hle\service\gsp.cpp" /> <ClCompile Include="hle\service\hid.cpp" /> @@ -171,6 +173,7 @@ <ItemGroup> <ClInclude Include="arm\arm_interface.h" /> <ClInclude Include="arm\disassembler\arm_disasm.h" /> + <ClInclude Include="arm\disassembler\load_symbol_map.h" /> <ClInclude Include="arm\interpreter\armcpu.h" /> <ClInclude Include="arm\interpreter\armdefs.h" /> <ClInclude Include="arm\interpreter\armemu.h" /> @@ -191,9 +194,10 @@ <ClInclude Include="file_sys\directory_file_system.h" /> <ClInclude Include="file_sys\file_sys.h" /> <ClInclude Include="file_sys\meta_file_system.h" /> + <ClInclude Include="hle\config_mem.h" /> + <ClInclude Include="hle\coprocessor.h" /> <ClInclude Include="hle\function_wrappers.h" /> <ClInclude Include="hle\hle.h" /> - <ClInclude Include="hle\mrc.h" /> <ClInclude Include="hle\service\apt.h" /> <ClInclude Include="hle\service\gsp.h" /> <ClInclude Include="hle\service\hid.h" /> diff --git a/src/core/core.vcxproj.filters b/src/core/core.vcxproj.filters index b5473bc41..5c947ec23 100644 --- a/src/core/core.vcxproj.filters +++ b/src/core/core.vcxproj.filters @@ -105,7 +105,13 @@ <ClCompile Include="hw\lcd.cpp"> <Filter>hw</Filter> </ClCompile> - <ClCompile Include="hle\mrc.cpp"> + <ClCompile Include="arm\disassembler\load_symbol_map.cpp"> + <Filter>arm\disassembler</Filter> + </ClCompile> + <ClCompile Include="hle\coprocessor.cpp"> + <Filter>hle</Filter> + </ClCompile> + <ClCompile Include="hle\config_mem.cpp"> <Filter>hle</Filter> </ClCompile> </ItemGroup> @@ -208,7 +214,13 @@ <ClInclude Include="hw\lcd.h"> <Filter>hw</Filter> </ClInclude> - <ClInclude Include="hle\mrc.h"> + <ClInclude Include="arm\disassembler\load_symbol_map.h"> + <Filter>arm\disassembler</Filter> + </ClInclude> + <ClInclude Include="hle\coprocessor.h"> + <Filter>hle</Filter> + </ClInclude> + <ClInclude Include="hle\config_mem.h"> <Filter>hle</Filter> </ClInclude> </ItemGroup> diff --git a/src/core/hle/config_mem.cpp b/src/core/hle/config_mem.cpp new file mode 100644 index 000000000..48aa878cc --- /dev/null +++ b/src/core/hle/config_mem.cpp @@ -0,0 +1,70 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common/common_types.h" +#include "common/log.h" + +#include "core/hle/config_mem.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace ConfigMem { + +enum { + KERNEL_VERSIONREVISION = 0x1FF80001, + KERNEL_VERSIONMINOR = 0x1FF80002, + KERNEL_VERSIONMAJOR = 0x1FF80003, + UPDATEFLAG = 0x1FF80004, + NSTID = 0x1FF80008, + SYSCOREVER = 0x1FF80010, + UNITINFO = 0x1FF80014, + KERNEL_CTRSDKVERSION = 0x1FF80018, + APPMEMTYPE = 0x1FF80030, + APPMEMALLOC = 0x1FF80040, + FIRM_VERSIONREVISION = 0x1FF80061, + FIRM_VERSIONMINOR = 0x1FF80062, + FIRM_VERSIONMAJOR = 0x1FF80063, + FIRM_SYSCOREVER = 0x1FF80064, + FIRM_CTRSDKVERSION = 0x1FF80068, +}; + +template <typename T> +inline void Read(T &var, const u32 addr) { + switch (addr) { + + // Bit 0 set for Retail + case UNITINFO: + var = 0x00000001; + break; + + // Set app memory size to 64MB? + case APPMEMALLOC: + var = 0x04000000; + break; + + // Unknown - normally set to: 0x08000000 - (APPMEMALLOC + *0x1FF80048) + // (Total FCRAM size - APPMEMALLOC - *0x1FF80048) + case 0x1FF80044: + var = 0x08000000 - (0x04000000 + 0x1400000); + break; + + // Unknown - normally set to: 0x1400000 (20MB) + case 0x1FF80048: + var = 0x1400000; + break; + + default: + ERROR_LOG(HLE, "unknown ConfigMem::Read%d @ 0x%08X", sizeof(var) * 8, addr); + } +} + +// Explicitly instantiate template functions because we aren't defining this in the header: + +template void Read<u64>(u64 &var, const u32 addr); +template void Read<u32>(u32 &var, const u32 addr); +template void Read<u16>(u16 &var, const u32 addr); +template void Read<u8>(u8 &var, const u32 addr); + + +} // namespace diff --git a/src/core/hle/config_mem.h b/src/core/hle/config_mem.h new file mode 100644 index 000000000..da396a3e6 --- /dev/null +++ b/src/core/hle/config_mem.h @@ -0,0 +1,21 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +// Configuration memory stores various hardware/kernel configuration settings. This memory page is +// read-only for ARM11 processes. I'm guessing this would normally be written to by the firmware/ +// bootrom. Because we're not emulating this, and essentially just "stubbing" the functionality, I'm +// putting this as a subset of HLE for now. + +#include "common/common_types.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// + +namespace ConfigMem { + +template <typename T> +inline void Read(T &var, const u32 addr); + +} // namespace diff --git a/src/core/hle/coprocessor.cpp b/src/core/hle/coprocessor.cpp new file mode 100644 index 000000000..74305331c --- /dev/null +++ b/src/core/hle/coprocessor.cpp @@ -0,0 +1,50 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "core/hle/coprocessor.h" +#include "core/hle/hle.h" +#include "core/mem_map.h" +#include "core/core.h" + +namespace HLE { + +/// Data synchronization barrier +u32 DataSynchronizationBarrier() { + return 0; +} + +/// Returns the coprocessor (in this case, syscore) command buffer pointer +Addr GetThreadCommandBuffer() { + // Called on insruction: mrc p15, 0, r0, c13, c0, 3 + return Memory::KERNEL_MEMORY_VADDR; +} + +/// Call an MCR (move to coprocessor from ARM register) instruction in HLE +s32 CallMCR(u32 instruction, u32 value) { + CoprocessorOperation operation = (CoprocessorOperation)((instruction >> 20) & 0xFF); + ERROR_LOG(OSHLE, "unimplemented MCR instruction=0x%08X, operation=%02X, value=%08X", + instruction, operation, value); + return 0; +} + +/// Call an MRC (move to ARM register from coprocessor) instruction in HLE +s32 CallMRC(u32 instruction) { + CoprocessorOperation operation = (CoprocessorOperation)((instruction >> 20) & 0xFF); + + switch (operation) { + + case DATA_SYNCHRONIZATION_BARRIER: + return DataSynchronizationBarrier(); + + case CALL_GET_THREAD_COMMAND_BUFFER: + return GetThreadCommandBuffer(); + + default: + ERROR_LOG(OSHLE, "unimplemented MRC instruction 0x%08X", instruction); + break; + } + return 0; +} + +} // namespace diff --git a/src/core/hle/mrc.h b/src/core/hle/coprocessor.h index d6b9f162f..03822af13 100644 --- a/src/core/hle/mrc.h +++ b/src/core/hle/coprocessor.h @@ -8,13 +8,16 @@ namespace HLE { -/// MRC operations (ARM register from coprocessor), decoded as instr[20:27] -enum ARM11_MRC_OPERATION { +/// Coprocessor operations +enum CoprocessorOperation { DATA_SYNCHRONIZATION_BARRIER = 0xE0, CALL_GET_THREAD_COMMAND_BUFFER = 0xE1, }; -/// Call an MRC operation in HLE -u32 CallMRC(ARM11_MRC_OPERATION operation); +/// Call an MCR (move to coprocessor from ARM register) instruction in HLE +s32 CallMCR(u32 instruction, u32 value); + +/// Call an MRC (move to ARM register from coprocessor) instruction in HLE +s32 CallMRC(u32 instruction); } // namespace diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 4897d3f28..18b01b14b 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -158,8 +158,8 @@ template<int func(u32, u32, u32, u32, u32)> void WrapI_UUUUU() { RETURN(retval); } -template<int func()> void WrapI_V() { - int retval = func(); +template<int func(void*)> void WrapI_V() { + u32 retval = func(Memory::GetPointer(PARAM(0))); RETURN(retval); } @@ -638,6 +638,10 @@ template<u32 func(const char *, const char *)> void WrapU_CC() { RETURN(retval); } +template<void func(const char*)> void WrapV_C() { + func(Memory::GetCharPointer(PARAM(0))); +} + template<void func(const char *, int)> void WrapV_CI() { func(Memory::GetCharPointer(PARAM(0)), PARAM(1)); } @@ -716,18 +720,28 @@ template <int func(int, const char *, int)> void WrapI_ICI() { } template<int func(int, void *, void *, void *, void *, u32, int)> void WrapI_IVVVVUI(){ - u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)), Memory::GetPointer(PARAM(2)), Memory::GetPointer(PARAM(3)), Memory::GetPointer(PARAM(4)), PARAM(5), PARAM(6) ); - RETURN(retval); + u32 retval = func(PARAM(0), Memory::GetPointer(PARAM(1)), Memory::GetPointer(PARAM(2)), Memory::GetPointer(PARAM(3)), Memory::GetPointer(PARAM(4)), PARAM(5), PARAM(6) ); + RETURN(retval); } template<int func(int, const char *, u32, void *, int, int, int)> void WrapI_ICUVIII(){ - u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)), PARAM(4), PARAM(5), PARAM(6)); - RETURN(retval); + u32 retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), Memory::GetPointer(PARAM(3)), PARAM(4), PARAM(5), PARAM(6)); + RETURN(retval); } -template<int func(void *, u32, u32, u32, u32, u32)> void WrapI_VUUUUU(){ - u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); - RETURN(retval); +template<int func(void*, u32)> void WrapI_VU(){ + u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1)); + RETURN(retval); +} + +template<int func(void*, u32, void*, int)> void WrapI_VUVI(){ + u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), Memory::GetPointer(PARAM(2)), PARAM(3)); + RETURN(retval); +} + +template<int func(void*, u32, u32, u32, u32, u32)> void WrapI_VUUUUU(){ + u32 retval = func(Memory::GetPointer(PARAM(0)), PARAM(1), PARAM(2), PARAM(3), PARAM(4), PARAM(5)); + RETURN(retval); } template<int func(u32, s64)> void WrapI_US64() { diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp index aae9a3943..be151665b 100644 --- a/src/core/hle/hle.cpp +++ b/src/core/hle/hle.cpp @@ -15,49 +15,6 @@ namespace HLE { static std::vector<ModuleDef> g_module_db; -u8* g_command_buffer = NULL; ///< Command buffer used for sharing between appcore and syscore - -// Read from memory used by CTROS HLE functions -template <typename T> -inline void Read(T &var, const u32 addr) { - if (addr >= HLE::CMD_BUFFER_ADDR && addr < HLE::CMD_BUFFER_ADDR_END) { - var = *((const T*)&g_command_buffer[addr & CMD_BUFFER_MASK]); - } else { - ERROR_LOG(HLE, "unknown read from address %08X", addr); - } -} - -// Write to memory used by CTROS HLE functions -template <typename T> -inline void Write(u32 addr, const T data) { - if (addr >= HLE::CMD_BUFFER_ADDR && addr < HLE::CMD_BUFFER_ADDR_END) { - *(T*)&g_command_buffer[addr & CMD_BUFFER_MASK] = data; - } else { - ERROR_LOG(HLE, "unknown write to address %08X", addr); - } -} - -u8 *GetPointer(const u32 addr) { - if (addr >= HLE::CMD_BUFFER_ADDR && addr < HLE::CMD_BUFFER_ADDR_END) { - return g_command_buffer + (addr & CMD_BUFFER_MASK); - } else { - ERROR_LOG(HLE, "unknown pointer from address %08X", addr); - return 0; - } -} - -// Explicitly instantiate template functions because we aren't defining this in the header: - -template void Read<u64>(u64 &var, const u32 addr); -template void Read<u32>(u32 &var, const u32 addr); -template void Read<u16>(u16 &var, const u32 addr); -template void Read<u8>(u8 &var, const u32 addr); - -template void Write<u64>(u32 addr, const u64 data); -template void Write<u32>(u32 addr, const u32 data); -template void Write<u16>(u32 addr, const u16 data); -template void Write<u8>(u32 addr, const u8 data); - const FunctionDef* GetSyscallInfo(u32 opcode) { u32 func_num = opcode & 0xFFFFFF; // 8 bits if (func_num > 0xFF) { @@ -91,8 +48,6 @@ void RegisterAllModules() { void Init() { Service::Init(); - - g_command_buffer = new u8[CMD_BUFFER_SIZE]; RegisterAllModules(); @@ -102,8 +57,6 @@ void Init() { void Shutdown() { Service::Shutdown(); - delete g_command_buffer; - g_module_db.clear(); NOTICE_LOG(HLE, "shutdown OK"); diff --git a/src/core/hle/hle.h b/src/core/hle/hle.h index 907e2d741..42f37e29c 100644 --- a/src/core/hle/hle.h +++ b/src/core/hle/hle.h @@ -17,13 +17,6 @@ namespace HLE { -enum { - CMD_BUFFER_ADDR = 0xA0010000, ///< Totally arbitrary unused address space - CMD_BUFFER_SIZE = 0x10000, - CMD_BUFFER_MASK = (CMD_BUFFER_SIZE - 1), - CMD_BUFFER_ADDR_END = (CMD_BUFFER_ADDR + CMD_BUFFER_SIZE), -}; - typedef u32 Addr; typedef void (*Func)(); @@ -39,20 +32,6 @@ struct ModuleDef { const FunctionDef* func_table; }; -// Read from memory used by CTROS HLE functions -template <typename T> -inline void Read(T &var, const u32 addr); - -// Write to memory used by CTROS HLE functions -template <typename T> -inline void Write(u32 addr, const T data); - -u8* GetPointer(const u32 Address); - -inline const char* GetCharPointer(const u32 address) { - return (const char *)GetPointer(address); -} - void RegisterModule(std::string name, int num_functions, const FunctionDef *func_table); void CallSyscall(u32 opcode); diff --git a/src/core/hle/mrc.cpp b/src/core/hle/mrc.cpp deleted file mode 100644 index 5223be7c9..000000000 --- a/src/core/hle/mrc.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "core/hle/mrc.h" -#include "core/hle/hle.h" -#include "core/mem_map.h" -#include "core/core.h" - -namespace HLE { - -enum { - CMD_GX_REQUEST_DMA = 0x00000000, -}; - -/// Data synchronization barrier -u32 DataSynchronizationBarrier(u32* command_buffer) { - u32 command = command_buffer[0]; - - switch (command) { - - case CMD_GX_REQUEST_DMA: - { - u32* src = (u32*)Memory::GetPointer(command_buffer[1]); - u32* dst = (u32*)Memory::GetPointer(command_buffer[2]); - u32 size = command_buffer[3]; - memcpy(dst, src, size); - } - break; - - default: - ERROR_LOG(OSHLE, "MRC::DataSynchronizationBarrier unknown command 0x%08X", command); - return -1; - } - - return 0; -} - -/// Returns the coprocessor (in this case, syscore) command buffer pointer -Addr GetThreadCommandBuffer() { - // Called on insruction: mrc p15, 0, r0, c13, c0, 3 - // Returns an address in OSHLE memory for the CPU to read/write to - RETURN(CMD_BUFFER_ADDR); - return CMD_BUFFER_ADDR; -} - -/// Call an MRC operation in HLE -u32 CallMRC(ARM11_MRC_OPERATION operation) { - switch (operation) { - - case DATA_SYNCHRONIZATION_BARRIER: - return DataSynchronizationBarrier((u32*)Memory::GetPointer(PARAM(0))); - - case CALL_GET_THREAD_COMMAND_BUFFER: - return GetThreadCommandBuffer(); - - default: - ERROR_LOG(OSHLE, "unimplemented MRC operation 0x%02X", operation); - break; - } - return -1; -} - -} // namespace diff --git a/src/core/hle/service/apt.cpp b/src/core/hle/service/apt.cpp index 4a1e8c992..709ac5493 100644 --- a/src/core/hle/service/apt.cpp +++ b/src/core/hle/service/apt.cpp @@ -18,7 +18,7 @@ void Initialize(Service::Interface* self) { } void GetLockHandle(Service::Interface* self) { - u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + Service::kCommandHeaderOffset); + u32* cmd_buff = Service::GetCommandBuffer(); cmd_buff[5] = 0x00000000; // TODO: This should be an actual mutex handle } diff --git a/src/core/hle/service/gsp.cpp b/src/core/hle/service/gsp.cpp index 88c1f1a0f..12c7dabcd 100644 --- a/src/core/hle/service/gsp.cpp +++ b/src/core/hle/service/gsp.cpp @@ -4,6 +4,7 @@ #include "common/log.h" +#include "common/bit_field.h" #include "core/mem_map.h" #include "core/hle/hle.h" @@ -12,10 +13,51 @@ #include "core/hw/lcd.h" //////////////////////////////////////////////////////////////////////////////////////////////////// + +/// GSP shared memory GX command buffer header +union GX_CmdBufferHeader { + u32 hex; + + // Current command index. This index is updated by GSP module after loading the command data, + // right before the command is processed. When this index is updated by GSP module, the total + // commands field is decreased by one as well. + BitField<0,8,u32> index; + + // Total commands to process, must not be value 0 when GSP module handles commands. This must be + // <=15 when writing a command to shared memory. This is incremented by the application when + // writing a command to shared memory, after increasing this value TriggerCmdReqQueue is only + // used if this field is value 1. + BitField<8,8,u32> number_commands; + +}; + +/// Gets the address of the start (header) of a command buffer in GSP shared memory +static inline u32 GX_GetCmdBufferAddress(u32 thread_id) { + return (0x10002000 + 0x800 + (thread_id * 0x200)); +} + +/// Gets a pointer to the start (header) of a command buffer in GSP shared memory +static inline u8* GX_GetCmdBufferPointer(u32 thread_id, u32 offset=0) { + return Memory::GetPointer(GX_GetCmdBufferAddress(thread_id) + offset); +} + +/// Finishes execution of a GSP command +void GX_FinishCommand(u32 thread_id) { + GX_CmdBufferHeader* header = (GX_CmdBufferHeader*)GX_GetCmdBufferPointer(thread_id); + header->number_commands = header->number_commands - 1; +} + +//////////////////////////////////////////////////////////////////////////////////////////////////// // Namespace GSP_GPU namespace GSP_GPU { +u32 g_thread_id = 0; + +enum { + CMD_GX_REQUEST_DMA = 0x00000000, +}; + enum { REG_FRAMEBUFFER_1 = 0x00400468, REG_FRAMEBUFFER_2 = 0x00400494, @@ -26,7 +68,7 @@ void ReadHWRegs(Service::Interface* self) { static const u32 framebuffer_1[] = {LCD::PADDR_VRAM_TOP_LEFT_FRAME1, LCD::PADDR_VRAM_TOP_RIGHT_FRAME1}; static const u32 framebuffer_2[] = {LCD::PADDR_VRAM_TOP_LEFT_FRAME2, LCD::PADDR_VRAM_TOP_RIGHT_FRAME2}; - u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + Service::kCommandHeaderOffset); + u32* cmd_buff = Service::GetCommandBuffer(); u32 reg_addr = cmd_buff[1]; u32 size = cmd_buff[2]; u32* dst = (u32*)Memory::GetPointer(cmd_buff[0x41]); @@ -50,18 +92,37 @@ void ReadHWRegs(Service::Interface* self) { break; default: - ERROR_LOG(OSHLE, "GSP_GPU::ReadHWRegs unknown register read at address %08X", reg_addr); + ERROR_LOG(GSP, "ReadHWRegs unknown register read at address %08X", reg_addr); } } void RegisterInterruptRelayQueue(Service::Interface* self) { - u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + Service::kCommandHeaderOffset); + u32* cmd_buff = Service::GetCommandBuffer(); u32 flags = cmd_buff[1]; u32 event_handle = cmd_buff[3]; // TODO(bunnei): Implement event handling + + cmd_buff[2] = g_thread_id; // ThreadID cmd_buff[4] = self->NewHandle(); +} + +/// This triggers handling of the GX command written to the command buffer in shared memory. +void TriggerCmdReqQueue(Service::Interface* self) { + GX_CmdBufferHeader* header = (GX_CmdBufferHeader*)GX_GetCmdBufferPointer(g_thread_id); + u32* cmd_buff = (u32*)GX_GetCmdBufferPointer(g_thread_id, 0x20 + (header->index * 0x20)); - return; + switch (cmd_buff[0]) { + + // GX request DMA - typically used for copying memory from GSP heap to VRAM + case CMD_GX_REQUEST_DMA: + memcpy(Memory::GetPointer(cmd_buff[2]), Memory::GetPointer(cmd_buff[1]), cmd_buff[3]); + break; + + default: + ERROR_LOG(GSP, "TriggerCmdReqQueue unknown command 0x%08X", cmd_buff[0]); + } + + GX_FinishCommand(g_thread_id); } const Interface::FunctionInfo FunctionTable[] = { @@ -76,7 +137,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00090082, NULL, "InvalidateDataCache"}, {0x000A0044, NULL, "RegisterInterruptEvents"}, {0x000B0040, NULL, "SetLcdForceBlack"}, - {0x000C0000, NULL, "TriggerCmdReqQueue"}, + {0x000C0000, TriggerCmdReqQueue, "TriggerCmdReqQueue"}, {0x000D0140, NULL, "SetDisplayTransfer"}, {0x000E0180, NULL, "SetTextureCopy"}, {0x000F0200, NULL, "SetMemoryFill"}, diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index b79dc9458..b260a290a 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h @@ -10,6 +10,7 @@ #include "common/common.h" #include "common/common_types.h" +#include "core/mem_map.h" #include "core/hle/syscall.h" //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -22,6 +23,15 @@ typedef s32 NativeUID; ///< Native handle for a service static const int kMaxPortSize = 0x08; ///< Maximum size of a port name (8 characters) static const int kCommandHeaderOffset = 0x80; ///< Offset into command buffer of header +/** + * Returns a pointer to the command buffer in kernel memory + * @param offset Optional offset into command buffer + * @return Pointer to command buffer + */ +inline static u32* GetCommandBuffer(const int offset=0) { + return (u32*)Memory::GetPointer(Memory::KERNEL_MEMORY_VADDR + kCommandHeaderOffset + offset); +} + class Manager; /// Interface to a CTROS service @@ -81,7 +91,7 @@ public: * @return Return result of svcSendSyncRequest passed back to user app */ Syscall::Result Sync() { - u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + kCommandHeaderOffset); + u32* cmd_buff = GetCommandBuffer(); auto itr = m_functions.find(cmd_buff[0]); if (itr == m_functions.end()) { diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp index 9437868c5..071741444 100644 --- a/src/core/hle/service/srv.cpp +++ b/src/core/hle/service/srv.cpp @@ -18,7 +18,7 @@ void Initialize(Service::Interface* self) { void GetServiceHandle(Service::Interface* self) { Syscall::Result res = 0; - u32* cmd_buff = (u32*)HLE::GetPointer(HLE::CMD_BUFFER_ADDR + Service::kCommandHeaderOffset); + u32* cmd_buff = Service::GetCommandBuffer(); std::string port_name = std::string((const char*)&cmd_buff[1], 0, Service::kMaxPortSize); Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); diff --git a/src/core/hle/syscall.cpp b/src/core/hle/syscall.cpp index df6412743..d47df6038 100644 --- a/src/core/hle/syscall.cpp +++ b/src/core/hle/syscall.cpp @@ -29,6 +29,9 @@ enum MapMemoryPermission { Result ControlMemory(u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissions) { u32 virtual_address = 0x00000000; + DEBUG_LOG(SVC, "ControlMemory called operation=0x%08X, addr0=0x%08X, addr1=0x%08X, size=%08X, permissions=0x%08X", + operation, addr0, addr1, size, permissions); + switch (operation) { // Map normal heap memory @@ -43,16 +46,18 @@ Result ControlMemory(u32 operation, u32 addr0, u32 addr1, u32 size, u32 permissi // Unknown ControlMemory operation default: - ERROR_LOG(OSHLE, "Unknown ControlMemory operation %08X", operation); + ERROR_LOG(SVC, "ControlMemory unknown operation=0x%08X", operation); } Core::g_app_core->SetReg(1, virtual_address); + return 0; } /// Maps a memory block to specified address Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherpermission) { - int x = 0; + DEBUG_LOG(SVC, "MapMemoryBlock called memblock=0x08X, addr=0x%08X, mypermissions=0x%08X, otherpermission=%d", + memblock, addr, mypermissions, otherpermission); switch (mypermissions) { case MEMORY_PERMISSION_NORMAL: case MEMORY_PERMISSION_NORMAL + 1: @@ -60,20 +65,23 @@ Result MapMemoryBlock(Handle memblock, u32 addr, u32 mypermissions, u32 otherper Memory::MapBlock_Shared(memblock, addr, mypermissions); break; default: - ERROR_LOG(OSHLE, "Unknown MapMemoryBlock permissions %08X", mypermissions); + ERROR_LOG(OSHLE, "MapMemoryBlock unknown permissions=0x%08X", mypermissions); } return 0; } /// Connect to an OS service given the port name, returns the handle to the port to out Result ConnectToPort(void* out, const char* port_name) { + Service::Interface* service = Service::g_manager->FetchFromPortName(port_name); Core::g_app_core->SetReg(1, service->GetUID()); + DEBUG_LOG(SVC, "ConnectToPort called port_name=%s", port_name); return 0; } /// Synchronize to an OS service Result SendSyncRequest(Handle session) { + DEBUG_LOG(SVC, "SendSyncRequest called session=0x%08X"); Service::Interface* service = Service::g_manager->FetchFromUID(session); service->Sync(); return 0; @@ -82,142 +90,177 @@ Result SendSyncRequest(Handle session) { /// Close a handle Result CloseHandle(Handle handle) { // ImplementMe + DEBUG_LOG(SVC, "(UNIMPLEMENTED) CloseHandle called handle=0x%08X", handle); return 0; } /// Wait for a handle to synchronize, timeout after the specified nanoseconds Result WaitSynchronization1(Handle handle, s64 nanoseconds) { // ImplementMe + DEBUG_LOG(SVC, "(UNIMPLEMENTED) WaitSynchronization1 called handle=0x%08X, nanoseconds=%d", + handle, nanoseconds); + return 0; +} + +/// Create an address arbiter (to allocate access to shared resources) +Result CreateAddressArbiter(void* arbiter) { + // ImplementMe + DEBUG_LOG(SVC, "(UNIMPLEMENTED) CreateAddressArbiter called"); + Core::g_app_core->SetReg(1, 0xDEADBEEF); + return 0; +} + +/// Used to output a message on a debug hardware unit - does nothing on a retail unit +void OutputDebugString(const char* string) { + NOTICE_LOG(SVC, "## OSDEBUG: %08X %s", Core::g_app_core->GetPC(), string); +} + +/// Get resource limit +Result GetResourceLimit(void* resource_limit, Handle process) { + // With regards to proceess values: + // 0xFFFF8001 is a handle alias for the current KProcess, and 0xFFFF8000 is a handle alias for + // the current KThread. + DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimit called process=0x%08X", process); + Core::g_app_core->SetReg(1, 0xDEADBEEF); + return 0; +} + +/// Get resource limit current values +Result GetResourceLimitCurrentValues(void* _values, Handle resource_limit, void* names, s32 name_count) { + //s64* values = (s64*)_values; + DEBUG_LOG(SVC, "(UNIMPLEMENTED) GetResourceLimitCurrentValues called resource_limit=%08X, names=%s, name_count=%d", + resource_limit, names, name_count); + Memory::Write32(Core::g_app_core->GetReg(0), 0); // Normmatt: Set used memory to 0 for now return 0; } const HLE::FunctionDef Syscall_Table[] = { - {0x00, NULL, "Unknown"}, - {0x01, WrapI_UUUUU<ControlMemory>, "ControlMemory"}, - {0x02, NULL, "QueryMemory"}, - {0x03, NULL, "ExitProcess"}, - {0x04, NULL, "GetProcessAffinityMask"}, - {0x05, NULL, "SetProcessAffinityMask"}, - {0x06, NULL, "GetProcessIdealProcessor"}, - {0x07, NULL, "SetProcessIdealProcessor"}, - {0x08, NULL, "CreateThread"}, - {0x09, NULL, "ExitThread"}, - {0x0A, NULL, "SleepThread"}, - {0x0B, NULL, "GetThreadPriority"}, - {0x0C, NULL, "SetThreadPriority"}, - {0x0D, NULL, "GetThreadAffinityMask"}, - {0x0E, NULL, "SetThreadAffinityMask"}, - {0x0F, NULL, "GetThreadIdealProcessor"}, - {0x10, NULL, "SetThreadIdealProcessor"}, - {0x11, NULL, "GetCurrentProcessorNumber"}, - {0x12, NULL, "Run"}, - {0x13, NULL, "CreateMutex"}, - {0x14, NULL, "ReleaseMutex"}, - {0x15, NULL, "CreateSemaphore"}, - {0x16, NULL, "ReleaseSemaphore"}, - {0x17, NULL, "CreateEvent"}, - {0x18, NULL, "SignalEvent"}, - {0x19, NULL, "ClearEvent"}, - {0x1A, NULL, "CreateTimer"}, - {0x1B, NULL, "SetTimer"}, - {0x1C, NULL, "CancelTimer"}, - {0x1D, NULL, "ClearTimer"}, - {0x1E, NULL, "CreateMemoryBlock"}, - {0x1F, WrapI_UUUU<MapMemoryBlock>, "MapMemoryBlock"}, - {0x20, NULL, "UnmapMemoryBlock"}, - {0x21, NULL, "CreateAddressArbiter"}, - {0x22, NULL, "ArbitrateAddress"}, - {0x23, WrapI_U<CloseHandle>, "CloseHandle"}, - {0x24, WrapI_US64<WaitSynchronization1>, "WaitSynchronization1"}, - {0x25, NULL, "WaitSynchronizationN"}, - {0x26, NULL, "SignalAndWait"}, - {0x27, NULL, "DuplicateHandle"}, - {0x28, NULL, "GetSystemTick"}, - {0x29, NULL, "GetHandleInfo"}, - {0x2A, NULL, "GetSystemInfo"}, - {0x2B, NULL, "GetProcessInfo"}, - {0x2C, NULL, "GetThreadInfo"}, - {0x2D, WrapI_VC<ConnectToPort>, "ConnectToPort"}, - {0x2E, NULL, "SendSyncRequest1"}, - {0x2F, NULL, "SendSyncRequest2"}, - {0x30, NULL, "SendSyncRequest3"}, - {0x31, NULL, "SendSyncRequest4"}, - {0x32, WrapI_U<SendSyncRequest>, "SendSyncRequest"}, - {0x33, NULL, "OpenProcess"}, - {0x34, NULL, "OpenThread"}, - {0x35, NULL, "GetProcessId"}, - {0x36, NULL, "GetProcessIdOfThread"}, - {0x37, NULL, "GetThreadId"}, - {0x38, NULL, "GetResourceLimit"}, - {0x39, NULL, "GetResourceLimitLimitValues"}, - {0x3A, NULL, "GetResourceLimitCurrentValues"}, - {0x3B, NULL, "GetThreadContext"}, - {0x3C, NULL, "Break"}, - {0x3D, NULL, "OutputDebugString"}, - {0x3E, NULL, "ControlPerformanceCounter"}, - {0x3F, NULL, "Unknown"}, - {0x40, NULL, "Unknown"}, - {0x41, NULL, "Unknown"}, - {0x42, NULL, "Unknown"}, - {0x43, NULL, "Unknown"}, - {0x44, NULL, "Unknown"}, - {0x45, NULL, "Unknown"}, - {0x46, NULL, "Unknown"}, - {0x47, NULL, "CreatePort"}, - {0x48, NULL, "CreateSessionToPort"}, - {0x49, NULL, "CreateSession"}, - {0x4A, NULL, "AcceptSession"}, - {0x4B, NULL, "ReplyAndReceive1"}, - {0x4C, NULL, "ReplyAndReceive2"}, - {0x4D, NULL, "ReplyAndReceive3"}, - {0x4E, NULL, "ReplyAndReceive4"}, - {0x4F, NULL, "ReplyAndReceive"}, - {0x50, NULL, "BindInterrupt"}, - {0x51, NULL, "UnbindInterrupt"}, - {0x52, NULL, "InvalidateProcessDataCache"}, - {0x53, NULL, "StoreProcessDataCache"}, - {0x54, NULL, "FlushProcessDataCache"}, - {0x55, NULL, "StartInterProcessDma"}, - {0x56, NULL, "StopDma"}, - {0x57, NULL, "GetDmaState"}, - {0x58, NULL, "RestartDma"}, - {0x59, NULL, "Unknown"}, - {0x5A, NULL, "Unknown"}, - {0x5B, NULL, "Unknown"}, - {0x5C, NULL, "Unknown"}, - {0x5D, NULL, "Unknown"}, - {0x5E, NULL, "Unknown"}, - {0x5F, NULL, "Unknown"}, - {0x60, NULL, "DebugActiveProcess"}, - {0x61, NULL, "BreakDebugProcess"}, - {0x62, NULL, "TerminateDebugProcess"}, - {0x63, NULL, "GetProcessDebugEvent"}, - {0x64, NULL, "ContinueDebugEvent"}, - {0x65, NULL, "GetProcessList"}, - {0x66, NULL, "GetThreadList"}, - {0x67, NULL, "GetDebugThreadContext"}, - {0x68, NULL, "SetDebugThreadContext"}, - {0x69, NULL, "QueryDebugProcessMemory"}, - {0x6A, NULL, "ReadProcessMemory"}, - {0x6B, NULL, "WriteProcessMemory"}, - {0x6C, NULL, "SetHardwareBreakPoint"}, - {0x6D, NULL, "GetDebugThreadParam"}, - {0x6E, NULL, "Unknown"}, - {0x6F, NULL, "Unknown"}, - {0x70, NULL, "ControlProcessMemory"}, - {0x71, NULL, "MapProcessMemory"}, - {0x72, NULL, "UnmapProcessMemory"}, - {0x73, NULL, "Unknown"}, - {0x74, NULL, "Unknown"}, - {0x75, NULL, "Unknown"}, - {0x76, NULL, "TerminateProcess"}, - {0x77, NULL, "Unknown"}, - {0x78, NULL, "CreateResourceLimit"}, - {0x79, NULL, "Unknown"}, - {0x7A, NULL, "Unknown"}, - {0x7B, NULL, "Unknown"}, - {0x7C, NULL, "KernelSetState"}, - {0x7D, NULL, "QueryProcessMemory"}, + {0x00, NULL, "Unknown"}, + {0x01, WrapI_UUUUU<ControlMemory>, "ControlMemory"}, + {0x02, NULL, "QueryMemory"}, + {0x03, NULL, "ExitProcess"}, + {0x04, NULL, "GetProcessAffinityMask"}, + {0x05, NULL, "SetProcessAffinityMask"}, + {0x06, NULL, "GetProcessIdealProcessor"}, + {0x07, NULL, "SetProcessIdealProcessor"}, + {0x08, NULL, "CreateThread"}, + {0x09, NULL, "ExitThread"}, + {0x0A, NULL, "SleepThread"}, + {0x0B, NULL, "GetThreadPriority"}, + {0x0C, NULL, "SetThreadPriority"}, + {0x0D, NULL, "GetThreadAffinityMask"}, + {0x0E, NULL, "SetThreadAffinityMask"}, + {0x0F, NULL, "GetThreadIdealProcessor"}, + {0x10, NULL, "SetThreadIdealProcessor"}, + {0x11, NULL, "GetCurrentProcessorNumber"}, + {0x12, NULL, "Run"}, + {0x13, NULL, "CreateMutex"}, + {0x14, NULL, "ReleaseMutex"}, + {0x15, NULL, "CreateSemaphore"}, + {0x16, NULL, "ReleaseSemaphore"}, + {0x17, NULL, "CreateEvent"}, + {0x18, NULL, "SignalEvent"}, + {0x19, NULL, "ClearEvent"}, + {0x1A, NULL, "CreateTimer"}, + {0x1B, NULL, "SetTimer"}, + {0x1C, NULL, "CancelTimer"}, + {0x1D, NULL, "ClearTimer"}, + {0x1E, NULL, "CreateMemoryBlock"}, + {0x1F, WrapI_UUUU<MapMemoryBlock>, "MapMemoryBlock"}, + {0x20, NULL, "UnmapMemoryBlock"}, + {0x21, WrapI_V<CreateAddressArbiter>, "CreateAddressArbiter"}, + {0x22, NULL, "ArbitrateAddress"}, + {0x23, WrapI_U<CloseHandle>, "CloseHandle"}, + {0x24, WrapI_US64<WaitSynchronization1>, "WaitSynchronization1"}, + {0x25, NULL, "WaitSynchronizationN"}, + {0x26, NULL, "SignalAndWait"}, + {0x27, NULL, "DuplicateHandle"}, + {0x28, NULL, "GetSystemTick"}, + {0x29, NULL, "GetHandleInfo"}, + {0x2A, NULL, "GetSystemInfo"}, + {0x2B, NULL, "GetProcessInfo"}, + {0x2C, NULL, "GetThreadInfo"}, + {0x2D, WrapI_VC<ConnectToPort>, "ConnectToPort"}, + {0x2E, NULL, "SendSyncRequest1"}, + {0x2F, NULL, "SendSyncRequest2"}, + {0x30, NULL, "SendSyncRequest3"}, + {0x31, NULL, "SendSyncRequest4"}, + {0x32, WrapI_U<SendSyncRequest>, "SendSyncRequest"}, + {0x33, NULL, "OpenProcess"}, + {0x34, NULL, "OpenThread"}, + {0x35, NULL, "GetProcessId"}, + {0x36, NULL, "GetProcessIdOfThread"}, + {0x37, NULL, "GetThreadId"}, + {0x38, WrapI_VU<GetResourceLimit>, "GetResourceLimit"}, + {0x39, NULL, "GetResourceLimitLimitValues"}, + {0x3A, WrapI_VUVI<GetResourceLimitCurrentValues>, "GetResourceLimitCurrentValues"}, + {0x3B, NULL, "GetThreadContext"}, + {0x3C, NULL, "Break"}, + {0x3D, WrapV_C<OutputDebugString>, "OutputDebugString"}, + {0x3E, NULL, "ControlPerformanceCounter"}, + {0x3F, NULL, "Unknown"}, + {0x40, NULL, "Unknown"}, + {0x41, NULL, "Unknown"}, + {0x42, NULL, "Unknown"}, + {0x43, NULL, "Unknown"}, + {0x44, NULL, "Unknown"}, + {0x45, NULL, "Unknown"}, + {0x46, NULL, "Unknown"}, + {0x47, NULL, "CreatePort"}, + {0x48, NULL, "CreateSessionToPort"}, + {0x49, NULL, "CreateSession"}, + {0x4A, NULL, "AcceptSession"}, + {0x4B, NULL, "ReplyAndReceive1"}, + {0x4C, NULL, "ReplyAndReceive2"}, + {0x4D, NULL, "ReplyAndReceive3"}, + {0x4E, NULL, "ReplyAndReceive4"}, + {0x4F, NULL, "ReplyAndReceive"}, + {0x50, NULL, "BindInterrupt"}, + {0x51, NULL, "UnbindInterrupt"}, + {0x52, NULL, "InvalidateProcessDataCache"}, + {0x53, NULL, "StoreProcessDataCache"}, + {0x54, NULL, "FlushProcessDataCache"}, + {0x55, NULL, "StartInterProcessDma"}, + {0x56, NULL, "StopDma"}, + {0x57, NULL, "GetDmaState"}, + {0x58, NULL, "RestartDma"}, + {0x59, NULL, "Unknown"}, + {0x5A, NULL, "Unknown"}, + {0x5B, NULL, "Unknown"}, + {0x5C, NULL, "Unknown"}, + {0x5D, NULL, "Unknown"}, + {0x5E, NULL, "Unknown"}, + {0x5F, NULL, "Unknown"}, + {0x60, NULL, "DebugActiveProcess"}, + {0x61, NULL, "BreakDebugProcess"}, + {0x62, NULL, "TerminateDebugProcess"}, + {0x63, NULL, "GetProcessDebugEvent"}, + {0x64, NULL, "ContinueDebugEvent"}, + {0x65, NULL, "GetProcessList"}, + {0x66, NULL, "GetThreadList"}, + {0x67, NULL, "GetDebugThreadContext"}, + {0x68, NULL, "SetDebugThreadContext"}, + {0x69, NULL, "QueryDebugProcessMemory"}, + {0x6A, NULL, "ReadProcessMemory"}, + {0x6B, NULL, "WriteProcessMemory"}, + {0x6C, NULL, "SetHardwareBreakPoint"}, + {0x6D, NULL, "GetDebugThreadParam"}, + {0x6E, NULL, "Unknown"}, + {0x6F, NULL, "Unknown"}, + {0x70, NULL, "ControlProcessMemory"}, + {0x71, NULL, "MapProcessMemory"}, + {0x72, NULL, "UnmapProcessMemory"}, + {0x73, NULL, "Unknown"}, + {0x74, NULL, "Unknown"}, + {0x75, NULL, "Unknown"}, + {0x76, NULL, "TerminateProcess"}, + {0x77, NULL, "Unknown"}, + {0x78, NULL, "CreateResourceLimit"}, + {0x79, NULL, "Unknown"}, + {0x7A, NULL, "Unknown"}, + {0x7B, NULL, "Unknown"}, + {0x7C, NULL, "KernelSetState"}, + {0x7D, NULL, "QueryProcessMemory"}, }; void Register() { diff --git a/src/core/loader.cpp b/src/core/loader.cpp index 7c1dfef61..8756588ae 100644 --- a/src/core/loader.cpp +++ b/src/core/loader.cpp @@ -89,8 +89,8 @@ bool Load_DAT(std::string &filename) { * but for the sake of making it easier... we'll temporarily/hackishly * allow it. No sense in making a proper reader for this. */ - u32 entrypoint = 0x080c3ee0; // write to same entrypoint as elf - u32 payload_offset = 0x6F4; + u32 entrypoint = 0x00100000; // write to same entrypoint as elf + u32 payload_offset = 0xA150; const u8 *src = &buffer[payload_offset]; u8 *dst = Memory::GetPointer(entrypoint); @@ -114,6 +114,47 @@ bool Load_DAT(std::string &filename) { return true; } + +/// Loads a CTR BIN file extracted from an ExeFS +bool Load_BIN(std::string &filename) { + std::string full_path = filename; + std::string path, file, extension; + SplitPath(ReplaceAll(full_path, "\\", "/"), &path, &file, &extension); +#if EMU_PLATFORM == PLATFORM_WINDOWS + path = ReplaceAll(path, "/", "\\"); +#endif + File::IOFile f(filename, "rb"); + + if (f.IsOpen()) { + u64 size = f.GetSize(); + u8* buffer = new u8[size]; + + f.ReadBytes(buffer, size); + + u32 entrypoint = 0x00100000; // Hardcoded, read from exheader + + const u8 *src = buffer; + u8 *dst = Memory::GetPointer(entrypoint); + u32 srcSize = size; + u32 *s = (u32*)src; + u32 *d = (u32*)dst; + for (int j = 0; j < (int)(srcSize + 3) / 4; j++) + { + *d++ = (*s++); + } + + Core::g_app_core->SetPC(entrypoint); + + delete[] buffer; + } + else { + return false; + } + f.Close(); + + return true; +} + namespace Loader { bool IsBootableDirectory() { @@ -145,6 +186,9 @@ FileType IdentifyFile(std::string &filename) { else if (!strcasecmp(extension.c_str(), ".elf")) { return FILETYPE_CTR_ELF; // TODO(bunnei): Do some filetype checking :p } + else if (!strcasecmp(extension.c_str(), ".bin")) { + return FILETYPE_CTR_BIN; + } else if (!strcasecmp(extension.c_str(), ".dat")) { return FILETYPE_LAUNCHER_DAT; } @@ -178,6 +222,9 @@ bool LoadFile(std::string &filename, std::string *error_string) { case FILETYPE_CTR_ELF: return Load_ELF(filename); + case FILETYPE_CTR_BIN: + return Load_BIN(filename); + case FILETYPE_LAUNCHER_DAT: return Load_DAT(filename); @@ -215,7 +262,7 @@ bool LoadFile(std::string &filename, std::string *error_string) { case FILETYPE_UNKNOWN: default: ERROR_LOG(LOADER, "Failed to identify file"); - *error_string = "Failed to identify file"; + *error_string = " Failed to identify file"; break; } return false; diff --git a/src/core/loader.h b/src/core/loader.h index df30f16c7..9d4aaa874 100644 --- a/src/core/loader.h +++ b/src/core/loader.h @@ -17,19 +17,21 @@ enum FileType { FILETYPE_CTR_CIA, FILETYPE_CTR_CXI, FILETYPE_CTR_ELF, - FILETYPE_LAUNCHER_DAT, - - FILETYPE_DIRECTORY_CXI, - - FILETYPE_UNKNOWN_BIN, - FILETYPE_UNKNOWN_ELF, + FILETYPE_CTR_BIN, - FILETYPE_ARCHIVE_RAR, - FILETYPE_ARCHIVE_ZIP, - - FILETYPE_NORMAL_DIRECTORY, + FILETYPE_LAUNCHER_DAT, - FILETYPE_UNKNOWN + FILETYPE_DIRECTORY_CXI, + + FILETYPE_UNKNOWN_BIN, + FILETYPE_UNKNOWN_ELF, + + FILETYPE_ARCHIVE_RAR, + FILETYPE_ARCHIVE_ZIP, + + FILETYPE_NORMAL_DIRECTORY, + + FILETYPE_UNKNOWN }; //////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp index af99cbe32..59560b87d 100644 --- a/src/core/mem_map.cpp +++ b/src/core/mem_map.cpp @@ -21,6 +21,7 @@ u8* g_heap = NULL; ///< Application heap (main memo u8* g_heap_gsp = NULL; ///< GSP heap (main memory) u8* g_vram = NULL; ///< Video memory (VRAM) pointer u8* g_shared_mem = NULL; ///< Shared memory +u8* g_kernel_mem; ///< Kernel memory u8* g_physical_bootrom = NULL; ///< Bootrom physical memory u8* g_uncached_bootrom = NULL; @@ -30,6 +31,7 @@ u8* g_physical_fcram = NULL; ///< Main physical memory (FCRAM u8* g_physical_heap_gsp = NULL; ///< GSP heap physical memory u8* g_physical_vram = NULL; ///< Video physical memory (VRAM) u8* g_physical_shared_mem = NULL; ///< Physical shared memory +u8* g_physical_kernel_mem; ///< Kernel memory // We don't declare the IO region in here since its handled by other means. static MemoryView g_views[] = { @@ -37,6 +39,7 @@ static MemoryView g_views[] = { {&g_vram, &g_physical_vram, VRAM_VADDR, VRAM_SIZE, 0}, {&g_heap, &g_physical_fcram, HEAP_VADDR, HEAP_SIZE, MV_IS_PRIMARY_RAM}, {&g_shared_mem, &g_physical_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, 0}, + {&g_kernel_mem, &g_physical_kernel_mem, KERNEL_MEMORY_VADDR, KERNEL_MEMORY_SIZE, 0}, {&g_heap_gsp, &g_physical_heap_gsp, HEAP_GSP_VADDR, HEAP_GSP_SIZE, 0}, }; diff --git a/src/core/mem_map.h b/src/core/mem_map.h index 62a8b82a8..af2212a5f 100644 --- a/src/core/mem_map.h +++ b/src/core/mem_map.h @@ -32,6 +32,16 @@ enum { SHARED_MEMORY_VADDR_END = (SHARED_MEMORY_VADDR + SHARED_MEMORY_SIZE), SHARED_MEMORY_MASK = (SHARED_MEMORY_SIZE - 1), + CONFIG_MEMORY_SIZE = 0x00001000, ///< Configuration memory size + CONFIG_MEMORY_VADDR = 0x1FF80000, ///< Configuration memory virtual address + CONFIG_MEMORY_VADDR_END = (CONFIG_MEMORY_VADDR + CONFIG_MEMORY_SIZE), + CONFIG_MEMORY_MASK = (CONFIG_MEMORY_SIZE - 1), + + KERNEL_MEMORY_SIZE = 0x00001000, ///< Kernel memory size + KERNEL_MEMORY_VADDR = 0xFFFF0000, ///< Kernel memory where the kthread objects etc are + KERNEL_MEMORY_VADDR_END = (KERNEL_MEMORY_VADDR + KERNEL_MEMORY_SIZE), + KERNEL_MEMORY_MASK = (KERNEL_MEMORY_SIZE - 1), + EXEFS_CODE_SIZE = 0x03F00000, EXEFS_CODE_VADDR = 0x00100000, ///< ExeFS:/.code is loaded here EXEFS_CODE_VADDR_END = (EXEFS_CODE_VADDR + EXEFS_CODE_SIZE), @@ -105,6 +115,7 @@ extern u8* g_heap_gsp; ///< GSP heap (main memory) extern u8* g_heap; ///< Application heap (main memory) extern u8* g_vram; ///< Video memory (VRAM) extern u8* g_shared_mem; ///< Shared memory +extern u8* g_kernel_mem; ///< Kernel memory extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here void Init(); diff --git a/src/core/mem_map_funcs.cpp b/src/core/mem_map_funcs.cpp index 2284b535c..8ab647714 100644 --- a/src/core/mem_map_funcs.cpp +++ b/src/core/mem_map_funcs.cpp @@ -9,6 +9,7 @@ #include "core/mem_map.h" #include "core/hw/hw.h" #include "hle/hle.h" +#include "hle/config_mem.h" namespace Memory { @@ -46,12 +47,10 @@ inline void _Read(T &var, const u32 addr) { // Could just do a base-relative read, too.... TODO const u32 vaddr = _VirtualAddress(addr); - - // Memory allocated for HLE use that can be addressed from the emulated application - // The primary use of this is sharing a commandbuffer between the HLE OS (syscore) and the LLE - // core running the user application (appcore) - if (vaddr >= HLE::CMD_BUFFER_ADDR && vaddr < HLE::CMD_BUFFER_ADDR_END) { - HLE::Read<T>(var, vaddr); + + // Kernel memory command buffer + if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) { + var = *((const T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK]); // Hardware I/O register reads // 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space @@ -74,6 +73,10 @@ inline void _Read(T &var, const u32 addr) { } else if ((vaddr >= SHARED_MEMORY_VADDR) && (vaddr < SHARED_MEMORY_VADDR_END)) { var = *((const T*)&g_shared_mem[vaddr & SHARED_MEMORY_MASK]); + // Config memory + } else if ((vaddr >= CONFIG_MEMORY_VADDR) && (vaddr < CONFIG_MEMORY_VADDR_END)) { + ConfigMem::Read<T>(var, vaddr); + // VRAM } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { var = *((const T*)&g_vram[vaddr & VRAM_MASK]); @@ -87,11 +90,9 @@ template <typename T> inline void _Write(u32 addr, const T data) { u32 vaddr = _VirtualAddress(addr); - // Memory allocated for HLE use that can be addressed from the emulated application - // The primary use of this is sharing a commandbuffer between the HLE OS (syscore) and the LLE - // core running the user application (appcore) - if (vaddr >= HLE::CMD_BUFFER_ADDR && vaddr < HLE::CMD_BUFFER_ADDR_END) { - HLE::Write<T>(vaddr, data); + // Kernel memory command buffer + if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) { + *(T*)&g_kernel_mem[vaddr & KERNEL_MEMORY_MASK] = data; // Hardware I/O register writes // 0x10XXXXXX- is physical address space, 0x1EXXXXXX is virtual address space @@ -118,12 +119,12 @@ inline void _Write(u32 addr, const T data) { } else if ((vaddr >= VRAM_VADDR) && (vaddr < VRAM_VADDR_END)) { *(T*)&g_vram[vaddr & VRAM_MASK] = data; - } else if ((vaddr & 0xFFF00000) == 0x1FF00000) { - _assert_msg_(MEMMAP, false, "umimplemented write to DSP memory"); - } else if ((vaddr & 0xFFFF0000) == 0x1FF80000) { - _assert_msg_(MEMMAP, false, "umimplemented write to Configuration Memory"); - } else if ((vaddr & 0xFFFFF000) == 0x1FF81000) { - _assert_msg_(MEMMAP, false, "umimplemented write to shared page"); + //} else if ((vaddr & 0xFFF00000) == 0x1FF00000) { + // _assert_msg_(MEMMAP, false, "umimplemented write to DSP memory"); + //} else if ((vaddr & 0xFFFF0000) == 0x1FF80000) { + // _assert_msg_(MEMMAP, false, "umimplemented write to Configuration Memory"); + //} else if ((vaddr & 0xFFFFF000) == 0x1FF81000) { + // _assert_msg_(MEMMAP, false, "umimplemented write to shared page"); // Error out... } else { @@ -135,8 +136,12 @@ inline void _Write(u32 addr, const T data) { u8 *GetPointer(const u32 addr) { const u32 vaddr = _VirtualAddress(addr); + // Kernel memory command buffer + if (vaddr >= KERNEL_MEMORY_VADDR && vaddr < KERNEL_MEMORY_VADDR_END) { + return g_kernel_mem + (vaddr & KERNEL_MEMORY_MASK); + // ExeFS:/.code is loaded here - if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) { + } else if ((vaddr >= EXEFS_CODE_VADDR) && (vaddr < EXEFS_CODE_VADDR_END)) { return g_exefs_code + (vaddr & EXEFS_CODE_MASK); // FCRAM - GSP heap |