4#include "utils/etl_base64.h"
6#include "plugin/plugin.h"
7#include "utils/align.h"
8#include "utils/hashflash.h"
9#include "utils/logging.h"
14#ifdef ANABRID_ENABLE_GLOBAL_PLUGIN_LOADER
20GlobalPluginLoader::GlobalPluginLoader() {
21#ifdef ANABRID_ENABLE_GLOBAL_PLUGIN_LOADER
25 LOGMEV(
"Preparing MPU and %d bytes memory", memsize);
27 LOGMEV(
"Skipping due to missing ANABRID_ENABLE_GLOBAL_PLUGIN_LOADER",
"dummy");
32void loader::convertFromJson(JsonVariantConst
src, Function &f) {
35 }
else if (
src.is<JsonObjectConst>()) {
36 auto o =
src.as<JsonObjectConst>();
41 if (o["returns"] == #name) \
42 f.ret_type = Function::Returns::name
54 constexpr size_t inspect_bytes = 3;
55 char ret[2 * inspect_bytes + 3];
56 for (
size_t i = 0; i < inspect_bytes; i++)
57 sprintf(ret + 2 * i,
"%x", mem[i]);
58 for (
size_t i = 0; i < inspect_bytes; i++)
59 sprintf(ret +
sizeof(ret) - 2 * (i + 1),
"%x", mem[i]);
60 return std::string(ret);
64void loader::convertToJson(
const GlobalPluginLoader &
src, JsonVariant dst) {
65 dst[
"type"] =
"GlobalPluginLoader";
66#ifndef ANABRID_ENABLE_GLOBAL_PLUGIN_LOADER
67 dst[
"hint"] =
"Set ANABRID_ENABLE_GLOBAL_PLUGIN_LOADER debug feature flag to enable this loader";
70 dst[
"memsize"] =
src.memsize;
72 dst[
"can_load"] =
src.can_load();
73 dst[
"is_loaded"] =
src.plugin.has_value();
76 auto plugin = dst.createNestedObject(
"plugin");
77 plugin[
"size"] =
src.plugin->size;
78 utils::sha256 plugin_checksum(
src.plugin->load_addr,
src.plugin->size);
79 plugin[
"sha256sum"] = plugin_checksum.to_string();
88void dispatch(uint8_t *callee, Function::Returns ret_type, JsonVariant ret) {
90 case Function::Returns::None: {
91 auto entry = (Function::None_f *)callee;
95#define CALL(type, sig) \
96 case Function::Returns::type: { \
97 auto entry = (Function::sig *)callee; \
103 CALL(String, String_f);
104 CALL(JsonObject, JsonObject_f)
108#define return_err(code, msg) \
110 msg_out["error"] = msg; \
115int loader::SinglePluginLoader::load_and_execute(JsonObjectConst msg_in, JsonObject &msg_out) {
117 return_err(1,
"Already have plugin loaded, can only load one plugin at a time. Call unload before.");
119 return_err(2,
"PluginLoader cannot load code. This is currently most likely due to the missing compile "
120 "time flag ANABRID_ENABLE_GLOBAL_PLUGIN_LOADER");
121 if (!msg_in.containsKey(
"entry"))
122 return_err(3,
"Requiring entry point \"entry\"=0x1234 even if it is just 0.");
125 if (msg_in[
"load_addr"] != load_addr)
128 "Require matching load address for verification. This SinglePluginLoader can only load from: [todo]");
129 auto firmeware_hash = loader::flashimage::sha256sum().to_string();
130 if (utils::sha256_test_short(msg_in[
"firmware_sha256"], firmeware_hash))
131 return_err(5,
"ABI mismatch: You built against [your firmware sha256] but we run [our sha256]");
135 new_plugin.load_addr = load_addr;
136 new_plugin.entry = msg_in[
"entry"];
137 if (msg_in.containsKey(
"exit")) {
138 new_plugin.exit = msg_in[
"exit"].as<Function>();
145 auto base64_payload = msg_in[
"payload"].as<std::string>();
146 new_plugin.size = base64_payload.size() / 4 * 3;
147 if (!load(new_plugin))
148 return_err(6,
"Payload too large or some code is already loaded.");
149 auto length_decoded = etl::base64::decode(base64_payload.c_str(), base64_payload.length(),
150 new_plugin.load_addr, new_plugin.size);
151 if (length_decoded != new_plugin.size) {
153 return_err(7,
"Could not decode base64-encoded payload.");
157 uint8_t *entry_point = assert_callable(plugin->load_addr + plugin->entry.addr);
160 return_err(8,
"Entry point address not properly aligned");
162 dispatch(entry_point, plugin->entry.ret_type, msg_out[
"returns"].as<JsonVariant>());
165 if (msg_in.containsKey(
"immediately_unload"))
172int loader::SinglePluginLoader::unload(JsonObjectConst msg_in, JsonObject &msg_out) {
174 return_err(9,
"Cannot unload, nothing loaded");
178 uint8_t *exit_point = assert_callable(plugin->load_addr + plugin->exit->addr);
181 return_err(10,
"Exit point address not properly aligned");
183 dispatch(exit_point, plugin->exit->ret_type, msg_out[
"returns"].as<JsonVariant>());
190int loader::SinglePluginLoader::load(
const Plugin &new_plugin) {
193 if (new_plugin.size > memsize)
200loader::GlobalPluginLoader loader::PluginLoader;
#define return_err(code, msg)
static constexpr int the_memsize
uint8_t GlobalPluginLoader_Storage[the_memsize]
FLASHMEM std::string shortened_hexdump(uint8_t *mem, size_t size)
FLASHMEM void dispatch(uint8_t *callee, Function::Returns ret_type, JsonVariant ret)
void prepare_mpu()
At the time being, we completely disable the Memory Protection Unit in order to enable our plugin sys...