powermac-rom/NanoKernel/NKInit.s
2018-04-15 17:00:11 +08:00

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