forked from M-Labs/artiq-zynq
libconfig: refactored load_pl into bootgen
Now allows loading firmware.
This commit is contained in:
parent
afecc83ecf
commit
eb78e4e2da
|
@ -1,46 +1,38 @@
|
||||||
use super::sd_reader;
|
use alloc::vec::Vec;
|
||||||
use core_io::{Error, Read, Seek, SeekFrom};
|
use core_io::{Error, Read, Seek, SeekFrom};
|
||||||
use libboard_zynq::{devc, sdio};
|
use libboard_zynq::devc;
|
||||||
use log::{info, debug};
|
use log::debug;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum PlLoadingError {
|
pub enum BootgenLoadingError {
|
||||||
BootImageNotFound,
|
|
||||||
InvalidBootImageHeader,
|
InvalidBootImageHeader,
|
||||||
MissingBitstreamPartition,
|
MissingPartition,
|
||||||
EncryptedBitstream,
|
EncryptedBitstream,
|
||||||
IoError(Error),
|
IoError(Error),
|
||||||
DevcError(devc::DevcError),
|
DevcError(devc::DevcError),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for PlLoadingError {
|
impl From<Error> for BootgenLoadingError {
|
||||||
fn from(error: Error) -> Self {
|
fn from(error: Error) -> Self {
|
||||||
PlLoadingError::IoError(error)
|
BootgenLoadingError::IoError(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<devc::DevcError> for PlLoadingError {
|
impl From<devc::DevcError> for BootgenLoadingError {
|
||||||
fn from(error: devc::DevcError) -> Self {
|
fn from(error: devc::DevcError) -> Self {
|
||||||
PlLoadingError::DevcError(error)
|
BootgenLoadingError::DevcError(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl core::fmt::Display for PlLoadingError {
|
impl core::fmt::Display for BootgenLoadingError {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
use PlLoadingError::*;
|
use BootgenLoadingError::*;
|
||||||
match self {
|
match self {
|
||||||
BootImageNotFound => write!(
|
|
||||||
f,
|
|
||||||
"Boot image not found, make sure `boot.bin` exists and your SD card is plugged in."
|
|
||||||
),
|
|
||||||
InvalidBootImageHeader => write!(
|
InvalidBootImageHeader => write!(
|
||||||
f,
|
f,
|
||||||
"Invalid boot image header. Check if the file is correct."
|
"Invalid boot image header. Check if the file is correct."
|
||||||
),
|
),
|
||||||
MissingBitstreamPartition => write!(
|
MissingPartition => write!(f, "Partition not found. Check your compile configuration."),
|
||||||
f,
|
|
||||||
"Bitstream partition not found. Check your compile configuration."
|
|
||||||
),
|
|
||||||
EncryptedBitstream => write!(f, "Encrypted bitstream is not supported."),
|
EncryptedBitstream => write!(f, "Encrypted bitstream is not supported."),
|
||||||
IoError(e) => write!(f, "Error while reading: {}", e),
|
IoError(e) => write!(f, "Error while reading: {}", e),
|
||||||
DevcError(e) => write!(f, "PCAP interface error: {}", e),
|
DevcError(e) => write!(f, "PCAP interface error: {}", e),
|
||||||
|
@ -66,7 +58,7 @@ struct PartitionHeader {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a u32 word from the reader.
|
/// Read a u32 word from the reader.
|
||||||
fn read_u32<Reader: Read>(reader: &mut Reader) -> Result<u32, PlLoadingError> {
|
fn read_u32<Reader: Read>(reader: &mut Reader) -> Result<u32, BootgenLoadingError> {
|
||||||
let mut buffer: [u8; 4] = [0; 4];
|
let mut buffer: [u8; 4] = [0; 4];
|
||||||
reader.read_exact(&mut buffer)?;
|
reader.read_exact(&mut buffer)?;
|
||||||
let mut result: u32 = 0;
|
let mut result: u32 = 0;
|
||||||
|
@ -79,7 +71,7 @@ fn read_u32<Reader: Read>(reader: &mut Reader) -> Result<u32, PlLoadingError> {
|
||||||
/// Load PL partition header.
|
/// Load PL partition header.
|
||||||
fn load_pl_header<File: Read + Seek>(
|
fn load_pl_header<File: Read + Seek>(
|
||||||
file: &mut File,
|
file: &mut File,
|
||||||
) -> Result<Option<PartitionHeader>, PlLoadingError> {
|
) -> Result<Option<PartitionHeader>, BootgenLoadingError> {
|
||||||
let mut buffer: [u8; 0x40] = [0; 0x40];
|
let mut buffer: [u8; 0x40] = [0; 0x40];
|
||||||
file.read_exact(&mut buffer)?;
|
file.read_exact(&mut buffer)?;
|
||||||
let header = unsafe { core::mem::transmute::<_, PartitionHeader>(buffer) };
|
let header = unsafe { core::mem::transmute::<_, PartitionHeader>(buffer) };
|
||||||
|
@ -90,56 +82,75 @@ fn load_pl_header<File: Read + Seek>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Locate the PL bitstream from the image, and return the size (in bytes) of the bitstream if successful.
|
fn load_ps_header<File: Read + Seek>(
|
||||||
/// This function would seek the file to the location of the bitstream.
|
file: &mut File,
|
||||||
fn locate_bitstream<File: Read + Seek>(file: &mut File) -> Result<usize, PlLoadingError> {
|
) -> Result<Option<PartitionHeader>, BootgenLoadingError> {
|
||||||
|
let mut buffer: [u8; 0x40] = [0; 0x40];
|
||||||
|
file.read_exact(&mut buffer)?;
|
||||||
|
let header = unsafe { core::mem::transmute::<_, PartitionHeader>(buffer) };
|
||||||
|
if header.attribute_bits & (1 << 4) != 0 {
|
||||||
|
Ok(Some(header))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Locate the partition from the image, and return the size (in bytes) of the partition if successful.
|
||||||
|
/// This function would seek the file to the location of the partition.
|
||||||
|
fn locate<
|
||||||
|
File: Read + Seek,
|
||||||
|
F: Fn(&mut File) -> Result<Option<PartitionHeader>, BootgenLoadingError>,
|
||||||
|
>(
|
||||||
|
file: &mut File,
|
||||||
|
f: F,
|
||||||
|
) -> Result<usize, BootgenLoadingError> {
|
||||||
|
file.seek(SeekFrom::Start(0))?;
|
||||||
const BOOT_HEADER_SIGN: u32 = 0x584C4E58;
|
const BOOT_HEADER_SIGN: u32 = 0x584C4E58;
|
||||||
// read boot header signature
|
// read boot header signature
|
||||||
file.seek(SeekFrom::Start(0x24))?;
|
file.seek(SeekFrom::Start(0x24))?;
|
||||||
if read_u32(file)? != BOOT_HEADER_SIGN {
|
if read_u32(file)? != BOOT_HEADER_SIGN {
|
||||||
return Err(PlLoadingError::InvalidBootImageHeader);
|
return Err(BootgenLoadingError::InvalidBootImageHeader);
|
||||||
}
|
}
|
||||||
|
// find fsbl offset
|
||||||
|
file.seek(SeekFrom::Start(0x30))?;
|
||||||
|
// the length is in bytes, we have to convert it to words to compare with the partition offset
|
||||||
|
// later
|
||||||
|
let fsbl = read_u32(file)? / 4;
|
||||||
// read partition header offset
|
// read partition header offset
|
||||||
file.seek(SeekFrom::Start(0x9C))?;
|
file.seek(SeekFrom::Start(0x9C))?;
|
||||||
let ptr = read_u32(file)?;
|
let ptr = read_u32(file)?;
|
||||||
debug!("Partition header pointer = {:0X}", ptr);
|
debug!("Partition header pointer = {:0X}", ptr);
|
||||||
file.seek(SeekFrom::Start(ptr as u64))?;
|
file.seek(SeekFrom::Start(ptr as u64))?;
|
||||||
|
|
||||||
let mut header_opt = None;
|
|
||||||
// at most 3 partition headers
|
// at most 3 partition headers
|
||||||
for _ in 0..3 {
|
for _ in 0..3 {
|
||||||
let result = load_pl_header(file)?;
|
if let Some(header) = f(file)? {
|
||||||
if let Some(h) = result {
|
let encrypted_length = header.encrypted_length;
|
||||||
header_opt = Some(h);
|
let unencrypted_length = header.unencrypted_length;
|
||||||
break;
|
debug!("Unencrypted length = {:0X}", unencrypted_length);
|
||||||
|
if encrypted_length != unencrypted_length {
|
||||||
|
return Err(BootgenLoadingError::EncryptedBitstream);
|
||||||
|
}
|
||||||
|
|
||||||
|
let start_addr = header.data_offset;
|
||||||
|
// skip fsbl
|
||||||
|
if start_addr == fsbl {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
debug!("Partition start address: {:0X}", start_addr);
|
||||||
|
file.seek(SeekFrom::Start(start_addr as u64 * 4))?;
|
||||||
|
|
||||||
|
return Ok(unencrypted_length as usize * 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let header = match header_opt {
|
Err(BootgenLoadingError::MissingPartition)
|
||||||
None => return Err(PlLoadingError::MissingBitstreamPartition),
|
|
||||||
Some(h) => h,
|
|
||||||
};
|
|
||||||
|
|
||||||
let encrypted_length = header.encrypted_length;
|
|
||||||
let unencrypted_length = header.unencrypted_length;
|
|
||||||
debug!("Unencrypted length = {:0X}", unencrypted_length);
|
|
||||||
if encrypted_length != unencrypted_length {
|
|
||||||
return Err(PlLoadingError::EncryptedBitstream);
|
|
||||||
}
|
|
||||||
|
|
||||||
let start_addr = header.data_offset;
|
|
||||||
debug!("Partition start address: {:0X}", start_addr);
|
|
||||||
file.seek(SeekFrom::Start(start_addr as u64 * 4))?;
|
|
||||||
|
|
||||||
Ok(unencrypted_length as usize * 4)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Load bitstream from bootgen file.
|
/// Load bitstream from bootgen file.
|
||||||
/// This function parses the file, locate the bitstream and load it through the PCAP driver.
|
/// This function parses the file, locate the bitstream and load it through the PCAP driver.
|
||||||
/// It requires a large buffer, please enable the DDR RAM before using it.
|
/// It requires a large buffer, please enable the DDR RAM before using it.
|
||||||
pub fn load_bitstream<File: Read + Seek>(
|
pub fn load_bitstream<File: Read + Seek>(file: &mut File) -> Result<(), BootgenLoadingError> {
|
||||||
file: &mut File,
|
let size = locate(file, load_pl_header)?;
|
||||||
) -> Result<(), PlLoadingError> {
|
|
||||||
let size = locate_bitstream(file)?;
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// align to 64 bytes
|
// align to 64 bytes
|
||||||
let ptr = alloc::alloc::alloc(alloc::alloc::Layout::from_size_align(size, 64).unwrap());
|
let ptr = alloc::alloc::alloc(alloc::alloc::Layout::from_size_align(size, 64).unwrap());
|
||||||
|
@ -159,20 +170,12 @@ pub fn load_bitstream<File: Read + Seek>(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_bitstream_from_sd() -> Result<(), PlLoadingError> {
|
pub fn get_runtime<File: Read + Seek>(file: &mut File) -> Result<Vec<u8>, BootgenLoadingError> {
|
||||||
let sdio0 = sdio::Sdio::sdio0(true);
|
let size = locate(file, load_ps_header)?;
|
||||||
if sdio0.is_card_inserted() {
|
let mut buffer = Vec::with_capacity(size);
|
||||||
info!("Card inserted. Mounting file system.");
|
unsafe {
|
||||||
let sd = sdio::sd_card::SdCard::from_sdio(sdio0).unwrap();
|
buffer.set_len(size);
|
||||||
let reader = sd_reader::SdReader::new(sd);
|
|
||||||
|
|
||||||
let fs = reader.mount_fatfs(sd_reader::PartitionEntry::Entry1)?;
|
|
||||||
let root_dir = fs.root_dir();
|
|
||||||
let mut file = root_dir.open_file("/BOOT.BIN").map_err(|_| PlLoadingError::BootImageNotFound)?;
|
|
||||||
info!("Found boot image!");
|
|
||||||
load_bitstream(&mut file)
|
|
||||||
} else {
|
|
||||||
info!("SD card not inserted. Bitstream cannot be loaded.");
|
|
||||||
Err(PlLoadingError::BootImageNotFound)
|
|
||||||
}
|
}
|
||||||
|
file.read_exact(&mut buffer)?;
|
||||||
|
Ok(buffer)
|
||||||
}
|
}
|
|
@ -2,13 +2,13 @@
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
use alloc::{string::FromUtf8Error, string::String, vec::Vec};
|
use alloc::{string::FromUtf8Error, string::String, vec::Vec, rc::Rc};
|
||||||
use core_io::{self as io, BufRead, BufReader, Read};
|
use core_io::{self as io, BufRead, BufReader, Read};
|
||||||
use libboard_zynq::sdio;
|
use libboard_zynq::sdio;
|
||||||
|
|
||||||
pub mod sd_reader;
|
pub mod sd_reader;
|
||||||
pub mod net_settings;
|
pub mod net_settings;
|
||||||
pub mod load_pl;
|
pub mod bootgen;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error<'a> {
|
pub enum Error<'a> {
|
||||||
|
@ -68,7 +68,7 @@ fn parse_config<'a>(
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
fs: Option<fatfs::FileSystem<sd_reader::SdReader>>,
|
fs: Option<Rc<fatfs::FileSystem<sd_reader::SdReader>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
@ -81,7 +81,11 @@ impl Config {
|
||||||
let reader = sd_reader::SdReader::new(sd);
|
let reader = sd_reader::SdReader::new(sd);
|
||||||
|
|
||||||
let fs = reader.mount_fatfs(sd_reader::PartitionEntry::Entry1)?;
|
let fs = reader.mount_fatfs(sd_reader::PartitionEntry::Entry1)?;
|
||||||
Ok(Config { fs: Some(fs) })
|
Ok(Config { fs: Some(Rc::new(fs)) })
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_fs(fs: Option<Rc<fatfs::FileSystem<sd_reader::SdReader>>>) -> Self {
|
||||||
|
Config { fs }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_dummy() -> Self {
|
pub fn new_dummy() -> Self {
|
||||||
|
|
Loading…
Reference in New Issue