xref: /openbmc/qemu/tests/unit/test-smp-parse.c (revision 3d28b844)
1 /*
2  * SMP parsing unit-tests
3  *
4  * Copyright (c) 2021 Huawei Technologies Co., Ltd
5  *
6  * Authors:
7  *  Yanan Wang <wangyanan55@huawei.com>
8  *
9  * This work is licensed under the terms of the GNU LGPL, version 2.1 or later.
10  * See the COPYING.LIB file in the top-level directory.
11  */
12 
13 #include "qemu/osdep.h"
14 #include "qom/object.h"
15 #include "qemu/module.h"
16 #include "qapi/error.h"
17 
18 #include "hw/boards.h"
19 
20 #define T true
21 #define F false
22 
23 #define MIN_CPUS 1    /* set the min CPUs supported by the machine as 1 */
24 #define MAX_CPUS 4096 /* set the max CPUs supported by the machine as 4096 */
25 
26 #define SMP_MACHINE_NAME "TEST-SMP"
27 
28 /*
29  * Used to define the generic 3-level CPU topology hierarchy
30  *  -sockets/cores/threads
31  */
32 #define SMP_CONFIG_GENERIC(ha, a, hb, b, hc, c, hd, d, he, e) \
33         {                                                     \
34             .has_cpus    = ha, .cpus    = a,                  \
35             .has_sockets = hb, .sockets = b,                  \
36             .has_cores   = hc, .cores   = c,                  \
37             .has_threads = hd, .threads = d,                  \
38             .has_maxcpus = he, .maxcpus = e,                  \
39         }
40 
41 #define CPU_TOPOLOGY_GENERIC(a, b, c, d, e)                   \
42         {                                                     \
43             .cpus     = a,                                    \
44             .sockets  = b,                                    \
45             .cores    = c,                                    \
46             .threads  = d,                                    \
47             .max_cpus = e,                                    \
48         }
49 
50 /*
51  * Currently a 5-level topology hierarchy is supported on PC machines
52  *  -sockets/dies/modules/cores/threads
53  */
54 #define SMP_CONFIG_WITH_MODS_DIES(ha, a, hb, b, hc, c, hd, d, \
55                                   he, e, hf, f, hg, g)        \
56         {                                                     \
57             .has_cpus    = ha, .cpus    = a,                  \
58             .has_sockets = hb, .sockets = b,                  \
59             .has_dies    = hc, .dies    = c,                  \
60             .has_modules = hd, .modules = d,                  \
61             .has_cores   = he, .cores   = e,                  \
62             .has_threads = hf, .threads = f,                  \
63             .has_maxcpus = hg, .maxcpus = g,                  \
64         }
65 
66 /*
67  * Currently a 4-level topology hierarchy is supported on ARM virt machines
68  *  -sockets/clusters/cores/threads
69  */
70 #define SMP_CONFIG_WITH_CLUSTERS(ha, a, hb, b, hc, c, hd, d, he, e, hf, f) \
71         {                                                     \
72             .has_cpus     = ha, .cpus     = a,                \
73             .has_sockets  = hb, .sockets  = b,                \
74             .has_clusters = hc, .clusters = c,                \
75             .has_cores    = hd, .cores    = d,                \
76             .has_threads  = he, .threads  = e,                \
77             .has_maxcpus  = hf, .maxcpus  = f,                \
78         }
79 
80 /*
81  * Currently a 5-level topology hierarchy is supported on s390 ccw machines
82  *  -drawers/books/sockets/cores/threads
83  */
84 #define SMP_CONFIG_WITH_BOOKS_DRAWERS(ha, a, hb, b, hc, c, hd, \
85                                       d, he, e, hf, f, hg, g)  \
86         {                                                      \
87             .has_cpus     = ha, .cpus     = a,                 \
88             .has_drawers  = hb, .drawers  = b,                 \
89             .has_books    = hc, .books    = c,                 \
90             .has_sockets  = hd, .sockets  = d,                 \
91             .has_cores    = he, .cores    = e,                 \
92             .has_threads  = hf, .threads  = f,                 \
93             .has_maxcpus  = hg, .maxcpus  = g,                 \
94         }
95 
96 /*
97  * Currently QEMU supports up to a 8-level topology hierarchy, which is the
98  * QEMU's unified abstract representation of CPU topology.
99  *  -drawers/books/sockets/dies/clusters/modules/cores/threads
100  */
101 #define SMP_CONFIG_WITH_FULL_TOPO(a, b, c, d, e, f, g, h, i, j) \
102         {                                                       \
103             .has_cpus     = true, .cpus     = a,                \
104             .has_drawers  = true, .drawers  = b,                \
105             .has_books    = true, .books    = c,                \
106             .has_sockets  = true, .sockets  = d,                \
107             .has_dies     = true, .dies     = e,                \
108             .has_clusters = true, .clusters = f,                \
109             .has_modules  = true, .modules  = g,                \
110             .has_cores    = true, .cores    = h,                \
111             .has_threads  = true, .threads  = i,                \
112             .has_maxcpus  = true, .maxcpus  = j,                \
113         }
114 
115 /**
116  * @config - the given SMP configuration
117  * @expect_prefer_sockets - the expected parsing result for the
118  * valid configuration, when sockets are preferred over cores
119  * @expect_prefer_cores - the expected parsing result for the
120  * valid configuration, when cores are preferred over sockets
121  * @expect_error - the expected error report when the given
122  * configuration is invalid
123  */
124 typedef struct SMPTestData {
125     SMPConfiguration config;
126     CpuTopology expect_prefer_sockets;
127     CpuTopology expect_prefer_cores;
128     const char *expect_error;
129 } SMPTestData;
130 
131 /*
132  * List all the possible valid sub-collections of the generic 5
133  * topology parameters (i.e. cpus/maxcpus/sockets/cores/threads),
134  * then test the automatic calculation algorithm of the missing
135  * values in the parser.
136  */
137 static const struct SMPTestData data_generic_valid[] = {
138     {
139         /* config: no configuration provided
140          * expect: cpus=1,sockets=1,cores=1,threads=1,maxcpus=1 */
141         .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, F, 0, F, 0),
142         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1),
143         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(1, 1, 1, 1, 1),
144     }, {
145         /* config: -smp 8
146          * prefer_sockets: cpus=8,sockets=8,cores=1,threads=1,maxcpus=8
147          * prefer_cores: cpus=8,sockets=1,cores=8,threads=1,maxcpus=8 */
148         .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, F, 0, F, 0),
149         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 8, 1, 1, 8),
150         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 1, 8, 1, 8),
151     }, {
152         /* config: -smp sockets=2
153          * expect: cpus=2,sockets=2,cores=1,threads=1,maxcpus=2 */
154         .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, F, 0, F, 0),
155         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2),
156         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(2, 2, 1, 1, 2),
157     }, {
158         /* config: -smp cores=4
159          * expect: cpus=4,sockets=1,cores=4,threads=1,maxcpus=4 */
160         .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, F, 0, F, 0),
161         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4),
162         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(4, 1, 4, 1, 4),
163     }, {
164         /* config: -smp threads=2
165          * expect: cpus=2,sockets=1,cores=1,threads=2,maxcpus=2 */
166         .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, T, 2, F, 0),
167         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2),
168         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(2, 1, 1, 2, 2),
169     }, {
170         /* config: -smp maxcpus=16
171          * prefer_sockets: cpus=16,sockets=16,cores=1,threads=1,maxcpus=16
172          * prefer_cores: cpus=16,sockets=1,cores=16,threads=1,maxcpus=16 */
173         .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, F, 0, T, 16),
174         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 16, 1, 1, 16),
175         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(16, 1, 16, 1, 16),
176     }, {
177         /* config: -smp 8,sockets=2
178          * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
179         .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, F, 0, F, 0),
180         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
181         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
182     }, {
183         /* config: -smp 8,cores=4
184          * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
185         .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, F, 0, F, 0),
186         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
187         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
188     }, {
189         /* config: -smp 8,threads=2
190          * prefer_sockets: cpus=8,sockets=4,cores=1,threads=2,maxcpus=8
191          * prefer_cores: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */
192         .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, T, 2, F, 0),
193         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 4, 1, 2, 8),
194         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
195     }, {
196         /* config: -smp 8,maxcpus=16
197          * prefer_sockets: cpus=8,sockets=16,cores=1,threads=1,maxcpus=16
198          * prefer_cores: cpus=8,sockets=1,cores=16,threads=1,maxcpus=16 */
199         .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, F, 0, T, 16),
200         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 16, 1, 1, 16),
201         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 1, 16, 1, 16),
202     }, {
203         /* config: -smp sockets=2,cores=4
204          * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
205         .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, F, 0, F, 0),
206         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
207         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
208     }, {
209         /* config: -smp sockets=2,threads=2
210          * expect: cpus=4,sockets=2,cores=1,threads=2,maxcpus=4 */
211         .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, T, 2, F, 0),
212         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4),
213         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(4, 2, 1, 2, 4),
214     }, {
215         /* config: -smp sockets=2,maxcpus=16
216          * expect: cpus=16,sockets=2,cores=8,threads=1,maxcpus=16 */
217         .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, F, 0, T, 16),
218         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16),
219         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(16, 2, 8, 1, 16),
220     }, {
221         /* config: -smp cores=4,threads=2
222          * expect: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */
223         .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, T, 2, F, 0),
224         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
225         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
226     }, {
227         /* config: -smp cores=4,maxcpus=16
228          * expect: cpus=16,sockets=4,cores=4,threads=1,maxcpus=16 */
229         .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, F, 0, T, 16),
230         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16),
231         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(16, 4, 4, 1, 16),
232     }, {
233         /* config: -smp threads=2,maxcpus=16
234          * prefer_sockets: cpus=16,sockets=8,cores=1,threads=2,maxcpus=16
235          * prefer_cores: cpus=16,sockets=1,cores=8,threads=2,maxcpus=16 */
236         .config = SMP_CONFIG_GENERIC(F, 0, F, 0, F, 0, T, 2, T, 16),
237         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 8, 1, 2, 16),
238         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(16, 1, 8, 2, 16),
239     }, {
240         /* config: -smp 8,sockets=2,cores=4
241          * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
242         .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, F, 0, F, 0),
243         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
244         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
245     }, {
246         /* config: -smp 8,sockets=2,threads=2
247          * expect: cpus=8,sockets=2,cores=2,threads=2,maxcpus=8 */
248         .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, T, 2, F, 0),
249         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8),
250         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8),
251     }, {
252         /* config: -smp 8,sockets=2,maxcpus=16
253          * expect: cpus=8,sockets=2,cores=8,threads=1,maxcpus=16 */
254         .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, F, 0, T, 16),
255         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16),
256         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 2, 8, 1, 16),
257     }, {
258         /* config: -smp 8,cores=4,threads=2
259          * expect: cpus=8,sockets=1,cores=4,threads=2,maxcpus=8 */
260         .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, T, 2, F, 0),
261         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
262         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 1, 4, 2, 8),
263     }, {
264         /* config: -smp 8,cores=4,maxcpus=16
265          * expect: cpus=8,sockets=4,cores=4,threads=1,maxcpus=16 */
266         .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, F, 0, T, 16),
267         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16),
268         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 4, 4, 1, 16),
269     }, {
270         /* config: -smp 8,threads=2,maxcpus=16
271          * prefer_sockets: cpus=8,sockets=8,cores=1,threads=2,maxcpus=16
272          * prefer_cores: cpus=8,sockets=1,cores=8,threads=2,maxcpus=16 */
273         .config = SMP_CONFIG_GENERIC(T, 8, F, 0, F, 0, T, 2, T, 16),
274         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 8, 1, 2, 16),
275         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 1, 8, 2, 16),
276     }, {
277         /* config: -smp sockets=2,cores=4,threads=2
278          * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
279         .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, T, 2, F, 0),
280         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
281         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
282     }, {
283         /* config: -smp sockets=2,cores=4,maxcpus=16
284          * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
285         .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, F, 0, T, 16),
286         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
287         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
288     }, {
289         /* config: -smp sockets=2,threads=2,maxcpus=16
290          * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
291         .config = SMP_CONFIG_GENERIC(F, 0, T, 2, F, 0, T, 2, T, 16),
292         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
293         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
294     }, {
295         /* config: -smp cores=4,threads=2,maxcpus=16
296          * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
297         .config = SMP_CONFIG_GENERIC(F, 0, F, 0, T, 4, T, 2, T, 16),
298         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
299         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
300     }, {
301         /* config: -smp 8,sockets=2,cores=4,threads=1
302          * expect: cpus=8,sockets=2,cores=4,threads=1,maxcpus=8 */
303         .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 1, F, 0),
304         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
305         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 2, 4, 1, 8),
306     }, {
307         /* config: -smp 8,sockets=2,cores=4,maxcpus=16
308          * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
309         .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, F, 0, T, 16),
310         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
311         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
312     }, {
313         /* config: -smp 8,sockets=2,threads=2,maxcpus=16
314          * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
315         .config = SMP_CONFIG_GENERIC(T, 8, T, 2, F, 0, T, 2, T, 16),
316         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
317         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
318     }, {
319         /* config: -smp 8,cores=4,threads=2,maxcpus=16
320          * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
321         .config = SMP_CONFIG_GENERIC(T, 8, F, 0, T, 4, T, 2, T, 16),
322         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
323         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
324     }, {
325         /* config: -smp sockets=2,cores=4,threads=2,maxcpus=16
326          * expect: cpus=16,sockets=2,cores=4,threads=2,maxcpus=16 */
327         .config = SMP_CONFIG_GENERIC(F, 0, T, 2, T, 4, T, 2, T, 16),
328         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
329         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(16, 2, 4, 2, 16),
330     }, {
331         /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=16
332          * expect: cpus=8,sockets=2,cores=4,threads=2,maxcpus=16 */
333         .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 16),
334         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
335         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 2, 4, 2, 16),
336     }, {
337         /*
338          * Unsupported parameters are always allowed to be set to '1'
339          * config:
340          *   -smp 8,drawers=1,books=1,sockets=2,dies=1,clusters=1,modules=1,\
341          *        cores=2,threads=2,maxcpus=8
342          * expect: cpus=8,sockets=2,cores=2,threads=2,maxcpus=8 */
343         .config = SMP_CONFIG_WITH_FULL_TOPO(8, 1, 1, 2, 1, 1, 1, 2, 2, 8),
344         .expect_prefer_sockets = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8),
345         .expect_prefer_cores   = CPU_TOPOLOGY_GENERIC(8, 2, 2, 2, 8),
346     },
347 };
348 
349 static const struct SMPTestData data_generic_invalid[] = {
350     {
351         /* config: -smp 2,modules=2 */
352         .config = SMP_CONFIG_WITH_MODS_DIES(T, 2, F, 0, F, 0, T, 2,
353                                             F, 0, F, 0, F, 0),
354         .expect_error = "modules > 1 not supported by this machine's CPU topology",
355     }, {
356         /* config: -smp 2,dies=2 */
357         .config = SMP_CONFIG_WITH_MODS_DIES(T, 2, F, 0, T, 2, F, 0,
358                                             F, 0, F, 0, F, 0),
359         .expect_error = "dies > 1 not supported by this machine's CPU topology",
360     }, {
361         /* config: -smp 2,clusters=2 */
362         .config = SMP_CONFIG_WITH_CLUSTERS(T, 2, F, 0, T, 2, F, 0, F, 0, F, 0),
363         .expect_error = "clusters > 1 not supported by this machine's CPU topology",
364     }, {
365         /* config: -smp 2,books=2 */
366         .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 2, F, 0, T, 2, F,
367                                                 0, F, 0, F, 0, F, 0),
368         .expect_error = "books > 1 not supported by this machine's CPU topology",
369     }, {
370         /* config: -smp 2,drawers=2 */
371         .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 2, T, 2, F, 0, F,
372                                                 0, F, 0, F, 0, F, 0),
373         .expect_error = "drawers > 1 not supported by this machine's CPU topology",
374     }, {
375         /* config: -smp 8,sockets=2,cores=4,threads=2,maxcpus=8 */
376         .config = SMP_CONFIG_GENERIC(T, 8, T, 2, T, 4, T, 2, T, 8),
377         .expect_error = "Invalid CPU topology: "
378                         "product of the hierarchy must match maxcpus: "
379                         "sockets (2) * cores (4) * threads (2) "
380                         "!= maxcpus (8)",
381     }, {
382         /* config: -smp 18,sockets=2,cores=4,threads=2,maxcpus=16 */
383         .config = SMP_CONFIG_GENERIC(T, 18, T, 2, T, 4, T, 2, T, 16),
384         .expect_error = "Invalid CPU topology: "
385                         "maxcpus must be equal to or greater than smp: "
386                         "sockets (2) * cores (4) * threads (2) "
387                         "== maxcpus (16) < smp_cpus (18)",
388     }, {
389         /*
390          * config: -smp 1
391          * The test machine should tweak the supported min CPUs to
392          * 2 (MIN_CPUS + 1) for testing.
393          */
394         .config = SMP_CONFIG_GENERIC(T, MIN_CPUS, F, 0, F, 0, F, 0, F, 0),
395         .expect_error = "Invalid SMP CPUs 1. The min CPUs supported "
396                         "by machine '" SMP_MACHINE_NAME "' is 2",
397     }, {
398         /*
399          * config: -smp 4096
400          * The test machine should tweak the supported max CPUs to
401          * 4095 (MAX_CPUS - 1) for testing.
402          */
403         .config = SMP_CONFIG_GENERIC(T, 4096, F, 0, F, 0, F, 0, F, 0),
404         .expect_error = "Invalid SMP CPUs 4096. The max CPUs supported "
405                         "by machine '" SMP_MACHINE_NAME "' is 4095",
406     },
407 };
408 
409 static const struct SMPTestData data_with_modules_invalid[] = {
410     {
411         /* config: -smp 16,sockets=2,modules=2,cores=4,threads=2,maxcpus=16 */
412         .config = SMP_CONFIG_WITH_MODS_DIES(T, 16, T, 2, F, 0, T, 2,
413                                             T, 4, T, 2, T, 16),
414         .expect_error = "Invalid CPU topology: "
415                         "product of the hierarchy must match maxcpus: "
416                         "sockets (2) * modules (2) * cores (4) * threads (2) "
417                         "!= maxcpus (16)",
418     }, {
419         /* config: -smp 34,sockets=2,modules=2,cores=4,threads=2,maxcpus=32 */
420         .config = SMP_CONFIG_WITH_MODS_DIES(T, 34, T, 2, F, 0, T, 2,
421                                             T, 4, T, 2, T, 32),
422         .expect_error = "Invalid CPU topology: "
423                         "maxcpus must be equal to or greater than smp: "
424                         "sockets (2) * modules (2) * cores (4) * threads (2) "
425                         "== maxcpus (32) < smp_cpus (34)",
426     },
427 };
428 
429 static const struct SMPTestData data_with_dies_invalid[] = {
430     {
431         /* config: -smp 16,sockets=2,dies=2,cores=4,threads=2,maxcpus=16 */
432         .config = SMP_CONFIG_WITH_MODS_DIES(T, 16, T, 2, T, 2, F, 0,
433                                             T, 4, T, 2, T, 16),
434         .expect_error = "Invalid CPU topology: "
435                         "product of the hierarchy must match maxcpus: "
436                         "sockets (2) * dies (2) * cores (4) * threads (2) "
437                         "!= maxcpus (16)",
438     }, {
439         /* config: -smp 34,sockets=2,dies=2,cores=4,threads=2,maxcpus=32 */
440         .config = SMP_CONFIG_WITH_MODS_DIES(T, 34, T, 2, T, 2, F, 0,
441                                             T, 4, T, 2, T, 32),
442         .expect_error = "Invalid CPU topology: "
443                         "maxcpus must be equal to or greater than smp: "
444                         "sockets (2) * dies (2) * cores (4) * threads (2) "
445                         "== maxcpus (32) < smp_cpus (34)",
446     },
447 };
448 
449 static const struct SMPTestData data_with_modules_dies_invalid[] = {
450     {
451         /*
452          * config: -smp 200,sockets=3,dies=5,modules=2,cores=4,\
453          * threads=2,maxcpus=200
454          */
455         .config = SMP_CONFIG_WITH_MODS_DIES(T, 200, T, 3, T, 5, T,
456                                             2, T, 4, T, 2, T, 200),
457         .expect_error = "Invalid CPU topology: "
458                         "product of the hierarchy must match maxcpus: "
459                         "sockets (3) * dies (5) * modules (2) * "
460                         "cores (4) * threads (2) != maxcpus (200)",
461     }, {
462         /*
463          * config: -smp 242,sockets=3,dies=5,modules=2,cores=4,\
464          * threads=2,maxcpus=240
465          */
466         .config = SMP_CONFIG_WITH_MODS_DIES(T, 242, T, 3, T, 5, T,
467                                             2, T, 4, T, 2, T, 240),
468         .expect_error = "Invalid CPU topology: "
469                         "maxcpus must be equal to or greater than smp: "
470                         "sockets (3) * dies (5) * modules (2) * "
471                         "cores (4) * threads (2) "
472                         "== maxcpus (240) < smp_cpus (242)",
473     },
474 };
475 
476 static const struct SMPTestData data_with_clusters_invalid[] = {
477     {
478         /* config: -smp 16,sockets=2,clusters=2,cores=4,threads=2,maxcpus=16 */
479         .config = SMP_CONFIG_WITH_CLUSTERS(T, 16, T, 2, T, 2, T, 4, T, 2, T, 16),
480         .expect_error = "Invalid CPU topology: "
481                         "product of the hierarchy must match maxcpus: "
482                         "sockets (2) * clusters (2) * cores (4) * threads (2) "
483                         "!= maxcpus (16)",
484     }, {
485         /* config: -smp 34,sockets=2,clusters=2,cores=4,threads=2,maxcpus=32 */
486         .config = SMP_CONFIG_WITH_CLUSTERS(T, 34, T, 2, T, 2, T, 4, T, 2, T, 32),
487         .expect_error = "Invalid CPU topology: "
488                         "maxcpus must be equal to or greater than smp: "
489                         "sockets (2) * clusters (2) * cores (4) * threads (2) "
490                         "== maxcpus (32) < smp_cpus (34)",
491     },
492 };
493 
494 static const struct SMPTestData data_with_books_invalid[] = {
495     {
496         /* config: -smp 16,books=2,sockets=2,cores=4,threads=2,maxcpus=16 */
497         .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 16, F, 0, T, 2, T,
498                                                 2, T, 4, T, 2, T, 16),
499         .expect_error = "Invalid CPU topology: "
500                         "product of the hierarchy must match maxcpus: "
501                         "books (2) * sockets (2) * cores (4) * threads (2) "
502                         "!= maxcpus (16)",
503     }, {
504         /* config: -smp 34,books=2,sockets=2,cores=4,threads=2,maxcpus=32 */
505         .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 34, F, 0, T, 2, T,
506                                                 2, T, 4, T, 2, T, 32),
507         .expect_error = "Invalid CPU topology: "
508                         "maxcpus must be equal to or greater than smp: "
509                         "books (2) * sockets (2) * cores (4) * threads (2) "
510                         "== maxcpus (32) < smp_cpus (34)",
511     },
512 };
513 
514 static const struct SMPTestData data_with_drawers_invalid[] = {
515     {
516         /* config: -smp 16,drawers=2,sockets=2,cores=4,threads=2,maxcpus=16 */
517         .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 16, T, 2, F, 0, T,
518                                                 2, T, 4, T, 2, T, 16),
519         .expect_error = "Invalid CPU topology: "
520                         "product of the hierarchy must match maxcpus: "
521                         "drawers (2) * sockets (2) * cores (4) * threads (2) "
522                         "!= maxcpus (16)",
523     }, {
524         /* config: -smp 34,drawers=2,sockets=2,cores=4,threads=2,maxcpus=32 */
525         .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 34, T, 2, F, 0, T,
526                                                 2, T, 4, T, 2, T, 32),
527         .expect_error = "Invalid CPU topology: "
528                         "maxcpus must be equal to or greater than smp: "
529                         "drawers (2) * sockets (2) * cores (4) * threads (2) "
530                         "== maxcpus (32) < smp_cpus (34)",
531     },
532 };
533 
534 static const struct SMPTestData data_with_drawers_books_invalid[] = {
535     {
536         /*
537          * config: -smp 200,drawers=3,books=5,sockets=2,cores=4,\
538          *              threads=2,maxcpus=200
539          */
540         .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 200, T, 3, T, 5, T,
541                                                 2, T, 4, T, 2, T, 200),
542         .expect_error = "Invalid CPU topology: "
543                         "product of the hierarchy must match maxcpus: "
544                         "drawers (3) * books (5) * sockets (2) * "
545                         "cores (4) * threads (2) != maxcpus (200)",
546     }, {
547         /*
548          * config: -smp 242,drawers=3,books=5,sockets=2,cores=4,\
549          *              threads=2,maxcpus=240
550          */
551         .config = SMP_CONFIG_WITH_BOOKS_DRAWERS(T, 242, T, 3, T, 5, T,
552                                                 2, T, 4, T, 2, T, 240),
553         .expect_error = "Invalid CPU topology: "
554                         "maxcpus must be equal to or greater than smp: "
555                         "drawers (3) * books (5) * sockets (2) * "
556                         "cores (4) * threads (2) "
557                         "== maxcpus (240) < smp_cpus (242)",
558     },
559 };
560 
561 static const struct SMPTestData data_full_topo_invalid[] = {
562     {
563         /*
564          * config: -smp 200,drawers=3,books=5,sockets=2,dies=4,\
565          *              clusters=2,modules=3,cores=7,threads=2,\
566          *              maxcpus=200
567          */
568         .config = SMP_CONFIG_WITH_FULL_TOPO(200, 3, 5, 2, 4, 2, 3, 7, 2, 200),
569         .expect_error = "Invalid CPU topology: "
570                         "product of the hierarchy must match maxcpus: "
571                         "drawers (3) * books (5) * sockets (2) * dies (4) * "
572                         "clusters (2) * modules (3) * cores (7) * threads (2) "
573                         "!= maxcpus (200)",
574     }, {
575         /*
576          * config: -smp 2881,drawers=3,books=5,sockets=2,dies=4,\
577          *              clusters=2,modules=3,cores=2,threads=2,
578          *              maxcpus=2880
579          */
580         .config = SMP_CONFIG_WITH_FULL_TOPO(2881, 3, 5, 2, 4,
581                                             2, 3, 2, 2, 2880),
582         .expect_error = "Invalid CPU topology: "
583                         "maxcpus must be equal to or greater than smp: "
584                         "drawers (3) * books (5) * sockets (2) * "
585                         "dies (4) * clusters (2) * modules (3) * "
586                         "cores (2) * threads (2) == maxcpus (2880) "
587                         "< smp_cpus (2881)",
588     }, {
589         /*
590          * config: -smp 1,drawers=3,books=5,sockets=2,dies=4,\
591          *              clusters=2,modules=3,cores=3,threads=3,\
592          *              maxcpus=6480
593          */
594         .config = SMP_CONFIG_WITH_FULL_TOPO(1, 3, 5, 2, 4, 2, 3, 3, 3, 6480),
595         .expect_error = "Invalid SMP CPUs 6480. The max CPUs supported "
596                         "by machine '" SMP_MACHINE_NAME "' is 4096",
597     },
598 };
599 
600 static const struct SMPTestData data_zero_topo_invalid[] = {
601     {
602         /*
603          * Test "cpus=0".
604          * config: -smp 0,drawers=1,books=1,sockets=1,dies=1,\
605          *              clusters=1,modules=1,cores=1,threads=1,\
606          *              maxcpus=1
607          */
608         .config = SMP_CONFIG_WITH_FULL_TOPO(0, 1, 1, 1, 1, 1, 1, 1, 1, 1),
609         .expect_error = "Invalid CPU topology: CPU topology parameters must "
610                         "be greater than zero",
611     }, {
612         /*
613          * Test "drawers=0".
614          * config: -smp 1,drawers=0,books=1,sockets=1,dies=1,\
615          *              clusters=1,modules=1,cores=1,threads=1,\
616          *              maxcpus=1
617          */
618         .config = SMP_CONFIG_WITH_FULL_TOPO(1, 0, 1, 1, 1, 1, 1, 1, 1, 1),
619         .expect_error = "Invalid CPU topology: CPU topology parameters must "
620                         "be greater than zero",
621     }, {
622         /*
623          * Test "books=0".
624          * config: -smp 1,drawers=1,books=0,sockets=1,dies=1,\
625          *              clusters=1,modules=1,cores=1,threads=1,\
626          *              maxcpus=1
627          */
628         .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 0, 1, 1, 1, 1, 1, 1, 1),
629         .expect_error = "Invalid CPU topology: CPU topology parameters must "
630                         "be greater than zero",
631     }, {
632         /*
633          * Test "sockets=0".
634          * config: -smp 1,drawers=1,books=1,sockets=0,dies=1,\
635          *              clusters=1,modules=1,cores=1,threads=1,
636          *              maxcpus=1
637          */
638         .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 0, 1, 1, 1, 1, 1, 1),
639         .expect_error = "Invalid CPU topology: CPU topology parameters must "
640                         "be greater than zero",
641     }, {
642         /*
643          * Test "dies=0".
644          * config: -smp 1,drawers=1,books=1,sockets=1,dies=0,\
645          *              clusters=1,modules=1,cores=1,threads=1,\
646          *              maxcpus=1
647          */
648         .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 0, 1, 1, 1, 1, 1),
649         .expect_error = "Invalid CPU topology: CPU topology parameters must "
650                         "be greater than zero",
651     }, {
652         /*
653          * Test "clusters=0".
654          * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\
655          *              clusters=0,modules=1,cores=1,threads=1,\
656          *              maxcpus=1
657          */
658         .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 0, 1, 1, 1, 1),
659         .expect_error = "Invalid CPU topology: CPU topology parameters must "
660                         "be greater than zero",
661     }, {
662         /*
663          * Test "modules=0".
664          * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\
665          *              clusters=1,modules=0,cores=1,threads=1,\
666          *              maxcpus=1
667          */
668         .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 1, 0, 1, 1, 1),
669         .expect_error = "Invalid CPU topology: CPU topology parameters must "
670                         "be greater than zero",
671     }, {
672         /*
673          * Test "cores=0".
674          * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\
675          *              clusters=1,modules=1,cores=0,threads=1,
676          *              maxcpus=1
677          */
678         .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 1, 1, 0, 1, 1),
679         .expect_error = "Invalid CPU topology: CPU topology parameters must "
680                         "be greater than zero",
681     }, {
682         /*
683          * Test "threads=0".
684          * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\
685          *              clusters=1,modules=1,cores=1,threads=0,\
686          *              maxcpus=1
687          */
688         .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 1, 1, 1, 0, 1),
689         .expect_error = "Invalid CPU topology: CPU topology parameters must "
690                         "be greater than zero",
691     }, {
692         /*
693          * Test "maxcpus=0".
694          * config: -smp 1,drawers=1,books=1,sockets=1,dies=1,\
695          *              clusters=1,modules=1,cores=1,threads=1,\
696          *              maxcpus=0
697          */
698         .config = SMP_CONFIG_WITH_FULL_TOPO(1, 1, 1, 1, 1, 1, 1, 1, 1, 0),
699         .expect_error = "Invalid CPU topology: CPU topology parameters must "
700                         "be greater than zero",
701     },
702 };
703 
704 static char *smp_config_to_string(const SMPConfiguration *config)
705 {
706     return g_strdup_printf(
707         "(SMPConfiguration) {\n"
708         "    .has_cpus     = %5s, cpus     = %" PRId64 ",\n"
709         "    .has_drawers  = %5s, drawers  = %" PRId64 ",\n"
710         "    .has_books    = %5s, books    = %" PRId64 ",\n"
711         "    .has_sockets  = %5s, sockets  = %" PRId64 ",\n"
712         "    .has_dies     = %5s, dies     = %" PRId64 ",\n"
713         "    .has_clusters = %5s, clusters = %" PRId64 ",\n"
714         "    .has_modules  = %5s, modules  = %" PRId64 ",\n"
715         "    .has_cores    = %5s, cores    = %" PRId64 ",\n"
716         "    .has_threads  = %5s, threads  = %" PRId64 ",\n"
717         "    .has_maxcpus  = %5s, maxcpus  = %" PRId64 ",\n"
718         "}",
719         config->has_cpus ? "true" : "false", config->cpus,
720         config->has_drawers ? "true" : "false", config->drawers,
721         config->has_books ? "true" : "false", config->books,
722         config->has_sockets ? "true" : "false", config->sockets,
723         config->has_dies ? "true" : "false", config->dies,
724         config->has_clusters ? "true" : "false", config->clusters,
725         config->has_modules ? "true" : "false", config->modules,
726         config->has_cores ? "true" : "false", config->cores,
727         config->has_threads ? "true" : "false", config->threads,
728         config->has_maxcpus ? "true" : "false", config->maxcpus);
729 }
730 
731 /* Use the different calculation than machine_topo_get_threads_per_socket(). */
732 static unsigned int cpu_topology_get_threads_per_socket(const CpuTopology *topo)
733 {
734     /* Check the divisor to avoid invalid topology examples causing SIGFPE. */
735     if (!topo->drawers || !topo->books || !topo->sockets) {
736         return 0;
737     } else {
738         return topo->max_cpus / topo->drawers / topo->books / topo->sockets;
739     }
740 }
741 
742 /* Use the different calculation than machine_topo_get_cores_per_socket(). */
743 static unsigned int cpu_topology_get_cores_per_socket(const CpuTopology *topo)
744 {
745     /* Check the divisor to avoid invalid topology examples causing SIGFPE. */
746     if (!topo->threads) {
747         return 0;
748     } else {
749         return cpu_topology_get_threads_per_socket(topo) / topo->threads;
750     }
751 }
752 
753 static char *cpu_topology_to_string(const CpuTopology *topo,
754                                     unsigned int threads_per_socket,
755                                     unsigned int cores_per_socket,
756                                     bool has_clusters)
757 {
758     return g_strdup_printf(
759         "(CpuTopology) {\n"
760         "    .cpus               = %u,\n"
761         "    .drawers            = %u,\n"
762         "    .books              = %u,\n"
763         "    .sockets            = %u,\n"
764         "    .dies               = %u,\n"
765         "    .clusters           = %u,\n"
766         "    .modules            = %u,\n"
767         "    .cores              = %u,\n"
768         "    .threads            = %u,\n"
769         "    .max_cpus           = %u,\n"
770         "    .threads_per_socket = %u,\n"
771         "    .cores_per_socket   = %u,\n"
772         "    .has_clusters       = %s,\n"
773         "}",
774         topo->cpus, topo->drawers, topo->books,
775         topo->sockets, topo->dies, topo->clusters,
776         topo->modules, topo->cores, topo->threads,
777         topo->max_cpus, threads_per_socket, cores_per_socket,
778         has_clusters ? "true" : "false");
779 }
780 
781 static void check_parse(MachineState *ms, const SMPConfiguration *config,
782                         const CpuTopology *expect_topo, const char *expect_err,
783                         bool is_valid)
784 {
785     MachineClass *mc = MACHINE_GET_CLASS(ms);
786     g_autofree char *config_str = smp_config_to_string(config);
787     g_autofree char *expect_topo_str = NULL, *output_topo_str = NULL;
788     unsigned int expect_threads_per_socket, expect_cores_per_socket;
789     unsigned int ms_threads_per_socket, ms_cores_per_socket;
790     Error *err = NULL;
791 
792     expect_threads_per_socket =
793                         cpu_topology_get_threads_per_socket(expect_topo);
794     expect_cores_per_socket =
795                         cpu_topology_get_cores_per_socket(expect_topo);
796     expect_topo_str = cpu_topology_to_string(expect_topo,
797                                              expect_threads_per_socket,
798                                              expect_cores_per_socket,
799                                              config->has_clusters);
800 
801     /* call the generic parser */
802     machine_parse_smp_config(ms, config, &err);
803 
804     ms_threads_per_socket = machine_topo_get_threads_per_socket(ms);
805     ms_cores_per_socket = machine_topo_get_cores_per_socket(ms);
806     output_topo_str = cpu_topology_to_string(&ms->smp,
807                                              ms_threads_per_socket,
808                                              ms_cores_per_socket,
809                                              mc->smp_props.has_clusters);
810 
811     /* when the configuration is supposed to be valid */
812     if (is_valid) {
813         if ((err == NULL) &&
814             (ms->smp.cpus == expect_topo->cpus) &&
815             (ms->smp.drawers == expect_topo->drawers) &&
816             (ms->smp.books == expect_topo->books) &&
817             (ms->smp.sockets == expect_topo->sockets) &&
818             (ms->smp.dies == expect_topo->dies) &&
819             (ms->smp.clusters == expect_topo->clusters) &&
820             (ms->smp.modules == expect_topo->modules) &&
821             (ms->smp.cores == expect_topo->cores) &&
822             (ms->smp.threads == expect_topo->threads) &&
823             (ms->smp.max_cpus == expect_topo->max_cpus) &&
824             (ms_threads_per_socket == expect_threads_per_socket) &&
825             (ms_cores_per_socket == expect_cores_per_socket) &&
826             (mc->smp_props.has_clusters == config->has_clusters)) {
827             return;
828         }
829 
830         if (err != NULL) {
831             g_printerr("Test smp_parse failed!\n"
832                        "Input configuration: %s\n"
833                        "Should be valid: yes\n"
834                        "Expected topology: %s\n\n"
835                        "Result is valid: no\n"
836                        "Output error report: %s\n",
837                        config_str, expect_topo_str, error_get_pretty(err));
838             goto end;
839         }
840 
841         g_printerr("Test smp_parse failed!\n"
842                    "Input configuration: %s\n"
843                    "Should be valid: yes\n"
844                    "Expected topology: %s\n\n"
845                    "Result is valid: yes\n"
846                    "Output topology: %s\n",
847                    config_str, expect_topo_str, output_topo_str);
848         goto end;
849     }
850 
851     /* when the configuration is supposed to be invalid */
852     if (err != NULL) {
853         if (expect_err == NULL ||
854             g_str_equal(expect_err, error_get_pretty(err))) {
855             error_free(err);
856             return;
857         }
858 
859         g_printerr("Test smp_parse failed!\n"
860                    "Input configuration: %s\n"
861                    "Should be valid: no\n"
862                    "Expected error report: %s\n\n"
863                    "Result is valid: no\n"
864                    "Output error report: %s\n",
865                    config_str, expect_err, error_get_pretty(err));
866         goto end;
867     }
868 
869     g_printerr("Test smp_parse failed!\n"
870                "Input configuration: %s\n"
871                "Should be valid: no\n"
872                "Expected error report: %s\n\n"
873                "Result is valid: yes\n"
874                "Output topology: %s\n",
875                config_str, expect_err, output_topo_str);
876 
877 end:
878     if (err != NULL) {
879         error_free(err);
880     }
881 
882     abort();
883 }
884 
885 static void smp_parse_test(MachineState *ms, SMPTestData *data, bool is_valid)
886 {
887     MachineClass *mc = MACHINE_GET_CLASS(ms);
888 
889     mc->smp_props.prefer_sockets = true;
890     check_parse(ms, &data->config, &data->expect_prefer_sockets,
891                 data->expect_error, is_valid);
892 
893     mc->smp_props.prefer_sockets = false;
894     check_parse(ms, &data->config, &data->expect_prefer_cores,
895                 data->expect_error, is_valid);
896 }
897 
898 /* The parsed results of the unsupported parameters should be 1 */
899 static void unsupported_params_init(const MachineClass *mc, SMPTestData *data)
900 {
901     if (!mc->smp_props.modules_supported) {
902         data->expect_prefer_sockets.modules = 1;
903         data->expect_prefer_cores.modules = 1;
904     }
905 
906     if (!mc->smp_props.dies_supported) {
907         data->expect_prefer_sockets.dies = 1;
908         data->expect_prefer_cores.dies = 1;
909     }
910 
911     if (!mc->smp_props.clusters_supported) {
912         data->expect_prefer_sockets.clusters = 1;
913         data->expect_prefer_cores.clusters = 1;
914     }
915 
916     if (!mc->smp_props.books_supported) {
917         data->expect_prefer_sockets.books = 1;
918         data->expect_prefer_cores.books = 1;
919     }
920 
921     if (!mc->smp_props.drawers_supported) {
922         data->expect_prefer_sockets.drawers = 1;
923         data->expect_prefer_cores.drawers = 1;
924     }
925 }
926 
927 static void machine_base_class_init(ObjectClass *oc, void *data)
928 {
929     MachineClass *mc = MACHINE_CLASS(oc);
930 
931     mc->min_cpus = MIN_CPUS;
932     mc->max_cpus = MAX_CPUS;
933 
934     mc->name = g_strdup(SMP_MACHINE_NAME);
935 }
936 
937 static void machine_generic_invalid_class_init(ObjectClass *oc, void *data)
938 {
939     MachineClass *mc = MACHINE_CLASS(oc);
940 
941     /* Force invalid min CPUs and max CPUs */
942     mc->min_cpus = MIN_CPUS + 1;
943     mc->max_cpus = MAX_CPUS - 1;
944 }
945 
946 static void machine_with_modules_class_init(ObjectClass *oc, void *data)
947 {
948     MachineClass *mc = MACHINE_CLASS(oc);
949 
950     mc->smp_props.modules_supported = true;
951 }
952 
953 static void machine_with_dies_class_init(ObjectClass *oc, void *data)
954 {
955     MachineClass *mc = MACHINE_CLASS(oc);
956 
957     mc->smp_props.dies_supported = true;
958 }
959 
960 static void machine_with_modules_dies_class_init(ObjectClass *oc, void *data)
961 {
962     MachineClass *mc = MACHINE_CLASS(oc);
963 
964     mc->smp_props.modules_supported = true;
965     mc->smp_props.dies_supported = true;
966 }
967 
968 static void machine_with_clusters_class_init(ObjectClass *oc, void *data)
969 {
970     MachineClass *mc = MACHINE_CLASS(oc);
971 
972     mc->smp_props.clusters_supported = true;
973 }
974 
975 static void machine_with_books_class_init(ObjectClass *oc, void *data)
976 {
977     MachineClass *mc = MACHINE_CLASS(oc);
978 
979     mc->smp_props.books_supported = true;
980 }
981 
982 static void machine_with_drawers_class_init(ObjectClass *oc, void *data)
983 {
984     MachineClass *mc = MACHINE_CLASS(oc);
985 
986     mc->smp_props.drawers_supported = true;
987 }
988 
989 static void machine_with_drawers_books_class_init(ObjectClass *oc, void *data)
990 {
991     MachineClass *mc = MACHINE_CLASS(oc);
992 
993     mc->smp_props.drawers_supported = true;
994     mc->smp_props.books_supported = true;
995 }
996 
997 static void machine_full_topo_class_init(ObjectClass *oc, void *data)
998 {
999     MachineClass *mc = MACHINE_CLASS(oc);
1000 
1001     mc->smp_props.drawers_supported = true;
1002     mc->smp_props.books_supported = true;
1003     mc->smp_props.dies_supported = true;
1004     mc->smp_props.clusters_supported = true;
1005     mc->smp_props.modules_supported = true;
1006 }
1007 
1008 static void test_generic_valid(const void *opaque)
1009 {
1010     const char *machine_type = opaque;
1011     Object *obj = object_new(machine_type);
1012     MachineState *ms = MACHINE(obj);
1013     MachineClass *mc = MACHINE_GET_CLASS(obj);
1014     SMPTestData data = {};
1015     int i;
1016 
1017     for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1018         data = data_generic_valid[i];
1019         unsupported_params_init(mc, &data);
1020 
1021         smp_parse_test(ms, &data, true);
1022     }
1023 
1024     object_unref(obj);
1025 }
1026 
1027 static void test_generic_invalid(const void *opaque)
1028 {
1029     const char *machine_type = opaque;
1030     Object *obj = object_new(machine_type);
1031     MachineState *ms = MACHINE(obj);
1032     MachineClass *mc = MACHINE_GET_CLASS(obj);
1033     SMPTestData data = {};
1034     int i;
1035 
1036     for (i = 0; i < ARRAY_SIZE(data_generic_invalid); i++) {
1037         data = data_generic_invalid[i];
1038         unsupported_params_init(mc, &data);
1039 
1040         smp_parse_test(ms, &data, false);
1041     }
1042 
1043     object_unref(obj);
1044 }
1045 
1046 static void test_with_modules(const void *opaque)
1047 {
1048     const char *machine_type = opaque;
1049     Object *obj = object_new(machine_type);
1050     MachineState *ms = MACHINE(obj);
1051     MachineClass *mc = MACHINE_GET_CLASS(obj);
1052     SMPTestData data = {};
1053     unsigned int num_modules = 2;
1054     int i;
1055 
1056     for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1057         data = data_generic_valid[i];
1058         unsupported_params_init(mc, &data);
1059 
1060         /* when modules parameter is omitted, it will be set as 1 */
1061         data.expect_prefer_sockets.modules = 1;
1062         data.expect_prefer_cores.modules = 1;
1063 
1064         smp_parse_test(ms, &data, true);
1065 
1066         /* when modules parameter is specified */
1067         data.config.has_modules = true;
1068         data.config.modules = num_modules;
1069         if (data.config.has_cpus) {
1070             data.config.cpus *= num_modules;
1071         }
1072         if (data.config.has_maxcpus) {
1073             data.config.maxcpus *= num_modules;
1074         }
1075 
1076         data.expect_prefer_sockets.modules = num_modules;
1077         data.expect_prefer_sockets.cpus *= num_modules;
1078         data.expect_prefer_sockets.max_cpus *= num_modules;
1079         data.expect_prefer_cores.modules = num_modules;
1080         data.expect_prefer_cores.cpus *= num_modules;
1081         data.expect_prefer_cores.max_cpus *= num_modules;
1082 
1083         smp_parse_test(ms, &data, true);
1084     }
1085 
1086     for (i = 0; i < ARRAY_SIZE(data_with_modules_invalid); i++) {
1087         data = data_with_modules_invalid[i];
1088         unsupported_params_init(mc, &data);
1089 
1090         smp_parse_test(ms, &data, false);
1091     }
1092 
1093     object_unref(obj);
1094 }
1095 
1096 static void test_with_dies(const void *opaque)
1097 {
1098     const char *machine_type = opaque;
1099     Object *obj = object_new(machine_type);
1100     MachineState *ms = MACHINE(obj);
1101     MachineClass *mc = MACHINE_GET_CLASS(obj);
1102     SMPTestData data = {};
1103     unsigned int num_dies = 2;
1104     int i;
1105 
1106     for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1107         data = data_generic_valid[i];
1108         unsupported_params_init(mc, &data);
1109 
1110         /* when dies parameter is omitted, it will be set as 1 */
1111         data.expect_prefer_sockets.dies = 1;
1112         data.expect_prefer_cores.dies = 1;
1113 
1114         smp_parse_test(ms, &data, true);
1115 
1116         /* when dies parameter is specified */
1117         data.config.has_dies = true;
1118         data.config.dies = num_dies;
1119         if (data.config.has_cpus) {
1120             data.config.cpus *= num_dies;
1121         }
1122         if (data.config.has_maxcpus) {
1123             data.config.maxcpus *= num_dies;
1124         }
1125 
1126         data.expect_prefer_sockets.dies = num_dies;
1127         data.expect_prefer_sockets.cpus *= num_dies;
1128         data.expect_prefer_sockets.max_cpus *= num_dies;
1129         data.expect_prefer_cores.dies = num_dies;
1130         data.expect_prefer_cores.cpus *= num_dies;
1131         data.expect_prefer_cores.max_cpus *= num_dies;
1132 
1133         smp_parse_test(ms, &data, true);
1134     }
1135 
1136     for (i = 0; i < ARRAY_SIZE(data_with_dies_invalid); i++) {
1137         data = data_with_dies_invalid[i];
1138         unsupported_params_init(mc, &data);
1139 
1140         smp_parse_test(ms, &data, false);
1141     }
1142 
1143     object_unref(obj);
1144 }
1145 
1146 static void test_with_modules_dies(const void *opaque)
1147 {
1148     const char *machine_type = opaque;
1149     Object *obj = object_new(machine_type);
1150     MachineState *ms = MACHINE(obj);
1151     MachineClass *mc = MACHINE_GET_CLASS(obj);
1152     SMPTestData data = {};
1153     unsigned int num_modules = 5, num_dies = 3;
1154     int i;
1155 
1156     for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1157         data = data_generic_valid[i];
1158         unsupported_params_init(mc, &data);
1159 
1160         /*
1161          * when modules and dies parameters are omitted, they will
1162          * be both set as 1.
1163          */
1164         data.expect_prefer_sockets.modules = 1;
1165         data.expect_prefer_sockets.dies = 1;
1166         data.expect_prefer_cores.modules = 1;
1167         data.expect_prefer_cores.dies = 1;
1168 
1169         smp_parse_test(ms, &data, true);
1170 
1171         /* when modules and dies parameters are both specified */
1172         data.config.has_modules = true;
1173         data.config.modules = num_modules;
1174         data.config.has_dies = true;
1175         data.config.dies = num_dies;
1176 
1177         if (data.config.has_cpus) {
1178             data.config.cpus *= num_modules * num_dies;
1179         }
1180         if (data.config.has_maxcpus) {
1181             data.config.maxcpus *= num_modules * num_dies;
1182         }
1183 
1184         data.expect_prefer_sockets.modules = num_modules;
1185         data.expect_prefer_sockets.dies = num_dies;
1186         data.expect_prefer_sockets.cpus *= num_modules * num_dies;
1187         data.expect_prefer_sockets.max_cpus *= num_modules * num_dies;
1188 
1189         data.expect_prefer_cores.modules = num_modules;
1190         data.expect_prefer_cores.dies = num_dies;
1191         data.expect_prefer_cores.cpus *= num_modules * num_dies;
1192         data.expect_prefer_cores.max_cpus *= num_modules * num_dies;
1193 
1194         smp_parse_test(ms, &data, true);
1195     }
1196 
1197     for (i = 0; i < ARRAY_SIZE(data_with_modules_dies_invalid); i++) {
1198         data = data_with_modules_dies_invalid[i];
1199         unsupported_params_init(mc, &data);
1200 
1201         smp_parse_test(ms, &data, false);
1202     }
1203 
1204     object_unref(obj);
1205 }
1206 
1207 static void test_with_clusters(const void *opaque)
1208 {
1209     const char *machine_type = opaque;
1210     Object *obj = object_new(machine_type);
1211     MachineState *ms = MACHINE(obj);
1212     MachineClass *mc = MACHINE_GET_CLASS(obj);
1213     SMPTestData data = {};
1214     unsigned int num_clusters = 2;
1215     int i;
1216 
1217     for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1218         data = data_generic_valid[i];
1219         unsupported_params_init(mc, &data);
1220 
1221         /* when clusters parameter is omitted, it will be set as 1 */
1222         data.expect_prefer_sockets.clusters = 1;
1223         data.expect_prefer_cores.clusters = 1;
1224 
1225         smp_parse_test(ms, &data, true);
1226 
1227         /* when clusters parameter is specified */
1228         data.config.has_clusters = true;
1229         data.config.clusters = num_clusters;
1230         if (data.config.has_cpus) {
1231             data.config.cpus *= num_clusters;
1232         }
1233         if (data.config.has_maxcpus) {
1234             data.config.maxcpus *= num_clusters;
1235         }
1236 
1237         data.expect_prefer_sockets.clusters = num_clusters;
1238         data.expect_prefer_sockets.cpus *= num_clusters;
1239         data.expect_prefer_sockets.max_cpus *= num_clusters;
1240         data.expect_prefer_cores.clusters = num_clusters;
1241         data.expect_prefer_cores.cpus *= num_clusters;
1242         data.expect_prefer_cores.max_cpus *= num_clusters;
1243 
1244         smp_parse_test(ms, &data, true);
1245     }
1246 
1247     for (i = 0; i < ARRAY_SIZE(data_with_clusters_invalid); i++) {
1248         data = data_with_clusters_invalid[i];
1249         unsupported_params_init(mc, &data);
1250 
1251         smp_parse_test(ms, &data, false);
1252     }
1253 
1254     object_unref(obj);
1255 }
1256 
1257 static void test_with_books(const void *opaque)
1258 {
1259     const char *machine_type = opaque;
1260     Object *obj = object_new(machine_type);
1261     MachineState *ms = MACHINE(obj);
1262     MachineClass *mc = MACHINE_GET_CLASS(obj);
1263     SMPTestData data = {};
1264     unsigned int num_books = 2;
1265     int i;
1266 
1267     for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1268         data = data_generic_valid[i];
1269         unsupported_params_init(mc, &data);
1270 
1271         /* when books parameter is omitted, it will be set as 1 */
1272         data.expect_prefer_sockets.books = 1;
1273         data.expect_prefer_cores.books = 1;
1274 
1275         smp_parse_test(ms, &data, true);
1276 
1277         /* when books parameter is specified */
1278         data.config.has_books = true;
1279         data.config.books = num_books;
1280         if (data.config.has_cpus) {
1281             data.config.cpus *= num_books;
1282         }
1283         if (data.config.has_maxcpus) {
1284             data.config.maxcpus *= num_books;
1285         }
1286 
1287         data.expect_prefer_sockets.books = num_books;
1288         data.expect_prefer_sockets.cpus *= num_books;
1289         data.expect_prefer_sockets.max_cpus *= num_books;
1290         data.expect_prefer_cores.books = num_books;
1291         data.expect_prefer_cores.cpus *= num_books;
1292         data.expect_prefer_cores.max_cpus *= num_books;
1293 
1294         smp_parse_test(ms, &data, true);
1295     }
1296 
1297     for (i = 0; i < ARRAY_SIZE(data_with_books_invalid); i++) {
1298         data = data_with_books_invalid[i];
1299         unsupported_params_init(mc, &data);
1300 
1301         smp_parse_test(ms, &data, false);
1302     }
1303 
1304     object_unref(obj);
1305 }
1306 
1307 static void test_with_drawers(const void *opaque)
1308 {
1309     const char *machine_type = opaque;
1310     Object *obj = object_new(machine_type);
1311     MachineState *ms = MACHINE(obj);
1312     MachineClass *mc = MACHINE_GET_CLASS(obj);
1313     SMPTestData data = {};
1314     unsigned int num_drawers = 2;
1315     int i;
1316 
1317     for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1318         data = data_generic_valid[i];
1319         unsupported_params_init(mc, &data);
1320 
1321         /* when drawers parameter is omitted, it will be set as 1 */
1322         data.expect_prefer_sockets.drawers = 1;
1323         data.expect_prefer_cores.drawers = 1;
1324 
1325         smp_parse_test(ms, &data, true);
1326 
1327         /* when drawers parameter is specified */
1328         data.config.has_drawers = true;
1329         data.config.drawers = num_drawers;
1330         if (data.config.has_cpus) {
1331             data.config.cpus *= num_drawers;
1332         }
1333         if (data.config.has_maxcpus) {
1334             data.config.maxcpus *= num_drawers;
1335         }
1336 
1337         data.expect_prefer_sockets.drawers = num_drawers;
1338         data.expect_prefer_sockets.cpus *= num_drawers;
1339         data.expect_prefer_sockets.max_cpus *= num_drawers;
1340         data.expect_prefer_cores.drawers = num_drawers;
1341         data.expect_prefer_cores.cpus *= num_drawers;
1342         data.expect_prefer_cores.max_cpus *= num_drawers;
1343 
1344         smp_parse_test(ms, &data, true);
1345     }
1346 
1347     for (i = 0; i < ARRAY_SIZE(data_with_drawers_invalid); i++) {
1348         data = data_with_drawers_invalid[i];
1349         unsupported_params_init(mc, &data);
1350 
1351         smp_parse_test(ms, &data, false);
1352     }
1353 
1354     object_unref(obj);
1355 }
1356 
1357 static void test_with_drawers_books(const void *opaque)
1358 {
1359     const char *machine_type = opaque;
1360     Object *obj = object_new(machine_type);
1361     MachineState *ms = MACHINE(obj);
1362     MachineClass *mc = MACHINE_GET_CLASS(obj);
1363     SMPTestData data = {};
1364     unsigned int num_drawers = 5, num_books = 3;
1365     int i;
1366 
1367     for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1368         data = data_generic_valid[i];
1369         unsupported_params_init(mc, &data);
1370 
1371         /*
1372          * when drawers and books parameters are omitted, they will
1373          * be both set as 1.
1374          */
1375         data.expect_prefer_sockets.drawers = 1;
1376         data.expect_prefer_sockets.books = 1;
1377         data.expect_prefer_cores.drawers = 1;
1378         data.expect_prefer_cores.books = 1;
1379 
1380         smp_parse_test(ms, &data, true);
1381 
1382         /* when drawers and books parameters are both specified */
1383         data.config.has_drawers = true;
1384         data.config.drawers = num_drawers;
1385         data.config.has_books = true;
1386         data.config.books = num_books;
1387 
1388         if (data.config.has_cpus) {
1389             data.config.cpus *= num_drawers * num_books;
1390         }
1391         if (data.config.has_maxcpus) {
1392             data.config.maxcpus *= num_drawers * num_books;
1393         }
1394 
1395         data.expect_prefer_sockets.drawers = num_drawers;
1396         data.expect_prefer_sockets.books = num_books;
1397         data.expect_prefer_sockets.cpus *= num_drawers * num_books;
1398         data.expect_prefer_sockets.max_cpus *= num_drawers * num_books;
1399 
1400         data.expect_prefer_cores.drawers = num_drawers;
1401         data.expect_prefer_cores.books = num_books;
1402         data.expect_prefer_cores.cpus *= num_drawers * num_books;
1403         data.expect_prefer_cores.max_cpus *= num_drawers * num_books;
1404 
1405         smp_parse_test(ms, &data, true);
1406     }
1407 
1408     for (i = 0; i < ARRAY_SIZE(data_with_drawers_books_invalid); i++) {
1409         data = data_with_drawers_books_invalid[i];
1410         unsupported_params_init(mc, &data);
1411 
1412         smp_parse_test(ms, &data, false);
1413     }
1414 
1415     object_unref(obj);
1416 }
1417 
1418 static void test_full_topo(const void *opaque)
1419 {
1420     const char *machine_type = opaque;
1421     Object *obj = object_new(machine_type);
1422     MachineState *ms = MACHINE(obj);
1423     MachineClass *mc = MACHINE_GET_CLASS(obj);
1424     SMPTestData data = {};
1425     unsigned int drawers, books, dies, clusters, modules, multiplier;
1426     int i;
1427 
1428     drawers = 5;
1429     books = 3;
1430     dies = 2;
1431     clusters = 3;
1432     modules = 2;
1433 
1434     multiplier = drawers * books * dies * clusters * modules;
1435     for (i = 0; i < ARRAY_SIZE(data_generic_valid); i++) {
1436         data = data_generic_valid[i];
1437         unsupported_params_init(mc, &data);
1438 
1439         /*
1440          * when drawers, books, dies, clusters and modules parameters are
1441          * omitted, they will be set as 1.
1442          */
1443         data.expect_prefer_sockets.drawers = 1;
1444         data.expect_prefer_sockets.books = 1;
1445         data.expect_prefer_sockets.dies = 1;
1446         data.expect_prefer_sockets.clusters = 1;
1447         data.expect_prefer_sockets.modules = 1;
1448         data.expect_prefer_cores.drawers = 1;
1449         data.expect_prefer_cores.books = 1;
1450         data.expect_prefer_cores.dies = 1;
1451         data.expect_prefer_cores.clusters = 1;
1452         data.expect_prefer_cores.modules = 1;
1453 
1454         smp_parse_test(ms, &data, true);
1455 
1456         /*
1457          * when drawers, books, dies, clusters and modules parameters
1458          * are specified.
1459          */
1460         data.config.has_drawers = true;
1461         data.config.drawers = drawers;
1462         data.config.has_books = true;
1463         data.config.books = books;
1464         data.config.has_dies = true;
1465         data.config.dies = dies;
1466         data.config.has_clusters = true;
1467         data.config.clusters = clusters;
1468         data.config.has_modules = true;
1469         data.config.modules = modules;
1470 
1471         if (data.config.has_cpus) {
1472             data.config.cpus *= multiplier;
1473         }
1474         if (data.config.has_maxcpus) {
1475             data.config.maxcpus *= multiplier;
1476         }
1477 
1478         data.expect_prefer_sockets.drawers = drawers;
1479         data.expect_prefer_sockets.books = books;
1480         data.expect_prefer_sockets.dies = dies;
1481         data.expect_prefer_sockets.clusters = clusters;
1482         data.expect_prefer_sockets.modules = modules;
1483         data.expect_prefer_sockets.cpus *= multiplier;
1484         data.expect_prefer_sockets.max_cpus *= multiplier;
1485 
1486         data.expect_prefer_cores.drawers = drawers;
1487         data.expect_prefer_cores.books = books;
1488         data.expect_prefer_cores.dies = dies;
1489         data.expect_prefer_cores.clusters = clusters;
1490         data.expect_prefer_cores.modules = modules;
1491         data.expect_prefer_cores.cpus *= multiplier;
1492         data.expect_prefer_cores.max_cpus *= multiplier;
1493 
1494         smp_parse_test(ms, &data, true);
1495     }
1496 
1497     for (i = 0; i < ARRAY_SIZE(data_full_topo_invalid); i++) {
1498         data = data_full_topo_invalid[i];
1499         unsupported_params_init(mc, &data);
1500 
1501         smp_parse_test(ms, &data, false);
1502     }
1503 
1504     for (i = 0; i < ARRAY_SIZE(data_zero_topo_invalid); i++) {
1505         data = data_zero_topo_invalid[i];
1506         unsupported_params_init(mc, &data);
1507 
1508         smp_parse_test(ms, &data, false);
1509     }
1510 
1511     object_unref(obj);
1512 }
1513 
1514 /* Type info of the tested machine */
1515 static const TypeInfo smp_machine_types[] = {
1516     {
1517         .name           = TYPE_MACHINE,
1518         .parent         = TYPE_OBJECT,
1519         .abstract       = true,
1520         .class_init     = machine_base_class_init,
1521         .class_size     = sizeof(MachineClass),
1522         .instance_size  = sizeof(MachineState),
1523     }, {
1524         .name           = MACHINE_TYPE_NAME("smp-generic-valid"),
1525         .parent         = TYPE_MACHINE,
1526     }, {
1527         .name           = MACHINE_TYPE_NAME("smp-generic-invalid"),
1528         .parent         = TYPE_MACHINE,
1529         .class_init     = machine_generic_invalid_class_init,
1530     }, {
1531         .name           = MACHINE_TYPE_NAME("smp-with-modules"),
1532         .parent         = TYPE_MACHINE,
1533         .class_init     = machine_with_modules_class_init,
1534     }, {
1535         .name           = MACHINE_TYPE_NAME("smp-with-dies"),
1536         .parent         = TYPE_MACHINE,
1537         .class_init     = machine_with_dies_class_init,
1538     }, {
1539         .name           = MACHINE_TYPE_NAME("smp-with-modules-dies"),
1540         .parent         = TYPE_MACHINE,
1541         .class_init     = machine_with_modules_dies_class_init,
1542     }, {
1543         .name           = MACHINE_TYPE_NAME("smp-with-clusters"),
1544         .parent         = TYPE_MACHINE,
1545         .class_init     = machine_with_clusters_class_init,
1546     }, {
1547         .name           = MACHINE_TYPE_NAME("smp-with-books"),
1548         .parent         = TYPE_MACHINE,
1549         .class_init     = machine_with_books_class_init,
1550     }, {
1551         .name           = MACHINE_TYPE_NAME("smp-with-drawers"),
1552         .parent         = TYPE_MACHINE,
1553         .class_init     = machine_with_drawers_class_init,
1554     }, {
1555         .name           = MACHINE_TYPE_NAME("smp-with-drawers-books"),
1556         .parent         = TYPE_MACHINE,
1557         .class_init     = machine_with_drawers_books_class_init,
1558     }, {
1559         .name           = MACHINE_TYPE_NAME("smp-full-topo"),
1560         .parent         = TYPE_MACHINE,
1561         .class_init     = machine_full_topo_class_init,
1562     }
1563 };
1564 
1565 DEFINE_TYPES(smp_machine_types)
1566 
1567 int main(int argc, char *argv[])
1568 {
1569     module_call_init(MODULE_INIT_QOM);
1570 
1571     g_test_init(&argc, &argv, NULL);
1572 
1573     g_test_add_data_func("/test-smp-parse/generic/valid",
1574                          MACHINE_TYPE_NAME("smp-generic-valid"),
1575                          test_generic_valid);
1576     g_test_add_data_func("/test-smp-parse/generic/invalid",
1577                          MACHINE_TYPE_NAME("smp-generic-invalid"),
1578                          test_generic_invalid);
1579     g_test_add_data_func("/test-smp-parse/with_modules",
1580                          MACHINE_TYPE_NAME("smp-with-modules"),
1581                          test_with_modules);
1582     g_test_add_data_func("/test-smp-parse/with_dies",
1583                          MACHINE_TYPE_NAME("smp-with-dies"),
1584                          test_with_dies);
1585     g_test_add_data_func("/test-smp-parse/with_modules_dies",
1586                          MACHINE_TYPE_NAME("smp-with-modules-dies"),
1587                          test_with_modules_dies);
1588     g_test_add_data_func("/test-smp-parse/with_clusters",
1589                          MACHINE_TYPE_NAME("smp-with-clusters"),
1590                          test_with_clusters);
1591     g_test_add_data_func("/test-smp-parse/with_books",
1592                          MACHINE_TYPE_NAME("smp-with-books"),
1593                          test_with_books);
1594     g_test_add_data_func("/test-smp-parse/with_drawers",
1595                          MACHINE_TYPE_NAME("smp-with-drawers"),
1596                          test_with_drawers);
1597     g_test_add_data_func("/test-smp-parse/with_drawers_books",
1598                          MACHINE_TYPE_NAME("smp-with-drawers-books"),
1599                          test_with_drawers_books);
1600     g_test_add_data_func("/test-smp-parse/full",
1601                          MACHINE_TYPE_NAME("smp-full-topo"),
1602                          test_full_topo);
1603 
1604     g_test_run();
1605 
1606     return 0;
1607 }
1608