1#!/usr/bin/perl -w 2 3use warnings; 4use strict; 5use POSIX; 6 7our $debug = 0; # produce copious debugging output at run-time? 8 9our @msgs = ( 10 # flags: 11 # s - applicable to save 12 # r - applicable to restore 13 # c - function pointer in callbacks struct rather than fixed function 14 # x - function pointer is in struct {save,restore}_callbacks 15 # and its null-ness needs to be passed through to the helper's xc 16 # W - needs a return value; callback is synchronous 17 # A - needs a return value; callback is asynchronous 18 [ 1, 'sr', "log", [qw(uint32_t level 19 uint32_t errnoval 20 STRING context 21 STRING formatted)] ], 22 [ 2, 'sr', "progress", [qw(STRING context 23 STRING doing_what), 24 'unsigned long', 'done', 25 'unsigned long', 'total'] ], 26 [ 3, 'srcxA', "suspend", [] ], 27 [ 4, 'srcxA', "postcopy", [] ], 28 [ 5, 'srcxA', "checkpoint", [] ], 29 [ 6, 'srcxA', "wait_checkpoint", [] ], 30 [ 7, 'scxA', "switch_qemu_logdirty", [qw(uint32_t domid 31 unsigned enable)] ], 32 [ 8, 'rcx', "restore_results", ['xen_pfn_t', 'store_gfn', 33 'xen_pfn_t', 'console_gfn'] ], 34 [ 9, 'srW', "complete", [qw(int retval 35 int errnoval)] ], 36); 37 38#---------------------------------------- 39 40our %cbs; 41our %func; 42our %func_ah; 43our @outfuncs; 44our %out_decls; 45our %out_body; 46our %msgnum_used; 47 48die unless @ARGV==1; 49die if $ARGV[0] =~ m/^-/; 50 51our ($intendedout) = @ARGV; 52 53$intendedout =~ m/([a-z]+)\.([ch])$/ or die; 54my ($want_ah, $ch) = ($1, $2); 55 56my $declprefix = ''; 57 58foreach my $ah (qw(callout helper)) { 59 $out_body{$ah} .= 60 <<END_BOTH.($ah eq 'callout' ? <<END_CALLOUT : <<END_HELPER); 61#include "libxl_osdeps.h" 62 63#include <assert.h> 64#include <string.h> 65#include <stdint.h> 66#include <limits.h> 67END_BOTH 68 69#include "libxl_internal.h" 70 71END_CALLOUT 72 73#include <xenctrl.h> 74#include <xenguest.h> 75#include "_libxl_save_msgs_${ah}.h" 76 77END_HELPER 78} 79 80die $want_ah unless defined $out_body{$want_ah}; 81 82sub f_decl ($$$$) { 83 my ($name, $ah, $c_rtype, $c_decl) = @_; 84 $out_decls{$name} = "${declprefix}$c_rtype $name$c_decl;\n"; 85 $func{$name} = "$c_rtype $name$c_decl\n{\n" . ($func{$name} || ''); 86 $func_ah{$name} = $ah; 87} 88 89sub f_more ($$) { 90 my ($name, $addbody) = @_; 91 $func{$name} ||= ''; 92 $func{$name} .= $addbody; 93 push @outfuncs, $name; 94} 95 96our $libxl = "libxl__srm"; 97our $callback = "${libxl}_callout_callback"; 98our $receiveds = "${libxl}_callout_received"; 99our $sendreply = "${libxl}_callout_sendreply"; 100our $getcallbacks = "${libxl}_callout_get_callbacks"; 101our $enumcallbacks = "${libxl}_callout_enumcallbacks"; 102sub cbtype ($) { "${libxl}_".$_[0]."_autogen_callbacks"; }; 103 104f_decl($sendreply, 'callout', 'void', "(int r, void *user)"); 105 106our $helper = "helper"; 107our $encode = "${helper}_stub"; 108our $allocbuf = "${helper}_allocbuf"; 109our $transmit = "${helper}_transmitmsg"; 110our $getreply = "${helper}_getreply"; 111our $setcallbacks = "${helper}_setcallbacks"; 112 113f_decl($allocbuf, 'helper', 'unsigned char *', '(int len, void *user)'); 114f_decl($transmit, 'helper', 'void', 115 '(unsigned char *msg_freed, int len, void *user)'); 116f_decl($getreply, 'helper', 'int', '(void *user)'); 117 118sub typeid ($) { my ($t) = @_; $t =~ s/\W/_/; return $t; }; 119 120$out_body{'callout'} .= <<END; 121static int bytes_get(const unsigned char **msg, 122 const unsigned char *const endmsg, 123 void *result, int rlen) 124{ 125 if (endmsg - *msg < rlen) return 0; 126 memcpy(result,*msg,rlen); 127 *msg += rlen; 128 return 1; 129} 130 131END 132$out_body{'helper'} .= <<END; 133static void bytes_put(unsigned char *const buf, int *len, 134 const void *value, int vlen) 135{ 136 assert(vlen < INT_MAX/2 - *len); 137 if (buf) 138 memcpy(buf + *len, value, vlen); 139 *len += vlen; 140} 141 142END 143 144foreach my $simpletype (qw(int uint16_t uint32_t unsigned), 'unsigned long', 'xen_pfn_t') { 145 my $typeid = typeid($simpletype); 146 $out_body{'callout'} .= <<END; 147static int ${typeid}_get(const unsigned char **msg, 148 const unsigned char *const endmsg, 149 $simpletype *result) 150{ 151 return bytes_get(msg, endmsg, result, sizeof(*result)); 152} 153 154END 155 $out_body{'helper'} .= <<END; 156static void ${typeid}_put(unsigned char *const buf, int *len, 157 const $simpletype value) 158{ 159 bytes_put(buf, len, &value, sizeof(value)); 160} 161 162END 163} 164 165$out_body{'callout'} .= <<END; 166static int BLOCK_get(const unsigned char **msg, 167 const unsigned char *const endmsg, 168 const uint8_t **result, uint32_t *result_size) 169{ 170 if (!uint32_t_get(msg,endmsg,result_size)) return 0; 171 if (endmsg - *msg < *result_size) return 0; 172 *result = (const void*)*msg; 173 *msg += *result_size; 174 return 1; 175} 176 177static int STRING_get(const unsigned char **msg, 178 const unsigned char *const endmsg, 179 const char **result) 180{ 181 const uint8_t *data; 182 uint32_t datalen; 183 if (!BLOCK_get(msg,endmsg,&data,&datalen)) return 0; 184 if (datalen == 0) return 0; 185 if (data[datalen-1] != '\\0') return 0; 186 *result = (const void*)data; 187 return 1; 188} 189 190END 191$out_body{'helper'} .= <<END; 192static void BLOCK_put(unsigned char *const buf, 193 int *len, 194 const uint8_t *bytes, uint32_t size) 195{ 196 uint32_t_put(buf, len, size); 197 bytes_put(buf, len, bytes, size); 198} 199 200static void STRING_put(unsigned char *const buf, 201 int *len, 202 const char *string) 203{ 204 size_t slen = strlen(string); 205 assert(slen < INT_MAX / 4); 206 assert(slen < (uint32_t)0x40000000); 207 BLOCK_put(buf, len, (const void*)string, slen+1); 208} 209 210END 211 212foreach my $sr (qw(save restore)) { 213 f_decl("${getcallbacks}_${sr}", 'callout', 214 "const ".cbtype($sr)." *", 215 "(void *data)"); 216 217 f_decl("${receiveds}_${sr}", 'callout', 'int', 218 "(const unsigned char *msg, uint32_t len, void *user)"); 219 220 f_decl("${enumcallbacks}_${sr}", 'callout', 'unsigned', 221 "(const ".cbtype($sr)." *cbs)"); 222 f_more("${enumcallbacks}_${sr}", " unsigned cbflags = 0;\n"); 223 224 f_decl("${setcallbacks}_${sr}", 'helper', 'void', 225 "(struct ${sr}_callbacks *cbs, unsigned cbflags)"); 226 227 f_more("${receiveds}_${sr}", 228 <<END_ALWAYS.($debug ? <<END_DEBUG : '').<<END_ALWAYS); 229 const unsigned char *const endmsg = msg + len; 230 uint16_t mtype; 231 if (!uint16_t_get(&msg,endmsg,&mtype)) return 0; 232END_ALWAYS 233 fprintf(stderr,"libxl callout receiver: got len=%u mtype=%u\\n",len,mtype); 234END_DEBUG 235 switch (mtype) { 236 237END_ALWAYS 238 239 $cbs{$sr} = "typedef struct ".cbtype($sr)." {\n"; 240} 241 242foreach my $msginfo (@msgs) { 243 my ($msgnum, $flags, $name, $args) = @$msginfo; 244 die if $msgnum_used{$msgnum}++; 245 246 my $f_more_sr = sub { 247 my ($contents_spec, $fnamebase) = @_; 248 $fnamebase ||= "${receiveds}"; 249 foreach my $sr (qw(save restore)) { 250 $sr =~ m/^./; 251 next unless $flags =~ m/$&/; 252 my $contents = (!ref $contents_spec) ? $contents_spec : 253 $contents_spec->($sr); 254 f_more("${fnamebase}_${sr}", $contents); 255 } 256 }; 257 258 $f_more_sr->(" case $msgnum: { /* $name */\n"); 259 if ($flags =~ m/W/) { 260 $f_more_sr->(" int r;\n"); 261 } 262 263 my $c_rtype_helper = $flags =~ m/[WA]/ ? 'int' : 'void'; 264 my $c_rtype_callout = $flags =~ m/W/ ? 'int' : 'void'; 265 my $c_decl = '('; 266 my $c_callback_args = ''; 267 268 f_more("${encode}_$name", 269 <<END_ALWAYS.($debug ? <<END_DEBUG : '').<<END_ALWAYS); 270 unsigned char *buf = 0; 271 int len = 0, allocd = 0; 272 273END_ALWAYS 274 fprintf(stderr,"libxl-save-helper: encoding $name\\n"); 275END_DEBUG 276 for (;;) { 277 uint16_t_put(buf, &len, $msgnum /* $name */); 278END_ALWAYS 279 280 my @args = @$args; 281 my $c_recv = ''; 282 my ($argtype, $arg); 283 while (($argtype, $arg, @args) = @args) { 284 my $typeid = typeid($argtype); 285 my $c_args = "$arg"; 286 my $c_get_args = "&$arg"; 287 if ($argtype eq 'STRING') { 288 $c_decl .= "const char *$arg, "; 289 $f_more_sr->(" const char *$arg;\n"); 290 } elsif ($argtype eq 'BLOCK') { 291 $c_decl .= "const uint8_t *$arg, uint32_t ${arg}_size, "; 292 $c_args .= ", ${arg}_size"; 293 $c_get_args .= ",&${arg}_size"; 294 $f_more_sr->(" const uint8_t *$arg;\n". 295 " uint32_t ${arg}_size;\n"); 296 } else { 297 $c_decl .= "$argtype $arg, "; 298 $f_more_sr->(" $argtype $arg;\n"); 299 } 300 $c_callback_args .= "$c_args, "; 301 $c_recv.= 302 " if (!${typeid}_get(&msg,endmsg,$c_get_args)) return 0;\n"; 303 f_more("${encode}_$name", " ${typeid}_put(buf, &len, $c_args);\n"); 304 } 305 $f_more_sr->($c_recv); 306 $c_decl .= "void *user)"; 307 $c_callback_args .= "user"; 308 309 $f_more_sr->(" if (msg != endmsg) return 0;\n"); 310 311 my $c_callback; 312 if ($flags !~ m/c/) { 313 $c_callback = "${callback}_$name"; 314 } else { 315 $f_more_sr->(sub { 316 my ($sr) = @_; 317 $cbs{$sr} .= " $c_rtype_callout (*${name})$c_decl;\n"; 318 return 319 " const ".cbtype($sr)." *const cbs =\n". 320 " ${getcallbacks}_${sr}(user);\n"; 321 }); 322 $c_callback = "cbs->${name}"; 323 } 324 my $c_make_callback = "$c_callback($c_callback_args)"; 325 if ($flags !~ m/W/) { 326 $f_more_sr->(" $c_make_callback;\n"); 327 } else { 328 $f_more_sr->(" r = $c_make_callback;\n". 329 " $sendreply(r, user);\n"); 330 f_decl($sendreply, 'callout', 'void', '(int r, void *user)'); 331 } 332 if ($flags =~ m/x/) { 333 my $c_v = "(1u<<$msgnum)"; 334 my $c_cb = "cbs->$name"; 335 $f_more_sr->(" if ($c_cb) cbflags |= $c_v;\n", $enumcallbacks); 336 $f_more_sr->(" $c_cb = (cbflags & $c_v) ? ${encode}_${name} : 0;\n", 337 $setcallbacks); 338 } 339 $f_more_sr->(" return 1;\n }\n\n"); 340 f_decl("${callback}_$name", 'callout', $c_rtype_callout, $c_decl); 341 f_decl("${encode}_$name", 'helper', $c_rtype_helper, $c_decl); 342 f_more("${encode}_$name", 343" if (buf) break; 344 buf = ${helper}_allocbuf(len, user); 345 assert(buf); 346 allocd = len; 347 len = 0; 348 } 349 assert(len == allocd); 350 ${transmit}(buf, len, user); 351"); 352 if ($flags =~ m/[WA]/) { 353 f_more("${encode}_$name", 354 (<<END_ALWAYS.($debug ? <<END_DEBUG : '').<<END_ALWAYS)); 355 int r = ${helper}_getreply(user); 356END_ALWAYS 357 fprintf(stderr,"libxl-save-helper: $name got reply %d\\n",r); 358END_DEBUG 359 return r; 360END_ALWAYS 361 } 362} 363 364print "/* AUTOGENERATED by $0 DO NOT EDIT */\n\n" or die $!; 365 366foreach my $sr (qw(save restore)) { 367 f_more("${enumcallbacks}_${sr}", 368 " return cbflags;\n"); 369 f_more("${receiveds}_${sr}", 370 " default:\n". 371 " return 0;\n". 372 " }"); 373 $cbs{$sr} .= "} ".cbtype($sr).";\n\n"; 374 if ($ch eq 'h') { 375 print $cbs{$sr} or die $!; 376 print "struct ${sr}_callbacks;\n"; 377 } 378} 379 380if ($ch eq 'c') { 381 foreach my $name (@outfuncs) { 382 next unless defined $func{$name}; 383 $func{$name} .= "}\n\n"; 384 $out_body{$func_ah{$name}} .= $func{$name}; 385 delete $func{$name}; 386 } 387 print $out_body{$want_ah} or die $!; 388} else { 389 foreach my $name (sort keys %out_decls) { 390 next unless $func_ah{$name} eq $want_ah; 391 print $out_decls{$name} or die $!; 392 } 393} 394 395close STDOUT or die $!; 396