Compare commits
34 Commits
mesosphere
...
meso_build
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4d4523041f | ||
|
|
e26e1df07f | ||
|
|
f92de24164 | ||
|
|
a8a90e6324 | ||
|
|
1c71d12d9d | ||
|
|
37738699f2 | ||
|
|
e973ef7533 | ||
|
|
2ee2a4f1ac | ||
|
|
2a2bffeb35 | ||
|
|
d04046ecaf | ||
|
|
f24171dc41 | ||
|
|
5b02c77400 | ||
|
|
2e7214b6fa | ||
|
|
d52179c708 | ||
|
|
388f9e6455 | ||
|
|
c547c7f0e7 | ||
|
|
4138abbefa | ||
|
|
1275eb0bf3 | ||
|
|
5ac9e45d86 | ||
|
|
feba788bc6 | ||
|
|
f4d10a4481 | ||
|
|
ff310a0647 | ||
|
|
85505db9b7 | ||
|
|
48b4dd48a4 | ||
|
|
8d46d901d9 | ||
|
|
1930880270 | ||
|
|
fa0df994ba | ||
|
|
909a1767a6 | ||
|
|
dbe59fd041 | ||
|
|
9b65daf439 | ||
|
|
4acdc899f5 | ||
|
|
76957e502d | ||
|
|
909397233c | ||
|
|
211a828730 |
10
Makefile
10
Makefile
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
namespace ams::secmon {
|
||||
|
||||
bool IsPhysicalMemoryAddress(uintptr_t address);
|
||||
size_t GetPhysicalMemorySize();
|
||||
|
||||
void UnmapTzram();
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ namespace ams::secmon::smc {
|
||||
ExosphereBlankProdInfo = 65005,
|
||||
ExosphereAllowCalWrites = 65006,
|
||||
ExosphereEmummcType = 65007,
|
||||
ExospherePayloadAddress = 65008,
|
||||
};
|
||||
|
||||
SmcResult SmcGetConfigUser(SmcArguments &args);
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 $@)
|
||||
|
||||
37
fusee/fusee-secondary/fusee_make_standard.py
Normal file
37
fusee/fusee-secondary/fusee_make_standard.py
Normal 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))
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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__
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
88
libraries/libmesosphere/source/arch/arm64/kern_panic_asm.s
Normal file
88
libraries/libmesosphere/source/arch/arm64/kern_panic_asm.s
Normal 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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -27,3 +27,5 @@
|
||||
#include <vapours/results.hpp>
|
||||
#include <vapours/crypto.hpp>
|
||||
#include <vapours/svc.hpp>
|
||||
|
||||
#include <vapours/ams/ams_fatal_error_context.hpp>
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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))); }
|
||||
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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:])
|
||||
|
||||
@@ -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
|
||||
#---------------------------------------------------------------------------------------
|
||||
#---------------------------------------------------------------------------------------
|
||||
@@ -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
|
||||
#---------------------------------------------------------------------------------------
|
||||
#---------------------------------------------------------------------------------------
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
36
stratosphere/ams_mitm/source/set_mitm/set_shim.c
Normal file
36
stratosphere/ams_mitm/source/set_mitm/set_shim.c
Normal 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;
|
||||
}
|
||||
20
stratosphere/ams_mitm/source/set_mitm/set_shim.h
Normal file
20
stratosphere/ams_mitm/source/set_mitm/set_shim.h
Normal 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
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()))):
|
||||
|
||||
Reference in New Issue
Block a user