Filter:   InfoImg
download ppc_init.c
Language: C
Copyright: Copyright 1991-1998 by Open Software Foundation, Inc. Copyright 1991-1998 by Apple Computer, Inc.
LOC: 411
Project Info
Hurd on Mach on PowerPC(hurdppc)
Server: Savannah NonGNU
Type: cvs
...pc\hurdppc\gnu‑osfmach\ppc\
   _setjmp.S
   alignment.c
   asm.h
   ast.h
   ast_types.h
   bcopy.S
   bits.S
   boot.h
   bzero.S
   cache.S
   clock.h
   console_feed.c
   console_feed_entries.h
   cpu_number.h
   cswtch.S
   db_disasm.c
   db_interface.c
   db_low_trace.c
   db_low_trace.h
   db_machdep.h
   db_trace.c
   endian.h
   exception.h
   Firmware.h
   Firmware.S
   FirmwareCalls.h
   fpu_protos.h
   gdb_defs.h
   genassym.c
   go.c
   hardclock_entries.h
   hw_exception.S
   hw_lock.S
   interrupt.c
   io_map.c
   io_map_entries.h
   iobus.h
   iso_font.h
   kgdb_defs.h
   kgdb_interface.c
   kgdb_setjmp.h
   klglue.S
   lock.h
   low_trace.h
   lowmem_vectors.S
   mach_param.h
   machine_routines.h
   machine_rpc.h
   machlimits.h
   machparam.h
   mem.c
   mem.h
   misc.c
   misc_asm.S
   misc_protos.h
   model_dep.c
   movc.S
   mp.h
   MPinterfaces.S
   ndr_def.h
   net_filter.c
   new_screen.h
   pcb.c
   pmap.c
   pmap.c-broken
   pmap.h
   pmap_internals.h
   ppc_disasm.i
   ppc_init.c
   ppc_rpc.c
   proc_reg.h
   screen.h
   screen_defs.h
   screen_switch.h
   serial_console.c
   serial_defs.h
   setjmp.h
   spl.h
   start.S
   status.c
   strlen.c
   stubs.c
   syscall_subr.h
   task.h
   testjump.c
   thread.h
   thread_act.h
   trap.c
   trap.h
   vm_tuning.h
   xpr.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
/*
 * Copyright 1991-1998 by Open Software Foundation, Inc. 
 *              All Rights Reserved 
 *  
 * Permission to use, copy, modify, and distribute this software and 
 * its documentation for any purpose and without fee is hereby granted, 
 * provided that the above copyright notice appears in all copies and 
 * that both the copyright notice and this permission notice appear in 
 * supporting documentation. 
 *  
 * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE. 
 *  
 * IN NO EVENT SHALL OSF BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
 */
/*
 * Copyright 1991-1998 by Apple Computer, Inc. 
 *              All Rights Reserved 
 *  
 * Permission to use, copy, modify, and distribute this software and 
 * its documentation for any purpose and without fee is hereby granted, 
 * provided that the above copyright notice appears in all copies and 
 * that both the copyright notice and this permission notice appear in 
 * supporting documentation. 
 *  
 * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
 * FOR A PARTICULAR PURPOSE. 
 *  
 * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
 * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
 * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
 */
/*
 * MkLinux
 */

#include <mach_debug.h>
#include <mach_kdb.h>
#include <debug.h>
#include <mach_kgdb.h>
#include <cpus.h>

#include <mach/vm_types.h>
#include <mach/vm_param.h>
#include <mach/thread_status.h>
#include <kern/misc_protos.h>
#include <kern/assert.h>
#include <kern/cpu_number.h>

#include <ppc/proc_reg.h>
#include <ppc/boot.h>
#include <ppc/misc_protos.h>
#include <ppc/pmap.h>
#include <ppc/pmap_internals.h>
#include <ppc/mem.h>
#include <ppc/exception.h>
#include <ppc/gdb_defs.h>
#include <ppc/POWERMAC/video_board.h>
#include <ppc/POWERMAC/video_pdm.h>
#include <ppc/POWERMAC/device_tree.h>
#if NCPUS > 1
#include <ppc/mp.h>
#include <ppc/POWERMAC/mp/mp.h>
#endif /* NCPUS > 1 */

/* External references */

#if	MACH_KDB
extern vm_offset_t	kern_sym_start;
extern vm_size_t	kern_sym_size;
extern const char *getenv(const char *name);
#endif	/* MACH_KDB */
extern unsigned int intstack[];	/* declared in start.s */
extern unsigned int intstack_top_ss;	/* declared in start.s */
#if	MACH_KGDB
extern unsigned int gdbstackptr;	/* declared in start.s */
extern unsigned int gdbstack_top_ss;	/* declared in start.s */
#endif	/* MACH_KGDB */

/* Stuff declared in kern/bootstrap.c which we may need to initialise */

extern vm_offset_t     boot_start;
extern vm_size_t       boot_size;
extern vm_offset_t     boot_region_desc;
extern vm_size_t       boot_region_count;
extern int             boot_thread_state_flavor;
extern thread_state_t  boot_thread_state;
extern unsigned int    boot_thread_state_count;

/* Trap handling function prototypes */

extern void thandler(void);	/* trap handler */
extern void ihandler(void);	/* interrupt handler */
extern void shandler(void);	/* syscall handler */
extern void gdbhandler(void);	/* debugger handler */
extern void fpu_switch(void);	/* fp handler */

/* definitions */

struct ppc_thread_state boot_task_thread_state;

void (*exception_handlers[])(void) = {
	thandler,	/* 0x000   INVALID EXCEPTION */
	thandler,	/* 0x100   System reset */
	thandler,	/* 0x200   Machine check */
	thandler,	/* 0x300   Data access */
	thandler,	/* 0x400   Instruction access */
	ihandler,	/* 0x500   External interrupt */
	thandler,	/* 0x600   Alignment */
	thandler,	/* 0x700   Program - fp exc, ill/priv instr, trap */
	fpu_switch,	/* 0x800   Floating point disabled */
	ihandler,	/* 0x900   Decrementer */
	thandler,	/* 0xA00   I/O controller interface */
	thandler,	/* 0xB00   INVALID EXCEPTION */
	shandler,	/* 0xC00   System call exception */
	thandler,	/* 0xD00   Trace */
	thandler,	/* 0xE00   FP assist */
	thandler,	/* 0xF00   INVALID EXCEPTION */
	thandler,	/* 0x1000  INVALID EXCEPTION */
	thandler,	/* 0x1100  INVALID EXCEPTION */
	thandler,	/* 0x1200  INVALID EXCEPTION */
	thandler,	/* 0x1300  instruction breakpoint */
	thandler,	/* 0x1400  system management */
	thandler,	/* 0x1500  INVALID EXCEPTION */
	thandler,	/* 0x1600  INVALID EXCEPTION */
	thandler,	/* 0x1700  INVALID EXCEPTION */
	thandler,	/* 0x1800  INVALID EXCEPTION */
	thandler,	/* 0x1900  INVALID EXCEPTION */
	thandler,	/* 0x1A00  INVALID EXCEPTION */
	thandler,	/* 0x1B00  INVALID EXCEPTION */
	thandler,	/* 0x1C00  INVALID EXCEPTION */
	thandler,	/* 0x1D00  INVALID EXCEPTION */
	thandler,	/* 0x1E00  INVALID EXCEPTION */
	thandler,	/* 0x1F00  INVALID EXCEPTION */
	thandler,	/* 0x2000  Run Mode/Trace */
	ihandler	/* 0x2100  Signal processor */
};

/* per_proc_info is accessed with VM switched off via sprg0 */
/* Note that we always get enough space for an extra cache line.  That is because
   for performance, we need to align the struct on a cache boundary.  With the
   extra space, we can shift the array up to 31 bytes to align */


/*	 struct per_proc_info per_proc_info[NCPUS];		*/		/* Unaligned here */
unsigned char per_proc_area[NCPUS*sizeof(struct per_proc_info)+32]; 
struct per_proc_info *per_proc_info; 

vm_size_t mem_size;  /* Size of actual physical memory present in bytes */

mem_region_t pmap_mem_regions[PMAP_MEM_REGION_MAX];
int	 pmap_mem_regions_count = 0;	/* No non-contiguous memory regions */

mem_region_t free_regions[FREE_REGION_MAX];
int	     free_regions_count;

vm_offset_t virtual_avail, virtual_end;

extern unsigned long etext;
extern unsigned long _ExceptionVectorsStart;
extern unsigned long _ExceptionVectorsEnd;

#if 1 /* TODO NMGS - vm_map_steal_memory shouldn't use these - remove */
vm_offset_t avail_start;
vm_offset_t avail_end;
#endif 
unsigned int avail_remaining = 0;
vm_offset_t first_avail;

#if	NCPUS > 1
void initPerProc(void);
vm_offset_t	interrupt_stack[NCPUS];
#endif	/* NCPUS > 1 */

/* This is the first C function to be called. It is called with VM
 * switched ON, with the bottom 2M of memory mapped into KERNELBASE_TEXT
 * via BAT0, and the region in 2-4M mapped 1-1 (KERNELBASE_DATA) via BAT1
 *
 * The IO space is mapped 1-1 either via a segment register or via
 * BAT2, depending upon the processor type.
 *
 * printf already works
 * 
 * First initialisation of memory.
 *  - zero bss,
 *  - invalidate some seg regs,
 *  - set up hash tables
 */

void ppc_vm_init(unsigned int memory_size, boot_args *args)
{
	unsigned int htabmask;
	unsigned int i;
	vm_size_t  addr;
	int boot_task_end_offset;
#if	NCPUS > 1
	const char *cpus;
#endif	/* NCPUS > 1 */

	printf("mem_size = %d M\n",memory_size / (1024 * 1024));

#define IMAC_SUPPORT
#ifdef IMAC_SUPPORT
	if (powermac_info.class == POWERMAC_CLASS_PCI) {

		/* All PCI macs have contiguous RAM, so force the
		   issue (for machines with bogus RAM bank tables) */
		args->PhysicalDRAM[0].base = 0;
		args->PhysicalDRAM[0].size = memory_size;

		/* now flush the bogus information in other
		   RAM bank table entries */
		for (i = 1; i<kMaxDRAMBanks; i++)
			args->PhysicalDRAM[i].size = 0;

	} else {
#else
	{
#endif

	 /* Stitch valid memory regions together - they may be contiguous
	  * even though they're not already glued together
	  */
	    addr = 0;	/* temp use as pointer to previous memory region... */
	    for (i = 1; i < kMaxDRAMBanks; i++) {
	  	if (args->PhysicalDRAM[i].size == 0)
			continue;
	  	if (args->PhysicalDRAM[i].base ==
		    args->PhysicalDRAM[addr].base +
		    args->PhysicalDRAM[addr].size) {
		  	/* The two regions are contigous, join them */
		  printf("region 0x%08x size 0x%08x joining region "
			 "0x%08x size 0x%08x\n",
			 args->PhysicalDRAM[addr].base,
			 args->PhysicalDRAM[addr].size,
			 args->PhysicalDRAM[i].base,
			 args->PhysicalDRAM[i].size);
			args->PhysicalDRAM[addr].size +=
			  	args->PhysicalDRAM[i].size;
			args->PhysicalDRAM[i].size = 0;
			/* "last" region remains this new bigger region */
		} else {
		  	/* move "last" region up to this one */
			addr = i;
		}
	    }
	}

	/* Go through the list of memory regions passed in via the args
	 * and copy valid entries into the pmap_mem_regions table, adding
	 * further calculated entries.
	 */
	
	   pmap_mem_regions_count = 0;
	   addr = 0;	/* Will use to total memory found so far */
	   for (i = 0; (addr < memory_size) && (i < kMaxDRAMBanks); i++) {
		if (args->PhysicalDRAM[i].size == 0)
			continue;

		/* The following should only happen if memory size has
		   been artificially reduced with -m */
		if (addr + args->PhysicalDRAM[i].size > memory_size)
			args->PhysicalDRAM[i].size = memory_size - addr;

		/* We've found a region, tally memory */

		pmap_mem_regions[pmap_mem_regions_count].start =
			args->PhysicalDRAM[i].base;
		pmap_mem_regions[pmap_mem_regions_count].end =
			args->PhysicalDRAM[i].base +
			args->PhysicalDRAM[i].size;

		/* Regions must be provided in ascending order */
		assert ((pmap_mem_regions_count == 0) ||
			pmap_mem_regions[pmap_mem_regions_count].start >
			pmap_mem_regions[pmap_mem_regions_count-1].start);

#ifdef IMAC_TEST
		printf("pmap[Table]: added region from %x to %x with size %x", 
			pmap_mem_regions[pmap_mem_regions_count].start,
			pmap_mem_regions[pmap_mem_regions_count].end,
			(pmap_mem_regions[pmap_mem_regions_count].end -
			 pmap_mem_regions[pmap_mem_regions_count].start));
#endif

		if (pmap_mem_regions_count > 0) {		
			/* we add on any pages not in the first memory
			 * region to the avail_remaining count. The first
			 * memory region is used for mapping everything for
			 * bootup and is taken care of specially.
			 */
			avail_remaining +=
				args->PhysicalDRAM[i].size / PPC_PGBYTES;
		}
		
		/* Keep track of how much memory we've found */

		addr += args->PhysicalDRAM[i].size;

		/* incremement number of regions found */
		pmap_mem_regions_count++;
	   }
	if (mem_size != addr) {
		printf("mem_size set to 0x%x\n", mem_size);
		mem_size = addr; /* Set up global variable */
	}
	
	/* Initialise the pmap system, using space above `first_avail'
	 * for the necessary data structures.
         * NOTE : assume that we'll have enough space mapped in already
         */

	/* Set up the various globals describing memory usage */

	/* A small table of free physical memory left behind by the
	 * early kernel initialisation from the first contiguous memory
	 * region. We pick up this memory later via the free_regions
	 * array.
	 *
	 * Free memory can be found between end of copied exception
	 * vectors and kernel text, and
	 * between the end of kernel text and the start of kernel data.
	 */

	free_regions[free_regions_count].start =
	  	round_page((unsigned int)&_ExceptionVectorsEnd -
			   (unsigned int)&_ExceptionVectorsStart);

	/* If we are on a PDM machine memory at 1M might be used
	 * for video. TODO NMGS call video driver to do this
	 * somehow
	 */
	if (IS_VIDEO_MEMORY(VPDM_PHYSADDR)) {

		/* cut this region short at the start of video */

		free_regions[free_regions_count].end   = VPDM_PHYSADDR;

		avail_remaining += (free_regions[free_regions_count].end - 
				    free_regions[free_regions_count].start) /
			PPC_PGBYTES;
		free_regions_count++;

		/* next region now starts after end of frame buffer */
		free_regions[free_regions_count].start =
			round_page(VPDM_PHYSADDR + VPDM_FRAMEBUF_MAX_SIZE);

	}

	free_regions[free_regions_count].end   = KERNELBASE_TEXT;

        avail_remaining += (free_regions[free_regions_count].end - 
                            free_regions[free_regions_count].start) /
                                    PPC_PGBYTES;

        free_regions_count++;


	free_regions[free_regions_count].start = round_page(&etext);
	free_regions[free_regions_count].end   = KERNELBASE_DATA;

        avail_remaining += (free_regions[free_regions_count].end - 
                            free_regions[free_regions_count].start) /
                                    PPC_PGBYTES;

        free_regions_count++;

	/* For PowerMac, first_avail is set to above the bootstrap task.
         * TODO NMGS - different screen modes - might free mem?
         */

	first_avail = round_page(args->first_avail);

#if	NCPUS > 1
	/*
	 * Must Allocate interrupt stacks before kdb is called and also
	 * before vm is initialized. Must find out number of cpus first.
	 */
	/*
	 * Get number of cpus to boot, passed as an optional argument
	 * boot: mach [-sah#]	# from 0 to 9 is the number of cpus to boot
	 */
	if (wncpu < 0) {
		/* If already > 0, then was command line arg, override env */
		if ((cpus = getenv("cpus")) != NULL) {
			/* only a single digit for now */
			if ((*cpus > '0') && (*cpus <= '9'))
				wncpu = *cpus - '0';
		} else {
			wncpu = NCPUS;
		}
	}
#endif	/* NCPUS > 1 */

#undef DEBUG
#define DEBUG 1

	pmap_bootstrap(memory_size,&first_avail);

	/* map in the exception vectors */
	{
		extern unsigned long exception_entry;
		extern unsigned long exception_end;

#if DEBUG
		printf("Mapping exception entry/exit 0x%x to 0x%x size 0x%x\n",
		       trunc_page(exception_entry),
		       trunc_page(exception_entry),
		       round_page(exception_end));
#endif /* DEBUG */
		pmap_map(trunc_page(exception_entry),
			 trunc_page(exception_entry),
			 round_page(exception_end),
			 VM_PROT_READ|VM_PROT_EXECUTE);
	}
	/*
	 * map the kernel text, data and bss. Don't forget other regions too
	 */
	for (i = 0; i < args->kern_info.region_count; i++) {
#if	MACH_KDB
		if (args->kern_info.regions[i].prot == VM_PROT_NONE &&
		    i == args->kern_info.region_count - 1) {
			/* assume that's the kernel symbol table */
			kern_sym_start = args->kern_info.regions[i].addr;
			kern_sym_size = args->kern_info.regions[i].size;
			printf("kernel symbol table at 0x%x size 0x%x\n",
			       kern_sym_start, kern_sym_size);
			args->kern_info.regions[i].prot |=
				(VM_PROT_WRITE|VM_PROT_READ);
		}
#endif	/* MACH_KDB */
#if DEBUG
		printf("kernel: mapping virt 0x%08x to phys 0x%08x size 0x%x, prot=0x%b\n",
		       ppc_trunc_page(args->kern_info.regions[i].addr),
		       ppc_trunc_page(args->kern_info.base_addr + 
				      args->kern_info.regions[i].offset),
		       ppc_round_page(args->kern_info.base_addr + 
				      args->kern_info.regions[i].size),
		       args->kern_info.regions[i].prot,
		       "\x10\1READ\2WRITE\3EXEC");
#endif /* DEBUG */
		(void)pmap_map(ppc_trunc_page(args->kern_info.regions[i].addr),
			       ppc_trunc_page(args->kern_info.base_addr + 
				      args->kern_info.regions[i].offset),
			       ppc_round_page(args->kern_info.base_addr + 
				      args->kern_info.regions[i].offset +
				      args->kern_info.regions[i].size),
			 args->kern_info.regions[i].prot);
	}
	boot_region_count = args->task_info.region_count;
	boot_size = 0;
	boot_task_end_offset = 0;
	/* Map bootstrap task pages 1-1 so that user_bootstrap can find it */
	for (i = 0; i < boot_region_count; i++) {
		if (args->task_info.regions[i].mapped) {
			/* kernel requires everything page aligned */
#if DEBUG
			printf("bootstrap: mapping virt 0x%08x to phys 0x%08x end 0x%x, prot=0x%b\n",
				 ppc_trunc_page(args->task_info.base_addr + 
					args->task_info.regions[i].offset),
				 ppc_trunc_page(args->task_info.base_addr + 
					args->task_info.regions[i].offset),
				 ppc_round_page(args->task_info.base_addr + 
					args->task_info.regions[i].offset +
					args->task_info.regions[i].size),
				 args->task_info.regions[i].prot,
				 "\x10\1READ\2WRITE\3EXEC");
#endif /* DEBUG */

			(void)pmap_map(
				  ppc_trunc_page(args->task_info.base_addr + 
				      args->task_info.regions[i].offset),
			          ppc_trunc_page(args->task_info.base_addr + 
				      args->task_info.regions[i].offset),
			          ppc_round_page(args->task_info.base_addr +
				      args->task_info.regions[i].offset +
				      args->task_info.regions[i].size),
			          args->task_info.regions[i].prot);

			/* Count the size of mapped space */
			boot_size += args->task_info.regions[i].size;

			/* There may be an overlapping physical page
			 * mapped to two different virtual addresses
			 */
			if (boot_task_end_offset >
			    args->task_info.regions[i].offset) {
				boot_size -= boot_task_end_offset - 
					args->task_info.regions[i].offset;
#if DEBUG
				printf("WARNING - bootstrap overlaps regions\n");
#endif /* DEBUG */
			}

			boot_task_end_offset =
				args->task_info.regions[i].offset +
				args->task_info.regions[i].size;
		}
	}

	if (boot_region_count) {

		/* Add a new region to the bootstrap task for it's stack */
		args->task_info.regions[boot_region_count].addr =
			BOOT_STACK_BASE;
		args->task_info.regions[boot_region_count].size =
			BOOT_STACK_SIZE;
		args->task_info.regions[boot_region_count].mapped = FALSE;
		boot_region_count++;
		
		boot_start        = args->task_info.base_addr;
		boot_region_desc  = (vm_offset_t) args->task_info.regions;
		/* TODO NMGS need to put param info onto top of boot stack */
		boot_task_thread_state.r1   = BOOT_STACK_PTR-0x100;
		boot_task_thread_state.srr0 = args->task_info.entry;
		boot_task_thread_state.srr1 =
			MSR_MARK_SYSCALL(MSR_EXPORT_MASK_SET);
		
		boot_thread_state_flavor = PPC_THREAD_STATE;
		boot_thread_state_count  = PPC_THREAD_STATE_COUNT;
		boot_thread_state        =
			(thread_state_t)&boot_task_thread_state;
	}

	/* Map bootstrap argument structure as data */
	(void) pmap_map((vm_offset_t)args,
			(vm_offset_t)args-KERNELBASE_DATA_OFFSET,
			((vm_offset_t)args->first_avail - 1) -
				KERNELBASE_DATA_OFFSET,
			VM_PROT_READ|VM_PROT_WRITE);

	/* Map interrupt stack red-zone */
	addr = trunc_page((vm_offset_t) &intstack - PPC_PGBYTES);
	(void) pmap_map(addr,
			addr - KERNELBASE_DATA_OFFSET,
			addr - KERNELBASE_DATA_OFFSET + PPC_PGBYTES-1,
			VM_PROT_READ);

	/* Map motherboard video memory via PTEs before removing BAT */

	if (IS_VIDEO_MEMORY(VPDM_PHYSADDR)) {
		(void) pmap_map_bd(VPDM_BASEADDR,
				   VPDM_PHYSADDR,
				   round_page(VPDM_PHYSADDR +
					      VPDM_FRAMEBUF_MAX_SIZE),
				   VM_PROT_READ | VM_PROT_WRITE);

		/* KAM 990104 - unmap BAT3 in case we're on a 750 and don't
		   do it below */
		mtdbatu(3,BAT_INVALID); mtdbatl(3,BAT_INVALID);
	}
	/* Set up per_proc info */
#if 0
	per_proc_info[0].cpu_number = 0;
#endif
	per_proc_info[cpu_number()].istackptr = 0; /* we're on the intr stack */
	per_proc_info[cpu_number()].intstack_top_ss = intstack_top_ss;
#if	MACH_KGDB
	per_proc_info[cpu_number()].gdbstackptr = gdbstackptr;
	per_proc_info[cpu_number()].gdbstack_top_ss = gdbstack_top_ss;
#endif	/* MACH_KGDB */
	per_proc_info[cpu_number()].phys_exception_handlers =
		kvtophys((vm_offset_t)&exception_handlers);
	per_proc_info[cpu_number()].virt_per_proc_info = (unsigned int)
		&per_proc_info[cpu_number()];
	per_proc_info[cpu_number()].active_kloaded = (unsigned int)
		&active_kloaded[cpu_number()];
	per_proc_info[cpu_number()].cpu_data = (unsigned int)
		&cpu_data[cpu_number()];
	per_proc_info[cpu_number()].active_stacks = (unsigned int)
		&active_stacks[cpu_number()];
	per_proc_info[cpu_number()].need_ast = (unsigned int)
		&need_ast[cpu_number()];
	per_proc_info[cpu_number()].fpu_pcb = 0;

	mtsprg(0, ((unsigned int)kvtophys((vm_offset_t)&per_proc_info[cpu_number()])));

	/* r2 points to our per_proc structure whilst we're in the kernel */
	__asm__ ("mr 2, %0" : : "r" (&per_proc_info[cpu_number()]));


#if MACH_KGDB
	kgdb_kernel_in_pmap = TRUE;
#endif /* MACH_KGDB */

#if DEBUG
	for (i=0 ; i < free_regions_count; i++) {
		printf("Free region start 0x%08x end 0x%08x\n",
		       free_regions[i].start,free_regions[i].end);
	}
#endif


	sync();isync();

	if (PROCESSOR_VERSION != PROCESSOR_VERSION_601) {
/*		mtdbatu(3,BAT_INVALID); mtdbatl(3,BAT_INVALID); TODO NMGS */
/* 		mtdbatu(2,BAT_INVALID); mtdbatl(2,BAT_INVALID); TODO NMGS */
		mtdbatu(1,BAT_INVALID); mtdbatl(1,BAT_INVALID);
		mtdbatu(0,BAT_INVALID); mtdbatl(0,BAT_INVALID);

		/* Clear instr BATs too on those processors that have them */
		mtibatu(3,BAT_INVALID); mtibatl(3,BAT_INVALID);
 		mtibatu(2,BAT_INVALID); mtibatl(2,BAT_INVALID);
		mtibatu(1,BAT_INVALID); mtibatl(1,BAT_INVALID);
		mtibatu(0,BAT_INVALID); mtibatl(0,BAT_INVALID);

		/* Kernel text+rodata is at 2-4M */

		/* use dbat 0 to map 2-4M 1-1 read-only for kernel only */
		mtdbatl(0, KERNELBASE_TEXT | PTE_WIMG_DEFAULT << 3 | 1);
		mtdbatu(0, KERNELBASE_TEXT | 0xf << 2 | 2);

		/* use ibat 0 to map 2-4M 1-1 executable for kernel only */
		mtibatl(0, KERNELBASE_TEXT | PTE_WIMG_DEFAULT << 3 | 1);
		mtibatu(0, KERNELBASE_TEXT | 0xf << 2 | 2);

		/* Kernel r/w data is at 4M and up */

		/* Must only map to less than first_avail
		 * since VM addresses above that may not be 1-1
		 */
		addr = 128 * 1024;
		i = 0;
		while (KERNELBASE_DATA + (addr * 2) < first_avail) {
			i = (i * 2) +1;
			addr = addr * 2;
		}

		if ( i > 31 ) {
			printf("Clamping BAT size to 4M\n");
			i = 31;
		}

		/* use dbat 1 to map 4M-XXX 1-1 read-write for kernel only */
		mtdbatl(1, KERNELBASE_DATA | (PTE_WIMG_DEFAULT << 3) | 2);
		mtdbatu(1, KERNELBASE_DATA | (i << 2) | 2);

		/* MP plugin has relocatable code stored in data segment */
		/* use ibat 1 to map 4M-XXX 1-1 executable for kernel only */
		mtibatl(1, KERNELBASE_DATA | (PTE_WIMG_DEFAULT << 3) | 2);
		mtibatu(1, KERNELBASE_DATA | (i << 2) | 2);
	} else {
		mtibatl(3,BAT_INVALID);
		mtibatl(2,BAT_INVALID);
		mtibatl(1,BAT_INVALID);
		mtibatl(0,BAT_INVALID);
	}
	sync();isync();
	{
		int i;
		__asm__ ("mr %0, 2" : "=r" (i));
		assert(i = (int)&per_proc_info[cpu_number()]);
	}
}