Use SEEK_SET instead of magic constant.
[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.17 2007/01/10 03:04:28 corecode 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/proc.h>
47 #include <sys/msgbuf.h>
48 #include <sys/vmspace.h>
49 #include <vm/vm_page.h>
50
51 #include <machine/globaldata.h>
52 #include <machine/tls.h>
53 #include <machine/md_var.h>
54 #include <machine/vmparam.h>
55
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <unistd.h>
59 #include <fcntl.h>
60 #include <string.h>
61 #include <err.h>
62 #include <errno.h>
63 #include <assert.h>
64
65 vm_paddr_t phys_avail[16];
66 vm_paddr_t Maxmem;
67 vm_paddr_t Maxmem_bytes;
68 int MemImageFd = -1;
69 int RootImageFd = -1;
70 vm_offset_t KvaStart;
71 vm_offset_t KvaEnd;
72 vm_offset_t KvaSize;
73 vm_offset_t virtual_start;
74 vm_offset_t virtual_end;
75 vm_offset_t kernel_vm_end;
76 vm_offset_t crashdumpmap;
77 vm_offset_t clean_sva;
78 vm_offset_t clean_eva;
79 struct msgbuf *msgbufp;
80 caddr_t ptvmmap;
81 vpte_t  *KernelPTD;
82 vpte_t  *KernelPTA;     /* Warning: Offset for direct VA translation */
83 u_int cpu_feature;      /* XXX */
84 u_int tsc_present;      /* XXX */
85
86 struct privatespace *CPU_prvspace;
87
88 static struct trapframe proc0_tf;
89 static void *proc0paddr;
90
91 static void init_sys_memory(char *imageFile);
92 static void init_kern_memory(void);
93 static void init_globaldata(void);
94 static void init_vkernel(void);
95 static void init_rootdevice(char *imageFile);
96 static void usage(const char *ctl);
97
98 /*
99  * Kernel startup for virtual kernels - standard main() 
100  */
101 int
102 main(int ac, char **av)
103 {
104         char *memImageFile = NULL;
105         char *rootImageFile = NULL;
106         char *suffix;
107         int c;
108         int i;
109         int n;
110
111         /*
112          * Process options
113          */
114         while ((c = getopt(ac, av, "vm:r:e:")) != -1) {
115                 switch(c) {
116                 case 'e':
117                         /*
118                          * name=value:name=value:name=value...
119                          */
120                         n = strlen(optarg);
121                         kern_envp = malloc(n + 2);
122                         for (i = 0; i < n; ++i) {
123                                 if (optarg[i] == ':')
124                                         kern_envp[i] = 0;
125                                 else
126                                         kern_envp[i] = optarg[i];
127                         }
128                         kern_envp[i++] = 0;
129                         kern_envp[i++] = 0;
130                         break;
131                 case 'v':
132                         bootverbose = 1;
133                         break;
134                 case 'i':
135                         memImageFile = optarg;
136                         break;
137                 case 'r':
138                         rootImageFile = optarg;
139                         break;
140                 case 'm':
141                         Maxmem_bytes = strtoull(optarg, &suffix, 0);
142                         if (suffix) {
143                                 switch(*suffix) {
144                                 case 'g':
145                                 case 'G':
146                                         Maxmem_bytes <<= 30;
147                                         break;
148                                 case 'm':
149                                 case 'M':
150                                         Maxmem_bytes <<= 20;
151                                         break;
152                                 case 'k':
153                                 case 'K':
154                                         Maxmem_bytes <<= 10;
155                                         break;
156                                 default:
157                                         Maxmem_bytes = 0;
158                                         usage("Bad maxmem option");
159                                         /* NOT REACHED */
160                                         break;
161                                 }
162                         }
163                         break;
164                 }
165         }
166
167         init_sys_memory(memImageFile);
168         init_kern_memory();
169         init_globaldata();
170         init_vkernel();
171         init_rootdevice(rootImageFile);
172         init_exceptions();
173         mi_startup();
174         /* NOT REACHED */
175         exit(1);
176 }
177
178 /*
179  * Initialize system memory.  This is the virtual kernel's 'RAM'.
180  */
181 static
182 void
183 init_sys_memory(char *imageFile)
184 {
185         struct stat st;
186         int i;
187         int fd;
188
189         /*
190          * Figure out the system memory image size.  If an image file was
191          * specified and -m was not specified, use the image file's size.
192          */
193
194         if (imageFile && stat(imageFile, &st) == 0 && Maxmem_bytes == 0)
195                 Maxmem_bytes = (vm_paddr_t)st.st_size;
196         if ((imageFile == NULL || stat(imageFile, &st) < 0) && 
197             Maxmem_bytes == 0) {
198                 err(1, "Cannot create new memory file %s unless "
199                        "system memory size is specified with -m",
200                        imageFile);
201                 /* NOT REACHED */
202         }
203
204         /*
205          * Maxmem must be known at this time
206          */
207         if (Maxmem_bytes < 32 * 1024 * 1024 || (Maxmem_bytes & SEG_MASK)) {
208                 err(1, "Bad maxmem specification: 32MB minimum, "
209                        "multiples of %dMB only",
210                        SEG_SIZE / 1024 / 1024);
211                 /* NOT REACHED */
212         }
213
214         /*
215          * Generate an image file name if necessary, then open/create the
216          * file exclusively locked.  Do not allow multiple virtual kernels
217          * to use the same image file.
218          */
219         if (imageFile == NULL) {
220                 for (i = 0; i < 1000000; ++i) {
221                         asprintf(&imageFile, "/var/vkernel/memimg.%06d", i);
222                         fd = open(imageFile, 
223                                   O_RDWR|O_CREAT|O_EXLOCK|O_NONBLOCK, 0644);
224                         if (fd < 0 && errno == EWOULDBLOCK) {
225                                 free(imageFile);
226                                 continue;
227                         }
228                         break;
229                 }
230         } else {
231                 fd = open(imageFile, O_RDWR|O_CREAT|O_EXLOCK|O_NONBLOCK, 0644);
232         }
233         printf("Using memory file: %s\n", imageFile);
234         if (fd < 0 || fstat(fd, &st) < 0) {
235                 err(1, "Unable to open/create %s: %s",
236                       imageFile, strerror(errno));
237                 /* NOT REACHED */
238         }
239
240         /*
241          * Truncate or extend the file as necessary.
242          */
243         if (st.st_size > Maxmem_bytes) {
244                 ftruncate(fd, Maxmem_bytes);
245         } else if (st.st_size < Maxmem_bytes) {
246                 char *zmem;
247                 off_t off = st.st_size & ~SEG_MASK;
248
249                 kprintf("%s: Reserving blocks for memory image\n", imageFile);
250                 zmem = malloc(SEG_SIZE);
251                 bzero(zmem, SEG_SIZE);
252                 lseek(fd, off, SEEK_SET);
253                 while (off < Maxmem_bytes) {
254                         if (write(fd, zmem, SEG_SIZE) != SEG_SIZE) {
255                                 err(1, "Unable to reserve blocks for memory image");
256                                 /* NOT REACHED */
257                         }
258                         off += SEG_SIZE;
259                 }
260                 if (fsync(fd) < 0)
261                         err(1, "Unable to reserve blocks for memory image");
262                 free(zmem);
263         }
264         MemImageFd = fd;
265         Maxmem = Maxmem_bytes >> PAGE_SHIFT;
266 }
267
268 /*
269  * Initialize kernel memory.  This reserves kernel virtual memory by using
270  * MAP_VPAGETABLE
271  */
272 static
273 void
274 init_kern_memory(void)
275 {
276         void *base;
277         char *zero;
278         vpte_t pte;
279         int i;
280
281         /*
282          * Memory map our kernel virtual memory space.  Note that the
283          * kernel image itself is not made part of this memory for the
284          * moment.
285          *
286          * The memory map must be segment-aligned so we can properly
287          * offset KernelPTD.
288          */
289         base = mmap((void *)0x40000000, KERNEL_KVA_SIZE, PROT_READ|PROT_WRITE,
290                     MAP_FILE|MAP_SHARED|MAP_VPAGETABLE, MemImageFd, 0);
291         if (base == MAP_FAILED) {
292                 err(1, "Unable to mmap() kernel virtual memory!");
293                 /* NOT REACHED */
294         }
295         KvaStart = (vm_offset_t)base;
296         KvaSize = KERNEL_KVA_SIZE;
297         KvaEnd = KvaStart + KvaSize;
298
299         /*
300          * Create a top-level page table self-mapping itself. 
301          *
302          * Initialize the page directory at physical page index 0 to point
303          * to an array of page table pages starting at physical page index 1
304          */
305         lseek(MemImageFd, 0L, 0);
306         for (i = 0; i < KERNEL_KVA_SIZE / SEG_SIZE; ++i) {
307                 pte = ((i + 1) * PAGE_SIZE) | VPTE_V | VPTE_R | VPTE_W;
308                 write(MemImageFd, &pte, sizeof(pte));
309         }
310
311         /*
312          * Initialize the PTEs in the page table pages required to map the
313          * page table itself.  This includes mapping the page directory page
314          * at the base so we go one more loop then normal.
315          */
316         lseek(MemImageFd, PAGE_SIZE, 0);
317         for (i = 0; i <= KERNEL_KVA_SIZE / SEG_SIZE * sizeof(vpte_t); ++i) {
318                 pte = (i * PAGE_SIZE) | VPTE_V | VPTE_R | VPTE_W;
319                 write(MemImageFd, &pte, sizeof(pte));
320         }
321
322         /*
323          * Initialize remaining PTEs to 0.  We may be reusing a memory image
324          * file.  This is approximately a megabyte.
325          */
326         i = (KERNEL_KVA_SIZE / PAGE_SIZE - i) * sizeof(pte);
327         zero = malloc(PAGE_SIZE);
328         while (i) {
329                 write(MemImageFd, zero, (i > PAGE_SIZE) ? PAGE_SIZE : i);
330                 i = i - ((i > PAGE_SIZE) ? PAGE_SIZE : i);
331         }
332         free(zero);
333
334         /*
335          * Enable the page table and calculate pointers to our self-map
336          * for easy kernel page table manipulation.
337          *
338          * KernelPTA must be offset so we can do direct VA translations
339          */
340         mcontrol(base, KERNEL_KVA_SIZE, MADV_SETMAP,
341                  0 | VPTE_R | VPTE_W | VPTE_V);
342         KernelPTD = (vpte_t *)base;                       /* pg directory */
343         KernelPTA = (vpte_t *)((char *)base + PAGE_SIZE); /* pg table pages */
344         KernelPTA -= KvaStart >> PAGE_SHIFT;
345
346         /*
347          * phys_avail[] represents unallocated physical memory.  MI code
348          * will use phys_avail[] to create the vm_page array.
349          */
350         phys_avail[0] = PAGE_SIZE +
351                         KERNEL_KVA_SIZE / PAGE_SIZE * sizeof(vpte_t);
352         phys_avail[0] = (phys_avail[0] + PAGE_MASK) & ~(vm_paddr_t)PAGE_MASK;
353         phys_avail[1] = Maxmem_bytes;
354
355         /*
356          * (virtual_start, virtual_end) represent unallocated kernel virtual
357          * memory.  MI code will create kernel_map using these parameters.
358          */
359         virtual_start = KvaStart + PAGE_SIZE +
360                         KERNEL_KVA_SIZE / PAGE_SIZE * sizeof(vpte_t);
361         virtual_start = (virtual_start + PAGE_MASK) & ~(vm_offset_t)PAGE_MASK;
362         virtual_end = KvaStart + KERNEL_KVA_SIZE;
363
364         /*
365          * Because we just pre-allocate the entire page table the demark used
366          * to determine when KVM must be grown is just set to the end of
367          * KVM.  pmap_growkernel() simply panics.
368          */
369         kernel_vm_end = virtual_end;
370
371         /*
372          * Allocate space for process 0's UAREA.
373          */
374         proc0paddr = (void *)virtual_start;
375         for (i = 0; i < UPAGES; ++i) {
376                 pmap_kenter_quick(virtual_start, phys_avail[0]);
377                 virtual_start += PAGE_SIZE;
378                 phys_avail[0] += PAGE_SIZE;
379         }
380
381         /*
382          * crashdumpmap
383          */
384         crashdumpmap = virtual_start;
385         virtual_start += MAXDUMPPGS * PAGE_SIZE;
386
387         /*
388          * msgbufp maps the system message buffer
389          */
390         assert((MSGBUF_SIZE & PAGE_MASK) == 0);
391         msgbufp = (void *)virtual_start;
392         for (i = 0; i < (MSGBUF_SIZE >> PAGE_SHIFT); ++i) {
393                 pmap_kenter_quick(virtual_start, phys_avail[0]);
394                 virtual_start += PAGE_SIZE;
395                 phys_avail[0] += PAGE_SIZE;
396         }
397         msgbufinit(msgbufp, MSGBUF_SIZE);
398
399         /*
400          * used by kern_memio for /dev/mem access
401          */
402         ptvmmap = (caddr_t)virtual_start;
403         virtual_start += PAGE_SIZE;
404
405         /*
406          * Bootstrap the kernel_pmap
407          */
408         pmap_bootstrap();
409 }
410
411 /*
412  * Map the per-cpu globaldata for cpu #0.  Allocate the space using
413  * virtual_start and phys_avail[0]
414  */
415 static
416 void
417 init_globaldata(void)
418 {
419         int i;
420         vm_paddr_t pa;
421         vm_offset_t va;
422
423         /*
424          * Reserve enough KVA to cover possible cpus.  This is a considerable
425          * amount of KVA since the privatespace structure includes two 
426          * whole page table mappings.
427          */
428         virtual_start = (virtual_start + SEG_MASK) & ~(vm_offset_t)SEG_MASK;
429         CPU_prvspace = (void *)virtual_start;
430         virtual_start += sizeof(struct privatespace) * SMP_MAXCPU;
431
432         /*
433          * Allocate enough physical memory to cover the mdglobaldata
434          * portion of the space and the idle stack and map the pages
435          * into KVA.  For cpu #0 only.
436          */
437         for (i = 0; i < sizeof(struct mdglobaldata); i += PAGE_SIZE) {
438                 pa = phys_avail[0];
439                 va = (vm_offset_t)&CPU_prvspace[0].mdglobaldata + i;
440                 pmap_kenter_quick(va, pa);
441                 phys_avail[0] += PAGE_SIZE;
442         }
443         for (i = 0; i < sizeof(CPU_prvspace[0].idlestack); i += PAGE_SIZE) {
444                 pa = phys_avail[0];
445                 va = (vm_offset_t)&CPU_prvspace[0].idlestack + i;
446                 pmap_kenter_quick(va, pa);
447                 phys_avail[0] += PAGE_SIZE;
448         }
449
450         /*
451          * Setup the %gs for cpu #0.  The mycpu macro works after this
452          * point.
453          */
454         tls_set_fs(&CPU_prvspace[0], sizeof(struct privatespace));
455 }
456
457 /*
458  * Initialize very low level systems including thread0, proc0, etc.
459  */
460 static
461 void
462 init_vkernel(void)
463 {
464         struct mdglobaldata *gd;
465
466         gd = &CPU_prvspace[0].mdglobaldata;
467         bzero(gd, sizeof(*gd));
468
469         gd->mi.gd_curthread = &thread0;
470         thread0.td_gd = &gd->mi;
471         ncpus = 1;
472         ncpus2 = 1;
473         init_param1();
474         gd->mi.gd_prvspace = &CPU_prvspace[0];
475         mi_gdinit(&gd->mi, 0);
476         cpu_gdinit(gd, 0);
477         mi_proc0init(&gd->mi, proc0paddr);
478         proc0.p_lwp.lwp_md.md_regs = &proc0_tf;
479
480         /*init_locks();*/
481         cninit();
482         rand_initialize();
483 #if 0   /* #ifdef DDB */
484         kdb_init();
485         if (boothowto & RB_KDB)
486                 Debugger("Boot flags requested debugger");
487 #endif
488 #if 0
489         initializecpu();        /* Initialize CPU registers */
490 #endif
491         init_param2((phys_avail[1] - phys_avail[0]) / PAGE_SIZE);
492
493 #if 0
494         /*
495          * Map the message buffer
496          */
497         for (off = 0; off < round_page(MSGBUF_SIZE); off += PAGE_SIZE)
498                 pmap_kenter((vm_offset_t)msgbufp + off, avail_end + off);
499         msgbufinit(msgbufp, MSGBUF_SIZE);
500 #endif
501 #if 0
502         thread0.td_pcb_cr3 ... MMU
503         proc0.p_lwp.lwp_md.md_regs = &proc0_tf;
504 #endif
505 }
506
507 /*
508  * The root filesystem path for the virtual kernel is optional.  If specified
509  * it points to a filesystem image.
510  */
511 static
512 void
513 init_rootdevice(char *imageFile)
514 {
515         struct stat st;
516
517         if (imageFile) {
518                 RootImageFd = open(imageFile, O_RDWR, 0644);
519                 if (RootImageFd < 0 || fstat(RootImageFd, &st) < 0) {
520                         err(1, "Unable to open/create %s: %s",
521                             imageFile, strerror(errno));
522                         /* NOT REACHED */
523                 }
524                 rootdevnames[0] = "ufs:vkd0a";
525         }
526 }
527
528 static
529 void
530 usage(const char *ctl)
531 {
532         
533 }
534
535 void
536 cpu_reset(void)
537 {
538         kprintf("cpu reset\n");
539         exit(0);
540 }
541
542 void
543 cpu_halt(void)
544 {
545         kprintf("cpu halt\n");
546         for (;;)
547                 __asm__ __volatile("hlt");
548 }