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