Skip to content

Commit 2c706b2

Browse files
committed
doc: add ACPI virtualization HLD
Transcribe and publish the reviewed ACPI virtualization HLD as another developer guide. Signed-off-by: David B. Kinder <david.b.kinder@intel.com>
1 parent 1707fc3 commit 2c706b2

File tree

6 files changed

+360
-0
lines changed

6 files changed

+360
-0
lines changed
Lines changed: 359 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,359 @@
1+
.. _ACPI-virt-HLD:
2+
3+
ACPI Virtualization High Level Design
4+
#####################################
5+
6+
ACPI introduction
7+
*****************
8+
9+
Advanced Configuration and Power Interface (ACPI) provides an open
10+
standard that operating systems can use to discover and configure
11+
computer hardware components to perform power management for example, by
12+
monitoring status and putting unused components to sleep.
13+
14+
Functions implemented by ACPI include:
15+
16+
- System/Device/Processor power management
17+
- Device/Processor performance management
18+
- Configuration / Plug and Play
19+
- System event
20+
- Battery management
21+
- Thermal management
22+
23+
ACPI enumerates and lists the different DMA engines in the platform, and
24+
device scope relationships between PCI devices and which DMA engine
25+
controls them. All critical functions depend on ACPI tables. Here's an
26+
example on an Apollo Lake platform (APL) with Linux installed:
27+
28+
.. code-block:: none
29+
30+
root@:Dom0 ~ $ ls /sys/firmware/acpi/tables/
31+
APIC data DMAR DSDT dynamic FACP FACS HPET MCFG NHLT TPM2
32+
33+
These tables provide different information and functions:
34+
35+
- Advanced Programmable Interrupt Controller (APIC) for Symmetric
36+
Multiprocessor systems (SMP),
37+
- DMA remapping (DMAR) for Intel |reg| Virtualization Technology for
38+
Directed I/O (VT-d),
39+
- Non-HD Audio Link Table (NHLT) for supporting audio device,
40+
- and Differentiated System Description Table (DSDT) for system
41+
configuration info. DSDT is a major ACPI table used to describe what
42+
peripherals the machine has, and information on PCI IRQ mappings and
43+
power management
44+
45+
Most of the ACPI functionality is provided in ACPI Machine Language
46+
(AML) bytecode stored in the ACPI tables. To make use of these tables,
47+
Linux implements an interpreter for the AML bytecode. At BIOS
48+
development time, the AML bytecode is compiled from the ASL (ACPI Source
49+
Language) code. The ``iasl`` command is used to disassemble the ACPI table
50+
and display its contents:
51+
52+
.. code-block:: none
53+
54+
root@:Dom0 ~ $ cp /sys/firmware/acpi/tables/DMAR .
55+
root@:Dom0 ~ $ iasl -d DMAR
56+
57+
Intel ACPI Component Architecture
58+
ASL+ Optimizing Compiler/Disassembler version 20170728
59+
Copyright (c) 2000 - 2017 Intel Corporation
60+
Input file DMAR, Length 0xB0 (176) bytes
61+
ACPI: DMAR 0x0000000000000000 0000B0 (v01 INTEL BDW 00000001 INTL 00000001)
62+
Acpi Data Table [DMAR] decoded
63+
Formatted output: DMAR.dsl - 5286 bytes
64+
65+
root@:Dom0 ~ $ cat DMAR.dsl
66+
[000h 0000 4] Signature : "DMAR" [DMA Remapping table]
67+
[004h 0004 4] Table Length : 000000B0
68+
[008h 0008 1] Revision : 01
69+
...
70+
[030h 0048 2] Subtable Type : 0000 [Hardware Unit Definition]
71+
[032h 0050 2] Length : 0018
72+
[034h 0052 1] Flags : 00
73+
[035h 0053 1] Reserved : 00
74+
[036h 0054 2] PCI Segment Number : 0000
75+
[038h 0056 8] Register Base Address : 00000000FED64000
76+
77+
From the displayed ASL, we can see some generic table fields, such as
78+
the version information, and one VTd remapping engine description with
79+
FED64000 as base address.
80+
81+
We can modify DMAR.dsl and assemble it again to AML:
82+
83+
.. code-block:: none
84+
85+
root@:Dom0 ~ $ iasl DMAR.dsl
86+
Intel ACPI Component Architecture
87+
ASL+ Optimizing Compiler/Disassembler version 20170728
88+
Copyright (c) 2000 - 2017 Intel Corporation
89+
Table Input: DMAR.dsl - 113 lines, 5286 bytes, 72 fields
90+
Binary Output: DMAR.aml - 176 bytes
91+
Compilation complete. 0 Errors, 0 Warnings, 0 Remarks
92+
93+
We can see the new AML file ``DMAR.aml`` is created.
94+
95+
There are many ACPI tables in the system, linked together via table
96+
pointers. In all ACPI-compatible system, the OS can enumerate all
97+
needed tables starting with the Root System Description Pointer (RSDP)
98+
provided at a known place in the system low address space, and pointing
99+
to an XSDT (Extended System Description Table). The following picture
100+
shows a typical ACPI table layout in an Intel APL platform:
101+
102+
.. figure:: images/acpi-image1.png
103+
:width: 700px
104+
:align: center
105+
:name: acpi-layout
106+
107+
Typical ACPI table layout in an Intel APL platform
108+
109+
110+
ACPI virtualization
111+
*******************
112+
113+
Most modern OSes requires ACPI, so ACRN provides ACPI virtualization to
114+
emulate an ACPI-capable virtual platform for the guest OS. To achieve
115+
this, there are two options, depending on physical device and ACPI
116+
resources are abstracted: Partitioning and Emulation.
117+
118+
Partitioning
119+
============
120+
121+
One option is to assign and partition physical devices and ACPI
122+
resources among all guest OSes. That means each guest OS owns specific
123+
devices with passthrough, such as shown below:
124+
125+
+--------------------------+--------------------------+--------------------------+
126+
| PCI Devices | VM0(Cluster VM) | VM1(IVI VM) |
127+
+--------------------------+--------------------------+--------------------------+
128+
| I2C | I2C3, I2C0 | I2C1, I2C2, I2C4, I2C5, |
129+
| | | I2C6, I2C7 |
130+
+--------------------------+--------------------------+--------------------------+
131+
| SPI | SPI1 | SPI0, SPI2 |
132+
+--------------------------+--------------------------+--------------------------+
133+
| USB | | USB-Host (xHCI) and |
134+
| | | USB-Device (xDCI) |
135+
+--------------------------+--------------------------+--------------------------+
136+
| SDIO | | SDIO |
137+
+--------------------------+--------------------------+--------------------------+
138+
| IPU | | IPU |
139+
+--------------------------+--------------------------+--------------------------+
140+
| Ethernet | Ethernet | |
141+
+--------------------------+--------------------------+--------------------------+
142+
| WIFI | | WIFI |
143+
+--------------------------+--------------------------+--------------------------+
144+
| Bluetooth | | Bluetooth |
145+
+--------------------------+--------------------------+--------------------------+
146+
| Audio | | Audio |
147+
+--------------------------+--------------------------+--------------------------+
148+
| GPIO | GPIO | |
149+
+--------------------------+--------------------------+--------------------------+
150+
| UART | UART | |
151+
+--------------------------+--------------------------+--------------------------+
152+
153+
In an early ACRN development phase, partitioning was used for
154+
simplicity. To implement partitioning, we need to hack the PCI logic to
155+
make different VMs see a different subset of devices, and create one
156+
copy of the ACPI tables for each of them, as shown in the following
157+
picture:
158+
159+
.. figure:: images/acpi-image3.png
160+
:width: 900px
161+
:align: center
162+
163+
For each VM, its ACPI tables are standalone copies and not related to
164+
other VMs. Opregion also needs to be copied for different VM.
165+
166+
For each table, we make modifications, based on the physical table, to
167+
reflect the assigned devices to a particular VM. In the picture below,
168+
we can see keep SP2(0:19.1) for VM0, and SP1(0:19.0)/SP3(0:19.2) for
169+
VM1. Any time a partition policy changes, we need to modify both tables
170+
again, including dissembling, modification, and assembling, which is
171+
tricky and bug-prone.
172+
173+
.. figure:: images/acpi-image2.png
174+
:width: 900px
175+
:align: center
176+
177+
Emulation
178+
---------
179+
180+
A second option is for the SOS (VM0) to "own" all devices and emulate a
181+
set of virtual devices for each of the UOS (VM1). This is the most
182+
popular model for virtualization, as show below. ACRN currently uses
183+
device emulation plus some device passthrough for UOS.
184+
185+
.. figure:: images/acpi-image5.png
186+
:width: 400px
187+
:align: center
188+
189+
Regarding ACPI virtualization in ACRN, different policy are used for
190+
different components:
191+
192+
- Hypervisor - ACPI is transparent to the Hypervisor, which has no
193+
knowledge of ACPI at all.
194+
- SOS - All ACPI resources are physically owned by the SOS, which
195+
enumerates all ACPI tables and devices.
196+
- UOS - Virtual ACPI resources exposed by the device model are owned by
197+
UOS.
198+
199+
Source for the ACPI emulation code for the device model is found in
200+
``hw/platform/acpi/acpi.c``.
201+
202+
Each entry in ``basl_ftables`` is related to each virtual ACPI table,
203+
including following elements:
204+
205+
- wsect - output handler to write related ACPI table contents to
206+
specific file
207+
- offset - related ACPI table offset in the memory
208+
- valid - dynamically indicate if this table is needed
209+
210+
.. code-block:: c
211+
212+
static struct {
213+
int (*wsect)(FILE *fp, struct vmctx *ctx);
214+
uint64_t offset;
215+
bool valid;
216+
} basl_ftables[] = {
217+
{ basl_fwrite_rsdp, 0, true },
218+
{ basl_fwrite_rsdt, RSDT_OFFSET, true },
219+
{ basl_fwrite_xsdt, XSDT_OFFSET, true },
220+
{ basl_fwrite_madt, MADT_OFFSET, true },
221+
{ basl_fwrite_fadt, FADT_OFFSET, true },
222+
{ basl_fwrite_hpet, HPET_OFFSET, true },
223+
{ basl_fwrite_mcfg, MCFG_OFFSET, true },
224+
{ basl_fwrite_facs, FACS_OFFSET, true },
225+
{ basl_fwrite_nhlt, NHLT_OFFSET, false }, /*valid with audio ptdev*/
226+
{ basl_fwrite_dsdt, DSDT_OFFSET, true }
227+
};
228+
229+
The main function to create virtual ACPI tables is ``acpi_build`` that
230+
calls ``basl_compile`` for each table and performs the following:
231+
232+
#. create two temp files: infile and outfile
233+
#. with output handler, write table contents stream to infile
234+
#. use ``iasl`` tool to assemble infile into outfile
235+
#. load outfile contents to the required memory offset
236+
237+
.. code-block:: c
238+
239+
static int
240+
basl_compile(struct vmctx *ctx,
241+
int (*fwrite_section)(FILE *, struct vmctx *),
242+
uint64_t offset)
243+
{
244+
struct basl_fio io[2];
245+
static char iaslbuf[3*MAXPATHLEN + 10];
246+
int err;
247+
248+
err = basl_start(&io[0], &io[1]);
249+
if (!err) {
250+
err = (*fwrite_section)(io[0].fp, ctx);
251+
252+
if (!err) {
253+
/*
254+
* iasl sends the results of the compilation to
255+
* stdout. Shut this down by using the shell to
256+
* redirect stdout to /dev/null, unless the user
257+
* has requested verbose output for debugging
258+
* purposes
259+
*/
260+
if (basl_verbose_iasl)
261+
snprintf(iaslbuf, sizeof(iaslbuf),
262+
"%s -p %s %s",
263+
ASL_COMPILER,
264+
io[1].f_name, io[0].f_name);
265+
else
266+
snprintf(iaslbuf, sizeof(iaslbuf),
267+
"/bin/sh -c \"%s -p %s %s\" 1> /dev/null",
268+
ASL_COMPILER,
269+
io[1].f_name, io[0].f_name);
270+
271+
err = system(iaslbuf);
272+
273+
if (!err) {
274+
/*
275+
* Copy the aml output file into guest
276+
* memory at the specified location
277+
*/
278+
err = basl_load(ctx, io[1].fd, offset);
279+
} else
280+
err = -1;
281+
}
282+
basl_end(&io[0], &io[1]);
283+
}
284+
285+
After processing each entry, the virtual ACPI tables are present in UOS
286+
memory.
287+
288+
For pass-through devices in UOS, we likely need to add some ACPI
289+
description in the UOS virtual DSDT table. There is one hook
290+
(``passthrough_write_dsdt``) in ``hw/pci/passthrough.c`` for it. The following
291+
source code shows calls to different functions to add different contents
292+
for each vendor and device id.
293+
294+
.. code-block:: c
295+
296+
static void
297+
passthru_write_dsdt(struct pci_vdev *dev)
298+
{
299+
struct passthru_dev *ptdev = (struct passthru_dev *) dev->arg;
300+
uint32_t vendor = 0, device = 0;
301+
302+
vendor = read_config(ptdev->phys_dev, PCIR_VENDOR, 2);
303+
304+
if (vendor != 0x8086)
305+
return;
306+
307+
device = read_config(ptdev->phys_dev, PCIR_DEVICE, 2);
308+
309+
/* Provides ACPI extra info */
310+
if (device == 0x5aaa)
311+
/* XDCI @ 00:15.1 to enable ADB */
312+
write_dsdt_xhci(dev);
313+
else if (device == 0x5ab4)
314+
/* HDAC @ 00:17.0 as codec */
315+
write_dsdt_hdac(dev);
316+
else if (device == 0x5a98)
317+
/* HDAS @ 00:e.0 */
318+
write_dsdt_hdas(dev);
319+
else if (device == 0x5aac)
320+
/* i2c @ 00:16.0 for ipu */
321+
write_dsdt_ipu_i2c(dev);
322+
else if (device == 0x5abc)
323+
/* URT1 @ 00:18.0 for bluetooth*/
324+
write_dsdt_urt1(dev);
325+
326+
}
327+
328+
For instance, ``write_dsdt_urt1`` provides ACPI contents for Bluetooth
329+
UART device when pass-throughed to the UOS. It provides virtual PCI
330+
device/function as ``_ADR``, with other descriptions possible for Bluetooth
331+
UART enumeration.
332+
333+
.. code-block:: c
334+
335+
static void
336+
write_dsdt_urt1(struct pci_vdev *dev)
337+
{
338+
printf("write virt-%x:%x.%x in dsdt for URT1 @ 00:18.0\n",
339+
dev->bus,
340+
dev->slot,
341+
dev->func);
342+
dsdt_line("Device (URT1)");
343+
dsdt_line("{");
344+
dsdt_line(" Name (_ADR, 0x%04X%04X)", dev->slot, dev->func);
345+
dsdt_line(" Name (_DDN, \"Intel(R) HS-UART Controller #1\")");
346+
dsdt_line(" Name (_UID, One)");
347+
dsdt_line(" Name (RBUF, ResourceTemplate ()");
348+
dsdt_line(" {");
349+
dsdt_line(" })");
350+
dsdt_line(" Method (_CRS, 0, NotSerialized)");
351+
dsdt_line(" {");
352+
dsdt_line(" Return (RBUF)");
353+
dsdt_line(" }");
354+
dsdt_line("}");
355+
}
356+
357+
This document introduces basic ACPI virtualization. Other topics such as
358+
power management virtualization, adds more requirement for ACPI, and
359+
will be discussed in the power management documentation.
36.8 KB
Loading
29.7 KB
Loading
35.6 KB
Loading
50.3 KB
Loading

doc/developer-guides/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ Developer Guides
99
primer.rst
1010
memmgt-hld.rst
1111
virtio-hld.rst
12+
ACPI-virt-hld.rst
1213
../api/index.rst
1314
../reference/kconfig/index.rst
1415
trusty.rst

0 commit comments

Comments
 (0)