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.Generic; 11 using System.Runtime.InteropServices; 12 using Antmicro.Renode.Core; 13 using Antmicro.Renode.Peripherals.Bus; 14 using Antmicro.Renode.Peripherals.IRQControllers; 15 using Antmicro.Renode.Utilities.Binding; 16 using Antmicro.Renode.Logging; 17 using Antmicro.Migrant.Hooks; 18 using Antmicro.Renode.Exceptions; 19 using ELFSharp.ELF; 20 using ELFSharp.UImage; 21 using Machine = Antmicro.Renode.Core.Machine; 22 23 namespace Antmicro.Renode.Peripherals.CPU 24 { 25 public partial class CortexM : Arm, IPeripheralWithTransactionState 26 { CortexM(string cpuType, IMachine machine, NVIC nvic, [NameAlias(R)] uint cpuId = 0, Endianess endianness = Endianess.LittleEndian, uint? fpuInterruptNumber = null, uint? numberOfMPURegions = null, bool enableTrustZone = false, uint? numberOfSAURegions = null, uint? numberOfIDAURegions = null)27 public CortexM(string cpuType, IMachine machine, NVIC nvic, [NameAlias("id")] uint cpuId = 0, Endianess endianness = Endianess.LittleEndian, 28 uint? fpuInterruptNumber = null, uint? numberOfMPURegions = null, bool enableTrustZone = false, uint? numberOfSAURegions = null, uint? numberOfIDAURegions = null) 29 : base(cpuType, machine, cpuId, endianness, numberOfMPURegions) 30 { 31 if(nvic == null) 32 { 33 throw new RecoverableException(new ArgumentNullException("nvic")); 34 } 35 36 tlibSetFpuInterruptNumber((int?)fpuInterruptNumber ?? -1); 37 38 if(!numberOfMPURegions.HasValue) 39 { 40 // FIXME: This is not correct for M7 and v8M cores 41 // Setting 8 regions backward-compatibility for now 42 this.NumberOfMPURegions = 8; 43 } 44 45 TrustZoneEnabled = enableTrustZone; 46 if(TrustZoneEnabled) 47 { 48 // Set CPU to start in Secure State 49 // this also enables TrustZone in the translation library 50 tlibSetSecurityState(1u); 51 52 NumberOfSAURegions = numberOfSAURegions ?? 8; // TODO: Determine default number 53 if(!numberOfSAURegions.HasValue) 54 { 55 this.Log(LogLevel.Info, "Configuring Security Attribution Unit regions to default: {0}", NumberOfSAURegions); 56 } 57 58 NumberOfIDAURegions = numberOfIDAURegions ?? 8; // TODO: Determine default number 59 if(!numberOfIDAURegions.HasValue) 60 { 61 this.Log(LogLevel.Info, "Configuring Implementation-Defined Attribution Unit regions to default: {0}", NumberOfIDAURegions); 62 } 63 } 64 65 this.nvic = nvic; 66 try 67 { 68 nvic.AttachCPU(this); 69 } 70 catch(RecoverableException e) 71 { 72 // Rethrow attachment error as ConstructionException, so the CreationDriver doesn't crash 73 throw new ConstructionException("Exception occurred when attaching NVIC: ", e); 74 } 75 } 76 77 public class ContextState : IContextState 78 { 79 public bool Privileged; 80 public bool CpuSecure; 81 public bool AttributionSecure; 82 } 83 Reset()84 public override void Reset() 85 { 86 pcNotInitialized = true; 87 vtorInitialized = false; 88 base.Reset(); 89 } 90 SetSleepOnExceptionExit(bool value)91 public void SetSleepOnExceptionExit(bool value) 92 { 93 tlibSetSleepOnExceptionExit(value ? 1 : 0); 94 } 95 OnResume()96 protected override void OnResume() 97 { 98 // Suppress initialization when processor is turned off as binary may not even be loaded yet 99 if(!IsHalted) 100 { 101 InitPCAndSP(); 102 } 103 base.OnResume(); 104 } 105 106 public override string Architecture { get { return "arm-m"; } } 107 108 public override List<GDBFeatureDescriptor> GDBFeatures 109 { 110 get 111 { 112 var features = new List<GDBFeatureDescriptor>(); 113 114 var mProfileFeature = new GDBFeatureDescriptor("org.gnu.gdb.arm.m-profile"); 115 for(var index = 0u; index <= 12; index++) 116 { 117 mProfileFeature.Registers.Add(new GDBRegisterDescriptor(index, 32, $"r{index}", "uint32", "general")); 118 } 119 mProfileFeature.Registers.Add(new GDBRegisterDescriptor(13, 32, "sp", "data_ptr", "general")); 120 mProfileFeature.Registers.Add(new GDBRegisterDescriptor(14, 32, "lr", "uint32", "general")); 121 mProfileFeature.Registers.Add(new GDBRegisterDescriptor(15, 32, "pc", "code_ptr", "general")); 122 mProfileFeature.Registers.Add(new GDBRegisterDescriptor(25, 32, "xpsr", "uint32", "general")); 123 features.Add(mProfileFeature); 124 125 var mSystemFeature = new GDBFeatureDescriptor("org.gnu.gdb.arm.m-system"); 126 mSystemFeature.Registers.Add(new GDBRegisterDescriptor(26, 32, "msp", "uint32", "general")); 127 mSystemFeature.Registers.Add(new GDBRegisterDescriptor(27, 32, "psp", "uint32", "general")); 128 mSystemFeature.Registers.Add(new GDBRegisterDescriptor(28, 32, "primask", "uint32", "general")); 129 mSystemFeature.Registers.Add(new GDBRegisterDescriptor(29, 32, "basepri", "uint32", "general")); 130 mSystemFeature.Registers.Add(new GDBRegisterDescriptor(30, 32, "faultmask", "uint32", "general")); 131 mSystemFeature.Registers.Add(new GDBRegisterDescriptor(31, 32, "control", "uint32", "general")); 132 features.Add(mSystemFeature); 133 134 return features; 135 } 136 } 137 138 public IReadOnlyDictionary<string, int> StateBits { get { return stateBits; } } 139 140 /// <remark>Should only be used for TrustZone CPUs, <see cref="RecoverableException"/> is thrown otherwise.</remark> GetIDAURegion(uint regionIndex)141 public IDAURegion GetIDAURegion(uint regionIndex) 142 { 143 AssertTrustZoneEnabled($"get IDAU region {regionIndex}"); 144 145 var rbar = tlibGetIdauRegionBaseAddressRegister(regionIndex); 146 var rlar = tlibGetIdauRegionLimitAddressRegister(regionIndex); 147 return new IDAURegion(rbar, rlar); 148 } 149 150 /// <remarks> 151 /// Should only be used for TrustZone CPUs, <see cref="RecoverableException"/> is thrown otherwise. 152 /// It's also thrown in case <paramref name="region"/>'s index is greater than <see cref="NumberOfIDAURegions"/>. 153 /// </remarks> SetIDAURegion(uint regionIndex, IDAURegion region)154 public void SetIDAURegion(uint regionIndex, IDAURegion region) 155 { 156 AssertTrustZoneEnabled($"set IDAU region {regionIndex}"); 157 158 if(regionIndex >= NumberOfIDAURegions) 159 { 160 throw new RecoverableException($"Invalid IDAU region: {regionIndex}, {nameof(NumberOfIDAURegions)}: {NumberOfIDAURegions}"); 161 } 162 163 tlibSetIdauRegionBaseAddressRegister(regionIndex, region.ToRBAR()); 164 tlibSetIdauRegionLimitAddressRegister(regionIndex, region.ToRLAR()); 165 } 166 SetIDAURegion(uint regionIndex, uint baseAddress, uint limitAddress, bool enabled, bool nonSecureCallable)167 public void SetIDAURegion(uint regionIndex, uint baseAddress, uint limitAddress, bool enabled, bool nonSecureCallable) 168 { 169 SetIDAURegion(regionIndex, new IDAURegion(baseAddress, limitAddress, enabled, nonSecureCallable)); 170 } 171 SetIDAURegion(uint regionIndex, uint rbar, uint rlar)172 public void SetIDAURegion(uint regionIndex, uint rbar, uint rlar) 173 { 174 SetIDAURegion(regionIndex, new IDAURegion(rbar, rlar)); 175 } 176 177 /// <remark>Should only be used for TrustZone CPUs, <see cref="RecoverableException"/> is thrown otherwise.</remark> TryAddImplementationDefinedExemptionRegion(uint startAddress, uint endAddress)178 public bool TryAddImplementationDefinedExemptionRegion(uint startAddress, uint endAddress) 179 { 180 AssertTrustZoneEnabled($"add implementation-defined exemption region 0x{startAddress:X8}-0x{endAddress:X8}"); 181 182 return tlibTryAddImplementationDefinedExemptionRegion(startAddress, endAddress) == 1u; 183 } 184 185 /// <remark>Should only be used for TrustZone CPUs, <see cref="RecoverableException"/> is thrown otherwise.</remark> TryRemoveImplementationDefinedExemptionRegion(uint startAddress, uint endAddress)186 public bool TryRemoveImplementationDefinedExemptionRegion(uint startAddress, uint endAddress) 187 { 188 AssertTrustZoneEnabled($"remove implementation-defined exemption region 0x{startAddress:X8}-0x{endAddress:X8}"); 189 190 return tlibTryRemoveImplementationDefinedExemptionRegion(startAddress, endAddress) == 1u; 191 } 192 193 public override MemorySystemArchitectureType MemorySystemArchitecture => NumberOfMPURegions > 0 ? MemorySystemArchitectureType.Physical_PMSA : MemorySystemArchitectureType.None; 194 195 public override uint ExceptionVectorAddress 196 { 197 get => VectorTableOffset; 198 set => VectorTableOffset = value; 199 } 200 201 // Sets VTOR for the current Security State the CPU is in right now 202 public uint VectorTableOffset 203 { 204 get 205 { 206 var secure = 0u; 207 if(TrustZoneEnabled) 208 { 209 secure = SecureState ? 1u : 0u; 210 } 211 return tlibGetInterruptVectorBase(secure); 212 } 213 set 214 { 215 var secure = 0u; 216 if(TrustZoneEnabled) 217 { 218 secure = SecureState ? 1u : 0u; 219 } 220 vtorInitialized = true; 221 if(!machine.SystemBus.IsMemory(value, this)) 222 { 223 this.Log(LogLevel.Warning, "Tried to set VTOR address at 0x{0:X} which does not lay in memory. Aborted.", value); 224 return; 225 } 226 this.NoisyLog("VectorTableOffset set to 0x{0:X}.", value); 227 tlibSetInterruptVectorBase(value, secure); 228 } 229 } 230 231 // NS alias for VTOR 232 public uint VectorTableOffsetNonSecure 233 { 234 get 235 { 236 if(!TrustZoneEnabled) 237 { 238 throw new RecoverableException("You need to enable TrustZone to use VTOR_NS"); 239 } 240 return tlibGetInterruptVectorBase(0u); 241 } 242 set 243 { 244 if(!TrustZoneEnabled) 245 { 246 throw new RecoverableException("You need to enable TrustZone to use VTOR_NS"); 247 } 248 vtorInitialized = true; 249 if(machine.SystemBus.FindMemory(value, this) == null) 250 { 251 this.Log(LogLevel.Warning, "Tried to set VTOR_NS address at 0x{0:X} which does not lay in memory. Aborted.", value); 252 return; 253 } 254 this.NoisyLog("VectorTableOffset_NS set to 0x{0:X}.", value); 255 tlibSetInterruptVectorBase(value, 0u); 256 } 257 } 258 259 [Register] 260 public RegisterValue FPCAR_NS 261 { 262 get => GetTrustZoneRelatedRegister(nameof(FPCAR_NS), () => GetRegisterValue32NonSecure((int)CortexMRegisters.FPCAR)); 263 set => SetTrustZoneRelatedRegister(nameof(FPCAR_NS), val => SetRegisterValue32NonSecure((int)CortexMRegisters.FPCAR, val), value); 264 } 265 266 [Register] 267 public RegisterValue FPDSCR_NS 268 { 269 get => GetTrustZoneRelatedRegister(nameof(FPDSCR_NS), () => GetRegisterValue32NonSecure((int)CortexMRegisters.FPDSCR)); 270 set => SetTrustZoneRelatedRegister(nameof(FPDSCR_NS), val => SetRegisterValue32NonSecure((int)CortexMRegisters.FPDSCR, val), value); 271 } 272 273 [Register] 274 public RegisterValue FPCCR_NS 275 { 276 get => GetTrustZoneRelatedRegister(nameof(FPCCR_NS), () => GetRegisterValue32NonSecure((int)CortexMRegisters.FPCCR)); 277 set => SetTrustZoneRelatedRegister(nameof(FPCCR_NS), val => SetRegisterValue32NonSecure((int)CortexMRegisters.FPCCR, val), value); 278 } 279 [Register] 280 public RegisterValue CPACR_NS 281 { 282 get => GetTrustZoneRelatedRegister(nameof(CPACR_NS), () => GetRegisterValue32NonSecure((int)CortexMRegisters.CPACR)); 283 set => SetTrustZoneRelatedRegister(nameof(CPACR_NS), val => SetRegisterValue32NonSecure((int)CortexMRegisters.CPACR, val), value); 284 } 285 286 public bool IDAUEnabled 287 { 288 get => GetTrustZoneRelatedRegister(nameof(IDAUEnabled), () => tlibGetIdauEnabled()) == 1u; 289 set => SetTrustZoneRelatedRegister(nameof(IDAUEnabled), val => tlibSetIdauEnabled(val), value ? 1u : 0u); 290 } 291 292 public uint NumberOfIDAURegions 293 { 294 get => GetTrustZoneRelatedRegister(nameof(NumberOfIDAURegions), () => tlibGetNumberOfIdauRegions()); 295 set => SetTrustZoneRelatedRegister(nameof(NumberOfIDAURegions), val => tlibSetNumberOfIdauRegions(val), value); 296 } 297 298 public uint NumberOfSAURegions 299 { 300 get => GetTrustZoneRelatedRegister(nameof(NumberOfSAURegions), () => tlibGetNumberOfSauRegions()); 301 set => SetTrustZoneRelatedRegister(nameof(NumberOfSAURegions), val => tlibSetNumberOfSauRegions(val), value); 302 } 303 304 public bool SecureState 305 { 306 get 307 { 308 AssertTrustZoneEnabled("get SecurityState"); 309 return tlibGetSecurityState() > 0; 310 } 311 set 312 { 313 AssertTrustZoneEnabled("modify SecurityState"); 314 tlibSetSecurityState(value ? 1u : 0u); 315 } 316 } 317 318 public bool FpuEnabled 319 { 320 set 321 { 322 tlibToggleFpu(value ? 1 : 0); 323 } 324 } 325 326 public bool TrustZoneEnabled { get; } 327 328 public UInt32 FaultStatus 329 { 330 get 331 { 332 var secure = 0u; 333 if(TrustZoneEnabled) 334 { 335 secure = SecureState ? 1u : 0u; 336 } 337 return tlibGetFaultStatus(secure); 338 } 339 set 340 { 341 var secure = 0u; 342 if(TrustZoneEnabled) 343 { 344 secure = SecureState ? 1u : 0u; 345 } 346 tlibSetFaultStatus(value, secure); 347 } 348 } 349 350 public UInt32 FaultStatusNonSecure 351 { 352 get 353 { 354 AssertTrustZoneEnabled("get FaultStatus_NS"); 355 return tlibGetFaultStatus(0u); 356 } 357 set 358 { 359 AssertTrustZoneEnabled("set FaultStatus_NS"); 360 tlibSetFaultStatus(value, 0u); 361 } 362 } 363 364 public UInt32 MemoryFaultAddress 365 { 366 get 367 { 368 var secure = 0u; 369 if(TrustZoneEnabled) 370 { 371 secure = SecureState ? 1u : 0u; 372 } 373 return tlibGetMemoryFaultAddress(secure); 374 } 375 } 376 377 public UInt32 MemoryFaultAddressNonSecure 378 { 379 get 380 { 381 AssertTrustZoneEnabled("get MemoryFaultAddress_NS"); 382 return tlibGetMemoryFaultAddress(0u); 383 } 384 } 385 386 public UInt32 SecureFaultAddress 387 { 388 get 389 { 390 AssertTrustZoneEnabled("get SecureFaultAddress"); 391 return tlibGetSecureFaultAddress(); 392 } 393 } 394 395 396 public UInt32 SecureFaultStatus 397 { 398 get 399 { 400 AssertTrustZoneEnabled("get SecureFaultStatus"); 401 return tlibGetSecureFaultStatus(); 402 } 403 set 404 { 405 AssertTrustZoneEnabled("set SecureFaultStatus"); 406 tlibSetSecureFaultStatus(value); 407 } 408 } 409 410 public bool IsV8 411 { 412 get 413 { 414 return tlibIsV8() > 0; 415 } 416 } 417 418 public UInt32 PmsaV8Ctrl 419 { 420 get 421 { 422 return tlibGetPmsav8Ctrl(); 423 } 424 set 425 { 426 tlibSetPmsav8Ctrl(value); 427 } 428 } 429 430 public UInt32 PmsaV8Rnr 431 { 432 get 433 { 434 return tlibGetPmsav8Rnr(); 435 } 436 set 437 { 438 tlibSetPmsav8Rnr(value); 439 } 440 } 441 442 public UInt32 PmsaV8Rbar 443 { 444 get 445 { 446 return tlibGetPmsav8Rbar(); 447 } 448 set 449 { 450 tlibSetPmsav8Rbar(value); 451 } 452 } 453 454 public UInt32 PmsaV8Rlar 455 { 456 get 457 { 458 return tlibGetPmsav8Rlar(); 459 } 460 set 461 { 462 tlibSetPmsav8Rlar(value); 463 } 464 } 465 466 public UInt32 PmsaV8Mair0 467 { 468 get 469 { 470 return tlibGetPmsav8Mair(0); 471 } 472 set 473 { 474 tlibSetPmsav8Mair(0, value); 475 } 476 } 477 478 public UInt32 PmsaV8Mair1 479 { 480 get 481 { 482 return tlibGetPmsav8Mair(1); 483 } 484 set 485 { 486 tlibSetPmsav8Mair(1, value); 487 } 488 } 489 490 public bool MPUEnabled 491 { 492 get 493 { 494 return tlibIsMpuEnabled() != 0; 495 } 496 set 497 { 498 tlibEnableMpu(value ? 1 : 0); 499 } 500 } 501 502 public UInt32 MPURegionBaseAddress 503 { 504 set 505 { 506 tlibSetMpuRegionBaseAddress(value); 507 } 508 get 509 { 510 return tlibGetMpuRegionBaseAddress(); 511 } 512 } 513 514 public UInt32 MPURegionAttributeAndSize 515 { 516 set 517 { 518 tlibSetMpuRegionSizeAndEnable(value); 519 } 520 get 521 { 522 return tlibGetMpuRegionSizeAndEnable(); 523 } 524 } 525 526 public UInt32 MPURegionNumber 527 { 528 set 529 { 530 tlibSetMpuRegionNumber(value); 531 } 532 get 533 { 534 return tlibGetMpuRegionNumber(); 535 } 536 } 537 538 public uint SAUControl 539 { 540 get => GetTrustZoneRelatedRegister(nameof(SAUControl), () => tlibGetSauControl()); 541 set => SetTrustZoneRelatedRegister(nameof(SAUControl), val => tlibSetSauControl(val), value); 542 } 543 544 public uint SAURegionNumber 545 { 546 get => GetTrustZoneRelatedRegister(nameof(SAURegionNumber), () => tlibGetSauRegionNumber()); 547 set => SetTrustZoneRelatedRegister(nameof(SAURegionNumber), val => tlibSetSauRegionNumber(val), value); 548 } 549 550 public uint SAURegionBaseAddress 551 { 552 get => GetTrustZoneRelatedRegister(nameof(SAURegionBaseAddress), () => tlibGetSauRegionBaseAddress()); 553 set => SetTrustZoneRelatedRegister(nameof(SAURegionBaseAddress), val => tlibSetSauRegionBaseAddress(val), value); 554 } 555 556 public uint SAURegionLimitAddress 557 { 558 get => GetTrustZoneRelatedRegister(nameof(SAURegionLimitAddress), () => tlibGetSauRegionLimitAddress()); 559 set => SetTrustZoneRelatedRegister(nameof(SAURegionLimitAddress), val => tlibSetSauRegionLimitAddress(val), value); 560 } 561 562 public CortexMImplementationDefinedAttributionUnit ImplementationDefinedAttributionUnit 563 { 564 set 565 { 566 if(value != null) 567 { 568 tlibSetCustomIdauHandlerEnabled(1); 569 } 570 else 571 { 572 tlibSetCustomIdauHandlerEnabled(0); 573 } 574 idau = value; 575 } 576 } 577 578 public uint XProgramStatusRegister 579 { 580 get 581 { 582 return tlibGetXpsr(); 583 } 584 } 585 GetPrimask(bool secure)586 public uint GetPrimask(bool secure) 587 { 588 return tlibGetPrimask(secure ? 1u : 0u); 589 } 590 GetFaultmask(bool secure)591 public uint GetFaultmask(bool secure) 592 { 593 return tlibGetFaultmask(secure ? 1u : 0u); 594 } 595 InitFromElf(IELF elf)596 public override void InitFromElf(IELF elf) 597 { 598 // do nothing 599 } 600 InitFromUImage(UImage uImage)601 public override void InitFromUImage(UImage uImage) 602 { 603 // do nothing 604 } 605 BeforePCWrite(UInt32 value)606 protected override UInt32 BeforePCWrite(UInt32 value) 607 { 608 if(value % 2 == 0) 609 { 610 this.Log(LogLevel.Warning, "Patching PC 0x{0:X} for Thumb mode.", value); 611 value += 1; 612 } 613 pcNotInitialized = false; 614 return base.BeforePCWrite(value); 615 } 616 OnLeavingResetState()617 protected override void OnLeavingResetState() 618 { 619 if(EmulationState == EmulationCPUState.Running) 620 { 621 InitPCAndSP(); 622 } 623 base.OnLeavingResetState(); 624 } 625 626 /// <remarks>Use <see cref="GetTrustZoneRelatedRegister"/> and <see cref="SetTrustZoneRelatedRegister"/> to wrap accesses which have to succeed.</remarks> AssertTrustZoneEnabled(string actionName)627 private void AssertTrustZoneEnabled(string actionName) 628 { 629 if(!TrustZoneEnabled) 630 { 631 throw new RecoverableException($"Tried to {actionName} in CPU with TrustZone disabled"); 632 } 633 } 634 GetTrustZoneRelatedRegister(string registerName, Func<uint> getter)635 private uint GetTrustZoneRelatedRegister(string registerName, Func<uint> getter) 636 { 637 if(!TrustZoneEnabled) 638 { 639 this.Log(LogLevel.Warning, "Tried to read from {0} in CPU without TrustZone implemented, returning 0x0", registerName); 640 return 0x0; 641 } 642 return getter(); 643 } 644 InitPCAndSP()645 private void InitPCAndSP() 646 { 647 var firstNotNullSection = machine.SystemBus.GetLookup(this).FirstNotNullSectionAddress; 648 if(!vtorInitialized && firstNotNullSection.HasValue) 649 { 650 if((firstNotNullSection.Value & (2 << 6 - 1)) > 0) 651 { 652 this.Log(LogLevel.Warning, "Alignment of VectorTableOffset register is not correct."); 653 } 654 else 655 { 656 var value = firstNotNullSection.Value; 657 this.Log(LogLevel.Info, "Guessing VectorTableOffset value to be 0x{0:X}.", value); 658 if(value > uint.MaxValue) 659 { 660 this.Log(LogLevel.Error, "Guessed VectorTableOffset doesn't fit in 32-bit address space: 0x{0:X}.", value); 661 return; // Keep VectorTableOffset uninitialized in the case of error condition 662 } 663 VectorTableOffset = checked((uint)value); 664 } 665 } 666 if(pcNotInitialized) 667 { 668 // stack pointer and program counter are being sent according 669 // to VTOR (vector table offset register) 670 var sysbus = machine.SystemBus; 671 var pc = sysbus.ReadDoubleWord(VectorTableOffset + 4, this); 672 var sp = sysbus.ReadDoubleWord(VectorTableOffset, this); 673 if(!sysbus.IsMemory(pc, this) || (pc == 0 && sp == 0)) 674 { 675 this.Log(LogLevel.Error, "PC does not lay in memory or PC and SP are equal to zero. CPU was halted."); 676 IsHalted = true; 677 return; // Keep PC and SP uninitialized in the case of error condition 678 } 679 this.Log(LogLevel.Info, "Setting initial values: PC = 0x{0:X}, SP = 0x{1:X}.", pc, sp); 680 PC = pc; 681 SP = sp; 682 } 683 } 684 SetTrustZoneRelatedRegister(string registerName, Action<uint> setter, uint value)685 private void SetTrustZoneRelatedRegister(string registerName, Action<uint> setter, uint value) 686 { 687 if(!TrustZoneEnabled) 688 { 689 this.Log(LogLevel.Warning, "Tried to write to {0} (value: 0x{1:X}) in CPU without TrustZone implemented, write ignored", registerName, value); 690 return; 691 } 692 setter(value); 693 } 694 695 [Export] HasEnabledTrustZone()696 private uint HasEnabledTrustZone() 697 { 698 return TrustZoneEnabled ? 1u : 0u; 699 } 700 701 [Export] SetPendingIRQ(int number)702 private void SetPendingIRQ(int number) 703 { 704 nvic.SetPendingIRQ(number); 705 } 706 707 [Export] AcknowledgeIRQ()708 private int AcknowledgeIRQ() 709 { 710 var result = nvic.AcknowledgeIRQ(); 711 return result; 712 } 713 714 [Export] CompleteIRQ(int number)715 private void CompleteIRQ(int number) 716 { 717 nvic.CompleteIRQ(number); 718 } 719 720 [Export] OnBASEPRIWrite(int value, uint secure)721 private void OnBASEPRIWrite(int value, uint secure) 722 { 723 if(secure > 0) 724 { 725 nvic.BASEPRI_S = (byte)value; 726 } 727 else 728 { 729 nvic.BASEPRI_NS = (byte)value; 730 } 731 } 732 733 [Export] FindPendingIRQ()734 private int FindPendingIRQ() 735 { 736 return nvic != null ? nvic.FindPendingInterrupt() : -1; 737 } 738 739 [Export] PendingMaskedIRQ()740 private int PendingMaskedIRQ() 741 { 742 return nvic.MaskedInterruptPresent ? 1 : 0; 743 } 744 745 [Export] InterruptTargetsSecure(int interruptNumber)746 private uint InterruptTargetsSecure(int interruptNumber) 747 { 748 return nvic.GetTargetInterruptSecurityState(interruptNumber) == NVIC.InterruptTargetSecurityState.Secure ? 1u : 0u; 749 } 750 751 [Export] CustomIdauHandler(IntPtr request, IntPtr region, IntPtr attribution)752 private int CustomIdauHandler(IntPtr request, IntPtr region, IntPtr attribution) 753 { 754 if(idau == null) 755 { 756 return 0; 757 } 758 759 var parsedRequest = (ExternalIDAURequest)Marshal.PtrToStructure(request, typeof(ExternalIDAURequest)); 760 var attributionFound = idau.AttributionCheckCallback(parsedRequest.Address, parsedRequest.Secure != 0, (AccessType)parsedRequest.AccessType, parsedRequest.AccessWidth, out var reg, out var attrib); 761 if(attributionFound) 762 { 763 Marshal.WriteInt32(region, reg); 764 Marshal.WriteInt32(attribution, (int)attrib); 765 } 766 return attributionFound ? 1 : 0; 767 } 768 769 public const uint IDAU_SAURegionAddressMask = ~(IDAU_SAURegionMinSize - 1u); 770 public const uint IDAU_SAURegionMinSize = 32u; 771 772 private NVIC nvic; 773 private CortexMImplementationDefinedAttributionUnit idau; 774 private bool pcNotInitialized = true; 775 private bool vtorInitialized; 776 777 // Keep in line with ExternalIDAURequest struct in tlib's arm/arch_callbacks.h 778 [StructLayout(LayoutKind.Sequential)] 779 private struct ExternalIDAURequest 780 { 781 public uint Address; 782 public int Secure; 783 public int AccessType; 784 public int AccessWidth; 785 } 786 787 private static readonly IReadOnlyDictionary<string, int> stateBits = new Dictionary<string, int> 788 { 789 ["privileged"] = 0, 790 ["cpuSecure"] = 1, 791 ["attributionSecure"] = 2, 792 }; 793 TryConvertStateObjToUlong(IContextState stateObj, out ulong? state)794 public bool TryConvertStateObjToUlong(IContextState stateObj, out ulong? state) 795 { 796 state = null; 797 if((stateObj == null) || !(stateObj is ContextState cortexMStateObj)) 798 { 799 return false; 800 } 801 state = 0u; 802 state |= (cortexMStateObj.Privileged ? 1u : 0) & 1u; 803 state |= (cortexMStateObj.CpuSecure ? 2u : 0) & 2u; 804 state |= (cortexMStateObj.AttributionSecure ? 4u : 0) & 4u; 805 return true; 806 } 807 TryConvertUlongToStateObj(ulong? state, out IContextState stateObj)808 public bool TryConvertUlongToStateObj(ulong? state, out IContextState stateObj) 809 { 810 stateObj = null; 811 if(!state.HasValue) 812 { 813 return false; 814 } 815 var cortexMStateObj = new ContextState 816 { 817 Privileged = (state & 1u) == 1u, 818 CpuSecure = (state & 2u) == 2u, 819 AttributionSecure = (state & 4u) == 4u 820 }; 821 stateObj = cortexMStateObj; 822 return true; 823 } 824 825 public struct IDAURegion 826 { IsBaseAddressValidAntmicro.Renode.Peripherals.CPU.CortexM.IDAURegion827 public static bool IsBaseAddressValid(uint address) 828 { 829 return address == (address & IDAU_SAURegionAddressMask); 830 } 831 IsLimitAddressValidAntmicro.Renode.Peripherals.CPU.CortexM.IDAURegion832 public static bool IsLimitAddressValid(uint address) 833 { 834 return address == (address | ~IDAU_SAURegionAddressMask); 835 } 836 IDAURegionAntmicro.Renode.Peripherals.CPU.CortexM.IDAURegion837 public IDAURegion(uint baseAddress, uint limitAddress, bool enabled, bool nonSecureCallable) 838 { 839 if(!IsBaseAddressValid(baseAddress) || !IsLimitAddressValid(limitAddress)) 840 { 841 throw new RecoverableException($"IDAU region must be {IDAU_SAURegionMinSize}B-aligned and the limit is inclusive, " 842 + $"e.g. 0x20-0x7F (limit=0x80 isn't valid); was: 0x{baseAddress:X8}-0x{limitAddress:X8}"); 843 } 844 BaseAddress = baseAddress; 845 LimitAddress = limitAddress; 846 Enabled = enabled; 847 NonSecureCallable = nonSecureCallable; 848 } 849 850 // tlib's IDAU configuration is currently similar to SAU. There are indexed regions for which registers contain 851 // base/limit addresses at bits 5-31 and the remaining bits might be some flags. Currently only used in RLAR. IDAURegionAntmicro.Renode.Peripherals.CPU.CortexM.IDAURegion852 public IDAURegion(uint rbar, uint rlar) 853 { 854 BaseAddress = rbar & IDAU_SAURegionAddressMask; 855 LimitAddress = rlar | ~IDAU_SAURegionAddressMask; 856 Enabled = (rlar & IDAURlarEnabledFlag) == IDAURlarEnabledFlag; 857 NonSecureCallable = (rlar & IDAURlarNonSecureCallableFlag) == IDAURlarNonSecureCallableFlag; 858 } 859 ToRBARAntmicro.Renode.Peripherals.CPU.CortexM.IDAURegion860 public uint ToRBAR() 861 { 862 return BaseAddress; 863 } 864 ToRLARAntmicro.Renode.Peripherals.CPU.CortexM.IDAURegion865 public uint ToRLAR() 866 { 867 uint rlar = LimitAddress & IDAU_SAURegionAddressMask; 868 rlar |= Enabled ? IDAURlarEnabledFlag : 0u; 869 rlar |= NonSecureCallable ? IDAURlarNonSecureCallableFlag : 0u; 870 return rlar; 871 } 872 ToStringAntmicro.Renode.Peripherals.CPU.CortexM.IDAURegion873 public override string ToString() 874 { 875 return $"{nameof(IDAURegion)} [\n" 876 +$" Enabled: {Enabled}\n" 877 +$" From: 0x{BaseAddress:x}, To: 0x{LimitAddress:x}\n" 878 +$" Is Non-secure Callable: {NonSecureCallable}\n" 879 + "]"; 880 } 881 882 // The struct is intentionally immutable so that nobody tries to just modify the struct and call it a day 883 // without passing the modified region to tlib. 884 public uint BaseAddress { get; private set; } 885 public bool Enabled { get; private set; } 886 public uint LimitAddress { get; private set; } 887 public bool NonSecureCallable { get; private set; } 888 889 private const uint IDAURlarEnabledFlag = 1u << 0; 890 private const uint IDAURlarNonSecureCallableFlag = 1u << 1; 891 } 892 893 // 649: Field '...' is never assigned to, and will always have its default value null 894 #pragma warning disable 649 895 896 [Import] 897 private Action<int> tlibToggleFpu; 898 899 [Import] 900 private Func<uint, uint> tlibGetFaultStatus; 901 902 [Import] 903 private Action<uint, uint> tlibSetFaultStatus; 904 905 [Import] 906 private Func<uint, uint> tlibGetMemoryFaultAddress; 907 908 [Import] 909 private Func<uint> tlibGetSecureFaultAddress; 910 911 [Import] 912 private Func<uint> tlibGetSecureFaultStatus; 913 914 [Import] 915 private Action<uint> tlibSetSecureFaultStatus; 916 917 [Import] 918 private Action<int> tlibEnableMpu; 919 920 [Import] 921 private Func<int> tlibIsMpuEnabled; 922 923 [Import] 924 private Action<uint> tlibSetMpuRegionBaseAddress; 925 926 [Import] 927 private Func<uint> tlibGetMpuRegionBaseAddress; 928 929 [Import] 930 private Action<uint> tlibSetMpuRegionSizeAndEnable; 931 932 [Import] 933 private Func<uint> tlibGetMpuRegionSizeAndEnable; 934 935 [Import] 936 private Action<uint> tlibSetMpuRegionNumber; 937 938 [Import] 939 private Func<uint> tlibGetMpuRegionNumber; 940 941 [Import] 942 private Action<int> tlibSetFpuInterruptNumber; 943 944 [Import] 945 private Func<uint, uint> tlibGetInterruptVectorBase; 946 947 [Import] 948 private Action<uint, uint> tlibSetInterruptVectorBase; 949 950 [Import] 951 private Func<uint> tlibGetXpsr; 952 953 [Import] 954 private Action<int> tlibSetSleepOnExceptionExit; 955 956 [Import] 957 private Func<uint, uint> tlibGetPrimask; 958 959 [Import] 960 private Func<uint, uint> tlibGetFaultmask; 961 962 [Import] 963 private Func<uint> tlibIsV8; 964 965 /* TrustZone */ 966 [Import] 967 private Action<uint> tlibSetSecurityState; 968 969 [Import] 970 private Func<uint> tlibGetSecurityState; 971 972 [Import(Name = "tlib_set_register_value_32_non_secure")] 973 private Action<int, uint> SetRegisterValue32NonSecure; 974 975 [Import(Name = "tlib_get_register_value_32_non_secure")] 976 private Func<int, uint> GetRegisterValue32NonSecure; 977 978 /* TrustZone IDAU */ 979 [Import] 980 private Action<uint> tlibSetNumberOfIdauRegions; 981 982 [Import] 983 private Func<uint> tlibGetNumberOfIdauRegions; 984 985 [Import] 986 private Action<uint> tlibSetIdauEnabled; 987 988 [Import] 989 private Func<uint> tlibGetIdauEnabled; 990 991 [Import] 992 private Action<uint, uint> tlibSetIdauRegionBaseAddressRegister; 993 994 [Import] 995 private Action<uint> tlibSetCustomIdauHandlerEnabled; 996 997 [Import] 998 private Func<uint, uint> tlibGetIdauRegionBaseAddressRegister; 999 1000 [Import] 1001 private Action<uint, uint> tlibSetIdauRegionLimitAddressRegister; 1002 1003 [Import] 1004 private Func<uint, uint> tlibGetIdauRegionLimitAddressRegister; 1005 1006 [Import] 1007 private Func<uint, uint, uint> tlibTryAddImplementationDefinedExemptionRegion; 1008 1009 [Import] 1010 private Func<uint, uint, uint> tlibTryRemoveImplementationDefinedExemptionRegion; 1011 1012 /* TrustZone SAU */ 1013 [Import] 1014 private Action<uint> tlibSetNumberOfSauRegions; 1015 1016 [Import] 1017 private Func<uint> tlibGetNumberOfSauRegions; 1018 1019 [Import] 1020 private Action<uint> tlibSetSauControl; 1021 1022 [Import] 1023 private Func<uint> tlibGetSauControl; 1024 1025 [Import] 1026 private Action<uint> tlibSetSauRegionNumber; 1027 1028 [Import] 1029 private Func<uint> tlibGetSauRegionNumber; 1030 1031 [Import] 1032 private Action<uint> tlibSetSauRegionBaseAddress; 1033 1034 [Import] 1035 private Func<uint> tlibGetSauRegionBaseAddress; 1036 1037 [Import] 1038 private Action<uint> tlibSetSauRegionLimitAddress; 1039 1040 [Import] 1041 private Func<uint> tlibGetSauRegionLimitAddress; 1042 1043 /* PMSAv8 MPU */ 1044 [Import] 1045 private Action<uint> tlibSetPmsav8Ctrl; 1046 1047 [Import] 1048 private Action<uint> tlibSetPmsav8Rnr; 1049 1050 [Import] 1051 private Action<uint> tlibSetPmsav8Rbar; 1052 1053 [Import] 1054 private Action<uint> tlibSetPmsav8Rlar; 1055 1056 [Import] 1057 private Action<uint, uint> tlibSetPmsav8Mair; 1058 1059 [Import] 1060 private Func<uint> tlibGetPmsav8Ctrl; 1061 1062 [Import] 1063 private Func<uint> tlibGetPmsav8Rnr; 1064 1065 [Import] 1066 private Func<uint> tlibGetPmsav8Rbar; 1067 1068 [Import] 1069 private Func<uint> tlibGetPmsav8Rlar; 1070 1071 [Import] 1072 private Func<uint, uint> tlibGetPmsav8Mair; 1073 1074 #pragma warning restore 649 1075 } 1076 } 1077 1078