Merge remote-tracking branch 'origin/master'
* origin/master: (98 commits) rosalina: fix for latest libctru changes pm: fix critical bugs where 1.0(?) titles not in the list have scheduling mode misconfigured loader: revert to use the NS patch due to a Nintendo bug: https://www.3dbrew.org/wiki/NCCH/Extended_Header#Flag1 loader: replace NS N3DS CPU patch with exheader override, fix overriding exheader with homebrew rosalina: ntp: use PTMSYSM_SetRtcTime revert the memory map to the old one (mostly) fix module loading kext: fix outer memory cacheability on newer versions so bascially rosalina's image... rosalina: add hidden debug info menu rosalina: refactor menu handling rosalina: rephrase brightness warning rosalina: add brightness control menu rosalina/pm: remove fs patch, use pm instead rosalina: cleanup variable names rosalina: reorder menus Fix latest commit rosalina menu: add scrolling, cpad and inputredir support (note: no ZL/ZR due to technical reasons) stuff newlib... ... # Conflicts: # k11_extension/source/main.c # k11_extension/source/svc/UnmapProcessMemoryEx.c # sysmodules/rosalina/Makefile # sysmodules/rosalina/include/menu.h # sysmodules/rosalina/include/utils.h # sysmodules/rosalina/source/errdisp.c # sysmodules/rosalina/source/main.c # sysmodules/rosalina/source/menu.c # sysmodules/rosalina/source/menus.c
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2016 Yifan Lu
|
||||
Copyright (c) 2016-2020 AuroraWright, TuxSH
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -28,16 +28,16 @@ INCLUDES := include
|
||||
ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard -mtp=soft
|
||||
DEFINES := -DARM11 -D_3DS
|
||||
|
||||
CFLAGS := -g -std=gnu11 -Wall -Wextra -Werror -O2 -mword-relocations \
|
||||
COMMON_FLAGS = -g -Wall -Wextra -Werror -O2 -mword-relocations \
|
||||
-fomit-frame-pointer -ffunction-sections -fdata-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
$(ARCH) $(DEFINES) $(INCLUDE)
|
||||
|
||||
CFLAGS += $(INCLUDE)
|
||||
CFLAGS := -std=gnu11 $(COMMON_FLAGS)
|
||||
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
CXXFLAGS := -fno-rtti -fno-exceptions -std=gnu++17 $(COMMON_FLAGS)
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),--section-start,.text=0x14000000
|
||||
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),-wrap,exit,--section-start,.text=0x14000000
|
||||
|
||||
LIBS := -lctru
|
||||
|
||||
|
||||
283
sysmodules/loader/source/bps_patcher.cpp
Normal file
283
sysmodules/loader/source/bps_patcher.cpp
Normal file
@@ -0,0 +1,283 @@
|
||||
#include "bps_patcher.h"
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <type_traits>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <3ds/os.h>
|
||||
#include <3ds/result.h>
|
||||
#include <3ds/services/fs.h>
|
||||
#include <3ds/svc.h>
|
||||
|
||||
#include "patcher.h"
|
||||
#include "strings.h"
|
||||
}
|
||||
|
||||
#include "file_util.h"
|
||||
|
||||
namespace patcher
|
||||
{
|
||||
namespace Bps
|
||||
{
|
||||
// The BPS format uses variable length encoding for all integers.
|
||||
// Realistically uint32s are more than enough for code patching.
|
||||
using Number = u32;
|
||||
|
||||
constexpr std::size_t FooterSize = 12;
|
||||
|
||||
// The BPS format uses CRC32 checksums.
|
||||
[[gnu::optimize("Os")]] static u32 crc32(const u8 *data, std::size_t size)
|
||||
{
|
||||
u32 crc = 0xFFFFFFFF;
|
||||
for(std::size_t i = 0; i < size; ++i)
|
||||
{
|
||||
crc ^= data[i];
|
||||
for(std::size_t j = 0; j < 8; ++j)
|
||||
{
|
||||
u32 mask = -(crc & 1);
|
||||
crc = (crc >> 1) ^ (0xEDB88320 & mask);
|
||||
}
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
// Utility class to make keeping track of offsets and bound checks less error prone.
|
||||
template <typename T>
|
||||
class Stream
|
||||
{
|
||||
public:
|
||||
Stream(T *ptr, std::size_t size) : m_ptr{ptr}, m_size{size} {}
|
||||
|
||||
bool Read(void *buffer, std::size_t length)
|
||||
{
|
||||
if(m_offset + length > m_size)
|
||||
return false;
|
||||
std::memcpy(buffer, m_ptr + m_offset, length);
|
||||
m_offset += length;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename OtherType>
|
||||
[[gnu::optimize("Os")]] bool CopyFrom(Stream<OtherType> &other, std::size_t length)
|
||||
{
|
||||
if(m_offset + length > m_size)
|
||||
return false;
|
||||
if(!other.Read(m_ptr + m_offset, length))
|
||||
return false;
|
||||
m_offset += length;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename ValueType>
|
||||
std::optional<ValueType> Read()
|
||||
{
|
||||
static_assert(std::is_pod_v<ValueType>);
|
||||
ValueType val{};
|
||||
if(!Read(&val, sizeof(val)))
|
||||
return std::nullopt;
|
||||
return val;
|
||||
}
|
||||
|
||||
[[gnu::optimize("Os")]] Number ReadNumber()
|
||||
{
|
||||
Number data = 0, shift = 1;
|
||||
std::optional<u8> x;
|
||||
while((x = Read<u8>()))
|
||||
{
|
||||
data += (*x & 0x7f) * shift;
|
||||
if(*x & 0x80)
|
||||
break;
|
||||
shift <<= 7;
|
||||
data += shift;
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
auto data() const { return m_ptr; }
|
||||
std::size_t size() const { return m_size; }
|
||||
std::size_t Tell() const { return m_offset; }
|
||||
|
||||
bool Seek(size_t offset)
|
||||
{
|
||||
m_offset = offset;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
T *m_ptr = nullptr;
|
||||
std::size_t m_size = 0;
|
||||
std::size_t m_offset = 0;
|
||||
};
|
||||
|
||||
class PatchApplier
|
||||
{
|
||||
public:
|
||||
PatchApplier(Stream<const u8> source, Stream<u8> target, Stream<const u8> patch)
|
||||
: m_source{source}, m_target{target}, m_patch{patch}
|
||||
{
|
||||
}
|
||||
|
||||
[[gnu::always_inline]] bool Apply()
|
||||
{
|
||||
const auto magic = *m_patch.Read<std::array<char, 4>>();
|
||||
if(std::string_view(magic.data(), magic.size()) != "BPS1")
|
||||
return false;
|
||||
|
||||
const Bps::Number source_size = m_patch.ReadNumber();
|
||||
const Bps::Number target_size = m_patch.ReadNumber();
|
||||
const Bps::Number metadata_size = m_patch.ReadNumber();
|
||||
if(source_size > m_source.size() || target_size > m_target.size() || metadata_size != 0)
|
||||
return false;
|
||||
|
||||
const std::size_t command_start_offset = m_patch.Tell();
|
||||
const std::size_t command_end_offset = m_patch.size() - FooterSize;
|
||||
m_patch.Seek(command_end_offset);
|
||||
const u32 source_crc32 = *m_patch.Read<u32>();
|
||||
const u32 target_crc32 = *m_patch.Read<u32>();
|
||||
m_patch.Seek(command_start_offset);
|
||||
|
||||
if(crc32(m_source.data(), source_size) != source_crc32)
|
||||
return false;
|
||||
|
||||
// Process all patch commands.
|
||||
std::memset(m_target.data(), 0, m_target.size());
|
||||
while(m_patch.Tell() < command_end_offset)
|
||||
{
|
||||
const bool ok = HandleCommand();
|
||||
if(!ok)
|
||||
return false;
|
||||
}
|
||||
|
||||
return crc32(m_target.data(), target_size) == target_crc32;
|
||||
}
|
||||
|
||||
private:
|
||||
bool HandleCommand()
|
||||
{
|
||||
const Number data = m_patch.ReadNumber();
|
||||
const Number command = data & 3;
|
||||
const Number length = (data >> 2) + 1;
|
||||
|
||||
switch(command)
|
||||
{
|
||||
case 0:
|
||||
return SourceRead(length);
|
||||
case 1:
|
||||
return TargetRead(length);
|
||||
case 2:
|
||||
return SourceCopy(length);
|
||||
case 3:
|
||||
return TargetCopy(length);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool SourceRead(Number length)
|
||||
{
|
||||
return m_source.Seek(m_target.Tell()) && m_target.CopyFrom(m_source, length);
|
||||
}
|
||||
|
||||
bool TargetRead(Number length) { return m_target.CopyFrom(m_patch, length); }
|
||||
|
||||
bool SourceCopy(Number length)
|
||||
{
|
||||
const Number data = m_patch.ReadNumber();
|
||||
m_source_relative_offset += (data & 1 ? -1 : +1) * int(data >> 1);
|
||||
if(!m_source.Seek(m_source_relative_offset) || !m_target.CopyFrom(m_source, length))
|
||||
return false;
|
||||
m_source_relative_offset += length;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TargetCopy(Number length)
|
||||
{
|
||||
const Number data = m_patch.ReadNumber();
|
||||
m_target_relative_offset += (data & 1 ? -1 : +1) * int(data >> 1);
|
||||
if(m_target.Tell() + length > m_target.size())
|
||||
return false;
|
||||
if(m_target_relative_offset + length > m_target.size())
|
||||
return false;
|
||||
// Byte by byte copy.
|
||||
for(size_t i = 0; i < length; ++i)
|
||||
m_target.data()[m_target.Tell() + i] = m_target.data()[m_target_relative_offset++];
|
||||
m_target.Seek(m_target.Tell() + length);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::size_t m_source_relative_offset = 0;
|
||||
std::size_t m_target_relative_offset = 0;
|
||||
Stream<const u8> m_source;
|
||||
Stream<u8> m_target;
|
||||
Stream<const u8> m_patch;
|
||||
};
|
||||
|
||||
} // namespace Bps
|
||||
|
||||
class ScopedAppHeap
|
||||
{
|
||||
public:
|
||||
ScopedAppHeap()
|
||||
{
|
||||
u32 tmp;
|
||||
m_size = osGetMemRegionFree(MEMREGION_APPLICATION);
|
||||
if(!R_SUCCEEDED(svcControlMemory(&tmp, BaseAddress, 0, m_size,
|
||||
MemOp(MEMOP_ALLOC | MEMOP_REGION_APP),
|
||||
MemPerm(MEMPERM_READ | MEMPERM_WRITE))))
|
||||
{
|
||||
svcBreak(USERBREAK_PANIC);
|
||||
}
|
||||
}
|
||||
|
||||
~ScopedAppHeap()
|
||||
{
|
||||
u32 tmp;
|
||||
svcControlMemory(&tmp, BaseAddress, 0, m_size, MEMOP_FREE, MemPerm(0));
|
||||
}
|
||||
|
||||
static constexpr u32 BaseAddress = 0x08000000;
|
||||
|
||||
private:
|
||||
u32 m_size;
|
||||
};
|
||||
|
||||
static inline bool ApplyCodeBpsPatch(u64 prog_id, u8 *code, u32 size)
|
||||
{
|
||||
char bps_path[] = "/luma/titles/0000000000000000/code.bps";
|
||||
progIdToStr(bps_path + 28, prog_id);
|
||||
util::File patch_file;
|
||||
if(!patch_file.Open(bps_path, FS_OPEN_READ))
|
||||
return true;
|
||||
const u32 patch_size = u32(patch_file.GetSize().value_or(0));
|
||||
|
||||
// Temporarily use APPLICATION memory to store the source and patch data.
|
||||
ScopedAppHeap memory;
|
||||
|
||||
u8 *source_data = reinterpret_cast<u8 *>(memory.BaseAddress);
|
||||
u8 *patch_data = source_data + size;
|
||||
std::memcpy(source_data, code, size);
|
||||
if(!patch_file.Read(patch_data, patch_size, 0))
|
||||
return false;
|
||||
|
||||
Bps::Stream<const u8> source_stream{source_data, size};
|
||||
Bps::Stream target_stream{code, size};
|
||||
Bps::Stream<const u8> patch_stream{patch_data, patch_size};
|
||||
Bps::PatchApplier applier{source_stream, target_stream, patch_stream};
|
||||
if(!applier.Apply())
|
||||
svcBreak(USERBREAK_PANIC);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace patcher
|
||||
|
||||
extern "C"
|
||||
{
|
||||
bool patcherApplyCodeBpsPatch(u64 progId, u8 *code, u32 size)
|
||||
{
|
||||
return patcher::ApplyCodeBpsPatch(progId, code, size);
|
||||
}
|
||||
}
|
||||
12
sysmodules/loader/source/bps_patcher.h
Normal file
12
sysmodules/loader/source/bps_patcher.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
#include <3ds/types.h>
|
||||
|
||||
bool patcherApplyCodeBpsPatch(u64 progId, u8* code, u32 size);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
76
sysmodules/loader/source/file_util.h
Normal file
76
sysmodules/loader/source/file_util.h
Normal file
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
#include <string.h>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <3ds/result.h>
|
||||
#include <3ds/services/fs.h>
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/types.h>
|
||||
}
|
||||
|
||||
namespace util
|
||||
{
|
||||
inline FS_Path MakePath(const char *path)
|
||||
{
|
||||
return {PATH_ASCII, strnlen(path, 255) + 1, path};
|
||||
}
|
||||
|
||||
// A small wrapper to make forgetting to close a file and
|
||||
// to check read lengths impossible.
|
||||
class File
|
||||
{
|
||||
public:
|
||||
File() = default;
|
||||
File(const File &other) = delete;
|
||||
File &operator=(const File &) = delete;
|
||||
File(File &&other) { *this = std::move(other); }
|
||||
File &operator=(File &&other)
|
||||
{
|
||||
std::swap(m_handle, other.m_handle);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~File() { Close(); }
|
||||
|
||||
bool Close()
|
||||
{
|
||||
const bool ok = !m_handle || R_SUCCEEDED(FSFILE_Close(*m_handle));
|
||||
if(ok)
|
||||
m_handle = std::nullopt;
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool Open(const char *path, int open_flags)
|
||||
{
|
||||
const FS_Path archive_path = {PATH_EMPTY, 1, ""};
|
||||
Handle handle;
|
||||
const bool ok = R_SUCCEEDED(FSUSER_OpenFileDirectly(&handle, ARCHIVE_SDMC, archive_path,
|
||||
MakePath(path), open_flags, 0));
|
||||
if(ok)
|
||||
m_handle = handle;
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool Read(void *buffer, u32 size, u64 offset)
|
||||
{
|
||||
u32 bytes_read = 0;
|
||||
const Result res = FSFILE_Read(*m_handle, &bytes_read, offset, buffer, size);
|
||||
return R_SUCCEEDED(res) && bytes_read == size;
|
||||
}
|
||||
|
||||
std::optional<u64> GetSize() const
|
||||
{
|
||||
u64 size;
|
||||
if(!R_SUCCEEDED(FSFILE_GetSize(*m_handle, &size)))
|
||||
return std::nullopt;
|
||||
return size;
|
||||
}
|
||||
|
||||
private:
|
||||
std::optional<Handle> m_handle;
|
||||
};
|
||||
|
||||
} // namespace util
|
||||
@@ -6,7 +6,7 @@
|
||||
#include "hbldr.h"
|
||||
|
||||
extern u32 config, multiConfig, bootConfig;
|
||||
extern bool isN3DS, needToInitSd, isSdMode;
|
||||
extern bool isN3DS, isSdMode;
|
||||
|
||||
static u8 g_ret_buf[sizeof(ExHeader_Info)];
|
||||
static u64 g_cached_programHandle;
|
||||
@@ -187,9 +187,6 @@ static Result GetProgramInfo(ExHeader_Info *exheaderInfo, u64 programHandle)
|
||||
s64 nbSection0Modules;
|
||||
svcGetSystemInfo(&nbSection0Modules, 26, 0);
|
||||
|
||||
// Force always having sdmc:/ and nand:/rw permission
|
||||
exheaderInfo->aci.local_caps.storage_info.fs_access_info |= FSACCESS_NANDRW | FSACCESS_SDMC_RW;
|
||||
|
||||
// Tweak 3dsx placeholder title exheaderInfo
|
||||
if (nbSection0Modules == 6 && exheaderInfo->aci.local_caps.title_id == HBLDR_3DSX_TID)
|
||||
{
|
||||
@@ -197,10 +194,12 @@ static Result GetProgramInfo(ExHeader_Info *exheaderInfo, u64 programHandle)
|
||||
HBLDR_PatchExHeaderInfo(exheaderInfo);
|
||||
hbldrExit();
|
||||
}
|
||||
|
||||
u64 originaltitleId = exheaderInfo->aci.local_caps.title_id;
|
||||
if(CONFIG(PATCHGAMES) && loadTitleExheaderInfo(exheaderInfo->aci.local_caps.title_id, exheaderInfo))
|
||||
exheaderInfo->aci.local_caps.title_id = originaltitleId;
|
||||
else
|
||||
{
|
||||
u64 originaltitleId = exheaderInfo->aci.local_caps.title_id;
|
||||
if(CONFIG(PATCHGAMES) && loadTitleExheaderInfo(exheaderInfo->aci.local_caps.title_id, exheaderInfo))
|
||||
exheaderInfo->aci.local_caps.title_id = originaltitleId;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "service_manager.h"
|
||||
|
||||
u32 config, multiConfig, bootConfig;
|
||||
bool isN3DS, needToInitSd, isSdMode;
|
||||
bool isN3DS, isSdMode;
|
||||
|
||||
// MAKE SURE fsreg has been init before calling this
|
||||
static Result fsldrPatchPermissions(void)
|
||||
@@ -29,27 +29,38 @@ static inline void loadCFWInfo(void)
|
||||
{
|
||||
s64 out;
|
||||
|
||||
assertSuccess(svcGetSystemInfo(&out, 0x10000, 3));
|
||||
if(svcGetSystemInfo(&out, 0x20000, 0) != 1) panic(0xDEADCAFE);
|
||||
|
||||
svcGetSystemInfo(&out, 0x10000, 3);
|
||||
config = (u32)out;
|
||||
assertSuccess(svcGetSystemInfo(&out, 0x10000, 4));
|
||||
svcGetSystemInfo(&out, 0x10000, 4);
|
||||
multiConfig = (u32)out;
|
||||
assertSuccess(svcGetSystemInfo(&out, 0x10000, 5));
|
||||
svcGetSystemInfo(&out, 0x10000, 5);
|
||||
bootConfig = (u32)out;
|
||||
|
||||
assertSuccess(svcGetSystemInfo(&out, 0x10000, 0x201));
|
||||
svcGetSystemInfo(&out, 0x10000, 0x201);
|
||||
isN3DS = (bool)out;
|
||||
assertSuccess(svcGetSystemInfo(&out, 0x10000, 0x202));
|
||||
needToInitSd = (bool)out;
|
||||
assertSuccess(svcGetSystemInfo(&out, 0x10000, 0x203));
|
||||
svcGetSystemInfo(&out, 0x10000, 0x203);
|
||||
isSdMode = (bool)out;
|
||||
|
||||
IFile file;
|
||||
if(needToInitSd) fileOpen(&file, ARCHIVE_SDMC, "/", FS_OPEN_READ); //Init SD card if SAFE_MODE is being booted
|
||||
}
|
||||
|
||||
// this is called before main
|
||||
void __appInit()
|
||||
void __ctru_exit(int rc) { (void)rc; } // needed to avoid linking error
|
||||
|
||||
// this is called after main exits
|
||||
void __wrap_exit(int rc)
|
||||
{
|
||||
(void)rc;
|
||||
// Not supposed to terminate... kernel will clean up the handles if it does happen anyway
|
||||
svcExitProcess();
|
||||
}
|
||||
|
||||
void __sync_init();
|
||||
void __libc_init_array(void);
|
||||
|
||||
// called before main
|
||||
void initSystem(void)
|
||||
{
|
||||
__sync_init();
|
||||
loadCFWInfo();
|
||||
|
||||
Result res;
|
||||
@@ -71,42 +82,8 @@ void __appInit()
|
||||
assertSuccess(FSUSER_SetPriority(0));
|
||||
|
||||
assertSuccess(pxiPmInit());
|
||||
}
|
||||
|
||||
// this is called after main exits
|
||||
void __appExit()
|
||||
{
|
||||
pxiPmExit();
|
||||
//fsldrExit();
|
||||
svcCloseHandle(*fsGetSessionHandle());
|
||||
fsRegExit();
|
||||
srvExit();
|
||||
}
|
||||
|
||||
// stubs for non-needed pre-main functions
|
||||
void __sync_init();
|
||||
void __sync_fini();
|
||||
void __system_initSyscalls();
|
||||
|
||||
void __ctru_exit()
|
||||
{
|
||||
void __libc_fini_array(void);
|
||||
|
||||
__libc_fini_array();
|
||||
__appExit();
|
||||
__sync_fini();
|
||||
svcExitProcess();
|
||||
}
|
||||
|
||||
void initSystem()
|
||||
{
|
||||
void __libc_init_array(void);
|
||||
|
||||
__sync_init();
|
||||
__system_initSyscalls();
|
||||
__appInit();
|
||||
|
||||
__libc_init_array();
|
||||
//__libc_init_array();
|
||||
}
|
||||
|
||||
static const ServiceManagerServiceEntry services[] = {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include <3ds.h>
|
||||
#include "patcher.h"
|
||||
#include "bps_patcher.h"
|
||||
#include "memory.h"
|
||||
#include "strings.h"
|
||||
#include "romfsredir.h"
|
||||
@@ -369,7 +370,7 @@ bool loadTitleExheaderInfo(u64 progId, ExHeader_Info *exheaderInfo)
|
||||
|
||||
u64 fileSize;
|
||||
|
||||
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || fileSize != sizeof(ExHeader_Info) || fileSize != sizeof(ExHeader)) goto error;
|
||||
if(R_FAILED(IFile_GetSize(&file, &fileSize)) || (fileSize != sizeof(ExHeader_Info) && fileSize != sizeof(ExHeader))) goto error;
|
||||
else
|
||||
{
|
||||
u64 total;
|
||||
@@ -469,12 +470,12 @@ static inline bool loadTitleLocaleConfig(u64 progId, u8 *mask, u8 *regionId, u8
|
||||
((buf[11] >= '0' && buf[11] <= '9') || (buf[11] >= 'a' && buf[11] <= 'f') || (buf[11] >= 'A' && buf[11] <= 'F')))
|
||||
{
|
||||
if (buf[10] >= '0' && buf[10] <= '9') *stateId = 16 * (buf[10] - '0');
|
||||
else if(buf[10] >= 'a' && buf[10] <= 'f') *stateId = 16 * (buf[10] - 'a');
|
||||
else if(buf[10] >= 'A' && buf[10] <= 'F') *stateId = 16 * (buf[10] - 'A');
|
||||
else if(buf[10] >= 'a' && buf[10] <= 'f') *stateId = 16 * (buf[10] - 'a' + 10);
|
||||
else if(buf[10] >= 'A' && buf[10] <= 'F') *stateId = 16 * (buf[10] - 'A' + 10);
|
||||
|
||||
if (buf[11] >= '0' && buf[11] <= '9') *stateId += buf[11] - '0';
|
||||
else if(buf[11] >= 'a' && buf[11] <= 'f') *stateId += buf[11] - 'a';
|
||||
else if(buf[11] >= 'A' && buf[11] <= 'F') *stateId += buf[11] - 'A';
|
||||
else if(buf[11] >= 'a' && buf[11] <= 'f') *stateId += buf[11] - 'a' + 10;
|
||||
else if(buf[11] >= 'A' && buf[11] <= 'F') *stateId += buf[11] - 'A' + 10;
|
||||
|
||||
*mask |= 8;
|
||||
}
|
||||
@@ -503,7 +504,7 @@ static inline bool patchLayeredFs(u64 progId, u8 *code, u32 size, u32 textSize,
|
||||
fsOpenFileDirectly = 0xFFFFFFFF,
|
||||
payloadOffset = 0,
|
||||
pathOffset = 0,
|
||||
pathAddress;
|
||||
pathAddress = 0xDEADCAFE;
|
||||
|
||||
if(!findLayeredFsSymbols(code, textSize, &fsMountArchive, &fsRegisterArchive, &fsTryOpenFile, &fsOpenFileDirectly) ||
|
||||
!findLayeredFsPayloadOffset(code, textSize, roSize, dataSize, roAddress, dataAddress, &payloadOffset, &pathOffset, &pathAddress)) return false;
|
||||
@@ -739,7 +740,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
|
||||
}
|
||||
}
|
||||
|
||||
else if(progId == 0x0004013000001702LL) //CFG
|
||||
else if((progId & ~0xF0000001ULL) == 0x0004013000001702LL) //CFG, SAFE_FIRM CFG
|
||||
{
|
||||
static const u8 pattern[] = {
|
||||
0x06, 0x46, 0x10, 0x48
|
||||
@@ -825,7 +826,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
|
||||
)) goto error;
|
||||
}
|
||||
|
||||
else if(progId == 0x0004013000001A02LL) //DSP
|
||||
else if((progId & ~0xF0000001ULL) == 0x0004013000001A02LL) //DSP, SAFE_FIRM DSP
|
||||
{
|
||||
static const u8 pattern[] = {
|
||||
0xE3, 0x10, 0x10, 0x80, 0xE2
|
||||
@@ -845,6 +846,7 @@ void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 ro
|
||||
|
||||
if(CONFIG(PATCHGAMES))
|
||||
{
|
||||
if(!patcherApplyCodeBpsPatch(progId, code, size)) goto error;
|
||||
if(!applyCodeIpsPatch(progId, code, size)) goto error;
|
||||
|
||||
if((u32)((progId >> 0x20) & 0xFFFFFFEDULL) == 0x00040000)
|
||||
|
||||
@@ -35,11 +35,12 @@ enum singleOptions
|
||||
PATCHVERSTRING,
|
||||
SHOWGBABOOT,
|
||||
PATCHUNITINFO,
|
||||
DISABLEARM11EXCHANDLERS
|
||||
DISABLEARM11EXCHANDLERS,
|
||||
ENABLESAFEFIRMROSALINA,
|
||||
};
|
||||
|
||||
extern u32 config, multiConfig, bootConfig;
|
||||
extern bool isN3DS, needToInitSd, isSdMode;
|
||||
extern bool isN3DS, isSdMode;
|
||||
|
||||
void patchCode(u64 progId, u16 progVer, u8 *code, u32 size, u32 textSize, u32 roSize, u32 dataSize, u32 roAddress, u32 dataAddress);
|
||||
Result fileOpen(IFile *file, FS_ArchiveID archiveId, const char *path, int flags);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
|
||||
@@ -1,3 +1,29 @@
|
||||
/*
|
||||
* This file is part of Luma3DS
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms 7.b and 7.c of GPLv3 apply to this file:
|
||||
* * Requiring preservation of specified reasonable legal notices or
|
||||
* author attributions in that material or in the Appropriate Legal
|
||||
* Notices displayed by works containing it.
|
||||
* * Prohibiting misrepresentation of the origin of that material,
|
||||
* or requiring that modified versions of such material be marked in
|
||||
* reasonable ways as different from the original version.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <3ds/types.h>
|
||||
|
||||
Reference in New Issue
Block a user