Compare commits
22 Commits
1.5.0-prer
...
1.5.1
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8274081e39 | ||
|
|
f1ad26ce84 | ||
|
|
e4c314146e | ||
|
|
52f00731d9 | ||
|
|
476d658a79 | ||
|
|
7263022bac | ||
|
|
e0e7aa1e2f | ||
|
|
bd9d8fff46 | ||
|
|
61e3f0b391 | ||
|
|
cd9b173318 | ||
|
|
a8df400825 | ||
|
|
68040e2922 | ||
|
|
8da4d14e15 | ||
|
|
e2ebf9c0ff | ||
|
|
5fb6f52b9e | ||
|
|
982389dceb | ||
|
|
f636596ee2 | ||
|
|
0a2440522f | ||
|
|
3292ea5970 | ||
|
|
33d42f4831 | ||
|
|
46094cfb3e | ||
|
|
618691a500 |
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 +=
|
||||
|
||||
@@ -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 :=
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
39
libraries/libstratosphere/source/os/os_unsafe_memory.cpp
Normal file
39
libraries/libstratosphere/source/os/os_unsafe_memory.cpp
Normal 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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
30
stratosphere/ams_mitm/source/set_mitm/setsys_shim.c
Normal file
30
stratosphere/ams_mitm/source/set_mitm/setsys_shim.c
Normal 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) } },
|
||||
);
|
||||
}
|
||||
20
stratosphere/ams_mitm/source/set_mitm/setsys_shim.h
Normal file
20
stratosphere/ams_mitm/source/set_mitm/setsys_shim.h
Normal 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
|
||||
@@ -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. */
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
Reference in New Issue
Block a user