中華レトロゲーム機を解析してみる


# 概要

一部の方面で話題になっている，中華レトロゲーム機を購入したので解析をしてみた．物忘れの激しいワタシ向けのメモのようなものである．

解析のゴールを何にするのかが悩ましいところであるが，中華レトロゲーム機向けのアプリケーションの開発環境の構築方法を示せればいいかなと思う．

そうすれば大勢の発想豊かなどなたかが，なにかいいものを作ってくれるのではないかと．

# イメージファイル

## 入手

電源を入れるとRetroFWの画面が表示された．これをキーワードにググると[RetroFW](https://github.com/retrofw/firmware)がすぐに見つかる．

リリースファイルの[RetroFW_v1.2.zip](https://github.com/retrofw/firmware/releases/download/1.2/RetroFW_v1.2.zip)をダウンロードし，中身を見てみる．

## 配布物の中身

zipファイルを展開すると，RetroFW.imgとバッチファイルとdd.exe，サブフォルダに各種uBoot.binとuImage.binが現れる．

## バッチファイルから見えてくること

バッチファイルの中を見ると，dd.exeを使ってRetroFW.imgの中の特定の位置にuBoot.binとuImage.binを書き込む処理が書かれていることがわかる．例えばRetroGame_v1.0_S_B.batは以下のようになっている．

```bat:RetroGame_v1.0_S_B.bat
dd if=kernel/RetroGame_v1.0_S_B.uBoot.bin  of=RetroFW.img conv=notrunc bs=512 seek=1 && dd if=kernel/RetroGame_v1.0_S_B.uImage.bin of=RetroFW.img conv=notrunc bs=1024 seek=4096
```

uBoot.binはファイルの先頭から512byteオフセットした位置から，uImage.binはファイルの先頭から4Mbyteオフセットした位置から書かれることがわかる．

[U-Boot](https://www.denx.de/wiki/U-Boot)は電源が入ってすぐの初期の段階で動作を開始し，ハードウエアの初期化を行った後にOSの起動を行う，いわゆるブートローダーである．

これがファイルの先頭から512byteオフセットした位置に書かれるのだから，この中華レトロゲーム機で採用しているチップはmicroSDの先頭から512byteオフセットした位置(仮にLBA 1としておく)からをRAMに読み出してジャンプする仕組みを備えていることが想像できる．

更にこのU-BootはmicroSDの先頭から4Mbyteオフセットした位置に置かれているuImage.binをRAMに読み出してジャンプするように書かれていると想像できる．

## イメージファイルから見えてくること

RetroFW.imgを見ると，最初の512byteがMBRであるように見える．

パーティションテーブルのわかりやすい部分だけを抜き出して，表にすると以下のようになる．

|パーティションNo.|先頭セクタ(LBA)|セクタ数|パーティション種類|
|:--|:--|:--|:--|
|#1|0x0000_4000|0x0004_0000|Linux|
|#2|0x0004_4000|0x0008_0000|Linux swap|
|#3|0x000c_4000|0x0013_c000|FAT32|
|#4|-|-|空き|

上記に従いRetroFW.imgをバイナリエディタで見てみると，確かに第1パーティション(オフセット0x0080_0000から)がrootfs，第2パーティション(オフセット0x0800_0000から)がswapに見える．

しかし第3パーティション(オフセット0x1800_0000から)は，しばらくの間0で埋められている．こうなっていると，恐らくLinuxからマウントしようとすると失敗するはずで，失敗した場合の動作があらかじめ仕込まれていると考えられる．

具体的には，FAT32でマウントを失敗したらmkfsする，という動作である．もう少し気の利いた設計がしてあるなら，FAT32領域をmicroSDの末尾まで拡張してからmkfsしてくれる事も考えられる([raspbian](https://www.raspberrypi.org/downloads/raspbian/)なんかはそうだから)．これは実際に動きを確認すればよいだろう．

MBRのオフセット0からのローダー部分には実行コードが配置されることになっており実際に何かかかれているが，このチップでもそうなのかは判断しづらい．

ひとまず先頭の4byte，`FA B8 00 10`を[逆アセンブル](https://onlinedisassembler.com/static/home/index.html)してみると...

```text
00000000 1000b8fa    b loc_fffee000
```

とのことで，相対ジャンプ命令でしかも飛び先はマイナス方向のようである．これは実行されないような気がしてならない．これ以上突っ込んで調べるのはやめて，ランダム値を書き込んでみてどうなるか，実際に動きを確認すればよいだろう．

## Linuxを使ってもっと調べる

ここまでバイナリエディタで調べたことであるが，Linux機を使えばもっと簡単に調べられる事に気づいた．

```text
$ fdisk -l ./RetroFW.img
Disk ./RetroFW.img: 1 GiB, 1073741824 bytes, 2097152 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0xbb005712

Device         Boot  Start     End Sectors  Size Id Type
./RetroFW.img1       16384  278527  262144  128M 83 Linux
./RetroFW.img2      278528  802815  524288  256M 82 Linux swap / Solaris
./RetroFW.img3      802816 2097151 1294336  632M  c W95 FAT32 (LBA)
```

調べたとおりである．せっかくなのでもう少し踏み込む．

```text
$ sudo mount -t ext4 -o ro,loop,offset=8388608 RetroFW.img /mnt

$ file /mnt/bin/busybox 
/mnt/bin/busybox: setuid ELF 32-bit LSB executable, MIPS, MIPS32 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, stripped

$ readelf -a /mnt/bin/busybox
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           MIPS R3000
  Version:                           0x1
  Entry point address:               0x402fb0
  Start of program headers:          52 (bytes into file)
  Start of section headers:          800132 (bytes into file)
  Flags:                             0x50001007, noreorder, pic, cpic, o32, mips32
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         9
  Size of section headers:           40 (bytes)
  Number of section headers:         26
  Section header string table index: 25
      :
Attribute Section: gnu
File Attributes
  Tag_GNU_MIPS_ABI_FP: Hard float (double precision)
```

MIPS32のバイナリで，FPU搭載のチップを使っているようである．

実際に購入した中華レトロゲーム機の製品名でググってみるとJZ4760というチップを使っている，という情報があり[Ingenic Semiconductor - Wikipedia](https://en.wikipedia.org/wiki/Ingenic_Semiconductor)を見るとMIPS32 rev1でFPUありの情報が得られる．

またバイナリは[uClibc](https://www.uclibc.org/)を使うようビルドされていることがわかる．

## U-Bootのバージョン

バイナリエディタでU-Bootのバイナリを見てみると，採用しているバージョンが以下であることがわかる．

```text:RetroGame_v1.0_S_B.uBoot.bin
U-Boot 1.1.6 (Jul 26 2018 - 14:28:08)
```

1.1.6となると2006年頃のものだろうか，ずいぶん古いものを使っている．ま，ブートローダーなので古くても構わないか．

現行のリリースバージョンはv2019.07のようだが，jz4760向けの実装は見当たらずに[jz4780の実装](https://gitlab.denx.de/u-boot/u-boot/tree/master/arch/mips/mach-jz47xx)しかなさそうである．

```text:RetroGame_v1.0_S_B.uBoot.bin
Board: Ingenic LEPUS (CPU Speed %d MHz)
```

という文字列も見つけた．LEPUSというのはリファレンス・デザインボードの名称のようであるため，これをキーワードに探せばjz4760向けの実装も見つかるのではないかと思われる．

ひとまずu-boot-1.1.6-jz-20120904-r1819.patch.gzなんてものを見つけた．これにはがっつりjz4760向けの実装が含まれている．RAMが使えるようにする部分の実装は，ボードの定数由来のパラメータが含まれることがある．リファレンス・デザインにしたがったボード設計になっているかがキモになるハズ．

## Linuxのバージョン

同様にバイナリエディタでuImageのバイナリを見てみると，採用しているバージョンが以下であることがわかる．

```text:RetroGame_v1.0_S_B.uImage.bin
Linux-2.6.31.3
```

2009年頃のものだろうか，これまた古いものを使っている．

現行のstableバージョンは5.2.14のようだが，これまたjz4760向けの実装は見当たらずに[jz4740, jz4770, jz4780の実装](https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/arch/mips/jz4740?h=v5.2.14)があるようだ．jz4740との違いはクロック周波数とFPUの有無，GPUの有無くらいと書かれていたので，jz4740向けのビルドで動いてしまうのかもしれない(ホントか?)．

こちらもGPLだから，探せばjz4760向けの実装も見つかるのではないかと思われる．

ひとまずlinux-2.6.31.3-jz-20120904-r1448.patch.gzなんてものを見つけた．これにはがっつりjz4760向けの実装が含まれている．

# 標準的な開発環境

RetroFWの標準的な開発環境を探してみたところ，さっくりと見つかった．

[Topic: RetroFW - Developer Support Thread](https://boards.dingoonity.org/ingenic-jz4760-devices/retrofw-developer-support-thread/)に書かれてある[チュートリアル](https://redirect.viglink.com/?format=go&jsonp=vglnk_156881591905714&key=5150cb74f98acee214af0b53b6829d41&libId=k0pcfxgc0102ljt2000DAwfv3cbhjannx&loc=https%3A%2F%2Fboards.dingoonity.org%2Fingenic-jz4760-devices%2Fretrofw-developer-support-thread%2F&v=1&out=https%3A%2F%2Fdocs.google.com%2Fdocument%2Fd%2F19kJXO3EZ8XCoeporuUUgV_S93AaPbSagza3sAgBILu8%2Fedit%3Fusp%3Dsharing&title=RetroFW%20-%20Developer%20Support%20Thread%20%7C%20Dingoonity.org%20-%20The%20Dingoo%20Community&txt=Tutorial%3A%20Configuring%20a%20Toolchain%20for%20RetroFW%20Development)どおりに構築すれば，サンプルのIPKを作るところまであっさりできた．

## 開発環境構築の要点

チュートリアルに書かれてある要点は以下の通りである．

* Ubuntuが動作する環境を用意する
* [BuildRoot](https://buildroot.org/)をビルドするためのパッケージを導入する
* BuildRootをビルドする
* ビルドしたツールチェインにパスを通す

チュートリアルには[VirtualBox](https://www.virtualbox.org/)を使ってUbuntuの動作環境を用意していたが，試しに[Windows Subsystem for Linux](https://ja.wikipedia.org/wiki/Windows_Subsystem_for_Linux)のUbuntuを使ってみたところ，一部を除き問題なく構築できた．なおWSLの導入については，説明を割愛する．

次にWSLのUbuntuに，BuildRootをビルドするためのパッケージを導入する．以下の通り．

```shell-session
$ sudo apt install build-essential libncurses5 libncurses5-dev git python unzip bc
```

次にBuildRootを取得し，ビルドする．

BuildRootのバージョンは2018.02.9を使うよう指定されており，新しいバージョンがリリースされていることに気づいても使わないように記載されている(ツールチェインのバージョンに敏感だから，とある)．

```shell-session
$ wget https://buildroot.org/downloads/buildroot-2018.02.9.tar.gz
$ tar -xzvf buildroot-2018.02.9.tar.gz
$ cd buildroot-2018.02.9
$ make menuconfig
```

buildrootのコンフィグレーションは，以下のようにするよう記載されている．

```text
Target Options
    Target Architecture - MIPS (little endian)
    Disable soft-float

Toolchain
    C library (uClibc-ng)
    Enable WCHAR support
    Enable C++ support

Target Packages
    Graphic libraries and applications (graphic/text)
        SDL
        SDL_gfx
        SDL_image
        SDL_mixer
        SDL_net
        SDL_sound
        SDL_TTF
```

あとはビルドするだけ．ツールチェイン(クロスコンパイラ)もまるごとビルドするため，結構時間がかかる．

```shell-session
$ export FORCE_UNSAFE_CONFIGURE=1
$ make
```
makeの最中にrootfsを作るのだが，WSLではこれがエラーになるようだ(fakerootがなんたら，fakedがなんたら，と出る)．今回は開発環境が構築できればよく，rootfsは使わないため無視してしまう．同様の手順をVirtualBox + Ubuntu 18.04.3 LTSで試したところ，エラーが出ることなくビルドが終了した．

このあとは好みに依存するが，ツールチェインを指定のディレクトリにコピーしてPATHを通すよう書かれている．

```shell-session
$ mkdir /opt/rs97tools
$ cp -R output/host/* /opt/rs97tools/
$ export PATH=/opt/rs97tools/mipsel-buildroot-linux-uclibc/sysroot/usr/bin:$PATH
$ export PATH=/opt/rs97tools/bin:$PATH
```

これで`mipsel-linux-gcc`や`sdl-config --libs`が実行できれば良い，とある．
お好みでサンプルプロジェクトのビルドを試してみるのも良い．

```shell-session
$ mkdir /opt/rs97apps
$ cd /opt/rs97apps
$ git clone https://github.com/jbanes/rs97-commander
$ cd rs97-commander
$ make
```

# まとめ

購入した中華レトロゲーム機ではOSとしてLinuxが動作しており，エミュレータがLinuxアプリケーションとして動作していることがわかった．

U-BootやLinuxは結構古いものを使っているが，チュートリアルが用意されているため，開発環境構築は容易である．

また[SDL(1.2)](https://www.libsdl.org/)に準拠したアプリケーションを書くことで，中華レトロゲーム機で動作させられそうなことがわかった．

SDL2をサポートした[RetroFW v2.0が開発中](https://boards.dingoonity.org/ingenic-jz4760-devices/retrofw-developer-support-thread/msg188095/#msg188095)とのことで，リリースを心待ちにしている．アプリケーションの開発環境を改善すべく，longtermなLinuxカーネルをポーティングしてみるとか試してみてたけど中断してしまった．

# おまけ

## ビルドを試す

せっかくツールチェインが用意できたので，U-Bootのコンパイルを試みる．

### U-Boot

```shell-session
$ wget ftp://ftp.denx.de/pub/u-boot/u-boot-1.1.6.tar.bz2
$ tar jxvf u-boot-1.1.6.tar.bz2
$ cd u-boot-1.1.6
$ gzip -cd ../u-boot-1.1.6-jz-20120904-r1819.patch.gz | patch -p1
```
[この例](https://github.com/pepe2k/u-boot_mod/commit/6d509b9219dc0e87f06ac2f24df60505fc1af707)を参考に，`include/asm-mips`以下にあるヘッダファイルの内容を変更する．大雑把に言うと`inline`や`__inline__`が付加されているにも関わらず`extern`されているのを`static`に修正する．

```shell-session
$ make lepus_msc_config
$ vi Makefile
(SUBDIRS から examples を削除)
$ make
```
これで`u-boot-msc.bin`ができる．動くかは試してない．

BuildRootで作られるツールチェインは，U-Bootをビルドするのにバージョンがマッチしないようだということがわかった．これは，ヘッダファイルの修正の参考にしたペイジの記載によると，ツールチェインが新しい場合にこのエラーになることが書かれているためである．

実はWSLのUbuntuでインストールできるgcc-mipsel-linux-gnu(gcc-7.4.0)でも，ビルドが通る．

```shell-session
$ apt install gcc-mipsel-linux-gnu
```
したあとに，

```text:Makefile
ifeq ($(ARCH),mips)
CROSS_COMPILE = mipsel-linux-gnu-
endif
```

と変更してmakeすれば良い．

.configを見たくて聞いてみたら，ソースコードを持っていないと[言われた](https://boards.dingoonity.org/ingenic-jz4760-devices/retrofw-developer-support-thread/msg190970/#msg190970)．

しかもスクラッチから作った方がいい，とか言うし．いやぁ，こっちはコンパイル，リンクまでてきているので確認して動けばそれでいいと思っている．動かなかったときのデバッグ方法を調べたうえで，仕込んでから確認しないとハマってしまうけど(LEDデバッグかなぁ)．

### Linux

```shell-session
$ wget https://mirrors.edge.kernel.org/pub/linux/kernel/v2.6/linux-2.6.31.3.tar.gz
$ tar zxvf linux-2.6.31.3.tar.gz
$ cd linux-2.6.31.3
$ gzip -cd ../linux-2.6.31.3-jz-20120904-r1448.patch.gz | patch -p1
$ make lepus_defconfig
$ make
  CHK     include/linux/version.h
  CHK     include/linux/utsrelease.h
  SYMLINK include/asm -> include/asm-mips
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/basic/docproc
  HOSTCC  scripts/basic/hash
  CC      kernel/bounds.s
In file included from include/linux/compiler.h:40:0,
                 from include/linux/stddef.h:4,
                 from include/linux/posix_types.h:4,
                 from include/linux/types.h:14,
                 from include/linux/page-flags.h:8,
                 from kernel/bounds.c:9:
include/linux/compiler-gcc.h:86:30: fatal error: linux/compiler-gcc6.h: No such file or directory
 #include gcc_header(__GNUC__)
                              ^
compilation terminated.
/home/yochy/linux-2.6.31.3/./Kbuild:35: recipe for target 'kernel/bounds.s' failed
make[1]: *** [kernel/bounds.s] Error 1
Makefile:977: recipe for target 'prepare0' failed
make: *** [prepare0] Error 2
```

というわけで，このままではコンパイルが通らない．使用しているコンパイラがgcc-6.4.0なのに対して，Linuxカーネルソースはgcc6を知らない，と言っているため．Ingenicが出している文書(Ingenic Linux Development Guide)を見ると，使用しているgccは4.1.2である．

WSLで作業を続けるには，これの64bitバイナリを作る必要がある．VirtualBoxのUbuntuなら32bitラインタイムライブラリと，ビルド済みのgcc-4.1.2を入れるだけでよいだろう．

一旦作業をVIrtualBox上のUbuntuに変え，以下のようにすると...

```shell-session
$ cd /opt
$ sudo tar jxvf ~/mipseltools-gcc412-glibc261.tar.bz2
$ export PATH=/opt/mipseltools-gcc412-glibc261/bin:$PATH
$ sudo dpkg --add-architecture i386
$ sudo apt install libc6:i386
```

これで使えるようになる．

```shell-session
$ make lepus_defconfig
$ make
    :
  TIMEC   kernel/timeconst.h
Can't use 'defined(@array)' (Maybe you should just omit the defined()?) at kernel/timeconst.pl line 373.
```

こんどはperlで文句を言われる．[ここ](https://patchwork.kernel.org/patch/1761511/)を参考に`kernel/timeconst.pl`を書き換えれば良い．

次はこんな感じ．

```shell-session
$ make
    :
drivers/video/jz4760_lcd.c:141: error: 'LCD_CTRL_BST_64' undeclared here (not in a function)
```

これは`.config`で定義しているLCDの宣言に関係する．

```text:.config
# CONFIG_JZ4760_LCD_TOPPOLY_TD025THEA7_RGB_DELTA is not set
CONFIG_JZ4760_LCD_TOPPOLY_TD043MGEB1=y
# CONFIG_JZ4760_LCD_TRULY_TFTG320240DTSW_18BIT is not set
```

どれをyにすればよいのかわからないので，ひとまずここまで．`LCD_CTRL_BST_64`自体は`arch/mips/include/asm/mach-jz4760b/jz4760blcdc.h`にあるので，これを`#include`すれば通るようになるだろう．

.configを見たくて聞いてみたら，カーネルソースを[公開してもらえた](https://boards.dingoonity.org/ingenic-jz4760-devices/retrofw-developer-support-thread/msg190970/#msg190970)．ここまでくれば，今どきのカーネルバージョンにポーティングも不可能ではないが，アプリケーションがちゃんと動くかわからないので保留かな．

## v1.2.1とv1.2を比較する

[RetroFW v1.2.1](https://github.com/retrofw/firmware/releases/tag/1.2.1)が出ているのに気づいたので，解析時に用いていたv1.2との差をナナメな方向から調べてみた．

結論を言ってしまうと，中身は同じものである．リリースのコメントを見ても，commit messageを見ても，中身を変えたとは書かれていない．

RetroFW.binの中身を各ゲーム機向けに書き換えるバッチファイルの名前が親切になったくらいか．

正直に言うと，RetroFW.binの0x0000_0000から0x087f_ffff(Linux領域の終端)までを切り取ってmicroSDに書き込めばFAT32領域が初期化されることなくそのままでアップデートできるからソフト入れ直す必要ないですよ，と書きたかった．残念．

### U-Boot/Linux kernel

U-BootとLinux kernelは同一であった(sha256の値が同一)．これ目当てでアップデートする意味はない．

### RetroFW.img

RegroFW.imgの中身は異なっていた(sha256の値が異なる)．

U-BootとLinux kernelが同一であることはわかっているため，MBRから求めたLinux領域に差があれば，なにかしら恩恵を受ける可能性がある．

そんなわけでRetroFW.imgのオフセット0x80_0000(LBAで0x4000セクタ)以降を比較したのだが，残念なことに内容は同一であった．

## v2.0とv1.2を比較する

[RetroFW v2.0](https://github.com/retrofw/firmware/releases/tag/2.0)が出ているのに気づいたので，解析時に用いていたv1.2との差を調べてみた．

結論から言うと，BuildRootの中身が変わっているので試す価値はあると思われる．詳しくは[CHANGELOG.md](https://github.com/retrofw/firmware/blob/master/CHANGELOG.md)を参照されたい．

なおU-BootやLinuxカーネルは(恐らく)同一である．

### パーティション構成

MBRを見ると，パーティション構成(サイズ)に若干差があったので示しておく．

|パーティションNo.|先頭セクタ(LBA)|セクタ数|パーティション種類|
|:--|:--|:--|:--|
|#1|0x0000_4000|0x0004_f800|Linux|
|#2|0x0005_3800|0x0007_0800|Linux swap|
|#3|0x000c_4000|0x0013_c000|FAT32|
|#4|-|-|空き|

Linux領域が若干拡張され，その分だけswap領域が減らされている．FAT32領域の先頭セクタは変わっていない．

従ってMBRとLinux領域のみを差し替えることで，FAT32領域を初期化せずに更新可能だと思われる．

### BuildRootのバージョン

一緒にリリースされているBuildRootのバージョンを確認すると，2018.02.11を使っているようである(CHANGESより)．先に示したチュートリアルには2018.02.9を使うように書かれているが，バージョンを更新したようである．

## v2.1とv2.0を比較する

[RetroFW v2.1](https://github.com/retrofw/retrofw.github.io/releases/tag/v2.1)が出ていた．

v2.0以降は更新情報が親切に書かれているので，リンク先のリリースノートを読んで必要性の可否を判断すればいいだろう．

ちなみにFAT32領域以前を差し替えて更新しようとしたら，再初期化が走った．転送済みのあれやこれが消えてしまうので，バックアップをお忘れなく．

## V2.2とv2.1を比較する

[RetroFW v2.2](https://github.com/retrofw/retrofw.github.io/releases/tag/v2.2)が出ていた．

なぜか今回は更新情報がちゃんと書かれていない．Readme.mdにそれっぽいものが書かれているが，システムリカバリのQ.O.L.変更って何のことだろう(この場合のQ.O.L.ってQuarity of Lifeでいいんだろうか)．

今回のイメージファイルはちょっと変わっていて，パーティションが1つしか含まれていない．

|パーティションNo.|先頭セクタ(LBA)|セクタ数|パーティション種類|
|:--|:--|:--|:--|
|#1|0x0000_4000|0x0004_f800|Linux|
|#2|-|-|空き|
|#3|-|-|空き|
|#4|-|-|空き|

microSDに書き込んで電源を入れてみたところ，当然のように初期化処理が走った．これまでの処理に比べて早く終了したように感じる．初期化処理を済ませたあとのパーティション構成は以下のようになっていた．

|パーティションNo.|先頭セクタ(LBA)|セクタ数|パーティション種類|
|:--|:--|:--|:--|
|#1|0x0000_4000|0x0004_f800|Linux|
|#2|0x0005_3800|0x0007_0800|Linux swap|
|#3|0x000c_4000|0x01c6_a000|FAT32|
|#4|-|-|空き|

これまでと比較してFAT32領域が広くなった．

ところでイメージファイルのサイズが175,112,704 byteなのだけど，これが342,017(0x53801) sectorで，ぎりぎりswapファイルのパーティションに食い込んでいる．1セクタ分小さくしなかったのは理由があるんだろうか．

さてもう少しReadme.mdを読むと，libopkやopkrunが取り込まれPyMenuやSimpleMenuが使えるようになった，とある．えっと...[PyMenu](https://github.com/JackD83/PyMenu)，[SimpleMenu](https://github.com/fgl82/simplemenu)のことかな．

あとでもう少し見ておこうかな．

# 参考文献

* [LDK Retro Game Console - LDKGame](https://ldkgame.com/)
* [GitHub - retrofw/firmware: RetroFW Firmware Releases](https://github.com/retrofw/firmware)
* [マスターブートレコード - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%9E%E3%82%B9%E3%82%BF%E3%83%BC%E3%83%96%E3%83%BC%E3%83%88%E3%83%AC%E3%82%B3%E3%83%BC%E3%83%89)

* [Ingenic Semiconductor Co., Ltd](http://www.ingenic.com.cn/en/)
* [Ingenic Semiconductor - Wikipedia](https://en.wikipedia.org/wiki/Ingenic_Semiconductor)

* [disassembler.io](https://onlinedisassembler.com/static/home/index.html)

* [U-Boot](https://www.denx.de/wiki/U-Boot)
* [uClibc](https://www.uclibc.org/)
* [The Linux Kernel Archives](https://www.kernel.org/)