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