Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


Guest configurator cleanup (nvram, vnet)
[palacios.git] / v3_config_guest.pl
1 #!/usr/bin/perl -w
2
3
4 print <<END
5
6 Welcome.  The purpose of this tool is to simplify the creation of
7 common forms of guests for the V3VEE environment on a Linux system.
8 These guests *should* work for any host embedding (e.g., Kitten) but
9 there may be hidden Linux assumptions.
10
11 The tool assumes you have already built Palacios, the Linux embedding,
12 and the Linux user-sapce tools.  If you haven't done this, hit CTRL-C
13 now, configure and build Palacios, the user-space tools, and run
14 v3_config_v3vee.pl.
15
16 This tool also assumes that you have the environment produced by
17 v3_config_v3vee.pl sourced:
18
19   source ./ENV
20
21 What this tool builds is a directory that contains a guest
22 configuration file (the ".pal" file) and its dependent files. Note
23 that lots of additional functionality is possible beyond what can be
24 configured with this tool.  The precise functionality depends on the
25 version and branch of Palacios, and what was configured into it when
26 it was built.  To access such functionality, you need to write your
27 own .pal file, or use one generated by this tool as a basis.
28
29 Any .pal guest configuration file is instantiated as a VM in the
30 following way:
31
32   cd guest
33   v3_create -b guest.pal name_of_guest
34
35 Any files (disk images) that your guest configuration depends on
36 must be accessible when v3_create is run.  
37
38 Once the VM is instantiated, you can then launch it:
39
40   v3_launch /dev/v3-vmN  (N is given by the v3_create command)
41
42 We will configure your guest via a sequence of questions.
43
44 END
45 ;
46
47 $pdir = $ENV{PALACIOS_DIR};
48
49 if (!defined($pdir)) { 
50   print "Please set PALACIOS_DIR (you probably have not sourced ENV) and try again\n";
51   exit -1;
52 }
53
54 $otherbios = get_palacios_core_feature($pdir,"V3_CONFIG_OTHERBIOS");
55 $otherbios = !defined($otherbios) ? 0 : $otherbios eq "y" ? 1: 0;
56 if ($otherbios) {
57   print "Your Palacios installation is set up for a custom BIOS. \n";
58   print "You probably do NOT want to use this tool...  Continue ? [n] : ";
59   if (get_user("n") eq "n") { exit -1; }
60 }
61
62
63 $name = "guest";
64 print "What is the name of your guest? [$name] : ";
65 $name = get_user($name);
66
67 $dir = "./$name";
68 print "What is the directory into which we will put your guest? [$dir] : ";
69 $dir = get_user($dir);
70 if (!mkdir($dir)) { 
71   print "Unable to create the directory\n";
72   exit -1;
73 }
74
75 $config{numcores} = quant_question("How many cores will your guest have?", 1);
76
77 $config{mem} = quant_question("How much memory should it have in MB?", 256);
78
79 if ($config{numcores}>1) { 
80   print "Do you want to to produce a NUMA configuration and mapping for your guest? [n] : ";
81   if (get_user("n") eq "y") { 
82     do_numa_config(\%config,$pdir);
83   }
84 }
85
86
87 print "We will give your guest the default performance tuning characteristics\n";
88 $config{perftune_block} .= <<PERFTUNE
89   <group name="yield">
90    <strategy>friendly</strategy>
91    <threshold>1000</threshold>
92    <time>1000</time>
93   </group>
94 PERFTUNE
95 ;
96
97 print "We will give your guest the default host scheduler interaction characteristics\n";
98 $config{schedule_hz_block} .= " <schedule_hz>100</schedule_hz>\n";
99
100
101 $config{telemetry} = yn_question("Do you want telemetry (information about guest exits) ?", "y", "enable", "disable");
102
103
104 $config{paging_mode} = yn_question("Do you want to use nested paging if possible on your hardware?\n  This will often (but not always) perform faster than shadow paging. ", "y", "nested", "shadow");
105
106 $config{large_pages} = yn_question("Do you want to use large pages if possible on your hardware?\n  This will often (but not always) perform faster. ", "n", "true", "false");
107
108 print "We will give your guest the default shadow paging strategy for when shadow paging is used.\n";
109 $config{shadow_strategy} = "VTLB";
110
111
112 $config{memmap_block} = " <!-- there are no passthrough memory regions, but you can add them using\n".
113                          "     the <memmap> syntax described in the manual -->\n";
114
115 if (is_palacios_core_feature_enabled($pdir, "V3_CONFIG_EXT_VMWARE")) {
116   print "We will include the VMware Personality Extension since your Palacios build has it enabled\n";
117   $config{extensions_block} .= "  <extension name=\"VMWARE_IFACE\"></extension>\n";
118 }
119
120 #
121 # Basic debugging
122 #
123 do_device(\%config, $pdir, "V3_CONFIG_BOCHS_DEBUG", "BOCHS_DEBUG", "bios_debug");
124 do_device(\%config, $pdir, "V3_CONFIG_OS_DEBUG", "OS_DEBUG", "os_debug");
125
126 #
127 # Interrupt control
128 #
129 #
130 do_device(\%config, $pdir, "V3_CONFIG_PIC", "8259A", "PIC", 1);  # must have
131 if ($config{numcores}==1 && is_palacios_core_feature_enabled($pdir,"V3_CONFIG_BOCHSBIOS")) {
132   print "This is a single core guest and your Palacios setup uses the legacy BOCHS BIOS.\n";
133   print " Do you want to have only the legacy (pre-APIC) interrupt controller logic? [n] :";
134   if (get_user("n") eq "y") { 
135     goto intr_done;
136   }
137 }
138 do_device(\%config, $pdir, "V3_CONFIG_APIC", "LAPIC", "apic", 1); # must have
139 do_device(\%config, $pdir, "V3_CONFIG_IO_APIC", "IOAPIC", "ioapic", 1, undef, "    <apic>apic</apic>\n"); 
140
141
142 #
143 # PCI buses and north/south bridge - all must haves
144 #
145 do_device(\%config, $pdir, "V3_CONFIG_PCI", "PCI", "pci0",1); # must have
146 do_device(\%config, $pdir, "V3_CONFIG_I440FX", "i440FX", "northbridge",1, undef, "    <bus>pci0</bus>\n"); #must have
147 do_device(\%config, $pdir, "V3_CONFIG_PIIX3", "PIIX3", "southbridge",1, undef, "    <bus>pci0</bus>\n"); #must have
148
149 #
150 # MPTABLE for legacy BIOS.  Innocuous for SEABIOS or OTHERBIOS
151 #
152 #
153 if (is_palacios_core_feature_enabled($pdir,"V3_CONFIG_MPTABLE")) {
154   print "We will include a classic MPTABLE constructor to describe your machine to the guest\n";
155   add_device(\%config, "MPTABLE", "mptable");
156 } else {
157   if ($config{numcores}>1 &&  is_palacios_core_feature_enabled($pdir,"V3_CONFIG_BOCHSBIOS")) {
158     print "This is a multicore guest, and your Palacios configuration uses the classic BOCHS BIOS\n".
159       "but does not have the MPTABLE constructor enabled...  This guest will almost\n".
160         "certainly fail to work.  Do you want to continue anyway? [n] :";
161     if (get_user("n") eq "n") { 
162       exit -1;
163     }
164   }
165 }
166
167
168
169 # Legacy timer
170 #
171 do_device(\%config, $pdir, "V3_CONFIG_PIT", "8254_PIT", "PIT",1); # must have
172
173 #
174 # Keyboard and mouse (PS/2 controller)
175 #
176 do_device(\%config, $pdir, "V3_CONFIG_KEYBOARD", "KEYBOARD", "keyboard",1); #must have
177
178
179 #
180 # Displays, Consoles, Serial
181 #
182 print "\nWe will now consider consoles and serial ports.\n\n";
183 do_consoles_and_ports(\%config, $pdir);
184
185
186 #
187 # Storage controllers and devices (attached to PCI bus)
188 #
189 #
190 print "\nWe will now consider storage controllers and devices.\n\n";
191 do_storage(\%config, $pdir, $dir, $name, "pci0", "southbridge");
192
193
194 #
195 # NVRAM 
196 #
197 # Note: do_storage *must* have placed an IDE named ide0 in order for this to work
198 #
199 do_device(\%config, $pdir, "V3_CONFIG_NVRAM", "NVRAM", "nvram", 1, undef, "     <storage>ide0</storage>\n"); #must have
200
201
202 #
203 # Network interfaces (attached to PCI bus)
204 #
205 #
206 print "\nWe will now consider network interfaces.\n\n";
207 do_network(\%config, $pdir, $dir, $name, "pci0", "southbridge");
208
209
210 #
211 #
212 # Generic Catch-all Device
213 #
214 do_generic(\%config, $pdir);
215
216
217 open(PAL,">$dir/$name.pal") or die "Cannot open $dir/$name.pal\n";
218
219 $target = PAL;
220
221 print $target "<vm class=\"PC\">\n\n";
222 print $target file_setup(\%config), "\n";
223 print $target memory_setup(\%config), "\n";
224 print $target paging_setup(\%config), "\n";
225 print $target memmap_setup(\%config), "\n";
226 print $target numa_setup(\%config), "\n";
227 print $target core_setup(\%config), "\n";
228 print $target schedule_setup(\%config), "\n";
229 print $target perftune_setup(\%config), "\n";
230 print $target telemetry_setup(\%config), "\n";
231 print $target extensions_setup(\%config), "\n";
232 print $target device_setup(\%config), "\n";
233 print $target "</vm>\n";
234
235 close(PAL);
236
237 print "\n\nYour guest is now ready in the directory $dir\n";
238
239 exit;
240
241
242 sub quant_question {
243   my ($ques, $default) = @_;
244
245   print $ques." [$default] : ";
246   
247   return get_user($default);
248 }
249
250 sub yn_question {
251   my ($ques, $default, $yans, $nans) = @_;
252   
253   my $ans;
254   
255   print $ques." [$default] : ";
256   $ans = get_user($default);
257   
258   if (substr($ans,0,1) eq 'y' || substr($ans,0,1) eq 'Y') { 
259     return $yans;
260   } else {
261     return $nans;
262   }
263 }
264
265 sub do_numa_config {
266   my ($cr, $pdir) =@_;
267   my %numa;
268   my $numpnodes;
269   my $numpcores;
270   my $numvnodes;
271   my $numvcores;
272   my $memblock="";
273   my $pernode;
274   my $lastnode;
275   my $i;
276   my @vnodemap;
277   my @vcoremap;
278   my $canauto=1;
279
280   %numa = get_numa_data();
281
282   $numvcores = $cr->{numcores};
283
284   print "NUMA configuration involves the following:\n";
285   print " 1. Definition of virtual NUMA nodes and their corresponding regions of guest physical memory\n";
286   print " 2. Mapping of virtual NUMA nodes to physical NUMA nodes\n";
287   print " 3. Mapping of virtual cores to virtual NUMA nodes\n";
288   print " 4. Mapping of virtual cores to physical cores\n";
289   print "Your guest contains ".$numvcores." virtual  cores.\n";
290   print "This host contains ".$numa{numcores}." physical cores and ".$numa{numnodes}." physical nodes.\n";
291   print "How many physical NUMA nodes does your target hardware have? [".$numa{numnodes}."] ? ";
292   $numpnodes=get_user($numa{numnodes});
293   $canauto=0 if ($numpnodes > $numa{numnodes});
294   print "How many physical cores does your target hardware have? [".$numa{numcores}."] ? ";
295   $numpcores=get_user($numa{numcores});
296   $canauto=0 if ($numpcores > $numa{numcores});
297   do {
298     print "How many virtual NUMA nodes do you want? (up to $numvcores) for auto) [2] : ";
299     $numvnodes=get_user("2");
300   } while ($numvnodes<=0 || $numvnodes>$numvcores);
301   $cr->{numnodes} = $numvnodes;
302   $pernode = int(($cr->{mem}*1024*1024)/$numvnodes);
303   $lastnode = $pernode + ($cr->{mem}*1024*1024)-$pernode*$numvnodes;
304   print "Your guest has ".$cr->{mem}." MB of RAM, which we have defined and mapped like this:\n";
305   for ($i=0;$i<$numvnodes;$i++) {
306     my $start=$i*$pernode;
307     my $end=(($i==($numvnodes-1)) ? $start+$lastnode : $start+$pernode);
308     my $pnode = $i % $numpnodes;
309     $vnodemap[$i]=$pnode;
310     $start=sprintf("0x%x",$start);
311     $end=sprintf("0x%x",$end);
312     print "vnode $i : GPA $start to GPA $end : pnode $pnode\n";
313     push @{$cr->{nodes}}, { start=>$start, end=>$end, vnode=>$i, pnode=>$pnode};
314   }
315   my $doauto=0;
316   if ($canauto) { 
317     print "We can now automatically map virtual cores to virtual NUMA nodes and physical CPUs using strided assignment\n";
318     print "assuming *this host's* NUMA configuration.  Or you can enter the assignments manually. \n";
319     print "  Which would you prefer {auto,manual} [auto] ? : ";
320     $doauto=1 if  (get_user("auto") eq "auto");
321   } else {
322     print "Automatic mapping of virtual cores to virtual NUMA nodes and physical CPUs is not possible\n";
323     print "given your host configuration.   Please configure manually below.\n";
324     $doauto=0;
325   }
326   if ($doauto) { 
327     for ($i=0;$i<$numvcores;$i++) { 
328       my $vnode = $i % $numvnodes;
329       my $pnode = $vnodemap[$vnode];
330       my $pcores = $numa{"node$pnode"}{cores};
331       my $numpcores_per_pnode = $#{$pcores}+1; # assumes identical number on each node...
332       my $pcore = $numa{"node$pnode"}{cores}->[int($i/$numpnodes) % $numpcores_per_pnode];
333       print "vcore $i : vnode $vnode : pnode $pnode : pcore $pcore\n";
334       $cr->{"core$i"}{pcore} = $pcore;
335       $cr->{"core$i"}{vnode} = $vnode;
336     }
337   } else {
338     for ($i=0;$i<$numvcores;$i++) { 
339       print "What is the virtual NUMA node for virtual core $i ? [] : ";
340       my $vnode = get_user("");
341       my $pnode = $vnodemap[$vnode];
342       print "That maps to physical NUMA node $pnode.\n";
343       print "What is the physical core for virtual core $i ? [] : ";
344       my $pcore = get_user("");
345       print "vcore $i : vnode $vnode : pnode $pnode : pcore $pcore\n";
346       $cr->{"core$i"}{pcore} = $pcore;
347       $cr->{"core$i"}{vnode} = $vnode;
348     }
349   }
350   $cr->{numa}=1;
351 }
352
353
354 sub get_numa_data() {
355   my $line;
356   my $maxnode=0;
357   my $maxcpu=0;
358   my %numa;
359
360   open (N, "numactl --hardware |");
361   while ($line=<N>) { 
362     if ($line=~/^node\s+(\d+)\s+cpus:\s+(.*)$/) { 
363       my $node=$1;
364       my @cpus = split(/\s+/,$2);
365       my $cpu;
366       if ($node>$maxnode) { $maxnode=$node; }
367       foreach $cpu (@cpus) { 
368         if ($cpu>$maxcpu) { $maxcpu=$cpu; }
369       }
370       $numa{"node$node"}{cores}=\@cpus;
371     }
372   }
373   $numa{numnodes}=$maxnode+1;
374   $numa{numcores}=$maxcpu+1;
375   return %numa;
376 }
377
378 sub do_device {
379   my ($cr,$pdir,$feature, $class, $id, $hardfail, $optblob, $nestblob) =@_;
380
381   if (is_palacios_core_feature_enabled($pdir, $feature)) {
382     print "We will include a $class since your Palacios build has it enabled\n";
383     add_device(\%config, $class, $id, $optblob, $nestblob);
384   } else {
385     if (defined($hardfail) && $hardfail) { 
386       print "Wow, your Palacios build doesn't have a $class... We can't live without that...\n";
387       exit -1;
388     } else {
389       print "Not configuring a $class since your Palacios build doesn't have it enabled\n";
390     }
391   }
392 }
393
394 sub do_consoles_and_ports {
395   my ($cr, $pdir) = @_;
396
397   my $cga = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_CGA");
398   my $curses = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_CURSES_CONSOLE");
399   my $cons = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_CONSOLE");
400   my $cancga = $cga && $curses && $cons;
401   my $vga = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_VGA");
402   my $gcons = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_GRAPHICS_CONSOLE");
403   my $canvga = $vga && $gcons;
404   my $serial = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_SERIAL_UART");
405   my $charstream = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_CHAR_STREAM");
406   my $stream = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_STREAM");
407   my $canserial = $serial && $charstream && $stream;
408   my $virtioconsole = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_LINUX_VIRTIO_CONSOLE");
409   my $canvirtioconsole = $virtioconsole; # probably need to verify frontend
410   my $paragraph = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_PARAGRAPH");
411   my $canparagraph = $paragraph && $gcons;
412
413   print "Your Palacios configuration allows the following options:\n";
414   print "  * CGA: classic 80x25 text-only PC console (common option): ".($cancga ? "available\n" : "NOT AVAILABLE\n");
415   print "  * VGA: classic 640x480 graphical PC console (uncommon option): ".($canvga ? "available\n" : "NOT AVAILABLE\n");
416   print "  * SERIAL: classic PC serial ports (common option): ".($canserial ? "available\n" : "NOT AVAILABLE\n");
417   print "  * VIRTIO: Linux Virtio Console (uncommon option): ".($canvirtioconsole ? "available\n" : "NOT AVAILABLE\n");
418   print "  * PARAGRAPH: Paravirtualized graphics card (uncommon option): ".($canparagraph ? "available\n" : "NOT AVAILABLE\n");
419   print "The CGA and VGA options are mutually exclusive\n";
420   print "THe VGA and PARAGRAPH options are mutually exclusive\n";
421   
422   if (!($cancga || $canvga || $canserial || $canvirtioconsole)) { 
423     print "Hmm... No console mechanism is enabled in your Palacios build...\n";
424     print "  This is probably not what you want...\n";
425 }
426   
427   $didcga=0;
428   if ($cancga) { 
429     print "Do you want to use CGA as a console? [y] : ";
430     if (get_user("y") eq "y") { 
431       add_device(\%config, "CGA_VIDEO", "cga", "passthrough=\"disable\"");
432       add_device(\%config, "CURSES_CONSOLE", "console", undef, 
433                  "    <frontend tag=\"cga\" />\n".
434                  "    <tty>user</tty>\n");
435       $didcga=1;
436     }
437   }
438   
439   $didvga=0;
440   if ($canvga && !$didcga) { 
441     print "Do you want to use VGA as a console? [n] : ";
442     if (get_user("n") eq "y") { 
443       add_device(\%config, "VGA", "vga", "passthrough=\"disable\" hostframebuf=\"enable\"");
444       # there is no gconsole device
445       $didvga=1;
446     }
447   }
448   
449   $didserial=0;
450   if ($canserial) {
451     print "You can include serial ports whether you use them for a console or not\n";
452     print "Note that you must configure your guest to place its console onto a serial port\n";
453     print "for it to be visible\n";
454     print "Do you want to include the serial ports (COM1..4) ? [y] : ";
455     if (get_user("y") eq "y") {
456       add_device(\%config,"SERIAL","serial");
457       add_device(\%config,"CHAR_STREAM","stream1","name=\"com1\"", "    <frontend tag=\"serial\" com_port=\"1\" />\n");
458       add_device(\%config,"CHAR_STREAM","stream2","name=\"com2\"", "    <frontend tag=\"serial\" com_port=\"2\" />\n");
459       add_device(\%config,"CHAR_STREAM","stream3","name=\"com3\"", "    <frontend tag=\"serial\" com_port=\"3\" />\n");
460       add_device(\%config,"CHAR_STREAM","stream4","name=\"com4\"", "    <frontend tag=\"serial\" com_port=\"4\" />\n");
461       $didserial=1;
462     }
463   }
464   
465   
466   $didvirtioconsole=0;
467   if ($canvirtioconsole) {
468     print "Do you want to add a VIRTIO console? [n] : ";
469     if (get_user("n") eq "y") { 
470       add_device(\%config,"LNX_VIRTIO_CONSOLE","virtio-cons",undef,"    <bus>pci0</bus>\n");
471       print "NOTE: no backend for the VIRTIO console is currently configured\n";
472       $didvirtioconsole=1;
473     }
474   }
475   
476   $didparagraph=0;
477   if ($canparagraph && !$didvga) {
478     print "Do you want to add a PARAGRAPH graphics card? [n] : ";
479     if (get_user("n") eq "y") {
480       add_device(\%config, "PARAGRAPH", "paragraph", undef,  
481                  "    <bus>pci0</bus>\n".
482                  "    <mode>gcons_mem</bus>\n");
483       $didparagraph=1;
484     }
485   }
486   
487   if (!($didcga || $didvga || $didserial || $didvirtioconsole || $didparagraph)) { 
488     print "You have configured your guest without any obvious way of interacting with it....\n";
489     print "  This is probably not what you want...\n";
490   } 
491
492
493
494 sub do_network {
495   my ($cr,$pdir,$dir,$name, $pcibus)=@_;
496   my $canvnet = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_VNET");
497   my $canbridge = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_NIC_BRIDGE");
498   my $canoverlay = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_VNET_NIC") && $canvnet; 
499   my $canvirtio = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_LINUX_VIRTIO_NET"); 
500   my $canvirtiovnet = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_LINUX_VIRTIO_VNET"); # not sure...
501   my $canne2k = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_NE2K"); 
502   my $canrtl8139 = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_RTL8139"); 
503   my @devs;
504   my @backends;
505   my $front;
506   my $back;
507   my $num;
508   my @test;
509   my $mac;
510
511   push @devs, "virtio" if $canvirtio;
512   push @devs, "rtl8139" if $canrtl8139;
513   push @devs, "ne2000" if $canne2k;
514
515   push @backends, "bridge" if $canbridge;
516   push @backends, "vnet" if $canoverlay;
517
518   if ($#devs==-1) { 
519     print "You have no network device implementations enabled in your Palacios build, so we are skipping networking\n";
520     return -1;
521   }
522   
523   if ($#backends==-1) { 
524     print "You have no network device backends enabled in your Palacios build, so we are skipping networking\n";
525     return -1;
526   }
527
528
529   $num=0;
530   while (1) { 
531     last if (!yn_question("Do you want to add ".($num==0 ? "a" : "another")." network device?","n",1,0));
532     print "This requires the addition of the frontend device (the NIC) and a backend device.\n";
533     print "Frontends in Palacios include:\n";
534     print "  * Virtio NIC (paravirtualized - common) : ".($canvirtio? "available" : "UNAVAILABLE")."\n";
535     print "  * RTL8139 NIC (uncommon) : ".($canrtl8139? "available" : "UNAVAILABLE")."\n";
536     print "  * NE2000 NIC (uncommon) : ".($canne2k? "available" : "UNAVAILABLE")."\n";
537     print "Which frontend do you want to add? {".join(", ", @devs)."} : ";
538     $front = get_user("");
539     @test = grep { /^$front$/ } @devs;
540     if ($#test!=0) { 
541       print "Unknown frontend\n"; 
542       next;
543     }
544     print "Backends in Palacios include:\n";
545     print "  * Bridge (direct attach to host NIC - common) : ".($canbridge? "available" : "UNAVAILABLE")."\n";
546     print "  * VNET overlay (uncommon) : ".($canoverlay ? "available" : "UNAVAILABLE")."\n";
547     print "Which backend do you want to add? {".join(", ", @backends)."} : ";
548     $back = get_user("");
549     @test = grep { /^$back/ } @backends;
550     if ($#test!=0) { 
551       print "Unknown backend\n"; 
552       next;
553     }
554     $mac=gen_macaddr();
555     print "What MAC address do you want your NIC to have? [$mac] : ";
556     $mac=get_user($mac);
557     if ($front eq "virtio") {
558        add_device($cr,"LNX_VIRTIO_NIC","net$num",undef,
559                   "    <bus>$pcibus</bus>\n".
560                   "    <mac>$mac</mac>\n".
561                   "    <model mode=\"guest-driven\" />\n");
562        print "The device is configured with default guest-driven operation\n";
563     }
564     if ($front eq "rtl8139") {
565        add_device($cr,"RTL8139","net$num",undef,
566                   "    <bus>$pcibus</bus>\n".
567                   "    <mac>$mac</mac>\n");
568     }
569     if ($front eq "ne2000") {
570        add_device($cr,"NE2000","net$num",undef,
571                   "    <bus>$pcibus</bus>\n".
572                   "    <mac>$mac</mac>\n");
573     }
574
575     if ($back eq "bridge") { 
576        my $host;
577        print "What is the name of the host NIC you want to bridge to? [eth0] : ";
578        $host=get_user("eth0");
579        add_device($cr,"NIC_BRIDGE","net$num-back",undef,
580                   "    <frontend tag=\"net$num\" />\n".
581                   "    <hostnic name=\"$host\" />\n");
582     }
583
584     if ($back eq "vnet") { 
585        add_device($cr,"VNET_NIC","net$num-back",undef,
586                   "    <frontend tag=\"net$num\" />\n");
587        print "Important: In order to use the VNET overlay, you must also create routes at run-time via /proc/v3vee/vnet\n";
588     }
589     $num++;
590   }
591  }
592
593
594 sub gen_macaddr {
595   return sprintf("%02X:%02X:%02X:%02X:%02X:%02X",
596                  int(rand(256)),
597                  int(rand(256)),
598                  int(rand(256)),
599                  int(rand(256)),
600                  int(rand(256)),
601                  int(rand(256)));
602 }
603                                                  
604
605 sub do_storage {
606   my ($cr,$pdir,$dir,$name,$pcibus,$controller)=@_;
607
608   # 
609   # IDE controller
610   #
611   do_device($cr, $pdir, "V3_CONFIG_IDE", "IDE", "ide0",1,undef,
612             "    <bus>$pcibus</bus>\n".
613             "    <controller>$controller</controller>\n" ); # must have
614   print "You can attach up to four storage devices to the storage controller \"ide\"\n";
615   do_storage_backend($cr, $pdir, $dir, $name, "ide0", "0_0", 
616                      "     <bus_num>0</bus_num>\n".
617                      "     <drive_num>0</drive_num>\n");
618   do_storage_backend($cr, $pdir, $dir, $name, "ide0", "0_1", 
619                    "     <bus_num>0</bus_num>\n".
620                    "     <drive_num>1</drive_num>\n");
621   do_storage_backend($cr, $pdir, $dir, $name, "ide0", "1_0", 
622                      "     <bus_num>1</bus_num>\n".
623                      "     <drive_num>0</drive_num>\n");
624   do_storage_backend($cr, $pdir, $dir, $name, "ide0", "1_1", 
625                      "     <bus_num>1</bus_num>\n".
626                    "     <drive_num>1</drive_num>\n");
627   
628   if (is_palacios_core_feature_enabled($pdir,"V3_CONFIG_LINUX_VIRTIO_BLOCK")) { 
629     print "You can attach VIRTIO block devices.  How many do you need? [0] : ";
630     my $num = get_user("0");
631     my $i;
632     for ($i=0;$i<$num;$i++) { 
633       add_device($cr,"LNX_VIRTIO_BLK","virtioblk$i",undef,"    <bus>$pcibus</bus>\n");
634       do_storage_backend($cr, $pdir, $dir, $name, "virtioblk$i", "data$i", "");
635     }
636   }
637 }
638
639
640 sub do_storage_backend {
641   my ($cr, $pdir, $dir, $name, $frontend, $loc, $frontendblock) = @_;
642   my ($canramdisk, $canfiledisk, $cannetdisk, $cantmpdisk);
643   my @devs=("cd","hd","nothing");
644   my @disks;
645   my $type;
646   my @type;
647   my $file;
648   my $size;
649
650   $canramdisk = is_palacios_core_feature_enabled($pdir, "V3_CONFIG_RAMDISK");
651   $canfiledisk = is_palacios_core_feature_enabled($pdir, "V3_CONFIG_FILEDISK");
652   $cannetdisk = is_palacios_core_feature_enabled($pdir, "V3_CONFIG_NETDISK");
653   $cantmpdisk = is_palacios_core_feature_enabled($pdir, "V3_CONFIG_TMPDISK");
654   push @disks, "ramdisk" if $canramdisk;
655   push @disks, "filedisk" if $canramdisk;
656   push @disks, "netdisk" if $cannetdisk;
657   push @disks, "tmpdisk" if $cantmpdisk;
658
659
660   if (!$canramdisk && !$canfiledisk && !$cannetdisk && !$cantmpdisk) {
661     print "You have no storage implementations enabled in your Palacios build, so it is impossible\n";
662     print "to add anything to storage controller \"$frontend\" location \"$loc\"\n";
663     return -1;
664   }
665    
666
667   while (1) { 
668     print "What do you want to attach to storage controller \"$frontend\" location \"$loc\"\n";
669     print "  Your options are {".join(", ",@devs)."} [nothing] : ";
670     $what = get_user("nothing");
671     @test = grep { /^$what$/ } @devs;
672     next if $#test!=0;
673     if ($what eq "nothing") {
674       return;
675     }
676     print "A storage device requires one of the following implementations\n";
677     print "  * RAMDISK - the data is kept in memory (common) : ".($canramdisk ? "available" : "UNAVAILABLE")."\n";
678     print "  * FILEDISK - the data is kept in a host file (common) : ".($canfiledisk ? "available" : "UNAVAILABLE")."\n";
679     print "  * NETDISK - the data is accessed via the network (uncommon) : ".($cannetdisk ? "available" : "UNAVAILABLE")."\n";
680     print "  * TMPDISK - the data is kept in memory and discarded (common) : ".($cantmpdisk ? "available" : "UNAVAILABLE")."\n";
681     print "  * RAMDISK - the data is kept in memory (common) : ".($canramdisk ? "available" : "UNAVAILABLE")."\n";
682     while (1) {
683       print "Which option do you want for this device? {".join(", ",@disks)."} [] : ";
684       $type = get_user("");
685       my @test = grep {/^$type$/} @disks;
686       last if $#test==0;
687     }
688
689     if ($type eq "filedisk" || $type eq "ramdisk") { 
690       print "$type requires a file (.iso for example).  Do you have one? [y] : ";
691       if (get_user("y") eq "y") { 
692         while (1) { 
693           print "What is its path? [] : ";
694           $file = get_user("");
695           if (!(-e $file)) {
696             print "$file does not exist\n";
697             next;
698           }
699           if (system("cp $file $dir/$frontend\_$loc.dat")) { 
700             print "Unable to copy $file\n";
701             next;
702           }
703           last;
704         }
705       } else {
706         print "We will make one.  How big should it be in MB? [64] : ";
707         $size = get_user("64");
708         gen_image_file("$dir/$frontend\_$loc.dat",$size);
709       }
710       $attach="    <frontend tag=\"$frontend\">\n";
711       if ($what eq "cd") { 
712         $attach.="     <model>V3VEE CDROM</model>\n".
713                  "     <type>CDROM</type>\n".$frontendblock;
714       } else {
715         $attach.="     <model>V3VEE HD</model>\n".
716                  "     <type>HD</type>\n".$frontendblock;
717       }
718       $attach.="    </frontend>\n";
719
720       if ($type eq "ramdisk") { 
721         add_device($cr,"RAMDISK","$frontend\_$loc", undef, 
722                    "    <file>$frontend\_$loc</file>\n".$attach);
723         add_file($cr, "$frontend\_$loc", "$frontend\_$loc.dat");
724       } else {
725         add_device($cr,"FILEDISK","$frontend\_$loc", $what eq "hd" ? "writable=\"1\"" : undef, 
726                    "    <path>$frontend\_$loc.dat</path>\n".$attach);
727       }
728       last;
729     } else {
730       print "$type is not currently supported\n";
731       next;
732     }
733   }
734 }
735
736
737 sub do_generic {
738   my ($cr, $pdir)=@_;
739
740   $block = <<GENERIC1
741     <ports> 
742       <!-- DMA 1 registers -->
743       <start>0x00</start>
744       <end>0x07</end>
745       <mode>PRINT_AND_IGNORE</mode>
746     </ports>
747     <ports>
748       <!-- DMA 2 registers -->
749       <start>0xc0</start>
750       <end>0xc7</end>
751       <mode>PRINT_AND_IGNORE</mode>
752     </ports>
753     <ports>
754      <!-- DMA 1 page registers -->
755      <start>0x81</start>
756      <end>0x87</end>
757      <mode>PRINT_AND_IGNORE</mode>
758     </ports>
759     <ports>
760      <!-- DMA 2 page registers -->
761      <start>0x88</start>
762      <end>0x8f</end>
763      <mode>PRINT_AND_IGNORE</mode>
764     </ports>
765     <ports>
766       <!-- DMA 1 Misc Registers -->
767       <start>0x08</start>
768       <end>0x0f</end>
769       <mode>PRINT_AND_IGNORE</mode>
770     </ports>
771     <ports>
772      <!-- DMA 2 Misc Registers -->
773      <start>0xd0</start>
774      <end>0xde</end>
775      <mode>PRINT_AND_IGNORE</mode>
776     </ports>
777     <ports>
778      <!-- ISA PNP -->
779      <start>0x274</start>
780      <end>0x277</end>
781      <mode>PRINT_AND_IGNORE</mode>
782     </ports>
783     <ports>
784      <!-- ISA PNP -->
785      <start>0x279</start>
786      <end>0x279</end>
787      <mode>PRINT_AND_IGNORE</mode>
788     </ports>
789     <ports>
790      <!-- ISA PNP -->
791      <start>0xa79</start>
792      <end>0xa79</end>
793      <mode>PRINT_AND_IGNORE</mode>
794     </ports>
795 GENERIC1
796 ;
797   my @dev = find_devices_by_class($cr,"PARALLEL");
798   if ($#dev<0) { 
799     $block .= <<GENERIC2
800     <ports>
801      <!-- Parallel Port -->
802      <start>0x378</start>
803      <end>0x37f</end>
804      <mode>PRINT_AND_IGNORE</mode>
805     </ports>
806 GENERIC2
807 ;
808   }
809   my @par = find_devices_by_class($cr,"SERIAL");
810   if ($#par<0) { 
811     $block .=<<GENERIC3
812     <ports>
813      <!-- Serial COM 1 -->
814      <start>0x3f8</start>
815      <end>0x3ff</end>
816      <mode>PRINT_AND_IGNORE</mode>
817     </ports>
818     <ports>
819      <!-- Serial COM 2 -->
820      <start>0x2f8</start>
821      <end>0x2ff</end>
822      <mode>PRINT_AND_IGNORE</mode>
823     </ports>
824     <ports>
825      <!-- Serial COM 3 -->
826      <start>0x3e8</start>
827      <end>0x3ef</end>
828      <mode>PRINT_AND_IGNORE</mode>
829     </ports>
830     <ports>
831     <!-- Serial COM 4 -->
832      <start>0x2e8</start>
833      <end>0x2ef</end>
834      <mode>PRINT_AND_IGNORE</mode>
835     </ports>
836 GENERIC3
837 ;
838   }
839
840   do_device($cr, $pdir, "V3_CONFIG_GENERIC", "GENERIC", "generic", 1, undef, $block);
841 }
842
843 sub add_file {
844   my ($cr, $name, $file) = @_;
845   
846   push @{$cr->{files}}, { name=>$name, file=>$file};
847
848 }
849
850 sub add_device {
851   my ($cr, $class, $id, $optblob, $nestblob) = @_;
852
853   push @{$cr->{devices}}, { class=>$class, id=>$id, opt=>$optblob, nest=>$nestblob };
854 }
855
856 sub find_devices_by_class {
857   my ($cr,$c)=@_;
858   return grep { $_->{class} eq $c } @{$cr->{devices}};
859 }
860
861 sub numa_setup {
862   my $cr =shift;
863   my $vnode;
864   my $s="";
865
866   if (!defined($cr->{numa})) { 
867     return "";
868   } else {
869     $s.=" <mem_layout vnodes=\"".($#{$cr->{nodes}}+1)."\" >\n";
870     foreach $vnode (@{$cr->{nodes}}) {
871       $s.="   <region start_addr=\"".$vnode->{start}."\" end_addr=\"".$vnode->{end}."\" vnode=\"".$vnode->{vnode}."\" node=\"".$vnode->{pnode}."\" />\n";
872     }
873     $s.=" </mem_layout>\n";
874     return $s;
875   }
876 }
877
878 sub core_setup  {
879   my $cr = shift;
880   my $i;
881   my $s="";
882   
883   
884   $s.= " <cores count=\"".$cr->{numcores}."\">\n";
885   if (!defined($cr->{numa})) { 
886     $s.= "  <core />\n";
887   } else {
888     for ($i=0;$i<$cr->{numcores};$i++) { 
889       $s.= "  <core target_cpu=\"".$cr->{"core$i"}{pcore}."\" vnode=\"".$cr->{"core$i"}{vnode}."\" />\n";
890     }
891   }
892   $s.= " </cores>\n";
893   
894   return $s;
895 }
896
897 sub memory_setup
898 {
899   my $cr=shift;
900
901   return " <memory>".$cr->{mem}."</memory>\n";
902 }
903
904 sub paging_setup  {
905   my $cr = shift;
906   my $s="";
907   
908   $s.= " <paging mode=\"".$cr->{paging_mode}."\">\n";
909   $s.= "  <large_pages>".$cr->{large_pages}."</large_pages>\n";
910   $s.= "  <strategy>".$cr->{shadow_strategy}."</strategy>\n";
911   $s.= " </paging>\n";
912   
913   return $s;
914 }
915
916 sub memmap_setup {
917   my $cr = shift;
918
919   return $cr->{memmap_block};
920 }
921
922 sub schedule_setup {
923   my $cr = shift;
924
925   return $cr->{schedule_hz_block};
926 }
927
928
929 sub perftune_setup  {
930   my $cr=shift;
931   my $s="";
932   if (defined($cr->{perftune_block})) { 
933     $s.=" <perftune>\n";
934     $s.= $cr->{perftune_block};
935     $s.=" </perftune>\n";
936   }
937   return $s;
938 }
939
940 sub extensions_setup  {
941   my $cr=shift;
942   my $s="";
943   if (defined($cr->{extensions_block})) { 
944     $s.=" <extensions>\n";
945     $s.= $cr->{extensions_block};
946     $s.=" </extensions>\n";
947   }
948   return $s;
949 }
950
951 sub telemetry_setup  {
952   my $cr=shift;
953   return " <telemetry>".$cr->{telemetry}."</telemetry>\n";
954 }
955
956 sub file_setup { 
957   my $cr=shift;
958   my $cf;
959   my $s="";
960
961   if (!defined($cr->{files})) { 
962     return " <!-- this configuration contains no files -->\n";
963   } else {
964
965     $s.=" <files>\n";
966    
967     foreach $cf (@{$cr->{files}}) {
968       $s.="   <file id=\"".$cf->{name}."\" filename=\"".$cf->{file}."\" />\n";
969     }
970     $s.=" </files>\n";
971     return $s;
972   }
973 }
974
975 sub device_setup { 
976   my $cr=shift;
977   my $cd;
978   my $s="";
979
980   $s.=" <devices>\n";
981
982   foreach $cd (@{$cr->{devices}}) {
983     $s.="   <device class=\"".$cd->{class}."\" id=\"".$cd->{id}."\"";
984     if (defined($cd->{opt})) { 
985       $s.=" ".$cd->{opt};
986     }
987     if (!defined($cd->{nest})) { 
988       $s.=" />\n";
989     } else {
990       $s.=" >\n";
991       $s.=$cd->{nest};
992       $s.="   </device>\n";
993     }
994   }
995
996   $s.=" </devices>\n";
997
998   return $s;
999
1000 }
1001
1002
1003
1004 sub get_user {
1005   my $def = shift;
1006   
1007   my $inp = <STDIN>; chomp($inp);
1008   
1009   if ($inp eq "") { 
1010     return $def;
1011   } else {
1012     return $inp;
1013   }
1014 }
1015
1016 sub get_kernel_feature {
1017   my $dir=shift;
1018   my $feature=shift;
1019   my $x;
1020
1021   $x=`grep $feature= $dir/config-\`uname -r\``;
1022
1023   if ($x=~/^\s*\#/) {
1024     return undef;
1025   } else {
1026     if ($x=~/\s*$feature=\s*(\S*)\s*$/) {
1027       return $1;
1028     } else {
1029       return undef;
1030     }
1031   }
1032 }
1033   
1034 sub get_palacios_core_feature {
1035   my $dir=shift;
1036   my $feature=shift;
1037   my $x;
1038
1039   $x=`grep $feature= $dir/.config`;
1040
1041   if ($x=~/^\s*\#/) {
1042     return undef;
1043   } else {
1044     if ($x=~/\s*$feature=\s*(\S*)\s*$/) {
1045       return $1;
1046     } else {
1047       return undef;
1048     }
1049   }
1050 }
1051
1052 sub is_palacios_core_feature_enabled {
1053   my $out = get_palacios_core_feature(@_);
1054   return !defined($out) ? 0 : $out eq "y";
1055 }
1056
1057
1058 sub powerof2  {
1059   my $x = shift;
1060   my $exp;
1061   
1062   $exp = log($x) /log(2);
1063
1064   return $exp==int($exp);
1065 }
1066
1067
1068 sub gen_image_file {
1069   my ($name, $size_mb) = @_;
1070
1071   if (system("dd if=/dev/zero of=$name bs=1048576 count=$size_mb")) { 
1072     return -1;
1073   } else  {
1074     return 0;
1075   }
1076 }