mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-26 13:52:21 +00:00
kernelldr: miscellaneous fixes
This commit is contained in:
parent
3c7c1fbd8a
commit
f78653d815
7 changed files with 45 additions and 42 deletions
|
@ -77,11 +77,11 @@ namespace ams::kern::init {
|
||||||
}
|
}
|
||||||
protected:
|
protected:
|
||||||
constexpr ALWAYS_INLINE u64 GetBits(size_t offset, size_t count) const {
|
constexpr ALWAYS_INLINE u64 GetBits(size_t offset, size_t count) const {
|
||||||
return (this->attributes >> offset) & ((1 << count) - 1);
|
return (this->attributes >> offset) & ((1ul << count) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE u64 SelectBits(size_t offset, size_t count) const {
|
constexpr ALWAYS_INLINE u64 SelectBits(size_t offset, size_t count) const {
|
||||||
return this->attributes & (((1 << count) - 1) << offset);
|
return this->attributes & (((1ul << count) - 1) << offset);
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
constexpr ALWAYS_INLINE bool IsUserExecuteNever() const { return this->GetBits(54, 1) != 0; }
|
constexpr ALWAYS_INLINE bool IsUserExecuteNever() const { return this->GetBits(54, 1) != 0; }
|
||||||
|
@ -128,9 +128,9 @@ namespace ams::kern::init {
|
||||||
return this->SelectBits(12, 36);
|
return this->SelectBits(12, 36);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE bool IsCompatibleWithAttribute(const PageTableEntry &rhs) const {
|
constexpr ALWAYS_INLINE bool IsCompatibleWithAttribute(const PageTableEntry &rhs, bool contig) const {
|
||||||
/* Check whether this has the same permission/etc as the desired attributes. */
|
/* Check whether this has the same permission/etc as the desired attributes. */
|
||||||
return (this->GetBlock() | rhs.GetRawAttributes()) == this->GetRawAttributes();
|
return L1PageTableEntry(this->GetBlock(), rhs, contig).GetRawAttributes() == this->GetRawAttributes();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -156,16 +156,16 @@ namespace ams::kern::init {
|
||||||
return this->SelectBits(12, 36);
|
return this->SelectBits(12, 36);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE bool IsCompatibleWithAttribute(const PageTableEntry &rhs) const {
|
constexpr ALWAYS_INLINE bool IsCompatibleWithAttribute(const PageTableEntry &rhs, bool contig) const {
|
||||||
/* Check whether this has the same permission/etc as the desired attributes. */
|
/* Check whether this has the same permission/etc as the desired attributes. */
|
||||||
return (this->GetBlock() | rhs.GetRawAttributes()) == this->GetRawAttributes();
|
return L2PageTableEntry(this->GetBlock(), rhs, contig).GetRawAttributes() == this->GetRawAttributes();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class L3PageTableEntry : public PageTableEntry {
|
class L3PageTableEntry : public PageTableEntry {
|
||||||
public:
|
public:
|
||||||
constexpr ALWAYS_INLINE L3PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
|
constexpr ALWAYS_INLINE L3PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
|
||||||
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x1)
|
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x3)
|
||||||
{
|
{
|
||||||
/* ... */
|
/* ... */
|
||||||
}
|
}
|
||||||
|
@ -176,9 +176,9 @@ namespace ams::kern::init {
|
||||||
return this->SelectBits(12, 36);
|
return this->SelectBits(12, 36);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE bool IsCompatibleWithAttribute(const PageTableEntry &rhs) const {
|
constexpr ALWAYS_INLINE bool IsCompatibleWithAttribute(const PageTableEntry &rhs, bool contig) const {
|
||||||
/* Check whether this has the same permission/etc as the desired attributes. */
|
/* Check whether this has the same permission/etc as the desired attributes. */
|
||||||
return (this->GetBlock() | rhs.GetRawAttributes()) == this->GetRawAttributes();
|
return L3PageTableEntry(this->GetBlock(), rhs, contig).GetRawAttributes() == this->GetRawAttributes();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -247,7 +247,7 @@ namespace ams::kern::init {
|
||||||
if (!l1_entry->IsTable()) {
|
if (!l1_entry->IsTable()) {
|
||||||
KPhysicalAddress new_table = allocator.Allocate();
|
KPhysicalAddress new_table = allocator.Allocate();
|
||||||
ClearNewPageTable(new_table);
|
ClearNewPageTable(new_table);
|
||||||
*l1_entry = L1PageTableEntry(phys_addr, attr.IsPrivilegedExecuteNever());
|
*l1_entry = L1PageTableEntry(new_table, attr.IsPrivilegedExecuteNever());
|
||||||
cpu::DataSynchronizationBarrierInnerShareable();
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,7 +281,7 @@ namespace ams::kern::init {
|
||||||
if (!l2_entry->IsTable()) {
|
if (!l2_entry->IsTable()) {
|
||||||
KPhysicalAddress new_table = allocator.Allocate();
|
KPhysicalAddress new_table = allocator.Allocate();
|
||||||
ClearNewPageTable(new_table);
|
ClearNewPageTable(new_table);
|
||||||
*l2_entry = L2PageTableEntry(phys_addr, attr.IsPrivilegedExecuteNever());
|
*l2_entry = L2PageTableEntry(new_table, attr.IsPrivilegedExecuteNever());
|
||||||
cpu::DataSynchronizationBarrierInnerShareable();
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -373,7 +373,7 @@ namespace ams::kern::init {
|
||||||
const KPhysicalAddress block = l1_entry->GetBlock();
|
const KPhysicalAddress block = l1_entry->GetBlock();
|
||||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L1BlockSize));
|
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L1BlockSize));
|
||||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, L1BlockSize));
|
MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, L1BlockSize));
|
||||||
MESOSPHERE_ABORT_UNLESS(l1_entry->IsCompatibleWithAttribute(attr_before));
|
MESOSPHERE_ABORT_UNLESS(l1_entry->IsCompatibleWithAttribute(attr_before, false));
|
||||||
|
|
||||||
/* Invalidate the existing L1 block. */
|
/* Invalidate the existing L1 block. */
|
||||||
*static_cast<PageTableEntry *>(l1_entry) = InvalidPageTableEntry;
|
*static_cast<PageTableEntry *>(l1_entry) = InvalidPageTableEntry;
|
||||||
|
@ -404,7 +404,7 @@ namespace ams::kern::init {
|
||||||
/* Invalidate the existing contiguous L2 block. */
|
/* Invalidate the existing contiguous L2 block. */
|
||||||
for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) {
|
for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) {
|
||||||
/* Ensure that the entry is valid. */
|
/* Ensure that the entry is valid. */
|
||||||
MESOSPHERE_ABORT_UNLESS(l2_entry[i].IsCompatibleWithAttribute(attr_before));
|
MESOSPHERE_ABORT_UNLESS(l2_entry[i].IsCompatibleWithAttribute(attr_before, true));
|
||||||
static_cast<PageTableEntry *>(l2_entry)[i] = InvalidPageTableEntry;
|
static_cast<PageTableEntry *>(l2_entry)[i] = InvalidPageTableEntry;
|
||||||
}
|
}
|
||||||
cpu::DataSynchronizationBarrierInnerShareable();
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
|
@ -422,7 +422,7 @@ namespace ams::kern::init {
|
||||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L2BlockSize));
|
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L2BlockSize));
|
||||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(block), L2BlockSize));
|
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(block), L2BlockSize));
|
||||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, L2BlockSize));
|
MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, L2BlockSize));
|
||||||
MESOSPHERE_ABORT_UNLESS(l2_entry->IsCompatibleWithAttribute(attr_before));
|
MESOSPHERE_ABORT_UNLESS(l2_entry->IsCompatibleWithAttribute(attr_before, false));
|
||||||
|
|
||||||
/* Invalidate the existing L2 block. */
|
/* Invalidate the existing L2 block. */
|
||||||
*static_cast<PageTableEntry *>(l2_entry) = InvalidPageTableEntry;
|
*static_cast<PageTableEntry *>(l2_entry) = InvalidPageTableEntry;
|
||||||
|
@ -456,7 +456,7 @@ namespace ams::kern::init {
|
||||||
/* Invalidate the existing contiguous L3 block. */
|
/* Invalidate the existing contiguous L3 block. */
|
||||||
for (size_t i = 0; i < L3ContiguousBlockSize / L3BlockSize; i++) {
|
for (size_t i = 0; i < L3ContiguousBlockSize / L3BlockSize; i++) {
|
||||||
/* Ensure that the entry is valid. */
|
/* Ensure that the entry is valid. */
|
||||||
MESOSPHERE_ABORT_UNLESS(l3_entry[i].IsCompatibleWithAttribute(attr_before));
|
MESOSPHERE_ABORT_UNLESS(l3_entry[i].IsCompatibleWithAttribute(attr_before, true));
|
||||||
static_cast<PageTableEntry *>(l3_entry)[i] = InvalidPageTableEntry;
|
static_cast<PageTableEntry *>(l3_entry)[i] = InvalidPageTableEntry;
|
||||||
}
|
}
|
||||||
cpu::DataSynchronizationBarrierInnerShareable();
|
cpu::DataSynchronizationBarrierInnerShareable();
|
||||||
|
@ -474,7 +474,7 @@ namespace ams::kern::init {
|
||||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L3BlockSize));
|
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), L3BlockSize));
|
||||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(block), L3BlockSize));
|
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(block), L3BlockSize));
|
||||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, L3BlockSize));
|
MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, L3BlockSize));
|
||||||
MESOSPHERE_ABORT_UNLESS(l3_entry->IsCompatibleWithAttribute(attr_before));
|
MESOSPHERE_ABORT_UNLESS(l3_entry->IsCompatibleWithAttribute(attr_before, false));
|
||||||
|
|
||||||
/* Invalidate the existing L3 block. */
|
/* Invalidate the existing L3 block. */
|
||||||
*static_cast<PageTableEntry *>(l3_entry) = InvalidPageTableEntry;
|
*static_cast<PageTableEntry *>(l3_entry) = InvalidPageTableEntry;
|
||||||
|
|
|
@ -55,7 +55,7 @@ namespace ams::kern::arm64::cpu {
|
||||||
ALWAYS_INLINE GenericRegisterAccessor(u64 v) : value(v) { /* ... */ }
|
ALWAYS_INLINE GenericRegisterAccessor(u64 v) : value(v) { /* ... */ }
|
||||||
protected:
|
protected:
|
||||||
constexpr ALWAYS_INLINE u64 GetBits(size_t offset, size_t count) const {
|
constexpr ALWAYS_INLINE u64 GetBits(size_t offset, size_t count) const {
|
||||||
return (this->value >> offset) & ((1 << count) - 1);
|
return (this->value >> offset) & ((1ul << count) - 1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -86,13 +86,11 @@ namespace ams::kern {
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
|
u64 KSystemControl::GenerateRandomRange(u64 min, u64 max) {
|
||||||
/* This is a biased random, but this is okay for now. */
|
|
||||||
/* TODO: unbiased random? */
|
|
||||||
const u64 range_size = ((max + 1) - min);
|
const u64 range_size = ((max + 1) - min);
|
||||||
const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
|
const u64 effective_max = (std::numeric_limits<u64>::max() / range_size) * range_size;
|
||||||
while (true) {
|
while (true) {
|
||||||
if (const u64 rnd = GenerateRandomU64(); rnd < effective_max) {
|
if (const u64 rnd = GenerateRandomU64(); rnd < effective_max) {
|
||||||
return rnd % effective_max;
|
return min + (rnd % range_size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -83,7 +83,7 @@ namespace ams::kern::smc {
|
||||||
void GenerateRandomBytes(void *dst, size_t size) {
|
void GenerateRandomBytes(void *dst, size_t size) {
|
||||||
/* Call SmcGenerateRandomBytes() */
|
/* Call SmcGenerateRandomBytes() */
|
||||||
/* TODO: Lock this to ensure only one core calls at once. */
|
/* TODO: Lock this to ensure only one core calls at once. */
|
||||||
SecureMonitorArguments args = { FunctionId_GetConfig, size };
|
SecureMonitorArguments args = { FunctionId_GenerateRandomBytes, size };
|
||||||
MESOSPHERE_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.x[0]));
|
MESOSPHERE_ABORT_UNLESS(size <= sizeof(args) - sizeof(args.x[0]));
|
||||||
CallPrivilegedSecureMonitorFunction(args);
|
CallPrivilegedSecureMonitorFunction(args);
|
||||||
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.x[0]) == SmcResult::Success));
|
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.x[0]) == SmcResult::Success));
|
||||||
|
|
|
@ -21,20 +21,6 @@ namespace ams::util {
|
||||||
|
|
||||||
template<char A, char B, char C, char D>
|
template<char A, char B, char C, char D>
|
||||||
struct FourCC {
|
struct FourCC {
|
||||||
/* TODO: C++20 std::endian */
|
|
||||||
static constexpr u32 Code = (static_cast<u32>(A) << 0x18) |
|
|
||||||
(static_cast<u32>(B) << 0x10) |
|
|
||||||
(static_cast<u32>(C) << 0x08) |
|
|
||||||
(static_cast<u32>(D) << 0x00);
|
|
||||||
|
|
||||||
static constexpr const char String[] = {D, C, B, A};
|
|
||||||
|
|
||||||
static_assert(sizeof(Code) == 4);
|
|
||||||
static_assert(sizeof(String) == 4);
|
|
||||||
};
|
|
||||||
|
|
||||||
template<char A, char B, char C, char D>
|
|
||||||
struct ReverseFourCC {
|
|
||||||
/* TODO: C++20 std::endian */
|
/* TODO: C++20 std::endian */
|
||||||
static constexpr u32 Code = (static_cast<u32>(A) << 0x00) |
|
static constexpr u32 Code = (static_cast<u32>(A) << 0x00) |
|
||||||
(static_cast<u32>(B) << 0x08) |
|
(static_cast<u32>(B) << 0x08) |
|
||||||
|
@ -47,4 +33,18 @@ namespace ams::util {
|
||||||
static_assert(sizeof(String) == 4);
|
static_assert(sizeof(String) == 4);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<char A, char B, char C, char D>
|
||||||
|
struct ReverseFourCC {
|
||||||
|
/* TODO: C++20 std::endian */
|
||||||
|
static constexpr u32 Code = (static_cast<u32>(A) << 0x18) |
|
||||||
|
(static_cast<u32>(B) << 0x10) |
|
||||||
|
(static_cast<u32>(C) << 0x08) |
|
||||||
|
(static_cast<u32>(D) << 0x00);
|
||||||
|
|
||||||
|
static constexpr const char String[] = {D, C, B, A};
|
||||||
|
|
||||||
|
static_assert(sizeof(Code) == 4);
|
||||||
|
static_assert(sizeof(String) == 4);
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
|
@ -44,8 +44,10 @@ namespace ams::kern::init::loader {
|
||||||
this->next_address = address;
|
this->next_address = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void Finalize() {
|
ALWAYS_INLINE uintptr_t Finalize() {
|
||||||
|
const uintptr_t final_address = this->next_address;
|
||||||
this->next_address = Null<uintptr_t>;
|
this->next_address = Null<uintptr_t>;
|
||||||
|
return final_address;
|
||||||
}
|
}
|
||||||
public:
|
public:
|
||||||
virtual KPhysicalAddress Allocate() override {
|
virtual KPhysicalAddress Allocate() override {
|
||||||
|
@ -255,10 +257,10 @@ namespace ams::kern::init::loader {
|
||||||
/* We don't have ams::os, this may go in hw:: or something. */
|
/* We don't have ams::os, this may go in hw:: or something. */
|
||||||
const uintptr_t rx_offset = layout->rx_offset;
|
const uintptr_t rx_offset = layout->rx_offset;
|
||||||
const uintptr_t rx_end_offset = layout->rx_end_offset;
|
const uintptr_t rx_end_offset = layout->rx_end_offset;
|
||||||
const uintptr_t ro_offset = layout->rx_offset;
|
const uintptr_t ro_offset = layout->ro_offset;
|
||||||
const uintptr_t ro_end_offset = layout->ro_end_offset;
|
const uintptr_t ro_end_offset = layout->ro_end_offset;
|
||||||
const uintptr_t rw_offset = layout->rx_offset;
|
const uintptr_t rw_offset = layout->rw_offset;
|
||||||
const uintptr_t rw_end_offset = layout->rw_end_offset;
|
/* UNUSED: const uintptr_t rw_end_offset = layout->rw_end_offset; */
|
||||||
const uintptr_t bss_end_offset = layout->bss_end_offset;
|
const uintptr_t bss_end_offset = layout->bss_end_offset;
|
||||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(rx_offset, 0x1000));
|
MESOSPHERE_ABORT_UNLESS(util::IsAligned(rx_offset, 0x1000));
|
||||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(rx_end_offset, 0x1000));
|
MESOSPHERE_ABORT_UNLESS(util::IsAligned(rx_end_offset, 0x1000));
|
||||||
|
@ -315,7 +317,7 @@ namespace ams::kern::init::loader {
|
||||||
ttbr1_table.Map(virtual_base_address + rw_offset, bss_end_offset - rw_offset, base_address + rw_offset, KernelRwDataAttribute, g_initial_page_allocator);
|
ttbr1_table.Map(virtual_base_address + rw_offset, bss_end_offset - rw_offset, base_address + rw_offset, KernelRwDataAttribute, g_initial_page_allocator);
|
||||||
|
|
||||||
/* Clear kernel .bss. */
|
/* Clear kernel .bss. */
|
||||||
std::memset(GetVoidPointer(virtual_base_address + bss_offset), 0, bss_end_offset - rw_end_offset);
|
std::memset(GetVoidPointer(virtual_base_address + bss_offset), 0, bss_end_offset - bss_offset);
|
||||||
|
|
||||||
/* Apply relocations to the kernel. */
|
/* Apply relocations to the kernel. */
|
||||||
const Elf::Elf64::Dyn *kernel_dynamic = reinterpret_cast<const Elf::Elf64::Dyn *>(GetInteger(virtual_base_address) + dynamic_offset);
|
const Elf::Elf64::Dyn *kernel_dynamic = reinterpret_cast<const Elf::Elf64::Dyn *>(GetInteger(virtual_base_address) + dynamic_offset);
|
||||||
|
@ -331,8 +333,8 @@ namespace ams::kern::init::loader {
|
||||||
return GetInteger(virtual_base_address) - base_address;
|
return GetInteger(virtual_base_address) - base_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Finalize() {
|
uintptr_t Finalize() {
|
||||||
g_initial_page_allocator.Finalize();
|
return g_initial_page_allocator.Finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -78,6 +78,9 @@ _start:
|
||||||
/* Call ams::kern::init::loader::Finalize() */
|
/* Call ams::kern::init::loader::Finalize() */
|
||||||
bl _ZN3ams4kern4init6loader8FinalizeEv
|
bl _ZN3ams4kern4init6loader8FinalizeEv
|
||||||
|
|
||||||
|
/* X0 is now the next address for the page allocator. */
|
||||||
|
/* We will return this to the kernel. */
|
||||||
|
|
||||||
/* Return to the newly-relocated kernel. */
|
/* Return to the newly-relocated kernel. */
|
||||||
ldr x1, [sp, #0x18] /* Return address to Kernel */
|
ldr x1, [sp, #0x18] /* Return address to Kernel */
|
||||||
ldr x2, [sp, #0x00] /* Relocated kernel base address diff. */
|
ldr x2, [sp, #0x00] /* Relocated kernel base address diff. */
|
||||||
|
|
Loading…
Reference in a new issue