[NTLK] Einstein 64-bit

Steven Frank stevenf at panic.com
Wed Dec 3 13:11:02 EST 2014


> On Dec 3, 2014, at 8:55 AM, Morgan Aldridge <morgant at makkintosshu.com> wrote:
> 
> While I haven't looked at the Einstein source to confirm, the fact
> that Paul Guyot contributed NativeCalls to NEWT/0 and that the
> functionality mimics the "Relativity" feature he built for Einstein
> (see <http://wwnc.newtontalk.net/resources/WWNC2006_Guyot_EinsteinRelativity.pdf>),
> I'd guess that would be at least on reason for the use.

After spending some quality time with the Einstein source last night, I learned that there are several ways that functions can be patched and bridged between the virtual Newton and the host OS.

-- TROMPatch (defined in TROMImage.h)

These appear to just overwrite the ARM opcodes in ROM with new ARM opcodes.

For example, in TROMImage.cp, we see this:

TROMPatch p000db0dc(0x000db0dc, 0xe1a0f00e, "BeaconDetect (2/2)"); // #  mov pc, lr

This writes the 32-bit value 0xe1a0f00e at ROM address 0x000dbodc, overwriting its previous value.  0xe1a0f00e is an ARM opcode for "mov pc, lr" (as mentioned in the comment), which is the way ARM returns from function calls.  So, if Einstein tries to execute ROM code at 0x000dbodc, it just returns immediately instead of trying to do whatever it does on a real Newton.

-- Virtualization patches

These appear to be a means of transferring control to a host-native function when the emulated ARM processor goes to execute code at a certain address.  These are defined in a table called k717006VirtualizationPatches at the top of TROMImage.cp.  A single virtualization patch looks something like this:

const KUInt32 k717006VirtualizationPatches[] = {
	/* ... */
	0x00358C9C / sizeof(KUInt32),	TVirtualizedCallsPatches::ksymcmp__FPcT1,
};	

Here, 0x00358C9C is the address of the ROM function symcmp(char*, char*).  When Einstein goes to execute code at address 0x00358C9C, it sees this patch and transfers control to TVirtualizedCalls::Execute() (in TVirtualizedCalls.cp) which then dispatches it to symcmp__FPcT1(), which provides a host-native implementation of symcmp() that doesn't require ARM emulation.

I assume that when we are ready to write our awesome MMU-bypassing native functions, this is where we'll hook in.

-- T_ROM_INJECTION (defined in TROMImage.h)

ROM injections appear to allow some host-native code to execute before (or after?) running the original ROM code, as opposed to virtualization patches, which replace the ROM function completely.

Here's an example from TROMImage.cp:

T_ROM_INJECTION(0x00018688, "Progress_ROMBoot") {
	TScreenManager *screen = ioCPU->GetEmulator()->GetScreenManager();
	if (screen->OverlayIsOn()) {
		screen->OverlayPrintProgress(1, 2);
		screen->OverlayPrintAt(0, 3, "ROMBoot", 1);
		screen->OverlayFlush();
	}
	return ioUnit;
}

This, I think, says: when execution hits ROM address 0x00018688, come run this native code (which in this case updates Einstein's progress bar overlay during the boot process) and then continue on with the original ARM code.

-- TNativeCalls

This is where ffi appears...

OH WAIT, I THINK I FINALLY UNDERSTAND.

I think what this does is load a host-native dylib/DLL and expose the functions it contains to the virtual Newton.  So, if you have a library (I notice that libresolv is included in the Xcode project), it'll load that and bridge those functions into the virtual Newton with the same function names?

Am I close?  :)

Sorry for the wall o' text -- I wanted to write it all down as a reference for future Einstein developers and also to document it for my own reference.  It's kind of confusing because the word "patch" is used to mean a couple of conceptually different things.  

Disclaimer: Information presented in this post not guaranteed to be accurate. :)

Steven




More information about the NewtonTalk mailing list