Following the Instruction Stream

“Which way for the TriMedia instruction stream?”

Lifting the veil on the 2Wire boot ROM reveals a curious way of storing code.

Normally object code is stored in sequential byte order. Whether in main memory or disk file, consecutive CPU instructions are usually stored in consecutive locations.

Not so for the Stage 1 bootloader of the TriMedia.  This core utilises a code storage method that could be dubbed  Bit Striping.

The method is best illustrated by way of a diagram.

The code is broken first into blocks of 32 bytes.  The instruction stream starts at bit 0 of byte 0, and proceeds through bit 0 of byte 1, then bit 0 of byte 2, and so on until bit 0 of byte 31.

The stream then moves to bit 1 of byte 0, and then to bit 1 of byte 1, then bit 1 of byte 2, and so on to bit 1 of byte 31.  Then to bit 2 of byte 0 and through bit 2 of byte 1, bit 2 of byte 2, etcetera, to bit 2 of byte 31. Using this scheme, the stream weaves it way around the whole block until hitting bit 7 of byte 31.

The stream then jumps to bit 0 of byte 32 in the second code block.  And it carries on this same zig-zag path through subsequent 32-byte blocks.

A singularly peculiar scheme, you could say.

In the example below, the (little-endian bit order) instruction stream begins:

11111011 11110000 00101000 00000001 00000000 00000001 ….

Converted to big-endian bit order hexadecimal notation, the beginning of the instruction stream reads:

DF 0F 14 80 00 80 ….

The 'Bit Striping' method of code storage in the TriMedia

Like much else with the TriMedia, this strange method of code storage is completely undocumented.

However, now the scheme is understood, the L1 bootloader code of the 2Wire can be transposed to sequential bit- and byte- order, and passed through our Open Source disassembler [1]:

$ dd if=2701hgv-c_bootrom.bin skip=913 count=64 bs=1 | xxd
0000000: c281 c181 c182 d1b5 c181 0200 0210 0c00  ................
0000010: 2000 0000 0020 2050 2222 0222 20a0 7484   ....  P""." .t.
0000020: 1c3c 1838 1030 1832 1434 0505 0505 0605  .<.8.0.2.4......
0000030: 1615 1311 1318 1112 1612 0002 0203 0a06  ................

$ ./tm32dis -mi 2701hgv-c_bootrom.bin 913 2508
Read in 4096 bytes from file '2701hgv-c_bootrom.bin'
Skipping 913 (0x391) bytes
Memory image transposed from bit-striped to sequential:
0000: de 03 00 00 21 14 00 0f 80 40 00 c0 00 40 00 00
0010: c0 20 80 40 80 00 61 7b 55 01 80 40 ff 03 00 a0
0020: 00 bc 5e 20 80 40 95 fb 03 ff 03 81 4f 00 20 40
0030: ff 03 ff 03 aa 02 00 00 00 00 00 00 00 00 00 00
0040: ff ef 00 40 e0 81 42 20 00 40 e0 f0 00 40 e0 00
[..snipped..]
Disassembling 2508 (0x9cc) bytes

disassembly
(* instruction 0   : 224 bits (28 bytes) long *)
(* offset          : 0x00000000 *)
(* bytes           : de 03 00 00 21 14 00 0f 80 40 00 c0 00 40 00 00 c0 20 80 40 80 00 61 7b 55 01 80 40 *)
(* format bytes    : 0xde03 & 0xff03 = 0xde03, format in little endian bit order: 01 11 10 11 11  *)
IF r1   iimm(0x40004000) -> r4,             (* 42 bits: 0x10200210000 *)
IF r1   iimm(0xa00) -> r60,                 (* 42 bits: 0x2000f0014 *)
IF r1   isubi(1) r0 -> r61,                 (* 42 bits: 0x1ed84004080 *)
IF r1   iclr,                               (* 42 bits: 0x557004000 *)
IF r1   iimm(0x40004000) -> r3;             (* 42 bits: 0x1020020c000 *)

(* instruction 1   : 88 bits (11 bytes) long *)
(* offset          : 0x0000001c *)
(* bytes           : ff 03 00 a0 00 bc 5e 20 80 40 95 *)
(* format bytes    : 0xff03 & 0xff03 = 0xff03, format in little endian bit order: 11 11 11 11 11  *)
IF r1   iimm(0x40000040) -> r2,             (* 42 bits: 0x1020000a000 *)
IF r1   nop,                                (*  0 bits *)
IF r1   writepcsw r60 r61,                  (* 34 bits: 0x254205ebc *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop;                                (*  0 bits *)

(* instruction 2   : 16 bits (2 bytes) long *)
(* offset          : 0x00000027 *)
(* bytes           : fb 03 *)
(* format bytes    : 0xfb03 & 0xff03 = 0xfb03, format in little endian bit order: 11 01 11 11 11  *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop;                                (*  0 bits *)

(* instruction 3   : 56 bits (7 bytes) long *)
(* offset          : 0x00000029 *)
(* bytes           : ff 03 81 4f 00 20 40 *)
(* format bytes    : 0xff03 & 0xff03 = 0xff03, format in little endian bit order: 11 11 11 11 11  *)
IF r1   nop,                                (*  0 bits *)
IF r1   ijmpi(0x4000009f),                  (* 42 bits: 0x10080004f81 *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop;                                (*  0 bits *)

(* instruction 4   : 16 bits (2 bytes) long *)
(* offset          : 0x00000030 *)
(* bytes           : ff 03 *)
(* format bytes    : 0xff03 & 0xff03 = 0xff03, format in little endian bit order: 11 11 11 11 11  *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop;                                (*  0 bits *)

(* instruction 5   : 16 bits (2 bytes) long *)
(* offset          : 0x00000032 *)
(* bytes           : ff 03 *)
(* format bytes    : 0xff03 & 0xff03 = 0xff03, format in little endian bit order: 11 11 11 11 11  *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop;                                (*  0 bits *)

(* instruction 6   : 16 bits (2 bytes) long *)
(* offset          : 0x00000034 *)
(* bytes           : aa 02 *)
(* format bytes    : 0xaa02 & 0xff03 = 0xaa02, format in little endian bit order: 01 01 01 01 01  *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop,                                (*  0 bits *)
IF r1   nop;                                (*  0 bits *)
[..snipped..]

P.S. There’s also a clever little Easter Egg hidden by 2Wire/TriMedia. Using the bit striping scheme as a by-product, a message has been encoded in the chaff bytes at the tail of the L1 bootloader :-)

P.P.S. Maybe it’s not an Easter Egg at all..  Is it a protection mechanism?

[1]
http://hackingbtbusinesshub.wordpress.com/2011/11/10/an-open-source-trimedia-tm32-disassembler/

About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Connecting to %s