mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 17:51:52 +01:00
Update Logger to use NDK Logger APIs + Improve Backing API + Fix FDSAN issues
This commit is contained in:
parent
4070686897
commit
97ac45d83b
@ -4,6 +4,7 @@
|
|||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
|
#include <android/log.h>
|
||||||
#include "skyline/loader/loader.h"
|
#include "skyline/loader/loader.h"
|
||||||
#include "skyline/common.h"
|
#include "skyline/common.h"
|
||||||
#include "skyline/os.h"
|
#include "skyline/os.h"
|
||||||
@ -12,24 +13,18 @@
|
|||||||
|
|
||||||
bool Halt;
|
bool Halt;
|
||||||
jobject Surface;
|
jobject Surface;
|
||||||
uint FaultCount;
|
|
||||||
skyline::GroupMutex JniMtx;
|
skyline::GroupMutex JniMtx;
|
||||||
skyline::u16 fps;
|
skyline::u16 fps;
|
||||||
skyline::u32 frametime;
|
skyline::u32 frametime;
|
||||||
std::weak_ptr<skyline::input::Input> inputWeak;
|
std::weak_ptr<skyline::input::Input> inputWeak;
|
||||||
|
|
||||||
void signalHandler(int signal) {
|
void signalHandler(int signal) {
|
||||||
syslog(LOG_ERR, "Halting program due to signal: %s", strsignal(signal));
|
__android_log_print(ANDROID_LOG_FATAL, "emu-cpp", "Halting program due to signal: %s", strsignal(signal));
|
||||||
if (FaultCount > 2)
|
exit(signal);
|
||||||
exit(SIGKILL);
|
|
||||||
else
|
|
||||||
Halt = true;
|
|
||||||
FaultCount++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(JNIEnv *env, jobject instance, jstring romUriJstring, jint romType, jint romFd, jint preferenceFd, jstring appFilesPathJstring) {
|
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(JNIEnv *env, jobject instance, jstring romUriJstring, jint romType, jint romFd, jint preferenceFd, jstring appFilesPathJstring) {
|
||||||
Halt = false;
|
Halt = false;
|
||||||
FaultCount = 0;
|
|
||||||
fps = 0;
|
fps = 0;
|
||||||
frametime = 0;
|
frametime = 0;
|
||||||
|
|
||||||
@ -44,6 +39,7 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
|||||||
|
|
||||||
auto jvmManager{std::make_shared<skyline::JvmManager>(env, instance)};
|
auto jvmManager{std::make_shared<skyline::JvmManager>(env, instance)};
|
||||||
auto settings{std::make_shared<skyline::Settings>(preferenceFd)};
|
auto settings{std::make_shared<skyline::Settings>(preferenceFd)};
|
||||||
|
close(preferenceFd);
|
||||||
|
|
||||||
auto appFilesPath{env->GetStringUTFChars(appFilesPathJstring, nullptr)};
|
auto appFilesPath{env->GetStringUTFChars(appFilesPathJstring, nullptr)};
|
||||||
auto logger{std::make_shared<skyline::Logger>(std::string(appFilesPath) + "skyline.log", static_cast<skyline::Logger::LogLevel>(std::stoi(settings->GetString("log_level"))))};
|
auto logger{std::make_shared<skyline::Logger>(std::string(appFilesPath) + "skyline.log", static_cast<skyline::Logger::LogLevel>(std::stoi(settings->GetString("log_level"))))};
|
||||||
@ -74,6 +70,8 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
|||||||
|
|
||||||
auto end{std::chrono::steady_clock::now()};
|
auto end{std::chrono::steady_clock::now()};
|
||||||
logger->Info("Done in: {} ms", (std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()));
|
logger->Info("Done in: {} ms", (std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count()));
|
||||||
|
|
||||||
|
close(romFd);
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_setHalt(JNIEnv *, jobject, jboolean halt) {
|
extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_setHalt(JNIEnv *, jobject, jboolean halt) {
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
// Copyright © 2020 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
#include <tinyxml2.h>
|
#include <tinyxml2.h>
|
||||||
|
#include <android/log.h>
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "nce.h"
|
#include "nce.h"
|
||||||
#include "gpu.h"
|
#include "gpu.h"
|
||||||
@ -68,11 +69,12 @@ namespace skyline {
|
|||||||
Settings::Settings(int fd) {
|
Settings::Settings(int fd) {
|
||||||
tinyxml2::XMLDocument pref;
|
tinyxml2::XMLDocument pref;
|
||||||
|
|
||||||
if (pref.LoadFile(fdopen(fd, "r")))
|
auto fileDeleter = [](FILE *file) { fclose(file); };
|
||||||
|
std::unique_ptr<FILE, decltype(fileDeleter)> file{fdopen(fd, "r"), fileDeleter};
|
||||||
|
if (pref.LoadFile(file.get()))
|
||||||
throw exception("TinyXML2 Error: " + std::string(pref.ErrorStr()));
|
throw exception("TinyXML2 Error: " + std::string(pref.ErrorStr()));
|
||||||
|
|
||||||
tinyxml2::XMLElement *elem{pref.LastChild()->FirstChild()->ToElement()};
|
tinyxml2::XMLElement *elem{pref.LastChild()->FirstChild()->ToElement()};
|
||||||
|
|
||||||
while (elem) {
|
while (elem) {
|
||||||
switch (elem->Value()[0]) {
|
switch (elem->Value()[0]) {
|
||||||
case 's':
|
case 's':
|
||||||
@ -88,7 +90,7 @@ namespace skyline {
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
syslog(LOG_ALERT, "Settings type is missing: %s for %s", elem->Value(), elem->FindAttribute("name")->Value());
|
__android_log_print(ANDROID_LOG_WARN, "emu-cpp", "Settings type is missing: %s for %s", elem->Value(), elem->FindAttribute("name")->Value());
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -122,7 +124,7 @@ namespace skyline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Logger::Logger(const std::string &path, LogLevel configLevel) : configLevel(configLevel) {
|
Logger::Logger(const std::string &path, LogLevel configLevel) : configLevel(configLevel) {
|
||||||
logFile.open(path, std::ios::app);
|
logFile.open(path, std::ios::trunc);
|
||||||
WriteHeader("Logging started");
|
WriteHeader("Logging started");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,14 +134,17 @@ namespace skyline {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void Logger::WriteHeader(const std::string &str) {
|
void Logger::WriteHeader(const std::string &str) {
|
||||||
syslog(LOG_ALERT, "%s", str.c_str());
|
__android_log_write(ANDROID_LOG_INFO, "emu-cpp", str.c_str());
|
||||||
|
|
||||||
std::lock_guard guard(mtx);
|
std::lock_guard guard(mtx);
|
||||||
logFile << "0|" << str << "\n";
|
logFile << "0|" << str << "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Logger::Write(LogLevel level, std::string str) {
|
void Logger::Write(LogLevel level, std::string str) {
|
||||||
syslog(levelSyslog[static_cast<u8>(level)], "%s", str.c_str());
|
constexpr std::array<char, 4> levelCharacter{'0', '1', '2', '3'}; // The LogLevel as written out to a file
|
||||||
|
constexpr std::array<int, 4> levelAlog{ANDROID_LOG_ERROR, ANDROID_LOG_WARN, ANDROID_LOG_INFO, ANDROID_LOG_DEBUG}; // This corresponds to LogLevel and provides it's equivalent for NDK Logging
|
||||||
|
|
||||||
|
__android_log_write(levelAlog[static_cast<u8>(level)], "emu-cpp", str.c_str());
|
||||||
|
|
||||||
for (auto &character : str)
|
for (auto &character : str)
|
||||||
if (character == '\n')
|
if (character == '\n')
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <syslog.h>
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
#include <frozen/unordered_map.h>
|
#include <frozen/unordered_map.h>
|
||||||
@ -366,8 +365,6 @@ namespace skyline {
|
|||||||
class Logger {
|
class Logger {
|
||||||
private:
|
private:
|
||||||
std::ofstream logFile; //!< An output stream to the log file
|
std::ofstream logFile; //!< An output stream to the log file
|
||||||
std::array<char, 4> levelCharacter{'0', '1', '2', '3'}; //!< The LogLevel as written out to a file
|
|
||||||
static constexpr std::array<int, 4> levelSyslog{LOG_ERR, LOG_WARNING, LOG_INFO, LOG_DEBUG}; //!< This corresponds to LogLevel and provides it's equivalent for syslog
|
|
||||||
Mutex mtx; //!< A mutex to lock before logging anything
|
Mutex mtx; //!< A mutex to lock before logging anything
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -377,6 +374,7 @@ namespace skyline {
|
|||||||
Info,
|
Info,
|
||||||
Debug,
|
Debug,
|
||||||
};
|
};
|
||||||
|
|
||||||
LogLevel configLevel; //!< The minimum level of logs to write
|
LogLevel configLevel; //!< The minimum level of logs to write
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -457,9 +455,9 @@ namespace skyline {
|
|||||||
*/
|
*/
|
||||||
class Settings {
|
class Settings {
|
||||||
private:
|
private:
|
||||||
std::map<std::string, std::string> stringMap; //!< A mapping from all keys to their corresponding string value
|
std::unordered_map<std::string, std::string> stringMap; //!< A mapping from all keys to their corresponding string value
|
||||||
std::map<std::string, bool> boolMap; //!< A mapping from all keys to their corresponding boolean value
|
std::unordered_map<std::string, bool> boolMap; //!< A mapping from all keys to their corresponding boolean value
|
||||||
std::map<std::string, int> intMap; //!< A mapping from all keys to their corresponding integer value
|
std::unordered_map<std::string, int> intMap; //!< A mapping from all keys to their corresponding integer value
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
@ -15,7 +15,7 @@ namespace skyline::crypto {
|
|||||||
|
|
||||||
void KeyStore::ReadPairs(const std::shared_ptr<vfs::Backing> &backing, ReadPairsCallback callback) {
|
void KeyStore::ReadPairs(const std::shared_ptr<vfs::Backing> &backing, ReadPairsCallback callback) {
|
||||||
std::vector<char> fileContent(backing->size);
|
std::vector<char> fileContent(backing->size);
|
||||||
backing->Read(fileContent.data(), 0, fileContent.size());
|
backing->Read(span(fileContent).cast<u8>());
|
||||||
|
|
||||||
auto lineStart{fileContent.begin()};
|
auto lineStart{fileContent.begin()};
|
||||||
std::vector<char>::iterator lineEnd;
|
std::vector<char>::iterator lineEnd;
|
||||||
|
@ -28,14 +28,14 @@ namespace skyline::crypto {
|
|||||||
std::map<Key128, Key128> titleKeys;
|
std::map<Key128, Key128> titleKeys;
|
||||||
|
|
||||||
std::unordered_map<std::string_view, std::optional<Key256> &> key256Names{
|
std::unordered_map<std::string_view, std::optional<Key256> &> key256Names{
|
||||||
{"header_key", headerKey}
|
{"header_key", headerKey},
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<std::string_view, IndexedKeys128 &> indexedKey128Names{
|
std::unordered_map<std::string_view, IndexedKeys128 &> indexedKey128Names{
|
||||||
{"titlekek_", titleKek},
|
{"titlekek_", titleKek},
|
||||||
{"key_area_key_application_", areaKeyApplication},
|
{"key_area_key_application_", areaKeyApplication},
|
||||||
{"key_area_key_ocean_", areaKeyOcean},
|
{"key_area_key_ocean_", areaKeyOcean},
|
||||||
{"key_area_key_system_", areaKeySystem}
|
{"key_area_key_system_", areaKeySystem},
|
||||||
};
|
};
|
||||||
|
|
||||||
using ReadPairsCallback = void (skyline::crypto::KeyStore::*)(std::string_view, std::string_view);
|
using ReadPairsCallback = void (skyline::crypto::KeyStore::*)(std::string_view, std::string_view);
|
||||||
|
@ -16,8 +16,8 @@ namespace skyline::kernel::type {
|
|||||||
class KSession : public KSyncObject {
|
class KSession : public KSyncObject {
|
||||||
public:
|
public:
|
||||||
std::shared_ptr<service::BaseService> serviceObject;
|
std::shared_ptr<service::BaseService> serviceObject;
|
||||||
std::unordered_map<KHandle, std::shared_ptr<service::BaseService>> domainTable; //!< A map from a virtual handle to it's service
|
std::vector<std::shared_ptr<service::BaseService>> domains; //!< A vector of services that correspond to virtual handles
|
||||||
KHandle handleIndex{0x1}; //!< The currently allocated handle index
|
KHandle handleIndex{}; //!< The currently allocated handle index
|
||||||
bool isOpen{true}; //!< If the session is open or not
|
bool isOpen{true}; //!< If the session is open or not
|
||||||
bool isDomain{}; //!< If this is a domain session or not
|
bool isDomain{}; //!< If this is a domain session or not
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ namespace skyline::kernel::type {
|
|||||||
*/
|
*/
|
||||||
KHandle ConvertDomain() {
|
KHandle ConvertDomain() {
|
||||||
isDomain = true;
|
isDomain = true;
|
||||||
domainTable[handleIndex] = serviceObject;
|
domains.push_back(serviceObject);
|
||||||
return handleIndex++;
|
return handleIndex++;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -10,14 +10,14 @@
|
|||||||
|
|
||||||
namespace skyline::loader {
|
namespace skyline::loader {
|
||||||
NroLoader::NroLoader(const std::shared_ptr<vfs::Backing> &backing) : backing(backing) {
|
NroLoader::NroLoader(const std::shared_ptr<vfs::Backing> &backing) : backing(backing) {
|
||||||
backing->Read(&header);
|
header = backing->Read<NroHeader>();
|
||||||
|
|
||||||
if (header.magic != util::MakeMagic<u32>("NRO0"))
|
if (header.magic != util::MakeMagic<u32>("NRO0"))
|
||||||
throw exception("Invalid NRO magic! 0x{0:X}", header.magic);
|
throw exception("Invalid NRO magic! 0x{0:X}", header.magic);
|
||||||
|
|
||||||
// The homebrew asset section is appended to the end of an NRO file
|
// The homebrew asset section is appended to the end of an NRO file
|
||||||
if (backing->size > header.size) {
|
if (backing->size > header.size) {
|
||||||
backing->Read(&assetHeader, header.size);
|
assetHeader = backing->Read<NroAssetHeader>(header.size);
|
||||||
|
|
||||||
if (assetHeader.magic != util::MakeMagic<u32>("ASET"))
|
if (assetHeader.magic != util::MakeMagic<u32>("ASET"))
|
||||||
throw exception("Invalid ASET magic! 0x{0:X}", assetHeader.magic);
|
throw exception("Invalid ASET magic! 0x{0:X}", assetHeader.magic);
|
||||||
@ -34,14 +34,14 @@ namespace skyline::loader {
|
|||||||
NroAssetSection &segmentHeader{assetHeader.icon};
|
NroAssetSection &segmentHeader{assetHeader.icon};
|
||||||
std::vector<u8> buffer(segmentHeader.size);
|
std::vector<u8> buffer(segmentHeader.size);
|
||||||
|
|
||||||
backing->Read(buffer.data(), header.size + segmentHeader.offset, segmentHeader.size);
|
backing->Read(buffer, header.size + segmentHeader.offset);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> NroLoader::GetSegment(const NroSegmentHeader &segment) {
|
std::vector<u8> NroLoader::GetSegment(const NroSegmentHeader &segment) {
|
||||||
std::vector<u8> buffer(segment.size);
|
std::vector<u8> buffer(segment.size);
|
||||||
|
|
||||||
backing->Read(buffer.data(), segment.offset, segment.size);
|
backing->Read(buffer, segment.offset);
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,8 +9,7 @@
|
|||||||
|
|
||||||
namespace skyline::loader {
|
namespace skyline::loader {
|
||||||
NsoLoader::NsoLoader(const std::shared_ptr<vfs::Backing> &backing) : backing(backing) {
|
NsoLoader::NsoLoader(const std::shared_ptr<vfs::Backing> &backing) : backing(backing) {
|
||||||
u32 magic{};
|
u32 magic{backing->Read<u32>()};
|
||||||
backing->Read(&magic);
|
|
||||||
|
|
||||||
if (magic != util::MakeMagic<u32>("NSO0"))
|
if (magic != util::MakeMagic<u32>("NSO0"))
|
||||||
throw exception("Invalid NSO magic! 0x{0:X}", magic);
|
throw exception("Invalid NSO magic! 0x{0:X}", magic);
|
||||||
@ -21,19 +20,18 @@ namespace skyline::loader {
|
|||||||
|
|
||||||
if (compressedSize) {
|
if (compressedSize) {
|
||||||
std::vector<u8> compressedBuffer(compressedSize);
|
std::vector<u8> compressedBuffer(compressedSize);
|
||||||
backing->Read(compressedBuffer.data(), segment.fileOffset, compressedSize);
|
backing->Read(compressedBuffer, segment.fileOffset);
|
||||||
|
|
||||||
LZ4_decompress_safe(reinterpret_cast<char *>(compressedBuffer.data()), reinterpret_cast<char *>(outputBuffer.data()), compressedSize, segment.decompressedSize);
|
LZ4_decompress_safe(reinterpret_cast<char *>(compressedBuffer.data()), reinterpret_cast<char *>(outputBuffer.data()), compressedSize, segment.decompressedSize);
|
||||||
} else {
|
} else {
|
||||||
backing->Read(outputBuffer.data(), segment.fileOffset, segment.decompressedSize);
|
backing->Read(outputBuffer, segment.fileOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return outputBuffer;
|
return outputBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader::ExecutableLoadInfo NsoLoader::LoadNso(const std::shared_ptr<vfs::Backing> &backing, const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state, size_t offset) {
|
Loader::ExecutableLoadInfo NsoLoader::LoadNso(const std::shared_ptr<vfs::Backing> &backing, const std::shared_ptr<kernel::type::KProcess> process, const DeviceState &state, size_t offset) {
|
||||||
NsoHeader header{};
|
auto header{backing->Read<NsoHeader>()};
|
||||||
backing->Read(&header);
|
|
||||||
|
|
||||||
if (header.magic != util::MakeMagic<u32>("NSO0"))
|
if (header.magic != util::MakeMagic<u32>("NSO0"))
|
||||||
throw exception("Invalid NSO magic! 0x{0:X}", header.magic);
|
throw exception("Invalid NSO magic! 0x{0:X}", header.magic);
|
||||||
|
@ -57,8 +57,7 @@ namespace skyline::loader {
|
|||||||
return std::vector<u8>();
|
return std::vector<u8>();
|
||||||
|
|
||||||
std::vector<u8> buffer(icon->size);
|
std::vector<u8> buffer(icon->size);
|
||||||
|
icon->Read(buffer);
|
||||||
icon->Read(buffer.data(), 0, icon->size);
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ namespace skyline::service::fssrv {
|
|||||||
return result::InvalidSize;
|
return result::InvalidSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
response.Push<u32>(static_cast<u32>(backing->Read(request.outputBuf.at(0).data(), offset, size)));
|
response.Push<u32>(static_cast<u32>(backing->Read(request.outputBuf.at(0), offset)));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,7 +48,7 @@ namespace skyline::service::fssrv {
|
|||||||
return result::InvalidSize;
|
return result::InvalidSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (backing->Write(request.inputBuf.at(0).data(), offset, request.inputBuf.at(0).size()) != size) {
|
if (backing->Write(request.inputBuf.at(0), offset) != size) {
|
||||||
state.logger->Warn("Failed to write all data to the backing");
|
state.logger->Warn("Failed to write all data to the backing");
|
||||||
return result::UnexpectedFailure;
|
return result::UnexpectedFailure;
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ namespace skyline::service::fssrv {
|
|||||||
return result::InvalidSize;
|
return result::InvalidSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
backing->Read(request.outputBuf.at(0).data(), offset, size);
|
backing->Read(request.outputBuf.at(0), offset);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10,7 +10,9 @@ namespace skyline::service::nvdrv {
|
|||||||
constexpr u32 VBlank0SyncpointId{26};
|
constexpr u32 VBlank0SyncpointId{26};
|
||||||
constexpr u32 VBlank1SyncpointId{27};
|
constexpr u32 VBlank1SyncpointId{27};
|
||||||
|
|
||||||
// Reserve both vblank syncpoints as client managed since the userspace driver has direct access to them
|
// Reserve both vblank syncpoints as client managed as they use Continuous Mode
|
||||||
|
// Refer to section 14.3.5.3 of the TRM for more information on Continuous Mode
|
||||||
|
// https://github.com/Jetson-TX1-AndroidTV/android_kernel_jetson_tx1_hdmi_primary/blob/8f74a72394efb871cb3f886a3de2998cd7ff2990/drivers/gpu/host1x/drm/dc.c#L660
|
||||||
ReserveSyncpoint(VBlank0SyncpointId, true);
|
ReserveSyncpoint(VBlank0SyncpointId, true);
|
||||||
ReserveSyncpoint(VBlank1SyncpointId, true);
|
ReserveSyncpoint(VBlank1SyncpointId, true);
|
||||||
}
|
}
|
||||||
@ -20,7 +22,7 @@ namespace skyline::service::nvdrv {
|
|||||||
throw exception("Requested syncpoint is in use");
|
throw exception("Requested syncpoint is in use");
|
||||||
|
|
||||||
syncpoints.at(id).reserved = true;
|
syncpoints.at(id).reserved = true;
|
||||||
syncpoints.at(id).clientManaged = clientManaged;
|
syncpoints.at(id).interfaceManaged = clientManaged;
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -44,7 +46,8 @@ namespace skyline::service::nvdrv {
|
|||||||
if (!syncpoint.reserved)
|
if (!syncpoint.reserved)
|
||||||
throw exception("Cannot check the expiry status of an unreserved syncpoint!");
|
throw exception("Cannot check the expiry status of an unreserved syncpoint!");
|
||||||
|
|
||||||
if (syncpoint.clientManaged)
|
// If the interface manages counters then we don't keep track of the maximum value as it handles sanity checking the values then
|
||||||
|
if (syncpoint.interfaceManaged)
|
||||||
return static_cast<i32>(syncpoint.counterMin - threshold) >= 0;
|
return static_cast<i32>(syncpoint.counterMin - threshold) >= 0;
|
||||||
else
|
else
|
||||||
return (syncpoint.counterMax - threshold) >= (syncpoint.counterMin - threshold);
|
return (syncpoint.counterMax - threshold) >= (syncpoint.counterMin - threshold);
|
||||||
|
@ -7,16 +7,17 @@
|
|||||||
|
|
||||||
namespace skyline::service::nvdrv {
|
namespace skyline::service::nvdrv {
|
||||||
/**
|
/**
|
||||||
* @brief NvHostSyncpoint handles allocating and accessing host1x syncpoints
|
* @brief NvHostSyncpoint handles allocating and accessing host1x syncpoints, these are cached versions of the HW syncpoints which are intermittently synced
|
||||||
|
* @note Refer to Chapter 14 of the Tegra X1 TRM for an exhaustive overview of them
|
||||||
* @url https://http.download.nvidia.com/tegra-public-appnotes/host1x.html
|
* @url https://http.download.nvidia.com/tegra-public-appnotes/host1x.html
|
||||||
* @url https://github.com/Jetson-TX1-AndroidTV/android_kernel_jetson_tx1_hdmi_primary/blob/jetson-tx1/drivers/video/tegra/host/nvhost_syncpt.c
|
* @url https://github.com/Jetson-TX1-AndroidTV/android_kernel_jetson_tx1_hdmi_primary/blob/jetson-tx1/drivers/video/tegra/host/nvhost_syncpt.c
|
||||||
*/
|
*/
|
||||||
class NvHostSyncpoint {
|
class NvHostSyncpoint {
|
||||||
private:
|
private:
|
||||||
struct SyncpointInfo {
|
struct SyncpointInfo {
|
||||||
std::atomic<u32> counterMin; //!< The least value the syncpoint can be (The value it was when it was last synchronized with the GPU for host managed syncpoints)
|
std::atomic<u32> counterMin; //!< The least value the syncpoint can be (The value it was when it was last synchronized with host1x)
|
||||||
std::atomic<u32> counterMax; //!< The maximum value the syncpoint can reach according to the current usage
|
std::atomic<u32> counterMax; //!< The maximum value the syncpoint can reach according to the current usage
|
||||||
bool clientManaged; //!< If the syncpoint is managed by the client (CPU) or host (GPU), it determines if the value is absolute or not
|
bool interfaceManaged; //!< If the syncpoint is managed by a host1x client interface, a client interface is a HW block that can handle host1x transactions on behalf of a host1x client (Which would otherwise need to be manually synced using PIO which is synchronous and requires direct cooperation of the CPU)
|
||||||
bool reserved;
|
bool reserved;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -89,9 +89,9 @@ namespace skyline::service {
|
|||||||
auto serviceObject{CreateService(name)};
|
auto serviceObject{CreateService(name)};
|
||||||
KHandle handle{};
|
KHandle handle{};
|
||||||
if (session.isDomain) {
|
if (session.isDomain) {
|
||||||
session.domainTable[++session.handleIndex] = serviceObject;
|
session.domains.push_back(serviceObject);
|
||||||
response.domainObjects.push_back(session.handleIndex);
|
response.domainObjects.push_back(session.handleIndex);
|
||||||
handle = session.handleIndex;
|
handle = session.handleIndex++;
|
||||||
} else {
|
} else {
|
||||||
handle = state.process->NewHandle<type::KSession>(serviceObject).handle;
|
handle = state.process->NewHandle<type::KSession>(serviceObject).handle;
|
||||||
response.moveHandles.push_back(handle);
|
response.moveHandles.push_back(handle);
|
||||||
@ -105,7 +105,7 @@ namespace skyline::service {
|
|||||||
KHandle handle{};
|
KHandle handle{};
|
||||||
|
|
||||||
if (session.isDomain) {
|
if (session.isDomain) {
|
||||||
session.domainTable[session.handleIndex] = serviceObject;
|
session.domains.push_back(serviceObject);
|
||||||
response.domainObjects.push_back(session.handleIndex);
|
response.domainObjects.push_back(session.handleIndex);
|
||||||
handle = session.handleIndex++;
|
handle = session.handleIndex++;
|
||||||
} else {
|
} else {
|
||||||
@ -121,9 +121,9 @@ namespace skyline::service {
|
|||||||
auto session{state.process->GetHandle<type::KSession>(handle)};
|
auto session{state.process->GetHandle<type::KSession>(handle)};
|
||||||
if (session->isOpen) {
|
if (session->isOpen) {
|
||||||
if (session->isDomain) {
|
if (session->isDomain) {
|
||||||
for (const auto &domainEntry : session->domainTable)
|
for (const auto &domainService : session->domains)
|
||||||
std::erase_if(serviceMap, [domainEntry](const auto &entry) {
|
std::erase_if(serviceMap, [domainService](const auto &entry) {
|
||||||
return entry.second == domainEntry.second;
|
return entry.second == domainService;
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
std::erase_if(serviceMap, [session](const auto &entry) {
|
std::erase_if(serviceMap, [session](const auto &entry) {
|
||||||
@ -148,7 +148,9 @@ namespace skyline::service {
|
|||||||
case ipc::CommandType::RequestWithContext:
|
case ipc::CommandType::RequestWithContext:
|
||||||
if (session->isDomain) {
|
if (session->isDomain) {
|
||||||
try {
|
try {
|
||||||
auto service{session->domainTable.at(request.domain->objectId)};
|
auto service{session->domains.at(request.domain->objectId)};
|
||||||
|
if (service == nullptr)
|
||||||
|
throw exception("Domain request used an expired handle");
|
||||||
switch (request.domain->command) {
|
switch (request.domain->command) {
|
||||||
case ipc::DomainCommand::SendMessage:
|
case ipc::DomainCommand::SendMessage:
|
||||||
response.errorCode = service->HandleRequest(*session, request, response);
|
response.errorCode = service->HandleRequest(*session, request, response);
|
||||||
@ -158,7 +160,7 @@ namespace skyline::service {
|
|||||||
std::erase_if(serviceMap, [service](const auto &entry) {
|
std::erase_if(serviceMap, [service](const auto &entry) {
|
||||||
return entry.second == service;
|
return entry.second == service;
|
||||||
});
|
});
|
||||||
session->domainTable.erase(request.domain->objectId);
|
session->domains.at(request.domain->objectId).reset();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (std::out_of_range &) {
|
} catch (std::out_of_range &) {
|
||||||
|
@ -11,9 +11,6 @@ namespace skyline::vfs {
|
|||||||
*/
|
*/
|
||||||
class Backing {
|
class Backing {
|
||||||
public:
|
public:
|
||||||
/**
|
|
||||||
* @brief The capabilities of the Backing
|
|
||||||
*/
|
|
||||||
union Mode {
|
union Mode {
|
||||||
struct {
|
struct {
|
||||||
bool read : 1; //!< The backing is readable
|
bool read : 1; //!< The backing is readable
|
||||||
@ -41,47 +38,44 @@ namespace skyline::vfs {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read bytes from the backing at a particular offset to a buffer
|
* @brief Read bytes from the backing at a particular offset to a buffer
|
||||||
* @param output The object to write to
|
* @param output The object to write the data read to
|
||||||
* @param offset The offset to start reading from
|
* @param offset The offset to start reading from
|
||||||
* @param size The amount to read in bytes
|
|
||||||
* @return The amount of bytes read
|
* @return The amount of bytes read
|
||||||
*/
|
*/
|
||||||
virtual size_t Read(u8 *output, size_t offset, size_t size) = 0;
|
virtual size_t Read(span<u8> output, size_t offset = 0) = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Read bytes from the backing at a particular offset to a buffer (template version)
|
* @brief Read bytes from the backing at a particular offset into an object
|
||||||
* @param output The object to write to
|
|
||||||
* @param offset The offset to start reading from
|
* @param offset The offset to start reading from
|
||||||
* @param size The amount to read in bytes
|
* @return The object that was read
|
||||||
* @return The amount of bytes read
|
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline size_t Read(T *output, size_t offset = 0, size_t size = 0) {
|
inline T Read(size_t offset = 0) {
|
||||||
return Read(reinterpret_cast<u8 *>(output), offset, size ? size : sizeof(T));
|
T object;
|
||||||
|
Read(span(reinterpret_cast<u8 *>(&object), sizeof(T)), offset);
|
||||||
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Writes from a buffer to a particular offset in the backing
|
* @brief Writes from a buffer to a particular offset in the backing
|
||||||
* @param input The object to write to the backing
|
* @param input The data to write to the backing
|
||||||
* @param offset The offset where the input buffer should be written
|
* @param offset The offset where the input buffer should be written
|
||||||
* @param size The amount to write
|
|
||||||
* @return The amount of bytes written
|
* @return The amount of bytes written
|
||||||
*/
|
*/
|
||||||
virtual size_t Write(u8 *input, size_t offset, size_t size) {
|
virtual size_t Write(span<u8> input, size_t offset = 0) {
|
||||||
throw exception("This backing does not support being written to");
|
throw exception("This backing does not support being written to");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Writes from a buffer to a particular offset in the backing (template version)
|
* @brief Writes from an object into a particular offset in the backing
|
||||||
* @tparam T The type of object to write
|
* @param object The object to write to the backing
|
||||||
* @param input The object to write to the backing
|
* @param offset The offset where the input should be written
|
||||||
* @param offset The offset where the input buffer should be written
|
|
||||||
* @param size The amount to write
|
|
||||||
* @return The amount of bytes written
|
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline size_t Write(T *output, size_t offset = 0, size_t size = 0) {
|
inline void WriteObject(const T& object, size_t offset = 0) {
|
||||||
return Write(reinterpret_cast<u8 *>(output), offset, size ? size : sizeof(T));
|
size_t size;
|
||||||
|
if((size = Write(span(reinterpret_cast<u8 *>(&object), sizeof(T)), offset)) != sizeof(T))
|
||||||
|
throw exception("Object wasn't written fully into output backing: {}/{}", size, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,34 +15,34 @@ namespace skyline::vfs {
|
|||||||
cipher.SetIV(ctr);
|
cipher.SetIV(ctr);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t CtrEncryptedBacking::Read(u8 *output, size_t offset, size_t size) {
|
size_t CtrEncryptedBacking::Read(span<u8> output, size_t offset) {
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
size_t sectorOffset{offset % SectorSize};
|
size_t sectorOffset{offset % SectorSize};
|
||||||
if (sectorOffset == 0) {
|
if (sectorOffset == 0) {
|
||||||
UpdateCtr(baseOffset + offset);
|
UpdateCtr(baseOffset + offset);
|
||||||
size_t read{backing->Read(output, offset, size)};
|
size_t read{backing->Read(output, offset)};
|
||||||
if (read != size)
|
if (read != size)
|
||||||
return 0;
|
return 0;
|
||||||
cipher.Decrypt({output, size});
|
cipher.Decrypt(output);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t sectorStart{offset - sectorOffset};
|
size_t sectorStart{offset - sectorOffset};
|
||||||
std::vector<u8> blockBuf(SectorSize);
|
std::vector<u8> blockBuf(SectorSize);
|
||||||
size_t read{backing->Read(blockBuf.data(), sectorStart, SectorSize)};
|
size_t read{backing->Read(blockBuf, sectorStart)};
|
||||||
if (read != SectorSize)
|
if (read != SectorSize)
|
||||||
return 0;
|
return 0;
|
||||||
UpdateCtr(baseOffset + sectorStart);
|
UpdateCtr(baseOffset + sectorStart);
|
||||||
cipher.Decrypt(blockBuf);
|
cipher.Decrypt(blockBuf);
|
||||||
if (size + sectorOffset < SectorSize) {
|
if (size + sectorOffset < SectorSize) {
|
||||||
std::memcpy(output, blockBuf.data() + sectorOffset, size);
|
std::memcpy(output.data(), blockBuf.data() + sectorOffset, size);
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t readInBlock{SectorSize - sectorOffset};
|
size_t readInBlock{SectorSize - sectorOffset};
|
||||||
std::memcpy(output, blockBuf.data() + sectorOffset, readInBlock);
|
std::memcpy(output.data(), blockBuf.data() + sectorOffset, readInBlock);
|
||||||
return readInBlock + Read(output + readInBlock, offset + readInBlock, size - readInBlock);
|
return readInBlock + Read(output.subspan(readInBlock), offset + readInBlock);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,6 @@ namespace skyline::vfs {
|
|||||||
public:
|
public:
|
||||||
CtrEncryptedBacking(crypto::KeyStore::Key128 &ctr, crypto::KeyStore::Key128 &key, const std::shared_ptr<Backing> &backing, size_t baseOffset);
|
CtrEncryptedBacking(crypto::KeyStore::Key128 &ctr, crypto::KeyStore::Key128 &key, const std::shared_ptr<Backing> &backing, size_t baseOffset);
|
||||||
|
|
||||||
size_t Read(u8 *output, size_t offset, size_t size) override;
|
size_t Read(span<u8> output, size_t offset = 0) override;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
namespace skyline::vfs {
|
namespace skyline::vfs {
|
||||||
NACP::NACP(const std::shared_ptr<vfs::Backing> &backing) {
|
NACP::NACP(const std::shared_ptr<vfs::Backing> &backing) {
|
||||||
backing->Read(&nacpContents);
|
nacpContents = backing->Read<NacpData>();
|
||||||
|
|
||||||
// TODO: Select based on language settings, complete struct, yada yada
|
// TODO: Select based on language settings, complete struct, yada yada
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ namespace skyline::vfs {
|
|||||||
using namespace loader;
|
using namespace loader;
|
||||||
|
|
||||||
NCA::NCA(const std::shared_ptr<vfs::Backing> &backing, const std::shared_ptr<crypto::KeyStore> &keyStore) : backing(backing), keyStore(keyStore) {
|
NCA::NCA(const std::shared_ptr<vfs::Backing> &backing, const std::shared_ptr<crypto::KeyStore> &keyStore) : backing(backing), keyStore(keyStore) {
|
||||||
backing->Read(&header);
|
header = backing->Read<NcaHeader>();
|
||||||
|
|
||||||
if (header.magic != util::MakeMagic<u32>("NCA3")) {
|
if (header.magic != util::MakeMagic<u32>("NCA3")) {
|
||||||
if (!keyStore->headerKey)
|
if (!keyStore->headerKey)
|
||||||
|
@ -20,22 +20,22 @@ namespace skyline::vfs {
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t OsBacking::Read(u8 *output, size_t offset, size_t size) {
|
size_t OsBacking::Read(span<u8> output, size_t offset) {
|
||||||
if (!mode.read)
|
if (!mode.read)
|
||||||
throw exception("Attempting to read a backing that is not readable");
|
throw exception("Attempting to read a backing that is not readable");
|
||||||
|
|
||||||
auto ret{pread64(fd, output, size, offset)};
|
auto ret{pread64(fd, output.data(), output.size(), offset)};
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
throw exception("Failed to read from fd: {}", strerror(errno));
|
throw exception("Failed to read from fd: {}", strerror(errno));
|
||||||
|
|
||||||
return static_cast<size_t>(ret);
|
return static_cast<size_t>(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t OsBacking::Write(u8 *output, size_t offset, size_t size) {
|
size_t OsBacking::Write(span<u8> input, size_t offset) {
|
||||||
if (!mode.write)
|
if (!mode.write)
|
||||||
throw exception("Attempting to write to a backing that is not writable");
|
throw exception("Attempting to write to a backing that is not writable");
|
||||||
|
|
||||||
auto ret{pwrite64(fd, output, size, offset)};
|
auto ret{pwrite64(fd, input.data(), input.size(), offset)};
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
throw exception("Failed to write to fd: {}", strerror(errno));
|
throw exception("Failed to write to fd: {}", strerror(errno));
|
||||||
|
|
||||||
|
@ -22,9 +22,9 @@ namespace skyline::vfs {
|
|||||||
|
|
||||||
~OsBacking();
|
~OsBacking();
|
||||||
|
|
||||||
size_t Read(u8 *output, size_t offset, size_t size);
|
size_t Read(span<u8> output, size_t offset = 0);
|
||||||
|
|
||||||
size_t Write(u8 *output, size_t offset, size_t size);
|
size_t Write(span<u8> input, size_t offset = 0);
|
||||||
|
|
||||||
void Resize(size_t size);
|
void Resize(size_t size);
|
||||||
};
|
};
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
namespace skyline::vfs {
|
namespace skyline::vfs {
|
||||||
PartitionFileSystem::PartitionFileSystem(std::shared_ptr<Backing> backing) : FileSystem(), backing(backing) {
|
PartitionFileSystem::PartitionFileSystem(std::shared_ptr<Backing> backing) : FileSystem(), backing(backing) {
|
||||||
backing->Read(&header);
|
header = backing->Read<FsHeader>();
|
||||||
|
|
||||||
if (header.magic == util::MakeMagic<u32>("PFS0"))
|
if (header.magic == util::MakeMagic<u32>("PFS0"))
|
||||||
hashed = false;
|
hashed = false;
|
||||||
@ -20,12 +20,11 @@ namespace skyline::vfs {
|
|||||||
fileDataOffset = stringTableOffset + header.stringTableSize;
|
fileDataOffset = stringTableOffset + header.stringTableSize;
|
||||||
|
|
||||||
std::vector<char> stringTable(header.stringTableSize + 1);
|
std::vector<char> stringTable(header.stringTableSize + 1);
|
||||||
backing->Read(stringTable.data(), stringTableOffset, header.stringTableSize);
|
backing->Read(span(stringTable).first(header.stringTableSize).cast<u8>(), stringTableOffset);
|
||||||
stringTable[header.stringTableSize] = 0;
|
stringTable[header.stringTableSize] = 0;
|
||||||
|
|
||||||
for (u32 entryOffset{sizeof(FsHeader)}; entryOffset < header.numFiles * entrySize; entryOffset += entrySize) {
|
for (u32 entryOffset{sizeof(FsHeader)}; entryOffset < header.numFiles * entrySize; entryOffset += entrySize) {
|
||||||
PartitionFileEntry entry;
|
auto entry{backing->Read<PartitionFileEntry>(entryOffset)};
|
||||||
backing->Read(&entry, entryOffset);
|
|
||||||
|
|
||||||
std::string name(&stringTable[entry.stringTableOffset]);
|
std::string name(&stringTable[entry.stringTableOffset]);
|
||||||
fileMap.emplace(name, std::move(entry));
|
fileMap.emplace(name, std::move(entry));
|
||||||
|
@ -16,7 +16,7 @@ namespace skyline::vfs {
|
|||||||
u32 numFiles; //!< The number of files in the filesystem
|
u32 numFiles; //!< The number of files in the filesystem
|
||||||
u32 stringTableSize; //!< The size of the filesystem's string table
|
u32 stringTableSize; //!< The size of the filesystem's string table
|
||||||
u32 _pad_;
|
u32 _pad_;
|
||||||
} header{};
|
} header;
|
||||||
static_assert(sizeof(FsHeader) == 0x10);
|
static_assert(sizeof(FsHeader) == 0x10);
|
||||||
|
|
||||||
struct PartitionFileEntry {
|
struct PartitionFileEntry {
|
||||||
|
@ -22,13 +22,12 @@ namespace skyline::vfs {
|
|||||||
*/
|
*/
|
||||||
RegionBacking(const std::shared_ptr<vfs::Backing> &backing, size_t offset, size_t size, Mode mode = {true, false, false}) : Backing(mode, size), backing(backing), baseOffset(offset) {};
|
RegionBacking(const std::shared_ptr<vfs::Backing> &backing, size_t offset, size_t size, Mode mode = {true, false, false}) : Backing(mode, size), backing(backing), baseOffset(offset) {};
|
||||||
|
|
||||||
inline size_t Read(u8 *output, size_t offset, size_t size) {
|
virtual size_t Read(span<u8> output, size_t offset = 0) {
|
||||||
if (!mode.read)
|
if (!mode.read)
|
||||||
throw exception("Attempting to read a backing that is not readable");
|
throw exception("Attempting to read a backing that is not readable");
|
||||||
|
if (size - offset < output.size())
|
||||||
size = std::min(offset + size, this->size) - offset;
|
throw exception("Trying to read past the end of a region backing: 0x{:X}/0x{:X} (Offset: 0x{:X})", output.size(), size, offset);
|
||||||
|
return backing->Read(output, baseOffset + offset);
|
||||||
return backing->Read(output, baseOffset + offset, size);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -6,20 +6,18 @@
|
|||||||
|
|
||||||
namespace skyline::vfs {
|
namespace skyline::vfs {
|
||||||
RomFileSystem::RomFileSystem(std::shared_ptr<Backing> backing) : FileSystem(), backing(backing) {
|
RomFileSystem::RomFileSystem(std::shared_ptr<Backing> backing) : FileSystem(), backing(backing) {
|
||||||
backing->Read(&header);
|
header = backing->Read<RomFsHeader>();
|
||||||
|
|
||||||
TraverseDirectory(0, "");
|
TraverseDirectory(0, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
void RomFileSystem::TraverseFiles(u32 offset, const std::string &path) {
|
void RomFileSystem::TraverseFiles(u32 offset, const std::string &path) {
|
||||||
RomFsFileEntry entry{};
|
RomFsFileEntry entry;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
backing->Read(&entry, header.fileMetaTableOffset + offset);
|
entry = backing->Read<RomFsFileEntry>(header.fileMetaTableOffset + offset);
|
||||||
|
|
||||||
if (entry.nameSize) {
|
if (entry.nameSize) {
|
||||||
std::vector<char> name(entry.nameSize);
|
std::vector<char> name(entry.nameSize);
|
||||||
backing->Read(name.data(), header.fileMetaTableOffset + offset + sizeof(RomFsFileEntry), entry.nameSize);
|
backing->Read(span(name).cast<u8>(), header.fileMetaTableOffset + offset + sizeof(RomFsFileEntry));
|
||||||
|
|
||||||
std::string fullPath{path + (path.empty() ? "" : "/") + std::string(name.data(), entry.nameSize)};
|
std::string fullPath{path + (path.empty() ? "" : "/") + std::string(name.data(), entry.nameSize)};
|
||||||
fileMap.emplace(fullPath, entry);
|
fileMap.emplace(fullPath, entry);
|
||||||
@ -30,13 +28,12 @@ namespace skyline::vfs {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void RomFileSystem::TraverseDirectory(u32 offset, const std::string &path) {
|
void RomFileSystem::TraverseDirectory(u32 offset, const std::string &path) {
|
||||||
RomFsDirectoryEntry entry{};
|
auto entry{backing->Read<RomFsDirectoryEntry>(header.dirMetaTableOffset + offset)};
|
||||||
backing->Read(&entry, header.dirMetaTableOffset + offset);
|
|
||||||
|
|
||||||
std::string childPath{path};
|
std::string childPath{path};
|
||||||
if (entry.nameSize) {
|
if (entry.nameSize) {
|
||||||
std::vector<char> name(entry.nameSize);
|
std::vector<char> name(entry.nameSize);
|
||||||
backing->Read(name.data(), header.dirMetaTableOffset + offset + sizeof(RomFsDirectoryEntry), entry.nameSize);
|
backing->Read(span(name).cast<u8>(), header.dirMetaTableOffset + offset + sizeof(RomFsDirectoryEntry));
|
||||||
childPath = path + (path.empty() ? "" : "/") + std::string(name.data(), entry.nameSize);
|
childPath = path + (path.empty() ? "" : "/") + std::string(name.data(), entry.nameSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -89,11 +86,11 @@ namespace skyline::vfs {
|
|||||||
u32 offset{ownEntry.fileOffset};
|
u32 offset{ownEntry.fileOffset};
|
||||||
|
|
||||||
do {
|
do {
|
||||||
backing->Read(&romFsFileEntry, header.fileMetaTableOffset + offset);
|
romFsFileEntry = backing->Read<RomFileSystem::RomFsFileEntry>(header.fileMetaTableOffset + offset);
|
||||||
|
|
||||||
if (romFsFileEntry.nameSize) {
|
if (romFsFileEntry.nameSize) {
|
||||||
std::vector<char> name(romFsFileEntry.nameSize);
|
std::vector<char> name(romFsFileEntry.nameSize);
|
||||||
backing->Read(name.data(), header.fileMetaTableOffset + offset + sizeof(RomFileSystem::RomFsFileEntry), romFsFileEntry.nameSize);
|
backing->Read(span(name).cast<u8>(), header.fileMetaTableOffset + offset + sizeof(RomFileSystem::RomFsFileEntry));
|
||||||
|
|
||||||
contents.emplace_back(Entry{std::string(name.data(), romFsFileEntry.nameSize), EntryType::File});
|
contents.emplace_back(Entry{std::string(name.data(), romFsFileEntry.nameSize), EntryType::File});
|
||||||
}
|
}
|
||||||
@ -107,11 +104,11 @@ namespace skyline::vfs {
|
|||||||
u32 offset{ownEntry.childOffset};
|
u32 offset{ownEntry.childOffset};
|
||||||
|
|
||||||
do {
|
do {
|
||||||
backing->Read(&romFsDirectoryEntry, header.dirMetaTableOffset + offset);
|
romFsDirectoryEntry = backing->Read<RomFileSystem::RomFsDirectoryEntry>(header.dirMetaTableOffset + offset);
|
||||||
|
|
||||||
if (romFsDirectoryEntry.nameSize) {
|
if (romFsDirectoryEntry.nameSize) {
|
||||||
std::vector<char> name(romFsDirectoryEntry.nameSize);
|
std::vector<char> name(romFsDirectoryEntry.nameSize);
|
||||||
backing->Read(name.data(), header.dirMetaTableOffset + offset + sizeof(RomFileSystem::RomFsDirectoryEntry), romFsDirectoryEntry.nameSize);
|
backing->Read(span(name).cast<u8>(), header.dirMetaTableOffset + offset + sizeof(RomFileSystem::RomFsDirectoryEntry));
|
||||||
|
|
||||||
contents.emplace_back(Entry{std::string(name.data(), romFsDirectoryEntry.nameSize), EntryType::Directory});
|
contents.emplace_back(Entry{std::string(name.data(), romFsDirectoryEntry.nameSize), EntryType::Directory});
|
||||||
}
|
}
|
||||||
|
@ -29,16 +29,6 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
|||||||
System.loadLibrary("skyline") // libskyline.so
|
System.loadLibrary("skyline") // libskyline.so
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* The file descriptor of the ROM
|
|
||||||
*/
|
|
||||||
private lateinit var romFd : ParcelFileDescriptor
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The file descriptor of the application Preference XML
|
|
||||||
*/
|
|
||||||
private lateinit var preferenceFd : ParcelFileDescriptor
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The [InputManager] class handles loading/saving the input data
|
* The [InputManager] class handles loading/saving the input data
|
||||||
*/
|
*/
|
||||||
@ -187,12 +177,13 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
|||||||
*/
|
*/
|
||||||
private fun executeApplication(rom : Uri) {
|
private fun executeApplication(rom : Uri) {
|
||||||
val romType = getRomFormat(rom, contentResolver).ordinal
|
val romType = getRomFormat(rom, contentResolver).ordinal
|
||||||
romFd = contentResolver.openFileDescriptor(rom, "r")!!
|
val romFd = contentResolver.openFileDescriptor(rom, "r")!!
|
||||||
|
val preferenceFd = ParcelFileDescriptor.open(File("${applicationInfo.dataDir}/shared_prefs/${applicationInfo.packageName}_preferences.xml"), ParcelFileDescriptor.MODE_READ_WRITE)
|
||||||
|
|
||||||
emulationThread = Thread {
|
emulationThread = Thread {
|
||||||
surfaceReady.block()
|
surfaceReady.block()
|
||||||
|
|
||||||
executeApplication(rom.toString(), romType, romFd.fd, preferenceFd.fd, applicationContext.filesDir.canonicalPath + "/")
|
executeApplication(rom.toString(), romType, romFd.detachFd(), preferenceFd.detachFd(), applicationContext.filesDir.canonicalPath + "/")
|
||||||
|
|
||||||
if (shouldFinish)
|
if (shouldFinish)
|
||||||
runOnUiThread { finish() }
|
runOnUiThread { finish() }
|
||||||
@ -225,9 +216,6 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
|||||||
|
|
||||||
input = InputManager(this)
|
input = InputManager(this)
|
||||||
|
|
||||||
val preference = File("${applicationInfo.dataDir}/shared_prefs/${applicationInfo.packageName}_preferences.xml")
|
|
||||||
preferenceFd = ParcelFileDescriptor.open(preference, ParcelFileDescriptor.MODE_READ_WRITE)
|
|
||||||
|
|
||||||
game_view.holder.addCallback(this)
|
game_view.holder.addCallback(this)
|
||||||
|
|
||||||
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
@ -262,8 +250,6 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
|||||||
|
|
||||||
shouldFinish = true
|
shouldFinish = true
|
||||||
|
|
||||||
romFd.close()
|
|
||||||
|
|
||||||
executeApplication(intent?.data!!)
|
executeApplication(intent?.data!!)
|
||||||
|
|
||||||
super.onNewIntent(intent)
|
super.onNewIntent(intent)
|
||||||
@ -281,9 +267,6 @@ class EmulationActivity : AppCompatActivity(), SurfaceHolder.Callback, View.OnTo
|
|||||||
vibrators.forEach { (_, vibrator) -> vibrator.cancel() }
|
vibrators.forEach { (_, vibrator) -> vibrator.cancel() }
|
||||||
vibrators.clear()
|
vibrators.clear()
|
||||||
|
|
||||||
romFd.close()
|
|
||||||
preferenceFd.close()
|
|
||||||
|
|
||||||
super.onDestroy()
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user