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