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.


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