Compare commits
33 Commits
hid_refact
...
11_support
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
feb765c40d | ||
|
|
d7429b74a4 | ||
|
|
53aae17b64 | ||
|
|
94d818db90 | ||
|
|
eccadf2958 | ||
|
|
60ea4a1b1c | ||
|
|
464f336016 | ||
|
|
c788f7a3fc | ||
|
|
bbfed7be66 | ||
|
|
e38f87b182 | ||
|
|
e4677d3a9d | ||
|
|
01a5f4094b | ||
|
|
2f12dd039f | ||
|
|
f058d04933 | ||
|
|
8e1a46b951 | ||
|
|
24db70602f | ||
|
|
4ce3778d87 | ||
|
|
95bbb20cb0 | ||
|
|
f089cd4b76 | ||
|
|
6f95b738dc | ||
|
|
6cc21e4d98 | ||
|
|
8936e4d5d9 | ||
|
|
3b3cb337f0 | ||
|
|
a56bdab820 | ||
|
|
866310937a | ||
|
|
cc7cf49c88 | ||
|
|
1e9a3c3f91 | ||
|
|
5002b17c71 | ||
|
|
3886c8707f | ||
|
|
4c8dad3ea2 | ||
|
|
25e1d34017 | ||
|
|
4f00303daf | ||
|
|
b421e3eadb |
7
Makefile
7
Makefile
@@ -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
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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();
|
||||||
|
|||||||
41
libraries/libmesosphere/include/mesosphere/kern_k_alpha.hpp
Normal file
41
libraries/libmesosphere/include/mesosphere/kern_k_alpha.hpp
Normal 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); /* ... */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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;
|
||||||
|
|||||||
48
libraries/libmesosphere/include/mesosphere/kern_k_beta.hpp
Normal file
48
libraries/libmesosphere/include/mesosphere/kern_k_beta.hpp
Normal 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); /* ... */ }
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 ®ion = 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; }
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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{};
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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); }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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; }
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -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); }
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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, _)
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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 ®ion : GetPhysicalMemoryRegionTree()) {
|
for (auto ®ion : 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 ®ion : GetVirtualMemoryRegionTree()) {
|
for (auto ®ion : 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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ®ion : KMemoryLayout::GetPhysicalMemoryRegionTree()) {
|
||||||
|
if (region.IsDerivedFrom(KMemoryRegionType_DramReservedBase)) {
|
||||||
|
MESOSPHERE_ABORT_UNLESS(region.GetEndAddress() != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
cpu::SynchronizeAllCores();
|
cpu::SynchronizeAllCores();
|
||||||
|
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
79
libraries/libmesosphere/source/svc/kern_svc_alpha_beta.cpp
Normal file
79
libraries/libmesosphere/source/svc/kern_svc_alpha_beta.cpp
Normal 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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:
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)) \
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 ®ion : 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 ®ion : KMemoryLayout::GetPhysicalMemoryRegionTree()) {
|
for (auto ®ion : 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 ®ion : KMemoryLayout::GetPhysicalMemoryRegionTree()) {
|
for (auto ®ion : 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -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 */
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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. */
|
||||||
|
|||||||
@@ -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();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user