diff --git a/Cargo.toml b/Cargo.toml index 71986ec..07cd23a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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" diff --git a/c-shell b/c-shell new file mode 100644 index 0000000..522eaae --- /dev/null +++ b/c-shell @@ -0,0 +1,168 @@ +// Example program +#include +#include +#include + +#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); +} diff --git a/examples/read_pcileech.rs b/examples/read_pcileech.rs index 695727b..4a492de 100644 --- a/examples/read_pcileech.rs +++ b/examples/read_pcileech.rs @@ -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() ); diff --git a/src/fpga.rs b/src/fpga.rs index a79f672..08c4153 100644 --- a/src/fpga.rs +++ b/src/fpga.rs @@ -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::()] = [(); 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::()] = [(); 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 { let wr_raw = self.read_config::(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 { let rd_raw = self.read_config::(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::(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::>() - .concat(); - - let bytes32 = + fn read_mem_build_request(bytes: &[u8], keep_alive: bool) -> Result> { + // 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::>() + .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 + ] + ); + } } diff --git a/src/fpga/tlps.rs b/src/fpga/tlps.rs index a4f1f41..e337650 100644 --- a/src/fpga/tlps.rs +++ b/src/fpga/tlps.rs @@ -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::()] = [(); 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::()] = [(); 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::()] = [(); 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::()] = [(); 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] + ) + } } diff --git a/src/ft60x.rs b/src/ft60x.rs index 88b37fe..58a9658 100644 --- a/src/ft60x.rs +++ b/src/ft60x.rs @@ -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; diff --git a/src/lib.rs b/src/lib.rs index fefd804..71b0233 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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