xref: /aosp_15_r20/external/crosvm/devices/src/pci/acpi.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1 // Copyright 2022 The ChromiumOS Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 use acpi_tables::aml;
6 use acpi_tables::aml::Aml;
7 use anyhow::anyhow;
8 use anyhow::Result;
9 use base::MemoryMapping;
10 use base::MemoryMappingBuilder;
11 use base::Protection;
12 use base::SharedMemory;
13 
14 pub const SHM_OFFSET: u32 = 0x1000;
15 pub const SHM_SIZE: u32 = 0x1000;
16 
17 pub struct DeviceVcfgRegister {
18     offset: u32,
19     shm: SharedMemory,
20 }
21 
22 impl DeviceVcfgRegister {
new(offset: u32) -> Result<DeviceVcfgRegister>23     pub fn new(offset: u32) -> Result<DeviceVcfgRegister> {
24         let shm = SharedMemory::new("VCFG register", SHM_SIZE as u64)
25             .map_err(|_| anyhow!("failed to create shared memory"))?;
26         Ok(DeviceVcfgRegister { offset, shm })
27     }
28 
create_shm_mmap(&self) -> Option<MemoryMapping>29     pub fn create_shm_mmap(&self) -> Option<MemoryMapping> {
30         MemoryMappingBuilder::new(SHM_SIZE as usize)
31             .from_shared_memory(&self.shm)
32             .offset(0)
33             .protection(Protection::read_write())
34             .build()
35             .ok()
36     }
37 }
38 
39 impl Aml for DeviceVcfgRegister {
to_aml_bytes(&self, bytes: &mut Vec<u8>)40     fn to_aml_bytes(&self, bytes: &mut Vec<u8>) {
41         aml::OpRegion::new(
42             "VREG".into(),
43             aml::OpRegionSpace::SystemMemory,
44             &aml::Add::new(&aml::ZERO, &aml::Name::new_field_name("VCFG"), &self.offset),
45             &4096_usize,
46         )
47         .to_aml_bytes(bytes);
48         aml::Field::new(
49             "VREG".into(),
50             aml::FieldAccessType::DWord,
51             aml::FieldLockRule::Lock,
52             aml::FieldUpdateRule::Preserve,
53             vec![
54                 aml::FieldEntry::Named(*b"PFPM", 32),
55                 aml::FieldEntry::Named(*b"PDSM", 32),
56                 aml::FieldEntry::Named(*b"NOTY", 32),
57             ],
58         )
59         .to_aml_bytes(bytes);
60         aml::OpRegion::new(
61             "SHAM".into(),
62             aml::OpRegionSpace::SystemMemory,
63             &aml::Add::new(
64                 &aml::ZERO,
65                 &aml::Name::new_field_name("VCFG"),
66                 &(self.offset + SHM_OFFSET),
67             ),
68             &SHM_SIZE,
69         )
70         .to_aml_bytes(bytes);
71         aml::Field::new(
72             "SHAM".into(),
73             aml::FieldAccessType::Any,
74             aml::FieldLockRule::Lock,
75             aml::FieldUpdateRule::Preserve,
76             vec![
77                 aml::FieldEntry::Named(*b"DSM0", 128),
78                 aml::FieldEntry::Named(*b"DSM1", 64),
79                 aml::FieldEntry::Named(*b"DSM2", 64),
80                 aml::FieldEntry::Named(*b"DSM3", 16384),
81             ],
82         )
83         .to_aml_bytes(bytes);
84         aml::Field::new(
85             "SHAM".into(),
86             aml::FieldAccessType::DWord,
87             aml::FieldLockRule::Lock,
88             aml::FieldUpdateRule::Preserve,
89             vec![
90                 aml::FieldEntry::Reserved(256),
91                 aml::FieldEntry::Named(*b"RTTP", 32),
92                 aml::FieldEntry::Named(*b"RTSZ", 32),
93                 aml::FieldEntry::Named(*b"RTDT", 16576),
94             ],
95         )
96         .to_aml_bytes(bytes);
97     }
98 }
99 
100 pub struct DsmMethod {}
101 
102 const ACPI_TYPE_INT: &dyn Aml = &1_usize;
103 const ACPI_TYPE_STRING: &dyn Aml = &2_usize;
104 const ACPI_TYPE_BUFFER: &dyn Aml = &3_usize;
105 const ACPI_TYPE_PACKAGE: &dyn Aml = &4_usize;
106 
107 // The ACPI _DSM methods are described under:
108 // https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/09_ACPI-Defined_Devices_and_Device-Specific_Objects/ACPIdefined_Devices_and_DeviceSpecificObjects.html?highlight=_dsm#dsm-device-specific-method
109 //
110 // Since the guest does not have access to native ACPI tables, whenever native driver for the
111 // pass-through device, which resides in guest, evaluates _DSM methods, such evaluation needs to be
112 // propagated to the host which can do the actual job.
113 //
114 // Below snippet generates AML code, which implements virtual _DSM method in guest ACPI tables.
115 // Its role is to collect and pass guest _DSM arguments into host (through shared memory). When all
116 // arguments are saved in shared memory, access to PDSM is issued which causes a trap to VMM. As a
117 // consequence VMM can read passed _DSM arguments and pass them further (through dedicated IOCTL)
118 // to the host kernel, which can actually evaluate the ACPI _DSM method using native tables. The
119 // results are passed back from ioctl to VMM and further to the guest through shared memory.
120 impl Aml for DsmMethod {
to_aml_bytes(&self, aml: &mut Vec<u8>)121     fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
122         aml::Method::new(
123             "_DSM".into(),
124             4,
125             true,
126             vec![
127                 &aml::Store::new(&aml::Name::new_field_name("DSM0"), &aml::Arg(0)),
128                 &aml::Store::new(&aml::Name::new_field_name("DSM1"), &aml::Arg(1)),
129                 &aml::Store::new(&aml::Name::new_field_name("DSM2"), &aml::Arg(2)),
130                 &aml::Store::new(&aml::Local(2), &aml::ObjectType::new(&aml::Arg(3))),
131                 &aml::Store::new(&aml::Local(1), &aml::SizeOf::new(&aml::Arg(3))),
132                 &aml::Store::new(&aml::Local(0), &aml::BufferTerm::new(&16384_usize)),
133                 &aml::If::new(
134                     &aml::Equal::new(&aml::Local(2), ACPI_TYPE_BUFFER),
135                     vec![
136                         &aml::CreateDWordField::new(
137                             &aml::Name::new_field_name("BFTP"),
138                             &aml::Local(0),
139                             &0_usize,
140                         ),
141                         &aml::CreateDWordField::new(
142                             &aml::Name::new_field_name("BFSZ"),
143                             &aml::Local(0),
144                             &4_usize,
145                         ),
146                         &aml::CreateField::new(
147                             &aml::Name::new_field_name("BFDT"),
148                             &aml::Local(0),
149                             &(8_usize * 8_usize),
150                             &aml::Multiply::new(&aml::ZERO, &aml::Local(1), &8_usize),
151                         ),
152                         &aml::Store::new(&aml::Name::new_field_name("BFTP"), ACPI_TYPE_BUFFER),
153                         &aml::Store::new(&aml::Name::new_field_name("BFSZ"), &aml::Local(1)),
154                         &aml::Store::new(&aml::Name::new_field_name("BFDT"), &aml::Arg(3)),
155                     ],
156                 ),
157                 &aml::Else::new(vec![
158                     &aml::If::new(
159                         &aml::Equal::new(&aml::Local(2), ACPI_TYPE_PACKAGE),
160                         vec![
161                             &aml::Store::new(&aml::Local(5), &aml::ZERO),
162                             &aml::CreateDWordField::new(
163                                 &aml::Name::new_field_name("PKTP"),
164                                 &aml::Local(0),
165                                 &aml::Local(5),
166                             ),
167                             &aml::Store::new(&aml::Name::new_field_name("PKTP"), ACPI_TYPE_PACKAGE),
168                             &aml::Add::new(&aml::Local(5), &aml::Local(5), &4_usize),
169                             &aml::CreateDWordField::new(
170                                 &aml::Name::new_field_name("PKSZ"),
171                                 &aml::Local(0),
172                                 &aml::Local(5),
173                             ),
174                             &aml::Store::new(&aml::Name::new_field_name("PKSZ"), &aml::Local(1)),
175                             &aml::Add::new(&aml::Local(5), &aml::Local(5), &4_usize),
176                             &aml::Store::new(&aml::Local(2), &aml::ZERO),
177                             &aml::While::new(
178                                 &aml::LessThan::new(&aml::Local(2), &aml::Local(1)),
179                                 vec![
180                                     &aml::Store::new(
181                                         &aml::Local(3),
182                                         &aml::DeRefOf::new(&aml::Index::new(
183                                             &aml::ZERO,
184                                             &aml::Arg(3),
185                                             &aml::Local(2),
186                                         )),
187                                     ),
188                                     &aml::Store::new(
189                                         &aml::Local(4),
190                                         &aml::ObjectType::new(&aml::Local(3)),
191                                     ),
192                                     &aml::Store::new(
193                                         &aml::Local(6),
194                                         &aml::SizeOf::new(&aml::Local(3)),
195                                     ),
196                                     &aml::CreateDWordField::new(
197                                         &aml::Name::new_field_name("OUTP"),
198                                         &aml::Local(0),
199                                         &aml::Local(5),
200                                     ),
201                                     &aml::Store::new(
202                                         &aml::Name::new_field_name("OUTP"),
203                                         &aml::Local(4),
204                                     ),
205                                     &aml::Add::new(&aml::Local(5), &aml::Local(5), &4_usize),
206                                     &aml::CreateDWordField::new(
207                                         &aml::Name::new_field_name("OUSZ"),
208                                         &aml::Local(0),
209                                         &aml::Local(5),
210                                     ),
211                                     &aml::Store::new(
212                                         &aml::Name::new_field_name("OUSZ"),
213                                         &aml::Local(6),
214                                     ),
215                                     &aml::Add::new(&aml::Local(5), &aml::Local(5), &4_usize),
216                                     &aml::If::new(
217                                         &aml::Equal::new(&aml::Local(4), ACPI_TYPE_INT),
218                                         vec![
219                                             &aml::CreateQWordField::new(
220                                                 &aml::Name::new_field_name("OUDT"),
221                                                 &aml::Local(0),
222                                                 &aml::Local(5),
223                                             ),
224                                             &aml::Store::new(
225                                                 &aml::Name::new_field_name("OUDT"),
226                                                 &aml::Local(3),
227                                             ),
228                                             &aml::Add::new(
229                                                 &aml::Local(5),
230                                                 &aml::Local(5),
231                                                 &8_usize,
232                                             ),
233                                         ],
234                                     ),
235                                     &aml::Else::new(vec![
236                                         &aml::If::new(
237                                             &aml::Equal::new(&aml::Local(4), ACPI_TYPE_STRING),
238                                             vec![
239                                                 &aml::CreateField::new(
240                                                     &aml::Name::new_field_name("OSDT"),
241                                                     &aml::Local(0),
242                                                     &aml::Multiply::new(
243                                                         &aml::ZERO,
244                                                         &aml::Local(5),
245                                                         &8_usize,
246                                                     ),
247                                                     &aml::Multiply::new(
248                                                         &aml::ZERO,
249                                                         &aml::Local(6),
250                                                         &8_usize,
251                                                     ),
252                                                 ),
253                                                 &aml::Store::new(
254                                                     &aml::Name::new_field_name("OSDT"),
255                                                     &aml::Local(3),
256                                                 ),
257                                                 &aml::And::new(
258                                                     &aml::Local(7),
259                                                     &aml::Local(6),
260                                                     &7_usize,
261                                                 ),
262                                                 &aml::If::new(
263                                                     &aml::NotEqual::new(&aml::Local(7), &aml::ZERO),
264                                                     vec![&aml::Add::new(
265                                                         &aml::Local(6),
266                                                         &aml::Local(6),
267                                                         &8_usize,
268                                                     )],
269                                                 ),
270                                                 &aml::Subtract::new(
271                                                     &aml::Local(6),
272                                                     &aml::Local(6),
273                                                     &aml::Local(7),
274                                                 ),
275                                                 &aml::Add::new(
276                                                     &aml::Local(5),
277                                                     &aml::Local(5),
278                                                     &aml::Local(6),
279                                                 ),
280                                             ],
281                                         ),
282                                         &aml::Else::new(vec![&aml::If::new(
283                                             &aml::Equal::new(&aml::Local(4), ACPI_TYPE_BUFFER),
284                                             vec![
285                                                 &aml::CreateField::new(
286                                                     &aml::Name::new_field_name("OBDT"),
287                                                     &aml::Local(0),
288                                                     &aml::Multiply::new(
289                                                         &aml::ZERO,
290                                                         &aml::Local(5),
291                                                         &8_usize,
292                                                     ),
293                                                     &aml::Multiply::new(
294                                                         &aml::ZERO,
295                                                         &aml::Local(6),
296                                                         &8_usize,
297                                                     ),
298                                                 ),
299                                                 &aml::Store::new(
300                                                     &aml::Name::new_field_name("OBDT"),
301                                                     &aml::Local(3),
302                                                 ),
303                                                 &aml::And::new(
304                                                     &aml::Local(7),
305                                                     &aml::Local(6),
306                                                     &7_usize,
307                                                 ),
308                                                 &aml::If::new(
309                                                     &aml::NotEqual::new(&aml::Local(7), &aml::ZERO),
310                                                     vec![&aml::Add::new(
311                                                         &aml::Local(6),
312                                                         &aml::Local(6),
313                                                         &8_usize,
314                                                     )],
315                                                 ),
316                                                 &aml::Subtract::new(
317                                                     &aml::Local(6),
318                                                     &aml::Local(6),
319                                                     &aml::Local(7),
320                                                 ),
321                                                 &aml::Add::new(
322                                                     &aml::Local(5),
323                                                     &aml::Local(5),
324                                                     &aml::Local(6),
325                                                 ),
326                                             ],
327                                         )]),
328                                     ]),
329                                     &aml::Add::new(&aml::Local(2), &aml::Local(2), &aml::ONE),
330                                 ],
331                             ),
332                         ],
333                     ),
334                     &aml::Else::new(vec![&aml::Return::new(&aml::ZERO)]),
335                 ]),
336                 &aml::Store::new(&aml::Name::new_field_name("DSM3"), &aml::Local(0)),
337                 // All DSM arguments are written to shared memory, lets access PDSM which will trap
338                 // to VMM which can process it further. The result will be stored in shared memory.
339                 &aml::Store::new(&aml::Name::new_field_name("PDSM"), &aml::ZERO),
340                 // Lets start converting the _DSM result stored in shared memory into proper format
341                 // which will allow to return result in desired format to the guest caller.
342                 &aml::Store::new(
343                     &aml::Local(0),
344                     &aml::ToInteger::new(&aml::ZERO, &aml::Name::new_field_name("RTTP")),
345                 ),
346                 &aml::If::new(
347                     &aml::Equal::new(&aml::Local(0), ACPI_TYPE_INT),
348                     vec![&aml::Return::new(&aml::ToInteger::new(
349                         &aml::ZERO,
350                         &aml::Name::new_field_name("RTDT"),
351                     ))],
352                 ),
353                 &aml::Else::new(vec![
354                     &aml::If::new(
355                         &aml::Equal::new(&aml::Local(0), ACPI_TYPE_STRING),
356                         vec![&aml::Return::new(&aml::ToString::new(
357                             &aml::ZERO,
358                             &aml::Name::new_field_name("RTDT"),
359                             &aml::ONES,
360                         ))],
361                     ),
362                     &aml::Else::new(vec![
363                         &aml::If::new(
364                             &aml::Equal::new(&aml::Local(0), ACPI_TYPE_BUFFER),
365                             vec![&aml::Return::new(&aml::Mid::new(
366                                 &aml::Name::new_field_name("RTDT"),
367                                 &0_usize,
368                                 &aml::ToInteger::new(
369                                     &aml::ZERO,
370                                     &aml::Name::new_field_name("RTSZ"),
371                                 ),
372                                 &aml::ZERO,
373                             ))],
374                         ),
375                         &aml::Else::new(vec![
376                             &aml::If::new(
377                                 &aml::Equal::new(&aml::Local(0), ACPI_TYPE_PACKAGE),
378                                 vec![
379                                     &aml::Store::new(&aml::Local(0), &aml::ZERO),
380                                     &aml::Store::new(
381                                         &aml::Local(1),
382                                         &aml::ToInteger::new(
383                                             &aml::ZERO,
384                                             &aml::Name::new_field_name("RTSZ"),
385                                         ),
386                                     ),
387                                     &aml::Store::new(
388                                         &aml::Local(2),
389                                         &aml::VarPackageTerm::new(&aml::Local(1)),
390                                     ),
391                                     &aml::Store::new(&aml::Local(3), &aml::ZERO),
392                                     &aml::While::new(
393                                         &aml::LessThan::new(&aml::Local(0), &aml::Local(1)),
394                                         vec![
395                                             &aml::Store::new(
396                                                 &aml::Local(4),
397                                                 &aml::ToInteger::new(
398                                                     &aml::ZERO,
399                                                     &aml::Mid::new(
400                                                         &aml::Name::new_field_name("RTDT"),
401                                                         &aml::Local(3),
402                                                         &4_usize,
403                                                         &aml::ZERO,
404                                                     ),
405                                                 ),
406                                             ),
407                                             &aml::Add::new(
408                                                 &aml::Local(3),
409                                                 &aml::Local(3),
410                                                 &4_usize,
411                                             ),
412                                             &aml::Store::new(
413                                                 &aml::Local(5),
414                                                 &aml::ToInteger::new(
415                                                     &aml::ZERO,
416                                                     &aml::Mid::new(
417                                                         &aml::Name::new_field_name("RTDT"),
418                                                         &aml::Local(3),
419                                                         &4_usize,
420                                                         &aml::ZERO,
421                                                     ),
422                                                 ),
423                                             ),
424                                             &aml::Add::new(
425                                                 &aml::Local(3),
426                                                 &aml::Local(3),
427                                                 &4_usize,
428                                             ),
429                                             &aml::Store::new(
430                                                 &aml::Local(6),
431                                                 &aml::Mid::new(
432                                                     &aml::Name::new_field_name("RTDT"),
433                                                     &aml::Local(3),
434                                                     &aml::Local(5),
435                                                     &aml::ZERO,
436                                                 ),
437                                             ),
438                                             &aml::Add::new(
439                                                 &aml::Local(3),
440                                                 &aml::Local(3),
441                                                 &aml::Local(5),
442                                             ),
443                                             &aml::If::new(
444                                                 &aml::Equal::new(&aml::Local(4), ACPI_TYPE_INT),
445                                                 vec![&aml::Store::new(
446                                                     &aml::Local(6),
447                                                     &aml::ToInteger::new(
448                                                         &aml::ZERO,
449                                                         &aml::Local(6),
450                                                     ),
451                                                 )],
452                                             ),
453                                             &aml::Else::new(vec![&aml::If::new(
454                                                 &aml::Equal::new(&aml::Local(4), ACPI_TYPE_STRING),
455                                                 vec![&aml::Store::new(
456                                                     &aml::Local(6),
457                                                     &aml::ToString::new(
458                                                         &aml::ZERO,
459                                                         &aml::Local(6),
460                                                         &aml::ONES,
461                                                     ),
462                                                 )],
463                                             )]),
464                                             &aml::Store::new(
465                                                 &aml::Index::new(
466                                                     &aml::ZERO,
467                                                     &aml::Local(2),
468                                                     &aml::Local(0),
469                                                 ),
470                                                 &aml::Local(6),
471                                             ),
472                                             &aml::Add::new(
473                                                 &aml::Local(0),
474                                                 &aml::Local(0),
475                                                 &aml::ONE,
476                                             ),
477                                         ],
478                                     ),
479                                     &aml::Return::new(&aml::Local(2)),
480                                 ],
481                             ),
482                             &aml::Else::new(vec![&aml::Return::new(&aml::ZERO)]),
483                         ]),
484                     ]),
485                 ]),
486             ],
487         )
488         .to_aml_bytes(aml);
489     }
490 }
491 
492 pub struct PowerResourceMethod {}
493 
494 impl Aml for PowerResourceMethod {
to_aml_bytes(&self, aml: &mut Vec<u8>)495     fn to_aml_bytes(&self, aml: &mut Vec<u8>) {
496         aml::PowerResource::new(
497             "PRIC".into(),
498             0u8,
499             0u16,
500             vec![
501                 &aml::Name::new("_STA".into(), &aml::ONE),
502                 &aml::Method::new(
503                     "_ON_".into(),
504                     0,
505                     true,
506                     vec![
507                         &aml::Store::new(&aml::Name::new_field_name("PFPM"), &aml::ONE),
508                         &aml::Store::new(&aml::Name::new_field_name("_STA"), &aml::ONE),
509                     ],
510                 ),
511                 &aml::Method::new(
512                     "_OFF".into(),
513                     0,
514                     true,
515                     vec![
516                         &aml::Store::new(&aml::Name::new_field_name("_STA"), &aml::ZERO),
517                         &aml::Store::new(&aml::Name::new_field_name("PFPM"), &aml::ZERO),
518                     ],
519                 ),
520             ],
521         )
522         .to_aml_bytes(aml);
523         aml::Name::new(
524             "_PR0".into(),
525             &aml::Package::new(vec![&aml::Name::new_field_name("PRIC")]),
526         )
527         .to_aml_bytes(aml);
528         aml::Name::new(
529             "_PR3".into(),
530             &aml::Package::new(vec![&aml::Name::new_field_name("PRIC")]),
531         )
532         .to_aml_bytes(aml);
533     }
534 }
535 
536 pub struct GpeScope {}
537 
538 impl GpeScope {
cast_to_aml_bytes(&self, aml: &mut Vec<u8>, gpe_nr: u32, notification_path: &str)539     pub fn cast_to_aml_bytes(&self, aml: &mut Vec<u8>, gpe_nr: u32, notification_path: &str) {
540         aml::Scope::new(
541             "_GPE".into(),
542             vec![&aml::Method::new(
543                 format!("_E{:02X}", gpe_nr).as_str().into(),
544                 0,
545                 false,
546                 vec![
547                     &aml::Store::new(
548                         &aml::Local(0),
549                         &aml::Path::new(format!("{}.NOTY", notification_path).as_str()),
550                     ),
551                     &aml::Notify::new(&aml::Path::new(notification_path), &aml::Local(0)),
552                 ],
553             )],
554         )
555         .to_aml_bytes(aml);
556     }
557 }
558