mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2025-05-30 14:35:17 -04: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
|
@ -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. */
|
||||
}
|
||||
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue