forked from M-Labs/artiq
comm: refactor to support lwip event model
This commit is contained in:
parent
9f52277245
commit
18106cc014
|
@ -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
|
||||||
|
|
|
@ -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)
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 <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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"),
|
||||||
|
|
|
@ -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 */
|
|
|
@ -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
|
|
@ -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 "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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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 <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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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])) {
|
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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
#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();
|
||||||
|
|
Loading…
Reference in New Issue