Index: arch/x86/x86/cpu.c =================================================================== RCS file: /cvsroot/src/sys/arch/x86/x86/cpu.c,v retrieving revision 1.69.2.2 diff -u -p -u -r1.69.2.2 cpu.c --- arch/x86/x86/cpu.c 30 May 2010 05:17:12 -0000 1.69.2.2 +++ arch/x86/x86/cpu.c 29 Jan 2011 18:51:45 -0000 @@ -84,7 +84,7 @@ __KERNEL_RCSID(0, "$NetBSD: cpu.c,v 1.69 #include #include -#include +#include #include #include @@ -122,6 +122,7 @@ void cpu_attach(device_t, device_t, v static bool cpu_suspend(device_t, const pmf_qual_t *); static bool cpu_resume(device_t, const pmf_qual_t *); +static bool cpu_shutdown(device_t, int); struct cpu_softc { device_t sc_dev; /* device tree glue */ @@ -301,10 +302,9 @@ cpu_attach(device_t parent, device_t sel return; } aprint_naive(": Application Processor\n"); - ptr = (uintptr_t)kmem_alloc(sizeof(*ci) + CACHE_LINE_SIZE - 1, + ptr = (uintptr_t)kmem_zalloc(sizeof(*ci) + CACHE_LINE_SIZE - 1, KM_SLEEP); ci = (struct cpu_info *)roundup2(ptr, CACHE_LINE_SIZE); - memset(ci, 0, sizeof(*ci)); ci->ci_curldt = -1; #ifdef TRAPLOG ci->ci_tlog_base = kmem_zalloc(sizeof(struct tlog), KM_SLEEP); @@ -332,6 +332,7 @@ cpu_attach(device_t parent, device_t sel ci->ci_self = ci; sc->sc_info = ci; ci->ci_dev = self; + ci->ci_acpiid = caa->cpu_id; ci->ci_cpuid = caa->cpu_number; ci->ci_func = caa->cpu_func; @@ -405,6 +406,7 @@ cpu_attach(device_t parent, device_t sel cpu_intr_init(ci); gdt_alloc_cpu(ci); cpu_set_tss_gates(ci); + cpu_allocate_l3pd(ci);) cpu_start_secondary(ci); if (ci->ci_flags & CPUF_PRESENT) { struct cpu_info *tmp; @@ -423,9 +425,10 @@ cpu_attach(device_t parent, device_t sel panic("unknown processor type??\n"); } + pat_init(ci); atomic_or_32(&cpus_attached, ci->ci_cpumask); - if (!pmf_device_register(self, cpu_suspend, cpu_resume)) + if (!pmf_device_register1(self, cpu_suspend, cpu_resume, cpu_shutdown)) aprint_error_dev(self, "couldn't establish power handler\n"); if (mp_verbose) { @@ -717,9 +720,18 @@ cpu_hatch(void *v) KASSERT((ci->ci_flags & CPUF_RUNNING) == 0); - lcr3(pmap_kernel()->pm_pdirpa); +#ifdef PAE + pd_entry_t * l3_pd = ci->ci_pae_l3_pdir; + for (i = 0 ; i < PDP_SIZE; i++) { + l3_pd[i] = pmap_kernel()->pm_pdirpa[i] | PG_V; + } + lcr3(ci->ci_pae_l3_pdirpa); +#else + lcr3(pmap_pdirpa(pmap_kernel(), 0)); +#endif + pcb = lwp_getpcb(curlwp); - pcb->pcb_cr3 = pmap_kernel()->pm_pdirpa; + pcb->pcb_cr3 = rcr3(); pcb = lwp_getpcb(ci->ci_data.cpu_idlelwp); lcr0(pcb->pcb_cr0); @@ -812,6 +824,8 @@ cpu_copy_trampoline(void) static void tss_init(struct i386tss *tss, void *stack, void *func) { + KASSERT(curcpu()->ci_pmap == pmap_kernel()); + memset(tss, 0, sizeof *tss); tss->tss_esp0 = tss->tss_esp = (int)((char *)stack + USPACE - 16); tss->tss_ss0 = GSEL(GDATA_SEL, SEL_KPL); @@ -819,7 +833,8 @@ tss_init(struct i386tss *tss, void *stac tss->tss_fs = GSEL(GCPU_SEL, SEL_KPL); tss->tss_gs = tss->__tss_es = tss->__tss_ds = tss->__tss_ss = GSEL(GDATA_SEL, SEL_KPL); - tss->tss_cr3 = pmap_kernel()->pm_pdirpa; + /* %cr3 contains the value associated to pmap_kernel */ + tss->tss_cr3 = rcr3(); tss->tss_esp = (int)((char *)stack + USPACE - 16); tss->tss_ldt = GSEL(GLDT_SEL, SEL_KPL); tss->__tss_eflags = PSL_MBO | PSL_NT; /* XXX not needed? */ @@ -878,6 +893,47 @@ cpu_set_tss_gates(struct cpu_info *ci) } #endif /* i386 */ +#ifdef PAE +cpu_allocate_l3pd(struct cpu_info *ci) +{ + int ret; + struct pglist pg; + struct vm_page *vmap; + + /* The BP has already its own L3 page allocated in locore.S. */ + KASSERT(ci != &cpu_info_primary); + + /* + * Allocate a page for the per-CPU L3 PD. cr3 being 32 bits, PA musts + * resides below the 4GB boundary. + */ + ret = uvm_pglistalloc(PAGE_SIZE, 0, 0x100000000ULL, 32, 0, &pg, 1, 0); + vmap = TAILQ_FIRST(&pg); + + if (ret != 0 || vmap == NULL) + panic("%s: failed to allocate L3 pglist for CPU %d (ret %d)\n", + __func__, cpu_index(ci), ret); + + ci->ci_pae_l3_pdirpa = vmap->phys_addr; + + ci->ci_pae_l3_pdir = (paddr_t *)uvm_km_alloc(kernel_map, PAGE_SIZE, 0, + UVM_KMF_VAONLY | UVM_KMF_NOWAIT); + if (ci->ci_pae_l3_pdir == NULL) + panic("%s: failed to allocate L3 PD for CPU %d\n", + __func__, cpu_index(ci)); + + pmap_kenter_pa((vaddr_t)ci->ci_pae_l3_pdir, ci->ci_pae_l3_pdirpa, + VM_PROT_READ | VM_PROT_WRITE, 0); + + pmap_update(pmap_kernel()); +} +#else +cpu_allocate_l3pd(struct cpu_info *ci) +{ + +} +#endif /* PAE */ + int mp_cpu_start(struct cpu_info *ci, paddr_t target) { @@ -1023,7 +1079,7 @@ cpu_suspend(device_t dv, const pmf_qual_ mutex_enter(&cpu_lock); err = cpu_setstate(ci, false); mutex_exit(&cpu_lock); - + if (err) return false; } @@ -1054,6 +1110,12 @@ cpu_resume(device_t dv, const pmf_qual_t return err == 0; } +static bool +cpu_shutdown(device_t dv, int how) +{ + return cpu_suspend(dv, NULL); +} + void cpu_get_tsc_freq(struct cpu_info *ci) { @@ -1094,3 +1156,26 @@ x86_cpu_idle_halt(void) x86_enable_intr(); } } + +/* + * Loads pmap for the current CPU. + */ +void +cpu_load_pmap(struct pmap *pmap) +{ +#ifdef PAE + int i, s; + struct cpu_info *ci; + + s = splvm(); /* just to be safe */ + ci = curcpu(); + pd_entry_t *l3_pd = ci->ci_pae_l3_pdir; + for (i = 0 ; i < PDP_SIZE; i++) { + l3_pd[i] = pmap->pm_pdirpa[i] | PG_V; + } + splx(s); + tlbflush(); +#else /* PAE */ + lcr3(pmap_pdirpa(pmap, 0)); +#endif /* PAE */ +}