mirror of
https://github.com/elliotnunn/powermac-rom.git
synced 2024-11-29 12:49:58 +00:00
2121 lines
43 KiB
ArmAsm
2121 lines
43 KiB
ArmAsm
;_______________________________________________________________________
|
|
; START OF NANOKERNEL
|
|
;
|
|
; Init.s is the first code file included by NanoKernel.s. It contains:
|
|
; the NanoKernel header (both declarative and executable)
|
|
;
|
|
; The NanoKernel header follows:
|
|
;_______________________________________________________________________
|
|
|
|
|
|
|
|
|
|
; This is the entry point from the Trampoline (our Open Firmware-savvy
|
|
; bootloader for NewWorld Macs, which is part of the Mac OS ROM file).
|
|
;
|
|
; When we receive control:
|
|
; r3 = ConfigInfo
|
|
; r4 = ProcessorInfo
|
|
; r5 = SystemInfo
|
|
; r6 = DiagInfo
|
|
; r7 = RTAS_flag ('RTAS' or 0)
|
|
; r8 = RTAS_proc
|
|
; r9 = HWInfo
|
|
; (and also, we can be sure that we are executing from the
|
|
; NewWorld ROM image that the Trampoline loaded into RAM)
|
|
;
|
|
; First we need to avoid executing the data that follows:
|
|
|
|
b EndOfNanoKernelHeader
|
|
|
|
|
|
|
|
; On OldWorld Macs, the 68k code in the 'boot' 3 resource
|
|
; (of the System or enabler file) loads the NanoKernel
|
|
; from the 'krnl' 0 resource (of the System file), and
|
|
; uses it to replace the ROM kernel.
|
|
;
|
|
; This code probably uses the following header:
|
|
|
|
dc.w kNanoKernelVersion
|
|
dc.w 12
|
|
dc.w 0x400
|
|
dc.w 0
|
|
EndOfNanoKernelHeader
|
|
|
|
|
|
|
|
; Do some sanity checking after receiving control from the Trampoline.
|
|
|
|
; cr5_eq is cleared for the builtin init process
|
|
|
|
crclr cr5_eq
|
|
|
|
|
|
; If data paging is off, jump straight to the builtin init code
|
|
|
|
mfmsr r0
|
|
rlwinm. r0, r0, 0, MSR_DRbit, MSR_DRbit
|
|
beql InitBuiltin
|
|
|
|
|
|
; But if data paging is on, do some very strange things...
|
|
|
|
; Does LR contain a return address, or my address, or...?
|
|
mflr r9
|
|
subi r9, r9, 28
|
|
|
|
; Prepare to jump to one of the filthy branch instructions
|
|
; that Trampoline stuffs into ConfigInfo
|
|
addi r12, r3, 64
|
|
|
|
; Unset MSR_POW, MSR_ILE, MSR_EE, MSR_IR and MSR_DR
|
|
mfmsr r11
|
|
li r10, -0x7fd0
|
|
andc r11, r11, r10
|
|
|
|
; Jump and set MSR with an RFI.
|
|
mtspr srr0, r12
|
|
mtspr srr1, r11
|
|
rfi
|
|
|
|
|
|
|
|
; This (offset 0x40) is the entry point from 'boot' 3 on OldWorld.
|
|
;
|
|
; The offset *might* be encoded in the header above!
|
|
;
|
|
; When we receive control:
|
|
; sprg0 = old KDP/EWA/r1 ptr
|
|
; r3 = PA_NanoKernelCode
|
|
; r4 = physical base of our global area
|
|
; r5 = NoIdeaR23
|
|
; r6 = PA_EDP or zero?
|
|
; r7 = ROMHeader.ROMRelease (e.g. 0x10B5 is 1.0ß5)
|
|
;
|
|
; For clarity, the NanoKernel-replacement code is included from
|
|
; another file. It copies the old kernel structures to a new area
|
|
; and adopts them as our own, with some modifications.
|
|
;
|
|
; Jumps to InitHighLevel (below) when finished.
|
|
|
|
include 'NKReplacementInit.s'
|
|
|
|
|
|
|
|
; Function that fills a new InfoRecord Page (IRP) with the
|
|
; bus error-eliciting value, 0x68f1.
|
|
; (called by both builtin and replacement code paths)
|
|
|
|
; CLOB r10, r12
|
|
|
|
InitIRP
|
|
lwz r12, EWA.PA_IRP(r1)
|
|
|
|
@wipe_loop
|
|
lisori r10, 0x68f168f1
|
|
stw r10, 0(r12)
|
|
stw r10, 4(r12)
|
|
addi r12, r12, 8
|
|
andi. r10, r12, 0xfff
|
|
bne @wipe_loop
|
|
blr
|
|
|
|
|
|
|
|
; This is the code that does the bulk of the builtin-specific init.
|
|
;
|
|
; If the Trampoline has not passed in a valid HWInfo struct then
|
|
; this code will depend on ProcessorInfoTable.s. In that case it
|
|
; will jump to ProcessorInfoTable.s:OverrideProcessorInfo, which
|
|
; will fall though to FinishInitBuiltin.
|
|
;
|
|
; But normally, this code will jump straight to FinishInitBuiltin.
|
|
|
|
include 'NKBuiltinInit.s'
|
|
|
|
|
|
|
|
; Table used by the common init code (below) to fill some KDP flags
|
|
; indicating processor capabilities (e.g. presence of L2CR register)
|
|
;
|
|
; No code here.
|
|
|
|
include 'NKProcFlagsTbl.s'
|
|
|
|
|
|
|
|
; Table used by the builtin init code (above) to populate some of
|
|
; the ProcessorInfo struct when information from the Trampoline
|
|
; is lacking.
|
|
;
|
|
; Includes OverrideProcessorInfo code for use by InitBuiltin.s.
|
|
; This code falls through to FinishInitBuiltin below.
|
|
|
|
include 'NKProcInfoTbl.s'
|
|
|
|
|
|
|
|
; Tidy up the builtin init process before joining the common
|
|
; init code path.
|
|
;
|
|
; This code might be accessed by fall-through from
|
|
; ProcessorInfoTable.s:OverrideProcessorInfo, or by branch
|
|
; from InitBuiltin.s
|
|
|
|
FinishInitBuiltin
|
|
|
|
; Set ProcessorInfo version in case ProcessorInfo had to be loaded
|
|
; from the table above.
|
|
|
|
li r8, 0x0112
|
|
sth r8, KDP.InfoRecord + InfoRecord.NKProcessorInfoVer(r1)
|
|
|
|
|
|
; Copy some choice values out of KDP's copy of NKProcessorInfo
|
|
|
|
lwz r9, KDP.ProcessorInfo + NKProcessorInfo.DecClockRateHz(r1)
|
|
stw r9, KDP.ProcessorInfo + NKProcessorInfo.ClockRates + 8(r1)
|
|
|
|
lwz r9, KDP.ProcessorInfo + NKProcessorInfo.BusClockRateHz(r1)
|
|
stw r9, KDP.ProcessorInfo + NKProcessorInfo.ClockRates + 4(r1)
|
|
|
|
lwz r9, KDP.ProcessorInfo + NKProcessorInfo.CpuClockRateHz(r1)
|
|
stw r9, KDP.ProcessorInfo + NKProcessorInfo.ClockRates + 0(r1)
|
|
|
|
li r9, 0
|
|
sth r9, KDP.ProcessorInfo + NKProcessorInfo.SetToZero(r1)
|
|
|
|
lwz r8, KDP.ProcessorInfo + NKProcessorInfo.DecClockRateHz(r1)
|
|
stw r8, PSA.DecClockRateHzCopy(r1)
|
|
|
|
|
|
; Test AltiVec and MQ registers
|
|
|
|
; Prepare a simple vector table to ignore illegal
|
|
; instructions (like lvewx on a G3 ;)
|
|
lwz r9, KDP.PA_NanoKernelCode(r1)
|
|
|
|
llabel r8, IgnoreSoftwareInt
|
|
add r8, r8, r9
|
|
stw r8, KDP.YellowVecBase + VecTable.ProgramIntVector(r1)
|
|
|
|
llabel r8, HandlePerfMonitorInt
|
|
add r8, r8, r9
|
|
stw r8, KDP.YellowVecBase + VecTable.PerfMonitorVector(r1)
|
|
|
|
addi r8, r1, KDP.YellowVecBase
|
|
mtsprg 3, r8
|
|
|
|
|
|
; Test MQ and save feature field
|
|
lis r8, 1 << (15 - EWA.kFlagHasMQ)
|
|
mtspr mq, r8
|
|
li r8, 0
|
|
mfspr r8, mq
|
|
stw r8, PSA.FlagsTemplate(r1)
|
|
|
|
; Add AV and save that in scratch field
|
|
_bset r9, r8, EWA.kFlagVec
|
|
stw r9, EWA.r0(r1)
|
|
|
|
; Load from scratch field into a vector register
|
|
addi r9, r1, 0
|
|
lvewx v0, 0, r9
|
|
|
|
; Save MQ into the scratch register in case vector save fails
|
|
stw r8, EWA.r0(r1)
|
|
|
|
; Try save vector register (with AV flag) to scratch field
|
|
stvewx v0, 0, r9
|
|
|
|
; Scratch field now contains AltiVec and MQ flags.
|
|
; Copy it to FlagsTemplate
|
|
lwz r8, EWA.r0(r1)
|
|
stw r8, PSA.FlagsTemplate(r1)
|
|
|
|
; initial blue flags = global template + EWA.kFlagEmu + EWA.kFlag9
|
|
oris r7, r8, 0xa0
|
|
stw r7, EWA.Flags(r1)
|
|
|
|
|
|
; Emulator data and code pointers useful for the common code path?
|
|
|
|
lwz r6, KDP.PA_ECB(r1)
|
|
lwz r10, KDP.LA_EmulatorKernelTrapTable(r1)
|
|
|
|
|
|
; Create MSR (machine status register) values for use by the common code path
|
|
|
|
mfmsr r14
|
|
|
|
; Zero out a reserved bit. Considering next insn, should have no effect
|
|
rlwinm r14, r14, 0, 7, 5
|
|
|
|
; Test for and keep MSR_IP (IVT location) flag
|
|
; (presumably set by Trampoline)
|
|
andi. r14, r14, MSR_IP
|
|
|
|
; "KernelModeMSR" -- Seems not to get used?
|
|
ori r15, r14, MSR_ME + MSR_DR + MSR_RI
|
|
|
|
; "MSR"
|
|
ori r11, r14, MSR_EE + MSR_PR + MSR_ME + MSR_IR + MSR_DR + MSR_RI
|
|
stw r11, PSA.UserModeMSR(r1)
|
|
|
|
|
|
; Zero out a bunch of registers.
|
|
|
|
li r13, 0
|
|
li r12, 0
|
|
li r0, 0
|
|
li r2, 0
|
|
li r3, 0
|
|
li r4, 0
|
|
|
|
|
|
|
|
; The builtin kernel can be partly reinited by a 68k RESET trap.
|
|
; Rene says this is for address space setup.
|
|
|
|
ResetBuiltinKernel
|
|
|
|
crclr cr5_eq
|
|
|
|
|
|
|
|
; The common code path! InitIRP has been called but IRP is
|
|
; otherwise untouched (InfoRecord still in KDP).
|
|
;
|
|
; We get here by a jump from InitReplacement.s
|
|
; or by fallthough from FinishInitBuiltin above.
|
|
;
|
|
; When we get here:
|
|
; cr5_eq = is_replacement_kernel
|
|
; cr0 will be set if IVT is in high meg (MSR.IP)
|
|
; r1 = KDP
|
|
; r2 = 0
|
|
; r3 = 0
|
|
; r4 = 0
|
|
; r5 = SystemInfo
|
|
; r6 = ECB
|
|
; r7 = Flags
|
|
; r9 = even more altivec crud
|
|
; r10 = LA_EmulatorKernelTrapTable
|
|
; r11 = MSR
|
|
; r12 = 0
|
|
; r13 = 0
|
|
; r15 = KernelModeMSR
|
|
|
|
InitHighLevel
|
|
|
|
|
|
; The XER contains carries, overflows and string lengths.
|
|
; Apple seems to use it for all sorts of crap.
|
|
|
|
mfxer r17
|
|
stw r17, ContextBlock.XER(r6)
|
|
|
|
|
|
|
|
; Boring intro from the high-level init code
|
|
|
|
_log 'Kernel code base at 0x'
|
|
|
|
lwz r8, KDP.PA_NanoKernelCode(r1)
|
|
mr r8, r8
|
|
bl Printw
|
|
|
|
_log ' Physical RAM size 0x'
|
|
|
|
lwz r8, EWA.PA_IRP(r1)
|
|
lwz r8, IRP.SystemInfo + NKSystemInfo.PhysicalMemorySize(r8)
|
|
mr r8, r8
|
|
bl Printw
|
|
|
|
_log 'bytes^n'
|
|
|
|
|
|
|
|
; Copy InfoRecord from KDP to IRP.
|
|
; (Does this become the authoritative version?)
|
|
|
|
lisori r22, InfoRecord.Size
|
|
lwz r9, EWA.PA_IRP(r1)
|
|
addi r8, r1, KDP.InfoRecord
|
|
addi r9, r9, IRP.InfoRecord
|
|
|
|
@loop
|
|
subic. r22, r22, 4
|
|
lwzx r0, r22, r8
|
|
stwx r0, r22, r9
|
|
bgt @loop
|
|
|
|
|
|
|
|
; Some useful values for filling tables
|
|
|
|
lwz r26, KDP.PA_ConfigInfo(r1)
|
|
lwz r25, KDP.PA_NanoKernelCode(r1)
|
|
lwz r18, KDP.PA_PageMapStart(r1)
|
|
|
|
|
|
|
|
; A quick reminder about wordfill:
|
|
; ARG void *r3 dest, long r22 len, long r23 fill
|
|
|
|
|
|
|
|
; Fill with Panics: Yellow, Orange, Red (KDP)
|
|
; Violet, Blue (PSA)
|
|
|
|
llabel r23, panic
|
|
add r23, r23, r25
|
|
|
|
addi r8, r1, KDP.YellowVecBase
|
|
li r22, VecTable.Size
|
|
bl wordfill
|
|
|
|
addi r8, r1, KDP.OrangeVecBase
|
|
li r22, VecTable.Size
|
|
bl wordfill
|
|
|
|
addi r8, r1, KDP.RedVecBase
|
|
li r22, VecTable.Size
|
|
bl wordfill
|
|
|
|
addi r8, r1, PSA.VioletVecBase
|
|
li r22, VecTable.Size
|
|
bl wordfill
|
|
|
|
addi r8, r1, PSA.BlueVecBase
|
|
li r22, VecTable.Size
|
|
bl wordfill
|
|
|
|
|
|
|
|
; Fill Green (PSA) with IgnoreSoftwareInt
|
|
|
|
llabel r23, IgnoreSoftwareInt
|
|
add r23, r23, r25
|
|
|
|
addi r8, r1, PSA.GreenVecBase
|
|
li r22, VecTable.Size
|
|
bl wordfill
|
|
|
|
|
|
|
|
; Activate Yellow and fill Yellow and Orange (KDP)
|
|
|
|
addi r9, r1, KDP.YellowVecBase
|
|
mtsprg 3, r9
|
|
|
|
addi r8, r1, KDP.OrangeVecBase
|
|
|
|
llabel r23, panic
|
|
add r23, r23, r25
|
|
stw r23, VecTable.SystemResetVector(r9)
|
|
stw r23, VecTable.SystemResetVector(r8)
|
|
|
|
llabel r23, IntMachineCheck
|
|
add r23, r23, r25
|
|
stw r23, VecTable.MachineCheckVector(r9)
|
|
stw r23, VecTable.MachineCheckVector(r8)
|
|
|
|
llabel r23, IntDSI
|
|
add r23, r23, r25
|
|
stw r23, VecTable.DSIVector(r9)
|
|
stw r23, VecTable.DSIVector(r8)
|
|
|
|
llabel r23, IntISI
|
|
add r23, r23, r25
|
|
stw r23, VecTable.ISIVector(r9)
|
|
stw r23, VecTable.ISIVector(r8)
|
|
|
|
; Difference: Yellow seems more likely to reach PIH
|
|
llabel r23, IntExternalYellow
|
|
add r23, r23, r25
|
|
stw r23, VecTable.ExternalIntVector(r9) ; yellow
|
|
|
|
llabel r23, IntExternalOrange
|
|
add r23, r23, r25
|
|
stw r23, VecTable.ExternalIntVector(r8) ; orange
|
|
|
|
llabel r23, IntAlignment
|
|
add r23, r23, r25
|
|
stw r23, VecTable.AlignmentIntVector(r9)
|
|
stw r23, VecTable.AlignmentIntVector(r8)
|
|
|
|
llabel r23, IntProgram
|
|
add r23, r23, r25
|
|
stw r23, VecTable.ProgramIntVector(r9)
|
|
stw r23, VecTable.ProgramIntVector(r8)
|
|
|
|
llabel r23, IntFPUnavail
|
|
add r23, r23, r25
|
|
stw r23, VecTable.FPUnavailVector(r9)
|
|
stw r23, VecTable.FPUnavailVector(r8)
|
|
|
|
llabel r23, IntDecrementer
|
|
add r23, r23, r25
|
|
stw r23, VecTable.DecrementerVector(r9)
|
|
stw r23, VecTable.DecrementerVector(r8)
|
|
|
|
llabel r23, IntSyscall
|
|
add r23, r23, r25
|
|
stw r23, VecTable.SyscallVector(r9)
|
|
stw r23, VecTable.SyscallVector(r8)
|
|
|
|
llabel r23, IntPerfMonitor
|
|
add r23, r23, r25
|
|
stw r23, VecTable.PerfMonitorVector(r9)
|
|
stw r23, VecTable.PerfMonitorVector(r8)
|
|
|
|
llabel r23, IntTrace
|
|
add r23, r23, r25
|
|
stw r23, VecTable.TraceVector(r9)
|
|
stw r23, VecTable.TraceVector(r8)
|
|
stw r23, 0x0080(r9) ; Unexplored parts of vecBase
|
|
stw r23, 0x0080(r8)
|
|
|
|
llabel r23, FDP_1c40 ; seems AltiVec-related
|
|
add r23, r23, r25
|
|
stw r23, 0x0058(r9)
|
|
stw r23, 0x0058(r8)
|
|
|
|
llabel r23, IntThermalEvent ; thermal event
|
|
add r23, r23, r25
|
|
stw r23, VecTable.ThermalEventVector(r9)
|
|
stw r23, VecTable.ThermalEventVector(r8)
|
|
|
|
|
|
|
|
; Fill Red (KDP), used while were emulating some instructions
|
|
|
|
addi r8, r1, KDP.RedVecBase
|
|
|
|
llabel r23, panic
|
|
add r23, r23, r25
|
|
stw r23, VecTable.SystemResetVector(r8)
|
|
|
|
llabel r23, IntMachineCheckMemRetry
|
|
add r23, r23, r25
|
|
stw r23, VecTable.MachineCheckVector(r8)
|
|
|
|
llabel r23, IntDSIOtherOther
|
|
add r23, r23, r25
|
|
stw r23, VecTable.DSIVector(r8)
|
|
|
|
llabel r23, IntSyscall
|
|
add r23, r23, r25
|
|
stw r23, VecTable.SyscallVector(r8)
|
|
|
|
|
|
|
|
; Fill Violet (PSA)
|
|
|
|
; Fill everything with this
|
|
llabel r23, major_0x04a20
|
|
add r23, r23, r25
|
|
addi r8, r1, PSA.VioletVecBase
|
|
li r22, VecTable.Size
|
|
bl wordfill
|
|
|
|
; Then override with these
|
|
llabel r23, panic
|
|
add r23, r23, r25
|
|
stw r23, VecTable.SystemResetVector(r8)
|
|
|
|
llabel r23, IntDSI
|
|
add r23, r23, r25
|
|
stw r23, VecTable.DSIVector(r8)
|
|
|
|
llabel r23, IntISI
|
|
add r23, r23, r25
|
|
stw r23, VecTable.ISIVector(r8)
|
|
|
|
llabel r23, IntAlignment
|
|
add r23, r23, r25
|
|
stw r23, VecTable.AlignmentIntVector(r8)
|
|
|
|
|
|
|
|
; For the PowerDispatch selector that governs idle modes
|
|
|
|
bl InitIdleVecTable
|
|
|
|
|
|
|
|
; Fill Blue (PSA)
|
|
|
|
addi r8, r1, PSA.BlueVecBase
|
|
|
|
llabel r23, panic
|
|
add r23, r23, r25
|
|
stw r23, VecTable.SystemResetVector(r8)
|
|
|
|
llabel r23, IntMachineCheck
|
|
add r23, r23, r25
|
|
stw r23, VecTable.MachineCheckVector(r8)
|
|
|
|
llabel r23, IntDSIOther
|
|
add r23, r23, r25
|
|
stw r23, VecTable.DSIVector(r8)
|
|
|
|
llabel r23, IntSyscall
|
|
add r23, r23, r25
|
|
stw r23, VecTable.SyscallVector(r8)
|
|
|
|
|
|
|
|
; Fill the NanoKernelCallTable, the IntProgram interface to the NanoKernel
|
|
|
|
; Start with a default function
|
|
|
|
llabel r23, major_0x046d0
|
|
add r23, r23, r25
|
|
|
|
addi r8, r1, KDP.NanoKernelCallTable
|
|
|
|
li r22, NanoKernelCallTable.Size
|
|
|
|
@kctab_initloop
|
|
subic. r22, r22, 4
|
|
stwx r23, r8, r22
|
|
bne @kctab_initloop
|
|
|
|
|
|
; Then some overrides (names still pretty poor)
|
|
|
|
llabel r23, kcReturnFromException
|
|
add r23, r23, r25
|
|
stw r23, NanoKernelCallTable.ReturnFromException(r8)
|
|
|
|
llabel r23, kcRunAlternateContext
|
|
add r23, r23, r25
|
|
stw r23, NanoKernelCallTable.RunAlternateContext(r8)
|
|
|
|
llabel r23, kcResetSystem
|
|
add r23, r23, r25
|
|
stw r23, NanoKernelCallTable.ResetSystem(r8)
|
|
|
|
llabel r23, kcVMDispatch
|
|
add r23, r23, r25
|
|
stw r23, NanoKernelCallTable.VMDispatch(r8)
|
|
|
|
llabel r23, kcPrioritizeInterrupts
|
|
add r23, r23, r25
|
|
stw r23, NanoKernelCallTable.PrioritizeInterrupts(r8)
|
|
|
|
llabel r23, kcPowerDispatch
|
|
add r23, r23, r25
|
|
stw r23, NanoKernelCallTable.PowerDispatch(r8)
|
|
|
|
llabel r23, kcRTASDispatch
|
|
add r23, r23, r25
|
|
stw r23, NanoKernelCallTable.RTASDispatch(r8)
|
|
|
|
llabel r23, kcCacheDispatch
|
|
add r23, r23, r25
|
|
stw r23, NanoKernelCallTable.CacheDispatch(r8)
|
|
|
|
llabel r23, kcMPDispatch
|
|
add r23, r23, r25
|
|
stw r23, NanoKernelCallTable.MPDispatch(r8)
|
|
|
|
llabel r23, kcThud
|
|
add r23, r23, r25
|
|
stw r23, NanoKernelCallTable.Thud(r8)
|
|
|
|
|
|
|
|
; Set ProcessorFlags (and two other bytes) from PVR.
|
|
; Nigh unforgivably ugly code, but ProcessorFlagsTable.s
|
|
; describes what it does pretty well.
|
|
|
|
SetProcessorFlags
|
|
|
|
mfpvr r23
|
|
srwi r23, r23, 16
|
|
andi. r8, r23, 0x8000
|
|
bne @pvr_has_high_bit_set
|
|
|
|
; PVR < 0x8000 (therefore probably equals 000*)
|
|
cmplwi r23, 0x000f ; but if not, pretend it's zero
|
|
ble @pvr_not_low
|
|
li r23, 0x0000
|
|
@pvr_not_low
|
|
|
|
add r8, r25, r23
|
|
lbz r23, ProcessorFlagsTable - NKTop + 0(r8)
|
|
stb r23, KDP.CpuSpecificByte1(r1)
|
|
lbz r23, ProcessorFlagsTable - NKTop + 32(r8)
|
|
stb r23, KDP.CpuSpecificByte2(r1)
|
|
mfpvr r23
|
|
srwi r23, r23, 16
|
|
slwi r23, r23, 2
|
|
add r8, r25, r23
|
|
lwz r23, ProcessorFlagsTable - NKTop + 64(r8)
|
|
stw r23, KDP.ProcessorInfo + NKProcessorInfo.ProcessorFlags(r1)
|
|
b @done
|
|
|
|
@pvr_has_high_bit_set
|
|
andi. r23, r23, 0x7fff
|
|
|
|
cmplwi r23, 0x000f
|
|
ble @other_pvr_not_low
|
|
li r23, -0x10
|
|
@other_pvr_not_low
|
|
|
|
add r8, r25, r23
|
|
lbz r23, ProcessorFlagsTable - NKTop + 16(r8)
|
|
stb r23, KDP.CpuSpecificByte1(r1)
|
|
lbz r23, ProcessorFlagsTable - NKTop + 48(r8)
|
|
stb r23, KDP.CpuSpecificByte2(r1)
|
|
mfpvr r23
|
|
srwi r23, r23, 16
|
|
andi. r23, r23, 0x7fff
|
|
slwi r23, r23, 2
|
|
add r8, r25, r23
|
|
lwz r23, ProcessorFlagsTable - NKTop + 128(r8)
|
|
stw r23, KDP.ProcessorInfo + NKProcessorInfo.ProcessorFlags(r1)
|
|
b @done
|
|
|
|
@done
|
|
|
|
|
|
; Init the NCB Pointer Cache
|
|
|
|
_InvalNCBPointerCache scratch=r23
|
|
|
|
|
|
|
|
; Initialize the seven kernel locks (Count and Signature fields)
|
|
|
|
li r23, 0
|
|
stw r23, PSA.HTABLock + Lock.Count(r1)
|
|
stw r23, PSA.PIHLock + Lock.Count(r1)
|
|
stw r23, PSA.SchLock + Lock.Count(r1)
|
|
stw r23, PSA.ThudLock + Lock.Count(r1)
|
|
stw r23, PSA.RTASLock + Lock.Count(r1)
|
|
stw r23, PSA.DbugLock + Lock.Count(r1)
|
|
stw r23, PSA.PoolLock + Lock.Count(r1)
|
|
|
|
lisori r23, Lock.kHTABLockSignature
|
|
stw r23, PSA.HTABLock + Lock.Signature(r1)
|
|
|
|
lisori r23, Lock.kPIHLockSignature
|
|
stw r23, PSA.PIHLock + Lock.Signature(r1)
|
|
|
|
lisori r23, Lock.kSchLockSignature
|
|
stw r23, PSA.SchLock + Lock.Signature(r1)
|
|
|
|
lisori r23, Lock.kThudLockSignature ; older kernel versions have a powr lock?
|
|
stw r23, PSA.ThudLock + Lock.Signature(r1)
|
|
|
|
lisori r23, Lock.kRTASLockSignature
|
|
stw r23, PSA.RTASLock + Lock.Signature(r1)
|
|
|
|
lisori r23, Lock.kDbugLockSignature
|
|
stw r23, PSA.DbugLock + Lock.Signature(r1)
|
|
|
|
lisori r23, Lock.kPoolLockSignature
|
|
stw r23, PSA.PoolLock + Lock.Signature(r1)
|
|
|
|
|
|
|
|
; These seem to be register templates.
|
|
|
|
lisori r17, 0x7fffdead
|
|
|
|
stw r17, PSA.VectorRegInitWord(r1)
|
|
stw r17, PSA.SevenFFFDead2(r1)
|
|
stw r17, PSA.SevenFFFDead3(r1)
|
|
stw r17, PSA.SevenFFFDead4(r1)
|
|
|
|
|
|
|
|
; Set up the not-quite-a-heap 'pool' of dynamic NanoKernel storage.
|
|
;
|
|
; And then set up the structure (hash table?) mapping opaque
|
|
; usermode-facing IDs with numeric types to storage blocks.
|
|
|
|
bl InitPool
|
|
bl InitIDIndex
|
|
|
|
|
|
|
|
; Leave AllCpuFeatures in r7 for use waaaaay down there...
|
|
|
|
lwz r7, EWA.Flags(r1)
|
|
|
|
|
|
|
|
; Create a blue process to own the blue and idle tasks
|
|
|
|
; Allocate and check
|
|
li r8, 32 ;Process.Size
|
|
bl PoolAllocClear ; takes size and returns ptr, all in r8
|
|
|
|
mr. r31, r8
|
|
beq Init_Panic
|
|
|
|
; Get opaque ID
|
|
li r9, Process.kIDClass
|
|
bl MakeID
|
|
|
|
; Point KDP to it
|
|
stw r31, PSA.blueProcessPtr(r1)
|
|
|
|
; Save ID in self and KDP
|
|
stw r8, Process.ID(r31)
|
|
stw r8, KDP.NanoKernelInfo + NKNanoKernelInfo.blueProcessID(r1)
|
|
|
|
; Sign it
|
|
lisori r8, Process.kSignature
|
|
stw r8, Process.Signature(r31)
|
|
|
|
; blue and idle
|
|
li r8, 2
|
|
stw r8, Process.TaskCount(r31)
|
|
|
|
|
|
|
|
; Init a global linked list of coherence groups.
|
|
; Leave ptr in r30.
|
|
|
|
addi r30, r1, PSA.CoherenceGrpList
|
|
InitList r30, 'GRPS', scratch=r17
|
|
|
|
|
|
|
|
; Create the motherboard coherence group (CGRP, ID class 10) in the pool.
|
|
; Owns a linked list of GRPSes, is itself a linked list member.
|
|
; Leave ptr in r29.
|
|
|
|
; Allocate the main structure in the kernel pool, and check for a null ptr
|
|
li r8, 0x58 ;CoherenceGroup.Size
|
|
bl PoolAllocClear
|
|
mr. r31, r8
|
|
beq Init_Panic
|
|
|
|
|
|
; Append to the global CGRP list
|
|
addi r17, r31, CoherenceGroup.LLL
|
|
stw r30, LLL.Freeform(r17)
|
|
InsertAsPrev r17, r30, scratch=r18
|
|
|
|
|
|
; Init a list of the CPUs in this CGRP
|
|
addi r29, r31, CoherenceGroup.CPUList
|
|
InitList r29, CoherenceGroup.kSignature, scratch=r17
|
|
|
|
|
|
; Get opaque ID
|
|
mr r8, r31
|
|
li r9, CoherenceGroup.kIDClass
|
|
bl MakeID
|
|
stw r8, CoherenceGroup.CPUList + LLL.Freeform(r31)
|
|
|
|
|
|
; Congratulate ourselves
|
|
mr r16, r8 ; Print macro clobbers r8 (opaque ID), so save it
|
|
|
|
_log 'Created motherboard coherence group. ID '
|
|
|
|
mr r8, r16
|
|
bl Printw
|
|
|
|
_log '^n'
|
|
|
|
|
|
; Fill in some actual fields (then still have 48 unused bytes)
|
|
li r16, 1
|
|
stw r16, CoherenceGroup.CpuCount(r31)
|
|
stw r16, CoherenceGroup.ScheduledCpuCount(r31)
|
|
|
|
|
|
; problem: expecting to see more stuff set here
|
|
|
|
|
|
|
|
; Create a CPU struct in KDP with a linked list of coherence groups
|
|
|
|
; Place
|
|
subi r31, r1, CPU.EWA
|
|
addi r30, r31, CPU.EWABase
|
|
|
|
|
|
; Get opaque ID
|
|
mr r8, r31
|
|
li r9, CPU.kIDClass
|
|
bl MakeID
|
|
|
|
|
|
; Identify and sign
|
|
stw r8, CPU.ID(r31)
|
|
|
|
lisori r8, CPU.kSignature
|
|
stw r8, CPU.Signature(r31)
|
|
|
|
|
|
; Append to the motherboard CGRP
|
|
addi r17, r31, CPU.LLL
|
|
|
|
stw r29, LLL.Freeform(r17)
|
|
InsertAsPrev r17, r29, scratch=r18
|
|
|
|
|
|
; Actually populate something useful (still have one unused long)
|
|
lisori r8, 15
|
|
stw r8, CPU.Flags(r31)
|
|
|
|
; Matches code in KCCreateCpuStruct very closely
|
|
|
|
addi r8, r1, PSA.Base
|
|
stw r8, EWA.PA_PSA - EWA.Base(r30)
|
|
|
|
|
|
stw r1, EWA.PA_KDP - EWA.Base(r30)
|
|
|
|
li r8, 0
|
|
stw r8, 0x0318(r30) ; -0x28
|
|
sth r8, 0x020a(r30) ; -0x136
|
|
|
|
lisori r8, 'time'
|
|
stw r8, 0x0004(r30)
|
|
|
|
li r8, 0x04
|
|
stb r8, 0x0014(r30)
|
|
|
|
li r8, 0x01
|
|
stb r8, 0x0016(r30)
|
|
|
|
li r8, 0x00
|
|
stb r8, 0x0017(r30)
|
|
|
|
lisori r8, 0x7fffffff
|
|
stw r8, 0x0038(r30)
|
|
|
|
oris r8, r8, 0xffff
|
|
stw r8, 0x003c(r30)
|
|
|
|
|
|
|
|
; Copy the 32-element BATRangeInit array from ConfigInfo
|
|
; For odd-indexed longs (offsets 0x*4 and 0x*c) with bit 22 set:
|
|
; - unset that bit
|
|
; - increment the value by PA_ConfigInfo (so... they were relative?)
|
|
|
|
lwz r26, KDP.PA_ConfigInfo(r1)
|
|
addi r9, r26, NKConfigurationInfo.BATRangeInit - 4
|
|
addi r8, r1, KDP.BATs - 4
|
|
li r22, 0x80
|
|
|
|
@BAT_copyloop
|
|
lwzu r20, 4(r9) ; grab 8 bytes
|
|
lwzu r21, 4(r9)
|
|
|
|
stwu r20, 4(r8) ; store the first byte directly
|
|
|
|
rlwinm r23, r21, 0, 23, 21 ; munge the second byte
|
|
cmpw r21, r23
|
|
|
|
beq @bitnotset
|
|
add r21, r23, r26
|
|
@bitnotset
|
|
|
|
addic. r22, r22, -8
|
|
stwu r21, 4(r8) ; but store it eventually
|
|
bgt @BAT_copyloop
|
|
|
|
|
|
|
|
; Create a 'system' address space owned by the motherboard coherence
|
|
; group and by the MacOS process that we created earlier.
|
|
; Leave a ptr to the new AddressSpace in r30 and its ID in r16.
|
|
|
|
li r8, 0
|
|
lwz r9, PSA.blueProcessPtr(r1)
|
|
|
|
; ARG MPCoherenceID r8 owningCOHG ; 0 to use mobo COHG
|
|
; Process *r9 owningPROC
|
|
|
|
bl NKCreateAddressSpaceSub
|
|
|
|
; RET MPErr r8
|
|
; AddressSpace *r9
|
|
|
|
cmpwi r8, 0
|
|
mr r30, r9
|
|
bne Init_Panic
|
|
|
|
|
|
; The relationship between SPACes and PROCs is still unclear...
|
|
lwz r31, PSA.blueProcessPtr(r1)
|
|
|
|
|
|
; Save the new addr spc ID in system process struct and KDP
|
|
lwz r16, AddressSpace.ID(r30)
|
|
stw r16, Process.SystemAddressSpaceID(r31)
|
|
stw r16, PSA.SystemAddressSpaceID(r1)
|
|
|
|
|
|
; Save a few pointers to it for good measure
|
|
stw r30, Process.SystemAddressSpacePtr(r31)
|
|
stw r30, EWA.PA_CurAddressSpace(r1)
|
|
stw r30, PSA.OtherSystemAddrSpcPtr(r1)
|
|
|
|
|
|
|
|
; Show off the new address space struct, and at the same time,
|
|
; copy the BATs that we copied from ConfigInfo to KDP, into the struct.
|
|
|
|
_log 'Created system address space. ID '
|
|
|
|
mr r8, r16
|
|
bl Printw
|
|
|
|
_log '^n BATs '
|
|
|
|
lwz r16, 0x0288(r1) ; kdp.bat0l
|
|
lwz r17, 0x028c(r1) ; kdp.bat0u
|
|
stw r16, 0x0080(r30)
|
|
stw r17, 0x0084(r30)
|
|
|
|
mr r8, r16
|
|
bl Printw
|
|
mr r8, r17
|
|
bl Printw
|
|
_log ' '
|
|
|
|
lwz r16, 0x0298(r1) ; kdp.bat1l
|
|
lwz r17, 0x029c(r1) ; kdp.bat1u
|
|
stw r16, 0x0088(r30)
|
|
stw r17, 0x008c(r30)
|
|
|
|
mr r8, r16
|
|
bl Printw
|
|
mr r8, r17
|
|
bl Printw
|
|
_log ' '
|
|
|
|
lwz r16, 0x02a8(r1) ; kdp.bat2l
|
|
lwz r17, 0x02ac(r1) ; kdp.bat2u
|
|
stw r16, 0x0090(r30)
|
|
stw r17, 0x0094(r30)
|
|
|
|
mr r8, r16
|
|
bl Printw
|
|
mr r8, r17
|
|
bl Printw
|
|
_log ' '
|
|
|
|
lwz r16, 0x02b8(r1) ; kdp.bat3l
|
|
lwz r17, 0x02bc(r1) ; kdp.bat3u
|
|
stw r16, 0x0098(r30)
|
|
stw r17, 0x009c(r30)
|
|
|
|
mr r8, r16
|
|
bl Printw
|
|
mr r8, r17
|
|
bl Printw
|
|
_log '^n'
|
|
|
|
|
|
|
|
; Initialize the kernel queues. They are called:
|
|
;
|
|
; - PHYS (free list, in KDP, by InitFreeList)
|
|
; - DLYQ (in KDP, by me)
|
|
; - DBUG (in KDP, by me)
|
|
; - PAGQ (in KDP, has ID, by me)
|
|
; - NOTQ (in KDP, by me)
|
|
; - TMRQs (one in KDP, two in pool, one more in pool for Nanodebugger)
|
|
; - RDYQs (four in KDP, for each task priority)
|
|
|
|
; Free list in hardcoded KDP location
|
|
; ARG KernelData *r1
|
|
; CLOB r8, r9
|
|
bl InitFreeList
|
|
|
|
|
|
; Delay queue in hardcoded KDP location
|
|
|
|
addi r9, r1, PSA.DelayQueue
|
|
InitList r9, 'DLYQ', scratch=r8
|
|
|
|
|
|
; Debugger queue in hardcoded KDP location
|
|
|
|
addi r9, r1, PSA.DbugQueue
|
|
InitList r9, 'DBUG', scratch=r8
|
|
|
|
|
|
; Page queue in hardcoded KDP location...
|
|
|
|
addi r8, r1, PSA.PageQueue
|
|
|
|
; ...with opaque id...
|
|
li r9, Queue.kIDClass
|
|
bl MakeID
|
|
addi r9, r1, PSA.PageQueue
|
|
stw r8, LLL.Freeform(r9)
|
|
|
|
; ...which the blue task will probably want to know about
|
|
stw r8, KDP.NanoKernelInfo + NKNanoKernelInfo.pageQueueID(r1)
|
|
|
|
InitList r9, 'PAGQ', scratch=r16
|
|
|
|
|
|
; Not sure what these globals relate to
|
|
|
|
li r8, 0
|
|
stw r8, PSA.QueueRelatedZero1(r1)
|
|
stw r8, PSA.QueueRelatedZero2(r1)
|
|
|
|
|
|
; Notification queue in hardcoded KDP location
|
|
|
|
addi r9, r1, PSA.NotQueue
|
|
InitList r9, 'NOTQ', scratch=r16
|
|
|
|
|
|
; TMRQs (see comments above and with InitTMRQs)
|
|
; (These are all the same structure but only one is signed!)
|
|
|
|
bl InitTMRQs
|
|
|
|
|
|
; One ready for each task priority (critical, etc)
|
|
|
|
bl SchInit
|
|
|
|
|
|
|
|
; Set the BAT and segment registers (how were SRs calculated?)
|
|
|
|
lwz r8, EWA.PA_CurAddressSpace(r1)
|
|
li r9, 0
|
|
bl SchSwitchSpace
|
|
|
|
|
|
|
|
; Create the Blue MacOS task
|
|
|
|
; ARG Flags r7, Process *r8
|
|
; RET Task *r8
|
|
|
|
lwz r8, PSA.blueProcessPtr(r1)
|
|
bl CreateTask
|
|
|
|
; Check
|
|
mr. r31, r8
|
|
beq Init_Panic
|
|
|
|
lwz r8, Task.ID(r31)
|
|
stw r8, KDP.NanoKernelInfo + NKNanoKernelInfo.blueTaskID(r1)
|
|
|
|
|
|
; Can equal -1 or a 68k interrupt number. PIHes touch it.
|
|
li r8, -1
|
|
sth r8, PSA.Pending68kInt(r1)
|
|
|
|
;
|
|
stw r31, PSA.PA_BlueTask(r1)
|
|
stw r31, EWA.PA_CurTask(r1)
|
|
|
|
; Misc population
|
|
lisori r8, 'blue'
|
|
stw r8, Task.Name(r31)
|
|
|
|
li r8, 2
|
|
stb r8, Task.State(r31)
|
|
|
|
lisori r8, 0x30028 ; (Z>>Task.kFlag14) | (Z>>Task.kFlagBlue) | (Z>>Task.kFlag26) | (Z>>Task.kFlag28)
|
|
stw r8, Task.Flags(r31)
|
|
|
|
li r8, 200
|
|
stw r8, Task.Weight(r31)
|
|
|
|
li r8, Task.kNominalPriority
|
|
stb r8, Task.Priority(r31)
|
|
|
|
lhz r8, EWA.CPUIndex(r1) ; zero??????
|
|
sth r8, 0x001a(r31)
|
|
|
|
lwz r8, EWA.CPUBase + CPU.ID(r1)
|
|
stw r8, Task.CpuID(r31)
|
|
|
|
lwz r6, KDP.PA_ECB(r1)
|
|
stw r6, Task.ContextBlockPtr(r31) ; override structs own ECB area
|
|
|
|
lwz r16, Task.ContextBlock + ContextBlock.VectorSaveArea(r31)
|
|
stw r16, ContextBlock.VectorSaveArea(r6)
|
|
|
|
|
|
; Bang on about some stuff
|
|
|
|
_log 'System context at 0x'
|
|
mr r8, r6
|
|
bl Printw
|
|
|
|
_log ' Vector save area at 0x'
|
|
mr r8, r16
|
|
bl Printw
|
|
|
|
_log ' SDR1 0x'
|
|
mfspr r8, sdr1
|
|
mr r8, r8
|
|
bl Printw
|
|
_log '^n'
|
|
|
|
|
|
; Task enqueueing is still a bit of a mystery to me
|
|
|
|
_log 'Adding blue task '
|
|
lwz r8, Task.ID(r31)
|
|
mr r8, r8
|
|
bl Printw
|
|
_log 'to the ready queue^n'
|
|
|
|
addi r16, r31, Task.QueueMember
|
|
RemoveFromList r16, scratch1=r17, scratch2=r18
|
|
|
|
|
|
; ARG Task *r8
|
|
; CLOB r16, r17, r18
|
|
|
|
mr r8, r31
|
|
bl SchRdyTaskNow
|
|
|
|
bl CalculateTimeslice
|
|
|
|
|
|
|
|
; Do some things I do not understand
|
|
bl FlagSchEval
|
|
bl StartTimeslicing
|
|
|
|
|
|
|
|
; Create the idle task for the first CPU
|
|
|
|
; Unset EWA.kFlagVec so that
|
|
; idle task vector registers are not saved/restored
|
|
; (Leave the old value in r31)
|
|
|
|
mr r31, r7
|
|
_bclr r7, r7, EWA.kFlagVec
|
|
|
|
; ARG Flags r7, Process *r8
|
|
; RET Task *r8
|
|
|
|
lwz r8, PSA.blueProcessPtr(r1)
|
|
bl CreateTask
|
|
|
|
; Restore Flags
|
|
mr r7, r31
|
|
|
|
; Check
|
|
mr. r31, r8
|
|
beq Init_Panic
|
|
|
|
; Misc population
|
|
lisori r8, 'idle'
|
|
stw r8, Task.Name(r31)
|
|
|
|
|
|
lisori r8, 0xA0040 ; (Z>>Task.kFlag12) | (Z>>Task.kFlag14) | (Z>>Task.kFlag25)
|
|
stw r8, Task.Flags(r31)
|
|
|
|
; For the scheduler
|
|
li r8, 1
|
|
stw r8, Task.Weight(r31)
|
|
|
|
li r8, Task.kIdlePriority
|
|
stb r8, Task.Priority(r31)
|
|
|
|
; Blue does this too, probably zero, not sure why?
|
|
lhz r8, -0x116(r1)
|
|
sth r8, 0x01a(r31)
|
|
|
|
lwz r8, EWA.CPUBase + CPU.ID(r1)
|
|
stw r8, Task.CpuID(r31)
|
|
|
|
; Add a feature!?!?!?!
|
|
lwz r8, Task.ContextBlock + ContextBlock.Flags(r31)
|
|
oris r8, r8, 0x40
|
|
stw r8, Task.ContextBlock + ContextBlock.Flags(r31)
|
|
|
|
; Point task ECB at the idle loop within the nanokernel code
|
|
lwz r8, KDP.PA_NanoKernelCode(r1)
|
|
llabel r26, SchIdleTask
|
|
add r8, r8, r26
|
|
stw r8, Task.ContextBlock + ContextBlock.CodePtr(r31)
|
|
|
|
; The idle task runs in privileged mode with physical addressing
|
|
lwz r8, 0x01a4(r31)
|
|
andi. r8, r8, 0xbfcf ; unset loword (MSR_POW, MSR_ILE), MSR_PR, MSR_IR, MSR_DR
|
|
stw r8, 0x01a4(r31)
|
|
|
|
; Idle task for first CPU
|
|
addi r30, r1, EWA.CPUBase
|
|
stw r31, CPU.IdleTaskPtr(r30)
|
|
|
|
; Boast a bit
|
|
_log 'Adding idle task '
|
|
lwz r8, Task.ID(r31)
|
|
mr r8, r8
|
|
bl Printw
|
|
_log 'to the ready queue^n'
|
|
|
|
; This sure looks like a linked-list insertion
|
|
addi r16, r31, Task.QueueMember
|
|
RemoveFromList r16, scratch1=r17, scratch2=r18
|
|
|
|
; ARG Task *r8
|
|
; CLOB r16, r17, r18
|
|
|
|
mr r8, r31
|
|
bl SchRdyTaskNow
|
|
|
|
bl CalculateTimeslice
|
|
|
|
; Create a 'dummy' address space
|
|
li r8, 0
|
|
lwz r9, PSA.blueProcessPtr(r1)
|
|
|
|
; ARG MPCoherenceID r8 owningCOHG ; 0 to use mobo COHG
|
|
; Process *r9 owningPROC
|
|
|
|
bl NKCreateAddressSpaceSub
|
|
|
|
; RET MPErr r8
|
|
; AddressSpace *r9
|
|
|
|
cmpwi r8, 0
|
|
mr r30, r9
|
|
lwz r31, EWA.CPUBase + CPU.IdleTaskPtr(r1)
|
|
bne Init_Panic
|
|
|
|
stw r30, Task.AddressSpacePtr(r31)
|
|
|
|
|
|
|
|
; Now do something with the page table
|
|
lwz r7, EWA.Flags(r1)
|
|
lwz r26, KDP.PA_ConfigInfo(r1)
|
|
lwz r18, KDP.PA_PageMapStart(r1)
|
|
|
|
|
|
|
|
; Put HTABORG and PTEGMask in KDP, and zero out the last PTEG
|
|
|
|
beq cr5, @skip_zeroing_pteg
|
|
mfspr r8, sdr1
|
|
|
|
; get settable HTABMASK bits
|
|
rlwinm r22, r8, 16, 7, 15
|
|
|
|
; and HTABORG
|
|
rlwinm r8, r8, 0, 0, 15
|
|
|
|
; get a PTEGMask from upper half of HTABMASK
|
|
ori r22, r22, (-64) & 0xffff
|
|
|
|
; Save in KDP (OldWorld must do this another way)
|
|
stw r8, KDP.HTABORG(r1)
|
|
stw r22, KDP.PTEGMask(r1)
|
|
|
|
; zero out the last PTEG in the HTAB
|
|
li r23, 0
|
|
addi r22, r22, 64
|
|
@loop
|
|
subic. r22, r22, 4
|
|
stwx r23, r8, r22
|
|
bgt @loop
|
|
@skip_zeroing_pteg
|
|
|
|
|
|
; Rather self-explanatory. Do this even if we did not just edit HTAB.
|
|
|
|
bl PagingFlushTLB
|
|
|
|
|
|
|
|
; Copy the ConfigInfo pagemap into KDP, absolut-ising entries
|
|
; whose physical addresses are relative to ConfigInfo.
|
|
|
|
beq cr5, @skip_copying_pagemap
|
|
lwz r9, NKConfigurationInfo.PageMapInitOffset(r26) ; from base of CI
|
|
lwz r22, NKConfigurationInfo.PageMapInitSize(r26)
|
|
add r9, r9, r26
|
|
|
|
@copyloop_pagemap
|
|
subi r22, r22, 4 ; load a word from the CI pagemap (top first)
|
|
lwzx r21, r9, r22
|
|
|
|
andi. r23, r21, PMDT.DaddyFlag | PMDT.PhysicalIsRelativeFlag
|
|
cmpwi r23, PMDT.PhysicalIsRelativeFlag
|
|
bne @physical_address_not_relative_to_config_info
|
|
|
|
rlwinm r21, r21, 0, ~PMDT.PhysicalIsRelativeFlag
|
|
add r21, r21, r26
|
|
@physical_address_not_relative_to_config_info
|
|
|
|
stwx r21, r18, r22 ; save in the KDP pagemap
|
|
|
|
subic. r22, r22, 4
|
|
lwzx r20, r9, r22 ; load another word, but no be cray
|
|
stwx r20, r18, r22 ; just save it in KDP
|
|
bgt @copyloop_pagemap
|
|
@skip_copying_pagemap
|
|
|
|
|
|
|
|
; Edit the KDP's copied PageMap to contain the correct physical address
|
|
; of the parts that we know about: IRP, KDP & surrounds, EDP.
|
|
; (No changes to flags)
|
|
|
|
; IRP
|
|
|
|
lwz r8, NKConfigurationInfo.PageMapIRPOffset(r26)
|
|
add r8, r18, r8
|
|
|
|
lisori r19, IRPOffset
|
|
add r19, r19, r1
|
|
|
|
; Set physical address (top 20 bits of second word)
|
|
lwz r23, PMDT.PBaseAndFlags(r8)
|
|
rlwimi r23, r19, 0, 0, 19
|
|
stw r23, PMDT.PBaseAndFlags(r8)
|
|
|
|
|
|
; KDP (plus the nine pages below it)
|
|
|
|
IRPTopOffset equ IRPOffset + 0x1000
|
|
|
|
lwz r8, NKConfigurationInfo.PageMapKDPOffset(r26)
|
|
add r8, r18, r8
|
|
|
|
lisori r19, IRPTopOffset
|
|
add r19, r1, r19
|
|
|
|
; Page count - 1
|
|
lisori r22, (-IRPTopOffset) >> 12
|
|
|
|
; Set physical address (top 20 bits of second word)
|
|
lwz r23, PMDT.PBaseAndFlags(r8)
|
|
rlwimi r23, r19, 0, 0, 19
|
|
stw r23, PMDT.PBaseAndFlags(r8)
|
|
|
|
; Set page count - 1 (bottom half of first word)
|
|
sth r22, PMDT.PageCount(r8)
|
|
|
|
; Whaaaaaa?
|
|
lhz r23, PMDT.LBase(r8)
|
|
subf r23, r22, r23
|
|
sth r23, PMDT.LBase(r8)
|
|
|
|
|
|
; EDP
|
|
|
|
lwz r19, KDP.PA_EmulatorData(r1)
|
|
lwz r8, NKConfigurationInfo.PageMapEDPOffset(r26)
|
|
add r8, r18, r8
|
|
|
|
lwz r23, PMDT.PBaseAndFlags(r8)
|
|
rlwimi r23, r19, 0, 0, 19
|
|
stw r23, PMDT.PBaseAndFlags(r8)
|
|
|
|
|
|
|
|
; Copy segment maps from ConfigInfo
|
|
; (128 bytes per mode: supervisor, user, CPU, overlay)
|
|
; even-indexed words are offsets into the pagemap
|
|
; odd-indexed words are or-ed with 0x20000000
|
|
|
|
addi r9, r26, NKConfigurationInfo.SegMaps - 4
|
|
addi r8, r1, KDP.SegMaps - 4
|
|
li r22, 128 * 4
|
|
|
|
@copyloop_segmaps
|
|
lwzu r23, 4(r9)
|
|
subic. r22, r22, 8
|
|
add r23, r18, r23 ; even-indexed words are PMDT offsets in PageMap
|
|
stwu r23, 4(r8)
|
|
|
|
lwzu r23, 4(r9)
|
|
oris r23, r23, 0x2000 ; no clue?
|
|
stwu r23, 4(r8)
|
|
|
|
bgt @copyloop_segmaps
|
|
|
|
|
|
|
|
; Give KDP pointers to its own structures (how lame).
|
|
|
|
addi r23, r1, KDP.SegMap32SupInit
|
|
stw r23, KDP.SegMap32SupInitPtr(r1)
|
|
|
|
lwz r23, NKConfigurationInfo.BatMap32SupInit(r26)
|
|
stw r23, KDP.BatMap32SupInit(r1)
|
|
|
|
|
|
addi r23, r1, KDP.SegMap32UsrInit
|
|
stw r23, KDP.SegMap32UsrInitPtr(r1)
|
|
|
|
lwz r23, NKConfigurationInfo.BatMap32UsrInit(r26)
|
|
stw r23, KDP.BatMap32UsrInit(r1)
|
|
|
|
|
|
addi r23, r1, KDP.SegMap32CPUInit
|
|
stw r23, KDP.SegMap32CPUInitPtr(r1)
|
|
|
|
lwz r23, NKConfigurationInfo.BatMap32CPUInit(r26)
|
|
stw r23, KDP.BatMap32CPUInit(r1)
|
|
|
|
|
|
addi r23, r1, KDP.SegMap32OvlInit
|
|
stw r23, KDP.SegMap32OvlInitPtr(r1)
|
|
|
|
lwz r23, NKConfigurationInfo.BatMap32OvlInit(r26)
|
|
stw r23, KDP.BatMap32OvlInit(r1)
|
|
|
|
|
|
|
|
; Use the PageMap kindly provided by the Trampoline to count VMMaxVirtualPages
|
|
; (remembering that virtual is meant in the '68k VM' sense).
|
|
|
|
; In brief: only big fat PMDTs on 256MB (i.e. segment) boundaries need apply.
|
|
|
|
; INDEPENDENT OF INSTALLED RAM!
|
|
|
|
li r22, 0 ; counter
|
|
addi r19, r1, KDP.SegMaps - 8
|
|
b @next_segment
|
|
|
|
@skip_pmdt
|
|
addi r8, r8, 0x08
|
|
b @searchloop
|
|
|
|
@next_segment
|
|
lwzu r8, 8(r19)
|
|
|
|
@searchloop
|
|
; Get both words of the pointed-to PMDT
|
|
lwz r30, 0(r8) ; OffsetWithinSegInPages(16b) || PageCount-1(16b)
|
|
lwz r31, 4(r8) ; PhysicalInPages(20b) || pageAttr(12b)
|
|
|
|
; Stop counting if we meet a PMDT not at the base of its segment.
|
|
|
|
; Stop counting if we meet a PMDT with its top two pageAttr bits both unset.
|
|
|
|
; If PMDT has its top two pageAttr bits both set,
|
|
; check the PMDT following it in the PageMap.
|
|
; (Never seen this in the wild.)
|
|
|
|
cmplwi cr7, r30, 0xffff ; if not at base:
|
|
rlwinm. r31, r31, 0, PMDT.DaddyFlag | PMDT.CountingFlag ; if neither flag:
|
|
bgt cr7, @finish_count ; stop counting
|
|
cmpwi cr6, r31, PMDT.DaddyFlag | PMDT.CountingFlag ; if both flags:
|
|
beq @finish_count ; stop counting
|
|
beq cr6, @skip_pmdt ; next PMDT instead
|
|
|
|
add r22, r22, r30
|
|
addi r22, r22, 1
|
|
beq cr7, @next_segment ; else count and move on to next segment descriptor
|
|
|
|
@finish_count
|
|
stw r22, KDP.VMMaxVirtualPages(r1)
|
|
|
|
|
|
|
|
; Create the Flat Page List:
|
|
; a draft PTE for every usable physical page.
|
|
|
|
; Usable physical pages are:
|
|
; Inside a RAM bank, and
|
|
; NOT inside the kernel's reserved physical memory
|
|
|
|
; By 'draft PTE', I mean these parts of the second word of a PTE:
|
|
; physical page number (base & 0xfffff000)
|
|
; WIMG bits (from oddly formatted ConfigInfo.PageAttributeInit)
|
|
; bottom PP bit always set
|
|
|
|
; And all this goes at the bottom of the kernel reserved area.
|
|
; Leave ptr to kernel reserved area in r21
|
|
; Leave ptr to topmost entry in r29.
|
|
|
|
ListFreePhysicalPages
|
|
|
|
beq cr5, @skip
|
|
|
|
lwz r21, KDP.KernelMemoryBase(r1)
|
|
lwz r20, KDP.KernelMemoryEnd(r1)
|
|
|
|
stw r21, KDP.FlatPageListPtr(r1)
|
|
|
|
lwz r30, EWA.PA_IRP(r1)
|
|
|
|
; Will be writing things to the very base of kernel memory. Oh dear.
|
|
subi r29, r21, 4
|
|
|
|
addi r19, r30, IRP.SystemInfo + NKSystemInfo.Bank0Start - 8
|
|
|
|
lwz r23, KDP.PageAttributeInit(r1) ; default WIMG/PP settings in PTEs
|
|
|
|
; Pull WIMG bits out of PageAttributeInit
|
|
li r30, 1
|
|
rlwimi r30, r23, 1, 25, 25
|
|
rlwimi r30, r23, 31, 26, 26
|
|
xori r30, r30, 0x20
|
|
rlwimi r30, r23, 29, 27, 27
|
|
rlwimi r30, r23, 27, 28, 28
|
|
|
|
li r23, NKSystemInfo.MaxBanks
|
|
|
|
@nextbank
|
|
subic. r23, r23, 1
|
|
blt @done
|
|
|
|
lwzu r31, 8(r19) ; bank start address
|
|
lwz r22, 4(r19) ; bank size
|
|
or r31, r31, r30 ; looks a lot like the second word of a PTE
|
|
|
|
@nextpage
|
|
cmplwi r22, 4096
|
|
cmplw cr6, r31, r21
|
|
cmplw cr7, r31, r20
|
|
subi r22, r22, 4096
|
|
blt @nextbank
|
|
|
|
; Check that this page is outside the kernel's reserved area
|
|
blt cr6, @below_reserved
|
|
blt cr7, @in_reserved
|
|
@below_reserved
|
|
stwu r31, 4(r29) ; write that part-PTE at the base of kernel memory
|
|
@in_reserved
|
|
|
|
addi r31, r31, 4096
|
|
b @nextpage
|
|
|
|
@done
|
|
@skip
|
|
|
|
|
|
|
|
PrimeFreeListFromBanks
|
|
|
|
beq cr5, PrimeFreeListFromSystemHeap
|
|
|
|
; Add ~18 to 20 of these pages to the free list, depending on RAM size
|
|
subf r22, r21, r29
|
|
addi r8, r22, 4096
|
|
srwi r17, r22, 13
|
|
addi r17, r17, 18
|
|
|
|
_log 'Priming the system free list with '
|
|
|
|
mr r8, r17
|
|
bl Printd
|
|
|
|
_log 'pages.^n'
|
|
|
|
@loop
|
|
lwz r8, 0(r29)
|
|
rlwinm r8, r8, 0, 0, 19 ; physical base of page
|
|
bl free_list_add_page
|
|
|
|
subi r17, r17, 1
|
|
subi r29, r29, 4
|
|
cmpwi r17, 0
|
|
bgt @loop
|
|
|
|
b DonePrimingFreeList
|
|
|
|
|
|
|
|
; Apparently the replacement kernel can find pages just above the EDP?
|
|
|
|
; More power to it, I say.
|
|
|
|
PrimeFreeListFromSystemHeap
|
|
|
|
lwz r8, 0x05a8(r1) ; kdp.0x5a8
|
|
addi r18, r1, 0x2000 ; kdp.0x2000
|
|
subf. r8, r18, r8
|
|
blt DonePrimingFreeList
|
|
addi r8, r8, 0x1000
|
|
srwi r17, r8, 12
|
|
|
|
_log 'Priming the system free list with '
|
|
|
|
mr r8, r17
|
|
bl Printd
|
|
|
|
_log 'system heap pages.^n'
|
|
|
|
|
|
@stupidloop
|
|
rlwinm r8, r18, 0, 0, 19
|
|
|
|
bl free_list_add_page
|
|
addi r17, r17, -0x01
|
|
addi r18, r18, 0x1000
|
|
cmpwi r17, 0x00
|
|
bgt @stupidloop
|
|
|
|
|
|
|
|
|
|
DonePrimingFreeList
|
|
|
|
|
|
|
|
; Bang on a little bit
|
|
|
|
|
|
_log 'VMMaxVirtualPages: ' ; 0005fffe
|
|
|
|
lwz r8, KDP.VMMaxVirtualPages(r1)
|
|
mr r8, r8
|
|
bl Printw
|
|
|
|
_log 'VMLogicalPages: '
|
|
|
|
lwz r8, 0x06a8(r1) ; kdp.phys_pages
|
|
mr r8, r8
|
|
bl Printw
|
|
|
|
_log '^n'
|
|
|
|
_log 'Interrupt handler kind: '
|
|
|
|
lwz r8, KDP.PA_ConfigInfo(r1) ; kdp.pa_ConfigInfo
|
|
lbz r8, NKConfigurationInfo.InterruptHandlerKind(r8)
|
|
mr r8, r8
|
|
bl Printb
|
|
|
|
_log '^n'
|
|
|
|
|
|
|
|
; Now the code paths diverge again.
|
|
;
|
|
; The builtin kernel needs to start the 68k virtual machine.
|
|
;
|
|
; The replacement kernel needs to return to the Mac OS
|
|
; boot process.
|
|
|
|
beq cr5, finish_old_world
|
|
|
|
|
|
|
|
; Here we reconcile the actual physical memory with the
|
|
; size of the contiguous part of the MacOS address space.
|
|
|
|
; Going in:
|
|
; r21 points to base of long array
|
|
; r29 points (empty ascending) to top of long array
|
|
|
|
; Pops have been made to prime the system free list,
|
|
; but otherwise, this contains all the physical memory
|
|
; that the Trampoline reported in the banks (Tramp already
|
|
; subtracted ROM and structures), minus the kernel data.
|
|
|
|
ReconcileMemory
|
|
|
|
; r22 = pages still in array * 4
|
|
subf r22, r21, r29
|
|
|
|
; r8 = theoretical maximum MacOS page count * 4
|
|
lwz r8, KDP.VMMaxVirtualPages(r1)
|
|
slwi r8, r8, 2
|
|
|
|
; Memory We Have versus Memory We Could Use
|
|
; (see blt below)
|
|
cmplw r22, r8
|
|
|
|
; TotalPhysicalPages equals pages not yet in free list but that could go in.
|
|
; (Therefore exludes Trampoline areas, kernel areas, free list prime)
|
|
addi r19, r22, 4
|
|
srwi r19, r19, 2
|
|
stw r19, KDP.TotalPhysicalPages(r1)
|
|
|
|
; r22 = pages in array destined to be mapped to blue area
|
|
blt @less_than_VMMaxVirtualPages
|
|
subi r22, r8, 4
|
|
@less_than_VMMaxVirtualPages
|
|
|
|
li r30, 0
|
|
|
|
lwz r8, EWA.PA_IRP(r1)
|
|
|
|
; That sets UsableMemorySize = LogicalMemorySize (= size of blue area),
|
|
addi r19, r22, 4
|
|
slwi r19, r19, 10
|
|
ori r30, r30, 0xffff
|
|
stw r19, IRP.SystemInfo + NKSystemInfo.UsableMemorySize(r8)
|
|
srwi r22, r22, 2
|
|
stw r19, IRP.SystemInfo + NKSystemInfo.LogicalMemorySize(r8)
|
|
; Now r22 is a page count
|
|
|
|
; The above, divided by 4096
|
|
srwi r19, r19, 12
|
|
stw r19, KDP.PrimaryAddrRangePages(r1)
|
|
|
|
addi r29, r1, KDP.FlatPageListSegPtrs - 4
|
|
addi r19, r1, KDP.SegMaps - 8
|
|
|
|
|
|
|
|
; Divvy up the FlatPageList into segments
|
|
@persegment
|
|
; r21 = fully ascending pointer (starts at base)
|
|
; r
|
|
|
|
cmplwi r22, 0xffff ; pages in a segment
|
|
lwzu r8, 8(r19) ; get the first word of a SegMap entry
|
|
|
|
rotlwi r31, r21, 10
|
|
ori r31, r31, 0xc00 ; r31 = second byte with fake-ass physical backing
|
|
|
|
; Rewrite the pagemap entry
|
|
stw r30, 0(r8) ; Whole segment
|
|
stw r31, 4(r8) ; Based on the FlatPageList, with weird shifts!
|
|
|
|
stwu r21, 0x0004(r29)
|
|
addis r21, r21, 4 ; we just used a segment's worth of pages on this
|
|
subis r22, r22, 1 ; pages in a segment
|
|
bgt @persegment
|
|
|
|
; Number of pages in that last segment
|
|
sth r22, 0x0002(r8)
|
|
|
|
lwz r17, KDP.PrimaryAddrRangePages(r1)
|
|
lwz r18, KDP.TotalPhysicalPages(r1)
|
|
stw r17, KDP.TotalPhysicalPages(r1)
|
|
|
|
; Get the number of 'unusable' physical pages (not [yet] wanted by main MacOS area)
|
|
; If any, they will be chucked on the free list
|
|
subf. r18, r17, r18
|
|
slwi r31, r17, 12 ; does this work with discontiguous banks? hmm...
|
|
ble @no_leftover_ram
|
|
|
|
; See?
|
|
_log 'Physical RAM greater than the initial logical area.^n Moving '
|
|
|
|
mr r8, r18
|
|
bl Printd
|
|
|
|
_log 'pages into the system free page list.^n'
|
|
|
|
|
|
@loop
|
|
mr r8, r31
|
|
bl free_list_add_page
|
|
addi r31, r31, 4096
|
|
subi r18, r18, 1
|
|
cmpwi r18, 0
|
|
bgt @loop
|
|
|
|
@no_leftover_ram
|
|
|
|
|
|
|
|
; Create Areas (an abstract NKv2 structure) from the Trampoline's PageMap
|
|
|
|
bl convert_pmdts_to_areas
|
|
|
|
|
|
|
|
; No understandy
|
|
|
|
addi r29, r1, 0x5e0 ; kdp.0x5e0
|
|
bl PagingFunc2
|
|
bl PagingFlushTLB
|
|
|
|
|
|
|
|
; Makes QEMU complain
|
|
|
|
bl ProbePerfMonitor
|
|
|
|
|
|
|
|
; Done all we can
|
|
|
|
_log 'Reset system - Into the 68K fire: '
|
|
|
|
mr r8, r11
|
|
bl Printw
|
|
mr r8, r10
|
|
bl Printw
|
|
|
|
_log '^n'
|
|
|
|
lwz r9, ContextBlock.XER(r6)
|
|
mfsprg r8, 0
|
|
mtxer r9
|
|
|
|
bl SchRestoreStartingAtR14
|
|
|
|
b kcPrioritizeInterrupts
|
|
|
|
|
|
|
|
finish_old_world
|
|
addi r29, r1, 0x5e8
|
|
bl PagingFunc2
|
|
bl PagingFlushTLB
|
|
bl convert_pmdts_to_areas
|
|
bl ProbePerfMonitor
|
|
lwz r27, 0x0630(r1)
|
|
lwz r27, 0x0094(r27)
|
|
bl PagingL2PWithoutBATs
|
|
beq setup_0x1160
|
|
li r30, 0x00
|
|
stw r30, -0x0004(r29)
|
|
eieio
|
|
stw r30, 0x0000(r29)
|
|
sync
|
|
|
|
setup_0x1160
|
|
bl PagingFunc1
|
|
lwz r27, 0x0630(r1)
|
|
lwz r27, 0x009c(r27)
|
|
bl PagingL2PWithoutBATs
|
|
beq setup_0x1188
|
|
li r30, 0x00
|
|
stw r30, -0x0004(r29)
|
|
eieio
|
|
stw r30, 0x0000(r29)
|
|
sync
|
|
|
|
setup_0x1188
|
|
bl PagingFunc1
|
|
lwz r27, 0x0630(r1)
|
|
lwz r27, 0x00a0(r27)
|
|
lis r19, 0x00
|
|
ori r19, r19, 0xa000
|
|
subf r19, r19, r27
|
|
|
|
setup_0x11a0
|
|
bl PagingL2PWithoutBATs
|
|
beq setup_0x11bc
|
|
li r30, 0x00
|
|
stw r30, -0x0004(r29)
|
|
eieio
|
|
stw r30, 0x0000(r29)
|
|
sync
|
|
|
|
setup_0x11bc
|
|
bl PagingFunc1
|
|
cmplw r27, r19
|
|
addi r27, r27, -0x1000
|
|
bgt setup_0x11a0
|
|
lwz r27, 0x0630(r1)
|
|
lwz r27, 0x00a4(r27)
|
|
bl PagingL2PWithoutBATs
|
|
beq setup_0x11f0
|
|
li r30, 0x00
|
|
stw r30, -0x0004(r29)
|
|
eieio
|
|
stw r30, 0x0000(r29)
|
|
sync
|
|
|
|
setup_0x11f0
|
|
bl PagingFunc1
|
|
|
|
_log 'Nanokernel replaced. Returning to boot process^n'
|
|
|
|
addi r9, r1, KDP.OrangeVecBase
|
|
mtsprg 3, r9
|
|
|
|
; r1 = kdp
|
|
b old_world_rfi_to_userspace_boot
|
|
|
|
|
|
|
|
; Called by InitReplacement.s if we accidentally try
|
|
; to replace a v2 kernel (like ourself).
|
|
;
|
|
; All we need to do is restore
|
|
; sprg0 (ewa/kdp) and sprg3 (vecBase).
|
|
|
|
CancelReplacement
|
|
|
|
bl InitScreenConsole
|
|
|
|
_log 'Nanokernel NOT replaced. Returning to boot process^n'
|
|
|
|
lwz r8, KDP.OldKDP(r1)
|
|
mtsprg 0, r8
|
|
|
|
addi r9, r8, KDP.OrangeVecBase
|
|
mtsprg 3, r9
|
|
|
|
|
|
|
|
; old_world_rfi_to_userspace_boot
|
|
|
|
; > r1 = kdp
|
|
|
|
old_world_rfi_to_userspace_boot ; OUTSIDE REFERER
|
|
lwz r4, KDP.LA_EmulatorKernelTrapTable(r1)
|
|
lwz r8, KDP.OtherFreeThing(r1)
|
|
lwz r9, PSA.UserModeMSR(r1)
|
|
addi r8, r8, ReturnCode - NKTop
|
|
mtsrr0 r8
|
|
mtsrr1 r9
|
|
rfi
|
|
|
|
|
|
ReturnCode
|
|
li r3, 255
|
|
mtlr r4
|
|
blrl
|
|
|
|
|
|
|
|
; ARG Lock *r8
|
|
|
|
align 5
|
|
|
|
AcquireLock ; OUTSIDE REFERER
|
|
lwarx r9, 0, r8
|
|
cmpwi r9, 0
|
|
mfsprg r9, 0
|
|
bne- @already_held
|
|
lwz r9, -0x0340(r9)
|
|
sync
|
|
stwcx. r9, 0, r8
|
|
bne- AcquireLock
|
|
mflr r9
|
|
stw r9, 0x0010(r8)
|
|
isync
|
|
blr
|
|
|
|
@already_held
|
|
stmw r22, -0x0094(r9)
|
|
mr r22, r9
|
|
mflr r30
|
|
mr r31, r8
|
|
lwz r29, -0x0340(r22)
|
|
lwz r28, 0x0000(r31)
|
|
stw r30, -0x0098(r22)
|
|
cmpw r28, r29
|
|
bne+ @0x84
|
|
bl @start_logging
|
|
_log 'Recursive spinlock ***^n'
|
|
bl Init_Panic
|
|
|
|
@0x84
|
|
bl @0x184
|
|
mr r24, r28
|
|
mr r25, r29
|
|
lwz r30, -0x0004(r22)
|
|
mfdec r29
|
|
lwz r28, -0x0438(r30)
|
|
slwi r28, r28, 3
|
|
subf r29, r28, r29
|
|
b @0xc0
|
|
|
|
@0xa8
|
|
lwz r30, -0x0004(r22)
|
|
lwz r28, -0x0b30(r30)
|
|
cmpwi r28, 0x00
|
|
beq- @0xc0
|
|
mfdec r29
|
|
addis r29, r29, -0x01
|
|
|
|
@0xc0
|
|
mfdec r28
|
|
subf. r28, r29, r28
|
|
bgt- @0x118
|
|
bl @start_logging
|
|
_log 'Timeout - locked CpuID '
|
|
mr r8, r30
|
|
bl printw
|
|
_log '***^n'
|
|
bl Init_Panic
|
|
|
|
@0x118
|
|
lwz r30, 0x0000(r31)
|
|
cmpwi r30, 0x00
|
|
bne+ @0xa8
|
|
|
|
@0x124
|
|
lwarx r30, 0, r31
|
|
cmpwi r30, 0
|
|
bne+ @0xa8
|
|
lwz r30, EWA.CPUBase + CPU.ID(r22)
|
|
sync
|
|
stwcx. r30, 0, r31
|
|
bne- @0x124
|
|
mfxer r30
|
|
bl @0x184
|
|
lwz r27, -0x0098(r22)
|
|
subfc r29, r25, r29
|
|
lwz r25, 0x000c(r31)
|
|
subfe r28, r24, r28
|
|
lwz r24, 0x0008(r31)
|
|
addc r25, r25, r29
|
|
adde r24, r24, r28
|
|
stw r25, 0x000c(r31)
|
|
stw r24, 0x0008(r31)
|
|
mtlr r27
|
|
stw r27, 0x0010(r31)
|
|
mtxer r30
|
|
mr r8, r22
|
|
lmw r22, -0x0094(r8)
|
|
blr
|
|
|
|
@0x184
|
|
mftbu r28
|
|
mftb r29
|
|
mftbu r27
|
|
cmpw r28, r27
|
|
beqlr+
|
|
b @0x184
|
|
|
|
@start_logging ; actually a func
|
|
mfsprg r28, 0
|
|
mflr r27
|
|
|
|
lwz r29, EWA.CPUBase + CPU.ID(r28)
|
|
_log '^n*** On CPU '
|
|
mr r8, r29
|
|
bl printw
|
|
|
|
_log 'spinlock 0x'
|
|
|
|
mr r8, r31
|
|
bl printw
|
|
|
|
; Print lock sig
|
|
lwz r8, Lock.Signature(r31)
|
|
rotlwi r8, r8, 8
|
|
bl printc
|
|
rotlwi r8, r8, 8
|
|
bl printc
|
|
rotlwi r8, r8, 8
|
|
bl printc
|
|
rotlwi r8, r8, 8
|
|
bl printc
|
|
|
|
lwz r29, -0x0098(r28)
|
|
_log ' caller 0x'
|
|
mr r8, r29
|
|
bl printw
|
|
|
|
mtlr r27
|
|
blr
|
|
|
|
|
|
|
|
Init_Panic
|
|
b panic
|