|
|
1.1 root 1: /* main entrypoint (from oskit multiboot_main) for Mach.
2: It turns out this file is almost entirely machine-dependent.
3:
4: This file defines `main', which is the entrypoint from the oskit.
5: It calls `setup_main' (kern/startup.c) after setting up the machine,
6: interrupts, paging, and `machine_slot[0]'; setup_main never returns.
7: This file defines `machine_init', which is called after VM is set up.
8: */
9:
10: #include <oskit/clientos.h>
11: #include <oskit/machine/base_multiboot.h>
12: #include <oskit/machine/base_stack.h>
13: #include <oskit/machine/physmem.h>
14: #include <oskit/x86/base_cpu.h>
15: #include <oskit/x86/debug_reg.h>
16: #include <oskit/lmm.h>
17: #include <oskit/machine/phys_lmm.h>
18: #include <oskit/machine/base_stack.h>
19:
20: #include <mach/vm_param.h>
21: #include <mach/vm_prot.h>
22: #include <mach/machine.h>
23:
24: #include <oskit/x86/proc_reg.h>
25: #include <oskit/x86/paging.h>
26: #include <oskit/x86/base_vm.h>
27: #include <oskit/c/unistd.h>
28: #include <oskit/dev/dev.h>
29: #include <oskit/smp.h>
30: #include "gdt.h"
31:
32: #include <string.h>
33:
34: #include "vm_param.h"
35: #include <kern/time_out.h>
36: #include <sys/time.h>
37: #include <vm/vm_page.h>
38: #include <vm/vm_map.h>
39: #include <kern/zalloc.h>
40: #include <i386/machspl.h>
41: #include <i386/pmap.h>
42: #include <i386/mp_desc.h>
43:
44: #include <kern/cpu_number.h>
45:
46: /* As of 2000-12-21 the oskit has an incorrect value for this constant
47: in <oskit/x86/proc_reg.h>, so we redefine it with the correct one. */
48: #undef CR4_PGE
49: #define CR4_PGE 0x80
50:
51: static void my_exit (int), (*his_exit) (int);
52:
53: /* XXX move to intel/pmap.h */
54: extern pt_entry_t *kernel_page_dir;
55:
56:
57: #include "assert.h"
58:
59: extern char version[];
60:
61: char **kernel_argv;
62: char *kernel_cmdline; /* XXX */
63:
64: void
65: setup_machine_slot (int mycpu)
66: {
67: struct cpu_info info;
68: cpuid (&info);
69:
70: /* Examine the CPU model information provided by the oskit,
71: and set machine_slot[0] to describe the CPU to users who ask. */
72: switch (info.family)
73: {
74: default:
75: case CPU_FAMILY_386:
76: machine_slot[mycpu].cpu_type = CPU_TYPE_I386;
77: break;
78: case CPU_FAMILY_486:
79: machine_slot[mycpu].cpu_type = CPU_TYPE_I486;
80: break;
81: case CPU_FAMILY_PENTIUM:
82: machine_slot[mycpu].cpu_type = CPU_TYPE_PENTIUM;
83: break;
84: case CPU_FAMILY_PENTIUM_PRO:
85: machine_slot[mycpu].cpu_type = CPU_TYPE_PENTIUMPRO;
86: break;
87: }
88: machine_slot[mycpu].cpu_subtype = CPU_SUBTYPE_AT386;
89: machine_slot[mycpu].is_cpu = TRUE;
90: }
91:
92: int
93: main (int argc, char **argv)
94: {
95: oskit_clientos_init ();
96:
97: printf ("Welcome to %s!\r\n", version);
98:
99: /*
100: * Initialize the PIC prior to any possible call to an spl.
101: */
102: picinit();
103:
104: /* Tell the oskit base_* code what virtual addresses we are using
105: to map the linear address space. It can't keep using the 1:1
106: kvtolin mapping once we flush the direct mapping below.
107: We must do this before pmap_bootstrap, because pmap_bootstrap
108: uses kvtolin to decide where to put its mappings! */
109: linear_base_va = -LINEAR_MIN_KERNEL_ADDRESS;
110:
111: /* This allocates the kernel page tables and initializes kernel_pmap. */
112: pmap_bootstrap();
113:
114: /*
115: * Turn paging on.
116: * We'll have to temporarily install a direct mapping
117: * between physical memory and low linear memory,
118: * until we start using our new kernel segment descriptors.
119: * One page table (4MB) should do the trick.
120: * Also, set the WP bit so that on 486 or better processors
121: * page-level write protection works in kernel mode.
122: */
123: kernel_page_dir[lin2pdenum(0)] =
124: kernel_page_dir[lin2pdenum(LINEAR_MIN_KERNEL_ADDRESS)];
125: paging_enable((oskit_addr_t) kernel_page_dir);
126: set_cr0 (get_cr0 () | CR0_WP);
127:
128: if (base_cpuid.feature_flags & CPUF_PAGE_GLOBAL_EXT) {
129: /*
130: * The processor supports the "global" bit to avoid flushing kernel TLB
131: * entries, if we turn it on. pmap_bootstrap checks this feature flag
132: * and begins use the global bit in page table entries. But according
133: * to the x86 specs we cannot set this bit before we do enable_paging
134: * above; setting CR4_PGE first doesn't work on some processors, in fact.
135: */
136: set_cr4 (get_cr4 () | CR4_PGE);
137: }
138:
139: /*
140: * Initialize and activate the real i386 protected-mode structures.
141: */
142: base_gdt_init(); /* reinitialize with linear_base_va */
143: gdt_init();
144: idt_init();
145: int_init();
146: ldt_init();
147:
148: base_cpu_load(); /* Load all the new tables into the CPU. */
149:
150: /* Now reload the TSS using our slot instead of the oskit's. */
151: base_gdt[sel_idx (KERNEL_TSS)].access &= ~ACC_TSS_BUSY;
152: set_tr(KERNEL_TSS);
153:
154: /* Arrange a callback to our special exit function below, so we can
155: try to return to a state the generic oskit reboot code can cope with. */
156: his_exit = oskit_libc_exit;
157: oskit_libc_exit = &my_exit;
158:
159: /* Get rid of the temporary direct mapping and flush it out of the TLB. */
160: kernel_page_dir[lin2pdenum(0)] = 0;
161: inval_tlb();
162:
163: /* Interrupt stacks are allocated in physical memory,
164: while kernel stacks are allocated in kernel virtual memory,
165: so phys_last_addr serves as a convenient dividing point. */
166: int_stack_high = phys_mem_max;
167:
168: #if NCPUS > 1
169: smp_init_paging (); /* This maps physical memory SMP needs. */
170: if (smp_init () != 0)
171: printf ("SMP initialization failed!\n");
172: else
173: {
174: int ncpus;
175: printf ("SMP initialized (maximum %d supported by this kernel).");
176: ncpus = smp_get_num_cpus ();
177: if (ncpus == 1)
178: printf ("Running on a uniprocessor.\n");
179: else
180: {
181: printf ("Detected %d CPUs.\n");
182: if (ncpus > NCPUS)
183: printf ("WARNING: This kernel can only use %d CPUs.\n"
184: "The remaining %d CPUs will be completely idle!"
185: "\nYou should recompile your kernel with --enable-cpus=%d"
186: " or higher.\n",
187: NCPUS, ncpus - NCPUS, ncpus);
188: }
189: master_cpu = smp_find_cur_cpu ();
190: ivect[SMP_IPI_VECTOR] = (int (*)())pmap_update_interrupt;
191: intpri[SMP_IPI_VECTOR] = SPL1;
192: mp_desc_init (master_cpu);
193: }
194: interrupt_stack_alloc ();
195: #endif
196:
197: setup_machine_slot (master_cpu);
198: machine_slot[master_cpu].running = TRUE;
199:
200: kernel_argv = argv; /* Stash our args for user_bootstrap to use. */
201:
202: { /* XXX */
203: static char cmdline[1024];
204: int i;
205: strcpy (cmdline, argv[0]);
206: for (i = 1; i < argc; ++i) {
207: strcat (cmdline, " ");
208: strcat (cmdline, argv[i]);
209: }
210: assert (strlen (cmdline) < sizeof cmdline);
211: kernel_cmdline = cmdline;
212: }
213:
214: /* Start the system. This function does not return. */
215: setup_main();
216: /* NOTREACHED */
217: return -1;
218: }
219:
220: /* This is the function we install in `oskit_libc_exit' to be called
221: by _exit, panic, et al. The oskit provided an original function
222: (now stored in `his_exit'), that will only work properly if we are
223: using direct-mapped physical addresses. So we provide here a
224: replacement that switches to direct linear addressing and moves
225: to a physical-addressed stack and PC to call the oskit's function. */
226: static void
227: my_exit (int rc)
228: {
229: /* Restore direct virtual->physical mapping and switch to
230: direct linear addressing code segment, so the oskit
231: can cope when it tries to turn paging off. */
232:
233: kernel_page_dir[lin2pdenum(0)]
234: = kernel_page_dir[lin2pdenum(LINEAR_MIN_KERNEL_ADDRESS)];
235: set_cr4 (get_cr4 () &~ CR4_PGE);
236: set_pdbr (kvtophys (kernel_page_dir));
237:
238: /* Reload the oskit's GDT slots. */
239: base_gdt_init ();
240: base_gdt_load ();
241:
242: asm volatile (" ljmp %0,$1f \n" /* Switch to LINEAR_CS, */
243: "1: movw %w1,%%ds\n" /* Switch %ds to LINEAR_DS. */
244: " movw %w1,%%es\n" /* Switch %es to LINEAR_DS. */
245: " movw %w1,%%ss\n" /* Switch %ss to LINEAR_DS. */
246: " movl %2,%%esp\n" /* and to phys-addr base_stack. */
247: " pushl %3 \n" /* Push argument (RC). */
248: " pushl %4 \n" /* Push bogus return address. */
249: " jmp %*%5" : : /* Jump to oskit, never return. */
250: "i" (LINEAR_CS), "r" (LINEAR_DS),
251: "ir" (kvtophys (&base_stack_end)),
252: "ir" (rc), "ir" (0),
253: "r" (kvtophys (his_exit)));
254: /* NOTREACHED */
255: }
256:
257: boolean_t pmap_valid_page(x)
258: vm_offset_t x;
259: {
260: /* XXX is this OK? What does it matter for? */
261: return (((phys_mem_min <= x) && (x < phys_mem_max)) &&
262: !(((boot_info.mem_lower * 1024) <= x) && (x < 1024*1024)));
263: }
264:
265:
266:
267: #include <mach/time_value.h>
268:
269: startrtclock()
270: {
271: clkstart();
272: }
273:
274: static void
275: inittodr()
276: {
277: oskit_timespec_t ts;
278: oskit_error_t rc;
279: spl_t s;
280:
281: rc = oskit_rtc_get (&ts);
282: if (rc)
283: panic (__FUNCTION__);
284:
285: s = splhigh();
286: #undef tv_sec /* oy */
287: time.seconds = ts.tv_sec;
288: time.microseconds = (ts.tv_nsec + 999) / 1000;
289: splx(s);
290: }
291:
292: /* This is called from host_set_time at splhigh to reset the hardware clock
293: to the new value of `time'. */
294: void
295: resettodr()
296: {
297: oskit_timespec_t ts = { time.seconds, time.microseconds * 1000 };
298: oskit_rtc_set (&ts);
299: }
300:
301:
302:
303: void
304: machine_idle (int mycpu)
305: {
306: asm volatile ("hlt" : : : "memory");
307: }
308:
309: void
310: halt_cpu ()
311: {
312: while (1)
313: asm volatile ("cli; hlt");
314: }
315:
316: void
317: halt_all_cpus(reboot)
318: boolean_t reboot;
319: {
320: exit(reboot ? 0 : 1);
321: }
322:
323:
324: void machine_init()
325: {
326: /*
327: * Set up to use floating point.
328: */
329: init_fpu();
330:
331: /*
332: * Get the time
333: */
334: inittodr();
335:
336: /*
337: * Unmap page 0 to trap NULL references.
338: * If there is real memory in the first physical page,
339: * then it will not be accessible through the normal
340: * direct mapping, so we need to take it out of the LMM.
341: */
342: if (phys_mem_min < PAGE_SIZE)
343: {
344: void *block = lmm_alloc_gen (&malloc_lmm,
345: PAGE_SIZE - phys_mem_min, 0, 0, 0,
346: phys_mem_min,
347: PAGE_SIZE - phys_mem_min);
348: if ((oskit_addr_t) block != phys_mem_min)
349: panic ("cannot allocate first page [%#x,%#x) from physical LMM!",
350: phys_mem_min, PAGE_SIZE);
351: else
352: {
353: /*
354: * So we have this partial page that we can't use where it is.
355: * Rather than waste it, let's map it in someplace else
356: * and donate it to someplace that can always use a little
357: * chunk of extra wired kernel virtual memory: the zone system.
358: */
359: extern vm_map_t zone_map; /* zalloc.c */
360: extern zone_t vm_page_zone; /* vm_resident.c */
361: vm_offset_t kva;
362: kern_return_t kr;
363: kr = kmem_alloc_pageable (zone_map, &kva, PAGE_SIZE);
364: if (kr != KERN_SUCCESS)
365: panic ("machine_init: kmem_alloc_pageable zone_map: %#x",
366: kr);
367: pmap_enter (kernel_pmap, kva, 0,
368: VM_PROT_READ | VM_PROT_WRITE, TRUE);
369: kva += phys_mem_min; /* Skip mapping below phys_mem_min. */
370: /*
371: * The vm_page_zone is always a needy soul early in life.
372: */
373: zcram (vm_page_zone, kva, PAGE_SIZE - phys_mem_min);
374: }
375: }
376: pmap_unmap_page_zero();
377:
378: /* Catch interrupt stack overflow. */
379: set_b0 (kvtolin (&base_stack_start), DR7_LEN_4, DR7_RW_DATA);
380: base_gdt_load(); /* necessary after setting debug regs */
381:
382: /* That loaded the oskit's selectors. Now reload ours. */
383: asm volatile("ljmp %0,$1f\n\t1:" : : "i" (KERNEL_CS));
384: set_ds(KERNEL_DS);
385: set_es(KERNEL_DS);
386: set_ss(KERNEL_DS);
387: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.