diff --git a/README.md b/README.md index a005bad8..6efa25d9 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,10 @@ The following configuration keys are available: - ``ip6``: IPv6 address. - ``startup``: startup kernel in ELF format (as produced by ``artiq_compile``). - ``rtioclk``: source of RTIO clock; valid values are ``external`` and ``internal``. +- ``boot``: SD card "boot.bin" file, for replacing the boot firmware/gateware. Write only. + +Configurations can be read/written/removed via ``artiq_coremgmt``. Config erase is +not implemented as it seems not very useful. Development instructions ------------------------ diff --git a/default.nix b/default.nix index 177799d8..d8831900 100644 --- a/default.nix +++ b/default.nix @@ -14,7 +14,7 @@ let name = "zc706-firmware"; src = ./src; - cargoSha256 = "0hjpxqz9ilr4fxi3w3xswn9dcrsh3g2m42vig80xdkpb7wn9gvs0"; + cargoSha256 = "1hmhnwvkn3z7qw4z6lxhczjl9r402k7xpycp987fnw7rfrqj9cp7"; nativeBuildInputs = [ pkgs.gnumake diff --git a/src/Cargo.lock b/src/Cargo.lock index 57ddfcd9..7d50ab20 100644 --- a/src/Cargo.lock +++ b/src/Cargo.lock @@ -56,7 +56,7 @@ checksum = "e3fcd8aba10d17504c87ef12d4f62ef404c6a4703d16682a9eb5543e6cf24455" [[package]] name = "core_io" version = "0.1.20200410" -source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#6266d280951c3fe5d4963a4b1ca45ce369d6b773" +source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#0efc7a616f90f1fdc495f7d112d1b3d2f604c3a8" dependencies = [ "memchr", ] @@ -186,7 +186,7 @@ dependencies = [ [[package]] name = "libasync" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#6266d280951c3fe5d4963a4b1ca45ce369d6b773" +source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#0efc7a616f90f1fdc495f7d112d1b3d2f604c3a8" dependencies = [ "embedded-hal", "libcortex_a9", @@ -198,7 +198,7 @@ dependencies = [ [[package]] name = "libboard_zynq" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#6266d280951c3fe5d4963a4b1ca45ce369d6b773" +source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#0efc7a616f90f1fdc495f7d112d1b3d2f604c3a8" dependencies = [ "bit_field", "embedded-hal", @@ -222,7 +222,7 @@ dependencies = [ [[package]] name = "libconfig" version = "0.1.0" -source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#6266d280951c3fe5d4963a4b1ca45ce369d6b773" +source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#0efc7a616f90f1fdc495f7d112d1b3d2f604c3a8" dependencies = [ "core_io", "fatfs", @@ -233,7 +233,7 @@ dependencies = [ [[package]] name = "libcortex_a9" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#6266d280951c3fe5d4963a4b1ca45ce369d6b773" +source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#0efc7a616f90f1fdc495f7d112d1b3d2f604c3a8" dependencies = [ "bit_field", "libregister", @@ -249,7 +249,7 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" [[package]] name = "libregister" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#6266d280951c3fe5d4963a4b1ca45ce369d6b773" +source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#0efc7a616f90f1fdc495f7d112d1b3d2f604c3a8" dependencies = [ "bit_field", "vcell", @@ -259,7 +259,7 @@ dependencies = [ [[package]] name = "libsupport_zynq" version = "0.0.0" -source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#6266d280951c3fe5d4963a4b1ca45ce369d6b773" +source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#0efc7a616f90f1fdc495f7d112d1b3d2f604c3a8" dependencies = [ "compiler_builtins", "libboard_zynq", diff --git a/src/runtime/Cargo.toml b/src/runtime/Cargo.toml index 5b7ad530..9b7af9c6 100644 --- a/src/runtime/Cargo.toml +++ b/src/runtime/Cargo.toml @@ -6,7 +6,7 @@ authors = ["M-Labs"] edition = "2018" [features] -target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706"] +target_zc706 = ["libboard_zynq/target_zc706", "libsupport_zynq/target_zc706", "libconfig/target_zc706"] default = ["target_zc706"] [dependencies] diff --git a/src/runtime/src/comms.rs b/src/runtime/src/comms.rs index 8b482146..71297f27 100644 --- a/src/runtime/src/comms.rs +++ b/src/runtime/src/comms.rs @@ -343,8 +343,8 @@ async fn handle_connection(stream: &TcpStream, control: Rc Result { @@ -85,7 +92,28 @@ async fn get_logger_buffer() -> LogBufferRef<'static> { get_logger_buffer_pred(|_| true).await } -async fn handle_connection(stream: &mut TcpStream, pull_id: Rc>) -> Result<()> { +async fn read_key(stream: &mut TcpStream) -> Result { + let len = read_i32(stream).await?; + if len <= 0 { + write_i8(stream, Reply::Error as i8).await?; + return Err(Error::UnexpectedPattern); + } + let mut buffer = Vec::with_capacity(len as usize); + for _ in 0..len { + buffer.push(0); + } + read_chunk(stream, &mut buffer).await?; + if !buffer.is_ascii() { + write_i8(stream, Reply::Error as i8).await?; + return Err(Error::UnexpectedPattern); + } + Ok(String::from_utf8(buffer).unwrap()) +} + +async fn handle_connection( + stream: &mut TcpStream, + pull_id: Rc>, + cfg: Rc) -> Result<()> { if !expect(&stream, b"ARTIQ management\n").await? { return Err(Error::UnexpectedPattern); } @@ -150,19 +178,70 @@ async fn handle_connection(stream: &mut TcpStream, pull_id: Rc>) -> } write_i8(stream, Reply::Success as i8).await?; } + Request::ConfigRead => { + let key = read_key(stream).await?; + debug!("read key: {}", key); + let value = cfg.read(&key); + if let Ok(value) = value { + debug!("got value"); + write_i8(stream, Reply::ConfigData as i8).await?; + write_chunk(stream, &value).await?; + } else { + warn!("read error: no such key"); + write_i8(stream, Reply::Error as i8).await?; + } + }, + Request::ConfigWrite => { + let key = read_key(stream).await?; + warn!("write key: {}", key); + let len = read_i32(stream).await?; + let len = if len <= 0 { + 0 + } else { + len as usize + }; + let mut buffer = Vec::with_capacity(len); + unsafe { + buffer.set_len(len); + } + read_chunk(stream, &mut buffer).await?; + let value = cfg.write(&key, buffer); + if value.is_ok() { + debug!("write success"); + write_i8(stream, Reply::Success as i8).await?; + } else { + // this is an error because we do not expect write to fail + error!("failed to write: {:?}", value); + write_i8(stream, Reply::Error as i8).await?; + } + }, + Request::ConfigRemove => { + let key = read_key(stream).await?; + debug!("erase key: {}", key); + let value = cfg.remove(&key); + if value.is_ok() { + debug!("erase success"); + write_i8(stream, Reply::Success as i8).await?; + } else { + warn!("erase failed"); + write_i8(stream, Reply::Error as i8).await?; + } + } } } } -pub fn start() { +pub fn start(cfg: Config) { task::spawn(async move { let pull_id = Rc::new(RefCell::new(0u32)); + let cfg = Rc::new(cfg); loop { let mut stream = TcpStream::accept(1380, 2048, 2048).await.unwrap(); let pull_id = pull_id.clone(); + let cfg = cfg.clone(); task::spawn(async move { info!("received connection"); - let _ = handle_connection(&mut stream, pull_id) + let _ = handle_connection(&mut stream, pull_id, cfg) .await .map_err(|e| warn!("connection terminated: {:?}", e)); let _ = stream.flush().await;