1 // 2 // Copyright (c) 2010-2025 Antmicro 3 // 4 // This file is licensed under the MIT License. 5 // Full license text is available in 'licenses/MIT.txt'. 6 // 7 using System; 8 using System.Linq; 9 using System.Collections.Generic; 10 11 using Antmicro.Renode.Core; 12 using Antmicro.Renode.Exceptions; 13 using Antmicro.Renode.Hooks; 14 using Antmicro.Renode.Logging; 15 using Antmicro.Renode.Utilities.Binding; 16 17 using Endianess = ELFSharp.ELF.Endianess; 18 19 namespace Antmicro.Renode.Peripherals.CPU 20 { 21 public abstract class BaseARMv8 : TranslationCPU, ICPUWithPSCI 22 { BaseARMv8(uint cpuId, string cpuType, IMachine machine, Endianess endianness = Endianess.LittleEndian)23 public BaseARMv8(uint cpuId, string cpuType, IMachine machine, Endianess endianness = Endianess.LittleEndian) : base(cpuId, cpuType, machine, endianness, CpuBitness.Bits64) 24 { 25 this.customFunctionHandlers = new Dictionary<ulong, Action>(); 26 } 27 28 public bool StubPSCICalls 29 { 30 get 31 { 32 return stubPSCICalls; 33 } 34 set 35 { 36 stubPSCICalls = value; 37 TlibStubSmcCalls(stubPSCICalls ? 1u : 0); 38 } 39 } 40 AddCustomPSCIStub(ulong functionIdentifier, Action stub)41 public void AddCustomPSCIStub(ulong functionIdentifier, Action stub) 42 { 43 try 44 { 45 customFunctionHandlers.Add(functionIdentifier, stub); 46 } 47 catch(ArgumentException) 48 { 49 throw new RecoverableException(string.Format("There's already a handler for a function: 0x{0:X}", functionIdentifier)); 50 } 51 this.Log(LogLevel.Debug, "Adding a handler for function: 0x{0:X}", functionIdentifier); 52 } 53 54 [Export] HandleSMCCall()55 private void HandleSMCCall() 56 { 57 var x0 = (uint)GetRegister((int)ARMv8ARegisters.X0); 58 var x1 = (ulong)GetRegister((int)ARMv8ARegisters.X1); 59 60 if(customFunctionHandlers.TryGetValue(x0, out var handler)) 61 { 62 handler(); 63 return; 64 } 65 66 switch((Function)x0) 67 { 68 case Function.PSCIVersion: 69 GetPSCIVersion(); 70 break; 71 case Function.CPUOn: 72 UnhaltCpu((uint)x1); 73 break; 74 default: 75 this.Log(LogLevel.Error, "Encountered an unexpected PSCI call request: 0x{0:X}", x0); 76 SetRegister((int)ARMv8ARegisters.X0, PSCICallResultNotSupported); 77 return; 78 } 79 80 // Set return code to success 81 SetRegister((int)ARMv8ARegisters.X0, PSCICallResultSuccess); 82 } 83 GetPSCIVersion()84 private void GetPSCIVersion() 85 { 86 SetRegister((int)ARMv8ARegisters.X1, PSCIVersion); 87 } 88 UnhaltCpu(uint cpuId)89 private void UnhaltCpu(uint cpuId) 90 { 91 var cpu = machine.SystemBus.GetCPUs().Where(x => x.MultiprocessingId == cpuId).Single(); 92 cpu.IsHalted = false; 93 } 94 95 private bool stubPSCICalls; 96 private readonly Dictionary<ulong, Action> customFunctionHandlers; 97 private const int PSCICallResultSuccess = 0; 98 private const int PSCICallResultNotSupported = -1; 99 private const int PSCIVersion = 2; 100 101 protected enum GICCPUInterfaceVersion : uint 102 { 103 None = 0b000, 104 Version30Or40 = 0b001, 105 Version41 = 0b011, 106 } 107 108 // Currently we support only a subset of available functions and return codes. 109 // Full list can be found here: https://github.com/zephyrproject-rtos/zephyr/blob/main/drivers/pm_cpu_ops/pm_cpu_ops_psci.h 110 private enum Function : uint 111 { 112 PSCIVersion = 0x84000000, 113 CPUOn = 0xC4000003, 114 } 115 116 #pragma warning disable 649 117 [Import] 118 private Action<uint> TlibStubSmcCalls; 119 #pragma warning restore 649 120 } 121 } 122