#include <kern/cpu_number.h>
#include <kern/kalloc.h>
#include <kern/cpu_data.h>
#include <mach/machine.h>
#include <vm/vm_kern.h>
#include <i386/mp_desc.h>
#include <i386/lock.h>
#include <i386/misc_protos.h>
#include <i386/mp.h>
#include <i386/pmap.h>
#include <kern/misc_protos.h>
#include <mach_kdb.h>
extern char intstack[];
extern char eintstack[];
cpu_data_t cpu_data_master;
cpu_data_t *cpu_data_ptr[MAX_CPUS] = { [0] &cpu_data_master };
decl_simple_lock_data(,cpu_lock);
unsigned int real_ncpus = 1;
unsigned int max_ncpus = MAX_CPUS;
struct fake_descriptor ldt_desc_pattern = {
(unsigned int) 0,
LDTSZ * sizeof(struct fake_descriptor) - 1,
0,
ACC_P|ACC_PL_K|ACC_LDT
};
struct fake_descriptor tss_desc_pattern = {
(unsigned int) 0,
sizeof(struct i386_tss),
0,
ACC_P|ACC_PL_K|ACC_TSS
};
struct fake_descriptor cpudata_desc_pattern = {
(unsigned int) 0,
sizeof(cpu_data_t)-1,
SZ_32,
ACC_P|ACC_PL_K|ACC_DATA_W
};
void
mp_desc_init(
cpu_data_t *cdp,
boolean_t is_boot_cpu)
{
struct mp_desc_table *mpt = cdp->cpu_desc_tablep;
cpu_desc_index_t *cdt = &cdp->cpu_desc_index;
if (is_boot_cpu) {
cdt->cdi_ktss = &ktss;
#if MACH_KDB
cdt->cdi_dbtss = &dbtss;
#endif
cdt->cdi_gdt = gdt;
cdt->cdi_idt = idt;
cdt->cdi_ldt = ldt;
} else {
cdt->cdi_ktss = &mpt->ktss;
cdt->cdi_gdt = mpt->gdt;
cdt->cdi_idt = mpt->idt;
cdt->cdi_ldt = mpt->ldt;
bcopy((char *)idt,
(char *)mpt->idt,
sizeof(idt));
bcopy((char *)gdt,
(char *)mpt->gdt,
sizeof(gdt));
bcopy((char *)ldt,
(char *)mpt->ldt,
sizeof(ldt));
bzero((char *)&mpt->ktss,
sizeof(struct i386_tss));
#if MACH_KDB
cdt->cdi_dbtss = &dbtss;
bcopy((char *)&dbtss,
(char *)&mpt->dbtss,
sizeof(struct i386_tss));
#endif
mpt->gdt[sel_idx(KERNEL_LDT)] = ldt_desc_pattern;
mpt->gdt[sel_idx(KERNEL_LDT)].offset = (vm_offset_t) mpt->ldt;
fix_desc(&mpt->gdt[sel_idx(KERNEL_LDT)], 1);
mpt->gdt[sel_idx(KERNEL_TSS)] = tss_desc_pattern;
mpt->gdt[sel_idx(KERNEL_TSS)].offset = (vm_offset_t) &mpt->ktss;
fix_desc(&mpt->gdt[sel_idx(KERNEL_TSS)], 1);
mpt->gdt[sel_idx(CPU_DATA_GS)] = cpudata_desc_pattern;
mpt->gdt[sel_idx(CPU_DATA_GS)].offset = (vm_offset_t) cdp;
fix_desc(&mpt->gdt[sel_idx(CPU_DATA_GS)], 1);
#if MACH_KDB
mpt->gdt[sel_idx(DEBUG_TSS)] = tss_desc_pattern;
mpt->gdt[sel_idx(DEBUG_TSS)].offset = (vm_offset_t) &mpt->dbtss;
fix_desc(&mpt->gdt[sel_idx(DEBUG_TSS)], 1);
mpt->dbtss.esp0 = (int)(db_task_stack_store +
(INTSTACK_SIZE * (cpu + 1)) - sizeof (natural_t));
mpt->dbtss.esp = mpt->dbtss.esp0;
mpt->dbtss.eip = (int)&db_task_start;
#endif
mpt->ktss.ss0 = KERNEL_DS;
mpt->ktss.io_bit_map_offset = 0x0FFF;
}
}
cpu_data_t *
cpu_data_alloc(boolean_t is_boot_cpu)
{
int ret;
cpu_data_t *cdp;
if (is_boot_cpu) {
assert(real_ncpus == 1);
simple_lock_init(&cpu_lock, 0);
cdp = &cpu_data_master;
if (cdp->cpu_processor == NULL) {
cdp->cpu_processor = cpu_processor_alloc(TRUE);
cdp->cpu_pmap = pmap_cpu_alloc(TRUE);
cdp->cpu_this = cdp;
cdp->cpu_int_stack_top = (vm_offset_t) eintstack;
mp_desc_init(cdp, TRUE);
}
return cdp;
}
if (real_ncpus >= max_ncpus)
return NULL;
ret = kmem_alloc(kernel_map,
(vm_offset_t *) &cdp, sizeof(cpu_data_t));
if (ret != KERN_SUCCESS) {
printf("cpu_data_alloc() failed, ret=%d\n", ret);
goto abort;
}
bzero((void*) cdp, sizeof(cpu_data_t));
cdp->cpu_this = cdp;
ret = kmem_alloc(kernel_map,
(vm_offset_t *) &cdp->cpu_int_stack_top,
INTSTACK_SIZE);
if (ret != KERN_SUCCESS) {
printf("cpu_data_alloc() int stack failed, ret=%d\n", ret);
goto abort;
}
bzero((void*) cdp->cpu_int_stack_top, INTSTACK_SIZE);
cdp->cpu_int_stack_top += INTSTACK_SIZE;
ret = kmem_alloc(kernel_map,
(vm_offset_t *) &cdp->cpu_desc_tablep,
sizeof(struct mp_desc_table));
if (ret != KERN_SUCCESS) {
printf("cpu_data_alloc() desc_table failed, ret=%d\n", ret);
goto abort;
}
simple_lock(&cpu_lock);
if (real_ncpus >= max_ncpus) {
simple_unlock(&cpu_lock);
goto abort;
}
cpu_data_ptr[real_ncpus] = cdp;
cdp->cpu_number = real_ncpus;
real_ncpus++;
simple_unlock(&cpu_lock);
kprintf("cpu_data_alloc(%d) 0x%x desc_table: 0x%x "
"int_stack: 0x%x-0x%x\n",
cdp->cpu_number, cdp, cdp->cpu_desc_tablep,
cdp->cpu_int_stack_top - INTSTACK_SIZE, cdp->cpu_int_stack_top);
return cdp;
abort:
if (cdp) {
if (cdp->cpu_desc_tablep)
kfree((void *) cdp->cpu_desc_tablep,
sizeof(*cdp->cpu_desc_tablep));
if (cdp->cpu_int_stack_top)
kfree((void *) (cdp->cpu_int_stack_top - INTSTACK_SIZE),
INTSTACK_SIZE);
kfree((void *) cdp, sizeof(*cdp));
}
return NULL;
}
boolean_t
valid_user_segment_selectors(uint16_t cs,
uint16_t ss,
uint16_t ds,
uint16_t es,
uint16_t fs,
uint16_t gs)
{
return valid_user_code_selector(cs) &&
valid_user_stack_selector(ss) &&
valid_user_data_selector(ds) &&
valid_user_data_selector(es) &&
valid_user_data_selector(fs) &&
valid_user_data_selector(gs);
}