Compare commits

..

3 Commits

Author SHA1 Message Date
Michael Scire
c9ead205a4 libstrat: fix bugs/compiler warnings 2020-07-01 09:22:09 -07:00
Michael Scire
d2fc7dba8c fs: use access_log for other user fs/dir/file bindings 2020-07-01 01:27:23 -07:00
Michael Scire
c6a0d88a76 fs: implement AccessLog, enable for File operations 2020-06-29 23:19:33 -07:00
619 changed files with 7789 additions and 54246 deletions

3
.gitignore vendored
View File

@@ -38,9 +38,6 @@
*.x86_64
*.hex
# Deko3d shaders
*.dksh
# Switch Executables
*.nso
*.nro

View File

@@ -64,7 +64,6 @@ dist-no-debug: all
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/010000000000003C
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000042
mkdir -p atmosphere-$(AMSVER)/atmosphere/fatal_errors
mkdir -p atmosphere-$(AMSVER)/atmosphere/config_templates
mkdir -p atmosphere-$(AMSVER)/atmosphere/config
@@ -92,13 +91,11 @@ dist-no-debug: all
cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000036/exefs.nsp
cp stratosphere/ro/ro.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037/exefs.nsp
cp stratosphere/jpegdec/jpegdec.nsp atmosphere-$(AMSVER)/atmosphere/contents/010000000000003C/exefs.nsp
cp stratosphere/pgl/pgl.nsp atmosphere-$(AMSVER)/atmosphere/contents/0100000000000042/exefs.nsp
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/flags
touch atmosphere-$(AMSVER)/atmosphere/contents/0100000000000032/flags/boot2.flag
mkdir -p atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037/flags
touch atmosphere-$(AMSVER)/atmosphere/contents/0100000000000037/flags/boot2.flag
cp troposphere/reboot_to_payload/reboot_to_payload.nro atmosphere-$(AMSVER)/switch/reboot_to_payload.nro
cp troposphere/daybreak/daybreak.nro atmosphere-$(AMSVER)/switch/daybreak.nro
cd atmosphere-$(AMSVER); zip -r ../atmosphere-$(AMSVER).zip ./*; cd ../;
rm -r atmosphere-$(AMSVER)
mkdir out
@@ -144,8 +141,6 @@ dist: dist-no-debug
cp stratosphere/spl/spl.elf atmosphere-$(AMSVER)-debug/spl.elf
cp stratosphere/erpt/erpt.elf atmosphere-$(AMSVER)-debug/erpt.elf
cp stratosphere/jpegdec/jpegdec.elf atmosphere-$(AMSVER)-debug/jpegdec.elf
cp stratosphere/pgl/pgl.elf atmosphere-$(AMSVER)-debug/pgl.elf
cp troposphere/daybreak/daybreak.elf atmosphere-$(AMSVER)-debug/daybreak.elf
cd atmosphere-$(AMSVER)-debug; zip -r ../atmosphere-$(AMSVER)-debug.zip ./*; cd ../;
rm -r atmosphere-$(AMSVER)-debug
mv atmosphere-$(AMSVER)-debug.zip out/atmosphere-$(AMSVER)-debug.zip

View File

@@ -1,31 +1,4 @@
# Changelog
## 0.14.1
+ An issue was fixed in 0.14.0 that would cause a black screen on boot when the INI1's size was not aligned to 8 bytes.
+ General system stability improvements to enhance the user's experience.
## 0.14.0
+ An API (`ams:su`) was added to allow homebrew to safely install system upgrades or downgrades.
+ This is a re-implementation of the logic that `ns` uses to install gamecard system updates.
+ Nintendo (and now atmosphère) uses an installation process that can recover no matter where a failure occurs, which should significantly improve the safety of custom system update installation.
+ Support was added to `exosphère` for running on Mariko hardware.
+ **Please note**: Atmosphère still does not support Mariko, and should not be run on Mariko yet.
+ Certain stratosphere components do not handle mariko-specific logic fully correctly yet, and may initialize or interact with hardware incorrectly.
+ This will be fixed and support will be added over the remainder of the Summer.
+ A homebrew application (`daybreak`) was added that uses the system updater API (with thanks to @Adubbz for both design and implementation).
+ `daybreak` is included with atmosphère, and functions as a safer/more accurate equivalent to e.g. ChoiDujourNX.
+ Upgrades/downgrades can be installed from a folder containing the update NCAs on the SD card.
+ Because the update logic functions identically to Nintendo's, `daybreak` will be safe to use on Mariko when the rest of atmosphère has support.
+ **Please note**: Daybreak requires that meta (.cnmt) NCAs have the correct extension `.cnmt.nca`.
+ This is because gamecard system update logic uses extension to determine whether to mount the content.
+ [Several](https://gist.github.com/HookedBehemoth/df36b5970e1c5b1b512ec7bdd9043c6e) [scripts](https://gist.github.com/antiKk/279966c27fdfd9c7fe63b4ae410f89c4) have been made by community members to automatically rename folders with incorrect extensions.
+ A bug was fixed that would cause file-based emummc to throw an error (showing a hexdump) on boot.
+ Major thanks to @hexkyz for tracking down and resolving this.
+ A number of minor issues were resolved, including:
+ fusee now prints information to the screen when an error occurs, instead of getting stuck trying to initialize the display.
+ A race condition in Horizon was worked around that could prevent boot under certain circumstances.
+ A bug was fixed that would cause atmosphère modules to open ten copies of certain filesystems instead of one.
+ This could cause object exhaustion under certain circumstances.
+ For those interested in atmosphère's future development plans, the project's [roadmap](https://github.com/Atmosphere-NX/Atmosphere/blob/ac9832c5ce7be5832f6d29f6564a9c03e7efd22f/docs/roadmap.md) was updated.
+ General system stability improvements to enhance the user's experience.
## 0.13.0
+ `exosphère`, atmosphère's secure monitor re-implementation, was completely re-written.
+ `exosphère` was the first component authored for the project in early 2018. It is written in C, and in a style very different from the rest of atmosphère's code.

View File

@@ -1,7 +1,12 @@
# Planned Features
atmosphère has a number of features that are either works-in-progress or planned. Please note that while time-estimates are given, they are loose, and things may be completed sooner or later than advertised.
The following descriptions were last updated on July 7th, 2020.
The following descriptions were last updated on June 29th, 2020.
## system updater homebrew
* **Description**: A user homebrew making use of the new system updater api, so that users can actually use the new api in practice.
* **Development Status**: Initial revision complete, pending re-write by Adubbz.
* **Completion Time**: June-July 2020
## ams-on-mariko
* **Description**: Atmosphere cannot run as-is on Mariko hardware. A large number of changes are needed in many components. Although secure monitor support is complete in exosphere, additional work is needed on the bootloader and stratosphere sides as well. Mariko support will also require further design thought; atmosphere's debugging design heavily relies on reboot-to-payload and (more generally) the ability to perform warmboot bootrom hax at will. This is not possible on Mariko, and will require a new design/software support for whatever solution is chosen.
@@ -15,7 +20,7 @@ The following descriptions were last updated on July 7th, 2020.
## mesosphere
* **Description**: mesosphère is a reimplementation of the Horizon operating system's Kernel. It aims to provide an open-source reference for Nintendo's code.
* **Development Status**: Under active development by SciresM.
* **Development Status**: Under semi-active development by SciresM; temporarily on pause while the System Updater API is completed.
* **Estimated Time**: Mid-to-Late 2020
## tma reimplementation
@@ -49,10 +54,6 @@ The following features were previously included under the planned features secti
Please note that this is not an exhaustive list of features present in atmosphère, and only serves to indicate what from the above has been completed.
## system updater homebrew
* **Description**: A user homebrew making use of the new system updater api, so that users can actually use the new api in practice.
* **Completion Time**: July 2020
## system updater api
* **Description**: A planned extension api for stratosphere (tenatively `ams:su`), this will provide an interface for homebrew to safely install system upgrades or downgrades. This will allow for much more easily transitioning safely between different versions of the operating system.
* **Completion Time**: June 2020

View File

@@ -24,9 +24,23 @@ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
$(TOPDIR)/../program
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \
$(notdir $(wildcard $(dir)/*.c))))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c)))
CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \
$(notdir $(wildcard $(dir)/*.cpp))))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp)))
SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \
$(notdir $(wildcard $(dir)/*.s))))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s)))
BINFILES := program.lz4 boot_code.lz4

View File

@@ -19,12 +19,10 @@
namespace ams::diag {
NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value, const char *format, ...) {
AMS_UNUSED(file, line, func, expr, value, format);
ams::secmon::loader::ErrorReboot();
}
NORETURN void AbortImpl(const char *file, int line, const char *func, const char *expr, u64 value) {
AMS_UNUSED(file, line, func, expr, value);
ams::secmon::loader::ErrorReboot();
}

View File

@@ -25,9 +25,23 @@ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(TOPDIR)/sc7fw \
$(TOPDIR)/rebootstub
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \
$(notdir $(wildcard $(dir)/*.c))))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c)))
CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \
$(notdir $(wildcard $(dir)/*.cpp))))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp)))
SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \
$(notdir $(wildcard $(dir)/*.s))))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s)))
BINFILES := sc7fw.bin rebootstub.bin

View File

@@ -23,9 +23,23 @@ export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \
$(notdir $(wildcard $(dir)/*.c))))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c)))
CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \
$(notdir $(wildcard $(dir)/*.cpp))))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp)))
SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \
$(notdir $(wildcard $(dir)/*.s))))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C

View File

@@ -23,9 +23,23 @@ export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \
$(notdir $(wildcard $(dir)/*.c))))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c)))
CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \
$(notdir $(wildcard $(dir)/*.cpp))))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp)))
SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \
$(notdir $(wildcard $(dir)/*.s))))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C

View File

@@ -90,7 +90,7 @@ namespace ams::sc7fw {
reg::ReadWrite(PMC + APBDEV_PMC_DPD_ENABLE, PMC_REG_BITS_ENUM(DPD_ENABLE_ON, ENABLE));
/* Wait forever until we're asleep. */
AMS_INFINITE_LOOP();
while (true) { /* ... */ }
}
}
@@ -102,9 +102,7 @@ namespace ams::sc7fw {
NORETURN void ExceptionHandler() {
/* Write enable to MAIN_RESET. */
reg::Write(PMC + APBDEV_PMC_CNTRL, PMC_REG_BITS_ENUM(CNTRL_MAIN_RESET, ENABLE));
/* Wait forever until we're reset. */
AMS_INFINITE_LOOP();
while (true) { /* ... */ }
}
}

View File

@@ -48,12 +48,7 @@ namespace ams::secmon::boot {
const auto pmc = MemoryRegionVirtualDevicePmc.GetAddress();
/* Set the physical address of the warmboot binary to scratch 1. */
if (GetSocType() == fuse::SocType_Mariko) {
reg::Write(pmc + APBDEV_PMC_SECURE_SCRATCH119, static_cast<u32>(MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware.GetAddress()));
} else /* if (GetSocType() == fuse::SocType_Erista) */ {
reg::Write(pmc + APBDEV_PMC_SCRATCH1, static_cast<u32>(MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware.GetAddress()));
}
reg::Write(pmc + APBDEV_PMC_SCRATCH1, static_cast<u32>(MemoryRegionPhysicalDramSecureDataStoreWarmbootFirmware.GetAddress()));
/* Configure logging by setting bits 18-19 of scratch 20. */
reg::ReadWrite(pmc + APBDEV_PMC_SCRATCH20, REG_BITS_VALUE(18, 2, 0));
@@ -71,7 +66,6 @@ namespace ams::secmon::boot {
/* The warmboot key as a parameter. The latter is a better solution, but it would be nice to take */
/* care of it here. Perhaps we should read the number of anti-downgrade fuses burnt, and translate that */
/* to the warmboot key? To be decided during the process of implementing ams-on-mariko support. */
reg::Write(pmc + APBDEV_PMC_SECURE_SCRATCH32, 0x129);
}
constinit const u8 DeviceMasterKeySourceKekSource[se::AesBlockSize] = {
@@ -85,8 +79,6 @@ namespace ams::secmon::boot {
if constexpr (false) {
/* TODO: Consider implementing this as a reference. */
}
AMS_UNUSED(is_prod);
}
/* NOTE: These are just latest-master-kek encrypted with BEK. */
@@ -100,10 +92,6 @@ namespace ams::secmon::boot {
0xF9, 0x37, 0xCF, 0x9A, 0xBD, 0x86, 0xBB, 0xA9, 0x9C, 0x9E, 0x03, 0xC4, 0xFC, 0xBC, 0x3B, 0xCE
};
constinit const u8 MasterKeySource[se::AesBlockSize] = {
0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C
};
void DeriveMasterKekAndDeviceKeyMariko(bool is_prod) {
/* Clear all keyslots other than KEK and SBK in SE1. */
for (int i = 0; i < pkg1::AesKeySlot_Count; ++i) {
@@ -135,14 +123,6 @@ namespace ams::secmon::boot {
}
}
void DeriveMasterKey() {
if (GetSocType() == fuse::SocType_Mariko) {
se::SetEncryptedAesKey128(pkg1::AesKeySlot_Master, pkg1::AesKeySlot_MasterKek, MasterKeySource, se::AesBlockSize);
} else /* if (GetSocType() == fuse::SocType_Erista) */ {
/* Nothing to do here; erista bootloader will have derived master key already. */
}
}
void SetupRandomKey(int slot, se::KeySlotLockFlags flags) {
/* Create an aligned buffer to hold the key. */
constexpr size_t KeySize = se::AesBlockSize;
@@ -332,9 +312,6 @@ namespace ams::secmon::boot {
/* Derive the master keys. */
DeriveAllMasterKeys(is_prod, work_block);
/* Lock the master key as a kek. */
se::LockAesKeySlot(pkg1::AesKeySlot_Master, se::KeySlotLockFlags_AllLockKek);
/* Derive the device master keys. */
DeriveAllDeviceMasterKeys(is_prod, work_block);
@@ -380,10 +357,7 @@ namespace ams::secmon::boot {
/* Lock the device key as only usable as a kek. */
se::LockAesKeySlot(pkg1::AesKeySlot_Device, se::KeySlotLockFlags_AllLockKek);
/* Derive the master key. */
DeriveMasterKey();
/* Derive all other keys. */
/* Derive all keys. */
DeriveAllKeys(is_prod);
}
@@ -408,7 +382,6 @@ namespace ams::secmon::boot {
constexpr void UnmapDramImpl(u64 *l1, u64 *l2, u64 *l3) {
/* Unmap the L1 entry corresponding to to the Dram entries. */
AMS_UNUSED(l2, l3);
InvalidateL1Entries(l1, MemoryRegionDram.GetAddress(), MemoryRegionDram.GetSize());
}

View File

@@ -16,24 +16,10 @@
#include <exosphere.hpp>
#include "secmon_error.hpp"
namespace ams {
namespace {
namespace {
constexpr bool SaveSystemStateForDebug = false;
constexpr bool SaveSystemStateForDebug = false;
constexpr bool LogSystemStateForDebug = false;
void LogU64(u64 value) {
char buffer[2 * sizeof(value)];
for (size_t i = 0; i < sizeof(value); ++i) {
buffer[sizeof(buffer) - 1 - (2 * i) - 0] = "0123456789ABCDEF"[(value >> 0) & 0xF];
buffer[sizeof(buffer) - 1 - (2 * i) - 1] = "0123456789ABCDEF"[(value >> 4) & 0xF];
value >>= 8;
}
log::SendText(buffer, sizeof(buffer));
}
}
}
namespace ams::diag {
@@ -112,57 +98,6 @@ namespace ams::secmon {
util::WaitMicroSeconds(1000);
}
ALWAYS_INLINE void LogSystemStateForDebugErrorReboot(u64 lr, u64 sp) {
log::SendText("*** Error Reboot ***\n", 21);
log::Flush();
u64 temp_reg;
__asm__ __volatile__("mrs %0, esr_el3" : "=r"(temp_reg) :: "memory");
log::SendText("ESR_EL3: ", 9);
LogU64(temp_reg);
log::SendText("\n", 1);
log::Flush();
__asm__ __volatile__("mrs %0, elr_el3" : "=r"(temp_reg) :: "memory");
log::SendText("ELR_EL3: ", 9);
LogU64(temp_reg);
log::SendText("\n", 1);
log::Flush();
__asm__ __volatile__("mrs %0, far_el3" : "=r"(temp_reg) :: "memory");
log::SendText("FAR_EL3: ", 9);
LogU64(temp_reg);
log::SendText("\n", 1);
log::Flush();
log::SendText("LR: ", 9);
LogU64(lr);
log::SendText("\n", 1);
log::Flush();
log::SendText("SP: ", 9);
LogU64(sp);
log::SendText("\n", 1);
log::Flush();
log::SendText("Stack:\n", 7);
log::Flush();
char buf[2];
for (int i = 0; i < 0x100; ++i) {
const u8 byte = *(volatile u8 *)(sp + i);
buf[0] = "0123456789ABCDEF"[(byte >> 4) & 0xF];
buf[1] = "0123456789ABCDEF"[(byte >> 0) & 0xF];
log::SendText(buf, 2);
log::Flush();
if (util::IsAligned(i + 1, 0x10)) {
log::SendText("\n", 1);
log::Flush();
}
}
}
}
void SetError(pkg1::ErrorInfo info) {
@@ -179,14 +114,6 @@ namespace ams::secmon {
SaveSystemStateForDebugErrorReboot();
}
if constexpr (LogSystemStateForDebug) {
u64 lr, sp;
__asm__ __volatile__("mov %0, lr" : "=r"(lr) :: "memory");
__asm__ __volatile__("mov %0, sp" : "=r"(sp) :: "memory");
LogSystemStateForDebugErrorReboot(lr, sp);
}
/* Lockout the security engine. */
se::Lockout();

View File

@@ -41,7 +41,6 @@ namespace ams::secmon {
constexpr void UnmapBootCodeImpl(u64 *l1, u64 *l2, u64 *l3, uintptr_t boot_code, size_t boot_code_size) {
/* Unmap the L3 entries corresponding to the boot code. */
AMS_UNUSED(l1, l2);
InvalidateL3Entries(l3, boot_code, boot_code_size);
}

View File

@@ -51,27 +51,27 @@ namespace ams::secmon {
constinit bool g_is_cold_boot = true;
constinit se::StickyBits ExpectedSeStickyBits = {
constinit const se::StickyBits ExpectedSeStickyBits = {
.se_security = (1 << 0), /* SE_HARD_SETTING */
.tzram_security = 0,
.crypto_security_perkey = (1 << pkg1::AesKeySlot_UserEnd) - 1,
.crypto_keytable_access = {
(0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 0: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 1: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 2: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 3: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 4: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 7) | (1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 5: User keyslot. KEY. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 6: Unused keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 7: Unused keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(0 << 7) | (0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 8: Temp keyslot. KEY. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 7) | (0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 9: SmcTemp keyslot. KEY. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
(1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 10: Wrap1 keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(0 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 11: Wrap2 keyslot. KEY. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 12: DMaster keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Master keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 14: Unused keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(1 << 7) | (0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Device keyslot. KEK. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 0: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 1: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 2: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 3: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 4: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(1 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 5: User keyslot. KEYUSE, UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 6: Unused keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 7: Unused keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 8: Temp keyslot. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 6) | (1 << 5) | (0 << 4) | (1 << 3) | (0 << 2) | (1 << 1) | (0 << 0), /* 9: SmcTemp keyslot. UIVUPDATE, OIVUPDATE, KEYUPDATE enabled. KEYUSE, UIVREAD, OIVREAD, KEYREAD disabled. */
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 10: Wrap1 keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 11: Wrap2 keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 12: DMaster keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Master keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 14: Unused keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
(0 << 6) | (0 << 5) | (0 << 4) | (0 << 3) | (0 << 2) | (0 << 1) | (0 << 0), /* 13: Device keyslot. KEYUSE, UIVUPDATE, UIVREAD, OIVUPDATE, OIVREAD, KEYUPDATE, KEYREAD disabled. */
},
.rsa_security_perkey = 0,
.rsa_keytable_access = {
@@ -139,16 +139,6 @@ namespace ams::secmon {
}
void VerifySecurityEngineStickyBits() {
/* On mariko, an extra sticky bit is set. */
if (GetSocType() == fuse::SocType_Mariko) {
ExpectedSeStickyBits.se_security |= (1 << 5);
} else /* if (GetSocType() == fuse::SocType_Erista) */ {
/* Erista does not support DST_KEYTABLE_ONLY, and so all keys will have the bit clear. */
for (size_t i = 0; i < util::size(ExpectedSeStickyBits.crypto_keytable_access); ++i) {
ExpectedSeStickyBits.crypto_keytable_access[i] &= ~(1 << 7);
}
}
if (!se::ValidateStickyBits(ExpectedSeStickyBits)) {
SetError(pkg1::ErrorInfo_InvalidSecurityEngineStickyBits);
AMS_ABORT("Invalid sticky bits");
@@ -948,16 +938,12 @@ namespace ams::secmon {
return reg::Read(MC + MC_SECURITY_CFG3) == 0;
}
void SetupLogForBoot() {
log::Initialize();
log::SendText("OHAYO\n", 6);
log::Flush();
}
void LogExitLp0() {
/* NOTE: Nintendo only does this on dev, but we will always do it. */
if (true /* !pkg1::IsProduction() */) {
SetupLogForBoot();
log::Initialize();
log::SendText("OHAYO\n", 6);
log::Flush();
}
}
@@ -983,7 +969,7 @@ namespace ams::secmon {
InitializeConfigurationContext();
/* Initialize uart for logging. */
SetupLogForBoot();
log::Initialize();
/* Initialize the security engine. */
se::Initialize();
@@ -1031,16 +1017,12 @@ namespace ams::secmon {
/* Overwrite keys that we want to be random with random contents. */
se::InitializeRandom();
se::ConfigureAutomaticContextSave();
se::SetRandomKey(pkg1::AesKeySlot_Temporary);
se::GenerateSrk();
se::SetRandomKey(pkg1::AesKeySlot_TzramSaveKek);
/* Initialize pmc secure scratch. */
if (GetSocType() == fuse::SocType_Erista) {
pmc::InitializeRandomScratch();
}
pmc::LockSecureRegister(pmc::SecureRegister_Srk);
pmc::InitializeRandomScratch();
/* Setup secure registers. */
SetupSecureRegisters();

View File

@@ -262,11 +262,6 @@ namespace ams::secmon::smc {
/* Get whether this unit should allow writing to the calibration partition. */
args.r[1] = (GetEmummcConfiguration().IsEmummcActive() || GetSecmonConfiguration().AllowWritingToCalibrationBinarySysmmc());
break;
case ConfigItem::ExosphereEmummcType:
/* Get what kind of emummc this unit has active. */
/* NOTE: This may return values other than 1 in the future. */
args.r[1] = (GetEmummcConfiguration().IsEmummcActive() ? 1 : 0);
break;
default:
return SmcResult::InvalidArgument;
}

View File

@@ -47,7 +47,6 @@ namespace ams::secmon::smc {
ExosphereHasRcmBugPatch = 65004,
ExosphereBlankProdInfo = 65005,
ExosphereAllowCalWrites = 65006,
ExosphereEmummcType = 65007,
};
SmcResult SmcGetConfigUser(SmcArguments &args);

View File

@@ -69,7 +69,6 @@ namespace ams::secmon::smc {
SmcResult SmcWriteAddress(SmcArguments &args) {
/* NOTE: This smc was deprecated in Atmosphère 0.13.0. */
AMS_UNUSED(args);
return SmcResult::NotImplemented;
}

View File

@@ -492,8 +492,6 @@ namespace ams::secmon::smc {
}
SmcResult SmcPowerOffCpu(SmcArguments &args) {
AMS_UNUSED(args);
/* Get the current core id. */
const auto core_id = hw::GetCurrentCoreId();

View File

@@ -155,27 +155,10 @@ namespace ams::secmon::smc {
/* Find the access table. */
const AccessTableEntry * const entry = GetAccessTableEntry(address);
/* Translate our entry into an address to access. */
uintptr_t virtual_address = 0;
/* If we have a table, perform the write. */
if (entry != nullptr) {
/* Get the address to read or write. */
virtual_address = entry->virtual_address + (address - entry->address);
} else {
/* For no clearly discernable reason, SmcReadWriteRegister returns success despite not doing the read/write */
/* when accessing the SMMU controls for the BPMP and for APB-DMA. */
/* This is "probably" to fuck with hackers who got access to the SMC and are trying to get control of the */
/* BPMP to exploit jamais vu, deja vu, or other related DMA/wake-from-sleep vulnerabilities. */
constexpr uintptr_t MC = MemoryRegionPhysicalDeviceMemoryController.GetAddress();
SMC_R_UNLESS((address == (MC + MC_SMMU_AVPC_ASID) || address == (MC + MC_SMMU_PPCS1_ASID)), InvalidArgument);
/* For backwards compatibility, we'll allow access to these devices on 1.0.0. */
if (GetTargetFirmware() < TargetFirmware_2_0_0) {
virtual_address = MemoryRegionVirtualDeviceMemoryController.GetAddress() + (address - MC);
}
}
/* Perform the read or write, if we should. */
if (virtual_address != 0) {
const uintptr_t virtual_address = entry->virtual_address + (address - entry->address);
u32 out = 0;
if (mask != ~static_cast<u32>(0)) {
@@ -186,6 +169,13 @@ namespace ams::secmon::smc {
}
args.r[1] = out;
} else {
/* For no clearly discernable reason, SmcReadWriteRegister returns success despite not doing the read/write */
/* when accessing the SMMU controls for the BPMP and for APB-DMA. */
/* This is "probably" to fuck with hackers who got access to the SMC and are trying to get control of the */
/* BPMP to exploit jamais vu, deja vu, or other related DMA/wake-from-sleep vulnerabilities. */
constexpr uintptr_t MC = MemoryRegionPhysicalDeviceMemoryController.GetAddress();
SMC_R_UNLESS((address == (MC + MC_SMMU_AVPC_ASID) || address == (MC + MC_SMMU_PPCS1_ASID)), InvalidArgument);
}
return SmcResult::Success;

View File

@@ -75,7 +75,6 @@ namespace ams::secmon::smc {
u8 msg[se::RsaSize];
public:
void Set(const void *m, size_t m_size) {
AMS_UNUSED(m_size);
std::memcpy(this->msg, m, sizeof(this->msg));
}

View File

@@ -3,11 +3,7 @@ import sys, lz4
from struct import unpack as up
def lz4_compress(data):
try:
import lz4.block as block
except ImportError:
block = lz4.LZ4_compress
return block.compress(data, 'high_compression', store_size=False)
return lz4.block.compress(data, 'high_compression', store_size=False)
def split_binary(data):
A, B, START, BOOT_CODE_START, BOOT_CODE_END, PROGRAM_START, C, D = up('<QQQQQQQQ', data[:0x40])
@@ -23,7 +19,7 @@ def split_binary(data):
def main(argc, argv):
if argc != 3:
print('Usage: %s in outdir' % argv[0])
print 'Usage: %s in outdir' % argv[0]
return 1
with open(argv[1], 'rb') as f:
data = f.read()
@@ -34,4 +30,4 @@ def main(argc, argv):
return 0
if __name__ == '__main__':
sys.exit(main(len(sys.argv), sys.argv))
sys.exit(main(len(sys.argv), sys.argv))

View File

@@ -23,9 +23,23 @@ export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \
$(notdir $(wildcard $(dir)/*.c))))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c)))
CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \
$(notdir $(wildcard $(dir)/*.cpp))))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp)))
SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \
$(notdir $(wildcard $(dir)/*.s))))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C

View File

@@ -90,9 +90,7 @@ namespace ams::warmboot {
NORETURN void ExceptionHandler() {
/* Write enable to MAIN_RESET. */
reg::Write(PMC + APBDEV_PMC_CNTRL, PMC_REG_BITS_ENUM(CNTRL_MAIN_RESET, ENABLE));
/* Wait forever until we're reset. */
AMS_INFINITE_LOOP();
while (true) { /* ... */ }
}
}

View File

@@ -17,7 +17,7 @@
#ifndef FUSEE_LOG_H
#define FUSEE_LOG_H
#define PRINT_MESSAGE_MAX_LENGTH 1024
#define PRINT_MESSAGE_MAX_LENGTH 512
#include <stdarg.h>

View File

@@ -17,26 +17,17 @@
#include <stdbool.h>
#include <stdarg.h>
#include "utils.h"
#include "display/video_fb.h"
#include "lib/log.h"
__attribute__ ((noreturn)) void generic_panic(void) {
print(SCREEN_LOG_LEVEL_ERROR, "Panic raised!");
while (true) {
/* Lock. */
}
}
__attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
/* Forcefully initialize the screen if logging is disabled. */
if (log_get_log_level() == SCREEN_LOG_LEVEL_NONE) {
/* Zero-fill the framebuffer and register it as printk provider. */
video_init((void *)0xC0000000);
/* Override the global logging level. */
log_set_log_level(SCREEN_LOG_LEVEL_ERROR);
}
/* Display fatal error. */
va_list args;
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
va_start(args, fmt);

View File

@@ -19,10 +19,9 @@
#include "exception_handlers.h"
#include "utils.h"
#include "lib/log.h"
#include "lib/vsprintf.h"
#define CODE_DUMP_SIZE 0x30
#define STACK_DUMP_SIZE 0x30
#define STACK_DUMP_SIZE 0x60
extern const uint32_t exception_handler_table[];
@@ -35,40 +34,6 @@ static const char *register_names[] = {
"SP", "LR", "PC", "CPSR",
};
/* Adapted from https://gist.github.com/ccbrown/9722406 */
static void hexdump(const void* data, size_t size, uintptr_t addrbase, char* strbuf) {
const uint8_t *d = (const uint8_t *)data;
char ascii[17] = {0};
ascii[16] = '\0';
for (size_t i = 0; i < size; i++) {
if (i % 16 == 0) {
strbuf += sprintf(strbuf, "%0*" PRIXPTR ": | ", 2 * sizeof(addrbase), addrbase + i);
}
strbuf += sprintf(strbuf, "%02X ", d[i]);
if (d[i] >= ' ' && d[i] <= '~') {
ascii[i % 16] = d[i];
} else {
ascii[i % 16] = '.';
}
if ((i+1) % 8 == 0 || i+1 == size) {
strbuf += sprintf(strbuf, " ");
if ((i+1) % 16 == 0) {
strbuf += sprintf(strbuf, "| %s \n", ascii);
} else if (i+1 == size) {
ascii[(i+1) % 16] = '\0';
if ((i+1) % 16 <= 8) {
strbuf += sprintf(strbuf, " ");
}
for (size_t j = (i+1) % 16; j < 16; j++) {
strbuf += sprintf(strbuf, " ");
}
strbuf += sprintf(strbuf, "| %s \n", ascii);
}
}
}
}
void setup_exception_handlers(void) {
volatile uint32_t *bpmp_exception_handler_table = (volatile uint32_t *)0x6000F200;
for (int i = 0; i < 8; i++) {
@@ -79,40 +44,38 @@ void setup_exception_handlers(void) {
}
void exception_handler_main(uint32_t *registers, unsigned int exception_type) {
char exception_log[0x400] = {0};
uint8_t code_dump[CODE_DUMP_SIZE] = {0};
uint8_t stack_dump[STACK_DUMP_SIZE] = {0};
size_t code_dump_size = 0;
size_t stack_dump_size = 0;
uint8_t code_dump[CODE_DUMP_SIZE];
uint8_t stack_dump[STACK_DUMP_SIZE];
size_t code_dump_size;
size_t stack_dump_size;
uint32_t pc = registers[15];
uint32_t cpsr = registers[16];
uint32_t instr_addr = pc + ((cpsr & 0x20) ? 2 : 4) - CODE_DUMP_SIZE;
sprintf(exception_log, "An exception occured!\n");
print(SCREEN_LOG_LEVEL_ERROR, "\nSomething went wrong...\n");
code_dump_size = safecpy(code_dump, (const void *)instr_addr, CODE_DUMP_SIZE);
stack_dump_size = safecpy(stack_dump, (const void *)registers[13], STACK_DUMP_SIZE);
sprintf(exception_log + strlen(exception_log), "\nException type: %s\n", exception_names[exception_type]);
sprintf(exception_log + strlen(exception_log), "\nRegisters:\n");
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nException type: %s\n",
exception_names[exception_type]);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nRegisters:\n\n");
/* Print r0 to pc. */
for (int i = 0; i < 16; i += 2) {
sprintf(exception_log + strlen(exception_log), "%-7s%08"PRIX32" %-7s%08"PRIX32"\n",
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%-7s%08"PRIX32" %-7s%08"PRIX32"\n",
register_names[i], registers[i], register_names[i+1], registers[i+1]);
}
/* Print cpsr. */
sprintf(exception_log + strlen(exception_log), "%-7s%08"PRIX32"\n", register_names[16], registers[16]);
/* Print code and stack regions. */
sprintf(exception_log + strlen(exception_log), "\nCode dump:\n");
hexdump(code_dump, code_dump_size, instr_addr, exception_log + strlen(exception_log));
sprintf(exception_log + strlen(exception_log), "\nStack dump:\n");
hexdump(stack_dump, stack_dump_size, registers[13], exception_log + strlen(exception_log));
sprintf(exception_log + strlen(exception_log), "\n");
/* Throw fatal error with the full exception log. */
fatal_error(exception_log);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%-7s%08"PRIX32"\n", register_names[16], registers[16]);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nCode dump:\n");
hexdump(code_dump, code_dump_size, instr_addr);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nStack dump:\n");
hexdump(stack_dump, stack_dump_size, registers[13]);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\n");
fatal_error("An exception occured!\n");
}

View File

@@ -17,7 +17,7 @@
#ifndef FUSEE_LOG_H
#define FUSEE_LOG_H
#define PRINT_MESSAGE_MAX_LENGTH 1024
#define PRINT_MESSAGE_MAX_LENGTH 512
#include <stdarg.h>

View File

@@ -42,8 +42,6 @@ static const char *get_error_desc_str(uint32_t error_desc) {
return "SError";
case 0x301:
return "Bad SVC";
case 0xFFD:
return "Stack overflow";
case 0xFFE:
return "std::abort() called";
default:

View File

@@ -106,7 +106,7 @@ void load_stage2(const char *bct0) {
}
if (strlen(config.path) + 1 + sizeof(stage2_args_t) > CHAINLOADER_ARG_DATA_MAX_SIZE) {
fatal_error("Stage2's path name is too big!\n");
print(SCREEN_LOG_LEVEL_ERROR, "Stage2's path name is too big!\n");
}
if (!check_32bit_address_loadable(config.entrypoint)) {

View File

@@ -26,7 +26,6 @@
#include "car.h"
#include "btn.h"
#include "lib/log.h"
#include "lib/vsprintf.h"
#include "display/video_fb.h"
#include <inttypes.h>
@@ -113,11 +112,11 @@ __attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
/* Turn on the backlight after initializing the lfb */
/* to avoid flickering. */
display_backlight(true);
/* Override the global logging level. */
log_set_log_level(SCREEN_LOG_LEVEL_ERROR);
}
/* Override the global logging level. */
log_set_log_level(SCREEN_LOG_LEVEL_ERROR);
/* Display fatal error. */
va_list args;
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
@@ -138,3 +137,37 @@ __attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, u
return true;
return false;
}
/* Adapted from https://gist.github.com/ccbrown/9722406 */
void hexdump(const void* data, size_t size, uintptr_t addrbase) {
const uint8_t *d = (const uint8_t *)data;
char ascii[17];
ascii[16] = '\0';
for (size_t i = 0; i < size; i++) {
if (i % 16 == 0) {
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%0*" PRIXPTR ": | ", 2 * sizeof(addrbase), addrbase + i);
}
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%02X ", d[i]);
if (d[i] >= ' ' && d[i] <= '~') {
ascii[i % 16] = d[i];
} else {
ascii[i % 16] = '.';
}
if ((i+1) % 8 == 0 || i+1 == size) {
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, " ");
if ((i+1) % 16 == 0) {
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "| %s \n", ascii);
} else if (i+1 == size) {
ascii[(i+1) % 16] = '\0';
if ((i+1) % 16 <= 8) {
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, " ");
}
for (size_t j = (i+1) % 16; j < 16; j++) {
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, " ");
}
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "| %s \n", ascii);
}
}
}
}

View File

@@ -117,12 +117,15 @@ static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t s
overlaps_a(start, end, __start__, __end__);
}
void hexdump(const void* data, size_t size, uintptr_t addrbase);
__attribute__((noreturn)) void watchdog_reboot(void);
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0);
__attribute__((noreturn)) void reboot_to_self(void);
__attribute__((noreturn)) void wait_for_button_and_reboot(void);
__attribute__((noreturn)) void generic_panic(void);
__attribute__((noreturn)) void fatal_error(const char *fmt, ...);
#endif

View File

@@ -89,7 +89,7 @@ export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir)) \
$(AMS)/exosphere $(AMS)/exosphere/warmboot $(AMS)/exosphere/program/rebootstub \
$(AMS)/thermosphere $(AMS)/fusee/fusee-primary $(AMS)/sept/sept-primary \
$(AMS)/sept/sept-secondary $(AMS)/emummc $(AMS)/mesosphere $(AMS)/mesosphere/kernel_ldr $(KIPDIRS)
$(AMS)/sept/sept-secondary $(AMS)/emummc $(AMS)/mesosphere/kernel_ldr $(KIPDIRS)
export DEPSDIR := $(CURDIR)/$(BUILD)
@@ -100,7 +100,7 @@ KIPFILES := loader.kip ncm.kip pm.kip sm.kip ams_mitm.kip spl.kip boot.kip
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) fusee-primary.bin \
exosphere.bin warmboot.bin rebootstub.bin thermosphere.bin splash_screen.bmp \
sept-primary.bin sept-secondary_00.enc sept-secondary_01.enc emummc.kip \
sept-secondary_dev_00.enc sept-secondary_dev_01.enc mesosphere.bin kernel_ldr.bin $(KIPFILES)
sept-secondary_dev_00.enc sept-secondary_dev_01.enc kernel_ldr.bin $(KIPFILES)
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C

View File

@@ -13,7 +13,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef FUSEE_CAR_H
#define FUSEE_CAR_H
@@ -37,27 +37,23 @@
/* Clock and reset devices. */
typedef enum {
CARDEVICE_BPMP = ((0 << 5) | 0x1),
CARDEVICE_UARTA = ((0 << 5) | 0x6),
CARDEVICE_UARTB = ((0 << 5) | 0x7),
CARDEVICE_I2C1 = ((0 << 5) | 0xC),
CARDEVICE_USBD = ((0 << 5) | 0x16),
CARDEVICE_HOST1X = ((0 << 5) | 0x1C),
CARDEVICE_AHBDMA = ((1 << 5) | 0x1),
CARDEVICE_APBDMA = ((1 << 5) | 0x2),
CARDEVICE_KFUSE = ((1 << 5) | 0x8),
CARDEVICE_I2C5 = ((1 << 5) | 0xF),
CARDEVICE_UARTC = ((1 << 5) | 0x17),
CARDEVICE_USB2 = ((1 << 5) | 0x1A),
CARDEVICE_UARTA = ((0 << 5) | 0x6),
CARDEVICE_UARTB = ((0 << 5) | 0x7),
CARDEVICE_UARTC = ((1 << 5) | 0x17),
CARDEVICE_I2C1 = ((0 << 5) | 0xC),
CARDEVICE_I2C5 = ((1 << 5) | 0xF),
CARDEVICE_TZRAM = ((3 << 5) | 0x1E),
CARDEVICE_SE = ((3 << 5) | 0x1F),
CARDEVICE_HOST1X = ((0 << 5) | 0x1C),
CARDEVICE_TSEC = ((2 << 5) | 0x13),
CARDEVICE_SOR_SAFE = ((6 << 5) | 0x1E),
CARDEVICE_SOR0 = ((5 << 5) | 0x16),
CARDEVICE_SOR1 = ((5 << 5) | 0x17),
CARDEVICE_KFUSE = ((1 << 5) | 0x8),
CARDEVICE_CL_DVFS = ((4 << 5) | 0x1B),
CARDEVICE_CORESIGHT = ((2 << 5) | 0x9),
CARDEVICE_TSEC = ((2 << 5) | 0x13),
CARDEVICE_ACTMON = ((3 << 5) | 0x17),
CARDEVICE_TZRAM = ((3 << 5) | 0x1E),
CARDEVICE_SE = ((3 << 5) | 0x1F),
CARDEVICE_CL_DVFS = ((4 << 5) | 0x1B),
CARDEVICE_SOR0 = ((5 << 5) | 0x16),
CARDEVICE_SOR1 = ((5 << 5) | 0x17),
CARDEVICE_SOR_SAFE = ((6 << 5) | 0x1E),
CARDEVICE_ACTMON = ((3 << 5) | 0x17),
CARDEVICE_BPMP = ((0 << 5) | 0x1)
} CarDevice;
/* Clock/Reset Controller (CLK_RST_CONTROLLER_) regs */
@@ -101,31 +97,31 @@ typedef struct {
uint32_t pllc_out;
uint32_t pllc_misc0;
uint32_t pllc_misc1;
/* PLLM 0x90-0x9c */
uint32_t pllm_base;
uint32_t pllm_out;
uint32_t pllm_misc1;
uint32_t pllm_misc2;
/* PLLP 0xa0-0xac */
uint32_t pllp_base;
uint32_t pllp_outa;
uint32_t pllp_outb;
uint32_t pllp_misc;
/* PLLA 0xb0-0xbc */
uint32_t plla_base;
uint32_t plla_out;
uint32_t plla_misc0;
uint32_t plla_misc1;
/* PLLU 0xc0-0xcc */
uint32_t pllu_base;
uint32_t pllu_out;
uint32_t pllu_misc1;
uint32_t pllu_misc2;
/* PLLD 0xd0-0xdc */
uint32_t plld_base;
uint32_t plld_out;
@@ -135,13 +131,13 @@ typedef struct {
/* PLLX 0xe0-0xe4 */
uint32_t pllx_base;
uint32_t pllx_misc;
/* PLLE 0xe8-0xf4 */
uint32_t plle_base;
uint32_t plle_misc;
uint32_t plle_ss_cntl1;
uint32_t plle_ss_cntl2;
uint32_t lvl2_clk_gate_ovra; /* _LVL2_CLK_GATE_OVRA_0, 0xf8 */
uint32_t lvl2_clk_gate_ovrb; /* _LVL2_CLK_GATE_OVRB_0, 0xfc */
@@ -192,7 +188,7 @@ typedef struct {
uint32_t _0x1e0[5];
uint32_t clk_source_tsec; /* _CLK_SOURCE_TSEC_0, 0x1f4 */
uint32_t _0x1f8;
uint32_t clk_spare2; /* _CLK_SPARE2_0, 0x1fc */
uint32_t _0x200[32];
@@ -261,7 +257,7 @@ typedef struct {
uint32_t lvl2_clk_gate_ovrc; /* _LVL2_CLK_GATE_OVRC, 0x3a0 */
uint32_t lvl2_clk_gate_ovrd; /* _LVL2_CLK_GATE_OVRD, 0x3a4 */
uint32_t _0x3a8[2];
uint32_t _0x3b0;
uint32_t clk_source_mselect; /* _CLK_SOURCE_MSELECT_0, 0x3b4 */
uint32_t clk_source_tsensor; /* _CLK_SOURCE_TSENSOR_0, 0x3b8 */
@@ -375,13 +371,13 @@ typedef struct {
uint32_t spare_reg0; /* _SPARE_REG0_0, 0x55c */
uint32_t audio_sync_clk_dmic1; /* _AUDIO_SYNC_CLK_DMIC1_0, 0x560 */
uint32_t audio_sync_clk_dmic2; /* _AUDIO_SYNC_CLK_DMIC2_0, 0x564 */
uint32_t _0x568[2];
uint32_t plld2_ss_cfg; /* _PLLD2_SS_CFG, 0x570 */
uint32_t plld2_ss_ctrl1; /* _PLLD2_SS_CTRL1_0, 0x574 */
uint32_t plld2_ss_ctrl2; /* _PLLD2_SS_CTRL2_0, 0x578 */
uint32_t _0x57c[5];
uint32_t plldp_base; /* _PLLDP_BASE, 0x590*/
uint32_t plldp_misc; /* _PLLDP_MISC, 0x594 */
uint32_t plldp_ss_cfg; /* _PLLDP_SS_CFG, 0x598 */
@@ -403,7 +399,7 @@ typedef struct {
uint32_t pllx_misc4; /* _PLLX_MISC_4_0, 0x5f0 */
uint32_t pllx_misc5; /* _PLLX_MISC_5_0, 0x5f4 */
uint32_t _0x5f8[2];
uint32_t clk_source_xusb_core_host; /* _CLK_SOURCE_XUSB_CORE_HOST_0, 0x600 */
uint32_t clk_source_xusb_falcon; /* _CLK_SOURCE_XUSB_FALCON_0, 0x604 */
uint32_t clk_source_xusb_fs; /* _CLK_SOURCE_XUSB_FS_0, 0x608 */
@@ -432,7 +428,7 @@ typedef struct {
uint32_t clk_source_uart_fst_mipi_cal; /* _CLK_SOURCE_UART_FST_MIPI_CAL_0, 0x66c */
uint32_t _0x670[2];
uint32_t clk_source_vic; /* _CLK_SOURCE_VIC_0, 0x678 */
uint32_t pllp_outc; /* _PLLP_OUTC_0, 0x67c */
uint32_t pllp_misc1; /* _PLLP_MISC1_0, 0x680 */
uint32_t _0x684[2];
@@ -443,14 +439,14 @@ typedef struct {
uint32_t clk_source_nvdec; /* _CLK_SOURCE_NVDEC_0, 0x698 */
uint32_t clk_source_nvjpg; /* _CLK_SOURCE_NVJPG_0, 0x69c */
uint32_t clk_source_nvenc; /* _CLK_SOURCE_NVENC_0, 0x6a0 */
uint32_t plla1_base; /* _PLLA1_BASE_0, 0x6a4 */
uint32_t plla1_misc0; /* _PLLA1_MISC_0_0, 0x6a8 */
uint32_t plla1_misc1; /* _PLLA1_MISC_1_0, 0x6ac */
uint32_t plla1_misc2; /* _PLLA1_MISC_2_0, 0x6b0 */
uint32_t plla1_misc3; /* _PLLA1_MISC_3_0, 0x6b4 */
uint32_t audio_sync_clk_dmic3; /* _AUDIO_SYNC_CLK_DMIC3_0, 0x6b8 */
uint32_t clk_source_dmic3; /* _CLK_SOURCE_DMIC3_0, 0x6bc */
uint32_t clk_source_ape; /* _CLK_SOURCE_APE_0, 0x6c0 */
uint32_t clk_source_qspi; /* _CLK_SOURCE_QSPI_0, 0x6c4 */
@@ -459,11 +455,11 @@ typedef struct {
uint32_t clk_source_pex_sata_usb_rx_byp; /* _CLK_SOURCE_PEX_SATA_USB_RX_BYP_0, 0x6d0 */
uint32_t clk_source_maud; /* _CLK_SOURCE_MAUD_0, 0x6d4 */
uint32_t clk_source_tsecb; /* _CLK_SOURCE_TSECB_0, 0x6d8 */
uint32_t clk_cpug_misc1; /* _CLK_CPUG_MISC1_0, 0x6dc */
uint32_t aclk_burst_policy; /* _ACLK_BURST_POLICY_0, 0x6e0 */
uint32_t super_aclk_divider; /* _SUPER_ACLK_DIVIDER_0, 0x6e4 */
uint32_t nvenc_super_clk_divider; /* _NVENC_SUPER_CLK_DIVIDER_0, 0x6e8 */
uint32_t vi_super_clk_divider; /* _VI_SUPER_CLK_DIVIDER_0, 0x6ec */
uint32_t vic_super_clk_divider; /* _VIC_SUPER_CLK_DIVIDER_0, 0x6f0 */
@@ -474,7 +470,7 @@ typedef struct {
uint32_t se_super_clk_divider; /* _SE_SUPER_CLK_DIVIDER_0, 0x704 */
uint32_t tsec_super_clk_divider; /* _TSEC_SUPER_CLK_DIVIDER_0, 0x708 */
uint32_t tsecb_super_clk_divider; /* _TSECB_SUPER_CLK_DIVIDER_0, 0x70c */
uint32_t clk_source_uartape; /* _CLK_SOURCE_UARTAPE_0, 0x710 */
uint32_t clk_cpug_misc2; /* _CLK_CPUG_MISC2_0, 0x714 */
uint32_t clk_source_dbgapb; /* _CLK_SOURCE_DBGAPB_0, 0x718 */
@@ -488,7 +484,7 @@ typedef struct {
uint32_t sdmmc4_pllc4_out0_shaper_ctrl; /* _SDMMC4_PLLC4_OUT0_SHAPER_CTRL_0, 0x738 */
uint32_t sdmmc4_pllc4_out1_shaper_ctrl; /* _SDMMC4_PLLC4_OUT1_SHAPER_CTRL_0, 0x73c */
uint32_t sdmmc4_pllc4_out2_shaper_ctrl; /* _SDMMC4_PLLC4_OUT2_SHAPER_CTRL_0, 0x740 */
uint32_t sdmmc4_div_clk_shaper_ctrl; /* _SDMMC4_DIV_CLK_SHAPER_CTRL_0, 0x744 */
uint32_t sdmmc4_div_clk_shaper_ctrl; /* _SDMMC4_DIV_CLK_SHAPER_CTRL_0, 0x744 */
} tegra_car_t;
static inline volatile tegra_car_t *car_get_regs(void) {

View File

@@ -18,9 +18,67 @@
#include <string.h>
#include "device_partition.h"
int device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors) {
int device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors)
{
int rc;
if (!devpart->initialized) {
rc = devpart->initializer(devpart);
if (rc != 0) {
return rc;
}
}
if ((devpart->read_cipher != NULL) && (devpart->crypto_mode != DevicePartitionCryptoMode_None)) {
for (uint64_t i = 0; i < num_sectors; i += devpart->crypto_work_buffer_num_sectors) {
uint64_t n = (i + devpart->crypto_work_buffer_num_sectors > num_sectors) ? (num_sectors - i) : devpart->crypto_work_buffer_num_sectors;
rc = devpart->reader(devpart, devpart->crypto_work_buffer, sector + i, n);
if (rc != 0) {
return rc;
}
rc = devpart->read_cipher(devpart, sector + i, n);
if (rc != 0) {
return rc;
}
memcpy(dst + (size_t)(devpart->sector_size * i), devpart->crypto_work_buffer, (size_t)(devpart->sector_size * n));
}
return 0;
} else {
return devpart->reader(devpart, dst, sector, num_sectors);
}
}
int device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors)
{
int rc;
if (!devpart->initialized) {
rc = devpart->initializer(devpart);
if (rc != 0) {
return rc;
}
}
if ((devpart->write_cipher != NULL) && (devpart->crypto_mode != DevicePartitionCryptoMode_None)) {
for (uint64_t i = 0; i < num_sectors; i += devpart->crypto_work_buffer_num_sectors) {
uint64_t n = (i + devpart->crypto_work_buffer_num_sectors > num_sectors) ? (num_sectors - i) : devpart->crypto_work_buffer_num_sectors;
memcpy(devpart->crypto_work_buffer, src + (size_t)(devpart->sector_size * i), (size_t)(devpart->sector_size * n));
rc = devpart->write_cipher(devpart, sector + i, n);
if (rc != 0) {
return rc;
}
rc = devpart->writer(devpart, devpart->crypto_work_buffer, sector + i, n);
if (rc != 0) {
return rc;
}
}
return 0;
} else {
return devpart->writer(devpart, src, sector, num_sectors);
}
}
int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors, const char *origin_path, int num_parts, uint64_t part_limit)
{
int rc = 0;
uint64_t target_sector = sector;
char target_path[0x300 + 1] = {0};
/* Perform initialization steps, if necessary. */
if (!devpart->initialized) {
@@ -30,37 +88,33 @@ int device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t
}
}
/* Handle emulation. */
if (devpart->is_emulated) {
/* Prepare the right file path if using file mode. */
if (devpart->emu_use_file) {
int num_parts = devpart->emu_num_parts;
uint64_t part_limit = devpart->emu_part_limit;
/* Prepare the right file path if using file mode. */
if (devpart->emu_use_file && (origin_path != NULL)) {
/* Handle data in multiple parts, if necessary. */
if (num_parts > 0) {
int target_part = 0;
uint64_t data_offset = sector * devpart->sector_size;
/* Handle data in multiple parts, if necessary. */
if (num_parts > 0) {
int target_part = 0;
char target_path[0x300 + 1] = {0};
uint64_t data_offset = sector * devpart->sector_size;
if (data_offset >= part_limit) {
uint64_t data_offset_aligned = (data_offset + (part_limit - 1)) & ~(part_limit - 1);
target_part = (data_offset_aligned == data_offset) ? (data_offset / part_limit) : (data_offset_aligned / part_limit) - 1;
target_sector = (data_offset - (target_part * part_limit)) / devpart->sector_size;
/* Target part is invalid. */
if (target_part > num_parts) {
return -1;
}
if (data_offset >= part_limit) {
uint64_t data_offset_aligned = (data_offset + (part_limit - 1)) & ~(part_limit - 1);
target_part = (data_offset_aligned == data_offset) ? (data_offset / part_limit) : (data_offset_aligned / part_limit) - 1;
target_sector = (data_offset - (target_part * part_limit)) / devpart->sector_size;
/* Target part is invalid. */
if (target_part > num_parts) {
return -1;
}
/* Treat the path as a folder with each part inside. */
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", devpart->emu_root_path, target_part);
/* Update the target file path. */
strcpy(devpart->emu_file_path, target_path);
}
/* Treat the path as a folder with each part inside. */
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part);
} else {
/* If there are no parts, copy the origin path directly. */
strcpy(target_path, origin_path);
}
/* Update the target file path. */
devpart->emu_file_path = target_path;
}
/* Read the partition data. */
@@ -93,9 +147,11 @@ int device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t
return rc;
}
int device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors) {
int emu_device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors, const char *origin_path, int num_parts, uint64_t part_limit)
{
int rc = 0;
uint64_t target_sector = sector;
char target_path[0x300 + 1] = {0};
/* Perform initialization steps, if necessary. */
if (!devpart->initialized) {
@@ -105,37 +161,33 @@ int device_partition_write_data(device_partition_t *devpart, const void *src, ui
}
}
/* Handle emulation. */
if (devpart->is_emulated) {
/* Prepare the right file path if using file mode. */
if (devpart->emu_use_file) {
int num_parts = devpart->emu_num_parts;
uint64_t part_limit = devpart->emu_part_limit;
/* Prepare the right file path if using file mode. */
if (devpart->emu_use_file && (origin_path != NULL)) {
/* Handle data in multiple parts, if necessary. */
if (num_parts > 0) {
int target_part = 0;
uint64_t data_offset = sector * devpart->sector_size;
/* Handle data in multiple parts, if necessary. */
if (num_parts > 0) {
int target_part = 0;
char target_path[0x300 + 1] = {0};
uint64_t data_offset = sector * devpart->sector_size;
if (data_offset >= part_limit) {
uint64_t data_offset_aligned = (data_offset + (part_limit - 1)) & ~(part_limit - 1);
target_part = (data_offset_aligned == data_offset) ? (data_offset / part_limit) : (data_offset_aligned / part_limit) - 1;
target_sector = (data_offset - (target_part * part_limit)) / devpart->sector_size;
/* Target part is invalid. */
if (target_part > num_parts) {
return -1;
}
if (data_offset >= part_limit) {
uint64_t data_offset_aligned = (data_offset + (part_limit - 1)) & ~(part_limit - 1);
target_part = (data_offset_aligned == data_offset) ? (data_offset / part_limit) : (data_offset_aligned / part_limit) - 1;
target_sector = (data_offset - (target_part * part_limit)) / devpart->sector_size;
/* Target part is invalid. */
if (target_part > num_parts) {
return -1;
}
/* Treat the path as a folder with each part inside. */
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", devpart->emu_root_path, target_part);
/* Update the target file path. */
strcpy(devpart->emu_file_path, target_path);
}
/* Treat the path as a folder with each part inside. */
snprintf(target_path, sizeof(target_path) - 1, "%s/%02d", origin_path, target_part);
} else {
/* If there are no parts, copy the origin path directly. */
strcpy(target_path, origin_path);
}
/* Update the target file path. */
devpart->emu_file_path = target_path;
}
/* Write the partition data. */

View File

@@ -67,16 +67,13 @@ typedef struct device_partition_t {
uint8_t __attribute__((aligned(16))) iv[DEVPART_IV_MAX_SIZE]; /* IV. */
bool initialized;
/* Emulation only. */
bool is_emulated;
char *emu_file_path; /* Emulated device file path. */
bool emu_use_file;
char emu_root_path[0x100 + 1];
char emu_file_path[0x300 + 1];
int emu_num_parts;
uint64_t emu_part_limit;
} device_partition_t;
int device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors);
int device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors);
int emu_device_partition_read_data(device_partition_t *devpart, void *dst, uint64_t sector, uint64_t num_sectors, const char *origin_path, int num_parts, uint64_t part_limit);
int emu_device_partition_write_data(device_partition_t *devpart, const void *src, uint64_t sector, uint64_t num_sectors, const char *origin_path, int num_parts, uint64_t part_limit);
#endif

View File

@@ -0,0 +1,489 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/iosupport.h>
#include <sys/param.h>
#include <unistd.h>
#include "emu_dev.h"
#include "utils.h"
static int emudev_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode);
static int emudev_close(struct _reent *r, void *fd);
static ssize_t emudev_write(struct _reent *r, void *fd, const char *ptr, size_t len);
static ssize_t emudev_read(struct _reent *r, void *fd, char *ptr, size_t len);
static off_t emudev_seek(struct _reent *r, void *fd, off_t pos, int whence);
static int emudev_fstat(struct _reent *r, void *fd, struct stat *st);
static int emudev_stat(struct _reent *r, const char *file, struct stat *st);
static int emudev_fsync(struct _reent *r, void *fd);
typedef struct emudev_device_t {
devoptab_t devoptab;
char origin_path[0x300+1];
int num_parts;
uint64_t part_limit;
uint8_t *tmp_sector;
device_partition_t devpart;
char name[32+1];
char root_path[34+1];
bool setup, registered;
} emudev_device_t;
typedef struct emudev_file_t {
emudev_device_t *device;
int open_flags;
uint64_t offset;
} emudev_file_t;
static emudev_device_t g_emudev_devices[EMUDEV_MAX_DEVICES] = {0};
static devoptab_t g_emudev_devoptab = {
.structSize = sizeof(emudev_file_t),
.open_r = emudev_open,
.close_r = emudev_close,
.write_r = emudev_write,
.read_r = emudev_read,
.seek_r = emudev_seek,
.fstat_r = emudev_fstat,
.stat_r = emudev_stat,
.fsync_r = emudev_fsync,
.deviceData = NULL,
};
static emudev_device_t *emudev_find_device(const char *name) {
for (size_t i = 0; i < EMUDEV_MAX_DEVICES; i++) {
if (g_emudev_devices[i].setup && strcmp(g_emudev_devices[i].name, name) == 0) {
return &g_emudev_devices[i];
}
}
return NULL;
}
int emudev_mount_device(const char *name, const device_partition_t *devpart, const char *origin_path, int num_parts, uint64_t part_limit) {
emudev_device_t *device = NULL;
if (name[0] == '\0' || devpart == NULL) {
errno = EINVAL;
return -1;
}
if (strlen(name) > 32) {
errno = ENAMETOOLONG;
return -1;
}
if (emudev_find_device(name) != NULL) {
errno = EEXIST; /* Device already exists */
return -1;
}
/* Find an unused slot. */
for (size_t i = 0; i < EMUDEV_MAX_DEVICES; i++) {
if (!g_emudev_devices[i].setup) {
device = &g_emudev_devices[i];
break;
}
}
if (device == NULL) {
errno = ENOMEM;
return -1;
}
memset(device, 0, sizeof(emudev_device_t));
device->devoptab = g_emudev_devoptab;
device->devpart = *devpart;
strcpy(device->name, name);
strcpy(device->root_path, name);
strcat(device->root_path, ":/");
/* Copy the file path for file mode. */
if (devpart->emu_use_file)
strcpy(device->origin_path, origin_path);
device->num_parts = num_parts;
device->part_limit = part_limit;
device->devoptab.name = device->name;
device->devoptab.deviceData = device;
/* Initialize immediately. */
int rc = device->devpart.initializer(&device->devpart);
if (rc != 0) {
errno = rc;
return -1;
}
/* Allocate memory for our intermediate sector. */
device->tmp_sector = (uint8_t *)malloc(devpart->sector_size);
if (device->tmp_sector == NULL) {
errno = ENOMEM;
return -1;
}
device->setup = true;
device->registered = false;
return 0;
}
int emudev_register_device(const char *name) {
emudev_device_t *device = emudev_find_device(name);
if (device == NULL) {
errno = ENOENT;
return -1;
}
if (device->registered) {
/* Do nothing if the device is already registered. */
return 0;
}
if (AddDevice(&device->devoptab) == -1) {
errno = ENOMEM;
return -1;
} else {
device->registered = true;
return 0;
}
}
int emudev_unregister_device(const char *name) {
emudev_device_t *device = emudev_find_device(name);
char drname[40];
if (device == NULL) {
errno = ENOENT;
return -1;
}
if (!device->registered) {
/* Do nothing if the device is not registered. */
return 0;
}
strcpy(drname, name);
strcat(drname, ":");
if (RemoveDevice(drname) == -1) {
errno = ENOENT;
return -1;
} else {
device->registered = false;
return 0;
}
}
int emudev_unmount_device(const char *name) {
int rc;
emudev_device_t *device = emudev_find_device(name);
if (device == NULL) {
errno = ENOENT;
return -1;
}
rc = emudev_unregister_device(name);
if (rc == -1) {
return -1;
}
free(device->tmp_sector);
device->devpart.finalizer(&device->devpart);
memset(device, 0, sizeof(emudev_device_t));
return 0;
}
int emudev_unmount_all(void) {
for (size_t i = 0; i < EMUDEV_MAX_DEVICES; i++) {
int rc = emudev_unmount_device(g_emudev_devices[i].name);
if (rc != 0) {
return rc;
}
}
return 0;
}
static int emudev_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode) {
(void)mode;
emudev_file_t *f = (emudev_file_t *)fileStruct;
emudev_device_t *device = (emudev_device_t *)(r->deviceData);
/* Only allow "device:/". */
if (strcmp(path, device->root_path) != 0) {
r->_errno = ENOENT;
return -1;
}
/* Forbid some flags that we explicitly don't support.*/
if (flags & (O_APPEND | O_TRUNC | O_EXCL)) {
r->_errno = EINVAL;
return -1;
}
memset(f, 0, sizeof(emudev_file_t));
f->device = device;
f->open_flags = flags;
return 0;
}
static int emudev_close(struct _reent *r, void *fd) {
(void)r;
emudev_file_t *f = (emudev_file_t *)fd;
memset(f, 0, sizeof(emudev_file_t));
return 0;
}
static ssize_t emudev_write(struct _reent *r, void *fd, const char *ptr, size_t len) {
emudev_file_t *f = (emudev_file_t *)fd;
emudev_device_t *device = f->device;
size_t sector_size = device->devpart.sector_size;
uint64_t sector_begin = f->offset / sector_size;
uint64_t sector_end = (f->offset + len + sector_size - 1) / sector_size;
uint64_t sector_end_aligned;
uint64_t current_sector = sector_begin;
const uint8_t *data = (const uint8_t *)ptr;
int no = 0;
if (sector_end >= device->devpart.num_sectors) {
len = (size_t)(sector_size * device->devpart.num_sectors - f->offset);
sector_end = device->devpart.num_sectors;
}
sector_end_aligned = sector_end - ((f->offset + len) % sector_size != 0 ? 1 : 0);
if (len == 0) {
return 0;
}
/* Unaligned at the start, we need to read the sector and incorporate the data. */
if (f->offset % sector_size != 0) {
size_t nb = (size_t)(len <= (sector_size - (f->offset % sector_size)) ? len : sector_size - (f->offset % sector_size));
no = emu_device_partition_read_data(&device->devpart, device->tmp_sector, sector_begin, 1, device->origin_path, device->num_parts, device->part_limit);
if (no != 0) {
r->_errno = no;
return -1;
}
memcpy(device->tmp_sector + (f->offset % sector_size), data, nb);
no = emu_device_partition_write_data(&device->devpart, device->tmp_sector, sector_begin, 1, device->origin_path, device->num_parts, device->part_limit);
if (no != 0) {
r->_errno = no;
return -1;
}
/* Advance */
data += sector_size - (f->offset % sector_size);
current_sector++;
}
/* Check if we're already done (otherwise this causes a bug in handling the last sector of the range). */
if (current_sector == sector_end) {
f->offset += len;
return len;
}
/* Write all of the sector-aligned data. */
if (current_sector != sector_end_aligned) {
no = emu_device_partition_write_data(&device->devpart, data, current_sector, sector_end_aligned - current_sector, device->origin_path, device->num_parts, device->part_limit);
if (no != 0) {
r->_errno = no;
return -1;
}
}
data += sector_size * (sector_end_aligned - current_sector);
current_sector = sector_end_aligned;
/* Unaligned at the end, we need to read the sector and incorporate the data. */
if (sector_end != sector_end_aligned) {
no = emu_device_partition_read_data(&device->devpart, device->tmp_sector, sector_end_aligned, 1, device->origin_path, device->num_parts, device->part_limit);
if (no != 0) {
r->_errno = no;
return -1;
}
memcpy(device->tmp_sector, data, (size_t)((f->offset + len) % sector_size));
no = emu_device_partition_write_data(&device->devpart, device->tmp_sector, sector_end_aligned, 1, device->origin_path, device->num_parts, device->part_limit);
if (no != 0) {
r->_errno = no;
return -1;
}
/* Advance */
data += sector_size - ((f->offset + len) % sector_size);
current_sector++;
}
f->offset += len;
return len;
}
static ssize_t emudev_read(struct _reent *r, void *fd, char *ptr, size_t len) {
emudev_file_t *f = (emudev_file_t *)fd;
emudev_device_t *device = f->device;
size_t sector_size = device->devpart.sector_size;
uint64_t sector_begin = f->offset / sector_size;
uint64_t sector_end = (f->offset + len + sector_size - 1) / sector_size;
uint64_t sector_end_aligned;
uint64_t current_sector = sector_begin;
uint8_t *data = (uint8_t *)ptr;
int no = 0;
if (sector_end >= device->devpart.num_sectors) {
len = (size_t)(sector_size * device->devpart.num_sectors - f->offset);
sector_end = device->devpart.num_sectors;
}
sector_end_aligned = sector_end - ((f->offset + len) % sector_size != 0 ? 1 : 0);
if (len == 0) {
return 0;
}
/* Unaligned at the start, we need to read the sector and incorporate the data. */
if (f->offset % sector_size != 0) {
size_t nb = (size_t)(len <= (sector_size - (f->offset % sector_size)) ? len : sector_size - (f->offset % sector_size));
no = emu_device_partition_read_data(&device->devpart, device->tmp_sector, sector_begin, 1, device->origin_path, device->num_parts, device->part_limit);
if (no != 0) {
r->_errno = no;
return -1;
}
memcpy(data, device->tmp_sector + (f->offset % sector_size), nb);
/* Advance */
data += sector_size - (f->offset % sector_size);
current_sector++;
}
/* Check if we're already done (otherwise this causes a bug in handling the last sector of the range). */
if (current_sector == sector_end) {
f->offset += len;
return len;
}
/* Read all of the sector-aligned data. */
if (current_sector != sector_end_aligned) {
no = emu_device_partition_read_data(&device->devpart, data, current_sector, sector_end_aligned - current_sector, device->origin_path, device->num_parts, device->part_limit);
if (no != 0) {
r->_errno = no;
return -1;
}
}
data += sector_size * (sector_end_aligned - current_sector);
current_sector = sector_end_aligned;
/* Unaligned at the end, we need to read the sector and incorporate the data. */
if (sector_end != sector_end_aligned) {
no = emu_device_partition_read_data(&device->devpart, device->tmp_sector, sector_end_aligned, 1, device->origin_path, device->num_parts, device->part_limit);
if (no != 0) {
r->_errno = no;
return -1;
}
memcpy(data, device->tmp_sector, (size_t)((f->offset + len) % sector_size));
/* Advance */
data += sector_size - ((f->offset + len) % sector_size);
current_sector++;
}
f->offset += len;
return len;
}
static off_t emudev_seek(struct _reent *r, void *fd, off_t pos, int whence) {
emudev_file_t *f = (emudev_file_t *)fd;
emudev_device_t *device = f->device;
uint64_t off;
switch (whence) {
case SEEK_SET:
off = 0;
break;
case SEEK_CUR:
off = f->offset;
break;
case SEEK_END:
off = device->devpart.num_sectors * device->devpart.sector_size;
break;
default:
r->_errno = EINVAL;
return -1;
}
if (pos < 0 && pos + off < 0) {
/* don't allow seek to before the beginning of the file */
r->_errno = EINVAL;
return -1;
}
f->offset = (uint64_t)(pos + off);
return (off_t)(pos + off);
}
static void emudev_stat_impl(emudev_device_t *device, struct stat *st) {
memset(st, 0, sizeof(struct stat));
st->st_size = (off_t)(device->devpart.num_sectors * device->devpart.sector_size);
st->st_nlink = 1;
st->st_blksize = device->devpart.sector_size;
st->st_blocks = st->st_size / st->st_blksize;
st->st_mode = S_IFBLK | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
}
static int emudev_fstat(struct _reent *r, void *fd, struct stat *st) {
(void)r;
emudev_file_t *f = (emudev_file_t *)fd;
emudev_device_t *device = f->device;
emudev_stat_impl(device, st);
return 0;
}
static int emudev_stat(struct _reent *r, const char *file, struct stat *st) {
emudev_device_t *device = (emudev_device_t *)(r->deviceData);
if (strcmp(file, device->root_path) != 0) {
r->_errno = ENOENT;
return -1;
}
emudev_stat_impl(device, st);
return 0;
}
static int emudev_fsync(struct _reent *r, void *fd) {
/* Nothing to do. */
(void)r;
(void)fd;
return 0;
}

View File

@@ -13,14 +13,22 @@
* 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
#ifndef FUSEE_EMU_DEV_H
#define FUSEE_EMU_DEV_H
#if defined(ATMOSPHERE_ARCH_ARM64)
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "device_partition.h"
#include "kern_libc_config.arch.arm64.h"
#define EMUDEV_MAX_DEVICES 16
#else
int emudev_mount_device(const char *name, const device_partition_t *devpart, const char *origin_path, int num_parts, uint64_t part_limit);
int emudev_register_device(const char *name);
int emudev_unregister_device(const char *name);
int emudev_unmount_device(const char *name); /* also unregisters. */
#error "Unknown architecture for libc"
int emudev_unmount_all(void);
#endif

View File

@@ -14,7 +14,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <inttypes.h>
#include "exception_handlers.h"
@@ -23,7 +22,7 @@
#include "lib/log.h"
#define CODE_DUMP_SIZE 0x30
#define STACK_DUMP_SIZE 0x30
#define STACK_DUMP_SIZE 0x60
extern const uint32_t exception_handler_table[];
@@ -36,40 +35,6 @@ static const char *register_names[] = {
"SP", "LR", "PC", "CPSR",
};
/* Adapted from https://gist.github.com/ccbrown/9722406 */
static void hexdump(const void* data, size_t size, uintptr_t addrbase, char* strbuf) {
const uint8_t *d = (const uint8_t *)data;
char ascii[17] = {0};
ascii[16] = '\0';
for (size_t i = 0; i < size; i++) {
if (i % 16 == 0) {
strbuf += sprintf(strbuf, "%0*" PRIXPTR ": | ", 2 * sizeof(addrbase), addrbase + i);
}
strbuf += sprintf(strbuf, "%02X ", d[i]);
if (d[i] >= ' ' && d[i] <= '~') {
ascii[i % 16] = d[i];
} else {
ascii[i % 16] = '.';
}
if ((i+1) % 8 == 0 || i+1 == size) {
strbuf += sprintf(strbuf, " ");
if ((i+1) % 16 == 0) {
strbuf += sprintf(strbuf, "| %s \n", ascii);
} else if (i+1 == size) {
ascii[(i+1) % 16] = '\0';
if ((i+1) % 16 <= 8) {
strbuf += sprintf(strbuf, " ");
}
for (size_t j = (i+1) % 16; j < 16; j++) {
strbuf += sprintf(strbuf, " ");
}
strbuf += sprintf(strbuf, "| %s \n", ascii);
}
}
}
}
void setup_exception_handlers(void) {
volatile uint32_t *bpmp_exception_handler_table = (volatile uint32_t *)0x6000F200;
for (int i = 0; i < 8; i++) {
@@ -80,40 +45,38 @@ void setup_exception_handlers(void) {
}
void exception_handler_main(uint32_t *registers, unsigned int exception_type) {
char exception_log[0x400] = {0};
uint8_t code_dump[CODE_DUMP_SIZE] = {0};
uint8_t stack_dump[STACK_DUMP_SIZE] = {0};
size_t code_dump_size = 0;
size_t stack_dump_size = 0;
uint8_t code_dump[CODE_DUMP_SIZE];
uint8_t stack_dump[STACK_DUMP_SIZE];
size_t code_dump_size;
size_t stack_dump_size;
uint32_t pc = registers[15];
uint32_t cpsr = registers[16];
uint32_t instr_addr = pc + ((cpsr & 0x20) ? 2 : 4) - CODE_DUMP_SIZE;
sprintf(exception_log, "An exception occured!\n");
print(SCREEN_LOG_LEVEL_ERROR, "\nSomething went wrong...\n");
code_dump_size = safecpy(code_dump, (const void *)instr_addr, CODE_DUMP_SIZE);
stack_dump_size = safecpy(stack_dump, (const void *)registers[13], STACK_DUMP_SIZE);
sprintf(exception_log + strlen(exception_log), "\nException type: %s\n", exception_names[exception_type]);
sprintf(exception_log + strlen(exception_log), "\nRegisters:\n");
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nException type: %s\n",
exception_names[exception_type]);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nRegisters:\n\n");
/* Print r0 to pc. */
for (int i = 0; i < 16; i += 2) {
sprintf(exception_log + strlen(exception_log), "%-7s%08"PRIX32" %-7s%08"PRIX32"\n",
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%-7s%08"PRIX32" %-7s%08"PRIX32"\n",
register_names[i], registers[i], register_names[i+1], registers[i+1]);
}
/* Print cpsr. */
sprintf(exception_log + strlen(exception_log), "%-7s%08"PRIX32"\n", register_names[16], registers[16]);
/* Print code and stack regions. */
sprintf(exception_log + strlen(exception_log), "\nCode dump:\n");
hexdump(code_dump, code_dump_size, instr_addr, exception_log + strlen(exception_log));
sprintf(exception_log + strlen(exception_log), "\nStack dump:\n");
hexdump(stack_dump, stack_dump_size, registers[13], exception_log + strlen(exception_log));
sprintf(exception_log + strlen(exception_log), "\n");
/* Throw fatal error with the full exception log. */
fatal_error(exception_log);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "%-7s%08"PRIX32"\n", register_names[16], registers[16]);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nCode dump:\n");
hexdump(code_dump, code_dump_size, instr_addr);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nStack dump:\n");
hexdump(stack_dump, stack_dump_size, registers[13]);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\n");
fatal_error("An exception occurred!\n");
}

View File

@@ -302,6 +302,7 @@ int fsdev_register_keys(const char *name, unsigned int target_firmware, BisParti
return 0;
}
int fsdev_unmount_all(void) {
for (size_t i = 0; i < FF_VOLUMES; i++) {
int ret = fsdev_unmount_device(g_fsdev_devices[i].name);

View File

@@ -112,3 +112,42 @@ int gpt_iterate_through_entries(FILE *disk, size_t sector_size, gpt_entry_iterat
return 0;
}
int gpt_iterate_through_emu_entries(FILE *disk, size_t sector_size, gpt_emu_entry_iterator_t callback, void *param, const char *origin_path, int num_parts, uint64_t part_limit) {
efi_header_t hdr;
efi_entry_t entry;
size_t offset = 2 * 512; /* Sector #2. */
size_t delta;
/* Get the header. */
if (gpt_get_header(&hdr, disk, sector_size) == -1) {
return -1;
}
/* Seek to the entry table. */
if (fseek(disk, sector_size * hdr.entries_first_lba - offset, SEEK_CUR) != 0) {
return -1;
}
offset = sector_size * hdr.entries_first_lba;
delta = hdr.entry_size - sizeof(efi_entry_t);
/* Iterate through the entries. */
for (uint32_t i = 0; i < hdr.entry_count; i++) {
if (!fread(&entry, sizeof(efi_entry_t), 1, disk)) {
return -1;
}
if (callback(&entry, param, offset, disk, origin_path, num_parts, part_limit) != 0) {
return -1;
}
if (delta != 0 && fseek(disk, delta, SEEK_CUR) != 0) {
return -1;
}
offset += hdr.entry_size;
}
return 0;
}

View File

@@ -56,5 +56,6 @@ typedef int (*gpt_emu_entry_iterator_t)(const efi_entry_t *entry, void *param, s
int gpt_get_header(efi_header_t *out, FILE *disk, size_t sector_size);
int gpt_iterate_through_entries(FILE *disk, size_t sector_size, gpt_entry_iterator_t callback, void *param);
int gpt_iterate_through_emu_entries(FILE *disk, size_t sector_size, gpt_emu_entry_iterator_t callback, void *param, const char *origin_path, int num_parts, uint64_t part_limit);
#endif

View File

@@ -971,6 +971,12 @@ void package2_patch_kernel(void *_kernel, size_t *kernel_size, bool is_sd_kernel
const uint32_t kernel_ldr_offset = *((volatile uint64_t *)((uintptr_t)_kernel + kernel_info->embedded_ini_ptr + 8));
memcpy((void *)((uintptr_t)_kernel + kernel_ldr_offset), kernel_ldr_bin, kernel_ldr_bin_size);
/* Set target firmware for our kernel loader. */
uint32_t *kldr_u32 = (uint32_t *)((uintptr_t)_kernel + kernel_ldr_offset);
if (kldr_u32[1] == 0x30444C4D) {
kldr_u32[2] = target_firmware;
}
/* Update size. */
*kernel_size = kernel_ldr_offset + kernel_ldr_bin_size;

View File

@@ -17,7 +17,7 @@
#ifndef FUSEE_LOG_H
#define FUSEE_LOG_H
#define PRINT_MESSAGE_MAX_LENGTH 1024
#define PRINT_MESSAGE_MAX_LENGTH 512
#include <stdarg.h>

View File

@@ -24,7 +24,6 @@
#include "nxboot.h"
#include "nxfs.h"
#include "bct.h"
#include "car.h"
#include "di.h"
#include "mc.h"
#include "se.h"
@@ -65,6 +64,7 @@
#undef u32
extern const uint8_t warmboot_bin[];
extern const uint32_t warmboot_bin_size;
static const uint8_t retail_pkc_modulus[0x100] = {
0xF7, 0x86, 0x47, 0xAB, 0x71, 0x89, 0x81, 0xB5, 0xCF, 0x0C, 0xB0, 0xE8, 0x48, 0xA7, 0xFD, 0xAD,
@@ -236,8 +236,6 @@ static uint32_t nxboot_get_specific_target_firmware(uint32_t target_firmware){
#define CHECK_NCA(NCA_ID, VERSION) do { if (is_nca_present(NCA_ID)) { return ATMOSPHERE_TARGET_FIRMWARE_##VERSION; } } while(0)
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_10_0_0) {
CHECK_NCA("5077973537f6735b564dd7475b779f87", 10_1_1); /* Exclusive to China. */
CHECK_NCA("fd1faed0ca750700d254c0915b93d506", 10_1_0);
CHECK_NCA("34728c771299443420820d8ae490ea41", 10_0_4);
CHECK_NCA("5b1df84f88c3334335bbb45d8522cbb4", 10_0_3);
CHECK_NCA("e951bc9dedcd54f65ffd83d4d050f9e0", 10_0_2);
@@ -634,8 +632,6 @@ uint32_t nxboot_main(void) {
void *warmboot_memaddr;
void *package1loader;
size_t package1loader_size;
void *mesosphere;
size_t mesosphere_size;
void *emummc;
size_t emummc_size;
uint32_t available_revision;
@@ -653,7 +649,7 @@ uint32_t nxboot_main(void) {
} else {
emummc_size = get_file_size("atmosphere/emummc.kip");
if (emummc_size != 0) {
/* Allocate memory for the emummc KIP. */
/* Allocate memory for the TSEC firmware. */
emummc = memalign(0x100, emummc_size);
if (emummc == NULL) {
@@ -931,28 +927,6 @@ uint32_t nxboot_main(void) {
pmc->scratch1 = (uint32_t)warmboot_memaddr;
}
/* Configure mesosphere. */
/* TODO: Support non-SD/embedded mesosphere. */
{
size_t sd_meso_size = get_file_size("atmosphere/mesosphere.bin");
if (sd_meso_size != 0) {
if (sd_meso_size > PACKAGE2_SIZE_MAX) {
fatal_error("Error: atmosphere/mesosphere.bin is too large!\n");
}
mesosphere = malloc(sd_meso_size);
if (mesosphere == NULL) {
fatal_error("Error: failed to allocate mesosphere!\n");
}
if (read_from_file(mesosphere, sd_meso_size, "atmosphere/mesosphere.bin") != sd_meso_size) {
fatal_error("Error: failed to read atmosphere/mesosphere.bin!\n");
}
mesosphere_size = sd_meso_size;
} else {
mesosphere = NULL;
mesosphere_size = 0;
}
}
print(SCREEN_LOG_LEVEL_INFO, "[NXBOOT] Rebuilding package2...\n");
/* Parse stratosphere config. */
@@ -961,7 +935,7 @@ uint32_t nxboot_main(void) {
print(SCREEN_LOG_LEVEL_INFO, u8"[NXBOOT] Configured Stratosphere...\n");
/* Patch package2, adding Thermosphère + custom KIPs. */
package2_rebuild_and_copy(package2, MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware, mesosphere, mesosphere_size, emummc, emummc_size);
package2_rebuild_and_copy(package2, MAILBOX_EXOSPHERE_CONFIGURATION->target_firmware, emummc, emummc_size);
/* Set detected FS version. */
MAILBOX_EXOSPHERE_CONFIGURATION->emummc_cfg.base_cfg.fs_version = stratosphere_get_fs_version();
@@ -1016,12 +990,6 @@ uint32_t nxboot_main(void) {
/* Wait for the splash screen to have been displayed for as long as it should be. */
splash_screen_wait_delay();
/* Set reset for USBD, USB2, AHBDMA, and APBDMA. */
rst_enable(CARDEVICE_USBD);
rst_enable(CARDEVICE_USB2);
rst_enable(CARDEVICE_AHBDMA);
rst_enable(CARDEVICE_APBDMA);
/* Return the memory address for booting CPU0. */
return (uint32_t)exosphere_memaddr;
}

View File

@@ -36,6 +36,7 @@ static bool g_emmc_device_initialized = false;
static bool g_fsdev_ready = false;
static bool g_rawdev_ready = false;
static bool g_emudev_ready = false;
static bool g_is_emummc = false;
@@ -355,6 +356,87 @@ static int nxfs_mount_partition_gpt_callback(const efi_entry_t *entry, void *par
return 0;
}
static int nxfs_mount_emu_partition_gpt_callback(const efi_entry_t *entry, void *param, size_t entry_offset, FILE *disk, const char *origin_path, int num_parts, uint64_t part_limit) {
(void)entry_offset;
(void)disk;
device_partition_t *parent = (device_partition_t *)param;
device_partition_t devpart = *parent;
char name_buffer[128];
const uint16_t *utf16name = entry->name;
uint32_t name_len;
int rc;
static const struct {
const char *partition_name;
const char *mount_point;
bool is_fat;
bool is_encrypted;
bool register_immediately;
} known_partitions[] = {
{"PRODINFO", "prodinfo", false, true, false},
{"PRODINFOF", "prodinfof", true, true, false},
{"BCPKG2-1-Normal-Main", "bcpkg21", false, false, true},
{"BCPKG2-2-Normal-Sub", "bcpkg22", false, false, false},
{"BCPKG2-3-SafeMode-Main", "bcpkg23", false, false, false},
{"BCPKG2-4-SafeMode-Sub", "bcpkg24", false, false, false},
{"BCPKG2-5-Repair-Main", "bcpkg25", false, false, false},
{"BCPKG2-6-Repair-Sub", "bcpkg26", false, false, false},
{"SAFE", "safe", true, true, false},
{"SYSTEM", "system", true, true, true},
{"USER", "user", true, true, false},
};
/* Convert the partition name to ASCII, for comparison. */
for (name_len = 0; name_len < sizeof(entry->name) && *utf16name != 0; name_len++) {
name_buffer[name_len] = (char)*utf16name++;
}
name_buffer[name_len] = '\0';
/* Mount the partition, if we know about it. */
for (size_t i = 0; i < sizeof(known_partitions)/sizeof(known_partitions[0]); i++) {
if (strcmp(name_buffer, known_partitions[i].partition_name) == 0) {
devpart.start_sector += entry->first_lba;
devpart.num_sectors = (entry->last_lba + 1) - entry->first_lba;
if (parent->num_sectors < devpart.num_sectors) {
errno = EINVAL;
return -1;
}
if (known_partitions[i].is_encrypted) {
devpart.read_cipher = nxfs_bis_crypto_decrypt;
devpart.write_cipher = nxfs_bis_crypto_encrypt;
devpart.crypto_mode = DevicePartitionCryptoMode_Xts;
}
if (known_partitions[i].is_fat) {
rc = fsdev_mount_device(known_partitions[i].mount_point, &devpart, false);
if (rc == -1) {
return -1;
}
if (known_partitions[i].register_immediately) {
rc = fsdev_register_device(known_partitions[i].mount_point);
if (rc == -1) {
return -1;
}
}
} else {
rc = emudev_mount_device(known_partitions[i].mount_point, &devpart, origin_path, num_parts, part_limit);
if (rc == -1) {
return -1;
}
if (known_partitions[i].register_immediately) {
rc = emudev_register_device(known_partitions[i].mount_point);
if (rc == -1) {
return -1;
}
}
}
}
}
return 0;
}
int nxfs_mount_sd() {
device_partition_t model;
int rc;
@@ -364,7 +446,6 @@ int nxfs_mount_sd() {
model.device_struct = &g_sd_mmcpart;
model.start_sector = 0;
model.num_sectors = 1u << 30; /* arbitrary numbers of sectors. TODO: find the size of the SD in sectors. */
model.is_emulated = false;
/* Mount the SD card device. */
rc = fsdev_mount_device("sdmc", &model, true);
@@ -398,7 +479,6 @@ int nxfs_mount_emmc() {
model.device_struct = &g_emmc_boot0_mmcpart;
model.start_sector = 0;
model.num_sectors = 0x184000 / model.sector_size;
model.is_emulated = false;
/* Mount boot0 device. */
rc = rawdev_mount_device("boot0", &model, true);
@@ -419,7 +499,6 @@ int nxfs_mount_emmc() {
model.device_struct = &g_emmc_boot1_mmcpart;
model.start_sector = 0;
model.num_sectors = 0x80000 / model.sector_size;
model.is_emulated = false;
/* Mount boot1 device. */
rc = rawdev_mount_device("boot1", &model, false);
@@ -435,7 +514,6 @@ int nxfs_mount_emmc() {
model.device_struct = &g_emmc_user_mmcpart;
model.start_sector = 0;
model.num_sectors = (256ull << 30) / model.sector_size;
model.is_emulated = false;
/* Mount raw NAND device. */
rc = rawdev_mount_device("rawnand", &model, false);
@@ -480,11 +558,10 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
model = g_emummc_devpart_template;
model.start_sector = emummc_start_sector + (0x400000 * 0 / model.sector_size);
model.num_sectors = 0x400000 / model.sector_size;
model.is_emulated = true;
model.emu_use_file = false;
/* Mount emulated boot0 device. */
rc = rawdev_mount_device("boot0", &model, true);
rc = emudev_mount_device("boot0", &model, NULL, 0, 0);
/* Failed to mount boot0 device. */
if (rc == -1) {
@@ -492,7 +569,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
}
/* Register emulated boot0 device. */
rc = rawdev_register_device("boot0");
rc = emudev_register_device("boot0");
/* Failed to register boot0 device. */
if (rc == -1) {
@@ -503,11 +580,10 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
model = g_emummc_devpart_template;
model.start_sector = emummc_start_sector + (0x400000 * 1 / model.sector_size);
model.num_sectors = 0x400000 / model.sector_size;
model.is_emulated = true;
model.emu_use_file = false;
/* Mount emulated boot1 device. */
rc = rawdev_mount_device("boot1", &model, false);
rc = emudev_mount_device("boot1", &model, NULL, 0, 0);
/* Failed to mount boot1. */
if (rc == -1) {
@@ -520,11 +596,10 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
model = g_emummc_devpart_template;
model.start_sector = emummc_start_sector + (0x400000 * 2 / model.sector_size);
model.num_sectors = (256ull << 30) / model.sector_size;
model.is_emulated = true;
model.emu_use_file = false;
/* Mount emulated raw NAND device. */
rc = rawdev_mount_device("rawnand", &model, false);
rc = emudev_mount_device("rawnand", &model, NULL, 0, 0);
/* Failed to mount raw NAND. */
if (rc == -1) {
@@ -532,7 +607,7 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
}
/* Register emulated raw NAND device. */
rc = rawdev_register_device("rawnand");
rc = emudev_register_device("rawnand");
/* Failed to register raw NAND device. */
if (rc == -1) {
@@ -548,14 +623,14 @@ int nxfs_mount_emummc_partition(uint64_t emummc_start_sector) {
}
/* Iterate the GPT and mount each emulated raw NAND partition. */
rc = gpt_iterate_through_entries(rawnand, model.sector_size, nxfs_mount_partition_gpt_callback, &model);
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, NULL, 0, 0);
/* Close emulated raw NAND device. */
fclose(rawnand);
/* All emulated devices are ready. */
if (rc == 0) {
g_rawdev_ready = true;
g_emudev_ready = true;
g_is_emummc = true;
}
@@ -566,9 +641,10 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
device_partition_t model;
int rc;
FILE *rawnand;
bool is_exfat;
char emummc_boot0_path[0x300 + 1] = {0};
char emummc_boot1_path[0x300 + 1] = {0};
/* Check if the SD card is EXFAT formatted. */
rc = fsdev_is_exfat("sdmc");
@@ -576,20 +652,29 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
if (rc == -1) {
return -1;
}
/* Set EXFAT status. */
is_exfat = (rc == 1);
/* Reject single part in FAT32. */
/* NOTE: This check has no effect in the current design. */
if (!is_exfat && (num_parts < 1)) {
return -2;
}
/* We want a folder with the archive bit set. */
rc = fsdev_get_attr(emummc_path);
/* Failed to get file DOS attributes. */
if (rc == -1) {
return -2;
}
/* Our path is not a directory. */
if (!(rc & AM_DIR)) {
return -3;
}
/* Our path is not a directory. */
if (!(rc & AM_DIR)) {
return -4;
}
/* Check if the archive bit is not set. */
if (!(rc & AM_ARC)) {
/* Try to set the archive bit. */
@@ -597,117 +682,102 @@ int nxfs_mount_emummc_file(const char *emummc_path, int num_parts, uint64_t part
/* Failed to set file DOS attributes. */
if (rc == -1) {
return -4;
return -5;
}
}
/* Prepare boot0 file path. */
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0");
/* Setup an emulation template for boot0. */
model = g_emummc_devpart_template;
model.start_sector = 0;
model.num_sectors = 0x400000 / model.sector_size;
model.is_emulated = true;
model.emu_use_file = true;
model.emu_num_parts = 0;
model.emu_part_limit = 0;
strcpy(model.emu_root_path, emummc_path);
strcpy(model.emu_file_path, emummc_boot0_path);
/* Prepare boot0 file path. */
snprintf(emummc_boot0_path, sizeof(emummc_boot0_path) - 1, "%s/%s", emummc_path, "boot0");
/* Mount emulated boot0 device. */
rc = rawdev_mount_device("boot0", &model, true);
rc = emudev_mount_device("boot0", &model, emummc_boot0_path, 0, 0);
/* Failed to mount boot0 device. */
if (rc == -1) {
return -5;
return -6;
}
/* Register emulated boot0 device. */
rc = rawdev_register_device("boot0");
rc = emudev_register_device("boot0");
/* Failed to register boot0 device. */
if (rc == -1) {
return -6;
return -7;
}
/* Prepare boot1 file path. */
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1");
/* Setup an emulation template for boot1. */
model = g_emummc_devpart_template;
model.start_sector = 0;
model.num_sectors = 0x400000 / model.sector_size;
model.is_emulated = true;
model.emu_use_file = true;
model.emu_num_parts = 0;
model.emu_part_limit = 0;
strcpy(model.emu_root_path, emummc_path);
strcpy(model.emu_file_path, emummc_boot1_path);
/* Prepare boot1 file path. */
snprintf(emummc_boot1_path, sizeof(emummc_boot1_path) - 1, "%s/%s", emummc_path, "boot1");
/* Mount emulated boot1 device. */
rc = rawdev_mount_device("boot1", &model, false);
rc = emudev_mount_device("boot1", &model, emummc_boot1_path, 0, 0);
/* Failed to mount boot1. */
if (rc == -1) {
return -7;
return -8;
}
/* Register emulated boot1 device. */
rc = rawdev_register_device("boot1");
rc = emudev_register_device("boot1");
/* Failed to register boot1 device. */
if (rc == -1) {
return -8;
return -9;
}
/* Setup a template for raw NAND. */
model = g_emummc_devpart_template;
model.start_sector = 0;
model.num_sectors = (256ull << 30) / model.sector_size;
model.is_emulated = true;
model.emu_use_file = true;
model.emu_num_parts = num_parts;
model.emu_part_limit = part_limit;
strcpy(model.emu_root_path, emummc_path);
strcpy(model.emu_file_path, emummc_path);
/* Mount emulated raw NAND device from single or multiple parts. */
rc = rawdev_mount_device("rawnand", &model, false);
rc = emudev_mount_device("rawnand", &model, emummc_path, num_parts, part_limit);
/* Failed to mount raw NAND. */
if (rc == -1) {
return -9;
return -10;
}
/* Register emulated raw NAND device. */
rc = rawdev_register_device("rawnand");
rc = emudev_register_device("rawnand");
/* Failed to register raw NAND device. */
if (rc == -1) {
return -10;
return -11;
}
/* Open emulated raw NAND device. */
rawnand = fopen("rawnand:/", "rb");
/* Failed to open emulated raw NAND device. */
if (rawnand == NULL) {
return -11;
return -12;
}
/* Iterate the GPT and mount each emulated raw NAND partition. */
rc = gpt_iterate_through_entries(rawnand, model.sector_size, nxfs_mount_partition_gpt_callback, &model);
rc = gpt_iterate_through_emu_entries(rawnand, model.sector_size, nxfs_mount_emu_partition_gpt_callback, &model, emummc_path, num_parts, part_limit);
/* Close emulated raw NAND device. */
fclose(rawnand);
/* All emulated devices are ready. */
if (rc == 0) {
g_rawdev_ready = true;
g_emudev_ready = true;
g_is_emummc = true;
}
return rc;
}
@@ -735,6 +805,18 @@ int nxfs_unmount_emmc() {
return rc;
}
int nxfs_unmount_emummc() {
int rc = 0;
/* Unmount all emulated devices. */
if (g_emudev_ready) {
rc = emudev_unmount_all();
g_emudev_ready = false;
}
return rc;
}
int nxfs_init() {
int rc;
@@ -750,5 +832,5 @@ int nxfs_init() {
}
int nxfs_end() {
return ((nxfs_unmount_sd() || nxfs_unmount_emmc()) ? -1 : 0);
return ((nxfs_unmount_sd() || nxfs_unmount_emmc() || nxfs_unmount_emummc()) ? -1 : 0);
}

View File

@@ -19,6 +19,7 @@
#include "fs_dev.h"
#include "raw_dev.h"
#include "emu_dev.h"
int nxfs_init();
int nxfs_end();

View File

@@ -44,7 +44,7 @@ static inline size_t align_to_4(size_t s) {
return ((s + 3) >> 2) << 2;
}
void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firmware, void *mesosphere, size_t mesosphere_size, void *emummc, size_t emummc_size) {
void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firmware, void *emummc, size_t emummc_size) {
package2_header_t *rebuilt_package2;
size_t rebuilt_package2_size;
void *kernel;
@@ -95,28 +95,10 @@ void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firm
fatal_error("Error: inappropriate kernel embedded ini context");
}
/* Use mesosphere instead of Nintendo's kernel when present. */
const bool is_mesosphere = mesosphere != NULL && mesosphere_size != 0;
if (is_mesosphere) {
kernel = mesosphere;
kernel_size = mesosphere_size;
/* Patch mesosphere to use our rebuilt ini. */
*(volatile uint64_t *)((uintptr_t)mesosphere + 8) = (uint64_t)mesosphere_size;
/* Place the kernel section at the correct location. */
package2->metadata.section_offsets[PACKAGE2_SECTION_KERNEL] = 0x60000;
package2->metadata.entrypoint = 0x60000;
print(SCREEN_LOG_LEVEL_DEBUG, "Using Mesosphere...\n");
}
print(SCREEN_LOG_LEVEL_DEBUG, "Rebuilding the INI1 section...\n");
if (target_firmware < ATMOSPHERE_TARGET_FIRMWARE_8_0_0) {
package2_get_src_section((void *)&orig_ini1, package2, PACKAGE2_SECTION_INI1);
}
if (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_8_0_0 || is_mesosphere) {
} else {
/* On 8.0.0, place INI1 right after kernelldr for our sanity. */
package2->metadata.section_offsets[PACKAGE2_SECTION_INI1] = package2->metadata.section_offsets[PACKAGE2_SECTION_KERNEL] + kernel_size;
}

View File

@@ -94,6 +94,6 @@ static inline uint8_t package2_meta_get_header_version(const package2_meta_t *me
return (uint8_t)((metadata->ctr_dwords[1] ^ (metadata->ctr_dwords[1] >> 16) ^ (metadata->ctr_dwords[1] >> 24)) & 0xFF);
}
void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firmware, void *mesosphere, size_t mesosphere_size, void *emummc, size_t emummc_size);
void package2_rebuild_and_copy(package2_header_t *package2, uint32_t target_firmware, void *emummc, size_t emummc_size);
#endif

View File

@@ -77,6 +77,9 @@ static rawdev_device_t *rawdev_find_device(const char *name) {
int rawdev_mount_device(const char *name, const device_partition_t *devpart, bool initialize_immediately) {
rawdev_device_t *device = NULL;
char drname[40];
strcpy(drname, name);
strcat(drname, ":");
if (name[0] == '\0' || devpart == NULL) {
errno = EINVAL;
@@ -202,19 +205,6 @@ int rawdev_unmount_device(const char *name) {
return 0;
}
int rawdev_register_keys(const char *name, unsigned int target_firmware, BisPartition part) {
rawdev_device_t *device = rawdev_find_device(name);
if (device == NULL) {
errno = ENOENT;
return -1;
}
derive_bis_key(device->devpart.keys, part, target_firmware);
return 0;
}
int rawdev_unmount_all(void) {
for (size_t i = 0; i < RAWDEV_MAX_DEVICES; i++) {
int rc = rawdev_unmount_device(g_rawdev_devices[i].name);

View File

@@ -21,7 +21,6 @@
#include <stdint.h>
#include <stdbool.h>
#include "device_partition.h"
#include "key_derivation.h"
#define RAWDEV_MAX_DEVICES 16
@@ -30,8 +29,6 @@ int rawdev_register_device(const char *name);
int rawdev_unregister_device(const char *name);
int rawdev_unmount_device(const char *name); /* also unregisters. */
int rawdev_register_keys(const char *name, unsigned int target_firmware, BisPartition part);
int rawdev_unmount_all(void);
#endif

View File

@@ -51,6 +51,7 @@ static bool g_stratosphere_boot_enabled = true;
static bool g_stratosphere_ncm_enabled = false;
extern const uint8_t loader_kip[], pm_kip[], sm_kip[], spl_kip[], boot_kip[], ncm_kip[], ams_mitm_kip[];
extern const uint32_t loader_kip_size, pm_kip_size, sm_kip_size, spl_kip_size, boot_kip_size, ncm_kip_size, ams_mitm_kip_size;
static emummc_fs_ver_t g_fs_ver = FS_VER_1_0_0;

View File

@@ -157,18 +157,12 @@ __attribute__ ((noreturn)) void generic_panic(void) {
}
__attribute__((noreturn)) void fatal_error(const char *fmt, ...) {
/* Override the global logging level. */
log_set_log_level(SCREEN_LOG_LEVEL_ERROR);
/* Display fatal error. */
va_list args;
print(SCREEN_LOG_LEVEL_ERROR, "Fatal error: ");
va_start(args, fmt);
vprint(SCREEN_LOG_LEVEL_ERROR, fmt, args);
va_end(args);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\n Press POWER to reboot.\n");
/* Wait for button and reboot. */
wait_for_button_and_reboot();
}
@@ -180,3 +174,37 @@ __attribute__((noinline)) bool overlaps(uint64_t as, uint64_t ae, uint64_t bs, u
return true;
return false;
}
/* Adapted from https://gist.github.com/ccbrown/9722406 */
void hexdump(const void* data, size_t size, uintptr_t addrbase) {
const uint8_t *d = (const uint8_t *)data;
char ascii[17];
ascii[16] = '\0';
for (size_t i = 0; i < size; i++) {
if (i % 16 == 0) {
printf("%0*" PRIXPTR ": | ", 2 * sizeof(addrbase), addrbase + i);
}
printf("%02X ", d[i]);
if (d[i] >= ' ' && d[i] <= '~') {
ascii[i % 16] = d[i];
} else {
ascii[i % 16] = '.';
}
if ((i+1) % 8 == 0 || i+1 == size) {
printf(" ");
if ((i+1) % 16 == 0) {
printf("| %s \n", ascii);
} else if (i+1 == size) {
ascii[(i+1) % 16] = '\0';
if ((i+1) % 16 <= 8) {
printf(" ");
}
for (size_t j = (i+1) % 16; j < 16; j++) {
printf(" ");
}
printf("| %s \n", ascii);
}
}
}
}

View File

@@ -118,6 +118,8 @@ static inline bool check_32bit_address_range_in_program(uintptr_t addr, size_t s
overlaps_a(start, end, __start__, __end__);
}
void hexdump(const void* data, size_t size, uintptr_t addrbase);
__attribute__((noreturn)) void watchdog_reboot(void);
__attribute__((noreturn)) void pmc_reboot(uint32_t scratch0);
__attribute__((noreturn)) void reboot_to_fusee_primary(void);
@@ -127,6 +129,8 @@ __attribute__((noreturn)) void wait_for_button_and_reboot(void);
void wait_for_button(void);
__attribute__((noreturn)) void generic_panic(void);
__attribute__((noreturn)) void fatal_error(const char *fmt, ...);
#endif

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = 2d522dc6a12b2eb5eb3f103a8c5b5126ca301b1a
parent = 35fffade4ea4fdbba9cf2443c321e724c9e70c3d
commit = 89f8944f8025c0557a18e64ceca7f65ab3090d82
parent = 29f1eb807066bdb551f8b1f7352c97e5ac62d436
method = merge
cmdver = 0.4.1

View File

@@ -1,4 +1,4 @@
ATMOSPHERE_LIBRARIES := libmesosphere libstratosphere libexosphere
ATMOSPHERE_LIBRARIES := libmesosphere libstratosphere
TOPTARGETS := all clean

View File

@@ -5,7 +5,7 @@ endif
include $(DEVKITPRO)/devkitA64/base_rules
export ATMOSPHERE_DEFINES += -DATMOSPHERE_ARCH_ARM64
export ATMOSPHERE_SETTINGS += -mtp=soft
export ATMOSPHERE_SETTINGS += -march=armv8-a+crc+crypto -mtp=soft
export ATMOSPHERE_CFLAGS +=
export ATMOSPHERE_CXXFLAGS +=
export ATMOSPHERE_ASFLAGS +=

View File

@@ -1,5 +1,5 @@
export ATMOSPHERE_DEFINES += -DATMOSPHERE_CPU_ARM_CORTEX_A57
export ATMOSPHERE_SETTINGS += -march=armv8-a+crc+crypto -mtune=cortex-a57
export ATMOSPHERE_SETTINGS += -mtune=cortex-a57
export ATMOSPHERE_CFLAGS +=
export ATMOSPHERE_CXXFLAGS +=
export ATMOSPHERE_ASFLAGS +=

View File

@@ -10,7 +10,7 @@ ifeq ($(strip $(ATMOSPHERE_BOARD)),)
export ATMOSPHERE_BOARD := nx-hac-001
ifeq ($(strip $(ATMOSPHERE_CPU)),)
export ATMOSPHERE_CPU := arm-cortex-a57
export ATMOSPHERE_CPU := arm-cortex-a57
endif
endif
@@ -28,44 +28,40 @@ export ATMOSPHERE_ASFLAGS :=
ifeq ($(ATMOSPHERE_BOARD),nx-hac-001)
ifeq ($(ATMOSPHERE_CPU),arm-cortex-a57)
export ATMOSPHERE_ARCH_DIR := arm64
export ATMOSPHERE_BOARD_DIR := nintendo/nx
export ATMOSPHERE_OS_DIR := horizon
export ATMOSPHERE_ARCH_DIR := arch/arm64
export ATMOSPHERE_BOARD_DIR := board/nintendo/nx
export ATMOSPHERE_OS_DIR := os/horizon
export ATMOSPHERE_ARCH_NAME := arm64
export ATMOSPHERE_BOARD_NAME := nintendo_nx
export ATMOSPHERE_OS_NAME := horizon
export ATMOSPHERE_CPU_EXTENSIONS := arm_crypto_extension aarch64_crypto_extension
else ifeq ($(ATMOSPHERE_CPU),arm7tdmi)
export ATMOSPHERE_ARCH_DIR := arm
export ATMOSPHERE_BOARD_DIR := nintendo/nx_bpmp
export ATMOSPHERE_OS_DIR := horizon
export ATMOSPHERE_ARCH_DIR := arch/arm
export ATMOSPHERE_BOARD_DIR := board/nintendo/nx_bpmp
export ATMOSPHERE_OS_DIR := os/horizon
export ATMOSPHERE_ARCH_NAME := arm
export ATMOSPHERE_BOARD_NAME := nintendo_nx
export ATMOSPHERE_OS_NAME := horizon
export ATMOSPHERE_CPU_EXTENSIONS :=
endif
endif
ifeq ($(ATMOSPHERE_CPU),arm-cortex-a57)
export ATMOSPHERE_CPU_DIR := cortex_a57
export ATMOSPHERE_CPU_DIR := arch/arm64/cpu/cortex_a57
export ATMOSPHERE_CPU_NAME := arm_cortex_a57
endif
ifeq ($(ATMOSPHERE_CPU),arm7tdmi)
export ATMOSPHERE_CPU_DIR := arm7tdmi
export ATMOSPHERE_CPU_DIR := arch/arm/cpu/arm7tdmi
export ATMOSPHERE_CPU_NAME := arm7tdmi
endif
export ATMOSPHERE_ARCH_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/arch/$(ATMOSPHERE_ARCH_DIR)
export ATMOSPHERE_BOARD_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/board/$(ATMOSPHERE_BOARD_DIR)
export ATMOSPHERE_OS_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/os/$(ATMOSPHERE_OS_DIR)
export ATMOSPHERE_CPU_MAKE_DIR := $(ATMOSPHERE_ARCH_MAKE_DIR)/cpu/$(ATMOSPHERE_CPU_DIR)
export ATMOSPHERE_ARCH_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_ARCH_DIR)
export ATMOSPHERE_BOARD_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_BOARD_DIR)
export ATMOSPHERE_OS_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_OS_DIR)
export ATMOSPHERE_CPU_MAKE_DIR := $(ATMOSPHERE_CONFIG_MAKE_DIR)/$(ATMOSPHERE_CPU_DIR)
export ATMOSPHERE_LIBRARY_DIR := lib_$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)
export ATMOSPHERE_BUILD_DIR := build_$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)
@@ -106,32 +102,12 @@ BUILD := build
DATA := data
INCLUDES := include
GENERAL_SOURCE_DIRS=$1 $(foreach d,$(filter-out $1/arch $1/board $1/os $1/cpu $1,$(wildcard $1/*)),$(if $(wildcard $d/.),$(call DIR_WILDCARD,$d) $d,))
SPECIFIC_SOURCE_DIRS=$(if $(wildcard $1/$2/$3/.*),$1/$2/$3 $(call DIR_WILDCARD,$1/$2/$3),$(if $(wildcard $1/$2/generic/.*), $1/$2/generic $(call DIR_WILDCARD,$1/$2/generic),))
UNFILTERED_SOURCE_DIRS=$1 $(foreach d,$(wildcard $1/*),$(if $(wildcard $d/.),$(call DIR_WILDCARD,$d) $d,))
ALL_SOURCE_DIRS=$(call GENERAL_SOURCE_DIRS,$1) \
$(call SPECIFIC_SOURCE_DIRS,$1,arch,$(ATMOSPHERE_ARCH_DIR)) \
$(call SPECIFIC_SOURCE_DIRS,$1,board,$(ATMOSPHERE_BOARD_DIR)) \
$(call SPECIFIC_SOURCE_DIRS,$1,os,$(ATMOSPHERE_OS_DIR)) \
$(call SPECIFIC_SOURCE_DIRS,$1,cpu,$(ATMOSPHERE_ARCH_DIR)/$(ATMOSPHERE_CPU_DIR))
GENERAL_SOURCE_DIRS=$1 $(foreach d,$(filter-out $1/arch $1/board $1,$(wildcard $1/*)),$(if $(wildcard $d/.),$(call DIR_WILDCARD,$d) $d,))
SPECIFIC_SOURCE_DIRS=$(if $(wildcard $1/$2/.*),$1/$2 $(call DIR_WILDCARD,$1/$2),)
ALL_SOURCE_DIRS=$(call GENERAL_SOURCE_DIRS,$1) $(call SPECIFIC_SOURCE_DIRS,$1,$(ATMOSPHERE_ARCH_DIR)) $(call SPECIFIC_SOURCE_DIRS,$1,$(ATMOSPHERE_BOARD_DIR)) $(call SPECIFIC_SOURCE_DIRS,$1,$(ATMOSPHERE_OS_DIR))
SOURCES ?= $(call ALL_SOURCE_DIRS,source)
FIND_SPECIFIC_SOURCE_FILES= $(notdir $(wildcard $1/*.$2.$3.$4)) $(filter-out $(subst .$2.$3.,.$2.generic.,$(notdir $(wildcard $1/*.$2.$3.$4))),$(notdir $(wildcard $1/*.$2.generic.$4)))
FIND_SPECIFIC_SOURCE_FILES_EX=$(foreach ext,$3,$(notdir $(wildcard $1/*.$2.$(ext).$4))) $(filter-out $(foreach ext,$3,$(subst .$2.$(ext).,.$2.generic.,$(notdir $(wildcard $1/*.$2.$(ext).$4)))),$(notdir $(wildcard $1/*.$2.generic.$4)))
FIND_SOURCE_FILES=$(foreach dir,$1,$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.$2)) \
$(notdir $(wildcard $(dir)/*.board.*.$2)) \
$(notdir $(wildcard $(dir)/*.os.*.$2)) \
$(notdir $(wildcard $(dir)/.cpu.*.$2)), \
$(notdir $(wildcard $(dir)/*.$2)))) \
$(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES,$(dir),arch,$(ATMOSPHERE_ARCH_NAME),$2)) \
$(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES,$(dir),board,$(ATMOSPHERE_BOARD_NAME),$2)) \
$(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES,$(dir),os,$(ATMOSPHERE_OS_NAME),$2)) \
$(foreach dir,$1,$(call FIND_SPECIFIC_SOURCE_FILES_EX,$(dir),cpu,$(ATMOSPHERE_CPU_NAME) $(ATMOSPHERE_CPU_EXTENSIONS),$2))
#---------------------------------------------------------------------------------
# Rules for compiling pre-compiled headers
#---------------------------------------------------------------------------------

View File

@@ -8,7 +8,7 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../common.mk
#---------------------------------------------------------------------------------
ifeq ($(strip $(ATMOSPHERE_ARCH_NAME)),arm64)
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Wextra -Werror -fno-non-call-exceptions
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Werror -fno-non-call-exceptions
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)

View File

@@ -7,12 +7,12 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../common.mk
# options for code generation
#---------------------------------------------------------------------------------
export DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_MESOSPHERE
export SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 -mgeneral-regs-only -ffixed-x18 -Wextra -Werror -fno-non-call-exceptions
export SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 -mgeneral-regs-only -ffixed-x18 -Werror -fno-non-call-exceptions
export CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
export CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
export ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
export ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES)
export LDFLAGS = -specs=$(TOPDIR)/$(notdir $(TOPDIR)).specs -fno-asynchronous-unwind-tables -fno-unwind-tables -nostdlib -nostartfiles -g $(SETTINGS) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now
export LDFLAGS = -specs=$(TOPDIR)/$(notdir $(TOPDIR)).specs -nostdlib -nostartfiles -g $(SETTINGS) -Wl,-Map,$(notdir $*.map) -Wl,-z,relro,-z,now
export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \
-Wl,--wrap,__cxa_throw \

View File

@@ -14,7 +14,7 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
#---------------------------------------------------------------------------------
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Wextra -Werror -flto -fno-non-call-exceptions
SETTINGS := $(ATMOSPHERE_SETTINGS) -Os -Werror -flto -fno-non-call-exceptions
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
@@ -39,9 +39,23 @@ ifneq ($(BUILD),$(notdir $(CURDIR)))
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \
$(notdir $(wildcard $(dir)/*.c))))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c)))
CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \
$(notdir $(wildcard $(dir)/*.cpp))))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp)))
SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \
$(notdir $(wildcard $(dir)/*.s))))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C

View File

@@ -14,7 +14,7 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
#---------------------------------------------------------------------------------
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_EXOSPHERE
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Wextra -Werror -fno-non-call-exceptions
SETTINGS := $(ATMOSPHERE_SETTINGS) -mgeneral-regs-only -ffixed-x18 -Os -Werror -fno-non-call-exceptions
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
@@ -39,9 +39,23 @@ ifneq ($(BUILD),$(notdir $(CURDIR)))
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \
$(notdir $(wildcard $(dir)/*.c))))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c)))
CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \
$(notdir $(wildcard $(dir)/*.cpp))))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp)))
SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \
$(notdir $(wildcard $(dir)/*.s))))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C

View File

@@ -89,13 +89,7 @@ namespace ams::secmon {
constexpr inline const SecureMonitorConfiguration DefaultSecureMonitorConfiguration = {
.target_firmware = ams::TargetFirmware_Current,
.key_generation = {},
.hardware_type = {},
.soc_type = {},
.hardware_state = {},
.pad_0B = {},
.flags = SecureMonitorConfigurationFlag_Default,
.reserved = {},
};
}

View File

@@ -203,12 +203,12 @@ DEFINE_CLK_RST_REG_BIT_ENUM(RST_CPUG_CMPLX_CLR_CLR_NONCPURESET, 29, DISABLE, ENA
HANDLER(H, MEM, 1, 0) \
HANDLER(H, AHBDMA, 1, 1) \
HANDLER(H, APBDMA, 1, 2) \
HANDLER(H, USB2, 1, 26) \
HANDLER(H, PMC, 1, 6) \
HANDLER(H, FUSE, 1, 7) \
HANDLER(H, KFUSE, 1, 8) \
HANDLER(H, I2C5, 1, 15) \
HANDLER(H, EMC, 1, 25) \
HANDLER(H, USB2, 1, 26) \
HANDLER(U, CSITE, 2, 9) \
HANDLER(U, IRAMA, 2, 20) \
HANDLER(U, IRAMB, 2, 21) \

View File

@@ -114,7 +114,6 @@
#define APBDEV_PMC_SECURE_SCRATCH113 (0xB1C)
#define APBDEV_PMC_SECURE_SCRATCH114 (0xB20)
#define APBDEV_PMC_SECURE_SCRATCH115 (0xB24)
#define APBDEV_PMC_SECURE_SCRATCH119 (0xB34)
#define PMC_REG_BITS_MASK(NAME) REG_NAMED_BITS_MASK (APBDEV_PMC, NAME)

View File

@@ -38,7 +38,7 @@ namespace ams::clkrst {
reg::ReadWrite(g_register_address + param.clk_enb_offset, REG_BITS_VALUE(param.index, 1, 0));
/* Set the clock source. */
if (param.clk_src_offset != 0) {
if (param.clk_src != 0) {
reg::Write(g_register_address + param.clk_src_offset, (param.clk_src << 29) | (param.clk_div << 0));
}
@@ -89,11 +89,11 @@ namespace ams::clkrst {
}
void EnableUartBClock() {
EnableClock(UartBClock);
EnableClock(UartAClock);
}
void EnableUartCClock() {
EnableClock(UartCClock);
EnableClock(UartAClock);
}
void EnableActmonClock() {

View File

@@ -33,8 +33,6 @@ namespace ams::crypto::impl {
template<size_t KeySize>
void AesImpl<KeySize>::Initialize(const void *key, size_t key_size, bool is_encrypt) {
static_assert(IsSupportedKeySize(KeySize));
AMS_ASSERT(key_size == sizeof(int));
AMS_UNUSED(is_encrypt);
/* Set the security engine keyslot. */
this->slot = *static_cast<const int *>(key);
@@ -52,11 +50,9 @@ namespace ams::crypto::impl {
} else if constexpr (KeySize == 24) {
/* Aes 192. */
/* TODO: se::EncryptAes192(dst, dst_size, this->slot, src, src_size); */
AMS_UNUSED(dst, dst_size, src, src_size);
} else if constexpr (KeySize == 32) {
/* Aes 256. */
/* TODO: se::EncryptAes256(dst, dst_size, this->slot, src, src_size); */
AMS_UNUSED(dst, dst_size, src, src_size);
} else {
/* Invalid key size. */
static_assert(!std::is_same<AesImpl<KeySize>, AesImpl<KeySize>>::value);
@@ -75,11 +71,9 @@ namespace ams::crypto::impl {
} else if constexpr (KeySize == 24) {
/* Aes 192. */
/* TODO: se::DecryptAes192(dst, dst_size, this->slot, src, src_size); */
AMS_UNUSED(dst, dst_size, src, src_size);
} else if constexpr (KeySize == 32) {
/* Aes 256. */
/* TODO: se::DecryptAes256(dst, dst_size, this->slot, src, src_size); */
AMS_UNUSED(dst, dst_size, src, src_size);
} else {
/* Invalid key size. */
static_assert(!std::is_same<AesImpl<KeySize>, AesImpl<KeySize>>::value);

View File

@@ -88,8 +88,6 @@ namespace ams::i2c {
}
bool Write(uintptr_t base_address, Port port, int address, const void *src, size_t src_size, bool unused) {
AMS_UNUSED(port, unused);
/* Ensure we don't write too much. */
u32 data = 0;
if (src_size > MaxTransferSize) {
@@ -127,8 +125,6 @@ namespace ams::i2c {
}
bool Read(uintptr_t base_address, Port port, void *dst, size_t dst_size, int address, bool unused) {
AMS_UNUSED(port, unused);
/* Ensure we don't read too much. */
if (dst_size > MaxTransferSize) {
return false;

View File

@@ -48,14 +48,12 @@ namespace ams::log {
clkrst::EnableUartAClock();
} else if constexpr (UartLogPort == uart::Port_LeftJoyCon) {
/* Logging to left joy-con (e.g. with Joyless). */
static_assert(uart::Port_LeftJoyCon == uart::Port_C);
pinmux::SetupUartC();
clkrst::EnableUartCClock();
} else if constexpr (UartLogPort == uart::Port_RightJoyCon) {
/* Logging to right joy-con (e.g. with Joyless). */
static_assert(uart::Port_RightJoyCon == uart::Port_B);
pinmux::SetupUartB();
clkrst::EnableUartBClock();
} else if constexpr (UartLogPort == uart::Port_RightJoyCon) {
/* Logging to right joy-con (e.g. with Joyless). */
pinmux::SetupUartC();
clkrst::EnableUartCClock();
} else {
__builtin_unreachable();
}

View File

@@ -104,7 +104,7 @@ namespace ams::pinmux {
/* Get the registers. */
const uintptr_t PINMUX = g_pinmux_address;
/* Configure Uart-C. */
/* Configure Uart-B. */
reg::Write(PINMUX + PINMUX_AUX_UART3_TX, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC),
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
@@ -114,13 +114,13 @@ namespace ams::pinmux {
reg::Write(PINMUX + PINMUX_AUX_UART3_RX, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC),
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, TRISTATE),
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
reg::Write(PINMUX + PINMUX_AUX_UART3_RTS, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC),
PINMUX_REG_BITS_ENUM(AUX_PUPD, PULL_DOWN),
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, DISABLE),
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
@@ -128,16 +128,13 @@ namespace ams::pinmux {
reg::Write(PINMUX + PINMUX_AUX_UART3_CTS, PINMUX_REG_BITS_ENUM(AUX_UART3_PM, UARTC),
PINMUX_REG_BITS_ENUM(AUX_PUPD, NONE),
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, TRISTATE),
PINMUX_REG_BITS_ENUM(AUX_TRISTATE, PASSTHROUGH),
PINMUX_REG_BITS_ENUM(AUX_E_INPUT, ENABLE),
PINMUX_REG_BITS_ENUM(AUX_LOCK, DISABLE),
PINMUX_REG_BITS_ENUM(AUX_E_OD, DISABLE));
/* Configure GPIO for Uart-C. */
reg::ReadWrite(g_gpio_address + 0x118, REG_BITS_VALUE(0, 1, 1));
reg::Read(g_gpio_address + 0x118);
reg::ReadWrite(g_gpio_address + 0x00C, REG_BITS_VALUE(1, 1, 0));
reg::Read(g_gpio_address + 0x00C);
reg::ReadWrite(g_gpio_address + 0x00C, REG_BITS_VALUE(1, 4, 0));
}
void SetupI2c1() {

View File

@@ -33,11 +33,11 @@ namespace ams::uart {
}
void WaitSymbols(int baud, u32 num) {
util::WaitMicroSeconds(util::DivideUp(num * 1'000'000, baud));
util::WaitMicroSeconds(util::DivideUp(1'000'000, baud) * num);
}
void WaitCycles(int baud, u32 num) {
util::WaitMicroSeconds(util::DivideUp(num * 1'000'000, 16 * baud));
util::WaitMicroSeconds(util::DivideUp(1'000'000, 16 * baud) * num);
}
ALWAYS_INLINE void WaitFifoNotFull(volatile UartRegisters *uart) {
@@ -60,6 +60,26 @@ namespace ams::uart {
constexpr inline u32 LockBit = (1 << 6);
void Lock(volatile UartRegisters *reg) {
while (true) {
if (reg->mie != 0) {
continue;
}
reg->irda_csr = LockBit;
if (reg->mie == 0) {
break;
}
reg->irda_csr = 0;
}
}
void Unlock(volatile UartRegisters *reg) {
reg->irda_csr = 0;
}
}
void SetRegisterAddress(uintptr_t address) {
@@ -77,13 +97,7 @@ namespace ams::uart {
constexpr u32 UartClock = 408000000;
const u32 divisor = (UartClock + (baud_rate * 16) / 2) / (baud_rate * 16);
/* Wait for idle state. */
WaitIdle(uart, UART_VENDOR_STATE_TX_IDLE);
/* Wait 100 us. */
util::WaitMicroSeconds(100);
/* Disable interrupts. */
/* Disable DLAB and all interrupts. */
uart->lcr = uart->lcr & ~UART_LCR_DLAB;
uart->ier = 0;
uart->mcr = 0;
@@ -114,8 +128,8 @@ namespace ams::uart {
/* Wait for idle state. */
WaitIdle(uart, UART_VENDOR_STATE_TX_IDLE | UART_VENDOR_STATE_RX_IDLE);
/* Wait 100 us. */
util::WaitMicroSeconds(100);
/* Set scratch register to 0. */
uart->spr = 0;
}
void SendText(Port port, const void *data, size_t size) {
@@ -125,6 +139,10 @@ namespace ams::uart {
/* Get pointer to data. */
const u8 *p = static_cast<const u8 *>(data);
/* Lock the uart registers. */
Lock(uart);
ON_SCOPE_EXIT { Unlock(uart); };
/* Send each byte. */
for (size_t i = 0; i < size; ++i) {
WaitFifoNotFull(uart);

View File

@@ -81,8 +81,7 @@ namespace ams::wdt {
/* Enable the counters. */
reg::Write(registers + 0x188, 0x1);
/* Wait forever until the reboot takes. */
AMS_INFINITE_LOOP();
while (true) { /* ... */ }
}
#endif

View File

@@ -9,10 +9,10 @@ include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
PRECOMPILED_HEADERS := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/include/mesosphere.hpp
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_MESOSPHERE
SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 -mgeneral-regs-only -ffixed-x18 -Wextra -Werror -fno-non-call-exceptions
SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 -mgeneral-regs-only -ffixed-x18 -Werror -fno-non-call-exceptions
CFLAGS := $(ATMOSPHERE_CFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
CXXFLAGS := $(CFLAGS) $(ATMOSPHERE_CXXFLAGS) -fno-use-cxa-atexit -flto
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS) $(DEFINES) $(INCLUDE)
ASFLAGS := $(ATMOSPHERE_ASFLAGS) $(SETTINGS)
SOURCES += $(call ALL_SOURCE_DIRS,../libvapours/source)
@@ -34,9 +34,23 @@ ifneq ($(BUILD),$(notdir $(CURDIR)))
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
CPPFILES := $(call FIND_SOURCE_FILES,$(SOURCES),cpp)
SFILES := $(call FIND_SOURCE_FILES,$(SOURCES),s)
CFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.c)) $(notdir $(wildcard $(dir)/*.board.*.c)) $(notdir $(wildcard $(dir)/*.os.*.c)), \
$(notdir $(wildcard $(dir)/*.c))))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).c)))
CFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).c)))
CPPFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.cpp)) $(notdir $(wildcard $(dir)/*.board.*.cpp)) $(notdir $(wildcard $(dir)/*.os.*.cpp)), \
$(notdir $(wildcard $(dir)/*.cpp))))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).cpp)))
CPPFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).cpp)))
SFILES := $(foreach dir,$(SOURCES),$(filter-out $(notdir $(wildcard $(dir)/*.arch.*.s)) $(notdir $(wildcard $(dir)/*.board.*.s)) $(notdir $(wildcard $(dir)/*.os.*.s)), \
$(notdir $(wildcard $(dir)/*.s))))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.arch.$(ATMOSPHERE_ARCH_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.board.$(ATMOSPHERE_BOARD_NAME).s)))
SFILES += $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.os.$(ATMOSPHERE_OS_NAME).s)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C

View File

@@ -27,9 +27,6 @@
#include <mesosphere/kern_initial_process.hpp>
#include <mesosphere/kern_k_exception_context.hpp>
/* Tracing functionality. */
#include <mesosphere/kern_k_trace.hpp>
/* Core pre-initialization includes. */
#include <mesosphere/kern_select_cpu.hpp>
#include <mesosphere/kern_select_system_control.hpp>

View File

@@ -1,279 +0,0 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_select_cpu.hpp>
#include <mesosphere/kern_k_typed_address.hpp>
namespace ams::kern::arch::arm {
struct GicDistributor {
u32 ctlr;
u32 typer;
u32 iidr;
u32 reserved_0x0c;
u32 statusr;
u32 reserved_0x14[3];
u32 impldef_0x20[8];
u32 setspi_nsr;
u32 reserved_0x44;
u32 clrspi_nsr;
u32 reserved_0x4c;
u32 setspi_sr;
u32 reserved_0x54;
u32 clrspi_sr;
u32 reserved_0x5c[9];
u32 igroupr[32];
u32 isenabler[32];
u32 icenabler[32];
u32 ispendr[32];
u32 icpendr[32];
u32 isactiver[32];
u32 icactiver[32];
union {
u8 bytes[1020];
u32 words[255];
} ipriorityr;
u32 _0x7fc;
union {
u8 bytes[1020];
u32 words[255];
} itargetsr;
u32 _0xbfc;
u32 icfgr[64];
u32 igrpmodr[32];
u32 _0xd80[32];
u32 nsacr[64];
u32 sgir;
u32 _0xf04[3];
u32 cpendsgir[4];
u32 spendsgir[4];
u32 reserved_0xf30[52];
static constexpr size_t SgirCpuTargetListShift = 16;
enum SgirTargetListFilter : u32 {
SgirTargetListFilter_CpuTargetList = (0 << 24),
SgirTargetListFilter_Others = (1 << 24),
SgirTargetListFilter_Self = (2 << 24),
SgirTargetListFilter_Reserved = (3 << 24),
};
};
static_assert(util::is_pod<GicDistributor>::value);
static_assert(sizeof(GicDistributor) == 0x1000);
struct GicCpuInterface {
u32 ctlr;
u32 pmr;
u32 bpr;
u32 iar;
u32 eoir;
u32 rpr;
u32 hppir;
u32 abpr;
u32 aiar;
u32 aeoir;
u32 ahppir;
u32 statusr;
u32 reserved_30[4];
u32 impldef_40[36];
u32 apr[4];
u32 nsapr[4];
u32 reserved_f0[3];
u32 iidr;
u32 reserved_100[960];
u32 dir;
u32 _0x1004[1023];
};
static_assert(util::is_pod<GicCpuInterface>::value);
static_assert(sizeof(GicCpuInterface) == 0x2000);
struct KInterruptController {
NON_COPYABLE(KInterruptController);
NON_MOVEABLE(KInterruptController);
public:
static constexpr s32 NumSoftwareInterrupts = 16;
static constexpr s32 NumLocalInterrupts = NumSoftwareInterrupts + 16;
static constexpr s32 NumGlobalInterrupts = 988;
static constexpr s32 NumInterrupts = NumLocalInterrupts + NumGlobalInterrupts;
static constexpr s32 NumPriorityLevels = 4;
public:
struct LocalState {
u32 isenabler[NumLocalInterrupts / 32];
u32 ipriorityr[NumLocalInterrupts / 4];
u32 itargetsr[NumLocalInterrupts / 4];
u32 icfgr[NumLocalInterrupts / 16];
};
struct GlobalState {
u32 isenabler[NumGlobalInterrupts / 32];
u32 ipriorityr[NumGlobalInterrupts / 4];
u32 itargetsr[NumGlobalInterrupts / 4];
u32 icfgr[NumGlobalInterrupts / 16];
};
enum PriorityLevel : u8 {
PriorityLevel_High = 0,
PriorityLevel_Low = NumPriorityLevels - 1,
PriorityLevel_Timer = 1,
PriorityLevel_Scheduler = 2,
};
private:
static inline u32 s_mask[cpu::NumCores];
private:
volatile GicDistributor *gicd;
volatile GicCpuInterface *gicc;
public:
constexpr KInterruptController() : gicd(nullptr), gicc(nullptr) { /* ... */ }
void Initialize(s32 core_id);
void Finalize(s32 core_id);
void SaveCoreLocal(LocalState *state) const;
void SaveGlobal(GlobalState *state) const;
void RestoreCoreLocal(const LocalState *state) const;
void RestoreGlobal(const GlobalState *state) const;
public:
u32 GetIrq() const {
return this->gicc->iar;
}
static constexpr s32 ConvertRawIrq(u32 irq) {
return (irq == 0x3FF) ? -1 : (irq & 0x3FF);
}
void Enable(s32 irq) const {
this->gicd->isenabler[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32)));
}
void Disable(s32 irq) const {
this->gicd->icenabler[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32)));
}
void Clear(s32 irq) const {
this->gicd->icpendr[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32)));
}
void SetTarget(s32 irq, s32 core_id) const {
this->gicd->itargetsr.bytes[irq] = this->gicd->itargetsr.bytes[irq] | GetGicMask(core_id);
}
void ClearTarget(s32 irq, s32 core_id) const {
this->gicd->itargetsr.bytes[irq] = this->gicd->itargetsr.bytes[irq] & ~GetGicMask(core_id);
}
void SetPriorityLevel(s32 irq, s32 level) const {
MESOSPHERE_ASSERT(PriorityLevel_High <= level && level <= PriorityLevel_Low);
this->gicd->ipriorityr.bytes[irq] = ToGicPriorityValue(level);
}
s32 GetPriorityLevel(s32 irq) const {
return FromGicPriorityValue(this->gicd->ipriorityr.bytes[irq]);
}
void SetPriorityLevel(s32 level) const {
MESOSPHERE_ASSERT(PriorityLevel_High <= level && level <= PriorityLevel_Low);
this->gicc->pmr = ToGicPriorityValue(level);
}
void SetEdge(s32 irq) const {
u32 cfg = this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)];
cfg &= ~(0x3 << (2 * (irq % (BITSIZEOF(u32) / 2))));
cfg |= (0x2 << (2 * (irq % (BITSIZEOF(u32) / 2))));
this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)] = cfg;
}
void SetLevel(s32 irq) const {
u32 cfg = this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)];
cfg &= ~(0x3 << (2 * (irq % (BITSIZEOF(u32) / 2))));
cfg |= (0x0 << (2 * (irq % (BITSIZEOF(u32) / 2))));
this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)] = cfg;
}
void SendInterProcessorInterrupt(s32 irq, u64 core_mask) {
MESOSPHERE_ASSERT(IsSoftware(irq));
this->gicd->sgir = GetCpuTargetListMask(irq, core_mask);
}
void SendInterProcessorInterrupt(s32 irq) {
MESOSPHERE_ASSERT(IsSoftware(irq));
this->gicd->sgir = GicDistributor::SgirTargetListFilter_Others | irq;
}
void EndOfInterrupt(u32 irq) const {
this->gicc->eoir = irq;
}
bool IsInterruptDefined(s32 irq) const {
const s32 num_interrupts = std::min(32 + 32 * (this->gicd->typer & 0x1F), static_cast<u32>(NumInterrupts));
return (0 <= irq && irq < num_interrupts);
}
public:
static constexpr ALWAYS_INLINE bool IsSoftware(s32 id) {
MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts);
return id < NumSoftwareInterrupts;
}
static constexpr ALWAYS_INLINE bool IsLocal(s32 id) {
MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts);
return id < NumLocalInterrupts;
}
static constexpr ALWAYS_INLINE bool IsGlobal(s32 id) {
MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts);
return NumLocalInterrupts <= id;
}
static constexpr size_t GetGlobalInterruptIndex(s32 id) {
MESOSPHERE_ASSERT(IsGlobal(id));
return id - NumLocalInterrupts;
}
static constexpr size_t GetLocalInterruptIndex(s32 id) {
MESOSPHERE_ASSERT(IsLocal(id));
return id;
}
private:
static constexpr size_t PriorityShift = BITSIZEOF(u8) - __builtin_ctz(NumPriorityLevels);
static_assert(PriorityShift < BITSIZEOF(u8));
static constexpr ALWAYS_INLINE u8 ToGicPriorityValue(s32 level) {
return (level << PriorityShift) | ((1 << PriorityShift) - 1);
}
static constexpr ALWAYS_INLINE s32 FromGicPriorityValue(u8 priority) {
return (priority >> PriorityShift) & (NumPriorityLevels - 1);
}
static constexpr ALWAYS_INLINE s32 GetCpuTargetListMask(s32 irq, u64 core_mask) {
MESOSPHERE_ASSERT(IsSoftware(irq));
MESOSPHERE_ASSERT(core_mask < (1ul << cpu::NumCores));
return GicDistributor::SgirTargetListFilter_CpuTargetList | irq | (static_cast<u16>(core_mask) << GicDistributor::SgirCpuTargetListShift);
}
static ALWAYS_INLINE s32 GetGicMask(s32 core_id) {
return s_mask[core_id];
}
ALWAYS_INLINE void SetGicMask(s32 core_id) const {
s_mask[core_id] = this->gicd->itargetsr.bytes[0];
}
NOINLINE void SetupInterruptLines(s32 core_id) const;
};
}

View File

@@ -1,29 +0,0 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_select_cpu.hpp>
#include <mesosphere/kern_k_typed_address.hpp>
#if 1
#include <mesosphere/arch/arm/kern_generic_interrupt_controller.hpp>
#else
#error "Unknown board for KInterruptController"
#endif

View File

@@ -1,25 +0,0 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* All architectures must define NumArchitectureDeviceRegions. */
constexpr inline const auto NumArchitectureDeviceRegions = 3;
constexpr inline const auto KMemoryRegionType_Uart = KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 0);
constexpr inline const auto KMemoryRegionType_InterruptCpuInterface = KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 1).SetAttribute(KMemoryRegionAttr_NoUserMap);
constexpr inline const auto KMemoryRegionType_InterruptDistributor = KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 2).SetAttribute(KMemoryRegionAttr_NoUserMap);
static_assert(KMemoryRegionType_Uart .GetValue() == (0x1D));
static_assert(KMemoryRegionType_InterruptCpuInterface.GetValue() == (0x2D | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_InterruptDistributor .GetValue() == (0x4D | KMemoryRegionAttr_NoUserMap));

View File

@@ -23,17 +23,6 @@
namespace ams::kern::arch::arm64::init {
inline void ClearPhysicalMemory(KPhysicalAddress address, size_t size) {
MESOSPHERE_INIT_ABORT_UNLESS(util::IsAligned(size, sizeof(u64)));
/* This Physical Address -> void * conversion is valid, because this is init page table code. */
/* The MMU is necessarily not yet turned on, if we are creating an initial page table. */
volatile u64 *ptr = reinterpret_cast<volatile u64 *>(GetInteger(address));
for (size_t i = 0; i < size / sizeof(u64); ++i) {
ptr[i] = 0;
}
}
class KInitialPageTable {
public:
class IPageAllocator {
@@ -72,11 +61,9 @@ namespace ams::kern::arch::arm64::init {
}
static ALWAYS_INLINE void ClearNewPageTable(KPhysicalAddress address) {
ClearPhysicalMemory(address, PageSize);
}
public:
static consteval size_t GetMaximumOverheadSize(size_t size) {
return (util::DivideUp(size, L1BlockSize) + util::DivideUp(size, L2BlockSize)) * PageSize;
/* 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);
}
private:
size_t NOINLINE GetBlockCount(KVirtualAddress virt_addr, size_t size, size_t block_size) {
@@ -718,7 +705,7 @@ namespace ams::kern::arch::arm64::init {
this->state.next_address += PageSize;
}
ClearPhysicalMemory(allocated, PageSize);
std::memset(reinterpret_cast<void *>(allocated), 0, PageSize);
return allocated;
}

View File

@@ -59,8 +59,9 @@ namespace ams::kern::arch::arm64::cpu {
InstructionMemoryBarrier();
}
ALWAYS_INLINE void Yield() {
__asm__ __volatile__("yield" ::: "memory");
ALWAYS_INLINE void InvalidateEntireInstructionCache() {
__asm__ __volatile__("ic iallu" ::: "memory");
EnsureInstructionConsistency();
}
ALWAYS_INLINE void SwitchProcess(u64 ttbr, u32 proc_id) {
@@ -148,25 +149,6 @@ namespace ams::kern::arch::arm64::cpu {
return true;
}
ALWAYS_INLINE bool CanAccessAtomic(KProcessAddress addr, bool privileged = false) {
const uintptr_t va = GetInteger(addr);
if (privileged) {
__asm__ __volatile__("at s1e1w, %[va]" :: [va]"r"(va) : "memory");
} else {
__asm__ __volatile__("at s1e0w, %[va]" :: [va]"r"(va) : "memory");
}
InstructionMemoryBarrier();
u64 par = GetParEl1();
if (par & 0x1) {
return false;
}
return (par >> (BITSIZEOF(par) - BITSIZEOF(u8))) == 0xFF;
}
/* Synchronization helpers. */
NOINLINE void SynchronizeAllCores();
@@ -174,7 +156,6 @@ namespace ams::kern::arch::arm64::cpu {
void ClearPageToZeroImpl(void *);
void FlushEntireDataCacheSharedForInit();
void FlushEntireDataCacheLocalForInit();
void InvalidateEntireInstructionCacheForInit();
void StoreEntireCacheForInit();
void FlushEntireDataCache();
@@ -184,8 +165,6 @@ namespace ams::kern::arch::arm64::cpu {
Result FlushDataCache(const void *addr, size_t size);
Result InvalidateInstructionCache(void *addr, size_t size);
void InvalidateEntireInstructionCache();
ALWAYS_INLINE void ClearPageToZero(void *page) {
MESOSPHERE_ASSERT(util::IsAligned(reinterpret_cast<uintptr_t>(page), PageSize));
MESOSPHERE_ASSERT(page != nullptr);
@@ -194,7 +173,7 @@ namespace ams::kern::arch::arm64::cpu {
ALWAYS_INLINE void InvalidateTlbByAsid(u32 asid) {
const u64 value = (static_cast<u64>(asid) << 48);
__asm__ __volatile__("tlbi aside1is, %[value]" :: [value]"r"(value) : "memory");
__asm__ __volatile__("tlbi aside1is, %[value]" :: [value]"r"(static_cast<u64>(value) << 48) : "memory");
EnsureInstructionConsistency();
}

View File

@@ -56,69 +56,26 @@ namespace ams::kern::arch::arm64::cpu {
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(OslarEl1, oslar_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(TpidrEl0, tpidr_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(TpidrRoEl0, tpidrro_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(ElrEl1, elr_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(EsrEl1, esr_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(SpsrEl1, spsr_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(EsrEl1, esr_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(Afsr0El1, afsr0_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(Afsr1El1, afsr1_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(MdscrEl1, mdscr_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CpacrEl1, cpacr_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(ContextidrEl1, contextidr_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntkCtlEl1, cntkctl_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntpCtlEl0, cntp_ctl_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(CntpCvalEl0, cntp_cval_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(Daif, daif)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(SpEl0, sp_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(IdAa64Dfr0El1, id_aa64dfr0_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmcrEl0, pmcr_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmUserEnrEl0, pmuserenr_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmcCntrEl0, pmccntr_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmSelrEl0, pmselr_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmcCfiltrEl0, pmccfiltr_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmIntEnSetEl1, pmintenset_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmCntEnSetEl0, pmcntenset_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmOvsSetEl0, pmovsset_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmIntEnClrEl1, pmintenclr_el1)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmCntEnClrEl0, pmcntenclr_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmOvsClrEl0, pmovsclr_el0)
#define FOR_I_IN_0_TO_30(HANDLER, ...) \
HANDLER(0, ## __VA_ARGS__) HANDLER(1, ## __VA_ARGS__) HANDLER(2, ## __VA_ARGS__) HANDLER(3, ## __VA_ARGS__) \
HANDLER(4, ## __VA_ARGS__) HANDLER(5, ## __VA_ARGS__) HANDLER(6, ## __VA_ARGS__) HANDLER(7, ## __VA_ARGS__) \
HANDLER(8, ## __VA_ARGS__) HANDLER(9, ## __VA_ARGS__) HANDLER(10, ## __VA_ARGS__) HANDLER(11, ## __VA_ARGS__) \
HANDLER(12, ## __VA_ARGS__) HANDLER(13, ## __VA_ARGS__) HANDLER(14, ## __VA_ARGS__) HANDLER(15, ## __VA_ARGS__) \
HANDLER(16, ## __VA_ARGS__) HANDLER(17, ## __VA_ARGS__) HANDLER(18, ## __VA_ARGS__) HANDLER(19, ## __VA_ARGS__) \
HANDLER(20, ## __VA_ARGS__) HANDLER(21, ## __VA_ARGS__) HANDLER(22, ## __VA_ARGS__) HANDLER(23, ## __VA_ARGS__) \
HANDLER(24, ## __VA_ARGS__) HANDLER(25, ## __VA_ARGS__) HANDLER(26, ## __VA_ARGS__) HANDLER(27, ## __VA_ARGS__) \
HANDLER(28, ## __VA_ARGS__) HANDLER(29, ## __VA_ARGS__) HANDLER(30, ## __VA_ARGS__)
#define MESOSPHERE_CPU_DEFINE_PMEV_ACCESSORS(ID, ...) \
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmevCntr##ID##El0, pmevcntr##ID##_el0) \
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmevTyper##ID##El0, pmevtyper##ID##_el0)
FOR_I_IN_0_TO_30(MESOSPHERE_CPU_DEFINE_PMEV_ACCESSORS)
#undef MESOSPHERE_CPU_DEFINE_PMEV_ACCESSORS
#undef FOR_I_IN_0_TO_30
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmUserEnrEl0, pmuserenr_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmcCntrEl0, pmccntr_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmevCntr0El0, pmevcntr0_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmevCntr1El0, pmevcntr1_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmevCntr2El0, pmevcntr2_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmevCntr3El0, pmevcntr3_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmevCntr4El0, pmevcntr4_el0)
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(PmevCntr5El0, pmevcntr5_el0)
#define FOR_I_IN_0_TO_15(HANDLER, ...) \
HANDLER(0, ## __VA_ARGS__) HANDLER(1, ## __VA_ARGS__) HANDLER(2, ## __VA_ARGS__) HANDLER(3, ## __VA_ARGS__) \
HANDLER(4, ## __VA_ARGS__) HANDLER(5, ## __VA_ARGS__) HANDLER(6, ## __VA_ARGS__) HANDLER(7, ## __VA_ARGS__) \
HANDLER(8, ## __VA_ARGS__) HANDLER(9, ## __VA_ARGS__) HANDLER(10, ## __VA_ARGS__) HANDLER(11, ## __VA_ARGS__) \
HANDLER(12, ## __VA_ARGS__) HANDLER(13, ## __VA_ARGS__) HANDLER(14, ## __VA_ARGS__) HANDLER(15, ## __VA_ARGS__)
HANDLER(12, ## __VA_ARGS__) HANDLER(13, ## __VA_ARGS__) HANDLER(14, ## __VA_ARGS__) HANDLER(15, ## __VA_ARGS__) \
#define MESOSPHERE_CPU_DEFINE_DBG_SYSREG_ACCESSORS(ID, ...) \
MESOSPHERE_CPU_DEFINE_SYSREG_ACCESSORS(DbgWcr##ID##El1, dbgwcr##ID##_el1) \
@@ -201,15 +158,6 @@ namespace ams::kern::arch::arm64::cpu {
const size_t shift_value = this->GetBits(16, 6);
return size_t(1) << (size_t(64) - shift_value);
}
constexpr ALWAYS_INLINE bool GetEpd0() const {
return this->GetBits(7, 1) != 0;
}
constexpr ALWAYS_INLINE decltype(auto) SetEpd0(bool set) {
this->SetBit(7, set);
return *this;
}
};
MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(ArchitecturalFeatureAccessControl) {
@@ -241,10 +189,6 @@ namespace ams::kern::arch::arm64::cpu {
constexpr ALWAYS_INLINE size_t GetNumBreakpoints() const {
return this->GetBits(12, 4);
}
constexpr ALWAYS_INLINE size_t GetNumContextAwareBreakpoints() const {
return this->GetBits(28, 4);
}
};
MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(MonitorDebugSystemControl) {
@@ -443,27 +387,6 @@ namespace ams::kern::arch::arm64::cpu {
/* TODO: Other bitfield accessors? */
};
MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS(PerformanceMonitorsControl) {
public:
MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS(PerformanceMonitorsControl, pmcr_el0)
public:
constexpr ALWAYS_INLINE u64 GetN() const {
return this->GetBits(11, 5);
}
constexpr ALWAYS_INLINE decltype(auto) SetEventCounterReset(bool en) {
this->SetBit(1, en);
return *this;
}
constexpr ALWAYS_INLINE decltype(auto) SetCycleCounterReset(bool en) {
this->SetBit(2, en);
return *this;
}
/* TODO: Other bitfield accessors? */
};
#undef FOR_I_IN_0_TO_15
#undef MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS_FUNCTIONS
#undef MESOSPHERE_CPU_SYSREG_ACCESSOR_CLASS

View File

@@ -30,38 +30,6 @@ namespace ams::kern::arch::arm64 {
class KDebug final : public KAutoObjectWithSlabHeapAndContainer<KDebug, KDebugBase> {
MESOSPHERE_AUTOOBJECT_TRAITS(KDebug, KSynchronizationObject);
public:
explicit KDebug() { /* ... */ }
virtual ~KDebug() { /* ... */ }
static void PostDestroy(uintptr_t arg) { MESOSPHERE_UNUSED(arg); /* ... */ }
public:
virtual Result GetThreadContextImpl(ams::svc::ThreadContext *out, KThread *thread, u32 context_flags) override;
virtual Result SetThreadContextImpl(const ams::svc::ThreadContext &ctx, KThread *thread, u32 context_flags) override;
private:
Result GetFpuContext(ams::svc::ThreadContext *out, KThread *thread, u32 context_flags);
Result SetFpuContext(const ams::svc::ThreadContext &ctx, KThread *thread, u32 context_flags);
public:
static uintptr_t GetProgramCounter(const KThread &thread);
static void SetPreviousProgramCounter();
static Result BreakIfAttached(ams::svc::BreakReason break_reason, uintptr_t address, size_t size);
static Result SetHardwareBreakPoint(ams::svc::HardwareBreakPointRegisterName name, u64 flags, u64 value);
static constexpr bool IsBreakInstruction(u32 insn, u32 psr) {
constexpr u32 BreakInstructionAarch64 = 0xE7FFFFFF;
constexpr u32 BreakInstructionAarch32 = 0xE7FFDEFE;
constexpr u32 BreakInstructionThumb32 = 0xB68E;
if ((psr & 0x10) == 0) {
return insn == BreakInstructionAarch64;
} else {
if ((psr & 0x20) == 0) {
return insn == BreakInstructionAarch32;
} else {
return insn == BreakInstructionThumb32;
}
}
}
/* TODO: This is a placeholder definition. */
};

View File

@@ -22,26 +22,9 @@ namespace ams::kern::arch::arm64 {
u64 x[(30 - 0) + 1];
u64 sp;
u64 pc;
u32 psr;
u32 write;
u64 psr;
u64 tpidr;
u64 reserved;
constexpr void GetSvcThreadContext(ams::svc::LastThreadContext *out) const {
if ((this->psr & 0x10) == 0) {
/* aarch64 thread. */
out->fp = this->x[29];
out->sp = this->sp;
out->lr = this->x[30];
out->pc = this->pc;
} else {
/* aarch32 thread. */
out->fp = this->x[11];
out->sp = this->x[13];
out->lr = this->x[14];
out->pc = this->pc;
}
}
};
static_assert(sizeof(KExceptionContext) == 0x120);

View File

@@ -18,19 +18,258 @@
#include <mesosphere/kern_select_cpu.hpp>
#include <mesosphere/kern_k_typed_address.hpp>
#if 1
namespace ams::kern::arch::arm64 {
#include <mesosphere/arch/arm/kern_generic_interrupt_controller.hpp>
namespace ams::kern::arch::arm64 {
struct GicDistributor {
u32 ctlr;
u32 typer;
u32 iidr;
u32 reserved_0x0c;
u32 statusr;
u32 reserved_0x14[3];
u32 impldef_0x20[8];
u32 setspi_nsr;
u32 reserved_0x44;
u32 clrspi_nsr;
u32 reserved_0x4c;
u32 setspi_sr;
u32 reserved_0x54;
u32 clrspi_sr;
u32 reserved_0x5c[9];
u32 igroupr[32];
u32 isenabler[32];
u32 icenabler[32];
u32 ispendr[32];
u32 icpendr[32];
u32 isactiver[32];
u32 icactiver[32];
union {
u8 bytes[1020];
u32 words[255];
} ipriorityr;
u32 _0x7fc;
union {
u8 bytes[1020];
u32 words[255];
} itargetsr;
u32 _0xbfc;
u32 icfgr[64];
u32 igrpmodr[32];
u32 _0xd80[32];
u32 nsacr[64];
u32 sgir;
u32 _0xf04[3];
u32 cpendsgir[4];
u32 spendsgir[4];
u32 reserved_0xf30[52];
using ams::kern::arch::arm::GicDistributor;
using ams::kern::arch::arm::GicCpuInterface;
using ams::kern::arch::arm::KInterruptController;
static constexpr size_t SgirCpuTargetListShift = 16;
}
enum SgirTargetListFilter : u32 {
SgirTargetListFilter_CpuTargetList = (0 << 24),
SgirTargetListFilter_Others = (1 << 24),
SgirTargetListFilter_Self = (2 << 24),
SgirTargetListFilter_Reserved = (3 << 24),
};
};
static_assert(util::is_pod<GicDistributor>::value);
static_assert(sizeof(GicDistributor) == 0x1000);
#else
struct GicCpuInterface {
u32 ctlr;
u32 pmr;
u32 bpr;
u32 iar;
u32 eoir;
u32 rpr;
u32 hppir;
u32 abpr;
u32 aiar;
u32 aeoir;
u32 ahppir;
u32 statusr;
u32 reserved_30[4];
u32 impldef_40[36];
u32 apr[4];
u32 nsapr[4];
u32 reserved_f0[3];
u32 iidr;
u32 reserved_100[960];
u32 dir;
u32 _0x1004[1023];
};
static_assert(util::is_pod<GicCpuInterface>::value);
static_assert(sizeof(GicCpuInterface) == 0x2000);
#error "Unknown board for KInterruptController"
struct KInterruptController {
NON_COPYABLE(KInterruptController);
NON_MOVEABLE(KInterruptController);
public:
static constexpr s32 NumSoftwareInterrupts = 16;
static constexpr s32 NumLocalInterrupts = NumSoftwareInterrupts + 16;
static constexpr s32 NumGlobalInterrupts = 988;
static constexpr s32 NumInterrupts = NumLocalInterrupts + NumGlobalInterrupts;
static constexpr s32 NumPriorityLevels = 4;
public:
struct LocalState {
u32 local_isenabler[NumLocalInterrupts / 32];
u32 local_ipriorityr[NumLocalInterrupts / 4];
u32 local_targetsr[NumLocalInterrupts / 4];
u32 local_icfgr[NumLocalInterrupts / 16];
};
#endif
struct GlobalState {
u32 global_isenabler[NumGlobalInterrupts / 32];
u32 global_ipriorityr[NumGlobalInterrupts / 4];
u32 global_targetsr[NumGlobalInterrupts / 4];
u32 global_icfgr[NumGlobalInterrupts / 16];
};
enum PriorityLevel : u8 {
PriorityLevel_High = 0,
PriorityLevel_Low = NumPriorityLevels - 1,
PriorityLevel_Timer = 1,
PriorityLevel_Scheduler = 2,
};
private:
static inline u32 s_mask[cpu::NumCores];
private:
volatile GicDistributor *gicd;
volatile GicCpuInterface *gicc;
public:
constexpr KInterruptController() : gicd(nullptr), gicc(nullptr) { /* ... */ }
void Initialize(s32 core_id);
void Finalize(s32 core_id);
public:
u32 GetIrq() const {
return this->gicc->iar;
}
static constexpr s32 ConvertRawIrq(u32 irq) {
return (irq == 0x3FF) ? -1 : (irq & 0x3FF);
}
void Enable(s32 irq) const {
this->gicd->isenabler[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32)));
}
void Disable(s32 irq) const {
this->gicd->icenabler[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32)));
}
void Clear(s32 irq) const {
this->gicd->icpendr[irq / BITSIZEOF(u32)] = (1u << (irq % BITSIZEOF(u32)));
}
void SetTarget(s32 irq, s32 core_id) const {
this->gicd->itargetsr.bytes[irq] = this->gicd->itargetsr.bytes[irq] | GetGicMask(core_id);
}
void ClearTarget(s32 irq, s32 core_id) const {
this->gicd->itargetsr.bytes[irq] = this->gicd->itargetsr.bytes[irq] & ~GetGicMask(core_id);
}
void SetPriorityLevel(s32 irq, s32 level) const {
MESOSPHERE_ASSERT(PriorityLevel_High <= level && level <= PriorityLevel_Low);
this->gicd->ipriorityr.bytes[irq] = ToGicPriorityValue(level);
}
s32 GetPriorityLevel(s32 irq) const {
return FromGicPriorityValue(this->gicd->ipriorityr.bytes[irq]);
}
void SetPriorityLevel(s32 level) const {
MESOSPHERE_ASSERT(PriorityLevel_High <= level && level <= PriorityLevel_Low);
this->gicc->pmr = ToGicPriorityValue(level);
}
void SetEdge(s32 irq) const {
u32 cfg = this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)];
cfg &= ~(0x3 << (2 * (irq % (BITSIZEOF(u32) / 2))));
cfg |= (0x2 << (2 * (irq % (BITSIZEOF(u32) / 2))));
this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)] = cfg;
}
void SetLevel(s32 irq) const {
u32 cfg = this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)];
cfg &= ~(0x3 << (2 * (irq % (BITSIZEOF(u32) / 2))));
cfg |= (0x0 << (2 * (irq % (BITSIZEOF(u32) / 2))));
this->gicd->icfgr[irq / (BITSIZEOF(u32) / 2)] = cfg;
}
void SendInterProcessorInterrupt(s32 irq, u64 core_mask) {
MESOSPHERE_ASSERT(IsSoftware(irq));
this->gicd->sgir = GetCpuTargetListMask(irq, core_mask);
}
void SendInterProcessorInterrupt(s32 irq) {
MESOSPHERE_ASSERT(IsSoftware(irq));
this->gicd->sgir = GicDistributor::SgirTargetListFilter_Others | irq;
}
void EndOfInterrupt(u32 irq) const {
this->gicc->eoir = irq;
}
bool IsInterruptDefined(s32 irq) {
const s32 num_interrupts = std::min(32 + 32 * (this->gicd->typer & 0x1F), static_cast<u32>(NumInterrupts));
return (0 <= irq && irq < num_interrupts);
}
/* TODO: Implement more KInterruptController functionality. */
public:
static constexpr ALWAYS_INLINE bool IsSoftware(s32 id) {
MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts);
return id < NumSoftwareInterrupts;
}
static constexpr ALWAYS_INLINE bool IsLocal(s32 id) {
MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts);
return id < NumLocalInterrupts;
}
static constexpr ALWAYS_INLINE bool IsGlobal(s32 id) {
MESOSPHERE_ASSERT(0 <= id && id < NumInterrupts);
return NumLocalInterrupts <= id;
}
static constexpr size_t GetGlobalInterruptIndex(s32 id) {
MESOSPHERE_ASSERT(IsGlobal(id));
return id - NumLocalInterrupts;
}
static constexpr size_t GetLocalInterruptIndex(s32 id) {
MESOSPHERE_ASSERT(IsLocal(id));
return id;
}
private:
static constexpr size_t PriorityShift = BITSIZEOF(u8) - __builtin_ctz(NumPriorityLevels);
static_assert(PriorityShift < BITSIZEOF(u8));
static constexpr ALWAYS_INLINE u8 ToGicPriorityValue(s32 level) {
return (level << PriorityShift) | ((1 << PriorityShift) - 1);
}
static constexpr ALWAYS_INLINE s32 FromGicPriorityValue(u8 priority) {
return (priority >> PriorityShift) & (NumPriorityLevels - 1);
}
static constexpr ALWAYS_INLINE s32 GetCpuTargetListMask(s32 irq, u64 core_mask) {
MESOSPHERE_ASSERT(IsSoftware(irq));
MESOSPHERE_ASSERT(core_mask < (1ul << cpu::NumCores));
return GicDistributor::SgirTargetListFilter_CpuTargetList | irq | (static_cast<u16>(core_mask) << GicDistributor::SgirCpuTargetListShift);
}
static ALWAYS_INLINE s32 GetGicMask(s32 core_id) {
return s_mask[core_id];
}
ALWAYS_INLINE void SetGicMask(s32 core_id) const {
s_mask[core_id] = this->gicd->itargetsr.bytes[0];
}
NOINLINE void SetupInterruptLines(s32 core_id) const;
};
}

View File

@@ -67,21 +67,10 @@ namespace ams::kern::arch::arm64 {
NOINLINE void Initialize(s32 core_id);
NOINLINE void Finalize(s32 core_id);
NOINLINE void Save(s32 core_id);
NOINLINE void Restore(s32 core_id);
bool IsInterruptDefined(s32 irq) const {
bool IsInterruptDefined(s32 irq) {
return this->interrupt_controller.IsInterruptDefined(irq);
}
bool IsGlobal(s32 irq) const {
return this->interrupt_controller.IsGlobal(irq);
}
bool IsLocal(s32 irq) const {
return this->interrupt_controller.IsLocal(irq);
}
NOINLINE Result BindHandler(KInterruptHandler *handler, s32 irq, s32 core_id, s32 priority, bool manual_clear, bool level);
NOINLINE Result UnbindHandler(s32 irq, s32 core);

View File

@@ -1,25 +0,0 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* All architectures must define NumArchitectureDeviceRegions. */
constexpr inline const auto NumArchitectureDeviceRegions = 3;
constexpr inline const auto KMemoryRegionType_Uart = KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 0);
constexpr inline const auto KMemoryRegionType_InterruptCpuInterface = KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 1).SetAttribute(KMemoryRegionAttr_NoUserMap);
constexpr inline const auto KMemoryRegionType_InterruptDistributor = KMemoryRegionType_ArchDeviceBase.DeriveSparse(0, NumArchitectureDeviceRegions, 2).SetAttribute(KMemoryRegionAttr_NoUserMap);
static_assert(KMemoryRegionType_Uart .GetValue() == (0x1D));
static_assert(KMemoryRegionType_InterruptCpuInterface.GetValue() == (0x2D | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_InterruptDistributor .GetValue() == (0x4D | KMemoryRegionAttr_NoUserMap));

View File

@@ -182,31 +182,25 @@ namespace ams::kern::arch::arm64 {
NOINLINE Result InitializeForProcess(u32 id, ams::svc::CreateProcessFlag as_type, bool enable_aslr, bool from_back, KMemoryManager::Pool pool, KProcessAddress code_address, size_t code_size, KMemoryBlockSlabManager *mem_block_slab_manager, KBlockInfoManager *block_info_manager, KPageTableManager *pt_manager);
Result Finalize();
private:
Result MapL1Blocks(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, PageLinkedList *page_list, bool reuse_ll);
Result MapL2Blocks(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, PageLinkedList *page_list, bool reuse_ll);
Result MapL3Blocks(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, PageLinkedList *page_list, bool reuse_ll);
Result Map(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, PageLinkedList *page_list, bool reuse_ll);
Result Unmap(KProcessAddress virt_addr, size_t num_pages, PageLinkedList *page_list, bool force, bool reuse_ll);
Result Map(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, size_t page_size, PageLinkedList *page_list, bool reuse_ll) {
switch (page_size) {
case L1BlockSize:
return this->MapL1Blocks(virt_addr, phys_addr, num_pages, entry_template, page_list, reuse_ll);
case L2ContiguousBlockSize:
entry_template.SetContiguous(true);
[[fallthrough]];
#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
case L2TegraSmmuBlockSize:
#endif
case L2BlockSize:
return this->MapL2Blocks(virt_addr, phys_addr, num_pages, entry_template, page_list, reuse_ll);
case L3BlockSize:
break;
case L2ContiguousBlockSize:
case L3ContiguousBlockSize:
entry_template.SetContiguous(true);
[[fallthrough]];
case L3BlockSize:
return this->MapL3Blocks(virt_addr, phys_addr, num_pages, entry_template, page_list, reuse_ll);
break;
MESOSPHERE_UNREACHABLE_DEFAULT_CASE();
}
return this->Map(virt_addr, phys_addr, num_pages, entry_template, page_list, reuse_ll);
}
Result MapContiguous(KProcessAddress virt_addr, KPhysicalAddress phys_addr, size_t num_pages, PageTableEntry entry_template, PageLinkedList *page_list, bool reuse_ll);

View File

@@ -106,8 +106,6 @@ namespace ams::kern::arch::arm64 {
NOINLINE void InitializeForProcess(void *tb, KVirtualAddress start, KVirtualAddress end);
L1PageTableEntry *Finalize();
void Dump(uintptr_t start, size_t size) const;
bool BeginTraversal(TraversalEntry *out_entry, TraversalContext *out_context, KProcessAddress address) const;
bool ContinueTraversal(TraversalEntry *out_entry, TraversalContext *context) const;

View File

@@ -44,10 +44,6 @@ namespace ams::kern::arch::arm64 {
return this->page_table.SetProcessMemoryPermission(addr, size, perm);
}
Result SetMemoryAttribute(KProcessAddress addr, size_t size, u32 mask, u32 attr) {
return this->page_table.SetMemoryAttribute(addr, size, mask, attr);
}
Result SetHeapSize(KProcessAddress *out, size_t size) {
return this->page_table.SetHeapSize(out, size);
}
@@ -60,34 +56,6 @@ namespace ams::kern::arch::arm64 {
return this->page_table.QueryInfo(out_info, out_page_info, addr);
}
Result QueryPhysicalAddress(ams::svc::PhysicalMemoryInfo *out, KProcessAddress address) const {
return this->page_table.QueryPhysicalAddress(out, address);
}
Result QueryStaticMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const {
return this->page_table.QueryStaticMapping(out, address, size);
}
Result QueryIoMapping(KProcessAddress *out, KPhysicalAddress address, size_t size) const {
return this->page_table.QueryIoMapping(out, address, size);
}
Result MapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) {
return this->page_table.MapMemory(dst_address, src_address, size);
}
Result UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) {
return this->page_table.UnmapMemory(dst_address, src_address, size);
}
Result MapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) {
return this->page_table.MapCodeMemory(dst_address, src_address, size);
}
Result UnmapCodeMemory(KProcessAddress dst_address, KProcessAddress src_address, size_t size) {
return this->page_table.UnmapCodeMemory(dst_address, src_address, size);
}
Result MapIo(KPhysicalAddress phys_addr, size_t size, KMemoryPermission perm) {
return this->page_table.MapIo(phys_addr, size, perm);
}
@@ -104,10 +72,6 @@ namespace ams::kern::arch::arm64 {
return this->page_table.MapPageGroup(addr, pg, state, perm);
}
Result UnmapPageGroup(KProcessAddress address, const KPageGroup &pg, KMemoryState state) {
return this->page_table.UnmapPageGroup(address, pg, state);
}
Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KMemoryState state, KMemoryPermission perm) {
return this->page_table.MapPages(out_addr, num_pages, alignment, phys_addr, state, perm);
}
@@ -116,10 +80,6 @@ namespace ams::kern::arch::arm64 {
return this->page_table.MapPages(out_addr, num_pages, state, perm);
}
Result MapPages(KProcessAddress address, size_t num_pages, KMemoryState state, KMemoryPermission perm) {
return this->page_table.MapPages(address, num_pages, state, perm);
}
Result UnmapPages(KProcessAddress addr, size_t num_pages, KMemoryState state) {
return this->page_table.UnmapPages(addr, num_pages, state);
}
@@ -128,123 +88,11 @@ namespace ams::kern::arch::arm64 {
return this->page_table.MakeAndOpenPageGroup(out, address, num_pages, state_mask, state, perm_mask, perm, attr_mask, attr);
}
Result MakeAndOpenPageGroupContiguous(KPageGroup *out, KProcessAddress address, size_t num_pages, u32 state_mask, u32 state, u32 perm_mask, u32 perm, u32 attr_mask, u32 attr) {
return this->page_table.MakeAndOpenPageGroupContiguous(out, address, num_pages, state_mask, state, perm_mask, perm, attr_mask, attr);
}
Result InvalidateProcessDataCache(KProcessAddress address, size_t size) {
return this->page_table.InvalidateProcessDataCache(address, size);
}
Result ReadDebugMemory(void *buffer, KProcessAddress address, size_t size) {
return this->page_table.ReadDebugMemory(buffer, address, size);
}
Result WriteDebugMemory(KProcessAddress address, const void *buffer, size_t size) {
return this->page_table.WriteDebugMemory(address, buffer, size);
}
Result LockForDeviceAddressSpace(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm, bool is_aligned) {
return this->page_table.LockForDeviceAddressSpace(out, address, size, perm, is_aligned);
}
Result UnlockForDeviceAddressSpace(KProcessAddress address, size_t size) {
return this->page_table.UnlockForDeviceAddressSpace(address, size);
}
Result LockForIpcUserBuffer(KPhysicalAddress *out, KProcessAddress address, size_t size) {
return this->page_table.LockForIpcUserBuffer(out, address, size);
}
Result UnlockForIpcUserBuffer(KProcessAddress address, size_t size) {
return this->page_table.UnlockForIpcUserBuffer(address, size);
}
Result LockForTransferMemory(KPageGroup *out, KProcessAddress address, size_t size, KMemoryPermission perm) {
return this->page_table.LockForTransferMemory(out, address, size, perm);
}
Result UnlockForTransferMemory(KProcessAddress address, size_t size, const KPageGroup &pg) {
return this->page_table.UnlockForTransferMemory(address, size, pg);
}
Result LockForCodeMemory(KPageGroup *out, KProcessAddress address, size_t size) {
return this->page_table.LockForCodeMemory(out, address, size);
}
Result UnlockForCodeMemory(KProcessAddress address, size_t size, const KPageGroup &pg) {
return this->page_table.UnlockForCodeMemory(address, size, pg);
}
Result CopyMemoryFromLinearToUser(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) {
return this->page_table.CopyMemoryFromLinearToUser(dst_addr, size, src_addr, src_state_mask, src_state, src_test_perm, src_attr_mask, src_attr);
}
Result CopyMemoryFromLinearToKernel(KProcessAddress dst_addr, size_t size, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) {
return this->page_table.CopyMemoryFromLinearToKernel(dst_addr, size, src_addr, src_state_mask, src_state, src_test_perm, src_attr_mask, src_attr);
}
Result CopyMemoryFromUserToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr) {
return this->page_table.CopyMemoryFromUserToLinear(dst_addr, size, dst_state_mask, dst_state, dst_test_perm, dst_attr_mask, dst_attr, src_addr);
}
Result CopyMemoryFromKernelToLinear(KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr) {
return this->page_table.CopyMemoryFromKernelToLinear(dst_addr, size, dst_state_mask, dst_state, dst_test_perm, dst_attr_mask, dst_attr, src_addr);
}
Result CopyMemoryFromHeapToHeap(KProcessPageTable &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) {
return this->page_table.CopyMemoryFromHeapToHeap(dst_page_table.page_table, dst_addr, size, dst_state_mask, dst_state, dst_test_perm, dst_attr_mask, dst_attr, src_addr, src_state_mask, src_state, src_test_perm, src_attr_mask, src_attr);
}
Result CopyMemoryFromHeapToHeapWithoutCheckDestination(KProcessPageTable &dst_page_table, KProcessAddress dst_addr, size_t size, u32 dst_state_mask, u32 dst_state, KMemoryPermission dst_test_perm, u32 dst_attr_mask, u32 dst_attr, KProcessAddress src_addr, u32 src_state_mask, u32 src_state, KMemoryPermission src_test_perm, u32 src_attr_mask, u32 src_attr) {
return this->page_table.CopyMemoryFromHeapToHeapWithoutCheckDestination(dst_page_table.page_table, dst_addr, size, dst_state_mask, dst_state, dst_test_perm, dst_attr_mask, dst_attr, src_addr, src_state_mask, src_state, src_test_perm, src_attr_mask, src_attr);
}
Result SetupForIpc(KProcessAddress *out_dst_addr, size_t size, KProcessAddress src_addr, KProcessPageTable &src_page_table, KMemoryPermission test_perm, KMemoryState dst_state, bool send) {
return this->page_table.SetupForIpc(out_dst_addr, size, src_addr, src_page_table.page_table, test_perm, dst_state, send);
}
Result CleanupForIpcServer(KProcessAddress address, size_t size, KMemoryState dst_state, KProcess *server_process) {
return this->page_table.CleanupForIpcServer(address, size, dst_state, server_process);
}
Result CleanupForIpcClient(KProcessAddress address, size_t size, KMemoryState dst_state) {
return this->page_table.CleanupForIpcClient(address, size, dst_state);
}
Result MapPhysicalMemory(KProcessAddress address, size_t size) {
return this->page_table.MapPhysicalMemory(address, size);
}
Result UnmapPhysicalMemory(KProcessAddress address, size_t size) {
return this->page_table.UnmapPhysicalMemory(address, size);
}
Result MapPhysicalMemoryUnsafe(KProcessAddress address, size_t size) {
return this->page_table.MapPhysicalMemoryUnsafe(address, size);
}
Result UnmapPhysicalMemoryUnsafe(KProcessAddress address, size_t size) {
return this->page_table.UnmapPhysicalMemoryUnsafe(address, size);
}
void DumpTable() const {
return this->page_table.DumpTable();
}
void DumpMemoryBlocks() const {
return this->page_table.DumpMemoryBlocks();
}
bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const {
return this->page_table.GetPhysicalAddress(out, address);
}
bool Contains(KProcessAddress addr, size_t size) const { return this->page_table.Contains(addr, size); }
bool IsInAliasRegion(KProcessAddress addr, size_t size) const { return this->page_table.IsInAliasRegion(addr, size); }
bool IsInUnsafeAliasRegion(KProcessAddress addr, size_t size) const { return this->page_table.IsInUnsafeAliasRegion(addr, size); }
bool CanContain(KProcessAddress addr, size_t size, KMemoryState state) const { return this->page_table.CanContain(addr, size, state); }
KProcessAddress GetAddressSpaceStart() const { return this->page_table.GetAddressSpaceStart(); }
@@ -261,11 +109,8 @@ namespace ams::kern::arch::arm64 {
size_t GetKernelMapRegionSize() const { return this->page_table.GetKernelMapRegionSize(); }
size_t GetAliasCodeRegionSize() const { return this->page_table.GetAliasCodeRegionSize(); }
size_t GetNormalMemorySize() const { return this->page_table.GetNormalMemorySize(); }
u32 GetAllocateOption() const { return this->page_table.GetAllocateOption(); }
KPhysicalAddress GetHeapPhysicalAddress(KVirtualAddress address) const {
/* TODO: Better way to convert address type? */
return this->page_table.GetHeapPhysicalAddress(address);
}

View File

@@ -1,69 +0,0 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_select_cpu.hpp>
namespace ams::kern::arch::arm64 {
template<typename T>
concept SlabHeapNode = requires (T &t) {
{ t.next } -> std::convertible_to<T *>;
};
template<typename T> requires SlabHeapNode<T>
ALWAYS_INLINE T *AllocateFromSlabAtomic(T **head) {
u32 tmp;
T *node, *next;
__asm__ __volatile__(
"1:\n"
" ldaxr %[node], [%[head]]\n"
" cbz %[node], 2f\n"
" ldr %[next], [%[node]]\n"
" stlxr %w[tmp], %[next], [%[head]]\n"
" cbnz %w[tmp], 1b\n"
" b 3f\n"
"2:\n"
" clrex\n"
"3:\n"
: [tmp]"=&r"(tmp), [node]"=&r"(node), [next]"=&r"(next), [head]"+&r"(head)
:
: "cc", "memory"
);
return node;
}
template<typename T> requires SlabHeapNode<T>
ALWAYS_INLINE void FreeToSlabAtomic(T **head, T *node) {
u32 tmp;
T *next;
__asm__ __volatile__(
"1:\n"
" ldaxr %[next], [%[head]]\n"
" str %[next], [%[node]]\n"
" stlxr %w[tmp], %[node], [%[head]]\n"
" cbnz %w[tmp], 1b\n"
"2:\n"
: [tmp]"=&r"(tmp), [node]"+&r"(node), [next]"=&r"(next), [head]"+&r"(head)
:
: "cc", "memory"
);
}
}

View File

@@ -23,9 +23,9 @@ namespace ams::kern::arch::arm64 {
class KSupervisorPageTable {
private:
KPageTable page_table;
u64 ttbr0_identity[cpu::NumCores];
u64 ttbr0[cpu::NumCores];
public:
constexpr KSupervisorPageTable() : page_table(), ttbr0_identity() { /* ... */ }
constexpr KSupervisorPageTable() : page_table(), ttbr0() { /* ... */ }
NOINLINE void Initialize(s32 core_id);
@@ -41,6 +41,8 @@ namespace ams::kern::arch::arm64 {
cpu::InvalidateEntireTlb();
}
void Finalize(s32 core_id);
Result MapPages(KProcessAddress *out_addr, size_t num_pages, size_t alignment, KPhysicalAddress phys_addr, KProcessAddress region_start, size_t region_num_pages, KMemoryState state, KMemoryPermission perm) {
return this->page_table.MapPages(out_addr, num_pages, alignment, phys_addr, region_start, region_num_pages, state, perm);
}
@@ -60,8 +62,6 @@ namespace ams::kern::arch::arm64 {
bool GetPhysicalAddress(KPhysicalAddress *out, KProcessAddress address) const {
return this->page_table.GetPhysicalAddress(out, address);
}
constexpr u64 GetIdentityMapTtbr0(s32 core_id) const { return this->ttbr0_identity[core_id]; }
};
}

View File

@@ -66,21 +66,7 @@ namespace ams::kern::arch::arm64 {
static void FpuContextSwitchHandler(KThread *thread);
u32 GetFpcr() const { return this->fpcr; }
u32 GetFpsr() const { return this->fpsr; }
void SetFpcr(u32 v) { this->fpcr = v; }
void SetFpsr(u32 v) { this->fpsr = v; }
void CloneFpuStatus();
void SetFpuRegisters(const u128 *v, bool is_64_bit);
const u128 *GetFpuRegisters() const { return this->fpu_registers; }
public:
static void OnThreadTerminating(const KThread *thread);
/* TODO: More methods (especially FPU management) */
};
void GetUserContext(ams::svc::ThreadContext *out, const KThread *thread);
}

View File

@@ -39,10 +39,6 @@ namespace ams::kern::arch::arm64 {
static bool ClearMemoryAligned64Bit(void *dst, size_t size);
static bool ClearMemorySize32Bit(void *dst);
static bool UpdateLockAtomic(u32 *out, u32 *address, u32 if_zero, u32 new_orr_mask);
static bool UpdateIfEqualAtomic(s32 *out, s32 *address, s32 compare_value, s32 new_value);
static bool DecrementIfLessThanAtomic(s32 *out, s32 *address, s32 compare);
static bool StoreDataCache(uintptr_t start, uintptr_t end);
static bool FlushDataCache(uintptr_t start, uintptr_t end);
static bool InvalidateDataCache(uintptr_t start, uintptr_t end);

View File

@@ -1,47 +0,0 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <mesosphere/kern_common.hpp>
#include <mesosphere/kern_k_page_group.hpp>
#include <mesosphere/kern_k_memory_manager.hpp>
#include <mesosphere/kern_select_page_table.hpp>
namespace ams::kern::board::generic {
using KDeviceVirtualAddress = u64;
class KDevicePageTable {
public:
constexpr KDevicePageTable() { /* ... */ }
Result ALWAYS_INLINE Initialize(u64 space_address, u64 space_size) { return ams::kern::svc::ResultNotImplemented(); }
void ALWAYS_INLINE Finalize() { /* ... */ }
Result ALWAYS_INLINE Attach(ams::svc::DeviceName device_name, u64 space_address, u64 space_size) { return ams::kern::svc::ResultNotImplemented(); }
Result ALWAYS_INLINE Detach(ams::svc::DeviceName device_name) { return ams::kern::svc::ResultNotImplemented(); }
Result ALWAYS_INLINE Map(size_t *out_mapped_size, const KPageGroup &pg, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool refresh_mappings) { return ams::kern::svc::ResultNotImplemented(); }
Result ALWAYS_INLINE Unmap(const KPageGroup &pg, KDeviceVirtualAddress device_address) { return ams::kern::svc::ResultNotImplemented(); }
public:
static ALWAYS_INLINE void Initialize() { /* ... */ }
static ALWAYS_INLINE void Lock() { /* ... */ }
static ALWAYS_INLINE void Unlock() { /* ... */ }
static ALWAYS_INLINE void Sleep() { /* ... */ }
static ALWAYS_INLINE void Wakeup() { /* ... */ }
};
}

View File

@@ -35,16 +35,6 @@ namespace ams::kern::board::nintendo::nx {
u32 hs_attached_value;
u32 hs_detached_value;
private:
static ALWAYS_INLINE bool IsHeapVirtualAddress(KVirtualAddress addr) {
const KMemoryRegion *hint = nullptr;
return KMemoryLayout::IsHeapVirtualAddress(hint, addr);
}
static ALWAYS_INLINE bool IsHeapPhysicalAddress(KPhysicalAddress addr) {
const KMemoryRegion *hint = nullptr;
return KMemoryLayout::IsHeapPhysicalAddress(hint, addr);
}
static ALWAYS_INLINE KVirtualAddress GetHeapVirtualAddress(KPhysicalAddress addr) {
return KPageTable::GetHeapVirtualAddress(addr);
}
@@ -63,30 +53,7 @@ namespace ams::kern::board::nintendo::nx {
public:
constexpr KDevicePageTable() : tables(), table_asids(), attached_device(), attached_value(), detached_value(), hs_attached_value(), hs_detached_value() { /* ... */ }
Result Initialize(u64 space_address, u64 space_size);
void Finalize();
Result Attach(ams::svc::DeviceName device_name, u64 space_address, u64 space_size);
Result Detach(ams::svc::DeviceName device_name);
Result Map(size_t *out_mapped_size, const KPageGroup &pg, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm, bool refresh_mappings);
Result Unmap(const KPageGroup &pg, KDeviceVirtualAddress device_address);
private:
Result MapDevicePage(size_t *out_mapped_size, s32 &num_pt, s32 max_pt, KPhysicalAddress phys_addr, u64 size, KDeviceVirtualAddress address, ams::svc::MemoryPermission device_perm);
Result MapImpl(size_t *out_mapped_size, s32 &num_pt, s32 max_pt, const KPageGroup &pg, KDeviceVirtualAddress device_address, ams::svc::MemoryPermission device_perm);
void UnmapImpl(KDeviceVirtualAddress address, u64 size, bool force);
bool IsFree(KDeviceVirtualAddress address, u64 size) const;
Result MakePageGroup(KPageGroup *out, KDeviceVirtualAddress address, u64 size) const;
bool Compare(const KPageGroup &pg, KDeviceVirtualAddress device_address) const;
public:
static void Initialize();
static void Lock();
static void Unlock();
static void Sleep();
static void Wakeup();
};
}

View File

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

View File

@@ -1,46 +0,0 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/* All architectures must define NumBoardDeviceRegions. */
constexpr inline const auto NumBoardDeviceRegions = 6;
/* UNUSED: .Derive(NumBoardDeviceRegions, 0); */
constexpr inline const auto KMemoryRegionType_MemoryController = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 1).SetAttribute(KMemoryRegionAttr_NoUserMap);
constexpr inline const auto KMemoryRegionType_MemoryController1 = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 2).SetAttribute(KMemoryRegionAttr_NoUserMap);
constexpr inline const auto KMemoryRegionType_MemoryController0 = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 3).SetAttribute(KMemoryRegionAttr_NoUserMap);
constexpr inline const auto KMemoryRegionType_PowerManagementController = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 4).DeriveTransition();
constexpr inline const auto KMemoryRegionType_LegacyLpsDevices = KMemoryRegionType_BoardDeviceBase.Derive(NumBoardDeviceRegions, 5);
static_assert(KMemoryRegionType_MemoryController .GetValue() == (0x55 | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_MemoryController1 .GetValue() == (0x65 | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_MemoryController0 .GetValue() == (0x95 | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_PowerManagementController.GetValue() == (0x1A5));
static_assert(KMemoryRegionType_LegacyLpsDevices.GetValue() == 0xC5);
constexpr inline const auto NumLegacyLpsDevices = 7;
constexpr inline const auto KMemoryRegionType_LegacyLpsExceptionVectors = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 0);
constexpr inline const auto KMemoryRegionType_LegacyLpsIram = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 1);
constexpr inline const auto KMemoryRegionType_LegacyLpsFlowController = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 2);
constexpr inline const auto KMemoryRegionType_LegacyLpsPrimaryICtlr = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 3);
constexpr inline const auto KMemoryRegionType_LegacyLpsSemaphore = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 4);
constexpr inline const auto KMemoryRegionType_LegacyLpsAtomics = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 5);
constexpr inline const auto KMemoryRegionType_LegacyLpsClkRst = KMemoryRegionType_LegacyLpsDevices.Derive(NumLegacyLpsDevices, 6);
static_assert(KMemoryRegionType_LegacyLpsExceptionVectors.GetValue() == 0x3C5);
static_assert(KMemoryRegionType_LegacyLpsIram .GetValue() == 0x5C5);
static_assert(KMemoryRegionType_LegacyLpsFlowController .GetValue() == 0x6C5);
static_assert(KMemoryRegionType_LegacyLpsPrimaryICtlr .GetValue() == 0x9C5);
static_assert(KMemoryRegionType_LegacyLpsSemaphore .GetValue() == 0xAC5);
static_assert(KMemoryRegionType_LegacyLpsAtomics .GetValue() == 0xCC5);
static_assert(KMemoryRegionType_LegacyLpsClkRst .GetValue() == 0x11C5);

View File

@@ -39,7 +39,7 @@ namespace ams::kern::board::nintendo::nx {
/* Initialization. */
static NOINLINE void InitializePhase1();
static NOINLINE void InitializePhase2();
static NOINLINE u32 GetCreateProcessMemoryPool();
static NOINLINE u32 GetInitialProcessBinaryPool();
/* Randomness. */
static void GenerateRandomBytes(void *dst, size_t size);
@@ -48,7 +48,7 @@ namespace ams::kern::board::nintendo::nx {
/* Privileged Access. */
static void ReadWriteRegisterPrivileged(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value);
static Result ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value);
static void ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value);
static ALWAYS_INLINE u32 ReadRegisterPrivileged(ams::svc::PhysicalAddress address) {
u32 v;
@@ -67,11 +67,6 @@ namespace ams::kern::board::nintendo::nx {
/* User access. */
static void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args);
/* Secure Memory. */
static size_t CalculateRequiredSecureMemorySize(size_t size, u32 pool);
static Result AllocateSecureMemory(KVirtualAddress *out, size_t size, u32 pool);
static void FreeSecureMemory(KVirtualAddress address, size_t size, u32 pool);
};
}

View File

@@ -26,5 +26,6 @@ namespace ams::kern::init {
KPhysicalAddress GetInitArgumentsAddress(s32 core_id);
void SetInitArguments(s32 core_id, KPhysicalAddress address, uintptr_t arg);
void StoreInitArguments();
}

View File

@@ -1,31 +0,0 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#if 1 || defined(AMS_BUILD_FOR_AUDITING)
#define MESOSPHERE_BUILD_FOR_AUDITING
#endif
#if defined(MESOSPHERE_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
#define MESOSPHERE_BUILD_FOR_DEBUGGING
#endif
#ifdef MESOSPHERE_BUILD_FOR_DEBUGGING
#define MESOSPHERE_ENABLE_ASSERTIONS
#define MESOSPHERE_ENABLE_DEBUG_PRINT
#endif
#define MESOSPHERE_BUILD_FOR_TRACING

View File

@@ -15,19 +15,26 @@
*/
#pragma once
#include <vapours.hpp>
#include <mesosphere/kern_build_config.hpp>
#include <mesosphere/svc/kern_svc_results.hpp>
namespace ams::kern {
constexpr size_t PageSize = 4_KB;
#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
ams::TargetFirmware GetTargetFirmware();
#else
consteval ALWAYS_INLINE ams::TargetFirmware GetTargetFirmware() {
return ams::TargetFirmware_Current;
}
#endif
}
#if 1 || defined(AMS_BUILD_FOR_AUDITING)
#define MESOSPHERE_BUILD_FOR_AUDITING
#endif
#if defined(MESOSPHERE_BUILD_FOR_AUDITING) || defined(AMS_BUILD_FOR_DEBUGGING)
#define MESOSPHERE_BUILD_FOR_DEBUGGING
#endif
#ifdef MESOSPHERE_BUILD_FOR_DEBUGGING
#define MESOSPHERE_ENABLE_ASSERTIONS
#define MESOSPHERE_ENABLE_DEBUG_PRINT
#endif
#include <mesosphere/svc/kern_svc_results.hpp>

Some files were not shown because too many files have changed in this diff Show More