mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-12-22 12:21:18 +00:00
fusee: implement mariko warmboot firmware cache
This commit is contained in:
parent
b74742e0a1
commit
6e9675916c
3 changed files with 127 additions and 21 deletions
|
@ -14,6 +14,7 @@
|
|||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
@ -344,3 +345,43 @@ uint32_t fuse_get_regulator(void) {
|
|||
return 0; /* Regulator_Erista_Max77621 */
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static const uint32_t fuse_version_increment_firmwares[] = {
|
||||
ATMOSPHERE_TARGET_FIRMWARE_11_0_0,
|
||||
ATMOSPHERE_TARGET_FIRMWARE_10_0_0,
|
||||
ATMOSPHERE_TARGET_FIRMWARE_9_1_0,
|
||||
ATMOSPHERE_TARGET_FIRMWARE_9_0_0,
|
||||
ATMOSPHERE_TARGET_FIRMWARE_8_1_0,
|
||||
ATMOSPHERE_TARGET_FIRMWARE_7_0_0,
|
||||
ATMOSPHERE_TARGET_FIRMWARE_6_2_0,
|
||||
ATMOSPHERE_TARGET_FIRMWARE_6_0_0,
|
||||
ATMOSPHERE_TARGET_FIRMWARE_5_0_0,
|
||||
ATMOSPHERE_TARGET_FIRMWARE_4_0_0,
|
||||
ATMOSPHERE_TARGET_FIRMWARE_3_0_2,
|
||||
ATMOSPHERE_TARGET_FIRMWARE_3_0_0,
|
||||
ATMOSPHERE_TARGET_FIRMWARE_2_0_0,
|
||||
ATMOSPHERE_TARGET_FIRMWARE_1_0_0,
|
||||
};
|
||||
|
||||
static const uint32_t num_fuse_increments = sizeof(fuse_version_increment_firmwares) / sizeof(fuse_version_increment_firmwares[0]);
|
||||
|
||||
uint32_t fuse_get_expected_fuse_count(uint32_t target_firmware) {
|
||||
for (uint32_t i = 0; i < num_fuse_increments; ++i) {
|
||||
if (target_firmware >= fuse_version_increment_firmwares[i]) {
|
||||
return num_fuse_increments - i;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
uint32_t fuse_get_burnt_fuse_count(void) {
|
||||
const uint32_t val = fuse_get_reserved_odm(7);
|
||||
uint32_t count = 0;
|
||||
for (uint32_t i = 0; i < sizeof(uint32_t) * CHAR_BIT; ++i) {
|
||||
if (((val >> i) & 1) != 0) {
|
||||
++count;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
|
|
@ -477,6 +477,9 @@ uint32_t fuse_get_device_unique_key_generation(void);
|
|||
uint32_t fuse_get_soc_type(void);
|
||||
uint32_t fuse_get_regulator(void);
|
||||
|
||||
uint32_t fuse_get_expected_fuse_count(uint32_t target_firmware);
|
||||
uint32_t fuse_get_burnt_fuse_count(void);
|
||||
|
||||
uint32_t fuse_hw_read(uint32_t addr);
|
||||
void fuse_hw_write(uint32_t value, uint32_t addr);
|
||||
void fuse_hw_sense(void);
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <malloc.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
#include "utils.h"
|
||||
#include "fs_utils.h"
|
||||
#include "nxboot.h"
|
||||
|
@ -675,6 +677,10 @@ static bool get_and_clear_has_run_sept(void) {
|
|||
return has_run_sept;
|
||||
}
|
||||
|
||||
static void get_mariko_warmboot_path(char *dst, size_t dst_size, uint32_t version) {
|
||||
snprintf(dst, dst_size, "warmboot_mariko/wb_%02" PRIx32 ".bin", version);
|
||||
}
|
||||
|
||||
/* This is the main function responsible for booting Horizon. */
|
||||
static nx_keyblob_t __attribute__((aligned(16))) g_keyblobs[32];
|
||||
uint32_t nxboot_main(void) {
|
||||
|
@ -948,26 +954,73 @@ uint32_t nxboot_main(void) {
|
|||
}
|
||||
|
||||
/* Read the warmboot firmware from a file, otherwise from Atmosphere's implementation (Erista only) or from cache (Mariko only). */
|
||||
if (loader_ctx->warmboot_path[0] != '\0') {
|
||||
warmboot_fw_size = get_file_size(loader_ctx->warmboot_path);
|
||||
if (warmboot_fw_size == 0) {
|
||||
fatal_error("[NXBOOT] Could not read the warmboot firmware from %s!\n", loader_ctx->warmboot_path);
|
||||
uint32_t warmboot_fuses = 0;
|
||||
if (is_mariko) {
|
||||
/* Get warmboot firmware from package1. */
|
||||
const package1_header_t *pk11_header = (const package1_header_t *)((uintptr_t)package1loader + (target_firmware >= ATMOSPHERE_TARGET_FIRMWARE_6_2_0 ? 0x7000 : 0x4000));
|
||||
|
||||
warmboot_fw = package1_get_warmboot_fw(pk11_header);
|
||||
warmboot_fw_size = *(const uint32_t *)warmboot_fw;
|
||||
|
||||
if (!(0x800 <= warmboot_fw_size && warmboot_fw_size < 0x1000)) {
|
||||
fatal_error("[NXBOOT] Warmboot firmware seems invalid!\n");
|
||||
}
|
||||
|
||||
/* Allocate memory for the warmboot firmware. */
|
||||
warmboot_fw = malloc(warmboot_fw_size);
|
||||
const uint32_t expected_fuses = fuse_get_expected_fuse_count(target_firmware);
|
||||
const uint32_t burnt_fuses = fuse_get_burnt_fuse_count();
|
||||
|
||||
if (warmboot_fw == NULL) {
|
||||
fatal_error("[NXBOOT] Out of memory!\n");
|
||||
warmboot_fuses = expected_fuses;
|
||||
|
||||
char warmboot_fn[0x80];
|
||||
get_mariko_warmboot_path(warmboot_fn, sizeof(warmboot_fn), expected_fuses);
|
||||
|
||||
if (!is_valid_file(warmboot_fn)) {
|
||||
dump_to_file(warmboot_fw, warmboot_fw_size, warmboot_fn);
|
||||
}
|
||||
if (read_from_file(warmboot_fw, warmboot_fw_size, loader_ctx->warmboot_path) != warmboot_fw_size) {
|
||||
fatal_error("[NXBOOT] Could not read the warmboot firmware from %s!\n", loader_ctx->warmboot_path);
|
||||
}
|
||||
} else {
|
||||
if (is_mariko) {
|
||||
/* TODO */
|
||||
|
||||
if (burnt_fuses > expected_fuses) {
|
||||
warmboot_fw = NULL;
|
||||
warmboot_fw_size = 0;
|
||||
for (uint32_t attempt = burnt_fuses; attempt <= 32; ++attempt) {
|
||||
get_mariko_warmboot_path(warmboot_fn, sizeof(warmboot_fn), attempt);
|
||||
if (is_valid_file(warmboot_fn)) {
|
||||
warmboot_fw_size = get_file_size(warmboot_fn);
|
||||
|
||||
/* Allocate memory for the warmboot firmware. */
|
||||
warmboot_fw = malloc(warmboot_fw_size);
|
||||
|
||||
if (warmboot_fw == NULL) {
|
||||
fatal_error("[NXBOOT] Out of memory!\n");
|
||||
}
|
||||
if (read_from_file(warmboot_fw, warmboot_fw_size, warmboot_fn) != warmboot_fw_size) {
|
||||
fatal_error("[NXBOOT] Could not read the warmboot firmware from %s!\n", warmboot_fn);
|
||||
}
|
||||
|
||||
warmboot_fuses = attempt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (warmboot_fw == NULL) {
|
||||
fatal_error("[NXBOOT] Failed to determine mariko warmboot firmware\n");
|
||||
}
|
||||
} else {
|
||||
if (loader_ctx->warmboot_path[0] != '\0') {
|
||||
warmboot_fw_size = get_file_size(loader_ctx->warmboot_path);
|
||||
if (warmboot_fw_size == 0) {
|
||||
fatal_error("[NXBOOT] Could not read the warmboot firmware from %s!\n", loader_ctx->warmboot_path);
|
||||
}
|
||||
|
||||
/* Allocate memory for the warmboot firmware. */
|
||||
warmboot_fw = malloc(warmboot_fw_size);
|
||||
|
||||
if (warmboot_fw == NULL) {
|
||||
fatal_error("[NXBOOT] Out of memory!\n");
|
||||
}
|
||||
if (read_from_file(warmboot_fw, warmboot_fw_size, loader_ctx->warmboot_path) != warmboot_fw_size) {
|
||||
fatal_error("[NXBOOT] Could not read the warmboot firmware from %s!\n", loader_ctx->warmboot_path);
|
||||
}
|
||||
} else {
|
||||
/* Use Atmosphere's warmboot firmware implementation. */
|
||||
warmboot_fw_size = warmboot_bin_size;
|
||||
|
@ -1013,16 +1066,25 @@ uint32_t nxboot_main(void) {
|
|||
|
||||
/* Handle warmboot security check. */
|
||||
if (is_mariko) {
|
||||
/* TODO */
|
||||
switch (warmboot_fuses) {
|
||||
case 7:
|
||||
pmc->secure_scratch32 = 0x87;
|
||||
break;
|
||||
case 8:
|
||||
pmc->secure_scratch32 = 0xA8;
|
||||
break;
|
||||
default:
|
||||
pmc->secure_scratch32 = (0x108 + 0x21 * (warmboot_fuses - 8));
|
||||
break;
|
||||
}
|
||||
|
||||
pmc->sec_disable3 |= BIT(16);
|
||||
} else {
|
||||
/* Set 3.0.0/3.0.1/3.0.2 warmboot security check. */
|
||||
if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_3_0_0) {
|
||||
const package1loader_header_t *package1loader_header = (const package1loader_header_t *)package1loader;
|
||||
if (!strcmp(package1loader_header->build_timestamp, "20170519101410")) {
|
||||
pmc->secure_scratch32 = 0xE3; /* Warmboot 3.0.0 security check.*/
|
||||
} else if (!strcmp(package1loader_header->build_timestamp, "20170710161758")) {
|
||||
pmc->secure_scratch32 = 0x104; /* Warmboot 3.0.1/3.0.2 security check. */
|
||||
}
|
||||
pmc->secure_scratch32 = 0xE3; /* Warmboot 3.0.0 security check.*/
|
||||
} else if (target_firmware == ATMOSPHERE_TARGET_FIRMWARE_3_0_1 || target_firmware == ATMOSPHERE_TARGET_FIRMWARE_3_0_2) {
|
||||
pmc->secure_scratch32 = 0x104; /* Warmboot 3.0.1/3.0.2 security check. */
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue