続フォトフレームHack

以前あきらめたmipsなフォトフレームをまたいじってみました。

[以前にページ](https://qiita.com/yamori813/items/2919b6344e7e27704726)に調べた情報も追記してあります。

このターゲットはmips4Kでmipsとしては後期のアーキテクチャです。またメモリも8Mバイトと結構大きいのも魅力です。

SOCの中にプリプートローダーのROMがあって、そのコードでSPI Flashの先頭の64KをSDRAMの0x80000000から貼り付けて、実行を移している。

おそらくブートローダーもコマンドオペレーションが可能なのではないかと思われますが、入り方がわかりません。

そして、SDRAM上のブートローダーがSPI Flashの中のlzo圧縮されたThreadXをメモリに貼り付けて起動していることがわかりました。

ThreadXはExpress Logic社のクローズドソースのRTOSで2019年にMSに買収されていました。

lzo圧縮は圧縮サイズと圧縮データがいくつか並ぶような構造のようです。このターゲットの場合は一つのブロックだけで圧縮されているようです。lzoのオープンソース(GPL)使ってるような気がします。

lzoはライブラリのlzoとコマンドのlzopにソースに分かれています。しかしlzoの方のexamplesディレクトリの下に簡単な圧縮解凍プログラムのlzopack.cというソースがあります。

このコードを改造してこのブートローダーが使用できる圧縮データを作れるようにしてみました。

https://github.com/yamori813/spmf_hack/blob/main/tools/splzo.c

オリジナルのブートローダーに無限ループのプロクラムを実行されせてみます。

無限ループのコードはこれです。

https://github.com/yamori813/spmf_hack/tree/fa598bc4511a244594b2e1bfe71e473e50091b95/hello

ビルドできたファイルを元のブートローダーとcatしてflashのザイズの2Mにしてflashromでspi flashに焼いてみます。

```
BOOT SPI
.B(128)P(1)D(1)M(0)
..
------------ [SPMF28XX Boot Loader] ------------
1 memProfile.pheapStart=8000D9A0
=========>new buddy system<============
new buddy system start_addr=0xA06FF000, size=0x100000
IOTRAp=200

[loadLzoFW] run,807FF000
[loadLzoFW] run,807FF000
[loadLzoFW] run,807FF000
[loadLzoFW] run,807FF000
[loadLzoFW] run,807FF000
[loadLzoFW] run,807FF000
[serialFlashDetect] run,dmaMode=0
. buf=A06FF010,size=256
EXEC round=16
   0 | 53;50;49;46;20;52;53;56;EF;BE;00;00;F1;0E;0F;F1;
   1 | 00;00;00;00;7F;00;00;00;00;00;00;00;00;00;00;00;
   2 | 00;00;00;00;00;05;00;07;7F;00;00;00;19;00;00;00;
   3 | 71;02;00;00;00;00;00;00;00;00;00;00;00;00;00;00;
   4 | 8C;20;15;00;01;00;80;00;00;01;00;00;00;02;00;A0;
   5 | 7F;00;00;00;04;00;00;00;01;00;1C;00;20;71;00;B0;
   6 | 00;00;00;00;40;70;00;B0;00;00;00;00;50;70;00;B0;
   7 | 02;00;00;00;02;00;0C;00;54;70;00;B0;00;02;00;00;
   8 | 01;00;24;00;5B;70;00;B0;02;00;00;00;73;70;00;B0;
   9 | 28;00;00;00;80;70;00;B0;02;00;00;00;E6;70;00;B0;
   A | 02;00;00;00;01;00;0C;00;23;40;00;B0;00;00;00;00;
   B | 00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;
   C | 00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;
   D | 00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;
   E | 00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;
   F | 00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;00;
[loadLzoFW] run,lzoSrc = 0xA06B0000,lzoSize = 0x4E200
[loadLzoFW] run prsvHeader->realFwBlks=19,prsvHeader->nrRealFW=271
.Using LZO firmware
..........[loadLzoFW] run,dstLen = 88
[loadLzoFW] run , _exceptVect = 0x80010000;80000280
 buf=B0001000,size=16
EXEC round=1
   0 | 00;00;00;00;00;00;06;00;00;00;00;00;00;00;01;00;
```

run,dstLen = 88となっていて、圧縮前のバイナリファイルと同じサイズなのでlzoはうまくいってると思われます。

uartを探してみたのですが、見つからなかったので、ブートローダーのprintルーチンを探り当てて、Hello Worldしてみました。

```
EXEC round=1
   0 | 00;00;00;00;00;00;06;00;00;00;00;00;00;00;01;00;
Hello World!!
MORIMORI 1234
```

0x2cのブロック数のところからのイメージを読み込むようです。ThreadXでは0x19(25)になっていました。ここを1にしてbootの直後にイメージを置くことができました。

~~printルーチンは例外の中にあるのではないかと思います。~~　mips16の部分があり見つけるのに手間取りました。

コードはgithubに上げてあります。

~~newlibを引っ付けてみたのですが、うまく動きません。。。~~ bootのprintルーチンはgpレジスタを使っていて、newlibでもgpレジスタを使うためにコンフリクトしていたようです。

オリジナルのバイナリを逆アセンブルしてみてluiがブートには0xb000しかなく、ThreadXには0xb001もあるので、IOはブートに必要なIOは前半の32Kにあり、それ以外が後半32Kにあるものと推測されます。

```
 % grep ",0xb000" boot.txt | awk '{print $4}' | sort | uniq -c
   3 a0,0xb000
   5 a1,0xb000
   1 a2,0xb000
   5 a3,0xb000
   7 s0,0xb000
   3 s1,0xb000
   4 t0,0xb000
  26 v0,0xb000
  19 v1,0xb000
  ```

ブートにUSBのメッセージが含まれるのでUSBは前半32Kにあると思われる。ThreadX部分のアップデートがブートで出来るようにしているものと思われます。

メモリマップ

|アドレス|機能|
|:--|:--|
|0x80000000-0x807fffff|RAM|
|0xb0000000-0xb000ffff|IO|
|0xd0000000-|?|

bootのIOの初期化

```
80000410:       00b0083c        lui     t0,0xb000
80000414:       01000924        li      t1,1
80000418:       a22009a1        sb      t1,0x20a2(t0)
8000041c:       a12009a1        sb      t1,0x20a1(t0)
80000420:       10000924        li      t1,16
80000424:       384009a1        sb      t1,0x4038(t0)
80000428:       304009a1        sb      t1,0x4030(t0)
8000042c:       0f000924        li      t1,15
80000430:       600009a1        sb      t1,0x0060(t0)
80000434:       8b00093c        lui     t1,0x8b
80000438:       45022935        ori     t1,t1,0x245
8000043c:       640009ad        sw      t1,0x0064(t0)
80000440:       01000924        li      t1,1
80000444:       890009a1        sb      t1,0x0089(t0)
80000448:       040000a1        sb      zero,0x0004(t0)
8000044c:       081000ad        sw      zero,0x1008(t0)
80000450:       0c1000ad        sw      zero,0x100c(t0)
80000454:       ffff0924        li      t1,-1
80000458:       000009a1        sb      t1,0x0000(t0)
8000045c:       001009a5        sh      t1,0x1000(t0)
80000460:       041009ad        sw      t1,0x1004(t0)
80000464:       01580924        li      t1,22529
80000468:       081009a5        sh      t1,0x1008(t0)
8000046c:       701000a1        sb      zero,0x1070(t0)
80000470:       00d0093c        lui     t1,0xd000
80000474:       601009ad        sw      t1,0x1060(t0)
80000478:       00d0093c        lui     t1,0xd000
8000047c:       ff1f2935        ori     t1,t1,0x1fff
80000480:       641009ad        sw      t1,0x1064(t0)
80000484:       58000985        lh      t1,0x0058(t0)
80000488:       000100a5        sh      zero,0x0100(t0)
8000048c:       020100a5        sh      zero,0x0102(t0)
```

objdumpはオフセットを10進数で表示するのを16進数に変えてあります。


一文字出力は以下のようです。

```
80007d58:       ff00a530        andi    a1,a1,0xff
80007d5c:       01118290        lbu     v0,4353(a0)
80007d60:       00000000        nop
80007d64:       42110200        srl     v0,v0,0x5
80007d68:       01004230        andi    v0,v0,0x1
80007d6c:       fbff4010        beqz    v0,0x80007d5c
80007d70:       00000000        nop
80007d74:       0800e003        jr      ra
80007d78:       081185a0        sb      a1,4360(a0)
```

printは

0x800025cc(mips16)->0x80003948(mips)->0x80007d58(mips)

で処理されているようです。出力先を代えることが出来るようにするためか、関数ポインターをつかってるようで、追うのが骨でした。

ステータスレジスタがデータポートより前にありuart互換ではないようです。

0xb0000000-0xb0007fffにありそうなIO

* 割り込み
* タイマー
* GPIO
* シリアル
* IR
* SPI
* USB
* SD ?

0xb0008000-0xb000ffffにありそうなIO

* LCD ~~(MIPI DSI?)~~

LCDはRDB入力なので、メモリにフレームバッファを設定して、クロックを作ってその領域をDMAしてくれるエンジンが入っているのではないかと思われます。

threadxは97d84(+10000)までがコードのようです。

```
  97c0f ?Dio
  97c22         h"l
  97c4f ?#J{
  97c85  1'A-
  97cb1 n#q`s
  97d84 empty
  97d94 image
  97da4 audio
  97db4 video
  ```