Compare commits

..

34 Commits

Author SHA1 Message Date
fincs
4d4523041f libstratosphere: fix building after PCH related build changes 2020-10-27 21:38:19 +01:00
Michael Scire
e26e1df07f meso: correct .o dependencies in kernel/kldr 2020-10-27 13:08:07 -07:00
Michael Scire
f92de24164 meso: commit mostly-working build system 2020-10-27 12:59:40 -07:00
Michael Scire
a8a90e6324 meso: commit wip (thanks fincs) rewrite to support build targets 2020-10-27 11:48:59 -07:00
Michael Scire
1c71d12d9d ams.mitm: avoid inadvertently breaking ftpd/file listers 2020-10-27 10:28:51 -07:00
Michael Scire
37738699f2 docs: edit terminology to be hip to the jive 2020-10-26 16:14:25 -07:00
Michael Scire
e973ef7533 git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "10e9e0e8"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "10e9e0e8"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-10-26 16:03:40 -07:00
Michael Scire
2ee2a4f1ac docs/fatal error: update for 0.15.0 2020-10-26 16:00:34 -07:00
Michael Scire
2a2bffeb35 ams: fix building debug elf zip 2020-10-15 09:47:06 -07:00
Michael Scire
d04046ecaf ams: bump version to 0.15.0 (release slated for post-crown-tundra) 2020-10-15 09:41:49 -07:00
Michael Scire
f24171dc41 ams: build experimental zip in addition to standard one 2020-10-15 09:41:01 -07:00
Michael Scire
5b02c77400 ams: fix updater misbehavior before 0.15.0 releases 2020-10-14 12:28:26 -07:00
Michael Scire
2e7214b6fa kern: perform rescheduling on dispatch re-enable (closes #1169) 2020-10-13 23:07:51 -07:00
Michael Scire
d52179c708 util: follow 90fd771 to its natural conclusion (generic base rbtree) 2020-10-12 01:06:19 -07:00
Michael Scire
388f9e6455 kern: minor behavioral fixes to condvar/address arbiter 2020-10-12 01:06:19 -07:00
SciresM
c547c7f0e7 Note that we are a python 2 project. 2020-10-09 17:37:51 -07:00
Michael Scire
4138abbefa erpt: fix attachment-in-save paths (closes #1124, #1145) 2020-09-23 19:49:20 -07:00
Michael Scire
1275eb0bf3 erpt: add fixed-width format option 2020-09-23 17:52:08 -07:00
Michael Scire
5ac9e45d86 erpt: support older erpt binaries 2020-09-23 17:36:46 -07:00
Michael Scire
feba788bc6 erpt.py: remove idaapi usage 2020-09-23 16:05:27 -07:00
Michael Scire
f4d10a4481 set.mitm: much more aggressively cache locale (#1160) 2020-09-23 02:01:07 -07:00
Michael Scire
ff310a0647 fusee: try to alleviate a little suffering 2020-09-22 13:54:23 -07:00
Michael Scire
85505db9b7 loader: adjust thread priority for applet-hbl 2020-09-22 12:01:28 -07:00
Michael Scire
48b4dd48a4 ams: expose reboot payload for kernel panic 2020-09-18 00:43:55 -07:00
Michael Scire
8d46d901d9 ams: make mesosphere usage user-visible in display version 2020-09-17 21:18:44 -07:00
Michael Scire
1930880270 fusee: change ncm from opt-in to opt-out 2020-09-17 21:04:43 -07:00
Michael Scire
fa0df994ba git subrepo push libraries
subrepo:
  subdir:   "libraries"
  merged:   "f6dac1e6"
upstream:
  origin:   "https://github.com/Atmosphere-NX/Atmosphere-libs"
  branch:   "master"
  commit:   "f6dac1e6"
git-subrepo:
  version:  "0.4.1"
  origin:   "???"
  commit:   "???"
2020-09-17 08:34:48 -07:00
Michael Scire
909a1767a6 ams: bump version to 0.14.4 2020-09-17 08:34:02 -07:00
Michael Scire
dbe59fd041 kern: fix KCodeMemory SVCs when Owner process != Generator process 2020-09-17 08:26:08 -07:00
Michael Scire
9b65daf439 kern: default to release config 2020-09-17 08:26:08 -07:00
Michael Scire
4acdc899f5 kern: generate fatal error on panic 2020-09-17 08:26:08 -07:00
Michael Scire
76957e502d kern: add build-define for logging to iram ringbuffer 2020-09-17 08:26:08 -07:00
Michael Scire
909397233c sm: Fix atmosphere-extension interaction with official JIT sysmodule usage 2020-09-17 08:24:47 -07:00
Michael Scire
211a828730 ro: fix process handle leak when using JitPlugin NROs 2020-09-17 08:17:11 -07:00
73 changed files with 1483 additions and 450 deletions

View File

@@ -70,8 +70,8 @@ dist-no-debug: all
mkdir -p atmosphere-$(AMSVER)/atmosphere/config
cp fusee/fusee-primary/fusee-primary.bin atmosphere-$(AMSVER)/atmosphere/reboot_payload.bin
cp fusee/fusee-mtc/fusee-mtc.bin atmosphere-$(AMSVER)/atmosphere/fusee-mtc.bin
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/sept/payload.bin
cp fusee/fusee-secondary/fusee-secondary-experimental.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin
cp fusee/fusee-secondary/fusee-secondary-experimental.bin atmosphere-$(AMSVER)/sept/payload.bin
cp sept/sept-primary/sept-primary.bin atmosphere-$(AMSVER)/sept/sept-primary.bin
cp sept/sept-secondary/sept-secondary.bin atmosphere-$(AMSVER)/sept/sept-secondary.bin
cp sept/sept-secondary/sept-secondary_00.enc atmosphere-$(AMSVER)/sept/sept-secondary_00.enc
@@ -99,9 +99,13 @@ dist-no-debug: all
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-EXPERIMENTAL-$(AMSVER).zip ./*; cd ../;
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/sept/payload.bin
cd atmosphere-$(AMSVER); zip -r ../atmosphere-$(AMSVER).zip ./*; cd ../;
rm -r atmosphere-$(AMSVER)
mkdir out
mv atmosphere-EXPERIMENTAL-$(AMSVER).zip out/atmosphere-EXPERIMENTAL-$(AMSVER).zip
mv atmosphere-$(AMSVER).zip out/atmosphere-$(AMSVER).zip
cp fusee/fusee-primary/fusee-primary.bin out/fusee-primary.bin
@@ -120,7 +124,7 @@ dist: dist-no-debug
mkdir atmosphere-$(AMSVER)-debug
cp fusee/fusee-primary/fusee-primary.elf atmosphere-$(AMSVER)-debug/fusee-primary.elf
cp fusee/fusee-mtc/fusee-mtc.elf atmosphere-$(AMSVER)-debug/fusee-mtc.elf
cp fusee/fusee-secondary/fusee-secondary.elf atmosphere-$(AMSVER)-debug/fusee-secondary.elf
cp fusee/fusee-secondary/fusee-secondary-experimental.elf atmosphere-$(AMSVER)-debug/fusee-secondary.elf
cp sept/sept-primary/sept-primary.elf atmosphere-$(AMSVER)-debug/sept-primary.elf
cp sept/sept-secondary/sept-secondary.elf atmosphere-$(AMSVER)-debug/sept-secondary.elf
cp sept/sept-secondary/key_derivation/key_derivation.elf atmosphere-$(AMSVER)-debug/sept-secondary-key-derivation.elf

View File

@@ -9,4 +9,4 @@ stage2_entrypoint = 0xF0000000
; To force-enable nogc, add nogc = 1
; To force-disable nogc, add nogc = 0
; To opt in to using Atmosphere's NCM reimplementation, add enable_ncm = 1
; To opt out of using Atmosphere's NCM reimplementation, add disable_ncm = 1

View File

@@ -4,7 +4,7 @@ Building Atmosphère is a very straightforward process that relies almost exclus
## Dependencies
+ [devkitA64](https://devkitpro.org)
+ [devkitARM](https://devkitpro.org)
+ [Python 2 or 3](https://www.python.org) (optional)
+ [Python 2](https://www.python.org) (Python 3 may work as well, but this is not guaranteed)
+ [PyCryptodome](https://pypi.org/project/pycryptodome) (optional)
## Instructions

View File

@@ -1,4 +1,39 @@
# Changelog
## 0.15.0
+ fusee-primary's panic display was updated to automatically identify and give suggestions to resolve many of the most common errors users encounter.
+ Having been tested as well as I can alone, `mesosphere` (atmosphère's reimplementation of the Nintendo Switch kernel) is now available for users interested in trying it.
+ Beginning in this release and until it is stable and well-tested, atmosphère will distribute two zips.
+ Users who wish to opt-in to mesosphere should download and extract the "cool kids" zip ("atmosphere-EXPERIMENTAL-").
+ Users who do not wish to use mesosphere should continue using the normal zip ("atmosphere-").
+ Users may detect whether mesosphere is active in system settings.
+ When mesosphere is active, the system version string will display "M.15.0" rather than "0.15.0", and so on for future releases.
+ Crash reports and the like will contain information on whether or not the user is using mesosphere, as well.
+ There are "probably" no material user-facing benefits to using mesosphere at this time.
+ Developers may be interested in the fact that mesosphere provides many newer SVC APIs even when on lower firmware versions.
+ The primary benefit to using mesosphere is that any issues you may encounter and report to me will be fixed.
+ All users who choose to opt in to using mesosphere have my deepest gratitude.
+ **Note:** If using hekate instead of fusee-primary, you will have to wait for the next hekate release for mesosphere to function, as hekate's support has not yet been included in an official release build.
+ This will be updated in the release notes when hekate provides a new release.
+ As mentioned in previous release notes, when mesosphere is stable and well-tested, it will be enabled by default and atmosphère's version will transition to 1.0.0.
+ Having been tested sufficiently over the last half-year, Atmosphere's NCM implementation is now opt-out, rather than opt in.
+ In the unlikely event that any issues are encountered, please report them to @SciresM.
+ Users interested in opting out of using our implementation should set `stratosphere!disable_ncm = 1` in BCT.ini.
+ The NCM implementation will stop being opt-out in a future update, probably around the same time that mesosphere becomes opt-out instead of opt-in.
+ Several bugs were fixed, including:
+ Loader now sets HBL's thread priority to a higher value when loading it in applet mode.
+ This fixes an extremely-slow launch ("hang") when using applet-HBL with certain games that do not suspend while inactive (e.g. Super Mario Sunshine).
+ set.mitm now caches user language configuration much more heavily.
+ This severely reduces lag in certain games which misuse the "nn::oe::GetDesiredLanguage()" API.
+ A bug was fixed that could cause erpt to fatal when loading an official save file that had error report attachments in it.
+ General system stability improvements to enhance the user's experience.
## 0.14.4
+ Several bugs were fixed involving the official jit sysmodule added in 10.0.0.
+ A Process handle leak was fixed when JitPlugin NRRs were registered with the `ro` sysmodule.
+ This prevented processes using jit from being able to exit, causing a full system freeze.
+ The `sm` atmosphere extension to not unregister services when the server's connection is closed was special-case disabled for `jit:u`.
+ This extension is normally desirable in order to allow more concurrent processes to exist (as only 0x40 sm connections may ever be concurrently open), but official jit sysmodule relies on the behavior.
+ This would cause crashes on attempts to launch a program using jit services more than once per reboot.
+ General system stability improvements to enhance the user's experience.
## 0.14.3
+ Support was added for 10.2.0.
+ General system stability improvements to enhance the user's experience.

View File

@@ -9,7 +9,7 @@ This file is located under the `/atmosphere/config/` folder on your SD card and
Atmosphère provides its own default splashscreen which is displayed at boot time. However, this can be replaced at will.
The boot splashscreen must be a BMP file, it must be 720x1280 (1280x720 rotated 90 degrees left/counterclockwise/anti-clockwise) resolution, and be in 32-bit ARGB format. You can use image editing software such as GIMP or Photoshop to export the image in this format.
Add the following lines to BCT.ini and change the value of `custom_splash` to the actual path and filename of your boot splashscreen:
```
[stage2]
@@ -29,11 +29,11 @@ nogc = X
0 = force-disable nogc, so Atmosphère will always enable the Game Card reader.
```
### NCM opt-in
Atmosphère provides a reimplementation of the [ncm](../components/modules/ncm.md) system module, but currently this is not enabled by default. If you wish to enable this reimplementation add the following line to the `stratosphere` section:
### NCM opt-out
Atmosphère provides a reimplementation of the [ncm](../components/modules/ncm.md) system module. If you wish to disable this reimplementation add the following line to the `stratosphere` section:
```
[stratosphere]
enable_ncm = 1
disable_ncm = 1
```
### Logging

View File

@@ -96,10 +96,6 @@ namespace ams::secmon {
util::ClearMemory(reinterpret_cast<void *>(address + size / 2), size / 2);
}
bool IsPhysicalMemoryAddress(uintptr_t address) {
return (address - MemoryRegionDram.GetAddress()) < GetPhysicalMemorySize();
}
}
void ClearBootCodeHigh() {
@@ -130,6 +126,10 @@ namespace ams::secmon {
}
}
bool IsPhysicalMemoryAddress(uintptr_t address) {
return (address - MemoryRegionDram.GetAddress()) < GetPhysicalMemorySize();
}
void UnmapTzram() {
/* Get the tables. */
u64 * const l1 = MemoryRegionVirtualTzramL1PageTable.GetPointer<u64>();

View File

@@ -18,6 +18,7 @@
namespace ams::secmon {
bool IsPhysicalMemoryAddress(uintptr_t address);
size_t GetPhysicalMemorySize();
void UnmapTzram();

View File

@@ -141,6 +141,9 @@ namespace ams::secmon::smc {
{ 0xC3000006, Restriction_Normal, SmcShowError },
{ 0xC3000007, Restriction_Normal, SmcSetKernelCarveoutRegion },
{ 0xC3000008, Restriction_Normal, SmcReadWriteRegister },
/* NOTE: Atmosphere extension for mesosphere. This ID is subject to change at any time. */
{ 0xC3000409, Restriction_Normal, SmcSetConfig },
};
constinit HandlerInfo g_ams_handlers[] = {

View File

@@ -15,6 +15,7 @@
*/
#include <exosphere.hpp>
#include "../secmon_error.hpp"
#include "../secmon_map.hpp"
#include "../secmon_misc.hpp"
#include "../secmon_page_mapper.hpp"
#include "../secmon_user_power_management.hpp"
@@ -157,6 +158,8 @@ namespace ams::secmon::smc {
return value.value;
}
constinit u64 g_payload_address = 0;
SmcResult GetConfig(SmcArguments &args, bool kern) {
switch (static_cast<ConfigItem>(args.r[1])) {
case ConfigItem::DisableProgramVerification:
@@ -267,6 +270,14 @@ namespace ams::secmon::smc {
/* NOTE: This may return values other than 1 in the future. */
args.r[1] = (GetEmummcConfiguration().IsEmummcActive() ? 1 : 0);
break;
case ConfigItem::ExospherePayloadAddress:
/* Gets the physical address of the reboot payload buffer, if one exists. */
if (g_payload_address != 0) {
args.r[1] = g_payload_address;
} else {
return SmcResult::NotInitialized;
}
break;
default:
return SmcResult::InvalidArgument;
}
@@ -309,6 +320,17 @@ namespace ams::secmon::smc {
return SmcResult::NotImplemented;
}
break;
case ConfigItem::ExospherePayloadAddress:
if (g_payload_address == 0) {
if (secmon::IsPhysicalMemoryAddress(args.r[2])) {
g_payload_address = args.r[2];
} else {
return SmcResult::InvalidArgument;
}
} else {
return SmcResult::Busy;
}
break;
default:
return SmcResult::InvalidArgument;
}

View File

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

View File

@@ -24,6 +24,9 @@
#include "lib/log.h"
#include "display/video_fb.h"
#define PROGRAM_ID_AMS_MITM 0x010041544D530000ull
#define PROGRAM_ID_BOOT 0x0100000000000005ull
static uint32_t g_panic_code = 0;
static const char *get_error_desc_str(uint32_t error_desc) {
@@ -42,6 +45,8 @@ static const char *get_error_desc_str(uint32_t error_desc) {
return "SError";
case 0x301:
return "Bad SVC";
case 0xF00:
return "Kernel Panic";
case 0xFFD:
return "Stack overflow";
case 0xFFE:
@@ -51,6 +56,61 @@ static const char *get_error_desc_str(uint32_t error_desc) {
}
}
static void _try_suggest_fix(const atmosphere_fatal_error_ctx *ctx) {
/* Try to recognize certain errors automatically, and suggest fixes for them. */
const char *suggestion = NULL;
if (ctx->error_desc == 0xFFE) {
if (ctx->program_id == PROGRAM_ID_AMS_MITM) {
/* When a user has archive bits set improperly, attempting to create an automatic backup will fail */
/* to create the file path with error 0x202 (fs::ResultPathNotFound()) */
if (ctx->gprs[0] == 0x202) {
/* When the archive bit error is occurring, it manifests as failure to create automatic backup. */
/* Thus, we can search the stack for the automatic backups path. */
const char * const automatic_backups_prefix = "automatic_backups/X" /* ..... */;
const int prefix_len = strlen(automatic_backups_prefix);
for (size_t i = 0; i + prefix_len < ctx->stack_dump_size; ++i) {
if (memcmp(&ctx->stack_dump[i], automatic_backups_prefix, prefix_len) == 0) {
suggestion = "The atmosphere directory may improperly have archive\n"
"bits set. Please try running an archive bit fixer tool\n"
"(for example, the one in Hekate).\n";
break;
}
}
} else if (ctx->gprs[0] == 0x249A02) { /* fs::ResultResultExFatUnavailable() */
/* When a user installs non-exFAT firm but has an exFAT formatted SD card, this error will */
/* be returned on attempt to access the SD card. */
suggestion = "Your console has non-exFAT firmware installed, but your SD card\n"
"is formatted as exFAT. Format your SD card as FAT32, or manually\n"
"flash exFAT firmware to package2.\n";
}
} else if (ctx->program_id == PROGRAM_ID_BOOT) {
/* 9.x -> 10.x updated the API for SvcQueryIoMapping. */
/* This can cause the kernel to reject incorrect-ABI calls by boot when a partial update is applied */
/* (older kernel in package2, for some reason). */
for (size_t i = 0; i < 8; ++i) {
if (ctx->gprs[i] == 0xF201) {
suggestion = "A partial update may have been improperly performed.\n"
"To fix, try manually flashing latest package2 to MMC.\n"
"\n"
"For help doing this, seek support in the ReSwitched or\n"
"Nintendo Homebrew discord servers.\n";
break;
}
}
}
} else if (ctx->error_desc == 0xF00) { /* Kernel Panic */
suggestion = "Please contact SciresM#0524 on Discord, or create an issue\n"
"on the Atmosphere GitHub issue tracker. Thank you very much\n"
"for helping to test mesosphere.\n";
}
if (suggestion != NULL) {
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\n%s", suggestion);
}
}
static void _check_and_display_atmosphere_fatal_error(void) {
/* Check for valid magic. */
if (ATMOSPHERE_FATAL_ERROR_CONTEXT->magic != ATMOSPHERE_REBOOT_TO_FATAL_MAGIC &&
@@ -84,7 +144,7 @@ static void _check_and_display_atmosphere_fatal_error(void) {
ATMOSPHERE_FATAL_ERROR_CONTEXT->magic = 0xCCCCCCCC;
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "A fatal error occurred when running Atmosph\xe8re.\n");
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "Title ID: %016llx\n", ctx.title_id);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "Program ID: %016llx\n", ctx.program_id);
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "Error Desc: %s (0x%x)\n", get_error_desc_str(ctx.error_desc), ctx.error_desc);
/* Save context to the SD card. */
@@ -99,6 +159,9 @@ static void _check_and_display_atmosphere_fatal_error(void) {
}
}
/* Try to print a fix suggestion via automatic error detection. */
_try_suggest_fix(&ctx);
/* Display error. */
print(SCREEN_LOG_LEVEL_ERROR | SCREEN_LOG_LEVEL_NO_PREFIX, "\nPress POWER to reboot\n");
}

View File

@@ -36,7 +36,7 @@
typedef struct {
uint32_t magic;
uint32_t error_desc;
uint64_t title_id;
uint64_t program_id;
union {
uint64_t gprs[32];
struct {

View File

@@ -186,11 +186,15 @@ DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
all : $(OUTPUT).bin
$(OUTPUT).bin : $(OUTPUT).elf
$(OUTPUT).bin : $(OUTPUT)-experimental.bin
@python $(TOPDIR)/fusee_make_standard.py $(OUTPUT)-experimental.bin $(OUTPUT).bin
@echo built ... $(notdir $@)
$(OUTPUT)-experimental.bin : $(OUTPUT)-experimental.elf
$(OBJCOPY) -S -O binary $< $@
@echo built ... $(notdir $@)
$(OUTPUT).elf : $(OFILES)
$(OUTPUT)-experimental.elf : $(OFILES)
%.elf: $(OFILES)
@echo linking $(notdir $@)

View File

@@ -0,0 +1,37 @@
#!/usr/bin/env python
import sys, os
from struct import pack as pk, unpack as up
def make_standard(exp):
std = exp[:]
_, metadata_offset, is_exp = up('<III', exp[:12])
assert is_exp == 1
# Patch the experimental flag to zero.
std = std[:8] + pk('<I', 0) + std[12:]
# Locate the mesosphere content header, patch to be experimental.
magic, size, code_ofs, content_ofs, num_contents, ver, sup_ver, rev = up('<IIIIIIII', exp[metadata_offset:metadata_offset + 0x20])
for i in range(num_contents):
start, size, cnt_type, flag0, flag1, flag2, pad = up('<IIBBBBI', exp[content_ofs + 0x20 * i:content_ofs + 0x20 * i + 0x10])
if cnt_type == 10: # CONTENT_TYPE_KRN
assert exp[content_ofs + 0x20 * i + 0x10:content_ofs + 0x20 * i + 0x10 + len(b'mesosphere') + 1] == (b'mesosphere\x00')
assert flag0 == 0 and flag1 == 0 and flag2 == 0
std = std[:content_ofs + 0x20 * i] + pk('<IIBBBBI', start, size, cnt_type, flag0 | 0x1, flag1, flag2, pad) + std[content_ofs + 0x20 * i + 0x10:]
return std
def main(argc, argv):
if argc != 3:
print('Usage: %s input output' % argv[0])
return 1
with open(argv[1], 'rb') as f:
experimental = f.read()
with open(argv[2], 'wb') as f:
f.write(make_standard(experimental))
return 0
if __name__ == '__main__':
sys.exit(main(len(sys.argv), sys.argv))

View File

@@ -254,4 +254,6 @@ SECTIONS
PROVIDE(__emummc_kip_size__ = emummc_kip_end - emummc_kip);
PROVIDE(__kernel_ldr_bin_start__ = kernel_ldr_bin - __start__);
PROVIDE(__kernel_ldr_bin_size__ = kernel_ldr_bin_end - kernel_ldr_bin);
PROVIDE(__mesosphere_bin_start__ = mesosphere_bin - __start__);
PROVIDE(__mesosphere_bin_size__ = mesosphere_bin_end - mesosphere_bin);
}

View File

@@ -55,6 +55,7 @@
#define u8 uint8_t
#define u32 uint32_t
#include "exosphere_bin.h"
#include "mesosphere_bin.h"
#include "sept_secondary_00_enc.h"
#include "sept_secondary_01_enc.h"
#include "sept_secondary_dev_00_enc.h"
@@ -66,6 +67,8 @@
extern const uint8_t warmboot_bin[];
extern int fusee_is_experimental(void);
static const uint8_t retail_pkc_modulus[0x100] = {
0xF7, 0x86, 0x47, 0xAB, 0x71, 0x89, 0x81, 0xB5, 0xCF, 0x0C, 0xB0, 0xE8, 0x48, 0xA7, 0xFD, 0xAD,
0xCB, 0x4E, 0x4A, 0x52, 0x0B, 0x1A, 0x8E, 0xDE, 0x41, 0x87, 0x6F, 0xB7, 0x31, 0x05, 0x5F, 0xAA,
@@ -209,11 +212,11 @@ static int stratosphere_ini_handler(void *user, const char *section, const char
strat_cfg->has_nogc_config = true;
sscanf(value, "%d", &tmp);
strat_cfg->enable_nogc = tmp != 0;
} else if (strcmp(name, STRATOSPHERE_ENABLE_NCM_KEY) == 0) {
} else if (strcmp(name, STRATOSPHERE_DISABLE_NCM_KEY) == 0) {
sscanf(value, "%d", &tmp);
strat_cfg->ncm_enabled = tmp != 0;
if (strat_cfg->ncm_enabled) {
stratosphere_enable_ncm();
strat_cfg->ncm_disabled = tmp != 0;
if (strat_cfg->ncm_disabled) {
stratosphere_disable_ncm();
}
} else {
return 0;
@@ -624,6 +627,7 @@ static nx_keyblob_t __attribute__((aligned(16))) g_keyblobs[32];
uint32_t nxboot_main(void) {
volatile tegra_pmc_t *pmc = pmc_get_regs();
loader_ctx_t *loader_ctx = get_loader_ctx();
const bool is_experimental = fusee_is_experimental();
package2_header_t *package2;
size_t package2_size;
void *tsec_fw;
@@ -933,7 +937,6 @@ uint32_t nxboot_main(void) {
}
/* Configure mesosphere. */
/* TODO: Support non-SD/embedded mesosphere. */
{
size_t sd_meso_size = get_file_size("atmosphere/mesosphere.bin");
if (sd_meso_size != 0) {
@@ -948,6 +951,20 @@ uint32_t nxboot_main(void) {
fatal_error("Error: failed to read atmosphere/mesosphere.bin!\n");
}
mesosphere_size = sd_meso_size;
} else if (is_experimental) {
mesosphere_size = mesosphere_bin_size;
mesosphere = malloc(mesosphere_size);
if (mesosphere == NULL) {
fatal_error("[NXBOOT] Out of memory!\n");
}
memcpy(mesosphere, mesosphere_bin, mesosphere_size);
if (mesosphere_size == 0) {
fatal_error("[NXBOOT] Could not read embedded mesosphere!\n");
}
} else {
mesosphere = NULL;
mesosphere_size = 0;

View File

@@ -30,6 +30,9 @@ _start:
.word (_metadata - _start)
_is_experimental:
.word 0x00000001 /* is experimental */
_crt0:
/* Switch to system mode, mask all interrupts, clear all flags */
msr cpsr_cxsf, #0xDF
@@ -68,6 +71,14 @@ _crt0:
ldr r1, [r1]
b main
.arm
.global fusee_is_experimental
.type fusee_is_experimental, %function
fusee_is_experimental:
ldr r0, =_is_experimental
ldr r0, [r0]
bx lr
/* Fusee-secondary header. */
.align 5
_metadata:
@@ -135,6 +146,17 @@ _content_headers:
.asciz "exosphere"
.align 5
/* mesosphere content header */
.word __mesosphere_bin_start__
.word __mesosphere_bin_size__
.byte CONTENT_TYPE_KRN
.byte CONTENT_FLAG_NONE
.byte CONTENT_FLAG_NONE
.byte CONTENT_FLAG_NONE
.word 0xCCCCCCCC
.asciz "mesosphere"
.align 5
/* fusee_primary content header */
.word __fusee_primary_bin_start__
.word __fusee_primary_bin_size__
@@ -249,7 +271,7 @@ _content_headers:
.word __ncm_kip_start__
.word __ncm_kip_size__
.byte CONTENT_TYPE_KIP
.byte CONTENT_FLAG0_EXPERIMENTAL
.byte CONTENT_FLAG_NONE
.byte CONTENT_FLAG_NONE
.byte CONTENT_FLAG_NONE
.word 0xCCCCCCCC
@@ -267,17 +289,6 @@ _content_headers:
.asciz "emummc"
.align 5
/* kernel_ldr content header */
.word __kernel_ldr_bin_start__
.word __kernel_ldr_bin_size__
.byte CONTENT_TYPE_KLD
.byte CONTENT_FLAG_NONE
.byte CONTENT_FLAG_NONE
.byte CONTENT_FLAG_NONE
.word 0xCCCCCCCC
.asciz "kernel_ldr"
.align 5
/* splash_screen content header */
.word __splash_screen_bmp_start__
.word __splash_screen_bmp_size__

View File

@@ -48,7 +48,7 @@ static bool g_stratosphere_pm_enabled = true;
static bool g_stratosphere_ams_mitm_enabled = true;
static bool g_stratosphere_spl_enabled = true;
static bool g_stratosphere_boot_enabled = true;
static bool g_stratosphere_ncm_enabled = false;
static bool g_stratosphere_ncm_enabled = true;
extern const uint8_t loader_kip[], pm_kip[], sm_kip[], spl_kip[], boot_kip[], ncm_kip[], ams_mitm_kip[];
@@ -58,17 +58,17 @@ emummc_fs_ver_t stratosphere_get_fs_version(void) {
return g_fs_ver;
}
void stratosphere_enable_ncm(void) {
void stratosphere_disable_ncm(void) {
/* The Atmosphere team believes our implementation of NCM to be extremely accurate, */
/* and does not think it likely there is any possibility of undesirable behavior */
/* when using the NCM reimplementation. However, because NCM manages critical save games */
/* the implementation will default to off for some time, until the code has been thoroughly */
/* tested in practice. */
/* the implementation may be optionally disabled for those not comfortable using it. */
/* PLEASE NOTE: The default behavior will be NCM on in a future atmosphere release, */
/* and this opt-in functionality will be removed at that time. */
g_stratosphere_ncm_enabled = true;
/* PLEASE NOTE: The NCM reimplementation has been well-tested, and correspondingly opt-out */
/* functionality will be removed in Atmosphere 1.0.0. */
g_stratosphere_ncm_enabled = false;
}
/* GCC doesn't consider the size as const... we have to write it ourselves. */

View File

@@ -30,7 +30,7 @@ ini1_header_t *stratosphere_get_ini1(uint32_t target_firmware);
ini1_header_t *stratosphere_get_sd_files_ini1(void);
void stratosphere_free_ini1(void);
void stratosphere_enable_ncm(void);
void stratosphere_disable_ncm(void);
emummc_fs_ver_t stratosphere_get_fs_version(void);
@@ -39,10 +39,10 @@ ini1_header_t *stratosphere_merge_inis(ini1_header_t **inis, unsigned int num_in
typedef struct {
bool has_nogc_config;
bool enable_nogc;
bool ncm_enabled;
bool ncm_disabled;
} stratosphere_cfg_t;
#define STRATOSPHERE_NOGC_KEY "nogc"
#define STRATOSPHERE_ENABLE_NCM_KEY "enable_ncm"
#define STRATOSPHERE_DISABLE_NCM_KEY "disable_ncm"
#endif

View File

@@ -6,7 +6,7 @@
[subrepo]
remote = https://github.com/Atmosphere-NX/Atmosphere-libs
branch = master
commit = 48dbf4808f4f2042de8c45e9ec471a8f60d5d621
parent = 47d0d5c6abc1c9957cd05c63b02ee5e712179b80
commit = 10e9e0e8f926b11c2c7de16ffe15bea7d7ec2cdf
parent = 2ee2a4f1ac04bc7f15de8be8d57ad04d7e73f735
method = merge
cmdver = 0.4.1

View File

@@ -15,8 +15,10 @@ endif
endif
ATMOSPHERE_BUILD_SETTINGS ?=
export ATMOSPHERE_DEFINES := -DATMOSPHERE
export ATMOSPHERE_SETTINGS := -fPIE -g
export ATMOSPHERE_SETTINGS := -fPIE -g $(ATMOSPHERE_BUILD_SETTINGS)
export ATMOSPHERE_CFLAGS := -Wall -ffunction-sections -fdata-sections -fno-strict-aliasing -fwrapv \
-fno-asynchronous-unwind-tables -fno-unwind-tables -fno-stack-protector \
-Wno-format-truncation -Wno-format-zero-length -Wno-stringop-truncation
@@ -132,10 +134,15 @@ FIND_SOURCE_FILES=$(foreach dir,$1,$(filter-out $(notdir $(wildcard $(dir)/*.arc
$(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))
ATMOSPHERE_GCH_IDENTIFIER ?= ams_placeholder_gch_identifier
#---------------------------------------------------------------------------------
# Rules for compiling pre-compiled headers
#---------------------------------------------------------------------------------
%.gch: %.hpp
@echo $<
$(CXX) -w -x c++-header -MMD -MP -MF $(DEPSDIR)/$*.d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER)
@cp $@ $(<).gch
%.hpp.gch/$(ATMOSPHERE_GCH_IDENTIFIER): %.hpp | %.hpp.gch
$(SILENTMSG) Precompiling $(notdir $<) for $(ATMOSPHERE_GCH_IDENTIFIER)
$(SILENTCMD)$(CXX) -w -x c++-header -MMD -MP -MQ$@ -MF $(DEPSDIR)/$(notdir $*).d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER)
%.hpp.gch: %.hpp
$(SILENTMSG) Precompiling $(notdir $<)
$(SILENTCMD)$(CXX) -w -x c++-header -MMD -MP -MQ$@ -MF $(DEPSDIR)/$(notdir $*).d $(CXXFLAGS) -c $< -o $@ $(ERROR_FILTER)

View File

@@ -29,7 +29,7 @@ export CXXWRAPS := -Wl,--wrap,__cxa_pure_virtual \
-Wl,--wrap,_ZSt20__throw_length_errorPKc \
-Wl,--wrap,_ZNSt11logic_errorC2EPKc
export LIBS := -lmesosphere
export LIBS := -l$(LIBMESOSPHERE_NAME)
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing

View File

@@ -1,12 +1,14 @@
#---------------------------------------------------------------------------------
# pull in common atmosphere configuration
#---------------------------------------------------------------------------------
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST)))
CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE)))
include $(CURRENT_DIRECTORY)/../config/common.mk
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
PRECOMPILED_HEADERS := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/include/mesosphere.hpp
PRECOMPILED_HEADERS := include/mesosphere.hpp
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_MESOSPHERE
SETTINGS := $(ATMOSPHERE_SETTINGS) -O2 -mgeneral-regs-only -ffixed-x18 -Wextra -Werror -fno-non-call-exceptions
@@ -28,7 +30,7 @@ LIBDIRS := $(ATMOSPHERE_LIBRARIES_DIR)/libvapours
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
ifneq ($(__RECURSIVE__),1)
#---------------------------------------------------------------------------------
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
@@ -54,7 +56,7 @@ endif
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.gch),$(notdir $(hdr)))
export GCH_DIRS := $(PRECOMPILED_HEADERS:.hpp=.hpp.gch)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
@@ -62,41 +64,70 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I.
.PHONY: clean all
#---------------------------------------------------------------------------------
ATMOSPHERE_BUILD_CONFIGS :=
all: release
define ATMOSPHERE_ADD_TARGET
ATMOSPHERE_BUILD_CONFIGS += $(strip $1)
$(strip $1): $$(ATMOSPHERE_LIBRARY_DIR)/$(strip $2)
$$(ATMOSPHERE_LIBRARY_DIR)/$(strip $2) : $$(ATMOSPHERE_LIBRARY_DIR) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(SOURCES) $$(INCLUDES) $$(GCH_DIRS)
@$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(CURDIR)/$$@ $(3) \
ATMOSPHERE_GCH_IDENTIFIER="$$(ATMOSPHERE_BOARD_NAME)_$$(ATMOSPHERE_ARCH_NAME)_$(strip $1)" \
DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \
--no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \
-f $$(THIS_MAKEFILE)
clean-$(strip $1):
@echo clean $(strip $1) ...
@rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(ATMOSPHERE_LIBRARY_DIR)/$(strip $2)
@rm -fr $$(foreach hdr,$$(GCH_DIRS),$$(hdr)/$$(ATMOSPHERE_BOARD_NAME)_$$(ATMOSPHERE_ARCH_NAME)_$(strip $1))
@for i in $$(GCH_DIRS) $$(ATMOSPHERE_BUILD_DIR) $$(ATMOSPHERE_LIBRARY_DIR); do [ -d $$$$i ] && rmdir --ignore-fail-on-non-empty $$$$i || true; done
endef
$(eval $(call ATMOSPHERE_ADD_TARGET, release, $(TARGET).a, \
ATMOSPHERE_BUILD_SETTINGS="" \
))
$(eval $(call ATMOSPHERE_ADD_TARGET, debug, $(TARGET)_debug.a, \
ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_DEBUGGING" \
))
$(eval $(call ATMOSPHERE_ADD_TARGET, audit, $(TARGET)_audit.a, \
ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_AUDITING" \
))
#---------------------------------------------------------------------------------
all: lib/$(TARGET).a
lib:
-include $(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME).mk
ALL_GCH_IDENTIFIERS := $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(ATMOSPHERE_BOARD_NAME)_$(ATMOSPHERE_ARCH_NAME)_$(config))
ALL_GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.hpp.gch),$(foreach id,$(ALL_GCH_IDENTIFIERS),$(hdr)/$(id)))
.PHONY: clean all $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config))
$(ATMOSPHERE_LIBRARY_DIR) $(GCH_DIRS):
@[ -d $@ ] || mkdir -p $@
release:
$(ATMOSPHERE_BUILD_DIR)/%:
@[ -d $@ ] || mkdir -p $@
lib/$(TARGET).a : lib release $(SOURCES) $(INCLUDES)
@$(MAKE) BUILD=release OUTPUT=$(CURDIR)/$@ \
BUILD_CFLAGS="-DNDEBUG=1 -O2" \
DEPSDIR=$(CURDIR)/release \
--no-print-directory -C release \
-f $(CURDIR)/Makefile
dist-bin: all
@tar --exclude=*~ -cjf $(TARGET).tar.bz2 include lib
dist-src:
@tar --exclude=*~ -cjf $(TARGET)-src.tar.bz2 include source Makefile
dist: dist-src dist-bin
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr release lib *.bz2
@rm -fr $(ATMOSPHERE_BUILD_DIR) $(ATMOSPHERE_LIBRARY_DIR) *.bz2 $(ALL_GCH_FILES)
@for i in $(GCH_DIRS); do [ -d $$i ] && rmdir --ignore-fail-on-non-empty $$i || true; done
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d) $(GCH_FILES:.gch=.d)
GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.hpp.gch),$(CURRENT_DIRECTORY)/$(hdr)/$(ATMOSPHERE_GCH_IDENTIFIER))
DEPENDS := $(OFILES:.o=.d) $(foreach hdr,$(GCH_FILES),$(notdir $(patsubst %.hpp.gch/,%.d,$(dir $(hdr)))))
#---------------------------------------------------------------------------------
# main targets

View File

@@ -63,7 +63,7 @@ namespace ams::kern::board::nintendo::nx {
/* Power management. */
static void SleepSystem();
static NORETURN void StopSystem();
static NORETURN void StopSystem(void *arg = nullptr);
/* User access. */
static void CallSecureMonitorFromUser(ams::svc::lp64::SecureMonitorArguments *args);

View File

@@ -15,7 +15,7 @@
*/
#pragma once
#if 1 || defined(AMS_BUILD_FOR_AUDITING)
#if defined(AMS_BUILD_FOR_AUDITING)
#define MESOSPHERE_BUILD_FOR_AUDITING
#endif
@@ -28,4 +28,5 @@
#define MESOSPHERE_ENABLE_DEBUG_PRINT
#endif
#define MESOSPHERE_BUILD_FOR_TRACING
//#define MESOSPHERE_BUILD_FOR_TRACING
#define MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP

View File

@@ -40,7 +40,7 @@ namespace ams::kern {
#ifndef MESOSPHERE_DEBUG_LOG_SELECTED
#ifdef ATMOSPHERE_BOARD_NINTENDO_NX
#define MESOSPHERE_DEBUG_LOG_USE_UART_C
#define MESOSPHERE_DEBUG_LOG_USE_UART_A
#else
#error "Unknown board for Default Debug Log Source"
#endif

View File

@@ -48,6 +48,7 @@ namespace ams::kern {
private:
friend class KScopedSchedulerLock;
friend class KScopedSchedulerLockAndSleep;
friend class KScopedDisableDispatch;
private:
SchedulingState state;
bool is_active;
@@ -161,8 +162,9 @@ namespace ams::kern {
}
ALWAYS_INLINE void ScheduleOnInterrupt() {
KScopedDisableDispatch dd;
GetCurrentThread().DisableDispatch();
this->Schedule();
GetCurrentThread().EnableDispatch();
}
void RescheduleOtherCores(u64 cores_needing_scheduling);

View File

@@ -559,20 +559,7 @@ namespace ams::kern {
GetCurrentThread().DisableDispatch();
}
ALWAYS_INLINE ~KScopedDisableDispatch() {
GetCurrentThread().EnableDispatch();
}
};
class KScopedEnableDispatch {
public:
explicit ALWAYS_INLINE KScopedEnableDispatch() {
GetCurrentThread().EnableDispatch();
}
ALWAYS_INLINE ~KScopedEnableDispatch() {
GetCurrentThread().DisableDispatch();
}
~KScopedDisableDispatch();
};
ALWAYS_INLINE KExceptionContext *GetExceptionContext(KThread *thread) {

View File

@@ -0,0 +1,88 @@
/*
* Copyright (c) 2018-2020 Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <mesosphere/kern_build_config.hpp>
#if defined(MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP)
#define MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT \
/* Save x0/x1 to stack. */ \
stp x0, x1, [sp, #-16]!; \
\
/* Get the exception context for the core. */ \
adr x0, _ZN3ams4kern26g_panic_exception_contextsE; \
mrs x1, mpidr_el1; \
and x1, x1, #0xFF; \
lsl x1, x1, #0x8; \
add x0, x0, x1; \
lsr x1, x1, #0x3; \
add x0, x0, x1; \
\
/* Save x0/x1/sp to the context. */ \
ldr x1, [sp, #(8 * 0)]; \
str x1, [x0, #(8 * 0)]; \
ldr x1, [sp, #(8 * 1)]; \
str x1, [x0, #(8 * 1)]; \
\
/* Save all other registers to the context. */ \
stp x2, x3, [x0, #(8 * 2)]; \
stp x4, x5, [x0, #(8 * 4)]; \
stp x6, x7, [x0, #(8 * 6)]; \
stp x8, x9, [x0, #(8 * 8)]; \
stp x10, x11, [x0, #(8 * 10)]; \
stp x12, x13, [x0, #(8 * 12)]; \
stp x14, x15, [x0, #(8 * 14)]; \
stp x16, x17, [x0, #(8 * 16)]; \
stp x18, x19, [x0, #(8 * 18)]; \
stp x20, x21, [x0, #(8 * 20)]; \
stp x22, x23, [x0, #(8 * 22)]; \
stp x24, x25, [x0, #(8 * 24)]; \
stp x26, x27, [x0, #(8 * 26)]; \
stp x28, x29, [x0, #(8 * 28)]; \
\
add x1, sp, #16; \
stp x30, x1, [x0, #(8 * 30)]; \
\
/* Restore x0/x1. */ \
ldp x0, x1, [sp], #16;
#else
#define MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT
#endif
/* ams::kern::Panic(const char *file, int line, const char *format, ...) */
.section .text._ZN3ams4kern5PanicEPKciS2_z, "ax", %progbits
.global _ZN3ams4kern5PanicEPKciS2_z
.type _ZN3ams4kern5PanicEPKciS2_z, %function
_ZN3ams4kern5PanicEPKciS2_z:
/* Generate the exception context. */
MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT
/* Jump to the architecturally-common implementation function. */
b _ZN3ams4kern9PanicImplEPKciS2_z
/* ams::kern::Panic() */
.section .text._ZN3ams4kern5PanicEv, "ax", %progbits
.global _ZN3ams4kern5PanicEv
.type _ZN3ams4kern5PanicEv, %function
_ZN3ams4kern5PanicEv:
/* Generate the exception context. */
MESOSPHERE_GENERATE_PANIC_EXCEPTION_CONTEXT
/* Jump to the architecturally-common implementation function. */
b _ZN3ams4kern9PanicImplEv

View File

@@ -308,6 +308,15 @@ namespace ams::kern::board::nintendo::nx {
g_secure_applet_memory_used = false;
}
u64 GetVersionIdentifier() {
u64 value = kern::GetTargetFirmware();
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MICRO) << 32;
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MINOR) << 40;
value |= static_cast<u64>(ATMOSPHERE_RELEASE_VERSION_MAJOR) << 48;
value |= static_cast<u64>('M') << 56;
return value;
}
}
/* Initialization. */
@@ -532,13 +541,90 @@ namespace ams::kern::board::nintendo::nx {
KSleepManager::SleepSystem();
}
void KSystemControl::StopSystem() {
void KSystemControl::StopSystem(void *arg) {
if (arg != nullptr) {
/* Get the address of the legacy IRAM region. */
const KVirtualAddress iram_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsIram) + 64_KB;
constexpr size_t RebootPayloadSize = 0x2E000;
/* NOTE: Atmosphere extension; if we received an exception context from Panic(), */
/* generate a fatal error report using it. */
const KExceptionContext *e_ctx = static_cast<const KExceptionContext *>(arg);
auto *f_ctx = GetPointer<::ams::impl::FatalErrorContext>(iram_address + RebootPayloadSize);
/* Clear the fatal context. */
std::memset(f_ctx, 0xCC, sizeof(*f_ctx));
/* Set metadata. */
f_ctx->magic = ::ams::impl::FatalErrorContext::Magic;
f_ctx->error_desc = ::ams::impl::FatalErrorContext::KernelPanicDesc;
f_ctx->program_id = (static_cast<u64>(util::FourCC<'M', 'E', 'S', 'O'>::Code) << 0) | (static_cast<u64>(util::FourCC<'S', 'P', 'H', 'R'>::Code) << 32);
/* Set identifier. */
f_ctx->report_identifier = KHardwareTimer::GetTick();
/* Set module base. */
f_ctx->module_base = KMemoryLayout::GetKernelCodeRegionExtents().GetAddress();
/* Set afsr1. */
f_ctx->afsr0 = 0;
f_ctx->afsr1 = GetVersionIdentifier();
/* Copy registers. */
for (size_t i = 0; i < util::size(e_ctx->x); ++i) {
f_ctx->gprs[i] = e_ctx->x[i];
}
f_ctx->sp = e_ctx->sp;
/* Dump stack trace. */
{
uintptr_t fp = e_ctx->x[29];
for (f_ctx->stack_trace_size = 0; f_ctx->stack_trace_size < ::ams::impl::FatalErrorContext::MaxStackTrace && fp != 0 && util::IsAligned(fp, 0x10) && cpu::GetPhysicalAddressWritable(nullptr, fp, true); ++(f_ctx->stack_trace_size)) {
struct {
uintptr_t fp;
uintptr_t lr;
} *stack_frame = reinterpret_cast<decltype(stack_frame)>(fp);
f_ctx->stack_trace[f_ctx->stack_trace_size] = stack_frame->lr;
fp = stack_frame->fp;
}
}
/* Dump stack. */
{
uintptr_t sp = e_ctx->sp;
for (f_ctx->stack_dump_size = 0; f_ctx->stack_dump_size < ::ams::impl::FatalErrorContext::MaxStackDumpSize && cpu::GetPhysicalAddressWritable(nullptr, sp + f_ctx->stack_dump_size, true); f_ctx->stack_dump_size += sizeof(u64)) {
*reinterpret_cast<u64 *>(f_ctx->stack_dump + f_ctx->stack_dump_size) = *reinterpret_cast<u64 *>(sp + f_ctx->stack_dump_size);
}
}
/* Try to get a payload address. */
const KMemoryRegion *cached_region = nullptr;
u64 reboot_payload_paddr = 0;
if (smc::TryGetConfig(std::addressof(reboot_payload_paddr), 1, smc::ConfigItem::ExospherePayloadAddress) && KMemoryLayout::IsLinearMappedPhysicalAddress(cached_region, reboot_payload_paddr, RebootPayloadSize)) {
/* If we have a payload, reboot to it. */
const KVirtualAddress reboot_payload = KMemoryLayout::GetLinearVirtualAddress(KPhysicalAddress(reboot_payload_paddr));
/* Clear IRAM. */
std::memset(GetVoidPointer(iram_address), 0xCC, RebootPayloadSize);
/* Copy the payload to iram. */
for (size_t i = 0; i < RebootPayloadSize / sizeof(u32); ++i) {
GetPointer<volatile u32>(iram_address)[i] = GetPointer<volatile u32>(reboot_payload)[i];
}
/* Reboot. */
smc::SetConfig(smc::ConfigItem::ExosphereNeedsReboot, smc::UserRebootType_ToPayload);
} else {
/* If we don't have a payload, reboot to rcm. */
smc::SetConfig(smc::ConfigItem::ExosphereNeedsReboot, smc::UserRebootType_ToRcm);
}
}
if (g_call_smc_on_panic) {
/* Display a panic screen via secure monitor. */
/* If we should, instruct the secure monitor to display a panic screen. */
smc::Panic(0xF00);
}
u32 dummy;
smc::init::ReadWriteRegister(std::addressof(dummy), 0x7000E400, 0x10, 0x10);
AMS_INFINITE_LOOP();
}

View File

@@ -24,6 +24,10 @@ namespace ams::kern::board::nintendo::nx::smc {
u64 x[8];
};
enum UserFunctionId : u32 {
UserFunctionId_SetConfig = 0xC3000401,
};
enum FunctionId : u32 {
FunctionId_CpuSuspend = 0xC4000001,
FunctionId_CpuOff = 0x84000002,
@@ -33,6 +37,9 @@ namespace ams::kern::board::nintendo::nx::smc {
FunctionId_Panic = 0xC3000006,
FunctionId_ConfigureCarveout = 0xC3000007,
FunctionId_ReadWriteRegister = 0xC3000008,
/* NOTE: Atmosphere extension for mesosphere. This ID is subject to change at any time. */
FunctionId_SetConfig = 0xC3000409,
};
void CallPrivilegedSecureMonitorFunction(SecureMonitorArguments &args) {
@@ -179,13 +186,28 @@ namespace ams::kern::board::nintendo::nx::smc {
}
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
bool TryGetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
SecureMonitorArguments args = { FunctionId_GetConfig, static_cast<u32>(config_item) };
CallPrivilegedSecureMonitorFunction(args);
MESOSPHERE_ABORT_UNLESS((static_cast<SmcResult>(args.x[0]) == SmcResult::Success));
if (static_cast<SmcResult>(args.x[0]) != SmcResult::Success) {
return false;
}
for (size_t i = 0; i < num_qwords && i < 7; i++) {
out[i] = args.x[1 + i];
}
return true;
}
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item) {
MESOSPHERE_ABORT_UNLESS(TryGetConfig(out, num_qwords, config_item));
}
bool SetConfig(ConfigItem config_item, u64 value) {
SecureMonitorArguments args = { FunctionId_SetConfig, static_cast<u32>(config_item), 0, value };
CallPrivilegedSecureMonitorFunction(args);
return static_cast<SmcResult>(args.x[0]) == SmcResult::Success;
}
bool ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value) {

View File

@@ -60,6 +60,10 @@ namespace ams::kern::board::nintendo::nx::smc {
ExosphereNeedsShutdown = 65002,
ExosphereGitCommitHash = 65003,
ExosphereHasRcmBugPatch = 65004,
ExosphereBlankProdInfo = 65005,
ExosphereAllowCalWrites = 65006,
ExosphereEmummcType = 65007,
ExospherePayloadAddress = 65008,
};
enum class SmcResult {
@@ -83,12 +87,20 @@ namespace ams::kern::board::nintendo::nx::smc {
using MemorySize = util::BitPack32::Field<Reserved9::Next, 2, smc::MemorySize>;
};
/* TODO: Rest of Secure Monitor API. */
enum UserRebootType {
UserRebootType_None = 0,
UserRebootType_ToRcm = 1,
UserRebootType_ToPayload = 2,
};
void GenerateRandomBytes(void *dst, size_t size);
bool TryGetConfig(u64 *out, size_t num_qwords, ConfigItem config_item);
void GetConfig(u64 *out, size_t num_qwords, ConfigItem config_item);
bool ReadWriteRegister(u32 *out, ams::svc::PhysicalAddress address, u32 mask, u32 value);
void ConfigureCarveout(size_t which, uintptr_t address, size_t size);
bool SetConfig(ConfigItem config_item, u64 value);
void CpuOn(u64 core_id, uintptr_t entrypoint, uintptr_t arg);
void NORETURN Panic(u32 color);

View File

@@ -18,6 +18,8 @@
namespace ams::kern {
#if defined(MESOSPHERE_DEBUG_LOG_USE_UART_A) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_B) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_C) || defined(MESOSPHERE_DEBUG_LOG_USE_UART_D)
namespace {
enum UartRegister {
@@ -138,4 +140,52 @@ namespace ams::kern {
ReadUartRegister(UartRegister_FCR);
}
#elif defined(MESOSPHERE_DEBUG_LOG_USE_IRAM_RINGBUFFER)
namespace {
constinit KVirtualAddress g_debug_iram_address = 0;
constexpr size_t RingBufferSize = 0x5000;
constinit uintptr_t g_offset = 0;
constinit u8 g_saved_buffer[RingBufferSize];
}
bool KDebugLogImpl::Initialize() {
/* Set the base address. */
g_debug_iram_address = KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsIram) + 0x38000;
std::memset(GetVoidPointer(g_debug_iram_address), 0xFF, RingBufferSize);
return true;
}
void KDebugLogImpl::PutChar(char c) {
GetPointer<char>(g_debug_iram_address)[g_offset++] = c;
if (g_offset == RingBufferSize) {
g_offset = 0;
}
}
void KDebugLogImpl::Flush() {
/* ... */
}
void KDebugLogImpl::Save() {
std::memcpy(g_saved_buffer, GetVoidPointer(g_debug_iram_address), RingBufferSize);
}
void KDebugLogImpl::Restore() {
std::memcpy(GetVoidPointer(g_debug_iram_address), g_saved_buffer, RingBufferSize);
}
#else
#error "Unknown Debug UART device!"
#endif
}

View File

@@ -73,15 +73,16 @@ namespace ams::kern {
s32 num_waiters = 0;
{
KScopedSchedulerLock sl;
g_cv_arbiter_compare_thread.SetupForAddressArbiterCompare(addr, -1);
auto it = this->tree.nfind(g_cv_arbiter_compare_thread);
/* Check the userspace value. */
s32 user_value;
R_UNLESS(UpdateIfEqual(std::addressof(user_value), addr, value, value + 1), svc::ResultInvalidCurrentMemory());
R_UNLESS(user_value == value, svc::ResultInvalidState());
g_cv_arbiter_compare_thread.SetupForAddressArbiterCompare(addr, -1);
auto it = this->tree.nfind(g_cv_arbiter_compare_thread);
while ((it != this->tree.end()) && (count <= 0 || num_waiters < count) && (it->GetAddressArbiterKey() == addr)) {
KThread *target_thread = std::addressof(*it);
target_thread->SetSyncedObject(nullptr, ResultSuccess());
@@ -108,26 +109,54 @@ namespace ams::kern {
/* Determine the updated value. */
s32 new_value;
if (count <= 0) {
if ((it != this->tree.end()) && (it->GetAddressArbiterKey() == addr)) {
new_value = value - 1;
if (GetTargetFirmware() >= TargetFirmware_7_0_0) {
if (count <= 0) {
if ((it != this->tree.end()) && (it->GetAddressArbiterKey() == addr)) {
new_value = value - 2;
} else {
new_value = value + 1;
}
} else {
new_value = value + 1;
if ((it != this->tree.end()) && (it->GetAddressArbiterKey() == addr)) {
auto tmp_it = it;
s32 tmp_num_waiters = 0;
while ((++tmp_it != this->tree.end()) && (tmp_it->GetAddressArbiterKey() == addr)) {
if ((tmp_num_waiters++) >= count) {
break;
}
}
if (tmp_num_waiters < count) {
new_value = value - 1;
} else {
new_value = value;
}
} else {
new_value = value + 1;
}
}
} else {
auto tmp_it = it;
int tmp_num_waiters = 0;
while ((tmp_it != this->tree.end()) && (tmp_it->GetAddressArbiterKey() == addr) && (tmp_num_waiters < count + 1)) {
++tmp_num_waiters;
++tmp_it;
}
if (tmp_num_waiters == 0) {
new_value = value + 1;
} else if (tmp_num_waiters <= count) {
new_value = value - 1;
if (count <= 0) {
if ((it != this->tree.end()) && (it->GetAddressArbiterKey() == addr)) {
new_value = value - 1;
} else {
new_value = value + 1;
}
} else {
new_value = value;
auto tmp_it = it;
s32 tmp_num_waiters = 0;
while ((tmp_it != this->tree.end()) && (tmp_it->GetAddressArbiterKey() == addr) && (tmp_num_waiters < count + 1)) {
++tmp_num_waiters;
++tmp_it;
}
if (tmp_num_waiters == 0) {
new_value = value + 1;
} else if (tmp_num_waiters <= count) {
new_value = value - 1;
} else {
new_value = value;
}
}
}

View File

@@ -133,7 +133,7 @@ namespace ams::kern {
}
/* Map the memory. */
R_TRY(GetCurrentProcess().GetPageTable().MapPageGroup(address, GetReference(this->page_group), KMemoryState_GeneratedCode, k_perm));
R_TRY(this->owner->GetPageTable().MapPageGroup(address, GetReference(this->page_group), KMemoryState_GeneratedCode, k_perm));
/* Mark ourselves as mapped. */
this->is_owner_mapped = true;
@@ -151,7 +151,7 @@ namespace ams::kern {
KScopedLightLock lk(this->lock);
/* Unmap the memory. */
R_TRY(GetCurrentProcess().GetPageTable().UnmapPageGroup(address, GetReference(this->page_group), KMemoryState_GeneratedCode));
R_TRY(this->owner->GetPageTable().UnmapPageGroup(address, GetReference(this->page_group), KMemoryState_GeneratedCode));
/* Mark ourselves as unmapped. */
MESOSPHERE_ASSERT(this->is_owner_mapped);

View File

@@ -205,13 +205,8 @@ namespace ams::kern {
}
/* Close threads in the list. */
if (num_waiters > MaxThreads) {
auto it = thread_list.begin();
while (it != thread_list.end()) {
KThread *thread = std::addressof(*it);
thread->Close();
it = thread_list.erase(it);
}
for (auto it = thread_list.begin(); it != thread_list.end(); it = thread_list.erase(it)) {
(*it).Close();
}
}

View File

@@ -34,6 +34,8 @@ namespace ams::kern {
return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006200, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap);
#elif defined(MESOSPHERE_DEBUG_LOG_USE_UART_D)
return KMemoryLayout::GetPhysicalMemoryRegionTree().Insert(0x70006300, 0x100, KMemoryRegionType_Uart | KMemoryRegionAttr_ShouldKernelMap);
#elif defined(MESOSPHERE_DEBUG_LOG_USE_IRAM_RINGBUFFER)
return true;
#else
#error "Unknown Debug UART device!"
#endif

View File

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

View File

@@ -27,6 +27,11 @@ namespace ams::result::impl {
namespace ams::kern {
/* NOTE: This is not exposed via a header, but is referenced via assembly. */
/* NOTE: Nintendo does not save register contents on panic; we use this */
/* to generate an atmosphere fatal report on panic. */
constinit KExceptionContext g_panic_exception_contexts[cpu::NumCores];
namespace {
constexpr std::array<s32, cpu::NumCores> NegativeArray = [] {
@@ -73,18 +78,38 @@ namespace ams::kern {
} while (!g_current_ticket.compare_exchange_weak(compare, desired));
}
ALWAYS_INLINE KExceptionContext *GetPanicExceptionContext(int core_id) {
#if defined(MESOSPHERE_ENABLE_PANIC_REGISTER_DUMP)
return std::addressof(g_panic_exception_contexts[core_id]);
#else
return nullptr;
#endif
}
[[gnu::unused]] void PrintCurrentState() {
/* Wait for it to be our turn to print. */
WaitCoreTicket();
const s32 core_id = GetCurrentCoreId();
/* Get the current exception context. */
const s32 core_id = GetCurrentCoreId();
const auto *core_ctx = GetPanicExceptionContext(core_id);
/* Print the state. */
MESOSPHERE_RELEASE_LOG("Core[%d] Current State:\n", core_id);
/* TODO: Dump register state. */
#ifdef ATMOSPHERE_ARCH_ARM64
/* Print registers. */
if (core_ctx != nullptr) {
MESOSPHERE_RELEASE_LOG(" Registers:\n");
for (size_t i = 0; i < util::size(core_ctx->x); ++i) {
MESOSPHERE_RELEASE_LOG(" X[%02zx]: %p\n", i, reinterpret_cast<void *>(core_ctx->x[i]));
}
MESOSPHERE_RELEASE_LOG(" SP: %p\n", reinterpret_cast<void *>(core_ctx->x[30]));
}
/* Print backtrace. */
MESOSPHERE_RELEASE_LOG(" Backtrace:\n");
uintptr_t fp = reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
uintptr_t fp = core_ctx != nullptr ? core_ctx->x[29] : reinterpret_cast<uintptr_t>(__builtin_frame_address(0));
for (size_t i = 0; i < 32 && fp && util::IsAligned(fp, 0x10) && cpu::GetPhysicalAddressWritable(nullptr, fp, true); i++) {
struct {
uintptr_t fp;
@@ -107,12 +132,12 @@ namespace ams::kern {
PrintCurrentState();
#endif
KSystemControl::StopSystem();
KSystemControl::StopSystem(GetPanicExceptionContext(GetCurrentCoreId()));
}
}
NORETURN WEAK_SYMBOL void Panic(const char *file, int line, const char *format, ...) {
NORETURN void PanicImpl(const char *file, int line, const char *format, ...) {
#ifdef MESOSPHERE_BUILD_FOR_DEBUGGING
/* Wait for it to be our turn to print. */
WaitCoreTicket();
@@ -133,7 +158,7 @@ namespace ams::kern {
StopSystem();
}
NORETURN WEAK_SYMBOL void Panic() {
NORETURN void PanicImpl() {
StopSystem();
}

View File

@@ -110,7 +110,7 @@ namespace ams::kern::svc {
case ams::svc::CodeMemoryOperation_MapToOwner:
{
/* Check that the region is in range. */
R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_GeneratedCode), svc::ResultInvalidMemoryRegion());
R_UNLESS(code_mem->GetOwner()->GetPageTable().CanContain(address, size, KMemoryState_GeneratedCode), svc::ResultInvalidMemoryRegion());
/* Check the memory permission. */
R_UNLESS(IsValidMapToOwnerCodeMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission());
@@ -122,7 +122,7 @@ namespace ams::kern::svc {
case ams::svc::CodeMemoryOperation_UnmapFromOwner:
{
/* Check that the region is in range. */
R_UNLESS(GetCurrentProcess().GetPageTable().CanContain(address, size, KMemoryState_GeneratedCode), svc::ResultInvalidMemoryRegion());
R_UNLESS(code_mem->GetOwner()->GetPageTable().CanContain(address, size, KMemoryState_GeneratedCode), svc::ResultInvalidMemoryRegion());
/* Check the memory permission. */
R_UNLESS(IsValidUnmapFromOwnerCodeMemoryPermission(perm), svc::ResultInvalidNewMemoryPermission());

View File

@@ -1,7 +1,9 @@
#---------------------------------------------------------------------------------
# pull in common atmosphere configuration
#---------------------------------------------------------------------------------
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../config/common.mk
THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST)))
CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE)))
include $(CURRENT_DIRECTORY)/../config/common.mk
#---------------------------------------------------------------------------------
# pull in switch rules
@@ -15,7 +17,7 @@ include $(DEVKITPRO)/libnx/switch_rules
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
PRECOMPILED_HEADERS := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/include/stratosphere.hpp
PRECOMPILED_HEADERS := $(CURRENT_DIRECTORY)/include/stratosphere.hpp
DEFINES := $(ATMOSPHERE_DEFINES) -DATMOSPHERE_IS_STRATOSPHERE -D_GNU_SOURCE
SETTINGS := $(ATMOSPHERE_SETTINGS) -O2
@@ -66,7 +68,7 @@ endif
export OFILES_BIN := $(addsuffix .o,$(BINFILES))
export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export GCH_FILES := $(foreach hdr,$(PRECOMPILED_HEADERS:.hpp=.gch),$(notdir $(hdr)))
export GCH_FILES := $(PRECOMPILED_HEADERS:.hpp=.hpp.gch)
export OFILES := $(OFILES_BIN) $(OFILES_SRC)
export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES)))
@@ -103,12 +105,12 @@ dist: dist-src dist-bin
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr release lib *.bz2 include/stratosphere.hpp.gch
@rm -fr release lib *.bz2 $(GCH_FILES)
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d) $(GCH_FILES:.gch=.d)
DEPENDS := $(OFILES:.o=.d) $(foreach hdr,$(GCH_FILES:.gch=.d),$(notdir $(hdr)))
#---------------------------------------------------------------------------------
# main targets

View File

@@ -65,47 +65,9 @@ namespace ams::exosphere {
namespace ams {
struct FatalErrorContext : sf::LargeData, sf::PrefersMapAliasTransferMode {
static constexpr size_t MaxStackTrace = 0x20;
static constexpr size_t MaxStackDumpSize = 0x100;
static constexpr size_t ThreadLocalSize = 0x100;
static constexpr size_t NumGprs = 29;
static constexpr uintptr_t StdAbortMagicAddress = 0x8;
static constexpr u64 StdAbortMagicValue = 0xA55AF00DDEADCAFEul;
static constexpr u32 StdAbortErrorDesc = 0xFFE;
static constexpr u32 StackOverflowErrorDesc = 0xFFD;
static constexpr u32 DataAbortErrorDesc = 0x101;
static constexpr u32 Magic = util::FourCC<'A', 'F', 'E', '2'>::Code;
struct FatalErrorContext : ::ams::impl::FatalErrorContext, sf::LargeData, sf::PrefersMapAliasTransferMode {};
u32 magic;
u32 error_desc;
u64 program_id;
union {
u64 gprs[32];
struct {
u64 _gprs[29];
u64 fp;
u64 lr;
u64 sp;
};
};
u64 pc;
u64 module_base;
u32 pstate;
u32 afsr0;
u32 afsr1;
u32 esr;
u64 far;
u64 report_identifier; /* Normally just system tick. */
u64 stack_trace_size;
u64 stack_dump_size;
u64 stack_trace[MaxStackTrace];
u8 stack_dump[MaxStackDumpSize];
u8 tls[ThreadLocalSize];
};
static_assert(sizeof(FatalErrorContext) == 0x450, "sizeof(FatalErrorContext)");
static_assert(util::is_pod<FatalErrorContext>::value, "FatalErrorContext");
static_assert(sizeof(FatalErrorContext) == sizeof(::ams::impl::FatalErrorContext));
#ifdef ATMOSPHERE_GIT_BRANCH
NX_CONSTEXPR const char *GetGitBranch() {

View File

@@ -29,7 +29,7 @@ namespace ams::spl::smc {
}
/* Functions. */
Result SetConfig(spl::ConfigItem which, const u64 *value, size_t num_qwords);
Result SetConfig(spl::ConfigItem which, const void *address, const u64 *value, size_t num_qwords);
Result GetConfig(u64 *out, size_t num_qwords, spl::ConfigItem which);
Result GetResult(Result *out, AsyncOperationKey op);
Result GetResultData(Result *out, void *out_buf, size_t out_buf_size, AsyncOperationKey op);
@@ -59,8 +59,12 @@ namespace ams::spl::smc {
Result AtmosphereGetEmummcConfig(void *out_config, void *out_paths, u32 storage_id);
/* Helpers. */
inline Result SetConfig(spl::ConfigItem which, const u64 *value, size_t num_qwords) {
return SetConfig(which, nullptr, value, num_qwords);
}
inline Result SetConfig(spl::ConfigItem which, const u64 value) {
return SetConfig(which, &value, 1);
return SetConfig(which, std::addressof(value), 1);
}
}

View File

@@ -222,6 +222,7 @@ namespace ams::spl {
ExosphereBlankProdInfo = 65005,
ExosphereAllowCalWrites = 65006,
ExosphereEmummcType = 65007,
ExospherePayloadAddress = 65008,
};
}
@@ -235,3 +236,4 @@ constexpr inline SplConfigItem SplConfigItem_ExosphereHasRcmBugPatch = static_ca
constexpr inline SplConfigItem SplConfigItem_ExosphereBlankProdInfo = static_cast<SplConfigItem>(65005);
constexpr inline SplConfigItem SplConfigItem_ExosphereAllowCalWrites = static_cast<SplConfigItem>(65006);
constexpr inline SplConfigItem SplConfigItem_ExosphereEmummcType = static_cast<SplConfigItem>(65007);
constexpr inline SplConfigItem SplConfigItem_ExospherePayloadAddress = static_cast<SplConfigItem>(65008);

View File

@@ -74,7 +74,10 @@ namespace ams {
ams_ctx.pc = ctx->pc.x;
ams_ctx.pstate = ctx->pstate;
ams_ctx.afsr0 = ctx->afsr0;
ams_ctx.afsr1 = ctx->afsr1;
ams_ctx.afsr1 = (static_cast<u64>(::ams::exosphere::GetVersion(ATMOSPHERE_RELEASE_VERSION)) << 32) | static_cast<u64>(hos::GetVersion());
if (svc::IsKernelMesosphere()) {
ams_ctx.afsr1 |= (static_cast<u64>('M') << (BITSIZEOF(u64) - BITSIZEOF(u8)));
}
ams_ctx.far = ctx->far.x;
ams_ctx.report_identifier = armGetSystemTick();

View File

@@ -24,7 +24,7 @@ namespace ams::erpt::srv {
attachment_id.uuid.ToString(uuid_str, sizeof(uuid_str));
AttachmentFileName attachment_name;
std::snprintf(attachment_name.name, sizeof(attachment_name.name), "%s/%s.att", ReportStoragePath, uuid_str);
std::snprintf(attachment_name.name, sizeof(attachment_name.name), "%s:/%s.att", ReportStoragePath, uuid_str);
return attachment_name;
}

View File

@@ -17,12 +17,12 @@
namespace ams::spl::smc {
Result SetConfig(spl::ConfigItem which, const u64 *value, size_t num_qwords) {
Result SetConfig(spl::ConfigItem which, const void *address, const u64 *value, size_t num_qwords) {
SecmonArgs args;
args.X[0] = static_cast<u64>(FunctionId::SetConfig);
args.X[1] = static_cast<u64>(which);
args.X[2] = 0;
args.X[2] = reinterpret_cast<u64>(address);
for (size_t i = 0; i < std::min(size_t(4), num_qwords); i++) {
args.X[3 + i] = value[i];
}

View File

@@ -27,3 +27,5 @@
#include <vapours/results.hpp>
#include <vapours/crypto.hpp>
#include <vapours/svc.hpp>
#include <vapours/ams/ams_fatal_error_context.hpp>

View File

@@ -16,8 +16,8 @@
#pragma once
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
#define ATMOSPHERE_RELEASE_VERSION_MINOR 14
#define ATMOSPHERE_RELEASE_VERSION_MICRO 3
#define ATMOSPHERE_RELEASE_VERSION_MINOR 15
#define ATMOSPHERE_RELEASE_VERSION_MICRO 0
#define ATMOSPHERE_RELEASE_VERSION ATMOSPHERE_RELEASE_VERSION_MAJOR, ATMOSPHERE_RELEASE_VERSION_MINOR, ATMOSPHERE_RELEASE_VERSION_MICRO

View File

@@ -0,0 +1,66 @@
/*
* 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/includes.hpp>
#include <vapours/defines.hpp>
namespace ams::impl {
struct FatalErrorContext {
static constexpr size_t MaxStackTrace = 0x20;
static constexpr size_t MaxStackDumpSize = 0x100;
static constexpr size_t ThreadLocalSize = 0x100;
static constexpr size_t NumGprs = 29;
static constexpr uintptr_t StdAbortMagicAddress = 0x8;
static constexpr u64 StdAbortMagicValue = 0xA55AF00DDEADCAFEul;
static constexpr u32 StdAbortErrorDesc = 0xFFE;
static constexpr u32 StackOverflowErrorDesc = 0xFFD;
static constexpr u32 KernelPanicDesc = 0xF00;
static constexpr u32 DataAbortErrorDesc = 0x101;
static constexpr u32 Magic = util::FourCC<'A', 'F', 'E', '2'>::Code;
u32 magic;
u32 error_desc;
u64 program_id;
union {
u64 gprs[32];
struct {
u64 _gprs[29];
u64 fp;
u64 lr;
u64 sp;
};
};
u64 pc;
u64 module_base;
u32 pstate;
u32 afsr0;
u32 afsr1;
u32 esr;
u64 far;
u64 report_identifier; /* Normally just system tick. */
u64 stack_trace_size;
u64 stack_dump_size;
u64 stack_trace[MaxStackTrace];
u8 stack_dump[MaxStackDumpSize];
u8 tls[ThreadLocalSize];
};
static_assert(sizeof(FatalErrorContext) == 0x450);
static_assert(std::is_standard_layout<FatalErrorContext>::value);
static_assert(std::is_trivial<FatalErrorContext>::value);
}

View File

@@ -22,58 +22,267 @@
namespace ams::util {
namespace impl {
class IntrusiveRedBlackTreeImpl;
}
struct IntrusiveRedBlackTreeNode {
NON_COPYABLE(IntrusiveRedBlackTreeNode);
private:
RB_ENTRY(IntrusiveRedBlackTreeNode) entry;
friend class impl::IntrusiveRedBlackTreeImpl;
template<class, class, class>
friend class IntrusiveRedBlackTree;
template<class, class>
friend class IntrusiveRedBlackTreeImpl;
public:
constexpr IntrusiveRedBlackTreeNode() : entry() { /* ... */}
};
static_assert(std::is_literal_type<IntrusiveRedBlackTreeNode>::value);
template<class T, class Traits>
class IntrusiveRedBlackTreeImpl {
NON_COPYABLE(IntrusiveRedBlackTreeImpl);
protected:
RB_HEAD(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode);
using RootType = IntrusiveRedBlackTreeRoot;
protected:
IntrusiveRedBlackTreeRoot root;
template<class T, class Traits, class Comparator>
class IntrusiveRedBlackTree;
namespace impl {
class IntrusiveRedBlackTreeImpl {
NON_COPYABLE(IntrusiveRedBlackTreeImpl);
private:
template<class, class, class>
friend class ::ams::util::IntrusiveRedBlackTree;
private:
RB_HEAD(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode);
using RootType = IntrusiveRedBlackTreeRoot;
private:
IntrusiveRedBlackTreeRoot root;
public:
template<bool Const>
class Iterator;
using value_type = IntrusiveRedBlackTreeNode;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = value_type *;
using const_pointer = const value_type *;
using reference = value_type &;
using const_reference = const value_type &;
using iterator = Iterator<false>;
using const_iterator = Iterator<true>;
template<bool Const>
class Iterator {
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename IntrusiveRedBlackTreeImpl::value_type;
using difference_type = typename IntrusiveRedBlackTreeImpl::difference_type;
using pointer = typename std::conditional<Const, IntrusiveRedBlackTreeImpl::const_pointer, IntrusiveRedBlackTreeImpl::pointer>::type;
using reference = typename std::conditional<Const, IntrusiveRedBlackTreeImpl::const_reference, IntrusiveRedBlackTreeImpl::reference>::type;
private:
pointer node;
public:
explicit Iterator(pointer n) : node(n) { /* ... */ }
bool operator==(const Iterator &rhs) const {
return this->node == rhs.node;
}
bool operator!=(const Iterator &rhs) const {
return !(*this == rhs);
}
pointer operator->() const {
return this->node;
}
reference operator*() const {
return *this->node;
}
Iterator &operator++() {
this->node = GetNext(this->node);
return *this;
}
Iterator &operator--() {
this->node = GetPrev(this->node);
return *this;
}
Iterator operator++(int) {
const Iterator it{*this};
++(*this);
return it;
}
Iterator operator--(int) {
const Iterator it{*this};
--(*this);
return it;
}
operator Iterator<true>() const {
return Iterator<true>(this->node);
}
};
protected:
/* Generate static implementations for non-comparison operations for IntrusiveRedBlackTreeRoot. */
RB_GENERATE_WITHOUT_COMPARE_STATIC(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode, entry);
private:
/* Define accessors using RB_* functions. */
constexpr ALWAYS_INLINE void InitializeImpl() {
RB_INIT(&this->root);
}
bool EmptyImpl() const {
return RB_EMPTY(&this->root);
}
IntrusiveRedBlackTreeNode *GetMinImpl() const {
return RB_MIN(IntrusiveRedBlackTreeRoot, const_cast<IntrusiveRedBlackTreeRoot *>(&this->root));
}
IntrusiveRedBlackTreeNode *GetMaxImpl() const {
return RB_MAX(IntrusiveRedBlackTreeRoot, const_cast<IntrusiveRedBlackTreeRoot *>(&this->root));
}
IntrusiveRedBlackTreeNode *RemoveImpl(IntrusiveRedBlackTreeNode *node) {
return RB_REMOVE(IntrusiveRedBlackTreeRoot, &this->root, node);
}
public:
static IntrusiveRedBlackTreeNode *GetNext(IntrusiveRedBlackTreeNode *node) {
return RB_NEXT(IntrusiveRedBlackTreeRoot, nullptr, node);
}
static IntrusiveRedBlackTreeNode *GetPrev(IntrusiveRedBlackTreeNode *node) {
return RB_PREV(IntrusiveRedBlackTreeRoot, nullptr, node);
}
static ALWAYS_INLINE IntrusiveRedBlackTreeNode const *GetNext(IntrusiveRedBlackTreeNode const *node) {
return static_cast<const IntrusiveRedBlackTreeNode *>(GetNext(const_cast<IntrusiveRedBlackTreeNode *>(node)));
}
static ALWAYS_INLINE IntrusiveRedBlackTreeNode const *GetPrev(IntrusiveRedBlackTreeNode const *node) {
return static_cast<const IntrusiveRedBlackTreeNode *>(GetPrev(const_cast<IntrusiveRedBlackTreeNode *>(node)));
}
public:
constexpr IntrusiveRedBlackTreeImpl() : root() {
this->InitializeImpl();
}
/* Iterator accessors. */
iterator begin() {
return iterator(this->GetMinImpl());
}
const_iterator begin() const {
return const_iterator(this->GetMinImpl());
}
iterator end() {
return iterator(static_cast<IntrusiveRedBlackTreeNode *>(nullptr));
}
const_iterator end() const {
return const_iterator(static_cast<const IntrusiveRedBlackTreeNode *>(nullptr));
}
const_iterator cbegin() const {
return this->begin();
}
const_iterator cend() const {
return this->end();
}
iterator iterator_to(reference ref) {
return iterator(&ref);
}
const_iterator iterator_to(const_reference ref) const {
return const_iterator(&ref);
}
/* Content management. */
bool empty() const {
return this->EmptyImpl();
}
reference back() {
return *this->GetMaxImpl();
}
const_reference back() const {
return *this->GetMaxImpl();
}
reference front() {
return *this->GetMinImpl();
}
const_reference front() const {
return *this->GetMinImpl();
}
iterator erase(iterator it) {
auto cur = std::addressof(*it);
auto next = GetNext(cur);
this->RemoveImpl(cur);
return iterator(next);
}
};
}
template<class T, class Traits, class Comparator>
class IntrusiveRedBlackTree {
NON_COPYABLE(IntrusiveRedBlackTree);
public:
using ImplType = impl::IntrusiveRedBlackTreeImpl;
private:
ImplType impl;
public:
struct IntrusiveRedBlackTreeRootWithCompare : ImplType::IntrusiveRedBlackTreeRoot{};
template<bool Const>
class Iterator;
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = T *;
using const_pointer = const T *;
using reference = T &;
using const_reference = const T &;
using iterator = Iterator<false>;
using const_iterator = Iterator<true>;
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using pointer = T *;
using const_pointer = const T *;
using reference = T &;
using const_reference = const T &;
using iterator = Iterator<false>;
using const_iterator = Iterator<true>;
template<bool Const>
class Iterator {
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename IntrusiveRedBlackTreeImpl::value_type;
using difference_type = typename IntrusiveRedBlackTreeImpl::difference_type;
using pointer = typename std::conditional<Const, IntrusiveRedBlackTreeImpl::const_pointer, IntrusiveRedBlackTreeImpl::pointer>::type;
using reference = typename std::conditional<Const, IntrusiveRedBlackTreeImpl::const_reference, IntrusiveRedBlackTreeImpl::reference>::type;
private:
pointer node;
public:
explicit Iterator(pointer n) : node(n) { /* ... */ }
friend class IntrusiveRedBlackTree<T, Traits, Comparator>;
using ImplIterator = typename std::conditional<Const, ImplType::const_iterator, ImplType::iterator>::type;
using iterator_category = std::bidirectional_iterator_tag;
using value_type = typename IntrusiveRedBlackTree::value_type;
using difference_type = typename IntrusiveRedBlackTree::difference_type;
using pointer = typename std::conditional<Const, IntrusiveRedBlackTree::const_pointer, IntrusiveRedBlackTree::pointer>::type;
using reference = typename std::conditional<Const, IntrusiveRedBlackTree::const_reference, IntrusiveRedBlackTree::reference>::type;
private:
ImplIterator iterator;
private:
explicit Iterator(ImplIterator it) : iterator(it) { /* ... */ }
explicit Iterator(ImplIterator::pointer p) : iterator(p) { /* ... */ }
ImplIterator GetImplIterator() const {
return this->iterator;
}
public:
bool operator==(const Iterator &rhs) const {
return this->node == rhs.node;
return this->iterator == rhs.iterator;
}
bool operator!=(const Iterator &rhs) const {
@@ -81,99 +290,77 @@ namespace ams::util {
}
pointer operator->() const {
return this->node;
return Traits::GetParent(std::addressof(*this->iterator));
}
reference operator*() const {
return *this->node;
return *Traits::GetParent(std::addressof(*this->iterator));
}
Iterator &operator++() {
this->node = Traits::GetParent(GetNext(Traits::GetNode(this->node)));
++this->iterator;
return *this;
}
Iterator &operator--() {
this->node = Traits::GetParent(GetPrev(Traits::GetNode(this->node)));
--this->iterator;
return *this;
}
Iterator operator++(int) {
const Iterator it{*this};
++(*this);
++this->iterator;
return it;
}
Iterator operator--(int) {
const Iterator it{*this};
--(*this);
--this->iterator;
return it;
}
operator Iterator<true>() const {
return Iterator<true>(this->node);
return Iterator<true>(this->iterator);
}
};
protected:
/* Generate static implementations for non-comparison operations for IntrusiveRedBlackTreeRoot. */
RB_GENERATE_WITHOUT_COMPARE_STATIC(IntrusiveRedBlackTreeRoot, IntrusiveRedBlackTreeNode, entry);
private:
/* Generate static implementations for comparison operations for IntrusiveRedBlackTreeRoot. */
RB_GENERATE_WITH_COMPARE_STATIC(IntrusiveRedBlackTreeRootWithCompare, IntrusiveRedBlackTreeNode, entry, CompareImpl);
private:
static int CompareImpl(const IntrusiveRedBlackTreeNode *lhs, const IntrusiveRedBlackTreeNode *rhs) {
return Comparator::Compare(*Traits::GetParent(lhs), *Traits::GetParent(rhs));
}
/* Define accessors using RB_* functions. */
constexpr ALWAYS_INLINE void InitializeImpl() {
RB_INIT(&this->root);
IntrusiveRedBlackTreeNode *InsertImpl(IntrusiveRedBlackTreeNode *node) {
return RB_INSERT(IntrusiveRedBlackTreeRootWithCompare, static_cast<IntrusiveRedBlackTreeRootWithCompare *>(&this->impl.root), node);
}
bool EmptyImpl() const {
return RB_EMPTY(&this->root);
IntrusiveRedBlackTreeNode *FindImpl(IntrusiveRedBlackTreeNode const *node) const {
return RB_FIND(IntrusiveRedBlackTreeRootWithCompare, const_cast<IntrusiveRedBlackTreeRootWithCompare *>(static_cast<const IntrusiveRedBlackTreeRootWithCompare *>(&this->impl.root)), const_cast<IntrusiveRedBlackTreeNode *>(node));
}
IntrusiveRedBlackTreeNode *GetMinImpl() const {
return RB_MIN(IntrusiveRedBlackTreeRoot, const_cast<IntrusiveRedBlackTreeRoot *>(&this->root));
}
IntrusiveRedBlackTreeNode *GetMaxImpl() const {
return RB_MAX(IntrusiveRedBlackTreeRoot, const_cast<IntrusiveRedBlackTreeRoot *>(&this->root));
}
IntrusiveRedBlackTreeNode *RemoveImpl(IntrusiveRedBlackTreeNode *node) {
return RB_REMOVE(IntrusiveRedBlackTreeRoot, &this->root, node);
IntrusiveRedBlackTreeNode *NFindImpl(IntrusiveRedBlackTreeNode const *node) const {
return RB_NFIND(IntrusiveRedBlackTreeRootWithCompare, const_cast<IntrusiveRedBlackTreeRootWithCompare *>(static_cast<const IntrusiveRedBlackTreeRootWithCompare *>(&this->impl.root)), const_cast<IntrusiveRedBlackTreeNode *>(node));
}
public:
static constexpr inline IntrusiveRedBlackTreeNode *GetNext(IntrusiveRedBlackTreeNode *node) {
return RB_NEXT(IntrusiveRedBlackTreeRoot, nullptr, node);
}
static constexpr inline IntrusiveRedBlackTreeNode const *GetNext(IntrusiveRedBlackTreeNode const *node) {
return const_cast<const IntrusiveRedBlackTreeNode *>(GetNext(const_cast<IntrusiveRedBlackTreeNode *>(node)));
}
static constexpr inline IntrusiveRedBlackTreeNode *GetPrev(IntrusiveRedBlackTreeNode *node) {
return RB_PREV(IntrusiveRedBlackTreeRoot, nullptr, node);
}
static constexpr inline IntrusiveRedBlackTreeNode const *GetPrev(IntrusiveRedBlackTreeNode const *node) {
return const_cast<const IntrusiveRedBlackTreeNode *>(GetPrev(const_cast<IntrusiveRedBlackTreeNode *>(node)));
}
public:
constexpr ALWAYS_INLINE IntrusiveRedBlackTreeImpl() : root() {
this->InitializeImpl();
}
constexpr ALWAYS_INLINE IntrusiveRedBlackTree() : impl() { /* ... */ }
/* Iterator accessors. */
iterator begin() {
return iterator(Traits::GetParent(this->GetMinImpl()));
return iterator(this->impl.begin());
}
const_iterator begin() const {
return const_iterator(Traits::GetParent(this->GetMinImpl()));
return const_iterator(this->impl.begin());
}
iterator end() {
return iterator(Traits::GetParent(static_cast<IntrusiveRedBlackTreeNode *>(nullptr)));
return iterator(this->impl.end());
}
const_iterator end() const {
return const_iterator(Traits::GetParent(static_cast<IntrusiveRedBlackTreeNode *>(nullptr)));
return const_iterator(this->impl.end());
}
const_iterator cbegin() const {
@@ -185,93 +372,50 @@ namespace ams::util {
}
iterator iterator_to(reference ref) {
return iterator(&ref);
return iterator(this->impl.iterator_to(*Traits::GetNode(std::addressof(ref))));
}
const_iterator iterator_to(const_reference ref) const {
return const_iterator(&ref);
return const_iterator(this->impl.iterator_to(*Traits::GetNode(std::addressof(ref))));
}
/* Content management. */
bool empty() const {
return this->EmptyImpl();
return this->impl.empty();
}
reference back() {
return *Traits::GetParent(this->GetMaxImpl());
return *Traits::GetParent(std::addressof(this->impl.back()));
}
const_reference back() const {
return *Traits::GetParent(this->GetMaxImpl());
return *Traits::GetParent(std::addressof(this->impl.back()));
}
reference front() {
return *Traits::GetParent(this->GetMinImpl());
return *Traits::GetParent(std::addressof(this->impl.front()));
}
const_reference front() const {
return *Traits::GetParent(this->GetMinImpl());
return *Traits::GetParent(std::addressof(this->impl.front()));
}
iterator erase(iterator it) {
auto cur = Traits::GetNode(&*it);
auto next = Traits::GetParent(GetNext(cur));
this->RemoveImpl(cur);
return iterator(next);
return iterator(this->impl.erase(it.GetImplIterator()));
}
};
template<class T, class Traits, class Comparator>
class IntrusiveRedBlackTree : public IntrusiveRedBlackTreeImpl<T, Traits> {
NON_COPYABLE(IntrusiveRedBlackTree);
public:
using ImplType = IntrusiveRedBlackTreeImpl<T, Traits>;
struct IntrusiveRedBlackTreeRootWithCompare : ImplType::IntrusiveRedBlackTreeRoot{};
using value_type = ImplType::value_type;
using size_type = ImplType::size_type;
using difference_type = ImplType::difference_type;
using pointer = ImplType::pointer;
using const_pointer = ImplType::const_pointer;
using reference = ImplType::reference;
using const_reference = ImplType::const_reference;
using iterator = ImplType::iterator;
using const_iterator = ImplType::const_iterator;
protected:
/* Generate static implementations for comparison operations for IntrusiveRedBlackTreeRoot. */
RB_GENERATE_WITH_COMPARE_STATIC(IntrusiveRedBlackTreeRootWithCompare, IntrusiveRedBlackTreeNode, entry, CompareImpl);
private:
static int CompareImpl(const IntrusiveRedBlackTreeNode *lhs, const IntrusiveRedBlackTreeNode *rhs) {
return Comparator::Compare(*Traits::GetParent(lhs), *Traits::GetParent(rhs));
}
/* Define accessors using RB_* functions. */
IntrusiveRedBlackTreeNode *InsertImpl(IntrusiveRedBlackTreeNode *node) {
return RB_INSERT(IntrusiveRedBlackTreeRootWithCompare, static_cast<IntrusiveRedBlackTreeRootWithCompare *>(&this->root), node);
}
IntrusiveRedBlackTreeNode *FindImpl(IntrusiveRedBlackTreeNode const *node) const {
return RB_FIND(IntrusiveRedBlackTreeRootWithCompare, const_cast<IntrusiveRedBlackTreeRootWithCompare *>(static_cast<const IntrusiveRedBlackTreeRootWithCompare *>(&this->root)), const_cast<IntrusiveRedBlackTreeNode *>(node));
}
IntrusiveRedBlackTreeNode *NFindImpl(IntrusiveRedBlackTreeNode const *node) const {
return RB_NFIND(IntrusiveRedBlackTreeRootWithCompare, const_cast<IntrusiveRedBlackTreeRootWithCompare *>(static_cast<const IntrusiveRedBlackTreeRootWithCompare *>(&this->root)), const_cast<IntrusiveRedBlackTreeNode *>(node));
}
public:
constexpr ALWAYS_INLINE IntrusiveRedBlackTree() : ImplType() { /* ... */ }
iterator insert(reference ref) {
this->InsertImpl(Traits::GetNode(&ref));
return iterator(&ref);
ImplType::pointer node = Traits::GetNode(std::addressof(ref));
this->InsertImpl(node);
return iterator(node);
}
iterator find(const_reference ref) const {
return iterator(Traits::GetParent(this->FindImpl(Traits::GetNode(&ref))));
return iterator(this->FindImpl(Traits::GetNode(std::addressof(ref))));
}
iterator nfind(const_reference ref) const {
return iterator(Traits::GetParent(this->NFindImpl(Traits::GetNode(&ref))));
return iterator(this->NFindImpl(Traits::GetNode(std::addressof(ref))));
}
};
@@ -283,12 +427,12 @@ namespace ams::util {
public:
template<class Comparator>
using TreeType = IntrusiveRedBlackTree<Derived, IntrusiveRedBlackTreeMemberTraits, Comparator>;
using TreeTypeImpl = IntrusiveRedBlackTreeImpl<Derived, IntrusiveRedBlackTreeMemberTraits>;
using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl;
private:
template<class, class, class>
friend class IntrusiveRedBlackTree;
template<class, class>
friend class IntrusiveRedBlackTreeImpl;
friend class impl::IntrusiveRedBlackTreeImpl;
static constexpr IntrusiveRedBlackTreeNode *GetNode(Derived *parent) {
return std::addressof(parent->*Member);
@@ -318,7 +462,7 @@ namespace ams::util {
public:
template<class Comparator>
using TreeType = IntrusiveRedBlackTree<Derived, IntrusiveRedBlackTreeMemberTraitsDeferredAssert, Comparator>;
using TreeTypeImpl = IntrusiveRedBlackTreeImpl<Derived, IntrusiveRedBlackTreeMemberTraitsDeferredAssert>;
using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl;
static constexpr bool IsValid() {
TYPED_STORAGE(Derived) DerivedStorage = {};
@@ -327,8 +471,8 @@ namespace ams::util {
private:
template<class, class, class>
friend class IntrusiveRedBlackTree;
template<class, class>
friend class IntrusiveRedBlackTreeImpl;
friend class impl::IntrusiveRedBlackTreeImpl;
static constexpr IntrusiveRedBlackTreeNode *GetNode(Derived *parent) {
return std::addressof(parent->*Member);
@@ -350,11 +494,11 @@ namespace ams::util {
template<class Derived>
class IntrusiveRedBlackTreeBaseNode : public IntrusiveRedBlackTreeNode {
public:
constexpr ALWAYS_INLINE Derived *GetPrev();
constexpr ALWAYS_INLINE const Derived *GetPrev() const;
constexpr ALWAYS_INLINE Derived *GetPrev() { return static_cast< Derived *>(impl::IntrusiveRedBlackTreeImpl::GetPrev(this)); }
constexpr ALWAYS_INLINE const Derived *GetPrev() const { return static_cast<const Derived *>(impl::IntrusiveRedBlackTreeImpl::GetPrev(this)); }
constexpr ALWAYS_INLINE Derived *GetNext();
constexpr ALWAYS_INLINE const Derived *GetNext() const;
constexpr ALWAYS_INLINE Derived *GetNext() { return static_cast< Derived *>(impl::IntrusiveRedBlackTreeImpl::GetNext(this)); }
constexpr ALWAYS_INLINE const Derived *GetNext() const { return static_cast<const Derived *>(impl::IntrusiveRedBlackTreeImpl::GetNext(this)); }
};
template<class Derived>
@@ -362,12 +506,12 @@ namespace ams::util {
public:
template<class Comparator>
using TreeType = IntrusiveRedBlackTree<Derived, IntrusiveRedBlackTreeBaseTraits, Comparator>;
using TreeTypeImpl = IntrusiveRedBlackTreeImpl<Derived, IntrusiveRedBlackTreeBaseTraits>;
using TreeTypeImpl = impl::IntrusiveRedBlackTreeImpl;
private:
template<class, class, class>
friend class IntrusiveRedBlackTree;
template<class, class>
friend class IntrusiveRedBlackTreeImpl;
friend class impl::IntrusiveRedBlackTreeImpl;
static constexpr IntrusiveRedBlackTreeNode *GetNode(Derived *parent) {
return static_cast<IntrusiveRedBlackTreeNode *>(parent);
@@ -386,16 +530,4 @@ namespace ams::util {
}
};
template<class Derived>
constexpr Derived *IntrusiveRedBlackTreeBaseNode<Derived>::GetPrev() { using TreeType = typename IntrusiveRedBlackTreeBaseTraits<Derived>::TreeTypeImpl; return static_cast<Derived *>(TreeType::GetPrev(static_cast<Derived *>(this))); }
template<class Derived>
constexpr const Derived *IntrusiveRedBlackTreeBaseNode<Derived>::GetPrev() const { using TreeType = typename IntrusiveRedBlackTreeBaseTraits<Derived>::TreeTypeImpl; return static_cast<const Derived *>(TreeType::GetPrev(static_cast<const Derived *>(this))); }
template<class Derived>
constexpr Derived *IntrusiveRedBlackTreeBaseNode<Derived>::GetNext() { using TreeType = typename IntrusiveRedBlackTreeBaseTraits<Derived>::TreeTypeImpl; return static_cast<Derived *>(TreeType::GetNext(static_cast<Derived *>(this))); }
template<class Derived>
constexpr const Derived *IntrusiveRedBlackTreeBaseNode<Derived>::GetNext() const { using TreeType = typename IntrusiveRedBlackTreeBaseTraits<Derived>::TreeTypeImpl; return static_cast<const Derived *>(TreeType::GetNext(static_cast<const Derived *>(this))); }
}

View File

@@ -1,26 +1,41 @@
TARGETS := kernel.bin kernel_ldr.bin
CLEAN_TARGETS := $(foreach target,$(TARGETS),$(target:.bin=)-clean)
ATMOSPHERE_BUILD_CONFIGS :=
all: release
SUBFOLDERS := $(MODULES)
define ATMOSPHERE_ADD_TARGET
all: mesosphere.bin
ATMOSPHERE_BUILD_CONFIGS += $(strip $1)
clean: $(CLEAN_TARGETS)
@rm -f mesosphere.bin
$(strip $1): mesosphere$(strip $2).bin
mesosphere.bin: $(TARGETS)
@python build_mesosphere.py
@echo "Built mesosphere.bin..."
mesosphere$(strip $2).bin: kernel/kernel$(strip $2).bin kernel_ldr/kernel_ldr$(strip $2).bin
@python build_mesosphere.py kernel_ldr/kernel_ldr$(strip $2).bin kernel/kernel$(strip $2).bin mesosphere$(strip $2).bin
@echo "Built mesosphere$(strip $2).bin..."
$(TARGETS): check_libmeso
$(MAKE) -C $(@:.bin=)
@cp $(@:.bin=)/$(@) $(@)
kernel/kernel$(strip $2).bin: check_libmeso$(strip $1)
@$$(MAKE) -C kernel $(strip $1)
check_libmeso:
@$(MAKE) --no-print-directory -C ../libraries/libmesosphere
kernel_ldr/kernel_ldr$(strip $2).bin: check_libmeso$(strip $1)
@$$(MAKE) -C kernel_ldr $(strip $1)
$(CLEAN_TARGETS):
$(MAKE) -C $(@:-clean=) clean
@rm -f $(@:-clean=).bin
check_libmeso$(strip $1):
@$$(MAKE) -C ../libraries/libmesosphere $(strip $1)
.PHONY: all clean $(CLEAN_TARGETS)
clean-$(strip $1):
@$$(MAKE) -C ../libraries/libmesosphere clean-$(strip $1)
@$$(MAKE) -C kernel clean-$(strip $1)
@$$(MAKE) -C kernel_ldr clean-$(strip $1)
@rm -f mesosphere$(strip $2).bin
endef
$(eval $(call ATMOSPHERE_ADD_TARGET, release, ,))
$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug,))
$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit,))
clean:
@$(MAKE) -C ../libraries/libmesosphere clean
@$(MAKE) -C kernel clean
@$(MAKE) -C kernel_ldr clean
@rm -f mesosphere*.bin
.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config))

View File

@@ -11,12 +11,12 @@ def align_up(val, algn):
def main(argc, argv):
if argc != 1:
print('Usage: %s' % argv[0])
if argc != 4:
print('Usage: %s kernel_ldr.bin kernel.bin output.bin' % argv[0])
return 1
with open('kernel_ldr/kernel_ldr.bin', 'rb') as f:
with open(argv[1], 'rb') as f:
kernel_ldr = f.read()
with open('kernel/kernel.bin', 'rb') as f:
with open(argv[2], 'rb') as f:
kernel = f.read()
kernel_metadata_offset = 4
assert (kernel_metadata_offset <= len(kernel) - 0x40)
@@ -37,7 +37,7 @@ def main(argc, argv):
kernel_ldr_end = kernel_ldr_offset + len(kernel_ldr)
mesosphere_end = align_up(kernel_ldr_end, 0x1000)
with open('mesosphere.bin', 'wb') as f:
with open(argv[3], 'wb') as f:
f.write(kernel[:kernel_metadata_offset + 4])
f.write(pk('<QQI', embedded_ini_offset, kernel_ldr_offset, atmosphere_target_firmware(10, 1, 0)))
f.write(kernel[kernel_metadata_offset + 0x18:])

View File

@@ -1,20 +1,18 @@
#---------------------------------------------------------------------------------
# pull in common atmosphere configuration
#---------------------------------------------------------------------------------
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/mesosphere.mk
THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST)))
CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE)))
include $(CURRENT_DIRECTORY)/../../libraries/config/templates/mesosphere.mk
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
ifneq ($(__RECURSIVE__),1)
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
@@ -44,41 +42,72 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I.
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR))
.PHONY: $(BUILD) clean all
export TOPDIR := $(CURRENT_DIRECTORY)
OUTPUT_BASE := $(TOPDIR)/$(notdir $(TOPDIR))
#---------------------------------------------------------------------------------
all: $(BUILD) check_libmeso
$(BUILD): check_libmeso
ATMOSPHERE_BUILD_CONFIGS :=
all: release
define ATMOSPHERE_ADD_TARGET
ATMOSPHERE_BUILD_CONFIGS += $(strip $1)
$(strip $1): check_libmeso_$(strip $1) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1)
@$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(OUTPUT_BASE)$(strip $2) $(3) \
DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \
LIBMESOSPHERE_NAME=mesosphere$(strip $2) \
--no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \
-f $$(THIS_MAKEFILE)
check_libmeso_$(strip $1):
@$$(MAKE) --no-print-directory -C ../../libraries/libmesosphere $(strip $1)
clean-$(strip $1):
@echo clean $(strip $1) ...
@rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(OUTPUT_BASE)$(strip $2).bin $$(OUTPUT_BASE)$(strip $2).elf
endef
$(eval $(call ATMOSPHERE_ADD_TARGET, release, , \
ATMOSPHERE_BUILD_SETTINGS="" \
))
$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug, \
ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_DEBUGGING" \
))
$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit, \
ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_AUDITING" \
))
$(ATMOSPHERE_BUILD_DIR)/%:
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
check_libmeso:
@$(MAKE) --no-print-directory -C ../../libraries/libmesosphere
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(OUTPUT).bin $(OUTPUT).elf
clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config))
.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config))
#---------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all : $(OUTPUT).bin
$(OUTPUT).bin : $(OUTPUT).elf
$(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@
@echo built ... $(notdir $@)
$(OUTPUT).elf : $(OFILES) ../../../libraries/libmesosphere/lib/libmesosphere.a
$(OUTPUT).elf : $(OFILES)
$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/$(ATMOSPHERE_LIBRARY_DIR)/lib$(LIBMESOSPHERE_NAME).a
%.elf:
@echo linking $(notdir $@)
@@ -101,4 +130,4 @@ kern_libc_generic.o: CFLAGS += -fno-builtin
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------

View File

@@ -1,20 +1,18 @@
#---------------------------------------------------------------------------------
# pull in common atmosphere configuration
#---------------------------------------------------------------------------------
include $(dir $(abspath $(lastword $(MAKEFILE_LIST))))/../../libraries/config/templates/mesosphere.mk
THIS_MAKEFILE := $(abspath $(lastword $(MAKEFILE_LIST)))
CURRENT_DIRECTORY := $(abspath $(dir $(THIS_MAKEFILE)))
include $(CURRENT_DIRECTORY)/../../libraries/config/templates/mesosphere.mk
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
ifneq ($(__RECURSIVE__),1)
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export TOPDIR := $(CURDIR)
export DEPSDIR := $(CURDIR)/$(BUILD)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) $(CURDIR)/include \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
CFILES := $(call FIND_SOURCE_FILES,$(SOURCES),c)
@@ -44,41 +42,72 @@ export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I.
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/$(ATMOSPHERE_LIBRARY_DIR))
.PHONY: $(BUILD) clean all
export TOPDIR := $(CURRENT_DIRECTORY)
OUTPUT_BASE := $(TOPDIR)/$(notdir $(TOPDIR))
#---------------------------------------------------------------------------------
all: $(BUILD) check_libmeso
$(BUILD): check_libmeso
ATMOSPHERE_BUILD_CONFIGS :=
all: release
define ATMOSPHERE_ADD_TARGET
ATMOSPHERE_BUILD_CONFIGS += $(strip $1)
$(strip $1): check_libmeso_$(strip $1) $$(ATMOSPHERE_BUILD_DIR)/$(strip $1)
@$$(MAKE) __RECURSIVE__=1 OUTPUT=$$(OUTPUT_BASE)$(strip $2) $(3) \
DEPSDIR=$$(CURDIR)/$$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \
LIBMESOSPHERE_NAME=mesosphere$(strip $2) \
--no-print-directory -C $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) \
-f $$(THIS_MAKEFILE)
check_libmeso_$(strip $1):
@$$(MAKE) --no-print-directory -C ../../libraries/libmesosphere $(strip $1)
clean-$(strip $1):
@echo clean $(strip $1) ...
@rm -fr $$(ATMOSPHERE_BUILD_DIR)/$(strip $1) $$(OUTPUT_BASE)$(strip $2).bin $$(OUTPUT_BASE)$(strip $2).elf
endef
$(eval $(call ATMOSPHERE_ADD_TARGET, release, , \
ATMOSPHERE_BUILD_SETTINGS="" \
))
$(eval $(call ATMOSPHERE_ADD_TARGET, debug, _debug, \
ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_DEBUGGING" \
))
$(eval $(call ATMOSPHERE_ADD_TARGET, audit, _audit, \
ATMOSPHERE_BUILD_SETTINGS="-DMESOSPHERE_BUILD_FOR_AUDITING" \
))
$(ATMOSPHERE_BUILD_DIR)/%:
@[ -d $@ ] || mkdir -p $@
@$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
check_libmeso:
@$(MAKE) --no-print-directory -C ../../libraries/libmesosphere
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@rm -fr $(BUILD) $(OUTPUT).bin $(OUTPUT).elf
clean: $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),clean-$(config))
.PHONY: all clean $(foreach config,$(ATMOSPHERE_BUILD_CONFIGS),$(config) clean-$(config))
#---------------------------------------------------------------------------------
else
.PHONY: all
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
all : $(OUTPUT).bin
$(OUTPUT).bin : $(OUTPUT).elf
$(OBJCOPY) -S -O binary --set-section-flags .bss=alloc,load,contents $< $@
@echo built ... $(notdir $@)
$(OUTPUT).elf : $(OFILES) ../../../libraries/libmesosphere/lib/libmesosphere.a
$(OUTPUT).elf : $(OFILES)
$(OFILES) : $(ATMOSPHERE_LIBRARIES_DIR)/libmesosphere/$(ATMOSPHERE_LIBRARY_DIR)/lib$(LIBMESOSPHERE_NAME).a
%.elf:
@echo linking $(notdir $@)
@@ -101,4 +130,4 @@ kern_libc_generic.o: CFLAGS += -fno-builtin
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------
#---------------------------------------------------------------------------------------

View File

@@ -64,6 +64,10 @@ namespace ams::mitm {
/* Emummc file protection. */
FsFile g_emummc_file;
/* Maintain exclusive access to the fusee-secondary archive. */
FsFile g_secondary_file;
FsFile g_sept_payload_file;
constexpr inline bool IsHexadecimal(const char *str) {
while (*str) {
if (std::isxdigit(static_cast<unsigned char>(*str))) {
@@ -129,6 +133,15 @@ namespace ams::mitm {
R_ABORT_UNLESS(fsFileWrite(&g_bis_key_file, 0, bis_keys, sizeof(bis_keys), FsWriteOption_Flush));
/* NOTE: g_bis_key_file is intentionally not closed here. This prevents any other process from opening it. */
}
/* Open a reference to the fusee-secondary archive. */
/* As upcoming/current atmosphere releases will contain more than one zip which users much choose between, */
/* maintaining an open reference prevents cleanly the issue of "automatic" updaters selecting the incorrect */
/* zip, and encourages good updating hygiene -- atmosphere should not be updated on SD while HOS is alive. */
{
R_ABORT_UNLESS(mitm::fs::OpenSdFile(std::addressof(g_secondary_file), "/atmosphere/fusee-secondary.bin", ams::fs::OpenMode_Read));
R_ABORT_UNLESS(mitm::fs::OpenSdFile(std::addressof(g_sept_payload_file), "/sept/payload.bin", ams::fs::OpenMode_Read));
}
}
/* Initialization implementation */

View File

@@ -108,6 +108,9 @@ namespace ams::mitm::bpc {
/* Copy in payload. */
std::memcpy(g_reboot_payload, payload, payload_size);
/* Note to the secure monitor that we have a payload. */
spl::smc::SetConfig(spl::ConfigItem::ExospherePayloadAddress, g_reboot_payload, nullptr, 0);
/* NOTE: Preferred reboot type may be overrwritten when parsed from settings during boot. */
g_reboot_type = RebootType::ToPayload;
}

View File

@@ -15,37 +15,94 @@
*/
#include <stratosphere.hpp>
#include "set_mitm_service.hpp"
#include "set_shim.h"
namespace ams::mitm::settings {
using namespace ams::settings;
namespace {
constinit os::ProcessId g_application_process_id = os::InvalidProcessId;
constinit cfg::OverrideLocale g_application_locale;
constinit bool g_valid_language;
constinit bool g_valid_region;
}
SetMitmService::SetMitmService(std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &c) : sf::MitmServiceImplBase(std::forward<std::shared_ptr<::Service>>(s), c) {
if (this->client_info.program_id == ncm::SystemProgramId::Ns) {
os::ProcessId application_process_id;
if (R_SUCCEEDED(pm::dmnt::GetApplicationProcessId(std::addressof(application_process_id))) && g_application_process_id == application_process_id) {
this->locale = g_application_locale;
this->is_valid_language = g_valid_language;
this->is_valid_region = g_valid_region;
this->got_locale = true;
} else {
this->InvalidateLocale();
}
} else {
this->InvalidateLocale();
}
}
Result SetMitmService::EnsureLocale() {
/* Optimization: if locale has already been gotten, we can stop. */
if (AMS_LIKELY(this->got_locale)) {
return ResultSuccess();
}
std::scoped_lock lk(this->lock);
const bool is_ns = this->client_info.program_id == ncm::SystemProgramId::Ns;
if (!this->got_locale) {
std::memset(&this->locale, 0xCC, sizeof(this->locale));
ncm::ProgramId program_id = this->client_info.program_id;
os::ProcessId application_process_id = os::InvalidProcessId;
if (is_ns) {
/* When NS asks for a locale, refresh to get the current application locale. */
os::ProcessId application_process_id;
R_TRY(pm::dmnt::GetApplicationProcessId(&application_process_id));
R_TRY(pm::info::GetProgramId(&program_id, application_process_id));
R_TRY(pm::dmnt::GetApplicationProcessId(std::addressof(application_process_id)));
R_TRY(pm::info::GetProgramId(std::addressof(program_id), application_process_id));
}
this->locale = cfg::GetOverrideLocale(program_id);
this->is_valid_language = settings::IsValidLanguageCode(this->locale.language_code);
this->is_valid_region = settings::IsValidRegionCode(this->locale.region_code);
this->got_locale = true;
if (is_ns) {
g_application_locale = this->locale;
g_valid_language = this->is_valid_language;
g_valid_region = this->is_valid_region;
g_application_process_id = application_process_id;
}
this->locale = cfg::GetOverrideLocale(program_id);
this->got_locale = !is_ns;
}
return ResultSuccess();
}
void SetMitmService::InvalidateLocale() {
std::scoped_lock lk(this->lock);
std::memset(std::addressof(this->locale), 0xCC, sizeof(this->locale));
this->is_valid_language = false;
this->is_valid_region = false;
this->got_locale = false;
}
Result SetMitmService::GetLanguageCode(sf::Out<settings::LanguageCode> out) {
this->EnsureLocale();
/* If there's no override locale, just use the actual one. */
R_UNLESS(settings::IsValidLanguageCode(this->locale.language_code), sm::mitm::ResultShouldForwardToSession());
if (AMS_UNLIKELY(!this->is_valid_language)) {
static_assert(sizeof(u64) == sizeof(settings::LanguageCode));
R_TRY(setGetLanguageCodeFwd(this->forward_service.get(), reinterpret_cast<u64 *>(std::addressof(this->locale.language_code))));
this->is_valid_language = true;
if (this->client_info.program_id == ncm::SystemProgramId::Ns) {
g_application_locale.language_code = this->locale.language_code;
g_valid_language = true;
}
}
out.SetValue(this->locale.language_code);
return ResultSuccess();
@@ -55,7 +112,16 @@ namespace ams::mitm::settings {
this->EnsureLocale();
/* If there's no override locale, just use the actual one. */
R_UNLESS(settings::IsValidRegionCode(this->locale.region_code), sm::mitm::ResultShouldForwardToSession());
if (AMS_UNLIKELY(!this->is_valid_region)) {
static_assert(sizeof(::SetRegion) == sizeof(settings::RegionCode));
R_TRY(setGetRegionCodeFwd(this->forward_service.get(), reinterpret_cast<::SetRegion *>(std::addressof(this->locale.region_code))));
this->is_valid_region = true;
if (this->client_info.program_id == ncm::SystemProgramId::Ns) {
g_application_locale.region_code = this->locale.region_code;
g_valid_region = true;
}
}
out.SetValue(this->locale.region_code);
return ResultSuccess();

View File

@@ -33,8 +33,10 @@ namespace ams::mitm::settings {
os::Mutex lock{false};
cfg::OverrideLocale locale;
bool got_locale = false;
bool is_valid_language = false;
bool is_valid_region = false;
public:
using MitmServiceImplBase::MitmServiceImplBase;
SetMitmService(std::shared_ptr<::Service> &&s, const sm::MitmProcessInfo &c);
public:
static bool ShouldMitm(const sm::MitmProcessInfo &client_info) {
/* We will mitm:
@@ -44,6 +46,7 @@ namespace ams::mitm::settings {
return client_info.program_id == ncm::SystemProgramId::Ns || is_game;
}
private:
void InvalidateLocale();
Result EnsureLocale();
public:
Result GetLanguageCode(sf::Out<ams::settings::LanguageCode> out);

View File

@@ -0,0 +1,36 @@
/*
* 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 "set_shim.h"
static Result _setCmdNoInOut64(Service* srv, u64 *out, u32 cmd_id) {
return serviceDispatchOut(srv, cmd_id, *out);
}
static Result _setCmdNoInOutU32(Service* srv, u32 *out, u32 cmd_id) {
return serviceDispatchOut(srv, cmd_id, *out);
}
/* Forwarding shims. */
Result setGetLanguageCodeFwd(Service *s, u64* out) {
return _setCmdNoInOut64(s, out, 0);
}
Result setGetRegionCodeFwd(Service *s, SetRegion *out) {
s32 code=0;
Result rc = _setCmdNoInOutU32(s, (u32*)&code, 4);
if (R_SUCCEEDED(rc) && out) *out = code;
return rc;
}

View File

@@ -0,0 +1,20 @@
/**
* @file set_shim.h
* @brief Settings Services (fs) IPC wrapper for set.mitm.
* @author SciresM
* @copyright libnx Authors
*/
#pragma once
#include <switch.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Forwarding shims. */
Result setGetLanguageCodeFwd(Service *s, u64* out);
Result setGetRegionCodeFwd(Service *s, SetRegion *out);
#ifdef __cplusplus
}
#endif

View File

@@ -56,10 +56,18 @@ namespace ams::mitm::settings {
const auto api_info = exosphere::GetApiInfo();
const char emummc_char = emummc::IsActive() ? 'E' : 'S';
/* NOTE: While Mesosphere is in experimental/opt-in, we will display it as part of the firmware. */
const char mesosphere_char = svc::IsKernelMesosphere() ? 'M' : '0';
/* TODO: Remove separate display for mesosphere vs not mesosphere in Atmosphere 1.0.0. */
AMS_ABORT_UNLESS(api_info.GetMajorVersion() == 0);
/* NOTE: We have carefully accounted for the size of the string we print. */
/* No truncation occurs assuming two-digits for all version number components. */
char display_version[sizeof(g_ams_firmware_version.display_version)];
std::snprintf(display_version, sizeof(display_version), "%s|AMS %u.%u.%u|%c", g_ams_firmware_version.display_version, api_info.GetMajorVersion(), api_info.GetMinorVersion(), api_info.GetMicroVersion(), emummc_char);
std::snprintf(display_version, sizeof(display_version), "%s|AMS %c.%u.%u|%c", g_ams_firmware_version.display_version, mesosphere_char, api_info.GetMinorVersion(), api_info.GetMicroVersion(), emummc_char);
std::memcpy(g_ams_firmware_version.display_version, display_version, sizeof(display_version));
}

View File

@@ -351,6 +351,10 @@ namespace ams::creport {
void CrashReport::SaveToFile(ScopedFile &file) {
file.WriteFormat("Atmosphère Crash Report (v1.5):\n");
/* TODO: Remove in Atmosphere 1.0.0. */
file.WriteFormat("Mesosphere: %s\n", svc::IsKernelMesosphere() ? "Enabled" : "Disabled");
file.WriteFormat("Result: 0x%X (2%03d-%04d)\n\n", this->result.GetValue(), this->result.GetModule(), this->result.GetDescription());
/* Process Info. */

View File

@@ -214,7 +214,9 @@ namespace ams::fatal::srv {
font::AddSpacingLines(0.5f);
font::PrintFormatLine( "Program: %016lX", static_cast<u64>(this->context->program_id));
font::AddSpacingLines(0.5f);
font::PrintFormatLine("Firmware: %s (Atmosphère %u.%u.%u-%s)", config.GetFirmwareVersion().display_version, ATMOSPHERE_RELEASE_VERSION, ams::GetGitRevision());
/* TODO: Remove Mesosphere identifier in 1.0.0. */
font::PrintFormatLine("Firmware: %s (Atmosphère%s %u.%u.%u-%s)", config.GetFirmwareVersion().display_version, svc::IsKernelMesosphere() ? " M" : "", ATMOSPHERE_RELEASE_VERSION, ams::GetGitRevision());
font::AddSpacingLines(1.5f);
if (!exosphere::ResultVersionMismatch::Includes(this->context->result)) {
font::Print(config.GetErrorDescription());

View File

@@ -198,6 +198,8 @@ namespace ams::ldr {
if (status.IsHbl()) {
if (R_SUCCEEDED(fs::OpenFile(std::addressof(file), SdOrBaseMetaPath, fs::OpenMode_Read))) {
ON_SCOPE_EXIT { fs::CloseFile(file); };
if (R_SUCCEEDED(LoadMetaFromFile(file, &g_original_meta_cache))) {
Meta *o_meta = &g_original_meta_cache.meta;
@@ -212,6 +214,15 @@ namespace ams::ldr {
caps::SetProgramInfoFlags(program_info_flags, meta->aci_kac, meta->aci->kac_size);
}
}
/* When hbl is applet, adjust main thread priority. */
if ((caps::GetProgramInfoFlags(meta->aci_kac, meta->aci->kac_size) & ProgramInfoFlag_ApplicationTypeMask) == ProgramInfoFlag_Applet) {
constexpr auto HblMainThreadPriorityApplication = 44;
constexpr auto HblMainThreadPriorityApplet = 40;
if (meta->npdm->main_thread_priority == HblMainThreadPriorityApplication) {
meta->npdm->main_thread_priority = HblMainThreadPriorityApplet;
}
}
} else if (hos::GetVersion() >= hos::Version_10_0_0) {
/* If storage id is none, there is no base code filesystem, and thus it is impossible for us to validate. */
/* However, if we're an application, we are guaranteed a base code filesystem. */

View File

@@ -382,13 +382,13 @@ namespace ams::ro::impl {
}
/* Context utilities. */
Result RegisterProcess(size_t *out_context_id, Handle process_handle, os::ProcessId process_id) {
Result RegisterProcess(size_t *out_context_id, os::ManagedHandle process_handle, os::ProcessId process_id) {
/* Validate process handle. */
{
os::ProcessId handle_pid = os::InvalidProcessId;
/* Validate handle is a valid process handle. */
R_UNLESS(R_SUCCEEDED(os::TryGetProcessId(&handle_pid, process_handle)), ResultInvalidProcess());
R_UNLESS(R_SUCCEEDED(os::TryGetProcessId(&handle_pid, process_handle.Get())), ResultInvalidProcess());
/* Validate process id. */
R_UNLESS(handle_pid == process_id, ResultInvalidProcess());
@@ -397,7 +397,7 @@ namespace ams::ro::impl {
/* Check if a process context already exists. */
R_UNLESS(GetContextByProcessId(process_id) == nullptr, ResultInvalidSession());
*out_context_id = AllocateContext(process_handle, process_id);
*out_context_id = AllocateContext(process_handle.Move(), process_id);
return ResultSuccess();
}
@@ -413,13 +413,13 @@ namespace ams::ro::impl {
}
/* Service implementations. */
Result RegisterModuleInfo(size_t context_id, Handle process_h, u64 nrr_address, u64 nrr_size, NrrKind nrr_kind, bool enforce_nrr_kind) {
Result RegisterModuleInfo(size_t context_id, os::ManagedHandle process_handle, u64 nrr_address, u64 nrr_size, NrrKind nrr_kind, bool enforce_nrr_kind) {
/* Get context. */
ProcessContext *context = GetContextById(context_id);
AMS_ABORT_UNLESS(context != nullptr);
/* Get program id. */
const ncm::ProgramId program_id = context->GetProgramId(process_h);
const ncm::ProgramId program_id = context->GetProgramId(process_handle.Get());
/* Validate address/size. */
R_TRY(ValidateAddressAndNonZeroSize(nrr_address, nrr_size));

View File

@@ -30,12 +30,12 @@ namespace ams::ro::impl {
bool ShouldEaseNroRestriction();
/* Context utilities. */
Result RegisterProcess(size_t *out_context_id, Handle process_handle, os::ProcessId process_id);
Result RegisterProcess(size_t *out_context_id, os::ManagedHandle process_handle, os::ProcessId process_id);
Result ValidateProcess(size_t context_id, os::ProcessId process_id);
void UnregisterProcess(size_t context_id);
/* Service implementations. */
Result RegisterModuleInfo(size_t context_id, Handle process_h, u64 nrr_address, u64 nrr_size, NrrKind nrr_kind, bool enforce_nrr_kind);
Result RegisterModuleInfo(size_t context_id, os::ManagedHandle process_h, u64 nrr_address, u64 nrr_size, NrrKind nrr_kind, bool enforce_nrr_kind);
Result UnregisterModuleInfo(size_t context_id, u64 nrr_address);
Result MapManualLoadModuleMemory(u64 *out_address, size_t context_id, u64 nro_address, u64 nro_size, u64 bss_address, u64 bss_size);
Result UnmapManualLoadModuleMemory(size_t context_id, u64 nro_address);

View File

@@ -56,12 +56,20 @@ namespace ams::ro {
}
Result RoService::RegisterProcessHandle(const sf::ClientProcessId &client_pid, sf::CopyHandle process_h) {
return impl::RegisterProcess(std::addressof(this->context_id), process_h.GetValue(), client_pid.GetValue());
/* Ensure we manage references to the process handle correctly. */
os::ManagedHandle process_handle(process_h.GetValue());
/* Register the process. */
return impl::RegisterProcess(std::addressof(this->context_id), std::move(process_handle), client_pid.GetValue());
}
Result RoService::RegisterProcessModuleInfo(const sf::ClientProcessId &client_pid, u64 nrr_address, u64 nrr_size, sf::CopyHandle process_h) {
/* Ensure we manage references to the process handle correctly. */
os::ManagedHandle process_handle(process_h.GetValue());
/* Register the module. */
R_TRY(impl::ValidateProcess(this->context_id, client_pid.GetValue()));
return impl::RegisterModuleInfo(this->context_id, process_h.GetValue(), nrr_address, nrr_size, this->nrr_kind, this->nrr_kind == NrrKind_JitPlugin);
return impl::RegisterModuleInfo(this->context_id, std::move(process_handle), nrr_address, nrr_size, this->nrr_kind, this->nrr_kind == NrrKind_JitPlugin);
}
}

View File

@@ -350,6 +350,12 @@ namespace ams::sm::impl {
return service == ServiceName::Encode("fsp-srv");
}
bool ShouldCloseOnClientDisconnect(ServiceName service) {
/* jit sysmodule is closed and relaunched by am for each application which uses it. */
constexpr auto JitU = ServiceName::Encode("jit:u");
return service == JitU;
}
Result GetMitmServiceHandleImpl(Handle *out, ServiceInfo *service_info, const MitmProcessInfo &client_info) {
/* Send command to query if we should mitm. */
bool should_mitm;
@@ -419,6 +425,28 @@ namespace ams::sm::impl {
return ResultSuccess();
}
}
/* Client disconnection callback. */
void OnClientDisconnected(os::ProcessId process_id) {
/* Ensure that the process id is valid. */
if (process_id == os::InvalidProcessId) {
return;
}
/* NOTE: Nintendo unregisters all services a process hosted on client close. */
/* We do not do this as an atmosphere extension, in order to reduce the number */
/* of sessions open at any given time. */
/* However, certain system behavior (jit) relies on this occurring. */
/* As such, we will special case the system components which rely on the behavior. */
for (size_t i = 0; i < ServiceCountMax; i++) {
if (g_service_list[i].name != InvalidServiceName && g_service_list[i].owner_process_id == process_id) {
if (ShouldCloseOnClientDisconnect(g_service_list[i].name)) {
g_service_list[i].Free();
}
}
}
}
/* Process management. */

View File

@@ -19,6 +19,9 @@
namespace ams::sm::impl {
/* Client disconnection callback. */
void OnClientDisconnected(os::ProcessId process_id);
/* Process management. */
Result RegisterProcess(os::ProcessId process_id, ncm::ProgramId program_id, cfg::OverrideStatus, const void *acid_sac, size_t acid_sac_size, const void *aci_sac, size_t aci_sac_size);
Result UnregisterProcess(os::ProcessId process_id);

View File

@@ -19,6 +19,12 @@
namespace ams::sm {
UserService::~UserService() {
if (this->has_initialized) {
impl::OnClientDisconnected(this->process_id);
}
}
Result UserService::RegisterClient(const sf::ClientProcessId &client_process_id) {
this->process_id = client_process_id.GetValue();
this->has_initialized = true;

View File

@@ -26,6 +26,8 @@ namespace ams::sm {
bool has_initialized = false;
private:
Result EnsureInitialized();
public:
virtual ~UserService();
public:
/* Official commands. */
Result RegisterClient(const sf::ClientProcessId &client_process_id);

View File

@@ -273,11 +273,12 @@ def get_full(nxo):
s.resolved = LOAD_BASE + s.value
if s.name:
if s.type == STT_FUNC:
print(hex(s.resolved), s.name)
idaapi.add_entry(s.resolved, s.resolved, s.name, 0)
#print(hex(s.resolved), s.name)
#idaapi.add_entry(s.resolved, s.resolved, s.name, 0)
pass
else:
idaapi.force_name(s.resolved, s.name)
#idaapi.force_name(s.resolved, s.name)
pass
else:
# NULL symbol
s.resolved = 0
@@ -353,12 +354,18 @@ def find_categories(full, num_fields):
return list(up('<'+'I'*num_fields, full[ind:ind+4*num_fields]))
def find_types(full, num_fields):
KNOWN = range(10) + [4, 4, 2, 4]
ind = full.index(''.join(pk('<I', i) for i in KNOWN))
KNOWN = range(10) + [4, 4, 2, 4]
KNOWN_OLD = range(10) + [4, 4, 0, 4]
try:
ind = full.index(''.join(pk('<I', i) for i in KNOWN))
except ValueError:
ind = full.index(''.join(pk('<I', i) for i in KNOWN_OLD))
return list(up('<'+'I'*num_fields, full[ind:ind+4*num_fields]))
def find_flags(full, num_fields):
KNOWN = '\x00' + ('\x01'*6) + '\x00\x01\x01\x00'
if num_fields < 443 + len(KNOWN):
return [0] * num_fields
ind = full.index(KNOWN) - 443
return list(up('<'+'B'*num_fields, full[ind:ind+num_fields]))
@@ -372,10 +379,10 @@ def flg_to_string(f):
return FIELD_FLAGS[f] if f in FIELD_FLAGS else 'FieldFlag_Unknown%d' % f
def main(argc, argv):
if argc != 2:
print 'Usage: %s erpt_nso' % argv[0]
if argc != 2 and not (argc == 3 and argv[1] == '-f'):
print 'Usage: %s [-f] erpt_nso' % argv[0]
return 1
f = open(argv[1], 'rb')
f = open(argv[-1], 'rb')
nxo = nxo64.load_nxo(f)
full = get_full(nxo)
field_table = locate_fields(full)
@@ -389,11 +396,13 @@ def main(argc, argv):
mc = max(len(cat_to_string(c)) for c in cats)
mt = max(len(typ_to_string(t)) for t in types)
ml = max(len(flg_to_string(f)) for f in flags)
if argc == 3:
mf, mc, mt, ml = (64, 48, 32, 32)
format_string = '- %%-%ds %%-%ds %%-%ds %%-%ds' % (mf+1, mc+1, mt+1, ml)
for i in xrange(NUM_FIELDS):
f, c, t, l = fields[i], cat_to_string(cats[i]), typ_to_string(types[i]), flg_to_string(flags[i])
print format_string % (f+',', c+',', t+',', l)
with open(argv[1]+'.hpp', 'w') as out:
with open(argv[-1]+'.hpp', 'w') as out:
out.write(HEADER)
out.write('#define AMS_ERPT_FOREACH_FIELD_TYPE(HANDLER) \\\n')
for tp in sorted(list(set(types + FIELD_TYPES.keys()))):