#include <cpus.h>
#include <string.h>
#include <mach/boolean.h>
#include <mach/kern_return.h>
#include <mach/mach_types.h>
#include <mach/machine.h>
#include <mach/host_info.h>
#include <mach/host_reboot.h>
#include <kern/counters.h>
#include <kern/cpu_data.h>
#include <kern/ipc_host.h>
#include <kern/host.h>
#include <kern/lock.h>
#include <kern/machine.h>
#include <kern/processor.h>
#include <kern/queue.h>
#include <kern/sched.h>
#include <kern/task.h>
#include <kern/thread.h>
#include <kern/thread_swap.h>
#include <kern/misc_protos.h>
#include <kern/mk_sp.h>
struct machine_info machine_info;
struct machine_slot machine_slot[NCPUS];
thread_t machine_wake_thread;
void processor_doshutdown(
processor_t processor);
void
cpu_up(
int cpu)
{
processor_t processor = cpu_to_processor(cpu);
processor_set_t pset = &default_pset;
struct machine_slot *ms;
spl_t s;
s = splsched();
processor_lock(processor);
init_ast_check(processor);
ms = &machine_slot[cpu];
ms->running = TRUE;
machine_info.avail_cpus++;
simple_lock(&pset->sched_lock);
pset_add_processor(pset, processor);
enqueue_tail(&pset->active_queue, (queue_entry_t)processor);
processor->deadline = UINT64_MAX;
processor->state = PROCESSOR_RUNNING;
simple_unlock(&pset->sched_lock);
processor_unlock(processor);
splx(s);
}
void
cpu_down(
int cpu)
{
processor_t processor;
struct machine_slot *ms;
spl_t s;
processor = cpu_to_processor(cpu);
s = splsched();
processor_lock(processor);
ms = &machine_slot[cpu];
ms->running = FALSE;
machine_info.avail_cpus--;
processor->state = PROCESSOR_OFF_LINE;
processor_unlock(processor);
splx(s);
}
kern_return_t
host_reboot(
host_priv_t host_priv,
int options)
{
if (host_priv == HOST_PRIV_NULL)
return (KERN_INVALID_HOST);
assert(host_priv == &realhost);
if (options & HOST_REBOOT_DEBUGGER) {
Debugger("Debugger");
return (KERN_SUCCESS);
}
halt_all_cpus(!(options & HOST_REBOOT_HALT));
return (KERN_SUCCESS);
}
kern_return_t
processor_assign(
processor_t processor,
processor_set_t new_pset,
boolean_t wait)
{
#ifdef lint
processor++; new_pset++; wait++;
#endif
return (KERN_FAILURE);
}
kern_return_t
processor_shutdown(
processor_t processor)
{
processor_set_t pset;
spl_t s;
s = splsched();
processor_lock(processor);
if ( processor->state == PROCESSOR_OFF_LINE ||
processor->state == PROCESSOR_SHUTDOWN ) {
processor_unlock(processor);
splx(s);
return (KERN_SUCCESS);
}
if (processor->state == PROCESSOR_START) {
processor_unlock(processor);
splx(s);
return (KERN_FAILURE);
}
pset = processor->processor_set;
simple_lock(&pset->sched_lock);
while (*(volatile int *)&processor->state == PROCESSOR_DISPATCHING) {
simple_unlock(&pset->sched_lock);
delay(1);
simple_lock(&pset->sched_lock);
}
if (processor->state == PROCESSOR_IDLE) {
remqueue(&pset->idle_queue, (queue_entry_t)processor);
pset->idle_count--;
}
else
if (processor->state == PROCESSOR_RUNNING)
remqueue(&pset->active_queue, (queue_entry_t)processor);
else
panic("processor_request_action");
processor->state = PROCESSOR_SHUTDOWN;
simple_unlock(&pset->sched_lock);
processor_unlock(processor);
processor_doshutdown(processor);
splx(s);
return (KERN_SUCCESS);
}
void
processor_doshutdown(
processor_t processor)
{
thread_t old_thread, self = current_thread();
processor_set_t pset;
processor_t prev;
prev = thread_bind(self, processor);
thread_block(THREAD_CONTINUE_NULL);
processor_lock(processor);
pset = processor->processor_set;
simple_lock(&pset->sched_lock);
if (pset->processor_count == 1) {
thread_t thread;
extern void start_cpu_thread(void);
simple_unlock(&pset->sched_lock);
processor_unlock(processor);
thread = kernel_thread_create(start_cpu_thread, MAXPRI_KERNEL);
thread_lock(thread);
machine_wake_thread = thread;
thread->state = TH_RUN;
pset_run_incr(thread->processor_set);
thread_unlock(thread);
processor_lock(processor);
simple_lock(&pset->sched_lock);
}
assert(processor->state == PROCESSOR_SHUTDOWN);
pset_remove_processor(pset, processor);
simple_unlock(&pset->sched_lock);
processor_unlock(processor);
thread_bind(self, prev);
old_thread = switch_to_shutdown_context(self,
processor_offline, processor);
if (processor != current_processor())
timer_call_shutdown(processor);
thread_dispatch(old_thread);
}
void
processor_offline(
processor_t processor)
{
register thread_t old_thread = processor->active_thread;
register int cpu = processor->slot_num;
timer_call_cancel(&processor->quantum_timer);
timer_switch(&kernel_timer[cpu]);
processor->active_thread = processor->idle_thread;
machine_thread_set_current(processor->active_thread);
thread_dispatch(old_thread);
PMAP_DEACTIVATE_KERNEL(cpu);
cpu_down(cpu);
cpu_sleep();
panic("zombie processor");
}
kern_return_t
host_get_boot_info(
host_priv_t host_priv,
kernel_boot_info_t boot_info)
{
char *src = "";
extern char *machine_boot_info(
kernel_boot_info_t boot_info,
vm_size_t buf_len);
if (host_priv == HOST_PRIV_NULL)
return (KERN_INVALID_HOST);
assert(host_priv == &realhost);
src = machine_boot_info(boot_info, KERNEL_BOOT_INFO_MAX);
if (src != boot_info)
(void) strncpy(boot_info, src, KERNEL_BOOT_INFO_MAX);
return (KERN_SUCCESS);
}