mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-09 22:56:35 +00:00
Implement much of the core Stage2 loader logic for Fusee
This commit is contained in:
parent
c9909b34db
commit
82552b5a89
4 changed files with 160 additions and 5 deletions
|
@ -12,7 +12,7 @@
|
||||||
#define BCT0_LOAD_END_ADDRESS (uintptr_t)(0x4003F000)
|
#define BCT0_LOAD_END_ADDRESS (uintptr_t)(0x4003F000)
|
||||||
#define MAGIC_BCT0 0x30544342
|
#define MAGIC_BCT0 0x30544342
|
||||||
|
|
||||||
#define DEFAULT_BCT0_FOR_DEBUG "BCT0\n[stage1]\nstage2_file = stage2.bin\nstage2_addr = 0xFFF00000\nstage2_entrypoint = 0xCAFEBABE\n"
|
#define DEFAULT_BCT0_FOR_DEBUG "BCT0\n[stage1]\nstage2_path = stage2.bin\nstage2_addr = 0xFFF00000\nstage2_entrypoint = 0xCAFEBABE\n"
|
||||||
|
|
||||||
const char *load_config(void) {
|
const char *load_config(void) {
|
||||||
if (!read_sd_file((void *)BCT0_LOAD_ADDRESS, BCT0_LOAD_END_ADDRESS - BCT0_LOAD_ADDRESS, "BCT.ini")) {
|
if (!read_sd_file((void *)BCT0_LOAD_ADDRESS, BCT0_LOAD_END_ADDRESS - BCT0_LOAD_ADDRESS, "BCT.ini")) {
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#define STAGE2_ARGC 3
|
#define STAGE2_ARGC 3
|
||||||
|
|
||||||
|
|
||||||
#define STAGE2_NAME_KEY "stage2_file"
|
#define STAGE2_NAME_KEY "stage2_path"
|
||||||
#define STAGE2_ADDRESS_KEY "stage2_addr"
|
#define STAGE2_ADDRESS_KEY "stage2_addr"
|
||||||
#define STAGE2_ENTRYPOINT_KEY "stage2_entrypoint"
|
#define STAGE2_ENTRYPOINT_KEY "stage2_entrypoint"
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,147 @@
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include <stdint.h>
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
|
#include "sd_utils.h"
|
||||||
|
#include "stage2.h"
|
||||||
|
#include "lib/printk.h"
|
||||||
|
#include "lib/vsprintf.h"
|
||||||
|
#include "lib/ini.h"
|
||||||
|
|
||||||
|
const char *g_bct0 = NULL;
|
||||||
|
|
||||||
|
static int loadlist_entry_ini_handler(void *user, const char *section, const char *name, const char *value) {
|
||||||
|
load_file_t *load_file_ctx = (load_file_t *)user;
|
||||||
|
uintptr_t x = 0;
|
||||||
|
const char *ext = NULL;
|
||||||
|
|
||||||
|
if (strcmp(section, "stage2") == 0) {
|
||||||
|
if (strstr(name, load_file_ctx->key) == name) {
|
||||||
|
ext = name + strlen(load_file_ctx->key);
|
||||||
|
if (strcmp(ext, "_path") == 0) {
|
||||||
|
/* Copy in the path. */
|
||||||
|
strncpy(load_file_ctx->path, value, sizeof(load_file_ctx->path));
|
||||||
|
} else if (strcmp(ext, "_addr") == 0) {
|
||||||
|
/* Read in load address as a hex string. */
|
||||||
|
sscanf(value, "%x", &x);
|
||||||
|
load_file_ctx->load_address = x;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool validate_load_address(uintptr_t load_addr) {
|
||||||
|
/* TODO: Actually validate addresses. */
|
||||||
|
(void)(load_addr);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void load_list_entry(const char *key) {
|
||||||
|
load_file_t load_file_ctx = {0};
|
||||||
|
load_file_ctx.key = key;
|
||||||
|
|
||||||
|
printk("Loading %s\n", key);
|
||||||
|
|
||||||
|
if (ini_parse_string(g_bct0, loadlist_entry_ini_handler, &load_file_ctx) < 0) {
|
||||||
|
printk("Error: Failed to parse BCT.ini!\n");
|
||||||
|
generic_panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (load_file_ctx.load_address == 0 || load_file_ctx.path[0] == '\x00') {
|
||||||
|
printk("Error: Failed to determine where to load %s!\n", key);
|
||||||
|
generic_panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
printk("Loading %s from %s to 0x%08x\n", key, load_file_ctx.path, load_file_ctx.load_address);
|
||||||
|
|
||||||
|
if (!validate_load_address(load_file_ctx.load_address)) {
|
||||||
|
printk("Error: Load address 0x%08x is invalid!\n");
|
||||||
|
generic_panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!read_sd_file((void *)load_file_ctx.load_address, LOADER_FILESIZE_MAX, load_file_ctx.path)) {
|
||||||
|
printk("Error: Failed to read %s!\n", load_file_ctx.path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void parse_loadlist(const char *ll) {
|
||||||
|
printk("Parsing load list: %s\n", ll);
|
||||||
|
|
||||||
|
char load_list[0x200] = {0};
|
||||||
|
strncpy(load_list, ll, 0x200);
|
||||||
|
|
||||||
|
char *entry, *p;
|
||||||
|
|
||||||
|
/* entry will point to the start of the current entry. p will point to the current location in the list. */
|
||||||
|
entry = load_list;
|
||||||
|
p = load_list;
|
||||||
|
|
||||||
|
while (*p) {
|
||||||
|
if (*p == ' ' || *p == '\t') {
|
||||||
|
/* We're at the end of an entry. */
|
||||||
|
*p = '\x00';
|
||||||
|
|
||||||
|
/* Load the entry. */
|
||||||
|
load_list_entry(entry);
|
||||||
|
/* Skip to the next delimiter. */
|
||||||
|
for (; *p == ' ' || *p == '\t'; p++) { }
|
||||||
|
if (*p == '\x00') {
|
||||||
|
break;
|
||||||
|
} else if (*p != '|') {
|
||||||
|
printk("Error: Load list is malformed!\n");
|
||||||
|
generic_panic();
|
||||||
|
} else {
|
||||||
|
/* Skip to the next entry. */
|
||||||
|
for (; *p == ' ' || *p == '\t'; p++) { }
|
||||||
|
entry = p;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int loadlist_ini_handler(void *user, const char *section, const char *name, const char *value) {
|
||||||
|
loader_ctx_t *loader_ctx = (loader_ctx_t *)user;
|
||||||
|
uintptr_t x = 0;
|
||||||
|
|
||||||
|
if (strcmp(section, "stage2") == 0) {
|
||||||
|
if (strcmp(name, LOADER_LOADLIST_KEY) == 0) {
|
||||||
|
parse_loadlist(value);
|
||||||
|
} else if (strcmp(name, LOADER_ENTRYPOINT_KEY) == 0) {
|
||||||
|
/* Read in entrypoint as a hex string. */
|
||||||
|
sscanf(value, "%x", &x);
|
||||||
|
loader_ctx->entrypoint = (entrypoint_t)x;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
entrypoint_t load_payload(const char *bct0) {
|
entrypoint_t load_payload(const char *bct0) {
|
||||||
/* TODO */
|
loader_ctx_t loader_ctx = {0};
|
||||||
(void)(bct0);
|
|
||||||
return (entrypoint_t)NULL;
|
/* Set BCT0 global. */
|
||||||
|
g_bct0 = bct0;
|
||||||
|
|
||||||
|
if (ini_parse_string(g_bct0, loadlist_ini_handler, &loader_ctx) < 0) {
|
||||||
|
printk("Error: Failed to parse BCT.ini!\n");
|
||||||
|
generic_panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loader_ctx.entrypoint == NULL) {
|
||||||
|
printk("Error: Failed to locate stage3 entrypoint!\n");
|
||||||
|
generic_panic();
|
||||||
|
}
|
||||||
|
|
||||||
|
return loader_ctx.entrypoint;
|
||||||
}
|
}
|
|
@ -3,6 +3,22 @@
|
||||||
|
|
||||||
typedef void (*entrypoint_t)(int argc, void **argv);
|
typedef void (*entrypoint_t)(int argc, void **argv);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char path[0x300];
|
||||||
|
const char *key;
|
||||||
|
uintptr_t load_address;
|
||||||
|
} load_file_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
entrypoint_t entrypoint;
|
||||||
|
} loader_ctx_t;
|
||||||
|
|
||||||
|
#define LOADER_ENTRYPOINT_KEY "entrypoint"
|
||||||
|
#define LOADER_LOADLIST_KEY "loadlist"
|
||||||
|
|
||||||
|
/* TODO: Should we allow files bigger than 16 MB? */
|
||||||
|
#define LOADER_FILESIZE_MAX 0x01000000
|
||||||
|
|
||||||
entrypoint_t load_payload(const char *bct0);
|
entrypoint_t load_payload(const char *bct0);
|
||||||
|
|
||||||
#endif
|
#endif
|
Loading…
Reference in a new issue