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
|
||||
import binascii
|
||||
import logging
|
||||
import io
|
||||
import struct
|
||||
|
||||
from sipyco.keepalive import create_connection
|
||||
|
@ -23,6 +25,8 @@ class Request(Enum):
|
|||
|
||||
DebugAllocator = 8
|
||||
|
||||
Flash = 9
|
||||
|
||||
|
||||
class Reply(Enum):
|
||||
Success = 1
|
||||
|
@ -196,3 +200,45 @@ class CommMgmt:
|
|||
|
||||
def debug_allocator(self):
|
||||
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",
|
||||
"build_misoc",
|
||||
"byteorder",
|
||||
"crc",
|
||||
"cslice",
|
||||
"dyld",
|
||||
"eh",
|
||||
|
|
|
@ -259,39 +259,12 @@ mod imp {
|
|||
}
|
||||
|
||||
pub fn write(key: &str, value: &[u8]) -> Result<(), Error> {
|
||||
fn flash_binary(origin: usize, payload: &[u8]) {
|
||||
let mut offset = 0;
|
||||
while offset < payload.len() {
|
||||
unsafe {
|
||||
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
|
||||
match append(key, value) {
|
||||
Err(Error::SpaceExhausted) => {
|
||||
compact()?;
|
||||
append(key, value)
|
||||
}
|
||||
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"))]
|
||||
pub unsafe fn reload () -> ! {
|
||||
csr::icap::iprog_write(1);
|
||||
|
|
|
@ -67,6 +67,8 @@ pub enum Request {
|
|||
|
||||
Reboot,
|
||||
|
||||
Flash { image: Vec<u8> },
|
||||
|
||||
DebugAllocator,
|
||||
}
|
||||
|
||||
|
@ -125,6 +127,10 @@ impl Request {
|
|||
|
||||
8 => Request::DebugAllocator,
|
||||
|
||||
9 => Request::Flash {
|
||||
image: reader.read_bytes()?,
|
||||
},
|
||||
|
||||
ty => return Err(Error::UnknownPacket(ty))
|
||||
})
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ build_misoc = { path = "../libbuild_misoc" }
|
|||
failure = { version = "0.1", default-features = false }
|
||||
failure_derive = { version = "0.1", default-features = false }
|
||||
byteorder = { version = "1.0", default-features = false }
|
||||
crc = { version = "1.7", default-features = false }
|
||||
cslice = { version = "0.3" }
|
||||
log = { version = "=0.4.14", default-features = false }
|
||||
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)]
|
||||
#![no_std]
|
||||
|
||||
extern crate crc;
|
||||
extern crate dyld;
|
||||
extern crate eh;
|
||||
#[macro_use]
|
||||
|
|
|
@ -14,10 +14,11 @@ impl From<SchedError> for Error<SchedError> {
|
|||
|
||||
mod local_coremgmt {
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use crc::crc32;
|
||||
use log::LevelFilter;
|
||||
|
||||
use board_misoc::{config, spiflash};
|
||||
use io::{Write, ProtoWrite, Error as IoError};
|
||||
use board_misoc::{config, mem, spiflash};
|
||||
use io::{Cursor, Write, ProtoWrite, ProtoRead, Error as IoError};
|
||||
use logger_artiq::BufferLogger;
|
||||
use mgmt_proto::{Error, Reply};
|
||||
use sched::{Io, TcpStream, Error as SchedError};
|
||||
|
@ -134,6 +135,54 @@ mod local_coremgmt {
|
|||
unsafe { println!("{}", ::ALLOC) }
|
||||
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)]
|
||||
|
@ -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)]
|
||||
|
@ -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::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::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
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import struct
|
||||
import tempfile
|
||||
import atexit
|
||||
|
||||
from sipyco import common_args
|
||||
|
||||
|
@ -9,6 +12,8 @@ from artiq import __version__ as artiq_version
|
|||
from artiq.master.databases import DeviceDB
|
||||
from artiq.coredevice.comm_kernel import CommKernel
|
||||
from artiq.coredevice.comm_mgmt import CommMgmt
|
||||
from artiq.frontend.bit2bin import bit2bin
|
||||
from misoc.tools.mkmscimg import insert_crc
|
||||
|
||||
|
||||
def get_argparser():
|
||||
|
@ -85,6 +90,13 @@ def get_argparser():
|
|||
t_boot = tools.add_parser("reboot",
|
||||
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
|
||||
t_debug = tools.add_parser("debug",
|
||||
help="specialized debug functions")
|
||||
|
@ -143,6 +155,37 @@ def main():
|
|||
if args.action == "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":
|
||||
mgmt.reboot()
|
||||
|
||||
|
|
Loading…
Reference in New Issue