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 Antmicro.Renode.Core; 10 using Antmicro.Renode.Logging; 11 using Antmicro.Renode.Debugging; 12 using Antmicro.Renode.Exceptions; 13 using Antmicro.Renode.Peripherals.Bus; 14 using Antmicro.Renode.Core.Structure.Registers; 15 using System.Collections.Generic; 16 using System.Collections.ObjectModel; 17 using Antmicro.Renode.Utilities; 18 using Antmicro.Renode.Peripherals.CPU; 19 using Antmicro.Renode.Peripherals.IRQControllers.ARM_GenericInterruptControllerModel; 20 21 namespace Antmicro.Renode.Peripherals.IRQControllers 22 { 23 // NOTE: Memory mapped Virtual CPU Interface is currently not supported. 24 // It can be accesses only through system registers. 25 public class ARM_GenericInterruptController : IARMCPUsConnectionsProvider, IBusPeripheral, ILocalGPIOReceiver, INumberedGPIOOutput, IIRQController 26 { ARM_GenericInterruptController(IMachine machine, bool supportsTwoSecurityStates = true, ARM_GenericInterruptControllerVersion architectureVersion = ARM_GenericInterruptControllerVersion.Default, uint sharedPeripheralCount = 960)27 public ARM_GenericInterruptController(IMachine machine, bool supportsTwoSecurityStates = true, ARM_GenericInterruptControllerVersion architectureVersion = ARM_GenericInterruptControllerVersion.Default, uint sharedPeripheralCount = 960) 28 { 29 if(architectureVersion == ARM_GenericInterruptControllerVersion.GICv1) 30 { 31 // On GICv1, `GICD_ITARGETSRn` supports up to 8 CPU targets, so we ignore higher affinity levels completely 32 affinityToIdMask = 0xFF; 33 } 34 else 35 { 36 affinityToIdMask = uint.MaxValue; 37 } 38 busController = machine.GetSystemBus(this); 39 40 if(sharedPeripheralCount > InterruptsDecoder.MaximumSharedPeripheralCount) 41 { 42 throw new ConstructionException($"The number of shared peripherals {sharedPeripheralCount} is larger than supported {(InterruptsDecoder.MaximumSharedPeripheralCount)}"); 43 } 44 45 // The behavior of the GIC doesn't directly depend on the supportsTwoSecurityState field 46 // The disabledSecurity field corresponds to the GICD_CTRL.DS flag described in the GICv3 Architecture Specification 47 // The GIC without support for two security states has disabled security 48 // Changing the disabledSecurity field affects the behavior and register map of a GIC 49 // Once security is disabled it's impossible to enable it 50 // So it is impossible to enable security for the GIC that doesn't support two security states 51 this.supportsTwoSecurityStates = supportsTwoSecurityStates; 52 if(architectureVersion == ARM_GenericInterruptControllerVersion.Default) 53 { 54 this.Log(LogLevel.Warning, "GIC architecture version not explicitly set. Defaulting to v3"); 55 this.ArchitectureVersion = DefaultArchitectureVersion; 56 } 57 else 58 { 59 this.ArchitectureVersion = architectureVersion; 60 } 61 62 this.irqsDecoder = new InterruptsDecoder(sharedPeripheralCount, identifierBits: 10); 63 64 var irqIds = InterruptId.GetRange(irqsDecoder.SharedPeripheralFirst, irqsDecoder.SharedPeripheralLast) 65 .Concat(InterruptId.GetRange(irqsDecoder.ExtendedSharedPeripheralFirst, irqsDecoder.ExtendedSharedPeripheralLast)); 66 sharedInterrupts = new ReadOnlyDictionary<InterruptId, SharedInterrupt>(irqIds.ToDictionary(id => id, id => new SharedInterrupt(id))); 67 68 var groupTypes = new[] 69 { 70 GroupType.Group0, 71 GroupType.Group1NonSecure, 72 GroupType.Group1Secure 73 }; 74 groups = new ReadOnlyDictionary<GroupType, InterruptGroup>(groupTypes.ToDictionary(type => type, _ => new InterruptGroup())); 75 76 supportedInterruptSignals = (InterruptSignalType[])Enum.GetValues(typeof(InterruptSignalType)); 77 Connections = new ReadOnlyDictionary<int, IGPIO>(new Dictionary<int, IGPIO>()); 78 79 // Field layouts of some of the registers depend on the current security state 80 distributorRegistersSecureView = new DoubleWordRegisterCollection(this, BuildDistributorRegistersMapSecurityView(false, SecurityState.Secure)); 81 distributorRegistersNonSecureView = new DoubleWordRegisterCollection(this, BuildDistributorRegistersMapSecurityView(false, SecurityState.NonSecure)); 82 distributorRegistersDisabledSecurityView = new DoubleWordRegisterCollection(this, BuildDistributorRegistersMapSecurityView(true)); 83 cpuInterfaceRegistersSecureView = new DoubleWordRegisterCollection(this, BuildCPUInterfaceRegistersMapSecurityView(false, SecurityState.Secure)); 84 cpuInterfaceRegistersNonSecureView = new DoubleWordRegisterCollection(this, BuildCPUInterfaceRegistersMapSecurityView(false, SecurityState.NonSecure)); 85 cpuInterfaceRegistersDisabledSecurityView = new DoubleWordRegisterCollection(this, BuildCPUInterfaceRegistersMapSecurityView(true)); 86 87 // The rest may behave differently for various security settings, but the layout of fields doesn't change 88 distributorDoubleWordRegisters = new DoubleWordRegisterCollection(this, BuildDistributorDoubleWordRegistersMap()); 89 distributorQuadWordRegisters = new QuadWordRegisterCollection(this, BuildDistributorQuadWordRegistersMap()); 90 cpuInterfaceRegisters = new DoubleWordRegisterCollection(this, BuildCPUInterfaceRegistersMap()); 91 cpuInterfaceSystemRegisters = new QuadWordRegisterCollection(this, BuildCPUInterfaceSystemRegistersMap()); 92 93 Reset(); 94 } 95 Reset()96 public void Reset() 97 { 98 LockExecuteAndUpdate(() => 99 { 100 ackControl = false; 101 enableFIQ = ArchitectureVersionAtLeast3; 102 disabledSecurity = false; 103 affinityRoutingEnabledSecure = false; 104 affinityRoutingEnabledNonSecure = false; 105 foreach(var irq in sharedInterrupts.Values) 106 { 107 irq.Reset(); 108 } 109 foreach(var group in groups.Values) 110 { 111 group.Reset(); 112 } 113 foreach(var cpu in cpuEntries.Values) 114 { 115 cpu.Reset(); 116 } 117 }); 118 119 distributorRegistersSecureView.Reset(); 120 distributorRegistersNonSecureView.Reset(); 121 distributorRegistersDisabledSecurityView.Reset(); 122 distributorDoubleWordRegisters.Reset(); 123 distributorQuadWordRegisters.Reset(); 124 cpuInterfaceRegistersSecureView.Reset(); 125 cpuInterfaceRegistersNonSecureView.Reset(); 126 cpuInterfaceRegistersDisabledSecurityView.Reset(); 127 cpuInterfaceRegisters.Reset(); 128 cpuInterfaceSystemRegisters.Reset(); 129 } 130 AttachCPU(IARMSingleSecurityStateCPU cpu)131 public void AttachCPU(IARMSingleSecurityStateCPU cpu) 132 { 133 if(ArchitectureVersion == ARM_GenericInterruptControllerVersion.GICv1) 134 { 135 var affinities = cpuEntries.Keys.Select(c => c.Affinity).Select(a => new Affinity(a.AllLevels & ~affinityToIdMask)); 136 var highAffinity = cpu.Affinity.AllLevels & ~affinityToIdMask; 137 if(affinities.Any(a => highAffinity != a.AllLevels)) 138 { 139 throw new RecoverableException($"Previously registered CPUs have Affinities above Aff0 different from {new Affinity(highAffinity)}." 140 + $" This is illegal for {nameof(ARM_GenericInterruptControllerVersion.GICv1)}."); 141 } 142 } 143 var processorNumber = GetProcessorNumber(cpu); 144 this.Log(LogLevel.Noisy, "Trying to attach CPU {0}", cpu.Affinity); 145 if(TryGetCPUEntry(processorNumber, out var existingCPUEntry)) 146 { 147 throw new RecoverableException($"The CPU with the Processor Number {processorNumber} already exists."); 148 } 149 if(cpuEntries.Values.Any(entry => entry.Affinity.AllLevels == cpu.Affinity.AllLevels)) 150 { 151 throw new RecoverableException($"The CPU with the affinity {cpu.Affinity} already exists."); 152 } 153 154 var cpuMappedConnections = supportedInterruptSignals.ToDictionary(type => type, _ => (IGPIO)new GPIO()); 155 CPUEntry cpuEntry = null; 156 var cpuTwoSecurityStates = cpu as IARMTwoSecurityStatesCPU; 157 if(cpuTwoSecurityStates != null) 158 { 159 cpuEntry = new CPUEntryWithTwoSecurityStates(this, cpuTwoSecurityStates, groups.Keys, cpuMappedConnections); 160 cpuTwoSecurityStates.ExecutionModeChanged += (_, __) => OnExecutionModeChanged(cpuEntry); 161 } 162 else 163 { 164 if(this.supportsTwoSecurityStates) 165 { 166 cpu.Log(LogLevel.Info, "CPU is attached to GIC supporting Security Extensions." 167 + " This CPU doesn't implement Security Extensions so all its GIC accesses will be {0}. GIC's '{1}'" 168 + " constructor argument can be set to 'false' to create GIC without support for Security Extensions.", 169 cpu.SecurityState, nameof(supportsTwoSecurityStates)); 170 } 171 cpuEntry = new CPUEntry(this, cpu, groups.Keys, cpuMappedConnections); 172 } 173 cpuEntry.PrivateInterruptChanged += OnPrivateInterrupt; 174 175 // The convention of connecting interrupt signals can be found near the InterruptSignalType definition 176 var firstGPIO = (int)processorNumber * supportedInterruptSignals.Length; 177 var cpuConnections = cpuMappedConnections.Select(x => new KeyValuePair<int, IGPIO>(firstGPIO + (int)x.Key, x.Value)); 178 Connections = new ReadOnlyDictionary<int, IGPIO>(Connections.Concat(cpuConnections).ToDictionary(x => x.Key, x => x.Value)); 179 180 // SGIs require an information about a requesting CPU when Affinity Routing is disabled. 181 foreach(var requester in cpuEntries.Values.Where(req => req.ProcessorNumber < CPUsCountLegacySupport)) 182 { 183 cpuEntry.RegisterLegacySGIRequester(requester); 184 } 185 186 cpusByProcessorNumberCache.Add(processorNumber, cpu); 187 cpuEntries.Add(cpu, cpuEntry); 188 CPUAttached?.Invoke(cpu); 189 190 if(processorNumber < CPUsCountLegacySupport) 191 { 192 legacyCpusAttachedMask |= cpuEntry.TargetFieldFlag; 193 // The new attached CPU need to be registered for all CPUs including itself. 194 foreach(var target in cpuEntries.Values) 195 { 196 target.RegisterLegacySGIRequester(cpuEntry); 197 } 198 } 199 } 200 201 [ConnectionRegion("distributor")] WriteByteToDistributor(long offset, byte value)202 public void WriteByteToDistributor(long offset, byte value) 203 { 204 LockExecuteAndUpdate(() => 205 { 206 var registerExists = IsDistributorByteAccessible(offset) && Utils.TryWriteByteToDoubleWordCollection(distributorDoubleWordRegisters, offset, value, this); 207 LogWriteAccess(registerExists, value, "Distributor (byte access)", offset, (DistributorRegisters)offset); 208 } 209 ); 210 } 211 212 [ConnectionRegion("distributor")] ReadByteFromDistributor(long offset)213 public byte ReadByteFromDistributor(long offset) 214 { 215 byte value = 0; 216 LockExecuteAndUpdate(() => 217 { 218 var registerExists = IsDistributorByteAccessible(offset) && Utils.TryReadByteFromDoubleWordCollection(distributorDoubleWordRegisters, offset, out value, this); 219 LogReadAccess(registerExists, value, "Distributor (byte access)", offset, (DistributorRegisters)offset); 220 } 221 ); 222 return value; 223 } 224 225 [ConnectionRegion("distributor")] WriteDoubleWordToDistributor(long offset, uint value)226 public void WriteDoubleWordToDistributor(long offset, uint value) 227 { 228 LockExecuteAndUpdate(() => 229 { 230 var registerExists = TryWriteRegisterSecurityView(offset, value, distributorDoubleWordRegisters, 231 distributorRegistersSecureView, distributorRegistersNonSecureView, distributorRegistersDisabledSecurityView); 232 registerExists = registerExists || Utils.TryWriteDoubleWordToQuadWordCollection(distributorQuadWordRegisters, offset, value, this); 233 LogWriteAccess(registerExists, value, "Distributor", offset, (DistributorRegisters)offset); 234 } 235 ); 236 } 237 238 [ConnectionRegion("distributor")] ReadDoubleWordFromDistributor(long offset)239 public uint ReadDoubleWordFromDistributor(long offset) 240 { 241 uint value = 0; 242 LockExecuteAndUpdate(() => 243 { 244 var registerExists = TryReadRegisterSecurityView(offset, out value, distributorDoubleWordRegisters, 245 distributorRegistersSecureView, distributorRegistersNonSecureView, distributorRegistersDisabledSecurityView); 246 registerExists = registerExists || Utils.TryReadDoubleWordFromQuadWordCollection(distributorQuadWordRegisters, offset, out value, this); 247 LogReadAccess(registerExists, value, "Distributor", offset, (DistributorRegisters)offset); 248 } 249 ); 250 return value; 251 } 252 253 [ConnectionRegion("distributor")] WriteQuadWordToDistributor(long offset, ulong value)254 public void WriteQuadWordToDistributor(long offset, ulong value) 255 { 256 LockExecuteAndUpdate(() => 257 LogWriteAccess(distributorQuadWordRegisters.TryWrite(offset, value), value, "Distributor", offset, (DistributorRegisters)offset) 258 ); 259 } 260 261 [ConnectionRegion("distributor")] ReadQuadWordFromDistributor(long offset)262 public ulong ReadQuadWordFromDistributor(long offset) 263 { 264 ulong value = 0; 265 LockExecuteAndUpdate(() => 266 LogWriteAccess(distributorQuadWordRegisters.TryRead(offset, out value), value, "Distributor", offset, (DistributorRegisters)offset) 267 ); 268 return value; 269 } 270 271 [ConnectionRegion("cpuInterface")] WriteDoubleWordToCPUInterface(long offset, uint value)272 public void WriteDoubleWordToCPUInterface(long offset, uint value) 273 { 274 LockExecuteAndUpdate(() => 275 { 276 var registerExists = TryWriteRegisterSecurityView(offset, value, cpuInterfaceRegisters, 277 cpuInterfaceRegistersSecureView, cpuInterfaceRegistersNonSecureView, cpuInterfaceRegistersDisabledSecurityView); 278 LogWriteAccess(registerExists, value, "memory-mapped CPU Interface", offset, (CPUInterfaceRegisters)offset); 279 } 280 ); 281 } 282 283 [ConnectionRegion("cpuInterface")] ReadDoubleWordFromCPUInterface(long offset)284 public uint ReadDoubleWordFromCPUInterface(long offset) 285 { 286 uint value = 0; 287 LockExecuteAndUpdate(() => 288 { 289 var registerExists = TryReadRegisterSecurityView(offset, out value, cpuInterfaceRegisters, 290 cpuInterfaceRegistersSecureView, cpuInterfaceRegistersNonSecureView, cpuInterfaceRegistersDisabledSecurityView); 291 LogReadAccess(registerExists, value, "memory-mapped CPU Interface", offset, (CPUInterfaceRegisters)offset); 292 } 293 ); 294 return value; 295 } 296 WriteSystemRegisterCPUInterface(uint offset, ulong value)297 public void WriteSystemRegisterCPUInterface(uint offset, ulong value) 298 { 299 LockExecuteAndUpdate(() => 300 LogWriteAccess(cpuInterfaceSystemRegisters.TryWrite(offset, value), value, "CPU Interface", offset, (CPUInterfaceSystemRegisters)offset) 301 ); 302 } 303 ReadSystemRegisterCPUInterface(uint offset)304 public ulong ReadSystemRegisterCPUInterface(uint offset) 305 { 306 ulong value = 0; 307 LockExecuteAndUpdate(() => 308 LogReadAccess(cpuInterfaceSystemRegisters.TryRead(offset, out value), value, "CPU Interface", offset, (CPUInterfaceSystemRegisters)offset) 309 ); 310 return value; 311 } 312 313 // Handles SPIs. OnGPIO(int number, bool value)314 public void OnGPIO(int number, bool value) 315 { 316 var irqId = new InterruptId((uint)number + (uint)irqsDecoder.SharedPeripheralFirst); 317 if(!irqsDecoder.IsSharedPeripheral(irqId)) 318 { 319 this.Log(LogLevel.Warning, "Generated interrupt isn't a Shared Peripheral Interrupt, interrupt identifier: {0}", irqId); 320 return; 321 } 322 this.Log(LogLevel.Debug, "Setting Shared Peripheral Interrupt #{0} signal to {1}", irqId, value); 323 LockExecuteAndUpdate(() => 324 sharedInterrupts[irqId].State.AssertAsPending(value) 325 ); 326 } 327 328 // Private Peripheral Interrupts are connected using the ILocalGPIOReceiver interface 329 // Every CPUEntry class implements the IGPIOReceiver interface used to connect PPIs to each CPU 330 // The CPUEntry provides event for handling received interrupts by an external action 331 // It's expected to handle all of these interrupts by OnPrivateInterrupt method GetLocalReceiver(int processorNumber)332 public IGPIOReceiver GetLocalReceiver(int processorNumber) 333 { 334 return GetCPUEntry((uint)processorNumber); 335 } 336 GetEnabledInterruptIdentifiers(uint processorNumber)337 public IEnumerable<uint> GetEnabledInterruptIdentifiers(uint processorNumber) 338 { 339 var cpu = GetCPUEntry(processorNumber); 340 lock(locker) 341 { 342 return GetAllEnabledInterrupts(cpu).Select(irq => (uint)irq.Identifier); 343 } 344 } 345 GetRedistributorRegistrations()346 public IEnumerable<ArmGicRedistributorRegistration> GetRedistributorRegistrations() 347 { 348 return this.GetMachine().GetSystemBus(this).GetRegistrationPoints(this).OfType<ArmGicRedistributorRegistration>(); 349 } 350 LockExecuteAndUpdate(Action action)351 public void LockExecuteAndUpdate(Action action) 352 { 353 lock(locker) 354 { 355 action(); 356 UpdateBestPendingInterrupts(); 357 foreach(var cpu in cpuEntries.Values) 358 { 359 cpu.UpdateSignals(); 360 } 361 } 362 } 363 LogWriteAccess(bool registerExists, object value, string collectionName, long offset, object prettyOffset)364 public void LogWriteAccess(bool registerExists, object value, string collectionName, long offset, object prettyOffset) 365 { 366 this.Log(LogLevel.Noisy, "{0} writes to 0x{1:X} ({2}) register of {3}, value 0x{4:X}.", GetAskingCPUEntry().Name, offset, prettyOffset, collectionName, value); 367 if(!registerExists) 368 { 369 this.Log(LogLevel.Warning, "Unhandled write to 0x{0:X} register of {1}, value 0x{2:X}.", offset, collectionName, value); 370 } 371 } 372 LogReadAccess(bool registerExists, object value, string collectionName, long offset, object prettyOffset)373 public void LogReadAccess(bool registerExists, object value, string collectionName, long offset, object prettyOffset) 374 { 375 if(!registerExists) 376 { 377 this.Log(LogLevel.Warning, "Unhandled read from 0x{0:X} register of {1}.", offset, collectionName); 378 } 379 this.Log(LogLevel.Noisy, "{0} reads from 0x{1:X} ({2}) register of {3}, returned 0x{4:X}.", GetAskingCPUEntry().Name, offset, prettyOffset, collectionName, value); 380 } 381 TryGetCPUEntry(uint processorNumber, out CPUEntry cpuEntry)382 public bool TryGetCPUEntry(uint processorNumber, out CPUEntry cpuEntry) 383 { 384 var exists = cpusByProcessorNumberCache.TryGetValue(processorNumber, out var cpu); 385 cpuEntry = exists ? cpuEntries[cpu] : null; 386 return exists; 387 } 388 TryGetCPUEntryForCPU(IARMSingleSecurityStateCPU cpu, out CPUEntry cpuEntry)389 public bool TryGetCPUEntryForCPU(IARMSingleSecurityStateCPU cpu, out CPUEntry cpuEntry) 390 { 391 return cpuEntries.TryGetValue(cpu, out cpuEntry); 392 } 393 GetCPUEntry(uint processorNumber)394 public CPUEntry GetCPUEntry(uint processorNumber) 395 { 396 if(!TryGetCPUEntry(processorNumber, out var cpuEntry)) 397 { 398 throw new RecoverableException($"There is no CPU with the Processor Number {processorNumber}."); 399 } 400 return cpuEntry; 401 } 402 BuildInterruptSetEnableRegisters(InterruptId startId, InterruptId endId, string name, Func<CPUEntry> cpuEntryProvider = null)403 public IEnumerable<DoubleWordRegister> BuildInterruptSetEnableRegisters(InterruptId startId, InterruptId endId, string name, Func<CPUEntry> cpuEntryProvider = null) 404 { 405 return BuildInterruptFlagRegisters(startId, endId, name, 406 writeCallback: (irq, val) => irq.Config.Enabled |= val, 407 valueProviderCallback: irq => irq.Config.Enabled, 408 cpuEntryProvider: cpuEntryProvider 409 ); 410 } 411 BuildInterruptClearEnableRegisters(InterruptId startId, InterruptId endId, string name, Func<CPUEntry> cpuEntryProvider = null)412 public IEnumerable<DoubleWordRegister> BuildInterruptClearEnableRegisters(InterruptId startId, InterruptId endId, string name, Func<CPUEntry> cpuEntryProvider = null) 413 { 414 return BuildInterruptFlagRegisters(startId, endId, name, 415 writeCallback: (irq, val) => irq.Config.Enabled &= !val, 416 valueProviderCallback: irq => irq.Config.Enabled, 417 cpuEntryProvider: cpuEntryProvider 418 ); 419 } 420 BuildInterruptPriorityRegisters(InterruptId startId, InterruptId endId, string name, Func<CPUEntry> cpuEntryProvider = null)421 public IEnumerable<DoubleWordRegister> BuildInterruptPriorityRegisters(InterruptId startId, InterruptId endId, string name, Func<CPUEntry> cpuEntryProvider = null) 422 { 423 return BuildInterruptEnumRegisters<InterruptPriority>(startId, endId, name, 4, 424 writeCallback: (irq, val) => irq.Config.Priority = val, 425 valueProviderCallback: irq => irq.Config.Priority, 426 cpuEntryProvider: cpuEntryProvider 427 ); 428 } 429 BuildPrivateInterruptTargetsRegisters(InterruptId startId, InterruptId endId, string name)430 public IEnumerable<DoubleWordRegister> BuildPrivateInterruptTargetsRegisters(InterruptId startId, InterruptId endId, string name) 431 { 432 return BuildInterruptValueRegisters(startId, endId, name, 4, 433 valueProviderCallback: _ => GetAskingCPUEntry().TargetFieldFlag 434 ); 435 } 436 BuildSharedInterruptTargetsRegisters(InterruptId startId, InterruptId endId, string name)437 public IEnumerable<DoubleWordRegister> BuildSharedInterruptTargetsRegisters(InterruptId startId, InterruptId endId, string name) 438 { 439 return BuildInterruptValueRegisters(startId, endId, name, 4, 440 writeCallback: (irq, val) => 441 { 442 if(IsAffinityRoutingEnabled(GetAskingCPUEntry())) 443 { 444 this.Log(LogLevel.Warning, "Trying to write ITARGETSR register when Affinity Routing is enabled, write ignored."); 445 return; 446 } 447 var validTargets = legacyCpusAttachedMask & val; 448 ((SharedInterrupt)irq).TargetCPUs = (byte)validTargets; 449 if(validTargets != val) 450 { 451 this.Log(LogLevel.Warning, "Interrupt {0} configured to target an invalid CPU, id: {1}, writes ignored.", irq.Identifier, String.Join(", ", BitHelper.GetSetBits(validTargets ^ val))); 452 } 453 }, 454 valueProviderCallback: irq => 455 { 456 if(IsAffinityRoutingEnabled(GetAskingCPUEntry())) 457 { 458 this.Log(LogLevel.Warning, "Trying to read ITARGETSR register when Affinity Routing is enabled, returning 0."); 459 return 0; 460 } 461 return ((SharedInterrupt)irq).TargetCPUs; 462 } 463 ); 464 } 465 BuildInterruptConfigurationRegisters(InterruptId startId, InterruptId endId, string name, bool isReadonly = false, Func<CPUEntry> cpuEntryProvider = null)466 public IEnumerable<DoubleWordRegister> BuildInterruptConfigurationRegisters(InterruptId startId, InterruptId endId, string name, bool isReadonly = false, Func<CPUEntry> cpuEntryProvider = null) 467 { 468 Action<Interrupt, InterruptTriggerType> writeCallback = null; 469 if(!isReadonly) 470 { 471 writeCallback = (irq, val) => 472 { 473 irq.State.TriggerType = val; 474 if(val != InterruptTriggerType.LevelSensitive && val != InterruptTriggerType.EdgeTriggered) 475 { 476 this.Log(LogLevel.Error, "Setting an unknown interrupt trigger type, value {0}", val); 477 } 478 }; 479 } 480 return BuildInterruptEnumRegisters<InterruptTriggerType>(startId, endId, name, 16, 481 writeCallback: writeCallback, 482 valueProviderCallback: irq => irq.State.TriggerType, 483 cpuEntryProvider: cpuEntryProvider 484 ); 485 } 486 BuildInterruptSetActiveRegisters(InterruptId startId, InterruptId endId, string name)487 public IEnumerable<DoubleWordRegister> BuildInterruptSetActiveRegisters(InterruptId startId, InterruptId endId, string name) 488 { 489 return BuildInterruptFlagRegisters(startId, endId, name, 490 writeCallback: (irq, val) => irq.State.Active |= val, 491 valueProviderCallback: irq => irq.State.Active 492 ); 493 } 494 BuildInterruptClearActiveRegisters(InterruptId startId, InterruptId endId, string name)495 public IEnumerable<DoubleWordRegister> BuildInterruptClearActiveRegisters(InterruptId startId, InterruptId endId, string name) 496 { 497 return BuildInterruptFlagRegisters(startId, endId, name, 498 writeCallback: (irq, val) => irq.State.Active &= !val, 499 valueProviderCallback: irq => irq.State.Active 500 ); 501 } 502 BuildInterruptSetPendingRegisters(InterruptId startId, InterruptId endId, string name)503 public IEnumerable<DoubleWordRegister> BuildInterruptSetPendingRegisters(InterruptId startId, InterruptId endId, string name) 504 { 505 return BuildInterruptFlagRegisters(startId, endId, name, 506 writeCallback: (irq, val) => irq.State.Pending |= val, 507 valueProviderCallback: irq => irq.State.Pending 508 ); 509 } 510 BuildInterruptClearPendingRegisters(InterruptId startId, InterruptId endId, string name, Func<CPUEntry> cpuEntryProvider = null)511 public IEnumerable<DoubleWordRegister> BuildInterruptClearPendingRegisters(InterruptId startId, InterruptId endId, string name, Func<CPUEntry> cpuEntryProvider = null) 512 { 513 return BuildInterruptFlagRegisters(startId, endId, name, 514 writeCallback: (irq, val) => irq.State.Pending &= !val, 515 valueProviderCallback: irq => irq.State.Pending, 516 cpuEntryProvider: cpuEntryProvider 517 ); 518 } 519 BuildInterruptGroupRegisters(InterruptId startId, InterruptId endId, string name, Func<CPUEntry> cpuEntryProvider = null)520 public IEnumerable<DoubleWordRegister> BuildInterruptGroupRegisters(InterruptId startId, InterruptId endId, string name, Func<CPUEntry> cpuEntryProvider = null) 521 { 522 return BuildInterruptFlagRegisters(startId, endId, name, 523 writeCallback: (irq, val) => irq.Config.GroupBit = val, 524 valueProviderCallback: irq => irq.Config.GroupBit, 525 allowAccessWhenNonSecureGroup: false, 526 cpuEntryProvider: cpuEntryProvider 527 ); 528 } 529 BuildInterruptGroupModifierRegisters(InterruptId startId, InterruptId endId, string name, Func<CPUEntry> cpuEntryProvider = null)530 public IEnumerable<DoubleWordRegister> BuildInterruptGroupModifierRegisters(InterruptId startId, InterruptId endId, string name, Func<CPUEntry> cpuEntryProvider = null) 531 { 532 return BuildInterruptFlagRegisters(startId, endId, name, 533 writeCallback: (irq, val) => 534 { 535 if(!DisabledSecurity) 536 { 537 irq.Config.GroupModifierBit = val; 538 } 539 else 540 { 541 // The Zephyr uses this field as usual, so the log message isn't a warning 542 this.Log(LogLevel.Debug, "The group modifier register is reserved for the disabled security, write ignored."); 543 } 544 }, 545 valueProviderCallback: irq => irq.Config.GroupModifierBit, 546 allowAccessWhenNonSecureGroup: false, 547 cpuEntryProvider: cpuEntryProvider 548 ); 549 } 550 BuildPrivateOrSharedPeripheralInterruptStatusRegisters(InterruptId startId, InterruptId endId, string name)551 public IEnumerable<DoubleWordRegister> BuildPrivateOrSharedPeripheralInterruptStatusRegisters(InterruptId startId, InterruptId endId, string name) 552 { 553 return BuildInterruptFlagRegisters(startId, endId, name, 554 valueProviderCallback: irq => irq.State.Pending 555 ); 556 } 557 558 public long PeripheralIdentificationOffset => ArchitectureVersionAtLeast3 559 ? (long)RedistributorRegisters.PeripheralIdentification2_v3v4 560 : (long)RedistributorRegisters.PeripheralIdentification2_v1v2; 561 562 public IReadOnlyDictionary<int, IGPIO> Connections { get; private set; } 563 public IEnumerable<IARMSingleSecurityStateCPU> AttachedCPUs => cpuEntries.Keys; 564 public InterruptsDecoder IrqsDecoder => irqsDecoder; 565 566 public bool DisabledSecurity 567 { 568 get => !supportsTwoSecurityStates || disabledSecurity; 569 set 570 { 571 if(!supportsTwoSecurityStates) 572 { 573 this.Log(LogLevel.Warning, "Disabling security isn't allowed for a single security GIC, write ignored."); 574 return; 575 } 576 if(!SetOnTransitionToTrue(ref disabledSecurity, value, "Trying to enable security when it's disabled, write ignored.")) 577 { 578 return; 579 } 580 581 if(groups.Values.Any(group => group.Enabled)) 582 { 583 this.Log(LogLevel.Warning, "Disabling security when a group of interrupts is enabled."); 584 } 585 586 var cpuConfigs = cpuEntries.Values.SelectMany(cpu => cpu.AllPrivateAndSoftwareGeneratedInterruptsConfigs); 587 var allInterruptConfigs = cpuConfigs.Concat(sharedInterrupts.Values.Select(irq => irq.Config)); 588 foreach(var config in allInterruptConfigs) 589 { 590 config.GroupModifierBit = false; 591 } 592 } 593 } 594 595 public bool AffinityRoutingEnabledSecure 596 { 597 get => affinityRoutingEnabledSecure; 598 set 599 { 600 if(!SetOnTransitionToTrue(ref affinityRoutingEnabledSecure, value, "Trying to disable affinity routing for secure state when it's enabled, write ignored.")) 601 { 602 return; 603 } 604 // According to the specification the value for secure state overrides the value for non-secure state. 605 affinityRoutingEnabledNonSecure = true; 606 607 if(groups.Values.Any(group => group.Enabled)) 608 { 609 this.Log(LogLevel.Warning, "Enabling affinity routing for secure state when a group of interrupts is enabled."); 610 } 611 } 612 } 613 614 public bool AffinityRoutingEnabledNonSecure 615 { 616 get => affinityRoutingEnabledNonSecure; 617 set 618 { 619 if(!SetOnTransitionToTrue(ref affinityRoutingEnabledNonSecure, value, "Trying to disable affinity routing for non-secure state when it's enabled, write ignored.")) 620 { 621 return; 622 } 623 if(groups[GroupType.Group1NonSecure].Enabled) 624 { 625 this.Log(LogLevel.Warning, "Enabling affinity routing for non-secure state when the Group 1 Non-secure is enabled."); 626 } 627 } 628 } 629 630 public bool AffinityRoutingEnabledBoth => DisabledSecurity || AffinityRoutingEnabledSecure && AffinityRoutingEnabledNonSecure; 631 632 /// <summary> 633 /// Setting this property to true will causes all interrupts to be reported to a core with lowest ID, which configuration allows it to take. 634 /// 635 /// This is mostly for debugging purposes. 636 /// It allows to predict a core (in a multi-core setup) to handle the given interrupt making it easier to debug. 637 /// </summary> 638 public bool ForceLowestIdCpuAsInterruptTarget { get; set; } 639 640 public ARM_GenericInterruptControllerVersion ArchitectureVersion { get; } 641 public bool ArchitectureVersionAtLeast3 => ArchitectureVersion >= ARM_GenericInterruptControllerVersion.GICv3; 642 public uint CPUInterfaceProductIdentifier { get; set; } = DefaultCPUInterfaceProductIdentifier; 643 public uint DistributorProductIdentifier { get; set; } = DefaultDistributorProductIdentifier; 644 public byte CPUInterfaceRevision { get; set; } = DefaultRevisionNumber; 645 public uint CPUInterfaceImplementer { get; set; } = DefaultImplementerIdentification; 646 public byte DistributorVariant { get; set; } = DefaultVariantNumber; 647 public byte DistributorRevision { get; set; } = DefaultRevisionNumber; 648 public uint DistributorImplementer { get; set; } = DefaultImplementerIdentification; 649 public uint RedistributorProductIdentifier { get; set; } = DefaultRedistributorProductIdentifier; 650 public byte RedistributorVariant { get; set; } = DefaultVariantNumber; 651 public byte RedistributorRevision { get; set; } = DefaultRevisionNumber; 652 public uint RedistributorImplementer { get; set; } = DefaultImplementerIdentification; 653 654 public event Action<IARMSingleSecurityStateCPU> CPUAttached; 655 OnPrivateInterrupt(CPUEntry cpu, int id, bool value)656 private void OnPrivateInterrupt(CPUEntry cpu, int id, bool value) 657 { 658 var irqId = new InterruptId((uint)id); 659 if(!irqsDecoder.IsPrivatePeripheral(irqId)) 660 { 661 this.Log(LogLevel.Warning, "Generated interrupt isn't a Private Peripheral Interrupt, interrupt identifier: {0}", irqId); 662 return; 663 } 664 this.Log(LogLevel.Debug, "Setting Private Peripheral Interrupt #{0} signal to {1} for {2}", irqId, value, cpu.Name); 665 LockExecuteAndUpdate(() => 666 cpu.PrivatePeripheralInterrupts[irqId].State.AssertAsPending(value) 667 ); 668 } 669 OnSoftwareGeneratedInterrupt(CPUEntry requestingCPU, SoftwareGeneratedInterruptRequest request)670 private void OnSoftwareGeneratedInterrupt(CPUEntry requestingCPU, SoftwareGeneratedInterruptRequest request) 671 { 672 // The GIC uses a groups configuration at the moment of SGI request to choose correct target CPUs. 673 var irqId = request.InterruptId; 674 DebugHelper.Assert(irqsDecoder.IsSoftwareGenerated(irqId), $"Invalid interrupt identifier ({irqId}), it doesn't indicate an SGI."); 675 this.Log(LogLevel.Noisy, "The {0} requests an SGI with id {1}.", requestingCPU.Name, irqId); 676 677 var targetCPUs = new List<CPUEntry>(); 678 switch(request.TargetCPUsType) 679 { 680 case SoftwareGeneratedInterruptRequest.TargetType.Loopback: 681 targetCPUs.Add(requestingCPU); 682 break; 683 case SoftwareGeneratedInterruptRequest.TargetType.AllCPUs: 684 targetCPUs.AddRange(cpuEntries.Values.Where(cpu => cpu != requestingCPU)); 685 break; 686 case SoftwareGeneratedInterruptRequest.TargetType.TargetList: 687 foreach(var affinity in request.TargetsList) 688 { 689 if(TryGetCPUEntry(affinity.AllLevels, out var targetCPU)) 690 { 691 targetCPUs.Add(targetCPU); 692 } 693 else 694 { 695 this.Log(LogLevel.Debug, "There is no target CPU with the affinity {0} for an SGI request.", affinity); 696 } 697 } 698 break; 699 default: 700 this.Log(LogLevel.Warning, "Unknown Software Generated Interrupt target type {0}", request.TargetCPUsType); 701 return; 702 } 703 704 if(IsAffinityRoutingEnabled(requestingCPU)) 705 { 706 OnSGIAffinityRouting(requestingCPU, targetCPUs, request); 707 } 708 else 709 { 710 OnSGILegacyRouting(requestingCPU, targetCPUs, request); 711 } 712 } 713 OnSGIAffinityRouting(CPUEntry requestingCPU, List<CPUEntry> targetCPUs, SoftwareGeneratedInterruptRequest request)714 private void OnSGIAffinityRouting(CPUEntry requestingCPU, List<CPUEntry> targetCPUs, SoftwareGeneratedInterruptRequest request) 715 { 716 var isOtherSecurityState = GroupTypeToIsStateSecure(request.TargetGroup) != requestingCPU.IsStateSecure; 717 if(isOtherSecurityState && !AffinityRoutingEnabledBoth) 718 { 719 this.Log(LogLevel.Debug, "Generating SGIs for the other Security state is only supported when affinity rouing is enabled for both Security states."); 720 return; 721 } 722 var irqId = request.InterruptId; 723 foreach(var target in targetCPUs) 724 { 725 var interrupt = target.SoftwareGeneratedInterruptsUnknownRequester[irqId]; 726 this.Log(LogLevel.Noisy, "Trying to request interrupt for target {0}, interrupt group type {1}, request group {2}, access in {3} state.", 727 target.Name, interrupt.Config.GroupType, request.TargetGroup, requestingCPU.IsStateSecure ? "secure" : "non-secure"); 728 729 if(ShouldAssertSGIAffinityRouting(requestingCPU, request, interrupt, target.NonSecureSGIAccess[(uint)irqId])) 730 { 731 this.Log(LogLevel.Noisy, "Setting Software Generated Interrupt #{0} signal for {1}", irqId, target.Name); 732 // SGIs are triggered by a register access so the method is already called inside a lock. 733 interrupt.State.AssertAsPending(true); 734 } 735 else 736 { 737 this.Log(LogLevel.Noisy, "SGI #{0} not forwarded for {1}.", irqId, target.Name); 738 } 739 } 740 } 741 ShouldAssertSGIAffinityRouting(CPUEntry requestingCPU, SoftwareGeneratedInterruptRequest request, SoftwareGeneratedInterrupt interrupt, NonSecureAccess targetNonSecureAccess)742 private bool ShouldAssertSGIAffinityRouting(CPUEntry requestingCPU, SoftwareGeneratedInterruptRequest request, SoftwareGeneratedInterrupt interrupt, 743 NonSecureAccess targetNonSecureAccess) 744 { 745 if(requestingCPU.IsStateSecure) 746 { 747 return request.TargetGroup == interrupt.Config.GroupType || 748 request.TargetGroup == GroupType.Group1Secure && interrupt.Config.GroupType == GroupType.Group0 && DisabledSecurity; 749 } 750 if(request.TargetGroup == interrupt.Config.GroupType || interrupt.Config.GroupType == GroupType.Group0) 751 { 752 return request.TargetGroup == GroupType.Group1NonSecure || DisabledSecurity || NonSecureAccessPermitsGroup(targetNonSecureAccess, request.TargetGroup); 753 } 754 return request.TargetGroup == GroupType.Group1NonSecure && interrupt.Config.GroupType == GroupType.Group1Secure && NonSecureAccessPermitsGroup(targetNonSecureAccess, request.TargetGroup); 755 } 756 OnSGILegacyRouting(CPUEntry requestingCPU, List<CPUEntry> targetCPUs, SoftwareGeneratedInterruptRequest request)757 private void OnSGILegacyRouting(CPUEntry requestingCPU, List<CPUEntry> targetCPUs, SoftwareGeneratedInterruptRequest request) 758 { 759 var irqId = request.InterruptId; 760 foreach(var target in targetCPUs) 761 { 762 if(!target.SoftwareGeneratedInterruptsLegacyRequester.TryGetValue(requestingCPU, out var interrupts)) 763 { 764 this.Log(LogLevel.Warning, "The GIC doesn't support requesting an SGI from the CPU with the Processor Number ({0}) greater than {1}, request ignored.", requestingCPU.ProcessorNumber, CPUsCountLegacySupport - 1); 765 return; 766 } 767 768 var interrupt = interrupts[irqId]; 769 this.Log(LogLevel.Noisy, "Trying to request interrupt for target {0}, interrupt group type (GICD_IGROUPRn) {1}, request group (NSATT) {2}, access in {3} state.", 770 target.Name, interrupt.Config.GroupType, request.TargetGroup, requestingCPU.IsStateSecure ? "secure" : "non-secure"); 771 772 if(ShouldAssertSGILegacyRouting(requestingCPU, request, interrupt)) 773 { 774 this.Log(LogLevel.Noisy, "Setting Software Generated Interrupt #{0} signal for {1}", irqId, target.Name); 775 // SGIs are triggered by a register access so the method is already called inside a lock. 776 interrupt.State.AssertAsPending(true); 777 } 778 else 779 { 780 this.Log(LogLevel.Noisy, "SGI #{0} not forwarded for {1}.", irqId, target.Name); 781 } 782 } 783 } 784 ShouldAssertSGILegacyRouting(CPUEntry requestingCPU, SoftwareGeneratedInterruptRequest request, SoftwareGeneratedInterrupt interrupt)785 private bool ShouldAssertSGILegacyRouting(CPUEntry requestingCPU, SoftwareGeneratedInterruptRequest request, SoftwareGeneratedInterrupt interrupt) 786 { 787 // See: "SGI generation when the GIC implements the Security Extensions" for the truth table 788 // Without the Security Extension, this is irrelevant 789 if(DisabledSecurity) 790 { 791 return true; 792 } 793 // If GICD_SGIR write is done in non-secure mode, only Group1 is forwarded 794 else if(!requestingCPU.IsStateSecure) 795 { 796 return interrupt.Config.GroupType != GroupType.Group0; 797 } 798 // According to the specification, interrupt with a group different than a target group is just ignored, if GICD_SGIR write is done in secure mode. 799 else if(requestingCPU.IsStateSecure && interrupt.Config.GroupType == request.TargetGroup) 800 { 801 return true; 802 } 803 804 return false; 805 } 806 NonSecureAccessPermitsGroup(NonSecureAccess access, GroupType type)807 private bool NonSecureAccessPermitsGroup(NonSecureAccess access, GroupType type) 808 { 809 // To maintain the principle that as the value increases additional accesses are permitted 810 // Arm strongly recommends that implementations treat the reserved value as 0b10. 811 // That's why we compare `access` using the >= operator. 812 switch(type) 813 { 814 case GroupType.Group1NonSecure: 815 return true; 816 case GroupType.Group1Secure: 817 return access >= NonSecureAccess.BothGroupsPermitted; 818 case GroupType.Group0: 819 return access >= NonSecureAccess.SecureGroup0Permitted; 820 default: 821 throw new ArgumentOutOfRangeException($"There is no valid GroupType for value: {type}."); 822 } 823 } 824 GroupTypeToIsStateSecure(GroupType type)825 private bool GroupTypeToIsStateSecure(GroupType type) 826 { 827 switch(type) 828 { 829 case GroupType.Group0: 830 case GroupType.Group1Secure: 831 return true; 832 case GroupType.Group1NonSecure: 833 return false; 834 default: 835 throw new ArgumentOutOfRangeException($"There is no valid GroupType for value: {type}."); 836 } 837 } 838 GetGroup1ForSecurityState(bool isSecure)839 private GroupType GetGroup1ForSecurityState(bool isSecure) 840 { 841 return isSecure 842 // When System register access is not enabled for Secure EL1, or when GICD_CTLR.DS == 1, 843 // the Distributor treats Secure Group 1 interrupts as Group 0 interrupts 844 ? DisabledSecurity ? GroupType.Group0 : GroupType.Group1Secure 845 : GroupType.Group1NonSecure; 846 } 847 848 // The GIC uses the latest CPU state and the latest groups configuration to choose a correct interrupt signal to assert. OnExecutionModeChanged(CPUEntry cpu)849 private void OnExecutionModeChanged(CPUEntry cpu) 850 { 851 lock(locker) 852 { 853 cpu.UpdateSignals(); 854 } 855 } 856 857 // Returns the best pending interrupt for given candidates. 858 // If null is returned, that means there's no pending interrupt. 859 private T FindBestPendingInterrupt<T>(IEnumerable<T> pendingCandidates) where T : Interrupt 860 { 861 var bestPending = pendingCandidates.FirstOrDefault(); 862 foreach(var irq in pendingCandidates.Skip(1)) 863 { 864 if(irq.Config.Priority < bestPending.Config.Priority) 865 { 866 bestPending = irq; 867 if(bestPending.Config.Priority == InterruptPriority.Highest) 868 { 869 break; 870 } 871 } 872 } 873 return bestPending; 874 } 875 UpdateBestPendingInterrupts()876 private void UpdateBestPendingInterrupts() 877 { 878 foreach(var cpu in cpuEntries.Values) 879 { 880 if(cpu.VirtualCPUInterfaceEnabled) 881 { 882 cpu.BestPendingVirtual = FindBestPendingInterrupt(GetAllPendingCandidateVirtualInterrupts(cpu)); 883 } 884 else 885 { 886 cpu.BestPendingVirtual = null; 887 } 888 cpu.BestPending = FindBestPendingInterrupt(GetAllPendingCandidateInterrupts(cpu)); 889 } 890 } 891 GetSharedInterruptsTargetingCPU(CPUEntry cpu)892 private IEnumerable<Interrupt> GetSharedInterruptsTargetingCPU(CPUEntry cpu) 893 { 894 IEnumerable<SharedInterrupt> interrupts = sharedInterrupts.Values; 895 if(cpuEntries.Count == 1) 896 { 897 // If there is only one CPU all interrupts target it. 898 return interrupts; 899 } 900 if(!IsAffinityRoutingEnabled(cpu)) 901 { 902 return interrupts.Where(irq => 903 irq.IsLegacyRoutingTargetingCPU(cpu) && (!ForceLowestIdCpuAsInterruptTarget || irq.IsLowestLegacyRoutingTargettedCPU(cpu)) 904 ); 905 } 906 907 return interrupts.Where(irq => 908 irq.IsAffinityRoutingTargetingCPU(cpu) && (!ForceLowestIdCpuAsInterruptTarget || irq.IsLowestAffinityRoutingTargettedCPU(cpu, this)) 909 ); 910 } 911 GetAllEnabledInterrupts(CPUEntry cpu)912 private IEnumerable<Interrupt> GetAllEnabledInterrupts(CPUEntry cpu) 913 { 914 var enabledGroups = groups.Keys.Where(type => groups[type].Enabled && cpu.Groups.Physical[type].Enabled).ToArray(); 915 IEnumerable<SharedInterrupt> filteredSharedInterrupts = sharedInterrupts.Values; 916 return cpu.AllPrivateAndSoftwareGeneratedInterrupts 917 .Concat(GetSharedInterruptsTargetingCPU(cpu)) 918 .Where(irq => irq.Config.Enabled && enabledGroups.Contains(irq.Config.GroupType)); 919 } 920 GetAllInterrupts(CPUEntry cpu)921 private IEnumerable<Interrupt> GetAllInterrupts(CPUEntry cpu) 922 { 923 return cpu.AllPrivateAndSoftwareGeneratedInterrupts.Concat(sharedInterrupts.Values); 924 } 925 InterruptPriorityFilter(InterruptPriority priorityMask, InterruptPriority runningPriority)926 private Func<Interrupt, bool> InterruptPriorityFilter(InterruptPriority priorityMask, InterruptPriority runningPriority) 927 { 928 return irq => irq.State.Pending && !irq.State.Active && irq.Config.Priority < priorityMask && irq.Config.Priority < runningPriority; 929 } 930 GetAllPendingCandidateInterrupts(CPUEntry cpu)931 private IEnumerable<Interrupt> GetAllPendingCandidateInterrupts(CPUEntry cpu) 932 { 933 var filter = InterruptPriorityFilter(cpu.PhysicalPriorityMask, cpu.RunningInterrupts.PhysicalPriority); 934 return GetAllEnabledInterrupts(cpu).Where(filter); 935 } 936 GetAllPendingCandidateVirtualInterrupts(CPUEntry cpu)937 private IEnumerable<VirtualInterrupt> GetAllPendingCandidateVirtualInterrupts(CPUEntry cpu) 938 { 939 var enabledGroups = groups.Keys.Where(type => cpu.Groups.Virtual[type].Enabled).ToArray(); 940 var filter = InterruptPriorityFilter(cpu.VirtualPriorityMask, cpu.RunningInterrupts.VirtualPriority); 941 return cpu 942 .VirtualInterrupts 943 .Where(irq => enabledGroups.Contains(irq.Config.GroupType) && filter(irq)); 944 } 945 BuildDistributorDoubleWordRegistersMap()946 private Dictionary<long, DoubleWordRegister> BuildDistributorDoubleWordRegistersMap() 947 { 948 var registersMap = new Dictionary<long, DoubleWordRegister> 949 { 950 {(long)DistributorRegisters.ControllerType, new DoubleWordRegister(this) 951 .WithValueField(27, 5, name: "SharedPeripheralInterruptsExtendedCount", 952 valueProviderCallback: _ => irqsDecoder.SharedPeripheralExtendedCount / 32 - 1 953 ) 954 .WithFlag(26, name: "AffinityLevel0RangeSupport", 955 valueProviderCallback: _ => false 956 ) 957 .WithFlag(25, name: "1OfNSharedPeripheralInterruptsSupport", 958 valueProviderCallback: _ => false 959 ) 960 .WithFlag(24, name: "AffinityLevel3Support", 961 valueProviderCallback: _ => false 962 ) 963 .WithValueField(19, 5, name: "SupportedInterruptIdentifierBits", 964 valueProviderCallback: _ => irqsDecoder.IdentifierBits - 1 965 ) 966 .WithFlag(18, name: "DirectVirtualLocalitySpecificPeripheralInterruptInjectionSupport", 967 valueProviderCallback: _ => false 968 ) 969 .WithFlag(17, name: "LocalitySpecificPeripheralInterruptSupport", 970 valueProviderCallback: _ => false 971 ) 972 .WithFlag(16, name: "MessageBasedInterruptActivationByWriteSupport", 973 valueProviderCallback: _ => false 974 ) 975 .WithReservedBits(11, 5) // Indicates the lack of the Locality-specific Peripheral Interrupt support 976 .WithFlag(10, name: "SecurityStateSupport", 977 valueProviderCallback: _ => !DisabledSecurity 978 ) 979 .WithFlag(9, name: "NonMaskableInterruptSupport", 980 valueProviderCallback: _ => false 981 ) 982 .WithFlag(8, name: "SharedPeripheralInterruptsExtendedSupport", 983 valueProviderCallback: _ => false 984 ) 985 .WithValueField(5, 3, name: "LegacyCpusCount", 986 valueProviderCallback: _ => (ulong)BitHelper.GetSetBits(legacyCpusAttachedMask).Count - 1 987 ) 988 .WithValueField(0, 5, name: "SharedPeripheralInterruptsCount", 989 valueProviderCallback: _ => ((uint)irqsDecoder.SharedPeripheralLast + 1) / 32 - 1 990 ) 991 }, 992 {(long)DistributorRegisters.ImplementerIdentification, new DoubleWordRegister(this) 993 .WithValueField(24, 8, FieldMode.Read, valueProviderCallback: _ => DistributorProductIdentifier, name: "ProductIdentifier") 994 .WithReservedBits(20, 4) 995 .WithValueField(16, 4, FieldMode.Read, valueProviderCallback: _ => DistributorVariant, name: "VariantNumber") 996 .WithValueField(12, 4, FieldMode.Read, valueProviderCallback: _ => DistributorRevision, name: "RevisionNumber") 997 .WithValueField(0, 12, FieldMode.Read, valueProviderCallback: _ => DistributorImplementer, name: "ImplementerIdentification") 998 }, 999 {(long)DistributorRegisters.SoftwareGeneratedInterruptControl, new DoubleWordRegister(this) 1000 .WithReservedBits(26, 6) 1001 .WithEnumField<DoubleWordRegister, SoftwareGeneratedInterruptRequest.TargetType>(24, 2, out var type, FieldMode.Write, name: "TargetListFilter") 1002 .WithValueField(16, 8, out var targetList, FieldMode.Write, name: "TargetsList") 1003 .WithFlag(15, out var group, FieldMode.Write, name: "GroupFilterSecureAccess") 1004 .WithReservedBits(4, 10) 1005 .WithValueField(0, 4, out var id, FieldMode.Write, name: "SoftwareGeneratedInterruptIdentifier") 1006 .WithWriteCallback((_, __) => 1007 { 1008 var list = new Affinity[]{}; 1009 if(type.Value == SoftwareGeneratedInterruptRequest.TargetType.TargetList) 1010 { 1011 list = BitHelper.GetSetBits(targetList.Value).Select(n => new Affinity((byte)n)).ToArray(); 1012 } 1013 var interrupt = new SoftwareGeneratedInterruptRequest(type.Value, list, group.Value ? GroupType.Group1 : GroupType.Group0, new InterruptId((uint)id.Value)); 1014 OnSoftwareGeneratedInterrupt(GetAskingCPUEntry(), interrupt); 1015 }) 1016 }, 1017 {PeripheralIdentificationOffset, new DoubleWordRegister(this) 1018 .WithReservedBits(8, 24) 1019 .WithEnumField<DoubleWordRegister, ARM_GenericInterruptControllerVersion>(4, 4, FieldMode.Read, name: "ArchitectureVersion", 1020 valueProviderCallback: _ => ArchitectureVersion 1021 ) 1022 .WithTag("ImplementationDefinedIdentificator", 0, 4) 1023 } 1024 }; 1025 1026 // All BuildInterrupt*Registers methods create registers with respect for Security State 1027 // There is no separate view (RegistersCollection) for this kind of registers, because their layout are independent of Security State 1028 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptSetEnable_0, 1029 BuildInterruptSetEnableRegisters(irqsDecoder.SoftwareGeneratedFirst, irqsDecoder.SharedPeripheralLast, "InterruptSetEnable") 1030 ); 1031 1032 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptClearEnable_0, 1033 BuildInterruptClearEnableRegisters(irqsDecoder.SoftwareGeneratedFirst, irqsDecoder.SharedPeripheralLast, "InterruptClearEnable") 1034 ); 1035 1036 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptPriority_0, 1037 BuildInterruptPriorityRegisters(irqsDecoder.SoftwareGeneratedFirst, irqsDecoder.SharedPeripheralLast, "InterruptPriority") 1038 ); 1039 1040 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptProcessorTargets_0, 1041 BuildPrivateInterruptTargetsRegisters(irqsDecoder.SoftwareGeneratedFirst, irqsDecoder.PrivatePeripheralLast, "InterruptProcessorTargets") 1042 ); 1043 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptProcessorTargets_8, 1044 BuildSharedInterruptTargetsRegisters(irqsDecoder.SharedPeripheralFirst, irqsDecoder.SharedPeripheralLast, "InterruptProcessorTargets") 1045 ); 1046 1047 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptConfiguration_0, 1048 BuildInterruptConfigurationRegisters(irqsDecoder.SoftwareGeneratedFirst, irqsDecoder.SoftwareGeneratedLast, "InterruptConfiguration", isReadonly: true) 1049 ); 1050 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptConfiguration_1, 1051 BuildInterruptConfigurationRegisters(irqsDecoder.PrivatePeripheralFirst, irqsDecoder.SharedPeripheralLast, "InterruptConfiguration") 1052 ); 1053 1054 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptSetActive_0, 1055 BuildInterruptSetActiveRegisters(irqsDecoder.SoftwareGeneratedFirst, irqsDecoder.SharedPeripheralLast, "InterruptSetActive") 1056 ); 1057 1058 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptClearActive_0, 1059 BuildInterruptClearActiveRegisters(irqsDecoder.SoftwareGeneratedFirst, irqsDecoder.SharedPeripheralLast, "InterruptClearActive") 1060 ); 1061 1062 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptSetPending_0, 1063 BuildInterruptSetPendingRegisters(irqsDecoder.SoftwareGeneratedFirst, irqsDecoder.SharedPeripheralLast, "InterruptSetPending") 1064 ); 1065 1066 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptClearPending_0, 1067 BuildInterruptClearPendingRegisters(irqsDecoder.SoftwareGeneratedFirst, irqsDecoder.SharedPeripheralLast, "InterruptClearPending") 1068 ); 1069 1070 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptGroup_0, 1071 BuildInterruptGroupRegisters(irqsDecoder.SoftwareGeneratedFirst, irqsDecoder.SharedPeripheralLast, "InterruptGroup") 1072 ); 1073 1074 // The range between 0xD00-0xDFC is implementation defined for GICv1 and GICv2. 1075 if(ArchitectureVersionAtLeast3) 1076 { 1077 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptGroupModifier_0_PPIStatus, 1078 BuildInterruptGroupModifierRegisters(irqsDecoder.SoftwareGeneratedFirst, irqsDecoder.SharedPeripheralLast, "InterruptGroupModifier") 1079 ); 1080 } 1081 else 1082 { 1083 // See e.g. https://developer.arm.com/documentation/ddi0416/b/programmers-model/distributor-register-descriptions and https://developer.arm.com/documentation/ddi0471/b/programmers-model/distributor-register-summary 1084 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptGroupModifier_0_PPIStatus, 1085 BuildPrivateOrSharedPeripheralInterruptStatusRegisters(irqsDecoder.PrivatePeripheralFirst, irqsDecoder.PrivatePeripheralLast, "PPI Status") 1086 ); 1087 1088 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptGroupModifier_1_SPIStatus_0, 1089 BuildPrivateOrSharedPeripheralInterruptStatusRegisters(irqsDecoder.SharedPeripheralFirst, irqsDecoder.SharedPeripheralLast, "SPI Status") 1090 ); 1091 } 1092 1093 return registersMap; 1094 } 1095 BuildDistributorQuadWordRegistersMap()1096 private Dictionary<long, QuadWordRegister> BuildDistributorQuadWordRegistersMap() 1097 { 1098 var registersMap = new Dictionary<long, QuadWordRegister>(); 1099 Utils.AddRegistersAtOffset(registersMap, (long)DistributorRegisters.InterruptRouting_0, 1100 BuildInterruptRoutingRegisters(irqsDecoder.SharedPeripheralFirst, irqsDecoder.SharedPeripheralLast) 1101 ); 1102 return registersMap; 1103 } 1104 BuildDistributorRegistersMapSecurityView(bool accessForDisabledSecurity, SecurityState? securityStateAccess = null)1105 private Dictionary<long, DoubleWordRegister> BuildDistributorRegistersMapSecurityView(bool accessForDisabledSecurity, SecurityState? securityStateAccess = null) 1106 { 1107 var controlRegister = new DoubleWordRegister(this) 1108 .WithFlag(31, FieldMode.Read, name: "RegisterWritePending", valueProviderCallback: _ => false); 1109 var registersMap = new Dictionary<long, DoubleWordRegister> 1110 { 1111 {(long)DistributorRegisters.Control, controlRegister} 1112 }; 1113 1114 if(accessForDisabledSecurity) 1115 { 1116 controlRegister 1117 .WithReservedBits(9, 22) 1118 .WithTaggedFlag("nASSGIreq", 8) // Requires FEAT_GICv4p1 support 1119 .WithFlag(7, FieldMode.Read, name: "Enable1ofNWakeup", valueProviderCallback: _ => false) // There is no support for waking up 1120 .WithFlag(6, FieldMode.Read, name: "DisableSecurity", valueProviderCallback: _ => true) 1121 .WithReservedBits(5, 1) 1122 .WithFlag(4, name: "EnableAffinityRouting", 1123 writeCallback: (_, value) => AffinityRoutingEnabledSecure = value, 1124 valueProviderCallback: _ => AffinityRoutingEnabledSecure 1125 ) 1126 .WithReservedBits(2, 2) 1127 .WithFlag(1, name: "EnableGroup1", 1128 writeCallback: (_, val) => groups[GroupType.Group1].Enabled = val, 1129 valueProviderCallback: _ => groups[GroupType.Group1].Enabled 1130 ) 1131 .WithFlag(0, name: "EnableGroup0", 1132 writeCallback: (_, val) => groups[GroupType.Group0].Enabled = val, 1133 valueProviderCallback: _ => groups[GroupType.Group0].Enabled 1134 ); 1135 } 1136 else if(securityStateAccess == SecurityState.Secure) 1137 { 1138 controlRegister 1139 .WithReservedBits(8, 23) 1140 .WithFlag(7, FieldMode.Read, name: "Enable1ofNWakeUp", valueProviderCallback: _ => false) // There is no support for waking up 1141 .WithFlag(6, name: "DisableSecurity", 1142 writeCallback: (_, val) => DisabledSecurity = val, 1143 valueProviderCallback: _ => DisabledSecurity 1144 ) 1145 .WithFlag(5, name: "EnableAffinityRoutingNonSecure", 1146 writeCallback: (_, value) => AffinityRoutingEnabledNonSecure = value, 1147 valueProviderCallback: _ => AffinityRoutingEnabledNonSecure 1148 ) 1149 .WithFlag(4, name: "EnableAffinityRoutingSecure", 1150 writeCallback: (_, value) => AffinityRoutingEnabledSecure = value, 1151 valueProviderCallback: _ => AffinityRoutingEnabledSecure 1152 ) 1153 .WithReservedBits(3, 1) 1154 .WithFlag(2, name: "EnableGroup1Secure", 1155 writeCallback: (_, val) => groups[GroupType.Group1Secure].Enabled = val, 1156 valueProviderCallback: _ => groups[GroupType.Group1Secure].Enabled 1157 ) 1158 .WithFlag(1, name: "EnableGroup1NonSecure", 1159 writeCallback: (_, val) => groups[GroupType.Group1NonSecure].Enabled = val, 1160 valueProviderCallback: _ => groups[GroupType.Group1NonSecure].Enabled 1161 ) 1162 .WithFlag(0, name: "EnableGroup0", 1163 writeCallback: (_, val) => groups[GroupType.Group0].Enabled = val, 1164 valueProviderCallback: _ => groups[GroupType.Group0].Enabled 1165 ); 1166 registersMap.Add((long)DistributorRegisters.NonSecureAccessControl_0, new DoubleWordRegister(this) 1167 .WithEnumFields<DoubleWordRegister, NonSecureAccess>(0, 2, 16, name: "NS_access", 1168 writeCallback: (i, _, val) => 1169 { 1170 var cpu = GetAskingCPUEntry(); 1171 if(IsAffinityRoutingEnabled(cpu)) 1172 { 1173 cpu.NonSecureSGIAccess[i] = val; 1174 } 1175 }, 1176 valueProviderCallback: (i, _) => 1177 { 1178 var cpu = GetAskingCPUEntry(); 1179 return IsAffinityRoutingEnabled(cpu) ? (NonSecureAccess)0 : cpu.NonSecureSGIAccess[i]; 1180 } 1181 ) 1182 // Those could be emitted in valueProvider/writeCallback instead, 1183 // but we don't want to emit the same warning 16 times per access. 1184 .WithWriteCallback((_, __) => 1185 { 1186 var cpu = GetAskingCPUEntry(); 1187 if(IsAffinityRoutingEnabled(cpu)) 1188 { 1189 this.Log(LogLevel.Warning, "Tried to write to GICD_NSACR0 when affinity routing is enabled. Access ignored, use GICR_NSACR instead."); 1190 } 1191 }) 1192 .WithReadCallback((_, __) => 1193 { 1194 var cpu = GetAskingCPUEntry(); 1195 if(IsAffinityRoutingEnabled(cpu)) 1196 { 1197 this.Log(LogLevel.Warning, "Tried to read from GICD_NSACR0 when affinity routing is enabled. Access ignored, use GICR_NSACR instead."); 1198 } 1199 }) 1200 ); 1201 // These registers do not support PPIs, therefore GICD_NSACR1 is RAZ/WI 1202 registersMap.Add((long)DistributorRegisters.NonSecureAccessControl_0 + 4, new DoubleWordRegister(this) 1203 .WithValueFields(0, 2, 16, FieldMode.Read, name: "NS_access", valueProviderCallback: (_, __) => 0) 1204 ); 1205 for(var j = 2; j < 64; ++j) 1206 { 1207 var i = j; 1208 registersMap.Add((long)DistributorRegisters.NonSecureAccessControl_0 + 4 * i, new DoubleWordRegister(this) 1209 .WithValueFields(0, 2, 16, name: "NS_access", valueProviderCallback: (_, __) => 0) 1210 .WithReadCallback((_, __) => this.Log(LogLevel.Warning, "GICD_NSACR{0} is not implemented yet", i)) 1211 .WithWriteCallback((_, __) => this.Log(LogLevel.Warning, "GICD_NSACR{0} is not implemented yet", i)) 1212 ); 1213 } 1214 } 1215 else 1216 { 1217 controlRegister 1218 .WithReservedBits(5, 26) 1219 .WithFlag(4, name: "EnableAffinityRoutingNonSecure", 1220 writeCallback: (_, value) => AffinityRoutingEnabledNonSecure = value, 1221 valueProviderCallback: _ => AffinityRoutingEnabledNonSecure 1222 ) 1223 .WithReservedBits(2, 2) 1224 .WithFlag(1, name: "EnableGroup1NonSecureAlias", 1225 writeCallback: (_, val) => groups[GroupType.Group1NonSecure].Enabled = val, 1226 valueProviderCallback: _ => groups[GroupType.Group1NonSecure].Enabled 1227 ) 1228 .WithFlag(0, name: "EnableGroup1NonSecureAlias", 1229 writeCallback: (_, val) => groups[GroupType.Group1NonSecure].Enabled = val, 1230 valueProviderCallback: _ => groups[GroupType.Group1NonSecure].Enabled 1231 ); 1232 } 1233 1234 return registersMap; 1235 } 1236 BuildCPUInterfaceSystemRegistersMap()1237 private Dictionary<long, QuadWordRegister> BuildCPUInterfaceSystemRegistersMap() 1238 { 1239 var registersMap = new Dictionary<long, QuadWordRegister> 1240 { 1241 {(long)CPUInterfaceSystemRegisters.SystemRegisterEnableEL3, new QuadWordRegister(this) 1242 .WithReservedBits(4, 60) 1243 .WithFlag(3, FieldMode.Read, name: "EnableAccessOnLowerThanEL3", valueProviderCallback: _ => true) 1244 .WithFlag(2, FieldMode.Read, name: "DisableIRQBypass", valueProviderCallback: _ => true) 1245 .WithFlag(1, FieldMode.Read, name: "DisableFIQBypass", valueProviderCallback: _ => true) 1246 .WithFlag(0, FieldMode.Read, name: "EnableSystemRegisterAccess", valueProviderCallback: _ => true) 1247 }, 1248 {(long)CPUInterfaceSystemRegisters.SystemRegisterEnableEL2, new QuadWordRegister(this) 1249 .WithReservedBits(4, 60) 1250 .WithFlag(3, FieldMode.Read, name: "EnableAccessOnLowerThanEL2", valueProviderCallback: _ => true) 1251 .WithFlag(2, FieldMode.Read, name: "DisableIRQBypass", valueProviderCallback: _ => true) 1252 .WithFlag(1, FieldMode.Read, name: "DisableFIQBypass", valueProviderCallback: _ => true) 1253 .WithFlag(0, FieldMode.Read, name: "EnableSystemRegisterAccess", valueProviderCallback: _ => true) 1254 }, 1255 {(long)CPUInterfaceSystemRegisters.SystemRegisterEnableEL1, new QuadWordRegister(this) 1256 .WithReservedBits(3, 61) 1257 .WithFlag(2, FieldMode.Read, name: "DisableIRQBypass", valueProviderCallback: _ => true) 1258 .WithFlag(1, FieldMode.Read, name: "DisableFIQBypass", valueProviderCallback: _ => true) 1259 .WithFlag(0, FieldMode.Read, name: "EnableSystemRegisterAccess", valueProviderCallback: _ => true) 1260 }, 1261 {(long)CPUInterfaceSystemRegisters.GroupEnable0, new QuadWordRegister(this) 1262 .WithReservedBits(1, 63) 1263 .WithFlag(0, name: "EnableGroup0", 1264 valueProviderCallback: _ => GetAskingCPUEntry().Groups[GroupType.Group0].Enabled, 1265 writeCallback: (_, val) => GetAskingCPUEntry().Groups[GroupType.Group0].Enabled = val 1266 ) 1267 }, 1268 {(long)CPUInterfaceSystemRegisters.GroupEnable1, new QuadWordRegister(this) 1269 .WithReservedBits(1, 63) 1270 .WithFlag(0, name: "EnableGroup1", 1271 valueProviderCallback: _ => GetAskingCPUEntry().GetGroupForRegisterSecurityAgnostic(GroupTypeSecurityAgnostic.Group1).Enabled, 1272 writeCallback: (_, val) => GetAskingCPUEntry().GetGroupForRegisterSecurityAgnostic(GroupTypeSecurityAgnostic.Group1).Enabled = val 1273 ) 1274 }, 1275 {(long)CPUInterfaceSystemRegisters.GroupEnable1EL3, new QuadWordRegister(this) 1276 .WithReservedBits(2, 62) 1277 .WithFlag(1, name: "EnableGroup1S", 1278 valueProviderCallback: _ => GetAskingCPUEntry().Groups[GroupType.Group1Secure].Enabled, 1279 writeCallback: (_, val) => GetAskingCPUEntry().Groups[GroupType.Group1Secure].Enabled = val 1280 ) 1281 .WithFlag(0, name: "EnableGroup1NS", 1282 valueProviderCallback: _ => GetAskingCPUEntry().Groups[GroupType.Group1NonSecure].Enabled, 1283 writeCallback: (_, val) => GetAskingCPUEntry().Groups[GroupType.Group1NonSecure].Enabled = val 1284 ) 1285 }, 1286 {(long)CPUInterfaceSystemRegisters.RunningPriority, new QuadWordRegister(this) 1287 .WithTaggedFlag("PriorityFromNonMaskableInterrupt", 63) // Requires FEAT_GICv3_NMI extension 1288 .WithTaggedFlag("PriorityFromNonSecureNonMaskableInterrupt", 62) // Requires FEAT_GICv3_NMI extension 1289 .WithReservedBits(8, 54) 1290 .WithEnumField<QuadWordRegister, InterruptPriority>(0, 8, FieldMode.Read, name: "RunningPriority", 1291 valueProviderCallback: _ => GetAskingCPUEntry().RunningInterrupts.Priority 1292 ) 1293 }, 1294 {(long)CPUInterfaceSystemRegisters.PriorityMask, new QuadWordRegister(this) 1295 .WithReservedBits(8, 56) 1296 .WithEnumField<QuadWordRegister, InterruptPriority>(0, 8, name: "PriorityMask", 1297 writeCallback: (_, val) => GetAskingCPUEntry().PriorityMask = val, 1298 valueProviderCallback: _ => GetAskingCPUEntry().PriorityMask 1299 ) 1300 }, 1301 {(long)CPUInterfaceSystemRegisters.InterruptAcknowledgeGroup0, 1302 BuildInterruptAcknowledgeRegister(new QuadWordRegister(this), 64, "InterruptAcknowledgeGroup0", () => GroupTypeSecurityAgnostic.Group0, false) 1303 }, 1304 {(long)CPUInterfaceSystemRegisters.InterruptAcknowledgeGroup1, 1305 BuildInterruptAcknowledgeRegister(new QuadWordRegister(this), 64, "InterruptAcknowledgeGroup1", () => GroupTypeSecurityAgnostic.Group1, false) 1306 }, 1307 {(long)CPUInterfaceSystemRegisters.InterruptDeactivate, 1308 BuildInterruptDeactivateOrInterruptEndRegister(new QuadWordRegister(this), 64, "InterruptDeactivate", null, 1309 useCPUIdentifier: false, isDeactivateRegister: true) 1310 }, 1311 {(long)CPUInterfaceSystemRegisters.InterruptEndGroup0, 1312 BuildInterruptDeactivateOrInterruptEndRegister(new QuadWordRegister(this), 64, "InterruptEndGroup0", () => GroupTypeSecurityAgnostic.Group0, 1313 useCPUIdentifier: false, isDeactivateRegister: false) 1314 }, 1315 {(long)CPUInterfaceSystemRegisters.InterruptEndGroup1, 1316 BuildInterruptDeactivateOrInterruptEndRegister(new QuadWordRegister(this), 64, "InterruptEndGroup1", () => GroupTypeSecurityAgnostic.Group1, 1317 useCPUIdentifier: false, isDeactivateRegister: false) 1318 }, 1319 {(long)CPUInterfaceSystemRegisters.ControlEL1, new QuadWordRegister(this) 1320 .WithReservedBits(20, 44) 1321 .WithTaggedFlag("ExtendedINTIDRange", 19) 1322 .WithTaggedFlag("RangeSelectorSupport", 18) 1323 .WithReservedBits(16, 2) 1324 .WithTaggedFlag("Affinity3Valid", 15) 1325 .WithTaggedFlag("SEISupport", 14) 1326 .WithTag("Identifier bits", 11, 3) 1327 .WithTag("PriorityBits", 8, 3) 1328 .WithReservedBits(7, 1) 1329 .WithTaggedFlag("PriorityMaskHintEnable", 6) 1330 .WithReservedBits(2, 4) 1331 .WithFlag(1, name: "EndOfInterruptMode", 1332 writeCallback: (_, val) => GetAskingCPUEntry().EndOfInterruptModeEL1 = (EndOfInterruptModes)(val ? 1 : 0), 1333 valueProviderCallback: _ => GetAskingCPUEntry().EndOfInterruptModeEL1 == EndOfInterruptModes.PriorityDropOnly 1334 ) 1335 .WithTaggedFlag("CommonBinaryPointRegister", 0) 1336 }, 1337 {(long)CPUInterfaceSystemRegisters.ControlEL3, new QuadWordRegister(this) 1338 .WithReservedBits(20, 44) 1339 .WithTaggedFlag("ExtendedINTIDRange", 19) 1340 .WithTaggedFlag("RangeSelectorSupport", 18) 1341 .WithTaggedFlag("DisableSecurityNotSupported", 17) 1342 .WithReservedBits(16, 1) 1343 .WithTaggedFlag("Affinity3Valid", 15) 1344 .WithTaggedFlag("SEISupport", 14) 1345 .WithTag("Identifier bits", 11, 3) 1346 .WithTag("PriorityBits", 8, 3) 1347 .WithReservedBits(7, 1) 1348 .WithTaggedFlag("PriorityMaskHintEnable", 6) 1349 .WithTaggedFlag("RoutingModifier", 5) 1350 .WithFlag(4, name: "EndOfInterruptModeEL1NonSecure", 1351 writeCallback: (_, val) => GetAskingCPUEntry().EndOfInterruptModeEL1NonSecure = (EndOfInterruptModes)(val ? 1 : 0), 1352 valueProviderCallback: _ => GetAskingCPUEntry().EndOfInterruptModeEL1NonSecure == EndOfInterruptModes.PriorityDropOnly 1353 ) 1354 .WithFlag(3, name: "EndOfInterruptModeEL1Secure", 1355 writeCallback: (_, val) => GetAskingCPUEntry().EndOfInterruptModeEL1Secure = (EndOfInterruptModes)(val ? 1 : 0), 1356 valueProviderCallback: _ => GetAskingCPUEntry().EndOfInterruptModeEL1Secure == EndOfInterruptModes.PriorityDropOnly 1357 ) 1358 .WithFlag(2, name: "EndOfInterruptModeEL3", 1359 writeCallback: (_, val) => GetAskingCPUEntryWithTwoSecurityStates().EndOfInterruptModeEL3 = (EndOfInterruptModes)(val ? 1 : 0), 1360 valueProviderCallback: _ => GetAskingCPUEntryWithTwoSecurityStates().EndOfInterruptModeEL3 == EndOfInterruptModes.PriorityDropOnly 1361 ) 1362 .WithTaggedFlag("CommonBinaryPointRegisterEL1NonSecure", 1) 1363 .WithTaggedFlag("CommonBinaryPointRegisterEL1Secure", 0) 1364 }, 1365 {(long)CPUInterfaceSystemRegisters.HypControl, new QuadWordRegister(this) 1366 .WithReservedBits(32, 32) 1367 .WithValueField(27, 5, FieldMode.Read, name: "EOIcount", 1368 valueProviderCallback: _ => GetAskingCPUEntry().EOICount 1369 ) 1370 .WithReservedBits(16, 11) 1371 .WithTaggedFlag("DVIM", 15) // Reserved when ICH_VTR_EL2.DVIM = 0 1372 .WithTaggedFlag("TDIR", 14) // Reserved when FEAT_GICv3_TDIR is not implemented 1373 .WithTaggedFlag("TSEI", 13) 1374 .WithTaggedFlag("TALL1", 12) 1375 .WithTaggedFlag("TALL0", 11) 1376 .WithTaggedFlag("TC", 10) 1377 .WithReservedBits(9, 1) 1378 .WithTaggedFlag("vSGIEOICount", 8) // Reserved when FEAT_GICv4p1 is not implemented 1379 .WithTaggedFlag("VGrp0DIE", 7) 1380 .WithTaggedFlag("VGrp1EIE", 6) 1381 .WithTaggedFlag("VGrp0DIE", 5) 1382 .WithTaggedFlag("VGrp0EIE", 4) 1383 .WithTaggedFlag("NPIE", 3) 1384 .WithTaggedFlag("LRENPIE", 2) 1385 .WithTaggedFlag("UIE", 1) 1386 .WithFlag(0, name: "En", 1387 valueProviderCallback: _ => GetAskingCPUEntry().VirtualCPUInterfaceEnabled, 1388 writeCallback: (_, val) => GetAskingCPUEntry().VirtualCPUInterfaceEnabled = val 1389 ) 1390 }, 1391 {(long)CPUInterfaceSystemRegisters.VGICType, new QuadWordRegister(this) 1392 .WithReservedBits(32, 32) 1393 .WithValueField(29, 3, FieldMode.Read, name: "PRIbits", 1394 valueProviderCallback: _ => VirtualPriorityBits - 1 1395 ) 1396 .WithTag("PREbits", 26, 3) 1397 .WithTag("IDbits", 23, 3) 1398 .WithTaggedFlag("SEIS", 22) 1399 .WithTaggedFlag("A3V", 21) 1400 .WithTaggedFlag("nV4", 20) 1401 .WithTaggedFlag("TDS", 19) 1402 .WithTaggedFlag("DVIM", 18) 1403 .WithReservedBits(5, 13) 1404 .WithValueField(0, 5, FieldMode.Read, name: "ListRegs", 1405 valueProviderCallback: _ => VirtualInterruptCount - 1 1406 ) 1407 }, 1408 {(long)CPUInterfaceSystemRegisters.VMControl, new QuadWordRegister(this) 1409 .WithReservedBits(32, 32) 1410 .WithEnumField<QuadWordRegister, InterruptPriority>(24, 8, name: "VPMR", 1411 valueProviderCallback: _ => GetAskingCPUEntry().VirtualPriorityMask, 1412 writeCallback: (_, val) => GetAskingCPUEntry().VirtualPriorityMask = val 1413 ) 1414 .WithTag("VBPR0", 21, 3) 1415 .WithTag("VBPR1", 18, 3) 1416 .WithEnumField<QuadWordRegister, EndOfInterruptModes>(9, 1, name: "VEOIM", 1417 valueProviderCallback: _ => GetAskingCPUEntry().EndOfInterruptModeVirtual, 1418 writeCallback: (_, val) => GetAskingCPUEntry().EndOfInterruptModeVirtual = val 1419 ) 1420 .WithReservedBits(5, 4) 1421 .WithTaggedFlag("VCBPR", 4) 1422 .WithFlag(3, name: "VFIQEn", 1423 valueProviderCallback: _ => GetAskingCPUEntry().VirtualFIQEnabled, 1424 writeCallback: (_, val) => GetAskingCPUEntry().VirtualFIQEnabled = val 1425 ) 1426 .WithTaggedFlag("VAckCtl", 2) 1427 .WithFlag(1, name: "VENG1", 1428 valueProviderCallback: _ => GetAskingCPUEntry().Groups.Virtual[GroupType.Group1].Enabled, 1429 writeCallback: (_, val) => GetAskingCPUEntry().Groups.Virtual[GroupType.Group1].Enabled = val 1430 ) 1431 .WithFlag(0, name: "VENG0", 1432 valueProviderCallback: _ => GetAskingCPUEntry().Groups.Virtual[GroupType.Group0].Enabled, 1433 writeCallback: (_, val) => GetAskingCPUEntry().Groups.Virtual[GroupType.Group0].Enabled = val 1434 ) 1435 }, 1436 {(long)CPUInterfaceSystemRegisters.SoftwareGeneratedInterruptGroup1Generate, BuildSGIGenerateRegister(() => GetGroup1ForSecurityState(GetAskingCPUEntry().IsStateSecure))}, 1437 {(long)CPUInterfaceSystemRegisters.SoftwareGeneratedInterruptGroup1GenerateAlias, BuildSGIGenerateRegister(() => GetGroup1ForSecurityState(!GetAskingCPUEntry().IsStateSecure))}, 1438 {(long)CPUInterfaceSystemRegisters.SoftwareGeneratedInterruptGroup0Generate, BuildSGIGenerateRegister(() => GroupType.Group0)}, 1439 }; 1440 1441 for(int j = 0; j < VirtualInterruptCount; ++j) 1442 { 1443 var i = j; 1444 1445 Func<VirtualInterrupt> virtualInterrupt = () => GetAskingCPUEntry().VirtualInterrupts[i]; 1446 Action syncInterruptState = () => 1447 { 1448 var currentInterrupt = virtualInterrupt(); 1449 var activeInterrupt = GetAskingCPUEntry().RunningInterrupts.GetActiveVirtual(currentInterrupt.Identifier); 1450 if(activeInterrupt != null) 1451 { 1452 activeInterrupt.Sync(currentInterrupt); 1453 } 1454 }; 1455 1456 registersMap.Add((long)CPUInterfaceSystemRegisters.ListRegister_0 + i, new QuadWordRegister(this) 1457 .WithValueField(62, 2, name: "State", 1458 valueProviderCallback: _ => virtualInterrupt().State.Bits, 1459 writeCallback: (_, val) => virtualInterrupt().State.Bits = val 1460 ) 1461 .WithFlag(61, name: "HW", 1462 valueProviderCallback: _ => virtualInterrupt().Hardware, 1463 writeCallback: (_, val) => virtualInterrupt().Hardware = val 1464 ) 1465 .WithFlag(60, name: "Group", 1466 valueProviderCallback: _ => virtualInterrupt().Config.GroupBit, 1467 writeCallback: (_, val) => virtualInterrupt().Config.GroupBit = val 1468 ) 1469 .WithReservedBits(56, 4) 1470 .WithEnumField<QuadWordRegister, InterruptPriority>(48, 8, name: "Priority", 1471 valueProviderCallback: _ => virtualInterrupt().Config.Priority, 1472 writeCallback: (_, val) => virtualInterrupt().Config.Priority = val 1473 ) 1474 .WithReservedBits(45, 3) 1475 .WithValueField(32, 13, name: "pINTID", 1476 valueProviderCallback: _ => (uint)virtualInterrupt().HardwareIdentifier, 1477 writeCallback: (_, val) => virtualInterrupt().SetHardwareIdentifier((uint)val) 1478 ) 1479 .WithValueField(0, 32, name: "vINTID", 1480 valueProviderCallback: _ => (uint)virtualInterrupt().Identifier, 1481 writeCallback: (_, val) => virtualInterrupt().SetIdentifier((uint)val) 1482 ) 1483 .WithWriteCallback((_, __) => syncInterruptState()) 1484 ); 1485 1486 registersMap.Add((long)CPUInterfaceSystemRegisters.ListRegisterUpper_0 + i, new QuadWordRegister(this) 1487 .WithReservedBits(32, 32) 1488 .WithValueField(30, 2, name: "State", 1489 valueProviderCallback: _ => virtualInterrupt().State.Bits, 1490 writeCallback: (_, val) => virtualInterrupt().State.Bits = val 1491 ) 1492 .WithFlag(29, name: "HW", 1493 valueProviderCallback: _ => virtualInterrupt().Hardware, 1494 writeCallback: (_, val) => virtualInterrupt().Hardware = val 1495 ) 1496 .WithFlag(28, name: "Group", 1497 valueProviderCallback: _ => virtualInterrupt().Config.GroupBit, 1498 writeCallback: (_, val) => virtualInterrupt().Config.GroupBit = val 1499 ) 1500 .WithReservedBits(24, 4) 1501 .WithEnumField<QuadWordRegister, InterruptPriority>(16, 8, name: "Priority", 1502 valueProviderCallback: _ => virtualInterrupt().Config.Priority, 1503 writeCallback: (_, val) => virtualInterrupt().Config.Priority = val 1504 ) 1505 .WithReservedBits(13, 3) 1506 .WithValueField(0, 13, name: "pINTID", 1507 valueProviderCallback: _ => (uint)virtualInterrupt().HardwareIdentifier, 1508 writeCallback: (_, val) => virtualInterrupt().SetHardwareIdentifier((uint)val) 1509 ) 1510 .WithWriteCallback((_, __) => syncInterruptState()) 1511 ); 1512 } 1513 1514 return registersMap; 1515 } 1516 BuildCPUInterfaceRegistersMap()1517 private Dictionary<long, DoubleWordRegister> BuildCPUInterfaceRegistersMap() 1518 { 1519 Func<GroupTypeSecurityAgnostic> getRegisterGroupTypeSecurityAgnostic = () => (DisabledSecurity || GetAskingCPUEntry().IsStateSecure) ? GroupTypeSecurityAgnostic.Group0 : GroupTypeSecurityAgnostic.Group1; 1520 var registersMap = new Dictionary<long, DoubleWordRegister> 1521 { 1522 {(long)CPUInterfaceRegisters.InterfaceIdentification, new DoubleWordRegister(this) 1523 .WithValueField(20, 12, FieldMode.Read, valueProviderCallback: _ => CPUInterfaceProductIdentifier, name: "ProductIdentifier") 1524 .WithEnumField<DoubleWordRegister, ARM_GenericInterruptControllerVersion>(16, 4, FieldMode.Read, valueProviderCallback: _ => ArchitectureVersion, name: "ArchitectureVersion") 1525 .WithValueField(12, 4, FieldMode.Read, valueProviderCallback: _ => CPUInterfaceRevision, name: "RevisionNumber") 1526 .WithValueField(0, 12, FieldMode.Read, valueProviderCallback: _ => CPUInterfaceImplementer, name: "ImplementerIdentification") 1527 }, 1528 {(long)CPUInterfaceRegisters.RunningPriority, new DoubleWordRegister(this) 1529 .WithReservedBits(8, 24) 1530 .WithEnumField<DoubleWordRegister, InterruptPriority>(0, 8, FieldMode.Read, name: "RunningPriority", 1531 valueProviderCallback: _ => GetAskingCPUEntry().RunningInterrupts.Priority 1532 ) 1533 }, 1534 {(long)CPUInterfaceRegisters.PriorityMask, new DoubleWordRegister(this) 1535 .WithReservedBits(8, 24) 1536 .WithEnumField<DoubleWordRegister, InterruptPriority>(0, 8, name: "PriorityMask", 1537 writeCallback: (_, val) => GetAskingCPUEntry().PriorityMask = val, 1538 valueProviderCallback: _ => GetAskingCPUEntry().PriorityMask 1539 ) 1540 }, 1541 {(long)CPUInterfaceRegisters.InterruptAcknowledge, 1542 BuildInterruptAcknowledgeRegister(new DoubleWordRegister(this), 32, "InterruptAcknowledge", getRegisterGroupTypeSecurityAgnostic, true) 1543 }, 1544 {(long)CPUInterfaceRegisters.InterruptEnd, 1545 BuildInterruptDeactivateOrInterruptEndRegister(new DoubleWordRegister(this), 32, "InterruptEnd", getRegisterGroupTypeSecurityAgnostic, 1546 useCPUIdentifier: true, isDeactivateRegister: false) 1547 }, 1548 {(long)CPUInterfaceRegisters.InterruptDeactivate, 1549 BuildInterruptDeactivateOrInterruptEndRegister(new DoubleWordRegister(this), 32, "InterruptDeactivate", null, 1550 useCPUIdentifier: true, isDeactivateRegister: true) 1551 }, 1552 }; 1553 1554 return registersMap; 1555 } 1556 BuildCPUInterfaceRegistersMapSecurityView(bool accessForDisabledSecurity, SecurityState? securityStateAccess = null)1557 private Dictionary<long, DoubleWordRegister> BuildCPUInterfaceRegistersMapSecurityView(bool accessForDisabledSecurity, SecurityState? securityStateAccess = null) 1558 { 1559 var controlRegister = new DoubleWordRegister(this); 1560 if(accessForDisabledSecurity || securityStateAccess == SecurityState.Secure) 1561 { 1562 controlRegister 1563 .WithFlag(8, FieldMode.Read, name: "IRQBypassGroup1", valueProviderCallback: _ => false) 1564 .WithFlag(7, FieldMode.Read, name: "FIQBypassGroup1", valueProviderCallback: _ => false) 1565 .WithFlag(6, FieldMode.Read, name: "IRQBypassGroup0", valueProviderCallback: _ => false) 1566 .WithFlag(5, FieldMode.Read, name: "FIQBypassGroup0", valueProviderCallback: _ => false) 1567 .WithTaggedFlag("PreemptionControl", 4) 1568 .WithFlag(3, name: "EnableFIQ", 1569 writeCallback: (_, val) => 1570 { 1571 if(!ArchitectureVersionAtLeast3) 1572 { 1573 enableFIQ = val; 1574 } 1575 else 1576 { 1577 this.Log(LogLevel.Warning, "Modifying EnableFIQ flag is not supported in this architecture version"); 1578 } 1579 }, 1580 valueProviderCallback: _ => enableFIQ 1581 ) 1582 .WithFlag(2, name: "AcknowledgementControl", 1583 writeCallback: (_, val) => { if(val) this.Log(LogLevel.Warning, "Setting deprecated GICC_CTLR.AckCtl flag!"); ackControl = val; }, 1584 valueProviderCallback: _ => ackControl 1585 ) 1586 .WithFlag(1, name: "EnableGroup1", 1587 writeCallback: (_, val) => GetAskingCPUEntry().Groups[GroupType.Group1].Enabled = val, 1588 valueProviderCallback: _ => GetAskingCPUEntry().Groups[GroupType.Group1].Enabled 1589 ) 1590 .WithFlag(0, name: "EnableGroup0", 1591 writeCallback: (_, val) => GetAskingCPUEntry().Groups[GroupType.Group0].Enabled = val, 1592 valueProviderCallback: _ => GetAskingCPUEntry().Groups[GroupType.Group0].Enabled 1593 ); 1594 1595 if(accessForDisabledSecurity) 1596 { 1597 controlRegister 1598 .WithReservedBits(10, 22) 1599 .WithFlag(9, name: "EndOfInterruptMode", 1600 writeCallback: (_, val) => GetAskingCPUEntry().EndOfInterruptModeEL1 = (EndOfInterruptModes)(val ? 1 : 0), 1601 valueProviderCallback: _ => GetAskingCPUEntry().EndOfInterruptModeEL1 == EndOfInterruptModes.PriorityDropOnly 1602 ); 1603 } 1604 else 1605 { 1606 controlRegister 1607 .WithReservedBits(11, 21) 1608 .WithFlag(10, name: "EndOfInterruptModeNonSecure", 1609 writeCallback: (_, val) => GetAskingCPUEntry().EndOfInterruptModeEL1NonSecure = (EndOfInterruptModes)(val ? 1 : 0), 1610 valueProviderCallback: _ => GetAskingCPUEntry().EndOfInterruptModeEL1NonSecure == EndOfInterruptModes.PriorityDropOnly 1611 ) 1612 .WithFlag(9, name: "EndOfInterruptModeSecure", 1613 writeCallback: (_, val) => GetAskingCPUEntry().EndOfInterruptModeEL1Secure = (EndOfInterruptModes)(val ? 1 : 0), 1614 valueProviderCallback: _ => GetAskingCPUEntry().EndOfInterruptModeEL1Secure == EndOfInterruptModes.PriorityDropOnly 1615 ); 1616 } 1617 } 1618 else 1619 { 1620 controlRegister 1621 .WithReservedBits(10, 22) 1622 .WithFlag(9, name: "EndOfInterruptModeNonSecure", 1623 writeCallback: (_, val) => GetAskingCPUEntry().EndOfInterruptModeEL1NonSecure = (EndOfInterruptModes)(val ? 1 : 0), 1624 valueProviderCallback: _ => GetAskingCPUEntry().EndOfInterruptModeEL1NonSecure == EndOfInterruptModes.PriorityDropOnly 1625 ) 1626 .WithReservedBits(7, 2) 1627 .WithFlag(6, FieldMode.Read, name: "IRQBypassGroup1", valueProviderCallback: _ => false) 1628 .WithFlag(5, FieldMode.Read, name: "FIQBypassGroup1", valueProviderCallback: _ => false) 1629 .WithReservedBits(1, 4) 1630 .WithFlag(0, name: "EnableGroup1", 1631 writeCallback: (_, val) => GetAskingCPUEntry().Groups[GroupType.Group1].Enabled = val, 1632 valueProviderCallback: _ => GetAskingCPUEntry().Groups[GroupType.Group1].Enabled 1633 ); 1634 } 1635 1636 var registersMap = new Dictionary<long, DoubleWordRegister> 1637 { 1638 {(long)CPUInterfaceRegisters.Control, controlRegister}, 1639 1640 // Aliases for acknowledging/ending non-secure interrupts in secure state. 1641 {(long)CPUInterfaceRegisters.InterruptAcknowledgeAlias, 1642 BuildInterruptAcknowledgeRegister(new DoubleWordRegister(this), 32, "InterruptAcknowledgeAlias", () => GroupTypeSecurityAgnostic.Group1, true) 1643 }, 1644 {(long)CPUInterfaceRegisters.InterruptEndAlias, 1645 BuildInterruptDeactivateOrInterruptEndRegister(new DoubleWordRegister(this), 32, "InterruptEndAlias", () => GroupTypeSecurityAgnostic.Group1, 1646 useCPUIdentifier: true, isDeactivateRegister: false) 1647 }, 1648 }; 1649 return registersMap; 1650 } 1651 BuildSGIGenerateRegister(Func<GroupType> getGroupType)1652 private QuadWordRegister BuildSGIGenerateRegister(Func<GroupType> getGroupType) 1653 { 1654 return new QuadWordRegister(this) 1655 .WithReservedBits(56, 8) 1656 .WithValueField(48, 8, out var affinity3, FieldMode.Write, name: "Affinity3") 1657 .WithValueField(44, 4, out var rangeSelector, FieldMode.Write, name: "Range Selector") 1658 .WithReservedBits(41, 3) 1659 .WithFlag(40, out var interruptRoutingMode, FieldMode.Write, name: "Interrupt Routing Mode") 1660 .WithValueField(32, 8, out var affinity2, FieldMode.Write, name: "Affinity2") 1661 .WithReservedBits(28, 4) 1662 .WithValueField(24, 4, out var interruptID, FieldMode.Write, name: "Interrupt ID") 1663 .WithValueField(16, 8, out var affinity1, FieldMode.Write, name: "Affinity1") 1664 .WithReservedBits(5, 11) 1665 .WithValueField(0, 5, out var targetList) 1666 .WithWriteCallback((_, newValue) => 1667 { 1668 var targetType = interruptRoutingMode.Value ? SoftwareGeneratedInterruptRequest.TargetType.AllCPUs : SoftwareGeneratedInterruptRequest.TargetType.TargetList; 1669 1670 var list = new Affinity[]{}; 1671 if(targetType == SoftwareGeneratedInterruptRequest.TargetType.TargetList) 1672 { 1673 var range = 16 * (byte)rangeSelector.Value; 1674 var aff1 = (byte)affinity1.Value; 1675 var aff2 = (byte)affinity2.Value; 1676 var aff3 = (byte)affinity3.Value; 1677 list = BitHelper.GetSetBits(targetList.Value).Select(n => new Affinity((byte)(range + n), aff1, aff2, aff3)).ToArray(); 1678 } 1679 1680 var interrupt = new SoftwareGeneratedInterruptRequest(targetType, list, getGroupType(), new InterruptId((uint)interruptID.Value)); 1681 OnSoftwareGeneratedInterrupt(GetAskingCPUEntry(), interrupt); 1682 }); 1683 } 1684 1685 private T BuildInterruptAcknowledgeRegister<T>(T register, int registerWidth, string name, 1686 Func<GroupTypeSecurityAgnostic> groupTypeRegisterProvider, bool useCPUIdentifier) where T : PeripheralRegister 1687 { 1688 return register 1689 .WithReservedBits(24, registerWidth - 24) 1690 .WithValueField(0, 24, FieldMode.Read, name: name, 1691 valueProviderCallback: _ => 1692 { 1693 var irqId = (uint)GetAskingCPUEntry().AcknowledgeBestPending(groupTypeRegisterProvider(), out var requester); 1694 var cpuId = useCPUIdentifier ? requester?.ProcessorNumber ?? 0 : 0; 1695 return cpuId << 10 | irqId; 1696 } 1697 ); 1698 } 1699 1700 private T BuildInterruptDeactivateOrInterruptEndRegister<T>(T register, int registerWidth, string name, 1701 Func<GroupTypeSecurityAgnostic> groupTypeRegisterProvider, bool useCPUIdentifier, bool isDeactivateRegister) where T : PeripheralRegister 1702 { 1703 return register 1704 .WithReservedBits(24, registerWidth - 24) 1705 .WithValueField(0, 24, FieldMode.Write, name: name, 1706 writeCallback: (_, val) => 1707 { 1708 var irqId = BitHelper.GetValue((uint)val, 0, 10); 1709 CPUEntry cpu = null; 1710 var cpuId = BitHelper.GetValue((uint)val, 10, 3); 1711 if(useCPUIdentifier && !TryGetCPUEntry(cpuId, out cpu)) 1712 { 1713 this.Log(LogLevel.Warning, "Trying to {0} the interrupt ({1}) for the non-existing CPU ({2}), write ignored.", 1714 isDeactivateRegister ? "deactivate" : "end", irqId, cpuId); 1715 return; 1716 } 1717 var askingCPUEntry = GetAskingCPUEntry(); 1718 if(isDeactivateRegister) 1719 { 1720 askingCPUEntry.InterruptDeactivate(new InterruptId(irqId), cpu); 1721 } 1722 else 1723 { 1724 askingCPUEntry.InterruptEnd(new InterruptId(irqId), groupTypeRegisterProvider(), cpu); 1725 } 1726 } 1727 ); 1728 } 1729 BuildInterruptRoutingRegisters(InterruptId startId, InterruptId endId)1730 private IEnumerable<QuadWordRegister> BuildInterruptRoutingRegisters(InterruptId startId, InterruptId endId) 1731 { 1732 return InterruptId.GetRange(startId, endId).Select( 1733 id => new QuadWordRegister(this) 1734 .WithReservedBits(40, 24) 1735 .WithValueField(32, 8, name: $"Affinity3_{(uint)id}", 1736 writeCallback: (_, val) => { if(IsAffinityRoutingEnabled(GetAskingCPUEntry())) sharedInterrupts[id].TargetAffinity.SetLevel(3, (byte)val); }, 1737 valueProviderCallback: _ => IsAffinityRoutingEnabled(GetAskingCPUEntry()) ? (ulong)sharedInterrupts[id].TargetAffinity.GetLevel(3) : 0 1738 ) 1739 .WithEnumField<QuadWordRegister, InterruptRoutingMode>(31, 1, name: $"RoutingMode_{(uint)id}", 1740 writeCallback: (_, val) => { if(IsAffinityRoutingEnabled(GetAskingCPUEntry())) sharedInterrupts[id].RoutingMode = val; }, 1741 valueProviderCallback: _ => IsAffinityRoutingEnabled(GetAskingCPUEntry()) ? sharedInterrupts[id].RoutingMode : default(InterruptRoutingMode) 1742 ) 1743 .WithReservedBits(24, 7) 1744 .WithValueField(16, 8, name: $"Affinity2_{(uint)id}", 1745 writeCallback: (_, val) => { if(IsAffinityRoutingEnabled(GetAskingCPUEntry())) sharedInterrupts[id].TargetAffinity.SetLevel(2, (byte)val); }, 1746 valueProviderCallback: _ => IsAffinityRoutingEnabled(GetAskingCPUEntry()) ? (ulong)sharedInterrupts[id].TargetAffinity.GetLevel(2) : 0 1747 ) 1748 .WithValueField(8, 8, name: $"Affinity1_{(uint)id}", 1749 writeCallback: (_, val) => { if(IsAffinityRoutingEnabled(GetAskingCPUEntry())) sharedInterrupts[id].TargetAffinity.SetLevel(1, (byte)val); }, 1750 valueProviderCallback: _ => IsAffinityRoutingEnabled(GetAskingCPUEntry()) ? (ulong)sharedInterrupts[id].TargetAffinity.GetLevel(1) : 0 1751 ) 1752 .WithValueField(0, 8, name: $"Affinity0_{(uint)id}", 1753 writeCallback: (_, val) => { if(IsAffinityRoutingEnabled(GetAskingCPUEntry())) sharedInterrupts[id].TargetAffinity.SetLevel(0, (byte)val); }, 1754 valueProviderCallback: _ => IsAffinityRoutingEnabled(GetAskingCPUEntry()) ? (ulong)sharedInterrupts[id].TargetAffinity.GetLevel(0) : 0 1755 ) 1756 .WithWriteCallback((_, __) => { if(!IsAffinityRoutingEnabled(GetAskingCPUEntry())) this.Log(LogLevel.Warning, "Trying to write IROUTER register when Affinity Routing is disabled, write ignored."); }) 1757 .WithReadCallback((_, __) => { if(!IsAffinityRoutingEnabled(GetAskingCPUEntry())) this.Log(LogLevel.Warning, "Trying to read IROUTER register when Affinity Routing is disabled."); }) 1758 ); 1759 } 1760 BuildInterruptFlagRegisters(InterruptId startId, InterruptId endId, string name, Action<Interrupt, bool> writeCallback = null, Func<Interrupt, bool> valueProviderCallback = null, bool allowAccessWhenNonSecureGroup = true, CPUEntry sgiRequestingCPU = null, Func<CPUEntry> cpuEntryProvider = null)1761 private IEnumerable<DoubleWordRegister> BuildInterruptFlagRegisters(InterruptId startId, InterruptId endId, string name, 1762 Action<Interrupt, bool> writeCallback = null, Func<Interrupt, bool> valueProviderCallback = null, bool allowAccessWhenNonSecureGroup = true, 1763 CPUEntry sgiRequestingCPU = null, Func<CPUEntry> cpuEntryProvider = null) 1764 { 1765 const int BitsPerRegister = 32; 1766 return BuildInterruptRegisters(startId, endId, BitsPerRegister, 1767 (register, irqGetter, irqId, fieldIndex) => 1768 { 1769 FieldMode fieldMode = 0; 1770 Action<bool, bool> writeCallbackWrapped = null; 1771 if(writeCallback != null) 1772 { 1773 fieldMode |= FieldMode.Write; 1774 writeCallbackWrapped = (_, val) => { if(CheckInterruptAccess(irqGetter, allowAccessWhenNonSecureGroup)) writeCallback(irqGetter(), val); }; 1775 } 1776 Func<bool, bool> valueProviderCallbackWrapped = null; 1777 if(valueProviderCallback != null) 1778 { 1779 fieldMode |= FieldMode.Read; 1780 valueProviderCallbackWrapped = _ => CheckInterruptAccess(irqGetter, allowAccessWhenNonSecureGroup) ? valueProviderCallback(irqGetter()) : false; 1781 } 1782 register.WithFlag(fieldIndex, fieldMode, name: $"{name}_{(uint)irqId}", 1783 writeCallback: writeCallbackWrapped, valueProviderCallback: valueProviderCallbackWrapped); 1784 }, 1785 1786 (register, fieldIndex) => register.WithReservedBits(fieldIndex, 1), 1787 sgiRequestingCPU, cpuEntryProvider 1788 ); 1789 } 1790 BuildInterruptValueRegisters(InterruptId startId, InterruptId endId, string name, int fieldsPerRegister, Action<Interrupt, ulong> writeCallback = null, Func<Interrupt, ulong> valueProviderCallback = null, bool allowAccessWhenNonSecureGroup = true, CPUEntry sgiRequestingCPU = null, Func<CPUEntry> cpuEntryProvider = null)1791 private IEnumerable<DoubleWordRegister> BuildInterruptValueRegisters(InterruptId startId, InterruptId endId, string name, int fieldsPerRegister, 1792 Action<Interrupt, ulong> writeCallback = null, Func<Interrupt, ulong> valueProviderCallback = null, bool allowAccessWhenNonSecureGroup = true, 1793 CPUEntry sgiRequestingCPU = null, Func<CPUEntry> cpuEntryProvider = null) 1794 { 1795 const int registerWidth = 32; 1796 var fieldWidth = registerWidth / fieldsPerRegister; 1797 return BuildInterruptRegisters(startId, endId, fieldsPerRegister, 1798 (register, irqGetter, irqId, fieldIndex) => 1799 { 1800 FieldMode fieldMode = 0; 1801 Action<ulong, ulong> writeCallbackWrapped = null; 1802 if(writeCallback != null) 1803 { 1804 fieldMode |= FieldMode.Write; 1805 writeCallbackWrapped = (_, val) => { if(CheckInterruptAccess(irqGetter, allowAccessWhenNonSecureGroup)) writeCallback(irqGetter(), val); }; 1806 } 1807 Func<ulong, ulong> valueProviderCallbackWrapped = null; 1808 if(valueProviderCallback != null) 1809 { 1810 fieldMode |= FieldMode.Read; 1811 valueProviderCallbackWrapped = _ => CheckInterruptAccess(irqGetter, allowAccessWhenNonSecureGroup) ? valueProviderCallback(irqGetter()) : 0; 1812 } 1813 register.WithValueField(fieldIndex * fieldWidth, fieldWidth, fieldMode, name: $"{name}_{(uint)irqId}", 1814 writeCallback: writeCallbackWrapped, valueProviderCallback: valueProviderCallbackWrapped); 1815 }, 1816 (register, fieldIndex) => register.WithReservedBits(fieldIndex * fieldWidth, fieldWidth), 1817 sgiRequestingCPU, cpuEntryProvider 1818 ); 1819 } 1820 1821 private IEnumerable<DoubleWordRegister> BuildInterruptEnumRegisters<TEnum>(InterruptId startId, InterruptId endId, string name, int fieldsPerRegister, 1822 Action<Interrupt, TEnum> writeCallback = null, Func<Interrupt, TEnum> valueProviderCallback = null, bool allowAccessWhenNonSecureGroup = true, 1823 CPUEntry sgiRequestingCPU = null, Func<CPUEntry> cpuEntryProvider = null) where TEnum : struct, IConvertible 1824 { 1825 const int registerWidth = 32; 1826 var fieldWidth = registerWidth / fieldsPerRegister; 1827 return BuildInterruptRegisters(startId, endId, fieldsPerRegister, 1828 (register, irqGetter, irqId, fieldIndex) => 1829 { 1830 FieldMode fieldMode = 0; 1831 Action<TEnum, TEnum> writeCallbackWrapped = null; 1832 if(writeCallback != null) 1833 { 1834 fieldMode |= FieldMode.Write; 1835 writeCallbackWrapped = (_, val) => { if(CheckInterruptAccess(irqGetter, allowAccessWhenNonSecureGroup)) writeCallback(irqGetter(), val); }; 1836 } 1837 Func<TEnum, TEnum> valueProviderCallbackWrapped = null; 1838 if(valueProviderCallback != null) 1839 { 1840 fieldMode |= FieldMode.Read; 1841 valueProviderCallbackWrapped = _ => CheckInterruptAccess(irqGetter, allowAccessWhenNonSecureGroup) ? valueProviderCallback(irqGetter()) : default(TEnum); 1842 } register.WithEnumFieldAntmicro.Renode.Peripherals.IRQControllers.ARM_GenericInterruptController.IConvertible1843 register.WithEnumField<DoubleWordRegister, TEnum>(fieldIndex * fieldWidth, fieldWidth, fieldMode, name: $"{name}_{(uint)irqId}", 1844 writeCallback: writeCallbackWrapped, valueProviderCallback: valueProviderCallbackWrapped); 1845 }, 1846 (register, fieldIndex) => register.WithReservedBits(fieldIndex * fieldWidth, fieldWidth), 1847 sgiRequestingCPU, cpuEntryProvider 1848 ); 1849 } 1850 IsAffinityRoutingEnabled(CPUEntry cpu)1851 private bool IsAffinityRoutingEnabled(CPUEntry cpu) 1852 { 1853 return DisabledSecurity || cpu.IsStateSecure ? AffinityRoutingEnabledSecure : AffinityRoutingEnabledNonSecure; 1854 } 1855 CheckInterruptAccess(Func<Interrupt> irqGetter, bool allowAccessWhenNonSecureGroup)1856 private bool CheckInterruptAccess(Func<Interrupt> irqGetter, bool allowAccessWhenNonSecureGroup) 1857 { 1858 if(DisabledSecurity || GetAskingCPUEntry().IsStateSecure 1859 || (allowAccessWhenNonSecureGroup && irqGetter().Config.GroupType == GroupType.Group1NonSecure)) 1860 { 1861 return true; 1862 } 1863 this.Log(LogLevel.Debug, "Trying to access a field of the interrupt {0}, which isn't accessible from the current security state.", irqGetter().Identifier); 1864 return false; 1865 } 1866 BuildInterruptRegisters(InterruptId startId, InterruptId endId, int fieldsPerRegister, Action<DoubleWordRegister, Func<Interrupt>, InterruptId, int> fieldAction, Action<DoubleWordRegister, int> fieldPlaceholderAction, CPUEntry sgiRequestingCPU, Func<CPUEntry> cpuEntryProvider )1867 private IEnumerable<DoubleWordRegister> BuildInterruptRegisters(InterruptId startId, InterruptId endId, int fieldsPerRegister, 1868 Action<DoubleWordRegister, Func<Interrupt>, InterruptId, int> fieldAction, 1869 Action<DoubleWordRegister, int> fieldPlaceholderAction, 1870 // NOTE: sgiRequestingCPU is currently always null as we don't support registers like GICD_CPENDSGIRn which need this information 1871 CPUEntry sgiRequestingCPU, Func<CPUEntry> cpuEntryProvider 1872 ) 1873 { 1874 if(cpuEntryProvider == null) 1875 { 1876 cpuEntryProvider = GetAskingCPUEntry; 1877 } 1878 var interruptsCount = (int)endId - (int)startId + 1; 1879 var registersCount = (interruptsCount + fieldsPerRegister - 1) / fieldsPerRegister; 1880 var fieldIndex = 0; 1881 foreach(var registerFirstIrqId in InterruptId.GetRange(startId, endId, (uint)fieldsPerRegister)) 1882 { 1883 var register = new DoubleWordRegister(this); 1884 var fieldsCount = fieldsPerRegister; 1885 if(fieldIndex + fieldsCount > interruptsCount) 1886 { 1887 fieldsCount = interruptsCount % fieldsPerRegister; 1888 } 1889 foreach(var irqId in InterruptId.GetRange(registerFirstIrqId, new InterruptId((uint)registerFirstIrqId + (uint)fieldsCount - 1))) 1890 { 1891 var inRegisterIndex = fieldIndex % fieldsPerRegister; 1892 if(irqsDecoder.Type(irqId) == InterruptType.Reserved) 1893 { 1894 fieldPlaceholderAction(register, inRegisterIndex); 1895 } 1896 else if(irqsDecoder.IsSoftwareGenerated(irqId)) 1897 { 1898 if(sgiRequestingCPU == null) 1899 { 1900 // NOTE: We're returning here from SoftwareGeneratedInterruptsUnknownRequester despite some of the registers operating on 1901 // the LegacyRequester interrupts. This is fine, as all of those registers actually operate on InterruptConfig 1902 // and that's shared between interrupts in UnknownRequester and LegacyRequester. 1903 fieldAction(register, () => cpuEntryProvider().SoftwareGeneratedInterruptsUnknownRequester[irqId], irqId, inRegisterIndex); 1904 } 1905 else 1906 { 1907 fieldAction(register, () => cpuEntryProvider().SoftwareGeneratedInterruptsLegacyRequester[sgiRequestingCPU][irqId], irqId, inRegisterIndex); 1908 } 1909 } 1910 else if(irqsDecoder.IsPrivatePeripheral(irqId)) 1911 { 1912 fieldAction(register, () => cpuEntryProvider().PrivatePeripheralInterrupts[irqId], irqId, inRegisterIndex); 1913 } 1914 else 1915 { 1916 fieldAction(register, () => sharedInterrupts[irqId], irqId, inRegisterIndex); 1917 } 1918 fieldIndex++; 1919 } 1920 // Always fill the whole register 1921 for(; (fieldIndex % fieldsPerRegister) != 0; fieldIndex++) 1922 { 1923 fieldPlaceholderAction(register, fieldIndex % fieldsPerRegister); 1924 } 1925 1926 yield return register; 1927 } 1928 } 1929 GetAskingCPUEntry()1930 private CPUEntry GetAskingCPUEntry() 1931 { 1932 var cpu = busController.GetCurrentCPU(); 1933 var armCPU = cpu as IARMSingleSecurityStateCPU; 1934 if(armCPU == null || !cpuEntries.ContainsKey(armCPU)) 1935 { 1936 throw new InvalidOperationException($"Non-Arm CPU or one that isn't attached to the GIC tried to access the GIC: {cpu.GetName()}"); 1937 } 1938 return cpuEntries[armCPU]; 1939 } 1940 GetAskingCPUEntryWithTwoSecurityStates()1941 private CPUEntryWithTwoSecurityStates GetAskingCPUEntryWithTwoSecurityStates() 1942 { 1943 var cpuEntry = GetAskingCPUEntry(); 1944 if(!(cpuEntry is CPUEntryWithTwoSecurityStates cpuEntryWithTwoSecurityStates)) 1945 { 1946 throw new InvalidOperationException($"The asking CPU '{cpuEntry.Name}' doesn't have two security states!"); 1947 } 1948 return cpuEntryWithTwoSecurityStates; 1949 } 1950 TryWriteRegisterSecurityView(long offset, uint value, DoubleWordRegisterCollection notBankedRegisters, DoubleWordRegisterCollection secureRegisters, DoubleWordRegisterCollection nonSecureRegisters, DoubleWordRegisterCollection disabledSecurityRegisters)1951 private bool TryWriteRegisterSecurityView(long offset, uint value, DoubleWordRegisterCollection notBankedRegisters, 1952 DoubleWordRegisterCollection secureRegisters, DoubleWordRegisterCollection nonSecureRegisters, DoubleWordRegisterCollection disabledSecurityRegisters) 1953 { 1954 var bankedRegisters = GetBankedRegistersCollection(secureRegisters, nonSecureRegisters, disabledSecurityRegisters); 1955 return bankedRegisters.TryWrite(offset, value) || notBankedRegisters.TryWrite(offset, value); 1956 } 1957 TryReadRegisterSecurityView(long offset, out uint value, DoubleWordRegisterCollection notBankedRegisters, DoubleWordRegisterCollection secureRegisters, DoubleWordRegisterCollection nonSecureRegisters, DoubleWordRegisterCollection disabledSecurityRegisters)1958 private bool TryReadRegisterSecurityView(long offset, out uint value, DoubleWordRegisterCollection notBankedRegisters, 1959 DoubleWordRegisterCollection secureRegisters, DoubleWordRegisterCollection nonSecureRegisters, DoubleWordRegisterCollection disabledSecurityRegisters) 1960 { 1961 var bankedRegisters = GetBankedRegistersCollection(secureRegisters, nonSecureRegisters, disabledSecurityRegisters); 1962 return bankedRegisters.TryRead(offset, out value) || notBankedRegisters.TryRead(offset, out value); 1963 } 1964 GetBankedRegistersCollection(DoubleWordRegisterCollection secureRegisters, DoubleWordRegisterCollection nonSecureRegisters, DoubleWordRegisterCollection disabledSecurityRegisters)1965 private DoubleWordRegisterCollection GetBankedRegistersCollection(DoubleWordRegisterCollection secureRegisters, DoubleWordRegisterCollection nonSecureRegisters, 1966 DoubleWordRegisterCollection disabledSecurityRegisters) 1967 { 1968 if(DisabledSecurity) 1969 { 1970 return disabledSecurityRegisters; 1971 } 1972 else 1973 { 1974 return GetAskingCPUEntry().IsStateSecure ? secureRegisters : nonSecureRegisters; 1975 } 1976 } 1977 IsDistributorByteAccessible(long offset)1978 private bool IsDistributorByteAccessible(long offset) 1979 { 1980 return IsByteOffsetInDistributorRegistersRange(offset, DistributorRegisters.InterruptPriority_0, DistributorRegisters.InterruptPriority_254) 1981 || IsByteOffsetInDistributorRegistersRange(offset, DistributorRegisters.InterruptProcessorTargets_0, DistributorRegisters.InterruptProcessorTargets_254) 1982 || IsByteOffsetInDistributorRegistersRange(offset, DistributorRegisters.SoftwareGeneratedIntrruptClearPending_0, DistributorRegisters.SoftwareGeneratedIntrruptClearPending_3) 1983 || IsByteOffsetInDistributorRegistersRange(offset, DistributorRegisters.SoftwareGeneratedIntrruptSetPending_0, DistributorRegisters.SoftwareGeneratedIntrruptSetPending_3); 1984 } 1985 IsByteOffsetInDistributorRegistersRange(long offset, DistributorRegisters startOffset, DistributorRegisters endOffset)1986 private bool IsByteOffsetInDistributorRegistersRange(long offset, DistributorRegisters startOffset, DistributorRegisters endOffset) 1987 { 1988 const long maxByteOffset = 3; 1989 return (long)startOffset <= offset && offset <= (long)endOffset + maxByteOffset; 1990 } 1991 IsRedistributorByteAccessible(long offset)1992 private bool IsRedistributorByteAccessible(long offset) 1993 { 1994 const long maxByteOffset = 3; 1995 return (long)RedistributorRegisters.InterruptPriority_0 <= offset && offset <= (long)RedistributorRegisters.InterruptPriority_7 + maxByteOffset; 1996 } 1997 SetOnTransitionToTrue(ref bool value, bool newValue, string warningOnTransitionToFalse)1998 private bool SetOnTransitionToTrue(ref bool value, bool newValue, string warningOnTransitionToFalse) 1999 { 2000 if(newValue == value) 2001 { 2002 return false; 2003 } 2004 if(!newValue) 2005 { 2006 this.Log(LogLevel.Warning, warningOnTransitionToFalse); 2007 return false; 2008 } 2009 value = true; 2010 return true; 2011 } 2012 ClearForcedTargettingCache()2013 private void ClearForcedTargettingCache() 2014 { 2015 forcedTargettedCpuForAffinityRouting = null; 2016 } 2017 GetProcessorNumber(ICPU cpu)2018 private static uint GetProcessorNumber(ICPU cpu) 2019 { 2020 switch(cpu.Model) 2021 { 2022 // For Cortex-A55 core number is stored in affinity level 1. 2023 // In older CPUs (i.e. Cortex-A53) it's stored in affinity level 0. 2024 case "cortex-a55": 2025 return BitHelper.GetValue(cpu.MultiprocessingId, 8, 8); 2026 default: 2027 return BitHelper.GetValue(cpu.MultiprocessingId, 0, 8); 2028 } 2029 } 2030 2031 private CPUEntry ForcedTargettingCpuForAffinityRouting 2032 { 2033 get 2034 { 2035 if(forcedTargettedCpuForAffinityRouting == null) 2036 { 2037 forcedTargettedCpuForAffinityRouting = cpuEntries.Values.Where(cpu => cpu.IsParticipatingInRouting).MinBy(cpu => cpu.Affinity.AllLevels); 2038 } 2039 return forcedTargettedCpuForAffinityRouting; 2040 } 2041 } 2042 2043 private bool ackControl; 2044 private bool enableFIQ; 2045 private bool disabledSecurity; 2046 private bool affinityRoutingEnabledSecure; 2047 private bool affinityRoutingEnabledNonSecure; 2048 private uint legacyCpusAttachedMask; 2049 private CPUEntry forcedTargettedCpuForAffinityRouting; 2050 2051 private readonly IBusController busController; 2052 private readonly Object locker = new Object(); 2053 private readonly Dictionary<uint, IARMSingleSecurityStateCPU> cpusByProcessorNumberCache = new Dictionary<uint, IARMSingleSecurityStateCPU>(); 2054 private readonly Dictionary<IARMSingleSecurityStateCPU, CPUEntry> cpuEntries = new Dictionary<IARMSingleSecurityStateCPU, CPUEntry>(); 2055 private readonly InterruptSignalType[] supportedInterruptSignals; 2056 private readonly ReadOnlyDictionary<InterruptId, SharedInterrupt> sharedInterrupts; 2057 private readonly ReadOnlyDictionary<GroupType, InterruptGroup> groups; 2058 private readonly DoubleWordRegisterCollection distributorDoubleWordRegisters; 2059 private readonly QuadWordRegisterCollection distributorQuadWordRegisters; 2060 private readonly DoubleWordRegisterCollection distributorRegistersSecureView; 2061 private readonly DoubleWordRegisterCollection distributorRegistersNonSecureView; 2062 private readonly DoubleWordRegisterCollection distributorRegistersDisabledSecurityView; 2063 private readonly DoubleWordRegisterCollection cpuInterfaceRegisters; 2064 private readonly DoubleWordRegisterCollection cpuInterfaceRegistersSecureView; 2065 private readonly DoubleWordRegisterCollection cpuInterfaceRegistersNonSecureView; 2066 private readonly DoubleWordRegisterCollection cpuInterfaceRegistersDisabledSecurityView; 2067 private readonly QuadWordRegisterCollection cpuInterfaceSystemRegisters; 2068 2069 private readonly uint affinityToIdMask; 2070 private readonly bool supportsTwoSecurityStates; 2071 private readonly InterruptsDecoder irqsDecoder; 2072 2073 private const ARM_GenericInterruptControllerVersion DefaultArchitectureVersion = ARM_GenericInterruptControllerVersion.GICv3; 2074 private const uint DefaultCPUInterfaceProductIdentifier = 0x0; 2075 private const uint DefaultDistributorProductIdentifier = 0x0; 2076 private const uint DefaultRedistributorProductIdentifier = 0x0; 2077 private const byte DefaultVariantNumber = 0x0; 2078 private const byte DefaultRevisionNumber = 0x0; 2079 private const uint DefaultImplementerIdentification = 0x43B; // This value indicates the JEP106 code of the Arm as an implementer 2080 2081 private const uint CPUsCountLegacySupport = 8; 2082 private const long RedistributorPrivateInterruptsFrameOffset = 0x10000; 2083 2084 private const uint VirtualInterruptCount = 16; 2085 private const uint VirtualPriorityBits = 5; 2086 2087 public class CPUEntry : IGPIOReceiver 2088 { CPUEntry(ARM_GenericInterruptController gic, IARMSingleSecurityStateCPU cpu, IEnumerable<GroupType> groupTypes, IReadOnlyDictionary<InterruptSignalType, IGPIO> interruptConnections)2089 public CPUEntry(ARM_GenericInterruptController gic, IARMSingleSecurityStateCPU cpu, IEnumerable<GroupType> groupTypes, IReadOnlyDictionary<InterruptSignalType, IGPIO> interruptConnections) 2090 { 2091 this.gic = gic; 2092 this.cpu = cpu; 2093 Name = $"cpu{Affinity}"; 2094 interruptSignals = interruptConnections; 2095 2096 var sgiIds = InterruptId.GetRange(gic.IrqsDecoder.SoftwareGeneratedFirst, gic.IrqsDecoder.SoftwareGeneratedLast); 2097 SoftwareGeneratedInterruptsConfig = new ReadOnlyDictionary<InterruptId, InterruptConfig>(sgiIds.ToDictionary(id => id, _ => new InterruptConfig())); 2098 SoftwareGeneratedInterruptsUnknownRequester = GenerateSGIs(SoftwareGeneratedInterruptsConfig, null); 2099 SoftwareGeneratedInterruptsLegacyRequester = new Dictionary<CPUEntry, ReadOnlyDictionary<InterruptId, SoftwareGeneratedInterrupt>>(); 2100 2101 redistributorDoubleWordRegisters = new DoubleWordRegisterCollection(this, BuildRedistributorDoubleWordRegisterMap()); 2102 redistributorQuadWordRegisters = new QuadWordRegisterCollection(this, BuildRedistributorQuadWordRegisterMap()); 2103 2104 var ppiIds = InterruptId.GetRange(gic.IrqsDecoder.PrivatePeripheralFirst, gic.IrqsDecoder.PrivatePeripheralLast) 2105 .Concat(InterruptId.GetRange(gic.IrqsDecoder.ExtendedPrivatePeripheralFirst, gic.IrqsDecoder.ExtendedPrivatePeripheralLast)); 2106 PrivatePeripheralInterrupts = new ReadOnlyDictionary<InterruptId, Interrupt>(ppiIds.ToDictionary(id => id, id => new Interrupt(id))); 2107 2108 Groups = new GroupCollection(this, groupTypes); 2109 RunningInterrupts = new RunningInterrupts(this); 2110 VirtualInterrupts = new VirtualInterrupt[VirtualInterruptCount]; 2111 for(var i = 0; i < VirtualInterruptCount; ++i) 2112 { 2113 VirtualInterrupts[i] = new VirtualInterrupt(); 2114 } 2115 } 2116 Reset()2117 public virtual void Reset() 2118 { 2119 foreach(var irq in AllPrivateAndSoftwareGeneratedInterrupts) 2120 { 2121 irq.Reset(); 2122 } 2123 foreach(var interrupt in VirtualInterrupts) 2124 { 2125 interrupt.Reset(); 2126 } 2127 for(var i = 0; i < NonSecureSGIAccess.Length; ++i) 2128 { 2129 NonSecureSGIAccess[i] = NonSecureAccess.NotPermitted; 2130 } 2131 Groups.Reset(); 2132 redistributorQuadWordRegisters.Reset(); 2133 redistributorDoubleWordRegisters.Reset(); 2134 VirtualCPUInterfaceEnabled = false; 2135 BestPending = null; 2136 BestPendingVirtual = null; 2137 EndOfInterruptModeEL1NonSecure = EndOfInterruptModes.PriorityDropAndDeactivation; 2138 EndOfInterruptModeEL1Secure = EndOfInterruptModes.PriorityDropAndDeactivation; 2139 EndOfInterruptModeVirtual = EndOfInterruptModes.PriorityDropAndDeactivation; 2140 VirtualFIQEnabled = false; 2141 IsSleeping = true; 2142 RunningInterrupts.Clear(); 2143 PhysicalPriorityMask = InterruptPriority.Idle; 2144 VirtualPriorityMask = InterruptPriority.Idle; 2145 UpdateSignals(); 2146 } 2147 2148 // It's expected to pass handling of private interrupts to the ARM_GenericInterruptController class using an event handler OnGPIO(int number, bool value)2149 public void OnGPIO(int number, bool value) 2150 { 2151 PrivateInterruptChanged?.Invoke(this, number, value); 2152 } 2153 AcknowledgeBestPending(GroupTypeSecurityAgnostic groupTypeRegister, out CPUEntry sgiRequestingCPU)2154 public virtual InterruptId AcknowledgeBestPending(GroupTypeSecurityAgnostic groupTypeRegister, out CPUEntry sgiRequestingCPU) 2155 { 2156 var groupType = GetGroupTypeForRegisterSecurityAgnostic(groupTypeRegister); 2157 var isVirtualized = IsVirtualized(groupType); 2158 sgiRequestingCPU = null; 2159 var pendingIrq = isVirtualized ? BestPendingVirtual : BestPending; 2160 if(pendingIrq == null) 2161 { 2162 return gic.IrqsDecoder.NoPending; 2163 } 2164 if(pendingIrq.Config.GroupType != groupType) 2165 { 2166 // In GICv2, Secure (Group 0) access can acknowledge Group 1 interrupt if GICC_CTLR.AckCtl is set. Otherwise, the returned Interrupt ID is 1022 (NoPending=1023). 2167 if(!isVirtualized && gic.ArchitectureVersion == ARM_GenericInterruptControllerVersion.GICv2 && groupTypeRegister == GroupTypeSecurityAgnostic.Group0) 2168 { 2169 if(!gic.ackControl) 2170 { 2171 gic.Log(LogLevel.Warning, "Trying to acknowledge pending Group 1 interrupt (#{0}) with secure GIC access while GICC_CTLR.AckCtl isn't set", (uint)pendingIrq.Identifier); 2172 return gic.IrqsDecoder.NonMaskableInterruptOrGICv2GroupMismatch; 2173 } 2174 } 2175 else 2176 { 2177 gic.Log(LogLevel.Warning, "Trying to acknowledge pending interrupt using register of an incorrect interrupt group ({0}), expected {1}.", groupType, pendingIrq.Config.GroupType); 2178 return gic.IrqsDecoder.NoPending; 2179 } 2180 } 2181 pendingIrq.State.Acknowledge(); 2182 RunningInterrupts.Push(groupType, pendingIrq); 2183 if(isVirtualized) 2184 { 2185 BestPendingVirtual = null; 2186 } 2187 else 2188 { 2189 BestPending = null; 2190 } 2191 2192 var pendingIrqAsSGI = pendingIrq as SoftwareGeneratedInterrupt; 2193 if(pendingIrqAsSGI != null) 2194 { 2195 sgiRequestingCPU = pendingIrqAsSGI.Requester; 2196 } 2197 2198 return pendingIrq.Identifier; 2199 } 2200 2201 // Performs priority drop and, if independentEOIControls is false, IRQ deactivation. InterruptEnd(InterruptId id, GroupTypeSecurityAgnostic groupTypeRegister, CPUEntry sgiRequestingCPU)2202 public void InterruptEnd(InterruptId id, GroupTypeSecurityAgnostic groupTypeRegister, CPUEntry sgiRequestingCPU) 2203 { 2204 var groupType = GetGroupTypeForRegisterSecurityAgnostic(groupTypeRegister); 2205 var isVirtualized = IsVirtualized(groupType); 2206 var shouldBeDeactivated = CurrentEndOfInterruptMode == EndOfInterruptModes.PriorityDropAndDeactivation; 2207 gic.Log(LogLevel.Debug, "Ending interrupt with id {0}{1}.", (uint)id, shouldBeDeactivated ? "" : " but it won't be deactivated"); 2208 2209 if(RunningInterrupts.Count(groupType) == 0) 2210 { 2211 gic.Log(LogLevel.Warning, "Trying to end the running interrupt when no interrupt is running."); 2212 return; 2213 } 2214 2215 var runningIrq = RunningInterrupts.Peek(groupType); 2216 if(runningIrq.Config.GroupType != groupType) 2217 { 2218 // In GICv2, Secure (Group 0) access can affect Group 1 interrupts if GICC_CTLR.AckCtl is set. 2219 if(!isVirtualized && gic.ArchitectureVersion == ARM_GenericInterruptControllerVersion.GICv2 && groupTypeRegister == GroupTypeSecurityAgnostic.Group0) 2220 { 2221 if(!gic.ackControl) 2222 { 2223 gic.Log(LogLevel.Warning, "Trying to end the running Group 1 interrupt (#{0}) with secure GIC access while GICC_CTLR.AckCtl isn't set, request ignored.", (uint)runningIrq.Identifier); 2224 return; 2225 } 2226 } 2227 else 2228 { 2229 gic.Log(LogLevel.Warning, "Trying to end the running interrupt using the register of an incorrect interrupt group ({0}), expected {1}, request ignored.", groupType, runningIrq.Config.GroupType); 2230 return; 2231 } 2232 } 2233 2234 if(!runningIrq.Identifier.Equals(id)) 2235 { 2236 gic.Log(LogLevel.Error, "Incorrect interrupt identifier to end the running interrupt, expected INTID {0}, given {1}, request ignored.", runningIrq.Identifier, id); 2237 return; 2238 } 2239 2240 if(!IsSoftwareGeneratedInterruptAccessValid(runningIrq, sgiRequestingCPU, "InterruptEnd")) 2241 { 2242 return; 2243 } 2244 2245 // The interrupt are just removed from stack of currently running interrupts 2246 // It's still accessible using one of the read only collections of interrupts (shared or private ones) 2247 // If the stack becomes empty, RunningPriority will return InterruptPriority.Idle; otherwise the priority of an interrupt on top of stack. 2248 RunningInterrupts.Pop(groupType); 2249 2250 if(shouldBeDeactivated) 2251 { 2252 DeactivateInterrupt(runningIrq, isVirtualized); 2253 } 2254 } 2255 InterruptDeactivate(InterruptId id, CPUEntry sgiRequestingCPU)2256 public void InterruptDeactivate(InterruptId id, CPUEntry sgiRequestingCPU) 2257 { 2258 Action<string> logFailure = failureReason => gic.Log( 2259 LogLevel.Warning, "Trying to deactivate interrupt with id {0} {1}, write ignored.", (uint)id, failureReason 2260 ); 2261 2262 var isVirtualized = IsVirtualized(); 2263 2264 if(CurrentEndOfInterruptMode == EndOfInterruptModes.PriorityDropAndDeactivation) 2265 { 2266 logFailure($"with EOImode=0 in the current CPU state: {CurrentCPUSecurityStateString}"); 2267 return; 2268 } 2269 2270 var interrupt = isVirtualized 2271 ? RunningInterrupts.GetActiveVirtual(id) 2272 : gic.GetAllInterrupts(this).SingleOrDefault(x => ((uint)x.Identifier) == ((uint)id) && x.State.Active); 2273 if(interrupt == null) 2274 { 2275 logFailure("which is an invalid INTID"); 2276 return; 2277 } 2278 2279 if(!gic.DisabledSecurity && !IsStateSecure) 2280 { 2281 var interruptGroupType = interrupt.Config.GroupType; 2282 if(interruptGroupType != GroupType.Group1NonSecure) 2283 { 2284 logFailure("belonging to " + (interruptGroupType == GroupType.Group0 ? "group 0" : "secure group 1") + " from a non-secure state"); 2285 return; 2286 } 2287 } 2288 2289 if(!IsSoftwareGeneratedInterruptAccessValid(interrupt, sgiRequestingCPU, "InterruptDeactivate")) 2290 { 2291 return; 2292 } 2293 2294 if(!interrupt.State.Active) 2295 { 2296 logFailure("but it isn't active"); 2297 return; 2298 } 2299 DeactivateInterrupt(interrupt, isVirtualized); 2300 } 2301 UpdateSignals()2302 public void UpdateSignals() 2303 { 2304 if(BestPending == null && BestPendingVirtual == null) 2305 { 2306 foreach(var signal in interruptSignals.Values) 2307 { 2308 signal.Set(false); 2309 } 2310 return; 2311 } 2312 2313 var signalType = GetBestPendingInterruptSignalType(); 2314 foreach(var signal in interruptSignals) 2315 { 2316 signal.Value.Set(signal.Key == signalType); 2317 } 2318 } 2319 GetGroupForRegisterSecurityAgnostic(GroupTypeSecurityAgnostic type)2320 public InterruptGroup GetGroupForRegisterSecurityAgnostic(GroupTypeSecurityAgnostic type) 2321 { 2322 return Groups[GetGroupTypeForRegisterSecurityAgnostic(type)]; 2323 } 2324 GetGroupTypeForRegisterSecurityAgnostic(GroupTypeSecurityAgnostic type)2325 public GroupType GetGroupTypeForRegisterSecurityAgnostic(GroupTypeSecurityAgnostic type) 2326 { 2327 if(type == GroupTypeSecurityAgnostic.Group0) 2328 { 2329 return GroupType.Group0; 2330 } 2331 else if(type == GroupTypeSecurityAgnostic.Group1) 2332 { 2333 var securityState = cpu.SecurityState; 2334 if(gic.DisabledSecurity || securityState == SecurityState.NonSecure) 2335 { 2336 return GroupType.Group1NonSecure; 2337 } 2338 else if(securityState == SecurityState.Secure) 2339 { 2340 return GroupType.Group1Secure; 2341 } 2342 } 2343 throw new ArgumentOutOfRangeException($"There is no valid InterruptGroupType for value: {type}."); 2344 } 2345 RegisterLegacySGIRequester(CPUEntry cpu)2346 public void RegisterLegacySGIRequester(CPUEntry cpu) 2347 { 2348 if(SoftwareGeneratedInterruptsLegacyRequester.ContainsKey(cpu)) 2349 { 2350 throw new ArgumentException($"The CPU ({cpu}) was already registered as a legacy requester."); 2351 } 2352 SoftwareGeneratedInterruptsLegacyRequester[cpu] = GenerateSGIs(SoftwareGeneratedInterruptsConfig, cpu); 2353 } 2354 IsVirtualized()2355 public bool IsVirtualized() 2356 { 2357 if(cpu.SecurityState != SecurityState.NonSecure || cpu.ExceptionLevel > ExceptionLevel.EL1_SystemMode) 2358 { 2359 return false; 2360 } 2361 return cpu.FIQMaskOverride || cpu.IRQMaskOverride; 2362 } 2363 IsVirtualized(GroupType type)2364 public bool IsVirtualized(GroupType type) 2365 { 2366 if(cpu.SecurityState != SecurityState.NonSecure || cpu.ExceptionLevel > ExceptionLevel.EL1_SystemMode) 2367 { 2368 return false; 2369 } 2370 if(type == GroupType.Group0) 2371 { 2372 return cpu.FIQMaskOverride; 2373 } 2374 if(type == GroupType.Group1) 2375 { 2376 return cpu.IRQMaskOverride; 2377 } 2378 throw new ArgumentOutOfRangeException($"There is no valid InterruptGroupType for value: {type}."); 2379 } 2380 2381 public QuadWordRegisterCollection RedistributorQuadWordRegisters => redistributorQuadWordRegisters; 2382 public DoubleWordRegisterCollection RedistributorDoubleWordRegisters => redistributorDoubleWordRegisters; 2383 2384 public event Action<CPUEntry, int, bool> PrivateInterruptChanged; 2385 2386 public IReadOnlyDictionary<InterruptId, Interrupt> PrivatePeripheralInterrupts { get; } 2387 public IReadOnlyDictionary<InterruptId, InterruptConfig> SoftwareGeneratedInterruptsConfig { get; } 2388 public IReadOnlyDictionary<InterruptId, SoftwareGeneratedInterrupt> SoftwareGeneratedInterruptsUnknownRequester; 2389 public Dictionary<CPUEntry, ReadOnlyDictionary<InterruptId, SoftwareGeneratedInterrupt>> SoftwareGeneratedInterruptsLegacyRequester { get; } 2390 2391 public IEnumerable<Interrupt> AllPrivateAndSoftwareGeneratedInterrupts => PrivatePeripheralInterrupts.Values 2392 .Concat(SoftwareGeneratedInterruptsUnknownRequester.Values) 2393 .Concat(SoftwareGeneratedInterruptsLegacyRequester.Values.SelectMany(x => x.Values)); 2394 public IEnumerable<InterruptConfig> AllPrivateAndSoftwareGeneratedInterruptsConfigs => PrivatePeripheralInterrupts.Values.Select(irq => irq.Config) 2395 .Concat(SoftwareGeneratedInterruptsConfig.Values); 2396 2397 public GroupCollection Groups { get; } 2398 2399 public bool IsSleeping 2400 { 2401 get => isSleeping; 2402 set 2403 { 2404 var changed = isSleeping != value; 2405 if(changed) 2406 { 2407 isSleeping = value; 2408 gic.ClearForcedTargettingCache(); 2409 } 2410 } 2411 } 2412 2413 public Affinity Affinity => cpu.Affinity; 2414 public bool IsParticipatingInRouting => !IsSleeping; 2415 public virtual string CurrentCPUSecurityStateString => $"state: {cpu.SecurityState}"; 2416 public virtual EndOfInterruptModes CurrentEndOfInterruptMode => EndOfInterruptModeEL1; 2417 2418 public EndOfInterruptModes EndOfInterruptModeEL1 2419 { 2420 get => IsVirtualized() 2421 ? EndOfInterruptModeVirtual 2422 : gic.DisabledSecurity || IsStateSecure ? EndOfInterruptModeEL1Secure : EndOfInterruptModeEL1NonSecure; 2423 set 2424 { 2425 if(IsVirtualized()) 2426 { 2427 EndOfInterruptModeVirtual = value; 2428 } 2429 else if(gic.DisabledSecurity || IsStateSecure) 2430 { 2431 EndOfInterruptModeEL1Secure = value; 2432 } 2433 else 2434 { 2435 EndOfInterruptModeEL1NonSecure = value; 2436 } 2437 } 2438 } 2439 2440 public EndOfInterruptModes EndOfInterruptModeEL1NonSecure { get; set; } 2441 public EndOfInterruptModes EndOfInterruptModeEL1Secure { get; set; } 2442 public EndOfInterruptModes EndOfInterruptModeVirtual { get; set; } 2443 public bool IsStateSecure => cpu.SecurityState == SecurityState.Secure; 2444 public string Name { get; } 2445 public uint ProcessorNumber => GetProcessorNumber(cpu); 2446 public uint TargetFieldFlag => ProcessorNumber <= CPUsCountLegacySupport ? 1U << (int)ProcessorNumber : 0; 2447 public bool VirtualCPUInterfaceEnabled { get; set; } 2448 public bool VirtualFIQEnabled { get; set; } 2449 2450 public Interrupt BestPending { get; set; } 2451 public Interrupt BestPendingVirtual { get; set; } 2452 public VirtualInterrupt[] VirtualInterrupts { get; } 2453 public InterruptPriority PriorityMask 2454 { 2455 get => IsVirtualized() ? VirtualPriorityMask : PhysicalPriorityMask; 2456 set 2457 { 2458 if(IsVirtualized()) 2459 { 2460 VirtualPriorityMask = value; 2461 } 2462 else 2463 { 2464 PhysicalPriorityMask = value; 2465 } 2466 } 2467 } 2468 public InterruptPriority VirtualPriorityMask { get; set; } 2469 public InterruptPriority PhysicalPriorityMask { get; set; } 2470 public RunningInterrupts RunningInterrupts { get; } 2471 public uint EOICount { get; private set; } 2472 public NonSecureAccess[] NonSecureSGIAccess { get; } = new NonSecureAccess[InterruptsDecoder.SoftwareGeneratedCount]; 2473 2474 public const int EOICountWidth = 5; 2475 public const int EOICountMask = (1 << EOICountWidth) - 1; 2476 GetBestPendingInterruptSignalType()2477 protected virtual InterruptSignalType GetBestPendingInterruptSignalType() 2478 { 2479 if(BestPending == null) 2480 { 2481 if(VirtualFIQEnabled && BestPendingVirtual.Config.GroupType == GroupType.Group0) 2482 { 2483 return InterruptSignalType.vFIQ; 2484 } 2485 return InterruptSignalType.vIRQ; 2486 } 2487 if(gic.enableFIQ && BestPending.Config.GroupType == GroupType.Group0) 2488 { 2489 return InterruptSignalType.FIQ; 2490 } 2491 return InterruptSignalType.IRQ; 2492 } 2493 2494 protected readonly ARM_GenericInterruptController gic; 2495 GenerateSGIs(IReadOnlyDictionary<InterruptId, InterruptConfig> configs, CPUEntry requester)2496 private ReadOnlyDictionary<InterruptId, SoftwareGeneratedInterrupt> GenerateSGIs(IReadOnlyDictionary<InterruptId, InterruptConfig> configs, CPUEntry requester) 2497 { 2498 return new ReadOnlyDictionary<InterruptId, SoftwareGeneratedInterrupt>(configs.ToDictionary(config => config.Key, config => new SoftwareGeneratedInterrupt(config.Key, config.Value, requester))); 2499 } 2500 DeactivateInterrupt(Interrupt interrupt, bool isVirtualized)2501 private void DeactivateInterrupt(Interrupt interrupt, bool isVirtualized) 2502 { 2503 gic.Log(LogLevel.Debug, "Deactivating interrupt with id {0}", (uint)interrupt.Identifier); 2504 interrupt.State.Active = false; 2505 2506 if(isVirtualized) 2507 { 2508 var virtualInterrupt = (VirtualInterrupt)interrupt; 2509 var lrEntry = VirtualInterrupts.SingleOrDefault(x => x.Identifier.Equals(interrupt.Identifier)); 2510 if(lrEntry == null) 2511 { 2512 EOICount = (EOICount + 1) & EOICountMask; 2513 } 2514 else 2515 { 2516 lrEntry.Sync(virtualInterrupt); 2517 } 2518 RunningInterrupts.RemoveActiveVirtual(virtualInterrupt.Identifier); 2519 if(virtualInterrupt.Hardware) 2520 { 2521 var physicalIrq = gic.GetAllInterrupts(this).SingleOrDefault(x => x.Identifier.Equals(virtualInterrupt.HardwareIdentifier)); 2522 if(physicalIrq != null) 2523 { 2524 physicalIrq.State.Active = false; 2525 } 2526 } 2527 } 2528 } 2529 IsSoftwareGeneratedInterruptAccessValid(Interrupt interrupt, CPUEntry accessingCPU, string registerTypeName)2530 private bool IsSoftwareGeneratedInterruptAccessValid(Interrupt interrupt, CPUEntry accessingCPU, string registerTypeName) 2531 { 2532 if(interrupt is SoftwareGeneratedInterrupt sgi) 2533 { 2534 if(sgi.Requester != null && sgi.Requester != accessingCPU && !gic.IsAffinityRoutingEnabled(sgi.Requester)) 2535 { 2536 var logMessage = "{0}: Incorrect Processor Number {1} passed for SGI ({2}), expected to be {3}."; 2537 if(gic.ArchitectureVersionAtLeast3) 2538 { 2539 logMessage += " Request will be ignored."; 2540 } 2541 gic.Log(LogLevel.Warning, logMessage, registerTypeName, accessingCPU.Affinity, interrupt.Identifier, sgi.Requester.Affinity); 2542 2543 if(gic.ArchitectureVersionAtLeast3) 2544 { 2545 /* 2546 * The documentation is not clear what happens here, if we are in SMP system, and there is a CPUID mismatch 2547 * -> For GICv3 the whole field of INTID (bits 23:0) should be passed, which contains CPUID in bits 12:10 - so it's safe to abort if they mismatch 2548 * -> For GICv2 it's not clear, but "For every read of a valid Interrupt ID from the GICC_IAR, the connected processor must perform a matching write to the GICC_EOIR. 2549 * The value written to the GICC_EOIR must be the interrupt ID read from the GICC_IAR." 2550 * So we stay permissive, and still allow the request to go through 2551 */ 2552 return false; 2553 } 2554 } 2555 } 2556 else if(accessingCPU != null && accessingCPU.ProcessorNumber != 0) 2557 { 2558 gic.Log(LogLevel.Debug, "{0}: Processor Number ({1}) passed for non-SGI interrupt ({2}).", registerTypeName, accessingCPU.ProcessorNumber, interrupt.Identifier); 2559 } 2560 return true; 2561 } 2562 BuildRedistributorQuadWordRegisterMap()2563 private Dictionary<long, QuadWordRegister> BuildRedistributorQuadWordRegisterMap() 2564 { 2565 var registerMap = new Dictionary<long, QuadWordRegister> 2566 { 2567 {(long)RedistributorRegisters.ControllerType, new QuadWordRegister(this) 2568 .WithValueField(32, 32, FieldMode.Read, name: "CPUAffinity", 2569 valueProviderCallback: _ => this.Affinity.AllLevels 2570 ) 2571 .WithValueField(27, 5, FieldMode.Read, name: "MaximumPrivatePeripheralInterruptIdentifier", 2572 valueProviderCallback: _ => 0b00 // The maximum PPI identifier is 31, because the GIC doesn't support an extended range of PPI 2573 ) 2574 .WithFlag(26, FieldMode.Read, name: "DirectSoftwareGeneratedInterruptInjectionSupport", 2575 valueProviderCallback: _ => false 2576 ) 2577 .WithTag("LocalitySpecificInterruptConfigurationSharing", 24, 2) 2578 .WithValueField(8, 16, FieldMode.Read, name: "ProcessorNumber", 2579 valueProviderCallback: _ => this.ProcessorNumber 2580 ) 2581 .WithTaggedFlag("vPEResidentIndicator", 7) 2582 .WithFlag(6, FieldMode.Read, name: "MPAMSupport", 2583 valueProviderCallback: _ => false 2584 ) 2585 .WithFlag(5, FieldMode.Read, name: "DPGSupport", 2586 valueProviderCallback: _ => false 2587 ) 2588 .WithFlag(4, FieldMode.Read, name: "HighestRedistributorInSeries", valueProviderCallback: _ => 2589 { 2590 var redistributorsNotLowerThanCurrent = gic.GetRedistributorRegistrations().OrderBy(redist => redist.Range.StartAddress).SkipWhile(x => x.Cpu != cpu); 2591 // there must exist a corresponding redistributor for this CPUEntry, as otherwise we wouldn't be able to access this register 2592 var currentRedistributor = redistributorsNotLowerThanCurrent.First(); 2593 var nextRedistributor = redistributorsNotLowerThanCurrent.Skip(1).FirstOrDefault(); 2594 // return true for the highest redistrubutor in the contiguous region 2595 return nextRedistributor == null || (nextRedistributor.Range.StartAddress - currentRedistributor.Range.EndAddress) > 1; 2596 }) 2597 .WithFlag(3, FieldMode.Read, name: "LocalitySpecificInterruptDirectInjectionSupport", 2598 valueProviderCallback: _ => false 2599 ) 2600 .WithTaggedFlag("DirtyBitControl", 2) 2601 .WithFlag(1, FieldMode.Read, name: "VirtualLocalitySpecificInterruptSupport", 2602 valueProviderCallback: _ => false 2603 ) 2604 .WithFlag(0, FieldMode.Read, name: "PhysicalLocalitySpecificInterruptSupport", 2605 valueProviderCallback: _ => false 2606 ) 2607 } 2608 }; 2609 2610 return registerMap; 2611 } 2612 BuildRedistributorDoubleWordRegisterMap()2613 private Dictionary<long, DoubleWordRegister> BuildRedistributorDoubleWordRegisterMap() 2614 { 2615 var registerMap = new Dictionary<long, DoubleWordRegister> 2616 { 2617 {(long)RedistributorRegisters.Control, new DoubleWordRegister(this) 2618 .WithFlag(31, FieldMode.Read, name: "UpstreamWritePending", 2619 valueProviderCallback: _ => false 2620 ) 2621 .WithReservedBits(27, 4) 2622 .WithTaggedFlag("DisableProcessorSelectionGroup1Secure", 26) 2623 .WithTaggedFlag("DisableProcessorSelectionGroup1NonSecure", 25) 2624 .WithTaggedFlag("DisableProcessorSelectionGroup0", 24) 2625 .WithReservedBits(4, 20) 2626 .WithFlag(3, FieldMode.Read, name: "RegisterWritePending", 2627 valueProviderCallback: _ => false 2628 ) 2629 .WithFlag(2, FieldMode.Read, name: "LocalitySpecificInterruptInvalidateSupport", 2630 valueProviderCallback: _ => false 2631 ) 2632 .WithFlag(1, FieldMode.Read, name: "LocalitySpecificInterruptClearEnableSupport", 2633 valueProviderCallback: _ => false 2634 ) 2635 .WithTaggedFlag("LocalitySpecificInterruptEnable", 0) 2636 }, 2637 {(long)RedistributorRegisters.ImplementerIdentification, new DoubleWordRegister(this) 2638 .WithValueField(24, 8, FieldMode.Read, name: "ProductID", valueProviderCallback: _ => gic.RedistributorProductIdentifier) 2639 .WithReservedBits(20, 4) 2640 .WithValueField(16, 4, FieldMode.Read, name: "Variant", valueProviderCallback: _ => gic.RedistributorVariant) 2641 .WithValueField(12, 4, FieldMode.Read, name: "Revision", valueProviderCallback: _ => gic.RedistributorRevision) 2642 .WithValueField(0, 12, FieldMode.Read, name: "Implementer", valueProviderCallback: _ => gic.RedistributorImplementer) 2643 }, 2644 {(long)RedistributorRegisters.Wake, new DoubleWordRegister(this, 0x1) 2645 // "There is only one GICR_WAKER.Sleep and one GICR_WAKER.Quiescent bit that can be read and written through the GICR_WAKER register of any Redistributor." 2646 .WithTaggedFlag("Quiescent", 31) 2647 .WithReservedBits(3, 28) 2648 .WithFlag(2, FieldMode.Read, name: "ChildrenAsleep", 2649 valueProviderCallback: _ => this.IsSleeping 2650 ) 2651 .WithFlag(1, name: "ProcessorSleep", 2652 writeCallback: (_, val) => this.IsSleeping = val, 2653 valueProviderCallback: _ => this.IsSleeping 2654 ) 2655 .WithTaggedFlag("Sleep", 0) 2656 // According to the reference manual this register should be RAZ/WI for an unsecure access, but we just show a warning in such a situation. 2657 .WithWriteCallback((_, __) => { if(!gic.DisabledSecurity && !this.IsStateSecure) this.Log(LogLevel.Warning, "Writing to the GICR_WAKER register from wrong security state."); }) 2658 .WithReadCallback((_, __) => { if(!gic.DisabledSecurity && !this.IsStateSecure) this.Log(LogLevel.Warning, "Reading from the GICR_WAKER register from wrong security state."); }) 2659 }, 2660 {(long)RedistributorRegisters.NonSecureAccessControl, new DoubleWordRegister(this) 2661 .WithEnumFields<DoubleWordRegister, NonSecureAccess>(0, 2, 16, name: "NS_access", 2662 writeCallback: (i, _, val) => 2663 { 2664 if(!gic.IsAffinityRoutingEnabled(this)) 2665 { 2666 NonSecureSGIAccess[i] = val; 2667 } 2668 }, 2669 valueProviderCallback: (i, _) => !gic.IsAffinityRoutingEnabled(this) ? (NonSecureAccess)0 : NonSecureSGIAccess[i] 2670 ) 2671 // Those could be emitted in valueProvider/writeCallback instead, 2672 // but we don't want to emit the same warning 16 times per access. 2673 .WithWriteCallback((_, __) => 2674 { 2675 if(!gic.IsAffinityRoutingEnabled(this)) 2676 { 2677 this.Log(LogLevel.Warning, "Tried to write to GICR_NSACR when affinity routing is disabled. Access ignored, use GICD_NSACR0 instead."); 2678 } 2679 }) 2680 .WithReadCallback((_, __) => 2681 { 2682 if(!gic.IsAffinityRoutingEnabled(this)) 2683 { 2684 this.Log(LogLevel.Warning, "Tried to read from GICR_NSACR when affinity routing is disabled. Access ignored, use GICD_NSACR0 instead."); 2685 } 2686 }) 2687 }, 2688 {gic.PeripheralIdentificationOffset, new DoubleWordRegister(this) 2689 .WithReservedBits(8, 24) 2690 .WithEnumField<DoubleWordRegister, ARM_GenericInterruptControllerVersion>(4, 4, FieldMode.Read, name: "ArchitectureVersion", 2691 valueProviderCallback: _ => gic.ArchitectureVersion 2692 ) 2693 .WithTag("ImplementationDefinedIdentificator", 0, 4) 2694 } 2695 }; 2696 2697 Utils.AddRegistersAtOffset(registerMap, (long)RedistributorRegisters.InterruptSetEnable_0, 2698 gic.BuildInterruptSetEnableRegisters(gic.IrqsDecoder.SoftwareGeneratedFirst, gic.IrqsDecoder.PrivatePeripheralLast, "InterruptSetEnable", 2699 cpuEntryProvider: () => this) 2700 ); 2701 2702 Utils.AddRegistersAtOffset(registerMap, (long)RedistributorRegisters.InterruptClearEnable_0, 2703 gic.BuildInterruptClearEnableRegisters(gic.IrqsDecoder.SoftwareGeneratedFirst, gic.IrqsDecoder.PrivatePeripheralLast, "InterruptClearEnable", 2704 cpuEntryProvider: () => this) 2705 ); 2706 2707 Utils.AddRegistersAtOffset(registerMap, (long)RedistributorRegisters.InterruptClearPending_0, 2708 gic.BuildInterruptClearPendingRegisters(gic.IrqsDecoder.SoftwareGeneratedFirst, gic.IrqsDecoder.PrivatePeripheralLast, "InterruptClearPending", 2709 cpuEntryProvider: () => this) 2710 ); 2711 2712 Utils.AddRegistersAtOffset(registerMap, (long)RedistributorRegisters.InterruptPriority_0, 2713 gic.BuildInterruptPriorityRegisters(gic.IrqsDecoder.SoftwareGeneratedFirst, gic.IrqsDecoder.PrivatePeripheralLast, "InterruptPriority", 2714 cpuEntryProvider: () => this) 2715 ); 2716 2717 Utils.AddRegistersAtOffset(registerMap, (long)RedistributorRegisters.PrivatePeripheralInterruptConfiguration, 2718 gic.BuildInterruptConfigurationRegisters(gic.IrqsDecoder.PrivatePeripheralFirst, gic.IrqsDecoder.PrivatePeripheralLast, "PrivatePeripheralInterruptConfiguration", 2719 cpuEntryProvider: () => this) 2720 ); 2721 2722 Utils.AddRegistersAtOffset(registerMap, (long)RedistributorRegisters.InterruptGroup_0, 2723 gic.BuildInterruptGroupRegisters(gic.IrqsDecoder.SoftwareGeneratedFirst, gic.IrqsDecoder.PrivatePeripheralLast, "InterruptGroup", 2724 cpuEntryProvider: () => this) 2725 ); 2726 2727 Utils.AddRegistersAtOffset(registerMap, (long)RedistributorRegisters.InterruptGroupModifier_0, 2728 gic.BuildInterruptGroupModifierRegisters(gic.IrqsDecoder.SoftwareGeneratedFirst, gic.IrqsDecoder.PrivatePeripheralLast, "InterruptGroupModifier", 2729 cpuEntryProvider: () => this) 2730 ); 2731 2732 return registerMap; 2733 } 2734 2735 private bool isSleeping = true; 2736 private readonly IARMSingleSecurityStateCPU cpu; 2737 private readonly IReadOnlyDictionary<InterruptSignalType, IGPIO> interruptSignals; 2738 private readonly QuadWordRegisterCollection redistributorQuadWordRegisters; 2739 private readonly DoubleWordRegisterCollection redistributorDoubleWordRegisters; 2740 2741 public class GroupCollection 2742 { GroupCollection(CPUEntry cpu, IEnumerable<GroupType> groupTypes)2743 public GroupCollection(CPUEntry cpu, IEnumerable<GroupType> groupTypes) 2744 { 2745 this.cpu = cpu; 2746 Physical = new ReadOnlyDictionary<GroupType, InterruptGroup>(groupTypes.ToDictionary(type => type, _ => new InterruptGroup())); 2747 Virtual = new ReadOnlyDictionary<GroupType, InterruptGroup>(groupTypes.ToDictionary(type => type, _ => new InterruptGroup())); 2748 } 2749 Reset()2750 public void Reset() 2751 { 2752 foreach(var group in Physical.Values) 2753 { 2754 group.Reset(); 2755 } 2756 foreach(var group in Virtual.Values) 2757 { 2758 group.Reset(); 2759 } 2760 } 2761 2762 public InterruptGroup this[GroupType type] => cpu.IsVirtualized(type) ? Virtual[type] : Physical[type]; 2763 public IReadOnlyDictionary<GroupType, InterruptGroup> Physical { get; } 2764 public IReadOnlyDictionary<GroupType, InterruptGroup> Virtual { get; } 2765 2766 private readonly CPUEntry cpu; 2767 } 2768 } 2769 2770 public class RunningInterrupts 2771 { RunningInterrupts(CPUEntry cpu)2772 public RunningInterrupts(CPUEntry cpu) 2773 { 2774 this.cpu = cpu; 2775 Physical = new Stack<Interrupt>(); 2776 Virtual = new Stack<VirtualInterrupt>(); 2777 activeVirtual = new Dictionary<InterruptId, VirtualInterrupt>(); 2778 } 2779 Clear()2780 public void Clear() 2781 { 2782 Physical.Clear(); 2783 Virtual.Clear(); 2784 activeVirtual.Clear(); 2785 } 2786 Push(GroupType type, Interrupt interrupt)2787 public void Push(GroupType type, Interrupt interrupt) 2788 { 2789 if(!interrupt.State.Active) 2790 { 2791 throw new ArgumentException("Trying to push inactive interrupt to interrupt stack"); 2792 } 2793 if(cpu.IsVirtualized(type)) 2794 { 2795 if(interrupt is VirtualInterrupt virtualInterrupt) 2796 { 2797 // GICv3 only has a maximum of 16 List Registers. 2798 // To allow the hypervisor to manage more virtual interrutps 2799 // than the implementation has list registers, 2800 // the LRs only act as a "cache" of the virtual interrupts. 2801 // The only requirement is that for a pending virtual interrupt to be raised, 2802 // it has to be in a list register. 2803 // This means that once we're acknowledging the interrupt, we're "cutting it off" 2804 // from the List Register, and the hypervisor is free to 2805 // reuse that LR to schedule another interrupt. 2806 // However, both the active and the list-register interrupts, 2807 // provided they have the same virtual identifier set, 2808 // have to be kept in sync, which is what the VirtualInterrupt.Sync method is used for. 2809 var cloned = virtualInterrupt.Clone(); 2810 Virtual.Push(cloned); 2811 activeVirtual.Add(cloned.Identifier, cloned); 2812 } 2813 else 2814 { 2815 throw new ArgumentException("Trying to push physical interrupt to virtual interrupt stack"); 2816 } 2817 } 2818 else 2819 { 2820 if(interrupt is VirtualInterrupt) 2821 { 2822 throw new ArgumentException("Trying to push virtual interrupt to physical interrupt stack"); 2823 } 2824 else 2825 { 2826 Physical.Push(interrupt); 2827 } 2828 } 2829 } 2830 Pop(GroupType type)2831 public Interrupt Pop(GroupType type) 2832 { 2833 return cpu.IsVirtualized(type) ? Virtual.Pop() : Physical.Pop(); 2834 } 2835 Peek(GroupType type)2836 public Interrupt Peek(GroupType type) 2837 { 2838 return cpu.IsVirtualized(type) ? Virtual.Peek() : Physical.Peek(); 2839 } 2840 Count(GroupType type)2841 public int Count(GroupType type) 2842 { 2843 return cpu.IsVirtualized(type) ? Virtual.Count : Physical.Count; 2844 } 2845 GetActiveVirtual(InterruptId id)2846 public VirtualInterrupt GetActiveVirtual(InterruptId id) 2847 { 2848 VirtualInterrupt result; 2849 var present = activeVirtual.TryGetValue(id, out result); 2850 return present ? result : null; 2851 } 2852 RemoveActiveVirtual(InterruptId id)2853 public void RemoveActiveVirtual(InterruptId id) 2854 { 2855 activeVirtual.Remove(id); 2856 } 2857 2858 public InterruptPriority Priority => cpu.IsVirtualized() ? VirtualPriority : PhysicalPriority; 2859 public Stack<Interrupt> Physical { get; } 2860 public InterruptPriority PhysicalPriority => Physical.Count > 0 ? Physical.Peek().Config.Priority : InterruptPriority.Idle; 2861 public Stack<VirtualInterrupt> Virtual { get; } 2862 public InterruptPriority VirtualPriority => Virtual.Count > 0 ? Virtual.Peek().Config.Priority : InterruptPriority.Idle; 2863 2864 private readonly Dictionary<InterruptId, VirtualInterrupt> activeVirtual; 2865 private readonly CPUEntry cpu; 2866 } 2867 2868 public class CPUEntryWithTwoSecurityStates : CPUEntry 2869 { CPUEntryWithTwoSecurityStates(ARM_GenericInterruptController gic, IARMTwoSecurityStatesCPU cpu, IEnumerable<GroupType> groupTypes, IReadOnlyDictionary<InterruptSignalType, IGPIO> interruptConnections)2870 public CPUEntryWithTwoSecurityStates(ARM_GenericInterruptController gic, IARMTwoSecurityStatesCPU cpu, IEnumerable<GroupType> groupTypes, IReadOnlyDictionary<InterruptSignalType, IGPIO> interruptConnections) 2871 : base(gic, cpu, groupTypes, interruptConnections) 2872 { 2873 this.cpu = cpu; 2874 } 2875 Reset()2876 public override void Reset() 2877 { 2878 EndOfInterruptModeEL3 = EndOfInterruptModes.PriorityDropAndDeactivation; 2879 base.Reset(); 2880 } 2881 AcknowledgeBestPending(GroupTypeSecurityAgnostic groupTypeRegister, out CPUEntry sgiRequestingCPU)2882 public override InterruptId AcknowledgeBestPending(GroupTypeSecurityAgnostic groupTypeRegister, out CPUEntry sgiRequestingCPU) 2883 { 2884 sgiRequestingCPU = null; 2885 if(BestPending != null && groupTypeRegister == GroupTypeSecurityAgnostic.Group0 && cpu.ExceptionLevel == ExceptionLevel.EL3_MonitorMode) 2886 { 2887 if(BestPending.Config.GroupType == GroupType.Group1Secure) 2888 { 2889 return gic.IrqsDecoder.ExpectedToHandleAtSecure; 2890 } 2891 else if(BestPending.Config.GroupType == GroupType.Group1NonSecure) 2892 { 2893 return gic.IrqsDecoder.ExpectedToHandleAtNonSecure; 2894 } 2895 } 2896 return base.AcknowledgeBestPending(groupTypeRegister, out sgiRequestingCPU); 2897 } 2898 2899 public override string CurrentCPUSecurityStateString => $"{cpu.ExceptionLevel}, {cpu.SecurityState}" + (gic.DisabledSecurity ? " (GIC security disabled)" : ""); 2900 public override EndOfInterruptModes CurrentEndOfInterruptMode => cpu.ExceptionLevel == ExceptionLevel.EL3_MonitorMode ? EndOfInterruptModeEL3 : EndOfInterruptModeEL1; 2901 public EndOfInterruptModes EndOfInterruptModeEL3 { get; set; } 2902 GetBestPendingInterruptSignalType()2903 protected override InterruptSignalType GetBestPendingInterruptSignalType() 2904 { 2905 // Based on the "4.6.2 Interrupt assignment to IRQ and FIQ signals" subsection of GICv3 and GICv4 Architecture Specification 2906 if(BestPending == null || cpu.HasSingleSecurityState || gic.DisabledSecurity) 2907 { 2908 return base.GetBestPendingInterruptSignalType(); 2909 } 2910 2911 var groupType = BestPending.Config.GroupType; 2912 cpu.GetAtomicExceptionLevelAndSecurityState(out var exceptionLevel, out var securityState); 2913 if(groupType == GroupType.Group0 2914 || (groupType == GroupType.Group1NonSecure && securityState == SecurityState.Secure) // Includes the case when the current EL is EL3_MonitorMode 2915 || (groupType == GroupType.Group1Secure && securityState == SecurityState.NonSecure) 2916 || (groupType == GroupType.Group1Secure && exceptionLevel == ExceptionLevel.EL3_MonitorMode && !cpu.IsEL3UsingAArch32State)) 2917 { 2918 return InterruptSignalType.FIQ; 2919 } 2920 return InterruptSignalType.IRQ; 2921 } 2922 2923 private readonly IARMTwoSecurityStatesCPU cpu; 2924 } 2925 2926 public class InterruptState 2927 { InterruptState()2928 public InterruptState() 2929 { 2930 TriggerType = DefaultTriggerType; 2931 } 2932 Reset()2933 public virtual void Reset() 2934 { 2935 Active = false; 2936 Pending = false; 2937 TriggerType = DefaultTriggerType; 2938 } 2939 Acknowledge()2940 public void Acknowledge() 2941 { 2942 if(!Pending || Active) 2943 { 2944 throw new InvalidOperationException("It's invalid to acknowledge an interrupt not in the pending state."); 2945 } 2946 if(TriggerType == InterruptTriggerType.EdgeTriggered) 2947 { 2948 Active = true; 2949 Pending = false; 2950 } 2951 else if(TriggerType == InterruptTriggerType.LevelSensitive) 2952 { 2953 Active = true; 2954 Pending = true; 2955 } 2956 } 2957 AssertAsPending(bool signal)2958 public void AssertAsPending(bool signal) 2959 { 2960 if(TriggerType == InterruptTriggerType.EdgeTriggered) 2961 { 2962 Pending |= signal; 2963 } 2964 else if(TriggerType == InterruptTriggerType.LevelSensitive) 2965 { 2966 Pending = signal; 2967 } 2968 } 2969 2970 public bool Active { get; set; } 2971 public bool IsInactive => !Active && !Pending; 2972 public bool Pending { get; set; } 2973 public ulong Bits 2974 { 2975 get => (Active ? 0b10ul : 0) | (Pending ? 0b01ul : 0); 2976 set 2977 { 2978 bool active = (value & 0b10) != 0; 2979 bool pending = (value & 1) != 0; 2980 Active = active; 2981 Pending = pending; 2982 } 2983 } 2984 public virtual InterruptTriggerType TriggerType { get; set; } 2985 2986 protected virtual InterruptTriggerType DefaultTriggerType => default(InterruptTriggerType); 2987 } 2988 2989 public class InterruptConfig 2990 { Reset()2991 public virtual void Reset() 2992 { 2993 Enabled = false; 2994 GroupBit = false; 2995 GroupModifierBit = false; 2996 Priority = default(InterruptPriority); 2997 } 2998 2999 public bool Enabled { get; set; } 3000 public bool GroupBit { get; set; } 3001 public bool GroupModifierBit { get; set; } 3002 public InterruptPriority Priority { get; set; } 3003 3004 public GroupType GroupType 3005 { 3006 get 3007 { 3008 if(GroupBit) 3009 { 3010 return GroupType.Group1NonSecure; 3011 } 3012 else if(GroupModifierBit) 3013 { 3014 return GroupType.Group1Secure; 3015 } 3016 else 3017 { 3018 return GroupType.Group0; 3019 } 3020 } 3021 } 3022 } 3023 3024 public class Interrupt 3025 { Interrupt(InterruptId identifier)3026 public Interrupt(InterruptId identifier) : base() 3027 { 3028 Identifier = identifier; 3029 } 3030 Reset()3031 public virtual void Reset() 3032 { 3033 Config.Reset(); 3034 State.Reset(); 3035 } 3036 3037 public InterruptId Identifier { get; protected set; } 3038 public virtual InterruptConfig Config { get; } = new InterruptConfig(); 3039 public virtual InterruptState State { get; } = new InterruptState(); 3040 } 3041 3042 public class SoftwareGeneratedInterruptState : InterruptState 3043 { 3044 public override InterruptTriggerType TriggerType 3045 { 3046 get => DefaultTriggerType; 3047 set 3048 { 3049 if(value != TriggerType) 3050 { 3051 throw new InvalidOperationException("SoftwareGeneratedInterrupt has constant trigger type."); 3052 } 3053 } 3054 } 3055 3056 protected override InterruptTriggerType DefaultTriggerType => InterruptTriggerType.EdgeTriggered; 3057 } 3058 3059 public class VirtualInterrupt : Interrupt 3060 { VirtualInterrupt()3061 public VirtualInterrupt() : base(new InterruptId(0)) 3062 { 3063 Reset(); 3064 } 3065 Reset()3066 public override void Reset() 3067 { 3068 base.Reset(); 3069 State.TriggerType = InterruptTriggerType.EdgeTriggered; 3070 Identifier = new InterruptId(0); 3071 HardwareIdentifier = new InterruptId(0); 3072 Hardware = false; 3073 } 3074 3075 // Performs a deep clone of the Virtual Interrupt. Clone()3076 public VirtualInterrupt Clone() 3077 { 3078 var cloned = new VirtualInterrupt(); 3079 cloned.Sync(this); 3080 return cloned; 3081 } 3082 SetIdentifier(uint id)3083 public void SetIdentifier(uint id) 3084 { 3085 Identifier = new InterruptId(id); 3086 } 3087 SetHardwareIdentifier(uint id)3088 public void SetHardwareIdentifier(uint id) 3089 { 3090 HardwareIdentifier = new InterruptId(id); 3091 } 3092 Sync(VirtualInterrupt other)3093 public void Sync(VirtualInterrupt other) 3094 { 3095 this.Identifier = other.Identifier; 3096 this.HardwareIdentifier = other.HardwareIdentifier; 3097 this.Hardware = other.Hardware; 3098 this.State.Bits = other.State.Bits; 3099 this.Config.GroupBit = other.Config.GroupBit; 3100 this.Config.Priority = other.Config.Priority; 3101 } 3102 3103 public InterruptId HardwareIdentifier { get; protected set; } 3104 public bool Hardware { get; set; } 3105 3106 public bool EOIMaitenance => !Hardware && EOIMaintenanceBit; 3107 3108 private bool EOIMaintenanceBit => ((uint)HardwareIdentifier & (1 << 9)) != 0; 3109 } 3110 3111 public class SoftwareGeneratedInterrupt : Interrupt 3112 { SoftwareGeneratedInterrupt(InterruptId irqId, InterruptConfig config, CPUEntry requester)3113 public SoftwareGeneratedInterrupt(InterruptId irqId, InterruptConfig config, CPUEntry requester) : base(irqId) 3114 { 3115 // Software Generated Interrupts with a same requester share a config. 3116 Config = config; 3117 Requester = requester; 3118 } 3119 3120 public override InterruptConfig Config { get; } 3121 public override InterruptState State { get; } = new SoftwareGeneratedInterruptState(); 3122 // The null value indicates that the Requester is unknown, what is typical for a GICv3 with Affinity Routing enabled. 3123 public CPUEntry Requester { get; } 3124 } 3125 3126 public class SharedInterrupt : Interrupt 3127 { SharedInterrupt(InterruptId irqId)3128 public SharedInterrupt(InterruptId irqId) : base(irqId) { } 3129 Reset()3130 public override void Reset() 3131 { 3132 base.Reset(); 3133 TargetCPUs = 0; 3134 } 3135 IsLegacyRoutingTargetingCPU(CPUEntry cpu)3136 public bool IsLegacyRoutingTargetingCPU(CPUEntry cpu) 3137 { 3138 return (TargetCPUs & cpu.TargetFieldFlag) != 0; 3139 } 3140 IsLowestLegacyRoutingTargettedCPU(CPUEntry cpu)3141 public bool IsLowestLegacyRoutingTargettedCPU(CPUEntry cpu) 3142 { 3143 return (TargetCPUs & (cpu.TargetFieldFlag - 1)) == 0; 3144 } 3145 IsAffinityRoutingTargetingCPU(CPUEntry cpu)3146 public bool IsAffinityRoutingTargetingCPU(CPUEntry cpu) 3147 { 3148 if(RoutingMode == InterruptRoutingMode.AnyTarget || TargetAffinity.AllLevels == cpu.Affinity.AllLevels) 3149 { 3150 return cpu.IsParticipatingInRouting; 3151 } 3152 return false; 3153 } 3154 IsLowestAffinityRoutingTargettedCPU(CPUEntry cpu, ARM_GenericInterruptController gic)3155 public bool IsLowestAffinityRoutingTargettedCPU(CPUEntry cpu, ARM_GenericInterruptController gic) 3156 { 3157 return cpu.IsParticipatingInRouting && (RoutingMode == InterruptRoutingMode.SpecifiedTarget ? TargetAffinity.AllLevels == cpu.Affinity.AllLevels : cpu == gic.ForcedTargettingCpuForAffinityRouting); 3158 } 3159 3160 public byte TargetCPUs { get; set; } 3161 public MutableAffinity TargetAffinity { get; } = new MutableAffinity(); 3162 public InterruptRoutingMode RoutingMode { get; set; } 3163 } 3164 3165 // This class will be extended at least for the Binary Point register support 3166 // It may be needed to separate it for CPUInterface and Distributor 3167 public class InterruptGroup 3168 { Reset()3169 public void Reset() 3170 { 3171 Enabled = false; 3172 } 3173 3174 public bool Enabled { get; set; } 3175 } 3176 3177 public struct InterruptId 3178 { GetRangeAntmicro.Renode.Peripherals.IRQControllers.InterruptId3179 public static IEnumerable<InterruptId> GetRange(InterruptId start, InterruptId end, uint step = 1) 3180 { 3181 for(var id = (uint)start; id <= (uint)end; id += step) 3182 { 3183 yield return new InterruptId(id); 3184 } 3185 } 3186 3187 public static explicit operator uint(InterruptId id) => id.id; 3188 public static explicit operator int(InterruptId id) => (int)id.id; 3189 InterruptIdAntmicro.Renode.Peripherals.IRQControllers.InterruptId3190 public InterruptId(uint interruptId) 3191 { 3192 id = interruptId; 3193 } 3194 ToStringAntmicro.Renode.Peripherals.IRQControllers.InterruptId3195 public override string ToString() 3196 { 3197 return $"{id}"; 3198 } 3199 3200 private readonly uint id; 3201 } 3202 3203 public class InterruptsDecoder 3204 { InterruptsDecoder(uint sharedPeripheralCount, uint identifierBits)3205 public InterruptsDecoder(uint sharedPeripheralCount, uint identifierBits) 3206 { 3207 this.sharedPeripheralCount = sharedPeripheralCount; 3208 this.identifierBits = identifierBits; 3209 3210 sharedPeripheralLast = new InterruptId((uint)SharedPeripheralFirst + sharedPeripheralCount - 1); 3211 extendedSharedPeripheralLast = new InterruptId((uint)extendedSharedPeripheralFirst + SharedPeripheralExtendedCount - 1); 3212 } 3213 Type(InterruptId id)3214 public InterruptType Type(InterruptId id) 3215 { 3216 if(IsSoftwareGenerated(id)) 3217 { 3218 return InterruptType.SoftwareGenerated; 3219 } 3220 else if(IsPrivatePeripheral(id)) 3221 { 3222 return InterruptType.PrivatePeripheral; 3223 } 3224 else if(IsSharedPeripheral(id)) 3225 { 3226 return InterruptType.SharedPeripheral; 3227 } 3228 else if(IsSpecial(id)) 3229 { 3230 return InterruptType.SpecialIdentifier; 3231 } 3232 else if(IsLocalitySpecificPeripheral(id)) 3233 { 3234 return InterruptType.LocalitySpecificPeripheral; 3235 } 3236 return InterruptType.Reserved; 3237 } 3238 3239 public bool IsSoftwareGenerated(InterruptId id) => (uint)id <= (uint)SoftwareGeneratedLast; 3240 3241 public bool IsPrivatePeripheral(InterruptId id) => ((uint)PrivatePeripheralFirst <= (uint)id && (uint)id <= (uint)PrivatePeripheralLast) 3242 || ((uint)ExtendedPrivatePeripheralFirst <= (uint)id && (uint)id <= (uint)ExtendedPrivatePeripheralLast); 3243 3244 public bool IsSharedPeripheral(InterruptId id) => ((uint)SharedPeripheralFirst <= (uint)id && (uint)id <= (uint)SharedPeripheralLast) 3245 || ((uint)ExtendedSharedPeripheralFirst <= (uint)id && (uint)id <= (uint)ExtendedSharedPeripheralLast); 3246 3247 public bool IsSpecial(InterruptId id) => (uint)ExpectedToHandleAtSecure <= (uint)id && (uint)id <= (uint)NoPending; 3248 3249 public bool IsLocalitySpecificPeripheral(InterruptId id) => (uint)id <= (uint)LocalitySpecificPeripheralFirst; 3250 3251 public InterruptId SoftwareGeneratedFirst => softwareGeneratedFirst; 3252 public InterruptId SoftwareGeneratedLast => softwareGeneratedLast; 3253 public InterruptId PrivatePeripheralFirst => privatePeripheralFirst; 3254 public InterruptId PrivatePeripheralLast => privatePeripheralLast; 3255 public InterruptId SharedPeripheralFirst => sharedPeripheralFirst; 3256 public InterruptId SharedPeripheralLast => sharedPeripheralLast; 3257 public InterruptId ExpectedToHandleAtSecure => expectedToHandleAtSecure; 3258 public InterruptId ExpectedToHandleAtNonSecure => expectedToHandleAtNonSecure; 3259 public InterruptId NonMaskableInterruptOrGICv2GroupMismatch => nonMaskableInterruptOrGICv2GroupMismatch; 3260 public InterruptId NoPending => noPending; 3261 public InterruptId ExtendedPrivatePeripheralFirst => extendedPrivatePeripheralFirst; 3262 public InterruptId ExtendedPrivatePeripheralLast => extendedPrivatePeripheralLast; 3263 public InterruptId ExtendedSharedPeripheralFirst => extendedSharedPeripheralFirst; 3264 public InterruptId ExtendedSharedPeripheralLast => extendedSharedPeripheralLast; 3265 public InterruptId LocalitySpecificPeripheralFirst => localitySpecificPeripheralFirst; 3266 public uint IdentifierBits => identifierBits; 3267 3268 public readonly uint SharedPeripheralExtendedCount = 1024; 3269 3270 private readonly InterruptId softwareGeneratedFirst = new InterruptId(0); 3271 private readonly InterruptId softwareGeneratedLast = new InterruptId(15); 3272 private readonly InterruptId privatePeripheralFirst = new InterruptId(16); 3273 private readonly InterruptId privatePeripheralLast = new InterruptId(31); 3274 private readonly InterruptId sharedPeripheralFirst = new InterruptId(32); 3275 private readonly InterruptId sharedPeripheralLast; // set in the constructor 3276 private readonly InterruptId expectedToHandleAtSecure = new InterruptId(1020); 3277 private readonly InterruptId expectedToHandleAtNonSecure = new InterruptId(1021); 3278 private readonly InterruptId nonMaskableInterruptOrGICv2GroupMismatch = new InterruptId(1022); 3279 private readonly InterruptId noPending = new InterruptId(1023); 3280 private readonly InterruptId extendedPrivatePeripheralFirst = new InterruptId(1056); 3281 private readonly InterruptId extendedPrivatePeripheralLast = new InterruptId(1119); 3282 private readonly InterruptId extendedSharedPeripheralFirst = new InterruptId(4096); 3283 private readonly InterruptId extendedSharedPeripheralLast; // set in the constructor 3284 private readonly InterruptId localitySpecificPeripheralFirst = new InterruptId(819); 3285 3286 private readonly uint sharedPeripheralCount; 3287 private readonly uint identifierBits; 3288 3289 public const uint MaximumSharedPeripheralCount = 988; 3290 public const uint SoftwareGeneratedCount = 16; 3291 } 3292 3293 public struct SoftwareGeneratedInterruptRequest 3294 { SoftwareGeneratedInterruptRequestAntmicro.Renode.Peripherals.IRQControllers.SoftwareGeneratedInterruptRequest3295 public SoftwareGeneratedInterruptRequest(TargetType type, Affinity[] list, GroupType group, InterruptId id) 3296 { 3297 TargetCPUsType = type; 3298 TargetsList = list; 3299 TargetGroup = group; 3300 InterruptId = id; 3301 } 3302 3303 public TargetType TargetCPUsType { get; } 3304 public Affinity[] TargetsList { get; } 3305 public GroupType TargetGroup { get; } 3306 public InterruptId InterruptId { get; } 3307 3308 public enum TargetType 3309 { 3310 TargetList = 0b00, 3311 AllCPUs = 0b01, 3312 Loopback = 0b10 3313 } 3314 } 3315 3316 public enum NonSecureAccess 3317 { 3318 NotPermitted = 0b00, 3319 SecureGroup0Permitted = 0b01, 3320 BothGroupsPermitted = 0b10, 3321 Reserved = 0b11, 3322 } 3323 3324 public enum EndOfInterruptModes 3325 { 3326 PriorityDropAndDeactivation = 0, 3327 PriorityDropOnly = 1, 3328 } 3329 3330 public enum InterruptPriority : byte 3331 { 3332 Highest = 0x00, 3333 Idle = 0xFF 3334 } 3335 3336 public enum InterruptTriggerType : byte 3337 { 3338 LevelSensitive = 0b00, 3339 EdgeTriggered = 0b10 3340 } 3341 3342 public enum InterruptRoutingMode : byte 3343 { 3344 SpecifiedTarget = 0b0, 3345 AnyTarget = 0b1 3346 } 3347 3348 public enum InterruptType 3349 { 3350 SoftwareGenerated, 3351 PrivatePeripheral, 3352 SharedPeripheral, 3353 SpecialIdentifier, 3354 LocalitySpecificPeripheral, 3355 Reserved 3356 } 3357 3358 public enum GroupType 3359 { 3360 Group0, 3361 Group1NonSecure, 3362 Group1Secure, 3363 Group1 = Group1NonSecure, 3364 } 3365 3366 public enum GroupTypeSecurityAgnostic 3367 { 3368 Group0, 3369 Group1 3370 } 3371 3372 public enum DistributorRegisters : long 3373 { 3374 Control = 0x0000, // GICD_CTLR 3375 ControllerType = 0x0004, // GICD_TYPER 3376 ImplementerIdentification = 0x0008, // GICD_IIDR 3377 ControllerType2 = 0x000C2, // GICD_TYPER2 3378 ErrorReportingStatus = 0x0010, // GICD_STATUSR 3379 SharedPeripheralInterruptSetNonSecure = 0x0040, // GICD_SETSPI_NSR 3380 SharedPeripheralInterruptClearNonSecure = 0x0048, // GICD_CLRSPI_NSR 3381 SharedPeripheralInterruptSetSecure = 0x0050, // GICD_SETSPI_SR 3382 SharedPeripheralInterruptClearSecure = 0x0058, // GICD_CLRSPI_SR 3383 InterruptGroup_0 = 0x0080, // GICD_IGROUPR<n> 3384 InterruptSetEnable_0 = 0x0100, // GICD_ISENABLER<n> 3385 InterruptClearEnable_0 = 0x0180, // GICD_ICENABLER<n> 3386 InterruptSetPending_0 = 0x0200, // GICD_ISPENDR<n> 3387 InterruptClearPending_0 = 0x0280, // GICD_ICPENDR<n> 3388 InterruptSetActive_0 = 0x0300, // GICD_ISACTIVER<n> 3389 InterruptClearActive_0 = 0x0380, // GICD_ICACTIVER<n> 3390 InterruptPriority_0 = 0x0400, // GICD_IPRIORITYR<n> 3391 InterruptPriority_254 = 0x07F8, // GICD_IPRIORITYR<n> 3392 InterruptProcessorTargets_0 = 0x0800, // GICD_ITARGETSR<n> 3393 InterruptProcessorTargets_8 = 0x0820, // GICD_ITARGETSR<n> 3394 InterruptProcessorTargets_254 = 0x0AF8, // GICD_ITARGETSR<n> 3395 InterruptConfiguration_0 = 0x0C00, // GICD_ICFGR<n> 3396 InterruptConfiguration_1 = 0x0C04, // GICD_ICFGR<n> 3397 InterruptGroupModifier_0_PPIStatus = 0x0D00, // GICD_IGRPMODR0 on GICv3, GICD_PPISR on GICv1/2 3398 InterruptGroupModifier_1_SPIStatus_0 = 0x0D04, // GICD_IGRPMODR<n> on GICv3, GICD_SPISR<n> on GICv1/2 3399 NonSecureAccessControl_0 = 0x0E00, // GICD_NSACR<n> 3400 SoftwareGeneratedInterruptControl = 0x0F00, // GICD_SGI 3401 SoftwareGeneratedIntrruptClearPending_0 = 0x0F10, // GICD_CPENDSGIR<n> 3402 SoftwareGeneratedIntrruptClearPending_3 = 0x0F1C, // GICD_CPENDSGIR<n> 3403 SoftwareGeneratedIntrruptSetPending_0 = 0x0F20, // GICD_SPENDSGIR<n> 3404 SoftwareGeneratedIntrruptSetPending_3 = 0x0F2C, // GICD_SPENDSGIR<n> 3405 NonMaskableInterrupt_0 = 0x0F80, // GICD_INMIR<n> 3406 PeripheralIdentification2_v1v2 = 0xFE8, // GICD_PIDR2 for GICv1 and GICv2 3407 SharedPeripheralInterruptExtendedGroup_0 = 0x1000, // GICD_IGROUPR<n>E 3408 SharedPeripheralInterruptExtendedSetEnable_0 = 0x1200, // GICD_ISENABLER<n>E 3409 SharedPeripheralInterruptExtendedClearEnable_0 = 0x1400, // GICD_ICENABLER<n>E 3410 SharedPeripheralInterruptExtendedSetPending_0 = 0x1600, // GICD_ISPENDR<n>E 3411 SharedPeripheralInterruptExtendedClearPending_0 = 0x1800, // GICD_ICPENDR<n>E 3412 SharedPeripheralInterruptExtendedSetActive_0 = 0x1A00, // GICD_ISACTIVER<n>E 3413 SharedPeripheralInterruptExtendedClearActive_0 = 0x1C00, // GICD_ICACTIVER<n>E 3414 SharedPeripheralInterruptExtendedPriority_0 = 0x2000, // GICD_IPRIORITYR<n>E 3415 SharedPeripheralInterruptExtendedConfiguration_0 = 0x3000, // GICD_ICFGR<n>E 3416 SharedPeripheralInterruptExtendedGroupModifier_0 = 0x3400, // GICD_IGRPMODR<n>E 3417 SharedPeripheralInterruptExtendedNonSecureAccessControl_0 = 0x3600, // GICD_NSACR<n>E 3418 SharedPeripheralInterruptExtendedNonMaskable_0 = 0x3B00, // GICD_INMIR<n>E 3419 InterruptRouting_0 = 0x6100, // GICD_IROUTER<n> 3420 SharedPeripheralInterruptExtendedRouting_0 = 0x8000, // GICD_IROUTER<n>E 3421 PeripheralIdentification2_v3v4 = 0xFFE8, // GICD_PIDR2 for GICv3 and GICv4 3422 } 3423 3424 public enum RedistributorRegisters : long 3425 { 3426 Control = 0x0000, // GICR_CTLR 3427 ImplementerIdentification = 0x0004, // GICR_IIDR 3428 ControllerType = 0x0008, // GICR_TYPER 3429 ErrorReportingStatus = 0x0010, // GICR_STATUSR 3430 Wake = 0x0014, // GICR_WAKER 3431 MaximumPARTIDAndPMG = 0x0018, // GICR_MPAMIDR 3432 SetPARTIDAndPMG = 0x001C, // GICR_PARTIDR 3433 SetLocalitySpecificPeripheralInterruptPending = 0x0040, // GICR_SETLPIR 3434 ClearLocalitySpecificPeripheralInterruptPending = 0x0048, // GICR_CLRLPIR 3435 PropertiesBaseAddress = 0x0070, // GICR_PROPBASER 3436 LocalitySpecificPeripheralInterruptPendingTableBaseAddress = 0x0078, // GICR_PENDBASER 3437 InvalidateLocalitySpecificPeripheralInterrupt = 0x00A0, // GICR_INVLPIR 3438 InvalidateAll = 0x00B0, // GICR_INVALLR 3439 Synchronize = 0x00C0, // GICR_SYNCR 3440 PeripheralIdentification2_v1v2 = 0xFE8, // GICR_PIDR2 for GICv1 and GICv2 3441 3442 // Registers from the SGI_base frame 3443 InterruptGroup_0 = 0x0080 + RedistributorPrivateInterruptsFrameOffset, // GICR_IGROUPR0 3444 PrivatePeripheralInterruptExtendedGroup_0 = 0x0084 + RedistributorPrivateInterruptsFrameOffset, // GICR_IGROUPR<n>E 3445 InterruptSetEnable_0 = 0x0100 + RedistributorPrivateInterruptsFrameOffset, // GICR_ISENABLER0 3446 PrivatePeripheralInterruptExtendedSetEnable_0 = 0x0104 + RedistributorPrivateInterruptsFrameOffset, // GICR_ISENABLER<n>E 3447 PrivatePeripheralInterruptExtendedClearEnable_0 = 0x0184 + RedistributorPrivateInterruptsFrameOffset, // GICR_ICENABLER<n>E 3448 InterruptClearEnable_0 = 0x0180 + RedistributorPrivateInterruptsFrameOffset, // GICR_ICENABLER0 3449 InterruptSetPending0 = 0x0200 + RedistributorPrivateInterruptsFrameOffset, // GICR_ISPENDR0 3450 PrivatePeripheralInterruptExtendedSetPending_0 = 0x0204 + RedistributorPrivateInterruptsFrameOffset, // GICR_ISPENDR<n>E 3451 InterruptClearPending_0 = 0x0280 + RedistributorPrivateInterruptsFrameOffset, // GICR_ICPENDR0 3452 PrivatePeripheralInterruptExtendedClearPending_0 = 0x0284 + RedistributorPrivateInterruptsFrameOffset, // GICR_ICPENDR<n>E 3453 InterruptSetActive_0 = 0x0300 + RedistributorPrivateInterruptsFrameOffset, // GICR_ISACTIVER0 3454 PrivatePeripheralInterruptExtendedSetActive_0 = 0x0304 + RedistributorPrivateInterruptsFrameOffset, // GICR_ISACTIVER<n>E 3455 InterruptClearActive_0 = 0x0380 + RedistributorPrivateInterruptsFrameOffset, // GICR_ICACTIVER0 3456 PrivatePeripheralInterruptExtendedClearActive_0 = 0x0384 + RedistributorPrivateInterruptsFrameOffset, // GICR_ICACTIVER<n>E 3457 InterruptPriority_0 = 0x0400 + RedistributorPrivateInterruptsFrameOffset, // GICR_IPRIORITYR<n> 3458 InterruptPriority_7 = 0x041C + RedistributorPrivateInterruptsFrameOffset, // GICR_IPRIORITYR<n> 3459 PrivatePeripheralInterruptExtendedPriority_0 = 0x0420 + RedistributorPrivateInterruptsFrameOffset, // GICR_IPRIORITYR<n>E 3460 SoftwareGeneratedInterruptConfiguration = 0x0C00 + RedistributorPrivateInterruptsFrameOffset, // GICR_ICFGR0 3461 PrivatePeripheralInterruptConfiguration = 0x0C04 + RedistributorPrivateInterruptsFrameOffset, // GICR_ICFGR1 3462 PrivatePeripheralInterruptExtendedConfiguration_0 = 0x0C08 + RedistributorPrivateInterruptsFrameOffset, // GICR_ICFGR<n>E 3463 InterruptGroupModifier_0 = 0x0D00 + RedistributorPrivateInterruptsFrameOffset, // GICR_IGRPMODR0 3464 PrivatePeripheralInterruptExtendedGroupModifier_0 = 0x0D04 + RedistributorPrivateInterruptsFrameOffset, // GICR_IGRPMODR<n>E 3465 NonSecureAccessControl = 0x0E00 + RedistributorPrivateInterruptsFrameOffset, // GICR_NSACR 3466 PrivatePeripheralInterruptNonMaskable = 0x0F80 + RedistributorPrivateInterruptsFrameOffset, // GICR_INMIR0 3467 PrivatePeripheralInterruptExtendeNonMaskable_0 = 0x0F84 + RedistributorPrivateInterruptsFrameOffset, // GICR_INMIR<n>E 3468 PeripheralIdentification2_v3v4 = 0xFFE8, // GICR_PIDR2 for GICv3 and GICv4 3469 } 3470 3471 public enum CPUInterfaceRegisters : long 3472 { 3473 Control = 0x0000, // GICC_CTLR 3474 PriorityMask = 0x0004, // GICC_PMR 3475 PriorityBinaryPoint = 0x0008, // GICC_BPR 3476 InterruptAcknowledge = 0x000C, // GICC_IAR 3477 InterruptEnd = 0x0010, // GICC_EOIR 3478 RunningPriority = 0x0014, // GICC_RPR 3479 HighestPriorityPendingInterrupt = 0x0018, // GICC_HPPIR 3480 ActivePriority = 0x001C, // GICC_ABPR 3481 InterruptAcknowledgeAlias = 0x0020, // GICC_AIAR 3482 InterruptEndAlias = 0x0024, // GICC_AEOIR 3483 HighestPriorityPendingInterruptAlias = 0x0028, // GICC_AHPPIR 3484 ErrorReportingStatus = 0x002C, // GICC_STATUSR 3485 ActivePriorities_0 = 0x00D0, // GICC_APR<n> 3486 ActivePrioritiesNonSecure_0 = 0x00E0, // GICC_NSAPR<n> 3487 InterfaceIdentification = 0x00FC, // GICC_IIDR 3488 InterruptDeactivate = 0x1000, // GICC_DIR 3489 } 3490 3491 // Those are used for both AArch32 and AArch64 registers. For AArch32, 3492 // the encoding is slightly modified (see encode_as_aarch64_register 3493 // in tlib for details) and the names are mostly the same except for 3494 // the '_ELx' suffix. 3495 public enum CPUInterfaceSystemRegisters : long 3496 { 3497 // Enum values are created from op0, op1, CRn, CRm and op2 fields of the MRS instruction 3498 SystemRegisterEnableEL3 = 0xF665, // ICC_SRE_EL3 / ICC_MSRE 3499 SystemRegisterEnableEL1 = 0xC665, // ICC_SRE_EL1 3500 PriorityMask = 0xC230, // ICC_PMR_EL1 3501 GroupEnable1 = 0xC667, // ICC_IGRPEN1_EL1 3502 ActivePriorityGroup0_0 = 0xC644, // ICC_AP0R0_EL1 3503 ActivePriorityGroup0_1 = 0xC645, // ICC_AP0R1_EL1 3504 ActivePriorityGroup0_2 = 0xC646, // ICC_AP0R2_EL1 3505 ActivePriorityGroup0_3 = 0xC647, // ICC_AP0R3_EL1 3506 ActivePriorityGroup1_0 = 0xC648, // ICC_AP1R0_EL1 3507 ActivePriorityGroup1_1 = 0xC649, // ICC_AP1R1_EL1 3508 ActivePriorityGroup1_2 = 0xC64A, // ICC_AP1R2_EL1 3509 ActivePriorityGroup1_3 = 0xC64B, // ICC_AP1R3_EL1 3510 SoftwareGeneratedInterruptGroup1GenerateAlias = 0xC65E, // ICC_ASGI1R_EL1 3511 PriorityBinaryPointGroup0 = 0xC643, // ICC_BPR0_EL1 3512 PriorityBinaryPointGroup1 = 0xC663, // ICC_BPR1_EL1 3513 ControlEL1 = 0xC664, // ICC_CTLR_EL1 3514 ControlEL3 = 0xF664, // ICC_CTLR_EL3 / ICC_MCTLR 3515 InterruptDeactivate = 0xC659, // ICC_DIR_EL1 3516 InterruptEndGroup0 = 0xC641, // ICC_EOIR0_EL1 3517 InterruptEndGroup1 = 0xC661, // ICC_EOIR1_EL1 3518 HighestPriorityPendingInterruptGroup0 = 0xC642, // ICC_HPPIR0_EL1 3519 HighestPriorityPendingInterruptGroup1 = 0xC662, // ICC_HPPIR1_EL1 3520 InterruptAcknowledgeGroup0 = 0xC640, // ICC_IAR0_EL1 3521 InterruptAcknowledgeGroup1 = 0xC660, // ICC_IAR1_EL1 3522 GroupEnable0 = 0xC666, // ICC_IGRPEN0_EL1 3523 GroupEnable1EL3 = 0xF667, // ICC_IGRPEN1_EL3 / ICC_MGRPEN1 3524 InterruptAcknowladgeNonMaskable = 0xC64D, // ICC_NMIAR1_EL1 3525 RunningPriority = 0xC65B, // ICC_RPR_EL1 3526 SoftwareGeneratedInterruptGroup0Generate = 0xC65F, // ICC_SGI0R_EL1 3527 SoftwareGeneratedInterruptGroup1Generate = 0xC65D, // ICC_SGI1R_EL1 3528 SystemRegisterEnableEL2 = 0xE64D, // ICC_SRE_EL2 3529 HypControl = 0xE658, // ICH_HCR_EL2 3530 VGICType = 0xE659, // ICH_VTR_EL2 3531 VMControl = 0xE65F, // ICH_VMCR_EL2 3532 ListRegister_0 = 0xE660, // ICH_LR<n>_EL2 3533 ListRegisterUpper_0 = 0xE670, // ICH_LRC<n> (Aarch32 only) 3534 } 3535 } 3536 3537 public enum ARM_GenericInterruptControllerVersion : byte 3538 { 3539 Default = 255, 3540 GICv1 = 1, 3541 GICv2 = 2, 3542 GICv3 = 3, 3543 GICv4 = 4 3544 } 3545 } 3546