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