0
\$\begingroup\$

I dumped the contents of a NAND flash chip, and do not understand why would each of the words in the image be in the reverse order. This CFI-compatible flash is connected to a TI AR7 SoC that integrates a MIPS 4K core.

I am dumping the flash using OpenOCD connected to the board's EJTAG port. I have done this before with very similar boards with AR7s and have never seen this.

Just to clarify, I am not speaking about endianness, every single 4 byte sequence seems to be reversed, including strings, ie: 'CTAWGODHRAW GNIN' instead of 'WATCHDOG WARNING'. ('0123' becomes '3210')

Are there reasons for the data to be inverted like this? How is the processor able to boot from this data if the flash is, for reading, just mapped at an address?

\$\endgroup\$
  • \$\begingroup\$ It all depends on the Endianness of your devices. \$\endgroup\$ – R Drast May 12 '15 at 13:41
  • \$\begingroup\$ Endianness only affects data that requires more than one byte to be stored, ie: an integer. Endianness does not affect the way strings of (ascii) chars are stored. stackoverflow.com/questions/1568057/… \$\endgroup\$ – istepaniuk May 12 '15 at 13:44
  • \$\begingroup\$ While the answer doesn't really explain it all that well I do agree this will be the underlying issue. I'm not familiar with that toolchain but no doubt OpenOCD is doing 32-bit reads and reversing the byte order somewhere along the line, remembering it doesn't know what is a string and what isn't. \$\endgroup\$ – PeterJ May 12 '15 at 13:52
  • 4
    \$\begingroup\$ Endianness can affect strings if you device stores & retrieves them in blocks larger than 1 char at a time. Its more efficient on a 32-bit device with 32-bit memory access to access 4 bytes in one go. \$\endgroup\$ – brhans May 12 '15 at 13:55
  • 1
    \$\begingroup\$ /Shrug. Endianness does indeed affect storage, even of strings, since almost nothing is written on a bytewise basis. The program doesn't need to know anything at all, all the conversion is handled in driver to the device. Reading it out in a raw fashion ignores all of the optimizations a device/driver implement. The Original Question sample confirms both a swap at the 16 bit word level and at the 32 bit level. Ymmv \$\endgroup\$ – R Drast May 12 '15 at 14:35
2
\$\begingroup\$

Short answer:

You are using OpenOCD in LE mode when your CPU runs on BE (or vice-versa).

You have to specify the correct -endian switch for the target command in your OpenOCD configuration.

Longer asnwer:

Where is the endianness mismatch?

Regardless of endianness, the data is being read from the flash one chip_bus_width bits at a time, in this case 16bits. The order and width (apparently 32) in which the nibbles are sent serially over the JTAG bus depends on the CPU endianness and OpenOCD has no way (without interference) to guess this if the particular CPU can run in either mode (like MIPS or ARM cores can).

It is the CPU itself that is performing the actual read operation, commanded by the TAP controller. This would not be the case if poking the flash using boundary scan.

For both mdw or dump_image OpenOCD commands, your 4 bytes will be reversed if your OpenOCD has a mismatching endianness (-endian) setting.

Endianness and byte sequences, or strings

As stated in some comments, C strings and byte arrays will always appear in-order when inspecting the memory in 1 by 1 increments, and thus should appear in-order if we dumped that memory into a file. That is part of the ANSI C standard, and set in stone by how pointer arithmetic works:

When an expression that has integral type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integral expression.

Increasing the address by one we always get the next-in-sequence byte (or char in a string), regardless of the endianness. It cannot be said more clear: Endianness does NOT affect how C-Style strings are stored.

Hex dump at address 0x000000e0 of a printf("Hello, world!");:

C object code, compiled for big endian (mips-gcc -EB): 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 00 00 00 |Hello, world!...|

C object code, compiled for little endian (mips-gcc -EL): 48 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 00 00 00 |Hello, world!...|

Integers (and bigger numbers) in the other hand, are stored in the byte order of the particular endianness, and examining an integer number in RAM or in the flash (or in a dump file, etc.) byte by byte, will yield different sequences for BE or LE, very loosely related with the actual issue.

\$\endgroup\$
1
\$\begingroup\$

It's an endian issue. The memory is working fine. It's simply to do with the software reading out 32 bit words and the mapping of the individual chars (single bytes) to their position in the 32 bit word.

I was able to predict the output and compare what I predicted to what was actually read.

A 32 bit word stores 4 bytes = 4 single ASCII characters.

Let's take a portion of the original text: WATCHDOG

Take the first 4 characters from left to right: WATC Those 4 can be stored in a 32 bit word. The next 4 can be stored in a 32 bit word: HDOG

Reverse the order of each group: CTAW GODH

Output text: CTAW GODH Which then matches the sequence of letters actually output.

Now, the question is how is the flash memory organised, as bytes, or 32 bit words? And what does the processor read? Does it read bytes and read 4 of them? Or does it read a 32 bits in a single operation?

If you're writing code to manipulate text strings you need to know exactly how they are stored and how the processor reads them.

Produce a table like this:

MemoryAddress......Character position in string

n ......... 4

n+1 ......... 3

n+2 ......... 2

n+3 ......... 1

n+4 ......... 4

n+5 ......... 3

...

In the old days of 8 bit microprocessors and 8 bit wide memory, these issues didn't exist. It's certainly something to understand when dealing with processors of 16 bits and higher and where memory is organised in widths of greater than 8 bits.

\$\endgroup\$
  • \$\begingroup\$ "to manipulate text strings you need to know exactly how they are stored" is simply wrong. Strings are always stored in the same way regardless of endianness, except for encodings that use more than a byte (like UTF-16, UTF-32, etc.). The 'CTAWGODHRAW GNIN' string was manually crafted for this question as an example. \$\endgroup\$ – istepaniuk May 12 '15 at 23:02
0
\$\begingroup\$

This does appear in fact to be an endianness issue. Unfortunately that word (endian) is used to much and creates unnecessary confusion, fear, etc.

For this to work then somewhere there needs to be a byteswap and likely there is if in fact this chip does work. And in that case you would swap everything assuming the flash is at that layer accessed only in 32 bit quantities. (could easily be that the peripheral accesses the flash 8 bits at a time, always does 32 bit reads and the way it shifts in does an endian swap as it passes the data on to the processors bus).

So you should try doing simple reads from the processor side not jtag side to see what you see, if still swapped then it is a mystery how this works. There would need to be hardware or software swapping everything before using/executing.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.