Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

isolated nonvolatile storage capsule with test #478

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
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
11 changes: 11 additions & 0 deletions examples/tests/isolated_nonvolatile_storage/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Makefile for user application

# Specify this directory relative to the current application.
TOCK_USERLAND_BASE_DIR = ../../..

# Which files to compile.
C_SRCS := $(wildcard *.c)

# Include userland master makefile. Contains rules and flags for actually
# building the application.
include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk
83 changes: 83 additions & 0 deletions examples/tests/isolated_nonvolatile_storage/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
Nonvolatile Storage Test App
============================

This app writes to flash storage and reads it back to test that flash storage
is working. It requires that a
`capsules::nonvolatile_storage_driver::NonvolatileStorage` interface be provided
to userland.



Example Hail Setup
------------------

One way to provide the Driver interface with Hail looks like:

```diff
--- a/boards/hail/src/main.rs
+++ b/boards/hail/src/main.rs
@@ -74,6 +74,7 @@ struct Hail {
ipc: kernel::ipc::IPC,
crc: &'static capsules::crc::Crc<'static, sam4l::crccu::Crccu<'static>>,
dac: &'static capsules::dac::Dac<'static>,
+ nv: &'static capsules::nonvolatile_storage_driver::NonvolatileStorage<'static>,
}

/// Mapping of integer syscalls to objects that implement syscalls.
@@ -104,6 +105,8 @@ impl Platform for Hail {
capsules::dac::DRIVER_NUM => f(Some(self.dac)),

kernel::ipc::DRIVER_NUM => f(Some(&self.ipc)),
+
+ 27 => f(Some(self.nv)),
_ => f(None),
}
}
@@ -443,6 +446,38 @@ pub unsafe fn reset_handler() {
capsules::dac::Dac::new(&mut sam4l::dac::DAC)
);

+ // Flash
+ let mux_flash = static_init!(
+ capsules::virtual_flash::MuxFlash<'static, sam4l::flashcalw::FLASHCALW>,
+ capsules::virtual_flash::MuxFlash::new(&sam4l::flashcalw::FLASH_CONTROLLER));
+ hil::flash::HasClient::set_client(&sam4l::flashcalw::FLASH_CONTROLLER, mux_flash);
+
+ // Nonvolatile Storage
+ let virtual_flash_nv = static_init!(
+ capsules::virtual_flash::FlashUser<'static, sam4l::flashcalw::FLASHCALW>,
+ capsules::virtual_flash::FlashUser::new(mux_flash));
+ pub static mut NV_PAGEBUFFER: sam4l::flashcalw::Sam4lPage = sam4l::flashcalw::Sam4lPage::new();
+
+ let nv_nv_to_page = static_init!(
+ capsules::nonvolatile_to_pages::NonvolatileToPages<'static,
+ capsules::virtual_flash::FlashUser<'static, sam4l::flashcalw::FLASHCALW>>,
+ capsules::nonvolatile_to_pages::NonvolatileToPages::new(
+ virtual_flash_nv,
+ &mut NV_PAGEBUFFER));
+ hil::flash::HasClient::set_client(virtual_flash_nv, nv_nv_to_page);
+
+ pub static mut NV_BUFFER: [u8; 512] = [0; 512];
+ let nv = static_init!(
+ capsules::nonvolatile_storage_driver::NonvolatileStorage<'static>,
+ capsules::nonvolatile_storage_driver::NonvolatileStorage::new(
+ nv_nv_to_page, kernel::Grant::create(),
+ 0x60000, // Start address for userspace accessible region
+ 0x20000, // Length of userspace accessible region
+ 0, // Start address of kernel accessible region
+ 0, // Length of kernel accessible region
+ &mut NV_BUFFER));
+ hil::nonvolatile_storage::NonvolatileStorage::set_client(nv_nv_to_page, nv);
+
let hail = Hail {
console: console,
gpio: gpio,
@@ -460,6 +495,7 @@ pub unsafe fn reset_handler() {
ipc: kernel::ipc::IPC::new(),
crc: crc,
dac: dac,
+ nv: nv,
};

// Need to reset the nRF on boot
```
81 changes: 81 additions & 0 deletions examples/tests/isolated_nonvolatile_storage/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#include <libtock-sync/storage/isolated_nonvolatile_storage.h>

static int test_all(void);
static int test(uint8_t* readbuf, uint8_t* writebuf, size_t size, size_t offset, size_t len);

int main(void) {
printf("[TEST] Isolated Nonvolatile Storage\n");

int r = test_all();
if (r == 0) {
printf("All tests succeeded\n");
} else {
printf("Failed with code %d\n", r);
}

return r;
}

static int test_all(void) {
int num_bytes;
libtocksync_isolated_nonvolatile_storage_get_number_bytes((uint32_t*) &num_bytes);
printf("Have %i bytes of nonvolatile storage\n", num_bytes);

int r;
uint8_t readbuf[512];
uint8_t writebuf[512];

if ((r = test(readbuf, writebuf, 256, 0, 14)) != 0) return r;
if ((r = test(readbuf, writebuf, 256, 20, 14)) != 0) return r;
if ((r = test(readbuf, writebuf, 512, 0, 512)) != 0) return r;

printf("Write to end of region (offset %d)\n", num_bytes - 512);
if ((r = test(readbuf, writebuf, 512, num_bytes - 512, 500)) != 0) return r;

printf("Write beyond end region, should fail (offset %d)\n", num_bytes);
if ((r = test(readbuf, writebuf, 512, num_bytes, 501)) == 0) return -1;

printf("Write starts beyond end region, should fail (offset %d)\n", num_bytes + 1);
if ((r = test(readbuf, writebuf, 512, num_bytes + 1, 1)) == 0) return -1;

printf("Write starts before start region, should fail (offset %d)\n", -1);
if ((r = test(readbuf, writebuf, 512, -1, 1)) == 0) return -1;

return 0;
}

static int test(uint8_t* readbuf, uint8_t* writebuf, size_t size, size_t offset, size_t len) {
int ret;
int length_written, length_read;

printf("\tTest with size %d ...\n", size);

for (size_t i = 0; i < len; i++) {
writebuf[i] = i;
}

ret = libtocksync_isolated_nonvolatile_storage_write(offset, len, writebuf, size, &length_written);
if (ret != RETURNCODE_SUCCESS) {
printf("\tERROR calling write. returncode: %d\n", ret);
return ret;
}

ret = libtocksync_isolated_nonvolatile_storage_read(offset, len, readbuf, size, &length_read);
if (ret != RETURNCODE_SUCCESS) {
printf("\tERROR calling read. returncode: %d\n", ret);
return ret;
}

for (size_t i = 0; i < len; i++) {
if (readbuf[i] != writebuf[i]) {
printf("\tInconsistency between data written and read at index %u\n", i);
return -1;
}
}

return 0;
}
80 changes: 80 additions & 0 deletions libtock-sync/storage/isolated_nonvolatile_storage.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
#include "isolated_nonvolatile_storage.h"
#include <stdio.h>

struct nv_data {
bool fired;
returncode_t ret;
int length;
int storage_size;
};

static struct nv_data result = {.fired = false};

static void get_number_bytes_cb(returncode_t ret, int number_bytes) {
result.fired = true;
result.ret = ret;
result.storage_size = number_bytes;
}

static void write_cb(returncode_t ret, int length) {
result.fired = true;
result.ret = ret;
result.length = length;
}

static void read_cb(returncode_t ret, int length) {
result.fired = true;
result.ret = ret;
result.length = length;
}

returncode_t libtocksync_isolated_nonvolatile_storage_get_number_bytes(uint32_t* number_bytes) {
returncode_t ret;
result.fired = false;

ret = libtock_isolated_nonvolatile_storage_get_number_bytes(get_number_bytes_cb);
if (ret != RETURNCODE_SUCCESS) return ret;

yield_for(&result.fired);
if (result.ret != RETURNCODE_SUCCESS) return result.ret;

*number_bytes = result.storage_size;
return RETURNCODE_SUCCESS;
}

returncode_t libtocksync_isolated_nonvolatile_storage_write(uint32_t offset, uint32_t length, uint8_t* buffer,
uint32_t buffer_length, int* length_written) {
returncode_t ret;
result.fired = false;

ret = libtock_isolated_nonvolatile_storage_write(offset, length, buffer, buffer_length, write_cb);
if (ret != RETURNCODE_SUCCESS) return ret;

yield_for(&result.fired);
if (result.ret != RETURNCODE_SUCCESS) return result.ret;

ret = libtock_isolated_nonvolatile_storage_set_allow_readonly_write_buffer(NULL, 0);
if (result.ret != RETURNCODE_SUCCESS) return result.ret;

*length_written = result.length;
return RETURNCODE_SUCCESS;
}

returncode_t libtocksync_isolated_nonvolatile_storage_read(uint32_t offset, uint32_t length, uint8_t* buffer,
uint32_t buffer_length, int* length_read) {
returncode_t ret;
result.fired = false;

ret = libtock_isolated_nonvolatile_storage_read(offset, length, buffer, buffer_length, read_cb);
if (ret != RETURNCODE_SUCCESS) return ret;

yield_for(&result.fired);
if (result.ret != RETURNCODE_SUCCESS) return result.ret;

ret = libtock_isolated_nonvolatile_storage_set_allow_readwrite_read_buffer(NULL, 0);
if (result.ret != RETURNCODE_SUCCESS) return result.ret;

*length_read = result.length;
return RETURNCODE_SUCCESS;
}

25 changes: 25 additions & 0 deletions libtock-sync/storage/isolated_nonvolatile_storage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <libtock/storage/isolated_nonvolatile_storage.h>
#include <libtock/tock.h>

#ifdef __cplusplus
extern "C" {
#endif

// Get number of bytes available to this app in nonvolatile storage
returncode_t libtocksync_isolated_nonvolatile_storage_get_number_bytes(uint32_t* number_bytes);

// Write `length` bytes from `buffer` to the nonvolatile storage starting at
// `offset`.
returncode_t libtocksync_isolated_nonvolatile_storage_write(uint32_t offset, uint32_t length, uint8_t* buffer,
uint32_t buffer_length, int* length_written);

// Read `length` bytes into `buffer` from the nonvolatile storage starting at
// `offset`.
returncode_t libtocksync_isolated_nonvolatile_storage_read(uint32_t offset, uint32_t length, uint8_t* buffer,
uint32_t buffer_length, int* length_read);

#ifdef __cplusplus
}
#endif
65 changes: 65 additions & 0 deletions libtock/storage/isolated_nonvolatile_storage.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#include "isolated_nonvolatile_storage.h"
#include "syscalls/isolated_nonvolatile_storage_syscalls.h"

static void get_number_bytes_done(int ret,
int number_bytes,
__attribute__ ((unused)) int arg3,
void* opaque) {
libtock_isolated_nonvolatile_storage_callback_get_number_bytes cb = (libtock_isolated_nonvolatile_storage_callback_get_number_bytes) opaque;
cb(tock_status_to_returncode(ret), number_bytes);
}

static void write_done(int ret,
int length,
__attribute__ ((unused)) int arg2,
void* opaque) {
libtock_isolated_nonvolatile_storage_callback_write cb = (libtock_isolated_nonvolatile_storage_callback_write) opaque;
cb(tock_status_to_returncode(ret), length);
}

static void read_done(int ret,
int length,
__attribute__ ((unused)) int arg2,
void* opaque) {
libtock_isolated_nonvolatile_storage_callback_read cb = (libtock_isolated_nonvolatile_storage_callback_read) opaque;
cb(tock_status_to_returncode(ret), length);
}

returncode_t libtock_isolated_nonvolatile_storage_get_number_bytes(libtock_isolated_nonvolatile_storage_callback_get_number_bytes cb) {
returncode_t ret;

ret = libtock_isolated_nonvolatile_storage_set_upcall_get_number_bytes_done(get_number_bytes_done, cb);
if (ret != RETURNCODE_SUCCESS) return ret;

ret = libtock_isolated_nonvolatile_storage_command_get_number_bytes();
return ret;
}

returncode_t libtock_isolated_nonvolatile_storage_write(uint32_t offset, uint32_t length, uint8_t* buffer,
uint32_t buffer_length, libtock_isolated_nonvolatile_storage_callback_write cb) {
returncode_t ret;

ret = libtock_isolated_nonvolatile_storage_set_upcall_write_done(write_done, cb);
if (ret != RETURNCODE_SUCCESS) return ret;

ret = libtock_isolated_nonvolatile_storage_set_allow_readonly_write_buffer(buffer, buffer_length);
if (ret != RETURNCODE_SUCCESS) return ret;

ret = libtock_isolated_nonvolatile_storage_command_write(offset, length);
return ret;
}

returncode_t libtock_isolated_nonvolatile_storage_read(uint32_t offset, uint32_t length, uint8_t* buffer, uint32_t buffer_length,
libtock_isolated_nonvolatile_storage_callback_read cb) {
returncode_t ret;

ret = libtock_isolated_nonvolatile_storage_set_upcall_read_done(read_done, cb);
if (ret != RETURNCODE_SUCCESS) return ret;

ret = libtock_isolated_nonvolatile_storage_set_allow_readwrite_read_buffer(buffer, buffer_length);
if (ret != RETURNCODE_SUCCESS) return ret;

ret = libtock_isolated_nonvolatile_storage_command_read(offset, length);
return ret;
}

42 changes: 42 additions & 0 deletions libtock/storage/isolated_nonvolatile_storage.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#pragma once

#include "../tock.h"
#include "syscalls/isolated_nonvolatile_storage_syscalls.h"

#ifdef __cplusplus
extern "C" {
#endif

// Function signature for nonvolatile storage get_number_bytes callbacks.
//
// - `arg1` (`returncode_t`): Status of get_number_bytes.
// - `arg2` (`int`): Number of bytes available in storage.
typedef void (*libtock_isolated_nonvolatile_storage_callback_get_number_bytes)(returncode_t, int);

// Function signature for nonvolatile storage write callbacks.
//
// - `arg1` (`returncode_t`): Status of write.
// - `arg2` (`int`): Length written.
typedef void (*libtock_isolated_nonvolatile_storage_callback_write)(returncode_t, int);

// Function signature for nonvolatile storage read callbacks.
//
// - `arg1` (`returncode_t`): Status of read.
// - `arg2` (`int`): Length ead.
typedef void (*libtock_isolated_nonvolatile_storage_callback_read)(returncode_t, int);

// Get the number of bytes available for storage.
returncode_t libtock_isolated_nonvolatile_storage_get_number_bytes(libtock_isolated_nonvolatile_storage_callback_get_number_bytes cb);

// Write `length` bytes from `buffer` to the storage starting at `offset`.
returncode_t libtock_isolated_nonvolatile_storage_write(uint32_t offset, uint32_t length, uint8_t* buffer,
uint32_t buffer_length, libtock_isolated_nonvolatile_storage_callback_write cb);

// Read `length` bytes into `buffer` from the storage starting at `offset`.
returncode_t libtock_isolated_nonvolatile_storage_read(uint32_t offset, uint32_t length, uint8_t* buffer, uint32_t buffer_length,
libtock_isolated_nonvolatile_storage_callback_read cb);

#ifdef __cplusplus
}
#endif

Loading
Loading