mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
mesosphere: Implement kernelldr through first page table mapping
This commit is contained in:
parent
b5becba8ff
commit
2866cb5fe6
24 changed files with 1520 additions and 8 deletions
|
@ -4,7 +4,7 @@
|
|||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Declare the exception vector table, enforcing it is aligned on a
|
||||
|
@ -92,7 +92,7 @@ vector_entry fiq_spx
|
|||
vector_entry serror_spx
|
||||
b unknown_exception
|
||||
check_vector_size serror_spx
|
||||
|
||||
|
||||
/* Lower EL, A64 */
|
||||
vector_entry synch_a64
|
||||
stp x29, x30, [sp, #-0x10]!
|
||||
|
|
|
@ -23,6 +23,13 @@
|
|||
|
||||
/* Primitive types. */
|
||||
#include "mesosphere/kern_k_typed_address.hpp"
|
||||
#include "mesosphere/kern_initial_process.hpp"
|
||||
|
||||
/* Initialization headers. */
|
||||
#include "mesosphere/init/kern_init_elf.hpp"
|
||||
#include "mesosphere/init/kern_init_layout.hpp"
|
||||
#include "mesosphere/init/kern_init_page_table_select.hpp"
|
||||
|
||||
/* Core functionality. */
|
||||
#include "mesosphere/kern_select_interrupts.hpp"
|
||||
#include "mesosphere/kern_select_k_system_control.hpp"
|
||||
|
|
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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/>.
|
||||
*/
|
||||
/*
|
||||
From musl include/elf.h
|
||||
|
||||
Copyright © 2005-2014 Rich Felker, et al.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::kern::init::Elf::Elf64 {
|
||||
|
||||
/* Type declarations required to perform relocations */
|
||||
using Half = u16;
|
||||
using Word = u32;
|
||||
using Sword = s32;
|
||||
using Xword = u64;
|
||||
using SXword = s64;
|
||||
|
||||
using Addr = u64;
|
||||
using Off = u64;
|
||||
|
||||
class Dyn {
|
||||
private:
|
||||
SXword tag;
|
||||
union {
|
||||
Xword value;
|
||||
Addr ptr;
|
||||
};
|
||||
public:
|
||||
constexpr ALWAYS_INLINE SXword GetTag() const {
|
||||
return this->tag;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE Xword GetValue() const {
|
||||
return this->value;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE Addr GetPtr() const {
|
||||
return this->ptr;
|
||||
}
|
||||
};
|
||||
|
||||
class Rel {
|
||||
private:
|
||||
Addr offset;
|
||||
Xword info;
|
||||
public:
|
||||
constexpr ALWAYS_INLINE Addr GetOffset() const {
|
||||
return this->offset;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE Xword GetSym() const {
|
||||
return this->info >> 32;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE Xword GetType() const {
|
||||
return this->info & 0xFFFFFFFF;
|
||||
}
|
||||
};
|
||||
|
||||
class Rela {
|
||||
private:
|
||||
Addr offset;
|
||||
Xword info;
|
||||
SXword addend;
|
||||
public:
|
||||
constexpr ALWAYS_INLINE Addr GetOffset() const {
|
||||
return this->offset;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE Xword GetSym() const {
|
||||
return this->info >> 32;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE Xword GetType() const {
|
||||
return this->info & 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE SXword GetAddend() const {
|
||||
return this->addend;
|
||||
}
|
||||
};
|
||||
|
||||
enum DynamicTag {
|
||||
DT_NULL = 0,
|
||||
DT_RELA = 7,
|
||||
DT_RELAENT = 9,
|
||||
DT_REL = 17,
|
||||
DT_RELENT = 19,
|
||||
|
||||
DT_RELACOUNT = 0x6ffffff9,
|
||||
DT_RELCOUNT = 0x6ffffffa
|
||||
};
|
||||
|
||||
enum RelocationType {
|
||||
R_AARCH64_RELATIVE = 0x403,
|
||||
};
|
||||
|
||||
/* API to apply relocations or call init array. */
|
||||
void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic);
|
||||
void CallInitArrayFuncs(uintptr_t init_array_start, uintptr_t init_array_end);
|
||||
|
||||
}
|
|
@ -0,0 +1,312 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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/>.
|
||||
*/
|
||||
/*
|
||||
From musl include/elf.h
|
||||
|
||||
Copyright © 2005-2014 Rich Felker, et al.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
#include <mesosphere/kern_panic.hpp>
|
||||
#include <mesosphere/kern_k_typed_address.hpp>
|
||||
#include "../kern_hardware_registers.hpp"
|
||||
|
||||
namespace ams::kern::init {
|
||||
|
||||
constexpr size_t PageSize = 0x1000;
|
||||
constexpr size_t L1BlockSize = 0x40000000;
|
||||
constexpr size_t L2BlockSize = 0x200000;
|
||||
constexpr size_t L2ContiguousBlockSize = 0x10 * L2BlockSize;
|
||||
constexpr size_t L3BlockSize = 0x1000;
|
||||
constexpr size_t L3ContiguousBlockSize = 0x10 * L3BlockSize;
|
||||
|
||||
class PageTableEntry {
|
||||
public:
|
||||
enum Permission : u64 {
|
||||
Permission_KernelRWX = ((0ul << 53) | (1ul << 54) | (0ul << 6)),
|
||||
Permission_KernelRX = ((0ul << 53) | (1ul << 54) | (2ul << 6)),
|
||||
Permission_KernelR = ((1ul << 53) | (1ul << 54) | (2ul << 6)),
|
||||
Permission_KernelRW = ((1ul << 53) | (1ul << 54) | (0ul << 6)),
|
||||
|
||||
Permission_UserRX = ((1ul << 53) | (0ul << 54) | (3ul << 6)),
|
||||
Permission_UserR = ((1ul << 53) | (1ul << 54) | (3ul << 6)),
|
||||
Permission_UserRW = ((1ul << 53) | (1ul << 54) | (1ul << 6)),
|
||||
};
|
||||
|
||||
enum Shareable : u64 {
|
||||
Shareable_NonShareable = (0 << 8),
|
||||
Shareable_OuterShareable = (2 << 8),
|
||||
Shareable_InnerShareable = (3 << 8),
|
||||
};
|
||||
|
||||
/* Official attributes are: */
|
||||
/* 0x00, 0x04, 0xFF, 0x44. 4-7 are unused. */
|
||||
enum PageAttribute : u64 {
|
||||
PageAttribute_Device_nGnRnE = (0 << 2),
|
||||
PageAttribute_Device_nGnRE = (1 << 2),
|
||||
PageAttribute_NormalMemory = (2 << 2),
|
||||
PageAttribute_NormalMemoryNotCacheable = (3 << 2),
|
||||
};
|
||||
|
||||
enum AccessFlag : u64 {
|
||||
AccessFlag_NotAccessed = (0 << 10),
|
||||
AccessFlag_Accessed = (1 << 10),
|
||||
};
|
||||
protected:
|
||||
u64 attributes;
|
||||
public:
|
||||
/* Take in a raw attribute. */
|
||||
constexpr ALWAYS_INLINE PageTableEntry(u64 attr) : attributes(attr) { /* ... */ }
|
||||
|
||||
/* Extend a previous attribute. */
|
||||
constexpr ALWAYS_INLINE PageTableEntry(const PageTableEntry &rhs, u64 new_attr) : attributes(rhs.attributes | new_attr) { /* ... */ }
|
||||
|
||||
/* Construct a new attribute. */
|
||||
constexpr ALWAYS_INLINE PageTableEntry(Permission perm, PageAttribute p_a, Shareable share)
|
||||
: attributes(static_cast<u64>(perm) | static_cast<u64>(AccessFlag_Accessed) | static_cast<u64>(p_a) | static_cast<u64>(share))
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
protected:
|
||||
constexpr ALWAYS_INLINE u64 GetBits(size_t offset, size_t count) const {
|
||||
return (this->attributes >> offset) & ((1 << count) - 1);
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE u64 SelectBits(size_t offset, size_t count) const {
|
||||
return this->attributes & (((1 << count) - 1) << offset);
|
||||
}
|
||||
public:
|
||||
constexpr ALWAYS_INLINE bool IsUserExecuteNever() const { return this->GetBits(54, 1) != 0; }
|
||||
constexpr ALWAYS_INLINE bool IsPrivilegedExecuteNever() const { return this->GetBits(53, 1) != 0; }
|
||||
constexpr ALWAYS_INLINE bool IsContiguous() const { return this->GetBits(52, 1) != 0; }
|
||||
constexpr ALWAYS_INLINE AccessFlag GetAccessFlag() const { return static_cast<AccessFlag>(this->GetBits(10, 1)); }
|
||||
constexpr ALWAYS_INLINE Shareable GetShareable() const { return static_cast<Shareable>(this->GetBits(8, 2)); }
|
||||
constexpr ALWAYS_INLINE PageAttribute GetPageAttribute() const { return static_cast<PageAttribute>(this->GetBits(2, 3)); }
|
||||
constexpr ALWAYS_INLINE bool IsNonSecure() const { return this->GetBits(5, 1) != 0; }
|
||||
constexpr ALWAYS_INLINE bool IsBlock() const { return this->GetBits(0, 2) == 0x1; }
|
||||
constexpr ALWAYS_INLINE bool IsTable() const { return this->GetBits(0, 2) == 0x3; }
|
||||
};
|
||||
|
||||
static_assert(sizeof(PageTableEntry) == sizeof(u64));
|
||||
|
||||
constexpr size_t MaxPageTableEntries = PageSize / sizeof(PageTableEntry);
|
||||
|
||||
class L1PageTableEntry : public PageTableEntry {
|
||||
public:
|
||||
constexpr ALWAYS_INLINE L1PageTableEntry(KPhysicalAddress phys_addr, bool pxn)
|
||||
: PageTableEntry((0x3ul << 60) | (static_cast<u64>(pxn) << 59) | GetInteger(phys_addr) | 0x3)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
constexpr ALWAYS_INLINE L1PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
|
||||
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x1)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE KPhysicalAddress GetBlock() const {
|
||||
return this->SelectBits(30, 18);
|
||||
}
|
||||
constexpr ALWAYS_INLINE KPhysicalAddress GetTable() const {
|
||||
return this->SelectBits(12, 36);
|
||||
}
|
||||
};
|
||||
|
||||
class L2PageTableEntry : public PageTableEntry {
|
||||
public:
|
||||
constexpr ALWAYS_INLINE L2PageTableEntry(KPhysicalAddress phys_addr, bool pxn)
|
||||
: PageTableEntry((0x3ul << 60) | (static_cast<u64>(pxn) << 59) | GetInteger(phys_addr) | 0x3)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
constexpr ALWAYS_INLINE L2PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
|
||||
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x1)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE KPhysicalAddress GetBlock() const {
|
||||
return this->SelectBits(21, 27);
|
||||
}
|
||||
constexpr ALWAYS_INLINE KPhysicalAddress GetTable() const {
|
||||
return this->SelectBits(12, 36);
|
||||
}
|
||||
};
|
||||
|
||||
class L3PageTableEntry : public PageTableEntry {
|
||||
public:
|
||||
constexpr ALWAYS_INLINE L3PageTableEntry(KPhysicalAddress phys_addr, const PageTableEntry &attr, bool contig)
|
||||
: PageTableEntry(attr, (static_cast<u64>(contig) << 52) | GetInteger(phys_addr) | 0x1)
|
||||
{
|
||||
/* ... */
|
||||
}
|
||||
|
||||
constexpr ALWAYS_INLINE KPhysicalAddress GetBlock() const {
|
||||
return this->SelectBits(21, 27);
|
||||
}
|
||||
constexpr ALWAYS_INLINE KPhysicalAddress GetTable() const {
|
||||
return this->SelectBits(12, 36);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class KInitialPageTable {
|
||||
public:
|
||||
class IPageAllocator {
|
||||
public:
|
||||
virtual KPhysicalAddress Allocate() { return Null<KPhysicalAddress>; }
|
||||
virtual void Free(KPhysicalAddress phys_addr) { /* Nothing to do here. */ (void)(phys_addr); }
|
||||
};
|
||||
private:
|
||||
KPhysicalAddress l1_table;
|
||||
public:
|
||||
constexpr ALWAYS_INLINE KInitialPageTable(KPhysicalAddress l1) : l1_table(l1) {
|
||||
ClearNewPageTable(this->l1_table);
|
||||
}
|
||||
private:
|
||||
static constexpr ALWAYS_INLINE L1PageTableEntry *GetL1Entry(KPhysicalAddress _l1_table, KVirtualAddress address) {
|
||||
L1PageTableEntry *l1_table = reinterpret_cast<L1PageTableEntry *>(GetInteger(_l1_table));
|
||||
return l1_table + ((GetInteger(address) >> 30) & (MaxPageTableEntries - 1));
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE L2PageTableEntry *GetL2Entry(const L1PageTableEntry *entry, KVirtualAddress address) {
|
||||
L2PageTableEntry *l2_table = reinterpret_cast<L2PageTableEntry *>(GetInteger(entry->GetTable()));
|
||||
return l2_table + ((GetInteger(address) >> 21) & (MaxPageTableEntries - 1));
|
||||
}
|
||||
|
||||
static constexpr ALWAYS_INLINE L3PageTableEntry *GetL3Entry(const L2PageTableEntry *entry, KVirtualAddress address) {
|
||||
L3PageTableEntry *l3_table = reinterpret_cast<L3PageTableEntry *>(GetInteger(entry->GetTable()));
|
||||
return l3_table + ((GetInteger(address) >> 12) & (MaxPageTableEntries - 1));
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address) {
|
||||
/* This Physical Address -> void * conversion is valid, because this is page table code. */
|
||||
/* The MMU is necessarily not yet turned on, if we are creating an initial page table. */
|
||||
std::memset(reinterpret_cast<void *>(GetInteger(address)), 0, PageSize);
|
||||
}
|
||||
public:
|
||||
void Map(KVirtualAddress virt_addr, size_t size, KPhysicalAddress phys_addr, const PageTableEntry &attr, IPageAllocator &allocator) {
|
||||
/* Ensure that addresses and sizes are page aligned. */
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(virt_addr), PageSize));
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(GetInteger(phys_addr), PageSize));
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(size, PageSize));
|
||||
|
||||
/* Iteratively map pages until the requested region is mapped. */
|
||||
while (size > 0) {
|
||||
L1PageTableEntry *l1_entry = GetL1Entry(this->l1_table, virt_addr);
|
||||
|
||||
/* Can we make an L1 block? */
|
||||
if (util::IsAligned(GetInteger(virt_addr), L1BlockSize) && util::IsAligned(GetInteger(phys_addr), L1BlockSize) && util::IsAligned(size, L1BlockSize)) {
|
||||
*l1_entry = L1PageTableEntry(phys_addr, attr, false);
|
||||
/* TODO: DataSynchronizationBarrier */
|
||||
virt_addr += L1BlockSize;
|
||||
phys_addr += L1BlockSize;
|
||||
size -= L1BlockSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we don't already have an L2 table, we need to make a new one. */
|
||||
if (!l1_entry->IsTable()) {
|
||||
KPhysicalAddress new_table = allocator.Allocate();
|
||||
ClearNewPageTable(new_table);
|
||||
*l1_entry = L1PageTableEntry(phys_addr, attr.IsPrivilegedExecuteNever());
|
||||
}
|
||||
|
||||
L2PageTableEntry *l2_entry = GetL2Entry(l1_entry, virt_addr);
|
||||
|
||||
/* Can we make a contiguous L2 block? */
|
||||
if (util::IsAligned(GetInteger(virt_addr), L2ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L2ContiguousBlockSize) && util::IsAligned(size, L2ContiguousBlockSize)) {
|
||||
for (size_t i = 0; i < L2ContiguousBlockSize / L2BlockSize; i++) {
|
||||
l2_entry[i] = L2PageTableEntry(phys_addr, attr, true);
|
||||
/* TODO: DataSynchronizationBarrier */
|
||||
virt_addr += L2ContiguousBlockSize;
|
||||
phys_addr += L2ContiguousBlockSize;
|
||||
size -= L2ContiguousBlockSize;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Can we make an L2 block? */
|
||||
if (util::IsAligned(GetInteger(virt_addr), L2BlockSize) && util::IsAligned(GetInteger(phys_addr), L2BlockSize) && util::IsAligned(size, L2BlockSize)) {
|
||||
*l2_entry = L2PageTableEntry(phys_addr, attr, false);
|
||||
/* TODO: DataSynchronizationBarrier */
|
||||
virt_addr += L2BlockSize;
|
||||
phys_addr += L2BlockSize;
|
||||
size -= L2BlockSize;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* If we don't already have an L3 table, we need to make a new one. */
|
||||
if (!l2_entry->IsTable()) {
|
||||
KPhysicalAddress new_table = allocator.Allocate();
|
||||
ClearNewPageTable(new_table);
|
||||
*l2_entry = L2PageTableEntry(phys_addr, attr.IsPrivilegedExecuteNever());
|
||||
}
|
||||
|
||||
L3PageTableEntry *l3_entry = GetL3Entry(l2_entry, virt_addr);
|
||||
|
||||
/* Can we make a contiguous L3 block? */
|
||||
if (util::IsAligned(GetInteger(virt_addr), L3ContiguousBlockSize) && util::IsAligned(GetInteger(phys_addr), L3ContiguousBlockSize) && util::IsAligned(size, L3ContiguousBlockSize)) {
|
||||
for (size_t i = 0; i < L3ContiguousBlockSize / L3BlockSize; i++) {
|
||||
l3_entry[i] = L3PageTableEntry(phys_addr, attr, true);
|
||||
/* TODO: DataSynchronizationBarrier */
|
||||
virt_addr += L3ContiguousBlockSize;
|
||||
phys_addr += L3ContiguousBlockSize;
|
||||
size -= L3ContiguousBlockSize;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Make an L3 block. */
|
||||
*l3_entry = L3PageTableEntry(phys_addr, attr, false);
|
||||
/* TODO: DataSynchronizationBarrier */
|
||||
virt_addr += L3BlockSize;
|
||||
phys_addr += L3BlockSize;
|
||||
size -= L3BlockSize;
|
||||
}
|
||||
}
|
||||
|
||||
bool IsFree(KVirtualAddress virt_addr, size_t size) {
|
||||
/* TODO */
|
||||
return false;
|
||||
}
|
||||
|
||||
void ReprotectFromReadWriteToRead(KVirtualAddress virt_addr, size_t size) {
|
||||
/* TODO */
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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/>.
|
||||
*/
|
||||
/*
|
||||
From musl include/elf.h
|
||||
|
||||
Copyright © 2005-2014 Rich Felker, et al.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
#include <vapours.hpp>
|
||||
|
||||
namespace ams::kern::hw {
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -21,6 +21,10 @@ namespace ams::kern {
|
|||
class KSystemControl {
|
||||
public:
|
||||
|
||||
/* Initialization. */
|
||||
static KPhysicalAddress GetKernelPhysicalBaseAddress(uintptr_t base_address);
|
||||
static bool ShouldIncreaseResourceRegionSize();
|
||||
|
||||
/* Panic. */
|
||||
static NORETURN void StopSystem();
|
||||
};
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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 <vapours.hpp>
|
||||
|
||||
#ifdef ATMOSPHERE_ARCH_ARM64
|
||||
|
||||
#include "../arch/arm64/init/kern_init_elf64.hpp"
|
||||
|
||||
#else
|
||||
|
||||
#error "Unknown Architecture"
|
||||
|
||||
#endif
|
||||
|
||||
namespace ams::kern::init::Elf {
|
||||
|
||||
/* TODO: Anything we want inside this namespace? */
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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 <vapours.hpp>
|
||||
|
||||
namespace ams::kern::init {
|
||||
|
||||
struct KernelLayout {
|
||||
u32 rx_offset;
|
||||
u32 rx_end_offset;
|
||||
u32 ro_offset;
|
||||
u32 ro_end_offset;
|
||||
u32 rw_offset;
|
||||
u32 rw_end_offset;
|
||||
u32 bss_offset;
|
||||
u32 bss_end_offset;
|
||||
u32 ini_end_offset;
|
||||
u32 dynamic_end_offset;
|
||||
u32 init_array_offset;
|
||||
u32 init_array_end_offset;
|
||||
};
|
||||
static_assert(std::is_pod<KernelLayout>::value);
|
||||
static_assert(sizeof(KernelLayout) == 0x30);
|
||||
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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
|
||||
|
||||
#ifdef ATMOSPHERE_ARCH_ARM64
|
||||
#include "../arch/arm64/init/kern_k_init_page_table.hpp"
|
||||
#else
|
||||
#error "Unknown architecutre for KInitialPageTable"
|
||||
#endif
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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 <vapours.hpp>
|
||||
#include "kern_panic.hpp"
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
constexpr u32 InitialProcessBinaryMagic = util::FourCC<'I','N','I','1'>::Code;
|
||||
constexpr size_t InitialProcessBinarySizeMax = 0xC00000;
|
||||
|
||||
struct InitialProcessBinaryHeader {
|
||||
u32 magic;
|
||||
u32 size;
|
||||
u32 num_processes;
|
||||
u32 reserved;
|
||||
};
|
||||
|
||||
}
|
|
@ -32,7 +32,7 @@ namespace ams::kern {
|
|||
#ifdef MESOSPHERE_ENABLE_ASSERTIONS
|
||||
#define MESOSPHERE_ASSERT_IMPL(expr, ...) \
|
||||
({ \
|
||||
if (AMS_UNLIKELY(!expr)) { \
|
||||
if (AMS_UNLIKELY(!(expr))) { \
|
||||
MESOSPHERE_PANIC(__VA_ARGS__); \
|
||||
} \
|
||||
})
|
||||
|
@ -47,7 +47,7 @@ namespace ams::kern {
|
|||
|
||||
#define MESOSPHERE_ABORT_UNLESS(expr) \
|
||||
({ \
|
||||
if (AMS_UNLIKELY(!expr)) { \
|
||||
if (AMS_UNLIKELY(!(expr))) { \
|
||||
MESOSPHERE_PANIC("Abort(): %s", #expr); \
|
||||
} \
|
||||
})
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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 <vapours.hpp>
|
||||
#include "kern_panic.hpp"
|
||||
|
||||
namespace ams::kern {
|
||||
|
||||
/* TODO: Actually select between architecture-specific interrupt code. */
|
||||
|
||||
|
||||
/* Enable or disable interrupts for the lifetime of an object. */
|
||||
class KScopedInterruptDisable {
|
||||
NON_COPYABLE(KScopedInterruptDisable);
|
||||
NON_MOVEABLE(KScopedInterruptDisable);
|
||||
public:
|
||||
KScopedInterruptDisable();
|
||||
~KScopedInterruptDisable();
|
||||
};
|
||||
|
||||
class KScopedInterruptEnable {
|
||||
NON_COPYABLE(KScopedInterruptEnable);
|
||||
NON_MOVEABLE(KScopedInterruptEnable);
|
||||
public:
|
||||
KScopedInterruptEnable();
|
||||
~KScopedInterruptEnable();
|
||||
};
|
||||
|
||||
}
|
|
@ -19,4 +19,4 @@
|
|||
#include "board/nintendo/switch/kern_k_system_control.hpp"
|
||||
#else
|
||||
#error "Unknown board for KSystemControl"
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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::init::Elf::Elf64 {
|
||||
|
||||
/* API to apply relocations or call init array. */
|
||||
void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic) {
|
||||
uintptr_t dyn_rel = 0;
|
||||
uintptr_t dyn_rela = 0;
|
||||
uintptr_t rel_count = 0;
|
||||
uintptr_t rela_count = 0;
|
||||
uintptr_t rel_ent = 0;
|
||||
uintptr_t rela_ent = 0;
|
||||
|
||||
/* Iterate over all tags, identifying important extents. */
|
||||
for (const Dyn *cur_entry = dynamic; cur_entry->GetTag() != DT_NULL; cur_entry++) {
|
||||
switch (cur_entry->GetTag()) {
|
||||
case DT_REL:
|
||||
dyn_rel = base_address + cur_entry->GetPtr();
|
||||
break;
|
||||
case DT_RELA:
|
||||
dyn_rela = base_address + cur_entry->GetPtr();
|
||||
break;
|
||||
case DT_RELENT:
|
||||
rel_ent = cur_entry->GetValue();
|
||||
break;
|
||||
case DT_RELAENT:
|
||||
rela_ent = cur_entry->GetValue();
|
||||
break;
|
||||
case DT_RELCOUNT:
|
||||
rel_count = cur_entry->GetValue();
|
||||
break;
|
||||
case DT_RELACOUNT:
|
||||
rela_count = cur_entry->GetValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply all Rel relocations */
|
||||
for (size_t i = 0; i < rel_count; i++) {
|
||||
const auto &rel = *reinterpret_cast<const Elf64::Rel *>(dyn_rel + rel_ent * i);
|
||||
|
||||
/* Only allow R_AARCH64_RELATIVE relocations. */
|
||||
while (rel.GetType() != R_AARCH64_RELATIVE) { /* ... */ }
|
||||
|
||||
/* Apply the relocation. */
|
||||
Elf64::Addr *target_address = reinterpret_cast<Elf64::Addr *>(base_address + rel.GetOffset());
|
||||
*target_address += base_address;
|
||||
}
|
||||
|
||||
/* Apply all Rela relocations. */
|
||||
for (size_t i = 0; i < rela_count; i++) {
|
||||
const auto &rela = *reinterpret_cast<const Elf64::Rela *>(dyn_rela + rela_ent * i);
|
||||
|
||||
/* Only allow R_AARCH64_RELATIVE relocations. */
|
||||
while (rela.GetType() != R_AARCH64_RELATIVE) { /* ... */ }
|
||||
|
||||
/* Apply the relocation. */
|
||||
Elf64::Addr *target_address = reinterpret_cast<Elf64::Addr *>(base_address + rela.GetOffset());
|
||||
*target_address = base_address + rela.GetAddend();
|
||||
}
|
||||
}
|
||||
|
||||
void CallInitArrayFuncs(uintptr_t init_array_start, uintptr_t init_array_end) {
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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::init::Elf::Elf64 {
|
||||
|
||||
/* API to apply relocations or call init array. */
|
||||
void ApplyRelocations(uintptr_t base_address, const Dyn *dynamic) {
|
||||
uintptr_t dyn_rel = 0;
|
||||
uintptr_t dyn_rela = 0;
|
||||
uintptr_t rel_count = 0;
|
||||
uintptr_t rela_count = 0;
|
||||
uintptr_t rel_ent = 0;
|
||||
uintptr_t rela_ent = 0;
|
||||
|
||||
/* Iterate over all tags, identifying important extents. */
|
||||
for (const Dyn *cur_entry = dynamic; cur_entry->GetTag() != DT_NULL; cur_entry++) {
|
||||
switch (cur_entry->GetTag()) {
|
||||
case DT_REL:
|
||||
dyn_rel = base_address + cur_entry->GetPtr();
|
||||
break;
|
||||
case DT_RELA:
|
||||
dyn_rela = base_address + cur_entry->GetPtr();
|
||||
break;
|
||||
case DT_RELENT:
|
||||
rel_ent = cur_entry->GetValue();
|
||||
break;
|
||||
case DT_RELAENT:
|
||||
rela_ent = cur_entry->GetValue();
|
||||
break;
|
||||
case DT_RELCOUNT:
|
||||
rel_count = cur_entry->GetValue();
|
||||
break;
|
||||
case DT_RELACOUNT:
|
||||
rela_count = cur_entry->GetValue();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Apply all Rel relocations */
|
||||
for (size_t i = 0; i < rel_count; i++) {
|
||||
const auto &rel = *reinterpret_cast<const Elf64::Rel *>(dyn_rel + rel_ent * i);
|
||||
|
||||
/* Only allow R_AARCH64_RELATIVE relocations. */
|
||||
while (rel.GetType() != R_AARCH64_RELATIVE) { /* ... */ }
|
||||
|
||||
/* Apply the relocation. */
|
||||
Elf64::Addr *target_address = reinterpret_cast<Elf64::Addr *>(base_address + rel.GetOffset());
|
||||
*target_address += base_address;
|
||||
}
|
||||
|
||||
/* Apply all Rela relocations. */
|
||||
for (size_t i = 0; i < rela_count; i++) {
|
||||
const auto &rela = *reinterpret_cast<const Elf64::Rela *>(dyn_rela + rela_ent * i);
|
||||
|
||||
/* Only allow R_AARCH64_RELATIVE relocations. */
|
||||
while (rela.GetType() != R_AARCH64_RELATIVE) { /* ... */ }
|
||||
|
||||
/* Apply the relocation. */
|
||||
Elf64::Addr *target_address = reinterpret_cast<Elf64::Addr *>(base_address + rela.GetOffset());
|
||||
*target_address = base_address + rela.GetAddend();
|
||||
}
|
||||
}
|
||||
|
||||
void CallInitArrayFuncs(uintptr_t init_array_start, uintptr_t init_array_end) {
|
||||
for (uintptr_t cur_entry = init_array_start; cur_entry < init_array_end; cur_entry += sizeof(void *)) {
|
||||
(*(void (**)())(cur_entry))();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -18,8 +18,64 @@
|
|||
|
||||
namespace ams::kern {
|
||||
|
||||
namespace {
|
||||
|
||||
/* Convenience definitions. */
|
||||
constexpr size_t FourGigabytes = 0x100000000ul;
|
||||
constexpr size_t SixGigabytes = 0x180000000ul;
|
||||
constexpr size_t EightGigabytes = 0x200000000ul;
|
||||
|
||||
size_t GetRealMemorySize() {
|
||||
/* TODO: Move this into a header for the MC in general. */
|
||||
constexpr u32 MemoryControllerConfigurationRegister = 0x70019050;
|
||||
u32 config_value;
|
||||
MESOSPHERE_ABORT_UNLESS(smc::ReadWriteRegister(&config_value, MemoryControllerConfigurationRegister, 0, 0));
|
||||
return static_cast<size_t>(config_value & 0x3FFF) << 20;
|
||||
}
|
||||
|
||||
inline u64 GetKernelConfiguration() {
|
||||
u64 value = 0;
|
||||
smc::GetConfig(&value, 1, smc::ConfigItem::KernelConfiguration);
|
||||
return value;
|
||||
}
|
||||
|
||||
inline smc::MemoryMode GetMemoryMode() {
|
||||
return static_cast<smc::MemoryMode>((GetKernelConfiguration() >> 10) & 0x3);
|
||||
}
|
||||
|
||||
size_t GetIntendedMemorySize() {
|
||||
const smc::MemoryMode memory_mode = GetMemoryMode();
|
||||
switch (memory_mode) {
|
||||
case smc::MemoryMode_4GB:
|
||||
default: /* All invalid modes should go to 4GB. */
|
||||
return FourGigabytes;
|
||||
case smc::MemoryMode_6GB:
|
||||
return SixGigabytes;
|
||||
case smc::MemoryMode_8GB:
|
||||
return EightGigabytes;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/* Initialization. */
|
||||
KPhysicalAddress KSystemControl::GetKernelPhysicalBaseAddress(uintptr_t base_address) {
|
||||
const size_t real_dram_size = GetRealMemorySize();
|
||||
const size_t intended_dram_size = GetIntendedMemorySize();
|
||||
if (intended_dram_size * 2 < real_dram_size) {
|
||||
return base_address;
|
||||
} else {
|
||||
return base_address + ((real_dram_size - intended_dram_size) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
bool KSystemControl::ShouldIncreaseResourceRegionSize() {
|
||||
return (GetKernelConfiguration() >> 3) & 1;
|
||||
}
|
||||
|
||||
void KSystemControl::StopSystem() {
|
||||
/* TODO: smc::Panic(0xF00); */
|
||||
/* Display a panic screen via exosphere. */
|
||||
smc::Panic(0xF00);
|
||||
while (true) { /* ... */ }
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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>
|
||||
#include "kern_secure_monitor.hpp"
|
||||
|
||||
namespace ams::kern::smc {
|
||||
|
||||
namespace {
|
||||
|
||||
struct SecureMonitorArguments {
|
||||
u64 x[8];
|
||||
};
|
||||
|
||||
enum FunctionId : u32 {
|
||||
FunctionId_CpuSuspend = 0xC4000001,
|
||||
FunctionId_CpuOff = 0x84000002,
|
||||
FunctionId_CpuOn = 0xC4000003,
|
||||
FunctionId_GetConfig = 0xC3000004,
|
||||
FunctionId_GenerateRandomBytes = 0xC3000005,
|
||||
FunctionId_Panic = 0xC3000006,
|
||||
FunctionId_ConfigureCarveout = 0xC3000007,
|
||||
FunctionId_ReadWriteRegister = 0xC3000008,
|
||||
};
|
||||
|
||||
void CallPrivilegedSecureMonitorFunction(SecureMonitorArguments &args) {
|
||||
/* Load arguments into registers. */
|
||||
register u64 x0 asm("x0") = args.x[0];
|
||||
register u64 x1 asm("x1") = args.x[1];
|
||||
register u64 x2 asm("x2") = args.x[2];
|
||||
register u64 x3 asm("x3") = args.x[3];
|
||||
register u64 x4 asm("x4") = args.x[4];
|
||||
register u64 x5 asm("x5") = args.x[5];
|
||||
register u64 x6 asm("x6") = args.x[6];
|
||||
register u64 x7 asm("x7") = args.x[7];
|
||||
|
||||
/* Actually make the call. */
|
||||
{
|
||||
/* Disable interrupts while making the call. */
|
||||
KScopedInterruptDisable intr_disable;
|
||||
__asm__ __volatile__("smc #1"
|
||||
: "+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"
|
||||
);
|
||||
/* TODO: Restore X18 */
|
||||
}
|
||||
|
||||
/* 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 GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
|
||||
SecureMonitorArguments args = { FunctionId_GetConfig, static_cast<u32>(config_item) };
|
||||
CallPrivilegedSecureMonitorFunction(args);
|
||||
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.x[0]) == SmcResult::Success));
|
||||
for (size_t i = 0; i < num_qwords && i < 7; i++) {
|
||||
out[i] = args.x[1 + i];
|
||||
}
|
||||
}
|
||||
|
||||
void NORETURN Panic(u32 color) {
|
||||
SecureMonitorArguments args = { FunctionId_Panic, color };
|
||||
CallPrivilegedSecureMonitorFunction(args);
|
||||
while (true) { /* ... */ }
|
||||
}
|
||||
|
||||
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value) {
|
||||
SecureMonitorArguments args = { FunctionId_ReadWriteRegister, address, mask, value };
|
||||
CallPrivilegedSecureMonitorFunction(args);
|
||||
*out = args.x[1];
|
||||
return static_cast<SmcResult>(args.x[0]) == SmcResult::Success;
|
||||
}
|
||||
|
||||
}
|
|
@ -18,6 +18,54 @@
|
|||
|
||||
namespace ams::kern::smc {
|
||||
|
||||
/* TODO: Secure Monitor API. */
|
||||
/* Types. */
|
||||
enum MemoryMode {
|
||||
MemoryMode_4GB = 0,
|
||||
MemoryMode_6GB = 1,
|
||||
MemoryMode_8GB = 2,
|
||||
};
|
||||
|
||||
enum class ConfigItem : u32 {
|
||||
/* Standard config items. */
|
||||
DisableProgramVerification = 1,
|
||||
DramId = 2,
|
||||
SecurityEngineIrqNumber = 3,
|
||||
Version = 4,
|
||||
HardwareType = 5,
|
||||
IsRetail = 6,
|
||||
IsRecoveryBoot = 7,
|
||||
DeviceId = 8,
|
||||
BootReason = 9,
|
||||
MemoryArrange = 10,
|
||||
IsDebugMode = 11,
|
||||
KernelConfiguration = 12,
|
||||
IsChargerHiZModeEnabled = 13,
|
||||
IsKiosk = 14,
|
||||
NewHardwareType = 15,
|
||||
NewKeyGeneration = 16,
|
||||
Package2Hash = 17,
|
||||
|
||||
/* Extension config items for exosphere. */
|
||||
ExosphereApiVersion = 65000,
|
||||
ExosphereNeedsReboot = 65001,
|
||||
ExosphereNeedsShutdown = 65002,
|
||||
ExosphereGitCommitHash = 65003,
|
||||
ExosphereHasRcmBugPatch = 65004,
|
||||
};
|
||||
|
||||
enum class SmcResult {
|
||||
Success = 0,
|
||||
NotImplemented = 1,
|
||||
InvalidArgument = 2,
|
||||
InProgress = 3,
|
||||
NoAsyncOperation = 4,
|
||||
InvalidAsyncOperation = 5,
|
||||
NotPermitted = 6,
|
||||
};
|
||||
|
||||
/* TODO: Rest of Secure Monitor API. */
|
||||
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item);
|
||||
void NORETURN Panic(u32 color);
|
||||
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value);
|
||||
|
||||
}
|
36
libraries/libmesosphere/source/kern_k_scoped_interrupt.cpp
Normal file
36
libraries/libmesosphere/source/kern_k_scoped_interrupt.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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 {
|
||||
|
||||
WEAK_SYMBOL KScopedInterruptDisable::KScopedInterruptDisable() {
|
||||
/* TODO: Disable interrupts. */
|
||||
}
|
||||
|
||||
WEAK_SYMBOL KScopedInterruptDisable::~KScopedInterruptDisable() {
|
||||
/* TODO: un-disable interrupts. */
|
||||
}
|
||||
|
||||
WEAK_SYMBOL KScopedInterruptEnable::KScopedInterruptEnable() {
|
||||
/* TODO: Enable interrupts. */
|
||||
}
|
||||
|
||||
WEAK_SYMBOL KScopedInterruptEnable::~KScopedInterruptEnable() {
|
||||
/* TODO: un-enable interrupts. */
|
||||
}
|
||||
|
||||
}
|
|
@ -49,6 +49,15 @@ SECTIONS
|
|||
. = ALIGN(8);
|
||||
} :krnlldr
|
||||
|
||||
/* .vectors. */
|
||||
. = ALIGN(2K);
|
||||
__vectors_start__ = . ;
|
||||
.vectors :
|
||||
{
|
||||
KEEP( *(.vectors) )
|
||||
. = ALIGN(8);
|
||||
} :krnlldr
|
||||
|
||||
/* =========== RODATA section =========== */
|
||||
. = ALIGN(8);
|
||||
__rodata_start = . ;
|
||||
|
@ -64,6 +73,7 @@ SECTIONS
|
|||
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } :krnlldr
|
||||
.gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } : rodata
|
||||
|
||||
__dynamic__start__ = . ;
|
||||
.dynamic : { *(.dynamic) } :krnlldr :dyn
|
||||
.dynsym : { *(.dynsym) } :krnlldr
|
||||
.dynstr : { *(.dynstr) } :krnlldr
|
||||
|
|
161
mesosphere/kernel_ldr/source/exceptions.s
Normal file
161
mesosphere/kernel_ldr/source/exceptions.s
Normal file
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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/>.
|
||||
*/
|
||||
|
||||
/* Some macros taken from https://github.com/ARM-software/arm-trusted-firmware/blob/master/include/common/aarch64/asm_macros.S */
|
||||
/*
|
||||
* Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
/*
|
||||
* Declare the exception vector table, enforcing it is aligned on a
|
||||
* 2KB boundary, as required by the ARMv8 architecture.
|
||||
* Use zero bytes as the fill value to be stored in the padding bytes
|
||||
* so that it inserts illegal AArch64 instructions. This increases
|
||||
* security, robustness and potentially facilitates debugging.
|
||||
*/
|
||||
.macro vector_base label, section_name=.vectors
|
||||
.section \section_name, "ax"
|
||||
.align 11, 0
|
||||
\label:
|
||||
.endm
|
||||
|
||||
/*
|
||||
* Create an entry in the exception vector table, enforcing it is
|
||||
* aligned on a 128-byte boundary, as required by the ARMv8 architecture.
|
||||
* Use zero bytes as the fill value to be stored in the padding bytes
|
||||
* so that it inserts illegal AArch64 instructions. This increases
|
||||
* security, robustness and potentially facilitates debugging.
|
||||
*/
|
||||
.macro vector_entry label, section_name=.vectors
|
||||
.cfi_sections .debug_frame
|
||||
.section \section_name, "ax"
|
||||
.align 7, 0
|
||||
.type \label, %function
|
||||
.func \label
|
||||
.cfi_startproc
|
||||
\label:
|
||||
.endm
|
||||
|
||||
/*
|
||||
* This macro verifies that the given vector doesnt exceed the
|
||||
* architectural limit of 32 instructions. This is meant to be placed
|
||||
* immediately after the last instruction in the vector. It takes the
|
||||
* vector entry as the parameter
|
||||
*/
|
||||
.macro check_vector_size since
|
||||
.endfunc
|
||||
.cfi_endproc
|
||||
.if (. - \since) > (32 * 4)
|
||||
.error "Vector exceeds 32 instructions"
|
||||
.endif
|
||||
.endm
|
||||
|
||||
/* Actual Vectors for KernelLdr. */
|
||||
.global kernelldr_vectors
|
||||
vector_base kernelldr_vectors
|
||||
|
||||
/* Current EL, SP0 */
|
||||
.global unknown_exception
|
||||
unknown_exception:
|
||||
vector_entry synch_sp0
|
||||
/* Just infinite loop. */
|
||||
b unknown_exception
|
||||
check_vector_size synch_sp0
|
||||
|
||||
vector_entry irq_sp0
|
||||
b unknown_exception
|
||||
check_vector_size irq_sp0
|
||||
|
||||
vector_entry fiq_sp0
|
||||
b unknown_exception
|
||||
check_vector_size fiq_sp0
|
||||
|
||||
vector_entry serror_sp0
|
||||
b unknown_exception
|
||||
check_vector_size serror_sp0
|
||||
|
||||
/* Current EL, SPx */
|
||||
vector_entry synch_spx
|
||||
b restore_tpidr_el1
|
||||
check_vector_size synch_spx
|
||||
|
||||
vector_entry irq_spx
|
||||
b unknown_exception
|
||||
check_vector_size irq_spx
|
||||
|
||||
vector_entry fiq_spx
|
||||
b unknown_exception
|
||||
check_vector_size fiq_spx
|
||||
|
||||
vector_entry serror_spx
|
||||
b unknown_exception
|
||||
check_vector_size serror_spx
|
||||
|
||||
/* Lower EL, A64 */
|
||||
vector_entry synch_a64
|
||||
b unknown_exception
|
||||
check_vector_size synch_a64
|
||||
|
||||
vector_entry irq_a64
|
||||
b unknown_exception
|
||||
check_vector_size irq_a64
|
||||
|
||||
vector_entry fiq_a64
|
||||
b unknown_exception
|
||||
check_vector_size fiq_a64
|
||||
|
||||
vector_entry serror_a64
|
||||
b unknown_exception
|
||||
check_vector_size serror_a64
|
||||
|
||||
/* Lower EL, A32 */
|
||||
vector_entry synch_a32
|
||||
b unknown_exception
|
||||
check_vector_size synch_a32
|
||||
|
||||
vector_entry irq_a32
|
||||
b unknown_exception
|
||||
check_vector_size irq_a32
|
||||
|
||||
vector_entry fiq_a32
|
||||
b unknown_exception
|
||||
check_vector_size fiq_a32
|
||||
|
||||
vector_entry serror_a32
|
||||
b unknown_exception
|
||||
.endfunc
|
||||
.cfi_endproc
|
||||
/* To save space, insert in an unused vector segment. */
|
||||
.global restore_tpidr_el1
|
||||
.type restore_tpidr_el1, %function
|
||||
restore_tpidr_el1:
|
||||
mrs x0, tpidr_el1
|
||||
/* Make sure that TPIDR_EL1 can be dereferenced. */
|
||||
invalid_tpidr:
|
||||
cbz x0, invalid_tpidr
|
||||
/* Restore saved registers. */
|
||||
ldp x19, x20, [x0], #0x10
|
||||
ldp x21, x22, [x0], #0x10
|
||||
ldp x23, x24, [x0], #0x10
|
||||
ldp x25, x26, [x0], #0x10
|
||||
ldp x27, x28, [x0], #0x10
|
||||
ldp x29, x30, [x0], #0x10
|
||||
ldp x1, xzr, [x0], #0x10
|
||||
mov sp, x1
|
||||
mov x0, #0x1
|
||||
ret
|
159
mesosphere/kernel_ldr/source/kern_init_loader.cpp
Normal file
159
mesosphere/kernel_ldr/source/kern_init_loader.cpp
Normal file
|
@ -0,0 +1,159 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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::init::loader {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr size_t KernelResourceRegionSize = 0x1728000;
|
||||
constexpr size_t ExtraKernelResourceSize = 0x68000;
|
||||
static_assert(ExtraKernelResourceSize + KernelResourceRegionSize == 0x1790000);
|
||||
|
||||
constexpr size_t InitialPageTableRegionSize = 0x200000;
|
||||
|
||||
class KInitialPageAllocator : public KInitialPageTable::IPageAllocator {
|
||||
private:
|
||||
uintptr_t next_address;
|
||||
public:
|
||||
constexpr ALWAYS_INLINE KInitialPageAllocator() : next_address(Null<uintptr_t>) { /* ... */ }
|
||||
|
||||
ALWAYS_INLINE void Initialize(uintptr_t address) {
|
||||
this->next_address = address;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void Finalize() {
|
||||
this->next_address = Null<uintptr_t>;
|
||||
}
|
||||
public:
|
||||
virtual KPhysicalAddress Allocate() override {
|
||||
MESOSPHERE_ABORT_UNLESS(this->next_address != Null<uintptr_t>);
|
||||
const uintptr_t allocated = this->next_address;
|
||||
this->next_address += PageSize;
|
||||
std::memset(reinterpret_cast<void *>(allocated), 0, PageSize);
|
||||
return allocated;
|
||||
}
|
||||
|
||||
/* No need to override free. The default does nothing, and so would we. */
|
||||
};
|
||||
|
||||
/* Global Allocator. */
|
||||
KInitialPageAllocator g_initial_page_allocator;
|
||||
|
||||
void RelocateKernelPhysically(uintptr_t &base_address, KernelLayout *&layout) {
|
||||
/* TODO: Proper secure monitor call. */
|
||||
KPhysicalAddress correct_base = KSystemControl::GetKernelPhysicalBaseAddress(base_address);
|
||||
if (correct_base != base_address) {
|
||||
const uintptr_t diff = GetInteger(correct_base) - base_address;
|
||||
const size_t size = layout->rw_end_offset;
|
||||
|
||||
/* Conversion from KPhysicalAddress to void * is safe here, because MMU is not set up yet. */
|
||||
std::memmove(reinterpret_cast<void *>(GetInteger(correct_base)), reinterpret_cast<void *>(base_address), size);
|
||||
base_address += diff;
|
||||
layout = reinterpret_cast<KernelLayout *>(reinterpret_cast<uintptr_t>(layout) + diff);
|
||||
}
|
||||
}
|
||||
|
||||
void SetupInitialIdentityMapping(KInitialPageTable &ttbr1_table, uintptr_t base_address, uintptr_t kernel_size, uintptr_t page_table_region, size_t page_table_region_size, KInitialPageTable::IPageAllocator &allocator) {
|
||||
/* Make a new page table for TTBR0_EL1. */
|
||||
KInitialPageTable ttbr0_table(allocator.Allocate());
|
||||
|
||||
/* Map in an RWX identity mapping for the kernel. */
|
||||
constexpr PageTableEntry KernelRWXIdentityAttribute(PageTableEntry::Permission_KernelRWX, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable);
|
||||
ttbr0_table.Map(base_address, kernel_size, base_address, KernelRWXIdentityAttribute, allocator);
|
||||
|
||||
/* Map in an RWX identity mapping for ourselves. */
|
||||
constexpr PageTableEntry KernelLdrRWXIdentityAttribute(PageTableEntry::Permission_KernelRWX, PageTableEntry::PageAttribute_NormalMemory, PageTableEntry::Shareable_InnerShareable);
|
||||
//ttbr0_table.Map(base_address, kernel_size, base_address, KernelRWXIdentityAttribute, allocator);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
uintptr_t Main(uintptr_t base_address, KernelLayout *layout, uintptr_t ini_base_address) {
|
||||
/* Relocate the kernel to the correct physical base address. */
|
||||
/* Base address and layout are passed by reference and modified. */
|
||||
RelocateKernelPhysically(base_address, layout);
|
||||
|
||||
/* Validate kernel layout. */
|
||||
/* TODO: constexpr 0x1000 definition somewhere. */
|
||||
/* In stratosphere, this is os::MemoryPageSize. */
|
||||
/* 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_end_offset = layout->rx_end_offset;
|
||||
const uintptr_t ro_offset = layout->rx_offset;
|
||||
const uintptr_t ro_end_offset = layout->ro_end_offset;
|
||||
const uintptr_t rw_offset = layout->rx_offset;
|
||||
const uintptr_t rw_end_offset = layout->rw_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_end_offset, 0x1000));
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(ro_offset, 0x1000));
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(ro_end_offset, 0x1000));
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(rw_offset, 0x1000));
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(rw_end_offset, 0x1000));
|
||||
MESOSPHERE_ABORT_UNLESS(util::IsAligned(bss_end_offset, 0x1000));
|
||||
const uintptr_t bss_offset = layout->bss_offset;
|
||||
const uintptr_t ini_end_offset = layout->ini_end_offset;
|
||||
const uintptr_t dynamic_end_offset = layout->dynamic_end_offset;
|
||||
const uintptr_t init_array_offset = layout->init_array_offset;
|
||||
const uintptr_t init_array_end_offset = layout->init_array_end_offset;
|
||||
|
||||
/* Decide if Kernel should have enlarged resource region. */
|
||||
const bool use_extra_resources = KSystemControl::ShouldIncreaseResourceRegionSize();
|
||||
const size_t resource_region_size = KernelResourceRegionSize + (use_extra_resources ? ExtraKernelResourceSize : 0);
|
||||
|
||||
/* Setup the INI1 header in memory for the kernel. */
|
||||
const uintptr_t ini_end_address = base_address + ini_end_offset + resource_region_size;
|
||||
const uintptr_t ini_load_address = ini_end_address - InitialProcessBinarySizeMax;
|
||||
if (ini_base_address != ini_load_address) {
|
||||
/* The INI is not at the correct address, so we need to relocate it. */
|
||||
const InitialProcessBinaryHeader *ini_header = reinterpret_cast<const InitialProcessBinaryHeader *>(ini_base_address);
|
||||
if (ini_header->magic == InitialProcessBinaryMagic && ini_header->size <= InitialProcessBinarySizeMax) {
|
||||
/* INI is valid, relocate it. */
|
||||
std::memmove(reinterpret_cast<void *>(ini_load_address), ini_header, ini_header->size);
|
||||
} else {
|
||||
/* INI is invalid. Make the destination header invalid. */
|
||||
std::memset(reinterpret_cast<void *>(ini_load_address), 0, sizeof(InitialProcessBinaryHeader));
|
||||
}
|
||||
}
|
||||
|
||||
/* We want to start allocating page tables at ini_end_address. */
|
||||
g_initial_page_allocator.Initialize(ini_end_address);
|
||||
|
||||
/* Make a new page table for TTBR1_EL1. */
|
||||
KInitialPageTable ttbr1_table(g_initial_page_allocator.Allocate());
|
||||
|
||||
/* Setup initial identity mapping. TTBR1 table passed by reference. */
|
||||
SetupInitialIdentityMapping(ttbr1_table, base_address, bss_end_offset, ini_end_address, InitialPageTableRegionSize, g_initial_page_allocator);
|
||||
|
||||
/* TODO: Use these. */
|
||||
(void)(bss_offset);
|
||||
(void)(ini_end_offset);
|
||||
(void)(dynamic_end_offset);
|
||||
(void)(init_array_offset);
|
||||
(void)(init_array_end_offset);
|
||||
|
||||
|
||||
/* TODO */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Finalize() {
|
||||
g_initial_page_allocator.Finalize();
|
||||
}
|
||||
|
||||
}
|
36
mesosphere/kernel_ldr/source/kern_k_scoped_interrupt.cpp
Normal file
36
mesosphere/kernel_ldr/source/kern_k_scoped_interrupt.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 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 {
|
||||
|
||||
inline KScopedInterruptDisable::KScopedInterruptDisable() {
|
||||
/* Intentionally do nothing, KernelLdr doesn't have interrupts set up. */
|
||||
}
|
||||
|
||||
inline KScopedInterruptDisable::~KScopedInterruptDisable() {
|
||||
/* Intentionally do nothing, KernelLdr doesn't have interrupts set up. */
|
||||
}
|
||||
|
||||
inline KScopedInterruptEnable::KScopedInterruptEnable() {
|
||||
/* Intentionally do nothing, KernelLdr doesn't have interrupts set up. */
|
||||
}
|
||||
|
||||
inline KScopedInterruptEnable::~KScopedInterruptEnable() {
|
||||
/* Intentionally do nothing, KernelLdr doesn't have interrupts set up. */
|
||||
}
|
||||
|
||||
}
|
|
@ -21,4 +21,75 @@
|
|||
.section .crt0.text.start, "ax", %progbits
|
||||
.global _start
|
||||
_start:
|
||||
b _start
|
||||
/* KernelLdr_Main(uintptr_t kernel_base_address, KernelMap *kernel_map, uintptr_t ini1_base_address); */
|
||||
adr x18, _start
|
||||
adr x16, __external_references
|
||||
ldr x17, [x16, #0x8] /* bss end */
|
||||
ldr x16, [x16, #0x0] /* bss start */
|
||||
add x16, x16, x18
|
||||
add x17, x17, x18
|
||||
clear_bss:
|
||||
cmp x16, x17
|
||||
b.cs clear_bss_done
|
||||
str xzr, [x16],#0x8
|
||||
b clear_bss
|
||||
clear_bss_done:
|
||||
adr x17, __external_references
|
||||
ldr x17, [x17, #0x10] /* stack top */
|
||||
add sp, x17, x18
|
||||
|
||||
/* Stack is now set up. */
|
||||
/* Apply relocations and call init array for KernelLdr. */
|
||||
sub sp, sp, #0x20
|
||||
stp x0, x1, [sp, #0x00]
|
||||
stp x2, x30, [sp, #0x10]
|
||||
adr x0, _start
|
||||
adr x1, __external_references
|
||||
ldr x1, [x1, #0x18] /* .dynamic. */
|
||||
add x1, x0, x1
|
||||
|
||||
/* branch to ams::kern::init::Elf::Elf64::ApplyRelocations(uintptr_t, const ams::kern::init::Elf::Elf64::Dyn *); */
|
||||
bl _ZN3ams4kern4init3Elf5Elf6416ApplyRelocationsEmPKNS3_3DynE
|
||||
|
||||
/* branch to ams::kern::init::Elf::Elf64::CallInitArrayFuncs(uintptr_t, uintptr_t) */
|
||||
adr x2, _start
|
||||
adr x1, __external_references
|
||||
ldr x0, [x1, #0x20] /* init_array_start */
|
||||
ldr x1, [x1, #0x28] /* init_array_end */
|
||||
add x0, x0, x2
|
||||
add x1, x1, x2
|
||||
bl _ZN3ams4kern4init3Elf5Elf6418CallInitArrayFuncsEmm
|
||||
|
||||
/* Setup system registers, for detection of errors during init later. */
|
||||
msr tpidr_el1, xzr /* Clear TPIDR_EL1 */
|
||||
adr x0, __external_references
|
||||
adr x1, _start
|
||||
ldr x0, [x0, #0x30]
|
||||
add x0, x1, x0
|
||||
msr vbar_el1, x0
|
||||
isb
|
||||
|
||||
/* Call ams::kern::init::loader::Main(uintptr_t, ams::kern::init::KernelLayout *, uintptr_t) */
|
||||
ldp x0, x1, [sp, #0x00]
|
||||
ldr x2, [sp, #0x10]
|
||||
bl _ZN3ams4kern4init6loader4MainEmPNS1_12KernelLayoutEm
|
||||
str x0, [sp, #0x00]
|
||||
|
||||
/* Call ams::kern::init::loader::Finalize() */
|
||||
bl _ZN3ams4kern4init6loader8FinalizeEv
|
||||
|
||||
/* Return to the newly-relocated kernel. */
|
||||
ldr x1, [sp, #0x18] /* Return address to Kernel */
|
||||
ldr x2, [sp, #0x00] /* Relocated kernel base address. */
|
||||
add x1, x2, x1
|
||||
br x1
|
||||
|
||||
|
||||
__external_references:
|
||||
.quad __bss_start__ - _start
|
||||
.quad __bss_end__ - _start
|
||||
.quad __stack_end - _start
|
||||
.quad __dynamic__start__ - _start
|
||||
.quad __init_array_start - _start
|
||||
.quad __init_array_end - _start
|
||||
.quad __vectors_start__ - _start
|
Loading…
Reference in a new issue