简体   繁体   English

通过单个GPIO引脚转储闪存

[英]Dump Flash Memory through a single GPIO pin

I'm working with Infineon's XMC4500 Relax Kit and I'm trying to extract the firmware through a single GPIO pin. 我正在使用英飞凌的XMC4500 Relax Kit,我试图通过一个GPIO引脚提取固件。

My very naive idea is to dump one bit at a time through the GPIO pin and somehow "sniff" the data with a logic analyzer. 我非常天真的想法是通过GPIO引脚一次转储一位,并用逻辑分析仪以某种方式“嗅探”数据。

Pseudocode: 伪代码:

while(word by word memory copy hasn't finished)
  ...
  register = value;
  temp_value = value AND 0x1;
  pin = temp_value;
  value = value >> 1;
  ...

Am I on the right track? 我是在正确的轨道上吗? Does anybody have a better/nicer idea how to archive this? 有没有人有更好/更好的想法如何存档?

### EDIT ### ### EDIT ###

Actually a requirement of my (shell)code would be that it needs to be really tiny. 实际上我的(shell)代码的要求是它需要非常小。 I found this nifty trick on how to dump firmware by blinking the LEDs. 我发现了这个关于如何通过闪烁LED来转储固件的巧妙技巧。

However I'm struggling to receive correct values with Saleae Logic Analyzer. 但是我很难通过Saleae Logic Analyzer获得正确的数值。

Basically what I'm doing is: 基本上我正在做的是:

  1. Setup the GPIO pin directions to output 设置GPIO引脚方向以输出
  2. Blink LED1 (pin 1.1) with a clock (SPI serial clock) 带时钟的闪烁LED1(引脚1.1)(SPI串行时钟)
  3. Blink LED2 (pin 1.0) with data bits (SPI MOSI) 使用数据位(SPI MOSI)闪烁LED2(引脚1.0)
  4. Sniff pins with a logic analyzer 使用逻辑分析仪嗅探引脚

Here's my C code: 这是我的C代码:

#include "XMC4500.h"

#define DEL 1260

void init() 
{
  // P1.0 output, push pull
  PORT1->IOCR0 = 0x80UL << 0;
  // P1.1 output, push pull
  PORT1->IOCR0 |= 0x80UL << 8;
}

void delay(int i) { 
  while(--i) { 
    asm("nop\n"); 
    asm("nop\n"); 
  } 
}

// Sets a pin to high
// P1.0 = SPI MOSI
// P1.1 = SPI CLOCK
void output_high(int i) {
  // P1.0 high
  if(i == 0) {
    PORT1->OUT |= 0x1UL;  
  }

  // P1.1 high
  if(i == 1) {
    PORT1->OUT |= 0x2UL;
  } 
}

// Sets a pin to low
// P1.0 = SPI MOSI
// P1.1 = SPI CLOCK
void output_low(int i) {
  // P1.0 low
  if(i == 0) {
    PORT1->OUT &= (~0x1UL);
  }

  // P1.1 low
  if(i == 1) {
    PORT1->OUT &= (~0x2UL);
  }
}

// SPI bit banging
void spi_send_byte(unsigned char data)
{
  int i;

  // Send bits 7..0
  for (i = 0; i < 8; i++)
  {
    // Sets P1.1 to low (serial clock)
    output_low(1);

    // Consider leftmost bit
    // Set line high if bit is 1, low if bit is 0
    if (data & 0x80)
      // Sets P1.0 to high (MOSI)
      output_high(0);
    else
      // Sets P1.0 to low (MOSI)
      output_low(0);

    delay(DEL);

    // Sets P1.1 to high (Serial Clock)
    output_high(1);

    // Shift byte left so next bit will be leftmost
    data <<= 1;
  }
}

int main() {
  init();

  while(1) {
    spi_send_byte('t');
    spi_send_byte('e');
    spi_send_byte('s');
    spi_send_byte('t');
  }

  return 0;
}

### 2nd EDIT ### ### 2nd EDIT ###

Dumping flash memory is working fine with the following code: 使用以下代码转储闪存工作正常:

#include "XMC4500.h"

// SPI bit banging
void spi_send_word(uint32_t data)
{
  int i;

  // LSB first, 32 bits per transfer
  for (i = 0; i < 32; i++)
  {
    // set pin 1.1 to low (SPI clock)
    PORT1->OUT &= (~0x2UL);

    // set line high if bit is 1, low if bit is 0
    if (data & 0x1) {
      // set pin 1.0 to high (SPI MOSI)
      PORT1->OUT |= 0x1UL;
    }
    else {
      // set pin 1.0 to low (SPI MOSI)
      PORT1->OUT &= (~0x1UL);   
    }

    // set pin 1.1 to high (SPI clock)
    PORT1->OUT |= 0x2UL;

    data >>= 1;
  }
}

int main() {
  // start dumping at memory address 0x08000000
  unsigned int *p;
  p = (uint32_t *)(0x08000000u);

  // configure pin 1.0 and pin 1.1 as output (push-pull)
  PORT1->IOCR0 = 0x8080UL;

  while(1) {
    spi_send_word(*p);
    p++;
  }
}

The biggest problem with your solution is recovering the timing information - knowing where one word starts and another ends. 解决方案的最大问题是恢复计时信息 - 知道一个单词的起始位置和另一个单词的结束位置。 It would be simpler to output the data on a UART tx pin - the UART adds start and stop bits and manages timing for you, and the output can be read directly via a regular PC serial port. 在UART tx引脚上输出数据会更简单 - UART会为您添加启动和停止位并管理时序,并且可以通过常规PC串行端口直接读取输出。

If you cannot use a UART, emulating a UART by bit-banging the GPIO with UART timing will still allow a conventional serial port to be used to receive the data directly. 如果您不能使用UART,则通过使用UART定时对GPIO进行位冲击来仿真UART仍然允许使用传统串行端口直接接收数据。

An example software UART implementation can be found here . 可以在此处找到示例软件UART实现。 In your case of course you need only the transmit capability. 在您的情况下,您当然只需要传输功能。

That might work decently depending on your requirements. 根据您的要求,这可能会有所体现。 Something to consider will be if there are any timing variations at all while looping through the data such as flash read times varying, cache stuff, etc you will run into a problem figuring out where bytes start and stop. 需要考虑的是,如果在循环读取数据时存在任何时序变化,例如闪存读取时间变化,缓存等等,您将遇到一个问题,找出字节开始和停止的位置。 You might want to take a look at the 1-Wire protocol: 您可能想看看1-Wire协议:

http://en.wikipedia.org/wiki/1-Wire http://en.wikipedia.org/wiki/1-Wire

You don't have to implement it to spec or anything, just take a look at it for an idea. 你不必将它实现到规范或任何东西,只需看看它的想法。 If you implement something like that your logic is just as simple: 如果你实现类似的东西,你的逻辑就是这么简单:

while(word by word memory copy hasn't finished)
  ...
  register = value;
  temp_value = value AND 0x1;
  one_wire_send(temp_value);
  value = value >> 1;
  ...

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM