Rust: implement exceptional kernel termination.

This also adjusts the way backtraces are serialized by kloader.
pull/584/head
whitequark 2016-10-06 13:42:35 +00:00
parent 84214ab0d1
commit 226fa723bb
11 changed files with 98 additions and 99 deletions

View File

@ -3,7 +3,6 @@ use board::csr;
use mailbox;
const KERNELCPU_EXEC_ADDRESS: usize = 0x42000000;
const KERNELCPU_PAYLOAD_ADDRESS: usize = 0x42020000;
const KERNELCPU_LAST_ADDRESS: usize = (0x4fffffff - 1024*1024);
const KSUPPORT_HEADER_SIZE: usize = 0x80;

View File

@ -15,8 +15,6 @@ pub struct Exception<'a> {
pub param: [u64; 3],
}
pub use self::c::BacktraceItem;
#[derive(Debug)]
pub enum Message<'a> {
LoadRequest(&'a [u8]),
@ -29,7 +27,7 @@ pub enum Message<'a> {
RunFinished,
RunException {
exception: Exception<'a>,
backtrace: &'a [BacktraceItem]
backtrace: &'a [usize]
},
WatchdogSetRequest { ms: u64 },
@ -315,7 +313,7 @@ mod c {
pub struct RunException {
pub ty: Type,
pub exception: *const Exception,
pub backtrace: *const BacktraceItem,
pub backtrace: *const usize,
pub backtrace_size: size_t
}
@ -417,13 +415,6 @@ mod c {
pub param: [u64; 3],
}
#[repr(C)]
#[derive(Debug)]
pub struct BacktraceItem {
pub function: usize,
pub offset: usize
}
pub unsafe fn from_c_str_len<'a>(ptr: *const c_char, len: size_t) -> &'a str {
str::from_utf8_unchecked(slice::from_raw_parts(ptr as *const u8, len))
}

View File

@ -350,12 +350,39 @@ fn process_kern_message(waiter: Waiter,
}
kern::RunFinished => {
try!(kern_acknowledge());
kernel::stop();
session.kernel_state = KernelState::Absent;
return Ok(true)
match stream {
None => return Ok(true),
Some(ref mut stream) =>
host_write(stream, host::Reply::KernelFinished)
}
}
kern::RunException { exception: ref exn, backtrace } => {
kernel::stop();
session.kernel_state = KernelState::Absent;
match stream {
None => {
error!("exception in flash kernel");
error!("{}: {} {:?}", exn.name, exn.message, exn.param);
error!("at {}:{}:{} in {}", exn.file, exn.line, exn.column, exn.function);
return Ok(true)
},
Some(ref mut stream) =>
host_write(stream, host::Reply::KernelException {
name: exn.name,
message: exn.message,
param: exn.param,
file: exn.file,
line: exn.line,
column: exn.column,
function: exn.function,
backtrace: backtrace
})
}
}
request => unexpected!("unexpected request {:?} from kernel CPU", request)
@ -374,9 +401,7 @@ fn host_kernel_worker(waiter: Waiter,
}
if mailbox::receive() != 0 {
if try!(process_kern_message(waiter, Some(stream), &mut session)) {
try!(host_write(stream, host::Reply::KernelFinished))
}
try!(process_kern_message(waiter, Some(stream), &mut session));
}
if session.kernel_state == KernelState::Running {

View File

@ -15,46 +15,6 @@ fn write_sync(writer: &mut Write) -> io::Result<()> {
writer.write_all(&[0x5a; 4])
}
#[derive(Debug)]
pub struct Exception {
name: String,
message: String,
param: [u64; 3],
file: String,
line: u32,
column: u32,
function: String,
}
impl Exception {
pub fn read_from(reader: &mut Read) -> io::Result<Exception> {
Ok(Exception {
name: try!(read_string(reader)),
message: try!(read_string(reader)),
param: [try!(read_u64(reader)),
try!(read_u64(reader)),
try!(read_u64(reader))],
file: try!(read_string(reader)),
line: try!(read_u32(reader)),
column: try!(read_u32(reader)),
function: try!(read_string(reader))
})
}
pub fn write_to(&self, writer: &mut Write) -> io::Result<()> {
try!(write_string(writer, &self.name));
try!(write_string(writer, &self.message));
try!(write_u64(writer, self.param[0]));
try!(write_u64(writer, self.param[1]));
try!(write_u64(writer, self.param[2]));
try!(write_string(writer, &self.file));
try!(write_u32(writer, self.line));
try!(write_u32(writer, self.column));
try!(write_string(writer, &self.function));
Ok(())
}
}
#[derive(Debug)]
pub enum Request {
Log,
@ -67,7 +27,15 @@ pub enum Request {
RunKernel,
RpcReply { tag: Vec<u8>, data: Vec<u8> },
RpcException(Exception),
RpcException {
name: String,
message: String,
param: [u64; 3],
file: String,
line: u32,
column: u32,
function: String,
},
FlashRead { key: String },
FlashWrite { key: String, value: Vec<u8> },
@ -100,7 +68,17 @@ impl Request {
try!(reader.read_exact(&mut data));
Request::RpcReply { tag: tag, data: data }
}
8 => Request::RpcException(try!(Exception::read_from(reader))),
8 => Request::RpcException {
name: try!(read_string(reader)),
message: try!(read_string(reader)),
param: [try!(read_u64(reader)),
try!(read_u64(reader)),
try!(read_u64(reader))],
file: try!(read_string(reader)),
line: try!(read_u32(reader)),
column: try!(read_u32(reader)),
function: try!(read_string(reader))
},
9 => Request::FlashRead {
key: try!(read_string(reader))
},
@ -130,7 +108,16 @@ pub enum Reply<'a> {
KernelFinished,
KernelStartupFailed,
KernelException(Exception),
KernelException {
name: &'a str,
message: &'a str,
param: [u64; 3],
file: &'a str,
line: u32,
column: u32,
function: &'a str,
backtrace: &'a [usize]
},
RpcRequest { service: u32, data: &'a [u8] },
@ -179,9 +166,23 @@ impl<'a> Reply<'a> {
Reply::KernelStartupFailed => {
try!(write_u8(&mut buf, 8));
},
Reply::KernelException(ref exception) => {
Reply::KernelException {
name, message, param, file, line, column, function, backtrace
} => {
try!(write_u8(&mut buf, 9));
try!(exception.write_to(writer));
try!(write_string(&mut buf, name));
try!(write_string(&mut buf, message));
try!(write_u64(&mut buf, param[0]));
try!(write_u64(&mut buf, param[1]));
try!(write_u64(&mut buf, param[2]));
try!(write_string(&mut buf, file));
try!(write_u32(&mut buf, line));
try!(write_u32(&mut buf, column));
try!(write_string(&mut buf, function));
try!(write_u32(&mut buf, backtrace.len() as u32));
for &addr in backtrace {
try!(write_u32(&mut buf, addr as u32))
}
},
Reply::RpcRequest { service, data } => {

View File

@ -233,7 +233,7 @@ struct artiq_raised_exception {
struct _Unwind_Exception unwind;
struct artiq_exception artiq;
int handled;
struct artiq_backtrace_item backtrace[1024];
uintptr_t backtrace[1024];
size_t backtrace_size;
};
@ -303,8 +303,7 @@ static _Unwind_Reason_Code __artiq_uncaught_exception(
uintptr_t pcOffset = pc - funcStart;
EH_LOG("===> uncaught (pc=%p+%p)", (void*)funcStart, (void*)pcOffset);
inflight->backtrace[inflight->backtrace_size].function = funcStart;
inflight->backtrace[inflight->backtrace_size].offset = pcOffset;
inflight->backtrace[inflight->backtrace_size] = funcStart + pcOffset;
++inflight->backtrace_size;
if(actions & _UA_END_OF_STACK) {

View File

@ -17,11 +17,6 @@ struct artiq_exception {
int64_t param[3];
};
struct artiq_backtrace_item {
intptr_t function;
intptr_t offset;
};
#ifdef __cplusplus
extern "C" {
#endif
@ -48,7 +43,7 @@ void __artiq_reraise(void)
/* Called by the runtime */
void __artiq_terminate(struct artiq_exception *artiq_exn,
struct artiq_backtrace_item *backtrace,
uintptr_t *backtrace,
size_t backtrace_size)
__attribute__((noreturn));

View File

@ -58,22 +58,6 @@ void kloader_start_kernel()
mailbox_acknowledge();
}
void kloader_filter_backtrace(struct artiq_backtrace_item *backtrace,
size_t *backtrace_size) {
struct artiq_backtrace_item *cursor = backtrace;
// Remove all backtrace items belonging to ksupport and subtract
// shared object base from the addresses.
for(int i = 0; i < *backtrace_size; i++) {
if(backtrace[i].function > KERNELCPU_PAYLOAD_ADDRESS) {
backtrace[i].function -= KERNELCPU_PAYLOAD_ADDRESS;
*cursor++ = backtrace[i];
}
}
*backtrace_size = cursor - backtrace;
}
static int kloader_start_flash_kernel(char *key)
{
#if (defined CSR_SPIFLASH_BASE && defined CONFIG_SPIFLASH_PAGE_SIZE)

View File

@ -1,16 +1,12 @@
#ifndef __KLOADER_H
#define __KLOADER_H
#include "artiq_personality.h"
#define KERNELCPU_EXEC_ADDRESS 0x42000000
#define KERNELCPU_PAYLOAD_ADDRESS 0x42020000
#define KERNELCPU_LAST_ADDRESS (0x4fffffff - 1024*1024)
#define KSUPPORT_HEADER_SIZE 0x80
int kloader_load_library(const void *code);
void kloader_filter_backtrace(struct artiq_backtrace_item *backtrace,
size_t *backtrace_size);
int kloader_start_startup_kernel(void);
int kloader_start_idle_kernel(void);

View File

@ -415,13 +415,26 @@ int main(void)
/* called from __artiq_personality */
void __artiq_terminate(struct artiq_exception *artiq_exn,
struct artiq_backtrace_item *backtrace,
uintptr_t *backtrace,
size_t backtrace_size)
{
struct msg_exception msg;
now_save();
uintptr_t *cursor = backtrace;
// Remove all backtrace items belonging to ksupport and subtract
// shared object base from the addresses.
for(int i = 0; i < backtrace_size; i++) {
if(backtrace[i] > KERNELCPU_PAYLOAD_ADDRESS) {
backtrace[i] -= KERNELCPU_PAYLOAD_ADDRESS;
*cursor++ = backtrace[i];
}
}
backtrace_size = cursor - backtrace;
msg.type = MESSAGE_TYPE_EXCEPTION;
msg.exception = artiq_exn;
msg.backtrace = backtrace;

View File

@ -56,7 +56,7 @@ struct msg_now_save {
struct msg_exception {
int type;
struct artiq_exception *exception;
struct artiq_backtrace_item *backtrace;
uintptr_t *backtrace;
size_t backtrace_size;
};

View File

@ -973,13 +973,9 @@ static int process_kmsg(struct msg_base *umsg)
out_packet_int32(msg->exception->column);
out_packet_string(msg->exception->function);
kloader_filter_backtrace(msg->backtrace,
&msg->backtrace_size);
out_packet_int32(msg->backtrace_size);
for(int i = 0; i < msg->backtrace_size; i++) {
struct artiq_backtrace_item *item = &msg->backtrace[i];
out_packet_int32(item->function + item->offset);
out_packet_int32(msg->backtrace[i]);
}
out_packet_finish();