diff --git a/artiq/coredevice/comm_kernel.py b/artiq/coredevice/comm_kernel.py index de3c55d9f..63fe42328 100644 --- a/artiq/coredevice/comm_kernel.py +++ b/artiq/coredevice/comm_kernel.py @@ -34,6 +34,8 @@ class _H2DMsgType(Enum): FLASH_ERASE_REQUEST = 11 FLASH_REMOVE_REQUEST = 12 + HOTSWAP = 14 + class _D2HMsgType(Enum): LOG_REPLY = 1 @@ -326,6 +328,10 @@ class CommKernel: self._read_empty(_D2HMsgType.FLASH_OK_REPLY) + def hotswap(self, image): + self._write_header(_H2DMsgType.HOTSWAP) + self._write_bytes(image) + def load(self, kernel_library): self._write_header(_H2DMsgType.LOAD_KERNEL) self._write_bytes(kernel_library) diff --git a/artiq/firmware/libboard/hotswap.rs b/artiq/firmware/libboard/hotswap.rs new file mode 100644 index 000000000..5fb2fd749 --- /dev/null +++ b/artiq/firmware/libboard/hotswap.rs @@ -0,0 +1,31 @@ +use irq; + +pub unsafe fn run(new_code: &[u8]) -> ! { + irq::set_ie(false); + #[cfg(target_arch="or1k")] + asm!(r#" + # This loop overwrites itself, but it's structured in such a way + # that before that happens, it loads itself into I$$ fully. + l.movhi r4, hi(_ftext) + l.ori r4, r4, lo(_ftext) + l.or r7, r4, r0 + 0: l.sfnei r5, 0 + l.bf 1f + l.nop + l.jr r7 + l.nop + 1: l.lwz r6, 0(r3) + l.sw 0(r4), r6 + l.addi r3, r3, 4 + l.addi r4, r4, 4 + l.addi r5, r5, -4 + l.bf 0b + l.nop + "# + : + : "{r3}"(new_code.as_ptr() as usize), + "{r5}"(new_code.len()) + : + : "volatile"); + loop {} +} diff --git a/artiq/firmware/libboard/lib.rs b/artiq/firmware/libboard/lib.rs index 999926cb0..499e4b0e1 100644 --- a/artiq/firmware/libboard/lib.rs +++ b/artiq/firmware/libboard/lib.rs @@ -35,6 +35,8 @@ mod ad9154_reg; #[cfg(has_ad9154)] pub mod ad9154; +pub mod hotswap; + #[cfg(feature = "uart_console")] pub use uart_console::Console; diff --git a/artiq/firmware/libproto/session_proto.rs b/artiq/firmware/libproto/session_proto.rs index 35afbe5fb..31f3cc911 100644 --- a/artiq/firmware/libproto/session_proto.rs +++ b/artiq/firmware/libproto/session_proto.rs @@ -46,6 +46,8 @@ pub enum Request { FlashWrite { key: String, value: Vec }, FlashRemove { key: String }, FlashErase, + + Hotswap(Vec), } impl Request { @@ -97,6 +99,7 @@ impl Request { 12 => Request::FlashRemove { key: reader.read_string()? }, + 14 => Request::Hotswap(reader.read_bytes()?), _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown request type")) }) } diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 9ed0ba3e2..370a9ac34 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -268,6 +268,10 @@ fn process_host_message(io: &Io, } } + // artiq_coreboot + host::Request::Hotswap(binary) => + unsafe { board::hotswap::run(&binary) }, + // artiq_run/artiq_master host::Request::SwitchClock(clk) => { if session.running() { diff --git a/artiq/frontend/artiq_coreboot.py b/artiq/frontend/artiq_coreboot.py new file mode 100644 index 000000000..b02c78793 --- /dev/null +++ b/artiq/frontend/artiq_coreboot.py @@ -0,0 +1,36 @@ +#!/usr/bin/env python3 + +import argparse +import struct + +from artiq.tools import verbosity_args, init_logger +from artiq.master.databases import DeviceDB +from artiq.master.worker_db import DeviceManager + + +def get_argparser(): + parser = argparse.ArgumentParser(description="ARTIQ core device hotswap tool") + + verbosity_args(parser) + parser.add_argument("--device-db", default="device_db.pyon", + help="device database file (default: '%(default)s')") + + parser.add_argument("image", metavar="IMAGE", type=argparse.FileType('rb'), + help="runtime image to be executed") + + return parser + + +def main(): + args = get_argparser().parse_args() + init_logger(args) + device_mgr = DeviceManager(DeviceDB(args.device_db)) + try: + comm = device_mgr.get("comm") + comm.check_system_info() + comm.hotswap(args.image.read()) + finally: + device_mgr.close_devices() + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py index 1d5a9fd57..e5b6c5b8f 100755 --- a/setup.py +++ b/setup.py @@ -24,6 +24,7 @@ console_scripts = [ "artiq_coreanalyzer=artiq.frontend.artiq_coreanalyzer:main", "artiq_coreconfig=artiq.frontend.artiq_coreconfig:main", "artiq_corelog=artiq.frontend.artiq_corelog:main", + "artiq_coreboot=artiq.frontend.artiq_coreboot:main", "artiq_ctlmgr=artiq.frontend.artiq_ctlmgr:main", "artiq_devtool=artiq.frontend.artiq_devtool:main", "artiq_influxdb=artiq.frontend.artiq_influxdb:main",