MyArcade Gamestation Pro: update.img
Overview
As mentioned in the flashing page, there’s three methods to flash the Gamestation Pro, two of which involve flashing over a firmware file from MASKROM mode. There’s also the third method that is much simpler than the previous two, relying mostly on the SD card. As of the time of writing, this method has not had any firmware officially released for it yet, however, as the method is a standard for Rockchip devices, it’s possible to construct an image that can take advantage of this flashing method with relative ease.
What’s Needed
There’s a few things that go into the update.img
file. They are as follows:
- The bootloader file, AKA
Loader.bin
. It’s unclear whether this is needed for flashing from within the operating system, however, it has some utility in that it is baked intoupdate.img
, allowing the new image to be used as the sole file involved in flashing via RKDevTool, the default software shipped by MyArcade for flashing the Gamestation Pro. - Basic device and firmware info. This includes details such as the machine model,
manufacturer, firmware revision, and a few other bits. This is specified in
a file
parameter.txt
. - Individual partition binaries. These contain our filesystems, bootloader, kernel,
etc. Relative paths to these files are stored in a file
package-file
. - Partition table info. This is used so the updater knows where to place each individual
partition binary. All that’s really used is the start and end byte count. A unique
partition identifier, AKA a GUID, is also needed for the
rootfs
partition, which generally holds operating system libraries and programs.
This may seem to be a bit more info than we already have, but, since the
Firmware.img
file distributed by MyArcade is a complete image of the system
flash storage, one can leverage the GPT partition table, a set of instructions for
the device to follow in order to find partitions. Utilizing the GPT partition
table in the same way the device would, a user would be able to find and extract
information and binaries for each partition without any additional needed info.
Thus, in implementation, all one needs is the following:
- The bootloader,
Loader.bin
- A complete image of the internal flash,
Firmware.img
- Some model info
- A guideline for a similarly spec’d device,
parameter.txt
- A file telling the packer where partition images are,
package-file
Extracting Partition Info: Quick and Dirty
One can do this the quick and dirty way, or, one can do this a bit more elegantly with a bit of foresight. As more fundamentals can be explored via the dirty way, one can start there to get a good understanding of the problem.
So, the user needs the GPT partition layout. The easiest way to obtain this is to just ask the device. If the device is loaded into MASKROM mode, one can ask for the partition layout like so:
rkdeveloptool ppt
**********Partition Info(GPT)**********
NO LBA Name
00 00000040 IDBlock
01 00000400 uboot
02 00000800 boot
03 00002C00 rootfs
04 00027C00 data
Running this produces a list of start LBAs for each
partition on the device in hexadecimal format. For those uninformed,
LBA, or Logical Block Addressing,
just means we orient things to be indexed around blocks rather than bytes.
Each block is n
bytes in size, where n
is also known as a sector size.
Usually, the default sector size is 512
, and the same holds true for the
Gamestation Pro.
Notably, however, this table lacks end LBAs. This isn’t much a problem.
Since the order of the partitions is known, one can just say that the last
LBA for a partition is the one just before the next start LBA. For example,
IDBlock
starts at LBA 0x40
. In decimal notation, that’s index 64
.
The next partition, uboot
, starts at 0x400
, or index 1024
. Thus, one
can safely state that IDBlock
starts at index 64
and ends on index 1023
,
inclusive. Subtracting these, one can observe a length of 960
LBAs, which in hex is
0x3C0
. The only outlier to this example is data
. There is no next partition.
In this case, the last sector for the partition can be determined by
counting off how many sectors are on the device. This can be done like so:
rkdeveloptool rfi
Flash Info:
Manufacturer: SAMSUNG, value=00
Flash Size: 230 MB
Flash Size: 471040 Sectors
Block Size: 128 KB
Page Size: 2 KB
ECC Bits: 0
Access Time: 40
Flash CS: Flash<0>
Thus, given the flash extends out 471040
sectors, one can assume that
the final partition extends all the way out to this LBA.
So where does one go from here? Well, if one knows where a partition starts
and ends, they can cut it out for use in the update.img
. The easiest way to
do this is with the dd
command. There’s two important arguments to make use of:
skip
: Using skip, one can jump to the first LBA without processing anything before it. The value to be used isstartLBA * sectorSize
, so in the case ofIDBlock
, that’ll be32768
.count
: Count allows one to only processx
bytes beforedd
finishes. One can use the value(nextPartitionStartLBA - startLBA) * 512
to only process bytes within the current partition. This is491520
forIDBlock
.
With these, a command like such can be created for each partition:
dd if=Firmware.img of=IDBlock_dd.bin skip=32768 count=491520 iflag=skip_bytes,count_bytes
Thus, the start and end LBAs for each partition are known and a binary of each partition has been extracted.
One may also desire to use rkdeveloptool
to extract partitions. This would certainly
be the easiest approach to use given the rl
command, however, only the first
0x2000000
bytes of the flash appear to be accessible via rkdeveloptool
’s rl
command.
That is to say, only the first 33.55
MB or so are accessible. What happens after
byte 0x2000000
is that all bytes are reported as 0xCC
, or 0b11001100
. This was consistent
after multiple runs starting at multiple different places.
Extracting Partition Info: The Elegant Way
The previous method is suboptimal for a variety of reasons, including but not limited to the following:
dd
isn’t available on Windows anddd
is a scary command to use.- The device must be connected in MASKROM mode in order to obtain a variety of information.
- Many numbers must be calculated by hand with plenty of conversions between decimal and hexadecimal.
So, the logical step is to make the computer do the work for you. This is tough to implement if one has to have the device connected to procure info as it’s another variable entering the fray. But what if there was another way to read the GPT header?
Rather than having something read the GPT header off for the user, a
user can simply read the GPT header themselves. This may seem counterintuitive
given a GPT header is represented by a messy cluster of bytes, but, since
one has technology, they can simply inform the computer what a GPT header is supposed
to look like and have the computer process it directly. As stated before, the Firmware.img
image is a full backup of the flash chip, so this contains the GPT header.
Using 4096kb/RockchipFwExtract, a Python3
script written by 4096kb, the process of locating the GPT header, extracting the
partition layout, and extracting each individual partition is completely automated
with no requirement for the device to be connected.
At a high level, the script does the following:
- Looks for the string
EFI PART
, a “magic number” that universally signifies the start of a GPT partition header - Reads in each field on the primary header according to how a GPT header is traditionally structured
- Performs CRC checksum calculation and verifies against embedded CRC to ensure data integrity
- Reads in each partition entry header
- Writes out each partition to its own file according to the start and end LBA specified in its header entry
All of this is done using Firmware.img
as the only input. The user only
needs to have Python3 installed on their computer.
The software has been validated to work on both Windows and Linux, with both
producing identical output. The script is also likely to work without modification
on MacOS as well.
Simply run the following in a terminal after copying Firmware.img
to the same folder as the script:
python3 extractfw.py Firmware.img
This will display the start and end LBA for each partition detected and write each partition out to its own file.
Packing update.img
So now you’ve got your hands on each individual partition and
you’ve got the start and end LBAs as well. Now it’s time to pack
them together with Loader.bin
into update.img
. There’s many
repos online with Rockchip tools designed to do this, but for
the RK3032, you want firefly-linux/tools.
This one is chosen as other versions of the Rockchip firmware pack tool
have issues with assigning RK3032
as the chip ID, a requirement for flashing
an update.img
on the Gamestation Pro.
Unfortunately, Windows users will either have to sit this one out, find a different tool, or use WSL or a virtual machine to do these next few steps.
First, though, one needs to inform the pack tool of a few things.
Device Info
As previously stated, this is done with parameter.txt
. Take, for example,
firefly-linux’s RK3036 config.
Here, they specify all of the details in one file. The most important thing to make
note of is the last two lines, CMDLINE:...
and uuid:...
. You’ll need to
copy over the partition layout and the UUID of the rootfs
partition over to
these values. The format on CMDLINE
is
{Partition Length}@{Partition Starting LBA}({Partition Name})
with all numbers in hexadecimal.
Fortunately, this too is automated using the aforementioned Python script.
Simply provide the preliminary info, then let the program fill out
CMDLINE
and uuid
. For example, fill out parameter_partial.txt
like so:
FIRMWARE_VER: 1.3.0
MACHINE_MODEL: RK3036
MACHINE_ID: 007
MANUFACTURER: RK3036
MAGIC: 0x5041524B
ATAG: 0x00200800
MACHINE: 3036
CHECK_MASK: 0x80
PWR_HLD: 0,0,A,0,1
TYPE: GPT
This will work for the Gamestation Pro. Now, we pass this info off to the Python script so it can add the rest:
python3 extractfw.py Firmware.img parameter_partial.txt
A new file, parameter.txt
, will be created in the script’s
rockdev
folder. A copy titled simply parameter
is also made
for compatibility’s sake as the next tool that’ll be mentioned
requires this exists.
Partition Image Locations
This is quite simple. package-file
simply states where
each part of the firmware is relative to itself.
An easy example can be found in the firefly-linux/tools repo.
It’s simply formatted dependency_name dependency/location
.
The Python script is also capable of generating this. If the steps
for generating parameter.txt
are followed, package-file
is also
generated right along side it.
To reiterate, package-file
states where files are
relative to itself. Do not move the files in such a
manner as to where the amount of clicks to get from
package-file
to a given file contained in its text
changes and don’t rename any folders which appear
in package-file
.
Packing
Congratulations, you’ve made it! You have everything you need
to build update.img
. Now it’s just time to do the deed.
After downloading the firefly-linux/tools
repo, navigate to
linux/Linux_Pack_Firmware/rockdev
. Copy rk3036-mkupdate.sh
to rk3032-mkupdate.sh
and modify the script so line 18 reads like so:
./rkImageMaker -RK3032 Loader.bin Image/update.img update.img -os_type:androidos || pause
This’ll set the chip ID to the value that’s expected by the
Gamestation Pro and simplifies the name on Loader.bin
.
Now, copy over the contents of the rockdev
folder created by
the Python script into the rockdev
folder from firefly-linux/tools
and copy your Loader.bin
into the rockdev
folder too. Execute rk3032-mkupdate.sh
.
With any luck, the script should spit out a complete update.img
file.