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.


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