Skip to content
Snippets Groups Projects
Commit fe9c4218 authored by rahix's avatar rahix
Browse files

Merge 'card10.cfg'

See merge request !215
parents 956c9c91 f1d63669
No related branches found
No related tags found
No related merge requests found
#include "modules/modules.h"
#include "modules/log.h"
#include "modules/filesystem.h"
#include "modules/config.h"
#include "card10-version.h"
#include "FreeRTOS.h"
......@@ -20,6 +21,8 @@ int main(void)
LOG_DEBUG("startup", "Initializing hardware ...");
hardware_early_init();
load_config();
/*
* Version Splash
*/
......
......@@ -70,7 +70,7 @@ subdir('ble/')
subdir('l0der/')
epicardium_cargs = []
epicardium_cargs = ['-D_POSIX_C_SOURCE=200809']
if get_option('jailbreak_card10')
epicardium_cargs += [
'-DJAILBREAK_CARD10=1',
......
#include "modules/log.h"
#include "modules/config.h"
#include "modules/filesystem.h"
#include <assert.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#define CONFIG_MAX_LINE_LENGTH 80
enum OptionType {
OptionType_Boolean,
OptionType_Int,
OptionType_Float,
OptionType_String,
};
struct config_option {
const char *name;
enum OptionType type;
union {
bool boolean;
long integer;
double floating_point;
char *string;
} value;
};
static struct config_option s_options[_EpicOptionCount] = {
/* clang-format off */
#define INIT_Boolean(v) { .boolean = (v) }
#define INIT_Int(v) { .integer = (v) }
#define INIT_Float(v) { .floating_point = (v) }
#define INIT_String(v) { .string = (v) }
#define INIT_(tp, v) INIT_ ## tp (v)
#define INIT(tp, v) INIT_ (tp, v)
#define CARD10_SETTING(identifier, spelling, tp, default_value) \
[Option ## identifier] = { .name = (spelling), \
.type = OptionType_ ## tp, \
.value = INIT(tp, (default_value)) },
#include "modules/config.def"
/* clang-format on */
};
static struct config_option *findOption(const char *key)
{
for (int i = 0; i < _EpicOptionCount; ++i) {
if (!strcmp(key, s_options[i].name)) {
return &s_options[i];
}
}
return NULL;
}
static bool set_bool(struct config_option *opt, const char *value)
{
bool val;
if (!strcmp(value, "1")) {
val = true;
} else if (!strcmp(value, "true")) {
val = true;
} else if (!strcmp(value, "0")) {
val = false;
} else if (!strcmp(value, "false")) {
val = false;
} else {
return false;
}
opt->value.boolean = val;
LOG_DEBUG(
"card10.cfg",
"setting '%s' to %s",
opt->name,
val ? "true" : "false"
);
return true;
}
static bool set_int(struct config_option *opt, const char *value)
{
char *endptr;
size_t len = strlen(value);
int v = strtol(value, &endptr, 0);
if (endptr != (value + len)) {
return false;
}
opt->value.integer = v;
LOG_DEBUG("card10.cfg", "setting '%s' to %d (0x%08x)", opt->name, v, v);
return true;
}
static bool set_float(struct config_option *opt, const char *value)
{
char *endptr;
size_t len = strlen(value);
double v = strtod(value, &endptr);
if (endptr != (value + len)) {
return false;
}
opt->value.floating_point = v;
LOG_DEBUG("card10.cfg", "setting '%s' to %f", opt->name, v);
return true;
}
const char *elide(const char *str)
{
static char ret[21];
size_t len = strlen(str);
if (len <= 20) {
return str;
}
strncpy(ret, str, 17);
ret[17] = '.';
ret[18] = '.';
ret[19] = '.';
ret[20] = '\0';
return ret;
}
static bool set_string(struct config_option *opt, const char *value)
{
//this leaks, but the lifetime of these ends when epicardium exits, so...
char *leaks = strdup(value);
opt->value.string = leaks;
LOG_DEBUG("card10.cfg", "setting '%s' to %s", opt->name, elide(leaks));
return true;
}
static void configure(const char *key, const char *value, int lineNumber)
{
struct config_option *opt = findOption(key);
if (!opt) {
//invalid key
LOG_WARN(
"card10.cfg",
"line %d: ignoring unknown option '%s'",
lineNumber,
key
);
return;
}
bool ok = false;
switch (opt->type) {
case OptionType_Boolean:
ok = set_bool(opt, value);
break;
case OptionType_Int:
ok = set_int(opt, value);
break;
case OptionType_Float:
ok = set_float(opt, value);
break;
case OptionType_String:
ok = set_string(opt, value);
break;
default:
assert(0 && "unreachable");
}
if (!ok) {
LOG_WARN(
"card10.cfg",
"line %d: ignoring invalid value '%s' for option '%s'",
lineNumber,
value,
key
);
}
}
static void doline(char *line, char *eol, int lineNumber)
{
//skip leading whitespace
while (*line && isspace(*line))
++line;
char *key = line;
if (*key == '#') {
//skip comments
return;
}
char *eq = strchr(line, '=');
if (!eq) {
if (*key) {
LOG_WARN(
"card10.cfg",
"line %d (%s): syntax error",
lineNumber,
elide(line)
);
}
return;
}
char *e_key = eq - 1;
//skip trailing whitespace in key
while (e_key > key && isspace(*e_key))
--e_key;
e_key[1] = '\0';
if (*key == '\0') {
LOG_WARN("card10.cfg", "line %d: empty key", lineNumber);
return;
}
char *value = eq + 1;
//skip leading whitespace
while (*value && isspace(*value))
++value;
char *e_val = eol - 1;
//skip trailing whitespace
while (e_val > value && isspace(*e_val))
--e_val;
if (*value == '\0') {
LOG_WARN(
"card10.cfg",
"line %d: empty value for option '%s'",
lineNumber,
key
);
return;
}
configure(key, value, lineNumber);
}
bool config_get_boolean(enum EpicConfigOption option)
{
struct config_option *opt = &s_options[option];
assert(opt->type == OptionType_Boolean);
return opt->value.boolean;
}
long config_get_integer(enum EpicConfigOption option)
{
struct config_option *opt = &s_options[option];
assert(opt->type == OptionType_Int);
return opt->value.integer;
}
double config_get_float(enum EpicConfigOption option)
{
struct config_option *opt = &s_options[option];
assert(opt->type == OptionType_Float);
return opt->value.floating_point;
}
const char *config_get_string(enum EpicConfigOption option)
{
struct config_option *opt = &s_options[option];
assert(opt->type == OptionType_String);
return opt->value.string;
}
void load_config(void)
{
LOG_DEBUG("card10.cfg", "loading...");
int fd = epic_file_open("card10.cfg", "r");
if (fd < 0) {
LOG_DEBUG(
"card10.cfg",
"loading failed: %s (%d)",
strerror(-fd),
fd
);
return;
}
char buf[CONFIG_MAX_LINE_LENGTH];
int lineNumber = 0;
int nread;
do {
//zero-terminate in case file is empty
buf[0] = '\0';
nread = epic_file_read(fd, buf, sizeof(buf));
if (nread < sizeof(buf)) {
//add fake EOL to ensure termination
buf[nread] = '\n';
}
char *line = buf;
char *eol = NULL;
int last_eol = 0;
while (line) {
//line points one character past the las (if any) '\n' hence '- 1'
last_eol = line - buf - 1;
eol = strchr(line, '\n');
++lineNumber;
if (eol) {
*eol = '\0';
doline(line, eol, lineNumber);
line = eol + 1;
} else {
if (line == buf) {
//line did not fit into buf
LOG_WARN(
"card10.cfg",
"line:%d: too long - aborting",
lineNumber
);
return;
} else {
int seek_back = last_eol - nread;
LOG_DEBUG(
"card10.cfg",
"nread, last_eol, seek_back: %d,%d,%d",
nread,
last_eol,
seek_back
);
assert(seek_back <= 0);
if (seek_back) {
int rc = epic_file_seek(
fd,
seek_back,
SEEK_CUR
);
if (rc < 0) {
LOG_ERR("card10.cfg",
"seek failed, aborting");
return;
}
char newline;
rc = epic_file_read(
fd, &newline, 1
);
if (rc < 0 || newline != '\n') {
LOG_ERR("card10.cfg",
"seek failed, aborting");
LOG_DEBUG(
"card10.cfg",
"seek failed at read-back of newline: rc: %d read: %d",
rc,
(int)newline
);
return;
}
}
break;
}
}
}
} while (nread == sizeof(buf));
}
#ifndef CARD10_SETTING
# define CARD10_SETTING(identifier, spelling, type, default_value)
#endif
CARD10_SETTING(ExecuteElf, "execute_elf", Boolean, false)
//CARD10_SETTING(Nick, "nick", String, "an0n")
//CARD10_SETTING(Timeout, "timeout", Integer, 123)
//CARD10_SETTING(Dampening, "dampening", Float, 420)
#undef CARD10_SETTING
#ifndef EPICARDIUM_MODULES_CONFIG_H_INCLUDED
#define EPICARDIUM_MODULES_CONFIG_H_INCLUDED
#include <stdbool.h>
enum EpicConfigOption {
#define CARD10_SETTING(identifier, spelling, type, default_value) Option ## identifier,
#include "modules/config.def"
_EpicOptionCount
};
//initialize configuration values and load card10.cfg
void load_config(void);
bool config_get_boolean(enum EpicConfigOption option);
long config_get_integer(enum EpicConfigOption option);
double config_get_float(enum EpicConfigOption option);
const char* config_get_string(enum EpicConfigOption option);
#endif//EPICARDIUM_MODULES_CONFIG_H_INCLUDED
#include "epicardium.h"
#include "modules/log.h"
#include "modules/modules.h"
#include "modules/config.h"
#include "api/dispatcher.h"
#include "api/interrupt-sender.h"
#include "l0der/l0der.h"
......@@ -49,6 +50,7 @@ static volatile struct load_info async_load = {
/* Whether to write the menu script before attempting to load. */
static volatile bool write_menu = false;
static bool execute_elfs = false;
/* Helpers {{{ */
......@@ -88,9 +90,7 @@ static int load_stat(char *name)
*/
static int do_load(struct load_info *info)
{
#if defined(JAILBREAK_CARD10) && (JAILBREAK_CARD10 == 1)
struct l0dable_info l0dable;
#endif
int res;
if (*info->name == '\0') {
......@@ -129,18 +129,22 @@ static int do_load(struct load_info *info)
case PL_PYTHON_INTERP:
core1_load(PYCARDIUM_IVT, info->name);
break;
#if defined(JAILBREAK_CARD10) && (JAILBREAK_CARD10 == 1)
case PL_L0DABLE:
res = l0der_load_path(info->name, &l0dable);
if (res != 0) {
LOG_ERR("lifecycle", "l0der failed: %d\n", res);
xSemaphoreGive(api_mutex);
return -ENOEXEC;
if (execute_elfs) {
res = l0der_load_path(info->name, &l0dable);
if (res != 0) {
LOG_ERR("lifecycle", "l0der failed: %d\n", res);
xSemaphoreGive(api_mutex);
return -ENOEXEC;
}
core1_load(l0dable.isr_vector, "");
} else {
LOG_WARN(
"lifecycle",
"Execution of .elf l0dables is disabled"
);
}
core1_load(l0dable.isr_vector, "");
break;
#endif
default:
LOG_ERR("lifecyle",
"Attempted to load invalid payload (%s)",
......@@ -379,6 +383,8 @@ void vLifecycleTask(void *pvParameters)
hardware_init();
execute_elfs = config_get_boolean(OptionExecuteElf);
/* When triggered, reset core 1 to menu */
while (1) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
......
......@@ -21,5 +21,6 @@ module_sources = files(
'trng.c',
'vibra.c',
'watchdog.c',
'usb.c'
'usb.c',
'config.c',
)
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment