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