xref: /openbmc/qemu/block/vhdx.h (revision ad6ef0a42e314a8c6ac6c96d5f6e607a1e5644b5)
1203cdba3SJeff Cody /*
2203cdba3SJeff Cody  * Block driver for Hyper-V VHDX Images
3203cdba3SJeff Cody  *
4203cdba3SJeff Cody  * Copyright (c) 2013 Red Hat, Inc.,
5203cdba3SJeff Cody  *
6203cdba3SJeff Cody  * Authors:
7203cdba3SJeff Cody  *  Jeff Cody <jcody@redhat.com>
8203cdba3SJeff Cody  *
96e9d290bSJeff Cody  *  This is based on the "VHDX Format Specification v1.00", published 8/25/2012
10203cdba3SJeff Cody  *  by Microsoft:
116e9d290bSJeff Cody  *      https://www.microsoft.com/en-us/download/details.aspx?id=34750
12203cdba3SJeff Cody  *
13203cdba3SJeff Cody  * This work is licensed under the terms of the GNU LGPL, version 2 or later.
14203cdba3SJeff Cody  * See the COPYING.LIB file in the top-level directory.
15203cdba3SJeff Cody  *
16203cdba3SJeff Cody  */
17203cdba3SJeff Cody 
18203cdba3SJeff Cody #ifndef BLOCK_VHDX_H
19203cdba3SJeff Cody #define BLOCK_VHDX_H
20e9991e29SStefano Garzarella #include "qemu/units.h"
213412f7b1SJeff Cody 
225366092cSChunyan Liu #define DEFAULT_LOG_SIZE 1048576 /* 1MiB */
230cb98af2SStefano Garzarella /* Note: can't use 1 * MiB, because it's passed to stringify() */
240cb98af2SStefano Garzarella 
25203cdba3SJeff Cody /* Structures and fields present in the VHDX file */
26203cdba3SJeff Cody 
27203cdba3SJeff Cody /* The header section has the following blocks,
28203cdba3SJeff Cody  * each block is 64KB:
29203cdba3SJeff Cody  *
30203cdba3SJeff Cody  * _____________________________________________________________________________
31203cdba3SJeff Cody  * | File Id. |   Header 1    | Header 2   | Region Table |  Reserved (768KB)  |
32203cdba3SJeff Cody  * |----------|---------------|------------|--------------|--------------------|
33203cdba3SJeff Cody  * |          |               |            |              |                    |
34203cdba3SJeff Cody  * 0.........64KB...........128KB........192KB..........256KB................1MB
35203cdba3SJeff Cody  */
36203cdba3SJeff Cody 
370cb98af2SStefano Garzarella #define VHDX_HEADER_BLOCK_SIZE      (64 * KiB)
38203cdba3SJeff Cody 
39203cdba3SJeff Cody #define VHDX_FILE_ID_OFFSET         0
40203cdba3SJeff Cody #define VHDX_HEADER1_OFFSET         (VHDX_HEADER_BLOCK_SIZE * 1)
41203cdba3SJeff Cody #define VHDX_HEADER2_OFFSET         (VHDX_HEADER_BLOCK_SIZE * 2)
42203cdba3SJeff Cody #define VHDX_REGION_TABLE_OFFSET    (VHDX_HEADER_BLOCK_SIZE * 3)
433412f7b1SJeff Cody #define VHDX_REGION_TABLE2_OFFSET   (VHDX_HEADER_BLOCK_SIZE * 4)
44203cdba3SJeff Cody 
453412f7b1SJeff Cody #define VHDX_HEADER_SECTION_END     (1 * MiB)
46203cdba3SJeff Cody /*
47203cdba3SJeff Cody  * A note on the use of MS-GUID fields.  For more details on the GUID,
48203cdba3SJeff Cody  * please see: https://en.wikipedia.org/wiki/Globally_unique_identifier.
49203cdba3SJeff Cody  *
50203cdba3SJeff Cody  * The VHDX specification only states that these are MS GUIDs, and which
51203cdba3SJeff Cody  * bytes are data1-data4. It makes no mention of what algorithm should be used
52203cdba3SJeff Cody  * to generate the GUID, nor what standard.  However, looking at the specified
53203cdba3SJeff Cody  * known GUID fields, it appears the GUIDs are:
54203cdba3SJeff Cody  *  Standard/DCE GUID type  (noted by 10b in the MSB of byte 0 of .data4)
55203cdba3SJeff Cody  *  Random algorithm        (noted by 0x4XXX for .data3)
56203cdba3SJeff Cody  */
57203cdba3SJeff Cody 
58203cdba3SJeff Cody /* ---- HEADER SECTION STRUCTURES ---- */
59203cdba3SJeff Cody 
60203cdba3SJeff Cody /* These structures are ones that are defined in the VHDX specification
61203cdba3SJeff Cody  * document */
62203cdba3SJeff Cody 
6362e466e8SJeff Cody #define VHDX_FILE_SIGNATURE 0x656C696678646876ULL  /* "vhdxfile" in ASCII */
64203cdba3SJeff Cody typedef struct VHDXFileIdentifier {
65203cdba3SJeff Cody     uint64_t    signature;              /* "vhdxfile" in ASCII */
66203cdba3SJeff Cody     uint16_t    creator[256];           /* optional; utf-16 string to identify
6761c02e56SJeff Cody                                            the vhdx file creator.  Diagnostic
68203cdba3SJeff Cody                                            only */
69203cdba3SJeff Cody } VHDXFileIdentifier;
70203cdba3SJeff Cody 
71203cdba3SJeff Cody 
72203cdba3SJeff Cody /* the guid is a 16 byte unique ID - the definition for this used by
73203cdba3SJeff Cody  * Microsoft is not just 16 bytes though - it is a structure that is defined,
74203cdba3SJeff Cody  * so we need to follow it here so that endianness does not trip us up */
75203cdba3SJeff Cody 
764f18b782SJeff Cody typedef struct QEMU_PACKED MSGUID {
77203cdba3SJeff Cody     uint32_t  data1;
78203cdba3SJeff Cody     uint16_t  data2;
79203cdba3SJeff Cody     uint16_t  data3;
80203cdba3SJeff Cody     uint8_t   data4[8];
81203cdba3SJeff Cody } MSGUID;
82203cdba3SJeff Cody 
83203cdba3SJeff Cody #define guid_eq(a, b) \
84203cdba3SJeff Cody     (memcmp(&(a), &(b), sizeof(MSGUID)) == 0)
85203cdba3SJeff Cody 
860cb98af2SStefano Garzarella #define VHDX_HEADER_SIZE (4 * KiB)    /* although the vhdx_header struct in disk
87203cdba3SJeff Cody                                          is only 582 bytes, for purposes of crc
88203cdba3SJeff Cody                                          the header is the first 4KB of the 64KB
89203cdba3SJeff Cody                                          block */
90203cdba3SJeff Cody 
91203cdba3SJeff Cody /* The full header is 4KB, although the actual header data is much smaller.
92203cdba3SJeff Cody  * But for the checksum calculation, it is over the entire 4KB structure,
93203cdba3SJeff Cody  * not just the defined portion of it */
943412f7b1SJeff Cody #define VHDX_HEADER_SIGNATURE 0x64616568
95203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXHeader {
96203cdba3SJeff Cody     uint32_t    signature;              /* "head" in ASCII */
97203cdba3SJeff Cody     uint32_t    checksum;               /* CRC-32C hash of the whole header */
98203cdba3SJeff Cody     uint64_t    sequence_number;        /* Seq number of this header.  Each
99203cdba3SJeff Cody                                            VHDX file has 2 of these headers,
100203cdba3SJeff Cody                                            and only the header with the highest
101203cdba3SJeff Cody                                            sequence number is valid */
102203cdba3SJeff Cody     MSGUID      file_write_guid;        /* 128 bit unique identifier. Must be
103203cdba3SJeff Cody                                            updated to new, unique value before
104203cdba3SJeff Cody                                            the first modification is made to
105203cdba3SJeff Cody                                            file */
106203cdba3SJeff Cody     MSGUID      data_write_guid;        /* 128 bit unique identifier. Must be
107203cdba3SJeff Cody                                            updated to new, unique value before
108203cdba3SJeff Cody                                            the first modification is made to
109203cdba3SJeff Cody                                            visible data.   Visbile data is
110203cdba3SJeff Cody                                            defined as:
111203cdba3SJeff Cody                                                     - system & user metadata
112203cdba3SJeff Cody                                                     - raw block data
113203cdba3SJeff Cody                                                     - disk size
114203cdba3SJeff Cody                                                     - any change that will
115203cdba3SJeff Cody                                                       cause the virtual disk
116203cdba3SJeff Cody                                                       sector read to differ
117203cdba3SJeff Cody 
118203cdba3SJeff Cody                                            This does not need to change if
119203cdba3SJeff Cody                                            blocks are re-arranged */
120203cdba3SJeff Cody     MSGUID      log_guid;               /* 128 bit unique identifier. If zero,
121203cdba3SJeff Cody                                            there is no valid log. If non-zero,
122203cdba3SJeff Cody                                            log entries with this guid are
123203cdba3SJeff Cody                                            valid. */
12461c02e56SJeff Cody     uint16_t    log_version;            /* version of the log format. Must be
12561c02e56SJeff Cody                                            set to zero */
126203cdba3SJeff Cody     uint16_t    version;                /* version of the vhdx file.  Currently,
127203cdba3SJeff Cody                                            only supported version is "1" */
128203cdba3SJeff Cody     uint32_t    log_length;             /* length of the log.  Must be multiple
129203cdba3SJeff Cody                                            of 1MB */
130203cdba3SJeff Cody     uint64_t    log_offset;             /* byte offset in the file of the log.
131203cdba3SJeff Cody                                            Must also be a multiple of 1MB */
132203cdba3SJeff Cody } VHDXHeader;
133203cdba3SJeff Cody 
134203cdba3SJeff Cody /* Header for the region table block */
1353412f7b1SJeff Cody #define VHDX_REGION_SIGNATURE  0x69676572  /* "regi" in ASCII */
136203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXRegionTableHeader {
137203cdba3SJeff Cody     uint32_t    signature;              /* "regi" in ASCII */
138203cdba3SJeff Cody     uint32_t    checksum;               /* CRC-32C hash of the 64KB table */
139203cdba3SJeff Cody     uint32_t    entry_count;            /* number of valid entries */
140203cdba3SJeff Cody     uint32_t    reserved;
141203cdba3SJeff Cody } VHDXRegionTableHeader;
142203cdba3SJeff Cody 
143203cdba3SJeff Cody /* Individual region table entry.  There may be a maximum of 2047 of these
144203cdba3SJeff Cody  *
145203cdba3SJeff Cody  *  There are two known region table properties.  Both are required.
146203cdba3SJeff Cody  *  BAT (block allocation table):  2DC27766F62342009D64115E9BFD4A08
147203cdba3SJeff Cody  *  Metadata:                      8B7CA20647904B9AB8FE575F050F886E
148203cdba3SJeff Cody  */
149203cdba3SJeff Cody #define VHDX_REGION_ENTRY_REQUIRED  0x01    /* if set, parser must understand
150203cdba3SJeff Cody                                                this entry in order to open
151203cdba3SJeff Cody                                                file */
152203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXRegionTableEntry {
153203cdba3SJeff Cody     MSGUID      guid;                   /* 128-bit unique identifier */
154203cdba3SJeff Cody     uint64_t    file_offset;            /* offset of the object in the file.
155203cdba3SJeff Cody                                            Must be multiple of 1MB */
156203cdba3SJeff Cody     uint32_t    length;                 /* length, in bytes, of the object */
157203cdba3SJeff Cody     uint32_t    data_bits;
158203cdba3SJeff Cody } VHDXRegionTableEntry;
159203cdba3SJeff Cody 
160203cdba3SJeff Cody 
161203cdba3SJeff Cody /* ---- LOG ENTRY STRUCTURES ---- */
1620cb98af2SStefano Garzarella #define VHDX_LOG_MIN_SIZE (1 * MiB)
1630cb98af2SStefano Garzarella #define VHDX_LOG_SECTOR_SIZE (4 * KiB)
164203cdba3SJeff Cody #define VHDX_LOG_HDR_SIZE 64
165625565d2SJeff Cody #define VHDX_LOG_SIGNATURE 0x65676f6c
166203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXLogEntryHeader {
167203cdba3SJeff Cody     uint32_t    signature;              /* "loge" in ASCII */
168203cdba3SJeff Cody     uint32_t    checksum;               /* CRC-32C hash of the 64KB table */
169203cdba3SJeff Cody     uint32_t    entry_length;           /* length in bytes, multiple of 1MB */
170203cdba3SJeff Cody     uint32_t    tail;                   /* byte offset of first log entry of a
171203cdba3SJeff Cody                                            seq, where this entry is the last
172203cdba3SJeff Cody                                            entry */
173203cdba3SJeff Cody     uint64_t    sequence_number;        /* incremented with each log entry.
174203cdba3SJeff Cody                                            May not be zero. */
175203cdba3SJeff Cody     uint32_t    descriptor_count;       /* number of descriptors in this log
176203cdba3SJeff Cody                                            entry, must be >= 0 */
177203cdba3SJeff Cody     uint32_t    reserved;
178203cdba3SJeff Cody     MSGUID      log_guid;               /* value of the log_guid from
179203cdba3SJeff Cody                                            vhdx_header.  If not found in
180203cdba3SJeff Cody                                            vhdx_header, it is invalid */
181203cdba3SJeff Cody     uint64_t    flushed_file_offset;    /* see spec for full details - this
18252f35022SStefan Weil                                            should be vhdx file size in bytes */
183203cdba3SJeff Cody     uint64_t    last_file_offset;       /* size in bytes that all allocated
184203cdba3SJeff Cody                                            file structures fit into */
185203cdba3SJeff Cody } VHDXLogEntryHeader;
186203cdba3SJeff Cody 
187203cdba3SJeff Cody #define VHDX_LOG_DESC_SIZE 32
188625565d2SJeff Cody #define VHDX_LOG_DESC_SIGNATURE 0x63736564
189625565d2SJeff Cody #define VHDX_LOG_ZERO_SIGNATURE 0x6f72657a
190203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXLogDescriptor {
191203cdba3SJeff Cody     uint32_t    signature;              /* "zero" or "desc" in ASCII */
192203cdba3SJeff Cody     union  {
193203cdba3SJeff Cody         uint32_t    reserved;           /* zero desc */
194203cdba3SJeff Cody         uint32_t    trailing_bytes;     /* data desc: bytes 4092-4096 of the
195203cdba3SJeff Cody                                            data sector */
196203cdba3SJeff Cody     };
197203cdba3SJeff Cody     union {
198203cdba3SJeff Cody         uint64_t    zero_length;        /* zero desc: length of the section to
199203cdba3SJeff Cody                                            zero */
200203cdba3SJeff Cody         uint64_t    leading_bytes;      /* data desc: bytes 0-7 of the data
201203cdba3SJeff Cody                                            sector */
202203cdba3SJeff Cody     };
203203cdba3SJeff Cody     uint64_t    file_offset;            /* file offset to write zeros - multiple
204203cdba3SJeff Cody                                            of 4kB */
205203cdba3SJeff Cody     uint64_t    sequence_number;        /* must match same field in
206203cdba3SJeff Cody                                            vhdx_log_entry_header */
207203cdba3SJeff Cody } VHDXLogDescriptor;
208203cdba3SJeff Cody 
209625565d2SJeff Cody #define VHDX_LOG_DATA_SIGNATURE 0x61746164
210203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXLogDataSector {
211203cdba3SJeff Cody     uint32_t    data_signature;         /* "data" in ASCII */
212203cdba3SJeff Cody     uint32_t    sequence_high;          /* 4 MSB of 8 byte sequence_number */
213203cdba3SJeff Cody     uint8_t     data[4084];             /* raw data, bytes 8-4091 (inclusive).
214203cdba3SJeff Cody                                            see the data descriptor field for the
2153202d8e4SMichael Tokarev                                            other missing bytes */
216203cdba3SJeff Cody     uint32_t    sequence_low;           /* 4 LSB of 8 byte sequence_number */
217203cdba3SJeff Cody } VHDXLogDataSector;
218203cdba3SJeff Cody 
219203cdba3SJeff Cody 
220203cdba3SJeff Cody 
221203cdba3SJeff Cody /* block states - different state values depending on whether it is a
222203cdba3SJeff Cody  * payload block, or a sector block. */
223203cdba3SJeff Cody 
224203cdba3SJeff Cody #define PAYLOAD_BLOCK_NOT_PRESENT       0
225203cdba3SJeff Cody #define PAYLOAD_BLOCK_UNDEFINED         1
226203cdba3SJeff Cody #define PAYLOAD_BLOCK_ZERO              2
227a9d1e9daSJeff Cody #define PAYLOAD_BLOCK_UNMAPPED          3
228a9d1e9daSJeff Cody #define PAYLOAD_BLOCK_UNMAPPED_v095     5
229d92aa883SJeff Cody #define PAYLOAD_BLOCK_FULLY_PRESENT     6
230203cdba3SJeff Cody #define PAYLOAD_BLOCK_PARTIALLY_PRESENT 7
231203cdba3SJeff Cody 
232203cdba3SJeff Cody #define SB_BLOCK_NOT_PRESENT    0
233203cdba3SJeff Cody #define SB_BLOCK_PRESENT        6
234203cdba3SJeff Cody 
235203cdba3SJeff Cody /* per the spec */
236203cdba3SJeff Cody #define VHDX_MAX_SECTORS_PER_BLOCK  (1 << 23)
237203cdba3SJeff Cody 
238203cdba3SJeff Cody /* upper 44 bits are the file offset in 1MB units lower 3 bits are the state
239203cdba3SJeff Cody    other bits are reserved */
240203cdba3SJeff Cody #define VHDX_BAT_STATE_BIT_MASK 0x07
24162e466e8SJeff Cody #define VHDX_BAT_FILE_OFF_MASK  0xFFFFFFFFFFF00000ULL /* upper 44 bits */
242203cdba3SJeff Cody typedef uint64_t VHDXBatEntry;
243203cdba3SJeff Cody 
244203cdba3SJeff Cody /* ---- METADATA REGION STRUCTURES ---- */
245203cdba3SJeff Cody 
246203cdba3SJeff Cody #define VHDX_METADATA_ENTRY_SIZE 32
247203cdba3SJeff Cody #define VHDX_METADATA_MAX_ENTRIES 2047  /* not including the header */
248203cdba3SJeff Cody #define VHDX_METADATA_TABLE_MAX_SIZE \
249203cdba3SJeff Cody     (VHDX_METADATA_ENTRY_SIZE * (VHDX_METADATA_MAX_ENTRIES+1))
25062e466e8SJeff Cody #define VHDX_METADATA_SIGNATURE 0x617461646174656DULL  /* "metadata" in ASCII */
251203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXMetadataTableHeader {
252203cdba3SJeff Cody     uint64_t    signature;              /* "metadata" in ASCII */
253203cdba3SJeff Cody     uint16_t    reserved;
254203cdba3SJeff Cody     uint16_t    entry_count;            /* number table entries. <= 2047 */
255203cdba3SJeff Cody     uint32_t    reserved2[5];
256203cdba3SJeff Cody } VHDXMetadataTableHeader;
257203cdba3SJeff Cody 
258203cdba3SJeff Cody #define VHDX_META_FLAGS_IS_USER         0x01    /* max 1024 entries */
259203cdba3SJeff Cody #define VHDX_META_FLAGS_IS_VIRTUAL_DISK 0x02    /* virtual disk metadata if set,
2603202d8e4SMichael Tokarev                                                    otherwise file metadata */
261203cdba3SJeff Cody #define VHDX_META_FLAGS_IS_REQUIRED     0x04    /* parse must understand this
262203cdba3SJeff Cody                                                    entry to open the file */
263203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXMetadataTableEntry {
264203cdba3SJeff Cody     MSGUID      item_id;                /* 128-bit identifier for metadata */
265203cdba3SJeff Cody     uint32_t    offset;                 /* byte offset of the metadata.  At
266203cdba3SJeff Cody                                            least 64kB.  Relative to start of
267203cdba3SJeff Cody                                            metadata region */
268203cdba3SJeff Cody                                         /* note: if length = 0, so is offset */
269203cdba3SJeff Cody     uint32_t    length;                 /* length of metadata. <= 1MB. */
270625565d2SJeff Cody     uint32_t    data_bits;              /* least-significant 3 bits are flags,
271625565d2SJeff Cody                                            the rest are reserved (see above) */
272203cdba3SJeff Cody     uint32_t    reserved2;
273203cdba3SJeff Cody } VHDXMetadataTableEntry;
274203cdba3SJeff Cody 
275203cdba3SJeff Cody #define VHDX_PARAMS_LEAVE_BLOCKS_ALLOCED 0x01   /* Do not change any blocks to
276203cdba3SJeff Cody                                                    be BLOCK_NOT_PRESENT.
277203cdba3SJeff Cody                                                    If set indicates a fixed
278203cdba3SJeff Cody                                                    size VHDX file */
279203cdba3SJeff Cody #define VHDX_PARAMS_HAS_PARENT           0x02    /* has parent / backing file */
2803412f7b1SJeff Cody #define VHDX_BLOCK_SIZE_MIN             (1   * MiB)
2813412f7b1SJeff Cody #define VHDX_BLOCK_SIZE_MAX             (256 * MiB)
282203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXFileParameters {
283203cdba3SJeff Cody     uint32_t    block_size;             /* size of each payload block, always
284203cdba3SJeff Cody                                            power of 2, <= 256MB and >= 1MB. */
285625565d2SJeff Cody     uint32_t data_bits;                 /* least-significant 2 bits are flags,
286625565d2SJeff Cody                                            the rest are reserved (see above) */
287203cdba3SJeff Cody } VHDXFileParameters;
288203cdba3SJeff Cody 
2893412f7b1SJeff Cody #define VHDX_MAX_IMAGE_SIZE  ((uint64_t) 64 * TiB)
290203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXVirtualDiskSize {
291203cdba3SJeff Cody     uint64_t    virtual_disk_size;      /* Size of the virtual disk, in bytes.
292203cdba3SJeff Cody                                            Must be multiple of the sector size,
293203cdba3SJeff Cody                                            max of 64TB */
294203cdba3SJeff Cody } VHDXVirtualDiskSize;
295203cdba3SJeff Cody 
296203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXPage83Data {
29761c02e56SJeff Cody     MSGUID      page_83_data;           /* unique id for scsi devices that
298203cdba3SJeff Cody                                            support page 0x83 */
299203cdba3SJeff Cody } VHDXPage83Data;
300203cdba3SJeff Cody 
301203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXVirtualDiskLogicalSectorSize {
302203cdba3SJeff Cody     uint32_t    logical_sector_size;    /* virtual disk sector size (in bytes).
303203cdba3SJeff Cody                                            Can only be 512 or 4096 bytes */
304203cdba3SJeff Cody } VHDXVirtualDiskLogicalSectorSize;
305203cdba3SJeff Cody 
306203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXVirtualDiskPhysicalSectorSize {
307203cdba3SJeff Cody     uint32_t    physical_sector_size;   /* physical sector size (in bytes).
308203cdba3SJeff Cody                                            Can only be 512 or 4096 bytes */
309203cdba3SJeff Cody } VHDXVirtualDiskPhysicalSectorSize;
310203cdba3SJeff Cody 
311203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXParentLocatorHeader {
31261c02e56SJeff Cody     MSGUID      locator_type;           /* type of the parent virtual disk. */
313203cdba3SJeff Cody     uint16_t    reserved;
314203cdba3SJeff Cody     uint16_t    key_value_count;        /* number of key/value pairs for this
315203cdba3SJeff Cody                                            locator */
316203cdba3SJeff Cody } VHDXParentLocatorHeader;
317203cdba3SJeff Cody 
318203cdba3SJeff Cody /* key and value strings are UNICODE strings, UTF-16 LE encoding, no NULs */
319203cdba3SJeff Cody typedef struct QEMU_PACKED VHDXParentLocatorEntry {
320203cdba3SJeff Cody     uint32_t    key_offset;             /* offset in metadata for key, > 0 */
321203cdba3SJeff Cody     uint32_t    value_offset;           /* offset in metadata for value, >0 */
322203cdba3SJeff Cody     uint16_t    key_length;             /* length of entry key, > 0 */
323203cdba3SJeff Cody     uint16_t    value_length;           /* length of entry value, > 0 */
324203cdba3SJeff Cody } VHDXParentLocatorEntry;
325203cdba3SJeff Cody 
326203cdba3SJeff Cody 
327203cdba3SJeff Cody /* ----- END VHDX SPECIFICATION STRUCTURES ---- */
328203cdba3SJeff Cody 
32928541d46SJeff Cody typedef struct VHDXMetadataEntries {
33028541d46SJeff Cody     VHDXMetadataTableEntry file_parameters_entry;
33128541d46SJeff Cody     VHDXMetadataTableEntry virtual_disk_size_entry;
33228541d46SJeff Cody     VHDXMetadataTableEntry page83_data_entry;
33328541d46SJeff Cody     VHDXMetadataTableEntry logical_sector_size_entry;
33428541d46SJeff Cody     VHDXMetadataTableEntry phys_sector_size_entry;
33528541d46SJeff Cody     VHDXMetadataTableEntry parent_locator_entry;
33628541d46SJeff Cody     uint16_t present;
33728541d46SJeff Cody } VHDXMetadataEntries;
33828541d46SJeff Cody 
339625565d2SJeff Cody typedef struct VHDXLogEntries {
340625565d2SJeff Cody     uint64_t offset;
341625565d2SJeff Cody     uint64_t length;
3420a43a1b5SJeff Cody     uint32_t write;
3430a43a1b5SJeff Cody     uint32_t read;
3440a43a1b5SJeff Cody     VHDXLogEntryHeader *hdr;
3450a43a1b5SJeff Cody     void *desc_buffer;
3460a43a1b5SJeff Cody     uint64_t sequence;
347625565d2SJeff Cody     uint32_t tail;
348625565d2SJeff Cody } VHDXLogEntries;
349625565d2SJeff Cody 
3501a848fd4SJeff Cody typedef struct VHDXRegionEntry {
3511a848fd4SJeff Cody     uint64_t start;
3521a848fd4SJeff Cody     uint64_t end;
3531a848fd4SJeff Cody     QLIST_ENTRY(VHDXRegionEntry) entries;
3541a848fd4SJeff Cody } VHDXRegionEntry;
3551a848fd4SJeff Cody 
35628541d46SJeff Cody typedef struct BDRVVHDXState {
35728541d46SJeff Cody     CoMutex lock;
35828541d46SJeff Cody 
35928541d46SJeff Cody     int curr_header;
36028541d46SJeff Cody     VHDXHeader *headers[2];
36128541d46SJeff Cody 
36228541d46SJeff Cody     VHDXRegionTableHeader rt;
36328541d46SJeff Cody     VHDXRegionTableEntry bat_rt;         /* region table for the BAT */
36428541d46SJeff Cody     VHDXRegionTableEntry metadata_rt;    /* region table for the metadata */
36528541d46SJeff Cody 
36628541d46SJeff Cody     VHDXMetadataTableHeader metadata_hdr;
36728541d46SJeff Cody     VHDXMetadataEntries metadata_entries;
36828541d46SJeff Cody 
36928541d46SJeff Cody     VHDXFileParameters params;
37028541d46SJeff Cody     uint32_t block_size;
37128541d46SJeff Cody     uint32_t block_size_bits;
37228541d46SJeff Cody     uint32_t sectors_per_block;
37328541d46SJeff Cody     uint32_t sectors_per_block_bits;
37428541d46SJeff Cody 
37528541d46SJeff Cody     uint64_t virtual_disk_size;
37628541d46SJeff Cody     uint32_t logical_sector_size;
37728541d46SJeff Cody     uint32_t physical_sector_size;
37828541d46SJeff Cody 
37928541d46SJeff Cody     uint64_t chunk_ratio;
38028541d46SJeff Cody     uint32_t chunk_ratio_bits;
38128541d46SJeff Cody     uint32_t logical_sector_size_bits;
38228541d46SJeff Cody 
38328541d46SJeff Cody     uint32_t bat_entries;
38428541d46SJeff Cody     VHDXBatEntry *bat;
38528541d46SJeff Cody     uint64_t bat_offset;
38628541d46SJeff Cody 
387c3906c5eSJeff Cody     bool first_visible_write;
38828541d46SJeff Cody     MSGUID session_guid;
38928541d46SJeff Cody 
390625565d2SJeff Cody     VHDXLogEntries log;
391625565d2SJeff Cody 
39228541d46SJeff Cody     VHDXParentLocatorHeader parent_header;
39328541d46SJeff Cody     VHDXParentLocatorEntry *parent_entries;
39428541d46SJeff Cody 
39528541d46SJeff Cody     Error *migration_blocker;
3961a848fd4SJeff Cody 
3977e30e6a6SJeff Cody     bool log_replayed_on_open;
3987e30e6a6SJeff Cody 
399b58deb34SPaolo Bonzini     QLIST_HEAD(, VHDXRegionEntry) regions;
40028541d46SJeff Cody } BDRVVHDXState;
401e8d4e5ffSJeff Cody 
4024f18b782SJeff Cody void vhdx_guid_generate(MSGUID *guid);
4034f18b782SJeff Cody 
404*65ff757dSKevin Wolf int GRAPH_RDLOCK
405*65ff757dSKevin Wolf vhdx_update_headers(BlockDriverState *bs, BDRVVHDXState *s, bool rw,
406c3906c5eSJeff Cody                     MSGUID *log_guid);
407c3906c5eSJeff Cody 
4084f18b782SJeff Cody uint32_t vhdx_update_checksum(uint8_t *buf, size_t size, int crc_offset);
409e8d4e5ffSJeff Cody uint32_t vhdx_checksum_calc(uint32_t crc, uint8_t *buf, size_t size,
410e8d4e5ffSJeff Cody                             int crc_offset);
411e8d4e5ffSJeff Cody 
412e8d4e5ffSJeff Cody bool vhdx_checksum_is_valid(uint8_t *buf, size_t size, int crc_offset);
413e8d4e5ffSJeff Cody 
414b7cfc7d5SKevin Wolf int GRAPH_RDLOCK
415b7cfc7d5SKevin Wolf vhdx_parse_log(BlockDriverState *bs, BDRVVHDXState *s, bool *flushed,
4167e30e6a6SJeff Cody                Error **errp);
417e8d4e5ffSJeff Cody 
418f6b08994SPaolo Bonzini int coroutine_fn GRAPH_RDLOCK
419f6b08994SPaolo Bonzini vhdx_log_write_and_flush(BlockDriverState *bs, BDRVVHDXState *s,
4208adc5233SJeff Cody                          void *data, uint32_t length, uint64_t offset);
4218adc5233SJeff Cody 
leguid_to_cpus(MSGUID * guid)4224f18b782SJeff Cody static inline void leguid_to_cpus(MSGUID *guid)
423e8d4e5ffSJeff Cody {
4241229e46dSPeter Maydell     guid->data1 = le32_to_cpu(guid->data1);
4251229e46dSPeter Maydell     guid->data2 = le16_to_cpu(guid->data2);
4261229e46dSPeter Maydell     guid->data3 = le16_to_cpu(guid->data3);
427e8d4e5ffSJeff Cody }
428e8d4e5ffSJeff Cody 
cpu_to_leguids(MSGUID * guid)4294f18b782SJeff Cody static inline void cpu_to_leguids(MSGUID *guid)
4304f18b782SJeff Cody {
4311229e46dSPeter Maydell     guid->data1 = cpu_to_le32(guid->data1);
4321229e46dSPeter Maydell     guid->data2 = cpu_to_le16(guid->data2);
4331229e46dSPeter Maydell     guid->data3 = cpu_to_le16(guid->data3);
4344f18b782SJeff Cody }
4354f18b782SJeff Cody 
4360f48e8f0SJeff Cody void vhdx_header_le_import(VHDXHeader *h);
4370f48e8f0SJeff Cody void vhdx_header_le_export(VHDXHeader *orig_h, VHDXHeader *new_h);
4380f48e8f0SJeff Cody void vhdx_log_desc_le_import(VHDXLogDescriptor *d);
4390f48e8f0SJeff Cody void vhdx_log_desc_le_export(VHDXLogDescriptor *d);
4404f75b52aSJeff Cody void vhdx_log_data_le_import(VHDXLogDataSector *d);
4410f48e8f0SJeff Cody void vhdx_log_data_le_export(VHDXLogDataSector *d);
4420f48e8f0SJeff Cody void vhdx_log_entry_hdr_le_import(VHDXLogEntryHeader *hdr);
4430f48e8f0SJeff Cody void vhdx_log_entry_hdr_le_export(VHDXLogEntryHeader *hdr);
444c325ee1dSJeff Cody void vhdx_region_header_le_import(VHDXRegionTableHeader *hdr);
445c325ee1dSJeff Cody void vhdx_region_header_le_export(VHDXRegionTableHeader *hdr);
446c325ee1dSJeff Cody void vhdx_region_entry_le_import(VHDXRegionTableEntry *e);
447c325ee1dSJeff Cody void vhdx_region_entry_le_export(VHDXRegionTableEntry *e);
448c325ee1dSJeff Cody void vhdx_metadata_header_le_import(VHDXMetadataTableHeader *hdr);
449c325ee1dSJeff Cody void vhdx_metadata_header_le_export(VHDXMetadataTableHeader *hdr);
450c325ee1dSJeff Cody void vhdx_metadata_entry_le_import(VHDXMetadataTableEntry *e);
451c325ee1dSJeff Cody void vhdx_metadata_entry_le_export(VHDXMetadataTableEntry *e);
452*65ff757dSKevin Wolf 
453*65ff757dSKevin Wolf int GRAPH_RDLOCK
454*65ff757dSKevin Wolf vhdx_user_visible_write(BlockDriverState *bs, BDRVVHDXState *s);
455c3906c5eSJeff Cody 
456203cdba3SJeff Cody #endif
457