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>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2019 TuxSH
|
||||
Copyright (c) 2019-2020 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,7 +28,7 @@ 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 \
|
||||
CFLAGS := -g -std=gnu11 -Wall -Wextra -Werror -Os -mword-relocations \
|
||||
-fomit-frame-pointer -ffunction-sections -fdata-sections \
|
||||
$(ARCH) $(DEFINES)
|
||||
|
||||
@@ -37,7 +37,7 @@ CFLAGS += $(INCLUDE)
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),-wrap,exit
|
||||
|
||||
LIBS := -lctru
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# 3ds_pm
|
||||
Open source replacement of the ARM11 PM system module.
|
||||
Open source replacement of the Arm11 PM system module.
|
||||
This is licensed under the MIT license.
|
||||
|
||||
# Usage
|
||||
|
||||
@@ -117,7 +117,11 @@ AccessControlInfo:
|
||||
ServiceAccessControl:
|
||||
# Note: pm also uses srv:pm and Loader but doesn't list them here.
|
||||
- fs:REG
|
||||
# Custom:
|
||||
- fs:USER
|
||||
FileSystemAccess:
|
||||
# Custom
|
||||
- DirectSdmc
|
||||
|
||||
SystemControlInfo:
|
||||
SaveDataSize: 0KB # It doesn't use any save data.
|
||||
|
||||
@@ -129,16 +129,21 @@ Result GetTitleExHeaderFlags(ExHeader_Arm11CoreInfo *outCoreInfo, ExHeader_Syste
|
||||
return res;
|
||||
}
|
||||
|
||||
Result GetCurrentAppTitleIdAndPid(u64 *outTitleId, u32 *outPid)
|
||||
Result GetCurrentAppInfo(FS_ProgramInfo *outProgramInfo, u32 *outPid, u32 *outLaunchFlags)
|
||||
{
|
||||
ProcessList_Lock(&g_manager.processList);
|
||||
Result res;
|
||||
|
||||
memset(outProgramInfo, 0, sizeof(FS_ProgramInfo));
|
||||
if (g_manager.runningApplicationData != NULL) {
|
||||
*outTitleId = g_manager.runningApplicationData->titleId;
|
||||
*outPid = g_manager.runningApplicationData->pid;
|
||||
ProcessData *app = g_manager.runningApplicationData;
|
||||
outProgramInfo->programId = app->titleId;
|
||||
outProgramInfo->mediaType = app->mediaType;
|
||||
*outPid = app->pid;
|
||||
*outLaunchFlags = app->launchFlags;
|
||||
res = 0;
|
||||
} else {
|
||||
*outTitleId = 0;
|
||||
*outPid = 0;
|
||||
res = MAKERESULT(RL_TEMPORARY, RS_NOTFOUND, RM_PM, 0x100);
|
||||
}
|
||||
ProcessList_Unlock(&g_manager.processList);
|
||||
|
||||
@@ -12,4 +12,4 @@ Result listMergeUniqueDependencies(ProcessData **procs, u64 *dependencies, u32 *
|
||||
Result GetTitleExHeaderFlags(ExHeader_Arm11CoreInfo *outCoreInfo, ExHeader_SystemInfoFlags *outSiFlags, const FS_ProgramInfo *programInfo);
|
||||
|
||||
// Custom
|
||||
Result GetCurrentAppTitleIdAndPid(u64 *outTitleId, u32 *outPid);
|
||||
Result GetCurrentAppInfo(FS_ProgramInfo *outProgramInfo, u32 *outPid, u32 *outLaunchFlags);
|
||||
|
||||
@@ -56,10 +56,12 @@ static Result loadWithoutDependencies(Handle *outDebug, ProcessData **outProcess
|
||||
process->pid = pid;
|
||||
process->titleId = exheaderInfo->aci.local_caps.title_id;;
|
||||
process->programHandle = programHandle;
|
||||
process->launchFlags = launchFlags; // not in official PM
|
||||
process->flags = 0; // will be filled later
|
||||
process->terminatedNotificationVariation = (launchFlags & 0xF0) >> 4;
|
||||
process->terminationStatus = TERMSTATUS_RUNNING;
|
||||
process->refcount = 1;
|
||||
process->mediaType = programInfo->mediaType; // not in official PM
|
||||
|
||||
ProcessList_Unlock(&g_manager.processList);
|
||||
svcSignalEvent(g_manager.newProcessEvent);
|
||||
@@ -71,7 +73,11 @@ static Result loadWithoutDependencies(Handle *outDebug, ProcessData **outProcess
|
||||
u32 serviceCount;
|
||||
for(serviceCount = 0; serviceCount < 34 && *(u64 *)localcaps->service_access[serviceCount] != 0; serviceCount++);
|
||||
|
||||
TRY(FSREG_Register(pid, programHandle, programInfo, &localcaps->storage_info));
|
||||
// Not in official PM: patch local caps to give access to everything
|
||||
ExHeader_Arm11StorageInfo storageInfo = localcaps->storage_info;
|
||||
storageInfo.fs_access_info = 0xFFFFFFFF;
|
||||
|
||||
TRY(FSREG_Register(pid, programHandle, programInfo, &storageInfo));
|
||||
TRY(SRVPM_RegisterProcess(pid, serviceCount, localcaps->service_access));
|
||||
|
||||
if (localcaps->reslimit_category <= RESLIMIT_CATEGORY_OTHER) {
|
||||
@@ -135,6 +141,11 @@ static Result loadWithDependencies(Handle *outDebug, ProcessData **outProcessDat
|
||||
process->flags |= PROCESSFLAG_DEPENDENCIES_LOADED;
|
||||
}
|
||||
|
||||
if (launchFlags & PMLAUNCHFLAGEXT_FAKE_DEPENDENCY_LOADING) {
|
||||
// See no evil
|
||||
numUnique = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Official pm does this:
|
||||
for each dependency:
|
||||
@@ -208,7 +219,7 @@ static Result launchTitleImpl(Handle *debug, ProcessData **outProcessData, const
|
||||
TRY(registerProgram(&programHandle, programInfo, programInfoUpdate));
|
||||
|
||||
res = LOADER_GetProgramInfo(exheaderInfo, programHandle);
|
||||
res = R_SUCCEEDED(res) && exheaderInfo->aci.local_caps.core_info.core_version != SYSCOREVER ? (Result)0xC8A05800 : res;
|
||||
res = R_SUCCEEDED(res) && SYSCOREVER == 2 && exheaderInfo->aci.local_caps.core_info.core_version != SYSCOREVER ? (Result)0xC8A05800 : res;
|
||||
|
||||
if (R_FAILED(res)) {
|
||||
LOADER_UnregisterProgram(programHandle);
|
||||
@@ -219,18 +230,18 @@ static Result launchTitleImpl(Handle *debug, ProcessData **outProcessData, const
|
||||
if (IS_N3DS && APPMEMTYPE == 6 && (launchFlags & PMLAUNCHFLAG_NORMAL_APPLICATION) != 0) {
|
||||
u32 limitMb;
|
||||
SystemMode n3dsSystemMode = exheaderInfo->aci.local_caps.core_info.n3ds_system_mode;
|
||||
if ((launchFlags & PMLAUNCHFLAG_FORCE_USE_O3DS_APP_MEM) || n3dsSystemMode == SYSMODE_O3DS_PROD) {
|
||||
if ((launchFlags & PMLAUNCHFLAG_FORCE_USE_O3DS_APP_MEM) & PMLAUNCHFLAG_FORCE_USE_O3DS_MAX_APP_MEM) {
|
||||
limitMb = 96;
|
||||
} else {
|
||||
switch (exheaderInfo->aci.local_caps.core_info.o3ds_system_mode) {
|
||||
case SYSMODE_O3DS_PROD: limitMb = 64; break;
|
||||
case SYSMODE_DEV1: limitMb = 96; break;
|
||||
case SYSMODE_DEV2: limitMb = 80; break;
|
||||
default: limitMb = 0; break;
|
||||
}
|
||||
bool forceO3dsAppMem = (launchFlags & PMLAUNCHFLAG_FORCE_USE_O3DS_APP_MEM) != 0;
|
||||
if (forceO3dsAppMem && (launchFlags & PMLAUNCHFLAG_FORCE_USE_O3DS_MAX_APP_MEM) != 0) {
|
||||
setAppMemLimit(96 << 20);
|
||||
} else if (forceO3dsAppMem || n3dsSystemMode == SYSMODE_O3DS_PROD) {
|
||||
switch (exheaderInfo->aci.local_caps.core_info.o3ds_system_mode) {
|
||||
case SYSMODE_O3DS_PROD: limitMb = 64; break;
|
||||
case SYSMODE_DEV1: limitMb = 96; break;
|
||||
case SYSMODE_DEV2: limitMb = 80; break;
|
||||
default: limitMb = 0; break;
|
||||
}
|
||||
|
||||
// Can be 0:
|
||||
setAppMemLimit(limitMb << 20);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
#include <3ds/services/fs.h>
|
||||
#include "process_data.h"
|
||||
|
||||
/// Custom launch flags for PM launch commands.
|
||||
enum {
|
||||
PMLAUNCHFLAGEXT_FAKE_DEPENDENCY_LOADING = BIT(24),
|
||||
};
|
||||
|
||||
Result LaunchTitle(u32 *outPid, const FS_ProgramInfo *programInfo, u32 launchFlags);
|
||||
Result LaunchTitleUpdate(const FS_ProgramInfo *programInfo, const FS_ProgramInfo *programInfoUpdate, u32 launchFlags);
|
||||
Result LaunchApp(const FS_ProgramInfo *programInfo, u32 launchFlags);
|
||||
|
||||
@@ -3,11 +3,24 @@
|
||||
#include "luma.h"
|
||||
#include "util.h"
|
||||
|
||||
bool hasKExt(void)
|
||||
{
|
||||
s64 val;
|
||||
return svcGetSystemInfo(&val, 0x20000, 0) == 1;
|
||||
}
|
||||
|
||||
u32 getKExtSize(void)
|
||||
{
|
||||
s64 val;
|
||||
Result res = svcGetSystemInfo(&val, 0x10000, 0x300);
|
||||
return R_FAILED(res) ? 0 : (u32)val;
|
||||
svcGetSystemInfo(&val, 0x10000, 0x300);
|
||||
return (u32)val;
|
||||
}
|
||||
|
||||
u32 getStolenSystemMemRegionSize(void)
|
||||
{
|
||||
s64 val;
|
||||
svcGetSystemInfo(&val, 0x10000, 0x301);
|
||||
return (u32)val;
|
||||
}
|
||||
|
||||
bool isTitleLaunchPrevented(u64 titleId)
|
||||
@@ -15,5 +28,5 @@ bool isTitleLaunchPrevented(u64 titleId)
|
||||
s64 numKips = 0;
|
||||
|
||||
svcGetSystemInfo(&numKips, 26, 0);
|
||||
return numKips >= 6 && (titleId & ~N3DS_TID_BIT) == 0x0004003000008A02ULL; // ErrDisp
|
||||
}
|
||||
return numKips >= 6 && (titleId & ~(N3DS_TID_MASK | 1)) == 0x0004003000008A02ULL; // ErrDisp
|
||||
}
|
||||
|
||||
@@ -2,5 +2,7 @@
|
||||
|
||||
#include <3ds/types.h>
|
||||
|
||||
bool hasKExt(void);
|
||||
u32 getKExtSize(void);
|
||||
bool isTitleLaunchPrevented(u64 titleId);
|
||||
u32 getStolenSystemMemRegionSize(void);
|
||||
bool isTitleLaunchPrevented(u64 titleId);
|
||||
|
||||
@@ -14,10 +14,27 @@
|
||||
#include "service_manager.h"
|
||||
|
||||
static MyThread processMonitorThread, taskRunnerThread;
|
||||
static u8 ALIGN(8) processDataBuffer[0x40 * sizeof(ProcessData)] = {0};
|
||||
static u8 ALIGN(8) exheaderInfoBuffer[6 * sizeof(ExHeader_Info)] = {0};
|
||||
static u8 ALIGN(8) threadStacks[2][THREAD_STACK_SIZE] = {0};
|
||||
|
||||
// this is called before main
|
||||
void __appInit()
|
||||
// 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();
|
||||
}
|
||||
|
||||
Result __sync_init(void);
|
||||
//void __libc_init_array(void);
|
||||
|
||||
// Called before main
|
||||
void initSystem()
|
||||
{
|
||||
__sync_init();
|
||||
//__libc_init_array();
|
||||
|
||||
// Wait for sm
|
||||
for(Result res = 0xD88007FA; res == (Result)0xD88007FA; svcSleepThread(500 * 1000LL)) {
|
||||
res = srvPmInit();
|
||||
@@ -28,14 +45,27 @@ void __appInit()
|
||||
loaderInit();
|
||||
fsRegInit();
|
||||
|
||||
static u8 ALIGN(8) processDataBuffer[0x40 * sizeof(ProcessData)] = {0};
|
||||
static u8 ALIGN(8) exheaderInfoBuffer[6 * sizeof(ExHeader_Info)] = {0};
|
||||
static u8 ALIGN(8) threadStacks[2][THREAD_STACK_SIZE] = {0};
|
||||
|
||||
// Init objects
|
||||
Manager_Init(processDataBuffer, 0x40);
|
||||
ExHeaderInfoHeap_Init(exheaderInfoBuffer, 6);
|
||||
TaskRunner_Init();
|
||||
}
|
||||
|
||||
static const ServiceManagerServiceEntry services[] = {
|
||||
{ "pm:app", 4, pmAppHandleCommands, false },
|
||||
{ "pm:dbg", 2, pmDbgHandleCommands, false },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const ServiceManagerNotificationEntry notifications[] = {
|
||||
{ 0x000, NULL },
|
||||
};
|
||||
|
||||
void __ctru_exit(int rc) { (void)rc; } // needed to avoid linking error
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Result res = 0;
|
||||
|
||||
// Init the reslimits, register the KIPs and map the firmlaunch parameters
|
||||
initializeReslimits();
|
||||
@@ -48,51 +78,7 @@ void __appInit()
|
||||
|
||||
// Launch NS, etc.
|
||||
autolaunchSysmodules();
|
||||
}
|
||||
|
||||
// this is called after main exits
|
||||
void __appExit()
|
||||
{
|
||||
// We don't clean up g_manager's handles because it could hang the process monitor thread, etc.
|
||||
fsRegExit();
|
||||
loaderExit();
|
||||
srvPmExit();
|
||||
}
|
||||
|
||||
|
||||
Result __sync_init(void);
|
||||
Result __sync_fini(void);
|
||||
void __libc_init_array(void);
|
||||
void __libc_fini_array(void);
|
||||
|
||||
void __ctru_exit()
|
||||
{
|
||||
__libc_fini_array();
|
||||
__appExit();
|
||||
__sync_fini();
|
||||
svcExitProcess();
|
||||
}
|
||||
|
||||
void initSystem()
|
||||
{
|
||||
__sync_init();
|
||||
__appInit();
|
||||
__libc_init_array();
|
||||
}
|
||||
|
||||
static const ServiceManagerServiceEntry services[] = {
|
||||
{ "pm:app", 3, pmAppHandleCommands, false },
|
||||
{ "pm:dbg", 2, pmDbgHandleCommands, false },
|
||||
{ NULL },
|
||||
};
|
||||
|
||||
static const ServiceManagerNotificationEntry notifications[] = {
|
||||
{ 0x000, NULL },
|
||||
};
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Result res = 0;
|
||||
if (R_FAILED(res = ServiceManager_Run(services, notifications, NULL))) {
|
||||
panic(res);
|
||||
}
|
||||
|
||||
@@ -7,6 +7,21 @@
|
||||
|
||||
Manager g_manager;
|
||||
|
||||
static void giveAllFsArchiveAccessToKip(u32 pid, u64 tid)
|
||||
{
|
||||
static const ExHeader_Arm11StorageInfo storageInfo = {
|
||||
.fs_access_info = 0xFFFFFFFF,
|
||||
};
|
||||
static const u64 programHandle = 0xFFFF000000000000LL;
|
||||
|
||||
FS_ProgramInfo info = {
|
||||
.programId = tid,
|
||||
.mediaType = MEDIATYPE_NAND,
|
||||
};
|
||||
|
||||
assertSuccess(FSREG_Register(pid, programHandle, &info, &storageInfo));
|
||||
}
|
||||
|
||||
void Manager_Init(void *procBuf, size_t numProc)
|
||||
{
|
||||
memset(&g_manager, 0, sizeof(Manager));
|
||||
@@ -34,14 +49,23 @@ void Manager_RegisterKips(void)
|
||||
process->handle = processHandle;
|
||||
process->pid = i;
|
||||
process->refcount = 1;
|
||||
process->titleId = 0x0004000100001000ULL; // note: same TID for all builtins
|
||||
process->titleId = 0x0004000100001000ULL; // note: same internal TID for all builtins
|
||||
process->flags = PROCESSFLAG_KIP;
|
||||
process->terminationStatus = TERMSTATUS_RUNNING;
|
||||
|
||||
assertSuccess(svcSetProcessResourceLimits(processHandle, g_manager.reslimits[RESLIMIT_CATEGORY_OTHER]));
|
||||
if (i < 5) {
|
||||
// Exempt rosalina from being resource-limited at all
|
||||
assertSuccess(svcSetProcessResourceLimits(processHandle, g_manager.reslimits[RESLIMIT_CATEGORY_OTHER]));
|
||||
}
|
||||
}
|
||||
|
||||
ProcessList_Unlock(&g_manager.processList);
|
||||
|
||||
// Give full archive access to us (PM) and Rosalina (real PIDs don't matter, they just have to be unique (?))
|
||||
// Loader doesn't depend on PM and has its own fs:REG handle so it must do it itself.
|
||||
giveAllFsArchiveAccessToKip(2, 0x0004013000001202LL); // PM
|
||||
if (numKips > 5) {
|
||||
giveAllFsArchiveAccessToKip(5, 0x0004013000006902LL); // Rosalina
|
||||
}
|
||||
}
|
||||
|
||||
Result UnregisterProcess(u64 titleId)
|
||||
@@ -66,3 +90,27 @@ Result UnregisterProcess(u64 titleId)
|
||||
ProcessList_Unlock(&g_manager.processList);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result PrepareToChainloadHomebrew(u64 titleId)
|
||||
{
|
||||
// Note: I'm allowing this command to be called for non-applications, maybe that'll be useful
|
||||
// in the future...
|
||||
|
||||
ProcessData *foundProcess = NULL;
|
||||
Result res;
|
||||
ProcessList_Lock(&g_manager.processList);
|
||||
foundProcess = ProcessList_FindProcessByTitleId(&g_manager.processList, titleId & ~N3DS_TID_MASK);
|
||||
if (foundProcess != NULL) {
|
||||
// Clear the "notify on termination, don't cleanup" flag, so that for ex. APT isn't notified & no need for UnregisterProcess,
|
||||
// and the "dependencies loaded" flag, so that the dependencies aren't killed (for ex. when
|
||||
// booting hbmenu instead of Home Menu, in which case the same title is going to be launched...)
|
||||
|
||||
foundProcess->flags &= ~(PROCESSFLAG_DEPENDENCIES_LOADED | PROCESSFLAG_NOTIFY_TERMINATION);
|
||||
res = 0;
|
||||
} else {
|
||||
res = MAKERESULT(RL_TEMPORARY, RS_NOTFOUND, RM_PM, 0x100);
|
||||
}
|
||||
|
||||
ProcessList_Unlock(&g_manager.processList);
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -21,3 +21,4 @@ extern Manager g_manager;
|
||||
void Manager_Init(void *procBuf, size_t numProc);
|
||||
void Manager_RegisterKips(void);
|
||||
Result UnregisterProcess(u64 titleId);
|
||||
Result PrepareToChainloadHomebrew(u64 titleId);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "launch.h"
|
||||
#include "info.h"
|
||||
#include "util.h"
|
||||
#include "manager.h"
|
||||
|
||||
void pmDbgHandleCommands(void *ctx)
|
||||
{
|
||||
@@ -11,10 +12,10 @@ void pmDbgHandleCommands(void *ctx)
|
||||
u32 cmdhdr = cmdbuf[0];
|
||||
|
||||
FS_ProgramInfo programInfo;
|
||||
Handle debug;
|
||||
|
||||
u64 titleId;
|
||||
Handle debug;
|
||||
u32 pid;
|
||||
u32 launchFlags;
|
||||
|
||||
switch (cmdhdr >> 16) {
|
||||
case 1:
|
||||
@@ -40,12 +41,11 @@ void pmDbgHandleCommands(void *ctx)
|
||||
|
||||
// Custom
|
||||
case 0x100:
|
||||
titleId = 0;
|
||||
pid = 0xFFFFFFFF;
|
||||
cmdbuf[1] = GetCurrentAppTitleIdAndPid(&titleId, &pid);
|
||||
cmdbuf[0] = IPC_MakeHeader(0x100, 4, 0);
|
||||
memcpy(cmdbuf + 2, &titleId, 8);
|
||||
cmdbuf[4] = pid;
|
||||
cmdbuf[1] = GetCurrentAppInfo(&programInfo, &pid, &launchFlags);
|
||||
cmdbuf[0] = IPC_MakeHeader(0x100, 7, 0);
|
||||
memcpy(cmdbuf + 2, &programInfo, sizeof(FS_ProgramInfo));
|
||||
cmdbuf[6] = pid;
|
||||
cmdbuf[7] = launchFlags;
|
||||
break;
|
||||
case 0x101:
|
||||
cmdbuf[1] = DebugNextApplicationByForce(cmdbuf[1] != 0);
|
||||
@@ -59,7 +59,11 @@ void pmDbgHandleCommands(void *ctx)
|
||||
cmdbuf[2] = IPC_Desc_MoveHandles(1);
|
||||
cmdbuf[3] = debug;
|
||||
break;
|
||||
|
||||
case 0x103:
|
||||
memcpy(&titleId, cmdbuf + 1, 8);
|
||||
cmdbuf[1] = PrepareToChainloadHomebrew(titleId);
|
||||
cmdbuf[0] = IPC_MakeHeader(0x103, 1, 0);
|
||||
break;
|
||||
default:
|
||||
cmdbuf[0] = IPC_MakeHeader(0, 1, 0);
|
||||
cmdbuf[1] = 0xD900182F;
|
||||
|
||||
@@ -29,10 +29,12 @@ typedef struct ProcessData {
|
||||
u32 pid;
|
||||
u64 titleId;
|
||||
u64 programHandle;
|
||||
u32 launchFlags;
|
||||
u8 flags;
|
||||
u8 terminatedNotificationVariation;
|
||||
TerminationStatus terminationStatus;
|
||||
u8 refcount;
|
||||
FS_MediaType mediaType;
|
||||
} ProcessData;
|
||||
|
||||
typedef struct ProcessList {
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
#include "manager.h"
|
||||
#include "luma.h"
|
||||
|
||||
#define CPUTIME_MULTI_MASK BIT(7)
|
||||
#define CPUTIME_SINGLE_MASK 0
|
||||
|
||||
typedef s64 ReslimitValues[10];
|
||||
|
||||
static const ResourceLimitType g_reslimitInitOrder[10] = {
|
||||
@@ -189,20 +192,23 @@ static ReslimitValues g_n3dsReslimitValues[4] = {
|
||||
Both modes pause threads they don't want to run in thread selection, and unpause them when needed.
|
||||
If the threads that are intended to be paused is running an SVC, the pause will happen *after* SVC return.
|
||||
|
||||
Mode0 (unsure)
|
||||
Mode0 "multi"
|
||||
|
||||
Starting by "sysmodule" threads, alternatively allow (if preemptible) only sysmodule threads,
|
||||
and then only application threads to run.
|
||||
The latter has an exception; if "sysmodule" threads have run for less than 2usec, they
|
||||
The latter has an exception; if "sysmodule" threads have run for less than 8usec (value is a kernel bug), they
|
||||
are unpaused an allowed to run instead.
|
||||
|
||||
This happens at a rate of 1ms * (cpuTime/100).
|
||||
This happens at a rate of 2ms * (cpuTime/100).
|
||||
|
||||
Mode1
|
||||
|
||||
Mode1 "single"
|
||||
|
||||
This mode is half-broken due to a kernel bug (when "current thread" is the priority 0 kernel thread).
|
||||
|
||||
When this mode is enabled, only one application thread is allowed to be created on core1.
|
||||
|
||||
This divides the core1 time into slices of 12.5ms.
|
||||
This divides the core1 time into slices of 25ms.
|
||||
|
||||
The "application" thread is given cpuTime% of the slice.
|
||||
The "sysmodules" threads are given a total of (90 - cpuTime)% of the slice.
|
||||
@@ -243,7 +249,10 @@ static ReslimitValues *fixupReslimitValues(void)
|
||||
{
|
||||
// In order: APPLICATION, SYS_APPLET, LIB_APPLET, OTHER
|
||||
// Fixup "commit" reslimit
|
||||
u32 sysmemalloc = SYSMEMALLOC + getKExtSize();
|
||||
|
||||
// Note: we lie in the reslimit and make as if neither KExt nor Roslina existed, to avoid breakage
|
||||
|
||||
u32 sysmemalloc = SYSMEMALLOC + (hasKExt() ? getStolenSystemMemRegionSize() : 0);
|
||||
ReslimitValues *values = !IS_N3DS ? g_o3dsReslimitValues : g_n3dsReslimitValues;
|
||||
|
||||
static const u32 minAppletMemAmount = 0x1200000;
|
||||
@@ -315,22 +324,23 @@ void setAppCpuTimeLimitAndSchedModeFromDescriptor(u64 titleId, u16 descriptor)
|
||||
- app has a non-0 cputime descriptor in exhdr: maximum core1 cputime reslimit and scheduling
|
||||
mode are set according to it. Current reslimit is set to 0. SetAppResourceLimit *is* needed
|
||||
to use core1.
|
||||
- app has a 0 cputime descriptor: maximum is set to 80.
|
||||
Current reslimit is set to 0, and SetAppResourceLimit *is* needed
|
||||
- app has a 0 cputime descriptor: maximum is set to 80, scheduling mode to "single" (broken).
|
||||
Current reslimit is set to 0, and SetAppResourceLimit *is* also needed
|
||||
to use core1, **EXCEPT** for an hardcoded set of titles.
|
||||
*/
|
||||
u8 cpuTime = (u8)descriptor;
|
||||
assertSuccess(setAppCpuTimeLimit(0)); // remove preemption first.
|
||||
|
||||
g_manager.cpuTimeBase = 0;
|
||||
u32 currentValueToSet = g_manager.cpuTimeBase; // 0
|
||||
|
||||
if (cpuTime != 0) {
|
||||
// Set core1 scheduling mode
|
||||
g_manager.maxAppCpuTime = cpuTime & 0x7F;
|
||||
assertSuccess(svcKernelSetState(6, 3, (cpuTime & 0x80) ? 0LL : 1LL));
|
||||
} else {
|
||||
if (cpuTime == 0) {
|
||||
// 2.0 apps have this exheader field correctly filled, very often to 0x9E (1.0 titles don't).
|
||||
u32 titleUid = ((u32)titleId >> 8) & 0xFFFFF;
|
||||
g_manager.maxAppCpuTime = 80;
|
||||
|
||||
// Default setting is 80% max "single", with a current value of 0
|
||||
cpuTime = CPUTIME_SINGLE_MASK | 80;
|
||||
|
||||
static const u32 numOverrides = sizeof(g_startCpuTimeOverrides) / sizeof(g_startCpuTimeOverrides[0]);
|
||||
|
||||
if (titleUid >= g_startCpuTimeOverrides[0].titleUid && titleUid <= g_startCpuTimeOverrides[numOverrides - 1].titleUid) {
|
||||
@@ -338,15 +348,26 @@ void setAppCpuTimeLimitAndSchedModeFromDescriptor(u64 titleId, u16 descriptor)
|
||||
for (u32 i = 0; i < numOverrides && titleUid < g_startCpuTimeOverrides[i].titleUid; i++);
|
||||
if (i < numOverrides) {
|
||||
if (g_startCpuTimeOverrides[i].value > 100 && g_startCpuTimeOverrides[i].value < 200) {
|
||||
assertSuccess(svcKernelSetState(6, 3, 0LL));
|
||||
assertSuccess(setAppCpuTimeLimit(g_startCpuTimeOverrides[i].value - 100));
|
||||
cpuTime = CPUTIME_MULTI_MASK | 80; // "multi", max 80%
|
||||
currentValueToSet = g_startCpuTimeOverrides[i].value - 100;
|
||||
} else {
|
||||
assertSuccess(svcKernelSetState(6, 3, 1LL));
|
||||
assertSuccess(setAppCpuTimeLimit(g_startCpuTimeOverrides[i].value));
|
||||
cpuTime = CPUTIME_SINGLE_MASK | 80; // "single", max 80%
|
||||
currentValueToSet = g_startCpuTimeOverrides[i].value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Set core1 scheduling mode
|
||||
assertSuccess(svcKernelSetState(6, 3, (cpuTime & CPUTIME_MULTI_MASK) ? 0LL : 1LL));
|
||||
|
||||
// Set max value (limit)
|
||||
g_manager.maxAppCpuTime = cpuTime & 0x7F;
|
||||
|
||||
// Set current value (for 1.0 apps)
|
||||
if (currentValueToSet != 0) {
|
||||
assertSuccess(setAppCpuTimeLimit(currentValueToSet));
|
||||
}
|
||||
}
|
||||
|
||||
Result SetAppResourceLimit(u32 mbz, ResourceLimitType category, u32 value, u64 mbz2)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -4,6 +4,11 @@
|
||||
|
||||
TaskRunner g_taskRunner;
|
||||
|
||||
static void taskRunnerNoOpFunction(void *args)
|
||||
{
|
||||
(void)args;
|
||||
}
|
||||
|
||||
void TaskRunner_Init(void)
|
||||
{
|
||||
memset(&g_taskRunner, 0, sizeof(TaskRunner));
|
||||
@@ -20,12 +25,23 @@ void TaskRunner_RunTask(void (*task)(void *argdata), void *argdata, size_t argsi
|
||||
LightEvent_Signal(&g_taskRunner.parametersSetEvent);
|
||||
}
|
||||
|
||||
void TaskRunner_Terminate(void)
|
||||
{
|
||||
g_taskRunner.shouldTerminate = true;
|
||||
TaskRunner_RunTask(taskRunnerNoOpFunction, NULL, 0);
|
||||
}
|
||||
|
||||
void TaskRunner_HandleTasks(void *p)
|
||||
{
|
||||
(void)p;
|
||||
for (;;) {
|
||||
while (!g_taskRunner.shouldTerminate) {
|
||||
LightEvent_Signal(&g_taskRunner.readyEvent);
|
||||
LightEvent_Wait(&g_taskRunner.parametersSetEvent);
|
||||
g_taskRunner.task(g_taskRunner.argStorage);
|
||||
}
|
||||
}
|
||||
|
||||
void TaskRunner_WaitReady(void)
|
||||
{
|
||||
LightEvent_Wait(&g_taskRunner.readyEvent);
|
||||
}
|
||||
|
||||
@@ -8,11 +8,15 @@ typedef struct TaskRunner {
|
||||
LightEvent parametersSetEvent;
|
||||
void (*task)(void *argdata);
|
||||
u8 argStorage[0x40];
|
||||
bool shouldTerminate;
|
||||
} TaskRunner;
|
||||
|
||||
extern TaskRunner g_taskRunner;
|
||||
|
||||
void TaskRunner_Init(void);
|
||||
void TaskRunner_RunTask(void (*task)(void *argdata), void *argdata, size_t argsize);
|
||||
void TaskRunner_Terminate(void);
|
||||
|
||||
/// Thread function
|
||||
void TaskRunner_HandleTasks(void *p);
|
||||
void TaskRunner_WaitReady(void);
|
||||
|
||||
@@ -6,6 +6,15 @@
|
||||
#include "exheader_info_heap.h"
|
||||
#include "task_runner.h"
|
||||
|
||||
void forceMountSdCard(void)
|
||||
{
|
||||
FS_Archive sdmcArchive;
|
||||
|
||||
assertSuccess(fsInit());
|
||||
assertSuccess(FSUSER_OpenArchive(&sdmcArchive, ARCHIVE_SDMC, fsMakePath(PATH_EMPTY, "")));
|
||||
// No need to clean up things as we will firmlaunch straight away
|
||||
}
|
||||
|
||||
static Result terminateUnusedDependencies(const u64 *dependencies, u32 numDeps)
|
||||
{
|
||||
ProcessData *process;
|
||||
@@ -65,6 +74,16 @@ static Result terminateProcessImpl(ProcessData *process, ExHeader_Info *exheader
|
||||
}
|
||||
}
|
||||
|
||||
static void terminateProcessByIdChecked(u32 pid)
|
||||
{
|
||||
ProcessData *process = ProcessList_FindProcessById(&g_manager.processList, pid);
|
||||
if (process != NULL) {
|
||||
ProcessData_SendTerminationNotification(process);
|
||||
} else {
|
||||
panic(0LL);
|
||||
}
|
||||
}
|
||||
|
||||
static Result commitPendingTerminations(s64 timeout)
|
||||
{
|
||||
// Wait for all of the processes that have received notification 0x100 to terminate
|
||||
@@ -247,6 +266,8 @@ ProcessData *terminateAllProcesses(u32 callerPid, s64 timeout)
|
||||
|
||||
u64 dependencies[48];
|
||||
u32 numDeps = 0;
|
||||
s64 numKips = 0;
|
||||
svcGetSystemInfo(&numKips, 26, 0);
|
||||
|
||||
ExHeader_Info *exheaderInfo = ExHeaderInfoHeap_New();
|
||||
|
||||
@@ -269,6 +290,12 @@ ProcessData *terminateAllProcesses(u32 callerPid, s64 timeout)
|
||||
}
|
||||
|
||||
ProcessList_Lock(&g_manager.processList);
|
||||
|
||||
// Send custom notification to at least Rosalina to make it relinquish some non-KIP services handles, stop the debugger, etc.
|
||||
if (numKips >= 6) {
|
||||
notifySubscribers(0x2000);
|
||||
}
|
||||
|
||||
// Send notification 0x100 to the currently running application
|
||||
if (g_manager.runningApplicationData != NULL) {
|
||||
g_manager.runningApplicationData->flags &= ~PROCESSFLAG_DEPENDENCIES_LOADED;
|
||||
@@ -302,20 +329,29 @@ ProcessData *terminateAllProcesses(u32 callerPid, s64 timeout)
|
||||
commitPendingTerminations(timeoutTicks >= 0 ? ticksToNs(timeoutTicks) : 0LL);
|
||||
g_manager.waitingForTermination = false;
|
||||
|
||||
// Now, send termination notification to PXI (PID 4)
|
||||
if (callerPid == (u32)-1) {
|
||||
// On firmlaunch, try to force Process9 to mount the SD card to allow the Process9 firmlaunch patch to load boot.firm if needed
|
||||
// Need to do that before we tell PXI to terminate
|
||||
s64 out;
|
||||
if(R_SUCCEEDED(svcGetSystemInfo(&out, 0x10000, 0x203)) && out != 0) {
|
||||
// If boot.firm is on the SD card, then...
|
||||
forceMountSdCard();
|
||||
}
|
||||
}
|
||||
|
||||
// Now, send termination notification to PXI (PID 4). Also do the same for Rosalina.
|
||||
assertSuccess(svcClearEvent(g_manager.allNotifiedTerminationEvent));
|
||||
g_manager.waitingForTermination = true;
|
||||
|
||||
ProcessList_Lock(&g_manager.processList);
|
||||
process = ProcessList_FindProcessById(&g_manager.processList, 4);
|
||||
if (process != NULL) {
|
||||
ProcessData_SendTerminationNotification(process);
|
||||
} else {
|
||||
panic(0LL);
|
||||
|
||||
if (numKips >= 6) {
|
||||
terminateProcessByIdChecked(5); // Rosalina
|
||||
}
|
||||
terminateProcessByIdChecked(4); // PXI
|
||||
|
||||
ProcessList_Unlock(&g_manager.processList);
|
||||
|
||||
// Allow 1.5 extra seconds for PXI (approx 402167783 ticks)
|
||||
// Allow 1.5 extra seconds for PXI and Rosalina (approx 402167783 ticks)
|
||||
timeoutTicks = dstTimePoint - svcGetSystemTick();
|
||||
commitPendingTerminations(1500 * 1000 * 1000LL + (timeoutTicks >= 0 ? ticksToNs(timeoutTicks) : 0LL));
|
||||
g_manager.waitingForTermination = false;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2015 TuxSH
|
||||
Copyright (c) 2015-2020 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
|
||||
@@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
SOFTWARE.
|
||||
|
||||
@@ -37,7 +37,7 @@ CFLAGS += $(INCLUDE)
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
|
||||
ASFLAGS := -g $(ARCH)
|
||||
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
|
||||
LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map),-wrap,exit
|
||||
|
||||
LIBS := -lctru
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# 3ds_pxi
|
||||
Open source replacement of the ARM11 PXI system module.
|
||||
Open source replacement of the Arm11 PXI system module.
|
||||
This is licensed under the MIT license.
|
||||
|
||||
# Usage
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
MyThread.c:
|
||||
Small threading library, based off ctrulib.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
(c) TuxSH, 2016-2020
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
MyThread.h:
|
||||
Small threading library, based off ctrulib.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
(c) TuxSH, 2016-2020
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
PXI.c:
|
||||
PXI I/O functions.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
(c) TuxSH, 2016-2020
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
PXI.h:
|
||||
PXI I/O functions.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
(c) TuxSH, 2016-2020
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
common.h:
|
||||
Common types and global variables.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
(c) TuxSH, 2016-2020
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
|
||||
@@ -2,12 +2,11 @@
|
||||
main.c
|
||||
(De)initialization stuff. It's also here where sessions are being accepted.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
(c) TuxSH, 2016-2020
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "PXI.h"
|
||||
#include "common.h"
|
||||
#include "MyThread.h"
|
||||
@@ -99,10 +98,40 @@ static inline void exitPXI(void)
|
||||
static u8 ALIGN(8) receiverStack[THREAD_STACK_SIZE];
|
||||
static u8 ALIGN(8) senderStack[THREAD_STACK_SIZE];
|
||||
static u8 ALIGN(8) PXISRV11HandlerStack[THREAD_STACK_SIZE];
|
||||
static MyThread receiverThread = {0}, senderThread = {0}, PXISRV11HandlerThread = {0};
|
||||
|
||||
Result __sync_init(void);
|
||||
Result __sync_fini(void);
|
||||
void __libc_fini_array(void);
|
||||
void __libc_init_array(void);
|
||||
|
||||
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;
|
||||
|
||||
srvExit();
|
||||
exitPXI();
|
||||
|
||||
svcCloseHandle(terminationRequestedEvent);
|
||||
svcCloseHandle(sessionManager.sendAllBuffersToArm9Event);
|
||||
svcCloseHandle(sessionManager.replySemaphore);
|
||||
svcCloseHandle(sessionManager.PXISRV11CommandReceivedEvent);
|
||||
svcCloseHandle(sessionManager.PXISRV11ReplySentEvent);
|
||||
|
||||
//__libc_fini_array();
|
||||
__sync_fini();
|
||||
svcExitProcess();
|
||||
}
|
||||
|
||||
// this is called before main
|
||||
void __appInit()
|
||||
|
||||
void initSystem(void)
|
||||
{
|
||||
__sync_init();
|
||||
|
||||
assertSuccess(svcCreateEvent(&terminationRequestedEvent, RESET_STICKY));
|
||||
|
||||
assertSuccess(svcCreateEvent(&sessionManager.sendAllBuffersToArm9Event, RESET_ONESHOT));
|
||||
@@ -117,52 +146,13 @@ void __appInit()
|
||||
if(R_FAILED(res) && res != (Result)0xD88007FA)
|
||||
svcBreak(USERBREAK_PANIC);
|
||||
}
|
||||
}
|
||||
|
||||
// this is called after main exits
|
||||
void __appExit()
|
||||
{
|
||||
srvExit();
|
||||
exitPXI();
|
||||
|
||||
svcCloseHandle(terminationRequestedEvent);
|
||||
svcCloseHandle(sessionManager.sendAllBuffersToArm9Event);
|
||||
svcCloseHandle(sessionManager.replySemaphore);
|
||||
svcCloseHandle(sessionManager.PXISRV11CommandReceivedEvent);
|
||||
svcCloseHandle(sessionManager.PXISRV11ReplySentEvent);
|
||||
}
|
||||
|
||||
// stubs for non-needed pre-main functions
|
||||
void __system_initSyscalls(){}
|
||||
|
||||
|
||||
Result __sync_init(void);
|
||||
Result __sync_fini(void);
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
Handle handles[10] = {0}; //notification handle + service handles
|
||||
MyThread receiverThread = {0}, senderThread = {0}, PXISRV11HandlerThread = {0};
|
||||
|
||||
for(u32 i = 0; i < 9; i++)
|
||||
assertSuccess(srvRegisterService(handles + 1 + i, serviceNames[i], 1));
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
receiver.c:
|
||||
Fetches replies coming from Process9, writing them in the appropriate buffer.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
(c) TuxSH, 2016-2020
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
receiver.h:
|
||||
Fetches replies coming from Process9, writing them in the appropriate buffer.
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
(c) TuxSH, 2016-2020
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ sender.c
|
||||
Handles commands from arm11 processes, then sends them to Process9, and replies to arm11 processes the replies received from Process9 (=> receiver.c).
|
||||
(except for PXISRV11)
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
(c) TuxSH, 2016-2020
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
sender.h
|
||||
Handles commands from arm11 processes, then sends them to Process9, and replies to arm11 processes the replies received from Process9 (=> receiver.c) (except for PXISRV11).
|
||||
|
||||
(c) TuxSH, 2016-2017
|
||||
(c) TuxSH, 2016-2020
|
||||
This is part of 3ds_pxi, which is licensed under the MIT license (see LICENSE for details).
|
||||
*/
|
||||
|
||||
|
||||
@@ -38,9 +38,9 @@ CFLAGS += $(INCLUDE)
|
||||
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
|
||||
|
||||
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 -lm
|
||||
LIBS := -lctru
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# list of directories containing libraries, this must be the top level containing
|
||||
@@ -131,6 +131,8 @@ $(OUTPUT).elf : $(OFILES)
|
||||
@$(LD) $(LDFLAGS) $(OFILES) $(LIBPATHS) $(LIBS) -o $@
|
||||
@$(NM) -CSn $@ > $(notdir $*.lst)
|
||||
|
||||
draw.o: CFLAGS += -O3
|
||||
|
||||
$(OFILES_SRC) : $(HFILES_BIN)
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
@@ -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,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,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
|
||||
@@ -54,9 +54,14 @@
|
||||
#define GPU_TRANSFER_CNT REG32(0x10400C18)
|
||||
#define GPU_CMDLIST_CNT REG32(0x104018F0)
|
||||
|
||||
#define LCD_TOP_BRIGHTNESS REG32(0x10202240)
|
||||
#define LCD_BOT_BRIGHTNESS REG32(0x10202A40)
|
||||
|
||||
#define FB_BOTTOM_VRAM_ADDR ((void *)0x1F48F000) // cached
|
||||
#define FB_BOTTOM_VRAM_PA 0x1848F000
|
||||
#define FB_BOTTOM_SIZE (320 * 240 * 2)
|
||||
#define FB_SCREENSHOT_SIZE (52 + 400 * 240 * 3)
|
||||
|
||||
|
||||
#define SCREEN_BOT_WIDTH 320
|
||||
#define SCREEN_BOT_HEIGHT 240
|
||||
@@ -73,19 +78,27 @@
|
||||
|
||||
#define DRAW_MAX_FORMATTED_STRING_SIZE 512
|
||||
|
||||
void Draw_Init(void);
|
||||
|
||||
void Draw_Lock(void);
|
||||
void Draw_Unlock(void);
|
||||
|
||||
void Draw_DrawCharacter(u32 posX, u32 posY, u32 color, char character);
|
||||
u32 Draw_DrawString(u32 posX, u32 posY, u32 color, const char *string);
|
||||
|
||||
__attribute__((format(printf,4,5)))
|
||||
u32 Draw_DrawFormattedString(u32 posX, u32 posY, u32 color, const char *fmt, ...);
|
||||
|
||||
void Draw_FillFramebuffer(u32 value);
|
||||
void Draw_ClearFramebuffer(void);
|
||||
void Draw_SetupFramebuffer(void);
|
||||
u32 Draw_AllocateFramebufferCache(void);
|
||||
void Draw_FreeFramebufferCache(void);
|
||||
void *Draw_GetFramebufferCache(void);
|
||||
u32 Draw_GetFramebufferCacheSize(void);
|
||||
u32 Draw_SetupFramebuffer(void);
|
||||
void Draw_RestoreFramebuffer(void);
|
||||
void Draw_FlushFramebuffer(void);
|
||||
u32 Draw_GetCurrentFramebufferAddress(bool top, bool left);
|
||||
|
||||
void Draw_CreateBitmapHeader(u8 *dst, u32 width, u32 heigth);
|
||||
void Draw_ConvertFrameBufferLine(u8 *line, bool top, bool left, u32 y);
|
||||
void Draw_ConvertFrameBufferLines(u8 *buf, u32 startingLine, u32 numLines, bool top, bool left);
|
||||
|
||||
@@ -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
|
||||
@@ -27,5 +27,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <3ds/types.h>
|
||||
#include "MyThread.h"
|
||||
|
||||
void ERRF_HandleCommands(void *ctx);
|
||||
MyThread *errDispCreateThread(void);
|
||||
void ERRF_HandleCommands(void);
|
||||
void errDispThreadMain(void);
|
||||
|
||||
@@ -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,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
@@ -18,14 +18,14 @@
|
||||
|
||||
#define MAX_DEBUG 3
|
||||
#define MAX_DEBUG_THREAD 127
|
||||
#define MAX_BREAKPOINT 256
|
||||
#define MAX_BREAKPOINT 64
|
||||
|
||||
#define MAX_TIO_OPEN_FILE 32
|
||||
|
||||
// 512+24 is the ideal size as IDA will try to read exactly 0x100 bytes at a time. Add 4 to this, for $#<checksum>, see below.
|
||||
// IDA seems to want additional bytes as well.
|
||||
// 1024 is fine enough to put all regs in the 'T' stop reply packets
|
||||
#define GDB_BUF_LEN 2048
|
||||
#define GDB_BUF_LEN 1024
|
||||
|
||||
#define GDB_HANDLER(name) GDB_Handle##name
|
||||
#define GDB_QUERY_HANDLER(name) GDB_HANDLER(Query##name)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
@@ -13,4 +13,4 @@ bool GDB_FetchPackedHioRequest(GDBContext *ctx, u32 addr);
|
||||
bool GDB_IsHioInProgress(GDBContext *ctx);
|
||||
int GDB_SendCurrentHioRequest(GDBContext *ctx);
|
||||
|
||||
GDB_DECLARE_HANDLER(HioReply);
|
||||
GDB_DECLARE_HANDLER(HioReply);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -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
|
||||
@@ -33,4 +33,5 @@
|
||||
#define HBLDR_DEFAULT_3DSX_TID 0x000400000D921E00ULL
|
||||
#define HBLDR_3DSX_TID (*(vu64 *)0x1FF81100)
|
||||
|
||||
void HBLDR_RestartHbApplication(void *p);
|
||||
void HBLDR_HandleCommands(void *ctx);
|
||||
|
||||
@@ -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,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
|
||||
@@ -36,4 +36,5 @@ extern int inputRedirectionStartResult;
|
||||
|
||||
MyThread *inputRedirectionCreateThread(void);
|
||||
void inputRedirectionThreadMain(void);
|
||||
Result InputRedirection_Disable(s64 timeout);
|
||||
Result InputRedirection_DoOrUndoPatches(void);
|
||||
|
||||
@@ -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,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
|
||||
@@ -27,33 +27,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <3ds/types.h>
|
||||
#include <3ds/services/hid.h>
|
||||
#include "MyThread.h"
|
||||
#include "utils.h"
|
||||
|
||||
#define HID_PAD (REG32(0x10146000) ^ 0xFFF)
|
||||
|
||||
#define BUTTON_A (1 << 0)
|
||||
#define BUTTON_B (1 << 1)
|
||||
#define BUTTON_SELECT (1 << 2)
|
||||
#define BUTTON_START (1 << 3)
|
||||
#define BUTTON_RIGHT (1 << 4)
|
||||
#define BUTTON_LEFT (1 << 5)
|
||||
#define BUTTON_UP (1 << 6)
|
||||
#define BUTTON_DOWN (1 << 7)
|
||||
#define BUTTON_R1 (1 << 8)
|
||||
#define BUTTON_L1 (1 << 9)
|
||||
#define BUTTON_X (1 << 10)
|
||||
#define BUTTON_Y (1 << 11)
|
||||
|
||||
#define DEFAULT_MENU_COMBO (BUTTON_L1 | BUTTON_DOWN | BUTTON_SELECT)
|
||||
#define DEFAULT_MENU_COMBO (KEY_L | KEY_DDOWN | KEY_SELECT)
|
||||
#define DIRECTIONAL_KEYS (KEY_DOWN | KEY_UP | KEY_LEFT | KEY_RIGHT)
|
||||
|
||||
#define CORE_APPLICATION 0
|
||||
#define CORE_SYSTEM 1
|
||||
|
||||
typedef enum MenuItemAction {
|
||||
METHOD,
|
||||
MENU
|
||||
MENU_END = 0,
|
||||
METHOD = 1,
|
||||
MENU = 2,
|
||||
} MenuItemAction;
|
||||
|
||||
typedef struct MenuItem {
|
||||
const char *title;
|
||||
|
||||
@@ -62,16 +54,20 @@ typedef struct MenuItem {
|
||||
struct Menu *menu;
|
||||
void (*method)(void);
|
||||
};
|
||||
|
||||
bool (*visibility)(void);
|
||||
} MenuItem;
|
||||
|
||||
typedef struct Menu {
|
||||
const char *title;
|
||||
|
||||
u32 nbItems;
|
||||
MenuItem items[0x40];
|
||||
MenuItem items[16];
|
||||
} Menu;
|
||||
|
||||
extern bool terminationRequest;
|
||||
extern Handle terminationRequestEvent;
|
||||
extern bool isN3DS;
|
||||
extern bool menuShouldExit;
|
||||
extern bool preTerminationRequested;
|
||||
extern Handle preTerminationEvent;
|
||||
|
||||
extern u32 menuCombo;
|
||||
|
||||
@@ -81,6 +77,9 @@ u32 waitInput(void);
|
||||
u32 waitComboWithTimeout(u32 msec);
|
||||
u32 waitCombo(void);
|
||||
|
||||
bool menuCheckN3ds(void);
|
||||
u32 menuCountItems(const Menu *menu);
|
||||
|
||||
MyThread *menuCreateThread(void);
|
||||
void menuEnter(void);
|
||||
void menuLeave(void);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
|
||||
/*
|
||||
* 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
|
||||
@@ -33,8 +33,12 @@
|
||||
extern Menu rosalinaMenu;
|
||||
|
||||
void RosalinaMenu_TakeScreenshot(void);
|
||||
void RosalinaMenu_ChangeScreenBrightness(void);
|
||||
void RosalinaMenu_ShowCredits(void);
|
||||
void RosalinaMenu_ProcessList(void);
|
||||
void RosalinaMenu_PowerOff(void);
|
||||
void RosalinaMenu_Reboot(void);
|
||||
void RosalinaMenu_Cheats(void);
|
||||
|
||||
bool rosalinaMenuShouldShowDebugInfo(void);
|
||||
void RosalinaMenu_ShowDebugInfo(void);
|
||||
|
||||
@@ -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
|
||||
@@ -33,4 +33,5 @@
|
||||
#define CHEATS_PER_MENU_PAGE 18
|
||||
|
||||
void RosalinaMenu_Cheats(void);
|
||||
void Cheat_ApplyCheats();
|
||||
void Cheat_SeedRng(u64 seed);
|
||||
void Cheat_ApplyCheats(void);
|
||||
|
||||
@@ -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
|
||||
@@ -32,6 +32,8 @@
|
||||
extern Menu debuggerMenu;
|
||||
|
||||
void debuggerFetchAndSetNextApplicationDebugHandleTask(void *argdata);
|
||||
Result debuggerDisable(s64 timeout);
|
||||
|
||||
void DebuggerMenu_EnableDebugger(void);
|
||||
void DebuggerMenu_DisableDebugger(void);
|
||||
void DebuggerMenu_DebugNextApplicationByForce(void);
|
||||
|
||||
@@ -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
|
||||
@@ -35,4 +35,4 @@ void MiscellaneousMenu_SwitchBoot3dsxTargetTitle(void);
|
||||
void MiscellaneousMenu_ChangeMenuCombo(void);
|
||||
void MiscellaneousMenu_SaveSettings(void);
|
||||
void MiscellaneousMenu_InputRedirection(void);
|
||||
void MiscellaneousMenu_SyncTimeDate(void);
|
||||
void MiscellaneousMenu_SyncTimeDate(void);
|
||||
|
||||
@@ -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,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,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
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
extern Menu screenFiltersMenu;
|
||||
|
||||
int screenFiltersCurrentTemperature;
|
||||
extern int screenFiltersCurrentTemperature;
|
||||
|
||||
void screenFiltersSetDisabled(void);
|
||||
void screenFiltersReduceBlueLevel1(void);
|
||||
|
||||
@@ -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
|
||||
@@ -30,6 +30,12 @@
|
||||
#include "menu.h"
|
||||
|
||||
extern Menu sysconfigMenu;
|
||||
extern bool isConnectionForced;
|
||||
|
||||
void SysConfigMenu_UpdateStatus(bool control);
|
||||
|
||||
void SysConfigMenu_ToggleLEDs(void);
|
||||
void SysConfigMenu_ToggleWireless(void);
|
||||
void SysConfigMenu_TogglePowerButton(void);
|
||||
void SysConfigMenu_ControlWifi(void);
|
||||
void SysConfigMenu_DisableForcedWifiConnection(void);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
@@ -18,13 +18,10 @@
|
||||
#include <errno.h>
|
||||
|
||||
#define SYNC_ERROR ENODEV
|
||||
|
||||
extern Handle SOCU_handle;
|
||||
extern Handle socMemhandle;
|
||||
|
||||
extern bool miniSocEnabled;
|
||||
|
||||
Result miniSocInit();
|
||||
Result miniSocInit(void);
|
||||
Result miniSocExitDirect(void);
|
||||
Result miniSocExit(void);
|
||||
|
||||
s32 _net_convert_error(s32 sock_retval);
|
||||
@@ -37,10 +34,17 @@ int socConnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);
|
||||
int socPoll(struct pollfd *fds, nfds_t nfds, int timeout);
|
||||
int socSetsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
|
||||
int socClose(int sockfd);
|
||||
long socGethostid(void);
|
||||
|
||||
ssize_t soc_recv(int sockfd, void *buf, size_t len, int flags);
|
||||
ssize_t soc_send(int sockfd, const void *buf, size_t len, int flags);
|
||||
ssize_t socRecvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
|
||||
ssize_t socSendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
|
||||
|
||||
// actually provided by ctrulib
|
||||
ssize_t soc_recvfrom(int sockfd, void *buf, size_t len, int flags, struct sockaddr *src_addr, socklen_t *addrlen);
|
||||
ssize_t soc_sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen);
|
||||
static inline ssize_t socRecv(int sockfd, void *buf, size_t len, int flags)
|
||||
{
|
||||
return socRecvfrom(sockfd, buf, len, flags, NULL, 0);
|
||||
}
|
||||
|
||||
static inline ssize_t socSend(int sockfd, const void *buf, size_t len, int flags)
|
||||
{
|
||||
return socSendto(sockfd, buf, len, flags, NULL, 0);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -30,4 +30,4 @@
|
||||
#include <time.h>
|
||||
|
||||
Result ntpGetTimeStamp(time_t *outTimestamp);
|
||||
Result ntpSetTimeDate(const struct tm *localt);
|
||||
Result ntpSetTimeDate(time_t timestamp);
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
// License for this file: ctrulib's license
|
||||
// Copyright AuroraWright, TuxSH 2019
|
||||
// Copyright AuroraWright, TuxSH 2019-2020
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <3ds/services/pmapp.h>
|
||||
#include <3ds/services/pmdbg.h>
|
||||
|
||||
Result PMDBG_GetCurrentAppTitleIdAndPid(u64 *outTitleId, u32 *outPid);
|
||||
/// Custom launch flags for PM launch commands.
|
||||
enum {
|
||||
PMLAUNCHFLAGEXT_FAKE_DEPENDENCY_LOADING = BIT(24),
|
||||
};
|
||||
|
||||
Result PMDBG_GetCurrentAppInfo(FS_ProgramInfo *outProgramInfo, u32 *outPid, u32 *outLaunchFlags);
|
||||
Result PMDBG_DebugNextApplicationByForce(bool debug);
|
||||
Result PMDBG_LaunchTitleDebug(Handle *outDebug, const FS_ProgramInfo *programInfo, u32 launchFlags);
|
||||
Result PMDBG_PrepareToChainloadHomebrew(u64 titleId);
|
||||
|
||||
@@ -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
|
||||
@@ -29,4 +29,5 @@
|
||||
#include <3ds/types.h>
|
||||
#include "menu.h"
|
||||
|
||||
void ProcessPatchesMenu_PatchUnpatchFSDirectly(void);
|
||||
Result OpenProcessByName(const char *name, Handle *h);
|
||||
Result PatchProcessByName(const char *name, Result (*func)(u32 size));
|
||||
@@ -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,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
@@ -68,10 +68,11 @@ typedef struct sock_server
|
||||
sock_free_func free;
|
||||
|
||||
Handle shall_terminate_event;
|
||||
Result init_result;
|
||||
} sock_server;
|
||||
|
||||
Result server_init(struct sock_server *serv);
|
||||
void server_bind(struct sock_server *serv, u16 port);
|
||||
Result server_bind(struct sock_server *serv, u16 port);
|
||||
void server_run(struct sock_server *serv);
|
||||
void server_kill_connections(struct sock_server *serv);
|
||||
void server_set_should_close_all(struct sock_server *serv);
|
||||
|
||||
@@ -9,6 +9,7 @@ typedef struct TaskRunner {
|
||||
LightEvent parametersSetEvent;
|
||||
void (*task)(void *argdata);
|
||||
u8 argStorage[0x40];
|
||||
bool shouldTerminate;
|
||||
} TaskRunner;
|
||||
|
||||
extern TaskRunner g_taskRunner;
|
||||
@@ -17,6 +18,8 @@ MyThread *taskRunnerCreateThread(void);
|
||||
|
||||
void TaskRunner_Init(void);
|
||||
void TaskRunner_RunTask(void (*task)(void *argdata), void *argdata, size_t argsize);
|
||||
void TaskRunner_Terminate(void);
|
||||
|
||||
/// Thread function
|
||||
void TaskRunner_HandleTasks(void);
|
||||
void TaskRunner_WaitReady(void);
|
||||
void TaskRunner_WaitReady(void);
|
||||
|
||||
@@ -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
|
||||
@@ -27,6 +27,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <3ds/svc.h>
|
||||
#include <3ds/srv.h>
|
||||
#include <3ds/result.h>
|
||||
#include <3ds/ipc.h>
|
||||
#include "csvc.h"
|
||||
@@ -40,7 +41,7 @@
|
||||
|
||||
#define REG32(addr) (*(vu32 *)(PA_PTR(addr)))
|
||||
|
||||
static inline u32 makeARMBranch(const void *src, const void *dst, bool link) // the macros for those are ugly and buggy
|
||||
static inline u32 makeArmBranch(const void *src, const void *dst, bool link) // the macros for those are ugly and buggy
|
||||
{
|
||||
u32 instrBase = link ? 0xEB000000 : 0xEA000000;
|
||||
u32 off = (u32)((const u8 *)dst - ((const u8 *)src + 8)); // the PC is always two instructions ahead of the one being executed
|
||||
@@ -48,7 +49,7 @@ static inline u32 makeARMBranch(const void *src, const void *dst, bool link) //
|
||||
return instrBase | ((off >> 2) & 0xFFFFFF);
|
||||
}
|
||||
|
||||
static inline void *decodeARMBranch(const void *src)
|
||||
static inline void *decodeArmBranch(const void *src)
|
||||
{
|
||||
u32 instr = *(const u32 *)src;
|
||||
s32 off = (instr & 0xFFFFFF) << 2;
|
||||
@@ -73,3 +74,12 @@ extern bool isN3DS;
|
||||
|
||||
Result OpenProcessByName(const char *name, Handle *h);
|
||||
Result SaveSettings(void);
|
||||
static inline bool isServiceUsable(const char *name)
|
||||
{
|
||||
bool r;
|
||||
return R_SUCCEEDED(srvIsServiceRegistered(&r, name)) && r;
|
||||
}
|
||||
|
||||
void formatMemoryPermission(char *outbuf, MemPerm perm);
|
||||
void formatUserMemoryState(char *outbuf, MemState state);
|
||||
u32 formatMemoryMapOfProcess(char *outbuf, u32 bufLen, Handle handle);
|
||||
|
||||
@@ -21,7 +21,7 @@ AccessControlInfo:
|
||||
IdealProcessor : 1
|
||||
AffinityMask : 3
|
||||
|
||||
Priority : 20
|
||||
Priority : 25 # 55
|
||||
|
||||
DisableDebug : false
|
||||
EnableForceDebug : true
|
||||
@@ -37,7 +37,7 @@ AccessControlInfo:
|
||||
CoreVersion : 2
|
||||
DescVersion : 2
|
||||
|
||||
MemoryType : System # Application / System / Base
|
||||
MemoryType : Base # Application / System / Base
|
||||
HandleTableSize: 150
|
||||
|
||||
MemoryMapping:
|
||||
|
||||
@@ -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,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,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
|
||||
@@ -32,22 +32,22 @@
|
||||
#include "memory.h"
|
||||
#include "menu.h"
|
||||
#include "utils.h"
|
||||
#include "csvc.h"
|
||||
|
||||
u8 framebufferCache[FB_BOTTOM_SIZE];
|
||||
#define KERNPA2VA(a) ((a) + (GET_VERSION_MINOR(osGetKernelVersion()) < 44 ? 0xD0000000 : 0xC0000000))
|
||||
|
||||
static u32 gpuSavedFramebufferAddr1, gpuSavedFramebufferAddr2, gpuSavedFramebufferFormat, gpuSavedFramebufferStride;
|
||||
|
||||
static u32 framebufferCacheSize;
|
||||
static void *framebufferCache;
|
||||
static RecursiveLock lock;
|
||||
|
||||
void Draw_Init(void)
|
||||
{
|
||||
RecursiveLock_Init(&lock);
|
||||
}
|
||||
|
||||
void Draw_Lock(void)
|
||||
{
|
||||
static bool lockInitialized = false;
|
||||
if(!lockInitialized)
|
||||
{
|
||||
RecursiveLock_Init(&lock);
|
||||
lockInitialized = true;
|
||||
}
|
||||
|
||||
RecursiveLock_Lock(&lock);
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ void Draw_Unlock(void)
|
||||
|
||||
void Draw_DrawCharacter(u32 posX, u32 posY, u32 color, char character)
|
||||
{
|
||||
volatile u16 *const fb = (volatile u16 *const)FB_BOTTOM_VRAM_ADDR;
|
||||
u16 *const fb = (u16 *)FB_BOTTOM_VRAM_ADDR;
|
||||
|
||||
s32 y;
|
||||
for(y = 0; y < 10; y++)
|
||||
@@ -129,34 +129,78 @@ void Draw_ClearFramebuffer(void)
|
||||
Draw_FillFramebuffer(0);
|
||||
}
|
||||
|
||||
void Draw_SetupFramebuffer(void)
|
||||
u32 Draw_AllocateFramebufferCache(void)
|
||||
{
|
||||
// Try to see how much we can allocate...
|
||||
// Can't use fbs in FCRAM when Home Menu is active (AXI config related maybe?)
|
||||
u32 addr = 0x0D000000;
|
||||
u32 tmp;
|
||||
u32 minSize = (FB_BOTTOM_SIZE + 0xFFF) & ~0xFFF;
|
||||
u32 maxSize = (FB_SCREENSHOT_SIZE + 0xFFF) & ~0xFFF;
|
||||
u32 remaining = (u32)osGetMemRegionFree(MEMREGION_SYSTEM);
|
||||
u32 size = remaining < maxSize ? remaining : maxSize;
|
||||
|
||||
if (size < minSize || R_FAILED(svcControlMemoryEx(&tmp, addr, 0, size, MEMOP_ALLOC, MEMREGION_SYSTEM | MEMPERM_READ | MEMPERM_WRITE, true)))
|
||||
{
|
||||
framebufferCache = NULL;
|
||||
framebufferCacheSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
framebufferCache = (u32 *)addr;
|
||||
framebufferCacheSize = size;
|
||||
}
|
||||
|
||||
return framebufferCacheSize;
|
||||
}
|
||||
|
||||
void Draw_FreeFramebufferCache(void)
|
||||
{
|
||||
u32 tmp;
|
||||
svcControlMemory(&tmp, (u32)framebufferCache, 0, framebufferCacheSize, MEMOP_FREE, 0);
|
||||
framebufferCacheSize = 0;
|
||||
framebufferCache = NULL;
|
||||
}
|
||||
|
||||
void *Draw_GetFramebufferCache(void)
|
||||
{
|
||||
return framebufferCache;
|
||||
}
|
||||
|
||||
u32 Draw_GetFramebufferCacheSize(void)
|
||||
{
|
||||
return framebufferCacheSize;
|
||||
}
|
||||
|
||||
u32 Draw_SetupFramebuffer(void)
|
||||
{
|
||||
while((GPU_PSC0_CNT | GPU_PSC1_CNT | GPU_TRANSFER_CNT | GPU_CMDLIST_CNT) & 1);
|
||||
|
||||
svcFlushEntireDataCache();
|
||||
Draw_FlushFramebuffer();
|
||||
memcpy(framebufferCache, FB_BOTTOM_VRAM_ADDR, FB_BOTTOM_SIZE);
|
||||
Draw_ClearFramebuffer();
|
||||
Draw_FlushFramebuffer();
|
||||
gpuSavedFramebufferAddr1 = GPU_FB_BOTTOM_ADDR_1;
|
||||
gpuSavedFramebufferAddr2 = GPU_FB_BOTTOM_ADDR_2;
|
||||
gpuSavedFramebufferFormat = GPU_FB_BOTTOM_FMT;
|
||||
gpuSavedFramebufferStride = GPU_FB_BOTTOM_STRIDE;
|
||||
|
||||
GPU_FB_BOTTOM_ADDR_1 = GPU_FB_BOTTOM_ADDR_2 = FB_BOTTOM_VRAM_PA;
|
||||
GPU_FB_BOTTOM_FMT = (GPU_FB_BOTTOM_FMT & ~7) | 2;
|
||||
GPU_FB_BOTTOM_FMT = (GPU_FB_BOTTOM_FMT & ~7) | GSP_RGB565_OES;
|
||||
GPU_FB_BOTTOM_STRIDE = 240 * 2;
|
||||
|
||||
Draw_FlushFramebuffer();
|
||||
return framebufferCacheSize;
|
||||
}
|
||||
|
||||
void Draw_RestoreFramebuffer(void)
|
||||
{
|
||||
memcpy(FB_BOTTOM_VRAM_ADDR, framebufferCache, FB_BOTTOM_SIZE);
|
||||
Draw_FlushFramebuffer();
|
||||
|
||||
GPU_FB_BOTTOM_ADDR_1 = gpuSavedFramebufferAddr1;
|
||||
GPU_FB_BOTTOM_ADDR_2 = gpuSavedFramebufferAddr2;
|
||||
GPU_FB_BOTTOM_FMT = gpuSavedFramebufferFormat;
|
||||
GPU_FB_BOTTOM_STRIDE = gpuSavedFramebufferStride;
|
||||
|
||||
Draw_FlushFramebuffer();
|
||||
}
|
||||
|
||||
void Draw_FlushFramebuffer(void)
|
||||
@@ -203,7 +247,7 @@ void Draw_CreateBitmapHeader(u8 *dst, u32 width, u32 heigth)
|
||||
Draw_WriteUnaligned(dst + 0x22, 3 * width * heigth, 4);
|
||||
}
|
||||
|
||||
static inline void Draw_ConvertPixelToBGR8(u8 *dst, const u8 *src, GSPGPU_FramebufferFormats srcFormat)
|
||||
static inline void Draw_ConvertPixelToBGR8(u8 *dst, const u8 *src, GSPGPU_FramebufferFormat srcFormat)
|
||||
{
|
||||
u8 red, green, blue;
|
||||
switch(srcFormat)
|
||||
@@ -267,16 +311,37 @@ static inline void Draw_ConvertPixelToBGR8(u8 *dst, const u8 *src, GSPGPU_Frameb
|
||||
}
|
||||
}
|
||||
|
||||
void Draw_ConvertFrameBufferLine(u8 *line, bool top, bool left, u32 y)
|
||||
typedef struct FrameBufferConvertArgs {
|
||||
u8 *buf;
|
||||
u8 startingLine;
|
||||
u8 numLines;
|
||||
bool top;
|
||||
bool left;
|
||||
} FrameBufferConvertArgs;
|
||||
|
||||
static void Draw_ConvertFrameBufferLinesKernel(const FrameBufferConvertArgs *args)
|
||||
{
|
||||
GSPGPU_FramebufferFormats fmt = top ? (GSPGPU_FramebufferFormats)(GPU_FB_TOP_FMT & 7) : (GSPGPU_FramebufferFormats)(GPU_FB_BOTTOM_FMT & 7);
|
||||
u32 width = top ? 400 : 320;
|
||||
u8 formatSizes[] = { 4, 3, 2, 2, 2 };
|
||||
u32 stride = top ? GPU_FB_TOP_STRIDE : GPU_FB_BOTTOM_STRIDE;
|
||||
static const u8 formatSizes[] = { 4, 3, 2, 2, 2 };
|
||||
|
||||
u32 pa = Draw_GetCurrentFramebufferAddress(top, left);
|
||||
u8 *addr = (u8 *)PA_PTR(pa);
|
||||
GSPGPU_FramebufferFormat fmt = args->top ? (GSPGPU_FramebufferFormat)(GPU_FB_TOP_FMT & 7) : (GSPGPU_FramebufferFormat)(GPU_FB_BOTTOM_FMT & 7);
|
||||
u32 width = args->top ? 400 : 320;
|
||||
u32 stride = args->top ? GPU_FB_TOP_STRIDE : GPU_FB_BOTTOM_STRIDE;
|
||||
|
||||
for(u32 x = 0; x < width; x++)
|
||||
Draw_ConvertPixelToBGR8(line + x * 3 , addr + x * stride + y * formatSizes[(u8)fmt], fmt);
|
||||
u32 pa = Draw_GetCurrentFramebufferAddress(args->top, args->left);
|
||||
u8 *addr = (u8 *)KERNPA2VA(pa);
|
||||
|
||||
for (u32 y = args->startingLine; y < args->startingLine + args->numLines; y++)
|
||||
{
|
||||
for(u32 x = 0; x < width; x++)
|
||||
{
|
||||
__builtin_prefetch(addr + x * stride + y * formatSizes[fmt], 0, 3);
|
||||
Draw_ConvertPixelToBGR8(args->buf + (x + width * y) * 3 , addr + x * stride + y * formatSizes[fmt], fmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Draw_ConvertFrameBufferLines(u8 *buf, u32 startingLine, u32 numLines, bool top, bool left)
|
||||
{
|
||||
FrameBufferConvertArgs args = { buf, (u8)startingLine, (u8)numLines, top, left };
|
||||
svcCustomBackdoor(Draw_ConvertFrameBufferLinesKernel, &args);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -32,7 +32,19 @@
|
||||
#include "fmt.h"
|
||||
#include "ifile.h"
|
||||
|
||||
extern Handle preTerminationEvent;
|
||||
static MyThread errDispThread;
|
||||
static u8 ALIGN(8) errDispThreadStack[0xD00];
|
||||
|
||||
static char userString[0x100 + 1] = {0};
|
||||
static char staticBuf[0x100 + 1] = {0};
|
||||
|
||||
MyThread *errDispCreateThread(void)
|
||||
{
|
||||
if(R_FAILED(MyThread_Create(&errDispThread, errDispThreadMain, errDispThreadStack, 0xD00, 55, CORE_SYSTEM)))
|
||||
svcBreak(USERBREAK_PANIC);
|
||||
return &errDispThread;
|
||||
}
|
||||
|
||||
static inline u32 ERRF_DisplayRegisterValue(u32 posX, u32 posY, const char *name, u32 value)
|
||||
{
|
||||
@@ -44,6 +56,11 @@ static inline int ERRF_FormatRegisterValue(char *out, const char *name, u32 valu
|
||||
return sprintf(out, "%-9s %08lx", name, value);
|
||||
}
|
||||
|
||||
static inline void ERRF_GetErrInfo(ERRF_FatalErrInfo* info, u32* in, u32 size)
|
||||
{
|
||||
memcpy(info, in, size);
|
||||
}
|
||||
|
||||
static int ERRF_FormatError(char *out, ERRF_FatalErrInfo *info)
|
||||
{
|
||||
char *outStart = out;
|
||||
@@ -148,7 +165,7 @@ static int ERRF_FormatError(char *out, ERRF_FatalErrInfo *info)
|
||||
desc = "The System Memory has been damaged.";
|
||||
break;
|
||||
case ERRF_ERRTYPE_FAILURE:
|
||||
info->data.failure_mesg[0x60] = 0; // make sure the last byte in the IPC buffer is NULL
|
||||
info->data.failure_mesg[0x5F] = 0; // make sure the last byte in the IPC buffer is NULL
|
||||
desc = info->data.failure_mesg;
|
||||
break;
|
||||
default:
|
||||
@@ -219,18 +236,18 @@ static Result ERRF_SaveErrorToFile(ERRF_FatalErrInfo *info)
|
||||
return res;
|
||||
}
|
||||
|
||||
void ERRF_HandleCommands(void *ctx)
|
||||
void ERRF_HandleCommands(void)
|
||||
{
|
||||
(void)ctx;
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
ERRF_FatalErrInfo info;
|
||||
|
||||
switch(cmdbuf[0] >> 16)
|
||||
{
|
||||
case 1: // Throw
|
||||
{
|
||||
ERRF_FatalErrInfo *info = (ERRF_FatalErrInfo *)(cmdbuf + 1);
|
||||
ERRF_SaveErrorToFile(info);
|
||||
if(info->type != ERRF_ERRTYPE_LOGGED || info->procId == 0)
|
||||
ERRF_GetErrInfo(&info, (cmdbuf + 1), sizeof(ERRF_FatalErrInfo));
|
||||
ERRF_SaveErrorToFile(&info);
|
||||
if(!menuShouldExit && (info.type != ERRF_ERRTYPE_LOGGED || info.procId == 0))
|
||||
{
|
||||
menuEnter();
|
||||
|
||||
@@ -238,7 +255,7 @@ void ERRF_HandleCommands(void *ctx)
|
||||
Draw_ClearFramebuffer();
|
||||
Draw_FlushFramebuffer();
|
||||
|
||||
ERRF_DisplayError(info);
|
||||
ERRF_DisplayError(&info);
|
||||
|
||||
/*
|
||||
If we ever wanted to return:
|
||||
@@ -252,26 +269,98 @@ void ERRF_HandleCommands(void *ctx)
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
cmdbuf[0] = 0x10040;
|
||||
cmdbuf[0] = IPC_MakeHeader(1, 1, 0);
|
||||
cmdbuf[1] = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
case 2: // SetUserString
|
||||
{
|
||||
if(cmdbuf[0] != 0x20042 || (cmdbuf[2] & 0x3C0F) != 2)
|
||||
if(cmdbuf[0] != IPC_MakeHeader(2, 1, 2) || (cmdbuf[2] & 0x3C0F) != 2)
|
||||
{
|
||||
cmdbuf[0] = 0x40;
|
||||
cmdbuf[0] = IPC_MakeHeader(0, 1, 0);
|
||||
cmdbuf[1] = 0xD9001830;
|
||||
}
|
||||
else
|
||||
{
|
||||
cmdbuf[0] = 0x20040;
|
||||
u32 sz = cmdbuf[1] <= 0x100 ? sz : 0x100;
|
||||
u32 sz = cmdbuf[1] <= 0x100 ? cmdbuf[1] : 0x100;
|
||||
memcpy(userString, cmdbuf + 3, sz);
|
||||
userString[sz] = 0;
|
||||
|
||||
cmdbuf[0] = IPC_MakeHeader(2, 1, 0);
|
||||
cmdbuf[1] = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void errDispThreadMain(void)
|
||||
{
|
||||
Handle handles[3];
|
||||
Handle serverHandle, clientHandle, sessionHandle = 0;
|
||||
|
||||
u32 replyTarget = 0;
|
||||
s32 index;
|
||||
|
||||
Result res;
|
||||
u32 *cmdbuf = getThreadCommandBuffer();
|
||||
u32 *sbuf = getThreadStaticBuffers();
|
||||
|
||||
sbuf[0] = IPC_Desc_StaticBuffer(0x100, 0);
|
||||
sbuf[1] = (u32)staticBuf;
|
||||
|
||||
assertSuccess(svcCreatePort(&serverHandle, &clientHandle, "err:f", 1));
|
||||
|
||||
do
|
||||
{
|
||||
handles[0] = preTerminationEvent;
|
||||
handles[1] = serverHandle;
|
||||
handles[2] = sessionHandle;
|
||||
|
||||
if(replyTarget == 0) // k11
|
||||
cmdbuf[0] = 0xFFFF0000;
|
||||
res = svcReplyAndReceive(&index, handles, 1 + (sessionHandle == 0 ? 1 : 2), replyTarget);
|
||||
|
||||
if(R_FAILED(res))
|
||||
{
|
||||
if((u32)res == 0xC920181A) // session closed by remote
|
||||
{
|
||||
svcCloseHandle(sessionHandle);
|
||||
sessionHandle = 0;
|
||||
replyTarget = 0;
|
||||
}
|
||||
|
||||
else
|
||||
svcBreak(USERBREAK_PANIC);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (index == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if(index == 1)
|
||||
{
|
||||
Handle session;
|
||||
assertSuccess(svcAcceptSession(&session, serverHandle));
|
||||
|
||||
if(sessionHandle == 0)
|
||||
sessionHandle = session;
|
||||
else
|
||||
svcCloseHandle(session);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERRF_HandleCommands();
|
||||
replyTarget = sessionHandle;
|
||||
}
|
||||
}
|
||||
}
|
||||
while(!preTerminationRequested);
|
||||
|
||||
svcCloseHandle(sessionHandle);
|
||||
svcCloseHandle(clientHandle);
|
||||
svcCloseHandle(serverHandle);
|
||||
}
|
||||
|
||||
@@ -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,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* This file is part of Luma3DS.
|
||||
* Copyright (C) 2016-2019 Aurora Wright, TuxSH
|
||||
* Copyright (C) 2016-2020 Aurora Wright, TuxSH
|
||||
*
|
||||
* SPDX-License-Identifier: (MIT OR GPL-2.0-or-later)
|
||||
*/
|
||||
@@ -9,15 +9,15 @@
|
||||
#include "gdb/net.h"
|
||||
#include "gdb/debug.h"
|
||||
|
||||
extern Handle terminationRequestEvent;
|
||||
extern bool terminationRequest;
|
||||
extern Handle preTerminationEvent;
|
||||
extern bool preTerminationRequested;
|
||||
|
||||
void GDB_RunMonitor(GDBServer *server)
|
||||
{
|
||||
Handle handles[3 + MAX_DEBUG];
|
||||
Result r = 0;
|
||||
|
||||
handles[0] = terminationRequestEvent;
|
||||
handles[0] = preTerminationEvent;
|
||||
handles[1] = server->super.shall_terminate_event;
|
||||
handles[2] = server->statusUpdated;
|
||||
|
||||
@@ -81,5 +81,5 @@ void GDB_RunMonitor(GDBServer *server)
|
||||
RecursiveLock_Unlock(&ctx->lock);
|
||||
}
|
||||
}
|
||||
while(!terminationRequest && server->super.running);
|
||||
while(!preTerminationRequested && server->super.running);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user