Kernel virtual memory must be mapped on a segment address boundary. Try
[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.34 2007/04/11 21:04:09 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 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
305 static
306 void
307 init_kern_memory(void)
308 {
309         void *base;
310         void *try;
311         char *zero;
312         char dummy;
313         char *topofstack = &dummy;
314         vpte_t pte;
315         int i;
316
317         /*
318          * Memory map our kernel virtual memory space.  Note that the
319          * kernel image itself is not made part of this memory for the
320          * moment.
321          *
322          * The memory map must be segment-aligned so we can properly
323          * offset KernelPTD.
324          *
325          * If the system kernel has a different MAXDSIZ, it might not
326          * be possible to map kernel memory in its prefered location.
327          * Try a number of different locations.
328          */
329         try = (void *)0x40000000;
330         base = NULL;
331         while ((char *)try + KERNEL_KVA_SIZE < topofstack) {
332                 base = mmap(try, KERNEL_KVA_SIZE, PROT_READ|PROT_WRITE,
333                             MAP_FILE|MAP_SHARED|MAP_VPAGETABLE,
334                             MemImageFd, 0);
335                 if (base == try)
336                         break;
337                 if (base != MAP_FAILED)
338                         munmap(base, KERNEL_KVA_SIZE);
339                 try = (char *)try + 0x10000000;
340         }
341         if (base != try) {
342                 err(1, "Unable to mmap() kernel virtual memory!");
343                 /* NOT REACHED */
344         }
345         madvise(base, KERNEL_KVA_SIZE, MADV_NOSYNC);
346         KvaStart = (vm_offset_t)base;
347         KvaSize = KERNEL_KVA_SIZE;
348         KvaEnd = KvaStart + KvaSize;
349         printf("KVM mapped at %p-%p\n", (void *)KvaStart, (void *)KvaEnd);
350
351         /*
352          * Create a top-level page table self-mapping itself. 
353          *
354          * Initialize the page directory at physical page index 0 to point
355          * to an array of page table pages starting at physical page index 1
356          */
357         lseek(MemImageFd, 0L, 0);
358         for (i = 0; i < KERNEL_KVA_SIZE / SEG_SIZE; ++i) {
359                 pte = ((i + 1) * PAGE_SIZE) | VPTE_V | VPTE_R | VPTE_W;
360                 write(MemImageFd, &pte, sizeof(pte));
361         }
362
363         /*
364          * Initialize the PTEs in the page table pages required to map the
365          * page table itself.  This includes mapping the page directory page
366          * at the base so we go one more loop then normal.
367          */
368         lseek(MemImageFd, PAGE_SIZE, 0);
369         for (i = 0; i <= KERNEL_KVA_SIZE / SEG_SIZE * sizeof(vpte_t); ++i) {
370                 pte = (i * PAGE_SIZE) | VPTE_V | VPTE_R | VPTE_W;
371                 write(MemImageFd, &pte, sizeof(pte));
372         }
373
374         /*
375          * Initialize remaining PTEs to 0.  We may be reusing a memory image
376          * file.  This is approximately a megabyte.
377          */
378         i = (KERNEL_KVA_SIZE / PAGE_SIZE - i) * sizeof(pte);
379         zero = malloc(PAGE_SIZE);
380         bzero(zero, PAGE_SIZE);
381         while (i) {
382                 write(MemImageFd, zero, (i > PAGE_SIZE) ? PAGE_SIZE : i);
383                 i = i - ((i > PAGE_SIZE) ? PAGE_SIZE : i);
384         }
385         free(zero);
386
387         /*
388          * Enable the page table and calculate pointers to our self-map
389          * for easy kernel page table manipulation.
390          *
391          * KernelPTA must be offset so we can do direct VA translations
392          */
393         mcontrol(base, KERNEL_KVA_SIZE, MADV_SETMAP,
394                  0 | VPTE_R | VPTE_W | VPTE_V);
395         KernelPTD = (vpte_t *)base;                       /* pg directory */
396         KernelPTA = (vpte_t *)((char *)base + PAGE_SIZE); /* pg table pages */
397         KernelPTA -= KvaStart >> PAGE_SHIFT;
398
399         /*
400          * phys_avail[] represents unallocated physical memory.  MI code
401          * will use phys_avail[] to create the vm_page array.
402          */
403         phys_avail[0] = PAGE_SIZE +
404                         KERNEL_KVA_SIZE / PAGE_SIZE * sizeof(vpte_t);
405         phys_avail[0] = (phys_avail[0] + PAGE_MASK) & ~(vm_paddr_t)PAGE_MASK;
406         phys_avail[1] = Maxmem_bytes;
407
408         /*
409          * (virtual_start, virtual_end) represent unallocated kernel virtual
410          * memory.  MI code will create kernel_map using these parameters.
411          */
412         virtual_start = KvaStart + PAGE_SIZE +
413                         KERNEL_KVA_SIZE / PAGE_SIZE * sizeof(vpte_t);
414         virtual_start = (virtual_start + PAGE_MASK) & ~(vm_offset_t)PAGE_MASK;
415         virtual_end = KvaStart + KERNEL_KVA_SIZE;
416
417         /*
418          * kernel_vm_end could be set to virtual_end but we want some 
419          * indication of how much of the kernel_map we've used, so
420          * set it low and let pmap_growkernel increase it even though we
421          * don't need to create any new page table pages.
422          */
423         kernel_vm_end = virtual_start;
424
425         /*
426          * Allocate space for process 0's UAREA.
427          */
428         proc0paddr = (void *)virtual_start;
429         for (i = 0; i < UPAGES; ++i) {
430                 pmap_kenter_quick(virtual_start, phys_avail[0]);
431                 virtual_start += PAGE_SIZE;
432                 phys_avail[0] += PAGE_SIZE;
433         }
434
435         /*
436          * crashdumpmap
437          */
438         crashdumpmap = virtual_start;
439         virtual_start += MAXDUMPPGS * PAGE_SIZE;
440
441         /*
442          * msgbufp maps the system message buffer
443          */
444         assert((MSGBUF_SIZE & PAGE_MASK) == 0);
445         msgbufp = (void *)virtual_start;
446         for (i = 0; i < (MSGBUF_SIZE >> PAGE_SHIFT); ++i) {
447                 pmap_kenter_quick(virtual_start, phys_avail[0]);
448                 virtual_start += PAGE_SIZE;
449                 phys_avail[0] += PAGE_SIZE;
450         }
451         msgbufinit(msgbufp, MSGBUF_SIZE);
452
453         /*
454          * used by kern_memio for /dev/mem access
455          */
456         ptvmmap = (caddr_t)virtual_start;
457         virtual_start += PAGE_SIZE;
458
459         /*
460          * Bootstrap the kernel_pmap
461          */
462         pmap_bootstrap();
463 }
464
465 /*
466  * Map the per-cpu globaldata for cpu #0.  Allocate the space using
467  * virtual_start and phys_avail[0]
468  */
469 static
470 void
471 init_globaldata(void)
472 {
473         int i;
474         vm_paddr_t pa;
475         vm_offset_t va;
476
477         /*
478          * Reserve enough KVA to cover possible cpus.  This is a considerable
479          * amount of KVA since the privatespace structure includes two 
480          * whole page table mappings.
481          */
482         virtual_start = (virtual_start + SEG_MASK) & ~(vm_offset_t)SEG_MASK;
483         CPU_prvspace = (void *)virtual_start;
484         virtual_start += sizeof(struct privatespace) * SMP_MAXCPU;
485
486         /*
487          * Allocate enough physical memory to cover the mdglobaldata
488          * portion of the space and the idle stack and map the pages
489          * into KVA.  For cpu #0 only.
490          */
491         for (i = 0; i < sizeof(struct mdglobaldata); i += PAGE_SIZE) {
492                 pa = phys_avail[0];
493                 va = (vm_offset_t)&CPU_prvspace[0].mdglobaldata + i;
494                 pmap_kenter_quick(va, pa);
495                 phys_avail[0] += PAGE_SIZE;
496         }
497         for (i = 0; i < sizeof(CPU_prvspace[0].idlestack); i += PAGE_SIZE) {
498                 pa = phys_avail[0];
499                 va = (vm_offset_t)&CPU_prvspace[0].idlestack + i;
500                 pmap_kenter_quick(va, pa);
501                 phys_avail[0] += PAGE_SIZE;
502         }
503
504         /*
505          * Setup the %gs for cpu #0.  The mycpu macro works after this
506          * point.
507          */
508         tls_set_fs(&CPU_prvspace[0], sizeof(struct privatespace));
509 }
510
511 /*
512  * Initialize very low level systems including thread0, proc0, etc.
513  */
514 static
515 void
516 init_vkernel(void)
517 {
518         struct mdglobaldata *gd;
519
520         gd = &CPU_prvspace[0].mdglobaldata;
521         bzero(gd, sizeof(*gd));
522
523         gd->mi.gd_curthread = &thread0;
524         thread0.td_gd = &gd->mi;
525         ncpus = 1;
526         ncpus2 = 1;
527         init_param1();
528         gd->mi.gd_prvspace = &CPU_prvspace[0];
529         mi_gdinit(&gd->mi, 0);
530         cpu_gdinit(gd, 0);
531         mi_proc0init(&gd->mi, proc0paddr);
532         lwp0.lwp_md.md_regs = &proc0_tf;
533
534         /*init_locks();*/
535         cninit();
536         rand_initialize();
537 #if 0   /* #ifdef DDB */
538         kdb_init();
539         if (boothowto & RB_KDB)
540                 Debugger("Boot flags requested debugger");
541 #endif
542 #if 0
543         initializecpu();        /* Initialize CPU registers */
544 #endif
545         init_param2((phys_avail[1] - phys_avail[0]) / PAGE_SIZE);
546
547 #if 0
548         /*
549          * Map the message buffer
550          */
551         for (off = 0; off < round_page(MSGBUF_SIZE); off += PAGE_SIZE)
552                 pmap_kenter((vm_offset_t)msgbufp + off, avail_end + off);
553         msgbufinit(msgbufp, MSGBUF_SIZE);
554 #endif
555 #if 0
556         thread0.td_pcb_cr3 ... MMU
557         lwp0.lwp_md.md_regs = &proc0_tf;
558 #endif
559 }
560
561 /*
562  * Filesystem image paths for the virtual kernel are optional.  
563  * If specified they each should point to a disk image, 
564  * the first of which will become the root disk.
565  *
566  * The virtual kernel caches data from our 'disk' just like a normal kernel,
567  * so we do not really want the real kernel to cache the data too.  Use
568  * O_DIRECT to remove the duplication.
569  */
570 static
571 void
572 init_disk(char *diskExp[], int diskFileNum)
573 {
574         int i;  
575
576         if (diskFileNum == 0)
577                 return;
578
579         for(i=0; i < diskFileNum; i++){
580                 char *fname;
581                 fname = diskExp[i];
582
583                 if (fname == NULL) {
584                         warnx("Invalid argument to '-r'");
585                         continue;
586                 }
587
588                 if (DiskNum < VKDISK_MAX) {
589                         struct stat st; 
590                         struct vkdisk_info* info = NULL;
591                         int fd;
592                         size_t l = 0;
593
594                         fd = open(fname, O_RDWR|O_DIRECT, 0644);
595                         if (fd < 0 || fstat(fd, &st) < 0) {
596                                 err(1, "Unable to open/create %s", fname);
597                                 /* NOT REACHED */
598                         }
599
600                         info = &DiskInfo[DiskNum];
601                         l = strlen(fname);
602
603                         info->unit = i;
604                         info->fd = fd;
605                         memcpy(info->fname, fname, l);
606
607                         if (i == 0)
608                                 rootdevnames[0] = "ufs:vkd0a";
609
610                         DiskNum++;
611                 } else {
612                         warnx("vkd%d (%s) > VKDISK_MAX", DiskNum, fname);
613                         continue;
614                 }
615         }
616 }
617
618 static
619 int
620 netif_set_tapflags(int tap_unit, int f, int s)
621 {
622         struct ifreq ifr;
623         int flags;
624
625         bzero(&ifr, sizeof(ifr));
626
627         snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tap%d", tap_unit);
628         if (ioctl(s, SIOCGIFFLAGS, &ifr) < 0) {
629                 warn("tap%d: ioctl(SIOCGIFFLAGS) failed", tap_unit);
630                 return -1;
631         }
632
633         /*
634          * Adjust if_flags
635          *
636          * If the flags are already set/cleared, then we return
637          * immediately to avoid extra syscalls
638          */
639         flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16);
640         if (f < 0) {
641                 /* Turn off flags */
642                 f = -f;
643                 if ((flags & f) == 0)
644                         return 0;
645                 flags &= ~f;
646         } else {
647                 /* Turn on flags */
648                 if (flags & f)
649                         return 0;
650                 flags |= f;
651         }
652
653         /*
654          * Fix up ifreq.ifr_name, since it may be trashed
655          * in previous ioctl(SIOCGIFFLAGS)
656          */
657         snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "tap%d", tap_unit);
658
659         ifr.ifr_flags = flags & 0xffff;
660         ifr.ifr_flagshigh = flags >> 16;
661         if (ioctl(s, SIOCSIFFLAGS, &ifr) < 0) {
662                 warn("tap%d: ioctl(SIOCSIFFLAGS) failed", tap_unit);
663                 return -1;
664         }
665         return 0;
666 }
667
668 static
669 int
670 netif_set_tapaddr(int tap_unit, in_addr_t addr, in_addr_t mask, int s)
671 {
672         struct ifaliasreq ifra;
673         struct sockaddr_in *in;
674
675         bzero(&ifra, sizeof(ifra));
676         snprintf(ifra.ifra_name, sizeof(ifra.ifra_name), "tap%d", tap_unit);
677
678         /* Setup address */
679         in = (struct sockaddr_in *)&ifra.ifra_addr;
680         in->sin_family = AF_INET;
681         in->sin_len = sizeof(*in);
682         in->sin_addr.s_addr = addr;
683
684         if (mask != 0) {
685                 /* Setup netmask */
686                 in = (struct sockaddr_in *)&ifra.ifra_mask;
687                 in->sin_len = sizeof(*in);
688                 in->sin_addr.s_addr = mask;
689         }
690
691         if (ioctl(s, SIOCAIFADDR, &ifra) < 0) {
692                 warn("tap%d: ioctl(SIOCAIFADDR) failed", tap_unit);
693                 return -1;
694         }
695         return 0;
696 }
697
698 static
699 int
700 netif_add_tap2brg(int tap_unit, const char *ifbridge, int s)
701 {
702         struct ifbreq ifbr;
703         struct ifdrv ifd;
704
705         bzero(&ifbr, sizeof(ifbr));
706         snprintf(ifbr.ifbr_ifsname, sizeof(ifbr.ifbr_ifsname),
707                  "tap%d", tap_unit);
708
709         bzero(&ifd, sizeof(ifd));
710         strlcpy(ifd.ifd_name, ifbridge, sizeof(ifd.ifd_name));
711         ifd.ifd_cmd = BRDGADD;
712         ifd.ifd_len = sizeof(ifbr);
713         ifd.ifd_data = &ifbr;
714
715         if (ioctl(s, SIOCSDRVSPEC, &ifd) < 0) {
716                 /*
717                  * 'errno == EEXIST' means that the tap(4) is already
718                  * a member of the bridge(4)
719                  */
720                 if (errno != EEXIST) {
721                         warn("ioctl(%s, SIOCSDRVSPEC) failed", ifbridge);
722                         return -1;
723                 }
724         }
725         return 0;
726 }
727
728 #define TAPDEV_OFLAGS   (O_RDWR | O_NONBLOCK)
729
730 /* XXX major()/minor() can't be used in vkernel */
731 #define TAPDEV_MAJOR(x) ((int)(((u_int)(x) >> 8) & 0xff))
732 #define TAPDEV_MINOR(x) ((int)((x) & 0xffff00ff))
733
734 #ifndef TAP_CDEV_MAJOR
735 #define TAP_CDEV_MAJOR  149
736 #endif
737
738 /*
739  * Locate the first unused tap(4) device file if auto mode is requested,
740  * or open the user supplied device file, and bring up the corresponding
741  * tap(4) interface.
742  *
743  * NOTE: Only tap(4) device file is supported currently
744  */
745 static
746 int
747 netif_open_tap(const char *netif, int *tap_unit, int s)
748 {
749         char tap_dev[MAXPATHLEN];
750         int tap_fd, failed;
751         struct stat st;
752
753         *tap_unit = -1;
754
755         if (strcmp(netif, "auto") == 0) {
756                 int i;
757
758                 /*
759                  * Find first unused tap(4) device file
760                  */
761                 for (i = 0; ; ++i) {
762                         snprintf(tap_dev, sizeof(tap_dev), "/dev/tap%d", i);
763                         tap_fd = open(tap_dev, TAPDEV_OFLAGS);
764                         if (tap_fd >= 0 || errno == ENOENT)
765                                 break;
766                 }
767                 if (tap_fd < 0) {
768                         warnx("Unable to find a free tap(4)");
769                         return -1;
770                 }
771         } else {
772                 /*
773                  * User supplied tap(4) device file
774                  */
775                 if (netif[0] == '/')    /* Absolute path */
776                         strlcpy(tap_dev, netif, sizeof(tap_dev));
777                 else
778                         snprintf(tap_dev, sizeof(tap_dev), "/dev/%s", netif);
779
780                 tap_fd = open(tap_dev, TAPDEV_OFLAGS);
781                 if (tap_fd < 0) {
782                         warn("Unable to open %s", tap_dev);
783                         return -1;
784                 }
785         }
786
787         /*
788          * Check whether the device file is a tap(4)
789          */
790         failed = 1;
791         if (fstat(tap_fd, &st) == 0 && S_ISCHR(st.st_mode) &&
792             TAPDEV_MAJOR(st.st_rdev) == TAP_CDEV_MAJOR) {
793                 *tap_unit = TAPDEV_MINOR(st.st_rdev);
794
795                 /*
796                  * Bring up the corresponding tap(4) interface
797                  */
798                 if (netif_set_tapflags(*tap_unit, IFF_UP, s) == 0)
799                         failed = 0;
800         } else {
801                 warnx("%s is not a tap(4) device", tap_dev);
802         }
803
804         if (failed) {
805                 close(tap_fd);
806                 tap_fd = -1;
807                 *tap_unit = -1;
808         }
809         return tap_fd;
810 }
811
812 #undef TAPDEV_MAJOR
813 #undef TAPDEV_MINOR
814 #undef TAPDEV_OFLAGS
815
816 /*
817  * Following syntax is supported,
818  * 1) x.x.x.x             tap(4)'s address is x.x.x.x
819  *
820  * 2) x.x.x.x/z           tap(4)'s address is x.x.x.x
821  *                        tap(4)'s netmask len is z
822  *
823  * 3) x.x.x.x:y.y.y.y     tap(4)'s address is x.x.x.x
824  *                        pseudo netif's address is y.y.y.y
825  *
826  * 4) x.x.x.x:y.y.y.y/z   tap(4)'s address is x.x.x.x
827  *                        pseudo netif's address is y.y.y.y
828  *                        tap(4) and pseudo netif's netmask len are z
829  *
830  * 5) bridgeX             tap(4) will be added to bridgeX
831  *
832  * 6) bridgeX:y.y.y.y     tap(4) will be added to bridgeX
833  *                        pseudo netif's address is y.y.y.y
834  *
835  * 7) bridgeX:y.y.y.y/z   tap(4) will be added to bridgeX
836  *                        pseudo netif's address is y.y.y.y
837  *                        pseudo netif's netmask len is z
838  */
839 static
840 int
841 netif_init_tap(int tap_unit, in_addr_t *addr, in_addr_t *mask, int s)
842 {
843         in_addr_t tap_addr, netmask, netif_addr;
844         int next_netif_addr;
845         char *tok, *masklen_str, *ifbridge;
846
847         *addr = 0;
848         *mask = 0;
849
850         tok = strtok(NULL, ":/");
851         if (tok == NULL) {
852                 /*
853                  * Nothing special, simply use tap(4) as backend
854                  */
855                 return 0;
856         }
857
858         if (inet_pton(AF_INET, tok, &tap_addr) > 0) {
859                 /*
860                  * tap(4)'s address is supplied
861                  */
862                 ifbridge = NULL;
863
864                 /*
865                  * If there is next token, then it may be pseudo
866                  * netif's address or netmask len for tap(4)
867                  */
868                 next_netif_addr = 0;
869         } else {
870                 /*
871                  * Not tap(4)'s address, assume it as a bridge(4)
872                  * iface name
873                  */
874                 tap_addr = 0;
875                 ifbridge = tok;
876
877                 /*
878                  * If there is next token, then it must be pseudo
879                  * netif's address
880                  */
881                 next_netif_addr = 1;
882         }
883
884         netmask = netif_addr = 0;
885
886         tok = strtok(NULL, ":/");
887         if (tok == NULL)
888                 goto back;
889
890         if (inet_pton(AF_INET, tok, &netif_addr) <= 0) {
891                 if (next_netif_addr) {
892                         warnx("Invalid pseudo netif address: %s", tok);
893                         return -1;
894                 }
895                 netif_addr = 0;
896
897                 /*
898                  * Current token is not address, then it must be netmask len
899                  */
900                 masklen_str = tok;
901         } else {
902                 /*
903                  * Current token is pseudo netif address, if there is next token
904                  * it must be netmask len
905                  */
906                 masklen_str = strtok(NULL, "/");
907         }
908
909         /* Calculate netmask */
910         if (masklen_str != NULL) {
911                 u_long masklen;
912
913                 masklen = strtoul(masklen_str, NULL, 10);
914                 if (masklen < 32 && masklen > 0) {
915                         netmask = htonl(~((1LL << (32 - masklen)) - 1)
916                                         & 0xffffffff);
917                 } else {
918                         warnx("Invalid netmask len: %lu", masklen);
919                         return -1;
920                 }
921         }
922
923         /* Make sure there is no more token left */
924         if (strtok(NULL, ":/") != NULL) {
925                 warnx("Invalid argument to '-I'");
926                 return -1;
927         }
928
929 back:
930         if (ifbridge == NULL) {
931                 /* Set tap(4) address/netmask */
932                 if (netif_set_tapaddr(tap_unit, tap_addr, netmask, s) < 0)
933                         return -1;
934         } else {
935                 /* Tie tap(4) to bridge(4) */
936                 if (netif_add_tap2brg(tap_unit, ifbridge, s) < 0)
937                         return -1;
938         }
939
940         *addr = netif_addr;
941         *mask = netmask;
942         return 0;
943 }
944
945 /*
946  * NetifInfo[] will be filled for pseudo netif initialization.
947  * NetifNum will be bumped to reflect the number of valid entries
948  * in NetifInfo[].
949  */
950 static
951 void
952 init_netif(char *netifExp[], int netifExpNum)
953 {
954         int i, s;
955
956         if (netifExpNum == 0)
957                 return;
958
959         s = socket(AF_INET, SOCK_DGRAM, 0);     /* for ioctl(SIOC) */
960         if (s < 0)
961                 return;
962
963         for (i = 0; i < netifExpNum; ++i) {
964                 struct vknetif_info *info;
965                 in_addr_t netif_addr, netif_mask;
966                 int tap_fd, tap_unit;
967                 char *netif;
968
969                 netif = strtok(netifExp[i], ":");
970                 if (netif == NULL) {
971                         warnx("Invalid argument to '-I'");
972                         continue;
973                 }
974
975                 /*
976                  * Open tap(4) device file and bring up the
977                  * corresponding interface
978                  */
979                 tap_fd = netif_open_tap(netif, &tap_unit, s);
980                 if (tap_fd < 0)
981                         continue;
982
983                 /*
984                  * Initialize tap(4) and get address/netmask
985                  * for pseudo netif
986                  *
987                  * NB: Rest part of netifExp[i] is passed
988                  *     to netif_init_tap() implicitly.
989                  */
990                 if (netif_init_tap(tap_unit, &netif_addr, &netif_mask, s) < 0) {
991                         /*
992                          * NB: Closing tap(4) device file will bring
993                          *     down the corresponding interface
994                          */
995                         close(tap_fd);
996                         continue;
997                 }
998
999                 info = &NetifInfo[NetifNum];
1000                 info->tap_fd = tap_fd;
1001                 info->tap_unit = tap_unit;
1002                 info->netif_addr = netif_addr;
1003                 info->netif_mask = netif_mask;
1004
1005                 NetifNum++;
1006                 if (NetifNum >= VKNETIF_MAX)    /* XXX will this happen? */
1007                         break;
1008         }
1009         close(s);
1010 }
1011
1012 static
1013 void
1014 usage(const char *ctl)
1015 {
1016         
1017 }
1018
1019 void
1020 cpu_reset(void)
1021 {
1022         kprintf("cpu reset\n");
1023         exit(0);
1024 }
1025
1026 void
1027 cpu_halt(void)
1028 {
1029         kprintf("cpu halt\n");
1030         for (;;)
1031                 __asm__ __volatile("hlt");
1032 }