diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..ca304b62
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,6 @@
+[submodule "app/libraries/tinyxml2"]
+ path = app/libraries/tinyxml2
+ url = https://github.com/leethomason/tinyxml2
+[submodule "app/libraries/fmt"]
+ path = app/libraries/fmt
+ url = https://github.com/fmtlib/fmt
diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
new file mode 100644
index 00000000..b522fcfe
--- /dev/null
+++ b/.idea/codeStyles/Project.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml
new file mode 100644
index 00000000..79ee123c
--- /dev/null
+++ b/.idea/codeStyles/codeStyleConfig.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/discord.xml b/.idea/discord.xml
new file mode 100644
index 00000000..1a65715f
--- /dev/null
+++ b/.idea/discord.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 00000000..35ee3ce2
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 37a75096..51b39f74 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -1,5 +1,40 @@
+
+
+
+
+
+
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 35eb1ddf..c399eec8 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,5 +2,7 @@
+
+
\ No newline at end of file
diff --git a/app/CMakeLists.txt b/app/CMakeLists.txt
index ea548beb..7e3bf2ff 100644
--- a/app/CMakeLists.txt
+++ b/app/CMakeLists.txt
@@ -1,20 +1,28 @@
-cmake_minimum_required (VERSION 3.2)
+cmake_minimum_required(VERSION 3.8)
project(Lightswitch VERSION 1 LANGUAGES CXX)
set_property(GLOBAL PROPERTY CMAKE_CXX_STANDARD 17 PROPERTY CMAKE_CXX_STANDARD_REQUIRED TRUE)
+set(BUILD_TESTS FALSE)
+set(CMAKE_CXX_STANDARD 17)
+set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
+add_subdirectory("libraries/tinyxml2")
+add_subdirectory("libraries/fmt")
+
set(source_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp)
-include_directories(${source_DIR}/include)
+include_directories(libraries/unicorn/include)
include_directories(${source_DIR})
add_library(lightswitch SHARED
${source_DIR}/lightswitch.cpp
- ${source_DIR}/core/arm/cpu.cpp
- ${source_DIR}/core/arm/memory.cpp
-
- ${source_DIR}/core/hos/kernel/ipc.cpp
- ${source_DIR}/core/hos/kernel/kernel.cpp
- ${source_DIR}/core/hos/kernel/svc.cpp
- ${source_DIR}/core/hos/loaders/nro.cpp
-)
-target_link_libraries(lightswitch ${source_DIR}/lib/${ANDROID_ABI}/libunicorn.a)
+ ${source_DIR}/switch/os/os.cpp
+ ${source_DIR}/switch/os/ipc.cpp
+ ${source_DIR}/switch/os/kernel.cpp
+ ${source_DIR}/switch/os/svc.cpp
+ ${source_DIR}/switch/hw/cpu.cpp
+ ${source_DIR}/switch/hw/memory.cpp
+ ${source_DIR}/switch/common.cpp
+ ${source_DIR}/switch/loader/nro.cpp
+ )
+target_link_libraries(lightswitch ${CMAKE_SOURCE_DIR}/libraries/unicorn/libunicorn.a fmt tinyxml2)
+target_compile_options(lightswitch PRIVATE -Wno-c++17-extensions)
diff --git a/app/build.gradle b/app/build.gradle
index 5e35c98b..e3730acc 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -4,28 +4,28 @@ android {
compileSdkVersion 29
buildToolsVersion "29.0.0"
defaultConfig {
- applicationId "gq.cyuubi.lightswitch"
+ applicationId "emu.lightswitch.lightswitch"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
- externalNativeBuild {
- cmake {
- cppFlags ""
- }
- }
ndk {
abiFilters "arm64-v8a"
}
}
buildTypes {
release {
+ minifyEnabled true
+ useProguard false
+ }
+ debug {
minifyEnabled false
- proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+ useProguard false
}
}
externalNativeBuild {
cmake {
+ version "3.8.0+"
path "CMakeLists.txt"
}
}
@@ -40,6 +40,7 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.0.2'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
- implementation 'androidx.preference:preference:1.1.0-beta01'
+ implementation 'androidx.preference:preference:1.1.0-rc01'
implementation 'com.google.android.material:material:1.0.0'
+ implementation 'me.xdrop:fuzzywuzzy:1.2.0'
}
diff --git a/app/libraries/fmt b/app/libraries/fmt
new file mode 160000
index 00000000..6a497e1d
--- /dev/null
+++ b/app/libraries/fmt
@@ -0,0 +1 @@
+Subproject commit 6a497e1d061993cce54c2d71506a90155a3725e6
diff --git a/app/libraries/tinyxml2 b/app/libraries/tinyxml2
new file mode 160000
index 00000000..61a4c7d5
--- /dev/null
+++ b/app/libraries/tinyxml2
@@ -0,0 +1 @@
+Subproject commit 61a4c7d507322c9f494f5880d4c94b60e4ce9590
diff --git a/app/src/main/cpp/include/unicorn/arm64.h b/app/libraries/unicorn/include/unicorn/arm64.h
similarity index 100%
rename from app/src/main/cpp/include/unicorn/arm64.h
rename to app/libraries/unicorn/include/unicorn/arm64.h
diff --git a/app/src/main/cpp/include/unicorn/platform.h b/app/libraries/unicorn/include/unicorn/platform.h
similarity index 100%
rename from app/src/main/cpp/include/unicorn/platform.h
rename to app/libraries/unicorn/include/unicorn/platform.h
diff --git a/app/src/main/cpp/include/unicorn/unicorn.h b/app/libraries/unicorn/include/unicorn/unicorn.h
similarity index 100%
rename from app/src/main/cpp/include/unicorn/unicorn.h
rename to app/libraries/unicorn/include/unicorn/unicorn.h
diff --git a/app/src/main/cpp/lib/arm64-v8a/libunicorn.a b/app/libraries/unicorn/libunicorn.a
similarity index 100%
rename from app/src/main/cpp/lib/arm64-v8a/libunicorn.a
rename to app/libraries/unicorn/libunicorn.a
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d42488e2..1dece4ef 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -1,30 +1,39 @@
+ xmlns:tools="http://schemas.android.com/tools"
+ package="emu.lightswitch.lightswitch">
-
-
+
+
-
+ android:allowBackup="true"
+ android:icon="@mipmap/ic_launcher"
+ android:label="@string/app_name"
+ android:roundIcon="@mipmap/ic_launcher_round"
+ android:supportsRtl="true"
+ android:theme="@style/AppTheme"
+ tools:ignore="GoogleAppIndexingWarning">
+
+ android:name="android.support.PARENT_ACTIVITY"
+ android:value="emu.lightswitch.lightswitch.MainActivity"/>
+
+
+
-
+
-
+
diff --git a/app/src/main/cpp/core/arm/cpu.cpp b/app/src/main/cpp/core/arm/cpu.cpp
deleted file mode 100644
index e543ba5e..00000000
--- a/app/src/main/cpp/core/arm/cpu.cpp
+++ /dev/null
@@ -1,89 +0,0 @@
-#include
-#include "cpu.h"
-#include "memory.h"
-#include "core/hos/kernel/svc.h"
-
-// TODO: Handle Unicorn errors
-namespace core::cpu {
- uc_engine *uc;
-
- void HookInterrupt(uc_engine *uc, uint32_t intno, void *user_data);
-
- bool Initialize()
- {
- uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc);
-
- uc_hook hook{};
- uc_hook_add(uc, &hook, UC_HOOK_INTR, (void *) HookInterrupt, 0, 1, 0);
-
- // Map stack memory
- if (!memory::Map(0x3000000, 0x1000000, "Stack")) return false;
- SetRegister(UC_ARM64_REG_SP, 0x3100000);
-
- // Map TLS memory
- if (!memory::Map(0x2000000, 0x1000, "TLS")) return false;
- SetRegister(UC_ARM64_REG_TPIDRRO_EL0, 0x2000000);
-
- return true;
- }
-
- void Run(uint64_t address)
- {
- uc_err err = uc_emu_start(uc, address, 1ULL << 63, 0, 0);
- if (err) syslog(LOG_ERR, "uc_emu_start failed: %s", uc_strerror(err));
- }
-
- uint64_t GetRegister(uint32_t regid)
- {
- uint64_t registerValue;
- uc_reg_read(uc, regid, ®isterValue);
- return registerValue;
- }
-
- void SetRegister(uint32_t regid, uint64_t value)
- {
- uc_reg_write(uc, regid, &value);
- }
-
- void HookInterrupt(uc_engine *uc, uint32_t intno, void *user_data)
- {
- if (intno == 2)
- {
- uint32_t instr{};
- uc_mem_read(uc, GetRegister(UC_ARM64_REG_PC) - 4, &instr, 4);
-
- uint32_t svcId = instr >> 5 & 0xFF;
-
- if (core::kernel::SvcHandler(svcId) == 0x177202)
- uc_close(uc);
- }
- else
- {
- syslog(LOG_ERR, "Unhandled interrupt #%i", intno);
- uc_close(uc);
- }
- }
-}
-
-// FIXME: Move this back to memory.cpp - zephyren25
-namespace core::memory {
- bool Map(uint64_t address, size_t size, std::string label) {
- void *ptr = mmap((void*)(address), size, PROT_EXEC | PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANON, 0, 0);
- if (!ptr)
- {
- syslog(LOG_ERR, "Failed mapping region '%s'", label.c_str());
- return false;
- }
-
- uc_err err = uc_mem_map_ptr(core::cpu::uc, address, size, UC_PROT_ALL, (void*)(address));
- if (err)
- {
- syslog(LOG_ERR, "UC map failed: %s", uc_strerror(err));
- return false;
- }
-
- syslog(LOG_DEBUG, "Successfully mapped region '%s' to 0x%x", label.c_str(), address);
- return true;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/cpp/core/arm/cpu.h b/app/src/main/cpp/core/arm/cpu.h
deleted file mode 100644
index 82cbc6ac..00000000
--- a/app/src/main/cpp/core/arm/cpu.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#pragma once
-#include
-#include
-
-namespace core::cpu {
- bool Initialize();
- void Run(uint64_t address);
-
- uint64_t GetRegister(uint32_t regid);
- void SetRegister(uint32_t regid, uint64_t value);
-
-// bool MapUnicorn(uint64_t address, size_t size);
-}
\ No newline at end of file
diff --git a/app/src/main/cpp/core/arm/memory.cpp b/app/src/main/cpp/core/arm/memory.cpp
deleted file mode 100644
index 0e8bf7d5..00000000
--- a/app/src/main/cpp/core/arm/memory.cpp
+++ /dev/null
@@ -1,40 +0,0 @@
-#include
-#include
-#include
-#include "memory.h"
-
-namespace core::memory {
- /*std::vector memoryRegions;
-
- bool Map(uint64_t address, size_t size, std::string label) {
- void* ptr = mmap((void*)(address), size, PROT_EXEC | PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, 0, 0);
- if (!ptr) {
- syslog(LOG_ERR, "Failed mapping region '%s'", label.c_str());
- return false;
- }
-
- syslog(LOG_INFO, "Mapping region '%s' to 0x%x, pointer %x", label.c_str(), address, (uint64_t)ptr);
-
- if (core::cpu::MapUnicorn(address, size, ptr)) return false;
-
- syslog(LOG_INFO, "Successfully mapped region '%s' to 0x%x", label.c_str(), address);
-
- memoryRegions.push_back({label, address, size, ptr});
- return true;
- }*/
-
- // TODO: Boundary checks
- void Write(void* data, uint64_t offset, size_t size) { std::memcpy((void*)(offset), data, size); }
-
- void WriteU8(uint8_t value, uint64_t offset) { Write(reinterpret_cast(&value), offset, 1); }
- void WriteU16(uint16_t value, uint64_t offset) { Write(reinterpret_cast(&value), offset, 2); }
- void WriteU32(uint32_t value, uint64_t offset) { Write(reinterpret_cast(&value), offset, 4); }
- void WriteU64(uint64_t value, uint64_t offset) { Write(reinterpret_cast(&value), offset, 8); }
-
- void Read(void* destination, uint64_t offset, size_t size) { std::memcpy(destination, (void*)(offset), size); }
-
- uint8_t ReadU8(uint64_t offset) { uint8_t value; Read(reinterpret_cast(&value), offset, 1); return value; }
- uint16_t ReadU16(uint64_t offset) { uint16_t value; Read(reinterpret_cast(&value), offset, 2); return value; }
- uint32_t ReadU32(uint64_t offset) { uint32_t value; Read(reinterpret_cast(&value), offset, 4); return value; }
- uint64_t ReadU64(uint64_t offset) { uint64_t value; Read(reinterpret_cast(&value), offset, 8); return value; }
-}
\ No newline at end of file
diff --git a/app/src/main/cpp/core/arm/memory.h b/app/src/main/cpp/core/arm/memory.h
deleted file mode 100644
index f7e02762..00000000
--- a/app/src/main/cpp/core/arm/memory.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#pragma once
-#include
-#include
-
-#define BASE_ADDRESS 0x80000000
-
-namespace core::memory {
- /*struct MemoryRegion {
- std::string label;
- uint64_t address;
- size_t size;
- void* ptr;
- };*/
-
- bool Map(uint64_t address, size_t size, std::string label = {});
-
- void Write(void* data, uint64_t offset, size_t size);
-
- void WriteU8(uint8_t value, uint64_t offset);
- void WriteU16(uint16_t value, uint64_t offset);
- void WriteU32(uint32_t value, uint64_t offset);
- void WriteU64(uint64_t value, uint64_t offset);
-
- void Read(void* destination, uint64_t offset, size_t size);
-
- uint8_t ReadU8(uint64_t offset);
- uint16_t ReadU16(uint64_t offset);
- uint32_t ReadU32(uint64_t offset);
- uint64_t ReadU64(uint64_t offset);
-}
\ No newline at end of file
diff --git a/app/src/main/cpp/core/hos/kernel/ipc.cpp b/app/src/main/cpp/core/hos/kernel/ipc.cpp
deleted file mode 100644
index 8fdba736..00000000
--- a/app/src/main/cpp/core/hos/kernel/ipc.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-#include
-#include
-#include "ipc.h"
-
-namespace core::kernel
-{
- IpcRequest::IpcRequest(uint8_t* tlsPtr)
- {
- for(int i = 0; i < 32; i++)
- syslog(LOG_DEBUG, "%02x\t%02x %02x %02x %02x %02x %02x %02x %02x", i*8, tlsPtr[0+(i*8)], tlsPtr[1+(i*8)], tlsPtr[2+(i*8)], tlsPtr[3+(i*8)], tlsPtr[4+(i*8)], tlsPtr[5+(i*8)], tlsPtr[6+(i*8)], tlsPtr[7+(i*8)]);
- syslog(LOG_DEBUG, "-----------------------");
- uint32_t word1 = ((uint32_t*)tlsPtr)[1];
- type = *(uint16_t*)tlsPtr;
- xCount = tlsPtr[2] & 0xF0 >> 4;
- aCount = tlsPtr[2] & 0x0F;
- bCount = tlsPtr[3] & 0xF0 >> 4;
- wCount = tlsPtr[3] & 0x0F;
- dataSize = word1 & 0x3FF;
- dataPos = 8;
-
- if(tlsPtr[2] || tlsPtr[3])
- {
- syslog(LOG_ERR, "IPC - X/A/B/W descriptors");
- exit(0);
- }
-
- syslog(LOG_DEBUG, "Enable handle descriptor: %s", word1 >> 31 ? "yes" : "no");
- if(word1 >> 31)
- {
- syslog(LOG_ERR, "IPC - Handle descriptor");
- exit(0);
- }
-
- // Align to 16 bytes
- if((dataPos % 16) != 0)
- dataPos += 16 - (dataPos % 16);
- dataPtr = &tlsPtr[dataPos+16];
-
- syslog(LOG_DEBUG, "Type: %x", type);
- syslog(LOG_DEBUG, "X descriptors: 0x%x", xCount);
- syslog(LOG_DEBUG, "A descriptors: 0x%x", aCount);
- syslog(LOG_DEBUG, "B descriptors: 0x%x", bCount);
- syslog(LOG_DEBUG, "W descriptors: 0x%x", wCount);
- syslog(LOG_DEBUG, "Raw data size: 0x%x", word1 & 0x3FF);
- syslog(LOG_DEBUG, "Data offset=%x, Data size=%x", dataPos, dataSize);
- syslog(LOG_DEBUG, "Payload CmdId=%i", *((uint32_t*)&tlsPtr[dataPos+8]));
- syslog(LOG_DEBUG, "Setting dataPtr to %08x", dataPos+16);
- }
-}
\ No newline at end of file
diff --git a/app/src/main/cpp/core/hos/kernel/ipc.h b/app/src/main/cpp/core/hos/kernel/ipc.h
deleted file mode 100644
index 657392b2..00000000
--- a/app/src/main/cpp/core/hos/kernel/ipc.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#pragma once
-#include
-
-namespace core::kernel
-{
-class IpcRequest
-{
-public:
- IpcRequest(uint8_t* tlsPtr);
-
- template
- T GetValue()
- {
- dataPos += sizeof(T);
- return *reinterpret_cast(&dataPtr[dataPos-sizeof(T)]);
- }
-
- uint16_t type, xCount, aCount, bCount, wCount;
- uint32_t dataSize;
-
-private:
- uint8_t* dataPtr;
- uint32_t dataPos;
-};
-
-class IpcResponse
-{
-public:
- IpcResponse() {}
-};
-}
\ No newline at end of file
diff --git a/app/src/main/cpp/core/hos/kernel/kernel.cpp b/app/src/main/cpp/core/hos/kernel/kernel.cpp
deleted file mode 100644
index 7c4675af..00000000
--- a/app/src/main/cpp/core/hos/kernel/kernel.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-#include
-#include
-#include "kernel.h"
-
-namespace core::kernel
-{
- std::unordered_map handles;
- uint32_t handleIndex = 0xd001;
-
- uint32_t NewHandle(KObjectPtr obj)
- {
- handles.insert({handleIndex, obj});
- syslog(LOG_DEBUG, "Creating new handle 0x%x", handleIndex);
- return handleIndex++;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/cpp/core/hos/kernel/kernel.h b/app/src/main/cpp/core/hos/kernel/kernel.h
deleted file mode 100644
index 309d3c23..00000000
--- a/app/src/main/cpp/core/hos/kernel/kernel.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#pragma once
-#include
-#include
-
-#define SM_HANDLE 0xd000 // sm: is hardcoded for now
-
-namespace core::kernel
-{
- class KObject
- {
- public:
- KObject(uint32_t handle) : handle(handle) {}
- uint32_t Handle() { return handle; }
- private:
- uint32_t handle;
- };
-
- typedef std::shared_ptr KObjectPtr;
-
- uint32_t NewHandle(KObjectPtr obj);
-}
\ No newline at end of file
diff --git a/app/src/main/cpp/core/hos/kernel/svc.cpp b/app/src/main/cpp/core/hos/kernel/svc.cpp
deleted file mode 100644
index 5a1b9a9e..00000000
--- a/app/src/main/cpp/core/hos/kernel/svc.cpp
+++ /dev/null
@@ -1,219 +0,0 @@
-#include
-#include
-#include
-#include
-#include "core/arm/cpu.h"
-#include "core/arm/memory.h"
-#include "kernel.h"
-#include "ipc.h"
-#include "svc.h"
-
-using namespace core::cpu;
-namespace core::kernel {
- static uint32_t ConnectToNamedPort()
- {
- std::string port(8, '\0');
- memory::Read((void*)port.data(), GetRegister(UC_ARM64_REG_X1), 8);
-
- if(std::strcmp(port.c_str(), "sm:") == 0)
- SetRegister(UC_ARM64_REG_W1, SM_HANDLE);
- else
- {
- syslog(LOG_ERR, "svcConnectToNamedPort tried connecting to invalid port '%s'", port.c_str());
- exit(0);
- }
-
- return 0;
- }
-
- static uint32_t SendSyncRequest()
- {
- syslog(LOG_INFO, "svcSendSyncRequest called for handle 0x%x, dumping TLS:", GetRegister(UC_ARM64_REG_X0));
- uint8_t tls[0x100];
- memory::Read(&tls, 0x2000000, 0x100);
-
- core::kernel::IpcRequest* r = new core::kernel::IpcRequest(tls);
-
- exit(0);
- return 0;
- }
-
- static uint32_t OutputDebugString()
- {
- std::string debug(GetRegister(UC_ARM64_REG_X1), '\0');
- memory::Read((void*)debug.data(), GetRegister(UC_ARM64_REG_X0), GetRegister(UC_ARM64_REG_X1));
-
- syslog(LOG_DEBUG, "svcOutputDebugString: %s", debug.c_str());
- return 0;
- }
-
- static uint32_t GetInfo()
- {
- switch (GetRegister(UC_ARM64_REG_X1))
- {
- case 8: // IsCurrentProcessBeingDebugged
- SetRegister(UC_ARM64_REG_X1, 0); // We're just lying to ourselves. Think about it
- break;
- case 12: // AddressSpaceBaseAddr
- SetRegister(UC_ARM64_REG_X1, BASE_ADDRESS);
- break;
- case 18: // TitleId
- SetRegister(UC_ARM64_REG_X1, 0); // TODO: Add this
- break;
- default:
- syslog(LOG_ERR, "Unimplemented GetInfo ID! ID1 = %i, ID2 = %i", GetRegister(UC_ARM64_REG_X1), GetRegister(UC_ARM64_REG_X3));
- return 0x177202;
- }
-
- return 0;
- }
-
- std::pair svcTable[] =
- {
- {0x00, nullptr},
- {0x01, nullptr},
- {0x02, nullptr},
- {0x03, nullptr},
- {0x04, nullptr},
- {0x05, nullptr},
- {0x06, nullptr},
- {0x07, nullptr},
- {0x08, nullptr},
- {0x09, nullptr},
- {0x0a, nullptr},
- {0x0b, nullptr},
- {0x0c, nullptr},
- {0x0d, nullptr},
- {0x0e, nullptr},
- {0x0f, nullptr},
- {0x10, nullptr},
- {0x11, nullptr},
- {0x12, nullptr},
- {0x13, nullptr},
- {0x14, nullptr},
- {0x15, nullptr},
- {0x16, nullptr},
- {0x17, nullptr},
- {0x18, nullptr},
- {0x19, nullptr},
- {0x1a, nullptr},
- {0x1b, nullptr},
- {0x1c, nullptr},
- {0x1d, nullptr},
- {0x1e, nullptr},
- {0x1f, ConnectToNamedPort},
- {0x20, nullptr},
- {0x21, SendSyncRequest},
- {0x22, nullptr},
- {0x23, nullptr},
- {0x24, nullptr},
- {0x25, nullptr},
- {0x26, nullptr},
- {0x27, OutputDebugString},
- {0x28, nullptr},
- {0x29, GetInfo},
- {0x2a, nullptr},
- {0x2b, nullptr},
- {0x2c, nullptr},
- {0x2d, nullptr},
- {0x2e, nullptr},
- {0x2f, nullptr},
- {0x30, nullptr},
- {0x31, nullptr},
- {0x32, nullptr},
- {0x33, nullptr},
- {0x34, nullptr},
- {0x35, nullptr},
- {0x36, nullptr},
- {0x37, nullptr},
- {0x38, nullptr},
- {0x39, nullptr},
- {0x3a, nullptr},
- {0x3b, nullptr},
- {0x3c, nullptr},
- {0x3d, nullptr},
- {0x3e, nullptr},
- {0x3f, nullptr},
- {0x40, nullptr},
- {0x41, nullptr},
- {0x42, nullptr},
- {0x43, nullptr},
- {0x44, nullptr},
- {0x45, nullptr},
- {0x46, nullptr},
- {0x47, nullptr},
- {0x48, nullptr},
- {0x49, nullptr},
- {0x4a, nullptr},
- {0x4b, nullptr},
- {0x4c, nullptr},
- {0x4d, nullptr},
- {0x4e, nullptr},
- {0x4f, nullptr},
- {0x50, nullptr},
- {0x51, nullptr},
- {0x52, nullptr},
- {0x53, nullptr},
- {0x54, nullptr},
- {0x55, nullptr},
- {0x56, nullptr},
- {0x57, nullptr},
- {0x58, nullptr},
- {0x59, nullptr},
- {0x5a, nullptr},
- {0x5b, nullptr},
- {0x5c, nullptr},
- {0x5d, nullptr},
- {0x5e, nullptr},
- {0x5f, nullptr},
- {0x60, nullptr},
- {0x61, nullptr},
- {0x62, nullptr},
- {0x63, nullptr},
- {0x64, nullptr},
- {0x65, nullptr},
- {0x66, nullptr},
- {0x67, nullptr},
- {0x68, nullptr},
- {0x69, nullptr},
- {0x6a, nullptr},
- {0x6b, nullptr},
- {0x6c, nullptr},
- {0x6d, nullptr},
- {0x6e, nullptr},
- {0x6f, nullptr},
- {0x70, nullptr},
- {0x71, nullptr},
- {0x72, nullptr},
- {0x73, nullptr},
- {0x74, nullptr},
- {0x75, nullptr},
- {0x76, nullptr},
- {0x77, nullptr},
- {0x78, nullptr},
- {0x79, nullptr},
- {0x7a, nullptr},
- {0x7b, nullptr},
- {0x7c, nullptr},
- {0x7d, nullptr},
- {0x7e, nullptr},
- {0x7f, nullptr}
- };
-
- uint32_t SvcHandler(uint32_t svc)
- {
- std::pair* result = &(svcTable[svc]);
-
- if (result->second)
- {
- uint32_t returnCode = result->second();
- SetRegister(UC_ARM64_REG_W0, returnCode);
- return returnCode;
- }
- else
- {
- syslog(LOG_ERR, "Unimplemented SVC 0x%02x", svc);
- return 0x177202; // "Unimplemented behaviour"
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/cpp/core/hos/kernel/svc.h b/app/src/main/cpp/core/hos/kernel/svc.h
deleted file mode 100644
index 0d9b7ae4..00000000
--- a/app/src/main/cpp/core/hos/kernel/svc.h
+++ /dev/null
@@ -1,5 +0,0 @@
-#pragma once
-
-namespace core::kernel {
- uint32_t SvcHandler(uint32_t svc);
-}
\ No newline at end of file
diff --git a/app/src/main/cpp/core/hos/loaders/nro.cpp b/app/src/main/cpp/core/hos/loaders/nro.cpp
deleted file mode 100644
index 6414a842..00000000
--- a/app/src/main/cpp/core/hos/loaders/nro.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-#include
-#include
-#include
-#include
-#include "core/arm/cpu.h"
-#include "core/arm/memory.h"
-#include "nro.h"
-
-void ReadDataFromFile(std::string file, char* output, uint32_t offset, size_t size)
-{
- std::ifstream f(file, std::ios::binary | std::ios::beg);
-
- f.seekg(offset);
- f.read(output, size);
-
- f.close();
-}
-
-namespace core::loader {
- bool LoadNro(std::string filePath)
- {
- syslog(LOG_INFO, "Loading NRO file %s\n", filePath.c_str());
-
- NroHeader header;
- ReadDataFromFile(filePath, reinterpret_cast(&header), 0x0, sizeof(NroHeader));
- if (header.magic != 0x304F524E)
- {
- syslog(LOG_ERR, "Invalid NRO magic 0x%x\n", header.magic);
- return false;
- }
-
- std::vector text, ro, data;
- text.resize(header.segments[0].size);
- ro.resize (header.segments[1].size);
- data.resize(header.segments[2].size);
-
- ReadDataFromFile(filePath, reinterpret_cast(text.data()), header.segments[0].fileOffset, header.segments[0].size);
- ReadDataFromFile(filePath, reinterpret_cast(ro.data()), header.segments[1].fileOffset, header.segments[1].size);
- ReadDataFromFile(filePath, reinterpret_cast(data.data()), header.segments[2].fileOffset, header.segments[2].size);
-
- if (!memory::Map(BASE_ADDRESS, header.segments[0].size, ".text") ||
- !memory::Map(BASE_ADDRESS + header.segments[0].size, header.segments[1].size, ".ro") ||
- !memory::Map(BASE_ADDRESS + header.segments[0].size + header.segments[1].size, header.segments[2].size, ".data") ||
- !memory::Map(BASE_ADDRESS + header.segments[0].size + header.segments[1].size + header.segments[2].size, header.bssSize, ".bss"))
- {
- syslog(LOG_ERR, "Failed mapping regions for executable");
- return false;
- }
-
- memory::Write(text.data(), BASE_ADDRESS, text.size());
- memory::Write(ro.data(), BASE_ADDRESS + header.segments[0].size, ro.size());
- memory::Write(data.data(), BASE_ADDRESS + header.segments[0].size + header.segments[1].size, data.size());
- return true;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/cpp/core/hos/loaders/nro.h b/app/src/main/cpp/core/hos/loaders/nro.h
deleted file mode 100644
index 1b8291d1..00000000
--- a/app/src/main/cpp/core/hos/loaders/nro.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#pragma once
-#include
-
-namespace core::loader {
- struct NroSegmentHeader {
- uint32_t fileOffset;
- uint32_t size;
- };
-
- struct NroHeader {
- uint32_t unused;
- uint32_t modOffset;
- uint64_t padding;
-
- uint32_t magic;
- uint32_t version;
- uint32_t size;
- uint32_t flags;
-
- NroSegmentHeader segments[3];
-
- uint32_t bssSize;
- uint32_t reserved0;
- uint64_t buildId[4];
- uint64_t reserved1;
-
- NroSegmentHeader extraSegments[3];
- };
-
- bool LoadNro(std::string filePath);
-}
\ No newline at end of file
diff --git a/app/src/main/cpp/lightswitch.cpp b/app/src/main/cpp/lightswitch.cpp
index fadc19a7..d3bbf0ae 100644
--- a/app/src/main/cpp/lightswitch.cpp
+++ b/app/src/main/cpp/lightswitch.cpp
@@ -1,16 +1,50 @@
#include
#include
-#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include "switch/device.h"
+#include "switch/common.h"
+
+std::thread *game_thread;
+
+void signal_handle(int sig_no) {
+ throw lightSwitch::exception("A signal has been raised: " + std::to_string(sig_no));
+}
+
+void thread_main(std::string rom_path, std::string pref_path, std::string log_path) {
+ auto log = std::make_shared(log_path);
+ log->write(lightSwitch::Logger::INFO, "Launching ROM {0}", rom_path);
+// long long i = 0;
+// while(true){
+// log->write(lightSwitch::Logger::INFO, "#{0}", i);
+// sleep(1);
+// i++;
+// }
+ auto settings = std::make_shared(pref_path);
+ try {
+ lightSwitch::device device(log, settings);
+ device.run(rom_path);
+ log->write(lightSwitch::Logger::INFO, "Emulation has ended!");
+ } catch (std::exception &e) {
+ log->write(lightSwitch::Logger::ERROR, e.what());
+ } catch (...) {
+ log->write(lightSwitch::Logger::ERROR, "An unknown exception has occurred.");
+ }
+}
extern "C"
JNIEXPORT void JNICALL
-Java_gq_cyuubi_lightswitch_MainActivity_loadFile(JNIEnv *env, jobject instance, jstring file_) {
- const char *file = env->GetStringUTFChars(file_, 0);
- core::cpu::Initialize();
- core::loader::LoadNro(file);
- core::cpu::Run(BASE_ADDRESS);
- env->ReleaseStringUTFChars(file_, file);
+Java_emu_lightswitch_lightswitch_MainActivity_loadFile(JNIEnv *env, jobject instance, jstring rom_path_,
+ jstring pref_path_, jstring log_path_) {
+ const char *rom_path = env->GetStringUTFChars(rom_path_, 0);
+ const char *pref_path = env->GetStringUTFChars(pref_path_, 0);
+ const char *log_path = env->GetStringUTFChars(log_path_, 0);
+ // std::signal(SIGABRT, signal_handle);
+ if (game_thread) pthread_kill(game_thread->native_handle(), SIGABRT);
+ // Running on UI thread is not a good idea, any crashes and such will be propagated
+ game_thread = new std::thread(thread_main, std::string(rom_path, strlen(rom_path)), std::string(pref_path, strlen(pref_path)), std::string(log_path, strlen(log_path)));
+ env->ReleaseStringUTFChars(rom_path_, rom_path);
+ env->ReleaseStringUTFChars(pref_path_, pref_path);
+ env->ReleaseStringUTFChars(log_path_, log_path);
}
\ No newline at end of file
diff --git a/app/src/main/cpp/switch/common.cpp b/app/src/main/cpp/switch/common.cpp
new file mode 100644
index 00000000..f2417590
--- /dev/null
+++ b/app/src/main/cpp/switch/common.cpp
@@ -0,0 +1,81 @@
+#include "common.h"
+#include
+#include
+
+namespace lightSwitch {
+ // Settings
+ Settings::Settings(std::string pref_xml) {
+ tinyxml2::XMLDocument pref;
+ if (pref.LoadFile(pref_xml.c_str())) {
+ syslog(LOG_ERR, "TinyXML2 Error: %s", pref.ErrorStr());
+ throw pref.ErrorID();
+ }
+ tinyxml2::XMLElement *elem = pref.LastChild()->FirstChild()->ToElement();
+ while (elem) {
+ switch (elem->Value()[0]) {
+ case 's':
+ string_map.insert(
+ std::pair((char *) elem->FindAttribute("name")->Value(),
+ (char *) elem->GetText()));
+ break;
+ case 'b':
+ bool_map.insert(
+ std::pair((char *) elem->FindAttribute("name")->Value(),
+ elem->FindAttribute("value")->BoolValue()));
+ default:
+ break;
+ };
+ if (elem->NextSibling())
+ elem = elem->NextSibling()->ToElement();
+ else break;
+ }
+ pref.Clear();
+ }
+
+ char *Settings::GetString(char *key) {
+ return string_map.at(key);
+ }
+
+ bool Settings::GetBool(char *key) {
+ return bool_map.at(key);
+ }
+
+ void Settings::List() {
+ auto it_s = string_map.begin();
+ while (it_s != string_map.end()) {
+ syslog(LOG_INFO, "Key: %s", it_s->first);
+ syslog(LOG_INFO, "Value: %s", GetString(it_s->first));
+ it_s++;
+ }
+ auto it_b = bool_map.begin();
+ while (it_b != bool_map.end()) {
+ syslog(LOG_INFO, "Key: %s", it_b->first);
+ syslog(LOG_INFO, "Value: %i", GetBool(it_b->first));
+ it_b++;
+ }
+ }
+
+ // Logger
+ Logger::Logger(std::string log_path) {
+ log_file.open(log_path, std::ios::app);
+ write_header("Logging started");
+ }
+
+ Logger::~Logger() {
+ write_header("Logging ended");
+ }
+
+ void Logger::write(Logger::LogLevel level, std::string str) {
+#ifdef NDEBUG
+ if (level == DEBUG)
+ return;
+#endif
+ log_file << "1|" << level_str[level] << "|" << str << "\n";
+ log_file.flush();
+ }
+
+ void Logger::write_header(std::string str) {
+ log_file << "0|" << str << "\n";
+ log_file.flush();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/cpp/switch/common.h b/app/src/main/cpp/switch/common.h
new file mode 100644
index 00000000..526a39c1
--- /dev/null
+++ b/app/src/main/cpp/switch/common.h
@@ -0,0 +1,71 @@
+#pragma once
+
+#include