以前あきらめたmipsなフォトフレームをまたいじってみました。
以前にページに調べた情報も追記してあります。
このターゲットは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というソースがあります。
このコードを改造してこのブートローダーが使用できる圧縮データを作れるようにしてみました。
オリジナルのブートローダーに無限ループのプロクラムを実行されせてみます。
無限ループのコードはこれです。
ビルドできたファイルを元のブートローダーと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