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