From 12682a277e9be7e1c9c897d4317f4f0c9ff8fa00 Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 26 Aug 2024 17:37:32 +0800 Subject: [PATCH 01/42] config: impl flashing over mgmt --- artiq/firmware/libboard_misoc/config.rs | 37 +++++++++++++++++++++---- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/artiq/firmware/libboard_misoc/config.rs b/artiq/firmware/libboard_misoc/config.rs index e5e62ad0c..a7c3d4a63 100644 --- a/artiq/firmware/libboard_misoc/config.rs +++ b/artiq/firmware/libboard_misoc/config.rs @@ -259,12 +259,39 @@ mod imp { } pub fn write(key: &str, value: &[u8]) -> Result<(), Error> { - match append(key, value) { - Err(Error::SpaceExhausted) => { - compact()?; - append(key, value) + fn flash_binary(origin: usize, payload: &[u8]) { + 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) => { + compact()?; + append(key, value) + } + res => res } - res => res } } From b60a616e78ec19654fba6778eca3726924e3920b Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 26 Aug 2024 17:39:02 +0800 Subject: [PATCH 02/42] drtio: add new messages for remote mgmt --- .../firmware/libproto_artiq/drtioaux_proto.rs | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index a1b17e888..ba826873a 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -127,6 +127,22 @@ pub enum Packet { SubkernelException { destination: u8, last: bool, 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 }, + + 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] }, + CoreMgmtAck, + CoreMgmtNack, } impl Packet { @@ -405,6 +421,93 @@ impl Packet { 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::CoreMgmtAck, + 0xde => Packet::CoreMgmtNack, + ty => return Err(Error::UnknownPacket(ty)) }) } @@ -693,6 +796,88 @@ impl Packet { writer.write_u8(0xcc)?; 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::CoreMgmtAck => writer.write_u8(0xdd)?, + Packet::CoreMgmtNack => writer.write_u8(0xde)?, } Ok(()) } From e57d18a41f8b8c12bd77855715c2ed7679d2d2d2 Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 26 Aug 2024 17:40:16 +0800 Subject: [PATCH 03/42] runtime: support mgmt over drtio --- artiq/firmware/libproto_artiq/mgmt_proto.rs | 4 +- artiq/firmware/runtime/main.rs | 6 +- artiq/firmware/runtime/mgmt.rs | 657 ++++++++++++++++---- artiq/firmware/runtime/rtio_mgt.rs | 2 +- 4 files changed, 547 insertions(+), 122 deletions(-) diff --git a/artiq/firmware/libproto_artiq/mgmt_proto.rs b/artiq/firmware/libproto_artiq/mgmt_proto.rs index 911799ef4..74724df13 100644 --- a/artiq/firmware/libproto_artiq/mgmt_proto.rs +++ b/artiq/firmware/libproto_artiq/mgmt_proto.rs @@ -16,7 +16,9 @@ pub enum Error { #[fail(display = "invalid UTF-8: {}", _0)] Utf8(Utf8Error), #[fail(display = "{}", _0)] - Io(#[cause] IoError) + Io(#[cause] IoError), + #[fail(display = "drtio error")] + DrtioError, } impl From> for Error { diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index dd52aabaf..78bf9b594 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -209,7 +209,11 @@ fn startup() { rtio_mgt::startup(&io, &aux_mutex, &drtio_routing_table, &up_destinations, &ddma_mutex, &subkernel_mutex); { let restart_idle = restart_idle.clone(); - io.spawn(4096, move |io| { mgmt::thread(io, &restart_idle) }); + 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, &restart_idle, &aux_mutex, &ddma_mutex, &subkernel_mutex, &drtio_routing_table) }); } { let aux_mutex = aux_mutex.clone(); diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 5b6fc6d01..0962fcc97 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -1,11 +1,12 @@ use log::{self, LevelFilter}; use core::cell::Cell; +use core::cell::RefCell; -use io::{Write, ProtoWrite, Error as IoError}; -use board_misoc::{config, spiflash}; -use logger_artiq::BufferLogger; +use board_artiq::drtio_routing; +use io::{ProtoRead, Write, Error as IoError}; 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 for Error { @@ -14,138 +15,556 @@ impl From for Error { } } -fn worker(io: &Io, stream: &mut TcpStream, restart_idle: &Urc>) -> Result<(), Error> { +mod local_coremgmt { + use alloc::{string::String, vec::Vec}; + use log::LevelFilter; + + use board_misoc::{config, spiflash}; + use io::{Write, ProtoWrite, Error as IoError}; + 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> { + BufferLogger::with(|logger| { + let mut buffer = io.until_ok(|| logger.buffer())?; + Reply::LogContent(buffer.extract()).write_to(stream) + })?; + Ok(()) + } + + pub fn clear_log(io: &Io, stream: &mut TcpStream) -> Result<(), Error> { + BufferLogger::with(|logger| -> Result<(), IoError> { + let mut buffer = io.until_ok(|| logger.buffer())?; + Ok(buffer.clear()) + })?; + + Reply::Success.write_to(stream)?; + Ok(()) + } + + pub fn pull_log(io: &Io, stream: &mut TcpStream) -> Result<(), Error> { + BufferLogger::with(|logger| -> Result<(), IoError> { + loop { + // Do this *before* acquiring the buffer, since that sets the log level + // to OFF. + let log_level = log::max_level(); + + let mut buffer = io.until_ok(|| logger.buffer())?; + if buffer.is_empty() { continue } + + stream.write_string(buffer.extract())?; + + if log_level == LevelFilter::Trace { + // Hold exclusive access over the logger until we get positive + // acknowledgement; otherwise we get an infinite loop of network + // trace messages being transmitted and causing more network + // trace messages to be emitted. + // + // Any messages unrelated to this management socket that arrive + // while it is flushed are lost, but such is life. + stream.flush()?; + } + + // Clear the log *after* flushing the network buffers, or we're just + // going to resend all the trace messages on the next iteration. + buffer.clear(); + } + })?; + Ok(()) + } + + pub fn set_log_filter(_io: &Io, stream: &mut TcpStream, level: LevelFilter) -> Result<(), Error> { + info!("changing log level to {}", level); + log::set_max_level(level); + Reply::Success.write_to(stream)?; + Ok(()) + } + + pub fn set_uart_log_filter(_io: &Io, stream: &mut TcpStream, level: LevelFilter) -> Result<(), Error> { + info!("changing UART log level to {}", level); + BufferLogger::with(|logger| + logger.set_uart_log_level(level)); + Reply::Success.write_to(stream)?; + Ok(()) + } + + pub fn config_read(_io: &Io, stream: &mut TcpStream, key: &String) -> Result<(), Error>{ + config::read(key, |result| { + match result { + Ok(value) => Reply::ConfigData(&value).write_to(stream), + Err(_) => Reply::Error.write_to(stream) + } + })?; + Ok(()) + } + + pub fn config_write(_io: &Io, stream: &mut TcpStream, key: &String, value: &Vec, restart_idle: &Urc>) -> Result<(), Error> { + match config::write(key, value) { + Ok(_) => { + if key == "idle_kernel" { + io.until(|| !restart_idle.get())?; + restart_idle.set(true); + } + Reply::Success.write_to(stream) + }, + Err(_) => Reply::Error.write_to(stream) + }?; + Ok(()) + } + + pub fn config_remove(_io: &Io, stream: &mut TcpStream, key: &String, restart_idle: &Urc>) -> Result<(), Error> { + match config::remove(key) { + Ok(()) => { + if key == "idle_kernel" { + io.until(|| !restart_idle.get())?; + restart_idle.set(true); + } + Reply::Success.write_to(stream) + }, + Err(_) => Reply::Error.write_to(stream) + }?; + Ok(()) + } + + pub fn config_erase(_io: &Io, stream: &mut TcpStream, restart_idle: &Urc>) -> Result<(), Error> { + match config::erase() { + Ok(()) => { + io.until(|| !restart_idle.get())?; + restart_idle.set(true); + Reply::Success.write_to(stream) + }, + Err(_) => Reply::Error.write_to(stream) + }?; + Ok(()) + } + + pub fn reboot(_io: &Io, stream: &mut TcpStream) -> Result<(), Error> { + Reply::RebootImminent.write_to(stream)?; + stream.close()?; + stream.flush()?; + + warn!("restarting"); + unsafe { spiflash::reload(); } + } + + pub fn debug_allocator(_io: &Io, _stream: &mut TcpStream) -> Result<(), Error> { + unsafe { println!("{}", ::ALLOC) } + 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 for Error { + fn from(_value: drtio::Error) -> Error { + 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> { + 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> { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, + &Packet::CoreMgmtClearLogRequest { destination } + ); + + match reply { + Ok(Packet::CoreMgmtAck) => { + 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> { + 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> { + 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::CoreMgmtAck) => { + 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> { + 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::CoreMgmtAck) => { + 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> { + 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::::new(); + loop { + match reply { + Ok(Packet::CoreMgmtConfigReadReply { length, last, value }) => { + buffer.extend(&value[..length as usize]); + + if last { + Reply::ConfigData(&value[..length as usize]).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, + _restart_idle: &Urc>) -> Result<(), Error> { + 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::CoreMgmtAck) => 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, + _restart_idle: &Urc>) -> Result<(), Error> { + 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::CoreMgmtAck) => { + 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, _restart_idle: &Urc>) -> Result<(), Error> { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, + &Packet::CoreMgmtConfigEraseRequest { + destination: destination, + }); + + match reply { + Ok(Packet::CoreMgmtAck) => { + 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> { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, + &Packet::CoreMgmtRebootRequest { + destination: destination, + }); + + match reply { + Ok(Packet::CoreMgmtAck) => { + 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> { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, + &Packet::CoreMgmtAllocatorDebugRequest { + destination: destination, + }); + + match reply { + Ok(Packet::CoreMgmtAck) => Ok(()), + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); + Err(drtio::Error::UnexpectedReply.into()) + } + Err(e) => { + error!("aux packet error ({})", e); + Err(e.into()) + } + } + } +} + +#[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, stream: &mut TcpStream, restart_idle: &Urc>, + _aux_mutex: &Mutex, _ddma_mutex: &Mutex, _subkernel_mutex: &Mutex, + _routing_table: &drtio_routing::RoutingTable, stream: &mut TcpStream) -> Result<(), Error> { 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 => { - BufferLogger::with(|logger| { - let mut buffer = io.until_ok(|| logger.buffer())?; - Reply::LogContent(buffer.extract()).write_to(stream) - })?; - } - Request::ClearLog => { - BufferLogger::with(|logger| -> Result<(), Error> { - let mut buffer = io.until_ok(|| logger.buffer())?; - Ok(buffer.clear()) - })?; - - Reply::Success.write_to(stream)?; - } - Request::PullLog => { - BufferLogger::with(|logger| -> Result<(), Error> { - loop { - // Do this *before* acquiring the buffer, since that sets the log level - // to OFF. - let log_level = log::max_level(); - - let mut buffer = io.until_ok(|| logger.buffer())?; - if buffer.is_empty() { continue } - - stream.write_string(buffer.extract())?; - - if log_level == LevelFilter::Trace { - // Hold exclusive access over the logger until we get positive - // acknowledgement; otherwise we get an infinite loop of network - // trace messages being transmitted and causing more network - // trace messages to be emitted. - // - // Any messages unrelated to this management socket that arrive - // while it is flushed are lost, but such is life. - stream.flush()?; - } - - // Clear the log *after* flushing the network buffers, or we're just - // going to resend all the trace messages on the next iteration. - buffer.clear(); - } - })?; - } - Request::SetLogFilter(level) => { - info!("changing log level to {}", level); - log::set_max_level(level); - Reply::Success.write_to(stream)?; - } - Request::SetUartLogFilter(level) => { - info!("changing UART log level to {}", level); - BufferLogger::with(|logger| - logger.set_uart_log_level(level)); - Reply::Success.write_to(stream)?; - } - - Request::ConfigRead { ref key } => { - config::read(key, |result| { - match result { - Ok(value) => Reply::ConfigData(&value).write_to(stream), - Err(_) => Reply::Error.write_to(stream) - } - })?; - } - Request::ConfigWrite { ref key, ref value } => { - match config::write(key, value) { - Ok(_) => { - if key == "idle_kernel" { - io.until(|| !restart_idle.get())?; - restart_idle.set(true); - } - Reply::Success.write_to(stream) - }, - Err(_) => Reply::Error.write_to(stream) - }?; - } - Request::ConfigRemove { ref key } => { - match config::remove(key) { - Ok(()) => { - if key == "idle_kernel" { - io.until(|| !restart_idle.get())?; - restart_idle.set(true); - } - Reply::Success.write_to(stream) - }, - Err(_) => Reply::Error.write_to(stream) - }?; - - } - Request::ConfigErase => { - match config::erase() { - Ok(()) => { - io.until(|| !restart_idle.get())?; - restart_idle.set(true); - Reply::Success.write_to(stream) - }, - Err(_) => Reply::Error.write_to(stream) - }?; - } - - Request::Reboot => { - Reply::RebootImminent.write_to(stream)?; - stream.close()?; - stream.flush()?; - - warn!("restarting"); - unsafe { spiflash::reload(); } - } - - Request::DebugAllocator => - unsafe { println!("{}", ::ALLOC) }, - }; + 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, restart_idle), + Request::ConfigRemove { ref key } => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, config_remove, key, restart_idle), + Request::ConfigErase => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, config_erase, restart_idle), + 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), + }?; } } -pub fn thread(io: Io, restart_idle: &Urc>) { +pub fn thread(io: Io, restart_idle: &Urc>, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, routing_table: &Urc>) { let listener = TcpListener::new(&io, 8192); listener.listen(1380).expect("mgmt: cannot listen"); info!("management interface active"); loop { - let stream = listener.accept().expect("mgmt: cannot accept").into_handle(); let restart_idle = restart_idle.clone(); - io.spawn(4096, move |io| { + 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(); + io.spawn(16384, move |io| { + let routing_table = routing_table.borrow(); let mut stream = TcpStream::from_handle(&io, stream); - match worker(&io, &mut stream, &restart_idle) { + match worker(&io, &mut stream, &restart_idle, &aux_mutex, &ddma_mutex, &subkernel_mutex, &routing_table) { Ok(()) => (), Err(Error::Io(IoError::UnexpectedEnd)) => (), Err(err) => error!("aborted: {}", err) diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 120a4a1c6..bc3ac7080 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -506,7 +506,7 @@ pub mod drtio { } } - fn partition_data(data: &[u8], send_f: F) -> Result<(), Error> + pub fn partition_data(data: &[u8], send_f: F) -> Result<(), Error> where F: Fn(&[u8; MASTER_PAYLOAD_MAX_SIZE], PayloadStatus, usize) -> Result<(), Error> { let mut i = 0; while i < data.len() { From 05578b282ebc8551251ebf4a8c82833b2e5081dc Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 26 Aug 2024 17:40:43 +0800 Subject: [PATCH 04/42] satman: support remote drtio instruction for core mgmt --- artiq/firmware/satman/main.rs | 111 ++++++++++++++++++++++++++++++++-- artiq/firmware/satman/mgmt.rs | 52 ++++++++++++++++ 2 files changed, 159 insertions(+), 4 deletions(-) create mode 100644 artiq/firmware/satman/mgmt.rs diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 8e265999e..9513f1a81 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -21,6 +21,7 @@ use board_artiq::si5324; use board_artiq::si549; #[cfg(soc_platform = "kasli")] use board_misoc::irq; +use board_misoc::spiflash; use board_artiq::{spi, drtioaux, drtio_routing}; #[cfg(soc_platform = "efc")] use board_artiq::ad9117; @@ -30,6 +31,7 @@ use board_artiq::drtio_eem; use riscv::register::{mcause, mepc, mtval}; use dma::Manager as DmaManager; use kernel::Manager as KernelManager; +use mgmt::Manager as CoreManager; use analyzer::Analyzer; #[global_allocator] @@ -41,6 +43,7 @@ mod dma; mod analyzer; mod kernel; mod cache; +mod mgmt; fn drtiosat_reset(reset: bool) { unsafe { @@ -129,7 +132,7 @@ macro_rules! forward { ($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, router: &mut routing::Router, self_destination: &mut u8, packet: drtioaux::Packet ) -> Result<(), drtioaux::Error> { @@ -495,6 +498,105 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg 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::CoreMgmtNack) + } + 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::CoreMgmtNack) + } + 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::CoreMgmtNack) + } 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::CoreMgmtNack) + } + } + } + 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); + let mut succeeded = true; + if last { + succeeded = coremgr.write_config().is_ok(); + debug!("Write succeeded: {}", succeeded); + coremgr.clear_data(); + } + + if succeeded { + drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck) + } else { + drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack) + } + } + 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(); + + if succeeded { + drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck) + } else { + drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack) + } + } + drtioaux::Packet::CoreMgmtRebootRequest { destination: _destination } => { + forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet); + + drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck)?; + warn!("restarting"); + unsafe { spiflash::reload(); } + } + _ => { warn!("received unexpected aux packet"); Ok(()) @@ -503,13 +605,13 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg } 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, destination: &mut u8) { let result = drtioaux::recv(0).and_then(|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) } else { Ok(()) @@ -834,6 +936,7 @@ pub extern fn main() -> i32 { let mut dma_manager = DmaManager::new(); let mut analyzer = Analyzer::new(); let mut kernelmgr = KernelManager::new(); + let mut coremgr = CoreManager::new(); cricon_select(RtioMaster::Drtio); drtioaux::reset(0); @@ -843,7 +946,7 @@ pub extern fn main() -> i32 { while drtiosat_link_rx_up() { drtiosat_process_errors(); 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); for rep in repeaters.iter_mut() { rep.service(&routing_table, rank, destination, &mut router); diff --git a/artiq/firmware/satman/mgmt.rs b/artiq/firmware/satman/mgmt.rs new file mode 100644 index 000000000..01c64dcef --- /dev/null +++ b/artiq/firmware/satman/mgmt.rs @@ -0,0 +1,52 @@ +use alloc::vec::Vec; + +use routing::{Sliceable, SliceMeta}; +use board_misoc::config; +use io::{Cursor, ProtoRead, ProtoWrite}; +use proto_artiq::drtioaux_proto::SAT_PAYLOAD_MAX_SIZE; + + +type Result = core::result::Result; + +pub struct Manager { + current_payload: Cursor>, + 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<()> { + let key = self.current_payload.read_string().map_err( + |err| error!("error on reading key: {:?}", err))?; + let value = self.current_payload.read_bytes().unwrap(); + + config::write(&key, &value).map_err(|err| { + error!("error on writing config: {:?}", err); + }) + } +} \ No newline at end of file From cbcf2bd84a174df9fb7fe17a9fcbf34efee37e9f Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 26 Aug 2024 17:41:27 +0800 Subject: [PATCH 05/42] frontend: pass drtio destination during communication --- artiq/coredevice/comm_mgmt.py | 4 +++- artiq/frontend/aqctl_corelog.py | 8 ++++++-- artiq/frontend/artiq_coremgmt.py | 7 ++++++- 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/artiq/coredevice/comm_mgmt.py b/artiq/coredevice/comm_mgmt.py index 870e2759d..1b218afec 100644 --- a/artiq/coredevice/comm_mgmt.py +++ b/artiq/coredevice/comm_mgmt.py @@ -46,15 +46,17 @@ class LogLevel(Enum): class CommMgmt: - def __init__(self, host, port=1380): + def __init__(self, host, port=1380, drtio_dest=0): self.host = host self.port = port + self.drtio_dest = drtio_dest def open(self): if hasattr(self, "socket"): return self.socket = create_connection(self.host, self.port) self.socket.sendall(b"ARTIQ management\n") + self._write_int8(self.drtio_dest) endian = self._read(1) if endian == b"e": self.endian = "<" diff --git a/artiq/frontend/aqctl_corelog.py b/artiq/frontend/aqctl_corelog.py index c5f5a8eee..d2dd33a4a 100755 --- a/artiq/frontend/aqctl_corelog.py +++ b/artiq/frontend/aqctl_corelog.py @@ -25,6 +25,9 @@ def get_argparser(): help="Simulation - does not connect to device") parser.add_argument("core_addr", metavar="CORE_ADDR", 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 @@ -39,7 +42,7 @@ async def get_logs_sim(host): log_with_name("firmware.simulation", logging.INFO, "hello " + host) -async def get_logs(host): +async def get_logs(host, drtio_dest): try: reader, writer = await async_open_connection( host, @@ -49,6 +52,7 @@ async def get_logs(host): max_fails=3, ) writer.write(b"ARTIQ management\n") + writer.write(drtio_dest.to_bytes(1)) endian = await reader.readexactly(1) if endian == b"e": endian = "<" @@ -96,7 +100,7 @@ def main(): signal_handler.setup() try: 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) try: server = Server({"corelog": PingTarget()}, None, True) diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index 789c26bf7..2fbf450c0 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -95,6 +95,11 @@ def get_argparser(): p_allocator = subparsers.add_parser("allocator", 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 @@ -107,7 +112,7 @@ def main(): core_addr = ddb.get("core", resolve_alias=True)["arguments"]["host"] else: core_addr = args.device - mgmt = CommMgmt(core_addr) + mgmt = CommMgmt(core_addr, drtio_dest=args.satellite) if args.tool == "log": if args.action == "set_level": From 455e2a8f9d1a7988e0326906c92f4c4d1059ee1f Mon Sep 17 00:00:00 2001 From: occheung Date: Tue, 27 Aug 2024 21:36:07 +0800 Subject: [PATCH 06/42] satman coremgmt: EOF line --- artiq/firmware/satman/mgmt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/satman/mgmt.rs b/artiq/firmware/satman/mgmt.rs index 01c64dcef..245e5f4d6 100644 --- a/artiq/firmware/satman/mgmt.rs +++ b/artiq/firmware/satman/mgmt.rs @@ -49,4 +49,4 @@ impl Manager { error!("error on writing config: {:?}", err); }) } -} \ No newline at end of file +} From 644e24be349c213e0597ab3005c858ebc0d3fe44 Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 28 Aug 2024 17:43:21 +0800 Subject: [PATCH 07/42] local coremgmt: return the whole config after read --- artiq/firmware/runtime/mgmt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 0962fcc97..95ac3870b 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -333,7 +333,7 @@ mod remote_coremgmt { buffer.extend(&value[..length as usize]); if last { - Reply::ConfigData(&value[..length as usize]).write_to(stream)?; + Reply::ConfigData(&buffer).write_to(stream)?; return Ok(()); } From f6cf66966ddd28e40f56bfb95212cb536b838134 Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 29 Aug 2024 12:30:15 +0800 Subject: [PATCH 08/42] remote coremgmt: restart device gracefully after flashing --- .../firmware/libproto_artiq/drtioaux_proto.rs | 3 ++ artiq/firmware/runtime/mgmt.rs | 1 + artiq/firmware/satman/main.rs | 11 +--- artiq/firmware/satman/mgmt.rs | 50 +++++++++++++++---- 4 files changed, 46 insertions(+), 19 deletions(-) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index ba826873a..8dbe9c98a 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -143,6 +143,7 @@ pub enum Packet { CoreMgmtConfigReadReply { last: bool, length: u16, value: [u8; SAT_PAYLOAD_MAX_SIZE] }, CoreMgmtAck, CoreMgmtNack, + CoreMgmtRebootImminent, } impl Packet { @@ -507,6 +508,7 @@ impl Packet { }, 0xdd => Packet::CoreMgmtAck, 0xde => Packet::CoreMgmtNack, + 0xdf => Packet::CoreMgmtRebootImminent, ty => return Err(Error::UnknownPacket(ty)) }) @@ -878,6 +880,7 @@ impl Packet { }, Packet::CoreMgmtAck => writer.write_u8(0xdd)?, Packet::CoreMgmtNack => writer.write_u8(0xde)?, + Packet::CoreMgmtRebootImminent => writer.write_u8(0xdf)?, } Ok(()) } diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 95ac3870b..34a2c7d2e 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -372,6 +372,7 @@ mod remote_coremgmt { destination: destination, length: len as u16, last: status.is_last(), data: *slice}); match reply { Ok(Packet::CoreMgmtAck) => Ok(()), + Ok(Packet::CoreMgmtRebootImminent) if status.is_last() => Ok(()), Ok(packet) => { error!("received unexpected aux packet: {:?}", packet); Err(drtio::Error::UnexpectedReply) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 9513f1a81..c7ca63775 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -562,17 +562,10 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet); coremgr.add_data(&data, length as usize); - let mut succeeded = true; if last { - succeeded = coremgr.write_config().is_ok(); - debug!("Write succeeded: {}", succeeded); - coremgr.clear_data(); - } - - if succeeded { - drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck) + coremgr.write_config() } else { - drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack) + drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck) } } drtioaux::Packet::CoreMgmtConfigRemoveRequest { destination: _destination, length, key } => { diff --git a/artiq/firmware/satman/mgmt.rs b/artiq/firmware/satman/mgmt.rs index 245e5f4d6..7e220fcd9 100644 --- a/artiq/firmware/satman/mgmt.rs +++ b/artiq/firmware/satman/mgmt.rs @@ -1,13 +1,12 @@ use alloc::vec::Vec; use routing::{Sliceable, SliceMeta}; -use board_misoc::config; +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; -type Result = core::result::Result; - pub struct Manager { current_payload: Cursor>, last_value: Sliceable, @@ -21,7 +20,7 @@ impl Manager { } } - pub fn fetch_config_value(&mut self, key: &str) -> Result<()> { + 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")) @@ -40,13 +39,44 @@ impl Manager { self.current_payload.set_position(0); } - pub fn write_config(&mut self) -> Result<()> { - let key = self.current_payload.read_string().map_err( - |err| error!("error on reading key: {:?}", err))?; + 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::CoreMgmtNack); + } + }; + let value = self.current_payload.read_bytes().unwrap(); - config::write(&key, &value).map_err(|err| { - error!("error on writing config: {:?}", err); - }) + match key.as_str() { + "gateware" | "bootloader" | "firmware" => { + drtioaux::send(0, &drtioaux::Packet::CoreMgmtRebootImminent)?; + #[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(); + + if succeeded { + drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck) + } else { + drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack) + } + } + } } } From 7af8511de38398b986b1d373993823f4d7373dda Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 29 Aug 2024 12:40:36 +0800 Subject: [PATCH 09/42] drtio-proto: remove reboot imminent message --- artiq/firmware/libproto_artiq/drtioaux_proto.rs | 3 --- artiq/firmware/runtime/mgmt.rs | 1 - artiq/firmware/satman/mgmt.rs | 2 +- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 8dbe9c98a..ba826873a 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -143,7 +143,6 @@ pub enum Packet { CoreMgmtConfigReadReply { last: bool, length: u16, value: [u8; SAT_PAYLOAD_MAX_SIZE] }, CoreMgmtAck, CoreMgmtNack, - CoreMgmtRebootImminent, } impl Packet { @@ -508,7 +507,6 @@ impl Packet { }, 0xdd => Packet::CoreMgmtAck, 0xde => Packet::CoreMgmtNack, - 0xdf => Packet::CoreMgmtRebootImminent, ty => return Err(Error::UnknownPacket(ty)) }) @@ -880,7 +878,6 @@ impl Packet { }, Packet::CoreMgmtAck => writer.write_u8(0xdd)?, Packet::CoreMgmtNack => writer.write_u8(0xde)?, - Packet::CoreMgmtRebootImminent => writer.write_u8(0xdf)?, } Ok(()) } diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 34a2c7d2e..95ac3870b 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -372,7 +372,6 @@ mod remote_coremgmt { destination: destination, length: len as u16, last: status.is_last(), data: *slice}); match reply { Ok(Packet::CoreMgmtAck) => Ok(()), - Ok(Packet::CoreMgmtRebootImminent) if status.is_last() => Ok(()), Ok(packet) => { error!("received unexpected aux packet: {:?}", packet); Err(drtio::Error::UnexpectedReply) diff --git a/artiq/firmware/satman/mgmt.rs b/artiq/firmware/satman/mgmt.rs index 7e220fcd9..1c0641493 100644 --- a/artiq/firmware/satman/mgmt.rs +++ b/artiq/firmware/satman/mgmt.rs @@ -53,7 +53,7 @@ impl Manager { match key.as_str() { "gateware" | "bootloader" | "firmware" => { - drtioaux::send(0, &drtioaux::Packet::CoreMgmtRebootImminent)?; + drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck)?; #[cfg(not(soc_platform = "efc"))] unsafe { clock::spin_us(10000); From 5502aefa393804163e3c7ad24dc8adea4bd631c4 Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 29 Aug 2024 13:08:38 +0800 Subject: [PATCH 10/42] drtio-proto: merge coremgmt ACK adn NACK --- .../firmware/libproto_artiq/drtioaux_proto.rs | 14 ++++++++------ artiq/firmware/runtime/mgmt.rs | 16 ++++++++-------- artiq/firmware/satman/main.rs | 18 +++++++----------- artiq/firmware/satman/mgmt.rs | 10 +++------- 4 files changed, 26 insertions(+), 32 deletions(-) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index ba826873a..4aeeaec12 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -141,8 +141,7 @@ pub enum Packet { 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] }, - CoreMgmtAck, - CoreMgmtNack, + CoreMgmtReply { succeeded: bool }, } impl Packet { @@ -505,8 +504,9 @@ impl Packet { value: value, } }, - 0xdd => Packet::CoreMgmtAck, - 0xde => Packet::CoreMgmtNack, + 0xdd => Packet::CoreMgmtReply { + succeeded: reader.read_bool()?, + }, ty => return Err(Error::UnknownPacket(ty)) }) @@ -876,8 +876,10 @@ impl Packet { writer.write_u16(length)?; writer.write_all(&value[0..length as usize])?; }, - Packet::CoreMgmtAck => writer.write_u8(0xdd)?, - Packet::CoreMgmtNack => writer.write_u8(0xde)?, + Packet::CoreMgmtReply { succeeded } => { + writer.write_u8(0xdd)?; + writer.write_bool(succeeded)?; + }, } Ok(()) } diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 95ac3870b..3fd70079d 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -216,7 +216,7 @@ mod remote_coremgmt { ); match reply { - Ok(Packet::CoreMgmtAck) => { + Ok(Packet::CoreMgmtReply { succeeded: true }) => { Reply::Success.write_to(stream)?; Ok(()) } @@ -267,7 +267,7 @@ mod remote_coremgmt { ); match reply { - Ok(Packet::CoreMgmtAck) => { + Ok(Packet::CoreMgmtReply { succeeded: true }) => { Reply::Success.write_to(stream)?; Ok(()) } @@ -293,7 +293,7 @@ mod remote_coremgmt { ); match reply { - Ok(Packet::CoreMgmtAck) => { + Ok(Packet::CoreMgmtReply { succeeded: true }) => { Reply::Success.write_to(stream)?; Ok(()) } @@ -371,7 +371,7 @@ mod remote_coremgmt { &Packet::CoreMgmtConfigWriteRequest { destination: destination, length: len as u16, last: status.is_last(), data: *slice}); match reply { - Ok(Packet::CoreMgmtAck) => Ok(()), + Ok(Packet::CoreMgmtReply { succeeded: true }) => Ok(()), Ok(packet) => { error!("received unexpected aux packet: {:?}", packet); Err(drtio::Error::UnexpectedReply) @@ -410,7 +410,7 @@ mod remote_coremgmt { }); match reply { - Ok(Packet::CoreMgmtAck) => { + Ok(Packet::CoreMgmtReply { succeeded: true }) => { Reply::Success.write_to(stream)?; Ok(()) } @@ -437,7 +437,7 @@ mod remote_coremgmt { }); match reply { - Ok(Packet::CoreMgmtAck) => { + Ok(Packet::CoreMgmtReply { succeeded: true }) => { Reply::Success.write_to(stream)?; Ok(()) } @@ -464,7 +464,7 @@ mod remote_coremgmt { }); match reply { - Ok(Packet::CoreMgmtAck) => { + Ok(Packet::CoreMgmtReply { succeeded: true }) => { Reply::RebootImminent.write_to(stream)?; Ok(()) } @@ -491,7 +491,7 @@ mod remote_coremgmt { }); match reply { - Ok(Packet::CoreMgmtAck) => Ok(()), + Ok(Packet::CoreMgmtReply { succeeded: true }) => Ok(()), Ok(packet) => { error!("received unexpected aux packet: {:?}", packet); Err(drtio::Error::UnexpectedReply.into()) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index c7ca63775..16ccf31fb 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -504,13 +504,13 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg 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::CoreMgmtNack) + 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::CoreMgmtNack) + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false }) } drtioaux::Packet::CoreMgmtConfigReadRequest { destination: _destination, @@ -524,7 +524,7 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg let key_slice = &key[..length as usize]; if !key_slice.is_ascii() { error!("invalid key"); - drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack) + 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() { @@ -538,7 +538,7 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg }, ) } else { - drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack) + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false }) } } } @@ -565,7 +565,7 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg if last { coremgr.write_config() } else { - drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck) + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true }) } } drtioaux::Packet::CoreMgmtConfigRemoveRequest { destination: _destination, length, key } => { @@ -576,16 +576,12 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg .map_err(|err| warn!("error on removing config: {:?}", err)) .is_ok(); - if succeeded { - drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck) - } else { - drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack) - } + 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::CoreMgmtAck)?; + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })?; warn!("restarting"); unsafe { spiflash::reload(); } } diff --git a/artiq/firmware/satman/mgmt.rs b/artiq/firmware/satman/mgmt.rs index 1c0641493..86e5794e3 100644 --- a/artiq/firmware/satman/mgmt.rs +++ b/artiq/firmware/satman/mgmt.rs @@ -45,7 +45,7 @@ impl Manager { Err(err) => { self.clear_data(); error!("error on reading key: {:?}", err); - return drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack); + return drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false }); } }; @@ -53,7 +53,7 @@ impl Manager { match key.as_str() { "gateware" | "bootloader" | "firmware" => { - drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck)?; + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })?; #[cfg(not(soc_platform = "efc"))] unsafe { clock::spin_us(10000); @@ -71,11 +71,7 @@ impl Manager { self.clear_data(); - if succeeded { - drtioaux::send(0, &drtioaux::Packet::CoreMgmtAck) - } else { - drtioaux::send(0, &drtioaux::Packet::CoreMgmtNack) - } + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded }) } } } From 045ebd53c4fe12e0808905d4d25f3e16f508bdaa Mon Sep 17 00:00:00 2001 From: occheung Date: Fri, 30 Aug 2024 18:41:45 +0800 Subject: [PATCH 11/42] coremgmt: implement flash --- artiq/coredevice/comm_mgmt.py | 46 ++++++++++++++++ artiq/firmware/Cargo.lock | 1 + artiq/firmware/libboard_misoc/config.rs | 37 ++----------- artiq/firmware/libboard_misoc/spiflash.rs | 44 +++++++++++++++ artiq/firmware/libproto_artiq/mgmt_proto.rs | 6 ++ artiq/firmware/runtime/Cargo.toml | 1 + artiq/firmware/runtime/main.rs | 1 + artiq/firmware/runtime/mgmt.rs | 61 ++++++++++++++++++++- artiq/frontend/artiq_coremgmt.py | 43 +++++++++++++++ 9 files changed, 206 insertions(+), 34 deletions(-) diff --git a/artiq/coredevice/comm_mgmt.py b/artiq/coredevice/comm_mgmt.py index 1b218afec..f8f95fc84 100644 --- a/artiq/coredevice/comm_mgmt.py +++ b/artiq/coredevice/comm_mgmt.py @@ -1,5 +1,7 @@ from enum import Enum +import binascii import logging +import io import struct from sipyco.keepalive import create_connection @@ -23,6 +25,8 @@ class Request(Enum): DebugAllocator = 8 + Flash = 9 + class Reply(Enum): Success = 1 @@ -196,3 +200,45 @@ class CommMgmt: def debug_allocator(self): 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) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index 527a662ee..a14353341 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -513,6 +513,7 @@ dependencies = [ "board_misoc", "build_misoc", "byteorder", + "crc", "cslice", "dyld", "eh", diff --git a/artiq/firmware/libboard_misoc/config.rs b/artiq/firmware/libboard_misoc/config.rs index a7c3d4a63..e5e62ad0c 100644 --- a/artiq/firmware/libboard_misoc/config.rs +++ b/artiq/firmware/libboard_misoc/config.rs @@ -259,39 +259,12 @@ mod imp { } pub fn write(key: &str, value: &[u8]) -> Result<(), Error> { - fn flash_binary(origin: usize, payload: &[u8]) { - 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) => { - compact()?; - append(key, value) - } - res => res + match append(key, value) { + Err(Error::SpaceExhausted) => { + compact()?; + append(key, value) } + res => res } } diff --git a/artiq/firmware/libboard_misoc/spiflash.rs b/artiq/firmware/libboard_misoc/spiflash.rs index 598d96633..0f25ecbbc 100644 --- a/artiq/firmware/libboard_misoc/spiflash.rs +++ b/artiq/firmware/libboard_misoc/spiflash.rs @@ -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"))] pub unsafe fn reload () -> ! { csr::icap::iprog_write(1); diff --git a/artiq/firmware/libproto_artiq/mgmt_proto.rs b/artiq/firmware/libproto_artiq/mgmt_proto.rs index 74724df13..bfc8cc004 100644 --- a/artiq/firmware/libproto_artiq/mgmt_proto.rs +++ b/artiq/firmware/libproto_artiq/mgmt_proto.rs @@ -67,6 +67,8 @@ pub enum Request { Reboot, + Flash { image: Vec }, + DebugAllocator, } @@ -125,6 +127,10 @@ impl Request { 8 => Request::DebugAllocator, + 9 => Request::Flash { + image: reader.read_bytes()?, + }, + ty => return Err(Error::UnknownPacket(ty)) }) } diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 0d132d5a9..f06b93e49 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -16,6 +16,7 @@ build_misoc = { path = "../libbuild_misoc" } failure = { version = "0.1", default-features = false } failure_derive = { version = "0.1", default-features = false } byteorder = { version = "1.0", default-features = false } +crc = { version = "1.7", default-features = false } cslice = { version = "0.3" } log = { version = "=0.4.14", default-features = false } managed = { version = "^0.7.1", default-features = false, features = ["alloc", "map"] } diff --git a/artiq/firmware/runtime/main.rs b/artiq/firmware/runtime/main.rs index 78bf9b594..a66b48fcf 100644 --- a/artiq/firmware/runtime/main.rs +++ b/artiq/firmware/runtime/main.rs @@ -1,6 +1,7 @@ #![feature(lang_items, panic_info_message, const_btree_new, iter_advance_by, never_type)] #![no_std] +extern crate crc; extern crate dyld; extern crate eh; #[macro_use] diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 3fd70079d..e798db894 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -17,10 +17,11 @@ impl From for Error { mod local_coremgmt { use alloc::{string::String, vec::Vec}; + use crc::crc32; use log::LevelFilter; - use board_misoc::{config, spiflash}; - use io::{Write, ProtoWrite, Error as IoError}; + use board_misoc::{config, mem, spiflash}; + use io::{Cursor, Write, ProtoWrite, ProtoRead, Error as IoError}; use logger_artiq::BufferLogger; use mgmt_proto::{Error, Reply}; use sched::{Io, TcpStream, Error as SchedError}; @@ -153,6 +154,54 @@ mod local_coremgmt { unsafe { println!("{}", ::ALLOC) } Ok(()) } + + pub fn flash(_io: &Io, stream: &mut TcpStream, image: &Vec) -> Result<(), Error> { + 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]); + } + } + + 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)] @@ -502,6 +551,13 @@ mod remote_coremgmt { } } } + + 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) -> Result<(), Error> { + todo!() + } } #[cfg(has_drtio)] @@ -545,6 +601,7 @@ fn worker(io: &Io, stream: &mut TcpStream, restart_idle: &Urc>, Request::ConfigErase => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, config_erase, restart_idle), 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), }?; } } diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index 2fbf450c0..d6c1826ae 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -1,7 +1,10 @@ #!/usr/bin/env python3 import argparse +import os import struct +import tempfile +import atexit from sipyco import common_args @@ -9,6 +12,8 @@ from artiq import __version__ as artiq_version from artiq.master.databases import DeviceDB from artiq.coredevice.comm_kernel import CommKernel from artiq.coredevice.comm_mgmt import CommMgmt +from artiq.frontend.bit2bin import bit2bin +from misoc.tools.mkmscimg import insert_crc def get_argparser(): @@ -85,6 +90,13 @@ def get_argparser(): t_boot = tools.add_parser("reboot", 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 t_debug = tools.add_parser("debug", help="specialized debug functions") @@ -142,6 +154,37 @@ def main(): mgmt.config_remove(key) if args.action == "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": mgmt.reboot() From c5988ab48b64fe1a8cb99d23d61f593f6f0a3f2a Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 2 Sep 2024 16:55:34 +0800 Subject: [PATCH 12/42] mgmt flash: simplify protocol --- artiq/coredevice/comm_mgmt.py | 37 ++++------------------- artiq/firmware/runtime/mgmt.rs | 51 ++++++++++++-------------------- artiq/frontend/artiq_coremgmt.py | 8 ++--- 3 files changed, 27 insertions(+), 69 deletions(-) diff --git a/artiq/coredevice/comm_mgmt.py b/artiq/coredevice/comm_mgmt.py index f8f95fc84..b0ab94509 100644 --- a/artiq/coredevice/comm_mgmt.py +++ b/artiq/coredevice/comm_mgmt.py @@ -201,42 +201,17 @@ class CommMgmt: def debug_allocator(self): self._write_header(Request.DebugAllocator) - def flash(self, **bin_paths): + 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 io.BytesIO() as image_buf: + for filename in bin_paths: with open(filename, "rb") as fi: bin_ = fi.read() - length = bin_buf.write(bin_) + image_buf.write(struct.pack(self.endian + "I", len(bin_))) + image_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) + crc = binascii.crc32(image_buf.getvalue()) image_buf.write(struct.pack(self.endian + "I", crc)) self._write_bytes(image_buf.getvalue()) diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index e798db894..33959f9cd 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -17,11 +17,12 @@ impl From for Error { mod local_coremgmt { use alloc::{string::String, vec::Vec}; + use byteorder::{ByteOrder, NativeEndian}; use crc::crc32; use log::LevelFilter; use board_misoc::{config, mem, spiflash}; - use io::{Cursor, Write, ProtoWrite, ProtoRead, Error as IoError}; + use io::{Write, ProtoWrite, Error as IoError}; use logger_artiq::BufferLogger; use mgmt_proto::{Error, Reply}; use sched::{Io, TcpStream, Error as SchedError}; @@ -155,44 +156,30 @@ mod local_coremgmt { Ok(()) } - pub fn flash(_io: &Io, stream: &mut TcpStream, image: &Vec) -> Result<(), Error> { - let mut reader = Cursor::new(&image[..]); - let expected_crc = reader.read_u32().unwrap(); + pub fn flash(_io: &Io, stream: &mut TcpStream, image: &[u8]) -> Result<(), Error> { + let (expected_crc, mut image) = { + let (image, crc_slice) = image.split_at(image.len() - 4); + (NativeEndian::read_u32(crc_slice), image) + }; - 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 bin_origins = [ + ("gateware" , 0 ), + ("bootloader", mem::ROM_BASE ), + ("firmware" , mem::FLASH_BOOT_ADDRESS), + ]; - let header = &image[header_offset..bin_offset]; - let binaries = &image[bin_offset..]; + for (name, origin) in bin_origins { + info!("Flashing {} binary...", name); + let size = NativeEndian::read_u32(&image[..4]) as usize; + image = &image[4..]; - info!("found header of size {}", header.len()); + let (bin, remaining) = image.split_at(size); + image = remaining; - 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]); - } + unsafe { spiflash::flash_binary(origin, bin) }; } reboot(_io, stream)?; diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index d6c1826ae..8b23c7e7c 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -179,12 +179,8 @@ def main(): "Found firmware files: {}".format(" ".join(firmwares))) firmware = firmwares[0] - bins = { - "gateware": gateware, - "bootloader": bootloader, - "firmware": firmware, - } - mgmt.flash(**bins) + bins = [ gateware, bootloader, firmware ] + mgmt.flash(bins) if args.tool == "reboot": mgmt.reboot() From bb8148e554ba6744a60d8e06e624f37dc6d3f861 Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 2 Sep 2024 16:57:38 +0800 Subject: [PATCH 13/42] mgmt: implement flash via drtio --- artiq/firmware/Cargo.lock | 2 + .../firmware/libproto_artiq/drtioaux_proto.rs | 21 ++++ artiq/firmware/runtime/mgmt.rs | 31 +++++- artiq/firmware/satman/Cargo.toml | 2 + artiq/firmware/satman/main.rs | 16 ++- artiq/firmware/satman/mgmt.rs | 98 +++++++++++++------ 6 files changed, 137 insertions(+), 33 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index a14353341..aa156989e 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -554,6 +554,8 @@ dependencies = [ "board_artiq", "board_misoc", "build_misoc", + "byteorder", + "crc", "cslice", "eh", "io", diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 4aeeaec12..267b983df 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -139,6 +139,7 @@ pub enum Packet { CoreMgmtConfigEraseRequest { destination: u8 }, CoreMgmtRebootRequest { destination: u8 }, CoreMgmtAllocatorDebugRequest { destination: u8 }, + CoreMgmtFlashRequest { destination: u8, last: bool, length: u16, data: [u8; MASTER_PAYLOAD_MAX_SIZE] }, 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 }, @@ -507,6 +508,19 @@ impl Packet { 0xdd => Packet::CoreMgmtReply { succeeded: reader.read_bool()?, }, + 0xde => { + 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::CoreMgmtFlashRequest { + destination: destination, + last: last, + length: length, + data: data, + } + }, ty => return Err(Error::UnknownPacket(ty)) }) @@ -880,6 +894,13 @@ impl Packet { writer.write_u8(0xdd)?; writer.write_bool(succeeded)?; }, + Packet::CoreMgmtFlashRequest { destination, last, length, data } => { + writer.write_u8(0xde)?; + writer.write_u8(destination)?; + writer.write_bool(last)?; + writer.write_u16(length)?; + writer.write_all(&data[..length as usize])?; + }, } Ok(()) } diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 33959f9cd..65567b3bc 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -542,8 +542,33 @@ mod remote_coremgmt { 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) -> Result<(), Error> { - todo!() + destination: u8, stream: &mut TcpStream, image: &[u8]) -> Result<(), Error> { + + match drtio::partition_data(&image, |slice, status, len: usize| { + let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, + &Packet::CoreMgmtFlashRequest { + 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::RebootImminent.write_to(stream)?; + Ok(()) + }, + Err(e) => { + Reply::Error.write_to(stream)?; + Err(e.into()) + }, + } } } @@ -588,7 +613,7 @@ fn worker(io: &Io, stream: &mut TcpStream, restart_idle: &Urc>, Request::ConfigErase => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, config_erase, restart_idle), 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), + Request::Flash { ref image } => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, flash, &image[..]), }?; } } diff --git a/artiq/firmware/satman/Cargo.toml b/artiq/firmware/satman/Cargo.toml index f8016f576..522ae7b32 100644 --- a/artiq/firmware/satman/Cargo.toml +++ b/artiq/firmware/satman/Cargo.toml @@ -15,6 +15,8 @@ build_misoc = { path = "../libbuild_misoc" } [dependencies] log = { version = "0.4", default-features = false } io = { path = "../libio", features = ["byteorder", "alloc"] } +byteorder = { version = "1.0", default-features = false } +crc = { version = "1.7", default-features = false } cslice = { version = "0.3" } board_misoc = { path = "../libboard_misoc", features = ["uart_console", "log"] } board_artiq = { path = "../libboard_artiq", features = ["alloc"] } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 16ccf31fb..9a98528a6 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -9,6 +9,8 @@ extern crate board_artiq; extern crate riscv; extern crate alloc; extern crate proto_artiq; +extern crate byteorder; +extern crate crc; extern crate cslice; extern crate io; extern crate eh; @@ -558,10 +560,10 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg }, ) } - drtioaux::Packet::CoreMgmtConfigWriteRequest { destination: _destination, length, last, data } => { + drtioaux::Packet::CoreMgmtConfigWriteRequest { destination: _destination, last, length, data } => { forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet); - coremgr.add_data(&data, length as usize); + coremgr.add_config_data(&data, length as usize); if last { coremgr.write_config() } else { @@ -585,6 +587,16 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg warn!("restarting"); unsafe { spiflash::reload(); } } + drtioaux::Packet::CoreMgmtFlashRequest { destination: _destination, last, length, data } => { + forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet); + + coremgr.add_image_data(&data, length as usize); + if last { + coremgr.flash_image() + } else { + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true }) + } + } _ => { warn!("received unexpected aux packet"); diff --git a/artiq/firmware/satman/mgmt.rs b/artiq/firmware/satman/mgmt.rs index 86e5794e3..911a15d5d 100644 --- a/artiq/firmware/satman/mgmt.rs +++ b/artiq/firmware/satman/mgmt.rs @@ -1,21 +1,25 @@ use alloc::vec::Vec; +use byteorder::{ByteOrder, NativeEndian}; +use crc::crc32; use routing::{Sliceable, SliceMeta}; use board_artiq::drtioaux; -use board_misoc::{clock, config, csr, spiflash}; +use board_misoc::{mem, clock, config, csr, spiflash}; use io::{Cursor, ProtoRead, ProtoWrite}; use proto_artiq::drtioaux_proto::SAT_PAYLOAD_MAX_SIZE; pub struct Manager { - current_payload: Cursor>, + config_payload: Cursor>, + image_payload: Cursor>, last_value: Sliceable, } impl Manager { pub fn new() -> Manager { Manager { - current_payload: Cursor::new(Vec::new()), + config_payload: Cursor::new(Vec::new()), + image_payload: Cursor::new(Vec::new()), last_value: Sliceable::new(0, Vec::new()), } } @@ -30,49 +34,87 @@ impl Manager { 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 add_config_data(&mut self, data: &[u8], data_len: usize) { + self.config_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 clear_config_data(&mut self) { + self.config_payload.get_mut().clear(); + self.config_payload.set_position(0); } pub fn write_config(&mut self) -> Result<(), drtioaux::Error> { - let key = match self.current_payload.read_string() { + let key = match self.config_payload.read_string() { Ok(key) => key, Err(err) => { - self.clear_data(); + self.clear_config_data(); error!("error on reading key: {:?}", err); return drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false }); } }; - let value = self.current_payload.read_bytes().unwrap(); + let value = self.config_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_config_data(); + + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded }) + } + + pub fn add_image_data(&mut self, data: &[u8], data_len: usize) { + self.image_payload.write_all(&data[..data_len]).unwrap(); + } + + pub fn clear_image_data(&mut self) { + self.image_payload.get_mut().clear(); + self.image_payload.set_position(0); + } + + pub fn flash_image(&mut self) -> Result<(), drtioaux::Error> { + let image = &self.image_payload.get_ref()[..]; + + let (expected_crc, mut image) = { + let (image, crc_slice) = image.split_at(image.len() - 4); + (NativeEndian::read_u32(crc_slice), image) + }; + + let actual_crc = crc32::checksum_ieee(image); + + if actual_crc == expected_crc { + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })?; + #[cfg(not(soc_platform = "efc"))] + unsafe { + clock::spin_us(10000); + csr::gt_drtio::txenable_write(0); } - _ => { - let succeeded = config::write(&key, &value).map_err(|err| { - error!("error on writing config: {:?}", err); - }).is_ok(); + let bin_origins = [ + ("gateware" , 0 ), + ("bootloader", mem::ROM_BASE ), + ("firmware" , mem::FLASH_BOOT_ADDRESS), + ]; - self.clear_data(); + for (name, origin) in bin_origins { + info!("Flashing {} binary...", name); + let size = NativeEndian::read_u32(&image[..4]) as usize; + image = &image[4..]; - drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded }) + let (bin, remaining) = image.split_at(size); + image = remaining; + + unsafe { spiflash::flash_binary(origin, bin) }; } + + warn!("restarting"); + unsafe { spiflash::reload(); } + + } else { + error!("CRC failed in SDRAM (actual {:08x}, expected {:08x})", actual_crc, expected_crc); + self.clear_image_data(); + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false }) } } } From 2c0a4c0bae9acd4c0b4a5489045423b6a320de7a Mon Sep 17 00:00:00 2001 From: occheung Date: Tue, 3 Sep 2024 11:42:39 +0800 Subject: [PATCH 14/42] drtio_proto: implement reboot init handshake --- .../firmware/libproto_artiq/drtioaux_proto.rs | 12 +++++++++ artiq/firmware/runtime/mgmt.rs | 12 ++++++++- artiq/firmware/satman/main.rs | 19 +++++++++++++- artiq/firmware/satman/mgmt.rs | 25 +++---------------- 4 files changed, 45 insertions(+), 23 deletions(-) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 267b983df..4e269fdd1 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -140,6 +140,8 @@ pub enum Packet { CoreMgmtRebootRequest { destination: u8 }, CoreMgmtAllocatorDebugRequest { destination: u8 }, CoreMgmtFlashRequest { destination: u8, last: bool, length: u16, data: [u8; MASTER_PAYLOAD_MAX_SIZE] }, + CoreMgmtDropLinkAck { destination: u8 }, + CoreMgmtDropLink, 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 }, @@ -521,6 +523,10 @@ impl Packet { data: data, } }, + 0xdf => Packet::CoreMgmtDropLink, + 0xe0 => Packet::CoreMgmtDropLinkAck { + destination: reader.read_u8()?, + }, ty => return Err(Error::UnknownPacket(ty)) }) @@ -901,6 +907,12 @@ impl Packet { writer.write_u16(length)?; writer.write_all(&data[..length as usize])?; }, + Packet::CoreMgmtDropLink => + writer.write_u8(0xdf)?, + Packet::CoreMgmtDropLinkAck { destination } => { + writer.write_u8(0xe0)?; + writer.write_u8(destination)?; + }, } Ok(()) } diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 65567b3bc..0c1b423d6 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -196,7 +196,7 @@ mod remote_coremgmt { use alloc::{string::String, vec::Vec}; use log::LevelFilter; - use board_artiq::{drtioaux::Packet, drtio_routing}; + use board_artiq::{drtioaux, drtioaux::Packet, drtio_routing}; use io::{Cursor, ProtoWrite}; use mgmt_proto::{Error, Reply}; use rtio_mgt::drtio; @@ -550,6 +550,16 @@ mod remote_coremgmt { destination: destination, length: len as u16, last: status.is_last(), data: *slice}); match reply { Ok(Packet::CoreMgmtReply { succeeded: true }) => Ok(()), + Ok(Packet::CoreMgmtDropLink) => { + if status.is_last() { + drtioaux::send( + linkno, &Packet::CoreMgmtDropLinkAck { destination: destination } + ).map_err(|_| drtio::Error::AuxError) + } else { + error!("received unexpected drop link packet"); + Err(drtio::Error::UnexpectedReply) + } + } Ok(packet) => { error!("received unexpected aux packet: {:?}", packet); Err(drtio::Error::UnexpectedReply) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 9a98528a6..1647c7955 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -592,11 +592,28 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg coremgr.add_image_data(&data, length as usize); if last { - coremgr.flash_image() + drtioaux::send(0, &drtioaux::Packet::CoreMgmtDropLink) } else { drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true }) } } + drtioaux::Packet::CoreMgmtDropLinkAck { destination: _destination } => { + forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet); + + #[cfg(not(soc_platform = "efc"))] + unsafe { + csr::gt_drtio::txenable_write(0); + } + + #[cfg(has_drtio_eem)] + unsafe { + csr::eem_transceiver::txenable_write(0); + } + + coremgr.flash_image(); + warn!("restarting"); + unsafe { spiflash::reload(); } + } _ => { warn!("received unexpected aux packet"); diff --git a/artiq/firmware/satman/mgmt.rs b/artiq/firmware/satman/mgmt.rs index 911a15d5d..2b44bc4bb 100644 --- a/artiq/firmware/satman/mgmt.rs +++ b/artiq/firmware/satman/mgmt.rs @@ -4,7 +4,7 @@ use crc::crc32; use routing::{Sliceable, SliceMeta}; use board_artiq::drtioaux; -use board_misoc::{mem, clock, config, csr, spiflash}; +use board_misoc::{mem, config, spiflash}; use io::{Cursor, ProtoRead, ProtoWrite}; use proto_artiq::drtioaux_proto::SAT_PAYLOAD_MAX_SIZE; @@ -68,12 +68,7 @@ impl Manager { self.image_payload.write_all(&data[..data_len]).unwrap(); } - pub fn clear_image_data(&mut self) { - self.image_payload.get_mut().clear(); - self.image_payload.set_position(0); - } - - pub fn flash_image(&mut self) -> Result<(), drtioaux::Error> { + pub fn flash_image(&self) { let image = &self.image_payload.get_ref()[..]; let (expected_crc, mut image) = { @@ -84,13 +79,6 @@ impl Manager { let actual_crc = crc32::checksum_ieee(image); if actual_crc == expected_crc { - drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true })?; - #[cfg(not(soc_platform = "efc"))] - unsafe { - clock::spin_us(10000); - csr::gt_drtio::txenable_write(0); - } - let bin_origins = [ ("gateware" , 0 ), ("bootloader", mem::ROM_BASE ), @@ -98,7 +86,7 @@ impl Manager { ]; for (name, origin) in bin_origins { - info!("Flashing {} binary...", name); + info!("flashing {} binary...", name); let size = NativeEndian::read_u32(&image[..4]) as usize; image = &image[4..]; @@ -108,13 +96,8 @@ impl Manager { unsafe { spiflash::flash_binary(origin, bin) }; } - warn!("restarting"); - unsafe { spiflash::reload(); } - } else { - error!("CRC failed in SDRAM (actual {:08x}, expected {:08x})", actual_crc, expected_crc); - self.clear_image_data(); - drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false }) + panic!("CRC failed in SDRAM (actual {:08x}, expected {:08x})", actual_crc, expected_crc); } } } From d935c22aad784ac1b233dff5d007ca316d7eb844 Mon Sep 17 00:00:00 2001 From: occheung Date: Tue, 3 Sep 2024 11:55:34 +0800 Subject: [PATCH 15/42] remove dead commented code --- artiq/firmware/libboard_misoc/spiflash.rs | 34 ----------------------- 1 file changed, 34 deletions(-) diff --git a/artiq/firmware/libboard_misoc/spiflash.rs b/artiq/firmware/libboard_misoc/spiflash.rs index 0f25ecbbc..7d66977f7 100644 --- a/artiq/firmware/libboard_misoc/spiflash.rs +++ b/artiq/firmware/libboard_misoc/spiflash.rs @@ -114,40 +114,6 @@ 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; From 18744388907e60cf96b70d7b5e1a327cb2f349ec Mon Sep 17 00:00:00 2001 From: occheung Date: Tue, 3 Sep 2024 12:37:32 +0800 Subject: [PATCH 16/42] coremgmt frontend: add artiq flash like source tree support --- artiq/frontend/artiq_coremgmt.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index 8b23c7e7c..b51861a95 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -97,6 +97,10 @@ def get_argparser(): p_directory = t_flash.add_argument("directory", metavar="DIRECTORY", type=str, help="directory that contains the binaries") + p_srcbuild = t_flash.add_argument("--srcbuild", + help="board binaries directory is laid out as a source build tree", + default=False, action="store_true") + # misc debug t_debug = tools.add_parser("debug", help="specialized debug functions") @@ -156,6 +160,15 @@ def main(): mgmt.config_erase() if args.tool == "flash": + def artifact_path(this_binary_dir, *path_filename): + if args.srcbuild: + # source tree - use path elements to locate file + return os.path.join(this_binary_dir, *path_filename) + else: + # flat tree - all files in the same directory, discard path elements + *_, filename = path_filename + return os.path.join(this_binary_dir, filename) + def convert_gateware(bit_filename): bin_handle, bin_filename = tempfile.mkstemp( prefix="artiq_", suffix="_" + os.path.basename(bit_filename)) @@ -164,12 +177,13 @@ def main(): 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") + gateware = convert_gateware( + artifact_path(args.directory, "gateware", "top.bit")) + bootloader = artifact_path(args.directory, "software", "bootloader", "bootloader.bin") firmwares = [] for firmware in "satman", "runtime": - filename = os.path.join(args.directory, firmware + ".fbi") + filename = artifact_path(args.directory, "software", firmware, firmware + ".fbi") if os.path.exists(filename): firmwares.append(filename) if not firmwares: From e85b640a838c25fd55a82511a96602ff5eaa1ab7 Mon Sep 17 00:00:00 2001 From: occheung Date: Tue, 3 Sep 2024 16:46:39 +0800 Subject: [PATCH 17/42] drtop-proto: rearrange packet assignment --- .../firmware/libproto_artiq/drtioaux_proto.rs | 94 +++++++++---------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 4e269fdd1..19a6502af 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -486,31 +486,6 @@ impl Packet { 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()?, - }, - 0xde => { let destination = reader.read_u8()?; let last = reader.read_bool()?; let length = reader.read_u16()?; @@ -523,10 +498,35 @@ impl Packet { data: data, } }, - 0xdf => Packet::CoreMgmtDropLink, - 0xe0 => Packet::CoreMgmtDropLinkAck { + 0xdc => Packet::CoreMgmtDropLinkAck { destination: reader.read_u8()?, }, + 0xdd => Packet::CoreMgmtDropLink, + 0xde => { + 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, + } + }, + 0xdf => { + 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, + } + }, + 0xe0 => Packet::CoreMgmtReply { + succeeded: reader.read_bool()?, + }, ty => return Err(Error::UnknownPacket(ty)) }) @@ -884,35 +884,35 @@ impl Packet { 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)?; - }, Packet::CoreMgmtFlashRequest { destination, last, length, data } => { - writer.write_u8(0xde)?; + writer.write_u8(0xdb)?; writer.write_u8(destination)?; writer.write_bool(last)?; writer.write_u16(length)?; writer.write_all(&data[..length as usize])?; }, - Packet::CoreMgmtDropLink => - writer.write_u8(0xdf)?, Packet::CoreMgmtDropLinkAck { destination } => { - writer.write_u8(0xe0)?; + writer.write_u8(0xdc)?; writer.write_u8(destination)?; }, + Packet::CoreMgmtDropLink => + writer.write_u8(0xdd)?, + Packet::CoreMgmtGetLogReply { last, length, data } => { + writer.write_u8(0xde)?; + writer.write_bool(last)?; + writer.write_u16(length)?; + writer.write_all(&data[0..length as usize])?; + }, + Packet::CoreMgmtConfigReadReply { last, length, value } => { + writer.write_u8(0xdf)?; + writer.write_bool(last)?; + writer.write_u16(length)?; + writer.write_all(&value[0..length as usize])?; + }, + Packet::CoreMgmtReply { succeeded } => { + writer.write_u8(0xe0)?; + writer.write_bool(succeeded)?; + }, } Ok(()) } From a56294f9de513cca8e460613491f5775b2744cbc Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 5 Sep 2024 11:56:43 +0800 Subject: [PATCH 18/42] satman coremgmt: impl config erase --- artiq/firmware/satman/main.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 1647c7955..3909ce6d3 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -580,6 +580,15 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded }) } + drtioaux::Packet::CoreMgmtConfigEraseRequest { destination: _destination } => { + forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet); + + let succeeded = config::erase() + .map_err(|err| warn!("error on erasing 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); From f2f27e2d308551750eb6ab6603210b8a623c9678 Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 5 Sep 2024 11:59:10 +0800 Subject: [PATCH 19/42] runtime mgmt: remove cursor --- artiq/firmware/runtime/mgmt.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 0c1b423d6..176a4d7ba 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -398,11 +398,11 @@ mod remote_coremgmt { routing_table: &drtio_routing::RoutingTable, linkno: u8, destination: u8, stream: &mut TcpStream, key: &String, value: &Vec, _restart_idle: &Urc>) -> Result<(), Error> { - let mut message = Cursor::new(Vec::with_capacity(key.len() + value.len() + 4 * 2)); + let mut message = 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| { + match drtio::partition_data(&message, |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}); From 4a54241e1bc2dea500df4668cc2026eeb810a3e1 Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 5 Sep 2024 11:59:23 +0800 Subject: [PATCH 20/42] runtime mgmt: reorganize uses --- artiq/firmware/runtime/mgmt.rs | 43 +++++++++++++++++----------------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 176a4d7ba..436d1d22c 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -2,7 +2,7 @@ use log::{self, LevelFilter}; use core::cell::Cell; use core::cell::RefCell; -use board_artiq::drtio_routing; +use board_artiq::drtio_routing::RoutingTable; use io::{ProtoRead, Write, Error as IoError}; use mgmt_proto::*; use sched::{Io, TcpListener, TcpStream, Error as SchedError}; @@ -22,10 +22,10 @@ mod local_coremgmt { use log::LevelFilter; use board_misoc::{config, mem, spiflash}; - use io::{Write, ProtoWrite, Error as IoError}; + use io::ProtoWrite; use logger_artiq::BufferLogger; - use mgmt_proto::{Error, Reply}; - use sched::{Io, TcpStream, Error as SchedError}; + + use super::*; pub fn get_log(io: &Io, stream: &mut TcpStream) -> Result<(), Error> { @@ -196,13 +196,12 @@ mod remote_coremgmt { use alloc::{string::String, vec::Vec}; use log::LevelFilter; - use board_artiq::{drtioaux, drtioaux::Packet, drtio_routing}; - use io::{Cursor, ProtoWrite}; - use mgmt_proto::{Error, Reply}; + use board_artiq::{drtioaux, drtioaux::Packet}; + use io::ProtoWrite; use rtio_mgt::drtio; - use sched::{Io, Mutex, TcpStream, Error as SchedError}; use proto_artiq::drtioaux_proto::MASTER_PAYLOAD_MAX_SIZE; + use super::*; impl From for Error { fn from(_value: drtio::Error) -> Error { @@ -212,7 +211,7 @@ mod remote_coremgmt { pub fn get_log(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, - routing_table: &drtio_routing::RoutingTable, linkno: u8, + routing_table: &RoutingTable, linkno: u8, destination: u8, stream: &mut TcpStream) -> Result<(), Error> { let mut buffer = String::new(); loop { @@ -245,7 +244,7 @@ mod remote_coremgmt { pub fn clear_log(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, - routing_table: &drtio_routing::RoutingTable, linkno: u8, + routing_table: &RoutingTable, linkno: u8, destination: u8, stream: &mut TcpStream) -> Result<(), Error> { let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, &Packet::CoreMgmtClearLogRequest { destination } @@ -271,7 +270,7 @@ mod remote_coremgmt { pub fn pull_log(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, - routing_table: &drtio_routing::RoutingTable, linkno: u8, + routing_table: &RoutingTable, linkno: u8, destination: u8, stream: &mut TcpStream) -> Result<(), Error> { loop { let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, @@ -296,7 +295,7 @@ mod remote_coremgmt { pub fn set_log_filter(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, - routing_table: &drtio_routing::RoutingTable, linkno: u8, + routing_table: &RoutingTable, linkno: u8, destination: u8, stream: &mut TcpStream, level: LevelFilter) -> Result<(), Error> { let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, &Packet::CoreMgmtSetLogLevelRequest { destination, log_level: level as u8 } @@ -322,7 +321,7 @@ mod remote_coremgmt { pub fn set_uart_log_filter(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, - routing_table: &drtio_routing::RoutingTable, linkno: u8, + routing_table: &RoutingTable, linkno: u8, destination: u8, stream: &mut TcpStream, level: LevelFilter) -> Result<(), Error> { let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, &Packet::CoreMgmtSetUartLogLevelRequest { destination, log_level: level as u8 } @@ -348,7 +347,7 @@ mod remote_coremgmt { pub fn config_read(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, - routing_table: &drtio_routing::RoutingTable, linkno: u8, + routing_table: &RoutingTable, linkno: u8, destination: u8, stream: &mut TcpStream, key: &String) -> Result<(), Error> { let mut config_key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE]; let len = key.len(); @@ -395,7 +394,7 @@ mod remote_coremgmt { pub fn config_write(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, - routing_table: &drtio_routing::RoutingTable, linkno: u8, + routing_table: &RoutingTable, linkno: u8, destination: u8, stream: &mut TcpStream, key: &String, value: &Vec, _restart_idle: &Urc>) -> Result<(), Error> { let mut message = Vec::with_capacity(key.len() + value.len() + 4 * 2); @@ -431,7 +430,7 @@ mod remote_coremgmt { pub fn config_remove(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, - routing_table: &drtio_routing::RoutingTable, linkno: u8, + routing_table: &RoutingTable, linkno: u8, destination: u8, stream: &mut TcpStream, key: &String, _restart_idle: &Urc>) -> Result<(), Error> { let mut config_key: [u8; MASTER_PAYLOAD_MAX_SIZE] = [0; MASTER_PAYLOAD_MAX_SIZE]; @@ -465,7 +464,7 @@ mod remote_coremgmt { pub fn config_erase(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, - routing_table: &drtio_routing::RoutingTable, linkno: u8, + routing_table: &RoutingTable, linkno: u8, destination: u8, stream: &mut TcpStream, _restart_idle: &Urc>) -> Result<(), Error> { let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, &Packet::CoreMgmtConfigEraseRequest { @@ -492,7 +491,7 @@ mod remote_coremgmt { pub fn reboot(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, - routing_table: &drtio_routing::RoutingTable, linkno: u8, + routing_table: &RoutingTable, linkno: u8, destination: u8, stream: &mut TcpStream) -> Result<(), Error> { let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, &Packet::CoreMgmtRebootRequest { @@ -519,7 +518,7 @@ mod remote_coremgmt { pub fn debug_allocator(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, - routing_table: &drtio_routing::RoutingTable, linkno: u8, + routing_table: &RoutingTable, linkno: u8, destination: u8, _stream: &mut TcpStream) -> Result<(), Error> { let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, &Packet::CoreMgmtAllocatorDebugRequest { @@ -541,7 +540,7 @@ mod remote_coremgmt { pub fn flash(io: &Io, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, - routing_table: &drtio_routing::RoutingTable, linkno: u8, + routing_table: &RoutingTable, linkno: u8, destination: u8, stream: &mut TcpStream, image: &[u8]) -> Result<(), Error> { match drtio::partition_data(&image, |slice, status, len: usize| { @@ -604,7 +603,7 @@ macro_rules! process { fn worker(io: &Io, stream: &mut TcpStream, restart_idle: &Urc>, _aux_mutex: &Mutex, _ddma_mutex: &Mutex, _subkernel_mutex: &Mutex, - _routing_table: &drtio_routing::RoutingTable, stream: &mut TcpStream) -> Result<(), Error> { + _routing_table: &RoutingTable, stream: &mut TcpStream) -> Result<(), Error> { read_magic(stream)?; let _destination = stream.read_u8()?; Write::write_all(stream, "e".as_bytes())?; @@ -628,7 +627,7 @@ fn worker(io: &Io, stream: &mut TcpStream, restart_idle: &Urc>, } } -pub fn thread(io: Io, restart_idle: &Urc>, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, routing_table: &Urc>) { +pub fn thread(io: Io, restart_idle: &Urc>, aux_mutex: &Mutex, ddma_mutex: &Mutex, subkernel_mutex: &Mutex, routing_table: &Urc>) { let listener = TcpListener::new(&io, 8192); listener.listen(1380).expect("mgmt: cannot listen"); info!("management interface active"); From 2b73d5a4c6f54a22b4e8cb76cf229ad0c54f924b Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 9 Sep 2024 17:28:14 +0800 Subject: [PATCH 21/42] drtio-proto: avoid expecting drop link ack response --- artiq/firmware/libproto_artiq/drtioaux_proto.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 19a6502af..9a0f423dc 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -946,7 +946,7 @@ impl Packet { Packet::DmaAddTraceReply { .. } | Packet::DmaRemoveTraceReply { .. } | Packet::DmaPlaybackReply { .. } | Packet::SubkernelLoadRunReply { .. } | Packet::SubkernelMessageAck { .. } | Packet::DmaPlaybackStatus { .. } | - Packet::SubkernelFinished { .. } => false, + Packet::SubkernelFinished { .. } | Packet::CoreMgmtDropLinkAck { .. } => false, _ => true } } From 5c21649d10b5a9c9de11c398a5b3bc2af3aa8d16 Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 19 Sep 2024 09:46:17 +0800 Subject: [PATCH 22/42] frontend: make coremgmt flash zynq-compatible --- artiq/coredevice/comm_mgmt.py | 3 +- artiq/frontend/artiq_coremgmt.py | 68 ++++++++++++++++++-------------- 2 files changed, 40 insertions(+), 31 deletions(-) diff --git a/artiq/coredevice/comm_mgmt.py b/artiq/coredevice/comm_mgmt.py index b0ab94509..c9f466b59 100644 --- a/artiq/coredevice/comm_mgmt.py +++ b/artiq/coredevice/comm_mgmt.py @@ -208,7 +208,8 @@ class CommMgmt: for filename in bin_paths: with open(filename, "rb") as fi: bin_ = fi.read() - image_buf.write(struct.pack(self.endian + "I", len(bin_))) + if (len(bin_paths) > 1): + image_buf.write(struct.pack(self.endian + "I", len(bin_))) image_buf.write(bin_) crc = binascii.crc32(image_buf.getvalue()) diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index b51861a95..e9cada16f 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -94,6 +94,9 @@ def get_argparser(): t_flash = tools.add_parser("flash", help="flash the running system") + p_zynq = t_flash.add_argument("-z", "--zynq", default=False, + help="target zynq device", action="store_true") + p_directory = t_flash.add_argument("directory", metavar="DIRECTORY", type=str, help="directory that contains the binaries") @@ -160,40 +163,45 @@ def main(): mgmt.config_erase() if args.tool == "flash": - def artifact_path(this_binary_dir, *path_filename): - if args.srcbuild: - # source tree - use path elements to locate file - return os.path.join(this_binary_dir, *path_filename) - else: - # flat tree - all files in the same directory, discard path elements - *_, filename = path_filename - return os.path.join(this_binary_dir, filename) + if args.zynq: + boot = os.path.join(args.directory, "boot.bin") + bins = [ boot ] + else: + def artifact_path(this_binary_dir, *path_filename): + if args.srcbuild: + # source tree - use path elements to locate file + return os.path.join(this_binary_dir, *path_filename) + else: + # flat tree - all files in the same directory, discard path elements + *_, filename = path_filename + return os.path.join(this_binary_dir, filename) - 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 + 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( - artifact_path(args.directory, "gateware", "top.bit")) - bootloader = artifact_path(args.directory, "software", "bootloader", "bootloader.bin") + gateware = convert_gateware( + artifact_path(args.directory, "gateware", "top.bit")) + bootloader = artifact_path(args.directory, "software", "bootloader", "bootloader.bin") - firmwares = [] - for firmware in "satman", "runtime": - filename = artifact_path(args.directory, "software", firmware, 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] + firmwares = [] + for firmware in "satman", "runtime": + filename = artifact_path(args.directory, "software", firmware, 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, bootloader, firmware ] - bins = [ gateware, bootloader, firmware ] mgmt.flash(bins) if args.tool == "reboot": From a2d341f4d62edfac402d8f090479613b2ed4dbba Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 19 Sep 2024 17:18:16 +0800 Subject: [PATCH 23/42] satman mgmt: get_slice_sat -> get_slice_satellite --- artiq/firmware/satman/mgmt.rs | 2 +- artiq/firmware/satman/routing.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/artiq/firmware/satman/mgmt.rs b/artiq/firmware/satman/mgmt.rs index 2b44bc4bb..ad0526b0d 100644 --- a/artiq/firmware/satman/mgmt.rs +++ b/artiq/firmware/satman/mgmt.rs @@ -31,7 +31,7 @@ impl Manager { } 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) + self.last_value.get_slice_satellite(data_slice) } pub fn add_config_data(&mut self, data: &[u8], data_len: usize) { diff --git a/artiq/firmware/satman/routing.rs b/artiq/firmware/satman/routing.rs index f8e0e6d24..2861f9fe6 100644 --- a/artiq/firmware/satman/routing.rs +++ b/artiq/firmware/satman/routing.rs @@ -4,6 +4,7 @@ use board_artiq::{drtioaux, drtio_routing}; use board_misoc::csr; use core::cmp::min; use proto_artiq::drtioaux_proto::PayloadStatus; +use SAT_PAYLOAD_MAX_SIZE; use MASTER_PAYLOAD_MAX_SIZE; /* represents data that has to be sent with the aux protocol */ @@ -56,6 +57,7 @@ impl Sliceable { self.data.extend(data); } + get_slice_fn!(get_slice_satellite, SAT_PAYLOAD_MAX_SIZE); get_slice_fn!(get_slice_master, MASTER_PAYLOAD_MAX_SIZE); } From 28654501af376b940d9968649bf843df75edeaf2 Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 19 Sep 2024 17:18:57 +0800 Subject: [PATCH 24/42] runtime mgmt: minor fix --- artiq/firmware/runtime/mgmt.rs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 436d1d22c..480443ba0 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -1,11 +1,8 @@ -use log::{self, LevelFilter}; -use core::cell::Cell; -use core::cell::RefCell; +use core::cell::{Cell, RefCell}; use board_artiq::drtio_routing::RoutingTable; use io::{ProtoRead, Write, Error as IoError}; use mgmt_proto::*; -use sched::{Io, TcpListener, TcpStream, Error as SchedError}; use sched::{Io, Mutex, TcpListener, TcpStream, Error as SchedError}; use urc::Urc; @@ -102,7 +99,7 @@ mod local_coremgmt { Ok(()) } - pub fn config_write(_io: &Io, stream: &mut TcpStream, key: &String, value: &Vec, restart_idle: &Urc>) -> Result<(), Error> { + pub fn config_write(io: &Io, stream: &mut TcpStream, key: &String, value: &Vec, restart_idle: &Urc>) -> Result<(), Error> { match config::write(key, value) { Ok(_) => { if key == "idle_kernel" { @@ -116,7 +113,7 @@ mod local_coremgmt { Ok(()) } - pub fn config_remove(_io: &Io, stream: &mut TcpStream, key: &String, restart_idle: &Urc>) -> Result<(), Error> { + pub fn config_remove(io: &Io, stream: &mut TcpStream, key: &String, restart_idle: &Urc>) -> Result<(), Error> { match config::remove(key) { Ok(()) => { if key == "idle_kernel" { @@ -130,7 +127,7 @@ mod local_coremgmt { Ok(()) } - pub fn config_erase(_io: &Io, stream: &mut TcpStream, restart_idle: &Urc>) -> Result<(), Error> { + pub fn config_erase(io: &Io, stream: &mut TcpStream, restart_idle: &Urc>) -> Result<(), Error> { match config::erase() { Ok(()) => { io.until(|| !restart_idle.get())?; @@ -603,7 +600,7 @@ macro_rules! process { fn worker(io: &Io, stream: &mut TcpStream, restart_idle: &Urc>, _aux_mutex: &Mutex, _ddma_mutex: &Mutex, _subkernel_mutex: &Mutex, - _routing_table: &RoutingTable, stream: &mut TcpStream) -> Result<(), Error> { + _routing_table: &RoutingTable) -> Result<(), Error> { read_magic(stream)?; let _destination = stream.read_u8()?; Write::write_all(stream, "e".as_bytes())?; From 6b6bcdb6d6dfacc662968cabced79a9efcd0f635 Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 19 Sep 2024 17:42:03 +0800 Subject: [PATCH 25/42] runtime mgmt: avoid passing incomplete message to corelog --- artiq/firmware/runtime/mgmt.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 480443ba0..fd39be059 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -269,14 +269,20 @@ mod remote_coremgmt { ddma_mutex: &Mutex, subkernel_mutex: &Mutex, routing_table: &RoutingTable, linkno: u8, destination: u8, stream: &mut TcpStream) -> Result<(), Error> { + let mut buffer = Vec::new(); 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::CoreMgmtGetLogReply { last, length, data }) => { + buffer.extend(&data[..length as usize]); + + if last { + stream.write_bytes(&buffer[..length as usize])?; + buffer.clear(); + } } Ok(packet) => { error!("received unexpected aux packet: {:?}", packet); From 9d3204d0193de6f8bb8091687285ccad56303537 Mon Sep 17 00:00:00 2001 From: occheung Date: Fri, 20 Sep 2024 11:46:33 +0800 Subject: [PATCH 26/42] runtim mgmt: fix pull log message relaying --- artiq/firmware/runtime/mgmt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index fd39be059..5527edb3b 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -280,7 +280,7 @@ mod remote_coremgmt { buffer.extend(&data[..length as usize]); if last { - stream.write_bytes(&buffer[..length as usize])?; + stream.write_bytes(&buffer)?; buffer.clear(); } } From 2e9622b9d6738c8edcdf0172638c8b0ebb81c8e3 Mon Sep 17 00:00:00 2001 From: occheung Date: Fri, 20 Sep 2024 11:47:05 +0800 Subject: [PATCH 27/42] update RELEASE_NOTES --- RELEASE_NOTES.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 7d1c160c8..3e4d3c4b4 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -22,6 +22,8 @@ ARTIQ-9 (Unreleased) * Idle kernels now restart when written with ``artiq_coremgmt`` and stop when erased/removed from config. * New support for the EBAZ4205 Zynq-SoC control card. * New core device driver for the AD9834 DDS, tested with the ZonRi Technology Co., Ltd. AD9834-Module. +* Support for coredevice reflashing through new the ``flash`` tool in ``artiq_coremgmt``. +* ``artiq_coremgmt`` now supports configuring satellites. ARTIQ-8 ------- From cc40313501eb182cb2ecc1d109feaa3458893606 Mon Sep 17 00:00:00 2001 From: occheung Date: Fri, 20 Sep 2024 17:38:14 +0800 Subject: [PATCH 28/42] flake8 --- artiq/coredevice/comm_mgmt.py | 3 +- artiq/frontend/artiq_coremgmt.py | 51 +++++++++++++++++++------------- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/artiq/coredevice/comm_mgmt.py b/artiq/coredevice/comm_mgmt.py index c9f466b59..c77d0b9ec 100644 --- a/artiq/coredevice/comm_mgmt.py +++ b/artiq/coredevice/comm_mgmt.py @@ -209,7 +209,8 @@ class CommMgmt: with open(filename, "rb") as fi: bin_ = fi.read() if (len(bin_paths) > 1): - image_buf.write(struct.pack(self.endian + "I", len(bin_))) + image_buf.write( + struct.pack(self.endian + "I", len(bin_))) image_buf.write(bin_) crc = binascii.crc32(image_buf.getvalue()) diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index e9cada16f..c1b56d2a8 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -13,7 +13,6 @@ from artiq.master.databases import DeviceDB from artiq.coredevice.comm_kernel import CommKernel from artiq.coredevice.comm_mgmt import CommMgmt from artiq.frontend.bit2bin import bit2bin -from misoc.tools.mkmscimg import insert_crc def get_argparser(): @@ -95,14 +94,18 @@ def get_argparser(): help="flash the running system") p_zynq = t_flash.add_argument("-z", "--zynq", default=False, - help="target zynq device", action="store_true") + help="target zynq device", + action="store_true") - p_directory = t_flash.add_argument("directory", metavar="DIRECTORY", type=str, - help="directory that contains the binaries") + p_directory = t_flash.add_argument("directory", + metavar="DIRECTORY", type=str, + help="directory that contains the " + "binaries") p_srcbuild = t_flash.add_argument("--srcbuild", - help="board binaries directory is laid out as a source build tree", - default=False, action="store_true") + help="board binaries directory is laid " + "out as a source build tree", + default=False, action="store_true") # misc debug t_debug = tools.add_parser("debug", @@ -116,8 +119,9 @@ def get_argparser(): # 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") + metavar="DRTIO ID", type=int, + help="specify DRTIO destination that " + "receives this command") return parser @@ -161,46 +165,53 @@ def main(): mgmt.config_remove(key) if args.action == "erase": mgmt.config_erase() - + if args.tool == "flash": if args.zynq: boot = os.path.join(args.directory, "boot.bin") - bins = [ boot ] + bins = [boot] else: def artifact_path(this_binary_dir, *path_filename): if args.srcbuild: # source tree - use path elements to locate file return os.path.join(this_binary_dir, *path_filename) else: - # flat tree - all files in the same directory, discard path elements + # flat tree + # all files in the same directory, discard path elements *_, filename = path_filename return os.path.join(this_binary_dir, filename) 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: + 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( - artifact_path(args.directory, "gateware", "top.bit")) - bootloader = artifact_path(args.directory, "software", "bootloader", "bootloader.bin") + gateware = convert_gateware(artifact_path( + args.directory, "gateware", "top.bit")) + bootloader = artifact_path( + args.directory, "software", "bootloader", "bootloader.bin") firmwares = [] for firmware in "satman", "runtime": - filename = artifact_path(args.directory, "software", firmware, firmware + ".fbi") + filename = artifact_path( + args.directory, "software", firmware, 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))) + raise ValueError("more than one firmware file, " + "please clean up your build directory. " + "Found firmware files: {}".format( + " ".join(firmwares))) firmware = firmwares[0] - bins = [ gateware, bootloader, firmware ] + bins = [gateware, bootloader, firmware] mgmt.flash(bins) From ea61d9bd39ece543bc2fa570193964ae66d5763b Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 2 Oct 2024 10:56:48 +0800 Subject: [PATCH 29/42] satman: uart_logger -> buffer_logger --- artiq/firmware/Cargo.lock | 1 + artiq/firmware/satman/Cargo.toml | 1 + artiq/firmware/satman/main.rs | 37 +++++++++++++++++++++++++++++--- 3 files changed, 36 insertions(+), 3 deletions(-) diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index aa156989e..98d7d730f 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -560,6 +560,7 @@ dependencies = [ "eh", "io", "log", + "logger_artiq", "proto_artiq", "riscv", ] diff --git a/artiq/firmware/satman/Cargo.toml b/artiq/firmware/satman/Cargo.toml index 522ae7b32..dca0c91f9 100644 --- a/artiq/firmware/satman/Cargo.toml +++ b/artiq/firmware/satman/Cargo.toml @@ -20,6 +20,7 @@ crc = { version = "1.7", default-features = false } cslice = { version = "0.3" } board_misoc = { path = "../libboard_misoc", features = ["uart_console", "log"] } board_artiq = { path = "../libboard_artiq", features = ["alloc"] } +logger_artiq = { path = "../liblogger_artiq" } alloc_list = { path = "../liballoc_list" } riscv = { version = "0.6.0", features = ["inline-asm"] } proto_artiq = { path = "../libproto_artiq", features = ["log", "alloc"] } diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 3909ce6d3..55cf7b65f 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -6,6 +6,7 @@ extern crate log; #[macro_use] extern crate board_misoc; extern crate board_artiq; +extern crate logger_artiq; extern crate riscv; extern crate alloc; extern crate proto_artiq; @@ -16,14 +17,14 @@ extern crate io; extern crate eh; use core::convert::TryFrom; -use board_misoc::{csr, ident, clock, config, uart_logger, i2c, pmp}; +use board_misoc::{csr, ident, clock, config, i2c, pmp}; #[cfg(has_si5324)] use board_artiq::si5324; #[cfg(has_si549)] use board_artiq::si549; #[cfg(soc_platform = "kasli")] use board_misoc::irq; -use board_misoc::spiflash; +use board_misoc::{boot, spiflash}; use board_artiq::{spi, drtioaux, drtio_routing}; #[cfg(soc_platform = "efc")] use board_artiq::ad9117; @@ -793,6 +794,27 @@ fn sysclk_setup() { } } +fn setup_log_levels() { + match config::read_str("log_level", |r| r.map(|s| s.parse())) { + Ok(Ok(log_level_filter)) => { + info!("log level set to {} by `log_level` config key", + log_level_filter); + log::set_max_level(log_level_filter); + } + _ => info!("log level set to INFO by default") + } + match config::read_str("uart_log_level", |r| r.map(|s| s.parse())) { + Ok(Ok(uart_log_level_filter)) => { + info!("UART log level set to {} by `uart_log_level` config key", + uart_log_level_filter); + logger_artiq::BufferLogger::with(|logger| + logger.set_uart_log_level(uart_log_level_filter)); + } + _ => info!("UART log level set to INFO by default") + } +} + +static mut LOG_BUFFER: [u8; 1<<17] = [0; 1<<17]; #[no_mangle] pub extern fn main() -> i32 { @@ -812,12 +834,21 @@ pub extern fn main() -> i32 { irq::enable(csr::WRPLL_INTERRUPT); clock::init(); - uart_logger::ConsoleLogger::register(); + unsafe { + logger_artiq::BufferLogger::new(&mut LOG_BUFFER[..]).register(|| + boot::start_user(startup as usize)); + } + 0 +} + +fn startup() { info!("ARTIQ satellite manager starting..."); info!("software ident {}", csr::CONFIG_IDENTIFIER_STR); info!("gateware ident {}", ident::read(&mut [0; 64])); + setup_log_levels(); + #[cfg(has_i2c)] i2c::init().expect("I2C initialization failed"); #[cfg(all(soc_platform = "kasli", hw_rev = "v2.0"))] From ffcf79b74e62b81d18ec9a7f10e22e398ff1d6d0 Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 2 Oct 2024 10:58:13 +0800 Subject: [PATCH 30/42] satman: support coremgmt logging --- artiq/firmware/satman/main.rs | 47 +++++++++++++++++++++++++++++------ artiq/firmware/satman/mgmt.rs | 42 +++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 8 deletions(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index 55cf7b65f..ca0253e04 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -501,19 +501,50 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg Ok(()) } - drtioaux::Packet::CoreMgmtGetLogRequest { destination: _destination, .. } | - drtioaux::Packet::CoreMgmtClearLogRequest { destination: _destination } | - drtioaux::Packet::CoreMgmtSetLogLevelRequest {destination: _destination, .. } => { + drtioaux::Packet::CoreMgmtGetLogRequest { destination: _destination, clear } => { 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 }) + let mut data_slice = [0; SAT_PAYLOAD_MAX_SIZE]; + if let Ok(meta) = coremgr.log_get_slice(&mut data_slice, clear) { + drtioaux::send( + 0, + &drtioaux::Packet::CoreMgmtGetLogReply { + last: meta.status.is_last(), + length: meta.len as u16, + data: data_slice, + }, + ) + } else { + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false }) + } } - drtioaux::Packet::CoreMgmtSetUartLogLevelRequest { destination: _destination, .. } => { + drtioaux::Packet::CoreMgmtClearLogRequest { 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::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: mgmt::clear_log().is_ok() }) + } + drtioaux::Packet::CoreMgmtSetLogLevelRequest {destination: _destination, log_level } => { + forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet); + + if let Ok(level_filter) = mgmt::byte_to_level_filter(log_level) { + info!("changing log level to {}", level_filter); + log::set_max_level(level_filter); + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true }) + } else { + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false }) + } + } + drtioaux::Packet::CoreMgmtSetUartLogLevelRequest { destination: _destination, log_level } => { + forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet); + + if let Ok(level_filter) = mgmt::byte_to_level_filter(log_level) { + info!("changing UART log level to {}", level_filter); + logger_artiq::BufferLogger::with(|logger| + logger.set_uart_log_level(level_filter)); + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true }) + } else { + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: false }) + } } drtioaux::Packet::CoreMgmtConfigReadRequest { destination: _destination, diff --git a/artiq/firmware/satman/mgmt.rs b/artiq/firmware/satman/mgmt.rs index ad0526b0d..9ad6f203a 100644 --- a/artiq/firmware/satman/mgmt.rs +++ b/artiq/firmware/satman/mgmt.rs @@ -5,14 +5,39 @@ use crc::crc32; use routing::{Sliceable, SliceMeta}; use board_artiq::drtioaux; use board_misoc::{mem, config, spiflash}; +use log::LevelFilter; +use logger_artiq::BufferLogger; use io::{Cursor, ProtoRead, ProtoWrite}; use proto_artiq::drtioaux_proto::SAT_PAYLOAD_MAX_SIZE; +pub fn clear_log() -> Result<(), ()> { + BufferLogger::with(|logger| { + let mut buffer = logger.buffer()?; + Ok(buffer.clear()) + }).map_err(|()| error!("error on clearing log buffer")) +} + +pub fn byte_to_level_filter(level_byte: u8) -> Result { + Ok(match level_byte { + 0 => LevelFilter::Off, + 1 => LevelFilter::Error, + 2 => LevelFilter::Warn, + 3 => LevelFilter::Info, + 4 => LevelFilter::Debug, + 5 => LevelFilter::Trace, + lv => { + error!("unknown log level: {}", lv); + return Err(()); + } + }) +} + pub struct Manager { config_payload: Cursor>, image_payload: Cursor>, last_value: Sliceable, + last_log: Sliceable, } impl Manager { @@ -21,6 +46,7 @@ impl Manager { config_payload: Cursor::new(Vec::new()), image_payload: Cursor::new(Vec::new()), last_value: Sliceable::new(0, Vec::new()), + last_log: Sliceable::new(0, Vec::new()), } } @@ -30,6 +56,22 @@ impl Manager { )).map_err(|_err| warn!("read error: no such key")) } + pub fn log_get_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE], consume: bool) -> Result { + // Populate buffer if depleted + if self.last_log.at_end() { + BufferLogger::with(|logger| { + let mut buffer = logger.buffer()?; + self.last_log = Sliceable::new(0, buffer.extract().as_bytes().to_vec()); + if consume { + buffer.clear(); + } + Ok(()) + }).map_err(|()| error!("error on getting log buffer"))?; + } + + Ok(self.last_log.get_slice_satellite(data_slice)) + } + pub fn get_config_value_slice(&mut self, data_slice: &mut [u8; SAT_PAYLOAD_MAX_SIZE]) -> SliceMeta { self.last_value.get_slice_satellite(data_slice) } From 9882e16216b03eeaf27ff97545aa5294d306e33a Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 2 Oct 2024 11:00:04 +0800 Subject: [PATCH 31/42] RELEASE_NOTES: fix typo --- RELEASE_NOTES.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RELEASE_NOTES.rst b/RELEASE_NOTES.rst index 3e4d3c4b4..658322357 100644 --- a/RELEASE_NOTES.rst +++ b/RELEASE_NOTES.rst @@ -22,7 +22,7 @@ ARTIQ-9 (Unreleased) * Idle kernels now restart when written with ``artiq_coremgmt`` and stop when erased/removed from config. * New support for the EBAZ4205 Zynq-SoC control card. * New core device driver for the AD9834 DDS, tested with the ZonRi Technology Co., Ltd. AD9834-Module. -* Support for coredevice reflashing through new the ``flash`` tool in ``artiq_coremgmt``. +* Support for coredevice reflashing through the new ``flash`` tool in ``artiq_coremgmt``. * ``artiq_coremgmt`` now supports configuring satellites. ARTIQ-8 From 21944ff865fb2b27531c21e29bc044d7ebc7009a Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 2 Oct 2024 11:22:46 +0800 Subject: [PATCH 32/42] coremgmt flash: update crc mismatch message --- artiq/firmware/runtime/mgmt.rs | 2 +- artiq/firmware/satman/mgmt.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index 5527edb3b..c411519df 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -181,7 +181,7 @@ mod local_coremgmt { reboot(_io, stream)?; } else { - error!("CRC failed in SDRAM (actual {:08x}, expected {:08x})", actual_crc, expected_crc); + error!("CRC failed, images have not been written to flash.\n(actual {:08x}, expected {:08x})", actual_crc, expected_crc); Reply::Error.write_to(stream)?; } Ok(()) diff --git a/artiq/firmware/satman/mgmt.rs b/artiq/firmware/satman/mgmt.rs index 9ad6f203a..338b1c26f 100644 --- a/artiq/firmware/satman/mgmt.rs +++ b/artiq/firmware/satman/mgmt.rs @@ -139,7 +139,7 @@ impl Manager { } } else { - panic!("CRC failed in SDRAM (actual {:08x}, expected {:08x})", actual_crc, expected_crc); + panic!("CRC failed, images have not been written to flash.\n(actual {:08x}, expected {:08x})", actual_crc, expected_crc); } } } From e8bd99048ed8df389d2c71ffbc65d3f3bb84b08e Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 2 Oct 2024 11:40:30 +0800 Subject: [PATCH 33/42] coremgmt frontend: fix arg name --- artiq/frontend/aqctl_corelog.py | 6 +++--- artiq/frontend/artiq_coremgmt.py | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/artiq/frontend/aqctl_corelog.py b/artiq/frontend/aqctl_corelog.py index d2dd33a4a..49f5b2565 100755 --- a/artiq/frontend/aqctl_corelog.py +++ b/artiq/frontend/aqctl_corelog.py @@ -25,9 +25,9 @@ def get_argparser(): help="Simulation - does not connect to device") parser.add_argument("core_addr", metavar="CORE_ADDR", 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") + parser.add_argument("-s", "--drtio-dest", default=0, + metavar="DRTIO_DEST", type=int, + help="specifies the DRTIO destination") return parser diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index c1b56d2a8..e5ccd7215 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -118,8 +118,8 @@ def get_argparser(): help="show heap layout") # manage target - p_drtio_dest = parser.add_argument("-s", "--satellite", default=0, - metavar="DRTIO ID", type=int, + p_drtio_dest = parser.add_argument("-s", "--drtio-dest", default=0, + metavar="DRTIO_DEST", type=int, help="specify DRTIO destination that " "receives this command") From f5ff90809805b078c4d4887bf96c5f5d0f690641 Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 2 Oct 2024 15:51:02 +0800 Subject: [PATCH 34/42] artiq_flash/coremgmt flash -> fetch_bin --- artiq/frontend/artiq_coremgmt.py | 44 +++--------------------- artiq/frontend/artiq_flash.py | 36 +++---------------- artiq/frontend/fetch_bin.py | 59 ++++++++++++++++++++++++++++++++ 3 files changed, 68 insertions(+), 71 deletions(-) create mode 100644 artiq/frontend/fetch_bin.py diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index e5ccd7215..d2163a5bc 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -13,6 +13,7 @@ from artiq.master.databases import DeviceDB from artiq.coredevice.comm_kernel import CommKernel from artiq.coredevice.comm_mgmt import CommMgmt from artiq.frontend.bit2bin import bit2bin +from artiq.frontend.fetch_bin import fetch_bin def get_argparser(): @@ -171,46 +172,9 @@ def main(): boot = os.path.join(args.directory, "boot.bin") bins = [boot] else: - def artifact_path(this_binary_dir, *path_filename): - if args.srcbuild: - # source tree - use path elements to locate file - return os.path.join(this_binary_dir, *path_filename) - else: - # flat tree - # all files in the same directory, discard path elements - *_, filename = path_filename - return os.path.join(this_binary_dir, filename) - - 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(artifact_path( - args.directory, "gateware", "top.bit")) - bootloader = artifact_path( - args.directory, "software", "bootloader", "bootloader.bin") - - firmwares = [] - for firmware in "satman", "runtime": - filename = artifact_path( - args.directory, "software", firmware, 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] - + gateware = fetch_bin(args.directory, "gateware", args.srcbuild) + bootloader = fetch_bin(args.directory, "bootloader", args.srcbuild) + firmware = fetch_bin(args.directory, ["runtime", "satman"], args.srcbuild) bins = [gateware, bootloader, firmware] mgmt.flash(bins) diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index b1914a4b5..b9563a339 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -15,6 +15,7 @@ from sipyco import common_args from artiq import __version__ as artiq_version from artiq.remoting import SSHClient, LocalClient from artiq.frontend.bit2bin import bit2bin +from artiq.frontend.fetch_bin import fetch_bin def get_argparser(): @@ -302,46 +303,19 @@ def main(): programmer = config["programmer"](client, preinit_script=args.preinit_command) - def artifact_path(this_binary_dir, *path_filename): - if args.srcbuild: - # source tree - use path elements to locate file - return os.path.join(this_binary_dir, *path_filename) - else: - # flat tree - all files in the same directory, discard path elements - *_, filename = path_filename - return os.path.join(this_binary_dir, filename) - - 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 - for action in args.action: if action == "gateware": - gateware_bin = convert_gateware( - artifact_path(binary_dir, "gateware", "top.bit")) + gateware_bin = fetch_bin(binary_dir, "gateware", args.srcbuild) programmer.write_binary(*config["gateware"], gateware_bin) elif action == "bootloader": - bootloader_bin = artifact_path(binary_dir, "software", "bootloader", "bootloader.bin") + bootloader_bin = fetch_bin(binary_dir, "bootloader", args.srcbuild) programmer.write_binary(*config["bootloader"], bootloader_bin) elif action == "storage": storage_img = args.storage programmer.write_binary(*config["storage"], storage_img) elif action == "firmware": - firmware_fbis = [] - for firmware in "satman", "runtime": - filename = artifact_path(binary_dir, "software", firmware, firmware + ".fbi") - if os.path.exists(filename): - firmware_fbis.append(filename) - if not firmware_fbis: - raise FileNotFoundError("no firmware found") - if len(firmware_fbis) > 1: - raise ValueError("more than one firmware file, please clean up your build directory. " - "Found firmware files: {}".format(" ".join(firmware_fbis))) - programmer.write_binary(*config["firmware"], firmware_fbis[0]) + firmware_fbi = fetch_bin(binary_dir, ["satman", "runtime"], args.srcbuild) + programmer.write_binary(*config["firmware"], firmware_fbi) elif action == "load": gateware_bit = artifact_path(binary_dir, "gateware", "top.bit") programmer.load(gateware_bit, 0) diff --git a/artiq/frontend/fetch_bin.py b/artiq/frontend/fetch_bin.py new file mode 100644 index 000000000..890c3413c --- /dev/null +++ b/artiq/frontend/fetch_bin.py @@ -0,0 +1,59 @@ +import atexit +import os +import tempfile + +from artiq.frontend.bit2bin import bit2bin + + +def fetch_bin(binary_dir, component, srcbuild=False): + def artifact_path(this_binary_dir, *path_filename): + if srcbuild: + # source tree - use path elements to locate file + return os.path.join(this_binary_dir, *path_filename) + else: + # flat tree - all files in the same directory, discard path elements + *_, filename = path_filename + return os.path.join(this_binary_dir, filename) + + 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 + + if type(component) == list: + bins = [] + for option in component: + try: + bins.append(fetch_bin(binary_dir, option, srcbuild)) + except FileNotFoundError: + pass + + if bins is None: + raise FileNotFoundError("multiple components not found: {}".format( + " ".join(component))) + + if len(bins) > 1: + raise ValueError("more than one file, " + "please clean up your build directory. " + "Found files: {}".format( + " ".join(bins))) + + return bins[0] + + path = artifact_path(binary_dir, *{ + "gateware": ["gateware", "top.bit"], + "bootloader": ["software", "bootloader", "bootloader.bin"], + "runtime": ["software", "runtime", "runtime.fbi"], + "satman": ["software", "satman", "satman.fbi"], + }[component]) + + if not os.path.exists(path): + raise FileNotFoundError("{} not found".format(component)) + + if component == "gateware": + path = convert_gateware(path) + + return path From a643da2c5edef5e83aef000a5371410f4c3e9fe9 Mon Sep 17 00:00:00 2001 From: occheung Date: Wed, 2 Oct 2024 15:51:43 +0800 Subject: [PATCH 35/42] fix frontend args reference --- artiq/frontend/aqctl_corelog.py | 2 +- artiq/frontend/artiq_coremgmt.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/artiq/frontend/aqctl_corelog.py b/artiq/frontend/aqctl_corelog.py index 49f5b2565..cd954f590 100755 --- a/artiq/frontend/aqctl_corelog.py +++ b/artiq/frontend/aqctl_corelog.py @@ -100,7 +100,7 @@ def main(): signal_handler.setup() try: get_logs_task = asyncio.ensure_future( - get_logs_sim(args.core_addr) if args.simulation else get_logs(args.core_addr, args.satellite), + get_logs_sim(args.core_addr) if args.simulation else get_logs(args.core_addr, args.drtio_dest), loop=loop) try: server = Server({"corelog": PingTarget()}, None, True) diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index d2163a5bc..903a5615f 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -136,7 +136,7 @@ def main(): core_addr = ddb.get("core", resolve_alias=True)["arguments"]["host"] else: core_addr = args.device - mgmt = CommMgmt(core_addr, drtio_dest=args.satellite) + mgmt = CommMgmt(core_addr, drtio_dest=args.drtio_dest) if args.tool == "log": if args.action == "set_level": From 1583debfe7a144b48c1c3eabff88d92efad52252 Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 24 Oct 2024 12:35:10 +0800 Subject: [PATCH 36/42] feature gate txenable with has_drtio_eem --- artiq/firmware/satman/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index ca0253e04..b5dfff323 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -641,7 +641,7 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg drtioaux::Packet::CoreMgmtDropLinkAck { destination: _destination } => { forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet); - #[cfg(not(soc_platform = "efc"))] + #[cfg(not(has_drtio_eem))] unsafe { csr::gt_drtio::txenable_write(0); } From f2c13a504114c712a78af80f9f8a8e176e744f8e Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 24 Oct 2024 12:36:43 +0800 Subject: [PATCH 37/42] drtio_proto: add allocate step for flashing This avoids reallocation when transfering binaries. Reallocation during flash handshakes could cause DRTIO timeouts. --- .../firmware/libproto_artiq/drtioaux_proto.rs | 38 ++++++++++++------- artiq/firmware/runtime/mgmt.rs | 22 ++++++++++- artiq/firmware/satman/main.rs | 8 +++- artiq/firmware/satman/mgmt.rs | 4 ++ 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/artiq/firmware/libproto_artiq/drtioaux_proto.rs b/artiq/firmware/libproto_artiq/drtioaux_proto.rs index 9a0f423dc..4891bedf1 100644 --- a/artiq/firmware/libproto_artiq/drtioaux_proto.rs +++ b/artiq/firmware/libproto_artiq/drtioaux_proto.rs @@ -139,7 +139,8 @@ pub enum Packet { CoreMgmtConfigEraseRequest { destination: u8 }, CoreMgmtRebootRequest { destination: u8 }, CoreMgmtAllocatorDebugRequest { destination: u8 }, - CoreMgmtFlashRequest { destination: u8, last: bool, length: u16, data: [u8; MASTER_PAYLOAD_MAX_SIZE] }, + CoreMgmtFlashRequest { destination: u8, payload_length: u32 }, + CoreMgmtFlashAddDataRequest { destination: u8, last: bool, length: u16, data: [u8; MASTER_PAYLOAD_MAX_SIZE] }, CoreMgmtDropLinkAck { destination: u8 }, CoreMgmtDropLink, CoreMgmtGetLogReply { last: bool, length: u16, data: [u8; SAT_PAYLOAD_MAX_SIZE] }, @@ -485,24 +486,28 @@ impl Packet { 0xda => Packet::CoreMgmtAllocatorDebugRequest { destination: reader.read_u8()?, }, - 0xdb => { + 0xdb => Packet::CoreMgmtFlashRequest { + destination: reader.read_u8()?, + payload_length: reader.read_u32()?, + }, + 0xdc => { 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::CoreMgmtFlashRequest { + Packet::CoreMgmtFlashAddDataRequest { destination: destination, last: last, length: length, data: data, } }, - 0xdc => Packet::CoreMgmtDropLinkAck { + 0xdd => Packet::CoreMgmtDropLinkAck { destination: reader.read_u8()?, }, - 0xdd => Packet::CoreMgmtDropLink, - 0xde => { + 0xde => Packet::CoreMgmtDropLink, + 0xdf => { let last = reader.read_bool()?; let length = reader.read_u16()?; let mut data: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE]; @@ -513,7 +518,7 @@ impl Packet { data: data, } }, - 0xdf => { + 0xe0 => { let last = reader.read_bool()?; let length = reader.read_u16()?; let mut value: [u8; SAT_PAYLOAD_MAX_SIZE] = [0; SAT_PAYLOAD_MAX_SIZE]; @@ -524,7 +529,7 @@ impl Packet { value: value, } }, - 0xe0 => Packet::CoreMgmtReply { + 0xe1 => Packet::CoreMgmtReply { succeeded: reader.read_bool()?, }, @@ -884,33 +889,38 @@ impl Packet { writer.write_u8(0xda)?; writer.write_u8(destination)?; }, - Packet::CoreMgmtFlashRequest { destination, last, length, data } => { + Packet::CoreMgmtFlashRequest { destination, payload_length } => { writer.write_u8(0xdb)?; writer.write_u8(destination)?; + writer.write_u32(payload_length)?; + }, + Packet::CoreMgmtFlashAddDataRequest { destination, last, length, data } => { + writer.write_u8(0xdc)?; + writer.write_u8(destination)?; writer.write_bool(last)?; writer.write_u16(length)?; writer.write_all(&data[..length as usize])?; }, Packet::CoreMgmtDropLinkAck { destination } => { - writer.write_u8(0xdc)?; + writer.write_u8(0xdd)?; writer.write_u8(destination)?; }, Packet::CoreMgmtDropLink => - writer.write_u8(0xdd)?, + writer.write_u8(0xde)?, Packet::CoreMgmtGetLogReply { last, length, data } => { - writer.write_u8(0xde)?; + writer.write_u8(0xdf)?; writer.write_bool(last)?; writer.write_u16(length)?; writer.write_all(&data[0..length as usize])?; }, Packet::CoreMgmtConfigReadReply { last, length, value } => { - writer.write_u8(0xdf)?; + writer.write_u8(0xe0)?; writer.write_bool(last)?; writer.write_u16(length)?; writer.write_all(&value[0..length as usize])?; }, Packet::CoreMgmtReply { succeeded } => { - writer.write_u8(0xe0)?; + writer.write_u8(0xe1)?; writer.write_bool(succeeded)?; }, } diff --git a/artiq/firmware/runtime/mgmt.rs b/artiq/firmware/runtime/mgmt.rs index c411519df..d0c6d8d95 100644 --- a/artiq/firmware/runtime/mgmt.rs +++ b/artiq/firmware/runtime/mgmt.rs @@ -546,9 +546,29 @@ mod remote_coremgmt { routing_table: &RoutingTable, linkno: u8, destination: u8, stream: &mut TcpStream, image: &[u8]) -> Result<(), Error> { + let alloc_reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, + &Packet::CoreMgmtFlashRequest { + destination: destination, + payload_length: image.len() as u32, + }); + + match alloc_reply { + Ok(Packet::CoreMgmtReply { succeeded: true }) => Ok(()), + Ok(packet) => { + error!("received unexpected aux packet: {:?}", packet); + Reply::Error.write_to(stream)?; + Err(drtio::Error::UnexpectedReply) + } + Err(e) => { + error!("aux packet error ({})", e); + Reply::Error.write_to(stream)?; + Err(e) + } + }?; + match drtio::partition_data(&image, |slice, status, len: usize| { let reply = drtio::aux_transact(io, aux_mutex, ddma_mutex, subkernel_mutex, routing_table, linkno, - &Packet::CoreMgmtFlashRequest { + &Packet::CoreMgmtFlashAddDataRequest { destination: destination, length: len as u16, last: status.is_last(), data: *slice}); match reply { Ok(Packet::CoreMgmtReply { succeeded: true }) => Ok(()), diff --git a/artiq/firmware/satman/main.rs b/artiq/firmware/satman/main.rs index b5dfff323..c289b6b50 100644 --- a/artiq/firmware/satman/main.rs +++ b/artiq/firmware/satman/main.rs @@ -628,7 +628,13 @@ fn process_aux_packet(dmamgr: &mut DmaManager, analyzer: &mut Analyzer, kernelmg warn!("restarting"); unsafe { spiflash::reload(); } } - drtioaux::Packet::CoreMgmtFlashRequest { destination: _destination, last, length, data } => { + drtioaux::Packet::CoreMgmtFlashRequest { destination: _destination, payload_length } => { + forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet); + + coremgr.allocate_image_buffer(payload_length as usize); + drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded: true }) + } + drtioaux::Packet::CoreMgmtFlashAddDataRequest { destination: _destination, last, length, data } => { forward!(router, _routing_table, _destination, *rank, *self_destination, _repeaters, &packet); coremgr.add_image_data(&data, length as usize); diff --git a/artiq/firmware/satman/mgmt.rs b/artiq/firmware/satman/mgmt.rs index 338b1c26f..d7058b837 100644 --- a/artiq/firmware/satman/mgmt.rs +++ b/artiq/firmware/satman/mgmt.rs @@ -106,6 +106,10 @@ impl Manager { drtioaux::send(0, &drtioaux::Packet::CoreMgmtReply { succeeded }) } + pub fn allocate_image_buffer(&mut self, image_size: usize) { + self.image_payload = Cursor::new(Vec::with_capacity(image_size)); + } + pub fn add_image_data(&mut self, data: &[u8], data_len: usize) { self.image_payload.write_all(&data[..data_len]).unwrap(); } From de349e4c39fb05c99846290abf90cfe1c4ef41f5 Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 24 Oct 2024 12:40:25 +0800 Subject: [PATCH 38/42] bit2bin, fetch_bin -> flash_tools --- artiq/frontend/artiq_coremgmt.py | 3 +- artiq/frontend/artiq_flash.py | 7 +- artiq/frontend/bit2bin.py | 69 ------------------- artiq/frontend/fetch_bin.py | 59 ---------------- artiq/frontend/flash_tools.py | 114 +++++++++++++++++++++++++++++++ 5 files changed, 118 insertions(+), 134 deletions(-) delete mode 100755 artiq/frontend/bit2bin.py delete mode 100644 artiq/frontend/fetch_bin.py create mode 100644 artiq/frontend/flash_tools.py diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index 903a5615f..448349f85 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -12,8 +12,7 @@ from artiq import __version__ as artiq_version from artiq.master.databases import DeviceDB from artiq.coredevice.comm_kernel import CommKernel from artiq.coredevice.comm_mgmt import CommMgmt -from artiq.frontend.bit2bin import bit2bin -from artiq.frontend.fetch_bin import fetch_bin +from artiq.frontend.flash_tools import bit2bin, fetch_bin def get_argparser(): diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index b9563a339..5a5296979 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -14,8 +14,7 @@ from sipyco import common_args from artiq import __version__ as artiq_version from artiq.remoting import SSHClient, LocalClient -from artiq.frontend.bit2bin import bit2bin -from artiq.frontend.fetch_bin import fetch_bin +from artiq.frontend.flash_tools import artifact_path, bit2bin, fetch_bin def get_argparser(): @@ -305,10 +304,10 @@ def main(): for action in args.action: if action == "gateware": - gateware_bin = fetch_bin(binary_dir, "gateware", args.srcbuild) + gateware_bin = fetch_bin(binary_dir, ["gateware"], args.srcbuild) programmer.write_binary(*config["gateware"], gateware_bin) elif action == "bootloader": - bootloader_bin = fetch_bin(binary_dir, "bootloader", args.srcbuild) + bootloader_bin = fetch_bin(binary_dir, ["bootloader"], args.srcbuild) programmer.write_binary(*config["bootloader"], bootloader_bin) elif action == "storage": storage_img = args.storage diff --git a/artiq/frontend/bit2bin.py b/artiq/frontend/bit2bin.py deleted file mode 100755 index df3927415..000000000 --- a/artiq/frontend/bit2bin.py +++ /dev/null @@ -1,69 +0,0 @@ -#!/usr/bin/env python3 -# Copyright 2014-2017 Robert Jordens -# after -# https://github.com/mfischer/fpgadev-zynq/blob/master/top/python/bit_to_zynq_bin.py - -import struct - - -def flip32(data): - sl = struct.Struct("I") - b = memoryview(data) - d = bytearray(len(data)) - for offset in range(0, len(data), sl.size): - sb.pack_into(d, offset, *sl.unpack_from(b, offset)) - return d - - -def bit2bin(bit, bin, flip=False): - l, = struct.unpack(">H", bit.read(2)) - if l != 9: - raise ValueError("Missing <0009> header, not a bit file") - _ = bit.read(l) # unknown data - l, = struct.unpack(">H", bit.read(2)) - if l != 1: - raise ValueError("Missing <0001> header, not a bit file") - - while True: - key = bit.read(1).decode() - if not key: - break - if key in "abcd": - d = bit.read(*struct.unpack(">H", bit.read(2))) - assert d.endswith(b"\x00") - d = d[:-1].decode() - name = { - "a": "Design", - "b": "Part name", - "c": "Date", - "d": "Time" - }[key] - print("{}: {}".format(name, d)) - elif key == "e": - l, = struct.unpack(">I", bit.read(4)) - print("Bitstream payload length: {:#x}".format(l)) - d = bit.read(l) - if flip: - d = flip32(d) - bin.write(d) - else: - d = bit.read(*struct.unpack(">H", bit.read(2))) - print("Unexpected key: {}: {}".format(key, d)) - - -if __name__ == "__main__": - import argparse - parser = argparse.ArgumentParser( - description="Convert FPGA bit files to raw bin format " - "suitable for flashing") - parser.add_argument("-f", "--flip", dest="flip", action="store_true", - default=False, help="Flip 32-bit endianess (needed for Zynq)") - parser.add_argument("bitfile", metavar="BITFILE", - help="Input bit file name") - parser.add_argument("binfile", metavar="BINFILE", - help="Output bin file name") - args = parser.parse_args() - - with open(args.bitfile, "rb") as f, open(args.binfile, "wb") as g: - bit2bin(f, g, args.flip) diff --git a/artiq/frontend/fetch_bin.py b/artiq/frontend/fetch_bin.py deleted file mode 100644 index 890c3413c..000000000 --- a/artiq/frontend/fetch_bin.py +++ /dev/null @@ -1,59 +0,0 @@ -import atexit -import os -import tempfile - -from artiq.frontend.bit2bin import bit2bin - - -def fetch_bin(binary_dir, component, srcbuild=False): - def artifact_path(this_binary_dir, *path_filename): - if srcbuild: - # source tree - use path elements to locate file - return os.path.join(this_binary_dir, *path_filename) - else: - # flat tree - all files in the same directory, discard path elements - *_, filename = path_filename - return os.path.join(this_binary_dir, filename) - - 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 - - if type(component) == list: - bins = [] - for option in component: - try: - bins.append(fetch_bin(binary_dir, option, srcbuild)) - except FileNotFoundError: - pass - - if bins is None: - raise FileNotFoundError("multiple components not found: {}".format( - " ".join(component))) - - if len(bins) > 1: - raise ValueError("more than one file, " - "please clean up your build directory. " - "Found files: {}".format( - " ".join(bins))) - - return bins[0] - - path = artifact_path(binary_dir, *{ - "gateware": ["gateware", "top.bit"], - "bootloader": ["software", "bootloader", "bootloader.bin"], - "runtime": ["software", "runtime", "runtime.fbi"], - "satman": ["software", "satman", "satman.fbi"], - }[component]) - - if not os.path.exists(path): - raise FileNotFoundError("{} not found".format(component)) - - if component == "gateware": - path = convert_gateware(path) - - return path diff --git a/artiq/frontend/flash_tools.py b/artiq/frontend/flash_tools.py new file mode 100644 index 000000000..d486454d3 --- /dev/null +++ b/artiq/frontend/flash_tools.py @@ -0,0 +1,114 @@ +import atexit +import os +import tempfile + + +def artifact_path(this_binary_dir, *path_filename, srcbuild=False): + if srcbuild: + # source tree - use path elements to locate file + return os.path.join(this_binary_dir, *path_filename) + else: + # flat tree - all files in the same directory, discard path elements + *_, filename = path_filename + return os.path.join(this_binary_dir, filename) + + +def fetch_bin(binary_dir, components, srcbuild=False): + 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 + + if len(components) > 1: + bins = [] + for option in components: + try: + bins.append(fetch_bin(binary_dir, [option], srcbuild)) + except FileNotFoundError: + pass + + if bins is None: + raise FileNotFoundError("multiple components not found: {}".format( + " ".join(components))) + + if len(bins) > 1: + raise ValueError("more than one file, " + "please clean up your build directory. " + "Found files: {}".format( + " ".join(bins))) + + return bins[0] + + else: + component = components[0] + path = artifact_path(binary_dir, *{ + "gateware": ["gateware", "top.bit"], + "boot": ["boot.bin"], + "bootloader": ["software", "bootloader", "bootloader.bin"], + "runtime": ["software", "runtime", "runtime.fbi"], + "satman": ["software", "satman", "satman.fbi"], + }[component], srcbuild=srcbuild) + + if not os.path.exists(path): + raise FileNotFoundError("{} not found".format(component)) + + if component == "gateware": + path = convert_gateware(path) + + return path + + +# Copyright 2014-2017 Robert Jordens +# after +# https://github.com/mfischer/fpgadev-zynq/blob/master/top/python/bit_to_zynq_bin.py + +import struct + + +def flip32(data): + sl = struct.Struct("I") + b = memoryview(data) + d = bytearray(len(data)) + for offset in range(0, len(data), sl.size): + sb.pack_into(d, offset, *sl.unpack_from(b, offset)) + return d + + +def bit2bin(bit, bin, flip=False): + l, = struct.unpack(">H", bit.read(2)) + if l != 9: + raise ValueError("Missing <0009> header, not a bit file") + _ = bit.read(l) # unknown data + l, = struct.unpack(">H", bit.read(2)) + if l != 1: + raise ValueError("Missing <0001> header, not a bit file") + + while True: + key = bit.read(1).decode() + if not key: + break + if key in "abcd": + d = bit.read(*struct.unpack(">H", bit.read(2))) + assert d.endswith(b"\x00") + d = d[:-1].decode() + name = { + "a": "Design", + "b": "Part name", + "c": "Date", + "d": "Time" + }[key] + print("{}: {}".format(name, d)) + elif key == "e": + l, = struct.unpack(">I", bit.read(4)) + print("Bitstream payload length: {:#x}".format(l)) + d = bit.read(l) + if flip: + d = flip32(d) + bin.write(d) + else: + d = bit.read(*struct.unpack(">H", bit.read(2))) + print("Unexpected key: {}: {}".format(key, d)) From e36916b931937a4ccaee51ce5baf583126fb0a6d Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 24 Oct 2024 12:42:11 +0800 Subject: [PATCH 39/42] coremgmt flashing: detect risc-v or zynq targets --- artiq/frontend/artiq_coremgmt.py | 41 ++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index 448349f85..c73dcfd70 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -93,10 +93,6 @@ def get_argparser(): t_flash = tools.add_parser("flash", help="flash the running system") - p_zynq = t_flash.add_argument("-z", "--zynq", default=False, - help="target zynq device", - action="store_true") - p_directory = t_flash.add_argument("directory", metavar="DIRECTORY", type=str, help="directory that contains the " @@ -167,15 +163,36 @@ def main(): mgmt.config_erase() if args.tool == "flash": - if args.zynq: - boot = os.path.join(args.directory, "boot.bin") - bins = [boot] - else: - gateware = fetch_bin(args.directory, "gateware", args.srcbuild) - bootloader = fetch_bin(args.directory, "bootloader", args.srcbuild) - firmware = fetch_bin(args.directory, ["runtime", "satman"], args.srcbuild) - bins = [gateware, bootloader, firmware] + retrieved_bins = [] + bin_dict = { + "zynq":[ + ["boot"] + ], + "riscv": [ + ["gateware"], + ["bootloader"], + ["runtime", "satman"], + ], + } + for bin_list in bin_dict.values(): + try: + bins = [] + for bin_name in bin_list: + bins.append(fetch_bin( + args.directory, bin_name, args.srcbuild)) + retrieved_bins.append(bins) + except FileNotFoundError: + pass + + if retrieved_bins is None: + raise FileNotFoundError("both risc-v and zynq binaries not found") + + if len(retrieved_bins) > 1: + raise ValueError("both risc-v and zynq binaries were found, " + "please clean up your build directory. ") + + bins = retrieved_bins[0] mgmt.flash(bins) if args.tool == "reboot": From 6251e734599c62b8532b55648ae9d9fb7e675b9c Mon Sep 17 00:00:00 2001 From: occheung Date: Thu, 24 Oct 2024 12:43:09 +0800 Subject: [PATCH 40/42] board_misoc: enable efc rebooting --- artiq/firmware/libboard_misoc/spiflash.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/firmware/libboard_misoc/spiflash.rs b/artiq/firmware/libboard_misoc/spiflash.rs index 7d66977f7..e686d17e6 100644 --- a/artiq/firmware/libboard_misoc/spiflash.rs +++ b/artiq/firmware/libboard_misoc/spiflash.rs @@ -124,7 +124,7 @@ pub unsafe fn flash_binary(origin: usize, payload: &[u8]) { write(origin, payload); } -#[cfg(any(soc_platform = "kasli", soc_platform = "kc705"))] +#[cfg(any(soc_platform = "kasli", soc_platform = "kc705", soc_platform = "efc"))] pub unsafe fn reload () -> ! { csr::icap::iprog_write(1); loop {} From 90764b04f9af1c0a20099bbdecdbf74c891ab40e Mon Sep 17 00:00:00 2001 From: occheung Date: Mon, 18 Nov 2024 16:04:44 +0800 Subject: [PATCH 41/42] both ... not -> neither ... nor --- artiq/frontend/artiq_coremgmt.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/artiq/frontend/artiq_coremgmt.py b/artiq/frontend/artiq_coremgmt.py index c73dcfd70..a137a402a 100755 --- a/artiq/frontend/artiq_coremgmt.py +++ b/artiq/frontend/artiq_coremgmt.py @@ -186,7 +186,7 @@ def main(): pass if retrieved_bins is None: - raise FileNotFoundError("both risc-v and zynq binaries not found") + raise FileNotFoundError("neither risc-v nor zynq binaries were found") if len(retrieved_bins) > 1: raise ValueError("both risc-v and zynq binaries were found, " From df1a389007f141f8652052abe301a853cd7fa1ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Bourdeauducq?= Date: Wed, 20 Nov 2024 08:23:51 +0800 Subject: [PATCH 42/42] flash_tools: cleanup import --- artiq/frontend/flash_tools.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/artiq/frontend/flash_tools.py b/artiq/frontend/flash_tools.py index d486454d3..432d03f37 100644 --- a/artiq/frontend/flash_tools.py +++ b/artiq/frontend/flash_tools.py @@ -1,6 +1,7 @@ import atexit import os import tempfile +import struct def artifact_path(this_binary_dir, *path_filename, srcbuild=False): @@ -65,9 +66,6 @@ def fetch_bin(binary_dir, components, srcbuild=False): # after # https://github.com/mfischer/fpgadev-zynq/blob/master/top/python/bit_to_zynq_bin.py -import struct - - def flip32(data): sl = struct.Struct("I")