• Hello MLAers! We've re-enabled auto-approval for accounts. If you are still waiting on account approval, please check this thread for more information.

Skipping the Startup Memory Test

0x1258 is Link2 which is probably going to be a Power PC ROM address (looks like 0xfff##### - last 1 MB of 4 MB ROM). It appears to only be used for calling SerialTestManager tests?

Can you post one of your NVRAM dumps so I can compare?

Is your ROM 077d.28f1 checksum 96cd923d or 077d.28f2 checksum 9630c68b?
I don't think that matters since they have the same ExceptionTable, HWInit (except for one byte at the end?), and OpenFW parts.
 
Attached two outputs from your tool, one after booting without ram test and one after booting with ram test.

ROM version 077d.28f2 checksum $9630c68b
 

Attachments

My guess is it's the same everywhere and the bit I saw toggling was just a coincidence because that byte (and the 3 bytes before it) certainly looks like an address.

From the source you shared, it's a 32bit read/write of offset 0x1040 and a zero skips the test and a non-zero runs it.

That does suggest in System 7, it does write a non-zero value at some point after boot (probably shutdown as well).

If I want to put a zero there to skip the test, I need to ensure I overwrite it after the System touches it or patch the System call to not write the non-zero value.
 
Attached two outputs from your tool, one after booting without ram test and one after booting with ram test.
0x1258 is zero in both.

I see 0x1254 = Link1 change from fff201f8 in FastConfigDump to fff20270 in SlowConfigDump.

fff20000 (3MB + 128K, size 64K) is the address of HWInit in the ROM, according to the results created by the tbxi command.
https://github.com/elliotnunn/tbxi

fff201f8 is the return address for the call at 0x1f4 in HWInit (in .POST) to CheckForInitialzation.
fff20270 is the return address for the call at 0x26c in HWInit (in ColdBoot) to RunTests.

That seems like a sufficient indication that the tests were run - as long as nothing else uses Link1. Searching HWInit.txt shows no other occurrences of Link1.

I used the MPW DumpXCOFF command using
https://github.com/ksherlock/mpw
to disassemble HWInit but it seems to be an incomplete dump. Maybe running the command in real MPW would produce a complete dump?
But at least the disassembly includes the parts I'm talking about. The parts match what's in the Diagnostics.s assembly file (though I didn't check every instruction or try to compile Diagnostics.s).
 

Attachments

I'm sorry, I think my brain is fried... Here are the two lines from the fast dump and the slow dump:

Code:
27F448FE FFF0D000 5D5CC8CE FFF0D000 FFF04C4C FFF201F8 00000000 00000000 // FAST
27F45CFE FFF0D000 DF7DC8CE FFF0D000 FFF04C4C FFF20270 00000000 00000000 // SLOW
                                                  ^

The bit that was flipping is indicated above. Contrary to what I wrote, it's actually offset 0x1256. My post #10 in this thread should have said 0x1256 instead of 0x1258 and then I repeated 0x1258 in subsequent posts. And that's why I thought it was within your range but then confused myself with that typo of 0x1258 again. Sorry about that. So I think 0x1256 was within the range you saw reads/writes to but it was not the change I was looking for.
 
Last edited:
The bit that was flipping is indicated above. Contrary to what I wrote, it's actually offset 0x1256. My post #10 in this thread should have said 0x1256 instead of 0x1258 and then I repeated 0x1258 in subsequent posts. And that's why I thought it was within your range but then confused myself with that typo of 0x1258 again. Sorry about that. So I think 0x1256 was within the range you saw reads/writes to but not the change I was looking for.
Right. 0x1256 which is part of the 32 bit value at 0x1254. 0x1254 is Link1 and it is not 32 different bits - it is a 32 bit value which is a return address to code in ROM (specifically in the HWInit part of the ROM). There's no RAM or stack during this time in the boot process, so offsets 0x1000..0x12ff in NVRAM are used. Return addresses are sometimes stored in the NVRAM Link# fields in that range.
 
I traced through parts of the shutdown code via MacsBug today under MacOS 8.6 and found where it's writing that '9' to NVRAM. There's a chain of handlers invoked during the shutdown and it looks to be in one of them -- I'm guessing these are the registered shutdown handlers. The first handler unmounts the drives and ejects any floppy disks. The second handler is the one I'm interested in. It calls gestalt a few times, grabs the trap address for the Expansion Manager and then looks like it conditionally writes a '0x09' to a byte in NVRAM. Need to look for something similar in System 7.6.1 and see if there it's writing it unconditionally.
 
The gestalt calls seem to be for the 'misc' and 'kdia' selectors. If 'misc' is supported, it's clearing something out a $0ddc and if 'kdia' is supported, it's reading something at $0dd8 offset $68. If that value is non-zero it is written to NVRAM otherwise it defaults to $09. It then reads bit 6 of $2400 and if set, skips the write. Then it checks bit 1 at $2400, bit 4 at $2401, and bit 3 at $2402 and if any of those are set, it writes to NVRAM at the byte at offset $1043 and then triggers the $032f selector with the expansion manager. I don't think I see any other checks in the handler for whether it should write to NVRAM (0x09 or whatever was at $0dd8) so the preference from the Memory control panel is at at one of those bits in $2400-$2402?
 
Oh hmm.. I turned off the memory tests and stepped through the code again (this is still on MacOS 8.6). I wanted to see where it branches away from writing to NVRAM. With the memory tests turned off, it looks like the call to Gestalt for the 'kdia' selector returns 0. And it bails there.
 
The gestalt calls seem to be for the 'misc' and 'kdia' selectors.
These appear to be from the gpch resources.
A couple bits of misc are documented in Inside Macintosh. What bit does it check?
kdia is undocumented.

If 'misc' is supported, it's clearing something out a $0ddc and if 'kdia' is supported, it's reading something at $0dd8 offset $68. If that value is non-zero it is written to NVRAM otherwise it defaults to $09.
$ddc is BootGlobPtr which I think points to a StartGlobals record.
$dd8 is UnivInfoPtr which is type ProductInfo. $68 is beyond the offsets documented in supermario (unless you meant decimal 68). The version is a byte at offset $17. supermario defines version 0 and version 1; both seem to have the same set of fields.

It then reads bit 6 of $2400 and if set, skips the write. Then it checks bit 1 at $2400, bit 4 at $2401, and bit 3 at $2402 and if any of those are set, it writes to NVRAM at the byte at offset $1043 and then triggers the $032f selector with the expansion manager. I don't think I see any other checks in the handler for whether it should write to NVRAM (0x09 or whatever was at $0dd8) so the preference from the Memory control panel is at at one of those bits in $2400-$2402?
Where does the $2400 address come from? Is it a field of BootGlobPtr or UnivInfoPtr or is it from a different low memory global (system symbol)?

Selector 032f is undocumented. 303C 032F AAF3 is found in gpch resources. My DumpNameRegistry source code has these:
Code:
	kReadNVRAMSelector			=	$022E;
	kWriteNVRAMSelector 		=	$032F;
which I mentioned at https://68kmla.org/bb/index.php?threads/the-great-gazelle-pci-hack-thread-part-2.38360/post-503281

In terms of CFM, maybe these get to NVRAMRead and NVRAMWrite in NVRAMServicesLib? I haven't checked.
 
A couple bits of misc are documented in Inside Macintosh. What bit does it check?

Bit 1 is tested. I think I saw that Bit 0 and Bit 2 are documented only.

$ddc is BootGlobPtr which I think points to a StartGlobals record.
$dd8 is UnivInfoPtr which is type ProductInfo. $68 is beyond the offsets documented in supermario (unless you meant decimal 68). The version is a byte at offset $17. supermario defines version 0 and version 1; both seem to have the same set of fields.

Hex $68.

Where does the $2400 address come from? Is it a field of BootGlobPtr or UnivInfoPtr or is it from a different low memory global (system symbol)?

This was a static address so another global.
 
Traced through on System 7.6.1 and it's very similar.
  • Same check of bit 1 on the response to the 'misc' gestalt selector before deciding whether to clear a field at $0ddc.
  • Same check to determine if the expansion manager trap exists.
  • On System 7.6.1, it does NOT look for the 'kdia' gestalt selector but just goes to look at $0dd8 and attempts to read offset $68 and if it's non-zero, uses it otherwise uses 0x09.
  • It then checks bit 6 at $2400 and if it's set, skips the NVRAM update.
  • It then checks bit 1 at $2400, 4 at $2401, 3 at $2402, and if any are set, it writes to NVRAM, otherwise skips.
  • Uses the same NVRAM write selector (0x32f) to update NVRAM.
Just need to understand what is at $2400-$2402 and how it's set. Will need to look at the Memory control panel code now on OS 8.6.
 
Looked at the disassembled code for the Memory control panel in Mac OS 8.6. So far look at what happens when you close the control panel. It looks like it saves a copy of the settings inside the System Folder -> Preferences -> Memory Preferences file. If the ram test is disabled, it creates a resource of type 'kdia' with ID=0 in that preferences file. It is 0 length so no contents. If the ram test is enabled, it removes this resource if it exists. It looks like it's just a copy of the settings to keep for itself. I don't really see anything else interesting when it closes.

Will look at if there's anything when the two radio buttons are toggled to see if it does something live when the user clicks on them.
 
For the MacOS 8.6 Memory CDEV, what it does:
  • On mouse click of the Startup Memory Tests On
    • Calls _DeleteGestaltValue for 'kdia'.
  • On mouse click of the Startup Memory Tests Off
    • Calls _NewGestaltValue for 'kdia'.
  • On close of the control panel
    • Makes changes to the System Folder -> Preferences -> Memory Preferences file
      • If Startup Memory Tests On, removes any 'kdia' resource from the preferences file.
      • If Startup Memory Tests Off, creates a 'kdia' resource ID=0 with 0 contents in the preferences file.
Then on shutdown:
  • Calls gestalt for 'kdia'
    • If noErr, skip writing anything to NVRAM.
    • If err:
      • Checks bit 6 at $2400 and if it's set, skips writing anything to NVRAM.
      • Checks bit 1 at $2400, 4 at $2401, 3 at $2402, and if any are set, it writes 0x09 or value from offset $68 at $0dd8 to NVRAM, otherwise skips.
On MacOS 8.6, the main gate seems to be that 'kdia' gestalt.

On System 7.6.1, the 'kdia' checks are missing.. but it still has the checks for the memory at $2400-$2402. Seems like the $2400-$2402 is a hardware check of some kind and probably not pertinent (to see if NVRAM is available or ?). In that sense it looks like on System 7.6.1, it will always force a memory check.

Going to look at the shutdown handlers (never written one before) and see if registering one that runs last could overwrite the change to NVRAM. Or if that won't work, will have to look into a patch, either dynamic at runtime or static.
 
Looks like I should be able to register a shutdown procedure that runs after Apple's that writes to NVRAM. Already see my procedure being called after Apple's. Only question is whether it's too late in the shutdown sequence and some subsystems aren't available anymore. But we'll see.
 
Ok, cooked up a system extension that will register a shutdown proc and overwrite that 0x09 with a 0x00 which then skips the ram test on the next cold boot.

All it does is register a shutdown procedure which executes before power off and essentially mimics what Apple does (even in System 7.6.1) but instead of writing the 0x09, it writes a 0x00 instead. It also does the check for the presence of the expansion manager trap as well as the checks against address $2400-$2402 as I believe it might be hardware checks on whether this is allowed or not. I skipped the gestalt calls ('misc' and 'kdia') as whatever Apple's code does with the 'misc' response is already done as I'm not removing their code. And the 'kdia' check is not present in Apple's 7.6.1 implementation so I skipped that as well.

Tested on System 7.6.1 only and on my Power Macintosh 8500. Seems to work ok. Attached below if anyone wants to try it.

noramtest.png

May work on a CDEV version later that provides the ability to toggle it on/off. But I don't think it's a big deal to just disable it using Extension Manager if you want the ram test on next cold boot.
 

Attachments

Last edited:
If you grep for (\$|0x)0*2400\b you find it in
Boot3.a, UniversalEqu.h, InternalOnlyEqu.a, InternalOnlyEqu.r, StartInit.a, ShutDownMgr.a
elliotnunn/boot3
elliotnunn/CubeE
elliotnunn/mac-rom
elliotnunn/supermario

0xDD0 is AddrMapFlags - a set of 32 boolean flags (one per bit).
0x2400 is AdrMapFlags1 - 32 additional boolean flags.
0x2404 is AdrMapFlags2 - last 32 boolean flags. 96 total.

TestForBaseAddr describes the usage of the flags.

A flag bit (one of BasesValidFlags) set to 1 means there's a base address corresponding to that bit in the DecoderInfo struct pointed to by the decoderInfoPtr field (not a pointer - it's an offset) of the ProductInfo struct pointed to by the low memory global UnivInfoPtr at 0xDD8.

GetUnivInfoBaseAddr describes the usage of decoderInfoPtr.

These are a list of the base addresses and their offset in DecoderInfo struct (divide by 4 for the corresponding BasesValidFlags bit number in AddrMapFlags):
Code:
0x000	ROMAddr // corresponding BasesValidFlags name is ROMExists
0x004	DiagROMAddr
0x008	VIA1Addr
0x00c	SCCRdAddr
0x010	SCCWrAddr
0x014	IWMAddr
0x018	PWMAddr
0x01c	SoundAddr
0x020	SCSIAddr
0x024	SCSIDackAddr
0x028	SCSIHskAddr
0x02c	VIA2Addr
0x030	ASCAddr
0x034	RBVAddr
0x038	VDACAddr
0x03c	SCSIDMAAddr
0x040	SWIMIOPAddr
0x044	SCCIOPAddr
0x048	OSSAddr
0x04c	FMCAddr
0x050	RPUAddr
0x054	OrwellAddr
0x058	JAWSAddr
0x05c	SonicAddr
0x060	SCSI96Addr1
0x064	SCSI96Addr2
0x068	DAFBAddr
0x06c	PSCAddr
0x070	ROMPhysAddr
0x074	PatchROMAddr
0x078	NewAgeAddr
0x07c	Unused31Addr
0x080	SingerAddr
0x084	DSPAddr
0x088	MACEAddr
0x08c	MUNIAddr
0x090	AMICAddr
0x094	PrattAddr
0x098	SWIM3Addr
0x09c	AwacsAddr
0x0a0	CivicAddr
0x0a4	SebastianAddr
0x0a8	BARTAddr
0x0ac	GrandCentralAddr
0x0b0	Unused44Addr
0x0b4	Unused45Addr
0x0b8	Unused46Addr
0x0bc	Unused47Addr
0x0c0	Unused48Addr
0x0c4	Unused49Addr
0x0c8	Unused50Addr
0x0cc	Unused51Addr
0x0d0	Unused52Addr
0x0d4	Unused53Addr
0x0d8	Unused54Addr
0x0dc	Unused55Addr
0x0e0	Unused56Addr
0x0e4	Unused57Addr
0x0e8	Unused58Addr
0x0ec	Unused59Addr
0x0f0	Unused60Addr
0x0f4	Unused61Addr
0x0f8	FooAddr
0x0fc	Unused63Addr
0x100	Unused64Addr
0x104	BarAddr
0x108	Unused66Addr
0x10c	Unused67Addr
0x110	Unused68Addr
0x114	Unused69Addr
0x118	Unused70Addr
0x11c	Unused71Addr
0x120	Unused72Addr
0x124	Unused73Addr
0x128	Unused74Addr
0x12c	Unused75Addr
0x130	Unused76Addr
0x134	Unused77Addr
0x138	Unused78Addr
0x13c	Unused79Addr
0x140	Unused80Addr
0x144	Unused81Addr
0x148	Unused82Addr
0x14c	Unused83Addr
0x150	Unused84Addr
0x154	Unused85Addr
0x158	Unused86Addr
0x15c	Unused87Addr
0x160	Unused88Addr
0x164	Unused89Addr
0x168	Unused90Addr
0x16c	Unused91Addr
0x170	Unused92Addr
0x174	Unused93Addr
0x178	Unused94Addr
0x17c	Unused95Addr
 
The gestalt calls seem to be for the 'misc' and 'kdia' selectors. If 'misc' is supported, it's clearing something out a $0ddc and if 'kdia' is supported, it's reading something at $0dd8 offset $68. If that value is non-zero it is written to NVRAM otherwise it defaults to $09. It then reads bit 6 of $2400 and if set, skips the write. Then it checks bit 1 at $2400, bit 4 at $2401, and bit 3 at $2402 and if any of those are set, it writes to NVRAM at the byte at offset $1043 and then triggers the $032f selector with the expansion manager. I don't think I see any other checks in the handler for whether it should write to NVRAM (0x09 or whatever was at $0dd8) so the preference from the Memory control panel is at at one of those bits in $2400-$2402?

Traced through on System 7.6.1 and it's very similar.
  • Same check of bit 1 on the response to the 'misc' gestalt selector before deciding whether to clear a field at $0ddc.
  • Same check to determine if the expansion manager trap exists.
  • On System 7.6.1, it does NOT look for the 'kdia' gestalt selector but just goes to look at $0dd8 and attempts to read offset $68 and if it's non-zero, uses it otherwise uses 0x09.
  • It then checks bit 6 at $2400 and if it's set, skips the NVRAM update.
  • It then checks bit 1 at $2400, 4 at $2401, 3 at $2402, and if any are set, it writes to NVRAM, otherwise skips.
  • Uses the same NVRAM write selector (0x32f) to update NVRAM.
Just need to understand what is at $2400-$2402 and how it's set. Will need to look at the Memory control panel code now on OS 8.6.

Then on shutdown:
  • Calls gestalt for 'kdia'
    • If noErr, skip writing anything to NVRAM.
    • If err:
      • Checks bit 6 at $2400 and if it's set, skips writing anything to NVRAM.
      • Checks bit 1 at $2400, 4 at $2401, 3 at $2402, and if any are set, it writes 0x09 or value from offset $68 at $0dd8 to NVRAM, otherwise skips.
On MacOS 8.6, the main gate seems to be that 'kdia' gestalt.

On System 7.6.1, the 'kdia' checks are missing.. but it still has the checks for the memory at $2400-$2402. Seems like the $2400-$2402 is a hardware check of some kind and probably not pertinent (to see if NVRAM is available or ?). In that sense it looks like on System 7.6.1, it will always force a memory check.

Code:
43	0x0ac	GrandCentralAddr	GrandCentralExists,
44	0x0b0	Unused44Addr		PBX1Exists,
45	0x0b4	Unused45Addr		PBX2Exists,
46	0x0b8	Unused46Addr		PBX3Exists,
47	0x0bc	Unused47Addr		ATAExists,
48	0x0c0	Unused48Addr		HammerHeadExists,
49	0x0c4	Unused49Addr		PlatinumExists,
50	0x0c8	Unused50Addr		Pratt2Exists,
51	0x0cc	Unused51Addr		PSXExists,
52	0x0d0	Unused52Addr		OHareExists,
53	0x0d4	Unused53Addr		GrackleExists,
54	0x0d8	Unused54Addr		HydraExists,
55	0x0dc	Unused55Addr		SuperIOExists,
56	0x0e0	Unused56Addr		SIOExists,
57	0x0e4	Unused57Addr		HeathrowExists,
58	0x0e8	Unused58Addr		MFMFloppyExists,
59	0x0ec	Unused59Addr		MFMMethodsVectorExists,
60	0x0f0	Unused60Addr		FatManExists,
61	0x0f4	Unused61Addr		OpenPICExists,
62	0x0f8	FooAddr				CHRPNess,
63	0x0fc	Unused63Addr		GatwickExists


bit 6 of 2400 = 32 + 24 + 6 = 62 = CHRPNess
bit 1 of 2400 = 32 + 24 + 1 = 57 = HeathrowExists
bit 4 of 2401 = 32 + 16 + 4 = 52 = OHareExists
bit 3 of 2402 = 32 + 8 + 3 = 43 = GrandCentralAddr

NVRAM is part of GrandCentral, OHare, or Heathrow. These are all CHRP machines.

I suppose it may be possible to scan ROM dumps to find ROMs that set these bits.
 
Last edited:
UniversalTables.a shows how the bits are setup for different machines. Just need an algorithm to find this in the ROM.
Edited my previous post above.
 
Last edited:
The code seems to do the "run startup ram test" byte write as long as CHRPNess (bit 6 of $2400) is set AND one of the other three (HeathrowExists, OHareExists, GrandCentralAddr) is set.

I have done the same tests/checks in the No Ram Test system extension so I think any model that Apple supported with their code should work here.

The read of the 'misc' gestalt is unnecessary as Apple's code seems to do that no matter what before doing anything else with 'kdia' or the memory at $2400-$2402, so since that code runs before mine, I don't have to mimic it.

EDIT: The only thing I should probably go back and add is reading offset $68 of $0dd8, and using that instead of 0x09 if it's non zero. Not clear to me whether some of the other ROMs will want a different value there and if that's what the check is for or not.

Actually the $0dd8 stuff doesn't matter either because it would be important to know if you are enabling the startup ram tests but I'm putting a zero there to not run them so doesn't matter. The only concern is if some other models are using a non-zero value to signify not to run the test but I wouldn't think that would be the case.
 
Last edited:
Back
Top