Add break after parsing the -n option.
[dragonfly.git] / sys / platform / vkernel / platform / init.c
1 /*
2  * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
3  * 
4  * This code is derived from software contributed to The DragonFly Project
5  * by Matthew Dillon <dillon@backplane.com>
6  * 
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  * 3. Neither the name of The DragonFly Project nor the names of its
18  *    contributors may be used to endorse or promote products derived
19  *    from this software without specific, prior written permission.
20  * 
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  * 
34  * $DragonFly: src/sys/platform/vkernel/platform/init.c,v 1.43 2007/07/02 17:44:00 josepht Exp $
35  */
36
37 #include <sys/types.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/stat.h>
41 #include <sys/mman.h>
42 #include <sys/cons.h>
43 #include <sys/random.h>
44 #include <sys/vkernel.h>
45 #include <sys/tls.h>
46 #include <sys/reboot.h>
47 #include <sys/proc.h>
48 #include <sys/msgbuf.h>
49 #include <sys/vmspace.h>
50 #include <sys/socket.h>
51 #include <sys/sockio.h>
52 #include <vm/vm_page.h>
53
54 #include <machine/globaldata.h>
55 #include <machine/tls.h>
56 #include <machine/md_var.h>
57 #include <machine/vmparam.h>
58
59 #include <net/if.h>
60 #include <net/if_arp.h>
61 #include <net/ethernet.h>
62 #include <net/bridge/if_bridgevar.h>
63 #include <netinet/in.h>
64 #include <arpa/inet.h>
65
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <stdarg.h>
69 #include <unistd.h>
70 #include <fcntl.h>
71 #include <string.h>
72 #include <err.h>
73 #include <errno.h>
74 #include <assert.h>
75
76 vm_paddr_t phys_avail[16];
77 vm_paddr_t Maxmem;
78 vm_paddr_t Maxmem_bytes;
79 int MemImageFd = -1;
80 struct vkdisk_info DiskInfo[VKDISK_MAX];
81 int DiskNum;
82 struct vknetif_info NetifInfo[VKNETIF_MAX];
83 int NetifNum;
84 char *pid_file;
85 vm_offset_t KvaStart;
86 vm_offset_t KvaEnd;
87 vm_offset_t KvaSize;
88 vm_offset_t virtual_start;
89 vm_offset_t virtual_end;
90 vm_offset_t kernel_vm_end;
91 vm_offset_t crashdumpmap;
92 vm_offset_t clean_sva;
93 vm_offset_t clean_eva;
94 struct msgbuf *msgbufp;
95 caddr_t ptvmmap;
96 vpte_t  *KernelPTD;
97 vpte_t  *KernelPTA;     /* Warning: Offset for direct VA translation */
98 u_int cpu_feature;      /* XXX */
99 u_int tsc_present;      /* XXX */
100 int optcpus;            /* number of cpus - see mp_start() */
101
102 struct privatespace *CPU_prvspace;
103
104 static struct trapframe proc0_tf;
105 static void *proc0paddr;
106
107 static void init_sys_memory(char *imageFile);
108 static void init_kern_memory(void);
109 static void init_globaldata(void);
110 static void init_vkernel(void);
111 static void init_disk(char *diskExp[], int diskFileNum, enum vkdisk_type type); 
112 static void init_netif(char *netifExp[], int netifFileNum);
113 static void writepid( void );
114 static void cleanpid( void );
115 static void usage(const char *ctl, ...);
116
117 static int save_ac;
118 static char **save_av;
119
120 /*
121  * Kernel startup for virtual kernels - standard main() 
122  */
123 int
124 main(int ac, char **av)
125 {
126         char *memImageFile = NULL;
127         char *netifFile[VKNETIF_MAX];
128         char *diskFile[VKDISK_MAX];
129         char *cdFile[VKDISK_MAX];
130         char *suffix;
131         int netifFileNum = 0;
132         int diskFileNum = 0;
133         int cdFileNum = 0;
134         int c;
135         int i;
136         int n;
137         
138         save_ac = ac;
139         save_av = av;
140
141         /*
142          * Process options
143          */
144         kernel_mem_readonly = 1;
145 #ifdef SMP
146         optcpus = 2;
147 #endif
148
149         while ((c = getopt(ac, av, "c:svm:n:r:e:i:p:I:U")) != -1) {
150                 switch(c) {
151                 case 'e':
152                         /*
153                          * name=value:name=value:name=value...
154                          */
155                         n = strlen(optarg);
156                         kern_envp = malloc(n + 2);
157                         for (i = 0; i < n; ++i) {
158                                 if (optarg[i] == ':')
159                                         kern_envp[i] = 0;
160                                 else
161                                         kern_envp[i] = optarg[i];
162                         }
163                         kern_envp[i++] = 0;
164                         kern_envp[i++] = 0;
165                         break;
166                 case 's':
167                         boothowto |= RB_SINGLE;
168                         break;
169                 case 'v':
170                         bootverbose = 1;
171                         break;
172                 case 'i':
173                         memImageFile = optarg;
174                         break;
175                 case 'I':
176                         if (netifFileNum < VKNETIF_MAX)
177                                 netifFile[netifFileNum++] = strdup(optarg);
178                         break;
179                 case 'r':
180                         if (diskFileNum + cdFileNum < VKDISK_MAX)
181                                 diskFile[diskFileNum++] = strdup(optarg);
182                         break;
183                 case 'c':
184                         if (diskFileNum + cdFileNum < VKDISK_MAX)
185                                 cdFile[cdFileNum++] = strdup(optarg);
186                         break;
187                 case 'm':
188                         Maxmem_bytes = strtoull(optarg, &suffix, 0);
189                         if (suffix) {
190                                 switch(*suffix) {
191                                 case 'g':
192                                 case 'G':
193                                         Maxmem_bytes <<= 30;
194                                         break;
195                                 case 'm':
196                                 case 'M':
197                                         Maxmem_bytes <<= 20;
198                                         break;
199                                 case 'k':
200                                 case 'K':
201                                         Maxmem_bytes <<= 10;
202                                         break;
203                                 default:
204                                         Maxmem_bytes = 0;
205                                         usage("Bad maxmem option");
206                                         /* NOT REACHED */
207                                         break;
208                                 }
209                         }
210                         break;
211                 case 'n':
212                         /*
213                          * This value is set up by mp_start(), don't just
214                          * set ncpus here.
215                          */
216 #ifdef SMP
217                         optcpus = strtol(optarg, NULL, 0);
218                         if (optcpus < 1 || optcpus > MAXCPU)
219                                 usage("Bad ncpus, valid range is 1-%d", MAXCPU);
220 #else
221                         if (strtol(optarg, NULL, 0) != 1) {
222                                 usage("You built a UP vkernel, only 1 cpu!");
223                         }
224 #endif
225                         
226                         break;
227                 case 'p':
228                         pid_file = optarg;      
229                         break;
230                 case 'U':
231                         kernel_mem_readonly = 0;
232                         break;
233                 }
234         }
235
236         writepid();
237         cpu_disable_intr();
238         init_sys_memory(memImageFile);
239         init_kern_memory();
240         init_globaldata();
241         init_vkernel();
242         init_kqueue();
243         init_disk(diskFile, diskFileNum, VKD_DISK);
244         init_disk(cdFile, cdFileNum, VKD_CD);
245         init_netif(netifFile, netifFileNum);
246         init_exceptions();
247         mi_startup();
248         /* NOT REACHED */
249         exit(1);
250 }
251
252 /*
253  * Initialize system memory.  This is the virtual kernel's 'RAM'.
254  */
255 static
256 void
257 init_sys_memory(char *imageFile)
258 {
259         struct stat st;
260         int i;
261         int fd;
262
263         /*
264          * Figure out the system memory image size.  If an image file was
265          * specified and -m was not specified, use the image file's size.
266          */
267
268         if (imageFile && stat(imageFile, &st) == 0 && Maxmem_bytes == 0)
269                 Maxmem_bytes = (vm_paddr_t)st.st_size;
270         if ((imageFile == NULL || stat(imageFile, &st) < 0) && 
271             Maxmem_bytes == 0) {
272                 err(1, "Cannot create new memory file %s unless "
273                        "system memory size is specified with -m",
274                        imageFile);
275                 /* NOT REACHED */
276         }
277
278         /*
279          * Maxmem must be known at this time
280          */
281         if (Maxmem_bytes < 32 * 1024 * 1024 || (Maxmem_bytes & SEG_MASK)) {
282                 err(1, "Bad maxmem specification: 32MB minimum, "
283                        "multiples of %dMB only",
284                        SEG_SIZE / 1024 / 1024);
285                 /* NOT REACHED */
286         }
287
288         /*
289          * Generate an image file name if necessary, then open/create the
290          * file exclusively locked.  Do not allow multiple virtual kernels
291          * to use the same image file.
292          */
293         if (imageFile == NULL) {
294                 for (i = 0; i < 1000000; ++i) {
295                         asprintf(&imageFile, "/var/vkernel/memimg.%06d", i);
296                         fd = open(imageFile, 
297                                   O_RDWR|O_CREAT|O_EXLOCK|O_NONBLOCK, 0644);
298                         if (fd < 0 && errno == EWOULDBLOCK) {
299                                 free(imageFile);
300                                 continue;
301                         }
302                         break;
303                 }
304         } else {
305                 fd = open(imageFile, O_RDWR|O_CREAT|O_EXLOCK|O_NONBLOCK, 0644);
306         }
307         printf("Using memory file: %s\n", imageFile);
308         if (fd < 0 || fstat(fd, &st) < 0) {
309                 err(1, "Unable to open/create %s", imageFile);
310                 /* NOT REACHED */
311         }
312
313         /*
314          * Truncate or extend the file as necessary.
315          */
316         if (st.st_size > Maxmem_bytes) {
317                 ftruncate(fd, Maxmem_bytes);
318         } else if (st.st_size < Maxmem_bytes) {
319                 char *zmem;
320                 off_t off = st.st_size & ~SEG_MASK;
321
322                 kprintf("%s: Reserving blocks for memory image\n", imageFile);
323                 zmem = malloc(SEG_SIZE);
324                 bzero(zmem, SEG_SIZE);
325                 lseek(fd, off, SEEK_SET);
326                 while (off < Maxmem_bytes) {
327                         if (write(fd, zmem, SEG_SIZE) != SEG_SIZE) {
328                                 err(1, "Unable to reserve blocks for memory image");
329                                 /* NOT REACHED */
330                         }
331                         off += SEG_SIZE;
332                 }
333                 if (fsync(fd) < 0)
334                         err(1, "Unable to reserve blocks for memory image");
335                 free(zmem);
336         }
337         MemImageFd = fd;
338         Maxmem = Maxmem_bytes >> PAGE_SHIFT;
339 }
340
341 /*
342  * Initialize kernel memory.  This reserves kernel virtual memory by using
343  * MAP_VPAGETABLE
344  */
345
346 static
347 void
348 init_kern_memory(void)
349 {
350         void *base;
351         void *try;
352         char *zero;
353         char dummy;
354         char *topofstack = &dummy;
355         vpte_t pte;
356         int i;
357
358         /*
359          * Memory map our kernel virtual memory space.  Note that the
360          * kernel image itself is not made part of this memory for the
361          * moment.
362          *
363          * The memory map must be segment-aligned so we can properly
364          * offset KernelPTD.
365          *
366          * If the system kernel has a different MAXDSIZ, it might not
367          * be possible to map kernel memory in its prefered location.
368          * Try a number of different locations.
369          */
370         try = (void *)0x40000000;
371         base = NULL;
372         while ((char *)try + KERNEL_KVA_SIZE < topofstack) {
373                 base = mmap(try, KERNEL_KVA_SIZE, PROT_READ|PROT_WRITE,
374                             MAP_FILE|MAP_SHARED|MAP_VPAGETABLE,
375                             MemImageFd, 0);
376                 if (base == try)
377                         break;
378                 if (base != MAP_FAILED)
379                         munmap(base, KERNEL_KVA_SIZE);
380                 try = (char *)try + 0x10000000;
381         }
382         if (base != try) {
383                 err(1, "Unable to mmap() kernel virtual memory!");
384                 /* NOT REACHED */
385         }
386         madvise(base, KERNEL_KVA_SIZE, MADV_NOSYNC);
387         KvaStart = (vm_offset_t)base;
388         KvaSize = KERNEL_KVA_SIZE;
389         KvaEnd = KvaStart + KvaSize;
390         printf("KVM mapped at %p-%p\n", (void *)KvaStart, (void *)KvaEnd);
391
392         /*
393          * Create a top-level page table self-mapping itself. 
394          *
395          * Initialize the page directory at physical page index 0 to point
396          * to an array of page table pages starting at physical page index 1
397          */
398         lseek(MemImageFd, 0L, 0);
399         for (i = 0; i < KERNEL_KVA_SIZE / SEG_SIZE; ++i) {
400                 pte = ((i + 1) * PAGE_SIZE) | VPTE_V | VPTE_R | VPTE_W;
401                 write(MemImageFd, &pte, sizeof(pte));
402         }
403
404         /*
405          * Initialize the PTEs in the page table pages required to map the
406          * page table itself.  This includes mapping the page directory page
407          * at the base so we go one more loop then normal.
408          */
409         lseek(MemImageFd, PAGE_SIZE, 0);
410         for (i = 0; i <= KERNEL_KVA_SIZE / SEG_SIZE * sizeof(vpte_t); ++i) {
411                 pte = (i * PAGE_SIZE) | VPTE_V | VPTE_R | VPTE_W;
412                 write(MemImageFd, &pte, sizeof(pte));
413         }
414
415         /*
416          * Initialize remaining PTEs to 0.  We may be reusing a memory image
417          * file.  This is approximately a megabyte.
418          */
419         i = (KERNEL_KVA_SIZE / PAGE_SIZE - i) * sizeof(pte);
420         zero = malloc(PAGE_SIZE);
421         bzero(zero, PAGE_SIZE);
422         while (i) {
423                 write(MemImageFd, zero, (i > PAGE_SIZE) ? PAGE_SIZE : i);
424                 i = i - ((i > PAGE_SIZE) ? PAGE_SIZE : i);
425         }
426         free(zero);
427
428         /*
429          * Enable the page table and calculate pointers to our self-map
430          * for easy kernel page table manipulation.
431          *
432          * KernelPTA must be offset so we can do direct VA translations
433          */
434         mcontrol(base, KERNEL_KVA_SIZE, MADV_SETMAP,
435                  0 | VPTE_R | VPTE_W | VPTE_V);
436         KernelPTD = (vpte_t *)base;                       /* pg directory */
437         KernelPTA = (vpte_t *)((char *)base + PAGE_SIZE); /* pg table pages */
438         KernelPTA -= KvaStart >> PAGE_SHIFT;
439
440         /*
441          * phys_avail[] represents unallocated physical memory.  MI code
442          * will use phys_avail[] to create the vm_page array.
443          */
444         phys_avail[0] = PAGE_SIZE +
445                         KERNEL_KVA_SIZE / PAGE_SIZE * sizeof(vpte_t);
446         phys_avail[0] = (phys_avail[0] + PAGE_MASK) & ~(vm_paddr_t)PAGE_MASK;
447         phys_avail[1] = Maxmem_bytes;
448
449         /*
450          * (virtual_start, virtual_end) represent unallocated kernel virtual
451          * memory.  MI code will create kernel_map using these parameters.
452          */
453         virtual_start = KvaStart + PAGE_SIZE +
454                         KERNEL_KVA_SIZE / PAGE_SIZE * sizeof(vpte_t);
455         virtual_start = (virtual_start + PAGE_MASK) & ~(vm_offset_t)PAGE_MASK;
456         virtual_end = KvaStart + KERNEL_KVA_SIZE;
457
458         /*
459          * kernel_vm_end could be set to virtual_end but we want some 
460          * indication of how much of the kernel_map we've used, so
461          * set it low and let pmap_growkernel increase it even though we
462          * don't need to create any new page table pages.
463          */
464         kernel_vm_end = virtual_start;
465
466         /*
467          * Allocate space for process 0's UAREA.
468          */
469         proc0paddr = (void *)virtual_start;
470         for (i = 0; i < UPAGES; ++i) {
471                 pmap_kenter_quick(virtual_start, phys_avail[0]);
472                 virtual_start += PAGE_SIZE;
473                 phys_avail[0] += PAGE_SIZE;
474         }
475
476         /*
477          * crashdumpmap
478          */
479         crashdumpmap = virtual_start;
480         virtual_start += MAXDUMPPGS * PAGE_SIZE;
481
482         /*
483          * msgbufp maps the system message buffer
484          */
485         assert((MSGBUF_SIZE & PAGE_MASK) == 0);
486         msgbufp = (void *)virtual_start;
487         for (i = 0; i < (MSGBUF_SIZE >> PAGE_SHIFT); ++i) {
488                 pmap_kenter_quick(virtual_start, phys_avail[0]);
489                 virtual_start += PAGE_SIZE;
490                 phys_avail[0] += PAGE_SIZE;
491         }
492         msgbufinit(msgbufp, MSGBUF_SIZE);
493
494         /*
495          * used by kern_memio for /dev/mem access
496          */
497         ptvmmap = (caddr_t)virtual_start;
498         virtual_start += PAGE_SIZE;
499
500         /*
501          * Bootstrap the kernel_pmap
502          */
503         pmap_bootstrap();
504 }
505
506 /*
507  * Map the per-cpu globaldata for cpu #0.  Allocate the space using
508  * virtual_start and phys_avail[0]
509  */
510 static
511 void
512 init_globaldata(void)
513 {
514         int i;
515         vm_paddr_t pa;
516         vm_offset_t va;
517
518         /*
519          * Reserve enough KVA to cover possible cpus.  This is a considerable
520          * amount of KVA since the privatespace structure includes two 
521          * whole page table mappings.
522          */
523         virtual_start = (virtual_start + SEG_MASK) & ~(vm_offset_t)SEG_MASK;
524         CPU_prvspace = (void *)virtual_start;
525         virtual_start += sizeof(struct privatespace) * SMP_MAXCPU;
526
527         /*
528          * Allocate enough physical memory to cover the mdglobaldata
529          * portion of the space and the idle stack and map the pages
530          * into KVA.  For cpu #0 only.
531          */
532         for (i = 0; i < sizeof(struct mdglobaldata); i += PAGE_SIZE) {
533                 pa = phys_avail[0];
534                 va = (vm_offset_t)&CPU_prvspace[0].mdglobaldata + i;
535                 pmap_kenter_quick(va, pa);
536                 phys_avail[0] += PAGE_SIZE;
537         }
538         for (i = 0; i < sizeof(CPU_prvspace[0].idlestack); i += PAGE_SIZE) {
539                 pa = phys_avail[0];
540                 va = (vm_offset_t)&CPU_prvspace[0].idlestack + i;
541                 pmap_kenter_quick(va, pa);
542                 phys_avail[0] += PAGE_SIZE;
543         }
544
545         /*
546          * Setup the %gs for cpu #0.  The mycpu macro works after this
547          * point.
548          */
549         tls_set_fs(&CPU_prvspace[0], sizeof(struct privatespace));
550 }
551
552 /*
553  * Initialize very low level systems including thread0, proc0, etc.
554  */
555 static
556 void
557 init_vkernel(void)
558 {
559         struct mdglobaldata *gd;
560
561         gd = &CPU_prvspace[0].mdglobaldata;
562         bzero(gd, sizeof(*gd));
563
564         gd->mi.gd_curthread = &thread0;
565         thread0.td_gd = &gd->mi;
566         ncpus = 1;
567         ncpus2 = 1;     /* rounded down power of 2 */
568         ncpus_fit = 1;  /* rounded up power of 2 */
569         /* ncpus2_mask and ncpus_fit_mask are 0 */
570         init_param1();
571         gd->mi.gd_prvspace = &CPU_prvspace[0];
572         mi_gdinit(&gd->mi, 0);
573         cpu_gdinit(gd, 0);
574         mi_proc0init(&gd->mi, proc0paddr);
575         lwp0.lwp_md.md_regs = &proc0_tf;
576
577         /*init_locks();*/
578         cninit();
579         rand_initialize();
580 #if 0   /* #ifdef DDB */
581         kdb_init();
582         if (boothowto & RB_KDB)
583                 Debugger("Boot flags requested debugger");
584 #endif
585 #if 0
586         initializecpu();        /* Initialize CPU registers */
587 #endif
588         init_param2((phys_avail[1] - phys_avail[0]) / PAGE_SIZE);
589
590 #if 0
591         /*
592          * Map the message buffer
593          */
594         for (off = 0; off < round_page(MSGBUF_SIZE); off += PAGE_SIZE)
595                 pmap_kenter((vm_offset_t)msgbufp + off, avail_end + off);
596         msgbufinit(msgbufp, MSGBUF_SIZE);
597 #endif
598 #if 0
599         thread0.td_pcb_cr3 ... MMU
600         lwp0.lwp_md.md_regs = &proc0_tf;
601 #endif
602 }
603
604 /*
605  * Filesystem image paths for the virtual kernel are optional.  
606  * If specified they each should point to a disk image, 
607  * the first of which will become the root disk.
608  *
609  * The virtual kernel caches data from our 'disk' just like a normal kernel,
610  * so we do not really want the real kernel to cache the data too.  Use
611  * O_DIRECT to remove the duplication.
612  */
613 static
614 void
615 init_disk(char *diskExp[], int diskFileNum, enum vkdisk_type type)
616 {
617         int i;  
618
619         if (diskFileNum == 0)
620                 return;
621
622         for(i=0; i < diskFileNum; i++){
623                 char *fname;
624                 fname = diskExp[i];
625
626                 if (fname == NULL) {
627                         warnx("Invalid argument to '-r'");
628                         continue;
629                 }
630
631                 if (DiskNum < VKDISK_MAX) {
632                         struct stat st; 
633                         struct vkdisk_info* info = NULL;
634                         int fd;
635                         size_t l = 0;
636
637                         if (type == VKD_DISK)
638                             fd = open(fname, O_RDWR|O_DIRECT|O_EXLOCK|O_NONBLOCK, 0644);
639                         else
640                             fd = open(fname, O_RDONLY|O_DIRECT, 0644);
641                         if (fd < 0 || fstat(fd, &st) < 0) {
642                                 if (errno == EAGAIN)
643                                         fprintf(stderr, "You may already have a vkernel using this disk image!\n");
644                                 err(1, "Unable to open/create %s", fname);
645                                 /* NOT REACHED */
646                         }
647                         /* get rid of O_NONBLOCK, keep O_DIRECT */
648                         if (type == VKD_DISK)
649                                 fcntl(fd, F_SETFL, O_DIRECT);
650
651                         info = &DiskInfo[DiskNum];
652                         l = strlen(fname);
653
654                         info->unit = i;
655                         info->fd = fd;
656                         info->type = type;
657                         memcpy(info->fname, fname, l);
658
659                         if (i == 0) {
660                                 if (type == VKD_CD)
661                                     rootdevnames[0] = "cd9660:vcd0a";
662                                 else if (type == VKD_DISK)
663                                     rootdevnames[0] = "ufs:vkd0s0a";
664                         }
665
666                         DiskNum++;
667                 } else {
668                         warnx("vkd%d (%s) > VKDISK_MAX", DiskNum, fname);
669                         continue;
670                 }
671         }
672 }
673
674 static
675 int
676 netif_set_tapflags(int tap_unit, int f, int s)
677 {
678         struct ifreq ifr;
679         int flags;
680
681         bzero(&ifr, sizeof(ifr));
682
683         snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tap%d", tap_unit);
684         if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
685                 warn("tap%d: ioctl(SIOCGIFFLAGS) failed", tap_unit);
686                 return -1;
687         }
688
689         /*
690          * Adjust if_flags
691          *
692          * If the flags are already set/cleared, then we return
693          * immediately to avoid extra syscalls
694          */
695         flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
696         if (f < 0) {
697                 /* Turn off flags */
698                 f = -f;
699                 if ((flags & f) == 0)
700                         return 0;
701                 flags &= ~f;
702         } else {
703                 /* Turn on flags */
704                 if (flags & f)
705                         return 0;
706                 flags |= f;
707         }
708
709         /*
710          * Fix up ifreq.ifr_name, since it may be trashed
711          * in previous ioctl(SIOCGIFFLAGS)
712          */
713         snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tap%d", tap_unit);
714
715         ifr.ifr_flags = flags & 0xffff;
716         ifr.ifr_flagshigh = flags >> 16;
717         if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
718                 warn("tap%d: ioctl(SIOCSIFFLAGS) failed", tap_unit);
719                 return -1;
720         }
721         return 0;
722 }
723
724 static
725 int
726 netif_set_tapaddr(int tap_unit, in_addr_t addr, in_addr_t mask, int s)
727 {
728         struct ifaliasreq ifra;
729         struct sockaddr_in *in;
730
731         bzero(&ifra, sizeof(ifra));
732         snprintf(ifra.ifra_name, sizeof(ifra.ifra_name), "tap%d", tap_unit);
733
734         /* Setup address */
735         in = (struct sockaddr_in *)&ifra.ifra_addr;
736         in->sin_family = AF_INET;
737         in->sin_len = sizeof(*in);
738         in->sin_addr.s_addr = addr;
739
740         if (mask != 0) {
741                 /* Setup netmask */
742                 in = (struct sockaddr_in *)&ifra.ifra_mask;
743                 in->sin_len = sizeof(*in);
744                 in->sin_addr.s_addr = mask;
745         }
746
747         if (ioctl(s, SIOCAIFADDR, &ifra) < 0) {
748                 warn("tap%d: ioctl(SIOCAIFADDR) failed", tap_unit);
749                 return -1;
750         }
751         return 0;
752 }
753
754 static
755 int
756 netif_add_tap2brg(int tap_unit, const char *ifbridge, int s)
757 {
758         struct ifbreq ifbr;
759         struct ifdrv ifd;
760
761         bzero(&ifbr, sizeof(ifbr));
762         snprintf(ifbr.ifbr_ifsname, sizeof(ifbr.ifbr_ifsname),
763                  "tap%d", tap_unit);
764
765         bzero(&ifd, sizeof(ifd));
766         strlcpy(ifd.ifd_name, ifbridge, sizeof(ifd.ifd_name));
767         ifd.ifd_cmd = BRDGADD;
768         ifd.ifd_len = sizeof(ifbr);
769         ifd.ifd_data = &ifbr;
770
771         if (ioctl(s, SIOCSDRVSPEC, &ifd) < 0) {
772                 /*
773                  * 'errno == EEXIST' means that the tap(4) is already
774                  * a member of the bridge(4)
775                  */
776                 if (errno != EEXIST) {
777                         warn("ioctl(%s, SIOCSDRVSPEC) failed", ifbridge);
778                         return -1;
779                 }
780         }
781         return 0;
782 }
783
784 #define TAPDEV_OFLAGS   (O_RDWR | O_NONBLOCK)
785
786 /* XXX major()/minor() can't be used in vkernel */
787 #define TAPDEV_MAJOR(x) ((int)(((u_int)(x) >> 8) & 0xff))
788 #define TAPDEV_MINOR(x) ((int)((x) & 0xffff00ff))
789
790 #ifndef TAP_CDEV_MAJOR
791 #define TAP_CDEV_MAJOR  149
792 #endif
793
794 /*
795  * Locate the first unused tap(4) device file if auto mode is requested,
796  * or open the user supplied device file, and bring up the corresponding
797  * tap(4) interface.
798  *
799  * NOTE: Only tap(4) device file is supported currently
800  */
801 static
802 int
803 netif_open_tap(const char *netif, int *tap_unit, int s)
804 {
805         char tap_dev[MAXPATHLEN];
806         int tap_fd, failed;
807         struct stat st;
808
809         *tap_unit = -1;
810
811         if (strcmp(netif, "auto") == 0) {
812                 int i;
813
814                 /*
815                  * Find first unused tap(4) device file
816                  */
817                 for (i = 0; ; ++i) {
818                         snprintf(tap_dev, sizeof(tap_dev), "/dev/tap%d", i);
819                         tap_fd = open(tap_dev, TAPDEV_OFLAGS);
820                         if (tap_fd >= 0 || errno == ENOENT)
821                                 break;
822                 }
823                 if (tap_fd < 0) {
824                         warnx("Unable to find a free tap(4)");
825                         return -1;
826                 }
827         } else {
828                 /*
829                  * User supplied tap(4) device file
830                  */
831                 if (netif[0] == '/')    /* Absolute path */
832                         strlcpy(tap_dev, netif, sizeof(tap_dev));
833                 else
834                         snprintf(tap_dev, sizeof(tap_dev), "/dev/%s", netif);
835
836                 tap_fd = open(tap_dev, TAPDEV_OFLAGS);
837                 if (tap_fd < 0) {
838                         warn("Unable to open %s", tap_dev);
839                         return -1;
840                 }
841         }
842
843         /*
844          * Check whether the device file is a tap(4)
845          */
846         failed = 1;
847         if (fstat(tap_fd, &st) == 0 && S_ISCHR(st.st_mode) &&
848             TAPDEV_MAJOR(st.st_rdev) == TAP_CDEV_MAJOR) {
849                 *tap_unit = TAPDEV_MINOR(st.st_rdev);
850
851                 /*
852                  * Bring up the corresponding tap(4) interface
853                  */
854                 if (netif_set_tapflags(*tap_unit, IFF_UP, s) == 0)
855                         failed = 0;
856         } else {
857                 warnx("%s is not a tap(4) device", tap_dev);
858         }
859
860         if (failed) {
861                 close(tap_fd);
862                 tap_fd = -1;
863                 *tap_unit = -1;
864         }
865         return tap_fd;
866 }
867
868 #undef TAPDEV_MAJOR
869 #undef TAPDEV_MINOR
870 #undef TAPDEV_OFLAGS
871
872 /*
873  * Following syntax is supported,
874  * 1) x.x.x.x             tap(4)'s address is x.x.x.x
875  *
876  * 2) x.x.x.x/z           tap(4)'s address is x.x.x.x
877  *                        tap(4)'s netmask len is z
878  *
879  * 3) x.x.x.x:y.y.y.y     tap(4)'s address is x.x.x.x
880  *                        pseudo netif's address is y.y.y.y
881  *
882  * 4) x.x.x.x:y.y.y.y/z   tap(4)'s address is x.x.x.x
883  *                        pseudo netif's address is y.y.y.y
884  *                        tap(4) and pseudo netif's netmask len are z
885  *
886  * 5) bridgeX             tap(4) will be added to bridgeX
887  *
888  * 6) bridgeX:y.y.y.y     tap(4) will be added to bridgeX
889  *                        pseudo netif's address is y.y.y.y
890  *
891  * 7) bridgeX:y.y.y.y/z   tap(4) will be added to bridgeX
892  *                        pseudo netif's address is y.y.y.y
893  *                        pseudo netif's netmask len is z
894  */
895 static
896 int
897 netif_init_tap(int tap_unit, in_addr_t *addr, in_addr_t *mask, int s)
898 {
899         in_addr_t tap_addr, netmask, netif_addr;
900         int next_netif_addr;
901         char *tok, *masklen_str, *ifbridge;
902
903         *addr = 0;
904         *mask = 0;
905
906         tok = strtok(NULL, ":/");
907         if (tok == NULL) {
908                 /*
909                  * Nothing special, simply use tap(4) as backend
910                  */
911                 return 0;
912         }
913
914         if (inet_pton(AF_INET, tok, &tap_addr) > 0) {
915                 /*
916                  * tap(4)'s address is supplied
917                  */
918                 ifbridge = NULL;
919
920                 /*
921                  * If there is next token, then it may be pseudo
922                  * netif's address or netmask len for tap(4)
923                  */
924                 next_netif_addr = 0;
925         } else {
926                 /*
927                  * Not tap(4)'s address, assume it as a bridge(4)
928                  * iface name
929                  */
930                 tap_addr = 0;
931                 ifbridge = tok;
932
933                 /*
934                  * If there is next token, then it must be pseudo
935                  * netif's address
936                  */
937                 next_netif_addr = 1;
938         }
939
940         netmask = netif_addr = 0;
941
942         tok = strtok(NULL, ":/");
943         if (tok == NULL)
944                 goto back;
945
946         if (inet_pton(AF_INET, tok, &netif_addr) <= 0) {
947                 if (next_netif_addr) {
948                         warnx("Invalid pseudo netif address: %s", tok);
949                         return -1;
950                 }
951                 netif_addr = 0;
952
953                 /*
954                  * Current token is not address, then it must be netmask len
955                  */
956                 masklen_str = tok;
957         } else {
958                 /*
959                  * Current token is pseudo netif address, if there is next token
960                  * it must be netmask len
961                  */
962                 masklen_str = strtok(NULL, "/");
963         }
964
965         /* Calculate netmask */
966         if (masklen_str != NULL) {
967                 u_long masklen;
968
969                 masklen = strtoul(masklen_str, NULL, 10);
970                 if (masklen < 32 && masklen > 0) {
971                         netmask = htonl(~((1LL << (32 - masklen)) - 1)
972                                         & 0xffffffff);
973                 } else {
974                         warnx("Invalid netmask len: %lu", masklen);
975                         return -1;
976                 }
977         }
978
979         /* Make sure there is no more token left */
980         if (strtok(NULL, ":/") != NULL) {
981                 warnx("Invalid argument to '-I'");
982                 return -1;
983         }
984
985 back:
986         if (ifbridge == NULL) {
987                 /* Set tap(4) address/netmask */
988                 if (netif_set_tapaddr(tap_unit, tap_addr, netmask, s) < 0)
989                         return -1;
990         } else {
991                 /* Tie tap(4) to bridge(4) */
992                 if (netif_add_tap2brg(tap_unit, ifbridge, s) < 0)
993                         return -1;
994         }
995
996         *addr = netif_addr;
997         *mask = netmask;
998         return 0;
999 }
1000
1001 /*
1002  * NetifInfo[] will be filled for pseudo netif initialization.
1003  * NetifNum will be bumped to reflect the number of valid entries
1004  * in NetifInfo[].
1005  */
1006 static
1007 void
1008 init_netif(char *netifExp[], int netifExpNum)
1009 {
1010         int i, s;
1011
1012         if (netifExpNum == 0)
1013                 return;
1014
1015         s = socket(AF_INET, SOCK_DGRAM, 0);     /* for ioctl(SIOC) */
1016         if (s < 0)
1017                 return;
1018
1019         for (i = 0; i < netifExpNum; ++i) {
1020                 struct vknetif_info *info;
1021                 in_addr_t netif_addr, netif_mask;
1022                 int tap_fd, tap_unit;
1023                 char *netif;
1024
1025                 netif = strtok(netifExp[i], ":");
1026                 if (netif == NULL) {
1027                         warnx("Invalid argument to '-I'");
1028                         continue;
1029                 }
1030
1031                 /*
1032                  * Open tap(4) device file and bring up the
1033                  * corresponding interface
1034                  */
1035                 tap_fd = netif_open_tap(netif, &tap_unit, s);
1036                 if (tap_fd < 0)
1037                         continue;
1038
1039                 /*
1040                  * Initialize tap(4) and get address/netmask
1041                  * for pseudo netif
1042                  *
1043                  * NB: Rest part of netifExp[i] is passed
1044                  *     to netif_init_tap() implicitly.
1045                  */
1046                 if (netif_init_tap(tap_unit, &netif_addr, &netif_mask, s) < 0) {
1047                         /*
1048                          * NB: Closing tap(4) device file will bring
1049                          *     down the corresponding interface
1050                          */
1051                         close(tap_fd);
1052                         continue;
1053                 }
1054
1055                 info = &NetifInfo[NetifNum];
1056                 info->tap_fd = tap_fd;
1057                 info->tap_unit = tap_unit;
1058                 info->netif_addr = netif_addr;
1059                 info->netif_mask = netif_mask;
1060
1061                 NetifNum++;
1062                 if (NetifNum >= VKNETIF_MAX)    /* XXX will this happen? */
1063                         break;
1064         }
1065         close(s);
1066 }
1067
1068 static
1069 void
1070 writepid( void )
1071 {
1072         pid_t self;
1073         FILE *fp;
1074
1075         if (pid_file != NULL) {
1076                 self = getpid();
1077                 fp = fopen(pid_file, "w");
1078
1079                 if (fp != NULL) {
1080                         fprintf(fp, "%ld\n", (long)self);
1081                         fclose(fp);
1082                 }
1083                 else {
1084                         perror("Warning: couldn't open pidfile");
1085                 }
1086         }
1087 }
1088
1089 static
1090 void
1091 cleanpid( void ) 
1092 {
1093         if (pid_file != NULL) {
1094                 if ( unlink(pid_file) != 0 )
1095                         perror("Warning: couldn't remove pidfile");
1096         }
1097 }
1098
1099 static
1100 void
1101 usage(const char *ctl, ...)
1102 {
1103         va_list va;
1104
1105         va_start(va, ctl);
1106         vfprintf(stderr, ctl, va);
1107         va_end(va);
1108         fprintf(stderr, "\n");
1109         exit(1);
1110 }
1111
1112 void
1113 cpu_reset(void)
1114 {
1115         kprintf("cpu reset, rebooting vkernel\n");
1116         closefrom(3);
1117         cleanpid();
1118         execv(save_av[0], save_av);
1119 }
1120
1121 void
1122 cpu_halt(void)
1123 {
1124         kprintf("cpu halt, exiting vkernel\n");
1125         cleanpid();
1126         exit(0);
1127 }