1 //
2 // Copyright (c) 2010-2024 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.Collections.Generic;
9 using System.Linq;
10 using Antmicro.Renode.Utilities;
11 
12 namespace Antmicro.Renode.Peripherals.CPU
13 {
14     public interface IARMSingleSecurityStateCPU : ICPU
15     {
16         ExceptionLevel ExceptionLevel { get; }
17 
18         Affinity Affinity { get; }
19         // This kind of CPU is always in a specific Security State and it can't be changed
20         SecurityState SecurityState { get; }
21 
22         bool FIQMaskOverride { get; }
23         bool IRQMaskOverride { get; }
24     }
25 
26     public interface IARMTwoSecurityStatesCPU : IARMSingleSecurityStateCPU
27     {
GetAtomicExceptionLevelAndSecurityState(out ExceptionLevel exceptionLevel, out SecurityState securityState)28         void GetAtomicExceptionLevelAndSecurityState(out ExceptionLevel exceptionLevel, out SecurityState securityState);
29 
30         // This property should return false if CPU doesn't support EL3
31         bool IsEL3UsingAArch32State { get; }
32 
33         // The CPU may support two security states, but be in configuration that allows only one
34         bool HasSingleSecurityState { get; }
35 
36         event Action<ExceptionLevel, SecurityState> ExecutionModeChanged;
37     }
38 
39     public interface IARMCPUsConnectionsProvider
40     {
AttachCPU(IARMSingleSecurityStateCPU cpu)41         void AttachCPU(IARMSingleSecurityStateCPU cpu);
42         // AttachedCPUs and CPUAttached provide information for GPIO handling purposes.
43         // Depending on the declaration order in repl file, some CPUs can be attached before or after peripheral's creation.
44         IEnumerable<IARMSingleSecurityStateCPU> AttachedCPUs { get; }
45         event Action<IARMSingleSecurityStateCPU> CPUAttached;
46     }
47 
48     public enum ExceptionLevel : uint
49     {
50         EL0_UserMode = 0,
51         EL1_SystemMode = 1,
52         EL2_HypervisorMode = 2,
53         EL3_MonitorMode = 3
54     }
55 
56     public enum ExecutionState
57     {
58         AArch32,
59         AArch64
60     }
61 
62     // GIC should use GPIO#0 of an ARM CPU to signal IRQ and GPIO#1 to signal FIQ
63     // An ARM CPU should be connected to a GIC following the convention `[<N*4>-<N*4+3>] -> cpuN@[0-3]`";
64     public enum InterruptSignalType
65     {
66         IRQ  = 0,
67         FIQ  = 1,
68         vIRQ = 2,
69         vFIQ = 3,
70     }
71 
72     public enum SecurityState
73     {
74         Secure,
75         NonSecure
76     }
77 
78     public class Affinity
79     {
Affinity(byte level0, byte level1 = 0, byte level2 = 0, byte level3 = 0)80         public Affinity(byte level0, byte level1 = 0, byte level2 = 0, byte level3 = 0)
81         {
82             levels[0] = level0;
83             levels[1] = level1;
84             levels[2] = level2;
85             levels[3] = level3;
86             UpdateLevels();
87         }
88 
Affinity(uint allLevels)89         public Affinity(uint allLevels)
90         {
91             BitHelper.GetBytesFromValue(levels, 0, allLevels, levels.Length, reverse: true);
92             UpdateLevels();
93         }
94 
GetLevel(int levelIndex)95         public byte GetLevel(int levelIndex)
96         {
97             return levels[levelIndex];
98         }
99 
100         public uint AllLevels => allLevels;
101 
ToString()102         public override string ToString()
103         {
104             return String.Join(".", levels);
105         }
106 
107         // NOTE: UpdateLevels needs to be called whenever any value inside of `levels` is updated.
UpdateLevels()108         protected void UpdateLevels()
109         {
110             allLevels = BitHelper.ToUInt32(levels, 0, levels.Length, reverse: true);
111         }
112 
113         protected readonly byte[] levels = new byte[LevelsCount];
114         protected const int LevelsCount = 4;
115 
116         private uint allLevels;
117     }
118 
119     public class MutableAffinity : Affinity
120     {
MutableAffinity()121         public MutableAffinity() : base(0) { }
122 
SetLevel(int levelIndex, byte levelValue)123         public void SetLevel(int levelIndex, byte levelValue)
124         {
125             levels[levelIndex] = levelValue;
126             UpdateLevels();
127         }
128     }
129 }
130