mirror of
https://github.com/m-labs/artiq.git
synced 2024-12-28 20:53:35 +08:00
comm: refactor to support lwip event model
This commit is contained in:
parent
9f52277245
commit
18106cc014
@ -1,10 +1,8 @@
|
||||
import struct
|
||||
import zlib
|
||||
import logging
|
||||
from enum import Enum
|
||||
from fractions import Fraction
|
||||
|
||||
from artiq.language import units
|
||||
from artiq.coredevice.runtime import Environment
|
||||
from artiq.coredevice import runtime_exceptions
|
||||
from artiq.language import core as core_language
|
||||
@ -15,33 +13,30 @@ logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class _H2DMsgType(Enum):
|
||||
LINK_MESSAGE = 1
|
||||
|
||||
REQUEST_IDENT = 2
|
||||
LOG_REQUEST = 1
|
||||
IDENT_REQUEST = 2
|
||||
SWITCH_CLOCK = 3
|
||||
|
||||
LOAD_OBJECT = 4
|
||||
RUN_KERNEL = 5
|
||||
|
||||
RPC_REPLY = 6
|
||||
|
||||
|
||||
class _D2HMsgType(Enum):
|
||||
MESSAGE_UNRECOGNIZED = 1
|
||||
LOG = 2
|
||||
LOG_REPLY = 1
|
||||
IDENT_REPLY = 2
|
||||
CLOCK_SWITCH_COMPLETED = 3
|
||||
CLOCK_SWITCH_FAILED = 4
|
||||
|
||||
IDENT = 3
|
||||
CLOCK_SWITCH_COMPLETED = 4
|
||||
CLOCK_SWITCH_FAILED = 5
|
||||
LOAD_COMPLETED = 5
|
||||
LOAD_FAILED = 6
|
||||
|
||||
OBJECT_LOADED = 6
|
||||
OBJECT_INCORRECT_LENGTH = 7
|
||||
OBJECT_CRC_FAILED = 8
|
||||
OBJECT_UNRECOGNIZED = 9
|
||||
KERNEL_FINISHED = 7
|
||||
KERNEL_STARTUP_FAILED = 8
|
||||
KERNEL_EXCEPTION = 9
|
||||
|
||||
KERNEL_FINISHED = 10
|
||||
KERNEL_STARTUP_FAILED = 11
|
||||
KERNEL_EXCEPTION = 12
|
||||
|
||||
RPC_REQUEST = 13
|
||||
RPC_REQUEST = 10
|
||||
|
||||
|
||||
class UnsupportedDevice(Exception):
|
||||
@ -71,39 +66,35 @@ class CommGeneric:
|
||||
raise NotImplementedError
|
||||
#
|
||||
|
||||
def _read(self, length):
|
||||
def _read_header(self):
|
||||
self.open()
|
||||
return self.read(length)
|
||||
|
||||
def _write(self, data):
|
||||
self.open()
|
||||
self.write(data)
|
||||
|
||||
def _get_device_msg(self):
|
||||
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)
|
||||
sync_count = 0
|
||||
while sync_count < 4:
|
||||
(c, ) = struct.unpack("B", self.read(1))
|
||||
if c == 0x5a:
|
||||
sync_count += 1
|
||||
else:
|
||||
logger.debug("message received: %r", msg)
|
||||
return msg
|
||||
sync_count = 0
|
||||
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):
|
||||
self._write(struct.pack(">lb", 0x5a5a5a5a,
|
||||
_H2DMsgType.REQUEST_IDENT.value))
|
||||
msg = self._get_device_msg()
|
||||
if msg != _D2HMsgType.IDENT:
|
||||
raise IOError("Incorrect reply from device: {}".format(msg))
|
||||
(reply, ) = struct.unpack("B", self._read(1))
|
||||
self._write_header(9, _H2DMsgType.IDENT_REQUEST)
|
||||
_, ty = self._read_header()
|
||||
if ty != _D2HMsgType.IDENT_REPLY:
|
||||
raise IOError("Incorrect reply from device: {}".format(ty))
|
||||
(reply, ) = struct.unpack("B", self.read(1))
|
||||
runtime_id = chr(reply)
|
||||
for i in range(3):
|
||||
(reply, ) = struct.unpack("B", self._read(1))
|
||||
(reply, ) = struct.unpack("B", self.read(1))
|
||||
runtime_id += chr(reply)
|
||||
if runtime_id != "AROR":
|
||||
raise UnsupportedDevice("Unsupported runtime ID: {}"
|
||||
@ -111,63 +102,59 @@ class CommGeneric:
|
||||
return Environment()
|
||||
|
||||
def switch_clock(self, external):
|
||||
self._write(struct.pack(
|
||||
">lbb", 0x5a5a5a5a, _H2DMsgType.SWITCH_CLOCK.value,
|
||||
int(external)))
|
||||
msg = self._get_device_msg()
|
||||
if msg != _D2HMsgType.CLOCK_SWITCH_COMPLETED:
|
||||
raise IOError("Incorrect reply from device: {}".format(msg))
|
||||
self._write_header(10, _H2DMsgType.SWITCH_CLOCK)
|
||||
self.write(struct.pack("B", int(external)))
|
||||
_, ty = self._read_header()
|
||||
if ty != _D2HMsgType.CLOCK_SWITCH_COMPLETED:
|
||||
raise IOError("Incorrect reply from device: {}".format(ty))
|
||||
|
||||
def load(self, kcode):
|
||||
self._write(struct.pack(
|
||||
">lblL",
|
||||
0x5a5a5a5a, _H2DMsgType.LOAD_OBJECT.value,
|
||||
len(kcode), zlib.crc32(kcode)))
|
||||
self._write(kcode)
|
||||
msg = self._get_device_msg()
|
||||
if msg != _D2HMsgType.OBJECT_LOADED:
|
||||
raise IOError("Incorrect reply from device: "+str(msg))
|
||||
self._write_header(len(kcode) + 9, _H2DMsgType.LOAD_OBJECT)
|
||||
self.write(kcode)
|
||||
_, ty = self._read_header()
|
||||
if ty != _D2HMsgType.LOAD_COMPLETED:
|
||||
raise IOError("Incorrect reply from device: "+str(ty))
|
||||
|
||||
def run(self, kname):
|
||||
self._write(struct.pack(
|
||||
">lbl", 0x5a5a5a5a, _H2DMsgType.RUN_KERNEL.value, len(kname)))
|
||||
for c in kname:
|
||||
self._write(struct.pack(">B", ord(c)))
|
||||
self._write_header(len(kname) + 9, _H2DMsgType.RUN_KERNEL)
|
||||
self.write(bytes(kname, "ascii"))
|
||||
logger.debug("running kernel: %s", kname)
|
||||
|
||||
def _receive_rpc_values(self):
|
||||
r = []
|
||||
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":
|
||||
return r
|
||||
if type_tag == "n":
|
||||
r.append(None)
|
||||
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":
|
||||
r.append(struct.unpack(">l", self._read(4))[0])
|
||||
r.append(struct.unpack(">l", self.read(4))[0])
|
||||
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":
|
||||
r.append(struct.unpack(">d", self._read(8))[0])
|
||||
r.append(struct.unpack(">d", self.read(8))[0])
|
||||
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))
|
||||
if type_tag == "l":
|
||||
r.append(self._receive_rpc_values())
|
||||
|
||||
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()
|
||||
logger.debug("rpc service: %d %r", rpc_num, args)
|
||||
eid, r = rpc_wrapper.run_rpc(
|
||||
user_exception_map, rpc_map[rpc_num], args)
|
||||
self._write(struct.pack(">ll", eid, r))
|
||||
logger.debug("rpc service: %d %r == %r", rpc_num, args, r)
|
||||
self._write_header(9+2*4, _H2DMsgType.RPC_REPLY)
|
||||
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):
|
||||
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)
|
||||
if eid < core_language.first_user_eid:
|
||||
exception = runtime_exceptions.exception_map[eid]
|
||||
@ -179,17 +166,24 @@ class CommGeneric:
|
||||
def serve(self, rpc_map, user_exception_map):
|
||||
rpc_wrapper = RPCWrapper()
|
||||
while True:
|
||||
msg = self._get_device_msg()
|
||||
if msg == _D2HMsgType.RPC_REQUEST:
|
||||
_, ty = self._read_header()
|
||||
if ty == _D2HMsgType.RPC_REQUEST:
|
||||
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)
|
||||
elif msg == _D2HMsgType.KERNEL_FINISHED:
|
||||
elif ty == _D2HMsgType.KERNEL_FINISHED:
|
||||
return
|
||||
else:
|
||||
raise IOError("Incorrect request from device: "+str(msg))
|
||||
raise IOError("Incorrect request from device: "+str(ty))
|
||||
|
||||
def send_link_message(self, data):
|
||||
self._write(struct.pack(
|
||||
">lb", 0x5a5a5a5a, _H2DMsgType.LINK_MESSAGE.value))
|
||||
self._write(data)
|
||||
def get_log(self):
|
||||
self._write_header(9, _H2DMsgType.LOG_REQUEST)
|
||||
length, ty = self._read_header()
|
||||
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
|
||||
|
@ -17,15 +17,12 @@ class Comm(CommGeneric, AutoDB):
|
||||
def open(self):
|
||||
if hasattr(self, "port"):
|
||||
return
|
||||
self.port = serial.serial_for_url(self.serial_dev, baudrate=115200)
|
||||
self.port.flush()
|
||||
self.set_remote_baud(self.baud_rate)
|
||||
self.set_baud(self.baud_rate)
|
||||
self.port = serial.serial_for_url(self.serial_dev,
|
||||
baudrate=self.baud_rate)
|
||||
|
||||
def close(self):
|
||||
if not hasattr(self, "port"):
|
||||
return
|
||||
self.set_remote_baud(115200)
|
||||
self.port.close()
|
||||
del self.port
|
||||
|
||||
@ -42,27 +39,3 @@ class Comm(CommGeneric, AutoDB):
|
||||
written = self.port.write(data[pos:])
|
||||
remaining -= 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)
|
||||
|
@ -1,6 +1,6 @@
|
||||
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
|
||||
|
||||
# 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)
|
||||
|
||||
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
|
||||
CFLAGS += -DARTIQ_AMP
|
||||
SERVICE_TABLE_INPUT = ksupport.elf
|
||||
|
@ -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 */
|
@ -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);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "comm.h"
|
||||
#include "log.h"
|
||||
#include "elf_loader.h"
|
||||
|
||||
#define EI_NIDENT 16
|
||||
@ -85,11 +85,11 @@ struct elf32_sym {
|
||||
|
||||
#define SANITIZE_OFFSET_SIZE(offset, size) \
|
||||
if(offset > 0x10000000) { \
|
||||
comm_log("Incorrect offset in ELF data"); \
|
||||
log("Incorrect offset in ELF data"); \
|
||||
return 0; \
|
||||
} \
|
||||
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; \
|
||||
}
|
||||
|
||||
@ -121,7 +121,7 @@ static int fixup(void *dest, int dest_length, struct elf32_rela *rela, void *tar
|
||||
val = _target - (_dest + offset);
|
||||
_dest[offset] = (_dest[offset] & 0xfc000000) | (val & 0x03ffffff);
|
||||
} else
|
||||
comm_log("Unsupported relocation type: %d", type);
|
||||
log("Unsupported relocation type: %d", type);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -141,15 +141,15 @@ int load_elf(symbol_resolver resolver, symbol_callback callback, void *elf_data,
|
||||
/* validate ELF */
|
||||
GET_POINTER_SAFE(ehdr, struct elf32_ehdr, 0);
|
||||
if(memcmp(ehdr->ident, elf_magic_header, sizeof(elf_magic_header)) != 0) {
|
||||
comm_log("Incorrect ELF header");
|
||||
log("Incorrect ELF header");
|
||||
return 0;
|
||||
}
|
||||
if(ehdr->type != ET_REL) {
|
||||
comm_log("ELF is not relocatable");
|
||||
log("ELF is not relocatable");
|
||||
return 0;
|
||||
}
|
||||
if(ehdr->machine != EM_OR1K) {
|
||||
comm_log("ELF is for a different machine");
|
||||
log("ELF is for a different machine");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -190,7 +190,7 @@ int load_elf(symbol_resolver resolver, symbol_callback callback, void *elf_data,
|
||||
|
||||
/* load .text section */
|
||||
if(textsize > dest_length) {
|
||||
comm_log(".text section is too large");
|
||||
log(".text section is too large");
|
||||
return 0;
|
||||
}
|
||||
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;
|
||||
target = resolver(name);
|
||||
if(target == NULL) {
|
||||
comm_log("Undefined symbol: %s", name);
|
||||
log("Undefined symbol: %s", name);
|
||||
return 0;
|
||||
}
|
||||
if(!fixup(dest, dest_length, rela, target))
|
||||
return 0;
|
||||
} else {
|
||||
comm_log("Unsupported relocation");
|
||||
log("Unsupported relocation");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <generated/csr.h>
|
||||
|
||||
#include "comm.h"
|
||||
#include "log.h"
|
||||
#include "exceptions.h"
|
||||
|
||||
#define MAX_EXCEPTION_CONTEXTS 64
|
||||
@ -52,7 +52,7 @@ void exception_raise_params(int id,
|
||||
stored_params[2] = p2;
|
||||
exception_longjmp(exception_contexts[--ec_top].jb);
|
||||
} else {
|
||||
comm_log("ERROR: uncaught exception, ID=%d\n", id);
|
||||
log("ERROR: uncaught exception, ID=%d\n", id);
|
||||
while(1);
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import sys
|
||||
|
||||
services = [
|
||||
("syscalls", [
|
||||
("rpc", "comm_rpc"),
|
||||
("rpc", "rpc"),
|
||||
("rtio_set_o", "rtio_set_o"),
|
||||
("rtio_set_oe", "rtio_set_oe"),
|
||||
("rtio_set_sensitivity", "rtio_set_sensitivity"),
|
||||
|
@ -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);
|
||||
}
|
@ -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
111
soc/runtime/kloader.c
Normal 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
19
soc/runtime/kloader.h
Normal 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 */
|
@ -7,8 +7,10 @@
|
||||
#include "rtio.h"
|
||||
#include "dds.h"
|
||||
|
||||
/* for the prototypes for comm_rpc and comm_log */
|
||||
#include "comm.h"
|
||||
/* for the prototype for rpc() */
|
||||
#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)
|
||||
@ -59,7 +61,7 @@ int main(void)
|
||||
while(1);
|
||||
}
|
||||
|
||||
int comm_rpc(int rpc_num, ...)
|
||||
int rpc(int rpc_num, ...)
|
||||
{
|
||||
struct msg_rpc_request request;
|
||||
struct msg_rpc_reply *reply;
|
||||
@ -83,7 +85,7 @@ int comm_rpc(int rpc_num, ...)
|
||||
return retval;
|
||||
}
|
||||
|
||||
void comm_log(const char *fmt, ...)
|
||||
void log(const char *fmt, ...)
|
||||
{
|
||||
struct msg_log request;
|
||||
|
||||
|
41
soc/runtime/log.c
Normal file
41
soc/runtime/log.c
Normal 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
13
soc/runtime/log.h
Normal 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 */
|
@ -8,153 +8,41 @@
|
||||
#include <generated/csr.h>
|
||||
|
||||
#include "test_mode.h"
|
||||
#include "comm.h"
|
||||
#include "kernelcpu.h"
|
||||
#include "elf_loader.h"
|
||||
#include "exceptions.h"
|
||||
#include "services.h"
|
||||
#include "rtio.h"
|
||||
#include "dds.h"
|
||||
#include "session.h"
|
||||
|
||||
#ifdef ARTIQ_AMP
|
||||
#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)
|
||||
void comm_service(void)
|
||||
{
|
||||
memset(symtab, 0, sizeof(symtab));
|
||||
_symtab_count = 0;
|
||||
_symtab_strptr = _symtab_strings;
|
||||
char *txdata;
|
||||
int txlen;
|
||||
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;
|
||||
}
|
||||
|
||||
session_poll((void **)&txdata, &txlen);
|
||||
if(txlen > 0) {
|
||||
for(i=0;i<txlen;i++)
|
||||
uart_write(txdata[i]);
|
||||
session_ack(txlen);
|
||||
}
|
||||
}
|
||||
|
||||
static int symtab_add(const char *name, void *target)
|
||||
static void regular_main(void)
|
||||
{
|
||||
if(_symtab_count >= sizeof(symtab)/sizeof(symtab[0])) {
|
||||
comm_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)]) {
|
||||
comm_log("Provided symbol string table overflow");
|
||||
symtab_init();
|
||||
return 0;
|
||||
}
|
||||
*_symtab_strptr = *name;
|
||||
_symtab_strptr++;
|
||||
if(*name == 0)
|
||||
break;
|
||||
name++;
|
||||
}
|
||||
|
||||
return 1;
|
||||
session_start();
|
||||
while(1)
|
||||
comm_service();
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -208,7 +96,7 @@ int main(void)
|
||||
test_main();
|
||||
} else {
|
||||
puts("Entering regular mode.");
|
||||
comm_serve(load_object, run_kernel);
|
||||
regular_main();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "elf_loader.h"
|
||||
#include "comm.h"
|
||||
#include "session.h"
|
||||
#include "rtio.h"
|
||||
#include "dds.h"
|
||||
#include "exceptions.h"
|
||||
|
503
soc/runtime/session.c
Normal file
503
soc/runtime/session.c
Normal 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
14
soc/runtime/session.h
Normal 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 */
|
@ -12,7 +12,7 @@
|
||||
|
||||
#ifdef ARTIQ_AMP
|
||||
|
||||
#include "kernelcpu.h"
|
||||
#include "kloader.h"
|
||||
#include "mailbox.h"
|
||||
#include "messages.h"
|
||||
|
||||
@ -20,7 +20,7 @@ static void amp_bridge_init(void)
|
||||
{
|
||||
struct msg_base *umsg;
|
||||
|
||||
kernelcpu_start(NULL);
|
||||
kloader_start_bridge();
|
||||
|
||||
while(1) {
|
||||
umsg = mailbox_wait_and_receive();
|
||||
|
Loading…
Reference in New Issue
Block a user