1 // 2 // Copyright (c) 2010-2025 Antmicro 3 // Copyright (c) 2011-2015 Realtime Embedded 4 // Copyright (c) 2020-2021 Microsoft 5 // 6 // This file is licensed under the MIT License. 7 // Full license text is available in 'licenses/MIT.txt'. 8 // 9 using System; 10 using System.Collections; 11 using System.Collections.Generic; 12 using System.Linq; 13 using Antmicro.Renode.Core; 14 using Antmicro.Renode.Core.Structure.Registers; 15 using Antmicro.Renode.Debugging; 16 using Antmicro.Renode.Exceptions; 17 using Antmicro.Renode.Logging; 18 using Antmicro.Renode.Peripherals.Bus; 19 using Antmicro.Renode.Peripherals.CPU; 20 using Antmicro.Renode.Peripherals.Timers; 21 using Antmicro.Renode.Time; 22 using Antmicro.Renode.UserInterface; 23 using Antmicro.Renode.Utilities; 24 25 namespace Antmicro.Renode.Peripherals.IRQControllers 26 { 27 [AllowedTranslations(AllowedTranslation.ByteToDoubleWord | AllowedTranslation.WordToDoubleWord)] 28 public class NVIC : IDoubleWordPeripheral, IHasDivisibleFrequency, IKnownSize, IIRQController 29 { NVIC(IMachine machine, long systickFrequency = 50 * 0x800000, byte priorityMask = 0xFF, bool haltSystickOnDeepSleep = true)30 public NVIC(IMachine machine, long systickFrequency = 50 * 0x800000, byte priorityMask = 0xFF, bool haltSystickOnDeepSleep = true) 31 { 32 priorities = new ExceptionSimpleArray<byte>(); 33 activeIRQs = new Stack<int>(); 34 pendingIRQs = new SortedSet<int>(); 35 this.machine = machine; 36 this.priorityMask = priorityMask; 37 defaultHaltSystickOnDeepSleep = haltSystickOnDeepSleep; 38 binaryPointPosition = new SecurityBanked<int>(); 39 currentSevOnPending = new SecurityBanked<bool>(); 40 basepri = new SecurityBanked<byte>(); 41 ccr = new SecurityBanked<uint>(); 42 irqs = new ExceptionSimpleArray<IRQState>(); 43 targetInterruptSecurityState = new InterruptTargetSecurityState[IRQCount]; 44 IRQ = new GPIO(); 45 resetMachine = machine.RequestReset; 46 systick = new SecurityBanked<SysTick> 47 { 48 NonSecureVal = new SysTick(machine, this, systickFrequency) 49 }; 50 RegisterCollection = new DoubleWordRegisterCollection(this); 51 DefineRegisters(); 52 Reset(); 53 } 54 AttachCPU(CortexM cpu)55 public void AttachCPU(CortexM cpu) 56 { 57 if(this.cpu != null) 58 { 59 throw new RecoverableException("The NVIC has already attached CPU."); 60 } 61 this.cpu = cpu; 62 this.cpuId = cpu.ModelID; 63 mpuVersion = cpu.IsV8 ? MPUVersion.PMSAv8 : MPUVersion.PMSAv7; 64 65 if(cpu.TrustZoneEnabled) 66 { 67 systick.SecureVal = new SysTick(machine, this, systick.NonSecureVal.Frequency, true); 68 } 69 70 if(cpu.Model == "cortex-m7") 71 { 72 DefineTightlyCoupledMemoryControlRegisters(); 73 } 74 75 cpu.AddHookAtWfiStateChange(HandleWfiStateChange); 76 } 77 78 public bool MaskedInterruptPresent { get { return maskedInterruptPresent; } } 79 80 public bool PauseInsteadOfReset { get; set; } 81 GetEnabledExternalInterrupts()82 public IEnumerable<int> GetEnabledExternalInterrupts() 83 { 84 return irqs.Skip(16).Select((x,i) => new {x,i}).Where(y => (y.x & IRQState.Enabled) != 0).Select(y => y.i).OrderBy(x => x); 85 } 86 GetEnabledInternalInterrupts()87 public IEnumerable<int> GetEnabledInternalInterrupts() 88 { 89 return irqs.Take(16).Select((x,i) => new {x,i}).Where(y => (y.x & IRQState.Enabled) != 0).Select(y => y.i).OrderBy(x => x); 90 } 91 92 public long Frequency 93 { 94 get => systick.Get(IsCurrentCPUInSecureState(out var _)).Frequency; 95 set 96 { 97 systick.Get(IsCurrentCPUInSecureState(out var _)).Frequency = value; 98 } 99 } 100 101 public int Divider 102 { 103 get => systick.Get(IsCurrentCPUInSecureState(out var _)).Divider; 104 set 105 { 106 systick.Get(IsCurrentCPUInSecureState(out var _)).Divider = value; 107 } 108 } 109 110 public bool HaltSystickOnDeepSleep { get; set; } 111 112 [ConnectionRegion("NonSecure")] ReadDoubleWordNonSecureAlias(long offset)113 public uint ReadDoubleWordNonSecureAlias(long offset) 114 { 115 if(!cpu.TrustZoneEnabled) 116 { 117 throw new RecoverableException(TrustZoneNSRegionWarning); 118 } 119 return ReadDoubleWord(offset, false); 120 } 121 ReadDoubleWord(long offset)122 public uint ReadDoubleWord(long offset) 123 { 124 return ReadDoubleWord(offset, IsCurrentCPUInSecureState(out var _)); 125 } 126 ReadDoubleWord(long offset, bool isSecure)127 public uint ReadDoubleWord(long offset, bool isSecure) 128 { 129 if(offset >= PriorityStart && offset < PriorityEnd) 130 { 131 return HandlePriorityRead(offset - PriorityStart, true, isSecure); 132 } 133 if(offset >= SetEnableStart && offset < SetEnableEnd) 134 { 135 return HandleEnableRead((int)(offset - SetEnableStart), isSecure); 136 } 137 if(offset >= ClearEnableStart && offset < ClearEnableEnd) 138 { 139 return HandleEnableRead((int)(offset - ClearEnableStart), isSecure); 140 } 141 if(offset >= SetPendingStart && offset < SetPendingEnd) 142 { 143 return GetPending((int)(offset - SetPendingStart), isSecure); 144 } 145 if(offset >= ClearPendingStart && offset < ClearPendingEnd) 146 { 147 return GetPending((int)(offset - ClearPendingStart), isSecure); 148 } 149 if(offset >= ActiveBitStart && offset < ActiveBitEnd) 150 { 151 return GetActive((int)(offset - ActiveBitStart), isSecure); 152 } 153 if(offset >= TargetNonSecureStart && offset < TargetNonSecureEnd) 154 { 155 bool isCpu = machine.GetSystemBus(this).TryGetCurrentCPU(out var cpu); 156 // For convenience, if we access this from outside CPU context (e.g. Monitor) let's allow this access through 157 if(!isSecure && isCpu) 158 { 159 this.WarningLog("CPU {0} tries to read from ITNS register, but it's in Non-secure state", cpu); 160 return 0; 161 } 162 return GetSecurityTarget((int)(offset - TargetNonSecureStart)); 163 } 164 if(offset >= MPUStart && offset < MPUEnd) 165 { 166 return HandleMPURead(offset - MPUStart); 167 } 168 if(offset >= SAUStart && offset < SAUEnd) 169 { 170 // SAU access is filtered at tlib level 171 return HandleSAURead(offset - SAUStart); 172 } 173 switch((Registers)offset) 174 { 175 case Registers.VectorTableOffset: 176 return (isSecure || !cpu.TrustZoneEnabled) ? cpu.VectorTableOffset : cpu.VectorTableOffsetNonSecure; 177 case Registers.CPUID: 178 return cpuId; 179 case Registers.CoprocessorAccessControl: 180 return (isSecure || !cpu.TrustZoneEnabled) ? cpu.CPACR : cpu.CPACR_NS; 181 case Registers.FPContextControl: 182 if(!IsPrivilegedMode()) 183 { 184 this.Log(LogLevel.Warning, "Tried to read FPContextControl from an unprivileged context. Returning 0."); 185 return 0; 186 } 187 return (isSecure || !cpu.TrustZoneEnabled) ? cpu.FPCCR: cpu.FPCCR_NS; 188 case Registers.FPContextAddress: 189 if(!IsPrivilegedMode()) 190 { 191 this.Log(LogLevel.Warning, "Tried to read FPContextAddress from an unprivileged context. Returning 0."); 192 return 0; 193 } 194 return isSecure || !cpu.TrustZoneEnabled ? cpu.FPCAR : cpu.FPCAR_NS; 195 case Registers.FPDefaultStatusControl: 196 if(!IsPrivilegedMode()) 197 { 198 this.Log(LogLevel.Warning, "Tried to read FPDefaultStatusControl from an unprivileged context. Returning 0."); 199 return 0; 200 } 201 return isSecure || !cpu.TrustZoneEnabled ? cpu.FPDSCR : cpu.FPDSCR_NS; 202 case Registers.ConfigurationAndControl: 203 return ccr.Get(isSecure); 204 case Registers.SystemHandlerPriority1: 205 case Registers.SystemHandlerPriority2: 206 case Registers.SystemHandlerPriority3: 207 return HandlePriorityRead(offset - 0xD14, false, isSecure); 208 case Registers.ConfigurableFaultStatus: 209 return isSecure || !cpu.TrustZoneEnabled ? cpu.FaultStatus : cpu.FaultStatusNonSecure; 210 case Registers.InterruptControllerType: 211 return 0b0111; 212 case Registers.MemoryFaultAddress: 213 return isSecure || !cpu.TrustZoneEnabled ? cpu.MemoryFaultAddress : cpu.MemoryFaultAddressNonSecure; 214 default: 215 lock(RegisterCollection) 216 { 217 isNextAccessSecure = isSecure; 218 return RegisterCollection.Read(offset); 219 } 220 } 221 } 222 223 public GPIO IRQ { get; private set; } 224 225 [ConnectionRegion("NonSecure")] WriteDoubleWordNonSecureAlias(long offset, uint value)226 public void WriteDoubleWordNonSecureAlias(long offset, uint value) 227 { 228 if(!cpu.TrustZoneEnabled) 229 { 230 throw new RecoverableException(TrustZoneNSRegionWarning); 231 } 232 WriteDoubleWord(offset, value, false); 233 } 234 WriteDoubleWord(long offset, uint value)235 public void WriteDoubleWord(long offset, uint value) 236 { 237 WriteDoubleWord(offset, value, IsCurrentCPUInSecureState(out var _)); 238 } 239 WriteDoubleWord(long offset, uint value, bool isSecure)240 public void WriteDoubleWord(long offset, uint value, bool isSecure) 241 { 242 if(offset >= SetEnableStart && offset < SetEnableEnd) 243 { 244 EnableOrDisableInterrupt((int)offset - SetEnableStart, value, true, isSecure); 245 return; 246 } 247 if(offset >= PriorityStart && offset < PriorityEnd) 248 { 249 HandlePriorityWrite(offset - PriorityStart, true, value, isSecure); 250 return; 251 } 252 if(offset >= ClearEnableStart && offset < ClearEnableEnd) 253 { 254 EnableOrDisableInterrupt((int)offset - ClearEnableStart, value, false, isSecure); 255 return; 256 } 257 if(offset >= ClearPendingStart && offset < ClearPendingEnd) 258 { 259 SetOrClearPendingInterrupt((int)offset - ClearPendingStart, value, false, isSecure); 260 return; 261 } 262 if(offset >= SetPendingStart && offset < SetPendingEnd) 263 { 264 SetOrClearPendingInterrupt((int)offset - SetPendingStart, value, true, isSecure); 265 return; 266 } 267 if(offset >= TargetNonSecureStart && offset < TargetNonSecureEnd) 268 { 269 bool isCpu = machine.GetSystemBus(this).TryGetCurrentCPU(out var cpu); 270 // For convenience, if we access this from outside CPU context (e.g. Monitor) let's allow this access through 271 if(!isSecure && isCpu) 272 { 273 this.WarningLog("CPU {0} tries to write to ITNS register, but it's in Non-secure state", cpu); 274 return; 275 } 276 ModifySecurityTarget((int)(offset - TargetNonSecureStart), value); 277 return; 278 } 279 if(offset >= MPUStart && offset < MPUEnd) 280 { 281 HandleMPUWrite(offset - MPUStart, value); 282 return; 283 } 284 if(offset >= SAUStart && offset < SAUEnd) 285 { 286 // SAU access is filtered at tlib level 287 HandleSAUWrite(offset - SAUStart, value); 288 return; 289 } 290 switch((Registers)offset) 291 { 292 case Registers.VectorTableOffset: 293 if(isSecure || !cpu.TrustZoneEnabled) 294 { 295 cpu.VectorTableOffset = value & 0xFFFFFF80; 296 } 297 else 298 { 299 cpu.VectorTableOffsetNonSecure = value & 0xFFFFFF80; 300 } 301 break; 302 case Registers.ApplicationInterruptAndReset: 303 var key = value >> 16; 304 if(key != VectKey) 305 { 306 this.DebugLog("Wrong key while accessing Application Interrupt and Reset Control register 0x{0:X}.", key); 307 break; 308 } 309 // Key is OK, allow access to go through 310 goto default; 311 case Registers.ConfigurableFaultStatus: 312 if(isSecure || !cpu.TrustZoneEnabled) 313 { 314 cpu.FaultStatus &= ~value; 315 } 316 else 317 { 318 cpu.FaultStatusNonSecure &= ~value; 319 } 320 break; 321 case Registers.SystemHandlerPriority1: 322 // 7th interrupt is ignored 323 priorities[(int)(isSecure ? SystemException.MemManageFault_S : SystemException.MemManageFault)] = (byte)value; 324 priorities[(int)SystemException.BusFault] = (byte)(value >> 8); 325 priorities[(int)(isSecure ? SystemException.UsageFault_S : SystemException.UsageFault)] = (byte)(value >> 16); 326 this.DebugLog("Priority of IRQs 4, 5, 6 set to 0x{0:X}, 0x{1:X}, 0x{2:X} respectively.", (byte)value, (byte)(value >> 8), (byte)(value >> 16)); 327 break; 328 case Registers.SystemHandlerPriority2: 329 // only 11th is not ignored 330 priorities[(int)(isSecure ? SystemException.SuperVisorCall_S : SystemException.SuperVisorCall)] = (byte)(value >> 24); 331 this.DebugLog("Priority of IRQ 11 set to 0x{0:X}.", (byte)(value >> 24)); 332 break; 333 case Registers.SystemHandlerPriority3: 334 priorities[(int)(isSecure ? SystemException.PendSV_S : SystemException.PendSV)] = (byte)(value >> 16); 335 priorities[(int)(isSecure ? SystemException.SysTick_S : SystemException.SysTick)] = (byte)(value >> 24); 336 this.DebugLog("Priority of IRQs 14, 15 set to 0x{0:X}, 0x{1:X} respectively.", (byte)(value >> 16), (byte)(value >> 24)); 337 break; 338 case Registers.CoprocessorAccessControl: 339 // for ARM v8 and CP10 values: 340 // 0b11 Full access to the FP Extension and MVE 341 // 0b01 Privileged access only to the FP Extension and MVE 342 // 0b00 No access to the FP Extension and MVE 343 // 0b10 Reserved 344 // Any attempted use without access generates a NOCP UsageFault. 345 // same for ARM v7, but if values of CP11 and CP10 differ then effects are unpredictable 346 if(isSecure || !cpu.TrustZoneEnabled) 347 { 348 cpu.CPACR = value; 349 } 350 else 351 { 352 cpu.CPACR_NS = value; 353 } 354 // Enable FPU if any access is permitted, privilege checks in tlib use CPACR register. 355 // Similarly, if TrustZone is enabled, CPACR should be used to check if FPU is enabled in respective Security state 356 if((value & 0x100000) == 0x100000) 357 { 358 this.DebugLog("Enabling FPU."); 359 cpu.FpuEnabled = true; 360 } 361 else 362 { 363 this.DebugLog("Disabling FPU."); 364 cpu.FpuEnabled = false; 365 } 366 break; 367 case Registers.SoftwareTriggerInterrupt: 368 // This register is implemented only in ARMv7m and ARMv8m 369 if(cpu.Model == "cortex-m3" || cpu.Model == "cortex-m4" || cpu.Model == "cortex-m4f" || cpu.Model == "cortex-m7") 370 { 371 SetPendingIRQ((int)(16 + value)); 372 } 373 else 374 { 375 this.Log(LogLevel.Error, "Software Trigger Interrupt Register not implemented for {0}", cpu.Model); 376 } 377 break; 378 case Registers.FPContextControl: 379 if(!IsPrivilegedMode()) 380 { 381 this.Log(LogLevel.Warning, "Writing to FPContextControl requires privileged access."); 382 break; 383 } 384 if(isSecure || !cpu.TrustZoneEnabled) 385 { 386 cpu.FPCCR = value; 387 } 388 else 389 { 390 cpu.FPCCR_NS = value; 391 } 392 break; 393 case Registers.FPContextAddress: 394 if(!IsPrivilegedMode()) 395 { 396 this.Log(LogLevel.Warning, "Writing to FPContextAddress requires privileged access."); 397 break; 398 } 399 // address must be 8-byte aligned 400 if(isSecure || !cpu.TrustZoneEnabled) 401 { 402 cpu.FPCAR = value & ~0x7u; 403 } 404 else 405 { 406 cpu.FPCAR_NS = value & ~0x7u; 407 } 408 break; 409 case Registers.FPDefaultStatusControl: 410 if(!IsPrivilegedMode()) 411 { 412 this.Log(LogLevel.Warning, "Writing to FPDefaultStatusControl requires privileged access."); 413 break; 414 } 415 // set only not reserved values 416 if(isSecure || !cpu.TrustZoneEnabled) 417 { 418 cpu.FPDSCR = value & 0x07c00000; 419 } 420 else 421 { 422 cpu.FPDSCR_NS = value & 0x07c00000; 423 } 424 break; 425 case Registers.ConfigurationAndControl: 426 ccr.Get(isSecure) = value; 427 break; 428 default: 429 lock(RegisterCollection) 430 { 431 isNextAccessSecure = isSecure; 432 RegisterCollection.Write(offset, value); 433 } 434 break; 435 } 436 } 437 Reset()438 public void Reset() 439 { 440 RegisterCollection.Reset(); 441 InitInterrupts(); 442 for(var i = 0; i < priorities.Length; i++) 443 { 444 priorities[i] = 0x00; 445 } 446 activeIRQs.Clear(); 447 systick.NonSecureVal.Reset(); 448 systick.SecureVal?.Reset(); 449 450 IRQ.Unset(); 451 currentSevOnPending.Reset(); 452 mpuControlRegister = 0; 453 HaltSystickOnDeepSleep = defaultHaltSystickOnDeepSleep; 454 canResetOnlyFromSecure = false; 455 deepSleepOnlyFromSecure = false; 456 binaryPointPosition.Reset(); 457 458 // bit [16] DC / Cache enable. This is a global enable bit for data and unified caches. 459 ccr.Reset(0x10000); 460 } 461 462 public long Size 463 { 464 get 465 { 466 return 0x1000; 467 } 468 } 469 AcknowledgeIRQ()470 public int AcknowledgeIRQ() 471 { 472 lock(irqs) 473 { 474 var result = FindPendingInterrupt(); 475 if(result != SpuriousInterrupt) 476 { 477 irqs[result] |= IRQState.Active; 478 irqs[result] &= ~IRQState.Pending; 479 pendingIRQs.Remove(result); 480 this.NoisyLog("Acknowledged IRQ {0}.", ExceptionToString(result)); 481 activeIRQs.Push(result); 482 } 483 // at this point we can surely deactivate interrupt, because the best was chosen 484 IRQ.Set(false); 485 return result; 486 } 487 } 488 CompleteIRQ(int number)489 public void CompleteIRQ(int number) 490 { 491 lock(irqs) 492 { 493 var currentIRQ = irqs[number]; 494 if((currentIRQ & IRQState.Active) == 0) 495 { 496 this.Log(LogLevel.Error, "Trying to complete not active IRQ {0}.", ExceptionToString(number)); 497 return; 498 } 499 irqs[number] &= ~IRQState.Active; 500 var activeIRQ = activeIRQs.Pop(); 501 if(activeIRQ != number) 502 { 503 this.Log(LogLevel.Error, "Trying to complete IRQ {0} that was not the last active. Last active was {1}.", ExceptionToString(number), ExceptionToString(activeIRQ)); 504 return; 505 } 506 if((currentIRQ & IRQState.Running) > 0) 507 { 508 this.NoisyLog("Completed IRQ {0} active -> pending.", ExceptionToString(number)); 509 irqs[number] |= IRQState.Pending; 510 pendingIRQs.Add(number); 511 } 512 else if((currentIRQ & IRQState.Pending) != 0) 513 { 514 this.NoisyLog("Completed IRQ {0} active -> pending.", number); 515 } 516 else 517 { 518 this.NoisyLog("Completed IRQ {0} active -> inactive.", ExceptionToString(number)); 519 } 520 FindPendingInterrupt(); 521 } 522 } 523 SetPendingIRQ(int number)524 public void SetPendingIRQ(int number) 525 { 526 lock(irqs) 527 { 528 this.NoisyLog("Internal IRQ {0}.", ExceptionToString(number)); 529 SetPending(number); 530 FindPendingInterrupt(); 531 } 532 } 533 OnGPIO(int number, bool value)534 public void OnGPIO(int number, bool value) 535 { 536 number += 16; // because this is HW interrupt 537 this.NoisyLog("External IRQ {0}: {1}", number, value); 538 var pendingInterrupt = SpuriousInterrupt; 539 lock(irqs) 540 { 541 if(value) 542 { 543 irqs[number] |= IRQState.Running; 544 SetPending(number); 545 } 546 else 547 { 548 irqs[number] &= ~IRQState.Running; 549 } 550 pendingInterrupt = FindPendingInterrupt(); 551 } 552 if(pendingInterrupt != SpuriousInterrupt && value) 553 { 554 // We assume both SysTicks are woken up on exiting deep sleep 555 // docs aren't clear on this, but this seems like a logical behavior 556 if(!systick.NonSecureVal.Enabled) 557 { 558 this.NoisyLog("Waking up from deep sleep"); 559 } 560 systick.NonSecureVal.Enabled |= value; 561 if(cpu.TrustZoneEnabled) 562 { 563 systick.SecureVal.Enabled |= value; 564 } 565 } 566 } 567 SetSevOnPendingOnAllCPUs(bool value)568 public void SetSevOnPendingOnAllCPUs(bool value) 569 { 570 foreach(var cpu in machine.SystemBus.GetCPUs().OfType<Arm>()) 571 { 572 cpu.SetSevOnPending(value); 573 } 574 } 575 SetSleepOnExceptionExitOnAllCPUs(bool value)576 public void SetSleepOnExceptionExitOnAllCPUs(bool value) 577 { 578 foreach(var cpu in machine.SystemBus.GetCPUs().OfType<CortexM>()) 579 { 580 cpu.SetSleepOnExceptionExit(value); 581 } 582 } 583 584 public DoubleWordRegisterCollection RegisterCollection { get; } 585 586 public bool DeepSleepEnabled { get; set; } 587 DefineRegisters()588 private void DefineRegisters() 589 { 590 Registers.SysTickControl.Define(RegisterCollection) 591 .WithFlag(0, 592 changeCallback: (_, value) => systick.Get(isNextAccessSecure).Enabled = value, 593 valueProviderCallback: _ => systick.Get(isNextAccessSecure).Enabled, 594 name: "ENABLE") 595 .WithFlag(1, 596 valueProviderCallback: _ => systick.Get(isNextAccessSecure).TickInterruptEnabled, 597 changeCallback: (_, newValue) => 598 { 599 this.NoisyLog("Systick_{0} interrupt {1}", isNextAccessSecure ? "S" : "NS", newValue ? "enabled" : "disabled"); 600 systick.Get(isNextAccessSecure).TickInterruptEnabled = newValue; 601 }, name: "TICKINT") 602 // If no external clock is provided, this bit reads as 1 and ignores writes. 603 .WithFlag(2, FieldMode.Read, valueProviderCallback: _ => true, name: "CLKSOURCE") // SysTick uses the processor clock 604 .WithReservedBits(3, 13) 605 .WithFlag(16, FieldMode.ReadToClear, 606 valueProviderCallback: _ => 607 { 608 var ret = systick.Get(isNextAccessSecure).CountFlag; 609 systick.Get(isNextAccessSecure).CountFlag = false; 610 return ret; 611 }, 612 name: "COUNTFLAG") 613 .WithReservedBits(17, 15); 614 615 Registers.SysTickReloadValue.Define(RegisterCollection) 616 .WithValueField(0, 24, 617 valueProviderCallback: _ => systick.Get(isNextAccessSecure).Reload, 618 changeCallback: (_, newValue) => systick.Get(isNextAccessSecure).Reload = newValue, 619 name: "RELOAD") 620 .WithReservedBits(24, 8); 621 622 Registers.SysTickValue.Define(RegisterCollection) 623 .WithValueField(0, 24, 624 writeCallback: (_, __) => systick.Get(isNextAccessSecure).UpdateSystickValue(), 625 valueProviderCallback: _ => 626 { 627 cpu?.SyncTime(); 628 return (uint)systick.Get(isNextAccessSecure).Value; 629 }, name: "CURRENT") 630 .WithReservedBits(24, 8); 631 632 Registers.SysTickCalibrationValue.Define(RegisterCollection) 633 // Note that some reference manuals state that this value is for 1ms interval and not for 10ms 634 .WithValueField(0, 24, FieldMode.Read, valueProviderCallback: _ => SysTickMaxValue & (uint)(systick.Get(isNextAccessSecure).Frequency / SysTickCalibration100Hz), name: "TENMS") 635 .WithReservedBits(24, 6) 636 .WithFlag(30, FieldMode.Read, valueProviderCallback: _ => systick.Get(isNextAccessSecure).Frequency % SysTickCalibration100Hz != 0, name: "SKEW") 637 .WithFlag(31, FieldMode.Read, valueProviderCallback: _ => true, name: "NOREF"); 638 639 Registers.InterruptControlState.Define(RegisterCollection) 640 .WithValueField(0, 9, FieldMode.Read, valueProviderCallback: _ => (uint)(activeIRQs.Count == 0 ? 0 : activeIRQs.Peek()), name: "VECTACTIVE") 641 .WithReservedBits(9, 2) 642 .WithTaggedFlag("RETTOBASE", 11) 643 .WithValueField(12, 9, FieldMode.Read, valueProviderCallback: _ => (uint)FindPendingInterrupt(), name: "VECTPENDING") 644 .WithReservedBits(21, 1) 645 .WithTaggedFlag("ISRPENDING", 22) 646 .WithTaggedFlag("ISRPREEMPT", 23) 647 .WithTaggedFlag("STTNS", 24) 648 .WithFlag(25, FieldMode.WriteOneToClear, writeCallback: (_, value) => 649 { 650 if(value) 651 { 652 ClearPending((int)(isNextAccessSecure ? SystemException.SysTick_S : SystemException.SysTick)); 653 } 654 }, name: "PENDSTCLR") 655 .WithFlag(26, writeCallback: (_, value) => 656 { 657 if(value) 658 { 659 SetPendingIRQ((int)(isNextAccessSecure ? SystemException.SysTick_S : SystemException.SysTick)); 660 } 661 }, valueProviderCallback: _ => irqs[(int)SystemException.SysTick].HasFlag(IRQState.Pending), name: "PENDSTSET") 662 .WithFlag(27, FieldMode.WriteOneToClear, writeCallback: (_, value) => 663 { 664 if(value) 665 { 666 ClearPending((int)(isNextAccessSecure ? SystemException.PendSV_S : SystemException.PendSV)); 667 } 668 }, name: "PENDSVCLR") 669 .WithFlag(28, writeCallback: (_, value) => 670 { 671 if(value) 672 { 673 SetPendingIRQ((int)(isNextAccessSecure ? SystemException.PendSV_S : SystemException.PendSV)); 674 } 675 }, valueProviderCallback: _ => irqs[(int)SystemException.PendSV].HasFlag(IRQState.Pending), name: "PENDSVSET") 676 .WithReservedBits(29, 1) 677 .WithFlag(30, FieldMode.WriteOneToClear, writeCallback: (_, value) => 678 { 679 if(value) 680 { 681 ClearPending((int)SystemException.NMI); 682 } 683 }, name: "PENDNMICLR") 684 .WithFlag(31, writeCallback: (_, value) => 685 { 686 if(value) 687 { 688 SetPendingIRQ((int)SystemException.NMI); 689 } 690 }, valueProviderCallback: _ => irqs[(int)SystemException.NMI].HasFlag(IRQState.Pending), name: "PENDNMISET"); 691 692 Registers.SystemControlRegister.Define(RegisterCollection) 693 .WithReservedBits(0, 1) 694 .WithFlag(1, out sleepOnExitEnabled, name: "SLEEPONEXIT", 695 changeCallback: (_, value) => SetSleepOnExceptionExitOnAllCPUs(value)) 696 .WithFlag(2, 697 writeCallback: (_, value) => 698 { 699 if(!isNextAccessSecure && deepSleepOnlyFromSecure) 700 { 701 this.WarningLog("Trying to set SLEEPDEEP but SLEEPDEEPS is set and the access is Non-secure. Ignoring"); 702 return; 703 } 704 DeepSleepEnabled = value; 705 }, 706 valueProviderCallback: _ => 707 { 708 if(!isNextAccessSecure && deepSleepOnlyFromSecure) 709 { 710 return false; 711 } 712 return DeepSleepEnabled; 713 }, 714 name: "SLEEPDEEP") 715 .WithFlag(3, 716 writeCallback: (_, value) => 717 { 718 if(isNextAccessSecure) 719 { 720 deepSleepOnlyFromSecure = value; 721 } 722 }, 723 valueProviderCallback: _ => 724 { 725 if(!isNextAccessSecure) 726 { 727 return false; 728 } 729 return deepSleepOnlyFromSecure; 730 }, 731 name: "SLEEPDEEPS") 732 .WithFlag(4, 733 changeCallback: (_, value) => 734 { 735 SetSevOnPendingOnAllCPUs(value); 736 currentSevOnPending.Get(isNextAccessSecure) = value; 737 }, 738 valueProviderCallback: _ => currentSevOnPending.Get(isNextAccessSecure), 739 name: "SEVONPEND") 740 .WithReservedBits(5, 27); 741 742 Registers.ApplicationInterruptAndReset.Define(RegisterCollection) 743 .WithReservedBits(0, 1) 744 .WithTaggedFlag("VECTCLRACTIVE", 1) 745 .WithFlag(2, writeCallback: (_, value) => 746 { 747 if(value) 748 { 749 if(canResetOnlyFromSecure && !isNextAccessSecure) 750 { 751 this.WarningLog("Requested reset with SYSRESETREQ but SYSRESETREQS is set and the access is Non-secure. Ignoring"); 752 return; 753 } 754 this.InfoLog("Resetting platform with SYSRESETREQ"); 755 if(PauseInsteadOfReset) 756 { 757 machine.Pause(); 758 } 759 else 760 { 761 resetMachine(); 762 } 763 } 764 }, name: "SYSRESETREQ") 765 .WithFlag(3, writeCallback: (_, value) => 766 { 767 if(!isNextAccessSecure) 768 { 769 // This bit is RAZ/WI from Non-secure state. 770 return; 771 } 772 canResetOnlyFromSecure = value; 773 }, valueProviderCallback: _ => 774 { 775 if(!isNextAccessSecure) 776 { 777 // This bit is RAZ/WI from Non-secure state. 778 return false; 779 } 780 return canResetOnlyFromSecure; 781 }, name: "SYSRESETREQS") 782 .WithTaggedFlag("DIT", 4) 783 .WithTaggedFlag("IESB", 5) 784 .WithReservedBits(6, 2) 785 .WithValueField(8, 3, writeCallback: (_, value) => 786 { 787 binaryPointPosition.Get(isNextAccessSecure) = (int)value; 788 }, name: "PRIGROUP") 789 .WithReservedBits(11, 2) 790 .WithFlag(13, writeCallback: (_, value) => 791 { 792 if(!isNextAccessSecure) 793 { 794 // This bit is WI from Non-secure state. 795 return; 796 } 797 var sec = value ? InterruptTargetSecurityState.NonSecure : InterruptTargetSecurityState.Secure; 798 foreach(var excp in new SystemException[] {SystemException.NMI, SystemException.HardFault, SystemException.BusFault}) 799 { 800 targetInterruptSecurityState[(int)excp] = sec; 801 } 802 }, name: "BFHFNMINS") 803 .WithFlag(14, writeCallback: (_, value) => 804 { 805 if(!isNextAccessSecure) 806 { 807 // This bit is RAZ/WI from Non-secure state. 808 return; 809 } 810 prioritizeSecureInterrupts = value; 811 }, valueProviderCallback: _ => 812 { 813 if(!isNextAccessSecure) 814 { 815 // This bit is RAZ/WI from Non-secure state. 816 return false; 817 } 818 return prioritizeSecureInterrupts; 819 }, name: "PRIS") 820 .WithTaggedFlag(name: "ENDIANNESS", 15) 821 // We guard access with VectKey in `WriteDoubleWord` - here we just return the expected value 822 .WithValueField(16, 16, valueProviderCallback: _ => VectKeyStat, name: "VECTKEYSTAT"); 823 824 825 Registers.SystemHandlerControlAndState.Define(RegisterCollection) 826 .WithTaggedFlag("MEMFAULTACT (Memory Manage Active)", 0) 827 .WithTaggedFlag("BUSFAULTACT (Bus Fault Active)", 1) 828 .WithReservedBits(2, 1) 829 .WithTaggedFlag("USGFAULTACT (Usage Fault Active)", 3) 830 .WithReservedBits(4, 3) 831 .WithTaggedFlag("SVCALLACT (SV Call Active)", 7) 832 .WithTaggedFlag("MONITORACT (Monitor Active)", 8) 833 .WithReservedBits(9, 1) 834 .WithTaggedFlag("PENDSVACT (Pend SV Active)", 10) 835 .WithTaggedFlag("SYSTICKACT (Sys Tick Active)", 11) 836 .WithTaggedFlag("USGFAULTPENDED (Usage Fault Pending)", 12) 837 .WithTaggedFlag("MEMFAULTPENDED (Mem Manage Pending)", 13) 838 .WithTaggedFlag("BUSFAULTPENDED (Bus Fault Pending)", 14) 839 .WithTaggedFlag("SVCALLPENDED (SV Call Pending)", 15) 840 // The enable flags only store written data. 841 // Changing them doesn't change a behavior of the model. 842 .WithFlag(16, name: "MEMFAULTENA (Memory Manage Fault Enable)") 843 .WithFlag(17, name: "BUSFAULTENA (Bus Fault Enable)") 844 .WithFlag(18, name: "USGFAULTENA (Usage Fault Enable)") 845 .WithReservedBits(19, 13) 846 .WithChangeCallback((_, val) => 847 this.Log(LogLevel.Warning, "Changing value of the SHCSR register to 0x{0:X}, the register isn't supported by Renode", val) 848 ); 849 850 Registers.CacheSizeSelection.Define(RegisterCollection) 851 .WithTaggedFlag("InD (Instruction or Data Selection)", 0) 852 .WithTag("Level", 1, 3) 853 .WithReservedBits(4, 28); 854 855 Registers.CacheSizeID.Define(RegisterCollection) 856 .WithTag("LineSize", 0, 3) 857 .WithTag("Associativity", 3, 10) 858 .WithTag("NumSets", 13, 15) 859 .WithTaggedFlag("WA (Write Allocation Support)", 28) 860 .WithTaggedFlag("RA (Read Allocation Support)", 29) 861 .WithTaggedFlag("WB (Write Back Support)", 30) 862 .WithTaggedFlag("WT (Write Through Support)", 31); 863 864 Registers.DebugExceptionAndMonitorControlRegister.Define(RegisterCollection) 865 .WithTaggedFlag("VC_CORERESET (Reset Vector Catch)", 0) 866 .WithReservedBits(1, 3) 867 .WithTaggedFlag("VC_MMERR (Debug trap on Memory Management faults)", 4) 868 .WithTaggedFlag("VC_NOCPERR (Debug trap on Usage Fault access to Coprocessor which is not present)", 5) 869 .WithTaggedFlag("VC_CHKERR (Debug trap on Usage Fault enabled checking errors)", 6) 870 .WithTaggedFlag("VC_STATERR (Debug trap on Usage Fault state error)", 7) 871 .WithTaggedFlag("VC_BUSERR (Debug trap on normal Bus error)", 8) 872 .WithTaggedFlag("VC_INTERR (Debug trap on interrupt/exception service errors)", 9) 873 .WithTaggedFlag("VC_HARDERR (Debug trap on Hard Fault)", 10) 874 .WithReservedBits(11, 5) 875 .WithTaggedFlag("MON_EN (Monitor Enable)", 16) 876 .WithTaggedFlag("MON_PEND (Monitor Pend)", 17) 877 .WithTaggedFlag("MON_STEP (Monitor Step)", 18) 878 .WithTaggedFlag("MON_REQ (Monitor Request)", 19) 879 .WithReservedBits(20, 4) 880 // The trace flag only store written data. 881 // Changing it doesn't change the behavior of the model. 882 .WithFlag(24, name: "TRCENA (Trace Enable)") 883 .WithReservedBits(25, 7); 884 885 Registers.SecureFaultStatus.Define(RegisterCollection) 886 .WithValueField(0, 8, writeCallback: (_, value) => 887 { 888 if(!isNextAccessSecure) 889 { 890 // This bit is RAZ/WI from Non-secure state. 891 return; 892 } 893 cpu.SecureFaultStatus = (uint)value; 894 }, valueProviderCallback: _ => 895 { 896 if(!isNextAccessSecure) 897 { 898 // This bit is RAZ/WI from Non-secure state. 899 return 0; 900 } 901 return cpu.SecureFaultStatus; 902 }, name: "Status bits") 903 .WithReservedBits(8, 24); 904 905 /* While the ISA manual permits this to be shared with MMFAR, we keep it separate, 906 * so we don't have to worry about invalidating it between exceptions. 907 * If there is an address here, it's always valid */ 908 Registers.SecureFaultAddress.Define(RegisterCollection) 909 .WithValueField(0, 32, FieldMode.Read, valueProviderCallback: _ => isNextAccessSecure ? cpu.SecureFaultAddress : 0, name: "Address"); 910 } 911 DefineTightlyCoupledMemoryControlRegisters()912 private void DefineTightlyCoupledMemoryControlRegisters() 913 { 914 // The ITCMC and DTCMC registers have same fields. 915 Registers.InstructionTightlyCoupledMemoryControl.DefineMany(RegisterCollection, 2, setup: (reg, index) => reg 916 .WithTaggedFlag("EN (TCM Enable)", 0) 917 .WithTaggedFlag("RMW (Read Modify Write Enable)", 1) 918 .WithTaggedFlag("RETEN (Retry Phase Enable)", 2) 919 .WithTag("SZ (TCM Size)", 3, 4) 920 .WithReservedBits(7, 25) 921 ); 922 } 923 InitInterrupts()924 private void InitInterrupts() 925 { 926 irqs.Clear(); 927 Array.Clear(targetInterruptSecurityState, 0, targetInterruptSecurityState.Length); 928 for(var i = 0; i < 16; i++) 929 { 930 irqs[i] = IRQState.Enabled; 931 } 932 foreach(var i in bankedInterrupts) 933 { 934 irqs[i] = IRQState.Enabled; 935 } 936 maskedInterruptPresent = false; 937 prioritizeSecureInterrupts = false; 938 pendingIRQs.Clear(); 939 } 940 GetStartingInterrupt(long offset, bool externalInterrupt)941 private static int GetStartingInterrupt(long offset, bool externalInterrupt) 942 { 943 return (int)(offset + (externalInterrupt ? 16 : 0)); 944 } 945 HandlePriorityWrite(long offset, bool externalInterrupt, uint value, bool isSecure)946 private void HandlePriorityWrite(long offset, bool externalInterrupt, uint value, bool isSecure) 947 { 948 lock(irqs) 949 { 950 var startingInterrupt = GetStartingInterrupt(offset, externalInterrupt); 951 for(var i = startingInterrupt; i < startingInterrupt + 4; i++) 952 { 953 if(!isSecure && !IsInterruptTargetNonSecure(i)) 954 { 955 this.WarningLog("Cannot set priority for IRQ {0}, since it targets Secure state, and the access is in Non-secure", 956 ExceptionToString(i)); 957 continue; 958 } 959 960 if((((byte)value) & ~priorityMask) != 0) 961 { 962 this.Log(LogLevel.Warning, "Trying to set the priority for interrupt {0} to 0x{1:X}, but it should be maskable with 0x{2:X}", i, value, priorityMask); 963 } 964 965 priorities[i] = (byte)(value & priorityMask); 966 967 this.DebugLog("Priority 0x{0:X} set for interrupt {1}.", priorities[i], i); 968 value >>= 8; 969 } 970 } 971 } 972 HandlePriorityRead(long offset, bool externalInterrupt, bool isSecure)973 private uint HandlePriorityRead(long offset, bool externalInterrupt, bool isSecure) 974 { 975 lock(irqs) 976 { 977 var returnValue = 0u; 978 var startingInterrupt = GetStartingInterrupt(offset, externalInterrupt); 979 for(var i = startingInterrupt + 3; i >= startingInterrupt; i--) 980 { 981 returnValue <<= 8; 982 // If we are in Secure state, get Secure variant for banked exception 983 if(isSecure && bankedInterrupts.Contains(i)) 984 { 985 returnValue |= priorities[i | BankedExcpSecureBit]; 986 } 987 else 988 { 989 // Cannot read the priority of a Secure interrupt in a Non-secure state, read zero instead 990 if(isSecure || IsInterruptTargetNonSecure(i)) 991 { 992 returnValue |= priorities[i]; 993 } 994 } 995 } 996 return returnValue; 997 } 998 } 999 HandleMPURead(long offset)1000 private uint HandleMPURead(long offset) 1001 { 1002 switch(mpuVersion) 1003 { 1004 case MPUVersion.PMSAv7: 1005 return HandleMPUReadV7(offset); 1006 case MPUVersion.PMSAv8: 1007 return HandleMPUReadV8(offset); 1008 default: 1009 throw new Exception("Attempted MPU read, but the MPU version is unknown"); 1010 } 1011 } 1012 HandleMPUWrite(long offset, uint value)1013 private void HandleMPUWrite(long offset, uint value) 1014 { 1015 switch(mpuVersion) 1016 { 1017 case MPUVersion.PMSAv7: 1018 HandleMPUWriteV7(offset, value); 1019 break; 1020 case MPUVersion.PMSAv8: 1021 HandleMPUWriteV8(offset, value); 1022 break; 1023 default: 1024 throw new Exception("Attempted MPU write, but the mpuVersion is unknown"); 1025 } 1026 } 1027 HandleMPUWriteV7(long offset, uint value)1028 private void HandleMPUWriteV7(long offset, uint value) 1029 { 1030 this.Log(LogLevel.Debug, "MPU: Trying to write to {0} (value: 0x{1:X08})", Enum.GetName(typeof(RegistersV7), offset), value); 1031 switch((RegistersV7)offset) 1032 { 1033 case RegistersV7.Type: 1034 this.Log(LogLevel.Warning, "MPU: Trying to write to a read-only register (MPU_TYPE)"); 1035 break; 1036 case RegistersV7.Control: 1037 if((mpuControlRegister & 0x1) != (value & 0x1)) 1038 { 1039 this.cpu.MPUEnabled = (value & 0x1) != 0x0; 1040 } 1041 mpuControlRegister = value; 1042 break; 1043 case RegistersV7.RegionNumber: // MPU_RNR 1044 cpu.MPURegionNumber = value; 1045 break; 1046 case RegistersV7.RegionBaseAddress: 1047 case RegistersV7.RegionBaseAddressAlias1: 1048 case RegistersV7.RegionBaseAddressAlias2: 1049 case RegistersV7.RegionBaseAddressAlias3: 1050 cpu.MPURegionBaseAddress = value; 1051 break; 1052 case RegistersV7.RegionAttributeAndSize: 1053 case RegistersV7.RegionAttributeAndSizeAlias1: 1054 case RegistersV7.RegionAttributeAndSizeAlias2: 1055 case RegistersV7.RegionAttributeAndSizeAlias3: 1056 cpu.MPURegionAttributeAndSize = value; 1057 break; 1058 } 1059 } 1060 HandleMPUWriteV8(long offset, uint value)1061 private void HandleMPUWriteV8(long offset, uint value) 1062 { 1063 this.Log(LogLevel.Debug, "MPU: Trying to write to {0} (value: 0x{1:X08})", Enum.GetName(typeof(RegistersV8), offset), value); 1064 1065 if (cpu.NumberOfMPURegions == 0) 1066 { 1067 this.Log(LogLevel.Error, $"CPU abort [PC={cpu.PC:x}]. Attempted a write to an MPU register, but the CPU doesn't support MPU. Set 'numberOfMPURegions' in CPU configuration to enable it."); 1068 throw new CpuAbortException(); 1069 } 1070 switch((RegistersV8)offset) 1071 { 1072 case RegistersV8.Type: 1073 this.Log(LogLevel.Warning, "MPU: Trying to write to a read-only register (MPU_TYPE)"); 1074 break; 1075 case RegistersV8.Control: 1076 cpu.PmsaV8Ctrl = value; 1077 break; 1078 case RegistersV8.RegionNumberRegister: 1079 cpu.PmsaV8Rnr = value; 1080 break; 1081 case RegistersV8.RegionBaseAddressRegister: 1082 case RegistersV8.RegionBaseAddressRegisterAlias1: 1083 case RegistersV8.RegionBaseAddressRegisterAlias2: 1084 case RegistersV8.RegionBaseAddressRegisterAlias3: 1085 cpu.PmsaV8Rbar = value; 1086 break; 1087 case RegistersV8.RegionLimitAddressRegister: 1088 case RegistersV8.RegionLimitAddressRegisterAlias1: 1089 case RegistersV8.RegionLimitAddressRegisterAlias2: 1090 case RegistersV8.RegionLimitAddressRegisterAlias3: 1091 cpu.PmsaV8Rlar = value; 1092 break; 1093 case RegistersV8.MemoryAttributeIndirectionRegister0: 1094 cpu.PmsaV8Mair0 = value; 1095 break; 1096 case RegistersV8.MemoryAttributeIndirectionRegister1: 1097 cpu.PmsaV8Mair1 = value; 1098 break; 1099 } 1100 } 1101 HandleMPUReadV7(long offset)1102 private uint HandleMPUReadV7(long offset) 1103 { 1104 uint value; 1105 switch((RegistersV7)offset) 1106 { 1107 case RegistersV7.Type: 1108 value = (cpu.NumberOfMPURegions & 0xFF) << 8; 1109 break; 1110 case RegistersV7.Control: 1111 value = mpuControlRegister; 1112 break; 1113 case RegistersV7.RegionNumber: 1114 value = cpu.MPURegionNumber; 1115 break; 1116 case RegistersV7.RegionBaseAddress: 1117 case RegistersV7.RegionBaseAddressAlias1: 1118 case RegistersV7.RegionBaseAddressAlias2: 1119 case RegistersV7.RegionBaseAddressAlias3: 1120 value = cpu.MPURegionBaseAddress; 1121 break; 1122 case RegistersV7.RegionAttributeAndSize: 1123 case RegistersV7.RegionAttributeAndSizeAlias1: 1124 case RegistersV7.RegionAttributeAndSizeAlias2: 1125 case RegistersV7.RegionAttributeAndSizeAlias3: 1126 value = cpu.MPURegionAttributeAndSize; 1127 break; 1128 default: 1129 value = 0x0; 1130 break; 1131 } 1132 this.Log(LogLevel.Debug, "MPU: Trying to read {0} (value: 0x{1:X08})", Enum.GetName(typeof(RegistersV7), offset), value); 1133 return value; 1134 } 1135 HandleMPUReadV8(long offset)1136 private uint HandleMPUReadV8(long offset) 1137 { 1138 if (cpu.NumberOfMPURegions == 0) 1139 { 1140 this.Log(LogLevel.Debug, $"Attempted a read from an MPU register, but the CPU doesn't support MPU. Set 'numberOfMPURegions' in CPU configuration to enable it."); 1141 return 0; 1142 } 1143 uint value; 1144 switch((RegistersV8)offset) 1145 { 1146 case RegistersV8.Type: 1147 value = (cpu.NumberOfMPURegions & 0xFF) << 8; 1148 break; 1149 case RegistersV8.Control: 1150 value = cpu.PmsaV8Ctrl; 1151 break; 1152 case RegistersV8.RegionNumberRegister: 1153 value = cpu.PmsaV8Rnr; 1154 break; 1155 case RegistersV8.RegionBaseAddressRegister: 1156 case RegistersV8.RegionBaseAddressRegisterAlias1: 1157 case RegistersV8.RegionBaseAddressRegisterAlias2: 1158 case RegistersV8.RegionBaseAddressRegisterAlias3: 1159 value = cpu.PmsaV8Rbar; 1160 break; 1161 case RegistersV8.RegionLimitAddressRegister: 1162 case RegistersV8.RegionLimitAddressRegisterAlias1: 1163 case RegistersV8.RegionLimitAddressRegisterAlias2: 1164 case RegistersV8.RegionLimitAddressRegisterAlias3: 1165 value = cpu.PmsaV8Rlar; 1166 break; 1167 case RegistersV8.MemoryAttributeIndirectionRegister0: 1168 value = cpu.PmsaV8Mair0; 1169 break; 1170 case RegistersV8.MemoryAttributeIndirectionRegister1: 1171 value = cpu.PmsaV8Mair1; 1172 break; 1173 default: 1174 value = 0x0; 1175 break; 1176 } 1177 this.Log(LogLevel.Debug, "MPU: Trying to read {0} (value: 0x{1:X08})", Enum.GetName(typeof(RegistersV7), offset), value); 1178 return value; 1179 } 1180 HandleSAURead(long offset)1181 private uint HandleSAURead(long offset) 1182 { 1183 switch((RegistersSAU)offset) 1184 { 1185 case RegistersSAU.Control: 1186 return cpu.SAUControl; 1187 case RegistersSAU.Type: 1188 return cpu.NumberOfSAURegions; 1189 case RegistersSAU.RegionNumber: 1190 return cpu.SAURegionNumber; 1191 case RegistersSAU.RegionBaseAddress: 1192 return cpu.SAURegionBaseAddress; 1193 case RegistersSAU.RegionLimitAddress: 1194 return cpu.SAURegionLimitAddress; 1195 default: 1196 this.WarningLog("SAU: Read from unhandled register 0x{0:x}", offset); 1197 return 0; 1198 } 1199 } 1200 HandleSAUWrite(long offset, uint value)1201 private void HandleSAUWrite(long offset, uint value) 1202 { 1203 switch((RegistersSAU)offset) 1204 { 1205 case RegistersSAU.Control: 1206 cpu.SAUControl = value; 1207 break; 1208 case RegistersSAU.Type: 1209 this.WarningLog("SAU: Write to read-only register 0x{0:x} ({1}), value 0x{2:x}", offset, nameof(RegistersSAU.Type), value); 1210 break; 1211 case RegistersSAU.RegionNumber: 1212 cpu.SAURegionNumber = value; 1213 break; 1214 case RegistersSAU.RegionBaseAddress: 1215 cpu.SAURegionBaseAddress = value; 1216 break; 1217 case RegistersSAU.RegionLimitAddress: 1218 cpu.SAURegionLimitAddress = value; 1219 break; 1220 default: 1221 this.WarningLog("SAU: Write to unhandled register 0x{0:x}, value 0x{1:x}", offset, value); 1222 break; 1223 } 1224 } 1225 HandleWfiStateChange(bool enteredWfi)1226 private void HandleWfiStateChange(bool enteredWfi) 1227 { 1228 if(enteredWfi && DeepSleepEnabled && HaltSystickOnDeepSleep) 1229 { 1230 systick.NonSecureVal.Enabled = false; 1231 if(cpu.TrustZoneEnabled) 1232 { 1233 systick.SecureVal.Enabled = false; 1234 } 1235 this.NoisyLog("Entering deep sleep"); 1236 } 1237 } 1238 EnableOrDisableInterrupt(int offset, uint value, bool enable, bool isSecure)1239 private void EnableOrDisableInterrupt(int offset, uint value, bool enable, bool isSecure) 1240 { 1241 lock(irqs) 1242 { 1243 var firstIRQNo = 8 * offset + 16; // 16 is added because this is HW interrupt 1244 { 1245 var lastIRQNo = firstIRQNo + 31; 1246 var mask = 1u; 1247 for(var i = firstIRQNo; i <= lastIRQNo; i++) 1248 { 1249 if((value & mask) > 0) 1250 { 1251 if(!isSecure && !IsInterruptTargetNonSecure(i)) 1252 { 1253 this.WarningLog("Cannot {0} IRQ {1}, since it targets Secure state, and the access is in Non-secure", 1254 enable ? "enable" : "disable", ExceptionToString(i)); 1255 continue; 1256 } 1257 1258 if(enable) 1259 { 1260 this.NoisyLog("Enabled IRQ {0}.", ExceptionToString(i)); 1261 irqs[i] |= IRQState.Enabled; 1262 } 1263 else 1264 { 1265 this.NoisyLog("Disabled IRQ {0}.", ExceptionToString(i)); 1266 irqs[i] &= ~IRQState.Enabled; 1267 } 1268 } 1269 mask <<= 1; 1270 } 1271 FindPendingInterrupt(); 1272 } 1273 } 1274 } 1275 HandleEnableRead(int offset, bool isSecure)1276 private uint HandleEnableRead(int offset, bool isSecure) 1277 { 1278 lock(irqs) 1279 { 1280 var firstIRQNo = 8 * offset + 16; 1281 var lastIRQNo = firstIRQNo + 31; 1282 var result = 0u; 1283 if(firstIRQNo < 0 || lastIRQNo > irqs.Length) 1284 { 1285 this.Log(LogLevel.Error, "Trying to access IRQs from range {0}-{1}, but only {2} are defined (offset 0x{3:X})", firstIRQNo, lastIRQNo, irqs.Length, offset); 1286 return result; 1287 } 1288 for(var i = lastIRQNo; i > firstIRQNo; i--) 1289 { 1290 // Cannot read the enable state of a Secure interrupt in a Non-secure state, read zero instead 1291 if(isSecure || IsInterruptTargetNonSecure(i)) 1292 { 1293 result |= ((irqs[(int)i] & IRQState.Enabled) != 0) ? 1u : 0u; 1294 } 1295 result <<= 1; 1296 } 1297 if(isSecure || IsInterruptTargetNonSecure(firstIRQNo)) 1298 { 1299 result |= ((irqs[(int)firstIRQNo] & IRQState.Enabled) != 0) ? 1u : 0u; 1300 } 1301 return result; 1302 } 1303 } 1304 SetPending(int i)1305 private void SetPending(int i) 1306 { 1307 this.DebugLog("Set pending IRQ {0}.", ExceptionToString(i)); 1308 var before = irqs[i]; 1309 irqs[i] |= IRQState.Pending; 1310 pendingIRQs.Add(i); 1311 1312 // when SEVONPEND is set all interrupts (even those masked) 1313 // generate an event when entering the pending state 1314 if(before != irqs[i] && currentSevOnPending.Get(IsInterruptTargetNonSecure(i))) 1315 { 1316 foreach(var cpu in machine.SystemBus.GetCPUs().OfType<CortexM>()) 1317 { 1318 cpu.SetEventFlag(true); 1319 } 1320 } 1321 } 1322 ClearPending(int i)1323 private void ClearPending(int i) 1324 { 1325 lock(irqs) 1326 { 1327 if((irqs[i] & IRQState.Running) == 0) 1328 { 1329 this.DebugLog("Cleared pending IRQ {0}.", ExceptionToString(i)); 1330 irqs[i] &= ~IRQState.Pending; 1331 pendingIRQs.Remove(i); 1332 } 1333 else 1334 { 1335 this.DebugLog("Not clearing pending IRQ {0} as it is currently running.", ExceptionToString(i)); 1336 } 1337 } 1338 } 1339 SetOrClearPendingInterrupt(int offset, uint value, bool set, bool isSecure)1340 private void SetOrClearPendingInterrupt(int offset, uint value, bool set, bool isSecure) 1341 { 1342 lock(irqs) 1343 { 1344 var firstIRQNo = 8 * offset + 16; // 16 is added because this is HW interrupt 1345 { 1346 var lastIRQNo = firstIRQNo + 31; 1347 var mask = 1u; 1348 for(var i = firstIRQNo; i <= lastIRQNo; i++) 1349 { 1350 if((value & mask) > 0) 1351 { 1352 if(!isSecure && !IsInterruptTargetNonSecure(i)) 1353 { 1354 this.WarningLog("Cannot {0} pending IRQ {1}, since it targets Secure state, and the access is in Non-secure", 1355 set ? "set" : "clear", ExceptionToString(i)); 1356 continue; 1357 } 1358 if (set) 1359 { 1360 SetPending(i); 1361 } 1362 else 1363 { 1364 ClearPending(i); 1365 } 1366 } 1367 mask <<= 1; 1368 } 1369 FindPendingInterrupt(); 1370 } 1371 } 1372 } 1373 ModifySecurityTarget(int offset, uint value)1374 private void ModifySecurityTarget(int offset, uint value) 1375 { 1376 lock(irqs) 1377 { 1378 var mask = 1u; 1379 // Only HW interrupts are modified by this 1380 for(var i = 0; i < 32; i++) 1381 { 1382 var pos = 16 + offset * 8 + i; 1383 this.NoisyLog("IRQ {0} configured as {1}", ExceptionToString(pos), (value & mask) > 0 ? "Non-secure" : "Secure"); 1384 targetInterruptSecurityState[pos] = (value & mask) > 0 ? InterruptTargetSecurityState.NonSecure : InterruptTargetSecurityState.Secure; 1385 mask <<= 1; 1386 } 1387 } 1388 } 1389 FindPendingInterrupt()1390 public int FindPendingInterrupt() 1391 { 1392 lock(irqs) 1393 { 1394 var bestPriority = 0xFF + 1; 1395 var preemptNeeded = activeIRQs.Count != 0; 1396 var result = SpuriousInterrupt; // TODO (and some log?) 1397 1398 foreach(int i in pendingIRQs) 1399 { 1400 var currentIRQ = irqs[i]; 1401 if(IsCandidate(currentIRQ, i) && AdjustPriority(i) < bestPriority) 1402 { 1403 result = i; 1404 bestPriority = AdjustPriority(i); 1405 } 1406 } 1407 if(preemptNeeded) 1408 { 1409 var activeTop = activeIRQs.Peek(); 1410 var activePriority = AdjustPriority(activeTop); 1411 if(!DoesAPreemptB(bestPriority, activePriority, !IsInterruptTargetNonSecure(result), !IsInterruptTargetNonSecure(activeTop))) 1412 { 1413 result = SpuriousInterrupt; 1414 } 1415 else 1416 { 1417 this.NoisyLog("IRQ {0} preempts {1}.", ExceptionToString(result), ExceptionToString(activeTop)); 1418 } 1419 } 1420 1421 if(result != SpuriousInterrupt) 1422 { 1423 if(ShouldRaiseException(result)) 1424 { 1425 IRQ.Set(true); 1426 } 1427 // This field has side-effects, and can cause Cortex-M CPU running in another thread to exit WFI immediately. 1428 // Make absolutely sure to execute last, after signaling IRQ handler to run with `IRQ.Set`. 1429 // Only this way the CPU will enter an exception handler immediately upon waking from WFI. 1430 // This doesn't matter for async (HW) interrupts, arriving when the core is executing normally. 1431 maskedInterruptPresent = true; 1432 } 1433 else 1434 { 1435 maskedInterruptPresent = false; 1436 } 1437 1438 return result; 1439 } 1440 } 1441 1442 /// <remarks> 1443 /// This exposes raw value of <see cref="targetInterruptSecurityState"/> 1444 /// note, that for some exceptions, this doesn't mean that they are Secure, since some exceptions are banked 1445 /// </remarks> 1446 [HideInMonitor] GetTargetInterruptSecurityState(int interruptNumber)1447 public InterruptTargetSecurityState GetTargetInterruptSecurityState(int interruptNumber) 1448 { 1449 // Don't check this for banked IRQs - this makes no sense at all! 1450 // since they are taken to the state in which they occurred - they can be triggered independently 1451 DebugHelper.Assert(!bankedInterrupts.Contains(interruptNumber)); 1452 1453 return targetInterruptSecurityState[interruptNumber]; 1454 } 1455 1456 ShouldRaiseException(int excp)1457 private bool ShouldRaiseException(int excp) 1458 { 1459 /* The intuition to understanding this: 1460 * PRIMASK is used to mask all exceptions, minus Reset, NMI and HardFault 1461 * FAULTMASK is a more restrictive PRIMASK, also masking HardFault 1462 * _NS variants will attempt to only disable NonSecure exceptions, but this can only happen if "PRIS" is set 1463 * here `BFHFNMINS` will also matter, since it retargets several exceptions (e.g. NMI), and enables HardFault banking 1464 */ 1465 if(!cpu.TrustZoneEnabled) 1466 { 1467 // These have prio below -1, so they are never maskable 1468 if(excp == (int)SystemException.NMI || excp == (int)SystemException.Reset) 1469 { 1470 return true; 1471 } 1472 1473 if(cpu.PRIMASK == 0 && cpu.FAULTMASK == 0) 1474 { 1475 return true; 1476 } 1477 else if(cpu.PRIMASK != 0 && cpu.FAULTMASK == 0) 1478 { 1479 // If only PRIMASK is set, HardFault always goes through 1480 return excp == (int)SystemException.HardFault; 1481 } 1482 // Otherwise, if FAULTMASK is set, deny everything 1483 } 1484 else 1485 { 1486 // Reset is not maskable 1487 if(excp == (int)SystemException.Reset) 1488 { 1489 return true; 1490 } 1491 1492 if(cpu.GetFaultmask(true) > 0 || cpu.GetFaultmask(false) > 0) 1493 { 1494 // "BFHFNMINS" is 1 1495 bool isNSEnabled = GetTargetInterruptSecurityState((int)SystemException.HardFault) == InterruptTargetSecurityState.NonSecure; 1496 if(cpu.GetFaultmask(true) > 0) 1497 { 1498 if(isNSEnabled) 1499 { 1500 return false; 1501 } 1502 else 1503 { 1504 return excp == (int)SystemException.HardFault_S || excp == (int)SystemException.NMI; 1505 } 1506 } 1507 else if(cpu.GetFaultmask(false) > 0) 1508 { 1509 if(isNSEnabled) 1510 { 1511 // If Configurable exceptions target Non-secure mode, and PRIS is set, we boost current execution priority to 0x80 1512 // which is the boundary between Secure and Non-secure priorities, so only Secure exceptions will pass. 1513 // If PRIS is unset, we block everything (raise priotity to 0), but not HardFault (Secure and Non-Secure) and NMI. 1514 return (prioritizeSecureInterrupts && !IsInterruptTargetNonSecure(excp)) 1515 || excp == (int)SystemException.NMI || excp == (int)SystemException.HardFault || excp == (int)SystemException.HardFault_S; 1516 } 1517 else 1518 { 1519 // Configurable exceptions target Secure mode only, so we raise execution priority to -1 1520 return excp == (int)SystemException.NMI; 1521 } 1522 } 1523 } 1524 // Secure PRIMASK is unset, so all pass, unless Non-secure is set 1525 else if(cpu.GetPrimask(true) == 0) 1526 { 1527 if(cpu.GetPrimask(false) == 0) 1528 { 1529 return true; 1530 } 1531 else 1532 { 1533 // If PRIMASK_NS is set, and PRIS is set, we boost current execution priority to 0x80 1534 // which is the boundary between Secure and Non-secure priorities, so only Secure exceptions will pass. 1535 // If PRIS is unset, we block everything (raise priotity to 0), but not HardFault and NMI. 1536 return (prioritizeSecureInterrupts && !IsInterruptTargetNonSecure(excp)) 1537 || excp == (int)SystemException.NMI || excp == (int)SystemException.HardFault; 1538 } 1539 } 1540 // Secure PRIMASK is set - deny all, except HardFault and NMI (exec priority boosted to 0) 1541 else if(cpu.GetPrimask(true) > 0) 1542 { 1543 return excp == (int)SystemException.HardFault || excp == (int)SystemException.HardFault_S || excp == (int)SystemException.NMI; 1544 } 1545 } 1546 1547 // Ignore exception otherwise 1548 return false; 1549 } 1550 AdjustPriority(int interruptNo)1551 private int AdjustPriority(int interruptNo) 1552 { 1553 byte priority = priorities[interruptNo]; 1554 if(!prioritizeSecureInterrupts) 1555 { 1556 return priority; 1557 } 1558 /* Rule: RWQWK (ARMv8-M Architecture Reference Manual) 1559 * When AIRCR.PRIS is 1, each Non-secure SHPRn_NS.PRI_n priority field value [7:0] has the following sequence 1560 * applied to it, it: 1561 * 1. Is divided by two. 1562 * 2. The constant 0x80 is then added to it. 1563 * though it appears that it applies to all Non-secure interrupts, not only exceptions configurable with SHPRn_NS.PRI_n 1564 */ 1565 1566 // It is a "byte" after all 1567 DebugHelper.Assert(priority <= 255); 1568 1569 if(IsInterruptTargetNonSecure(interruptNo)) 1570 { 1571 // Divide by two, and set 7th bit. Since 255 is the lowest priority (highest number), this is fine 1572 priority >>= 1; 1573 priority |= 0x80; 1574 } 1575 return priority; 1576 } 1577 IsInterruptTargetNonSecure(int interruptNo)1578 private bool IsInterruptTargetNonSecure(int interruptNo) 1579 { 1580 if(!cpu.TrustZoneEnabled) 1581 { 1582 return true; 1583 } 1584 if(bankedInterrupts.Contains(interruptNo)) 1585 { 1586 return (interruptNo & BankedExcpSecureBit) == 0; 1587 } 1588 // HardFault is banked if "BFHFNMINS" is set 1589 if((interruptNo == (int)SystemException.HardFault_S || interruptNo == (int)SystemException.HardFault) 1590 && targetInterruptSecurityState[(int)SystemException.HardFault] == InterruptTargetSecurityState.NonSecure) 1591 { 1592 return (interruptNo & BankedExcpSecureBit) == 0; 1593 } 1594 return targetInterruptSecurityState[interruptNo] == InterruptTargetSecurityState.NonSecure; 1595 } 1596 IsCandidate(IRQState state, int index)1597 private bool IsCandidate(IRQState state, int index) 1598 { 1599 const IRQState mask = IRQState.Pending | IRQState.Enabled | IRQState.Active; 1600 const IRQState candidate = IRQState.Pending | IRQState.Enabled; 1601 1602 return ((state & mask) == candidate) && 1603 (basepri.Get(!IsInterruptTargetNonSecure(index)) == 0 || priorities[index] < basepri.Get(!IsInterruptTargetNonSecure(index))); 1604 } 1605 DoesAPreemptB(int priorityA, int priorityB, bool secureA, bool secureB)1606 private bool DoesAPreemptB(int priorityA, int priorityB, bool secureA, bool secureB) 1607 { 1608 var binaryPointMaskA = ~((1 << binaryPointPosition.Get(secureA) + 1) - 1); 1609 var binaryPointMaskB = ~((1 << binaryPointPosition.Get(secureB) + 1) - 1); 1610 return (priorityA & binaryPointMaskA) < (priorityB & binaryPointMaskB); 1611 } 1612 GetPending(int offset, bool isSecure)1613 private uint GetPending(int offset, bool isSecure) 1614 { 1615 int startIndex = 16 + offset * 8; 1616 return BitHelper.GetValueFromBitsArray(irqs.Skip(startIndex).Take(32).Select((irq, idx) => (isSecure || IsInterruptTargetNonSecure(startIndex + idx)) && ((irq & IRQState.Pending) != 0))); 1617 } 1618 GetActive(int offset, bool isSecure)1619 private uint GetActive(int offset, bool isSecure) 1620 { 1621 int startIndex = 16 + offset * 8; 1622 return BitHelper.GetValueFromBitsArray(irqs.Skip(startIndex).Take(32).Select((irq, idx) => (isSecure || IsInterruptTargetNonSecure(startIndex + idx)) && ((irq & IRQState.Active) != 0))); 1623 } 1624 GetSecurityTarget(int offset)1625 private uint GetSecurityTarget(int offset) 1626 { 1627 // We skip first 16 entries, as these are not Hard IRQs. Some of them can be configured by `AIRCR.BFHFNMINS`, but we use common list to store their configuration 1628 return BitHelper.GetValueFromBitsArray(targetInterruptSecurityState.Skip(16 + offset * 8).Take(32).Select(irq => irq == InterruptTargetSecurityState.NonSecure)); 1629 } 1630 IsPrivilegedMode()1631 private bool IsPrivilegedMode() 1632 { 1633 // Is in handler mode or is privileged 1634 return (cpu.XProgramStatusRegister & InterruptProgramStatusRegisterMask) != 0 || (cpu.Control & 1) == 0; 1635 } 1636 1637 /* Expect this to return `true` only if the CPU is in Secure state 1638 * otherwise this will return `false` - also for CPUs with disabled TrustZone 1639 * or for Monitor access. If the CPU was not the originator (e.g. Monitor), then `currentCpu` will be `null` 1640 */ IsCurrentCPUInSecureState(out ICPU currentCpu)1641 private bool IsCurrentCPUInSecureState(out ICPU currentCpu) 1642 { 1643 currentCpu = null; 1644 try 1645 { 1646 currentCpu = machine.GetSystemBus(this).GetCurrentCPU(); 1647 // Checking if TZ is enabled is a short-cut to avoid lengthy lookups into CPU state 1648 // and stack unwinding if an exception is thrown. 1649 // It results in a significant speed-up 1650 if(currentCpu is CortexM mcpu && mcpu.TrustZoneEnabled) 1651 { 1652 return mcpu.SecureState; 1653 } 1654 return false; 1655 } 1656 catch(RecoverableException) 1657 { 1658 // TrustZone might not be enabled 1659 return false; 1660 } 1661 } 1662 ExceptionToString(int exception)1663 private static string ExceptionToString(int exception) 1664 { 1665 if(Enum.IsDefined(typeof(SystemException), exception)) 1666 { 1667 return ((SystemException)exception).ToString(); 1668 } 1669 // Otherwise, it's an external Hard IRQ. 1670 return $"HardwareIRQ#{exception - ((int)SystemException.SysTick) - 1} ({exception})"; 1671 } 1672 1673 // This is just a cache of BASEPRI register, present in ARMv7M and newer CPUs 1674 // modifying them here will cause a bad desync with the CPU state 1675 private readonly SecurityBanked<byte> basepri; 1676 1677 [HideInMonitor] 1678 public byte BASEPRI_NS 1679 { 1680 get { return basepri.NonSecureVal; } 1681 set 1682 { 1683 if(value == basepri.NonSecureVal) 1684 { 1685 return; 1686 } 1687 basepri.NonSecureVal = value; 1688 FindPendingInterrupt(); 1689 } 1690 } 1691 1692 [HideInMonitor] 1693 public byte BASEPRI_S 1694 { 1695 get { return basepri.SecureVal; } 1696 set 1697 { 1698 if(value == basepri.SecureVal) 1699 { 1700 return; 1701 } 1702 basepri.SecureVal = value; 1703 FindPendingInterrupt(); 1704 } 1705 } 1706 1707 [Flags] 1708 private enum IRQState : byte 1709 { 1710 Running = 1, 1711 Pending = 2, 1712 Active = 4, 1713 Enabled = 32 1714 } 1715 1716 private enum Registers 1717 { 1718 InterruptControllerType = 0x4, 1719 SysTickControl = 0x10, 1720 SysTickReloadValue = 0x14, 1721 SysTickValue = 0x18, 1722 SysTickCalibrationValue = 0x1C, 1723 SetEnable = 0x100, 1724 ClearEnable = 0x180, 1725 SetPending = 0x200, 1726 ClearPending = 0x280, 1727 ActiveBit = 0x300, 1728 InterruptTargetNonSecure = 0x380, // ITNS 1729 InterruptPriority = 0x400, 1730 CPUID = 0xD00, 1731 InterruptControlState = 0xD04, 1732 VectorTableOffset = 0xD08, 1733 ApplicationInterruptAndReset = 0xD0C, // AIRCR 1734 SystemControlRegister = 0xD10, // SCR 1735 ConfigurationAndControl = 0xD14, // CCR 1736 SystemHandlerPriority1 = 0xD18, // SHPR1 1737 SystemHandlerPriority2 = 0xD1C, // SHPR2 1738 SystemHandlerPriority3 = 0xD20, // SHPR3 1739 SystemHandlerControlAndState = 0xD24, // SHCSR 1740 ConfigurableFaultStatus = 0xD28, // CFSR 1741 HardFaultStatus = 0xD2C, // HFSR 1742 DebugFaultStatus = 0xD30, // DFSR 1743 // FPU registers 0xD88 .. F3C 1744 MemoryFaultAddress = 0xD34, // MMFAR 1745 BusFaultAddress = 0xD38, // BFAR 1746 AuxiliaryFaultStatus = 0xD3C, // AFSR 1747 ProcessorFeature0 = 0xD40, // ID_PFR0 1748 ProcessorFeature1 = 0xD44, // ID_PFR1 1749 DebugFeature0 = 0xD48, // ID_DFR0 1750 AuxiliaryFeature0 = 0xD4C, // ID_AFR0 1751 MemoryModelFeature0 = 0xD50, // ID_MMFR0 1752 MemoryModelFeature1 = 0xD54, // ID_MMFR1 1753 MemoryModelFeature2 = 0xD58, // ID_MMFR2 1754 MemoryModelFeature3 = 0xD5C, // ID_MMFR3 1755 InstructionSetAttribute0 = 0xD60, // ID_ISAR0 1756 InstructionSetAttribute1 = 0xD64, // ID_ISAR1 1757 InstructionSetAttribute2 = 0xD68, // ID_ISAR2 1758 InstructionSetAttribute3 = 0xD6C, // ID_ISAR3 1759 InstructionSetAttribute4 = 0xD70, // ID_ISAR4 1760 ID_ISAR5 = 0xD74, // ID_ISAR5 1761 CacheLevelID = 0xD78, // CLIDR 1762 CacheType = 0xD7C, // CTR 1763 CacheSizeID = 0xD80, // CCSIDR 1764 CacheSizeSelection = 0xD84, // CSSELR 1765 CoprocessorAccessControl = 0xD88, // CPACR 1766 MPUType = 0xD90, // MPU_TYPE 1767 MPUControl = 0xD94, // MPU_CTRL 1768 MPURegionNumber = 0xD98, // MPU_RNR 1769 MPURegionBaseAddress = 0xD9C, // MPU_RBAR 1770 MPURegionAttributeAndSize = 0xDA0, // MPU_RASR 1771 Alias1OfMPURegionBaseAddress = 0xDA4, // MPU_RBAR_A1 1772 Alias1OfMPURegionAttributeAndSize = 0xDA8, // MPU_RASR_A1 1773 Alias2OfMPURegionBaseAddress = 0xDAC, // MPU_RBAR_A2 1774 Alias2OfMPURegionAttributeAndSize = 0xDB0, // MPU_RASR_A2 1775 Alias3OfMPURegionBaseAddress = 0xDB4, // MPU_RBAR_A3 1776 Alias3OfMPURegionAttributeAndSize = 0xDB8, // MPU_RASR_A3 1777 SAUControl = 0xDD0, // SAU_CTRL 1778 SAUType = 0xDD4, // SAU_TYPE 1779 SAURegionNumber = 0xDD8, // SAU_RNR 1780 SAURegionBaseAddress = 0xDDC, // SAU_RBAR 1781 SAURegionLimitAddress = 0xDE0, // SAU_RLAR 1782 SecureFaultStatus = 0xDE4, // SAU_SFSR 1783 SecureFaultAddress = 0xDE8, // SAU_SFAR 1784 DebugExceptionAndMonitorControlRegister = 0xDFC, // DEMCR 1785 SoftwareTriggerInterrupt = 0xF00, // STIR 1786 FPContextControl = 0xF34, // FPCCR 1787 FPContextAddress = 0xF38, // FPCAR 1788 FPDefaultStatusControl = 0xF3C, // FPDSCR 1789 FloatingPointDefaultStatusControl = 0xF3C, // FPDSCR 1790 MediaAndFPFeature0 = 0xF40, // MVFR0 1791 MediaAndFPFeature1 = 0xF44, // MVFR1 1792 MediaAndFPFeature2 = 0xF48, // MVFR2 1793 ICacheInvalidateAllToPoUaIgnored = 0xF50, // ICIALLU 1794 ICacheInvalidateByMVAToPoUaAddress = 0xF58, // ICIMVAU 1795 DCacheInvalidateByMVAToPoCAddress = 0xF5C, // DCIMVAC 1796 DCacheInvalidateBySetWay= 0xF60, // DCISW 1797 DCacheCleanByMVAToPoUAddress = 0xF64, // DCCMVAU 1798 DCacheCleanByMVAToPoCAddress = 0xF68, // DCCMVAC 1799 DCacheCleanBySetWay= 0xF6C, // DCCSW 1800 DCacheCleanAndInvalidateByMVAToPoCAddress = 0xF70, // DCCIMVAC 1801 DCacheCleanAndInvalidateBySetWay= 0xF74, // DCCISW 1802 BranchPredictorInvalidateAllIgnored = 0xF78, // BPIALL 1803 1804 // Registers with addresses from 0xF90 to 0xFCF are implementation defined. 1805 // The following ones are valid for Cortex-M7. 1806 InstructionTightlyCoupledMemoryControl = 0xF90, // ITCMCR 1807 DataTightlyCoupledMemoryControl = 0xF94, // DTCMCR 1808 AHBPControl = 0xF98, // AHBPCR 1809 L1CacheControl = 0xF9C, // CACR 1810 AHBSlaveControl = 0xFA0, // AHBSCR 1811 AuxiliaryBusFaultStatus = 0xFA8, // ABFSR 1812 } 1813 1814 private enum RegistersV7 1815 { 1816 Type = 0x00, 1817 Control = 0x04, 1818 RegionNumber = 0x08, 1819 RegionBaseAddress = 0x0C, 1820 RegionAttributeAndSize = 0x10, 1821 RegionBaseAddressAlias1 = 0x14, 1822 RegionAttributeAndSizeAlias1 = 0x18, 1823 RegionBaseAddressAlias2 = 0x1C, 1824 RegionAttributeAndSizeAlias2 = 0x20, 1825 RegionBaseAddressAlias3 = 0x24, 1826 RegionAttributeAndSizeAlias3 = 0x28, 1827 } 1828 1829 private enum RegistersV8 1830 { 1831 Type = 0x00, 1832 Control = 0x04, 1833 RegionNumberRegister = 0x08, 1834 RegionBaseAddressRegister = 0x0C, 1835 RegionLimitAddressRegister = 0x10, 1836 RegionBaseAddressRegisterAlias1 = 0x14, 1837 RegionLimitAddressRegisterAlias1 = 0x18, 1838 RegionBaseAddressRegisterAlias2 = 0x1C, 1839 RegionLimitAddressRegisterAlias2 = 0x20, 1840 RegionBaseAddressRegisterAlias3 = 0x24, 1841 RegionLimitAddressRegisterAlias3 = 0x28, 1842 MemoryAttributeIndirectionRegister0 = 0x30, 1843 MemoryAttributeIndirectionRegister1 = 0x34 1844 } 1845 1846 private enum RegistersSAU 1847 { 1848 Control = 0x0, // SAU_CTRL 1849 Type = 0x4, // SAU_TYPE 1850 RegionNumber = 0x8, // SAU_RNR 1851 RegionBaseAddress = 0xc, // SAU_RBAR 1852 RegionLimitAddress = 0x10, // SAU_RLAR 1853 } 1854 1855 private enum MPUVersion 1856 { 1857 PMSAv7, 1858 PMSAv8 1859 } 1860 1861 private enum SystemException 1862 { 1863 Reset = 1, 1864 NMI = 2, 1865 HardFault = 3, 1866 MemManageFault = 4, 1867 BusFault = 5, 1868 UsageFault = 6, 1869 SecureFault = 7, 1870 SuperVisorCall = 11, 1871 DebugMonitor = 12, 1872 PendSV = 14, 1873 SysTick = 15, 1874 1875 // These are not real exceptions! 1876 // We cheat here a bit, to create banked exceptions for TrustZone 1877 // since they can live indepenently from their not-banked variants (so effectively they behave like separate exceptions) 1878 HardFault_S = HardFault | BankedExcpSecureBit, 1879 MemManageFault_S = MemManageFault | BankedExcpSecureBit, 1880 UsageFault_S = UsageFault | BankedExcpSecureBit, 1881 SuperVisorCall_S = SuperVisorCall | BankedExcpSecureBit, 1882 DebugMonitor_S = DebugMonitor | BankedExcpSecureBit, 1883 PendSV_S = PendSV | BankedExcpSecureBit, 1884 SysTick_S = SysTick | BankedExcpSecureBit, 1885 } 1886 1887 public enum InterruptTargetSecurityState 1888 { 1889 Secure = 0, 1890 NonSecure = 1, 1891 } 1892 1893 private class SecurityBanked<T> 1894 { 1895 public T SecureVal; 1896 public T NonSecureVal; 1897 Reset()1898 public void Reset() 1899 { 1900 SecureVal = default(T); 1901 NonSecureVal = default(T); 1902 } 1903 Reset(T val)1904 public void Reset(T val) 1905 { 1906 SecureVal = val; 1907 NonSecureVal = val; 1908 } 1909 Get(bool IsSecure)1910 public ref T Get(bool IsSecure) 1911 { 1912 return ref IsSecure ? ref SecureVal : ref NonSecureVal; 1913 } 1914 } 1915 1916 private class SysTick 1917 { SysTick(IMachine machine, NVIC parent, long systickFrequency, bool isSecure = false)1918 public SysTick(IMachine machine, NVIC parent, long systickFrequency, bool isSecure = false) 1919 { 1920 IsSecure = isSecure; 1921 this.parent = parent; 1922 // We set initial limit to the maximum 24-bit value, and don't modify it afterwards. 1923 // Instead we reload counter with RELOAD value when counter reaches 0. 1924 systick = new LimitTimer(machine.ClockSource, systickFrequency, parent, nameof(systick) + (isSecure ? "_S" : "_NS"), SysTickMaxValue, Direction.Descending, false, eventEnabled: true); 1925 systick.LimitReached += () => 1926 { 1927 CountFlag = true; 1928 if(TickInterruptEnabled) 1929 { 1930 parent.SetPendingIRQ((int)(IsSecure ? SystemException.SysTick_S : SystemException.SysTick)); 1931 } 1932 1933 // If the systick timer is running and the reload value is 0, this has the effect of disabling the counter on the expiration. 1934 if(Reload == 0) 1935 { 1936 systick.Enabled = false; 1937 } 1938 else 1939 { 1940 systick.Value = Reload; 1941 } 1942 }; 1943 } 1944 Reset()1945 public void Reset() 1946 { 1947 systickEnabled = false; 1948 reloadValue = 0; 1949 1950 systick.Reset(); 1951 systick.AutoUpdate = true; 1952 } 1953 UpdateSystickValue()1954 public void UpdateSystickValue() 1955 { 1956 if(reloadValue != 0) 1957 { 1958 // Write to this register does not trigger the SysTick exception logic - we can't write zero to timer value as it would trigger an event. 1959 systick.Value = reloadValue; 1960 } 1961 CountFlag = false; 1962 } 1963 1964 public bool IsSecure { get; } 1965 1966 public bool TickInterruptEnabled { get; set; } // TICKINT 1967 public bool CountFlag { get; set; } // COUNTFLAG 1968 1969 // Systick can be enabled but doesn't have to count, e.g. if RELOAD value is set to 0, 1970 // or we are in DEEPSLEEP 1971 public bool Enabled 1972 { 1973 get => systickEnabled; 1974 set 1975 { 1976 systickEnabled = value; 1977 if(value && Reload == 0) 1978 { 1979 parent.DebugLog("Systick_{0} enabled but it won't be started as long as the reload value is zero", IsSecure ? "S" : "NS"); 1980 return; 1981 } 1982 parent.NoisyLog("Systick_{0} {1}", IsSecure ? "S" : "NS", value ? "enabled" : "disabled"); 1983 systick.Enabled = value; 1984 } 1985 } 1986 1987 public ulong Value // CURRENT 1988 { 1989 get => systick.Value; 1990 } 1991 1992 public ulong Reload // RELOAD 1993 { 1994 get => reloadValue; 1995 set 1996 { 1997 if(Enabled && reloadValue == 0 && !systick.Enabled) 1998 { 1999 // We explicitly enable underlying SysTick counter only in the case it was blocked by RELOAD=0. 2000 // We ignore other cases, as we don't want to accidentally enable counter in DEEPSLEEP just by writing to this register. 2001 parent.DebugLog("Resuming Systick_{0} counter due to reload value change from 0x0 to 0x{1:X}", IsSecure ? "_S" : "_NS", value); 2002 systick.Value = value; 2003 systick.Enabled = true; 2004 } 2005 reloadValue = value; 2006 } 2007 } 2008 2009 public long Frequency 2010 { 2011 get => systick.Frequency; 2012 set 2013 { 2014 systick.Frequency = value; 2015 } 2016 } 2017 2018 public int Divider 2019 { 2020 get => systick.Divider; 2021 set 2022 { 2023 systick.Divider = value; 2024 } 2025 } 2026 2027 private ulong reloadValue; 2028 private bool systickEnabled; // ENABLE 2029 private readonly LimitTimer systick; 2030 private readonly NVIC parent; 2031 } 2032 2033 /// This is the simplest hash-map-like class, to store exceptions. 2034 /// We use <see cref="BankedExcpSecureBit"/> to mark banked exception as Secure. 2035 /// Such exception behaves like separate exception (e.g. Secure and Non-secure banked exception can exist at once). 2036 /// This way, we can use the end of the array to place the extra Secure banked exceptions 2037 /// it's still easier than using a dictionary. 2038 private class ExceptionSimpleArray<T> : IEnumerable<T> 2039 { ExceptionSimpleArray()2040 public ExceptionSimpleArray() 2041 { 2042 // Regular IRQs, plus banked, plus HardFault (which can be banked, but doesn't have to be) 2043 container = new T[IRQCount + bankedInterrupts.Length / 2 + 1]; 2044 } 2045 Clear()2046 public void Clear() 2047 { 2048 Array.Clear(container, 0, container.Length); 2049 } 2050 2051 public T this[int index] 2052 { 2053 get 2054 { 2055 return container[MapSystemExceptionToInteger(index)]; 2056 } 2057 set 2058 { 2059 container[MapSystemExceptionToInteger(index)] = value; 2060 } 2061 } 2062 2063 public int Length => container.Length; 2064 MapSystemExceptionToInteger(int exception)2065 private static int MapSystemExceptionToInteger(int exception) 2066 { 2067 if(exception < BankedExcpSecureBit) 2068 { 2069 return exception; 2070 } 2071 switch(exception) 2072 { 2073 case (int)SystemException.MemManageFault_S: 2074 return IRQCount; 2075 case (int)SystemException.UsageFault_S: 2076 return IRQCount + 1; 2077 case (int)SystemException.SuperVisorCall_S: 2078 return IRQCount + 2; 2079 case (int)SystemException.PendSV_S: 2080 return IRQCount + 3; 2081 case (int)SystemException.SysTick_S: 2082 return IRQCount + 4; 2083 case (int)SystemException.HardFault_S: 2084 return IRQCount + 5; 2085 case (int)SystemException.DebugMonitor_S: 2086 return IRQCount + 6; 2087 default: 2088 throw new InvalidOperationException($"Exception number {exception} is invalid"); 2089 } 2090 } 2091 GetEnumerator()2092 public IEnumerator<T> GetEnumerator() 2093 { 2094 return container.AsEnumerable().GetEnumerator(); 2095 } 2096 IEnumerable.GetEnumerator()2097 IEnumerator IEnumerable.GetEnumerator() 2098 { 2099 return GetEnumerator(); 2100 } 2101 2102 private readonly T[] container; 2103 } 2104 2105 // bit [16] DC / Cache enable. This is a global enable bit for data and unified caches. 2106 private readonly SecurityBanked<uint> ccr; 2107 2108 private readonly bool defaultHaltSystickOnDeepSleep; 2109 private readonly SecurityBanked<SysTick> systick; 2110 private readonly byte priorityMask; 2111 private readonly SecurityBanked<bool> currentSevOnPending; 2112 private readonly Stack<int> activeIRQs; 2113 private readonly ISet<int> pendingIRQs; 2114 private readonly SecurityBanked<int> binaryPointPosition; // from the right 2115 private bool isNextAccessSecure; 2116 private bool canResetOnlyFromSecure; 2117 private bool deepSleepOnlyFromSecure; 2118 private bool prioritizeSecureInterrupts; 2119 private uint mpuControlRegister; 2120 private MPUVersion mpuVersion; 2121 2122 private bool maskedInterruptPresent; 2123 2124 // This is configurable through NVIC_ITNSx only for Hardware Interrupts (exception numbered 16 and above) 2125 // for configuring selected exceptions, look at AIRCR.BFHFNMINS 2126 // for other exceptions, this will be completely ignored 2127 private readonly InterruptTargetSecurityState[] targetInterruptSecurityState; 2128 2129 private readonly ExceptionSimpleArray<IRQState> irqs; 2130 private readonly ExceptionSimpleArray<byte> priorities; 2131 private readonly Action resetMachine; 2132 private CortexM cpu; 2133 private readonly IMachine machine; 2134 private uint cpuId; 2135 2136 private IFlagRegisterField sleepOnExitEnabled; 2137 2138 private static readonly int[] bankedInterrupts = new int [] 2139 { 2140 (int)SystemException.MemManageFault, 2141 (int)SystemException.UsageFault, 2142 (int)SystemException.SuperVisorCall, 2143 (int)SystemException.PendSV, 2144 (int)SystemException.SysTick, 2145 (int)SystemException.DebugMonitor, 2146 2147 (int)SystemException.MemManageFault_S, 2148 (int)SystemException.UsageFault_S, 2149 (int)SystemException.SuperVisorCall_S, 2150 (int)SystemException.PendSV_S, 2151 (int)SystemException.SysTick_S, 2152 (int)SystemException.DebugMonitor_S, 2153 // Lack of HardFault here is not a mistake 2154 // HardFault is by default handled as Secure exception 2155 }; 2156 2157 private const string TrustZoneNSRegionWarning = "Without TrustZone enabled in the CPU, a NonSecure region should not be registered"; 2158 private const int MPUStart = 0xD90; 2159 private const int MPUEnd = 0xDC4; // resized for compat. with V8 MPU 2160 private const int SAUStart = 0xDD0; 2161 private const int SAUEnd = 0xDE4; 2162 private const int SetEnableStart = 0x100; 2163 private const int SetEnableEnd = 0x140; 2164 private const int ClearEnableStart = 0x180; 2165 private const int ClearEnableEnd = 0x1C0; 2166 private const int SetPendingStart = 0x200; 2167 private const int SetPendingEnd = 0x240; 2168 private const int ClearPendingStart = 0x280; 2169 private const int ClearPendingEnd = 0x2C0; 2170 private const int ActiveBitStart = 0x300; 2171 private const int ActiveBitEnd = 0x320; 2172 private const int TargetNonSecureStart = 0x380; 2173 private const int TargetNonSecureEnd = 0x3C0; 2174 private const int PriorityStart = 0x400; 2175 private const int PriorityEnd = 0x7F0; 2176 private const int IRQCount = 512 + 16 + 1; 2177 private const int SpuriousInterrupt = IRQCount - 1; 2178 private const int VectKey = 0x5FA; 2179 private const int VectKeyStat = 0xFA05; 2180 private const uint SysTickMaximumValue = 0x00FFFFFF; 2181 2182 private const int BankedExcpSecureBit = 1 << 30; 2183 private const uint InterruptProgramStatusRegisterMask = 0x1FF; 2184 private const int SysTickCalibration100Hz = 100; 2185 private const int SysTickMaxValue = (1 << 24) - 1; 2186 } 2187 } 2188