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:
Lorenzo Dellacà
2020-07-04 02:43:27 +02:00
266 changed files with 3161 additions and 1525 deletions

View File

@@ -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

View File

@@ -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

View 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);
}
}

View 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

View 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

View File

@@ -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;
}

View File

@@ -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[] = {

View File

@@ -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)

View File

@@ -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);

View File

@@ -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

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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.

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}
}

View File

@@ -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);

View File

@@ -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
}

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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)

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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;

View File

@@ -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.

View File

@@ -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

View File

@@ -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

View File

@@ -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).
*/

View File

@@ -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).
*/

View File

@@ -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).
*/

View File

@@ -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).
*/

View File

@@ -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).
*/

View File

@@ -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));

View File

@@ -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).
*/

View File

@@ -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).
*/

View File

@@ -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).
*/

View File

@@ -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).
*/

View File

@@ -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)
#---------------------------------------------------------------------------------

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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

View File

@@ -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)

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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);

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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);

View File

@@ -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));

View File

@@ -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

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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)
*/

View File

@@ -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