Compare commits
26 Commits
0.14.4
...
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 |
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,31 @@
|
||||
# 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.
|
||||
|
||||
@@ -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) {
|
||||
@@ -53,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 &&
|
||||
@@ -86,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. */
|
||||
@@ -101,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 = f6dac1e67793233cc916f317cf517244dd348a5e
|
||||
parent = 909a1767a6080bab7ea6032c00e1ff4cec993af0
|
||||
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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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. */
|
||||
@@ -534,10 +543,14 @@ namespace ams::kern::board::nintendo::nx {
|
||||
|
||||
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>(KMemoryLayout::GetDeviceVirtualAddress(KMemoryRegionType_LegacyLpsIram) + 0x3E000);
|
||||
auto *f_ctx = GetPointer<::ams::impl::FatalErrorContext>(iram_address + RebootPayloadSize);
|
||||
|
||||
/* Clear the fatal context. */
|
||||
std::memset(f_ctx, 0xCC, sizeof(*f_ctx));
|
||||
@@ -553,6 +566,10 @@ namespace ams::kern::board::nintendo::nx {
|
||||
/* 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];
|
||||
@@ -581,8 +598,27 @@ namespace ams::kern::board::nintendo::nx {
|
||||
}
|
||||
}
|
||||
|
||||
/* Trigger a reboot to rcm. */
|
||||
smc::init::SetConfig(smc::ConfigItem::ExosphereNeedsReboot, smc::UserRebootType_ToRcm);
|
||||
/* 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) {
|
||||
|
||||
@@ -37,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) {
|
||||
@@ -140,35 +143,6 @@ namespace ams::kern::board::nintendo::nx::smc {
|
||||
args.x[7] = x7;
|
||||
}
|
||||
|
||||
void CallUserSecureMonitorFunctionForInit(SecureMonitorArguments &args) {
|
||||
/* Load arguments into registers. */
|
||||
register u64 x0 asm("x0") = args.x[0];
|
||||
register u64 x1 asm("x1") = args.x[1];
|
||||
register u64 x2 asm("x2") = args.x[2];
|
||||
register u64 x3 asm("x3") = args.x[3];
|
||||
register u64 x4 asm("x4") = args.x[4];
|
||||
register u64 x5 asm("x5") = args.x[5];
|
||||
register u64 x6 asm("x6") = args.x[6];
|
||||
register u64 x7 asm("x7") = args.x[7];
|
||||
|
||||
/* Actually make the call. */
|
||||
__asm__ __volatile__("smc #0"
|
||||
: "+r"(x0), "+r"(x1), "+r"(x2), "+r"(x3), "+r"(x4), "+r"(x5), "+r"(x6), "+r"(x7)
|
||||
:
|
||||
: "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17", "x18", "cc", "memory"
|
||||
);
|
||||
|
||||
/* Store arguments to output. */
|
||||
args.x[0] = x0;
|
||||
args.x[1] = x1;
|
||||
args.x[2] = x2;
|
||||
args.x[3] = x3;
|
||||
args.x[4] = x4;
|
||||
args.x[5] = x5;
|
||||
args.x[6] = x6;
|
||||
args.x[7] = x7;
|
||||
}
|
||||
|
||||
/* Global lock for generate random bytes. */
|
||||
KSpinLock g_generate_random_lock;
|
||||
|
||||
@@ -210,21 +184,30 @@ namespace ams::kern::board::nintendo::nx::smc {
|
||||
return static_cast<SmcResult>(args.x[0]) == SmcResult::Success;
|
||||
}
|
||||
|
||||
bool SetConfig(ConfigItem config_item, u64 value) {
|
||||
SecureMonitorArguments args = { UserFunctionId_SetConfig, static_cast<u32>(config_item), 0, value };
|
||||
CallUserSecureMonitorFunctionForInit(args);
|
||||
return static_cast<SmcResult>(args.x[0]) == SmcResult::Success;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -89,12 +93,14 @@ namespace ams::kern::board::nintendo::nx::smc {
|
||||
UserRebootType_ToPayload = 2,
|
||||
};
|
||||
|
||||
/* TODO: Rest of Secure Monitor API. */
|
||||
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);
|
||||
@@ -108,8 +114,6 @@ namespace ams::kern::board::nintendo::nx::smc {
|
||||
void GenerateRandomBytes(void *dst, size_t size);
|
||||
bool ReadWriteRegister(u32 *out, u64 address, u32 mask, u32 value);
|
||||
|
||||
bool SetConfig(ConfigItem config_item, u64 value);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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];
|
||||
}
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
#pragma once
|
||||
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MINOR 14
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 4
|
||||
#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
|
||||
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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