;_______________________________________________________________________ ; 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 for the NanoKernel. Execution always starts here, ; regardless of how the NK was put in control. The immediate purpose of this ; code is to figure out if it was called by the Trampoline bootloader for ; NewWorld Macs or the 'boot' 3 resource on OldWorld Macs. The code path ; diverges dramatically for the 2 cases, so it is important to figure out which ; is which. ; If data paging is off, we recieved control from the Trampoline and we are the ; built in NanoKernel. The register assignments are as follows: ; r3 = ConfigInfo ; r4 = ProcessorInfo ; r5 = SystemInfo ; r6 = DiagInfo ; r7 = RTAS_flag ('RTAS' or 0) ; r8 = RTAS_proc ; r9 = HWInfo ; r23= SCC (Serial Communications Controller) base address ; ; If data paging is on, we recieved control from the 'boot' 3 resource and we ; are replacing another NanoKernel. The register assignments are as follows: ; LR = return address? ; sprg0 = old KDP/EWA/r1 ptr ; r3 = PA_NanoKernelCode (the physical address of this code) ; r4 = physical base of our global area ; r5 = SCC base address (will be saved to NoIdeaR23) ; r6 = PA_EDP or zero? ; r7 = ROMHeader.ROMRelease (e.g. 0x10B5 is 1.0ß5) ; AUTO-GENERATED SYMBOL LIST ; IMPORTS: ; NKAddressSpaces ; CreateAreasFromPageMap ; FreePageListPush ; InitFreePageList ; NKCreateAddressSpaceSub ; NKBuiltinInit ; InitBuiltin ; NKCache ; kcCacheDispatch ; NKConsoleLog ; printb ; printc ; printd ; printw ; NKIndex ; InitIDIndex ; MakeID ; NKInterrupts ; HandlePerfMonitorInt ; IgnoreSoftwareInt ; IntAlignment ; IntDSI ; IntDecrementer ; IntExternalAlternate ; IntExternalSystem ; IntFPUnavail ; IntISI ; IntMachineCheck ; IntPerfMonitor ; IntProgram ; IntSyscall ; IntThermalEvent ; IntTrace ; MemRetryDSI ; MemRetryMachineCheck ; PIHDSI ; kcPrioritizeInterrupts ; kcResetSystem ; kcReturnFromException ; kcRunAlternateContext ; kcThud ; major_0x046d0 ; major_0x04a20 ; wordfill ; NKMPCalls ; kcMPDispatch ; NKPaging ; PagingFlushTLB ; PagingFunc1 ; PagingFunc2 ; PagingL2PWithoutBATs ; NKPoolAllocator ; InitPool ; PoolAllocClear ; NKPowerCalls ; InitIdleVecTable ; kcPowerDispatch ; NKProcFlagsTbl ; ProcessorFlagsTable ; NKRTASCalls ; kcRTASDispatch ; NKReplacementInit ; InitReplacement ; NKScheduler ; CalculateTimeslice ; FlagSchEval ; SchIdleTask ; SchInit ; SchRdyTaskNow ; SchRestoreStartingAtR14 ; SchSwitchSpace ; NKScreenConsole ; InitScreenConsole ; NKTasks ; CreateTask ; NKThud ; panic ; NKTimers ; InitTMRQs ; StartTimeslicing ; NKTranslation ; FDP_1c40 ; ProbePerfMonitor ; NKVMCalls ; kcVMDispatch ; EXPORTS: ; CancelReplacement (=> NKReplacementInit) ; FinishInitBuiltin (=> NKBuiltinInit) ; InitHighLevel (=> NKReplacementInit) ; InitIRP (=> NKBuiltinInit, NKReplacementInit) ; ResetBuiltinKernel (=> NKInterrupts) ; 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 ; Figure out how we got control ; 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, we are the replacement NanoKernel. ; We need to turn off paging and jump to the replacement init code. ; Does LR contain a return address, or my address, or...? mflr r9 subi r9, r9, 28 ; Find the physical address of the replacement init code addi r12, r3, InitReplacement - NKTop; offset ; 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 ; We will now be at InitReplacement with paging off rfi ; 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.VecBaseSystem + VecTable.ProgramIntVector(r1) llabel r8, HandlePerfMonitorInt add r8, r8, r9 stw r8, KDP.VecBaseSystem + VecTable.PerfMonitorVector(r1) addi r8, r1, KDP.VecBaseSystem 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 the old-style KDP vector tables, and also two new PSA ones, ; with panics llabel r23, panic add r23, r23, r25 addi r8, r1, KDP.VecBaseSystem li r22, VecTable.Size bl wordfill addi r8, r1, KDP.VecBaseAlternate li r22, VecTable.Size bl wordfill addi r8, r1, KDP.VecBaseMemRetry li r22, VecTable.Size bl wordfill addi r8, r1, PSA.VioletVecBase li r22, VecTable.Size bl wordfill addi r8, r1, PSA.VecBasePIH li r22, VecTable.Size bl wordfill ; Fill Green (PSA) with IgnoreSoftwareInt llabel r23, IgnoreSoftwareInt add r23, r23, r25 addi r8, r1, PSA.VecBaseScreenConsole li r22, VecTable.Size bl wordfill ; Populate System and Alternate Context vector tables. ; Activate System Context vector table (will enter 68k emu soon). addi r9, r1, KDP.VecBaseSystem mtsprg 3, r9 addi r8, r1, KDP.VecBaseAlternate 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) ; Here is the difference between the System and Alternate ; vector tables llabel r23, IntExternalSystem add r23, r23, r25 stw r23, VecTable.ExternalIntVector(r9) llabel r23, IntExternalAlternate add r23, r23, r25 stw r23, VecTable.ExternalIntVector(r8) 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 the Translation vector table addi r8, r1, KDP.VecBaseMemRetry llabel r23, panic add r23, r23, r25 stw r23, VecTable.SystemResetVector(r8) llabel r23, MemRetryMachineCheck add r23, r23, r25 stw r23, VecTable.MachineCheckVector(r8) llabel r23, MemRetryDSI 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.VecBasePIH 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, PIHDSI 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 InitFreePageList) ; - 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 InitFreePageList ; 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.kFlagNotDebuggable) | (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.kFlagNotDebuggable) | (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 FreePageListPush ; PhysicalPage *r8 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 FreePageListPush ; PhysicalPage *r8 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, KDP.VMLogicalPages(r1) 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.VMLogicalPages(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.VMLogicalPages(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 FreePageListPush ; PhysicalPage *r8 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 CreateAreasFromPageMap ; 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 CreateAreasFromPageMap 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.VecBaseAlternate 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.VecBaseAlternate 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, PSA.DecClockRateHzCopy(r30) slwi r28, r28, 3 subf r29, r28, r29 b @0xc0 @0xa8 lwz r30, -0x0004(r22) lwz r28, PSA.ThudLock(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