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.


Additional sanity-checks for guest configuration (v3_config_guest.pl)
[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-space 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
196 #
197 # Network interfaces (attached to PCI bus)
198 #
199 #
200 print "\nWe will now consider network interfaces.\n\n";
201 do_network(\%config, $pdir, $dir, $name, "pci0", "southbridge");
202
203
204 #
205 # Sanity-check - is there something bootable?
206 #
207 #
208 if (!($config{havecd} && !($config{havehd}))) {
209   print "The guest's storage configuration does not have either a CD or an HD.  \n";
210   print "This means the guest BIOS will have nothing local to boot.  \n";
211   if (!($config{havenic})) { 
212     print "The guest also does does not have a NIC, which means the BIOS cannot\n";
213     print "do a network boot.\n";
214   } else {
215     print "The guest does have a NIC, so a network boot is possible, if the\n";
216     print "BIOS supports it.\n";
217   }
218   print "If this is not your intent, you probably want to CTRL-C and try again.\n";
219 }
220
221 print "The BIOS boot sequence will be set to CD,HD.   If you need to change this\n";
222 print "later, edit the <bootseq> block within the NVRAM device.\n";
223
224 #
225 # NVRAM 
226 #
227 # Note: do_storage *must* have placed an IDE named ide0 in order for this to work
228 #
229 do_device(\%config, $pdir, "V3_CONFIG_NVRAM", "NVRAM", "nvram", 1, undef, "     <storage>ide0</storage>\n     <bootseq>cd,hd</bootseq>\n"); #must have
230
231 #
232 #
233 # Generic Catch-all Device
234 #
235 do_generic(\%config, $pdir);
236
237
238 open(PAL,">$dir/$name.pal") or die "Cannot open $dir/$name.pal\n";
239
240 $target = PAL;
241
242 print $target "<vm class=\"PC\">\n\n";
243 print $target file_setup(\%config), "\n";
244 print $target memory_setup(\%config), "\n";
245 print $target paging_setup(\%config), "\n";
246 print $target memmap_setup(\%config), "\n";
247 print $target numa_setup(\%config), "\n";
248 print $target core_setup(\%config), "\n";
249 print $target schedule_setup(\%config), "\n";
250 print $target perftune_setup(\%config), "\n";
251 print $target telemetry_setup(\%config), "\n";
252 print $target extensions_setup(\%config), "\n";
253 print $target device_setup(\%config), "\n";
254 print $target "</vm>\n";
255
256 close(PAL);
257
258 print "\n\nYour guest is now ready in the directory $dir\n\n";
259 print "To run it, do:\n\n";
260 print "  cd $dir\n";
261 print "  v3_create -b $name.pal $name\n";
262 print "  v3_launch /dev/v3-vmN (N given by v3_create)\n\n";
263 print "Other useful tools:\n\n";
264 print "  v3_console (CGA console)\n";
265 print "  v3_stream (connect to stream, for example, serial port)\n\n";
266
267 exit;
268
269
270 sub quant_question {
271   my ($ques, $default) = @_;
272
273   print $ques." [$default] : ";
274   
275   return get_user($default);
276 }
277
278 sub yn_question {
279   my ($ques, $default, $yans, $nans) = @_;
280   
281   my $ans;
282   
283   print $ques." [$default] : ";
284   $ans = get_user($default);
285   
286   if (substr($ans,0,1) eq 'y' || substr($ans,0,1) eq 'Y') { 
287     return $yans;
288   } else {
289     return $nans;
290   }
291 }
292
293 sub do_numa_config {
294   my ($cr, $pdir) =@_;
295   my %numa;
296   my $numpnodes;
297   my $numpcores;
298   my $numvnodes;
299   my $numvcores;
300   my $memblock="";
301   my $pernode;
302   my $lastnode;
303   my $i;
304   my @vnodemap;
305   my @vcoremap;
306   my $canauto=1;
307
308   %numa = get_numa_data();
309
310   $numvcores = $cr->{numcores};
311
312   print "NUMA configuration involves the following:\n";
313   print " 1. Definition of virtual NUMA nodes and their corresponding regions of guest physical memory\n";
314   print " 2. Mapping of virtual NUMA nodes to physical NUMA nodes\n";
315   print " 3. Mapping of virtual cores to virtual NUMA nodes\n";
316   print " 4. Mapping of virtual cores to physical cores\n";
317   print "Your guest contains ".$numvcores." virtual  cores.\n";
318   print "This host contains ".$numa{numcores}." physical cores and ".$numa{numnodes}." physical nodes.\n";
319   print "How many physical NUMA nodes does your target hardware have? [".$numa{numnodes}."] ? ";
320   $numpnodes=get_user($numa{numnodes});
321   $canauto=0 if ($numpnodes > $numa{numnodes});
322   print "How many physical cores does your target hardware have? [".$numa{numcores}."] ? ";
323   $numpcores=get_user($numa{numcores});
324   $canauto=0 if ($numpcores > $numa{numcores});
325   do {
326     print "How many virtual NUMA nodes do you want? (up to $numvcores) for auto) [2] : ";
327     $numvnodes=get_user("2");
328   } while ($numvnodes<=0 || $numvnodes>$numvcores);
329   $cr->{numnodes} = $numvnodes;
330   $pernode = int(($cr->{mem}*1024*1024)/$numvnodes);
331   $lastnode = $pernode + ($cr->{mem}*1024*1024)-$pernode*$numvnodes;
332   print "Your guest has ".$cr->{mem}." MB of RAM, which we have defined and mapped like this:\n";
333   for ($i=0;$i<$numvnodes;$i++) {
334     my $start=$i*$pernode;
335     my $end=(($i==($numvnodes-1)) ? $start+$lastnode : $start+$pernode);
336     my $pnode = $i % $numpnodes;
337     $vnodemap[$i]=$pnode;
338     $start=sprintf("0x%x",$start);
339     $end=sprintf("0x%x",$end);
340     print "vnode $i : GPA $start to GPA $end : pnode $pnode\n";
341     push @{$cr->{nodes}}, { start=>$start, end=>$end, vnode=>$i, pnode=>$pnode};
342   }
343   my $doauto=0;
344   if ($canauto) { 
345     print "We can now automatically map virtual cores to virtual NUMA nodes and physical CPUs using strided assignment\n";
346     print "assuming *this host's* NUMA configuration.  Or you can enter the assignments manually. \n";
347     print "  Which would you prefer {auto,manual} [auto] ? : ";
348     $doauto=1 if  (get_user("auto") eq "auto");
349   } else {
350     print "Automatic mapping of virtual cores to virtual NUMA nodes and physical CPUs is not possible\n";
351     print "given your host configuration.   Please configure manually below.\n";
352     $doauto=0;
353   }
354   if ($doauto) { 
355     for ($i=0;$i<$numvcores;$i++) { 
356       my $vnode = $i % $numvnodes;
357       my $pnode = $vnodemap[$vnode];
358       my $pcores = $numa{"node$pnode"}{cores};
359       my $numpcores_per_pnode = $#{$pcores}+1; # assumes identical number on each node...
360       my $pcore = $numa{"node$pnode"}{cores}->[int($i/$numpnodes) % $numpcores_per_pnode];
361       print "vcore $i : vnode $vnode : pnode $pnode : pcore $pcore\n";
362       $cr->{"core$i"}{pcore} = $pcore;
363       $cr->{"core$i"}{vnode} = $vnode;
364     }
365   } else {
366     for ($i=0;$i<$numvcores;$i++) { 
367       print "What is the virtual NUMA node for virtual core $i ? [] : ";
368       my $vnode = get_user("");
369       my $pnode = $vnodemap[$vnode];
370       print "That maps to physical NUMA node $pnode.\n";
371       print "What is the physical core for virtual core $i ? [] : ";
372       my $pcore = get_user("");
373       print "vcore $i : vnode $vnode : pnode $pnode : pcore $pcore\n";
374       $cr->{"core$i"}{pcore} = $pcore;
375       $cr->{"core$i"}{vnode} = $vnode;
376     }
377   }
378   $cr->{numa}=1;
379 }
380
381
382 sub get_numa_data() {
383   my $line;
384   my $maxnode=0;
385   my $maxcpu=0;
386   my %numa;
387
388   open (N, "numactl --hardware |");
389   while ($line=<N>) { 
390     if ($line=~/^node\s+(\d+)\s+cpus:\s+(.*)$/) { 
391       my $node=$1;
392       my @cpus = split(/\s+/,$2);
393       my $cpu;
394       if ($node>$maxnode) { $maxnode=$node; }
395       foreach $cpu (@cpus) { 
396         if ($cpu>$maxcpu) { $maxcpu=$cpu; }
397       }
398       $numa{"node$node"}{cores}=\@cpus;
399     }
400   }
401   $numa{numnodes}=$maxnode+1;
402   $numa{numcores}=$maxcpu+1;
403   return %numa;
404 }
405
406 sub do_device {
407   my ($cr,$pdir,$feature, $class, $id, $hardfail, $optblob, $nestblob) =@_;
408
409   if (is_palacios_core_feature_enabled($pdir, $feature)) {
410     print "We will include a $class since your Palacios build has it enabled\n";
411     add_device(\%config, $class, $id, $optblob, $nestblob);
412   } else {
413     if (defined($hardfail) && $hardfail) { 
414       print "Wow, your Palacios build doesn't have a $class... We can't live without that...\n";
415       exit -1;
416     } else {
417       print "Not configuring a $class since your Palacios build doesn't have it enabled\n";
418     }
419   }
420 }
421
422 sub do_consoles_and_ports {
423   my ($cr, $pdir) = @_;
424
425   my $cga = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_CGA");
426   my $curses = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_CURSES_CONSOLE");
427   my $cons = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_CONSOLE");
428   my $cancga = $cga && $curses && $cons;
429   my $vga = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_VGA");
430   my $gcons = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_GRAPHICS_CONSOLE");
431   my $canvga = $vga && $gcons;
432   my $serial = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_SERIAL_UART");
433   my $charstream = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_CHAR_STREAM");
434   my $stream = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_STREAM");
435   my $canserial = $serial && $charstream && $stream;
436   my $virtioconsole = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_LINUX_VIRTIO_CONSOLE");
437   my $canvirtioconsole = $virtioconsole; # probably need to verify frontend
438   my $paragraph = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_PARAGRAPH");
439   my $canparagraph = $paragraph && $gcons;
440
441   print "Your Palacios configuration allows the following options:\n";
442   print "  * CGA: classic 80x25 text-only PC console (common option): ".($cancga ? "available\n" : "NOT AVAILABLE\n");
443   print "  * VGA: classic 640x480 graphical PC console (uncommon option): ".($canvga ? "available\n" : "NOT AVAILABLE\n");
444   print "  * SERIAL: classic PC serial ports (common option): ".($canserial ? "available\n" : "NOT AVAILABLE\n");
445   print "  * VIRTIO: Linux Virtio Console (uncommon option): ".($canvirtioconsole ? "available\n" : "NOT AVAILABLE\n");
446   print "  * PARAGRAPH: Paravirtualized graphics card (uncommon option): ".($canparagraph ? "available\n" : "NOT AVAILABLE\n");
447   print "The CGA and VGA options are mutually exclusive\n";
448   print "THe VGA and PARAGRAPH options are mutually exclusive\n";
449   
450   if (!($cancga || $canvga || $canserial || $canvirtioconsole)) { 
451     print "Hmm... No console mechanism is enabled in your Palacios build...\n";
452     print "  This is probably not what you want...\n";
453   }
454   
455   $didcga=0;
456   if ($cancga) { 
457     print "Do you want to use CGA as a console? [y] : ";
458     if (get_user("y") eq "y") { 
459       add_device(\%config, "CGA_VIDEO", "cga", "passthrough=\"disable\"");
460       add_device(\%config, "CURSES_CONSOLE", "console", undef, 
461                  "    <frontend tag=\"cga\" />\n".
462                  "    <tty>user</tty>\n");
463       $didcga=1;
464     }
465   }
466   
467   $didvga=0;
468   if ($canvga && !$didcga) { 
469     print "Do you want to use VGA as a console? [n] : ";
470     if (get_user("n") eq "y") { 
471       add_device(\%config, "VGA", "vga", "passthrough=\"disable\" hostframebuf=\"enable\"");
472       # there is no gconsole device
473       $didvga=1;
474     }
475   }
476   
477   $didserial=0;
478   if ($canserial) {
479     print "You can include serial ports whether you use them for a console or not\n";
480     print "Note that you must configure your guest to place its console onto a serial port\n";
481     print "for it to be visible\n";
482     print "Do you want to include the serial ports (COM1..4) ? [y] : ";
483     if (get_user("y") eq "y") {
484       add_device(\%config,"SERIAL","serial");
485       add_device(\%config,"CHAR_STREAM","stream1","name=\"com1\"", "    <frontend tag=\"serial\" com_port=\"1\" />\n");
486       add_device(\%config,"CHAR_STREAM","stream2","name=\"com2\"", "    <frontend tag=\"serial\" com_port=\"2\" />\n");
487       add_device(\%config,"CHAR_STREAM","stream3","name=\"com3\"", "    <frontend tag=\"serial\" com_port=\"3\" />\n");
488       add_device(\%config,"CHAR_STREAM","stream4","name=\"com4\"", "    <frontend tag=\"serial\" com_port=\"4\" />\n");
489       $didserial=1;
490     }
491   }
492   
493   
494   $didvirtioconsole=0;
495   if ($canvirtioconsole) {
496     print "Do you want to add a VIRTIO console? [n] : ";
497     if (get_user("n") eq "y") { 
498       add_device(\%config,"LNX_VIRTIO_CONSOLE","virtio-cons",undef,"    <bus>pci0</bus>\n");
499       print "NOTE: no backend for the VIRTIO console is currently configured\n";
500       $didvirtioconsole=1;
501     }
502   }
503   
504   $didparagraph=0;
505   if ($canparagraph && !$didvga) {
506     print "Do you want to add a PARAGRAPH graphics card? [n] : ";
507     if (get_user("n") eq "y") {
508       add_device(\%config, "PARAGRAPH", "paragraph", undef,  
509                  "    <bus>pci0</bus>\n".
510                  "    <mode>gcons_mem</bus>\n");
511       $didparagraph=1;
512     }
513   }
514   
515   if (!($didcga || $didvga || $didserial || $didvirtioconsole || $didparagraph)) { 
516     print "You have configured your guest without any obvious way of interacting with it....\n";
517     print "  This is probably not what you want...\n";
518   } 
519
520
521
522
523 sub do_network {
524   my ($cr,$pdir,$dir,$name, $pcibus)=@_;
525   my $canvnet = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_VNET");
526   my $canbridge = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_NIC_BRIDGE");
527   my $canoverlay = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_VNET_NIC") && $canvnet; 
528   my $canvirtio = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_LINUX_VIRTIO_NET"); 
529   my $canvirtiovnet = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_LINUX_VIRTIO_VNET"); # not sure...
530   my $canne2k = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_NE2K"); 
531   my $canrtl8139 = is_palacios_core_feature_enabled($pdir,"V3_CONFIG_RTL8139"); 
532   my @devs;
533   my @backends;
534   my $front;
535   my $back;
536   my $num;
537   my @test;
538   my $mac;
539
540   push @devs, "virtio" if $canvirtio;
541   push @devs, "rtl8139" if $canrtl8139;
542   push @devs, "ne2000" if $canne2k;
543
544   push @backends, "bridge" if $canbridge;
545   push @backends, "vnet" if $canoverlay;
546
547   if ($#devs==-1) { 
548     print "You have no network device implementations enabled in your Palacios build, so we are skipping networking\n";
549     return -1;
550   }
551   
552   if ($#backends==-1) { 
553     print "You have no network device backends enabled in your Palacios build, so we are skipping networking\n";
554     return -1;
555   }
556
557
558   $num=0;
559   while (1) { 
560     last if (!yn_question("Do you want to add ".($num==0 ? "a" : "another")." network device?","n",1,0));
561     print "This requires the addition of the frontend device (the NIC) and a backend device.\n";
562     print "Frontends in Palacios include:\n";
563     print "  * Virtio NIC (paravirtualized - common) : ".($canvirtio? "available" : "UNAVAILABLE")."\n";
564     print "  * RTL8139 NIC (uncommon) : ".($canrtl8139? "available" : "UNAVAILABLE")."\n";
565     print "  * NE2000 NIC (uncommon) : ".($canne2k? "available" : "UNAVAILABLE")."\n";
566     print "Which frontend do you want to add? {".join(", ", @devs)."} : ";
567     $front = get_user("");
568     @test = grep { /^$front$/ } @devs;
569     if ($#test!=0) { 
570       print "Unknown frontend\n"; 
571       next;
572     }
573     print "Backends in Palacios include:\n";
574     print "  * Bridge (direct attach to host NIC - common) : ".($canbridge? "available" : "UNAVAILABLE")."\n";
575     print "  * VNET overlay (uncommon) : ".($canoverlay ? "available" : "UNAVAILABLE")."\n";
576     print "Which backend do you want to add? {".join(", ", @backends)."} : ";
577     $back = get_user("");
578     @test = grep { /^$back/ } @backends;
579     if ($#test!=0) { 
580       print "Unknown backend\n"; 
581       next;
582     }
583     $mac=gen_macaddr();
584     print "What MAC address do you want your NIC to have? [$mac] : ";
585     $mac=get_user($mac);
586     if ($front eq "virtio") {
587        add_device($cr,"LNX_VIRTIO_NIC","net$num",undef,
588                   "    <bus>$pcibus</bus>\n".
589                   "    <mac>$mac</mac>\n".
590                   "    <model mode=\"guest-driven\" />\n");
591        print "The device is configured with default guest-driven operation\n";
592     }
593     if ($front eq "rtl8139") {
594        add_device($cr,"RTL8139","net$num",undef,
595                   "    <bus>$pcibus</bus>\n".
596                   "    <mac>$mac</mac>\n");
597     }
598     if ($front eq "ne2000") {
599        add_device($cr,"NE2000","net$num",undef,
600                   "    <bus>$pcibus</bus>\n".
601                   "    <mac>$mac</mac>\n");
602     }
603
604     if ($back eq "bridge") { 
605        my $host;
606        print "What is the name of the host NIC you want to bridge to? [eth0] : ";
607        $host=get_user("eth0");
608        add_device($cr,"NIC_BRIDGE","net$num-back",undef,
609                   "    <frontend tag=\"net$num\" />\n".
610                   "    <hostnic name=\"$host\" />\n");
611     }
612
613     if ($back eq "vnet") { 
614        add_device($cr,"VNET_NIC","net$num-back",undef,
615                   "    <frontend tag=\"net$num\" />\n");
616        print "Important: In order to use the VNET overlay, you must also create routes at run-time via /proc/v3vee/vnet\n";
617     }
618     $num++;
619   }
620
621   if ($num>0) { 
622     $cr->{havenic}=1;
623   }
624  }
625
626
627 sub gen_macaddr {
628   return sprintf("%02X:%02X:%02X:%02X:%02X:%02X",
629                  int(rand(256)),
630                  int(rand(256)),
631                  int(rand(256)),
632                  int(rand(256)),
633                  int(rand(256)),
634                  int(rand(256)));
635 }
636                                                  
637
638 sub do_storage {
639   my ($cr,$pdir,$dir,$name,$pcibus,$controller)=@_;
640
641   # 
642   # IDE controller
643   #
644   do_device($cr, $pdir, "V3_CONFIG_IDE", "IDE", "ide0",1,undef,
645             "    <bus>$pcibus</bus>\n".
646             "    <controller>$controller</controller>\n" ); # must have
647   print "You can attach up to four storage devices to the storage controller \"ide\"\n";
648   do_storage_backend($cr, $pdir, $dir, $name, "ide0", "0_0", 
649                      "     <bus_num>0</bus_num>\n".
650                      "     <drive_num>0</drive_num>\n");
651   do_storage_backend($cr, $pdir, $dir, $name, "ide0", "0_1", 
652                    "     <bus_num>0</bus_num>\n".
653                    "     <drive_num>1</drive_num>\n");
654   do_storage_backend($cr, $pdir, $dir, $name, "ide0", "1_0", 
655                      "     <bus_num>1</bus_num>\n".
656                      "     <drive_num>0</drive_num>\n");
657   do_storage_backend($cr, $pdir, $dir, $name, "ide0", "1_1", 
658                      "     <bus_num>1</bus_num>\n".
659                    "     <drive_num>1</drive_num>\n");
660   
661   if (is_palacios_core_feature_enabled($pdir,"V3_CONFIG_LINUX_VIRTIO_BLOCK")) { 
662     print "You can attach VIRTIO block devices.  How many do you need? [0] : ";
663     my $num = get_user("0");
664     my $i;
665     for ($i=0;$i<$num;$i++) { 
666       add_device($cr,"LNX_VIRTIO_BLK","virtioblk$i",undef,"    <bus>$pcibus</bus>\n");
667       do_storage_backend($cr, $pdir, $dir, $name, "virtioblk$i", "data$i", "");
668     }
669   }
670
671 }      
672
673
674
675 sub do_storage_backend {
676   my ($cr, $pdir, $dir, $name, $frontend, $loc, $frontendblock) = @_;
677   my ($canramdisk, $canfiledisk, $cannetdisk, $cantmpdisk);
678   my @devs=("cd","hd","nothing");
679   my @disks;
680   my $type;
681   my @type;
682   my $file;
683   my $size;
684
685   $canramdisk = is_palacios_core_feature_enabled($pdir, "V3_CONFIG_RAMDISK");
686   $canfiledisk = is_palacios_core_feature_enabled($pdir, "V3_CONFIG_FILEDISK");
687   $cannetdisk = is_palacios_core_feature_enabled($pdir, "V3_CONFIG_NETDISK");
688   $cantmpdisk = is_palacios_core_feature_enabled($pdir, "V3_CONFIG_TMPDISK");
689   push @disks, "ramdisk" if $canramdisk;
690   push @disks, "filedisk" if $canramdisk;
691   push @disks, "netdisk" if $cannetdisk;
692   push @disks, "tmpdisk" if $cantmpdisk;
693
694
695   if (!$canramdisk && !$canfiledisk && !$cannetdisk && !$cantmpdisk) {
696     print "You have no storage implementations enabled in your Palacios build, so it is impossible\n";
697     print "to add anything to storage controller \"$frontend\" location \"$loc\"\n";
698     return -1;
699   }
700    
701
702   while (1) { 
703     print "What do you want to attach to storage controller \"$frontend\" location \"$loc\"\n";
704     print "  Your options are {".join(", ",@devs)."} [nothing] : ";
705     $what = get_user("nothing");
706     @test = grep { /^$what$/ } @devs;
707     next if $#test!=0;
708     if ($what eq "nothing") {
709       return;
710     }
711     print "A storage device requires one of the following implementations\n";
712     print "  * RAMDISK - the data is kept in memory (common) : ".($canramdisk ? "available" : "UNAVAILABLE")."\n";
713     print "  * FILEDISK - the data is kept in a host file (common) : ".($canfiledisk ? "available" : "UNAVAILABLE")."\n";
714     print "  * NETDISK - the data is accessed via the network (uncommon) : ".($cannetdisk ? "available" : "UNAVAILABLE")."\n";
715     print "  * TMPDISK - the data is kept in memory and discarded (common) : ".($cantmpdisk ? "available" : "UNAVAILABLE")."\n";
716     while (1) {
717       print "Which option do you want for this device? {".join(", ",@disks)."} [] : ";
718       $type = get_user("");
719       my @test = grep {/^$type$/} @disks;
720       last if $#test==0;
721     }
722
723     if ($type eq "filedisk" || $type eq "ramdisk") { 
724       print "$type requires a file (.iso for example).  Do you have one? [y] : ";
725       if (get_user("y") eq "y") { 
726         while (1) { 
727           print "What is its path? [] : ";
728           $file = get_user("");
729           if (!(-e $file)) {
730             print "$file does not exist\n";
731             next;
732           }
733           if (system("cp $file $dir/$frontend\_$loc.dat")) { 
734             print "Unable to copy $file\n";
735             next;
736           }
737           last;
738         }
739       } else {
740         print "We will make one.  How big should it be in MB? [64] : ";
741         $size = get_user("64");
742         gen_image_file("$dir/$frontend\_$loc.dat",$size);
743       }
744       $attach="    <frontend tag=\"$frontend\">\n";
745       if ($what eq "cd") { 
746         $attach.="     <model>V3VEE CDROM</model>\n".
747                  "     <type>CDROM</type>\n".$frontendblock;
748         $cr->{havecd}=1;
749       } else {
750         $attach.="     <model>V3VEE HD</model>\n".
751                  "     <type>HD</type>\n".$frontendblock;
752         $cr->{havehd}=1;
753       }
754       $attach.="    </frontend>\n";
755
756       if ($type eq "ramdisk") { 
757         add_device($cr,"RAMDISK","$frontend\_$loc", undef, 
758                    "    <file>$frontend\_$loc</file>\n".$attach);
759         add_file($cr, "$frontend\_$loc", "$frontend\_$loc.dat");
760       } else {
761         add_device($cr,"FILEDISK","$frontend\_$loc", $what eq "hd" ? "writable=\"1\"" : undef, 
762                    "    <path>$frontend\_$loc.dat</path>\n".$attach);
763       }
764       last;
765     } else {
766       print "$type is not currently supported\n";
767       next;
768     }
769   }
770 }
771
772
773 sub do_generic {
774   my ($cr, $pdir)=@_;
775
776   $block = <<GENERIC1
777     <ports> 
778       <!-- DMA 1 registers -->
779       <start>0x00</start>
780       <end>0x07</end>
781       <mode>PRINT_AND_IGNORE</mode>
782     </ports>
783     <ports>
784       <!-- DMA 2 registers -->
785       <start>0xc0</start>
786       <end>0xc7</end>
787       <mode>PRINT_AND_IGNORE</mode>
788     </ports>
789     <ports>
790      <!-- DMA 1 page registers -->
791      <start>0x81</start>
792      <end>0x87</end>
793      <mode>PRINT_AND_IGNORE</mode>
794     </ports>
795     <ports>
796      <!-- DMA 2 page registers -->
797      <start>0x88</start>
798      <end>0x8f</end>
799      <mode>PRINT_AND_IGNORE</mode>
800     </ports>
801     <ports>
802       <!-- DMA 1 Misc Registers -->
803       <start>0x08</start>
804       <end>0x0f</end>
805       <mode>PRINT_AND_IGNORE</mode>
806     </ports>
807     <ports>
808      <!-- DMA 2 Misc Registers -->
809      <start>0xd0</start>
810      <end>0xde</end>
811      <mode>PRINT_AND_IGNORE</mode>
812     </ports>
813     <ports>
814      <!-- ISA PNP -->
815      <start>0x274</start>
816      <end>0x277</end>
817      <mode>PRINT_AND_IGNORE</mode>
818     </ports>
819     <ports>
820      <!-- ISA PNP -->
821      <start>0x279</start>
822      <end>0x279</end>
823      <mode>PRINT_AND_IGNORE</mode>
824     </ports>
825     <ports>
826      <!-- ISA PNP -->
827      <start>0xa79</start>
828      <end>0xa79</end>
829      <mode>PRINT_AND_IGNORE</mode>
830     </ports>
831 GENERIC1
832 ;
833   my @dev = find_devices_by_class($cr,"PARALLEL");
834   if ($#dev<0) { 
835     $block .= <<GENERIC2
836     <ports>
837      <!-- Parallel Port -->
838      <start>0x378</start>
839      <end>0x37f</end>
840      <mode>PRINT_AND_IGNORE</mode>
841     </ports>
842 GENERIC2
843 ;
844   }
845   my @par = find_devices_by_class($cr,"SERIAL");
846   if ($#par<0) { 
847     $block .=<<GENERIC3
848     <ports>
849      <!-- Serial COM 1 -->
850      <start>0x3f8</start>
851      <end>0x3ff</end>
852      <mode>PRINT_AND_IGNORE</mode>
853     </ports>
854     <ports>
855      <!-- Serial COM 2 -->
856      <start>0x2f8</start>
857      <end>0x2ff</end>
858      <mode>PRINT_AND_IGNORE</mode>
859     </ports>
860     <ports>
861      <!-- Serial COM 3 -->
862      <start>0x3e8</start>
863      <end>0x3ef</end>
864      <mode>PRINT_AND_IGNORE</mode>
865     </ports>
866     <ports>
867     <!-- Serial COM 4 -->
868      <start>0x2e8</start>
869      <end>0x2ef</end>
870      <mode>PRINT_AND_IGNORE</mode>
871     </ports>
872 GENERIC3
873 ;
874   }
875
876   do_device($cr, $pdir, "V3_CONFIG_GENERIC", "GENERIC", "generic", 1, undef, $block);
877 }
878
879 sub add_file {
880   my ($cr, $name, $file) = @_;
881   
882   push @{$cr->{files}}, { name=>$name, file=>$file};
883
884 }
885
886 sub add_device {
887   my ($cr, $class, $id, $optblob, $nestblob) = @_;
888
889   push @{$cr->{devices}}, { class=>$class, id=>$id, opt=>$optblob, nest=>$nestblob };
890 }
891
892 sub find_devices_by_class {
893   my ($cr,$c)=@_;
894   return grep { $_->{class} eq $c } @{$cr->{devices}};
895 }
896
897 sub numa_setup {
898   my $cr =shift;
899   my $vnode;
900   my $s="";
901
902   if (!defined($cr->{numa})) { 
903     return "";
904   } else {
905     $s.=" <mem_layout vnodes=\"".($#{$cr->{nodes}}+1)."\" >\n";
906     foreach $vnode (@{$cr->{nodes}}) {
907       $s.="   <region start_addr=\"".$vnode->{start}."\" end_addr=\"".$vnode->{end}."\" vnode=\"".$vnode->{vnode}."\" node=\"".$vnode->{pnode}."\" />\n";
908     }
909     $s.=" </mem_layout>\n";
910     return $s;
911   }
912 }
913
914 sub core_setup  {
915   my $cr = shift;
916   my $i;
917   my $s="";
918   
919   
920   $s.= " <cores count=\"".$cr->{numcores}."\">\n";
921   if (!defined($cr->{numa})) { 
922     $s.= "  <core />\n";
923   } else {
924     for ($i=0;$i<$cr->{numcores};$i++) { 
925       $s.= "  <core target_cpu=\"".$cr->{"core$i"}{pcore}."\" vnode=\"".$cr->{"core$i"}{vnode}."\" />\n";
926     }
927   }
928   $s.= " </cores>\n";
929   
930   return $s;
931 }
932
933 sub memory_setup
934 {
935   my $cr=shift;
936
937   return " <memory>".$cr->{mem}."</memory>\n";
938 }
939
940 sub paging_setup  {
941   my $cr = shift;
942   my $s="";
943   
944   $s.= " <paging mode=\"".$cr->{paging_mode}."\">\n";
945   $s.= "  <large_pages>".$cr->{large_pages}."</large_pages>\n";
946   $s.= "  <strategy>".$cr->{shadow_strategy}."</strategy>\n";
947   $s.= " </paging>\n";
948   
949   return $s;
950 }
951
952 sub memmap_setup {
953   my $cr = shift;
954
955   return $cr->{memmap_block};
956 }
957
958 sub schedule_setup {
959   my $cr = shift;
960
961   return $cr->{schedule_hz_block};
962 }
963
964
965 sub perftune_setup  {
966   my $cr=shift;
967   my $s="";
968   if (defined($cr->{perftune_block})) { 
969     $s.=" <perftune>\n";
970     $s.= $cr->{perftune_block};
971     $s.=" </perftune>\n";
972   }
973   return $s;
974 }
975
976 sub extensions_setup  {
977   my $cr=shift;
978   my $s="";
979   if (defined($cr->{extensions_block})) { 
980     $s.=" <extensions>\n";
981     $s.= $cr->{extensions_block};
982     $s.=" </extensions>\n";
983   }
984   return $s;
985 }
986
987 sub telemetry_setup  {
988   my $cr=shift;
989   return " <telemetry>".$cr->{telemetry}."</telemetry>\n";
990 }
991
992 sub file_setup { 
993   my $cr=shift;
994   my $cf;
995   my $s="";
996
997   if (!defined($cr->{files})) { 
998     return " <!-- this configuration contains no files -->\n";
999   } else {
1000
1001     $s.=" <files>\n";
1002    
1003     foreach $cf (@{$cr->{files}}) {
1004       $s.="   <file id=\"".$cf->{name}."\" filename=\"".$cf->{file}."\" />\n";
1005     }
1006     $s.=" </files>\n";
1007     return $s;
1008   }
1009 }
1010
1011 sub device_setup { 
1012   my $cr=shift;
1013   my $cd;
1014   my $s="";
1015
1016   $s.=" <devices>\n";
1017
1018   foreach $cd (@{$cr->{devices}}) {
1019     $s.="   <device class=\"".$cd->{class}."\" id=\"".$cd->{id}."\"";
1020     if (defined($cd->{opt})) { 
1021       $s.=" ".$cd->{opt};
1022     }
1023     if (!defined($cd->{nest})) { 
1024       $s.=" />\n";
1025     } else {
1026       $s.=" >\n";
1027       $s.=$cd->{nest};
1028       $s.="   </device>\n";
1029     }
1030   }
1031
1032   $s.=" </devices>\n";
1033
1034   return $s;
1035
1036 }
1037
1038
1039
1040 sub get_user {
1041   my $def = shift;
1042   
1043   my $inp = <STDIN>; chomp($inp);
1044   
1045   if ($inp eq "") { 
1046     return $def;
1047   } else {
1048     return $inp;
1049   }
1050 }
1051
1052 sub get_kernel_feature {
1053   my $dir=shift;
1054   my $feature=shift;
1055   my $x;
1056
1057   $x=`grep $feature= $dir/config-\`uname -r\``;
1058
1059   if ($x=~/^\s*\#/) {
1060     return undef;
1061   } else {
1062     if ($x=~/\s*$feature=\s*(\S*)\s*$/) {
1063       return $1;
1064     } else {
1065       return undef;
1066     }
1067   }
1068 }
1069   
1070 sub get_palacios_core_feature {
1071   my $dir=shift;
1072   my $feature=shift;
1073   my $x;
1074
1075   $x=`grep $feature= $dir/.config`;
1076
1077   if ($x=~/^\s*\#/) {
1078     return undef;
1079   } else {
1080     if ($x=~/\s*$feature=\s*(\S*)\s*$/) {
1081       return $1;
1082     } else {
1083       return undef;
1084     }
1085   }
1086 }
1087
1088 sub is_palacios_core_feature_enabled {
1089   my $out = get_palacios_core_feature(@_);
1090   return !defined($out) ? 0 : $out eq "y";
1091 }
1092
1093
1094 sub powerof2  {
1095   my $x = shift;
1096   my $exp;
1097   
1098   $exp = log($x) /log(2);
1099
1100   return $exp==int($exp);
1101 }
1102
1103
1104 sub gen_image_file {
1105   my ($name, $size_mb) = @_;
1106
1107   if (system("dd if=/dev/zero of=$name bs=1048576 count=$size_mb")) { 
1108     return -1;
1109   } else  {
1110     return 0;
1111   }
1112 }