Compare commits

..

22 Commits

Author SHA1 Message Date
Michael Scire
8274081e39 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "b1607dc8a"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "b1607dc8a"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2023-03-13 17:17:50 -07:00
Michael Scire
f1ad26ce84 ams: bump version 2023-03-13 17:16:51 -07:00
Michael Scire
e4c314146e docs: update changelog 2023-03-13 17:16:33 -07:00
Michael Scire
52f00731d9 settings: add os guard 2023-03-12 22:34:23 -07:00
Michael Scire
476d658a79 ams: allow convertible-to-result in abort print macros 2023-03-11 15:14:33 -07:00
Michael Scire
7263022bac docs: mention bluetooth db feature 2023-03-10 10:24:19 -07:00
Michael Scire
e0e7aa1e2f set.mitm: misc style fixes for bluetooth db 2023-03-10 10:19:58 -07:00
ndeadly
bd9d8fff46 Add system setting to mirror bluetooth pairing database to sd card (#1787)
* ams_mitm: add ability to mirror bluetooth device pairing database to sd card via a system setting

* ams_mitm: address requested stylistic changes

* ams_mitm: make use of R_SUCCEED macro

* ams_mitm: use settings::BluetoothDevicesSettings instead of libnx type

* ams_mitm: fix logic error when truncating pairing database on read

* Update .ini comment

* ams_mitm: missing R_TRY around call to fs::FlushFile

* stratosphere: remove union from BluetoothDevicesSettings type

---------

Co-authored-by: ndeadly <24677491+ndeadly@users.noreply.github.com>
2023-03-10 10:06:38 -07:00
Michael Scire
61e3f0b391 windows: disable -fdata-sections
This causes all data to be emitted as .data$*. This breaks fzero-initialized-in-bss,
because linker puts stuff in .data even when it's all-zero and should end up in .bss.
2023-03-09 23:46:54 -07:00
Michael Scire
cd9b173318 windows: re-enable lto for os/fs libraries 2023-03-09 23:46:31 -07:00
Michael Scire
a8df400825 kern: fix stray addressof operator 2023-03-08 09:46:38 -07:00
Michael Scire
68040e2922 windows: add brave new mingw compat hook for gcc 12.2.0+ 2023-03-07 22:07:03 -07:00
Michael Scire
8da4d14e15 kern: minor cleanup (thanks @liamwhite) 2023-03-06 21:18:00 -07:00
Michael Scire
e2ebf9c0ff fatal: correct comment about pools 2023-03-01 03:21:51 -07:00
Michael Scire
5fb6f52b9e fatal: dynamically allocate memory as required (preferring system > nonsecure > unsafe) 2023-03-01 03:20:49 -07:00
Michael Scire
982389dceb os: add UnsafeMemory apis 2023-03-01 03:20:49 -07:00
Adubbz
f636596ee2 daybreak: scale title font size
(cherry picked from commit 035b37c615183bd387210a54d269346e3a9b379a)
2023-02-25 10:53:16 +11:00
Michael Scire
0a2440522f fatal: use a hack to be kinder wrt pl:u session limit 2023-02-23 22:06:49 -07:00
Michael Scire
3292ea5970 kern: fix stray comment copy/paste error 2023-02-23 22:00:00 -07:00
Michael Scire
33d42f4831 erpt: update server code for 16.0.0 logic changes 2023-02-23 21:51:51 -07:00
Michael Scire
46094cfb3e kern: increase non-dynamic heap sizes to 8 GB to match 2023-02-23 19:05:52 -07:00
Michael Scire
618691a500 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "af0d00890"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "af0d00890"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2023-02-23 09:01:41 -07:00
35 changed files with 531 additions and 81 deletions

View File

@@ -67,6 +67,10 @@
; Note that this setting is ignored (and treated as 1) when htc is enabled.
; 0 = Disabled, 1 = Enabled
; enable_log_manager = u8!0x0
; Controls whether the bluetooth pairing database is redirected to the SD card (shared across sysmmc/all emummcs)
; NOTE: On <13.0.0, the database size was 10 instead of 20; booting pre-13.0.0 will truncate the database.
; 0 = Disabled, 1 = Enabled
; enable_external_bluetooth_db = u8!0x0
[hbloader]
; Controls the size of the homebrew heap when running as applet.
; If set to zero, all available applet memory is used as heap.

View File

@@ -1,4 +1,16 @@
# Changelog
## 1.5.1
+ `fatal` was updated to reduce memory footprint.
+ Starting in 16.0.0, official `fatal` has no framebuffer or rendering logic, and instead calls other system service commands to draw the screen.
+ However, these commands aren't usable by atmosphère (too small rendering window, bad color support).
+ To reduce the relative memory footprint differential between atmosphère and official code, the framebuffer (2 MB) is now dynamically allocated when needed.
+ This will try to allocate from multiple pools (preferring System > System_NonSecure > Application).
+ This technically requires that 2 MB be available in at least one of these pools for the fatal screen to render (otherwise, a reboot-to-black-and-white-fatal will occur), but this should be a non-issue in almost all cases.
+ A feature was added to optionally mirror the bluetooth pairing database to the SD card (thanks @ndeadly).
+ This allows device pairings to be automatically kept in-sync across sysmmc/all emummcs.
+ This is opt-in, and can be controlled by setting `atmosphere!enable_external_bluetooth_db = u8!0x1`.
+ When enabled, the pairing database will be synchronized to `/atmosphere/bluetooth_devices.db`.
+ General system stability improvements to enhance the user's experience.
## 1.5.0
+ Support was added for 16.0.0
+ `mesosphère` was updated to reflect the latest official kernel behavior.

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = b7711b8fbcec5013e1738218267d69b2cb44f85e
parent = 590f22933db38f089ab2224f7fd86658a9533e8d
commit = b1607dc8a3d85bc8c859c60d70ebb4a3dcbb85b8
parent = f1ad26ce844ab7a63b948281b50c12e5d1dac8ce
method = merge
cmdver = 0.4.1

View File

@@ -1,5 +1,5 @@
export ATMOSPHERE_DEFINES += -DATMOSPHERE_OS_WINDOWS
export ATMOSPHERE_SETTINGS += -fno-omit-frame-pointer
export ATMOSPHERE_SETTINGS += -fno-omit-frame-pointer -fno-data-sections
export ATMOSPHERE_CFLAGS +=
export ATMOSPHERE_CXXFLAGS +=
export ATMOSPHERE_ASFLAGS +=

View File

@@ -58,7 +58,7 @@ export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \
-Wl,--wrap,exit
else ifeq ($(ATMOSPHERE_BOARD),generic_windows)
export CXXREQUIRED :=
export CXXWRAPS := -Wl,--wrap,__p__acmdln
export CXXWRAPS := -Wl,--wrap,__p__acmdln -Wl,--wrap,_set_invalid_parameter_handler
else
export CXXREQUIRED :=
export CXXWRAPS :=

View File

@@ -48,7 +48,7 @@ namespace ams::kern {
/* Check that the object is closed. */
R_UNLESS(derived->IsServerClosed(), svc::ResultInvalidState());
return Delete(obj.GetPointerUnsafe(), name);
R_RETURN(Delete(obj.GetPointerUnsafe(), name));
}
template<typename Derived> requires std::derived_from<Derived, KAutoObject>

View File

@@ -234,11 +234,11 @@ namespace ams::kern {
KPriorityQueueImpl m_scheduled_queue;
KPriorityQueueImpl m_suggested_queue;
private:
constexpr ALWAYS_INLINE void ClearAffinityBit(u64 &affinity, s32 core) {
static constexpr ALWAYS_INLINE void ClearAffinityBit(u64 &affinity, s32 core) {
affinity &= ~(UINT64_C(1) << core);
}
constexpr ALWAYS_INLINE s32 GetNextCore(u64 &affinity) {
static constexpr ALWAYS_INLINE s32 GetNextCore(u64 &affinity) {
const s32 core = __builtin_ctzll(static_cast<unsigned long long>(affinity));
ClearAffinityBit(affinity, core);
return core;

View File

@@ -214,7 +214,7 @@ namespace ams::kern {
template<typename T> requires (std::same_as<T, KThread> || std::same_as<T, RedBlackKeyType>)
static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KThread &rhs) {
if (lhs.GetPriority() < rhs.GetPriority()) {
/* And then by priority. */
/* Sort by priority. */
return -1;
} else {
return 1;

View File

@@ -51,7 +51,7 @@ namespace ams::kern {
/* Sleep the thread. */
{
KScopedSchedulerLockAndSleep lk(&timer, owner, timeout);
KScopedSchedulerLockAndSleep lk(std::addressof(timer), owner, timeout);
if (!allow_terminating_thread && owner->IsTerminationRequested()) {
lk.CancelSleep();

View File

@@ -29,6 +29,7 @@
#include <stratosphere/os/os_process_memory_api.hpp>
#include <stratosphere/os/os_process_code_memory_api.hpp>
#include <stratosphere/os/os_insecure_memory_api.hpp>
#include <stratosphere/os/os_unsafe_memory_api.hpp>
#include <stratosphere/os/os_random.hpp>
#include <stratosphere/os/os_mutex.hpp>
#include <stratosphere/os/os_condition_variable.hpp>

View File

@@ -0,0 +1,25 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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/>.
*/
#pragma once
#include <stratosphere/os/os_memory_common.hpp>
namespace ams::os {
Result AllocateUnsafeMemory(uintptr_t *out_address, size_t size);
Result FreeUnsafeMemory(uintptr_t address, size_t size);
}

View File

@@ -235,4 +235,31 @@ namespace ams::settings {
return !(lhs <= rhs);
}
struct BluetoothDevicesSettings : public sf::LargeData {
u8 address[0x6];
char name[0x20];
u8 class_of_device[0x3];
u8 link_key[0x10];
u8 link_key_present;
u16 version;
u32 trusted_services;
u16 vid;
u16 pid;
u8 sub_class;
u8 attribute_mask;
u16 descriptor_length;
u8 descriptor[0x80];
u8 key_type;
u8 device_type;
u16 brr_size;
u8 brr[0x9];
u8 reserved0;
char name2[0xF9];
u8 reserved1[0x31];
};
#if defined(ATMOSPHERE_OS_HORIZON)
static_assert(sizeof(BluetoothDevicesSettings) == sizeof(::SetSysBluetoothDevicesSettings));
#endif
}

View File

@@ -154,10 +154,12 @@ spl_secure_monitor_api.os.generic.o: CXXFLAGS += -I$(ATMOSPHERE_LIBRARIES_DIR)/l
fs_id_string_impl.os.generic.o: CXXFLAGS += -I$(ATMOSPHERE_LIBRARIES_DIR)/libexosphere/include
ifeq ($(ATMOSPHERE_OS_NAME),windows)
os_%.o: CXXFLAGS += -fno-lto
fssystem_%.o: CXXFLAGS += -fno-lto
fssrv_%.o: CXXFLAGS += -fno-lto
fs_%.o: CXXFLAGS += -fno-lto
# I do not remember why these had fno-lto, but it appears to
# work without no-lto (2023/03/09), so I am disabling these. I may regret this later.
#os_%.o: CXXFLAGS += -fno-lto
#fssystem_%.o: CXXFLAGS += -fno-lto
#fssrv_%.o: CXXFLAGS += -fno-lto
#fs_%.o: CXXFLAGS += -fno-lto
endif
#---------------------------------------------------------------------------------

View File

@@ -16,6 +16,7 @@
#include <stratosphere.hpp>
extern "C" char **__real___p__acmdln(void);
extern "C" _invalid_parameter_handler __real__set_invalid_parameter_handler(_invalid_parameter_handler);
namespace ams {
@@ -65,4 +66,11 @@ extern "C" {
return __real___p__acmdln();
}
/* On some mingw gcc versions, acmdln isn't used, so we need to hook a different part of crt init. */
_invalid_parameter_handler __wrap__set_invalid_parameter_handler(_invalid_parameter_handler handler) {
::ams::os::Initialize();
return __real__set_invalid_parameter_handler(handler);
}
}

View File

@@ -29,7 +29,7 @@ namespace ams::erpt::srv {
}
Context::Context(CategoryId cat, u32 max_records) : m_category(cat), m_max_record_count(max_records), m_record_count(0) {
Context::Context(CategoryId cat) : m_category(cat) {
g_category_list.push_front(*this);
}
@@ -38,12 +38,11 @@ namespace ams::erpt::srv {
}
Result Context::AddCategoryToReport(Report *report) {
R_SUCCEED_IF(m_record_list.empty());
for (auto it = m_record_list.begin(); it != m_record_list.end(); it++) {
for (u32 i = 0; i < it->m_ctx.field_count; i++) {
auto *field = std::addressof(it->m_ctx.fields[i]);
u8 *arr_buf = it->m_ctx.array_buffer;
if (m_record != nullptr) {
const auto *entry = m_record->GetContextEntryPtr();
for (u32 i = 0; i < entry->field_count; i++) {
auto *field = std::addressof(entry->fields[i]);
u8 *arr_buf = entry->array_buffer;
switch (field->type) {
case FieldType_Bool: R_TRY(Cipher::AddField(report, field->id, field->value_bool)); break;
@@ -70,46 +69,23 @@ namespace ams::erpt::srv {
R_SUCCEED();
}
Result Context::AddContextToCategory(const ContextEntry *entry, const u8 *data, u32 data_size) {
Result Context::SubmitContext(const ContextEntry *entry, const u8 *data, u32 data_size) {
auto record = std::make_unique<ContextRecord>();
R_UNLESS(record != nullptr, erpt::ResultOutOfMemory());
R_TRY(record->Initialize(entry, data, data_size));
this->AddContextRecordToCategory(std::move(record));
R_SUCCEED();
}
Result Context::AddContextRecordToCategory(std::unique_ptr<ContextRecord> record) {
if (m_record_count < m_max_record_count) {
m_record_list.push_front(*record.release());
m_record_count++;
} else {
ContextRecord *back = std::addressof(m_record_list.back());
m_record_list.pop_back();
m_record_list.push_front(*record.release());
delete back;
}
R_SUCCEED();
}
Result Context::SubmitContext(const ContextEntry *entry, const u8 *data, u32 data_size) {
auto it = util::range::find_if(g_category_list, [&](const Context &cur) {
return cur.m_category == entry->category;
});
R_UNLESS(it != g_category_list.end(), erpt::ResultCategoryNotFound());
R_RETURN(it->AddContextToCategory(entry, data, data_size));
R_RETURN(SubmitContextRecord(std::move(record)));
}
Result Context::SubmitContextRecord(std::unique_ptr<ContextRecord> record) {
auto it = util::range::find_if(g_category_list, [&](const Context &cur) {
return cur.m_category == record->m_ctx.category;
return cur.m_category == record->GetContextEntryPtr()->category;
});
R_UNLESS(it != g_category_list.end(), erpt::ResultCategoryNotFound());
R_RETURN(it->AddContextRecordToCategory(std::move(record)));
it->m_record = std::move(record);
R_SUCCEED();
}
Result Context::WriteContextsToReport(Report *report) {

View File

@@ -26,16 +26,12 @@ namespace ams::erpt::srv {
class Context : public Allocator, public util::IntrusiveListBaseNode<Context> {
private:
const CategoryId m_category;
const u32 m_max_record_count;
u32 m_record_count;
util::IntrusiveListBaseTraits<ContextRecord>::ListType m_record_list;
std::unique_ptr<ContextRecord> m_record;
public:
Context(CategoryId cat, u32 max_records);
Context(CategoryId cat);
~Context();
Result AddCategoryToReport(Report *report);
Result AddContextToCategory(const ContextEntry *entry, const u8 *data, u32 data_size);
Result AddContextRecordToCategory(std::unique_ptr<ContextRecord> record);
public:
static Result SubmitContext(const ContextEntry *entry, const u8 *data, u32 data_size);
static Result SubmitContextRecord(std::unique_ptr<ContextRecord> record);

View File

@@ -21,8 +21,7 @@ namespace ams::erpt::srv {
class Context;
class ContextRecord : public Allocator, public util::IntrusiveListBaseNode<ContextRecord> {
friend class Context;
class ContextRecord : public Allocator {
private:
static u32 s_record_count;
public:

View File

@@ -106,7 +106,7 @@ namespace ams::erpt::srv {
g_sf_allocator.Attach(g_heap_handle);
for (auto i = 0; i < CategoryId_Count; i++) {
Context *ctx = new Context(static_cast<CategoryId>(i), 1);
Context *ctx = new Context(static_cast<CategoryId>(i));
AMS_ABORT_UNLESS(ctx != nullptr);
}

View File

@@ -24,6 +24,7 @@ namespace ams::os::impl {
R_RETURN(impl::GetAslrSpaceManager().MapAtRandomAddress(out_address,
[](uintptr_t map_address, size_t map_size) -> Result {
R_TRY_CATCH(svc::MapInsecureMemory(map_address, map_size)) {
R_CONVERT(svc::ResultOutOfMemory, os::ResultOutOfMemory())
R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultInvalidCurrentMemoryState())
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;

View File

@@ -0,0 +1,27 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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/>.
*/
#pragma once
#include <stratosphere.hpp>
namespace ams::os::impl {
class UnsafeMemoryImpl {
public:
static Result AllocateUnsafeMemoryImpl(uintptr_t *out_address, size_t size);
static Result FreeUnsafeMemoryImpl(uintptr_t address, size_t size);
};
}

View File

@@ -0,0 +1,54 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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/>.
*/
#include <stratosphere.hpp>
#include "os_unsafe_memory_impl.hpp"
#include "os_aslr_space_manager.hpp"
namespace ams::os::impl {
Result UnsafeMemoryImpl::AllocateUnsafeMemoryImpl(uintptr_t *out_address, size_t size) {
/* Map at a random address. */
R_RETURN(impl::GetAslrSpaceManager().MapAtRandomAddress(out_address,
[](uintptr_t map_address, size_t map_size) -> Result {
R_TRY_CATCH(svc::MapPhysicalMemoryUnsafe(map_address, map_size)) {
R_CONVERT(svc::ResultOutOfResource, os::ResultOutOfResource())
R_CONVERT(svc::ResultOutOfMemory, os::ResultOutOfMemory())
R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultInvalidCurrentMemoryState())
R_CONVERT(svc::ResultLimitReached, os::ResultOutOfMemory())
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
R_SUCCEED();
},
[](uintptr_t map_address, size_t map_size) -> void {
R_ABORT_UNLESS(UnsafeMemoryImpl::FreeUnsafeMemoryImpl(map_address, map_size));
},
size,
0
));
}
Result UnsafeMemoryImpl::FreeUnsafeMemoryImpl(uintptr_t address, size_t size) {
R_TRY_CATCH(svc::UnmapPhysicalMemoryUnsafe(address, size)) {
R_CONVERT(svc::ResultOutOfResource, os::ResultOutOfResource())
R_CONVERT(svc::ResultOutOfMemory, os::ResultOutOfResource())
R_CONVERT(svc::ResultInvalidCurrentMemory, os::ResultBusy())
R_CONVERT(svc::ResultInvalidMemoryRegion, os::ResultInvalidParameter())
} R_END_TRY_CATCH_WITH_ABORT_UNLESS;
R_SUCCEED();
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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/>.
*/
#include <stratosphere.hpp>
#include "impl/os_unsafe_memory_impl.hpp"
namespace ams::os {
Result AllocateUnsafeMemory(uintptr_t *out_address, size_t size) {
/* Check arguments. */
AMS_ASSERT(size > 0);
AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize));
/* Allocate memory. */
R_RETURN(impl::UnsafeMemoryImpl::AllocateUnsafeMemoryImpl(out_address, size));
}
Result FreeUnsafeMemory(uintptr_t address, size_t size) {
/* Check arguments. */
AMS_ASSERT(util::IsAligned(address, os::MemoryPageSize));
AMS_ASSERT(util::IsAligned(size, os::MemoryPageSize));
/* Free memory. */
R_RETURN(impl::UnsafeMemoryImpl::FreeUnsafeMemoryImpl(address, size));
}
}

View File

@@ -17,7 +17,7 @@
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 1
#define ATMOSPHERE_RELEASE_VERSION_MINOR 5
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0
#define ATMOSPHERE_RELEASE_VERSION_MICRO 1
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO

View File

@@ -457,10 +457,10 @@ namespace ams::result::impl {
#define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) do { ::ams::diag::impl::FatalErrorByResultForNx(val); AMS_INFINITE_LOOP(); AMS_ASSUME(false); } while (false)
#elif defined(ATMOSPHERE_OS_HORIZON)
#define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) AMS_CALL_ASSERT_FAIL_IMPL(::ams::diag::AssertionType_Assert, "ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32, cond, val.GetModule(), val.GetDescription(), static_cast<::ams::Result>(val).GetInnerValue())
#define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) AMS_CALL_ABORT_IMPL("ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32, cond, val.GetModule(), val.GetDescription(), static_cast<::ams::Result>(val).GetInnerValue())
#define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) AMS_CALL_ABORT_IMPL("ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32, cond, static_cast<::ams::Result>(val).GetModule(), static_cast<::ams::Result>(val).GetDescription(), static_cast<::ams::Result>(val).GetInnerValue())
#else
#define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) AMS_CALL_ASSERT_FAIL_IMPL(::ams::diag::AssertionType_Assert, "ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32 "\n Name: %s", cond, val.GetModule(), val.GetDescription(), static_cast<::ams::Result>(val).GetInnerValue(), ::ams::GetResultName(val))
#define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) AMS_CALL_ABORT_IMPL("ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32 "\n Name: %s", cond, val.GetModule(), val.GetDescription(), static_cast<::ams::Result>(val).GetInnerValue(), ::ams::GetResultName(val))
#define AMS_CALL_ON_RESULT_ASSERTION_IMPL(cond, val) AMS_CALL_ASSERT_FAIL_IMPL(::ams::diag::AssertionType_Assert, "ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32 "\n Name: %s", cond, val.GetModule(), val.GetDescription(), static_cast<::ams::Result>(val).GetInnerValue(), ::ams::GetResultName(static_cast<::ams::Result>(val)))
#define AMS_CALL_ON_RESULT_ABORT_IMPL(cond, val) AMS_CALL_ABORT_IMPL("ams::Result::IsSuccess()", "Failed: %s\n Module: %d\n Description: %d\n InnerValue: 0x%08" PRIX32 "\n Name: %s", cond, static_cast<::ams::Result>(val).GetModule(), static_cast<::ams::Result>(val).GetDescription(), static_cast<::ams::Result>(val).GetInnerValue(), ::ams::GetResultName(static_cast<::ams::Result>(val)))
#endif
/// Evaluates an expression that returns a result, and asserts the result if it would fail.

View File

@@ -27,11 +27,11 @@ namespace ams::svc {
constexpr inline size_t AddressMemoryRegionSmall36Size = 2_GB;
constexpr inline size_t AddressMemoryRegionLarge36Size = 64_GB - AddressMemoryRegionSmall36Size;
constexpr inline size_t AddressMemoryRegionHeap36Size = 6_GB;
constexpr inline size_t AddressMemoryRegionHeap36Size = 8_GB;
constexpr inline size_t AddressMemoryRegionAlias36Size = 6_GB;
constexpr inline size_t AddressMemoryRegionSmall39Size = 64_GB;
constexpr inline size_t AddressMemoryRegionHeap39Size = 6_GB;
constexpr inline size_t AddressMemoryRegionHeap39Size = 8_GB;
constexpr inline size_t AddressMemoryRegionAlias39Size = 64_GB;
constexpr inline size_t AddressMemoryRegionStack39Size = 2_GB;

View File

@@ -29,7 +29,6 @@ _ZN3ams4kern10KScheduler12ScheduleImplEv:
mov x1, x0
/* First, clear the need's scheduling bool (and dmb ish after, as it's an atomic). */
/* TODO: Should this be a stlrb? Nintendo does not do one. */
strb wzr, [x1]
dmb ish

View File

@@ -16,6 +16,7 @@
#include <stratosphere.hpp>
#include "setsys_mitm_service.hpp"
#include "settings_sd_kvs.hpp"
#include "setsys_shim.h"
namespace ams::mitm::settings {
@@ -23,6 +24,8 @@ namespace ams::mitm::settings {
namespace {
constexpr const char ExternalBluetoothDatabasePath[] = "@Sdcard:/atmosphere/bluetooth_devices.db";
constinit os::SdkMutex g_firmware_version_lock;
constinit bool g_cached_firmware_version;
constinit settings::FirmwareVersion g_firmware_version;
@@ -77,7 +80,7 @@ namespace ams::mitm::settings {
CacheFirmwareVersion();
/* We want to give a special firmware version to the home menu title, and nothing else. */
/* This means Qlaunch + Maintenance Menu, and nothing else. */
/* This means qlaunch + maintenance menu, and nothing else. */
if (client_info.program_id == ncm::SystemAppletId::Qlaunch || client_info.program_id == ncm::SystemAppletId::MaintenanceMenu) {
*out = g_ams_firmware_version;
} else {
@@ -87,6 +90,99 @@ namespace ams::mitm::settings {
R_SUCCEED();
}
bool IsExternalBluetoothDatabaseEnabled() {
u8 en = 0;
settings::fwdbg::GetSettingsItemValue(std::addressof(en), sizeof(en), "atmosphere", "enable_external_bluetooth_db");
return en;
}
bool HasExternalBluetoothDatabase() {
bool file_exists;
R_ABORT_UNLESS(fs::HasFile(std::addressof(file_exists), ExternalBluetoothDatabasePath));
return file_exists;
}
Result ReadExternalBluetoothDatabase(s32 *entries_read, settings::BluetoothDevicesSettings *db, size_t db_max_size) {
/* Open the external database file. */
fs::FileHandle file;
R_TRY(fs::OpenFile(std::addressof(file), ExternalBluetoothDatabasePath, fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Read the number of database entries stored in external database. */
u64 total_entries;
R_TRY(fs::ReadFile(file, 0, std::addressof(total_entries), sizeof(total_entries)));
u64 db_offset = sizeof(total_entries);
if (total_entries > db_max_size) {
/* Pairings are stored from least to most recent. Add offset to skip the older entries that won't fit. */
db_offset += (total_entries - db_max_size) * sizeof(settings::BluetoothDevicesSettings);
/* Cap number of database entries read to size of database on this firmware. */
total_entries = db_max_size;
}
/* Read database entries. */
R_TRY(fs::ReadFile(file, db_offset, db, total_entries * sizeof(settings::BluetoothDevicesSettings)));
/* Convert entries to the old format if running on a firmware below 13.0.0. */
if (hos::GetVersion() < hos::Version_13_0_0) {
for (size_t i = 0; i < total_entries; ++i) {
/* Copy the newer name field to the older one. */
util::TSNPrintf(db[i].name, sizeof(db[i].name), "%s", db[i].name2);
/* Clear the newer name field. */
std::memset(db[i].name2, 0, sizeof(db[i].name2));
}
}
/* Set the output. */
*entries_read = static_cast<s32>(total_entries);
R_SUCCEED();
}
Result StoreExternalBluetoothDatabase(const settings::BluetoothDevicesSettings *db, u64 total_entries) {
/* Open the external database file. */
fs::FileHandle file;
R_TRY(fs::OpenFile(std::addressof(file), ExternalBluetoothDatabasePath, fs::OpenMode_Write));
ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Ensure the file is the appropriate size for the number of entries. */
R_TRY(fs::SetFileSize(file, sizeof(total_entries) + total_entries * sizeof(settings::BluetoothDevicesSettings)));
/* Write the number of database entries. */
R_TRY(fs::WriteFile(file, 0, std::addressof(total_entries), sizeof(total_entries), fs::WriteOption::None));
/* Write the database entries. */
u64 db_offset = sizeof(total_entries);
if (hos::GetVersion() < hos::Version_13_0_0) {
/* Convert entries to the new format if running on a firmware below 13.0.0. */
for (size_t i = 0; i < total_entries; ++i) {
/* Make a copy of the current database entry. */
settings::BluetoothDevicesSettings tmp = db[i];
/* Copy the older name field to the newer one. */
util::TSNPrintf(tmp.name2, sizeof(tmp.name2), "%s", tmp.name);
/* Clear the original name field. */
std::memset(tmp.name, 0, sizeof(tmp.name));
/* Write the converted database entry. */
R_TRY(fs::WriteFile(file, db_offset, std::addressof(tmp), sizeof(settings::BluetoothDevicesSettings), fs::WriteOption::None));
/* Advance to the next database entry. */
db_offset += sizeof(settings::BluetoothDevicesSettings);
}
/* Flush the data we've written. */
R_TRY(fs::FlushFile(file));
} else {
/* We can just write the database to the file. */
R_TRY(fs::WriteFile(file, db_offset, db, total_entries * sizeof(settings::BluetoothDevicesSettings), fs::WriteOption::Flush));
}
R_SUCCEED();
}
}
Result SetSysMitmService::GetFirmwareVersion(sf::Out<settings::FirmwareVersion> out) {
@@ -102,6 +198,47 @@ namespace ams::mitm::settings {
R_RETURN(GetFirmwareVersionImpl(out.GetPointer(), m_client_info));
}
Result SetSysMitmService::SetBluetoothDevicesSettings(const sf::InMapAliasArray<settings::BluetoothDevicesSettings> &settings) {
/* We only want to perform additional logic when the external database setting is enabled. */
R_UNLESS(IsExternalBluetoothDatabaseEnabled(), sm::mitm::ResultShouldForwardToSession());
/* Create the external database if it doesn't exist. */
if (!HasExternalBluetoothDatabase()) {
R_TRY(fs::CreateFile(ExternalBluetoothDatabasePath, 0));
}
/* Backup the local database to the sd card. */
R_TRY(StoreExternalBluetoothDatabase(settings.GetPointer(), settings.GetSize()));
/* Ensure that the updated database is stored to the system save as usual. */
static_assert(sizeof(settings::BluetoothDevicesSettings) == sizeof(::SetSysBluetoothDevicesSettings));
R_TRY(setsysSetBluetoothDevicesSettingsFwd(m_forward_service.get(), reinterpret_cast<const ::SetSysBluetoothDevicesSettings *>(settings.GetPointer()), settings.GetSize()));
R_SUCCEED();
}
Result SetSysMitmService::GetBluetoothDevicesSettings(sf::Out<s32> out_count, const sf::OutMapAliasArray<settings::BluetoothDevicesSettings> &out) {
/* We only want to perform additional logic when the external database setting is enabled. */
R_UNLESS(IsExternalBluetoothDatabaseEnabled(), sm::mitm::ResultShouldForwardToSession());
if (!HasExternalBluetoothDatabase()) {
/* Fetch the local database from the system save. */
static_assert(sizeof(settings::BluetoothDevicesSettings) == sizeof(::SetSysBluetoothDevicesSettings));
R_TRY(setsysGetBluetoothDevicesSettingsFwd(m_forward_service.get(), out_count.GetPointer(), reinterpret_cast<::SetSysBluetoothDevicesSettings *>(out.GetPointer()), out.GetSize()));
/* Create the external database file. */
R_TRY(fs::CreateFile(ExternalBluetoothDatabasePath, 0));
/* Backup the local database to the sd card. */
R_TRY(StoreExternalBluetoothDatabase(out.GetPointer(), out_count.GetValue()));
} else {
/* Read the external database from the sd card. */
R_TRY(ReadExternalBluetoothDatabase(out_count.GetPointer(), out.GetPointer(), out.GetSize()));
}
R_SUCCEED();
}
Result SetSysMitmService::GetSettingsItemValueSize(sf::Out<u64> out_size, const settings::SettingsName &name, const settings::SettingsItemKey &key) {
R_TRY_CATCH(settings::fwdbg::GetSdCardKeyValueStoreSettingsItemValueSize(out_size.GetPointer(), name.value, key.value)) {
R_CATCH_RETHROW(sf::impl::ResultRequestContextChanged)

View File

@@ -16,12 +16,14 @@
#pragma once
#include <stratosphere.hpp>
#define AMS_SETTINGS_SYSTEM_MITM_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 3, Result, GetFirmwareVersion, (sf::Out<ams::settings::FirmwareVersion> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 4, Result, GetFirmwareVersion2, (sf::Out<ams::settings::FirmwareVersion> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 37, Result, GetSettingsItemValueSize, (sf::Out<u64> out_size, const ams::settings::SettingsName &name, const ams::settings::SettingsItemKey &key), (out_size, name, key)) \
AMS_SF_METHOD_INFO(C, H, 38, Result, GetSettingsItemValue, (sf::Out<u64> out_size, const sf::OutBuffer &out, const ams::settings::SettingsName &name, const ams::settings::SettingsItemKey &key), (out_size, out, name, key)) \
AMS_SF_METHOD_INFO(C, H, 62, Result, GetDebugModeFlag, (sf::Out<bool> out), (out))
#define AMS_SETTINGS_SYSTEM_MITM_INTERFACE_INFO(C, H) \
AMS_SF_METHOD_INFO(C, H, 3, Result, GetFirmwareVersion, (sf::Out<ams::settings::FirmwareVersion> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 4, Result, GetFirmwareVersion2, (sf::Out<ams::settings::FirmwareVersion> out), (out)) \
AMS_SF_METHOD_INFO(C, H, 11, Result, SetBluetoothDevicesSettings, (const sf::InMapAliasArray<ams::settings::BluetoothDevicesSettings> &settings), (settings)) \
AMS_SF_METHOD_INFO(C, H, 12, Result, GetBluetoothDevicesSettings, (sf::Out<s32> out_count, const sf::OutMapAliasArray<ams::settings::BluetoothDevicesSettings> &out), (out_count, out)) \
AMS_SF_METHOD_INFO(C, H, 37, Result, GetSettingsItemValueSize, (sf::Out<u64> out_size, const ams::settings::SettingsName &name, const ams::settings::SettingsItemKey &key), (out_size, name, key)) \
AMS_SF_METHOD_INFO(C, H, 38, Result, GetSettingsItemValue, (sf::Out<u64> out_size, const sf::OutBuffer &out, const ams::settings::SettingsName &name, const ams::settings::SettingsItemKey &key), (out_size, out, name, key)) \
AMS_SF_METHOD_INFO(C, H, 62, Result, GetDebugModeFlag, (sf::Out<bool> out), (out))
AMS_SF_DEFINE_MITM_INTERFACE(ams::mitm::settings, ISetSysMitmInterface, AMS_SETTINGS_SYSTEM_MITM_INTERFACE_INFO, 0x0E82ED13)
@@ -41,6 +43,8 @@ namespace ams::mitm::settings {
public:
Result GetFirmwareVersion(sf::Out<ams::settings::FirmwareVersion> out);
Result GetFirmwareVersion2(sf::Out<ams::settings::FirmwareVersion> out);
Result SetBluetoothDevicesSettings(const sf::InMapAliasArray<ams::settings::BluetoothDevicesSettings> &settings);
Result GetBluetoothDevicesSettings(sf::Out<s32> out_count, const sf::OutMapAliasArray<ams::settings::BluetoothDevicesSettings> &out);
Result GetSettingsItemValueSize(sf::Out<u64> out_size, const ams::settings::SettingsName &name, const ams::settings::SettingsItemKey &key);
Result GetSettingsItemValue(sf::Out<u64> out_size, const sf::OutBuffer &out, const ams::settings::SettingsName &name, const ams::settings::SettingsItemKey &key);
Result GetDebugModeFlag(sf::Out<bool> out);

View File

@@ -0,0 +1,30 @@
/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope 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/>.
*/
#include "setsys_shim.h"
Result setsysSetBluetoothDevicesSettingsFwd(Service *s, const SetSysBluetoothDevicesSettings *settings, s32 count) {
return serviceDispatch(s, 11,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_In },
.buffers = { { settings, count * sizeof(SetSysBluetoothDevicesSettings) } },
);
}
Result setsysGetBluetoothDevicesSettingsFwd(Service *s, s32 *total_out, SetSysBluetoothDevicesSettings *settings, s32 count) {
return serviceDispatchOut(s, 12, *total_out,
.buffer_attrs = { SfBufferAttr_HipcMapAlias | SfBufferAttr_Out },
.buffers = { { settings, count * sizeof(SetSysBluetoothDevicesSettings) } },
);
}

View File

@@ -0,0 +1,20 @@
/**
* @file setsys_shim.h
* @brief Settings Services (fs) IPC wrapper for setsys.mitm.
* @author ndeadly
* @copyright libnx Authors
*/
#pragma once
#include <switch.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Forwarding shims. */
Result setsysSetBluetoothDevicesSettingsFwd(Service *s, const SetSysBluetoothDevicesSettings *settings, s32 count);
Result setsysGetBluetoothDevicesSettingsFwd(Service *s, s32 *total_out, SetSysBluetoothDevicesSettings *settings, s32 count);
#ifdef __cplusplus
}
#endif

View File

@@ -393,6 +393,11 @@ namespace ams::settings::fwdbg {
/* 0 = Disabled, 1 = Enabled */
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_log_manager", "u8!0x0"));
/* Controls whether the bluetooth pairing database is redirected to the SD card (shared across sysmmc/all emummcs) */
/* NOTE: On <13.0.0, the database size was 10 instead of 20; booting pre-13.0.0 will truncate the database. */
/* 0 = Disabled, 1 = Enabled */
R_ABORT_UNLESS(ParseSettingsItemValue("atmosphere", "enable_external_bluetooth_db", "u8!0x0"));
/* Hbloader custom settings. */
/* Controls the size of the homebrew heap when running as applet. */

View File

@@ -78,6 +78,9 @@
"svcReplyAndReceive": "0x43",
"svcReplyAndReceiveWithUserBuffer": "0x44",
"svcCreateEvent": "0x45",
"svcMapPhysicalMemoryUnsafe": "0x48",
"svcUnmapPhysicalMemoryUnsafe": "0x48",
"svcSetUnsafeLimit": "0x4A",
"svcReadWriteRegister": "0x4E",
"svcDebugActiveProcess": "0x60",
"svcGetDebugEvent": "0x63",
@@ -86,7 +89,9 @@
"svcQueryDebugProcessMemory": "0x69",
"svcReadDebugProcessMemory": "0x6a",
"svcGetDebugThreadParam": "0x6d",
"svcCallSecureMonitor": "0x7f"
"svcCallSecureMonitor": "0x7f",
"svcMapInsecureMemory": "0x90",
"svcUnmapInsecureMemory": "0x91"
}
}, {
"type": "min_kernel_version",

View File

@@ -99,6 +99,41 @@ namespace ams {
namespace init {
namespace {
Result InitializePlatformServiceWithoutSessionCountForHomebrewCompatibility() {
/* NOTE: This implements a hack, to keep a session to pl:u without counting against the global limit. */
/* This is done because as of 16.0.0, pl:u is the only way to get shared font access, and there are */
/* not enough sessions for all reasonable the clients when homebrew gets involved. */
/* Please do not do similar things for other services; this is a hack which may not always work, */
/* and which could cause problems in other contexts where the ServerManager doesn't have enough */
/* slots in truth. */
/* Initialize pl. */
R_ABORT_UNLESS(plInitialize(::PlServiceType_User));
/* Get the service session for pl. */
Service *srv = plGetServiceSession();
/* Next, create a clone. */
/* Because this doesn't go through sm, this does not count against the session limit. */
Service clone;
R_TRY(serviceClone(srv, std::addressof(clone)));
/* Next, close the pl service session from sm. */
/* This decrements the used session count by one, since the session is from sm. */
serviceClose(srv);
/* HACK: replace the session with the clone we made, to restore functionality. */
*srv = clone;
return 0;
}
}
void InitializeSystemModule() {
/* Initialize heap. */
fatal::srv::InitializeFsHeap();
@@ -126,7 +161,7 @@ namespace ams {
R_ABORT_UNLESS(psmInitialize());
R_ABORT_UNLESS(spsmInitialize());
R_ABORT_UNLESS(plInitialize(::PlServiceType_User));
R_ABORT_UNLESS(InitializePlatformServiceWithoutSessionCountForHomebrewCompatibility());
gpio::Initialize();
/* Mount the SD card. */

View File

@@ -42,7 +42,46 @@ namespace ams::fatal::srv {
alignas(os::MemoryPageSize) constinit u8 g_nv_transfer_memory[0x40000];
/* There should only be a single (1280*768) framebuffer. */
alignas(os::MemoryPageSize) constinit u8 g_framebuffer_memory[FatalScreenWidthAlignedBytes * util::AlignUp(FatalScreenHeight, 128)];
constexpr size_t FrameBufferRequiredSizeBytes = FatalScreenWidthAlignedBytes * util::AlignUp(FatalScreenHeight, 128);
constexpr size_t FrameBufferRequiredSizePageAligned = util::AlignUp(FrameBufferRequiredSizeBytes, os::MemoryPageSize);
constexpr size_t FrameBufferRequiredSizeHeapAligned = util::AlignUp(FrameBufferRequiredSizeBytes, os::MemoryHeapUnitSize);
constinit u8 *g_framebuffer_pointer = nullptr;
void InitializeFrameBufferPointer() {
/* Try to get a framebuffer from heap. */
{
if (R_SUCCEEDED(os::SetMemoryHeapSize(FrameBufferRequiredSizeHeapAligned))) {
g_framebuffer_pointer = reinterpret_cast<u8 *>(os::GetMemoryHeapAddress());
return;
}
}
/* We couldn't use heap, so try insecure memory, from the system nonsecure pool. */
{
uintptr_t address = 0;
if (R_SUCCEEDED(os::AllocateInsecureMemory(std::addressof(address), FrameBufferRequiredSizePageAligned))) {
g_framebuffer_pointer = reinterpret_cast<u8 *>(address);
return;
}
}
/* Neither heap nor insecure is available, so we're going to have to try to raid the unsafe pool. */
{
/* First, increase the limit to an extremely high value. */
size_t large_size = std::max(64_MB, FrameBufferRequiredSizeHeapAligned);
while (svc::ResultLimitReached::Includes(svc::SetUnsafeLimit(large_size))) {
large_size *= 2;
}
/* Next, map some unsafe memory. */
uintptr_t address = 0;
if (R_SUCCEEDED(os::AllocateUnsafeMemory(std::addressof(address), FrameBufferRequiredSizePageAligned))) {
g_framebuffer_pointer = reinterpret_cast<u8 *>(address);
return;
}
}
}
}
@@ -202,8 +241,12 @@ namespace ams::fatal::srv {
void ShowFatalTask::PreRenderFrameBuffer() {
const FatalConfig &config = GetFatalConfig();
/* Allocate a frame buffer. */
InitializeFrameBufferPointer();
AMS_ABORT_UNLESS(g_framebuffer_pointer != nullptr);
/* Pre-render the image into the static framebuffer. */
u16 *tiled_buf = reinterpret_cast<u16 *>(g_framebuffer_memory);
u16 *tiled_buf = reinterpret_cast<u16 *>(g_framebuffer_pointer);
/* Temporarily use the NV transfer memory as font backing heap. */
font::SetHeapMemory(g_nv_transfer_memory, sizeof(g_nv_transfer_memory));
@@ -214,7 +257,7 @@ namespace ams::fatal::srv {
font::SetFontColor(0xFFFF);
/* Draw a background. */
for (size_t i = 0; i < sizeof(g_framebuffer_memory) / sizeof(*tiled_buf); i++) {
for (size_t i = 0; i < FrameBufferRequiredSizeBytes / sizeof(*tiled_buf); i++) {
tiled_buf[i] = 0x39C9;
}
@@ -439,7 +482,7 @@ namespace ams::fatal::srv {
R_TRY(nvFenceInit());
/* Create nvmap. */
R_TRY(nvMapCreate(std::addressof(m_map), g_framebuffer_memory, sizeof(g_framebuffer_memory), 0x20000, NvKind_Pitch, true));
R_TRY(nvMapCreate(std::addressof(m_map), g_framebuffer_pointer, FrameBufferRequiredSizeBytes, 0x20000, NvKind_Pitch, true));
/* Setup graphics buffer. */
{
@@ -460,9 +503,9 @@ namespace ams::fatal::srv {
grbuf.planes[0].block_height_log2 = 4;
grbuf.nvmap_id = nvMapGetId(std::addressof(m_map));
grbuf.stride = FatalScreenWidthAligned;
grbuf.total_size = sizeof(g_framebuffer_memory);
grbuf.total_size = FrameBufferRequiredSizeBytes;
grbuf.planes[0].pitch = FatalScreenWidthAlignedBytes;
grbuf.planes[0].size = sizeof(g_framebuffer_memory);
grbuf.planes[0].size = FrameBufferRequiredSizeBytes;
grbuf.planes[0].offset = 0;
R_TRY(nwindowConfigureBuffer(std::addressof(m_win), 0, std::addressof(grbuf)));
@@ -474,7 +517,7 @@ namespace ams::fatal::srv {
void ShowFatalTask::DisplayPreRenderedFrame() {
s32 slot;
R_ABORT_UNLESS(nwindowDequeueBuffer(std::addressof(m_win), std::addressof(slot), nullptr));
dd::FlushDataCache(g_framebuffer_memory, sizeof(g_framebuffer_memory));
dd::FlushDataCache(g_framebuffer_pointer, FrameBufferRequiredSizeBytes);
R_ABORT_UNLESS(nwindowQueueBuffer(std::addressof(m_win), m_win.cur_slot, NULL));
}

View File

@@ -16,6 +16,7 @@
#include "ui_util.hpp"
#include <cstdio>
#include <math.h>
#include <cstring>
namespace dbk {
@@ -73,7 +74,7 @@ namespace dbk {
nvgFill(vg);
/* Setup the font. */
nvgFontSize(vg, 32.0f);
nvgFontSize(vg, std::min(32.0f, -(strlen(title)*0.5f) + 47.0f));
nvgFontFace(vg, SwitchStandardFont);
nvgTextAlign(vg, NVG_ALIGN_LEFT | NVG_ALIGN_MIDDLE);
nvgFillColor(vg, nvgRGB(0, 0, 0));