From 3b54736c02533156a8adfbd7934d848f37fbe120 Mon Sep 17 00:00:00 2001 From: whitequark Date: Thu, 2 Feb 2017 02:51:13 +0000 Subject: [PATCH] firmware: port flash storage management to Rust. --- artiq/firmware/libboard/lib.rs | 3 + artiq/firmware/libboard/spiflash.rs | 123 +++++++++++ artiq/firmware/runtime/config.rs | 220 +++++++++++++++----- artiq/firmware/runtime/lib.rs | 10 +- artiq/firmware/runtime/rtio_mgt.rs | 33 +-- artiq/firmware/runtime/session.rs | 33 +-- artiq/runtime/Makefile | 2 +- artiq/runtime/flash_storage.c | 308 ---------------------------- artiq/runtime/flash_storage.h | 13 -- 9 files changed, 342 insertions(+), 403 deletions(-) create mode 100644 artiq/firmware/libboard/spiflash.rs delete mode 100644 artiq/runtime/flash_storage.c delete mode 100644 artiq/runtime/flash_storage.h diff --git a/artiq/firmware/libboard/lib.rs b/artiq/firmware/libboard/lib.rs index ee3406b72..84a745936 100644 --- a/artiq/firmware/libboard/lib.rs +++ b/artiq/firmware/libboard/lib.rs @@ -16,6 +16,9 @@ pub mod uart; #[cfg(feature = "uart_console")] pub mod uart_console; +#[cfg(has_spiflash)] +pub mod spiflash; + #[cfg(has_i2c)] pub mod i2c; #[cfg(has_i2c)] diff --git a/artiq/firmware/libboard/spiflash.rs b/artiq/firmware/libboard/spiflash.rs new file mode 100644 index 000000000..26c5cbbc6 --- /dev/null +++ b/artiq/firmware/libboard/spiflash.rs @@ -0,0 +1,123 @@ +#![allow(dead_code)] + +use core::cmp; +use csr; + +const CMD_PP: u8 = 0x02; +const CMD_WRDI: u8 = 0x04; +const CMD_RDSR: u8 = 0x05; +const CMD_WREN: u8 = 0x06; +const CMD_SE: u8 = 0xd8; + +const PIN_CLK: u8 = 1 << 1; +const PIN_CS_N: u8 = 1 << 2; +const PIN_DQ_I: u8 = 1 << 3; + +const SR_WIP: u8 = 1; + +fn write_byte(mut byte: u8) { + unsafe { + csr::spiflash::bitbang_write(0); + for _ in 0..8 { + csr::spiflash::bitbang_write((byte & 0x80) >> 7); + csr::spiflash::bitbang_write((byte & 0x80) >> 7 | PIN_CLK); + byte <<= 1; + } + csr::spiflash::bitbang_write(0); + } +} + +fn write_addr(mut addr: usize) { + unsafe { + csr::spiflash::bitbang_write(0); + for _ in 0..24 { + csr::spiflash::bitbang_write(((addr & 0x800000) >> 23) as u8); + csr::spiflash::bitbang_write(((addr & 0x800000) >> 23) as u8 | PIN_CLK); + addr <<= 1; + } + csr::spiflash::bitbang_write(0); + } +} + +fn wait_until_ready() { + unsafe { + loop { + let mut sr = 0; + write_byte(CMD_RDSR); + for _ in 0..8 { + sr <<= 1; + csr::spiflash::bitbang_write(PIN_DQ_I | PIN_CLK); + sr |= csr::spiflash::miso_read(); + csr::spiflash::bitbang_write(PIN_DQ_I); + } + csr::spiflash::bitbang_write(0); + csr::spiflash::bitbang_write(PIN_CS_N); + if sr & SR_WIP == 0 { + return + } + } + } +} + +pub fn erase_sector(addr: usize) { + unsafe { + let sector_addr = addr & !(csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize - 1); + + csr::spiflash::bitbang_en_write(1); + + wait_until_ready(); + + write_byte(CMD_WREN); + csr::spiflash::bitbang_write(PIN_CS_N); + + write_byte(CMD_SE); + write_addr(sector_addr); + csr::spiflash::bitbang_write(PIN_CS_N); + + wait_until_ready(); + + csr::spiflash::bitbang_en_write(0); + } +} + +fn write_page(addr: usize, data: &[u8]) { + unsafe { + csr::spiflash::bitbang_en_write(1); + + wait_until_ready(); + + write_byte(CMD_WREN); + csr::spiflash::bitbang_write(PIN_CS_N); + write_byte(CMD_PP); + write_addr(addr); + for &byte in data { + write_byte(byte) + } + + csr::spiflash::bitbang_write(PIN_CS_N); + csr::spiflash::bitbang_write(0); + + wait_until_ready(); + + csr::spiflash::bitbang_en_write(0); + } +} + +const PAGE_SIZE: usize = csr::CONFIG_SPIFLASH_PAGE_SIZE as usize; +const PAGE_MASK: usize = PAGE_SIZE - 1; + +pub fn write(mut addr: usize, mut data: &[u8]) { + if addr & PAGE_MASK != 0 { + let size = cmp::min((PAGE_SIZE - (addr & PAGE_MASK)) as usize, data.len()); + write_page(addr, &data[..size]); + addr += size; + data = &data[size..]; + } + + while data.len() > 0 { + let size = cmp::min(PAGE_SIZE as usize, data.len()); + write_page(addr, &data[..size]); + addr += size; + data = &data[size..]; + } +} diff --git a/artiq/firmware/runtime/config.rs b/artiq/firmware/runtime/config.rs index 7e67ac6cc..d8304f8b9 100644 --- a/artiq/firmware/runtime/config.rs +++ b/artiq/firmware/runtime/config.rs @@ -1,68 +1,192 @@ -use std::cmp; -use std::vec::Vec; -use std::string::String; -use libc::{c_void, c_char, c_int, c_uint}; +use core::str; +use std::btree_map::BTreeMap; +use byteorder::{ByteOrder, BigEndian}; +use board::{mem, csr, cache, spiflash}; -extern { - fn fs_remove(key: *const c_char); - fn fs_erase(); - fn fs_write(key: *const c_char, buffer: *const c_void, buflen: c_uint) -> c_int; - fn fs_read(key: *const c_char, buffer: *mut c_void, buflen: c_uint, - remain: *mut c_uint) -> c_uint; -} +const ADDR: usize = mem::FLASH_BOOT_ADDRESS + 0x80000 /* max runtime size */; +const SIZE: usize = csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize; -macro_rules! c_str { - ($s:ident) => { - { - let mut c = [0; 64 + 1]; - let len = cmp::min($s.len(), c.len() - 1); - c[..len].copy_from_slice($s.as_bytes()); - c +mod lock { + use core::slice; + use core::sync::atomic::{AtomicUsize, Ordering}; + + static LOCKED: AtomicUsize = AtomicUsize::new(0); + + pub struct Lock; + + impl Lock { + pub fn take() -> Result { + if LOCKED.swap(1, Ordering::SeqCst) != 0 { + Err(()) // already locked + } else { + Ok(Lock) // locked now + } + } + + pub fn data(&self) -> &'static [u8] { + unsafe { slice::from_raw_parts(super::ADDR as *const u8, super::SIZE) } + } + } + + impl Drop for Lock { + fn drop(&mut self) { + LOCKED.store(0, Ordering::SeqCst) } } } -pub fn read(key: &str, buf: &mut [u8]) -> Result { - let key_c = c_str!(key); - let mut remain: c_uint = 0; - let result = unsafe { - fs_read(key_c.as_ptr() as *const c_char, - buf.as_mut_ptr() as *mut c_void, buf.len() as c_uint, &mut remain) - }; - if remain == 0 { Ok(result as usize) } else { Err(remain as usize) } +pub use self::lock::Lock; + +struct Iter<'a> { + data: &'a [u8], + offset: usize } -pub fn read_to_end(key: &str) -> Vec { - let mut value = Vec::new(); - match read(key, &mut []) { - Ok(0) => (), - Ok(_) => unreachable!(), - Err(size) => { - value.resize(size, 0); - read(key, &mut value).unwrap(); +impl<'a> Iter<'a> { + fn new(data: &'a [u8]) -> Iter<'a> { + Iter { data: data, offset: 0 } + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = Result<(&'a [u8], &'a [u8]), ()>; + + fn next(&mut self) -> Option { + let data = &self.data[self.offset..]; + + if data.len() < 4 { + error!("offset {}: truncated record", self.offset); + return Some(Err(())) + } + + let record_size = BigEndian::read_u32(data) as usize; + if record_size < 4 { + error!("offset {}: invalid record size", self.offset); + return Some(Err(())) + } + if record_size == !0 /* all ones; erased flash */ { + return None + } + + let record_body = &data[4..record_size]; + match record_body.iter().position(|&x| x == 0) { + None => { + error!("offset {}: missing separator", self.offset); + Some(Err(())) + } + Some(pos) => { + self.offset += record_size; + + let (key, zero_and_value) = record_body.split_at(pos); + Some(Ok((key, &zero_and_value[1..]))) + } } } - value } -pub fn read_string(key: &str) -> String { - String::from_utf8(read_to_end(key)).unwrap() +pub fn read) -> R, R>(key: &str, f: F) -> R { + f(Lock::take().and_then(|lock| { + let mut iter = Iter::new(lock.data()); + let mut value = &[][..]; + while let Some(result) = iter.next() { + let (record_key, record_value) = result?; + if key.as_bytes() == record_key { + // last write wins + value = record_value + } + } + Ok(value) + })) } -pub fn write(key: &str, buf: &[u8]) -> Result<(), ()> { - let key_c = c_str!(key); - let result = unsafe { - fs_write(key_c.as_ptr() as *const c_char, - buf.as_ptr() as *mut c_void, buf.len() as c_uint) +pub fn read_str) -> R, R>(key: &str, f: F) -> R { + read(key, |result| { + f(result.and_then(|value| str::from_utf8(value).map_err(|_| ()))) + }) +} + +fn append_at(mut offset: usize, key: &[u8], value: &[u8]) -> Result { + let record_size = 4 + key.len() + 1 + value.len(); + if offset + record_size > SIZE { + return Err(()) + } + + let mut record_size_bytes = [0u8; 4]; + BigEndian::write_u32(&mut record_size_bytes[..], record_size as u32); + + spiflash::write(ADDR + offset, &record_size_bytes[..]); + offset += record_size_bytes.len(); + + spiflash::write(ADDR + offset, key); + offset += key.len(); + + spiflash::write(ADDR + offset, &[0]); + offset += 1; + + spiflash::write(ADDR + offset, value); + offset += value.len(); + + cache::flush_l2_cache(); + Ok(offset) +} + +fn compact() -> Result<(), ()> { + let lock = Lock::take()?; + + let mut items = BTreeMap::new(); + { + let mut iter = Iter::new(lock.data()); + while let Some(result) = iter.next() { + let (key, value) = result?; + items.insert(key, value); + } + } + + spiflash::erase_sector(ADDR); + cache::flush_l2_cache(); + + let mut offset = 0; + for (key, value) in items { + offset = append_at(offset, key, value)?; + } + Ok(()) +} + +fn append(key: &str, value: &[u8]) -> Result<(), ()> { + let lock = Lock::take()?; + + let free_offset = { + let mut iter = Iter::new(lock.data()); + while let Some(result) = iter.next() { + let _ = result?; + } + iter.offset }; - if result == 1 { Ok(()) } else { Err(()) } + + append_at(free_offset, key.as_bytes(), value)?; + Ok(()) } -pub fn remove(key: &str) { - let key_c = c_str!(key); - unsafe { fs_remove(key_c.as_ptr() as *const c_char) } +pub fn write(key: &str, value: &[u8]) -> Result<(), ()> { + match append(key, value) { + Ok(()) => (), + Err(()) => { + compact()?; + append(key, value)?; + } + } + Ok(()) } -pub fn erase() { - unsafe { fs_erase() } +pub fn remove(key: &str) -> Result<(), ()> { + write(key, &[]) +} + +pub fn erase() -> Result<(), ()> { + let _lock = Lock::take()?; + + spiflash::erase_sector(ADDR); + cache::flush_l2_cache(); + + Ok(()) } diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index bee69d4dc..8c6c371f7 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -1,5 +1,5 @@ #![no_std] -#![feature(libc, repr_simd)] +#![feature(libc, repr_simd, const_fn)] extern crate alloc_artiq; #[macro_use] @@ -67,8 +67,8 @@ fn startup() { info!("press 'e' to erase startup and idle kernels..."); while board::clock::get_ms() < t + 1000 { if unsafe { readchar_nonblock() != 0 && readchar() == b'e' as libc::c_char } { - config::remove("startup_kernel"); - config::remove("idle_kernel"); + config::remove("startup_kernel").unwrap(); + config::remove("idle_kernel").unwrap(); info!("startup and idle kernels erased"); break } @@ -83,7 +83,7 @@ fn startup() { board::ad9154::init().expect("cannot initialize ad9154"); let hardware_addr; - match EthernetAddress::parse(&config::read_string("mac")) { + match config::read_str("mac", |r| r.and_then(|s| EthernetAddress::parse(s))) { Err(()) => { hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x01]); warn!("using default MAC address {}; consider changing it", hardware_addr); @@ -95,7 +95,7 @@ fn startup() { } let protocol_addr; - match IpAddress::parse(&config::read_string("ip")) { + match config::read_str("ip", |r| r.and_then(|s| IpAddress::parse(s))) { Err(()) | Ok(IpAddress::Unspecified) => { protocol_addr = IpAddress::v4(192, 168, 1, 50); info!("using default IP address {}", protocol_addr); diff --git a/artiq/firmware/runtime/rtio_mgt.rs b/artiq/firmware/runtime/rtio_mgt.rs index 5b5c0d8e2..fb821612a 100644 --- a/artiq/firmware/runtime/rtio_mgt.rs +++ b/artiq/firmware/runtime/rtio_mgt.rs @@ -154,24 +154,25 @@ mod drtio { pub fn startup(io: &Io) { crg::init(); - let mut opt = [b'i']; - let clk; - match config::read("startup_clock", &mut opt) { - Ok(0) | Ok(1) if &opt == b"i" => { - info!("startup RTIO clock: internal"); - clk = 0 - } - Ok(1) if &opt == b"e" => { - info!("startup RTIO clock: external"); - clk = 1 - } - _ => { - error!("unrecognized startup_clock configuration entry"); - clk = 0 - } + #[derive(Debug)] + enum RtioClock { + Internal = 0, + External = 1 }; - if !crg::switch_clock(clk) { + let clk = config::read("startup_clock", |result| { + match result { + Ok(b"i") => RtioClock::Internal, + Ok(b"e") => RtioClock::External, + _ => { + error!("unrecognized startup_clock configuration entry"); + RtioClock::Internal + } + } + }); + + info!("startup RTIO clock: {:?}", clk); + if !crg::switch_clock(clk as u8) { error!("startup RTIO clock failed"); warn!("this may cause the system initialization to fail"); warn!("fix clocking and reset the device"); diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 7128ffe77..682dbae1c 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -233,8 +233,12 @@ fn process_host_message(io: &Io, // artiq_coreconfig host::Request::FlashRead { ref key } => { - let value = config::read_to_end(key); - host_write(stream, host::Reply::FlashRead(&value)) + config::read(key, |result| { + match result { + Ok(value) => host_write(stream, host::Reply::FlashRead(&value)), + Err(()) => host_write(stream, host::Reply::FlashError) + } + }) } host::Request::FlashWrite { ref key, ref value } => { @@ -245,13 +249,18 @@ fn process_host_message(io: &Io, } host::Request::FlashRemove { ref key } => { - config::remove(key); - host_write(stream, host::Reply::FlashOk) + match config::remove(key) { + Ok(()) => host_write(stream, host::Reply::FlashOk), + Err(_) => host_write(stream, host::Reply::FlashError), + } + } host::Request::FlashErase => { - config::erase(); - host_write(stream, host::Reply::FlashOk) + match config::erase() { + Ok(()) => host_write(stream, host::Reply::FlashOk), + Err(_) => host_write(stream, host::Reply::FlashError), + } } // artiq_run/artiq_master @@ -599,12 +608,12 @@ fn flash_kernel_worker(io: &Io, config_key: &str) -> io::Result<()> { let mut session = Session::new(congress); - let kernel = config::read_to_end(config_key); - if kernel.len() == 0 { - return Err(io::Error::new(io::ErrorKind::NotFound, "kernel not found")) - } - - unsafe { kern_load(io, &mut session, &kernel)? }; + config::read(config_key, |result| { + match result { + Ok(kernel) if kernel.len() > 0 => unsafe { kern_load(io, &mut session, &kernel) }, + _ => Err(io::Error::new(io::ErrorKind::NotFound, "kernel not found")), + } + })?; kern_run(&mut session)?; loop { diff --git a/artiq/runtime/Makefile b/artiq/runtime/Makefile index 6e2301cc2..43ee5f437 100644 --- a/artiq/runtime/Makefile +++ b/artiq/runtime/Makefile @@ -39,7 +39,7 @@ $(RUSTOUT)/libruntime.a: cargo build --target=or1k-unknown-none \ --manifest-path $(realpath $(RUNTIME_DIRECTORY)/../firmware/runtime/Cargo.toml) -runtime.elf: $(RUSTOUT)/libruntime.a flash_storage.o ksupport_data.o +runtime.elf: $(RUSTOUT)/libruntime.a ksupport_data.o $(LD) $(LDFLAGS) \ -T $(RUNTIME_DIRECTORY)/runtime.ld \ -o $@ \ diff --git a/artiq/runtime/flash_storage.c b/artiq/runtime/flash_storage.c deleted file mode 100644 index 3e18151d6..000000000 --- a/artiq/runtime/flash_storage.c +++ /dev/null @@ -1,308 +0,0 @@ -/* - * Yann Sionneau , 2015 - */ - -#include -#include -#include -#include -#include -#include - -#include "flash_storage.h" - -#if (defined CSR_SPIFLASH_BASE && defined CONFIG_SPIFLASH_PAGE_SIZE) - -#define STORAGE_ADDRESS ((char *)(FLASH_BOOT_ADDRESS + 0x80000 /* max runtime size */)) -#define STORAGE_SIZE CONFIG_SPIFLASH_SECTOR_SIZE -#define END_MARKER (0xFFFFFFFF) - -#define min(a, b) (a>b?b:a) -#define max(a, b) (a>b?a:b) - -struct record { - char *key; - unsigned int key_len; - char *value; - unsigned int value_len; - char *raw_record; - unsigned int size; -}; - -struct iter_state { - char *buffer; - unsigned int seek; - unsigned int buf_len; -}; - -static unsigned int get_record_size(char *buff) -{ - unsigned int record_size; - - memcpy(&record_size, buff, 4); - return record_size; -} - -static void record_iter_init(struct iter_state *is, char *buffer, unsigned int buf_len) -{ - is->buffer = buffer; - is->seek = 0; - is->buf_len = buf_len; -} - -static int record_iter_next(struct iter_state *is, struct record *record, int *fatal) -{ - if(is->seek >= is->buf_len) - return 0; - - record->raw_record = &is->buffer[is->seek]; - record->size = get_record_size(record->raw_record); - - if(record->size == END_MARKER) - return 0; - - if(record->size < 6) { - // core_log("flash_storage might be corrupted: record size is %u (<6) at address %08x\n", - // record->size, record->raw_record); - if(fatal) - *fatal = 1; - return 0; - } - - if(is->seek > is->buf_len - sizeof(record->size) - 2) { /* 2 is the minimum key length */ - // core_log("flash_storage might be corrupted: END_MARKER missing at the end of " - // "the storage sector\n"); - if(fatal) - *fatal = 1; - return 0; - } - - if(record->size > is->buf_len - is->seek) { - // core_log("flash_storage might be corrupted: invalid record_size %d at address %08x\n", - // record->size, record->raw_record); - if(fatal) - *fatal = 1; - return 0; - } - - record->key = record->raw_record + sizeof(record->size); - record->key_len = strnlen(record->key, record->size - sizeof(record->size)) + 1; - - if(record->key_len == record->size - sizeof(record->size) + 1) { - // core_log("flash_storage might be corrupted: invalid key length at address %08x\n", - // record->raw_record); - if(fatal) - *fatal = 1; - return 0; - } - - record->value = record->key + record->key_len; - record->value_len = record->size - record->key_len - sizeof(record->size); - - is->seek += record->size; - return 1; -} - -static unsigned int get_free_space(void) -{ - struct iter_state is; - struct record record; - - record_iter_init(&is, STORAGE_ADDRESS, STORAGE_SIZE); - while(record_iter_next(&is, &record, NULL)); - return STORAGE_SIZE - is.seek; -} - -static int is_empty(struct record *record) -{ - return record->value_len == 0; -} - -static int key_exists(char *buff, const char *key, char *end, char accept_empty, - struct record *found_record) -{ - struct iter_state is; - struct record iter_record; - int found = 0; - - record_iter_init(&is, buff, end - buff); - while(record_iter_next(&is, &iter_record, NULL)) { - if(strcmp(iter_record.key, key) == 0) { - found = 1; - if(found_record) - *found_record = iter_record; - } - } - - if(found && is_empty(found_record) && !accept_empty) - return 0; - - if(found) - return 1; - - return 0; -} - -static char check_for_duplicates(char *buff) -{ - struct record record, following_record; - struct iter_state is; - int no_error; - - record_iter_init(&is, buff, STORAGE_SIZE); - no_error = record_iter_next(&is, &record, NULL); - while(no_error) { - no_error = record_iter_next(&is, &following_record, NULL); - if(no_error && key_exists(following_record.raw_record, record.key, &buff[STORAGE_SIZE], 1, NULL)) - return 1; - record = following_record; - } - - return 0; -} - -static char check_for_empty_records(char *buff) -{ - struct iter_state is; - struct record record; - - record_iter_init(&is, buff, STORAGE_SIZE); - while(record_iter_next(&is, &record, NULL)) - if(is_empty(&record)) - return 1; - - return 0; -} - -static unsigned int try_to_flush_duplicates(const char *new_key, unsigned int buf_len) -{ - unsigned int key_size, new_record_size, ret = 0, can_rollback = 0; - struct record record, previous_record; - char sector_buff[STORAGE_SIZE]; - struct iter_state is; - - memcpy(sector_buff, STORAGE_ADDRESS, STORAGE_SIZE); - if(check_for_duplicates(sector_buff) - || key_exists(sector_buff, new_key, §or_buff[STORAGE_SIZE], 0, NULL) - || check_for_empty_records(sector_buff)) { - fs_erase(); - record_iter_init(&is, sector_buff, STORAGE_SIZE); - while(record_iter_next(&is, &record, NULL)) { - if(is_empty(&record)) - continue; - if(!key_exists((char *)STORAGE_ADDRESS, record.key, STORAGE_ADDRESS + STORAGE_SIZE, 1, NULL)) { - struct record rec; - - if(!key_exists(sector_buff, record.key, §or_buff[STORAGE_SIZE], 0, &rec)) - continue; - if(strcmp(new_key, record.key) == 0) { // If we are about to write this key we don't keep the old value. - previous_record = rec; // This holds the old record in case we need it back (for instance if new record is too long) - can_rollback = 1; - } else - fs_write(record.key, rec.value, rec.value_len); - } - } - ret = 1; - } - - key_size = strlen(new_key) + 1; - new_record_size = key_size + buf_len + sizeof(new_record_size); - if(can_rollback && new_record_size > get_free_space()) { - fs_write(new_key, previous_record.value, previous_record.value_len); - } - - return ret; -} - -static void write_at_offset(const char *key, const void *buffer, - int buf_len, unsigned int sector_offset) -{ - int key_len = strlen(key) + 1; - unsigned int record_size = key_len + buf_len + sizeof(record_size); - unsigned int flash_addr = (unsigned int)STORAGE_ADDRESS + sector_offset; - - write_to_flash(flash_addr, (unsigned char *)&record_size, sizeof(record_size)); - write_to_flash(flash_addr+sizeof(record_size), (unsigned char *)key, key_len); - write_to_flash(flash_addr+sizeof(record_size)+key_len, buffer, buf_len); - flush_cpu_dcache(); -} - - -int fs_write(const char *key, const void *buffer, unsigned int buf_len) -{ - struct record record; - unsigned int key_size = strlen(key) + 1; - unsigned int new_record_size = key_size + sizeof(int) + buf_len; - int no_error, fatal = 0; - struct iter_state is; - - record_iter_init(&is, STORAGE_ADDRESS, STORAGE_SIZE); - while((no_error = record_iter_next(&is, &record, &fatal))); - - if(fatal) - goto fatal_error; - - if(STORAGE_SIZE - is.seek >= new_record_size) { - write_at_offset(key, buffer, buf_len, is.seek); - return 1; - } - - if(!try_to_flush_duplicates(key, buf_len)) // storage is full, let's try to free some space up. - return 0; // No duplicates found, cannot write the new key-value record: sector is full. - // Now retrying to write, hoping enough flash was freed. - - record_iter_init(&is, STORAGE_ADDRESS, STORAGE_SIZE); - while((no_error = record_iter_next(&is, &record, &fatal))); - - if(fatal) - goto fatal_error; - - if(STORAGE_SIZE - is.seek >= new_record_size) { - write_at_offset(key, buffer, buf_len, is.seek); - return 1; // We eventually succeeded in writing the record - } else - return 0; // Storage is definitely full. - -fatal_error: - // core_log("fatal error: flash storage might be corrupted\n"); - return 0; -} - -void fs_erase(void) -{ - erase_flash_sector((unsigned int)STORAGE_ADDRESS); - flush_cpu_dcache(); -} - -unsigned int fs_read(const char *key, void *buffer, unsigned int buf_len, unsigned int *remain) -{ - unsigned int read_length = 0; - struct iter_state is; - struct record record; - int fatal = 0; - - if(remain) - *remain = 0; - - record_iter_init(&is, STORAGE_ADDRESS, STORAGE_SIZE); - while(record_iter_next(&is, &record, &fatal)) { - if(strcmp(record.key, key) == 0) { - memcpy(buffer, record.value, min(record.value_len, buf_len)); - read_length = min(record.value_len, buf_len); - if(remain) - *remain = max(0, (int)record.value_len - (int)buf_len); - } - } - - // if(fatal) - // core_log("fatal error: flash storage might be corrupted\n"); - - return read_length; -} - -void fs_remove(const char *key) -{ - fs_write(key, NULL, 0); -} - -#endif /* CSR_SPIFLASH_BASE && CONFIG_SPIFLASH_PAGE_SIZE */ diff --git a/artiq/runtime/flash_storage.h b/artiq/runtime/flash_storage.h deleted file mode 100644 index e983de778..000000000 --- a/artiq/runtime/flash_storage.h +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Yann Sionneau , 2015 - */ - -#ifndef __FLASH_STORAGE_H -#define __FLASH_STORAGE_H - -void fs_remove(const char *key); -void fs_erase(void); -int fs_write(const char *key, const void *buffer, unsigned int buflen); -unsigned int fs_read(const char *key, void *buffer, unsigned int buflen, unsigned int *remain); - -#endif /* __FLASH_STORAGE_H */