NewtonOS patches work by mapping ROM code to RAM via the Memory Management Unit (MMU). Mapping is done on a per page basis. Each page has a size of 4k. Patching a page requires placing a copy of the original code in the ROM into a patch page, and modifying the data to be patched.
More background information can be found here:
Since the NewtonOS ROMs can differ from model to model, certain areas of the ROMs have been fixed in their layout, and designated as patchable areas. The patchable areas usually contain jump tables, providing one level of indirection for function calls. This allows replacing function implementations easily, and helps reducing the number of pages which need to be remapped.
An important aspect of the patchable areas is that they are only sparsely populated: Only the first 128 bytes are usually used. As an example, the patchable area at 0x01a00000 only contains 32 patchable vectors:
This is important when looking at the MMU page table patch information: The patch information for the page tables only needs to cover the first 128 bytes of a 4k page, the rest of the page is not relevant. This reduces the size of the patches significantly.
A patch links together four different areas:
- The patchable areas in the ROM
- The MMU level 2 tables in RAM
- Patches to the MMU level 2 tables in the patch
- Patch code for the patchable areas in the patch
The links are:
- MMU patch information to code in the path: The link is done via the
LoadPage macro. It instructs the MMU which page in the patch to refer to. Pages in the patch are numbered 2 to 7 for the ROM patch, and there is one page (number 1) in the REx patch.
- Patched code back to proper virtual address: The mapping of the patched code back into the virtual address space is done implicitly by using calculating the proper offset into the patch table, and using that in the updated code for the patchable area.
Patch pages are coded with position independent code: Mapping page 2 to address 0x01d80000 or to address 0x01da0000 results in the same content.
Anatomy of a Patch
To understand how a patch works in detail, the 717260 patch serves as a good example. The reverse engineered source code is located on SourceForge.
Creating own Patches
Here is a list of potential patches to be developed:
- Empty Patch: Purpose is to clear out the MMU patch tables and get the Newton into an unpatched state
- Minimum Patch: Purpose is to take the empty patch and patch just one function
- Larger Patch: Purpose is to add a new page to the patch
- New Page Patch: Purpose is to remap a new page of the pageable area
- Changed Page Patch: Purpose is to change an existing patched page