]> git.proxmox.com Git - mirror_qemu.git/blob - hw/cxl/cxl-cdat.c
Merge tag 'for_upstream' of https://git.kernel.org/pub/scm/virt/kvm/mst/qemu into...
[mirror_qemu.git] / hw / cxl / cxl-cdat.c
1 /*
2 * CXL CDAT Structure
3 *
4 * Copyright (C) 2021 Avery Design Systems, Inc.
5 *
6 * This work is licensed under the terms of the GNU GPL, version 2 or later.
7 * See the COPYING file in the top-level directory.
8 */
9
10 #include "qemu/osdep.h"
11 #include "hw/pci/pci.h"
12 #include "hw/cxl/cxl.h"
13 #include "qapi/error.h"
14 #include "qemu/error-report.h"
15
16 static void cdat_len_check(CDATSubHeader *hdr, Error **errp)
17 {
18 assert(hdr->length);
19 assert(hdr->reserved == 0);
20
21 switch (hdr->type) {
22 case CDAT_TYPE_DSMAS:
23 assert(hdr->length == sizeof(CDATDsmas));
24 break;
25 case CDAT_TYPE_DSLBIS:
26 assert(hdr->length == sizeof(CDATDslbis));
27 break;
28 case CDAT_TYPE_DSMSCIS:
29 assert(hdr->length == sizeof(CDATDsmscis));
30 break;
31 case CDAT_TYPE_DSIS:
32 assert(hdr->length == sizeof(CDATDsis));
33 break;
34 case CDAT_TYPE_DSEMTS:
35 assert(hdr->length == sizeof(CDATDsemts));
36 break;
37 case CDAT_TYPE_SSLBIS:
38 assert(hdr->length >= sizeof(CDATSslbisHeader));
39 assert((hdr->length - sizeof(CDATSslbisHeader)) %
40 sizeof(CDATSslbe) == 0);
41 break;
42 default:
43 error_setg(errp, "Type %d is reserved", hdr->type);
44 }
45 }
46
47 static void ct3_build_cdat(CDATObject *cdat, Error **errp)
48 {
49 g_autofree CDATTableHeader *cdat_header = NULL;
50 g_autofree CDATEntry *cdat_st = NULL;
51 uint8_t sum = 0;
52 int ent, i;
53
54 /* Use default table if fopen == NULL */
55 assert(cdat->build_cdat_table);
56
57 cdat_header = g_malloc0(sizeof(*cdat_header));
58 if (!cdat_header) {
59 error_setg(errp, "Failed to allocate CDAT header");
60 return;
61 }
62
63 cdat->built_buf_len = cdat->build_cdat_table(&cdat->built_buf, cdat->private);
64
65 if (!cdat->built_buf_len) {
66 /* Build later as not all data available yet */
67 cdat->to_update = true;
68 return;
69 }
70 cdat->to_update = false;
71
72 cdat_st = g_malloc0(sizeof(*cdat_st) * (cdat->built_buf_len + 1));
73 if (!cdat_st) {
74 error_setg(errp, "Failed to allocate CDAT entry array");
75 return;
76 }
77
78 /* Entry 0 for CDAT header, starts with Entry 1 */
79 for (ent = 1; ent < cdat->built_buf_len + 1; ent++) {
80 CDATSubHeader *hdr = cdat->built_buf[ent - 1];
81 uint8_t *buf = (uint8_t *)cdat->built_buf[ent - 1];
82
83 cdat_st[ent].base = hdr;
84 cdat_st[ent].length = hdr->length;
85
86 cdat_header->length += hdr->length;
87 for (i = 0; i < hdr->length; i++) {
88 sum += buf[i];
89 }
90 }
91
92 /* CDAT header */
93 cdat_header->revision = CXL_CDAT_REV;
94 /* For now, no runtime updates */
95 cdat_header->sequence = 0;
96 cdat_header->length += sizeof(CDATTableHeader);
97 sum += cdat_header->revision + cdat_header->sequence +
98 cdat_header->length;
99 /* Sum of all bytes including checksum must be 0 */
100 cdat_header->checksum = ~sum + 1;
101
102 cdat_st[0].base = g_steal_pointer(&cdat_header);
103 cdat_st[0].length = sizeof(*cdat_header);
104 cdat->entry_len = 1 + cdat->built_buf_len;
105 cdat->entry = g_steal_pointer(&cdat_st);
106 }
107
108 static void ct3_load_cdat(CDATObject *cdat, Error **errp)
109 {
110 g_autofree CDATEntry *cdat_st = NULL;
111 g_autofree char *buf = NULL;
112 uint8_t sum = 0;
113 int num_ent;
114 int i = 0, ent = 1;
115 gsize file_size = 0;
116 CDATSubHeader *hdr;
117 GError *error = NULL;
118
119 /* Read CDAT file and create its cache */
120 if (!g_file_get_contents(cdat->filename, (gchar **)&buf,
121 &file_size, &error)) {
122 error_setg(errp, "CDAT: File read failed: %s", error->message);
123 g_error_free(error);
124 return;
125 }
126 if (file_size < sizeof(CDATTableHeader)) {
127 error_setg(errp, "CDAT: File too short");
128 return;
129 }
130 i = sizeof(CDATTableHeader);
131 num_ent = 1;
132 while (i < file_size) {
133 hdr = (CDATSubHeader *)(buf + i);
134 if (i + sizeof(CDATSubHeader) > file_size) {
135 error_setg(errp, "CDAT: Truncated table");
136 return;
137 }
138 cdat_len_check(hdr, errp);
139 i += hdr->length;
140 if (i > file_size) {
141 error_setg(errp, "CDAT: Truncated table");
142 return;
143 }
144 num_ent++;
145 }
146 if (i != file_size) {
147 error_setg(errp, "CDAT: File length mismatch");
148 return;
149 }
150
151 cdat_st = g_new0(CDATEntry, num_ent);
152
153 /* Set CDAT header, Entry = 0 */
154 cdat_st[0].base = buf;
155 cdat_st[0].length = sizeof(CDATTableHeader);
156 i = 0;
157
158 while (i < cdat_st[0].length) {
159 sum += buf[i++];
160 }
161
162 /* Read CDAT structures */
163 while (i < file_size) {
164 hdr = (CDATSubHeader *)(buf + i);
165 cdat_st[ent].base = hdr;
166 cdat_st[ent].length = hdr->length;
167
168 while (buf + i < (char *)cdat_st[ent].base + cdat_st[ent].length) {
169 assert(i < file_size);
170 sum += buf[i++];
171 }
172
173 ent++;
174 }
175
176 if (sum != 0) {
177 warn_report("CDAT: Found checksum mismatch in %s", cdat->filename);
178 }
179 cdat->entry_len = num_ent;
180 cdat->entry = g_steal_pointer(&cdat_st);
181 cdat->buf = g_steal_pointer(&buf);
182 }
183
184 void cxl_doe_cdat_init(CXLComponentState *cxl_cstate, Error **errp)
185 {
186 CDATObject *cdat = &cxl_cstate->cdat;
187
188 if (cdat->filename) {
189 ct3_load_cdat(cdat, errp);
190 } else {
191 ct3_build_cdat(cdat, errp);
192 }
193 }
194
195 void cxl_doe_cdat_update(CXLComponentState *cxl_cstate, Error **errp)
196 {
197 CDATObject *cdat = &cxl_cstate->cdat;
198
199 if (cdat->to_update) {
200 ct3_build_cdat(cdat, errp);
201 }
202 }
203
204 void cxl_doe_cdat_release(CXLComponentState *cxl_cstate)
205 {
206 CDATObject *cdat = &cxl_cstate->cdat;
207
208 free(cdat->entry);
209 if (cdat->built_buf) {
210 cdat->free_cdat_table(cdat->built_buf, cdat->built_buf_len,
211 cdat->private);
212 }
213 g_free(cdat->buf);
214 }