This repository has been archived by the owner on Jan 30, 2024. It is now read-only.
[RFC] pass command line arguments to the embedded program #148
Labels
difficulty: hard
Fairly difficult to solve
priority: low
Low priority for the Knurling team
status: needs PR
Issue just needs a Pull Request implementing the changes
type: enhancement
Enhancement or feature request
this is a non-hacky solution to knurling-rs/defmt#260
Summary
Arguments passed to
probe-run
after the ELF file path are passed to the embedded program. The embedded program can retrieve those command line arguments using theprobe_args::args
API$ probe-run --chip CHIP my-elf hello world
With the ability to read command line arguments we can make
defmt-test
behave closer to the standardtest
harness and support e.g. command-line test filters.Implementation
TL; DR
probe-run
will write the command line arguments in RAM below the first stack frame.It will do this before the user code runs so no host-target communication (e.g. RTT) is required to pass the command-line flags.
(well, technically the flags will be written above (higher address) the first stack frame because the stack grows downwards in ARM Cortex-M programs)
probe-run
sideBefore flashing the program,
probe-run
will compute how much stack space is required to store the command line arguments. Using this information it will compute a "modified initial Stack Pointer" (MISP)Example:
initial SP value in vector table =
0x2001_0000
stack space required by command line arguments =
0x100
modified initial SP (MISP) =
0x2000_FF000
probe-run
will flash the firmware and then do a "reset halt". The target is now at the start of the Reset handler. At this point the target has loaded 'initial SP' from the vector table into its SP register.probe-run
will write the MISP into the target's SP register.probe-run
puts a breakpoint onmain
(we already do this) and lets the program execute until that point. At this point the target has initialized its static variables.probe-run
will write the command line arguments, along with a slice of pointers to them, into RAM and then write to the specialPROBE_ARGS_POINTER
andPROBE_ARGS_LENGTH
static variables (seeprobe-args
section for more details about these 2 variables)probe-run
"resumes" the target and does what it already does today (defmt logs, backtrace, etc.)probe-args
sideThis is a target library (no_std code).
Runtime semantics:
when the program runs "outside"
probe-run
,probe_args::args
returns an empty slice and the target uses the normal initial stack pointer (the one stored in the vector table)when the program runs "within"
probe-run
,probe_args::args
returnsprobe-run
's command line arguments and the target uses the modified initial stack pointer value.Prior art
From what I remember the Linux ELF loader works a bit like this. It writes command line arguments below the first stack frame. Above that data and just below the first stack frame it writes the pointer to those arguments (
argv
) and the number of arguments (argc
). The real entry point (the one in libc) of the ELF program, written in assembly, retrievesargv
andargc
from the stack (they are at$SP - 16
) and passes them to the user entry point ("main").Known limitations
probe_args::args
will always return an empty slice when invoked after a software reset. This is becausecortex-m-rt
will zeroPROBE_ARGS_POINTER
(before usermain
runs) butprobe-run
will not setPROBE_ARGS_POINTER
on software reset.Edits
--
(e.g.probe-run --chip CHIP my-elf -- command line arguments
) but this is not compatible with howRust Analyzercargo test
passes arguments to the Cargo runner; it passes e.g.--exact
,capture
right after the ELF file path.The text was updated successfully, but these errors were encountered: