Compare commits

..

No commits in common. "92ae487143e24e5fbafd2ee3689603174a8d92d6" and "c28c567e72b214b525328db63af439cdd2bd31d2" have entirely different histories.

9 changed files with 143 additions and 174 deletions

12
firmware/Cargo.lock generated
View File

@ -153,7 +153,7 @@ dependencies = [
[[package]] [[package]]
name = "libasync" name = "libasync"
version = "0.0.0" version = "0.0.0"
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#d86f69a2539a9b76575caee0f665829c488ea962" source = "git+https://git.m-labs.hk/M-Labs/zc706.git#008a9954292980b34fc20cc519a19e92b4ac077d"
dependencies = [ dependencies = [
"embedded-hal", "embedded-hal",
"libcortex_a9", "libcortex_a9",
@ -165,13 +165,12 @@ dependencies = [
[[package]] [[package]]
name = "libboard_zynq" name = "libboard_zynq"
version = "0.0.0" version = "0.0.0"
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#d86f69a2539a9b76575caee0f665829c488ea962" source = "git+https://git.m-labs.hk/M-Labs/zc706.git#008a9954292980b34fc20cc519a19e92b4ac077d"
dependencies = [ dependencies = [
"bit_field", "bit_field",
"embedded-hal", "embedded-hal",
"libcortex_a9", "libcortex_a9",
"libregister", "libregister",
"log",
"nb", "nb",
"smoltcp", "smoltcp",
"void", "void",
@ -181,7 +180,7 @@ dependencies = [
[[package]] [[package]]
name = "libcortex_a9" name = "libcortex_a9"
version = "0.0.0" version = "0.0.0"
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#d86f69a2539a9b76575caee0f665829c488ea962" source = "git+https://git.m-labs.hk/M-Labs/zc706.git#008a9954292980b34fc20cc519a19e92b4ac077d"
dependencies = [ dependencies = [
"bit_field", "bit_field",
"libregister", "libregister",
@ -190,7 +189,7 @@ dependencies = [
[[package]] [[package]]
name = "libregister" name = "libregister"
version = "0.0.0" version = "0.0.0"
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#d86f69a2539a9b76575caee0f665829c488ea962" source = "git+https://git.m-labs.hk/M-Labs/zc706.git#008a9954292980b34fc20cc519a19e92b4ac077d"
dependencies = [ dependencies = [
"bit_field", "bit_field",
"vcell", "vcell",
@ -200,13 +199,14 @@ dependencies = [
[[package]] [[package]]
name = "libsupport_zynq" name = "libsupport_zynq"
version = "0.0.0" version = "0.0.0"
source = "git+https://git.m-labs.hk/M-Labs/zc706.git#d86f69a2539a9b76575caee0f665829c488ea962" source = "git+https://git.m-labs.hk/M-Labs/zc706.git#008a9954292980b34fc20cc519a19e92b4ac077d"
dependencies = [ dependencies = [
"compiler_builtins", "compiler_builtins",
"libboard_zynq", "libboard_zynq",
"libcortex_a9", "libcortex_a9",
"libregister", "libregister",
"linked_list_allocator", "linked_list_allocator",
"log",
"r0", "r0",
] ]

View File

@ -1 +1 @@
"199qfs7fbbj8kxkyb0dcns6hdq9hvlppk7l3pnz204j9zkd7dkcp" "1mfprkcq4cr4jiihy1qn8q8qymxwhafh90vyr3i4brj4aq5kksn1"

View File

@ -1,4 +1,4 @@
use core::{mem, ptr, ops::{Deref, Range}}; use core::{mem, ptr, fmt, slice, str, convert, ops::{Deref, Range}};
use super::{ use super::{
Arch, Arch,
elf::*, elf::*,

View File

@ -9,15 +9,64 @@ use super::{
Error, Error,
}; };
pub struct DynamicSection { fn elf_hash(name: &[u8]) -> u32 {
pub strtab: Range<usize>, let mut h: u32 = 0;
pub symtab: Range<usize>, for c in name {
pub hash: Range<usize>, h = (h << 4) + *c as u32;
pub hash_bucket: Range<usize>, let g = h & 0xf0000000;
pub hash_chain: Range<usize>, if g != 0 {
pub rel: Range<usize>, h ^= g >> 24;
pub rela: Range<usize>, h &= !g;
pub pltrel: Range<usize>, }
}
h
}
pub struct DynamicSection<'a> {
pub strtab: &'a [u8],
pub symtab: &'a [Elf32_Sym],
pub hash_bucket: &'a [Elf32_Word],
pub hash_chain: &'a [Elf32_Word],
pub rel: &'a [Elf32_Rel],
pub rela: &'a [Elf32_Rela],
pub pltrel: &'a [Elf32_Rel],
}
impl<'a> DynamicSection<'a> {
pub fn lookup(&self, name: &[u8]) -> Option<Elf32_Word> {
let hash = elf_hash(name);
let mut index = self.hash_bucket[hash as usize % self.hash_bucket.len()] as usize;
loop {
if index == STN_UNDEF { return None }
let sym = &self.symtab[index];
let sym_name_off = sym.st_name as usize;
match self.strtab.get(sym_name_off..sym_name_off + name.len()) {
Some(sym_name) if sym_name == name => {
if ELF32_ST_BIND(sym.st_info) & STB_GLOBAL == 0 {
return None
}
match sym.st_shndx {
SHN_UNDEF => return None,
SHN_ABS => return Some(sym.st_value),
_ => return Some(sym.st_value)
}
}
_ => (),
}
index = self.hash_chain[index] as usize;
}
}
pub fn name_starting_at(&self, offset: usize) -> Result<&'a [u8], Error> {
let size = self.strtab.iter().skip(offset).position(|&x| x == 0)
.ok_or("symbol in symbol table not null-terminated")?;
Ok(self.strtab.get(offset..offset + size)
.ok_or("cannot read symbol name")?)
}
} }
/// target memory image /// target memory image
@ -41,7 +90,7 @@ impl Image {
} }
/// assumes that self.data is properly aligned /// assumes that self.data is properly aligned
pub(crate) fn get_ref<T>(&self, offset: usize) -> Option<&T> pub fn get_ref<T>(&self, offset: usize) -> Option<&T>
where where
T: Copy, T: Copy,
{ {
@ -55,15 +104,15 @@ impl Image {
} }
} }
/// assumes that self.data is properly aligned fn get_ref_slice<T: Copy>(&self, offset: usize, len: usize) -> Option<&[T]> {
/// if self.data.len() < offset + mem::size_of::<T>() * len {
/// range: in bytes None
pub(crate) fn get_ref_slice_unchecked<T: Copy>(&self, range: &Range<usize>) -> &[T] { } else if (self.data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 {
let offset = range.start; None
let len = (range.end - range.start) / mem::size_of::<T>(); } else {
let ptr = self.data.as_ptr().wrapping_offset(offset as isize) as *const T; let ptr = self.data.as_ptr().wrapping_offset(offset as isize) as *const T;
unsafe { slice::from_raw_parts(ptr, len) } Some(unsafe { slice::from_raw_parts(ptr, len) })
}
} }
fn dyn_headers<'a>(&'a self, range: Range<usize>) -> fn dyn_headers<'a>(&'a self, range: Range<usize>) ->
@ -99,13 +148,13 @@ impl Image {
DT_SYMTAB => symtab_off = val, DT_SYMTAB => symtab_off = val,
DT_SYMENT => sym_ent = val, DT_SYMENT => sym_ent = val,
DT_REL => rel_off = val, DT_REL => rel_off = val,
DT_RELSZ => rel_sz = val, DT_RELSZ => rel_sz = val / mem::size_of::<Elf32_Rel>(),
DT_RELENT => rel_ent = val, DT_RELENT => rel_ent = val,
DT_RELA => rela_off = val, DT_RELA => rela_off = val,
DT_RELASZ => rela_sz = val, DT_RELASZ => rela_sz = val / mem::size_of::<Elf32_Rela>(),
DT_RELAENT => rela_ent = val, DT_RELAENT => rela_ent = val,
DT_JMPREL => pltrel_off = val, DT_JMPREL => pltrel_off = val,
DT_PLTRELSZ => pltrel_sz = val, DT_PLTRELSZ => pltrel_sz = val / mem::size_of::<Elf32_Rel>(),
DT_HASH => { DT_HASH => {
nbucket = *self.get_ref::<Elf32_Word>(val + 0) nbucket = *self.get_ref::<Elf32_Word>(val + 0)
.ok_or("cannot read hash bucket count")? as usize; .ok_or("cannot read hash bucket count")? as usize;
@ -118,44 +167,44 @@ impl Image {
} }
} }
if strtab_off + strtab_sz > self.data.len() {
return Err("invalid strtab offset/size")?
}
if symtab_off + symtab_sz > self.data.len() {
return Err("invalid symtab offset/size")?
}
if sym_ent != mem::size_of::<Elf32_Sym>() { if sym_ent != mem::size_of::<Elf32_Sym>() {
return Err("incorrect symbol entry size")? return Err("incorrect symbol entry size")?
} }
if rel_off + rel_sz > self.data.len() {
return Err("invalid rel offset/size")?
}
if rel_ent != 0 && rel_ent != mem::size_of::<Elf32_Rel>() { if rel_ent != 0 && rel_ent != mem::size_of::<Elf32_Rel>() {
return Err("incorrect relocation entry size")? return Err("incorrect relocation entry size")?
} }
if rela_off + rela_sz > self.data.len() {
return Err("invalid rela offset/size")?
}
if rela_ent != 0 && rela_ent != mem::size_of::<Elf32_Rela>() { if rela_ent != 0 && rela_ent != mem::size_of::<Elf32_Rela>() {
return Err("incorrect relocation entry size")? return Err("incorrect relocation entry size")?
} }
if pltrel_off + pltrel_sz > self.data.len() {
return Err("invalid pltrel offset/size")?
}
// These are the same--there are as many chains as buckets, and the chains only contain // These are the same--there are as many chains as buckets, and the chains only contain
// the symbols that overflowed the bucket. // the symbols that overflowed the bucket.
symtab_sz = nchain; symtab_sz = nchain;
let hash = self.get_ref_slice::<Elf32_Word>(hash_off, hash_sz)
.ok_or("cannot read hash entries")?;
let strtab = self.get_ref_slice(strtab_off, strtab_sz)
.ok_or("cannot read string table")?;
let symtab = self.get_ref_slice::<Elf32_Sym>(symtab_off, symtab_sz)
.ok_or("cannot read symbol table")?;
let hash_bucket = &hash[..nbucket];
let hash_chain = &hash[nbucket..nbucket + nchain];
let rel = self.get_ref_slice::<Elf32_Rel>(rel_off, rel_sz)
.ok_or("cannot read rel entries")?;
let rela = self.get_ref_slice::<Elf32_Rela>(rela_off, rela_sz)
.ok_or("cannot read rela entries")?;
let pltrel = self.get_ref_slice::<Elf32_Rel>(pltrel_off, pltrel_sz)
.ok_or("cannot read pltrel entries")?;
// debug!("ELF: {} rela, {} rel, {} pltrel entries", rela_sz, rel_sz, pltrel_sz);
Ok(DynamicSection { Ok(DynamicSection {
strtab: strtab_off..strtab_off + strtab_sz, strtab,
symtab: symtab_off..symtab_off + symtab_sz, symtab,
hash: hash_off..hash_off + hash_sz, hash_bucket,
hash_bucket: 0..nbucket, hash_chain,
hash_chain: nbucket..nbucket + nchain, rel,
rel: rel_off..rel_off + rel_sz, rela,
rela: rela_off..rela_off + rela_sz, pltrel,
pltrel: pltrel_off..pltrel_off + rela_sz,
}) })
} }

View File

@ -3,9 +3,9 @@
extern crate alloc; extern crate alloc;
extern crate log; extern crate log;
use core::{fmt, str, convert}; use core::{mem, ptr, fmt, slice, str, convert, ops::Range};
use alloc::string::String; use alloc::string::String;
use log::{info, trace}; use log::{info, trace, error};
use elf::*; use elf::*;
pub mod elf; pub mod elf;
@ -44,90 +44,16 @@ impl fmt::Display for Error {
} }
} }
fn elf_hash(name: &[u8]) -> u32 {
let mut h: u32 = 0;
for c in name {
h = (h << 4) + *c as u32;
let g = h & 0xf0000000;
if g != 0 {
h ^= g >> 24;
h &= !g;
}
}
h
}
pub struct Library { pub struct Library {
image: Image, image: Image,
dyn_section: DynamicSection, dyn_range: Range<usize>,
dyn_section: DynamicSection<'static>,
} }
impl Library { impl Library {
fn strtab(&self) -> &[u8] { pub fn lookup(&self, name: &[u8]) -> Option<u32> {
self.image.get_ref_slice_unchecked(&self.dyn_section.strtab) self.dyn_section.lookup(name)
} .map(|addr| self.image.ptr() as u32 + addr)
fn symtab(&self) -> &[Elf32_Sym] {
self.image.get_ref_slice_unchecked(&self.dyn_section.symtab)
}
fn hash(&self) -> &[Elf32_Word] {
self.image.get_ref_slice_unchecked(&self.dyn_section.hash)
}
fn hash_bucket(&self) -> &[Elf32_Word] {
&self.hash()[self.dyn_section.hash_bucket.clone()]
}
fn hash_chain(&self) -> &[Elf32_Word] {
&self.hash()[self.dyn_section.hash_chain.clone()]
}
fn rel(&self) -> &[Elf32_Rel] {
self.image.get_ref_slice_unchecked(&self.dyn_section.rel)
}
fn rela(&self) -> &[Elf32_Rela] {
self.image.get_ref_slice_unchecked(&self.dyn_section.rela)
}
fn pltrel(&self) -> &[Elf32_Rel] {
self.image.get_ref_slice_unchecked(&self.dyn_section.pltrel)
}
pub fn lookup(&self, name: &[u8]) -> Option<Elf32_Word> {
let hash = elf_hash(name);
let mut index = self.hash_bucket()[hash as usize % self.hash_bucket().len()] as usize;
loop {
if index == STN_UNDEF { return None }
let sym = &self.symtab()[index];
let sym_name_off = sym.st_name as usize;
match self.strtab().get(sym_name_off..sym_name_off + name.len()) {
Some(sym_name) if sym_name == name => {
if ELF32_ST_BIND(sym.st_info) & STB_GLOBAL == 0 {
return None
}
match sym.st_shndx {
SHN_UNDEF => return None,
SHN_ABS => return Some(self.image.ptr() as u32 + sym.st_value),
_ => return Some(self.image.ptr() as u32 + sym.st_value)
}
}
_ => (),
}
index = self.hash_chain()[index] as usize;
}
}
pub fn name_starting_at(&self, offset: usize) -> Result<&[u8], Error> {
let size = self.strtab().iter().skip(offset).position(|&x| x == 0)
.ok_or("symbol in symbol table not null-terminated")?;
Ok(self.strtab().get(offset..offset + size)
.ok_or("cannot read symbol name")?)
} }
} }
@ -187,20 +113,23 @@ pub fn load(
let dyn_section = image.dyn_section(dyn_range.clone())?; let dyn_section = image.dyn_section(dyn_range.clone())?;
info!("Relocating {} rela, {} rel, {} pltrel", info!("Relocating {} rela, {} rel, {} pltrel",
dyn_section.rela.len(), dyn_section.rel.len(), dyn_section.pltrel.len()); dyn_section.rela.len(), dyn_section.rel.len(), dyn_section.pltrel.len());
let lib = Library {
image, for rela in dyn_section.rela {
dyn_section, reloc::relocate(arch, &image, &dyn_section, rela, resolve)?;
}
for rel in dyn_section.rela {
reloc::relocate(arch, &image, &dyn_section, rel, resolve)?;
}
for pltrel in dyn_section.pltrel {
reloc::relocate(arch, &image, &dyn_section, pltrel, resolve)?;
}
let dyn_section = unsafe {
core::mem::transmute(dyn_section)
}; };
Ok(Library {
for rela in lib.rela() { image,
reloc::relocate(arch, &lib, rela, resolve)?; dyn_range,
} dyn_section,
for rel in lib.rel() { })
reloc::relocate(arch, &lib, rel, resolve)?;
}
for pltrel in lib.pltrel() {
reloc::relocate(arch, &lib, pltrel, resolve)?;
}
Ok(lib)
} }

View File

@ -4,8 +4,7 @@ use super::{
Arch, Arch,
elf::*, elf::*,
Error, Error,
image::Image, image::{DynamicSection, Image},
Library,
}; };
pub trait Relocatable { pub trait Relocatable {
@ -88,16 +87,16 @@ fn format_sym_name(sym_name: &[u8]) -> String {
.unwrap_or(String::from("<invalid symbol name>")) .unwrap_or(String::from("<invalid symbol name>"))
} }
pub fn relocate<R: Relocatable>( pub fn relocate<'a, R: Relocatable>(
arch: Arch, lib: &Library, arch: Arch, image: &'a Image, dynamic_section: &'a DynamicSection<'a>,
rel: &R, resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word> rel: &'a R, resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>
) -> Result<(), Error> { ) -> Result<(), Error> {
// debug!("rel r_offset={:08X} r_info={:08X} r_addend={:08X}", rel.offset(), rel.r_info, rela.r_addend); // debug!("rel r_offset={:08X} r_info={:08X} r_addend={:08X}", rel.offset(), rel.r_info, rela.r_addend);
let sym; let sym;
if rel.sym_info() == 0 { if rel.sym_info() == 0 {
sym = None; sym = None;
} else { } else {
sym = Some(lib.symtab().get(rel.sym_info() as usize) sym = Some(dynamic_section.symtab.get(rel.sym_info() as usize)
.ok_or("symbol out of bounds of symbol table")?) .ok_or("symbol out of bounds of symbol table")?)
} }
@ -109,18 +108,18 @@ pub fn relocate<R: Relocatable>(
return Ok(()), return Ok(()),
RelType::Relative => { RelType::Relative => {
let addend = rel.addend(&lib.image); let addend = rel.addend(image);
value = lib.image.ptr().wrapping_offset(addend as isize) as Elf32_Word; value = image.ptr().wrapping_offset(addend as isize) as Elf32_Word;
} }
RelType::Lookup => { RelType::Lookup => {
let sym = sym.ok_or("relocation requires an associated symbol")?; let sym = sym.ok_or("relocation requires an associated symbol")?;
let sym_name = lib.name_starting_at(sym.st_name as usize)?; let sym_name = dynamic_section.name_starting_at(sym.st_name as usize)?;
if let Some(addr) = lib.lookup(sym_name) { if let Some(addr) = dynamic_section.lookup(sym_name) {
// First, try to resolve against itself. // First, try to resolve against itself.
trace!("looked up symbol {} in image", format_sym_name(sym_name)); trace!("looked up symbol {} in image", format_sym_name(sym_name));
value = lib.image.ptr() as u32 + addr; value = image.ptr() as u32 + addr;
} else if let Some(addr) = resolve(sym_name) { } else if let Some(addr) = resolve(sym_name) {
// Second, call the user-provided function. // Second, call the user-provided function.
trace!("resolved symbol {:?}", format_sym_name(sym_name)); trace!("resolved symbol {:?}", format_sym_name(sym_name));
@ -133,5 +132,5 @@ pub fn relocate<R: Relocatable>(
} }
debug!("rel_type={:?} write at {:08X} value {:08X}", rel_type, rel.offset(), value); debug!("rel_type={:?} write at {:08X} value {:08X}", rel_type, rel.offset(), value);
lib.image.write(rel.offset(), value) image.write(rel.offset(), value)
} }

View File

@ -107,15 +107,8 @@ async fn handle_connection(stream: &TcpStream, control: Rc<RefCell<kernel::Contr
expect(&stream, b"ARTIQ coredev\n").await?; expect(&stream, b"ARTIQ coredev\n").await?;
debug!("received connection"); debug!("received connection");
loop { loop {
match expect(&stream, &[0x5a, 0x5a, 0x5a, 0x5a]).await { if !expect(&stream, &[0x5a, 0x5a, 0x5a, 0x5a]).await? {
Ok(true) => {} return Err(Error::UnexpectedPattern)
Ok(false) =>
return Err(Error::UnexpectedPattern),
// peer has closed the connection
Err(smoltcp::Error::Illegal) =>
return Ok(()),
Err(e) =>
return Err(e)?,
} }
let request: Request = FromPrimitive::from_i8(read_i8(&stream).await?) let request: Request = FromPrimitive::from_i8(read_i8(&stream).await?)
.ok_or(Error::UnrecognizedPacket)?; .ok_or(Error::UnrecognizedPacket)?;

View File

@ -8,8 +8,8 @@ extern crate log;
use core::{cmp, str}; use core::{cmp, str};
use log::info; use log::info;
use libboard_zynq::{logger, timer::GlobalTimer}; use libboard_zynq::timer::GlobalTimer;
use libsupport_zynq::ram; use libsupport_zynq::{logger, ram};
mod proto; mod proto;
mod comms; mod comms;

View File

@ -9,10 +9,9 @@ use cstr_core::CStr;
use libboard_zynq::{ use libboard_zynq::{
self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll, IoPll}, self as zynq, clocks::Clocks, clocks::source::{ClockSource, ArmPll, IoPll},
logger,
timer::GlobalTimer, timer::GlobalTimer,
}; };
use libsupport_zynq::boot; use libsupport_zynq::{boot, logger};
extern "C" { extern "C" {