forked from M-Labs/artiq
1
0
Fork 0

coremgmt: implement flash

This commit is contained in:
occheung 2024-08-30 18:41:45 +08:00
parent cd6e5ff378
commit a1e392fb0e
9 changed files with 206 additions and 34 deletions

View File

@ -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)

View File

@ -513,6 +513,7 @@ dependencies = [
"board_misoc",
"build_misoc",
"byteorder",
"crc",
"cslice",
"dyld",
"eh",

View File

@ -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
}
}

View File

@ -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);

View File

@ -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))
})
}

View File

@ -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"] }

View File

@ -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]

View File

@ -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),
}?;
}
}

View File

@ -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")
@ -142,6 +154,37 @@ def main():
mgmt.config_remove(key)
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()