1use anyhow::{Result, bail, ensure};
6use rusb::{Direction, Recipient, RequestType};
7use std::cell::Cell;
8use std::mem::size_of;
9use std::rc::Rc;
10use std::time::Duration;
11use zerocopy::{FromBytes, Immutable, IntoBytes};
12
13use crate::io::eeprom;
14use crate::io::gpio::GpioPin;
15use crate::io::spi::{
16 AssertChipSelect, MaxSizes, SpiError, Target, TargetChipDeassert, Transfer, TransferMode,
17};
18use crate::transport::TransportError;
19use crate::transport::hyperdebug::{BulkInterface, Inner};
20
21pub struct HyperdebugSpiTarget {
22 inner: Rc<Inner>,
23 interface: BulkInterface,
24 target_enable_cmd: u8,
25 target_idx: u8,
26 feature_bitmap: u16,
27 supports_tpm_poll: bool,
28 max_sizes: MaxSizes,
29 cs_asserted_count: Cell<u32>,
30}
31
32const TRANSFER_START_TIMEOUT: Duration = Duration::from_millis(1100);
37
38const USB_SPI_PKT_ID_CMD_GET_USB_SPI_CONFIG: u16 = 0;
39const USB_SPI_PKT_ID_RSP_USB_SPI_CONFIG: u16 = 1;
40const USB_SPI_PKT_ID_CMD_TRANSFER_START: u16 = 2;
41const USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE: u16 = 3;
42const USB_SPI_PKT_ID_RSP_TRANSFER_START: u16 = 5;
44const USB_SPI_PKT_ID_RSP_TRANSFER_CONTINUE: u16 = 6;
45const USB_SPI_PKT_ID_CMD_CHIP_SELECT: u16 = 7;
46const USB_SPI_PKT_ID_RSP_CHIP_SELECT: u16 = 8;
47const USB_SPI_PKT_ID_CMD_EEPROM_TRANSFER_START: u16 = 9;
48
49pub const USB_SPI_REQ_ENABLE: u8 = 0;
50pub const USB_SPI_REQ_ENABLE_AP: u8 = 2;
52pub const USB_SPI_REQ_ENABLE_EC: u8 = 3;
53
54const USB_MAX_SIZE: usize = 64;
55const FULL_DUPLEX: usize = 65535;
56
57const FEATURE_BIT_FULL_DUPLEX: u16 = 0x0001;
58const FEATURE_BIT_EEPROM: u16 = 0x0002;
59const FEATURE_BIT_EEPROM_DUAL: u16 = 0x0004;
60const FEATURE_BIT_EEPROM_QUAD: u16 = 0x0008;
61const FEATURE_BIT_EEPROM_OCTO: u16 = 0x0010;
62const FEATURE_BIT_EEPROM_DTR: u16 = 0x0020;
63const FEATURE_BIT_EEPROM_DOUBLE_BUFFER: u16 = 0x0040;
64
65const EEPROM_FLAGS_OPCODE_LEN_POS: u8 = 0;
66const EEPROM_FLAGS_ADDR_LEN_POS: u8 = 2;
67const EEPROM_FLAGS_MODE_111: u32 = 0x00000000;
68const EEPROM_FLAGS_MODE_11N: u32 = 0x00000020;
69const EEPROM_FLAGS_MODE_1NN: u32 = 0x00000040;
70const EEPROM_FLAGS_MODE_NNN: u32 = 0x00000060;
71const EEPROM_FLAGS_WIDTH_1WIRE: u32 = 0x00000000;
72const EEPROM_FLAGS_WIDTH_2WIRE: u32 = 0x00000080;
73const EEPROM_FLAGS_WIDTH_4WIRE: u32 = 0x00000100;
74const EEPROM_FLAGS_WIDTH_8WIRE: u32 = 0x00000180;
75const EEPROM_FLAGS_DTR: u32 = 0x00000200;
76const EEPROM_FLAGS_DUMMY_CYCLES_POS: u8 = 10;
77const EEPROM_FLAGS_GSC_READY: u32 = 0x04000000;
78const EEPROM_FLAGS_TPM: u32 = 0x08000000;
79const EEPROM_FLAGS_WRITE_ENABLE: u32 = 0x10000000;
80const EEPROM_FLAGS_POLL_BUSY: u32 = 0x20000000;
81const EEPROM_FLAGS_DOUBLE_BUFFER: u32 = 0x40000000;
82const EEPROM_FLAGS_WRITE: u32 = 0x80000000;
83
84const STATUS_SUCCESS: u16 = 0x0000;
85const STATUS_TIMEOUT: u16 = 0x0001;
86const STATUS_BUSY: u16 = 0x0002;
87const STATUS_WRITE_COUNT_INVALID: u16 = 0x0003;
88const STATUS_READ_COUNT_INVALID: u16 = 0x0004;
89const STATUS_DISABLED: u16 = 0x0005;
90const STATUS_RX_BAD_DATA_INDEX: u16 = 0x0006;
91const STATUS_RX_DATA_OVERFLOW: u16 = 0x0007;
92const STATUS_RX_UNEXPECTED_PACKET: u16 = 0x0008;
93const STATUS_UNSUPPORTED_FULL_DUPLEX: u16 = 0x0009;
94const STATUS_UNSUPPORTED_FLASH_MODE: u16 = 0x000A;
95const STATUS_STREAMING_FIRST_SUCCESS: u16 = 0x000B;
96
97fn status_code_description(status_code: u16) -> String {
98 match status_code {
99 STATUS_SUCCESS => "success",
100 STATUS_TIMEOUT => "timeout",
101 STATUS_BUSY => "busy",
102 STATUS_WRITE_COUNT_INVALID => "protocol corruption (WRITE_COUNT_INVALID)",
103 STATUS_READ_COUNT_INVALID => "protocol corruption (READ_COUNT_INVALID)",
104 STATUS_DISABLED => "port not enabled",
105 STATUS_RX_BAD_DATA_INDEX => "protocol corruption (RX_BAD_DATA_INDEX)",
106 STATUS_RX_DATA_OVERFLOW => "protocol corruption (RX_DATA_OVERFLOW)",
107 STATUS_RX_UNEXPECTED_PACKET => "protocol corruption (RX_UNEXPECTED_PACKET)",
108 STATUS_UNSUPPORTED_FULL_DUPLEX => "full duplex not supported",
109 STATUS_UNSUPPORTED_FLASH_MODE => "requested flash mode not supported",
110 _ => {
111 return format!("unknown error {:04x}", status_code);
112 }
113 }
114 .to_string()
115}
116
117#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
118#[repr(C)]
119struct RspUsbSpiConfig {
120 packet_id: u16,
121 max_write_chunk: u16,
122 max_read_chunk: u16,
123 feature_bitmap: u16,
124}
125
126#[derive(Immutable, IntoBytes, FromBytes, Debug)]
127#[repr(C)]
128struct CmdTransferStart {
129 packet_id: u16,
130 write_count: u16,
131 read_count: u16,
132 data: [u8; USB_MAX_SIZE - 6],
133}
134impl CmdTransferStart {
135 fn new() -> Self {
136 Self {
137 packet_id: USB_SPI_PKT_ID_CMD_TRANSFER_START,
138 write_count: 0,
139 read_count: 0,
140 data: [0; USB_MAX_SIZE - 6],
141 }
142 }
143}
144
145#[derive(Immutable, IntoBytes, FromBytes, Debug)]
146#[repr(C)]
147struct CmdEepromTransferStart {
148 packet_id: u16,
149 count: u16,
150 flags: u32,
151 data: [u8; USB_MAX_SIZE - 8],
152}
153impl CmdEepromTransferStart {
154 fn new() -> Self {
155 Self {
156 packet_id: USB_SPI_PKT_ID_CMD_EEPROM_TRANSFER_START,
157 count: 0,
158 flags: 0,
159 data: [0; USB_MAX_SIZE - 8],
160 }
161 }
162}
163
164#[derive(Immutable, IntoBytes, FromBytes, Debug)]
165#[repr(C)]
166struct CmdTransferContinue {
167 packet_id: u16,
168 data_index: u16,
169 data: [u8; USB_MAX_SIZE - 4],
170}
171impl CmdTransferContinue {
172 fn new() -> Self {
173 Self {
174 packet_id: USB_SPI_PKT_ID_CMD_TRANSFER_CONTINUE,
175 data_index: 0,
176 data: [0; USB_MAX_SIZE - 4],
177 }
178 }
179}
180
181#[derive(Immutable, IntoBytes, FromBytes, Debug)]
182#[repr(C)]
183struct RspTransferStart {
184 packet_id: u16,
185 status_code: u16,
186 data: [u8; USB_MAX_SIZE - 4],
187}
188impl RspTransferStart {
189 fn new() -> Self {
190 Self {
191 packet_id: 0,
192 status_code: 0,
193 data: [0; USB_MAX_SIZE - 4],
194 }
195 }
196}
197
198#[derive(Immutable, IntoBytes, FromBytes, Debug)]
199#[repr(C)]
200struct RspTransferContinue {
201 packet_id: u16,
202 data_index: u16,
203 data: [u8; USB_MAX_SIZE - 4],
204}
205impl RspTransferContinue {
206 fn new() -> Self {
207 Self {
208 packet_id: 0,
209 data_index: 0,
210 data: [0; USB_MAX_SIZE - 4],
211 }
212 }
213}
214
215#[derive(Immutable, IntoBytes, FromBytes, Debug)]
216#[repr(C)]
217struct CmdChipSelect {
218 packet_id: u16,
219 flags: u16,
220}
221impl CmdChipSelect {
222 fn new(assert_chip_select: bool) -> Self {
223 Self {
224 packet_id: USB_SPI_PKT_ID_CMD_CHIP_SELECT,
225 flags: u16::from(assert_chip_select),
226 }
227 }
228}
229
230#[derive(Immutable, IntoBytes, FromBytes, Debug, Default)]
231#[repr(C)]
232struct RspChipSelect {
233 packet_id: u16,
234 status_code: u16,
235}
236impl RspChipSelect {
237 fn new() -> Self {
238 Self {
239 packet_id: 0,
240 status_code: 0,
241 }
242 }
243}
244
245enum StreamState<'a> {
246 NoPending,
247 PendingWrite,
248 PendingRead(&'a mut [u8]),
249}
250
251impl HyperdebugSpiTarget {
252 pub fn open(
253 inner: &Rc<Inner>,
254 spi_interface: &BulkInterface,
255 enable_cmd: u8,
256 idx: u8,
257 supports_tpm_poll: bool,
258 ) -> Result<Self> {
259 let mut usb_handle = inner.usb_device.borrow_mut();
260
261 inner.selected_spi.set(idx);
263 usb_handle.write_control(
264 rusb::request_type(Direction::Out, RequestType::Vendor, Recipient::Interface),
265 enable_cmd,
266 idx as u16,
267 spi_interface.interface as u16,
268 &[],
269 )?;
270
271 usb_handle.claim_interface(spi_interface.interface)?;
273
274 usb_handle.write_bulk(
276 spi_interface.out_endpoint,
277 &USB_SPI_PKT_ID_CMD_GET_USB_SPI_CONFIG.to_le_bytes(),
278 )?;
279 let mut resp: RspUsbSpiConfig = Default::default();
280 let rc = usb_handle.read_bulk(spi_interface.in_endpoint, resp.as_mut_bytes())?;
281 ensure!(
282 rc == size_of::<RspUsbSpiConfig>(),
283 TransportError::CommunicationError(
284 "Unrecognized reponse to GET_USB_SPI_CONFIG".to_string()
285 )
286 );
287 ensure!(
288 resp.packet_id == USB_SPI_PKT_ID_RSP_USB_SPI_CONFIG,
289 TransportError::CommunicationError(
290 "Unrecognized reponse to GET_USB_SPI_CONFIG".to_string()
291 )
292 );
293
294 Ok(Self {
295 inner: Rc::clone(inner),
296 interface: *spi_interface,
297 target_enable_cmd: enable_cmd,
298 target_idx: idx,
299 feature_bitmap: resp.feature_bitmap,
300 supports_tpm_poll,
301 max_sizes: MaxSizes {
302 read: resp.max_read_chunk as usize,
303 write: resp.max_write_chunk as usize,
304 },
305 cs_asserted_count: Cell::new(0),
306 })
307 }
308
309 fn select_my_spi_bus(&self) -> Result<()> {
311 if self.inner.selected_spi.get() != self.target_idx {
312 self.inner.selected_spi.set(self.target_idx);
313 self.inner.usb_device.borrow().write_control(
314 rusb::request_type(Direction::Out, RequestType::Vendor, Recipient::Interface),
315 self.target_enable_cmd,
316 self.target_idx as u16,
317 self.interface.interface as u16,
318 &[],
319 )?;
320 }
321 Ok(())
322 }
323
324 fn transmit(&self, wbuf: &[u8], rbuf_len: usize) -> Result<()> {
326 let mut req = CmdTransferStart::new();
327 req.write_count = wbuf.len() as u16;
328 req.read_count = rbuf_len as u16;
329 let databytes = std::cmp::min(USB_MAX_SIZE - 6, wbuf.len());
330 req.data[0..databytes].clone_from_slice(&wbuf[0..databytes]);
331 self.usb_write_bulk(&req.as_bytes()[0..6 + databytes])?;
332 let mut index = databytes;
333
334 while index < wbuf.len() {
335 let mut req = CmdTransferContinue::new();
336 req.data_index = index as u16;
337 let databytes = std::cmp::min(USB_MAX_SIZE - 4, wbuf.len() - index);
338 req.data[0..databytes].clone_from_slice(&wbuf[index..index + databytes]);
339 self.usb_write_bulk(&req.as_bytes()[0..4 + databytes])?;
340 index += databytes;
341 }
342 Ok(())
343 }
344
345 fn tpm_transmit(&self, wbuf: &[u8], rbuf_len: usize, await_gsc_ready: bool) -> Result<()> {
349 const TPM_HEADER_SIZE: usize = 4;
350 let mut req = CmdEepromTransferStart::new();
351 if rbuf_len == 0 {
352 req.flags |= EEPROM_FLAGS_WRITE;
353 req.count = (wbuf.len() - TPM_HEADER_SIZE) as u16;
354 ensure!(
355 wbuf.len() > TPM_HEADER_SIZE,
356 SpiError::InvalidDataLength(wbuf.len())
357 );
358 } else {
359 req.count = rbuf_len as u16;
360 ensure!(
361 wbuf.len() == TPM_HEADER_SIZE,
362 SpiError::InvalidDataLength(wbuf.len())
363 );
364 }
365
366 req.flags |= (TPM_HEADER_SIZE as u32) << EEPROM_FLAGS_ADDR_LEN_POS;
367 req.flags |= EEPROM_FLAGS_TPM;
368 if await_gsc_ready {
369 req.flags |= EEPROM_FLAGS_GSC_READY;
370 }
371
372 let data_start_offset = 0;
373 let databytes = std::cmp::min(USB_MAX_SIZE - 8 - data_start_offset, wbuf.len());
375 req.data[data_start_offset..data_start_offset + databytes]
376 .clone_from_slice(&wbuf[0..databytes]);
377 self.usb_write_bulk(&req.as_bytes()[0..8 + data_start_offset + databytes])?;
378 let mut index = databytes;
379
380 while index < wbuf.len() {
381 let mut req = CmdTransferContinue::new();
382 req.data_index = index as u16;
383 let databytes = std::cmp::min(USB_MAX_SIZE - 4, wbuf.len() - index);
384 req.data[0..databytes].clone_from_slice(&wbuf[index..index + databytes]);
385 self.usb_write_bulk(&req.as_bytes()[0..4 + databytes])?;
386 index += databytes;
387 }
388 Ok(())
389 }
390
391 fn receive(&self, rbuf: &mut [u8]) -> Result<()> {
393 let mut resp = RspTransferStart::new();
394 let bytecount = self.usb_read_bulk_timeout(resp.as_mut_bytes(), TRANSFER_START_TIMEOUT)?;
395 ensure!(
396 bytecount >= 4,
397 TransportError::CommunicationError("Short reponse to TRANSFER_START".to_string())
398 );
399 ensure!(
400 resp.packet_id == USB_SPI_PKT_ID_RSP_TRANSFER_START,
401 TransportError::CommunicationError(format!(
402 "Unrecognized reponse to TRANSFER_START: {}",
403 resp.packet_id
404 ))
405 );
406 ensure!(
407 resp.status_code == STATUS_SUCCESS,
408 TransportError::CommunicationError(format!(
409 "SPI error: {}",
410 status_code_description(resp.status_code)
411 ))
412 );
413 let databytes = bytecount - 4;
414 rbuf[0..databytes].clone_from_slice(&resp.data[0..databytes]);
415 let mut index = databytes;
416 while index < rbuf.len() {
417 let mut resp = RspTransferContinue::new();
418 let bytecount = self.usb_read_bulk(resp.as_mut_bytes())?;
419 ensure!(
420 bytecount > 4,
421 TransportError::CommunicationError(
422 "Short reponse to TRANSFER_CONTINUE".to_string()
423 )
424 );
425 ensure!(
426 resp.packet_id == USB_SPI_PKT_ID_RSP_TRANSFER_CONTINUE,
427 TransportError::CommunicationError(format!(
428 "Unrecognized reponse to TRANSFER_CONTINUE: {}",
429 resp.packet_id
430 ))
431 );
432 ensure!(
433 resp.data_index == index as u16,
434 TransportError::CommunicationError(
435 "Unexpected byte index in reponse to TRANSFER_START".to_string()
436 )
437 );
438 let databytes = bytecount - 4;
439 rbuf[index..index + databytes].clone_from_slice(&resp.data[0..databytes]);
440 index += databytes;
441 }
442 Ok(())
443 }
444
445 fn receive_first_streaming(&self) -> Result<()> {
446 let mut resp = RspTransferStart::new();
447 let bytecount = self.usb_read_bulk(resp.as_mut_bytes())?;
448 ensure!(
449 bytecount >= 4,
450 TransportError::CommunicationError("Short reponse to TRANSFER_START".to_string())
451 );
452 ensure!(
453 resp.packet_id == USB_SPI_PKT_ID_RSP_TRANSFER_START,
454 TransportError::CommunicationError(format!(
455 "Unrecognized reponse to TRANSFER_START: {}",
456 resp.packet_id
457 ))
458 );
459 ensure!(
460 resp.status_code == STATUS_STREAMING_FIRST_SUCCESS,
461 TransportError::CommunicationError(format!(
462 "SPI error: {}, expected streaming response",
463 status_code_description(resp.status_code)
464 ))
465 );
466 Ok(())
467 }
468
469 fn verify_width(&self, requested_width: eeprom::DataWidth) -> Result<()> {
470 match requested_width {
471 eeprom::DataWidth::Single => (),
472 eeprom::DataWidth::Dual => ensure!(
473 self.feature_bitmap & FEATURE_BIT_EEPROM_DUAL != 0,
474 SpiError::InvalidDataWidth(requested_width)
475 ),
476 eeprom::DataWidth::Quad => ensure!(
477 self.feature_bitmap & FEATURE_BIT_EEPROM_QUAD != 0,
478 SpiError::InvalidDataWidth(requested_width)
479 ),
480 eeprom::DataWidth::Octo => ensure!(
481 self.feature_bitmap & FEATURE_BIT_EEPROM_OCTO != 0,
482 SpiError::InvalidDataWidth(requested_width)
483 ),
484 }
485 Ok(())
486 }
487
488 fn eeprom_transmit<'a>(
490 &self,
491 write_enable: Option<&eeprom::Cmd>,
492 cmd: &eeprom::Cmd,
493 wbuf: &[u8],
494 rbuf: &'a mut [u8],
495 wait_for_busy_clear: bool,
496 stream_state: StreamState,
497 ) -> Result<StreamState<'a>> {
498 let double_buffer = self.feature_bitmap & FEATURE_BIT_EEPROM_DOUBLE_BUFFER != 0;
499
500 self.verify_width(cmd.get_width())?;
501
502 let mut req = CmdEepromTransferStart::new();
503 let mut idx = 0;
504 if rbuf.is_empty() {
505 req.flags |= EEPROM_FLAGS_WRITE;
506 req.count = wbuf.len() as u16;
507 } else {
508 req.count = rbuf.len() as u16;
509 }
510
511 req.flags |= match cmd.get_switch() {
512 eeprom::Switch::Mode111 => EEPROM_FLAGS_MODE_111,
513 eeprom::Switch::Mode11N => EEPROM_FLAGS_MODE_11N,
514 eeprom::Switch::Mode1NN => EEPROM_FLAGS_MODE_1NN,
515 eeprom::Switch::ModeNNN => EEPROM_FLAGS_MODE_NNN,
516 };
517 req.flags |= match cmd.get_width() {
518 eeprom::DataWidth::Single => EEPROM_FLAGS_WIDTH_1WIRE,
519 eeprom::DataWidth::Dual => EEPROM_FLAGS_WIDTH_2WIRE,
520 eeprom::DataWidth::Quad => EEPROM_FLAGS_WIDTH_4WIRE,
521 eeprom::DataWidth::Octo => EEPROM_FLAGS_WIDTH_8WIRE,
522 };
523 if cmd.get_double_transfer_rate() {
524 ensure!(
525 self.feature_bitmap & FEATURE_BIT_EEPROM_DTR != 0,
526 SpiError::InvalidDoubleTransferRate()
527 );
528 req.flags |= EEPROM_FLAGS_DTR;
529 }
530
531 req.flags |= (cmd.get_opcode_len() as u32) << EEPROM_FLAGS_OPCODE_LEN_POS;
533
534 if double_buffer {
535 req.flags |= EEPROM_FLAGS_DOUBLE_BUFFER;
536 }
537 if let Some(pre_cmd) = write_enable {
538 req.flags |= EEPROM_FLAGS_WRITE_ENABLE;
539 let opcode_bytes = pre_cmd.get_opcode();
540 if opcode_bytes.len() != 1 {
541 panic!("Illegal write enable sequence");
542 }
543 req.data[idx..idx + opcode_bytes.len()].clone_from_slice(opcode_bytes);
544 idx += opcode_bytes.len();
545 }
546 if wait_for_busy_clear {
547 req.flags |= EEPROM_FLAGS_POLL_BUSY;
548 }
549 let opcode_bytes = cmd.get_opcode();
550 let address_bytes =
551 &cmd.get_address().to_be_bytes()[(4 - cmd.get_address_len()) as usize..];
552
553 req.data[idx..idx + opcode_bytes.len()].clone_from_slice(opcode_bytes);
554 idx += opcode_bytes.len();
555 let mut addr_len = cmd.get_address_len();
556 req.data[idx..idx + address_bytes.len()].clone_from_slice(address_bytes);
557 idx += address_bytes.len();
558 if cmd.get_switch() == eeprom::Switch::Mode111
559 && cmd.get_dummy_cycles().is_multiple_of(8)
560 && addr_len + cmd.get_dummy_cycles() / 8 <= 7
561 {
562 addr_len += cmd.get_dummy_cycles() / 8;
566 for _ in 0..cmd.get_dummy_cycles() / 8 {
567 req.data[idx] = 0x00;
568 idx += 1;
569 }
570 } else if cmd.get_dummy_cycles() < 32 {
571 req.flags |= (cmd.get_dummy_cycles() as u32) << EEPROM_FLAGS_DUMMY_CYCLES_POS
572 } else {
573 bail!(SpiError::InvalidDummyCycles(cmd.get_dummy_cycles()));
574 }
575 req.flags |= (addr_len as u32) << EEPROM_FLAGS_ADDR_LEN_POS;
576
577 let data_start_offset = idx;
578 let databytes = std::cmp::min(USB_MAX_SIZE - 8 - data_start_offset, wbuf.len());
580 req.data[data_start_offset..data_start_offset + databytes]
581 .clone_from_slice(&wbuf[0..databytes]);
582 self.usb_write_bulk(&req.as_bytes()[0..8 + data_start_offset + databytes])?;
583 let mut index = databytes;
584
585 while index < wbuf.len() {
586 let mut req = CmdTransferContinue::new();
587 req.data_index = index as u16;
588 let databytes = std::cmp::min(USB_MAX_SIZE - 4, wbuf.len() - index);
589 req.data[0..databytes].clone_from_slice(&wbuf[index..index + databytes]);
590 self.usb_write_bulk(&req.as_bytes()[0..4 + databytes])?;
591 index += databytes;
592 }
593
594 let next_stream_state = if rbuf.is_empty() {
595 StreamState::PendingWrite
596 } else {
597 StreamState::PendingRead(rbuf)
598 };
599 if double_buffer {
600 self.receive_streamed_data(stream_state)?;
601 Ok(next_stream_state)
602 } else {
603 self.receive_streamed_data(next_stream_state)?;
604 Ok(StreamState::NoPending)
605 }
606 }
607
608 fn receive_streamed_data(&self, stream_state: StreamState) -> Result<()> {
609 match stream_state {
610 StreamState::NoPending => self.receive_first_streaming(),
611 StreamState::PendingWrite => self.receive(&mut []),
612 StreamState::PendingRead(rbuf) => self.receive(rbuf),
613 }
614 }
615
616 fn eeprom_transmit_get_last_streamed_data(&self) -> Result<()> {
617 let mut req = CmdEepromTransferStart::new();
618 req.count = 0;
619 req.flags = EEPROM_FLAGS_DOUBLE_BUFFER;
620 self.usb_write_bulk(&req.as_bytes()[0..8])
621 }
622
623 fn get_last_streamed_data(&self, stream_state: StreamState) -> Result<()> {
624 match stream_state {
625 StreamState::NoPending => Ok(()),
626 StreamState::PendingWrite => {
627 self.eeprom_transmit_get_last_streamed_data()?;
628 self.receive(&mut [])
629 }
630 StreamState::PendingRead(rbuf) => {
631 self.eeprom_transmit_get_last_streamed_data()?;
632 self.receive(rbuf)
633 }
634 }
635 }
636
637 fn do_assert_cs(&self, assert: bool) -> Result<()> {
639 let mut count = self.cs_asserted_count.get();
640 if assert {
641 if count == 0 {
642 self._do_assert_cs(assert)?;
643 }
644 count += 1;
645 } else {
646 if count == 1 {
647 self._do_assert_cs(assert)?;
648 }
649 count -= 1;
650 }
651 self.cs_asserted_count.set(count);
652 Ok(())
653 }
654
655 fn _do_assert_cs(&self, assert: bool) -> Result<()> {
656 let req = CmdChipSelect::new(assert);
657 self.usb_write_bulk(req.as_bytes())?;
658
659 let mut resp = RspChipSelect::new();
660 let bytecount = self.usb_read_bulk(resp.as_mut_bytes())?;
661 ensure!(
662 bytecount >= 4,
663 TransportError::CommunicationError("Unrecognized reponse to CHIP_SELECT".to_string())
664 );
665 ensure!(
666 resp.packet_id == USB_SPI_PKT_ID_RSP_CHIP_SELECT,
667 TransportError::CommunicationError("Unrecognized reponse to CHIP_SELECT".to_string())
668 );
669 ensure!(
670 resp.status_code == STATUS_SUCCESS,
671 TransportError::CommunicationError(format!("SPI error: {}", resp.status_code))
672 );
673 Ok(())
674 }
675
676 fn usb_write_bulk(&self, buf: &[u8]) -> Result<()> {
678 self.inner
679 .usb_device
680 .borrow()
681 .write_bulk(self.interface.out_endpoint, buf)?;
682 Ok(())
683 }
684
685 fn usb_read_bulk(&self, buf: &mut [u8]) -> Result<usize> {
687 self.inner
688 .usb_device
689 .borrow()
690 .read_bulk(self.interface.in_endpoint, buf)
691 }
692
693 fn usb_read_bulk_timeout(&self, buf: &mut [u8], timeout: Duration) -> Result<usize> {
695 self.inner
696 .usb_device
697 .borrow()
698 .read_bulk_timeout(self.interface.in_endpoint, buf, timeout)
699 }
700}
701
702impl Target for HyperdebugSpiTarget {
703 fn get_transfer_mode(&self) -> Result<TransferMode> {
704 Ok(TransferMode::Mode0)
705 }
706 fn set_transfer_mode(&self, _mode: TransferMode) -> Result<()> {
707 todo!();
708 }
709
710 fn get_bits_per_word(&self) -> Result<u32> {
711 Ok(8)
712 }
713 fn set_bits_per_word(&self, bits_per_word: u32) -> Result<()> {
714 match bits_per_word {
715 8 => Ok(()),
716 _ => Err(SpiError::InvalidWordSize(bits_per_word).into()),
717 }
718 }
719
720 fn get_max_speed(&self) -> Result<u32> {
721 let mut buf = String::new();
722 let captures = self.inner.cmd_one_line_output_match(
723 &format!("spi info {}", &self.target_idx),
724 &super::SPI_REGEX,
725 &mut buf,
726 )?;
727 Ok(captures.get(3).unwrap().as_str().parse().unwrap())
728 }
729 fn set_max_speed(&self, frequency: u32) -> Result<()> {
730 self.inner
731 .cmd_no_output(&format!("spi set speed {} {}", &self.target_idx, frequency))
732 }
733
734 fn supports_bidirectional_transfer(&self) -> Result<bool> {
735 Ok((self.feature_bitmap & FEATURE_BIT_FULL_DUPLEX) != 0)
736 }
737
738 fn supports_tpm_poll(&self) -> Result<bool> {
739 Ok(self.supports_tpm_poll)
740 }
741
742 fn set_pins(
743 &self,
744 serial_clock: Option<&Rc<dyn GpioPin>>,
745 host_out_device_in: Option<&Rc<dyn GpioPin>>,
746 host_in_device_out: Option<&Rc<dyn GpioPin>>,
747 chip_select: Option<&Rc<dyn GpioPin>>,
748 gsc_ready: Option<&Rc<dyn GpioPin>>,
749 ) -> Result<()> {
750 if serial_clock.is_some() || host_out_device_in.is_some() || host_in_device_out.is_some() {
751 bail!(SpiError::InvalidPin);
752 }
753 if let Some(pin) = chip_select {
754 self.inner.cmd_no_output(&format!(
755 "spi set cs {} {}",
756 &self.target_idx,
757 pin.get_internal_pin_name().ok_or(SpiError::InvalidPin)?
758 ))?;
759 }
760 if let Some(pin) = gsc_ready {
761 self.inner.cmd_no_output(&format!(
762 "spi set ready {} {}",
763 &self.target_idx,
764 pin.get_internal_pin_name().ok_or(SpiError::InvalidPin)?
765 ))?;
766 }
767 Ok(())
768 }
769
770 fn get_max_transfer_count(&self) -> Result<usize> {
771 Ok(usize::MAX)
774 }
775
776 fn get_max_transfer_sizes(&self) -> Result<MaxSizes> {
777 Ok(self.max_sizes)
778 }
779
780 fn get_flashrom_programmer(&self) -> Result<String> {
781 Ok(format!(
782 "raiden_debug_spi:serial={},target={}",
783 self.inner.usb_device.borrow().get_serial_number(),
784 self.target_idx
785 ))
786 }
787
788 fn run_transaction(&self, transaction: &mut [Transfer]) -> Result<()> {
789 let mut idx: usize = 0;
790 self.select_my_spi_bus()?;
791
792 match transaction {
796 [Transfer::Write(wbuf), Transfer::Read(rbuf)] => {
797 ensure!(
801 wbuf.len() <= self.max_sizes.write,
802 SpiError::InvalidDataLength(wbuf.len())
803 );
804 ensure!(
805 rbuf.len() <= self.max_sizes.read,
806 SpiError::InvalidDataLength(rbuf.len())
807 );
808 self.transmit(wbuf, rbuf.len())?;
809 self.receive(rbuf)?;
810 return Ok(());
811 }
812 [
813 Transfer::Write(wbuf),
814 Transfer::TpmPoll,
815 Transfer::Read(rbuf),
816 Transfer::GscReady,
817 ] => {
818 ensure!(
821 wbuf.len() <= self.max_sizes.write,
822 SpiError::InvalidDataLength(wbuf.len())
823 );
824 ensure!(
825 rbuf.len() <= self.max_sizes.read,
826 SpiError::InvalidDataLength(rbuf.len())
827 );
828 self.tpm_transmit(wbuf, rbuf.len(), true)?;
829 self.receive(rbuf)?;
830 return Ok(());
831 }
832 [
833 Transfer::Write(wbuf),
834 Transfer::TpmPoll,
835 Transfer::Read(rbuf),
836 ] => {
837 ensure!(
840 wbuf.len() <= self.max_sizes.write,
841 SpiError::InvalidDataLength(wbuf.len())
842 );
843 ensure!(
844 rbuf.len() <= self.max_sizes.read,
845 SpiError::InvalidDataLength(rbuf.len())
846 );
847 self.tpm_transmit(wbuf, rbuf.len(), false)?;
848 self.receive(rbuf)?;
849 return Ok(());
850 }
851 [Transfer::Write(wbuf)] => {
852 ensure!(
853 wbuf.len() <= self.max_sizes.write,
854 SpiError::InvalidDataLength(wbuf.len())
855 );
856 self.transmit(wbuf, 0)?;
857 self.receive(&mut [])?;
858 return Ok(());
859 }
860 [Transfer::Write(wbuf1), Transfer::Write(wbuf2)] => {
861 if wbuf1.len() + wbuf2.len() <= self.max_sizes.write {
862 let mut combined_buf = vec![0u8; wbuf1.len() + wbuf2.len()];
863 combined_buf[..wbuf1.len()].clone_from_slice(wbuf1);
864 combined_buf[wbuf1.len()..].clone_from_slice(wbuf2);
865 self.transmit(&combined_buf, 0)?;
866 self.receive(&mut [])?;
867 return Ok(());
868 }
869 }
870 [
871 Transfer::Write(wbuf1),
872 Transfer::TpmPoll,
873 Transfer::Write(wbuf2),
874 Transfer::GscReady,
875 ] => {
876 ensure!(
879 wbuf1.len() + wbuf2.len() <= self.max_sizes.write,
880 SpiError::InvalidDataLength(wbuf1.len() + wbuf2.len())
881 );
882 let mut combined_buf = vec![0u8; wbuf1.len() + wbuf2.len()];
883 combined_buf[..wbuf1.len()].clone_from_slice(wbuf1);
884 combined_buf[wbuf1.len()..].clone_from_slice(wbuf2);
885 self.tpm_transmit(&combined_buf, 0, true)?;
886 self.receive(&mut [])?;
887 return Ok(());
888 }
889 [
890 Transfer::Write(wbuf1),
891 Transfer::TpmPoll,
892 Transfer::Write(wbuf2),
893 ] => {
894 ensure!(
897 wbuf1.len() + wbuf2.len() <= self.max_sizes.write,
898 SpiError::InvalidDataLength(wbuf1.len() + wbuf2.len())
899 );
900 let mut combined_buf = vec![0u8; wbuf1.len() + wbuf2.len()];
901 combined_buf[..wbuf1.len()].clone_from_slice(wbuf1);
902 combined_buf[wbuf1.len()..].clone_from_slice(wbuf2);
903 self.tpm_transmit(&combined_buf, 0, false)?;
904 self.receive(&mut [])?;
905 return Ok(());
906 }
907 [Transfer::Read(rbuf)] => {
908 ensure!(
909 rbuf.len() <= self.max_sizes.read,
910 SpiError::InvalidDataLength(rbuf.len())
911 );
912 self.transmit(&[], rbuf.len())?;
913 self.receive(rbuf)?;
914 return Ok(());
915 }
916 _ => (),
917 }
918
919 self.do_assert_cs(true)?;
923 while idx < transaction.len() {
924 match &mut transaction[idx..] {
925 [Transfer::Write(wbuf), Transfer::Read(rbuf), ..] => {
926 ensure!(
927 wbuf.len() <= self.max_sizes.write,
928 SpiError::InvalidDataLength(wbuf.len())
929 );
930 ensure!(
931 rbuf.len() <= self.max_sizes.read,
932 SpiError::InvalidDataLength(rbuf.len())
933 );
934 self.transmit(wbuf, rbuf.len())?;
935 self.receive(rbuf)?;
936 idx += 2;
938 continue;
939 }
940 [Transfer::Write(wbuf), ..] => {
941 ensure!(
942 wbuf.len() <= self.max_sizes.write,
943 SpiError::InvalidDataLength(wbuf.len())
944 );
945 self.transmit(wbuf, 0)?;
946 self.receive(&mut [])?;
947 }
948 [Transfer::Read(rbuf), ..] => {
949 ensure!(
950 rbuf.len() <= self.max_sizes.read,
951 SpiError::InvalidDataLength(rbuf.len())
952 );
953 self.transmit(&[], rbuf.len())?;
954 self.receive(rbuf)?;
955 }
956 [Transfer::Both(wbuf, rbuf), ..] => {
957 ensure!(
958 (self.feature_bitmap & FEATURE_BIT_FULL_DUPLEX) != 0,
959 TransportError::CommunicationError(
960 "HyperDebug does not support bidirectional SPI".to_string()
961 )
962 );
963 ensure!(
964 rbuf.len() == wbuf.len(),
965 SpiError::MismatchedDataLength(wbuf.len(), rbuf.len())
966 );
967 ensure!(
968 wbuf.len() <= self.max_sizes.read && wbuf.len() <= self.max_sizes.write,
969 SpiError::InvalidDataLength(wbuf.len())
970 );
971 self.transmit(wbuf, FULL_DUPLEX)?;
972 self.receive(rbuf)?;
973 }
974 [Transfer::TpmPoll, ..] => bail!(TransportError::UnsupportedOperation),
975 [Transfer::GscReady, ..] => bail!(TransportError::UnsupportedOperation),
976 [] => (),
977 }
978 idx += 1;
979 }
980 self.do_assert_cs(false)?;
981 Ok(())
982 }
983
984 fn run_eeprom_transactions(&self, mut transactions: &mut [eeprom::Transaction]) -> Result<()> {
985 if self.feature_bitmap & FEATURE_BIT_EEPROM == 0 {
986 return eeprom::default_run_eeprom_transactions(self, transactions);
989 }
990 self.select_my_spi_bus()?;
991 let mut stream_state = StreamState::NoPending;
992 loop {
993 match transactions {
994 [
995 eeprom::Transaction::Command(pre_cmd),
996 eeprom::Transaction::Write(cmd, wbuf),
997 eeprom::Transaction::WaitForBusyClear,
998 rest @ ..,
999 ] => {
1000 if pre_cmd.get_opcode().len() == 1 {
1001 stream_state = self.eeprom_transmit(
1002 Some(pre_cmd), cmd,
1004 wbuf,
1005 &mut [],
1006 true, stream_state,
1008 )?;
1009 } else {
1010 stream_state =
1011 self.eeprom_transmit(None, pre_cmd, &[], &mut [], false, stream_state)?;
1012 stream_state = self.eeprom_transmit(
1013 None, cmd,
1015 wbuf,
1016 &mut [],
1017 true, stream_state,
1019 )?;
1020 }
1021 transactions = rest;
1022 }
1023 [eeprom::Transaction::Command(cmd), rest @ ..] => {
1024 stream_state =
1025 self.eeprom_transmit(None, cmd, &[], &mut [], false, stream_state)?;
1026 transactions = rest;
1027 }
1028 [eeprom::Transaction::Read(cmd, rbuf), rest @ ..] => {
1029 stream_state =
1030 self.eeprom_transmit(None, cmd, &[], rbuf, false, stream_state)?;
1031 transactions = rest;
1032 }
1033 [
1034 eeprom::Transaction::Write(cmd, wbuf),
1035 eeprom::Transaction::WaitForBusyClear,
1036 rest @ ..,
1037 ] => {
1038 stream_state = self.eeprom_transmit(
1039 None, cmd,
1041 wbuf,
1042 &mut [],
1043 true, stream_state,
1045 )?;
1046 transactions = rest;
1047 }
1048 [eeprom::Transaction::Write(cmd, wbuf), rest @ ..] => {
1049 stream_state =
1050 self.eeprom_transmit(None, cmd, wbuf, &mut [], false, stream_state)?;
1051 transactions = rest;
1052 }
1053 [eeprom::Transaction::WaitForBusyClear, rest @ ..] => {
1054 self.get_last_streamed_data(stream_state)?;
1055 let mut status = eeprom::STATUS_WIP;
1056 while status & eeprom::STATUS_WIP != 0 {
1057 self.run_transaction(&mut [
1058 Transfer::Write(&[eeprom::READ_STATUS]),
1059 Transfer::Read(std::slice::from_mut(&mut status)),
1060 ])?;
1061 }
1062 stream_state = StreamState::NoPending;
1063 transactions = rest;
1064 }
1065 [] => {
1066 return self.get_last_streamed_data(stream_state);
1067 }
1068 }
1069 }
1070 }
1071
1072 fn assert_cs(self: Rc<Self>) -> Result<AssertChipSelect> {
1073 self.do_assert_cs(true)?;
1074 Ok(AssertChipSelect::new(self))
1075 }
1076}
1077
1078impl TargetChipDeassert for HyperdebugSpiTarget {
1079 fn deassert_cs(&self) {
1080 self.do_assert_cs(false)
1083 .expect("Error while deasserting CS");
1084 }
1085}