summaryrefslogtreecommitdiff
path: root/docs/specs/vmgenid.txt
blob: aa9f5186767c22698f9615995c19c05d1e85eb39 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
VIRTUAL MACHINE GENERATION ID
=============================

Copyright (C) 2016 Red Hat, Inc.
Copyright (C) 2017 Skyport Systems, Inc.

This work is licensed under the terms of the GNU GPL, version 2 or later.
See the COPYING file in the top-level directory.

===

The VM generation ID (vmgenid) device is an emulated device which
exposes a 128-bit, cryptographically random, integer value identifier,
referred to as a Globally Unique Identifier, or GUID.

This allows management applications (e.g. libvirt) to notify the guest
operating system when the virtual machine is executed with a different
configuration (e.g. snapshot execution or creation from a template).  The
guest operating system notices the change, and is then able to react as
appropriate by marking its copies of distributed databases as dirty,
re-initializing its random number generator etc.


Requirements
------------

These requirements are extracted from the "How to implement virtual machine
generation ID support in a virtualization platform" section of the
specification, dated August 1, 2012.


The document may be found on the web at:
  http://go.microsoft.com/fwlink/?LinkId=260709

R1a. The generation ID shall live in an 8-byte aligned buffer.

R1b. The buffer holding the generation ID shall be in guest RAM, ROM, or device
     MMIO range.

R1c. The buffer holding the generation ID shall be kept separate from areas
     used by the operating system.

R1d. The buffer shall not be covered by an AddressRangeMemory or
     AddressRangeACPI entry in the E820 or UEFI memory map.

R1e. The generation ID shall not live in a page frame that could be mapped with
     caching disabled. (In other words, regardless of whether the generation ID
     lives in RAM, ROM or MMIO, it shall only be mapped as cacheable.)

R2 to R5. [These AML requirements are isolated well enough in the Microsoft
          specification for us to simply refer to them here.]

R6. The hypervisor shall expose a _HID (hardware identifier) object in the
    VMGenId device's scope that is unique to the hypervisor vendor.


QEMU Implementation
-------------------

The above-mentioned specification does not dictate which ACPI descriptor table
will contain the VM Generation ID device.  Other implementations (Hyper-V and
Xen) put it in the main descriptor table (Differentiated System Description
Table or DSDT).  For ease of debugging and implementation, we have decided to
put it in its own Secondary System Description Table, or SSDT.

The following is a dump of the contents from a running system:

# iasl -p ./SSDT -d /sys/firmware/acpi/tables/SSDT

Intel ACPI Component Architecture
ASL+ Optimizing Compiler version 20150717-64
Copyright (c) 2000 - 2015 Intel Corporation

Reading ACPI table from file /sys/firmware/acpi/tables/SSDT - Length
00000198 (0x0000C6)
ACPI: SSDT 0x0000000000000000 0000C6 (v01 BOCHS  VMGENID  00000001 BXPC
00000001)
Acpi table [SSDT] successfully installed and loaded
Pass 1 parse of [SSDT]
Pass 2 parse of [SSDT]
Parsing Deferred Opcodes (Methods/Buffers/Packages/Regions)

Parsing completed
Disassembly completed
ASL Output:    ./SSDT.dsl - 1631 bytes
# cat SSDT.dsl
/*
 * Intel ACPI Component Architecture
 * AML/ASL+ Disassembler version 20150717-64
 * Copyright (c) 2000 - 2015 Intel Corporation
 *
 * Disassembling to symbolic ASL+ operators
 *
 * Disassembly of /sys/firmware/acpi/tables/SSDT, Sun Feb  5 00:19:37 2017
 *
 * Original Table Header:
 *     Signature        "SSDT"
 *     Length           0x000000CA (202)
 *     Revision         0x01
 *     Checksum         0x4B
 *     OEM ID           "BOCHS "
 *     OEM Table ID     "VMGENID"
 *     OEM Revision     0x00000001 (1)
 *     Compiler ID      "BXPC"
 *     Compiler Version 0x00000001 (1)
 */
DefinitionBlock ("/sys/firmware/acpi/tables/SSDT.aml", "SSDT", 1, "BOCHS ",
"VMGENID", 0x00000001)
{
    Name (VGIA, 0x07FFF000)
    Scope (\_SB)
    {
        Device (VGEN)
        {
            Name (_HID, "QEMUVGID")  // _HID: Hardware ID
            Name (_CID, "VM_Gen_Counter")  // _CID: Compatible ID
            Name (_DDN, "VM_Gen_Counter")  // _DDN: DOS Device Name
            Method (_STA, 0, NotSerialized)  // _STA: Status
            {
                Local0 = 0x0F
                If ((VGIA == Zero))
                {
                    Local0 = Zero
                }

                Return (Local0)
            }

            Method (ADDR, 0, NotSerialized)
            {
                Local0 = Package (0x02) {}
                Index (Local0, Zero) = (VGIA + 0x28)
                Index (Local0, One) = Zero
                Return (Local0)
            }
        }
    }

    Method (\_GPE._E05, 0, NotSerialized)  // _Exx: Edge-Triggered GPE
    {
        Notify (\_SB.VGEN, 0x80) // Status Change
    }
}


Design Details:
---------------

Requirements R1a through R1e dictate that the memory holding the
VM Generation ID must be allocated and owned by the guest firmware,
in this case BIOS or UEFI.  However, to be useful, QEMU must be able to
change the contents of the memory at runtime, specifically when starting a
backed-up or snapshotted image.  In order to do this, QEMU must know the
address that has been allocated.

The mechanism chosen for this memory sharing is writeable fw_cfg blobs.
These are data object that are visible to both QEMU and guests, and are
addressable as sequential files.

More information about fw_cfg can be found in "docs/specs/fw_cfg.txt"

Two fw_cfg blobs are used in this case:

/etc/vmgenid_guid - contains the actual VM Generation ID GUID
                  - read-only to the guest
/etc/vmgenid_addr - contains the address of the downloaded vmgenid blob
                  - writeable by the guest


QEMU sends the following commands to the guest at startup:

1. Allocate memory for vmgenid_guid fw_cfg blob.
2. Write the address of vmgenid_guid into the SSDT (VGIA ACPI variable as
   shown above in the iasl dump).  Note that this change is not propagated
   back to QEMU.
3. Write the address of vmgenid_guid back to QEMU's copy of vmgenid_addr
   via the fw_cfg DMA interface.

After step 3, QEMU is able to update the contents of vmgenid_guid at will.

Since BIOS or UEFI does not necessarily run when we wish to change the GUID,
the value of VGIA is persisted via the VMState mechanism.

As spelled out in the specification, any change to the GUID executes an
ACPI notification.  The exact handler to use is not specified, so the vmgenid
device uses the first unused one:  \_GPE._E05.


Endian-ness Considerations:
---------------------------

Although not specified in Microsoft's document, it is assumed that the
device is expected to use little-endian format.

All GUID passed in via command line or monitor are treated as big-endian.
GUID values displayed via monitor are shown in big-endian format.


GUID Storage Format:
--------------------

In order to implement an OVMF "SDT Header Probe Suppressor", the contents of
the vmgenid_guid fw_cfg blob are not simply a 128-bit GUID.  There is also
significant padding in order to align and fill a memory page, as shown in the
following diagram:

+----------------------------------+
| SSDT with OEM Table ID = VMGENID |
+----------------------------------+
| ...                              |       TOP OF PAGE
| VGIA dword object ---------------|-----> +---------------------------+
| ...                              |       | fw-allocated array for    |
| _STA method referring to VGIA    |       | "etc/vmgenid_guid"        |
| ...                              |       +---------------------------+
| ADDR method referring to VGIA    |       |  0: OVMF SDT Header probe |
| ...                              |       |     suppressor            |
+----------------------------------+       | 36: padding for 8-byte    |
                                           |     alignment             |
                                           | 40: GUID                  |
                                           | 56: padding to page size  |
                                           +---------------------------+
                                           END OF PAGE


Device Usage:
-------------

The device has one property, which may be only be set using the command line:

  guid - sets the value of the GUID.  A special value "auto" instructs
         QEMU to generate a new random GUID.

For example:

  QEMU  -device vmgenid,guid="324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87"
  QEMU  -device vmgenid,guid=auto

The property may be queried via QMP/HMP:

  (QEMU) query-vm-generation-id
  {"return": {"guid": "324e6eaf-d1d1-4bf6-bf41-b9bb6c91fb87"}}

Setting of this parameter is intentionally left out from the QMP/HMP
interfaces.  There are no known use cases for changing the GUID once QEMU is
running, and adding this capability would greatly increase the complexity.