diff --git a/examples/tests/isolated_nonvolatile_storage/invs_no_permission/Makefile b/examples/tests/isolated_nonvolatile_storage/invs_no_permission/Makefile new file mode 100644 index 000000000..a7af26fe3 --- /dev/null +++ b/examples/tests/isolated_nonvolatile_storage/invs_no_permission/Makefile @@ -0,0 +1,15 @@ +# Makefile for user application + +# Specify this directory relative to the current application. +TOCK_USERLAND_BASE_DIR = ../../../.. + +# Which files to compile. +C_SRCS := $(wildcard *.c) + +# Set the SHA256 hash for the credential checker on the `nrf52840dk-test-invs` +# board. Also set the write_id to 0 meaning no storage permissions. +ELF2TAB_ARGS += --sha256 --write_id 0 + +# Include userland master makefile. Contains rules and flags for actually +# building the application. +include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk diff --git a/examples/tests/isolated_nonvolatile_storage/invs_no_permission/README.md b/examples/tests/isolated_nonvolatile_storage/invs_no_permission/README.md new file mode 100644 index 000000000..eccc8b2a8 --- /dev/null +++ b/examples/tests/isolated_nonvolatile_storage/invs_no_permission/README.md @@ -0,0 +1,6 @@ +Isolated Nonvolatile Storage Test App With No Permissions +========================================================= + +This app tries to use the isolated nonvolatile storage capsule but is granted no +storage access permissions (its `write_id` in the TBF header is 0). This +verifies that the read and write calls return `ENOSUPPORT`. diff --git a/examples/tests/isolated_nonvolatile_storage/invs_no_permission/main.c b/examples/tests/isolated_nonvolatile_storage/invs_no_permission/main.c new file mode 100644 index 000000000..9e5cfddfd --- /dev/null +++ b/examples/tests/isolated_nonvolatile_storage/invs_no_permission/main.c @@ -0,0 +1,93 @@ +#include +#include +#include + +#include + + +static bool test_exists(void) { + bool exists = libtock_isolated_nonvolatile_storage_exists(); + + if (exists) { + return true; + } + return false; +} + +static bool test_size(void) { + uint64_t num_bytes; + returncode_t ret; + + ret = libtocksync_isolated_nonvolatile_storage_get_number_bytes(&num_bytes); + + if (ret == RETURNCODE_ENOSUPPORT) { + return true; + } + return false; +} + +static bool test_read(void) { + returncode_t ret; + + uint8_t readbuf[512]; + + uint32_t offset = 0; + uint32_t length = 10; + + ret = libtocksync_isolated_nonvolatile_storage_read(offset, readbuf, length); + if (ret == RETURNCODE_ENOSUPPORT) { + return true; + } + return false; +} + + +static bool test_write(void) { + returncode_t ret; + + uint8_t writebuf[512] = {0x3f}; + + uint32_t offset = 0; + uint32_t length = 10; + + ret = libtocksync_isolated_nonvolatile_storage_write(offset, writebuf, length); + if (ret == RETURNCODE_ENOSUPPORT) { + return true; + } + return false; +} + + +int main(void) { + printf("[TEST] Isolated Nonvolatile Storage - No Permissions\n"); + + printf("[INVS TEST] Exists: "); + if (test_exists()) { + printf("Success\n"); + } else { + printf("Fail\n"); + } + + printf("[INVS TEST] Size: "); + if (test_size()) { + printf("Success\n"); + } else { + printf("Fail\n"); + } + + printf("[INVS TEST] Read: "); + if (test_read()) { + printf("Success\n"); + } else { + printf("Fail\n"); + } + + printf("[INVS TEST] Write: "); + if (test_write()) { + printf("Success\n"); + } else { + printf("Fail\n"); + } + + return 0; +} diff --git a/examples/tests/isolated_nonvolatile_storage/invs_read_write/Makefile b/examples/tests/isolated_nonvolatile_storage/invs_read_write/Makefile new file mode 100644 index 000000000..b4d265836 --- /dev/null +++ b/examples/tests/isolated_nonvolatile_storage/invs_read_write/Makefile @@ -0,0 +1,15 @@ +# Makefile for user application + +# Specify this directory relative to the current application. +TOCK_USERLAND_BASE_DIR = ../../../.. + +# Which files to compile. +C_SRCS := $(wildcard *.c) + +# Set the SHA256 hash for the credential checker on the `nrf52840dk-test-invs` +# board. +ELF2TAB_ARGS += --sha256 + +# Include userland master makefile. Contains rules and flags for actually +# building the application. +include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk diff --git a/examples/tests/isolated_nonvolatile_storage/invs_read_write/README.md b/examples/tests/isolated_nonvolatile_storage/invs_read_write/README.md new file mode 100644 index 000000000..49274eb21 --- /dev/null +++ b/examples/tests/isolated_nonvolatile_storage/invs_read_write/README.md @@ -0,0 +1,28 @@ +Isolated Nonvolatile Storage Test App +===================================== + +This app writes to flash storage and reads it back to test that isolated storage +is working. + +Example Output +-------------- + +``` +[TEST] Isolated Nonvolatile Storage +Have 4096 bytes of nonvolatile storage + Test with read size 14 and write size 256 ... + Test with read size 14 and write size 256 ... + Test with read size 512 and write size 512 ... +Write to end of region (offset 3584) + Test with read size 512 and write size 500 ... +Write beyond end region, should fail (offset 4096) + Test with read size 512 and write size 501 ... + ERROR calling write. returncode: -6 +Write starts beyond end region, should fail (offset 4097) + Test with read size 512 and write size 1 ... + ERROR calling write. returncode: -6 +Write starts before start region, should fail (offset -1) + Test with read size 512 and write size 512 ... + ERROR calling write. returncode: -6 +All tests succeeded +``` diff --git a/examples/tests/isolated_nonvolatile_storage/invs_read_write/main.c b/examples/tests/isolated_nonvolatile_storage/invs_read_write/main.c new file mode 100644 index 000000000..3ceb055e9 --- /dev/null +++ b/examples/tests/isolated_nonvolatile_storage/invs_read_write/main.c @@ -0,0 +1,86 @@ +#include +#include +#include + +#include + +static int test_all(void); +static int test(uint8_t* readbuf, size_t readsize, uint8_t* writebuf, size_t writesize, size_t offset); + +static size_t min(size_t a, size_t b) { + if (a < b) return a; + return b; +} + +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) { + uint64_t num_bytes_total; + libtocksync_isolated_nonvolatile_storage_get_number_bytes(&num_bytes_total); + int num_bytes = num_bytes_total; + printf("Have %i bytes of nonvolatile storage\n", num_bytes); + + int r; + uint8_t readbuf[512]; + uint8_t writebuf[512]; + + if ((r = test(readbuf, 14, writebuf, 256, 0)) != 0) return r; + if ((r = test(readbuf, 14, writebuf, 256, 20)) != 0) return r; + if ((r = test(readbuf, 512, writebuf, 512, 0)) != 0) return r; + + printf("Write to end of region (offset %d)\n", num_bytes - 512); + if ((r = test(readbuf, 512, writebuf, 500, num_bytes - 512)) != 0) return r; + + printf("Write beyond end region, should fail (offset %d)\n", num_bytes); + if ((r = test(readbuf, 512, writebuf, 501, num_bytes)) == 0) return -1; + + printf("Write starts beyond end region, should fail (offset %d)\n", num_bytes + 1); + if ((r = test(readbuf, 512, writebuf, 1, num_bytes + 1)) == 0) return -1; + + printf("Write starts before start region, should fail (offset %d)\n", -1); + if ((r = test(readbuf, 512, writebuf, 512, -1)) == 0) return -1; + + return 0; +} + +static int test(uint8_t* readbuf, size_t readsize, uint8_t* writebuf, size_t writesize, size_t offset) { + int ret; + + printf("\tTest with read size %d and write size %d ...\n", readsize, writesize); + + for (size_t i = 0; i < writesize; i++) { + writebuf[i] = i; + } + + ret = libtocksync_isolated_nonvolatile_storage_write(offset, writebuf, writesize); + if (ret != RETURNCODE_SUCCESS) { + printf("\tERROR calling write. returncode: %d\n", ret); + return ret; + } + + ret = libtocksync_isolated_nonvolatile_storage_read(offset, readbuf, readsize); + if (ret != RETURNCODE_SUCCESS) { + printf("\tERROR calling read. returncode: %d\n", ret); + return ret; + } + + for (size_t i = 0; i < min(readsize, writesize); i++) { + if (readbuf[i] != writebuf[i]) { + printf("\tInconsistency between data written and read at index %u\n", i); + return -1; + } + } + + return 0; +} diff --git a/examples/tests/isolated_nonvolatile_storage/invs_single/Makefile b/examples/tests/isolated_nonvolatile_storage/invs_single/Makefile new file mode 100644 index 000000000..b4d265836 --- /dev/null +++ b/examples/tests/isolated_nonvolatile_storage/invs_single/Makefile @@ -0,0 +1,15 @@ +# Makefile for user application + +# Specify this directory relative to the current application. +TOCK_USERLAND_BASE_DIR = ../../../.. + +# Which files to compile. +C_SRCS := $(wildcard *.c) + +# Set the SHA256 hash for the credential checker on the `nrf52840dk-test-invs` +# board. +ELF2TAB_ARGS += --sha256 + +# Include userland master makefile. Contains rules and flags for actually +# building the application. +include $(TOCK_USERLAND_BASE_DIR)/AppMakefile.mk diff --git a/examples/tests/isolated_nonvolatile_storage/invs_single/README.md b/examples/tests/isolated_nonvolatile_storage/invs_single/README.md new file mode 100644 index 000000000..486b08a75 --- /dev/null +++ b/examples/tests/isolated_nonvolatile_storage/invs_single/README.md @@ -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 +``` \ No newline at end of file diff --git a/examples/tests/isolated_nonvolatile_storage/invs_single/main.c b/examples/tests/isolated_nonvolatile_storage/invs_single/main.c new file mode 100644 index 000000000..e49c2a6f7 --- /dev/null +++ b/examples/tests/isolated_nonvolatile_storage/invs_single/main.c @@ -0,0 +1,325 @@ +#include +#include +#include + +#include + + + +struct nv_data { + bool fired; + returncode_t ret; + 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) { + result.fired = true; + result.ret = ret; +} + +static void read_cb(returncode_t ret) { + result.fired = true; + result.ret = ret; +} + +static void write_done(int ret, + __attribute__ ((unused)) int arg1, + __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)); +} + +static void read_done(int ret, + __attribute__ ((unused)) int arg1, + __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)); +} + + +static uint64_t get_region_size(void) { + uint64_t num_bytes; + libtocksync_isolated_nonvolatile_storage_get_number_bytes(&num_bytes); + return num_bytes; +} + + + +static bool test_exists(void) { + bool exists = libtock_isolated_nonvolatile_storage_exists(); + + if (exists) { + return true; + } + return false; +} + +static bool test_size(void) { + uint64_t num_bytes; + returncode_t ret; + + ret = libtocksync_isolated_nonvolatile_storage_get_number_bytes(&num_bytes); + + if (ret == RETURNCODE_SUCCESS) { + if (num_bytes > 0) { + return true; + } + } + return false; +} + +static bool test_read(void) { + returncode_t ret; + + uint8_t readbuf[512]; + + uint32_t offset = 0; + uint32_t length = 10; + + ret = libtocksync_isolated_nonvolatile_storage_read(offset, readbuf, length); + if (ret == RETURNCODE_SUCCESS) { + return true; + } + return false; +} + +static bool test_read_zerobuffer(void) { + returncode_t ret; + + uint8_t readbuf[512]; + + uint32_t offset = 0; + + ret = libtocksync_isolated_nonvolatile_storage_read(offset, readbuf, 0); + if (ret == RETURNCODE_ERESERVE) { + return true; + } + return false; +} + +static bool test_read_fail_noallow(void) { + returncode_t ret; + + uint32_t offset = 0; + + result.fired = false; + + ret = libtock_isolated_nonvolatile_storage_set_upcall_read_done(read_done, read_cb); + if (ret != RETURNCODE_SUCCESS) return false; + + ret = libtock_isolated_nonvolatile_storage_set_allow_readwrite_read_buffer(NULL, 0); + if (ret != RETURNCODE_SUCCESS) return false; + + ret = libtock_isolated_nonvolatile_storage_command_read(offset); + if (ret != RETURNCODE_SUCCESS) return false; + + yield_for(&result.fired); + + if (result.ret == RETURNCODE_ERESERVE) { + return true; + } + return false; +} + +static bool test_read_fail_notwithinregion(void) { + returncode_t ret; + + uint8_t readbuf[512]; + + uint64_t offset; + size_t length; + + offset = get_region_size() - 5; + length = 10; + ret = libtocksync_isolated_nonvolatile_storage_read(offset, readbuf, length); + if (ret != RETURNCODE_EINVAL) return false; + + offset = get_region_size() + 10; + length = 10; + ret = libtocksync_isolated_nonvolatile_storage_read(offset, readbuf, length); + if (ret != RETURNCODE_EINVAL) return false; + + offset = 0; + length = get_region_size() + 1; + ret = libtocksync_isolated_nonvolatile_storage_read(offset, readbuf, length); + if (ret != RETURNCODE_EINVAL) return false; + + offset = get_region_size() - 1; + length = 2; + ret = libtocksync_isolated_nonvolatile_storage_read(offset, readbuf, length); + if (ret != RETURNCODE_EINVAL) return false; + + return true; +} + +static bool test_write(void) { + returncode_t ret; + + uint8_t writebuf[512] = {0x3f}; + + uint32_t offset = 0; + uint32_t length = 10; + + ret = libtocksync_isolated_nonvolatile_storage_write(offset, writebuf, length); + if (ret == RETURNCODE_SUCCESS) { + return true; + } + return false; +} + +static bool test_write_zerobuffer(void) { + returncode_t ret; + + uint8_t writebuf[512]; + + uint32_t offset = 0; + + ret = libtocksync_isolated_nonvolatile_storage_read(offset, writebuf, 0); + if (ret == RETURNCODE_ERESERVE) { + return true; + } + return false; +} + +static bool test_write_fail_noallow(void) { + returncode_t ret; + + uint32_t offset = 0; + + result.fired = false; + + ret = libtock_isolated_nonvolatile_storage_set_upcall_write_done(write_done, write_cb); + if (ret != RETURNCODE_SUCCESS) return false; + + ret = libtock_isolated_nonvolatile_storage_set_allow_readonly_write_buffer(NULL, 0); + if (ret != RETURNCODE_SUCCESS) return false; + + ret = libtock_isolated_nonvolatile_storage_command_write(offset); + if (ret != RETURNCODE_SUCCESS) return false; + + yield_for(&result.fired); + + if (result.ret == RETURNCODE_ERESERVE) { + return true; + } + return false; +} + +static bool test_write_fail_notwithinregion(void) { + returncode_t ret; + + uint8_t writebuf[512] = {0x99}; + + uint64_t offset; + size_t length; + + offset = get_region_size() - 5; + length = 10; + ret = libtocksync_isolated_nonvolatile_storage_read(offset, writebuf, length); + if (ret != RETURNCODE_EINVAL) return false; + + offset = get_region_size() + 10; + length = 10; + ret = libtocksync_isolated_nonvolatile_storage_read(offset, writebuf, length); + if (ret != RETURNCODE_EINVAL) return false; + + offset = 0; + length = get_region_size() + 1; + ret = libtocksync_isolated_nonvolatile_storage_read(offset, writebuf, length); + if (ret != RETURNCODE_EINVAL) return false; + + offset = get_region_size() - 1; + length = 2; + ret = libtocksync_isolated_nonvolatile_storage_read(offset, writebuf, length); + if (ret != RETURNCODE_EINVAL) return false; + + return true; +} + + + +int main(void) { + printf("[TEST] Isolated Nonvolatile Storage - Single\n"); + + printf("[INVS TEST] Exists: "); + if (test_exists()) { + printf("Success\n"); + } else { + printf("Fail\n"); + } + + printf("[INVS TEST] Size: "); + if (test_size()) { + printf("Success\n"); + } else { + printf("Fail\n"); + } + + printf("[INVS TEST] Read: "); + if (test_read()) { + printf("Success\n"); + } else { + printf("Fail\n"); + } + + printf("[INVS TEST] Read Zero Buffer: "); + if (test_read_zerobuffer()) { + printf("Success\n"); + } else { + printf("Fail\n"); + } + + printf("[INVS TEST] Read Fail No Allow: "); + if (test_read_fail_noallow()) { + printf("Success\n"); + } else { + printf("Fail\n"); + } + + printf("[INVS TEST] Read Fail Not Within Region: "); + if (test_read_fail_notwithinregion()) { + printf("Success\n"); + } else { + printf("Fail\n"); + } + + printf("[INVS TEST] Write: "); + if (test_write()) { + printf("Success\n"); + } else { + printf("Fail\n"); + } + + printf("[INVS TEST] Write Zero Buffer: "); + if (test_write_zerobuffer()) { + printf("Success\n"); + } else { + printf("Fail\n"); + } + + printf("[INVS TEST] Write Fail No Allow: "); + if (test_write_fail_noallow()) { + printf("Success\n"); + } else { + printf("Fail\n"); + } + + printf("[INVS TEST] Write Fail Not Within Region: "); + if (test_write_fail_notwithinregion()) { + printf("Success\n"); + } else { + printf("Fail\n"); + } + + return 0; +} diff --git a/libtock-sync/storage/isolated_nonvolatile_storage.c b/libtock-sync/storage/isolated_nonvolatile_storage.c new file mode 100644 index 000000000..87b3136be --- /dev/null +++ b/libtock-sync/storage/isolated_nonvolatile_storage.c @@ -0,0 +1,74 @@ +#include "isolated_nonvolatile_storage.h" +#include + +struct nv_data { + bool fired; + returncode_t ret; + uint64_t storage_size; +}; + +static struct nv_data result = {.fired = false}; + +static void get_number_bytes_cb(returncode_t ret, uint64_t number_bytes) { + result.fired = true; + result.ret = ret; + result.storage_size = number_bytes; +} + +static void write_cb(returncode_t ret) { + result.fired = true; + result.ret = ret; +} + +static void read_cb(returncode_t ret) { + result.fired = true; + result.ret = ret; +} + +returncode_t libtocksync_isolated_nonvolatile_storage_get_number_bytes(uint64_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(uint64_t offset, uint8_t* buffer, + uint32_t buffer_length) { + returncode_t ret; + result.fired = false; + + ret = libtock_isolated_nonvolatile_storage_write(offset, 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; + + return RETURNCODE_SUCCESS; +} + +returncode_t libtocksync_isolated_nonvolatile_storage_read(uint64_t offset, uint8_t* buffer, + uint32_t buffer_length) { + returncode_t ret; + result.fired = false; + + ret = libtock_isolated_nonvolatile_storage_read(offset, 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; + + return RETURNCODE_SUCCESS; +} diff --git a/libtock-sync/storage/isolated_nonvolatile_storage.h b/libtock-sync/storage/isolated_nonvolatile_storage.h new file mode 100644 index 000000000..d8589fac1 --- /dev/null +++ b/libtock-sync/storage/isolated_nonvolatile_storage.h @@ -0,0 +1,23 @@ +#pragma once + +#include +#include + +#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(uint64_t* number_bytes); + +// Write bytes from `buffer` to the nonvolatile storage starting at `offset`. +returncode_t libtocksync_isolated_nonvolatile_storage_write(uint64_t offset, uint8_t* buffer, + uint32_t buffer_length); + +// Read bytes into `buffer` from the nonvolatile storage starting at `offset`. +returncode_t libtocksync_isolated_nonvolatile_storage_read(uint64_t offset, uint8_t* buffer, + uint32_t buffer_length); + +#ifdef __cplusplus +} +#endif diff --git a/libtock/storage/isolated_nonvolatile_storage.c b/libtock/storage/isolated_nonvolatile_storage.c new file mode 100644 index 000000000..5b51a362c --- /dev/null +++ b/libtock/storage/isolated_nonvolatile_storage.c @@ -0,0 +1,69 @@ +#include "isolated_nonvolatile_storage.h" +#include "syscalls/isolated_nonvolatile_storage_syscalls.h" + +static void get_number_bytes_done(int ret, + int number_bytes_lo, + int number_bytes_hi, + void* opaque) { + libtock_isolated_nonvolatile_storage_callback_get_number_bytes cb = + (libtock_isolated_nonvolatile_storage_callback_get_number_bytes) opaque; + uint64_t num = (uint64_t) number_bytes_lo | ((uint64_t) number_bytes_hi) << 32; + + cb(tock_status_to_returncode(ret), num); +} + +static void write_done(int ret, + __attribute__ ((unused)) int arg1, + __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)); +} + +static void read_done(int ret, + __attribute__ ((unused)) int arg1, + __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)); +} + +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(uint64_t offset, uint8_t* buffer, + size_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); + return ret; +} + +returncode_t libtock_isolated_nonvolatile_storage_read(uint64_t offset, uint8_t* buffer, size_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); + return ret; +} diff --git a/libtock/storage/isolated_nonvolatile_storage.h b/libtock/storage/isolated_nonvolatile_storage.h new file mode 100644 index 000000000..dd5aa825e --- /dev/null +++ b/libtock/storage/isolated_nonvolatile_storage.h @@ -0,0 +1,44 @@ +#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` (`uint64_t`): Number of bytes available in storage. +typedef void (*libtock_isolated_nonvolatile_storage_callback_get_number_bytes)(returncode_t, uint64_t); + +// Function signature for nonvolatile storage write callbacks. +// +// - `arg1` (`returncode_t`): Status of write. +typedef void (*libtock_isolated_nonvolatile_storage_callback_write)(returncode_t); + +// Function signature for nonvolatile storage read callbacks. +// +// - `arg1` (`returncode_t`): Status of read. +typedef void (*libtock_isolated_nonvolatile_storage_callback_read)(returncode_t); + +// 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 bytes from `buffer` to the storage starting at `offset`. +returncode_t libtock_isolated_nonvolatile_storage_write(uint64_t offset, + uint8_t* buffer, + size_t buffer_length, + libtock_isolated_nonvolatile_storage_callback_write cb); + +// Read bytes into `buffer` from the storage starting at `offset`. +returncode_t libtock_isolated_nonvolatile_storage_read(uint64_t offset, + uint8_t* buffer, + size_t buffer_length, + libtock_isolated_nonvolatile_storage_callback_read cb); + +#ifdef __cplusplus +} +#endif diff --git a/libtock/storage/syscalls/isolated_nonvolatile_storage_syscalls.c b/libtock/storage/syscalls/isolated_nonvolatile_storage_syscalls.c new file mode 100644 index 000000000..2acd6189e --- /dev/null +++ b/libtock/storage/syscalls/isolated_nonvolatile_storage_syscalls.c @@ -0,0 +1,53 @@ +#include "isolated_nonvolatile_storage_syscalls.h" + +static uint32_t lo(uint64_t v) { + return (uint32_t) v; +} + +static uint32_t hi(uint64_t v) { + return (uint32_t) (v >> 32); +} + +bool libtock_isolated_nonvolatile_storage_exists(void) { + return driver_exists(DRIVER_NUM_ISOLATED_NONVOLATILE_STORAGE); +} + +returncode_t libtock_isolated_nonvolatile_storage_set_upcall_get_number_bytes_done(subscribe_upcall cb, void* opaque) { + subscribe_return_t sval = subscribe(DRIVER_NUM_ISOLATED_NONVOLATILE_STORAGE, 0, cb, opaque); + return tock_subscribe_return_to_returncode(sval); +} + +returncode_t libtock_isolated_nonvolatile_storage_set_upcall_read_done(subscribe_upcall cb, void* opaque) { + subscribe_return_t sval = subscribe(DRIVER_NUM_ISOLATED_NONVOLATILE_STORAGE, 1, cb, opaque); + return tock_subscribe_return_to_returncode(sval); +} + +returncode_t libtock_isolated_nonvolatile_storage_set_upcall_write_done(subscribe_upcall cb, void* opaque) { + subscribe_return_t sval = subscribe(DRIVER_NUM_ISOLATED_NONVOLATILE_STORAGE, 2, cb, opaque); + return tock_subscribe_return_to_returncode(sval); +} + +returncode_t libtock_isolated_nonvolatile_storage_set_allow_readwrite_read_buffer(uint8_t* buffer, size_t len) { + allow_rw_return_t aval = allow_readwrite(DRIVER_NUM_ISOLATED_NONVOLATILE_STORAGE, 0, (void*) buffer, len); + return tock_allow_rw_return_to_returncode(aval); +} + +returncode_t libtock_isolated_nonvolatile_storage_set_allow_readonly_write_buffer(uint8_t* buffer, size_t len) { + allow_ro_return_t aval = allow_readonly(DRIVER_NUM_ISOLATED_NONVOLATILE_STORAGE, 0, (void*) buffer, len); + return tock_allow_ro_return_to_returncode(aval); +} + +returncode_t libtock_isolated_nonvolatile_storage_command_get_number_bytes(void) { + syscall_return_t cval = command(DRIVER_NUM_ISOLATED_NONVOLATILE_STORAGE, 1, 0, 0); + return tock_command_return_novalue_to_returncode(cval); +} + +returncode_t libtock_isolated_nonvolatile_storage_command_read(uint64_t offset) { + syscall_return_t cval = command(DRIVER_NUM_ISOLATED_NONVOLATILE_STORAGE, 2, lo(offset), hi(offset)); + return tock_command_return_novalue_to_returncode(cval); +} + +returncode_t libtock_isolated_nonvolatile_storage_command_write(uint64_t offset) { + syscall_return_t cval = command(DRIVER_NUM_ISOLATED_NONVOLATILE_STORAGE, 3, lo(offset), hi(offset)); + return tock_command_return_novalue_to_returncode(cval); +} diff --git a/libtock/storage/syscalls/isolated_nonvolatile_storage_syscalls.h b/libtock/storage/syscalls/isolated_nonvolatile_storage_syscalls.h new file mode 100644 index 000000000..b306f9994 --- /dev/null +++ b/libtock/storage/syscalls/isolated_nonvolatile_storage_syscalls.h @@ -0,0 +1,31 @@ +#pragma once + +#include "../../tock.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define DRIVER_NUM_ISOLATED_NONVOLATILE_STORAGE 0x50004 + +bool libtock_isolated_nonvolatile_storage_exists(void); + +returncode_t libtock_isolated_nonvolatile_storage_set_upcall_get_number_bytes_done(subscribe_upcall cb, void* opaque); + +returncode_t libtock_isolated_nonvolatile_storage_set_upcall_read_done(subscribe_upcall cb, void* opaque); + +returncode_t libtock_isolated_nonvolatile_storage_set_upcall_write_done(subscribe_upcall cb, void* opaque); + +returncode_t libtock_isolated_nonvolatile_storage_set_allow_readwrite_read_buffer(uint8_t* buffer, size_t len); + +returncode_t libtock_isolated_nonvolatile_storage_set_allow_readonly_write_buffer(uint8_t* buffer, size_t len); + +returncode_t libtock_isolated_nonvolatile_storage_command_get_number_bytes(void); + +returncode_t libtock_isolated_nonvolatile_storage_command_read(uint64_t offset); + +returncode_t libtock_isolated_nonvolatile_storage_command_write(uint64_t offset); + +#ifdef __cplusplus +} +#endif