]>
Commit | Line | Data |
---|---|---|
20f5d14d BW |
1 | VIRTUAL MACHINE GENERATION ID |
2 | ============================= | |
3 | ||
4 | Copyright (C) 2016 Red Hat, Inc. | |
5 | Copyright (C) 2017 Skyport Systems, Inc. | |
6 | ||
7 | This work is licensed under the terms of the GNU GPL, version 2 or later. | |
8 | See the COPYING file in the top-level directory. | |
9 | ||
10 | === | |
11 | ||
12 | The VM generation ID (vmgenid) device is an emulated device which | |
13 | exposes a 128-bit, cryptographically random, integer value identifier, | |
14 | referred to as a Globally Unique Identifier, or GUID. | |
15 | ||
16 | This allows management applications (e.g. libvirt) to notify the guest | |
17 | operating system when the virtual machine is executed with a different | |
18 | configuration (e.g. snapshot execution or creation from a template). The | |
19 | guest operating system notices the change, and is then able to react as | |
20 | appropriate by marking its copies of distributed databases as dirty, | |
21 | re-initializing its random number generator etc. | |
22 | ||
23 | ||
24 | Requirements | |
25 | ------------ | |
26 | ||
27 | These requirements are extracted from the "How to implement virtual machine | |
28 | generation ID support in a virtualization platform" section of the | |
29 | specification, dated August 1, 2012. | |
30 | ||
31 | ||
32 | The document may be found on the web at: | |
33 | http://go.microsoft.com/fwlink/?LinkId=260709 | |
34 | ||
35 | R1a. The generation ID shall live in an 8-byte aligned buffer. | |
36 | ||
37 | R1b. The buffer holding the generation ID shall be in guest RAM, ROM, or device | |
38 | MMIO range. | |
39 | ||
40 | R1c. The buffer holding the generation ID shall be kept separate from areas | |
41 | used by the operating system. | |
42 | ||
43 | R1d. The buffer shall not be covered by an AddressRangeMemory or | |
44 | AddressRangeACPI entry in the E820 or UEFI memory map. | |
45 | ||
46 | R1e. The generation ID shall not live in a page frame that could be mapped with | |
47 | caching disabled. (In other words, regardless of whether the generation ID | |
48 | lives in RAM, ROM or MMIO, it shall only be mapped as cacheable.) | |
49 | ||
50 | R2 to R5. [These AML requirements are isolated well enough in the Microsoft | |
51 | specification for us to simply refer to them here.] | |
52 | ||
53 | R6. The hypervisor shall expose a _HID (hardware identifier) object in the | |
54 | VMGenId device's scope that is unique to the hypervisor vendor. | |
55 | ||
56 | ||
57 | QEMU Implementation | |
58 | ------------------- | |
59 | ||
60 | The above-mentioned specification does not dictate which ACPI descriptor table | |
61 | will contain the VM Generation ID device. Other implementations (Hyper-V and | |
62 | Xen) put it in the main descriptor table (Differentiated System Description | |
63 | Table or DSDT). For ease of debugging and implementation, we have decided to | |
64 | put it in its own Secondary System Description Table, or SSDT. | |
65 | ||
66 | The following is a dump of the contents from a running system: | |
67 | ||
68 | # iasl -p ./SSDT -d /sys/firmware/acpi/tables/SSDT | |
69 | ||
70 | Intel ACPI Component Architecture | |
71 | ASL+ Optimizing Compiler version 20150717-64 | |
72 | Copyright (c) 2000 - 2015 Intel Corporation | |
73 | ||
74 | Reading ACPI table from file /sys/firmware/acpi/tables/SSDT - Length | |
75 | 00000198 (0x0000C6) | |
76 | ACPI: SSDT 0x0000000000000000 0000C6 (v01 BOCHS VMGENID 00000001 BXPC | |
77 | 00000001) | |
78 | Acpi table [SSDT] successfully installed and loaded | |
79 | Pass 1 parse of [SSDT] | |
80 | Pass 2 parse of [SSDT] | |
81 | Parsing Deferred Opcodes (Methods/Buffers/Packages/Regions) | |
82 | ||
83 | Parsing completed | |
84 | Disassembly completed | |
85 | ASL Output: ./SSDT.dsl - 1631 bytes | |
86 | # cat SSDT.dsl | |
87 | /* | |
88 | * Intel ACPI Component Architecture | |
89 | * AML/ASL+ Disassembler version 20150717-64 | |
90 | * Copyright (c) 2000 - 2015 Intel Corporation | |
91 | * | |
92 | * Disassembling to symbolic ASL+ operators | |
93 | * | |
94 | * Disassembly of /sys/firmware/acpi/tables/SSDT, Sun Feb 5 00:19:37 2017 | |
95 | * | |
96 | * Original Table Header: | |
97 | * Signature "SSDT" | |
98 | * Length 0x000000CA (202) | |
99 | * Revision 0x01 | |
100 | * Checksum 0x4B | |
101 | * OEM ID "BOCHS " | |
102 | * OEM Table ID "VMGENID" | |
103 | * OEM Revision 0x00000001 (1) | |
104 | * Compiler ID "BXPC" | |
105 | * Compiler Version 0x00000001 (1) | |
106 | */ | |
107 | DefinitionBlock ("/sys/firmware/acpi/tables/SSDT.aml", "SSDT", 1, "BOCHS ", | |
108 | "VMGENID", 0x00000001) | |
109 | { | |
110 | Name (VGIA, 0x07FFF000) | |
111 | Scope (\_SB) | |
112 | { | |
113 | Device (VGEN) | |
114 | { | |
115 | Name (_HID, "QEMUVGID") // _HID: Hardware ID | |
116 | Name (_CID, "VM_Gen_Counter") // _CID: Compatible ID | |
117 | Name (_DDN, "VM_Gen_Counter") // _DDN: DOS Device Name | |
118 | Method (_STA, 0, NotSerialized) // _STA: Status | |
119 | { | |
120 | Local0 = 0x0F | |
121 | If ((VGIA == Zero)) | |
122 | { | |
123 | Local0 = Zero | |
124 | } | |
125 | ||
126 | Return (Local0) | |
127 | } | |
128 | ||
129 | Method (ADDR, 0, NotSerialized) | |
130 | { | |
131 | Local0 = Package (0x02) {} | |
132 | Index (Local0, Zero) = (VGIA + 0x28) | |
133 | Index (Local0, One) = Zero | |
134 | Return (Local0) | |
135 | } | |
136 | } | |
137 | } | |
138 | ||
139 | Method (\_GPE._E05, 0, NotSerialized) // _Exx: Edge-Triggered GPE | |
140 | { | |
141 | Notify (\_SB.VGEN, 0x80) // Status Change | |
142 | } | |
143 | } | |
144 | ||
145 | ||
146 | Design Details: | |
147 | --------------- | |
148 | ||
149 | Requirements R1a through R1e dictate that the memory holding the | |
150 | VM Generation ID must be allocated and owned by the guest firmware, | |
151 | in this case BIOS or UEFI. However, to be useful, QEMU must be able to | |
152 | change the contents of the memory at runtime, specifically when starting a | |
153 | backed-up or snapshotted image. In order to do this, QEMU must know the | |
154 | address that has been allocated. | |
155 | ||
156 | The mechanism chosen for this memory sharing is writeable fw_cfg blobs. | |
157 | These are data object that are visible to both QEMU and guests, and are | |
158 | addressable as sequential files. | |
159 | ||
160 | More information about fw_cfg can be found in "docs/specs/fw_cfg.txt" | |
161 | ||
162 | Two fw_cfg blobs are used in this case: | |
163 | ||
164 | /etc/vmgenid_guid - contains the actual VM Generation ID GUID | |
165 | - read-only to the guest | |
166 | /etc/vmgenid_addr - contains the address of the downloaded vmgenid blob | |
167 | - writeable by the guest | |
168 | ||
169 | ||
170 | QEMU sends the following commands to the guest at startup: | |
171 | ||
172 | 1. Allocate memory for vmgenid_guid fw_cfg blob. | |
173 | 2. Write the address of vmgenid_guid into the SSDT (VGIA ACPI variable as | |
174 | shown above in the iasl dump). Note that this change is not propagated | |
175 | back to QEMU. | |
176 | 3. Write the address of vmgenid_guid back to QEMU's copy of vmgenid_addr | |
177 | via the fw_cfg DMA interface. | |
178 | ||
179 | After step 3, QEMU is able to update the contents of vmgenid_guid at will. | |
180 | ||
181 | Since BIOS or UEFI does not necessarily run when we wish to change the GUID, | |
182 | the value of VGIA is persisted via the VMState mechanism. | |
183 | ||
184 | As spelled out in the specification, any change to the GUID executes an | |
185 | ACPI notification. The exact handler to use is not specified, so the vmgenid | |
186 | device uses the first unused one: \_GPE._E05. | |
187 | ||
188 | ||
189 | Endian-ness Considerations: | |
190 | --------------------------- | |
191 | ||
192 | Although not specified in Microsoft's document, it is assumed that the | |
193 | device is expected to use little-endian format. | |
194 | ||
195 | All GUID passed in via command line or monitor are treated as big-endian. | |
196 | GUID values displayed via monitor are shown in big-endian format. | |
197 | ||
198 | ||
199 | GUID Storage Format: | |
200 | -------------------- | |
201 | ||
202 | In order to implement an OVMF "SDT Header Probe Suppressor", the contents of | |
203 | the vmgenid_guid fw_cfg blob are not simply a 128-bit GUID. There is also | |
204 | significant padding in order to align and fill a memory page, as shown in the | |
205 | following diagram: | |
206 | ||
207 | +----------------------------------+ | |
208 | | SSDT with OEM Table ID = VMGENID | | |
209 | +----------------------------------+ | |
210 | | ... | TOP OF PAGE | |
211 | | VGIA dword object ---------------|-----> +---------------------------+ | |
212 | | ... | | fw-allocated array for | | |
213 | | _STA method referring to VGIA | | "etc/vmgenid_guid" | | |
214 | | ... | +---------------------------+ | |
215 | | ADDR method referring to VGIA | | 0: OVMF SDT Header probe | | |
216 | | ... | | suppressor | | |
217 | +----------------------------------+ | 36: padding for 8-byte | | |
218 | | alignment | | |
219 | | 40: GUID | | |
220 | | 56: padding to page size | | |
221 | +---------------------------+ | |
222 | END OF PAGE | |
223 | ||
224 | ||
225 | Device Usage: | |
226 | ------------- | |
227 | ||
228 | The device has one property, which may be only be set using the command line: | |
229 | ||
230 | guid - sets the value of the GUID. A special value "auto" instructs | |
231 | QEMU to generate a new random GUID. | |
232 | ||
233 | For example: | |
234 | ||
235 | QEMU -device vmgenid,guid="324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87" | |
236 | QEMU -device vmgenid,guid=auto | |
237 | ||
238 | The property may be queried via QMP/HMP: | |
239 | ||
240 | (QEMU) query-vm-generation-id | |
241 | {"return": {"guid": "324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87"}} | |
242 | ||
243 | Setting of this parameter is intentionally left out from the QMP/HMP | |
244 | interfaces. There are no known use cases for changing the GUID once QEMU is | |
245 | running, and adding this capability would greatly increase the complexity. |