[app][lkboot] restructure to add booting out of flash

-Now lkboot will start a network server (if networking is enabled)
    and wait for a predetermined amount of time (5 seconds currently).
    If after that time no one has talked to it, it will try to boot
    an image out of flash.
-If no networking, then directly boot an image out of flash immediately.

TODO: configure timeout, add 'autoboot' command to lkboot to let the host
short circuit the wait.
This commit is contained in:
Travis Geiselbrecht
2015-03-03 14:59:27 -08:00
parent 9dafcb855d
commit d449902adc
4 changed files with 458 additions and 321 deletions

View File

@@ -30,6 +30,7 @@
#include <endian.h>
#include <malloc.h>
#include <arch.h>
#include <err.h>
#include <trace.h>
#include <kernel/thread.h>
@@ -48,178 +49,270 @@
#define bootdevice "spi0"
#define LOCAL_TRACE 0
extern void *lkb_iobuffer;
extern paddr_t lkb_iobuffer_phys;
extern size_t lkb_iobuffer_size;
struct lkb_command {
struct lkb_command *next;
const char *name;
lkb_handler_t handler;
void *cookie;
struct lkb_command *next;
const char *name;
lkb_handler_t handler;
void *cookie;
};
struct lkb_command *lkb_cmd_list = NULL;
void lkb_register(const char *name, lkb_handler_t handler, void *cookie) {
struct lkb_command *cmd = malloc(sizeof(struct lkb_command));
if (cmd != NULL) {
cmd->next = lkb_cmd_list;
cmd->name = name;
cmd->handler = handler;
cmd->cookie = cookie;
lkb_cmd_list = cmd;
}
struct lkb_command *cmd = malloc(sizeof(struct lkb_command));
if (cmd != NULL) {
cmd->next = lkb_cmd_list;
cmd->name = name;
cmd->handler = handler;
cmd->cookie = cookie;
lkb_cmd_list = cmd;
}
}
static int do_reboot(void *arg) {
thread_sleep(250);
platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_RESET);
return 0;
thread_sleep(250);
platform_halt(HALT_ACTION_REBOOT, HALT_REASON_SW_RESET);
return 0;
}
static int do_boot(void *arg) {
thread_sleep(250);
thread_sleep(250);
/* construct a boot argument list */
// XXX get memory smarter than this
const size_t bootargs_size = 64*1024;
void *args = (void *)((uintptr_t)lkb_iobuffer + lkb_iobuffer_size - bootargs_size);
paddr_t args_phys = lkb_iobuffer_phys + lkb_iobuffer_size - bootargs_size;
bootargs_start(args, bootargs_size);
bootargs_add_command_line(args, bootargs_size, "what what");
/* construct a boot argument list */
// XXX get memory smarter than this
const size_t bootargs_size = 64*1024;
void *args = (void *)((uintptr_t)lkb_iobuffer + lkb_iobuffer_size - bootargs_size);
paddr_t args_phys = lkb_iobuffer_phys + lkb_iobuffer_size - bootargs_size;
bootargs_start(args, bootargs_size);
bootargs_add_command_line(args, bootargs_size, "what what");
ulong lk_args[4];
bootargs_generate_lk_arg_values(args_phys, lk_args);
ulong lk_args[4];
bootargs_generate_lk_arg_values(args_phys, lk_args);
const void *ptr;
const void *ptr;
/* sniff it to see if it's a bootimage or a raw image */
bootimage_t *bi;
if (bootimage_open(lkb_iobuffer, lkb_iobuffer_size, &bi) >= 0) {
size_t len;
/* sniff it to see if it's a bootimage or a raw image */
bootimage_t *bi;
if (bootimage_open(lkb_iobuffer, lkb_iobuffer_size, &bi) >= 0) {
size_t len;
/* it's a bootimage */
TRACEF("detected bootimage\n");
/* it's a bootimage */
TRACEF("detected bootimage\n");
/* find the lk image */
if (bootimage_get_file_section(bi, TYPE_LK, &ptr, &len) >= 0) {
TRACEF("found lk section at %p\n", ptr);
/* find the lk image */
if (bootimage_get_file_section(bi, TYPE_LK, &ptr, &len) >= 0) {
TRACEF("found lk section at %p\n", ptr);
/* add the boot image to the argument list */
size_t bootimage_size;
bootimage_get_range(bi, NULL, &bootimage_size);
/* add the boot image to the argument list */
size_t bootimage_size;
bootimage_get_range(bi, NULL, &bootimage_size);
bootargs_add_bootimage_pointer(args, bootargs_size, lkb_iobuffer_phys, bootimage_size);
}
} else {
/* raw image, just chain load it directly */
TRACEF("raw image, chainloading\n");
bootargs_add_bootimage_pointer(args, bootargs_size, "pmem", lkb_iobuffer_phys, bootimage_size);
}
} else {
/* raw image, just chain load it directly */
TRACEF("raw image, chainloading\n");
ptr = lkb_iobuffer;
}
ptr = lkb_iobuffer;
}
arch_chain_load((void *)ptr, lk_args[0], lk_args[1], lk_args[2], lk_args[3]);
arch_chain_load((void *)ptr, lk_args[0], lk_args[1], lk_args[2], lk_args[3]);
return 0;
return 0;
}
/* try to boot the system from a flash partition */
status_t do_flash_boot(void)
{
status_t err;
/* construct a boot argument list */
// XXX get memory smarter than this
const size_t bootargs_size = 64*1024;
void *args = (void *)((uintptr_t)lkb_iobuffer + lkb_iobuffer_size - bootargs_size);
paddr_t args_phys = lkb_iobuffer_phys + lkb_iobuffer_size - bootargs_size;
bootargs_start(args, bootargs_size);
bootargs_add_command_line(args, bootargs_size, "what what");
ulong lk_args[4];
bootargs_generate_lk_arg_values(args_phys, lk_args);
const void *ptr;
if (!ptable_found_valid()) {
TRACEF("ptable not found\n");
return ERR_NOT_FOUND;
}
/* find the system partition */
struct ptable_entry entry;
err = ptable_find("system", &entry);
if (err < 0) {
TRACEF("cannot find system partition\n");
return ERR_NOT_FOUND;
}
/* get a direct pointer to the device */
bdev_t *bdev = ptable_get_device();
if (!bdev) {
TRACEF("error opening boot device\n");
return ERR_NOT_FOUND;
}
/* convert the bdev to a memory pointer */
err = bio_ioctl(bdev, BIO_IOCTL_GET_MEM_MAP, (void *)&ptr);
TRACEF("err %d, ptr %p\n", err, ptr);
if (err < 0) {
TRACEF("error getting direct pointer to block device\n");
return ERR_NOT_FOUND;
}
/* sniff it to see if it's a bootimage or a raw image */
bootimage_t *bi;
if (bootimage_open((char *)ptr + entry.offset, entry.length, &bi) >= 0) {
size_t len;
/* it's a bootimage */
TRACEF("detected bootimage\n");
/* find the lk image */
if (bootimage_get_file_section(bi, TYPE_LK, &ptr, &len) >= 0) {
TRACEF("found lk section at %p\n", ptr);
/* add the boot image to the argument list */
size_t bootimage_size;
bootimage_get_range(bi, NULL, &bootimage_size);
bootargs_add_bootimage_pointer(args, bootargs_size, bdev->name, entry.offset, bootimage_size);
}
} else {
/* did not find a bootimage, abort */
bio_ioctl(bdev, BIO_IOCTL_PUT_MEM_MAP, NULL);
return ERR_NOT_FOUND;
}
TRACEF("chain loading binary at %p\n", ptr);
arch_chain_load((void *)ptr, lk_args[0], lk_args[1], lk_args[2], lk_args[3]);
/* put the block device back into block mode (though we never get here) */
bio_ioctl(bdev, BIO_IOCTL_PUT_MEM_MAP, NULL);
return NO_ERROR;
}
// return NULL for success, error string for failure
const char *lkb_handle_command(lkb_t *lkb, const char *cmd, const char *arg, unsigned len) {
struct lkb_command *lcmd;
for (lcmd = lkb_cmd_list; lcmd; lcmd = lcmd->next) {
if (!strcmp(lcmd->name, cmd)) {
return lcmd->handler(lkb, arg, len, lcmd->cookie);
}
}
int lkb_handle_command(lkb_t *lkb, const char *cmd, const char *arg, unsigned len, const char **result)
{
*result = NULL;
if (len > lkb_iobuffer_size) {
return "buffer too small";
}
if (!strcmp(cmd, "flash") || !strcmp(cmd, "erase")) {
struct ptable_entry entry;
bdev_t *bdev;
struct lkb_command *lcmd;
for (lcmd = lkb_cmd_list; lcmd; lcmd = lcmd->next) {
if (!strcmp(lcmd->name, cmd)) {
*result = lcmd->handler(lkb, arg, len, lcmd->cookie);
return 0;
}
}
if (ptable_find(arg, &entry) < 0) {
size_t plen = len;
/* doesn't exist, make one */
if (len > lkb_iobuffer_size) {
*result = "buffer too small";
return -1;
}
if (!strcmp(cmd, "flash") || !strcmp(cmd, "erase")) {
struct ptable_entry entry;
bdev_t *bdev;
if (ptable_find(arg, &entry) < 0) {
size_t plen = len;
/* doesn't exist, make one */
#if PLATFORM_ZYNQ
/* XXX not really the right place, should be in the ptable/bio layer */
plen = ROUNDUP(plen, 256*1024);
/* XXX not really the right place, should be in the ptable/bio layer */
plen = ROUNDUP(plen, 256*1024);
#endif
off_t off = ptable_allocate(plen, 0);
if (off < 0) {
return "no space to allocate partition";
}
off_t off = ptable_allocate(plen, 0);
if (off < 0) {
*result = "no space to allocate partition";
return -1;
}
if (ptable_add(arg, off, plen, 0) < 0) {
return "error creating partition";
}
if (ptable_add(arg, off, plen, 0) < 0) {
*result = "error creating partition";
return -1;
}
if (ptable_find(arg, &entry) < 0) {
return "couldn't find partition after creating it";
}
}
if (len > entry.length) {
return "partition too small";
}
if (lkb_read(lkb, lkb_iobuffer, len)) {
return "io error";
}
if (!(bdev = bio_open(bootdevice))) {
return "bio_open failed";
}
if (bio_erase(bdev, entry.offset, entry.length) != (ssize_t)entry.length) {
bio_close(bdev);
return "bio_erase failed";
}
if (!strcmp(cmd, "flash")) {
if (bio_write(bdev, lkb_iobuffer, entry.offset, len) != (ssize_t)len) {
bio_close(bdev);
return "bio_write failed";
}
}
bio_close(bdev);
return NULL;
} else if (!strcmp(cmd, "remove")) {
if (ptable_remove(arg) < 0) {
return "remove failed";
}
return NULL;
} else if (!strcmp(cmd, "fpga")) {
if (ptable_find(arg, &entry) < 0) {
*result = "couldn't find partition after creating it";
return -1;
}
}
if (len > entry.length) {
*result = "partition too small";
return -1;
}
if (lkb_read(lkb, lkb_iobuffer, len)) {
*result = "io error";
return -1;
}
if (!(bdev = ptable_get_device())) {
*result = "ptable_get_device failed";
return -1;
}
printf("lkboot: erasing partition of size %llu\n", entry.length);
if (bio_erase(bdev, entry.offset, entry.length) != (ssize_t)entry.length) {
*result = "bio_erase failed";
return -1;
}
if (!strcmp(cmd, "flash")) {
printf("lkboot: writing to partition\n");
if (bio_write(bdev, lkb_iobuffer, entry.offset, len) != (ssize_t)len) {
*result = "bio_write failed";
return -1;
}
}
} else if (!strcmp(cmd, "remove")) {
if (ptable_remove(arg) < 0) {
*result = "remove failed";
return -1;
}
} else if (!strcmp(cmd, "fpga")) {
#if PLATFORM_ZYNQ
if (lkb_read(lkb, lkb_iobuffer, len)) {
return "io error";
}
if (lkb_read(lkb, lkb_iobuffer, len)) {
*result = "io error";
return -1;
}
zynq_reset_fpga();
zynq_program_fpga(lkb_iobuffer_phys, len);
return NULL;
zynq_reset_fpga();
zynq_program_fpga(lkb_iobuffer_phys, len);
*result = NULL;
#else
return "no fpga";
*result = "no fpga";
return -1;
#endif
} else if (!strcmp(cmd, "boot")) {
if (lkb_read(lkb, lkb_iobuffer, len)) {
return "io error";
}
thread_resume(thread_create("boot", &do_boot, NULL,
DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
return NULL;
} else if (!strcmp(cmd, "getsysparam")) {
const void *ptr;
size_t len;
if (sysparam_get_ptr(arg, &ptr, &len) == 0) {
lkb_write(lkb, ptr, len);
}
return NULL;
} else if (!strcmp(cmd, "reboot")) {
thread_resume(thread_create("reboot", &do_reboot, NULL,
DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
return NULL;
} else {
return "unknown command";
}
}
} else if (!strcmp(cmd, "boot")) {
if (lkb_read(lkb, lkb_iobuffer, len)) {
*result = "io error";
return -1;
}
thread_resume(thread_create("boot", &do_boot, NULL,
DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
} else if (!strcmp(cmd, "getsysparam")) {
const void *ptr;
size_t len;
if (sysparam_get_ptr(arg, &ptr, &len) == 0) {
lkb_write(lkb, ptr, len);
}
} else if (!strcmp(cmd, "reboot")) {
thread_resume(thread_create("reboot", &do_reboot, NULL,
DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
} else {
*result = "unknown command";
return -1;
}
// vim: noexpandtab
return 0;
}

View File

@@ -36,7 +36,7 @@ int lkb_write(lkb_t *lkb, const void *data, size_t len);
// use lkb_read() to read some or all of this data
// return NULL on success, or an asciiz string (message) for error
typedef const char* (*lkb_handler_t)(lkb_t *lkb,
const char *arg, unsigned len, void *cookie);
const char *arg, unsigned len, void *cookie);
// cmd must be a string constant
void lkb_register(const char *cmd, lkb_handler_t handler, void *cookie);

View File

@@ -28,15 +28,29 @@
#include <debug.h>
#include <string.h>
#include <pow2.h>
#include <err.h>
#include <assert.h>
#include <trace.h>
#include <kernel/thread.h>
#include <kernel/mutex.h>
#include <kernel/vm.h>
#include <lib/minip.h>
#include <app/lkboot.h>
#include "lkboot.h"
#if WITH_LIB_MINIP
#include <lib/minip.h>
#define LKBOOT_WITH_SERVER 1
#else
#define LKBOOT_WITH_SERVER 0
#endif
//#define LKBOOT_SERVER_TIMEOUT INFINITE_TIME
#define LKBOOT_SERVER_TIMEOUT 5000
#define LOCAL_TRACE 0
void *lkb_iobuffer = 0;
paddr_t lkb_iobuffer_phys = 0;
size_t lkb_iobuffer_size = 16*1024*1024;
@@ -48,217 +62,249 @@ size_t lkb_iobuffer_size = 16*1024*1024;
#define STATE_ERROR 4
typedef struct LKB {
tcp_socket_t *s;
int state;
size_t avail;
tcp_socket_t *s;
int state;
size_t avail;
} lkb_t;
static volatile int busy = 0;
extern int lkb_handle_command(lkb_t *lkb, const char *cmd, const char *arg, unsigned len, const char **result);
extern status_t do_flash_boot(void);
static int readx(void *s, void *_data, size_t len) {
char *data = _data;
while (len > 0) {
int r = tcp_read(s, data, len);
if (r <= 0) return -1;
data += r;
len -= r;
}
return 0;
char *data = _data;
while (len > 0) {
int r = tcp_read(s, data, len);
if (r <= 0) return -1;
data += r;
len -= r;
}
return 0;
}
static int lkb_send(lkb_t *lkb, u8 opcode, const void *data, size_t len) {
msg_hdr_t hdr;
msg_hdr_t hdr;
// once we sent our OKAY or FAIL or errored out, no more writes
if (lkb->state >= STATE_DONE) return -1;
// once we sent our OKAY or FAIL or errored out, no more writes
if (lkb->state >= STATE_DONE) return -1;
switch (opcode) {
case MSG_OKAY:
case MSG_FAIL:
lkb->state = STATE_DONE;
if (len > 0xFFFF) return -1;
break;
case MSG_LOG:
if (len > 0xFFFF) return -1;
break;
case MSG_SEND_DATA:
if (len > 0x10000) return -1;
break;
case MSG_GO_AHEAD:
if (lkb->state == STATE_OPEN) {
lkb->state = STATE_DATA;
break;
}
len = 0;
default:
lkb->state = STATE_ERROR;
opcode = MSG_FAIL;
data = "internal error";
len = 14;
break;
}
switch (opcode) {
case MSG_OKAY:
case MSG_FAIL:
lkb->state = STATE_DONE;
if (len > 0xFFFF) return -1;
break;
case MSG_LOG:
if (len > 0xFFFF) return -1;
break;
case MSG_SEND_DATA:
if (len > 0x10000) return -1;
break;
case MSG_GO_AHEAD:
if (lkb->state == STATE_OPEN) {
lkb->state = STATE_DATA;
break;
}
len = 0;
default:
lkb->state = STATE_ERROR;
opcode = MSG_FAIL;
data = "internal error";
len = 14;
break;
}
hdr.opcode = opcode;
hdr.extra = 0;
hdr.length = (opcode == MSG_SEND_DATA) ? (len - 1) : len;
if (tcp_write(lkb->s, &hdr, sizeof(hdr)) != sizeof(&hdr)) {
printf("xmit hdr fail\n");
lkb->state = STATE_ERROR;
return -1;
}
if (len && (tcp_write(lkb->s, data, len) != (ssize_t)len)) {
printf("xmit data fail\n");
lkb->state = STATE_ERROR;
return -1;
}
return 0;
hdr.opcode = opcode;
hdr.extra = 0;
hdr.length = (opcode == MSG_SEND_DATA) ? (len - 1) : len;
if (tcp_write(lkb->s, &hdr, sizeof(hdr)) != sizeof(&hdr)) {
printf("xmit hdr fail\n");
lkb->state = STATE_ERROR;
return -1;
}
if (len && (tcp_write(lkb->s, data, len) != (ssize_t)len)) {
printf("xmit data fail\n");
lkb->state = STATE_ERROR;
return -1;
}
return 0;
}
#define lkb_okay(lkb) lkb_send(lkb, MSG_OKAY, NULL, 0)
#define lkb_fail(lkb, msg) lkb_send(lkb, MSG_FAIL, msg, strlen(msg))
int lkb_write(lkb_t *lkb, const void *_data, size_t len) {
const char *data = _data;
while (len > 0) {
size_t xfer = (len > 65536) ? 65536 : len;
if (lkb_send(lkb, MSG_SEND_DATA, data, xfer)) return -1;
len -= xfer;
data += xfer;
}
return 0;
const char *data = _data;
while (len > 0) {
size_t xfer = (len > 65536) ? 65536 : len;
if (lkb_send(lkb, MSG_SEND_DATA, data, xfer)) return -1;
len -= xfer;
data += xfer;
}
return 0;
}
int lkb_read(lkb_t *lkb, void *_data, size_t len) {
char *data = _data;
char *data = _data;
printf("lkb_read %d\n", len);
if (lkb->state == STATE_RESP) {
return 0;
}
if (lkb->state == STATE_OPEN) {
if (lkb_send(lkb, MSG_GO_AHEAD, NULL, 0)) return -1;
}
while (len > 0) {
if (lkb->avail == 0) {
msg_hdr_t hdr;
if (readx(lkb->s, &hdr, sizeof(hdr))) goto fail;
if (hdr.opcode == MSG_END_DATA) {
lkb->state = STATE_RESP;
return -1;
}
if (hdr.opcode != MSG_SEND_DATA) goto fail;
lkb->avail = ((size_t) hdr.length) + 1;
}
if (lkb->avail >= len) {
if (readx(lkb->s, data, len)) goto fail;
lkb->avail -= len;
return 0;
}
if (readx(lkb->s, data, lkb->avail)) {
lkb->state = STATE_ERROR;
return -1;
}
data += lkb->avail;
len -= lkb->avail;
lkb->avail = 0;
}
return 0;
printf("lkb_read %d\n", len);
if (lkb->state == STATE_RESP) {
return 0;
}
if (lkb->state == STATE_OPEN) {
if (lkb_send(lkb, MSG_GO_AHEAD, NULL, 0)) return -1;
}
while (len > 0) {
if (lkb->avail == 0) {
msg_hdr_t hdr;
if (readx(lkb->s, &hdr, sizeof(hdr))) goto fail;
if (hdr.opcode == MSG_END_DATA) {
lkb->state = STATE_RESP;
return -1;
}
if (hdr.opcode != MSG_SEND_DATA) goto fail;
lkb->avail = ((size_t) hdr.length) + 1;
}
if (lkb->avail >= len) {
if (readx(lkb->s, data, len)) goto fail;
lkb->avail -= len;
return 0;
}
if (readx(lkb->s, data, lkb->avail)) {
lkb->state = STATE_ERROR;
return -1;
}
data += lkb->avail;
len -= lkb->avail;
lkb->avail = 0;
}
return 0;
fail:
lkb->state = STATE_ERROR;
return -1;
lkb->state = STATE_ERROR;
return -1;
}
const char *lkb_handle_command(lkb_t *lkb, const char *cmd, const char *arg, unsigned len);
static status_t handle_txn(tcp_socket_t *s)
{
msg_hdr_t hdr;
lkb_t lkb;
char cmd[128];
char *arg;
int err;
const char *result;
unsigned len;
static int handle_txn(void *s) {
msg_hdr_t hdr;
lkb_t lkb;
char cmd[128];
char *arg;
const char *err;
unsigned len;
if (readx(s, &hdr, sizeof(hdr))) goto fail;
if (hdr.opcode != MSG_CMD) goto fail;
if (hdr.length > 127) goto fail;
if (readx(s, cmd, hdr.length)) goto fail;
cmd[hdr.length] = 0;
if (readx(s, &hdr, sizeof(hdr))) goto fail;
if (hdr.opcode != MSG_CMD) goto fail;
if (hdr.length > 127) goto fail;
if (readx(s, cmd, hdr.length)) goto fail;
cmd[hdr.length] = 0;
printf("lkboot: recv '%s'\n", cmd);
printf("lkboot: recv '%s'\n", cmd);
if (!(arg = strchr(cmd, ':'))) goto fail;
*arg++ = 0;
len = atoul(arg);
if (!(arg = strchr(arg, ':'))) goto fail;
arg++;
lkb.s = s;
lkb.state = STATE_OPEN;
lkb.avail = 0;
err = lkb_handle_command(&lkb, cmd, arg, len, &result);
if (err >= 0) {
lkb_okay(&lkb);
} else {
lkb_fail(&lkb, result);
}
return NO_ERROR;
if (!(arg = strchr(cmd, ':'))) goto fail;
*arg++ = 0;
len = atoul(arg);
if (!(arg = strchr(arg, ':'))) goto fail;
arg++;
lkb.s = s;
lkb.state = STATE_OPEN;
lkb.avail = 0;
err = lkb_handle_command(&lkb, cmd, arg, len);
if (err == 0) {
lkb_okay(&lkb);
} else {
lkb_fail(&lkb, err);
}
fail:
tcp_close(s);
busy = 0;
return 0;
tcp_close(s);
return ERR_IO;
}
static int lkboot_server(void *arg) {
tcp_socket_t *listen_socket;
tcp_socket_t *s;
static void lkboot_task(const struct app_descriptor *app, void *args)
{
#if LKBOOT_WITH_SERVER
tcp_socket_t *listen_socket = NULL;
bool wait_forever = (LKBOOT_SERVER_TIMEOUT == INFINITE_TIME);
if (tcp_open_listen(&listen_socket, 1023) < 0) {
printf("lkboot: error opening listen socket\n");
return -1;
}
// allocate memory for the server
if (vmm_alloc_contiguous(vmm_get_kernel_aspace(), "lkboot_iobuf",
lkb_iobuffer_size, &lkb_iobuffer, log2_uint(lkb_iobuffer_size), 0,
ARCH_MMU_FLAG_UNCACHED) < 0) {
goto regboot;
}
if (arch_mmu_query((u32) lkb_iobuffer, &lkb_iobuffer_phys, NULL) < 0) {
goto regboot;
}
printf("lkboot: iobuffer %p (phys 0x%lx)\n", lkb_iobuffer, lkb_iobuffer_phys);
for (;;) {
if (tcp_accept(listen_socket, &s) < 0) {
continue;
}
if (busy) {
printf("lkboot: concurrent connections disallowed\n");
tcp_close(s);
continue;
}
busy = 1;
thread_detach_and_resume(
thread_create("lkboot_txn", &handle_txn, s,
DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
}
return 0;
}
serverloop:
/* open the server's socket */
if (tcp_open_listen(&listen_socket, 1023) < 0) {
printf("lkboot: error opening listen socket\n");
goto regboot;
}
static void lkboot_init(const struct app_descriptor *app) {
printf("lkboot: init\n");
/* run the main lkserver loop */
printf("lkboot: starting network server\n");
lk_time_t t = current_time();
for (;;) {
tcp_socket_t *s;
if (vmm_alloc_contiguous(vmm_get_kernel_aspace(), "lkboot_iobuf",
lkb_iobuffer_size, &lkb_iobuffer, log2_uint(16*1024*1024), 0,
ARCH_MMU_FLAG_UNCACHED) < 0) {
goto fail_alloc;
}
if (arch_mmu_query((u32) lkb_iobuffer, &lkb_iobuffer_phys, NULL) < 0) {
goto fail_alloc;
}
printf("lkboot: iobuffer %p (phys 0x%lx)\n", lkb_iobuffer, lkb_iobuffer_phys);
/* calculate how much longer we will wait */
lk_time_t timeout = INFINITE_TIME;
if (!wait_forever) {
timeout = current_time() - t;
if (timeout >= LKBOOT_SERVER_TIMEOUT)
break;
timeout = LKBOOT_SERVER_TIMEOUT - timeout;
}
thread_detach_and_resume(
thread_create("lkbootserver", &lkboot_server, NULL,
DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
return;
/* wait for a new connection */
if (tcp_accept_timeout(listen_socket, &s, timeout) < 0) {
continue;
}
fail_alloc:
printf("lkboot: failed to allocate iobuffer\n");
DEBUG_ASSERT(s);
/* handle the command and close it */
handle_txn(s);
tcp_close(s);
/* after the first command, stay in the server loop forever */
if (!wait_forever) {
wait_forever = true;
printf("lkboot: handled command, staying in server loop\n");
}
}
tcp_close(listen_socket);
printf("lkboot: network server timed out\n");
#endif
regboot:
printf("lkboot: trying to boot from flash...\n");
status_t err = do_flash_boot();
TRACEF("do_flash_boot returns %d\n", err);
#if LKBOOT_WITH_SERVER
if (err < 0) {
TRACEF("restarting network server\n");
wait_forever = true;
goto serverloop;
}
#endif
TRACEF("nothing to do, exiting\n");
}
APP_START(lkboot)
.init = lkboot_init,
.flags = 0,
.entry = lkboot_task,
.flags = 0,
APP_END
// vim: noexpandtab

View File

@@ -23,40 +23,40 @@
#pragma once
typedef struct {
unsigned char opcode;
unsigned char extra;
unsigned short length;
unsigned char opcode;
unsigned char extra;
unsigned short length;
} msg_hdr_t;
// unless otherwise specified, extra is always zero.
#define MSG_OKAY 0x00
#define MSG_OKAY 0x00
// length must be zero.
// server indicates command was successful.
#define MSG_FAIL 0xFF
#define MSG_FAIL 0xFF
// length may be nonzero, if so data is a human readable error message
// extra may be nonzero, if so it is a more specific error code
#define MSG_LOG 0xFE
#define MSG_LOG 0xFE
// data contains human readable log message from server
// server may issue these at any time
#define MSG_GO_AHEAD 0x01
#define MSG_GO_AHEAD 0x01
// length must be zero
// server indicates that command was valid and it is ready for data
// client should send MSG_SEND_DATA messages to transfer data
#define MSG_CMD 0x40
#define MSG_CMD 0x40
// length must be greater than zero
// data will contain an ascii command
// server may reject excessively large commands
#define MSG_SEND_DATA 0x41
#define MSG_SEND_DATA 0x41
// client sends data to server
// length is datalen -1 (to allow for full 64k chunks)
#define MSG_END_DATA 0x42
#define MSG_END_DATA 0x42
// client ends data stream
// server will then respond with MSG_OKAY or MSG_FAIL
@@ -78,5 +78,3 @@ typedef struct {
//
// C: MSG_CMD "reboot:0:"
// S: MSG_OKAY
// vim: noexpandtab