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