Add initial (primitive) firmware upload / Flash write support

parent 9b539060
This diff is collapsed.
......@@ -11,6 +11,16 @@
#define KESTREL_SERVICE_THREAD_PRIORITY K_PRIO_COOP(1)
#endif
struct firmware_buffer_region {
uint8_t *buffer_address;
unsigned long long buffer_length;
uintptr_t current_write_offset;
uint8_t locked;
uint8_t overflow;
};
extern struct firmware_buffer_region main_firmware_buffer;
extern uint8_t kestrel_basic_init_complete;
extern uint8_t host_background_service_task_active;
extern uint8_t host_console_service_task_requested;
......@@ -25,6 +35,7 @@ int kestrel_init(void);
int power_on_host(void);
void power_off_chassis(void);
void print_chassis_status(void);
int write_flash_buffer_to_flash(void);
int primary_service_event_loop(void);
......
......@@ -31,14 +31,14 @@ static void kestrel_console_thread(const void *p1, const void *p2)
void *active_log_backend = (void*)p2;
uint32_t active_log_level = CONFIG_LOG_DEFAULT_LEVEL;
// Get shell printf context
const struct shell_fprintf *sh_fprintf = shell->fprintf_ctx;
// Get shell printf context
const struct shell_fprintf *sh_fprintf = shell->fprintf_ctx;
k_mutex_lock(&shell->ctx->wr_mtx, K_FOREVER);
shell_stop(shell);
sh_fprintf->fwrite((const struct shell *)sh_fprintf->user_ctx, CONSOLE_ATTACH_BANNER, strlen(CONSOLE_ATTACH_BANNER));
sh_fprintf->fwrite((const struct shell *)sh_fprintf->user_ctx, CONSOLE_ATTACH_BANNER, strlen(CONSOLE_ATTACH_BANNER));
attach_to_host_console(shell);
......@@ -93,6 +93,14 @@ static void print_kestrel_utility_command_usage(const struct shell *shell, char*
shell_print(shell, "Usage: %s <poweron chassison chassisoff>", command_name);
}
static void print_kestrel_reflash_command_usage(const struct shell *shell, char* command_name) {
shell_print(shell, "Usage: %s <pnor>", command_name);
}
static void print_kestrel_memdump_command_usage(const struct shell *shell, char* command_name) {
shell_print(shell, "Usage: %s <address> [length]", command_name);
}
static int kestrel_shell_cmd_utility(const struct shell *shell, size_t argc, char **argv)
{
if (argc < 2) {
......@@ -118,6 +126,56 @@ static int kestrel_shell_cmd_utility(const struct shell *shell, size_t argc, cha
}
}
static int kestrel_shell_cmd_reflash(const struct shell *shell, size_t argc, char **argv)
{
if (argc < 2) {
print_kestrel_reflash_command_usage(shell, argv[0]);
return -1;
}
if (strcmp(argv[1], "pnor") == 0) {
VERIFY_KESTREL_START_COMPLETE(shell)
return write_flash_buffer_to_flash();
}
else {
shell_print(shell, "%s: Invalid parameter", argv[0]);
print_kestrel_reflash_command_usage(shell, argv[0]);
return -1;
}
}
static int kestrel_shell_cmd_memdump(const struct shell *shell, size_t argc, char **argv)
{
uintptr_t address;
size_t length;
int pos;
int remaining;
if (argc < 2) {
print_kestrel_memdump_command_usage(shell, argv[0]);
return -1;
}
address = strtoul(argv[1], NULL, 16);
if (argc > 2) {
length = strtoul(argv[2], NULL, 16);
}
else {
length = 1;
}
for (pos = 0; pos < length; pos += remaining) {
remaining = MIN(length - pos, SHELL_HEXDUMP_BYTES_IN_LINE);
shell_hexdump_line(shell, address, (uint8_t*)address, remaining);
address += remaining;
}
shell_print(shell, "");
return 0;
}
static int kestrel_shell_cmd_console(const struct shell *shell, size_t argc, char **argv)
{
const void *active_log_backend = NULL;
......@@ -153,6 +211,10 @@ SHELL_STATIC_SUBCMD_SET_CREATE(sub_kestrel,
SHELL_CMD(obmcutil, NULL, "OBMC-compatible utilty command", kestrel_shell_cmd_utility),
// OpenBMC console command (compat)
SHELL_CMD(obmc-console-client, NULL, "OBMC-compatible console command", kestrel_shell_cmd_console),
// Flash programming command
SHELL_CMD(reflash, NULL, "Simple Flash utility", kestrel_shell_cmd_reflash),
// Arbitrary memory dump command
SHELL_CMD(memdump, NULL, "Memory dump tool", kestrel_shell_cmd_memdump),
// Command list array terminator
SHELL_SUBCMD_SET_END
);
......
......@@ -10,6 +10,9 @@
#include "civetweb.h"
#define WITH_ZEPHYR 1
#include "kestrel.h"
#define HTTP_PORT 8080
#define HTTPS_PORT 4443
......@@ -54,6 +57,7 @@ int hello_world_handler(struct mg_connection *conn, void *cbdata)
mg_printf(conn, "<ul>\n");
mg_printf(conn, "<li><a href=/info>system info</a></li>\n");
mg_printf(conn, "<li><a href=/history>cookie demo</a></li>\n");
mg_printf(conn, "<li><a href=/firmwareupload>firmware upload</a></li>\n");
mg_printf(conn, "</ul>\n");
mg_printf(conn, "</body></html>\n");
......@@ -141,6 +145,98 @@ int history_handler(struct mg_connection *conn, void *cbdata)
return 200;
}
int firmware_upload_form_handler(struct mg_connection *conn, void *cbdata)
{
mg_printf(conn,
"HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nConnection: "
"close\r\n\r\n");
mg_printf(conn, "<!DOCTYPE html>\n");
mg_printf(conn, "<html>\n<head>\n");
mg_printf(conn, "<meta charset=\"UTF-8\">\n");
mg_printf(conn, "<title>File upload</title>\n");
mg_printf(conn, "</head>\n<body>\n");
mg_printf(conn,
"<form action=\"%s\" method=\"POST\" "
"enctype=\"multipart/form-data\">\n",
(const char *)cbdata);
mg_printf(conn, "<input type=\"file\" name=\"firmwarefile\" multiple>\n");
mg_printf(conn, "<input type=\"submit\" value=\"Submit\">\n");
mg_printf(conn, "</form>\n</body>\n</html>\n");
return 200;
}
int fw_field_received(const char *key, const char *filename, char *path, size_t pathlen, void *user_data)
{
(void)key;
(void)path;
(void)pathlen;
if (strcmp(key, "firmwarefile") == 0) {
return MG_FORM_FIELD_STORAGE_GET;
}
return MG_FORM_FIELD_STORAGE_ABORT;
}
int fw_data_received(const char *key, const char *value, size_t valuelen, void *user_data)
{
struct firmware_buffer_region *fw_data = (struct firmware_buffer_region *)user_data;
if ((fw_data->current_write_offset + valuelen) > fw_data->buffer_length) {
// Buffer overflow!
// Discard the extra data...
valuelen = fw_data->buffer_length - fw_data->current_write_offset;
fw_data->overflow = 1;
}
memcpy(fw_data->buffer_address + fw_data->current_write_offset, value, valuelen);
fw_data->current_write_offset += valuelen;
return 0;
}
int firmware_upload_handler(struct mg_connection *conn, void *cbdata)
{
/* Handler may access the request info using mg_get_request_info */
const struct mg_request_info *req_info = mg_get_request_info(conn);
int ret;
struct mg_form_data_handler fdh = {fw_field_received,
fw_data_received,
0,
(void *)&main_firmware_buffer};
/* It would be possible to check the request info here before calling
* mg_handle_form_request. */
(void)req_info;
mg_printf(conn,
"HTTP/1.1 200 OK\r\n"
"Content-Type: text/plain\r\n"
"Connection: close\r\n\r\n");
main_firmware_buffer.locked = 1;
main_firmware_buffer.overflow = 0;
main_firmware_buffer.current_write_offset = 0;
/* Call the form handler */
mg_printf(conn, "File(s) uploaded:");
ret = mg_handle_form_request(conn, &fdh);
main_firmware_buffer.locked = 0;
mg_printf(conn, "\r\n%i files\r\n", ret);
mg_printf(conn, "\r\n%ld bytes\r\n", main_firmware_buffer.current_write_offset);
if (main_firmware_buffer.overflow) {
mg_printf(conn, "\r\nWARNING: Data was discarded due to buffer overflow!r\n");
return 500;
}
return 200;
}
void *main_pthread(void *arg)
{
static const char * const options[] = {
......@@ -166,9 +262,12 @@ void *main_pthread(void *arg)
return 0;
}
mg_set_request_handler(ctx, "/$", hello_world_handler, 0);
mg_set_request_handler(ctx, "/info$", system_info_handler, 0);
mg_set_request_handler(ctx, "/history", history_handler, 0);
mg_set_request_handler(ctx, "/$", hello_world_handler, (void *)0);
mg_set_request_handler(ctx, "/info$", system_info_handler, (void *)0);
mg_set_request_handler(ctx, "/history", history_handler, (void *)0);
mg_set_request_handler(ctx, "/firmwareupload", firmware_upload_form_handler, (void *)"/firmwareupload.callback");
mg_set_request_handler(ctx, "/firmwareupload.callback", firmware_upload_handler, (void *)0);
return 0;
}
......
......@@ -12,6 +12,8 @@ CONFIG_DEVICE_SHELL=y
CONFIG_POSIX_CLOCK=y
CONFIG_DATE_SHELL=y
CONFIG_NET_SHELL=y
CONFIG_FLASH_SHELL=y
CONFIG_FLASH_MAP_SHELL=y
CONFIG_SHELL_CMDS_SELECT=y
CONFIG_SHELL_BACKEND_SERIAL=y
CONFIG_SHELL_BACKEND_TELNET=y
......@@ -28,6 +30,12 @@ CONFIG_FILE_SYSTEM_LITTLEFS=y
# Kestrel specific configuration
CONFIG_NET_TC_THREAD_PREEMPTIVE=y
CONFIG_NET_TC_TX_COUNT=1
# The Kestrel CPU is quite slow, and it's easy to starve the CivetWeb process
# during file uploads if the TCP queues have a higher preempt priority than
# the CivetWeb process (by default, this is true)...
CONFIG_NUM_PREEMPT_PRIORITIES=1
# Kernel options
CONFIG_TEST_RANDOM_GENERATOR=y
......@@ -70,10 +78,10 @@ CONFIG_NET_MGMT=y
CONFIG_NET_MGMT_EVENT=y
# Network buffers
CONFIG_NET_PKT_RX_COUNT=96
CONFIG_NET_PKT_TX_COUNT=96
CONFIG_NET_BUF_RX_COUNT=128
CONFIG_NET_BUF_TX_COUNT=128
CONFIG_NET_PKT_RX_COUNT=4096
CONFIG_NET_PKT_TX_COUNT=4096
CONFIG_NET_BUF_RX_COUNT=4096
CONFIG_NET_BUF_TX_COUNT=4096
CONFIG_NET_CONTEXT_NET_PKT_POOL=y
CONFIG_NET_BUF_POOL_USAGE=y
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment