#!/usr/bin/perl -w use warnings; use strict; use POSIX; our $debug = 0; # produce copious debugging output at run-time? our @msgs = ( # flags: # s - applicable to save # r - applicable to restore # c - function pointer in callbacks struct rather than fixed function # x - function pointer is in struct {save,restore}_callbacks # and its null-ness needs to be passed through to the helper's xc # W - needs a return value; callback is synchronous # A - needs a return value; callback is asynchronous [ 1, 'sr', "log", [qw(uint32_t level uint32_t errnoval STRING context STRING formatted)] ], [ 2, 'sr', "progress", [qw(STRING context STRING doing_what), 'unsigned long', 'done', 'unsigned long', 'total'] ], [ 3, 'scxW', "suspend", [] ], [ 4, 'scxW', "postcopy", [] ], [ 5, 'scxA', "checkpoint", [] ], [ 6, 'scxA', "switch_qemu_logdirty", [qw(int domid unsigned enable)] ], # toolstack_save done entirely `by hand' [ 7, 'rcxW', "toolstack_restore", [qw(uint32_t domid BLOCK tsdata)] ], [ 8, 'r', "restore_results", ['unsigned long', 'store_mfn', 'unsigned long', 'console_mfn', 'unsigned long', 'genidad'] ], [ 9, 'srW', "complete", [qw(int retval int errnoval)] ], ); #---------------------------------------- our %cbs; our %func; our %func_ah; our @outfuncs; our %out_decls; our %out_body; our %msgnum_used; die unless @ARGV==1; die if $ARGV[0] =~ m/^-/; our ($intendedout) = @ARGV; $intendedout =~ m/([a-z]+)\.([ch])$/ or die; my ($want_ah, $ch) = ($1, $2); my $declprefix = ''; foreach my $ah (qw(callout helper)) { $out_body{$ah} .= < #include #include #include END_BOTH #include "libxl_internal.h" END_CALLOUT #include "_libxl_save_msgs_${ah}.h" #include #include END_HELPER } die $want_ah unless defined $out_body{$want_ah}; sub f_decl ($$$$) { my ($name, $ah, $c_rtype, $c_decl) = @_; $out_decls{$name} = "${declprefix}$c_rtype $name$c_decl;\n"; $func{$name} = "$c_rtype $name$c_decl\n{\n" . ($func{$name} || ''); $func_ah{$name} = $ah; } sub f_more ($$) { my ($name, $addbody) = @_; $func{$name} ||= ''; $func{$name} .= $addbody; push @outfuncs, $name; } our $libxl = "libxl__srm"; our $callback = "${libxl}_callout_callback"; our $receiveds = "${libxl}_callout_received"; our $sendreply = "${libxl}_callout_sendreply"; our $getcallbacks = "${libxl}_callout_get_callbacks"; our $enumcallbacks = "${libxl}_callout_enumcallbacks"; sub cbtype ($) { "${libxl}_".$_[0]."_autogen_callbacks"; }; f_decl($sendreply, 'callout', 'void', "(int r, void *user)"); our $helper = "helper"; our $encode = "${helper}_stub"; our $allocbuf = "${helper}_allocbuf"; our $transmit = "${helper}_transmitmsg"; our $getreply = "${helper}_getreply"; our $setcallbacks = "${helper}_setcallbacks"; f_decl($allocbuf, 'helper', 'unsigned char *', '(int len, void *user)'); f_decl($transmit, 'helper', 'void', '(unsigned char *msg_freed, int len, void *user)'); f_decl($getreply, 'helper', 'int', '(void *user)'); sub typeid ($) { my ($t) = @_; $t =~ s/\W/_/; return $t; }; $out_body{'callout'} .= <($sr); f_more("${fnamebase}_${sr}", $contents); } }; $f_more_sr->(" case $msgnum: { /* $name */\n"); if ($flags =~ m/W/) { $f_more_sr->(" int r;\n"); } my $c_rtype_helper = $flags =~ m/[WA]/ ? 'int' : 'void'; my $c_rtype_callout = $flags =~ m/W/ ? 'int' : 'void'; my $c_decl = '('; my $c_callback_args = ''; f_more("${encode}_$name", <(" const char *$arg;\n"); } elsif ($argtype eq 'BLOCK') { $c_decl .= "const uint8_t *$arg, uint32_t ${arg}_size, "; $c_args .= ", ${arg}_size"; $c_get_args .= ",&${arg}_size"; $f_more_sr->(" const uint8_t *$arg;\n". " uint32_t ${arg}_size;\n"); } else { $c_decl .= "$argtype $arg, "; $f_more_sr->(" $argtype $arg;\n"); } $c_callback_args .= "$c_args, "; $c_recv.= " if (!${typeid}_get(&msg,endmsg,$c_get_args)) return 0;\n"; f_more("${encode}_$name", " ${typeid}_put(buf, &len, $c_args);\n"); } $f_more_sr->($c_recv); $c_decl .= "void *user)"; $c_callback_args .= "user"; $f_more_sr->(" if (msg != endmsg) return 0;\n"); my $c_callback; if ($flags !~ m/c/) { $c_callback = "${callback}_$name"; } else { $f_more_sr->(sub { my ($sr) = @_; $cbs{$sr} .= " $c_rtype_callout (*${name})$c_decl;\n"; return " const ".cbtype($sr)." *const cbs =\n". " ${getcallbacks}_${sr}(user);\n"; }); $c_callback = "cbs->${name}"; } my $c_make_callback = "$c_callback($c_callback_args)"; if ($flags !~ m/W/) { $f_more_sr->(" $c_make_callback;\n"); } else { $f_more_sr->(" r = $c_make_callback;\n". " $sendreply(r, user);\n"); f_decl($sendreply, 'callout', 'void', '(int r, void *user)'); } if ($flags =~ m/x/) { my $c_v = "(1u<<$msgnum)"; my $c_cb = "cbs->$name"; $f_more_sr->(" if ($c_cb) cbflags |= $c_v;\n", $enumcallbacks); $f_more_sr->(" $c_cb = (cbflags & $c_v) ? ${encode}_${name} : 0;\n", $setcallbacks); } $f_more_sr->(" return 1;\n }\n\n"); f_decl("${callback}_$name", 'callout', $c_rtype_callout, $c_decl); f_decl("${encode}_$name", 'helper', $c_rtype_helper, $c_decl); f_more("${encode}_$name", " if (buf) break; buf = ${helper}_allocbuf(len, user); assert(buf); allocd = len; len = 0; } assert(len == allocd); ${transmit}(buf, len, user); "); if ($flags =~ m/[WA]/) { f_more("${encode}_$name", (<