|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989, 1988 Carnegie Mellon University
4: * All Rights Reserved.
5: *
6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
11: *
12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15: *
16: * Carnegie Mellon requests users of this software to return to
17: *
18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
22: *
23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: * File: model_dep.c
28: * Author: Avadis Tevanian, Jr., Michael Wayne Young
29: *
30: * Copyright (C) 1986, Avadis Tevanian, Jr., Michael Wayne Young
31: *
32: * Basic initialization for I386 - ISA bus machines.
33: */
34:
35: #include <platforms.h>
36: #include <mach_kdb.h>
37:
38: #include <mach/vm_param.h>
39: #include <mach/vm_prot.h>
40: #include <mach/machine.h>
41: #include <mach/machine/multiboot.h>
42:
43: #include "vm_param.h"
44: #include <kern/time_out.h>
45: #include <sys/time.h>
46: #include <vm/vm_page.h>
47: #include <i386/machspl.h>
48: #include <i386/pmap.h>
49: #include "proc_reg.h"
50:
51: /* Location of the kernel's symbol table.
52: Both of these are 0 if none is available. */
53: #if MACH_KDB
54: static vm_offset_t kern_sym_start, kern_sym_end;
55: #else
56: #define kern_sym_start 0
57: #define kern_sym_end 0
58: #endif
59:
60: /* These indicate the total extent of physical memory addresses we're using.
61: They are page-aligned. */
62: vm_offset_t phys_first_addr = 0;
63: vm_offset_t phys_last_addr;
64:
65: /* Virtual address of physical memory, for the kvtophys/phystokv macros. */
66: vm_offset_t phys_mem_va;
67:
68: struct multiboot_info *boot_info;
69:
70: /* Command line supplied to kernel. */
71: char *kernel_cmdline = "";
72:
73: /* This is used for memory initialization:
74: it gets bumped up through physical memory
75: that exists and is not occupied by boot gunk.
76: It is not necessarily page-aligned. */
77: static vm_offset_t avail_next = 0x1000; /* XX end of BIOS data area */
78:
79: /* Possibly overestimated amount of available memory
80: still remaining to be handed to the VM system. */
81: static vm_size_t avail_remaining;
82:
83: /* Configuration parameter:
84: if zero, only use physical memory in the low 16MB of addresses.
85: Only SCSI still has DMA problems. */
86: #ifdef LINUX_DEV
87: int use_all_mem = 1;
88: #else
89: #include "nscsi.h"
90: #if NSCSI > 0
91: int use_all_mem = 0;
92: #else
93: int use_all_mem = 1;
94: #endif
95: #endif
96:
97: extern char version[];
98:
99: extern void setup_main();
100:
101: void inittodr(); /* forward */
102:
103: int rebootflag = 0; /* exported to kdintr */
104:
105: /* XX interrupt stack pointer and highwater mark, for locore.S. */
106: vm_offset_t int_stack_top, int_stack_high;
107:
108: #ifdef LINUX_DEV
109: extern void linux_init(void);
110: #endif
111:
112: /*
113: * Find devices. The system is alive.
114: */
115: void machine_init()
116: {
117: /*
118: * Initialize the console.
119: */
120: cninit();
121:
122: /*
123: * Set up to use floating point.
124: */
125: init_fpu();
126:
127: #ifdef LINUX_DEV
128: /*
129: * Initialize Linux drivers.
130: */
131: linux_init();
132: #endif
133:
134: /*
135: * Find the devices
136: */
137: probeio();
138:
139: /*
140: * Get the time
141: */
142: inittodr();
143:
144: /*
145: * Tell the BIOS not to clear and test memory.
146: */
147: *(unsigned short *)phystokv(0x472) = 0x1234;
148:
149: /*
150: * Unmap page 0 to trap NULL references.
151: */
152: pmap_unmap_page_zero();
153: }
154:
155: /*
156: * Halt a cpu.
157: */
158: halt_cpu()
159: {
160: asm volatile("cli");
161: while(1);
162: }
163:
164: /*
165: * Halt the system or reboot.
166: */
167: halt_all_cpus(reboot)
168: boolean_t reboot;
169: {
170: if (reboot) {
171: kdreboot();
172: }
173: else {
174: rebootflag = 1;
175: printf("In tight loop: hit ctl-alt-del to reboot\n");
176: (void) spl0();
177: }
178: for (;;)
179: continue;
180: }
181:
182: void exit(int rc)
183: {
184: halt_all_cpus(0);
185: }
186:
187: void db_reset_cpu()
188: {
189: halt_all_cpus(1);
190: }
191:
192:
193: /*
194: * Compute physical memory size and other parameters.
195: */
196: void
197: mem_size_init()
198: {
199: /* Physical memory on all PCs starts at physical address 0.
200: XX make it a constant. */
201: phys_first_addr = 0;
202:
203: phys_last_addr = 0x100000 + (boot_info->mem_upper * 0x400);
204: avail_remaining
205: = phys_last_addr - (0x100000 - (boot_info->mem_lower * 0x400)
206: - 0x1000);
207:
208: printf("AT386 boot: physical memory from 0x%x to 0x%x\n",
209: phys_first_addr, phys_last_addr);
210:
211: if ((!use_all_mem) && phys_last_addr > 16 * 1024*1024) {
212: printf("** Limiting useable memory to 16 Meg to avoid DMA problems.\n");
213: /* This is actually enforced below, in init_alloc_aligned. */
214: }
215:
216: phys_first_addr = round_page(phys_first_addr);
217: phys_last_addr = trunc_page(phys_last_addr);
218: }
219:
220: /*
221: * Basic PC VM initialization.
222: * Turns on paging and changes the kernel segments to use high linear addresses.
223: */
224: i386at_init()
225: {
226: /* XXX move to intel/pmap.h */
227: extern pt_entry_t *kernel_page_dir;
228:
229: /*
230: * Initialize the PIC prior to any possible call to an spl.
231: */
232: picinit();
233:
234: /*
235: * Find memory size parameters.
236: */
237: mem_size_init();
238:
239: /*
240: * Initialize kernel physical map, mapping the
241: * region from loadpt to avail_start.
242: * Kernel virtual address starts at VM_KERNEL_MIN_ADDRESS.
243: * XXX make the BIOS page (page 0) read-only.
244: */
245: pmap_bootstrap();
246:
247: /*
248: * Turn paging on.
249: * We'll have to temporarily install a direct mapping
250: * between physical memory and low linear memory,
251: * until we start using our new kernel segment descriptors.
252: * One page table (4MB) should do the trick.
253: * Also, set the WP bit so that on 486 or better processors
254: * page-level write protection works in kernel mode.
255: */
256: kernel_page_dir[lin2pdenum(0)] =
257: kernel_page_dir[lin2pdenum(LINEAR_MIN_KERNEL_ADDRESS)];
258: set_cr3((unsigned)kernel_page_dir);
259: set_cr0(get_cr0() | CR0_PG | CR0_WP);
260: flush_instr_queue();
261:
262: /*
263: * Initialize and activate the real i386 protected-mode structures.
264: */
265: gdt_init();
266: idt_init();
267: int_init();
268: ldt_init();
269: ktss_init();
270:
271: /* Get rid of the temporary direct mapping and flush it out of the TLB. */
272: kernel_page_dir[lin2pdenum(0)] = 0;
273: set_cr3((unsigned)kernel_page_dir);
274:
275:
276:
277: /* XXX We'll just use the initialization stack we're already running on
278: as the interrupt stack for now. Later this will have to change,
279: because the init stack will get freed after bootup. */
280: asm("movl %%esp,%0" : "=m" (int_stack_top));
281:
282: /* Interrupt stacks are allocated in physical memory,
283: while kernel stacks are allocated in kernel virtual memory,
284: so phys_last_addr serves as a convenient dividing point. */
285: int_stack_high = phys_last_addr;
286: }
287:
288: /*
289: * C boot entrypoint - called by boot_entry in boothdr.S.
290: * Running in 32-bit flat mode, but without paging yet.
291: */
292: void c_boot_entry(vm_offset_t bi)
293: {
294: /* Stash the boot_image_info pointer. */
295: boot_info = (struct multiboot_info*)phystokv(bi);
296:
297: /* XXX we currently assume phys_mem_va is always 0 here -
298: if it isn't, we must tweak the pointers in the boot_info. */
299:
300: /* Before we do _anything_ else, print the hello message.
301: If there are no initialized console devices yet,
302: it will be stored and printed at the first opportunity. */
303: printf(version);
304: printf("\n");
305:
306: /* Find the kernel command line, if there is one. */
307: if (boot_info->flags & MULTIBOOT_CMDLINE)
308: kernel_cmdline = (char*)phystokv(boot_info->cmdline);
309:
310: #if MACH_KDB
311: /*
312: * Locate the kernel's symbol table, if the boot loader provided it.
313: * We need to do this before i386at_init()
314: * so that the symbol table's memory won't be stomped on.
315: */
316: if ((boot_info->flags & MULTIBOOT_AOUT_SYMS)
317: && boot_info->syms.a.addr)
318: {
319: vm_size_t symtab_size, strtab_size;
320:
321: kern_sym_start = (vm_offset_t)phystokv(boot_info->syms.a.addr);
322: symtab_size = (vm_offset_t)phystokv(boot_info->syms.a.tabsize);
323: strtab_size = (vm_offset_t)phystokv(boot_info->syms.a.strsize);
324: kern_sym_end = kern_sym_start + 4 + symtab_size + strtab_size;
325:
326: printf("kernel symbol table at %08x-%08x (%d,%d)\n",
327: kern_sym_start, kern_sym_end,
328: symtab_size, strtab_size);
329: }
330: #endif MACH_KDB
331:
332: /*
333: * Do basic VM initialization
334: */
335: i386at_init();
336:
337: #if MACH_KDB
338: /*
339: * Initialize the kernel debugger's kernel symbol table.
340: */
341: if (kern_sym_start)
342: {
343: aout_db_sym_init(kern_sym_start, kern_sym_end, "mach", 0);
344: }
345:
346: /*
347: * Cause a breakpoint trap to the debugger before proceeding
348: * any further if the proper option flag was specified
349: * on the kernel's command line.
350: * XXX check for surrounding spaces.
351: */
352: if (strstr(kernel_cmdline, "-d ")) {
353: cninit(); /* need console for debugger */
354: Debugger();
355: }
356: #endif MACH_KDB
357:
358: machine_slot[0].is_cpu = TRUE;
359: machine_slot[0].running = TRUE;
360: machine_slot[0].cpu_subtype = CPU_SUBTYPE_AT386;
361:
1.1.1.2 ! root 362: #if 0
! 363: switch (discover_x86_cpu_type ())
! 364: {
! 365: case 3:
! 366: default:
! 367: machine_slot[0].cpu_type = CPU_TYPE_I386;
! 368: break;
! 369: case 4:
! 370: machine_slot[0].cpu_type = CPU_TYPE_I486;
! 371: break;
! 372: case 5:
! 373: machine_slot[0].cpu_type = CPU_TYPE_PENTIUM;
! 374: break;
! 375: case 6:
! 376: machine_slot[0].cpu_type = CPU_TYPE_PENTIUMPRO;
! 377: break;
! 378: }
! 379: #else
! 380: machine_slot[0].cpu_type = CPU_TYPE_I386;
! 381: #endif
! 382:
! 383:
1.1 root 384: /*
385: * Start the system.
386: */
387: setup_main();
388:
389: }
390:
391: #include <mach/vm_prot.h>
392: #include <vm/pmap.h>
393: #include <mach/time_value.h>
394:
395: timemmap(dev,off,prot)
396: vm_prot_t prot;
397: {
398: extern time_value_t *mtime;
399:
400: #ifdef lint
401: dev++; off++;
402: #endif lint
403:
404: if (prot & VM_PROT_WRITE) return (-1);
405:
406: return (i386_btop(pmap_extract(pmap_kernel(), (vm_offset_t) mtime)));
407: }
408:
409: startrtclock()
410: {
411: clkstart();
412: }
413:
414: void
415: inittodr()
416: {
417: time_value_t new_time;
418:
419: new_time.seconds = 0;
420: new_time.microseconds = 0;
421:
422: (void) readtodc(&new_time.seconds);
423:
424: {
425: spl_t s = splhigh();
426: time = new_time;
427: splx(s);
428: }
429: }
430:
431: void
432: resettodr()
433: {
434: writetodc();
435: }
436:
437: unsigned int pmap_free_pages()
438: {
439: return atop(avail_remaining);
440: }
441:
442: /* Always returns page-aligned regions. */
443: boolean_t
444: init_alloc_aligned(vm_size_t size, vm_offset_t *addrp)
445: {
446: vm_offset_t addr;
447: extern char start[], end[];
448: int i;
449:
450: /* Memory regions to skip. */
451: vm_offset_t boot_info_start_pa = kvtophys(boot_info);
452: vm_offset_t boot_info_end_pa = boot_info_start_pa + sizeof(*boot_info);
453: vm_offset_t cmdline_start_pa = boot_info->flags & MULTIBOOT_CMDLINE
454: ? boot_info->cmdline : 0;
455: vm_offset_t cmdline_end_pa = cmdline_start_pa
456: ? cmdline_start_pa+strlen((char*)phystokv(cmdline_start_pa))+1
457: : 0;
458: vm_offset_t mods_start_pa = boot_info->flags & MULTIBOOT_MODS
459: ? boot_info->mods_addr : 0;
460: vm_offset_t mods_end_pa = mods_start_pa
461: ? mods_start_pa
462: + boot_info->mods_count * sizeof(struct multiboot_module)
463: : 0;
464:
465: retry:
466:
467: /* Page-align the start address. */
468: avail_next = round_page(avail_next);
469:
470: /* Check if we have reached the end of memory. */
471: if (avail_next == phys_last_addr)
472: return FALSE;
473:
474: /* Tentatively assign the current location to the caller. */
475: addr = avail_next;
476:
477: /* Bump the pointer past the newly allocated region
478: and see where that puts us. */
479: avail_next += size;
480:
481: /* Skip past the I/O and ROM area. */
482: if ((avail_next > (boot_info->mem_lower * 0x400)) && (addr < 0x100000))
483: {
484: avail_next = 0x100000;
485: goto retry;
486: }
487:
488: /* If we're only supposed to use the low 16 megs, enforce that. */
489: if ((!use_all_mem) && (addr >= 16 * 1024*1024)) {
490: return FALSE;
491: }
492:
493: /* Skip our own kernel code, data, and bss. */
494: if ((avail_next >= (vm_offset_t)start) && (addr < (vm_offset_t)end))
495: {
496: avail_next = (vm_offset_t)end;
497: goto retry;
498: }
499:
500: /* Skip any areas occupied by valuable boot_info data. */
501: if ((avail_next > boot_info_start_pa) && (addr < boot_info_end_pa))
502: {
503: avail_next = boot_info_end_pa;
504: goto retry;
505: }
506: if ((avail_next > cmdline_start_pa) && (addr < cmdline_end_pa))
507: {
508: avail_next = cmdline_end_pa;
509: goto retry;
510: }
511: if ((avail_next > mods_start_pa) && (addr < mods_end_pa))
512: {
513: avail_next = mods_end_pa;
514: goto retry;
515: }
516: if ((avail_next > kern_sym_start) && (addr < kern_sym_end))
517: {
518: avail_next = kern_sym_end;
519: goto retry;
520: }
521: if (boot_info->flags & MULTIBOOT_MODS)
522: {
523: struct multiboot_module *m = (struct multiboot_module *)
524: phystokv(boot_info->mods_addr);
525: for (i = 0; i < boot_info->mods_count; i++)
526: {
527: if ((avail_next > m[i].mod_start)
528: && (addr < m[i].mod_end))
529: {
530: avail_next = m[i].mod_end;
531: goto retry;
532: }
533: /* XXX string */
534: }
535: }
536:
537: avail_remaining -= size;
538:
539: *addrp = addr;
540: return TRUE;
541: }
542:
543: boolean_t pmap_next_page(addrp)
544: vm_offset_t *addrp;
545: {
546: return init_alloc_aligned(PAGE_SIZE, addrp);
547: }
548:
549: /* Grab a physical page:
550: the standard memory allocation mechanism
551: during system initialization. */
552: vm_offset_t
553: pmap_grab_page()
554: {
555: vm_offset_t addr;
556: if (!pmap_next_page(&addr))
557: panic("Not enough memory to initialize Mach");
558: return addr;
559: }
560:
561: boolean_t pmap_valid_page(x)
562: vm_offset_t x;
563: {
564: /* XXX is this OK? What does it matter for? */
565: return (((phys_first_addr <= x) && (x < phys_last_addr)) &&
566: !(((boot_info->mem_lower * 1024) <= x) && (x < 1024*1024)));
567: }
568:
569: #ifndef NBBY
570: #define NBBY 8
571: #endif
572: #ifndef NBPW
573: #define NBPW (NBBY * sizeof(int))
574: #endif
575: #define DMA_MAX (16*1024*1024)
576:
577: /*
578: * Allocate contiguous pages below 16 MB
579: * starting at specified boundary for DMA.
580: */
581: vm_offset_t
582: alloc_dma_mem(size, align)
583: vm_size_t size;
584: vm_offset_t align;
585: {
586: int *bits, i, j, k, n;
587: int npages, count, bit, mask;
588: int first_page, last_page;
589: vm_offset_t addr;
590: vm_page_t p, prevp;
591:
592: npages = round_page(size) / PAGE_SIZE;
593: mask = align ? (align - 1) / PAGE_SIZE : 0;
594:
595: /*
596: * Allocate bit array.
597: */
598: n = ((DMA_MAX / PAGE_SIZE) + NBPW - 1) / NBPW;
599: i = n * NBPW;
600: bits = (unsigned *)kalloc(i);
601: if (bits == 0) {
602: printf("alloc_dma_mem: unable alloc bit array\n");
603: return (0);
604: }
605: bzero((char *)bits, i);
606:
607: /*
608: * Walk the page free list and set a bit for
609: * every usable page in bit array.
610: */
611: simple_lock(&vm_page_queue_free_lock);
612: for (p = vm_page_queue_free; p; p = (vm_page_t)p->pageq.next) {
613: if (p->phys_addr < DMA_MAX) {
614: i = p->phys_addr / PAGE_SIZE;
615: bits[i / NBPW] |= 1 << (i % NBPW);
616: }
617: }
618:
619: /*
620: * Search for contiguous pages by scanning bit array.
621: */
622: for (i = 0, first_page = -1; i < n; i++) {
623: for (bit = 1, j = 0; j < NBPW; j++, bit <<= 1) {
624: if (bits[i] & bit) {
625: if (first_page < 0) {
626: k = i * NBPW + j;
627: if (!mask
628: || (((k & mask) + npages)
629: <= mask + 1)) {
630: first_page = k;
631: if (npages == 1)
632: goto found;
633: count = 1;
634: }
635: } else if (++count == npages)
636: goto found;
637: } else
638: first_page = -1;
639: }
640: }
641: addr = 0;
642: goto out;
643:
644: found:
645: /*
646: * Remove pages from the free list.
647: */
648: addr = first_page * PAGE_SIZE;
649: last_page = first_page + npages;
650: vm_page_free_count -= npages;
651: p = vm_page_queue_free;
652: prevp = 0;
653: while (1) {
654: i = p->phys_addr / PAGE_SIZE;
655: if (i >= first_page && i < last_page) {
656: if (prevp)
657: prevp->pageq.next = p->pageq.next;
658: else
659: vm_page_queue_free = (vm_page_t)p->pageq.next;
660: p->free = FALSE;
661: if (--npages == 0)
662: break;
663: } else
664: prevp = p;
665: p = (vm_page_t)p->pageq.next;
666: }
667:
668: out:
669: simple_unlock(&vm_page_queue_free_lock);
670: kfree((vm_offset_t)bits, n * NBPW);
671: return (addr);
672: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.