[app][lkboot] modularlize lkboot, add secondary DCC channel, remove large buffer
Change-Id: I5a59f06c909722fe7269aa0991da10fa1ea8196e
This commit is contained in:
@@ -32,8 +32,10 @@
|
||||
#include <arch.h>
|
||||
#include <err.h>
|
||||
#include <trace.h>
|
||||
#include <pow2.h>
|
||||
|
||||
#include <kernel/thread.h>
|
||||
#include <kernel/vm.h>
|
||||
|
||||
#include <lib/bio.h>
|
||||
#include <lib/bootargs.h>
|
||||
@@ -45,16 +47,13 @@
|
||||
|
||||
#if PLATFORM_ZYNQ
|
||||
#include <platform/fpga.h>
|
||||
#include <platform/zynq.h>
|
||||
#endif
|
||||
|
||||
#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;
|
||||
@@ -81,16 +80,63 @@ static int do_reboot(void *arg) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int do_boot(void *arg) {
|
||||
struct chainload_args {
|
||||
void *func;
|
||||
ulong args[4];
|
||||
};
|
||||
|
||||
static int chainload_thread(void *arg)
|
||||
{
|
||||
struct chainload_args *args = (struct chainload_args *)arg;
|
||||
|
||||
thread_sleep(250);
|
||||
|
||||
TRACEF("chain loading address %p, args 0x%lx 0x%lx 0x%lx 0x%lx\n",
|
||||
args->func, args->args[0], args->args[1], args->args[2], args->args[3]);
|
||||
arch_chain_load((void *)args->func, args->args[0], args->args[1], args->args[2], args->args[3]);
|
||||
|
||||
for (;;);
|
||||
}
|
||||
|
||||
static int do_boot(lkb_t *lkb, size_t len, const char **result)
|
||||
{
|
||||
LTRACEF("lkb %p, len %zu, result %p\n", lkb, len, result);
|
||||
|
||||
void *buf;
|
||||
paddr_t buf_phys;
|
||||
|
||||
if (vmm_alloc_contiguous(vmm_get_kernel_aspace(), "lkboot_iobuf",
|
||||
len, &buf, log2_uint(1024*1024), 0, ARCH_MMU_FLAG_UNCACHED) < 0) {
|
||||
*result = "not enough memory";
|
||||
return -1;
|
||||
}
|
||||
arch_mmu_query((vaddr_t)buf, &buf_phys, NULL);
|
||||
LTRACEF("iobuffer %p (phys 0x%lx)\n", buf, buf_phys);
|
||||
|
||||
if (lkb_read(lkb, buf, len)) {
|
||||
*result = "io error";
|
||||
// XXX free buffer here
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* construct a boot argument list */
|
||||
// XXX get memory smarter than this
|
||||
const size_t bootargs_size = 64*1024;
|
||||
const size_t bootargs_size = PAGE_SIZE;
|
||||
#if 0
|
||||
void *args = (void *)((uintptr_t)lkb_iobuffer + lkb_iobuffer_size - bootargs_size);
|
||||
paddr_t args_phys = lkb_iobuffer_phys + lkb_iobuffer_size - bootargs_size;
|
||||
#elif PLATFORM_ZYNQ
|
||||
/* grab the top page of sram */
|
||||
/* XXX do this better */
|
||||
paddr_t args_phys = SRAM_BASE + SRAM_SIZE - bootargs_size;
|
||||
void *args = paddr_to_kvaddr(args_phys);
|
||||
#else
|
||||
#error need better way
|
||||
#endif
|
||||
LTRACEF("boot args %p, phys 0x%lx, len %zu\n", args, args_phys, bootargs_size);
|
||||
|
||||
bootargs_start(args, bootargs_size);
|
||||
bootargs_add_command_line(args, bootargs_size, "what what");
|
||||
arch_clean_cache_range((vaddr_t)args, bootargs_size);
|
||||
|
||||
ulong lk_args[4];
|
||||
bootargs_generate_lk_arg_values(args_phys, lk_args);
|
||||
@@ -99,7 +145,7 @@ static int do_boot(void *arg) {
|
||||
|
||||
/* 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) {
|
||||
if (bootimage_open(buf, len, &bi) >= 0) {
|
||||
size_t len;
|
||||
|
||||
/* it's a bootimage */
|
||||
@@ -113,16 +159,26 @@ static int do_boot(void *arg) {
|
||||
size_t bootimage_size;
|
||||
bootimage_get_range(bi, NULL, &bootimage_size);
|
||||
|
||||
bootargs_add_bootimage_pointer(args, bootargs_size, "pmem", lkb_iobuffer_phys, bootimage_size);
|
||||
bootargs_add_bootimage_pointer(args, bootargs_size, "pmem", buf_phys, bootimage_size);
|
||||
}
|
||||
} else {
|
||||
/* raw image, just chain load it directly */
|
||||
TRACEF("raw image, chainloading\n");
|
||||
|
||||
ptr = lkb_iobuffer;
|
||||
ptr = buf;
|
||||
}
|
||||
|
||||
arch_chain_load((void *)ptr, lk_args[0], lk_args[1], lk_args[2], lk_args[3]);
|
||||
/* start a boot thread to complete the startup */
|
||||
static struct chainload_args cl_args;
|
||||
|
||||
cl_args.func = (void *)ptr;
|
||||
cl_args.args[0] = lk_args[0];
|
||||
cl_args.args[1] = lk_args[1];
|
||||
cl_args.args[2] = lk_args[2];
|
||||
cl_args.args[3] = lk_args[3];
|
||||
|
||||
thread_resume(thread_create("boot", &chainload_thread, &cl_args,
|
||||
DEFAULT_PRIORITY, DEFAULT_STACK_SIZE));
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -132,13 +188,26 @@ status_t do_flash_boot(void)
|
||||
{
|
||||
status_t err;
|
||||
|
||||
LTRACE_ENTRY;
|
||||
|
||||
/* construct a boot argument list */
|
||||
// XXX get memory smarter than this
|
||||
const size_t bootargs_size = 64*1024;
|
||||
const size_t bootargs_size = PAGE_SIZE;
|
||||
#if 0
|
||||
/* old code */
|
||||
void *args = (void *)((uintptr_t)lkb_iobuffer + lkb_iobuffer_size - bootargs_size);
|
||||
paddr_t args_phys = lkb_iobuffer_phys + lkb_iobuffer_size - bootargs_size;
|
||||
#elif PLATFORM_ZYNQ
|
||||
/* grab the top page of sram */
|
||||
paddr_t args_phys = SRAM_BASE + SRAM_SIZE - bootargs_size;
|
||||
void *args = paddr_to_kvaddr(args_phys);
|
||||
#else
|
||||
#error need better way
|
||||
#endif
|
||||
LTRACEF("boot args %p, phys 0x%lx, len %zu\n", args, args_phys, bootargs_size);
|
||||
|
||||
bootargs_start(args, bootargs_size);
|
||||
bootargs_add_command_line(args, bootargs_size, "what what");
|
||||
arch_clean_cache_range((vaddr_t)args, bootargs_size);
|
||||
|
||||
ulong lk_args[4];
|
||||
bootargs_generate_lk_arg_values(args_phys, lk_args);
|
||||
@@ -207,7 +276,7 @@ status_t do_flash_boot(void)
|
||||
}
|
||||
|
||||
// return NULL for success, error string for failure
|
||||
int lkb_handle_command(lkb_t *lkb, const char *cmd, const char *arg, unsigned len, const char **result)
|
||||
int lkb_handle_command(lkb_t *lkb, const char *cmd, const char *arg, size_t len, const char **result)
|
||||
{
|
||||
*result = NULL;
|
||||
|
||||
@@ -219,10 +288,6 @@ int lkb_handle_command(lkb_t *lkb, const char *cmd, const char *arg, unsigned le
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
@@ -254,25 +319,49 @@ int lkb_handle_command(lkb_t *lkb, const char *cmd, const char *arg, unsigned le
|
||||
*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";
|
||||
|
||||
void *buf = malloc(bdev->block_size);
|
||||
if (!buf) {
|
||||
*result = "memory allocation failed";
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t pos = 0;
|
||||
while (pos < len) {
|
||||
size_t toread = MIN(len - pos, bdev->block_size);
|
||||
|
||||
LTRACEF("offset %zu, toread %zu\n", pos, toread);
|
||||
|
||||
if (lkb_read(lkb, buf, toread)) {
|
||||
*result = "io error";
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (bio_write(bdev, buf, entry.offset + pos, toread) != (ssize_t)toread) {
|
||||
*result = "bio_write failed";
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
pos += toread;
|
||||
}
|
||||
|
||||
free(buf);
|
||||
}
|
||||
} else if (!strcmp(cmd, "remove")) {
|
||||
if (ptable_remove(arg) < 0) {
|
||||
@@ -281,25 +370,41 @@ int lkb_handle_command(lkb_t *lkb, const char *cmd, const char *arg, unsigned le
|
||||
}
|
||||
} else if (!strcmp(cmd, "fpga")) {
|
||||
#if PLATFORM_ZYNQ
|
||||
if (lkb_read(lkb, lkb_iobuffer, len)) {
|
||||
*result = "io error";
|
||||
void *buf = malloc(len);
|
||||
if (!buf) {
|
||||
*result = "error allocating buffer";
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* translate to physical address */
|
||||
paddr_t pa = kvaddr_to_paddr(buf);
|
||||
if (pa == 0) {
|
||||
*result = "error allocating buffer";
|
||||
free(buf);
|
||||
return -1;
|
||||
|
||||
}
|
||||
|
||||
if (lkb_read(lkb, buf, len)) {
|
||||
*result = "io error";
|
||||
free(buf);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* make sure the cache is flushed for this buffer for DMA coherency purposes */
|
||||
arch_clean_cache_range((vaddr_t)buf, len);
|
||||
|
||||
/* program the fpga */
|
||||
zynq_reset_fpga();
|
||||
zynq_program_fpga(lkb_iobuffer_phys, len);
|
||||
*result = NULL;
|
||||
zynq_program_fpga(pa, len);
|
||||
|
||||
free(buf);
|
||||
#else
|
||||
*result = "no fpga";
|
||||
return -1;
|
||||
#endif
|
||||
} 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));
|
||||
return do_boot(lkb, len, result);
|
||||
} else if (!strcmp(cmd, "getsysparam")) {
|
||||
const void *ptr;
|
||||
size_t len;
|
||||
|
||||
259
app/lkboot/dcc.c
Normal file
259
app/lkboot/dcc.c
Normal file
@@ -0,0 +1,259 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#include "lkboot.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <debug.h>
|
||||
#include <string.h>
|
||||
#include <compiler.h>
|
||||
#include <err.h>
|
||||
#include <assert.h>
|
||||
#include <trace.h>
|
||||
#include <stdlib.h>
|
||||
#include <lib/cbuf.h>
|
||||
#include <app/lkboot.h>
|
||||
#include <arch/arm/dcc.h>
|
||||
#include <arch/mmu.h>
|
||||
#include <kernel/mutex.h>
|
||||
|
||||
#include "pdcc.h"
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
static struct pdcc_buffer_descriptor buffer_desc __ALIGNED(256);
|
||||
static paddr_t buffer_desc_phys;
|
||||
|
||||
#define DCC_BUFLEN 256
|
||||
|
||||
static uint8_t htod_buffer[DCC_BUFLEN] __ALIGNED(CACHE_LINE);
|
||||
static uint8_t dtoh_buffer[DCC_BUFLEN] __ALIGNED(CACHE_LINE);
|
||||
|
||||
static uint htod_index;
|
||||
static uint htod_pos;
|
||||
static bool dtoh_filled;
|
||||
|
||||
static void send_pdcc_command(uint32_t opcode, uint32_t data)
|
||||
{
|
||||
uint32_t word;
|
||||
|
||||
word = PDCC_VALID |
|
||||
((opcode & 0x7f) << PDCC_OPCODE_SHIFT) |
|
||||
(data & 0x00ffffff);
|
||||
|
||||
// XXX may block forever
|
||||
LTRACEF("sending 0x%x\n", word);
|
||||
arm_dcc_write(&word, 1, INFINITE_TIME);
|
||||
}
|
||||
|
||||
static void send_buffer_header(void)
|
||||
{
|
||||
send_pdcc_command(PDCC_OP_BUF_HEADER, buffer_desc_phys / 256);
|
||||
}
|
||||
|
||||
static void send_reset(void)
|
||||
{
|
||||
send_pdcc_command(PDCC_OP_RESET, 0);
|
||||
}
|
||||
|
||||
static void send_out_index_update(uint32_t index)
|
||||
{
|
||||
send_pdcc_command(PDCC_OP_UPDATE_OUT_INDEX, index);
|
||||
}
|
||||
|
||||
static void send_buffer_consumed(void)
|
||||
{
|
||||
send_pdcc_command(PDCC_OP_CONSUMED_IN, 0);
|
||||
}
|
||||
|
||||
#define DCC_PROCESS_RESET 1
|
||||
static int dcc_process_opcode(uint32_t word)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
if (word & PDCC_VALID) {
|
||||
uint32_t opcode = PDCC_OPCODE(word);
|
||||
uint32_t data = PDCC_DATA(word);
|
||||
LTRACEF("word 0x%x, opcode 0x%x, data 0x%x\n", word, opcode, data);
|
||||
switch (opcode) {
|
||||
case PDCC_OP_RESET:
|
||||
htod_index = 0;
|
||||
htod_pos = 0;
|
||||
dtoh_filled = false;
|
||||
|
||||
// try to send the buffer header
|
||||
send_buffer_header();
|
||||
ret = DCC_PROCESS_RESET;
|
||||
break;
|
||||
case PDCC_OP_BUF_HEADER:
|
||||
// we shouldn't get this
|
||||
break;
|
||||
|
||||
case PDCC_OP_UPDATE_OUT_INDEX:
|
||||
if (data > DCC_BUFLEN) {
|
||||
// out of range
|
||||
send_reset();
|
||||
} else {
|
||||
htod_index = data;
|
||||
htod_pos = 0;
|
||||
arch_invalidate_cache_range((vaddr_t)htod_buffer, DCC_BUFLEN);
|
||||
}
|
||||
break;
|
||||
|
||||
case PDCC_OP_CONSUMED_IN:
|
||||
arch_invalidate_cache_range((vaddr_t)dtoh_buffer, DCC_BUFLEN);
|
||||
dtoh_filled = false;
|
||||
break;
|
||||
default:
|
||||
TRACEF("bad opcode from host 0x%x\n", opcode);
|
||||
send_reset();
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static ssize_t dcc_read(void *unused, void *_data, size_t len)
|
||||
{
|
||||
unsigned char *data = _data;
|
||||
size_t pos = 0;
|
||||
uint32_t dcc;
|
||||
|
||||
LTRACEF("buf %p, len %zu, htod_pos %u, htod_index %u\n", _data, len, htod_pos, htod_index);
|
||||
|
||||
lk_time_t timeout = 0; // first dcc command should be with no timeout
|
||||
while (pos < len) {
|
||||
// process a dcc command
|
||||
ssize_t err = arm_dcc_read(&dcc, 1, timeout);
|
||||
if (err > 0) {
|
||||
err = dcc_process_opcode(dcc);
|
||||
if (err == DCC_PROCESS_RESET) {
|
||||
return ERR_IO;
|
||||
}
|
||||
}
|
||||
|
||||
// see if there is any data in the incoming buffer
|
||||
if (htod_index > 0) {
|
||||
size_t tocopy = MIN(htod_index - htod_pos, len - pos);
|
||||
|
||||
memcpy(&data[pos], &htod_buffer[htod_pos], tocopy);
|
||||
pos += tocopy;
|
||||
htod_pos += tocopy;
|
||||
|
||||
// if we consumed everything, tell the host we're done with the buffer
|
||||
if (htod_pos == htod_index) {
|
||||
send_buffer_consumed();
|
||||
htod_index = 0;
|
||||
htod_pos = 0;
|
||||
arch_invalidate_cache_range((vaddr_t)htod_buffer, DCC_BUFLEN);
|
||||
}
|
||||
}
|
||||
|
||||
timeout = 1000;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t dcc_write(void *unused, const void *_data, size_t len)
|
||||
{
|
||||
const unsigned char *data = _data;
|
||||
size_t pos = 0;
|
||||
|
||||
LTRACEF("buf %p, len %zu\n", _data, len);
|
||||
|
||||
while (pos < len) {
|
||||
LTRACEF("pos %zu, len %zu, dtoh_filled %d\n", pos, len, dtoh_filled);
|
||||
if (!dtoh_filled) {
|
||||
// put as much data as we can in the outgoing buffer
|
||||
size_t tocopy = MIN(len, DCC_BUFLEN);
|
||||
|
||||
LTRACEF("tocopy %zu\n", tocopy);
|
||||
memcpy(dtoh_buffer, data, tocopy);
|
||||
arch_clean_cache_range((vaddr_t)dtoh_buffer, DCC_BUFLEN);
|
||||
send_out_index_update(tocopy);
|
||||
dtoh_filled = true;
|
||||
|
||||
pos += tocopy;
|
||||
}
|
||||
|
||||
// process a dcc command
|
||||
uint32_t dcc;
|
||||
ssize_t err = arm_dcc_read(&dcc, 1, 1000);
|
||||
if (err > 0) {
|
||||
err = dcc_process_opcode(dcc);
|
||||
if (err == DCC_PROCESS_RESET) {
|
||||
return ERR_IO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pos;
|
||||
}
|
||||
|
||||
lkb_t *lkboot_check_dcc_open(void)
|
||||
{
|
||||
lkb_t *lkb = NULL;
|
||||
|
||||
// read a dcc op and process it
|
||||
{
|
||||
uint32_t dcc;
|
||||
ssize_t err = arm_dcc_read(&dcc, 1, 0);
|
||||
if (err > 0) {
|
||||
err = dcc_process_opcode(dcc);
|
||||
}
|
||||
}
|
||||
|
||||
if (htod_index > 0) {
|
||||
// we have data, construct a lkb and return it
|
||||
LTRACEF("we have data on dcc, starting command handler\n");
|
||||
lkb = lkboot_create_lkb(NULL, dcc_read, dcc_write);
|
||||
}
|
||||
|
||||
return lkb;
|
||||
}
|
||||
|
||||
void lkboot_dcc_init(void)
|
||||
{
|
||||
paddr_t pa;
|
||||
status_t err;
|
||||
|
||||
buffer_desc.version = PDCC_VERSION;
|
||||
|
||||
err = arch_mmu_query((vaddr_t)htod_buffer, &pa, NULL);
|
||||
DEBUG_ASSERT(err == NO_ERROR);
|
||||
|
||||
buffer_desc.htod_buffer_phys = pa;
|
||||
buffer_desc.htod_buffer_len = DCC_BUFLEN;
|
||||
|
||||
err = arch_mmu_query((vaddr_t)dtoh_buffer, &pa, NULL);
|
||||
DEBUG_ASSERT(err == NO_ERROR);
|
||||
|
||||
buffer_desc.dtoh_buffer_phys = pa;
|
||||
buffer_desc.dtoh_buffer_len = DCC_BUFLEN;
|
||||
|
||||
err = arch_mmu_query((vaddr_t)&buffer_desc, &buffer_desc_phys, NULL);
|
||||
DEBUG_ASSERT(err == NO_ERROR);
|
||||
|
||||
arch_clean_cache_range((vaddr_t)&buffer_desc, sizeof(buffer_desc));
|
||||
}
|
||||
|
||||
66
app/lkboot/inet.c
Normal file
66
app/lkboot/inet.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#if WITH_LIB_MINIP
|
||||
#include <app.h>
|
||||
|
||||
#include <platform.h>
|
||||
#include <stdio.h>
|
||||
#include <debug.h>
|
||||
#include <string.h>
|
||||
#include <pow2.h>
|
||||
#include <err.h>
|
||||
#include <assert.h>
|
||||
#include <trace.h>
|
||||
|
||||
#include <app/lkboot.h>
|
||||
|
||||
#include "lkboot.h"
|
||||
|
||||
#include <lib/minip.h>
|
||||
|
||||
#define LOCAL_TRACE 0
|
||||
|
||||
static ssize_t tcp_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;
|
||||
}
|
||||
|
||||
lkb_t *lkboot_tcp_opened(void *s)
|
||||
{
|
||||
lkb_t *lkb;
|
||||
|
||||
lkb = lkboot_create_lkb(s, tcp_readx, (void *)tcp_write);
|
||||
if (!lkb)
|
||||
return NULL;
|
||||
|
||||
return lkb;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -21,6 +21,8 @@
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "lkboot.h"
|
||||
|
||||
#include <app.h>
|
||||
|
||||
#include <platform.h>
|
||||
@@ -38,23 +40,15 @@
|
||||
#include <kernel/vm.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_WITH_SERVER 1
|
||||
#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;
|
||||
|
||||
#define STATE_OPEN 0
|
||||
#define STATE_DATA 1
|
||||
#define STATE_RESP 2
|
||||
@@ -62,23 +56,27 @@ size_t lkb_iobuffer_size = 16*1024*1024;
|
||||
#define STATE_ERROR 4
|
||||
|
||||
typedef struct LKB {
|
||||
tcp_socket_t *s;
|
||||
lkb_read_hook *read;
|
||||
lkb_write_hook *write;
|
||||
|
||||
void *cookie;
|
||||
|
||||
int state;
|
||||
size_t avail;
|
||||
} lkb_t;
|
||||
|
||||
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);
|
||||
lkb_t *lkboot_create_lkb(void *cookie, lkb_read_hook *read, lkb_write_hook *write) {
|
||||
lkb_t *lkb = malloc(sizeof(lkb_t));
|
||||
if (!lkb)
|
||||
return NULL;
|
||||
|
||||
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;
|
||||
lkb->cookie = cookie;
|
||||
lkb->state = STATE_OPEN;
|
||||
lkb->avail = 0;
|
||||
lkb->read = read;
|
||||
lkb->write = write;
|
||||
|
||||
return lkb;
|
||||
}
|
||||
|
||||
static int lkb_send(lkb_t *lkb, u8 opcode, const void *data, size_t len) {
|
||||
@@ -116,12 +114,12 @@ static int lkb_send(lkb_t *lkb, u8 opcode, const void *data, size_t len) {
|
||||
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)) {
|
||||
if (lkb->write(lkb->cookie, &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)) {
|
||||
if (len && (lkb->write(lkb->cookie, data, len) != (ssize_t)len)) {
|
||||
printf("xmit data fail\n");
|
||||
lkb->state = STATE_ERROR;
|
||||
return -1;
|
||||
@@ -146,7 +144,6 @@ int lkb_write(lkb_t *lkb, const void *_data, size_t len) {
|
||||
int lkb_read(lkb_t *lkb, void *_data, size_t len) {
|
||||
char *data = _data;
|
||||
|
||||
printf("lkb_read %d\n", len);
|
||||
if (lkb->state == STATE_RESP) {
|
||||
return 0;
|
||||
}
|
||||
@@ -156,7 +153,7 @@ int lkb_read(lkb_t *lkb, void *_data, size_t len) {
|
||||
while (len > 0) {
|
||||
if (lkb->avail == 0) {
|
||||
msg_hdr_t hdr;
|
||||
if (readx(lkb->s, &hdr, sizeof(hdr))) goto fail;
|
||||
if (lkb->read(lkb->cookie, &hdr, sizeof(hdr))) goto fail;
|
||||
if (hdr.opcode == MSG_END_DATA) {
|
||||
lkb->state = STATE_RESP;
|
||||
return -1;
|
||||
@@ -165,11 +162,11 @@ int lkb_read(lkb_t *lkb, void *_data, size_t len) {
|
||||
lkb->avail = ((size_t) hdr.length) + 1;
|
||||
}
|
||||
if (lkb->avail >= len) {
|
||||
if (readx(lkb->s, data, len)) goto fail;
|
||||
if (lkb->read(lkb->cookie, data, len)) goto fail;
|
||||
lkb->avail -= len;
|
||||
return 0;
|
||||
}
|
||||
if (readx(lkb->s, data, lkb->avail)) {
|
||||
if (lkb->read(lkb->cookie, data, lkb->avail)) {
|
||||
lkb->state = STATE_ERROR;
|
||||
return -1;
|
||||
}
|
||||
@@ -184,120 +181,126 @@ fail:
|
||||
return -1;
|
||||
}
|
||||
|
||||
static status_t handle_txn(tcp_socket_t *s)
|
||||
status_t lkboot_process_command(lkb_t *lkb)
|
||||
{
|
||||
msg_hdr_t hdr;
|
||||
lkb_t lkb;
|
||||
char cmd[128];
|
||||
char *arg;
|
||||
int err;
|
||||
const char *result;
|
||||
unsigned len;
|
||||
|
||||
if (readx(s, &hdr, sizeof(hdr))) goto fail;
|
||||
if (lkb->read(lkb->cookie, &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;
|
||||
if (lkb->read(lkb->cookie, cmd, hdr.length)) goto fail;
|
||||
cmd[hdr.length] = 0;
|
||||
|
||||
printf("lkboot: recv '%s'\n", cmd);
|
||||
TRACEF("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);
|
||||
|
||||
err = lkb_handle_command(lkb, cmd, arg, len, &result);
|
||||
if (err >= 0) {
|
||||
lkb_okay(&lkb);
|
||||
lkb_okay(lkb);
|
||||
} else {
|
||||
lkb_fail(&lkb, result);
|
||||
lkb_fail(lkb, result);
|
||||
}
|
||||
|
||||
TRACEF("command handled with success\n");
|
||||
return NO_ERROR;
|
||||
|
||||
fail:
|
||||
tcp_close(s);
|
||||
TRACEF("command failed\n");
|
||||
return ERR_IO;
|
||||
}
|
||||
|
||||
static status_t lkboot_server(bool wait_forever)
|
||||
{
|
||||
lkboot_dcc_init();
|
||||
|
||||
#if WITH_LIB_MINIP
|
||||
/* open the server's socket */
|
||||
tcp_socket_t *listen_socket = NULL;
|
||||
if (tcp_open_listen(&listen_socket, 1023) < 0) {
|
||||
printf("lkboot: error opening listen socket\n");
|
||||
return ERR_NO_MEMORY;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* run the main lkserver loop */
|
||||
printf("lkboot: starting server\n");
|
||||
lk_time_t t = current_time(); /* remember when we started */
|
||||
for (;;) {
|
||||
bool handled_command = false;
|
||||
|
||||
lkb_t *lkb;
|
||||
|
||||
#if WITH_LIB_MINIP
|
||||
/* wait for a new connection */
|
||||
lk_time_t timeout = 100;
|
||||
tcp_socket_t *s;
|
||||
if (tcp_accept_timeout(listen_socket, &s, timeout) >= 0) {
|
||||
DEBUG_ASSERT(s);
|
||||
|
||||
/* handle the command and close it */
|
||||
lkb = lkboot_tcp_opened(s);
|
||||
lkboot_process_command(lkb);
|
||||
free(lkb);
|
||||
tcp_close(s);
|
||||
handled_command = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* check if anything is coming in on dcc */
|
||||
lkb = lkboot_check_dcc_open();
|
||||
if (lkb) {
|
||||
lkboot_process_command(lkb);
|
||||
free(lkb);
|
||||
handled_command = true;
|
||||
}
|
||||
|
||||
/* after the first command, stay in the server loop forever */
|
||||
if (handled_command && !wait_forever) {
|
||||
wait_forever = true;
|
||||
printf("lkboot: handled command, staying in server loop\n");
|
||||
}
|
||||
|
||||
/* see if we need to drop out and try to direct boot */
|
||||
if (!wait_forever) {
|
||||
if (current_time() - t >= LKBOOT_SERVER_TIMEOUT) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if WITH_LIB_MINIP
|
||||
tcp_close(listen_socket);
|
||||
#endif
|
||||
|
||||
printf("lkboot: server timed out\n");
|
||||
|
||||
return ERR_TIMED_OUT;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
// 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);
|
||||
|
||||
serverloop:
|
||||
/* open the server's socket */
|
||||
if (tcp_open_listen(&listen_socket, 1023) < 0) {
|
||||
printf("lkboot: error opening listen socket\n");
|
||||
goto regboot;
|
||||
}
|
||||
|
||||
/* run the main lkserver loop */
|
||||
printf("lkboot: starting network server\n");
|
||||
lk_time_t t = current_time();
|
||||
for (;;) {
|
||||
tcp_socket_t *s;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* wait for a new connection */
|
||||
if (tcp_accept_timeout(listen_socket, &s, timeout) < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
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");
|
||||
lkboot_server(false);
|
||||
#endif
|
||||
|
||||
regboot:
|
||||
printf("lkboot: trying to boot from flash...\n");
|
||||
|
||||
TRACEF("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;
|
||||
TRACEF("restarting server\n");
|
||||
lkboot_server(true);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Brian Swetland
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
@@ -22,59 +22,26 @@
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
unsigned char opcode;
|
||||
unsigned char extra;
|
||||
unsigned short length;
|
||||
} msg_hdr_t;
|
||||
#include <sys/types.h>
|
||||
#include <app/lkboot.h>
|
||||
#include "lkboot_protocol.h"
|
||||
|
||||
// unless otherwise specified, extra is always zero.
|
||||
/* private to lkboot app */
|
||||
|
||||
#define MSG_OKAY 0x00
|
||||
// length must be zero.
|
||||
// server indicates command was successful.
|
||||
int lkb_handle_command(lkb_t *lkb, const char *cmd, const char *arg, size_t len, const char **result);
|
||||
|
||||
#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
|
||||
status_t do_flash_boot(void);
|
||||
|
||||
#define MSG_LOG 0xFE
|
||||
// data contains human readable log message from server
|
||||
// server may issue these at any time
|
||||
typedef ssize_t lkb_read_hook(void *s, void *data, size_t len);
|
||||
typedef ssize_t lkb_write_hook(void *s, const void *data, size_t len);
|
||||
|
||||
#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
|
||||
lkb_t *lkboot_create_lkb(void *cookie, lkb_read_hook *read, lkb_write_hook *write);
|
||||
status_t lkboot_process_command(lkb_t *);
|
||||
|
||||
#define MSG_CMD 0x40
|
||||
// length must be greater than zero
|
||||
// data will contain an ascii command
|
||||
// server may reject excessively large commands
|
||||
/* inet server */
|
||||
lkb_t *lkboot_tcp_opened(void *s);
|
||||
|
||||
#define MSG_SEND_DATA 0x41
|
||||
// client sends data to server
|
||||
// length is datalen -1 (to allow for full 64k chunks)
|
||||
/* dcc based server */
|
||||
void lkboot_dcc_init(void);
|
||||
lkb_t *lkboot_check_dcc_open(void);
|
||||
|
||||
#define MSG_END_DATA 0x42
|
||||
// client ends data stream
|
||||
// server will then respond with MSG_OKAY or MSG_FAIL
|
||||
|
||||
// command strings are in the form of
|
||||
// <command> ':' <decimal-datalen> ':' <optional-arguments>
|
||||
|
||||
// example:
|
||||
// C: MSG_CMD "flash:32768:bootloader"
|
||||
// S: MSG_GO_AHEAD
|
||||
// C: MSG_SEND_DATA 16384 ...
|
||||
// C: MSG_SEND_DATA 16384 ...
|
||||
// C: MSG_END_DATA
|
||||
// S: MSG_LOG "erasing sectors"
|
||||
// S: MSG_LOG "writing sectors"
|
||||
// S: MSG_OKAY
|
||||
//
|
||||
// C: MSG_CMD "eraese:0:bootloader"
|
||||
// S: MSG_FAIL "unknown command 'eraese'"
|
||||
//
|
||||
// C: MSG_CMD "reboot:0:"
|
||||
// S: MSG_OKAY
|
||||
|
||||
80
app/lkboot/lkboot_protocol.h
Normal file
80
app/lkboot/lkboot_protocol.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright (c) 2014 Brian Swetland
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
typedef struct {
|
||||
unsigned char opcode;
|
||||
unsigned char extra;
|
||||
unsigned short length;
|
||||
} msg_hdr_t;
|
||||
|
||||
// unless otherwise specified, extra is always zero.
|
||||
|
||||
#define MSG_OKAY 0x00
|
||||
// length must be zero.
|
||||
// server indicates command was successful.
|
||||
|
||||
#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
|
||||
// data contains human readable log message from server
|
||||
// server may issue these at any time
|
||||
|
||||
#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
|
||||
// length must be greater than zero
|
||||
// data will contain an ascii command
|
||||
// server may reject excessively large commands
|
||||
|
||||
#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
|
||||
// client ends data stream
|
||||
// server will then respond with MSG_OKAY or MSG_FAIL
|
||||
|
||||
// command strings are in the form of
|
||||
// <command> ':' <decimal-datalen> ':' <optional-arguments>
|
||||
|
||||
// example:
|
||||
// C: MSG_CMD "flash:32768:bootloader"
|
||||
// S: MSG_GO_AHEAD
|
||||
// C: MSG_SEND_DATA 16384 ...
|
||||
// C: MSG_SEND_DATA 16384 ...
|
||||
// C: MSG_END_DATA
|
||||
// S: MSG_LOG "erasing sectors"
|
||||
// S: MSG_LOG "writing sectors"
|
||||
// S: MSG_OKAY
|
||||
//
|
||||
// C: MSG_CMD "eraese:0:bootloader"
|
||||
// S: MSG_FAIL "unknown command 'eraese'"
|
||||
//
|
||||
// C: MSG_CMD "reboot:0:"
|
||||
// S: MSG_OKAY
|
||||
53
app/lkboot/pdcc.h
Normal file
53
app/lkboot/pdcc.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Travis Geiselbrecht
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files
|
||||
* (the "Software"), to deal in the Software without restriction,
|
||||
* including without limitation the rights to use, copy, modify, merge,
|
||||
* publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
* and to permit persons to whom the Software is furnished to do so,
|
||||
* subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be
|
||||
* included in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/* in memory and DCC descriptors for the PDCC protocol */
|
||||
|
||||
/* shared outside of lk repository, be careful of modifications */
|
||||
#define PDCC_VERSION 1
|
||||
|
||||
struct pdcc_buffer_descriptor {
|
||||
uint32_t version;
|
||||
|
||||
uint32_t htod_buffer_phys;
|
||||
uint32_t htod_buffer_len;
|
||||
|
||||
uint32_t dtoh_buffer_phys;
|
||||
uint32_t dtoh_buffer_len;
|
||||
};
|
||||
|
||||
#define PDCC_VALID (1<<31)
|
||||
#define PDCC_OPCODE_SHIFT (24)
|
||||
#define PDCC_OPCODE(x) (((x) >> PDCC_OPCODE_SHIFT) & 0x7f)
|
||||
#define PDCC_DATA(x) ((x) & 0x00ffffff);
|
||||
|
||||
enum {
|
||||
PDCC_OP_RESET = 0,
|
||||
PDCC_OP_BUF_HEADER,
|
||||
PDCC_OP_UPDATE_OUT_INDEX,
|
||||
PDCC_OP_CONSUMED_IN,
|
||||
};
|
||||
|
||||
@@ -6,12 +6,15 @@ MODULE_DEPS += \
|
||||
lib/bio \
|
||||
lib/bootargs \
|
||||
lib/bootimage \
|
||||
lib/cbuf \
|
||||
lib/ptable \
|
||||
lib/sysparam
|
||||
|
||||
MODULE_SRCS += \
|
||||
$(LOCAL_DIR)/commands.c \
|
||||
$(LOCAL_DIR)/dcc.c \
|
||||
$(LOCAL_DIR)/inet.c \
|
||||
$(LOCAL_DIR)/lkboot.c \
|
||||
$(LOCAL_DIR)/commands.c
|
||||
|
||||
GLOBAL_INCLUDES += $(LOCAL_DIR)/include
|
||||
|
||||
|
||||
Reference in New Issue
Block a user