Hi everyone,
I have added a new component to the Mac OS ROM: the "Wedge". The Wedge is a chunk of C code inserted into the ROM that runs between the Trampoline and the NanoKernel. It takes the structures prepared by the Trampoline, carefully patches them, spits out some textual debug output, and then hands control to the NanoKernel. The debug output remains hidden in memory while the machine boots up. Once (and if) the machine is booted, it can be read by a small app, WedgeLogReader.
At present the only task of the Wedge is to expand the main segment of Mac OS memory. This allows an extra 128MB of RAM to be used, on top of the 1.5GB limit.
Why go to the trouble of bootstrapping a C runtime? Two reasons:
- Ease. Patching the PageMap is too complex to accomplish reliably in RISC assembly (see the crash reports above).
- Portability. The code can be tested on your machine in userspace before risking a crash on boot.
And what cool stuff is in the attached archive?
- PowerMacInfo, in case you didn't already have a copy. This will crash on a Wedge ROM, because it hardcodes the InfoRecord Page address.
- WedgeDryRun, a text app to test the Wedge code on your machine. If this crashes, let me know.
- Mac OS ROM, with all the trimmings. Besides bumping the RAM limit slightly, this should work on all unsupported G4 desktops (including the 9serve, MacOS Plus!). The annoying NanoKernel log window is off by default. If you find it stable and you want the extra RAM, then this is ready for production use!
- WedgeLogReader, a text app to dump the Wedge log left over from boot. Naturally, it only shows useful information if you booted with the Wedge.
- NKLogReader, again in case you didn't have a copy.
Those testers who had trouble with the previous patched ROMs, would you please try this out? The best information to post would be: WedgeDryRun output, WedgeLogReader output, NKLogReader output, and before/after screenshots of About This Computer. Please post text inline! That way I can read it on my phone, and it gets indexed by Google.
For the morbidly curious, here is the Wedge C code. The same code runs in both the attached ROM and the WedgeLogReader. I don't suppose that one of the admins feels like changing the tab size to 4?Code: [Select]#include <PPCInfoRecordsPriv.h>
#include <MacTypes.h>
#define kFlagNone 0
#define kFlagIRP 1
#define kFlagKDP 2
#define kFlagEDP 3
#define LA_InfoRecord_Orig 0x5fffe000UL
#define LA_UniversalArea_Orig 0x64000000UL
#define LA_RiscRom_Orig 0x68000000UL
#define LA_ConfigInfo_Orig 0x68fef000UL
#define LA_KernelData_Orig 0x68ffe000UL
#define LA_KernelData_Orig 0x68fff000UL
#define kConfigInfoSize 4096
#define kHardwareInfoSize 192
#define kPatchInfoRecord 0x00000001UL
#define kPatchUniversalArea 0x00000010UL
#define kCanPatchEmulator 0x80000000UL
#define kDelta 0x80000000UL
void *memcpy(void *dest, void *src, long n)
{
long i;
char *d = (char *)dest;
char *s = (char *)src;
if(dest < src) /* copy left to right */
{
for(i=0; i<n; i++) d[i] = s[i];
}
else /* copy right to left */
{
for(i=n-1; i>=0; i--) d[i] = s[i];
}
return dest;
}
void *memset(void *dest, int v, long n)
{
char *d = (char *)dest;
while(n) d[--n] = (char)v;
return dest;
}
struct PME
{
unsigned long word1; /* LogicalPageIndexInSegment(16b) || PageCountMinus1(16b) */
unsigned long word2; /* PhysicalPage(20b) || pageAttr(12b) */
};
typedef struct PME PME;
PME *getPageMapPtr(NKConfigurationInfo *ConfigInfo)
{
return (PME *)((long)ConfigInfo + (long)ConfigInfo->PageMapInitOffset);
}
int pmeIsBlank(PME *pme)
{
if(pme->word1 != 0x0000ffffUL) return 0;
if((pme->word2 & 0x00000f00UL) != 0x00000a00UL) return 0;
return 1;
}
int segmentOf(unsigned long LA)
{
return LA >> 28;
}
/*
Create a PageMapEntry (specifying a logical-to-physical mapping within a PowerPC segment)
and insert it into a ConfigInfo struct, taking care not to corrupt the structure.
(Intended to replicate the behaviour of the Trampoline, based on its debug output)
*/
int AddPageMapEntry(NKConfigurationInfo *ci, unsigned long LA, unsigned long count, unsigned long PA, unsigned long pageAttr, unsigned long flags)
{
PME *pageMapBase = getPageMapPtr(ci);
PME newEnt;
int entryOffset; /* offset of our new entry within the PageMap (bytes) */
int i;
/* Format string lifted from Trampoline (changed a tiny bit). */
printf("AddPageMapEntry: LA = 0x%08X, count = 0x%05X, PA = 0x%08X, pageAttr = 0x%04X, flags = 0x%02X.\n", LA, count, PA, pageAttr, flags);
/* "Design" the new entry. */
newEnt.word1 = ((LA << 4) & 0xffff0000UL) | (count - 1);
newEnt.word2 = (PA & 0xfffff000UL) | pageAttr;
/* Choose an offset for the entry. */
entryOffset = ci->SegMap32SupInit[segmentOf(LA) * 2];
for(;;)
{
PME *existing;
existing = (PME *)((long)pageMapBase + (long)entryOffset);
if(pmeIsBlank(existing)) break;
if((existing->word1 & 0xffff0000UL) > (newEnt.word1 & 0xffff0000UL)) break;
entryOffset += sizeof(PME);
}
/* Shift the entries above our new entry by 8 bytes. */
for(i=0; i<8; i++)
{
if(*((char *)pageMapBase + ci->PageMapInitSize + i) != 0)
{
printf("PageMap overflow!\n", entryOffset/sizeof(PME));
return 100;
}
}
for(i = ci->PageMapInitSize - 1; i >= entryOffset; i--)
{
*((char *)pageMapBase + i + 8) = *((char *)pageMapBase + i);
}
/* Bump the declared PageMap size by 8 bytes. (ignored by kernel?) */
ci->PageMapInitSize += sizeof(PME);
/* The SegMap (four copies) contains an offset into the PageMap at every second word -- update these. */
for(i=segmentOf(LA)+1; i<16; i++)
{
ci->SegMap32SupInit[i * 2] += sizeof(PME);
ci->SegMap32UsrInit[i * 2] += sizeof(PME);
ci->SegMap32CPUInit[i * 2] += sizeof(PME);
ci->SegMap32OvlInit[i * 2] += sizeof(PME);
}
/* Adjust the pointers to the special PageMap entries. */
if(ci->PageMapIRPOffset >= entryOffset) ci->PageMapIRPOffset += sizeof(PME);
if(ci->PageMapKDPOffset >= entryOffset) ci->PageMapKDPOffset += sizeof(PME);
if(ci->PageMapEDPOffset >= entryOffset) ci->PageMapEDPOffset += sizeof(PME);
/* Set the correct pointer if it is a special one */
if(flags == kFlagIRP)
ci->PageMapIRPOffset = entryOffset;
else if(flags == kFlagKDP)
ci->PageMapKDPOffset = entryOffset;
else if(flags == kFlagEDP)
ci->PageMapEDPOffset = entryOffset;
/* Save our new entry in the gap we have made in the PageMap. */
memcpy((char *)pageMapBase + entryOffset, &newEnt, sizeof(PME));
return 0;
}
/*
Create a blank PageMap inside a pre-existing ConfigInfo structure, with only
those "dummy" entries that the Trampoline would create before calling
AddPageMapEntry.
(Intended to replicate the behaviour of the Trampoline, based on its debug output)
*/
void ErasePageMapTable(NKConfigurationInfo *ci)
{
PME *pageMapBase;
long *pmp;
int seg;
printf("ErasePageMapTable at offset 0x%x\n\n", ci->PageMapInitOffset);
/* Zero out the existing PageMap */
pageMapBase = getPageMapPtr(ci);
memset(pageMapBase, 0, ci->PageMapInitSize);
/* Count up with pmp */
pmp = (long *)pageMapBase;
ci->PageMapInitOffset = (long)pageMapBase - (long)ci;
for(seg=0; seg<16; seg++)
{
ci->SegMap32SupInit[seg * 2] =
ci->SegMap32UsrInit[seg * 2] =
ci->SegMap32CPUInit[seg * 2] =
ci->SegMap32OvlInit[seg * 2] = (long)pmp - (long)pageMapBase;
if(seg <= 5)
{
*pmp++ = 0x0000ffffUL; *pmp++ = 0x00000a00UL;
*pmp++ = 0x0000ffffUL; *pmp++ = 0x00000a00UL;
}
else if(seg >= 6 && seg <= 7)
{
*pmp++ = 0x0000ffffUL; *pmp++ = 0x00000a01UL;
*pmp++ = 0x0000ffffUL; *pmp++ = 0x00000a01UL;
*pmp++ = 0x0000ffffUL; *pmp++ = 0x00000a00UL;
}
else if(seg >= 8)
{
*pmp++ = 0x0000ffffUL; *pmp++ = 0x00000a01UL + (seg << 28);
*pmp++ = 0x0000ffffUL; *pmp++ = 0x00000a00UL;
}
}
ci->PageMapInitSize = (long)pmp - (long)pageMapBase;
/* Zero out the special pointers */
ci->PageMapIRPOffset = 0;
ci->PageMapKDPOffset = 0;
ci->PageMapEDPOffset = 0;
}
int PatchMacOSAddressSpace(long patches, unsigned long makeMemAvail, NKConfigurationInfo *ci, NKConfigurationInfo *newci, NKHWInfo *hi, NKHWInfo *newhi)
{
int seg;
PME *pageMapBase;
PME *entryp;
unsigned long LA, newLA, count, PA, pageAttr, flags;
int ret;
int offset;
unsigned long i;
pageMapBase = getPageMapPtr(ci);
ErasePageMapTable(newci);
printf("PatchMacOSAddressSpace: makeMemAvail %08x\n", makeMemAvail);
for(seg=0; seg<16; seg++)
{
for(offset = ci->SegMap32SupInit[seg*2];; offset += sizeof (PME)) /* Iterate over PMEs. */
{
entryp = (PME *)((long)pageMapBase + offset);
/* Misc error conditions */
if(seg < 15 && offset >= ci->SegMap32SupInit[(seg+1) * 2])
{
printf("Overran this segment of the PageMap!\n\n");
return 101;
}
if(offset >= ci->PageMapInitSize)
{
printf("Overran the whole PageMap!\n\n");
return 102;
}
if(pmeIsBlank(entryp)) break;
/* Extract info from PME */
LA = newLA = (seg << 28) | (entryp->word1 >> 4 & 0x0ffff000UL);
count = (entryp->word1 & 0x0000ffffUL) + 1;
PA = entryp->word2 & 0xfffff000UL;
pageAttr = entryp->word2 & 0x00000fffUL;
if(offset == ci->PageMapIRPOffset)
flags = kFlagIRP;
else if(offset == ci->PageMapKDPOffset)
flags = kFlagKDP;
else if(offset == ci->PageMapEDPOffset)
flags = kFlagEDP;
else
flags = kFlagNone;
printf(" nontrivial PME LA = 0x%08X, count = 0x%05X, PA = 0x%08X, pageAttr = 0x%04X, flags = 0x%02X.\n ", LA, count, PA, pageAttr, flags);
/* Delete those two annoying PMEs that signal to end the MacOS area */
/* (LA 50000000 count fffe PA 00000000 pageAttr a00) */
if((LA << 4) == 0 && (pageAttr & 0xf00) == 0xa00)
{
printf("MacOS area delimiter: skipping\n\n");
continue;
}
/* Move the InfoRecord page. */
if((patches & kPatchInfoRecord) && LA == LA_InfoRecord_Orig)
{
printf("**IRP**\n ");
newLA += kDelta;
/* IRP logical address in ConfigInfo */
newci->LA_InfoRecord = newLA;
/* IRP logical address is hardcoded into emulator by lis/ori, so change that. */
if(patches & kCanPatchEmulator)
{
unsigned short hi = LA >> 16;
unsigned short lo = LA & 0xffff;
unsigned short *em = (unsigned short *)0x00f60000UL;
for(i=0; i<0x10000; i+=2)
{
if(em[i+1] == hi && em[i+3] == lo)
{
printf("Patching Emulator lis/ori @ %05x\n ", i*2);
em[i+1] = newLA >> 16;
em[i+3] = newLA & 0xffff;
break;
}
}
}
}
/* Move the area containing the Universal structures and the Device Tree */
if((patches & kPatchUniversalArea) && LA == LA_UniversalArea_Orig)
{
printf("**Universal/DeviceTree area**\n ");
newLA += kDelta;
/* Logical address pointers in HardwareInfo */
newhi->DeviceTreeBase = hi->DeviceTreeBase - LA + newLA;
newhi->UniversalInfoTableBase = hi->UniversalInfoTableBase - LA + newLA;
}
if(newLA < makeMemAvail)
{
printf("makeMemAvail is too large with this PME in the way.\n\n");
return 103;
}
/* If this PME was unchanged then newLA will just equal the original LA. */
ret = AddPageMapEntry(newci, newLA, count, PA, pageAttr, flags);
if(ret) return ret;
printf("\n");
}
}
/* Done all meaningful PMEs... put the "MacOS area delimiter" back in */
printf(" Reinserting the MacOS area delimiters:\n");
for(i=0; i<2; i++)
{
printf(" ");
ret = AddPageMapEntry(newci, makeMemAvail & 0xf0000000UL, makeMemAvail >> 12 & 0xffffUL, 0UL, 0xa00, 0);
if(ret) return ret;
}
printf("\n");
return 0;
}
void DebugDumpPageMap(NKConfigurationInfo *ci)
{
PME *pageMapBase, *pme;
int i, j;
pageMapBase = getPageMapPtr(ci);
printf("DebugDumpPageMap\n");
for(i=0; i<ci->PageMapInitSize; i+=sizeof(PME))
{
for(j=0; j<16; j++)
{
if(ci->SegMap32SupInit[j*2] == i)
{
printf("%X ", j);
break;
}
}
if(j == 16) printf(" ");
pme = (PME *)((long)pageMapBase + i);
printf("%03x: %08x %08x", i, pme->word1, pme->word2);
if(i == ci->PageMapIRPOffset)
{
printf(" IRP");
}
else if(i == ci->PageMapEDPOffset)
{
printf(" EDP");
}
else if(i == ci->PageMapKDPOffset)
{
printf(" KDP");
}
printf("\n");
}
printf("\n");
}
/* Main function for Wedge patch */
void wedge(NKConfigurationInfo *ci, NKProcessorInfo *pi, NKSystemInfo *si, NKDiagnosticInfo *di, OSType rtasFour, unsigned long rtasProc, NKHWInfo *hi)
{
char ci_tmp[kConfigInfoSize], hi_tmp[kHardwareInfoSize];
int ret;
printf("Hello from the Wedge.\n");
printf(" ConfigInfo (r3) @ %08x\n", ci);
printf(" ProcessorInfo (r4) @ %08x\n", pi);
printf(" SystemInfo (r5) @ %08x\n", si);
printf(" DiagnosticInfo (r6) @ %08x\n", di);
printf(" RTAS (r7) = %08x\n", rtasFour);
printf(" RTASProc (r8) @ %08x\n", rtasProc);
printf(" HardwareInfo (r9) @ %08x\n", hi);
printf("\n");
/* PatchMacOSAddressSpace */
DebugDumpPageMap((NKConfigurationInfo *)ci);
printf("Rearranging the MacOS address space...\n\n");
memcpy(ci_tmp, ci, sizeof ci_tmp);
memcpy(hi_tmp, hi, sizeof hi_tmp);
ret = PatchMacOSAddressSpace(kPatchInfoRecord | kPatchUniversalArea | kCanPatchEmulator,
0x68000000UL,
(NKConfigurationInfo *)ci, (NKConfigurationInfo *)ci_tmp,
(NKHWInfo *)hi, (NKHWInfo *)hi_tmp);
if(!ret)
{
printf("Copying modified ConfigInfo and HWInfo over the originals.\n\n");
memcpy(ci, ci_tmp, sizeof ci_tmp);
memcpy(hi, hi_tmp, sizeof hi_tmp);
DebugDumpPageMap((NKConfigurationInfo *)ci);
}
else
{
printf("PatchMacOSAddressSpace failed with error %d.\n", ret);
}
/* Insert more clever, interesting patches here. */
/* Uses r3-r9 -- compiler doesn't really need a prototype for this. */
printf("\nHanding over to the NanoKernel.\n");
NanoKernelJump(ci, pi, si, di, rtasFour, rtasProc, hi);
}
/* Main function for MPW Tool */
void main(void)
{
char ci_tmp[kConfigInfoSize], hi_tmp[kHardwareInfoSize];
char *ci, *hi;
long nk_struct_ver, nk_struct_len;
int ret;
printf("Hello from the (dry-run) Wedge.\n");
ci = (char *)0x68fef000UL;
printf(" ConfigInfo @ %08x\n", ci);
NKLocateInfoRecord(6, &hi, &nk_struct_ver, &nk_struct_len);
printf(" HardwareInfo @ %08x\n", hi);
printf("\n");
DebugDumpPageMap((NKConfigurationInfo *)ci);
printf("Copying the system ConfigInfo and HardwareInfo structs.\n\n");
memcpy(ci_tmp, ci, sizeof ci_tmp);
memcpy(hi_tmp, hi, sizeof hi_tmp);
ret = PatchMacOSAddressSpace(kPatchInfoRecord | kPatchUniversalArea,
0x68000000UL,
(NKConfigurationInfo *)ci, (NKConfigurationInfo *)ci_tmp,
(NKHWInfo *)hi, (NKHWInfo *)hi_tmp);
if(!ret)
{
printf("PatchMacOSAddressSpace succeeded (but was forbidden from patching the Emulator).\n\n");
DebugDumpPageMap((NKConfigurationInfo *)ci_tmp);
}
else
{
printf("PatchMacOSAddressSpace failed with error %d.\n", ret);
}
}
And here is some sample output.Code: [Select]Hello from the Wedge.
ConfigInfo (r3) @ 00003000
ProcessorInfo (r4) @ 0fffff40
SystemInfo (r5) @ 0ffffe00
DiagnosticInfo (r6) @ 00000000
RTAS (r7) = 52544153
RTASProc (r8) @ 00000000
HardwareInfo (r9) @ 0ffffd40
DebugDumpPageMap
0 000: 0000ffff 00000a00
008: 0000ffff 00000a00
1 010: 0000ffff 00000a00
018: 0000ffff 00000a00
2 020: 0000ffff 00000a00
028: 0000ffff 00000a00
3 030: 0000ffff 00000a00
038: 0000ffff 00000a00
4 040: 0000ffff 00000a00
048: 0000ffff 00000a00
5 050: 0000fffd 00000a00
058: 0000fffd 00000a00
060: fffe0000 00000012 IRP
068: 0000ffff 00000a00
070: 0000ffff 00000a00
6 078: 4000017f 0ab00012
080: 8fef0000 00003013
088: 8ffe0000 00000011 KDP
090: 8fff0000 00000012 EDP
098: 0000ffff 00000a01
0a0: 0000ffff 00000a01
0a8: 0000ffff 00000a00
7 0b0: 0000ffff 00000a01
0b8: 0000ffff 00000a01
0c0: 0000ffff 00000a00
8 0c8: 0000ffff 8000003a
0d0: 0000ffff 80000a01
0d8: 0000ffff 00000a00
9 0e0: 0000000f 9000003a
0e8: 0020001f 9002003a
0f0: 80007fff 98000032
0f8: 0000ffff 90000a01
100: 0000ffff 00000a00
A 108: 0000ffff a0000a01
110: 0000ffff 00000a00
B 118: 0000ffff b0000a01
120: 0000ffff 00000a00
C 128: 0000ffff c0000a01
130: 0000ffff 00000a00
D 138: 0000ffff d0000a01
140: 0000ffff 00000a00
E 148: 0000ffff e0000a01
150: 0000ffff 00000a00
F 158: 0000ffff f000003a
160: 0000ffff f0000a01
168: 0000ffff 00000a00
Rearranging the MacOS address space...
ErasePageMapTable at offset 0x3ac
PatchMacOSAddressSpace: makeMemAvail 68000000
nontrivial PME LA = 0x50000000, count = 0x0FFFE, PA = 0x00000000, pageAttr = 0x0A00, flags = 0x00.
MacOS area delimiter: skipping
nontrivial PME LA = 0x50000000, count = 0x0FFFE, PA = 0x00000000, pageAttr = 0x0A00, flags = 0x00.
MacOS area delimiter: skipping
nontrivial PME LA = 0x5FFFE000, count = 0x00001, PA = 0x00000000, pageAttr = 0x0012, flags = 0x01.
**IRP**
Patching Emulator lis/ori @ 181e8
AddPageMapEntry: LA = 0xDFFFE000, count = 0x00001, PA = 0x00000000, pageAttr = 0x0012, flags = 0x01.
nontrivial PME LA = 0x64000000, count = 0x00180, PA = 0x0AB00000, pageAttr = 0x0012, flags = 0x00.
**Universal/DeviceTree area**
AddPageMapEntry: LA = 0xE4000000, count = 0x00180, PA = 0x0AB00000, pageAttr = 0x0012, flags = 0x00.
nontrivial PME LA = 0x68FEF000, count = 0x00001, PA = 0x00003000, pageAttr = 0x0013, flags = 0x00.
AddPageMapEntry: LA = 0x68FEF000, count = 0x00001, PA = 0x00003000, pageAttr = 0x0013, flags = 0x00.
nontrivial PME LA = 0x68FFE000, count = 0x00001, PA = 0x00000000, pageAttr = 0x0011, flags = 0x02.
AddPageMapEntry: LA = 0x68FFE000, count = 0x00001, PA = 0x00000000, pageAttr = 0x0011, flags = 0x02.
nontrivial PME LA = 0x68FFF000, count = 0x00001, PA = 0x00000000, pageAttr = 0x0012, flags = 0x03.
AddPageMapEntry: LA = 0x68FFF000, count = 0x00001, PA = 0x00000000, pageAttr = 0x0012, flags = 0x03.
nontrivial PME LA = 0x80000000, count = 0x10000, PA = 0x80000000, pageAttr = 0x003A, flags = 0x00.
AddPageMapEntry: LA = 0x80000000, count = 0x10000, PA = 0x80000000, pageAttr = 0x003A, flags = 0x00.
nontrivial PME LA = 0x90000000, count = 0x00010, PA = 0x90000000, pageAttr = 0x003A, flags = 0x00.
AddPageMapEntry: LA = 0x90000000, count = 0x00010, PA = 0x90000000, pageAttr = 0x003A, flags = 0x00.
nontrivial PME LA = 0x90020000, count = 0x00020, PA = 0x90020000, pageAttr = 0x003A, flags = 0x00.
AddPageMapEntry: LA = 0x90020000, count = 0x00020, PA = 0x90020000, pageAttr = 0x003A, flags = 0x00.
nontrivial PME LA = 0x98000000, count = 0x08000, PA = 0x98000000, pageAttr = 0x0032, flags = 0x00.
AddPageMapEntry: LA = 0x98000000, count = 0x08000, PA = 0x98000000, pageAttr = 0x0032, flags = 0x00.
nontrivial PME LA = 0xF0000000, count = 0x10000, PA = 0xF0000000, pageAttr = 0x003A, flags = 0x00.
AddPageMapEntry: LA = 0xF0000000, count = 0x10000, PA = 0xF0000000, pageAttr = 0x003A, flags = 0x00.
Reinserting the MacOS area delimiters:
AddPageMapEntry: LA = 0x60000000, count = 0x08000, PA = 0x00000000, pageAttr = 0x0A00, flags = 0x00.
AddPageMapEntry: LA = 0x60000000, count = 0x08000, PA = 0x00000000, pageAttr = 0x0A00, flags = 0x00.
Copying modified ConfigInfo and HWInfo over the originals.
DebugDumpPageMap
0 000: 0000ffff 00000a00
008: 0000ffff 00000a00
1 010: 0000ffff 00000a00
018: 0000ffff 00000a00
2 020: 0000ffff 00000a00
028: 0000ffff 00000a00
3 030: 0000ffff 00000a00
038: 0000ffff 00000a00
4 040: 0000ffff 00000a00
048: 0000ffff 00000a00
5 050: 0000ffff 00000a00
058: 0000ffff 00000a00
6 060: 00007fff 00000a00
068: 00007fff 00000a00
070: 8fef0000 00003013
078: 8ffe0000 00000011 KDP
080: 8fff0000 00000012 EDP
088: 0000ffff 00000a01
090: 0000ffff 00000a01
098: 0000ffff 00000a00
7 0a0: 0000ffff 00000a01
0a8: 0000ffff 00000a01
0b0: 0000ffff 00000a00
8 0b8: 0000ffff 8000003a
0c0: 0000ffff 80000a01
0c8: 0000ffff 00000a00
9 0d0: 0000000f 9000003a
0d8: 0020001f 9002003a
0e0: 80007fff 98000032
0e8: 0000ffff 90000a01
0f0: 0000ffff 00000a00
A 0f8: 0000ffff a0000a01
100: 0000ffff 00000a00
B 108: 0000ffff b0000a01
110: 0000ffff 00000a00
C 118: 0000ffff c0000a01
120: 0000ffff 00000a00
D 128: fffe0000 00000012 IRP
130: 0000ffff d0000a01
138: 0000ffff 00000a00
E 140: 4000017f 0ab00012
148: 0000ffff e0000a01
150: 0000ffff 00000a00
F 158: 0000ffff f000003a
160: 0000ffff f0000a01
168: 0000ffff 00000a00
Handing over to the NanoKernel.
@ELN Are there Python scripts for creating the "Third limit-breaking ROM", or is any other such tooling available?
For example, using your tbxi and tbxi-patches projects like we do for the Mac mini G4 ROM patches, or other similar tooling.
If so, we could apply the 1.628 GB RAM limit patches to Rairii's 10.2.1 CPU Software 5.9 version of the ROM, and get even System 7 to move up from 1.5 GB max RAM to 1.628 GB!
Both the third-limit breaking ROM and Rairii's ROM are based on the same US Mac OS ROM 10.2.1 with CPU Software 5.9, so most likely it will work!
(Nevermind figuring out what to do with so much RAM on System 7. That can wait!)
It's great to have you join the fray! Mac OS 9 army grows!


