version 1.4, 2007/10/18 15:28:38 |
version 1.4.2.3, 2007/12/27 00:43:26 |
|
|
/* $NetBSD$ */ |
/* $NetBSD$ */ |
|
|
/*- |
/*- |
* Copyright (c) 2000 The NetBSD Foundation, Inc. |
* Copyright (c) 2000, 2006, 2007 The NetBSD Foundation, Inc. |
* All rights reserved. |
* All rights reserved. |
* |
* |
* This code is derived from software contributed to The NetBSD Foundation |
* This code is derived from software contributed to The NetBSD Foundation |
* by RedBack Networks Inc. |
* by Bill Sommerfeld of RedBack Networks Inc, and by Andrew Doran. |
* |
|
* Author: Bill Sommerfeld |
|
* |
* |
* Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
* modification, are permitted provided that the following conditions |
* modification, are permitted provided that the following conditions |
Line 87 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 85 __KERNEL_RCSID(0, "$NetBSD$"); |
|
#include <sys/systm.h> |
#include <sys/systm.h> |
#include <sys/device.h> |
#include <sys/device.h> |
#include <sys/malloc.h> |
#include <sys/malloc.h> |
|
#include <sys/cpu.h> |
|
#include <sys/atomic.h> |
|
|
#include <uvm/uvm_extern.h> |
#include <uvm/uvm_extern.h> |
|
|
#include <machine/cpu.h> |
|
#include <machine/cpufunc.h> |
#include <machine/cpufunc.h> |
#include <machine/cpuvar.h> |
#include <machine/cpuvar.h> |
#include <machine/pmap.h> |
#include <machine/pmap.h> |
Line 124 __KERNEL_RCSID(0, "$NetBSD$"); |
|
Line 123 __KERNEL_RCSID(0, "$NetBSD$"); |
|
int cpu_match(struct device *, struct cfdata *, void *); |
int cpu_match(struct device *, struct cfdata *, void *); |
void cpu_attach(struct device *, struct device *, void *); |
void cpu_attach(struct device *, struct device *, void *); |
|
|
|
static bool cpu_suspend(device_t); |
|
static bool cpu_resume(device_t); |
|
|
struct cpu_softc { |
struct cpu_softc { |
struct device sc_dev; /* device tree glue */ |
struct device sc_dev; /* device tree glue */ |
struct cpu_info *sc_info; /* pointer to CPU info */ |
struct cpu_info *sc_info; /* pointer to CPU info */ |
}; |
}; |
|
|
int mp_cpu_start(struct cpu_info *); |
int mp_cpu_start(struct cpu_info *, paddr_t); |
void mp_cpu_start_cleanup(struct cpu_info *); |
void mp_cpu_start_cleanup(struct cpu_info *); |
const struct cpu_functions mp_cpu_funcs = { mp_cpu_start, NULL, |
const struct cpu_functions mp_cpu_funcs = { mp_cpu_start, NULL, |
mp_cpu_start_cleanup }; |
mp_cpu_start_cleanup }; |
Line 158 struct cpu_info cpu_info_primary = { |
|
Line 160 struct cpu_info cpu_info_primary = { |
|
|
|
struct cpu_info *cpu_info_list = &cpu_info_primary; |
struct cpu_info *cpu_info_list = &cpu_info_primary; |
|
|
static void cpu_set_tss_gates(struct cpu_info *ci); |
static void cpu_set_tss_gates(struct cpu_info *); |
|
|
#ifdef i386 |
#ifdef i386 |
static void cpu_init_tss(struct i386tss *, void *, void *); |
static void cpu_init_tss(struct i386tss *, void *, void *); |
#endif |
#endif |
|
|
|
#ifdef MULTIPROCESSOR |
|
static void cpu_init_idle_lwp(struct cpu_info *); |
|
#endif |
|
|
uint32_t cpus_attached = 0; |
uint32_t cpus_attached = 0; |
|
uint32_t cpus_running = 0; |
|
|
extern char x86_64_doubleflt_stack[]; |
extern char x86_64_doubleflt_stack[]; |
|
|
|
bool x86_mp_online; |
|
paddr_t mp_trampoline_paddr = MP_TRAMPOLINE; |
|
|
|
static vaddr_t cmos_data_mapping; |
|
|
#ifdef MULTIPROCESSOR |
#ifdef MULTIPROCESSOR |
/* |
/* |
* Array of CPU info structures. Must be statically-allocated because |
* Array of CPU info structures. Must be statically-allocated because |
Line 175 extern char x86_64_doubleflt_stack[]; |
|
Line 187 extern char x86_64_doubleflt_stack[]; |
|
*/ |
*/ |
struct cpu_info *cpu_info[X86_MAXPROCS] = { &cpu_info_primary, }; |
struct cpu_info *cpu_info[X86_MAXPROCS] = { &cpu_info_primary, }; |
|
|
uint32_t cpus_running = 0; |
|
|
|
void cpu_hatch(void *); |
void cpu_hatch(void *); |
static void cpu_boot_secondary(struct cpu_info *ci); |
static void cpu_boot_secondary(struct cpu_info *ci); |
static void cpu_start_secondary(struct cpu_info *ci); |
static void cpu_start_secondary(struct cpu_info *ci); |
Line 189 static void cpu_copy_trampoline(void); |
|
Line 199 static void cpu_copy_trampoline(void); |
|
* Called from lapic_boot_init() (from mpbios_scan()). |
* Called from lapic_boot_init() (from mpbios_scan()). |
*/ |
*/ |
void |
void |
cpu_init_first() |
cpu_init_first(void) |
{ |
{ |
int cpunum = lapic_cpu_number(); |
int cpunum = lapic_cpu_number(); |
|
|
Line 200 cpu_init_first() |
|
Line 210 cpu_init_first() |
|
|
|
cpu_info_primary.ci_cpuid = cpunum; |
cpu_info_primary.ci_cpuid = cpunum; |
cpu_copy_trampoline(); |
cpu_copy_trampoline(); |
|
|
|
cmos_data_mapping = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, UVM_KMF_VAONLY); |
|
if (cmos_data_mapping == 0) |
|
panic("No KVA for page 0"); |
|
pmap_kenter_pa(cmos_data_mapping, 0, VM_PROT_READ|VM_PROT_WRITE); |
|
pmap_update(pmap_kernel()); |
} |
} |
#endif |
#endif |
|
|
Line 328 cpu_attach(struct device *parent, struct |
|
Line 344 cpu_attach(struct device *parent, struct |
|
switch (caa->cpu_role) { |
switch (caa->cpu_role) { |
case CPU_ROLE_SP: |
case CPU_ROLE_SP: |
aprint_normal(": (uniprocessor)\n"); |
aprint_normal(": (uniprocessor)\n"); |
ci->ci_flags |= CPUF_PRESENT | CPUF_SP | CPUF_PRIMARY; |
atomic_or_32(&ci->ci_flags, |
|
CPUF_PRESENT | CPUF_SP | CPUF_PRIMARY); |
cpu_intr_init(ci); |
cpu_intr_init(ci); |
identifycpu(ci); |
identifycpu(ci); |
cpu_init(ci); |
cpu_init(ci); |
cpu_set_tss_gates(ci); |
cpu_set_tss_gates(ci); |
pmap_cpu_init_late(ci); |
pmap_cpu_init_late(ci); |
|
x86_errata(); |
break; |
break; |
|
|
case CPU_ROLE_BP: |
case CPU_ROLE_BP: |
aprint_normal(": (boot processor)\n"); |
aprint_normal(": (boot processor)\n"); |
ci->ci_flags |= CPUF_PRESENT | CPUF_BSP | CPUF_PRIMARY; |
atomic_or_32(&ci->ci_flags, |
|
CPUF_PRESENT | CPUF_BSP | CPUF_PRIMARY); |
cpu_intr_init(ci); |
cpu_intr_init(ci); |
identifycpu(ci); |
identifycpu(ci); |
cpu_init(ci); |
cpu_init(ci); |
Line 354 cpu_attach(struct device *parent, struct |
|
Line 373 cpu_attach(struct device *parent, struct |
|
#if NIOAPIC > 0 |
#if NIOAPIC > 0 |
ioapic_bsp_id = caa->cpu_number; |
ioapic_bsp_id = caa->cpu_number; |
#endif |
#endif |
|
x86_errata(); |
break; |
break; |
|
|
case CPU_ROLE_AP: |
case CPU_ROLE_AP: |
Line 387 cpu_attach(struct device *parent, struct |
|
Line 407 cpu_attach(struct device *parent, struct |
|
|
|
cpus_attached |= ci->ci_cpumask; |
cpus_attached |= ci->ci_cpumask; |
|
|
|
if (!pmf_device_register(self, cpu_suspend, cpu_resume)) |
|
aprint_error_dev(self, "couldn't establish power handler\n"); |
|
|
#if defined(MULTIPROCESSOR) |
#if defined(MULTIPROCESSOR) |
if (mp_verbose) { |
if (mp_verbose) { |
struct lwp *l = ci->ci_data.cpu_idlelwp; |
struct lwp *l = ci->ci_data.cpu_idlelwp; |
Line 409 cpu_attach(struct device *parent, struct |
|
Line 432 cpu_attach(struct device *parent, struct |
|
*/ |
*/ |
|
|
void |
void |
cpu_init(ci) |
cpu_init(struct cpu_info *ci) |
struct cpu_info *ci; |
|
{ |
{ |
/* configure the CPU if needed */ |
/* configure the CPU if needed */ |
if (ci->cpu_setup != NULL) |
if (ci->cpu_setup != NULL) |
|
|
#endif /* i386 */ |
#endif /* i386 */ |
#endif /* MTRR */ |
#endif /* MTRR */ |
|
|
#ifdef MULTIPROCESSOR |
atomic_or_32(&ci->ci_flags, CPUF_RUNNING); |
ci->ci_flags |= CPUF_RUNNING; |
atomic_or_32(&cpus_running, ci->ci_cpumask); |
cpus_running |= ci->ci_cpumask; |
|
|
#ifndef MULTIPROCESSOR |
|
/* XXX */ |
|
x86_patch(); |
#endif |
#endif |
} |
} |
|
|
bool x86_mp_online; |
|
|
|
#ifdef MULTIPROCESSOR |
#ifdef MULTIPROCESSOR |
void |
void |
cpu_boot_secondary_processors() |
cpu_boot_secondary_processors(void) |
{ |
{ |
struct cpu_info *ci; |
struct cpu_info *ci; |
u_long i; |
u_long i; |
|
|
|
/* Now that we know the number of CPUs, patch the text segment. */ |
|
x86_patch(); |
|
|
for (i=0; i < X86_MAXPROCS; i++) { |
for (i=0; i < X86_MAXPROCS; i++) { |
ci = cpu_info[i]; |
ci = cpu_info[i]; |
if (ci == NULL) |
if (ci == NULL) |
Line 515 cpu_init_idle_lwp(struct cpu_info *ci) |
|
Line 541 cpu_init_idle_lwp(struct cpu_info *ci) |
|
} |
} |
|
|
void |
void |
cpu_init_idle_lwps() |
cpu_init_idle_lwps(void) |
{ |
{ |
struct cpu_info *ci; |
struct cpu_info *ci; |
u_long i; |
u_long i; |
Line 533 cpu_init_idle_lwps() |
|
Line 559 cpu_init_idle_lwps() |
|
} |
} |
|
|
void |
void |
cpu_start_secondary(ci) |
cpu_start_secondary(struct cpu_info *ci) |
struct cpu_info *ci; |
|
{ |
{ |
int i; |
int i; |
struct pmap *kpm = pmap_kernel(); |
|
extern paddr_t mp_pdirpa; |
extern paddr_t mp_pdirpa; |
|
|
#ifdef __x86_64__ |
mp_pdirpa = pmap_init_tmp_pgtbl(mp_trampoline_paddr); |
/* |
|
* The initial PML4 pointer must be below 4G, so if the |
|
* current one isn't, use a "bounce buffer" |
|
* |
|
* XXX move elsewhere, not per CPU. |
|
*/ |
|
if (kpm->pm_pdirpa > 0xffffffff) { |
|
extern vaddr_t lo32_vaddr; |
|
extern paddr_t lo32_paddr; |
|
memcpy((void *)lo32_vaddr, kpm->pm_pdir, PAGE_SIZE); |
|
mp_pdirpa = lo32_paddr; |
|
} else |
|
#endif |
|
mp_pdirpa = kpm->pm_pdirpa; |
|
|
|
ci->ci_flags |= CPUF_AP; |
atomic_or_32(&ci->ci_flags, CPUF_AP); |
|
|
aprint_debug("%s: starting\n", ci->ci_dev->dv_xname); |
aprint_debug("%s: starting\n", ci->ci_dev->dv_xname); |
|
|
ci->ci_curlwp = ci->ci_data.cpu_idlelwp; |
ci->ci_curlwp = ci->ci_data.cpu_idlelwp; |
CPU_STARTUP(ci); |
CPU_STARTUP(ci, mp_trampoline_paddr); |
|
|
/* |
/* |
* wait for it to become ready |
* wait for it to become ready |
*/ |
*/ |
for (i = 100000; (!(ci->ci_flags & CPUF_PRESENT)) && i>0;i--) { |
for (i = 100000; (!(ci->ci_flags & CPUF_PRESENT)) && i>0;i--) { |
delay(10); |
i8254_delay(10); |
} |
} |
if (! (ci->ci_flags & CPUF_PRESENT)) { |
if ((ci->ci_flags & CPUF_PRESENT) == 0) { |
aprint_error("%s: failed to become ready\n", |
aprint_error("%s: failed to become ready\n", |
ci->ci_dev->dv_xname); |
ci->ci_dev->dv_xname); |
#if defined(MPDEBUG) && defined(DDB) |
#if defined(MPDEBUG) && defined(DDB) |
Line 582 cpu_start_secondary(ci) |
|
Line 592 cpu_start_secondary(ci) |
|
} |
} |
|
|
void |
void |
cpu_boot_secondary(ci) |
cpu_boot_secondary(struct cpu_info *ci) |
struct cpu_info *ci; |
|
{ |
{ |
int i; |
int i; |
|
|
ci->ci_flags |= CPUF_GO; /* XXX atomic */ |
atomic_or_32(&ci->ci_flags, CPUF_GO); |
|
|
for (i = 100000; (!(ci->ci_flags & CPUF_RUNNING)) && i>0;i--) { |
for (i = 100000; (!(ci->ci_flags & CPUF_RUNNING)) && i>0;i--) { |
delay(10); |
i8254_delay(10); |
} |
} |
if (! (ci->ci_flags & CPUF_RUNNING)) { |
if ((ci->ci_flags & CPUF_RUNNING) == 0) { |
aprint_error("%s: failed to start\n", ci->ci_dev->dv_xname); |
aprint_error("%s: failed to start\n", ci->ci_dev->dv_xname); |
#if defined(MPDEBUG) && defined(DDB) |
#if defined(MPDEBUG) && defined(DDB) |
printf("dropping into debugger; continue from here to resume boot\n"); |
printf("dropping into debugger; continue from here to resume boot\n"); |
Line 606 cpu_boot_secondary(ci) |
|
Line 614 cpu_boot_secondary(ci) |
|
* This is called from code in mptramp.s; at this point, we are running |
* This is called from code in mptramp.s; at this point, we are running |
* in the idle pcb/idle stack of the new CPU. When this function returns, |
* in the idle pcb/idle stack of the new CPU. When this function returns, |
* this processor will enter the idle loop and start looking for work. |
* this processor will enter the idle loop and start looking for work. |
* |
|
* XXX should share some of this with init386 in machdep.c |
|
*/ |
*/ |
void |
void |
cpu_hatch(void *v) |
cpu_hatch(void *v) |
{ |
{ |
struct cpu_info *ci = (struct cpu_info *)v; |
struct cpu_info *ci = (struct cpu_info *)v; |
int s; |
int s, i; |
|
|
#ifdef __x86_64__ |
#ifdef __x86_64__ |
cpu_init_msrs(ci); |
cpu_init_msrs(ci, true); |
#endif |
#endif |
cpu_probe_features(ci); |
cpu_probe_features(ci); |
cpu_feature &= ci->ci_feature_flags; |
cpu_feature &= ci->ci_feature_flags; |
cpu_feature2 &= ci->ci_feature2_flags; |
cpu_feature2 &= ci->ci_feature2_flags; |
|
|
#ifdef DEBUG |
KDASSERT((ci->ci_flags & CPUF_PRESENT) == 0); |
if (ci->ci_flags & CPUF_PRESENT) |
atomic_or_32(&ci->ci_flags, CPUF_PRESENT); |
panic("%s: already running!?", ci->ci_dev->dv_xname); |
while ((ci->ci_flags & CPUF_GO) == 0) { |
#endif |
/* Don't use delay, boot CPU may be patching the text. */ |
|
for (i = 10000; i != 0; i--) |
ci->ci_flags |= CPUF_PRESENT; |
x86_pause(); |
|
} |
|
|
|
/* Beacuse the text may have been patched in x86_patch(). */ |
|
wbinvd(); |
|
x86_flush(); |
|
|
lapic_enable(); |
KASSERT((ci->ci_flags & CPUF_RUNNING) == 0); |
lapic_initclocks(); |
|
|
|
while ((ci->ci_flags & CPUF_GO) == 0) |
|
delay(10); |
|
#ifdef DEBUG |
|
if (ci->ci_flags & CPUF_RUNNING) |
|
panic("%s: already running!?", ci->ci_dev->dv_xname); |
|
#endif |
|
|
|
|
lcr3(pmap_kernel()->pm_pdirpa); |
|
curlwp->l_addr->u_pcb.pcb_cr3 = pmap_kernel()->pm_pdirpa; |
lcr0(ci->ci_data.cpu_idlelwp->l_addr->u_pcb.pcb_cr0); |
lcr0(ci->ci_data.cpu_idlelwp->l_addr->u_pcb.pcb_cr0); |
cpu_init_idt(); |
cpu_init_idt(); |
lapic_set_lvt(); |
|
gdt_init_cpu(ci); |
gdt_init_cpu(ci); |
|
lapic_enable(); |
|
lapic_set_lvt(); |
|
lapic_initclocks(); |
|
|
#ifdef i386 |
#ifdef i386 |
npxinit(ci); |
npxinit(ci); |
Line 652 cpu_hatch(void *v) |
|
Line 659 cpu_hatch(void *v) |
|
lldt(GSYSSEL(GLDT_SEL, SEL_KPL)); |
lldt(GSYSSEL(GLDT_SEL, SEL_KPL)); |
|
|
cpu_init(ci); |
cpu_init(ci); |
|
cpu_get_tsc_freq(ci); |
|
|
s = splhigh(); |
s = splhigh(); |
#ifdef i386 |
#ifdef i386 |
Line 661 cpu_hatch(void *v) |
|
Line 669 cpu_hatch(void *v) |
|
#endif |
#endif |
x86_enable_intr(); |
x86_enable_intr(); |
splx(s); |
splx(s); |
|
x86_errata(); |
|
|
aprint_debug("%s: CPU %ld running\n", ci->ci_dev->dv_xname, |
aprint_debug("%s: CPU %ld running\n", ci->ci_dev->dv_xname, |
(long)ci->ci_cpuid); |
(long)ci->ci_cpuid); |
Line 694 cpu_debug_dump(void) |
|
Line 703 cpu_debug_dump(void) |
|
#endif |
#endif |
|
|
static void |
static void |
cpu_copy_trampoline() |
cpu_copy_trampoline(void) |
{ |
{ |
/* |
/* |
* Copy boot code. |
* Copy boot code. |
*/ |
*/ |
extern u_char cpu_spinup_trampoline[]; |
extern u_char cpu_spinup_trampoline[]; |
extern u_char cpu_spinup_trampoline_end[]; |
extern u_char cpu_spinup_trampoline_end[]; |
pmap_kenter_pa((vaddr_t)MP_TRAMPOLINE, /* virtual */ |
|
(paddr_t)MP_TRAMPOLINE, /* physical */ |
vaddr_t mp_trampoline_vaddr; |
VM_PROT_ALL); /* protection */ |
|
|
mp_trampoline_vaddr = uvm_km_alloc(kernel_map, PAGE_SIZE, 0, |
|
UVM_KMF_VAONLY); |
|
|
|
pmap_kenter_pa(mp_trampoline_vaddr, mp_trampoline_paddr, |
|
VM_PROT_READ | VM_PROT_WRITE); |
pmap_update(pmap_kernel()); |
pmap_update(pmap_kernel()); |
memcpy((void *)MP_TRAMPOLINE, |
memcpy((void *)mp_trampoline_vaddr, |
cpu_spinup_trampoline, |
cpu_spinup_trampoline, |
cpu_spinup_trampoline_end-cpu_spinup_trampoline); |
cpu_spinup_trampoline_end-cpu_spinup_trampoline); |
|
|
|
pmap_kremove(mp_trampoline_vaddr, PAGE_SIZE); |
|
pmap_update(pmap_kernel()); |
|
uvm_km_free(kernel_map, mp_trampoline_vaddr, PAGE_SIZE, UVM_KMF_VAONLY); |
} |
} |
|
|
#endif |
#endif |
Line 783 cpu_set_tss_gates(struct cpu_info *ci) |
|
Line 801 cpu_set_tss_gates(struct cpu_info *ci) |
|
} |
} |
#endif /* i386 */ |
#endif /* i386 */ |
|
|
|
|
int |
int |
mp_cpu_start(struct cpu_info *ci) |
mp_cpu_start(struct cpu_info *ci, paddr_t target) |
{ |
{ |
#if NLAPIC > 0 |
#if NLAPIC > 0 |
int error; |
int error; |
Line 793 mp_cpu_start(struct cpu_info *ci) |
|
Line 810 mp_cpu_start(struct cpu_info *ci) |
|
unsigned short dwordptr[2]; |
unsigned short dwordptr[2]; |
|
|
/* |
/* |
|
* Bootstrap code must be addressable in real mode |
|
* and it must be page aligned. |
|
*/ |
|
KASSERT(target < 0x10000 && target % PAGE_SIZE == 0); |
|
|
|
/* |
* "The BSP must initialize CMOS shutdown code to 0Ah ..." |
* "The BSP must initialize CMOS shutdown code to 0Ah ..." |
*/ |
*/ |
|
|
Line 805 mp_cpu_start(struct cpu_info *ci) |
|
Line 828 mp_cpu_start(struct cpu_info *ci) |
|
*/ |
*/ |
|
|
dwordptr[0] = 0; |
dwordptr[0] = 0; |
dwordptr[1] = MP_TRAMPOLINE >> 4; |
dwordptr[1] = target >> 4; |
|
|
pmap_kenter_pa(0, 0, VM_PROT_READ|VM_PROT_WRITE); |
memcpy((uint8_t *)(cmos_data_mapping + 0x467), dwordptr, 4); |
pmap_update(pmap_kernel()); |
|
memcpy((uint8_t *)0x467, dwordptr, 4); |
|
pmap_kremove(0, PAGE_SIZE); |
|
pmap_update(pmap_kernel()); |
|
|
|
#if NLAPIC > 0 |
#if NLAPIC > 0 |
/* |
/* |
Line 822 mp_cpu_start(struct cpu_info *ci) |
|
Line 841 mp_cpu_start(struct cpu_info *ci) |
|
if ((error = x86_ipi_init(ci->ci_apicid)) != 0) |
if ((error = x86_ipi_init(ci->ci_apicid)) != 0) |
return error; |
return error; |
|
|
delay(10000); |
i8254_delay(10000); |
|
|
if (cpu_feature & CPUID_APIC) { |
if (cpu_feature & CPUID_APIC) { |
|
|
if ((error = x86_ipi(MP_TRAMPOLINE/PAGE_SIZE, |
if ((error = x86_ipi(target / PAGE_SIZE, |
ci->ci_apicid, |
ci->ci_apicid, |
LAPIC_DLMODE_STARTUP)) != 0) |
LAPIC_DLMODE_STARTUP)) != 0) |
return error; |
return error; |
delay(200); |
i8254_delay(200); |
|
|
if ((error = x86_ipi(MP_TRAMPOLINE/PAGE_SIZE, |
if ((error = x86_ipi(target / PAGE_SIZE, |
ci->ci_apicid, |
ci->ci_apicid, |
LAPIC_DLMODE_STARTUP)) != 0) |
LAPIC_DLMODE_STARTUP)) != 0) |
return error; |
return error; |
delay(200); |
i8254_delay(200); |
} |
} |
} |
} |
#endif |
#endif |
Line 859 typedef void (vector)(void); |
|
Line 878 typedef void (vector)(void); |
|
extern vector Xsyscall, Xsyscall32; |
extern vector Xsyscall, Xsyscall32; |
|
|
void |
void |
cpu_init_msrs(struct cpu_info *ci) |
cpu_init_msrs(struct cpu_info *ci, bool full) |
{ |
{ |
wrmsr(MSR_STAR, |
wrmsr(MSR_STAR, |
((uint64_t)GSEL(GCODE_SEL, SEL_KPL) << 32) | |
((uint64_t)GSEL(GCODE_SEL, SEL_KPL) << 32) | |
Line 868 cpu_init_msrs(struct cpu_info *ci) |
|
Line 887 cpu_init_msrs(struct cpu_info *ci) |
|
wrmsr(MSR_CSTAR, (uint64_t)Xsyscall32); |
wrmsr(MSR_CSTAR, (uint64_t)Xsyscall32); |
wrmsr(MSR_SFMASK, PSL_NT|PSL_T|PSL_I|PSL_C); |
wrmsr(MSR_SFMASK, PSL_NT|PSL_T|PSL_I|PSL_C); |
|
|
wrmsr(MSR_FSBASE, 0); |
if (full) { |
wrmsr(MSR_GSBASE, (u_int64_t)ci); |
wrmsr(MSR_FSBASE, 0); |
wrmsr(MSR_KERNELGSBASE, 0); |
wrmsr(MSR_GSBASE, (u_int64_t)ci); |
|
wrmsr(MSR_KERNELGSBASE, 0); |
|
} |
|
|
if (cpu_feature & CPUID_NOX) |
if (cpu_feature & CPUID_NOX) |
wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NXE); |
wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_NXE); |
} |
} |
#endif /* __x86_64__ */ |
#endif /* __x86_64__ */ |
|
|
|
/* XXX joerg restructure and restart CPUs individually */ |
|
static bool |
|
cpu_suspend(device_t dv) |
|
{ |
|
struct cpu_softc *sc = device_private(dv); |
|
struct cpu_info *ci = sc->sc_info; |
|
int err; |
|
|
|
if (ci->ci_flags & CPUF_PRIMARY) |
|
return true; |
|
if (ci->ci_data.cpu_idlelwp == NULL) |
|
return true; |
|
if ((ci->ci_flags & CPUF_PRESENT) == 0) |
|
return true; |
|
|
|
mutex_enter(&cpu_lock); |
|
err = cpu_setonline(ci, false); |
|
mutex_exit(&cpu_lock); |
|
return err == 0; |
|
} |
|
|
|
static bool |
|
cpu_resume(device_t dv) |
|
{ |
|
struct cpu_softc *sc = device_private(dv); |
|
struct cpu_info *ci = sc->sc_info; |
|
int err; |
|
|
|
if (ci->ci_flags & CPUF_PRIMARY) |
|
return true; |
|
if (ci->ci_data.cpu_idlelwp == NULL) |
|
return true; |
|
if ((ci->ci_flags & CPUF_PRESENT) == 0) |
|
return true; |
|
|
|
mutex_enter(&cpu_lock); |
|
err = cpu_setonline(ci, true); |
|
mutex_exit(&cpu_lock); |
|
|
|
return err == 0; |
|
} |
|
|
|
void |
|
cpu_get_tsc_freq(struct cpu_info *ci) |
|
{ |
|
uint64_t last_tsc; |
|
u_int junk[4]; |
|
|
|
if (ci->ci_feature_flags & CPUID_TSC) { |
|
/* Serialize. */ |
|
x86_cpuid(0, junk); |
|
last_tsc = rdtsc(); |
|
i8254_delay(100000); |
|
ci->ci_tsc_freq = (rdtsc() - last_tsc) * 10; |
|
} |
|
} |