Skip to content

Commit

Permalink
archive version 9: now without openocd/pyocd flashing
Browse files Browse the repository at this point in the history
Humility has historically had support for a --force-openocd flag on the
flash subcommand, as a hedge against probe-rs having bugs or limited
chip support. In practice, as far as I can tell, we never use it.

This support required one of the three giant merge-conflict-prone match
statements on which I declared war in #1886. The second such match
statement was providing similar support for PyOCD, which Humility
appears to have never actually implemented!

So this change removes both. Archives built at or after this change can
only be flashed (by Humility) using probe-rs. One giant scary match
statement remains, but it's in my sights.

I have left the openocd.cfg file in the archive because it's useful for
debugging, even if we don't use it for _flashing._ (My workflow if I
need gdb is typically to flash with Humility via probe-rs, and _then_
fire up openocd.)

I've bumped the archive version here so that using such an archive with
an older Humility gets you a cogent error. (Otherwise, you get a weird
crash about loading flash.ron, no matter what you're trying to do.)

Note that this requires a corresponding change in Humility, both to
tolerate the absence of the removed fields, and to handle the new
archive version.

    oxidecomputer/humility#514
  • Loading branch information
cbiffle committed Oct 11, 2024
1 parent ff04d42 commit f9ffe54
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 182 deletions.
5 changes: 2 additions & 3 deletions build/xtask/src/dist.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ pub const DEFAULT_KERNEL_STACK: u32 = 1024;
/// that generates the Humility binary necessary for Hubris's CI has run.
/// Once that binary is in place, you should be able to bump this version
/// without breaking CI.
const HUBRIS_ARCHIVE_VERSION: u32 = 8;
const HUBRIS_ARCHIVE_VERSION: u32 = 9;

/// `PackageConfig` contains a bundle of data that's commonly used when
/// building a full app image, grouped together to avoid passing a bunch
Expand Down Expand Up @@ -872,10 +872,9 @@ fn build_archive(
// any external configuration files, serialize it, and add it to the
// archive.
//
if let Some(mut config) =
if let Some(config) =
crate::flash::config(cfg.toml.board.as_str(), &chip_dir)?
{
config.flatten()?;
archive.text(
img_dir.join("flash.ron"),
ron::ser::to_string_pretty(
Expand Down
184 changes: 5 additions & 179 deletions build/xtask/src/flash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,203 +3,29 @@
// file, You can obtain one at https://mozilla.org/MPL/2.0/.

use serde::Serialize;
use std::path::{Path, PathBuf};
use std::path::Path;

//
// We allow for enough information to be put in the archive for the image to
// be flashed based only on the archive (e.g., by Humility). Because flashing
// is itself a bit of a mess (requiring different programs for different
// targets), this is a bit gritty (e.g., any required external configuration
// files must themselves put in the archive). If these structures need to
// change, be sure to make corresponding changes to Humility.
//
#[derive(Debug, Serialize)]
pub enum FlashProgram {
PyOcd(Vec<FlashArgument>),
OpenOcd(FlashProgramConfig),
}

//
// Enum describing flash programs configuration (e.g., "openocd.cfg" for
// OpenOCD), either as a path in the file system or with the entire contents.
//
#[derive(Debug, Serialize)]
pub enum FlashProgramConfig {
Path(PathBuf),
Payload(String),
}

//
// An enum describing a single command-line argument to the flash program.
//
#[derive(Debug, Serialize)]
pub enum FlashArgument {
// A direct string
Direct(String),

// The filesystem path of the binary flash payload itself
Payload,

// A single argument consisting of a prefix and a suffix. When the
// argument is processed, a single argument should be generated consisting
// of the prefix, the path of the flash, and the suffix, all joined by
// spaces.
FormattedPayload(String, String),

// The filesystem path of the flash program configuration
Config,
}

#[derive(Debug, Serialize)]
#[derive(Debug, Serialize, Default)]
pub struct FlashConfig {
/// The name used by probe-rs to identify the chip.
chip: Option<String>,
program: FlashProgram,
args: Vec<FlashArgument>,
}

impl FlashProgramConfig {
fn new(path: PathBuf) -> Self {
FlashProgramConfig::Path(path)
}
}

impl FlashConfig {
fn new(program: FlashProgram) -> Self {
FlashConfig {
chip: None,
program,
args: vec![],
}
}

//
// Add a command-line argument to the flash program
//
fn arg<'a>(&'a mut self, val: &str) -> &'a mut Self {
self.args.push(FlashArgument::Direct(val.to_string()));
self
}

//
// Set the chip
//
fn set_chip(&mut self, val: &str) -> &mut Self {
self.chip = Some(val.to_string());
self
}

//
// Add the path to the payload as an argument to the flash program
//
fn payload(&mut self) -> &mut Self {
self.args.push(FlashArgument::Payload);
self
}

//
// Add a formatted payload as a single argument to the flash program. The
// argument will consists of the specified prefix, followed by the path to
// the payload, followed by the specified suffix.
//
fn formatted_payload<'a>(
&'a mut self,
prefix: &str,
suffix: &str,
) -> &'a mut Self {
self.args.push(FlashArgument::FormattedPayload(
prefix.to_string(),
suffix.to_string(),
));
self
}

//
// Add a flasher configuration file as an argument to the flash program
//
fn config(&mut self) -> &mut Self {
self.args.push(FlashArgument::Config);
self
}

//
// Slurp in any flash program configuration file and flatten it into
// our overall configuration
//
pub fn flatten(&mut self) -> anyhow::Result<()> {
if let FlashProgram::OpenOcd(FlashProgramConfig::Path(path)) =
&self.program
{
let p: PathBuf = path.iter().collect();
let text = std::fs::read_to_string(p)?;
self.program =
FlashProgram::OpenOcd(FlashProgramConfig::Payload(text));
}

Ok(())
}
}

pub fn config(
board: &str,
chip_dir: &Path,
_chip_dir: &Path,
) -> anyhow::Result<Option<FlashConfig>> {
let mut flash = match board {
"lpcxpresso55s69"
| "rot-carrier-1"
| "rot-carrier-2"
| "oxide-rot-1"
| "oxide-rot-1-selfsigned" => {
let chip = if board == "rot-carrier-1" {
"lpc55s28"
} else {
"lpc55s69"
};

let mut args = vec![];

for arg in ["reset", "-t", chip].iter() {
args.push(FlashArgument::Direct(arg.to_string()));
}

let mut flash = FlashConfig::new(FlashProgram::PyOcd(args));

flash
.arg("flash")
.arg("-t")
.arg(chip)
.arg("--format")
.arg("hex")
.payload();

flash
}

"stm32f3-discovery" | "stm32f4-discovery" | "nucleo-h743zi2"
| "nucleo-h753zi" | "gemini-bu-1" | "gimletlet-1" | "gimletlet-2"
| "gimlet-b" | "gimlet-c" | "gimlet-d" | "gimlet-e" | "gimlet-f"
| "psc-b" | "psc-c" | "sidecar-b" | "sidecar-c" | "sidecar-d"
| "stm32g031-nucleo" | "donglet-g030" | "donglet-g031"
| "oxcon2023g0" | "stm32g070-nucleo" | "stm32g0b1-nucleo"
| "medusa-a" | "grapefruit" => {
let cfg = FlashProgramConfig::new(chip_dir.join("openocd.cfg"));

let mut flash = FlashConfig::new(FlashProgram::OpenOcd(cfg));

flash
.arg("-f")
.config()
.arg("-c")
.formatted_payload("program", "verify reset")
.arg("-c")
.arg("exit");

flash
}
_ => {
eprintln!("Warning: unrecognized board, won't know how to flash.");
return Ok(None);
}
};
let mut flash = FlashConfig::default();

flash.set_chip(chip_name(board)?);

Expand Down

0 comments on commit f9ffe54

Please sign in to comment.