1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate * CDDL HEADER START
3*0Sstevel@tonic-gate *
4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance
7*0Sstevel@tonic-gate * with the License.
8*0Sstevel@tonic-gate *
9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate * and limitations under the License.
13*0Sstevel@tonic-gate *
14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate *
20*0Sstevel@tonic-gate * CDDL HEADER END
21*0Sstevel@tonic-gate */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24*0Sstevel@tonic-gate * Use is subject to license terms.
25*0Sstevel@tonic-gate */
26*0Sstevel@tonic-gate
27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
28*0Sstevel@tonic-gate
29*0Sstevel@tonic-gate #include <sys/types.h>
30*0Sstevel@tonic-gate #include <sys/cmn_err.h>
31*0Sstevel@tonic-gate #include <sys/mman.h>
32*0Sstevel@tonic-gate #include <sys/sunddi.h>
33*0Sstevel@tonic-gate #include <sys/tnf_probe.h>
34*0Sstevel@tonic-gate #include <vm/hat_sfmmu.h>
35*0Sstevel@tonic-gate #include <vm/as.h>
36*0Sstevel@tonic-gate #include <vm/xhat.h>
37*0Sstevel@tonic-gate #include <vm/xhat_sfmmu.h>
38*0Sstevel@tonic-gate #include <sys/zulu_hat.h>
39*0Sstevel@tonic-gate #include <sys/zulumod.h>
40*0Sstevel@tonic-gate
41*0Sstevel@tonic-gate /*
42*0Sstevel@tonic-gate * This file contains the implementation of zulu_hat: an XHAT provider
43*0Sstevel@tonic-gate * to support the MMU for the XVR-4000 graphics accelerator (code name zulu).
44*0Sstevel@tonic-gate *
45*0Sstevel@tonic-gate * The zulu hat is linked into the kernel misc module zuluvm.
46*0Sstevel@tonic-gate * zuluvm provides services that the zulu device driver module requires
47*0Sstevel@tonic-gate * that are not part of the standard ddi. See PSARC 2002/231.
48*0Sstevel@tonic-gate *
49*0Sstevel@tonic-gate * The zulu driver is delivered by the graphics consolidation.
50*0Sstevel@tonic-gate * zuluvm is in ON workspace.
51*0Sstevel@tonic-gate *
52*0Sstevel@tonic-gate * There are two types of interfaces provided by zulu_hat
53*0Sstevel@tonic-gate * 1. The set of functions and data structures used by zuluvm to obtain
54*0Sstevel@tonic-gate * tte entries for the zulu MMU and to manage the association between
55*0Sstevel@tonic-gate * user process's address spaces and zulu graphics contexts.
56*0Sstevel@tonic-gate *
57*0Sstevel@tonic-gate * 2. The entry points required for an XHAT provider: zulu_hat_ops
58*0Sstevel@tonic-gate */
59*0Sstevel@tonic-gate
60*0Sstevel@tonic-gate /*
61*0Sstevel@tonic-gate * zulu_ctx_tab contains an array of pointers to the zulu_hats.
62*0Sstevel@tonic-gate *
63*0Sstevel@tonic-gate * During zulu graphics context switch, the zulu MMU's current context register
64*0Sstevel@tonic-gate * is set to the index of the process's zulu hat's location in the array
65*0Sstevel@tonic-gate * zulu_ctx_tab.
66*0Sstevel@tonic-gate *
67*0Sstevel@tonic-gate * This allows the TL=1 TLB miss handler to quickly find the zulu hat and
68*0Sstevel@tonic-gate * lookup a tte in the zulu hat's TSB.
69*0Sstevel@tonic-gate *
70*0Sstevel@tonic-gate * To synchronize with the trap handler we use bit zero of
71*0Sstevel@tonic-gate * the pointer as a lock bit. See the function zulu_ctx_tsb_lock_enter().
72*0Sstevel@tonic-gate *
73*0Sstevel@tonic-gate * If the trap handler finds the ctx locked it doesn't wait, it
74*0Sstevel@tonic-gate * posts a soft interrupt which is handled at TL=0.
75*0Sstevel@tonic-gate */
76*0Sstevel@tonic-gate
77*0Sstevel@tonic-gate #define ZULU_HAT_MAX_CTX 32
78*0Sstevel@tonic-gate struct zulu_hat *zulu_ctx_tab[ZULU_HAT_MAX_CTX];
79*0Sstevel@tonic-gate
80*0Sstevel@tonic-gate /*
81*0Sstevel@tonic-gate * To avoid searching through the whole zulu_ctx_tab for a free slot,
82*0Sstevel@tonic-gate * we maintain the value of zulu_ctx_search_start.
83*0Sstevel@tonic-gate *
84*0Sstevel@tonic-gate * This value is a guess as to where a free slot in the context table might be.
85*0Sstevel@tonic-gate * All slots < zulu_ctx_search_start are definitely occupied.
86*0Sstevel@tonic-gate */
87*0Sstevel@tonic-gate static int zulu_ctx_search_start = 0;
88*0Sstevel@tonic-gate
89*0Sstevel@tonic-gate
90*0Sstevel@tonic-gate /*
91*0Sstevel@tonic-gate * this mutex protects the zulu_ctx_tab and zulu_ctx_search_start
92*0Sstevel@tonic-gate */
93*0Sstevel@tonic-gate static kmutex_t zulu_ctx_lock;
94*0Sstevel@tonic-gate
95*0Sstevel@tonic-gate
96*0Sstevel@tonic-gate uint64_t zulu_tsb_hit = 0; /* assembly code increments this */
97*0Sstevel@tonic-gate static uint64_t zulu_tsb_miss = 0;
98*0Sstevel@tonic-gate static uint64_t zulu_as_fault = 0;
99*0Sstevel@tonic-gate
100*0Sstevel@tonic-gate /*
101*0Sstevel@tonic-gate * The zulu device has two zulu data mmus.
102*0Sstevel@tonic-gate * We use the base pagesize for one of them and the and 4M for the other.
103*0Sstevel@tonic-gate */
104*0Sstevel@tonic-gate extern int zuluvm_base_pgsize;
105*0Sstevel@tonic-gate
106*0Sstevel@tonic-gate
107*0Sstevel@tonic-gate
108*0Sstevel@tonic-gate /*
109*0Sstevel@tonic-gate * call zuluvm to remove translations for a page
110*0Sstevel@tonic-gate */
111*0Sstevel@tonic-gate static void
zulu_hat_demap_page(struct zulu_hat * zhat,caddr_t vaddr,int size)112*0Sstevel@tonic-gate zulu_hat_demap_page(struct zulu_hat *zhat, caddr_t vaddr, int size)
113*0Sstevel@tonic-gate {
114*0Sstevel@tonic-gate if (zhat->zulu_ctx < 0) {
115*0Sstevel@tonic-gate /* context has been stolen, so page is already demapped */
116*0Sstevel@tonic-gate return;
117*0Sstevel@tonic-gate }
118*0Sstevel@tonic-gate zuluvm_demap_page(zhat->zdev, NULL, zhat->zulu_ctx, vaddr, size);
119*0Sstevel@tonic-gate }
120*0Sstevel@tonic-gate
121*0Sstevel@tonic-gate static void
zulu_hat_demap_ctx(void * zdev,int zulu_ctx)122*0Sstevel@tonic-gate zulu_hat_demap_ctx(void *zdev, int zulu_ctx)
123*0Sstevel@tonic-gate {
124*0Sstevel@tonic-gate if (zulu_ctx < 0) {
125*0Sstevel@tonic-gate /* context has been stolen */
126*0Sstevel@tonic-gate return;
127*0Sstevel@tonic-gate }
128*0Sstevel@tonic-gate zuluvm_demap_ctx(zdev, zulu_ctx);
129*0Sstevel@tonic-gate }
130*0Sstevel@tonic-gate
131*0Sstevel@tonic-gate
132*0Sstevel@tonic-gate /*
133*0Sstevel@tonic-gate * steal the least recently used context slot.
134*0Sstevel@tonic-gate */
135*0Sstevel@tonic-gate static int
zulu_hat_steal_ctx()136*0Sstevel@tonic-gate zulu_hat_steal_ctx()
137*0Sstevel@tonic-gate {
138*0Sstevel@tonic-gate int ctx;
139*0Sstevel@tonic-gate hrtime_t delta = INT64_MAX;
140*0Sstevel@tonic-gate struct zulu_hat *zhat_oldest = NULL;
141*0Sstevel@tonic-gate
142*0Sstevel@tonic-gate ASSERT(mutex_owned(&zulu_ctx_lock));
143*0Sstevel@tonic-gate
144*0Sstevel@tonic-gate for (ctx = 0; ctx < ZULU_HAT_MAX_CTX; ctx++) {
145*0Sstevel@tonic-gate struct zulu_hat *zhat = ZULU_CTX_GET_HAT(ctx);
146*0Sstevel@tonic-gate
147*0Sstevel@tonic-gate /*
148*0Sstevel@tonic-gate * we shouldn't be here unless all slots are occupied
149*0Sstevel@tonic-gate */
150*0Sstevel@tonic-gate ASSERT(zhat != NULL);
151*0Sstevel@tonic-gate
152*0Sstevel@tonic-gate TNF_PROBE_3(steal_ctx_loop, "zulu_hat", /* CSTYLED */,
153*0Sstevel@tonic-gate tnf_int, ctx, ctx,
154*0Sstevel@tonic-gate tnf_long, last_used, zhat->last_used,
155*0Sstevel@tonic-gate tnf_long, oldest, delta);
156*0Sstevel@tonic-gate
157*0Sstevel@tonic-gate if (zhat->last_used < delta) {
158*0Sstevel@tonic-gate zhat_oldest = zhat;
159*0Sstevel@tonic-gate delta = zhat->last_used;
160*0Sstevel@tonic-gate }
161*0Sstevel@tonic-gate }
162*0Sstevel@tonic-gate
163*0Sstevel@tonic-gate ASSERT(zhat_oldest != NULL);
164*0Sstevel@tonic-gate
165*0Sstevel@tonic-gate mutex_enter(&zhat_oldest->lock);
166*0Sstevel@tonic-gate
167*0Sstevel@tonic-gate /* Nobody should have the tsb lock bit set here */
168*0Sstevel@tonic-gate ASSERT(((uint64_t)zulu_ctx_tab[zhat_oldest->zulu_ctx] & ZULU_CTX_LOCK)
169*0Sstevel@tonic-gate == 0);
170*0Sstevel@tonic-gate
171*0Sstevel@tonic-gate ctx = zhat_oldest->zulu_ctx;
172*0Sstevel@tonic-gate zhat_oldest->zulu_ctx = -1;
173*0Sstevel@tonic-gate
174*0Sstevel@tonic-gate ZULU_CTX_SET_HAT(ctx, NULL);
175*0Sstevel@tonic-gate
176*0Sstevel@tonic-gate zulu_hat_demap_ctx(zhat_oldest->zdev, ctx);
177*0Sstevel@tonic-gate
178*0Sstevel@tonic-gate mutex_exit(&zhat_oldest->lock);
179*0Sstevel@tonic-gate
180*0Sstevel@tonic-gate TNF_PROBE_1(zulu_hat_steal_ctx, "zulu_hat", /* CSTYLED */,
181*0Sstevel@tonic-gate tnf_int, ctx, ctx);
182*0Sstevel@tonic-gate
183*0Sstevel@tonic-gate return (ctx);
184*0Sstevel@tonic-gate }
185*0Sstevel@tonic-gate
186*0Sstevel@tonic-gate /*
187*0Sstevel@tonic-gate * find a slot in the context table for a zulu_hat
188*0Sstevel@tonic-gate */
189*0Sstevel@tonic-gate static void
zulu_hat_ctx_alloc(struct zulu_hat * zhat)190*0Sstevel@tonic-gate zulu_hat_ctx_alloc(struct zulu_hat *zhat)
191*0Sstevel@tonic-gate {
192*0Sstevel@tonic-gate int ctx;
193*0Sstevel@tonic-gate
194*0Sstevel@tonic-gate mutex_enter(&zulu_ctx_lock);
195*0Sstevel@tonic-gate
196*0Sstevel@tonic-gate for (ctx = zulu_ctx_search_start; ctx < ZULU_HAT_MAX_CTX; ctx++) {
197*0Sstevel@tonic-gate if (ZULU_CTX_IS_FREE(ctx)) {
198*0Sstevel@tonic-gate zulu_ctx_search_start = ctx + 1;
199*0Sstevel@tonic-gate break;
200*0Sstevel@tonic-gate }
201*0Sstevel@tonic-gate }
202*0Sstevel@tonic-gate
203*0Sstevel@tonic-gate if (ctx == ZULU_HAT_MAX_CTX) {
204*0Sstevel@tonic-gate /* table is full need to steal an entry */
205*0Sstevel@tonic-gate zulu_ctx_search_start = ZULU_HAT_MAX_CTX;
206*0Sstevel@tonic-gate ctx = zulu_hat_steal_ctx();
207*0Sstevel@tonic-gate }
208*0Sstevel@tonic-gate
209*0Sstevel@tonic-gate mutex_enter(&zhat->lock);
210*0Sstevel@tonic-gate
211*0Sstevel@tonic-gate ZULU_CTX_SET_HAT(ctx, zhat);
212*0Sstevel@tonic-gate zhat->zulu_ctx = ctx;
213*0Sstevel@tonic-gate
214*0Sstevel@tonic-gate mutex_exit(&zhat->lock);
215*0Sstevel@tonic-gate
216*0Sstevel@tonic-gate mutex_exit(&zulu_ctx_lock);
217*0Sstevel@tonic-gate
218*0Sstevel@tonic-gate TNF_PROBE_2(zulu_hat_ctx_alloc, "zulu_hat", /* CSTYLED */,
219*0Sstevel@tonic-gate tnf_opaque, zhat, zhat, tnf_int, ctx, ctx);
220*0Sstevel@tonic-gate }
221*0Sstevel@tonic-gate
222*0Sstevel@tonic-gate /*
223*0Sstevel@tonic-gate * zulu_hat_validate_ctx: Called before the graphics context associated
224*0Sstevel@tonic-gate * with a given zulu hat becomes the current zulu graphics context.
225*0Sstevel@tonic-gate * Make sure that the hat has a slot in zulu_ctx_tab.
226*0Sstevel@tonic-gate */
227*0Sstevel@tonic-gate void
zulu_hat_validate_ctx(struct zulu_hat * zhat)228*0Sstevel@tonic-gate zulu_hat_validate_ctx(struct zulu_hat *zhat)
229*0Sstevel@tonic-gate {
230*0Sstevel@tonic-gate if (zhat->zulu_ctx < 0) {
231*0Sstevel@tonic-gate zulu_hat_ctx_alloc(zhat);
232*0Sstevel@tonic-gate }
233*0Sstevel@tonic-gate zhat->last_used = gethrtime();
234*0Sstevel@tonic-gate }
235*0Sstevel@tonic-gate
236*0Sstevel@tonic-gate
237*0Sstevel@tonic-gate static void
zulu_hat_ctx_free(struct zulu_hat * zhat)238*0Sstevel@tonic-gate zulu_hat_ctx_free(struct zulu_hat *zhat)
239*0Sstevel@tonic-gate {
240*0Sstevel@tonic-gate TNF_PROBE_1(zulu_hat_ctx_free, "zulu_hat", /* CSTYLED */,
241*0Sstevel@tonic-gate tnf_int, ctx, zhat->zulu_ctx);
242*0Sstevel@tonic-gate
243*0Sstevel@tonic-gate mutex_enter(&zulu_ctx_lock);
244*0Sstevel@tonic-gate
245*0Sstevel@tonic-gate mutex_enter(&zhat->lock);
246*0Sstevel@tonic-gate if (zhat->zulu_ctx >= 0) {
247*0Sstevel@tonic-gate ZULU_CTX_SET_HAT(zhat->zulu_ctx, NULL);
248*0Sstevel@tonic-gate
249*0Sstevel@tonic-gate if (zulu_ctx_search_start > zhat->zulu_ctx) {
250*0Sstevel@tonic-gate zulu_ctx_search_start = zhat->zulu_ctx;
251*0Sstevel@tonic-gate }
252*0Sstevel@tonic-gate }
253*0Sstevel@tonic-gate mutex_exit(&zhat->lock);
254*0Sstevel@tonic-gate mutex_exit(&zulu_ctx_lock);
255*0Sstevel@tonic-gate }
256*0Sstevel@tonic-gate
257*0Sstevel@tonic-gate /*
258*0Sstevel@tonic-gate * Lock the zulu tsb for a given zulu_hat.
259*0Sstevel@tonic-gate *
260*0Sstevel@tonic-gate * We're just protecting against the TLB trap handler here. Other operations
261*0Sstevel@tonic-gate * on the zulu_hat require entering the zhat's lock.
262*0Sstevel@tonic-gate */
263*0Sstevel@tonic-gate static void
zulu_ctx_tsb_lock_enter(struct zulu_hat * zhat)264*0Sstevel@tonic-gate zulu_ctx_tsb_lock_enter(struct zulu_hat *zhat)
265*0Sstevel@tonic-gate {
266*0Sstevel@tonic-gate uint64_t lck;
267*0Sstevel@tonic-gate uint64_t *plck;
268*0Sstevel@tonic-gate
269*0Sstevel@tonic-gate ASSERT(mutex_owned(&zhat->lock));
270*0Sstevel@tonic-gate
271*0Sstevel@tonic-gate if (zhat->zulu_ctx < 0) {
272*0Sstevel@tonic-gate return;
273*0Sstevel@tonic-gate }
274*0Sstevel@tonic-gate plck = (uint64_t *)&zulu_ctx_tab[zhat->zulu_ctx];
275*0Sstevel@tonic-gate
276*0Sstevel@tonic-gate for (; ; ) {
277*0Sstevel@tonic-gate lck = *plck;
278*0Sstevel@tonic-gate if (!(lck & ZULU_CTX_LOCK)) {
279*0Sstevel@tonic-gate uint64_t old_lck, new_lck;
280*0Sstevel@tonic-gate
281*0Sstevel@tonic-gate new_lck = lck | ZULU_CTX_LOCK;
282*0Sstevel@tonic-gate
283*0Sstevel@tonic-gate old_lck = cas64(plck, lck, new_lck);
284*0Sstevel@tonic-gate
285*0Sstevel@tonic-gate if (old_lck == lck) {
286*0Sstevel@tonic-gate /*
287*0Sstevel@tonic-gate * success
288*0Sstevel@tonic-gate */
289*0Sstevel@tonic-gate break;
290*0Sstevel@tonic-gate }
291*0Sstevel@tonic-gate }
292*0Sstevel@tonic-gate }
293*0Sstevel@tonic-gate }
294*0Sstevel@tonic-gate
295*0Sstevel@tonic-gate static void
zulu_ctx_tsb_lock_exit(struct zulu_hat * zhat)296*0Sstevel@tonic-gate zulu_ctx_tsb_lock_exit(struct zulu_hat *zhat)
297*0Sstevel@tonic-gate {
298*0Sstevel@tonic-gate uint64_t lck;
299*0Sstevel@tonic-gate int zulu_ctx = zhat->zulu_ctx;
300*0Sstevel@tonic-gate
301*0Sstevel@tonic-gate if (zulu_ctx < 0) {
302*0Sstevel@tonic-gate return;
303*0Sstevel@tonic-gate }
304*0Sstevel@tonic-gate lck = (uint64_t)zulu_ctx_tab[zulu_ctx];
305*0Sstevel@tonic-gate ASSERT(lck & ZULU_CTX_LOCK);
306*0Sstevel@tonic-gate lck &= ~ZULU_CTX_LOCK;
307*0Sstevel@tonic-gate zulu_ctx_tab[zulu_ctx] = (struct zulu_hat *)lck;
308*0Sstevel@tonic-gate }
309*0Sstevel@tonic-gate
310*0Sstevel@tonic-gate /*
311*0Sstevel@tonic-gate * Each zulu hat has a "shadow tree" which is a table of 4MB address regions
312*0Sstevel@tonic-gate * for which the zhat has mappings.
313*0Sstevel@tonic-gate *
314*0Sstevel@tonic-gate * This table is maintained in an avl tree.
315*0Sstevel@tonic-gate * Nodes in the tree are called shadow blocks (or sblks)
316*0Sstevel@tonic-gate *
317*0Sstevel@tonic-gate * This data structure allows unload operations by (address, range) to be
318*0Sstevel@tonic-gate * much more efficent.
319*0Sstevel@tonic-gate *
320*0Sstevel@tonic-gate * We get called a lot for address ranges that have never been supplied
321*0Sstevel@tonic-gate * to zulu.
322*0Sstevel@tonic-gate */
323*0Sstevel@tonic-gate
324*0Sstevel@tonic-gate /*
325*0Sstevel@tonic-gate * compare the base address of two nodes in the shadow tree
326*0Sstevel@tonic-gate */
327*0Sstevel@tonic-gate static int
zulu_shadow_tree_compare(const void * a,const void * b)328*0Sstevel@tonic-gate zulu_shadow_tree_compare(const void *a, const void *b)
329*0Sstevel@tonic-gate {
330*0Sstevel@tonic-gate struct zulu_shadow_blk *zba = (struct zulu_shadow_blk *)a;
331*0Sstevel@tonic-gate struct zulu_shadow_blk *zbb = (struct zulu_shadow_blk *)b;
332*0Sstevel@tonic-gate uint64_t addr_a = zba->ivaddr;
333*0Sstevel@tonic-gate uint64_t addr_b = zbb->ivaddr;
334*0Sstevel@tonic-gate
335*0Sstevel@tonic-gate TNF_PROBE_2(zulu_shadow_tree_compare, "zulu_shadow_tree", /* CSTYLED */,
336*0Sstevel@tonic-gate tnf_opaque, addr_a, addr_a, tnf_opaque, addr_b, addr_b);
337*0Sstevel@tonic-gate
338*0Sstevel@tonic-gate if (addr_a < addr_b) {
339*0Sstevel@tonic-gate return (-1);
340*0Sstevel@tonic-gate } else if (addr_a > addr_b) {
341*0Sstevel@tonic-gate return (1);
342*0Sstevel@tonic-gate } else {
343*0Sstevel@tonic-gate return (0);
344*0Sstevel@tonic-gate }
345*0Sstevel@tonic-gate }
346*0Sstevel@tonic-gate
347*0Sstevel@tonic-gate /*
348*0Sstevel@tonic-gate * lookup the entry in the shadow tree for a given virtual address
349*0Sstevel@tonic-gate */
350*0Sstevel@tonic-gate static struct zulu_shadow_blk *
zulu_shadow_tree_lookup(struct zulu_hat * zhat,uint64_t ivaddr,avl_index_t * where)351*0Sstevel@tonic-gate zulu_shadow_tree_lookup(struct zulu_hat *zhat, uint64_t ivaddr,
352*0Sstevel@tonic-gate avl_index_t *where)
353*0Sstevel@tonic-gate {
354*0Sstevel@tonic-gate struct zulu_shadow_blk proto;
355*0Sstevel@tonic-gate struct zulu_shadow_blk *sblk;
356*0Sstevel@tonic-gate
357*0Sstevel@tonic-gate proto.ivaddr = ivaddr & ZULU_SHADOW_BLK_MASK;
358*0Sstevel@tonic-gate
359*0Sstevel@tonic-gate /*
360*0Sstevel@tonic-gate * pages typically fault in in order so we cache the last shadow
361*0Sstevel@tonic-gate * block that was referenced so we usually get to reduce calls to
362*0Sstevel@tonic-gate * avl_find.
363*0Sstevel@tonic-gate */
364*0Sstevel@tonic-gate if ((zhat->sblk_last != NULL) &&
365*0Sstevel@tonic-gate (proto.ivaddr == zhat->sblk_last->ivaddr)) {
366*0Sstevel@tonic-gate sblk = zhat->sblk_last;
367*0Sstevel@tonic-gate } else {
368*0Sstevel@tonic-gate sblk = (struct zulu_shadow_blk *)avl_find(&zhat->shadow_tree,
369*0Sstevel@tonic-gate &proto, where);
370*0Sstevel@tonic-gate zhat->sblk_last = sblk;
371*0Sstevel@tonic-gate }
372*0Sstevel@tonic-gate
373*0Sstevel@tonic-gate TNF_PROBE_2(zulu_shadow_tree_lookup, "zulu_shadow_tree", /* CSTYLED */,
374*0Sstevel@tonic-gate tnf_opaque, ivaddr, proto.ivaddr,
375*0Sstevel@tonic-gate tnf_opaque, where, where ? *where : ~0);
376*0Sstevel@tonic-gate
377*0Sstevel@tonic-gate return (sblk);
378*0Sstevel@tonic-gate }
379*0Sstevel@tonic-gate
380*0Sstevel@tonic-gate /*
381*0Sstevel@tonic-gate * insert a sblk into the shadow tree for a given zblk.
382*0Sstevel@tonic-gate * If a sblk already exists, just increment it's refcount.
383*0Sstevel@tonic-gate */
384*0Sstevel@tonic-gate static void
zulu_shadow_tree_insert(struct zulu_hat * zhat,struct zulu_hat_blk * zblk)385*0Sstevel@tonic-gate zulu_shadow_tree_insert(struct zulu_hat *zhat, struct zulu_hat_blk *zblk)
386*0Sstevel@tonic-gate {
387*0Sstevel@tonic-gate avl_index_t where;
388*0Sstevel@tonic-gate struct zulu_shadow_blk *sblk = NULL;
389*0Sstevel@tonic-gate uint64_t ivaddr;
390*0Sstevel@tonic-gate uint64_t end;
391*0Sstevel@tonic-gate
392*0Sstevel@tonic-gate ivaddr = zblk->zulu_hat_blk_vaddr & ZULU_SHADOW_BLK_MASK;
393*0Sstevel@tonic-gate
394*0Sstevel@tonic-gate end = zblk->zulu_hat_blk_vaddr + ZULU_HAT_PGSZ(zblk->zulu_hat_blk_size);
395*0Sstevel@tonic-gate
396*0Sstevel@tonic-gate sblk = zulu_shadow_tree_lookup(zhat, ivaddr, &where);
397*0Sstevel@tonic-gate if (sblk != NULL) {
398*0Sstevel@tonic-gate sblk->ref_count++;
399*0Sstevel@tonic-gate
400*0Sstevel@tonic-gate end = zblk->zulu_hat_blk_vaddr +
401*0Sstevel@tonic-gate ZULU_HAT_PGSZ(zblk->zulu_hat_blk_size);
402*0Sstevel@tonic-gate if (zblk->zulu_hat_blk_vaddr < sblk->min_addr) {
403*0Sstevel@tonic-gate sblk->min_addr = zblk->zulu_hat_blk_vaddr;
404*0Sstevel@tonic-gate }
405*0Sstevel@tonic-gate /*
406*0Sstevel@tonic-gate * a blk can set both the minimum and maximum when it
407*0Sstevel@tonic-gate * is the first zblk added to a previously emptied sblk
408*0Sstevel@tonic-gate */
409*0Sstevel@tonic-gate if (end > sblk->max_addr) {
410*0Sstevel@tonic-gate sblk->max_addr = end;
411*0Sstevel@tonic-gate }
412*0Sstevel@tonic-gate } else {
413*0Sstevel@tonic-gate sblk = kmem_zalloc(sizeof (*sblk), KM_SLEEP);
414*0Sstevel@tonic-gate sblk->ref_count = 1;
415*0Sstevel@tonic-gate sblk->ivaddr = ivaddr;
416*0Sstevel@tonic-gate sblk->min_addr = zblk->zulu_hat_blk_vaddr;
417*0Sstevel@tonic-gate sblk->max_addr = end;
418*0Sstevel@tonic-gate zhat->sblk_last = sblk;
419*0Sstevel@tonic-gate
420*0Sstevel@tonic-gate avl_insert(&zhat->shadow_tree, sblk, where);
421*0Sstevel@tonic-gate }
422*0Sstevel@tonic-gate zblk->zulu_shadow_blk = sblk;
423*0Sstevel@tonic-gate TNF_PROBE_2(zulu_shadow_tree_insert, "zulu_shadow_tree", /* CSTYLED */,
424*0Sstevel@tonic-gate tnf_opaque, vaddr, ivaddr,
425*0Sstevel@tonic-gate tnf_opaque, ref_count, sblk->ref_count);
426*0Sstevel@tonic-gate }
427*0Sstevel@tonic-gate
428*0Sstevel@tonic-gate /*
429*0Sstevel@tonic-gate * decrement the ref_count for the sblk that corresponds to a given zblk.
430*0Sstevel@tonic-gate * When the ref_count goes to zero remove the sblk from the tree and free it.
431*0Sstevel@tonic-gate */
432*0Sstevel@tonic-gate
433*0Sstevel@tonic-gate static void
zulu_shadow_tree_delete(struct zulu_hat * zhat,struct zulu_hat_blk * zblk)434*0Sstevel@tonic-gate zulu_shadow_tree_delete(struct zulu_hat *zhat, struct zulu_hat_blk *zblk)
435*0Sstevel@tonic-gate {
436*0Sstevel@tonic-gate struct zulu_shadow_blk *sblk;
437*0Sstevel@tonic-gate
438*0Sstevel@tonic-gate ASSERT(zblk->zulu_shadow_blk != NULL);
439*0Sstevel@tonic-gate
440*0Sstevel@tonic-gate sblk = zblk->zulu_shadow_blk;
441*0Sstevel@tonic-gate
442*0Sstevel@tonic-gate TNF_PROBE_2(zulu_shadow_tree_delete, "zulu_shadow_tree", /* CSTYLED */,
443*0Sstevel@tonic-gate tnf_opaque, vaddr, sblk->ivaddr,
444*0Sstevel@tonic-gate tnf_opaque, ref_count, sblk->ref_count-1);
445*0Sstevel@tonic-gate
446*0Sstevel@tonic-gate if (--sblk->ref_count == 0) {
447*0Sstevel@tonic-gate if (zhat->sblk_last == sblk) {
448*0Sstevel@tonic-gate zhat->sblk_last = NULL;
449*0Sstevel@tonic-gate }
450*0Sstevel@tonic-gate sblk->min_addr = sblk->ivaddr + ZULU_SHADOW_BLK_RANGE;
451*0Sstevel@tonic-gate sblk->max_addr = sblk->ivaddr;
452*0Sstevel@tonic-gate } else {
453*0Sstevel@tonic-gate /*
454*0Sstevel@tonic-gate * Update the high and low water marks for this sblk.
455*0Sstevel@tonic-gate * These are estimates, because we don't know if the previous
456*0Sstevel@tonic-gate * or next region are actually occupied, but we can tell
457*0Sstevel@tonic-gate * whether the previous values have become invalid.
458*0Sstevel@tonic-gate *
459*0Sstevel@tonic-gate * In the most often applied case a segment is being
460*0Sstevel@tonic-gate * unloaded, and the min_addr will be kept up to date as
461*0Sstevel@tonic-gate * the zblks are deleted in order.
462*0Sstevel@tonic-gate */
463*0Sstevel@tonic-gate uint64_t end = zblk->zulu_hat_blk_vaddr +
464*0Sstevel@tonic-gate ZULU_HAT_PGSZ(zblk->zulu_hat_blk_size);
465*0Sstevel@tonic-gate
466*0Sstevel@tonic-gate if (zblk->zulu_hat_blk_vaddr == sblk->min_addr) {
467*0Sstevel@tonic-gate sblk->min_addr = end;
468*0Sstevel@tonic-gate }
469*0Sstevel@tonic-gate if (end == sblk->max_addr) {
470*0Sstevel@tonic-gate sblk->max_addr = zblk->zulu_hat_blk_vaddr;
471*0Sstevel@tonic-gate }
472*0Sstevel@tonic-gate }
473*0Sstevel@tonic-gate
474*0Sstevel@tonic-gate zblk->zulu_shadow_blk = NULL;
475*0Sstevel@tonic-gate }
476*0Sstevel@tonic-gate
477*0Sstevel@tonic-gate static void
zulu_shadow_tree_destroy(struct zulu_hat * zhat)478*0Sstevel@tonic-gate zulu_shadow_tree_destroy(struct zulu_hat *zhat)
479*0Sstevel@tonic-gate {
480*0Sstevel@tonic-gate struct zulu_shadow_blk *sblk;
481*0Sstevel@tonic-gate void *cookie = NULL;
482*0Sstevel@tonic-gate
483*0Sstevel@tonic-gate while ((sblk = (struct zulu_shadow_blk *)avl_destroy_nodes(
484*0Sstevel@tonic-gate &zhat->shadow_tree, &cookie)) != NULL) {
485*0Sstevel@tonic-gate TNF_PROBE_2(shadow_tree_destroy, "zulu_hat", /* CSTYLED */,
486*0Sstevel@tonic-gate tnf_opaque, vaddr, sblk->ivaddr,
487*0Sstevel@tonic-gate tnf_opaque, ref_count, sblk->ref_count);
488*0Sstevel@tonic-gate kmem_free(sblk, sizeof (*sblk));
489*0Sstevel@tonic-gate }
490*0Sstevel@tonic-gate avl_destroy(&zhat->shadow_tree);
491*0Sstevel@tonic-gate }
492*0Sstevel@tonic-gate
493*0Sstevel@tonic-gate /*
494*0Sstevel@tonic-gate * zulu_hat_insert_map:
495*0Sstevel@tonic-gate *
496*0Sstevel@tonic-gate * Add a zulu_hat_blk to the a zhat's mappings list.
497*0Sstevel@tonic-gate *
498*0Sstevel@tonic-gate * Several data stuctures are used
499*0Sstevel@tonic-gate * tsb: for simple fast lookups by the trap handler
500*0Sstevel@tonic-gate * hash table: for efficent lookups by address, range
501*0Sstevel@tonic-gate * An shadow tree of 4MB ranges with mappings for unloading big regions.
502*0Sstevel@tonic-gate */
503*0Sstevel@tonic-gate static void
zulu_hat_insert_map(struct zulu_hat * zhat,struct zulu_hat_blk * zblk)504*0Sstevel@tonic-gate zulu_hat_insert_map(struct zulu_hat *zhat, struct zulu_hat_blk *zblk)
505*0Sstevel@tonic-gate {
506*0Sstevel@tonic-gate int tsb_hash;
507*0Sstevel@tonic-gate
508*0Sstevel@tonic-gate tsb_hash = ZULU_TSB_HASH(zblk->zulu_hat_blk_vaddr,
509*0Sstevel@tonic-gate zblk->zulu_hat_blk_size, zhat->zulu_tsb_size);
510*0Sstevel@tonic-gate
511*0Sstevel@tonic-gate TNF_PROBE_3(zulu_hat_insert_map, "zulu_hat", /* CSTYLED */,
512*0Sstevel@tonic-gate tnf_opaque, zblkp, zblk,
513*0Sstevel@tonic-gate tnf_opaque, vaddr, zblk->zulu_hat_blk_vaddr,
514*0Sstevel@tonic-gate tnf_opaque, hash, tsb_hash);
515*0Sstevel@tonic-gate
516*0Sstevel@tonic-gate ASSERT(tsb_hash < zhat->zulu_tsb_size);
517*0Sstevel@tonic-gate
518*0Sstevel@tonic-gate zulu_shadow_tree_insert(zhat, zblk);
519*0Sstevel@tonic-gate
520*0Sstevel@tonic-gate /*
521*0Sstevel@tonic-gate * The hash table is an array of buckets. Each bucket is the
522*0Sstevel@tonic-gate * head of a linked list of mappings who's address hashess to the bucket
523*0Sstevel@tonic-gate * New entries go to the head of the list.
524*0Sstevel@tonic-gate */
525*0Sstevel@tonic-gate zblk->zulu_hash_prev = NULL;
526*0Sstevel@tonic-gate zblk->zulu_hash_next = ZULU_MAP_HASH_HEAD(zhat,
527*0Sstevel@tonic-gate zblk->zulu_hat_blk_vaddr, zblk->zulu_hat_blk_size);
528*0Sstevel@tonic-gate if (zblk->zulu_hash_next) {
529*0Sstevel@tonic-gate zblk->zulu_hash_next->zulu_hash_prev = zblk;
530*0Sstevel@tonic-gate }
531*0Sstevel@tonic-gate ZULU_MAP_HASH_HEAD(zhat, zblk->zulu_hat_blk_vaddr,
532*0Sstevel@tonic-gate zblk->zulu_hat_blk_size) = zblk;
533*0Sstevel@tonic-gate
534*0Sstevel@tonic-gate zulu_ctx_tsb_lock_enter(zhat);
535*0Sstevel@tonic-gate zhat->zulu_tsb[tsb_hash] = zblk->zulu_hat_blk_tte;
536*0Sstevel@tonic-gate zulu_ctx_tsb_lock_exit(zhat);
537*0Sstevel@tonic-gate }
538*0Sstevel@tonic-gate
539*0Sstevel@tonic-gate /*
540*0Sstevel@tonic-gate * remove a block from a zhat
541*0Sstevel@tonic-gate */
542*0Sstevel@tonic-gate static void
zulu_hat_remove_map(struct zulu_hat * zhat,struct zulu_hat_blk * zblk)543*0Sstevel@tonic-gate zulu_hat_remove_map(struct zulu_hat *zhat, struct zulu_hat_blk *zblk)
544*0Sstevel@tonic-gate {
545*0Sstevel@tonic-gate int tsb_hash = ZULU_TSB_HASH(zblk->zulu_hat_blk_vaddr,
546*0Sstevel@tonic-gate zblk->zulu_hat_blk_size, zhat->zulu_tsb_size);
547*0Sstevel@tonic-gate
548*0Sstevel@tonic-gate TNF_PROBE_2(zulu_hat_remove_map, "zulu_hat", /* CSTYLED */,
549*0Sstevel@tonic-gate tnf_opaque, vaddr, zblk->zulu_hat_blk_vaddr,
550*0Sstevel@tonic-gate tnf_opaque, hash, tsb_hash);
551*0Sstevel@tonic-gate
552*0Sstevel@tonic-gate ASSERT(tsb_hash < zhat->zulu_tsb_size);
553*0Sstevel@tonic-gate ASSERT(mutex_owned(&zhat->lock));
554*0Sstevel@tonic-gate
555*0Sstevel@tonic-gate zulu_shadow_tree_delete(zhat, zblk);
556*0Sstevel@tonic-gate
557*0Sstevel@tonic-gate /*
558*0Sstevel@tonic-gate * first remove zblk from hash table
559*0Sstevel@tonic-gate */
560*0Sstevel@tonic-gate if (zblk->zulu_hash_prev) {
561*0Sstevel@tonic-gate zblk->zulu_hash_prev->zulu_hash_next = zblk->zulu_hash_next;
562*0Sstevel@tonic-gate } else {
563*0Sstevel@tonic-gate ZULU_MAP_HASH_HEAD(zhat, zblk->zulu_hat_blk_vaddr,
564*0Sstevel@tonic-gate zblk->zulu_hat_blk_size) = NULL;
565*0Sstevel@tonic-gate }
566*0Sstevel@tonic-gate if (zblk->zulu_hash_next) {
567*0Sstevel@tonic-gate zblk->zulu_hash_next->zulu_hash_prev = zblk->zulu_hash_prev;
568*0Sstevel@tonic-gate }
569*0Sstevel@tonic-gate zblk->zulu_hash_next = NULL;
570*0Sstevel@tonic-gate zblk->zulu_hash_prev = NULL;
571*0Sstevel@tonic-gate
572*0Sstevel@tonic-gate /*
573*0Sstevel@tonic-gate * then remove the tsb entry
574*0Sstevel@tonic-gate */
575*0Sstevel@tonic-gate zulu_ctx_tsb_lock_enter(zhat);
576*0Sstevel@tonic-gate if (zhat->zulu_tsb[tsb_hash].un.zulu_tte_addr ==
577*0Sstevel@tonic-gate zblk->zulu_hat_blk_vaddr) {
578*0Sstevel@tonic-gate zhat->zulu_tsb[tsb_hash].zulu_tte_valid = 0;
579*0Sstevel@tonic-gate }
580*0Sstevel@tonic-gate zulu_ctx_tsb_lock_exit(zhat);
581*0Sstevel@tonic-gate }
582*0Sstevel@tonic-gate
583*0Sstevel@tonic-gate /*
584*0Sstevel@tonic-gate * look for a mapping to a given vaddr and page size
585*0Sstevel@tonic-gate */
586*0Sstevel@tonic-gate static struct zulu_hat_blk *
zulu_lookup_map_bysize(struct zulu_hat * zhat,caddr_t vaddr,int page_sz)587*0Sstevel@tonic-gate zulu_lookup_map_bysize(struct zulu_hat *zhat, caddr_t vaddr, int page_sz)
588*0Sstevel@tonic-gate {
589*0Sstevel@tonic-gate struct zulu_hat_blk *zblkp;
590*0Sstevel@tonic-gate uint64_t ivaddr = (uint64_t)vaddr;
591*0Sstevel@tonic-gate int blks_checked = 0;
592*0Sstevel@tonic-gate
593*0Sstevel@tonic-gate ASSERT(mutex_owned(&zhat->lock));
594*0Sstevel@tonic-gate
595*0Sstevel@tonic-gate for (zblkp = ZULU_MAP_HASH_HEAD(zhat, ivaddr, page_sz); zblkp != NULL;
596*0Sstevel@tonic-gate zblkp = zblkp->zulu_hash_next) {
597*0Sstevel@tonic-gate uint64_t size;
598*0Sstevel@tonic-gate uint64_t iaddr;
599*0Sstevel@tonic-gate
600*0Sstevel@tonic-gate blks_checked++;
601*0Sstevel@tonic-gate
602*0Sstevel@tonic-gate size = ZULU_HAT_PGSZ(zblkp->zulu_hat_blk_size);
603*0Sstevel@tonic-gate iaddr = ZULU_VADDR((uint64_t)zblkp->zulu_hat_blk_vaddr);
604*0Sstevel@tonic-gate
605*0Sstevel@tonic-gate if (iaddr <= ivaddr && (iaddr + size) > ivaddr) {
606*0Sstevel@tonic-gate int tsb_hash;
607*0Sstevel@tonic-gate
608*0Sstevel@tonic-gate tsb_hash = ZULU_TSB_HASH(zblkp->zulu_hat_blk_vaddr,
609*0Sstevel@tonic-gate zblkp->zulu_hat_blk_size,
610*0Sstevel@tonic-gate zhat->zulu_tsb_size);
611*0Sstevel@tonic-gate ASSERT(tsb_hash < zhat->zulu_tsb_size);
612*0Sstevel@tonic-gate
613*0Sstevel@tonic-gate zulu_ctx_tsb_lock_enter(zhat);
614*0Sstevel@tonic-gate zhat->zulu_tsb[tsb_hash] = zblkp->zulu_hat_blk_tte;
615*0Sstevel@tonic-gate zulu_ctx_tsb_lock_exit(zhat);
616*0Sstevel@tonic-gate break;
617*0Sstevel@tonic-gate }
618*0Sstevel@tonic-gate
619*0Sstevel@tonic-gate }
620*0Sstevel@tonic-gate
621*0Sstevel@tonic-gate TNF_PROBE_3(zulu_hat_lookup_map_bysz, "zulu_hat", /* CSTYLED */,
622*0Sstevel@tonic-gate tnf_opaque, zblkp, zblkp,
623*0Sstevel@tonic-gate tnf_int, blks_checked, blks_checked,
624*0Sstevel@tonic-gate tnf_int, page_sz, page_sz);
625*0Sstevel@tonic-gate
626*0Sstevel@tonic-gate return (zblkp);
627*0Sstevel@tonic-gate }
628*0Sstevel@tonic-gate
629*0Sstevel@tonic-gate /*
630*0Sstevel@tonic-gate * Lookup a zblk for a given virtual address.
631*0Sstevel@tonic-gate */
632*0Sstevel@tonic-gate static struct zulu_hat_blk *
zulu_lookup_map(struct zulu_hat * zhat,caddr_t vaddr)633*0Sstevel@tonic-gate zulu_lookup_map(struct zulu_hat *zhat, caddr_t vaddr)
634*0Sstevel@tonic-gate {
635*0Sstevel@tonic-gate struct zulu_hat_blk *zblkp = NULL;
636*0Sstevel@tonic-gate
637*0Sstevel@tonic-gate /*
638*0Sstevel@tonic-gate * if the hat is using 4M pages, look first for a 4M page
639*0Sstevel@tonic-gate */
640*0Sstevel@tonic-gate if (zhat->map4m) {
641*0Sstevel@tonic-gate zblkp = zulu_lookup_map_bysize(zhat, vaddr, ZULU_TTE4M);
642*0Sstevel@tonic-gate if (zblkp != NULL) {
643*0Sstevel@tonic-gate return (zblkp);
644*0Sstevel@tonic-gate }
645*0Sstevel@tonic-gate }
646*0Sstevel@tonic-gate /*
647*0Sstevel@tonic-gate * Otherwise look for a 8k page
648*0Sstevel@tonic-gate * Note: if base pagesize gets increased to 64K remove this test
649*0Sstevel@tonic-gate */
650*0Sstevel@tonic-gate if (zhat->map8k) {
651*0Sstevel@tonic-gate zblkp = zulu_lookup_map_bysize(zhat, vaddr, ZULU_TTE8K);
652*0Sstevel@tonic-gate if (zblkp != NULL) {
653*0Sstevel@tonic-gate return (zblkp);
654*0Sstevel@tonic-gate }
655*0Sstevel@tonic-gate }
656*0Sstevel@tonic-gate /*
657*0Sstevel@tonic-gate * only if the page isn't found in the sizes that match the zulu mmus
658*0Sstevel@tonic-gate * look for the inefficient 64K or 512K page sizes
659*0Sstevel@tonic-gate */
660*0Sstevel@tonic-gate if (zhat->map64k) {
661*0Sstevel@tonic-gate zblkp = zulu_lookup_map_bysize(zhat, vaddr, ZULU_TTE64K);
662*0Sstevel@tonic-gate if (zblkp != NULL) {
663*0Sstevel@tonic-gate return (zblkp);
664*0Sstevel@tonic-gate }
665*0Sstevel@tonic-gate }
666*0Sstevel@tonic-gate if (zhat->map512k) {
667*0Sstevel@tonic-gate zblkp = zulu_lookup_map_bysize(zhat, vaddr, ZULU_TTE512K);
668*0Sstevel@tonic-gate }
669*0Sstevel@tonic-gate
670*0Sstevel@tonic-gate return (zblkp);
671*0Sstevel@tonic-gate }
672*0Sstevel@tonic-gate
673*0Sstevel@tonic-gate /*
674*0Sstevel@tonic-gate * zulu_hat_load: Load translation for given vaddr
675*0Sstevel@tonic-gate */
676*0Sstevel@tonic-gate int
zulu_hat_load(struct zulu_hat * zhat,caddr_t vaddr,enum seg_rw rw,int * ppg_size)677*0Sstevel@tonic-gate zulu_hat_load(struct zulu_hat *zhat, caddr_t vaddr,
678*0Sstevel@tonic-gate enum seg_rw rw, int *ppg_size)
679*0Sstevel@tonic-gate {
680*0Sstevel@tonic-gate faultcode_t as_err;
681*0Sstevel@tonic-gate struct zulu_hat_blk *zblkp;
682*0Sstevel@tonic-gate int rval;
683*0Sstevel@tonic-gate uint64_t flags_pfn;
684*0Sstevel@tonic-gate struct zulu_tte tte;
685*0Sstevel@tonic-gate
686*0Sstevel@tonic-gate TNF_PROBE_2(zulu_hat_load, "zulu_hat", /* CSTYLED */,
687*0Sstevel@tonic-gate tnf_int, zulu_ctx, zhat->zulu_ctx,
688*0Sstevel@tonic-gate tnf_opaque, vaddr, vaddr);
689*0Sstevel@tonic-gate
690*0Sstevel@tonic-gate mutex_enter(&zhat->lock);
691*0Sstevel@tonic-gate ASSERT(zhat->zulu_ctx >= 0);
692*0Sstevel@tonic-gate /*
693*0Sstevel@tonic-gate * lookup in our tsb first
694*0Sstevel@tonic-gate */
695*0Sstevel@tonic-gate zulu_ctx_tsb_lock_enter(zhat);
696*0Sstevel@tonic-gate flags_pfn = zulu_hat_tsb_lookup_tl0(zhat, vaddr);
697*0Sstevel@tonic-gate zulu_ctx_tsb_lock_exit(zhat);
698*0Sstevel@tonic-gate
699*0Sstevel@tonic-gate if (flags_pfn) {
700*0Sstevel@tonic-gate uint64_t *p = (uint64_t *)&tte;
701*0Sstevel@tonic-gate
702*0Sstevel@tonic-gate p++; /* ignore the tag */
703*0Sstevel@tonic-gate *p = flags_pfn; /* load the flags */
704*0Sstevel@tonic-gate
705*0Sstevel@tonic-gate zuluvm_load_tte(zhat, vaddr, flags_pfn, tte.zulu_tte_perm,
706*0Sstevel@tonic-gate tte.zulu_tte_size);
707*0Sstevel@tonic-gate if (ppg_size != NULL) {
708*0Sstevel@tonic-gate *ppg_size = tte.zulu_tte_size;
709*0Sstevel@tonic-gate }
710*0Sstevel@tonic-gate
711*0Sstevel@tonic-gate zulu_tsb_hit++;
712*0Sstevel@tonic-gate mutex_exit(&zhat->lock);
713*0Sstevel@tonic-gate return (0);
714*0Sstevel@tonic-gate }
715*0Sstevel@tonic-gate
716*0Sstevel@tonic-gate zulu_tsb_miss++;
717*0Sstevel@tonic-gate
718*0Sstevel@tonic-gate zblkp = zulu_lookup_map(zhat, vaddr);
719*0Sstevel@tonic-gate if (zblkp) {
720*0Sstevel@tonic-gate tte = zblkp->zulu_hat_blk_tte;
721*0Sstevel@tonic-gate tte.zulu_tte_pfn = ZULU_HAT_ADJ_PFN((&tte), vaddr);
722*0Sstevel@tonic-gate zuluvm_load_tte(zhat, vaddr, tte.zulu_tte_pfn,
723*0Sstevel@tonic-gate tte.zulu_tte_perm, tte.zulu_tte_size);
724*0Sstevel@tonic-gate if (ppg_size != NULL) {
725*0Sstevel@tonic-gate *ppg_size = tte.zulu_tte_size;
726*0Sstevel@tonic-gate }
727*0Sstevel@tonic-gate mutex_exit(&zhat->lock);
728*0Sstevel@tonic-gate return (0);
729*0Sstevel@tonic-gate }
730*0Sstevel@tonic-gate
731*0Sstevel@tonic-gate /*
732*0Sstevel@tonic-gate * Set a flag indicating that we're processing a fault.
733*0Sstevel@tonic-gate * See comments in zulu_hat_unload_region.
734*0Sstevel@tonic-gate */
735*0Sstevel@tonic-gate zhat->in_fault = 1;
736*0Sstevel@tonic-gate mutex_exit(&zhat->lock);
737*0Sstevel@tonic-gate
738*0Sstevel@tonic-gate zulu_as_fault++;
739*0Sstevel@tonic-gate TNF_PROBE_0(calling_as_fault, "zulu_hat", /* CSTYLED */);
740*0Sstevel@tonic-gate
741*0Sstevel@tonic-gate as_err = as_fault((struct hat *)zhat, zhat->zulu_xhat.xhat_as,
742*0Sstevel@tonic-gate (caddr_t)(ZULU_VADDR((uint64_t)vaddr) & PAGEMASK),
743*0Sstevel@tonic-gate PAGESIZE, F_INVAL, rw);
744*0Sstevel@tonic-gate
745*0Sstevel@tonic-gate mutex_enter(&zhat->lock);
746*0Sstevel@tonic-gate zhat->in_fault = 0;
747*0Sstevel@tonic-gate if (ppg_size != NULL) {
748*0Sstevel@tonic-gate /*
749*0Sstevel@tonic-gate * caller wants to know the page size (used by preload)
750*0Sstevel@tonic-gate */
751*0Sstevel@tonic-gate zblkp = zulu_lookup_map(zhat, vaddr);
752*0Sstevel@tonic-gate if (zblkp != NULL) {
753*0Sstevel@tonic-gate *ppg_size = zblkp->zulu_hat_blk_size;
754*0Sstevel@tonic-gate } else {
755*0Sstevel@tonic-gate *ppg_size = -1;
756*0Sstevel@tonic-gate }
757*0Sstevel@tonic-gate }
758*0Sstevel@tonic-gate mutex_exit(&zhat->lock);
759*0Sstevel@tonic-gate
760*0Sstevel@tonic-gate TNF_PROBE_1(as_fault_returned, "zulu_hat", /* CSTYLED */,
761*0Sstevel@tonic-gate tnf_int, as_err, as_err);
762*0Sstevel@tonic-gate
763*0Sstevel@tonic-gate if (as_err != 0) {
764*0Sstevel@tonic-gate printf("as_fault returned %d\n", as_err);
765*0Sstevel@tonic-gate rval = as_err;
766*0Sstevel@tonic-gate } else if (zhat->freed) {
767*0Sstevel@tonic-gate rval = -1;
768*0Sstevel@tonic-gate } else {
769*0Sstevel@tonic-gate rval = 0;
770*0Sstevel@tonic-gate }
771*0Sstevel@tonic-gate
772*0Sstevel@tonic-gate return (rval);
773*0Sstevel@tonic-gate }
774*0Sstevel@tonic-gate
775*0Sstevel@tonic-gate static struct xhat *
zulu_hat_alloc(void * arg)776*0Sstevel@tonic-gate zulu_hat_alloc(void *arg)
777*0Sstevel@tonic-gate {
778*0Sstevel@tonic-gate struct zulu_hat *zhat = kmem_zalloc(sizeof (struct zulu_hat), KM_SLEEP);
779*0Sstevel@tonic-gate
780*0Sstevel@tonic-gate (void) arg;
781*0Sstevel@tonic-gate
782*0Sstevel@tonic-gate zulu_hat_ctx_alloc(zhat);
783*0Sstevel@tonic-gate
784*0Sstevel@tonic-gate mutex_init(&zhat->lock, NULL, MUTEX_DEFAULT, NULL);
785*0Sstevel@tonic-gate
786*0Sstevel@tonic-gate zhat->zulu_tsb = kmem_zalloc(ZULU_TSB_SZ, KM_SLEEP);
787*0Sstevel@tonic-gate zhat->zulu_tsb_size = ZULU_TSB_NUM;
788*0Sstevel@tonic-gate zhat->hash_tbl = kmem_zalloc(ZULU_HASH_TBL_SZ, KM_SLEEP);
789*0Sstevel@tonic-gate avl_create(&zhat->shadow_tree, zulu_shadow_tree_compare,
790*0Sstevel@tonic-gate sizeof (zhat->shadow_tree), ZULU_SHADOW_BLK_LINK_OFFSET);
791*0Sstevel@tonic-gate /*
792*0Sstevel@tonic-gate * The zulu hat has a few opaque data structs embedded in it.
793*0Sstevel@tonic-gate * This tag makes finding the our data easier with a debugger.
794*0Sstevel@tonic-gate */
795*0Sstevel@tonic-gate zhat->magic = 0x42;
796*0Sstevel@tonic-gate
797*0Sstevel@tonic-gate zhat->freed = 0;
798*0Sstevel@tonic-gate TNF_PROBE_1(zulu_hat_alloc, "zulu_hat", /* CSTYLED */,
799*0Sstevel@tonic-gate tnf_int, zulu_ctx, zhat->zulu_ctx);
800*0Sstevel@tonic-gate return ((struct xhat *)zhat);
801*0Sstevel@tonic-gate }
802*0Sstevel@tonic-gate
803*0Sstevel@tonic-gate static void
zulu_hat_free(struct xhat * xhat)804*0Sstevel@tonic-gate zulu_hat_free(struct xhat *xhat)
805*0Sstevel@tonic-gate {
806*0Sstevel@tonic-gate struct zulu_hat *zhat = (struct zulu_hat *)xhat;
807*0Sstevel@tonic-gate
808*0Sstevel@tonic-gate TNF_PROBE_1(zulu_hat_free, "zulu_hat", /* CSTYLED */,
809*0Sstevel@tonic-gate tnf_int, zulu_ctx, zhat->zulu_ctx);
810*0Sstevel@tonic-gate
811*0Sstevel@tonic-gate zulu_shadow_tree_destroy(zhat);
812*0Sstevel@tonic-gate kmem_free(zhat->hash_tbl, ZULU_HASH_TBL_SZ);
813*0Sstevel@tonic-gate kmem_free(zhat->zulu_tsb, ZULU_TSB_SZ);
814*0Sstevel@tonic-gate mutex_destroy(&zhat->lock);
815*0Sstevel@tonic-gate kmem_free(xhat, sizeof (struct zulu_hat));
816*0Sstevel@tonic-gate }
817*0Sstevel@tonic-gate
818*0Sstevel@tonic-gate static void
zulu_hat_free_start(struct xhat * xhat)819*0Sstevel@tonic-gate zulu_hat_free_start(struct xhat *xhat)
820*0Sstevel@tonic-gate {
821*0Sstevel@tonic-gate struct zulu_hat *zhat = (struct zulu_hat *)xhat;
822*0Sstevel@tonic-gate
823*0Sstevel@tonic-gate TNF_PROBE_1(zulu_hat_free_start, "zulu_hat", /* CSTYLED */,
824*0Sstevel@tonic-gate tnf_int, zulu_ctx, zhat->zulu_ctx);
825*0Sstevel@tonic-gate (void) xhat;
826*0Sstevel@tonic-gate }
827*0Sstevel@tonic-gate
828*0Sstevel@tonic-gate /*
829*0Sstevel@tonic-gate * zulu_hat_memload: This is the callback where the vm system gives us our
830*0Sstevel@tonic-gate * translations
831*0Sstevel@tonic-gate */
832*0Sstevel@tonic-gate static void
zulu_do_hat_memload(struct xhat * xhat,caddr_t vaddr,struct page * page,uint_t attr,uint_t flags,int use_pszc)833*0Sstevel@tonic-gate zulu_do_hat_memload(struct xhat *xhat, caddr_t vaddr, struct page *page,
834*0Sstevel@tonic-gate uint_t attr, uint_t flags, int use_pszc)
835*0Sstevel@tonic-gate {
836*0Sstevel@tonic-gate void *blk;
837*0Sstevel@tonic-gate struct zulu_hat *zhat = (struct zulu_hat *)xhat;
838*0Sstevel@tonic-gate struct zulu_hat_blk *zblk;
839*0Sstevel@tonic-gate pfn_t pfn;
840*0Sstevel@tonic-gate
841*0Sstevel@tonic-gate TNF_PROBE_4(zulu_hat_memload, "zulu_hat", /* CSTYLED */,
842*0Sstevel@tonic-gate tnf_int, zulu_ctx, zhat->zulu_ctx,
843*0Sstevel@tonic-gate tnf_opaque, vaddr, vaddr, tnf_opaque, attr, attr,
844*0Sstevel@tonic-gate tnf_opaque, flags, flags);
845*0Sstevel@tonic-gate
846*0Sstevel@tonic-gate /*
847*0Sstevel@tonic-gate * keep track of the highest address that this zhat has had
848*0Sstevel@tonic-gate * a mapping for.
849*0Sstevel@tonic-gate * We use this in unload to avoid searching for regions that
850*0Sstevel@tonic-gate * we've never seen.
851*0Sstevel@tonic-gate *
852*0Sstevel@tonic-gate * This is particularly useful avoiding repeated searches for
853*0Sstevel@tonic-gate * for the process's mappings to the zulu hardware. These mappings
854*0Sstevel@tonic-gate * are explicitly unloaded at each graphics context switch..
855*0Sstevel@tonic-gate *
856*0Sstevel@tonic-gate * This takes advantage of the fact that the device addresses
857*0Sstevel@tonic-gate * are always above than the heap where most DMA data is stored.
858*0Sstevel@tonic-gate */
859*0Sstevel@tonic-gate if (vaddr > zhat->vaddr_max) {
860*0Sstevel@tonic-gate zhat->vaddr_max = vaddr;
861*0Sstevel@tonic-gate }
862*0Sstevel@tonic-gate
863*0Sstevel@tonic-gate pfn = xhat_insert_xhatblk(page, xhat, &blk);
864*0Sstevel@tonic-gate zblk = (struct zulu_hat_blk *)blk;
865*0Sstevel@tonic-gate zblk->zulu_hat_blk_vaddr = (uintptr_t)vaddr;
866*0Sstevel@tonic-gate zblk->zulu_hat_blk_pfn = (uint_t)pfn;
867*0Sstevel@tonic-gate /*
868*0Sstevel@tonic-gate * The perm bit is actually in the tte which gets copied to the TSB
869*0Sstevel@tonic-gate */
870*0Sstevel@tonic-gate zblk->zulu_hat_blk_perm = (attr & PROT_WRITE) ? 1 : 0;
871*0Sstevel@tonic-gate zblk->zulu_hat_blk_size = use_pszc ? page->p_szc : 0;
872*0Sstevel@tonic-gate zblk->zulu_hat_blk_valid = 1;
873*0Sstevel@tonic-gate
874*0Sstevel@tonic-gate switch (zblk->zulu_hat_blk_size) {
875*0Sstevel@tonic-gate case ZULU_TTE8K:
876*0Sstevel@tonic-gate zhat->map8k = 1;
877*0Sstevel@tonic-gate break;
878*0Sstevel@tonic-gate case ZULU_TTE64K:
879*0Sstevel@tonic-gate zhat->map64k = 1;
880*0Sstevel@tonic-gate break;
881*0Sstevel@tonic-gate case ZULU_TTE512K:
882*0Sstevel@tonic-gate zhat->map512k = 1;
883*0Sstevel@tonic-gate break;
884*0Sstevel@tonic-gate case ZULU_TTE4M:
885*0Sstevel@tonic-gate zhat->map4m = 1;
886*0Sstevel@tonic-gate break;
887*0Sstevel@tonic-gate default:
888*0Sstevel@tonic-gate panic("zulu_hat illegal page size\n");
889*0Sstevel@tonic-gate }
890*0Sstevel@tonic-gate
891*0Sstevel@tonic-gate mutex_enter(&zhat->lock);
892*0Sstevel@tonic-gate
893*0Sstevel@tonic-gate zulu_hat_insert_map(zhat, zblk);
894*0Sstevel@tonic-gate if (!zhat->freed) {
895*0Sstevel@tonic-gate zuluvm_load_tte(zhat, vaddr, zblk->zulu_hat_blk_pfn,
896*0Sstevel@tonic-gate zblk->zulu_hat_blk_perm, zblk->zulu_hat_blk_size);
897*0Sstevel@tonic-gate }
898*0Sstevel@tonic-gate zhat->fault_ivaddr_last =
899*0Sstevel@tonic-gate ZULU_VADDR((uint64_t)zblk->zulu_hat_blk_vaddr);
900*0Sstevel@tonic-gate
901*0Sstevel@tonic-gate mutex_exit(&zhat->lock);
902*0Sstevel@tonic-gate }
903*0Sstevel@tonic-gate
904*0Sstevel@tonic-gate static void
zulu_hat_memload(struct xhat * xhat,caddr_t vaddr,struct page * page,uint_t attr,uint_t flags)905*0Sstevel@tonic-gate zulu_hat_memload(struct xhat *xhat, caddr_t vaddr, struct page *page,
906*0Sstevel@tonic-gate uint_t attr, uint_t flags)
907*0Sstevel@tonic-gate {
908*0Sstevel@tonic-gate zulu_do_hat_memload(xhat, vaddr, page, attr, flags, 0);
909*0Sstevel@tonic-gate }
910*0Sstevel@tonic-gate
911*0Sstevel@tonic-gate static void
zulu_hat_devload(struct xhat * xhat,caddr_t vaddr,size_t size,pfn_t pfn,uint_t attr,int flags)912*0Sstevel@tonic-gate zulu_hat_devload(struct xhat *xhat, caddr_t vaddr, size_t size, pfn_t pfn,
913*0Sstevel@tonic-gate uint_t attr, int flags)
914*0Sstevel@tonic-gate {
915*0Sstevel@tonic-gate struct page *pp = page_numtopp_nolock(pfn);
916*0Sstevel@tonic-gate (void) size;
917*0Sstevel@tonic-gate zulu_do_hat_memload(xhat, vaddr, pp, attr, (uint_t)flags, 1);
918*0Sstevel@tonic-gate }
919*0Sstevel@tonic-gate
920*0Sstevel@tonic-gate static void
zulu_hat_memload_array(struct xhat * xhat,caddr_t addr,size_t len,struct page ** gen_pps,uint_t attr,uint_t flags)921*0Sstevel@tonic-gate zulu_hat_memload_array(struct xhat *xhat, caddr_t addr, size_t len,
922*0Sstevel@tonic-gate struct page **gen_pps, uint_t attr, uint_t flags)
923*0Sstevel@tonic-gate {
924*0Sstevel@tonic-gate struct zulu_hat *zhat = (struct zulu_hat *)xhat;
925*0Sstevel@tonic-gate
926*0Sstevel@tonic-gate TNF_PROBE_3(zulu_hat_memload_array, "zulu_hat", /* CSTYLED */,
927*0Sstevel@tonic-gate tnf_int, zulu_ctx, zhat->zulu_ctx,
928*0Sstevel@tonic-gate tnf_opaque, addr, addr,
929*0Sstevel@tonic-gate tnf_opaque, len, len);
930*0Sstevel@tonic-gate
931*0Sstevel@tonic-gate for (; len > 0; len -= ZULU_HAT_PGSZ((*gen_pps)->p_szc),
932*0Sstevel@tonic-gate gen_pps += ZULU_HAT_NUM_PGS((*gen_pps)->p_szc)) {
933*0Sstevel@tonic-gate zulu_do_hat_memload(xhat, addr, *gen_pps, attr, flags, 1);
934*0Sstevel@tonic-gate
935*0Sstevel@tonic-gate addr += ZULU_HAT_PGSZ((*gen_pps)->p_szc);
936*0Sstevel@tonic-gate }
937*0Sstevel@tonic-gate }
938*0Sstevel@tonic-gate
939*0Sstevel@tonic-gate static void
free_zblks(struct zulu_hat_blk * free_list)940*0Sstevel@tonic-gate free_zblks(struct zulu_hat_blk *free_list)
941*0Sstevel@tonic-gate {
942*0Sstevel@tonic-gate struct zulu_hat_blk *zblkp;
943*0Sstevel@tonic-gate struct zulu_hat_blk *next;
944*0Sstevel@tonic-gate
945*0Sstevel@tonic-gate for (zblkp = free_list; zblkp != NULL; zblkp = next) {
946*0Sstevel@tonic-gate next = zblkp->zulu_hash_next;
947*0Sstevel@tonic-gate (void) xhat_delete_xhatblk((struct xhat_hme_blk *)zblkp, 0);
948*0Sstevel@tonic-gate }
949*0Sstevel@tonic-gate }
950*0Sstevel@tonic-gate
951*0Sstevel@tonic-gate static void
add_to_free_list(struct zulu_hat_blk ** pfree_list,struct zulu_hat_blk * zblk)952*0Sstevel@tonic-gate add_to_free_list(struct zulu_hat_blk **pfree_list, struct zulu_hat_blk *zblk)
953*0Sstevel@tonic-gate {
954*0Sstevel@tonic-gate zblk->zulu_hash_next = *pfree_list;
955*0Sstevel@tonic-gate *pfree_list = zblk;
956*0Sstevel@tonic-gate }
957*0Sstevel@tonic-gate
958*0Sstevel@tonic-gate static void
zulu_hat_unload_region(struct zulu_hat * zhat,uint64_t ivaddr,size_t size,struct zulu_shadow_blk * sblk,struct zulu_hat_blk ** pfree_list)959*0Sstevel@tonic-gate zulu_hat_unload_region(struct zulu_hat *zhat, uint64_t ivaddr, size_t size,
960*0Sstevel@tonic-gate struct zulu_shadow_blk *sblk, struct zulu_hat_blk **pfree_list)
961*0Sstevel@tonic-gate {
962*0Sstevel@tonic-gate uint64_t end = ivaddr + size;
963*0Sstevel@tonic-gate int found = 0;
964*0Sstevel@tonic-gate
965*0Sstevel@tonic-gate TNF_PROBE_2(zulu_hat_unload_region, "zulu_hat", /* CSTYLED */,
966*0Sstevel@tonic-gate tnf_opaque, vaddr, ivaddr, tnf_opaque, size, size);
967*0Sstevel@tonic-gate
968*0Sstevel@tonic-gate /*
969*0Sstevel@tonic-gate * check address against the low and highwater marks for mappings
970*0Sstevel@tonic-gate * in this sblk
971*0Sstevel@tonic-gate */
972*0Sstevel@tonic-gate if (ivaddr < sblk->min_addr) {
973*0Sstevel@tonic-gate ivaddr = sblk->min_addr;
974*0Sstevel@tonic-gate TNF_PROBE_1(zulu_hat_unload_skip, "zulu_hat", /* CSTYLED */,
975*0Sstevel@tonic-gate tnf_opaque, ivaddr, ivaddr);
976*0Sstevel@tonic-gate }
977*0Sstevel@tonic-gate if (end > sblk->max_addr) {
978*0Sstevel@tonic-gate end = sblk->max_addr;
979*0Sstevel@tonic-gate TNF_PROBE_1(zulu_hat_unload_reg_skip, "zulu_hat", /* CSTYLED */,
980*0Sstevel@tonic-gate tnf_opaque, end, end);
981*0Sstevel@tonic-gate }
982*0Sstevel@tonic-gate /*
983*0Sstevel@tonic-gate * REMIND: It's not safe to touch the sblk after we enter this loop
984*0Sstevel@tonic-gate * because it may get deleted.
985*0Sstevel@tonic-gate */
986*0Sstevel@tonic-gate
987*0Sstevel@tonic-gate while (ivaddr < end) {
988*0Sstevel@tonic-gate uint64_t iaddr;
989*0Sstevel@tonic-gate size_t pg_sz;
990*0Sstevel@tonic-gate struct zulu_hat_blk *zblkp;
991*0Sstevel@tonic-gate
992*0Sstevel@tonic-gate zblkp = zulu_lookup_map(zhat, (caddr_t)ivaddr);
993*0Sstevel@tonic-gate if (zblkp == NULL) {
994*0Sstevel@tonic-gate ivaddr += PAGESIZE;
995*0Sstevel@tonic-gate continue;
996*0Sstevel@tonic-gate }
997*0Sstevel@tonic-gate
998*0Sstevel@tonic-gate iaddr = ZULU_VADDR((uint64_t)zblkp->zulu_hat_blk_vaddr);
999*0Sstevel@tonic-gate pg_sz = ZULU_HAT_PGSZ(zblkp->zulu_hat_blk_size);
1000*0Sstevel@tonic-gate
1001*0Sstevel@tonic-gate found++;
1002*0Sstevel@tonic-gate
1003*0Sstevel@tonic-gate zulu_hat_remove_map(zhat, zblkp);
1004*0Sstevel@tonic-gate /*
1005*0Sstevel@tonic-gate * skip demap page if as_free has already been entered
1006*0Sstevel@tonic-gate * zuluvm demapped the context already
1007*0Sstevel@tonic-gate */
1008*0Sstevel@tonic-gate if (!zhat->freed) {
1009*0Sstevel@tonic-gate if ((zhat->in_fault) &&
1010*0Sstevel@tonic-gate (iaddr == zhat->fault_ivaddr_last)) {
1011*0Sstevel@tonic-gate /*
1012*0Sstevel@tonic-gate * We're being called from within as_fault to
1013*0Sstevel@tonic-gate * unload the last translation we loaded.
1014*0Sstevel@tonic-gate *
1015*0Sstevel@tonic-gate * This is probably due to watchpoint handling.
1016*0Sstevel@tonic-gate * Delay the demap for a millisecond
1017*0Sstevel@tonic-gate * to allow zulu to make some progress.
1018*0Sstevel@tonic-gate */
1019*0Sstevel@tonic-gate drv_usecwait(1000);
1020*0Sstevel@tonic-gate zhat->fault_ivaddr_last = 0;
1021*0Sstevel@tonic-gate }
1022*0Sstevel@tonic-gate zulu_hat_demap_page(zhat, (caddr_t)iaddr,
1023*0Sstevel@tonic-gate zblkp->zulu_hat_blk_size);
1024*0Sstevel@tonic-gate }
1025*0Sstevel@tonic-gate
1026*0Sstevel@tonic-gate add_to_free_list(pfree_list, zblkp);
1027*0Sstevel@tonic-gate
1028*0Sstevel@tonic-gate if ((iaddr + pg_sz) >= end) {
1029*0Sstevel@tonic-gate break;
1030*0Sstevel@tonic-gate }
1031*0Sstevel@tonic-gate
1032*0Sstevel@tonic-gate ivaddr += pg_sz;
1033*0Sstevel@tonic-gate }
1034*0Sstevel@tonic-gate TNF_PROBE_1(zulu_hat_unload_region_done, "zulu_hat", /* CSTYLED */,
1035*0Sstevel@tonic-gate tnf_opaque, found, found);
1036*0Sstevel@tonic-gate }
1037*0Sstevel@tonic-gate
1038*0Sstevel@tonic-gate static void
zulu_hat_unload(struct xhat * xhat,caddr_t vaddr,size_t size,uint_t flags)1039*0Sstevel@tonic-gate zulu_hat_unload(struct xhat *xhat, caddr_t vaddr, size_t size, uint_t flags)
1040*0Sstevel@tonic-gate {
1041*0Sstevel@tonic-gate struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1042*0Sstevel@tonic-gate uint64_t ivaddr;
1043*0Sstevel@tonic-gate uint64_t end;
1044*0Sstevel@tonic-gate int found = 0;
1045*0Sstevel@tonic-gate struct zulu_hat_blk *free_list = NULL;
1046*0Sstevel@tonic-gate
1047*0Sstevel@tonic-gate (void) flags;
1048*0Sstevel@tonic-gate
1049*0Sstevel@tonic-gate TNF_PROBE_4(zulu_hat_unload, "zulu_hat", /* CSTYLED */,
1050*0Sstevel@tonic-gate tnf_int, zulu_ctx, zhat->zulu_ctx,
1051*0Sstevel@tonic-gate tnf_opaque, vaddr, vaddr,
1052*0Sstevel@tonic-gate tnf_opaque, vaddr_max, zhat->vaddr_max,
1053*0Sstevel@tonic-gate tnf_opaque, size, size);
1054*0Sstevel@tonic-gate
1055*0Sstevel@tonic-gate mutex_enter(&zhat->lock);
1056*0Sstevel@tonic-gate
1057*0Sstevel@tonic-gate /*
1058*0Sstevel@tonic-gate * The following test prevents us from searching for the user's
1059*0Sstevel@tonic-gate * mappings to the zulu device registers. Those mappings get unloaded
1060*0Sstevel@tonic-gate * every time a graphics context switch away from a given context
1061*0Sstevel@tonic-gate * occurs.
1062*0Sstevel@tonic-gate *
1063*0Sstevel@tonic-gate * Since the heap is located at smaller virtual addresses than the
1064*0Sstevel@tonic-gate * registers, this simple test avoids quite a bit of useless work.
1065*0Sstevel@tonic-gate */
1066*0Sstevel@tonic-gate if (vaddr > zhat->vaddr_max) {
1067*0Sstevel@tonic-gate /*
1068*0Sstevel@tonic-gate * all existing mappings have lower addresses than vaddr
1069*0Sstevel@tonic-gate * no need to search further.
1070*0Sstevel@tonic-gate */
1071*0Sstevel@tonic-gate mutex_exit(&zhat->lock);
1072*0Sstevel@tonic-gate return;
1073*0Sstevel@tonic-gate }
1074*0Sstevel@tonic-gate
1075*0Sstevel@tonic-gate ivaddr = (uint64_t)vaddr;
1076*0Sstevel@tonic-gate end = ivaddr + size;
1077*0Sstevel@tonic-gate
1078*0Sstevel@tonic-gate do {
1079*0Sstevel@tonic-gate struct zulu_shadow_blk *sblk;
1080*0Sstevel@tonic-gate
1081*0Sstevel@tonic-gate sblk = zulu_shadow_tree_lookup(zhat, ivaddr, NULL);
1082*0Sstevel@tonic-gate if (sblk != NULL) {
1083*0Sstevel@tonic-gate uint64_t sblk_end;
1084*0Sstevel@tonic-gate size_t region_size;
1085*0Sstevel@tonic-gate
1086*0Sstevel@tonic-gate found++;
1087*0Sstevel@tonic-gate
1088*0Sstevel@tonic-gate sblk_end = (ivaddr + ZULU_SHADOW_BLK_RANGE) &
1089*0Sstevel@tonic-gate ZULU_SHADOW_BLK_MASK;
1090*0Sstevel@tonic-gate
1091*0Sstevel@tonic-gate if (sblk_end < end) {
1092*0Sstevel@tonic-gate region_size = sblk_end - ivaddr;
1093*0Sstevel@tonic-gate } else {
1094*0Sstevel@tonic-gate region_size = end - ivaddr;
1095*0Sstevel@tonic-gate }
1096*0Sstevel@tonic-gate zulu_hat_unload_region(zhat, ivaddr, region_size, sblk,
1097*0Sstevel@tonic-gate &free_list);
1098*0Sstevel@tonic-gate
1099*0Sstevel@tonic-gate }
1100*0Sstevel@tonic-gate ivaddr += ZULU_SHADOW_BLK_RANGE;
1101*0Sstevel@tonic-gate } while (ivaddr < end);
1102*0Sstevel@tonic-gate
1103*0Sstevel@tonic-gate mutex_exit(&zhat->lock);
1104*0Sstevel@tonic-gate
1105*0Sstevel@tonic-gate free_zblks(free_list);
1106*0Sstevel@tonic-gate
1107*0Sstevel@tonic-gate TNF_PROBE_1(zulu_hat_unload_done, "zulu_hat", /* CSTYLED */,
1108*0Sstevel@tonic-gate tnf_int, found, found);
1109*0Sstevel@tonic-gate }
1110*0Sstevel@tonic-gate
1111*0Sstevel@tonic-gate static void
zulu_hat_unload_callback(struct xhat * xhat,caddr_t vaddr,size_t size,uint_t flags,hat_callback_t * pcb)1112*0Sstevel@tonic-gate zulu_hat_unload_callback(struct xhat *xhat, caddr_t vaddr, size_t size,
1113*0Sstevel@tonic-gate uint_t flags, hat_callback_t *pcb)
1114*0Sstevel@tonic-gate {
1115*0Sstevel@tonic-gate (void) size;
1116*0Sstevel@tonic-gate (void) pcb;
1117*0Sstevel@tonic-gate zulu_hat_unload(xhat, vaddr, size, flags);
1118*0Sstevel@tonic-gate }
1119*0Sstevel@tonic-gate
1120*0Sstevel@tonic-gate
1121*0Sstevel@tonic-gate /*
1122*0Sstevel@tonic-gate * unload one page
1123*0Sstevel@tonic-gate */
1124*0Sstevel@tonic-gate static int
zulu_hat_pageunload(struct xhat * xhat,struct page * pp,uint_t flags,void * xblk)1125*0Sstevel@tonic-gate zulu_hat_pageunload(struct xhat *xhat, struct page *pp, uint_t flags,
1126*0Sstevel@tonic-gate void *xblk)
1127*0Sstevel@tonic-gate {
1128*0Sstevel@tonic-gate struct zulu_hat_blk *zblk = (struct zulu_hat_blk *)xblk;
1129*0Sstevel@tonic-gate struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1130*0Sstevel@tonic-gate int do_delete;
1131*0Sstevel@tonic-gate
1132*0Sstevel@tonic-gate (void) pp;
1133*0Sstevel@tonic-gate (void) flags;
1134*0Sstevel@tonic-gate
1135*0Sstevel@tonic-gate TNF_PROBE_3(zulu_hat_pageunload, "zulu_hat", /* CSTYLED */,
1136*0Sstevel@tonic-gate tnf_int, zulu_ctx, zhat->zulu_ctx,
1137*0Sstevel@tonic-gate tnf_opaque, vaddr, zblk->zulu_hat_blk_vaddr,
1138*0Sstevel@tonic-gate tnf_int, pg_size, zblk->zulu_hat_blk_size);
1139*0Sstevel@tonic-gate
1140*0Sstevel@tonic-gate mutex_enter(&zhat->lock);
1141*0Sstevel@tonic-gate if (zblk->zulu_shadow_blk != NULL) {
1142*0Sstevel@tonic-gate
1143*0Sstevel@tonic-gate do_delete = 1;
1144*0Sstevel@tonic-gate
1145*0Sstevel@tonic-gate zulu_hat_remove_map(zhat, zblk);
1146*0Sstevel@tonic-gate
1147*0Sstevel@tonic-gate /*
1148*0Sstevel@tonic-gate * now that the entry is removed from the TSB, remove the
1149*0Sstevel@tonic-gate * translation from the zulu hardware.
1150*0Sstevel@tonic-gate *
1151*0Sstevel@tonic-gate * Skip the demap if this as is in the process of being freed.
1152*0Sstevel@tonic-gate * The zuluvm as callback has demapped the whole context.
1153*0Sstevel@tonic-gate */
1154*0Sstevel@tonic-gate if (!zhat->freed) {
1155*0Sstevel@tonic-gate zulu_hat_demap_page(zhat,
1156*0Sstevel@tonic-gate (caddr_t)(zblk->zulu_hat_blk_page << ZULU_HAT_BP_SHIFT),
1157*0Sstevel@tonic-gate zblk->zulu_hat_blk_size);
1158*0Sstevel@tonic-gate }
1159*0Sstevel@tonic-gate } else {
1160*0Sstevel@tonic-gate /*
1161*0Sstevel@tonic-gate * This block has already been removed from the zulu_hat,
1162*0Sstevel@tonic-gate * it's on a free list waiting for our thread to release
1163*0Sstevel@tonic-gate * a mutex so it can be freed
1164*0Sstevel@tonic-gate */
1165*0Sstevel@tonic-gate do_delete = 0;
1166*0Sstevel@tonic-gate
1167*0Sstevel@tonic-gate TNF_PROBE_0(zulu_hat_pageunload_skip, "zulu_hat",
1168*0Sstevel@tonic-gate /* CSTYLED */);
1169*0Sstevel@tonic-gate }
1170*0Sstevel@tonic-gate mutex_exit(&zhat->lock);
1171*0Sstevel@tonic-gate
1172*0Sstevel@tonic-gate if (do_delete) {
1173*0Sstevel@tonic-gate (void) xhat_delete_xhatblk(xblk, 1);
1174*0Sstevel@tonic-gate }
1175*0Sstevel@tonic-gate
1176*0Sstevel@tonic-gate return (0);
1177*0Sstevel@tonic-gate }
1178*0Sstevel@tonic-gate
1179*0Sstevel@tonic-gate static void
zulu_hat_swapout(struct xhat * xhat)1180*0Sstevel@tonic-gate zulu_hat_swapout(struct xhat *xhat)
1181*0Sstevel@tonic-gate {
1182*0Sstevel@tonic-gate struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1183*0Sstevel@tonic-gate struct zulu_hat_blk *zblk;
1184*0Sstevel@tonic-gate struct zulu_hat_blk *free_list = NULL;
1185*0Sstevel@tonic-gate int i;
1186*0Sstevel@tonic-gate int nblks = 0;
1187*0Sstevel@tonic-gate
1188*0Sstevel@tonic-gate TNF_PROBE_1(zulu_hat_swapout, "zulu_hat", /* CSTYLED */,
1189*0Sstevel@tonic-gate tnf_int, zulu_ctx, zhat->zulu_ctx);
1190*0Sstevel@tonic-gate
1191*0Sstevel@tonic-gate mutex_enter(&zhat->lock);
1192*0Sstevel@tonic-gate
1193*0Sstevel@tonic-gate /*
1194*0Sstevel@tonic-gate * real swapout calls are rare so we don't do anything in
1195*0Sstevel@tonic-gate * particular to optimize them.
1196*0Sstevel@tonic-gate *
1197*0Sstevel@tonic-gate * Just loop over all buckets in the hash table and free each
1198*0Sstevel@tonic-gate * zblk.
1199*0Sstevel@tonic-gate */
1200*0Sstevel@tonic-gate for (i = 0; i < ZULU_HASH_TBL_NUM; i++) {
1201*0Sstevel@tonic-gate struct zulu_hat_blk *next;
1202*0Sstevel@tonic-gate for (zblk = zhat->hash_tbl[i]; zblk != NULL; zblk = next) {
1203*0Sstevel@tonic-gate next = zblk->zulu_hash_next;
1204*0Sstevel@tonic-gate zulu_hat_remove_map(zhat, zblk);
1205*0Sstevel@tonic-gate add_to_free_list(&free_list, zblk);
1206*0Sstevel@tonic-gate nblks++;
1207*0Sstevel@tonic-gate }
1208*0Sstevel@tonic-gate }
1209*0Sstevel@tonic-gate
1210*0Sstevel@tonic-gate /*
1211*0Sstevel@tonic-gate * remove all mappings for this context from zulu hardware.
1212*0Sstevel@tonic-gate */
1213*0Sstevel@tonic-gate zulu_hat_demap_ctx(zhat->zdev, zhat->zulu_ctx);
1214*0Sstevel@tonic-gate
1215*0Sstevel@tonic-gate mutex_exit(&zhat->lock);
1216*0Sstevel@tonic-gate
1217*0Sstevel@tonic-gate free_zblks(free_list);
1218*0Sstevel@tonic-gate
1219*0Sstevel@tonic-gate TNF_PROBE_1(zulu_hat_swapout_done, "zulu_hat", /* CSTYLED */,
1220*0Sstevel@tonic-gate tnf_int, nblks, nblks);
1221*0Sstevel@tonic-gate }
1222*0Sstevel@tonic-gate
1223*0Sstevel@tonic-gate
1224*0Sstevel@tonic-gate static void
zulu_hat_unshare(struct xhat * xhat,caddr_t vaddr,size_t size)1225*0Sstevel@tonic-gate zulu_hat_unshare(struct xhat *xhat, caddr_t vaddr, size_t size)
1226*0Sstevel@tonic-gate {
1227*0Sstevel@tonic-gate TNF_PROBE_0(zulu_hat_unshare, "zulu_hat", /* CSTYLED */);
1228*0Sstevel@tonic-gate
1229*0Sstevel@tonic-gate zulu_hat_unload(xhat, vaddr, size, 0);
1230*0Sstevel@tonic-gate }
1231*0Sstevel@tonic-gate
1232*0Sstevel@tonic-gate /*
1233*0Sstevel@tonic-gate * Functions to manage changes in protections for mappings.
1234*0Sstevel@tonic-gate *
1235*0Sstevel@tonic-gate * These are rarely called in normal operation so for now just unload
1236*0Sstevel@tonic-gate * the region.
1237*0Sstevel@tonic-gate * If the mapping is still needed, it will fault in later with the new
1238*0Sstevel@tonic-gate * attrributes.
1239*0Sstevel@tonic-gate */
1240*0Sstevel@tonic-gate typedef enum {
1241*0Sstevel@tonic-gate ZULU_HAT_CHGATTR,
1242*0Sstevel@tonic-gate ZULU_HAT_SETATTR,
1243*0Sstevel@tonic-gate ZULU_HAT_CLRATTR
1244*0Sstevel@tonic-gate } zulu_hat_prot_op;
1245*0Sstevel@tonic-gate
1246*0Sstevel@tonic-gate static void
zulu_hat_update_attr(struct xhat * xhat,caddr_t vaddr,size_t size,uint_t flags,zulu_hat_prot_op op)1247*0Sstevel@tonic-gate zulu_hat_update_attr(struct xhat *xhat, caddr_t vaddr, size_t size,
1248*0Sstevel@tonic-gate uint_t flags, zulu_hat_prot_op op)
1249*0Sstevel@tonic-gate {
1250*0Sstevel@tonic-gate struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1251*0Sstevel@tonic-gate
1252*0Sstevel@tonic-gate TNF_PROBE_5(zulu_hat_changeprot, "zulu_hat", /* CSTYLED */,
1253*0Sstevel@tonic-gate tnf_int, ctx, zhat->zulu_ctx,
1254*0Sstevel@tonic-gate tnf_opaque, vaddr, vaddr, tnf_opaque, size, size,
1255*0Sstevel@tonic-gate tnf_uint, flags, flags, tnf_int, op, op);
1256*0Sstevel@tonic-gate
1257*0Sstevel@tonic-gate zulu_hat_unload(xhat, vaddr, size, 0);
1258*0Sstevel@tonic-gate }
1259*0Sstevel@tonic-gate
1260*0Sstevel@tonic-gate static void
zulu_hat_chgprot(struct xhat * xhat,caddr_t vaddr,size_t size,uint_t flags)1261*0Sstevel@tonic-gate zulu_hat_chgprot(struct xhat *xhat, caddr_t vaddr, size_t size, uint_t flags)
1262*0Sstevel@tonic-gate {
1263*0Sstevel@tonic-gate struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1264*0Sstevel@tonic-gate #ifdef DEBUG
1265*0Sstevel@tonic-gate printf("zulu_hat_chgprot: ctx: %d addr: %lx, size: %lx flags: %x\n",
1266*0Sstevel@tonic-gate zhat->zulu_ctx, (uint64_t)vaddr, size, flags);
1267*0Sstevel@tonic-gate #endif
1268*0Sstevel@tonic-gate zulu_hat_update_attr(xhat, vaddr, size, flags, ZULU_HAT_CHGATTR);
1269*0Sstevel@tonic-gate }
1270*0Sstevel@tonic-gate
1271*0Sstevel@tonic-gate
1272*0Sstevel@tonic-gate static void
zulu_hat_setattr(struct xhat * xhat,caddr_t vaddr,size_t size,uint_t flags)1273*0Sstevel@tonic-gate zulu_hat_setattr(struct xhat *xhat, caddr_t vaddr, size_t size, uint_t flags)
1274*0Sstevel@tonic-gate {
1275*0Sstevel@tonic-gate struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1276*0Sstevel@tonic-gate #ifdef DEBUG
1277*0Sstevel@tonic-gate printf("zulu_hat_setattr: ctx: %d addr: %lx, size: %lx flags: %x\n",
1278*0Sstevel@tonic-gate zhat->zulu_ctx, (uint64_t)vaddr, size, flags);
1279*0Sstevel@tonic-gate #endif
1280*0Sstevel@tonic-gate zulu_hat_update_attr(xhat, vaddr, size, flags, ZULU_HAT_SETATTR);
1281*0Sstevel@tonic-gate }
1282*0Sstevel@tonic-gate
1283*0Sstevel@tonic-gate static void
zulu_hat_clrattr(struct xhat * xhat,caddr_t vaddr,size_t size,uint_t flags)1284*0Sstevel@tonic-gate zulu_hat_clrattr(struct xhat *xhat, caddr_t vaddr, size_t size, uint_t flags)
1285*0Sstevel@tonic-gate {
1286*0Sstevel@tonic-gate struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1287*0Sstevel@tonic-gate #ifdef DEBUG
1288*0Sstevel@tonic-gate printf("zulu_hat_clrattr: ctx: %d addr: %lx, size: %lx flags: %x\n",
1289*0Sstevel@tonic-gate zhat->zulu_ctx, (uint64_t)vaddr, size, flags);
1290*0Sstevel@tonic-gate #endif
1291*0Sstevel@tonic-gate zulu_hat_update_attr(xhat, vaddr, size, flags, ZULU_HAT_CLRATTR);
1292*0Sstevel@tonic-gate }
1293*0Sstevel@tonic-gate
1294*0Sstevel@tonic-gate static void
zulu_hat_chgattr(struct xhat * xhat,caddr_t vaddr,size_t size,uint_t flags)1295*0Sstevel@tonic-gate zulu_hat_chgattr(struct xhat *xhat, caddr_t vaddr, size_t size, uint_t flags)
1296*0Sstevel@tonic-gate {
1297*0Sstevel@tonic-gate struct zulu_hat *zhat = (struct zulu_hat *)xhat;
1298*0Sstevel@tonic-gate TNF_PROBE_3(zulu_hat_chgattr, "zulu_hat", /* CSTYLED */,
1299*0Sstevel@tonic-gate tnf_int, ctx, zhat->zulu_ctx,
1300*0Sstevel@tonic-gate tnf_opaque, vaddr, vaddr,
1301*0Sstevel@tonic-gate tnf_opaque, flags, flags);
1302*0Sstevel@tonic-gate #ifdef DEBUG
1303*0Sstevel@tonic-gate printf("zulu_hat_chgattr: ctx: %d addr: %lx, size: %lx flags: %x\n",
1304*0Sstevel@tonic-gate zhat->zulu_ctx, (uint64_t)vaddr, size, flags);
1305*0Sstevel@tonic-gate #endif
1306*0Sstevel@tonic-gate zulu_hat_update_attr(xhat, vaddr, size, flags, ZULU_HAT_CHGATTR);
1307*0Sstevel@tonic-gate }
1308*0Sstevel@tonic-gate
1309*0Sstevel@tonic-gate
1310*0Sstevel@tonic-gate struct xhat_ops zulu_hat_ops = {
1311*0Sstevel@tonic-gate zulu_hat_alloc, /* xhat_alloc */
1312*0Sstevel@tonic-gate zulu_hat_free, /* xhat_free */
1313*0Sstevel@tonic-gate zulu_hat_free_start, /* xhat_free_start */
1314*0Sstevel@tonic-gate NULL, /* xhat_free_end */
1315*0Sstevel@tonic-gate NULL, /* xhat_dup */
1316*0Sstevel@tonic-gate NULL, /* xhat_swapin */
1317*0Sstevel@tonic-gate zulu_hat_swapout, /* xhat_swapout */
1318*0Sstevel@tonic-gate zulu_hat_memload, /* xhat_memload */
1319*0Sstevel@tonic-gate zulu_hat_memload_array, /* xhat_memload_array */
1320*0Sstevel@tonic-gate zulu_hat_devload, /* xhat_devload */
1321*0Sstevel@tonic-gate zulu_hat_unload, /* xhat_unload */
1322*0Sstevel@tonic-gate zulu_hat_unload_callback, /* xhat_unload_callback */
1323*0Sstevel@tonic-gate zulu_hat_setattr, /* xhat_setattr */
1324*0Sstevel@tonic-gate zulu_hat_clrattr, /* xhat_clrattr */
1325*0Sstevel@tonic-gate zulu_hat_chgattr, /* xhat_chgattr */
1326*0Sstevel@tonic-gate zulu_hat_unshare, /* xhat_unshare */
1327*0Sstevel@tonic-gate zulu_hat_chgprot, /* xhat_chgprot */
1328*0Sstevel@tonic-gate zulu_hat_pageunload, /* xhat_pageunload */
1329*0Sstevel@tonic-gate };
1330*0Sstevel@tonic-gate
1331*0Sstevel@tonic-gate xblk_cache_t zulu_xblk_cache = {
1332*0Sstevel@tonic-gate NULL,
1333*0Sstevel@tonic-gate NULL,
1334*0Sstevel@tonic-gate NULL,
1335*0Sstevel@tonic-gate xhat_xblkcache_reclaim
1336*0Sstevel@tonic-gate };
1337*0Sstevel@tonic-gate
1338*0Sstevel@tonic-gate xhat_provider_t zulu_hat_provider = {
1339*0Sstevel@tonic-gate XHAT_PROVIDER_VERSION,
1340*0Sstevel@tonic-gate 0,
1341*0Sstevel@tonic-gate NULL,
1342*0Sstevel@tonic-gate NULL,
1343*0Sstevel@tonic-gate "zulu_hat_provider",
1344*0Sstevel@tonic-gate &zulu_xblk_cache,
1345*0Sstevel@tonic-gate &zulu_hat_ops,
1346*0Sstevel@tonic-gate sizeof (struct zulu_hat_blk) + sizeof (struct xhat_hme_blk)
1347*0Sstevel@tonic-gate };
1348*0Sstevel@tonic-gate
1349*0Sstevel@tonic-gate /*
1350*0Sstevel@tonic-gate * The following functions are the entry points that zuluvm uses.
1351*0Sstevel@tonic-gate */
1352*0Sstevel@tonic-gate
1353*0Sstevel@tonic-gate /*
1354*0Sstevel@tonic-gate * initialize this module. Called from zuluvm's _init function
1355*0Sstevel@tonic-gate */
1356*0Sstevel@tonic-gate int
zulu_hat_init()1357*0Sstevel@tonic-gate zulu_hat_init()
1358*0Sstevel@tonic-gate {
1359*0Sstevel@tonic-gate int c;
1360*0Sstevel@tonic-gate int rval;
1361*0Sstevel@tonic-gate mutex_init(&zulu_ctx_lock, NULL, MUTEX_DEFAULT, NULL);
1362*0Sstevel@tonic-gate
1363*0Sstevel@tonic-gate for (c = 0; c < ZULU_HAT_MAX_CTX; c++) {
1364*0Sstevel@tonic-gate ZULU_CTX_LOCK_INIT(c);
1365*0Sstevel@tonic-gate }
1366*0Sstevel@tonic-gate zulu_ctx_search_start = 0;
1367*0Sstevel@tonic-gate rval = xhat_provider_register(&zulu_hat_provider);
1368*0Sstevel@tonic-gate if (rval != 0) {
1369*0Sstevel@tonic-gate mutex_destroy(&zulu_ctx_lock);
1370*0Sstevel@tonic-gate }
1371*0Sstevel@tonic-gate return (rval);
1372*0Sstevel@tonic-gate }
1373*0Sstevel@tonic-gate
1374*0Sstevel@tonic-gate /*
1375*0Sstevel@tonic-gate * un-initialize this module. Called from zuluvm's _fini function
1376*0Sstevel@tonic-gate */
1377*0Sstevel@tonic-gate int
zulu_hat_destroy()1378*0Sstevel@tonic-gate zulu_hat_destroy()
1379*0Sstevel@tonic-gate {
1380*0Sstevel@tonic-gate if (xhat_provider_unregister(&zulu_hat_provider) != 0) {
1381*0Sstevel@tonic-gate return (-1);
1382*0Sstevel@tonic-gate }
1383*0Sstevel@tonic-gate mutex_destroy(&zulu_ctx_lock);
1384*0Sstevel@tonic-gate return (0);
1385*0Sstevel@tonic-gate }
1386*0Sstevel@tonic-gate
1387*0Sstevel@tonic-gate int
zulu_hat_attach(void * arg)1388*0Sstevel@tonic-gate zulu_hat_attach(void *arg)
1389*0Sstevel@tonic-gate {
1390*0Sstevel@tonic-gate (void) arg;
1391*0Sstevel@tonic-gate return (0);
1392*0Sstevel@tonic-gate }
1393*0Sstevel@tonic-gate
1394*0Sstevel@tonic-gate int
zulu_hat_detach(void * arg)1395*0Sstevel@tonic-gate zulu_hat_detach(void *arg)
1396*0Sstevel@tonic-gate {
1397*0Sstevel@tonic-gate (void) arg;
1398*0Sstevel@tonic-gate return (0);
1399*0Sstevel@tonic-gate }
1400*0Sstevel@tonic-gate
1401*0Sstevel@tonic-gate /*
1402*0Sstevel@tonic-gate * create a zulu hat for this address space.
1403*0Sstevel@tonic-gate */
1404*0Sstevel@tonic-gate struct zulu_hat *
zulu_hat_proc_attach(struct as * as,void * zdev)1405*0Sstevel@tonic-gate zulu_hat_proc_attach(struct as *as, void *zdev)
1406*0Sstevel@tonic-gate {
1407*0Sstevel@tonic-gate struct zulu_hat *zhat;
1408*0Sstevel@tonic-gate int xhat_rval;
1409*0Sstevel@tonic-gate
1410*0Sstevel@tonic-gate xhat_rval = xhat_attach_xhat(&zulu_hat_provider, as,
1411*0Sstevel@tonic-gate (struct xhat **)&zhat, NULL);
1412*0Sstevel@tonic-gate if ((xhat_rval == 0) && (zhat != NULL)) {
1413*0Sstevel@tonic-gate mutex_enter(&zhat->lock);
1414*0Sstevel@tonic-gate ZULU_HAT2AS(zhat) = as;
1415*0Sstevel@tonic-gate zhat->zdev = zdev;
1416*0Sstevel@tonic-gate mutex_exit(&zhat->lock);
1417*0Sstevel@tonic-gate }
1418*0Sstevel@tonic-gate
1419*0Sstevel@tonic-gate TNF_PROBE_3(zulu_hat_proc_attach, "zulu_hat", /* CSTYLED */,
1420*0Sstevel@tonic-gate tnf_int, xhat_rval, xhat_rval, tnf_opaque, as, as,
1421*0Sstevel@tonic-gate tnf_opaque, zhat, zhat);
1422*0Sstevel@tonic-gate
1423*0Sstevel@tonic-gate return (zhat);
1424*0Sstevel@tonic-gate }
1425*0Sstevel@tonic-gate
1426*0Sstevel@tonic-gate void
zulu_hat_proc_detach(struct zulu_hat * zhat)1427*0Sstevel@tonic-gate zulu_hat_proc_detach(struct zulu_hat *zhat)
1428*0Sstevel@tonic-gate {
1429*0Sstevel@tonic-gate struct as *as = ZULU_HAT2AS(zhat);
1430*0Sstevel@tonic-gate
1431*0Sstevel@tonic-gate zulu_hat_ctx_free(zhat);
1432*0Sstevel@tonic-gate
1433*0Sstevel@tonic-gate (void) xhat_detach_xhat(&zulu_hat_provider, ZULU_HAT2AS(zhat));
1434*0Sstevel@tonic-gate
1435*0Sstevel@tonic-gate TNF_PROBE_1(zulu_hat_proc_detach, "zulu_hat", /* CSTYLED */,
1436*0Sstevel@tonic-gate tnf_opaque, as, as);
1437*0Sstevel@tonic-gate }
1438*0Sstevel@tonic-gate
1439*0Sstevel@tonic-gate /*
1440*0Sstevel@tonic-gate * zulu_hat_terminate
1441*0Sstevel@tonic-gate *
1442*0Sstevel@tonic-gate * Disables any further TLB miss processing for this hat
1443*0Sstevel@tonic-gate * Called by zuluvm's as_free callback. The primary purpose of this
1444*0Sstevel@tonic-gate * function is to cause any pending zulu DMA to abort quickly.
1445*0Sstevel@tonic-gate */
1446*0Sstevel@tonic-gate void
zulu_hat_terminate(struct zulu_hat * zhat)1447*0Sstevel@tonic-gate zulu_hat_terminate(struct zulu_hat *zhat)
1448*0Sstevel@tonic-gate {
1449*0Sstevel@tonic-gate int ctx = zhat->zulu_ctx;
1450*0Sstevel@tonic-gate
1451*0Sstevel@tonic-gate TNF_PROBE_1(zulu_hat_terminate, "zulu_hat", /* CSTYLED */,
1452*0Sstevel@tonic-gate tnf_int, ctx, ctx);
1453*0Sstevel@tonic-gate
1454*0Sstevel@tonic-gate mutex_enter(&zhat->lock);
1455*0Sstevel@tonic-gate
1456*0Sstevel@tonic-gate zhat->freed = 1;
1457*0Sstevel@tonic-gate
1458*0Sstevel@tonic-gate zulu_ctx_tsb_lock_enter(zhat);
1459*0Sstevel@tonic-gate /*
1460*0Sstevel@tonic-gate * zap the tsb
1461*0Sstevel@tonic-gate */
1462*0Sstevel@tonic-gate bzero(zhat->zulu_tsb, ZULU_TSB_SZ);
1463*0Sstevel@tonic-gate zulu_ctx_tsb_lock_exit(zhat);
1464*0Sstevel@tonic-gate
1465*0Sstevel@tonic-gate zulu_hat_demap_ctx(zhat->zdev, zhat->zulu_ctx);
1466*0Sstevel@tonic-gate
1467*0Sstevel@tonic-gate mutex_exit(&zhat->lock);
1468*0Sstevel@tonic-gate
1469*0Sstevel@tonic-gate TNF_PROBE_0(zulu_hat_terminate_done, "zulu_hat", /* CSTYLED */);
1470*0Sstevel@tonic-gate }
1471