1*4f364e7cSRobert Mustacchi /*
2*4f364e7cSRobert Mustacchi * CDDL HEADER START
3*4f364e7cSRobert Mustacchi *
4*4f364e7cSRobert Mustacchi * The contents of this file are subject to the terms of the
5*4f364e7cSRobert Mustacchi * Common Development and Distribution License (the "License").
6*4f364e7cSRobert Mustacchi * You may not use this file except in compliance with the License.
7*4f364e7cSRobert Mustacchi *
8*4f364e7cSRobert Mustacchi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*4f364e7cSRobert Mustacchi * or http://www.opensolaris.org/os/licensing.
10*4f364e7cSRobert Mustacchi * See the License for the specific language governing permissions
11*4f364e7cSRobert Mustacchi * and limitations under the License.
12*4f364e7cSRobert Mustacchi *
13*4f364e7cSRobert Mustacchi * When distributing Covered Code, include this CDDL HEADER in each
14*4f364e7cSRobert Mustacchi * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*4f364e7cSRobert Mustacchi * If applicable, add the following below this CDDL HEADER, with the
16*4f364e7cSRobert Mustacchi * fields enclosed by brackets "[]" replaced with your own identifying
17*4f364e7cSRobert Mustacchi * information: Portions Copyright [yyyy] [name of copyright owner]
18*4f364e7cSRobert Mustacchi *
19*4f364e7cSRobert Mustacchi * CDDL HEADER END
20*4f364e7cSRobert Mustacchi */
21*4f364e7cSRobert Mustacchi /*
22*4f364e7cSRobert Mustacchi * Copyright (c) 2014 Joyent, Inc. All rights reserved.
23*4f364e7cSRobert Mustacchi */
24*4f364e7cSRobert Mustacchi
25*4f364e7cSRobert Mustacchi /*
26*4f364e7cSRobert Mustacchi * Don't Panic! If you find the blocks of assembly that follow confusing and
27*4f364e7cSRobert Mustacchi * you're questioning why they exist, please go read section 8 of the umem.c big
28*4f364e7cSRobert Mustacchi * theory statement. Next familiarize yourself with the malloc and free
29*4f364e7cSRobert Mustacchi * implementations in libumem's malloc.c.
30*4f364e7cSRobert Mustacchi *
31*4f364e7cSRobert Mustacchi * What follows is the i386 implementation of the thread caching automatic
32*4f364e7cSRobert Mustacchi * assembly generation. With i386 a function only has three registers it's
33*4f364e7cSRobert Mustacchi * allowed to change without restoring them: eax, ecx, and edx. All others have
34*4f364e7cSRobert Mustacchi * to be preserved. Since the set of registers we have available is so small, we
35*4f364e7cSRobert Mustacchi * have to make use of esi, ebx, and edi and save their original values to the
36*4f364e7cSRobert Mustacchi * stack.
37*4f364e7cSRobert Mustacchi *
38*4f364e7cSRobert Mustacchi * Malloc register usage:
39*4f364e7cSRobert Mustacchi * o. esi: Size of the malloc (passed into us and modified)
40*4f364e7cSRobert Mustacchi * o. edi: Size of the cache
41*4f364e7cSRobert Mustacchi * o. eax: Buffer to return
42*4f364e7cSRobert Mustacchi * o. ebx: Scratch space and temporary values
43*4f364e7cSRobert Mustacchi * o. ecx: Pointer to the tmem_t in the ulwp_t.
44*4f364e7cSRobert Mustacchi * o. edx: Pointer to the tmem_t array of roots
45*4f364e7cSRobert Mustacchi *
46*4f364e7cSRobert Mustacchi * Free register usage:
47*4f364e7cSRobert Mustacchi * o. esi: Size of the malloc (passed into us and modified)
48*4f364e7cSRobert Mustacchi * o. edi: Size of the cache
49*4f364e7cSRobert Mustacchi * o. eax: Buffer to free
50*4f364e7cSRobert Mustacchi * o. ebx: Scratch space and temporary values
51*4f364e7cSRobert Mustacchi * o. ecx: Pointer to the tmem_t in the ulwp_t.
52*4f364e7cSRobert Mustacchi * o. edx: Pointer to the tmem_t array of roots
53*4f364e7cSRobert Mustacchi *
54*4f364e7cSRobert Mustacchi * Once we determine what cache we are using, we increment %edx to the
55*4f364e7cSRobert Mustacchi * appropriate offset and set %edi with the size of the cache. This means that
56*4f364e7cSRobert Mustacchi * when we break out to the normal buffer allocation point %edx contains the
57*4f364e7cSRobert Mustacchi * head of the linked list and %edi is the amount that we have to adjust the
58*4f364e7cSRobert Mustacchi * total amount cached by the thread.
59*4f364e7cSRobert Mustacchi *
60*4f364e7cSRobert Mustacchi * Each block of assembly has psuedocode that describes its purpose.
61*4f364e7cSRobert Mustacchi */
62*4f364e7cSRobert Mustacchi
63*4f364e7cSRobert Mustacchi #include <inttypes.h>
64*4f364e7cSRobert Mustacchi #include <strings.h>
65*4f364e7cSRobert Mustacchi #include <umem_impl.h>
66*4f364e7cSRobert Mustacchi #include "umem_base.h"
67*4f364e7cSRobert Mustacchi
68*4f364e7cSRobert Mustacchi #include <atomic.h>
69*4f364e7cSRobert Mustacchi
70*4f364e7cSRobert Mustacchi const int umem_genasm_supported = 1;
71*4f364e7cSRobert Mustacchi static uintptr_t umem_genasm_mptr = (uintptr_t)&_malloc;
72*4f364e7cSRobert Mustacchi static size_t umem_genasm_msize = 512;
73*4f364e7cSRobert Mustacchi static uintptr_t umem_genasm_fptr = (uintptr_t)&_free;
74*4f364e7cSRobert Mustacchi static size_t umem_genasm_fsize = 512;
75*4f364e7cSRobert Mustacchi static uintptr_t umem_genasm_omptr = (uintptr_t)umem_malloc;
76*4f364e7cSRobert Mustacchi static uintptr_t umem_genasm_ofptr = (uintptr_t)umem_malloc_free;
77*4f364e7cSRobert Mustacchi /*
78*4f364e7cSRobert Mustacchi * The maximum number of caches we can support. We use a single byte addl so
79*4f364e7cSRobert Mustacchi * this is 255 (UINT8_MAX) / sizeof (uintptr_t). In this case 63
80*4f364e7cSRobert Mustacchi */
81*4f364e7cSRobert Mustacchi #define UMEM_GENASM_MAX32 63
82*4f364e7cSRobert Mustacchi
83*4f364e7cSRobert Mustacchi #define PTC_JMPADDR(dest, src) (dest - (src + 4))
84*4f364e7cSRobert Mustacchi #define PTC_ROOT_SIZE sizeof (uintptr_t)
85*4f364e7cSRobert Mustacchi #define MULTINOP 0x0000441f0f
86*4f364e7cSRobert Mustacchi
87*4f364e7cSRobert Mustacchi /*
88*4f364e7cSRobert Mustacchi * void *ptcmalloc(size_t orig_size);
89*4f364e7cSRobert Mustacchi *
90*4f364e7cSRobert Mustacchi * size_t size = orig_size + 8;
91*4f364e7cSRobert Mustacchi *
92*4f364e7cSRobert Mustacchi * if (size < orig_size)
93*4f364e7cSRobert Mustacchi * goto tomalloc; ! This is overflow
94*4f364e7cSRobert Mustacchi *
95*4f364e7cSRobert Mustacchi * if (size > cache_size)
96*4f364e7cSRobert Mustacchi * goto tomalloc;
97*4f364e7cSRobert Mustacchi *
98*4f364e7cSRobert Mustacchi * tmem_t *t = (uintptr_t)curthread() + umem_thr_offset;
99*4f364e7cSRobert Mustacchi * void **roots = t->tm_roots;
100*4f364e7cSRobert Mustacchi */
101*4f364e7cSRobert Mustacchi #define PTC_MALINIT_JOUT 0x0e
102*4f364e7cSRobert Mustacchi #define PTC_MALINIT_MCS 0x14
103*4f364e7cSRobert Mustacchi #define PTC_MALINIT_JOV 0x1a
104*4f364e7cSRobert Mustacchi #define PTC_MALINIT_SOFF 0x27
105*4f364e7cSRobert Mustacchi static const uint8_t malinit[] = {
106*4f364e7cSRobert Mustacchi 0x55, /* pushl %ebp */
107*4f364e7cSRobert Mustacchi 0x89, 0xe5, /* movl %esp, %ebp */
108*4f364e7cSRobert Mustacchi 0x57, /* pushl %edi */
109*4f364e7cSRobert Mustacchi 0x56, /* pushl %esi */
110*4f364e7cSRobert Mustacchi 0x53, /* pushl %ebx */
111*4f364e7cSRobert Mustacchi 0x8b, 0x75, 0x08, /* movl 0x8(%ebp), %esi */
112*4f364e7cSRobert Mustacchi 0x83, 0xc6, 0x08, /* addl $0x8,%esi */
113*4f364e7cSRobert Mustacchi 0x0f, 0x82, 0x00, 0x00, 0x00, 0x00, /* jc +$JMP (errout) */
114*4f364e7cSRobert Mustacchi 0x81, 0xfe, 0x00, 0x00, 0x00, 0x00, /* cmpl sizeof ($C0), %esi */
115*4f364e7cSRobert Mustacchi 0x0f, 0x87, 0x00, 0x00, 0x00, 0x00, /* ja +$JMP (errout) */
116*4f364e7cSRobert Mustacchi 0x65, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, /* movl %gs:0x0,%ecx */
117*4f364e7cSRobert Mustacchi 0x81, 0xc1, 0x00, 0x00, 0x00, 0x00, /* addl $OFF, %ecx */
118*4f364e7cSRobert Mustacchi 0x8d, 0x51, 0x04 /* leal 0x4(%ecx), %edx */
119*4f364e7cSRobert Mustacchi };
120*4f364e7cSRobert Mustacchi
121*4f364e7cSRobert Mustacchi /*
122*4f364e7cSRobert Mustacchi * void ptcfree(void *buf);
123*4f364e7cSRobert Mustacchi *
124*4f364e7cSRobert Mustacchi * if (buf == NULL)
125*4f364e7cSRobert Mustacchi * return;
126*4f364e7cSRobert Mustacchi *
127*4f364e7cSRobert Mustacchi * malloc_data_t *tag = buf;
128*4f364e7cSRobert Mustacchi * tag--;
129*4f364e7cSRobert Mustacchi * int size = tag->malloc_size;
130*4f364e7cSRobert Mustacchi * int tagtval = UMEM_MALLOC_DECODE(tag->malloc_tag, size);
131*4f364e7cSRobert Mustacchi *
132*4f364e7cSRobert Mustacchi * if (tagval != MALLOC_MAGIC)
133*4f364e7cSRobert Mustacchi * goto tofree;
134*4f364e7cSRobert Mustacchi *
135*4f364e7cSRobert Mustacchi * if (size > cache_max)
136*4f364e7cSRobert Mustacchi * goto tofree;
137*4f364e7cSRobert Mustacchi *
138*4f364e7cSRobert Mustacchi * tmem_t *t = (uintptr_t)curthread() + umem_thr_offset;
139*4f364e7cSRobert Mustacchi * void **roots = t->tm_roots;
140*4f364e7cSRobert Mustacchi */
141*4f364e7cSRobert Mustacchi #define PTC_FRINI_JDONE 0x0d
142*4f364e7cSRobert Mustacchi #define PTC_FRINI_JFREE 0x23
143*4f364e7cSRobert Mustacchi #define PTC_FRINI_MCS 0x29
144*4f364e7cSRobert Mustacchi #define PTC_FRINI_JOV 0x2f
145*4f364e7cSRobert Mustacchi #define PTC_FRINI_SOFF 0x3c
146*4f364e7cSRobert Mustacchi static const uint8_t freeinit[] = {
147*4f364e7cSRobert Mustacchi 0x55, /* pushl %ebp */
148*4f364e7cSRobert Mustacchi 0x89, 0xe5, /* movl %esp, %ebp */
149*4f364e7cSRobert Mustacchi 0x57, /* pushl %edi */
150*4f364e7cSRobert Mustacchi 0x56, /* pushl %esi */
151*4f364e7cSRobert Mustacchi 0x53, /* pushl %ebx */
152*4f364e7cSRobert Mustacchi 0x8b, 0x45, 0x08, /* movl 0x8(%ebp), %eax */
153*4f364e7cSRobert Mustacchi 0x85, 0xc0, /* testl %eax, %eax */
154*4f364e7cSRobert Mustacchi 0x0f, 0x84, 0x00, 0x00, 0x00, 0x00, /* je $JDONE (done) */
155*4f364e7cSRobert Mustacchi 0x83, 0xe8, 0x08, /* subl $0x8,%eax */
156*4f364e7cSRobert Mustacchi 0x8b, 0x30, /* movl (%eax),%esi */
157*4f364e7cSRobert Mustacchi 0x8b, 0x50, 0x04, /* movl 0x4(%eax),%edx */
158*4f364e7cSRobert Mustacchi 0x01, 0xf2, /* addl %esi,%edx */
159*4f364e7cSRobert Mustacchi 0x81, 0xfa, 0x00, 0xc0, 0x10, 0x3a, /* cmpl MAGIC32, %edx */
160*4f364e7cSRobert Mustacchi 0x0f, 0x85, 0x00, 0x00, 0x00, 0x00, /* jne +JFREE (goto freebuf) */
161*4f364e7cSRobert Mustacchi
162*4f364e7cSRobert Mustacchi 0x81, 0xfe, 0x00, 0x00, 0x00, 0x00, /* cmpl sizeof ($C0), %esi */
163*4f364e7cSRobert Mustacchi 0x0f, 0x87, 0x00, 0x00, 0x00, 0x00, /* ja +$JMP (errout) */
164*4f364e7cSRobert Mustacchi 0x65, 0x8b, 0x0d, 0x00, 0x0, 0x00, 0x00, /* movl %gs:0x0,%ecx */
165*4f364e7cSRobert Mustacchi 0x81, 0xc1, 0x00, 0x00, 0x00, 0x00, /* addl $0xOFF, %ecx */
166*4f364e7cSRobert Mustacchi 0x8d, 0x51, 0x04 /* leal 0x4(%ecx),%edx */
167*4f364e7cSRobert Mustacchi };
168*4f364e7cSRobert Mustacchi
169*4f364e7cSRobert Mustacchi /*
170*4f364e7cSRobert Mustacchi * if (size <= $CACHE_SIZE) {
171*4f364e7cSRobert Mustacchi * csize = $CACHE_SIZE;
172*4f364e7cSRobert Mustacchi * } else ... ! goto next cache
173*4f364e7cSRobert Mustacchi */
174*4f364e7cSRobert Mustacchi #define PTC_INICACHE_CMP 0x02
175*4f364e7cSRobert Mustacchi #define PTC_INICACHE_SIZE 0x09
176*4f364e7cSRobert Mustacchi #define PTC_INICACHE_JMP 0x0e
177*4f364e7cSRobert Mustacchi static const uint8_t inicache[] = {
178*4f364e7cSRobert Mustacchi 0x81, 0xfe, 0xff, 0x00, 0x00, 0x00, /* cmpl sizeof ($C0), %esi */
179*4f364e7cSRobert Mustacchi 0x77, 0x0a, /* ja +0xa */
180*4f364e7cSRobert Mustacchi 0xbf, 0xff, 0x00, 0x00, 0x00, /* movl sizeof ($C0), %edi */
181*4f364e7cSRobert Mustacchi 0xe9, 0x00, 0x00, 0x00, 0x00 /* jmp +$JMP (allocbuf) */
182*4f364e7cSRobert Mustacchi };
183*4f364e7cSRobert Mustacchi
184*4f364e7cSRobert Mustacchi /*
185*4f364e7cSRobert Mustacchi * if (size <= $CACHE_SIZE) {
186*4f364e7cSRobert Mustacchi * csize = $CACHE_SIZE;
187*4f364e7cSRobert Mustacchi * roots += $CACHE_NUM;
188*4f364e7cSRobert Mustacchi * } else ... ! goto next cache
189*4f364e7cSRobert Mustacchi */
190*4f364e7cSRobert Mustacchi #define PTC_GENCACHE_CMP 0x02
191*4f364e7cSRobert Mustacchi #define PTC_GENCACHE_NUM 0x0a
192*4f364e7cSRobert Mustacchi #define PTC_GENCACHE_SIZE 0x0c
193*4f364e7cSRobert Mustacchi #define PTC_GENCACHE_JMP 0x11
194*4f364e7cSRobert Mustacchi static const uint8_t gencache[] = {
195*4f364e7cSRobert Mustacchi 0x81, 0xfe, 0x00, 0x00, 0x00, 0x00, /* cmpl sizeof ($CACHE), %esi */
196*4f364e7cSRobert Mustacchi 0x77, 0x0d, /* ja +0xd (next cache) */
197*4f364e7cSRobert Mustacchi 0x83, 0xc2, 0x00, /* addl $4*$ii, %edx */
198*4f364e7cSRobert Mustacchi 0xbf, 0x00, 0x00, 0x00, 0x00, /* movl sizeof ($CACHE), %edi */
199*4f364e7cSRobert Mustacchi 0xe9, 0x00, 0x00, 0x00, 0x00 /* jmp +$JMP (allocbuf) */
200*4f364e7cSRobert Mustacchi };
201*4f364e7cSRobert Mustacchi
202*4f364e7cSRobert Mustacchi /*
203*4f364e7cSRobert Mustacchi * else if (size <= $CACHE_SIZE) {
204*4f364e7cSRobert Mustacchi * csize = $CACHE_SIZE;
205*4f364e7cSRobert Mustacchi * roots += $CACHE_NUM;
206*4f364e7cSRobert Mustacchi * } else {
207*4f364e7cSRobert Mustacchi * goto tofunc; ! goto tomalloc if ptcmalloc.
208*4f364e7cSRobert Mustacchi * } ! goto tofree if ptcfree.
209*4f364e7cSRobert Mustacchi */
210*4f364e7cSRobert Mustacchi #define PTC_FINCACHE_CMP 0x02
211*4f364e7cSRobert Mustacchi #define PTC_FINCACHE_JMP 0x07
212*4f364e7cSRobert Mustacchi #define PTC_FINCACHE_NUM 0x0a
213*4f364e7cSRobert Mustacchi #define PTC_FINCACHE_SIZE 0x0c
214*4f364e7cSRobert Mustacchi static const uint8_t fincache[] = {
215*4f364e7cSRobert Mustacchi 0x81, 0xfe, 0xff, 0x00, 0x00, 0x00, /* cmpl sizeof ($CLAST), %esi */
216*4f364e7cSRobert Mustacchi 0x77, 0x00, /* ja +$JMP (to errout) */
217*4f364e7cSRobert Mustacchi 0x83, 0xc2, 0x00, /* addl $4*($NCACHES-1), %edx */
218*4f364e7cSRobert Mustacchi 0xbf, 0x00, 0x00, 0x00, 0x00, /* movl sizeof ($CLAST), %edi */
219*4f364e7cSRobert Mustacchi };
220*4f364e7cSRobert Mustacchi
221*4f364e7cSRobert Mustacchi /*
222*4f364e7cSRobert Mustacchi * if (*root == NULL)
223*4f364e7cSRobert Mustacchi * goto tomalloc;
224*4f364e7cSRobert Mustacchi *
225*4f364e7cSRobert Mustacchi * malloc_data_t *ret = *root;
226*4f364e7cSRobert Mustacchi * *root = *(void **)ret;
227*4f364e7cSRobert Mustacchi * t->tm_size += csize;
228*4f364e7cSRobert Mustacchi * ret->malloc_size = size;
229*4f364e7cSRobert Mustacchi *
230*4f364e7cSRobert Mustacchi * ret->malloc_data = UMEM_MALLOC_ENCODE(MALLOC_SECOND_MAGIC, size);
231*4f364e7cSRobert Mustacchi * ret++;
232*4f364e7cSRobert Mustacchi *
233*4f364e7cSRobert Mustacchi * return ((void *)ret);
234*4f364e7cSRobert Mustacchi * tomalloc:
235*4f364e7cSRobert Mustacchi * return (malloc(orig_size));
236*4f364e7cSRobert Mustacchi */
237*4f364e7cSRobert Mustacchi #define PTC_MALFINI_ALLABEL 0x00
238*4f364e7cSRobert Mustacchi #define PTC_MALFINI_JMLABEL 0x20
239*4f364e7cSRobert Mustacchi #define PTC_MALFINI_JMADDR 0x25
240*4f364e7cSRobert Mustacchi static const uint8_t malfini[] = {
241*4f364e7cSRobert Mustacchi /* allocbuf: */
242*4f364e7cSRobert Mustacchi 0x8b, 0x02, /* movl (%edx), %eax */
243*4f364e7cSRobert Mustacchi 0x85, 0xc0, /* testl %eax, %eax */
244*4f364e7cSRobert Mustacchi 0x74, 0x1a, /* je +0x1a (errout) */
245*4f364e7cSRobert Mustacchi 0x8b, 0x18, /* movl (%eax), %esi */
246*4f364e7cSRobert Mustacchi 0x89, 0x1a, /* movl %esi, (%edx) */
247*4f364e7cSRobert Mustacchi 0x29, 0x39, /* subl %edi, (%ecx) */
248*4f364e7cSRobert Mustacchi 0x89, 0x30, /* movl %esi, ($eax) */
249*4f364e7cSRobert Mustacchi 0xba, 0x00, 0xc0, 0x10, 0x3a, /* movl $0x3a10c000,%edx */
250*4f364e7cSRobert Mustacchi 0x29, 0xf2, /* subl %esi, %edx */
251*4f364e7cSRobert Mustacchi 0x89, 0x50, 0x04, /* movl %edx, 0x4(%eax) */
252*4f364e7cSRobert Mustacchi 0x83, 0xc0, 0x08, /* addl %0x8, %eax */
253*4f364e7cSRobert Mustacchi 0x5b, /* popl %ebx */
254*4f364e7cSRobert Mustacchi 0x5e, /* popl %esi */
255*4f364e7cSRobert Mustacchi 0x5f, /* popl %edi */
256*4f364e7cSRobert Mustacchi 0xc9, /* leave */
257*4f364e7cSRobert Mustacchi 0xc3, /* ret */
258*4f364e7cSRobert Mustacchi /* errout: */
259*4f364e7cSRobert Mustacchi 0x5b, /* popl %ebx */
260*4f364e7cSRobert Mustacchi 0x5e, /* popl %esi */
261*4f364e7cSRobert Mustacchi 0x5f, /* popl %edi */
262*4f364e7cSRobert Mustacchi 0xc9, /* leave */
263*4f364e7cSRobert Mustacchi 0xe9, 0x00, 0x00, 0x00, 0x00 /* jmp $malloc */
264*4f364e7cSRobert Mustacchi };
265*4f364e7cSRobert Mustacchi
266*4f364e7cSRobert Mustacchi /*
267*4f364e7cSRobert Mustacchi * if (t->tm_size + csize > umem_ptc_size)
268*4f364e7cSRobert Mustacchi * goto tofree;
269*4f364e7cSRobert Mustacchi *
270*4f364e7cSRobert Mustacchi * t->tm_size += csize
271*4f364e7cSRobert Mustacchi * *(void **)tag = *root;
272*4f364e7cSRobert Mustacchi * *root = tag;
273*4f364e7cSRobert Mustacchi * return;
274*4f364e7cSRobert Mustacchi * tofree:
275*4f364e7cSRobert Mustacchi * free(buf);
276*4f364e7cSRobert Mustacchi * return;
277*4f364e7cSRobert Mustacchi */
278*4f364e7cSRobert Mustacchi #define PTC_FRFINI_RBUFLABEL 0x00
279*4f364e7cSRobert Mustacchi #define PTC_FRFINI_CACHEMAX 0x06
280*4f364e7cSRobert Mustacchi #define PTC_FRFINI_DONELABEL 0x14
281*4f364e7cSRobert Mustacchi #define PTC_FRFINI_JFLABEL 0x19
282*4f364e7cSRobert Mustacchi #define PTC_FRFINI_JFADDR 0x1e
283*4f364e7cSRobert Mustacchi static const uint8_t freefini[] = {
284*4f364e7cSRobert Mustacchi /* freebuf: */
285*4f364e7cSRobert Mustacchi 0x8b, 0x19, /* movl (%ecx),%ebx */
286*4f364e7cSRobert Mustacchi 0x01, 0xfb, /* addl %edi,%ebx */
287*4f364e7cSRobert Mustacchi 0x81, 0xfb, 0x00, 0x00, 0x00, 0x00, /* cmpl maxsize, %ebx */
288*4f364e7cSRobert Mustacchi 0x73, 0x0d, /* jae +0xd <tofree> */
289*4f364e7cSRobert Mustacchi 0x01, 0x39, /* addl %edi,(%ecx) */
290*4f364e7cSRobert Mustacchi 0x8b, 0x3a, /* movl (%edx),%edi */
291*4f364e7cSRobert Mustacchi 0x89, 0x38, /* movl %edi,(%eax) */
292*4f364e7cSRobert Mustacchi 0x89, 0x02, /* movl %eax,(%edx) */
293*4f364e7cSRobert Mustacchi /* done: */
294*4f364e7cSRobert Mustacchi 0x5b, /* popl %ebx */
295*4f364e7cSRobert Mustacchi 0x5e, /* popl %esi */
296*4f364e7cSRobert Mustacchi 0x5f, /* popl %edi */
297*4f364e7cSRobert Mustacchi 0xc9, /* leave */
298*4f364e7cSRobert Mustacchi 0xc3, /* ret */
299*4f364e7cSRobert Mustacchi /* realfree: */
300*4f364e7cSRobert Mustacchi 0x5b, /* popl %ebx */
301*4f364e7cSRobert Mustacchi 0x5e, /* popl %esi */
302*4f364e7cSRobert Mustacchi 0x5f, /* popl %edi */
303*4f364e7cSRobert Mustacchi 0xc9, /* leave */
304*4f364e7cSRobert Mustacchi 0xe9, 0x00, 0x00, 0x00, 0x00 /* jmp free */
305*4f364e7cSRobert Mustacchi };
306*4f364e7cSRobert Mustacchi
307*4f364e7cSRobert Mustacchi /*
308*4f364e7cSRobert Mustacchi * Construct the initial part of malloc. off contains the offset from curthread
309*4f364e7cSRobert Mustacchi * to the root of the tmem structure. ep is the address of the label to error
310*4f364e7cSRobert Mustacchi * and jump to free. csize is the size of the largest umem_cache in ptcumem.
311*4f364e7cSRobert Mustacchi */
312*4f364e7cSRobert Mustacchi static int
genasm_malinit(uint8_t * bp,uint32_t off,uint32_t ep,uint32_t csize)313*4f364e7cSRobert Mustacchi genasm_malinit(uint8_t *bp, uint32_t off, uint32_t ep, uint32_t csize)
314*4f364e7cSRobert Mustacchi {
315*4f364e7cSRobert Mustacchi uint32_t addr;
316*4f364e7cSRobert Mustacchi
317*4f364e7cSRobert Mustacchi bcopy(malinit, bp, sizeof (malinit));
318*4f364e7cSRobert Mustacchi addr = PTC_JMPADDR(ep, PTC_MALINIT_JOUT);
319*4f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_MALINIT_JOUT, sizeof (addr));
320*4f364e7cSRobert Mustacchi bcopy(&csize, bp + PTC_MALINIT_MCS, sizeof (csize));
321*4f364e7cSRobert Mustacchi addr = PTC_JMPADDR(ep, PTC_MALINIT_JOV);
322*4f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_MALINIT_JOV, sizeof (addr));
323*4f364e7cSRobert Mustacchi bcopy(&off, bp + PTC_MALINIT_SOFF, sizeof (off));
324*4f364e7cSRobert Mustacchi
325*4f364e7cSRobert Mustacchi return (sizeof (malinit));
326*4f364e7cSRobert Mustacchi }
327*4f364e7cSRobert Mustacchi
328*4f364e7cSRobert Mustacchi static int
genasm_frinit(uint8_t * bp,uint32_t off,uint32_t dp,uint32_t ep,uint32_t mc)329*4f364e7cSRobert Mustacchi genasm_frinit(uint8_t *bp, uint32_t off, uint32_t dp, uint32_t ep, uint32_t mc)
330*4f364e7cSRobert Mustacchi {
331*4f364e7cSRobert Mustacchi uint32_t addr;
332*4f364e7cSRobert Mustacchi
333*4f364e7cSRobert Mustacchi bcopy(freeinit, bp, sizeof (freeinit));
334*4f364e7cSRobert Mustacchi addr = PTC_JMPADDR(dp, PTC_FRINI_JDONE);
335*4f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_FRINI_JDONE, sizeof (addr));
336*4f364e7cSRobert Mustacchi addr = PTC_JMPADDR(ep, PTC_FRINI_JFREE);
337*4f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_FRINI_JFREE, sizeof (addr));
338*4f364e7cSRobert Mustacchi bcopy(&mc, bp + PTC_FRINI_MCS, sizeof (mc));
339*4f364e7cSRobert Mustacchi addr = PTC_JMPADDR(ep, PTC_FRINI_JOV);
340*4f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_FRINI_JOV, sizeof (addr));
341*4f364e7cSRobert Mustacchi bcopy(&off, bp + PTC_FRINI_SOFF, sizeof (off));
342*4f364e7cSRobert Mustacchi return (sizeof (freeinit));
343*4f364e7cSRobert Mustacchi }
344*4f364e7cSRobert Mustacchi
345*4f364e7cSRobert Mustacchi /*
346*4f364e7cSRobert Mustacchi * Create the initial cache entry of the specified size. The value of ap tells
347*4f364e7cSRobert Mustacchi * us what the address of the label to try and allocate a buffer. This value is
348*4f364e7cSRobert Mustacchi * an offset from the current base to that value.
349*4f364e7cSRobert Mustacchi */
350*4f364e7cSRobert Mustacchi static int
genasm_firstcache(uint8_t * bp,uint32_t csize,uint32_t ap)351*4f364e7cSRobert Mustacchi genasm_firstcache(uint8_t *bp, uint32_t csize, uint32_t ap)
352*4f364e7cSRobert Mustacchi {
353*4f364e7cSRobert Mustacchi uint32_t addr;
354*4f364e7cSRobert Mustacchi
355*4f364e7cSRobert Mustacchi bcopy(inicache, bp, sizeof (inicache));
356*4f364e7cSRobert Mustacchi bcopy(&csize, bp + PTC_INICACHE_CMP, sizeof (csize));
357*4f364e7cSRobert Mustacchi bcopy(&csize, bp + PTC_INICACHE_SIZE, sizeof (csize));
358*4f364e7cSRobert Mustacchi addr = PTC_JMPADDR(ap, PTC_INICACHE_JMP);
359*4f364e7cSRobert Mustacchi ASSERT(addr != 0);
360*4f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_INICACHE_JMP, sizeof (addr));
361*4f364e7cSRobert Mustacchi
362*4f364e7cSRobert Mustacchi return (sizeof (inicache));
363*4f364e7cSRobert Mustacchi }
364*4f364e7cSRobert Mustacchi
365*4f364e7cSRobert Mustacchi static int
genasm_gencache(uint8_t * bp,int num,uint32_t csize,uint32_t ap)366*4f364e7cSRobert Mustacchi genasm_gencache(uint8_t *bp, int num, uint32_t csize, uint32_t ap)
367*4f364e7cSRobert Mustacchi {
368*4f364e7cSRobert Mustacchi uint32_t addr;
369*4f364e7cSRobert Mustacchi uint8_t coff;
370*4f364e7cSRobert Mustacchi
371*4f364e7cSRobert Mustacchi ASSERT(256 / PTC_ROOT_SIZE > num);
372*4f364e7cSRobert Mustacchi ASSERT(num != 0);
373*4f364e7cSRobert Mustacchi bcopy(gencache, bp, sizeof (gencache));
374*4f364e7cSRobert Mustacchi bcopy(&csize, bp + PTC_GENCACHE_CMP, sizeof (csize));
375*4f364e7cSRobert Mustacchi bcopy(&csize, bp + PTC_GENCACHE_SIZE, sizeof (csize));
376*4f364e7cSRobert Mustacchi coff = num * PTC_ROOT_SIZE;
377*4f364e7cSRobert Mustacchi bcopy(&coff, bp + PTC_GENCACHE_NUM, sizeof (coff));
378*4f364e7cSRobert Mustacchi addr = PTC_JMPADDR(ap, PTC_GENCACHE_JMP);
379*4f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_GENCACHE_JMP, sizeof (addr));
380*4f364e7cSRobert Mustacchi
381*4f364e7cSRobert Mustacchi return (sizeof (gencache));
382*4f364e7cSRobert Mustacchi }
383*4f364e7cSRobert Mustacchi
384*4f364e7cSRobert Mustacchi static int
genasm_lastcache(uint8_t * bp,int num,uint32_t csize,uint32_t ep)385*4f364e7cSRobert Mustacchi genasm_lastcache(uint8_t *bp, int num, uint32_t csize, uint32_t ep)
386*4f364e7cSRobert Mustacchi {
387*4f364e7cSRobert Mustacchi uint8_t addr;
388*4f364e7cSRobert Mustacchi
389*4f364e7cSRobert Mustacchi ASSERT(ep <= 0xff && ep > 7);
390*4f364e7cSRobert Mustacchi ASSERT(256 / PTC_ROOT_SIZE > num);
391*4f364e7cSRobert Mustacchi bcopy(fincache, bp, sizeof (fincache));
392*4f364e7cSRobert Mustacchi bcopy(&csize, bp + PTC_FINCACHE_CMP, sizeof (csize));
393*4f364e7cSRobert Mustacchi bcopy(&csize, bp + PTC_FINCACHE_SIZE, sizeof (csize));
394*4f364e7cSRobert Mustacchi addr = num * PTC_ROOT_SIZE;
395*4f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_FINCACHE_NUM, sizeof (addr));
396*4f364e7cSRobert Mustacchi addr = ep - PTC_FINCACHE_JMP - 1;
397*4f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_FINCACHE_JMP, sizeof (addr));
398*4f364e7cSRobert Mustacchi
399*4f364e7cSRobert Mustacchi return (sizeof (fincache));
400*4f364e7cSRobert Mustacchi }
401*4f364e7cSRobert Mustacchi
402*4f364e7cSRobert Mustacchi static int
genasm_malfini(uint8_t * bp,uintptr_t mptr)403*4f364e7cSRobert Mustacchi genasm_malfini(uint8_t *bp, uintptr_t mptr)
404*4f364e7cSRobert Mustacchi {
405*4f364e7cSRobert Mustacchi uint32_t addr;
406*4f364e7cSRobert Mustacchi
407*4f364e7cSRobert Mustacchi bcopy(malfini, bp, sizeof (malfini));
408*4f364e7cSRobert Mustacchi addr = PTC_JMPADDR(mptr, ((uintptr_t)bp + PTC_MALFINI_JMADDR));
409*4f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_MALFINI_JMADDR, sizeof (addr));
410*4f364e7cSRobert Mustacchi
411*4f364e7cSRobert Mustacchi return (sizeof (malfini));
412*4f364e7cSRobert Mustacchi }
413*4f364e7cSRobert Mustacchi
414*4f364e7cSRobert Mustacchi static int
genasm_frfini(uint8_t * bp,uint32_t maxthr,uintptr_t fptr)415*4f364e7cSRobert Mustacchi genasm_frfini(uint8_t *bp, uint32_t maxthr, uintptr_t fptr)
416*4f364e7cSRobert Mustacchi {
417*4f364e7cSRobert Mustacchi uint32_t addr;
418*4f364e7cSRobert Mustacchi
419*4f364e7cSRobert Mustacchi bcopy(freefini, bp, sizeof (freefini));
420*4f364e7cSRobert Mustacchi bcopy(&maxthr, bp + PTC_FRFINI_CACHEMAX, sizeof (maxthr));
421*4f364e7cSRobert Mustacchi addr = PTC_JMPADDR(fptr, ((uintptr_t)bp + PTC_FRFINI_JFADDR));
422*4f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_FRFINI_JFADDR, sizeof (addr));
423*4f364e7cSRobert Mustacchi
424*4f364e7cSRobert Mustacchi return (sizeof (freefini));
425*4f364e7cSRobert Mustacchi }
426*4f364e7cSRobert Mustacchi
427*4f364e7cSRobert Mustacchi /*
428*4f364e7cSRobert Mustacchi * The malloc inline assembly is constructed as follows:
429*4f364e7cSRobert Mustacchi *
430*4f364e7cSRobert Mustacchi * o Malloc prologue assembly
431*4f364e7cSRobert Mustacchi * o Generic first-cache check
432*4f364e7cSRobert Mustacchi * o n Generic cache checks (where n = _tmem_get_entries() - 2)
433*4f364e7cSRobert Mustacchi * o Generic last-cache check
434*4f364e7cSRobert Mustacchi * o Malloc epilogue assembly
435*4f364e7cSRobert Mustacchi *
436*4f364e7cSRobert Mustacchi * Generally there are at least three caches. When there is only one cache we
437*4f364e7cSRobert Mustacchi * only use the generic last-cache. In the case where there are two caches, we
438*4f364e7cSRobert Mustacchi * just leave out the middle ones.
439*4f364e7cSRobert Mustacchi */
440*4f364e7cSRobert Mustacchi static int
genasm_malloc(void * base,size_t len,int nents,int * umem_alloc_sizes)441*4f364e7cSRobert Mustacchi genasm_malloc(void *base, size_t len, int nents, int *umem_alloc_sizes)
442*4f364e7cSRobert Mustacchi {
443*4f364e7cSRobert Mustacchi int ii, off;
444*4f364e7cSRobert Mustacchi uint8_t *bp;
445*4f364e7cSRobert Mustacchi size_t total;
446*4f364e7cSRobert Mustacchi uint32_t allocoff, erroff;
447*4f364e7cSRobert Mustacchi
448*4f364e7cSRobert Mustacchi total = sizeof (malinit) + sizeof (malfini) + sizeof (fincache);
449*4f364e7cSRobert Mustacchi
450*4f364e7cSRobert Mustacchi if (nents >= 2)
451*4f364e7cSRobert Mustacchi total += sizeof (inicache) + sizeof (gencache) * (nents - 2);
452*4f364e7cSRobert Mustacchi
453*4f364e7cSRobert Mustacchi if (total > len)
454*4f364e7cSRobert Mustacchi return (1);
455*4f364e7cSRobert Mustacchi
456*4f364e7cSRobert Mustacchi erroff = total - sizeof (malfini) + PTC_MALFINI_JMLABEL;
457*4f364e7cSRobert Mustacchi allocoff = total - sizeof (malfini) + PTC_MALFINI_ALLABEL;
458*4f364e7cSRobert Mustacchi
459*4f364e7cSRobert Mustacchi bp = base;
460*4f364e7cSRobert Mustacchi
461*4f364e7cSRobert Mustacchi off = genasm_malinit(bp, umem_tmem_off, erroff,
462*4f364e7cSRobert Mustacchi umem_alloc_sizes[nents-1]);
463*4f364e7cSRobert Mustacchi bp += off;
464*4f364e7cSRobert Mustacchi allocoff -= off;
465*4f364e7cSRobert Mustacchi erroff -= off;
466*4f364e7cSRobert Mustacchi
467*4f364e7cSRobert Mustacchi if (nents > 1) {
468*4f364e7cSRobert Mustacchi off = genasm_firstcache(bp, umem_alloc_sizes[0], allocoff);
469*4f364e7cSRobert Mustacchi bp += off;
470*4f364e7cSRobert Mustacchi allocoff -= off;
471*4f364e7cSRobert Mustacchi erroff -= off;
472*4f364e7cSRobert Mustacchi }
473*4f364e7cSRobert Mustacchi
474*4f364e7cSRobert Mustacchi for (ii = 1; ii < nents - 1; ii++) {
475*4f364e7cSRobert Mustacchi off = genasm_gencache(bp, ii, umem_alloc_sizes[ii], allocoff);
476*4f364e7cSRobert Mustacchi bp += off;
477*4f364e7cSRobert Mustacchi allocoff -= off;
478*4f364e7cSRobert Mustacchi erroff -= off;
479*4f364e7cSRobert Mustacchi }
480*4f364e7cSRobert Mustacchi
481*4f364e7cSRobert Mustacchi bp += genasm_lastcache(bp, nents - 1, umem_alloc_sizes[nents - 1],
482*4f364e7cSRobert Mustacchi erroff);
483*4f364e7cSRobert Mustacchi bp += genasm_malfini(bp, umem_genasm_omptr);
484*4f364e7cSRobert Mustacchi ASSERT(((uintptr_t)bp - total) == (uintptr_t)base);
485*4f364e7cSRobert Mustacchi
486*4f364e7cSRobert Mustacchi return (0);
487*4f364e7cSRobert Mustacchi }
488*4f364e7cSRobert Mustacchi
489*4f364e7cSRobert Mustacchi static int
genasm_free(void * base,size_t len,int nents,int * umem_alloc_sizes)490*4f364e7cSRobert Mustacchi genasm_free(void *base, size_t len, int nents, int *umem_alloc_sizes)
491*4f364e7cSRobert Mustacchi {
492*4f364e7cSRobert Mustacchi uint8_t *bp;
493*4f364e7cSRobert Mustacchi int ii, off;
494*4f364e7cSRobert Mustacchi size_t total;
495*4f364e7cSRobert Mustacchi uint32_t rbufoff, retoff, erroff;
496*4f364e7cSRobert Mustacchi
497*4f364e7cSRobert Mustacchi /* Assume that nents has already been audited for us */
498*4f364e7cSRobert Mustacchi total = sizeof (freeinit) + sizeof (freefini) + sizeof (fincache);
499*4f364e7cSRobert Mustacchi if (nents >= 2)
500*4f364e7cSRobert Mustacchi total += sizeof (inicache) + sizeof (gencache) * (nents - 2);
501*4f364e7cSRobert Mustacchi
502*4f364e7cSRobert Mustacchi if (total > len)
503*4f364e7cSRobert Mustacchi return (1);
504*4f364e7cSRobert Mustacchi
505*4f364e7cSRobert Mustacchi erroff = total - (sizeof (freefini) - PTC_FRFINI_JFLABEL);
506*4f364e7cSRobert Mustacchi rbufoff = total - (sizeof (freefini) - PTC_FRFINI_RBUFLABEL);
507*4f364e7cSRobert Mustacchi retoff = total - (sizeof (freefini) - PTC_FRFINI_DONELABEL);
508*4f364e7cSRobert Mustacchi
509*4f364e7cSRobert Mustacchi bp = base;
510*4f364e7cSRobert Mustacchi
511*4f364e7cSRobert Mustacchi off = genasm_frinit(bp, umem_tmem_off, retoff, erroff,
512*4f364e7cSRobert Mustacchi umem_alloc_sizes[nents - 1]);
513*4f364e7cSRobert Mustacchi bp += off;
514*4f364e7cSRobert Mustacchi erroff -= off;
515*4f364e7cSRobert Mustacchi rbufoff -= off;
516*4f364e7cSRobert Mustacchi
517*4f364e7cSRobert Mustacchi if (nents > 1) {
518*4f364e7cSRobert Mustacchi off = genasm_firstcache(bp, umem_alloc_sizes[0], rbufoff);
519*4f364e7cSRobert Mustacchi bp += off;
520*4f364e7cSRobert Mustacchi erroff -= off;
521*4f364e7cSRobert Mustacchi rbufoff -= off;
522*4f364e7cSRobert Mustacchi }
523*4f364e7cSRobert Mustacchi
524*4f364e7cSRobert Mustacchi for (ii = 1; ii < nents - 1; ii++) {
525*4f364e7cSRobert Mustacchi off = genasm_gencache(bp, ii, umem_alloc_sizes[ii], rbufoff);
526*4f364e7cSRobert Mustacchi bp += off;
527*4f364e7cSRobert Mustacchi rbufoff -= off;
528*4f364e7cSRobert Mustacchi erroff -= off;
529*4f364e7cSRobert Mustacchi }
530*4f364e7cSRobert Mustacchi
531*4f364e7cSRobert Mustacchi bp += genasm_lastcache(bp, nents - 1, umem_alloc_sizes[nents - 1],
532*4f364e7cSRobert Mustacchi erroff);
533*4f364e7cSRobert Mustacchi bp += genasm_frfini(bp, umem_ptc_size, umem_genasm_ofptr);
534*4f364e7cSRobert Mustacchi ASSERT(((uintptr_t)bp - total) == (uintptr_t)base);
535*4f364e7cSRobert Mustacchi
536*4f364e7cSRobert Mustacchi return (0);
537*4f364e7cSRobert Mustacchi }
538*4f364e7cSRobert Mustacchi
539*4f364e7cSRobert Mustacchi int
umem_genasm(int * alloc_sizes,umem_cache_t ** caches,int ncaches)540*4f364e7cSRobert Mustacchi umem_genasm(int *alloc_sizes, umem_cache_t **caches, int ncaches)
541*4f364e7cSRobert Mustacchi {
542*4f364e7cSRobert Mustacchi int nents, i;
543*4f364e7cSRobert Mustacchi uint8_t *mptr;
544*4f364e7cSRobert Mustacchi uint8_t *fptr;
545*4f364e7cSRobert Mustacchi uint64_t v, *vptr;
546*4f364e7cSRobert Mustacchi
547*4f364e7cSRobert Mustacchi mptr = (void *)((uintptr_t)umem_genasm_mptr + 5);
548*4f364e7cSRobert Mustacchi fptr = (void *)((uintptr_t)umem_genasm_fptr + 5);
549*4f364e7cSRobert Mustacchi if (umem_genasm_mptr == 0 || umem_genasm_msize == 0 ||
550*4f364e7cSRobert Mustacchi umem_genasm_fptr == 0 || umem_genasm_fsize == 0)
551*4f364e7cSRobert Mustacchi return (1);
552*4f364e7cSRobert Mustacchi
553*4f364e7cSRobert Mustacchi /*
554*4f364e7cSRobert Mustacchi * The total number of caches that we can service is the minimum of:
555*4f364e7cSRobert Mustacchi * o the amount supported by libc
556*4f364e7cSRobert Mustacchi * o the total number of umem caches
557*4f364e7cSRobert Mustacchi * o we use a single byte addl, so it's 255 / sizeof (uintptr_t). For
558*4f364e7cSRobert Mustacchi * 32-bit, this is 63.
559*4f364e7cSRobert Mustacchi */
560*4f364e7cSRobert Mustacchi nents = _tmem_get_nentries();
561*4f364e7cSRobert Mustacchi
562*4f364e7cSRobert Mustacchi if (UMEM_GENASM_MAX32 < nents)
563*4f364e7cSRobert Mustacchi nents = UMEM_GENASM_MAX32;
564*4f364e7cSRobert Mustacchi
565*4f364e7cSRobert Mustacchi if (ncaches < nents)
566*4f364e7cSRobert Mustacchi nents = ncaches;
567*4f364e7cSRobert Mustacchi
568*4f364e7cSRobert Mustacchi /* Based on our constraints, this is not an error */
569*4f364e7cSRobert Mustacchi if (nents == 0 || umem_ptc_size == 0)
570*4f364e7cSRobert Mustacchi return (0);
571*4f364e7cSRobert Mustacchi
572*4f364e7cSRobert Mustacchi /* Take into account the jump */
573*4f364e7cSRobert Mustacchi if (genasm_malloc(mptr, umem_genasm_msize, nents,
574*4f364e7cSRobert Mustacchi alloc_sizes) != 0)
575*4f364e7cSRobert Mustacchi return (1);
576*4f364e7cSRobert Mustacchi
577*4f364e7cSRobert Mustacchi if (genasm_free(fptr, umem_genasm_fsize, nents,
578*4f364e7cSRobert Mustacchi alloc_sizes) != 0)
579*4f364e7cSRobert Mustacchi return (1);
580*4f364e7cSRobert Mustacchi
581*4f364e7cSRobert Mustacchi /* nop out the jump with a multibyte jump */
582*4f364e7cSRobert Mustacchi vptr = (void *)umem_genasm_mptr;
583*4f364e7cSRobert Mustacchi v = MULTINOP;
584*4f364e7cSRobert Mustacchi v |= *vptr & (0xffffffULL << 40);
585*4f364e7cSRobert Mustacchi (void) atomic_swap_64(vptr, v);
586*4f364e7cSRobert Mustacchi vptr = (void *)umem_genasm_fptr;
587*4f364e7cSRobert Mustacchi v = MULTINOP;
588*4f364e7cSRobert Mustacchi v |= *vptr & (0xffffffULL << 40);
589*4f364e7cSRobert Mustacchi (void) atomic_swap_64(vptr, v);
590*4f364e7cSRobert Mustacchi
591*4f364e7cSRobert Mustacchi for (i = 0; i < nents; i++)
592*4f364e7cSRobert Mustacchi caches[i]->cache_flags |= UMF_PTC;
593*4f364e7cSRobert Mustacchi
594*4f364e7cSRobert Mustacchi return (0);
595*4f364e7cSRobert Mustacchi }
596