@@ -55,3 +55,161 @@ macro_rules! singleton {
55
55
} )
56
56
} ;
57
57
}
58
+
59
+ /// Macro to create interfaces to PLIC contexts in PACs.
60
+ ///
61
+ /// This macro expects 5 arguments:
62
+ ///
63
+ /// - `PLIC`: name of the PLIC context interface structure to be created.
64
+ /// We recommend to leave `PLIC` for context 0 and `PLICx` for the remaining contexts.
65
+ ///
66
+ /// - `BASE`: base address of the PLIC peripheral of the target.
67
+ ///
68
+ /// - `CONTEXT`: context number assigned to the PLIC interface.
69
+ ///
70
+ /// - `INTERRUPT`: enum type of the external interruptions of the target.
71
+ /// This type must implement the [`crate::peripheral::plic::InterruptNumber`] trait.
72
+ ///
73
+ /// - `PRIORITY`: enum type of the priority levels supported by the target.
74
+ /// This type must implement the [`crate::peripheral::plic::PriorityNumber`] trait.
75
+ ///
76
+ /// # Note
77
+ ///
78
+ /// This macro requires the `plic` feature to be active.
79
+ #[ cfg( feature = "plic" ) ]
80
+ #[ macro_export]
81
+ macro_rules! plic_context {
82
+ ( $PLIC: ident, $BASE: literal, $CONTEXT: literal, $INTERRUPT: ident, $PRIORITY: ident) => {
83
+ /// Platform-Level Interrupt Controller (PLIC) context.
84
+ #[ repr( transparent) ]
85
+ pub struct $PLIC {
86
+ context: $crate:: peripheral:: PLIC <$BASE, $CONTEXT>,
87
+ }
88
+
89
+ impl $PLIC {
90
+ /// Creates a new PLIC context interface.
91
+ pub const fn new( ) -> Self {
92
+ Self {
93
+ context: $crate:: peripheral:: PLIC :: new( ) ,
94
+ }
95
+ }
96
+
97
+ /// Enables machine external interrupts.
98
+ #[ inline( always) ]
99
+ pub fn enable( ) {
100
+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: enable( ) ;
101
+ }
102
+
103
+ /// Disables machine external interrupts.
104
+ #[ inline( always) ]
105
+ pub fn disable( ) {
106
+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: disable( ) ;
107
+ }
108
+
109
+ /// Returns the priority level associated to a given interrupt source.
110
+ #[ inline( always) ]
111
+ pub fn priority( source: $INTERRUPT) -> $PRIORITY {
112
+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: priority( source)
113
+ }
114
+
115
+ /// Getter method for the priority level associated to a given interrupt source.
116
+ #[ inline( always) ]
117
+ pub fn get_priority( & self , source: $INTERRUPT) -> $PRIORITY {
118
+ Self :: priority( source)
119
+ }
120
+
121
+ /// Sets the priority level of a given interrupt source.
122
+ ///
123
+ /// # Note
124
+ ///
125
+ /// Interrupt source priorities are shared among all the contexts of the PLIC.
126
+ /// Thus, changing the priority of sources may affect other PLIC contexts.
127
+ ///
128
+ /// # Safety
129
+ ///
130
+ /// Changing priority levels can break priority-based critical sections and compromise memory safety.
131
+ #[ inline( always) ]
132
+ pub unsafe fn set_priority( & mut self , source: $INTERRUPT, priority: $PRIORITY) {
133
+ self . context. set_priority( source, priority) ;
134
+ }
135
+
136
+ /// Checks if an interrupt triggered by a given source is pending.
137
+ #[ inline( always) ]
138
+ pub fn is_interrupt_pending( source: $INTERRUPT) -> bool {
139
+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: is_interrupt_pending( source)
140
+ }
141
+
142
+ /// Checks if an interrupt source is enabled for the PLIC context.
143
+ #[ inline( always) ]
144
+ pub fn is_interrupt_enabled( source: $INTERRUPT) -> bool {
145
+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: is_interrupt_enabled( source)
146
+ }
147
+
148
+ /// Enables an interrupt source for the PLIC context.
149
+ ///
150
+ /// # Safety
151
+ ///
152
+ /// It performs non-atomic read-modify-write operations, which may lead to undefined behavior.
153
+ /// Additionally, Enabling an interrupt source can break mask-based critical sections.
154
+ #[ inline( always) ]
155
+ pub unsafe fn enable_interrupt( & mut self , source: $INTERRUPT) {
156
+ self . context. enable_interrupt( source) ;
157
+ }
158
+
159
+ /// Disables an interrupt source for the PLIC context.
160
+ ///
161
+ /// # Safety
162
+ ///
163
+ /// It performs non-atomic read-modify-write operations, which may lead to undefined behavior.
164
+ #[ inline( always) ]
165
+ pub unsafe fn disable_interrupt( & mut self , source: $INTERRUPT) {
166
+ self . context. disable_interrupt( source) ;
167
+ }
168
+
169
+ /// Returns the priority threshold of the PLIC context.
170
+ #[ inline( always) ]
171
+ pub fn threshold( ) -> $PRIORITY {
172
+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: threshold( )
173
+ }
174
+
175
+ /// Getter method for the priority threshold of the PLIC context.
176
+ #[ inline( always) ]
177
+ pub fn get_threshold( & self ) -> $PRIORITY {
178
+ Self :: threshold( )
179
+ }
180
+
181
+ /// Sets the priority threshold for for the PLIC context.
182
+ ///
183
+ /// # Safety
184
+ ///
185
+ /// Unmasking an interrupt source can break mask-based critical sections.
186
+ #[ inline( always) ]
187
+ pub unsafe fn set_threshold( & mut self , priority: $PRIORITY) {
188
+ self . context. set_threshold( priority) ;
189
+ }
190
+
191
+ /// Claims the number of a pending interrupt for for the PLIC context.
192
+ /// If no interrupt is pending for this context, it returns [`None`].
193
+ #[ inline( always) ]
194
+ pub fn claim( ) -> Option <$INTERRUPT> {
195
+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: claim( )
196
+ }
197
+
198
+ /// Marks a pending interrupt as complete from for the PLIC context.
199
+ #[ inline( always) ]
200
+ pub fn complete( source: $INTERRUPT) {
201
+ $crate:: peripheral:: PLIC :: <$BASE, $CONTEXT>:: complete( source) ;
202
+ }
203
+
204
+ /// Resets the PLIC peripherals.
205
+ ///
206
+ /// # Safety
207
+ ///
208
+ /// It performs non-atomic read-modify-write operations, which may lead to undefined behavior.
209
+ #[ inline( always) ]
210
+ pub unsafe fn reset( & mut self ) {
211
+ self . context. reset:: <$INTERRUPT, $PRIORITY>( ) ;
212
+ }
213
+ }
214
+ } ;
215
+ }
0 commit comments