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 into update.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 is startLBA * sectorSize, so in the case of IDBlock, that’ll be 32768.
  • count: Count allows one to only process x bytes before dd finishes. One can use the value (nextPartitionStartLBA - startLBA) * 512 to only process bytes within the current partition. This is 491520 for IDBlock.

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.55MB 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 and dd 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.