From e2513a24016dd4eb7814e952206120fbfe9b1abb Mon Sep 17 00:00:00 2001 From: whitequark Date: Tue, 26 Dec 2017 02:48:36 +0000 Subject: [PATCH] runtime: ensure flash storage never overlaps with runtime sections. --- artiq/firmware/runtime/config.rs | 68 +++++++++++++++++-------------- artiq/firmware/runtime/runtime.ld | 9 ++++ artiq/frontend/artiq_flash.py | 7 ++-- 3 files changed, 50 insertions(+), 34 deletions(-) diff --git a/artiq/firmware/runtime/config.rs b/artiq/firmware/runtime/config.rs index 4a1407a08..cc0d2ab14 100644 --- a/artiq/firmware/runtime/config.rs +++ b/artiq/firmware/runtime/config.rs @@ -3,10 +3,7 @@ mod imp { use core::str; use std::btree_map::BTreeMap; use byteorder::{ByteOrder, BigEndian}; - use board::{mem, csr, cache, spiflash}; - - const ADDR: usize = mem::FLASH_BOOT_ADDRESS + 0x80000 /* max runtime size */; - const SIZE: usize = csr::CONFIG_SPIFLASH_SECTOR_SIZE as usize; + use board::{cache, spiflash}; mod lock { use core::slice; @@ -26,7 +23,16 @@ mod imp { } 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; - if record_size < 4 { - error!("offset {}: invalid record size", self.offset); - return Some(Err(())) - } if record_size == !0 /* all ones; erased flash */ { 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]; @@ -107,29 +112,28 @@ mod imp { }) } - fn append_at(mut offset: usize, key: &[u8], value: &[u8]) -> Result { + 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(); - if offset + record_size > SIZE { + if data.len() < record_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(data.as_ptr() as usize, &record_size_bytes[..]); + data = &data[record_size_bytes.len()..]; - spiflash::write(ADDR + offset, key); - offset += key.len(); + spiflash::write(data.as_ptr() as usize, key); + data = &data[key.len()..]; - spiflash::write(ADDR + offset, &[0]); - offset += 1; + spiflash::write(data.as_ptr() as usize, &[0]); + data = &data[1..]; - spiflash::write(ADDR + offset, value); - offset += value.len(); + spiflash::write(data.as_ptr() as usize, value); + data = &data[value.len()..]; - cache::flush_l2_cache(); - Ok(offset) + Ok(data) } fn compact() -> Result<(), ()> { @@ -144,28 +148,30 @@ mod imp { } } - spiflash::erase_sector(ADDR); - cache::flush_l2_cache(); - - let mut offset = 0; + let mut data = lock.data(); + spiflash::erase_sector(data.as_ptr() as usize); for (key, value) in items { - offset = append_at(offset, key, value)?; + data = unsafe { append_at(data, key, value)? }; } + + cache::flush_l2_cache(); Ok(()) } fn append(key: &str, value: &[u8]) -> Result<(), ()> { let lock = Lock::take()?; - let free_offset = { + let free = { let mut iter = Iter::new(lock.data()); while let Some(result) = iter.next() { 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(()) } @@ -185,9 +191,9 @@ mod imp { } 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(); Ok(()) diff --git a/artiq/firmware/runtime/runtime.ld b/artiq/firmware/runtime/runtime.ld index 1d21c61fb..54a964836 100644 --- a/artiq/firmware/runtime/runtime.ld +++ b/artiq/firmware/runtime/runtime.ld @@ -66,6 +66,15 @@ SECTIONS _edata = .; } > runtime + .storage : + { + /* Keep in sync with artiq_flash.py */ + _fstorage = .; + . = _ftext + 0x80000; + . += /*SPIFLASH_SECTOR_SIZE*/ 0x10000; + _estorage = .; + } > runtime + .bss : { . = ALIGN(4); diff --git a/artiq/frontend/artiq_flash.py b/artiq/frontend/artiq_flash.py index db1a98f31..beb408e0c 100755 --- a/artiq/frontend/artiq_flash.py +++ b/artiq/frontend/artiq_flash.py @@ -41,7 +41,7 @@ Prerequisites: help="board variant") parser.add_argument("--preinit-command", default=[], action="append", help="add a pre-initialization OpenOCD command. " - "Useful for selecting a development board " + "Useful for selecting a development board " "when several are connected.") parser.add_argument("-f", "--storage", help="write file to storage area") parser.add_argument("-d", "--dir", help="look for files in this directory") @@ -188,6 +188,7 @@ def main(): parser = get_argparser() opts = parser.parse_args() + storage_at = 0x80000 # Keep in sync with runtime.ld config = { "kc705": { "programmer_factory": partial(ProgrammerJtagSpi7, "kc705"), @@ -196,7 +197,7 @@ def main(): "gateware": (0, 0x000000), "bios": (0, 0xaf0000), "runtime": (0, 0xb00000), - "storage": (0, 0xb80000), + "storage": (0, 0xb00000 + storage_at), }, "sayma": { "programmer_factory": ProgrammerSayma, @@ -205,7 +206,7 @@ def main(): "gateware": (0, 0x000000), "bios": (1, 0x000000), "runtime": (1, 0x010000), - "storage": (1, 0x090000), + "storage": (1, 0x010000 + storage_at), }, }[opts.target]