1
+ use core:: { marker:: { PhantomData , PhantomPinned } , mem, pin:: Pin } ;
2
+ use core:: alloc:: Allocator ;
3
+
4
+ use bitflags:: bitflags;
5
+
6
+ use crate :: { platform:: { MemoryInfo , ProcessorTopology } , sdt:: { SdtHeader , Signature } , AcpiResult , AcpiTable } ;
7
+
8
+ /// System Resource Affinity Table (SRAT).
9
+ ///
10
+ /// This optional table provides information that allows OSPM to associate the following types of
11
+ /// devices with system locality / proximity domains and clock domains:
12
+ /// - processors,
13
+ /// - memory ranges (including those provided by hot-added memory devices), and
14
+ /// - generic initiators (e.g. heterogeneous processors and accelerators, GPUs, and I/O devices
15
+ /// with integrated compute or DMA engines).
16
+ #[ repr( C , packed) ]
17
+ pub struct Srat {
18
+ header : SdtHeader ,
19
+ _reserved_1 : u32 ,
20
+ _reserved_2 : u64 ,
21
+ _pinned : PhantomPinned ,
22
+ }
23
+
24
+ /// ### Safety: Implementation properly represents a valid SRAT.
25
+ unsafe impl AcpiTable for Srat {
26
+ const SIGNATURE : Signature = Signature :: SRAT ;
27
+
28
+ fn header ( & self ) -> & SdtHeader {
29
+ & self . header
30
+ }
31
+ }
32
+
33
+ impl Srat {
34
+ #[ cfg( feature = "allocator_api" ) ]
35
+ pub fn parse_topology_in < ' a , A > (
36
+ self : Pin < & Self > ,
37
+ allocator : A
38
+ ) -> AcpiResult < ( ProcessorTopology < ' a , A > , MemoryInfo < ' a , A > ) >
39
+ where
40
+ A : Allocator + Clone ,
41
+ {
42
+ for entry in self . entries ( ) {
43
+ match entry {
44
+ SratEntry :: LocalApic ( _) |
45
+ SratEntry :: LocalX2Apic ( _) => {
46
+ return self . parse_apic_topology_in ( allocator) ;
47
+ }
48
+ SratEntry :: Gicc ( _) |
49
+ SratEntry :: GicIts ( _) => {
50
+ unimplemented ! ( ) ;
51
+ }
52
+ SratEntry :: Memory ( _) |
53
+ SratEntry :: GenericInitiator ( _) => { }
54
+ } ;
55
+ }
56
+
57
+ unreachable ! ( ) ;
58
+ }
59
+
60
+ #[ cfg( feature = "allocator_api" ) ]
61
+ pub fn parse_apic_topology_in < ' a , A > (
62
+ self : Pin < & Self > ,
63
+ allocator : A
64
+ ) -> AcpiResult < ( ProcessorTopology < ' a , A > , MemoryInfo < ' a , A > ) >
65
+ where
66
+ A : Allocator + Clone ,
67
+ {
68
+ use crate :: { platform:: { MemoryRange , ProcessorAffinity } , ManagedSlice } ;
69
+
70
+ let mut processor_count = 0 ;
71
+ let mut memory_range_count = 0 ;
72
+
73
+ for entry in self . entries ( ) {
74
+ match entry {
75
+ SratEntry :: LocalApic ( _) |
76
+ SratEntry :: LocalX2Apic ( _) => processor_count += 1 ,
77
+ SratEntry :: Memory ( _) => memory_range_count += 1 ,
78
+ _ => ( ) ,
79
+ }
80
+ }
81
+
82
+ let mut processor_affinities = ManagedSlice :: new_in ( processor_count, allocator. clone ( ) ) ?;
83
+ let mut memory_ranges = ManagedSlice :: new_in ( memory_range_count, allocator. clone ( ) ) ?;
84
+
85
+ processor_count = 0 ;
86
+ memory_range_count = 0 ;
87
+
88
+ for entry in self . entries ( ) {
89
+ match entry {
90
+ SratEntry :: LocalApic ( entry) => {
91
+ let local_apic_id = entry. apic_id as u32 ;
92
+ let mut proximity_domain = entry. proximity_domain_low as u32 ;
93
+ for i in 0 ..3 {
94
+ let shift = 8 * ( 3 - i) ;
95
+ proximity_domain += ( entry. proximity_domain_high [ i] as u32 ) << shift;
96
+ }
97
+ let flags = entry. flags ;
98
+ let is_enabled = flags. contains ( LocalApicAffinityFlags :: ENABLED ) ;
99
+ let processor_affinity = ProcessorAffinity { local_apic_id, proximity_domain, is_enabled } ;
100
+ processor_affinities[ processor_count] = processor_affinity;
101
+ processor_count += 1 ;
102
+ }
103
+ SratEntry :: LocalX2Apic ( entry) => {
104
+ let local_apic_id = entry. x2apic_id ;
105
+ let proximity_domain = entry. proximity_domain ;
106
+ let flags = entry. flags ;
107
+ let is_enabled = flags. contains ( LocalX2ApicAffinityFlags :: ENABLED ) ;
108
+ let processor_affinity = ProcessorAffinity { local_apic_id, proximity_domain, is_enabled } ;
109
+ processor_affinities[ processor_count] = processor_affinity;
110
+ processor_count += 1 ;
111
+ }
112
+ SratEntry :: Memory ( entry) => {
113
+ let flags = entry. flags ;
114
+ let base_address = entry. base_address_low as u64 + ( ( entry. base_address_high as u64 ) << 32 ) ;
115
+ let length = entry. length_low as u64 + ( ( entry. length_high as u64 ) << 32 ) ;
116
+ let proximity_domain = Some ( entry. proximity_domain ) ;
117
+ let hot_pluggable = flags. contains ( MemoryAffinityFlags :: HOT_PLUGGABLE ) ;
118
+ let non_volatile = flags. contains ( MemoryAffinityFlags :: NON_VOLATILE ) ;
119
+ let is_enabled = flags. contains ( MemoryAffinityFlags :: ENABLED ) ;
120
+ let memory_range = MemoryRange {
121
+ base_address,
122
+ length,
123
+ proximity_domain,
124
+ hot_pluggable,
125
+ non_volatile,
126
+ is_enabled,
127
+ } ;
128
+ memory_ranges[ memory_range_count] = memory_range;
129
+ memory_range_count += 1 ;
130
+ }
131
+ // TODO: parse information of generic initiators
132
+ SratEntry :: GenericInitiator ( _) => { }
133
+ _ => { }
134
+ }
135
+ }
136
+
137
+ let processor_topology = ProcessorTopology { processor_affinities } ;
138
+ let memory_info = MemoryInfo { memory_ranges } ;
139
+ Ok ( ( processor_topology, memory_info) )
140
+ }
141
+
142
+ fn entries ( self : Pin < & Self > ) -> SratEntryIter {
143
+ let ptr = unsafe { Pin :: into_inner_unchecked ( self ) as * const Srat as * const u8 } ;
144
+ SratEntryIter {
145
+ pointer : unsafe { ptr. add ( mem:: size_of :: < Srat > ( ) ) } ,
146
+ remaining_length : self . header . length - mem:: size_of :: < Srat > ( ) as u32 ,
147
+ _phantom : PhantomData ,
148
+ }
149
+ }
150
+ }
151
+
152
+ struct SratEntryIter < ' a > {
153
+ pointer : * const u8 ,
154
+ remaining_length : u32 ,
155
+ _phantom : PhantomData < & ' a ( ) > ,
156
+ }
157
+
158
+ impl < ' a > Iterator for SratEntryIter < ' a > {
159
+ type Item = SratEntry < ' a > ;
160
+
161
+ fn next ( & mut self ) -> Option < Self :: Item > {
162
+ if self . remaining_length > 0 {
163
+ let entry_pointer = self . pointer ;
164
+ let entry_header = unsafe { * ( self . pointer as * const AffinityEntryHeader ) } ;
165
+
166
+ self . pointer = unsafe { self . pointer . offset ( entry_header. length as isize ) } ;
167
+ self . remaining_length -= entry_header. length as u32 ;
168
+
169
+ match entry_header. r#type {
170
+ AffinityEntryType :: LocalApic => Some ( SratEntry :: LocalApic ( unsafe { & * ( entry_pointer as * const LocalApicAffinityEntry ) } ) ) ,
171
+ AffinityEntryType :: Memory => Some ( SratEntry :: Memory ( unsafe { & * ( entry_pointer as * const MemoryAffinityEntry ) } ) ) ,
172
+ AffinityEntryType :: LocalX2Apic => Some ( SratEntry :: LocalX2Apic ( unsafe { & * ( entry_pointer as * const LocalX2ApicAffinityEntry ) } ) ) ,
173
+ AffinityEntryType :: Gicc => Some ( SratEntry :: Gicc ( unsafe { & * ( entry_pointer as * const GiccAffinityEntry ) } ) ) ,
174
+ AffinityEntryType :: GicIts => Some ( SratEntry :: GicIts ( unsafe { & * ( entry_pointer as * const GicItsAffinityEntry ) } ) ) ,
175
+ AffinityEntryType :: GenericInitiator => Some ( SratEntry :: GenericInitiator ( unsafe { & * ( entry_pointer as * const GenericInitiatorAffinityEntry ) } ) ) ,
176
+ }
177
+ } else {
178
+ None
179
+ }
180
+ }
181
+ }
182
+
183
+ enum SratEntry < ' a > {
184
+ LocalApic ( & ' a LocalApicAffinityEntry ) ,
185
+ Memory ( & ' a MemoryAffinityEntry ) ,
186
+ LocalX2Apic ( & ' a LocalX2ApicAffinityEntry ) ,
187
+ Gicc ( & ' a GiccAffinityEntry ) ,
188
+ GicIts ( & ' a GicItsAffinityEntry ) ,
189
+ GenericInitiator ( & ' a GenericInitiatorAffinityEntry ) ,
190
+ }
191
+
192
+ #[ derive( Clone , Copy ) ]
193
+ #[ repr( C , packed) ]
194
+ struct AffinityEntryHeader {
195
+ r#type : AffinityEntryType ,
196
+ length : u8 ,
197
+ }
198
+
199
+ #[ derive( Clone , Copy ) ]
200
+ #[ repr( u8 ) ]
201
+ enum AffinityEntryType {
202
+ LocalApic = 0 ,
203
+ Memory = 1 ,
204
+ LocalX2Apic = 2 ,
205
+ Gicc = 3 ,
206
+ GicIts = 4 ,
207
+ GenericInitiator = 5 ,
208
+ }
209
+
210
+ #[ repr( C , packed) ]
211
+ struct LocalApicAffinityEntry {
212
+ header : AffinityEntryHeader ,
213
+ proximity_domain_low : u8 ,
214
+ apic_id : u8 ,
215
+ flags : LocalApicAffinityFlags ,
216
+ local_sapic_eid : u8 ,
217
+ proximity_domain_high : [ u8 ; 3 ] ,
218
+ clock_domain : u32 ,
219
+ }
220
+
221
+ bitflags ! {
222
+ #[ derive( Clone , Copy ) ]
223
+ struct LocalApicAffinityFlags : u32 {
224
+ const ENABLED = 1 ;
225
+ }
226
+ }
227
+
228
+ #[ repr( C , packed) ]
229
+ struct MemoryAffinityEntry {
230
+ header : AffinityEntryHeader ,
231
+ proximity_domain : u32 ,
232
+ _reserved_1 : u16 ,
233
+ base_address_low : u32 ,
234
+ base_address_high : u32 ,
235
+ length_low : u32 ,
236
+ length_high : u32 ,
237
+ _reserved_2 : u32 ,
238
+ flags : MemoryAffinityFlags ,
239
+ _reserved_3 : u64 ,
240
+ }
241
+
242
+ bitflags ! {
243
+ #[ derive( Clone , Copy ) ]
244
+ struct MemoryAffinityFlags : u32 {
245
+ const ENABLED = 1 ;
246
+ const HOT_PLUGGABLE = 1 << 1 ;
247
+ const NON_VOLATILE = 1 << 2 ;
248
+ }
249
+ }
250
+
251
+ #[ repr( C , packed) ]
252
+ struct LocalX2ApicAffinityEntry {
253
+ header : AffinityEntryHeader ,
254
+ _reserved_1 : u16 ,
255
+ proximity_domain : u32 ,
256
+ x2apic_id : u32 ,
257
+ flags : LocalX2ApicAffinityFlags ,
258
+ clock_domain : u32 ,
259
+ _reserved_2 : u32 ,
260
+ }
261
+
262
+ type LocalX2ApicAffinityFlags = LocalApicAffinityFlags ;
263
+
264
+ #[ repr( C , packed) ]
265
+ struct GiccAffinityEntry {
266
+ header : AffinityEntryHeader ,
267
+ proximity_domain : u32 ,
268
+ acpi_processor_uid : u32 ,
269
+ flags : GiccAffinityFlags ,
270
+ clock_domain : u32 ,
271
+ }
272
+
273
+ type GiccAffinityFlags = LocalApicAffinityFlags ;
274
+
275
+ #[ repr( C , packed) ]
276
+ struct GicItsAffinityEntry {
277
+ header : AffinityEntryHeader ,
278
+ proximity_domain : u32 ,
279
+ _reserved : u16 ,
280
+ its_id : u32 ,
281
+ }
282
+
283
+ #[ repr( C , packed) ]
284
+ struct GenericInitiatorAffinityEntry {
285
+ header : AffinityEntryHeader ,
286
+ _reserved_1 : u8 ,
287
+ device_handle_type : DeviceHandleType ,
288
+ proximity_domain : u32 ,
289
+ device_handle : DeviceHandle ,
290
+ flags : GenericInitiatorAffinityFlags ,
291
+ _reserved_2 : u32 ,
292
+ }
293
+
294
+ #[ repr( u8 ) ]
295
+ #[ non_exhaustive]
296
+ enum DeviceHandleType {
297
+ Acpi = 0 ,
298
+ Pci = 1 ,
299
+ }
300
+
301
+ #[ repr( C ) ]
302
+ enum DeviceHandle {
303
+ Acpi ( AcpiDeviceHandle ) ,
304
+ Pci ( PciDeviceHandle ) ,
305
+ }
306
+
307
+ #[ repr( C , packed) ]
308
+ struct AcpiDeviceHandle {
309
+ acpi_hid : u64 ,
310
+ acpi_uid : u32 ,
311
+ _reserved : u32 ,
312
+ }
313
+
314
+ #[ repr( C , packed) ]
315
+ struct PciDeviceHandle {
316
+ pci_segment : u16 ,
317
+ pci_bdf_number : u16 ,
318
+ _reserved : [ u32 ; 3 ] ,
319
+ }
320
+
321
+ bitflags ! {
322
+ #[ derive( Clone , Copy ) ]
323
+ struct GenericInitiatorAffinityFlags : u32 {
324
+ const ENABLED = 1 ;
325
+ const ARCHITECTURAL_TRANSACTIONS = 1 << 1 ;
326
+ }
327
+ }
0 commit comments