runtime: ensure flash storage never overlaps with runtime sections.

This commit is contained in:
whitequark 2017-12-26 02:48:36 +00:00
parent 6e341da3a1
commit e2513a2401
3 changed files with 50 additions and 34 deletions

View File

@ -3,10 +3,7 @@ mod imp {
use core::str; use core::str;
use std::btree_map::BTreeMap; use std::btree_map::BTreeMap;
use byteorder::{ByteOrder, BigEndian}; use byteorder::{ByteOrder, BigEndian};
use board::{mem, csr, cache, spiflash}; use board::{cache, spiflash};
const ADDR: usize = mem::FLASH_BOOT_ADDRESS + 0x80000 /* max runtime size */;
const SIZE: usize = csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize;
mod lock { mod lock {
use core::slice; use core::slice;
@ -26,7 +23,16 @@ mod imp {
} }
pub fn data(&self) -> &'static [u8] { pub fn data(&self) -> &'static [u8] {
unsafe { slice::from_raw_parts(super::ADDR as *const u8, super::SIZE) } extern {
static _fstorage: u8;
static _estorage: u8;
}
unsafe {
let begin = &_fstorage as *const u8;
let end = &_estorage as *const u8;
slice::from_raw_parts(begin, end as usize - begin as usize)
}
} }
} }
@ -62,12 +68,11 @@ mod imp {
} }
let record_size = BigEndian::read_u32(data) as usize; 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 */ { if record_size == !0 /* all ones; erased flash */ {
return None return None
} else if record_size < 4 || record_size > data.len() {
error!("offset {}: invalid record size", self.offset);
return Some(Err(()))
} }
let record_body = &data[4..record_size]; let record_body = &data[4..record_size];
@ -107,29 +112,28 @@ mod imp {
}) })
} }
fn append_at(mut offset: usize, key: &[u8], value: &[u8]) -> Result<usize, ()> { unsafe fn append_at<'a>(mut data: &'a [u8], key: &[u8], value: &[u8]) -> Result<&'a [u8], ()> {
let record_size = 4 + key.len() + 1 + value.len(); let record_size = 4 + key.len() + 1 + value.len();
if offset + record_size > SIZE { if data.len() < record_size {
return Err(()) return Err(())
} }
let mut record_size_bytes = [0u8; 4]; let mut record_size_bytes = [0u8; 4];
BigEndian::write_u32(&mut record_size_bytes[..], record_size as u32); BigEndian::write_u32(&mut record_size_bytes[..], record_size as u32);
spiflash::write(ADDR + offset, &record_size_bytes[..]); spiflash::write(data.as_ptr() as usize, &record_size_bytes[..]);
offset += record_size_bytes.len(); data = &data[record_size_bytes.len()..];
spiflash::write(ADDR + offset, key); spiflash::write(data.as_ptr() as usize, key);
offset += key.len(); data = &data[key.len()..];
spiflash::write(ADDR + offset, &[0]); spiflash::write(data.as_ptr() as usize, &[0]);
offset += 1; data = &data[1..];
spiflash::write(ADDR + offset, value); spiflash::write(data.as_ptr() as usize, value);
offset += value.len(); data = &data[value.len()..];
cache::flush_l2_cache(); Ok(data)
Ok(offset)
} }
fn compact() -> Result<(), ()> { fn compact() -> Result<(), ()> {
@ -144,28 +148,30 @@ mod imp {
} }
} }
spiflash::erase_sector(ADDR); let mut data = lock.data();
cache::flush_l2_cache(); spiflash::erase_sector(data.as_ptr() as usize);
let mut offset = 0;
for (key, value) in items { for (key, value) in items {
offset = append_at(offset, key, value)?; data = unsafe { append_at(data, key, value)? };
} }
cache::flush_l2_cache();
Ok(()) Ok(())
} }
fn append(key: &str, value: &[u8]) -> Result<(), ()> { fn append(key: &str, value: &[u8]) -> Result<(), ()> {
let lock = Lock::take()?; let lock = Lock::take()?;
let free_offset = { let free = {
let mut iter = Iter::new(lock.data()); let mut iter = Iter::new(lock.data());
while let Some(result) = iter.next() { while let Some(result) = iter.next() {
let _ = result?; let _ = result?;
} }
iter.offset &iter.data[iter.offset..]
}; };
append_at(free_offset, key.as_bytes(), value)?; unsafe { append_at(free, key.as_bytes(), value)? };
cache::flush_l2_cache();
Ok(()) Ok(())
} }
@ -185,9 +191,9 @@ mod imp {
} }
pub fn erase() -> Result<(), ()> { pub fn erase() -> Result<(), ()> {
let _lock = Lock::take()?; let lock = Lock::take()?;
spiflash::erase_sector(ADDR); spiflash::erase_sector(lock.data().as_ptr() as usize);
cache::flush_l2_cache(); cache::flush_l2_cache();
Ok(()) Ok(())

View File

@ -66,6 +66,15 @@ SECTIONS
_edata = .; _edata = .;
} > runtime } > runtime
.storage :
{
/* Keep in sync with artiq_flash.py */
_fstorage = .;
. = _ftext + 0x80000;
. += /*SPIFLASH_SECTOR_SIZE*/ 0x10000;
_estorage = .;
} > runtime
.bss : .bss :
{ {
. = ALIGN(4); . = ALIGN(4);

View File

@ -188,6 +188,7 @@ def main():
parser = get_argparser() parser = get_argparser()
opts = parser.parse_args() opts = parser.parse_args()
storage_at = 0x80000 # Keep in sync with runtime.ld
config = { config = {
"kc705": { "kc705": {
"programmer_factory": partial(ProgrammerJtagSpi7, "kc705"), "programmer_factory": partial(ProgrammerJtagSpi7, "kc705"),
@ -196,7 +197,7 @@ def main():
"gateware": (0, 0x000000), "gateware": (0, 0x000000),
"bios": (0, 0xaf0000), "bios": (0, 0xaf0000),
"runtime": (0, 0xb00000), "runtime": (0, 0xb00000),
"storage": (0, 0xb80000), "storage": (0, 0xb00000 + storage_at),
}, },
"sayma": { "sayma": {
"programmer_factory": ProgrammerSayma, "programmer_factory": ProgrammerSayma,
@ -205,7 +206,7 @@ def main():
"gateware": (0, 0x000000), "gateware": (0, 0x000000),
"bios": (1, 0x000000), "bios": (1, 0x000000),
"runtime": (1, 0x010000), "runtime": (1, 0x010000),
"storage": (1, 0x090000), "storage": (1, 0x010000 + storage_at),
}, },
}[opts.target] }[opts.target]