Skip to content

Instantly share code, notes, and snippets.

@wilm0x42
Last active August 26, 2022 13:21
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wilm0x42/2382af4e200a6bb076c91c56813aba54 to your computer and use it in GitHub Desktop.
Save wilm0x42/2382af4e200a6bb076c91c56813aba54 to your computer and use it in GitHub Desktop.
How exactly the elusive GPF format works

The heck is this?

Gecko Patch File format, or GPF, is a feature of Gecko OS that the internet seems to have overlooked. (A google search yields just short of anything meaningful) This document aims to explain how to use this feature without the need to reverse engineer the source code.

But what's it DO?

GCT files, which you should be quite familiar with, contain code for Gecko OS to interpret and execute during gameplay. GPF files, on the other hand, simply contain chunks of data for Gecko OS to write out over specified places in memory, before the game boots. Here's how the format describes this information:

The Format

The file begins with a single byte that dictates how many patches are in this file. This means that a single GPF can only contain 255 patches of arbitrary size. In this case, 0 does in fact mean there are no patches to be applied.

After that follows the patches. Here's the format they follow:

struct patch
{
	uint32 destination_addr;
	uint32 patch_size;
	uint8 patch_data[patch_size];
};

In English: Each patch has a small "header," consisting of:

  • An unsigned 32-bit integer indicating where in memory this patch will be placed (AKA a pointer, in this case)
  • A second unsigned 32-bit integer stating the length of the patch, in bytes.

Technically, this means that each patch can only be 2^32 bytes long (4GB), but, you know... details... Next comes the actual data of the patch. The next patch would come immediately after this data. Keep in mind that all integer values are in big endian.

To be clear, here's an example GPF that writes the string "NICE_MEME" to 0x80b326f3.

01 80 b3 26 f3 00 00 00 09 4E 49 43 45 5F 4D 45 4D 45

  • 01: patch count
  • 80b326f3: destination address
  • 00000009: byte length of patch
  • 4E 49 43 45 5F 4D 45 4D 45: "NICE_MEME" in hex

If you happen to know C, here's the code that actually applies the patches, from apploader.c in Gecko OS:

//---------------------------------------------------------------------------------
void app_apply_patch()
//---------------------------------------------------------------------------------
{

	int i;

	u8 *filebuff = (u8*)sdbuffer;
	u8 *asmbuff;

	no_patches = filebuff[0];

	filebuff += 1;

	for(i=0;i<no_patches;i++)
	{
		patch_dest = be32(filebuff);
		patch_size = be32(filebuff+4);

		memcpy((u8*)patch_dest, filebuff+8, patch_size);
		DCFlushRange((u8*)patch_dest, patch_size);
		filebuff = filebuff + patch_size + 8;
	}
}

Where sdbuffer is the data of the entire GPF.

@wilm0x42
Copy link
Author

nousbgecko

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment