Extended PRAM


 

Extended PRAM Map

Offset
(hex)
Length
(dec)
Related to
1 1Used by a system program _InternalWait
8 4Looks like the last 4 bytes of the regular PRAM
(See IM, Vol II, OS Util)
1016Looks like the first 16 bytes of the regular PRAM
(See IM, Vol II, OS Util)
78 4Startup Disk info (apparently, SCSI id)
7C2System Beep. As was pointed out earlier, it is in fact an id (short int) of the corresponding 'snd ' resource in the System file;
accessed through the Sound control panel
7E1Used by a system program _InitProcMenu
7F1Apparently it has something to do with the way windows and dialogs appear on the screen
802Used by a system program _GetVideoDefault
apparently, some default video settings
826Hilite Color, apparently in the RGB format,
set up through the Color control panel
8A1 Bit field: Memory/cache control flags
1xxx xxxx
68040 Cache is off
Toggled through Cache control panel
0xxx xxxx
68040 Cache is on
xxxx x1x1
32-bit addressing is on
(toggled through the Memory control panel)
AF1Has something to do with the RAM disk size
B84 A 32-bit field whose
high-order 13 bits
this Mac's birthday: the number of 2-day intervals since Jan 2, 1989
this field may not be zero
low-order 19 bits
total amount of time this Mac has been up since its birthday (first boot), in 5-min intervals
The explanation of this field is courtesy of John Goodman, who figured it all out, and to who can tell much more details about this field
BD33looks like the name of the default AppleTalk zone (in Str32 format)
Used (and set!) by some system programs in ROM,
DE 2at addresses 8009d544 and 8009d73C
E04has something to do with the network: an AppleTalk active/inactive flag, and the selected network access (say, LocalTalk or EtherTalk).
See Chooser and Network control panel
E412Latitude/Longitude of the place this Mac is at.
Set up through the Map control panel



 

Saving and Restoring xPRAM

Applications/Control panels/Extensions that can save the current xPRAM settings, and restore them at a later moment:




 

Reading and Writing xPRAM

 

using m68k assembly

The following code reads or writes into any field of xPRAM given the field's offset and length:
        LEA     buf,a0          ; where to get/put the info
        MOVE.W  length,d0
        SWAP    d0              ; Length in the hi word of D0
        MOVE.W  offset,d0       ; Offset in the lo word of D0
        DC.W    $A051 or $A052  ; _ReadXPRam or _WriteXPRam
On return, D0 contains 0 (no error) or -1 (failure: say, the offset is not within the 256-byte xPRAM).
The code above can be used to read/write the entire xPRAM: set the offset to 0 and the length to 256. Note, some old Mac models (II's and IIx's) had a bug in their ROM that prevents from writing the very last byte of xPRAM (offset=255).


 

using C/C++ on a 68k Mac

To read size bytes of the xPRAM into a (previously allocated) buffer where, starting from the beginning of xPRAM:
		// This is
		//      CLR.L     D0            offset would be 0
		//      MOVE.W    (A7)+,D0      size -> lo word of d0
		//      SWAP      D0            size -> hi word of d0
		//      MOVEA.L   (A7)+,A0      where -> A0
		//      _ReadXPRam
pascal void read_extended_PRAM(char * where, const short size) =
{ 0x4280, 0x301F, 0x4840, 0x205F, 0xA051  };
When I wrote this code, I had only Symantec C++ 6.0.1 compiler, which didn't permit asm{} inlines in C++ code. So I had to code in hex...

Writing to xPRAM is similar to reading, only one has to use trap A052 rather than A051. The following function writes size bytes from a buffer where into xPRAM, starting at offset:

		// This is
		//      MOVE.L  (A7)+,D0
		//      MOVEA.L (A7)+,A0   where -> A0
		//      _WriteXPRam
pascal void write_extended_PRAM
        (const char * where, const short offset, const short size) =
{0x201F, 0x205F, 0xA052};


 

How _ReadXPRam/_WriteXPRam do their job

Here's an insight (gained from tracing A051/A052 traps in MacsBug):
these traps use some sort of serial (bit-by-bit) interface to access the clock chip, via the bus address 0x50f00000 (or something like this).


 

How did I find out the xPRAM layout

Traps _ReadXPRam/_WriteXPRam are not documented, let alone the xPRAM.
I figured the stuff out by messing around with MacsBug: I restarted the system, and dropped into the debugger as soon as I could. I set breaks on traps A051 (_ReadXPRam) and A052 (_WriteXPRam), and let the system go on booting and run. I played with all control panels and watched if setting/resetting some values ends up in the debugger. There, a mere peek at the contents of D0 will tell everything: the location (byte-offset) in xPRAM that is being read/written is in the lower-order word of D0, and the size of the data is in the high-order-word. This is exactly the way I reengineered the xPRAM map (well, I also disassembled a few control panels, e.g., Sound, Cache, and Memory)


 

Universal (PowerMac/m68K) xPRAM reader

A compiled version of this code (a PPC application) is also available:
     xPRAMdump-ppc [.cpt.hqx, 29K]
Besides the application, this archive includes the source code below.

// 			Printing out the contents of the xPRAM
// The trick is that _ReadXPRam/_WriteXPRam traps are available only
// from within 68K universe. So, if this code runs in the PowerPC mode,
// we've got to switch universes before running M68K code sequences....

#include <stdio.h>
#include <MixedMode.h>


		// This is
		//	CLR.L	  D0				offset would be 0
		//	MOVE.W    $4(A7),D0		size -> lo word of d0
		//	SWAP	  D0				size -> hi word of d0
		//	MOVEA.L	  6(A7),A0		where -> A0
		//	_ReadXPRam
		//	MOVEA.L (A7)+,A0		standard PASCAL epilogue
		//	ADDQ.W	#$6,A7
		//	JMP	(A0)
		//	RTS
		// This is a sequence of M68K instructions; unfortunately,
		// a PowerMac compiler doesn't understand them. So we've
		// got to assemble by hand <sigh>
		//
		// BTW, to write into xPRAM, replace 0xA051 in the sequence
		// below with 0xA052
//pascal void read_extended_PRAM(char * where, const short size) =
static short read_extended_PRAM []=
{ 0x4280, 0x302F, 0x0004, 0x206F, 0x006, 0x4840, 0xA051, 0x205F, 0x5C4F, 0x4ED0  };


#define COMP_NORET_2(name, a1, a2)											\
	name##_procinfo = kPascalStackBased				\
		| STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(a1)))	\
		| STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(a2)))
#define RD_ALLOC(routine) static RoutineDescriptor			\
	routine##_RD = BUILD_ROUTINE_DESCRIPTOR(routine##_procinfo, routine)

enum {
  COMP_NORET_2(read_extended_PRAM,char *,const short)
};

void main(void)
{
  unsigned char whole_xPRAM_buffer[256];
  UniversalProcPtr u_read_extended_PRAM = 
  	NewRoutineDescriptor((long (*)())read_extended_PRAM,
  			     read_extended_PRAM_procinfo,
  			     kM68kISA);
  CallUniversalProc(u_read_extended_PRAM,read_extended_PRAM_procinfo,
  		whole_xPRAM_buffer,sizeof(whole_xPRAM_buffer));
  DisposeRoutineDescriptor(u_read_extended_PRAM);
 
  printf("\ncontents of the xPRAM\n");
  for(register int i=0; i<sizeof(whole_xPRAM_buffer); i+=16)
  {
    printf("\n%04x  ",i);
    for(register int j=0; j<16; j++)
	 printf("%s%02x", j%4 == 0 ? " " : "", whole_xPRAM_buffer[i+j]);
  }
}
I tested the code on PowerMac 7100/80 and 8500/132, using CodeWarrior C++ versions 9 and 12.


Last updated January 16, 1998

This site's top page is http://okmij.org/ftp/

oleg-at-okmij.org
Your comments, problem reports, questions are very welcome!