Browse Source

use liconfig, libcoreio, szl from zynq-rs

master
parent
commit
86b9045417
  1. 9
      default.nix
  2. 15
      local_run.sh
  3. 16
      remote_run.sh
  4. 2
      shell.nix
  5. 26
      src/Cargo.lock
  6. 15
      src/Cargo.toml
  7. 5
      src/Makefile
  8. 15
      src/libconfig/Cargo.toml
  9. 181
      src/libconfig/src/bootgen.rs
  10. 115
      src/libconfig/src/lib.rs
  11. 62
      src/libconfig/src/net_settings.rs
  12. 303
      src/libconfig/src/sd_reader.rs
  13. 14
      src/libcoreio/Cargo.toml
  14. 1674
      src/libcoreio/src/io/buffered.rs
  15. 896
      src/libcoreio/src/io/cursor.rs
  16. 551
      src/libcoreio/src/io/error.rs
  17. 378
      src/libcoreio/src/io/impls.rs
  18. 2664
      src/libcoreio/src/io/mod.rs
  19. 13
      src/libcoreio/src/io/prelude.rs
  20. 269
      src/libcoreio/src/io/util.rs
  21. 51
      src/libcoreio/src/lib.rs
  22. 2
      src/runtime/Cargo.toml
  23. 22
      src/szl/Cargo.toml
  24. 22
      src/szl/build.rs
  25. 69
      src/szl/link.x
  26. 169
      src/szl/src/main.rs
  27. 399
      src/szl/src/netboot.rs
  28. 10
      zynq-rs.nix

9
default.nix

@ -2,6 +2,7 @@ let
zynq-rs = (import ./zynq-rs.nix);
pkgs = import <nixpkgs> { overlays = [ (import "${zynq-rs}/nix/mozilla-overlay.nix") ]; };
rustPlatform = (import "${zynq-rs}/nix/rust-platform.nix" { inherit pkgs; });
zc706-szl = (import zynq-rs).zc706-szl;
zc706-fsbl = import "${zynq-rs}/nix/fsbl.nix" { inherit pkgs; };
mkbootimage = import "${zynq-rs}/nix/mkbootimage.nix" { inherit pkgs; };
artiqpkgs = import <artiq-fast/default.nix> { inherit pkgs; };
@ -12,7 +13,7 @@ let
version = "0.1.0";
src = ./src;
cargoSha256 = "0fpnwiqwscd8v48hpjzy0ydmiv3kl68lbl9j06nkybs9flj1r08a";
cargoSha256 = "10hap25cy2qgwr7b86jid73i6fp480iym29r3r97jindfxk0svi0";
nativeBuildInputs = [
pkgs.gnumake
@ -31,10 +32,8 @@ let
mkdir -p $out $out/nix-support
cp ../build/runtime.bin $out/runtime.bin
cp ../build/firmware/armv7-none-eabihf/release/runtime $out/runtime.elf
cp ../build/firmware/armv7-none-eabihf/debug/szl $out/szl.elf
echo file binary-dist $out/runtime.bin >> $out/nix-support/hydra-build-products
echo file binary-dist $out/runtime.elf >> $out/nix-support/hydra-build-products
echo file binary-dist $out/szl.elf >> $out/nix-support/hydra-build-products
'';
doCheck = false;
@ -58,7 +57,7 @@ let
jtag = pkgs.runCommand "zc706-${variant}-jtag" {}
''
mkdir $out
ln -s ${firmware}/szl.elf $out
ln -s ${zc706-szl}/szl.elf $out
ln -s ${firmware}/runtime.bin $out
ln -s ${gateware}/top.bit $out
'';
@ -71,7 +70,7 @@ let
# can't write software (mkbootimage will segfault).
bifdir=`mktemp -d`
cd $bifdir
ln -s ${firmware}/szl.elf szl.elf
ln -s ${zc706-szl}/szl.elf szl.elf
ln -s ${firmware}/runtime.elf runtime.elf
ln -s ${gateware}/top.bit top.bit
cat > boot.bif << EOF

15
local_run.sh

@ -2,6 +2,15 @@
set -e
if [ -z "$OPENOCD_ZYNQ" ]; then
echo "OPENOCD_ZYNQ environment variable must be set"
exit 1
fi
if [ -z "$SZL" ]; then
echo "SZL environment variable must be set"
exit 1
fi
impure=0
load_bitstream=1
board_host="192.168.1.52"
@ -24,18 +33,16 @@ load_bitstream_cmd=""
build_dir=`pwd`/build
result_dir=`pwd`/result
cd $OPENOCD_ZYNQ
openocd -f zc706.cfg -c "load_image $SZL; resume 0; exit"
sleep 5
if [ $impure -eq 1 ]; then
if [ $load_bitstream -eq 1 ]; then
load_bitstream_cmd="-g $build_dir/gateware/top.bit"
fi
openocd -f zc706.cfg -c "load_image $build_dir/firmware/armv7-none-eabihf/debug/szl; resume 0; exit"
sleep 5
artiq_netboot $load_bitstream_cmd -f $build_dir/runtime.bin -b $board_host
else
if [ $load_bitstream -eq 1 ]; then
load_bitstream_cmd="-g $result_dir/top.bit"
fi
openocd -f zc706.cfg -c "load_image $result_dir/szl.elf; resume 0; exit"
sleep 5
artiq_netboot $load_bitstream_cmd -f $result_dir/runtime.bin -b $board_host
fi

16
remote_run.sh

@ -2,6 +2,15 @@
set -e
if [ -z "$OPENOCD_ZYNQ" ]; then
echo "OPENOCD_ZYNQ environment variable must be set"
exit 1
fi
if [ -z "$SZL" ]; then
echo "SZL environment variable must be set"
exit 1
fi
target_host="rpi-4.m-labs.hk"
impure=0
pure_dir="result"
@ -36,19 +45,18 @@ load_bitstream_cmd=""
echo "Creating $target_folder..."
ssh $sshopts $target_host "mkdir -p $target_folder"
echo "Copying files..."
rsync -e "ssh $sshopts" $OPENOCD_ZYNQ/* $target_host:$target_folder
rsync -e "ssh $sshopts" -Lc $OPENOCD_ZYNQ/* $target_host:$target_folder
rsync -e "ssh $sshopts" -Lc $SZL $target_host:$target_folder
if [ $impure -eq 1 ]; then
if [ $load_bitstream -eq 1 ]; then
load_bitstream_cmd="-g build/gateware/top.bit"
fi
firmware="build/runtime.bin"
rsync -e "ssh $sshopts" $impure_dir/firmware/armv7-none-eabihf/debug/szl $target_host:$target_folder/szl.elf
else
if [ $load_bitstream -eq 1 ]; then
load_bitstream_cmd="-g $pure_dir/top.bit"
fi
firmware="$pure_dir/runtime.bin"
rsync -e "ssh $sshopts" -Lc $pure_dir/szl.elf $target_host:$target_folder
firmware="$pure_dir/runtime.bin"
fi
echo "Programming board..."
ssh $sshopts $target_host "cd $target_folder; openocd -f zc706.cfg -c'load_image szl.elf; resume 0; exit'"

2
shell.nix

@ -6,6 +6,7 @@ let
artiqpkgs = import "${artiq-fast}/default.nix" { inherit pkgs; };
vivado = import "${artiq-fast}/vivado.nix" { inherit pkgs; };
cargo-xbuild = import ./cargo-xbuild.nix { inherit pkgs; };
zc706-szl = (import zynq-rs).zc706-szl;
in
pkgs.stdenv.mkDerivation {
name = "artiq-zynq-env";
@ -30,4 +31,5 @@ in
XARGO_RUST_SRC = "${rustPlatform.rust.rustc.src}/src";
OPENOCD_ZYNQ = "${zynq-rs}/openocd";
SZL = "${zc706-szl}/szl.elf";
}

26
src/Cargo.lock

@ -58,6 +58,7 @@ dependencies = [
[[package]]
name = "core_io"
version = "0.1.20200410"
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#7360984efbd772ae992ef00af09786b0ae8430f0"
dependencies = [
"memchr",
]
@ -187,7 +188,7 @@ dependencies = [
[[package]]
name = "libasync"
version = "0.0.0"
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#4fef8a71929b989e1189736628ab9c186f23f3a5"
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#7360984efbd772ae992ef00af09786b0ae8430f0"
dependencies = [
"embedded-hal",
"libcortex_a9",
@ -199,7 +200,7 @@ dependencies = [
[[package]]
name = "libboard_zynq"
version = "0.0.0"
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#4fef8a71929b989e1189736628ab9c186f23f3a5"
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#7360984efbd772ae992ef00af09786b0ae8430f0"
dependencies = [
"bit_field",
"embedded-hal",
@ -223,6 +224,7 @@ dependencies = [
[[package]]
name = "libconfig"
version = "0.1.0"
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#7360984efbd772ae992ef00af09786b0ae8430f0"
dependencies = [
"core_io",
"fatfs",
@ -233,7 +235,7 @@ dependencies = [
[[package]]
name = "libcortex_a9"
version = "0.0.0"
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#4fef8a71929b989e1189736628ab9c186f23f3a5"
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#7360984efbd772ae992ef00af09786b0ae8430f0"
dependencies = [
"bit_field",
"libregister",
@ -249,7 +251,7 @@ checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
[[package]]
name = "libregister"
version = "0.0.0"
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#4fef8a71929b989e1189736628ab9c186f23f3a5"
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#7360984efbd772ae992ef00af09786b0ae8430f0"
dependencies = [
"bit_field",
"vcell",
@ -259,7 +261,7 @@ dependencies = [
[[package]]
name = "libsupport_zynq"
version = "0.0.0"
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#4fef8a71929b989e1189736628ab9c186f23f3a5"
source = "git+https://git.m-labs.hk/M-Labs/zynq-rs.git#7360984efbd772ae992ef00af09786b0ae8430f0"
dependencies = [
"compiler_builtins",
"libboard_zynq",
@ -451,20 +453,6 @@ dependencies = [
"unicode-xid",
]
[[package]]
name = "szl"
version = "0.1.0"
dependencies = [
"byteorder",
"core_io",
"libboard_zynq",
"libconfig",
"libcortex_a9",
"libregister",
"libsupport_zynq",
"log",
]
[[package]]
name = "unicode-xid"
version = "0.2.1"

15
src/Cargo.toml

@ -2,24 +2,11 @@
members = [
"libc",
"libdyld",
"libconfig",
"libcoreio",
"libdwarf",
"libunwind",
"runtime",
"szl"
]
# Note: we are using dev profile for szl to override the opt-level only
[profile.dev]
panic = "abort"
debug = true
codegen-units = 1
opt-level = 'z'
lto = true
debug-assertions = false
overflow-checks = false
[profile.release]
panic = "abort"
debug = true
@ -28,5 +15,5 @@ opt-level = 2
lto = true
[patch.crates-io]
core_io = { path = "./libcoreio" }
core_io = { git = "https://git.m-labs.hk/M-Labs/zynq-rs.git" }
compiler_builtins = { git = "https://git.m-labs.hk/M-Labs/compiler-builtins-zynq.git"}

5
src/Makefile

@ -1,6 +1,6 @@
VARIANT := simple
all: ../build/firmware/armv7-none-eabihf/debug/szl ../build/firmware/armv7-none-eabihf/release/runtime ../build/runtime.bin
all: ../build/firmware/armv7-none-eabihf/release/runtime ../build/runtime.bin
.PHONY: all
@ -14,6 +14,3 @@ all: ../build/firmware/armv7-none-eabihf/debug/szl ../build/firmware/armv7-none-
../build/runtime.bin: ../build/firmware/armv7-none-eabihf/release/runtime
llvm-objcopy -O binary ../build/firmware/armv7-none-eabihf/release/runtime ../build/runtime.bin
../build/firmware/armv7-none-eabihf/debug/szl: .cargo/* armv7-none-eabihf.json Cargo.lock Cargo.toml szl/* szl/src/*
XBUILD_SYSROOT_PATH=`pwd`/../build/sysroot cargo xbuild -p szl --target-dir ../build/firmware

15
src/libconfig/Cargo.toml

@ -1,15 +0,0 @@
[package]
name = "libconfig"
version = "0.1.0"
authors = ["M-Labs"]
edition = "2018"
[dependencies]
libboard_zynq = { git = "https://git.m-labs.hk/M-Labs/zynq-rs.git" }
core_io = { version = "0.1", features = ["collections"] }
fatfs = { version = "0.3", features = ["core_io"], default-features = false }
log = "0.4"
[features]
ipv6 = []

181
src/libconfig/src/bootgen.rs

@ -1,181 +0,0 @@
use alloc::vec::Vec;
use core_io::{Error, Read, Seek, SeekFrom};
use libboard_zynq::devc;
use log::debug;
#[derive(Debug)]
pub enum BootgenLoadingError {
InvalidBootImageHeader,
MissingPartition,
EncryptedBitstream,
IoError(Error),
DevcError(devc::DevcError),
}
impl From<Error> for BootgenLoadingError {
fn from(error: Error) -> Self {
BootgenLoadingError::IoError(error)
}
}
impl From<devc::DevcError> for BootgenLoadingError {
fn from(error: devc::DevcError) -> Self {
BootgenLoadingError::DevcError(error)
}
}
impl core::fmt::Display for BootgenLoadingError {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
use BootgenLoadingError::*;
match self {
InvalidBootImageHeader => write!(
f,
"Invalid boot image header. Check if the file is correct."
),
MissingPartition => write!(f, "Partition not found. Check your compile configuration."),
EncryptedBitstream => write!(f, "Encrypted bitstream is not supported."),
IoError(e) => write!(f, "Error while reading: {}", e),
DevcError(e) => write!(f, "PCAP interface error: {}", e),
}
}
}
#[repr(C)]
struct PartitionHeader {
pub encrypted_length: u32,
pub unencrypted_length: u32,
pub word_length: u32,
pub dest_load_addr: u32,
pub dest_exec_addr: u32,
pub data_offset: u32,
pub attribute_bits: u32,
pub section_count: u32,
pub checksum_offset: u32,
pub header_offset: u32,
pub cert_offset: u32,
pub reserved: [u32; 4],
pub checksum: u32,
}
/// Read a u32 word from the reader.
fn read_u32<Reader: Read>(reader: &mut Reader) -> Result<u32, BootgenLoadingError> {
let mut buffer: [u8; 4] = [0; 4];
reader.read_exact(&mut buffer)?;
let mut result: u32 = 0;
for i in 0..4 {
result |= (buffer[i] as u32) << (i * 8);
}
Ok(result)
}
/// Load PL partition header.
fn load_pl_header<File: Read + Seek>(
file: &mut File,
) -> 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 & (2 << 4) != 0 {
Ok(Some(header))
} else {
Ok(None)
}
}
fn load_ps_header<File: Read + Seek>(
file: &mut File,
) -> 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;
// read boot header signature
file.seek(SeekFrom::Start(0x24))?;
if read_u32(file)? != BOOT_HEADER_SIGN {
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
file.seek(SeekFrom::Start(0x9C))?;
let ptr = read_u32(file)?;
debug!("Partition header pointer = {:0X}", ptr);
file.seek(SeekFrom::Start(ptr as u64))?;
// at most 3 partition headers
for _ in 0..3 {
if let Some(header) = f(file)? {
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(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);
}
}
Err(BootgenLoadingError::MissingPartition)
}
/// Load bitstream from bootgen file.
/// 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.
pub fn load_bitstream<File: Read + Seek>(file: &mut File) -> Result<(), BootgenLoadingError> {
let size = locate(file, load_pl_header)?;
unsafe {
// align to 64 bytes
let ptr = alloc::alloc::alloc(alloc::alloc::Layout::from_size_align(size, 64).unwrap());
let buffer = core::slice::from_raw_parts_mut(ptr, size);
file.read_exact(buffer).map_err(|e| {
core::ptr::drop_in_place(ptr);
e
})?;
let mut devcfg = devc::DevC::new();
devcfg.enable();
devcfg.program(&buffer).map_err(|e| {
core::ptr::drop_in_place(ptr);
e
})?;
core::ptr::drop_in_place(ptr);
Ok(())
}
}
pub fn get_runtime<File: Read + Seek>(file: &mut File) -> Result<Vec<u8>, BootgenLoadingError> {
let size = locate(file, load_ps_header)?;
let mut buffer = Vec::with_capacity(size);
unsafe {
buffer.set_len(size);
}
file.read_exact(&mut buffer)?;
Ok(buffer)
}

115
src/libconfig/src/lib.rs

@ -1,115 +0,0 @@
#![no_std]
extern crate alloc;
use core::fmt;
use alloc::{string::FromUtf8Error, string::String, vec::Vec, rc::Rc};
use core_io::{self as io, BufRead, BufReader, Read};
use libboard_zynq::sdio;
pub mod sd_reader;
pub mod net_settings;
pub mod bootgen;
#[derive(Debug)]
pub enum Error<'a> {
SdError(sdio::sd_card::CardInitializationError),
IoError(io::Error),
Utf8Error(FromUtf8Error),
KeyNotFoundError(&'a str),
NoConfig,
}
pub type Result<'a, T> = core::result::Result<T, Error<'a>>;
impl<'a> fmt::Display for Error<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Error::SdError(error) => write!(f, "SD error: {}", error),
Error::IoError(error) => write!(f, "I/O error: {}", error),
Error::Utf8Error(error) => write!(f, "UTF-8 error: {}", error),
Error::KeyNotFoundError(name) => write!(f, "Configuration key `{}` not found", name),
Error::NoConfig => write!(f, "Configuration not present"),
}
}
}
impl<'a> From<sdio::sd_card::CardInitializationError> for Error<'a> {
fn from(error: sdio::sd_card::CardInitializationError) -> Self {
Error::SdError(error)
}
}
impl<'a> From<io::Error> for Error<'a> {
fn from(error: io::Error) -> Self {
Error::IoError(error)
}
}
impl<'a> From<FromUtf8Error> for Error<'a> {
fn from(error: FromUtf8Error) -> Self {
Error::Utf8Error(error)
}
}
fn parse_config<'a>(
key: &'a str,
buffer: &mut Vec<u8>,
file: fatfs::File<sd_reader::SdReader>,
) -> Result<'a, ()> {
let prefix = [key, "="].concat();
for line in BufReader::new(file).lines() {
let line = line?;
if line.starts_with(&prefix) {
buffer.extend(line[prefix.len()..].as_bytes());
return Ok(());
}
}
Err(Error::KeyNotFoundError(key))
}
pub struct Config {
fs: Option<Rc<fatfs::FileSystem<sd_reader::SdReader>>>,
}
impl Config {
pub fn new() -> Result<'static, Self> {
let sdio = sdio::Sdio::sdio0(true);
if !sdio.is_card_inserted() {
Err(sdio::sd_card::CardInitializationError::NoCardInserted)?;
}
let sd = sdio::sd_card::SdCard::from_sdio(sdio)?;
let reader = sd_reader::SdReader::new(sd);
let fs = reader.mount_fatfs(sd_reader::PartitionEntry::Entry1)?;
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 {
Config { fs: None }
}
pub fn read<'b>(&self, key: &'b str) -> Result<'b, Vec<u8>> {
if let Some(fs) = &self.fs {
let root_dir = fs.root_dir();
let mut buffer: Vec<u8> = Vec::new();
match root_dir.open_file(&["/CONFIG/", key, ".BIN"].concat()) {
Ok(mut f) => f.read_to_end(&mut buffer).map(|_| ())?,
Err(_) => match root_dir.open_file("/CONFIG.TXT") {
Ok(f) => parse_config(key, &mut buffer, f)?,
Err(_) => return Err(Error::KeyNotFoundError(key)),
},
};
Ok(buffer)
} else {
Err(Error::NoConfig)
}
}
pub fn read_str<'b>(&self, key: &'b str) -> Result<'b, String> {
Ok(String::from_utf8(self.read(key)?)?)
}
}

62
src/libconfig/src/net_settings.rs

@ -1,62 +0,0 @@
use core::fmt;
use libboard_zynq::smoltcp::wire::{EthernetAddress, IpAddress};
use super::Config;
pub struct NetAddresses {
pub hardware_addr: EthernetAddress,
pub ipv4_addr: IpAddress,
#[cfg(feature = "ipv6")]
pub ipv6_ll_addr: IpAddress,
#[cfg(feature = "ipv6")]
pub ipv6_addr: Option<IpAddress>
}
impl fmt::Display for NetAddresses {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "MAC={} IPv4={} ",
self.hardware_addr, self.ipv4_addr)?;
#[cfg(feature = "ipv6")]
{
write!(f, "IPv6-LL={}", self.ipv6_ll_addr)?;
match self.ipv6_addr {
Some(addr) => write!(f, " {}", addr)?,
None => write!(f, " IPv6: no configured address")?
}
}
Ok(())
}
}
pub fn get_adresses(cfg: &Config) -> NetAddresses {
let mut hardware_addr = EthernetAddress([0x02, 0x00, 0x00, 0x00, 0x00, 0x52]);
let mut ipv4_addr = IpAddress::v4(192, 168, 1, 52);
if let Ok(Ok(addr)) = cfg.read_str("mac").map(|s| s.parse()) {
hardware_addr = addr;
}
if let Ok(Ok(addr)) = cfg.read_str("ip").map(|s| s.parse()) {
ipv4_addr = addr;
}
#[cfg(feature = "ipv6")]
let ipv6_addr = cfg.read_str("ipv6").ok().and_then(|s| s.parse().ok());
#[cfg(feature = "ipv6")]
let ipv6_ll_addr = IpAddress::v6(
0xfe80, 0x0000, 0x0000, 0x0000,
(((hardware_addr.0[0] ^ 0x02) as u16) << 8) | (hardware_addr.0[1] as u16),
((hardware_addr.0[2] as u16) << 8) | 0x00ff,
0xfe00 | (hardware_addr.0[3] as u16),
((hardware_addr.0[4] as u16) << 8) | (hardware_addr.0[5] as u16));
NetAddresses {
hardware_addr,
ipv4_addr,
#[cfg(feature = "ipv6")]
ipv6_ll_addr,
#[cfg(feature = "ipv6")]
ipv6_addr
}
}

303
src/libconfig/src/sd_reader.rs

@ -1,303 +0,0 @@
use core_io::{BufRead, Error, ErrorKind, Read, Result as IoResult, Seek, SeekFrom, Write};
use fatfs;
use libboard_zynq::sdio::{sd_card::SdCard, CmdTransferError};
use log::debug;
use alloc::vec::Vec;
const MBR_SIGNATURE: [u8; 2] = [0x55, 0xAA];
const PARTID_FAT12: u8 = 0x01;
const PARTID_FAT16_LESS32M: u8 = 0x04;
const PARTID_FAT16: u8 = 0x06;
const PARTID_FAT32: u8 = 0x0B;
const PARTID_FAT32_LBA: u8 = 0x0C;
fn cmd_error_to_io_error(_: CmdTransferError) -> Error {
Error::new(ErrorKind::Other, "Command transfer error")
}
const BLOCK_SIZE: usize = 512;
/// SdReader struct implementing `Read + BufRead + Write + Seek` traits for `core_io`.
/// Used as an adaptor for fatfs crate, but could be used directly for raw data access.
///
/// Implementation: all read/writes would be split into unaligned and block-aligned parts,
/// unaligned read/writes would do a buffered read/write using a block-sized internal buffer,
/// while aligned transactions would be sent to the SD card directly for performance reason.
pub struct SdReader {
/// Internal SdCard handle.
sd: SdCard,
/// Read buffer with the size of 1 block.
buffer: Vec<u8>,
/// Address for the next byte.
byte_addr: u32,
/// Internal index for the next byte.
/// Normally in range `[0, BLOCK_SIZE - 1]`.
///
/// `index = BLOCK_SIZE` means that the `buffer` is invalid for the current `byte_addr`,
/// the next `fill_buf` call would fill the buffer.
index: usize,
/// Dirty flag indicating the content has to be flushed.
dirty: bool,
/// Base offset for translation from logical address to physical address.
offset: u32,
}
#[derive(Copy, Clone)]
#[allow(unused)]
// Partition entry enum, normally we would use entry1.
pub enum PartitionEntry {
Entry1 = 0x1BE,
Entry2 = 0x1CE,
Entry3 = 0x1DE,
Entry4 = 0x1EE,
}
impl SdReader {
/// Create SdReader from SdCard
pub fn new(sd: SdCard) -> SdReader {
let mut vec: Vec<u8> = Vec::with_capacity(BLOCK_SIZE);
unsafe {
vec.set_len(vec.capacity());
}
SdReader {
sd,
buffer: vec,
byte_addr: 0,
index: BLOCK_SIZE,
dirty: false,
offset: 0,
}
}
/// Internal read function for unaligned read.
/// The read must not cross block boundary.
fn read_unaligned(&mut self, buf: &mut [u8]) -> IoResult<usize> {
if buf.len() == 0 {
return Ok(0);
}
let filled_buffer = self.fill_buf()?;
for (dest, src) in buf.iter_mut().zip(filled_buffer.iter()) {
*dest = *src;
}
self.consume(buf.len());
Ok(buf.len())
}
/// Internal write function for unaligned write.
/// The write must not cross block boundary.
fn write_unaligned(&mut self, buf: &[u8]) -> IoResult<usize> {
if buf.len() == 0 {
return Ok(0);
}
// update buffer if needed, as we will flush the entire block later.
self.fill_buf()?;
self.dirty = true;
let dest_buffer = &mut self.buffer[self.index..];
for (src, dest) in buf.iter().zip(dest_buffer.iter_mut()) {
*dest = *src;
}
self.consume(buf.len());
Ok(buf.len())
}
/// Split the slice into three segments, with the middle block-aligned.
/// Alignment depends on the current `self.byte_addr` instead of the slice pointer address
fn block_align<'b>(&self, buf: &'b [u8]) -> (&'b [u8], &'b [u8], &'b [u8]) {
let head_len = BLOCK_SIZE - (self.byte_addr as usize % BLOCK_SIZE);
if head_len > buf.len() {
(buf, &[], &[])
} else {
let remaining_length = buf.len() - head_len;
let mid_length = remaining_length - remaining_length % BLOCK_SIZE;
let (head, remaining) = buf.split_at(head_len);
let (mid, tail) = remaining.split_at(mid_length);
(head, mid, tail)
}
}
/// Split the mutable slice into three segments, with the middle block-aligned.
/// Alignment depends on the current `self.byte_addr` instead of the slice pointer address
fn block_align_mut<'b>(&self, buf: &'b mut [u8]) -> (&'b mut [u8], &'b mut [u8], &'b mut [u8]) {
let head_len = BLOCK_SIZE - (self.byte_addr as usize % BLOCK_SIZE);
if head_len > buf.len() {
(buf, &mut [], &mut [])
} else {
let remaining_length = buf.len() - head_len;
let mid_length = remaining_length - remaining_length % BLOCK_SIZE;
let (head, remaining) = buf.split_at_mut(head_len);
let (mid, tail) = remaining.split_at_mut(mid_length);
(head, mid, tail)
}
}
/// Invalidate the buffer, so later unaligned read/write would reload the buffer from SD card.
fn invalidate_buffer(&mut self) {
self.index = BLOCK_SIZE;
}
/// Set the base offset of the SD card, to transform from physical address to logical address.
fn set_base_offset(&mut self, offset: u32) -> IoResult<u64> {
self.offset = offset;
self.seek(SeekFrom::Start(0))
}
/// Mount fatfs from partition entry, and return the fatfs object if success.
/// This takes the ownership of self, so currently there is no way to recover from an error,
/// except creating a new SD card instance.
pub fn mount_fatfs(mut self, entry: PartitionEntry) -> IoResult<fatfs::FileSystem<Self>> {
let mut buffer: [u8; 4] = [0; 4];
self.seek(SeekFrom::Start(0x1FE))?;
self.read_exact(&mut buffer[..2])?;
// check MBR signature
if buffer[..2] != MBR_SIGNATURE {
return Err(Error::new(
ErrorKind::InvalidData,
"Incorrect signature for MBR sector.",
));
}
// Read partition ID.
self.seek(SeekFrom::Start(entry as u64 + 0x4))?;
self.read_exact(&mut buffer[..1])?;
debug!("Partition ID: {:0X}", buffer[0]);
match buffer[0] {
PARTID_FAT12 | PARTID_FAT16_LESS32M | PARTID_FAT16 |
PARTID_FAT32 | PARTID_FAT32_LBA => {}
_ => {
return Err(Error::new(
ErrorKind::InvalidData,
"No FAT partition found for the specified entry.",
));
}
}
// Read LBA
self.seek(SeekFrom::Current(0x3))?;
self.read_exact(&mut buffer)?;
let mut lba: u32 = 0;
// Little endian
for i in 0..4 {
lba |= (buffer[i] as u32) << (i * 8);
}
// Set to logical address
self.set_base_offset(lba * BLOCK_SIZE as u32)?;
// setup fatfs
fatfs::FileSystem::new(self, fatfs::FsOptions::new())
}
}
impl Read for SdReader {
fn read(&mut self, buf: &mut [u8]) -> IoResult<usize> {
let total_length = buf.len();
let (a, b, c) = self.block_align_mut(buf);
self.read_unaligned(a)?;
if b.len() > 0 {
// invalidate internal buffer
self.invalidate_buffer();
if let Err(_) = self.sd.read_block(
self.byte_addr / BLOCK_SIZE as u32,
(b.len() / BLOCK_SIZE) as u16,
b,
) {
// we have to allow partial read, as per the trait required
return Ok(a.len());
}
self.byte_addr += b.len() as u32;
}
if let Err(_) = self.read_unaligned(c) {
// we have to allow partial read, as per the trait required
return Ok(a.len() + b.len());
}
Ok(total_length)
}
}
impl BufRead for SdReader {
fn fill_buf(&mut self) -> IoResult<&[u8]> {
if self.index == BLOCK_SIZE {
// flush the buffer if it is dirty before overwriting it with new data
if self.dirty {
self.flush()?;
}
// reload buffer
self.sd
.read_block(self.byte_addr / (BLOCK_SIZE as u32), 1, &mut self.buffer)
.map_err(cmd_error_to_io_error)?;
self.index = (self.byte_addr as usize) % BLOCK_SIZE;
}
Ok(&self.buffer[self.index..])
}
fn consume(&mut self, amt: usize) {
self.index += amt;
self.byte_addr += amt as u32;
}
}
impl Write for SdReader {
fn write(&mut self, buf: &[u8]) -> IoResult<usize> {
let (a, b, c) = self.block_align(buf);
self.write_unaligned(a)?;
if b.len() > 0 {
self.flush()?;
self.invalidate_buffer();
if let Err(_) = self.sd.write_block(
self.byte_addr / BLOCK_SIZE as u32,
(b.len() / BLOCK_SIZE) as u16,
b,
) {
return Ok(a.len());
}
self.byte_addr += b.len() as u32;
}
if let Err(_) = self.write_unaligned(c) {
return Ok(a.len() + b.len());
}
Ok(buf.len())
}
fn flush(&mut self) -> IoResult<()> {
if self.dirty {
let block_addr = (self.byte_addr - self.index as u32) / (BLOCK_SIZE as u32);
self.sd
.write_block(block_addr, 1, &self.buffer)
.map_err(cmd_error_to_io_error)?;
self.dirty = false;
}
Ok(())
}
}
impl Seek for SdReader {
fn seek(&mut self, pos: SeekFrom) -> IoResult<u64> {
let raw_target = match pos {
SeekFrom::Start(x) => self.offset as i64 + x as i64,
SeekFrom::Current(x) => self.byte_addr as i64 + x,
SeekFrom::End(_) => panic!("SD card does not support seek from end"),
};
if raw_target < self.offset as i64 || raw_target > core::u32::MAX as i64 {
return Err(Error::new(ErrorKind::InvalidInput, "Invalid address"));
}
let target_byte_addr = raw_target as u32;
let address_same_block =
self.byte_addr / (BLOCK_SIZE as u32) == target_byte_addr / (BLOCK_SIZE as u32);
// if the buffer was invalidated, we consider seek as different block
let same_block = address_same_block && self.index != BLOCK_SIZE;
if !same_block {
self.flush()?;
}
self.byte_addr = target_byte_addr;
self.index = if same_block {
target_byte_addr as usize % BLOCK_SIZE
} else {
// invalidate the buffer as we moved to a different block
BLOCK_SIZE
};
Ok((self.byte_addr - self.offset) as u64)
}
}
impl Drop for SdReader {
fn drop(&mut self) {
// just try to flush it, ignore error if any
self.flush().unwrap_or(());
}
}

14
src/libcoreio/Cargo.toml

@ -1,14 +0,0 @@
[package]
authors = ["M-Labs"]
name = "core_io"
version = "0.1.20200410"
[lib]
name = "core_io"
[dependencies]
memchr = { version = "2", default-features = false, optional = true }
[features]
alloc = []
collections = ["alloc", "memchr"]

1674
src/libcoreio/src/io/buffered.rs
File diff suppressed because it is too large
View File

896
src/libcoreio/src/io/cursor.rs

@ -1,896 +0,0 @@
use crate::io::prelude::*;
use core::cmp;
use crate::io::{self, Error, ErrorKind, Initializer, SeekFrom};
#[cfg(feature = "collections")]
use core::convert::TryInto;
#[cfg(feature="collections")]
use collections::vec::Vec;
#[cfg(feature = "alloc")]
use alloc::boxed::Box;
/// A `Cursor` wraps an in-memory buffer and provides it with a
/// [`Seek`] implementation.
///
/// `Cursor`s are used with in-memory buffers, anything implementing
/// `AsRef<[u8]>`, to allow them to implement [`Read`] and/or [`Write`],
/// allowing these buffers to be used anywhere you might use a reader or writer
/// that does actual I/O.
///
/// The standard library implements some I/O traits on various types which
/// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and
/// `Cursor<`[`&[u8]`][bytes]`>`.
///
/// # Examples
///
/// We may want to write bytes to a [`File`] in our production
/// code, but use an in-memory buffer in our tests. We can do this with
/// `Cursor`:
///
/// [`Seek`]: trait.Seek.html
/// [`Read`]: ../../std/io/trait.Read.html
/// [`Write`]: ../../std/io/trait.Write.html
/// [`Vec`]: ../../std/vec/struct.Vec.html
/// [bytes]: ../../std/primitive.slice.html
/// [`File`]: ../fs/struct.File.html
///
/// ```no_run
/// use std::io::prelude::*;
/// use std::io::{self, SeekFrom};
/// use std::fs::File;
///
/// // a library function we've written
/// fn write_ten_bytes_at_end<W: Write + Seek>(writer: &mut W) -> io::Result<()> {
/// writer.seek(SeekFrom::End(-10))?;
///
/// for i in 0..10 {
/// writer.write(&[i])?;
/// }
///
/// // all went well
/// Ok(())
/// }
///
/// # fn foo() -> io::Result<()> {
/// // Here's some code that uses this library function.
/// //
/// // We might want to use a BufReader here for efficiency, but let's
/// // keep this example focused.
/// let mut file = File::create("foo.txt")?;
///
/// write_ten_bytes_at_end(&mut file)?;
/// # Ok(())
/// # }
///
/// // now let's write a test
/// #[test]
/// fn test_writes_bytes() {
/// // setting up a real File is much slower than an in-memory buffer,
/// // let's use a cursor instead
/// use std::io::Cursor;
/// let mut buff = Cursor::new(vec![0; 15]);
///
/// write_ten_bytes_at_end(&mut buff).unwrap();
///
/// assert_eq!(&buff.get_ref()[5..15], &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
/// }
/// ```
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Cursor<T> {
inner: T,
pos: u64,
}
impl<T> Cursor<T> {
/// Creates a new cursor wrapping the provided underlying in-memory buffer.
///
/// Cursor initial position is `0` even if underlying buffer (e.g., `Vec`)
/// is not empty. So writing to cursor starts with overwriting `Vec`
/// content, not with appending to it.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
/// ```
pub fn new(inner: T) -> Cursor<T> {
Cursor { pos: 0, inner }
}
/// Consumes this cursor, returning the underlying value.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
///
/// let vec = buff.into_inner();
/// ```
pub fn into_inner(self) -> T {
self.inner
}
/// Gets a reference to the underlying value in this cursor.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
///
/// let reference = buff.get_ref();
/// ```
pub fn get_ref(&self) -> &T {
&self.inner
}
/// Gets a mutable reference to the underlying value in this cursor.
///
/// Care should be taken to avoid modifying the internal I/O state of the
/// underlying value as it may corrupt this cursor's position.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let mut buff = Cursor::new(Vec::new());
/// # fn force_inference(_: &Cursor<Vec<u8>>) {}
/// # force_inference(&buff);
///
/// let reference = buff.get_mut();
/// ```
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
/// Returns the current position of this cursor.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
/// use std::io::prelude::*;
/// use std::io::SeekFrom;
///
/// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
///
/// assert_eq!(buff.position(), 0);
///
/// buff.seek(SeekFrom::Current(2)).unwrap();
/// assert_eq!(buff.position(), 2);
///
/// buff.seek(SeekFrom::Current(-1)).unwrap();
/// assert_eq!(buff.position(), 1);
/// ```
pub fn position(&self) -> u64 {
self.pos
}
/// Sets the position of this cursor.
///
/// # Examples
///
/// ```
/// use std::io::Cursor;
///
/// let mut buff = Cursor::new(vec![1, 2, 3, 4, 5]);
///
/// assert_eq!(buff.position(), 0);
///
/// buff.set_position(2);
/// assert_eq!(buff.position(), 2);
///
/// buff.set_position(4);
/// assert_eq!(buff.position(), 4);
/// ```
pub fn set_position(&mut self, pos: u64) {
self.pos = pos;
}
}
impl<T> io::Seek for Cursor<T>
where
T: AsRef<[u8]>,
{
fn seek(&mut self, style: SeekFrom) -> io::Result<u64> {
let (base_pos, offset) = match style {
SeekFrom::Start(n) => {
self.pos = n;
return Ok(n);
}
SeekFrom::End(n) => (self.inner.as_ref().len() as u64, n),
SeekFrom::Current(n) => (self.pos, n),
};
let new_pos = if offset >= 0 {
base_pos.checked_add(offset as u64)
} else {
base_pos.checked_sub((offset.wrapping_neg()) as u64)
};
match new_pos {
Some(n) => {
self.pos = n;
Ok(self.pos)
}
None => Err(Error::new(
ErrorKind::InvalidInput,
"invalid seek to a negative or overflowing position",
)),
}
}
fn stream_len(&mut self) -> io::Result<u64> {
Ok(self.inner.as_ref().len() as u64)
}
fn stream_position(&mut self) -> io::Result<u64> {
Ok(self.pos)
}
}
impl<T> Read for Cursor<T>
where
T: AsRef<[u8]>,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n = Read::read(&mut self.get_ref().as_ref(), buf)?;
self.pos += n as u64;
Ok(n)
}
fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
let n = buf.len();
Read::read_exact(&mut self.get_ref().as_ref(), buf)?;
self.pos += n as u64;
Ok(())
}
#[inline]
unsafe fn initializer(&self) -> Initializer {
Initializer::nop()
}
}
#[cfg(feature = "collections")]
impl<T> BufRead for Cursor<T>
where
T: AsRef<[u8]>,
{
fn fill_buf(&mut self) -> io::Result<&[u8]> {
let amt = cmp::min(self.pos, self.inner.as_ref().len() as u64);
Ok(&self.inner.as_ref()[(amt as usize)..])
}
fn consume(&mut self, amt: usize) {
self.pos += amt as u64;
}
}
// Non-resizing write implementation
#[inline]
fn slice_write(pos_mut: &mut u64, slice: &mut [u8], buf: &[u8]) -> io::Result<usize> {
let pos = cmp::min(*pos_mut, slice.len() as u64);
let amt = (&mut slice[(pos as usize)..]).write(buf)?;
*pos_mut += amt as u64;
Ok(amt)
}
// Resizing write implementation
#[cfg(feature = "collections")]
fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
let pos: usize = (*pos_mut).try_into().map_err(|_| {
Error::new(
ErrorKind::InvalidInput,
"cursor position exceeds maximum possible vector length",
)
})?;
// Make sure the internal buffer is as least as big as where we
// currently are
let len = vec.len();
if len < pos {
// use `resize` so that the zero filling is as efficient as possible
vec.resize(pos, 0);
}
// Figure out what bytes will be used to overwrite what's currently
// there (left), and what will be appended on the end (right)
{
let space = vec.len() - pos;
let (left, right) = buf.split_at(cmp::min(space, buf.len()));
vec[pos..pos + left.len()].copy_from_slice(left);
vec.extend_from_slice(right);
}
// Bump us forward
*pos_mut = (pos + buf.len()) as u64;
Ok(buf.len())
}
impl Write for Cursor<&mut [u8]> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
slice_write(&mut self.pos, self.inner, buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(feature = "collections")]
impl Write for Cursor<&mut Vec<u8>> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
vec_write(&mut self.pos, self.inner, buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(feature = "collections")]
impl Write for Cursor<Vec<u8>> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
vec_write(&mut self.pos, &mut self.inner, buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(feature = "alloc")]
impl Write for Cursor<Box<[u8]>> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
slice_write(&mut self.pos, &mut self.inner, buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::io::prelude::*;
use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom};
#[test]
fn test_vec_writer() {
let mut writer = Vec::new();
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
.unwrap(),
3
);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(writer, b);
}
#[test]
fn test_mem_writer() {
let mut writer = Cursor::new(Vec::new());
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
.unwrap(),
3
);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
assert_eq!(&writer.get_ref()[..], b);
}
#[test]
fn test_mem_mut_writer() {
let mut vec = Vec::new();
let mut writer = Cursor::new(&mut vec);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],)
.unwrap(),
3
);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];