1 #include <assert.h>
2 #include <stdbool.h>
3 #include <stddef.h>
4 #include <stdint.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8
9 #include <getopt.h>
10
11 #include <xen-tools/common-macros.h>
12 #include <xen/lib/x86/cpu-policy.h>
13 #include <xen/domctl.h>
14
15 static bool debug;
16
17 #define EMPTY_LEAF ((struct cpuid_leaf){})
18
check_policy(struct cpu_policy * cp)19 static void check_policy(struct cpu_policy *cp)
20 {
21 struct cpu_policy new = {};
22 size_t data_end;
23 xen_cpuid_leaf_t *leaves = malloc(CPUID_MAX_SERIALISED_LEAVES *
24 sizeof(xen_cpuid_leaf_t));
25 xen_msr_entry_t *msrs = malloc(MSR_MAX_SERIALISED_ENTRIES *
26 sizeof(xen_cpuid_leaf_t));
27 unsigned int nr_leaves = CPUID_MAX_SERIALISED_LEAVES;
28 unsigned int nr_msrs = MSR_MAX_SERIALISED_ENTRIES;
29 int rc;
30
31 if ( !leaves || !msrs )
32 return;
33
34 /*
35 * Clean unusable leaves. These can't be accessed via architectural
36 * means, but may be filled by the fread() across the entire structure.
37 * Also zero the trailing padding (if any).
38 */
39 cp->basic.raw[4] = EMPTY_LEAF;
40 cp->basic.raw[7] = EMPTY_LEAF;
41 cp->basic.raw[0xb] = EMPTY_LEAF;
42 cp->basic.raw[0xd] = EMPTY_LEAF;
43 data_end = offsetof(typeof(*cp), x86_vendor) + sizeof(cp->x86_vendor);
44 if ( data_end < sizeof(*cp) )
45 memset((void *)cp + data_end, 0, sizeof(*cp) - data_end);
46
47 /*
48 * Fix up the data in the source policy which isn't expected to survive
49 * serialisation.
50 */
51 x86_cpu_policy_clear_out_of_range_leaves(cp);
52 x86_cpu_policy_recalc_synth(cp);
53
54 /* Serialise... */
55 rc = x86_cpuid_copy_to_buffer(cp, leaves, &nr_leaves);
56 assert(rc == 0);
57 assert(nr_leaves <= CPUID_MAX_SERIALISED_LEAVES);
58
59 rc = x86_msr_copy_to_buffer(cp, msrs, &nr_msrs);
60 assert(rc == 0);
61 assert(nr_msrs <= MSR_MAX_SERIALISED_ENTRIES);
62
63 /* ... and deserialise. */
64 rc = x86_cpuid_copy_from_buffer(&new, leaves, nr_leaves, NULL, NULL);
65 assert(rc == 0);
66
67 rc = x86_msr_copy_from_buffer(&new, msrs, nr_msrs, NULL);
68 assert(rc == 0);
69
70 /* The result after serialisation/deserialisaion should be identical... */
71 if ( memcmp(cp, &new, sizeof(*cp)) != 0 )
72 {
73 if ( debug )
74 {
75 unsigned char *l = (void *)cp, *r = (void *)&new;
76
77 for ( size_t i = 0; i < sizeof(*cp); ++i )
78 if ( l[i] != r[i] )
79 printf("Differ at offset %zu: %u vs %u\n",
80 i, l[i], r[i]);
81 }
82
83 abort();
84 }
85
86 free(leaves);
87 }
88
main(int argc,char ** argv)89 int main(int argc, char **argv)
90 {
91 FILE *fp = NULL;
92
93 setbuf(stdin, NULL);
94 setbuf(stdout, NULL);
95
96 while ( true )
97 {
98 static const struct option opts[] = {
99 { "debug", no_argument, NULL, 'd' },
100 { "help", no_argument, NULL, 'h' },
101 {},
102 };
103 int c = getopt_long(argc, argv, "hd", opts, NULL);
104
105 if ( c == -1 )
106 break;
107
108 switch ( c )
109 {
110 case 'd':
111 printf("Enabling debug\n");
112 debug = true;
113 break;
114
115 case '?':
116 case 'h':
117 printf("Usage: %s [--debug] <FILE>\n", argv[0]);
118 default:
119 exit(-(c != 'h'));
120 break;
121 }
122 }
123
124 if ( optind == argc ) /* No positional parameters. Use stdin. */
125 {
126 printf("Using stdin\n");
127 fp = stdin;
128 }
129
130 #ifdef __AFL_HAVE_MANUAL_CONTROL
131 __AFL_INIT();
132 while ( __AFL_LOOP(1000) )
133 #endif
134 {
135 struct cpu_policy *cp = NULL;
136
137 if ( fp != stdin )
138 {
139 printf("Opening file '%s'\n", argv[optind]);
140 fp = fopen(argv[optind], "rb");
141
142 if ( !fp )
143 {
144 perror("fopen");
145 exit(-1);
146 }
147 }
148
149 cp = calloc(1, sizeof(*cp));
150 if ( !cp )
151 goto skip;
152
153 fread(cp, sizeof(*cp), 1, fp);
154
155 if ( !feof(fp) )
156 goto skip;
157
158 check_policy(cp);
159
160 skip:
161 free(cp);
162
163 if ( fp != stdin )
164 {
165 fclose(fp);
166 fp = NULL;
167 }
168 }
169
170 return 0;
171 }
172