firmware: create and apply rustfmt policy
Co-authored-by: Egor Savkin <es@m-labs.hk> Co-committed-by: Egor Savkin <es@m-labs.hk>
This commit was merged in pull request #221.
This commit is contained in:
19
flake.nix
19
flake.nix
@@ -253,6 +253,23 @@
|
||||
'';
|
||||
};
|
||||
|
||||
fmt-check = pkgs.stdenv.mkDerivation {
|
||||
name = "fmt-check";
|
||||
|
||||
nativeBuildInputs = [
|
||||
rustPlatform.rust.cargo
|
||||
];
|
||||
|
||||
phases = [ "buildPhase" ];
|
||||
|
||||
buildPhase =
|
||||
''
|
||||
cd ${self}/src
|
||||
cargo fmt -- --check
|
||||
touch $out
|
||||
'';
|
||||
};
|
||||
|
||||
# for hitl-tests
|
||||
zc706-nist_qc2 = (build { target = "zc706"; variant = "nist_qc2"; });
|
||||
zc706-hitl-tests = pkgs.stdenv.mkDerivation {
|
||||
@@ -341,7 +358,7 @@
|
||||
(build { target = "kasli_soc"; variant = "master"; json = ./kasli-soc-master.json; }) //
|
||||
(build { target = "kasli_soc"; variant = "satellite"; json = ./kasli-soc-satellite.json; });
|
||||
|
||||
hydraJobs = packages.x86_64-linux // { inherit zc706-hitl-tests; inherit gateware-sim; };
|
||||
hydraJobs = packages.x86_64-linux // { inherit zc706-hitl-tests; inherit gateware-sim; inherit fmt-check; };
|
||||
|
||||
devShell.x86_64-linux = pkgs.mkShell {
|
||||
name = "artiq-zynq-dev-shell";
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use libconfig::Config;
|
||||
#[cfg(has_drtio_routing)]
|
||||
use crate::pl::csr;
|
||||
use core::fmt;
|
||||
|
||||
use log::{warn, info};
|
||||
use libconfig::Config;
|
||||
use log::{info, warn};
|
||||
|
||||
#[cfg(has_drtio_routing)]
|
||||
use crate::pl::csr;
|
||||
|
||||
#[cfg(has_drtio_routing)]
|
||||
pub const DEST_COUNT: usize = 256;
|
||||
@@ -18,7 +19,7 @@ impl RoutingTable {
|
||||
// default routing table is for star topology with no repeaters
|
||||
pub fn default_master(default_n_links: usize) -> RoutingTable {
|
||||
let mut ret = RoutingTable([[INVALID_HOP; MAX_HOPS]; DEST_COUNT]);
|
||||
let n_entries = default_n_links + 1; // include local RTIO
|
||||
let n_entries = default_n_links + 1; // include local RTIO
|
||||
for i in 0..n_entries {
|
||||
ret.0[i][0] = i as u8;
|
||||
}
|
||||
@@ -58,10 +59,10 @@ impl fmt::Display for RoutingTable {
|
||||
pub fn config_routing_table(default_n_links: usize, cfg: &Config) -> RoutingTable {
|
||||
let mut ret = RoutingTable::default_master(default_n_links);
|
||||
if let Ok(data) = cfg.read("routing_table") {
|
||||
if data.len() == DEST_COUNT*MAX_HOPS {
|
||||
if data.len() == DEST_COUNT * MAX_HOPS {
|
||||
for i in 0..DEST_COUNT {
|
||||
for j in 0..MAX_HOPS {
|
||||
ret.0[i][j] = data[i*MAX_HOPS+j];
|
||||
ret.0[i][j] = data[i * MAX_HOPS + j];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
|
||||
use crc;
|
||||
|
||||
use core_io::{ErrorKind as IoErrorKind, Error as IoError};
|
||||
use io::{proto::ProtoRead, proto::ProtoWrite, Cursor};
|
||||
use libboard_zynq::{timer::GlobalTimer, time::Milliseconds};
|
||||
use io::{proto::{ProtoRead, ProtoWrite},
|
||||
Cursor};
|
||||
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
||||
use libcortex_a9::asm::dmb;
|
||||
use crate::mem::mem::DRTIOAUX_MEM;
|
||||
use crate::pl::csr::DRTIOAUX;
|
||||
use crate::drtioaux_proto::Error as ProtocolError;
|
||||
|
||||
pub use crate::drtioaux_proto::Packet;
|
||||
use crate::{drtioaux_proto::Error as ProtocolError, mem::mem::DRTIOAUX_MEM, pl::csr::DRTIOAUX};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
@@ -21,7 +19,7 @@ pub enum Error {
|
||||
|
||||
RoutingError,
|
||||
|
||||
Protocol(ProtocolError)
|
||||
Protocol(ProtocolError),
|
||||
}
|
||||
|
||||
impl From<ProtocolError> for Error {
|
||||
@@ -63,7 +61,7 @@ pub fn copy_work_buffer(src: *mut u32, dst: *mut u32, len: isize) {
|
||||
// and AXI burst reads/writes are not implemented yet in gateware
|
||||
// thus the need for a work buffer for transmitting and copying it over
|
||||
unsafe {
|
||||
for i in 0..(len/4) {
|
||||
for i in 0..(len / 4) {
|
||||
*dst.offset(i) = *src.offset(i);
|
||||
//data memory barrier to prevent bursts
|
||||
dmb();
|
||||
@@ -72,8 +70,7 @@ pub fn copy_work_buffer(src: *mut u32, dst: *mut u32, len: isize) {
|
||||
}
|
||||
|
||||
fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
|
||||
where F: FnOnce(&[u8]) -> Result<T, Error>
|
||||
{
|
||||
where F: FnOnce(&[u8]) -> Result<T, Error> {
|
||||
let linkidx = linkno as usize;
|
||||
unsafe {
|
||||
if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 {
|
||||
@@ -93,12 +90,12 @@ fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
|
||||
|
||||
pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||
if has_rx_error(linkno) {
|
||||
return Err(Error::GatewareError)
|
||||
return Err(Error::GatewareError);
|
||||
}
|
||||
|
||||
receive(linkno, |buffer| {
|
||||
if buffer.len() < 8 {
|
||||
return Err(IoError::new(IoErrorKind::UnexpectedEof, "Unexpected end").into())
|
||||
return Err(IoError::new(IoErrorKind::UnexpectedEof, "Unexpected end").into());
|
||||
}
|
||||
|
||||
let mut reader = Cursor::new(buffer);
|
||||
@@ -107,7 +104,7 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
|
||||
reader.set_position(checksum_at);
|
||||
if reader.read_u32()? != checksum {
|
||||
return Err(Error::CorruptedPacket)
|
||||
return Err(Error::CorruptedPacket);
|
||||
}
|
||||
reader.set_position(0);
|
||||
|
||||
@@ -115,9 +112,7 @@ pub fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>,
|
||||
timer: GlobalTimer) -> Result<Packet, Error>
|
||||
{
|
||||
pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error> {
|
||||
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
|
||||
let limit = timer.get_time() + timeout_ms;
|
||||
while timer.get_time() < limit {
|
||||
@@ -130,15 +125,14 @@ pub fn recv_timeout(linkno: u8, timeout_ms: Option<u64>,
|
||||
}
|
||||
|
||||
fn transmit<F>(linkno: u8, f: F) -> Result<(), Error>
|
||||
where F: FnOnce(&mut [u8]) -> Result<usize, Error>
|
||||
{
|
||||
where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
|
||||
let linkno = linkno as usize;
|
||||
unsafe {
|
||||
while (DRTIOAUX[linkno].aux_tx_read)() != 0 {}
|
||||
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
|
||||
let len = DRTIOAUX_MEM[linkno].size / 2;
|
||||
// work buffer, works with unaligned mem access
|
||||
let mut buf: [u8; 1024] = [0; 1024];
|
||||
let mut buf: [u8; 1024] = [0; 1024];
|
||||
let len = f(&mut buf[0..len])?;
|
||||
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
|
||||
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
|
||||
@@ -152,7 +146,7 @@ pub fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
|
||||
let mut writer = Cursor::new(buffer);
|
||||
|
||||
packet.write_to(&mut writer)?;
|
||||
|
||||
|
||||
// Pad till offset 4, insert checksum there
|
||||
let padding = (12 - (writer.position() % 8)) % 8;
|
||||
for _ in 0..padding {
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
use core_io::{Error as IoError, ErrorKind as IoErrorKind};
|
||||
use crc;
|
||||
|
||||
use core_io::{ErrorKind as IoErrorKind, Error as IoError};
|
||||
use void::Void;
|
||||
use io::{proto::{ProtoRead, ProtoWrite},
|
||||
Cursor};
|
||||
use libasync::{block_async, task};
|
||||
use libboard_zynq::{time::Milliseconds, timer::GlobalTimer};
|
||||
use nb;
|
||||
|
||||
use libboard_zynq::{timer::GlobalTimer, time::Milliseconds};
|
||||
use libasync::{task, block_async};
|
||||
|
||||
use io::{proto::ProtoRead, proto::ProtoWrite, Cursor};
|
||||
use crate::mem::mem::DRTIOAUX_MEM;
|
||||
use crate::pl::csr::DRTIOAUX;
|
||||
use crate::drtioaux::{Error, has_rx_error, copy_work_buffer};
|
||||
use void::Void;
|
||||
|
||||
pub use crate::drtioaux_proto::Packet;
|
||||
use crate::{drtioaux::{copy_work_buffer, has_rx_error, Error},
|
||||
mem::mem::DRTIOAUX_MEM,
|
||||
pl::csr::DRTIOAUX};
|
||||
|
||||
pub async fn reset(linkno: u8) {
|
||||
let linkno = linkno as usize;
|
||||
@@ -29,16 +27,14 @@ fn tx_ready(linkno: usize) -> nb::Result<(), Void> {
|
||||
unsafe {
|
||||
if (DRTIOAUX[linkno].aux_tx_read)() != 0 {
|
||||
Err(nb::Error::WouldBlock)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
|
||||
where F: FnOnce(&[u8]) -> Result<T, Error>
|
||||
{
|
||||
where F: FnOnce(&[u8]) -> Result<T, Error> {
|
||||
let linkidx = linkno as usize;
|
||||
unsafe {
|
||||
if (DRTIOAUX[linkidx].aux_rx_present_read)() == 1 {
|
||||
@@ -58,12 +54,12 @@ async fn receive<F, T>(linkno: u8, f: F) -> Result<Option<T>, Error>
|
||||
|
||||
pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||
if has_rx_error(linkno) {
|
||||
return Err(Error::GatewareError)
|
||||
return Err(Error::GatewareError);
|
||||
}
|
||||
|
||||
receive(linkno, |buffer| {
|
||||
if buffer.len() < 8 {
|
||||
return Err(IoError::new(IoErrorKind::UnexpectedEof, "Unexpected end").into())
|
||||
return Err(IoError::new(IoErrorKind::UnexpectedEof, "Unexpected end").into());
|
||||
}
|
||||
|
||||
let mut reader = Cursor::new(buffer);
|
||||
@@ -72,17 +68,16 @@ pub async fn recv(linkno: u8) -> Result<Option<Packet>, Error> {
|
||||
let checksum = crc::crc32::checksum_ieee(&reader.get_ref()[0..checksum_at]);
|
||||
reader.set_position(checksum_at);
|
||||
if reader.read_u32()? != checksum {
|
||||
return Err(Error::CorruptedPacket)
|
||||
return Err(Error::CorruptedPacket);
|
||||
}
|
||||
reader.set_position(0);
|
||||
|
||||
Ok(Packet::read_from(&mut reader)?)
|
||||
}).await
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>,
|
||||
timer: GlobalTimer) -> Result<Packet, Error>
|
||||
{
|
||||
pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>, timer: GlobalTimer) -> Result<Packet, Error> {
|
||||
let timeout_ms = Milliseconds(timeout_ms.unwrap_or(10));
|
||||
let limit = timer.get_time() + timeout_ms;
|
||||
let mut would_block = false;
|
||||
@@ -93,7 +88,9 @@ pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>,
|
||||
task::r#yield().await;
|
||||
}
|
||||
match recv(linkno).await? {
|
||||
None => { would_block = true; },
|
||||
None => {
|
||||
would_block = true;
|
||||
}
|
||||
Some(packet) => return Ok(packet),
|
||||
}
|
||||
}
|
||||
@@ -101,15 +98,14 @@ pub async fn recv_timeout(linkno: u8, timeout_ms: Option<u64>,
|
||||
}
|
||||
|
||||
async fn transmit<F>(linkno: u8, f: F) -> Result<(), Error>
|
||||
where F: FnOnce(&mut [u8]) -> Result<usize, Error>
|
||||
{
|
||||
where F: FnOnce(&mut [u8]) -> Result<usize, Error> {
|
||||
let linkno = linkno as usize;
|
||||
unsafe {
|
||||
let _ = block_async!(tx_ready(linkno)).await;
|
||||
let ptr = DRTIOAUX_MEM[linkno].base as *mut u32;
|
||||
let len = DRTIOAUX_MEM[linkno].size / 2;
|
||||
// work buffer, works with unaligned mem access
|
||||
let mut buf: [u8; 1024] = [0; 1024];
|
||||
let mut buf: [u8; 1024] = [0; 1024];
|
||||
let len = f(&mut buf[0..len])?;
|
||||
copy_work_buffer(buf.as_mut_ptr() as *mut u32, ptr, len as isize);
|
||||
(DRTIOAUX[linkno].aux_tx_length_write)(len as u16);
|
||||
@@ -123,7 +119,7 @@ pub async fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
|
||||
let mut writer = Cursor::new(buffer);
|
||||
|
||||
packet.write_to(&mut writer)?;
|
||||
|
||||
|
||||
// Pad till offset 4, insert checksum there
|
||||
let padding = (12 - (writer.position() % 8)) % 8;
|
||||
for _ in 0..padding {
|
||||
@@ -134,5 +130,6 @@ pub async fn send(linkno: u8, packet: &Packet) -> Result<(), Error> {
|
||||
writer.write_u32(checksum)?;
|
||||
|
||||
Ok(writer.position())
|
||||
}).await
|
||||
})
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
use core_io::{Write, Read, Error as IoError};
|
||||
|
||||
use io::proto::{ProtoWrite, ProtoRead};
|
||||
use core_io::{Error as IoError, Read, Write};
|
||||
use io::proto::{ProtoRead, ProtoWrite};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
UnknownPacket(u8),
|
||||
Io(IoError)
|
||||
Io(IoError),
|
||||
}
|
||||
|
||||
impl From<IoError> for Error {
|
||||
@@ -22,45 +21,122 @@ pub enum Packet {
|
||||
ResetAck,
|
||||
TSCAck,
|
||||
|
||||
DestinationStatusRequest { destination: u8 },
|
||||
DestinationStatusRequest {
|
||||
destination: u8,
|
||||
},
|
||||
DestinationDownReply,
|
||||
DestinationOkReply,
|
||||
DestinationSequenceErrorReply { channel: u16 },
|
||||
DestinationCollisionReply { channel: u16 },
|
||||
DestinationBusyReply { channel: u16 },
|
||||
DestinationSequenceErrorReply {
|
||||
channel: u16,
|
||||
},
|
||||
DestinationCollisionReply {
|
||||
channel: u16,
|
||||
},
|
||||
DestinationBusyReply {
|
||||
channel: u16,
|
||||
},
|
||||
|
||||
RoutingSetPath { destination: u8, hops: [u8; 32] },
|
||||
RoutingSetRank { rank: u8 },
|
||||
RoutingSetPath {
|
||||
destination: u8,
|
||||
hops: [u8; 32],
|
||||
},
|
||||
RoutingSetRank {
|
||||
rank: u8,
|
||||
},
|
||||
RoutingAck,
|
||||
|
||||
MonitorRequest { destination: u8, channel: u16, probe: u8 },
|
||||
MonitorReply { value: u64 },
|
||||
InjectionRequest { destination: u8, channel: u16, overrd: u8, value: u8 },
|
||||
InjectionStatusRequest { destination: u8, channel: u16, overrd: u8 },
|
||||
InjectionStatusReply { value: u8 },
|
||||
MonitorRequest {
|
||||
destination: u8,
|
||||
channel: u16,
|
||||
probe: u8,
|
||||
},
|
||||
MonitorReply {
|
||||
value: u64,
|
||||
},
|
||||
InjectionRequest {
|
||||
destination: u8,
|
||||
channel: u16,
|
||||
overrd: u8,
|
||||
value: u8,
|
||||
},
|
||||
InjectionStatusRequest {
|
||||
destination: u8,
|
||||
channel: u16,
|
||||
overrd: u8,
|
||||
},
|
||||
InjectionStatusReply {
|
||||
value: u8,
|
||||
},
|
||||
|
||||
I2cStartRequest { destination: u8, busno: u8 },
|
||||
I2cRestartRequest { destination: u8, busno: u8 },
|
||||
I2cStopRequest { destination: u8, busno: u8 },
|
||||
I2cWriteRequest { destination: u8, busno: u8, data: u8 },
|
||||
I2cWriteReply { succeeded: bool, ack: bool },
|
||||
I2cReadRequest { destination: u8, busno: u8, ack: bool },
|
||||
I2cReadReply { succeeded: bool, data: u8 },
|
||||
I2cBasicReply { succeeded: bool },
|
||||
I2cSwitchSelectRequest { destination: u8, busno: u8, address: u8, mask: u8 },
|
||||
|
||||
SpiSetConfigRequest { destination: u8, busno: u8, flags: u8, length: u8, div: u8, cs: u8 },
|
||||
SpiWriteRequest { destination: u8, busno: u8, data: u32 },
|
||||
SpiReadRequest { destination: u8, busno: u8 },
|
||||
SpiReadReply { succeeded: bool, data: u32 },
|
||||
SpiBasicReply { succeeded: bool },
|
||||
I2cStartRequest {
|
||||
destination: u8,
|
||||
busno: u8,
|
||||
},
|
||||
I2cRestartRequest {
|
||||
destination: u8,
|
||||
busno: u8,
|
||||
},
|
||||
I2cStopRequest {
|
||||
destination: u8,
|
||||
busno: u8,
|
||||
},
|
||||
I2cWriteRequest {
|
||||
destination: u8,
|
||||
busno: u8,
|
||||
data: u8,
|
||||
},
|
||||
I2cWriteReply {
|
||||
succeeded: bool,
|
||||
ack: bool,
|
||||
},
|
||||
I2cReadRequest {
|
||||
destination: u8,
|
||||
busno: u8,
|
||||
ack: bool,
|
||||
},
|
||||
I2cReadReply {
|
||||
succeeded: bool,
|
||||
data: u8,
|
||||
},
|
||||
I2cBasicReply {
|
||||
succeeded: bool,
|
||||
},
|
||||
I2cSwitchSelectRequest {
|
||||
destination: u8,
|
||||
busno: u8,
|
||||
address: u8,
|
||||
mask: u8,
|
||||
},
|
||||
|
||||
SpiSetConfigRequest {
|
||||
destination: u8,
|
||||
busno: u8,
|
||||
flags: u8,
|
||||
length: u8,
|
||||
div: u8,
|
||||
cs: u8,
|
||||
},
|
||||
SpiWriteRequest {
|
||||
destination: u8,
|
||||
busno: u8,
|
||||
data: u32,
|
||||
},
|
||||
SpiReadRequest {
|
||||
destination: u8,
|
||||
busno: u8,
|
||||
},
|
||||
SpiReadReply {
|
||||
succeeded: bool,
|
||||
data: u32,
|
||||
},
|
||||
SpiBasicReply {
|
||||
succeeded: bool,
|
||||
},
|
||||
}
|
||||
|
||||
impl Packet {
|
||||
pub fn read_from<R>(reader: &mut R) -> Result<Self, Error>
|
||||
where R: Read + ?Sized
|
||||
{
|
||||
where R: Read + ?Sized {
|
||||
Ok(match reader.read_u8()? {
|
||||
0x00 => Packet::EchoRequest,
|
||||
0x01 => Packet::EchoReply,
|
||||
@@ -69,18 +145,18 @@ impl Packet {
|
||||
0x04 => Packet::TSCAck,
|
||||
|
||||
0x20 => Packet::DestinationStatusRequest {
|
||||
destination: reader.read_u8()?
|
||||
destination: reader.read_u8()?,
|
||||
},
|
||||
0x21 => Packet::DestinationDownReply,
|
||||
0x22 => Packet::DestinationOkReply,
|
||||
0x23 => Packet::DestinationSequenceErrorReply {
|
||||
channel: reader.read_u16()?
|
||||
channel: reader.read_u16()?,
|
||||
},
|
||||
0x24 => Packet::DestinationCollisionReply {
|
||||
channel: reader.read_u16()?
|
||||
channel: reader.read_u16()?,
|
||||
},
|
||||
0x25 => Packet::DestinationBusyReply {
|
||||
channel: reader.read_u16()?
|
||||
channel: reader.read_u16()?,
|
||||
},
|
||||
|
||||
0x30 => {
|
||||
@@ -89,75 +165,75 @@ impl Packet {
|
||||
reader.read_exact(&mut hops)?;
|
||||
Packet::RoutingSetPath {
|
||||
destination: destination,
|
||||
hops: hops
|
||||
hops: hops,
|
||||
}
|
||||
},
|
||||
}
|
||||
0x31 => Packet::RoutingSetRank {
|
||||
rank: reader.read_u8()?
|
||||
rank: reader.read_u8()?,
|
||||
},
|
||||
0x32 => Packet::RoutingAck,
|
||||
|
||||
0x40 => Packet::MonitorRequest {
|
||||
destination: reader.read_u8()?,
|
||||
channel: reader.read_u16()?,
|
||||
probe: reader.read_u8()?
|
||||
probe: reader.read_u8()?,
|
||||
},
|
||||
0x41 => Packet::MonitorReply {
|
||||
value: reader.read_u64()?
|
||||
value: reader.read_u64()?,
|
||||
},
|
||||
0x50 => Packet::InjectionRequest {
|
||||
destination: reader.read_u8()?,
|
||||
channel: reader.read_u16()?,
|
||||
overrd: reader.read_u8()?,
|
||||
value: reader.read_u8()?
|
||||
value: reader.read_u8()?,
|
||||
},
|
||||
0x51 => Packet::InjectionStatusRequest {
|
||||
destination: reader.read_u8()?,
|
||||
channel: reader.read_u16()?,
|
||||
overrd: reader.read_u8()?
|
||||
overrd: reader.read_u8()?,
|
||||
},
|
||||
0x52 => Packet::InjectionStatusReply {
|
||||
value: reader.read_u8()?
|
||||
value: reader.read_u8()?,
|
||||
},
|
||||
|
||||
0x80 => Packet::I2cStartRequest {
|
||||
destination: reader.read_u8()?,
|
||||
busno: reader.read_u8()?
|
||||
busno: reader.read_u8()?,
|
||||
},
|
||||
0x81 => Packet::I2cRestartRequest {
|
||||
destination: reader.read_u8()?,
|
||||
busno: reader.read_u8()?
|
||||
busno: reader.read_u8()?,
|
||||
},
|
||||
0x82 => Packet::I2cStopRequest {
|
||||
destination: reader.read_u8()?,
|
||||
busno: reader.read_u8()?
|
||||
busno: reader.read_u8()?,
|
||||
},
|
||||
0x83 => Packet::I2cWriteRequest {
|
||||
destination: reader.read_u8()?,
|
||||
busno: reader.read_u8()?,
|
||||
data: reader.read_u8()?
|
||||
data: reader.read_u8()?,
|
||||
},
|
||||
0x84 => Packet::I2cWriteReply {
|
||||
succeeded: reader.read_bool()?,
|
||||
ack: reader.read_bool()?
|
||||
ack: reader.read_bool()?,
|
||||
},
|
||||
0x85 => Packet::I2cReadRequest {
|
||||
destination: reader.read_u8()?,
|
||||
busno: reader.read_u8()?,
|
||||
ack: reader.read_bool()?
|
||||
ack: reader.read_bool()?,
|
||||
},
|
||||
0x86 => Packet::I2cReadReply {
|
||||
succeeded: reader.read_bool()?,
|
||||
data: reader.read_u8()?
|
||||
data: reader.read_u8()?,
|
||||
},
|
||||
0x87 => Packet::I2cBasicReply {
|
||||
succeeded: reader.read_bool()?
|
||||
succeeded: reader.read_bool()?,
|
||||
},
|
||||
0x88 => Packet::I2cSwitchSelectRequest {
|
||||
destination: reader.read_u8()?,
|
||||
busno: reader.read_u8()?,
|
||||
address: reader.read_u8()?,
|
||||
mask: reader.read_u8()?
|
||||
mask: reader.read_u8()?,
|
||||
},
|
||||
|
||||
0x90 => Packet::SpiSetConfigRequest {
|
||||
@@ -166,157 +242,180 @@ impl Packet {
|
||||
flags: reader.read_u8()?,
|
||||
length: reader.read_u8()?,
|
||||
div: reader.read_u8()?,
|
||||
cs: reader.read_u8()?
|
||||
cs: reader.read_u8()?,
|
||||
},
|
||||
/* 0x91: was Packet::SpiSetXferRequest */
|
||||
0x92 => Packet::SpiWriteRequest {
|
||||
destination: reader.read_u8()?,
|
||||
busno: reader.read_u8()?,
|
||||
data: reader.read_u32()?
|
||||
data: reader.read_u32()?,
|
||||
},
|
||||
0x93 => Packet::SpiReadRequest {
|
||||
destination: reader.read_u8()?,
|
||||
busno: reader.read_u8()?
|
||||
busno: reader.read_u8()?,
|
||||
},
|
||||
0x94 => Packet::SpiReadReply {
|
||||
succeeded: reader.read_bool()?,
|
||||
data: reader.read_u32()?
|
||||
data: reader.read_u32()?,
|
||||
},
|
||||
0x95 => Packet::SpiBasicReply {
|
||||
succeeded: reader.read_bool()?
|
||||
succeeded: reader.read_bool()?,
|
||||
},
|
||||
|
||||
ty => return Err(Error::UnknownPacket(ty))
|
||||
ty => return Err(Error::UnknownPacket(ty)),
|
||||
})
|
||||
}
|
||||
|
||||
pub fn write_to<W>(&self, writer: &mut W) -> Result<(), IoError>
|
||||
where W: Write + ?Sized
|
||||
{
|
||||
|
||||
where W: Write + ?Sized {
|
||||
match *self {
|
||||
Packet::EchoRequest =>
|
||||
writer.write_u8(0x00)?,
|
||||
Packet::EchoReply =>
|
||||
writer.write_u8(0x01)?,
|
||||
Packet::ResetRequest =>
|
||||
writer.write_u8(0x02)?,
|
||||
Packet::ResetAck =>
|
||||
writer.write_u8(0x03)?,
|
||||
Packet::TSCAck =>
|
||||
writer.write_u8(0x04)?,
|
||||
Packet::EchoRequest => writer.write_u8(0x00)?,
|
||||
Packet::EchoReply => writer.write_u8(0x01)?,
|
||||
Packet::ResetRequest => writer.write_u8(0x02)?,
|
||||
Packet::ResetAck => writer.write_u8(0x03)?,
|
||||
Packet::TSCAck => writer.write_u8(0x04)?,
|
||||
|
||||
Packet::DestinationStatusRequest { destination } => {
|
||||
writer.write_u8(0x20)?;
|
||||
writer.write_u8(destination)?;
|
||||
},
|
||||
Packet::DestinationDownReply =>
|
||||
writer.write_u8(0x21)?,
|
||||
Packet::DestinationOkReply =>
|
||||
writer.write_u8(0x22)?,
|
||||
}
|
||||
Packet::DestinationDownReply => writer.write_u8(0x21)?,
|
||||
Packet::DestinationOkReply => writer.write_u8(0x22)?,
|
||||
Packet::DestinationSequenceErrorReply { channel } => {
|
||||
writer.write_u8(0x23)?;
|
||||
writer.write_u16(channel)?;
|
||||
},
|
||||
}
|
||||
Packet::DestinationCollisionReply { channel } => {
|
||||
writer.write_u8(0x24)?;
|
||||
writer.write_u16(channel)?;
|
||||
},
|
||||
}
|
||||
Packet::DestinationBusyReply { channel } => {
|
||||
writer.write_u8(0x25)?;
|
||||
writer.write_u16(channel)?;
|
||||
},
|
||||
}
|
||||
|
||||
Packet::RoutingSetPath { destination, hops } => {
|
||||
writer.write_u8(0x30)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_all(&hops)?;
|
||||
},
|
||||
}
|
||||
Packet::RoutingSetRank { rank } => {
|
||||
writer.write_u8(0x31)?;
|
||||
writer.write_u8(rank)?;
|
||||
},
|
||||
Packet::RoutingAck =>
|
||||
writer.write_u8(0x32)?,
|
||||
}
|
||||
Packet::RoutingAck => writer.write_u8(0x32)?,
|
||||
|
||||
Packet::MonitorRequest { destination, channel, probe } => {
|
||||
Packet::MonitorRequest {
|
||||
destination,
|
||||
channel,
|
||||
probe,
|
||||
} => {
|
||||
writer.write_u8(0x40)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u16(channel)?;
|
||||
writer.write_u8(probe)?;
|
||||
},
|
||||
}
|
||||
Packet::MonitorReply { value } => {
|
||||
writer.write_u8(0x41)?;
|
||||
writer.write_u64(value)?;
|
||||
},
|
||||
Packet::InjectionRequest { destination, channel, overrd, value } => {
|
||||
}
|
||||
Packet::InjectionRequest {
|
||||
destination,
|
||||
channel,
|
||||
overrd,
|
||||
value,
|
||||
} => {
|
||||
writer.write_u8(0x50)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u16(channel)?;
|
||||
writer.write_u8(overrd)?;
|
||||
writer.write_u8(value)?;
|
||||
},
|
||||
Packet::InjectionStatusRequest { destination, channel, overrd } => {
|
||||
}
|
||||
Packet::InjectionStatusRequest {
|
||||
destination,
|
||||
channel,
|
||||
overrd,
|
||||
} => {
|
||||
writer.write_u8(0x51)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u16(channel)?;
|
||||
writer.write_u8(overrd)?;
|
||||
},
|
||||
}
|
||||
Packet::InjectionStatusReply { value } => {
|
||||
writer.write_u8(0x52)?;
|
||||
writer.write_u8(value)?;
|
||||
},
|
||||
}
|
||||
|
||||
Packet::I2cStartRequest { destination, busno } => {
|
||||
writer.write_u8(0x80)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(busno)?;
|
||||
},
|
||||
}
|
||||
Packet::I2cRestartRequest { destination, busno } => {
|
||||
writer.write_u8(0x81)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(busno)?;
|
||||
},
|
||||
}
|
||||
Packet::I2cStopRequest { destination, busno } => {
|
||||
writer.write_u8(0x82)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(busno)?;
|
||||
},
|
||||
Packet::I2cWriteRequest { destination, busno, data } => {
|
||||
}
|
||||
Packet::I2cWriteRequest {
|
||||
destination,
|
||||
busno,
|
||||
data,
|
||||
} => {
|
||||
writer.write_u8(0x83)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(busno)?;
|
||||
writer.write_u8(data)?;
|
||||
},
|
||||
}
|
||||
Packet::I2cWriteReply { succeeded, ack } => {
|
||||
writer.write_u8(0x84)?;
|
||||
writer.write_bool(succeeded)?;
|
||||
writer.write_bool(ack)?;
|
||||
},
|
||||
Packet::I2cReadRequest { destination, busno, ack } => {
|
||||
}
|
||||
Packet::I2cReadRequest {
|
||||
destination,
|
||||
busno,
|
||||
ack,
|
||||
} => {
|
||||
writer.write_u8(0x85)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(busno)?;
|
||||
writer.write_bool(ack)?;
|
||||
},
|
||||
}
|
||||
Packet::I2cReadReply { succeeded, data } => {
|
||||
writer.write_u8(0x86)?;
|
||||
writer.write_bool(succeeded)?;
|
||||
writer.write_u8(data)?;
|
||||
},
|
||||
}
|
||||
Packet::I2cBasicReply { succeeded } => {
|
||||
writer.write_u8(0x87)?;
|
||||
writer.write_bool(succeeded)?;
|
||||
},
|
||||
Packet::I2cSwitchSelectRequest { destination, busno, address, mask } => {
|
||||
}
|
||||
Packet::I2cSwitchSelectRequest {
|
||||
destination,
|
||||
busno,
|
||||
address,
|
||||
mask,
|
||||
} => {
|
||||
writer.write_u8(0x88)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(busno)?;
|
||||
writer.write_u8(address)?;
|
||||
writer.write_u8(mask)?;
|
||||
},
|
||||
}
|
||||
|
||||
Packet::SpiSetConfigRequest { destination, busno, flags, length, div, cs } => {
|
||||
Packet::SpiSetConfigRequest {
|
||||
destination,
|
||||
busno,
|
||||
flags,
|
||||
length,
|
||||
div,
|
||||
cs,
|
||||
} => {
|
||||
writer.write_u8(0x90)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(busno)?;
|
||||
@@ -324,30 +423,32 @@ impl Packet {
|
||||
writer.write_u8(length)?;
|
||||
writer.write_u8(div)?;
|
||||
writer.write_u8(cs)?;
|
||||
},
|
||||
Packet::SpiWriteRequest { destination, busno, data } => {
|
||||
}
|
||||
Packet::SpiWriteRequest {
|
||||
destination,
|
||||
busno,
|
||||
data,
|
||||
} => {
|
||||
writer.write_u8(0x92)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(busno)?;
|
||||
writer.write_u32(data)?;
|
||||
},
|
||||
}
|
||||
Packet::SpiReadRequest { destination, busno } => {
|
||||
writer.write_u8(0x93)?;
|
||||
writer.write_u8(destination)?;
|
||||
writer.write_u8(busno)?;
|
||||
},
|
||||
}
|
||||
Packet::SpiReadReply { succeeded, data } => {
|
||||
writer.write_u8(0x94)?;
|
||||
writer.write_bool(succeeded)?;
|
||||
writer.write_u32(data)?;
|
||||
},
|
||||
}
|
||||
Packet::SpiBasicReply { succeeded } => {
|
||||
writer.write_u8(0x95)?;
|
||||
writer.write_bool(succeeded)?;
|
||||
},
|
||||
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,10 +19,8 @@ pub struct IoExpander<'a> {
|
||||
registers: Registers,
|
||||
}
|
||||
|
||||
|
||||
impl<'a> IoExpander<'a> {
|
||||
pub fn new(i2c: &'a mut i2c::I2c, index: u8) -> Result<Self, &'static str> {
|
||||
|
||||
// Both expanders on SHARED I2C bus
|
||||
let mut io_expander = match index {
|
||||
0 => IoExpander {
|
||||
@@ -54,10 +52,7 @@ impl<'a> IoExpander<'a> {
|
||||
_ => return Err("incorrect I/O expander index"),
|
||||
};
|
||||
if !io_expander.check_ack()? {
|
||||
info!(
|
||||
"MCP23017 io expander {} not found. Checking for PCA9539.",
|
||||
index
|
||||
);
|
||||
info!("MCP23017 io expander {} not found. Checking for PCA9539.", index);
|
||||
io_expander.address += 0xa8; // translate to PCA9539 addresses (see schematic)
|
||||
io_expander.registers = Registers {
|
||||
iodira: 0x06,
|
||||
|
||||
@@ -1,34 +1,36 @@
|
||||
#![no_std]
|
||||
#![feature(never_type)]
|
||||
|
||||
extern crate log;
|
||||
extern crate core_io;
|
||||
extern crate crc;
|
||||
extern crate embedded_hal;
|
||||
extern crate core_io;
|
||||
extern crate io;
|
||||
extern crate libasync;
|
||||
extern crate libboard_zynq;
|
||||
extern crate libregister;
|
||||
extern crate libconfig;
|
||||
extern crate libcortex_a9;
|
||||
extern crate libasync;
|
||||
extern crate libregister;
|
||||
extern crate log;
|
||||
extern crate log_buffer;
|
||||
|
||||
#[path = "../../../build/pl.rs"]
|
||||
pub mod pl;
|
||||
pub mod drtioaux_proto;
|
||||
pub mod drtio_routing;
|
||||
pub mod logger;
|
||||
#[cfg(has_si5324)]
|
||||
pub mod si5324;
|
||||
#[cfg(has_drtio)]
|
||||
pub mod drtioaux;
|
||||
#[cfg(has_drtio)]
|
||||
pub mod drtioaux_async;
|
||||
#[cfg(has_drtio)]
|
||||
#[path = "../../../build/mem.rs"]
|
||||
pub mod mem;
|
||||
pub mod drtioaux_proto;
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
pub mod io_expander;
|
||||
pub mod logger;
|
||||
#[cfg(has_drtio)]
|
||||
#[rustfmt::skip]
|
||||
#[path = "../../../build/mem.rs"]
|
||||
pub mod mem;
|
||||
#[rustfmt::skip]
|
||||
#[path = "../../../build/pl.rs"]
|
||||
pub mod pl;
|
||||
#[cfg(has_si5324)]
|
||||
pub mod si5324;
|
||||
|
||||
use core::{cmp, str};
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
use core::cell::Cell;
|
||||
use core::fmt::Write;
|
||||
use log::{Log, LevelFilter};
|
||||
use log_buffer::LogBuffer;
|
||||
use libcortex_a9::mutex::{Mutex, MutexGuard};
|
||||
use core::{cell::Cell, fmt::Write};
|
||||
|
||||
use libboard_zynq::{println, timer::GlobalTimer};
|
||||
use libcortex_a9::mutex::{Mutex, MutexGuard};
|
||||
use log::{LevelFilter, Log};
|
||||
use log_buffer::LogBuffer;
|
||||
|
||||
pub struct LogBufferRef<'a> {
|
||||
buffer: MutexGuard<'a, LogBuffer<&'static mut [u8]>>,
|
||||
old_log_level: LevelFilter
|
||||
buffer: MutexGuard<'a, LogBuffer<&'static mut [u8]>>,
|
||||
old_log_level: LevelFilter,
|
||||
}
|
||||
|
||||
impl<'a> LogBufferRef<'a> {
|
||||
@@ -37,7 +37,7 @@ impl<'a> Drop for LogBufferRef<'a> {
|
||||
}
|
||||
|
||||
pub struct BufferLogger {
|
||||
buffer: Mutex<LogBuffer<&'static mut [u8]>>,
|
||||
buffer: Mutex<LogBuffer<&'static mut [u8]>>,
|
||||
uart_filter: Cell<LevelFilter>,
|
||||
buffer_filter: Cell<LevelFilter>,
|
||||
}
|
||||
@@ -56,8 +56,7 @@ impl BufferLogger {
|
||||
pub fn register(self) {
|
||||
unsafe {
|
||||
LOGGER = Some(self);
|
||||
log::set_logger(LOGGER.as_ref().unwrap())
|
||||
.expect("global logger can only be initialized once");
|
||||
log::set_logger(LOGGER.as_ref().unwrap()).expect("global logger can only be initialized once");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,9 +65,7 @@ impl BufferLogger {
|
||||
}
|
||||
|
||||
pub fn buffer<'a>(&'a self) -> Option<LogBufferRef<'a>> {
|
||||
self.buffer
|
||||
.try_lock()
|
||||
.map(LogBufferRef::new)
|
||||
self.buffer.try_lock().map(LogBufferRef::new)
|
||||
}
|
||||
|
||||
pub fn uart_log_level(&self) -> LevelFilter {
|
||||
@@ -99,25 +96,36 @@ impl Log for BufferLogger {
|
||||
|
||||
fn log(&self, record: &log::Record) {
|
||||
if self.enabled(record.metadata()) {
|
||||
let timestamp = unsafe {
|
||||
GlobalTimer::get()
|
||||
}.get_us().0;
|
||||
let seconds = timestamp / 1_000_000;
|
||||
let micros = timestamp % 1_000_000;
|
||||
let timestamp = unsafe { GlobalTimer::get() }.get_us().0;
|
||||
let seconds = timestamp / 1_000_000;
|
||||
let micros = timestamp % 1_000_000;
|
||||
|
||||
if record.level() <= self.buffer_log_level() {
|
||||
let mut buffer = self.buffer.lock();
|
||||
writeln!(buffer, "[{:6}.{:06}s] {:>5}({}): {}", seconds, micros,
|
||||
record.level(), record.target(), record.args()).unwrap();
|
||||
writeln!(
|
||||
buffer,
|
||||
"[{:6}.{:06}s] {:>5}({}): {}",
|
||||
seconds,
|
||||
micros,
|
||||
record.level(),
|
||||
record.target(),
|
||||
record.args()
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
if record.level() <= self.uart_log_level() {
|
||||
println!("[{:6}.{:06}s] {:>5}({}): {}", seconds, micros,
|
||||
record.level(), record.target(), record.args());
|
||||
println!(
|
||||
"[{:6}.{:06}s] {:>5}({}): {}",
|
||||
seconds,
|
||||
micros,
|
||||
record.level(),
|
||||
record.target(),
|
||||
record.args()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn flush(&self) {
|
||||
}
|
||||
fn flush(&self) {}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
use core::result;
|
||||
use log::info;
|
||||
use libboard_zynq::{i2c::I2c, timer::GlobalTimer, time::Milliseconds};
|
||||
|
||||
use embedded_hal::blocking::delay::DelayUs;
|
||||
use libboard_zynq::{i2c::I2c, time::Milliseconds, timer::GlobalTimer};
|
||||
use log::info;
|
||||
|
||||
#[cfg(not(si5324_soft_reset))]
|
||||
use crate::pl::csr;
|
||||
|
||||
@@ -11,9 +13,13 @@ const ADDRESS: u8 = 0x68;
|
||||
|
||||
#[cfg(not(si5324_soft_reset))]
|
||||
fn hard_reset(timer: &mut GlobalTimer) {
|
||||
unsafe { csr::si5324_rst_n::out_write(0); }
|
||||
unsafe {
|
||||
csr::si5324_rst_n::out_write(0);
|
||||
}
|
||||
timer.delay_us(1_000);
|
||||
unsafe { csr::si5324_rst_n::out_write(1); }
|
||||
unsafe {
|
||||
csr::si5324_rst_n::out_write(1);
|
||||
}
|
||||
timer.delay_us(10_000);
|
||||
}
|
||||
|
||||
@@ -29,7 +35,7 @@ pub struct FrequencySettings {
|
||||
pub n31: u32,
|
||||
pub n32: u32,
|
||||
pub bwsel: u8,
|
||||
pub crystal_as_ckin2: bool
|
||||
pub crystal_as_ckin2: bool,
|
||||
}
|
||||
|
||||
pub enum Input {
|
||||
@@ -39,52 +45,52 @@ pub enum Input {
|
||||
|
||||
fn map_frequency_settings(settings: &FrequencySettings) -> Result<FrequencySettings> {
|
||||
if settings.nc1_ls != 0 && (settings.nc1_ls % 2) == 1 {
|
||||
return Err("NC1_LS must be 0 or even")
|
||||
return Err("NC1_LS must be 0 or even");
|
||||
}
|
||||
if settings.nc1_ls > (1 << 20) {
|
||||
return Err("NC1_LS is too high")
|
||||
return Err("NC1_LS is too high");
|
||||
}
|
||||
if (settings.n2_ls % 2) == 1 {
|
||||
return Err("N2_LS must be even")
|
||||
return Err("N2_LS must be even");
|
||||
}
|
||||
if settings.n2_ls > (1 << 20) {
|
||||
return Err("N2_LS is too high")
|
||||
return Err("N2_LS is too high");
|
||||
}
|
||||
if settings.n31 > (1 << 19) {
|
||||
return Err("N31 is too high")
|
||||
return Err("N31 is too high");
|
||||
}
|
||||
if settings.n32 > (1 << 19) {
|
||||
return Err("N32 is too high")
|
||||
return Err("N32 is too high");
|
||||
}
|
||||
let r = FrequencySettings {
|
||||
n1_hs: match settings.n1_hs {
|
||||
4 => 0b000,
|
||||
5 => 0b001,
|
||||
6 => 0b010,
|
||||
7 => 0b011,
|
||||
8 => 0b100,
|
||||
9 => 0b101,
|
||||
4 => 0b000,
|
||||
5 => 0b001,
|
||||
6 => 0b010,
|
||||
7 => 0b011,
|
||||
8 => 0b100,
|
||||
9 => 0b101,
|
||||
10 => 0b110,
|
||||
11 => 0b111,
|
||||
_ => return Err("N1_HS has an invalid value")
|
||||
_ => return Err("N1_HS has an invalid value"),
|
||||
},
|
||||
nc1_ls: settings.nc1_ls - 1,
|
||||
n2_hs: match settings.n2_hs {
|
||||
4 => 0b000,
|
||||
5 => 0b001,
|
||||
6 => 0b010,
|
||||
7 => 0b011,
|
||||
8 => 0b100,
|
||||
9 => 0b101,
|
||||
4 => 0b000,
|
||||
5 => 0b001,
|
||||
6 => 0b010,
|
||||
7 => 0b011,
|
||||
8 => 0b100,
|
||||
9 => 0b101,
|
||||
10 => 0b110,
|
||||
11 => 0b111,
|
||||
_ => return Err("N2_HS has an invalid value")
|
||||
_ => return Err("N2_HS has an invalid value"),
|
||||
},
|
||||
n2_ls: settings.n2_ls - 1,
|
||||
n31: settings.n31 - 1,
|
||||
n32: settings.n32 - 1,
|
||||
bwsel: settings.bwsel,
|
||||
crystal_as_ckin2: settings.crystal_as_ckin2
|
||||
crystal_as_ckin2: settings.crystal_as_ckin2,
|
||||
};
|
||||
Ok(r)
|
||||
}
|
||||
@@ -92,13 +98,13 @@ fn map_frequency_settings(settings: &FrequencySettings) -> Result<FrequencySetti
|
||||
fn write(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
|
||||
i2c.start().unwrap();
|
||||
if !i2c.write(ADDRESS << 1).unwrap() {
|
||||
return Err("Si5324 failed to ack write address")
|
||||
return Err("Si5324 failed to ack write address");
|
||||
}
|
||||
if !i2c.write(reg).unwrap() {
|
||||
return Err("Si5324 failed to ack register")
|
||||
return Err("Si5324 failed to ack register");
|
||||
}
|
||||
if !i2c.write(val).unwrap() {
|
||||
return Err("Si5324 failed to ack value")
|
||||
return Err("Si5324 failed to ack value");
|
||||
}
|
||||
i2c.stop().unwrap();
|
||||
Ok(())
|
||||
@@ -108,10 +114,10 @@ fn write(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
|
||||
fn write_no_ack_value(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
|
||||
i2c.start().unwrap();
|
||||
if !i2c.write(ADDRESS << 1).unwrap() {
|
||||
return Err("Si5324 failed to ack write address")
|
||||
return Err("Si5324 failed to ack write address");
|
||||
}
|
||||
if !i2c.write(reg).unwrap() {
|
||||
return Err("Si5324 failed to ack register")
|
||||
return Err("Si5324 failed to ack register");
|
||||
}
|
||||
i2c.write(val).unwrap();
|
||||
i2c.stop().unwrap();
|
||||
@@ -121,22 +127,22 @@ fn write_no_ack_value(i2c: &mut I2c, reg: u8, val: u8) -> Result<()> {
|
||||
fn read(i2c: &mut I2c, reg: u8) -> Result<u8> {
|
||||
i2c.start().unwrap();
|
||||
if !i2c.write(ADDRESS << 1).unwrap() {
|
||||
return Err("Si5324 failed to ack write address")
|
||||
return Err("Si5324 failed to ack write address");
|
||||
}
|
||||
if !i2c.write(reg).unwrap() {
|
||||
return Err("Si5324 failed to ack register")
|
||||
return Err("Si5324 failed to ack register");
|
||||
}
|
||||
i2c.restart().unwrap();
|
||||
if !i2c.write((ADDRESS << 1) | 1).unwrap() {
|
||||
return Err("Si5324 failed to ack read address")
|
||||
return Err("Si5324 failed to ack read address");
|
||||
}
|
||||
let val = i2c.read(false).unwrap();
|
||||
i2c.stop().unwrap();
|
||||
Ok(val)
|
||||
}
|
||||
|
||||
fn rmw<F>(i2c: &mut I2c, reg: u8, f: F) -> Result<()> where
|
||||
F: Fn(u8) -> u8 {
|
||||
fn rmw<F>(i2c: &mut I2c, reg: u8, f: F) -> Result<()>
|
||||
where F: Fn(u8) -> u8 {
|
||||
let value = read(i2c, reg)?;
|
||||
write(i2c, reg, f(value))?;
|
||||
Ok(())
|
||||
@@ -155,18 +161,18 @@ fn soft_reset(i2c: &mut I2c, timer: &mut GlobalTimer) -> Result<()> {
|
||||
}
|
||||
|
||||
fn has_xtal(i2c: &mut I2c) -> Result<bool> {
|
||||
Ok((read(i2c, 129)? & 0x01) == 0) // LOSX_INT=0
|
||||
Ok((read(i2c, 129)? & 0x01) == 0) // LOSX_INT=0
|
||||
}
|
||||
|
||||
fn has_ckin(i2c: &mut I2c, input: Input) -> Result<bool> {
|
||||
match input {
|
||||
Input::Ckin1 => Ok((read(i2c, 129)? & 0x02) == 0), // LOS1_INT=0
|
||||
Input::Ckin2 => Ok((read(i2c, 129)? & 0x04) == 0), // LOS2_INT=0
|
||||
Input::Ckin1 => Ok((read(i2c, 129)? & 0x02) == 0), // LOS1_INT=0
|
||||
Input::Ckin2 => Ok((read(i2c, 129)? & 0x04) == 0), // LOS2_INT=0
|
||||
}
|
||||
}
|
||||
|
||||
fn locked(i2c: &mut I2c) -> Result<bool> {
|
||||
Ok((read(i2c, 130)? & 0x01) == 0) // LOL_INT=0
|
||||
Ok((read(i2c, 130)? & 0x01) == 0) // LOL_INT=0
|
||||
}
|
||||
|
||||
fn monitor_lock(i2c: &mut I2c, timer: &mut GlobalTimer) -> Result<()> {
|
||||
@@ -211,11 +217,11 @@ pub fn bypass(i2c: &mut I2c, input: Input, timer: &mut GlobalTimer) -> Result<()
|
||||
Input::Ckin2 => 0b01,
|
||||
};
|
||||
init(i2c, timer)?;
|
||||
rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0
|
||||
rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?; // CKSEL_REG
|
||||
rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00
|
||||
rmw(i2c, 6, |v| (v & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111
|
||||
rmw(i2c, 0, |v| (v & 0xfd) | 0x02)?; // BYPASS_REG=1
|
||||
rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0
|
||||
rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?; // CKSEL_REG
|
||||
rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00
|
||||
rmw(i2c, 6, |v| (v & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111
|
||||
rmw(i2c, 0, |v| (v & 0xfd) | 0x02)?; // BYPASS_REG=1
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -228,31 +234,31 @@ pub fn setup(i2c: &mut I2c, settings: &FrequencySettings, input: Input, timer: &
|
||||
|
||||
init(i2c, timer)?;
|
||||
if settings.crystal_as_ckin2 {
|
||||
rmw(i2c, 0, |v| v | 0x40)?; // FREE_RUN=1
|
||||
rmw(i2c, 0, |v| v | 0x40)?; // FREE_RUN=1
|
||||
}
|
||||
rmw(i2c, 2, |v| (v & 0x0f) | (s.bwsel << 4))?;
|
||||
rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0
|
||||
rmw(i2c, 3, |v| (v & 0x2f) | (cksel_reg << 6) | 0x10)?; // CKSEL_REG, SQ_ICAL=1
|
||||
rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00
|
||||
rmw(i2c, 6, |v| (v & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111
|
||||
write(i2c, 25, (s.n1_hs << 5 ) as u8)?;
|
||||
write(i2c, 31, (s.nc1_ls >> 16) as u8)?;
|
||||
write(i2c, 32, (s.nc1_ls >> 8 ) as u8)?;
|
||||
write(i2c, 33, (s.nc1_ls) as u8)?;
|
||||
write(i2c, 34, (s.nc1_ls >> 16) as u8)?; // write to NC2_LS as well
|
||||
write(i2c, 35, (s.nc1_ls >> 8 ) as u8)?;
|
||||
write(i2c, 36, (s.nc1_ls) as u8)?;
|
||||
write(i2c, 40, (s.n2_hs << 5 ) as u8 | (s.n2_ls >> 16) as u8)?;
|
||||
write(i2c, 41, (s.n2_ls >> 8 ) as u8)?;
|
||||
write(i2c, 42, (s.n2_ls) as u8)?;
|
||||
write(i2c, 43, (s.n31 >> 16) as u8)?;
|
||||
write(i2c, 44, (s.n31 >> 8) as u8)?;
|
||||
write(i2c, 45, (s.n31) as u8)?;
|
||||
write(i2c, 46, (s.n32 >> 16) as u8)?;
|
||||
write(i2c, 47, (s.n32 >> 8) as u8)?;
|
||||
write(i2c, 48, (s.n32) as u8)?;
|
||||
rmw(i2c, 137, |v| v | 0x01)?; // FASTLOCK=1
|
||||
rmw(i2c, 136, |v| v | 0x40)?; // ICAL=1
|
||||
rmw(i2c, 2, |v| (v & 0x0f) | (s.bwsel << 4))?;
|
||||
rmw(i2c, 21, |v| v & 0xfe)?; // CKSEL_PIN=0
|
||||
rmw(i2c, 3, |v| (v & 0x2f) | (cksel_reg << 6) | 0x10)?; // CKSEL_REG, SQ_ICAL=1
|
||||
rmw(i2c, 4, |v| (v & 0x3f) | (0b00 << 6))?; // AUTOSEL_REG=b00
|
||||
rmw(i2c, 6, |v| (v & 0xc0) | 0b111111)?; // SFOUT2_REG=b111 SFOUT1_REG=b111
|
||||
write(i2c, 25, (s.n1_hs << 5) as u8)?;
|
||||
write(i2c, 31, (s.nc1_ls >> 16) as u8)?;
|
||||
write(i2c, 32, (s.nc1_ls >> 8) as u8)?;
|
||||
write(i2c, 33, (s.nc1_ls) as u8)?;
|
||||
write(i2c, 34, (s.nc1_ls >> 16) as u8)?; // write to NC2_LS as well
|
||||
write(i2c, 35, (s.nc1_ls >> 8) as u8)?;
|
||||
write(i2c, 36, (s.nc1_ls) as u8)?;
|
||||
write(i2c, 40, (s.n2_hs << 5) as u8 | (s.n2_ls >> 16) as u8)?;
|
||||
write(i2c, 41, (s.n2_ls >> 8) as u8)?;
|
||||
write(i2c, 42, (s.n2_ls) as u8)?;
|
||||
write(i2c, 43, (s.n31 >> 16) as u8)?;
|
||||
write(i2c, 44, (s.n31 >> 8) as u8)?;
|
||||
write(i2c, 45, (s.n31) as u8)?;
|
||||
write(i2c, 46, (s.n32 >> 16) as u8)?;
|
||||
write(i2c, 47, (s.n32 >> 8) as u8)?;
|
||||
write(i2c, 48, (s.n32) as u8)?;
|
||||
rmw(i2c, 137, |v| v | 0x01)?; // FASTLOCK=1
|
||||
rmw(i2c, 136, |v| v | 0x40)?; // ICAL=1
|
||||
|
||||
if !has_xtal(i2c)? {
|
||||
return Err("Si5324 misses XA/XB signal");
|
||||
@@ -270,7 +276,7 @@ pub fn select_input(i2c: &mut I2c, input: Input, timer: &mut GlobalTimer) -> Res
|
||||
Input::Ckin1 => 0b00,
|
||||
Input::Ckin2 => 0b01,
|
||||
};
|
||||
rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?;
|
||||
rmw(i2c, 3, |v| (v & 0x3f) | (cksel_reg << 6))?;
|
||||
if !has_ckin(i2c, input)? {
|
||||
return Err("Si5324 misses clock input signal");
|
||||
}
|
||||
@@ -285,12 +291,12 @@ pub mod siphaser {
|
||||
|
||||
pub fn select_recovered_clock(i2c: &mut I2c, rc: bool, timer: &mut GlobalTimer) -> Result<()> {
|
||||
let val = read(i2c, 3)?;
|
||||
write(i2c, 3, (val & 0xdf) | (1 << 5))?; // DHOLD=1
|
||||
write(i2c, 3, (val & 0xdf) | (1 << 5))?; // DHOLD=1
|
||||
unsafe {
|
||||
csr::siphaser::switch_clocks_write(if rc { 1 } else { 0 });
|
||||
}
|
||||
let val = read(i2c, 3)?;
|
||||
write(i2c, 3, (val & 0xdf) | (0 << 5))?; // DHOLD=0
|
||||
write(i2c, 3, (val & 0xdf) | (0 << 5))?; // DHOLD=0
|
||||
monitor_lock(i2c, timer)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -309,9 +315,7 @@ pub mod siphaser {
|
||||
csr::siphaser::error_write(1);
|
||||
}
|
||||
timer.delay_us(5_000);
|
||||
unsafe {
|
||||
csr::siphaser::error_read() != 0
|
||||
}
|
||||
unsafe { csr::siphaser::error_read() != 0 }
|
||||
}
|
||||
|
||||
fn find_edge(target: bool, timer: &mut GlobalTimer) -> Result<u32> {
|
||||
@@ -340,14 +344,19 @@ pub mod siphaser {
|
||||
}
|
||||
let width = find_edge(true, timer)? + jitter_margin;
|
||||
// width is 360 degrees (one full rotation of the phase between s/h limits) minus jitter
|
||||
info!("calibration successful, lead: {}, width: {} ({}deg)", lead, width, width*360/(56*8));
|
||||
info!(
|
||||
"calibration successful, lead: {}, width: {} ({}deg)",
|
||||
lead,
|
||||
width,
|
||||
width * 360 / (56 * 8)
|
||||
);
|
||||
|
||||
// Apply reverse phase shift for half the width to get into the
|
||||
// middle of the working region.
|
||||
for _ in 0..width/2 {
|
||||
for _ in 0..width / 2 {
|
||||
phase_shift(0, timer);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use std::env;
|
||||
use std::fs::File;
|
||||
use std::io::{BufRead, BufReader, Write};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use std::{env,
|
||||
fs::File,
|
||||
io::{BufRead, BufReader, Write},
|
||||
path::PathBuf};
|
||||
|
||||
pub fn add_linker_script() {
|
||||
// Put the linker script somewhere the linker can find it
|
||||
|
||||
@@ -4,8 +4,7 @@ fn main() {
|
||||
}
|
||||
|
||||
mod libc {
|
||||
use std::path::Path;
|
||||
use std::env;
|
||||
use std::{env, path::Path};
|
||||
|
||||
pub fn compile() {
|
||||
let cfg = &mut cc::Build::new();
|
||||
@@ -32,9 +31,7 @@ mod libc {
|
||||
cfg.flag("-U_FORTIFY_SOURCE");
|
||||
cfg.define("_FORTIFY_SOURCE", Some("0"));
|
||||
|
||||
let sources = vec![
|
||||
"printf.c"
|
||||
];
|
||||
let sources = vec!["printf.c"];
|
||||
|
||||
let root = Path::new("./");
|
||||
for src in sources {
|
||||
|
||||
@@ -11,10 +11,12 @@
|
||||
#![allow(non_upper_case_globals)]
|
||||
#![allow(unused)]
|
||||
|
||||
use crate::DwarfReader;
|
||||
use core::mem;
|
||||
|
||||
use cslice::CSlice;
|
||||
|
||||
use crate::DwarfReader;
|
||||
|
||||
pub const DW_EH_PE_omit: u8 = 0xFF;
|
||||
pub const DW_EH_PE_absptr: u8 = 0x00;
|
||||
|
||||
@@ -160,15 +162,11 @@ pub unsafe fn find_eh_action(
|
||||
if ar_filter == 0 {
|
||||
saw_cleanup = true;
|
||||
} else if ar_filter > 0 {
|
||||
let catch_type = get_ttype_entry(
|
||||
ar_filter as usize,
|
||||
ttype_encoding,
|
||||
ttype_base,
|
||||
ttype_table,
|
||||
)?;
|
||||
let catch_type =
|
||||
get_ttype_entry(ar_filter as usize, ttype_encoding, ttype_base, ttype_table)?;
|
||||
match catch_type {
|
||||
Some(clause_ptr) if *(clause_ptr as *const u32) == id => {
|
||||
return Ok(EHAction::Catch(lpad))
|
||||
return Ok(EHAction::Catch(lpad));
|
||||
}
|
||||
None => return Ok(EHAction::Catch(lpad)),
|
||||
_ => {}
|
||||
@@ -251,19 +249,11 @@ fn get_base(encoding: u8, context: &EHContext<'_>) -> Result<usize, ()> {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn read_encoded_pointer(
|
||||
reader: &mut DwarfReader,
|
||||
context: &EHContext<'_>,
|
||||
encoding: u8,
|
||||
) -> Result<usize, ()> {
|
||||
unsafe fn read_encoded_pointer(reader: &mut DwarfReader, context: &EHContext<'_>, encoding: u8) -> Result<usize, ()> {
|
||||
read_encoded_pointer_with_base(reader, encoding, get_base(encoding, context)?)
|
||||
}
|
||||
|
||||
unsafe fn read_encoded_pointer_with_base(
|
||||
reader: &mut DwarfReader,
|
||||
encoding: u8,
|
||||
base: usize,
|
||||
) -> Result<usize, ()> {
|
||||
unsafe fn read_encoded_pointer_with_base(reader: &mut DwarfReader, encoding: u8, base: usize) -> Result<usize, ()> {
|
||||
if encoding == DW_EH_PE_omit {
|
||||
return Err(());
|
||||
}
|
||||
|
||||
@@ -1451,8 +1451,7 @@ pub const R_AARCH64_TLSDESC_CALL: usize = 569;
|
||||
pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12: usize = 570;
|
||||
pub const R_AARCH64_TLSLE_LDST128_TPREL_LO12_NC: usize = 571;
|
||||
pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12: usize = 572;
|
||||
pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC: usize =
|
||||
573;
|
||||
pub const R_AARCH64_TLSLD_LDST128_DTPREL_LO12_NC: usize = 573;
|
||||
pub const R_AARCH64_COPY: usize = 1024;
|
||||
pub const R_AARCH64_GLOB_DAT: usize = 1025;
|
||||
pub const R_AARCH64_JUMP_SLOT: usize = 1026;
|
||||
@@ -2267,7 +2266,9 @@ pub struct Elf32_Ehdr {
|
||||
pub e_shstrndx: Elf32_Half,
|
||||
}
|
||||
impl Clone for Elf32_Ehdr {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2288,7 +2289,9 @@ pub struct Elf64_Ehdr {
|
||||
pub e_shstrndx: Elf64_Half,
|
||||
}
|
||||
impl Clone for Elf64_Ehdr {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2305,7 +2308,9 @@ pub struct Elf32_Shdr {
|
||||
pub sh_entsize: Elf32_Word,
|
||||
}
|
||||
impl Clone for Elf32_Shdr {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2322,7 +2327,9 @@ pub struct Elf64_Shdr {
|
||||
pub sh_entsize: Elf64_Xword,
|
||||
}
|
||||
impl Clone for Elf64_Shdr {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2335,7 +2342,9 @@ pub struct Elf32_Sym {
|
||||
pub st_shndx: Elf32_Section,
|
||||
}
|
||||
impl Clone for Elf32_Sym {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2348,7 +2357,9 @@ pub struct Elf64_Sym {
|
||||
pub st_size: Elf64_Xword,
|
||||
}
|
||||
impl Clone for Elf64_Sym {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2357,7 +2368,9 @@ pub struct Elf32_Syminfo {
|
||||
pub si_flags: Elf32_Half,
|
||||
}
|
||||
impl Clone for Elf32_Syminfo {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2366,7 +2379,9 @@ pub struct Elf64_Syminfo {
|
||||
pub si_flags: Elf64_Half,
|
||||
}
|
||||
impl Clone for Elf64_Syminfo {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2375,7 +2390,9 @@ pub struct Elf32_Rel {
|
||||
pub r_info: Elf32_Word,
|
||||
}
|
||||
impl Clone for Elf32_Rel {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2384,7 +2401,9 @@ pub struct Elf64_Rel {
|
||||
pub r_info: Elf64_Xword,
|
||||
}
|
||||
impl Clone for Elf64_Rel {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2394,7 +2413,9 @@ pub struct Elf32_Rela {
|
||||
pub r_addend: Elf32_Sword,
|
||||
}
|
||||
impl Clone for Elf32_Rela {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2404,7 +2425,9 @@ pub struct Elf64_Rela {
|
||||
pub r_addend: Elf64_Sxword,
|
||||
}
|
||||
impl Clone for Elf64_Rela {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2419,7 +2442,9 @@ pub struct Elf32_Phdr {
|
||||
pub p_align: Elf32_Word,
|
||||
}
|
||||
impl Clone for Elf32_Phdr {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2434,7 +2459,9 @@ pub struct Elf64_Phdr {
|
||||
pub p_align: Elf64_Xword,
|
||||
}
|
||||
impl Clone for Elf64_Phdr {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Copy)]
|
||||
@@ -2449,10 +2476,14 @@ pub union Elf32_Dyn__bindgen_ty_1 {
|
||||
pub d_ptr: Elf32_Addr,
|
||||
}
|
||||
impl Clone for Elf32_Dyn__bindgen_ty_1 {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
impl Clone for Elf32_Dyn {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Copy)]
|
||||
@@ -2467,10 +2498,14 @@ pub union Elf64_Dyn__bindgen_ty_1 {
|
||||
pub d_ptr: Elf64_Addr,
|
||||
}
|
||||
impl Clone for Elf64_Dyn__bindgen_ty_1 {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
impl Clone for Elf64_Dyn {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2484,7 +2519,9 @@ pub struct Elf32_Verdef {
|
||||
pub vd_next: Elf32_Word,
|
||||
}
|
||||
impl Clone for Elf32_Verdef {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2498,7 +2535,9 @@ pub struct Elf64_Verdef {
|
||||
pub vd_next: Elf64_Word,
|
||||
}
|
||||
impl Clone for Elf64_Verdef {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2507,7 +2546,9 @@ pub struct Elf32_Verdaux {
|
||||
pub vda_next: Elf32_Word,
|
||||
}
|
||||
impl Clone for Elf32_Verdaux {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2516,7 +2557,9 @@ pub struct Elf64_Verdaux {
|
||||
pub vda_next: Elf64_Word,
|
||||
}
|
||||
impl Clone for Elf64_Verdaux {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2528,7 +2571,9 @@ pub struct Elf32_Verneed {
|
||||
pub vn_next: Elf32_Word,
|
||||
}
|
||||
impl Clone for Elf32_Verneed {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2540,7 +2585,9 @@ pub struct Elf64_Verneed {
|
||||
pub vn_next: Elf64_Word,
|
||||
}
|
||||
impl Clone for Elf64_Verneed {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2552,7 +2599,9 @@ pub struct Elf32_Vernaux {
|
||||
pub vna_next: Elf32_Word,
|
||||
}
|
||||
impl Clone for Elf32_Vernaux {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2564,7 +2613,9 @@ pub struct Elf64_Vernaux {
|
||||
pub vna_next: Elf64_Word,
|
||||
}
|
||||
impl Clone for Elf64_Vernaux {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Copy)]
|
||||
@@ -2578,10 +2629,14 @@ pub union Elf32_auxv_t__bindgen_ty_1 {
|
||||
pub a_val: u32,
|
||||
}
|
||||
impl Clone for Elf32_auxv_t__bindgen_ty_1 {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
impl Clone for Elf32_auxv_t {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Copy)]
|
||||
@@ -2595,10 +2650,14 @@ pub union Elf64_auxv_t__bindgen_ty_1 {
|
||||
pub a_val: u64,
|
||||
}
|
||||
impl Clone for Elf64_auxv_t__bindgen_ty_1 {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
impl Clone for Elf64_auxv_t {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2608,7 +2667,9 @@ pub struct Elf32_Nhdr {
|
||||
pub n_type: Elf32_Word,
|
||||
}
|
||||
impl Clone for Elf32_Nhdr {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2618,7 +2679,9 @@ pub struct Elf64_Nhdr {
|
||||
pub n_type: Elf64_Word,
|
||||
}
|
||||
impl Clone for Elf64_Nhdr {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2630,7 +2693,9 @@ pub struct Elf32_Move {
|
||||
pub m_stride: Elf32_Half,
|
||||
}
|
||||
impl Clone for Elf32_Move {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2642,7 +2707,9 @@ pub struct Elf64_Move {
|
||||
pub m_stride: Elf64_Half,
|
||||
}
|
||||
impl Clone for Elf64_Move {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Copy)]
|
||||
@@ -2657,7 +2724,9 @@ pub struct Elf32_gptab__bindgen_ty_1 {
|
||||
pub gt_unused: Elf32_Word,
|
||||
}
|
||||
impl Clone for Elf32_gptab__bindgen_ty_1 {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2666,10 +2735,14 @@ pub struct Elf32_gptab__bindgen_ty_2 {
|
||||
pub gt_bytes: Elf32_Word,
|
||||
}
|
||||
impl Clone for Elf32_gptab__bindgen_ty_2 {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
impl Clone for Elf32_gptab {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2679,7 +2752,9 @@ pub struct Elf32_RegInfo {
|
||||
pub ri_gp_value: Elf32_Sword,
|
||||
}
|
||||
impl Clone for Elf32_RegInfo {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2690,7 +2765,9 @@ pub struct Elf_Options {
|
||||
pub info: Elf32_Word,
|
||||
}
|
||||
impl Clone for Elf_Options {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2699,7 +2776,9 @@ pub struct Elf_Options_Hw {
|
||||
pub hwp_flags2: Elf32_Word,
|
||||
}
|
||||
impl Clone for Elf_Options_Hw {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2711,7 +2790,9 @@ pub struct Elf32_Lib {
|
||||
pub l_flags: Elf32_Word,
|
||||
}
|
||||
impl Clone for Elf32_Lib {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy)]
|
||||
@@ -2723,17 +2804,31 @@ pub struct Elf64_Lib {
|
||||
pub l_flags: Elf64_Word,
|
||||
}
|
||||
impl Clone for Elf64_Lib {
|
||||
fn clone(&self) -> Self { *self }
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
pub type Elf32_Conflict = Elf32_Addr;
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct EXIDX_Entry(u32, u32);
|
||||
|
||||
pub fn ELF32_R_SYM(info: Elf32_Word) -> Elf32_Word { info >> 8 }
|
||||
pub fn ELF32_R_TYPE(info: Elf32_Word) -> u8 { info as u8 }
|
||||
pub fn ELF32_R_INFO(sym: Elf32_Word, ty: u8) -> Elf32_Word { sym << 8 | ty as Elf32_Word }
|
||||
pub fn ELF32_R_SYM(info: Elf32_Word) -> Elf32_Word {
|
||||
info >> 8
|
||||
}
|
||||
pub fn ELF32_R_TYPE(info: Elf32_Word) -> u8 {
|
||||
info as u8
|
||||
}
|
||||
pub fn ELF32_R_INFO(sym: Elf32_Word, ty: u8) -> Elf32_Word {
|
||||
sym << 8 | ty as Elf32_Word
|
||||
}
|
||||
|
||||
pub fn ELF32_ST_BIND(info: u8) -> u8 { info >> 4 }
|
||||
pub fn ELF32_ST_TYPE(info: u8) -> u8 { info & 0xf }
|
||||
pub fn ELF32_ST_INFO(bind: u8, ty: u8) -> u8 { (bind << 4) | (ty & 0xf) }
|
||||
pub fn ELF32_ST_BIND(info: u8) -> u8 {
|
||||
info >> 4
|
||||
}
|
||||
pub fn ELF32_ST_TYPE(info: u8) -> u8 {
|
||||
info & 0xf
|
||||
}
|
||||
pub fn ELF32_ST_INFO(bind: u8, ty: u8) -> u8 {
|
||||
(bind << 4) | (ty & 0xf)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use core::{mem, ptr, ops::{Deref, Range}};
|
||||
use super::{
|
||||
Arch,
|
||||
elf::*,
|
||||
};
|
||||
use core::{mem,
|
||||
ops::{Deref, Range},
|
||||
ptr};
|
||||
|
||||
use super::{elf::*, Arch};
|
||||
|
||||
fn read_unaligned<T: Copy>(data: &[u8], offset: usize) -> Option<T> {
|
||||
if data.len() < offset + mem::size_of::<T>() {
|
||||
@@ -31,14 +31,40 @@ impl<'a> File<'a> {
|
||||
|
||||
pub fn arch(&self) -> Option<Arch> {
|
||||
const IDENT_OPENRISC: [u8; EI_NIDENT] = [
|
||||
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
||||
ELFCLASS32, ELFDATA2MSB, EV_CURRENT, ELFOSABI_NONE,
|
||||
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0
|
||||
ELFMAG0,
|
||||
ELFMAG1,
|
||||
ELFMAG2,
|
||||
ELFMAG3,
|
||||
ELFCLASS32,
|
||||
ELFDATA2MSB,
|
||||
EV_CURRENT,
|
||||
ELFOSABI_NONE,
|
||||
/* ABI version */ 0,
|
||||
/* padding */ 0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
];
|
||||
const IDENT_ARM: [u8; EI_NIDENT] = [
|
||||
ELFMAG0, ELFMAG1, ELFMAG2, ELFMAG3,
|
||||
ELFCLASS32, ELFDATA2LSB, EV_CURRENT, ELFOSABI_NONE,
|
||||
/* ABI version */ 0, /* padding */ 0, 0, 0, 0, 0, 0, 0
|
||||
ELFMAG0,
|
||||
ELFMAG1,
|
||||
ELFMAG2,
|
||||
ELFMAG3,
|
||||
ELFCLASS32,
|
||||
ELFDATA2LSB,
|
||||
EV_CURRENT,
|
||||
ELFOSABI_NONE,
|
||||
/* ABI version */ 0,
|
||||
/* padding */ 0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
];
|
||||
|
||||
match (self.ehdr.e_ident, self.ehdr.e_machine) {
|
||||
@@ -48,16 +74,14 @@ impl<'a> File<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn program_headers<'b>(&'b self) -> impl Iterator<Item = Option<Elf32_Phdr>> + 'b
|
||||
{
|
||||
pub fn program_headers<'b>(&'b self) -> impl Iterator<Item = Option<Elf32_Phdr>> + 'b {
|
||||
(0..self.ehdr.e_phnum).map(move |i| {
|
||||
let phdr_off = self.ehdr.e_phoff as usize + mem::size_of::<Elf32_Phdr>() * i as usize;
|
||||
self.read_unaligned::<Elf32_Phdr>(phdr_off)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn section_headers<'b>(&'b self) -> impl Iterator<Item = Option<Elf32_Shdr>> + 'b
|
||||
{
|
||||
pub fn section_headers<'b>(&'b self) -> impl Iterator<Item = Option<Elf32_Shdr>> + 'b {
|
||||
(0..self.ehdr.e_shnum).map(move |i| {
|
||||
let shdr_off = self.ehdr.e_shoff as usize + mem::size_of::<Elf32_Shdr>() * i as usize;
|
||||
self.read_unaligned::<Elf32_Shdr>(shdr_off)
|
||||
|
||||
@@ -1,13 +1,9 @@
|
||||
use core::{
|
||||
ops::{Deref, DerefMut, Range},
|
||||
mem,
|
||||
slice,
|
||||
};
|
||||
use alloc::alloc::{alloc_zeroed, dealloc, Layout, LayoutError};
|
||||
use super::{
|
||||
elf::*,
|
||||
Error,
|
||||
};
|
||||
use core::{mem,
|
||||
ops::{Deref, DerefMut, Range},
|
||||
slice};
|
||||
|
||||
use super::{elf::*, Error};
|
||||
|
||||
pub struct DynamicSection {
|
||||
pub strtab: Range<usize>,
|
||||
@@ -34,17 +30,12 @@ impl Image {
|
||||
slice::from_raw_parts_mut(ptr, size)
|
||||
};
|
||||
|
||||
Ok(Image {
|
||||
layout,
|
||||
data,
|
||||
})
|
||||
Ok(Image { layout, data })
|
||||
}
|
||||
|
||||
/// assumes that self.data is properly aligned
|
||||
pub(crate) fn get_ref<T>(&self, offset: usize) -> Option<&T>
|
||||
where
|
||||
T: Copy,
|
||||
{
|
||||
where T: Copy {
|
||||
if self.data.len() < offset + mem::size_of::<T>() {
|
||||
None
|
||||
} else if (self.data.as_ptr() as usize + offset) & (mem::align_of::<T>() - 1) != 0 {
|
||||
@@ -66,55 +57,53 @@ impl Image {
|
||||
unsafe { slice::from_raw_parts(ptr, len) }
|
||||
}
|
||||
|
||||
fn dyn_headers<'a>(&'a self, range: Range<usize>) ->
|
||||
impl Iterator<Item = &'a Elf32_Dyn> + 'a
|
||||
{
|
||||
fn dyn_headers<'a>(&'a self, range: Range<usize>) -> impl Iterator<Item = &'a Elf32_Dyn> + 'a {
|
||||
range
|
||||
.step_by(mem::size_of::<Elf32_Dyn>())
|
||||
.filter_map(move |offset| {
|
||||
self.get_ref::<Elf32_Dyn>(offset)
|
||||
})
|
||||
.filter_map(move |offset| self.get_ref::<Elf32_Dyn>(offset))
|
||||
.take_while(|d| unsafe { d.d_un.d_val } as i32 != DT_NULL)
|
||||
}
|
||||
|
||||
pub fn dyn_section(&self, range: Range<usize>) -> Result<DynamicSection, Error> {
|
||||
let (mut strtab_off, mut strtab_sz) = (0, 0);
|
||||
let (mut rel_off, mut rel_sz) = (0, 0);
|
||||
let (mut rela_off, mut rela_sz) = (0, 0);
|
||||
let (mut rel_off, mut rel_sz) = (0, 0);
|
||||
let (mut rela_off, mut rela_sz) = (0, 0);
|
||||
let (mut pltrel_off, mut pltrel_sz) = (0, 0);
|
||||
let (mut hash_off, mut hash_sz) = (0, 0);
|
||||
let (mut hash_off, mut hash_sz) = (0, 0);
|
||||
let mut symtab_off = 0;
|
||||
let mut sym_ent = 0;
|
||||
let mut rel_ent = 0;
|
||||
let mut rela_ent = 0;
|
||||
let mut nbucket = 0;
|
||||
let mut nchain = 0;
|
||||
let mut sym_ent = 0;
|
||||
let mut rel_ent = 0;
|
||||
let mut rela_ent = 0;
|
||||
let mut nbucket = 0;
|
||||
let mut nchain = 0;
|
||||
|
||||
for dyn_header in self.dyn_headers(range) {
|
||||
let val = unsafe { dyn_header.d_un.d_val } as usize;
|
||||
match dyn_header.d_tag {
|
||||
DT_NULL => break,
|
||||
DT_STRTAB => strtab_off = val,
|
||||
DT_STRSZ => strtab_sz = val,
|
||||
DT_SYMTAB => symtab_off = val,
|
||||
DT_SYMENT => sym_ent = val,
|
||||
DT_REL => rel_off = val,
|
||||
DT_RELSZ => rel_sz = val,
|
||||
DT_RELENT => rel_ent = val,
|
||||
DT_RELA => rela_off = val,
|
||||
DT_RELASZ => rela_sz = val,
|
||||
DT_RELAENT => rela_ent = val,
|
||||
DT_JMPREL => pltrel_off = val,
|
||||
DT_PLTRELSZ => pltrel_sz = val,
|
||||
DT_HASH => {
|
||||
nbucket = *self.get_ref::<Elf32_Word>(val + 0)
|
||||
DT_NULL => break,
|
||||
DT_STRTAB => strtab_off = val,
|
||||
DT_STRSZ => strtab_sz = val,
|
||||
DT_SYMTAB => symtab_off = val,
|
||||
DT_SYMENT => sym_ent = val,
|
||||
DT_REL => rel_off = val,
|
||||
DT_RELSZ => rel_sz = val,
|
||||
DT_RELENT => rel_ent = val,
|
||||
DT_RELA => rela_off = val,
|
||||
DT_RELASZ => rela_sz = val,
|
||||
DT_RELAENT => rela_ent = val,
|
||||
DT_JMPREL => pltrel_off = val,
|
||||
DT_PLTRELSZ => pltrel_sz = val,
|
||||
DT_HASH => {
|
||||
nbucket = *self
|
||||
.get_ref::<Elf32_Word>(val + 0)
|
||||
.ok_or("cannot read hash bucket count")? as usize;
|
||||
nchain = *self.get_ref::<Elf32_Word>(val + 4)
|
||||
nchain = *self
|
||||
.get_ref::<Elf32_Word>(val + 4)
|
||||
.ok_or("cannot read hash chain count")? as usize;
|
||||
hash_off = val + 8;
|
||||
hash_sz = (nbucket + nchain) * mem::size_of::<Elf32_Word>();
|
||||
hash_sz = (nbucket + nchain) * mem::size_of::<Elf32_Word>();
|
||||
}
|
||||
_ => ()
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,28 +112,28 @@ impl Image {
|
||||
let symtab_sz = nchain * mem::size_of::<Elf32_Sym>();
|
||||
|
||||
if strtab_off + strtab_sz > self.data.len() {
|
||||
return Err("invalid strtab offset/size")?
|
||||
return Err("invalid strtab offset/size")?;
|
||||
}
|
||||
if symtab_off + symtab_sz > self.data.len() {
|
||||
return Err("invalid symtab offset/size")?
|
||||
return Err("invalid symtab offset/size")?;
|
||||
}
|
||||
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")?
|
||||
return Err("invalid rel offset/size")?;
|
||||
}
|
||||
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")?
|
||||
return Err("invalid rela offset/size")?;
|
||||
}
|
||||
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")?
|
||||
return Err("invalid pltrel offset/size")?;
|
||||
}
|
||||
|
||||
Ok(DynamicSection {
|
||||
@@ -165,7 +154,7 @@ impl Image {
|
||||
|
||||
pub fn write(&self, offset: usize, value: Elf32_Word) -> Result<(), Error> {
|
||||
if offset + mem::size_of::<Elf32_Addr>() > self.data.len() {
|
||||
return Err("relocation out of image bounds")?
|
||||
return Err("relocation out of image bounds")?;
|
||||
}
|
||||
|
||||
let ptr = (self.data.as_ptr() as usize + offset) as *mut Elf32_Addr;
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate log;
|
||||
extern crate libcortex_a9;
|
||||
extern crate log;
|
||||
|
||||
use core::{convert, fmt, ops::Range, str};
|
||||
use alloc::string::String;
|
||||
use log::{debug, trace};
|
||||
use core::{convert, fmt, ops::Range, str};
|
||||
|
||||
use elf::*;
|
||||
use log::{debug, trace};
|
||||
|
||||
pub mod elf;
|
||||
mod file;
|
||||
@@ -21,11 +22,10 @@ pub enum Arch {
|
||||
OpenRisc,
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Parsing(&'static str),
|
||||
Lookup(String)
|
||||
Lookup(String),
|
||||
}
|
||||
|
||||
impl convert::From<&'static str> for Error {
|
||||
@@ -37,10 +37,8 @@ impl convert::From<&'static str> for Error {
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&Error::Parsing(desc) =>
|
||||
write!(f, "parse error: {}", desc),
|
||||
&Error::Lookup(ref sym) =>
|
||||
write!(f, "symbol lookup error: {}", sym),
|
||||
&Error::Parsing(desc) => write!(f, "parse error: {}", desc),
|
||||
&Error::Lookup(ref sym) => write!(f, "symbol lookup error: {}", sym),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -103,20 +101,22 @@ impl Library {
|
||||
let mut index = self.hash_bucket()[hash as usize % self.hash_bucket().len()] as usize;
|
||||
|
||||
loop {
|
||||
if index == STN_UNDEF { return None }
|
||||
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
|
||||
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)
|
||||
_ => return Some(self.image.ptr() as u32 + sym.st_value),
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
@@ -127,10 +127,16 @@ impl Library {
|
||||
}
|
||||
|
||||
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")?)
|
||||
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")?)
|
||||
}
|
||||
|
||||
/// Rebind Rela by `name` to a new `addr`
|
||||
@@ -143,53 +149,59 @@ impl Library {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(
|
||||
data: &[u8],
|
||||
resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>
|
||||
) -> Result<Library, Error> {
|
||||
pub fn load(data: &[u8], resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>) -> Result<Library, Error> {
|
||||
// validate ELF file
|
||||
let file = file::File::new(data)
|
||||
.ok_or("cannot read ELF header")?;
|
||||
let file = file::File::new(data).ok_or("cannot read ELF header")?;
|
||||
if file.ehdr.e_type != ET_DYN {
|
||||
return Err("not a shared library")?
|
||||
return Err("not a shared library")?;
|
||||
}
|
||||
let arch = file.arch()
|
||||
.ok_or("not for a supported architecture")?;
|
||||
let arch = file.arch().ok_or("not for a supported architecture")?;
|
||||
|
||||
// prepare target memory
|
||||
let image_size = file.program_headers()
|
||||
let image_size = file
|
||||
.program_headers()
|
||||
.filter_map(|phdr| phdr.map(|phdr| phdr.p_vaddr + phdr.p_memsz))
|
||||
.max()
|
||||
.unwrap_or(0) as usize;
|
||||
let image_align = file.program_headers()
|
||||
.filter_map(|phdr| phdr.and_then(|phdr| {
|
||||
if phdr.p_type == PT_LOAD {
|
||||
Some(phdr.p_align)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}))
|
||||
let image_align = file
|
||||
.program_headers()
|
||||
.filter_map(|phdr| {
|
||||
phdr.and_then(|phdr| {
|
||||
if phdr.p_type == PT_LOAD {
|
||||
Some(phdr.p_align)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
.max()
|
||||
.unwrap_or(4) as usize;
|
||||
// 1 image for all segments
|
||||
let mut image = image::Image::new(image_size, image_align)
|
||||
.map_err(|_| "cannot allocate target image")?;
|
||||
debug!("ELF target: {} bytes, align to {:X}, allocated at {:08X}", image_size, image_align, image.ptr() as usize);
|
||||
let mut image = image::Image::new(image_size, image_align).map_err(|_| "cannot allocate target image")?;
|
||||
debug!(
|
||||
"ELF target: {} bytes, align to {:X}, allocated at {:08X}",
|
||||
image_size,
|
||||
image_align,
|
||||
image.ptr() as usize
|
||||
);
|
||||
|
||||
// LOAD
|
||||
for phdr in file.program_headers() {
|
||||
let phdr = phdr.ok_or("cannot read program header")?;
|
||||
trace!("Program header: {:08X}+{:08X} to {:08X}",
|
||||
phdr.p_offset, phdr.p_filesz,
|
||||
image.ptr() as u32
|
||||
trace!(
|
||||
"Program header: {:08X}+{:08X} to {:08X}",
|
||||
phdr.p_offset,
|
||||
phdr.p_filesz,
|
||||
image.ptr() as u32
|
||||
);
|
||||
let file_range = phdr.p_offset as usize..(phdr.p_offset + phdr.p_filesz) as usize;
|
||||
match phdr.p_type {
|
||||
PT_LOAD => {
|
||||
let src = file.get(file_range)
|
||||
let src = file
|
||||
.get(file_range)
|
||||
.ok_or("program header requests an out of bounds load (in file)")?;
|
||||
let dst = image.get_mut(phdr.p_vaddr as usize..
|
||||
(phdr.p_vaddr + phdr.p_filesz) as usize)
|
||||
let dst = image
|
||||
.get_mut(phdr.p_vaddr as usize..(phdr.p_vaddr + phdr.p_filesz) as usize)
|
||||
.ok_or("program header requests an out of bounds load (in target)")?;
|
||||
dst.copy_from_slice(src);
|
||||
}
|
||||
@@ -203,9 +215,9 @@ pub fn load(
|
||||
let shdr = shdr.ok_or("cannot read section header")?;
|
||||
match shdr.sh_type as usize {
|
||||
SHT_ARM_EXIDX => {
|
||||
let range = shdr.sh_addr as usize..
|
||||
(shdr.sh_addr + shdr.sh_size) as usize;
|
||||
let _ = image.get(range.clone())
|
||||
let range = shdr.sh_addr as usize..(shdr.sh_addr + shdr.sh_size) as usize;
|
||||
let _ = image
|
||||
.get(range.clone())
|
||||
.ok_or("section header specifies EXIDX outside of image (in target)")?;
|
||||
exidx = Some(range);
|
||||
}
|
||||
@@ -214,11 +226,14 @@ pub fn load(
|
||||
}
|
||||
|
||||
// relocate DYNAMIC
|
||||
let dyn_range = file.dyn_header_vaddr()
|
||||
.ok_or("cannot find a dynamic header")?;
|
||||
let dyn_range = file.dyn_header_vaddr().ok_or("cannot find a dynamic header")?;
|
||||
let dyn_section = image.dyn_section(dyn_range.clone())?;
|
||||
debug!("Relocating {} rela, {} rel, {} pltrel",
|
||||
dyn_section.rela.len(), dyn_section.rel.len(), dyn_section.pltrel.len());
|
||||
debug!(
|
||||
"Relocating {} rela, {} rel, {} pltrel",
|
||||
dyn_section.rela.len(),
|
||||
dyn_section.rel.len(),
|
||||
dyn_section.pltrel.len()
|
||||
);
|
||||
let lib = Library {
|
||||
arch,
|
||||
image,
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
use alloc::string::String;
|
||||
|
||||
use libcortex_a9::{asm::{dsb, isb},
|
||||
cache::{bpiall, dcci_slice, iciallu}};
|
||||
use log::trace;
|
||||
use super::{
|
||||
Arch,
|
||||
elf::*,
|
||||
Error,
|
||||
image::Image,
|
||||
Library,
|
||||
};
|
||||
use libcortex_a9::{
|
||||
cache::{dcci_slice, iciallu, bpiall},
|
||||
asm::{dsb, isb},
|
||||
};
|
||||
|
||||
use super::{elf::*, image::Image, Arch, Error, Library};
|
||||
|
||||
pub trait Relocatable {
|
||||
fn offset(&self) -> usize;
|
||||
@@ -66,25 +60,18 @@ enum RelType {
|
||||
impl RelType {
|
||||
pub fn new(arch: Arch, type_info: u8) -> Option<Self> {
|
||||
match type_info {
|
||||
R_OR1K_NONE if arch == Arch::OpenRisc =>
|
||||
Some(RelType::None),
|
||||
R_ARM_NONE if arch == Arch::Arm =>
|
||||
Some(RelType::None),
|
||||
R_OR1K_NONE if arch == Arch::OpenRisc => Some(RelType::None),
|
||||
R_ARM_NONE if arch == Arch::Arm => Some(RelType::None),
|
||||
|
||||
R_OR1K_RELATIVE if arch == Arch::OpenRisc =>
|
||||
Some(RelType::Relative),
|
||||
R_ARM_RELATIVE if arch == Arch::Arm =>
|
||||
Some(RelType::Relative),
|
||||
R_OR1K_RELATIVE if arch == Arch::OpenRisc => Some(RelType::Relative),
|
||||
R_ARM_RELATIVE if arch == Arch::Arm => Some(RelType::Relative),
|
||||
|
||||
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT
|
||||
if arch == Arch::OpenRisc => Some(RelType::LookupAbs),
|
||||
R_ARM_GLOB_DAT | R_ARM_JUMP_SLOT | R_ARM_ABS32
|
||||
if arch == Arch::Arm => Some(RelType::LookupAbs),
|
||||
R_OR1K_32 | R_OR1K_GLOB_DAT | R_OR1K_JMP_SLOT if arch == Arch::OpenRisc => Some(RelType::LookupAbs),
|
||||
R_ARM_GLOB_DAT | R_ARM_JUMP_SLOT | R_ARM_ABS32 if arch == Arch::Arm => Some(RelType::LookupAbs),
|
||||
|
||||
R_ARM_PREL31 if arch == Arch::Arm => Some(RelType::LookupRel),
|
||||
|
||||
_ =>
|
||||
None
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -96,22 +83,25 @@ fn format_sym_name(sym_name: &[u8]) -> String {
|
||||
}
|
||||
|
||||
pub fn relocate<R: Relocatable>(
|
||||
arch: Arch, lib: &Library,
|
||||
rel: &R, resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>
|
||||
arch: Arch,
|
||||
lib: &Library,
|
||||
rel: &R,
|
||||
resolve: &dyn Fn(&[u8]) -> Option<Elf32_Word>,
|
||||
) -> Result<(), Error> {
|
||||
let sym;
|
||||
if rel.sym_info() == 0 {
|
||||
sym = None;
|
||||
} else {
|
||||
sym = Some(lib.symtab().get(rel.sym_info() as usize)
|
||||
.ok_or("symbol out of bounds of symbol table")?)
|
||||
sym = Some(
|
||||
lib.symtab()
|
||||
.get(rel.sym_info() as usize)
|
||||
.ok_or("symbol out of bounds of symbol table")?,
|
||||
)
|
||||
}
|
||||
|
||||
let rel_type = RelType::new(arch, rel.type_info())
|
||||
.ok_or("unsupported relocation type")?;
|
||||
let rel_type = RelType::new(arch, rel.type_info()).ok_or("unsupported relocation type")?;
|
||||
let value = match rel_type {
|
||||
RelType::None =>
|
||||
return Ok(()),
|
||||
RelType::None => return Ok(()),
|
||||
|
||||
RelType::Relative => {
|
||||
let addend = rel.addend(&lib.image);
|
||||
@@ -132,42 +122,48 @@ pub fn relocate<R: Relocatable>(
|
||||
addr
|
||||
} else {
|
||||
// We couldn't find it anywhere.
|
||||
return Err(Error::Lookup(format_sym_name(sym_name)))
|
||||
return Err(Error::Lookup(format_sym_name(sym_name)));
|
||||
};
|
||||
|
||||
match rel_type {
|
||||
RelType::LookupAbs => sym_addr,
|
||||
RelType::LookupRel =>
|
||||
sym_addr.wrapping_sub(
|
||||
lib.image.ptr().wrapping_offset(rel.offset() as isize) as Elf32_Addr),
|
||||
_ => unreachable!()
|
||||
RelType::LookupRel => {
|
||||
sym_addr.wrapping_sub(lib.image.ptr().wrapping_offset(rel.offset() as isize) as Elf32_Addr)
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match rel.type_info() {
|
||||
R_ARM_PREL31 => {
|
||||
let reloc_word = lib.image.get_ref::<Elf32_Word>(rel.offset())
|
||||
.ok_or("relocation offset cannot be read")?;
|
||||
lib.image.write(rel.offset(), (reloc_word & 0x80000000) | (value & 0x7FFFFFFF))
|
||||
},
|
||||
let reloc_word = lib
|
||||
.image
|
||||
.get_ref::<Elf32_Word>(rel.offset())
|
||||
.ok_or("relocation offset cannot be read")?;
|
||||
lib.image
|
||||
.write(rel.offset(), (reloc_word & 0x80000000) | (value & 0x7FFFFFFF))
|
||||
}
|
||||
|
||||
_ => lib.image.write(rel.offset(), value),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rebind(
|
||||
arch: Arch, lib: &Library, name: &[u8], value: Elf32_Word
|
||||
) -> Result<(), Error> {
|
||||
pub fn rebind(arch: Arch, lib: &Library, name: &[u8], value: Elf32_Word) -> Result<(), Error> {
|
||||
fn rebind_symbol_to_value<R: Relocatable>(
|
||||
arch: Arch, lib: &Library,name: &[u8], value: Elf32_Word, relocs: &[R]
|
||||
arch: Arch,
|
||||
lib: &Library,
|
||||
name: &[u8],
|
||||
value: Elf32_Word,
|
||||
relocs: &[R],
|
||||
) -> Result<(), Error> {
|
||||
for reloc in relocs {
|
||||
let rel_type = RelType::new(arch, reloc.type_info())
|
||||
.ok_or("unsupported relocation type")?;
|
||||
let rel_type = RelType::new(arch, reloc.type_info()).ok_or("unsupported relocation type")?;
|
||||
match rel_type {
|
||||
RelType::LookupAbs => {
|
||||
let sym = lib.symtab().get(reloc.sym_info() as usize)
|
||||
let sym = lib
|
||||
.symtab()
|
||||
.get(reloc.sym_info() as usize)
|
||||
.ok_or("symbol out of bounds of symbol table")?;
|
||||
let sym_name = lib.name_starting_at(sym.st_name as usize)?;
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use core_io::{Read, Write, Error as IoError};
|
||||
use core_io::{Error as IoError, Read, Write};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Cursor<T> {
|
||||
inner: T,
|
||||
pos: usize
|
||||
pos: usize,
|
||||
}
|
||||
|
||||
impl<T> Cursor<T> {
|
||||
@@ -39,7 +39,6 @@ impl<T> Cursor<T> {
|
||||
}
|
||||
|
||||
impl<T: AsRef<[u8]>> Read for Cursor<T> {
|
||||
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
|
||||
let data = &self.inner.as_ref()[self.pos..];
|
||||
let len = buf.len().min(data.len());
|
||||
@@ -50,10 +49,9 @@ impl<T: AsRef<[u8]>> Read for Cursor<T> {
|
||||
}
|
||||
|
||||
impl Write for Cursor<&mut [u8]> {
|
||||
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
|
||||
let data = &mut self.inner[self.pos..];
|
||||
let len = buf.len().min(data.len());
|
||||
let len = buf.len().min(data.len());
|
||||
data[..len].copy_from_slice(&buf[..len]);
|
||||
self.pos += len;
|
||||
Ok(len)
|
||||
@@ -67,7 +65,6 @@ impl Write for Cursor<&mut [u8]> {
|
||||
|
||||
#[cfg(feature = "alloc")]
|
||||
impl Write for Cursor<::alloc::Vec<u8>> {
|
||||
|
||||
#[inline]
|
||||
fn write(&mut self, buf: &[u8]) -> Result<usize, IoError> {
|
||||
self.inner.extend_from_slice(buf);
|
||||
|
||||
@@ -16,7 +16,7 @@ pub mod cursor;
|
||||
pub mod proto;
|
||||
|
||||
pub use cursor::Cursor;
|
||||
#[cfg(all(feature = "byteorder", feature = "alloc"))]
|
||||
pub use proto::ReadStringError;
|
||||
#[cfg(feature = "byteorder")]
|
||||
pub use proto::{ProtoRead, ProtoWrite};
|
||||
#[cfg(all(feature = "byteorder", feature = "alloc"))]
|
||||
pub use proto::ReadStringError;
|
||||
@@ -1,15 +1,14 @@
|
||||
use alloc::{string::String, vec};
|
||||
use core::str::Utf8Error;
|
||||
use byteorder::{ByteOrder, NativeEndian};
|
||||
use alloc::vec;
|
||||
use alloc::string::String;
|
||||
|
||||
use core_io::{Read, Write, Error as IoError};
|
||||
use byteorder::{ByteOrder, NativeEndian};
|
||||
use core_io::{Error as IoError, Read, Write};
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum ReadStringError<T> {
|
||||
Utf8(Utf8Error),
|
||||
Other(T)
|
||||
Other(T),
|
||||
}
|
||||
|
||||
pub trait ProtoRead {
|
||||
@@ -141,7 +140,9 @@ pub trait ProtoWrite {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ProtoRead for T where T: Read + ?Sized {
|
||||
impl<T> ProtoRead for T
|
||||
where T: Read + ?Sized
|
||||
{
|
||||
type ReadError = IoError;
|
||||
|
||||
fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError> {
|
||||
@@ -149,7 +150,9 @@ impl<T> ProtoRead for T where T: Read + ?Sized {
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ProtoWrite for T where T: Write + ?Sized {
|
||||
impl<T> ProtoWrite for T
|
||||
where T: Write + ?Sized
|
||||
{
|
||||
type WriteError = IoError;
|
||||
|
||||
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError> {
|
||||
|
||||
@@ -1,27 +1,25 @@
|
||||
use libc::{c_void, c_int};
|
||||
use libc::{c_int, c_void};
|
||||
|
||||
use crate::libunwind as uw;
|
||||
|
||||
const UW_REG_SP: c_int = 13;
|
||||
|
||||
pub fn backtrace<F>(f: F) -> Result<(), uw::_Unwind_Reason_Code>
|
||||
where F: FnMut(usize) -> ()
|
||||
{
|
||||
where F: FnMut(usize) -> () {
|
||||
struct TraceContext<F> {
|
||||
step_fn: F,
|
||||
prev_sp: uw::_Unwind_Word
|
||||
prev_sp: uw::_Unwind_Word,
|
||||
}
|
||||
|
||||
extern fn trace<F>(context: *mut uw::_Unwind_Context, arg: *mut c_void)
|
||||
-> uw::_Unwind_Reason_Code
|
||||
where F: FnMut(usize) -> ()
|
||||
{
|
||||
extern "C" fn trace<F>(context: *mut uw::_Unwind_Context, arg: *mut c_void) -> uw::_Unwind_Reason_Code
|
||||
where F: FnMut(usize) -> () {
|
||||
unsafe {
|
||||
let trace_context = &mut *(arg as *mut TraceContext<F>);
|
||||
|
||||
// Detect the root of a libfringe thread
|
||||
let cur_sp = uw::_Unwind_GetGR(context, UW_REG_SP);
|
||||
if cur_sp == trace_context.prev_sp {
|
||||
return uw::_URC_END_OF_STACK
|
||||
return uw::_URC_END_OF_STACK;
|
||||
} else {
|
||||
trace_context.prev_sp = cur_sp;
|
||||
}
|
||||
@@ -35,7 +33,7 @@ pub fn backtrace<F>(f: F) -> Result<(), uw::_Unwind_Reason_Code>
|
||||
let mut trace_context = TraceContext { step_fn: f, prev_sp: 0 };
|
||||
match uw::_Unwind_Backtrace(trace::<F>, &mut trace_context as *mut _ as *mut c_void) {
|
||||
uw::_URC_NO_REASON => Ok(()),
|
||||
err => Err(err)
|
||||
err => Err(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,8 +5,7 @@ fn main() {
|
||||
}
|
||||
|
||||
mod llvm_libunwind {
|
||||
use std::path::Path;
|
||||
use std::env;
|
||||
use std::{env, path::Path};
|
||||
|
||||
fn setup_options(cfg: &mut cc::Build) {
|
||||
cfg.no_default_flags(true);
|
||||
@@ -82,11 +81,7 @@ mod llvm_libunwind {
|
||||
cfg.flag("-fvisibility=hidden");
|
||||
cfg.flag_if_supported("-fvisibility-global-new-delete-hidden");
|
||||
|
||||
let unwind_sources = vec![
|
||||
"Unwind-EHABI.cpp",
|
||||
"Unwind-seh.cpp",
|
||||
"libunwind.cpp"
|
||||
];
|
||||
let unwind_sources = vec!["Unwind-EHABI.cpp", "Unwind-seh.cpp", "libunwind.cpp"];
|
||||
|
||||
let root = Path::new("../llvm_libunwind");
|
||||
cfg.include(root.join("include"));
|
||||
|
||||
@@ -21,8 +21,7 @@ pub use _Unwind_Reason_Code::*;
|
||||
pub type _Unwind_Exception_Class = u64;
|
||||
pub type _Unwind_Word = uintptr_t;
|
||||
pub type _Unwind_Ptr = uintptr_t;
|
||||
pub type _Unwind_Trace_Fn =
|
||||
extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code;
|
||||
pub type _Unwind_Trace_Fn = extern "C" fn(ctx: *mut _Unwind_Context, arg: *mut c_void) -> _Unwind_Reason_Code;
|
||||
|
||||
#[cfg(target_arch = "x86")]
|
||||
pub const unwinder_private_data_size: usize = 5;
|
||||
@@ -279,7 +278,6 @@ if #[cfg(all(windows, target_arch = "x86_64", target_env = "gnu"))] {
|
||||
} // cfg_if!
|
||||
|
||||
#[no_mangle]
|
||||
extern fn abort() {
|
||||
extern "C" fn abort() {
|
||||
panic!("Abort!");
|
||||
}
|
||||
|
||||
|
||||
@@ -3,8 +3,7 @@ use libboard_zynq::smoltcp::Error;
|
||||
use libcortex_a9::cache;
|
||||
use log::{debug, info, warn};
|
||||
|
||||
use crate::proto_async::*;
|
||||
use crate::pl;
|
||||
use crate::{pl, proto_async::*};
|
||||
|
||||
const BUFFER_SIZE: usize = 512 * 1024;
|
||||
|
||||
@@ -13,9 +12,7 @@ struct Buffer {
|
||||
data: [u8; BUFFER_SIZE],
|
||||
}
|
||||
|
||||
static mut BUFFER: Buffer = Buffer {
|
||||
data: [0; BUFFER_SIZE]
|
||||
};
|
||||
static mut BUFFER: Buffer = Buffer { data: [0; BUFFER_SIZE] };
|
||||
|
||||
fn arm() {
|
||||
debug!("arming RTIO analyzer");
|
||||
@@ -46,7 +43,7 @@ struct Header {
|
||||
total_byte_count: u64,
|
||||
error_occurred: bool,
|
||||
log_channel: u8,
|
||||
dds_onehot_sel: bool
|
||||
dds_onehot_sel: bool,
|
||||
}
|
||||
|
||||
async fn write_header(stream: &mut TcpStream, header: &Header) -> Result<(), Error> {
|
||||
@@ -78,10 +75,14 @@ async fn handle_connection(stream: &mut TcpStream) -> Result<(), Error> {
|
||||
|
||||
let header = Header {
|
||||
total_byte_count: total_byte_count,
|
||||
sent_bytes: if wraparound { BUFFER_SIZE as u32 } else { total_byte_count as u32 },
|
||||
sent_bytes: if wraparound {
|
||||
BUFFER_SIZE as u32
|
||||
} else {
|
||||
total_byte_count as u32
|
||||
},
|
||||
error_occurred: overflow_occurred | bus_error_occurred,
|
||||
log_channel: pl::csr::CONFIG_RTIO_LOG_CHANNEL as u8,
|
||||
dds_onehot_sel: true // kept for backward compatibility of analyzer dumps
|
||||
dds_onehot_sel: true, // kept for backward compatibility of analyzer dumps
|
||||
};
|
||||
debug!("{:?}", header);
|
||||
|
||||
|
||||
@@ -1,39 +1,33 @@
|
||||
use core::{fmt, slice, str};
|
||||
use core::cell::RefCell;
|
||||
use alloc::{vec, vec::Vec, string::String, collections::BTreeMap, rc::Rc};
|
||||
use log::{info, warn, error};
|
||||
use alloc::{collections::BTreeMap, rc::Rc, string::String, vec, vec::Vec};
|
||||
use core::{cell::RefCell, fmt, slice, str};
|
||||
|
||||
use cslice::CSlice;
|
||||
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
|
||||
use libboard_zynq::{
|
||||
self as zynq,
|
||||
smoltcp::{
|
||||
self,
|
||||
wire::IpCidr,
|
||||
iface::{NeighborCache, EthernetInterfaceBuilder},
|
||||
time::Instant,
|
||||
},
|
||||
timer::GlobalTimer,
|
||||
};
|
||||
use libcortex_a9::{semaphore::Semaphore, mutex::Mutex, sync_channel::{Sender, Receiver}};
|
||||
use futures::{select_biased, future::FutureExt};
|
||||
use libasync::{smoltcp::{Sockets, TcpStream}, task};
|
||||
use libconfig::{Config, net_settings};
|
||||
use futures::{future::FutureExt, select_biased};
|
||||
use libasync::{smoltcp::{Sockets, TcpStream},
|
||||
task};
|
||||
use libboard_artiq::drtio_routing;
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
use libboard_zynq::error_led::ErrorLED;
|
||||
use libboard_zynq::{self as zynq,
|
||||
smoltcp::{self,
|
||||
iface::{EthernetInterfaceBuilder, NeighborCache},
|
||||
time::Instant,
|
||||
wire::IpCidr},
|
||||
timer::GlobalTimer};
|
||||
use libconfig::{net_settings, Config};
|
||||
use libcortex_a9::{mutex::Mutex,
|
||||
semaphore::Semaphore,
|
||||
sync_channel::{Receiver, Sender}};
|
||||
use log::{error, info, warn};
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
|
||||
use crate::proto_async::*;
|
||||
use crate::kernel;
|
||||
use crate::rpc;
|
||||
use crate::moninj;
|
||||
use crate::mgmt;
|
||||
use crate::analyzer;
|
||||
use crate::rtio_mgt::{self, resolve_channel_name};
|
||||
#[cfg(has_drtio)]
|
||||
use crate::pl;
|
||||
use crate::{analyzer, kernel, mgmt, moninj,
|
||||
proto_async::*,
|
||||
rpc,
|
||||
rtio_mgt::{self, resolve_channel_name}};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
@@ -49,9 +43,9 @@ impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Error::NetworkError(error) => write!(f, "network error: {}", error),
|
||||
Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
||||
Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
||||
Error::BufferExhausted => write!(f, "buffer exhausted"),
|
||||
Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
||||
Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
||||
Error::BufferExhausted => write!(f, "buffer exhausted"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,15 +82,16 @@ static CACHE_STORE: Mutex<BTreeMap<String, Vec<i32>>> = Mutex::new(BTreeMap::new
|
||||
static DMA_RECORD_STORE: Mutex<BTreeMap<String, (Vec<u8>, i64)>> = Mutex::new(BTreeMap::new());
|
||||
|
||||
async fn write_header(stream: &TcpStream, reply: Reply) -> Result<()> {
|
||||
stream.send_slice(&[0x5a, 0x5a, 0x5a, 0x5a, reply.to_u8().unwrap()]).await?;
|
||||
stream
|
||||
.send_slice(&[0x5a, 0x5a, 0x5a, 0x5a, reply.to_u8().unwrap()])
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn read_request(stream: &TcpStream, allow_close: bool) -> Result<Option<Request>> {
|
||||
match expect(stream, &[0x5a, 0x5a, 0x5a, 0x5a]).await {
|
||||
Ok(true) => {}
|
||||
Ok(false) =>
|
||||
return Err(Error::UnexpectedPattern),
|
||||
Ok(false) => return Err(Error::UnexpectedPattern),
|
||||
Err(smoltcp::Error::Finished) => {
|
||||
if allow_close {
|
||||
info!("peer closed connection");
|
||||
@@ -105,11 +100,12 @@ async fn read_request(stream: &TcpStream, allow_close: bool) -> Result<Option<Re
|
||||
error!("peer unexpectedly closed connection");
|
||||
return Err(smoltcp::Error::Finished)?;
|
||||
}
|
||||
},
|
||||
Err(e) =>
|
||||
return Err(e)?,
|
||||
}
|
||||
Err(e) => return Err(e)?,
|
||||
}
|
||||
Ok(Some(FromPrimitive::from_i8(read_i8(&stream).await?).ok_or(Error::UnrecognizedPacket)?))
|
||||
Ok(Some(
|
||||
FromPrimitive::from_i8(read_i8(&stream).await?).ok_or(Error::UnrecognizedPacket)?,
|
||||
))
|
||||
}
|
||||
|
||||
async fn read_bytes(stream: &TcpStream, max_length: usize) -> Result<Vec<u8>> {
|
||||
@@ -128,9 +124,7 @@ async fn fast_send(sender: &mut Sender<'_, kernel::Message>, content: kernel::Me
|
||||
let mut content = content;
|
||||
for _ in 0..RETRY_LIMIT {
|
||||
match sender.try_send(content) {
|
||||
Ok(()) => {
|
||||
return
|
||||
},
|
||||
Ok(()) => return,
|
||||
Err(v) => {
|
||||
content = v;
|
||||
}
|
||||
@@ -142,10 +136,8 @@ async fn fast_send(sender: &mut Sender<'_, kernel::Message>, content: kernel::Me
|
||||
async fn fast_recv(receiver: &mut Receiver<'_, kernel::Message>) -> kernel::Message {
|
||||
for _ in 0..RETRY_LIMIT {
|
||||
match receiver.try_recv() {
|
||||
Ok(v) => {
|
||||
return v;
|
||||
},
|
||||
Err(()) => ()
|
||||
Ok(v) => return v,
|
||||
Err(()) => (),
|
||||
}
|
||||
}
|
||||
receiver.async_recv().await
|
||||
@@ -161,7 +153,11 @@ async fn write_exception_string(stream: &TcpStream, s: CSlice<'static, u8>) -> R
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kernel::Control>>, _up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) -> Result<()> {
|
||||
async fn handle_run_kernel(
|
||||
stream: Option<&TcpStream>,
|
||||
control: &Rc<RefCell<kernel::Control>>,
|
||||
_up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) -> Result<()> {
|
||||
control.borrow_mut().tx.async_send(kernel::Message::StartRequest).await;
|
||||
loop {
|
||||
let reply = control.borrow_mut().rx.async_recv().await;
|
||||
@@ -169,7 +165,7 @@ async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kern
|
||||
kernel::Message::RpcSend { is_async, data } => {
|
||||
if stream.is_none() {
|
||||
error!("Unexpected RPC from startup/idle kernel!");
|
||||
break
|
||||
break;
|
||||
}
|
||||
let stream = stream.unwrap();
|
||||
write_header(stream, Reply::RPCRequest).await?;
|
||||
@@ -196,46 +192,64 @@ async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kern
|
||||
fast_send(&mut control.tx, kernel::Message::RpcRecvReply(Ok(size))).await;
|
||||
match fast_recv(&mut control.rx).await {
|
||||
kernel::Message::RpcRecvRequest(slot) => slot,
|
||||
other => panic!("expected nested value slot from kernel CPU, not {:?}", other),
|
||||
other => {
|
||||
panic!("expected nested value slot from kernel CPU, not {:?}", other)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}).await?;
|
||||
control.borrow_mut().tx.async_send(kernel::Message::RpcRecvReply(Ok(0))).await;
|
||||
},
|
||||
})
|
||||
.await?;
|
||||
control
|
||||
.borrow_mut()
|
||||
.tx
|
||||
.async_send(kernel::Message::RpcRecvReply(Ok(0)))
|
||||
.await;
|
||||
}
|
||||
Request::RPCException => {
|
||||
let mut control = control.borrow_mut();
|
||||
match control.rx.async_recv().await {
|
||||
kernel::Message::RpcRecvRequest(_) => (),
|
||||
other => panic!("expected (ignored) root value slot from kernel CPU, not {:?}", other),
|
||||
}
|
||||
let id = read_i32(stream).await? as u32;
|
||||
let message = read_i32(stream).await? as u32;
|
||||
let param = [read_i64(stream).await?,
|
||||
read_i64(stream).await?,
|
||||
read_i64(stream).await?];
|
||||
let file = read_i32(stream).await? as u32;
|
||||
let line = read_i32(stream).await?;
|
||||
let column = read_i32(stream).await?;
|
||||
let id = read_i32(stream).await? as u32;
|
||||
let message = read_i32(stream).await? as u32;
|
||||
let param = [
|
||||
read_i64(stream).await?,
|
||||
read_i64(stream).await?,
|
||||
read_i64(stream).await?,
|
||||
];
|
||||
let file = read_i32(stream).await? as u32;
|
||||
let line = read_i32(stream).await?;
|
||||
let column = read_i32(stream).await?;
|
||||
let function = read_i32(stream).await? as u32;
|
||||
control.tx.async_send(kernel::Message::RpcRecvReply(Err(kernel::RPCException {
|
||||
id, message, param, file, line, column, function
|
||||
}))).await;
|
||||
},
|
||||
control
|
||||
.tx
|
||||
.async_send(kernel::Message::RpcRecvReply(Err(kernel::RPCException {
|
||||
id,
|
||||
message,
|
||||
param,
|
||||
file,
|
||||
line,
|
||||
column,
|
||||
function,
|
||||
})))
|
||||
.await;
|
||||
}
|
||||
_ => {
|
||||
error!("unexpected RPC request from host: {:?}", host_request);
|
||||
return Err(Error::UnrecognizedPacket)
|
||||
return Err(Error::UnrecognizedPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
kernel::Message::KernelFinished(async_errors) => {
|
||||
if let Some(stream) = stream {
|
||||
write_header(stream, Reply::KernelFinished).await?;
|
||||
write_i8(stream, async_errors as i8).await?;
|
||||
}
|
||||
break;
|
||||
},
|
||||
}
|
||||
kernel::Message::KernelException(exceptions, stack_pointers, backtrace, async_errors) => {
|
||||
match stream {
|
||||
Some(stream) => {
|
||||
@@ -247,12 +261,22 @@ async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kern
|
||||
let exception = exception.as_ref().unwrap();
|
||||
write_i32(stream, exception.id as i32).await?;
|
||||
|
||||
if exception.message.len() == usize::MAX { // exception with host string
|
||||
if exception.message.len() == usize::MAX {
|
||||
// exception with host string
|
||||
write_exception_string(stream, exception.message).await?;
|
||||
} else {
|
||||
let msg = str::from_utf8(unsafe { slice::from_raw_parts(exception.message.as_ptr(), exception.message.len()) })
|
||||
.unwrap()
|
||||
.replace("{rtio_channel_info:0}", &format!("0x{:04x}:{}", exception.param[0], resolve_channel_name(exception.param[0] as u32)));
|
||||
let msg = str::from_utf8(unsafe {
|
||||
slice::from_raw_parts(exception.message.as_ptr(), exception.message.len())
|
||||
})
|
||||
.unwrap()
|
||||
.replace(
|
||||
"{rtio_channel_info:0}",
|
||||
&format!(
|
||||
"0x{:04x}:{}",
|
||||
exception.param[0],
|
||||
resolve_channel_name(exception.param[0] as u32)
|
||||
),
|
||||
);
|
||||
write_exception_string(stream, unsafe { CSlice::new(msg.as_ptr(), msg.len()) }).await?;
|
||||
}
|
||||
|
||||
@@ -275,7 +299,7 @@ async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kern
|
||||
write_i32(stream, sp as i32).await?;
|
||||
}
|
||||
write_i8(stream, async_errors as i8).await?;
|
||||
},
|
||||
}
|
||||
None => {
|
||||
error!("Uncaught kernel exceptions: {:?}", exceptions);
|
||||
}
|
||||
@@ -284,27 +308,41 @@ async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kern
|
||||
}
|
||||
kernel::Message::CachePutRequest(key, value) => {
|
||||
CACHE_STORE.lock().insert(key, value);
|
||||
},
|
||||
}
|
||||
kernel::Message::CacheGetRequest(key) => {
|
||||
const DEFAULT: Vec<i32> = Vec::new();
|
||||
let value = CACHE_STORE.lock().get(&key).unwrap_or(&DEFAULT).clone();
|
||||
control.borrow_mut().tx.async_send(kernel::Message::CacheGetReply(value)).await;
|
||||
},
|
||||
control
|
||||
.borrow_mut()
|
||||
.tx
|
||||
.async_send(kernel::Message::CacheGetReply(value))
|
||||
.await;
|
||||
}
|
||||
kernel::Message::DmaPutRequest(recorder) => {
|
||||
DMA_RECORD_STORE.lock().insert(recorder.name, (recorder.buffer, recorder.duration));
|
||||
},
|
||||
DMA_RECORD_STORE
|
||||
.lock()
|
||||
.insert(recorder.name, (recorder.buffer, recorder.duration));
|
||||
}
|
||||
kernel::Message::DmaEraseRequest(name) => {
|
||||
// prevent possible OOM when we have large DMA record replacement.
|
||||
DMA_RECORD_STORE.lock().remove(&name);
|
||||
},
|
||||
}
|
||||
kernel::Message::DmaGetRequest(name) => {
|
||||
let result = DMA_RECORD_STORE.lock().get(&name).map(|v| v.clone());
|
||||
control.borrow_mut().tx.async_send(kernel::Message::DmaGetReply(result)).await;
|
||||
},
|
||||
control
|
||||
.borrow_mut()
|
||||
.tx
|
||||
.async_send(kernel::Message::DmaGetReply(result))
|
||||
.await;
|
||||
}
|
||||
#[cfg(has_drtio)]
|
||||
kernel::Message::UpDestinationsRequest(destination) => {
|
||||
let result = _up_destinations.borrow()[destination as usize];
|
||||
control.borrow_mut().tx.async_send(kernel::Message::UpDestinationsReply(result)).await;
|
||||
control
|
||||
.borrow_mut()
|
||||
.tx
|
||||
.async_send(kernel::Message::UpDestinationsReply(result))
|
||||
.await;
|
||||
}
|
||||
_ => {
|
||||
panic!("unexpected message from core1 while kernel was running: {:?}", reply);
|
||||
@@ -314,11 +352,17 @@ async fn handle_run_kernel(stream: Option<&TcpStream>, control: &Rc<RefCell<kern
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
async fn load_kernel(buffer: &Vec<u8>, control: &Rc<RefCell<kernel::Control>>, stream: Option<&TcpStream>) -> Result<()> {
|
||||
async fn load_kernel(
|
||||
buffer: &Vec<u8>,
|
||||
control: &Rc<RefCell<kernel::Control>>,
|
||||
stream: Option<&TcpStream>,
|
||||
) -> Result<()> {
|
||||
let mut control = control.borrow_mut();
|
||||
control.restart();
|
||||
control.tx.async_send(kernel::Message::LoadRequest(buffer.to_vec())).await;
|
||||
control
|
||||
.tx
|
||||
.async_send(kernel::Message::LoadRequest(buffer.to_vec()))
|
||||
.await;
|
||||
let reply = control.rx.async_recv().await;
|
||||
match reply {
|
||||
kernel::Message::LoadCompleted => {
|
||||
@@ -326,7 +370,7 @@ async fn load_kernel(buffer: &Vec<u8>, control: &Rc<RefCell<kernel::Control>>, s
|
||||
write_header(stream, Reply::LoadCompleted).await?;
|
||||
}
|
||||
Ok(())
|
||||
},
|
||||
}
|
||||
kernel::Message::LoadFailed => {
|
||||
if let Some(stream) = stream {
|
||||
write_header(stream, Reply::LoadFailed).await?;
|
||||
@@ -335,7 +379,7 @@ async fn load_kernel(buffer: &Vec<u8>, control: &Rc<RefCell<kernel::Control>>, s
|
||||
error!("Kernel load failed");
|
||||
}
|
||||
Err(Error::UnexpectedPattern)
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
error!("unexpected message from core1: {:?}", reply);
|
||||
if let Some(stream) = stream {
|
||||
@@ -347,7 +391,11 @@ async fn load_kernel(buffer: &Vec<u8>, control: &Rc<RefCell<kernel::Control>>, s
|
||||
}
|
||||
}
|
||||
|
||||
async fn handle_connection(stream: &mut TcpStream, control: Rc<RefCell<kernel::Control>>, up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>) -> Result<()> {
|
||||
async fn handle_connection(
|
||||
stream: &mut TcpStream,
|
||||
control: Rc<RefCell<kernel::Control>>,
|
||||
up_destinations: &Rc<RefCell<[bool; drtio_routing::DEST_COUNT]>>,
|
||||
) -> Result<()> {
|
||||
stream.set_ack_delay(None);
|
||||
|
||||
if !expect(stream, b"ARTIQ coredev\n").await? {
|
||||
@@ -364,17 +412,17 @@ async fn handle_connection(stream: &mut TcpStream, control: Rc<RefCell<kernel::C
|
||||
Request::SystemInfo => {
|
||||
write_header(stream, Reply::SystemInfo).await?;
|
||||
stream.send_slice("ARZQ".as_bytes()).await?;
|
||||
},
|
||||
}
|
||||
Request::LoadKernel => {
|
||||
let buffer = read_bytes(stream, 1024*1024).await?;
|
||||
let buffer = read_bytes(stream, 1024 * 1024).await?;
|
||||
load_kernel(&buffer, &control, Some(stream)).await?;
|
||||
},
|
||||
}
|
||||
Request::RunKernel => {
|
||||
handle_run_kernel(Some(stream), &control, &up_destinations).await?;
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
error!("unexpected request from host: {:?}", request);
|
||||
return Err(Error::UnrecognizedPacket)
|
||||
return Err(Error::UnrecognizedPacket);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -398,24 +446,24 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||
let ip_addrs = [
|
||||
IpCidr::new(net_addresses.ipv4_addr, 0),
|
||||
IpCidr::new(net_addresses.ipv6_ll_addr, 0),
|
||||
IpCidr::new(addr, 0)
|
||||
IpCidr::new(addr, 0),
|
||||
];
|
||||
EthernetInterfaceBuilder::new(&mut eth)
|
||||
.ethernet_addr(net_addresses.hardware_addr)
|
||||
.ip_addrs(ip_addrs)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.finalize()
|
||||
.ethernet_addr(net_addresses.hardware_addr)
|
||||
.ip_addrs(ip_addrs)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.finalize()
|
||||
}
|
||||
None => {
|
||||
let ip_addrs = [
|
||||
IpCidr::new(net_addresses.ipv4_addr, 0),
|
||||
IpCidr::new(net_addresses.ipv6_ll_addr, 0)
|
||||
IpCidr::new(net_addresses.ipv6_ll_addr, 0),
|
||||
];
|
||||
EthernetInterfaceBuilder::new(&mut eth)
|
||||
.ethernet_addr(net_addresses.hardware_addr)
|
||||
.ip_addrs(ip_addrs)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.finalize()
|
||||
.ethernet_addr(net_addresses.hardware_addr)
|
||||
.ip_addrs(ip_addrs)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.finalize()
|
||||
}
|
||||
};
|
||||
|
||||
@@ -424,8 +472,10 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||
// before, mutex was on io, but now that io isn't used...?
|
||||
let aux_mutex: Rc<Mutex<bool>> = Rc::new(Mutex::new(false));
|
||||
#[cfg(has_drtio)]
|
||||
let drtio_routing_table = Rc::new(RefCell::new(
|
||||
drtio_routing::config_routing_table(pl::csr::DRTIO.len(), &cfg)));
|
||||
let drtio_routing_table = Rc::new(RefCell::new(drtio_routing::config_routing_table(
|
||||
pl::csr::DRTIO.len(),
|
||||
&cfg,
|
||||
)));
|
||||
#[cfg(not(has_drtio))]
|
||||
let drtio_routing_table = Rc::new(RefCell::new(drtio_routing::RoutingTable::default_empty()));
|
||||
let up_destinations = Rc::new(RefCell::new([false; drtio_routing::DEST_COUNT]));
|
||||
@@ -497,14 +547,10 @@ pub fn main(timer: GlobalTimer, cfg: Config) {
|
||||
}
|
||||
});
|
||||
|
||||
Sockets::run(&mut iface, || {
|
||||
Instant::from_millis(timer.get_time().0 as i32)
|
||||
});
|
||||
Sockets::run(&mut iface, || Instant::from_millis(timer.get_time().0 as i32));
|
||||
}
|
||||
|
||||
|
||||
pub fn soft_panic_main(timer: GlobalTimer, cfg: Config) -> ! {
|
||||
|
||||
let net_addresses = net_settings::get_addresses(&cfg);
|
||||
info!("network addresses: {}", net_addresses);
|
||||
|
||||
@@ -522,24 +568,24 @@ pub fn soft_panic_main(timer: GlobalTimer, cfg: Config) -> ! {
|
||||
let ip_addrs = [
|
||||
IpCidr::new(net_addresses.ipv4_addr, 0),
|
||||
IpCidr::new(net_addresses.ipv6_ll_addr, 0),
|
||||
IpCidr::new(addr, 0)
|
||||
IpCidr::new(addr, 0),
|
||||
];
|
||||
EthernetInterfaceBuilder::new(&mut eth)
|
||||
.ethernet_addr(net_addresses.hardware_addr)
|
||||
.ip_addrs(ip_addrs)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.finalize()
|
||||
.ethernet_addr(net_addresses.hardware_addr)
|
||||
.ip_addrs(ip_addrs)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.finalize()
|
||||
}
|
||||
None => {
|
||||
let ip_addrs = [
|
||||
IpCidr::new(net_addresses.ipv4_addr, 0),
|
||||
IpCidr::new(net_addresses.ipv6_ll_addr, 0)
|
||||
IpCidr::new(net_addresses.ipv6_ll_addr, 0),
|
||||
];
|
||||
EthernetInterfaceBuilder::new(&mut eth)
|
||||
.ethernet_addr(net_addresses.hardware_addr)
|
||||
.ip_addrs(ip_addrs)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.finalize()
|
||||
.ethernet_addr(net_addresses.hardware_addr)
|
||||
.ip_addrs(ip_addrs)
|
||||
.neighbor_cache(neighbor_cache)
|
||||
.finalize()
|
||||
}
|
||||
};
|
||||
|
||||
@@ -555,7 +601,5 @@ pub fn soft_panic_main(timer: GlobalTimer, cfg: Config) -> ! {
|
||||
err_led.toggle(true);
|
||||
}
|
||||
|
||||
Sockets::run(&mut iface, || {
|
||||
Instant::from_millis(timer.get_time().0 as i32)
|
||||
});
|
||||
}
|
||||
Sockets::run(&mut iface, || Instant::from_millis(timer.get_time().0 as i32));
|
||||
}
|
||||
|
||||
@@ -13,14 +13,14 @@
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
use core::mem;
|
||||
|
||||
use cslice::CSlice;
|
||||
use unwind as uw;
|
||||
use libc::{c_int, c_void, uintptr_t};
|
||||
use log::{trace, error};
|
||||
use crate::kernel::KERNEL_IMAGE;
|
||||
|
||||
use dwarf::eh::{self, EHAction, EHContext};
|
||||
use libc::{c_int, c_void, uintptr_t};
|
||||
use log::{error, trace};
|
||||
use unwind as uw;
|
||||
|
||||
use crate::kernel::KERNEL_IMAGE;
|
||||
|
||||
const EXCEPTION_CLASS: uw::_Unwind_Exception_Class = 0x4d_4c_42_53_41_52_54_51; /* 'MLBSARTQ' */
|
||||
|
||||
@@ -32,13 +32,13 @@ const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Exception<'a> {
|
||||
pub id: u32,
|
||||
pub file: CSlice<'a, u8>,
|
||||
pub line: u32,
|
||||
pub column: u32,
|
||||
pub id: u32,
|
||||
pub file: CSlice<'a, u8>,
|
||||
pub line: u32,
|
||||
pub column: u32,
|
||||
pub function: CSlice<'a, u8>,
|
||||
pub message: CSlice<'a, u8>,
|
||||
pub param: [i64; 3]
|
||||
pub message: CSlice<'a, u8>,
|
||||
pub param: [i64; 3],
|
||||
}
|
||||
|
||||
fn str_err(_: core::str::Utf8Error) -> core::fmt::Error {
|
||||
@@ -55,12 +55,16 @@ fn exception_str<'a>(s: &'a CSlice<'a, u8>) -> Result<&'a str, core::str::Utf8Er
|
||||
|
||||
impl<'a> core::fmt::Debug for Exception<'a> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(f, "Exception {} from {} in {}:{}:{}, message: {}",
|
||||
write!(
|
||||
f,
|
||||
"Exception {} from {} in {}:{}:{}, message: {}",
|
||||
self.id,
|
||||
exception_str(&self.function).map_err(str_err)?,
|
||||
exception_str(&self.file).map_err(str_err)?,
|
||||
self.line, self.column,
|
||||
exception_str(&self.message).map_err(str_err)?)
|
||||
self.line,
|
||||
self.column,
|
||||
exception_str(&self.message).map_err(str_err)?
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,9 +95,9 @@ struct ExceptionBuffer {
|
||||
|
||||
static mut EXCEPTION_BUFFER: ExceptionBuffer = ExceptionBuffer {
|
||||
uw_exceptions: [uw::_Unwind_Exception {
|
||||
exception_class: EXCEPTION_CLASS,
|
||||
exception_class: EXCEPTION_CLASS,
|
||||
exception_cleanup: cleanup,
|
||||
private: [0; uw::unwinder_private_data_size],
|
||||
private: [0; uw::unwinder_private_data_size],
|
||||
}; MAX_INFLIGHT_EXCEPTIONS],
|
||||
exceptions: [None; MAX_INFLIGHT_EXCEPTIONS + 1],
|
||||
exception_stack: [-1; MAX_INFLIGHT_EXCEPTIONS + 1],
|
||||
@@ -102,17 +106,17 @@ static mut EXCEPTION_BUFFER: ExceptionBuffer = ExceptionBuffer {
|
||||
stack_pointers: [StackPointerBacktrace {
|
||||
stack_pointer: 0,
|
||||
initial_backtrace_size: 0,
|
||||
current_backtrace_size: 0
|
||||
current_backtrace_size: 0,
|
||||
}; MAX_INFLIGHT_EXCEPTIONS + 1],
|
||||
exception_count: 0
|
||||
exception_count: 0,
|
||||
};
|
||||
|
||||
pub unsafe extern fn reset_exception_buffer() {
|
||||
pub unsafe extern "C" fn reset_exception_buffer() {
|
||||
trace!("reset exception buffer");
|
||||
EXCEPTION_BUFFER.uw_exceptions = [uw::_Unwind_Exception {
|
||||
exception_class: EXCEPTION_CLASS,
|
||||
exception_class: EXCEPTION_CLASS,
|
||||
exception_cleanup: cleanup,
|
||||
private: [0; uw::unwinder_private_data_size],
|
||||
private: [0; uw::unwinder_private_data_size],
|
||||
}; MAX_INFLIGHT_EXCEPTIONS];
|
||||
EXCEPTION_BUFFER.exceptions = [None; MAX_INFLIGHT_EXCEPTIONS + 1];
|
||||
EXCEPTION_BUFFER.exception_stack = [-1; MAX_INFLIGHT_EXCEPTIONS + 1];
|
||||
@@ -120,26 +124,25 @@ pub unsafe extern fn reset_exception_buffer() {
|
||||
EXCEPTION_BUFFER.exception_count = 0;
|
||||
}
|
||||
|
||||
type _Unwind_Stop_Fn = extern "C" fn(version: c_int,
|
||||
actions: i32,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context,
|
||||
stop_parameter: *mut c_void)
|
||||
-> uw::_Unwind_Reason_Code;
|
||||
type _Unwind_Stop_Fn = extern "C" fn(
|
||||
version: c_int,
|
||||
actions: i32,
|
||||
exception_class: uw::_Unwind_Exception_Class,
|
||||
exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context,
|
||||
stop_parameter: *mut c_void,
|
||||
) -> uw::_Unwind_Reason_Code;
|
||||
|
||||
extern {
|
||||
extern "C" {
|
||||
// not defined in EHABI, but LLVM added it and is useful to us
|
||||
fn _Unwind_ForcedUnwind(exception: *mut uw::_Unwind_Exception,
|
||||
stop_fn: _Unwind_Stop_Fn,
|
||||
stop_parameter: *mut c_void) -> uw::_Unwind_Reason_Code;
|
||||
fn _Unwind_ForcedUnwind(
|
||||
exception: *mut uw::_Unwind_Exception,
|
||||
stop_fn: _Unwind_Stop_Fn,
|
||||
stop_parameter: *mut c_void,
|
||||
) -> uw::_Unwind_Reason_Code;
|
||||
}
|
||||
|
||||
unsafe fn find_eh_action(
|
||||
context: *mut uw::_Unwind_Context,
|
||||
foreign_exception: bool,
|
||||
id: u32,
|
||||
) -> Result<EHAction, ()> {
|
||||
unsafe fn find_eh_action(context: *mut uw::_Unwind_Context, foreign_exception: bool, id: u32) -> Result<EHAction, ()> {
|
||||
let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8;
|
||||
let mut ip_before_instr: c_int = 0;
|
||||
let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr);
|
||||
@@ -154,10 +157,11 @@ unsafe fn find_eh_action(
|
||||
eh::find_eh_action(lsda, &eh_context, foreign_exception, id)
|
||||
}
|
||||
|
||||
pub unsafe fn artiq_personality(_state: uw::_Unwind_State,
|
||||
exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
pub unsafe fn artiq_personality(
|
||||
_state: uw::_Unwind_State,
|
||||
exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context,
|
||||
) -> uw::_Unwind_Reason_Code {
|
||||
// we will only do phase 2 forced unwinding now
|
||||
// The DWARF unwinder assumes that _Unwind_Context holds things like the function
|
||||
// and LSDA pointers, however ARM EHABI places them into the exception object.
|
||||
@@ -165,9 +169,7 @@ pub unsafe fn artiq_personality(_state: uw::_Unwind_State,
|
||||
// take only the context pointer, GCC personality routines stash a pointer to
|
||||
// exception_object in the context, using location reserved for ARM's
|
||||
// "scratch register" (r12).
|
||||
uw::_Unwind_SetGR(context,
|
||||
uw::UNWIND_POINTER_REG,
|
||||
exception_object as uw::_Unwind_Ptr);
|
||||
uw::_Unwind_SetGR(context, uw::UNWIND_POINTER_REG, exception_object as uw::_Unwind_Ptr);
|
||||
// ...A more principled approach would be to provide the full definition of ARM's
|
||||
// _Unwind_Context in our libunwind bindings and fetch the required data from there
|
||||
// directly, bypassing DWARF compatibility functions.
|
||||
@@ -186,10 +188,8 @@ pub unsafe fn artiq_personality(_state: uw::_Unwind_State,
|
||||
};
|
||||
match eh_action {
|
||||
EHAction::None => return continue_unwind(exception_object, context),
|
||||
EHAction::Cleanup(lpad) |
|
||||
EHAction::Catch(lpad) => {
|
||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0,
|
||||
exception_object as uintptr_t);
|
||||
EHAction::Cleanup(lpad) | EHAction::Catch(lpad) => {
|
||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.0, exception_object as uintptr_t);
|
||||
uw::_Unwind_SetGR(context, UNWIND_DATA_REG.1, exception as *const _ as uw::_Unwind_Word);
|
||||
uw::_Unwind_SetIP(context, lpad);
|
||||
return uw::_URC_INSTALL_CONTEXT;
|
||||
@@ -199,9 +199,10 @@ pub unsafe fn artiq_personality(_state: uw::_Unwind_State,
|
||||
|
||||
// On ARM EHABI the personality routine is responsible for actually
|
||||
// unwinding a single stack frame before returning (ARM EHABI Sec. 6.1).
|
||||
unsafe fn continue_unwind(exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code {
|
||||
unsafe fn continue_unwind(
|
||||
exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context,
|
||||
) -> uw::_Unwind_Reason_Code {
|
||||
let reason = __gnu_unwind_frame(exception_object, context);
|
||||
if reason == uw::_URC_NO_REASON {
|
||||
uw::_URC_CONTINUE_UNWIND
|
||||
@@ -211,13 +212,14 @@ pub unsafe fn artiq_personality(_state: uw::_Unwind_State,
|
||||
}
|
||||
// defined in libgcc
|
||||
extern "C" {
|
||||
fn __gnu_unwind_frame(exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context)
|
||||
-> uw::_Unwind_Reason_Code;
|
||||
fn __gnu_unwind_frame(
|
||||
exception_object: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context,
|
||||
) -> uw::_Unwind_Reason_Code;
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe extern fn raise(exception: *const Exception) -> ! {
|
||||
pub unsafe extern "C" fn raise(exception: *const Exception) -> ! {
|
||||
use cslice::AsCSlice;
|
||||
|
||||
let count = EXCEPTION_BUFFER.exception_count;
|
||||
@@ -244,8 +246,11 @@ pub unsafe extern fn raise(exception: *const Exception) -> ! {
|
||||
}
|
||||
}
|
||||
assert!(found);
|
||||
let _result = _Unwind_ForcedUnwind(&mut EXCEPTION_BUFFER.uw_exceptions[stack[count - 1] as usize],
|
||||
stop_fn, core::ptr::null_mut());
|
||||
let _result = _Unwind_ForcedUnwind(
|
||||
&mut EXCEPTION_BUFFER.uw_exceptions[stack[count - 1] as usize],
|
||||
stop_fn,
|
||||
core::ptr::null_mut(),
|
||||
);
|
||||
} else {
|
||||
if count < MAX_INFLIGHT_EXCEPTIONS {
|
||||
trace!("raising exception at level {}", count);
|
||||
@@ -253,34 +258,33 @@ pub unsafe extern fn raise(exception: *const Exception) -> ! {
|
||||
for (i, slot) in EXCEPTION_BUFFER.exceptions.iter_mut().enumerate() {
|
||||
// we should always be able to find a slot
|
||||
if slot.is_none() {
|
||||
*slot = Some(
|
||||
*mem::transmute::<*const Exception, *const Exception<'static>>
|
||||
(exception));
|
||||
*slot = Some(*mem::transmute::<*const Exception, *const Exception<'static>>(
|
||||
exception,
|
||||
));
|
||||
EXCEPTION_BUFFER.exception_stack[count] = i as isize;
|
||||
EXCEPTION_BUFFER.uw_exceptions[i].private =
|
||||
[0; uw::unwinder_private_data_size];
|
||||
EXCEPTION_BUFFER.uw_exceptions[i].private = [0; uw::unwinder_private_data_size];
|
||||
EXCEPTION_BUFFER.stack_pointers[i] = StackPointerBacktrace {
|
||||
stack_pointer: 0,
|
||||
initial_backtrace_size: EXCEPTION_BUFFER.backtrace_size,
|
||||
current_backtrace_size: 0,
|
||||
};
|
||||
EXCEPTION_BUFFER.exception_count += 1;
|
||||
let _result = _Unwind_ForcedUnwind(&mut EXCEPTION_BUFFER.uw_exceptions[i],
|
||||
stop_fn, core::ptr::null_mut());
|
||||
let _result =
|
||||
_Unwind_ForcedUnwind(&mut EXCEPTION_BUFFER.uw_exceptions[i], stop_fn, core::ptr::null_mut());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
error!("too many nested exceptions");
|
||||
// TODO: better reporting?
|
||||
let exception = Exception {
|
||||
id: get_exception_id("RuntimeError"),
|
||||
file: file!().as_c_slice(),
|
||||
line: line!(),
|
||||
column: column!(),
|
||||
id: get_exception_id("RuntimeError"),
|
||||
file: file!().as_c_slice(),
|
||||
line: line!(),
|
||||
column: column!(),
|
||||
// https://github.com/rust-lang/rfcs/pull/1719
|
||||
function: "__artiq_raise".as_c_slice(),
|
||||
message: "too many nested exceptions".as_c_slice(),
|
||||
param: [0, 0, 0]
|
||||
message: "too many nested exceptions".as_c_slice(),
|
||||
param: [0, 0, 0],
|
||||
};
|
||||
EXCEPTION_BUFFER.exceptions[MAX_INFLIGHT_EXCEPTIONS] = Some(mem::transmute(exception));
|
||||
EXCEPTION_BUFFER.stack_pointers[MAX_INFLIGHT_EXCEPTIONS] = Default::default();
|
||||
@@ -291,17 +295,20 @@ pub unsafe extern fn raise(exception: *const Exception) -> ! {
|
||||
unreachable!();
|
||||
}
|
||||
|
||||
pub unsafe extern fn resume() -> ! {
|
||||
pub unsafe extern "C" fn resume() -> ! {
|
||||
trace!("resume");
|
||||
assert!(EXCEPTION_BUFFER.exception_count != 0);
|
||||
let i = EXCEPTION_BUFFER.exception_stack[EXCEPTION_BUFFER.exception_count - 1];
|
||||
assert!(i != -1);
|
||||
let _result = _Unwind_ForcedUnwind(&mut EXCEPTION_BUFFER.uw_exceptions[i as usize],
|
||||
stop_fn, core::ptr::null_mut());
|
||||
let _result = _Unwind_ForcedUnwind(
|
||||
&mut EXCEPTION_BUFFER.uw_exceptions[i as usize],
|
||||
stop_fn,
|
||||
core::ptr::null_mut(),
|
||||
);
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub unsafe extern fn end_catch() {
|
||||
pub unsafe extern "C" fn end_catch() {
|
||||
let mut count = EXCEPTION_BUFFER.exception_count;
|
||||
assert!(count != 0);
|
||||
// we remove all exceptions with SP <= current exception SP
|
||||
@@ -309,8 +316,7 @@ pub unsafe extern fn end_catch() {
|
||||
let index = EXCEPTION_BUFFER.exception_stack[count - 1] as usize;
|
||||
EXCEPTION_BUFFER.exception_stack[count - 1] = -1;
|
||||
EXCEPTION_BUFFER.exceptions[index] = None;
|
||||
let outer_sp = EXCEPTION_BUFFER.stack_pointers
|
||||
[index].stack_pointer;
|
||||
let outer_sp = EXCEPTION_BUFFER.stack_pointers[index].stack_pointer;
|
||||
count -= 1;
|
||||
for i in (0..count).rev() {
|
||||
let index = EXCEPTION_BUFFER.exception_stack[i];
|
||||
@@ -334,8 +340,7 @@ pub unsafe extern fn end_catch() {
|
||||
};
|
||||
}
|
||||
|
||||
extern fn cleanup(_unwind_code: uw::_Unwind_Reason_Code,
|
||||
_uw_exception: *mut uw::_Unwind_Exception) {
|
||||
extern "C" fn cleanup(_unwind_code: uw::_Unwind_Reason_Code, _uw_exception: *mut uw::_Unwind_Exception) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
@@ -345,18 +350,26 @@ fn uncaught_exception() -> ! {
|
||||
for i in 0..EXCEPTION_BUFFER.exception_count {
|
||||
if EXCEPTION_BUFFER.exception_stack[i] != i as isize {
|
||||
// find the correct index
|
||||
let index = EXCEPTION_BUFFER.exception_stack
|
||||
let index = EXCEPTION_BUFFER
|
||||
.exception_stack
|
||||
.iter()
|
||||
.position(|v| *v == i as isize).unwrap();
|
||||
.position(|v| *v == i as isize)
|
||||
.unwrap();
|
||||
let a = EXCEPTION_BUFFER.exception_stack[index];
|
||||
let b = EXCEPTION_BUFFER.exception_stack[i];
|
||||
assert!(a != -1 && b != -1);
|
||||
core::mem::swap(&mut EXCEPTION_BUFFER.exception_stack[index],
|
||||
&mut EXCEPTION_BUFFER.exception_stack[i]);
|
||||
core::mem::swap(&mut EXCEPTION_BUFFER.exceptions[a as usize],
|
||||
&mut EXCEPTION_BUFFER.exceptions[b as usize]);
|
||||
core::mem::swap(&mut EXCEPTION_BUFFER.stack_pointers[a as usize],
|
||||
&mut EXCEPTION_BUFFER.stack_pointers[b as usize]);
|
||||
core::mem::swap(
|
||||
&mut EXCEPTION_BUFFER.exception_stack[index],
|
||||
&mut EXCEPTION_BUFFER.exception_stack[i],
|
||||
);
|
||||
core::mem::swap(
|
||||
&mut EXCEPTION_BUFFER.exceptions[a as usize],
|
||||
&mut EXCEPTION_BUFFER.exceptions[b as usize],
|
||||
);
|
||||
core::mem::swap(
|
||||
&mut EXCEPTION_BUFFER.stack_pointers[a as usize],
|
||||
&mut EXCEPTION_BUFFER.stack_pointers[b as usize],
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -364,17 +377,20 @@ fn uncaught_exception() -> ! {
|
||||
crate::kernel::core1::terminate(
|
||||
EXCEPTION_BUFFER.exceptions[..EXCEPTION_BUFFER.exception_count].as_ref(),
|
||||
EXCEPTION_BUFFER.stack_pointers[..EXCEPTION_BUFFER.exception_count].as_ref(),
|
||||
EXCEPTION_BUFFER.backtrace[..EXCEPTION_BUFFER.backtrace_size].as_mut())
|
||||
EXCEPTION_BUFFER.backtrace[..EXCEPTION_BUFFER.backtrace_size].as_mut(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// stop function which would be executed when we unwind each frame
|
||||
extern fn stop_fn(_version: c_int,
|
||||
actions: i32,
|
||||
_uw_exception_class: uw::_Unwind_Exception_Class,
|
||||
_uw_exception: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context,
|
||||
_stop_parameter: *mut c_void) -> uw::_Unwind_Reason_Code {
|
||||
extern "C" fn stop_fn(
|
||||
_version: c_int,
|
||||
actions: i32,
|
||||
_uw_exception_class: uw::_Unwind_Exception_Class,
|
||||
_uw_exception: *mut uw::_Unwind_Exception,
|
||||
context: *mut uw::_Unwind_Context,
|
||||
_stop_parameter: *mut c_void,
|
||||
) -> uw::_Unwind_Reason_Code {
|
||||
unsafe {
|
||||
let load_addr = KERNEL_IMAGE.as_ref().unwrap().get_load_addr();
|
||||
let backtrace_size = EXCEPTION_BUFFER.backtrace_size;
|
||||
@@ -423,7 +439,7 @@ static EXCEPTION_ID_LOOKUP: [(&str, u32); 11] = [
|
||||
pub fn get_exception_id(name: &str) -> u32 {
|
||||
for (n, id) in EXCEPTION_ID_LOOKUP.iter() {
|
||||
if *n == name {
|
||||
return *id
|
||||
return *id;
|
||||
}
|
||||
}
|
||||
unimplemented!("unallocated internal exception id")
|
||||
@@ -431,26 +447,24 @@ pub fn get_exception_id(name: &str) -> u32 {
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! artiq_raise {
|
||||
($name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => ({
|
||||
($name:expr, $message:expr, $param0:expr, $param1:expr, $param2:expr) => {{
|
||||
use cslice::AsCSlice;
|
||||
let name_id = $crate::eh_artiq::get_exception_id($name);
|
||||
let message_cl = $message.clone();
|
||||
let exn = $crate::eh_artiq::Exception {
|
||||
id: name_id,
|
||||
file: file!().as_c_slice(),
|
||||
line: line!(),
|
||||
column: column!(),
|
||||
id: name_id,
|
||||
file: file!().as_c_slice(),
|
||||
line: line!(),
|
||||
column: column!(),
|
||||
// https://github.com/rust-lang/rfcs/pull/1719
|
||||
function: "(Rust function)".as_c_slice(),
|
||||
message: message_cl.as_c_slice(),
|
||||
param: [$param0, $param1, $param2]
|
||||
message: message_cl.as_c_slice(),
|
||||
param: [$param0, $param1, $param2],
|
||||
};
|
||||
#[allow(unused_unsafe)]
|
||||
unsafe {
|
||||
$crate::eh_artiq::raise(&exn)
|
||||
}
|
||||
});
|
||||
($name:expr, $message:expr) => ({
|
||||
artiq_raise!($name, $message, 0, 0, 0)
|
||||
});
|
||||
}};
|
||||
($name:expr, $message:expr) => {{ artiq_raise!($name, $message, 0, 0, 0) }};
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
use libboard_zynq;
|
||||
|
||||
use crate::artiq_raise;
|
||||
|
||||
pub static mut I2C_BUS: Option<libboard_zynq::i2c::I2c> = None;
|
||||
|
||||
pub extern fn start(busno: i32) {
|
||||
pub extern "C" fn start(busno: i32) {
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
@@ -14,7 +15,7 @@ pub extern fn start(busno: i32) {
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn restart(busno: i32) {
|
||||
pub extern "C" fn restart(busno: i32) {
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
@@ -25,7 +26,7 @@ pub extern fn restart(busno: i32) {
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn stop(busno: i32) {
|
||||
pub extern "C" fn stop(busno: i32) {
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
@@ -36,7 +37,7 @@ pub extern fn stop(busno: i32) {
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn write(busno: i32, data: i32) -> bool {
|
||||
pub extern "C" fn write(busno: i32, data: i32) -> bool {
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
@@ -48,7 +49,7 @@ pub extern fn write(busno: i32, data: i32) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn read(busno: i32, ack: bool) -> i32 {
|
||||
pub extern "C" fn read(busno: i32, ack: bool) -> i32 {
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
@@ -60,11 +61,12 @@ pub extern fn read(busno: i32, ack: bool) -> i32 {
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn switch_select(busno: i32, address: i32, mask: i32) {
|
||||
pub extern "C" fn switch_select(busno: i32, address: i32, mask: i32) {
|
||||
if busno > 0 {
|
||||
artiq_raise!("I2CError", "I2C bus could not be accessed");
|
||||
}
|
||||
let ch = match mask { //decode from mainline, PCA9548-centric API
|
||||
let ch = match mask {
|
||||
//decode from mainline, PCA9548-centric API
|
||||
0x00 => None,
|
||||
0x01 => Some(0),
|
||||
0x02 => Some(1),
|
||||
@@ -74,10 +76,15 @@ pub extern fn switch_select(busno: i32, address: i32, mask: i32) {
|
||||
0x20 => Some(5),
|
||||
0x40 => Some(6),
|
||||
0x80 => Some(7),
|
||||
_ => artiq_raise!("I2CError", "switch select supports only one channel")
|
||||
_ => artiq_raise!("I2CError", "switch select supports only one channel"),
|
||||
};
|
||||
unsafe {
|
||||
if (&mut I2C_BUS).as_mut().unwrap().pca954x_select(address as u8, ch).is_err() {
|
||||
if (&mut I2C_BUS)
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.pca954x_select(address as u8, ch)
|
||||
.is_err()
|
||||
{
|
||||
artiq_raise!("I2CError", "switch select failed");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
use libboard_zynq::{gic, mpcore, println, stdio};
|
||||
use libcortex_a9::{
|
||||
asm, interrupt_handler,
|
||||
regs::MPIDR,
|
||||
spin_lock_yield, notify_spin_lock
|
||||
};
|
||||
use libregister::RegisterR;
|
||||
use core::sync::atomic::{AtomicBool, Ordering};
|
||||
|
||||
use libboard_zynq::{gic, mpcore, println, stdio};
|
||||
use libcortex_a9::{asm, interrupt_handler, notify_spin_lock, regs::MPIDR, spin_lock_yield};
|
||||
use libregister::RegisterR;
|
||||
|
||||
extern "C" {
|
||||
static mut __stack1_start: u32;
|
||||
fn main_core1() -> !;
|
||||
|
||||
@@ -1,29 +1,25 @@
|
||||
use core::ffi::VaList;
|
||||
use core::ptr;
|
||||
use core::str;
|
||||
use alloc::vec;
|
||||
use core::{ffi::VaList, ptr, str};
|
||||
|
||||
use libc::{c_char, c_int, size_t};
|
||||
use libm;
|
||||
use log::{info, warn};
|
||||
|
||||
use alloc::vec;
|
||||
|
||||
use crate::eh_artiq;
|
||||
use crate::rtio;
|
||||
use crate::i2c;
|
||||
use super::rpc::{rpc_send, rpc_send_async, rpc_recv};
|
||||
use super::dma;
|
||||
use super::cache;
|
||||
use super::core1::rtio_get_destination_status;
|
||||
use super::{cache,
|
||||
core1::rtio_get_destination_status,
|
||||
dma,
|
||||
rpc::{rpc_recv, rpc_send, rpc_send_async}};
|
||||
use crate::{eh_artiq, i2c, rtio};
|
||||
|
||||
extern "C" {
|
||||
fn vsnprintf_(buffer: *mut c_char, count: size_t, format: *const c_char, va: VaList) -> c_int;
|
||||
}
|
||||
|
||||
unsafe extern fn core_log(fmt: *const c_char, mut args: ...) {
|
||||
unsafe extern "C" fn core_log(fmt: *const c_char, mut args: ...) {
|
||||
let size = vsnprintf_(ptr::null_mut(), 0, fmt, args.as_va_list()) as usize;
|
||||
let mut buf = vec![0; size + 1];
|
||||
vsnprintf_(buf.as_mut_ptr() as *mut i8, size + 1, fmt, args.as_va_list());
|
||||
let buf: &[u8] = &buf.as_slice()[..size-1]; // strip \n and NUL
|
||||
let buf: &[u8] = &buf.as_slice()[..size - 1]; // strip \n and NUL
|
||||
match str::from_utf8(buf) {
|
||||
Ok(s) => info!("kernel: {}", s),
|
||||
Err(e) => {
|
||||
@@ -33,14 +29,13 @@ unsafe extern fn core_log(fmt: *const c_char, mut args: ...) {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe extern fn rtio_log(fmt: *const c_char, mut args: ...) {
|
||||
unsafe extern "C" fn rtio_log(fmt: *const c_char, mut args: ...) {
|
||||
let size = vsnprintf_(ptr::null_mut(), 0, fmt, args.as_va_list()) as usize;
|
||||
let mut buf = vec![0; size + 1];
|
||||
vsnprintf_(buf.as_mut_ptr(), size + 1, fmt, args.as_va_list());
|
||||
rtio::write_log(buf.as_slice());
|
||||
}
|
||||
|
||||
|
||||
macro_rules! api {
|
||||
($i:ident) => ({
|
||||
extern { static $i: u8; }
|
||||
@@ -56,24 +51,25 @@ macro_rules! api {
|
||||
}
|
||||
|
||||
macro_rules! api_libm_f64f64 {
|
||||
($i:ident) => ({
|
||||
extern fn $i(x: f64) -> f64 {
|
||||
($i:ident) => {{
|
||||
extern "C" fn $i(x: f64) -> f64 {
|
||||
libm::$i(x)
|
||||
}
|
||||
api!($i = $i)
|
||||
})
|
||||
}};
|
||||
}
|
||||
|
||||
macro_rules! api_libm_f64f64f64 {
|
||||
($i:ident) => ({
|
||||
extern fn $i(x: f64, y: f64) -> f64 {
|
||||
($i:ident) => {{
|
||||
extern "C" fn $i(x: f64, y: f64) -> f64 {
|
||||
libm::$i(x, y)
|
||||
}
|
||||
api!($i = $i)
|
||||
})
|
||||
}};
|
||||
}
|
||||
|
||||
pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
#[rustfmt::skip]
|
||||
let api = &[
|
||||
// timing
|
||||
api!(now_mu = rtio::now_mu),
|
||||
@@ -124,6 +120,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
api!(__aeabi_ddiv),
|
||||
api!(__aeabi_dmul),
|
||||
api!(__aeabi_dsub),
|
||||
|
||||
// Double-precision floating-point comparison helper functions
|
||||
// RTABI chapter 4.1.2, Table 3
|
||||
api!(__aeabi_dcmpeq),
|
||||
@@ -133,12 +130,14 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
api!(__aeabi_dcmpge),
|
||||
api!(__aeabi_dcmpgt),
|
||||
api!(__aeabi_dcmpun),
|
||||
|
||||
// Single-precision floating-point arithmetic helper functions
|
||||
// RTABI chapter 4.1.2, Table 4
|
||||
api!(__aeabi_fadd),
|
||||
api!(__aeabi_fdiv),
|
||||
api!(__aeabi_fmul),
|
||||
api!(__aeabi_fsub),
|
||||
|
||||
// Single-precision floating-point comparison helper functions
|
||||
// RTABI chapter 4.1.2, Table 5
|
||||
api!(__aeabi_fcmpeq),
|
||||
@@ -148,6 +147,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
api!(__aeabi_fcmpge),
|
||||
api!(__aeabi_fcmpgt),
|
||||
api!(__aeabi_fcmpun),
|
||||
|
||||
// Floating-point to integer conversions.
|
||||
// RTABI chapter 4.1.2, Table 6
|
||||
api!(__aeabi_d2iz),
|
||||
@@ -158,9 +158,11 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
api!(__aeabi_f2uiz),
|
||||
api!(__aeabi_f2lz),
|
||||
api!(__aeabi_f2ulz),
|
||||
|
||||
// Conversions between floating types.
|
||||
// RTABI chapter 4.1.2, Table 7
|
||||
api!(__aeabi_f2d),
|
||||
|
||||
// Integer to floating-point conversions.
|
||||
// RTABI chapter 4.1.2, Table 8
|
||||
api!(__aeabi_i2d),
|
||||
@@ -171,12 +173,14 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
api!(__aeabi_ui2f),
|
||||
api!(__aeabi_l2f),
|
||||
api!(__aeabi_ul2f),
|
||||
|
||||
// Long long helper functions
|
||||
// RTABI chapter 4.2, Table 9
|
||||
api!(__aeabi_lmul),
|
||||
api!(__aeabi_llsl),
|
||||
api!(__aeabi_llsr),
|
||||
api!(__aeabi_lasr),
|
||||
|
||||
// Integer division functions
|
||||
// RTABI chapter 4.3.1
|
||||
api!(__aeabi_idiv),
|
||||
@@ -184,6 +188,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
api!(__aeabi_idivmod),
|
||||
api!(__aeabi_uidiv),
|
||||
api!(__aeabi_uldivmod),
|
||||
|
||||
// 4.3.4 Memory copying, clearing, and setting
|
||||
api!(__aeabi_memcpy8),
|
||||
api!(__aeabi_memcpy4),
|
||||
@@ -199,10 +204,30 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
api!(__aeabi_memclr),
|
||||
|
||||
// libc
|
||||
api!(memcpy, extern { fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; }),
|
||||
api!(memmove, extern { fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8; }),
|
||||
api!(memset, extern { fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8; }),
|
||||
api!(memcmp, extern { fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; }),
|
||||
api!(
|
||||
memcpy,
|
||||
extern "C" {
|
||||
fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
|
||||
}
|
||||
),
|
||||
api!(
|
||||
memmove,
|
||||
extern "C" {
|
||||
fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
|
||||
}
|
||||
),
|
||||
api!(
|
||||
memset,
|
||||
extern "C" {
|
||||
fn memset(s: *mut u8, c: i32, n: usize) -> *mut u8;
|
||||
}
|
||||
),
|
||||
api!(
|
||||
memcmp,
|
||||
extern "C" {
|
||||
fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32;
|
||||
}
|
||||
),
|
||||
|
||||
// exceptions
|
||||
api!(_Unwind_Resume = unwind::_Unwind_Resume),
|
||||
@@ -210,6 +235,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
api!(__nac3_raise = eh_artiq::raise),
|
||||
api!(__nac3_resume = eh_artiq::resume),
|
||||
api!(__nac3_end_catch = eh_artiq::end_catch),
|
||||
|
||||
// legacy exception symbols
|
||||
api!(__artiq_personality = eh_artiq::artiq_personality),
|
||||
api!(__artiq_raise = eh_artiq::raise),
|
||||
@@ -241,7 +267,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
api_libm_f64f64!(fabs),
|
||||
api_libm_f64f64!(floor),
|
||||
{
|
||||
extern fn fma(x: f64, y: f64, z: f64) -> f64 {
|
||||
extern "C" fn fma(x: f64, y: f64, z: f64) -> f64 {
|
||||
libm::fma(x, y, z)
|
||||
}
|
||||
api!(fma = fma)
|
||||
@@ -253,7 +279,7 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
api_libm_f64f64!(j0),
|
||||
api_libm_f64f64!(j1),
|
||||
{
|
||||
extern fn jn(n: i32, x: f64) -> f64 {
|
||||
extern "C" fn jn(n: i32, x: f64) -> f64 {
|
||||
libm::jn(n, x)
|
||||
}
|
||||
api!(jn = jn)
|
||||
@@ -275,13 +301,13 @@ pub fn resolve(required: &[u8]) -> Option<u32> {
|
||||
api_libm_f64f64!(y0),
|
||||
api_libm_f64f64!(y1),
|
||||
{
|
||||
extern fn yn(n: i32, x: f64) -> f64 {
|
||||
extern "C" fn yn(n: i32, x: f64) -> f64 {
|
||||
libm::yn(n, x)
|
||||
}
|
||||
api!(yn = yn)
|
||||
},
|
||||
];
|
||||
api.iter()
|
||||
.find(|&&(exported, _)| exported.as_bytes() == required)
|
||||
.map(|&(_, ptr)| ptr as u32)
|
||||
.find(|&&(exported, _)| exported.as_bytes() == required)
|
||||
.map(|&(_, ptr)| ptr as u32)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
use alloc::{string::String, boxed::Box};
|
||||
use cslice::{CSlice, AsCSlice};
|
||||
use core::mem::{transmute, forget};
|
||||
use super::{KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, Message};
|
||||
use alloc::{boxed::Box, string::String};
|
||||
use core::mem::{forget, transmute};
|
||||
|
||||
pub extern fn get(key: CSlice<u8>) -> &CSlice<'static, i32> {
|
||||
use cslice::{AsCSlice, CSlice};
|
||||
|
||||
use super::{Message, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
|
||||
|
||||
pub extern "C" fn get(key: CSlice<u8>) -> &CSlice<'static, i32> {
|
||||
let key = String::from_utf8(key.as_ref().to_vec()).unwrap();
|
||||
unsafe {
|
||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::CacheGetRequest(key));
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::CacheGetRequest(key));
|
||||
let msg = KERNEL_CHANNEL_0TO1.as_mut().unwrap().recv();
|
||||
if let Message::CacheGetReply(v) = msg {
|
||||
let leaked = Box::new(v.as_c_slice());
|
||||
@@ -20,11 +25,13 @@ pub extern fn get(key: CSlice<u8>) -> &CSlice<'static, i32> {
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn put(key: CSlice<u8>, list: &CSlice<i32>) {
|
||||
pub extern "C" fn put(key: CSlice<u8>, list: &CSlice<i32>) {
|
||||
let key = String::from_utf8(key.as_ref().to_vec()).unwrap();
|
||||
let value = list.as_ref().to_vec();
|
||||
unsafe {
|
||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::CachePutRequest(key, value));
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::CachePutRequest(key, value));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use libcortex_a9::sync_channel::{Sender, Receiver};
|
||||
use core::mem::{forget, replace};
|
||||
|
||||
use libcortex_a9::sync_channel::{Receiver, Sender};
|
||||
use libsupport_zynq::boot::Core1;
|
||||
|
||||
use super::{CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK, Message};
|
||||
use super::{Message, CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK};
|
||||
use crate::irq::restart_core1;
|
||||
|
||||
use core::mem::{forget, replace};
|
||||
|
||||
pub struct Control {
|
||||
pub tx: Sender<'static, Message>,
|
||||
pub rx: Receiver<'static, Message>,
|
||||
@@ -53,4 +53,3 @@ impl Control {
|
||||
forget(replace(&mut self.rx, core0_rx));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,31 +1,20 @@
|
||||
//! Kernel prologue/epilogue that runs on the 2nd CPU core
|
||||
|
||||
use core::{mem, ptr, cell::UnsafeCell};
|
||||
use alloc::borrow::ToOwned;
|
||||
use log::{debug, info, error};
|
||||
use cslice::CSlice;
|
||||
use core::{cell::UnsafeCell, mem, ptr};
|
||||
|
||||
use libcortex_a9::{
|
||||
enable_fpu,
|
||||
cache::{dcci_slice, iciallu, bpiall},
|
||||
asm::{dsb, isb},
|
||||
sync_channel,
|
||||
};
|
||||
use libboard_zynq::{mpcore, gic};
|
||||
use cslice::CSlice;
|
||||
use dyld::{self, elf::EXIDX_Entry, Library};
|
||||
use libboard_zynq::{gic, mpcore};
|
||||
use libcortex_a9::{asm::{dsb, isb},
|
||||
cache::{bpiall, dcci_slice, iciallu},
|
||||
enable_fpu, sync_channel};
|
||||
use libsupport_zynq::ram;
|
||||
use dyld::{self, Library, elf::EXIDX_Entry};
|
||||
use log::{debug, error, info};
|
||||
|
||||
use super::{api::resolve, dma, rpc::rpc_send_async, Message, CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_SEM, INIT_LOCK,
|
||||
KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, KERNEL_IMAGE};
|
||||
use crate::{eh_artiq, get_async_errors, rtio};
|
||||
use super::{
|
||||
api::resolve,
|
||||
rpc::rpc_send_async,
|
||||
INIT_LOCK,
|
||||
CHANNEL_0TO1, CHANNEL_1TO0,
|
||||
CHANNEL_SEM,
|
||||
KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0,
|
||||
KERNEL_IMAGE,
|
||||
Message,
|
||||
dma,
|
||||
};
|
||||
|
||||
// linker symbols
|
||||
extern "C" {
|
||||
@@ -38,13 +27,13 @@ extern "C" {
|
||||
unsafe fn attribute_writeback(typeinfo: *const ()) {
|
||||
struct Attr {
|
||||
offset: usize,
|
||||
tag: CSlice<'static, u8>,
|
||||
name: CSlice<'static, u8>
|
||||
tag: CSlice<'static, u8>,
|
||||
name: CSlice<'static, u8>,
|
||||
}
|
||||
|
||||
struct Type {
|
||||
attributes: *const *const Attr,
|
||||
objects: *const *const ()
|
||||
objects: *const *const (),
|
||||
}
|
||||
|
||||
let mut tys = typeinfo as *const *const Type;
|
||||
@@ -63,11 +52,16 @@ unsafe fn attribute_writeback(typeinfo: *const ()) {
|
||||
attributes = attributes.offset(1);
|
||||
|
||||
if (*attribute).tag.len() > 0 {
|
||||
rpc_send_async(0, &(*attribute).tag, [
|
||||
&object as *const _ as *const (),
|
||||
&(*attribute).name as *const _ as *const (),
|
||||
(object as usize + (*attribute).offset) as *const ()
|
||||
].as_ptr());
|
||||
rpc_send_async(
|
||||
0,
|
||||
&(*attribute).tag,
|
||||
[
|
||||
&object as *const _ as *const (),
|
||||
&(*attribute).name as *const _ as *const (),
|
||||
(object as usize + (*attribute).offset) as *const (),
|
||||
]
|
||||
.as_ptr(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -82,7 +76,8 @@ pub struct KernelImage {
|
||||
|
||||
impl KernelImage {
|
||||
pub fn new(library: Library) -> Result<Self, dyld::Error> {
|
||||
let __modinit__ = library.lookup(b"__modinit__")
|
||||
let __modinit__ = library
|
||||
.lookup(b"__modinit__")
|
||||
.ok_or(dyld::Error::Lookup("__modinit__".to_owned()))?;
|
||||
let typeinfo = library.lookup(b"typeinfo");
|
||||
|
||||
@@ -90,8 +85,7 @@ impl KernelImage {
|
||||
let bss_start = library.lookup(b"__bss_start");
|
||||
let end = library.lookup(b"_end");
|
||||
if let Some(bss_start) = bss_start {
|
||||
let end = end
|
||||
.ok_or(dyld::Error::Lookup("_end".to_owned()))?;
|
||||
let end = end.ok_or(dyld::Error::Lookup("_end".to_owned()))?;
|
||||
unsafe {
|
||||
ptr::write_bytes(bss_start as *mut u8, 0, (end - bss_start) as usize);
|
||||
}
|
||||
@@ -126,9 +120,7 @@ impl KernelImage {
|
||||
}
|
||||
|
||||
pub fn get_load_addr(&self) -> usize {
|
||||
unsafe {
|
||||
self.library.get().as_ref().unwrap().image.as_ptr() as usize
|
||||
}
|
||||
unsafe { self.library.get().as_ref().unwrap().image.as_ptr() as usize }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,20 +156,19 @@ pub extern "C" fn main_core1() {
|
||||
let message = core1_rx.recv();
|
||||
match message {
|
||||
Message::LoadRequest(data) => {
|
||||
let result = dyld::load(&data, &resolve)
|
||||
.and_then(KernelImage::new);
|
||||
let result = dyld::load(&data, &resolve).and_then(KernelImage::new);
|
||||
match result {
|
||||
Ok(kernel) => {
|
||||
loaded_kernel = Some(kernel);
|
||||
debug!("kernel loaded");
|
||||
core1_tx.send(Message::LoadCompleted);
|
||||
},
|
||||
}
|
||||
Err(error) => {
|
||||
error!("failed to load shared library: {}", error);
|
||||
core1_tx.send(Message::LoadFailed);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
Message::StartRequest => {
|
||||
info!("kernel starting");
|
||||
if let Some(kernel) = loaded_kernel.take() {
|
||||
@@ -202,9 +193,11 @@ pub extern "C" fn main_core1() {
|
||||
}
|
||||
|
||||
/// Called by eh_artiq
|
||||
pub fn terminate(exceptions: &'static [Option<eh_artiq::Exception<'static>>],
|
||||
stack_pointers: &'static [eh_artiq::StackPointerBacktrace],
|
||||
backtrace: &'static mut [(usize, usize)]) -> ! {
|
||||
pub fn terminate(
|
||||
exceptions: &'static [Option<eh_artiq::Exception<'static>>],
|
||||
stack_pointers: &'static [eh_artiq::StackPointerBacktrace],
|
||||
backtrace: &'static mut [(usize, usize)],
|
||||
) -> ! {
|
||||
{
|
||||
let core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() };
|
||||
let errors = unsafe { get_async_errors() };
|
||||
@@ -215,7 +208,7 @@ pub fn terminate(exceptions: &'static [Option<eh_artiq::Exception<'static>>],
|
||||
|
||||
/// Called by llvm_libunwind
|
||||
#[no_mangle]
|
||||
extern fn dl_unwind_find_exidx(pc: *const u32, len_ptr: *mut u32) -> *const u32 {
|
||||
extern "C" fn dl_unwind_find_exidx(pc: *const u32, len_ptr: *mut u32) -> *const u32 {
|
||||
let length;
|
||||
let start: *const EXIDX_Entry;
|
||||
unsafe {
|
||||
@@ -223,9 +216,14 @@ extern fn dl_unwind_find_exidx(pc: *const u32, len_ptr: *mut u32) -> *const u32
|
||||
length = (&__exidx_end as *const EXIDX_Entry).offset_from(&__exidx_start) as u32;
|
||||
start = &__exidx_start;
|
||||
} else if KERNEL_IMAGE != ptr::null() {
|
||||
let exidx = KERNEL_IMAGE.as_ref()
|
||||
let exidx = KERNEL_IMAGE
|
||||
.as_ref()
|
||||
.expect("dl_unwind_find_exidx kernel image")
|
||||
.library.get().as_ref().unwrap().exidx();
|
||||
.library
|
||||
.get()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.exidx();
|
||||
length = exidx.len() as u32;
|
||||
start = exidx.as_ptr();
|
||||
} else {
|
||||
@@ -237,7 +235,7 @@ extern fn dl_unwind_find_exidx(pc: *const u32, len_ptr: *mut u32) -> *const u32
|
||||
start as *const u32
|
||||
}
|
||||
|
||||
pub extern fn rtio_get_destination_status(destination: i32) -> bool {
|
||||
pub extern "C" fn rtio_get_destination_status(destination: i32) -> bool {
|
||||
#[cfg(has_drtio)]
|
||||
if destination > 0 && destination < 255 {
|
||||
let reply = unsafe {
|
||||
@@ -248,9 +246,9 @@ pub extern fn rtio_get_destination_status(destination: i32) -> bool {
|
||||
};
|
||||
return match reply {
|
||||
Message::UpDestinationsReply(x) => x,
|
||||
_ => panic!("received unexpected reply to UpDestinationsRequest: {:?}", reply)
|
||||
_ => panic!("received unexpected reply to UpDestinationsRequest: {:?}", reply),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
destination == 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,21 +1,18 @@
|
||||
use crate::{
|
||||
pl::csr,
|
||||
artiq_raise,
|
||||
rtio,
|
||||
};
|
||||
use alloc::{vec::Vec, string::String, boxed::Box};
|
||||
use cslice::CSlice;
|
||||
use super::{KERNEL_IMAGE, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, Message};
|
||||
use alloc::{boxed::Box, string::String, vec::Vec};
|
||||
use core::mem;
|
||||
|
||||
use cslice::CSlice;
|
||||
use libcortex_a9::cache::dcci_slice;
|
||||
|
||||
use super::{Message, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, KERNEL_IMAGE};
|
||||
use crate::{artiq_raise, pl::csr, rtio};
|
||||
|
||||
const ALIGNMENT: usize = 16 * 8;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct DmaTrace {
|
||||
duration: i64,
|
||||
address: i32,
|
||||
address: i32,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -33,10 +30,13 @@ pub unsafe fn init_dma_recorder() {
|
||||
mem::forget(mem::replace(&mut RECORDER, None));
|
||||
}
|
||||
|
||||
pub extern fn dma_record_start(name: CSlice<u8>) {
|
||||
pub extern "C" fn dma_record_start(name: CSlice<u8>) {
|
||||
let name = String::from_utf8(name.as_ref().to_vec()).unwrap();
|
||||
unsafe {
|
||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::DmaEraseRequest(name.clone()));
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::DmaEraseRequest(name.clone()));
|
||||
}
|
||||
unsafe {
|
||||
if RECORDER.is_some() {
|
||||
@@ -44,10 +44,10 @@ pub extern fn dma_record_start(name: CSlice<u8>) {
|
||||
}
|
||||
|
||||
let library = KERNEL_IMAGE.as_ref().unwrap();
|
||||
library.rebind(b"rtio_output",
|
||||
dma_record_output as *const ()).unwrap();
|
||||
library.rebind(b"rtio_output_wide",
|
||||
dma_record_output_wide as *const ()).unwrap();
|
||||
library.rebind(b"rtio_output", dma_record_output as *const ()).unwrap();
|
||||
library
|
||||
.rebind(b"rtio_output_wide", dma_record_output_wide as *const ())
|
||||
.unwrap();
|
||||
|
||||
RECORDER = Some(DmaRecorder {
|
||||
name,
|
||||
@@ -57,29 +57,29 @@ pub extern fn dma_record_start(name: CSlice<u8>) {
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn dma_record_stop(duration: i64) {
|
||||
pub extern "C" fn dma_record_stop(duration: i64) {
|
||||
unsafe {
|
||||
if RECORDER.is_none() {
|
||||
artiq_raise!("DMAError", "DMA is not recording")
|
||||
}
|
||||
|
||||
let library = KERNEL_IMAGE.as_ref().unwrap();
|
||||
library.rebind(b"rtio_output",
|
||||
rtio::output as *const ()).unwrap();
|
||||
library.rebind(b"rtio_output_wide",
|
||||
rtio::output_wide as *const ()).unwrap();
|
||||
library.rebind(b"rtio_output", rtio::output as *const ()).unwrap();
|
||||
library
|
||||
.rebind(b"rtio_output_wide", rtio::output_wide as *const ())
|
||||
.unwrap();
|
||||
|
||||
let mut recorder = RECORDER.take().unwrap();
|
||||
recorder.duration = duration;
|
||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(
|
||||
Message::DmaPutRequest(recorder)
|
||||
);
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::DmaPutRequest(recorder));
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
unsafe fn dma_record_output_prepare(timestamp: i64, target: i32,
|
||||
words: usize) {
|
||||
unsafe fn dma_record_output_prepare(timestamp: i64, target: i32, words: usize) {
|
||||
// See gateware/rtio/dma.py.
|
||||
const HEADER_LENGTH: usize = /*length*/1 + /*channel*/3 + /*timestamp*/8 + /*address*/1;
|
||||
let length = HEADER_LENGTH + /*data*/words * 4;
|
||||
@@ -87,36 +87,36 @@ unsafe fn dma_record_output_prepare(timestamp: i64, target: i32,
|
||||
let buffer = &mut RECORDER.as_mut().unwrap().buffer;
|
||||
buffer.reserve(length);
|
||||
buffer.extend_from_slice(&[
|
||||
(length >> 0) as u8,
|
||||
(target >> 8) as u8,
|
||||
(target >> 16) as u8,
|
||||
(target >> 24) as u8,
|
||||
(timestamp >> 0) as u8,
|
||||
(timestamp >> 8) as u8,
|
||||
(length >> 0) as u8,
|
||||
(target >> 8) as u8,
|
||||
(target >> 16) as u8,
|
||||
(target >> 24) as u8,
|
||||
(timestamp >> 0) as u8,
|
||||
(timestamp >> 8) as u8,
|
||||
(timestamp >> 16) as u8,
|
||||
(timestamp >> 24) as u8,
|
||||
(timestamp >> 32) as u8,
|
||||
(timestamp >> 40) as u8,
|
||||
(timestamp >> 48) as u8,
|
||||
(timestamp >> 56) as u8,
|
||||
(target >> 0) as u8,
|
||||
(target >> 0) as u8,
|
||||
]);
|
||||
}
|
||||
|
||||
pub extern fn dma_record_output(target: i32, word: i32) {
|
||||
pub extern "C" fn dma_record_output(target: i32, word: i32) {
|
||||
unsafe {
|
||||
let timestamp = rtio::now_mu();
|
||||
dma_record_output_prepare(timestamp, target, 1);
|
||||
RECORDER.as_mut().unwrap().buffer.extend_from_slice(&[
|
||||
(word >> 0) as u8,
|
||||
(word >> 8) as u8,
|
||||
(word >> 0) as u8,
|
||||
(word >> 8) as u8,
|
||||
(word >> 16) as u8,
|
||||
(word >> 24) as u8,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn dma_record_output_wide(target: i32, words: CSlice<i32>) {
|
||||
pub extern "C" fn dma_record_output_wide(target: i32, words: CSlice<i32>) {
|
||||
assert!(words.len() <= 16); // enforce the hardware limit
|
||||
|
||||
unsafe {
|
||||
@@ -125,8 +125,8 @@ pub extern fn dma_record_output_wide(target: i32, words: CSlice<i32>) {
|
||||
let buffer = &mut RECORDER.as_mut().unwrap().buffer;
|
||||
for word in words.as_ref().iter() {
|
||||
buffer.extend_from_slice(&[
|
||||
(word >> 0) as u8,
|
||||
(word >> 8) as u8,
|
||||
(word >> 0) as u8,
|
||||
(word >> 8) as u8,
|
||||
(word >> 16) as u8,
|
||||
(word >> 24) as u8,
|
||||
]);
|
||||
@@ -134,19 +134,22 @@ pub extern fn dma_record_output_wide(target: i32, words: CSlice<i32>) {
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn dma_erase(name: CSlice<u8>) {
|
||||
pub extern "C" fn dma_erase(name: CSlice<u8>) {
|
||||
let name = String::from_utf8(name.as_ref().to_vec()).unwrap();
|
||||
unsafe {
|
||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::DmaEraseRequest(name));
|
||||
KERNEL_CHANNEL_1TO0
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.send(Message::DmaEraseRequest(name));
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn dma_retrieve(name: CSlice<u8>) -> DmaTrace {
|
||||
pub extern "C" fn dma_retrieve(name: CSlice<u8>) -> DmaTrace {
|
||||
let name = String::from_utf8(name.as_ref().to_vec()).unwrap();
|
||||
unsafe {
|
||||
KERNEL_CHANNEL_1TO0.as_mut().unwrap().send(Message::DmaGetRequest(name));
|
||||
}
|
||||
match unsafe {KERNEL_CHANNEL_0TO1.as_mut().unwrap()}.recv() {
|
||||
match unsafe { KERNEL_CHANNEL_0TO1.as_mut().unwrap() }.recv() {
|
||||
Message::DmaGetReply(None) => (),
|
||||
Message::DmaGetReply(Some((mut v, duration))) => {
|
||||
v.reserve(ALIGNMENT - 1);
|
||||
@@ -162,18 +165,15 @@ pub extern fn dma_retrieve(name: CSlice<u8>) -> DmaTrace {
|
||||
dcci_slice(&v);
|
||||
let v = Box::new(v);
|
||||
let address = Box::into_raw(v) as *mut Vec<u8> as i32;
|
||||
return DmaTrace {
|
||||
address,
|
||||
duration,
|
||||
};
|
||||
},
|
||||
return DmaTrace { address, duration };
|
||||
}
|
||||
_ => panic!("Expected DmaGetReply after DmaGetRequest!"),
|
||||
}
|
||||
// we have to defer raising error as we have to drop the message first...
|
||||
artiq_raise!("DMAError", "DMA trace not found");
|
||||
}
|
||||
|
||||
pub extern fn dma_playback(timestamp: i64, ptr: i32) {
|
||||
pub extern "C" fn dma_playback(timestamp: i64, ptr: i32) {
|
||||
unsafe {
|
||||
let v = Box::from_raw(ptr as *mut Vec<u8>);
|
||||
let padding = ALIGNMENT - v.as_ptr() as usize % ALIGNMENT;
|
||||
@@ -197,16 +197,23 @@ pub extern fn dma_playback(timestamp: i64, ptr: i32) {
|
||||
let channel = csr::rtio_dma::error_channel_read();
|
||||
csr::rtio_dma::error_write(1);
|
||||
if error & 1 != 0 {
|
||||
artiq_raise!("RTIOUnderflow",
|
||||
artiq_raise!(
|
||||
"RTIOUnderflow",
|
||||
"RTIO underflow at {1} mu, channel {rtio_channel_info:0}",
|
||||
channel as i64, timestamp as i64, 0);
|
||||
channel as i64,
|
||||
timestamp as i64,
|
||||
0
|
||||
);
|
||||
}
|
||||
if error & 2 != 0 {
|
||||
artiq_raise!("RTIODestinationUnreachable",
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
"RTIO destination unreachable, output, at {1} mu, channel {rtio_channel_info:0}",
|
||||
channel as i64, timestamp as i64, 0);
|
||||
channel as i64,
|
||||
timestamp as i64,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
use alloc::{string::String, vec::Vec};
|
||||
use core::ptr;
|
||||
use alloc::{vec::Vec, string::String};
|
||||
|
||||
use libcortex_a9::{mutex::Mutex, sync_channel, semaphore::Semaphore};
|
||||
use libcortex_a9::{mutex::Mutex, semaphore::Semaphore, sync_channel};
|
||||
|
||||
use crate::eh_artiq;
|
||||
|
||||
mod control;
|
||||
pub use control::Control;
|
||||
pub mod core1;
|
||||
mod api;
|
||||
mod rpc;
|
||||
pub mod core1;
|
||||
mod dma;
|
||||
mod rpc;
|
||||
pub use dma::DmaRecorder;
|
||||
mod cache;
|
||||
|
||||
@@ -21,7 +22,7 @@ pub struct RPCException {
|
||||
pub file: u32,
|
||||
pub line: i32,
|
||||
pub column: i32,
|
||||
pub function: u32
|
||||
pub function: u32,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -31,11 +32,16 @@ pub enum Message {
|
||||
LoadFailed,
|
||||
StartRequest,
|
||||
KernelFinished(u8),
|
||||
KernelException(&'static [Option<eh_artiq::Exception<'static>>],
|
||||
&'static [eh_artiq::StackPointerBacktrace],
|
||||
&'static [(usize, usize)],
|
||||
u8),
|
||||
RpcSend { is_async: bool, data: Vec<u8> },
|
||||
KernelException(
|
||||
&'static [Option<eh_artiq::Exception<'static>>],
|
||||
&'static [eh_artiq::StackPointerBacktrace],
|
||||
&'static [(usize, usize)],
|
||||
u8,
|
||||
),
|
||||
RpcSend {
|
||||
is_async: bool,
|
||||
data: Vec<u8>,
|
||||
},
|
||||
RpcRecvRequest(*mut ()),
|
||||
RpcRecvReply(Result<usize, RPCException>),
|
||||
|
||||
@@ -64,4 +70,3 @@ static mut KERNEL_CHANNEL_1TO0: Option<sync_channel::Sender<'static, Message>> =
|
||||
pub static mut KERNEL_IMAGE: *const core1::KernelImage = ptr::null();
|
||||
|
||||
static INIT_LOCK: Mutex<()> = Mutex::new(());
|
||||
|
||||
|
||||
@@ -1,14 +1,11 @@
|
||||
//! Kernel-side RPC API
|
||||
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use cslice::CSlice;
|
||||
|
||||
use crate::eh_artiq;
|
||||
use crate::rpc::send_args;
|
||||
use super::{
|
||||
KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0,
|
||||
Message,
|
||||
};
|
||||
use super::{Message, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0};
|
||||
use crate::{eh_artiq, rpc::send_args};
|
||||
|
||||
fn rpc_send_common(is_async: bool, service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
||||
let core1_tx = unsafe { KERNEL_CHANNEL_1TO0.as_mut().unwrap() };
|
||||
@@ -17,15 +14,15 @@ fn rpc_send_common(is_async: bool, service: u32, tag: &CSlice<u8>, data: *const
|
||||
core1_tx.send(Message::RpcSend { is_async, data: buffer });
|
||||
}
|
||||
|
||||
pub extern fn rpc_send(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
||||
pub extern "C" fn rpc_send(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
||||
rpc_send_common(false, service, tag, data);
|
||||
}
|
||||
|
||||
pub extern fn rpc_send_async(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
||||
pub extern "C" fn rpc_send_async(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
|
||||
rpc_send_common(true, service, tag, data);
|
||||
}
|
||||
|
||||
pub extern fn rpc_recv(slot: *mut ()) -> usize {
|
||||
pub extern "C" fn rpc_recv(slot: *mut ()) -> usize {
|
||||
let reply = unsafe {
|
||||
let core1_rx = KERNEL_CHANNEL_0TO1.as_mut().unwrap();
|
||||
let core1_tx = KERNEL_CHANNEL_1TO0.as_mut().unwrap();
|
||||
@@ -36,15 +33,15 @@ pub extern fn rpc_recv(slot: *mut ()) -> usize {
|
||||
Message::RpcRecvReply(Ok(alloc_size)) => alloc_size,
|
||||
Message::RpcRecvReply(Err(exception)) => unsafe {
|
||||
eh_artiq::raise(&eh_artiq::Exception {
|
||||
id: exception.id,
|
||||
file: CSlice::new(exception.file as *const u8, usize::MAX),
|
||||
line: exception.line as u32,
|
||||
column: exception.column as u32,
|
||||
id: exception.id,
|
||||
file: CSlice::new(exception.file as *const u8, usize::MAX),
|
||||
line: exception.line as u32,
|
||||
column: exception.column as u32,
|
||||
function: CSlice::new(exception.function as *const u8, usize::MAX),
|
||||
message: CSlice::new(exception.message as *const u8, usize::MAX),
|
||||
param: exception.param
|
||||
message: CSlice::new(exception.message as *const u8, usize::MAX),
|
||||
param: exception.param,
|
||||
})
|
||||
},
|
||||
_ => panic!("received unexpected reply to RpcRecvRequest: {:?}", reply)
|
||||
_ => panic!("received unexpected reply to RpcRecvRequest: {:?}", reply),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
#![recursion_limit="1024"] // for futures_util::select!
|
||||
#![recursion_limit = "1024"] // for futures_util::select!
|
||||
#![feature(alloc_error_handler)]
|
||||
#![feature(panic_info_message)]
|
||||
#![feature(c_variadic)]
|
||||
@@ -12,25 +12,32 @@
|
||||
#[macro_use]
|
||||
extern crate alloc;
|
||||
|
||||
use log::{info, warn, error};
|
||||
|
||||
use libboard_zynq::{timer::GlobalTimer, mpcore, gic};
|
||||
use libasync::{task, block_async};
|
||||
use libsupport_zynq::ram;
|
||||
use nb;
|
||||
use void::Void;
|
||||
use libconfig::Config;
|
||||
use libcortex_a9::l2c::enable_l2_cache;
|
||||
use libboard_artiq::{logger, identifier_read, pl};
|
||||
use libasync::{block_async, task};
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
use libboard_artiq::io_expander;
|
||||
use libboard_artiq::{identifier_read, logger, pl};
|
||||
use libboard_zynq::{gic, mpcore, timer::GlobalTimer};
|
||||
use libconfig::Config;
|
||||
use libcortex_a9::l2c::enable_l2_cache;
|
||||
use libsupport_zynq::ram;
|
||||
use log::{error, info, warn};
|
||||
use nb;
|
||||
use void::Void;
|
||||
|
||||
const ASYNC_ERROR_COLLISION: u8 = 1 << 0;
|
||||
const ASYNC_ERROR_BUSY: u8 = 1 << 1;
|
||||
const ASYNC_ERROR_SEQUENCE_ERROR: u8 = 1 << 2;
|
||||
|
||||
mod proto_async;
|
||||
mod analyzer;
|
||||
mod comms;
|
||||
mod eh_artiq;
|
||||
mod i2c;
|
||||
mod irq;
|
||||
mod kernel;
|
||||
mod mgmt;
|
||||
mod moninj;
|
||||
mod panic;
|
||||
mod proto_async;
|
||||
mod rpc;
|
||||
#[cfg(ki_impl = "csr")]
|
||||
#[path = "rtio_csr.rs"]
|
||||
@@ -38,16 +45,8 @@ mod rtio;
|
||||
#[cfg(ki_impl = "acp")]
|
||||
#[path = "rtio_acp.rs"]
|
||||
mod rtio;
|
||||
mod rtio_mgt;
|
||||
mod rtio_clocking;
|
||||
mod kernel;
|
||||
mod moninj;
|
||||
mod eh_artiq;
|
||||
mod panic;
|
||||
mod mgmt;
|
||||
mod analyzer;
|
||||
mod irq;
|
||||
mod i2c;
|
||||
mod rtio_mgt;
|
||||
|
||||
static mut SEEN_ASYNC_ERRORS: u8 = 0;
|
||||
|
||||
@@ -74,15 +73,27 @@ async fn report_async_rtio_errors() {
|
||||
let errors = pl::csr::rtio_core::async_error_read();
|
||||
if errors & ASYNC_ERROR_COLLISION != 0 {
|
||||
let channel = pl::csr::rtio_core::collision_channel_read();
|
||||
error!("RTIO collision involving channel 0x{:04x}:{}", channel, rtio_mgt::resolve_channel_name(channel as u32));
|
||||
error!(
|
||||
"RTIO collision involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
rtio_mgt::resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
if errors & ASYNC_ERROR_BUSY != 0 {
|
||||
let channel = pl::csr::rtio_core::busy_channel_read();
|
||||
error!("RTIO busy error involving channel 0x{:04x}:{}", channel, rtio_mgt::resolve_channel_name(channel as u32));
|
||||
error!(
|
||||
"RTIO busy error involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
rtio_mgt::resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
if errors & ASYNC_ERROR_SEQUENCE_ERROR != 0 {
|
||||
let channel = pl::csr::rtio_core::sequence_error_channel_read();
|
||||
error!("RTIO sequence error involving channel 0x{:04x}:{}", channel, rtio_mgt::resolve_channel_name(channel as u32));
|
||||
error!(
|
||||
"RTIO sequence error involving channel 0x{:04x}:{}",
|
||||
channel,
|
||||
rtio_mgt::resolve_channel_name(channel as u32)
|
||||
);
|
||||
}
|
||||
SEEN_ASYNC_ERRORS = errors;
|
||||
pl::csr::rtio_core::async_error_write(errors);
|
||||
@@ -90,18 +101,14 @@ async fn report_async_rtio_errors() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static mut LOG_BUFFER: [u8; 1<<17] = [0; 1<<17];
|
||||
static mut LOG_BUFFER: [u8; 1 << 17] = [0; 1 << 17];
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main_core0() {
|
||||
enable_l2_cache(0x8);
|
||||
let mut timer = GlobalTimer::start();
|
||||
|
||||
let buffer_logger = unsafe {
|
||||
logger::BufferLogger::new(&mut LOG_BUFFER[..])
|
||||
};
|
||||
let buffer_logger = unsafe { logger::BufferLogger::new(&mut LOG_BUFFER[..]) };
|
||||
buffer_logger.set_uart_log_level(log::LevelFilter::Info);
|
||||
buffer_logger.register();
|
||||
log::set_max_level(log::LevelFilter::Info);
|
||||
@@ -137,7 +144,7 @@ pub fn main_core0() {
|
||||
Config::new_dummy()
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
rtio_clocking::init(&mut timer, &cfg);
|
||||
|
||||
task::spawn(report_async_rtio_errors());
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
use alloc::{rc::Rc, string::String, vec::Vec};
|
||||
use core::cell::RefCell;
|
||||
|
||||
use futures::{future::poll_fn, task::Poll};
|
||||
use libasync::{smoltcp::TcpStream, task};
|
||||
use libboard_zynq::{smoltcp, slcr};
|
||||
use libconfig::Config;
|
||||
use core::cell::RefCell;
|
||||
use alloc::{rc::Rc, vec::Vec, string::String};
|
||||
use log::{self, info, debug, warn, error, LevelFilter};
|
||||
|
||||
use libboard_artiq::logger::{BufferLogger, LogBufferRef};
|
||||
use crate::proto_async::*;
|
||||
use libboard_zynq::{slcr, smoltcp};
|
||||
use libconfig::Config;
|
||||
use log::{self, debug, error, info, warn, LevelFilter};
|
||||
use num_derive::FromPrimitive;
|
||||
use num_traits::FromPrimitive;
|
||||
|
||||
use crate::proto_async::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
NetworkError(smoltcp::Error),
|
||||
@@ -24,10 +25,10 @@ type Result<T> = core::result::Result<T, Error>;
|
||||
impl core::fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
|
||||
match self {
|
||||
&Error::NetworkError(error) => write!(f, "network error: {}", error),
|
||||
&Error::NetworkError(error) => write!(f, "network error: {}", error),
|
||||
&Error::UnknownLogLevel(lvl) => write!(f, "unknown log level {}", lvl),
|
||||
&Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
||||
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
||||
&Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
||||
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,9 +75,7 @@ async fn read_log_level_filter(stream: &mut TcpStream) -> Result<log::LevelFilte
|
||||
}
|
||||
|
||||
async fn get_logger_buffer_pred<F>(f: F) -> LogBufferRef<'static>
|
||||
where
|
||||
F: Fn(&LogBufferRef) -> bool,
|
||||
{
|
||||
where F: Fn(&LogBufferRef) -> bool {
|
||||
poll_fn(|ctx| {
|
||||
let logger = unsafe { BufferLogger::get_logger().as_mut().unwrap() };
|
||||
match logger.buffer() {
|
||||
@@ -112,10 +111,7 @@ async fn read_key(stream: &mut TcpStream) -> Result<String> {
|
||||
Ok(String::from_utf8(buffer).unwrap())
|
||||
}
|
||||
|
||||
async fn handle_connection(
|
||||
stream: &mut TcpStream,
|
||||
pull_id: Rc<RefCell<u32>>,
|
||||
cfg: Rc<Config>) -> Result<()> {
|
||||
async fn handle_connection(stream: &mut TcpStream, pull_id: Rc<RefCell<u32>>, cfg: Rc<Config>) -> Result<()> {
|
||||
if !expect(&stream, b"ARTIQ management\n").await? {
|
||||
return Err(Error::UnexpectedPattern);
|
||||
}
|
||||
@@ -163,7 +159,7 @@ async fn handle_connection(
|
||||
logger.set_buffer_log_level(LevelFilter::Trace);
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
Request::SetLogFilter => {
|
||||
let lvl = read_log_level_filter(stream).await?;
|
||||
info!("Changing log level to {}", lvl);
|
||||
@@ -174,10 +170,7 @@ async fn handle_connection(
|
||||
let lvl = read_log_level_filter(stream).await?;
|
||||
info!("Changing UART log level to {}", lvl);
|
||||
unsafe {
|
||||
BufferLogger::get_logger()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.set_uart_log_level(lvl);
|
||||
BufferLogger::get_logger().as_ref().unwrap().set_uart_log_level(lvl);
|
||||
}
|
||||
write_i8(stream, Reply::Success as i8).await?;
|
||||
}
|
||||
@@ -193,16 +186,12 @@ async fn handle_connection(
|
||||
warn!("read error: no such key");
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
}
|
||||
},
|
||||
}
|
||||
Request::ConfigWrite => {
|
||||
let key = read_key(stream).await?;
|
||||
debug!("write key: {}", key);
|
||||
let len = read_i32(stream).await?;
|
||||
let len = if len <= 0 {
|
||||
0
|
||||
} else {
|
||||
len as usize
|
||||
};
|
||||
let len = if len <= 0 { 0 } else { len as usize };
|
||||
let mut buffer = Vec::with_capacity(len);
|
||||
unsafe {
|
||||
buffer.set_len(len);
|
||||
@@ -217,7 +206,7 @@ async fn handle_connection(
|
||||
error!("failed to write: {:?}", value);
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
}
|
||||
},
|
||||
}
|
||||
Request::ConfigRemove => {
|
||||
let key = read_key(stream).await?;
|
||||
debug!("erase key: {}", key);
|
||||
@@ -229,7 +218,7 @@ async fn handle_connection(
|
||||
warn!("erase failed");
|
||||
write_i8(stream, Reply::Error as i8).await?;
|
||||
}
|
||||
},
|
||||
}
|
||||
Request::Reboot => {
|
||||
info!("rebooting");
|
||||
write_i8(stream, Reply::RebootImminent as i8).await?;
|
||||
|
||||
@@ -1,26 +1,23 @@
|
||||
use core::{fmt, cell::RefCell};
|
||||
use alloc::{collections::BTreeMap, rc::Rc};
|
||||
use log::{debug, info, warn};
|
||||
use void::Void;
|
||||
use core::{cell::RefCell, fmt};
|
||||
|
||||
use futures::{pin_mut, select_biased, FutureExt};
|
||||
use libasync::{block_async, nb, smoltcp::TcpStream, task};
|
||||
use libboard_artiq::drtio_routing;
|
||||
|
||||
use libboard_zynq::{smoltcp, timer::GlobalTimer, time::Milliseconds};
|
||||
use libasync::{task, smoltcp::TcpStream, block_async, nb};
|
||||
use libboard_zynq::{smoltcp, time::Milliseconds, timer::GlobalTimer};
|
||||
use libcortex_a9::mutex::Mutex;
|
||||
|
||||
use log::{debug, info, warn};
|
||||
use num_derive::{FromPrimitive, ToPrimitive};
|
||||
use num_traits::{FromPrimitive, ToPrimitive};
|
||||
use futures::{pin_mut, select_biased, FutureExt};
|
||||
use void::Void;
|
||||
|
||||
use crate::proto_async::*;
|
||||
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum Error {
|
||||
NetworkError(smoltcp::Error),
|
||||
UnexpectedPattern,
|
||||
UnrecognizedPacket
|
||||
UnrecognizedPacket,
|
||||
}
|
||||
|
||||
pub type Result<T> = core::result::Result<T, Error>;
|
||||
@@ -29,8 +26,8 @@ impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
&Error::NetworkError(error) => write!(f, "network error: {}", error),
|
||||
&Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
||||
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
||||
&Error::UnexpectedPattern => write!(f, "unexpected pattern"),
|
||||
&Error::UnrecognizedPacket => write!(f, "unrecognized packet"),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,60 +43,102 @@ enum HostMessage {
|
||||
MonitorProbe = 0,
|
||||
MonitorInjection = 3,
|
||||
Inject = 1,
|
||||
GetInjectionStatus = 2
|
||||
GetInjectionStatus = 2,
|
||||
}
|
||||
|
||||
#[derive(Debug, FromPrimitive, ToPrimitive)]
|
||||
enum DeviceMessage {
|
||||
MonitorStatus = 0,
|
||||
InjectionStatus = 1
|
||||
InjectionStatus = 1,
|
||||
}
|
||||
|
||||
#[cfg(has_drtio)]
|
||||
mod remote_moninj {
|
||||
use super::*;
|
||||
use libboard_artiq::drtioaux_async;
|
||||
use crate::rtio_mgt::drtio;
|
||||
use log::error;
|
||||
|
||||
pub async fn read_probe(aux_mutex: &Rc<Mutex<bool>>, timer: GlobalTimer, linkno: u8, destination: u8, channel: i32, probe: i8) -> i64 {
|
||||
let reply = drtio::aux_transact(aux_mutex, linkno, &drtioaux_async::Packet::MonitorRequest {
|
||||
destination: destination,
|
||||
channel: channel as _,
|
||||
probe: probe as _},
|
||||
timer).await;
|
||||
use super::*;
|
||||
use crate::rtio_mgt::drtio;
|
||||
|
||||
pub async fn read_probe(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
channel: i32,
|
||||
probe: i8,
|
||||
) -> i64 {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
&drtioaux_async::Packet::MonitorRequest {
|
||||
destination: destination,
|
||||
channel: channel as _,
|
||||
probe: probe as _,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
match reply {
|
||||
Ok(drtioaux_async::Packet::MonitorReply { value }) => return value as i64,
|
||||
Ok(packet) => error!("received unexpected aux packet: {:?}", packet),
|
||||
Err("link went down") => { debug!("link is down"); },
|
||||
Err(e) => error!("aux packet error ({})", e)
|
||||
Err("link went down") => {
|
||||
debug!("link is down");
|
||||
}
|
||||
Err(e) => error!("aux packet error ({})", e),
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
pub async fn inject(aux_mutex: &Rc<Mutex<bool>>, _timer: GlobalTimer, linkno: u8, destination: u8, channel: i32, overrd: i8, value: i8) {
|
||||
pub async fn inject(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
_timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
channel: i32,
|
||||
overrd: i8,
|
||||
value: i8,
|
||||
) {
|
||||
let _lock = aux_mutex.lock();
|
||||
drtioaux_async::send(linkno, &drtioaux_async::Packet::InjectionRequest {
|
||||
destination: destination,
|
||||
channel: channel as _,
|
||||
overrd: overrd as _,
|
||||
value: value as _
|
||||
}).await.unwrap();
|
||||
drtioaux_async::send(
|
||||
linkno,
|
||||
&drtioaux_async::Packet::InjectionRequest {
|
||||
destination: destination,
|
||||
channel: channel as _,
|
||||
overrd: overrd as _,
|
||||
value: value as _,
|
||||
},
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub async fn read_injection_status(aux_mutex: &Rc<Mutex<bool>>, timer: GlobalTimer, linkno: u8, destination: u8, channel: i32, overrd: i8) -> i8 {
|
||||
let reply = drtio::aux_transact(aux_mutex,
|
||||
linkno,
|
||||
pub async fn read_injection_status(
|
||||
aux_mutex: &Rc<Mutex<bool>>,
|
||||
timer: GlobalTimer,
|
||||
linkno: u8,
|
||||
destination: u8,
|
||||
channel: i32,
|
||||
overrd: i8,
|
||||
) -> i8 {
|
||||
let reply = drtio::aux_transact(
|
||||
aux_mutex,
|
||||
linkno,
|
||||
&drtioaux_async::Packet::InjectionStatusRequest {
|
||||
destination: destination,
|
||||
channel: channel as _,
|
||||
overrd: overrd as _},
|
||||
timer).await;
|
||||
overrd: overrd as _,
|
||||
},
|
||||
timer,
|
||||
)
|
||||
.await;
|
||||
match reply {
|
||||
Ok(drtioaux_async::Packet::InjectionStatusReply { value }) => return value as i8,
|
||||
Ok(packet) => error!("received unexpected aux packet: {:?}", packet),
|
||||
Err("link went down") => { debug!("link is down"); },
|
||||
Err(e) => error!("aux packet error ({})", e)
|
||||
Err("link went down") => {
|
||||
debug!("link is down");
|
||||
}
|
||||
Err(e) => error!("aux packet error ({})", e),
|
||||
}
|
||||
0
|
||||
}
|
||||
@@ -157,8 +196,12 @@ macro_rules! dispatch {
|
||||
}}
|
||||
}
|
||||
|
||||
async fn handle_connection(stream: &TcpStream, timer: GlobalTimer,
|
||||
_aux_mutex: &Rc<Mutex<bool>>, _routing_table: &drtio_routing::RoutingTable) -> Result<()> {
|
||||
async fn handle_connection(
|
||||
stream: &TcpStream,
|
||||
timer: GlobalTimer,
|
||||
_aux_mutex: &Rc<Mutex<bool>>,
|
||||
_routing_table: &drtio_routing::RoutingTable,
|
||||
) -> Result<()> {
|
||||
if !expect(&stream, b"ARTIQ moninj\n").await? {
|
||||
return Err(Error::UnexpectedPattern);
|
||||
}
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
use libboard_zynq::{print, println};
|
||||
use libregister::RegisterR;
|
||||
use libcortex_a9::regs::MPIDR;
|
||||
use unwind::backtrace;
|
||||
|
||||
#[cfg(feature = "target_kasli_soc")]
|
||||
use libboard_zynq::error_led::ErrorLED;
|
||||
use crate::comms::soft_panic_main;
|
||||
use log::error;
|
||||
use libboard_zynq::timer::GlobalTimer;
|
||||
use libboard_zynq::{print, println, timer::GlobalTimer};
|
||||
use libconfig::Config;
|
||||
use libcortex_a9::regs::MPIDR;
|
||||
use libregister::RegisterR;
|
||||
use log::error;
|
||||
use unwind::backtrace;
|
||||
|
||||
use crate::comms::soft_panic_main;
|
||||
|
||||
static mut PANICKED: [bool; 2] = [false; 2];
|
||||
static mut SOFT_PANICKED: bool = false;
|
||||
@@ -68,9 +67,7 @@ fn soft_panic(info: &core::panic::PanicInfo) -> ! {
|
||||
let timer = GlobalTimer::start();
|
||||
let cfg = match Config::new() {
|
||||
Ok(cfg) => cfg,
|
||||
Err(_) => {
|
||||
Config::new_dummy()
|
||||
}
|
||||
Err(_) => Config::new_dummy(),
|
||||
};
|
||||
soft_panic_main(timer, cfg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use core::cmp::min;
|
||||
use core::cell::RefCell;
|
||||
use core::{cell::RefCell, cmp::min};
|
||||
|
||||
use libboard_zynq::smoltcp;
|
||||
use libasync::smoltcp::TcpStream;
|
||||
use libboard_zynq::smoltcp;
|
||||
|
||||
type Result<T> = core::result::Result<T, smoltcp::Error>;
|
||||
|
||||
@@ -14,25 +13,27 @@ enum RecvState<T> {
|
||||
pub async fn expect(stream: &TcpStream, pattern: &[u8]) -> Result<bool> {
|
||||
let mut state = RecvState::NeedsMore(0, true);
|
||||
loop {
|
||||
state = stream.recv(|buf| {
|
||||
let mut consumed = 0;
|
||||
if let RecvState::NeedsMore(mut cur_index, _) = state {
|
||||
for b in buf.iter() {
|
||||
consumed += 1;
|
||||
if *b == pattern[cur_index] {
|
||||
if cur_index + 1 == pattern.len() {
|
||||
return (consumed, RecvState::Completed(true));
|
||||
state = stream
|
||||
.recv(|buf| {
|
||||
let mut consumed = 0;
|
||||
if let RecvState::NeedsMore(mut cur_index, _) = state {
|
||||
for b in buf.iter() {
|
||||
consumed += 1;
|
||||
if *b == pattern[cur_index] {
|
||||
if cur_index + 1 == pattern.len() {
|
||||
return (consumed, RecvState::Completed(true));
|
||||
}
|
||||
} else {
|
||||
return (consumed, RecvState::Completed(false));
|
||||
}
|
||||
} else {
|
||||
return (consumed, RecvState::Completed(false));
|
||||
cur_index += 1;
|
||||
}
|
||||
cur_index += 1;
|
||||
(consumed, RecvState::NeedsMore(cur_index, true))
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
(consumed, RecvState::NeedsMore(cur_index, true))
|
||||
} else {
|
||||
unreachable!();
|
||||
}
|
||||
}).await?;
|
||||
})
|
||||
.await?;
|
||||
if let RecvState::Completed(result) = state {
|
||||
return Ok(result);
|
||||
}
|
||||
@@ -40,15 +41,11 @@ pub async fn expect(stream: &TcpStream, pattern: &[u8]) -> Result<bool> {
|
||||
}
|
||||
|
||||
pub async fn read_bool(stream: &TcpStream) -> Result<bool> {
|
||||
Ok(stream.recv(|buf| {
|
||||
(1, buf[0] != 0)
|
||||
}).await?)
|
||||
Ok(stream.recv(|buf| (1, buf[0] != 0)).await?)
|
||||
}
|
||||
|
||||
pub async fn read_i8(stream: &TcpStream) -> Result<i8> {
|
||||
Ok(stream.recv(|buf| {
|
||||
(1, buf[0] as i8)
|
||||
}).await?)
|
||||
Ok(stream.recv(|buf| (1, buf[0] as i8)).await?)
|
||||
}
|
||||
|
||||
pub async fn read_i32(stream: &TcpStream) -> Result<i32> {
|
||||
@@ -68,12 +65,14 @@ pub async fn read_chunk(stream: &TcpStream, destination: &mut [u8]) -> Result<()
|
||||
let destination = RefCell::new(destination);
|
||||
let mut done = 0;
|
||||
while done < total {
|
||||
let count = stream.recv(|buf| {
|
||||
let mut destination = destination.borrow_mut();
|
||||
let count = min(total - done, buf.len());
|
||||
destination[done..done + count].copy_from_slice(&buf[..count]);
|
||||
(count, count)
|
||||
}).await?;
|
||||
let count = stream
|
||||
.recv(|buf| {
|
||||
let mut destination = destination.borrow_mut();
|
||||
let count = min(total - done, buf.len());
|
||||
destination[done..done + count].copy_from_slice(&buf[..count]);
|
||||
(count, count)
|
||||
})
|
||||
.await?;
|
||||
done += count;
|
||||
}
|
||||
Ok(())
|
||||
|
||||
@@ -1,18 +1,17 @@
|
||||
use core::str;
|
||||
use core::future::Future;
|
||||
use cslice::{CSlice, CMutSlice};
|
||||
use log::trace;
|
||||
use byteorder::{NativeEndian, ByteOrder};
|
||||
|
||||
use core_io::{Write, Error};
|
||||
use libboard_zynq::smoltcp;
|
||||
use libasync::smoltcp::TcpStream;
|
||||
use alloc::boxed::Box;
|
||||
use async_recursion::async_recursion;
|
||||
use core::{future::Future, str};
|
||||
|
||||
use async_recursion::async_recursion;
|
||||
use byteorder::{ByteOrder, NativeEndian};
|
||||
use core_io::{Error, Write};
|
||||
use cslice::{CMutSlice, CSlice};
|
||||
use io::proto::ProtoWrite;
|
||||
use libasync::smoltcp::TcpStream;
|
||||
use libboard_zynq::smoltcp;
|
||||
use log::trace;
|
||||
|
||||
use self::tag::{split_tag, Tag, TagIterator};
|
||||
use crate::proto_async;
|
||||
use self::tag::{Tag, TagIterator, split_tag};
|
||||
|
||||
#[inline]
|
||||
fn round_up(val: usize, power_of_two: usize) -> usize {
|
||||
@@ -52,17 +51,17 @@ async unsafe fn recv_elements<F>(
|
||||
elt_tag: Tag<'async_recursion>,
|
||||
length: usize,
|
||||
storage: *mut (),
|
||||
alloc: &(impl Fn(usize) -> F + 'async_recursion)
|
||||
alloc: &(impl Fn(usize) -> F + 'async_recursion),
|
||||
) -> Result<(), smoltcp::Error>
|
||||
where
|
||||
F: Future<Output=*mut ()>,
|
||||
F: Future<Output = *mut ()>,
|
||||
{
|
||||
// List of simple types are special-cased in the protocol for performance.
|
||||
match elt_tag {
|
||||
Tag::Bool => {
|
||||
let dest = core::slice::from_raw_parts_mut(storage as *mut u8, length);
|
||||
proto_async::read_chunk(stream, dest).await?;
|
||||
},
|
||||
}
|
||||
Tag::Int32 => {
|
||||
let ptr = storage as *mut u32;
|
||||
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 4);
|
||||
@@ -70,7 +69,7 @@ where
|
||||
drop(dest);
|
||||
let dest = core::slice::from_raw_parts_mut(ptr, length);
|
||||
NativeEndian::from_slice_u32(dest);
|
||||
},
|
||||
}
|
||||
Tag::Int64 | Tag::Float64 => {
|
||||
let ptr = storage as *mut u64;
|
||||
let dest = core::slice::from_raw_parts_mut(ptr as *mut u8, length * 8);
|
||||
@@ -78,7 +77,7 @@ where
|
||||
drop(dest);
|
||||
let dest = core::slice::from_raw_parts_mut(ptr, length);
|
||||
NativeEndian::from_slice_u64(dest);
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
let mut data = storage;
|
||||
for _ in 0..length {
|
||||
@@ -95,36 +94,37 @@ where
|
||||
/// invoked any number of times with the size of the required allocation as a parameter
|
||||
/// (which is assumed to be correctly aligned for all payload types).
|
||||
#[async_recursion(?Send)]
|
||||
async unsafe fn recv_value<F>(stream: &TcpStream, tag: Tag<'async_recursion>, data: &mut *mut (),
|
||||
alloc: &(impl Fn(usize) -> F + 'async_recursion))
|
||||
-> Result<(), smoltcp::Error>
|
||||
where F: Future<Output=*mut ()>
|
||||
async unsafe fn recv_value<F>(
|
||||
stream: &TcpStream,
|
||||
tag: Tag<'async_recursion>,
|
||||
data: &mut *mut (),
|
||||
alloc: &(impl Fn(usize) -> F + 'async_recursion),
|
||||
) -> Result<(), smoltcp::Error>
|
||||
where
|
||||
F: Future<Output = *mut ()>,
|
||||
{
|
||||
macro_rules! consume_value {
|
||||
($ty:ty, |$ptr:ident| $map:expr) => ({
|
||||
($ty:ty, | $ptr:ident | $map:expr) => {{
|
||||
let $ptr = align_ptr_mut::<$ty>(*data);
|
||||
*data = $ptr.offset(1) as *mut ();
|
||||
$map
|
||||
})
|
||||
}};
|
||||
}
|
||||
|
||||
match tag {
|
||||
Tag::None => Ok(()),
|
||||
Tag::Bool =>
|
||||
consume_value!(i8, |ptr| {
|
||||
*ptr = proto_async::read_i8(stream).await?;
|
||||
Ok(())
|
||||
}),
|
||||
Tag::Int32 =>
|
||||
consume_value!(i32, |ptr| {
|
||||
*ptr = proto_async::read_i32(stream).await?;
|
||||
Ok(())
|
||||
}),
|
||||
Tag::Int64 | Tag::Float64 =>
|
||||
consume_value!(i64, |ptr| {
|
||||
*ptr = proto_async::read_i64(stream).await?;
|
||||
Ok(())
|
||||
}),
|
||||
Tag::Bool => consume_value!(i8, |ptr| {
|
||||
*ptr = proto_async::read_i8(stream).await?;
|
||||
Ok(())
|
||||
}),
|
||||
Tag::Int32 => consume_value!(i32, |ptr| {
|
||||
*ptr = proto_async::read_i32(stream).await?;
|
||||
Ok(())
|
||||
}),
|
||||
Tag::Int64 | Tag::Float64 => consume_value!(i64, |ptr| {
|
||||
*ptr = proto_async::read_i64(stream).await?;
|
||||
Ok(())
|
||||
}),
|
||||
Tag::String | Tag::Bytes | Tag::ByteArray => {
|
||||
consume_value!(CMutSlice<u8>, |ptr| {
|
||||
let length = proto_async::read_i32(stream).await? as usize;
|
||||
@@ -148,7 +148,10 @@ async unsafe fn recv_value<F>(stream: &TcpStream, tag: Tag<'async_recursion>, da
|
||||
}
|
||||
Tag::List(it) => {
|
||||
#[repr(C)]
|
||||
struct List { elements: *mut (), length: usize }
|
||||
struct List {
|
||||
elements: *mut (),
|
||||
length: usize,
|
||||
}
|
||||
consume_value!(*mut List, |ptr_to_list| {
|
||||
let tag = it.clone().next().expect("truncated tag");
|
||||
let length = proto_async::read_i32(stream).await? as usize;
|
||||
@@ -180,7 +183,7 @@ async unsafe fn recv_value<F>(stream: &TcpStream, tag: Tag<'async_recursion>, da
|
||||
for _ in 0..num_dims {
|
||||
let len = proto_async::read_i32(stream).await? as usize;
|
||||
total_len *= len;
|
||||
consume_value!(usize, |ptr| *ptr = len )
|
||||
consume_value!(usize, |ptr| *ptr = len)
|
||||
}
|
||||
|
||||
// Allocate backing storage for elements; deserialize them.
|
||||
@@ -198,14 +201,18 @@ async unsafe fn recv_value<F>(stream: &TcpStream, tag: Tag<'async_recursion>, da
|
||||
Ok(())
|
||||
}
|
||||
Tag::Keyword(_) => unreachable!(),
|
||||
Tag::Object => unreachable!()
|
||||
Tag::Object => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn recv_return<F>(stream: &TcpStream, tag_bytes: &[u8], data: *mut (),
|
||||
alloc: &impl Fn(usize) -> F)
|
||||
-> Result<(), smoltcp::Error>
|
||||
where F: Future<Output=*mut ()>
|
||||
pub async fn recv_return<F>(
|
||||
stream: &TcpStream,
|
||||
tag_bytes: &[u8],
|
||||
data: *mut (),
|
||||
alloc: &impl Fn(usize) -> F,
|
||||
) -> Result<(), smoltcp::Error>
|
||||
where
|
||||
F: Future<Output = *mut ()>,
|
||||
{
|
||||
let mut it = TagIterator::new(tag_bytes);
|
||||
trace!("recv ...->{}", it);
|
||||
@@ -217,10 +224,8 @@ pub async fn recv_return<F>(stream: &TcpStream, tag_bytes: &[u8], data: *mut (),
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn send_elements<W>(writer: &mut W, elt_tag: Tag, length: usize, data: *const ())
|
||||
-> Result<(), Error>
|
||||
where W: Write + ?Sized
|
||||
{
|
||||
unsafe fn send_elements<W>(writer: &mut W, elt_tag: Tag, length: usize, data: *const ()) -> Result<(), Error>
|
||||
where W: Write + ?Sized {
|
||||
writer.write_u8(elt_tag.as_u8())?;
|
||||
match elt_tag {
|
||||
// we cannot use NativeEndian::from_slice_i32 as the data is not mutable,
|
||||
@@ -228,15 +233,15 @@ unsafe fn send_elements<W>(writer: &mut W, elt_tag: Tag, length: usize, data: *c
|
||||
Tag::Bool => {
|
||||
let slice = core::slice::from_raw_parts(data as *const u8, length);
|
||||
writer.write_all(slice)?;
|
||||
},
|
||||
}
|
||||
Tag::Int32 => {
|
||||
let slice = core::slice::from_raw_parts(data as *const u8, length * 4);
|
||||
writer.write_all(slice)?;
|
||||
},
|
||||
}
|
||||
Tag::Int64 | Tag::Float64 => {
|
||||
let slice = core::slice::from_raw_parts(data as *const u8, length * 8);
|
||||
writer.write_all(slice)?;
|
||||
},
|
||||
}
|
||||
_ => {
|
||||
let mut data = data;
|
||||
for _ in 0..length {
|
||||
@@ -247,36 +252,26 @@ unsafe fn send_elements<W>(writer: &mut W, elt_tag: Tag, length: usize, data: *c
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
|
||||
-> Result<(), Error>
|
||||
where W: Write + ?Sized
|
||||
{
|
||||
unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ()) -> Result<(), Error>
|
||||
where W: Write + ?Sized {
|
||||
macro_rules! consume_value {
|
||||
($ty:ty, |$ptr:ident| $map:expr) => ({
|
||||
($ty:ty, | $ptr:ident | $map:expr) => {{
|
||||
let $ptr = align_ptr::<$ty>(*data);
|
||||
*data = $ptr.offset(1) as *const ();
|
||||
$map
|
||||
})
|
||||
}};
|
||||
}
|
||||
|
||||
writer.write_u8(tag.as_u8())?;
|
||||
match tag {
|
||||
Tag::None => Ok(()),
|
||||
Tag::Bool =>
|
||||
consume_value!(u8, |ptr|
|
||||
writer.write_u8(*ptr)),
|
||||
Tag::Int32 =>
|
||||
consume_value!(u32, |ptr|
|
||||
writer.write_u32(*ptr)),
|
||||
Tag::Int64 | Tag::Float64 =>
|
||||
consume_value!(u64, |ptr|
|
||||
writer.write_u64(*ptr)),
|
||||
Tag::String =>
|
||||
consume_value!(CSlice<u8>, |ptr|
|
||||
writer.write_string(str::from_utf8((*ptr).as_ref()).unwrap())),
|
||||
Tag::Bytes | Tag::ByteArray =>
|
||||
consume_value!(CSlice<u8>, |ptr|
|
||||
writer.write_bytes((*ptr).as_ref())),
|
||||
Tag::Bool => consume_value!(u8, |ptr| writer.write_u8(*ptr)),
|
||||
Tag::Int32 => consume_value!(u32, |ptr| writer.write_u32(*ptr)),
|
||||
Tag::Int64 | Tag::Float64 => consume_value!(u64, |ptr| writer.write_u64(*ptr)),
|
||||
Tag::String => consume_value!(CSlice<u8>, |ptr| {
|
||||
writer.write_string(str::from_utf8((*ptr).as_ref()).unwrap())
|
||||
}),
|
||||
Tag::Bytes | Tag::ByteArray => consume_value!(CSlice<u8>, |ptr| writer.write_bytes((*ptr).as_ref())),
|
||||
Tag::Tuple(it, arity) => {
|
||||
let mut it = it.clone();
|
||||
writer.write_u8(arity)?;
|
||||
@@ -291,7 +286,10 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
|
||||
}
|
||||
Tag::List(it) => {
|
||||
#[repr(C)]
|
||||
struct List { elements: *const (), length: u32 }
|
||||
struct List {
|
||||
elements: *const (),
|
||||
length: u32,
|
||||
}
|
||||
consume_value!(&List, |ptr| {
|
||||
let length = (**ptr).length as usize;
|
||||
writer.write_u32((*ptr).length)?;
|
||||
@@ -301,7 +299,7 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
|
||||
}
|
||||
Tag::Array(it, num_dims) => {
|
||||
writer.write_u8(num_dims)?;
|
||||
consume_value!(*const(), |buffer| {
|
||||
consume_value!(*const (), |buffer| {
|
||||
let elt_tag = it.clone().next().expect("truncated tag");
|
||||
|
||||
let mut total_len = 1;
|
||||
@@ -324,7 +322,9 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
|
||||
}
|
||||
Tag::Keyword(it) => {
|
||||
#[repr(C)]
|
||||
struct Keyword<'a> { name: CSlice<'a, u8> }
|
||||
struct Keyword<'a> {
|
||||
name: CSlice<'a, u8>,
|
||||
}
|
||||
consume_value!(Keyword, |ptr| {
|
||||
writer.write_string(str::from_utf8((*ptr).name.as_ref()).unwrap())?;
|
||||
let tag = it.clone().next().expect("truncated tag");
|
||||
@@ -336,17 +336,16 @@ unsafe fn send_value<W>(writer: &mut W, tag: Tag, data: &mut *const ())
|
||||
}
|
||||
Tag::Object => {
|
||||
#[repr(C)]
|
||||
struct Object { id: u32 }
|
||||
consume_value!(*const Object, |ptr|
|
||||
writer.write_u32((**ptr).id))
|
||||
struct Object {
|
||||
id: u32,
|
||||
}
|
||||
consume_value!(*const Object, |ptr| writer.write_u32((**ptr).id))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_args<W>(writer: &mut W, service: u32, tag_bytes: &[u8], data: *const *const ())
|
||||
-> Result<(), Error>
|
||||
where W: Write + ?Sized
|
||||
{
|
||||
pub fn send_args<W>(writer: &mut W, service: u32, tag_bytes: &[u8], data: *const *const ()) -> Result<(), Error>
|
||||
where W: Write + ?Sized {
|
||||
let (arg_tags_bytes, return_tag_bytes) = split_tag(tag_bytes);
|
||||
|
||||
let mut args_it = TagIterator::new(arg_tags_bytes);
|
||||
@@ -359,7 +358,7 @@ pub fn send_args<W>(writer: &mut W, service: u32, tag_bytes: &[u8], data: *const
|
||||
let mut data = unsafe { *data.offset(index) };
|
||||
unsafe { send_value(writer, arg_tag, &mut data)? };
|
||||
} else {
|
||||
break
|
||||
break;
|
||||
}
|
||||
}
|
||||
writer.write_u8(0)?;
|
||||
@@ -372,10 +371,10 @@ mod tag {
|
||||
use core::fmt;
|
||||
|
||||
pub fn split_tag(tag_bytes: &[u8]) -> (&[u8], &[u8]) {
|
||||
let tag_separator =
|
||||
tag_bytes.iter()
|
||||
.position(|&b| b == b':')
|
||||
.expect("tag without a return separator");
|
||||
let tag_separator = tag_bytes
|
||||
.iter()
|
||||
.position(|&b| b == b':')
|
||||
.expect("tag without a return separator");
|
||||
let (arg_tags_bytes, rest) = tag_bytes.split_at(tag_separator);
|
||||
let return_tag_bytes = &rest[1..];
|
||||
(arg_tags_bytes, return_tag_bytes)
|
||||
@@ -396,7 +395,7 @@ mod tag {
|
||||
Array(TagIterator<'a>, u8),
|
||||
Range(TagIterator<'a>),
|
||||
Keyword(TagIterator<'a>),
|
||||
Object
|
||||
Object,
|
||||
}
|
||||
|
||||
impl<'a> Tag<'a> {
|
||||
@@ -431,14 +430,15 @@ mod tag {
|
||||
Tag::Tuple(it, arity) => {
|
||||
let it = it.clone();
|
||||
it.take(arity.into()).map(|t| t.alignment()).max().unwrap()
|
||||
},
|
||||
}
|
||||
Tag::Range(it) => {
|
||||
let it = it.clone();
|
||||
it.take(3).map(|t| t.alignment()).max().unwrap()
|
||||
}
|
||||
// the ptr/length(s) pair is basically CSlice
|
||||
Tag::Bytes | Tag::String | Tag::ByteArray | Tag::List(_) | Tag::Array(_, _) =>
|
||||
core::mem::align_of::<CSlice<()>>(),
|
||||
Tag::Bytes | Tag::String | Tag::ByteArray | Tag::List(_) | Tag::Array(_, _) => {
|
||||
core::mem::align_of::<CSlice<()>>()
|
||||
}
|
||||
Tag::Keyword(_) => unreachable!("Tag::Keyword should not appear in composite types"),
|
||||
Tag::Object => core::mem::align_of::<u32>(),
|
||||
}
|
||||
@@ -484,7 +484,7 @@ mod tag {
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct TagIterator<'a> {
|
||||
data: &'a [u8]
|
||||
data: &'a [u8],
|
||||
}
|
||||
|
||||
impl<'a> TagIterator<'a> {
|
||||
@@ -492,13 +492,14 @@ mod tag {
|
||||
TagIterator { data }
|
||||
}
|
||||
|
||||
|
||||
fn sub(&mut self, count: u8) -> TagIterator<'a> {
|
||||
let data = self.data;
|
||||
for _ in 0..count {
|
||||
self.next().expect("truncated tag");
|
||||
}
|
||||
TagIterator { data: &data[..(data.len() - self.data.len())] }
|
||||
TagIterator {
|
||||
data: &data[..(data.len() - self.data.len())],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -507,7 +508,7 @@ mod tag {
|
||||
|
||||
fn next(&mut self) -> Option<Tag<'a>> {
|
||||
if self.data.len() == 0 {
|
||||
return None
|
||||
return None;
|
||||
}
|
||||
|
||||
let tag_byte = self.data[0];
|
||||
@@ -535,7 +536,7 @@ mod tag {
|
||||
b'r' => Tag::Range(self.sub(1)),
|
||||
b'k' => Tag::Keyword(self.sub(1)),
|
||||
b'O' => Tag::Object,
|
||||
_ => unreachable!()
|
||||
_ => unreachable!(),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -552,22 +553,14 @@ mod tag {
|
||||
}
|
||||
|
||||
match tag {
|
||||
Tag::None =>
|
||||
write!(f, "None")?,
|
||||
Tag::Bool =>
|
||||
write!(f, "Bool")?,
|
||||
Tag::Int32 =>
|
||||
write!(f, "Int32")?,
|
||||
Tag::Int64 =>
|
||||
write!(f, "Int64")?,
|
||||
Tag::Float64 =>
|
||||
write!(f, "Float64")?,
|
||||
Tag::String =>
|
||||
write!(f, "String")?,
|
||||
Tag::Bytes =>
|
||||
write!(f, "Bytes")?,
|
||||
Tag::ByteArray =>
|
||||
write!(f, "ByteArray")?,
|
||||
Tag::None => write!(f, "None")?,
|
||||
Tag::Bool => write!(f, "Bool")?,
|
||||
Tag::Int32 => write!(f, "Int32")?,
|
||||
Tag::Int64 => write!(f, "Int64")?,
|
||||
Tag::Float64 => write!(f, "Float64")?,
|
||||
Tag::String => write!(f, "String")?,
|
||||
Tag::Bytes => write!(f, "Bytes")?,
|
||||
Tag::ByteArray => write!(f, "ByteArray")?,
|
||||
Tag::Tuple(it, _) => {
|
||||
write!(f, "Tuple(")?;
|
||||
it.fmt(f)?;
|
||||
@@ -593,8 +586,7 @@ mod tag {
|
||||
it.fmt(f)?;
|
||||
write!(f, ")")?;
|
||||
}
|
||||
Tag::Object =>
|
||||
write!(f, "Object")?,
|
||||
Tag::Object => write!(f, "Object")?,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
use cslice::CSlice;
|
||||
use vcell::VolatileCell;
|
||||
use libcortex_a9::asm;
|
||||
use crate::artiq_raise;
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
|
||||
use crate::pl::csr;
|
||||
use crate::rtio_mgt::resolve_channel_name;
|
||||
use cslice::CSlice;
|
||||
use libcortex_a9::asm;
|
||||
use vcell::VolatileCell;
|
||||
|
||||
pub const RTIO_O_STATUS_WAIT: i32 = 1;
|
||||
pub const RTIO_O_STATUS_UNDERFLOW: i32 = 2;
|
||||
pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: i32 = 4;
|
||||
pub const RTIO_I_STATUS_WAIT_EVENT: i32 = 1;
|
||||
pub const RTIO_I_STATUS_OVERFLOW: i32 = 2;
|
||||
pub const RTIO_I_STATUS_WAIT_STATUS: i32 = 4; // TODO
|
||||
pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: i32 = 8;
|
||||
use crate::{artiq_raise, pl::csr, rtio_mgt::resolve_channel_name};
|
||||
|
||||
pub const RTIO_O_STATUS_WAIT: i32 = 1;
|
||||
pub const RTIO_O_STATUS_UNDERFLOW: i32 = 2;
|
||||
pub const RTIO_O_STATUS_DESTINATION_UNREACHABLE: i32 = 4;
|
||||
pub const RTIO_I_STATUS_WAIT_EVENT: i32 = 1;
|
||||
pub const RTIO_I_STATUS_OVERFLOW: i32 = 2;
|
||||
pub const RTIO_I_STATUS_WAIT_STATUS: i32 = 4; // TODO
|
||||
pub const RTIO_I_STATUS_DESTINATION_UNREACHABLE: i32 = 8;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct TimestampedData {
|
||||
@@ -47,10 +46,10 @@ static mut TRANSACTION_BUFFER: Transaction = Transaction {
|
||||
reply_timestamp: VolatileCell::new(0),
|
||||
padding0: [0; 2],
|
||||
padding1: [0; 2],
|
||||
padding2: [0; 2]
|
||||
padding2: [0; 2],
|
||||
};
|
||||
|
||||
pub extern fn init() {
|
||||
pub extern "C" fn init() {
|
||||
unsafe {
|
||||
csr::rtio_core::reset_write(1);
|
||||
csr::rtio::engine_addr_base_write(&TRANSACTION_BUFFER as *const Transaction as u32);
|
||||
@@ -58,7 +57,7 @@ pub extern fn init() {
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn get_counter() -> i64 {
|
||||
pub extern "C" fn get_counter() -> i64 {
|
||||
unsafe {
|
||||
csr::rtio::counter_update_write(1);
|
||||
csr::rtio::counter_read() as i64
|
||||
@@ -67,15 +66,15 @@ pub extern fn get_counter() -> i64 {
|
||||
|
||||
static mut NOW: i64 = 0;
|
||||
|
||||
pub extern fn now_mu() -> i64 {
|
||||
pub extern "C" fn now_mu() -> i64 {
|
||||
unsafe { NOW }
|
||||
}
|
||||
|
||||
pub extern fn at_mu(t: i64) {
|
||||
pub extern "C" fn at_mu(t: i64) {
|
||||
unsafe { NOW = t }
|
||||
}
|
||||
|
||||
pub extern fn delay_mu(dt: i64) {
|
||||
pub extern "C" fn delay_mu(dt: i64) {
|
||||
unsafe { NOW += dt }
|
||||
}
|
||||
|
||||
@@ -87,18 +86,34 @@ unsafe fn process_exceptional_status(channel: i32, status: i32) {
|
||||
while csr::rtio::o_status_read() as i32 & RTIO_O_STATUS_WAIT != 0 {}
|
||||
}
|
||||
if status & RTIO_O_STATUS_UNDERFLOW != 0 {
|
||||
artiq_raise!("RTIOUnderflow",
|
||||
format!("RTIO underflow at {{1}} mu, channel 0x{:04x}:{}, slack {{2}} mu", channel, resolve_channel_name(channel as u32)),
|
||||
channel as i64, timestamp, timestamp - get_counter());
|
||||
artiq_raise!(
|
||||
"RTIOUnderflow",
|
||||
format!(
|
||||
"RTIO underflow at {{1}} mu, channel 0x{:04x}:{}, slack {{2}} mu",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
channel as i64,
|
||||
timestamp,
|
||||
timestamp - get_counter()
|
||||
);
|
||||
}
|
||||
if status & RTIO_O_STATUS_DESTINATION_UNREACHABLE != 0 {
|
||||
artiq_raise!("RTIODestinationUnreachable",
|
||||
format!("RTIO destination unreachable, output, at {{0}} mu, channel 0x{:04x}:{}", channel, resolve_channel_name(channel as u32)),
|
||||
timestamp, channel as i64, 0);
|
||||
artiq_raise!(
|
||||
"RTIODestinationUnreachable",
|
||||
format!(
|
||||
"RTIO destination unreachable, output, at {{0}} mu, channel 0x{:04x}:{}",
|
||||
channel,
|
||||
resolve_channel_name(channel as u32)
|
||||
),
|
||||
timestamp,
|
||||
channel as i64,
|
||||
0
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub extern fn output(target: i32, data: i32) {
|
||||
pub extern "C" fn output(target: i32, data: i32) {
|
||||
unsafe {
|
||||
// Clear status so we can observe response
|
||||
TRANSACTION_BUFFER.reply_status.set(0);
|
||||
@@ -126,7 +141,7 @@ pub extern fn output(target: i32, data: i32) {
|
||||
}
|
||||
}
|
||||