forked from M-Labs/artiq
runtime: ensure flash storage never overlaps with runtime sections.
This commit is contained in:
parent
6e341da3a1
commit
e2513a2401
|
@ -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(())
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -41,7 +41,7 @@ Prerequisites:
|
||||||
help="board variant")
|
help="board variant")
|
||||||
parser.add_argument("--preinit-command", default=[], action="append",
|
parser.add_argument("--preinit-command", default=[], action="append",
|
||||||
help="add a pre-initialization OpenOCD command. "
|
help="add a pre-initialization OpenOCD command. "
|
||||||
"Useful for selecting a development board "
|
"Useful for selecting a development board "
|
||||||
"when several are connected.")
|
"when several are connected.")
|
||||||
parser.add_argument("-f", "--storage", help="write file to storage area")
|
parser.add_argument("-f", "--storage", help="write file to storage area")
|
||||||
parser.add_argument("-d", "--dir", help="look for files in this directory")
|
parser.add_argument("-d", "--dir", help="look for files in this directory")
|
||||||
|
@ -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]
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue