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