mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2025-02-05 15:02:49 +00:00
Compare commits
1 commit
fea4be2380
...
43686f79a6
Author | SHA1 | Date | |
---|---|---|---|
|
43686f79a6 |
49 changed files with 595 additions and 774 deletions
|
@ -1,6 +1,6 @@
|
|||
# Key: debugmode, default: 1.
|
||||
# Desc: Controls whether kernel is debug mode.
|
||||
# Disabling this will break Atmosphere.
|
||||
# Disabling this may break Atmosphere's debugger in a future release.
|
||||
|
||||
# Key: debugmode_user, default: 0.
|
||||
# Desc: Controls whether userland is debug mode.
|
||||
|
|
|
@ -93,13 +93,9 @@ namespace ams::kern::arch::arm64 {
|
|||
MESOSPHERE_ASSERT(alignment < L1BlockSize);
|
||||
return KPageTable::GetBlockSize(static_cast<KPageTable::BlockType>(KPageTable::GetBlockType(alignment) + 1));
|
||||
}
|
||||
public:
|
||||
/* TODO: How should this size be determined. Does the KProcess slab count need to go in a header as a define? */
|
||||
static constexpr size_t NumTtbr0Entries = 81;
|
||||
private:
|
||||
static constinit inline const volatile u64 s_ttbr0_entries[NumTtbr0Entries] = {};
|
||||
private:
|
||||
KPageTableManager *m_manager;
|
||||
u64 m_ttbr;
|
||||
u8 m_asid;
|
||||
protected:
|
||||
Result OperateImpl(PageLinkedList *page_list, KProcessAddress virt_addr, size_t num_pages, KPhysicalAddress phys_addr, bool is_pa_valid, const KPageProperties properties, OperationType operation, bool reuse_ll);
|
||||
|
@ -172,28 +168,17 @@ namespace ams::kern::arch::arm64 {
|
|||
return entry;
|
||||
}
|
||||
public:
|
||||
constexpr explicit KPageTable(util::ConstantInitializeTag) : KPageTableBase(util::ConstantInitialize), m_manager(), m_asid() { /* ... */ }
|
||||
constexpr explicit KPageTable(util::ConstantInitializeTag) : KPageTableBase(util::ConstantInitialize), m_manager(), m_ttbr(), m_asid() { /* ... */ }
|
||||
explicit KPageTable() { /* ... */ }
|
||||
|
||||
static NOINLINE void Initialize(s32 core_id);
|
||||
|
||||
static const volatile u64 &GetTtbr0Entry(size_t index) { return s_ttbr0_entries[index]; }
|
||||
|
||||
static ALWAYS_INLINE u64 GetKernelTtbr0() {
|
||||
return s_ttbr0_entries[0];
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void ActivateKernel() {
|
||||
/* Activate, using asid 0 and process id = 0xFFFFFFFF */
|
||||
cpu::SwitchProcess(GetKernelTtbr0(), 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void ActivateProcess(size_t proc_idx, u32 proc_id) {
|
||||
cpu::SwitchProcess(s_ttbr0_entries[proc_idx + 1], proc_id);
|
||||
ALWAYS_INLINE void Activate(u32 proc_id) {
|
||||
cpu::SwitchProcess(m_ttbr, proc_id);
|
||||
}
|
||||
|
||||
NOINLINE Result InitializeForKernel(void *table, KVirtualAddress start, KVirtualAddress end);
|
||||
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit, size_t process_index);
|
||||
NOINLINE Result InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit);
|
||||
Result Finalize();
|
||||
private:
|
||||
Result MapL1Blocks(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, bool disable_head_merge, PageLinkedList *page_list, bool reuse_ll);
|
||||
|
|
|
@ -23,13 +23,13 @@ namespace ams::kern::arch::arm64 {
|
|||
private:
|
||||
KPageTable m_page_table;
|
||||
public:
|
||||
void Activate(size_t process_index, u64 id) {
|
||||
void Activate(u64 id) {
|
||||
/* Activate the page table with the specified contextidr. */
|
||||
m_page_table.ActivateProcess(process_index, id);
|
||||
m_page_table.Activate(id);
|
||||
}
|
||||
|
||||
Result Initialize(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit, size_t process_index) {
|
||||
R_RETURN(m_page_table.InitializeForProcess(flags, from_back, pool, code_address, code_size, system_resource, resource_limit, process_index));
|
||||
Result Initialize(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
||||
R_RETURN(m_page_table.InitializeForProcess(flags, from_back, pool, code_address, code_size, system_resource, resource_limit));
|
||||
}
|
||||
|
||||
void Finalize() { m_page_table.Finalize(); }
|
||||
|
@ -154,8 +154,8 @@ namespace ams::kern::arch::arm64 {
|
|||
R_RETURN(m_page_table.InvalidateCurrentProcessDataCache(address, size));
|
||||
}
|
||||
|
||||
Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size, bool force_debug_prod) {
|
||||
R_RETURN(m_page_table.ReadDebugMemory(buffer, address, size, force_debug_prod));
|
||||
Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size) {
|
||||
R_RETURN(m_page_table.ReadDebugMemory(buffer, address, size));
|
||||
}
|
||||
|
||||
Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size, KMemoryState state) {
|
||||
|
|
|
@ -29,7 +29,8 @@ namespace ams::kern::arch::arm64 {
|
|||
NOINLINE void Initialize(s32 core_id);
|
||||
|
||||
void Activate() {
|
||||
m_page_table.ActivateKernel();
|
||||
/* Activate, using process id = 0xFFFFFFFF */
|
||||
m_page_table.Activate(0xFFFFFFFF);
|
||||
}
|
||||
|
||||
void ActivateForInit() {
|
||||
|
|
|
@ -25,7 +25,6 @@ namespace ams::kern::arch::arm64 {
|
|||
static bool CopyMemoryFromUser(void *dst, const void *src, size_t size);
|
||||
static bool CopyMemoryFromUserAligned32Bit(void *dst, const void *src, size_t size);
|
||||
static bool CopyMemoryFromUserAligned64Bit(void *dst, const void *src, size_t size);
|
||||
static bool CopyMemoryFromUserSize64Bit(void *dst, const void *src);
|
||||
static bool CopyMemoryFromUserSize32Bit(void *dst, const void *src);
|
||||
static s32 CopyStringFromUser(void *dst, const void *src, size_t size);
|
||||
|
||||
|
|
|
@ -45,7 +45,6 @@ namespace ams::kern::board::nintendo::nx {
|
|||
};
|
||||
public:
|
||||
/* Initialization. */
|
||||
static NOINLINE void ConfigureKTargetSystem();
|
||||
static NOINLINE void InitializePhase1();
|
||||
static NOINLINE void InitializePhase2();
|
||||
static NOINLINE u32 GetCreateProcessMemoryPool();
|
||||
|
|
|
@ -39,16 +39,14 @@ namespace ams::kern {
|
|||
}
|
||||
}
|
||||
|
||||
Result WaitForAddress(uintptr_t addr, ams::svc::ArbitrationType type, s64 value, s64 timeout) {
|
||||
Result WaitForAddress(uintptr_t addr, ams::svc::ArbitrationType type, s32 value, s64 timeout) {
|
||||
switch (type) {
|
||||
case ams::svc::ArbitrationType_WaitIfLessThan:
|
||||
R_RETURN(this->WaitIfLessThan(addr, static_cast<s32>(value), false, timeout));
|
||||
R_RETURN(this->WaitIfLessThan(addr, value, false, timeout));
|
||||
case ams::svc::ArbitrationType_DecrementAndWaitIfLessThan:
|
||||
R_RETURN(this->WaitIfLessThan(addr, static_cast<s32>(value), true, timeout));
|
||||
R_RETURN(this->WaitIfLessThan(addr, value, true, timeout));
|
||||
case ams::svc::ArbitrationType_WaitIfEqual:
|
||||
R_RETURN(this->WaitIfEqual(addr, static_cast<s32>(value), timeout));
|
||||
case ams::svc::ArbitrationType_WaitIfEqual64:
|
||||
R_RETURN(this->WaitIfEqual64(addr, value, timeout));
|
||||
R_RETURN(this->WaitIfEqual(addr, value, timeout));
|
||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +56,6 @@ namespace ams::kern {
|
|||
Result SignalAndModifyByWaitingCountIfEqual(uintptr_t addr, s32 value, s32 count);
|
||||
Result WaitIfLessThan(uintptr_t addr, s32 value, bool decrement, s64 timeout);
|
||||
Result WaitIfEqual(uintptr_t addr, s32 value, s64 timeout);
|
||||
Result WaitIfEqual64(uintptr_t addr, s64 value, s64 timeout);
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ namespace ams::kern {
|
|||
size_t m_size;
|
||||
Type m_type;
|
||||
public:
|
||||
static uintptr_t GetAddressSpaceStart(ams::svc::CreateProcessFlag flags, Type type);
|
||||
static size_t GetAddressSpaceSize(ams::svc::CreateProcessFlag flags, Type type);
|
||||
static uintptr_t GetAddressSpaceStart(size_t width, Type type);
|
||||
static size_t GetAddressSpaceSize(size_t width, Type type);
|
||||
|
||||
static void SetAddressSpaceSize(size_t width, Type type, size_t size);
|
||||
|
||||
|
|
|
@ -168,10 +168,9 @@ namespace ams::kern {
|
|||
struct DebugFlags {
|
||||
using IdBits = Field<0, CapabilityId<CapabilityType::DebugFlags> + 1>;
|
||||
|
||||
DEFINE_FIELD(AllowDebug, IdBits, 1, bool);
|
||||
DEFINE_FIELD(ForceDebugProd, AllowDebug, 1, bool);
|
||||
DEFINE_FIELD(ForceDebug, ForceDebugProd, 1, bool);
|
||||
DEFINE_FIELD(Reserved, ForceDebug, 12);
|
||||
DEFINE_FIELD(AllowDebug, IdBits, 1, bool);
|
||||
DEFINE_FIELD(ForceDebug, AllowDebug, 1, bool);
|
||||
DEFINE_FIELD(Reserved, ForceDebug, 13);
|
||||
};
|
||||
|
||||
#undef DEFINE_FIELD
|
||||
|
@ -256,10 +255,6 @@ namespace ams::kern {
|
|||
return m_debug_capabilities.Get<DebugFlags::AllowDebug>();
|
||||
}
|
||||
|
||||
constexpr bool CanForceDebugProd() const {
|
||||
return m_debug_capabilities.Get<DebugFlags::ForceDebugProd>();
|
||||
}
|
||||
|
||||
constexpr bool CanForceDebug() const {
|
||||
return m_debug_capabilities.Get<DebugFlags::ForceDebug>();
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@ namespace ams::kern {
|
|||
KLightLock m_lock;
|
||||
KProcess::State m_old_process_state;
|
||||
bool m_is_attached;
|
||||
bool m_is_force_debug_prod;
|
||||
public:
|
||||
explicit KDebugBase() { /* ... */ }
|
||||
protected:
|
||||
|
@ -63,10 +62,6 @@ namespace ams::kern {
|
|||
return m_is_attached;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool IsForceDebugProd() const {
|
||||
return m_is_force_debug_prod;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool OpenProcess() {
|
||||
return m_process_holder.Open();
|
||||
}
|
||||
|
|
|
@ -200,8 +200,7 @@ namespace ams::kern {
|
|||
KMemoryBlockDisableMergeAttribute_DeviceLeft = (1u << 1),
|
||||
KMemoryBlockDisableMergeAttribute_IpcLeft = (1u << 2),
|
||||
KMemoryBlockDisableMergeAttribute_Locked = (1u << 3),
|
||||
/* ... */
|
||||
KMemoryBlockDisableMergeAttribute_DeviceRight = (1u << 5),
|
||||
KMemoryBlockDisableMergeAttribute_DeviceRight = (1u << 4),
|
||||
|
||||
KMemoryBlockDisableMergeAttribute_AllLeft = KMemoryBlockDisableMergeAttribute_Normal | KMemoryBlockDisableMergeAttribute_DeviceLeft | KMemoryBlockDisableMergeAttribute_IpcLeft | KMemoryBlockDisableMergeAttribute_Locked,
|
||||
KMemoryBlockDisableMergeAttribute_AllRight = KMemoryBlockDisableMergeAttribute_DeviceRight,
|
||||
|
@ -289,18 +288,18 @@ namespace ams::kern {
|
|||
|
||||
class KMemoryBlock : public util::IntrusiveRedBlackTreeBaseNode<KMemoryBlock> {
|
||||
private:
|
||||
u16 m_device_disable_merge_left_count;
|
||||
u16 m_device_disable_merge_right_count;
|
||||
KProcessAddress m_address;
|
||||
size_t m_num_pages;
|
||||
KMemoryState m_memory_state;
|
||||
u16 m_ipc_lock_count;
|
||||
u16 m_device_use_count;
|
||||
u16 m_ipc_disable_merge_count;
|
||||
KMemoryPermission m_permission;
|
||||
KMemoryPermission m_original_permission;
|
||||
KMemoryAttribute m_attribute;
|
||||
KMemoryBlockDisableMergeAttribute m_disable_merge_attribute;
|
||||
KProcessAddress m_address;
|
||||
u32 m_num_pages;
|
||||
KMemoryState m_memory_state;
|
||||
u16 m_ipc_lock_count;
|
||||
u16 m_ipc_disable_merge_count;
|
||||
u16 m_device_use_count;
|
||||
u16 m_device_disable_merge_left_count;
|
||||
u16 m_device_disable_merge_right_count;
|
||||
public:
|
||||
static constexpr ALWAYS_INLINE int Compare(const KMemoryBlock &lhs, const KMemoryBlock &rhs) {
|
||||
if (lhs.GetAddress() < rhs.GetAddress()) {
|
||||
|
@ -344,10 +343,6 @@ namespace ams::kern {
|
|||
return m_ipc_disable_merge_count;
|
||||
}
|
||||
|
||||
constexpr u16 GetDeviceUseCount() const {
|
||||
return m_device_use_count;
|
||||
}
|
||||
|
||||
constexpr KMemoryPermission GetPermission() const {
|
||||
return m_permission;
|
||||
}
|
||||
|
@ -379,15 +374,16 @@ namespace ams::kern {
|
|||
public:
|
||||
explicit KMemoryBlock() { /* ... */ }
|
||||
|
||||
constexpr KMemoryBlock(util::ConstantInitializeTag, KProcessAddress addr, u32 np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr)
|
||||
: util::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(util::ConstantInitialize), m_permission(p), m_original_permission(KMemoryPermission_None),
|
||||
m_attribute(attr), m_disable_merge_attribute(), m_address(addr), m_num_pages(np), m_memory_state(ms), m_ipc_lock_count(0),
|
||||
m_ipc_disable_merge_count(), m_device_use_count(0), m_device_disable_merge_left_count(), m_device_disable_merge_right_count()
|
||||
constexpr KMemoryBlock(util::ConstantInitializeTag, KProcessAddress addr, size_t np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr)
|
||||
: util::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(util::ConstantInitialize), m_device_disable_merge_left_count(),
|
||||
m_device_disable_merge_right_count(), m_address(addr), m_num_pages(np), m_memory_state(ms), m_ipc_lock_count(0),
|
||||
m_device_use_count(0), m_ipc_disable_merge_count(), m_permission(p), m_original_permission(KMemoryPermission_None),
|
||||
m_attribute(attr), m_disable_merge_attribute()
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
constexpr void Initialize(KProcessAddress addr, u32 np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr) {
|
||||
constexpr void Initialize(KProcessAddress addr, size_t np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr) {
|
||||
MESOSPHERE_ASSERT_THIS();
|
||||
m_device_disable_merge_left_count = 0;
|
||||
m_device_disable_merge_right_count = 0;
|
||||
|
|
|
@ -318,7 +318,7 @@ namespace ams::kern {
|
|||
R_RETURN(this->CheckMemoryStateContiguous(nullptr, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr));
|
||||
}
|
||||
|
||||
Result CheckMemoryState(KMemoryBlockManager::const_iterator it, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const;
|
||||
Result CheckMemoryState(const KMemoryInfo &info, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const;
|
||||
Result CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KMemoryBlockManager::const_iterator it, KProcessAddress last_addr, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const;
|
||||
Result CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const;
|
||||
Result CheckMemoryState(size_t *out_blocks_needed, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr = DefaultMemoryIgnoreAttr) const {
|
||||
|
@ -328,8 +328,6 @@ namespace ams::kern {
|
|||
R_RETURN(this->CheckMemoryState(nullptr, addr, size, state_mask, state, perm_mask, perm, attr_mask, attr, ignore_attr));
|
||||
}
|
||||
|
||||
bool CanReadWriteDebugMemory(KProcessAddress addr, size_t size, bool force_debug_prod);
|
||||
|
||||
Result LockMemoryAndOpen(KPageGroup *out_pg, KPhysicalAddress *out_paddr, KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, KMemoryPermission new_perm, u32 lock_attr);
|
||||
Result UnlockMemory(KProcessAddress addr, size_t size, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, KMemoryPermission new_perm, u32 lock_attr, const KPageGroup *pg);
|
||||
|
||||
|
@ -423,7 +421,7 @@ namespace ams::kern {
|
|||
Result InvalidateProcessDataCache(KProcessAddress address, size_t size);
|
||||
Result InvalidateCurrentProcessDataCache(KProcessAddress address, size_t size);
|
||||
|
||||
Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size, bool force_debug_prod);
|
||||
Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size);
|
||||
Result ReadDebugIoMemory(void *buffer, KProcessAddress address, size_t size, KMemoryState state);
|
||||
|
||||
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size);
|
||||
|
|
|
@ -206,10 +206,6 @@ namespace ams::kern {
|
|||
return m_capabilities.IsPermittedDebug();
|
||||
}
|
||||
|
||||
constexpr bool CanForceDebugProd() const {
|
||||
return m_capabilities.CanForceDebugProd();
|
||||
}
|
||||
|
||||
constexpr bool CanForceDebug() const {
|
||||
return m_capabilities.CanForceDebug();
|
||||
}
|
||||
|
@ -364,7 +360,7 @@ namespace ams::kern {
|
|||
R_RETURN(m_address_arbiter.SignalToAddress(address, signal_type, value, count));
|
||||
}
|
||||
|
||||
Result WaitAddressArbiter(uintptr_t address, ams::svc::ArbitrationType arb_type, s64 value, s64 timeout) {
|
||||
Result WaitAddressArbiter(uintptr_t address, ams::svc::ArbitrationType arb_type, s32 value, s64 timeout) {
|
||||
R_RETURN(m_address_arbiter.WaitForAddress(address, arb_type, value, timeout));
|
||||
}
|
||||
|
||||
|
@ -378,7 +374,7 @@ namespace ams::kern {
|
|||
|
||||
/* Update the current page table. */
|
||||
if (next_process) {
|
||||
next_process->GetPageTable().Activate(next_process->GetSlabIndex(), next_process->GetProcessId());
|
||||
next_process->GetPageTable().Activate(next_process->GetProcessId());
|
||||
} else {
|
||||
Kernel::GetKernelPageTable().Activate();
|
||||
}
|
||||
|
|
|
@ -69,7 +69,6 @@ namespace ams::kern {
|
|||
static NOINLINE void InitializePhase1Base(u64 seed);
|
||||
public:
|
||||
/* Initialization. */
|
||||
static NOINLINE void ConfigureKTargetSystem();
|
||||
static NOINLINE void InitializePhase1();
|
||||
static NOINLINE void InitializePhase2();
|
||||
static NOINLINE u32 GetCreateProcessMemoryPool();
|
||||
|
|
|
@ -24,36 +24,29 @@ namespace ams::kern {
|
|||
friend class KSystemControlBase;
|
||||
friend class KSystemControl;
|
||||
private:
|
||||
struct KTargetSystemData {
|
||||
bool is_debug_mode;
|
||||
bool enable_debug_logging;
|
||||
bool enable_user_exception_handlers;
|
||||
bool enable_debug_memory_fill;
|
||||
bool enable_user_pmu_access;
|
||||
bool enable_kernel_debugging;
|
||||
bool enable_dynamic_resource_limits;
|
||||
};
|
||||
static inline constinit bool s_is_debug_mode;
|
||||
static inline constinit bool s_enable_debug_logging;
|
||||
static inline constinit bool s_enable_user_exception_handlers;
|
||||
static inline constinit bool s_enable_debug_memory_fill;
|
||||
static inline constinit bool s_enable_user_pmu_access;
|
||||
static inline constinit bool s_enable_kernel_debugging;
|
||||
static inline constinit bool s_enable_dynamic_resource_limits;
|
||||
private:
|
||||
static inline constinit bool s_is_initialized = false;
|
||||
static inline constinit const volatile KTargetSystemData s_data = {
|
||||
.is_debug_mode = true,
|
||||
.enable_debug_logging = true,
|
||||
.enable_user_exception_handlers = true,
|
||||
.enable_debug_memory_fill = true,
|
||||
.enable_user_pmu_access = true,
|
||||
.enable_kernel_debugging = true,
|
||||
.enable_dynamic_resource_limits = false,
|
||||
};
|
||||
private:
|
||||
static ALWAYS_INLINE void SetInitialized() { s_is_initialized = true; }
|
||||
static ALWAYS_INLINE void SetIsDebugMode(bool en) { s_is_debug_mode = en; }
|
||||
static ALWAYS_INLINE void EnableDebugLogging(bool en) { s_enable_debug_logging = en; }
|
||||
static ALWAYS_INLINE void EnableUserExceptionHandlers(bool en) { s_enable_user_exception_handlers = en; }
|
||||
static ALWAYS_INLINE void EnableDebugMemoryFill(bool en) { s_enable_debug_memory_fill = en; }
|
||||
static ALWAYS_INLINE void EnableUserPmuAccess(bool en) { s_enable_user_pmu_access = en; }
|
||||
static ALWAYS_INLINE void EnableKernelDebugging(bool en) { s_enable_kernel_debugging = en; }
|
||||
static ALWAYS_INLINE void EnableDynamicResourceLimits(bool en) { s_enable_dynamic_resource_limits = en; }
|
||||
public:
|
||||
static ALWAYS_INLINE bool IsDebugMode() { return s_is_initialized && s_data.is_debug_mode; }
|
||||
static ALWAYS_INLINE bool IsDebugLoggingEnabled() { return s_is_initialized && s_data.enable_debug_logging; }
|
||||
static ALWAYS_INLINE bool IsUserExceptionHandlersEnabled() { return s_is_initialized && s_data.enable_user_exception_handlers; }
|
||||
static ALWAYS_INLINE bool IsDebugMemoryFillEnabled() { return s_is_initialized && s_data.enable_debug_memory_fill; }
|
||||
static ALWAYS_INLINE bool IsUserPmuAccessEnabled() { return s_is_initialized && s_data.enable_user_pmu_access; }
|
||||
static ALWAYS_INLINE bool IsKernelDebuggingEnabled() { return s_is_initialized && s_data.enable_kernel_debugging; }
|
||||
static ALWAYS_INLINE bool IsDynamicResourceLimitsEnabled() { return s_is_initialized && s_data.enable_dynamic_resource_limits; }
|
||||
static ALWAYS_INLINE bool IsDebugMode() { return s_is_debug_mode; }
|
||||
static ALWAYS_INLINE bool IsDebugLoggingEnabled() { return s_enable_debug_logging; }
|
||||
static ALWAYS_INLINE bool IsUserExceptionHandlersEnabled() { return s_enable_user_exception_handlers; }
|
||||
static ALWAYS_INLINE bool IsDebugMemoryFillEnabled() { return s_enable_debug_memory_fill; }
|
||||
static ALWAYS_INLINE bool IsUserPmuAccessEnabled() { return s_enable_user_pmu_access; }
|
||||
static ALWAYS_INLINE bool IsKernelDebuggingEnabled() { return s_enable_kernel_debugging; }
|
||||
static ALWAYS_INLINE bool IsDynamicResourceLimitsEnabled() { return s_enable_dynamic_resource_limits; }
|
||||
};
|
||||
|
||||
}
|
|
@ -48,22 +48,6 @@ namespace ams::kern {
|
|||
KProcess *GetOwner() const { return m_owner; }
|
||||
KProcessAddress GetSourceAddress() { return m_address; }
|
||||
size_t GetSize() const { return m_is_initialized ? GetReference(m_page_group).GetNumPages() * PageSize : 0; }
|
||||
|
||||
constexpr uintptr_t GetHint() const {
|
||||
/* Get memory size. */
|
||||
const size_t size = this->GetSize();
|
||||
|
||||
/* TODO: Is this architecture specific? */
|
||||
if (size >= 2_MB) {
|
||||
return GetInteger(m_address) & (2_MB - 1);
|
||||
} else if (size >= 64_KB) {
|
||||
return GetInteger(m_address) & (64_KB - 1);
|
||||
} else if (size >= 4_KB) {
|
||||
return GetInteger(m_address) & (4_KB - 1);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -79,12 +79,6 @@ namespace ams::kern::arch::arm {
|
|||
|
||||
/* Setup all interrupt lines. */
|
||||
SetupInterruptLines(core_id);
|
||||
|
||||
/* Clear pointers, if needed. */
|
||||
if (core_id == 0) {
|
||||
m_gicd = nullptr;
|
||||
m_gicc = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void KInterruptController::SaveCoreLocal(LocalState *state) const {
|
||||
|
|
|
@ -15,28 +15,6 @@
|
|||
*/
|
||||
#include <mesosphere.hpp>
|
||||
|
||||
/* <stratosphere/rocrt/rocrt.hpp> */
|
||||
namespace ams::rocrt {
|
||||
|
||||
constexpr inline const u32 ModuleHeaderVersion = util::FourCC<'M','O','D','0'>::Code;
|
||||
|
||||
struct ModuleHeader {
|
||||
u32 signature;
|
||||
u32 dynamic_offset;
|
||||
u32 bss_start_offset;
|
||||
u32 bss_end_offset;
|
||||
u32 exception_info_start_offset;
|
||||
u32 exception_info_end_offset;
|
||||
u32 module_offset;
|
||||
};
|
||||
|
||||
struct ModuleHeaderLocation {
|
||||
u32 pad;
|
||||
u32 header_offset;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace ams::kern::arch::arm64 {
|
||||
|
||||
namespace {
|
||||
|
@ -679,7 +657,7 @@ namespace ams::kern::arch::arm64 {
|
|||
return PrintAddressWithModuleName(address, has_module_name, module_name, base_address);
|
||||
}
|
||||
|
||||
dyn_address = base_address + mod_offset + temp_32;
|
||||
dyn_address = module.start_address + mod_offset + temp_32;
|
||||
}
|
||||
|
||||
/* Locate tables inside .dyn. */
|
||||
|
|
|
@ -85,6 +85,77 @@ namespace ams::kern::arch::arm64 {
|
|||
return (static_cast<u64>(asid) << 48) | (static_cast<u64>(GetInteger(table)));
|
||||
}
|
||||
|
||||
class KPageTableAsidManager {
|
||||
private:
|
||||
using WordType = u32;
|
||||
static constexpr u8 ReservedAsids[] = { 0 };
|
||||
static constexpr size_t NumReservedAsids = util::size(ReservedAsids);
|
||||
static constexpr size_t BitsPerWord = BITSIZEOF(WordType);
|
||||
static constexpr size_t AsidCount = 0x100;
|
||||
static constexpr size_t NumWords = AsidCount / BitsPerWord;
|
||||
static constexpr WordType FullWord = ~WordType(0u);
|
||||
private:
|
||||
WordType m_state[NumWords];
|
||||
KLightLock m_lock;
|
||||
u8 m_hint;
|
||||
private:
|
||||
constexpr bool TestImpl(u8 asid) const {
|
||||
return m_state[asid / BitsPerWord] & (1u << (asid % BitsPerWord));
|
||||
}
|
||||
constexpr void ReserveImpl(u8 asid) {
|
||||
MESOSPHERE_ASSERT(!this->TestImpl(asid));
|
||||
m_state[asid / BitsPerWord] |= (1u << (asid % BitsPerWord));
|
||||
}
|
||||
|
||||
constexpr void ReleaseImpl(u8 asid) {
|
||||
MESOSPHERE_ASSERT(this->TestImpl(asid));
|
||||
m_state[asid / BitsPerWord] &= ~(1u << (asid % BitsPerWord));
|
||||
}
|
||||
|
||||
constexpr u8 FindAvailable() const {
|
||||
for (size_t i = 0; i < util::size(m_state); i++) {
|
||||
if (m_state[i] == FullWord) {
|
||||
continue;
|
||||
}
|
||||
const WordType clear_bit = (m_state[i] + 1) ^ (m_state[i]);
|
||||
return BitsPerWord * i + BitsPerWord - 1 - ClearLeadingZero(clear_bit);
|
||||
}
|
||||
if (m_state[util::size(m_state)-1] == FullWord) {
|
||||
MESOSPHERE_PANIC("Unable to reserve ASID");
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE WordType ClearLeadingZero(WordType value) {
|
||||
return __builtin_clzll(value) - (BITSIZEOF(unsigned long long) - BITSIZEOF(WordType));
|
||||
}
|
||||
public:
|
||||
constexpr KPageTableAsidManager() : m_state(), m_lock(), m_hint() {
|
||||
for (size_t i = 0; i < NumReservedAsids; i++) {
|
||||
this->ReserveImpl(ReservedAsids[i]);
|
||||
}
|
||||
}
|
||||
|
||||
u8 Reserve() {
|
||||
KScopedLightLock lk(m_lock);
|
||||
|
||||
if (this->TestImpl(m_hint)) {
|
||||
m_hint = this->FindAvailable();
|
||||
}
|
||||
|
||||
this->ReserveImpl(m_hint);
|
||||
|
||||
return m_hint++;
|
||||
}
|
||||
|
||||
void Release(u8 asid) {
|
||||
KScopedLightLock lk(m_lock);
|
||||
this->ReleaseImpl(asid);
|
||||
}
|
||||
};
|
||||
|
||||
KPageTableAsidManager g_asid_manager;
|
||||
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void KPageTable::NoteUpdated() const {
|
||||
|
@ -113,7 +184,6 @@ namespace ams::kern::arch::arm64 {
|
|||
this->OnKernelTableSinglePageUpdated(virt_addr);
|
||||
}
|
||||
|
||||
|
||||
void KPageTable::Initialize(s32 core_id) {
|
||||
/* Nothing actually needed here. */
|
||||
MESOSPHERE_UNUSED(core_id);
|
||||
|
@ -124,29 +194,38 @@ namespace ams::kern::arch::arm64 {
|
|||
m_asid = 0;
|
||||
m_manager = Kernel::GetSystemSystemResource().GetPageTableManagerPointer();
|
||||
|
||||
/* Allocate a page for ttbr. */
|
||||
/* NOTE: It is a postcondition of page table manager allocation that the page is all-zero. */
|
||||
const u64 asid_tag = (static_cast<u64>(m_asid) << 48ul);
|
||||
const KVirtualAddress page = m_manager->Allocate();
|
||||
MESOSPHERE_ASSERT(page != Null<KVirtualAddress>);
|
||||
m_ttbr = GetInteger(KPageTableBase::GetLinearMappedPhysicalAddress(page)) | asid_tag;
|
||||
|
||||
/* Initialize the base page table. */
|
||||
MESOSPHERE_R_ABORT_UNLESS(KPageTableBase::InitializeForKernel(true, table, start, end));
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result KPageTable::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit, size_t process_index) {
|
||||
/* Determine our ASID */
|
||||
m_asid = process_index + 1;
|
||||
MESOSPHERE_ABORT_UNLESS(0 < m_asid && m_asid < util::size(s_ttbr0_entries));
|
||||
Result KPageTable::InitializeForProcess(ams::svc::CreateProcessFlag flags, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KSystemResource *system_resource, KResourceLimit *resource_limit) {
|
||||
/* Get an ASID */
|
||||
m_asid = g_asid_manager.Reserve();
|
||||
ON_RESULT_FAILURE { g_asid_manager.Release(m_asid); };
|
||||
|
||||
/* Set our manager. */
|
||||
m_manager = system_resource->GetPageTableManagerPointer();
|
||||
|
||||
/* Get the virtual address of our L1 table. */
|
||||
const KPhysicalAddress ttbr0_phys = KPhysicalAddress(s_ttbr0_entries[m_asid] & UINT64_C(0xFFFFFFFFFFFE));
|
||||
const KVirtualAddress ttbr0_virt = KMemoryLayout::GetLinearVirtualAddress(ttbr0_phys);
|
||||
/* Allocate a new table, and set our ttbr value. */
|
||||
const KVirtualAddress new_table = m_manager->Allocate();
|
||||
R_UNLESS(new_table != Null<KVirtualAddress>, svc::ResultOutOfResource());
|
||||
m_ttbr = EncodeTtbr(GetPageTablePhysicalAddress(new_table), m_asid);
|
||||
ON_RESULT_FAILURE_2 { m_manager->Free(new_table); };
|
||||
|
||||
/* Initialize our base table. */
|
||||
const size_t as_width = GetAddressSpaceWidth(flags);
|
||||
const KProcessAddress as_start = 0;
|
||||
const KProcessAddress as_end = (1ul << as_width);
|
||||
R_TRY(KPageTableBase::InitializeForProcess(flags, from_back, pool, GetVoidPointer(ttbr0_virt), as_start, as_end, code_address, code_size, system_resource, resource_limit));
|
||||
R_TRY(KPageTableBase::InitializeForProcess(flags, from_back, pool, GetVoidPointer(new_table), as_start, as_end, code_address, code_size, system_resource, resource_limit));
|
||||
|
||||
/* Note that we've updated the table (since we created it). */
|
||||
this->NoteUpdated();
|
||||
|
@ -250,16 +329,20 @@ namespace ams::kern::arch::arm64 {
|
|||
}
|
||||
}
|
||||
|
||||
/* Clear the L1 table. */
|
||||
/* Free the L1 table. */
|
||||
{
|
||||
const KVirtualAddress l1_table = reinterpret_cast<uintptr_t>(impl.Finalize());
|
||||
ClearPageTable(l1_table);
|
||||
this->GetPageTableManager().Free(l1_table);
|
||||
}
|
||||
|
||||
/* Perform inherited finalization. */
|
||||
KPageTableBase::Finalize();
|
||||
}
|
||||
|
||||
/* Release our asid. */
|
||||
g_asid_manager.Release(m_asid);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
|
|
@ -126,20 +126,6 @@ _ZN3ams4kern4arch5arm6415UserspaceAccess30CopyMemoryFromUserAligned64BitEPvPKvm:
|
|||
mov x0, #1
|
||||
ret
|
||||
|
||||
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryFromUserSize64Bit(void *dst, const void *src) */
|
||||
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv, "ax", %progbits
|
||||
.global _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv
|
||||
.type _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv, %function
|
||||
.balign 0x10
|
||||
_ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize64BitEPvPKv:
|
||||
/* Just load and store a u64. */
|
||||
ldtr x2, [x1]
|
||||
str x2, [x0]
|
||||
|
||||
/* We're done. */
|
||||
mov x0, #1
|
||||
ret
|
||||
|
||||
/* ams::kern::arch::arm64::UserspaceAccess::CopyMemoryFromUserSize32Bit(void *dst, const void *src) */
|
||||
.section .text._ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize32BitEPvPKv, "ax", %progbits
|
||||
.global _ZN3ams4kern4arch5arm6415UserspaceAccess27CopyMemoryFromUserSize32BitEPvPKv
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
/*
|
||||
* 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/>.
|
||||
*/
|
||||
|
||||
/* ams::kern::svc::CallWaitForAddress64From32() */
|
||||
.section .text._ZN3ams4kern3svc26CallWaitForAddress64From32Ev, "ax", %progbits
|
||||
.global _ZN3ams4kern3svc26CallWaitForAddress64From32Ev
|
||||
.type _ZN3ams4kern3svc26CallWaitForAddress64From32Ev, %function
|
||||
_ZN3ams4kern3svc26CallWaitForAddress64From32Ev:
|
||||
/* Save LR + callee-save registers. */
|
||||
str x30, [sp, #-16]!
|
||||
stp x6, x7, [sp, #-16]!
|
||||
|
||||
/* Gather the arguments into correct registers. */
|
||||
/* NOTE: This has to be manually implemented via asm, */
|
||||
/* in order to avoid breaking ABI with pre-19.0.0. */
|
||||
orr x2, x2, x5, lsl#32
|
||||
orr x3, x3, x4, lsl#32
|
||||
|
||||
/* Invoke the svc handler. */
|
||||
bl _ZN3ams4kern3svc22WaitForAddress64From32ENS_3svc7AddressENS2_15ArbitrationTypeEll
|
||||
|
||||
/* Clean up registers. */
|
||||
mov x1, xzr
|
||||
mov x2, xzr
|
||||
mov x3, xzr
|
||||
mov x4, xzr
|
||||
mov x5, xzr
|
||||
|
||||
ldp x6, x7, [sp], #0x10
|
||||
ldr x30, [sp], #0x10
|
||||
ret
|
||||
|
||||
/* ams::kern::svc::CallWaitForAddress64() */
|
||||
.section .text._ZN3ams4kern3svc20CallWaitForAddress64Ev, "ax", %progbits
|
||||
.global _ZN3ams4kern3svc20CallWaitForAddress64Ev
|
||||
.type _ZN3ams4kern3svc20CallWaitForAddress64Ev, %function
|
||||
_ZN3ams4kern3svc20CallWaitForAddress64Ev:
|
||||
/* Save LR + FP. */
|
||||
stp x29, x30, [sp, #-16]!
|
||||
|
||||
/* Invoke the svc handler. */
|
||||
bl _ZN3ams4kern3svc22WaitForAddress64From32ENS_3svc7AddressENS2_15ArbitrationTypeEll
|
||||
|
||||
/* Clean up registers. */
|
||||
mov x1, xzr
|
||||
mov x2, xzr
|
||||
mov x3, xzr
|
||||
mov x4, xzr
|
||||
mov x5, xzr
|
||||
mov x6, xzr
|
||||
mov x7, xzr
|
||||
|
||||
ldp x29, x30, [sp], #0x10
|
||||
ret
|
|
@ -36,10 +36,6 @@ namespace ams::kern::svc {
|
|||
/* Declare special prototype for (unsupported) CallCallSecureMonitor64From32. */
|
||||
void CallCallSecureMonitor64From32();
|
||||
|
||||
/* Declare special prototypes for WaitForAddress. */
|
||||
void CallWaitForAddress64();
|
||||
void CallWaitForAddress64From32();
|
||||
|
||||
namespace {
|
||||
|
||||
#ifndef MESOSPHERE_USE_STUBBED_SVC_TABLES
|
||||
|
@ -85,8 +81,6 @@ namespace ams::kern::svc {
|
|||
|
||||
table[svc::SvcId_CallSecureMonitor] = CallCallSecureMonitor64From32;
|
||||
|
||||
table[svc::SvcId_WaitForAddress] = CallWaitForAddress64From32;
|
||||
|
||||
return table;
|
||||
}();
|
||||
|
||||
|
@ -103,8 +97,6 @@ namespace ams::kern::svc {
|
|||
|
||||
table[svc::SvcId_ReturnFromException] = CallReturnFromException64;
|
||||
|
||||
table[svc::SvcId_WaitForAddress] = CallWaitForAddress64;
|
||||
|
||||
return table;
|
||||
}();
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||
/* Struct representing registers saved on wake/sleep. */
|
||||
class SavedSystemRegisters {
|
||||
private:
|
||||
u64 ttbr0_el1;
|
||||
u64 elr_el1;
|
||||
u64 sp_el0;
|
||||
u64 spsr_el1;
|
||||
|
@ -89,6 +90,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||
|
||||
void SavedSystemRegisters::Save() {
|
||||
/* Save system registers. */
|
||||
this->ttbr0_el1 = cpu::GetTtbr0El1();
|
||||
this->tpidr_el0 = cpu::GetTpidrEl0();
|
||||
this->elr_el1 = cpu::GetElrEl1();
|
||||
this->sp_el0 = cpu::GetSpEl0();
|
||||
|
@ -403,7 +405,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||
cpu::EnsureInstructionConsistency();
|
||||
|
||||
/* Restore system registers. */
|
||||
cpu::SetTtbr0El1 (KPageTable::GetKernelTtbr0());
|
||||
cpu::SetTtbr0El1 (this->ttbr0_el1);
|
||||
cpu::SetTpidrEl0 (this->tpidr_el0);
|
||||
cpu::SetElrEl1 (this->elr_el1);
|
||||
cpu::SetSpEl0 (this->sp_el0);
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace ams::kern::board::nintendo::nx {
|
|||
constexpr size_t SecureSizeMax = util::AlignDown(512_MB - 1, SecureAlignment);
|
||||
|
||||
/* Global variables for panic. */
|
||||
constinit const volatile bool g_call_smc_on_panic = false;
|
||||
constinit bool g_call_smc_on_panic;
|
||||
|
||||
/* Global variables for secure memory. */
|
||||
constinit KSpinLock g_secure_applet_lock;
|
||||
|
@ -401,67 +401,34 @@ namespace ams::kern::board::nintendo::nx {
|
|||
}
|
||||
|
||||
/* System Initialization. */
|
||||
void KSystemControl::ConfigureKTargetSystem() {
|
||||
void KSystemControl::InitializePhase1() {
|
||||
/* Configure KTargetSystem. */
|
||||
volatile auto *ts = const_cast<volatile KTargetSystem::KTargetSystemData *>(std::addressof(KTargetSystem::s_data));
|
||||
{
|
||||
/* Set IsDebugMode. */
|
||||
{
|
||||
ts->is_debug_mode = GetConfigBool(smc::ConfigItem::IsDebugMode);
|
||||
KTargetSystem::SetIsDebugMode(GetConfigBool(smc::ConfigItem::IsDebugMode));
|
||||
|
||||
/* If debug mode, we want to initialize uart logging. */
|
||||
ts->enable_debug_logging = ts->is_debug_mode;
|
||||
KTargetSystem::EnableDebugLogging(KTargetSystem::IsDebugMode());
|
||||
}
|
||||
|
||||
/* Set Kernel Configuration. */
|
||||
{
|
||||
const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)};
|
||||
|
||||
ts->enable_debug_memory_fill = kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>();
|
||||
ts->enable_user_exception_handlers = kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>();
|
||||
ts->enable_dynamic_resource_limits = !kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>();
|
||||
ts->enable_user_pmu_access = kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>();
|
||||
KTargetSystem::EnableDebugMemoryFill(kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>());
|
||||
KTargetSystem::EnableUserExceptionHandlers(kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>());
|
||||
KTargetSystem::EnableDynamicResourceLimits(!kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>());
|
||||
KTargetSystem::EnableUserPmuAccess(kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>());
|
||||
|
||||
/* Configure call smc on panic. */
|
||||
*const_cast<volatile bool *>(std::addressof(g_call_smc_on_panic)) = kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>();
|
||||
g_call_smc_on_panic = kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>();
|
||||
}
|
||||
|
||||
/* Set Kernel Debugging. */
|
||||
{
|
||||
/* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */
|
||||
/* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */
|
||||
ts->enable_kernel_debugging = GetConfigBool(smc::ConfigItem::DisableProgramVerification);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KSystemControl::InitializePhase1() {
|
||||
/* Enable KTargetSystem. */
|
||||
KTargetSystem::SetInitialized();
|
||||
|
||||
/* Check KTargetSystem was configured correctly. */
|
||||
{
|
||||
/* Check IsDebugMode. */
|
||||
{
|
||||
MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDebugMode() == GetConfigBool(smc::ConfigItem::IsDebugMode));
|
||||
MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDebugLoggingEnabled() == GetConfigBool(smc::ConfigItem::IsDebugMode));
|
||||
}
|
||||
|
||||
/* Check Kernel Configuration. */
|
||||
{
|
||||
const auto kernel_config = util::BitPack32{GetConfigU32(smc::ConfigItem::KernelConfiguration)};
|
||||
|
||||
MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDebugMemoryFillEnabled() == kernel_config.Get<smc::KernelConfiguration::DebugFillMemory>());
|
||||
MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsUserExceptionHandlersEnabled() == kernel_config.Get<smc::KernelConfiguration::EnableUserExceptionHandlers>());
|
||||
MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsDynamicResourceLimitsEnabled() == !kernel_config.Get<smc::KernelConfiguration::DisableDynamicResourceLimits>());
|
||||
MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsUserPmuAccessEnabled() == kernel_config.Get<smc::KernelConfiguration::EnableUserPmuAccess>());
|
||||
|
||||
MESOSPHERE_ABORT_UNLESS(g_call_smc_on_panic == kernel_config.Get<smc::KernelConfiguration::UseSecureMonitorPanicCall>());
|
||||
}
|
||||
|
||||
/* Check Kernel Debugging. */
|
||||
{
|
||||
MESOSPHERE_ABORT_UNLESS(KTargetSystem::IsKernelDebuggingEnabled() == GetConfigBool(smc::ConfigItem::DisableProgramVerification));
|
||||
KTargetSystem::EnableKernelDebugging(GetConfigBool(smc::ConfigItem::DisableProgramVerification));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,10 +23,6 @@ namespace ams::kern {
|
|||
return UserspaceAccess::CopyMemoryFromUserSize32Bit(out, GetVoidPointer(address));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool ReadFromUser(s64 *out, KProcessAddress address) {
|
||||
return UserspaceAccess::CopyMemoryFromUserSize64Bit(out, GetVoidPointer(address));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE bool DecrementIfLessThan(s32 *out, KProcessAddress address, s32 value) {
|
||||
/* NOTE: If scheduler lock is not held here, interrupt disable is required. */
|
||||
/* KScopedInterruptDisable di; */
|
||||
|
@ -283,51 +279,4 @@ namespace ams::kern {
|
|||
R_RETURN(cur_thread->GetWaitResult());
|
||||
}
|
||||
|
||||
Result KAddressArbiter::WaitIfEqual64(uintptr_t addr, s64 value, s64 timeout) {
|
||||
/* Prepare to wait. */
|
||||
KThread *cur_thread = GetCurrentThreadPointer();
|
||||
KHardwareTimer *timer;
|
||||
ThreadQueueImplForKAddressArbiter wait_queue(std::addressof(m_tree));
|
||||
|
||||
{
|
||||
KScopedSchedulerLockAndSleep slp(std::addressof(timer), cur_thread, timeout);
|
||||
|
||||
/* Check that the thread isn't terminating. */
|
||||
if (cur_thread->IsTerminationRequested()) {
|
||||
slp.CancelSleep();
|
||||
R_THROW(svc::ResultTerminationRequested());
|
||||
}
|
||||
|
||||
/* Read the value from userspace. */
|
||||
s64 user_value;
|
||||
if (!ReadFromUser(std::addressof(user_value), addr)) {
|
||||
slp.CancelSleep();
|
||||
R_THROW(svc::ResultInvalidCurrentMemory());
|
||||
}
|
||||
|
||||
/* Check that the value is equal. */
|
||||
if (value != user_value) {
|
||||
slp.CancelSleep();
|
||||
R_THROW(svc::ResultInvalidState());
|
||||
}
|
||||
|
||||
/* Check that the timeout is non-zero. */
|
||||
if (timeout == 0) {
|
||||
slp.CancelSleep();
|
||||
R_THROW(svc::ResultTimedOut());
|
||||
}
|
||||
|
||||
/* Set the arbiter. */
|
||||
cur_thread->SetAddressArbiter(std::addressof(m_tree), addr);
|
||||
m_tree.insert(*cur_thread);
|
||||
|
||||
/* Wait for the thread to finish. */
|
||||
wait_queue.SetHardwareTimer(timer);
|
||||
cur_thread->BeginWait(std::addressof(wait_queue));
|
||||
}
|
||||
|
||||
/* Get the wait result. */
|
||||
R_RETURN(cur_thread->GetWaitResult());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -37,24 +37,6 @@ namespace ams::kern {
|
|||
{ 39, Invalid, ams::svc::AddressMemoryRegionStack39Size, KAddressSpaceInfo::Type_Stack, },
|
||||
};
|
||||
|
||||
constexpr u8 FlagsToAddressSpaceWidthTable[4] = {
|
||||
32, 36, 32, 39
|
||||
};
|
||||
|
||||
constexpr size_t GetAddressSpaceWidth(ams::svc::CreateProcessFlag flags) {
|
||||
/* Convert the input flags to an array index. */
|
||||
const size_t idx = (flags & ams::svc::CreateProcessFlag_AddressSpaceMask) >> ams::svc::CreateProcessFlag_AddressSpaceShift;
|
||||
MESOSPHERE_ABORT_UNLESS(idx < sizeof(FlagsToAddressSpaceWidthTable));
|
||||
|
||||
/* Return the width. */
|
||||
return FlagsToAddressSpaceWidthTable[idx];
|
||||
}
|
||||
|
||||
static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace32Bit) == 32);
|
||||
static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64BitDeprecated) == 36);
|
||||
static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias) == 32);
|
||||
static_assert(GetAddressSpaceWidth(ams::svc::CreateProcessFlag_AddressSpace64Bit) == 39);
|
||||
|
||||
KAddressSpaceInfo &GetAddressSpaceInfo(size_t width, KAddressSpaceInfo::Type type) {
|
||||
for (auto &info : AddressSpaceInfos) {
|
||||
if (info.GetWidth() == width && info.GetType() == type) {
|
||||
|
@ -66,12 +48,12 @@ namespace ams::kern {
|
|||
|
||||
}
|
||||
|
||||
uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(ams::svc::CreateProcessFlag flags, KAddressSpaceInfo::Type type) {
|
||||
return GetAddressSpaceInfo(GetAddressSpaceWidth(flags), type).GetAddress();
|
||||
uintptr_t KAddressSpaceInfo::GetAddressSpaceStart(size_t width, KAddressSpaceInfo::Type type) {
|
||||
return GetAddressSpaceInfo(width, type).GetAddress();
|
||||
}
|
||||
|
||||
size_t KAddressSpaceInfo::GetAddressSpaceSize(ams::svc::CreateProcessFlag flags, KAddressSpaceInfo::Type type) {
|
||||
return GetAddressSpaceInfo(GetAddressSpaceWidth(flags), type).GetSize();
|
||||
size_t KAddressSpaceInfo::GetAddressSpaceSize(size_t width, KAddressSpaceInfo::Type type) {
|
||||
return GetAddressSpaceInfo(width, type).GetSize();
|
||||
}
|
||||
|
||||
void KAddressSpaceInfo::SetAddressSpaceSize(size_t width, Type type, size_t size) {
|
||||
|
|
|
@ -262,14 +262,7 @@ namespace ams::kern {
|
|||
/* Validate. */
|
||||
R_UNLESS(cap.Get<DebugFlags::Reserved>() == 0, svc::ResultReservedUsed());
|
||||
|
||||
u32 total = 0;
|
||||
if (cap.Get<DebugFlags::AllowDebug>()) { ++total; }
|
||||
if (cap.Get<DebugFlags::ForceDebugProd>()) { ++total; }
|
||||
if (cap.Get<DebugFlags::ForceDebug>()) { ++total; }
|
||||
R_UNLESS(total <= 1, svc::ResultInvalidCombination());
|
||||
|
||||
m_debug_capabilities.Set<DebugFlags::AllowDebug>(cap.Get<DebugFlags::AllowDebug>());
|
||||
m_debug_capabilities.Set<DebugFlags::ForceDebugProd>(cap.Get<DebugFlags::ForceDebugProd>());
|
||||
m_debug_capabilities.Set<DebugFlags::ForceDebug>(cap.Get<DebugFlags::ForceDebug>());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
|
|
@ -27,8 +27,7 @@ namespace ams::kern {
|
|||
|
||||
void KDebugBase::Initialize() {
|
||||
/* Clear the continue flags. */
|
||||
m_continue_flags = 0;
|
||||
m_is_force_debug_prod = GetCurrentProcess().CanForceDebugProd();
|
||||
m_continue_flags = 0;
|
||||
}
|
||||
|
||||
bool KDebugBase::Is64Bit() const {
|
||||
|
@ -121,11 +120,8 @@ namespace ams::kern {
|
|||
/* Read the memory. */
|
||||
if (info.GetSvcState() != ams::svc::MemoryState_Io) {
|
||||
/* The memory is normal memory. */
|
||||
R_TRY(target_pt.ReadDebugMemory(GetVoidPointer(buffer), cur_address, cur_size, this->IsForceDebugProd()));
|
||||
R_TRY(target_pt.ReadDebugMemory(GetVoidPointer(buffer), cur_address, cur_size));
|
||||
} else {
|
||||
/* Only allow IO memory to be read if not force debug prod. */
|
||||
R_UNLESS(!this->IsForceDebugProd(), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
/* The memory is IO memory. */
|
||||
R_TRY(target_pt.ReadDebugIoMemory(GetVoidPointer(buffer), cur_address, cur_size, info.GetState()));
|
||||
}
|
||||
|
@ -273,9 +269,6 @@ namespace ams::kern {
|
|||
switch (state) {
|
||||
case KProcess::State_Created:
|
||||
case KProcess::State_Running:
|
||||
/* Created and running processes can only be debugged if the debugger is not ForceDebugProd. */
|
||||
R_UNLESS(!this->IsForceDebugProd(), svc::ResultInvalidState());
|
||||
break;
|
||||
case KProcess::State_Crashed:
|
||||
break;
|
||||
case KProcess::State_CreatedAttached:
|
||||
|
@ -415,6 +408,69 @@ namespace ams::kern {
|
|||
/* Get the process pointer. */
|
||||
KProcess * const target = this->GetProcessUnsafe();
|
||||
|
||||
/* Detach from the process. */
|
||||
{
|
||||
/* Lock both ourselves and the target process. */
|
||||
KScopedLightLock state_lk(target->GetStateLock());
|
||||
KScopedLightLock list_lk(target->GetListLock());
|
||||
KScopedLightLock this_lk(m_lock);
|
||||
|
||||
/* Check that we're still attached. */
|
||||
if (this->IsAttached()) {
|
||||
/* Lock the scheduler. */
|
||||
KScopedSchedulerLock sl;
|
||||
|
||||
/* Get the process's state. */
|
||||
const KProcess::State state = target->GetState();
|
||||
|
||||
/* Check that the process is in a state where we can terminate it. */
|
||||
R_UNLESS(state != KProcess::State_Created, svc::ResultInvalidState());
|
||||
R_UNLESS(state != KProcess::State_CreatedAttached, svc::ResultInvalidState());
|
||||
|
||||
/* Decide on a new state for the process. */
|
||||
KProcess::State new_state;
|
||||
if (state == KProcess::State_RunningAttached) {
|
||||
/* If the process is running, transition it accordingly. */
|
||||
new_state = KProcess::State_Running;
|
||||
} else if (state == KProcess::State_DebugBreak) {
|
||||
/* If the process is debug breaked, transition it accordingly. */
|
||||
new_state = KProcess::State_Crashed;
|
||||
|
||||
/* Suspend all the threads in the process. */
|
||||
{
|
||||
auto end = target->GetThreadList().end();
|
||||
for (auto it = target->GetThreadList().begin(); it != end; ++it) {
|
||||
/* Request that we suspend the thread. */
|
||||
it->RequestSuspend(KThread::SuspendType_Debug);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
/* Otherwise, don't transition. */
|
||||
new_state = state;
|
||||
}
|
||||
|
||||
#if defined(MESOSPHERE_ENABLE_HARDWARE_SINGLE_STEP)
|
||||
/* Clear single step on all threads. */
|
||||
{
|
||||
auto end = target->GetThreadList().end();
|
||||
for (auto it = target->GetThreadList().begin(); it != end; ++it) {
|
||||
it->ClearHardwareSingleStep();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Detach from the process. */
|
||||
target->ClearDebugObject(new_state);
|
||||
m_is_attached = false;
|
||||
|
||||
/* Close the initial reference opened to our process. */
|
||||
this->CloseProcess();
|
||||
|
||||
/* Clear our continue flags. */
|
||||
m_continue_flags = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Terminate the process. */
|
||||
target->Terminate();
|
||||
|
||||
|
@ -906,12 +962,7 @@ namespace ams::kern {
|
|||
case ams::svc::DebugException_UndefinedInstruction:
|
||||
{
|
||||
MESOSPHERE_ASSERT(info->info.exception.exception_data_count == 1);
|
||||
/* Only save the instruction if the caller is not force debug prod. */
|
||||
if (this->IsForceDebugProd()) {
|
||||
out->info.exception.specific.undefined_instruction.insn = 0;
|
||||
} else {
|
||||
out->info.exception.specific.undefined_instruction.insn = info->info.exception.exception_data[0];
|
||||
}
|
||||
out->info.exception.specific.undefined_instruction.insn = info->info.exception.exception_data[0];
|
||||
}
|
||||
break;
|
||||
case ams::svc::DebugException_BreakPoint:
|
||||
|
|
|
@ -193,25 +193,40 @@ namespace ams::kern {
|
|||
R_UNLESS(this->Is64Bit(), svc::ResultInvalidCombination());
|
||||
}
|
||||
|
||||
using ASType = KAddressSpaceInfo::Type;
|
||||
|
||||
const uintptr_t start_address = rx_address;
|
||||
const uintptr_t end_address = bss_size > 0 ? bss_address + bss_size : rw_address + rw_size;
|
||||
const size_t as_width = this->Is64BitAddressSpace() ? ((GetTargetFirmware() >= TargetFirmware_2_0_0) ? 39 : 36) : 32;
|
||||
const ASType as_type = this->Is64BitAddressSpace() ? ((GetTargetFirmware() >= TargetFirmware_2_0_0) ? KAddressSpaceInfo::Type_Map39Bit : KAddressSpaceInfo::Type_MapSmall) : KAddressSpaceInfo::Type_MapSmall;
|
||||
const uintptr_t map_start = KAddressSpaceInfo::GetAddressSpaceStart(as_width, as_type);
|
||||
const size_t map_size = KAddressSpaceInfo::GetAddressSpaceSize(as_width, as_type);
|
||||
const uintptr_t map_end = map_start + map_size;
|
||||
MESOSPHERE_ABORT_UNLESS(start_address == 0);
|
||||
|
||||
/* Default fields in parameter to zero. */
|
||||
*out = {};
|
||||
|
||||
/* Set fields in parameter. */
|
||||
out->code_address = 0;
|
||||
out->code_address = map_start + start_address;
|
||||
out->code_num_pages = util::AlignUp(end_address - start_address, PageSize) / PageSize;
|
||||
out->program_id = m_kip_header.GetProgramId();
|
||||
out->version = m_kip_header.GetVersion();
|
||||
out->flags = 0;
|
||||
out->reslimit = ams::svc::InvalidHandle;
|
||||
out->system_resource_num_pages = 0;
|
||||
MESOSPHERE_ABORT_UNLESS((out->code_address / PageSize) + out->code_num_pages <= (map_end / PageSize));
|
||||
|
||||
/* Copy name field. */
|
||||
m_kip_header.GetName(out->name, sizeof(out->name));
|
||||
|
||||
/* Apply ASLR, if needed. */
|
||||
if (enable_aslr) {
|
||||
const size_t choices = (map_end / KernelAslrAlignment) - (util::AlignUp(out->code_address + out->code_num_pages * PageSize, KernelAslrAlignment) / KernelAslrAlignment);
|
||||
out->code_address += KSystemControl::GenerateRandomRange(0, choices) * KernelAslrAlignment;
|
||||
out->flags |= ams::svc::CreateProcessFlag_EnableAslr;
|
||||
}
|
||||
|
||||
/* Apply other flags. */
|
||||
if (this->Is64Bit()) {
|
||||
out->flags |= ams::svc::CreateProcessFlag_Is64Bit;
|
||||
|
@ -221,28 +236,10 @@ namespace ams::kern {
|
|||
} else {
|
||||
out->flags |= ams::svc::CreateProcessFlag_AddressSpace32Bit;
|
||||
}
|
||||
if (enable_aslr) {
|
||||
out->flags |= ams::svc::CreateProcessFlag_EnableAslr;
|
||||
}
|
||||
|
||||
/* All initial processes should disable device address space merge. */
|
||||
out->flags |= ams::svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge;
|
||||
|
||||
/* Set and check code address. */
|
||||
using ASType = KAddressSpaceInfo::Type;
|
||||
const ASType as_type = this->Is64BitAddressSpace() ? ((GetTargetFirmware() >= TargetFirmware_2_0_0) ? KAddressSpaceInfo::Type_Map39Bit : KAddressSpaceInfo::Type_MapSmall) : KAddressSpaceInfo::Type_MapSmall;
|
||||
const uintptr_t map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(out->flags), as_type);
|
||||
const size_t map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(out->flags), as_type);
|
||||
const uintptr_t map_end = map_start + map_size;
|
||||
out->code_address = map_start + start_address;
|
||||
MESOSPHERE_ABORT_UNLESS((out->code_address / PageSize) + out->code_num_pages <= (map_end / PageSize));
|
||||
|
||||
/* Apply ASLR, if needed. */
|
||||
if (enable_aslr) {
|
||||
const size_t choices = (map_end / KernelAslrAlignment) - (util::AlignUp(out->code_address + out->code_num_pages * PageSize, KernelAslrAlignment) / KernelAslrAlignment);
|
||||
out->code_address += KSystemControl::GenerateRandomRange(0, choices) * KernelAslrAlignment;
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
|
|
@ -54,11 +54,11 @@ namespace ams::kern {
|
|||
return "Unknown ";
|
||||
}
|
||||
|
||||
constexpr const char *GetMemoryPermissionString(const KMemoryBlock &block) {
|
||||
if (block.GetState() == KMemoryState_Free) {
|
||||
constexpr const char *GetMemoryPermissionString(const KMemoryInfo &info) {
|
||||
if (info.m_state == KMemoryState_Free) {
|
||||
return " ";
|
||||
} else {
|
||||
switch (block.GetPermission()) {
|
||||
switch (info.m_permission) {
|
||||
case KMemoryPermission_UserReadExecute:
|
||||
return "r-x";
|
||||
case KMemoryPermission_UserRead:
|
||||
|
@ -71,19 +71,19 @@ namespace ams::kern {
|
|||
}
|
||||
}
|
||||
|
||||
void DumpMemoryBlock(const KMemoryBlock &block) {
|
||||
const char *state = GetMemoryStateName(block.GetState());
|
||||
const char *perm = GetMemoryPermissionString(block);
|
||||
const uintptr_t start = GetInteger(block.GetAddress());
|
||||
const uintptr_t end = GetInteger(block.GetLastAddress());
|
||||
const size_t kb = block.GetSize() / 1_KB;
|
||||
void DumpMemoryInfo(const KMemoryInfo &info) {
|
||||
const char *state = GetMemoryStateName(info.m_state);
|
||||
const char *perm = GetMemoryPermissionString(info);
|
||||
const uintptr_t start = info.GetAddress();
|
||||
const uintptr_t end = info.GetLastAddress();
|
||||
const size_t kb = info.GetSize() / 1_KB;
|
||||
|
||||
const char l = (block.GetAttribute() & KMemoryAttribute_Locked) ? 'L' : '-';
|
||||
const char i = (block.GetAttribute() & KMemoryAttribute_IpcLocked) ? 'I' : '-';
|
||||
const char d = (block.GetAttribute() & KMemoryAttribute_DeviceShared) ? 'D' : '-';
|
||||
const char u = (block.GetAttribute() & KMemoryAttribute_Uncached) ? 'U' : '-';
|
||||
const char l = (info.m_attribute & KMemoryAttribute_Locked) ? 'L' : '-';
|
||||
const char i = (info.m_attribute & KMemoryAttribute_IpcLocked) ? 'I' : '-';
|
||||
const char d = (info.m_attribute & KMemoryAttribute_DeviceShared) ? 'D' : '-';
|
||||
const char u = (info.m_attribute & KMemoryAttribute_Uncached) ? 'U' : '-';
|
||||
|
||||
MESOSPHERE_LOG("0x%10lx - 0x%10lx (%9zu KB) %s %s %c%c%c%c [%d, %d]\n", start, end, kb, perm, state, l, i, d, u, block.GetIpcLockCount(), block.GetDeviceUseCount());
|
||||
MESOSPHERE_LOG("0x%10lx - 0x%10lx (%9zu KB) %s %s %c%c%c%c [%d, %d]\n", start, end, kb, perm, state, l, i, d, u, info.m_ipc_lock_count, info.m_device_use_count);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -123,14 +123,15 @@ namespace ams::kern {
|
|||
const KProcessAddress region_end = region_start + region_num_pages * PageSize;
|
||||
const KProcessAddress region_last = region_end - 1;
|
||||
for (const_iterator it = this->FindIterator(region_start); it != m_memory_block_tree.cend(); it++) {
|
||||
if (region_last < it->GetAddress()) {
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
if (region_last < info.GetAddress()) {
|
||||
break;
|
||||
}
|
||||
if (it->GetState() != KMemoryState_Free) {
|
||||
if (info.m_state != KMemoryState_Free) {
|
||||
continue;
|
||||
}
|
||||
|
||||
KProcessAddress area = (it->GetAddress() <= GetInteger(region_start)) ? region_start : it->GetAddress();
|
||||
KProcessAddress area = (info.GetAddress() <= GetInteger(region_start)) ? region_start : info.GetAddress();
|
||||
area += guard_pages * PageSize;
|
||||
|
||||
const KProcessAddress offset_area = util::AlignDown(GetInteger(area), alignment) + offset;
|
||||
|
@ -139,7 +140,7 @@ namespace ams::kern {
|
|||
const KProcessAddress area_end = area + num_pages * PageSize + guard_pages * PageSize;
|
||||
const KProcessAddress area_last = area_end - 1;
|
||||
|
||||
if (GetInteger(it->GetAddress()) <= GetInteger(area) && area < area_last && area_last <= region_last && GetInteger(area_last) <= GetInteger(it->GetLastAddress())) {
|
||||
if (info.GetAddress() <= GetInteger(area) && area < area_last && area_last <= region_last && GetInteger(area_last) <= info.GetLastAddress()) {
|
||||
return area;
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +171,7 @@ namespace ams::kern {
|
|||
it = prev;
|
||||
}
|
||||
|
||||
if (address + num_pages * PageSize < it->GetEndAddress()) {
|
||||
if (address + num_pages * PageSize < it->GetMemoryInfo().GetEndAddress()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -188,39 +189,43 @@ namespace ams::kern {
|
|||
|
||||
while (remaining_pages > 0) {
|
||||
const size_t remaining_size = remaining_pages * PageSize;
|
||||
KMemoryInfo cur_info = it->GetMemoryInfo();
|
||||
if (it->HasProperties(state, perm, attr)) {
|
||||
/* If we already have the right properties, just advance. */
|
||||
if (cur_address + remaining_size < it->GetEndAddress()) {
|
||||
if (cur_address + remaining_size < cur_info.GetEndAddress()) {
|
||||
remaining_pages = 0;
|
||||
cur_address += remaining_size;
|
||||
} else {
|
||||
remaining_pages = (cur_address + remaining_size - it->GetEndAddress()) / PageSize;
|
||||
cur_address = it->GetEndAddress();
|
||||
remaining_pages = (cur_address + remaining_size - cur_info.GetEndAddress()) / PageSize;
|
||||
cur_address = cur_info.GetEndAddress();
|
||||
}
|
||||
} else {
|
||||
/* If we need to, create a new block before and insert it. */
|
||||
if (it->GetAddress() != GetInteger(cur_address)) {
|
||||
if (cur_info.GetAddress() != GetInteger(cur_address)) {
|
||||
KMemoryBlock *new_block = allocator->Allocate();
|
||||
|
||||
it->Split(new_block, cur_address);
|
||||
it = m_memory_block_tree.insert(*new_block);
|
||||
it++;
|
||||
|
||||
cur_address = it->GetAddress();
|
||||
cur_info = it->GetMemoryInfo();
|
||||
cur_address = cur_info.GetAddress();
|
||||
}
|
||||
|
||||
/* If we need to, create a new block after and insert it. */
|
||||
if (it->GetSize() > remaining_size) {
|
||||
if (cur_info.GetSize() > remaining_size) {
|
||||
KMemoryBlock *new_block = allocator->Allocate();
|
||||
|
||||
it->Split(new_block, cur_address + remaining_size);
|
||||
it = m_memory_block_tree.insert(*new_block);
|
||||
|
||||
cur_info = it->GetMemoryInfo();
|
||||
}
|
||||
|
||||
/* Update block state. */
|
||||
it->Update(state, perm, attr, it->GetAddress() == address, set_disable_attr, clear_disable_attr);
|
||||
cur_address += it->GetSize();
|
||||
remaining_pages -= it->GetNumPages();
|
||||
cur_address += cur_info.GetSize();
|
||||
remaining_pages -= cur_info.GetNumPages();
|
||||
}
|
||||
it++;
|
||||
}
|
||||
|
@ -240,38 +245,42 @@ namespace ams::kern {
|
|||
|
||||
while (remaining_pages > 0) {
|
||||
const size_t remaining_size = remaining_pages * PageSize;
|
||||
KMemoryInfo cur_info = it->GetMemoryInfo();
|
||||
if (it->HasProperties(test_state, test_perm, test_attr) && !it->HasProperties(state, perm, attr)) {
|
||||
/* If we need to, create a new block before and insert it. */
|
||||
if (it->GetAddress() != GetInteger(cur_address)) {
|
||||
if (cur_info.GetAddress() != GetInteger(cur_address)) {
|
||||
KMemoryBlock *new_block = allocator->Allocate();
|
||||
|
||||
it->Split(new_block, cur_address);
|
||||
it = m_memory_block_tree.insert(*new_block);
|
||||
it++;
|
||||
|
||||
cur_address = it->GetAddress();
|
||||
cur_info = it->GetMemoryInfo();
|
||||
cur_address = cur_info.GetAddress();
|
||||
}
|
||||
|
||||
/* If we need to, create a new block after and insert it. */
|
||||
if (it->GetSize() > remaining_size) {
|
||||
if (cur_info.GetSize() > remaining_size) {
|
||||
KMemoryBlock *new_block = allocator->Allocate();
|
||||
|
||||
it->Split(new_block, cur_address + remaining_size);
|
||||
it = m_memory_block_tree.insert(*new_block);
|
||||
|
||||
cur_info = it->GetMemoryInfo();
|
||||
}
|
||||
|
||||
/* Update block state. */
|
||||
it->Update(state, perm, attr, it->GetAddress() == address, set_disable_attr, clear_disable_attr);
|
||||
cur_address += it->GetSize();
|
||||
remaining_pages -= it->GetNumPages();
|
||||
cur_address += cur_info.GetSize();
|
||||
remaining_pages -= cur_info.GetNumPages();
|
||||
} else {
|
||||
/* If we already have the right properties, just advance. */
|
||||
if (cur_address + remaining_size < it->GetEndAddress()) {
|
||||
if (cur_address + remaining_size < cur_info.GetEndAddress()) {
|
||||
remaining_pages = 0;
|
||||
cur_address += remaining_size;
|
||||
} else {
|
||||
remaining_pages = (cur_address + remaining_size - it->GetEndAddress()) / PageSize;
|
||||
cur_address = it->GetEndAddress();
|
||||
remaining_pages = (cur_address + remaining_size - cur_info.GetEndAddress()) / PageSize;
|
||||
cur_address = cur_info.GetEndAddress();
|
||||
}
|
||||
}
|
||||
it++;
|
||||
|
@ -293,30 +302,34 @@ namespace ams::kern {
|
|||
|
||||
while (remaining_pages > 0) {
|
||||
const size_t remaining_size = remaining_pages * PageSize;
|
||||
KMemoryInfo cur_info = it->GetMemoryInfo();
|
||||
|
||||
/* If we need to, create a new block before and insert it. */
|
||||
if (it->GetAddress() != cur_address) {
|
||||
if (cur_info.m_address != GetInteger(cur_address)) {
|
||||
KMemoryBlock *new_block = allocator->Allocate();
|
||||
|
||||
it->Split(new_block, cur_address);
|
||||
it = m_memory_block_tree.insert(*new_block);
|
||||
it++;
|
||||
|
||||
cur_address = it->GetAddress();
|
||||
cur_info = it->GetMemoryInfo();
|
||||
cur_address = cur_info.GetAddress();
|
||||
}
|
||||
|
||||
if (it->GetSize() > remaining_size) {
|
||||
if (cur_info.GetSize() > remaining_size) {
|
||||
/* If we need to, create a new block after and insert it. */
|
||||
KMemoryBlock *new_block = allocator->Allocate();
|
||||
|
||||
it->Split(new_block, cur_address + remaining_size);
|
||||
it = m_memory_block_tree.insert(*new_block);
|
||||
|
||||
cur_info = it->GetMemoryInfo();
|
||||
}
|
||||
|
||||
/* Call the locked update function. */
|
||||
(std::addressof(*it)->*lock_func)(perm, it->GetAddress() == address, it->GetEndAddress() == end_address);
|
||||
cur_address += it->GetSize();
|
||||
remaining_pages -= it->GetNumPages();
|
||||
(std::addressof(*it)->*lock_func)(perm, cur_info.GetAddress() == address, cur_info.GetEndAddress() == end_address);
|
||||
cur_address += cur_info.GetSize();
|
||||
remaining_pages -= cur_info.GetNumPages();
|
||||
it++;
|
||||
}
|
||||
|
||||
|
@ -334,39 +347,43 @@ namespace ams::kern {
|
|||
|
||||
while (remaining_pages > 0) {
|
||||
const size_t remaining_size = remaining_pages * PageSize;
|
||||
KMemoryInfo cur_info = it->GetMemoryInfo();
|
||||
|
||||
if ((it->GetAttribute() & mask) != attr) {
|
||||
/* If we need to, create a new block before and insert it. */
|
||||
if (it->GetAddress() != GetInteger(cur_address)) {
|
||||
if (cur_info.GetAddress() != GetInteger(cur_address)) {
|
||||
KMemoryBlock *new_block = allocator->Allocate();
|
||||
|
||||
it->Split(new_block, cur_address);
|
||||
it = m_memory_block_tree.insert(*new_block);
|
||||
it++;
|
||||
|
||||
cur_address = it->GetAddress();
|
||||
cur_info = it->GetMemoryInfo();
|
||||
cur_address = cur_info.GetAddress();
|
||||
}
|
||||
|
||||
/* If we need to, create a new block after and insert it. */
|
||||
if (it->GetSize() > remaining_size) {
|
||||
if (cur_info.GetSize() > remaining_size) {
|
||||
KMemoryBlock *new_block = allocator->Allocate();
|
||||
|
||||
it->Split(new_block, cur_address + remaining_size);
|
||||
it = m_memory_block_tree.insert(*new_block);
|
||||
|
||||
cur_info = it->GetMemoryInfo();
|
||||
}
|
||||
|
||||
/* Update block state. */
|
||||
it->UpdateAttribute(mask, attr);
|
||||
cur_address += it->GetSize();
|
||||
remaining_pages -= it->GetNumPages();
|
||||
cur_address += cur_info.GetSize();
|
||||
remaining_pages -= cur_info.GetNumPages();
|
||||
} else {
|
||||
/* If we already have the right attributes, just advance. */
|
||||
if (cur_address + remaining_size < it->GetEndAddress()) {
|
||||
if (cur_address + remaining_size < cur_info.GetEndAddress()) {
|
||||
remaining_pages = 0;
|
||||
cur_address += remaining_size;
|
||||
} else {
|
||||
remaining_pages = (cur_address + remaining_size - it->GetEndAddress()) / PageSize;
|
||||
cur_address = it->GetEndAddress();
|
||||
remaining_pages = (cur_address + remaining_size - cur_info.GetEndAddress()) / PageSize;
|
||||
cur_address = cur_info.GetEndAddress();
|
||||
}
|
||||
}
|
||||
it++;
|
||||
|
@ -384,6 +401,8 @@ namespace ams::kern {
|
|||
auto it = m_memory_block_tree.cbegin();
|
||||
auto prev = it++;
|
||||
while (it != m_memory_block_tree.cend()) {
|
||||
const KMemoryInfo prev_info = prev->GetMemoryInfo();
|
||||
const KMemoryInfo cur_info = it->GetMemoryInfo();
|
||||
|
||||
/* Sequential blocks which can be merged should be merged. */
|
||||
if (prev->CanMergeWith(*it)) {
|
||||
|
@ -391,17 +410,17 @@ namespace ams::kern {
|
|||
}
|
||||
|
||||
/* Sequential blocks should be sequential. */
|
||||
if (prev->GetEndAddress() != it->GetAddress()) {
|
||||
if (prev_info.GetEndAddress() != cur_info.GetAddress()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If the block is ipc locked, it must have a count. */
|
||||
if ((it->GetAttribute() & KMemoryAttribute_IpcLocked) != 0 && it->GetIpcLockCount() == 0) {
|
||||
if ((cur_info.m_attribute & KMemoryAttribute_IpcLocked) != 0 && cur_info.m_ipc_lock_count == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If the block is device shared, it must have a count. */
|
||||
if ((it->GetAttribute() & KMemoryAttribute_DeviceShared) != 0 && it->GetDeviceUseCount() == 0) {
|
||||
if ((cur_info.m_attribute & KMemoryAttribute_DeviceShared) != 0 && cur_info.m_device_use_count == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -411,13 +430,14 @@ namespace ams::kern {
|
|||
|
||||
/* Our loop will miss checking the last block, potentially, so check it. */
|
||||
if (prev != m_memory_block_tree.cend()) {
|
||||
const KMemoryInfo prev_info = prev->GetMemoryInfo();
|
||||
/* If the block is ipc locked, it must have a count. */
|
||||
if ((prev->GetAttribute() & KMemoryAttribute_IpcLocked) != 0 && prev->GetIpcLockCount() == 0) {
|
||||
if ((prev_info.m_attribute & KMemoryAttribute_IpcLocked) != 0 && prev_info.m_ipc_lock_count == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* If the block is device shared, it must have a count. */
|
||||
if ((prev->GetAttribute() & KMemoryAttribute_DeviceShared) != 0 && prev->GetDeviceUseCount() == 0) {
|
||||
if ((prev_info.m_attribute & KMemoryAttribute_DeviceShared) != 0 && prev_info.m_device_use_count == 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -430,7 +450,7 @@ namespace ams::kern {
|
|||
void KMemoryBlockManager::DumpBlocks() const {
|
||||
/* Dump each block. */
|
||||
for (const auto &block : m_memory_block_tree) {
|
||||
DumpMemoryBlock(block);
|
||||
DumpMemoryInfo(block.GetMemoryInfo());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -141,10 +141,10 @@ namespace ams::kern {
|
|||
|
||||
/* Define helpers. */
|
||||
auto GetSpaceStart = [&](KAddressSpaceInfo::Type type) ALWAYS_INLINE_LAMBDA {
|
||||
return KAddressSpaceInfo::GetAddressSpaceStart(flags, type);
|
||||
return KAddressSpaceInfo::GetAddressSpaceStart(m_address_space_width, type);
|
||||
};
|
||||
auto GetSpaceSize = [&](KAddressSpaceInfo::Type type) ALWAYS_INLINE_LAMBDA {
|
||||
return KAddressSpaceInfo::GetAddressSpaceSize(flags, type);
|
||||
return KAddressSpaceInfo::GetAddressSpaceSize(m_address_space_width, type);
|
||||
};
|
||||
|
||||
/* Default to zero alias region extra size. */
|
||||
|
@ -664,11 +664,11 @@ namespace ams::kern {
|
|||
}
|
||||
}
|
||||
|
||||
Result KPageTableBase::CheckMemoryState(KMemoryBlockManager::const_iterator it, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const {
|
||||
Result KPageTableBase::CheckMemoryState(const KMemoryInfo &info, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) const {
|
||||
/* Validate the states match expectation. */
|
||||
R_UNLESS((it->GetState() & state_mask) == state, svc::ResultInvalidCurrentMemory());
|
||||
R_UNLESS((it->GetPermission() & perm_mask) == perm, svc::ResultInvalidCurrentMemory());
|
||||
R_UNLESS((it->GetAttribute() & attr_mask) == attr, svc::ResultInvalidCurrentMemory());
|
||||
R_UNLESS((info.m_state & state_mask) == state, svc::ResultInvalidCurrentMemory());
|
||||
R_UNLESS((info.m_permission & perm_mask) == perm, svc::ResultInvalidCurrentMemory());
|
||||
R_UNLESS((info.m_attribute & attr_mask) == attr, svc::ResultInvalidCurrentMemory());
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
@ -679,26 +679,28 @@ namespace ams::kern {
|
|||
/* Get information about the first block. */
|
||||
const KProcessAddress last_addr = addr + size - 1;
|
||||
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(addr);
|
||||
KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
/* If the start address isn't aligned, we need a block. */
|
||||
const size_t blocks_for_start_align = (util::AlignDown(GetInteger(addr), PageSize) != it->GetAddress()) ? 1 : 0;
|
||||
const size_t blocks_for_start_align = (util::AlignDown(GetInteger(addr), PageSize) != info.GetAddress()) ? 1 : 0;
|
||||
|
||||
while (true) {
|
||||
/* Validate against the provided masks. */
|
||||
R_TRY(this->CheckMemoryState(it, state_mask, state, perm_mask, perm, attr_mask, attr));
|
||||
R_TRY(this->CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr));
|
||||
|
||||
/* Break once we're done. */
|
||||
if (last_addr <= it->GetLastAddress()) {
|
||||
if (last_addr <= info.GetLastAddress()) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Advance our iterator. */
|
||||
it++;
|
||||
MESOSPHERE_ASSERT(it != m_memory_block_manager.cend());
|
||||
info = it->GetMemoryInfo();
|
||||
}
|
||||
|
||||
/* If the end address isn't aligned, we need a block. */
|
||||
const size_t blocks_for_end_align = (util::AlignUp(GetInteger(addr) + size, PageSize) != it->GetEndAddress()) ? 1 : 0;
|
||||
const size_t blocks_for_end_align = (util::AlignUp(GetInteger(addr) + size, PageSize) != info.GetEndAddress()) ? 1 : 0;
|
||||
|
||||
if (out_blocks_needed != nullptr) {
|
||||
*out_blocks_needed = blocks_for_start_align + blocks_for_end_align;
|
||||
|
@ -710,27 +712,31 @@ namespace ams::kern {
|
|||
Result KPageTableBase::CheckMemoryState(KMemoryState *out_state, KMemoryPermission *out_perm, KMemoryAttribute *out_attr, size_t *out_blocks_needed, KMemoryBlockManager::const_iterator it, KProcessAddress last_addr, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr, u32 ignore_attr) const {
|
||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
/* Get information about the first block. */
|
||||
KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
/* Validate all blocks in the range have correct state. */
|
||||
const KMemoryState first_state = it->GetState();
|
||||
const KMemoryPermission first_perm = it->GetPermission();
|
||||
const KMemoryAttribute first_attr = it->GetAttribute();
|
||||
const KMemoryState first_state = info.m_state;
|
||||
const KMemoryPermission first_perm = info.m_permission;
|
||||
const KMemoryAttribute first_attr = info.m_attribute;
|
||||
while (true) {
|
||||
/* Validate the current block. */
|
||||
R_UNLESS(it->GetState() == first_state, svc::ResultInvalidCurrentMemory());
|
||||
R_UNLESS(it->GetPermission() == first_perm, svc::ResultInvalidCurrentMemory());
|
||||
R_UNLESS((it->GetAttribute() | ignore_attr) == (first_attr | ignore_attr), svc::ResultInvalidCurrentMemory());
|
||||
R_UNLESS(info.m_state == first_state, svc::ResultInvalidCurrentMemory());
|
||||
R_UNLESS(info.m_permission == first_perm, svc::ResultInvalidCurrentMemory());
|
||||
R_UNLESS((info.m_attribute | ignore_attr) == (first_attr | ignore_attr), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
/* Validate against the provided masks. */
|
||||
R_TRY(this->CheckMemoryState(it, state_mask, state, perm_mask, perm, attr_mask, attr));
|
||||
R_TRY(this->CheckMemoryState(info, state_mask, state, perm_mask, perm, attr_mask, attr));
|
||||
|
||||
/* Break once we're done. */
|
||||
if (last_addr <= it->GetLastAddress()) {
|
||||
if (last_addr <= info.GetLastAddress()) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Advance our iterator. */
|
||||
it++;
|
||||
MESOSPHERE_ASSERT(it != m_memory_block_manager.cend());
|
||||
info = it->GetMemoryInfo();
|
||||
}
|
||||
|
||||
/* Write output state. */
|
||||
|
@ -746,7 +752,7 @@ namespace ams::kern {
|
|||
|
||||
/* If the end address isn't aligned, we need a block. */
|
||||
if (out_blocks_needed != nullptr) {
|
||||
const size_t blocks_for_end_align = (util::AlignDown(GetInteger(last_addr), PageSize) + PageSize != it->GetEndAddress()) ? 1 : 0;
|
||||
const size_t blocks_for_end_align = (util::AlignDown(GetInteger(last_addr), PageSize) + PageSize != info.GetEndAddress()) ? 1 : 0;
|
||||
*out_blocks_needed = blocks_for_end_align;
|
||||
}
|
||||
|
||||
|
@ -1170,14 +1176,17 @@ namespace ams::kern {
|
|||
{
|
||||
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(dst_address);
|
||||
while (true) {
|
||||
/* Get the memory info. */
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
/* Check if the memory has code flag. */
|
||||
if ((it->GetState() & KMemoryState_FlagCode) != 0) {
|
||||
if ((info.GetState() & KMemoryState_FlagCode) != 0) {
|
||||
any_code_pages = true;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if we're done. */
|
||||
if (dst_address + size - 1 <= it->GetLastAddress()) {
|
||||
if (dst_address + size - 1 <= info.GetLastAddress()) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1346,13 +1355,14 @@ namespace ams::kern {
|
|||
const size_t random_offset = KSystemControl::GenerateRandomRange(0, (region_num_pages - num_pages - guard_pages) * PageSize / alignment) * alignment;
|
||||
const KProcessAddress candidate = util::AlignDown(GetInteger(region_start + random_offset), alignment) + offset;
|
||||
|
||||
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(candidate);
|
||||
MESOSPHERE_ABORT_UNLESS(it != m_memory_block_manager.end());
|
||||
KMemoryInfo info;
|
||||
ams::svc::PageInfo page_info;
|
||||
MESOSPHERE_R_ABORT_UNLESS(this->QueryInfoImpl(std::addressof(info), std::addressof(page_info), candidate));
|
||||
|
||||
if (it->GetState() != KMemoryState_Free) { continue; }
|
||||
if (info.m_state != KMemoryState_Free) { continue; }
|
||||
if (!(region_start <= candidate)) { continue; }
|
||||
if (!(it->GetAddress() + guard_pages * PageSize <= GetInteger(candidate))) { continue; }
|
||||
if (!(candidate + (num_pages + guard_pages) * PageSize - 1 <= it->GetLastAddress())) { continue; }
|
||||
if (!(info.GetAddress() + guard_pages * PageSize <= GetInteger(candidate))) { continue; }
|
||||
if (!(candidate + (num_pages + guard_pages) * PageSize - 1 <= info.GetLastAddress())) { continue; }
|
||||
if (!(candidate + (num_pages + guard_pages) * PageSize - 1 <= region_start + region_num_pages * PageSize - 1)) { continue; }
|
||||
|
||||
address = candidate;
|
||||
|
@ -1383,8 +1393,10 @@ namespace ams::kern {
|
|||
/* Iterate, counting blocks with the desired state. */
|
||||
size_t total_size = 0;
|
||||
for (KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(m_address_space_start); it != m_memory_block_manager.end(); ++it) {
|
||||
if (it->GetState() == state) {
|
||||
total_size += it->GetSize();
|
||||
/* Get the memory info. */
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
if (info.GetState() == state) {
|
||||
total_size += info.GetSize();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1476,14 +1488,17 @@ namespace ams::kern {
|
|||
/* Check that the iterator is valid. */
|
||||
MESOSPHERE_ASSERT(it != m_memory_block_manager.end());
|
||||
|
||||
/* Get the memory info. */
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
/* Determine the range to map. */
|
||||
KProcessAddress map_address = std::max(GetInteger(it->GetAddress()), GetInteger(start_address));
|
||||
const KProcessAddress map_end_address = std::min(GetInteger(it->GetEndAddress()), GetInteger(end_address));
|
||||
KProcessAddress map_address = std::max(info.GetAddress(), GetInteger(start_address));
|
||||
const KProcessAddress map_end_address = std::min(info.GetEndAddress(), GetInteger(end_address));
|
||||
MESOSPHERE_ABORT_UNLESS(map_end_address != map_address);
|
||||
|
||||
/* Determine if we should disable head merge. */
|
||||
const bool disable_head_merge = it->GetAddress() >= GetInteger(start_address) && (it->GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Normal) != 0;
|
||||
const KPageProperties map_properties = { it->GetPermission(), false, false, disable_head_merge ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None };
|
||||
const bool disable_head_merge = info.GetAddress() >= GetInteger(start_address) && (info.GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Normal) != 0;
|
||||
const KPageProperties map_properties = { info.GetPermission(), false, false, disable_head_merge ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None };
|
||||
|
||||
/* While we have pages to map, map them. */
|
||||
size_t map_pages = (map_end_address - map_address) / PageSize;
|
||||
|
@ -1512,7 +1527,7 @@ namespace ams::kern {
|
|||
}
|
||||
|
||||
/* Check if we're done. */
|
||||
if (last_address <= it->GetLastAddress()) {
|
||||
if (last_address <= info.GetLastAddress()) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -2017,18 +2032,19 @@ namespace ams::kern {
|
|||
address = util::AlignDown(GetInteger(address), PageSize);
|
||||
|
||||
/* Verify that we can query the address. */
|
||||
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(address);
|
||||
R_UNLESS(it != m_memory_block_manager.end(), svc::ResultInvalidCurrentMemory());
|
||||
KMemoryInfo info;
|
||||
ams::svc::PageInfo page_info;
|
||||
R_TRY(this->QueryInfoImpl(std::addressof(info), std::addressof(page_info), address));
|
||||
|
||||
/* Check the memory state. */
|
||||
R_TRY(this->CheckMemoryState(it, KMemoryState_FlagCanQueryPhysical, KMemoryState_FlagCanQueryPhysical, KMemoryPermission_UserReadExecute, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||
R_TRY(this->CheckMemoryState(info, KMemoryState_FlagCanQueryPhysical, KMemoryState_FlagCanQueryPhysical, KMemoryPermission_UserReadExecute, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||
|
||||
/* Prepare to traverse. */
|
||||
KPhysicalAddress phys_addr;
|
||||
size_t phys_size;
|
||||
|
||||
KProcessAddress virt_addr = it->GetAddress();
|
||||
KProcessAddress end_addr = it->GetEndAddress();
|
||||
KProcessAddress virt_addr = info.GetAddress();
|
||||
KProcessAddress end_addr = info.GetEndAddress();
|
||||
|
||||
/* Perform traversal. */
|
||||
{
|
||||
|
@ -2695,37 +2711,18 @@ namespace ams::kern {
|
|||
R_RETURN(cpu::InvalidateDataCache(GetVoidPointer(address), size));
|
||||
}
|
||||
|
||||
bool KPageTableBase::CanReadWriteDebugMemory(KProcessAddress address, size_t size, bool force_debug_prod) {
|
||||
/* Check pre-conditions. */
|
||||
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
|
||||
|
||||
/* If the memory is debuggable and user-readable, we can perform the access. */
|
||||
if (R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_FlagCanDebug, KMemoryState_FlagCanDebug, KMemoryPermission_NotMapped | KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None))) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* If we're in debug mode, and the process isn't force debug prod, check if the memory is debuggable and kernel-readable and user-executable. */
|
||||
if (KTargetSystem::IsDebugMode() && !force_debug_prod) {
|
||||
if (R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_FlagCanDebug, KMemoryState_FlagCanDebug, KMemoryPermission_KernelRead | KMemoryPermission_UserExecute, KMemoryPermission_KernelRead | KMemoryPermission_UserExecute, KMemoryAttribute_None, KMemoryAttribute_None))) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* If neither of the above checks passed, we can't access the memory. */
|
||||
return false;
|
||||
}
|
||||
|
||||
Result KPageTableBase::ReadDebugMemory(void *buffer, KProcessAddress address, size_t size, bool force_debug_prod) {
|
||||
Result KPageTableBase::ReadDebugMemory(void *buffer, KProcessAddress address, size_t size) {
|
||||
/* Lightly validate the region is in range. */
|
||||
R_UNLESS(this->Contains(address, size), svc::ResultInvalidCurrentMemory());
|
||||
|
||||
/* Lock the table. */
|
||||
KScopedLightLock lk(m_general_lock);
|
||||
|
||||
/* Require that the memory either be user-readable-and-mapped or debug-accessible. */
|
||||
const bool can_read = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_None, KMemoryState_None, KMemoryPermission_NotMapped | KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||
/* Require that the memory either be user readable or debuggable. */
|
||||
const bool can_read = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_None, KMemoryState_None, KMemoryPermission_UserRead, KMemoryPermission_UserRead, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||
if (!can_read) {
|
||||
R_UNLESS(this->CanReadWriteDebugMemory(address, size, force_debug_prod), svc::ResultInvalidCurrentMemory());
|
||||
const bool can_debug = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_FlagCanDebug, KMemoryState_FlagCanDebug, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||
R_UNLESS(can_debug, svc::ResultInvalidCurrentMemory());
|
||||
}
|
||||
|
||||
/* Get the impl. */
|
||||
|
@ -2807,10 +2804,11 @@ namespace ams::kern {
|
|||
/* Lock the table. */
|
||||
KScopedLightLock lk(m_general_lock);
|
||||
|
||||
/* Require that the memory either be user-writable-and-mapped or debug-accessible. */
|
||||
const bool can_write = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_None, KMemoryState_None, KMemoryPermission_NotMapped | KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||
if (!can_write) {
|
||||
R_UNLESS(this->CanReadWriteDebugMemory(address, size, false), svc::ResultInvalidCurrentMemory());
|
||||
/* Require that the memory either be user writable or debuggable. */
|
||||
const bool can_read = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_None, KMemoryState_None, KMemoryPermission_UserReadWrite, KMemoryPermission_UserReadWrite, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||
if (!can_read) {
|
||||
const bool can_debug = R_SUCCEEDED(this->CheckMemoryStateContiguous(address, size, KMemoryState_FlagCanDebug, KMemoryState_FlagCanDebug, KMemoryPermission_None, KMemoryPermission_None, KMemoryAttribute_None, KMemoryAttribute_None));
|
||||
R_UNLESS(can_debug, svc::ResultInvalidCurrentMemory());
|
||||
}
|
||||
|
||||
/* Get the impl. */
|
||||
|
@ -3856,25 +3854,27 @@ namespace ams::kern {
|
|||
/* Iterate, mapping as needed. */
|
||||
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(aligned_src_start);
|
||||
while (true) {
|
||||
/* Validate the current block. */
|
||||
R_TRY(this->CheckMemoryState(it, test_state, test_state, test_perm, test_perm, test_attr_mask, KMemoryAttribute_None));
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
if (mapping_src_start < mapping_src_end && GetInteger(mapping_src_start) < GetInteger(it->GetEndAddress()) && GetInteger(it->GetAddress()) < GetInteger(mapping_src_end)) {
|
||||
const auto cur_start = it->GetAddress() >= GetInteger(mapping_src_start) ? GetInteger(it->GetAddress()) : GetInteger(mapping_src_start);
|
||||
const auto cur_end = mapping_src_last >= GetInteger(it->GetLastAddress()) ? GetInteger(it->GetEndAddress()) : GetInteger(mapping_src_end);
|
||||
/* Validate the current block. */
|
||||
R_TRY(this->CheckMemoryState(info, test_state, test_state, test_perm, test_perm, test_attr_mask, KMemoryAttribute_None));
|
||||
|
||||
if (mapping_src_start < mapping_src_end && GetInteger(mapping_src_start) < info.GetEndAddress() && info.GetAddress() < GetInteger(mapping_src_end)) {
|
||||
const auto cur_start = info.GetAddress() >= GetInteger(mapping_src_start) ? info.GetAddress() : GetInteger(mapping_src_start);
|
||||
const auto cur_end = mapping_src_last >= info.GetLastAddress() ? info.GetEndAddress() : GetInteger(mapping_src_end);
|
||||
const size_t cur_size = cur_end - cur_start;
|
||||
|
||||
if (GetInteger(it->GetAddress()) < GetInteger(mapping_src_start)) {
|
||||
if (info.GetAddress() < GetInteger(mapping_src_start)) {
|
||||
++blocks_needed;
|
||||
}
|
||||
if (mapping_src_last < GetInteger(it->GetLastAddress())) {
|
||||
if (mapping_src_last < info.GetLastAddress()) {
|
||||
++blocks_needed;
|
||||
}
|
||||
|
||||
/* Set the permissions on the block, if we need to. */
|
||||
if ((it->GetPermission() & KMemoryPermission_IpcLockChangeMask) != src_perm) {
|
||||
const DisableMergeAttribute head_body_attr = (GetInteger(mapping_src_start) >= GetInteger(it->GetAddress())) ? DisableMergeAttribute_DisableHeadAndBody : DisableMergeAttribute_None;
|
||||
const DisableMergeAttribute tail_attr = (cur_end == GetInteger(mapping_src_end)) ? DisableMergeAttribute_DisableTail : DisableMergeAttribute_None;
|
||||
if ((info.GetPermission() & KMemoryPermission_IpcLockChangeMask) != src_perm) {
|
||||
const DisableMergeAttribute head_body_attr = (GetInteger(mapping_src_start) >= info.GetAddress()) ? DisableMergeAttribute_DisableHeadAndBody : DisableMergeAttribute_None;
|
||||
const DisableMergeAttribute tail_attr = (cur_end == GetInteger(mapping_src_end)) ? DisableMergeAttribute_DisableTail : DisableMergeAttribute_None;
|
||||
const KPageProperties properties = { src_perm, false, false, static_cast<DisableMergeAttribute>(head_body_attr | tail_attr) };
|
||||
R_TRY(this->Operate(page_list, cur_start, cur_size / PageSize, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, false));
|
||||
}
|
||||
|
@ -3884,7 +3884,7 @@ namespace ams::kern {
|
|||
}
|
||||
|
||||
/* If the block is at the end, we're done. */
|
||||
if (aligned_src_last <= GetInteger(it->GetLastAddress())) {
|
||||
if (aligned_src_last <= info.GetLastAddress()) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4248,50 +4248,56 @@ namespace ams::kern {
|
|||
const auto mapped_last = mapped_end - 1;
|
||||
|
||||
/* Get current and next iterators. */
|
||||
KMemoryBlockManager::const_iterator cur_it = m_memory_block_manager.FindIterator(mapping_start);
|
||||
KMemoryBlockManager::const_iterator next_it = cur_it;
|
||||
KMemoryBlockManager::const_iterator start_it = m_memory_block_manager.FindIterator(mapping_start);
|
||||
KMemoryBlockManager::const_iterator next_it = start_it;
|
||||
++next_it;
|
||||
|
||||
/* Get the current block info. */
|
||||
KMemoryInfo cur_info = start_it->GetMemoryInfo();
|
||||
|
||||
/* Create tracking variables. */
|
||||
KProcessAddress cur_address = cur_it->GetAddress();
|
||||
size_t cur_size = cur_it->GetSize();
|
||||
bool cur_perm_eq = cur_it->GetPermission() == cur_it->GetOriginalPermission();
|
||||
bool cur_needs_set_perm = !cur_perm_eq && cur_it->GetIpcLockCount() == 1;
|
||||
bool first = cur_it->GetIpcDisableMergeCount() == 1 && (cur_it->GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Locked) == 0;
|
||||
KProcessAddress cur_address = cur_info.GetAddress();
|
||||
size_t cur_size = cur_info.GetSize();
|
||||
bool cur_perm_eq = cur_info.GetPermission() == cur_info.GetOriginalPermission();
|
||||
bool cur_needs_set_perm = !cur_perm_eq && cur_info.GetIpcLockCount() == 1;
|
||||
bool first = cur_info.GetIpcDisableMergeCount() == 1 && (cur_info.GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Locked) == 0;
|
||||
|
||||
while ((GetInteger(cur_address) + cur_size - 1) < mapped_last) {
|
||||
/* Check that we have a next block. */
|
||||
MESOSPHERE_ABORT_UNLESS(next_it != m_memory_block_manager.end());
|
||||
|
||||
/* Get the next info. */
|
||||
const KMemoryInfo next_info = next_it->GetMemoryInfo();
|
||||
|
||||
/* Check if we can consolidate the next block's permission set with the current one. */
|
||||
const bool next_perm_eq = next_it->GetPermission() == next_it->GetOriginalPermission();
|
||||
const bool next_needs_set_perm = !next_perm_eq && next_it->GetIpcLockCount() == 1;
|
||||
if (cur_perm_eq == next_perm_eq && cur_needs_set_perm == next_needs_set_perm && cur_it->GetOriginalPermission() == next_it->GetOriginalPermission()) {
|
||||
const bool next_perm_eq = next_info.GetPermission() == next_info.GetOriginalPermission();
|
||||
const bool next_needs_set_perm = !next_perm_eq && next_info.GetIpcLockCount() == 1;
|
||||
if (cur_perm_eq == next_perm_eq && cur_needs_set_perm == next_needs_set_perm && cur_info.GetOriginalPermission() == next_info.GetOriginalPermission()) {
|
||||
/* We can consolidate the reprotection for the current and next block into a single call. */
|
||||
cur_size += next_it->GetSize();
|
||||
cur_size += next_info.GetSize();
|
||||
} else {
|
||||
/* We have to operate on the current block. */
|
||||
if ((cur_needs_set_perm || first) && !cur_perm_eq) {
|
||||
const KPageProperties properties = { cur_it->GetPermission(), false, false, first ? DisableMergeAttribute_EnableAndMergeHeadBodyTail : DisableMergeAttribute_None };
|
||||
const KPageProperties properties = { cur_info.GetPermission(), false, false, first ? DisableMergeAttribute_EnableAndMergeHeadBodyTail : DisableMergeAttribute_None };
|
||||
MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), cur_address, cur_size / PageSize, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, true));
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
cur_address = next_it->GetAddress();
|
||||
cur_size = next_it->GetSize();
|
||||
cur_address = next_info.GetAddress();
|
||||
cur_size = next_info.GetSize();
|
||||
first = false;
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
cur_info = next_info;
|
||||
cur_perm_eq = next_perm_eq;
|
||||
cur_needs_set_perm = next_needs_set_perm;
|
||||
|
||||
cur_it = next_it++;
|
||||
++next_it;
|
||||
}
|
||||
|
||||
/* Process the last block. */
|
||||
if ((first || cur_needs_set_perm) && !cur_perm_eq) {
|
||||
const KPageProperties properties = { cur_it->GetPermission(), false, false, first ? DisableMergeAttribute_EnableAndMergeHeadBodyTail : DisableMergeAttribute_None };
|
||||
const KPageProperties properties = { cur_info.GetPermission(), false, false, first ? DisableMergeAttribute_EnableAndMergeHeadBodyTail : DisableMergeAttribute_None };
|
||||
MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), cur_address, cur_size / PageSize, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, true));
|
||||
}
|
||||
}
|
||||
|
@ -4300,37 +4306,41 @@ namespace ams::kern {
|
|||
/* Iterate, reprotecting as needed. */
|
||||
{
|
||||
/* Get current and next iterators. */
|
||||
KMemoryBlockManager::const_iterator cur_it = m_memory_block_manager.FindIterator(mapping_start);
|
||||
KMemoryBlockManager::const_iterator next_it = cur_it;
|
||||
KMemoryBlockManager::const_iterator start_it = m_memory_block_manager.FindIterator(mapping_start);
|
||||
KMemoryBlockManager::const_iterator next_it = start_it;
|
||||
++next_it;
|
||||
|
||||
/* Validate the current block. */
|
||||
MESOSPHERE_R_ABORT_UNLESS(this->CheckMemoryState(cur_it, test_state, test_state, KMemoryPermission_None, KMemoryPermission_None, test_attr_mask | KMemoryAttribute_IpcLocked, KMemoryAttribute_IpcLocked));
|
||||
KMemoryInfo cur_info = start_it->GetMemoryInfo();
|
||||
MESOSPHERE_R_ABORT_UNLESS(this->CheckMemoryState(cur_info, test_state, test_state, KMemoryPermission_None, KMemoryPermission_None, test_attr_mask | KMemoryAttribute_IpcLocked, KMemoryAttribute_IpcLocked));
|
||||
|
||||
/* Create tracking variables. */
|
||||
KProcessAddress cur_address = cur_it->GetAddress();
|
||||
size_t cur_size = cur_it->GetSize();
|
||||
bool cur_perm_eq = cur_it->GetPermission() == cur_it->GetOriginalPermission();
|
||||
bool cur_needs_set_perm = !cur_perm_eq && cur_it->GetIpcLockCount() == 1;
|
||||
bool first = cur_it->GetIpcDisableMergeCount() == 1 && (cur_it->GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Locked) == 0;
|
||||
KProcessAddress cur_address = cur_info.GetAddress();
|
||||
size_t cur_size = cur_info.GetSize();
|
||||
bool cur_perm_eq = cur_info.GetPermission() == cur_info.GetOriginalPermission();
|
||||
bool cur_needs_set_perm = !cur_perm_eq && cur_info.GetIpcLockCount() == 1;
|
||||
bool first = cur_info.GetIpcDisableMergeCount() == 1 && (cur_info.GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute_Locked) == 0;
|
||||
|
||||
while ((cur_address + cur_size - 1) < mapping_last) {
|
||||
/* Check that we have a next block. */
|
||||
MESOSPHERE_ABORT_UNLESS(next_it != m_memory_block_manager.end());
|
||||
|
||||
/* Get the next info. */
|
||||
const KMemoryInfo next_info = next_it->GetMemoryInfo();
|
||||
|
||||
/* Validate the next block. */
|
||||
MESOSPHERE_R_ABORT_UNLESS(this->CheckMemoryState(next_it, test_state, test_state, KMemoryPermission_None, KMemoryPermission_None, test_attr_mask | KMemoryAttribute_IpcLocked, KMemoryAttribute_IpcLocked));
|
||||
MESOSPHERE_R_ABORT_UNLESS(this->CheckMemoryState(next_info, test_state, test_state, KMemoryPermission_None, KMemoryPermission_None, test_attr_mask | KMemoryAttribute_IpcLocked, KMemoryAttribute_IpcLocked));
|
||||
|
||||
/* Check if we can consolidate the next block's permission set with the current one. */
|
||||
const bool next_perm_eq = next_it->GetPermission() == next_it->GetOriginalPermission();
|
||||
const bool next_needs_set_perm = !next_perm_eq && next_it->GetIpcLockCount() == 1;
|
||||
if (cur_perm_eq == next_perm_eq && cur_needs_set_perm == next_needs_set_perm && cur_it->GetOriginalPermission() == next_it->GetOriginalPermission()) {
|
||||
const bool next_perm_eq = next_info.GetPermission() == next_info.GetOriginalPermission();
|
||||
const bool next_needs_set_perm = !next_perm_eq && next_info.GetIpcLockCount() == 1;
|
||||
if (cur_perm_eq == next_perm_eq && cur_needs_set_perm == next_needs_set_perm && cur_info.GetOriginalPermission() == next_info.GetOriginalPermission()) {
|
||||
/* We can consolidate the reprotection for the current and next block into a single call. */
|
||||
cur_size += next_it->GetSize();
|
||||
cur_size += next_info.GetSize();
|
||||
} else {
|
||||
/* We have to operate on the current block. */
|
||||
if ((cur_needs_set_perm || first) && !cur_perm_eq) {
|
||||
const KPageProperties properties = { cur_needs_set_perm ? cur_it->GetOriginalPermission() : cur_it->GetPermission(), false, false, first ? DisableMergeAttribute_EnableHeadAndBody : DisableMergeAttribute_None };
|
||||
const KPageProperties properties = { cur_needs_set_perm ? cur_info.GetOriginalPermission() : cur_info.GetPermission(), false, false, first ? DisableMergeAttribute_EnableHeadAndBody : DisableMergeAttribute_None };
|
||||
R_TRY(this->Operate(updater.GetPageList(), cur_address, cur_size / PageSize, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, false));
|
||||
}
|
||||
|
||||
|
@ -4338,24 +4348,24 @@ namespace ams::kern {
|
|||
mapped_size += cur_size;
|
||||
|
||||
/* Advance. */
|
||||
cur_address = next_it->GetAddress();
|
||||
cur_size = next_it->GetSize();
|
||||
cur_address = next_info.GetAddress();
|
||||
cur_size = next_info.GetSize();
|
||||
first = false;
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
cur_info = next_info;
|
||||
cur_perm_eq = next_perm_eq;
|
||||
cur_needs_set_perm = next_needs_set_perm;
|
||||
|
||||
cur_it = next_it++;
|
||||
++next_it;
|
||||
}
|
||||
|
||||
/* Process the last block. */
|
||||
const auto lock_count = cur_it->GetIpcLockCount() + (next_it != m_memory_block_manager.end() ? (next_it->GetIpcDisableMergeCount() - next_it->GetIpcLockCount()) : 0);
|
||||
const auto lock_count = cur_info.GetIpcLockCount() + (next_it != m_memory_block_manager.end() ? (next_it->GetIpcDisableMergeCount() - next_it->GetIpcLockCount()) : 0);
|
||||
if ((first || cur_needs_set_perm || (lock_count == 1)) && !cur_perm_eq) {
|
||||
const DisableMergeAttribute head_body_attr = first ? DisableMergeAttribute_EnableHeadAndBody : DisableMergeAttribute_None;
|
||||
const DisableMergeAttribute tail_attr = lock_count == 1 ? DisableMergeAttribute_EnableTail : DisableMergeAttribute_None;
|
||||
const KPageProperties properties = { cur_needs_set_perm ? cur_it->GetOriginalPermission() : cur_it->GetPermission(), false, false, static_cast<DisableMergeAttribute>(head_body_attr | tail_attr) };
|
||||
const KPageProperties properties = { cur_needs_set_perm ? cur_info.GetOriginalPermission() : cur_info.GetPermission(), false, false, static_cast<DisableMergeAttribute>(head_body_attr | tail_attr) };
|
||||
R_TRY(this->Operate(updater.GetPageList(), cur_address, cur_size / PageSize, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, false));
|
||||
}
|
||||
}
|
||||
|
@ -4388,36 +4398,38 @@ namespace ams::kern {
|
|||
/* Iterate over blocks, fixing permissions. */
|
||||
KMemoryBlockManager::const_iterator it = m_memory_block_manager.FindIterator(address);
|
||||
while (true) {
|
||||
const auto cur_start = it->GetAddress() >= GetInteger(src_map_start) ? it->GetAddress() : GetInteger(src_map_start);
|
||||
const auto cur_end = src_map_last <= it->GetLastAddress() ? src_map_end : it->GetEndAddress();
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
const auto cur_start = info.GetAddress() >= GetInteger(src_map_start) ? info.GetAddress() : GetInteger(src_map_start);
|
||||
const auto cur_end = src_map_last <= info.GetLastAddress() ? src_map_end : info.GetEndAddress();
|
||||
|
||||
/* If we can, fix the protections on the block. */
|
||||
if ((it->GetIpcLockCount() == 0 && (it->GetPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm) ||
|
||||
(it->GetIpcLockCount() != 0 && (it->GetOriginalPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm))
|
||||
if ((info.GetIpcLockCount() == 0 && (info.GetPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm) ||
|
||||
(info.GetIpcLockCount() != 0 && (info.GetOriginalPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm))
|
||||
{
|
||||
/* Check if we actually need to fix the protections on the block. */
|
||||
if (cur_end == src_map_end || it->GetAddress() <= GetInteger(src_map_start) || (it->GetPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm) {
|
||||
const bool start_nc = (it->GetAddress() == GetInteger(src_map_start)) ? ((it->GetDisableMergeAttribute() & (KMemoryBlockDisableMergeAttribute_Locked | KMemoryBlockDisableMergeAttribute_IpcLeft)) == 0) : it->GetAddress() <= GetInteger(src_map_start);
|
||||
if (cur_end == src_map_end || info.GetAddress() <= GetInteger(src_map_start) || (info.GetPermission() & KMemoryPermission_IpcLockChangeMask) != prot_perm) {
|
||||
const bool start_nc = (info.GetAddress() == GetInteger(src_map_start)) ? ((info.GetDisableMergeAttribute() & (KMemoryBlockDisableMergeAttribute_Locked | KMemoryBlockDisableMergeAttribute_IpcLeft)) == 0) : info.GetAddress() <= GetInteger(src_map_start);
|
||||
|
||||
const DisableMergeAttribute head_body_attr = start_nc ? DisableMergeAttribute_EnableHeadAndBody : DisableMergeAttribute_None;
|
||||
DisableMergeAttribute tail_attr;
|
||||
if (cur_end == src_map_end && it->GetEndAddress() == src_map_end) {
|
||||
if (cur_end == src_map_end && info.GetEndAddress() == src_map_end) {
|
||||
auto next_it = it;
|
||||
++next_it;
|
||||
|
||||
const auto lock_count = it->GetIpcLockCount() + (next_it != m_memory_block_manager.end() ? (next_it->GetIpcDisableMergeCount() - next_it->GetIpcLockCount()) : 0);
|
||||
const auto lock_count = info.GetIpcLockCount() + (next_it != m_memory_block_manager.end() ? (next_it->GetIpcDisableMergeCount() - next_it->GetIpcLockCount()) : 0);
|
||||
tail_attr = lock_count == 0 ? DisableMergeAttribute_EnableTail : DisableMergeAttribute_None;
|
||||
} else {
|
||||
tail_attr = DisableMergeAttribute_None;
|
||||
}
|
||||
|
||||
const KPageProperties properties = { it->GetPermission(), false, false, static_cast<DisableMergeAttribute>(head_body_attr | tail_attr) };
|
||||
const KPageProperties properties = { info.GetPermission(), false, false, static_cast<DisableMergeAttribute>(head_body_attr | tail_attr) };
|
||||
MESOSPHERE_R_ABORT_UNLESS(this->Operate(page_list, cur_start, (cur_end - cur_start) / PageSize, Null<KPhysicalAddress>, false, properties, OperationType_ChangePermissions, true));
|
||||
}
|
||||
}
|
||||
|
||||
/* If we're past the end of the region, we're done. */
|
||||
if (src_map_last <= it->GetLastAddress()) {
|
||||
if (src_map_last <= info.GetLastAddress()) {
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4456,21 +4468,24 @@ namespace ams::kern {
|
|||
/* Check that the iterator is valid. */
|
||||
MESOSPHERE_ASSERT(it != m_memory_block_manager.end());
|
||||
|
||||
/* Get the memory info. */
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
/* Check if we're done. */
|
||||
if (last_address <= it->GetLastAddress()) {
|
||||
if (it->GetState() != KMemoryState_Free) {
|
||||
if (last_address <= info.GetLastAddress()) {
|
||||
if (info.GetState() != KMemoryState_Free) {
|
||||
mapped_size += (last_address + 1 - cur_address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Track the memory if it's mapped. */
|
||||
if (it->GetState() != KMemoryState_Free) {
|
||||
mapped_size += it->GetEndAddress() - cur_address;
|
||||
if (info.GetState() != KMemoryState_Free) {
|
||||
mapped_size += KProcessAddress(info.GetEndAddress()) - cur_address;
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
cur_address = it->GetEndAddress();
|
||||
cur_address = info.GetEndAddress();
|
||||
++it;
|
||||
}
|
||||
|
||||
|
@ -4512,18 +4527,21 @@ namespace ams::kern {
|
|||
/* Check that the iterator is valid. */
|
||||
MESOSPHERE_ASSERT(it != m_memory_block_manager.end());
|
||||
|
||||
const bool is_free = it->GetState() == KMemoryState_Free;
|
||||
/* Get the memory info. */
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
const bool is_free = info.GetState() == KMemoryState_Free;
|
||||
if (is_free) {
|
||||
if (it->GetAddress() < GetInteger(address)) {
|
||||
if (info.GetAddress() < GetInteger(address)) {
|
||||
++num_allocator_blocks;
|
||||
}
|
||||
if (last_address < it->GetLastAddress()) {
|
||||
if (last_address < info.GetLastAddress()) {
|
||||
++num_allocator_blocks;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we're done. */
|
||||
if (last_address <= it->GetLastAddress()) {
|
||||
if (last_address <= info.GetLastAddress()) {
|
||||
if (!is_free) {
|
||||
checked_mapped_size += (last_address + 1 - cur_address);
|
||||
}
|
||||
|
@ -4532,11 +4550,11 @@ namespace ams::kern {
|
|||
|
||||
/* Track the memory if it's mapped. */
|
||||
if (!is_free) {
|
||||
checked_mapped_size += it->GetEndAddress() - cur_address;
|
||||
checked_mapped_size += KProcessAddress(info.GetEndAddress()) - cur_address;
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
cur_address = it->GetEndAddress();
|
||||
cur_address = info.GetEndAddress();
|
||||
++it;
|
||||
}
|
||||
|
||||
|
@ -4576,23 +4594,26 @@ namespace ams::kern {
|
|||
/* Check that the iterator is valid. */
|
||||
MESOSPHERE_ASSERT(it != m_memory_block_manager.end());
|
||||
|
||||
/* Get the memory info. */
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
/* If the memory state is free, we mapped it and need to unmap it. */
|
||||
if (it->GetState() == KMemoryState_Free) {
|
||||
if (info.GetState() == KMemoryState_Free) {
|
||||
/* Determine the range to unmap. */
|
||||
const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None };
|
||||
const size_t cur_pages = std::min(it->GetEndAddress() - cur_address, last_unmap_address + 1 - cur_address) / PageSize;
|
||||
const size_t cur_pages = std::min(KProcessAddress(info.GetEndAddress()) - cur_address, last_unmap_address + 1 - cur_address) / PageSize;
|
||||
|
||||
/* Unmap. */
|
||||
MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), cur_address, cur_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, true));
|
||||
}
|
||||
|
||||
/* Check if we're done. */
|
||||
if (last_unmap_address <= it->GetLastAddress()) {
|
||||
if (last_unmap_address <= info.GetLastAddress()) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
cur_address = it->GetEndAddress();
|
||||
cur_address = info.GetEndAddress();
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
@ -4611,11 +4632,14 @@ namespace ams::kern {
|
|||
/* Check that the iterator is valid. */
|
||||
MESOSPHERE_ASSERT(it != m_memory_block_manager.end());
|
||||
|
||||
/* Get the memory info. */
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
/* If it's unmapped, we need to map it. */
|
||||
if (it->GetState() == KMemoryState_Free) {
|
||||
if (info.GetState() == KMemoryState_Free) {
|
||||
/* Determine the range to map. */
|
||||
const KPageProperties map_properties = { KMemoryPermission_UserReadWrite, false, false, cur_address == this->GetAliasRegionStart() ? DisableMergeAttribute_DisableHead : DisableMergeAttribute_None };
|
||||
size_t map_pages = std::min(it->GetEndAddress() - cur_address, last_address + 1 - cur_address) / PageSize;
|
||||
size_t map_pages = std::min(KProcessAddress(info.GetEndAddress()) - cur_address, last_address + 1 - cur_address) / PageSize;
|
||||
|
||||
/* While we have pages to map, map them. */
|
||||
{
|
||||
|
@ -4656,12 +4680,12 @@ namespace ams::kern {
|
|||
}
|
||||
|
||||
/* Check if we're done. */
|
||||
if (last_address <= it->GetLastAddress()) {
|
||||
if (last_address <= info.GetLastAddress()) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
cur_address = it->GetEndAddress();
|
||||
cur_address = info.GetEndAddress();
|
||||
++it;
|
||||
}
|
||||
|
||||
|
@ -4713,23 +4737,26 @@ namespace ams::kern {
|
|||
/* Check that the iterator is valid. */
|
||||
MESOSPHERE_ASSERT(it != m_memory_block_manager.end());
|
||||
|
||||
/* Get the memory info. */
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
/* Verify the memory's state. */
|
||||
const bool is_normal = it->GetState() == KMemoryState_Normal && it->GetAttribute() == 0;
|
||||
const bool is_free = it->GetState() == KMemoryState_Free;
|
||||
const bool is_normal = info.GetState() == KMemoryState_Normal && info.GetAttribute() == 0;
|
||||
const bool is_free = info.GetState() == KMemoryState_Free;
|
||||
R_UNLESS(is_normal || is_free, svc::ResultInvalidCurrentMemory());
|
||||
|
||||
if (is_normal) {
|
||||
R_UNLESS(it->GetAttribute() == KMemoryAttribute_None, svc::ResultInvalidCurrentMemory());
|
||||
R_UNLESS(info.GetAttribute() == KMemoryAttribute_None, svc::ResultInvalidCurrentMemory());
|
||||
|
||||
if (map_start_address == Null<KProcessAddress>) {
|
||||
map_start_address = cur_address;
|
||||
}
|
||||
map_last_address = (last_address >= it->GetLastAddress()) ? it->GetLastAddress() : last_address;
|
||||
map_last_address = (last_address >= info.GetLastAddress()) ? info.GetLastAddress() : last_address;
|
||||
|
||||
if (it->GetAddress() < GetInteger(address)) {
|
||||
if (info.GetAddress() < GetInteger(address)) {
|
||||
++num_allocator_blocks;
|
||||
}
|
||||
if (last_address < it->GetLastAddress()) {
|
||||
if (last_address < info.GetLastAddress()) {
|
||||
++num_allocator_blocks;
|
||||
}
|
||||
|
||||
|
@ -4737,12 +4764,12 @@ namespace ams::kern {
|
|||
}
|
||||
|
||||
/* Check if we're done. */
|
||||
if (last_address <= it->GetLastAddress()) {
|
||||
if (last_address <= info.GetLastAddress()) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
cur_address = it->GetEndAddress();
|
||||
cur_address = info.GetEndAddress();
|
||||
++it;
|
||||
}
|
||||
|
||||
|
@ -4775,23 +4802,26 @@ namespace ams::kern {
|
|||
/* Check that the iterator is valid. */
|
||||
MESOSPHERE_ASSERT(it != m_memory_block_manager.end());
|
||||
|
||||
/* Get the memory info. */
|
||||
const KMemoryInfo info = it->GetMemoryInfo();
|
||||
|
||||
/* If the memory state is normal, we need to unmap it. */
|
||||
if (it->GetState() == KMemoryState_Normal) {
|
||||
if (info.GetState() == KMemoryState_Normal) {
|
||||
/* Determine the range to unmap. */
|
||||
const KPageProperties unmap_properties = { KMemoryPermission_None, false, false, DisableMergeAttribute_None };
|
||||
const size_t cur_pages = std::min(it->GetEndAddress() - cur_address, last_address + 1 - cur_address) / PageSize;
|
||||
const size_t cur_pages = std::min(KProcessAddress(info.GetEndAddress()) - cur_address, last_address + 1 - cur_address) / PageSize;
|
||||
|
||||
/* Unmap. */
|
||||
MESOSPHERE_R_ABORT_UNLESS(this->Operate(updater.GetPageList(), cur_address, cur_pages, Null<KPhysicalAddress>, false, unmap_properties, OperationType_Unmap, false));
|
||||
}
|
||||
|
||||
/* Check if we're done. */
|
||||
if (last_address <= it->GetLastAddress()) {
|
||||
if (last_address <= info.GetLastAddress()) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* Advance. */
|
||||
cur_address = it->GetEndAddress();
|
||||
cur_address = info.GetEndAddress();
|
||||
++it;
|
||||
}
|
||||
|
||||
|
|
|
@ -220,8 +220,18 @@ namespace ams::kern {
|
|||
m_running_thread_switch_counts[i] = 0;
|
||||
}
|
||||
|
||||
/* Set max memory. */
|
||||
m_max_process_memory = m_page_table.GetHeapRegionSize();
|
||||
/* Set max memory based on address space type. */
|
||||
switch ((params.flags & ams::svc::CreateProcessFlag_AddressSpaceMask)) {
|
||||
case ams::svc::CreateProcessFlag_AddressSpace32Bit:
|
||||
case ams::svc::CreateProcessFlag_AddressSpace64BitDeprecated:
|
||||
case ams::svc::CreateProcessFlag_AddressSpace64Bit:
|
||||
m_max_process_memory = m_page_table.GetHeapRegionSize();
|
||||
break;
|
||||
case ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias:
|
||||
m_max_process_memory = m_page_table.GetHeapRegionSize() + m_page_table.GetAliasRegionSize();
|
||||
break;
|
||||
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
|
||||
}
|
||||
|
||||
/* Generate random entropy. */
|
||||
KSystemControl::GenerateRandom(m_entropy, util::size(m_entropy));
|
||||
|
@ -289,7 +299,7 @@ namespace ams::kern {
|
|||
/* Setup page table. */
|
||||
{
|
||||
const bool from_back = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) == 0;
|
||||
R_TRY(m_page_table.Initialize(static_cast<ams::svc::CreateProcessFlag>(params.flags), from_back, pool, params.code_address, params.code_num_pages * PageSize, m_system_resource, res_limit, this->GetSlabIndex()));
|
||||
R_TRY(m_page_table.Initialize(static_cast<ams::svc::CreateProcessFlag>(params.flags), from_back, pool, params.code_address, params.code_num_pages * PageSize, m_system_resource, res_limit));
|
||||
}
|
||||
ON_RESULT_FAILURE_2 { m_page_table.Finalize(); };
|
||||
|
||||
|
@ -368,7 +378,7 @@ namespace ams::kern {
|
|||
/* Setup page table. */
|
||||
{
|
||||
const bool from_back = (params.flags & ams::svc::CreateProcessFlag_EnableAslr) == 0;
|
||||
R_TRY(m_page_table.Initialize(static_cast<ams::svc::CreateProcessFlag>(params.flags), from_back, pool, params.code_address, code_size, m_system_resource, res_limit, this->GetSlabIndex()));
|
||||
R_TRY(m_page_table.Initialize(static_cast<ams::svc::CreateProcessFlag>(params.flags), from_back, pool, params.code_address, code_size, m_system_resource, res_limit));
|
||||
}
|
||||
ON_RESULT_FAILURE_2 { m_page_table.Finalize(); };
|
||||
|
||||
|
|
|
@ -124,14 +124,31 @@ namespace ams::kern {
|
|||
}
|
||||
|
||||
/* System Initialization. */
|
||||
void KSystemControlBase::ConfigureKTargetSystem() {
|
||||
/* By default, use the default config set in the KTargetSystem header. */
|
||||
}
|
||||
|
||||
void KSystemControlBase::InitializePhase1() {
|
||||
/* Enable KTargetSystem. */
|
||||
/* Configure KTargetSystem. */
|
||||
{
|
||||
KTargetSystem::SetInitialized();
|
||||
/* Set IsDebugMode. */
|
||||
{
|
||||
KTargetSystem::SetIsDebugMode(true);
|
||||
|
||||
/* If debug mode, we want to initialize uart logging. */
|
||||
KTargetSystem::EnableDebugLogging(true);
|
||||
}
|
||||
|
||||
/* Set Kernel Configuration. */
|
||||
{
|
||||
KTargetSystem::EnableDebugMemoryFill(false);
|
||||
KTargetSystem::EnableUserExceptionHandlers(true);
|
||||
KTargetSystem::EnableDynamicResourceLimits(true);
|
||||
KTargetSystem::EnableUserPmuAccess(false);
|
||||
}
|
||||
|
||||
/* Set Kernel Debugging. */
|
||||
{
|
||||
/* NOTE: This is used to restrict access to SvcKernelDebug/SvcChangeKernelTraceState. */
|
||||
/* Mesosphere may wish to not require this, as we'd ideally keep ProgramVerification enabled for userland. */
|
||||
KTargetSystem::EnableKernelDebugging(true);
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize random and resource limit. */
|
||||
|
|
|
@ -41,22 +41,17 @@ namespace ams::kern::svc {
|
|||
case ams::svc::ArbitrationType_WaitIfLessThan:
|
||||
case ams::svc::ArbitrationType_DecrementAndWaitIfLessThan:
|
||||
case ams::svc::ArbitrationType_WaitIfEqual:
|
||||
case ams::svc::ArbitrationType_WaitIfEqual64:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Result WaitForAddress(uintptr_t address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) {
|
||||
Result WaitForAddress(uintptr_t address, ams::svc::ArbitrationType arb_type, int32_t value, int64_t timeout_ns) {
|
||||
/* Validate input. */
|
||||
R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory());
|
||||
if (arb_type == ams::svc::ArbitrationType_WaitIfEqual64) {
|
||||
R_UNLESS(util::IsAligned(address, sizeof(int64_t)), svc::ResultInvalidAddress());
|
||||
} else {
|
||||
R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress());
|
||||
}
|
||||
R_UNLESS(IsValidArbitrationType(arb_type), svc::ResultInvalidEnumValue());
|
||||
R_UNLESS(AMS_LIKELY(!IsKernelAddress(address)), svc::ResultInvalidCurrentMemory());
|
||||
R_UNLESS(util::IsAligned(address, sizeof(int32_t)), svc::ResultInvalidAddress());
|
||||
R_UNLESS(IsValidArbitrationType(arb_type), svc::ResultInvalidEnumValue());
|
||||
|
||||
/* Convert timeout from nanoseconds to ticks. */
|
||||
s64 timeout;
|
||||
|
@ -90,7 +85,7 @@ namespace ams::kern::svc {
|
|||
|
||||
/* ============================= 64 ABI ============================= */
|
||||
|
||||
Result WaitForAddress64(ams::svc::Address address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) {
|
||||
Result WaitForAddress64(ams::svc::Address address, ams::svc::ArbitrationType arb_type, int32_t value, int64_t timeout_ns) {
|
||||
R_RETURN(WaitForAddress(address, arb_type, value, timeout_ns));
|
||||
}
|
||||
|
||||
|
@ -100,7 +95,7 @@ namespace ams::kern::svc {
|
|||
|
||||
/* ============================= 64From32 ABI ============================= */
|
||||
|
||||
Result WaitForAddress64From32(ams::svc::Address address, ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) {
|
||||
Result WaitForAddress64From32(ams::svc::Address address, ams::svc::ArbitrationType arb_type, int32_t value, int64_t timeout_ns) {
|
||||
R_RETURN(WaitForAddress(address, arb_type, value, timeout_ns));
|
||||
}
|
||||
|
||||
|
|
|
@ -24,9 +24,6 @@ namespace ams::kern::svc {
|
|||
constexpr inline int32_t MaximumDebuggableThreadCount = 0x60;
|
||||
|
||||
Result DebugActiveProcess(ams::svc::Handle *out_handle, uint64_t process_id) {
|
||||
/* Check that the SVC can be used. */
|
||||
R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented());
|
||||
|
||||
/* Get the process from its id. */
|
||||
KProcess *process = KProcess::GetProcessFromId(process_id);
|
||||
R_UNLESS(process != nullptr, svc::ResultInvalidProcessId());
|
||||
|
@ -35,8 +32,9 @@ namespace ams::kern::svc {
|
|||
ON_SCOPE_EXIT { process->Close(); };
|
||||
|
||||
/* Check that the debugging is allowed. */
|
||||
const bool allowable = process->IsPermittedDebug() || GetCurrentProcess().CanForceDebug() || GetCurrentProcess().CanForceDebugProd();
|
||||
R_UNLESS(allowable, svc::ResultInvalidState());
|
||||
if (!process->IsPermittedDebug()) {
|
||||
R_UNLESS(GetCurrentProcess().CanForceDebug(), svc::ResultInvalidState());
|
||||
}
|
||||
|
||||
/* Disallow debugging one's own processs, to prevent softlocks. */
|
||||
R_UNLESS(process != GetCurrentProcessPointer(), svc::ResultInvalidState());
|
||||
|
@ -94,9 +92,6 @@ namespace ams::kern::svc {
|
|||
|
||||
template<typename EventInfoType>
|
||||
Result GetDebugEvent(KUserPointer<EventInfoType *> out_info, ams::svc::Handle debug_handle) {
|
||||
/* Only allow invoking the svc on development hardware or if force debug prod. */
|
||||
R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented());
|
||||
|
||||
/* Get the debug object. */
|
||||
KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle);
|
||||
R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle());
|
||||
|
@ -169,9 +164,6 @@ namespace ams::kern::svc {
|
|||
}
|
||||
|
||||
Result GetDebugThreadContext(KUserPointer<ams::svc::ThreadContext *> out_context, ams::svc::Handle debug_handle, uint64_t thread_id, uint32_t context_flags) {
|
||||
/* Only allow invoking the svc on development hardware or if force debug prod. */
|
||||
R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented());
|
||||
|
||||
/* Validate the context flags. */
|
||||
R_UNLESS((context_flags | ams::svc::ThreadContextFlag_All) == ams::svc::ThreadContextFlag_All, svc::ResultInvalidEnumValue());
|
||||
|
||||
|
@ -228,9 +220,6 @@ namespace ams::kern::svc {
|
|||
}
|
||||
|
||||
Result QueryDebugProcessMemory(ams::svc::MemoryInfo *out_memory_info, ams::svc::PageInfo *out_page_info, ams::svc::Handle debug_handle, uintptr_t address) {
|
||||
/* Only allow invoking the svc on development hardware or if force debug prod. */
|
||||
R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented());
|
||||
|
||||
/* Get the debug object. */
|
||||
KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle);
|
||||
R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle());
|
||||
|
@ -272,9 +261,6 @@ namespace ams::kern::svc {
|
|||
}
|
||||
|
||||
Result ReadDebugProcessMemory(uintptr_t buffer, ams::svc::Handle debug_handle, uintptr_t address, size_t size) {
|
||||
/* Only allow invoking the svc on development hardware or if force debug prod. */
|
||||
R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented());
|
||||
|
||||
/* Validate address / size. */
|
||||
R_UNLESS(size > 0, svc::ResultInvalidSize());
|
||||
R_UNLESS((address < address + size), svc::ResultInvalidCurrentMemory());
|
||||
|
@ -320,9 +306,6 @@ namespace ams::kern::svc {
|
|||
}
|
||||
|
||||
Result GetDebugThreadParam(uint64_t *out_64, uint32_t *out_32, ams::svc::Handle debug_handle, uint64_t thread_id, ams::svc::DebugThreadParam param) {
|
||||
/* Only allow invoking the svc on development hardware or if force debug prod. */
|
||||
R_UNLESS(KTargetSystem::IsDebugMode() || GetCurrentProcess().CanForceDebugProd(), svc::ResultNotImplemented());
|
||||
|
||||
/* Get the debug object. */
|
||||
KScopedAutoObject debug = GetCurrentProcess().GetHandleTable().GetObject<KDebug>(debug_handle);
|
||||
R_UNLESS(debug.IsNotNull(), svc::ResultInvalidHandle());
|
||||
|
|
|
@ -314,19 +314,6 @@ namespace ams::kern::svc {
|
|||
*out = io_region->GetHint();
|
||||
}
|
||||
break;
|
||||
case ams::svc::InfoType_TransferMemoryHint:
|
||||
{
|
||||
/* Verify the sub-type is valid. */
|
||||
R_UNLESS(info_subtype == 0, svc::ResultInvalidCombination());
|
||||
|
||||
/* Get the transfer memory from its handle. */
|
||||
KScopedAutoObject transfer_memory = GetCurrentProcess().GetHandleTable().GetObject<KTransferMemory>(handle);
|
||||
R_UNLESS(transfer_memory.IsNotNull(), svc::ResultInvalidHandle());
|
||||
|
||||
/* Get the transfer memory's address hint. */
|
||||
*out = transfer_memory->GetHint();
|
||||
}
|
||||
break;
|
||||
case ams::svc::InfoType_MesosphereMeta:
|
||||
{
|
||||
/* Verify the handle is invalid. */
|
||||
|
|
|
@ -71,9 +71,6 @@ namespace ams::kern::svc {
|
|||
}
|
||||
|
||||
Result GetProcessList(int32_t *out_num_processes, KUserPointer<uint64_t *> out_process_ids, int32_t max_out_count) {
|
||||
/* Only allow invoking the svc on development hardware. */
|
||||
R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented());
|
||||
|
||||
/* Validate that the out count is valid. */
|
||||
R_UNLESS((0 <= max_out_count && max_out_count <= static_cast<int32_t>(std::numeric_limits<int32_t>::max() / sizeof(u64))), svc::ResultOutOfRange());
|
||||
|
||||
|
@ -113,8 +110,8 @@ namespace ams::kern::svc {
|
|||
case ams::svc::CreateProcessFlag_AddressSpace32Bit:
|
||||
case ams::svc::CreateProcessFlag_AddressSpace32BitWithoutAlias:
|
||||
{
|
||||
map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_MapSmall);
|
||||
map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_MapSmall);
|
||||
map_start = KAddressSpaceInfo::GetAddressSpaceStart(32, KAddressSpaceInfo::Type_MapSmall);
|
||||
map_size = KAddressSpaceInfo::GetAddressSpaceSize(32, KAddressSpaceInfo::Type_MapSmall);
|
||||
map_end = map_start + map_size;
|
||||
}
|
||||
break;
|
||||
|
@ -123,8 +120,8 @@ namespace ams::kern::svc {
|
|||
/* 64-bit address space requires 64-bit process. */
|
||||
R_UNLESS(is_64_bit, svc::ResultInvalidCombination());
|
||||
|
||||
map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_MapSmall);
|
||||
map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_MapSmall);
|
||||
map_start = KAddressSpaceInfo::GetAddressSpaceStart(36, KAddressSpaceInfo::Type_MapSmall);
|
||||
map_size = KAddressSpaceInfo::GetAddressSpaceSize(36, KAddressSpaceInfo::Type_MapSmall);
|
||||
map_end = map_start + map_size;
|
||||
}
|
||||
break;
|
||||
|
@ -133,10 +130,10 @@ namespace ams::kern::svc {
|
|||
/* 64-bit address space requires 64-bit process. */
|
||||
R_UNLESS(is_64_bit, svc::ResultInvalidCombination());
|
||||
|
||||
map_start = KAddressSpaceInfo::GetAddressSpaceStart(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_Map39Bit);
|
||||
map_end = map_start + KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_Map39Bit);
|
||||
map_start = KAddressSpaceInfo::GetAddressSpaceStart(39, KAddressSpaceInfo::Type_Map39Bit);
|
||||
map_end = map_start + KAddressSpaceInfo::GetAddressSpaceSize(39, KAddressSpaceInfo::Type_Map39Bit);
|
||||
|
||||
map_size = KAddressSpaceInfo::GetAddressSpaceSize(static_cast<ams::svc::CreateProcessFlag>(params.flags), KAddressSpaceInfo::Type_Heap);
|
||||
map_size = KAddressSpaceInfo::GetAddressSpaceSize(39, KAddressSpaceInfo::Type_Heap);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
|
|
@ -217,9 +217,6 @@ namespace ams::kern::svc {
|
|||
}
|
||||
|
||||
Result GetThreadList(int32_t *out_num_threads, KUserPointer<uint64_t *> out_thread_ids, int32_t max_out_count, ams::svc::Handle debug_handle) {
|
||||
/* Only allow invoking the svc on development hardware. */
|
||||
R_UNLESS(KTargetSystem::IsDebugMode(), svc::ResultNotImplemented());
|
||||
|
||||
/* Validate that the out count is valid. */
|
||||
R_UNLESS((0 <= max_out_count && max_out_count <= static_cast<int32_t>(std::numeric_limits<int32_t>::max() / sizeof(u64))), svc::ResultOutOfRange());
|
||||
|
||||
|
@ -228,34 +225,30 @@ namespace ams::kern::svc {
|
|||
R_UNLESS(GetCurrentProcess().GetPageTable().Contains(KProcessAddress(out_thread_ids.GetUnsafePointer()), max_out_count * sizeof(u64)), svc::ResultInvalidCurrentMemory());
|
||||
}
|
||||
|
||||
/* Get the handle table. */
|
||||
auto &handle_table = GetCurrentProcess().GetHandleTable();
|
||||
|
||||
/* Try to get as a debug object. */
|
||||
KScopedAutoObject debug = handle_table.GetObject<KDebug>(debug_handle);
|
||||
if (debug.IsNotNull()) {
|
||||
/* Check that the debug object has a process. */
|
||||
R_UNLESS(debug->IsAttached(), svc::ResultProcessTerminated());
|
||||
R_UNLESS(debug->OpenProcess(), svc::ResultProcessTerminated());
|
||||
ON_SCOPE_EXIT { debug->CloseProcess(); };
|
||||
|
||||
/* Get the thread list. */
|
||||
R_TRY(debug->GetProcessUnsafe()->GetThreadList(out_num_threads, out_thread_ids, max_out_count));
|
||||
if (debug_handle == ams::svc::InvalidHandle) {
|
||||
/* If passed invalid handle, we should return the global thread list. */
|
||||
R_TRY(KThread::GetThreadList(out_num_threads, out_thread_ids, max_out_count));
|
||||
} else {
|
||||
/* Only allow getting as a process (or global) if the caller does not have ForceDebugProd. */
|
||||
R_UNLESS(!GetCurrentProcess().CanForceDebugProd(), svc::ResultInvalidHandle());
|
||||
/* Get the handle table. */
|
||||
auto &handle_table = GetCurrentProcess().GetHandleTable();
|
||||
|
||||
/* Try to get as a debug object. */
|
||||
KScopedAutoObject debug = handle_table.GetObject<KDebug>(debug_handle);
|
||||
if (debug.IsNotNull()) {
|
||||
/* Check that the debug object has a process. */
|
||||
R_UNLESS(debug->IsAttached(), svc::ResultProcessTerminated());
|
||||
R_UNLESS(debug->OpenProcess(), svc::ResultProcessTerminated());
|
||||
ON_SCOPE_EXIT { debug->CloseProcess(); };
|
||||
|
||||
/* Get the thread list. */
|
||||
R_TRY(debug->GetProcessUnsafe()->GetThreadList(out_num_threads, out_thread_ids, max_out_count));
|
||||
} else {
|
||||
/* Try to get as a process. */
|
||||
KScopedAutoObject process = handle_table.GetObjectWithoutPseudoHandle<KProcess>(debug_handle);
|
||||
R_UNLESS(process.IsNotNull(), svc::ResultInvalidHandle());
|
||||
|
||||
/* Try to get as a process. */
|
||||
KScopedAutoObject process = handle_table.GetObjectWithoutPseudoHandle<KProcess>(debug_handle);
|
||||
if (process.IsNotNull()) {
|
||||
/* Get the thread list. */
|
||||
R_TRY(process->GetThreadList(out_num_threads, out_thread_ids, max_out_count));
|
||||
} else {
|
||||
/* If the object is not a process, the caller may want the global thread list. */
|
||||
R_UNLESS(debug_handle == ams::svc::InvalidHandle, svc::ResultInvalidHandle());
|
||||
|
||||
/* If passed invalid handle, we should return the global thread list. */
|
||||
R_TRY(KThread::GetThreadList(out_num_threads, out_thread_ids, max_out_count));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -231,7 +231,7 @@
|
|||
R_RETURN(::svcGetThreadContext3(reinterpret_cast<::ThreadContext *>(out_context.GetPointerUnsafe()), thread_handle));
|
||||
}
|
||||
|
||||
ALWAYS_INLINE Result WaitForAddress(::ams::svc::Address address, ::ams::svc::ArbitrationType arb_type, int64_t value, int64_t timeout_ns) {
|
||||
ALWAYS_INLINE Result WaitForAddress(::ams::svc::Address address, ::ams::svc::ArbitrationType arb_type, int32_t value, int64_t timeout_ns) {
|
||||
R_RETURN(::svcWaitForAddress(reinterpret_cast<void *>(static_cast<uintptr_t>(address)), arb_type, value, timeout_ns));
|
||||
}
|
||||
|
||||
|
|
|
@ -67,7 +67,7 @@
|
|||
HANDLER(0x31, Result, GetResourceLimitCurrentValue, OUTPUT(int64_t, out_current_value), INPUT(::ams::svc::Handle, resource_limit_handle), INPUT(::ams::svc::LimitableResource, which)) \
|
||||
HANDLER(0x32, Result, SetThreadActivity, INPUT(::ams::svc::Handle, thread_handle), INPUT(::ams::svc::ThreadActivity, thread_activity)) \
|
||||
HANDLER(0x33, Result, GetThreadContext3, OUTPTR(::ams::svc::ThreadContext, out_context), INPUT(::ams::svc::Handle, thread_handle)) \
|
||||
HANDLER(0x34, Result, WaitForAddress, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::ArbitrationType, arb_type), INPUT(int64_t, value), INPUT(int64_t, timeout_ns)) \
|
||||
HANDLER(0x34, Result, WaitForAddress, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::ArbitrationType, arb_type), INPUT(int32_t, value), INPUT(int64_t, timeout_ns)) \
|
||||
HANDLER(0x35, Result, SignalToAddress, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::SignalType, signal_type), INPUT(int32_t, value), INPUT(int32_t, count)) \
|
||||
HANDLER(0x36, void, SynchronizePreemptionState) \
|
||||
HANDLER(0x37, Result, GetResourceLimitPeakValue, OUTPUT(int64_t, out_peak_value), INPUT(::ams::svc::Handle, resource_limit_handle), INPUT(::ams::svc::LimitableResource, which)) \
|
||||
|
|
|
@ -191,8 +191,6 @@ namespace ams::svc {
|
|||
InfoType_IsSvcPermitted = 26,
|
||||
InfoType_IoRegionHint = 27,
|
||||
InfoType_AliasRegionExtraSize = 28,
|
||||
/* ... */
|
||||
InfoType_TransferMemoryHint = 34,
|
||||
|
||||
InfoType_MesosphereMeta = 65000,
|
||||
InfoType_MesosphereCurrentProcess = 65001,
|
||||
|
@ -263,7 +261,6 @@ namespace ams::svc {
|
|||
ArbitrationType_WaitIfLessThan = 0,
|
||||
ArbitrationType_DecrementAndWaitIfLessThan = 1,
|
||||
ArbitrationType_WaitIfEqual = 2,
|
||||
ArbitrationType_WaitIfEqual64 = 3,
|
||||
};
|
||||
|
||||
enum YieldType : s64 {
|
||||
|
|
|
@ -125,8 +125,6 @@ SECTIONS
|
|||
.gnu.version_r : { *(.gnu.version_r) } :rodata
|
||||
.note.gnu.build-id : { *(.note.gnu.build-id) } :rodata
|
||||
|
||||
__rodata_end = .;
|
||||
|
||||
/* =========== DATA section =========== */
|
||||
. = ALIGN(0x1000);
|
||||
__data_start = . ;
|
||||
|
|
|
@ -15,9 +15,6 @@
|
|||
*/
|
||||
#include <mesosphere.hpp>
|
||||
|
||||
extern "C" void __rodata_start();
|
||||
extern "C" void __rodata_end();
|
||||
|
||||
extern "C" void __bin_start__();
|
||||
extern "C" void __bin_end__();
|
||||
|
||||
|
@ -223,31 +220,6 @@ namespace ams::kern::init {
|
|||
};
|
||||
static_assert(kern::arch::arm64::init::IsInitialPageAllocator<KInitialPageAllocatorForFinalizeIdentityMapping>);
|
||||
|
||||
void SetupAllTtbr0Entries(KInitialPageTable &init_pt, KInitialPageAllocator &allocator) {
|
||||
/* Validate that the ttbr0 array is in rodata. */
|
||||
const uintptr_t rodata_start = reinterpret_cast<uintptr_t>(__rodata_start);
|
||||
const uintptr_t rodata_end = reinterpret_cast<uintptr_t>(__rodata_end);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(rodata_start < rodata_end);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(rodata_start <= reinterpret_cast<uintptr_t>(std::addressof(KPageTable::GetTtbr0Entry(0))));
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(reinterpret_cast<uintptr_t>(std::addressof(KPageTable::GetTtbr0Entry(KPageTable::NumTtbr0Entries))) < rodata_end);
|
||||
|
||||
/* Allocate pages for all ttbr0 entries. */
|
||||
for (size_t i = 0; i < KPageTable::NumTtbr0Entries; ++i) {
|
||||
/* Allocate a page. */
|
||||
KPhysicalAddress page = allocator.Allocate(PageSize);
|
||||
MESOSPHERE_INIT_ABORT_UNLESS(page != Null<KPhysicalAddress>);
|
||||
|
||||
/* Check that the page is allowed to be a ttbr0 entry. */
|
||||
MESOSPHERE_INIT_ABORT_UNLESS((GetInteger(page) & UINT64_C(0xFFFF000000000001)) == 0);
|
||||
|
||||
/* Get the physical address of the ttbr0 entry. */
|
||||
const auto ttbr0_phys_ptr = init_pt.GetPhysicalAddress(KVirtualAddress(std::addressof(KPageTable::GetTtbr0Entry(i))));
|
||||
|
||||
/* Set the entry to the newly allocated page. */
|
||||
*reinterpret_cast<volatile u64 *>(GetInteger(ttbr0_phys_ptr)) = (static_cast<u64>(i) << 48) | GetInteger(page);
|
||||
}
|
||||
}
|
||||
|
||||
void FinalizeIdentityMapping(KInitialPageTable &init_pt, KInitialPageAllocator &allocator, u64 phys_to_virt_offset) {
|
||||
/* Create an allocator for identity mapping finalization. */
|
||||
KInitialPageAllocatorForFinalizeIdentityMapping finalize_allocator(allocator, phys_to_virt_offset);
|
||||
|
@ -619,9 +591,6 @@ namespace ams::kern::init {
|
|||
/* Create page table object for use during remaining initialization. */
|
||||
KInitialPageTable init_pt;
|
||||
|
||||
/* Setup all ttbr0 pages. */
|
||||
SetupAllTtbr0Entries(init_pt, g_initial_page_allocator);
|
||||
|
||||
/* Unmap the identity mapping. */
|
||||
FinalizeIdentityMapping(init_pt, g_initial_page_allocator, g_phase2_linear_region_phys_to_virt_diff);
|
||||
|
||||
|
|
|
@ -111,8 +111,4 @@ namespace ams::kern {
|
|||
KThread &Kernel::GetMainThread(s32 core_id) { return g_main_threads.m_arr[core_id]; }
|
||||
KThread &Kernel::GetIdleThread(s32 core_id) { return g_idle_threads.m_arr[core_id]; }
|
||||
|
||||
__attribute__((constructor)) void ConfigureKTargetSystem() {
|
||||
KSystemControl::ConfigureKTargetSystem();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -110,7 +110,6 @@
|
|||
"type": "debug_flags",
|
||||
"value": {
|
||||
"allow_debug": false,
|
||||
"force_debug_prod": false,
|
||||
"force_debug": true
|
||||
}
|
||||
}
|
||||
|
|
|
@ -105,7 +105,6 @@
|
|||
"type": "debug_flags",
|
||||
"value": {
|
||||
"allow_debug": false,
|
||||
"force_debug_prod": false,
|
||||
"force_debug": true
|
||||
}
|
||||
}]
|
||||
|
|
|
@ -104,7 +104,6 @@
|
|||
"type": "debug_flags",
|
||||
"value": {
|
||||
"allow_debug": false,
|
||||
"force_debug_prod": false,
|
||||
"force_debug": true
|
||||
}
|
||||
}]
|
||||
|
|
|
@ -308,19 +308,10 @@ namespace ams::ldr {
|
|||
);
|
||||
|
||||
DEFINE_CAPABILITY_CLASS(DebugFlags,
|
||||
DEFINE_CAPABILITY_FIELD(AllowDebug, IdBits, 1, bool);
|
||||
DEFINE_CAPABILITY_FIELD(ForceDebugProd, AllowDebug, 1, bool);
|
||||
DEFINE_CAPABILITY_FIELD(ForceDebug, ForceDebugProd, 1, bool);
|
||||
DEFINE_CAPABILITY_FIELD(AllowDebug, IdBits, 1, bool);
|
||||
DEFINE_CAPABILITY_FIELD(ForceDebug, AllowDebug, 1, bool);
|
||||
|
||||
bool IsValid(const util::BitPack32 *kac, size_t kac_count) const {
|
||||
u32 total = 0;
|
||||
if (this->GetAllowDebug()) { ++total; }
|
||||
if (this->GetForceDebugProd()) { ++total; }
|
||||
if (this->GetForceDebug()) { ++total; }
|
||||
if (total > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < kac_count; i++) {
|
||||
if (GetCapabilityId(kac[i]) == Id) {
|
||||
const auto restriction = Decode(kac[i]);
|
||||
|
@ -328,14 +319,12 @@ namespace ams::ldr {
|
|||
return (restriction.GetValue() & this->GetValue()) == this->GetValue();
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static constexpr util::BitPack32 Encode(bool allow_debug, bool force_debug_prod, bool force_debug) {
|
||||
static constexpr util::BitPack32 Encode(bool allow_debug, bool force_debug) {
|
||||
util::BitPack32 encoded{IdBitsValue};
|
||||
encoded.Set<AllowDebug>(allow_debug);
|
||||
encoded.Set<ForceDebugProd>(force_debug_prod);
|
||||
encoded.Set<ForceDebug>(force_debug);
|
||||
return encoded;
|
||||
}
|
||||
|
@ -417,7 +406,7 @@ namespace ams::ldr {
|
|||
kac[i] = CapabilityApplicationType::Encode(flags & ProgramInfoFlag_ApplicationTypeMask);
|
||||
break;
|
||||
case CapabilityId::DebugFlags:
|
||||
kac[i] = CapabilityDebugFlags::Encode((flags & ProgramInfoFlag_AllowDebug) != 0, CapabilityDebugFlags::Decode(cap).GetForceDebugProd(), CapabilityDebugFlags::Decode(cap).GetForceDebug());
|
||||
kac[i] = CapabilityDebugFlags::Encode((flags & ProgramInfoFlag_AllowDebug) != 0, CapabilityDebugFlags::Decode(cap).GetForceDebug());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -85,7 +85,6 @@
|
|||
"type": "debug_flags",
|
||||
"value": {
|
||||
"allow_debug": false,
|
||||
"force_debug_prod": false,
|
||||
"force_debug": true
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue