]>
Commit | Line | Data |
---|---|---|
1c79356b A |
1 | /* |
2 | * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * The contents of this file constitute Original Code as defined in and | |
7 | * are subject to the Apple Public Source License Version 1.1 (the | |
8 | * "License"). You may not use this file except in compliance with the | |
9 | * License. Please obtain a copy of the License at | |
10 | * http://www.apple.com/publicsource and read it before using this file. | |
11 | * | |
12 | * This Original Code and all software distributed under the License are | |
13 | * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the | |
17 | * License for the specific language governing rights and limitations | |
18 | * under the License. | |
19 | * | |
20 | * @APPLE_LICENSE_HEADER_END@ | |
21 | */ | |
22 | /* | |
23 | * @OSF_COPYRIGHT@ | |
24 | */ | |
25 | /* | |
26 | * Mach Operating System | |
27 | * Copyright (c) 1991,1990,1989, 1988 Carnegie Mellon University | |
28 | * All Rights Reserved. | |
29 | * | |
30 | * Permission to use, copy, modify and distribute this software and its | |
31 | * documentation is hereby granted, provided that both the copyright | |
32 | * notice and this permission notice appear in all copies of the | |
33 | * software, derivative works or modified versions, and any portions | |
34 | * thereof, and that both notices appear in supporting documentation. | |
35 | * | |
36 | * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" | |
37 | * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR | |
38 | * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. | |
39 | * | |
40 | * Carnegie Mellon requests users of this software to return to | |
41 | * | |
42 | * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU | |
43 | * School of Computer Science | |
44 | * Carnegie Mellon University | |
45 | * Pittsburgh PA 15213-3890 | |
46 | * | |
47 | * any improvements or extensions that they make and grant Carnegie Mellon | |
48 | * the rights to redistribute these changes. | |
49 | */ | |
50 | ||
51 | /* | |
52 | */ | |
53 | ||
54 | /* | |
55 | * File: model_dep.c | |
56 | * Author: Avadis Tevanian, Jr., Michael Wayne Young | |
57 | * | |
58 | * Copyright (C) 1986, Avadis Tevanian, Jr., Michael Wayne Young | |
59 | * | |
60 | * Basic initialization for I386 - ISA bus machines. | |
61 | */ | |
62 | ||
63 | #include <cpus.h> | |
64 | #include <platforms.h> | |
65 | #include <mp_v1_1.h> | |
66 | #include <mach_kdb.h> | |
67 | #include <himem.h> | |
68 | #include <fast_idle.h> | |
69 | ||
70 | #include <mach/i386/vm_param.h> | |
71 | ||
72 | #include <string.h> | |
73 | #include <mach/vm_param.h> | |
74 | #include <mach/vm_prot.h> | |
75 | #include <mach/machine.h> | |
76 | #include <mach/time_value.h> | |
77 | #include <kern/etap_macros.h> | |
78 | #include <kern/spl.h> | |
79 | #include <kern/assert.h> | |
80 | #include <kern/debug.h> | |
81 | #include <kern/misc_protos.h> | |
82 | #include <kern/startup.h> | |
83 | #include <kern/clock.h> | |
84 | #include <kern/time_out.h> | |
85 | #include <kern/xpr.h> | |
86 | #include <kern/cpu_data.h> | |
87 | #include <vm/vm_page.h> | |
88 | #include <vm/pmap.h> | |
89 | #include <vm/vm_kern.h> | |
90 | #include <i386/fpu.h> | |
91 | #include <i386/pmap.h> | |
92 | #include <i386/ipl.h> | |
93 | #include <i386/pio.h> | |
94 | #include <i386/misc_protos.h> | |
95 | #include <i386/cpuid.h> | |
96 | #include <i386/rtclock_entries.h> | |
97 | #include <i386/AT386/mp/mp.h> | |
98 | #if MACH_KDB | |
99 | #include <ddb/db_aout.h> | |
100 | #endif /* MACH_KDB */ | |
101 | #include <ddb/tr.h> | |
102 | #ifdef __MACHO__ | |
103 | #include <i386/AT386/kernBootStruct.h> | |
104 | #include <mach/boot_info.h> | |
105 | #include <mach/thread_status.h> | |
106 | #endif | |
107 | ||
108 | #if NCPUS > 1 | |
109 | #include <i386/mp_desc.h> | |
110 | #endif /* NCPUS */ | |
111 | ||
112 | #if MP_V1_1 | |
113 | #include <i386/AT386/mp/mp_v1_1.h> | |
114 | #endif /* MP_V1_1 */ | |
115 | ||
116 | vm_size_t mem_size = 0; | |
117 | vm_offset_t first_addr = 0; /* set by start.s - keep out of bss */ | |
118 | vm_offset_t first_avail = 0;/* first after page tables */ | |
119 | vm_offset_t last_addr; | |
120 | ||
121 | vm_offset_t avail_start, avail_end; | |
122 | vm_offset_t virtual_avail, virtual_end; | |
123 | vm_offset_t hole_start, hole_end; | |
124 | vm_offset_t avail_next; | |
125 | unsigned int avail_remaining; | |
126 | ||
127 | /* parameters passed from bootstrap loader */ | |
128 | int cnvmem = 0; /* must be in .data section */ | |
129 | int extmem = 0; | |
130 | ||
131 | /* FIXME!! REMOVE WHEN OSFMK DEVICES ARE COMPLETELY PULLED OUT */ | |
132 | int dev_name_count = 0; | |
133 | int dev_name_list = 0; | |
134 | ||
135 | #ifndef __MACHO__ | |
136 | extern char edata, end; | |
137 | #endif | |
138 | ||
139 | extern char version[]; | |
140 | ||
141 | int rebootflag = 0; /* exported to kdintr */ | |
142 | ||
143 | ||
144 | void parse_arguments(void); | |
145 | const char *getenv(const char *); | |
146 | ||
147 | #define BOOT_LINE_LENGTH 160 | |
148 | char boot_string_store[BOOT_LINE_LENGTH] = {0}; | |
149 | char *boot_string = (char *)0; | |
150 | int boot_string_sz = BOOT_LINE_LENGTH; | |
151 | int boottype = 0; | |
152 | ||
153 | #if __MACHO__ | |
154 | #include <mach-o/loader.h> | |
155 | vm_offset_t edata, etext, end; | |
156 | ||
157 | extern struct mach_header _mh_execute_header; | |
158 | void *sectTEXTB; int sectSizeTEXT; | |
159 | void *sectDATAB; int sectSizeDATA; | |
160 | void *sectOBJCB; int sectSizeOBJC; | |
161 | void *sectLINKB; int sectSizeLINK; | |
162 | ||
163 | /* Kernel boot information */ | |
164 | KERNBOOTSTRUCT kernBootStructData; | |
165 | KERNBOOTSTRUCT *kernBootStruct; | |
166 | #endif | |
167 | ||
168 | vm_offset_t kern_args_start = 0; /* kernel arguments */ | |
169 | vm_size_t kern_args_size = 0; /* size of kernel arguments */ | |
170 | ||
171 | #ifdef __MACHO__ | |
172 | ||
173 | unsigned long | |
174 | i386_preinit() | |
175 | { | |
176 | int i; | |
177 | struct segment_command *sgp; | |
178 | struct section *sp; | |
179 | ||
180 | sgp = (struct segment_command *) getsegbyname("__DATA"); | |
181 | if (sgp) { | |
182 | sp = (struct section *) firstsect(sgp); | |
183 | if (sp) { | |
184 | do { | |
185 | if (sp->flags & S_ZEROFILL) | |
186 | bzero((char *) sp->addr, sp->size); | |
187 | } while (sp = (struct section *)nextsect(sgp, sp)); | |
188 | } | |
189 | } | |
190 | ||
1c79356b A |
191 | bcopy((char *) KERNSTRUCT_ADDR, (char *) &kernBootStructData, |
192 | sizeof(kernBootStructData)); | |
193 | ||
194 | kernBootStruct = &kernBootStructData; | |
195 | ||
0b4e3aa0 | 196 | end = round_page( kernBootStruct->kaddr + kernBootStruct->ksize ); |
1c79356b A |
197 | |
198 | return end; | |
199 | } | |
200 | #endif | |
201 | ||
202 | /* | |
203 | * Cpu initialization. Running virtual, but without MACH VM | |
204 | * set up. First C routine called. | |
205 | */ | |
206 | void | |
207 | machine_startup(void) | |
208 | { | |
209 | ||
210 | #ifdef __MACHO__ | |
211 | ||
212 | ||
213 | /* Now copy over various bits.. */ | |
214 | cnvmem = kernBootStruct->convmem; | |
215 | extmem = kernBootStruct->extmem; | |
216 | kern_args_start = (vm_offset_t) kernBootStruct->bootString; | |
217 | kern_args_size = strlen(kernBootStruct->bootString); | |
218 | boottype = kernBootStruct->rootdev; | |
219 | ||
220 | /* Now retrieve addresses for end, edata, and etext | |
221 | * from MACH-O headers. | |
222 | */ | |
223 | ||
224 | sectTEXTB = (void *) getsegdatafromheader( | |
225 | &_mh_execute_header, "__TEXT", §SizeTEXT); | |
226 | sectDATAB = (void *) getsegdatafromheader( | |
227 | &_mh_execute_header, "__DATA", §SizeDATA); | |
228 | sectOBJCB = (void *) getsegdatafromheader( | |
229 | &_mh_execute_header, "__OBJC", §SizeOBJC); | |
230 | sectLINKB = (void *) getsegdatafromheader( | |
231 | &_mh_execute_header, "__LINKEDIT", §SizeLINK); | |
232 | ||
233 | etext = (vm_offset_t) sectTEXTB + sectSizeTEXT; | |
234 | edata = (vm_offset_t) sectDATAB + sectSizeDATA; | |
235 | #endif | |
236 | ||
237 | /* | |
238 | * Parse startup arguments | |
239 | */ | |
240 | parse_arguments(); | |
241 | ||
242 | disableDebugOuput = FALSE; | |
243 | debug_mode = TRUE; | |
244 | ||
245 | printf_init(); /* Init this in case we need debugger */ | |
246 | panic_init(); /* Init this in case we need debugger */ | |
247 | ||
248 | PE_init_platform(FALSE, kernBootStruct); | |
249 | PE_init_kprintf(FALSE); | |
250 | PE_init_printf(FALSE); | |
251 | ||
252 | /* | |
253 | * Do basic VM initialization | |
254 | */ | |
255 | i386_init(); | |
256 | ||
257 | PE_init_platform(TRUE, kernBootStruct); | |
258 | PE_init_kprintf(TRUE); | |
259 | PE_init_printf(TRUE); | |
260 | ||
261 | #if MACH_KDB | |
262 | ||
263 | /* | |
264 | * Initialize the kernel debugger. | |
265 | */ | |
266 | ddb_init(); | |
267 | ||
268 | /* | |
269 | * Cause a breakpoint trap to the debugger before proceeding | |
270 | * any further if the proper option bit was specified in | |
271 | * the boot flags. | |
272 | * | |
273 | * XXX use -a switch to invoke kdb, since there's no | |
274 | * boot-program switch to turn on RB_HALT! | |
275 | */ | |
276 | ||
277 | if (halt_in_debugger) { | |
278 | printf("inline call to debugger(machine_startup)\n"); | |
279 | Debugger("inline call"); | |
280 | } | |
281 | #endif /* MACH_KDB */ | |
282 | TR_INIT(); | |
283 | ||
284 | printf(version); | |
285 | ||
286 | machine_slot[0].is_cpu = TRUE; | |
287 | machine_slot[0].running = TRUE; | |
288 | #ifdef MACH_BSD | |
289 | /* FIXME */ | |
290 | machine_slot[0].cpu_type = CPU_TYPE_I386; | |
291 | machine_slot[0].cpu_subtype = CPU_SUBTYPE_PENTPRO; | |
292 | #else | |
293 | machine_slot[0].cpu_type = cpuid_cputype(0); | |
294 | machine_slot[0].cpu_subtype = CPU_SUBTYPE_AT386; | |
295 | #endif | |
296 | ||
297 | /* | |
298 | * Start the system. | |
299 | */ | |
300 | #if NCPUS > 1 | |
301 | mp_desc_init(0); | |
302 | #endif /* NCPUS */ | |
303 | ||
304 | setup_main(); | |
305 | } | |
306 | ||
307 | ||
308 | vm_offset_t env_start = 0; /* environment */ | |
309 | vm_size_t env_size = 0; /* size of environment */ | |
310 | ||
311 | /* | |
312 | * Parse command line arguments. | |
313 | */ | |
314 | void | |
315 | parse_arguments(void) | |
316 | { | |
317 | char *p = (char *) kern_args_start; | |
318 | char *endp = (char *) kern_args_start + kern_args_size - 1; | |
319 | char ch; | |
320 | ||
321 | if (kern_args_start == 0) | |
322 | return; | |
0b4e3aa0 A |
323 | |
324 | /* | |
325 | * handle switches in exact format of -h or -m64 | |
326 | */ | |
327 | while ( (p < endp) && (*p != '\0')) { | |
328 | if (*p++ != '-') | |
329 | continue; | |
330 | switch (*p++) { | |
331 | case 'h': | |
332 | halt_in_debugger = 1; | |
333 | break; | |
334 | case 'm': | |
335 | mem_size = atoi_term(p,&p)*1024*1024; | |
336 | break; | |
337 | case 'k': | |
338 | mem_size = atoi_term(p,&p)*1024; | |
339 | break; | |
340 | default: | |
341 | break; | |
342 | } | |
1c79356b | 343 | } |
0b4e3aa0 | 344 | |
1c79356b A |
345 | } |
346 | ||
347 | const char * | |
348 | getenv(const char *name) | |
349 | { | |
350 | int len = strlen(name); | |
351 | const char *p = (const char *)env_start; | |
352 | const char *endp = p + env_size; | |
353 | ||
354 | while (p < endp) { | |
355 | if (len >= endp - p) | |
356 | break; | |
357 | if (strncmp(name, p, len) == 0 && *(p + len) == '=') | |
358 | return p + len + 1; | |
359 | while (*p++) | |
360 | ; | |
361 | } | |
362 | return NULL; | |
363 | } | |
364 | ||
365 | extern void | |
366 | calibrate_delay(void); | |
367 | ||
368 | /* | |
369 | * Find devices. The system is alive. | |
370 | */ | |
371 | void | |
372 | machine_init(void) | |
373 | { | |
374 | int unit; | |
375 | const char *p; | |
376 | int n; | |
377 | ||
378 | /* | |
379 | * Adjust delay count before entering drivers | |
380 | */ | |
381 | ||
382 | calibrate_delay(); | |
383 | ||
384 | /* | |
385 | * Display CPU identification | |
386 | */ | |
387 | cpuid_cpu_display("CPU identification", 0); | |
388 | cpuid_cache_display("CPU configuration", 0); | |
389 | ||
390 | #if MP_V1_1 | |
391 | mp_v1_1_init(); | |
392 | #endif /* MP_V1_1 */ | |
393 | ||
394 | /* | |
395 | * Set up to use floating point. | |
396 | */ | |
397 | init_fpu(); | |
398 | ||
399 | #if 0 | |
400 | #if NPCI > 0 | |
401 | dma_zones_init(); | |
402 | #endif /* NPCI > 0 */ | |
403 | #endif | |
404 | ||
405 | /* | |
406 | * Configure clock devices. | |
407 | */ | |
408 | clock_config(); | |
409 | } | |
410 | ||
411 | /* | |
412 | * Halt a cpu. | |
413 | */ | |
414 | void | |
415 | halt_cpu(void) | |
416 | { | |
417 | halt_all_cpus(FALSE); | |
418 | } | |
419 | ||
420 | int reset_mem_on_reboot = 1; | |
421 | ||
422 | /* | |
423 | * Halt the system or reboot. | |
424 | */ | |
425 | void | |
426 | halt_all_cpus( | |
427 | boolean_t reboot) | |
428 | { | |
429 | if (reboot) { | |
430 | /* | |
431 | * Tell the BIOS not to clear and test memory. | |
432 | */ | |
433 | if (! reset_mem_on_reboot) | |
434 | *(unsigned short *)phystokv(0x472) = 0x1234; | |
435 | ||
436 | kdreboot(); | |
437 | } | |
438 | else { | |
439 | rebootflag = 1; | |
440 | printf("In tight loop: hit ctl-alt-del to reboot\n"); | |
441 | (void) spllo(); | |
442 | } | |
443 | for (;;) | |
444 | continue; | |
445 | } | |
446 | ||
447 | /* | |
448 | * Basic VM initialization. | |
449 | */ | |
450 | ||
451 | void | |
452 | i386_init(void) | |
453 | { | |
454 | int i,j; /* Standard index vars. */ | |
455 | vm_size_t bios_hole_size; | |
456 | ||
457 | #ifndef __MACHO__ | |
458 | /* | |
459 | * Zero the BSS. | |
460 | */ | |
461 | ||
462 | bzero((char *)&edata,(unsigned)(&end - &edata)); | |
463 | #endif | |
464 | ||
465 | boot_string = &boot_string_store[0]; | |
466 | ||
467 | /* | |
468 | * Initialize the pic prior to any possible call to an spl. | |
469 | */ | |
470 | ||
471 | set_cpu_model(); | |
472 | vm_set_page_size(); | |
473 | ||
474 | /* | |
475 | * Initialize the Event Trace Analysis Package | |
476 | * Static Phase: 1 of 2 | |
477 | */ | |
478 | etap_init_phase1(); | |
479 | ||
480 | /* | |
481 | * Compute the memory size. | |
482 | */ | |
483 | ||
484 | #if 1 | |
485 | /* FIXME | |
486 | * fdisk needs to change to use a sysctl instead of | |
487 | * opening /dev/kmem and reading out the kernboot structure | |
488 | */ | |
489 | ||
490 | first_addr = (char *)(KERNSTRUCT_ADDR) + sizeof(KERNBOOTSTRUCT); | |
491 | #else | |
492 | #if NCPUS > 1 | |
493 | first_addr = 0x1000; | |
494 | #else | |
495 | /* First two pages are used to boot the other cpus. */ | |
496 | /* TODO - reclaim pages after all cpus have booted */ | |
497 | ||
498 | first_addr = 0x3000; | |
499 | #endif | |
500 | #endif | |
501 | ||
502 | /* BIOS leaves data in low memory */ | |
503 | last_addr = 1024*1024 + extmem*1024; | |
504 | /* extended memory starts at 1MB */ | |
505 | ||
506 | bios_hole_size = 1024*1024 - trunc_page((vm_offset_t)(1024 * cnvmem)); | |
507 | ||
508 | /* | |
509 | * Initialize for pmap_free_pages and pmap_next_page. | |
510 | * These guys should be page-aligned. | |
511 | */ | |
512 | ||
513 | hole_start = trunc_page((vm_offset_t)(1024 * cnvmem)); | |
514 | hole_end = round_page((vm_offset_t)first_avail); | |
515 | ||
516 | /* | |
517 | * compute mem_size | |
518 | */ | |
519 | ||
520 | if (mem_size != 0) { | |
521 | if (mem_size < (last_addr) - bios_hole_size) | |
522 | last_addr = mem_size + bios_hole_size; | |
523 | } | |
524 | ||
525 | first_addr = round_page(first_addr); | |
526 | last_addr = trunc_page(last_addr); | |
527 | mem_size = last_addr - bios_hole_size; | |
528 | ||
529 | avail_start = first_addr; | |
530 | avail_end = last_addr; | |
531 | avail_next = avail_start; | |
532 | ||
533 | /* | |
534 | * Initialize kernel physical map, mapping the | |
535 | * region from loadpt to avail_start. | |
536 | * Kernel virtual address starts at VM_KERNEL_MIN_ADDRESS. | |
537 | */ | |
538 | ||
539 | ||
540 | #if NCPUS > 1 && AT386 | |
541 | /* | |
542 | * Must Allocate interrupt stacks before kdb is called and also | |
543 | * before vm is initialized. Must find out number of cpus first. | |
544 | */ | |
545 | /* | |
546 | * Get number of cpus to boot, passed as an optional argument | |
547 | * boot: mach [-sah#] # from 0 to 9 is the number of cpus to boot | |
548 | */ | |
549 | if (wncpu == -1) { | |
550 | /* | |
551 | * "-1" check above is to allow for old boot loader to pass | |
552 | * wncpu through boothowto. New boot loader uses environment. | |
553 | */ | |
554 | const char *cpus; | |
555 | if ((cpus = getenv("cpus")) != NULL) { | |
556 | /* only a single digit for now */ | |
557 | if ((*cpus > '0') && (*cpus <= '9')) | |
558 | wncpu = *cpus - '0'; | |
559 | } else | |
560 | wncpu = NCPUS; | |
561 | } | |
562 | mp_probe_cpus(); | |
563 | interrupt_stack_alloc(); | |
564 | ||
565 | #endif /* NCPUS > 1 && AT386 */ | |
566 | ||
567 | pmap_bootstrap(0); | |
568 | ||
569 | avail_remaining = atop((avail_end - avail_start) - | |
570 | (hole_end - hole_start)); | |
571 | } | |
572 | ||
573 | unsigned int | |
574 | pmap_free_pages(void) | |
575 | { | |
576 | return avail_remaining; | |
577 | } | |
578 | ||
579 | boolean_t | |
580 | pmap_next_page( | |
581 | vm_offset_t *addrp) | |
582 | { | |
583 | if (avail_next == avail_end) | |
584 | return FALSE; | |
585 | ||
586 | /* skip the hole */ | |
587 | ||
588 | if (avail_next == hole_start) | |
589 | avail_next = hole_end; | |
590 | ||
591 | *addrp = avail_next; | |
592 | avail_next += PAGE_SIZE; | |
593 | avail_remaining--; | |
594 | ||
595 | return TRUE; | |
596 | } | |
597 | ||
598 | boolean_t | |
599 | pmap_valid_page( | |
600 | vm_offset_t x) | |
601 | { | |
602 | return ((avail_start <= x) && (x < avail_end)); | |
603 | } | |
604 | ||
605 | /*XXX*/ | |
606 | void fc_get(mach_timespec_t *ts); | |
607 | #include <kern/clock.h> | |
608 | #include <i386/rtclock_entries.h> | |
609 | extern kern_return_t sysclk_gettime( | |
610 | mach_timespec_t *cur_time); | |
611 | void fc_get(mach_timespec_t *ts) { | |
612 | (void )sysclk_gettime(ts); | |
613 | } | |
614 | ||
615 | void | |
616 | Debugger( | |
617 | const char *message) | |
618 | { | |
619 | printf("Debugger called: <%s>\n", message); | |
620 | ||
621 | __asm__("int3"); | |
622 | } | |
623 | ||
624 | void | |
625 | display_syscall(int syscall) | |
626 | { | |
627 | printf("System call happened %d\n", syscall); | |
628 | } | |
629 | ||
630 | #if XPR_DEBUG && (NCPUS == 1 || MP_V1_1) | |
631 | ||
632 | extern kern_return_t sysclk_gettime_interrupts_disabled( | |
633 | mach_timespec_t *cur_time); | |
634 | ||
635 | int xpr_time(void) | |
636 | { | |
637 | mach_timespec_t time; | |
638 | ||
639 | sysclk_gettime_interrupts_disabled(&time); | |
640 | return(time.tv_sec*1000000 + time.tv_nsec/1000); | |
641 | } | |
642 | #endif /* XPR_DEBUG && (NCPUS == 1 || MP_V1_1) */ | |
643 | ||
644 | enable_bluebox() | |
645 | { | |
646 | } | |
647 | disable_bluebox() | |
648 | { | |
649 | } | |
650 | ||
651 | char * | |
652 | machine_boot_info(char *buf, vm_size_t size) | |
653 | { | |
654 | *buf ='\0'; | |
655 | return buf; | |
656 | } | |
657 |