Add the Wedge

The Wedge is a C program that, when inserted into a PowerPC ROM, runs
just before the NanoKernel. This is very early in the boot process. The
Wedge takes this opportunity to rearrange the MacOS address space and
make more than 1.5 GB RAM available to applications. Some serious
problems remain with this approach, so a "proper" solution to the 1.5 GB
RAM limit will take more work.

This code was ripped out of the old CDG5 build system and refactored. It
it more appropriate to keep the Wedge separate from the real OS code.
This commit is contained in:
Elliot Nunn 2017-11-19 22:29:19 +08:00
commit 95df455703
12 changed files with 2029 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
Intermediates/
Apps/
*.dmg

26
EasyBuild Normal file
View File

@ -0,0 +1,26 @@
Set Parent "`Files -f "{0}" | StreamEdit -d -e '/((Å:)*)¨1([Â:]*)/ Print ¨1'`"
SetDirectory "{Parent}"
Set IM :Intermediates:
Set Apps :Apps:
NewFolder {IM} · Dev:Null || Set Status 0
NewFolder {Apps} · Dev:Null || Set Status 0
Make {IM}RomWedge.x {IM}Linker {Apps}TestWedge {Apps}WedgeLogReader > {IM}MakeOut
{IM}MakeOut
If !{#}
Echo Next time, pass the address of your ROM(s) as an argument,
Echo and the Wedge will be inserted.
Exit
End
Loop
If !{#}
Break
End
{IM}Linker "{1}" {IM}RomWedge.x
Shift
End

122
Linker.c Normal file
View File

@ -0,0 +1,122 @@
#include <stdio.h>
#include <XCOFF.h>
#include <MacTypes.h>
long getblob(char *fileName, char **bufpp)
{
FILE *fp;
FileHdr xc_head;
fp = fopen(fileName, "rb");
if(!fp) return -1;
fread(&xc_head, 1, sizeof xc_head, fp); /* first, is this open file an XCOFF? */
if(!feof(fp) && xc_head.f_magic == U802TOCMAGIC) { /* YES, XCOFF */
SectionHdrEntry xc_sec;
/* we have an xcoff! */
//if(xc_head.f_nscns != 0) fprintf(stderr, "(XCOFF) %s has %d (!= 1) sections.\n", fileName, xc_head.f_nscns+1);
fseek(fp, xc_head.f_opthdr, SEEK_CUR); /* skip the aux header */
fread(&xc_sec, 1, sizeof xc_sec, fp);
if(feof(fp)) return -2; /* couldnt get a section header entry */
*bufpp = (char *)malloc(xc_sec.s_size);
if(!*bufpp) return -3; /* oom */
fseek(fp, xc_sec.s_scnptr, SEEK_SET);
fread(*bufpp, 1, xc_sec.s_size, fp);
if(feof(fp)) return -4; /* could not read section */
return xc_sec.s_size;
} else { /* NO, RAW FILE */
long size;
fseek(fp, 0, SEEK_END); /* apparently this passes for an idiom in C */
size = ftell(fp);
*bufpp = (char *)malloc(size);
if(!*bufpp) return -3; /* oom */
fseek(fp, 0, SEEK_SET);
fread(*bufpp, 1, size, fp);
if(feof(fp)) return -4; /* could not read section */
return size;
}
}
int main(int argc, char *argv[])
{
FILE *fp;
char *blob[2];
long size[2];
int i;
if(argc != 3) {
fprintf(stderr, "Usage: %s ROM WEDGE\n", argv[0]);
return 1;
}
for(i=0; i<2; i++) /* Two or more, use a for. */
{
char *fname = argv[i+1];
size[i] = getblob(fname, &(blob[i]));
if(size[i] <= 0) {
fprintf(stderr, "%s: Failed to load: %s\n", argv[0], fname);
return 1;
}
}
printf("Linking Wedge into %s\n", argv[1]);
if(size[0] != 0x400000) {
fprintf(stderr, "%s: ROM is 0x%X bytes, failing\n", argv[0], size[0]);
return 1;
}
if(size[1] > 0x20000) {
fprintf(stderr, "%s: WEDGE is 0x%X bytes, to large\n", argv[0], size[1]);
return 1;
}
if(blob[0][0x340000] == 0) {
/* NanoKernel needs to be moved */
printf("Moving NanoKernel from 310000 to 340000.\n");
memcpy(blob[0] + 0x340000, blob[0] + 0x310000, 0x20000);
printf("Erasing original NanoKernel location.\n");
memset(blob[0] + 0x310000, 0, 0x20000);
} else {
printf("NanoKernel already moved to 340000. Erasing old Wedge.\n");
memset(blob[0] + 0x310000, 0, 0x20000);
}
printf("Copying Wedge (0x%X bytes).\n", size[1]);
memcpy(blob[0] + 0x310000, blob[1], size[1]);
printf("Writing out.\n");
fp = fopen(argv[1], "wb");
if(!fp) {
fprintf(stderr, "%s: Failed to open for writing: %s\n", argv[0], argv[1]);
return 1;
}
if(fwrite(blob[0], size[0], 1, fp) != 1) {
fprintf(stderr, "%s: Failed to write: %s\n", argv[0], argv[1]);
return 1;
}
if(fclose(fp)) {
fprintf(stderr, "%s: Failed to close: %s\n", argv[0], argv[1]);
return 1;
}
return 0;
}

33
MakeFile Normal file
View File

@ -0,0 +1,33 @@
MpwToolLibs68k = ¶
"{Libraries}Stubs.o" ¶
"{CLibraries}StdCLib.o" ¶
"{Libraries}MacRuntime.o" ¶
"{Libraries}IntEnv.o" ¶
"{Libraries}Interface.o" ¶
SiowLibsPPC = ¶
"{PPCLibraries}PPCSIOW.o" ¶
"{PPCLibraries}MrCPlusLib.o" ¶
"{SharedLibraries}InterfaceLib" ¶
"{SharedLibraries}StdCLib" ¶
"{SharedLibraries}MathLib" ¶
"{PPCLibraries}PPCCRuntime.o" ¶
IM = :Intermediates:
Apps = :Apps:
{IM} Ä :
{IM}RomWedge.x Ä {IM}WedgeStub.s.x {IM}printf.c.x {IM}Wedge.c.x
PPCLink -outputformat xcoff -codeorder source -roistext on -o {Targ} {Deps}
{IM}Linker Ä {IM}Linker.c.o
ILink -d -t 'MPST' -c 'MPS ' -o {Targ} {MpwToolLibs68k} {Deps}
{Apps}TestWedge Ä {IM}Wedge.c.x {IM}NKShim.s.x
PPCLink -d -t 'APPL' -c 'siow' -o {Targ} {Deps} {SiowLibsPPC}
Rez -a "{RIncludes}SIOW.r" -d DEFAULT_SAVE_PREF=1 -o {Targ}
{Apps}WedgeLogReader Ä {IM}WedgeLogReader.c.x
PPCLink -d -t 'APPL' -c 'siow' -o {Targ} {Deps} {SiowLibsPPC}
Rez -a "{RIncludes}SIOW.r" -d DEFAULT_SAVE_PREF=1 -o {Targ}

24
NKShim.h Normal file
View File

@ -0,0 +1,24 @@
#pragma once
#include <MacTypes.h>
OSErr NKxprintf(char *);
enum {
kNKSystemInfo = 2,
kNKDiagInfo = 3,
kNKNanoKernelInfo = 4,
kNKProcessorInfo = 5,
kNKHWInfo = 6,
kNKProcessorState = 7,
};
OSErr NKLocateInfoRecord(long whichRecord, char **record, long *version, long *length);
OSErr NKKernelDebuggerCmd(char *cmd);

84
NKShim.s Normal file
View File

@ -0,0 +1,84 @@
; MakeFunction sets up everything you need to make an assembly function
; callable from C and debuggable with a symbolic debugger. It does the following:
; - export the function's transition vector
; - export the function name
; - create a toc entry for the function's transition vector
; - create the transition vector, which must contain
; - the function entry point (the name of the function)
; - the TOC anchor (the predefined variable TOC[tc0])
; - tell PPCAsm to create a function entry point symbol for symbolic debuggers
; - create a csect for the function (one csect per function lets the
; linker do dead code stripping, resulting in smaller executables)
MACRO
MakeFunction &fnName
EXPORT &fnName[DS]
EXPORT .&fnName[PR]
TC &fnName[TC], &fnName[DS]
CSECT &fnName[DS]
DC.L .&fnName[PR]
DC.L TOC[tc0]
CSECT .&fnName[PR]
FUNCTION .&fnName[PR]
ENDM
linkageArea: set 24 ; constant comes from the PowerPC Runtime Architecture Document
CalleesParams: set 32 ; always leave space for GPR's 3-10
CalleesLocalVars: set 0 ; NKxprintf doesn't have any
numGPRs: set 0 ; num volitile GPR's (GPR's 13-31) used by NKxprintf
numFPRs: set 0 ; num volitile FPR's (FPR's 14-31) used by NKxprintf
spaceToSave: set linkageArea + CalleesParams + CalleesLocalVars + 4*numGPRs + 8*numFPRs
; declare the C function DisplayAlert as external
import .DisplayAlert
import gHelloString ; global variable from C program
import gGoodbyeString ; global variable from C program
toc
tc gHelloString[TC], gHelloString
tc gGoodbyeString[TC], gGoodbyeString
; Call the MakeFunction macro, defined in MakeFunction.s to begin the function
MakeFunction NKxprintf
li r0, 96
sc
blr
MakeFunction NKLocateInfoRecord ; Lifted shamelessly from MPLibrary
stw r4,0x001C(SP)
stw r5,0x0020(SP)
stw r6,0x0024(SP)
li r0,107
sc
cmpwi r3,0
bnelr
lwz r7,0x001C(SP)
lwz r8,0x0020(SP)
lwz r9,0x0024(SP)
cmplwi cr5,r7,0x0000
cmplwi cr6,r8,0x0000
cmplwi cr7,r9,0x0000
beq cr5,$+0x0008 ; 0x00008440
stw r4,0x0000(r7)
beq cr6,$+0x0008 ; 0x00008448
stw r5,0x0000(r8)
beq cr7,$+0x0008 ; 0x00008450
stw r6,0x0000(r9)
blr
MakeFunction NKKernelDebuggerCmd
li r0, 200
sc
blr

690
PPCInfoRecordsPriv.h Normal file
View File

@ -0,0 +1,690 @@
/*
* Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
*
* "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
* Reserved. This file contains Original Code and/or Modifications of
* Original Code as defined in and that are subject to the Apple Public
* Source License Version 1.0 (the 'License'). You may not use this file
* except in compliance with the License. Please obtain a copy of the
* License at http://www.apple.com/publicsource and read it before using
* this file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
* License for the specific language governing rights and limitations
* under the License."
*
* @APPLE_LICENSE_HEADER_END@
*/
/*
File: PPCInfoRecordsPriv.h
Contains: PowerPC information records created by hardware intialization and maintained by the NanoKernel.
Version: Mac OS
DRI: Jim Murphy
Copyright: © 1997-1998 by Apple Computer, Inc., all rights reserved.
Warning: *** APPLE INTERNAL USE ONLY ***
This file contains unreleased SPI's
BuildInfo: Built by: Naga Pappireddi
With Interfacer: 3.0d9 (PowerPC native)
From: PPCInfoRecordsPriv.i
Revision: 18
Dated: 9/9/98
Last change by: RAV
Last comment: Set nanokernel info rev to 1.0.4. I'm reserving 2.0.0 for the
Bugs: Report bugs to Radar component "System Interfaces", "Latest"
List the version information (from above) in the Problem Description.
*/
// LIGHTLY EDITED TO MAKE CONFIGINFO REFLECT ITS TRUE SELF
#ifndef __PPCINFORECORDSPRIV__
#define __PPCINFORECORDSPRIV__
#ifndef __MACTYPES__
#include <MacTypes.h>
#endif
#if PRAGMA_ONCE
#pragma once
#endif
#ifdef __cplusplus
extern "C" {
#endif
#if PRAGMA_IMPORT
#pragma import on
#endif
#if PRAGMA_STRUCT_ALIGN
#pragma options align=mac68k
#elif PRAGMA_STRUCT_PACKPUSH
#pragma pack(push, 2)
#elif PRAGMA_STRUCT_PACK
#pragma pack(2)
#endif
/*
_______________________________________________________________________
Configuration Info Record
Used to pass Configuration information from the Boot Program to the
NanoKernel for data structure and address mapping initialization.
_______________________________________________________________________
*/
struct NKConfigurationInfo {
/* Physical ROM Info*/
UInt32 ROMCheckSumByte0; /* ROM Checksum - Byte Lane 0*/
UInt32 ROMCheckSumByte1; /* ROM Checksum - Byte Lane 1*/
UInt32 ROMCheckSumByte2; /* ROM Checksum - Byte Lane 2*/
UInt32 ROMCheckSumByte3; /* ROM Checksum - Byte Lane 3*/
UInt32 ROMCheckSumByte4; /* ROM Checksum - Byte Lane 4*/
UInt32 ROMCheckSumByte5; /* ROM Checksum - Byte Lane 5*/
UInt32 ROMCheckSumByte6; /* ROM Checksum - Byte Lane 6*/
UInt32 ROMCheckSumByte7; /* ROM Checksum - Byte Lane 7*/
UInt64 ROMCheckSum64; /* ROM Checksum - 64 bit sum of doublewords*/
UInt32 ROMImageBaseOffset; /* Offset of Base of total ROM image*/
UInt32 ROMImageSize; /* Number of bytes in ROM image*/
UInt32 ROMImageVersion; /* ROM Version number for entire ROM*/
/* ROM component Info (offsets are from base of ConfigInfo page)*/
UInt32 Mac68KROMOffset; /* Offset of base of Macintosh 68K ROM*/
UInt32 Mac68KROMSize; /* Number of bytes in Macintosh 68K ROM*/
UInt32 ExceptionTableOffset; /* Offset of base of PowerPC Exception Table Code*/
UInt32 ExceptionTableSize; /* Number of bytes in PowerPC Exception Table Code*/
UInt32 HWInitCodeOffset; /* Offset of base of Hardware Init Code*/
UInt32 HWInitCodeSize; /* Number of bytes in Hardware Init Code*/
UInt32 KernelCodeOffset; /* Offset of base of NanoKernel Code*/
UInt32 KernelCodeSize; /* Number of bytes in NanoKernel Code*/
UInt32 EmulatorCodeOffset; /* Offset of base of Emulator Code*/
UInt32 EmulatorCodeSize; /* Number of bytes in Emulator Code*/
UInt32 OpcodeTableOffset; /* Offset of base of Opcode Table*/
UInt32 OpcodeTableSize; /* Number of bytes in Opcode Table*/
/* Offsets within the Emulator Data Page.*/
UInt8 BootstrapVersion[16]; /* Bootstrap loader version info*/
UInt32 BootVersionOffset; /* offset within EmulatorData of BootstrapVersion*/
UInt32 ECBOffset; /* offset within EmulatorData of ECB*/
UInt32 IplValueOffset; /* offset within EmulatorData of IplValue*/
/* Offsets within the Emulator Code.*/
UInt32 EmulatorEntryOffset; /* offset within Emulator Code of entry point*/
UInt32 KernelTrapTableOffset; /* offset within Emulator Code of KernelTrapTable*/
/* Interrupt Passing Masks.*/
UInt32 TestIntMaskInit; /* initial value for test interrupt mask*/
UInt32 ClearIntMaskInit; /* initial value for clear interrupt mask*/
UInt32 PostIntMaskInit; /* initial value for post interrupt mask*/
UInt32 LA_InterruptCtl; /* logical address of Interrupt Control I/O page*/
UInt8 InterruptHandlerKind; /* kind of handler to use*/
UInt8 filler1;
UInt16 filler2;
UInt32 LA_InfoRecord; /* logical address of InfoRecord page*/
UInt32 LA_KernelData; /* logical address of KernelData page*/
UInt32 LA_EmulatorData; /* logical address of EmulatorData page*/
UInt32 LA_DispatchTable; /* logical address of Dispatch Table*/
UInt32 LA_EmulatorCode; /* logical address of Emulator Code*/
UInt32 MacLowMemInitOffset; /* offset to list of LowMem addr/data values*/
/* Address Space Mapping.*/
UInt32 PageAttributeInit; /* default WIMG/PP settings for PTE creation*/
UInt32 PageMapInitSize; /* size of page mapping info*/
UInt32 PageMapInitOffset; /* offset to page mapping info (from base of ConfigInfo)*/
UInt32 PageMapIRPOffset; /* offset of InfoRecord map info (from base of PageMap)*/
UInt32 PageMapKDPOffset; /* offset of KernelData map info (from base of PageMap)*/
UInt32 PageMapEDPOffset; /* offset of EmulatorData map info (from base of PageMap)*/
UInt32 SegMap32SupInit[32]; /* 32 bit mode Segment Map Supervisor space*/
UInt32 SegMap32UsrInit[32]; /* 32 bit mode Segment Map User space*/
UInt32 SegMap32CPUInit[32]; /* 32 bit mode Segment Map CPU space*/
UInt32 SegMap32OvlInit[32]; /* 32 bit mode Segment Map Overlay mode*/
UInt32 BATRangeInit[32]; /* BAT mapping ranges*/
UInt32 BatMap32SupInit; /* 32 bit mode BAT Map Supervisor space*/
UInt32 BatMap32UsrInit; /* 32 bit mode BAT Map User space*/
UInt32 BatMap32CPUInit; /* 32 bit mode BAT Map CPU space*/
UInt32 BatMap32OvlInit; /* 32 bit mode BAT Map Overlay mode*/
/* Only needed for Smurf*/
UInt32 SharedMemoryAddr; /* physical address of Mac/Smurf shared message mem*/
UInt32 PA_RelocatedLowMemInit; /* physical address of RelocatedLowMem*/
UInt32 OpenFWBundleOffset; /* Offset of base of OpenFirmware PEF Bundle*/
UInt32 OpenFWBundleSize; /* Number of bytes in OpenFirmware PEF Bundle*/
UInt32 LA_OpenFirmware; /* logical address of Open Firmware*/
UInt32 PA_OpenFirmware; /* physical address of Open Firmware*/
UInt32 LA_HardwarePriv; /* logical address of HardwarePriv callback*/
UInt32 filler3[2]; /* pad structure size out to a cache block*/
};
typedef struct NKConfigurationInfo NKConfigurationInfo;
/*
_______________________________________________________________________
System Info Record
Used to pass System information from the NanoKernel to user mode
software.
_______________________________________________________________________
*/
enum {
nkSystemInfoPtr = 0x5FFFEFF0, /* logical address of SystemInfo record*/
nkSystemInfoVer = 0x5FFFEFF4, /* version number of SystemInfo record*/
nkSystemInfoLen = 0x5FFFEFF6 /* length of SystemInfo record*/
};
struct NKSystemInfo {
UInt32 PhysicalMemorySize; /* Number of bytes in Physical RAM*/
UInt32 UsableMemorySize; /* Number of bytes in Usable RAM*/
UInt32 LogicalMemorySize; /* Number of bytes in Logical RAM*/
UInt32 HashTableSize; /* Number of bytes in Memory Hash Table*/
UInt32 L2DataCacheTotalSize; /* number of bytes in the L2 Data Cache*/
UInt32 L2InstCacheTotalSize; /* number of bytes in the L2 Instruction Cache*/
UInt16 L2CombinedCaches; /* 1 <- combined or no cache, 0 <- split cache*/
UInt16 L2InstCacheBlockSize; /* number of bytes in a Block of the L2 Instruction Cache*/
UInt16 L2DataCacheBlockSize; /* number of bytes in a Block of the L2 Data Cache*/
UInt16 L2InstCacheAssociativity; /* Associativity of the L2 Instruction Cache*/
UInt16 L2DataCacheAssociativity; /* Associativity of the L2 Data Cache*/
UInt16 unused_1; /* unused*/
UInt16 unused_2; /* unused*/
UInt8 FlashManufacturerCode; /* Flash ROM Manufacturer code*/
UInt8 FlashDeviceCode; /* Flash ROM Device code*/
UInt32 FlashStart; /* Starting address of Flash ROM*/
UInt32 FlashSize; /* Number of bytes in Flash ROM*/
/* 0x30 */
UInt32 Bank0Start; /* Starting address of RAM bank 0*/
UInt32 Bank0Size; /* Number of bytes in RAM bank 0*/
UInt32 Bank1Start; /* Starting address of RAM bank 1*/
UInt32 Bank1Size; /* Number of bytes in RAM bank 1*/
UInt32 Bank2Start; /* Starting address of RAM bank 2*/
UInt32 Bank2Size; /* Number of bytes in RAM bank 2*/
UInt32 Bank3Start; /* Starting address of RAM bank 3*/
UInt32 Bank3Size; /* Number of bytes in RAM bank 3*/
UInt32 Bank4Start; /* Starting address of RAM bank 4*/
UInt32 Bank4Size; /* Number of bytes in RAM bank 4*/
UInt32 Bank5Start; /* Starting address of RAM bank 5*/
UInt32 Bank5Size; /* Number of bytes in RAM bank 5*/
UInt32 Bank6Start; /* Starting address of RAM bank 6*/
UInt32 Bank6Size; /* Number of bytes in RAM bank 6*/
UInt32 Bank7Start; /* Starting address of RAM bank 7*/
UInt32 Bank7Size; /* Number of bytes in RAM bank 7*/
UInt32 Bank8Start; /* Starting address of RAM bank 8*/
UInt32 Bank8Size; /* Number of bytes in RAM bank 8*/
UInt32 Bank9Start; /* Starting address of RAM bank 9*/
UInt32 Bank9Size; /* Number of bytes in RAM bank 9*/
UInt32 Bank10Start; /* Starting address of RAM bank 10*/
UInt32 Bank10Size; /* Number of bytes in RAM bank 10*/
UInt32 Bank11Start; /* Starting address of RAM bank 11*/
UInt32 Bank11Size; /* Number of bytes in RAM bank 11*/
UInt32 Bank12Start; /* Starting address of RAM bank 12*/
UInt32 Bank12Size; /* Number of bytes in RAM bank 12*/
UInt32 Bank13Start; /* Starting address of RAM bank 13*/
UInt32 Bank13Size; /* Number of bytes in RAM bank 13*/
UInt32 Bank14Start; /* Starting address of RAM bank 14*/
UInt32 Bank14Size; /* Number of bytes in RAM bank 14*/
UInt32 Bank15Start; /* Starting address of RAM bank 15*/
UInt32 Bank15Size; /* Number of bytes in RAM bank 15*/
UInt32 Bank16Start; /* Starting address of RAM bank 16*/
UInt32 Bank16Size; /* Number of bytes in RAM bank 16*/
UInt32 Bank17Start; /* Starting address of RAM bank 17*/
UInt32 Bank17Size; /* Number of bytes in RAM bank 17*/
UInt32 Bank18Start; /* Starting address of RAM bank 18*/
UInt32 Bank18Size; /* Number of bytes in RAM bank 18*/
UInt32 Bank19Start; /* Starting address of RAM bank 19*/
UInt32 Bank19Size; /* Number of bytes in RAM bank 19*/
UInt32 Bank20Start; /* Starting address of RAM bank 20*/
UInt32 Bank20Size; /* Number of bytes in RAM bank 20*/
UInt32 Bank21Start; /* Starting address of RAM bank 21*/
UInt32 Bank21Size; /* Number of bytes in RAM bank 21*/
UInt32 Bank22Start; /* Starting address of RAM bank 22*/
UInt32 Bank22Size; /* Number of bytes in RAM bank 22*/
UInt32 Bank23Start; /* Starting address of RAM bank 23*/
UInt32 Bank23Size; /* Number of bytes in RAM bank 23*/
UInt32 Bank24Start; /* Starting address of RAM bank 24*/
UInt32 Bank24Size; /* Number of bytes in RAM bank 24*/
UInt32 Bank25Start; /* Starting address of RAM bank 25*/
UInt32 Bank25Size; /* Number of bytes in RAM bank 25*/
/* Interrupt Support Data*/
UInt32 IntCntrBaseAddr; /* Interrupt Controller Base Address (variable is used since this is a PCI Dev and address is relocatable)*/
UInt32 IntPendingReg[2]; /* Data of current interrupts pending register*/
/* These fields were added to report information about tightly-coupled L2 caches.*/
/* The inline L2 information should be used in situations where there is a CPU*/
/* card L2 cache that can coexist with a motherboard L2.*/
UInt32 InlineL2DSize; /* Size of in-line L2 Dcache*/
UInt32 InlineL2ISize; /* Size of in-line L2 Icache*/
UInt16 InlineL2Combined; /* 1 <- combined or no cache, 0 <- split cache*/
UInt16 InlineL2IBlockSize; /* Block size of in-line I L2 cache*/
UInt16 InlineL2DBlockSize; /* Block size of in-line D L2 cache*/
UInt16 InlineL2IAssoc; /* Associativity of L2 I*/
UInt16 InlineL2DAssoc; /* Associativity of L2 D*/
UInt16 filler1; /* pad*/
/* More Interrupt Support Data*/
UInt32 IntsCompleted[2]; /* completed interrupts*/
UInt32 filler2[6]; /* pad to nice cache block alignment*/
};
typedef struct NKSystemInfo NKSystemInfo;
enum {
kMaxBanks = 26, /* 6 banks, 0É25*/
kSystemInfoVersion = 0x0105 /* 1.0.5*/
};
/*
_______________________________________________________________________
Diagnostic Info Record
Used to pass Diagnostic information from the power on Diagnostics to
the NanoKernel, and from the NanoKernel to user mode software.
_______________________________________________________________________
*/
enum {
nkDiagnosticInfoPtr = 0x5FFFEFE8, /* logical address of DiagnosticInfo record*/
nkDiagnosticInfoVer = 0x5FFFEFEC, /* version number of DiagnosticInfo record*/
nkDiagnosticInfoLen = 0x5FFFEFEE /* length of DiagnosticInfo record*/
};
struct NKDiagnosticInfo {
UInt32 BankMBFailOffset; /* Mother Board RAM failure code*/
UInt32 BankAFailOffset; /* Bank A RAM failure code*/
UInt32 BankBFailOffset; /* Bank B RAM failure code*/
UInt32 BankCFailOffset; /* Bank C RAM failure code*/
UInt32 BankDFailOffset; /* Bank D RAM failure code*/
UInt32 BankEFailOffset; /* Bank E RAM failure code*/
UInt32 BankFFailOffset; /* Bank F RAM failure code*/
UInt32 BankGFailOffset; /* Bank G RAM failure code*/
UInt32 BankHFailOffset; /* Bank H RAM failure code*/
UInt32 CacheFailOffset; /* cache failure code*/
UInt32 LongBootParamOffset; /* on longBoot this is where the params will be*/
UInt32 POSTTraceOffset; /* this tells us what route the POST took*/
UInt32 POSTOldWarmOffset; /* logged address of old warmstart flag*/
UInt32 POSTOldLongOffset; /* logged address of old long boot flag*/
UInt32 POSTOldGlobbOffset; /* logged address of old Diagnostic Info Record*/
UInt32 POSTOldParamOffset; /* the params from the old diag globb*/
UInt32 POSTStartRTCUOffset; /* PPC Real Time Clock Upper at start of POST*/
UInt32 POSTStartRTCLOffset; /* PPC Real Time Clock Lower at start of POST*/
UInt32 POSTEndRTCUOffset; /* PPC Real Time Clock Upper at end of POST*/
UInt32 POSTEndRTCLOffset; /* PPC Real Time Clock Lower at end of POST*/
UInt32 POSTTestTypeOffset; /* when long RAM tests fail test type which failed is put here*/
UInt32 POSTError2Offset; /* result codes from tests*/
UInt32 POSTError3Offset; /* result codes from tests*/
UInt32 POSTError4Offset; /* result codes from tests*/
UInt8 RegistersStore[140]; /* store all 60x registers here, still fit into 256 bytes size.*/
UInt32 DiagPOSTResult2; /* POST results*/
UInt32 DiagPOSTResult1; /* POST results*/
UInt32 DiagLongBootSig; /* Burn in restart flag*/
UInt32 DiagWarmStartHigh; /* First long of native warm start (WLSC) <SM44>*/
UInt32 DiagWarmStartLow; /* Second long of native warm start (SamB) <SM44>*/
};
typedef struct NKDiagnosticInfo NKDiagnosticInfo;
enum {
kDiagnosticInfoVersion = 0x0100 /* 1.0.0*/
};
/*
_______________________________________________________________________
NanoKernel Info Record
Used to pass NanoKernel statistics from the NanoKernel to user mode
software.
_______________________________________________________________________
*/
enum {
nkNanoKernelInfoPtr = 0x5FFFEFE0, /* logical address of NanoKernelInfo record*/
nkNanoKernelInfoVer = 0x5FFFEFE4, /* version number of NanoKernelInfo record*/
nkNanoKernelInfoLen = 0x5FFFEFE6 /* length of NanoKernelInfo record*/
};
struct NKNanoKernelInfo {
UInt32 ExceptionCauseCounts[32]; /* counters per exception cause*/
UInt32 NanoKernelCallCounts[16]; /* counters per NanoKernel call*/
UInt32 ExternalIntCount; /* count of External Interrupts*/
UInt32 MisalignmentCount; /* count of Misalignment Interrupts*/
UInt32 FPUReloadCount; /* count of FPU reloads on demand*/
UInt32 DecrementerIntCount; /* count of Decrementer Interrupts*/
UInt32 QuietWriteCount; /* count of Writes to Quiet Read-Only memory*/
UInt32 HashTableCreateCount; /* count of Hash Table Entry creations*/
UInt32 HashTableDeleteCount; /* count of Hash Table Entry deletions*/
UInt32 HashTableOverflowCount; /* count of Hash Table Entry overflows*/
UInt32 EmulatedUnimpInstCount; /* count of Emulated unimplemented instructions*/
UInt32 NCBPtrCacheMissCount; /* count of NCB Pointer cache misses*/
UInt32 ExceptionPropagateCount; /* count of Exceptions propagated to system*/
UInt32 ExceptionForcedCount; /* count of Exceptions forced to system*/
UInt64 SysContextCpuTime; /* CPU Time used by System Context*/
UInt64 AltContextCpuTime; /* CPU Time used by Alternate Context*/
UInt32 blueProcessID; /* ID of the blue process.*/
UInt32 blueTaskID; /* ID of the blue task.*/
UInt32 pageQueueID; /* ID of the page fault queue.*/
UInt32 TaskCount; /* Number of tasks.*/
UInt32 FreePoolExtendCount; /* Number of pages given to the nanokernel.*/
UInt32 rsrv1[3];
};
typedef struct NKNanoKernelInfo NKNanoKernelInfo;
enum {
kNanoKernelInfoVersion = 0x0104 /* 1.0.4*/
};
/*
_______________________________________________________________________
Processor Info Record
Used to pass Processor information from the NanoKernel to user mode
software.
_______________________________________________________________________
*/
enum {
nkProcessorInfoPtr = 0x5FFFEFD8, /* logical address of ProcessorInfo record*/
nkProcessorInfoVer = 0x5FFFEFDC, /* version number of ProcessorInfo record*/
nkProcessorInfoLen = 0x5FFFEFDE /* length of ProcessorInfo record*/
};
struct NKProcessorInfo {
UInt32 ProcessorVersionReg; /* contents of the PVR special purpose register*/
UInt32 CpuClockRateHz; /* CPU Clock frequency*/
UInt32 BusClockRateHz; /* Bus Clock frequency*/
UInt32 DecClockRateHz; /* Decrementer Clock frequency*/
UInt32 PageSize; /* number of bytes in a memory page*/
UInt32 DataCacheTotalSize; /* number of bytes in the Data Cache*/
UInt32 InstCacheTotalSize; /* number of bytes in the Instruction Cache*/
UInt16 CoherencyBlockSize; /* number of bytes in a Coherency Block*/
UInt16 ReservationGranuleSize; /* number of bytes in a Reservation Granule*/
UInt16 CombinedCaches; /* 1 <- combined or no cache, 0 <- split cache*/
UInt16 InstCacheLineSize; /* number of bytes in a Line of the Instruction Cache*/
UInt16 DataCacheLineSize; /* number of bytes in a Line of the Data Cache*/
UInt16 DataCacheBlockSizeTouch; /* number of bytes in a Block for DCBT DCBTST*/
UInt16 InstCacheBlockSize; /* number of bytes in a Block of the Instruction Cache*/
UInt16 DataCacheBlockSize; /* number of bytes in a Block of the Data Cache*/
UInt16 InstCacheAssociativity; /* Associativity of the Instruction Cache*/
UInt16 DataCacheAssociativity; /* Associativity of the Data Cache*/
UInt16 TransCacheTotalSize; /* number of entries in the Translation Cache*/
UInt16 TransCacheAssociativity; /* Associativity of the Translation Cache*/
/* These fields were added to report information about back-side L2 caches*/
UInt32 ProcessorL2DSize; /* Size of back-side L2 Dcache*/
UInt32 ProcessorL2ISize; /* Size of back-side L2 Icache*/
UInt16 ProcessorL2Combined; /* 1 <- combined or no cache, 0 <- split cache*/
UInt16 ProcessorL2IBlockSize; /* Block size of back-side I L2 cache*/
UInt16 ProcessorL2DBlockSize; /* Block size of back-side D L2 cache*/
UInt16 ProcessorL2IAssoc; /* Associativity of L2 I*/
UInt16 ProcessorL2DAssoc; /* Associativity of L2 D*/
UInt16 filler1; /* align to long*/
UInt32 ProcessorFlags; /* flags to specify processor features*/
UInt32 filler2[5]; /* pad to nice cache block alignment*/
};
typedef struct NKProcessorInfo NKProcessorInfo;
/*
ProcessorFlags - Definitions for the processor flags field. These are bit positions,
as in Ò1 << hasVMXÓ, and not masks.
*/
enum {
hasL2CR = 0,
hasPLRUL1 = 1,
hasTAU = 2,
hasVMX = 3
};
enum {
kProcessorInfoVersion = 0x0101 /* 1.0.1*/
};
/*
_______________________________________________________________________
Hardware Info Record
Used to pass hardware information from the NanoKernel to user mode
software.
_______________________________________________________________________
*/
enum {
nkHWInfoPtr = 0x5FFFEFD0, /* logical address of HWInfo record*/
nkHWInfoVer = 0x5FFFEFD4, /* version number of HWInfo record*/
nkHWInfoLen = 0x5FFFEFD6 /* length of HWInfo record*/
};
enum {
nkHWInfoFlagSlowMESH = 1, /* set if fast MESH doesn't work on this box*/
nkHWInfoFlagAsynchMESH = 2, /* set if Synchronous MESH doesn't work on this box*/
nkHWInfoFlagNoCopySWTLB = 4 /* set if the software TLB walk code for 603 should NOT be copied*/
};
struct NKHWInfo {
UInt32 MacROM_Base; /* base address (physical) of Mac ROM*/
UInt32 DeviceTreeBase; /* base address of the copied device tree properties*/
UInt32 UniversalInfoTableBase; /* base address of the Universal Info Table*/
UInt32 ConfigInfoTableBase; /* base address of the Config Info Table*/
UInt16 * VectorLookupTable; /* base address of the interrupt vector lookup table*/
UInt32 * VectorMaskTable; /* base address of the interrupt vector mask table*/
UInt32 OpenPICBaseAddr; /* OpenPIC base address*/
UInt8 * ISAMaster8259; /* ISA Master 8259 ports*/
UInt8 * ISASlave8259; /* ISA Slave 8259 ports*/
UInt32 * InterruptAck8259; /* address to read to ack 8259 interrupt*/
/* interrupt pending bits (actively changing)*/
UInt32 PendingInts[2]; /* 64 bits of pending interrupts*/
/* some Mac I/O device base addresses*/
UInt32 ADB_Base; /* base address of ADB*/
UInt32 SCSI_DMA_Base; /* base address of SCSI DMA registers*/
/* RTAS related stuff*/
UInt32 RTAS_PrivDataArea; /* RTAS private data area */
UInt32 MacOS_NVRAM_Offset; /* offset into nvram to MacOS data*/
UInt32 RTAS_NVRAM_Fetch; /* token for RTAS NVRAM fetch*/
UInt32 RTAS_NVRAM_Store; /* token for RTAS NVRAM store*/
UInt32 RTAS_Get_Clock; /* token for RTAS clock get*/
UInt32 RTAS_Set_Clock; /* token for RTAS clock set*/
UInt32 RTAS_Restart; /* token for RTAS Restart*/
UInt32 RTAS_Shutdown; /* token for RTAS Shutdown*/
UInt32 RTAS_Restart_At; /* token for RTAS system startup at specified time*/
UInt32 RTAS_EventScan; /* token for RTAS event scan*/
UInt32 RTAS_Check_Exception; /* token for RTAS check exception*/
UInt32 RTAS_Read_PCI_Config; /* token for RTAS read PCI config*/
UInt32 RTAS_Write_PCI_Config; /* token for RTAS write PCI config*/
/* SIO interrupt source numbers for the MPIC*/
SInt16 SIOIntVect; /* SIO (8259 cascade vector) vector number*/
SInt16 SIOIntBit; /* SIO (8259 cascade vector) bit number*/
SInt32 Signature; /* signature for this record ('Hnfo')*/
/* more interrupt source numbers*/
SInt16 SpuriousIntVect; /* spurious vector number*/
SInt16 CPU_ID; /* the ID of this CPU (universal-tables-related)*/
SInt16 SCCAIntVect; /* SCC A (non-DMA) vector number*/
SInt16 SCCBIntVect; /* SCC B (non-DMA) vector number*/
SInt16 SCSIIntVect; /* SCSI vector number*/
SInt16 SCSIDMAIntVect; /* SCSI DMA vector number*/
SInt16 VIAIntVect; /* VIA vector number*/
SInt16 VIAIntBit; /* VIA bit number*/
SInt16 ADBIntVect; /* ADB vector number*/
SInt16 NMIIntVect; /* NMI vector number*/
SInt16 NMIIntBit; /* NMI bit number*/
/* current (actively changing) interrupt handling variables*/
SInt16 ISAPendingInt; /* currently pending ISA/8259 interrupt*/
SInt8 CompletedInts[8]; /* completed interrupts*/
SInt32 HardwareInfoFlags; /* 32 bits of flags (see enum above)*/
UInt32 RTAS_Get_PowerOn_Time; /* token for RTAS getting time for system startup*/
UInt32 filler1[1]; /* pad to cache block alignment*/
};
typedef struct NKHWInfo NKHWInfo;
enum {
kHWInfoVersion = 0x0103 /* 1.0.3*/
};
/*
_______________________________________________________________________
Processor State Record
Used to save the state of the processor across sleep.
_______________________________________________________________________
*/
enum {
nkProcessorStatePtr = 0x5FFFEFC8, /* logical address of ProcessorState record*/
nkProcessorStateVer = 0x5FFFEFCC, /* version number of ProcessorState record*/
nkProcessorStateLen = 0x5FFFEFCE /* length of ProcessorState record*/
};
struct NKProcessorState {
UInt32 saveDBAT0u; /* place to store DBAT0U*/
UInt32 saveDBAT0l; /* place to store DBAT0L*/
UInt32 saveDBAT1u; /* place to store DBAT1U*/
UInt32 saveDBAT1l; /* place to store DBAT1L*/
UInt32 saveDBAT2u; /* place to store DBAT2U*/
UInt32 saveDBAT2l; /* place to store DBAT2L*/
UInt32 saveDBAT3u; /* place to store DBAT3U*/
UInt32 saveDBAT3l; /* place to store DBAT3L*/
UInt32 saveIBAT0u; /* place to store IBAT0U*/
UInt32 saveIBAT0l; /* place to store IBAT0L*/
UInt32 saveIBAT1u; /* place to store IBAT1U*/
UInt32 saveIBAT1l; /* place to store IBAT1L*/
UInt32 saveIBAT2u; /* place to store IBAT2U*/
UInt32 saveIBAT2l; /* place to store IBAT2L*/
UInt32 saveIBAT3u; /* place to store IBAT3U*/
UInt32 saveIBAT3l; /* place to store IBAT3L*/
UInt32 saveSPRG0; /* place to store SPRG0*/
UInt32 saveSPRG1; /* place to store SPRG1*/
UInt32 saveSPRG2; /* place to store SPRG2*/
UInt32 saveSPRG3; /* place to store SPRG3*/
UInt32 saveL2CR; /* place to store Arthur's L2CR*/
UInt32 saveSRR0; /* place to store SRR0*/
UInt32 saveSRR1; /* place to store SRR1*/
UInt32 saveTBU; /* place to store TBU*/
UInt32 saveTBL; /* place to store TBL*/
UInt32 saveHID0; /* place to store HID0*/
UInt32 saveDEC; /* place to store DEC*/
UInt32 saveMSR; /* place to store MSR*/
UInt32 saveSDR1; /* place to store SDR1*/
/* saveKernelDataPtr needs to always be right after saveReturnAddr*/
/* because of how the code works. DO NOT CHANGE THIS ORDERING!*/
UInt32 saveReturnAddr; /* place to store the addr to jump to.*/
UInt32 saveKernelDataPtr; /* place to store the KernelDataPtr*/
UInt32 saveContextPtr; /* place to store the ContextPtr*/
};
typedef struct NKProcessorState NKProcessorState;
enum {
kProcessorStateVersion = 0x0100 /* 1.0.0*/
};
#if PRAGMA_STRUCT_ALIGN
#pragma options align=reset
#elif PRAGMA_STRUCT_PACKPUSH
#pragma pack(pop)
#elif PRAGMA_STRUCT_PACK
#pragma pack()
#endif
#ifdef PRAGMA_IMPORT_OFF
#pragma import off
#elif PRAGMA_IMPORT
#pragma import reset
#endif
#ifdef __cplusplus
}
#endif
#endif /* __PPCINFORECORDSPRIV__ */

609
Wedge.c Normal file
View File

@ -0,0 +1,609 @@
#include "PPCInfoRecordsPriv.h"
#include "NKShim.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_EmulatorData_Orig 0x68fff000UL
#define kConfigInfoSize 4096
#define kHardwareInfoSize 192
#define kPatchInfoRecord 0x00000001UL
#define kPatchUniversalArea 0x00000010UL
#define kPatchConfigInfoPage 0x00000100UL
#define kPatchKDP 0x00001000UL
#define kPatchEDP 0x00010000UL
#define kCanPatchROM 0x80000000UL
#define kDelta 0x80000000UL
#define ROM ((char *)0x00c00000UL)
#define Em ((long *)(ROM + 0x360000UL))
#define MainCode ((unsigned short *)ROM)
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 & kCanPatchROM)
{
unsigned short hi = LA >> 16;
unsigned short lo = LA & 0xffff;
unsigned short *em = (unsigned short *)Em;
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;
}
/* Move the (completely unused?) ConfigInfo area: crashes after DR emulator loads */
if((patches & kPatchConfigInfoPage) && LA == LA_ConfigInfo_Orig)
{
printf("**ConfigInfo**\n ");
newLA += kDelta;
for(i=0; i<0xaa550/2; i++)
{
if(MainCode[i] == 0x68fe && MainCode[i+1] >= 0xf000) MainCode[i] += kDelta >> 16;
}
/* No pointers? Makes sense I guess... */
}
/* Move the KDP: crashed in 68k fire */
if((patches & kPatchKDP) && LA == LA_KernelData_Orig)
{
printf("**Kernel Data Page**\n ");
newLA += kDelta;
for(i=0; i<0xaa550/2; i++)
{
if(MainCode[i] == 0x68ff && MainCode[i+1] >= 0x5000) MainCode[i] += kDelta >> 16;
}
/* Only one pointer that I know of */
newci->LA_KernelData = newLA;
}
/* Move the EDP: crashes after DR emulator loads */
if((patches & kPatchEDP) && LA == LA_EmulatorData_Orig)
{
printf("**Emulator Data Page**\n ");
newLA += kDelta;
/* Only one pointer that I know of */
newci->LA_EmulatorData = 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");
}
}
/* Now do the 68000000 BAT */
/* 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 | kCanPatchROM,// | kPatchConfigInfoPage | kPatchKDP | kPatchEDP,
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 | kPatchConfigInfoPage | kPatchKDP | kPatchEDP,
0x68000000UL,
(NKConfigurationInfo *)ci, (NKConfigurationInfo *)ci_tmp,
(NKHWInfo *)hi, (NKHWInfo *)hi_tmp);
if(!ret)
{
printf("PatchMacOSAddressSpace succeeded (but was forbidden from patching the ROM).\n\n");
DebugDumpPageMap((NKConfigurationInfo *)ci_tmp);
}
else
{
printf("PatchMacOSAddressSpace failed with error %d.\n", ret);
}
}

14
WedgeLogReader.c Normal file
View File

@ -0,0 +1,14 @@
#include <stdio.h>
#define Middle ((long *)0xfff20000UL)
void main(void)
{
if(Middle[-2] != 'WgLg')
{
printf("The Wedge did not run. Restart with a Mac OS ROM file in your System Folder that has the Wedge built in. This application displays the Wedge log.\n");
return;
}
fwrite((char *)Middle, 1, Middle[-1], stdout);;
}

116
WedgeStub.s Normal file
View File

@ -0,0 +1,116 @@
PA_ROM equ 0x00c00000
Me equ 0x310000
Middle equ 0x320000
NK equ 0x340000
Magic equ 'Wdg_'
MACRO
MakeFunction &fnName
EXPORT &fnName[DS]
EXPORT .&fnName[PR]
TC &fnName[TC], &fnName[DS]
CSECT &fnName[DS]
DC.L .&fnName[PR]
DC.L TOC[tc0]
CSECT .&fnName[PR]
FUNCTION .&fnName[PR]
ENDM
MACRO
lisori &reg, &val
lis &reg, ((&val) >> 16) & 0xffff
ori &reg, &reg, (&val) & 0xffff
ENDM
MakeFunction __start
import .wedge
; Pointers in r20, scratch values in r0
; Need to reference MagicSentinel so that it gets put before the string table
; (There is probably a better way)
b * + 8
dc.l MagicSentinel{RO}
; Initial debug log
lisori r20, PA_ROM + Middle
lisori r0, 'WgLg'
stw r0, -8(r20)
li r0, 0
stw r0, -4(r20)
; Search for the string table (tested, works)
bl * + 4
mflr r20 ; start here
@a lwzu r0, 4(r20) ; find the sentinel
xoris r0, r0, Magic >> 16
cmplwi r0, Magic & 0xffff
bne @a
@b lwzu r0, 4(r20) ; skip the csect padding
cmpwi r0, 0
beq @b
; Set RTOC and save string table ptr at -4(RTOC)
lisori RTOC, PA_ROM + Middle - 64
stw r20, -4(RTOC)
; Get a stack, just below the waistline
lisori SP, PA_ROM + Middle - 128
; Go
b .wedge
MakeFunction NanoKernelJump
lisori r0, PA_ROM + NK
mtlr r0
blr
MakeFunction asm_putc
; Just a stub/test function for now
lisori r6, PA_ROM + Middle
lwz r5, -4(r6)
; lbz r4, 0(r3)
stbx r3, r5, r6
addi r5, r5, 1
stw r5, -4(r6)
li r3, 0
blr
; Insert a sentinel value just before the C string table
; (Requires PPCLink -codeorder source -roistext on)
csect MagicSentinel[RO]
dc.l Magic

210
printf.c Normal file
View File

@ -0,0 +1,210 @@
/*
File: printf.c
Copyright (C) 2004 Kustaa Nyholm
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "printf.h"
typedef void (*putcf) (void*,char);
void asm_putc (char);
#ifdef PRINTF_LONG_SUPPORT
static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf)
{
int n=0;
unsigned int d=1;
while (num/d >= base)
d*=base;
while (d!=0) {
int dgt = num / d;
num%=d;
d/=base;
if (n || dgt>0|| d==0) {
*bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
++n;
}
}
*bf=0;
}
static void li2a (long num, char * bf)
{
if (num<0) {
num=-num;
*bf++ = '-';
}
uli2a(num,10,0,bf);
}
#endif
static void ui2a(unsigned int num, unsigned int base, int uc,char * bf)
{
int n=0;
unsigned int d=1;
while (num/d >= base)
d*=base;
while (d!=0) {
int dgt = num / d;
num%= d;
d/=base;
if (n || dgt>0 || d==0) {
*bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10);
++n;
}
}
*bf=0;
}
static void i2a (int num, char * bf)
{
if (num<0) {
num=-num;
*bf++ = '-';
}
ui2a(num,10,0,bf);
}
static int a2d(char ch)
{
if (ch>='0' && ch<='9')
return ch-'0';
else if (ch>='a' && ch<='f')
return ch-'a'+10;
else if (ch>='A' && ch<='F')
return ch-'A'+10;
else return -1;
}
static char a2i(char ch, char** src,int base,int* nump)
{
char* p= *src;
int num=0;
int digit;
while ((digit=a2d(ch))>=0) {
if (digit>base) break;
num=num*base+digit;
ch=*p++;
}
*src=p;
*nump=num;
return ch;
}
static void putchw(int n, char z, char* bf)
{
char fc=z? '0' : ' ';
char ch;
char* p=bf;
while (*p++ && n > 0)
n--;
while (n-- > 0)
asm_putc(fc);
while ((ch= *bf++))
asm_putc(ch);
}
void tfp_format(char *fmt, va_list va)
{
char bf[12];
char ch;
while ((ch=*(fmt++))) {
if (ch!='%')
asm_putc(ch);
else {
char lz=0;
#ifdef PRINTF_LONG_SUPPORT
char lng=0;
#endif
int w=0;
ch=*(fmt++);
if (ch=='0') {
ch=*(fmt++);
lz=1;
}
if (ch>='0' && ch<='9') {
ch=a2i(ch,&fmt,10,&w);
}
#ifdef PRINTF_LONG_SUPPORT
if (ch=='l') {
ch=*(fmt++);
lng=1;
}
#endif
switch (ch) {
case 0:
goto abort;
case 'u' : {
#ifdef PRINTF_LONG_SUPPORT
if (lng)
uli2a(va_arg(va, unsigned long int),10,0,bf);
else
#endif
ui2a(va_arg(va, unsigned int),10,0,bf);
putchw(w,lz,bf);
break;
}
case 'd' : {
#ifdef PRINTF_LONG_SUPPORT
if (lng)
li2a(va_arg(va, unsigned long int),bf);
else
#endif
i2a(va_arg(va, int),bf);
putchw(w,lz,bf);
break;
}
case 'x': case 'X' :
#ifdef PRINTF_LONG_SUPPORT
if (lng)
uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf);
else
#endif
ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf);
putchw(w,lz,bf);
break;
case 'c' :
asm_putc((char)(va_arg(va, int)));
break;
case 's' :
putchw(w,0,va_arg(va, char*));
break;
case '%' :
asm_putc(ch);
default:
break;
}
}
}
abort:;
}
extern void printf(char *fmt, ...)
{
va_list va;
va_start(va,fmt);
tfp_format(fmt,va);
va_end(va);
}

98
printf.h Normal file
View File

@ -0,0 +1,98 @@
/*
File: printf.h
Copyright (C) 2004 Kustaa Nyholm
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
This library is realy just two files: 'printf.h' and 'printf.c'.
They provide a simple and small (+200 loc) printf functionality to
be used in embedded systems.
I've found them so usefull in debugging that I do not bother with a
debugger at all.
They are distributed in source form, so to use them, just compile them
into your project.
Two printf variants are provided: printf and sprintf.
The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'.
Zero padding and field width are also supported.
If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the
long specifier is also
supported. Note that this will pull in some long math routines (pun intended!)
and thus make your executable noticably longer.
The memory foot print of course depends on the target cpu, compiler and
compiler options, but a rough guestimate (based on a H8S target) is about
1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
Not too bad. Your milage may vary. By hacking the source code you can
get rid of some hunred bytes, I'm sure, but personally I feel the balance of
functionality and flexibility versus code size is close to optimal for
many embedded systems.
To use the printf you need to supply your own character output function,
something like :
void putc ( void* p, char c)
{
while (!SERIAL_PORT_EMPTY) ;
SERIAL_PORT_TX_REGISTER = c;
}
Before you can call printf you need to initialize it to use your
character output function with something like:
init_printf(NULL,putc);
Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',
the NULL (or any pointer) you pass into the 'init_printf' will eventually be
passed to your 'putc' routine. This allows you to pass some storage space (or
anything realy) to the character output function, if necessary.
This is not often needed but it was implemented like that because it made
implementing the sprintf function so neat (look at the source code).
The code is re-entrant, except for the 'init_printf' function, so it
is safe to call it from interupts too, although this may result in mixed output.
If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
The printf and sprintf functions are actually macros that translate to
'tfp_printf' and 'tfp_sprintf'. This makes it possible
to use them along with 'stdio.h' printf's in a single source file.
You just need to undef the names before you include the 'stdio.h'.
Note that these are not function like macros, so if you have variables
or struct members with these names, things will explode in your face.
Without variadic macros this is the best we can do to wrap these
fucnction. If it is a problem just give up the macros and use the
functions directly or rename them.
For further details see source code.
regs Kusti, 23.10.2004
*/
#ifndef __TFP_PRINTF__
#define __TFP_PRINTF__
#include <stdarg.h>
extern void printf(char *fmt, ...);
#endif