Monday 26 November 2018

microcontroller - 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.


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.


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 ###


Actually a requirement of my (shell)code would be that it needs to be really tiny. I found this nifty trick on how to dump firmware by blinking the LEDs.


However I'm struggling to receive correct values with Saleae Logic Analyzer.


Basically what I'm doing is:



  1. Setup the GPIO pin directions to output

  2. Blink LED1 (pin 1.1) with a clock (SPI serial clock)

  3. Blink LED2 (pin 1.0) with data bits (SPI MOSI)


  4. Sniff pins with a logic analyzer


Here's my C code:


#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 ###


Finally sorted it out. 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++;
}
}



No comments:

Post a Comment

arduino - Can I use TI&#39;s cc2541 BLE as micro controller to perform operations/ processing instead of ATmega328P AU to save cost?

I am using arduino pro mini (which contains Atmega328p AU ) along with cc2541(HM-10) to process and transfer data over BLE to smartphone. I...