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