Replaced old bitfield crate with a new one and unit tested tlp structs

rust_native
ko1N 4 years ago
parent 8ba97711aa
commit f5cc8dd318

@ -12,15 +12,14 @@ readme = "README.md"
crate-type = ["lib", "cdylib"]
[dependencies]
memflow-core = { git = "ssh://git@github.com/memflow/memflow.git", branch = "dev", features = ["plugins"] }
memflow-derive = { git = "ssh://git@github.com/memflow/memflow.git", branch = "dev" }
#memflow-core = { path = "../memflow/memflow-core", features = ["plugins"] }
#memflow-derive = { path = "../memflow/memflow-derive" }
memflow = { version = "0.1", features = ["inventory"] }
memflow-derive = "0.1"
log = { version = "0.4.8", default-features = false }
rusb = "0.6.0"
dataview = "0.1"
bitfield = "0.13.2"
pretty-hex = "0.1"
c2rust-bitfields = "0.3.0"
libc = "0.2"
[dev-dependencies]
clap = "2.33.0"

@ -0,0 +1,168 @@
// Example program
#include <iostream>
#include <string>
#include <cstdint>
#define WORD uint16_t
#define DWORD uint32_t
#define BYTE uint8_t
#define PBYTE uint8_t*
#define TRUE 1
#define BOOL int
#define QWORD uint64_t
#define FALSE 0
#define PDWORD DWORD*
#define ENDIAN_SWAP_DWORD(x) (x = (x << 24) | ((x >> 8) & 0xff00) | ((x << 8) & 0xff0000) | (x >> 24))
#define TLP_MRd32 0x00
#define TLP_MRd64 0x20
#define TLP_MRdLk32 0x01
#define TLP_MRdLk64 0x21
#define TLP_MWr32 0x40
#define TLP_MWr64 0x60
#define TLP_IORd 0x02
#define TLP_IOWr 0x42
#define TLP_CfgRd0 0x04
#define TLP_CfgRd1 0x05
#define TLP_CfgWr0 0x44
#define TLP_CfgWr1 0x45
#define TLP_Cpl 0x0A
#define TLP_CplD 0x4A
#define TLP_CplLk 0x0B
#define TLP_CplDLk 0x4B
#define MAX_SIZE_TX 0x3f0
typedef struct tdTLP_HDR {
WORD Length : 10;
WORD _AT : 2;
WORD _Attr : 2;
WORD _EP : 1;
WORD _TD : 1;
BYTE _R1 : 4;
BYTE _TC : 3;
BYTE _R2 : 1;
BYTE TypeFmt;
} TLP_HDR, *PTLP_HDR;
typedef struct tdTLP_HDR_MRdWr32 {
TLP_HDR h;
BYTE FirstBE : 4;
BYTE LastBE : 4;
BYTE Tag;
WORD RequesterID;
DWORD Address;
} TLP_HDR_MRdWr32, *PTLP_HDR_MRdWr32;
typedef struct tdTLP_HDR_MRdWr64 {
TLP_HDR h;
BYTE FirstBE : 4;
BYTE LastBE : 4;
BYTE Tag;
WORD RequesterID;
DWORD AddressHigh;
DWORD AddressLow;
} TLP_HDR_MRdWr64, *PTLP_HDR_MRdWr64;
int pfnFT_WritePipe(PBYTE pb, DWORD cb) {
printf("writepipe: %d bytes\n", cb);
for (int i = 0; i < cb; i++) {
printf("%d, ", (int)pb[i]);
}
printf("\n\n");
return 0;
}
BOOL DeviceFPGA_TxTlp(PBYTE pbTlp, DWORD cbTlp, BOOL fRdKeepalive, BOOL fFlush)
{
PBYTE txbuf_pb = (PBYTE)malloc(0x1000 * 32);
DWORD txbuf_cb = 0;
DWORD status;
PBYTE pbTx;
QWORD i;
DWORD cbTx, cbTxed = 0;
if(cbTlp & 0x3) { return FALSE; }
if(cbTlp > 4 * 4 + 128) { return FALSE; }
if(cbTlp && (txbuf_cb + (cbTlp << 1) + (fFlush ? 8 : 0) >= MAX_SIZE_TX)) {
if(!DeviceFPGA_TxTlp(NULL, 0, FALSE, TRUE)) { return FALSE; }
}
//if(ctxLC->fPrintf[LC_PRINTF_VVV]) {
// TLP_Print(ctxLC, pbTlp, cbTlp, TRUE);
//}
// prepare transmit buffer
pbTx = txbuf_pb + txbuf_cb;
cbTx = 2 * cbTlp;
for(i = 0; i < cbTlp; i += 4) {
*(PDWORD)(pbTx + (i << 1)) = *(PDWORD)(pbTlp + i);
*(PDWORD)(pbTx + ((i << 1) + 4)) = 0x77000000; // TX TLP
}
if(cbTlp) {
*(PDWORD)(pbTx + ((i << 1) - 4)) = 0x77040000; // TX TLP VALID LAST
}
if(fRdKeepalive) {
cbTx += 8;
*(PDWORD)(pbTx + (i << 1)) = 0xffeeddcc;
*(PDWORD)(pbTx + ((i << 1) + 4)) = 0x77020000; // LOOPBACK TX
}
txbuf_cb += cbTx;
// transmit
if((txbuf_cb >= MAX_SIZE_TX) || (fFlush && txbuf_cb)) {
status = pfnFT_WritePipe(txbuf_pb, txbuf_cb);
if(status == 0x20) {
//DeviceFPGA_ReInitializeFTDI(ctx); // try recovery if possible.
status = pfnFT_WritePipe(txbuf_pb, txbuf_cb);
}
txbuf_cb = 0;
//usleep(ctx->perf.DELAY_WRITE);
return (0 == status);
}
return TRUE;
}
int main()
{
DWORD tx[4] = { 0 };
PBYTE txb = (PBYTE)tx;
PTLP_HDR_MRdWr64 hdrRd64 = (PTLP_HDR_MRdWr64)tx;
PTLP_HDR_MRdWr32 hdrRd32 = (PTLP_HDR_MRdWr32)tx;
printf("stuff: 0x%x\n", (WORD)(0x123 >> 2));
/*
hdrRd32->h.TypeFmt = TLP_MRd64;
hdrRd32->h.Length = (WORD)(0x123 >> 2);
*/
hdrRd32->h.TypeFmt = TLP_MRd32;
hdrRd32->h.Length = (WORD)(0x123 >> 2);
hdrRd32->RequesterID = 17;
hdrRd32->Tag = 0x80;
hdrRd32->FirstBE = 0xf;
hdrRd32->LastBE = 0xf;
hdrRd32->Address = (DWORD)(0x6000);
//uint64_t addr = 0x100000000 + 0x6000;
//hdrRd64->AddressHigh = (DWORD)(addr >> 32);
//hdrRd64->AddressLow = (DWORD)(addr);
//printf("sizeof 32: 0x%x\n", sizeof(TLP_HDR_MRdWr32));
//printf("sizeof 64: 0x%x\n", sizeof(TLP_HDR_MRdWr64));
printf("tlp:\n");
for (int i = 0; i < 16; i++) {
printf("%d ", (int)txb[i]);
//printf("%X ", tx[i]);
}
printf("\n");
for(int j = 0; j < 4; j++) {
ENDIAN_SWAP_DWORD(tx[j]);
}
DeviceFPGA_TxTlp((PBYTE)tx, /*is32 ? 12 : 16*/ 12, FALSE, TRUE);
}

@ -1,6 +1,6 @@
use log::Level;
use memflow_core::connector::ConnectorArgs;
use memflow::connector::ConnectorArgs;
use memflow_pcileech::{create_connector, PcieGen};
fn main() {
@ -10,7 +10,7 @@ fn main() {
// TODO: put this + more in a conn print trait ->
println!(
"pcie device opened with link width {} and pcie gen {}",
"pcie device opened with link width {} and pcie gen {:?}",
conn.pcie_link_width(),
conn.pcie_gen()
);

@ -9,12 +9,12 @@ use core::time::Duration;
use log::{info, trace, warn};
use memflow_core::{
use memflow::{
error::{Error, Result},
size,
};
use bitfield::bitfield;
use c2rust_bitfields::*;
use dataview::Pod;
use pretty_hex::*;
@ -33,37 +33,37 @@ pub struct PhyConfig {
pub rd: PhyConfigRd, // 32 bits
}
bitfield! {
pub struct PhyConfigWr(u16);
impl Debug;
pub pl_directed_link_auton, set_pl_directed_link_auton: 0;
pub pl_directed_link_change, set_pl_directed_link_change: 2, 1;
pub pl_directed_link_speed, set_pl_directed_link_speed: 3;
pub pl_directed_link_width, set_pl_directed_link_width: 5, 4;
pub pl_upstream_prefer_deemph, _: 6;
pub pl_transmit_hot_rst, set_pl_transmit_hot_rst: 7;
pub pl_downstream_deemph_source, _: 8;
//_, _: 16, 9;
#[repr(C, align(1))]
#[derive(BitfieldStruct, Pod)]
pub struct PhyConfigWr {
#[bitfield(name = "pl_directed_link_auton", ty = "libc::uint8_t", bits = "0..=0")]
#[bitfield(name = "pl_directed_link_change", ty = "libc::uint8_t", bits = "1..=2")]
#[bitfield(name = "pl_directed_link_speed", ty = "libc::uint8_t", bits = "3..=3")]
#[bitfield(name = "pl_directed_link_width", ty = "libc::uint8_t", bits = "4..=5")]
#[bitfield(name = "pl_upstream_prefer_deemph", ty = "libc::uint8_t", bits = "6..=6")]
#[bitfield(name = "pl_transmit_hot_rst", ty = "libc::uint8_t", bits = "7..=7")]
#[bitfield(name = "pl_downstream_deemph_source", ty = "libc::uint8_t", bits = "8..=8")]
buffer: [u8; 2],
}
const _: [(); core::mem::size_of::<PhyConfigWr>()] = [(); 2];
bitfield! {
pub struct PhyConfigRd(u32);
impl Debug;
pub pl_ltssm_state, _: 5, 0;
pub pl_rx_pm_state, _: 7, 6;
pub pl_tx_pm_state, _: 10, 8;
pub pl_initial_link_width, _: 13, 11;
pub pl_lane_reversal_mode, _: 15, 14;
pub pl_sel_lnk_width, _: 17, 16;
pub pl_phy_lnk_up, _: 18;
pub pl_link_gen2_cap, _: 19;
pub pl_link_partner_gen2_supported, _: 20;
pub pl_link_upcfg_cap, _: 21;
pub pl_sel_lnk_rate, _: 22;
pub pl_directed_change_done, _: 23;
pub pl_received_hot_rst, _: 24;
//_, _: 31, 25;
#[repr(C, align(1))]
#[derive(BitfieldStruct, Pod)]
pub struct PhyConfigRd {
#[bitfield(name = "pl_ltssm_state", ty = "libc::uint8_t", bits = "0..=5")]
#[bitfield(name = "pl_rx_pm_state", ty = "libc::uint8_t", bits = "6..=7")]
#[bitfield(name = "pl_tx_pm_state", ty = "libc::uint8_t", bits = "8..=10")]
#[bitfield(name = "pl_initial_link_width", ty = "libc::uint8_t", bits = "11..=13")]
#[bitfield(name = "pl_lane_reversal_mode", ty = "libc::uint8_t", bits = "14..=15")]
#[bitfield(name = "pl_sel_lnk_width", ty = "libc::uint8_t", bits = "16..=17")]
#[bitfield(name = "pl_phy_lnk_up", ty = "libc::uint8_t", bits = "18..=18")]
#[bitfield(name = "pl_link_gen2_cap", ty = "libc::uint8_t", bits = "19..=19")]
#[bitfield(name = "pl_link_partner_gen2_supported", ty = "libc::uint8_t", bits = "20..=20")]
#[bitfield(name = "pl_link_upcfg_cap", ty = "libc::uint8_t", bits = "21..=21")]
#[bitfield(name = "pl_sel_lnk_rate", ty = "libc::uint8_t", bits = "22..=22")]
#[bitfield(name = "pl_directed_change_done", ty = "libc::uint8_t", bits = "23..=23")]
#[bitfield(name = "pl_received_hot_rst", ty = "libc::uint8_t", bits = "24..=24")]
buffer: [u8; 4],
}
const _: [(); core::mem::size_of::<PhyConfigRd>()] = [(); 4];
@ -199,12 +199,12 @@ impl Device {
warn!("hot resetting the fpga");
let mut wr = self.get_phy_wr()?;
wr.set_pl_transmit_hot_rst(true);
wr.set_pl_transmit_hot_rst(1);
self.set_phy_wr(&wr)?;
std::thread::sleep(Duration::from_millis(250)); // TODO: poll pl_ltssm_state + timeout with failure
wr.set_pl_transmit_hot_rst(false);
wr.set_pl_transmit_hot_rst(0);
self.set_phy_wr(&wr)?;
Ok(())
}
@ -216,17 +216,17 @@ impl Device {
pub fn get_phy_wr(&mut self) -> Result<PhyConfigWr> {
let wr_raw =
self.read_config::<u16>(0x0016, FPGA_CONFIG_PCIE | FPGA_CONFIG_SPACE_READWRITE)?;
Ok(PhyConfigWr { 0: wr_raw })
Ok(PhyConfigWr { buffer: u16::to_le_bytes(wr_raw) })
}
pub fn set_phy_wr(&mut self, wr: &PhyConfigWr) -> Result<()> {
self.write_config(0x0016, wr.0, FPGA_CONFIG_PCIE | FPGA_CONFIG_SPACE_READWRITE)
self.write_config(0x0016, u16::from_le_bytes(wr.buffer), FPGA_CONFIG_PCIE | FPGA_CONFIG_SPACE_READWRITE)
}
pub fn get_phy_rd(&mut self) -> Result<PhyConfigRd> {
let rd_raw =
self.read_config::<u32>(0x000a, FPGA_CONFIG_PCIE | FPGA_CONFIG_SPACE_READONLY)?;
Ok(PhyConfigRd { 0: rd_raw })
Ok(PhyConfigRd { buffer: u32::to_le_bytes(rd_raw) })
}
/// Prints out all internal registers of the FPGA to `info!()`
@ -293,10 +293,15 @@ impl Device {
}*/
// TODO: this is duplicated code (see config_parse_response)
// https://github.com/ufrisk/LeechCore/blob/master/leechcore/device_fpga.c#L1603
pub fn recv_tlps_64(&mut self, bytes: u32 /* maybe u16? */) -> Result<()> {
let mut respbuf = vec![0u8; 0x1000]; // TEST
let mut respbuf = vec![0u8; 0x4000]; // TEST
self.ft60.read_pipe(&mut respbuf)?;
//let tlps = [0u8; 16+512]; // TLP_RX_MAX_SIZE
//let tlp_num = 0;
let mut tlps = Vec::new();
let view = respbuf.as_data_view();
let mut skip = 0;
for i in (0..respbuf.len()).step_by(32) {
@ -318,55 +323,60 @@ impl Device {
continue;
}
trace!("parsing data buffer");
for j in 0..7 {
//trace!("parsing tlp data buffer");
let mut tlp_offs = 0;
for _ in 0..7 {
if (status & 0x03) == 0 {
println!("pcie tlp received :)");
// println!("pcie tlp received :)");
tlps.push(view.copy::<u32>(i + skip + 4 + tlp_offs));
// if(tlps.len() >= TLP_RX_MAX_SIZE / sizeof(DWORD)) { return; }
}
if (status & 0x07) == 4 {
println!("pcie tlp LAST received :)");
//println!("pcie tlp LAST received :)");
// TODO: dispatch tlp buffer
if tlps.len() >= 3 {
println!("received {} tlps", tlps.len() << 2);
// TODO: transmute tlps buffer to tlp header
} else {
println!("received {} tlps - ERROR, Bad PCIe TLP received", tlps.len() << 2);
}
tlps.clear();
}
tlp_offs += 4;
status >>= 4;
}
}
Ok(())
}
pub fn send_tlps_64(&mut self, tlps: &[TlpReadWrite64], keep_alive: bool) -> Result<()> {
let bytes = tlps
.iter()
.map(|t| t.as_bytes())
.collect::<Vec<_>>()
.concat();
let bytes32 =
fn read_mem_build_request(bytes: &[u8], keep_alive: bool) -> Result<Vec<u8>> {
// convert slice into [u32] slice which is 4 times smaller
let dwords =
unsafe { std::slice::from_raw_parts(bytes.as_ptr() as *const u32, bytes.len() / 4) };
self.send_tlps_raw(&bytes32, keep_alive)
}
/// Send a TLP to the fpga
fn send_tlps_raw(&mut self, tlps: &[u32], keep_alive: bool) -> Result<()> {
if tlps.len() > 4 + 32 {
// tlp buffer constraints
if (bytes.len() & 0x3) != 0 || bytes.len() > 4 * 4 + 128 {
return Err(Error::Connector("tlp buffer is too large"));
}
/*
if(cbTlp && (ctx->txbuf.cb + (cbTlp << 1) + (fFlush ? 8 : 0) >= ctx->perf.MAX_SIZE_TX)) {
if(!DeviceFPGA_TxTlp(ctxLC, ctx, NULL, 0, FALSE, TRUE)) { return FALSE; }
}
if(cbTlp && (txbuf_cb + (cbTlp << 1) + (fFlush ? 8 : 0) >= MAX_SIZE_TX)) {
if(!DeviceFPGA_TxTlp(NULL, 0, FALSE, TRUE)) { return FALSE; }
}
*/
// TLP_Print
// create transmit buffer
let mut buf = Vec::new();
for tlp in tlps.iter() {
for tlp in dwords.iter() {
buf.push(tlp.to_be());
buf.push(0x77000000); // TX TLP
}
// TODO: remove this pop in the algorithm
if !tlps.is_empty() {
if !bytes.is_empty() {
buf.pop();
buf.push(0x77040000); // TX TLP VALID LAST
}
@ -378,13 +388,39 @@ impl Device {
// currently we just flush out every tlp transmission immediately
// and not buffer them internally.
let byte_buf: &[u8] = unsafe { std::mem::transmute(buf.as_slice()) };
let byte_buf = buf
.iter()
.map(|&t| u32::to_le_bytes(t))
.collect::<Vec<_>>()
.concat();
Ok(byte_buf.to_vec())
}
pub fn read_mem_into_raw(&mut self, addr: u64, size: u64, device_id: u16) -> Result<()> {
// TODO: safety checks
// TODO: split by page and page align
let tlp = if addr < size::gb(4) as u64 {
TlpReadWrite32::new_read(addr as u32, size as u16, 0x0, device_id).as_bytes().to_vec()
} else {
TlpReadWrite64::new_read(addr, size as u16, 0x0, device_id).as_bytes().to_vec()
};
let req = Self::read_mem_build_request(tlp.as_slice(), false)?;
// TODO: handle error codes?
self.ft60.write_pipe(byte_buf)?;
// if status == 0x20 {
// failure
// }
self.ft60.write_pipe(&req)?;
std::thread::sleep(std::time::Duration::from_millis(500));
self.recv_tlps_64(0x1000)?;
/*
let mut readbuf = [0u8; size::kb(128)];
let bytes = self.ft60.read_pipe(&mut readbuf)?;
Self::read_config_parse_response(addr, &readbuf[..bytes], buf, flags)
*/
Ok(())
}
@ -740,4 +776,25 @@ mod tests {
.unwrap();
assert_eq!(outbuf, [0, 128, 0, 128, 128, 2, 35, 119,]);
}
#[test]
fn test_read_mem32() {
let tlp = TlpReadWrite32::new_read(0x6000, 0x123, 0x80, 17);
assert_eq!(
Device::read_mem_build_request(&tlp.as_bytes(), false).unwrap(),
[0, 0, 0, 72, 0, 0, 0, 119, 0, 17, 128, 255, 0, 0, 0, 119, 0, 0, 96, 0, 0, 0, 4, 119]
);
}
#[test]
fn test_read_mem64() {
let tlp = TlpReadWrite64::new_read(size::gb(4) as u64 + 0x6000, 0x123, 0x80, 17);
assert_eq!(
Device::read_mem_build_request(&tlp.as_bytes(), false).unwrap(),
[
32, 0, 0, 72, 0, 0, 0, 119, 0, 17, 128, 255, 0, 0, 0, 119, 0, 0, 0, 1, 0, 0, 0,
119, 0, 0, 96, 0, 0, 0, 4, 119
]
);
}
}

@ -1,4 +1,4 @@
use bitfield::bitfield;
use c2rust_bitfields::*;
use dataview::{DataView, Pod};
const TLP_READ_32: u8 = 0x00;
@ -8,40 +8,33 @@ const fn pack_bits4(first: u8, second: u8) -> u8 {
(first & ((1 << 4) - 1)) + ((second & ((1 << 4) - 1)) << 4)
}
const fn split_addr64_high(address: u64) -> u32 {
((address & ((1 << 32) - 1)) >> 32) as u32
}
const fn split_addr64_low(address: u64) -> u32 {
(address & ((1 << 32) - 1)) as u32
}
bitfield! {
pub struct TlpHeader(u32);
impl Debug;
pub len_tlps, set_len_tlps: 9, 0;
pub at, _: 11, 10;
pub attr, _: 13, 12;
pub ep, _: 14;
pub td, _: 15;
pub r1, _: 19, 16;
pub tc, _: 22, 20;
pub r2, _: 23;
pub ty, set_ty: 31, 24;
#[repr(C, align(1))]
#[derive(BitfieldStruct, Pod)]
pub struct TlpHeader {
#[bitfield(name = "len_tlps", ty = "libc::uint16_t", bits = "0..=9")]
#[bitfield(name = "at", ty = "libc::uint16_t", bits = "10..=11")]
#[bitfield(name = "attr", ty = "libc::uint16_t", bits = "12..=13")]
#[bitfield(name = "ep", ty = "libc::uint16_t", bits = "14..=14")]
#[bitfield(name = "td", ty = "libc::uint16_t", bits = "15..=15")]
#[bitfield(name = "r1", ty = "libc::uint8_t", bits = "16..=19")]
#[bitfield(name = "tc", ty = "libc::uint8_t", bits = "20..=22")]
#[bitfield(name = "r2", ty = "libc::uint8_t", bits = "23..=23")]
#[bitfield(name = "ty", ty = "libc::uint8_t", bits = "24..=31")]
buffer: [u8; 4],
}
const _: [(); core::mem::size_of::<TlpHeader>()] = [(); 4];
unsafe impl Pod for TlpHeader {}
impl TlpHeader {
pub fn new(ty: u8, len_tlps: u16) -> Self {
let mut h = Self { 0: 0 };
println!("ok0");
h.set_ty(ty as u32);
println!("ok1");
h.set_len_tlps(len_tlps as u32);
println!("ok2");
let mut h = Self::zeroed();
h.set_ty(ty);
if len_tlps < 0x1000 {
// shift length
h.set_len_tlps(len_tlps / 4);
} else {
// max length
h.set_len_tlps(len_tlps);
}
h
}
}
@ -61,7 +54,7 @@ const _: [(); core::mem::size_of::<TlpReadWrite32>()] = [(); 0xC];
impl TlpReadWrite32 {
pub fn new_read(address: u32, len: u16, tag: u8, requester_id: u16) -> Self {
Self {
header: TlpHeader::new(TLP_READ_32, len / 4),
header: TlpHeader::new(TLP_READ_32, len),
be: pack_bits4(0xF, 0xF),
tag,
requester_id,
@ -102,12 +95,12 @@ const _: [(); core::mem::size_of::<TlpReadWrite64>()] = [(); 0x10];
impl TlpReadWrite64 {
pub fn new_read(address: u64, len: u16, tag: u8, requester_id: u16) -> Self {
Self {
header: TlpHeader::new(TLP_READ_64, len / 4),
header: TlpHeader::new(TLP_READ_64, len),
be: pack_bits4(0xF, 0xF),
tag,
requester_id,
address_high: split_addr64_high(address),
address_low: split_addr64_low(address),
address_high: (address >> 32) as u32,
address_low: address as u32,
}
}
@ -124,18 +117,65 @@ impl TlpReadWrite64 {
}
pub fn set_address(&mut self, address: u64) {
self.address_high = split_addr64_high(address);
self.address_low = split_addr64_low(address);
self.address_high = (address >> 32) as u32;
self.address_low = address as u32;
}
}
/// Tlp Packet - Completion with Data
#[repr(C, align(1))]
#[derive(BitfieldStruct, Pod)]
pub struct TlpCplD {
header: TlpHeader,
#[bitfield(name = "byte_count", ty = "libc::uint16_t", bits = "0..=11")]
#[bitfield(name = "attr", ty = "libc::uint16_t", bits = "12..=12")]
#[bitfield(name = "ep", ty = "libc::uint16_t", bits = "13..=15")]
buffer1: [u8; 2],
completer_id: u16,
#[bitfield(name = "lower_addr", ty = "libc::uint8_t", bits = "0..=6")]
#[bitfield(name = "r1", ty = "libc::uint8_t", bits = "7..=7")]
buffer2: [u8; 1],
tag: u8,
requester_id: u16,
}
//const _: [(); core::mem::size_of::<TlpCplD>()] = [(); 0x10];
#[cfg(test)]
mod tests {
use super::pack_bits4;
use super::{pack_bits4, TlpHeader, TlpReadWrite32, TlpReadWrite64, TLP_READ_32, TLP_READ_64};
use dataview::Pod;
use memflow::size;
#[test]
fn test_pack_bits4() {
assert_eq!(pack_bits4(0xA, 0xB), 0xBA);
assert_eq!(pack_bits4(0xAB, 0xCD), 0xDB);
}
#[test]
fn test_header32() {
let header = TlpHeader::new(TLP_READ_32, 0x123);
assert_eq!(header.as_bytes(), &[72, 0, 0, 0])
}
#[test]
fn test_header64() {
let header = TlpHeader::new(TLP_READ_64, 0x123);
assert_eq!(header.as_bytes(), &[72, 0, 0, 32])
}
#[test]
fn test_tlp_rw32() {
let tlp = TlpReadWrite32::new_read(0x6000, 0x123, 0x80, 17);
assert_eq!(tlp.as_bytes(), &[72, 0, 0, 0, 255, 128, 17, 0, 0, 96, 0, 0])
}
#[test]
fn test_tlp_rw64() {
let tlp = TlpReadWrite64::new_read(size::gb(4) as u64 + 0x6000, 0x123, 0x80, 17);
assert_eq!(
tlp.as_bytes(),
&[72, 0, 0, 32, 255, 128, 17, 0, 1, 0, 0, 0, 0, 96, 0, 0]
)
}
}

@ -12,7 +12,7 @@ use core::time::Duration;
use log::{info, trace};
use memflow_core::error::{Error, Result};
use memflow::error::{Error, Result};
use dataview::Pod;

@ -8,10 +8,11 @@ use log::{info, warn};
use fpga::{PhyConfigRd, PhyConfigWr};
use memflow_core::connector::ConnectorArgs;
use memflow_core::*;
use memflow::connector::ConnectorArgs;
use memflow::*;
use memflow_derive::connector;
#[derive(Debug)]
pub enum PcieGen {
Gen1 = 0,
Gen2 = 1,
@ -74,25 +75,22 @@ impl PciLeech {
}
}
pub fn pcie_gen(&self) -> u8 {
pub fn pcie_gen(&self) -> PcieGen {
match self.phy_rd.pl_sel_lnk_rate() {
false => 1,
true => 2,
0 => PcieGen::Gen1,
1 => PcieGen::Gen2,
_ => panic!("invalid sel_lnk_rate"),
}
}
pub fn set_pcie_gen(&mut self, gen: PcieGen) -> Result<()> {
let gen2 = match gen {
PcieGen::Gen1 => false,
PcieGen::Gen2 => true,
};
if gen2 == self.phy_rd.pl_sel_lnk_rate() {
let genb = gen as u8;
if genb == self.phy_rd.pl_sel_lnk_rate() {
info!("requested pcie gen already set.");
return Ok(());
}
if gen2 && !self.phy_rd.pl_link_gen2_cap() {
if genb != 0 && self.phy_rd.pl_link_gen2_cap() == 0 {
warn!("pcie gen2 is not supported by the fpga configuration");
return Err(Error::Connector(
"pcie gen2 is not supported by the fpga configuration",
@ -100,15 +98,15 @@ impl PciLeech {
}
// update config
self.phy_wr.set_pl_directed_link_auton(true);
self.phy_wr.set_pl_directed_link_speed(gen2);
self.phy_wr.set_pl_directed_link_auton(1);
self.phy_wr.set_pl_directed_link_speed(genb);
self.phy_wr.set_pl_directed_link_change(2);
self.device.set_phy_wr(&self.phy_wr)?;
// poll config update
for _ in 0..32 {
if let Ok(rd) = self.device.get_phy_rd() {
if rd.pl_directed_change_done() {
if rd.pl_directed_change_done() == 1 {
info!("fpga changes successfully applied");
self.phy_rd = rd;
break;
@ -117,8 +115,8 @@ impl PciLeech {
}
// reset config
self.phy_wr.set_pl_directed_link_auton(false);
self.phy_wr.set_pl_directed_link_speed(false);
self.phy_wr.set_pl_directed_link_auton(0);
self.phy_wr.set_pl_directed_link_speed(0);
self.phy_wr.set_pl_directed_link_change(0);
self.device.set_phy_wr(&self.phy_wr)?;
@ -132,28 +130,7 @@ impl PciLeech {
// test read functions
pub fn test_read(&mut self) -> Result<()> {
// create read request
/*
// cb
// device id
// addr
*/
// TODO: 32bit target
let tag = 0; // 0x80 for ecc?
println!("stuff0");
let tlp = TlpReadWrite64::new_read(0x1000, 0x1000, tag, self.device_id);
// TODO: tag++ for every tlp in one request?
println!("stuff1");
self.device.send_tlps_64(&[tlp], false)?;
// TODO: read stuff back synchronously?
println!("stuff2");
std::thread::sleep(std::time::Duration::from_millis(25));
// bytes added together from read requests
self.device.recv_tlps_64(0x1000)?;
println!("stuff3");
self.device.read_mem_into_raw(0x1000, 0x1000, self.device_id);
Ok(())
}
}
@ -170,6 +147,10 @@ impl PhysicalMemory for PciLeech {
"memflow_pcileech::phys_write_iter not implemented",
))
}
fn metadata(&self) -> PhysicalMemoryMetadata {
panic!()
}
}
// TODO: handle args properly

Loading…
Cancel
Save