2
0
mirror of https://github.com/m-labs/artiq.git synced 2024-12-25 19:28:26 +08:00

runtime: implement mailbox, use it for kernel startup, exceptions and termination

This commit is contained in:
Sebastien Bourdeauducq 2015-04-05 22:04:50 +08:00
parent 7ea9250b31
commit 72f9f7ed79
13 changed files with 236 additions and 60 deletions

View File

@ -5,8 +5,8 @@ from artiq.language.core import RuntimeException
# Must be kept in sync with soc/runtime/exceptions.h
class OutOfMemory(RuntimeException):
"""Raised when the runtime fails to allocate memory.
class InternalError(RuntimeException):
"""Raised when the runtime encounters an internal error condition.
"""
eid = 1

View File

@ -1,19 +1,20 @@
include $(MSCDIR)/software/common.mak
OBJECTS_SERVICES=exception_jmp.o exceptions.o rtio.o dds.o
OBJECTS=isr.o elf_loader.o services.o comm_serial.o test_mode.o main.o
OBJECTS := isr.o elf_loader.o services.o comm_serial.o test_mode.o main.o
OBJECTS_KSUPPORT := exception_jmp.o exceptions.o rtio.o dds.o
# NOTE: this does not handle dependencies well. Run "make clean"
# when switching between UP and AMP.
UNIPROCESSOR := $(shell echo -e "\#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 += kernelcpu.o ksupport_data.o
OBJECTS += mailbox.o kernelcpu.o ksupport_data.o
OBJECTS_KSUPPORT += mailbox.o ksupport.o
CFLAGS += -DARTIQ_AMP
SERVICE_TABLE_INPUT = ksupport.elf
else
ifeq ($(UNIPROCESSOR),1)
OBJECTS += $(OBJECTS_SERVICES)
OBJECTS += $(OBJECTS_KSUPPORT)
else
$(error failed to determine UP/AMP build)
endif
@ -32,8 +33,6 @@ all: runtime.bin
$(MSCDIR)/mkmscimg.py -f -o $@ $<
runtime.elf: $(OBJECTS) libs
%.elf:
$(LD) $(LDFLAGS) \
-T linker.ld \
-N -o $@ \
@ -44,7 +43,7 @@ runtime.elf: $(OBJECTS) libs
-lbase -lcompiler-rt
@chmod -x $@
ksupport.elf: $(OBJECTS_SERVICES) ksupport.o
ksupport.elf: $(OBJECTS_KSUPPORT)
$(LD) $(LDFLAGS) \
-T ksupport.ld \
-N -o $@ \
@ -74,8 +73,8 @@ libs:
$(MAKE) -C $(MSCDIR)/software/libbase
clean:
$(RM) $(OBJECTS) $(OBJECTS:.o=.d) $(OBJECTS_SERVICES) $(OBJECTS_SERVICES:.o=.d)
$(RM) $(OBJECTS) $(OBJECTS:.o=.d) $(OBJECTS_KSUPPORT) $(OBJECTS_KSUPPORT:.o=.d)
$(RM) runtime.elf runtime.bin runtime.fbi .*~ *~
$(RM) service_table.h ksupport.d ksupport.o ksupport.elf ksupport.bin
$(RM) service_table.h ksupport.elf ksupport.bin
.PHONY: all main.o clean libs load

View File

@ -2,13 +2,15 @@
#define __COMM_H
enum {
KERNEL_RUN_FINISHED,
KERNEL_RUN_EXCEPTION,
KERNEL_RUN_STARTUP_FAILED
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 *);
typedef int (*kernel_runner)(const char *, int *, long long int *);
void comm_serve(object_loader load_object, kernel_runner run_kernel);
int comm_rpc(int rpc_num, ...);

View File

@ -132,6 +132,7 @@ static void receive_and_run_kernel(kernel_runner run_kernel)
int i;
char kernel_name[256];
int r, eid;
long long int eparams[3];
length = receive_int();
if(length > (sizeof(kernel_name)-1)) {
@ -142,7 +143,7 @@ static void receive_and_run_kernel(kernel_runner run_kernel)
kernel_name[i] = receive_char();
kernel_name[length] = 0;
r = run_kernel(kernel_name, &eid);
r = run_kernel(kernel_name, &eid, eparams);
switch(r) {
case KERNEL_RUN_FINISHED:
send_char(MSGTYPE_KERNEL_FINISHED);
@ -151,12 +152,7 @@ static void receive_and_run_kernel(kernel_runner run_kernel)
send_char(MSGTYPE_KERNEL_EXCEPTION);
send_int(eid);
for(i=0;i<3;i++)
#ifdef ARTIQ_AMP
#warning TODO
send_llint(0LL);
#else
send_llint(exception_params[i]);
#endif
send_llint(eparams[i]);
break;
case KERNEL_RUN_STARTUP_FAILED:
send_char(MSGTYPE_KERNEL_STARTUP_FAILED);

View File

@ -1,7 +1,11 @@
#include <generated/csr.h>
#include "exceptions.h"
#ifndef ARTIQ_AMP
#ifdef ARTIQ_AMP
#include "mailbox.h"
#include "messages.h"
#else
#include "comm.h"
#endif
@ -14,12 +18,12 @@ struct exception_context {
static struct exception_context exception_contexts[MAX_EXCEPTION_CONTEXTS];
static int ec_top;
static int stored_id;
long long int exception_params[3];
static long long int stored_params[3];
void *exception_push(void)
{
if(ec_top >= MAX_EXCEPTION_CONTEXTS)
exception_raise(EID_OUT_OF_MEMORY);
exception_raise(EID_INTERNAL_ERROR);
return exception_contexts[ec_top++].jb;
}
@ -28,8 +32,13 @@ void exception_pop(int levels)
ec_top -= levels;
}
int exception_getid(void)
int exception_getid(long long int *eparams)
{
int i;
if(eparams)
for(i=0;i<3;i++)
eparams[i] = stored_params[i];
return stored_id;
}
@ -44,13 +53,20 @@ void exception_raise_params(int id,
{
if(ec_top > 0) {
stored_id = id;
exception_params[0] = p0;
exception_params[1] = p1;
exception_params[2] = p2;
stored_params[0] = p0;
stored_params[1] = p1;
stored_params[2] = p2;
exception_longjmp(exception_contexts[--ec_top].jb);
} else {
#ifdef ARTIQ_AMP
#warning TODO
struct msg_exception msg;
int i;
msg.type = MESSAGE_TYPE_EXCEPTION;
msg.eid = EID_INTERNAL_ERROR;
for(i=0;i<3;i++)
msg.eparams[i] = 0;
mailbox_send_and_wait(&msg);
#else
comm_log("ERROR: uncaught exception, ID=%d\n", id);
#endif

View File

@ -3,21 +3,19 @@
enum {
EID_NONE = 0,
EID_OUT_OF_MEMORY = 1,
EID_INTERNAL_ERROR = 1,
EID_RPC_EXCEPTION = 2,
EID_RTIO_UNDERFLOW = 3,
EID_RTIO_SEQUENCE_ERROR = 4,
EID_RTIO_OVERFLOW = 5,
};
extern long long int exception_params[3];
int exception_setjmp(void *jb) __attribute__((returns_twice));
void exception_longjmp(void *jb) __attribute__((noreturn));
void *exception_push(void);
void exception_pop(int levels);
int exception_getid(void);
int exception_getid(long long int *eparams);
void exception_raise(int id) __attribute__((noreturn));
void exception_raise_params(int id,
long long int p0, long long int p1,

View File

@ -1,9 +1,9 @@
#include <stdio.h>
#include <string.h>
#include <system.h>
#include <generated/csr.h>
#include "mailbox.h"
#include "kernelcpu.h"
extern char _binary_ksupport_bin_start;
@ -13,8 +13,8 @@ void kernelcpu_start(void *addr)
{
memcpy((void *)KERNELCPU_EXEC_ADDRESS, &_binary_ksupport_bin_start,
&_binary_ksupport_bin_end - &_binary_ksupport_bin_start);
KERNELCPU_MAILBOX = (unsigned int)addr;
flush_l2_cache();
mailbox_acknowledge();
mailbox_send(addr);
kernel_cpu_reset_write(0);
}

View File

@ -6,8 +6,6 @@
#define KERNELCPU_EXEC_ADDRESS 0x40020000
#define KERNELCPU_PAYLOAD_ADDRESS 0x40024000
#define KERNELCPU_MAILBOX MMPTR(0xd0000000)
void kernelcpu_start(void *addr);
void kernelcpu_stop(void);

View File

@ -1,14 +1,21 @@
#include "kernelcpu.h"
#include "exceptions.h"
#include "comm.h"
#include "mailbox.h"
#include "messages.h"
#include "rtio.h"
#include "dds.h"
void exception_handler(unsigned long vect, unsigned long *sp);
void exception_handler(unsigned long vect, unsigned long *sp)
{
/* TODO: report hardware exception to comm CPU */
for(;;);
struct msg_exception msg;
int i;
msg.type = MESSAGE_TYPE_EXCEPTION;
msg.eid = EID_INTERNAL_ERROR;
for(i=0;i<3;i++)
msg.eparams[i] = 0;
mailbox_send_and_wait(&msg);
while(1);
}
typedef void (*kernel_function)(void);
@ -19,17 +26,26 @@ int main(void)
kernel_function k;
void *jb;
k = (kernel_function)KERNELCPU_MAILBOX;
jb = exception_push();
if(exception_setjmp(jb))
KERNELCPU_MAILBOX = KERNEL_RUN_EXCEPTION;
else {
if(exception_setjmp(jb)) {
struct msg_exception msg;
msg.type = MESSAGE_TYPE_EXCEPTION;
msg.eid = exception_getid(msg.eparams);
mailbox_send_and_wait(&msg);
} else {
struct msg_finished msg;
k = mailbox_receive();
if(!k)
exception_raise(EID_INTERNAL_ERROR);
dds_init();
rtio_init();
k();
exception_pop(1);
KERNELCPU_MAILBOX = KERNEL_RUN_FINISHED;
msg.type = MESSAGE_TYPE_FINISHED;
mailbox_send_and_wait(&msg);
}
while(1);
}

81
soc/runtime/mailbox.c Normal file
View File

@ -0,0 +1,81 @@
#include <stdlib.h>
#include <system.h>
#include <spr-defs.h>
#include <hw/common.h>
#include "mailbox.h"
#define KERNELCPU_MAILBOX MMPTR(0xd0000000)
static unsigned int last_transmission;
static void _flush_cpu_dcache(void)
{
unsigned long dccfgr;
unsigned long cache_set_size;
unsigned long cache_ways;
unsigned long cache_block_size;
unsigned long cache_size;
int i;
dccfgr = mfspr(SPR_DCCFGR);
cache_ways = 1 << (dccfgr & SPR_ICCFGR_NCW);
cache_set_size = 1 << ((dccfgr & SPR_DCCFGR_NCS) >> 3);
cache_block_size = (dccfgr & SPR_DCCFGR_CBS) ? 32 : 16;
cache_size = cache_set_size * cache_ways * cache_block_size;
for (i = 0; i < cache_size; i += cache_block_size)
mtspr(SPR_DCBIR, i);
}
/* TODO: do not use L2 cache in AMP systems */
static void _flush_l2_cache(void)
{
unsigned int i;
register unsigned int addr;
register unsigned int dummy;
for(i=0;i<2*8192/4;i++) {
addr = 0x40000000 + i*4;
__asm__ volatile("l.lwz %0, 0(%1)\n":"=r"(dummy):"r"(addr));
}
}
void mailbox_send(void *ptr)
{
_flush_l2_cache();
last_transmission = (unsigned int)ptr;
KERNELCPU_MAILBOX = last_transmission;
}
int mailbox_acknowledged(void)
{
return KERNELCPU_MAILBOX != last_transmission;
}
void mailbox_send_and_wait(void *ptr)
{
mailbox_send(ptr);
while(!mailbox_acknowledged());
}
void *mailbox_receive(void)
{
unsigned int r;
r = KERNELCPU_MAILBOX;
if(r == last_transmission)
return NULL;
else {
if(r) {
_flush_l2_cache();
_flush_cpu_dcache();
}
return (void *)r;
}
}
void mailbox_acknowledge(void)
{
KERNELCPU_MAILBOX = 0;
}

11
soc/runtime/mailbox.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef __MAILBOX_H
#define __MAILBOX_H
void mailbox_send(void *ptr);
int mailbox_acknowledged(void);
void mailbox_send_and_wait(void *ptr);
void *mailbox_receive(void);
void mailbox_acknowledge(void);
#endif /* __MAILBOX_H */

View File

@ -10,12 +10,17 @@
#include "test_mode.h"
#include "comm.h"
#include "elf_loader.h"
#include "kernelcpu.h"
#include "exceptions.h"
#include "services.h"
#include "rtio.h"
#include "dds.h"
#ifdef ARTIQ_AMP
#include "kernelcpu.h"
#include "mailbox.h"
#include "messages.h"
#endif
static struct symbol symtab[128];
static int _symtab_count;
static char _symtab_strings[128*16];
@ -63,15 +68,44 @@ static int load_object(void *buffer, int length)
buffer, length, (void *)KERNELCPU_PAYLOAD_ADDRESS, 4*1024*1024);
}
#ifdef ARTIQ_AMP
static int process_msg(struct msg_unknown *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;
}
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)
static int run_kernel(const char *kernel_name, int *eid, long long int *eparams)
{
kernel_function k;
#ifndef ARTIQ_AMP
#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);
@ -80,20 +114,22 @@ static int run_kernel(const char *kernel_name, int *eid)
#ifdef ARTIQ_AMP
kernelcpu_start(k);
*eid = 0;
while(1) {
unsigned int r;
struct msg_unknown *umsg;
r = KERNELCPU_MAILBOX;
if(r < 0x40000000) {
kernelcpu_stop();
return r;
}
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();
*eid = exception_getid(eparams);
return KERNEL_RUN_EXCEPTION;
} else {
dds_init();

23
soc/runtime/messages.h Normal file
View File

@ -0,0 +1,23 @@
#ifndef __MESSAGES_H
#define __MESSAGES_H
enum {
MESSAGE_TYPE_FINISHED,
MESSAGE_TYPE_EXCEPTION
};
struct msg_unknown {
int type;
};
struct msg_finished {
int type;
};
struct msg_exception {
int type;
int eid;
long long int eparams[3];
};
#endif /* __MESSAGES_H */