Skip to content

Commit d44d764

Browse files
committed
🎉
0 parents  commit d44d764

File tree

10 files changed

+410
-0
lines changed

10 files changed

+410
-0
lines changed

.cargo/config

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
[target.'cfg(all(target_arch = "arm", target_os = "none"))']
2+
3+
rustflags = [
4+
"-C", "link-arg=--nmagic",
5+
"-C", "link-arg=-Tlink.x",
6+
7+
# Code-size optimizations.
8+
"-Z", "trap-unreachable=no",
9+
"-C", "inline-threshold=5",
10+
"-C", "no-vectorize-loops",
11+
"-C", "force-frame-pointers=no",
12+
13+
# We don't know where the flash loader will be
14+
# placed in memory, so we need to create
15+
# position independent code (pic).
16+
"-C", "relocation-model=pic",
17+
]
18+
19+
[build]
20+
target = "thumbv6m-none-eabi" # Cortex-M0 and Cortex-M0+
21+
# target = "thumbv7m-none-eabi" # Cortex-M3
22+
# target = "thumbv7em-none-eabi" # Cortex-M4 and Cortex-M7 (no FPU)
23+
# target = "thumbv7em-none-eabihf" # Cortex-M4F and Cortex-M7F (with FPU)
24+
# target = "thumbv8m.base-none-eabi" # Cortex-M23
25+
# target = "thumbv8m.main-none-eabi" # Cortex-M33 (no FPU)
26+
# target = "thumbv8m.main-none-eabihf" # Cortex-M33 (with FPU)

.gitignore

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
**/*.rs.bk
2+
.#*
3+
.gdb_history
4+
Cargo.lock
5+
target/
6+
7+
# editor files
8+
.vscode/*
9+
!.vscode/*.md
10+
!.vscode/*.svd
11+
!.vscode/launch.json
12+
!.vscode/tasks.json
13+
!.vscode/extensions.json
14+
!.vscode/settings.json

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"editor.formatOnSave": true
3+
}

Cargo.toml

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
[package]
2+
authors = ["Dario Nieuwenhuis <dirbaio@dirbaio.net>"]
3+
edition = "2018"
4+
readme = "README.md"
5+
name = "flash-algo"
6+
version = "0.1.0"
7+
8+
[dependencies]
9+
cortex-m = "0.7.0"
10+
11+
# this lets you use `cargo fix`!
12+
[[bin]]
13+
name = "flash-algo"
14+
test = false
15+
bench = false
16+
17+
[profile.dev]
18+
codegen-units = 1
19+
debug = 2
20+
debug-assertions = true
21+
incremental = false
22+
opt-level = 3
23+
overflow-checks = true
24+
25+
[profile.release]
26+
codegen-units = 1
27+
debug = 2
28+
debug-assertions = false
29+
incremental = false
30+
lto = "fat"
31+
opt-level = 's'
32+
overflow-checks = false
33+
34+
# do not optimize proc-macro crates = faster builds from scratch
35+
[profile.dev.build-override]
36+
codegen-units = 8
37+
debug = false
38+
debug-assertions = false
39+
opt-level = 0
40+
overflow-checks = false
41+
42+
[profile.release.build-override]
43+
codegen-units = 8
44+
debug = false
45+
debug-assertions = false
46+
opt-level = 0
47+
overflow-checks = false

README.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# RaspberryPi Pico RP2040 flash algorithm
2+
3+
This is a flash algorithm for the RP2040 chip, used in the Raspberry Pi Pico board.
4+
It implements the CMSIS-Pack ABI, so it's compatible with any tools that use it, including probe-rs.
5+
6+
## Building
7+
8+
Building requires nightly Rust.
9+
10+
Just run `build.sh`. It spits out the flash algo in the probe-rs YAML format:
11+
12+
flash-algo$ ./build.sh
13+
instructions: sLUUIACIGUoBRguI...wRwAgcEc=
14+
pc_init: 0x00000000
15+
pc_uninit: 0x0000007c
16+
pc_program_page: 0x00000088
17+
pc_erase_sector: 0x00000084
18+
pc_erase_all: 0x00000080
19+
20+
## Hacking
21+
22+
The `algo` module contains the FlashAlgo trait, and an `algo!` macro to generate
23+
the glue functions for a given struct implementing it. This is generic for all chips, so feel free to reuse it!
24+
25+
`main.rs` has the actual implementation for RP2040.
26+
27+
# License
28+
29+
This thingy is licensed under either of
30+
31+
- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
32+
http://www.apache.org/licenses/LICENSE-2.0)
33+
34+
- MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
35+
36+
at your option.

build.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
use std::env;
2+
use std::fs::File;
3+
use std::io::Write;
4+
use std::path::PathBuf;
5+
6+
fn main() {
7+
// Put `link.x` in our output directory and ensure it's
8+
// on the linker search path.
9+
let out = &PathBuf::from(env::var_os("OUT_DIR").unwrap());
10+
File::create(out.join("link.x"))
11+
.unwrap()
12+
.write_all(include_bytes!("link.x"))
13+
.unwrap();
14+
println!("cargo:rustc-link-search={}", out.display());
15+
16+
// By default, Cargo will re-run a build script whenever
17+
// any file in the project changes. By specifying `link.x`
18+
// here, we ensure the build script is only re-run when
19+
// `link.x` is changed.
20+
println!("cargo:rerun-if-changed=link.x");
21+
}

build.sh

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
cargo build --release -Zbuild-std=core -Zbuild-std-features=panic_immediate_abort
6+
ELF=target/thumbv6m-none-eabi/release/flash-algo
7+
8+
llvm-objdump --disassemble $ELF > target/disassembly.s
9+
llvm-objdump -x $ELF > target/dump.txt
10+
llvm-nm $ELF -n > target/nm.txt
11+
12+
function bin {
13+
llvm-objcopy $ELF -O binary - | base64 -w0
14+
}
15+
16+
function sym {
17+
echo $((0x$(llvm-nm $ELF | grep $1 | cut -d ' ' -f 1) + 1))
18+
}
19+
20+
cat <<EOF
21+
instructions: $(bin)
22+
pc_init: $(sym _algo_init)
23+
pc_uninit: $(sym _algo_uninit)
24+
pc_program_page: $(sym _algo_program_page)
25+
pc_erase_sector: $(sym _algo_erase_sector)
26+
pc_erase_all: $(sym _algo_erase_all)
27+
EOF

link.x

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
SECTIONS {
2+
. = 0x0;
3+
4+
.text : {
5+
KEEP(*(.entry))
6+
KEEP(*(.entry.*))
7+
8+
*(.text)
9+
*(.text.*)
10+
11+
*(.rodata)
12+
*(.rodata.*)
13+
14+
*(.data)
15+
*(.data.*)
16+
17+
*(.sdata)
18+
*(.sdata.*)
19+
20+
*(.bss)
21+
*(.bss.*)
22+
23+
*(.uninit)
24+
*(.uninit.*)
25+
26+
. = ALIGN(4);
27+
}
28+
29+
/DISCARD/ : {
30+
/* Unused exception related info that only wastes space */
31+
*(.ARM.exidx);
32+
*(.ARM.exidx.*);
33+
*(.ARM.extab.*);
34+
}
35+
}

src/algo.rs

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
#![macro_use]
2+
3+
4+
use core::num::NonZeroU32;
5+
6+
#[panic_handler]
7+
fn panic(_info: &core::panic::PanicInfo) -> ! {
8+
unsafe {
9+
asm!("udf #0");
10+
core::hint::unreachable_unchecked();
11+
}
12+
}
13+
14+
pub const FUNCTION_ERASE: u32 = 1;
15+
pub const FUNCTION_PROGRAM: u32 = 2;
16+
pub const FUNCTION_VERIFY: u32 = 3;
17+
18+
pub type ErrorCode = NonZeroU32;
19+
20+
pub trait FlashAlgo: Sized + 'static {
21+
/// Initialize the flash algorithm.
22+
fn new(address: u32, clock: u32, function: u32) -> Result<Self, ErrorCode>;
23+
24+
/// Erase entire chip. May only be called after init() with FUNCTION_ERASE
25+
fn erase_all(&mut self) -> Result<(), ErrorCode>;
26+
27+
/// Erase sector. May only be called after init() with FUNCTION_ERASE
28+
fn erase_sector(&mut self, addr: u32) -> Result<(), ErrorCode>;
29+
30+
/// Program bytes. May only be called after init() with FUNCTION_PROGRAM
31+
fn program_page(&mut self, addr: u32, size: u32, data: *const u8) -> Result<(), ErrorCode>;
32+
}
33+
34+
#[macro_export]
35+
macro_rules! algo {
36+
($type:ty) => {
37+
static mut _IS_INIT: bool = false;
38+
static mut _ALGO_INSTANCE: MaybeUninit<$type> = MaybeUninit::uninit();
39+
40+
#[no_mangle]
41+
#[link_section = ".entry"]
42+
pub unsafe extern "C" fn _algo_init(addr: u32, clock: u32, function: u32) -> u32 {
43+
if _IS_INIT {
44+
_algo_uninit();
45+
}
46+
_IS_INIT = true;
47+
match <$type as FlashAlgo>::new(addr, clock, function) {
48+
Ok(inst) => {
49+
_ALGO_INSTANCE.as_mut_ptr().write(inst);
50+
_IS_INIT = true;
51+
0
52+
}
53+
Err(e) => e.get(),
54+
}
55+
}
56+
#[no_mangle]
57+
#[link_section = ".entry"]
58+
pub unsafe extern "C" fn _algo_uninit() -> u32 {
59+
if !_IS_INIT {
60+
return 1;
61+
}
62+
_ALGO_INSTANCE.as_mut_ptr().drop_in_place();
63+
_IS_INIT = false;
64+
0
65+
}
66+
#[no_mangle]
67+
#[link_section = ".entry"]
68+
pub unsafe extern "C" fn _algo_erase_all() -> u32 {
69+
if !_IS_INIT {
70+
return 1;
71+
}
72+
let this = &mut *_ALGO_INSTANCE.as_mut_ptr();
73+
match <$type as FlashAlgo>::erase_all(this) {
74+
Ok(()) => 0,
75+
Err(e) => e.get(),
76+
}
77+
}
78+
#[no_mangle]
79+
#[link_section = ".entry"]
80+
pub unsafe extern "C" fn _algo_erase_sector(addr: u32) -> u32 {
81+
if !_IS_INIT {
82+
return 1;
83+
}
84+
let this = &mut *_ALGO_INSTANCE.as_mut_ptr();
85+
match <$type as FlashAlgo>::erase_sector(this, addr) {
86+
Ok(()) => 0,
87+
Err(e) => e.get(),
88+
}
89+
}
90+
#[no_mangle]
91+
#[link_section = ".entry"]
92+
pub unsafe extern "C" fn _algo_program_page(addr: u32, size: u32, data: *const u8) -> u32 {
93+
if !_IS_INIT {
94+
return 1;
95+
}
96+
let this = &mut *_ALGO_INSTANCE.as_mut_ptr();
97+
match <$type as FlashAlgo>::program_page(this, addr, size, data) {
98+
Ok(()) => 0,
99+
Err(e) => e.get(),
100+
}
101+
}
102+
};
103+
}

0 commit comments

Comments
 (0)