Source to osfmk/kern/startup.c


Enter a symbol's name here to quickly find it.

/*
 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
 *
 * @[email protected]
 * 
 * The contents of this file constitute Original Code as defined in and
 * are subject to the Apple Public Source License Version 1.1 (the
 * "License").  You may not use this file except in compliance with the
 * License.  Please obtain a copy of the License at
 * http://www.apple.com/publicsource and read it before using this file.
 * 
 * This Original Code and all software distributed under the License are
 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
 * License for the specific language governing rights and limitations
 * under the License.
 * 
 * @[email protected]
 */
/*
 * @[email protected]
 */
/* 
 * Mach Operating System
 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
 * All Rights Reserved.
 * 
 * Permission to use, copy, modify and distribute this software and its
 * documentation is hereby granted, provided that both the copyright
 * notice and this permission notice appear in all copies of the
 * software, derivative works or modified versions, and any portions
 * thereof, and that both notices appear in supporting documentation.
 * 
 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
 * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
 * 
 * Carnegie Mellon requests users of this software to return to
 * 
 *  Software Distribution Coordinator  or  [email protected]
 *  School of Computer Science
 *  Carnegie Mellon University
 *  Pittsburgh PA 15213-3890
 * 
 * any improvements or extensions that they make and grant Carnegie Mellon
 * the rights to redistribute these changes.
 */
/*
 */

/*
 *	Mach kernel startup.
 */

#include <debug.h>
#include <xpr_debug.h>
#include <mach_kdp.h>
#include <cpus.h>
#include <mach_host.h>
#include <norma_vm.h>
#include <etap.h>

#include <mach/boolean.h>
#include <mach/machine.h>
#include <mach/task_special_ports.h>
#include <mach/vm_param.h>
#include <ipc/ipc_init.h>
#include <kern/assert.h>
#include <kern/misc_protos.h>
#include <kern/clock.h>
#include <kern/cpu_number.h>
#include <kern/etap_macros.h>
#include <kern/machine.h>
#include <kern/processor.h>
#include <kern/sched_prim.h>
#include <kern/sf.h>
#include <kern/startup.h>
#include <kern/task.h>
#include <kern/thread.h>
#include <kern/timer.h>
#include <kern/xpr.h>
#include <kern/zalloc.h>
#include <vm/vm_kern.h>
#include <vm/vm_init.h>
#include <vm/vm_map.h>
#include <vm/vm_object.h>
#include <vm/vm_page.h>
#include <vm/vm_pageout.h>
#include <machine/pmap.h>
#include <sys/version.h>

vm_offset_t	shared_file_text_region;
vm_offset_t	shared_file_data_region;

#ifdef __ppc__
#include <ppc/Firmware.h>
#include <ppc/mappings.h>
#include <ppc/miscserv.h>
#endif

/* Externs XXX */
extern void	rtclock_reset(void);

/* Forwards */
void		cpu_launch_first_thread(
			thread_t			thread);
void		start_kernel_threads(void);
void        swapin_thread();

ipc_port_t	shared_text_region_handle;
ipc_port_t	shared_data_region_handle;
vm_offset_t	shared_file_mapping_array;

/*
 *	Running in virtual memory, on the interrupt stack.
 *	Does not return.  Dispatches initial thread.
 *
 *	Assumes that master_cpu is set.
 */
void
setup_main(void)
{
	mk_sp_attribute_struct_t	startup_thread_attributes;
	thread_t					startup_thread;

	printf_init();
	panic_init();

	sched_init();
	vm_mem_bootstrap();
	ipc_bootstrap();
	vm_mem_init();
	ipc_init();
	pager_mux_hash_init();

	/*
	 * As soon as the virtual memory system is up, we record
	 * that this CPU is using the kernel pmap.
	 */
	PMAP_ACTIVATE_KERNEL(master_cpu);

#ifdef __ppc__
	mapping_free_prime();						/* Load up with temporary mapping blocks */
#endif

	machine_init();
	kmod_init();
	clock_init();

	init_timers();

	machine_info.max_cpus = NCPUS;
	machine_info.memory_size = mem_size;
	machine_info.avail_cpus = 0;
	machine_info.major_version = KERNEL_MAJOR_VERSION;
	machine_info.minor_version = KERNEL_MINOR_VERSION;

	/*
	 *	Initialize the IPC, task, and thread subsystems.
	 */
    ledger_init();
	swapper_init();
	task_init();
	act_init();
	thread_init();
	subsystem_init();
#if	MACH_HOST
	pset_sys_init();
#endif	/* MACH_HOST */

	/*
	 *	Initialize the Event Trace Analysis Package.
	 * 	Dynamic Phase: 2 of 2
	 */
	etap_init_phase2();
	
	/*
	 *	Create a kernel thread to start the other kernel
	 *	threads.  Thread_resume (from kernel_thread) calls
	 *	thread_setrun, which may look at current thread;
	 *	we must avoid this, since there is no current thread.
	 */
	startup_thread_attributes.policy_id = POLICY_FIFO;
	startup_thread_attributes.priority =
			startup_thread_attributes.max_priority = BASEPRI_KERNEL;
	startup_thread_attributes.sched_data =
			startup_thread_attributes.unconsumed_quantum = 0;

	/*
	 * Create the thread, and point it at the routine.
	 */
	startup_thread = kernel_thread_with_attributes(kernel_task,
						   (sp_attributes_t)&startup_thread_attributes,
											   start_kernel_threads, FALSE);
							
	/*
	 * Pretend it is already running, and resume it.
	 * Since it looks as if it is running, thread_resume
	 * will not try to put it on the run queues.
	 *
	 * We can do all of this without locking, because nothing
	 * else is running yet.
	 */
	startup_thread->state |= TH_RUN;
	(void) thread_resume(startup_thread->top_act);
	/*
	 * Start the thread.
	 */
	cpu_launch_first_thread(startup_thread);
	/*NOTREACHED*/
	panic("cpu_launch_first_thread returns!");
}

/*
 * Now running in a thread.  Create the rest of the kernel threads
 * and the bootstrap task.
 */
void
start_kernel_threads(void)
{
	mk_sp_attribute_struct_t	idle_thread_attributes;
	register int				i;
	long			shared_text_region_size;
	long			shared_data_region_size;

	thread_bind(current_thread(), cpu_to_processor(cpu_number()));
	/*
	 *	Create the idle threads and the other
	 *	service threads.
	 */
	idle_thread_attributes.policy_id = POLICY_FIFO;
	idle_thread_attributes.priority =
			idle_thread_attributes.max_priority = BASEPRI_KERNEL;
	idle_thread_attributes.sched_data =
			idle_thread_attributes.unconsumed_quantum = 0;

	for (i = 0; i < NCPUS; i++) {
	  if (1 /*machine_slot[i].is_cpu*/) {
			processor_t		processor = cpu_to_processor(i);
			thread_t		thread;
			sched_policy_t	*policy;
			sf_return_t		sfr;
			spl_t			s;

			thread = kernel_thread_with_attributes(kernel_task,
							(sp_attributes_t)&idle_thread_attributes,
														idle_thread, FALSE);
			s = splsched();
			thread_lock(thread);
			thread_bind_locked(thread, processor);
			processor->idle_thread = thread;
			/*(void) thread_resume(thread->top_act);*/
			thread->state |= TH_RUN;
			
			/* get pointer to scheduling policy "object" */
			policy = &sched_policy[thread->policy];
	
			sfr = policy->sp_ops.sp_thread_unblock(policy, thread);
			assert(sfr == SF_SUCCESS);
			thread_unlock(thread);
			splx(s);
	    }
	}

	/*
	 * Initialize the thread callout mechanism.
	 */
	thread_call_initialize();

	/*
	 * Invoke some black magic.
	 */
#if __ppc__
	mapping_adjust();
#endif

	/*
	 *	Invoke the thread reaper mechanism.
	 */
	thread_reaper();

	/*
	 *	Start the stack swapin thread
	 */
	kernel_thread(kernel_task,swapin_thread);

	/*
	 *	Invoke the periodic scheduler mechanism.
	 */
	recompute_priorities();

	/*
	 *	Create the clock service.
	 */
	clock_service_create();

	/*
	 *	Create the device service.
	 */
	device_service_create();

	shared_text_region_size = 0x10000000;
	shared_data_region_size = 0x10000000;
	shared_file_init(&shared_text_region_handle,
			shared_text_region_size, &shared_data_region_handle,
			shared_data_region_size, &shared_file_mapping_array);

#ifdef	IOKIT
	{
		PE_init_iokit();
	}
#endif

	/*
	 *	Start the user bootstrap.
	 */
	
	(void) spllo();						/* Allow interruptions */
	
#ifdef	MACH_BSD
	{ 
		extern void bsd_init(void);
		bsd_init();
	}
#endif

	/*
	 *	Invoke the processor action mechanism.
	 */
	processor_action();

	thread_bind(current_thread(), PROCESSOR_NULL);

	/*
	 *	Become the pageout daemon.
	 */

	vm_pageout();
	/*NOTREACHED*/
}

void
slave_main(void)
{
	thread_t startup_thread;

	startup_thread = cpu_to_processor(cpu_number())->next_thread;
	rem_runq(startup_thread);
	cpu_launch_first_thread(startup_thread);
	/*NOTREACHED*/
	panic("cpu_launch_first_thread returns!");
}

/*
 * Now running in a thread context
 */
void
start_cpu_thread(void)
{
	processor_t	processor;

	processor = cpu_to_processor(cpu_number());

	slave_machine_init();

	if (processor->processor_self == IP_NULL) {
		ipc_processor_init(processor);
		ipc_processor_enable(processor);
	}

	printf("start_cpu_thread done on cpu %x\n", cpu_number());

	/* TODO: Mark this processor ready to dispatch threads */

	thread_terminate_self();
}

/*
 *	Start up the first thread on a CPU.
 *	First thread is specified for the master CPU.
 */
void
cpu_launch_first_thread(
	thread_t		thread)
{
	register int	mycpu = cpu_number();

	cpu_up(mycpu);
	start_timer(&kernel_timer[mycpu]);

	if (thread == THREAD_NULL) {
	    thread = cpu_to_processor(mycpu)->idle_thread;
		if (thread == THREAD_NULL || !rem_runq(thread))
		    panic("cpu_launch_first_thread");
	}

	rtclock_reset();		/* start realtime clock ticking */
	PMAP_ACTIVATE_KERNEL(mycpu);

	thread_machine_set_current(thread);
	thread_lock(thread);
	thread->state &= ~TH_UNINT;
	thread_unlock(thread);
	timer_switch(&thread->system_timer);

	PMAP_ACTIVATE_USER(thread->top_act, mycpu);

	assert(mycpu == cpu_number());

	/* The following is necessary to keep things balanced */
	disable_preemption();
	
	load_context(thread);
	/*NOTREACHED*/
}