forked from M-Labs/artiq
coremgmt: implement flash
This commit is contained in:
parent
cd6e5ff378
commit
a1e392fb0e
|
@ -1,5 +1,7 @@
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
import binascii
|
||||||
import logging
|
import logging
|
||||||
|
import io
|
||||||
import struct
|
import struct
|
||||||
|
|
||||||
from sipyco.keepalive import create_connection
|
from sipyco.keepalive import create_connection
|
||||||
|
@ -23,6 +25,8 @@ class Request(Enum):
|
||||||
|
|
||||||
DebugAllocator = 8
|
DebugAllocator = 8
|
||||||
|
|
||||||
|
Flash = 9
|
||||||
|
|
||||||
|
|
||||||
class Reply(Enum):
|
class Reply(Enum):
|
||||||
Success = 1
|
Success = 1
|
||||||
|
@ -196,3 +200,45 @@ class CommMgmt:
|
||||||
|
|
||||||
def debug_allocator(self):
|
def debug_allocator(self):
|
||||||
self._write_header(Request.DebugAllocator)
|
self._write_header(Request.DebugAllocator)
|
||||||
|
|
||||||
|
def flash(self, **bin_paths):
|
||||||
|
self._write_header(Request.Flash)
|
||||||
|
|
||||||
|
addr_table = {}
|
||||||
|
with io.BytesIO() as image_buf, io.BytesIO() as bin_buf:
|
||||||
|
offset = 0
|
||||||
|
# Reserve 4-bytes for CRC
|
||||||
|
image_buf.write(struct.pack(self.endian + "I", 0))
|
||||||
|
# Reserve 4-bytes for header length
|
||||||
|
image_buf.write(struct.pack(self.endian + "I", 0))
|
||||||
|
image_buf.write(struct.pack(self.endian + "I", len(bin_paths)))
|
||||||
|
for bin_name, filename in bin_paths.items():
|
||||||
|
with open(filename, "rb") as fi:
|
||||||
|
bin_ = fi.read()
|
||||||
|
length = bin_buf.write(bin_)
|
||||||
|
|
||||||
|
bin_name_str = bin_name.encode("utf-8")
|
||||||
|
image_buf.write(struct.pack(self.endian + "I", len(bin_name_str)))
|
||||||
|
image_buf.write(bin_name_str)
|
||||||
|
image_buf.write(struct.pack(self.endian + "II", offset, length))
|
||||||
|
|
||||||
|
offset += length
|
||||||
|
|
||||||
|
# header = image_buf.getvalue()
|
||||||
|
# image = image_buf.getvalue()
|
||||||
|
|
||||||
|
assert(image_buf.tell() == len(image_buf.getvalue()))
|
||||||
|
header_len = image_buf.tell() - 8
|
||||||
|
image_buf.seek(4, 0)
|
||||||
|
image_buf.write(struct.pack(self.endian + "I", header_len))
|
||||||
|
image_buf.seek(0, 2)
|
||||||
|
image_buf.write(bin_buf.getvalue())
|
||||||
|
|
||||||
|
image_buf.seek(4, 0)
|
||||||
|
crc = binascii.crc32(image_buf.read())
|
||||||
|
image_buf.seek(0, 0)
|
||||||
|
image_buf.write(struct.pack(self.endian + "I", crc))
|
||||||
|
|
||||||
|
self._write_bytes(image_buf.getvalue())
|
||||||
|
|
||||||
|
self._read_expect(Reply.RebootImminent)
|
||||||
|
|
|
@ -513,6 +513,7 @@ dependencies = [
|
||||||
"board_misoc",
|
"board_misoc",
|
||||||
"build_misoc",
|
"build_misoc",
|
||||||
"byteorder",
|
"byteorder",
|
||||||
|
"crc",
|
||||||
"cslice",
|
"cslice",
|
||||||
"dyld",
|
"dyld",
|
||||||
"eh",
|
"eh",
|
||||||
|
|
|
@ -259,39 +259,12 @@ mod imp {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn write(key: &str, value: &[u8]) -> Result<(), Error> {
|
pub fn write(key: &str, value: &[u8]) -> Result<(), Error> {
|
||||||
fn flash_binary(origin: usize, payload: &[u8]) {
|
match append(key, value) {
|
||||||
let mut offset = 0;
|
Err(Error::SpaceExhausted) => {
|
||||||
while offset < payload.len() {
|
compact()?;
|
||||||
unsafe {
|
append(key, value)
|
||||||
spiflash::erase_sector(origin + offset);
|
|
||||||
}
|
|
||||||
offset += spiflash::SECTOR_SIZE;
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
spiflash::write(origin, payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
match key {
|
|
||||||
"gateware" => {
|
|
||||||
flash_binary(0, value);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
"bootloader" => {
|
|
||||||
flash_binary(::mem::ROM_BASE, value);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
"firmware" => {
|
|
||||||
flash_binary(::mem::FLASH_BOOT_ADDRESS, value);
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
_ => match append(key, value) {
|
|
||||||
Err(Error::SpaceExhausted) => {
|
|
||||||
compact()?;
|
|
||||||
append(key, value)
|
|
||||||
}
|
|
||||||
res => res
|
|
||||||
}
|
}
|
||||||
|
res => res
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -114,6 +114,50 @@ pub unsafe fn write(mut addr: usize, mut data: &[u8]) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub unsafe fn write_image(image: &[u8]) {
|
||||||
|
// let image = &image[..];
|
||||||
|
// let actual_crc = crc32::checksum_ieee(image);
|
||||||
|
|
||||||
|
// if actual_crc == expected_crc {
|
||||||
|
// let mut reader = Cursor::new(header);
|
||||||
|
// let bin_no = reader.read_u32().unwrap() as usize;
|
||||||
|
// for _ in 0..bin_no {
|
||||||
|
// let bin_name = reader.read_string().unwrap();
|
||||||
|
// let offset = reader.read_u32().unwrap() as usize;
|
||||||
|
// let len = reader.read_u32().unwrap() as usize;
|
||||||
|
|
||||||
|
// let origin = match bin_name.as_str() {
|
||||||
|
// "gateware" => 0,
|
||||||
|
// "bootloader" => mem::ROM_BASE,
|
||||||
|
// "firmware" => mem::FLASH_BOOT_ADDRESS,
|
||||||
|
// _ => {
|
||||||
|
// error!("unexpected binary component {}", bin_name);
|
||||||
|
// return Ok(Reply::Error.write_to(stream)?);
|
||||||
|
// }
|
||||||
|
// };
|
||||||
|
|
||||||
|
// unsafe {
|
||||||
|
// spiflash::flash_binary(origin, &image[offset..offset+len]);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
// reboot(_io, stream)?;
|
||||||
|
// } else {
|
||||||
|
// error!("CRC failed in SDRAM (actual {:08x}, expected {:08x})", actual_crc, expected_crc);
|
||||||
|
// Reply::Error.write_to(stream)?;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
|
pub unsafe fn flash_binary(origin: usize, payload: &[u8]) {
|
||||||
|
assert!((origin & (SECTOR_SIZE - 1)) == 0);
|
||||||
|
let mut offset = 0;
|
||||||
|
while offset < payload.len() {
|
||||||
|
erase_sector(origin + offset);
|
||||||
|
offset += SECTOR_SIZE;
|
||||||
|
}
|
||||||
|
write(origin, payload);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(any(soc_platform = "kasli", soc_platform = "kc705"))]
|
#[cfg(any(soc_platform = "kasli", soc_platform = "kc705"))]
|
||||||
pub unsafe fn reload () -> ! {
|
pub unsafe fn reload () -> ! {
|
||||||
csr::icap::iprog_write(1);
|
csr::icap::iprog_write(1);
|
||||||
|
|
|
@ -67,6 +67,8 @@ pub enum Request {
|
||||||
|
|
||||||
Reboot,
|
Reboot,
|
||||||
|
|
||||||
|
Flash { image: Vec<u8> },
|
||||||
|
|
||||||
DebugAllocator,
|
DebugAllocator,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -125,6 +127,10 @@ impl Request {
|
||||||
|
|
||||||
8 => Request::DebugAllocator,
|
8 => Request::DebugAllocator,
|
||||||
|
|
||||||
|
9 => Request::Flash {
|
||||||
|
image: reader.read_bytes()?,
|
||||||
|
},
|
||||||
|
|
||||||
ty => return Err(Error::UnknownPacket(ty))
|
ty => return Err(Error::UnknownPacket(ty))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ build_misoc = { path = "../libbuild_misoc" }
|
||||||
failure = { version = "0.1", default-features = false }
|
failure = { version = "0.1", default-features = false }
|
||||||
failure_derive = { version = "0.1", default-features = false }
|
failure_derive = { version = "0.1", default-features = false }
|
||||||
byteorder = { version = "1.0", default-features = false }
|
byteorder = { version = "1.0", default-features = false }
|
||||||
|
crc = { version = "1.7", default-features = false }
|
||||||
cslice = { version = "0.3" }
|
cslice = { version = "0.3" }
|
||||||
log = { version = "=0.4.14", default-features = false }
|
log = { version = "=0.4.14", default-features = false }
|
||||||
managed = { version = "^0.7.1", default-features = false, features = ["alloc", "map"] }
|
managed = { version = "^0.7.1", default-features = false, features = ["alloc", "map"] }
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#![feature(lang_items, panic_info_message, const_btree_new, iter_advance_by, never_type)]
|
#![feature(lang_items, panic_info_message, const_btree_new, iter_advance_by, never_type)]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate crc;
|
||||||
extern crate dyld;
|
extern crate dyld;
|
||||||
extern crate eh;
|
extern crate eh;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
|
|
|
@ -14,10 +14,11 @@ impl From<SchedError> for Error<SchedError> {
|
||||||
|
|
||||||
mod local_coremgmt {
|
mod local_coremgmt {
|
||||||
use alloc::{string::String, vec::Vec};
|
use alloc::{string::String, vec::Vec};
|
||||||
|
use crc::crc32;
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
|
|
||||||
use board_misoc::{config, spiflash};
|
use board_misoc::{config, mem, spiflash};
|
||||||
use io::{Write, ProtoWrite, Error as IoError};
|
use io::{Cursor, Write, ProtoWrite, ProtoRead, Error as IoError};
|
||||||
use logger_artiq::BufferLogger;
|
use logger_artiq::BufferLogger;
|
||||||
use mgmt_proto::{Error, Reply};
|
use mgmt_proto::{Error, Reply};
|
||||||
use sched::{Io, TcpStream, Error as SchedError};
|
use sched::{Io, TcpStream, Error as SchedError};
|
||||||
|
@ -134,6 +135,54 @@ mod local_coremgmt {
|
||||||
unsafe { println!("{}", ::ALLOC) }
|
unsafe { println!("{}", ::ALLOC) }
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn flash(_io: &Io, stream: &mut TcpStream, image: &Vec<u8>) -> Result<(), Error<SchedError>> {
|
||||||
|
let mut reader = Cursor::new(&image[..]);
|
||||||
|
let expected_crc = reader.read_u32().unwrap();
|
||||||
|
|
||||||
|
let image = &image[4..];
|
||||||
|
let actual_crc = crc32::checksum_ieee(image);
|
||||||
|
|
||||||
|
if actual_crc == expected_crc {
|
||||||
|
info!("Checksum matched");
|
||||||
|
let header_size = reader.read_u32().unwrap() as usize;
|
||||||
|
let header_offset = reader.position();
|
||||||
|
let bin_offset = header_offset + header_size;
|
||||||
|
|
||||||
|
let header = &image[header_offset..bin_offset];
|
||||||
|
let binaries = &image[bin_offset..];
|
||||||
|
|
||||||
|
info!("found header of size {}", header.len());
|
||||||
|
|
||||||
|
let mut reader = Cursor::new(header);
|
||||||
|
let bin_no = reader.read_u32().unwrap() as usize;
|
||||||
|
for _ in 0..bin_no {
|
||||||
|
let bin_name = reader.read_string().unwrap();
|
||||||
|
let offset = reader.read_u32().unwrap() as usize;
|
||||||
|
let len = reader.read_u32().unwrap() as usize;
|
||||||
|
|
||||||
|
let origin = match bin_name.as_str() {
|
||||||
|
"gateware" => 0,
|
||||||
|
"bootloader" => mem::ROM_BASE,
|
||||||
|
"firmware" => mem::FLASH_BOOT_ADDRESS,
|
||||||
|
_ => {
|
||||||
|
error!("unexpected binary component {}", bin_name);
|
||||||
|
return Ok(Reply::Error.write_to(stream)?);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
spiflash::flash_binary(origin, &binaries[offset..offset+len]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
reboot(_io, stream)?;
|
||||||
|
} else {
|
||||||
|
error!("CRC failed in SDRAM (actual {:08x}, expected {:08x})", actual_crc, expected_crc);
|
||||||
|
Reply::Error.write_to(stream)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
|
@ -481,6 +530,13 @@ mod remote_coremgmt {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn flash(io: &Io, aux_mutex: &Mutex,
|
||||||
|
ddma_mutex: &Mutex, subkernel_mutex: &Mutex,
|
||||||
|
routing_table: &drtio_routing::RoutingTable, linkno: u8,
|
||||||
|
destination: u8, stream: &mut TcpStream, image: &Vec<u8>) -> Result<(), Error<SchedError>> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(has_drtio)]
|
#[cfg(has_drtio)]
|
||||||
|
@ -523,6 +579,7 @@ fn worker(io: &Io, _aux_mutex: &Mutex, _ddma_mutex: &Mutex, _subkernel_mutex: &M
|
||||||
Request::ConfigErase => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, config_erase),
|
Request::ConfigErase => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, config_erase),
|
||||||
Request::Reboot => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, reboot),
|
Request::Reboot => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, reboot),
|
||||||
Request::DebugAllocator => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, debug_allocator),
|
Request::DebugAllocator => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, debug_allocator),
|
||||||
|
Request::Flash { ref image } => process!(io, _aux_mutex, _ddma_mutex, _subkernel_mutex, _routing_table, stream, _destination, flash, image),
|
||||||
}?;
|
}?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import os
|
||||||
import struct
|
import struct
|
||||||
|
import tempfile
|
||||||
|
import atexit
|
||||||
|
|
||||||
from sipyco import common_args
|
from sipyco import common_args
|
||||||
|
|
||||||
|
@ -9,6 +12,8 @@ from artiq import __version__ as artiq_version
|
||||||
from artiq.master.databases import DeviceDB
|
from artiq.master.databases import DeviceDB
|
||||||
from artiq.coredevice.comm_kernel import CommKernel
|
from artiq.coredevice.comm_kernel import CommKernel
|
||||||
from artiq.coredevice.comm_mgmt import CommMgmt
|
from artiq.coredevice.comm_mgmt import CommMgmt
|
||||||
|
from artiq.frontend.bit2bin import bit2bin
|
||||||
|
from misoc.tools.mkmscimg import insert_crc
|
||||||
|
|
||||||
|
|
||||||
def get_argparser():
|
def get_argparser():
|
||||||
|
@ -85,6 +90,13 @@ def get_argparser():
|
||||||
t_boot = tools.add_parser("reboot",
|
t_boot = tools.add_parser("reboot",
|
||||||
help="reboot the running system")
|
help="reboot the running system")
|
||||||
|
|
||||||
|
# flashing
|
||||||
|
t_flash = tools.add_parser("flash",
|
||||||
|
help="flash the running system")
|
||||||
|
|
||||||
|
p_directory = t_flash.add_argument("directory", metavar="DIRECTORY", type=str,
|
||||||
|
help="directory that contains the binaries")
|
||||||
|
|
||||||
# misc debug
|
# misc debug
|
||||||
t_debug = tools.add_parser("debug",
|
t_debug = tools.add_parser("debug",
|
||||||
help="specialized debug functions")
|
help="specialized debug functions")
|
||||||
|
@ -142,6 +154,37 @@ def main():
|
||||||
mgmt.config_remove(key)
|
mgmt.config_remove(key)
|
||||||
if args.action == "erase":
|
if args.action == "erase":
|
||||||
mgmt.config_erase()
|
mgmt.config_erase()
|
||||||
|
|
||||||
|
if args.tool == "flash":
|
||||||
|
def convert_gateware(bit_filename):
|
||||||
|
bin_handle, bin_filename = tempfile.mkstemp(
|
||||||
|
prefix="artiq_", suffix="_" + os.path.basename(bit_filename))
|
||||||
|
with open(bit_filename, "rb") as bit_file, open(bin_handle, "wb") as bin_file:
|
||||||
|
bit2bin(bit_file, bin_file)
|
||||||
|
atexit.register(lambda: os.unlink(bin_filename))
|
||||||
|
return bin_filename
|
||||||
|
|
||||||
|
gateware = convert_gateware(os.path.join(args.directory, "top.bit"))
|
||||||
|
bootloader = os.path.join(args.directory, "bootloader.bin")
|
||||||
|
|
||||||
|
firmwares = []
|
||||||
|
for firmware in "satman", "runtime":
|
||||||
|
filename = os.path.join(args.directory, firmware + ".fbi")
|
||||||
|
if os.path.exists(filename):
|
||||||
|
firmwares.append(filename)
|
||||||
|
if not firmwares:
|
||||||
|
raise FileNotFoundError("no firmware found")
|
||||||
|
if len(firmwares) > 1:
|
||||||
|
raise ValueError("more than one firmware file, please clean up your build directory. "
|
||||||
|
"Found firmware files: {}".format(" ".join(firmwares)))
|
||||||
|
firmware = firmwares[0]
|
||||||
|
|
||||||
|
bins = {
|
||||||
|
"gateware": gateware,
|
||||||
|
"bootloader": bootloader,
|
||||||
|
"firmware": firmware,
|
||||||
|
}
|
||||||
|
mgmt.flash(**bins)
|
||||||
|
|
||||||
if args.tool == "reboot":
|
if args.tool == "reboot":
|
||||||
mgmt.reboot()
|
mgmt.reboot()
|
||||||
|
|
Loading…
Reference in New Issue