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