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.


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