forked from M-Labs/artiq
1
0
Fork 0

Compare commits

...

10 Commits

14 changed files with 1110 additions and 147 deletions

View File

@ -1,5 +1,7 @@
from enum import Enum from enum import Enum
import binascii
import logging import logging
import io
import struct import struct
from sipyco.keepalive import create_connection from sipyco.keepalive import create_connection
@ -23,6 +25,8 @@ class Request(Enum):
DebugAllocator = 8 DebugAllocator = 8
Flash = 9
class Reply(Enum): class Reply(Enum):
Success = 1 Success = 1
@ -46,15 +50,17 @@ class LogLevel(Enum):
class CommMgmt: class CommMgmt:
def __init__(self, host, port=1380): def __init__(self, host, port=1380, drtio_dest=0):
self.host = host self.host = host
self.port = port self.port = port
self.drtio_dest = drtio_dest
def open(self): def open(self):
if hasattr(self, "socket"): if hasattr(self, "socket"):
return return
self.socket = create_connection(self.host, self.port) self.socket = create_connection(self.host, self.port)
self.socket.sendall(b"ARTIQ management\n") self.socket.sendall(b"ARTIQ management\n")
self._write_int8(self.drtio_dest)
endian = self._read(1) endian = self._read(1)
if endian == b"e": if endian == b"e":
self.endian = "<" self.endian = "<"
@ -194,3 +200,45 @@ class CommMgmt:
def debug_allocator(self): def debug_allocator(self):
self._write_header(Request.DebugAllocator) self._write_header(Request.DebugAllocator)
def flash(self, **bin_paths):
self._write_header(Request.Flash)
addr_table = {}
with io.BytesIO() as image_buf, io.BytesIO() as bin_buf:
offset = 0
# Reserve 4-bytes for CRC
image_buf.write(struct.pack(self.endian + "I", 0))
# Reserve 4-bytes for header length
image_buf.write(struct.pack(self.endian + "I", 0))
image_buf.write(struct.pack(self.endian + "I", len(bin_paths)))
for bin_name, filename in bin_paths.items():
with open(filename, "rb") as fi:
bin_ = fi.read()
length = bin_buf.write(bin_)
bin_name_str = bin_name.encode("utf-8")
image_buf.write(struct.pack(self.endian + "I", len(bin_name_str)))
image_buf.write(bin_name_str)
image_buf.write(struct.pack(self.endian + "II", offset, length))
offset += length
# header = image_buf.getvalue()
# image = image_buf.getvalue()
assert(image_buf.tell() == len(image_buf.getvalue()))
header_len = image_buf.tell() - 8
image_buf.seek(4, 0)
image_buf.write(struct.pack(self.endian + "I", header_len))
image_buf.seek(0, 2)
image_buf.write(bin_buf.getvalue())
image_buf.seek(4, 0)
crc = binascii.crc32(image_buf.read())
image_buf.seek(0, 0)
image_buf.write(struct.pack(self.endian + "I", crc))
self._write_bytes(image_buf.getvalue())
self._read_expect(Reply.RebootImminent)

View File

@ -513,6 +513,7 @@ dependencies = [
"board_misoc", "board_misoc",
"build_misoc", "build_misoc",
"byteorder", "byteorder",
"crc",
"cslice", "cslice",
"dyld", "dyld",
"eh", "eh",

View File

@ -259,33 +259,7 @@ mod imp {
} }
pub fn write(key: &str, value: &[u8]) -> Result<(), Error> { pub fn write(key: &str, value: &[u8]) -> Result<(), Error> {
fn flash_binary(origin: usize, payload: &[u8]) { match append(key, value) {
let mut offset = 0;
while offset < payload.len() {
unsafe {
spiflash::erase_sector(origin + offset);
}
offset += spiflash::SECTOR_SIZE;
}
unsafe {
spiflash::write(origin, payload);
}
}
match key {
"gateware" => {
flash_binary(0, value);
Ok(())
}
"bootloader" => {
flash_binary(::mem::ROM_BASE, value);
Ok(())
}
"firmware" => {
flash_binary(::mem::FLASH_BOOT_ADDRESS, value);
Ok(())
}
_ => match append(key, value) {
Err(Error::SpaceExhausted) => { Err(Error::SpaceExhausted) => {
compact()?; compact()?;
append(key, value) append(key, value)
@ -293,7 +267,6 @@ mod imp {
res => res res => res
} }
} }
}
pub fn write_int(key: &str, value: u32) -> Result<(), Error> { pub fn write_int(key: &str, value: u32) -> Result<(), Error> {
let mut buf = [0; 16]; let mut buf = [0; 16];

View File

@ -114,6 +114,50 @@ pub unsafe fn write(mut addr: usize, mut data: &[u8]) {
} }
} }
// pub unsafe fn write_image(image: &[u8]) {
// let image = &image[..];
// let actual_crc = crc32::checksum_ieee(image);
// if actual_crc == expected_crc {
// let mut reader = Cursor::new(header);
// let bin_no = reader.read_u32().unwrap() as usize;
// for _ in 0..bin_no {
// let bin_name = reader.read_string().unwrap();
// let offset = reader.read_u32().unwrap() as usize;
// let len = reader.read_u32().unwrap() as usize;
// let origin = match bin_name.as_str() {
// "gateware" => 0,
// "bootloader" => mem::ROM_BASE,
// "firmware" => mem::FLASH_BOOT_ADDRESS,
// _ => {
// error!("unexpected binary component {}", bin_name);
// return Ok(Reply::Error.write_to(stream)?);
// }
// };
// unsafe {
// spiflash::flash_binary(origin, &image[offset..offset+len]);
// }
// }
// reboot(_io, stream)?;
// } else {
// error!("CRC failed in SDRAM (actual {:08x}, expected {:08x})", actual_crc, expected_crc);
// Reply::Error.write_to(stream)?;
// }
// }
pub unsafe fn flash_binary(origin: usize, payload: &[u8]) {
assert!((origin & (SECTOR_SIZE - 1)) == 0);
let mut offset = 0;
while offset < payload.len() {
erase_sector(origin + offset);
offset += SECTOR_SIZE;
}
write(origin, payload);
}
#[cfg(any(soc_platform = "kasli", soc_platform = "kc705"))] #[cfg(any(soc_platform = "kasli", soc_platform = "kc705"))]
pub unsafe fn reload () -> ! { pub unsafe fn reload () -> ! {
csr::icap::iprog_write(1); csr::icap::iprog_write(1);

View File

@ -127,6 +127,21 @@ pub enum Packet {
SubkernelException { last: bool, length: u16, data: [u8; SAT_PAYLOAD_MAX_SIZE] }, SubkernelException { last: bool, length: u16, data: [u8; SAT_PAYLOAD_MAX_SIZE] },
SubkernelMessage { source: u8, destination: u8, id: u32, status: PayloadStatus, length: u16, data: [u8; MASTER_PAYLOAD_MAX_SIZE] }, SubkernelMessage { source: u8, destination: u8, id: u32, status: PayloadStatus, length: u16, data: [u8; MASTER_PAYLOAD_MAX_SIZE] },
SubkernelMessageAck { destination: u8 }, SubkernelMessageAck { destination: u8 },
CoreMgmtGetLogRequest { destination: u8, clear: bool },
CoreMgmtClearLogRequest { destination: u8 },
CoreMgmtSetLogLevelRequest { destination: u8, log_level: u8 },
CoreMgmtSetUartLogLevelRequest { destination: u8, log_level: u8 },
CoreMgmtConfigReadRequest { destination: u8, length: u16, key: [u8; MASTER_PAYLOAD_MAX_SIZE] },
CoreMgmtConfigReadContinue { destination: u8 },
CoreMgmtConfigWriteRequest { destination: u8, last: bool, length: u16, data: [u8; MASTER_PAYLOAD_MAX_SIZE] },
CoreMgmtConfigRemoveRequest { destination: u8, length: u16, key: [u8; MASTER_PAYLOAD_MAX_SIZE] },
CoreMgmtConfigEraseRequest { destination: u8 },
CoreMgmtRebootRequest { destination: u8 },
CoreMgmtAllocatorDebugRequest { destination: u8 },
CoreMgmtGetLogReply { last: bool, length: u16, data: [u8; SAT_PAYLOAD_MAX_SIZE] },
CoreMgmtConfigReadReply { last: bool, length: u16, value: [u8; SAT_PAYLOAD_MAX_SIZE] },
CoreMgmtReply { succeeded: bool },
} }
impl Packet { impl Packet {
@ -401,6 +416,94 @@ impl Packet {
destination: reader.read_u8()? destination: reader.read_u8()?
}, },
0xd0 => Packet::CoreMgmtGetLogRequest {
destination: reader.read_u8()?,
clear: reader.read_bool()?,
},
0xd1 => Packet::CoreMgmtClearLogRequest {
destination: reader.read_u8()?,
},
0xd2 => Packet::CoreMgmtSetLogLevelRequest {
destination: reader.read_u8()?,
log_level: reader.read_u8()?,
},
0xd3 => Packet::CoreMgmtSetUartLogLevelRequest {
destination: reader.read_u8()?,
log_level: reader.read_u8()?,
},
0xd4 => {
let destination = reader.read_u8()?;
let length = reader.read_u16()?;
let mut key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut key[0..length as usize])?;
Packet::CoreMgmtConfigReadRequest {
destination: destination,
length: length,
key: key,
}
},
0xd5 => Packet::CoreMgmtConfigReadContinue {
destination: reader.read_u8()?,
},
0xd6 => {
let destination = reader.read_u8()?;
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let mut data: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::CoreMgmtConfigWriteRequest {
destination: destination,
last: last,
length: length,
data: data,
}
},
0xd7 => {
let destination = reader.read_u8()?;
let length = reader.read_u16()?;
let mut key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut key[0..length as usize])?;
Packet::CoreMgmtConfigRemoveRequest {
destination: destination,
length: length,
key: key,
}
},
0xd8 => Packet::CoreMgmtConfigEraseRequest {
destination: reader.read_u8()?,
},
0xd9 => Packet::CoreMgmtRebootRequest {
destination: reader.read_u8()?,
},
0xda => Packet::CoreMgmtAllocatorDebugRequest {
destination: reader.read_u8()?,
},
0xdb => {
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let mut data: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut data[0..length as usize])?;
Packet::CoreMgmtGetLogReply {
last: last,
length: length,
data: data,
}
},
0xdc => {
let last = reader.read_bool()?;
let length = reader.read_u16()?;
let mut value: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE];
reader.read_exact(&mut value[0..length as usize])?;
Packet::CoreMgmtConfigReadReply {
last: last,
length: length,
value: value,
}
},
0xdd => Packet::CoreMgmtReply {
succeeded: reader.read_bool()?,
},
ty => return Err(Error::UnknownPacket(ty)) ty => return Err(Error::UnknownPacket(ty))
}) })
} }
@ -686,6 +789,90 @@ impl Packet {
writer.write_u8(0xcc)?; writer.write_u8(0xcc)?;
writer.write_u8(destination)?; writer.write_u8(destination)?;
}, },
Packet::CoreMgmtGetLogRequest { destination, clear } => {
writer.write_u8(0xd0)?;
writer.write_u8(destination)?;
writer.write_bool(clear)?;
},
Packet::CoreMgmtClearLogRequest { destination } => {
writer.write_u8(0xd1)?;
writer.write_u8(destination)?;
},
Packet::CoreMgmtSetLogLevelRequest { destination, log_level } => {
writer.write_u8(0xd2)?;
writer.write_u8(destination)?;
writer.write_u8(log_level)?;
},
Packet::CoreMgmtSetUartLogLevelRequest { destination, log_level } => {
writer.write_u8(0xd3)?;
writer.write_u8(destination)?;
writer.write_u8(log_level)?;
},
Packet::CoreMgmtConfigReadRequest {
destination,
length,
key,
} => {
writer.write_u8(0xd4)?;
writer.write_u8(destination)?;
writer.write_u16(length)?;
writer.write_all(&key[0..length as usize])?;
},
Packet::CoreMgmtConfigReadContinue { destination } => {
writer.write_u8(0xd5)?;
writer.write_u8(destination)?;
},
Packet::CoreMgmtConfigWriteRequest {
destination,
last,
length,
data,
} => {
writer.write_u8(0xd6)?;
writer.write_u8(destination)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_all(&data[0..length as usize])?;
},
Packet::CoreMgmtConfigRemoveRequest {
destination,
length,
key,
} => {
writer.write_u8(0xd7)?;
writer.write_u8(destination)?;
writer.write_u16(length)?;
writer.write_all(&key[0..length as usize])?;
},
Packet::CoreMgmtConfigEraseRequest { destination } => {
writer.write_u8(0xd8)?;
writer.write_u8(destination)?;
},
Packet::CoreMgmtRebootRequest { destination } => {
writer.write_u8(0xd9)?;
writer.write_u8(destination)?;
},
Packet::CoreMgmtAllocatorDebugRequest { destination } => {
writer.write_u8(0xda)?;
writer.write_u8(destination)?;
},
Packet::CoreMgmtGetLogReply { last, length, data } => {
writer.write_u8(0xdb)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_all(&data[0..length as usize])?;
},
Packet::CoreMgmtConfigReadReply { last, length, value } => {
writer.write_u8(0xdc)?;
writer.write_bool(last)?;
writer.write_u16(length)?;
writer.write_all(&value[0..length as usize])?;
},
Packet::CoreMgmtReply { succeeded } => {
writer.write_u8(0xdd)?;
writer.write_bool(succeeded)?;
},
} }
Ok(()) Ok(())
} }

View File

@ -16,7 +16,9 @@ pub enum Error<T> {
#[fail(display = "invalid UTF-8: {}", _0)] #[fail(display = "invalid UTF-8: {}", _0)]
Utf8(Utf8Error), Utf8(Utf8Error),
#[fail(display = "{}", _0)] #[fail(display = "{}", _0)]
Io(#[cause] IoError<T>) Io(#[cause] IoError<T>),
#[fail(display = "drtio error")]
DrtioError,
} }
impl<T> From<IoError<T>> for Error<T> { impl<T> From<IoError<T>> for Error<T> {
@ -65,6 +67,8 @@ pub enum Request {
Reboot, Reboot,
Flash { image: Vec<u8> },
DebugAllocator, DebugAllocator,
} }
@ -123,6 +127,10 @@ impl Request {
8 => Request::DebugAllocator, 8 => Request::DebugAllocator,
9 => Request::Flash {
image: reader.read_bytes()?,
},
ty => return Err(Error::UnknownPacket(ty)) ty => return Err(Error::UnknownPacket(ty))
}) })
} }

View File

@ -16,6 +16,7 @@ build_misoc = { path = "../libbuild_misoc" }
failure = { version = "0.1", default-features = false } failure = { version = "0.1", default-features = false }
failure_derive = { version = "0.1", default-features = false } failure_derive = { version = "0.1", default-features = false }
byteorder = { version = "1.0", default-features = false } byteorder = { version = "1.0", default-features = false }
crc = { version = "1.7", default-features = false }
cslice = { version = "0.3" } cslice = { version = "0.3" }
log = { version = "=0.4.14", default-features = false } log = { version = "=0.4.14", default-features = false }
managed = { version = "^0.7.1", default-features = false, features = ["alloc", "map"] } managed = { version = "^0.7.1", default-features = false, features = ["alloc", "map"] }

View File

@ -1,6 +1,7 @@
#![feature(lang_items, panic_info_message, const_btree_new, iter_advance_by, never_type)] #![feature(lang_items, panic_info_message, const_btree_new, iter_advance_by, never_type)]
#![no_std] #![no_std]
extern crate crc;
extern crate dyld; extern crate dyld;
extern crate eh; extern crate eh;
#[macro_use] #[macro_use]
@ -206,7 +207,13 @@ fn startup() {
rtio_mgt::startup(&io, &aux_mutex, &drtio_routing_table, &up_destinations, &ddma_mutex, &subkernel_mutex); rtio_mgt::startup(&io, &aux_mutex, &drtio_routing_table, &up_destinations, &ddma_mutex, &subkernel_mutex);
io.spawn(4096, mgmt::thread); {
let aux_mutex = aux_mutex.clone();
let ddma_mutex = ddma_mutex.clone();
let subkernel_mutex = subkernel_mutex.clone();
let drtio_routing_table = drtio_routing_table.clone();
io.spawn(4096, move |io| { mgmt::thread(io, &aux_mutex, &ddma_mutex, &subkernel_mutex, &drtio_routing_table) });
}
{ {
let aux_mutex = aux_mutex.clone(); let aux_mutex = aux_mutex.clone();
let drtio_routing_table = drtio_routing_table.clone(); let drtio_routing_table = drtio_routing_table.clone();

View File

@ -1,10 +1,10 @@
use log::{self, LevelFilter}; use core::cell::RefCell;
use io::{Write, ProtoWrite, Error as IoError}; use board_artiq::drtio_routing;
use board_misoc::{config, spiflash}; use io::{ProtoRead, Write, Error as IoError};
use logger_artiq::BufferLogger;
use mgmt_proto::*; use mgmt_proto::*;
use sched::{Io, TcpListener, TcpStream, Error as SchedError}; use sched::{Io, Mutex, TcpListener, TcpStream, Error as SchedError};
use urc::Urc;
impl From<SchedError> for Error<SchedError> { impl From<SchedError> for Error<SchedError> {
fn from(value: SchedError) -> Error<SchedError> { fn from(value: SchedError) -> Error<SchedError> {
@ -12,29 +12,38 @@ impl From<SchedError> for Error<SchedError> {
} }
} }
fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error<SchedError>> { mod local_coremgmt {
read_magic(stream)?; use alloc::{string::String, vec::Vec};
Write::write_all(stream, "e".as_bytes())?; use crc::crc32;
info!("new connection from {}", stream.remote_endpoint()); use log::LevelFilter;
loop { use board_misoc::{config, mem, spiflash};
match Request::read_from(stream)? { use io::{Cursor, Write, ProtoWrite, ProtoRead, Error as IoError};
Request::GetLog => { use logger_artiq::BufferLogger;
use mgmt_proto::{Error, Reply};
use sched::{Io, TcpStream, Error as SchedError};
pub fn get_log(io: &Io, stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
BufferLogger::with(|logger| { BufferLogger::with(|logger| {
let mut buffer = io.until_ok(|| logger.buffer())?; let mut buffer = io.until_ok(|| logger.buffer())?;
Reply::LogContent(buffer.extract()).write_to(stream) Reply::LogContent(buffer.extract()).write_to(stream)
})?; })?;
Ok(())
} }
Request::ClearLog => {
BufferLogger::with(|logger| -> Result<(), Error<SchedError>> { pub fn clear_log(io: &Io, stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
BufferLogger::with(|logger| -> Result<(), IoError<SchedError>> {
let mut buffer = io.until_ok(|| logger.buffer())?; let mut buffer = io.until_ok(|| logger.buffer())?;
Ok(buffer.clear()) Ok(buffer.clear())
})?; })?;
Reply::Success.write_to(stream)?; Reply::Success.write_to(stream)?;
Ok(())
} }
Request::PullLog => {
BufferLogger::with(|logger| -> Result<(), Error<SchedError>> { pub fn pull_log(io: &Io, stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
BufferLogger::with(|logger| -> Result<(), IoError<SchedError>> {
loop { loop {
// Do this *before* acquiring the buffer, since that sets the log level // Do this *before* acquiring the buffer, since that sets the log level
// to OFF. // to OFF.
@ -61,48 +70,59 @@ fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
buffer.clear(); buffer.clear();
} }
})?; })?;
Ok(())
} }
Request::SetLogFilter(level) => {
pub fn set_log_filter(_io: &Io, stream: &mut TcpStream, level: LevelFilter) -> Result<(), Error<SchedError>> {
info!("changing log level to {}", level); info!("changing log level to {}", level);
log::set_max_level(level); log::set_max_level(level);
Reply::Success.write_to(stream)?; Reply::Success.write_to(stream)?;
Ok(())
} }
Request::SetUartLogFilter(level) => {
pub fn set_uart_log_filter(_io: &Io, stream: &mut TcpStream, level: LevelFilter) -> Result<(), Error<SchedError>> {
info!("changing UART log level to {}", level); info!("changing UART log level to {}", level);
BufferLogger::with(|logger| BufferLogger::with(|logger|
logger.set_uart_log_level(level)); logger.set_uart_log_level(level));
Reply::Success.write_to(stream)?; Reply::Success.write_to(stream)?;
Ok(())
} }
Request::ConfigRead { ref key } => { pub fn config_read(_io: &Io, stream: &mut TcpStream, key: &String) -> Result<(), Error<SchedError>>{
config::read(key, |result| { config::read(key, |result| {
match result { match result {
Ok(value) => Reply::ConfigData(&value).write_to(stream), Ok(value) => Reply::ConfigData(&value).write_to(stream),
Err(_) => Reply::Error.write_to(stream) Err(_) => Reply::Error.write_to(stream)
} }
})?; })?;
Ok(())
} }
Request::ConfigWrite { ref key, ref value } => {
pub fn config_write(_io: &Io, stream: &mut TcpStream, key: &String, value: &Vec<u8>) -> Result<(), Error<SchedError>> {
match config::write(key, value) { match config::write(key, value) {
Ok(_) => Reply::Success.write_to(stream), Ok(_) => Reply::Success.write_to(stream),
Err(_) => Reply::Error.write_to(stream) Err(_) => Reply::Error.write_to(stream)
}?; }?;
Ok(())
} }
Request::ConfigRemove { ref key } => {
pub fn config_remove(_io: &Io, stream: &mut TcpStream, key: &String) -> Result<(), Error<SchedError>> {
match config::remove(key) { match config::remove(key) {
Ok(()) => Reply::Success.write_to(stream), Ok(()) => Reply::Success.write_to(stream),
Err(_) => Reply::Error.write_to(stream) Err(_) => Reply::Error.write_to(stream)
}?; }?;
Ok(())
} }
Request::ConfigErase => {
pub fn config_erase(_io: &Io, stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
match config::erase() { match config::erase() {
Ok(()) => Reply::Success.write_to(stream), Ok(()) => Reply::Success.write_to(stream),
Err(_) => Reply::Error.write_to(stream) Err(_) => Reply::Error.write_to(stream)
}?; }?;
Ok(())
} }
Request::Reboot => { pub fn reboot(_io: &Io, stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
Reply::RebootImminent.write_to(stream)?; Reply::RebootImminent.write_to(stream)?;
stream.close()?; stream.close()?;
stream.flush()?; stream.flush()?;
@ -111,22 +131,474 @@ fn worker(io: &Io, stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
unsafe { spiflash::reload(); } unsafe { spiflash::reload(); }
} }
Request::DebugAllocator => pub fn debug_allocator(_io: &Io, _stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
unsafe { println!("{}", ::ALLOC) }, unsafe { println!("{}", ::ALLOC) }
Ok(())
}
pub fn flash(_io: &Io, stream: &mut TcpStream, image: &Vec<u8>) -> Result<(), Error<SchedError>> {
let mut reader = Cursor::new(&image[..]);
let expected_crc = reader.read_u32().unwrap();
let image = &image[4..];
let actual_crc = crc32::checksum_ieee(image);
if actual_crc == expected_crc {
info!("Checksum matched");
let header_size = reader.read_u32().unwrap() as usize;
let header_offset = reader.position();
let bin_offset = header_offset + header_size;
let header = &image[header_offset..bin_offset];
let binaries = &image[bin_offset..];
info!("found header of size {}", header.len());
let mut reader = Cursor::new(header);
let bin_no = reader.read_u32().unwrap() as usize;
for _ in 0..bin_no {
let bin_name = reader.read_string().unwrap();
let offset = reader.read_u32().unwrap() as usize;
let len = reader.read_u32().unwrap() as usize;
let origin = match bin_name.as_str() {
"gateware" => 0,
"bootloader" => mem::ROM_BASE,
"firmware" => mem::FLASH_BOOT_ADDRESS,
_ => {
error!("unexpected binary component {}", bin_name);
return Ok(Reply::Error.write_to(stream)?);
}
}; };
unsafe {
spiflash::flash_binary(origin, &binaries[offset..offset+len]);
} }
} }
pub fn thread(io: Io) { reboot(_io, stream)?;
} else {
error!("CRC failed in SDRAM (actual {:08x}, expected {:08x})", actual_crc, expected_crc);
Reply::Error.write_to(stream)?;
}
Ok(())
}
}
#[cfg(has_drtio)]
mod remote_coremgmt {
use alloc::{string::String, vec::Vec};
use log::LevelFilter;
use board_artiq::{drtioaux::Packet, drtio_routing};
use io::{Cursor, ProtoWrite};
use mgmt_proto::{Error, Reply};
use rtio_mgt::drtio;
use sched::{Io, Mutex, TcpStream, Error as SchedError};
use proto_artiq::drtioaux_proto::MASTER_PAYLOAD_MAX_SIZE;
impl From<drtio::Error> for Error<SchedError> {
fn from(_value: drtio::Error) -> Error<SchedError> {
Error::DrtioError
}
}
pub fn get_log(io: &Io, aux_mutex: &Mutex,
ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
routing_table: &drtio_routing::RoutingTable, linkno: u8,
destination: u8, stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
let mut buffer = String::new();
loop {
let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno,
&Packet::CoreMgmtGetLogRequest { destination, clear: false }
);
match reply {
Ok(Packet::CoreMgmtGetLogReply { last, length, data }) => {
buffer.push_str(
core::str::from_utf8(&data[..length as usize]).map_err(|_| Error::DrtioError)?);
if last {
Reply::LogContent(&buffer).write_to(stream)?;
return Ok(());
}
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Reply::Error.write_to(stream)?;
return Err(drtio::Error::UnexpectedReply.into());
}
Err(e) => {
error!("aux packet error ({})", e);
Reply::Error.write_to(stream)?;
return Err(e.into());
}
}
}
}
pub fn clear_log(io: &Io, aux_mutex: &Mutex,
ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
routing_table: &drtio_routing::RoutingTable, linkno: u8,
destination: u8, stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno,
&Packet::CoreMgmtClearLogRequest { destination }
);
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
Reply::Success.write_to(stream)?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Reply::Error.write_to(stream)?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
Reply::Error.write_to(stream)?;
Err(e.into())
}
}
}
pub fn pull_log(io: &Io, aux_mutex: &Mutex,
ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
routing_table: &drtio_routing::RoutingTable, linkno: u8,
destination: u8, stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
loop {
let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno,
&Packet::CoreMgmtGetLogRequest { destination, clear: true }
);
match reply {
Ok(Packet::CoreMgmtGetLogReply { last: _, length, data }) => {
stream.write_bytes(&data[..length as usize])?;
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
return Err(drtio::Error::UnexpectedReply.into());
}
Err(e) => {
error!("aux packet error ({})", e);
return Err(e.into());
}
}
}
}
pub fn set_log_filter(io: &Io, aux_mutex: &Mutex,
ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
routing_table: &drtio_routing::RoutingTable, linkno: u8,
destination: u8, stream: &mut TcpStream, level: LevelFilter) -> Result<(), Error<SchedError>> {
let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno,
&Packet::CoreMgmtSetLogLevelRequest { destination, log_level: level as u8 }
);
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
Reply::Success.write_to(stream)?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Reply::Error.write_to(stream)?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
Reply::Error.write_to(stream)?;
Err(e.into())
}
}
}
pub fn set_uart_log_filter(io: &Io, aux_mutex: &Mutex,
ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
routing_table: &drtio_routing::RoutingTable, linkno: u8,
destination: u8, stream: &mut TcpStream, level: LevelFilter) -> Result<(), Error<SchedError>> {
let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno,
&Packet::CoreMgmtSetUartLogLevelRequest { destination, log_level: level as u8 }
);
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
Reply::Success.write_to(stream)?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Reply::Error.write_to(stream)?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
Reply::Error.write_to(stream)?;
Err(e.into())
}
}
}
pub fn config_read(io: &Io, aux_mutex: &Mutex,
ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
routing_table: &drtio_routing::RoutingTable, linkno: u8,
destination: u8, stream: &mut TcpStream, key: &String) -> Result<(), Error<SchedError>> {
let mut config_key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
let len = key.len();
config_key[..len].clone_from_slice(key.as_bytes());
let mut reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno,
&Packet::CoreMgmtConfigReadRequest {
destination: destination,
length: len as u16,
key: config_key,
}
);
let mut buffer = Vec::<u8>::new();
loop {
match reply {
Ok(Packet::CoreMgmtConfigReadReply { length, last, value }) => {
buffer.extend(&value[..length as usize]);
if last {
Reply::ConfigData(&buffer).write_to(stream)?;
return Ok(());
}
reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno,
&Packet::CoreMgmtConfigReadContinue {
destination: destination,
}
);
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Reply::Error.write_to(stream)?;
return Err(drtio::Error::UnexpectedReply.into());
}
Err(e) => {
error!("aux packet error ({})", e);
Reply::Error.write_to(stream)?;
return Err(e.into());
}
}
}
}
pub fn config_write(io: &Io, aux_mutex: &Mutex,
ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
routing_table: &drtio_routing::RoutingTable, linkno: u8,
destination: u8, stream: &mut TcpStream, key: &String, value: &Vec<u8>) -> Result<(), Error<SchedError>> {
let mut message = Cursor::new(Vec::with_capacity(key.len() + value.len() + 4 * 2));
message.write_string(key).unwrap();
message.write_bytes(value).unwrap();
match drtio::partition_data(message.get_ref(), |slice, status, len: usize| {
let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno,
&Packet::CoreMgmtConfigWriteRequest {
destination: destination, length: len as u16, last: status.is_last(), data: *slice});
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => Ok(()),
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Err(drtio::Error::UnexpectedReply)
}
Err(e) => {
error!("aux packet error ({})", e);
Err(e)
}
}
}) {
Ok(()) => {
Reply::Success.write_to(stream)?;
Ok(())
},
Err(e) => {
Reply::Error.write_to(stream)?;
Err(e.into())
},
}
}
pub fn config_remove(io: &Io, aux_mutex: &Mutex,
ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
routing_table: &drtio_routing::RoutingTable, linkno: u8,
destination: u8, stream: &mut TcpStream, key: &String) -> Result<(), Error<SchedError>> {
let mut config_key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE];
let len = key.len();
config_key[..len].clone_from_slice(key.as_bytes());
let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno,
&Packet::CoreMgmtConfigRemoveRequest {
destination: destination,
length: key.len() as u16,
key: config_key,
});
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
Reply::Success.write_to(stream)?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Reply::Error.write_to(stream)?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
Reply::Error.write_to(stream)?;
Err(e.into())
}
}
}
pub fn config_erase(io: &Io, aux_mutex: &Mutex,
ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
routing_table: &drtio_routing::RoutingTable, linkno: u8,
destination: u8, stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno,
&Packet::CoreMgmtConfigEraseRequest {
destination: destination,
});
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
Reply::Success.write_to(stream)?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Reply::Error.write_to(stream)?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
Reply::Error.write_to(stream)?;
Err(e.into())
}
}
}
pub fn reboot(io: &Io, aux_mutex: &Mutex,
ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
routing_table: &drtio_routing::RoutingTable, linkno: u8,
destination: u8, stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno,
&Packet::CoreMgmtRebootRequest {
destination: destination,
});
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => {
Reply::RebootImminent.write_to(stream)?;
Ok(())
}
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Reply::Error.write_to(stream)?;
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
Reply::Error.write_to(stream)?;
Err(e.into())
}
}
}
pub fn debug_allocator(io: &Io, aux_mutex: &Mutex,
ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
routing_table: &drtio_routing::RoutingTable, linkno: u8,
destination: u8, _stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno,
&Packet::CoreMgmtAllocatorDebugRequest {
destination: destination,
});
match reply {
Ok(Packet::CoreMgmtReply { succeeded: true }) => Ok(()),
Ok(packet) => {
error!("received unexpected aux packet: {:?}", packet);
Err(drtio::Error::UnexpectedReply.into())
}
Err(e) => {
error!("aux packet error ({})", e);
Err(e.into())
}
}
}
pub fn flash(io: &Io, aux_mutex: &Mutex,
ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
routing_table: &drtio_routing::RoutingTable, linkno: u8,
destination: u8, stream: &mut TcpStream, image: &Vec<u8>) -> Result<(), Error<SchedError>> {
todo!()
}
}
#[cfg(has_drtio)]
macro_rules! process {
($io:ident, $aux_mutex:ident, $ddma_mutex:ident, $subkernel_mutex:ident, $routing_table:ident, $tcp_stream:ident, $destination: ident, $func:ident $(, $param:expr)*) => {{
let hop = $routing_table.0[$destination as usize][0];
if hop == 0 {
local_coremgmt::$func($io, $tcp_stream, $($param, )*)
} else {
let linkno = hop - 1;
remote_coremgmt::$func($io, $aux_mutex, $ddma_mutex, $subkernel_mutex, $routing_table, linkno, $destination, $tcp_stream, $($param, )*)
}
}}
}
#[cfg(not(has_drtio))]
macro_rules! process {
($io:ident, $aux_mutex:ident, $ddma_mutex:ident, $subkernel_mutex:ident, $routing_table:ident, $tcp_stream:ident, $_destination: ident, $func:ident $(, $param:expr)*) => {{
local_coremgmt::$func($io, $tcp_stream, $($param, )*)
}}
}
fn worker(io: &Io, _aux_mutex: &Mutex, _ddma_mutex: &Mutex, _subkernel_mutex: &Mutex,
_routing_table: &drtio_routing::RoutingTable, stream: &mut TcpStream) -> Result<(), Error<SchedError>> {
read_magic(stream)?;
let _destination = stream.read_u8()?;
Write::write_all(stream, "e".as_bytes())?;
info!("new connection from {}", stream.remote_endpoint());
loop {
match Request::read_from(stream)? {
Request::GetLog => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, get_log),
Request::ClearLog => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, clear_log),
Request::PullLog => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, pull_log),
Request::SetLogFilter(level) => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, set_log_filter, level),
Request::SetUartLogFilter(level) => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, set_uart_log_filter, level),
Request::ConfigRead { ref key } => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, config_read, key),
Request::ConfigWrite { ref key, ref value } => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, config_write, key, value),
Request::ConfigRemove { ref key } => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, config_remove, key),
Request::ConfigErase => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, config_erase),
Request::Reboot => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, reboot),
Request::DebugAllocator => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, debug_allocator),
Request::Flash { ref image } => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, flash, image),
}?;
}
}
pub fn thread(io: Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, routing_table: &Urc<RefCell<drtio_routing::RoutingTable>>) {
let listener = TcpListener::new(&io, 8192); let listener = TcpListener::new(&io, 8192);
listener.listen(1380).expect("mgmt: cannot listen"); listener.listen(1380).expect("mgmt: cannot listen");
info!("management interface active"); info!("management interface active");
loop { loop {
let aux_mutex = aux_mutex.clone();
let ddma_mutex = ddma_mutex.clone();
let subkernel_mutex = subkernel_mutex.clone();
let routing_table = routing_table.clone();
let stream = listener.accept().expect("mgmt: cannot accept").into_handle(); let stream = listener.accept().expect("mgmt: cannot accept").into_handle();
io.spawn(4096, move |io| { io.spawn(16384, move |io| {
let routing_table = routing_table.borrow();
let mut stream = TcpStream::from_handle(&io, stream); let mut stream = TcpStream::from_handle(&io, stream);
match worker(&io, &mut stream) { match worker(&io, &aux_mutex, &ddma_mutex, &subkernel_mutex, &routing_table, &mut stream) {
Ok(()) => (), Ok(()) => (),
Err(Error::Io(IoError::UnexpectedEnd)) => (), Err(Error::Io(IoError::UnexpectedEnd)) => (),
Err(err) => error!("aborted: {}", err) Err(err) => error!("aborted: {}", err)

View File

@ -469,7 +469,7 @@ pub mod drtio {
} }
} }
fn partition_data<F>(data: &[u8], send_f: F) -> Result<(), Error> pub fn partition_data<F>(data: &[u8], send_f: F) -> Result<(), Error>
where F: Fn(&[u8; MASTER_PAYLOAD_MAX_SIZE], PayloadStatus, usize) -> Result<(), Error> { where F: Fn(&[u8; MASTER_PAYLOAD_MAX_SIZE], PayloadStatus, usize) -> Result<(), Error> {
let mut i = 0; let mut i = 0;
while i < data.len() { while i < data.len() {

View File

@ -21,6 +21,7 @@ use board_artiq::si5324;
use board_artiq::si549; use board_artiq::si549;
#[cfg(soc_platform = "kasli")] #[cfg(soc_platform = "kasli")]
use board_misoc::irq; use board_misoc::irq;
use board_misoc::spiflash;
use board_artiq::{spi, drtioaux, drtio_routing}; use board_artiq::{spi, drtioaux, drtio_routing};
#[cfg(soc_platform = "efc")] #[cfg(soc_platform = "efc")]
use board_artiq::ad9117; use board_artiq::ad9117;
@ -30,6 +31,7 @@ use board_artiq::drtio_eem;
use riscv::register::{mcause, mepc, mtval}; use riscv::register::{mcause, mepc, mtval};
use dma::Manager as DmaManager; use dma::Manager as DmaManager;
use kernel::Manager as KernelManager; use kernel::Manager as KernelManager;
use mgmt::Manager as CoreManager;
use analyzer::Analyzer; use analyzer::Analyzer;
#[global_allocator] #[global_allocator]
@ -41,6 +43,7 @@ mod dma;
mod analyzer; mod analyzer;
mod kernel; mod kernel;
mod cache; mod cache;
mod mgmt;
fn drtiosat_reset(reset: bool) { fn drtiosat_reset(reset: bool) {
unsafe { unsafe {
@ -129,7 +132,7 @@ macro_rules! forward {
($router:expr, $routing_table:expr, $destination:expr, $rank:expr, $self_destination:expr, $repeaters:expr, $packet:expr) => {} ($router:expr, $routing_table:expr, $destination:expr, $rank:expr, $self_destination:expr, $repeaters:expr, $packet:expr) => {}
} }
fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmgr: &mut KernelManager, fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmgr: &mut KernelManager, coremgr: &mut CoreManager,
_repeaters: &mut [repeater::Repeater], _routing_table: &mut drtio_routing::RoutingTable, rank: &mut u8, _repeaters: &mut [repeater::Repeater], _routing_table: &mut drtio_routing::RoutingTable, rank: &mut u8,
router: &mut routing::Router, self_destination: &mut u8, packet: drtioaux::Packet router: &mut routing::Router, self_destination: &mut u8, packet: drtioaux::Packet
) -> Result<(), drtioaux::Error<!>> { ) -> Result<(), drtioaux::Error<!>> {
@ -489,6 +492,94 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg
Ok(()) Ok(())
} }
drtioaux::Packet::CoreMgmtGetLogRequest { destination: _destination, .. } |
drtioaux::Packet::CoreMgmtClearLogRequest { destination: _destination } |
drtioaux::Packet::CoreMgmtSetLogLevelRequest {destination: _destination, .. } => {
forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet);
error!("RISC-V satellite devices do not support buffered logging");
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
}
drtioaux::Packet::CoreMgmtSetUartLogLevelRequest { destination: _destination, .. } => {
forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet);
error!("RISC-V satellite devices has fixed UART log level fixed at TRACE");
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
}
drtioaux::Packet::CoreMgmtConfigReadRequest {
destination: _destination,
length,
key,
} => {
forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet);
let mut value_slice = [0; SAT_PAYLOAD_MAX_SIZE];
let key_slice = &key[..length as usize];
if !key_slice.is_ascii() {
error!("invalid key");
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
} else {
let key = core::str::from_utf8(key_slice).unwrap();
if coremgr.fetch_config_value(key).is_ok() {
let meta = coremgr.get_config_value_slice(&mut value_slice);
drtioaux::send(
0,
&drtioaux::Packet::CoreMgmtConfigReadReply {
length: meta.len as u16,
last: meta.status.is_last(),
value: value_slice,
},
)
} else {
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false })
}
}
}
drtioaux::Packet::CoreMgmtConfigReadContinue {
destination: _destination,
} => {
forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet);
let mut value_slice = [0; SAT_PAYLOAD_MAX_SIZE];
let meta = coremgr.get_config_value_slice(&mut value_slice);
drtioaux::send(
0,
&drtioaux::Packet::CoreMgmtConfigReadReply {
length: meta.len as u16,
last: meta.status.is_last(),
value: value_slice,
},
)
}
drtioaux::Packet::CoreMgmtConfigWriteRequest { destination: _destination, length, last, data } => {
forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet);
coremgr.add_data(&data, length as usize);
if last {
coremgr.write_config()
} else {
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })
}
}
drtioaux::Packet::CoreMgmtConfigRemoveRequest { destination: _destination, length, key } => {
forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet);
let key = core::str::from_utf8(&key[..length as usize]).unwrap();
let succeeded = config::remove(key)
.map_err(|err| warn!("error on removing config: {:?}", err))
.is_ok();
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded })
}
drtioaux::Packet::CoreMgmtRebootRequest { destination: _destination } => {
forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet);
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })?;
warn!("restarting");
unsafe { spiflash::reload(); }
}
_ => { _ => {
warn!("received unexpected aux packet"); warn!("received unexpected aux packet");
Ok(()) Ok(())
@ -497,13 +588,13 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg
} }
fn process_aux_packets(dma_manager: &mut DmaManager, analyzer: &mut Analyzer, fn process_aux_packets(dma_manager: &mut DmaManager, analyzer: &mut Analyzer,
kernelmgr: &mut KernelManager, repeaters: &mut [repeater::Repeater], kernelmgr: &mut KernelManager, coremgr: &mut CoreManager, repeaters: &mut [repeater::Repeater],
routing_table: &mut drtio_routing::RoutingTable, rank: &mut u8, router: &mut routing::Router, routing_table: &mut drtio_routing::RoutingTable, rank: &mut u8, router: &mut routing::Router,
destination: &mut u8) { destination: &mut u8) {
let result = let result =
drtioaux::recv(0).and_then(|packet| { drtioaux::recv(0).and_then(|packet| {
if let Some(packet) = packet.or_else(|| router.get_local_packet()) { if let Some(packet) = packet.or_else(|| router.get_local_packet()) {
process_aux_packet(dma_manager, analyzer, kernelmgr, process_aux_packet(dma_manager, analyzer, kernelmgr, coremgr,
repeaters, routing_table, rank, router, destination, packet) repeaters, routing_table, rank, router, destination, packet)
} else { } else {
Ok(()) Ok(())
@ -823,6 +914,7 @@ pub extern fn main() -> i32 {
let mut dma_manager = DmaManager::new(); let mut dma_manager = DmaManager::new();
let mut analyzer = Analyzer::new(); let mut analyzer = Analyzer::new();
let mut kernelmgr = KernelManager::new(); let mut kernelmgr = KernelManager::new();
let mut coremgr = CoreManager::new();
cricon_select(RtioMaster::Drtio); cricon_select(RtioMaster::Drtio);
drtioaux::reset(0); drtioaux::reset(0);
@ -832,7 +924,7 @@ pub extern fn main() -> i32 {
while drtiosat_link_rx_up() { while drtiosat_link_rx_up() {
drtiosat_process_errors(); drtiosat_process_errors();
process_aux_packets(&mut dma_manager, &mut analyzer, process_aux_packets(&mut dma_manager, &mut analyzer,
&mut kernelmgr, &mut repeaters, &mut routing_table, &mut kernelmgr, &mut coremgr, &mut repeaters, &mut routing_table,
&mut rank, &mut router, &mut destination); &mut rank, &mut router, &mut destination);
for rep in repeaters.iter_mut() { for rep in repeaters.iter_mut() {
rep.service(&routing_table, rank, destination, &mut router); rep.service(&routing_table, rank, destination, &mut router);

View File

@ -0,0 +1,78 @@
use alloc::vec::Vec;
use routing::{Sliceable, SliceMeta};
use board_artiq::drtioaux;
use board_misoc::{clock, config, csr, spiflash};
use io::{Cursor, ProtoRead, ProtoWrite};
use proto_artiq::drtioaux_proto::SAT_PAYLOAD_MAX_SIZE;
pub struct Manager {
current_payload: Cursor<Vec<u8>>,
last_value: Sliceable,
}
impl Manager {
pub fn new() -> Manager {
Manager {
current_payload: Cursor::new(Vec::new()),
last_value: Sliceable::new(0, Vec::new()),
}
}
pub fn fetch_config_value(&mut self, key: &str) -> Result<(), ()> {
config::read(key, |result| result.map(
|value| self.last_value = Sliceable::new(0, value.to_vec())
)).map_err(|_err| warn!("read error: no such key"))
}
pub fn get_config_value_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE]) -> SliceMeta {
self.last_value.get_slice_sat(data_slice)
}
pub fn add_data(&mut self, data: &[u8], data_len: usize) {
self.current_payload.write_all(&data[..data_len]).unwrap();
}
pub fn clear_data(&mut self) {
self.current_payload.get_mut().clear();
self.current_payload.set_position(0);
}
pub fn write_config(&mut self) -> Result<(), drtioaux::Error<!>> {
let key = match self.current_payload.read_string() {
Ok(key) => key,
Err(err) => {
self.clear_data();
error!("error on reading key: {:?}", err);
return drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false });
}
};
let value = self.current_payload.read_bytes().unwrap();
match key.as_str() {
"gateware" | "bootloader" | "firmware" => {
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })?;
#[cfg(not(soc_platform = "efc"))]
unsafe {
clock::spin_us(10000);
csr::gt_drtio::txenable_write(0);
}
config::write(&key, &value).expect("failed to write to flash storage");
warn!("restarting");
unsafe { spiflash::reload(); }
}
_ => {
let succeeded = config::write(&key, &value).map_err(|err| {
error!("error on writing config: {:?}", err);
}).is_ok();
self.clear_data();
drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded })
}
}
}
}

View File

@ -25,6 +25,9 @@ def get_argparser():
help="Simulation - does not connect to device") help="Simulation - does not connect to device")
parser.add_argument("core_addr", metavar="CORE_ADDR", parser.add_argument("core_addr", metavar="CORE_ADDR",
help="hostname or IP address of the core device") help="hostname or IP address of the core device")
parser.add_argument("-s", "--satellite", default=0,
metavar="DRTIO_ID", type=int,
help="the logged DRTIO destination")
return parser return parser
@ -39,7 +42,7 @@ async def get_logs_sim(host):
log_with_name("firmware.simulation", logging.INFO, "hello " + host) log_with_name("firmware.simulation", logging.INFO, "hello " + host)
async def get_logs(host): async def get_logs(host, drtio_dest):
try: try:
reader, writer = await async_open_connection( reader, writer = await async_open_connection(
host, host,
@ -49,6 +52,7 @@ async def get_logs(host):
max_fails=3, max_fails=3,
) )
writer.write(b"ARTIQ management\n") writer.write(b"ARTIQ management\n")
writer.write(drtio_dest.to_bytes(1))
endian = await reader.readexactly(1) endian = await reader.readexactly(1)
if endian == b"e": if endian == b"e":
endian = "<" endian = "<"
@ -96,7 +100,7 @@ def main():
signal_handler.setup() signal_handler.setup()
try: try:
get_logs_task = asyncio.ensure_future( get_logs_task = asyncio.ensure_future(
get_logs_sim(args.core_addr) if args.simulation else get_logs(args.core_addr), get_logs_sim(args.core_addr) if args.simulation else get_logs(args.core_addr, args.satellite),
loop=loop) loop=loop)
try: try:
server = Server({"corelog": PingTarget()}, None, True) server = Server({"corelog": PingTarget()}, None, True)

View File

@ -1,7 +1,10 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
import argparse import argparse
import os
import struct import struct
import tempfile
import atexit
from sipyco import common_args from sipyco import common_args
@ -9,6 +12,8 @@ from artiq import __version__ as artiq_version
from artiq.master.databases import DeviceDB from artiq.master.databases import DeviceDB
from artiq.coredevice.comm_kernel import CommKernel from artiq.coredevice.comm_kernel import CommKernel
from artiq.coredevice.comm_mgmt import CommMgmt from artiq.coredevice.comm_mgmt import CommMgmt
from artiq.frontend.bit2bin import bit2bin
from misoc.tools.mkmscimg import insert_crc
def get_argparser(): def get_argparser():
@ -85,6 +90,13 @@ def get_argparser():
t_boot = tools.add_parser("reboot", t_boot = tools.add_parser("reboot",
help="reboot the running system") help="reboot the running system")
# flashing
t_flash = tools.add_parser("flash",
help="flash the running system")
p_directory = t_flash.add_argument("directory", metavar="DIRECTORY", type=str,
help="directory that contains the binaries")
# misc debug # misc debug
t_debug = tools.add_parser("debug", t_debug = tools.add_parser("debug",
help="specialized debug functions") help="specialized debug functions")
@ -95,6 +107,11 @@ def get_argparser():
p_allocator = subparsers.add_parser("allocator", p_allocator = subparsers.add_parser("allocator",
help="show heap layout") help="show heap layout")
# manage target
p_drtio_dest = parser.add_argument("-s", "--satellite", default=0,
metavar="DRTIO ID", type=int,
help="specify DRTIO destination that receives this command")
return parser return parser
@ -107,7 +124,7 @@ def main():
core_addr = ddb.get("core", resolve_alias=True)["arguments"]["host"] core_addr = ddb.get("core", resolve_alias=True)["arguments"]["host"]
else: else:
core_addr = args.device core_addr = args.device
mgmt = CommMgmt(core_addr) mgmt = CommMgmt(core_addr, drtio_dest=args.satellite)
if args.tool == "log": if args.tool == "log":
if args.action == "set_level": if args.action == "set_level":
@ -138,6 +155,37 @@ def main():
if args.action == "erase": if args.action == "erase":
mgmt.config_erase() mgmt.config_erase()
if args.tool == "flash":
def convert_gateware(bit_filename):
bin_handle, bin_filename = tempfile.mkstemp(
prefix="artiq_", suffix="_" + os.path.basename(bit_filename))
with open(bit_filename, "rb") as bit_file, open(bin_handle, "wb") as bin_file:
bit2bin(bit_file, bin_file)
atexit.register(lambda: os.unlink(bin_filename))
return bin_filename
gateware = convert_gateware(os.path.join(args.directory, "top.bit"))
bootloader = os.path.join(args.directory, "bootloader.bin")
firmwares = []
for firmware in "satman", "runtime":
filename = os.path.join(args.directory, firmware + ".fbi")
if os.path.exists(filename):
firmwares.append(filename)
if not firmwares:
raise FileNotFoundError("no firmware found")
if len(firmwares) > 1:
raise ValueError("more than one firmware file, please clean up your build directory. "
"Found firmware files: {}".format(" ".join(firmwares)))
firmware = firmwares[0]
bins = {
"gateware": gateware,
"bootloader": bootloader,
"firmware": firmware,
}
mgmt.flash(**bins)
if args.tool == "reboot": if args.tool == "reboot":
mgmt.reboot() mgmt.reboot()