1# awk script to generate hypercall handler prototypes and a macro for doing
2# the calls of the handlers inside a switch() statement.
3
4BEGIN {
5    printf("#ifndef XEN_HYPERCALL_DEFS_H\n");
6    printf("#define XEN_HYPERCALL_DEFS_H\n\n");
7    printf("/* Generated file, do not edit! */\n\n");
8    e = 0;
9    n = 0;
10    p = 0;
11    nc = 0;
12}
13
14# Issue error to stderr
15function do_err(msg) {
16    print "Error: "msg": "$0 >"/dev/stderr";
17    exit 1;
18}
19
20# Generate handler call
21function do_call(f, p,    i) {
22    printf("            ret = %s_%s(", pre[f, p], fn[f]);
23    for (i = 1; i <= n_args[f]; i++) {
24        if (i > 1)
25            printf(", ");
26        if (ptr[f, i])
27            printf("(XEN_GUEST_HANDLE_PARAM(%s)){ _p(a%d) }", typ[f, i], i);
28        else
29            printf("(%s)(a%d)", typ[f, i], i);
30    }
31    printf("); \\\n");
32}
33
34# Generate case statement for call
35function do_case(f, p) {
36    printf("        case __HYPERVISOR_%s: \\\n", fn[f]);
37    do_call(f, p);
38    printf("            break; \\\n");
39}
40
41# Generate switch statement for calling handlers
42function do_switch(ca, p,    i) {
43    printf("        switch ( num ) \\\n");
44    printf("        { \\\n");
45    for (i = 1; i <= nc; i++)
46        if (call[i] == ca && call_prio[i] == p)
47            do_case(call_fn[i], call_p[i]);
48    printf("        default: \\\n");
49    printf("            ret = -ENOSYS; \\\n");
50    printf("            break; \\\n");
51    printf("        } \\\n");
52}
53
54function rest_of_line(par,    i, val) {
55    val = $(par);
56    for (i = par + 1; i <= NF; i++)
57        val = val " " $(i);
58    return val;
59}
60
61# Handle comments (multi- and single line)
62$1 == "/*" {
63    comment = 1;
64}
65comment == 1 {
66    if ($(NF) == "*/") comment = 0;
67    next;
68}
69
70# Skip preprocessing artefacts
71$1 == "extern" {
72    next;
73}
74/^#/ {
75    next;
76}
77
78# Drop empty lines
79NF == 0 {
80    next;
81}
82
83# Handle "handle:" line
84$1 == "handle:" {
85    if (NF < 3)
86        do_err("\"handle:\" requires at least two parameters");
87    val = rest_of_line(3);
88    xlate[val] = $2;
89    next;
90}
91
92# Handle "defhandle:" line
93$1 == "defhandle:" {
94    if (NF < 2)
95        do_err("\"defhandle:\" requires at least one parameter");
96    e++;
97    if (NF == 2) {
98        emit[e] = sprintf("DEFINE_XEN_GUEST_HANDLE(%s);", $2);
99    } else {
100        val = rest_of_line(3);
101        emit[e] = sprintf("__DEFINE_XEN_GUEST_HANDLE(%s, %s);", $2, val);
102        xlate[val] = $2;
103    }
104    next;
105}
106
107# Handle "rettype:" line
108$1 == "rettype:" {
109    if (NF < 3)
110        do_err("\"rettype:\" requires at least two parameters");
111    if ($2 in rettype)
112        do_err("rettype can be set only once for each prefix");
113    rettype[$2] = rest_of_line(3);
114    next;
115}
116
117# Handle "caller:" line
118$1 == "caller:" {
119    caller[$2] = 1;
120    next;
121}
122
123# Handle "prefix:" line
124$1 == "prefix:" {
125    p = NF - 1;
126    for (i = 2; i <= NF; i++) {
127        prefix[i - 1] = $(i);
128        if (!(prefix[i - 1] in rettype))
129            rettype[prefix[i - 1]] = "long";
130    }
131    next;
132}
133
134# Handle "table:" line
135$1 == "table:" {
136    table = 1;
137    for (i = 2; i <= NF; i++)
138        col[i - 1] = $(i);
139    n_cols = NF - 1;
140    next;
141}
142
143# Handle table definition line
144table == 1 {
145    if (NF != n_cols + 1)
146        do_err("Table definition line has wrong number of fields");
147    for (c = 1; c <= n_cols; c++) {
148        if (caller[col[c]] != 1)
149            continue;
150        if ($(c + 1) == "-")
151            continue;
152        pref = $(c + 1);
153        idx = index(pref, ":");
154        if (idx == 0)
155            prio = 100;
156        else {
157            prio = substr(pref, idx + 1) + 0;
158            pref = substr(pref, 1, idx - 1);
159            if (prio >= 100 || prio < 1)
160                do_err("Priority must be in the range 1..99");
161        }
162        fnd = 0;
163        for (i = 1; i <= n; i++) {
164            if (fn[i] != $1)
165                continue;
166            for (j = 1; j <= n_pre[i]; j++) {
167                if (pre[i, j] == pref) {
168                    prios[col[c], prio]++;
169                    if (prios[col[c], prio] == 1) {
170                        n_prios[col[c]]++;
171                        prio_list[col[c], n_prios[col[c]]] = prio;
172                        prio_mask[col[c], prio] = "(1ULL << __HYPERVISOR_"$1")";
173                    } else
174                        prio_mask[col[c], prio] = prio_mask[col[c], prio] " | (1ULL << __HYPERVISOR_"$1")";
175                    nc++;
176                    call[nc] = col[c];
177                    call_fn[nc] = i;
178                    call_p[nc] = j;
179                    call_prio[nc] = prio;
180                    fnd = 1;
181                }
182            }
183        }
184        if (fnd == 0)
185            do_err("No prototype for prefix/hypercall combination");
186    }
187    next;
188}
189
190# Prototype line
191{
192    bro = index($0, "(");
193    brc = index($0, ")");
194    if (bro < 2 || brc < bro)
195        do_err("No valid prototype line");
196    n++;
197    fn[n] = substr($0, 1, bro - 1);
198    n_pre[n] = p;
199    for (i = 1; i <= p; i++)
200        pre[n, i] = prefix[i];
201    args = substr($0, bro + 1, brc - bro - 1);
202    n_args[n] = split(args, a, ",");
203    if (n_args[n] > 5)
204        do_err("Too many parameters");
205    for (i = 1; i <= n_args[n]; i++) {
206        sub("^ *", "", a[i]);         # Remove leading white space
207        sub(" +", " ", a[i]);         # Replace multiple spaces with single ones
208        sub(" *$", "", a[i]);         # Remove trailing white space
209        ptr[n, i] = index(a[i], "*"); # Is it a pointer type?
210        sub("[*]", "", a[i]);         # Remove "*"
211        if (index(a[i], " ") == 0)
212            do_err("Parameter with no type or no name");
213        typ[n, i] = a[i];
214        sub(" [^ ]+$", "", typ[n, i]);    # Remove parameter name
215        if (ptr[n, i] && (typ[n, i] in xlate))
216            typ[n, i] = xlate[typ[n, i]];
217        arg[n, i] = a[i];
218        sub("^([^ ]+ )+", "", arg[n, i]); # Remove parameter type
219    }
220}
221
222# Generate the output
223END {
224    # Verbatim generated lines
225    for (i = 1; i <= e; i++)
226        printf("%s\n", emit[i]);
227    printf("\n");
228    # Generate prototypes
229    for (i = 1; i <= n; i++) {
230        for (p = 1; p <= n_pre[i]; p++) {
231            printf("%s %s_%s(", rettype[pre[i, p]], pre[i, p], fn[i]);
232            if (n_args[i] == 0)
233                printf("void");
234            else
235                for (j = 1; j <= n_args[i]; j++) {
236                    if (j > 1)
237                        printf(", ");
238                    if (ptr[i, j])
239                        printf("XEN_GUEST_HANDLE_PARAM(%s)", typ[i, j]);
240                    else
241                        printf("%s", typ[i, j]);
242                    printf(" %s", arg[i, j]);
243                }
244            printf(");\n");
245        }
246    }
247    # Generate call sequences and args array contents
248    for (ca in caller) {
249        if (caller[ca] != 1)
250            continue;
251        need_mask = 0;
252        for (pl = 1; pl <= n_prios[ca]; pl++) {
253            for (pll = pl; pll > 1; pll--) {
254                if (prio_list[ca, pl] > p_list[pll - 1])
255                    break;
256                else
257                    p_list[pll] = p_list[pll - 1];
258            }
259            p_list[pll] = prio_list[ca, pl];
260            # If any prio but the default one has more than 1 entry we need "mask"
261            if (p_list[pll] != 100 && prios[ca, p_list[pll]] > 1)
262                need_mask = 1;
263        }
264        printf("\n");
265        printf("#define call_handlers_%s(num, ret, a1, a2, a3, a4, a5) \\\n", ca);
266        printf("({ \\\n");
267        if (need_mask)
268            printf("    uint64_t mask = (num) > 63 ? 0 : 1ULL << (num); \\\n");
269        printf("    ");
270        for (pl = 1; pl <= n_prios[ca]; pl++) {
271            if (prios[ca, p_list[pl]] > 1) {
272                if (pl < n_prios[ca]) {
273                    printf("    if ( likely(mask & (%s)) ) \\\n", prio_mask[ca, p_list[pl]]);
274                    printf("    { \\\n");
275                }
276                if (prios[ca, p_list[pl]] == 2) {
277                    fnd = 0;
278                    for (i = 1; i <= nc; i++)
279                        if (call[i] == ca && call_prio[i] == p_list[pl]) {
280                            fnd++;
281                            if (fnd == 1)
282                                printf("        if ( (num) == __HYPERVISOR_%s ) \\\n", fn[call_fn[i]]);
283                            else
284                                printf("        else \\\n");
285                            do_call(call_fn[i], call_p[i]);
286                        }
287                } else {
288                    do_switch(ca, p_list[pl]);
289                }
290                if (pl < n_prios[ca])
291                    printf("    } \\\n");
292            } else {
293                for (i = 1; i <= nc; i++)
294                    if (call[i] == ca && call_prio[i] == p_list[pl]) {
295                        printf("if ( likely((num) == __HYPERVISOR_%s) ) \\\n", fn[call_fn[i]]);
296                        do_call(call_fn[i], call_p[i]);
297                    }
298            }
299            if (pl < n_prios[ca] || prios[ca, p_list[pl]] <= 2)
300                printf("    else \\\n");
301        }
302        if (prios[ca, p_list[n_prios[ca]]] <= 2) {
303            printf("\\\n");
304            printf("        ret = -ENOSYS; \\\n");
305        }
306        printf("})\n");
307        delete p_list;
308        printf("\n");
309        printf("#define hypercall_args_%s \\\n", ca);
310        printf("{ \\\n");
311        for (i = 1; i <= nc; i++)
312            if (call[i] == ca)
313                printf("[__HYPERVISOR_%s] = %d, \\\n", fn[call_fn[i]], n_args[call_fn[i]]);
314        printf("}\n");
315    }
316    printf("\n#endif /* XEN_HYPERCALL_DEFS_H */\n");
317}
318