Compare commits

...

33 Commits

Author SHA1 Message Date
Michael Scire
feb765c40d kernel patches: fuck armconverter.com 2020-12-02 06:03:26 -08:00
Michael Scire
d7429b74a4 kern: tweak KScopedAutoObject 2020-12-02 04:08:06 -08:00
Michael Scire
53aae17b64 kern: allow non-inline GetObjectForIpc 2020-12-02 04:07:01 -08:00
Michael Scire
94d818db90 kern: fix KHandleTable null deref in ipc 2020-12-02 04:05:16 -08:00
Michael Scire
eccadf2958 kern: session mapping getters are on the hotpath 2020-12-02 03:52:08 -08:00
Michael Scire
60ea4a1b1c kern: tweak optimization settings for hot paths 2020-12-02 03:39:07 -08:00
Michael Scire
464f336016 kern: more iterator adjustments 2020-12-02 03:33:10 -08:00
Michael Scire
c788f7a3fc strat: add new npdm field 2020-12-02 02:51:02 -08:00
Michael Scire
bbfed7be66 ams.mitm: fix old hid api references 2020-12-02 02:37:48 -08:00
Michael Scire
e38f87b182 ams: this version will be 0.16.0 2020-12-02 02:26:22 -08:00
Michael Scire
e4677d3a9d Merge remote-tracking branch 'origin/hid_refactor' into 11_support 2020-12-02 02:24:18 -08:00
Michael Scire
01a5f4094b hot path: just in case 2020-12-02 02:17:32 -08:00
Michael Scire
2f12dd039f microkernel: hot paths are pretty fucking hot 2020-12-02 02:14:24 -08:00
Michael Scire
f058d04933 kern: update KConditionVariable to support new has_waiter_flag rules 2020-12-02 01:28:21 -08:00
Michael Scire
8e1a46b951 kern: fix SvcGetResourceLimitPeakValue 2020-12-01 19:29:17 -08:00
Michael Scire
24db70602f kern: fix copy/paste error 2020-12-01 19:21:45 -08:00
Michael Scire
4ce3778d87 kern: fix bugs caused by UB + transition to -Os 2020-12-01 18:41:44 -08:00
Michael Scire
95bbb20cb0 loader: support 11.x DisableDeviceAddressSpaceMerge 2020-12-01 17:47:48 -08:00
Michael Scire
f089cd4b76 kern: allow non-inline KSchedulerLock::Lock 2020-12-01 17:36:14 -08:00
Michael Scire
6f95b738dc kern: build as -Os instead of -O2 2020-12-01 17:34:09 -08:00
Michael Scire
6cc21e4d98 kern: reduce KMemoryRegionAllocator slab size 2020-12-01 17:31:21 -08:00
Michael Scire
8936e4d5d9 kern: assume that uart has been setup by secmon 2020-12-01 17:30:42 -08:00
Michael Scire
3b3cb337f0 kern: update Initialize0 to account for new ordering 2020-12-01 17:29:42 -08:00
Michael Scire
a56bdab820 kern: add new overflow checks on KMemoryRegions 2020-12-01 17:14:23 -08:00
Michael Scire
866310937a kern: fix assertion in the multi-region pool partition code 2020-12-01 17:03:42 -08:00
Michael Scire
cc7cf49c88 kern: improve KMemoryManager pool detection 2020-12-01 17:03:00 -08:00
Michael Scire
1e9a3c3f91 kern: update KMemoryRegion to store last address rather than size 2020-12-01 16:42:25 -08:00
Michael Scire
5002b17c71 kern: add KAlpha/KBeta 2020-12-01 16:32:30 -08:00
Michael Scire
3886c8707f kern: stubs for Svc39, 3A, 46, 47 2020-12-01 16:23:09 -08:00
Michael Scire
4c8dad3ea2 kern: remove now unused SetupFor*Compare funcs 2020-12-01 16:20:20 -08:00
Michael Scire
25e1d34017 KConditionVariable/KAddressArbiter: no need for global compare thread 2020-12-01 16:19:39 -08:00
Michael Scire
4f00303daf kern: set EL2 id registers on deprivilege 2020-12-01 15:57:45 -08:00
Michael Scire
b421e3eadb kern: implement 64-virtual-core interface 2020-12-01 15:54:31 -08:00
74 changed files with 1182 additions and 560 deletions

View File

@@ -141,15 +141,16 @@ dist: dist-no-debug
cp stratosphere/creport/creport.elf atmosphere-$(AMSVER)-debug/creport.elf cp stratosphere/creport/creport.elf atmosphere-$(AMSVER)-debug/creport.elf
cp stratosphere/dmnt/dmnt.elf atmosphere-$(AMSVER)-debug/dmnt.elf cp stratosphere/dmnt/dmnt.elf atmosphere-$(AMSVER)-debug/dmnt.elf
cp stratosphere/eclct.stub/eclct.stub.elf atmosphere-$(AMSVER)-debug/eclct.stub.elf cp stratosphere/eclct.stub/eclct.stub.elf atmosphere-$(AMSVER)-debug/eclct.stub.elf
cp stratosphere/erpt/erpt.elf atmosphere-$(AMSVER)-debug/erpt.elf
cp stratosphere/fatal/fatal.elf atmosphere-$(AMSVER)-debug/fatal.elf cp stratosphere/fatal/fatal.elf atmosphere-$(AMSVER)-debug/fatal.elf
cp stratosphere/jpegdec/jpegdec.elf atmosphere-$(AMSVER)-debug/jpegdec.elf
cp stratosphere/loader/loader.elf atmosphere-$(AMSVER)-debug/loader.elf cp stratosphere/loader/loader.elf atmosphere-$(AMSVER)-debug/loader.elf
cp stratosphere/ncm/ncm.elf atmosphere-$(AMSVER)-debug/ncm.elf
cp stratosphere/pgl/pgl.elf atmosphere-$(AMSVER)-debug/pgl.elf
cp stratosphere/pm/pm.elf atmosphere-$(AMSVER)-debug/pm.elf cp stratosphere/pm/pm.elf atmosphere-$(AMSVER)-debug/pm.elf
cp stratosphere/ro/ro.elf atmosphere-$(AMSVER)-debug/ro.elf cp stratosphere/ro/ro.elf atmosphere-$(AMSVER)-debug/ro.elf
cp stratosphere/sm/sm.elf atmosphere-$(AMSVER)-debug/sm.elf cp stratosphere/sm/sm.elf atmosphere-$(AMSVER)-debug/sm.elf
cp stratosphere/spl/spl.elf atmosphere-$(AMSVER)-debug/spl.elf cp stratosphere/spl/spl.elf atmosphere-$(AMSVER)-debug/spl.elf
cp stratosphere/erpt/erpt.elf atmosphere-$(AMSVER)-debug/erpt.elf
cp stratosphere/jpegdec/jpegdec.elf atmosphere-$(AMSVER)-debug/jpegdec.elf
cp stratosphere/pgl/pgl.elf atmosphere-$(AMSVER)-debug/pgl.elf
cp troposphere/daybreak/daybreak.elf atmosphere-$(AMSVER)-debug/daybreak.elf cp troposphere/daybreak/daybreak.elf atmosphere-$(AMSVER)-debug/daybreak.elf
cd atmosphere-$(AMSVER)-debug; zip -r ../atmosphere-$(AMSVER)-debug.zip ./*; cd ../; cd atmosphere-$(AMSVER)-debug; zip -r ../atmosphere-$(AMSVER)-debug.zip ./*; cd ../;
rm -r atmosphere-$(AMSVER)-debug rm -r atmosphere-$(AMSVER)-debug

View File

@@ -543,8 +543,8 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, proc_id_recv)[] = {0xA9B
/* /*
stp x10, x11, [sp, #-0x10]! stp x10, x11, [sp, #-0x10]!
ldr x11, [sp, #0x90] ldr x11, [sp, #0x80]
mov w10, w28 mov w10, #3
lsl x10, x10, #2 lsl x10, x10, #2
ldr x10, [x11, x10] ldr x10, [x11, x10]
mov x9, #0x0000ffffffffffff mov x9, #0x0000ffffffffffff
@@ -567,11 +567,11 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(1000, proc_id_recv)[] = {0xA9B
mov x0, x8 mov x0, x8
*/ */
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1100, proc_id_send)[] = {0xE0, 0x03, 0x15, 0xAA, 0xA8, 0x02, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0x00, 0x01, 0x3F, 0xD6, 0x88, 0x4A, 0x3C, 0x8B, 0x09, 0xFC, 0x60, 0xD3, 0x00, 0x25, 0x00, 0x29}; static const uint8_t MAKE_KERNEL_PATTERN_NAME(1100, proc_id_send)[] = {0xE0, 0x03, 0x15, 0xAA, 0xA8, 0x02, 0x40, 0xF9, 0x08, 0x1D, 0x40, 0xF9, 0x00, 0x01, 0x3F, 0xD6, 0x88, 0x4A, 0x3C, 0x8B, 0x09, 0xFC, 0x60, 0xD3, 0x00, 0x25, 0x00, 0x29};
static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, proc_id_send)[] = {0xA9BF2FEA, 0xF9404BEB, 0x2A1C03EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54FFFFA0, 0xA9BF27E8, 0xF94002A8, 0xF9401D08, 0xAA1503E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0}; static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, proc_id_send)[] = {0xA9BF2FEA, 0xF94043EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF94002A8, 0xF9401D08, 0xAA1503E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
/* /*
stp x10, x11, [sp, #-0x10]! stp x10, x11, [sp, #-0x10]!
ldr x11, [sp, #0xE0] ldr x11, [sp, #0xE0]
ldr w10, [sp, #0xC0] mov w10, #3
lsl x10, x10, #2 lsl x10, x10, #2
ldr x10, [x11, x10] ldr x10, [x11, x10]
mov x9, #0x0000ffffffffffff mov x9, #0x0000ffffffffffff
@@ -594,7 +594,7 @@ static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, proc_id_send)[] = {0xA9B
mov x0, x8 mov x0, x8
*/ */
static const uint8_t MAKE_KERNEL_PATTERN_NAME(1100, proc_id_recv)[] = {0x08, 0x03, 0x40, 0xF9, 0xE0, 0x03, 0x18, 0xAA, 0x08, 0x1D, 0x40, 0xF9, 0x00, 0x01, 0x3F, 0xD6, 0xE8, 0x7F, 0x40, 0xF9, 0x09, 0xFC, 0x60, 0xD3, 0xEA, 0x5B, 0x40, 0xF9}; static const uint8_t MAKE_KERNEL_PATTERN_NAME(1100, proc_id_recv)[] = {0x08, 0x03, 0x40, 0xF9, 0xE0, 0x03, 0x18, 0xAA, 0x08, 0x1D, 0x40, 0xF9, 0x00, 0x01, 0x3F, 0xD6, 0xE8, 0x7F, 0x40, 0xF9, 0x09, 0xFC, 0x60, 0xD3, 0xEA, 0x5B, 0x40, 0xF9};
static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, proc_id_recv)[] = {0xA9BF2FEA, 0xF94073EB, 0xB940C3EA, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54FFFFA0, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0}; static const instruction_t MAKE_KERNEL_PATCH_NAME(1100, proc_id_recv)[] = {0xA9BF2FEA, 0xF94073EB, 0x5280006A, 0xD37EF54A, 0xF86A696A, 0x92FFFFE9, 0x8A090148, 0xD2FFFFE9, 0x8A09014A, 0xD2FFFFC9, 0xEB09015F, 0x54000100, 0xA9BF27E8, 0xF9400308, 0xF9401D08, 0xAA1803E0, 0xD63F0100, 0xA8C127E8, 0xAA0003E8, 0xA8C12FEA, 0xAA0803E0};
/* svcControlCodeMemory Patches */ /* svcControlCodeMemory Patches */
/* b.eq -> nop */ /* b.eq -> nop */
@@ -1090,7 +1090,7 @@ void package2_patch_kernel(void *_kernel, size_t *kernel_size, bool is_sd_kernel
uint8_t *pattern_loc = search_pattern(kernel, *kernel_size, kernel_info->patches[i].pattern, kernel_info->patches[i].pattern_size); uint8_t *pattern_loc = search_pattern(kernel, *kernel_size, kernel_info->patches[i].pattern, kernel_info->patches[i].pattern_size);
if (pattern_loc == NULL) { if (pattern_loc == NULL) {
/* TODO: Should we print an error/abort here? */ fatal_error("kernel_patcher: failed to identify patch location!\n");
continue; continue;
} }
/* Patch kernel to branch to our hook at the desired place. */ /* Patch kernel to branch to our hook at the desired place. */

View File

@@ -7,7 +7,7 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../common.mk
# options for code generation # options for code generation
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
export DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_MESOSPHERE export DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_MESOSPHERE
export SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 -mgeneral-regs-only -ffixed-x18 -Wextra -Werror -fno-non-call-exceptions export SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -mgeneral-regs-only -ffixed-x18 -Wextra -Werror -fno-non-call-exceptions
export CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) export CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
export CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit export CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
export ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) export ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)

View File

@@ -11,7 +11,7 @@ include $(CURRENT_DIRECTORY)/../config/common.mk
PRECOMPILED_HEADERS := include/mesosphere.hpp PRECOMPILED_HEADERS := include/mesosphere.hpp
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_MESOSPHERE DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_MESOSPHERE
SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 -mgeneral-regs-only -ffixed-x18 -Wextra -Werror -fno-non-call-exceptions SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -mgeneral-regs-only -ffixed-x18 -Wextra -Werror -fno-non-call-exceptions
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit -flto CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit -flto
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE) ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)

View File

@@ -77,6 +77,8 @@
#include <mesosphere/kern_select_debug.hpp> #include <mesosphere/kern_select_debug.hpp>
#include <mesosphere/kern_k_process.hpp> #include <mesosphere/kern_k_process.hpp>
#include <mesosphere/kern_k_resource_limit.hpp> #include <mesosphere/kern_k_resource_limit.hpp>
#include <mesosphere/kern_k_alpha.hpp>
#include <mesosphere/kern_k_beta.hpp>
/* More Miscellaneous objects. */ /* More Miscellaneous objects. */
#include <mesosphere/kern_k_object_name.hpp> #include <mesosphere/kern_k_object_name.hpp>

View File

@@ -668,6 +668,7 @@ namespace ams::kern::arch::arm64::init {
this->PhysicallyRandomize(virt_addr, size, L2BlockSize, do_copy); this->PhysicallyRandomize(virt_addr, size, L2BlockSize, do_copy);
this->PhysicallyRandomize(virt_addr, size, L3ContiguousBlockSize, do_copy); this->PhysicallyRandomize(virt_addr, size, L3ContiguousBlockSize, do_copy);
this->PhysicallyRandomize(virt_addr, size, L3BlockSize, do_copy); this->PhysicallyRandomize(virt_addr, size, L3BlockSize, do_copy);
cpu::StoreEntireCacheForInit();
} }
}; };

View File

@@ -25,7 +25,7 @@ namespace ams::kern::arch::arm64 {
public: public:
constexpr KNotAlignedSpinLock() : packed_tickets(0) { /* ... */ } constexpr KNotAlignedSpinLock() : packed_tickets(0) { /* ... */ }
void Lock() { ALWAYS_INLINE void Lock() {
u32 tmp0, tmp1, tmp2; u32 tmp0, tmp1, tmp2;
__asm__ __volatile__( __asm__ __volatile__(
@@ -52,7 +52,7 @@ namespace ams::kern::arch::arm64 {
); );
} }
void Unlock() { ALWAYS_INLINE void Unlock() {
const u32 value = this->packed_tickets + 1; const u32 value = this->packed_tickets + 1;
__asm__ __volatile__( __asm__ __volatile__(
" stlrh %w[value], %[packed_tickets]\n" " stlrh %w[value], %[packed_tickets]\n"
@@ -71,7 +71,7 @@ namespace ams::kern::arch::arm64 {
public: public:
constexpr KAlignedSpinLock() : current_ticket(0), next_ticket(0) { /* ... */ } constexpr KAlignedSpinLock() : current_ticket(0), next_ticket(0) { /* ... */ }
void Lock() { ALWAYS_INLINE void Lock() {
u32 tmp0, tmp1, got_lock; u32 tmp0, tmp1, got_lock;
__asm__ __volatile__( __asm__ __volatile__(
@@ -94,7 +94,7 @@ namespace ams::kern::arch::arm64 {
); );
} }
void Unlock() { ALWAYS_INLINE void Unlock() {
const u32 value = this->current_ticket + 1; const u32 value = this->current_ticket + 1;
__asm__ __volatile__( __asm__ __volatile__(
" stlrh %w[value], %[current_ticket]\n" " stlrh %w[value], %[current_ticket]\n"

View File

@@ -0,0 +1,33 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <mesosphere/kern_common.hpp>
namespace ams::kern::board::nintendo::nx::impl::cpu {
/* Virtual to Physical core map. */
constexpr inline const s32 VirtualToPhysicalCoreMap[BITSIZEOF(u64)] = {
0, 1, 2, 3, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 3,
};
}

View File

@@ -34,6 +34,8 @@ namespace ams::kern::init {
size_t num_KObjectName; size_t num_KObjectName;
size_t num_KResourceLimit; size_t num_KResourceLimit;
size_t num_KDebug; size_t num_KDebug;
size_t num_KAlpha;
size_t num_KBeta;
}; };
NOINLINE void InitializeSlabResourceCounts(); NOINLINE void InitializeSlabResourceCounts();

View File

@@ -0,0 +1,41 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_auto_object.hpp>
#include <mesosphere/kern_slab_helpers.hpp>
namespace ams::kern {
class KAlpha final : public KAutoObjectWithSlabHeapAndContainer<KAlpha, KAutoObjectWithList> {
MESOSPHERE_AUTOOBJECT_TRAITS(KAlpha, KAutoObject);
private:
/* NOTE: Official KAlpha has size 0x50, corresponding to 0x20 bytes of fields. */
/* TODO: Add these fields, if KAlpha is ever instantiable in the NX kernel. */
public:
explicit KAlpha() {
/* ... */
}
virtual ~KAlpha() { /* ... */ }
/* virtual void Finalize() override; */
virtual bool IsInitialized() const override { return false /* TODO */; }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
};
}

View File

@@ -198,7 +198,7 @@ namespace ams::kern {
} }
} }
ALWAYS_INLINE ~KScopedAutoObject() { ~KScopedAutoObject() {
if (this->obj != nullptr) { if (this->obj != nullptr) {
this->obj->Close(); this->obj->Close();
} }
@@ -206,7 +206,7 @@ namespace ams::kern {
} }
template<typename U> requires (std::derived_from<T, U> || std::derived_from<U, T>) template<typename U> requires (std::derived_from<T, U> || std::derived_from<U, T>)
constexpr ALWAYS_INLINE KScopedAutoObject(KScopedAutoObject<U> &&rhs) { constexpr KScopedAutoObject(KScopedAutoObject<U> &&rhs) {
if constexpr (std::derived_from<U, T>) { if constexpr (std::derived_from<U, T>) {
/* Upcast. */ /* Upcast. */
this->obj = rhs.obj; this->obj = rhs.obj;

View File

@@ -0,0 +1,48 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_auto_object.hpp>
#include <mesosphere/kern_slab_helpers.hpp>
namespace ams::kern {
class KProcess;
class KBeta final : public KAutoObjectWithSlabHeapAndContainer<KBeta, KAutoObjectWithList> {
MESOSPHERE_AUTOOBJECT_TRAITS(KBeta, KAutoObject);
private:
friend class KProcess;
private:
/* NOTE: Official KBeta has size 0x88, corresponding to 0x58 bytes of fields. */
/* TODO: Add these fields, if KBeta is ever instantiable in the NX kernel. */
util::IntrusiveListNode process_list_node;
public:
explicit KBeta()
: process_list_node()
{
/* ... */
}
virtual ~KBeta() { /* ... */ }
/* virtual void Finalize() override; */
virtual bool IsInitialized() const override { return false /* TODO */; }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
};
}

View File

@@ -112,6 +112,10 @@ namespace ams::kern {
KSessionRequest, KSessionRequest,
KCodeMemory, KCodeMemory,
/* NOTE: True order for these has not been determined yet. */
KAlpha,
KBeta,
FinalClassesEnd = FinalClassesStart + NumFinalClasses, FinalClassesEnd = FinalClassesStart + NumFinalClasses,
}; };

View File

@@ -20,8 +20,6 @@
namespace ams::kern { namespace ams::kern {
extern KThread g_cv_arbiter_compare_thread;
class KConditionVariable { class KConditionVariable {
public: public:
using ThreadTree = typename KThread::ConditionVariableThreadTreeType; using ThreadTree = typename KThread::ConditionVariableThreadTreeType;

View File

@@ -160,14 +160,16 @@ namespace ams::kern {
return this->template GetObjectWithoutPseudoHandle<T>(handle); return this->template GetObjectWithoutPseudoHandle<T>(handle);
} }
ALWAYS_INLINE KScopedAutoObject<KAutoObject> GetObjectForIpcWithoutPseudoHandle(ams::svc::Handle handle) const { KScopedAutoObject<KAutoObject> GetObjectForIpcWithoutPseudoHandle(ams::svc::Handle handle) const {
/* Lock and look up in table. */ /* Lock and look up in table. */
KScopedDisableDispatch dd; KScopedDisableDispatch dd;
KScopedSpinLock lk(this->lock); KScopedSpinLock lk(this->lock);
KAutoObject *obj = this->GetObjectImpl(handle); KAutoObject *obj = this->GetObjectImpl(handle);
if (obj->DynamicCast<KInterruptEvent *>() != nullptr) { if (AMS_LIKELY(obj != nullptr)) {
return nullptr; if (AMS_UNLIKELY(obj->DynamicCast<KInterruptEvent *>() != nullptr)) {
return nullptr;
}
} }
return obj; return obj;

View File

@@ -112,7 +112,9 @@ namespace ams::kern {
} }
static ALWAYS_INLINE KVirtualAddress GetStackTopAddress(s32 core_id, KMemoryRegionType type) { static ALWAYS_INLINE KVirtualAddress GetStackTopAddress(s32 core_id, KMemoryRegionType type) {
return Dereference(GetVirtualMemoryRegionTree().FindByTypeAndAttribute(type, static_cast<u32>(core_id))).GetEndAddress(); const auto &region = Dereference(GetVirtualMemoryRegionTree().FindByTypeAndAttribute(type, static_cast<u32>(core_id)));
MESOSPHERE_INIT_ABORT_UNLESS(region.GetEndAddress() != 0);
return region.GetEndAddress();
} }
public: public:
static ALWAYS_INLINE KMemoryRegionTree &GetVirtualMemoryRegionTree() { return s_virtual_tree; } static ALWAYS_INLINE KMemoryRegionTree &GetVirtualMemoryRegionTree() { return s_virtual_tree; }

View File

@@ -70,11 +70,13 @@ namespace ams::kern {
public: public:
Impl() : heap(), page_reference_counts(), management_region(), pool(), next(), prev() { /* ... */ } Impl() : heap(), page_reference_counts(), management_region(), pool(), next(), prev() { /* ... */ }
size_t Initialize(const KMemoryRegion *region, Pool pool, KVirtualAddress management_region, KVirtualAddress management_region_end); size_t Initialize(uintptr_t address, size_t size, KVirtualAddress management, KVirtualAddress management_end, Pool p);
KVirtualAddress AllocateBlock(s32 index, bool random) { return this->heap.AllocateBlock(index, random); } KVirtualAddress AllocateBlock(s32 index, bool random) { return this->heap.AllocateBlock(index, random); }
void Free(KVirtualAddress addr, size_t num_pages) { this->heap.Free(addr, num_pages); } void Free(KVirtualAddress addr, size_t num_pages) { this->heap.Free(addr, num_pages); }
void UpdateUsedHeapSize() { this->heap.UpdateUsedSize(); }
void InitializeOptimizedMemory() { std::memset(GetVoidPointer(this->management_region), 0, CalculateOptimizedProcessOverheadSize(this->heap.GetSize())); } void InitializeOptimizedMemory() { std::memset(GetVoidPointer(this->management_region), 0, CalculateOptimizedProcessOverheadSize(this->heap.GetSize())); }
void TrackUnoptimizedAllocation(KVirtualAddress block, size_t num_pages); void TrackUnoptimizedAllocation(KVirtualAddress block, size_t num_pages);

View File

@@ -29,7 +29,7 @@ namespace ams::kern {
private: private:
uintptr_t address; uintptr_t address;
uintptr_t pair_address; uintptr_t pair_address;
size_t region_size; uintptr_t last_address;
u32 attributes; u32 attributes;
u32 type_id; u32 type_id;
public: public:
@@ -43,18 +43,18 @@ namespace ams::kern {
} }
} }
public: public:
constexpr ALWAYS_INLINE KMemoryRegion() : address(0), pair_address(0), region_size(0), attributes(0), type_id(0) { /* ... */ } constexpr ALWAYS_INLINE KMemoryRegion() : address(0), pair_address(0), last_address(0), attributes(0), type_id(0) { /* ... */ }
constexpr ALWAYS_INLINE KMemoryRegion(uintptr_t a, size_t rs, uintptr_t p, u32 r, u32 t) : constexpr ALWAYS_INLINE KMemoryRegion(uintptr_t a, size_t la, uintptr_t p, u32 r, u32 t) :
address(a), pair_address(p), region_size(rs), attributes(r), type_id(t) address(a), pair_address(p), last_address(la), attributes(r), type_id(t)
{ {
/* ... */ /* ... */
} }
constexpr ALWAYS_INLINE KMemoryRegion(uintptr_t a, size_t rs, u32 r, u32 t) : KMemoryRegion(a, rs, std::numeric_limits<uintptr_t>::max(), r, t) { /* ... */ } constexpr ALWAYS_INLINE KMemoryRegion(uintptr_t a, size_t la, u32 r, u32 t) : KMemoryRegion(a, la, std::numeric_limits<uintptr_t>::max(), r, t) { /* ... */ }
private: private:
constexpr ALWAYS_INLINE void Reset(uintptr_t a, uintptr_t rs, uintptr_t p, u32 r, u32 t) { constexpr ALWAYS_INLINE void Reset(uintptr_t a, uintptr_t la, uintptr_t p, u32 r, u32 t) {
this->address = a; this->address = a;
this->pair_address = p; this->pair_address = p;
this->region_size = rs; this->last_address = la;
this->attributes = r; this->attributes = r;
this->type_id = t; this->type_id = t;
} }
@@ -67,16 +67,16 @@ namespace ams::kern {
return this->pair_address; return this->pair_address;
} }
constexpr ALWAYS_INLINE size_t GetSize() const { constexpr ALWAYS_INLINE uintptr_t GetLastAddress() const {
return this->region_size; return this->last_address;
} }
constexpr ALWAYS_INLINE uintptr_t GetEndAddress() const { constexpr ALWAYS_INLINE uintptr_t GetEndAddress() const {
return this->GetAddress() + this->GetSize(); return this->GetLastAddress() + 1;
} }
constexpr ALWAYS_INLINE uintptr_t GetLastAddress() const { constexpr ALWAYS_INLINE size_t GetSize() const {
return this->GetEndAddress() - 1; return this->GetEndAddress() - this->GetAddress();
} }
constexpr ALWAYS_INLINE u32 GetAttributes() const { constexpr ALWAYS_INLINE u32 GetAttributes() const {
@@ -93,6 +93,7 @@ namespace ams::kern {
} }
constexpr ALWAYS_INLINE bool Contains(uintptr_t address) const { constexpr ALWAYS_INLINE bool Contains(uintptr_t address) const {
MESOSPHERE_INIT_ABORT_UNLESS(this->GetEndAddress() != 0);
return this->GetAddress() <= address && address <= this->GetLastAddress(); return this->GetAddress() <= address && address <= this->GetLastAddress();
} }
@@ -130,17 +131,17 @@ namespace ams::kern {
return this->first_region->GetAddress(); return this->first_region->GetAddress();
} }
constexpr ALWAYS_INLINE uintptr_t GetLastAddress() const {
return this->last_region->GetLastAddress();
}
constexpr ALWAYS_INLINE uintptr_t GetEndAddress() const { constexpr ALWAYS_INLINE uintptr_t GetEndAddress() const {
return this->last_region->GetEndAddress(); return this->GetLastAddress() + 1;
} }
constexpr ALWAYS_INLINE size_t GetSize() const { constexpr ALWAYS_INLINE size_t GetSize() const {
return this->GetEndAddress() - this->GetAddress(); return this->GetEndAddress() - this->GetAddress();
} }
constexpr ALWAYS_INLINE uintptr_t GetLastAddress() const {
return this->GetEndAddress() - 1;
}
}; };
private: private:
using TreeType = util::IntrusiveRedBlackTreeBaseTraits<KMemoryRegion>::TreeType<KMemoryRegion>; using TreeType = util::IntrusiveRedBlackTreeBaseTraits<KMemoryRegion>::TreeType<KMemoryRegion>;
@@ -160,7 +161,7 @@ namespace ams::kern {
constexpr ALWAYS_INLINE KMemoryRegionTree() : tree() { /* ... */ } constexpr ALWAYS_INLINE KMemoryRegionTree() : tree() { /* ... */ }
public: public:
KMemoryRegion *FindModifiable(uintptr_t address) { KMemoryRegion *FindModifiable(uintptr_t address) {
if (auto it = this->find(KMemoryRegion(address, 1, 0, 0)); it != this->end()) { if (auto it = this->find(KMemoryRegion(address, address, 0, 0)); it != this->end()) {
return std::addressof(*it); return std::addressof(*it);
} else { } else {
return nullptr; return nullptr;
@@ -168,7 +169,7 @@ namespace ams::kern {
} }
const KMemoryRegion *Find(uintptr_t address) const { const KMemoryRegion *Find(uintptr_t address) const {
if (auto it = this->find(KMemoryRegion(address, 1, 0, 0)); it != this->cend()) { if (auto it = this->find(KMemoryRegion(address, address, 0, 0)); it != this->cend()) {
return std::addressof(*it); return std::addressof(*it);
} else { } else {
return nullptr; return nullptr;
@@ -234,7 +235,7 @@ namespace ams::kern {
return extents; return extents;
} }
public: public:
NOINLINE void InsertDirectly(uintptr_t address, size_t size, u32 attr = 0, u32 type_id = 0); NOINLINE void InsertDirectly(uintptr_t address, uintptr_t last_address, u32 attr = 0, u32 type_id = 0);
NOINLINE bool Insert(uintptr_t address, size_t size, u32 type_id, u32 new_attr = 0, u32 old_attr = 0); NOINLINE bool Insert(uintptr_t address, size_t size, u32 type_id, u32 new_attr = 0, u32 old_attr = 0);
NOINLINE KVirtualAddress GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id); NOINLINE KVirtualAddress GetRandomAlignedRegion(size_t size, size_t alignment, u32 type_id);

View File

@@ -22,6 +22,7 @@
#include <mesosphere/kern_k_thread.hpp> #include <mesosphere/kern_k_thread.hpp>
#include <mesosphere/kern_k_thread_local_page.hpp> #include <mesosphere/kern_k_thread_local_page.hpp>
#include <mesosphere/kern_k_shared_memory_info.hpp> #include <mesosphere/kern_k_shared_memory_info.hpp>
#include <mesosphere/kern_k_beta.hpp>
#include <mesosphere/kern_k_worker_task.hpp> #include <mesosphere/kern_k_worker_task.hpp>
#include <mesosphere/kern_select_page_table.hpp> #include <mesosphere/kern_select_page_table.hpp>
#include <mesosphere/kern_k_condition_variable.hpp> #include <mesosphere/kern_k_condition_variable.hpp>
@@ -52,6 +53,7 @@ namespace ams::kern {
static constexpr size_t AslrAlignment = KernelAslrAlignment; static constexpr size_t AslrAlignment = KernelAslrAlignment;
private: private:
using SharedMemoryInfoList = util::IntrusiveListBaseTraits<KSharedMemoryInfo>::ListType; using SharedMemoryInfoList = util::IntrusiveListBaseTraits<KSharedMemoryInfo>::ListType;
using BetaList = util::IntrusiveListMemberTraits<&KBeta::process_list_node>::ListType;
using TLPTree = util::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>; using TLPTree = util::IntrusiveRedBlackTreeBaseTraits<KThreadLocalPage>::TreeType<KThreadLocalPage>;
using TLPIterator = TLPTree::iterator; using TLPIterator = TLPTree::iterator;
private: private:
@@ -95,6 +97,7 @@ namespace ams::kern {
KThread *exception_thread{}; KThread *exception_thread{};
ThreadList thread_list{}; ThreadList thread_list{};
SharedMemoryInfoList shared_memory_list{}; SharedMemoryInfoList shared_memory_list{};
BetaList beta_list{};
bool is_suspended{}; bool is_suspended{};
bool is_jit_debug{}; bool is_jit_debug{};
ams::svc::DebugEvent jit_debug_event_type{}; ams::svc::DebugEvent jit_debug_event_type{};

View File

@@ -45,7 +45,7 @@ namespace ams::kern {
return this->owner_thread == GetCurrentThreadPointer(); return this->owner_thread == GetCurrentThreadPointer();
} }
ALWAYS_INLINE void Lock() { void Lock() {
MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT_THIS();
if (this->IsLockedByCurrentThread()) { if (this->IsLockedByCurrentThread()) {
@@ -67,7 +67,7 @@ namespace ams::kern {
} }
} }
ALWAYS_INLINE void Unlock() { void Unlock() {
MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
MESOSPHERE_ASSERT(this->lock_count > 0); MESOSPHERE_ASSERT(this->lock_count > 0);

View File

@@ -37,7 +37,7 @@ namespace ams::kern {
*out_timer = this->timer; *out_timer = this->timer;
} }
ALWAYS_INLINE ~KScopedSchedulerLockAndSleep() { ~KScopedSchedulerLockAndSleep() {
/* Register the sleep. */ /* Register the sleep. */
if (this->timeout_tick > 0) { if (this->timeout_tick > 0) {
this->timer->RegisterAbsoluteTask(this->thread, this->timeout_tick); this->timer->RegisterAbsoluteTask(this->thread, this->timeout_tick);

View File

@@ -45,10 +45,10 @@ namespace ams::kern {
this->state = st; this->state = st;
} }
constexpr KProcessAddress GetClientAddress() const { return this->client_address; } constexpr ALWAYS_INLINE KProcessAddress GetClientAddress() const { return this->client_address; }
constexpr KProcessAddress GetServerAddress() const { return this->server_address; } constexpr ALWAYS_INLINE KProcessAddress GetServerAddress() const { return this->server_address; }
constexpr size_t GetSize() const { return this->size; } constexpr ALWAYS_INLINE size_t GetSize() const { return this->size; }
constexpr KMemoryState GetMemoryState() const { return this->state; } constexpr ALWAYS_INLINE KMemoryState GetMemoryState() const { return this->state; }
}; };
private: private:
Mapping static_mappings[NumStaticMappings]; Mapping static_mappings[NumStaticMappings];
@@ -62,32 +62,32 @@ namespace ams::kern {
void Initialize() { /* ... */ } void Initialize() { /* ... */ }
void Finalize(); void Finalize();
constexpr size_t GetSendCount() const { return this->num_send; } constexpr ALWAYS_INLINE size_t GetSendCount() const { return this->num_send; }
constexpr size_t GetReceiveCount() const { return this->num_recv; } constexpr ALWAYS_INLINE size_t GetReceiveCount() const { return this->num_recv; }
constexpr size_t GetExchangeCount() const { return this->num_exch; } constexpr ALWAYS_INLINE size_t GetExchangeCount() const { return this->num_exch; }
Result PushSend(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state); Result PushSend(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state);
Result PushReceive(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state); Result PushReceive(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state);
Result PushExchange(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state); Result PushExchange(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state);
constexpr KProcessAddress GetSendClientAddress(size_t i) const { return GetSendMapping(i).GetClientAddress(); } constexpr ALWAYS_INLINE KProcessAddress GetSendClientAddress(size_t i) const { return GetSendMapping(i).GetClientAddress(); }
constexpr KProcessAddress GetSendServerAddress(size_t i) const { return GetSendMapping(i).GetServerAddress(); } constexpr ALWAYS_INLINE KProcessAddress GetSendServerAddress(size_t i) const { return GetSendMapping(i).GetServerAddress(); }
constexpr size_t GetSendSize(size_t i) const { return GetSendMapping(i).GetSize(); } constexpr ALWAYS_INLINE size_t GetSendSize(size_t i) const { return GetSendMapping(i).GetSize(); }
constexpr KMemoryState GetSendMemoryState(size_t i) const { return GetSendMapping(i).GetMemoryState(); } constexpr ALWAYS_INLINE KMemoryState GetSendMemoryState(size_t i) const { return GetSendMapping(i).GetMemoryState(); }
constexpr KProcessAddress GetReceiveClientAddress(size_t i) const { return GetReceiveMapping(i).GetClientAddress(); } constexpr ALWAYS_INLINE KProcessAddress GetReceiveClientAddress(size_t i) const { return GetReceiveMapping(i).GetClientAddress(); }
constexpr KProcessAddress GetReceiveServerAddress(size_t i) const { return GetReceiveMapping(i).GetServerAddress(); } constexpr ALWAYS_INLINE KProcessAddress GetReceiveServerAddress(size_t i) const { return GetReceiveMapping(i).GetServerAddress(); }
constexpr size_t GetReceiveSize(size_t i) const { return GetReceiveMapping(i).GetSize(); } constexpr ALWAYS_INLINE size_t GetReceiveSize(size_t i) const { return GetReceiveMapping(i).GetSize(); }
constexpr KMemoryState GetReceiveMemoryState(size_t i) const { return GetReceiveMapping(i).GetMemoryState(); } constexpr ALWAYS_INLINE KMemoryState GetReceiveMemoryState(size_t i) const { return GetReceiveMapping(i).GetMemoryState(); }
constexpr KProcessAddress GetExchangeClientAddress(size_t i) const { return GetExchangeMapping(i).GetClientAddress(); } constexpr ALWAYS_INLINE KProcessAddress GetExchangeClientAddress(size_t i) const { return GetExchangeMapping(i).GetClientAddress(); }
constexpr KProcessAddress GetExchangeServerAddress(size_t i) const { return GetExchangeMapping(i).GetServerAddress(); } constexpr ALWAYS_INLINE KProcessAddress GetExchangeServerAddress(size_t i) const { return GetExchangeMapping(i).GetServerAddress(); }
constexpr size_t GetExchangeSize(size_t i) const { return GetExchangeMapping(i).GetSize(); } constexpr ALWAYS_INLINE size_t GetExchangeSize(size_t i) const { return GetExchangeMapping(i).GetSize(); }
constexpr KMemoryState GetExchangeMemoryState(size_t i) const { return GetExchangeMapping(i).GetMemoryState(); } constexpr ALWAYS_INLINE KMemoryState GetExchangeMemoryState(size_t i) const { return GetExchangeMapping(i).GetMemoryState(); }
private: private:
Result PushMap(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state, size_t index); Result PushMap(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state, size_t index);
constexpr const Mapping &GetSendMapping(size_t i) const { constexpr ALWAYS_INLINE const Mapping &GetSendMapping(size_t i) const {
MESOSPHERE_ASSERT(i < this->num_send); MESOSPHERE_ASSERT(i < this->num_send);
const size_t index = i; const size_t index = i;
@@ -98,7 +98,7 @@ namespace ams::kern {
} }
} }
constexpr const Mapping &GetReceiveMapping(size_t i) const { constexpr ALWAYS_INLINE const Mapping &GetReceiveMapping(size_t i) const {
MESOSPHERE_ASSERT(i < this->num_recv); MESOSPHERE_ASSERT(i < this->num_recv);
const size_t index = this->num_send + i; const size_t index = this->num_send + i;
@@ -109,7 +109,7 @@ namespace ams::kern {
} }
} }
constexpr const Mapping &GetExchangeMapping(size_t i) const { constexpr ALWAYS_INLINE const Mapping &GetExchangeMapping(size_t i) const {
MESOSPHERE_ASSERT(i < this->num_exch); MESOSPHERE_ASSERT(i < this->num_exch);
const size_t index = this->num_send + this->num_recv + i; const size_t index = this->num_send + this->num_recv + i;
@@ -176,50 +176,50 @@ namespace ams::kern {
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ } static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
constexpr KThread *GetThread() const { return this->thread; } constexpr ALWAYS_INLINE KThread *GetThread() const { return this->thread; }
constexpr KWritableEvent *GetEvent() const { return this->event; } constexpr ALWAYS_INLINE KWritableEvent *GetEvent() const { return this->event; }
constexpr uintptr_t GetAddress() const { return this->address; } constexpr ALWAYS_INLINE uintptr_t GetAddress() const { return this->address; }
constexpr size_t GetSize() const { return this->size; } constexpr ALWAYS_INLINE size_t GetSize() const { return this->size; }
constexpr KProcess *GetServerProcess() const { return this->server; } constexpr ALWAYS_INLINE KProcess *GetServerProcess() const { return this->server; }
void SetServerProcess(KProcess *process) { void ALWAYS_INLINE SetServerProcess(KProcess *process) {
this->server = process; this->server = process;
this->server->Open(); this->server->Open();
} }
constexpr void ClearThread() { this->thread = nullptr; } constexpr ALWAYS_INLINE void ClearThread() { this->thread = nullptr; }
constexpr void ClearEvent() { this->event = nullptr; } constexpr ALWAYS_INLINE void ClearEvent() { this->event = nullptr; }
constexpr size_t GetSendCount() const { return this->mappings.GetSendCount(); } constexpr ALWAYS_INLINE size_t GetSendCount() const { return this->mappings.GetSendCount(); }
constexpr size_t GetReceiveCount() const { return this->mappings.GetReceiveCount(); } constexpr ALWAYS_INLINE size_t GetReceiveCount() const { return this->mappings.GetReceiveCount(); }
constexpr size_t GetExchangeCount() const { return this->mappings.GetExchangeCount(); } constexpr ALWAYS_INLINE size_t GetExchangeCount() const { return this->mappings.GetExchangeCount(); }
Result PushSend(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) { ALWAYS_INLINE Result PushSend(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) {
return this->mappings.PushSend(client, server, size, state); return this->mappings.PushSend(client, server, size, state);
} }
Result PushReceive(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) { ALWAYS_INLINE Result PushReceive(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) {
return this->mappings.PushReceive(client, server, size, state); return this->mappings.PushReceive(client, server, size, state);
} }
Result PushExchange(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) { ALWAYS_INLINE Result PushExchange(KProcessAddress client, KProcessAddress server, size_t size, KMemoryState state) {
return this->mappings.PushExchange(client, server, size, state); return this->mappings.PushExchange(client, server, size, state);
} }
constexpr KProcessAddress GetSendClientAddress(size_t i) const { return this->mappings.GetSendClientAddress(i); } constexpr ALWAYS_INLINE KProcessAddress GetSendClientAddress(size_t i) const { return this->mappings.GetSendClientAddress(i); }
constexpr KProcessAddress GetSendServerAddress(size_t i) const { return this->mappings.GetSendServerAddress(i); } constexpr ALWAYS_INLINE KProcessAddress GetSendServerAddress(size_t i) const { return this->mappings.GetSendServerAddress(i); }
constexpr size_t GetSendSize(size_t i) const { return this->mappings.GetSendSize(i); } constexpr ALWAYS_INLINE size_t GetSendSize(size_t i) const { return this->mappings.GetSendSize(i); }
constexpr KMemoryState GetSendMemoryState(size_t i) const { return this->mappings.GetSendMemoryState(i); } constexpr ALWAYS_INLINE KMemoryState GetSendMemoryState(size_t i) const { return this->mappings.GetSendMemoryState(i); }
constexpr KProcessAddress GetReceiveClientAddress(size_t i) const { return this->mappings.GetReceiveClientAddress(i); } constexpr ALWAYS_INLINE KProcessAddress GetReceiveClientAddress(size_t i) const { return this->mappings.GetReceiveClientAddress(i); }
constexpr KProcessAddress GetReceiveServerAddress(size_t i) const { return this->mappings.GetReceiveServerAddress(i); } constexpr ALWAYS_INLINE KProcessAddress GetReceiveServerAddress(size_t i) const { return this->mappings.GetReceiveServerAddress(i); }
constexpr size_t GetReceiveSize(size_t i) const { return this->mappings.GetReceiveSize(i); } constexpr ALWAYS_INLINE size_t GetReceiveSize(size_t i) const { return this->mappings.GetReceiveSize(i); }
constexpr KMemoryState GetReceiveMemoryState(size_t i) const { return this->mappings.GetReceiveMemoryState(i); } constexpr ALWAYS_INLINE KMemoryState GetReceiveMemoryState(size_t i) const { return this->mappings.GetReceiveMemoryState(i); }
constexpr KProcessAddress GetExchangeClientAddress(size_t i) const { return this->mappings.GetExchangeClientAddress(i); } constexpr ALWAYS_INLINE KProcessAddress GetExchangeClientAddress(size_t i) const { return this->mappings.GetExchangeClientAddress(i); }
constexpr KProcessAddress GetExchangeServerAddress(size_t i) const { return this->mappings.GetExchangeServerAddress(i); } constexpr ALWAYS_INLINE KProcessAddress GetExchangeServerAddress(size_t i) const { return this->mappings.GetExchangeServerAddress(i); }
constexpr size_t GetExchangeSize(size_t i) const { return this->mappings.GetExchangeSize(i); } constexpr ALWAYS_INLINE size_t GetExchangeSize(size_t i) const { return this->mappings.GetExchangeSize(i); }
constexpr KMemoryState GetExchangeMemoryState(size_t i) const { return this->mappings.GetExchangeMemoryState(i); } constexpr ALWAYS_INLINE KMemoryState GetExchangeMemoryState(size_t i) const { return this->mappings.GetExchangeMemoryState(i); }
}; };
} }

View File

@@ -124,7 +124,21 @@ namespace ams::kern {
static_assert(sizeof(SyncObjectBuffer::sync_objects) == sizeof(SyncObjectBuffer::handles)); static_assert(sizeof(SyncObjectBuffer::sync_objects) == sizeof(SyncObjectBuffer::handles));
struct ConditionVariableComparator { struct ConditionVariableComparator {
static constexpr ALWAYS_INLINE int Compare(const KThread &lhs, const KThread &rhs) { struct LightCompareType {
uintptr_t cv_key;
s32 priority;
constexpr ALWAYS_INLINE uintptr_t GetConditionVariableKey() const {
return this->cv_key;
}
constexpr ALWAYS_INLINE s32 GetPriority() const {
return this->priority;
}
};
template<typename T> requires (std::same_as<T, KThread> || std::same_as<T, LightCompareType>)
static constexpr ALWAYS_INLINE int Compare(const T &lhs, const KThread &rhs) {
const uintptr_t l_key = lhs.GetConditionVariableKey(); const uintptr_t l_key = lhs.GetConditionVariableKey();
const uintptr_t r_key = rhs.GetConditionVariableKey(); const uintptr_t r_key = rhs.GetConditionVariableKey();
@@ -139,6 +153,8 @@ namespace ams::kern {
} }
} }
}; };
static_assert(ams::util::HasLightCompareType<ConditionVariableComparator>);
static_assert(std::same_as<ams::util::LightCompareType<ConditionVariableComparator, void>, ConditionVariableComparator::LightCompareType>);
private: private:
static inline std::atomic<u64> s_next_thread_id = 0; static inline std::atomic<u64> s_next_thread_id = 0;
private: private:
@@ -152,7 +168,8 @@ namespace ams::kern {
ConditionVariableThreadTree *condvar_tree{}; ConditionVariableThreadTree *condvar_tree{};
uintptr_t condvar_key{}; uintptr_t condvar_key{};
KAffinityMask affinity_mask{}; u64 virtual_affinity_mask{};
KAffinityMask physical_affinity_mask{};
u64 thread_id{}; u64 thread_id{};
std::atomic<s64> cpu_time{}; std::atomic<s64> cpu_time{};
KSynchronizationObject *synced_object{}; KSynchronizationObject *synced_object{};
@@ -181,12 +198,13 @@ namespace ams::kern {
Result wait_result; Result wait_result;
Result debug_exception_result; Result debug_exception_result;
s32 base_priority{}; s32 base_priority{};
s32 ideal_core_id{}; s32 physical_ideal_core_id{};
s32 virtual_ideal_core_id{};
s32 num_kernel_waiters{}; s32 num_kernel_waiters{};
s32 current_core_id{}; s32 current_core_id{};
s32 core_id{}; s32 core_id{};
KAffinityMask original_affinity_mask{}; KAffinityMask original_physical_affinity_mask{};
s32 original_ideal_core_id{}; s32 original_physical_ideal_core_id{};
s32 num_core_migration_disables{}; s32 num_core_migration_disables{};
ThreadState thread_state{}; ThreadState thread_state{};
std::atomic<bool> termination_requested{}; std::atomic<bool> termination_requested{};
@@ -202,21 +220,21 @@ namespace ams::kern {
virtual ~KThread() { /* ... */ } virtual ~KThread() { /* ... */ }
Result Initialize(KThreadFunction func, uintptr_t arg, void *kern_stack_top, KProcessAddress user_stack_top, s32 prio, s32 core, KProcess *owner, ThreadType type); Result Initialize(KThreadFunction func, uintptr_t arg, void *kern_stack_top, KProcessAddress user_stack_top, s32 prio, s32 virt_core, KProcess *owner, ThreadType type);
private: private:
static Result InitializeThread(KThread *thread, KThreadFunction func, uintptr_t arg, KProcessAddress user_stack_top, s32 prio, s32 core, KProcess *owner, ThreadType type); static Result InitializeThread(KThread *thread, KThreadFunction func, uintptr_t arg, KProcessAddress user_stack_top, s32 prio, s32 virt_core, KProcess *owner, ThreadType type);
public: public:
static Result InitializeKernelThread(KThread *thread, KThreadFunction func, uintptr_t arg, s32 prio, s32 core) { static Result InitializeKernelThread(KThread *thread, KThreadFunction func, uintptr_t arg, s32 prio, s32 virt_core) {
return InitializeThread(thread, func, arg, Null<KProcessAddress>, prio, core, nullptr, ThreadType_Kernel); return InitializeThread(thread, func, arg, Null<KProcessAddress>, prio, virt_core, nullptr, ThreadType_Kernel);
} }
static Result InitializeHighPriorityThread(KThread *thread, KThreadFunction func, uintptr_t arg) { static Result InitializeHighPriorityThread(KThread *thread, KThreadFunction func, uintptr_t arg) {
return InitializeThread(thread, func, arg, Null<KProcessAddress>, 0, GetCurrentCoreId(), nullptr, ThreadType_HighPriority); return InitializeThread(thread, func, arg, Null<KProcessAddress>, 0, GetCurrentCoreId(), nullptr, ThreadType_HighPriority);
} }
static Result InitializeUserThread(KThread *thread, KThreadFunction func, uintptr_t arg, KProcessAddress user_stack_top, s32 prio, s32 core, KProcess *owner) { static Result InitializeUserThread(KThread *thread, KThreadFunction func, uintptr_t arg, KProcessAddress user_stack_top, s32 prio, s32 virt_core, KProcess *owner) {
return InitializeThread(thread, func, arg, user_stack_top, prio, core, owner, ThreadType_User); return InitializeThread(thread, func, arg, user_stack_top, prio, virt_core, owner, ThreadType_User);
} }
static void ResumeThreadsSuspendedForInit(); static void ResumeThreadsSuspendedForInit();
@@ -323,10 +341,14 @@ namespace ams::kern {
constexpr KThreadContext &GetContext() { return this->thread_context; } constexpr KThreadContext &GetContext() { return this->thread_context; }
constexpr const KThreadContext &GetContext() const { return this->thread_context; } constexpr const KThreadContext &GetContext() const { return this->thread_context; }
constexpr const KAffinityMask &GetAffinityMask() const { return this->affinity_mask; } constexpr u64 GetVirtualAffinityMask() const { return this->virtual_affinity_mask; }
constexpr const KAffinityMask &GetAffinityMask() const { return this->physical_affinity_mask; }
Result GetCoreMask(int32_t *out_ideal_core, u64 *out_affinity_mask); Result GetCoreMask(int32_t *out_ideal_core, u64 *out_affinity_mask);
Result SetCoreMask(int32_t ideal_core, u64 affinity_mask); Result SetCoreMask(int32_t ideal_core, u64 affinity_mask);
Result GetPhysicalCoreMask(int32_t *out_ideal_core, u64 *out_affinity_mask);
constexpr ThreadState GetState() const { return static_cast<ThreadState>(this->thread_state & ThreadState_Mask); } constexpr ThreadState GetState() const { return static_cast<ThreadState>(this->thread_state & ThreadState_Mask); }
constexpr ThreadState GetRawState() const { return this->thread_state; } constexpr ThreadState GetRawState() const { return this->thread_state; }
NOINLINE void SetState(ThreadState state); NOINLINE void SetState(ThreadState state);
@@ -336,11 +358,6 @@ namespace ams::kern {
constexpr uintptr_t GetConditionVariableKey() const { return this->condvar_key; } constexpr uintptr_t GetConditionVariableKey() const { return this->condvar_key; }
constexpr uintptr_t GetAddressArbiterKey() const { return this->condvar_key; } constexpr uintptr_t GetAddressArbiterKey() const { return this->condvar_key; }
constexpr void SetupForConditionVariableCompare(uintptr_t cv_key, int priority) {
this->condvar_key = cv_key;
this->priority = priority;
}
constexpr void SetConditionVariable(ConditionVariableThreadTree *tree, KProcessAddress address, uintptr_t cv_key, u32 value) { constexpr void SetConditionVariable(ConditionVariableThreadTree *tree, KProcessAddress address, uintptr_t cv_key, u32 value) {
this->condvar_tree = tree; this->condvar_tree = tree;
this->condvar_key = cv_key; this->condvar_key = cv_key;
@@ -356,11 +373,6 @@ namespace ams::kern {
return this->condvar_tree != nullptr; return this->condvar_tree != nullptr;
} }
constexpr void SetupForAddressArbiterCompare(uintptr_t address, int priority) {
this->condvar_key = address;
this->priority = priority;
}
constexpr void SetAddressArbiter(ConditionVariableThreadTree *tree, uintptr_t address) { constexpr void SetAddressArbiter(ConditionVariableThreadTree *tree, uintptr_t address) {
this->condvar_tree = tree; this->condvar_tree = tree;
this->condvar_key = address; this->condvar_key = address;
@@ -374,7 +386,9 @@ namespace ams::kern {
return this->condvar_tree != nullptr; return this->condvar_tree != nullptr;
} }
constexpr s32 GetIdealCore() const { return this->ideal_core_id; } constexpr s32 GetIdealVirtualCore() const { return this->virtual_ideal_core_id; }
constexpr s32 GetIdealPhysicalCore() const { return this->physical_ideal_core_id; }
constexpr s32 GetActiveCore() const { return this->core_id; } constexpr s32 GetActiveCore() const { return this->core_id; }
constexpr void SetActiveCore(s32 core) { this->core_id = core; } constexpr void SetActiveCore(s32 core) { this->core_id = core; }

View File

@@ -28,3 +28,24 @@
#else #else
#error "Unknown architecture for CPU" #error "Unknown architecture for CPU"
#endif #endif
#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
#include <mesosphere/board/nintendo/nx/kern_cpu_map.hpp>
namespace ams::kern::cpu {
using namespace ams::kern::board::nintendo::nx::impl::cpu;
}
#else
#error "Unknown board for CPU Map"
#endif
namespace ams::kern {
static_assert(cpu::NumCores <= static_cast<s32>(BITSIZEOF(u64)));
static_assert(util::size(cpu::VirtualToPhysicalCoreMap) == BITSIZEOF(u64));
}

View File

@@ -42,7 +42,7 @@ namespace ams::kern {
u32 prev_intr_state; u32 prev_intr_state;
public: public:
ALWAYS_INLINE KScopedInterruptDisable() : prev_intr_state(KInterruptManager::DisableInterrupts()) { /* ... */ } ALWAYS_INLINE KScopedInterruptDisable() : prev_intr_state(KInterruptManager::DisableInterrupts()) { /* ... */ }
~KScopedInterruptDisable() { KInterruptManager::RestoreInterrupts(prev_intr_state); } ALWAYS_INLINE ~KScopedInterruptDisable() { KInterruptManager::RestoreInterrupts(prev_intr_state); }
}; };
class KScopedInterruptEnable { class KScopedInterruptEnable {
@@ -52,7 +52,7 @@ namespace ams::kern {
u32 prev_intr_state; u32 prev_intr_state;
public: public:
ALWAYS_INLINE KScopedInterruptEnable() : prev_intr_state(KInterruptManager::EnableInterrupts()) { /* ... */ } ALWAYS_INLINE KScopedInterruptEnable() : prev_intr_state(KInterruptManager::EnableInterrupts()) { /* ... */ }
~KScopedInterruptEnable() { KInterruptManager::RestoreInterrupts(prev_intr_state); } ALWAYS_INLINE ~KScopedInterruptEnable() { KInterruptManager::RestoreInterrupts(prev_intr_state); }
}; };
} }

View File

@@ -59,6 +59,7 @@ namespace ams::kern::svc {
/* Set omit-frame-pointer to prevent GCC from emitting MOV X29, SP instructions. */ /* Set omit-frame-pointer to prevent GCC from emitting MOV X29, SP instructions. */
#pragma GCC push_options #pragma GCC push_options
#pragma GCC optimize ("-O2")
#pragma GCC optimize ("omit-frame-pointer") #pragma GCC optimize ("omit-frame-pointer")
AMS_SVC_FOREACH_KERN_DEFINITION(DECLARE_SVC_STRUCT, _) AMS_SVC_FOREACH_KERN_DEFINITION(DECLARE_SVC_STRUCT, _)

View File

@@ -182,6 +182,9 @@ namespace ams::kern::board::nintendo::nx {
const KMemoryRegion *region = KMemoryLayout::Find(KPhysicalAddress(address)); const KMemoryRegion *region = KMemoryLayout::Find(KPhysicalAddress(address));
if (AMS_LIKELY(region != nullptr)) { if (AMS_LIKELY(region != nullptr)) {
if (AMS_LIKELY(region->IsDerivedFrom(KMemoryRegionType_MemoryController))) { if (AMS_LIKELY(region->IsDerivedFrom(KMemoryRegionType_MemoryController))) {
/* Check the region is valid. */
MESOSPHERE_ABORT_UNLESS(region->GetEndAddress() != 0);
/* Get the offset within the region. */ /* Get the offset within the region. */
const size_t offset = address - region->GetAddress(); const size_t offset = address - region->GetAddress();
MESOSPHERE_ABORT_UNLESS(offset < region->GetSize()); MESOSPHERE_ABORT_UNLESS(offset < region->GetSize());
@@ -210,6 +213,9 @@ namespace ams::kern::board::nintendo::nx {
region->IsDerivedFrom(KMemoryRegionType_MemoryController0) || region->IsDerivedFrom(KMemoryRegionType_MemoryController0) ||
region->IsDerivedFrom(KMemoryRegionType_MemoryController1)) region->IsDerivedFrom(KMemoryRegionType_MemoryController1))
{ {
/* Check the region is valid. */
MESOSPHERE_ABORT_UNLESS(region->GetEndAddress() != 0);
/* Get the offset within the region. */ /* Get the offset within the region. */
const size_t offset = address - region->GetAddress(); const size_t offset = address - region->GetAddress();
MESOSPHERE_ABORT_UNLESS(offset < region->GetSize()); MESOSPHERE_ABORT_UNLESS(offset < region->GetSize());
@@ -449,6 +455,8 @@ namespace ams::kern::board::nintendo::nx {
/* Configure the Kernel Carveout region. */ /* Configure the Kernel Carveout region. */
{ {
const auto carveout = KMemoryLayout::GetCarveoutRegionExtents(); const auto carveout = KMemoryLayout::GetCarveoutRegionExtents();
MESOSPHERE_ABORT_UNLESS(carveout.GetEndAddress() != 0);
smc::ConfigureCarveout(0, carveout.GetAddress(), carveout.GetSize()); smc::ConfigureCarveout(0, carveout.GetAddress(), carveout.GetSize());
} }
@@ -545,7 +553,7 @@ namespace ams::kern::board::nintendo::nx {
if (arg != nullptr) { if (arg != nullptr) {
/* Get the address of the legacy IRAM region. */ /* Get the address of the legacy IRAM region. */
const KVirtualAddress iram_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsIram) + 64_KB; const KVirtualAddress iram_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsIram) + 64_KB;
constexpr size_t RebootPayloadSize = 0x2E000; constexpr size_t RebootPayloadSize = 0x24000;
/* NOTE: Atmosphere extension; if we received an exception context from Panic(), */ /* NOTE: Atmosphere extension; if we received an exception context from Panic(), */
/* generate a fatal error report using it. */ /* generate a fatal error report using it. */

View File

@@ -58,28 +58,30 @@ namespace ams::kern::board::nintendo::nx::smc {
/* Disable interrupts while making the call. */ /* Disable interrupts while making the call. */
KScopedInterruptDisable intr_disable; KScopedInterruptDisable intr_disable;
/* Backup the current thread pointer. */ {
const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue(); /* Backup the current thread pointer. */
const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue();
__asm__ __volatile__("smc #1" __asm__ __volatile__("smc #1"
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7) : "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
: :
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory" : "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
); );
/* Restore the current thread pointer into X18. */ /* Restore the current thread pointer into X18. */
cpu::SetCurrentThreadPointerValue(current_thread_pointer_value); cpu::SetCurrentThreadPointerValue(current_thread_pointer_value);
/* Store arguments to output. */
args.x[0] = x0;
args.x[1] = x1;
args.x[2] = x2;
args.x[3] = x3;
args.x[4] = x4;
args.x[5] = x5;
args.x[6] = x6;
args.x[7] = x7;
}
} }
/* Store arguments to output. */
args.x[0] = x0;
args.x[1] = x1;
args.x[2] = x2;
args.x[3] = x3;
args.x[4] = x4;
args.x[5] = x5;
args.x[6] = x6;
args.x[7] = x7;
} }
void CallUserSecureMonitorFunction(ams::svc::lp64::SecureMonitorArguments *args) { void CallUserSecureMonitorFunction(ams::svc::lp64::SecureMonitorArguments *args) {
@@ -98,28 +100,30 @@ namespace ams::kern::board::nintendo::nx::smc {
/* Disable interrupts while making the call. */ /* Disable interrupts while making the call. */
KScopedInterruptDisable intr_disable; KScopedInterruptDisable intr_disable;
/* Backup the current thread pointer. */ {
const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue(); /* Backup the current thread pointer. */
const uintptr_t current_thread_pointer_value = cpu::GetCurrentThreadPointerValue();
__asm__ __volatile__("smc #0" __asm__ __volatile__("smc #0"
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7) : "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
: :
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory" : "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
); );
/* Restore the current thread pointer into X18. */ /* Restore the current thread pointer into X18. */
cpu::SetCurrentThreadPointerValue(current_thread_pointer_value); cpu::SetCurrentThreadPointerValue(current_thread_pointer_value);
/* Store arguments to output. */
args->r[0] = x0;
args->r[1] = x1;
args->r[2] = x2;
args->r[3] = x3;
args->r[4] = x4;
args->r[5] = x5;
args->r[6] = x6;
args->r[7] = x7;
}
} }
/* Store arguments to output. */
args->r[0] = x0;
args->r[1] = x1;
args->r[2] = x2;
args->r[3] = x3;
args->r[4] = x4;
args->r[5] = x5;
args->r[6] = x6;
args->r[7] = x7;
} }
void CallPrivilegedSecureMonitorFunctionForInit(SecureMonitorArguments &args) { void CallPrivilegedSecureMonitorFunctionForInit(SecureMonitorArguments &args) {

View File

@@ -39,7 +39,9 @@ namespace ams::kern::init {
HANDLER(KObjectName, (SLAB_COUNT(KObjectName)), ## __VA_ARGS__) \ HANDLER(KObjectName, (SLAB_COUNT(KObjectName)), ## __VA_ARGS__) \
HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ## __VA_ARGS__) \ HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ## __VA_ARGS__) \
HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ## __VA_ARGS__) \ HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ## __VA_ARGS__) \
HANDLER(KDebug, (SLAB_COUNT(KDebug)), ## __VA_ARGS__) HANDLER(KDebug, (SLAB_COUNT(KDebug)), ## __VA_ARGS__) \
HANDLER(KAlpha, (SLAB_COUNT(KAlpha)), ## __VA_ARGS__) \
HANDLER(KBeta, (SLAB_COUNT(KBeta)), ## __VA_ARGS__)
namespace { namespace {
@@ -68,6 +70,8 @@ namespace ams::kern::init {
constexpr size_t SlabCountKObjectName = 7; constexpr size_t SlabCountKObjectName = 7;
constexpr size_t SlabCountKResourceLimit = 5; constexpr size_t SlabCountKResourceLimit = 5;
constexpr size_t SlabCountKDebug = cpu::NumCores; constexpr size_t SlabCountKDebug = cpu::NumCores;
constexpr size_t SlabCountKAlpha = 1;
constexpr size_t SlabCountKBeta = 6;
constexpr size_t SlabCountExtraKThread = 160; constexpr size_t SlabCountExtraKThread = 160;
@@ -94,6 +98,8 @@ namespace ams::kern::init {
.num_KObjectName = SlabCountKObjectName, .num_KObjectName = SlabCountKObjectName,
.num_KResourceLimit = SlabCountKResourceLimit, .num_KResourceLimit = SlabCountKResourceLimit,
.num_KDebug = SlabCountKDebug, .num_KDebug = SlabCountKDebug,
.num_KAlpha = SlabCountKAlpha,
.num_KBeta = SlabCountKBeta,
}; };
template<typename T> template<typename T>

View File

@@ -51,37 +51,22 @@ namespace ams::kern {
} }
bool KDebugLogImpl::Initialize() { bool KDebugLogImpl::Initialize() {
/* Get the uart memory region. */
const KMemoryRegion *uart_region = KMemoryLayout::GetPhysicalMemoryRegionTree().FindFirstDerived(KMemoryRegionType_Uart);
if (uart_region == nullptr) {
return false;
}
/* Set the uart register base address. */ /* Set the uart register base address. */
g_uart_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_Uart); g_uart_address = uart_region->GetPairAddress();
if (g_uart_address == Null<KVirtualAddress>) {
return false;
}
/* Parameters for uart. */ /* NOTE: We assume here that UART init/config has been done by the Secure Monitor. */
constexpr u32 BaudRate = 115200; /* As such, we only need to disable interrupts. */
constexpr u32 Pllp = 408000000;
constexpr u32 Rate = 16 * BaudRate;
constexpr u32 Divisor = (Pllp + Rate / 2) / Rate;
/* Initialize the UART registers. */
/* Set Divisor Latch Access bit, to allow access to DLL/DLH */
WriteUartRegister(UartRegister_LCR, 0x80);
ReadUartRegister(UartRegister_LCR);
/* Program the divisor into DLL/DLH. */
WriteUartRegister(UartRegister_DLL, Divisor & 0xFF);
WriteUartRegister(UartRegister_DLH, (Divisor >> 8) & 0xFF);
ReadUartRegister(UartRegister_DLH);
/* Set word length to 3, clear Divisor Latch Access. */
WriteUartRegister(UartRegister_LCR, 0x03);
ReadUartRegister(UartRegister_LCR);
/* Disable UART interrupts. */
WriteUartRegister(UartRegister_IER, 0x00); WriteUartRegister(UartRegister_IER, 0x00);
/* Configure the FIFO to be enabled and clear receive. */
WriteUartRegister(UartRegister_FCR, 0x03);
WriteUartRegister(UartRegister_IRDA_CSR, 0x02);
ReadUartRegister(UartRegister_FCR);
return true; return true;
} }

View File

@@ -26,7 +26,9 @@ namespace ams::kern {
}; };
KVirtualAddress GetInitialProcessBinaryAddress() { KVirtualAddress GetInitialProcessBinaryAddress() {
return KMemoryLayout::GetPageTableHeapRegion().GetEndAddress() - InitialProcessBinarySizeMax; const uintptr_t end_address = KMemoryLayout::GetPageTableHeapRegion().GetEndAddress();
MESOSPHERE_ABORT_UNLESS(end_address != 0);
return end_address - InitialProcessBinarySizeMax;
} }
void LoadInitialProcessBinaryHeader(InitialProcessBinaryHeader *header) { void LoadInitialProcessBinaryHeader(InitialProcessBinaryHeader *header) {
@@ -97,8 +99,11 @@ namespace ams::kern {
/* Ensure that we do not leak pages. */ /* Ensure that we do not leak pages. */
ON_SCOPE_EXIT { pg.Close(); }; ON_SCOPE_EXIT { pg.Close(); };
/* Map the process's memory into the temporary region. */ /* Get the temporary region. */
const auto &temp_region = KMemoryLayout::GetTempRegion(); const auto &temp_region = KMemoryLayout::GetTempRegion();
MESOSPHERE_ABORT_UNLESS(temp_region.GetEndAddress() != 0);
/* Map the process's memory into the temporary region. */
KProcessAddress temp_address = Null<KProcessAddress>; KProcessAddress temp_address = Null<KProcessAddress>;
MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().MapPageGroup(std::addressof(temp_address), pg, temp_region.GetAddress(), temp_region.GetSize() / PageSize, KMemoryState_Kernel, KMemoryPermission_KernelReadWrite)); MESOSPHERE_R_ABORT_UNLESS(Kernel::GetKernelPageTable().MapPageGroup(std::addressof(temp_address), pg, temp_region.GetAddress(), temp_region.GetSize() / PageSize, KMemoryState_Kernel, KMemoryPermission_KernelReadWrite));

View File

@@ -50,9 +50,8 @@ namespace ams::kern {
s32 num_waiters = 0; s32 num_waiters = 0;
{ {
KScopedSchedulerLock sl; KScopedSchedulerLock sl;
g_cv_arbiter_compare_thread.SetupForAddressArbiterCompare(addr, -1);
auto it = this->tree.nfind(g_cv_arbiter_compare_thread); auto it = this->tree.nfind_light({ addr, -1 });
while ((it != this->tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { while ((it != this->tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) {
KThread *target_thread = std::addressof(*it); KThread *target_thread = std::addressof(*it);
target_thread->SetSyncedObject(nullptr, ResultSuccess()); target_thread->SetSyncedObject(nullptr, ResultSuccess());
@@ -79,10 +78,7 @@ namespace ams::kern {
R_UNLESS(UpdateIfEqual(std::addressof(user_value), addr, value, value + 1), svc::ResultInvalidCurrentMemory()); R_UNLESS(UpdateIfEqual(std::addressof(user_value), addr, value, value + 1), svc::ResultInvalidCurrentMemory());
R_UNLESS(user_value == value, svc::ResultInvalidState()); R_UNLESS(user_value == value, svc::ResultInvalidState());
g_cv_arbiter_compare_thread.SetupForAddressArbiterCompare(addr, -1); auto it = this->tree.nfind_light({ addr, -1 });
auto it = this->tree.nfind(g_cv_arbiter_compare_thread);
while ((it != this->tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) { while ((it != this->tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) {
KThread *target_thread = std::addressof(*it); KThread *target_thread = std::addressof(*it);
target_thread->SetSyncedObject(nullptr, ResultSuccess()); target_thread->SetSyncedObject(nullptr, ResultSuccess());
@@ -103,10 +99,8 @@ namespace ams::kern {
s32 num_waiters = 0; s32 num_waiters = 0;
{ {
KScopedSchedulerLock sl; KScopedSchedulerLock sl;
g_cv_arbiter_compare_thread.SetupForAddressArbiterCompare(addr, -1);
auto it = this->tree.nfind(g_cv_arbiter_compare_thread);
auto it = this->tree.nfind_light({ addr, -1 });
/* Determine the updated value. */ /* Determine the updated value. */
s32 new_value; s32 new_value;
if (GetTargetFirmware() >= TargetFirmware_7_0_0) { if (GetTargetFirmware() >= TargetFirmware_7_0_0) {

View File

@@ -17,8 +17,6 @@
namespace ams::kern { namespace ams::kern {
constinit KThread g_cv_arbiter_compare_thread;
namespace { namespace {
ALWAYS_INLINE bool ReadFromUser(u32 *out, KProcessAddress address) { ALWAYS_INLINE bool ReadFromUser(u32 *out, KProcessAddress address) {
@@ -179,9 +177,8 @@ namespace ams::kern {
int num_waiters = 0; int num_waiters = 0;
{ {
KScopedSchedulerLock sl; KScopedSchedulerLock sl;
g_cv_arbiter_compare_thread.SetupForConditionVariableCompare(cv_key, -1);
auto it = this->tree.nfind(g_cv_arbiter_compare_thread); auto it = this->tree.nfind_light({ cv_key, -1 });
while ((it != this->tree.end()) && (count <= 0 || num_waiters < count) && (it->GetConditionVariableKey() == cv_key)) { while ((it != this->tree.end()) && (count <= 0 || num_waiters < count) && (it->GetConditionVariableKey() == cv_key)) {
KThread *target_thread = std::addressof(*it); KThread *target_thread = std::addressof(*it);
@@ -197,6 +194,12 @@ namespace ams::kern {
target_thread->ClearConditionVariable(); target_thread->ClearConditionVariable();
++num_waiters; ++num_waiters;
} }
/* If we have no waiters, clear the has waiter flag. */
if (it == this->tree.end() || it->GetConditionVariableKey() != cv_key) {
const u32 has_waiter_flag = 0;
WriteToUser(cv_key, std::addressof(has_waiter_flag));
}
} }
/* Close threads in the array. */ /* Close threads in the array. */
@@ -247,6 +250,13 @@ namespace ams::kern {
next_owner_thread->Wakeup(); next_owner_thread->Wakeup();
} }
/* Write to the cv key. */
{
const u32 has_waiter_flag = 1;
WriteToUser(key, std::addressof(has_waiter_flag));
cpu::DataMemoryBarrier();
}
/* Write the value to userspace. */ /* Write the value to userspace. */
if (!WriteToUser(addr, std::addressof(next_value))) { if (!WriteToUser(addr, std::addressof(next_value))) {
slp.CancelSleep(); slp.CancelSleep();

View File

@@ -55,6 +55,7 @@ namespace ams::kern {
MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(start, size, phys_type, attr)); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(start, size, phys_type, attr));
const KMemoryRegion *phys = KMemoryLayout::GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(phys_type, attr); const KMemoryRegion *phys = KMemoryLayout::GetPhysicalMemoryRegionTree().FindByTypeAndAttribute(phys_type, attr);
MESOSPHERE_INIT_ABORT_UNLESS(phys != nullptr); MESOSPHERE_INIT_ABORT_UNLESS(phys != nullptr);
MESOSPHERE_INIT_ABORT_UNLESS(phys->GetEndAddress() != 0);
MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetVirtualMemoryRegionTree().Insert(phys->GetPairAddress(), size, virt_type, attr)); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetVirtualMemoryRegionTree().Insert(phys->GetPairAddress(), size, virt_type, attr));
} }
@@ -104,6 +105,7 @@ namespace ams::kern {
void SetupPoolPartitionMemoryRegions() { void SetupPoolPartitionMemoryRegions() {
/* Start by identifying the extents of the DRAM memory region. */ /* Start by identifying the extents of the DRAM memory region. */
const auto dram_extents = KMemoryLayout::GetMainMemoryPhysicalExtents(); const auto dram_extents = KMemoryLayout::GetMainMemoryPhysicalExtents();
MESOSPHERE_INIT_ABORT_UNLESS(dram_extents.GetEndAddress() != 0);
/* Determine the end of the pool region. */ /* Determine the end of the pool region. */
const uintptr_t pool_end = dram_extents.GetEndAddress() - KTraceBufferSize; const uintptr_t pool_end = dram_extents.GetEndAddress() - KTraceBufferSize;

View File

@@ -23,7 +23,7 @@ namespace ams::kern {
NON_COPYABLE(KMemoryRegionAllocator); NON_COPYABLE(KMemoryRegionAllocator);
NON_MOVEABLE(KMemoryRegionAllocator); NON_MOVEABLE(KMemoryRegionAllocator);
public: public:
static constexpr size_t MaxMemoryRegions = 1000; static constexpr size_t MaxMemoryRegions = 200;
private: private:
KMemoryRegion region_heap[MaxMemoryRegions]; KMemoryRegion region_heap[MaxMemoryRegions];
size_t num_regions; size_t num_regions;
@@ -40,8 +40,6 @@ namespace ams::kern {
new (region) KMemoryRegion(std::forward<Args>(args)...); new (region) KMemoryRegion(std::forward<Args>(args)...);
return region; return region;
return &this->region_heap[this->num_regions++];
} }
}; };
@@ -55,8 +53,8 @@ namespace ams::kern {
} }
void KMemoryRegionTree::InsertDirectly(uintptr_t address, size_t size, u32 attr, u32 type_id) { void KMemoryRegionTree::InsertDirectly(uintptr_t address, uintptr_t last_address, u32 attr, u32 type_id) {
this->insert(*AllocateRegion(address, size, attr, type_id)); this->insert(*AllocateRegion(address, last_address, attr, type_id));
} }
bool KMemoryRegionTree::Insert(uintptr_t address, size_t size, u32 type_id, u32 new_attr, u32 old_attr) { bool KMemoryRegionTree::Insert(uintptr_t address, size_t size, u32 type_id, u32 new_attr, u32 old_attr) {
@@ -82,9 +80,7 @@ namespace ams::kern {
/* Cache information from the region before we remove it. */ /* Cache information from the region before we remove it. */
const uintptr_t old_address = found->GetAddress(); const uintptr_t old_address = found->GetAddress();
const size_t old_size = found->GetSize(); const uintptr_t old_last = found->GetLastAddress();
const uintptr_t old_end = old_address + old_size;
const uintptr_t old_last = old_end - 1;
const uintptr_t old_pair = found->GetPairAddress(); const uintptr_t old_pair = found->GetPairAddress();
const u32 old_type = found->GetType(); const u32 old_type = found->GetType();
@@ -92,24 +88,24 @@ namespace ams::kern {
this->erase(this->iterator_to(*found)); this->erase(this->iterator_to(*found));
/* Insert the new region into the tree. */ /* Insert the new region into the tree. */
const uintptr_t new_pair = (old_pair != std::numeric_limits<uintptr_t>::max()) ? old_pair + (address - old_address) : old_pair;
if (old_address == address) { if (old_address == address) {
/* Reuse the old object for the new region, if we can. */ /* Reuse the old object for the new region, if we can. */
found->Reset(address, size, new_pair, new_attr, type_id); found->Reset(address, inserted_region_last, old_pair, new_attr, type_id);
this->insert(*found); this->insert(*found);
} else { } else {
/* If we can't re-use, adjust the old region. */ /* If we can't re-use, adjust the old region. */
found->Reset(old_address, address - old_address, old_pair, old_attr, old_type); found->Reset(old_address, address - 1, old_pair, old_attr, old_type);
this->insert(*found); this->insert(*found);
/* Insert a new region for the split. */ /* Insert a new region for the split. */
this->insert(*AllocateRegion(address, size, new_pair, new_attr, type_id)); const uintptr_t new_pair = (old_pair != std::numeric_limits<uintptr_t>::max()) ? old_pair + (address - old_address) : old_pair;
this->insert(*AllocateRegion(address, inserted_region_last, new_pair, new_attr, type_id));
} }
/* If we need to insert a region after the region, do so. */ /* If we need to insert a region after the region, do so. */
if (old_last != inserted_region_last) { if (old_last != inserted_region_last) {
const uintptr_t after_pair = (old_pair != std::numeric_limits<uintptr_t>::max()) ? old_pair + (inserted_region_end - old_address) : old_pair; const uintptr_t after_pair = (old_pair != std::numeric_limits<uintptr_t>::max()) ? old_pair + (inserted_region_end - old_address) : old_pair;
this->insert(*AllocateRegion(inserted_region_end, old_end - inserted_region_end, after_pair, old_attr, old_type)); this->insert(*AllocateRegion(inserted_region_end, old_last, after_pair, old_attr, old_type));
} }
return true; return true;
@@ -125,8 +121,11 @@ namespace ams::kern {
const uintptr_t first_address = extents.GetAddress(); const uintptr_t first_address = extents.GetAddress();
const uintptr_t last_address = extents.GetLastAddress(); const uintptr_t last_address = extents.GetLastAddress();
const uintptr_t first_index = first_address / alignment;
const uintptr_t last_index = last_address / alignment;
while (true) { while (true) {
const uintptr_t candidate = util::AlignDown(KSystemControl::Init::GenerateRandomRange(first_address, last_address), alignment); const uintptr_t candidate = KSystemControl::Init::GenerateRandomRange(first_index, last_index) * alignment;
/* Ensure that the candidate doesn't overflow with the size. */ /* Ensure that the candidate doesn't overflow with the size. */
if (!(candidate < candidate + size)) { if (!(candidate < candidate + size)) {
@@ -157,13 +156,13 @@ namespace ams::kern {
/* Initialize linear trees. */ /* Initialize linear trees. */
for (auto &region : GetPhysicalMemoryRegionTree()) { for (auto &region : GetPhysicalMemoryRegionTree()) {
if (region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) { if (region.HasTypeAttribute(KMemoryRegionAttr_LinearMapped)) {
GetPhysicalLinearMemoryRegionTree().InsertDirectly(region.GetAddress(), region.GetSize(), region.GetAttributes(), region.GetType()); GetPhysicalLinearMemoryRegionTree().InsertDirectly(region.GetAddress(), region.GetLastAddress(), region.GetAttributes(), region.GetType());
} }
} }
for (auto &region : GetVirtualMemoryRegionTree()) { for (auto &region : GetVirtualMemoryRegionTree()) {
if (region.IsDerivedFrom(KMemoryRegionType_Dram)) { if (region.IsDerivedFrom(KMemoryRegionType_Dram)) {
GetVirtualLinearMemoryRegionTree().InsertDirectly(region.GetAddress(), region.GetSize(), region.GetAttributes(), region.GetType()); GetVirtualLinearMemoryRegionTree().InsertDirectly(region.GetAddress(), region.GetLastAddress(), region.GetAttributes(), region.GetType());
} }
} }
} }

View File

@@ -20,12 +20,16 @@ namespace ams::kern {
namespace { namespace {
constexpr KMemoryManager::Pool GetPoolFromMemoryRegionType(u32 type) { constexpr KMemoryManager::Pool GetPoolFromMemoryRegionType(u32 type) {
switch (type) { if ((type | KMemoryRegionType_VirtualDramApplicationPool) == type) {
case KMemoryRegionType_VirtualDramApplicationPool: return KMemoryManager::Pool_Application; return KMemoryManager::Pool_Application;
case KMemoryRegionType_VirtualDramAppletPool: return KMemoryManager::Pool_Applet; } else if ((type | KMemoryRegionType_VirtualDramAppletPool) == type) {
case KMemoryRegionType_VirtualDramSystemPool: return KMemoryManager::Pool_System; return KMemoryManager::Pool_Applet;
case KMemoryRegionType_VirtualDramSystemNonSecurePool: return KMemoryManager::Pool_SystemNonSecure; } else if ((type | KMemoryRegionType_VirtualDramSystemPool) == type) {
MESOSPHERE_UNREACHABLE_DEFAULT_CASE(); return KMemoryManager::Pool_System;
} else if ((type | KMemoryRegionType_VirtualDramSystemNonSecurePool) == type) {
return KMemoryManager::Pool_SystemNonSecure;
} else {
MESOSPHERE_PANIC("InvalidMemoryRegionType for conversion to Pool");
} }
} }
@@ -37,9 +41,11 @@ namespace ams::kern {
std::memset(GetVoidPointer(management_region), 0, management_region_size); std::memset(GetVoidPointer(management_region), 0, management_region_size);
/* Traverse the virtual memory layout tree, initializing each manager as appropriate. */ /* Traverse the virtual memory layout tree, initializing each manager as appropriate. */
while (true) { while (this->num_managers != MaxManagerCount) {
/* Locate the region that should initialize the current manager. */ /* Locate the region that should initialize the current manager. */
const KMemoryRegion *region = nullptr; uintptr_t region_address = 0;
size_t region_size = 0;
Pool region_pool = Pool_Count;
for (const auto &it : KMemoryLayout::GetVirtualMemoryRegionTree()) { for (const auto &it : KMemoryLayout::GetVirtualMemoryRegionTree()) {
/* We only care about regions that we need to create managers for. */ /* We only care about regions that we need to create managers for. */
if (!it.IsDerivedFrom(KMemoryRegionType_VirtualDramUserPool)) { if (!it.IsDerivedFrom(KMemoryRegionType_VirtualDramUserPool)) {
@@ -51,39 +57,62 @@ namespace ams::kern {
continue; continue;
} }
region = std::addressof(it); /* Validate the region. */
break; MESOSPHERE_ABORT_UNLESS(it.GetEndAddress() != 0);
MESOSPHERE_ASSERT(it.GetAddress() != Null<decltype(it.GetAddress())>);
MESOSPHERE_ASSERT(it.GetSize() > 0);
/* Update the region's extents. */
if (region_address == 0) {
region_address = it.GetAddress();
region_size = it.GetSize();
region_pool = GetPoolFromMemoryRegionType(it.GetType());
} else {
MESOSPHERE_ASSERT(it.GetAddress() == region_address + region_size);
/* Update the size. */
region_size = it.GetEndAddress() - region_address;
MESOSPHERE_ABORT_UNLESS(GetPoolFromMemoryRegionType(it.GetType()) == region_pool);
}
} }
/* If we didn't find a region, then we're done initializing managers. */ /* If we didn't find a region, we're done. */
if (region == nullptr) { if (region_size == 0) {
break; break;
} }
/* Ensure that the region is correct. */
MESOSPHERE_ASSERT(region->GetAddress() != Null<decltype(region->GetAddress())>);
MESOSPHERE_ASSERT(region->GetSize() > 0);
MESOSPHERE_ASSERT(region->GetEndAddress() >= region->GetAddress());
MESOSPHERE_ASSERT(region->IsDerivedFrom(KMemoryRegionType_VirtualDramUserPool));
MESOSPHERE_ASSERT(region->GetAttributes() == this->num_managers);
/* Initialize a new manager for the region. */ /* Initialize a new manager for the region. */
const Pool pool = GetPoolFromMemoryRegionType(region->GetType());
Impl *manager = std::addressof(this->managers[this->num_managers++]); Impl *manager = std::addressof(this->managers[this->num_managers++]);
MESOSPHERE_ABORT_UNLESS(this->num_managers <= util::size(this->managers)); MESOSPHERE_ABORT_UNLESS(this->num_managers <= util::size(this->managers));
const size_t cur_size = manager->Initialize(region, pool, management_region, management_region_end); const size_t cur_size = manager->Initialize(region_address, region_size, management_region, management_region_end, region_pool);
management_region += cur_size; management_region += cur_size;
MESOSPHERE_ABORT_UNLESS(management_region <= management_region_end); MESOSPHERE_ABORT_UNLESS(management_region <= management_region_end);
/* Insert the manager into the pool list. */ /* Insert the manager into the pool list. */
if (this->pool_managers_tail[pool] == nullptr) { if (this->pool_managers_tail[region_pool] == nullptr) {
this->pool_managers_head[pool] = manager; this->pool_managers_head[region_pool] = manager;
} else { } else {
this->pool_managers_tail[pool]->SetNext(manager); this->pool_managers_tail[region_pool]->SetNext(manager);
manager->SetPrev(this->pool_managers_tail[pool]); manager->SetPrev(this->pool_managers_tail[region_pool]);
} }
this->pool_managers_tail[pool] = manager; this->pool_managers_tail[region_pool] = manager;
}
/* Free each region to its corresponding heap. */
for (const auto &it : KMemoryLayout::GetVirtualMemoryRegionTree()) {
if (it.IsDerivedFrom(KMemoryRegionType_VirtualDramUserPool)) {
/* Check the region. */
MESOSPHERE_ABORT_UNLESS(it.GetEndAddress() != 0);
/* Free the memory to the heap. */
this->managers[it.GetAttributes()].Free(it.GetAddress(), it.GetSize() / PageSize);
}
}
/* Update the used size for all managers. */
for (size_t i = 0; i < this->num_managers; ++i) {
this->managers[i].UpdateUsedHeapSize();
} }
} }
@@ -354,12 +383,12 @@ namespace ams::kern {
return ResultSuccess(); return ResultSuccess();
} }
size_t KMemoryManager::Impl::Initialize(const KMemoryRegion *region, Pool p, KVirtualAddress management, KVirtualAddress management_end) { size_t KMemoryManager::Impl::Initialize(uintptr_t address, size_t size, KVirtualAddress management, KVirtualAddress management_end, Pool p) {
/* Calculate management sizes. */ /* Calculate management sizes. */
const size_t ref_count_size = (region->GetSize() / PageSize) * sizeof(u16); const size_t ref_count_size = (size / PageSize) * sizeof(u16);
const size_t optimize_map_size = CalculateOptimizedProcessOverheadSize(region->GetSize()); const size_t optimize_map_size = CalculateOptimizedProcessOverheadSize(size);
const size_t manager_size = util::AlignUp(optimize_map_size + ref_count_size, PageSize); const size_t manager_size = util::AlignUp(optimize_map_size + ref_count_size, PageSize);
const size_t page_heap_size = KPageHeap::CalculateManagementOverheadSize(region->GetSize()); const size_t page_heap_size = KPageHeap::CalculateManagementOverheadSize(size);
const size_t total_management_size = manager_size + page_heap_size; const size_t total_management_size = manager_size + page_heap_size;
MESOSPHERE_ABORT_UNLESS(manager_size <= total_management_size); MESOSPHERE_ABORT_UNLESS(manager_size <= total_management_size);
MESOSPHERE_ABORT_UNLESS(management + total_management_size <= management_end); MESOSPHERE_ABORT_UNLESS(management + total_management_size <= management_end);
@@ -372,13 +401,7 @@ namespace ams::kern {
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(this->management_region), PageSize)); MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(this->management_region), PageSize));
/* Initialize the manager's KPageHeap. */ /* Initialize the manager's KPageHeap. */
this->heap.Initialize(region->GetAddress(), region->GetSize(), management + manager_size, page_heap_size); this->heap.Initialize(address, size, management + manager_size, page_heap_size);
/* Free the memory to the heap. */
this->heap.Free(region->GetAddress(), region->GetSize() / PageSize);
/* Update the heap's used size. */
this->heap.UpdateUsedSize();
return total_management_size; return total_management_size;
} }

View File

@@ -1807,6 +1807,9 @@ namespace ams::kern {
const KMemoryRegion *region = KMemoryLayout::GetPhysicalMemoryRegionTree().FindFirstDerived(region_type); const KMemoryRegion *region = KMemoryLayout::GetPhysicalMemoryRegionTree().FindFirstDerived(region_type);
R_UNLESS(region != nullptr, svc::ResultOutOfRange()); R_UNLESS(region != nullptr, svc::ResultOutOfRange());
/* Check that the region is valid. */
MESOSPHERE_ABORT_UNLESS(region->GetEndAddress() != 0);
/* Map the region. */ /* Map the region. */
R_TRY_CATCH(this->MapStatic(region->GetAddress(), region->GetSize(), perm)) { R_TRY_CATCH(this->MapStatic(region->GetAddress(), region->GetSize(), perm)) {
R_CONVERT(svc::ResultInvalidAddress, svc::ResultOutOfRange()) R_CONVERT(svc::ResultInvalidAddress, svc::ResultOutOfRange())
@@ -3051,6 +3054,9 @@ namespace ams::kern {
return ResultSuccess(); return ResultSuccess();
} }
#pragma GCC push_options
#pragma GCC optimize ("-O3")
Result KPageTableBase::SetupForIpcClient(PageLinkedList *page_list, size_t *out_blocks_needed, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state) { Result KPageTableBase::SetupForIpcClient(PageLinkedList *page_list, size_t *out_blocks_needed, KProcessAddress address, size_t size, KMemoryPermission test_perm, KMemoryState dst_state) {
/* Validate pre-conditions. */ /* Validate pre-conditions. */
MESOSPHERE_ASSERT(this->IsLockedByCurrentThread()); MESOSPHERE_ASSERT(this->IsLockedByCurrentThread());
@@ -3704,6 +3710,8 @@ namespace ams::kern {
} }
} }
#pragma GCC pop_options
Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) { Result KPageTableBase::MapPhysicalMemory(KProcessAddress address, size_t size) {
/* Lock the physical memory lock. */ /* Lock the physical memory lock. */
KScopedLightLock phys_lk(this->map_physical_memory_lock); KScopedLightLock phys_lk(this->map_physical_memory_lock);

View File

@@ -129,6 +129,17 @@ namespace ams::kern {
} }
} }
/* Close all references to our betas. */
{
auto it = this->beta_list.begin();
while (it != this->beta_list.end()) {
KBeta *beta = std::addressof(*it);
it = this->beta_list.erase(it);
beta->Close();
}
}
/* Our thread local page list must be empty at this point. */ /* Our thread local page list must be empty at this point. */
MESOSPHERE_ABORT_UNLESS(this->partially_used_tlp_tree.empty()); MESOSPHERE_ABORT_UNLESS(this->partially_used_tlp_tree.empty());
MESOSPHERE_ABORT_UNLESS(this->fully_used_tlp_tree.empty()); MESOSPHERE_ABORT_UNLESS(this->fully_used_tlp_tree.empty());
@@ -922,7 +933,7 @@ namespace ams::kern {
mem_reservation.Commit(); mem_reservation.Commit();
/* Note for debug that we're running a new process. */ /* Note for debug that we're running a new process. */
MESOSPHERE_LOG("KProcess::Run() pid=%ld name=%-12s thread=%ld affinity=0x%lx ideal_core=%d active_core=%d\n", this->process_id, this->name, main_thread->GetId(), main_thread->GetAffinityMask().GetAffinityMask(), main_thread->GetIdealCore(), main_thread->GetActiveCore()); MESOSPHERE_LOG("KProcess::Run() pid=%ld name=%-12s thread=%ld affinity=0x%lx ideal_core=%d active_core=%d\n", this->process_id, this->name, main_thread->GetId(), main_thread->GetVirtualAffinityMask(), main_thread->GetIdealVirtualCore(), main_thread->GetActiveCore());
return ResultSuccess(); return ResultSuccess();
} }

View File

@@ -17,6 +17,9 @@
namespace ams::kern { namespace ams::kern {
#pragma GCC push_options
#pragma GCC optimize ("-O3")
namespace ipc { namespace ipc {
using MessageBuffer = ams::svc::ipc::MessageBuffer; using MessageBuffer = ams::svc::ipc::MessageBuffer;
@@ -1362,4 +1365,6 @@ namespace ams::kern {
this->NotifyAvailable(svc::ResultSessionClosed()); this->NotifyAvailable(svc::ResultSessionClosed());
} }
#pragma GCC pop_options
} }

View File

@@ -38,13 +38,17 @@ namespace ams::kern {
} }
Result KThread::Initialize(KThreadFunction func, uintptr_t arg, void *kern_stack_top, KProcessAddress user_stack_top, s32 prio, s32 core, KProcess *owner, ThreadType type) { Result KThread::Initialize(KThreadFunction func, uintptr_t arg, void *kern_stack_top, KProcessAddress user_stack_top, s32 prio, s32 virt_core, KProcess *owner, ThreadType type) {
/* Assert parameters are valid. */ /* Assert parameters are valid. */
MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(kern_stack_top != nullptr); MESOSPHERE_ASSERT(kern_stack_top != nullptr);
MESOSPHERE_ASSERT((type == ThreadType_Main) || (ams::svc::HighestThreadPriority <= prio && prio <= ams::svc::LowestThreadPriority)); MESOSPHERE_ASSERT((type == ThreadType_Main) || (ams::svc::HighestThreadPriority <= prio && prio <= ams::svc::LowestThreadPriority));
MESOSPHERE_ASSERT((owner != nullptr) || (type != ThreadType_User)); MESOSPHERE_ASSERT((owner != nullptr) || (type != ThreadType_User));
MESOSPHERE_ASSERT(0 <= core && core < static_cast<s32>(cpu::NumCores)); MESOSPHERE_ASSERT(0 <= virt_core && virt_core < static_cast<s32>(BITSIZEOF(u64)));
/* Convert the virtual core to a physical core. */
const s32 phys_core = cpu::VirtualToPhysicalCoreMap[virt_core];
MESOSPHERE_ASSERT(0 <= phys_core && phys_core < static_cast<s32>(cpu::NumCores));
/* First, clear the TLS address. */ /* First, clear the TLS address. */
this->tls_address = Null<KProcessAddress>; this->tls_address = Null<KProcessAddress>;
@@ -59,8 +63,8 @@ namespace ams::kern {
} }
[[fallthrough]]; [[fallthrough]];
case ThreadType_HighPriority: case ThreadType_HighPriority:
{ if (type != ThreadType_Main) {
MESOSPHERE_ASSERT(core == GetCurrentCoreId()); MESOSPHERE_ASSERT(phys_core == GetCurrentCoreId());
} }
[[fallthrough]]; [[fallthrough]];
case ThreadType_Kernel: case ThreadType_Kernel:
@@ -71,8 +75,8 @@ namespace ams::kern {
[[fallthrough]]; [[fallthrough]];
case ThreadType_User: case ThreadType_User:
{ {
MESOSPHERE_ASSERT(((owner == nullptr) || (owner->GetCoreMask() | (1ul << core)) == owner->GetCoreMask())); MESOSPHERE_ASSERT(((owner == nullptr) || (owner->GetCoreMask() | (1ul << virt_core)) == owner->GetCoreMask()));
MESOSPHERE_ASSERT(((owner == nullptr) || (owner->GetPriorityMask() | (1ul << prio)) == owner->GetPriorityMask())); MESOSPHERE_ASSERT(((owner == nullptr) || (owner->GetPriorityMask() | (1ul << prio)) == owner->GetPriorityMask()));
} }
break; break;
default: default:
@@ -81,8 +85,10 @@ namespace ams::kern {
} }
/* Set the ideal core ID and affinity mask. */ /* Set the ideal core ID and affinity mask. */
this->ideal_core_id = core; this->virtual_ideal_core_id = virt_core;
this->affinity_mask.SetAffinity(core, true); this->physical_ideal_core_id = phys_core;
this->virtual_affinity_mask = (static_cast<u64>(1) << virt_core);
this->physical_affinity_mask.SetAffinity(phys_core, true);
/* Set the thread state. */ /* Set the thread state. */
this->thread_state = (type == ThreadType_Main) ? ThreadState_Runnable : ThreadState_Initialized; this->thread_state = (type == ThreadType_Main) ? ThreadState_Runnable : ThreadState_Initialized;
@@ -103,7 +109,7 @@ namespace ams::kern {
this->cancellable = false; this->cancellable = false;
/* Set core ID and wait result. */ /* Set core ID and wait result. */
this->core_id = this->ideal_core_id; this->core_id = phys_core;
this->wait_result = svc::ResultNoSynchronizationObject(); this->wait_result = svc::ResultNoSynchronizationObject();
/* Set the stack top. */ /* Set the stack top. */
@@ -141,7 +147,7 @@ namespace ams::kern {
this->num_kernel_waiters = 0; this->num_kernel_waiters = 0;
/* Set our current core id. */ /* Set our current core id. */
this->current_core_id = core; this->current_core_id = phys_core;
/* We haven't released our resource limit hint, and we've spent no time on the cpu. */ /* We haven't released our resource limit hint, and we've spent no time on the cpu. */
this->resource_limit_release_hint = 0; this->resource_limit_release_hint = 0;
@@ -201,6 +207,7 @@ namespace ams::kern {
Result KThread::InitializeThread(KThread *thread, KThreadFunction func, uintptr_t arg, KProcessAddress user_stack_top, s32 prio, s32 core, KProcess *owner, ThreadType type) { Result KThread::InitializeThread(KThread *thread, KThreadFunction func, uintptr_t arg, KProcessAddress user_stack_top, s32 prio, s32 core, KProcess *owner, ThreadType type) {
/* Get stack region for the thread. */ /* Get stack region for the thread. */
const auto &stack_region = KMemoryLayout::GetKernelStackRegion(); const auto &stack_region = KMemoryLayout::GetKernelStackRegion();
MESOSPHERE_ABORT_UNLESS(stack_region.GetEndAddress() != 0);
/* Allocate a page to use as the thread. */ /* Allocate a page to use as the thread. */
KPageBuffer *page = KPageBuffer::Allocate(); KPageBuffer *page = KPageBuffer::Allocate();
@@ -390,20 +397,19 @@ namespace ams::kern {
++this->num_core_migration_disables; ++this->num_core_migration_disables;
/* Save our ideal state to restore when we're unpinned. */ /* Save our ideal state to restore when we're unpinned. */
this->original_ideal_core_id = this->ideal_core_id; this->original_physical_ideal_core_id = this->physical_ideal_core_id;
this->original_affinity_mask = this->affinity_mask; this->original_physical_affinity_mask = this->physical_affinity_mask;
/* Bind ourselves to this core. */ /* Bind ourselves to this core. */
const s32 active_core = this->GetActiveCore(); const s32 active_core = this->GetActiveCore();
const s32 current_core = GetCurrentCoreId(); const s32 current_core = GetCurrentCoreId();
this->SetActiveCore(current_core); this->SetActiveCore(current_core);
this->ideal_core_id = current_core; this->physical_ideal_core_id = current_core;
this->physical_affinity_mask.SetAffinityMask(1ul << current_core);
this->affinity_mask.SetAffinityMask(1ul << current_core); if (active_core != current_core || this->physical_affinity_mask.GetAffinityMask() != this->original_physical_affinity_mask.GetAffinityMask()) {
KScheduler::OnThreadAffinityMaskChanged(this, this->original_physical_affinity_mask, active_core);
if (active_core != current_core || this->affinity_mask.GetAffinityMask() != this->original_affinity_mask.GetAffinityMask()) {
KScheduler::OnThreadAffinityMaskChanged(this, this->original_affinity_mask, active_core);
} }
} }
@@ -438,19 +444,19 @@ namespace ams::kern {
--this->num_core_migration_disables; --this->num_core_migration_disables;
/* Restore our original state. */ /* Restore our original state. */
const KAffinityMask old_mask = this->affinity_mask; const KAffinityMask old_mask = this->physical_affinity_mask;
this->ideal_core_id = this->original_ideal_core_id; this->physical_ideal_core_id = this->original_physical_ideal_core_id;
this->affinity_mask = this->original_affinity_mask; this->physical_affinity_mask = this->original_physical_affinity_mask;
if (this->affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { if (this->physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) {
const s32 active_core = this->GetActiveCore(); const s32 active_core = this->GetActiveCore();
if (!this->affinity_mask.GetAffinity(active_core)) { if (!this->physical_affinity_mask.GetAffinity(active_core)) {
if (this->ideal_core_id >= 0) { if (this->physical_ideal_core_id >= 0) {
this->SetActiveCore(this->ideal_core_id); this->SetActiveCore(this->physical_ideal_core_id);
} else { } else {
this->SetActiveCore(BITSIZEOF(unsigned long long) - 1 - __builtin_clzll(this->affinity_mask.GetAffinityMask())); this->SetActiveCore(BITSIZEOF(unsigned long long) - 1 - __builtin_clzll(this->physical_affinity_mask.GetAffinityMask()));
} }
} }
KScheduler::OnThreadAffinityMaskChanged(this, old_mask, active_core); KScheduler::OnThreadAffinityMaskChanged(this, old_mask, active_core);
@@ -492,16 +498,16 @@ namespace ams::kern {
MESOSPHERE_ASSERT(this->num_core_migration_disables >= 0); MESOSPHERE_ASSERT(this->num_core_migration_disables >= 0);
if ((this->num_core_migration_disables++) == 0) { if ((this->num_core_migration_disables++) == 0) {
/* Save our ideal state to restore when we can migrate again. */ /* Save our ideal state to restore when we can migrate again. */
this->original_ideal_core_id = this->ideal_core_id; this->original_physical_ideal_core_id = this->physical_ideal_core_id;
this->original_affinity_mask = this->affinity_mask; this->original_physical_affinity_mask = this->physical_affinity_mask;
/* Bind ourselves to this core. */ /* Bind ourselves to this core. */
const s32 active_core = this->GetActiveCore(); const s32 active_core = this->GetActiveCore();
this->ideal_core_id = active_core; this->physical_ideal_core_id = active_core;
this->affinity_mask.SetAffinityMask(1ul << active_core); this->physical_affinity_mask.SetAffinityMask(1ul << active_core);
if (this->affinity_mask.GetAffinityMask() != this->original_affinity_mask.GetAffinityMask()) { if (this->physical_affinity_mask.GetAffinityMask() != this->original_physical_affinity_mask.GetAffinityMask()) {
KScheduler::OnThreadAffinityMaskChanged(this, this->original_affinity_mask, active_core); KScheduler::OnThreadAffinityMaskChanged(this, this->original_physical_affinity_mask, active_core);
} }
} }
} }
@@ -513,20 +519,20 @@ namespace ams::kern {
KScopedSchedulerLock sl; KScopedSchedulerLock sl;
MESOSPHERE_ASSERT(this->num_core_migration_disables > 0); MESOSPHERE_ASSERT(this->num_core_migration_disables > 0);
if ((--this->num_core_migration_disables) == 0) { if ((--this->num_core_migration_disables) == 0) {
const KAffinityMask old_mask = this->affinity_mask; const KAffinityMask old_mask = this->physical_affinity_mask;
/* Restore our ideals. */ /* Restore our ideals. */
this->ideal_core_id = this->original_ideal_core_id; this->physical_ideal_core_id = this->original_physical_ideal_core_id;
this->affinity_mask = this->original_affinity_mask; this->physical_affinity_mask = this->original_physical_affinity_mask;
if (this->affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { if (this->physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) {
const s32 active_core = this->GetActiveCore(); const s32 active_core = this->GetActiveCore();
if (!this->affinity_mask.GetAffinity(active_core)) { if (!this->physical_affinity_mask.GetAffinity(active_core)) {
if (this->ideal_core_id >= 0) { if (this->physical_ideal_core_id >= 0) {
this->SetActiveCore(this->ideal_core_id); this->SetActiveCore(this->physical_ideal_core_id);
} else { } else {
this->SetActiveCore(BITSIZEOF(unsigned long long) - 1 - __builtin_clzll(this->affinity_mask.GetAffinityMask())); this->SetActiveCore(BITSIZEOF(unsigned long long) - 1 - __builtin_clzll(this->physical_affinity_mask.GetAffinityMask()));
} }
} }
KScheduler::OnThreadAffinityMaskChanged(this, old_mask, active_core); KScheduler::OnThreadAffinityMaskChanged(this, old_mask, active_core);
@@ -535,6 +541,19 @@ namespace ams::kern {
} }
Result KThread::GetCoreMask(int32_t *out_ideal_core, u64 *out_affinity_mask) { Result KThread::GetCoreMask(int32_t *out_ideal_core, u64 *out_affinity_mask) {
MESOSPHERE_ASSERT_THIS();
{
KScopedSchedulerLock sl;
/* Get the virtual mask. */
*out_ideal_core = this->virtual_ideal_core_id;
*out_affinity_mask = this->virtual_affinity_mask;
}
return ResultSuccess();
}
Result KThread::GetPhysicalCoreMask(int32_t *out_ideal_core, u64 *out_affinity_mask) {
MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT_THIS();
{ {
KScopedSchedulerLock sl; KScopedSchedulerLock sl;
@@ -542,63 +561,72 @@ namespace ams::kern {
/* Select between core mask and original core mask. */ /* Select between core mask and original core mask. */
if (this->num_core_migration_disables == 0) { if (this->num_core_migration_disables == 0) {
*out_ideal_core = this->ideal_core_id; *out_ideal_core = this->physical_ideal_core_id;
*out_affinity_mask = this->affinity_mask.GetAffinityMask(); *out_affinity_mask = this->physical_affinity_mask.GetAffinityMask();
} else { } else {
*out_ideal_core = this->original_ideal_core_id; *out_ideal_core = this->original_physical_ideal_core_id;
*out_affinity_mask = this->original_affinity_mask.GetAffinityMask(); *out_affinity_mask = this->original_physical_affinity_mask.GetAffinityMask();
} }
} }
return ResultSuccess(); return ResultSuccess();
} }
Result KThread::SetCoreMask(int32_t ideal_core, u64 affinity_mask) { Result KThread::SetCoreMask(int32_t core_id, u64 v_affinity_mask) {
MESOSPHERE_ASSERT_THIS(); MESOSPHERE_ASSERT_THIS();
MESOSPHERE_ASSERT(this->parent != nullptr); MESOSPHERE_ASSERT(this->parent != nullptr);
MESOSPHERE_ASSERT(affinity_mask != 0); MESOSPHERE_ASSERT(v_affinity_mask != 0);
KScopedLightLock lk(this->activity_pause_lock); KScopedLightLock lk(this->activity_pause_lock);
/* Set the core mask. */ /* Set the core mask. */
u64 p_affinity_mask = 0;
{ {
KScopedSchedulerLock sl; KScopedSchedulerLock sl;
MESOSPHERE_ASSERT(this->num_core_migration_disables >= 0); MESOSPHERE_ASSERT(this->num_core_migration_disables >= 0);
/* If the core id is no-update magic, preserve the ideal core id. */ /* If the core id is no-update magic, preserve the ideal core id. */
if (ideal_core == ams::svc::IdealCoreNoUpdate) { if (core_id == ams::svc::IdealCoreNoUpdate) {
if (this->num_core_migration_disables == 0) { core_id = this->virtual_ideal_core_id;
ideal_core = this->ideal_core_id; R_UNLESS(((1ul << core_id) & v_affinity_mask) != 0, svc::ResultInvalidCombination());
} else { }
ideal_core = this->original_ideal_core_id;
}
R_UNLESS(((1ul << ideal_core) & affinity_mask) != 0, svc::ResultInvalidCombination()); /* Set the virtual core/affinity mask. */
this->virtual_ideal_core_id = core_id;
this->virtual_affinity_mask = v_affinity_mask;
/* Translate the virtual core to a physical core. */
if (core_id >= 0) {
core_id = cpu::VirtualToPhysicalCoreMap[core_id];
}
/* Translate the virtual affinity mask to a physical one. */
while (v_affinity_mask != 0) {
const u64 next = __builtin_ctzll(v_affinity_mask);
v_affinity_mask &= ~(1ul << next);
p_affinity_mask |= (1ul << cpu::VirtualToPhysicalCoreMap[next]);
} }
/* If we haven't disabled migration, perform an affinity change. */ /* If we haven't disabled migration, perform an affinity change. */
if (this->num_core_migration_disables == 0) { if (this->num_core_migration_disables == 0) {
const KAffinityMask old_mask = this->affinity_mask; const KAffinityMask old_mask = this->physical_affinity_mask;
/* Set our new ideals. */ /* Set our new ideals. */
this->ideal_core_id = ideal_core; this->physical_ideal_core_id = core_id;
this->affinity_mask.SetAffinityMask(affinity_mask); this->physical_affinity_mask.SetAffinityMask(p_affinity_mask);
if (this->affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) { if (this->physical_affinity_mask.GetAffinityMask() != old_mask.GetAffinityMask()) {
const s32 active_core = this->GetActiveCore(); const s32 active_core = this->GetActiveCore();
if (active_core >= 0) { if (active_core >= 0 && !this->physical_affinity_mask.GetAffinity(active_core)) {
if (!this->affinity_mask.GetAffinity(active_core)) { const s32 new_core = this->physical_ideal_core_id >= 0 ? this->physical_ideal_core_id : BITSIZEOF(unsigned long long) - 1 - __builtin_clzll(this->physical_affinity_mask.GetAffinityMask());
this->SetActiveCore(this->ideal_core_id); this->SetActiveCore(new_core);
} else {
this->SetActiveCore(BITSIZEOF(unsigned long long) - 1 - __builtin_clzll(this->affinity_mask.GetAffinityMask()));
}
} }
KScheduler::OnThreadAffinityMaskChanged(this, old_mask, active_core); KScheduler::OnThreadAffinityMaskChanged(this, old_mask, active_core);
} }
} else { } else {
/* Otherwise, we edit the original affinity for restoration later. */ /* Otherwise, we edit the original affinity for restoration later. */
this->original_ideal_core_id = ideal_core; this->original_physical_ideal_core_id = core_id;
this->original_affinity_mask.SetAffinityMask(affinity_mask); this->original_physical_affinity_mask.SetAffinityMask(p_affinity_mask);
} }
} }
@@ -627,7 +655,7 @@ namespace ams::kern {
} }
/* If the thread is currently running, check whether it's no longer allowed under the new mask. */ /* If the thread is currently running, check whether it's no longer allowed under the new mask. */
if (thread_is_current && ((1ul << thread_core) & affinity_mask) == 0) { if (thread_is_current && ((1ul << thread_core) & p_affinity_mask) == 0) {
/* If the thread is pinned, we want to wait until it's not pinned. */ /* If the thread is pinned, we want to wait until it's not pinned. */
if (this->GetStackParameters().is_pinned) { if (this->GetStackParameters().is_pinned) {
/* Verify that the current thread isn't terminating. */ /* Verify that the current thread isn't terminating. */
@@ -1127,7 +1155,7 @@ namespace ams::kern {
/* If the thread is runnable, send a termination interrupt to other cores. */ /* If the thread is runnable, send a termination interrupt to other cores. */
if (this->GetState() == ThreadState_Runnable) { if (this->GetState() == ThreadState_Runnable) {
if (const u64 core_mask = this->affinity_mask.GetAffinityMask() & ~(1ul << GetCurrentCoreId()); core_mask != 0) { if (const u64 core_mask = this->physical_affinity_mask.GetAffinityMask() & ~(1ul << GetCurrentCoreId()); core_mask != 0) {
cpu::DataSynchronizationBarrier(); cpu::DataSynchronizationBarrier();
Kernel::GetInterruptManager().SendInterProcessorInterrupt(KInterruptName_ThreadTerminate, core_mask); Kernel::GetInterruptManager().SendInterProcessorInterrupt(KInterruptName_ThreadTerminate, core_mask);
} }

View File

@@ -52,6 +52,8 @@ namespace ams::kern {
/* Initialize the memory manager and the KPageBuffer slabheap. */ /* Initialize the memory manager and the KPageBuffer slabheap. */
{ {
const auto &management_region = KMemoryLayout::GetPoolManagementRegion(); const auto &management_region = KMemoryLayout::GetPoolManagementRegion();
MESOSPHERE_ABORT_UNLESS(management_region.GetEndAddress() != 0);
Kernel::GetMemoryManager().Initialize(management_region.GetAddress(), management_region.GetSize()); Kernel::GetMemoryManager().Initialize(management_region.GetAddress(), management_region.GetSize());
init::InitializeKPageBufferSlabHeap(); init::InitializeKPageBufferSlabHeap();
} }
@@ -68,6 +70,8 @@ namespace ams::kern {
/* Initialize the Dynamic Slab Heaps. */ /* Initialize the Dynamic Slab Heaps. */
{ {
const auto &pt_heap_region = KMemoryLayout::GetPageTableHeapRegion(); const auto &pt_heap_region = KMemoryLayout::GetPageTableHeapRegion();
MESOSPHERE_ABORT_UNLESS(pt_heap_region.GetEndAddress() != 0);
Kernel::InitializeResourceManagers(pt_heap_region.GetAddress(), pt_heap_region.GetSize()); Kernel::InitializeResourceManagers(pt_heap_region.GetAddress(), pt_heap_region.GetSize());
} }
} }
@@ -124,6 +128,13 @@ namespace ams::kern {
/* Resume all threads suspended while we initialized. */ /* Resume all threads suspended while we initialized. */
KThread::ResumeThreadsSuspendedForInit(); KThread::ResumeThreadsSuspendedForInit();
/* Validate that all reserved dram blocks are valid. */
for (const auto &region : KMemoryLayout::GetPhysicalMemoryRegionTree()) {
if (region.IsDerivedFrom(KMemoryRegionType_DramReservedBase)) {
MESOSPHERE_ABORT_UNLESS(region.GetEndAddress() != 0);
}
}
} }
cpu::SynchronizeAllCores(); cpu::SynchronizeAllCores();

View File

@@ -92,6 +92,9 @@ namespace ams::kern::svc {
/* Ensure that we found the region. */ /* Ensure that we found the region. */
R_UNLESS(region != nullptr, svc::ResultNotFound()); R_UNLESS(region != nullptr, svc::ResultNotFound());
/* Chcek that the region is valid. */
MESOSPHERE_ABORT_UNLESS(region->GetEndAddress() != 0);
R_TRY(pt.QueryStaticMapping(std::addressof(found_address), region->GetAddress(), region->GetSize())); R_TRY(pt.QueryStaticMapping(std::addressof(found_address), region->GetAddress(), region->GetSize()));
found_size = region->GetSize(); found_size = region->GetSize();
} }

View File

@@ -0,0 +1,79 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mesosphere.hpp>
namespace ams::kern::svc {
/* ============================= Common ============================= */
namespace {
Result Unknown39() {
return svc::ResultNotImplemented();
}
Result Unknown3A() {
return svc::ResultNotImplemented();
}
Result Unknown46() {
return svc::ResultNotImplemented();
}
Result Unknown47() {
return svc::ResultNotImplemented();
}
}
/* ============================= 64 ABI ============================= */
Result Unknown3964() {
return Unknown39();
}
Result Unknown3A64() {
/* NOTE: From official stubs, true API to this is something like Unknown3A(u64 *, u32_or_u64, u64, u64, u64_or_u32, u64_or_u32); */
return Unknown3A();
}
Result Unknown4664() {
return Unknown46();
}
Result Unknown4764() {
return Unknown47();
}
/* ============================= 64From32 ABI ============================= */
Result Unknown3964From32() {
return Unknown39();
}
Result Unknown3A64From32() {
return Unknown3A();
}
Result Unknown4664From32() {
return Unknown46();
}
Result Unknown4764From32() {
return Unknown47();
}
}

View File

@@ -363,7 +363,11 @@ namespace ams::kern::svc {
case ams::svc::DebugThreadParam_IdealCore: case ams::svc::DebugThreadParam_IdealCore:
{ {
/* Get the ideal core. */ /* Get the ideal core. */
*out_32 = thread->GetIdealCore(); s32 core_id;
u64 affinity_mask;
thread->GetPhysicalCoreMask(std::addressof(core_id), std::addressof(affinity_mask));
*out_32 = core_id;
} }
break; break;
case ams::svc::DebugThreadParam_CurrentCore: case ams::svc::DebugThreadParam_CurrentCore:
@@ -375,7 +379,11 @@ namespace ams::kern::svc {
case ams::svc::DebugThreadParam_AffinityMask: case ams::svc::DebugThreadParam_AffinityMask:
{ {
/* Get the affinity mask. */ /* Get the affinity mask. */
*out_32 = thread->GetAffinityMask().GetAffinityMask(); s32 core_id;
u64 affinity_mask;
thread->GetPhysicalCoreMask(std::addressof(core_id), std::addressof(affinity_mask));
*out_32 = affinity_mask;
} }
break; break;
default: default:

View File

@@ -206,28 +206,35 @@ namespace ams::kern::svc {
case ams::svc::InfoType_ThreadTickCount: case ams::svc::InfoType_ThreadTickCount:
{ {
/* Verify the requested core is valid. */ /* Verify the requested core is valid. */
const bool core_valid = (info_subtype == static_cast<u64>(-1ul)) || (info_subtype < cpu::NumCores); const bool core_valid = (info_subtype == static_cast<u64>(-1ul)) || (info_subtype < util::size(cpu::VirtualToPhysicalCoreMap));
R_UNLESS(core_valid, svc::ResultInvalidCombination()); R_UNLESS(core_valid, svc::ResultInvalidCombination());
/* Get the thread from its handle. */ /* Get the thread from its handle. */
KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(handle); KScopedAutoObject thread = GetCurrentProcess().GetHandleTable().GetObject<KThread>(handle);
R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle()); R_UNLESS(thread.IsNotNull(), svc::ResultInvalidHandle());
/* Get the tick count. */ /* Disable interrupts while we get the tick count. */
s64 tick_count; s64 tick_count;
if (info_subtype == static_cast<u64>(-1ul)) { {
tick_count = thread->GetCpuTime(); KScopedInterruptDisable di;
if (GetCurrentThreadPointer() == thread.GetPointerUnsafe()) {
const s64 cur_tick = KHardwareTimer::GetTick(); if (info_subtype == static_cast<u64>(-1ul)) {
const s64 prev_switch = Kernel::GetScheduler().GetLastContextSwitchTime(); tick_count = thread->GetCpuTime();
tick_count += (cur_tick - prev_switch); if (GetCurrentThreadPointer() == thread.GetPointerUnsafe()) {
} const s64 cur_tick = KHardwareTimer::GetTick();
} else { const s64 prev_switch = Kernel::GetScheduler().GetLastContextSwitchTime();
tick_count = thread->GetCpuTime(static_cast<s32>(info_subtype)); tick_count += (cur_tick - prev_switch);
if (GetCurrentThreadPointer() == thread.GetPointerUnsafe() && static_cast<s32>(info_subtype) == GetCurrentCoreId()) { }
const s64 cur_tick = KHardwareTimer::GetTick(); } else {
const s64 prev_switch = Kernel::GetScheduler().GetLastContextSwitchTime(); const s32 phys_core = cpu::VirtualToPhysicalCoreMap[info_subtype];
tick_count += (cur_tick - prev_switch); MESOSPHERE_ABORT_UNLESS(phys_core < static_cast<s32>(cpu::NumCores));
tick_count = thread->GetCpuTime(phys_core);
if (GetCurrentThreadPointer() == thread.GetPointerUnsafe() && phys_core == GetCurrentCoreId()) {
const s64 cur_tick = KHardwareTimer::GetTick();
const s64 prev_switch = Kernel::GetScheduler().GetLastContextSwitchTime();
tick_count += (cur_tick - prev_switch);
}
} }
} }

View File

@@ -17,6 +17,9 @@
namespace ams::kern::svc { namespace ams::kern::svc {
#pragma GCC push_options
#pragma GCC optimize ("-O3")
/* ============================= Common ============================= */ /* ============================= Common ============================= */
namespace { namespace {
@@ -304,4 +307,6 @@ namespace ams::kern::svc {
return ReplyAndReceiveWithUserBuffer(out_index, message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns); return ReplyAndReceiveWithUserBuffer(out_index, message_buffer, message_buffer_size, handles, num_handles, reply_target, timeout_ns);
} }
#pragma GCC pop_options
} }

View File

@@ -22,7 +22,31 @@ namespace ams::kern::svc {
namespace { namespace {
int32_t GetCurrentProcessorNumber() { int32_t GetCurrentProcessorNumber() {
return GetCurrentCoreId(); /* Setup variables to track affinity information. */
s32 current_phys_core;
u64 v_affinity_mask = 0;
/* Forever try to get the affinity. */
while (true) {
/* Update affinity information if we've run out. */
while (v_affinity_mask == 0) {
current_phys_core = GetCurrentCoreId();
v_affinity_mask = GetCurrentThread().GetVirtualAffinityMask();
if ((v_affinity_mask & (1ul << current_phys_core)) != 0) {
return current_phys_core;
}
}
/* Check the next virtual bit. */
do {
const s32 next_virt_core = static_cast<s32>(__builtin_ctzll(v_affinity_mask));
if (current_phys_core == cpu::VirtualToPhysicalCoreMap[next_virt_core]) {
return next_virt_core;
}
v_affinity_mask &= ~(1ul << next_virt_core);
} while (v_affinity_mask != 0);
}
} }
} }

View File

@@ -62,7 +62,7 @@ namespace ams::kern::svc {
R_UNLESS(resource_limit.IsNotNull(), svc::ResultInvalidHandle()); R_UNLESS(resource_limit.IsNotNull(), svc::ResultInvalidHandle());
/* Get the peak value. */ /* Get the peak value. */
*out_peak_value = resource_limit->GetCurrentValue(which); *out_peak_value = resource_limit->GetPeakValue(which);
return ResultSuccess(); return ResultSuccess();
} }

View File

@@ -210,7 +210,8 @@ namespace ams::ldr {
MetaFlag_AddressSpaceTypeShift = 1, MetaFlag_AddressSpaceTypeShift = 1,
MetaFlag_AddressSpaceTypeMask = (7 << MetaFlag_AddressSpaceTypeShift), MetaFlag_AddressSpaceTypeMask = (7 << MetaFlag_AddressSpaceTypeShift),
MetaFlag_OptimizeMemoryAllocation = (1 << 4), MetaFlag_OptimizeMemoryAllocation = (1 << 4),
MetaFlag_DisableDeviceAddressSpaceMerge = (1 << 5),
}; };
enum AddressSpaceType { enum AddressSpaceType {

View File

@@ -400,6 +400,8 @@ struct { \
RB_PROTOTYPE_REMOVE(name, type, attr); \ RB_PROTOTYPE_REMOVE(name, type, attr); \
RB_PROTOTYPE_FIND(name, type, attr); \ RB_PROTOTYPE_FIND(name, type, attr); \
RB_PROTOTYPE_NFIND(name, type, attr); \ RB_PROTOTYPE_NFIND(name, type, attr); \
RB_PROTOTYPE_FIND_LIGHT(name, type, attr); \
RB_PROTOTYPE_NFIND_LIGHT(name, type, attr); \
RB_PROTOTYPE_NEXT(name, type, attr); \ RB_PROTOTYPE_NEXT(name, type, attr); \
RB_PROTOTYPE_PREV(name, type, attr); \ RB_PROTOTYPE_PREV(name, type, attr); \
RB_PROTOTYPE_MINMAX(name, type, attr); RB_PROTOTYPE_MINMAX(name, type, attr);
@@ -415,6 +417,10 @@ struct { \
attr struct type *name##_RB_FIND(struct name *, struct type *) attr struct type *name##_RB_FIND(struct name *, struct type *)
#define RB_PROTOTYPE_NFIND(name, type, attr) \ #define RB_PROTOTYPE_NFIND(name, type, attr) \
attr struct type *name##_RB_NFIND(struct name *, struct type *) attr struct type *name##_RB_NFIND(struct name *, struct type *)
#define RB_PROTOTYPE_FIND_LIGHT(name, type, attr) \
attr struct type *name##_RB_FIND_LIGHT(struct name *, const void *)
#define RB_PROTOTYPE_NFIND_LIGHT(name, type, attr) \
attr struct type *name##_RB_NFIND_LIGHT(struct name *, const void *)
#define RB_PROTOTYPE_NEXT(name, type, attr) \ #define RB_PROTOTYPE_NEXT(name, type, attr) \
attr struct type *name##_RB_NEXT(struct type *) attr struct type *name##_RB_NEXT(struct type *)
#define RB_PROTOTYPE_PREV(name, type, attr) \ #define RB_PROTOTYPE_PREV(name, type, attr) \
@@ -436,15 +442,17 @@ struct { \
RB_GENERATE_PREV(name, type, field, attr) \ RB_GENERATE_PREV(name, type, field, attr) \
RB_GENERATE_MINMAX(name, type, field, attr) RB_GENERATE_MINMAX(name, type, field, attr)
#define RB_GENERATE_WITH_COMPARE(name, type, field, cmp) \ #define RB_GENERATE_WITH_COMPARE(name, type, field, cmp, lcmp) \
RB_GENERATE_WITH_COMPARE_INTERNAL(name, type, field, cmp,) RB_GENERATE_WITH_COMPARE_INTERNAL(name, type, field, cmp, lcmp,)
#define RB_GENERATE_WITH_COMPARE_STATIC(name, type, field, cmp) \ #define RB_GENERATE_WITH_COMPARE_STATIC(name, type, field, cmp, lcmp) \
RB_GENERATE_WITH_COMPARE_INTERNAL(name, type, field, cmp, __unused static) RB_GENERATE_WITH_COMPARE_INTERNAL(name, type, field, cmp, lcmp, __unused static)
#define RB_GENERATE_WITH_COMPARE_INTERNAL(name, type, field, cmp, attr) \ #define RB_GENERATE_WITH_COMPARE_INTERNAL(name, type, field, cmp, lcmp, attr) \
RB_GENERATE_INSERT_COLOR(name, type, field, attr) \ RB_GENERATE_INSERT_COLOR(name, type, field, attr) \
RB_GENERATE_INSERT(name, type, field, cmp, attr) \ RB_GENERATE_INSERT(name, type, field, cmp, attr) \
RB_GENERATE_FIND(name, type, field, cmp, attr) \ RB_GENERATE_FIND(name, type, field, cmp, attr) \
RB_GENERATE_NFIND(name, type, field, cmp, attr) RB_GENERATE_NFIND(name, type, field, cmp, attr) \
RB_GENERATE_FIND_LIGHT(name, type, field, lcmp, attr) \
RB_GENERATE_NFIND_LIGHT(name, type, field, lcmp, attr)
#define RB_GENERATE_ALL(name, type, field, cmp) \ #define RB_GENERATE_ALL(name, type, field, cmp) \
RB_GENERATE_ALL_INTERNAL(name, type, field, cmp,) RB_GENERATE_ALL_INTERNAL(name, type, field, cmp,)
@@ -719,6 +727,47 @@ name##_RB_NFIND(struct name *head, struct type *elm) \
return (res); \ return (res); \
} }
#define RB_GENERATE_FIND_LIGHT(name, type, field, lcmp, attr) \
/* Finds the node with the same key as elm */ \
attr struct type * \
name##_RB_FIND_LIGHT(struct name *head, const void *lelm) \
{ \
struct type *tmp = RB_ROOT(head); \
int comp; \
while (tmp) { \
comp = lcmp(lelm, tmp); \
if (comp < 0) \
tmp = RB_LEFT(tmp, field); \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (NULL); \
}
#define RB_GENERATE_NFIND_LIGHT(name, type, field, lcmp, attr) \
/* Finds the first node greater than or equal to the search key */ \
attr struct type * \
name##_RB_NFIND_LIGHT(struct name *head, const void *lelm) \
{ \
struct type *tmp = RB_ROOT(head); \
struct type *res = NULL; \
int comp; \
while (tmp) { \
comp = lcmp(lelm, tmp); \
if (comp < 0) { \
res = tmp; \
tmp = RB_LEFT(tmp, field); \
} \
else if (comp > 0) \
tmp = RB_RIGHT(tmp, field); \
else \
return (tmp); \
} \
return (res); \
}
#define RB_GENERATE_NEXT(name, type, field, attr) \ #define RB_GENERATE_NEXT(name, type, field, attr) \
/* ARGSUSED */ \ /* ARGSUSED */ \
attr struct type * \ attr struct type * \
@@ -788,6 +837,8 @@ name##_RB_MINMAX(struct name *head, int val) \
#define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y) #define RB_REMOVE(name, x, y) name##_RB_REMOVE(x, y)
#define RB_FIND(name, x, y) name##_RB_FIND(x, y) #define RB_FIND(name, x, y) name##_RB_FIND(x, y)
#define RB_NFIND(name, x, y) name##_RB_NFIND(x, y) #define RB_NFIND(name, x, y) name##_RB_NFIND(x, y)
#define RB_FIND_LIGHT(name, x, y) name##_RB_FIND_LIGHT(x, y)
#define RB_NFIND_LIGHT(name, x, y) name##_RB_NFIND_LIGHT(x, y)
#define RB_NEXT(name, x, y) name##_RB_NEXT(y) #define RB_NEXT(name, x, y) name##_RB_NEXT(y)
#define RB_PREV(name, x, y) name##_RB_PREV(y) #define RB_PREV(name, x, y) name##_RB_PREV(y)
#define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF) #define RB_MIN(name, x) name##_RB_MINMAX(x, RB_NEGINF)

View File

@@ -16,7 +16,7 @@
#pragma once #pragma once
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0 #define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
#define ATMOSPHERE_RELEASE_VERSION_MINOR 15 #define ATMOSPHERE_RELEASE_VERSION_MINOR 16
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0 #define ATMOSPHERE_RELEASE_VERSION_MICRO 0
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO #define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO

View File

@@ -528,6 +528,7 @@ namespace ams::svc::codegen::impl {
/* Set omit-frame-pointer to prevent GCC from emitting MOV X29, SP instructions. */ /* Set omit-frame-pointer to prevent GCC from emitting MOV X29, SP instructions. */
#pragma GCC push_options #pragma GCC push_options
#pragma GCC optimize ("-O2")
#pragma GCC optimize ("omit-frame-pointer") #pragma GCC optimize ("omit-frame-pointer")
static ALWAYS_INLINE ReturnType WrapSvcFunction() { static ALWAYS_INLINE ReturnType WrapSvcFunction() {

View File

@@ -29,6 +29,7 @@ namespace ams::svc::codegen {
public: public:
/* Set omit-frame-pointer to prevent GCC from emitting MOV X29, SP instructions. */ /* Set omit-frame-pointer to prevent GCC from emitting MOV X29, SP instructions. */
#pragma GCC push_options #pragma GCC push_options
#pragma GCC optimize ("-O2")
#pragma GCC optimize ("omit-frame-pointer") #pragma GCC optimize ("omit-frame-pointer")
static ALWAYS_INLINE void Call64() { static ALWAYS_INLINE void Call64() {

View File

@@ -19,6 +19,9 @@
namespace ams::svc::ipc { namespace ams::svc::ipc {
#pragma GCC push_options
#pragma GCC optimize ("-O3")
ALWAYS_INLINE u32 *GetMessageBuffer() { ALWAYS_INLINE u32 *GetMessageBuffer() {
return GetThreadLocalRegion()->message_buffer; return GetThreadLocalRegion()->message_buffer;
} }
@@ -545,4 +548,6 @@ namespace ams::svc::ipc {
} }
}; };
#pragma GCC pop_options
} }

View File

@@ -85,6 +85,9 @@
HANDLER(0x36, void, SynchronizePreemptionState) \ 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)) \ HANDLER(0x37, Result, GetResourceLimitPeakValue, OUTPUT(int64_t, out_peak_value), INPUT(::ams::svc::Handle, resource_limit_handle), INPUT(::ams::svc::LimitableResource, which)) \
\ \
HANDLER(0x39, Result, Unknown39) \
HANDLER(0x3A, Result, Unknown3A) \
\
HANDLER(0x3C, void, KernelDebug, INPUT(::ams::svc::KernelDebugType, kern_debug_type), INPUT(uint64_t, arg0), INPUT(uint64_t, arg1), INPUT(uint64_t, arg2)) \ HANDLER(0x3C, void, KernelDebug, INPUT(::ams::svc::KernelDebugType, kern_debug_type), INPUT(uint64_t, arg0), INPUT(uint64_t, arg1), INPUT(uint64_t, arg2)) \
HANDLER(0x3D, void, ChangeKernelTraceState, INPUT(::ams::svc::KernelTraceState, kern_trace_state)) \ HANDLER(0x3D, void, ChangeKernelTraceState, INPUT(::ams::svc::KernelTraceState, kern_trace_state)) \
\ \
@@ -94,7 +97,8 @@
HANDLER(0x43, Result, ReplyAndReceive, OUTPUT(int32_t, out_index), INPTR(::ams::svc::Handle, handles), INPUT(int32_t, num_handles), INPUT(::ams::svc::Handle, reply_target), INPUT(int64_t, timeout_ns)) \ HANDLER(0x43, Result, ReplyAndReceive, OUTPUT(int32_t, out_index), INPTR(::ams::svc::Handle, handles), INPUT(int32_t, num_handles), INPUT(::ams::svc::Handle, reply_target), INPUT(int64_t, timeout_ns)) \
HANDLER(0x44, Result, ReplyAndReceiveWithUserBuffer, OUTPUT(int32_t, out_index), INPUT(::ams::svc::Address, message_buffer), INPUT(::ams::svc::Size, message_buffer_size), INPTR(::ams::svc::Handle, handles), INPUT(int32_t, num_handles), INPUT(::ams::svc::Handle, reply_target), INPUT(int64_t, timeout_ns)) \ HANDLER(0x44, Result, ReplyAndReceiveWithUserBuffer, OUTPUT(int32_t, out_index), INPUT(::ams::svc::Address, message_buffer), INPUT(::ams::svc::Size, message_buffer_size), INPTR(::ams::svc::Handle, handles), INPUT(int32_t, num_handles), INPUT(::ams::svc::Handle, reply_target), INPUT(int64_t, timeout_ns)) \
HANDLER(0x45, Result, CreateEvent, OUTPUT(::ams::svc::Handle, out_write_handle), OUTPUT(::ams::svc::Handle, out_read_handle)) \ HANDLER(0x45, Result, CreateEvent, OUTPUT(::ams::svc::Handle, out_write_handle), OUTPUT(::ams::svc::Handle, out_read_handle)) \
\ HANDLER(0x46, Result, Unknown46) \
HANDLER(0x47, Result, Unknown47) \
HANDLER(0x48, Result, MapPhysicalMemoryUnsafe, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::Size, size)) \ HANDLER(0x48, Result, MapPhysicalMemoryUnsafe, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::Size, size)) \
HANDLER(0x49, Result, UnmapPhysicalMemoryUnsafe, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::Size, size)) \ HANDLER(0x49, Result, UnmapPhysicalMemoryUnsafe, INPUT(::ams::svc::Address, address), INPUT(::ams::svc::Size, size)) \
HANDLER(0x4A, Result, SetUnsafeLimit, INPUT(::ams::svc::Size, limit)) \ HANDLER(0x4A, Result, SetUnsafeLimit, INPUT(::ams::svc::Size, limit)) \

View File

@@ -21,6 +21,9 @@
namespace ams::util { namespace ams::util {
#pragma GCC push_options
#pragma GCC optimize ("-O3")
/* Forward declare implementation class for Node. */ /* Forward declare implementation class for Node. */
namespace impl { namespace impl {
@@ -38,17 +41,17 @@ namespace ams::util {
public: public:
constexpr IntrusiveListNode() : prev(this), next(this) { /* ... */ } constexpr IntrusiveListNode() : prev(this), next(this) { /* ... */ }
constexpr bool IsLinked() const { constexpr ALWAYS_INLINE bool IsLinked() const {
return this->next != this; return this->next != this;
} }
private: private:
void LinkPrev(IntrusiveListNode *node) { ALWAYS_INLINE void LinkPrev(IntrusiveListNode *node) {
/* We can't link an already linked node. */ /* We can't link an already linked node. */
AMS_ASSERT(!node->IsLinked()); AMS_ASSERT(!node->IsLinked());
this->SplicePrev(node, node); this->SplicePrev(node, node);
} }
void SplicePrev(IntrusiveListNode *first, IntrusiveListNode *last) { ALWAYS_INLINE void SplicePrev(IntrusiveListNode *first, IntrusiveListNode *last) {
/* Splice a range into the list. */ /* Splice a range into the list. */
auto last_prev = last->prev; auto last_prev = last->prev;
first->prev = this->prev; first->prev = this->prev;
@@ -57,13 +60,13 @@ namespace ams::util {
this->prev = last_prev; this->prev = last_prev;
} }
void LinkNext(IntrusiveListNode *node) { ALWAYS_INLINE void LinkNext(IntrusiveListNode *node) {
/* We can't link an already linked node. */ /* We can't link an already linked node. */
AMS_ASSERT(!node->IsLinked()); AMS_ASSERT(!node->IsLinked());
return this->SpliceNext(node, node); return this->SpliceNext(node, node);
} }
void SpliceNext(IntrusiveListNode *first, IntrusiveListNode *last) { ALWAYS_INLINE void SpliceNext(IntrusiveListNode *first, IntrusiveListNode *last) {
/* Splice a range into the list. */ /* Splice a range into the list. */
auto last_prev = last->prev; auto last_prev = last->prev;
first->prev = this; first->prev = this;
@@ -72,11 +75,11 @@ namespace ams::util {
this->next = first; this->next = first;
} }
void Unlink() { ALWAYS_INLINE void Unlink() {
this->Unlink(this->next); this->Unlink(this->next);
} }
void Unlink(IntrusiveListNode *last) { ALWAYS_INLINE void Unlink(IntrusiveListNode *last) {
/* Unlink a node from a next node. */ /* Unlink a node from a next node. */
auto last_prev = last->prev; auto last_prev = last->prev;
this->prev->next = last; this->prev->next = last;
@@ -85,19 +88,19 @@ namespace ams::util {
this->prev = last_prev; this->prev = last_prev;
} }
IntrusiveListNode *GetPrev() { ALWAYS_INLINE IntrusiveListNode *GetPrev() {
return this->prev; return this->prev;
} }
const IntrusiveListNode *GetPrev() const { ALWAYS_INLINE const IntrusiveListNode *GetPrev() const {
return this->prev; return this->prev;
} }
IntrusiveListNode *GetNext() { ALWAYS_INLINE IntrusiveListNode *GetNext() {
return this->next; return this->next;
} }
const IntrusiveListNode *GetNext() const { ALWAYS_INLINE const IntrusiveListNode *GetNext() const {
return this->next; return this->next;
} }
}; };
@@ -136,149 +139,149 @@ namespace ams::util {
private: private:
pointer node; pointer node;
public: public:
explicit Iterator(pointer n) : node(n) { /* ... */ } ALWAYS_INLINE explicit Iterator(pointer n) : node(n) { /* ... */ }
bool operator==(const Iterator &rhs) const { ALWAYS_INLINE bool operator==(const Iterator &rhs) const {
return this->node == rhs.node; return this->node == rhs.node;
} }
bool operator!=(const Iterator &rhs) const { ALWAYS_INLINE bool operator!=(const Iterator &rhs) const {
return !(*this == rhs); return !(*this == rhs);
} }
pointer operator->() const { ALWAYS_INLINE pointer operator->() const {
return this->node; return this->node;
} }
reference operator*() const { ALWAYS_INLINE reference operator*() const {
return *this->node; return *this->node;
} }
Iterator &operator++() { ALWAYS_INLINE Iterator &operator++() {
this->node = this->node->next; this->node = this->node->next;
return *this; return *this;
} }
Iterator &operator--() { ALWAYS_INLINE Iterator &operator--() {
this->node = this->node->prev; this->node = this->node->prev;
return *this; return *this;
} }
Iterator operator++(int) { ALWAYS_INLINE Iterator operator++(int) {
const Iterator it{*this}; const Iterator it{*this};
++(*this); ++(*this);
return it; return it;
} }
Iterator operator--(int) { ALWAYS_INLINE Iterator operator--(int) {
const Iterator it{*this}; const Iterator it{*this};
--(*this); --(*this);
return it; return it;
} }
operator Iterator<true>() const { ALWAYS_INLINE operator Iterator<true>() const {
return Iterator<true>(this->node); return Iterator<true>(this->node);
} }
Iterator<false> GetNonConstIterator() const { ALWAYS_INLINE Iterator<false> GetNonConstIterator() const {
return Iterator<false>(const_cast<IntrusiveListImpl::pointer>(this->node)); return Iterator<false>(const_cast<IntrusiveListImpl::pointer>(this->node));
} }
}; };
public: public:
constexpr IntrusiveListImpl() : root_node() { /* ... */ } constexpr ALWAYS_INLINE IntrusiveListImpl() : root_node() { /* ... */ }
/* Iterator accessors. */ /* Iterator accessors. */
iterator begin() { ALWAYS_INLINE iterator begin() {
return iterator(this->root_node.GetNext()); return iterator(this->root_node.GetNext());
} }
const_iterator begin() const { ALWAYS_INLINE const_iterator begin() const {
return const_iterator(this->root_node.GetNext()); return const_iterator(this->root_node.GetNext());
} }
iterator end() { ALWAYS_INLINE iterator end() {
return iterator(&this->root_node); return iterator(&this->root_node);
} }
const_iterator end() const { ALWAYS_INLINE const_iterator end() const {
return const_iterator(&this->root_node); return const_iterator(&this->root_node);
} }
iterator iterator_to(reference v) { ALWAYS_INLINE iterator iterator_to(reference v) {
/* Only allow iterator_to for values in lists. */ /* Only allow iterator_to for values in lists. */
AMS_ASSERT(v.IsLinked()); AMS_ASSERT(v.IsLinked());
return iterator(&v); return iterator(&v);
} }
const_iterator iterator_to(const_reference v) const { ALWAYS_INLINE const_iterator iterator_to(const_reference v) const {
/* Only allow iterator_to for values in lists. */ /* Only allow iterator_to for values in lists. */
AMS_ASSERT(v.IsLinked()); AMS_ASSERT(v.IsLinked());
return const_iterator(&v); return const_iterator(&v);
} }
/* Content management. */ /* Content management. */
bool empty() const { ALWAYS_INLINE bool empty() const {
return !this->root_node.IsLinked(); return !this->root_node.IsLinked();
} }
size_type size() const { ALWAYS_INLINE size_type size() const {
return static_cast<size_type>(std::distance(this->begin(), this->end())); return static_cast<size_type>(std::distance(this->begin(), this->end()));
} }
reference back() { ALWAYS_INLINE reference back() {
return *this->root_node.GetPrev(); return *this->root_node.GetPrev();
} }
const_reference back() const { ALWAYS_INLINE const_reference back() const {
return *this->root_node.GetPrev(); return *this->root_node.GetPrev();
} }
reference front() { ALWAYS_INLINE reference front() {
return *this->root_node.GetNext(); return *this->root_node.GetNext();
} }
const_reference front() const { ALWAYS_INLINE const_reference front() const {
return *this->root_node.GetNext(); return *this->root_node.GetNext();
} }
void push_back(reference node) { ALWAYS_INLINE void push_back(reference node) {
this->root_node.LinkPrev(&node); this->root_node.LinkPrev(&node);
} }
void push_front(reference node) { ALWAYS_INLINE void push_front(reference node) {
this->root_node.LinkNext(&node); this->root_node.LinkNext(&node);
} }
void pop_back() { ALWAYS_INLINE void pop_back() {
this->root_node.GetPrev()->Unlink(); this->root_node.GetPrev()->Unlink();
} }
void pop_front() { ALWAYS_INLINE void pop_front() {
this->root_node.GetNext()->Unlink(); this->root_node.GetNext()->Unlink();
} }
iterator insert(const_iterator pos, reference node) { ALWAYS_INLINE iterator insert(const_iterator pos, reference node) {
pos.GetNonConstIterator()->LinkPrev(&node); pos.GetNonConstIterator()->LinkPrev(&node);
return iterator(&node); return iterator(&node);
} }
void splice(const_iterator pos, IntrusiveListImpl &o) { ALWAYS_INLINE void splice(const_iterator pos, IntrusiveListImpl &o) {
splice_impl(pos, o.begin(), o.end()); splice_impl(pos, o.begin(), o.end());
} }
void splice(const_iterator pos, IntrusiveListImpl &o, const_iterator first) { ALWAYS_INLINE void splice(const_iterator pos, IntrusiveListImpl &o, const_iterator first) {
AMS_UNUSED(o); AMS_UNUSED(o);
const_iterator last(first); const_iterator last(first);
std::advance(last, 1); std::advance(last, 1);
splice_impl(pos, first, last); splice_impl(pos, first, last);
} }
void splice(const_iterator pos, IntrusiveListImpl &o, const_iterator first, const_iterator last) { ALWAYS_INLINE void splice(const_iterator pos, IntrusiveListImpl &o, const_iterator first, const_iterator last) {
AMS_UNUSED(o); AMS_UNUSED(o);
splice_impl(pos, first, last); splice_impl(pos, first, last);
} }
iterator erase(const_iterator pos) { ALWAYS_INLINE iterator erase(const_iterator pos) {
if (pos == this->end()) { if (pos == this->end()) {
return this->end(); return this->end();
} }
@@ -287,13 +290,13 @@ namespace ams::util {
return it; return it;
} }
void clear() { ALWAYS_INLINE void clear() {
while (!this->empty()) { while (!this->empty()) {
this->pop_front(); this->pop_front();
} }
} }
private: private:
void splice_impl(const_iterator _pos, const_iterator _first, const_iterator _last) { ALWAYS_INLINE void splice_impl(const_iterator _pos, const_iterator _first, const_iterator _last) {
if (_first == _last) { if (_first == _last) {
return; return;
} }
@@ -344,198 +347,198 @@ namespace ams::util {
private: private:
ImplIterator iterator; ImplIterator iterator;
private: private:
explicit Iterator(ImplIterator it) : iterator(it) { /* ... */ } explicit ALWAYS_INLINE Iterator(ImplIterator it) : iterator(it) { /* ... */ }
ImplIterator GetImplIterator() const { ALWAYS_INLINE ImplIterator GetImplIterator() const {
return this->iterator; return this->iterator;
} }
public: public:
bool operator==(const Iterator &rhs) const { ALWAYS_INLINE bool operator==(const Iterator &rhs) const {
return this->iterator == rhs.iterator; return this->iterator == rhs.iterator;
} }
bool operator!=(const Iterator &rhs) const { ALWAYS_INLINE bool operator!=(const Iterator &rhs) const {
return !(*this == rhs); return !(*this == rhs);
} }
pointer operator->() const { ALWAYS_INLINE pointer operator->() const {
return &Traits::GetParent(*this->iterator); return &Traits::GetParent(*this->iterator);
} }
reference operator*() const { ALWAYS_INLINE reference operator*() const {
return Traits::GetParent(*this->iterator); return Traits::GetParent(*this->iterator);
} }
Iterator &operator++() { ALWAYS_INLINE Iterator &operator++() {
++this->iterator; ++this->iterator;
return *this; return *this;
} }
Iterator &operator--() { ALWAYS_INLINE Iterator &operator--() {
--this->iterator; --this->iterator;
return *this; return *this;
} }
Iterator operator++(int) { ALWAYS_INLINE Iterator operator++(int) {
const Iterator it{*this}; const Iterator it{*this};
++this->iterator; ++this->iterator;
return it; return it;
} }
Iterator operator--(int) { ALWAYS_INLINE Iterator operator--(int) {
const Iterator it{*this}; const Iterator it{*this};
--this->iterator; --this->iterator;
return it; return it;
} }
operator Iterator<true>() const { ALWAYS_INLINE operator Iterator<true>() const {
return Iterator<true>(this->iterator); return Iterator<true>(this->iterator);
} }
}; };
private: private:
static constexpr IntrusiveListNode &GetNode(reference ref) { static constexpr ALWAYS_INLINE IntrusiveListNode &GetNode(reference ref) {
return Traits::GetNode(ref); return Traits::GetNode(ref);
} }
static constexpr IntrusiveListNode const &GetNode(const_reference ref) { static constexpr ALWAYS_INLINE IntrusiveListNode const &GetNode(const_reference ref) {
return Traits::GetNode(ref); return Traits::GetNode(ref);
} }
static constexpr reference GetParent(IntrusiveListNode &node) { static constexpr ALWAYS_INLINE reference GetParent(IntrusiveListNode &node) {
return Traits::GetParent(node); return Traits::GetParent(node);
} }
static constexpr const_reference GetParent(IntrusiveListNode const &node) { static constexpr ALWAYS_INLINE const_reference GetParent(IntrusiveListNode const &node) {
return Traits::GetParent(node); return Traits::GetParent(node);
} }
public: public:
constexpr IntrusiveList() : impl() { /* ... */ } constexpr ALWAYS_INLINE IntrusiveList() : impl() { /* ... */ }
/* Iterator accessors. */ /* Iterator accessors. */
iterator begin() { ALWAYS_INLINE iterator begin() {
return iterator(this->impl.begin()); return iterator(this->impl.begin());
} }
const_iterator begin() const { ALWAYS_INLINE const_iterator begin() const {
return const_iterator(this->impl.begin()); return const_iterator(this->impl.begin());
} }
iterator end() { ALWAYS_INLINE iterator end() {
return iterator(this->impl.end()); return iterator(this->impl.end());
} }
const_iterator end() const { ALWAYS_INLINE const_iterator end() const {
return const_iterator(this->impl.end()); return const_iterator(this->impl.end());
} }
const_iterator cbegin() const { ALWAYS_INLINE const_iterator cbegin() const {
return this->begin(); return this->begin();
} }
const_iterator cend() const { ALWAYS_INLINE const_iterator cend() const {
return this->end(); return this->end();
} }
reverse_iterator rbegin() { ALWAYS_INLINE reverse_iterator rbegin() {
return reverse_iterator(this->end()); return reverse_iterator(this->end());
} }
const_reverse_iterator rbegin() const { ALWAYS_INLINE const_reverse_iterator rbegin() const {
return const_reverse_iterator(this->end()); return const_reverse_iterator(this->end());
} }
reverse_iterator rend() { ALWAYS_INLINE reverse_iterator rend() {
return reverse_iterator(this->begin()); return reverse_iterator(this->begin());
} }
const_reverse_iterator rend() const { ALWAYS_INLINE const_reverse_iterator rend() const {
return const_reverse_iterator(this->begin()); return const_reverse_iterator(this->begin());
} }
const_reverse_iterator crbegin() const { ALWAYS_INLINE const_reverse_iterator crbegin() const {
return this->rbegin(); return this->rbegin();
} }
const_reverse_iterator crend() const { ALWAYS_INLINE const_reverse_iterator crend() const {
return this->rend(); return this->rend();
} }
iterator iterator_to(reference v) { ALWAYS_INLINE iterator iterator_to(reference v) {
return iterator(this->impl.iterator_to(GetNode(v))); return iterator(this->impl.iterator_to(GetNode(v)));
} }
const_iterator iterator_to(const_reference v) const { ALWAYS_INLINE const_iterator iterator_to(const_reference v) const {
return const_iterator(this->impl.iterator_to(GetNode(v))); return const_iterator(this->impl.iterator_to(GetNode(v)));
} }
/* Content management. */ /* Content management. */
bool empty() const { ALWAYS_INLINE bool empty() const {
return this->impl.empty(); return this->impl.empty();
} }
size_type size() const { ALWAYS_INLINE size_type size() const {
return this->impl.size(); return this->impl.size();
} }
reference back() { ALWAYS_INLINE reference back() {
AMS_ASSERT(!this->impl.empty()); AMS_ASSERT(!this->impl.empty());
return GetParent(this->impl.back()); return GetParent(this->impl.back());
} }
const_reference back() const { ALWAYS_INLINE const_reference back() const {
AMS_ASSERT(!this->impl.empty()); AMS_ASSERT(!this->impl.empty());
return GetParent(this->impl.back()); return GetParent(this->impl.back());
} }
reference front() { ALWAYS_INLINE reference front() {
AMS_ASSERT(!this->impl.empty()); AMS_ASSERT(!this->impl.empty());
return GetParent(this->impl.front()); return GetParent(this->impl.front());
} }
const_reference front() const { ALWAYS_INLINE const_reference front() const {
AMS_ASSERT(!this->impl.empty()); AMS_ASSERT(!this->impl.empty());
return GetParent(this->impl.front()); return GetParent(this->impl.front());
} }
void push_back(reference ref) { ALWAYS_INLINE void push_back(reference ref) {
this->impl.push_back(GetNode(ref)); this->impl.push_back(GetNode(ref));
} }
void push_front(reference ref) { ALWAYS_INLINE void push_front(reference ref) {
this->impl.push_front(GetNode(ref)); this->impl.push_front(GetNode(ref));
} }
void pop_back() { ALWAYS_INLINE void pop_back() {
AMS_ASSERT(!this->impl.empty()); AMS_ASSERT(!this->impl.empty());
this->impl.pop_back(); this->impl.pop_back();
} }
void pop_front() { ALWAYS_INLINE void pop_front() {
AMS_ASSERT(!this->impl.empty()); AMS_ASSERT(!this->impl.empty());
this->impl.pop_front(); this->impl.pop_front();
} }
iterator insert(const_iterator pos, reference ref) { ALWAYS_INLINE iterator insert(const_iterator pos, reference ref) {
return iterator(this->impl.insert(pos.GetImplIterator(), GetNode(ref))); return iterator(this->impl.insert(pos.GetImplIterator(), GetNode(ref)));
} }
void splice(const_iterator pos, IntrusiveList &o) { ALWAYS_INLINE void splice(const_iterator pos, IntrusiveList &o) {
this->impl.splice(pos.GetImplIterator(), o.impl); this->impl.splice(pos.GetImplIterator(), o.impl);
} }
void splice(const_iterator pos, IntrusiveList &o, const_iterator first) { ALWAYS_INLINE void splice(const_iterator pos, IntrusiveList &o, const_iterator first) {
this->impl.splice(pos.GetImplIterator(), o.impl, first.GetImplIterator()); this->impl.splice(pos.GetImplIterator(), o.impl, first.GetImplIterator());
} }
void splice(const_iterator pos, IntrusiveList &o, const_iterator first, const_iterator last) { ALWAYS_INLINE void splice(const_iterator pos, IntrusiveList &o, const_iterator first, const_iterator last) {
this->impl.splice(pos.GetImplIterator(), o.impl, first.GetImplIterator(), last.GetImplIterator()); this->impl.splice(pos.GetImplIterator(), o.impl, first.GetImplIterator(), last.GetImplIterator());
} }
iterator erase(const_iterator pos) { ALWAYS_INLINE iterator erase(const_iterator pos) {
return iterator(this->impl.erase(pos.GetImplIterator())); return iterator(this->impl.erase(pos.GetImplIterator()));
} }
void clear() { ALWAYS_INLINE void clear() {
this->impl.clear(); this->impl.clear();
} }
}; };
@@ -550,19 +553,19 @@ namespace ams::util {
private: private:
friend class IntrusiveList<Derived, IntrusiveListMemberTraits>; friend class IntrusiveList<Derived, IntrusiveListMemberTraits>;
static constexpr IntrusiveListNode &GetNode(Derived &parent) { static constexpr ALWAYS_INLINE IntrusiveListNode &GetNode(Derived &parent) {
return parent.*Member; return parent.*Member;
} }
static constexpr IntrusiveListNode const &GetNode(Derived const &parent) { static constexpr ALWAYS_INLINE IntrusiveListNode const &GetNode(Derived const &parent) {
return parent.*Member; return parent.*Member;
} }
static constexpr Derived &GetParent(IntrusiveListNode &node) { static constexpr ALWAYS_INLINE Derived &GetParent(IntrusiveListNode &node) {
return util::GetParentReference<Member, Derived>(&node); return util::GetParentReference<Member, Derived>(&node);
} }
static constexpr Derived const &GetParent(IntrusiveListNode const &node) { static constexpr ALWAYS_INLINE Derived const &GetParent(IntrusiveListNode const &node) {
return util::GetParentReference<Member, Derived>(&node); return util::GetParentReference<Member, Derived>(&node);
} }
private: private:
@@ -585,19 +588,19 @@ namespace ams::util {
private: private:
friend class IntrusiveList<Derived, IntrusiveListMemberTraitsDeferredAssert>; friend class IntrusiveList<Derived, IntrusiveListMemberTraitsDeferredAssert>;
static constexpr IntrusiveListNode &GetNode(Derived &parent) { static constexpr ALWAYS_INLINE IntrusiveListNode &GetNode(Derived &parent) {
return parent.*Member; return parent.*Member;
} }
static constexpr IntrusiveListNode const &GetNode(Derived const &parent) { static constexpr ALWAYS_INLINE IntrusiveListNode const &GetNode(Derived const &parent) {
return parent.*Member; return parent.*Member;
} }
static constexpr Derived &GetParent(IntrusiveListNode &node) { static constexpr ALWAYS_INLINE Derived &GetParent(IntrusiveListNode &node) {
return util::GetParentReference<Member, Derived>(&node); return util::GetParentReference<Member, Derived>(&node);
} }
static constexpr Derived const &GetParent(IntrusiveListNode const &node) { static constexpr ALWAYS_INLINE Derived const &GetParent(IntrusiveListNode const &node) {
return util::GetParentReference<Member, Derived>(&node); return util::GetParentReference<Member, Derived>(&node);
} }
}; };
@@ -612,21 +615,23 @@ namespace ams::util {
private: private:
friend class IntrusiveList<Derived, IntrusiveListBaseTraits>; friend class IntrusiveList<Derived, IntrusiveListBaseTraits>;
static constexpr IntrusiveListNode &GetNode(Derived &parent) { static constexpr ALWAYS_INLINE IntrusiveListNode &GetNode(Derived &parent) {
return static_cast<IntrusiveListNode &>(parent); return static_cast<IntrusiveListNode &>(parent);
} }
static constexpr IntrusiveListNode const &GetNode(Derived const &parent) { static constexpr ALWAYS_INLINE IntrusiveListNode const &GetNode(Derived const &parent) {
return static_cast<const IntrusiveListNode &>(parent); return static_cast<const IntrusiveListNode &>(parent);
} }
static constexpr Derived &GetParent(IntrusiveListNode &node) { static constexpr ALWAYS_INLINE Derived &GetParent(IntrusiveListNode &node) {
return static_cast<Derived &>(node); return static_cast<Derived &>(node);
} }
static constexpr Derived const &GetParent(IntrusiveListNode const &node) { static constexpr ALWAYS_INLINE Derived const &GetParent(IntrusiveListNode const &node) {
return static_cast<const Derived &>(node); return static_cast<const Derived &>(node);
} }
}; };
#pragma GCC pop_options
} }

View File

@@ -22,6 +22,9 @@
namespace ams::util { namespace ams::util {
#pragma GCC push_options
#pragma GCC optimize ("-O3")
namespace impl { namespace impl {
class IntrusiveRedBlackTreeImpl; class IntrusiveRedBlackTreeImpl;
@@ -82,47 +85,47 @@ namespace ams::util {
private: private:
pointer node; pointer node;
public: public:
explicit Iterator(pointer n) : node(n) { /* ... */ } explicit ALWAYS_INLINE Iterator(pointer n) : node(n) { /* ... */ }
bool operator==(const Iterator &rhs) const { ALWAYS_INLINE bool operator==(const Iterator &rhs) const {
return this->node == rhs.node; return this->node == rhs.node;
} }
bool operator!=(const Iterator &rhs) const { ALWAYS_INLINE bool operator!=(const Iterator &rhs) const {
return !(*this == rhs); return !(*this == rhs);
} }
pointer operator->() const { ALWAYS_INLINE pointer operator->() const {
return this->node; return this->node;
} }
reference operator*() const { ALWAYS_INLINE reference operator*() const {
return *this->node; return *this->node;
} }
Iterator &operator++() { ALWAYS_INLINE Iterator &operator++() {
this->node = GetNext(this->node); this->node = GetNext(this->node);
return *this; return *this;
} }
Iterator &operator--() { ALWAYS_INLINE Iterator &operator--() {
this->node = GetPrev(this->node); this->node = GetPrev(this->node);
return *this; return *this;
} }
Iterator operator++(int) { ALWAYS_INLINE Iterator operator++(int) {
const Iterator it{*this}; const Iterator it{*this};
++(*this); ++(*this);
return it; return it;
} }
Iterator operator--(int) { ALWAYS_INLINE Iterator operator--(int) {
const Iterator it{*this}; const Iterator it{*this};
--(*this); --(*this);
return it; return it;
} }
operator Iterator<true>() const { ALWAYS_INLINE operator Iterator<true>() const {
return Iterator<true>(this->node); return Iterator<true>(this->node);
} }
}; };
@@ -135,27 +138,27 @@ namespace ams::util {
RB_INIT(&this->root); RB_INIT(&this->root);
} }
bool EmptyImpl() const { ALWAYS_INLINE bool EmptyImpl() const {
return RB_EMPTY(&this->root); return RB_EMPTY(&this->root);
} }
IntrusiveRedBlackTreeNode *GetMinImpl() const { ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetMinImpl() const {
return RB_MIN(IntrusiveRedBlackTreeRoot, const_cast<IntrusiveRedBlackTreeRoot *>(&this->root)); return RB_MIN(IntrusiveRedBlackTreeRoot, const_cast<IntrusiveRedBlackTreeRoot *>(&this->root));
} }
IntrusiveRedBlackTreeNode *GetMaxImpl() const { ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetMaxImpl() const {
return RB_MAX(IntrusiveRedBlackTreeRoot, const_cast<IntrusiveRedBlackTreeRoot *>(&this->root)); return RB_MAX(IntrusiveRedBlackTreeRoot, const_cast<IntrusiveRedBlackTreeRoot *>(&this->root));
} }
IntrusiveRedBlackTreeNode *RemoveImpl(IntrusiveRedBlackTreeNode *node) { ALWAYS_INLINE IntrusiveRedBlackTreeNode *RemoveImpl(IntrusiveRedBlackTreeNode *node) {
return RB_REMOVE(IntrusiveRedBlackTreeRoot, &this->root, node); return RB_REMOVE(IntrusiveRedBlackTreeRoot, &this->root, node);
} }
public: public:
static IntrusiveRedBlackTreeNode *GetNext(IntrusiveRedBlackTreeNode *node) { static ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetNext(IntrusiveRedBlackTreeNode *node) {
return RB_NEXT(IntrusiveRedBlackTreeRoot, nullptr, node); return RB_NEXT(IntrusiveRedBlackTreeRoot, nullptr, node);
} }
static IntrusiveRedBlackTreeNode *GetPrev(IntrusiveRedBlackTreeNode *node) { static ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetPrev(IntrusiveRedBlackTreeNode *node) {
return RB_PREV(IntrusiveRedBlackTreeRoot, nullptr, node); return RB_PREV(IntrusiveRedBlackTreeRoot, nullptr, node);
} }
@@ -167,65 +170,65 @@ namespace ams::util {
return static_cast<const IntrusiveRedBlackTreeNode *>(GetPrev(const_cast<IntrusiveRedBlackTreeNode *>(node))); return static_cast<const IntrusiveRedBlackTreeNode *>(GetPrev(const_cast<IntrusiveRedBlackTreeNode *>(node)));
} }
public: public:
constexpr IntrusiveRedBlackTreeImpl() : root() { ALWAYS_INLINE constexpr IntrusiveRedBlackTreeImpl() : root() {
this->InitializeImpl(); this->InitializeImpl();
} }
/* Iterator accessors. */ /* Iterator accessors. */
iterator begin() { ALWAYS_INLINE iterator begin() {
return iterator(this->GetMinImpl()); return iterator(this->GetMinImpl());
} }
const_iterator begin() const { ALWAYS_INLINE const_iterator begin() const {
return const_iterator(this->GetMinImpl()); return const_iterator(this->GetMinImpl());
} }
iterator end() { ALWAYS_INLINE iterator end() {
return iterator(static_cast<IntrusiveRedBlackTreeNode *>(nullptr)); return iterator(static_cast<IntrusiveRedBlackTreeNode *>(nullptr));
} }
const_iterator end() const { ALWAYS_INLINE const_iterator end() const {
return const_iterator(static_cast<const IntrusiveRedBlackTreeNode *>(nullptr)); return const_iterator(static_cast<const IntrusiveRedBlackTreeNode *>(nullptr));
} }
const_iterator cbegin() const { ALWAYS_INLINE const_iterator cbegin() const {
return this->begin(); return this->begin();
} }
const_iterator cend() const { ALWAYS_INLINE const_iterator cend() const {
return this->end(); return this->end();
} }
iterator iterator_to(reference ref) { ALWAYS_INLINE iterator iterator_to(reference ref) {
return iterator(&ref); return iterator(&ref);
} }
const_iterator iterator_to(const_reference ref) const { ALWAYS_INLINE const_iterator iterator_to(const_reference ref) const {
return const_iterator(&ref); return const_iterator(&ref);
} }
/* Content management. */ /* Content management. */
bool empty() const { ALWAYS_INLINE bool empty() const {
return this->EmptyImpl(); return this->EmptyImpl();
} }
reference back() { ALWAYS_INLINE reference back() {
return *this->GetMaxImpl(); return *this->GetMaxImpl();
} }
const_reference back() const { ALWAYS_INLINE const_reference back() const {
return *this->GetMaxImpl(); return *this->GetMaxImpl();
} }
reference front() { ALWAYS_INLINE reference front() {
return *this->GetMinImpl(); return *this->GetMinImpl();
} }
const_reference front() const { ALWAYS_INLINE const_reference front() const {
return *this->GetMinImpl(); return *this->GetMinImpl();
} }
iterator erase(iterator it) { ALWAYS_INLINE iterator erase(iterator it) {
auto cur = std::addressof(*it); auto cur = std::addressof(*it);
auto next = GetNext(cur); auto next = GetNext(cur);
this->RemoveImpl(cur); this->RemoveImpl(cur);
@@ -235,6 +238,27 @@ namespace ams::util {
} }
template<typename T>
concept HasLightCompareType = requires {
{ std::is_same<typename T::LightCompareType, void>::value } -> std::convertible_to<bool>;
};
namespace impl {
template<typename T, typename Default>
consteval auto *GetLightCompareType() {
if constexpr (HasLightCompareType<T>) {
return static_cast<typename T::LightCompareType *>(nullptr);
} else {
return static_cast<Default *>(nullptr);
}
}
}
template<typename T, typename Default>
using LightCompareType = typename std::remove_pointer<decltype(impl::GetLightCompareType<T, Default>())>::type;
template<class T, class Traits, class Comparator> template<class T, class Traits, class Comparator>
class IntrusiveRedBlackTree { class IntrusiveRedBlackTree {
NON_COPYABLE(IntrusiveRedBlackTree); NON_COPYABLE(IntrusiveRedBlackTree);
@@ -258,6 +282,10 @@ namespace ams::util {
using iterator = Iterator<false>; using iterator = Iterator<false>;
using const_iterator = Iterator<true>; using const_iterator = Iterator<true>;
using light_value_type = LightCompareType<Comparator, value_type>;
using const_light_pointer = const light_value_type *;
using const_light_reference = const light_value_type &;
template<bool Const> template<bool Const>
class Iterator { class Iterator {
public: public:
@@ -273,150 +301,170 @@ namespace ams::util {
private: private:
ImplIterator iterator; ImplIterator iterator;
private: private:
explicit Iterator(ImplIterator it) : iterator(it) { /* ... */ } explicit ALWAYS_INLINE Iterator(ImplIterator it) : iterator(it) { /* ... */ }
explicit Iterator(ImplIterator::pointer p) : iterator(p) { /* ... */ } explicit ALWAYS_INLINE Iterator(ImplIterator::pointer p) : iterator(p) { /* ... */ }
ImplIterator GetImplIterator() const { ALWAYS_INLINE ImplIterator GetImplIterator() const {
return this->iterator; return this->iterator;
} }
public: public:
bool operator==(const Iterator &rhs) const { ALWAYS_INLINE bool operator==(const Iterator &rhs) const {
return this->iterator == rhs.iterator; return this->iterator == rhs.iterator;
} }
bool operator!=(const Iterator &rhs) const { ALWAYS_INLINE bool operator!=(const Iterator &rhs) const {
return !(*this == rhs); return !(*this == rhs);
} }
pointer operator->() const { ALWAYS_INLINE pointer operator->() const {
return Traits::GetParent(std::addressof(*this->iterator)); return Traits::GetParent(std::addressof(*this->iterator));
} }
reference operator*() const { ALWAYS_INLINE reference operator*() const {
return *Traits::GetParent(std::addressof(*this->iterator)); return *Traits::GetParent(std::addressof(*this->iterator));
} }
Iterator &operator++() { ALWAYS_INLINE Iterator &operator++() {
++this->iterator; ++this->iterator;
return *this; return *this;
} }
Iterator &operator--() { ALWAYS_INLINE Iterator &operator--() {
--this->iterator; --this->iterator;
return *this; return *this;
} }
Iterator operator++(int) { ALWAYS_INLINE Iterator operator++(int) {
const Iterator it{*this}; const Iterator it{*this};
++this->iterator; ++this->iterator;
return it; return it;
} }
Iterator operator--(int) { ALWAYS_INLINE Iterator operator--(int) {
const Iterator it{*this}; const Iterator it{*this};
--this->iterator; --this->iterator;
return it; return it;
} }
operator Iterator<true>() const { ALWAYS_INLINE operator Iterator<true>() const {
return Iterator<true>(this->iterator); return Iterator<true>(this->iterator);
} }
}; };
private: private:
/* Generate static implementations for comparison operations for IntrusiveRedBlackTreeRoot. */ /* Generate static implementations for comparison operations for IntrusiveRedBlackTreeRoot. */
RB_GENERATE_WITH_COMPARE_STATIC(IntrusiveRedBlackTreeRootWithCompare, IntrusiveRedBlackTreeNode, entry, CompareImpl); RB_GENERATE_WITH_COMPARE_STATIC(IntrusiveRedBlackTreeRootWithCompare, IntrusiveRedBlackTreeNode, entry, CompareImpl, LightCompareImpl);
private: private:
static int CompareImpl(const IntrusiveRedBlackTreeNode *lhs, const IntrusiveRedBlackTreeNode *rhs) { static int CompareImpl(const IntrusiveRedBlackTreeNode *lhs, const IntrusiveRedBlackTreeNode *rhs) {
return Comparator::Compare(*Traits::GetParent(lhs), *Traits::GetParent(rhs)); return Comparator::Compare(*Traits::GetParent(lhs), *Traits::GetParent(rhs));
} }
static int LightCompareImpl(const void *elm, const IntrusiveRedBlackTreeNode *rhs) {
return Comparator::Compare(*static_cast<const_light_pointer>(elm), *Traits::GetParent(rhs));
}
/* Define accessors using RB_* functions. */ /* Define accessors using RB_* functions. */
IntrusiveRedBlackTreeNode *InsertImpl(IntrusiveRedBlackTreeNode *node) { ALWAYS_INLINE IntrusiveRedBlackTreeNode *InsertImpl(IntrusiveRedBlackTreeNode *node) {
return RB_INSERT(IntrusiveRedBlackTreeRootWithCompare, static_cast<IntrusiveRedBlackTreeRootWithCompare *>(&this->impl.root), node); return RB_INSERT(IntrusiveRedBlackTreeRootWithCompare, static_cast<IntrusiveRedBlackTreeRootWithCompare *>(&this->impl.root), node);
} }
IntrusiveRedBlackTreeNode *FindImpl(IntrusiveRedBlackTreeNode const *node) const { ALWAYS_INLINE IntrusiveRedBlackTreeNode *FindImpl(IntrusiveRedBlackTreeNode const *node) const {
return RB_FIND(IntrusiveRedBlackTreeRootWithCompare, const_cast<IntrusiveRedBlackTreeRootWithCompare *>(static_cast<const IntrusiveRedBlackTreeRootWithCompare *>(&this->impl.root)), const_cast<IntrusiveRedBlackTreeNode *>(node)); return RB_FIND(IntrusiveRedBlackTreeRootWithCompare, const_cast<IntrusiveRedBlackTreeRootWithCompare *>(static_cast<const IntrusiveRedBlackTreeRootWithCompare *>(&this->impl.root)), const_cast<IntrusiveRedBlackTreeNode *>(node));
} }
IntrusiveRedBlackTreeNode *NFindImpl(IntrusiveRedBlackTreeNode const *node) const { ALWAYS_INLINE IntrusiveRedBlackTreeNode *NFindImpl(IntrusiveRedBlackTreeNode const *node) const {
return RB_NFIND(IntrusiveRedBlackTreeRootWithCompare, const_cast<IntrusiveRedBlackTreeRootWithCompare *>(static_cast<const IntrusiveRedBlackTreeRootWithCompare *>(&this->impl.root)), const_cast<IntrusiveRedBlackTreeNode *>(node)); return RB_NFIND(IntrusiveRedBlackTreeRootWithCompare, const_cast<IntrusiveRedBlackTreeRootWithCompare *>(static_cast<const IntrusiveRedBlackTreeRootWithCompare *>(&this->impl.root)), const_cast<IntrusiveRedBlackTreeNode *>(node));
} }
ALWAYS_INLINE IntrusiveRedBlackTreeNode *FindLightImpl(const_light_pointer lelm) const {
return RB_FIND_LIGHT(IntrusiveRedBlackTreeRootWithCompare, const_cast<IntrusiveRedBlackTreeRootWithCompare *>(static_cast<const IntrusiveRedBlackTreeRootWithCompare *>(&this->impl.root)), static_cast<const void *>(lelm));
}
ALWAYS_INLINE IntrusiveRedBlackTreeNode *NFindLightImpl(const_light_pointer lelm) const {
return RB_NFIND_LIGHT(IntrusiveRedBlackTreeRootWithCompare, const_cast<IntrusiveRedBlackTreeRootWithCompare *>(static_cast<const IntrusiveRedBlackTreeRootWithCompare *>(&this->impl.root)), static_cast<const void *>(lelm));
}
public: public:
constexpr ALWAYS_INLINE IntrusiveRedBlackTree() : impl() { /* ... */ } constexpr ALWAYS_INLINE IntrusiveRedBlackTree() : impl() { /* ... */ }
/* Iterator accessors. */ /* Iterator accessors. */
iterator begin() { ALWAYS_INLINE iterator begin() {
return iterator(this->impl.begin()); return iterator(this->impl.begin());
} }
const_iterator begin() const { ALWAYS_INLINE const_iterator begin() const {
return const_iterator(this->impl.begin()); return const_iterator(this->impl.begin());
} }
iterator end() { ALWAYS_INLINE iterator end() {
return iterator(this->impl.end()); return iterator(this->impl.end());
} }
const_iterator end() const { ALWAYS_INLINE const_iterator end() const {
return const_iterator(this->impl.end()); return const_iterator(this->impl.end());
} }
const_iterator cbegin() const { ALWAYS_INLINE const_iterator cbegin() const {
return this->begin(); return this->begin();
} }
const_iterator cend() const { ALWAYS_INLINE const_iterator cend() const {
return this->end(); return this->end();
} }
iterator iterator_to(reference ref) { ALWAYS_INLINE iterator iterator_to(reference ref) {
return iterator(this->impl.iterator_to(*Traits::GetNode(std::addressof(ref)))); return iterator(this->impl.iterator_to(*Traits::GetNode(std::addressof(ref))));
} }
const_iterator iterator_to(const_reference ref) const { ALWAYS_INLINE const_iterator iterator_to(const_reference ref) const {
return const_iterator(this->impl.iterator_to(*Traits::GetNode(std::addressof(ref)))); return const_iterator(this->impl.iterator_to(*Traits::GetNode(std::addressof(ref))));
} }
/* Content management. */ /* Content management. */
bool empty() const { ALWAYS_INLINE bool empty() const {
return this->impl.empty(); return this->impl.empty();
} }
reference back() { ALWAYS_INLINE reference back() {
return *Traits::GetParent(std::addressof(this->impl.back())); return *Traits::GetParent(std::addressof(this->impl.back()));
} }
const_reference back() const { ALWAYS_INLINE const_reference back() const {
return *Traits::GetParent(std::addressof(this->impl.back())); return *Traits::GetParent(std::addressof(this->impl.back()));
} }
reference front() { ALWAYS_INLINE reference front() {
return *Traits::GetParent(std::addressof(this->impl.front())); return *Traits::GetParent(std::addressof(this->impl.front()));
} }
const_reference front() const { ALWAYS_INLINE const_reference front() const {
return *Traits::GetParent(std::addressof(this->impl.front())); return *Traits::GetParent(std::addressof(this->impl.front()));
} }
iterator erase(iterator it) { ALWAYS_INLINE iterator erase(iterator it) {
return iterator(this->impl.erase(it.GetImplIterator())); return iterator(this->impl.erase(it.GetImplIterator()));
} }
iterator insert(reference ref) { ALWAYS_INLINE iterator insert(reference ref) {
ImplType::pointer node = Traits::GetNode(std::addressof(ref)); ImplType::pointer node = Traits::GetNode(std::addressof(ref));
this->InsertImpl(node); this->InsertImpl(node);
return iterator(node); return iterator(node);
} }
iterator find(const_reference ref) const { ALWAYS_INLINE iterator find(const_reference ref) const {
return iterator(this->FindImpl(Traits::GetNode(std::addressof(ref)))); return iterator(this->FindImpl(Traits::GetNode(std::addressof(ref))));
} }
iterator nfind(const_reference ref) const { ALWAYS_INLINE iterator nfind(const_reference ref) const {
return iterator(this->NFindImpl(Traits::GetNode(std::addressof(ref)))); return iterator(this->NFindImpl(Traits::GetNode(std::addressof(ref))));
} }
ALWAYS_INLINE iterator find_light(const_light_reference ref) const {
return iterator(this->FindLightImpl(std::addressof(ref)));
}
ALWAYS_INLINE iterator nfind_light(const_light_reference ref) const {
return iterator(this->NFindLightImpl(std::addressof(ref)));
}
}; };
template<auto T, class Derived = util::impl::GetParentType<T>> template<auto T, class Derived = util::impl::GetParentType<T>>
@@ -434,19 +482,19 @@ namespace ams::util {
friend class impl::IntrusiveRedBlackTreeImpl; friend class impl::IntrusiveRedBlackTreeImpl;
static constexpr IntrusiveRedBlackTreeNode *GetNode(Derived *parent) { static constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetNode(Derived *parent) {
return std::addressof(parent->*Member); return std::addressof(parent->*Member);
} }
static constexpr IntrusiveRedBlackTreeNode const *GetNode(Derived const *parent) { static constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode const *GetNode(Derived const *parent) {
return std::addressof(parent->*Member); return std::addressof(parent->*Member);
} }
static constexpr Derived *GetParent(IntrusiveRedBlackTreeNode *node) { static constexpr ALWAYS_INLINE Derived *GetParent(IntrusiveRedBlackTreeNode *node) {
return util::GetParentPointer<Member, Derived>(node); return util::GetParentPointer<Member, Derived>(node);
} }
static constexpr Derived const *GetParent(IntrusiveRedBlackTreeNode const *node) { static constexpr ALWAYS_INLINE Derived const *GetParent(IntrusiveRedBlackTreeNode const *node) {
return util::GetParentPointer<Member, Derived>(node); return util::GetParentPointer<Member, Derived>(node);
} }
private: private:
@@ -474,19 +522,19 @@ namespace ams::util {
friend class impl::IntrusiveRedBlackTreeImpl; friend class impl::IntrusiveRedBlackTreeImpl;
static constexpr IntrusiveRedBlackTreeNode *GetNode(Derived *parent) { static constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetNode(Derived *parent) {
return std::addressof(parent->*Member); return std::addressof(parent->*Member);
} }
static constexpr IntrusiveRedBlackTreeNode const *GetNode(Derived const *parent) { static constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode const *GetNode(Derived const *parent) {
return std::addressof(parent->*Member); return std::addressof(parent->*Member);
} }
static constexpr Derived *GetParent(IntrusiveRedBlackTreeNode *node) { static constexpr ALWAYS_INLINE Derived *GetParent(IntrusiveRedBlackTreeNode *node) {
return util::GetParentPointer<Member, Derived>(node); return util::GetParentPointer<Member, Derived>(node);
} }
static constexpr Derived const *GetParent(IntrusiveRedBlackTreeNode const *node) { static constexpr ALWAYS_INLINE Derived const *GetParent(IntrusiveRedBlackTreeNode const *node) {
return util::GetParentPointer<Member, Derived>(node); return util::GetParentPointer<Member, Derived>(node);
} }
}; };
@@ -513,21 +561,23 @@ namespace ams::util {
friend class impl::IntrusiveRedBlackTreeImpl; friend class impl::IntrusiveRedBlackTreeImpl;
static constexpr IntrusiveRedBlackTreeNode *GetNode(Derived *parent) { static constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode *GetNode(Derived *parent) {
return static_cast<IntrusiveRedBlackTreeNode *>(parent); return static_cast<IntrusiveRedBlackTreeNode *>(parent);
} }
static constexpr IntrusiveRedBlackTreeNode const *GetNode(Derived const *parent) { static constexpr ALWAYS_INLINE IntrusiveRedBlackTreeNode const *GetNode(Derived const *parent) {
return static_cast<const IntrusiveRedBlackTreeNode *>(parent); return static_cast<const IntrusiveRedBlackTreeNode *>(parent);
} }
static constexpr Derived *GetParent(IntrusiveRedBlackTreeNode *node) { static constexpr ALWAYS_INLINE Derived *GetParent(IntrusiveRedBlackTreeNode *node) {
return static_cast<Derived *>(node); return static_cast<Derived *>(node);
} }
static constexpr Derived const *GetParent(IntrusiveRedBlackTreeNode const *node) { static constexpr ALWAYS_INLINE Derived const *GetParent(IntrusiveRedBlackTreeNode const *node) {
return static_cast<const Derived *>(node); return static_cast<const Derived *>(node);
} }
}; };
#pragma GCC pop_options
} }

View File

@@ -29,6 +29,8 @@ namespace ams::kern::init {
/* Prototypes for functions declared in ASM that we need to reference. */ /* Prototypes for functions declared in ASM that we need to reference. */
void StartOtherCore(const ams::kern::init::KInitArguments *init_args); void StartOtherCore(const ams::kern::init::KInitArguments *init_args);
size_t GetMiscUnknownDebugRegionSize();
namespace { namespace {
/* Global Allocator. */ /* Global Allocator. */
@@ -139,10 +141,10 @@ namespace ams::kern::init {
InitializeSlabResourceCounts(); InitializeSlabResourceCounts();
/* Insert the root region for the virtual memory tree, from which all other regions will derive. */ /* Insert the root region for the virtual memory tree, from which all other regions will derive. */
KMemoryLayout::GetVirtualMemoryRegionTree().InsertDirectly(KernelVirtualAddressSpaceBase, KernelVirtualAddressSpaceSize); KMemoryLayout::GetVirtualMemoryRegionTree().InsertDirectly(KernelVirtualAddressSpaceBase, KernelVirtualAddressSpaceBase + KernelVirtualAddressSpaceSize - 1);
/* Insert the root region for the physical memory tree, from which all other regions will derive. */ /* Insert the root region for the physical memory tree, from which all other regions will derive. */
KMemoryLayout::GetPhysicalMemoryRegionTree().InsertDirectly(KernelPhysicalAddressSpaceBase, KernelPhysicalAddressSpaceSize); KMemoryLayout::GetPhysicalMemoryRegionTree().InsertDirectly(KernelPhysicalAddressSpaceBase, KernelPhysicalAddressSpaceBase + KernelPhysicalAddressSpaceSize - 1);
/* Save start and end for ease of use. */ /* Save start and end for ease of use. */
const uintptr_t code_start_virt_addr = reinterpret_cast<uintptr_t>(_start); const uintptr_t code_start_virt_addr = reinterpret_cast<uintptr_t>(_start);
@@ -165,11 +167,42 @@ namespace ams::kern::init {
const size_t code_region_size = GetInteger(code_region_end) - GetInteger(code_region_start); const size_t code_region_size = GetInteger(code_region_end) - GetInteger(code_region_start);
MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetVirtualMemoryRegionTree().Insert(GetInteger(code_region_start), code_region_size, KMemoryRegionType_KernelCode)); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetVirtualMemoryRegionTree().Insert(GetInteger(code_region_start), code_region_size, KMemoryRegionType_KernelCode));
/* Setup the misc region. */ /* Setup board-specific device physical regions. */
constexpr size_t MiscRegionSize = 32_MB; SetupDevicePhysicalMemoryRegions();
/* Determine the amount of space needed for the misc region. */
size_t misc_region_needed_size;
{
/* Each core has a one page stack for all three stack types (Main, Idle, Exception). */
misc_region_needed_size = cpu::NumCores * (3 * (PageSize + PageSize));
/* Account for each auto-map device. */
for (const auto &region : KMemoryLayout::GetPhysicalMemoryRegionTree()) {
if (region.HasTypeAttribute(KMemoryRegionAttr_ShouldKernelMap)) {
/* Check that the region is valid. */
MESOSPHERE_INIT_ABORT_UNLESS(region.GetEndAddress() != 0);
/* Account for the region. */
misc_region_needed_size += PageSize + (util::AlignUp(region.GetLastAddress(), PageSize) - util::AlignDown(region.GetAddress(), PageSize));
}
}
/* Account for the unknown debug region. */
misc_region_needed_size += GetMiscUnknownDebugRegionSize();
/* Multiply the needed size by three, to account for the need for guard space. */
misc_region_needed_size *= 3;
}
/* Decide on the actual size for the misc region. */
constexpr size_t MiscRegionAlign = KernelAslrAlignment; constexpr size_t MiscRegionAlign = KernelAslrAlignment;
const KVirtualAddress misc_region_start = KMemoryLayout::GetVirtualMemoryRegionTree().GetRandomAlignedRegion(MiscRegionSize, MiscRegionAlign, KMemoryRegionType_Kernel); constexpr size_t MiscRegionMinimumSize = 32_MB;
MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetVirtualMemoryRegionTree().Insert(GetInteger(misc_region_start), MiscRegionSize, KMemoryRegionType_KernelMisc)); const size_t misc_region_size = util::AlignUp(std::max(misc_region_needed_size, MiscRegionMinimumSize), MiscRegionAlign);
MESOSPHERE_INIT_ABORT_UNLESS(misc_region_size > 0);
/* Setup the misc region. */
const KVirtualAddress misc_region_start = KMemoryLayout::GetVirtualMemoryRegionTree().GetRandomAlignedRegion(misc_region_size, MiscRegionAlign, KMemoryRegionType_Kernel);
MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetVirtualMemoryRegionTree().Insert(GetInteger(misc_region_start), misc_region_size, KMemoryRegionType_KernelMisc));
/* Setup the stack region. */ /* Setup the stack region. */
constexpr size_t StackRegionSize = 14_MB; constexpr size_t StackRegionSize = 14_MB;
@@ -202,16 +235,13 @@ namespace ams::kern::init {
/* Setup the Misc Unknown Debug region, if it's not zero. */ /* Setup the Misc Unknown Debug region, if it's not zero. */
if (misc_unk_debug_phys_addr) { if (misc_unk_debug_phys_addr) {
constexpr size_t MiscUnknownDebugRegionSize = PageSize;
constexpr size_t MiscUnknownDebugRegionAlign = PageSize; constexpr size_t MiscUnknownDebugRegionAlign = PageSize;
const KVirtualAddress misc_unk_debug_virt_addr = KMemoryLayout::GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(MiscUnknownDebugRegionSize, MiscUnknownDebugRegionAlign, KMemoryRegionType_KernelMisc, PageSize); const size_t misc_unk_debug_size = GetMiscUnknownDebugRegionSize();
MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetVirtualMemoryRegionTree().Insert(GetInteger(misc_unk_debug_virt_addr), MiscUnknownDebugRegionSize, KMemoryRegionType_KernelMiscUnknownDebug)); const KVirtualAddress misc_unk_debug_virt_addr = KMemoryLayout::GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(misc_unk_debug_size, MiscUnknownDebugRegionAlign, KMemoryRegionType_KernelMisc, PageSize);
ttbr1_table.Map(misc_unk_debug_virt_addr, MiscUnknownDebugRegionSize, misc_unk_debug_phys_addr, KernelRoDataAttribute, g_initial_page_allocator); MESOSPHERE_INIT_ABORT_UNLESS(KMemoryLayout::GetVirtualMemoryRegionTree().Insert(GetInteger(misc_unk_debug_virt_addr), misc_unk_debug_size, KMemoryRegionType_KernelMiscUnknownDebug));
ttbr1_table.Map(misc_unk_debug_virt_addr, misc_unk_debug_size, misc_unk_debug_phys_addr, KernelRoDataAttribute, g_initial_page_allocator);
} }
/* Setup board-specific device physical regions. */
SetupDevicePhysicalMemoryRegions();
/* Automatically map in devices that have auto-map attributes. */ /* Automatically map in devices that have auto-map attributes. */
for (auto &region : KMemoryLayout::GetPhysicalMemoryRegionTree()) { for (auto &region : KMemoryLayout::GetPhysicalMemoryRegionTree()) {
/* We only care about kernel regions. */ /* We only care about kernel regions. */
@@ -229,6 +259,9 @@ namespace ams::kern::init {
continue; continue;
} }
/* Check that the region is valid. */
MESOSPHERE_INIT_ABORT_UNLESS(region.GetEndAddress() != 0);
/* Set the attribute to note we've mapped this region. */ /* Set the attribute to note we've mapped this region. */
region.SetTypeAttribute(KMemoryRegionAttr_DidKernelMap); region.SetTypeAttribute(KMemoryRegionAttr_DidKernelMap);
@@ -258,10 +291,6 @@ namespace ams::kern::init {
/* Physically randomize the slab region. */ /* Physically randomize the slab region. */
/* NOTE: Nintendo does this only on 10.0.0+ */ /* NOTE: Nintendo does this only on 10.0.0+ */
ttbr1_table.PhysicallyRandomize(slab_region_start, slab_region_size, false); ttbr1_table.PhysicallyRandomize(slab_region_start, slab_region_size, false);
cpu::StoreEntireCacheForInit();
/* Clear the slab region. */
std::memset(GetVoidPointer(slab_region_start), 0, slab_region_size);
/* Determine size available for kernel page table heaps, requiring > 8 MB. */ /* Determine size available for kernel page table heaps, requiring > 8 MB. */
const KPhysicalAddress resource_end_phys_addr = slab_start_phys_addr + resource_region_size; const KPhysicalAddress resource_end_phys_addr = slab_start_phys_addr + resource_region_size;
@@ -282,15 +311,22 @@ namespace ams::kern::init {
/* All DRAM regions that we haven't tagged by this point will be mapped under the linear mapping. Tag them. */ /* All DRAM regions that we haven't tagged by this point will be mapped under the linear mapping. Tag them. */
for (auto &region : KMemoryLayout::GetPhysicalMemoryRegionTree()) { for (auto &region : KMemoryLayout::GetPhysicalMemoryRegionTree()) {
if (region.GetType() == KMemoryRegionType_Dram) { if (region.GetType() == KMemoryRegionType_Dram) {
/* Check that the region is valid. */
MESOSPHERE_INIT_ABORT_UNLESS(region.GetEndAddress() != 0);
/* Set the linear map attribute. */
region.SetTypeAttribute(KMemoryRegionAttr_LinearMapped); region.SetTypeAttribute(KMemoryRegionAttr_LinearMapped);
} }
} }
/* Get the linear region extents. */
const auto linear_extents = KMemoryLayout::GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionAttr_LinearMapped);
MESOSPHERE_INIT_ABORT_UNLESS(linear_extents.GetEndAddress() != 0);
/* Setup the linear mapping region. */ /* Setup the linear mapping region. */
constexpr size_t LinearRegionAlign = 1_GB; constexpr size_t LinearRegionAlign = 1_GB;
const auto linear_extents = KMemoryLayout::GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionAttr_LinearMapped); const KPhysicalAddress aligned_linear_phys_start = util::AlignDown(linear_extents.GetAddress(), LinearRegionAlign);
const KPhysicalAddress aligned_linear_phys_start = util::AlignDown(linear_extents.first_region->GetAddress(), LinearRegionAlign); const size_t linear_region_size = util::AlignUp(linear_extents.GetEndAddress(), LinearRegionAlign) - GetInteger(aligned_linear_phys_start);
const size_t linear_region_size = util::AlignUp(linear_extents.last_region->GetEndAddress(), LinearRegionAlign) - GetInteger(aligned_linear_phys_start);
const KVirtualAddress linear_region_start = KMemoryLayout::GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(linear_region_size, LinearRegionAlign, KMemoryRegionType_None, LinearRegionAlign); const KVirtualAddress linear_region_start = KMemoryLayout::GetVirtualMemoryRegionTree().GetRandomAlignedRegionWithGuard(linear_region_size, LinearRegionAlign, KMemoryRegionType_None, LinearRegionAlign);
const uintptr_t linear_region_phys_to_virt_diff = GetInteger(linear_region_start) - GetInteger(aligned_linear_phys_start); const uintptr_t linear_region_phys_to_virt_diff = GetInteger(linear_region_start) - GetInteger(aligned_linear_phys_start);
@@ -304,6 +340,8 @@ namespace ams::kern::init {
continue; continue;
} }
MESOSPHERE_INIT_ABORT_UNLESS(region.GetEndAddress() != 0);
if (cur_size == 0) { if (cur_size == 0) {
cur_phys_addr = region.GetAddress(); cur_phys_addr = region.GetAddress();
cur_size = region.GetSize(); cur_size = region.GetSize();
@@ -332,6 +370,13 @@ namespace ams::kern::init {
} }
} }
/* Clear the slab region. */
std::memset(GetVoidPointer(slab_region_start), 0, slab_region_size);
/* NOTE: Unknown function is called here which is ifdef'd out on retail kernel. */
/* The unknown function is immediately before the function which gets the unknown debug region size, inside this translation unit. */
/* It's likely that this is some kind of initializer for the unknown debug region. */
/* Create regions for and map all core-specific stacks. */ /* Create regions for and map all core-specific stacks. */
for (size_t i = 0; i < cpu::NumCores; i++) { for (size_t i = 0; i < cpu::NumCores; i++) {
MapStackForCore(ttbr1_table, KMemoryRegionType_KernelMiscMainStack, i); MapStackForCore(ttbr1_table, KMemoryRegionType_KernelMiscMainStack, i);
@@ -443,4 +488,8 @@ namespace ams::kern::init {
cpu::EnsureInstructionConsistency(); cpu::EnsureInstructionConsistency();
} }
size_t GetMiscUnknownDebugRegionSize() {
return 0;
}
} }

View File

@@ -249,6 +249,27 @@ _ZN3ams4kern4init16JumpFromEL2ToEL1Ev:
bl _ZN3ams4kern4arch5arm643cpu32FlushEntireDataCacheWithoutStackEv bl _ZN3ams4kern4arch5arm643cpu32FlushEntireDataCacheWithoutStackEv
/* Setup system registers for deprivileging. */ /* Setup system registers for deprivileging. */
/* Check if we're on cortex A57 or A53. If we are, set ACTLR_EL2. */
mrs x1, midr_el1
/* Is the manufacturer ID 'A' (ARM)? */
ubfx x2, x1, #0x18, #8
cmp x2, #0x41
b.ne 2f
/* Is the board ID Cortex-A57? */
ubfx x2, x1, #4, #0xC
mov x3, #0xD07
cmp x2, x3
b.eq 1f
/* Is the board ID Cortex-A53? */
mov x3, #0xD03
cmp x2, x3
b.ne 2f
1:
/* ACTLR_EL2: */ /* ACTLR_EL2: */
/* - CPUACTLR access control = 1 */ /* - CPUACTLR access control = 1 */
/* - CPUECTLR access control = 1 */ /* - CPUECTLR access control = 1 */
@@ -258,6 +279,7 @@ _ZN3ams4kern4init16JumpFromEL2ToEL1Ev:
mov x0, #0x73 mov x0, #0x73
msr actlr_el2, x0 msr actlr_el2, x0
2:
/* HCR_EL2: */ /* HCR_EL2: */
/* - RW = 1 (el1 is aarch64) */ /* - RW = 1 (el1 is aarch64) */
mov x0, #0x80000000 mov x0, #0x80000000
@@ -275,6 +297,14 @@ _ZN3ams4kern4init16JumpFromEL2ToEL1Ev:
mov x0, #0xFFFFFFFF mov x0, #0xFFFFFFFF
msr dacr32_el2, x0 msr dacr32_el2, x0
/* Set VPIDR_EL2 = MIDR_EL1 */
mrs x0, midr_el1
msr vpidr_el2, x0
/* SET VMPIDR_EL2 = MPIDR_EL1 */
mrs x0, mpidr_el1
msr vmpidr_el2, x0
/* SPSR_EL2: */ /* SPSR_EL2: */
/* - EL1h */ /* - EL1h */
/* - IRQ masked */ /* - IRQ masked */

View File

@@ -303,7 +303,6 @@ namespace ams::kern::init::loader {
/* On 10.0.0+, Physically randomize the kernel region. */ /* On 10.0.0+, Physically randomize the kernel region. */
if (kern::GetTargetFirmware() >= ams::TargetFirmware_10_0_0) { if (kern::GetTargetFirmware() >= ams::TargetFirmware_10_0_0) {
ttbr1_table.PhysicallyRandomize(virtual_base_address + rx_offset, bss_end_offset - rx_offset, true); ttbr1_table.PhysicallyRandomize(virtual_base_address + rx_offset, bss_end_offset - rx_offset, true);
cpu::StoreEntireCacheForInit();
} }
/* Clear kernel .bss. */ /* Clear kernel .bss. */

View File

@@ -21,8 +21,8 @@ namespace ams::mitm::hid {
Result HidMitmService::SetSupportedNpadStyleSet(const sf::ClientAppletResourceUserId &client_aruid, u32 style_set) { Result HidMitmService::SetSupportedNpadStyleSet(const sf::ClientAppletResourceUserId &client_aruid, u32 style_set) {
/* This code applies only to hbl, guaranteed by the check in ShouldMitm. */ /* This code applies only to hbl, guaranteed by the check in ShouldMitm. */
style_set |= TYPE_SYSTEM | TYPE_SYSTEM_EXT; style_set |= HidNpadStyleTag_NpadSystem | HidNpadStyleTag_NpadSystemExt;
return hidSetSupportedNpadStyleSetFwd(this->forward_service.get(), static_cast<u64>(this->client_info.process_id), static_cast<u64>(client_aruid.GetValue()), static_cast<HidControllerType>(style_set)); return hidSetSupportedNpadStyleSetFwd(this->forward_service.get(), static_cast<u64>(this->client_info.process_id), static_cast<u64>(client_aruid.GetValue()), style_set);
} }
} }

View File

@@ -17,11 +17,11 @@
#include <stratosphere/sf/sf_mitm_dispatch.h> #include <stratosphere/sf/sf_mitm_dispatch.h>
/* Command forwarders. */ /* Command forwarders. */
Result hidSetSupportedNpadStyleSetFwd(Service* s, u64 process_id, u64 aruid, HidControllerType type) { Result hidSetSupportedNpadStyleSetFwd(Service* s, u64 process_id, u64 aruid, u32 style_set) {
const struct { const struct {
u32 type; u32 style_set;
u32 pad; u32 pad;
u64 aruid; u64 aruid;
} in = { type, 0, aruid }; } in = { style_set, 0, aruid };
return serviceMitmDispatchIn(s, 100, in, .in_send_pid = true, .override_pid = process_id); return serviceMitmDispatchIn(s, 100, in, .in_send_pid = true, .override_pid = process_id);
} }

View File

@@ -12,7 +12,7 @@ extern "C" {
#endif #endif
/* Command forwarders. */ /* Command forwarders. */
Result hidSetSupportedNpadStyleSetFwd(Service* s, u64 process_id, u64 aruid, HidControllerType type); Result hidSetSupportedNpadStyleSetFwd(Service* s, u64 process_id, u64 aruid, u32 style_set);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@@ -11,6 +11,7 @@
"pool_partition": 2, "pool_partition": 2,
"is_64_bit": true, "is_64_bit": true,
"address_space_type": 3, "address_space_type": 3,
"disable_device_address_space_merge": true,
"filesystem_access": { "filesystem_access": {
"permissions": "0xFFFFFFFFFFFFFFFF" "permissions": "0xFFFFFFFFFFFFFFFF"
}, },

View File

@@ -11,6 +11,7 @@
"pool_partition": 2, "pool_partition": 2,
"is_64_bit": true, "is_64_bit": true,
"address_space_type": 3, "address_space_type": 3,
"disable_device_address_space_merge": true,
"filesystem_access": { "filesystem_access": {
"permissions": "0xFFFFFFFFFFFFFFFF" "permissions": "0xFFFFFFFFFFFFFFFF"
}, },

View File

@@ -11,6 +11,7 @@
"pool_partition": 2, "pool_partition": 2,
"is_64_bit": true, "is_64_bit": true,
"address_space_type": 3, "address_space_type": 3,
"disable_device_address_space_merge": true,
"filesystem_access": { "filesystem_access": {
"permissions": "0xFFFFFFFFFFFFFFFF" "permissions": "0xFFFFFFFFFFFFFFFF"
}, },

View File

@@ -11,6 +11,7 @@
"pool_partition": 2, "pool_partition": 2,
"is_64_bit": true, "is_64_bit": true,
"address_space_type": 3, "address_space_type": 3,
"disable_device_address_space_merge": true,
"filesystem_access": { "filesystem_access": {
"permissions": "0xFFFFFFFFFFFFFFFF" "permissions": "0xFFFFFFFFFFFFFFFF"
}, },

View File

@@ -11,6 +11,7 @@
"pool_partition": 2, "pool_partition": 2,
"is_64_bit": true, "is_64_bit": true,
"address_space_type": 3, "address_space_type": 3,
"disable_device_address_space_merge": true,
"filesystem_access": { "filesystem_access": {
"permissions": "0xFFFFFFFFFFFFFFFF" "permissions": "0xFFFFFFFFFFFFFFFF"
}, },

View File

@@ -11,6 +11,7 @@
"pool_partition": 2, "pool_partition": 2,
"is_64_bit": true, "is_64_bit": true,
"address_space_type": 3, "address_space_type": 3,
"disable_device_address_space_merge": true,
"filesystem_access": { "filesystem_access": {
"permissions": "0xFFFFFFFFFFFFFFFF" "permissions": "0xFFFFFFFFFFFFFFFF"
}, },

View File

@@ -11,6 +11,7 @@
"pool_partition": 2, "pool_partition": 2,
"is_64_bit": true, "is_64_bit": true,
"address_space_type": 3, "address_space_type": 3,
"disable_device_address_space_merge": true,
"filesystem_access": { "filesystem_access": {
"permissions": "0x0" "permissions": "0x0"
}, },

View File

@@ -55,11 +55,20 @@ namespace ams::ldr {
R_UNLESS(npdm->magic == Npdm::Magic, ResultInvalidMeta()); R_UNLESS(npdm->magic == Npdm::Magic, ResultInvalidMeta());
/* Validate flags. */ /* Validate flags. */
u32 mask = ~0x1F; u32 mask;
if (hos::GetVersion() < hos::Version_7_0_0) { if (hos::GetVersion() >= hos::Version_11_0_0) {
/* 7.0.0 added 0x10 as a valid bit to NPDM flags, so before that we only check 0xF. */ /* 11.0.0 added bit 5 = "DisableDeviceAddressSpaceMerge". */
mask = ~0x3F;
} else if (hos::GetVersion() >= hos::Version_7_0_0) {
/* 7.0.0 added bit 4 = "UseOptimizedMemory" */
mask = ~0x1F;
} else {
mask = ~0xF; mask = ~0xF;
} }
/* We set the "DisableDeviceAddressSpaceMerge" bit on all versions, so be permissive with it. */
mask &= ~0x20;
R_UNLESS(!(npdm->flags & mask), ResultInvalidMeta()); R_UNLESS(!(npdm->flags & mask), ResultInvalidMeta());
/* Validate Acid extents. */ /* Validate Acid extents. */

View File

@@ -326,6 +326,13 @@ namespace ams::ldr {
} }
} }
/* 11.0.0+ Set Disable DAS merge. */
if (hos::GetVersion() >= hos::Version_11_0_0 || svc::IsKernelMesosphere()) {
if (meta_flags & Npdm::MetaFlag_DisableDeviceAddressSpaceMerge) {
flags |= svc::CreateProcessFlag_DisableDeviceAddressSpaceMerge;
}
}
*out = flags; *out = flags;
return ResultSuccess(); return ResultSuccess();
} }

View File

@@ -11,6 +11,7 @@
"pool_partition": 2, "pool_partition": 2,
"is_64_bit": true, "is_64_bit": true,
"address_space_type": 3, "address_space_type": 3,
"disable_device_address_space_merge": true,
"filesystem_access": { "filesystem_access": {
"permissions": "0xFFFFFFFFFFFFFFFF" "permissions": "0xFFFFFFFFFFFFFFFF"
}, },

View File

@@ -11,6 +11,7 @@
"pool_partition": 2, "pool_partition": 2,
"is_64_bit": true, "is_64_bit": true,
"address_space_type": 3, "address_space_type": 3,
"disable_device_address_space_merge": true,
"filesystem_access": { "filesystem_access": {
"permissions": "0xFFFFFFFFFFFFFFFF" "permissions": "0xFFFFFFFFFFFFFFFF"
}, },