J'ai acheté une machine de jeu rétro chinoise, qui est devenue un sujet brûlant dans certains domaines, alors je l'ai analysée. C'est comme un mémo pour moi qui oublie beaucoup.
Je me demande quel devrait être le but de l'analyse, mais je pense que ce serait bien si je pouvais montrer comment créer un environnement de développement d'applications pour les machines de jeux rétro chinoises.
Ensuite, je pense que beaucoup de gens avec beaucoup d'idées feront quelque chose de bien.
Lors de la mise sous tension, l'écran RetroFW s'affiche. Si vous recherchez ce mot-clé sur Google, vous trouverez immédiatement RetroFW.
Téléchargez le fichier de version RetroFW_v1.2.zip et jetez un œil au contenu.
Lorsque vous décompressez le fichier zip, RetroFW.img, le fichier de commandes et dd.exe, ainsi que divers uBoot.bin et uImage.bin apparaissent dans les sous-dossiers.
Si vous regardez à l'intérieur du fichier de commandes, vous pouvez voir que le processus d'écriture de uBoot.bin et uImage.bin à un emplacement spécifique dans RetroFW.img à l'aide de dd.exe est écrit. Par exemple, RetroGame_v1.0_S_B.bat se présente comme suit.
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
On peut voir que uBoot.bin est écrit à partir du décalage de position de 512 octets depuis le début du fichier, et uImage.bin est écrit à partir du décalage de position de 4 Mo depuis le début du fichier.
U-Boot démarre l'opération au stade initial immédiatement après la mise sous tension et démarre le système d'exploitation après l'initialisation du matériel. C'est un soi-disant chargeur de démarrage qui fonctionne.
Comme cela est écrit à une position de 512 octets décalée par rapport au début du fichier, la puce utilisée dans cette machine de jeu rétro chinoise lit à partir de la position 512 octets de décalage depuis le début de la microSD (temporairement définie comme LBA 1) vers la RAM et saute. Vous pouvez imaginer qu'il a un mécanisme.
De plus, on peut imaginer que ce U-Boot est écrit pour lire uImage.bin situé à une position décalée de 4 Mo du début de la microSD dans la RAM et sauter.
En regardant RetroFW.img, il semble que les 512 premiers octets sont des MBR.
Extraire uniquement la partie facile à comprendre de la table de partition et en faire une table est la suivante.
No de partition. | Premier secteur(LBA) | Nombre de secteurs | Type de partition |
---|---|---|---|
#1 | 0x0000_4000 | 0x0004_0000 | Linux |
#2 | 0x0004_4000 | 0x0008_0000 | Linux swap |
#3 | 0x000c_4000 | 0x0013_c000 | FAT32 |
#4 | - | - | Gratuit |
Si vous regardez RetroFW.img avec un éditeur binaire conformément à ce qui précède, vous pouvez voir que la première partition (à partir de l'offset 0x0080_0000) est rootfs et la deuxième partition (à partir de l'offset 0x0800_0000) est swap.
Cependant, la troisième partition (à partir du décalage 0x1800_0000) est remplie de 0 pendant un certain temps. Dans ce cas, si vous essayez de monter depuis Linux, il échouera probablement, et on pense que l'opération en cas d'échec est préchargée.
Plus précisément, si le montage échoue avec FAT32, mkfs est exécuté. Si vous avez un design un peu plus astucieux, il est possible d'étendre la zone FAT32 jusqu'à la fin de la microSD puis mkfs (raspbian. ) Parce que c'est le cas). Vous pouvez en fait vérifier le mouvement de ceci.
Le code d'exécution est censé être placé dans la partie chargeur à partir de l'offset 0 du MBR, et quelque chose est réellement écrit, mais il est difficile de juger s'il en est de même avec cette puce.
Pour le moment, essayez assemblage inversé pour les 4 premiers octets, FA B8 00 10
...
00000000 1000b8fa b loc_fffee000
Il s'agit donc d'une commande de saut relative et la destination du saut semble être dans la direction négative. Ne pensez pas que ce n'est pas fait. Au lieu de creuser davantage, vous devriez essayer d'écrire une valeur aléatoire et voir réellement ce qui se passe.
J'ai cherché jusqu'à présent avec un éditeur binaire, mais j'ai trouvé qu'il était plus facile de vérifier avec une machine Linux.
$ 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)
Comme je l'ai vérifié. C'est un gros problème, alors j'irai un peu plus loin.
$ 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)
C'est un binaire de MIPS32 et semble utiliser une puce équipée de FPU.
Il existe des informations selon lesquelles une puce appelée JZ4760 est utilisée lorsqu'elle est recherchée sur Google avec le nom du produit de la machine de jeu rétro chinoise réellement achetée Ingenic Semiconductor --Wikipedia Si vous regardez, vous pouvez obtenir des informations avec FPU avec MIPS32 rev1.
Vous pouvez également voir que le binaire est construit pour utiliser uClibc.
Si vous regardez les binaires U-Boot avec un éditeur binaire, vous pouvez voir que les versions utilisées sont les suivantes.
text:RetroGame_v1.0_S_B.uBoot.bin
U-Boot 1.1.6 (Jul 26 2018 - 14:28:08)
Pour ce qui est de la version 1.1.6, c'est probablement vers 2006, et j'en utilise une très ancienne. Eh bien, puisqu'il s'agit d'un chargeur de démarrage, peut-il être ancien?
La version actuelle semble être v2019.07, mais je ne trouve pas d'implémentation pour jz4760 [Implémentation de jz4780](https://gitlab.denx.de/u-boot/u-boot/tree/master/arch/ mips / mach-jz47xx) Il semble qu'il n'y en ait qu'un.
text:RetroGame_v1.0_S_B.uBoot.bin
Board: Ingenic LEPUS (CPU Speed %d MHz)
J'ai également trouvé la chaîne de caractères. LEPUS semble être le nom d'une carte de conception de référence, donc si vous recherchez ceci comme mot-clé, vous pouvez trouver une implémentation pour jz4760.
Pour le moment, j'ai trouvé quelque chose comme u-boot-1.1.6-jz-20120904-r1819.patch.gz. Il comprend une implémentation solide pour le jz4760. L'implémentation de la partie qui rend la RAM disponible peut inclure des paramètres dérivés des constantes de la carte. La clé est de savoir si la carte est conçue selon la conception de référence.
De même, si vous regardez le binaire uImage avec un éditeur binaire, vous pouvez voir que la version utilisée est la suivante.
text:RetroGame_v1.0_S_B.uImage.bin
Linux-2.6.31.3
Peut-être que c'est vers 2009, j'utilise un ancien.
La version stable actuelle semble être la 5.2.14, mais je ne trouve aucune implémentation pour jz4760 non plus [Implémentation de jz4740, jz4770, jz4780](https://git.kernel.org/pub/scm/linux/kernel/ Il semble y avoir git / stable / linux.git / tree / arch / mips / jz4740? H = v5.2.14). Il a été écrit que la différence par rapport à jz4740 est la fréquence d'horloge, la présence ou l'absence de FPU et la présence ou l'absence de GPU, donc cela peut fonctionner avec la version pour jz4740 (vraiment?).
C'est aussi une GPL, donc si vous la cherchez, vous pouvez trouver une implémentation pour jz4760.
Pour le moment, j'ai trouvé quelque chose comme linux-2.6.31.3-jz-20120904-r1448.patch.gz. Il comprend une implémentation solide pour le jz4760.
Lorsque j'ai recherché un environnement de développement standard pour RetroFW, je l'ai trouvé rapidement.
[Tutoriel](https: // redirect.) Écrit dans Rubrique: RetroFW - Thread de support pour les développeurs viglink.com/?format=go&jsonp=vglnk_156881591905714&key=5150cb74f98acee214af0b53b6829d41&libId=k0pcfxgc0102ljt2000DAwfv3cbhjannx&loc=https%3A%2F% % 2Fdocs.google.com% 2Fdocument% 2Fd% 2F19kJXO3EZ8XCoeporuUUgV_S93AaPbSagza3sAgBILu8% 2Fedit% 3Fusp% 3Dsharing & title = RetroFW% 20-% 20Developer% 20Support% 20Thread% 20Thread% 20Thread% 20Thread% 20Thread% 20Thread% 20Thread% 20Thread% 20Thread% 20Thread% 20Support% 20-% 20Developer% 20 % 20Configuring% 20a% 20Toolchain% 20for% 20RetroFW% 20Development), il était facile de créer un échantillon d'IPK.
Les principaux points écrits dans le didacticiel sont les suivants.
Dans le tutoriel, j'ai utilisé VirtualBox pour préparer l'environnement d'exploitation d'Ubuntu, mais j'ai essayé Windows Subsystem for Linux. Quand j'ai essayé d'utiliser Ubuntu (/ wiki / Windows_Subsystem_for_Linux), j'ai pu le construire sans aucun problème, sauf pour certaines parties. L'explication de l'introduction de WSL est omise.
Ensuite, installez le package pour créer BuildRoot sur Ubuntu de WSL. Comme suit.
$ sudo apt install build-essential libncurses5 libncurses5-dev git python unzip bc
Ensuite, récupérez BuildRoot et compilez.
La version de BuildRoot est spécifiée pour utiliser 2018.02.9, et il est indiqué de ne pas l'utiliser même si vous remarquez qu'une nouvelle version a été publiée (car elle est sensible à la version de la chaîne d'outils).
$ 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
La configuration de buildroot est décrite comme suit.
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
Tout ce que vous avez à faire est de construire. Il faut beaucoup de temps pour construire toute la chaîne d'outils (compilateur croisé).
$ export FORCE_UNSAFE_CONFIGURE=1
$ make
Je crée des rootfs pendant make, mais dans WSL cela semble être une erreur (ce qu'est fakeroot, qu'est-ce que truqué). Cette fois, il suffit de créer un environnement de développement et rootfs n'est pas utilisé, il est donc ignoré. Lorsque j'ai essayé la même procédure avec VirtualBox + Ubuntu 18.04.3 LTS, la construction s'est terminée sans aucune erreur.
Après cela, selon vos préférences, il est écrit pour copier la chaîne d'outils dans le répertoire spécifié et la placer dans le PATH.
$ 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
Ce serait bien si mipsel-linux-gcc
et sdl-config --libs
pouvaient être exécutés avec ça.
Vous pouvez également essayer de créer l'exemple de projet si vous le souhaitez.
$ mkdir /opt/rs97apps
$ cd /opt/rs97apps
$ git clone https://github.com/jbanes/rs97-commander
$ cd rs97-commander
$ make
Il a été constaté que Linux fonctionne en tant que système d'exploitation sur la machine de jeu rétro chinoise achetée et que l'émulateur fonctionne en tant qu'application Linux.
U-Boot et Linux sont assez anciens, mais comme des tutoriels sont disponibles, il est facile de créer un environnement de développement.
De plus, en écrivant une application conforme à SDL (1.2), il a été constaté qu'elle pouvait être utilisée sur une machine de jeu rétro chinoise.
SDL2 pris en charge RetroFW v2.0 est en cours de développement J'ai hâte d'y être. J'ai essayé de porter un noyau Linux à long terme pour améliorer l'environnement de développement d'applications, mais cela a été interrompu.
Maintenant que la chaîne d'outils est prête, essayez de compiler U-Boot.
U-Boot
$ 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
Reportez-vous à cet exemple et modifiez le contenu du fichier d'en-tête sous ʻinclude / asm-mips. En gros, même si ʻinline
et __inline__
sont ajoutés, ʻextern est corrigé en
statique`.
$ make lepus_msc_config
$ vi Makefile
(Suppression d'exemples de SUBDIRS)
$ make
Cela créera ʻu-boot-msc.bin`. Je n'ai pas essayé de fonctionner.
Il s'avère que la chaîne d'outils créée par BuildRoot ne semble pas correspondre à la version pour construire U-Boot. En effet, la description de Page, qui a été utilisée comme référence pour modifier le fichier d'en-tête, indique que cette erreur se produira si la chaîne d'outils est nouvelle.
En fait, gcc-mipsel-linux-gnu (gcc-7.4.0), qui peut être installé sur Ubuntu de WSL, fonctionne également.
$ apt install gcc-mipsel-linux-gnu
Après ça
Makefile
ifeq ($(ARCH),mips)
CROSS_COMPILE = mipsel-linux-gnu-
endif
Vous pouvez le modifier pour le faire.
Quand j'ai demandé à voir .config, on m'a [dit] que je n'avais pas le code source (https://boards.dingoonity.org/ingenic-jz4760-devices/retrofw-developer-support-thread/msg190970/ # msg190970).
De plus, il vaut mieux le faire à partir de zéro. Eh bien, celui-ci a été compilé et lié, donc je pense que ce n'est pas grave si vous vérifiez et déplacez. J'en suis accro si je ne le vérifie pas après avoir étudié la méthode de débogage quand cela ne fonctionne pas (je me demande si c'est un débogage LED).
Linux
$ 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
Par conséquent, il ne se compilera pas tel quel. Le compilateur que j'utilise est gcc-6.4.0, mais la source du noyau Linux dit qu'il ne connaît pas gcc6. En regardant le document (Ingenic Linux Development Guide) publié par Ingenic, le gcc utilisé est 4.1.2.
Pour continuer à travailler avec WSL, vous devez créer un binaire 64 bits pour cela. Pour VirtualBox Ubuntu, tout ce que vous avez à faire est d'installer la bibliothèque de temps de ligne 32 bits et le gcc-4.1.2 pré-construit.
Une fois que vous avez changé le travail en Ubuntu sur VIrtualBox et procédez comme suit ...
$ 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
Vous pouvez maintenant l'utiliser.
$ 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.
Cette fois, je me plains de perl. Vous pouvez réécrire kernel / timeconst.pl
en vous référant à here.
Ensuite, c'est comme ça.
$ make
:
drivers/video/jz4760_lcd.c:141: error: 'LCD_CTRL_BST_64' undeclared here (not in a function)
Ceci est lié à la déclaration LCD définie dans .config
.
.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
Je ne sais pas lequel devrait être réglé sur y, alors c'est tout pour le moment. Le LCD_CTRL_BST_64
lui-même est situé dans ʻarch / mips / include / asm / mach-jz4760b / jz4760blcdc.h, donc vous pouvez le passer par
# include`.
Quand j'ai demandé à voir .config, j'ai obtenu la source du noyau publiée. À ce stade, le portage vers la version actuelle du noyau n'est pas impossible, mais je ne sais pas si l'application fonctionnera correctement, donc je pense que c'est en attente.
J'ai remarqué que RetroFW v1.2.1 est apparu, donc la différence avec la v1.2 utilisée au moment de l'analyse n'est pas bonne. J'ai enquêté dans différentes directions.
Pour conclure, le contenu est le même. En regardant les commentaires de la version et le message de validation, cela ne dit pas que le contenu a changé.
Le nom du fichier batch qui réécrit le contenu de RetroFW.bin pour chaque machine de jeu est devenu kind.
Pour être honnête, je voulais écrire que si vous coupez 0x0000_0000 à 0x087f_ffff (fin de la zone Linux) de RetroFW.bin et que vous l'écrivez sur microSD, vous pouvez mettre à jour la zone FAT32 telle quelle sans être initialisé, vous n'avez donc pas besoin de réinstaller le logiciel. C'était. Pardon.
U-Boot/Linux kernel
U-Boot et le noyau Linux étaient les mêmes (la valeur sha256 est la même). Il ne sert à rien de mettre à jour à cet effet.
RetroFW.img
Le contenu de RegroFW.img était différent (la valeur de sha256 était différente).
Puisque nous savons que U-Boot et le noyau Linux sont identiques, s'il y a une différence dans la zone Linux obtenue à partir de MBR, il peut y avoir un avantage.
C'est pourquoi j'ai comparé RetroFW.img après le décalage 0x80_0000 (secteur 0x4000 dans LBA), mais malheureusement, le contenu était le même.
J'ai remarqué que RetroFW v2.0 était sorti, j'ai donc vérifié la différence par rapport à la v1.2 utilisée au moment de l'analyse. ..
De la conclusion, cela semble valoir la peine d'essayer car le contenu de BuildRoot a changé. Pour plus de détails, reportez-vous à CHANGELOG.md.
Les noyaux U-Boot et Linux sont (probablement) les mêmes.
En regardant le MBR, il y avait une légère différence dans la configuration de la partition (taille), donc je vais le montrer ici.
No de partition. | Premier secteur(LBA) | Nombre de secteurs | Type de partition |
---|---|---|---|
#1 | 0x0000_4000 | 0x0004_f800 | Linux |
#2 | 0x0005_3800 | 0x0007_0800 | Linux swap |
#3 | 0x000c_4000 | 0x0013_c000 | FAT32 |
#4 | - | - | Gratuit |
La zone Linux a été légèrement étendue et la zone d'échange a été réduite en conséquence. Le premier secteur de la zone FAT32 n'a pas changé.
Par conséquent, il semble que la zone FAT32 puisse être mise à jour sans l'initialiser en remplaçant uniquement les zones MBR et Linux.
En vérifiant la version de BuildRoot publiée ensemble, il semble que 2018.02.11 soit utilisé (à partir de CHANGES). Le tutoriel montré ci-dessus indique d'utiliser 2018.02.9, mais il semble que la version a été mise à jour.
RetroFW v2.1 a été publié.
Depuis la version 2.0 et les versions ultérieures, les informations de mise à jour sont rédigées avec gentillesse, vous devez lire la note de publication liée et décider si cela est nécessaire ou non.
À propos, lorsque j'ai essayé de remplacer et de mettre à jour la zone FAT32 et les versions antérieures, la réinitialisation s'est déroulée. N'oubliez pas de le sauvegarder car il sera perdu.
RetroFW v2.2 a été publié.
Pour une raison quelconque, les informations de mise à jour ne sont pas écrites correctement cette fois. Il y a quelque chose comme ça dans Readme.md, mais quel est le changement Q.O.L. de la récupération du système (Q.O.L. dans ce cas, la Quarity of Life?).
Le fichier image cette fois est un peu étrange, il ne contient qu'une seule partition.
No de partition. | Premier secteur(LBA) | Nombre de secteurs | Type de partition |
---|---|---|---|
#1 | 0x0000_4000 | 0x0004_f800 | Linux |
#2 | - | - | Gratuit |
#3 | - | - | Gratuit |
#4 | - | - | Gratuit |
Lorsque je l'ai écrit sur la microSD et que je l'ai mis sous tension, le processus d'initialisation s'est déroulé comme une évidence. On a l'impression qu'il s'est terminé plus tôt que le traitement précédent. La structure de partition après le processus d'initialisation était la suivante.
No de partition. | Premier secteur(LBA) | Nombre de secteurs | Type de partition |
---|---|---|---|
#1 | 0x0000_4000 | 0x0004_f800 | Linux |
#2 | 0x0005_3800 | 0x0007_0800 | Linux swap |
#3 | 0x000c_4000 | 0x01c6_a000 | FAT32 |
#4 | - | - | Gratuit |
La zone FAT32 est devenue plus large qu'auparavant.
À propos, la taille du fichier image est de 175 112 704 octets, mais il s'agit du secteur 342 017 (0x53801) et il coupe simplement la partition du fichier d'échange. Y a-t-il une raison pour laquelle je ne l'ai pas réduit d'un secteur?
En passant, quand j'ai lu un peu plus Readme.md, il est dit que libopk et opkrun ont été importés et PyMenu et SimpleMenu sont devenus disponibles. Euh ... PyMenu, SimpleMenu.
Voyons un peu plus tard.
[Master Boot Record-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)
Recommended Posts