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