2015-04-22 01:31:31 +08:00
|
|
|
#include <string.h>
|
2015-04-28 01:31:55 +08:00
|
|
|
#include <stdio.h>
|
2015-04-22 01:31:31 +08:00
|
|
|
#include <stdarg.h>
|
2015-12-11 22:55:40 +08:00
|
|
|
#include <id.h>
|
2015-04-22 01:31:31 +08:00
|
|
|
|
|
|
|
#include <generated/csr.h>
|
|
|
|
|
|
|
|
#include "mailbox.h"
|
|
|
|
#include "messages.h"
|
|
|
|
|
2015-04-29 12:58:37 +08:00
|
|
|
#include "clock.h"
|
2015-04-22 01:31:31 +08:00
|
|
|
#include "log.h"
|
|
|
|
#include "kloader.h"
|
2015-08-02 11:41:05 +08:00
|
|
|
#include "artiq_personality.h"
|
2015-05-07 23:47:48 +08:00
|
|
|
#include "flash_storage.h"
|
2015-07-28 00:19:07 +08:00
|
|
|
#include "rtiocrg.h"
|
2015-07-25 16:26:04 +08:00
|
|
|
#include "session.h"
|
2015-04-22 01:31:31 +08:00
|
|
|
|
2016-01-08 02:29:35 +08:00
|
|
|
// 2.5MiB in payload + 1KiB for headers.
|
|
|
|
// We need more than 1MiB to send a 1MiB list due to tags;
|
|
|
|
// about 5/4MiB for an 1MiB int32 list, 9/8MiB for an 1MiB int64 list.
|
|
|
|
#define BUFFER_SIZE (2560*1024 + 1024)
|
|
|
|
#define BUFFER_IN_SIZE BUFFER_SIZE
|
|
|
|
#define BUFFER_OUT_SIZE BUFFER_SIZE
|
2015-04-22 01:31:31 +08:00
|
|
|
|
2015-08-08 18:21:43 +08:00
|
|
|
static int process_input();
|
|
|
|
static int out_packet_available();
|
|
|
|
|
|
|
|
// ============================= Reader interface =============================
|
|
|
|
|
|
|
|
// Align the 9th byte (right after the header) of buffer_in so that
|
|
|
|
// the payload can be deserialized directly from the buffer using word reads.
|
2015-04-22 01:31:31 +08:00
|
|
|
static struct {
|
|
|
|
char padding[3];
|
2015-08-08 18:21:43 +08:00
|
|
|
union {
|
|
|
|
char data[BUFFER_IN_SIZE];
|
|
|
|
struct {
|
|
|
|
int32_t sync;
|
|
|
|
int32_t length;
|
|
|
|
int8_t type;
|
|
|
|
} __attribute__((packed)) header;
|
|
|
|
};
|
|
|
|
} __attribute__((packed, aligned(4))) buffer_in;
|
|
|
|
|
|
|
|
static int buffer_in_write_cursor, buffer_in_read_cursor;
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static void in_packet_reset()
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
buffer_in_write_cursor = 0;
|
|
|
|
buffer_in_read_cursor = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int in_packet_fill(uint8_t *data, int length)
|
2015-04-22 01:31:31 +08:00
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
int consumed = 0;
|
|
|
|
while(consumed < length) {
|
|
|
|
/* Make sure the output buffer is available for any reply
|
|
|
|
* we might need to send. */
|
|
|
|
if(!out_packet_available())
|
|
|
|
break;
|
|
|
|
|
|
|
|
if(buffer_in_write_cursor < 4) {
|
|
|
|
/* Haven't received the synchronization sequence yet. */
|
|
|
|
buffer_in.data[buffer_in_write_cursor++] = data[consumed];
|
|
|
|
|
|
|
|
/* Framing error? */
|
|
|
|
if(data[consumed++] != 0x5a) {
|
|
|
|
buffer_in_write_cursor = 0;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else if(buffer_in_write_cursor < 8) {
|
|
|
|
/* Haven't received the packet length yet. */
|
|
|
|
buffer_in.data[buffer_in_write_cursor++] = data[consumed++];
|
|
|
|
} else if(buffer_in.header.length == 0) {
|
|
|
|
/* Zero-length packet means session reset. */
|
|
|
|
return -2;
|
|
|
|
} else if(buffer_in.header.length > BUFFER_IN_SIZE) {
|
|
|
|
/* Packet wouldn't fit in the buffer. */
|
|
|
|
return -1;
|
|
|
|
} else if(buffer_in.header.length > buffer_in_write_cursor) {
|
|
|
|
/* Receiving payload. */
|
|
|
|
int remaining = buffer_in.header.length - buffer_in_write_cursor;
|
|
|
|
int amount = length - consumed > remaining ? remaining : length - consumed;
|
|
|
|
memcpy(&buffer_in.data[buffer_in_write_cursor], &data[consumed],
|
|
|
|
amount);
|
|
|
|
buffer_in_write_cursor += amount;
|
|
|
|
consumed += amount;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(buffer_in.header.length == buffer_in_write_cursor) {
|
|
|
|
/* We have a complete packet. */
|
2015-04-22 01:31:31 +08:00
|
|
|
|
2015-08-08 18:21:43 +08:00
|
|
|
buffer_in_read_cursor = sizeof(buffer_in.header);
|
|
|
|
if(!process_input())
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if(buffer_in_read_cursor < buffer_in_write_cursor) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("session.c: read underrun (%d bytes remaining)\n",
|
|
|
|
buffer_in_write_cursor - buffer_in_read_cursor);
|
2015-08-08 18:21:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
in_packet_reset();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return consumed;
|
2015-04-22 01:31:31 +08:00
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static void in_packet_chunk(void *ptr, int length)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
if(buffer_in_read_cursor + length > buffer_in_write_cursor) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("session.c: read overrun while trying to read %d bytes"
|
|
|
|
" (%d remaining)\n",
|
|
|
|
length, buffer_in_write_cursor - buffer_in_read_cursor);
|
2015-08-08 18:21:43 +08:00
|
|
|
}
|
2015-04-22 01:31:31 +08:00
|
|
|
|
2015-08-08 18:21:43 +08:00
|
|
|
if(ptr != NULL)
|
|
|
|
memcpy(ptr, &buffer_in.data[buffer_in_read_cursor], length);
|
|
|
|
buffer_in_read_cursor += length;
|
2015-04-22 01:31:31 +08:00
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static int8_t in_packet_int8()
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
int8_t result;
|
|
|
|
in_packet_chunk(&result, sizeof(result));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static int32_t in_packet_int32()
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
int32_t result;
|
|
|
|
in_packet_chunk(&result, sizeof(result));
|
|
|
|
return result;
|
2015-04-22 01:31:31 +08:00
|
|
|
}
|
|
|
|
|
2015-08-08 21:01:08 +08:00
|
|
|
static int64_t in_packet_int64()
|
|
|
|
{
|
|
|
|
int64_t result;
|
|
|
|
in_packet_chunk(&result, sizeof(result));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static const void *in_packet_bytes(int *length)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
*length = in_packet_int32();
|
|
|
|
const void *ptr = &buffer_in.data[buffer_in_read_cursor];
|
|
|
|
in_packet_chunk(NULL, *length);
|
|
|
|
return ptr;
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static const char *in_packet_string()
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
int length;
|
|
|
|
const char *string = in_packet_bytes(&length);
|
2015-08-10 01:17:00 +08:00
|
|
|
if(string[length - 1] != 0) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("session.c: string is not zero-terminated\n");
|
2015-08-08 18:21:43 +08:00
|
|
|
return "";
|
|
|
|
}
|
|
|
|
return string;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ============================= Writer interface =============================
|
|
|
|
|
|
|
|
static union {
|
|
|
|
char data[BUFFER_OUT_SIZE];
|
|
|
|
struct {
|
|
|
|
int32_t sync;
|
|
|
|
int32_t length;
|
|
|
|
int8_t type;
|
|
|
|
} __attribute__((packed)) header;
|
|
|
|
} buffer_out;
|
|
|
|
|
2015-08-08 19:06:11 +08:00
|
|
|
static int buffer_out_read_cursor, buffer_out_sent_cursor, buffer_out_write_cursor;
|
2015-08-08 18:21:43 +08:00
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static void out_packet_reset()
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
buffer_out_read_cursor = 0;
|
|
|
|
buffer_out_write_cursor = 0;
|
2015-08-08 19:06:11 +08:00
|
|
|
buffer_out_sent_cursor = 0;
|
2015-08-08 18:21:43 +08:00
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static int out_packet_available()
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
return buffer_out_write_cursor == 0;
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static void out_packet_extract(void **data, int *length)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
if(buffer_out_write_cursor > 0 &&
|
|
|
|
buffer_out.header.length > 0) {
|
|
|
|
*data = &buffer_out.data[buffer_out_read_cursor];
|
|
|
|
*length = buffer_out_write_cursor - buffer_out_read_cursor;
|
|
|
|
} else {
|
|
|
|
*length = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-08 19:06:11 +08:00
|
|
|
static void out_packet_advance_consumed(int length)
|
2015-08-08 18:48:25 +08:00
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
if(buffer_out_read_cursor + length > buffer_out_write_cursor) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("session.c: write underrun (consume) while trying to"
|
|
|
|
" acknowledge %d bytes (%d remaining)\n",
|
|
|
|
length, buffer_out_write_cursor - buffer_out_read_cursor);
|
2015-08-08 18:21:43 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer_out_read_cursor += length;
|
2015-08-08 19:06:11 +08:00
|
|
|
}
|
|
|
|
|
2015-12-18 00:13:22 +08:00
|
|
|
static void out_packet_advance_sent(int length)
|
|
|
|
{
|
2015-08-08 19:06:11 +08:00
|
|
|
if(buffer_out_sent_cursor + length > buffer_out_write_cursor) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("session.c: write underrun (send) while trying to"
|
|
|
|
" acknowledge %d bytes (%d remaining)\n",
|
|
|
|
length, buffer_out_write_cursor - buffer_out_sent_cursor);
|
2015-08-08 19:06:11 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer_out_sent_cursor += length;
|
|
|
|
if(buffer_out_sent_cursor == buffer_out_write_cursor)
|
2015-08-08 18:21:43 +08:00
|
|
|
out_packet_reset();
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static int out_packet_chunk(const void *ptr, int length)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
if(buffer_out_write_cursor + length > BUFFER_OUT_SIZE) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("session.c: write overrun while trying to write %d bytes"
|
|
|
|
" (%d remaining)\n",
|
|
|
|
length, BUFFER_OUT_SIZE - buffer_out_write_cursor);
|
2015-08-08 18:21:43 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&buffer_out.data[buffer_out_write_cursor], ptr, length);
|
|
|
|
buffer_out_write_cursor += length;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static void out_packet_start(int type)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
buffer_out.header.sync = 0x5a5a5a5a;
|
|
|
|
buffer_out.header.type = type;
|
|
|
|
buffer_out.header.length = 0;
|
|
|
|
buffer_out_write_cursor = sizeof(buffer_out.header);
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static void out_packet_finish()
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
buffer_out.header.length = buffer_out_write_cursor;
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static void out_packet_empty(int type)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
out_packet_start(type);
|
|
|
|
out_packet_finish();
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static int out_packet_int8(int8_t value)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
return out_packet_chunk(&value, sizeof(value));
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static int out_packet_int32(int32_t value)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
return out_packet_chunk(&value, sizeof(value));
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static int out_packet_int64(int64_t value)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
return out_packet_chunk(&value, sizeof(value));
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static int out_packet_float64(double value)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
return out_packet_chunk(&value, sizeof(value));
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static int out_packet_bytes(const void *ptr, int length)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
return out_packet_int32(length) &&
|
|
|
|
out_packet_chunk(ptr, length);
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:48:25 +08:00
|
|
|
static int out_packet_string(const char *string)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
return out_packet_bytes(string, strlen(string) + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// =============================== API handling ===============================
|
|
|
|
|
2015-04-22 01:31:31 +08:00
|
|
|
static int user_kernel_state;
|
|
|
|
|
|
|
|
enum {
|
|
|
|
USER_KERNEL_NONE = 0,
|
|
|
|
USER_KERNEL_LOADED,
|
|
|
|
USER_KERNEL_RUNNING,
|
|
|
|
USER_KERNEL_WAIT_RPC /* < must come after _RUNNING */
|
|
|
|
};
|
|
|
|
|
2015-10-31 23:26:09 +08:00
|
|
|
void session_startup_kernel(void)
|
|
|
|
{
|
|
|
|
struct msg_base *umsg;
|
|
|
|
|
|
|
|
watchdog_init();
|
|
|
|
if(!kloader_start_startup_kernel())
|
|
|
|
return;
|
|
|
|
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Startup kernel started\n");
|
2015-10-31 23:26:09 +08:00
|
|
|
while(1) {
|
|
|
|
kloader_service_essential_kmsg();
|
|
|
|
|
|
|
|
umsg = mailbox_receive();
|
|
|
|
if(umsg) {
|
|
|
|
if(!kloader_validate_kpointer(umsg))
|
|
|
|
break;
|
|
|
|
if(kloader_is_essential_kmsg(umsg->type))
|
|
|
|
continue;
|
|
|
|
if(umsg->type == MESSAGE_TYPE_FINISHED)
|
|
|
|
break;
|
|
|
|
else if(umsg->type == MESSAGE_TYPE_EXCEPTION) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("WARNING: startup kernel ended with exception\n");
|
2015-10-31 23:26:09 +08:00
|
|
|
break;
|
|
|
|
} else {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("ERROR: received invalid message type from kernel CPU\n");
|
2015-10-31 23:26:09 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(watchdog_expired()) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("WARNING: watchdog expired in startup kernel\n");
|
2015-10-31 23:26:09 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
kloader_stop();
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Startup kernel terminated\n");
|
2015-10-31 23:26:09 +08:00
|
|
|
}
|
|
|
|
|
2015-04-22 01:31:31 +08:00
|
|
|
void session_start(void)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
in_packet_reset();
|
|
|
|
out_packet_reset();
|
|
|
|
|
2015-05-09 17:11:34 +08:00
|
|
|
kloader_stop();
|
2015-08-08 18:21:43 +08:00
|
|
|
user_kernel_state = USER_KERNEL_NONE;
|
2015-04-22 01:31:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void session_end(void)
|
|
|
|
{
|
2015-05-09 17:11:34 +08:00
|
|
|
kloader_stop();
|
2015-10-31 23:26:09 +08:00
|
|
|
watchdog_init();
|
2015-04-22 01:31:31 +08:00
|
|
|
kloader_start_idle_kernel();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* host to device */
|
|
|
|
enum {
|
|
|
|
REMOTEMSG_TYPE_LOG_REQUEST = 1,
|
2015-08-28 13:37:46 +08:00
|
|
|
REMOTEMSG_TYPE_LOG_CLEAR,
|
|
|
|
|
2015-04-22 01:31:31 +08:00
|
|
|
REMOTEMSG_TYPE_IDENT_REQUEST,
|
|
|
|
REMOTEMSG_TYPE_SWITCH_CLOCK,
|
2015-08-02 11:41:05 +08:00
|
|
|
|
|
|
|
REMOTEMSG_TYPE_LOAD_LIBRARY,
|
2015-04-22 01:31:31 +08:00
|
|
|
REMOTEMSG_TYPE_RUN_KERNEL,
|
|
|
|
|
2015-05-07 23:47:48 +08:00
|
|
|
REMOTEMSG_TYPE_RPC_REPLY,
|
2015-08-08 21:01:08 +08:00
|
|
|
REMOTEMSG_TYPE_RPC_EXCEPTION,
|
2015-05-07 23:47:48 +08:00
|
|
|
|
|
|
|
REMOTEMSG_TYPE_FLASH_READ_REQUEST,
|
|
|
|
REMOTEMSG_TYPE_FLASH_WRITE_REQUEST,
|
|
|
|
REMOTEMSG_TYPE_FLASH_ERASE_REQUEST,
|
|
|
|
REMOTEMSG_TYPE_FLASH_REMOVE_REQUEST
|
2015-04-22 01:31:31 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
/* device to host */
|
|
|
|
enum {
|
|
|
|
REMOTEMSG_TYPE_LOG_REPLY = 1,
|
2015-08-28 13:37:46 +08:00
|
|
|
|
2015-04-22 01:31:31 +08:00
|
|
|
REMOTEMSG_TYPE_IDENT_REPLY,
|
|
|
|
REMOTEMSG_TYPE_CLOCK_SWITCH_COMPLETED,
|
|
|
|
REMOTEMSG_TYPE_CLOCK_SWITCH_FAILED,
|
|
|
|
|
|
|
|
REMOTEMSG_TYPE_LOAD_COMPLETED,
|
|
|
|
REMOTEMSG_TYPE_LOAD_FAILED,
|
|
|
|
|
|
|
|
REMOTEMSG_TYPE_KERNEL_FINISHED,
|
|
|
|
REMOTEMSG_TYPE_KERNEL_STARTUP_FAILED,
|
|
|
|
REMOTEMSG_TYPE_KERNEL_EXCEPTION,
|
|
|
|
|
|
|
|
REMOTEMSG_TYPE_RPC_REQUEST,
|
2015-05-07 23:47:48 +08:00
|
|
|
|
|
|
|
REMOTEMSG_TYPE_FLASH_READ_REPLY,
|
|
|
|
REMOTEMSG_TYPE_FLASH_OK_REPLY,
|
2016-03-19 06:29:42 +08:00
|
|
|
REMOTEMSG_TYPE_FLASH_ERROR_REPLY,
|
|
|
|
|
|
|
|
REMOTEMSG_TYPE_WATCHDOG_EXPIRED,
|
|
|
|
REMOTEMSG_TYPE_CLOCK_FAILURE,
|
2015-04-22 01:31:31 +08:00
|
|
|
};
|
|
|
|
|
2015-08-10 01:17:00 +08:00
|
|
|
static int receive_rpc_value(const char **tag, void **slot);
|
|
|
|
|
2015-04-22 01:31:31 +08:00
|
|
|
static int process_input(void)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
switch(buffer_in.header.type) {
|
2015-12-11 22:55:40 +08:00
|
|
|
case REMOTEMSG_TYPE_IDENT_REQUEST: {
|
|
|
|
char version[IDENT_SIZE];
|
|
|
|
|
|
|
|
get_ident(version);
|
|
|
|
|
2015-08-08 18:21:43 +08:00
|
|
|
out_packet_start(REMOTEMSG_TYPE_IDENT_REPLY);
|
|
|
|
out_packet_chunk("AROR", 4);
|
2015-12-11 22:55:40 +08:00
|
|
|
out_packet_chunk(version, strlen(version));
|
2015-08-08 18:21:43 +08:00
|
|
|
out_packet_finish();
|
2015-04-22 01:31:31 +08:00
|
|
|
break;
|
2015-12-11 22:55:40 +08:00
|
|
|
}
|
2015-08-08 18:21:43 +08:00
|
|
|
|
|
|
|
case REMOTEMSG_TYPE_SWITCH_CLOCK: {
|
|
|
|
int clk = in_packet_int8();
|
|
|
|
|
2015-04-22 01:31:31 +08:00
|
|
|
if(user_kernel_state >= USER_KERNEL_RUNNING) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Attempted to switch RTIO clock while kernel running\n");
|
2015-08-08 18:21:43 +08:00
|
|
|
out_packet_empty(REMOTEMSG_TYPE_CLOCK_SWITCH_FAILED);
|
2015-07-25 16:26:04 +08:00
|
|
|
break;
|
2015-04-22 01:31:31 +08:00
|
|
|
}
|
2015-08-08 18:21:43 +08:00
|
|
|
|
|
|
|
if(rtiocrg_switch_clock(clk))
|
|
|
|
out_packet_empty(REMOTEMSG_TYPE_CLOCK_SWITCH_COMPLETED);
|
2015-07-28 00:05:24 +08:00
|
|
|
else
|
2015-08-08 18:21:43 +08:00
|
|
|
out_packet_empty(REMOTEMSG_TYPE_CLOCK_SWITCH_FAILED);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case REMOTEMSG_TYPE_LOG_REQUEST:
|
|
|
|
#if (LOG_BUFFER_SIZE + 9) > BUFFER_OUT_SIZE
|
|
|
|
#error Output buffer cannot hold the log buffer
|
|
|
|
#endif
|
|
|
|
out_packet_start(REMOTEMSG_TYPE_LOG_REPLY);
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log_get(&buffer_out.data[buffer_out_write_cursor]);
|
2015-08-08 18:21:43 +08:00
|
|
|
buffer_out_write_cursor += LOG_BUFFER_SIZE;
|
|
|
|
out_packet_finish();
|
2015-04-22 01:31:31 +08:00
|
|
|
break;
|
2015-08-08 18:21:43 +08:00
|
|
|
|
2015-08-28 13:37:46 +08:00
|
|
|
case REMOTEMSG_TYPE_LOG_CLEAR:
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log_clear();
|
2015-08-28 13:37:46 +08:00
|
|
|
out_packet_empty(REMOTEMSG_TYPE_LOG_REPLY);
|
|
|
|
break;
|
|
|
|
|
2015-08-08 18:21:43 +08:00
|
|
|
case REMOTEMSG_TYPE_FLASH_READ_REQUEST: {
|
2015-12-04 15:57:39 +08:00
|
|
|
#if CONFIG_SPIFLASH_SECTOR_SIZE - 4 > BUFFER_OUT_SIZE - 9
|
2015-08-08 18:21:43 +08:00
|
|
|
#error Output buffer cannot hold the flash storage data
|
|
|
|
#endif
|
|
|
|
const char *key = in_packet_string();
|
|
|
|
int value_length;
|
|
|
|
|
|
|
|
out_packet_start(REMOTEMSG_TYPE_FLASH_READ_REPLY);
|
|
|
|
value_length = fs_read(key, &buffer_out.data[buffer_out_write_cursor],
|
|
|
|
sizeof(buffer_out.data) - buffer_out_write_cursor, NULL);
|
|
|
|
buffer_out_write_cursor += value_length;
|
|
|
|
out_packet_finish();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case REMOTEMSG_TYPE_FLASH_WRITE_REQUEST: {
|
2015-12-04 15:57:39 +08:00
|
|
|
#if CONFIG_SPIFLASH_SECTOR_SIZE - 4 > BUFFER_IN_SIZE - 9
|
2015-08-08 18:21:43 +08:00
|
|
|
#error Input buffer cannot hold the flash storage data
|
|
|
|
#endif
|
|
|
|
const char *key, *value;
|
|
|
|
int value_length;
|
|
|
|
key = in_packet_string();
|
|
|
|
value = in_packet_bytes(&value_length);
|
|
|
|
|
|
|
|
if(fs_write(key, value, value_length))
|
|
|
|
out_packet_empty(REMOTEMSG_TYPE_FLASH_OK_REPLY);
|
|
|
|
else
|
|
|
|
out_packet_empty(REMOTEMSG_TYPE_FLASH_ERROR_REPLY);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case REMOTEMSG_TYPE_FLASH_ERASE_REQUEST:
|
|
|
|
fs_erase();
|
|
|
|
out_packet_empty(REMOTEMSG_TYPE_FLASH_OK_REPLY);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REMOTEMSG_TYPE_FLASH_REMOVE_REQUEST: {
|
|
|
|
const char *key = in_packet_string();
|
|
|
|
|
|
|
|
fs_remove(key);
|
|
|
|
out_packet_empty(REMOTEMSG_TYPE_FLASH_OK_REPLY);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case REMOTEMSG_TYPE_LOAD_LIBRARY: {
|
|
|
|
const void *kernel = &buffer_in.data[buffer_in_read_cursor];
|
|
|
|
buffer_in_read_cursor = buffer_in_write_cursor;
|
|
|
|
|
2015-04-22 01:31:31 +08:00
|
|
|
if(user_kernel_state >= USER_KERNEL_RUNNING) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Attempted to load new kernel library while already running\n");
|
2015-08-08 18:21:43 +08:00
|
|
|
out_packet_empty(REMOTEMSG_TYPE_LOAD_FAILED);
|
2015-08-02 11:41:05 +08:00
|
|
|
break;
|
2015-04-22 01:31:31 +08:00
|
|
|
}
|
2015-08-08 18:21:43 +08:00
|
|
|
|
|
|
|
if(kloader_load_library(kernel)) {
|
|
|
|
out_packet_empty(REMOTEMSG_TYPE_LOAD_COMPLETED);
|
2015-04-22 01:31:31 +08:00
|
|
|
user_kernel_state = USER_KERNEL_LOADED;
|
2015-08-02 11:41:05 +08:00
|
|
|
} else {
|
2015-08-08 18:21:43 +08:00
|
|
|
out_packet_empty(REMOTEMSG_TYPE_LOAD_FAILED);
|
2015-08-02 11:41:05 +08:00
|
|
|
}
|
2015-04-22 01:31:31 +08:00
|
|
|
break;
|
2015-08-08 18:21:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case REMOTEMSG_TYPE_RUN_KERNEL:
|
2015-04-22 01:31:31 +08:00
|
|
|
if(user_kernel_state != USER_KERNEL_LOADED) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Attempted to run kernel while not in the LOADED state\n");
|
2015-08-08 18:21:43 +08:00
|
|
|
out_packet_empty(REMOTEMSG_TYPE_KERNEL_STARTUP_FAILED);
|
2015-04-22 01:31:31 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-08-02 11:41:05 +08:00
|
|
|
watchdog_init();
|
2015-08-07 13:49:57 +08:00
|
|
|
kloader_start_kernel();
|
2015-04-22 01:31:31 +08:00
|
|
|
|
2015-04-22 11:41:54 +08:00
|
|
|
user_kernel_state = USER_KERNEL_RUNNING;
|
2015-04-22 01:31:31 +08:00
|
|
|
break;
|
2015-08-08 18:21:43 +08:00
|
|
|
|
2015-08-10 01:17:00 +08:00
|
|
|
case REMOTEMSG_TYPE_RPC_REPLY: {
|
|
|
|
struct msg_rpc_recv_request *request;
|
|
|
|
struct msg_rpc_recv_reply reply;
|
2015-04-22 01:31:31 +08:00
|
|
|
|
2015-08-10 01:17:00 +08:00
|
|
|
if(user_kernel_state != USER_KERNEL_WAIT_RPC) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Unsolicited RPC reply\n");
|
2015-08-10 01:17:00 +08:00
|
|
|
return 0; // restart session
|
|
|
|
}
|
|
|
|
|
|
|
|
request = mailbox_wait_and_receive();
|
|
|
|
if(request->type != MESSAGE_TYPE_RPC_RECV_REQUEST) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Expected MESSAGE_TYPE_RPC_RECV_REQUEST, got %d\n",
|
|
|
|
request->type);
|
2015-08-10 01:17:00 +08:00
|
|
|
return 0; // restart session
|
|
|
|
}
|
2015-08-08 21:01:08 +08:00
|
|
|
|
2015-08-10 01:17:00 +08:00
|
|
|
const char *tag = in_packet_string();
|
|
|
|
void *slot = request->slot;
|
|
|
|
if(!receive_rpc_value(&tag, &slot)) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Failed to receive RPC reply\n");
|
2015-08-10 01:17:00 +08:00
|
|
|
return 0; // restart session
|
|
|
|
}
|
2015-04-22 01:31:31 +08:00
|
|
|
|
2015-08-10 01:17:00 +08:00
|
|
|
reply.type = MESSAGE_TYPE_RPC_RECV_REPLY;
|
|
|
|
reply.alloc_size = 0;
|
|
|
|
reply.exception = NULL;
|
|
|
|
mailbox_send_and_wait(&reply);
|
2015-08-08 21:01:08 +08:00
|
|
|
|
2015-08-10 01:17:00 +08:00
|
|
|
user_kernel_state = USER_KERNEL_RUNNING;
|
|
|
|
break;
|
|
|
|
}
|
2015-08-08 21:01:08 +08:00
|
|
|
|
|
|
|
case REMOTEMSG_TYPE_RPC_EXCEPTION: {
|
2015-08-09 21:16:41 +08:00
|
|
|
struct msg_rpc_recv_request *request;
|
|
|
|
struct msg_rpc_recv_reply reply;
|
2015-08-08 21:01:08 +08:00
|
|
|
|
|
|
|
struct artiq_exception exception;
|
|
|
|
exception.name = in_packet_string();
|
|
|
|
exception.message = in_packet_string();
|
|
|
|
exception.param[0] = in_packet_int64();
|
|
|
|
exception.param[1] = in_packet_int64();
|
|
|
|
exception.param[2] = in_packet_int64();
|
|
|
|
exception.file = in_packet_string();
|
|
|
|
exception.line = in_packet_int32();
|
|
|
|
exception.column = in_packet_int32();
|
|
|
|
exception.function = in_packet_string();
|
|
|
|
|
|
|
|
if(user_kernel_state != USER_KERNEL_WAIT_RPC) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Unsolicited RPC exception reply\n");
|
2015-08-08 21:01:08 +08:00
|
|
|
return 0; // restart session
|
|
|
|
}
|
|
|
|
|
2015-08-09 21:16:41 +08:00
|
|
|
request = mailbox_wait_and_receive();
|
|
|
|
if(request->type != MESSAGE_TYPE_RPC_RECV_REQUEST) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Expected MESSAGE_TYPE_RPC_RECV_REQUEST, got %d\n",
|
2015-08-09 21:16:41 +08:00
|
|
|
request->type);
|
|
|
|
return 0; // restart session
|
|
|
|
}
|
|
|
|
|
|
|
|
reply.type = MESSAGE_TYPE_RPC_RECV_REPLY;
|
|
|
|
reply.alloc_size = 0;
|
2015-08-08 21:01:08 +08:00
|
|
|
reply.exception = &exception;
|
2015-04-22 01:31:31 +08:00
|
|
|
mailbox_send_and_wait(&reply);
|
2015-08-08 21:01:08 +08:00
|
|
|
|
2015-04-22 01:31:31 +08:00
|
|
|
user_kernel_state = USER_KERNEL_RUNNING;
|
|
|
|
break;
|
|
|
|
}
|
2015-05-07 23:47:48 +08:00
|
|
|
|
2015-08-08 18:21:43 +08:00
|
|
|
default:
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Received invalid packet type %d from host\n",
|
|
|
|
buffer_in.header.type);
|
2015-08-10 01:17:00 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// See comm_generic.py:_{send,receive}_rpc_value and llvm_ir_generator.py:_rpc_tag.
|
|
|
|
static void skip_rpc_value(const char **tag) {
|
|
|
|
switch(*(*tag)++) {
|
|
|
|
case 't': {
|
|
|
|
int size = *(*tag)++;
|
|
|
|
for(int i = 0; i < size; i++)
|
|
|
|
skip_rpc_value(tag);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'l':
|
2016-07-06 17:51:57 +08:00
|
|
|
case 'a':
|
2015-08-10 01:17:00 +08:00
|
|
|
skip_rpc_value(tag);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'r':
|
|
|
|
skip_rpc_value(tag);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int sizeof_rpc_value(const char **tag)
|
|
|
|
{
|
|
|
|
switch(*(*tag)++) {
|
|
|
|
case 't': { // tuple
|
|
|
|
int size = *(*tag)++;
|
|
|
|
|
|
|
|
int32_t length = 0;
|
|
|
|
for(int i = 0; i < size; i++)
|
|
|
|
length += sizeof_rpc_value(tag);
|
|
|
|
return length;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'n': // None
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
case 'b': // bool
|
|
|
|
return sizeof(int8_t);
|
|
|
|
|
|
|
|
case 'i': // int(width=32)
|
|
|
|
return sizeof(int32_t);
|
|
|
|
|
|
|
|
case 'I': // int(width=64)
|
|
|
|
return sizeof(int64_t);
|
|
|
|
|
|
|
|
case 'f': // float
|
|
|
|
return sizeof(double);
|
|
|
|
|
|
|
|
case 'F': // Fraction
|
|
|
|
return sizeof(struct { int64_t numerator, denominator; });
|
|
|
|
|
|
|
|
case 's': // string
|
|
|
|
return sizeof(char *);
|
|
|
|
|
|
|
|
case 'l': // list(elt='a)
|
2016-07-06 17:51:57 +08:00
|
|
|
case 'a': // array(elt='a)
|
2015-08-10 01:17:00 +08:00
|
|
|
skip_rpc_value(tag);
|
|
|
|
return sizeof(struct { int32_t length; struct {} *elements; });
|
|
|
|
|
|
|
|
case 'r': // range(elt='a)
|
|
|
|
return sizeof_rpc_value(tag) * 3;
|
|
|
|
|
|
|
|
default:
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("sizeof_rpc_value: unknown tag %02x\n", *((*tag) - 1));
|
2015-08-10 01:17:00 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void *alloc_rpc_value(int size)
|
|
|
|
{
|
|
|
|
struct msg_rpc_recv_request *request;
|
|
|
|
struct msg_rpc_recv_reply reply;
|
|
|
|
|
|
|
|
reply.type = MESSAGE_TYPE_RPC_RECV_REPLY;
|
|
|
|
reply.alloc_size = size;
|
|
|
|
reply.exception = NULL;
|
|
|
|
mailbox_send_and_wait(&reply);
|
|
|
|
|
|
|
|
request = mailbox_wait_and_receive();
|
|
|
|
if(request->type != MESSAGE_TYPE_RPC_RECV_REQUEST) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Expected MESSAGE_TYPE_RPC_RECV_REQUEST, got %d\n",
|
|
|
|
request->type);
|
2015-08-10 01:17:00 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return request->slot;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int receive_rpc_value(const char **tag, void **slot)
|
|
|
|
{
|
|
|
|
switch(*(*tag)++) {
|
|
|
|
case 't': { // tuple
|
|
|
|
int size = *(*tag)++;
|
|
|
|
|
|
|
|
for(int i = 0; i < size; i++) {
|
|
|
|
if(!receive_rpc_value(tag, slot))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'n': // None
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'b': { // bool
|
|
|
|
*((*(int8_t**)slot)++) = in_packet_int8();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'i': { // int(width=32)
|
|
|
|
*((*(int32_t**)slot)++) = in_packet_int32();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'I': { // int(width=64)
|
|
|
|
*((*(int64_t**)slot)++) = in_packet_int64();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'f': { // float
|
|
|
|
*((*(int64_t**)slot)++) = in_packet_int64();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'F': { // Fraction
|
|
|
|
struct { int64_t numerator, denominator; } *fraction = *slot;
|
|
|
|
fraction->numerator = in_packet_int64();
|
|
|
|
fraction->denominator = in_packet_int64();
|
|
|
|
*slot = (void*)((intptr_t)(*slot) + sizeof(*fraction));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 's': { // string
|
|
|
|
const char *in_string = in_packet_string();
|
|
|
|
char *out_string = alloc_rpc_value(strlen(in_string) + 1);
|
|
|
|
memcpy(out_string, in_string, strlen(in_string) + 1);
|
|
|
|
*((*(char***)slot)++) = out_string;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2016-07-06 17:51:57 +08:00
|
|
|
case 'l': // list(elt='a)
|
|
|
|
case 'a': { // array(elt='a)
|
2015-08-10 01:17:00 +08:00
|
|
|
struct { int32_t length; struct {} *elements; } *list = *slot;
|
|
|
|
list->length = in_packet_int32();
|
|
|
|
|
|
|
|
const char *tag_copy = *tag;
|
|
|
|
list->elements = alloc_rpc_value(sizeof_rpc_value(&tag_copy) * list->length);
|
|
|
|
|
|
|
|
void *element = list->elements;
|
|
|
|
for(int i = 0; i < list->length; i++) {
|
|
|
|
const char *tag_copy = *tag;
|
|
|
|
if(!receive_rpc_value(&tag_copy, &element))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
skip_rpc_value(tag);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 'r': { // range(elt='a)
|
|
|
|
const char *tag_copy;
|
|
|
|
tag_copy = *tag;
|
|
|
|
if(!receive_rpc_value(&tag_copy, slot)) // min
|
|
|
|
return 0;
|
|
|
|
tag_copy = *tag;
|
|
|
|
if(!receive_rpc_value(&tag_copy, slot)) // max
|
|
|
|
return 0;
|
|
|
|
tag_copy = *tag;
|
|
|
|
if(!receive_rpc_value(&tag_copy, slot)) // step
|
|
|
|
return 0;
|
|
|
|
*tag = tag_copy;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("receive_rpc_value: unknown tag %02x\n", *((*tag) - 1));
|
2015-08-08 18:21:43 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-05-07 23:47:48 +08:00
|
|
|
|
2015-08-08 18:21:43 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2015-05-07 23:47:48 +08:00
|
|
|
|
2015-08-09 07:17:19 +08:00
|
|
|
static int send_rpc_value(const char **tag, void **value)
|
2015-08-08 18:48:25 +08:00
|
|
|
{
|
2015-08-08 19:12:28 +08:00
|
|
|
if(!out_packet_int8(**tag))
|
2015-08-09 07:17:19 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
switch(*(*tag)++) {
|
|
|
|
case 't': { // tuple
|
|
|
|
int size = *(*tag)++;
|
|
|
|
if(!out_packet_int8(size))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
for(int i = 0; i < size; i++) {
|
|
|
|
if(!send_rpc_value(tag, value))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2015-05-07 23:47:48 +08:00
|
|
|
|
2015-08-08 18:21:43 +08:00
|
|
|
case 'n': // None
|
2015-05-07 23:47:48 +08:00
|
|
|
break;
|
2015-08-08 18:21:43 +08:00
|
|
|
|
2015-08-09 07:17:19 +08:00
|
|
|
case 'b': { // bool
|
2015-08-10 01:17:00 +08:00
|
|
|
return out_packet_int8(*((*(int8_t**)value)++));
|
2015-08-09 07:17:19 +08:00
|
|
|
}
|
2015-05-07 23:47:48 +08:00
|
|
|
|
2015-08-09 07:17:19 +08:00
|
|
|
case 'i': { // int(width=32)
|
2015-08-10 01:17:00 +08:00
|
|
|
return out_packet_int32(*((*(int32_t**)value)++));
|
2015-08-09 07:17:19 +08:00
|
|
|
}
|
2015-05-07 23:47:48 +08:00
|
|
|
|
2015-08-09 07:17:19 +08:00
|
|
|
case 'I': { // int(width=64)
|
2015-08-10 01:17:00 +08:00
|
|
|
return out_packet_int64(*((*(int64_t**)value)++));
|
2015-08-09 07:17:19 +08:00
|
|
|
}
|
2015-04-22 01:31:31 +08:00
|
|
|
|
2015-08-09 07:17:19 +08:00
|
|
|
case 'f': { // float
|
2015-08-10 01:17:00 +08:00
|
|
|
return out_packet_float64(*((*(double**)value)++));
|
2015-08-09 07:17:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case 'F': { // Fraction
|
2015-08-10 01:17:00 +08:00
|
|
|
struct { int64_t numerator, denominator; } *fraction = *value;
|
|
|
|
if(!out_packet_int64(fraction->numerator))
|
|
|
|
return 0;
|
|
|
|
if(!out_packet_int64(fraction->denominator))
|
2015-08-09 07:17:19 +08:00
|
|
|
return 0;
|
2015-08-10 01:17:00 +08:00
|
|
|
*value = (void*)((intptr_t)(*value) + sizeof(*fraction));
|
2015-08-09 07:17:19 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case 's': { // string
|
2015-08-10 01:17:00 +08:00
|
|
|
return out_packet_string(*((*(const char***)value)++));
|
2015-08-09 07:17:19 +08:00
|
|
|
}
|
2015-04-22 01:31:31 +08:00
|
|
|
|
2016-07-06 17:51:57 +08:00
|
|
|
case 'l': // list(elt='a)
|
|
|
|
case 'a': { // array(elt='a)
|
2015-08-09 07:17:19 +08:00
|
|
|
struct { uint32_t length; struct {} *elements; } *list = *value;
|
2015-08-08 18:21:43 +08:00
|
|
|
void *element = list->elements;
|
|
|
|
|
2015-08-09 07:17:19 +08:00
|
|
|
if(!out_packet_int32(list->length))
|
|
|
|
return 0;
|
|
|
|
|
2015-08-08 18:21:43 +08:00
|
|
|
for(int i = 0; i < list->length; i++) {
|
2015-08-10 01:36:14 +08:00
|
|
|
const char *tag_copy = *tag;
|
2016-01-08 02:29:35 +08:00
|
|
|
if(!send_rpc_value(&tag_copy, &element)) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("failed to send list at element %d/%d\n", i, list->length);
|
2015-08-09 07:17:19 +08:00
|
|
|
return 0;
|
2016-01-08 02:29:35 +08:00
|
|
|
}
|
2015-04-22 01:31:31 +08:00
|
|
|
}
|
2015-08-10 01:36:14 +08:00
|
|
|
skip_rpc_value(tag);
|
2015-08-08 21:01:08 +08:00
|
|
|
|
2015-08-09 07:17:19 +08:00
|
|
|
*value = (void*)((intptr_t)(*value) + sizeof(*list));
|
2015-08-08 21:01:08 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2015-08-09 07:17:19 +08:00
|
|
|
case 'r': { // range(elt='a)
|
|
|
|
const char *tag_copy;
|
|
|
|
tag_copy = *tag;
|
|
|
|
if(!send_rpc_value(&tag_copy, value)) // min
|
|
|
|
return 0;
|
|
|
|
tag_copy = *tag;
|
|
|
|
if(!send_rpc_value(&tag_copy, value)) // max
|
|
|
|
return 0;
|
|
|
|
tag_copy = *tag;
|
|
|
|
if(!send_rpc_value(&tag_copy, value)) // step
|
|
|
|
return 0;
|
|
|
|
*tag = tag_copy;
|
|
|
|
break;
|
|
|
|
}
|
2015-08-08 21:01:08 +08:00
|
|
|
|
2016-04-26 06:05:32 +08:00
|
|
|
case 'k': { // keyword(value='a)
|
|
|
|
struct { const char *name; struct {} contents; } *option = *value;
|
2015-08-09 07:17:19 +08:00
|
|
|
void *contents = &option->contents;
|
2015-08-08 21:01:08 +08:00
|
|
|
|
2016-04-26 06:05:32 +08:00
|
|
|
if(!out_packet_string(option->name))
|
2015-08-09 07:17:19 +08:00
|
|
|
return 0;
|
|
|
|
|
2016-04-26 06:05:32 +08:00
|
|
|
// keyword never appears in composite types, so we don't have
|
2015-08-09 07:17:19 +08:00
|
|
|
// to accurately advance *value.
|
2016-04-26 06:05:32 +08:00
|
|
|
return send_rpc_value(tag, &contents);
|
2015-08-09 07:17:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case 'O': { // host object
|
|
|
|
struct { uint32_t id; } **object = *value;
|
2016-07-07 20:40:50 +08:00
|
|
|
|
|
|
|
if(!out_packet_int32((*object)->id))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
*value = (void*)((intptr_t)(*value) + sizeof(*object));
|
|
|
|
break;
|
2015-04-22 01:31:31 +08:00
|
|
|
}
|
|
|
|
|
2015-04-30 10:52:50 +08:00
|
|
|
default:
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("send_rpc_value: unknown tag %02x\n", *((*tag) - 1));
|
2015-08-09 07:17:19 +08:00
|
|
|
return 0;
|
2015-04-30 10:52:50 +08:00
|
|
|
}
|
|
|
|
|
2015-08-09 07:17:19 +08:00
|
|
|
return 1;
|
2015-04-30 10:52:50 +08:00
|
|
|
}
|
|
|
|
|
2015-08-09 07:17:19 +08:00
|
|
|
static int send_rpc_request(int service, const char *tag, va_list args)
|
2015-04-30 10:52:50 +08:00
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
out_packet_start(REMOTEMSG_TYPE_RPC_REQUEST);
|
|
|
|
out_packet_int32(service);
|
|
|
|
|
2015-08-09 21:16:41 +08:00
|
|
|
while(*tag != ':') {
|
2015-08-08 18:21:43 +08:00
|
|
|
void *value = va_arg(args, void*);
|
|
|
|
if(!kloader_validate_kpointer(value))
|
|
|
|
return 0;
|
2015-08-09 07:17:19 +08:00
|
|
|
if(!send_rpc_value(&tag, &value))
|
2015-04-30 10:52:50 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-08-09 07:17:19 +08:00
|
|
|
out_packet_int8(0);
|
2015-08-09 21:16:41 +08:00
|
|
|
|
2015-08-10 01:17:00 +08:00
|
|
|
out_packet_string(tag + 1); // return tags
|
2015-08-08 18:21:43 +08:00
|
|
|
out_packet_finish();
|
2015-04-30 10:52:50 +08:00
|
|
|
return 1;
|
|
|
|
}
|
2015-04-29 12:58:37 +08:00
|
|
|
|
2016-01-10 21:04:55 +08:00
|
|
|
struct cache_row {
|
|
|
|
struct cache_row *next;
|
|
|
|
char *key;
|
|
|
|
size_t length;
|
|
|
|
int32_t *elements;
|
|
|
|
int borrowed;
|
|
|
|
};
|
|
|
|
|
|
|
|
static struct cache_row *cache;
|
|
|
|
|
2015-04-22 01:31:31 +08:00
|
|
|
/* assumes output buffer is empty when called */
|
2015-04-28 02:11:58 +08:00
|
|
|
static int process_kmsg(struct msg_base *umsg)
|
2015-04-22 01:31:31 +08:00
|
|
|
{
|
2015-07-25 16:26:04 +08:00
|
|
|
if(!kloader_validate_kpointer(umsg))
|
2015-04-30 10:52:50 +08:00
|
|
|
return 0;
|
2015-07-25 16:26:04 +08:00
|
|
|
if(kloader_is_essential_kmsg(umsg->type))
|
|
|
|
return 1; /* handled elsewhere */
|
2015-08-09 21:16:41 +08:00
|
|
|
if(user_kernel_state == USER_KERNEL_WAIT_RPC &&
|
|
|
|
umsg->type == MESSAGE_TYPE_RPC_RECV_REQUEST) {
|
|
|
|
// Handled and acknowledged when we receive
|
|
|
|
// REMOTEMSG_TYPE_RPC_{EXCEPTION,REPLY}.
|
|
|
|
return 1;
|
|
|
|
}
|
2015-07-25 16:26:04 +08:00
|
|
|
if(user_kernel_state != USER_KERNEL_RUNNING) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Received unexpected message from kernel CPU while not in running state\n");
|
2015-07-07 21:29:38 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2015-04-22 01:31:31 +08:00
|
|
|
|
|
|
|
switch(umsg->type) {
|
|
|
|
case MESSAGE_TYPE_FINISHED:
|
2015-08-08 18:21:43 +08:00
|
|
|
out_packet_empty(REMOTEMSG_TYPE_KERNEL_FINISHED);
|
2015-04-22 01:31:31 +08:00
|
|
|
|
2016-01-11 04:01:20 +08:00
|
|
|
for(struct cache_row *iter = cache; iter; iter = iter->next)
|
|
|
|
iter->borrowed = 0;
|
|
|
|
|
2015-05-09 17:11:34 +08:00
|
|
|
kloader_stop();
|
2015-04-22 01:31:31 +08:00
|
|
|
user_kernel_state = USER_KERNEL_LOADED;
|
2016-01-11 04:01:20 +08:00
|
|
|
|
2015-04-22 01:31:31 +08:00
|
|
|
break;
|
2015-08-08 18:21:43 +08:00
|
|
|
|
2015-04-22 01:31:31 +08:00
|
|
|
case MESSAGE_TYPE_EXCEPTION: {
|
|
|
|
struct msg_exception *msg = (struct msg_exception *)umsg;
|
|
|
|
|
2015-08-08 21:01:08 +08:00
|
|
|
out_packet_start(REMOTEMSG_TYPE_KERNEL_EXCEPTION);
|
|
|
|
|
|
|
|
out_packet_string(msg->exception->name);
|
|
|
|
out_packet_string(msg->exception->message);
|
|
|
|
out_packet_int64(msg->exception->param[0]);
|
|
|
|
out_packet_int64(msg->exception->param[1]);
|
|
|
|
out_packet_int64(msg->exception->param[2]);
|
|
|
|
|
|
|
|
out_packet_string(msg->exception->file);
|
|
|
|
out_packet_int32(msg->exception->line);
|
|
|
|
out_packet_int32(msg->exception->column);
|
|
|
|
out_packet_string(msg->exception->function);
|
|
|
|
|
|
|
|
kloader_filter_backtrace(msg->backtrace,
|
|
|
|
&msg->backtrace_size);
|
|
|
|
|
|
|
|
out_packet_int32(msg->backtrace_size);
|
|
|
|
for(int i = 0; i < msg->backtrace_size; i++) {
|
|
|
|
struct artiq_backtrace_item *item = &msg->backtrace[i];
|
|
|
|
out_packet_int32(item->function + item->offset);
|
|
|
|
}
|
|
|
|
|
|
|
|
out_packet_finish();
|
2015-04-22 01:31:31 +08:00
|
|
|
|
2015-05-09 17:11:34 +08:00
|
|
|
kloader_stop();
|
2015-04-22 01:31:31 +08:00
|
|
|
user_kernel_state = USER_KERNEL_LOADED;
|
2015-04-29 12:58:37 +08:00
|
|
|
mailbox_acknowledge();
|
|
|
|
break;
|
|
|
|
}
|
2015-08-08 18:21:43 +08:00
|
|
|
|
2016-01-02 22:51:04 +08:00
|
|
|
case MESSAGE_TYPE_RPC_SEND:
|
|
|
|
case MESSAGE_TYPE_RPC_BATCH: {
|
2015-08-09 07:25:58 +08:00
|
|
|
struct msg_rpc_send *msg = (struct msg_rpc_send *)umsg;
|
2015-04-22 01:31:31 +08:00
|
|
|
|
2015-08-09 07:17:19 +08:00
|
|
|
if(!send_rpc_request(msg->service, msg->tag, msg->args)) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Failed to send RPC request (service %d, tag %s)\n",
|
|
|
|
msg->service, msg->tag);
|
2015-08-08 19:12:28 +08:00
|
|
|
return 0; // restart session
|
2015-08-08 18:21:43 +08:00
|
|
|
}
|
|
|
|
|
2016-01-02 22:51:04 +08:00
|
|
|
if(msg->type == MESSAGE_TYPE_RPC_SEND)
|
|
|
|
user_kernel_state = USER_KERNEL_WAIT_RPC;
|
2015-04-29 12:58:37 +08:00
|
|
|
mailbox_acknowledge();
|
2015-04-22 01:31:31 +08:00
|
|
|
break;
|
|
|
|
}
|
2015-08-08 18:21:43 +08:00
|
|
|
|
2016-01-10 21:04:55 +08:00
|
|
|
case MESSAGE_TYPE_CACHE_GET_REQUEST: {
|
|
|
|
struct msg_cache_get_request *request = (struct msg_cache_get_request *)umsg;
|
|
|
|
struct msg_cache_get_reply reply;
|
|
|
|
|
|
|
|
reply.type = MESSAGE_TYPE_CACHE_GET_REPLY;
|
|
|
|
reply.length = 0;
|
|
|
|
reply.elements = NULL;
|
|
|
|
|
|
|
|
for(struct cache_row *iter = cache; iter; iter = iter->next) {
|
|
|
|
if(!strcmp(iter->key, request->key)) {
|
|
|
|
reply.length = iter->length;
|
|
|
|
reply.elements = iter->elements;
|
|
|
|
iter->borrowed = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
mailbox_send(&reply);
|
2016-01-10 23:45:56 +08:00
|
|
|
break;
|
2016-01-10 21:04:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
case MESSAGE_TYPE_CACHE_PUT_REQUEST: {
|
|
|
|
struct msg_cache_put_request *request = (struct msg_cache_put_request *)umsg;
|
|
|
|
struct msg_cache_put_reply reply;
|
|
|
|
|
|
|
|
reply.type = MESSAGE_TYPE_CACHE_PUT_REPLY;
|
|
|
|
|
|
|
|
struct cache_row *row = NULL;
|
|
|
|
for(struct cache_row *iter = cache; iter; iter = iter->next) {
|
|
|
|
if(!strcmp(iter->key, request->key)) {
|
|
|
|
row = iter;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!row) {
|
2016-01-11 04:01:20 +08:00
|
|
|
row = calloc(1, sizeof(struct cache_row));
|
2016-01-10 21:04:55 +08:00
|
|
|
row->key = calloc(strlen(request->key) + 1, 1);
|
|
|
|
strcpy(row->key, request->key);
|
2016-01-11 04:01:20 +08:00
|
|
|
row->next = cache;
|
|
|
|
cache = row;
|
2016-01-10 21:04:55 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!row->borrowed) {
|
2016-03-08 05:12:03 +08:00
|
|
|
row->length = request->length;
|
|
|
|
if(row->length != 0) {
|
2016-01-10 21:08:26 +08:00
|
|
|
row->elements = calloc(row->length, sizeof(int32_t));
|
|
|
|
memcpy(row->elements, request->elements,
|
|
|
|
sizeof(int32_t) * row->length);
|
2016-03-08 05:12:03 +08:00
|
|
|
} else {
|
|
|
|
free(row->elements);
|
|
|
|
row->elements = NULL;
|
2016-01-10 21:08:26 +08:00
|
|
|
}
|
|
|
|
|
2016-01-10 21:04:55 +08:00
|
|
|
reply.succeeded = 1;
|
|
|
|
} else {
|
|
|
|
reply.succeeded = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
mailbox_send(&reply);
|
2016-01-10 23:45:56 +08:00
|
|
|
break;
|
2016-01-10 21:04:55 +08:00
|
|
|
}
|
|
|
|
|
2015-04-22 01:31:31 +08:00
|
|
|
default: {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Received invalid message type %d from kernel CPU\n",
|
|
|
|
umsg->type);
|
2015-04-28 02:11:58 +08:00
|
|
|
return 0;
|
2015-04-22 01:31:31 +08:00
|
|
|
}
|
|
|
|
}
|
2015-08-08 19:12:28 +08:00
|
|
|
|
2015-04-28 02:11:58 +08:00
|
|
|
return 1;
|
2015-04-22 01:31:31 +08:00
|
|
|
}
|
|
|
|
|
2015-08-08 18:21:43 +08:00
|
|
|
/* Returns amount of bytes consumed on success.
|
|
|
|
* Returns -1 in case of irrecoverable error
|
|
|
|
* (the session must be dropped and session_end called).
|
|
|
|
* Returns -2 if the host has requested session reset.
|
|
|
|
*/
|
2015-08-08 18:48:25 +08:00
|
|
|
int session_input(void *data, int length)
|
|
|
|
{
|
2015-08-08 18:21:43 +08:00
|
|
|
return in_packet_fill((uint8_t*)data, length);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* *length is set to -1 in case of irrecoverable error
|
2015-04-28 02:11:58 +08:00
|
|
|
* (the session must be dropped and session_end called)
|
|
|
|
*/
|
2016-03-19 06:29:42 +08:00
|
|
|
void session_poll(void **data, int *length, int *close_flag)
|
2015-04-22 01:31:31 +08:00
|
|
|
{
|
2016-03-19 06:29:42 +08:00
|
|
|
*close_flag = 0;
|
|
|
|
|
2015-07-28 00:05:24 +08:00
|
|
|
if(user_kernel_state == USER_KERNEL_RUNNING) {
|
|
|
|
if(watchdog_expired()) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("Watchdog expired\n");
|
2016-03-19 06:29:42 +08:00
|
|
|
|
|
|
|
*close_flag = 1;
|
|
|
|
out_packet_empty(REMOTEMSG_TYPE_WATCHDOG_EXPIRED);
|
2015-07-28 00:05:24 +08:00
|
|
|
}
|
2015-07-28 00:19:07 +08:00
|
|
|
if(!rtiocrg_check()) {
|
2016-02-15 06:54:54 +08:00
|
|
|
core_log("RTIO clock failure\n");
|
2016-03-19 06:29:42 +08:00
|
|
|
|
|
|
|
*close_flag = 1;
|
|
|
|
out_packet_empty(REMOTEMSG_TYPE_CLOCK_FAILURE);
|
2015-07-28 00:05:24 +08:00
|
|
|
}
|
2015-04-29 12:58:37 +08:00
|
|
|
}
|
|
|
|
|
2016-03-19 06:29:42 +08:00
|
|
|
if(!*close_flag) {
|
|
|
|
/* If the output buffer is available,
|
|
|
|
* check if the kernel CPU has something to transmit.
|
|
|
|
*/
|
|
|
|
if(out_packet_available()) {
|
|
|
|
struct msg_base *umsg = mailbox_receive();
|
|
|
|
if(umsg) {
|
|
|
|
if(!process_kmsg(umsg)) {
|
|
|
|
*length = -1;
|
|
|
|
return;
|
|
|
|
}
|
2015-04-28 02:11:58 +08:00
|
|
|
}
|
2015-04-22 01:31:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-08 18:21:43 +08:00
|
|
|
out_packet_extract(data, length);
|
2015-04-23 23:22:40 +08:00
|
|
|
}
|
|
|
|
|
2015-08-08 19:06:11 +08:00
|
|
|
void session_ack_consumed(int length)
|
|
|
|
{
|
|
|
|
out_packet_advance_consumed(length);
|
|
|
|
}
|
|
|
|
|
|
|
|
void session_ack_sent(int length)
|
2015-04-23 23:22:40 +08:00
|
|
|
{
|
2015-08-08 19:06:11 +08:00
|
|
|
out_packet_advance_sent(length);
|
2015-04-22 01:31:31 +08:00
|
|
|
}
|