4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 #include <sys/types.h>
27 #include <sys/systm.h>
28 #include <sys/archsystm.h>
29 #include <sys/machsystm.h>
30 #include <sys/t_lock.h>
35 #include <sys/cmn_err.h>
36 #include <sys/cpuvar.h>
37 #include <sys/atomic.h>
43 #include <vm/seg_kmem.h>
44 #include <vm/seg_kpm.h>
45 #include <vm/hat_sfmmu.h>
46 #include <sys/debug.h>
47 #include <sys/cpu_module.h>
50 * A quick way to generate a cache consistent address to map in a page.
51 * users: ppcopy, pagezero, /proc, dev/mem
53 * The ppmapin/ppmapout routines provide a quick way of generating a cache
54 * consistent address by reserving a given amount of kernel address space.
55 * The base is PPMAPBASE and its size is PPMAPSIZE. This memory is divided
56 * into x number of sets, where x is the number of colors for the virtual
57 * cache. The number of colors is how many times a page can be mapped
58 * simulatenously in the cache. For direct map caches this translates to
59 * the number of pages in the cache.
60 * Each set will be assigned a group of virtual pages from the reserved memory
61 * depending on its virtual color.
62 * When trying to assign a virtual address we will find out the color for the
63 * physical page in question (if applicable). Then we will try to find an
64 * available virtual page from the set of the appropiate color.
67 int pp_slots
= 4; /* small default, tuned by cpu module */
69 /* tuned by cpu module, default is "safe" */
70 int pp_consistent_coloring
= PPAGE_STORES_POLLUTE
| PPAGE_LOADS_POLLUTE
;
72 static caddr_t ppmap_vaddrs
[PPMAPSIZE
/ MMU_PAGESIZE
];
73 static int nsets
; /* number of sets */
74 static int ppmap_shift
; /* set selector */
77 #define MAXCOLORS 16 /* for debug only */
78 static int ppalloc_noslot
= 0; /* # of allocations from kernelmap */
79 static int align_hits
;
80 static int pp_allocs
; /* # of ppmapin requests */
84 * There are only 64 TLB entries on spitfire, 16 on cheetah
85 * (fully-associative TLB) so we allow the cpu module to tune the
86 * number to use here via pp_slots.
88 static struct ppmap_va
{
89 caddr_t ppmap_slots
[MAXPP_SLOTS
];
92 /* prevent compilation with VAC defined */
94 #error "sun4v ppmapin and ppmapout do not support VAC"
103 ASSERT(pp_slots
<= MAXPP_SLOTS
);
105 va
= (caddr_t
)PPMAPBASE
;
108 * sun4v does not have a virtual indexed cache and simply
109 * has only one set containing all pages.
111 nsets
= mmu_btop(PPMAPSIZE
);
112 ppmap_shift
= MMU_PAGESHIFT
;
114 for (nset
= 0; nset
< nsets
; nset
++) {
116 (caddr_t
)((uintptr_t)va
+ (nset
* MMU_PAGESIZE
));
121 * Allocate a cache consistent virtual address to map a page, pp,
122 * with protection, vprot; and map it in the MMU, using the most
123 * efficient means possible. The argument avoid is a virtual address
124 * hint which when masked yields an offset into a virtual cache
125 * that should be avoided when allocating an address to map in a
126 * page. An avoid arg of -1 means you don't care, for instance pagezero.
128 * machine dependent, depends on virtual address space layout,
129 * understands that all kernel addresses have bit 31 set.
131 * NOTE: For sun4 platforms the meaning of the hint argument is opposite from
132 * that found in other architectures. In other architectures the hint
133 * (called avoid) was used to ask ppmapin to NOT use the specified cache color.
134 * This was used to avoid virtual cache trashing in the bcopy. Unfortunately
135 * in the case of a COW, this later on caused a cache aliasing conflict. In
136 * sun4, the bcopy routine uses the block ld/st instructions so we don't have
137 * to worry about virtual cache trashing. Actually, by using the hint to choose
138 * the right color we can almost guarantee a cache conflict will not occur.
143 ppmapin(page_t
*pp
, uint_t vprot
, caddr_t hint
)
153 * For sun4v caches are physical caches, we can pick any address
156 for (nset
= 0; nset
< nsets
; nset
++) {
157 va
= ppmap_vaddrs
[nset
];
162 if (atomic_cas_ptr(&ppmap_vaddrs
[nset
], va
, NULL
) ==
164 hat_memload(kas
.a_hat
, va
, pp
,
177 * No free slots; get a random one from the kernel heap area.
179 va
= vmem_alloc(heap_arena
, PAGESIZE
, VM_SLEEP
);
181 hat_memload(kas
.a_hat
, va
, pp
, vprot
| HAT_NOSYNC
, HAT_LOAD_LOCK
);
192 if (va
>= kernelheap
&& va
< ekernelheap
) {
194 * Space came from kernelmap, flush the page and
197 hat_unload(kas
.a_hat
, va
, PAGESIZE
,
198 (HAT_UNLOAD_NOSYNC
| HAT_UNLOAD_UNLOCK
));
199 vmem_free(heap_arena
, va
, PAGESIZE
);
202 * Space came from ppmap_vaddrs[], give it back.
204 nset
= ((uintptr_t)va
>> ppmap_shift
) & (nsets
- 1);
205 hat_unload(kas
.a_hat
, va
, PAGESIZE
,
206 (HAT_UNLOAD_NOSYNC
| HAT_UNLOAD_UNLOCK
));
208 ASSERT(ppmap_vaddrs
[nset
] == NULL
);
209 ppmap_vaddrs
[nset
] = va
;
214 #define PP_STAT_ADD(stat) (stat)++
215 uint_t pload
, ploadfail
;
216 uint_t ppzero
, ppzero_short
;
218 #define PP_STAT_ADD(stat)
222 pp_unload_tlb(caddr_t
*pslot
, caddr_t va
)
224 ASSERT(*pslot
== va
);
226 vtag_flushpage(va
, (uint64_t)ksfmmup
);
227 *pslot
= NULL
; /* release the slot */
231 * Routine to copy kernel pages during relocation. It will copy one
232 * PAGESIZE page to another PAGESIZE page. This function may be called
233 * above LOCK_LEVEL so it should not grab any locks.
236 ppcopy_kernel__relocatable(page_t
*fm_pp
, page_t
*to_pp
)
238 uint64_t fm_pa
, to_pa
;
241 fm_pa
= (uint64_t)(fm_pp
->p_pagenum
) << MMU_PAGESHIFT
;
242 to_pa
= (uint64_t)(to_pp
->p_pagenum
) << MMU_PAGESHIFT
;
244 nbytes
= MMU_PAGESIZE
;
246 for (; nbytes
> 0; fm_pa
+= 32, to_pa
+= 32, nbytes
-= 32)
247 hw_pa_bcopy32(fm_pa
, to_pa
);
251 * Copy the data from the physical page represented by "frompp" to
252 * that represented by "topp".
254 * Try to use per cpu mapping first, if that fails then call pp_mapin
256 * Returns one on success or zero on some sort of fault while doing the copy.
259 ppcopy(page_t
*fm_pp
, page_t
*to_pp
)
261 caddr_t fm_va
= NULL
;
267 ASSERT(PAGE_LOCKED(fm_pp
));
268 ASSERT(PAGE_LOCKED(to_pp
));
271 * Try to map using KPM if enabled. If it fails, fall
272 * back to ppmapin/ppmapout.
274 if ((kpm_enable
== 0) ||
275 (fm_va
= hat_kpm_mapin(fm_pp
, NULL
)) == NULL
||
276 (to_va
= hat_kpm_mapin(to_pp
, NULL
)) == NULL
) {
278 hat_kpm_mapout(fm_pp
, NULL
, fm_va
);
279 fm_va
= ppmapin(fm_pp
, PROT_READ
, (caddr_t
)-1);
280 to_va
= ppmapin(to_pp
, PROT_READ
| PROT_WRITE
, fm_va
);
285 if (on_fault(&ljb
)) {
289 bcopy(fm_va
, to_va
, PAGESIZE
);
295 hat_kpm_mapout(fm_pp
, NULL
, fm_va
);
296 hat_kpm_mapout(to_pp
, NULL
, to_va
);
305 * Zero the physical page from off to off + len given by `pp'
306 * without changing the reference and modified bits of page.
308 * Again, we'll try per cpu mapping first.
312 pagezero(page_t
*pp
, uint_t off
, uint_t len
)
315 extern int hwblkclr(void *, size_t);
316 extern int use_hw_bzero
;
319 ASSERT((int)len
> 0 && (int)off
>= 0 && off
+ len
<= PAGESIZE
);
320 ASSERT(PAGE_LOCKED(pp
));
324 if (len
!= MMU_PAGESIZE
|| !use_hw_bzero
) {
325 PP_STAT_ADD(ppzero_short
);
331 * Try to use KPM if enabled. If that fails, fall back to
335 if (kpm_enable
!= 0) {
337 va
= hat_kpm_mapin(pp
, NULL
);
343 va
= ppmapin(pp
, PROT_READ
| PROT_WRITE
, (caddr_t
)-1);
347 bzero(va
+ off
, len
);
348 sync_icache(va
+ off
, len
);
349 } else if (hwblkclr(va
+ off
, len
)) {
351 * We may not have used block commit asi.
352 * So flush the I-$ manually
354 sync_icache(va
+ off
, len
);
357 * We have used blk commit, and flushed the I-$.
358 * However we still may have an instruction in the
359 * pipeline. Only a flush will invalidate that.
365 hat_kpm_mapout(pp
, NULL
, va
);