]>
Commit | Line | Data |
---|---|---|
1 | #ifndef HW_HYPERV_DYNMEM_PROTO_H | |
2 | #define HW_HYPERV_DYNMEM_PROTO_H | |
3 | ||
4 | /* | |
5 | * Hyper-V Dynamic Memory Protocol definitions | |
6 | * | |
7 | * Copyright (C) 2020-2023 Oracle and/or its affiliates. | |
8 | * | |
9 | * Based on drivers/hv/hv_balloon.c from Linux kernel: | |
10 | * Copyright (c) 2012, Microsoft Corporation. | |
11 | * | |
12 | * Author: K. Y. Srinivasan <kys@microsoft.com> | |
13 | * | |
14 | * This work is licensed under the terms of the GNU GPL, version 2. | |
15 | * See the COPYING file in the top-level directory. | |
16 | */ | |
17 | ||
18 | /* | |
19 | * Protocol versions. The low word is the minor version, the high word the major | |
20 | * version. | |
21 | * | |
22 | * History: | |
23 | * Initial version 1.0 | |
24 | * Changed to 0.1 on 2009/03/25 | |
25 | * Changes to 0.2 on 2009/05/14 | |
26 | * Changes to 0.3 on 2009/12/03 | |
27 | * Changed to 1.0 on 2011/04/05 | |
28 | * Changed to 2.0 on 2019/12/10 | |
29 | */ | |
30 | ||
31 | #define DYNMEM_MAKE_VERSION(Major, Minor) ((uint32_t)(((Major) << 16) | (Minor))) | |
32 | #define DYNMEM_MAJOR_VERSION(Version) ((uint32_t)(Version) >> 16) | |
33 | #define DYNMEM_MINOR_VERSION(Version) ((uint32_t)(Version) & 0xff) | |
34 | ||
35 | enum { | |
36 | DYNMEM_PROTOCOL_VERSION_1 = DYNMEM_MAKE_VERSION(0, 3), | |
37 | DYNMEM_PROTOCOL_VERSION_2 = DYNMEM_MAKE_VERSION(1, 0), | |
38 | DYNMEM_PROTOCOL_VERSION_3 = DYNMEM_MAKE_VERSION(2, 0), | |
39 | ||
40 | DYNMEM_PROTOCOL_VERSION_WIN7 = DYNMEM_PROTOCOL_VERSION_1, | |
41 | DYNMEM_PROTOCOL_VERSION_WIN8 = DYNMEM_PROTOCOL_VERSION_2, | |
42 | DYNMEM_PROTOCOL_VERSION_WIN10 = DYNMEM_PROTOCOL_VERSION_3, | |
43 | ||
44 | DYNMEM_PROTOCOL_VERSION_CURRENT = DYNMEM_PROTOCOL_VERSION_WIN10 | |
45 | }; | |
46 | ||
47 | ||
48 | ||
49 | /* | |
50 | * Message Types | |
51 | */ | |
52 | ||
53 | enum dm_message_type { | |
54 | /* | |
55 | * Version 0.3 | |
56 | */ | |
57 | DM_ERROR = 0, | |
58 | DM_VERSION_REQUEST = 1, | |
59 | DM_VERSION_RESPONSE = 2, | |
60 | DM_CAPABILITIES_REPORT = 3, | |
61 | DM_CAPABILITIES_RESPONSE = 4, | |
62 | DM_STATUS_REPORT = 5, | |
63 | DM_BALLOON_REQUEST = 6, | |
64 | DM_BALLOON_RESPONSE = 7, | |
65 | DM_UNBALLOON_REQUEST = 8, | |
66 | DM_UNBALLOON_RESPONSE = 9, | |
67 | DM_MEM_HOT_ADD_REQUEST = 10, | |
68 | DM_MEM_HOT_ADD_RESPONSE = 11, | |
69 | DM_VERSION_03_MAX = 11, | |
70 | /* | |
71 | * Version 1.0. | |
72 | */ | |
73 | DM_INFO_MESSAGE = 12, | |
74 | DM_VERSION_1_MAX = 12, | |
75 | ||
76 | /* | |
77 | * Version 2.0 | |
78 | */ | |
79 | DM_MEM_HOT_REMOVE_REQUEST = 13, | |
80 | DM_MEM_HOT_REMOVE_RESPONSE = 14 | |
81 | }; | |
82 | ||
83 | ||
84 | /* | |
85 | * Structures defining the dynamic memory management | |
86 | * protocol. | |
87 | */ | |
88 | ||
89 | union dm_version { | |
90 | struct { | |
91 | uint16_t minor_version; | |
92 | uint16_t major_version; | |
93 | }; | |
94 | uint32_t version; | |
95 | } QEMU_PACKED; | |
96 | ||
97 | ||
98 | union dm_caps { | |
99 | struct { | |
100 | uint64_t balloon:1; | |
101 | uint64_t hot_add:1; | |
102 | /* | |
103 | * To support guests that may have alignment | |
104 | * limitations on hot-add, the guest can specify | |
105 | * its alignment requirements; a value of n | |
106 | * represents an alignment of 2^n in mega bytes. | |
107 | */ | |
108 | uint64_t hot_add_alignment:4; | |
109 | uint64_t hot_remove:1; | |
110 | uint64_t reservedz:57; | |
111 | } cap_bits; | |
112 | uint64_t caps; | |
113 | } QEMU_PACKED; | |
114 | ||
115 | union dm_mem_page_range { | |
116 | struct { | |
117 | /* | |
118 | * The PFN number of the first page in the range. | |
119 | * 40 bits is the architectural limit of a PFN | |
120 | * number for AMD64. | |
121 | */ | |
122 | uint64_t start_page:40; | |
123 | /* | |
124 | * The number of pages in the range. | |
125 | */ | |
126 | uint64_t page_cnt:24; | |
127 | } finfo; | |
128 | uint64_t page_range; | |
129 | } QEMU_PACKED; | |
130 | ||
131 | ||
132 | ||
133 | /* | |
134 | * The header for all dynamic memory messages: | |
135 | * | |
136 | * type: Type of the message. | |
137 | * size: Size of the message in bytes; including the header. | |
138 | * trans_id: The guest is responsible for manufacturing this ID. | |
139 | */ | |
140 | ||
141 | struct dm_header { | |
142 | uint16_t type; | |
143 | uint16_t size; | |
144 | uint32_t trans_id; | |
145 | } QEMU_PACKED; | |
146 | ||
147 | /* | |
148 | * A generic message format for dynamic memory. | |
149 | * Specific message formats are defined later in the file. | |
150 | */ | |
151 | ||
152 | struct dm_message { | |
153 | struct dm_header hdr; | |
154 | uint8_t data[]; /* enclosed message */ | |
155 | } QEMU_PACKED; | |
156 | ||
157 | ||
158 | /* | |
159 | * Specific message types supporting the dynamic memory protocol. | |
160 | */ | |
161 | ||
162 | /* | |
163 | * Version negotiation message. Sent from the guest to the host. | |
164 | * The guest is free to try different versions until the host | |
165 | * accepts the version. | |
166 | * | |
167 | * dm_version: The protocol version requested. | |
168 | * is_last_attempt: If TRUE, this is the last version guest will request. | |
169 | * reservedz: Reserved field, set to zero. | |
170 | */ | |
171 | ||
172 | struct dm_version_request { | |
173 | struct dm_header hdr; | |
174 | union dm_version version; | |
175 | uint32_t is_last_attempt:1; | |
176 | uint32_t reservedz:31; | |
177 | } QEMU_PACKED; | |
178 | ||
179 | /* | |
180 | * Version response message; Host to Guest and indicates | |
181 | * if the host has accepted the version sent by the guest. | |
182 | * | |
183 | * is_accepted: If TRUE, host has accepted the version and the guest | |
184 | * should proceed to the next stage of the protocol. FALSE indicates that | |
185 | * guest should re-try with a different version. | |
186 | * | |
187 | * reservedz: Reserved field, set to zero. | |
188 | */ | |
189 | ||
190 | struct dm_version_response { | |
191 | struct dm_header hdr; | |
192 | uint64_t is_accepted:1; | |
193 | uint64_t reservedz:63; | |
194 | } QEMU_PACKED; | |
195 | ||
196 | /* | |
197 | * Message reporting capabilities. This is sent from the guest to the | |
198 | * host. | |
199 | */ | |
200 | ||
201 | struct dm_capabilities { | |
202 | struct dm_header hdr; | |
203 | union dm_caps caps; | |
204 | uint64_t min_page_cnt; | |
205 | uint64_t max_page_number; | |
206 | } QEMU_PACKED; | |
207 | ||
208 | /* | |
209 | * Response to the capabilities message. This is sent from the host to the | |
210 | * guest. This message notifies if the host has accepted the guest's | |
211 | * capabilities. If the host has not accepted, the guest must shutdown | |
212 | * the service. | |
213 | * | |
214 | * is_accepted: Indicates if the host has accepted guest's capabilities. | |
215 | * reservedz: Must be 0. | |
216 | */ | |
217 | ||
218 | struct dm_capabilities_resp_msg { | |
219 | struct dm_header hdr; | |
220 | uint64_t is_accepted:1; | |
221 | uint64_t hot_remove:1; | |
222 | uint64_t suppress_pressure_reports:1; | |
223 | uint64_t reservedz:61; | |
224 | } QEMU_PACKED; | |
225 | ||
226 | /* | |
227 | * This message is used to report memory pressure from the guest. | |
228 | * This message is not part of any transaction and there is no | |
229 | * response to this message. | |
230 | * | |
231 | * num_avail: Available memory in pages. | |
232 | * num_committed: Committed memory in pages. | |
233 | * page_file_size: The accumulated size of all page files | |
234 | * in the system in pages. | |
235 | * zero_free: The number of zero and free pages. | |
236 | * page_file_writes: The writes to the page file in pages. | |
237 | * io_diff: An indicator of file cache efficiency or page file activity, | |
238 | * calculated as File Cache Page Fault Count - Page Read Count. | |
239 | * This value is in pages. | |
240 | * | |
241 | * Some of these metrics are Windows specific and fortunately | |
242 | * the algorithm on the host side that computes the guest memory | |
243 | * pressure only uses num_committed value. | |
244 | */ | |
245 | ||
246 | struct dm_status { | |
247 | struct dm_header hdr; | |
248 | uint64_t num_avail; | |
249 | uint64_t num_committed; | |
250 | uint64_t page_file_size; | |
251 | uint64_t zero_free; | |
252 | uint32_t page_file_writes; | |
253 | uint32_t io_diff; | |
254 | } QEMU_PACKED; | |
255 | ||
256 | ||
257 | /* | |
258 | * Message to ask the guest to allocate memory - balloon up message. | |
259 | * This message is sent from the host to the guest. The guest may not be | |
260 | * able to allocate as much memory as requested. | |
261 | * | |
262 | * num_pages: number of pages to allocate. | |
263 | */ | |
264 | ||
265 | struct dm_balloon { | |
266 | struct dm_header hdr; | |
267 | uint32_t num_pages; | |
268 | uint32_t reservedz; | |
269 | } QEMU_PACKED; | |
270 | ||
271 | ||
272 | /* | |
273 | * Balloon response message; this message is sent from the guest | |
274 | * to the host in response to the balloon message. | |
275 | * | |
276 | * reservedz: Reserved; must be set to zero. | |
277 | * more_pages: If FALSE, this is the last message of the transaction. | |
278 | * if TRUE there will be at least one more message from the guest. | |
279 | * | |
280 | * range_count: The number of ranges in the range array. | |
281 | * | |
282 | * range_array: An array of page ranges returned to the host. | |
283 | * | |
284 | */ | |
285 | ||
286 | struct dm_balloon_response { | |
287 | struct dm_header hdr; | |
288 | uint32_t reservedz; | |
289 | uint32_t more_pages:1; | |
290 | uint32_t range_count:31; | |
291 | union dm_mem_page_range range_array[]; | |
292 | } QEMU_PACKED; | |
293 | ||
294 | /* | |
295 | * Un-balloon message; this message is sent from the host | |
296 | * to the guest to give guest more memory. | |
297 | * | |
298 | * more_pages: If FALSE, this is the last message of the transaction. | |
299 | * if TRUE there will be at least one more message from the guest. | |
300 | * | |
301 | * reservedz: Reserved; must be set to zero. | |
302 | * | |
303 | * range_count: The number of ranges in the range array. | |
304 | * | |
305 | * range_array: An array of page ranges returned to the host. | |
306 | * | |
307 | */ | |
308 | ||
309 | struct dm_unballoon_request { | |
310 | struct dm_header hdr; | |
311 | uint32_t more_pages:1; | |
312 | uint32_t reservedz:31; | |
313 | uint32_t range_count; | |
314 | union dm_mem_page_range range_array[]; | |
315 | } QEMU_PACKED; | |
316 | ||
317 | /* | |
318 | * Un-balloon response message; this message is sent from the guest | |
319 | * to the host in response to an unballoon request. | |
320 | * | |
321 | */ | |
322 | ||
323 | struct dm_unballoon_response { | |
324 | struct dm_header hdr; | |
325 | } QEMU_PACKED; | |
326 | ||
327 | ||
328 | /* | |
329 | * Hot add request message. Message sent from the host to the guest. | |
330 | * | |
331 | * mem_range: Memory range to hot add. | |
332 | * | |
333 | */ | |
334 | ||
335 | struct dm_hot_add { | |
336 | struct dm_header hdr; | |
337 | union dm_mem_page_range range; | |
338 | } QEMU_PACKED; | |
339 | ||
340 | /* | |
341 | * Hot add response message. | |
342 | * This message is sent by the guest to report the status of a hot add request. | |
343 | * If page_count is less than the requested page count, then the host should | |
344 | * assume all further hot add requests will fail, since this indicates that | |
345 | * the guest has hit an upper physical memory barrier. | |
346 | * | |
347 | * Hot adds may also fail due to low resources; in this case, the guest must | |
348 | * not complete this message until the hot add can succeed, and the host must | |
349 | * not send a new hot add request until the response is sent. | |
350 | * If VSC fails to hot add memory DYNMEM_NUMBER_OF_UNSUCCESSFUL_HOTADD_ATTEMPTS | |
351 | * times it fails the request. | |
352 | * | |
353 | * | |
354 | * page_count: number of pages that were successfully hot added. | |
355 | * | |
356 | * result: result of the operation 1: success, 0: failure. | |
357 | * | |
358 | */ | |
359 | ||
360 | struct dm_hot_add_response { | |
361 | struct dm_header hdr; | |
362 | uint32_t page_count; | |
363 | uint32_t result; | |
364 | } QEMU_PACKED; | |
365 | ||
366 | struct dm_hot_remove { | |
367 | struct dm_header hdr; | |
368 | uint32_t virtual_node; | |
369 | uint32_t page_count; | |
370 | uint32_t qos_flags; | |
371 | uint32_t reservedZ; | |
372 | } QEMU_PACKED; | |
373 | ||
374 | struct dm_hot_remove_response { | |
375 | struct dm_header hdr; | |
376 | uint32_t result; | |
377 | uint32_t range_count; | |
378 | uint64_t more_pages:1; | |
379 | uint64_t reservedz:63; | |
380 | union dm_mem_page_range range_array[]; | |
381 | } QEMU_PACKED; | |
382 | ||
383 | #define DM_REMOVE_QOS_LARGE (1 << 0) | |
384 | #define DM_REMOVE_QOS_LOCAL (1 << 1) | |
385 | #define DM_REMOVE_QOS_MASK (0x3) | |
386 | ||
387 | /* | |
388 | * Types of information sent from host to the guest. | |
389 | */ | |
390 | ||
391 | enum dm_info_type { | |
392 | INFO_TYPE_MAX_PAGE_CNT = 0, | |
393 | MAX_INFO_TYPE | |
394 | }; | |
395 | ||
396 | ||
397 | /* | |
398 | * Header for the information message. | |
399 | */ | |
400 | ||
401 | struct dm_info_header { | |
402 | enum dm_info_type type; | |
403 | uint32_t data_size; | |
404 | uint8_t data[]; | |
405 | } QEMU_PACKED; | |
406 | ||
407 | /* | |
408 | * This message is sent from the host to the guest to pass | |
409 | * some relevant information (win8 addition). | |
410 | * | |
411 | * reserved: no used. | |
412 | * info_size: size of the information blob. | |
413 | * info: information blob. | |
414 | */ | |
415 | ||
416 | struct dm_info_msg { | |
417 | struct dm_header hdr; | |
418 | uint32_t reserved; | |
419 | uint32_t info_size; | |
420 | uint8_t info[]; | |
421 | }; | |
422 | ||
423 | #endif |