Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .cargo/config.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@


[target.aarch64-unknown-linux-gnu]
linker = "aarch64-linux-gnu-gcc"
10 changes: 5 additions & 5 deletions .github/workflows/build_and_test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#


name: register_tool
name: Register_Tool

on:
push:
Expand All @@ -33,7 +33,7 @@ env:
CARGO_TERM_COLOR: always

jobs:
build:
Build_and_Test:

runs-on: ubuntu-latest
container: rust:latest
Expand All @@ -47,7 +47,7 @@ jobs:
- name: Build
run: cargo build --verbose
- name: Run tests
run: cargo test && cd aep_rust_common && cargo test
run: cargo test && cd tools/ucompleter/aep_rust_common && cargo test
- name: rustup aarch64
run: rustup target add aarch64-unknown-linux-gnu
- name: gcc-arm64
Expand All @@ -61,11 +61,11 @@ jobs:
- uses: actions/upload-artifact@v4
with:
name: register_tool-arm64
path: "target/aarch64-unknown-linux-gnu/debian/register_tool*.deb"
path: "target/aarch64-unknown-linux-gnu/debian/register-tool*.deb"
overwrite: true
- uses: actions/upload-artifact@v4
with:
name: register_tool-x86
path: target/debian/register_tool*.deb
path: target/debian/register-tool*.deb
overwrite: true

2 changes: 1 addition & 1 deletion .gitmodules
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[submodule "tools/ucompleter"]
path = tools/ucompleter
url = git@github.com:AndrewOfC/ucompleter
url = git@github.com:AndrewOfC/ucompleter.git
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,14 @@ yaml-rust = "0.4.5"
libc = "0.2.174"
regex = "1.11.1"
aep_rust_common = { path = "tools/ucompleter/aep_rust_common" }
lazy_static = "1.5.0"


[package.metadata.deb]
copyright = "© copyright Andrew Ellis Page"
extended-description-file= "README.md"
section = "Utilities"
assets = [ "$auto", [ "examples/raspberrypi4b_source.yaml", "/usr/share/doc/register-tool/examples/", "0644" ],
["examples/raspberrypi4b.yaml", "/usr/share/doc/register-tool/examples/", "0644" ],
["docs/*", "/usr/share/doc/register-tool/docs/", "0644"]]

58 changes: 42 additions & 16 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,31 @@

[![Build, Test and Package](https://github.com/AndrewOfC/register_tool/actions/workflows/build_and_test.yml/badge.svg?branch=master)](https://github.com/AndrewOfC/register_tool/actions/workflows/build_and_test.yml)
![](https://www.rust-lang.org/logos/rust-logo-blk.svg)

# Overview

This is a tool for examining and manipulating memory mapped registers in embedded devices via symbolic
names instead of raw addresses.
names instead of raw addresses.

The program reads a register configuration file in yaml format which contains register definitions.

# Demonstration

[YouTube Video](https://youtu.be/6FWzfbQRQ3M)

![sparkfun](./docs/sparkfun.jpg)

Here on a [SparkFun PiWedge](https://www.sparkfun.com/sparkfun-pi-wedge.html) we've connected GPIO[27] pin of the RaspberyPi 4b's BCM2711 to an LED through a 330Ω resister.
On the command line we set the pins .function register to 1(output), then set the .set register to
1 to turn on the LED, then set the .clear register to 1 to turn it off.

```
register_tool GPIO.pins[27].function=1 # configures for output
register_tool GPIO.pins[27].set=1 # sets pin 27 hi
register_tool GPIO.pins[27].clear=1 # sets pin 27 lo
```


# Building

## aarch64-unknown-linux-gnu
Expand All @@ -16,11 +38,25 @@ sudo apt-get install -y gcc-aarch64-linux-gnu # once

git clone https://https://github.com/AndrewOfC/register_tool.git --recursive
cd register_tool
cargo build

cargo build --target aarch64-unknown-linux-gnu
```

The executable can be found in "target/aarch64-uknonwn-linux-gnu/debug/register_tool"

# Installation

From .deb package

## RasberryPi4b

### With .deb package
If installing from the .deb package, copy or symlink the file [/usr/share/doc/register-tool/examples/raspberrypi4b.yaml](file:///usr/share/doc/register-tool/examples/raspberrypi4b.yaml) to
$HOME/.config/register_tool/register_tool.yaml

### With local build

copy or symlink the file [examples/raspberrypi4.yaml](file://examples/raspberrypi4.yaml)

# Usage

```bash
Expand Down Expand Up @@ -170,21 +206,11 @@ on the bash command line. It is not required, but it is recommended.

# Example Files

| File | Contents |
|-----------------------------------------------------------------|------------------------------------------|
| File | Contents |
|----------------------------------------------------------|------------------------------------------|
| [raspberrypi4b_source.yaml](examples/raspberrypi4b_source.yaml) | Register definitions for RaspberryPi 4b This file was constructed with data from: [bcm2711-peripherals.pdf](https://datasheets.raspberrypi.com/bcm2711/bcm2711-peripherals.pdf)|
| [raspberrypi4b.yaml](examples/raspberrypi4b.yaml) | The raspberrypi4b_source.yaml file remapped for a 'per pin' perspective. |

# Example
| [raspberrypi4b.yaml](examples/raspberrypi4b.yaml) | The raspberrypi4b_source.yaml file remapped for a 'per pin' perspective.| |

To toggle GPIO pin 27 on a RaspberryPi 4b using a [SparkFun PiWedge](https://www.sparkfun.com/sparkfun-pi-wedge.html)

```
register_tool GPIO.pins[27].function=1 # configures for output
register_tool GPIO.pins[27].set=1 # sets pin 27 hi
register_tool GPIO.pins[27].clear=1 # sets pin 27 lo
```
![sparkfun](./docs/sparkfun.jpg)
# Layout

| Dir | Contents |
Expand Down
Binary file modified docs/sparkfun.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
26 changes: 23 additions & 3 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,15 @@ fn main() {
process::exit(3);
} ;

let mut register_tool = RegisterTool::new(descender);
let mut register_tool = match RegisterTool::new(descender) {
Ok(rt) => rt,
Err(errs) => {
for e in errs {
eprintln!("{}", e);
}
process::exit(4);
}
} ;


if *options.get_one::<bool>("dump").unwrap_or(&false) {
Expand All @@ -109,18 +117,30 @@ fn main() {
}
}

/*
* gather up all the registers to read or set.
* If there are erroneous registers report them all and exit
*/
match register_tool.gather_regs(&registers) {
Ok(_) => {}
Err(e) => {
println!("{}", e);
for e in e {
eprintln!("{}", e);
}
process::exit(1);
}
} ;

if *options.get_one::<bool>("test").unwrap_or(&false) {
register_tool.set_test_area() ;
} else {
register_tool.set_base_address() ;
match register_tool.set_base_address() {
Ok(_) => {}
Err(e) => {
eprintln!("{}", e);
process::exit(1);
}
}
}

let results = register_tool.apply_registers(|v| {
Expand Down
13 changes: 13 additions & 0 deletions src/register_op.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,19 @@ pub fn parse_bits(bitsstr: &str) -> Result<(u32, u32), String> {
}

impl RegisterOp {

/// a noop register
pub fn noop() -> RegisterOp {
RegisterOp {
offset: 0,
set_mask: 0,
read_mask: 0,
shift: 0,
value: None,
shadow_offset: None,
access_type: RegisterAccess::Unspecified,
}
}
pub fn new(descender: &dyn Descender<dyn Write>, value: Option<u32>, path:&str) -> Result<RegisterOp, String> {

let offset_r = descender.get_int_field_or_parent(path, "offset");
Expand Down
100 changes: 82 additions & 18 deletions src/register_tool.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ pub struct RegisterTool {
regs: Vec<RegisterOp>,
addr: *mut u8,
test_mode: bool,
device: String,
base: u64,
length: u64,
}

impl RegisterTool {
Expand Down Expand Up @@ -69,7 +72,7 @@ impl RegisterTool {
match self.descender.set_root(&*old_root) {
Ok(_) => {},
Err(e) => {
println!("Error resetting root: {}", e);
eprintln!("Error resetting root: {}", e);
fail = true;
}
}
Expand All @@ -84,27 +87,73 @@ impl RegisterTool {
}

impl RegisterTool {
pub fn new(descender: Box<dyn Descender<dyn Write>>) -> Self {
Self {descender, regs: Vec::new(), addr: std::ptr::null_mut(), test_mode: false }
pub fn new(descender: Box<dyn Descender<dyn Write>>) -> Result<Self, Vec<String>> {
let mut errs: Vec<String> = Vec::new();

/*
* Validate the integrity of the file
*/
let device = match descender.get_string_field_or_parent("","device") {
Ok(d) => d,
Err(e) => {
errs.push(format!("device not found: {}", e));
"".to_string()
}
} ;

let base = match descender.get_int_field_or_parent("","base") {
Ok(b) => b,
Err(e) => {
errs.push(format!("base not found: {}", e));
0
}
} as u64 ;

let length = match descender.get_int_field_or_parent("","length") {
Ok(l) => l,
Err(e) => {
errs.push(format!("length not found: {}", e));
0
}
} as u64 ;

/*
* return all collected errors
*/
if errs.len() > 0 {
return Err(errs);
}
let register_tool = Self {descender, regs: Vec::new(), addr: std::ptr::null_mut(), test_mode: false, device, base, length } ;

Ok(register_tool)
}

pub fn set_base_address(&mut self) {
let device = self.descender.get_string_field_or_parent("","device").expect("device not found") ;
let base = self.descender.get_int_field_or_parent("","base").expect("base not found") ;
let length = self.descender.get_int_field_or_parent("","length").expect("length not found") ;
self.addr = mmap_memory(device.as_str(), base as u64, length as u64).expect("mmap failed") ;
pub fn set_base_address(&mut self) -> Result<(), String> {
self.addr = match mmap_memory(self.device.as_str(), self.base, self.length) {
Ok(a) => a,
Err(e) => {
return Err(format!("Error mapping memory: {}", e));
}
} ;
Ok(())
}

pub fn set_test_area(&mut self) {
let length = self.descender.get_int_field_or_parent("", "length").expect("length not found");
let mut memory = Vec::with_capacity(length as usize);
memory.resize(length as usize, 0u8);
let mut memory = Vec::with_capacity(self.length as usize);
memory.resize(self.length as usize, 0u8);
self.addr = memory.as_mut_ptr();
std::mem::forget(memory);
self.test_mode = true;
}

pub fn gather_regs(&mut self, regsspecs: &Vec<&str>) -> Result<(), String> {

///
/// gather the registers to set or read.
///
/// return Ok or the collected errors
///
pub fn gather_regs(&mut self, regsspecs: &Vec<&str>) -> Result<(), Vec<String>> {
let mut errs: Vec<String> = Vec::new();

let old_root = match &self.descender.get_string_field_or_parent("completion-metadata", "root") {
Ok(r) => self.descender.set_root(r).unwrap(),
Expand All @@ -114,31 +163,43 @@ impl RegisterTool {
for spec in regsspecs {
let parts = spec.split("=").collect::<Vec<&str>>();
if parts.len() > 2 {
return Err(format!("Bad argument {}", spec));
errs.push(format!("Bad argument {}", spec));
continue ;
}
let is_set = parts.len() == 2 ;
let value = if is_set {
match parts[1].parse::<u32>() {
Ok(v) => Some(v),
Err(_) => return Err(format!("Bad argument {}", spec)),
Err(_) => {
errs.push(format!("Bad argument {}", spec)) ;
None
}
}
} else { None };

let r = match RegisterOp::new(&*self.descender, value, parts[0]) {
Ok(r) => r,
Err(e) => return Err(e),
Err(e) => { errs.push(e) ;
RegisterOp::noop()
}
} ;

self.regs.push(r)
}

match self.descender.set_root(&*old_root) {
Ok(_) => {},
Err(e) => {
println!("Error resetting root: {}", e);
return Err(format!("Error resetting root: {}", e));
errs.push(format!("Error resetting old root: {}", e));
}
} ;

if errs.len() > 0 {
Err(errs)
} else {
Ok(())
}
Ok(())
}

pub fn apply_registers<F>(&self, f: F) -> Result<Vec<Result<u32, String>>, String>
Expand All @@ -159,8 +220,11 @@ impl RegisterTool {
}
Ok(results)
}

}

///
/// Free any memory we might have allocated
///
impl Drop for RegisterTool {
fn drop(&mut self) {
if self.test_mode {
Expand Down
Loading