Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/pci/acpi.rs
5394 views
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 {
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
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 {
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 {
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 {
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 {
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{gpe_nr:02X}").as_str().into(),
544
0,
545
false,
546
vec![
547
&aml::Store::new(
548
&aml::Local(0),
549
&aml::Path::new(format!("{notification_path}.NOTY").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
559