forked from M-Labs/artiq
1
0
Fork 0

comm: refactor to support lwip event model

This commit is contained in:
Sebastien Bourdeauducq 2015-04-22 01:31:31 +08:00
parent 9f52277245
commit 18106cc014
20 changed files with 832 additions and 625 deletions

View File

@ -1,10 +1,8 @@
import struct import struct
import zlib
import logging import logging
from enum import Enum from enum import Enum
from fractions import Fraction from fractions import Fraction
from artiq.language import units
from artiq.coredevice.runtime import Environment from artiq.coredevice.runtime import Environment
from artiq.coredevice import runtime_exceptions from artiq.coredevice import runtime_exceptions
from artiq.language import core as core_language from artiq.language import core as core_language
@ -15,33 +13,30 @@ logger = logging.getLogger(__name__)
class _H2DMsgType(Enum): class _H2DMsgType(Enum):
LINK_MESSAGE = 1 LOG_REQUEST = 1
IDENT_REQUEST = 2
REQUEST_IDENT = 2
SWITCH_CLOCK = 3 SWITCH_CLOCK = 3
LOAD_OBJECT = 4 LOAD_OBJECT = 4
RUN_KERNEL = 5 RUN_KERNEL = 5
RPC_REPLY = 6
class _D2HMsgType(Enum): class _D2HMsgType(Enum):
MESSAGE_UNRECOGNIZED = 1 LOG_REPLY = 1
LOG = 2 IDENT_REPLY = 2
CLOCK_SWITCH_COMPLETED = 3
CLOCK_SWITCH_FAILED = 4
IDENT = 3 LOAD_COMPLETED = 5
CLOCK_SWITCH_COMPLETED = 4 LOAD_FAILED = 6
CLOCK_SWITCH_FAILED = 5
OBJECT_LOADED = 6 KERNEL_FINISHED = 7
OBJECT_INCORRECT_LENGTH = 7 KERNEL_STARTUP_FAILED = 8
OBJECT_CRC_FAILED = 8 KERNEL_EXCEPTION = 9
OBJECT_UNRECOGNIZED = 9
KERNEL_FINISHED = 10 RPC_REQUEST = 10
KERNEL_STARTUP_FAILED = 11
KERNEL_EXCEPTION = 12
RPC_REQUEST = 13
class UnsupportedDevice(Exception): class UnsupportedDevice(Exception):
@ -71,39 +66,35 @@ class CommGeneric:
raise NotImplementedError raise NotImplementedError
# #
def _read(self, length): def _read_header(self):
self.open() self.open()
return self.read(length)
def _write(self, data): sync_count = 0
self.open() while sync_count < 4:
self.write(data) (c, ) = struct.unpack("B", self.read(1))
if c == 0x5a:
def _get_device_msg(self): sync_count += 1
while True:
(reply, ) = struct.unpack("B", self._read(1))
msg = _D2HMsgType(reply)
if msg == _D2HMsgType.LOG:
(length, ) = struct.unpack(">h", self._read(2))
log_message = ""
for i in range(length):
(c, ) = struct.unpack("B", self._read(1))
log_message += chr(c)
logger.info("DEVICE LOG: %s", log_message)
else: else:
logger.debug("message received: %r", msg) sync_count = 0
return msg length, tyv = struct.unpack(">lB", self.read(5))
ty = _D2HMsgType(tyv)
logger.debug("receiving message: type=%r length=%d", ty, length)
return length, ty
def _write_header(self, length, ty):
self.open()
logger.debug("sending message: type=%r length=%d", ty, length)
self.write(struct.pack(">llB", 0x5a5a5a5a, length, ty.value))
def get_runtime_env(self): def get_runtime_env(self):
self._write(struct.pack(">lb", 0x5a5a5a5a, self._write_header(9, _H2DMsgType.IDENT_REQUEST)
_H2DMsgType.REQUEST_IDENT.value)) _, ty = self._read_header()
msg = self._get_device_msg() if ty != _D2HMsgType.IDENT_REPLY:
if msg != _D2HMsgType.IDENT: raise IOError("Incorrect reply from device: {}".format(ty))
raise IOError("Incorrect reply from device: {}".format(msg)) (reply, ) = struct.unpack("B", self.read(1))
(reply, ) = struct.unpack("B", self._read(1))
runtime_id = chr(reply) runtime_id = chr(reply)
for i in range(3): for i in range(3):
(reply, ) = struct.unpack("B", self._read(1)) (reply, ) = struct.unpack("B", self.read(1))
runtime_id += chr(reply) runtime_id += chr(reply)
if runtime_id != "AROR": if runtime_id != "AROR":
raise UnsupportedDevice("Unsupported runtime ID: {}" raise UnsupportedDevice("Unsupported runtime ID: {}"
@ -111,63 +102,59 @@ class CommGeneric:
return Environment() return Environment()
def switch_clock(self, external): def switch_clock(self, external):
self._write(struct.pack( self._write_header(10, _H2DMsgType.SWITCH_CLOCK)
">lbb", 0x5a5a5a5a, _H2DMsgType.SWITCH_CLOCK.value, self.write(struct.pack("B", int(external)))
int(external))) _, ty = self._read_header()
msg = self._get_device_msg() if ty != _D2HMsgType.CLOCK_SWITCH_COMPLETED:
if msg != _D2HMsgType.CLOCK_SWITCH_COMPLETED: raise IOError("Incorrect reply from device: {}".format(ty))
raise IOError("Incorrect reply from device: {}".format(msg))
def load(self, kcode): def load(self, kcode):
self._write(struct.pack( self._write_header(len(kcode) + 9, _H2DMsgType.LOAD_OBJECT)
">lblL", self.write(kcode)
0x5a5a5a5a, _H2DMsgType.LOAD_OBJECT.value, _, ty = self._read_header()
len(kcode), zlib.crc32(kcode))) if ty != _D2HMsgType.LOAD_COMPLETED:
self._write(kcode) raise IOError("Incorrect reply from device: "+str(ty))
msg = self._get_device_msg()
if msg != _D2HMsgType.OBJECT_LOADED:
raise IOError("Incorrect reply from device: "+str(msg))
def run(self, kname): def run(self, kname):
self._write(struct.pack( self._write_header(len(kname) + 9, _H2DMsgType.RUN_KERNEL)
">lbl", 0x5a5a5a5a, _H2DMsgType.RUN_KERNEL.value, len(kname))) self.write(bytes(kname, "ascii"))
for c in kname:
self._write(struct.pack(">B", ord(c)))
logger.debug("running kernel: %s", kname) logger.debug("running kernel: %s", kname)
def _receive_rpc_values(self): def _receive_rpc_values(self):
r = [] r = []
while True: while True:
type_tag = chr(struct.unpack(">B", self._read(1))[0]) type_tag = chr(struct.unpack("B", self.read(1))[0])
if type_tag == "\x00": if type_tag == "\x00":
return r return r
if type_tag == "n": if type_tag == "n":
r.append(None) r.append(None)
if type_tag == "b": if type_tag == "b":
r.append(bool(struct.unpack(">B", self._read(1))[0])) r.append(bool(struct.unpack("B", self.read(1))[0]))
if type_tag == "i": if type_tag == "i":
r.append(struct.unpack(">l", self._read(4))[0]) r.append(struct.unpack(">l", self.read(4))[0])
if type_tag == "I": if type_tag == "I":
r.append(struct.unpack(">q", self._read(8))[0]) r.append(struct.unpack(">q", self.read(8))[0])
if type_tag == "f": if type_tag == "f":
r.append(struct.unpack(">d", self._read(8))[0]) r.append(struct.unpack(">d", self.read(8))[0])
if type_tag == "F": if type_tag == "F":
n, d = struct.unpack(">qq", self._read(16)) n, d = struct.unpack(">qq", self.read(16))
r.append(Fraction(n, d)) r.append(Fraction(n, d))
if type_tag == "l": if type_tag == "l":
r.append(self._receive_rpc_values()) r.append(self._receive_rpc_values())
def _serve_rpc(self, rpc_wrapper, rpc_map, user_exception_map): def _serve_rpc(self, rpc_wrapper, rpc_map, user_exception_map):
rpc_num = struct.unpack(">h", self._read(2))[0] rpc_num = struct.unpack(">l", self.read(4))[0]
args = self._receive_rpc_values() args = self._receive_rpc_values()
logger.debug("rpc service: %d %r", rpc_num, args) logger.debug("rpc service: %d %r", rpc_num, args)
eid, r = rpc_wrapper.run_rpc( eid, r = rpc_wrapper.run_rpc(
user_exception_map, rpc_map[rpc_num], args) user_exception_map, rpc_map[rpc_num], args)
self._write(struct.pack(">ll", eid, r)) self._write_header(9+2*4, _H2DMsgType.RPC_REPLY)
logger.debug("rpc service: %d %r == %r", rpc_num, args, r) self.write(struct.pack(">ll", eid, r))
logger.debug("rpc service: %d %r == %r (eid %d)", rpc_num, args,
r, eid)
def _serve_exception(self, rpc_wrapper, user_exception_map): def _serve_exception(self, rpc_wrapper, user_exception_map):
eid, p0, p1, p2 = struct.unpack(">lqqq", self._read(4+3*8)) eid, p0, p1, p2 = struct.unpack(">lqqq", self.read(4+3*8))
rpc_wrapper.filter_rpc_exception(eid) rpc_wrapper.filter_rpc_exception(eid)
if eid < core_language.first_user_eid: if eid < core_language.first_user_eid:
exception = runtime_exceptions.exception_map[eid] exception = runtime_exceptions.exception_map[eid]
@ -179,17 +166,24 @@ class CommGeneric:
def serve(self, rpc_map, user_exception_map): def serve(self, rpc_map, user_exception_map):
rpc_wrapper = RPCWrapper() rpc_wrapper = RPCWrapper()
while True: while True:
msg = self._get_device_msg() _, ty = self._read_header()
if msg == _D2HMsgType.RPC_REQUEST: if ty == _D2HMsgType.RPC_REQUEST:
self._serve_rpc(rpc_wrapper, rpc_map, user_exception_map) self._serve_rpc(rpc_wrapper, rpc_map, user_exception_map)
elif msg == _D2HMsgType.KERNEL_EXCEPTION: elif ty == _D2HMsgType.KERNEL_EXCEPTION:
self._serve_exception(rpc_wrapper, user_exception_map) self._serve_exception(rpc_wrapper, user_exception_map)
elif msg == _D2HMsgType.KERNEL_FINISHED: elif ty == _D2HMsgType.KERNEL_FINISHED:
return return
else: else:
raise IOError("Incorrect request from device: "+str(msg)) raise IOError("Incorrect request from device: "+str(ty))
def send_link_message(self, data): def get_log(self):
self._write(struct.pack( self._write_header(9, _H2DMsgType.LOG_REQUEST)
">lb", 0x5a5a5a5a, _H2DMsgType.LINK_MESSAGE.value)) length, ty = self._read_header()
self._write(data) if ty != _D2HMsgType.LOG_REPLY:
raise IOError("Incorrect request from device: "+str(ty))
r = ""
for i in range(length - 9):
c = struct.unpack("B", self.read(1))[0]
if c:
r += chr(c)
return r

View File

@ -17,15 +17,12 @@ class Comm(CommGeneric, AutoDB):
def open(self): def open(self):
if hasattr(self, "port"): if hasattr(self, "port"):
return return
self.port = serial.serial_for_url(self.serial_dev, baudrate=115200) self.port = serial.serial_for_url(self.serial_dev,
self.port.flush() baudrate=self.baud_rate)
self.set_remote_baud(self.baud_rate)
self.set_baud(self.baud_rate)
def close(self): def close(self):
if not hasattr(self, "port"): if not hasattr(self, "port"):
return return
self.set_remote_baud(115200)
self.port.close() self.port.close()
del self.port del self.port
@ -42,27 +39,3 @@ class Comm(CommGeneric, AutoDB):
written = self.port.write(data[pos:]) written = self.port.write(data[pos:])
remaining -= written remaining -= written
pos += written pos += written
def set_baud(self, baud):
self.port.baudrate = baud
self.port.flush()
logger.debug("local baud rate set to %d", baud)
def set_remote_baud(self, baud):
self.send_link_message(struct.pack(">l", baud))
handshake = 0
fails = 0
while handshake < 4:
(recv, ) = struct.unpack("B", self.read(1))
if recv == 0x5a:
handshake += 1
else:
# FIXME: when loading immediately after a board reset,
# we erroneously get some zeros back.
logger.warning("unexpected sync character: %02x", recv)
handshake = 0
if recv != 0:
fails += 1
if fails > 3:
raise IOError("Baudrate ack failed")
logger.debug("remote baud rate set to %d", baud)

View File

@ -1,6 +1,6 @@
include $(MSCDIR)/software/common.mak include $(MSCDIR)/software/common.mak
OBJECTS := isr.o elf_loader.o services.o comm_serial.o test_mode.o main.o OBJECTS := isr.o elf_loader.o services.o session.o log.o test_mode.o kloader.o main.o
OBJECTS_KSUPPORT := exception_jmp.o exceptions.o rtio.o dds.o OBJECTS_KSUPPORT := exception_jmp.o exceptions.o rtio.o dds.o
# NOTE: this does not handle dependencies well. Run "make clean" # NOTE: this does not handle dependencies well. Run "make clean"
@ -8,7 +8,7 @@ OBJECTS_KSUPPORT := exception_jmp.o exceptions.o rtio.o dds.o
UNIPROCESSOR := $(shell printf "\#include <generated/csr.h>\nCSR_KERNEL_CPU_BASE" | $(CC_normal) $(CFLAGS) -E - | tail -n 1 | grep -c CSR_KERNEL_CPU_BASE) UNIPROCESSOR := $(shell printf "\#include <generated/csr.h>\nCSR_KERNEL_CPU_BASE" | $(CC_normal) $(CFLAGS) -E - | tail -n 1 | grep -c CSR_KERNEL_CPU_BASE)
ifeq ($(UNIPROCESSOR),0) ifeq ($(UNIPROCESSOR),0)
OBJECTS += mailbox.o kernelcpu.o ksupport_data.o OBJECTS += mailbox.o ksupport_data.o
OBJECTS_KSUPPORT += mailbox.o bridge.o ksupport.o OBJECTS_KSUPPORT += mailbox.o bridge.o ksupport.o
CFLAGS += -DARTIQ_AMP CFLAGS += -DARTIQ_AMP
SERVICE_TABLE_INPUT = ksupport.elf SERVICE_TABLE_INPUT = ksupport.elf

View File

@ -1,23 +0,0 @@
#ifndef __COMM_H
#define __COMM_H
#include <stdarg.h>
enum {
KERNEL_RUN_INVALID_STATUS,
KERNEL_RUN_FINISHED,
KERNEL_RUN_EXCEPTION,
KERNEL_RUN_STARTUP_FAILED
};
typedef int (*object_loader)(void *, int);
typedef int (*kernel_runner)(const char *, int *, long long int *);
void comm_serve(object_loader load_object, kernel_runner run_kernel);
void comm_rpc_va(int rpc_num, va_list args, int *eid, int *retval);
int comm_rpc(int rpc_num, ...);
void comm_log_va(const char *fmt, va_list args);
void comm_log(const char *fmt, ...);
#endif /* __COMM_H */

View File

@ -1,292 +0,0 @@
#include <stdarg.h>
#include <crc.h>
#include <uart.h>
#include <generated/csr.h>
#include "comm.h"
#ifndef ARTIQ_AMP
#include "exceptions.h"
#endif
/* host to device */
enum {
MSGTYPE_SET_BAUD_RATE = 1,
MSGTYPE_REQUEST_IDENT,
MSGTYPE_SWITCH_CLOCK,
MSGTYPE_LOAD_OBJECT,
MSGTYPE_RUN_KERNEL,
};
/* device to host */
enum {
MSGTYPE_MESSAGE_UNRECOGNIZED = 1,
MSGTYPE_LOG,
MSGTYPE_IDENT,
MSGTYPE_CLOCK_SWITCH_COMPLETED,
MSGTYPE_CLOCK_SWITCH_FAILED,
MSGTYPE_OBJECT_LOADED,
MSGTYPE_OBJECT_INCORRECT_LENGTH,
MSGTYPE_OBJECT_CRC_FAILED,
MSGTYPE_OBJECT_UNRECOGNIZED,
MSGTYPE_KERNEL_FINISHED,
MSGTYPE_KERNEL_STARTUP_FAILED,
MSGTYPE_KERNEL_EXCEPTION,
MSGTYPE_RPC_REQUEST,
};
static int receive_int(void)
{
unsigned int r;
int i;
r = 0;
for(i=0;i<4;i++) {
r <<= 8;
r |= (unsigned char)uart_read();
}
return r;
}
static char receive_char(void)
{
return uart_read();
}
static void send_llint(long long int x)
{
int i;
for(i=0;i<8;i++) {
uart_write((x & 0xff00000000000000LL) >> 56);
x <<= 8;
}
}
static void send_int(int x)
{
int i;
for(i=0;i<4;i++) {
uart_write((x & 0xff000000) >> 24);
x <<= 8;
}
}
static void send_sint(short int i)
{
uart_write((i >> 8) & 0xff);
uart_write(i & 0xff);
}
static void send_char(char c)
{
uart_write(c);
}
static void receive_sync(void)
{
char c;
int recognized;
recognized = 0;
while(recognized < 4) {
c = uart_read();
if(c == 0x5a)
recognized++;
else
recognized = 0;
}
}
static void receive_and_load_object(object_loader load_object)
{
int length;
int i;
unsigned char buffer[256*1024];
unsigned int crc;
length = receive_int();
if(length > sizeof(buffer)) {
send_char(MSGTYPE_OBJECT_INCORRECT_LENGTH);
return;
}
crc = receive_int();
for(i=0;i<length;i++)
buffer[i] = receive_char();
if(crc32(buffer, length) != crc) {
send_char(MSGTYPE_OBJECT_CRC_FAILED);
return;
}
if(load_object(buffer, length))
send_char(MSGTYPE_OBJECT_LOADED);
else
send_char(MSGTYPE_OBJECT_UNRECOGNIZED);
}
static void receive_and_run_kernel(kernel_runner run_kernel)
{
int length;
int i;
char kernel_name[256];
int r, eid;
long long int eparams[3];
length = receive_int();
if(length > (sizeof(kernel_name)-1)) {
send_char(MSGTYPE_OBJECT_INCORRECT_LENGTH);
return;
}
for(i=0;i<length;i++)
kernel_name[i] = receive_char();
kernel_name[length] = 0;
r = run_kernel(kernel_name, &eid, eparams);
switch(r) {
case KERNEL_RUN_FINISHED:
send_char(MSGTYPE_KERNEL_FINISHED);
break;
case KERNEL_RUN_EXCEPTION:
send_char(MSGTYPE_KERNEL_EXCEPTION);
send_int(eid);
for(i=0;i<3;i++)
send_llint(eparams[i]);
break;
case KERNEL_RUN_STARTUP_FAILED:
send_char(MSGTYPE_KERNEL_STARTUP_FAILED);
break;
default:
comm_log("BUG: run_kernel returned unexpected value '%d'", r);
break;
}
}
void comm_serve(object_loader load_object, kernel_runner run_kernel)
{
char msgtype;
while(1) {
receive_sync();
msgtype = receive_char();
if(msgtype == MSGTYPE_REQUEST_IDENT) {
send_char(MSGTYPE_IDENT);
send_int(0x41524f52); /* "AROR" - ARTIQ runtime on OpenRISC */
} else if(msgtype == MSGTYPE_LOAD_OBJECT)
receive_and_load_object(load_object);
else if(msgtype == MSGTYPE_RUN_KERNEL)
receive_and_run_kernel(run_kernel);
else if(msgtype == MSGTYPE_SET_BAUD_RATE) {
unsigned int ftw;
ftw = ((long long)receive_int() << 32LL)/(long long)identifier_frequency_read();
send_int(0x5a5a5a5a);
uart_sync();
uart_phy_tuning_word_write(ftw);
} else if(msgtype == MSGTYPE_SWITCH_CLOCK) {
rtiocrg_clock_sel_write(receive_char());
send_char(MSGTYPE_CLOCK_SWITCH_COMPLETED);
} else
send_char(MSGTYPE_MESSAGE_UNRECOGNIZED);
}
}
static int send_value(int type_tag, void *value)
{
char base_type;
int i, p;
int len;
base_type = type_tag;
send_char(base_type);
switch(base_type) {
case 'n':
return 0;
case 'b':
if(*(char *)value)
send_char(1);
else
send_char(0);
return 1;
case 'i':
send_int(*(int *)value);
return 4;
case 'I':
case 'f':
send_int(*(int *)value);
send_int(*((int *)value + 1));
return 8;
case 'F':
for(i=0;i<4;i++)
send_int(*((int *)value + i));
return 16;
case 'l':
len = *(int *)value;
p = 4;
for(i=0;i<len;i++)
p += send_value(type_tag >> 8, (char *)value + p);
send_char(0);
return p;
}
return 0;
}
void comm_rpc_va(int rpc_num, va_list args, int *eid, int *retval)
{
int type_tag;
send_char(MSGTYPE_RPC_REQUEST);
send_sint(rpc_num);
while((type_tag = va_arg(args, int)))
send_value(type_tag, type_tag == 'n' ? NULL : va_arg(args, void *));
send_char(0);
*eid = receive_int();
*retval = receive_int();
}
#ifndef ARTIQ_AMP
int comm_rpc(int rpc_num, ...)
{
va_list args;
int eid, retval;
va_start(args, rpc_num);
comm_rpc_va(rpc_num, args, &eid, &retval);
va_end(args);
if(eid != EID_NONE)
exception_raise(eid);
return retval;
}
#endif
void comm_log_va(const char *fmt, va_list args)
{
int len;
char outbuf[256];
int i;
len = vscnprintf(outbuf, sizeof(outbuf), fmt, args);
send_char(MSGTYPE_LOG);
send_sint(len);
for(i=0;i<len;i++)
send_char(outbuf[i]);
}
void comm_log(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
comm_log_va(fmt, args);
va_end(args);
}

View File

@ -1,6 +1,6 @@
#include <string.h> #include <string.h>
#include "comm.h" #include "log.h"
#include "elf_loader.h" #include "elf_loader.h"
#define EI_NIDENT 16 #define EI_NIDENT 16
@ -85,11 +85,11 @@ struct elf32_sym {
#define SANITIZE_OFFSET_SIZE(offset, size) \ #define SANITIZE_OFFSET_SIZE(offset, size) \
if(offset > 0x10000000) { \ if(offset > 0x10000000) { \
comm_log("Incorrect offset in ELF data"); \ log("Incorrect offset in ELF data"); \
return 0; \ return 0; \
} \ } \
if((offset + size) > elf_length) { \ if((offset + size) > elf_length) { \
comm_log("Attempted to access past the end of ELF data"); \ log("Attempted to access past the end of ELF data"); \
return 0; \ return 0; \
} }
@ -121,7 +121,7 @@ static int fixup(void *dest, int dest_length, struct elf32_rela *rela, void *tar
val = _target - (_dest + offset); val = _target - (_dest + offset);
_dest[offset] = (_dest[offset] & 0xfc000000) | (val & 0x03ffffff); _dest[offset] = (_dest[offset] & 0xfc000000) | (val & 0x03ffffff);
} else } else
comm_log("Unsupported relocation type: %d", type); log("Unsupported relocation type: %d", type);
return 1; return 1;
} }
@ -141,15 +141,15 @@ int load_elf(symbol_resolver resolver, symbol_callback callback, void *elf_data,
/* validate ELF */ /* validate ELF */
GET_POINTER_SAFE(ehdr, struct elf32_ehdr, 0); GET_POINTER_SAFE(ehdr, struct elf32_ehdr, 0);
if(memcmp(ehdr->ident, elf_magic_header, sizeof(elf_magic_header)) != 0) { if(memcmp(ehdr->ident, elf_magic_header, sizeof(elf_magic_header)) != 0) {
comm_log("Incorrect ELF header"); log("Incorrect ELF header");
return 0; return 0;
} }
if(ehdr->type != ET_REL) { if(ehdr->type != ET_REL) {
comm_log("ELF is not relocatable"); log("ELF is not relocatable");
return 0; return 0;
} }
if(ehdr->machine != EM_OR1K) { if(ehdr->machine != EM_OR1K) {
comm_log("ELF is for a different machine"); log("ELF is for a different machine");
return 0; return 0;
} }
@ -190,7 +190,7 @@ int load_elf(symbol_resolver resolver, symbol_callback callback, void *elf_data,
/* load .text section */ /* load .text section */
if(textsize > dest_length) { if(textsize > dest_length) {
comm_log(".text section is too large"); log(".text section is too large");
return 0; return 0;
} }
memcpy(dest, (char *)elf_data + textoff, textsize); memcpy(dest, (char *)elf_data + textoff, textsize);
@ -209,13 +209,13 @@ int load_elf(symbol_resolver resolver, symbol_callback callback, void *elf_data,
name = (char *)elf_data + strtaboff + sym->name; name = (char *)elf_data + strtaboff + sym->name;
target = resolver(name); target = resolver(name);
if(target == NULL) { if(target == NULL) {
comm_log("Undefined symbol: %s", name); log("Undefined symbol: %s", name);
return 0; return 0;
} }
if(!fixup(dest, dest_length, rela, target)) if(!fixup(dest, dest_length, rela, target))
return 0; return 0;
} else { } else {
comm_log("Unsupported relocation"); log("Unsupported relocation");
return 0; return 0;
} }
} }

View File

@ -1,6 +1,6 @@
#include <generated/csr.h> #include <generated/csr.h>
#include "comm.h" #include "log.h"
#include "exceptions.h" #include "exceptions.h"
#define MAX_EXCEPTION_CONTEXTS 64 #define MAX_EXCEPTION_CONTEXTS 64
@ -52,7 +52,7 @@ void exception_raise_params(int id,
stored_params[2] = p2; stored_params[2] = p2;
exception_longjmp(exception_contexts[--ec_top].jb); exception_longjmp(exception_contexts[--ec_top].jb);
} else { } else {
comm_log("ERROR: uncaught exception, ID=%d\n", id); log("ERROR: uncaught exception, ID=%d\n", id);
while(1); while(1);
} }
} }

View File

@ -5,7 +5,7 @@ import sys
services = [ services = [
("syscalls", [ ("syscalls", [
("rpc", "comm_rpc"), ("rpc", "rpc"),
("rtio_set_o", "rtio_set_o"), ("rtio_set_o", "rtio_set_o"),
("rtio_set_oe", "rtio_set_oe"), ("rtio_set_oe", "rtio_set_oe"),
("rtio_set_sensitivity", "rtio_set_sensitivity"), ("rtio_set_sensitivity", "rtio_set_sensitivity"),

View File

@ -1,24 +0,0 @@
#include <stdio.h>
#include <string.h>
#include <generated/csr.h>
#include "mailbox.h"
#include "kernelcpu.h"
extern char _binary_ksupport_bin_start;
extern char _binary_ksupport_bin_end;
void kernelcpu_start(void *addr)
{
memcpy((void *)KERNELCPU_EXEC_ADDRESS, &_binary_ksupport_bin_start,
&_binary_ksupport_bin_end - &_binary_ksupport_bin_start);
mailbox_acknowledge();
mailbox_send(addr);
kernel_cpu_reset_write(0);
}
void kernelcpu_stop(void)
{
kernel_cpu_reset_write(1);
}

View File

@ -1,12 +0,0 @@
#ifndef __KERNELCPU_H
#define __KERNELCPU_H
#include <hw/common.h>
#define KERNELCPU_EXEC_ADDRESS 0x40020000
#define KERNELCPU_PAYLOAD_ADDRESS 0x40024000
void kernelcpu_start(void *addr);
void kernelcpu_stop(void);
#endif /* __KERNELCPU_H */

111
soc/runtime/kloader.c Normal file
View File

@ -0,0 +1,111 @@
#include <string.h>
#include <generated/csr.h>
#include "log.h"
#include "mailbox.h"
#include "elf_loader.h"
#include "services.h"
#include "kloader.h"
static struct symbol symtab[128];
static int _symtab_count;
static char _symtab_strings[128*16];
static char *_symtab_strptr;
static void symtab_init(void)
{
memset(symtab, 0, sizeof(symtab));
_symtab_count = 0;
_symtab_strptr = _symtab_strings;
}
static int symtab_add(const char *name, void *target)
{
if(_symtab_count >= sizeof(symtab)/sizeof(symtab[0])) {
log("Too many provided symbols in object");
symtab_init();
return 0;
}
symtab[_symtab_count].name = _symtab_strptr;
symtab[_symtab_count].target = target;
_symtab_count++;
while(1) {
if(_symtab_strptr >= &_symtab_strings[sizeof(_symtab_strings)]) {
log("Provided symbol string table overflow");
symtab_init();
return 0;
}
*_symtab_strptr = *name;
_symtab_strptr++;
if(*name == 0)
break;
name++;
}
return 1;
}
int kloader_load(void *buffer, int length)
{
#ifdef ARTIQ_AMP
if(!kernel_cpu_reset_read()) {
log("BUG: attempted to load while kernel CPU running");
return 0;
}
#endif
symtab_init();
return load_elf(
resolve_service_symbol, symtab_add,
buffer, length, (void *)KERNELCPU_PAYLOAD_ADDRESS, 4*1024*1024);
}
kernel_function kloader_find(const char *name)
{
return find_symbol(symtab, name);
}
#ifdef ARTIQ_AMP
extern char _binary_ksupport_bin_start;
extern char _binary_ksupport_bin_end;
static void start_kernel_cpu(void *addr)
{
memcpy((void *)KERNELCPU_EXEC_ADDRESS, &_binary_ksupport_bin_start,
&_binary_ksupport_bin_end - &_binary_ksupport_bin_start);
mailbox_acknowledge();
mailbox_send(addr);
kernel_cpu_reset_write(0);
}
void kloader_start_bridge(void)
{
start_kernel_cpu(NULL);
}
void kloader_start_user_kernel(kernel_function k)
{
if(!kernel_cpu_reset_read()) {
log("BUG: attempted to start kernel CPU while already running (user kernel)");
return;
}
start_kernel_cpu((void *)k);
}
void kloader_start_idle_kernel(void)
{
if(!kernel_cpu_reset_read()) {
log("BUG: attempted to start kernel CPU while already running (idle kernel)");
return;
}
/* TODO */
}
void kloader_stop_kernel(void)
{
kernel_cpu_reset_write(1);
}
#endif

19
soc/runtime/kloader.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef __KLOADER_H
#define __KLOADER_H
#define KERNELCPU_EXEC_ADDRESS 0x40020000
#define KERNELCPU_PAYLOAD_ADDRESS 0x40024000
typedef void (*kernel_function)(void);
int kloader_load(void *buffer, int length);
kernel_function kloader_find(const char *name);
#ifdef ARTIQ_AMP
void kloader_start_bridge(void);
void kloader_start_idle_kernel(void);
void kloader_start_user_kernel(kernel_function k);
void kloader_stop_kernel(void);
#endif
#endif /* __KLOADER_H */

View File

@ -7,8 +7,10 @@
#include "rtio.h" #include "rtio.h"
#include "dds.h" #include "dds.h"
/* for the prototypes for comm_rpc and comm_log */ /* for the prototype for rpc() */
#include "comm.h" #include "session.h"
/* for the prototype for log() */
#include "log.h"
void exception_handler(unsigned long vect, unsigned long *sp); void exception_handler(unsigned long vect, unsigned long *sp);
void exception_handler(unsigned long vect, unsigned long *sp) void exception_handler(unsigned long vect, unsigned long *sp)
@ -59,7 +61,7 @@ int main(void)
while(1); while(1);
} }
int comm_rpc(int rpc_num, ...) int rpc(int rpc_num, ...)
{ {
struct msg_rpc_request request; struct msg_rpc_request request;
struct msg_rpc_reply *reply; struct msg_rpc_reply *reply;
@ -83,7 +85,7 @@ int comm_rpc(int rpc_num, ...)
return retval; return retval;
} }
void comm_log(const char *fmt, ...) void log(const char *fmt, ...)
{ {
struct msg_log request; struct msg_log request;

41
soc/runtime/log.c Normal file
View File

@ -0,0 +1,41 @@
#include <stdarg.h>
#include <stdio.h>
#include "log.h"
static int buffer_index;
static char buffer[LOG_BUFFER_SIZE];
void log_va(const char *fmt, va_list args)
{
char outbuf[256];
int i, len;
len = vscnprintf(outbuf, sizeof(outbuf), fmt, args);
for(i=0;i<len;i++) {
buffer[buffer_index] = outbuf[i];
buffer_index = (buffer_index + 1) % LOG_BUFFER_SIZE;
}
buffer[buffer_index] = '\n';
buffer_index = (buffer_index + 1) % LOG_BUFFER_SIZE;
}
void log(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
log_va(fmt, args);
va_end(args);
}
void log_get(char *outbuf)
{
int i, j;
j = buffer_index + 1;
for(i=0;i<LOG_BUFFER_SIZE;i++) {
outbuf[i] = buffer[j];
j = (j + 1) % LOG_BUFFER_SIZE;
}
}

13
soc/runtime/log.h Normal file
View File

@ -0,0 +1,13 @@
#ifndef __LOG_H
#define __LOG_H
#include <stdarg.h>
#define LOG_BUFFER_SIZE 4096
void log_va(const char *fmt, va_list args);
void log(const char *fmt, ...);
void log_get(char *outbuf);
#endif /* __LOG_H */

View File

@ -8,153 +8,41 @@
#include <generated/csr.h> #include <generated/csr.h>
#include "test_mode.h" #include "test_mode.h"
#include "comm.h" #include "session.h"
#include "kernelcpu.h"
#include "elf_loader.h"
#include "exceptions.h"
#include "services.h"
#include "rtio.h"
#include "dds.h"
#ifdef ARTIQ_AMP void comm_service(void)
#include "mailbox.h"
#include "messages.h"
#endif
static struct symbol symtab[128];
static int _symtab_count;
static char _symtab_strings[128*16];
static char *_symtab_strptr;
static void symtab_init(void)
{ {
memset(symtab, 0, sizeof(symtab)); char *txdata;
_symtab_count = 0; int txlen;
_symtab_strptr = _symtab_strings; static char rxdata;
static int rxpending;
int r, i;
if(!rxpending && uart_read_nonblock()) {
rxdata = uart_read();
rxpending = 1;
}
if(rxpending) {
r = session_input(&rxdata, 1);
if(r > 0)
rxpending = 0;
} }
static int symtab_add(const char *name, void *target) session_poll((void **)&txdata, &txlen);
if(txlen > 0) {
for(i=0;i<txlen;i++)
uart_write(txdata[i]);
session_ack(txlen);
}
}
static void regular_main(void)
{ {
if(_symtab_count >= sizeof(symtab)/sizeof(symtab[0])) { session_start();
comm_log("Too many provided symbols in object"); while(1)
symtab_init(); comm_service();
return 0;
}
symtab[_symtab_count].name = _symtab_strptr;
symtab[_symtab_count].target = target;
_symtab_count++;
while(1) {
if(_symtab_strptr >= &_symtab_strings[sizeof(_symtab_strings)]) {
comm_log("Provided symbol string table overflow");
symtab_init();
return 0;
}
*_symtab_strptr = *name;
_symtab_strptr++;
if(*name == 0)
break;
name++;
} }
return 1;
}
static int load_object(void *buffer, int length)
{
symtab_init();
return load_elf(
resolve_service_symbol, symtab_add,
buffer, length, (void *)KERNELCPU_PAYLOAD_ADDRESS, 4*1024*1024);
}
#ifdef ARTIQ_AMP
static int process_msg(struct msg_base *umsg, int *eid, long long int *eparams)
{
int i;
switch(umsg->type) {
case MESSAGE_TYPE_FINISHED:
return KERNEL_RUN_FINISHED;
case MESSAGE_TYPE_EXCEPTION: {
struct msg_exception *msg = (struct msg_exception *)umsg;
*eid = msg->eid;
for(i=0;i<3;i++)
eparams[i] = msg->eparams[i];
return KERNEL_RUN_EXCEPTION;
}
case MESSAGE_TYPE_RPC_REQUEST: {
struct msg_rpc_request *msg = (struct msg_rpc_request *)umsg;
struct msg_rpc_reply reply;
reply.type = MESSAGE_TYPE_RPC_REPLY;
comm_rpc_va(msg->rpc_num, msg->args, &reply.eid, &reply.retval);
mailbox_send_and_wait(&reply);
return KERNEL_RUN_INVALID_STATUS;
}
case MESSAGE_TYPE_LOG: {
struct msg_log *msg = (struct msg_log *)umsg;
comm_log(msg->fmt, msg->args);
return KERNEL_RUN_INVALID_STATUS;
}
default:
*eid = EID_INTERNAL_ERROR;
for(i=0;i<3;i++)
eparams[i] = 0;
return KERNEL_RUN_EXCEPTION;
}
}
#endif
typedef void (*kernel_function)(void);
static int run_kernel(const char *kernel_name, int *eid, long long int *eparams)
{
kernel_function k;
#ifdef ARTIQ_AMP
int r;
#else
void *jb;
#endif
k = find_symbol(symtab, kernel_name);
if(k == NULL) {
comm_log("Failed to find kernel entry point '%s' in object", kernel_name);
return KERNEL_RUN_STARTUP_FAILED;
}
#ifdef ARTIQ_AMP
kernelcpu_start(k);
while(1) {
struct msg_base *umsg;
umsg = mailbox_receive();
r = KERNEL_RUN_INVALID_STATUS;
if(umsg)
r = process_msg(umsg, eid, eparams);
if(r != KERNEL_RUN_INVALID_STATUS)
break;
}
kernelcpu_stop();
return r;
#else
jb = exception_push();
if(exception_setjmp(jb)) {
*eid = exception_getid(eparams);
return KERNEL_RUN_EXCEPTION;
} else {
dds_init();
rtio_init();
flush_cpu_icache();
k();
exception_pop(1);
return KERNEL_RUN_FINISHED;
}
#endif
}
static void blink_led(void) static void blink_led(void)
{ {
@ -208,7 +96,7 @@ int main(void)
test_main(); test_main();
} else { } else {
puts("Entering regular mode."); puts("Entering regular mode.");
comm_serve(load_object, run_kernel); regular_main();
} }
return 0; return 0;
} }

View File

@ -1,7 +1,7 @@
#include <string.h> #include <string.h>
#include "elf_loader.h" #include "elf_loader.h"
#include "comm.h" #include "session.h"
#include "rtio.h" #include "rtio.h"
#include "dds.h" #include "dds.h"
#include "exceptions.h" #include "exceptions.h"

503
soc/runtime/session.c Normal file
View File

@ -0,0 +1,503 @@
#include <string.h>
#include <stdarg.h>
#include <generated/csr.h>
#ifdef ARTIQ_AMP
#include "mailbox.h"
#include "messages.h"
#else
#include <system.h>
#include "exceptions.h"
#include "rtio.h"
#include "dds.h"
#endif
#include "log.h"
#include "kloader.h"
#include "exceptions.h"
#include "session.h"
#define BUFFER_IN_SIZE (32*1024)
#define BUFFER_OUT_SIZE (32*1024)
static int buffer_in_index;
/* The 9th byte (right after the header) of buffer_in must be aligned
* to a 32-bit boundary for elf_loader to work.
*/
static struct {
char padding[3];
char data[BUFFER_IN_SIZE];
} __attribute__((packed)) _buffer_in __attribute__((aligned(4)));
#define buffer_in _buffer_in.data
static int buffer_out_index;
static char buffer_out[BUFFER_OUT_SIZE];
static int get_in_packet_len(void)
{
int r;
memcpy(&r, &buffer_in[4], 4);
return r;
}
static int get_out_packet_len(void)
{
int r;
memcpy(&r, &buffer_out[4], 4);
return r;
}
static void submit_output(int len)
{
memset(&buffer_out[0], 0x5a, 4);
memcpy(&buffer_out[4], &len, 4);
buffer_out_index = 0;
}
static int user_kernel_state;
enum {
USER_KERNEL_NONE = 0,
USER_KERNEL_LOADED,
USER_KERNEL_RUNNING,
USER_KERNEL_WAIT_RPC /* < must come after _RUNNING */
};
void session_start(void)
{
buffer_in_index = 0;
buffer_out_index = 0;
memset(&buffer_out[4], 0, 4);
#ifdef ARTIQ_AMP
kloader_stop_kernel();
#endif
user_kernel_state = USER_KERNEL_NONE;
}
void session_end(void)
{
#ifdef ARTIQ_AMP
kloader_stop_kernel();
kloader_start_idle_kernel();
#endif
}
/* host to device */
enum {
REMOTEMSG_TYPE_LOG_REQUEST = 1,
REMOTEMSG_TYPE_IDENT_REQUEST,
REMOTEMSG_TYPE_SWITCH_CLOCK,
REMOTEMSG_TYPE_LOAD_OBJECT,
REMOTEMSG_TYPE_RUN_KERNEL,
REMOTEMSG_TYPE_RPC_REPLY
};
/* device to host */
enum {
REMOTEMSG_TYPE_LOG_REPLY = 1,
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,
};
static int add_rpc_value(int bi, int type_tag, void *value)
{
char base_type;
int obi, r;
int i, p;
int len;
obi = bi;
base_type = type_tag;
if((bi + 1) > BUFFER_OUT_SIZE)
return -1;
buffer_out[bi++] = base_type;
switch(base_type) {
case 'n':
return bi - obi;
case 'b':
if((bi + 1) > BUFFER_OUT_SIZE)
return -1;
if(*(char *)value)
buffer_out[bi++] = 1;
else
buffer_out[bi++] = 0;
return bi - obi;
case 'i':
if((bi + 4) > BUFFER_OUT_SIZE)
return -1;
memcpy(&buffer_out[bi], value, 4);
bi += 4;
return bi - obi;
case 'I':
case 'f':
if((bi + 8) > BUFFER_OUT_SIZE)
return -1;
memcpy(&buffer_out[bi], value, 8);
bi += 8;
return bi - obi;
case 'F':
if((bi + 16) > BUFFER_OUT_SIZE)
return -1;
memcpy(&buffer_out[bi], value, 16);
bi += 16;
return bi - obi;
case 'l':
len = *(int *)value;
p = 4;
for(i=0;i<len;i++) {
r = add_rpc_value(bi, type_tag >> 8, (char *)value + p);
if(r < 0)
return r;
bi += r;
p += r;
}
if((bi + 1) > BUFFER_OUT_SIZE)
return -1;
buffer_out[bi++] = 0;
return bi - obi;
}
return -1;
}
static int send_rpc_request(int rpc_num, va_list args)
{
int r;
int bi = 8;
int type_tag;
buffer_out[bi++] = REMOTEMSG_TYPE_RPC_REQUEST;
memcpy(&buffer_out[bi], &rpc_num, 4);
bi += 4;
while((type_tag = va_arg(args, int))) {
r = add_rpc_value(bi, type_tag,
type_tag == 'n' ? NULL : va_arg(args, void *));
if(bi < 0)
return 0;
bi += r;
}
if((bi + 1) > BUFFER_OUT_SIZE)
return 0;
buffer_out[bi++] = 0;
submit_output(bi);
return 1;
}
#ifndef ARTIQ_AMP
static int rpc_reply_eid;
static int rpc_reply_retval;
int rpc(int rpc_num, ...)
{
va_list args;
va_start(args, rpc_num);
send_rpc_request(rpc_num, args);
va_end(args);
user_kernel_state = USER_KERNEL_WAIT_RPC;
while(user_kernel_state == USER_KERNEL_WAIT_RPC)
comm_service();
if(rpc_reply_eid != EID_NONE)
exception_raise(rpc_reply_eid);
return rpc_reply_retval;
}
/* assumes output buffer is empty when called */
static void run_kernel_up(kernel_function k)
{
void *jb;
int eid;
long long eparams[3];
jb = exception_push();
if(exception_setjmp(jb)) {
eid = exception_getid(eparams);
buffer_out[8] = REMOTEMSG_TYPE_KERNEL_EXCEPTION;
memcpy(&buffer_out[9], &eid, 4);
memcpy(&buffer_out[13], eparams, 3*8);
submit_output(9+4+3*8);
} else {
dds_init();
rtio_init();
flush_cpu_icache();
k();
exception_pop(1);
buffer_out[8] = REMOTEMSG_TYPE_KERNEL_FINISHED;
submit_output(9);
}
}
#endif /* !ARTIQ_AMP */
static int process_input(void)
{
switch(buffer_in[8]) {
case REMOTEMSG_TYPE_LOG_REQUEST:
#if (LOG_BUFFER_SIZE + 9) > BUFFER_OUT_SIZE
#error Output buffer cannot hold the log buffer
#endif
buffer_out[8] = REMOTEMSG_TYPE_LOG_REPLY;
log_get(&buffer_out[9]);
submit_output(9 + LOG_BUFFER_SIZE);
break;
case REMOTEMSG_TYPE_IDENT_REQUEST:
buffer_out[8] = REMOTEMSG_TYPE_IDENT_REPLY;
buffer_out[9] = 'A';
buffer_out[10] = 'R';
buffer_out[11] = 'O';
buffer_out[12] = 'R';
submit_output(13);
break;
case REMOTEMSG_TYPE_SWITCH_CLOCK:
if(user_kernel_state >= USER_KERNEL_RUNNING) {
log("Attempted to switch RTIO clock while kernel running");
buffer_out[8] = REMOTEMSG_TYPE_CLOCK_SWITCH_FAILED;
submit_output(9);
break;
}
rtiocrg_clock_sel_write(buffer_in[9]);
buffer_out[8] = REMOTEMSG_TYPE_CLOCK_SWITCH_COMPLETED;
submit_output(9);
break;
case REMOTEMSG_TYPE_LOAD_OBJECT:
if(user_kernel_state >= USER_KERNEL_RUNNING) {
log("Attempted to load new kernel while already running");
buffer_out[8] = REMOTEMSG_TYPE_LOAD_FAILED;
submit_output(9);
break;
}
if(kloader_load(&buffer_in[9], get_in_packet_len() - 8)) {
buffer_out[8] = REMOTEMSG_TYPE_LOAD_COMPLETED;
user_kernel_state = USER_KERNEL_LOADED;
} else
buffer_out[8] = REMOTEMSG_TYPE_LOAD_FAILED;
submit_output(9);
break;
case REMOTEMSG_TYPE_RUN_KERNEL: {
kernel_function k;
if(user_kernel_state != USER_KERNEL_LOADED) {
log("Attempted to run kernel while not in the LOADED state");
buffer_out[8] = REMOTEMSG_TYPE_KERNEL_STARTUP_FAILED;
submit_output(9);
break;
}
if((buffer_in_index + 1) > BUFFER_OUT_SIZE) {
log("Kernel name too long");
buffer_out[8] = REMOTEMSG_TYPE_KERNEL_STARTUP_FAILED;
submit_output(9);
break;
}
buffer_in[buffer_in_index] = 0;
k = kloader_find((char *)&buffer_in[9]);
if(k == NULL) {
log("Failed to find kernel entry point '%s' in object", &buffer_in[9]);
buffer_out[8] = REMOTEMSG_TYPE_KERNEL_STARTUP_FAILED;
submit_output(9);
break;
}
#ifdef ARTIQ_AMP
kloader_start_user_kernel(k);
#else
run_kernel_up(k);
#endif
user_kernel_state = USER_KERNEL_RUNNING;
break;
}
case REMOTEMSG_TYPE_RPC_REPLY: {
#ifdef ARTIQ_AMP
struct msg_rpc_reply reply;
#endif
if(user_kernel_state != USER_KERNEL_WAIT_RPC) {
log("Unsolicited RPC reply");
return 0;
}
#ifdef ARTIQ_AMP
reply.type = MESSAGE_TYPE_RPC_REPLY;
memcpy(&reply.eid, &buffer_in[9], 4);
memcpy(&reply.retval, &buffer_in[13], 4);
mailbox_send_and_wait(&reply);
#else
memcpy(&rpc_reply_eid, &buffer_in[9], 4);
memcpy(&rpc_reply_retval, &buffer_in[13], 4);
#endif
user_kernel_state = USER_KERNEL_RUNNING;
break;
}
default:
return 0;
}
return 1;
}
/* Returns -1 in case of irrecoverable error
* (the session must be dropped and session_end called)
*/
int session_input(void *data, int len)
{
unsigned char *_data = data;
int consumed;
consumed = 0;
while(len > 0) {
/* Make sure the output buffer is available for any reply
* we might need to send. */
if(get_out_packet_len() != 0)
return consumed;
if(buffer_in_index < 4) {
/* synchronizing */
if(_data[consumed] == 0x5a)
buffer_in[buffer_in_index++] = 0x5a;
else
buffer_in_index = 0;
consumed++; len--;
} else if(buffer_in_index < 8) {
/* receiving length */
buffer_in[buffer_in_index++] = _data[consumed];
consumed++; len--;
} else {
/* receiving payload */
int packet_len;
int count;
packet_len = get_in_packet_len();
if(packet_len > BUFFER_IN_SIZE)
return -1;
count = packet_len - buffer_in_index;
if(count > len)
count = len;
memcpy(&buffer_in[buffer_in_index], &_data[consumed], count);
buffer_in_index += count;
if(buffer_in_index == packet_len) {
if(!process_input())
return -1;
buffer_in_index = 0;
}
consumed += count; len -= count;
}
}
return consumed;
}
#ifdef ARTIQ_AMP
/* assumes output buffer is empty when called */
static void process_kmsg(struct msg_base *umsg)
{
if(user_kernel_state != USER_KERNEL_RUNNING) {
log("Received message from kernel CPU while not in running state");
return;
}
switch(umsg->type) {
case MESSAGE_TYPE_FINISHED:
buffer_out[8] = REMOTEMSG_TYPE_KERNEL_FINISHED;
submit_output(9);
kloader_stop_kernel();
user_kernel_state = USER_KERNEL_LOADED;
break;
case MESSAGE_TYPE_EXCEPTION: {
struct msg_exception *msg = (struct msg_exception *)umsg;
buffer_out[8] = REMOTEMSG_TYPE_KERNEL_EXCEPTION;
memcpy(&buffer_out[9], &msg->eid, 4);
memcpy(&buffer_out[13], msg->eparams, 3*8);
submit_output(9+4+3*8);
kloader_stop_kernel();
user_kernel_state = USER_KERNEL_LOADED;
break;
}
case MESSAGE_TYPE_RPC_REQUEST: {
struct msg_rpc_request *msg = (struct msg_rpc_request *)umsg;
send_rpc_request(msg->rpc_num, msg->args);
user_kernel_state = USER_KERNEL_WAIT_RPC;
break;
}
case MESSAGE_TYPE_LOG: {
struct msg_log *msg = (struct msg_log *)umsg;
log(msg->fmt, msg->args);
break;
}
default: {
int eid;
log("Received invalid message type from kernel CPU");
buffer_out[8] = REMOTEMSG_TYPE_KERNEL_EXCEPTION;
eid = EID_INTERNAL_ERROR;
memcpy(&buffer_out[9], &eid, 4);
memset(&buffer_out[13], 0, 3*8);
submit_output(9+4+3*8);
kloader_stop_kernel();
user_kernel_state = USER_KERNEL_LOADED;
break;
}
}
}
#endif /* ARTIQ_AMP */
void session_poll(void **data, int *len)
{
int l;
l = get_out_packet_len();
#ifdef ARTIQ_AMP
/* If the output buffer is available,
* check if the kernel CPU has something to transmit.
*/
if(l == 0) {
struct msg_base *umsg;
umsg = mailbox_receive();
if(umsg) {
process_kmsg(umsg);
mailbox_acknowledge();
}
l = get_out_packet_len();
}
#endif
*len = l - buffer_out_index;
*data = &buffer_out[buffer_out_index];
}
void session_ack(int len)
{
buffer_out_index += len;
if(buffer_out_index >= get_out_packet_len()) {
memset(&buffer_out[4], 0, 4);
buffer_out_index = 0;
}
}

14
soc/runtime/session.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef __SESSION_H
#define __SESSION_H
void session_start(void);
void session_end(void);
int session_input(void *data, int len);
void session_poll(void **data, int *len);
void session_ack(int len);
int rpc(int rpc_num, ...);
void comm_service(void);
#endif /* __SESSION_H */

View File

@ -12,7 +12,7 @@
#ifdef ARTIQ_AMP #ifdef ARTIQ_AMP
#include "kernelcpu.h" #include "kloader.h"
#include "mailbox.h" #include "mailbox.h"
#include "messages.h" #include "messages.h"
@ -20,7 +20,7 @@ static void amp_bridge_init(void)
{ {
struct msg_base *umsg; struct msg_base *umsg;
kernelcpu_start(NULL); kloader_start_bridge();
while(1) { while(1) {
umsg = mailbox_wait_and_receive(); umsg = mailbox_wait_and_receive();