14f364e7cSRobert Mustacchi /*
24f364e7cSRobert Mustacchi * CDDL HEADER START
34f364e7cSRobert Mustacchi *
44f364e7cSRobert Mustacchi * The contents of this file are subject to the terms of the
54f364e7cSRobert Mustacchi * Common Development and Distribution License (the "License").
64f364e7cSRobert Mustacchi * You may not use this file except in compliance with the License.
74f364e7cSRobert Mustacchi *
84f364e7cSRobert Mustacchi * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
94f364e7cSRobert Mustacchi * or http://www.opensolaris.org/os/licensing.
104f364e7cSRobert Mustacchi * See the License for the specific language governing permissions
114f364e7cSRobert Mustacchi * and limitations under the License.
124f364e7cSRobert Mustacchi *
134f364e7cSRobert Mustacchi * When distributing Covered Code, include this CDDL HEADER in each
144f364e7cSRobert Mustacchi * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
154f364e7cSRobert Mustacchi * If applicable, add the following below this CDDL HEADER, with the
164f364e7cSRobert Mustacchi * fields enclosed by brackets "[]" replaced with your own identifying
174f364e7cSRobert Mustacchi * information: Portions Copyright [yyyy] [name of copyright owner]
184f364e7cSRobert Mustacchi *
194f364e7cSRobert Mustacchi * CDDL HEADER END
204f364e7cSRobert Mustacchi */
214f364e7cSRobert Mustacchi /*
22*b1e2e3fbSRobert Mustacchi * Copyright (c) 2019 Joyent, Inc. All rights reserved.
234f364e7cSRobert Mustacchi */
244f364e7cSRobert Mustacchi
254f364e7cSRobert Mustacchi /*
264f364e7cSRobert Mustacchi * Don't Panic! If you find the blocks of assembly that follow confusing and
274f364e7cSRobert Mustacchi * you're questioning why they exist, please go read section 8 of the umem.c big
284f364e7cSRobert Mustacchi * theory statement. Next familiarize yourself with the malloc and free
294f364e7cSRobert Mustacchi * implementations in libumem's malloc.c.
304f364e7cSRobert Mustacchi *
314f364e7cSRobert Mustacchi * What follows is the i386 implementation of the thread caching automatic
324f364e7cSRobert Mustacchi * assembly generation. With i386 a function only has three registers it's
334f364e7cSRobert Mustacchi * allowed to change without restoring them: eax, ecx, and edx. All others have
344f364e7cSRobert Mustacchi * to be preserved. Since the set of registers we have available is so small, we
354f364e7cSRobert Mustacchi * have to make use of esi, ebx, and edi and save their original values to the
364f364e7cSRobert Mustacchi * stack.
374f364e7cSRobert Mustacchi *
384f364e7cSRobert Mustacchi * Malloc register usage:
394f364e7cSRobert Mustacchi * o. esi: Size of the malloc (passed into us and modified)
404f364e7cSRobert Mustacchi * o. edi: Size of the cache
414f364e7cSRobert Mustacchi * o. eax: Buffer to return
424f364e7cSRobert Mustacchi * o. ebx: Scratch space and temporary values
434f364e7cSRobert Mustacchi * o. ecx: Pointer to the tmem_t in the ulwp_t.
444f364e7cSRobert Mustacchi * o. edx: Pointer to the tmem_t array of roots
454f364e7cSRobert Mustacchi *
464f364e7cSRobert Mustacchi * Free register usage:
474f364e7cSRobert Mustacchi * o. esi: Size of the malloc (passed into us and modified)
484f364e7cSRobert Mustacchi * o. edi: Size of the cache
494f364e7cSRobert Mustacchi * o. eax: Buffer to free
504f364e7cSRobert Mustacchi * o. ebx: Scratch space and temporary values
514f364e7cSRobert Mustacchi * o. ecx: Pointer to the tmem_t in the ulwp_t.
524f364e7cSRobert Mustacchi * o. edx: Pointer to the tmem_t array of roots
534f364e7cSRobert Mustacchi *
544f364e7cSRobert Mustacchi * Once we determine what cache we are using, we increment %edx to the
554f364e7cSRobert Mustacchi * appropriate offset and set %edi with the size of the cache. This means that
564f364e7cSRobert Mustacchi * when we break out to the normal buffer allocation point %edx contains the
574f364e7cSRobert Mustacchi * head of the linked list and %edi is the amount that we have to adjust the
584f364e7cSRobert Mustacchi * total amount cached by the thread.
594f364e7cSRobert Mustacchi *
604f364e7cSRobert Mustacchi * Each block of assembly has psuedocode that describes its purpose.
614f364e7cSRobert Mustacchi */
624f364e7cSRobert Mustacchi
63*b1e2e3fbSRobert Mustacchi /*
64*b1e2e3fbSRobert Mustacchi * umem_base must be first.
65*b1e2e3fbSRobert Mustacchi */
66*b1e2e3fbSRobert Mustacchi #include "umem_base.h"
67*b1e2e3fbSRobert Mustacchi
684f364e7cSRobert Mustacchi #include <inttypes.h>
694f364e7cSRobert Mustacchi #include <strings.h>
704f364e7cSRobert Mustacchi #include <umem_impl.h>
714f364e7cSRobert Mustacchi #include <atomic.h>
72*b1e2e3fbSRobert Mustacchi #include <sys/mman.h>
73*b1e2e3fbSRobert Mustacchi #include <errno.h>
744f364e7cSRobert Mustacchi
754f364e7cSRobert Mustacchi const int umem_genasm_supported = 1;
764f364e7cSRobert Mustacchi static uintptr_t umem_genasm_mptr = (uintptr_t)&_malloc;
774f364e7cSRobert Mustacchi static size_t umem_genasm_msize = 512;
784f364e7cSRobert Mustacchi static uintptr_t umem_genasm_fptr = (uintptr_t)&_free;
794f364e7cSRobert Mustacchi static size_t umem_genasm_fsize = 512;
804f364e7cSRobert Mustacchi static uintptr_t umem_genasm_omptr = (uintptr_t)umem_malloc;
814f364e7cSRobert Mustacchi static uintptr_t umem_genasm_ofptr = (uintptr_t)umem_malloc_free;
824f364e7cSRobert Mustacchi /*
834f364e7cSRobert Mustacchi * The maximum number of caches we can support. We use a single byte addl so
844f364e7cSRobert Mustacchi * this is 255 (UINT8_MAX) / sizeof (uintptr_t). In this case 63
854f364e7cSRobert Mustacchi */
864f364e7cSRobert Mustacchi #define UMEM_GENASM_MAX32 63
874f364e7cSRobert Mustacchi
884f364e7cSRobert Mustacchi #define PTC_JMPADDR(dest, src) (dest - (src + 4))
894f364e7cSRobert Mustacchi #define PTC_ROOT_SIZE sizeof (uintptr_t)
904f364e7cSRobert Mustacchi #define MULTINOP 0x0000441f0f
914f364e7cSRobert Mustacchi
924f364e7cSRobert Mustacchi /*
934f364e7cSRobert Mustacchi * void *ptcmalloc(size_t orig_size);
944f364e7cSRobert Mustacchi *
954f364e7cSRobert Mustacchi * size_t size = orig_size + 8;
964f364e7cSRobert Mustacchi *
974f364e7cSRobert Mustacchi * if (size < orig_size)
984f364e7cSRobert Mustacchi * goto tomalloc; ! This is overflow
994f364e7cSRobert Mustacchi *
1004f364e7cSRobert Mustacchi * if (size > cache_size)
1014f364e7cSRobert Mustacchi * goto tomalloc;
1024f364e7cSRobert Mustacchi *
1034f364e7cSRobert Mustacchi * tmem_t *t = (uintptr_t)curthread() + umem_thr_offset;
1044f364e7cSRobert Mustacchi * void **roots = t->tm_roots;
1054f364e7cSRobert Mustacchi */
1064f364e7cSRobert Mustacchi #define PTC_MALINIT_JOUT 0x0e
1074f364e7cSRobert Mustacchi #define PTC_MALINIT_MCS 0x14
1084f364e7cSRobert Mustacchi #define PTC_MALINIT_JOV 0x1a
1094f364e7cSRobert Mustacchi #define PTC_MALINIT_SOFF 0x27
1104f364e7cSRobert Mustacchi static const uint8_t malinit[] = {
1114f364e7cSRobert Mustacchi 0x55, /* pushl %ebp */
1124f364e7cSRobert Mustacchi 0x89, 0xe5, /* movl %esp, %ebp */
1134f364e7cSRobert Mustacchi 0x57, /* pushl %edi */
1144f364e7cSRobert Mustacchi 0x56, /* pushl %esi */
1154f364e7cSRobert Mustacchi 0x53, /* pushl %ebx */
1164f364e7cSRobert Mustacchi 0x8b, 0x75, 0x08, /* movl 0x8(%ebp), %esi */
1174f364e7cSRobert Mustacchi 0x83, 0xc6, 0x08, /* addl $0x8,%esi */
1184f364e7cSRobert Mustacchi 0x0f, 0x82, 0x00, 0x00, 0x00, 0x00, /* jc +$JMP (errout) */
1194f364e7cSRobert Mustacchi 0x81, 0xfe, 0x00, 0x00, 0x00, 0x00, /* cmpl sizeof ($C0), %esi */
1204f364e7cSRobert Mustacchi 0x0f, 0x87, 0x00, 0x00, 0x00, 0x00, /* ja +$JMP (errout) */
1214f364e7cSRobert Mustacchi 0x65, 0x8b, 0x0d, 0x00, 0x00, 0x00, 0x00, /* movl %gs:0x0,%ecx */
1224f364e7cSRobert Mustacchi 0x81, 0xc1, 0x00, 0x00, 0x00, 0x00, /* addl $OFF, %ecx */
1234f364e7cSRobert Mustacchi 0x8d, 0x51, 0x04 /* leal 0x4(%ecx), %edx */
1244f364e7cSRobert Mustacchi };
1254f364e7cSRobert Mustacchi
1264f364e7cSRobert Mustacchi /*
1274f364e7cSRobert Mustacchi * void ptcfree(void *buf);
1284f364e7cSRobert Mustacchi *
1294f364e7cSRobert Mustacchi * if (buf == NULL)
1304f364e7cSRobert Mustacchi * return;
1314f364e7cSRobert Mustacchi *
1324f364e7cSRobert Mustacchi * malloc_data_t *tag = buf;
1334f364e7cSRobert Mustacchi * tag--;
1344f364e7cSRobert Mustacchi * int size = tag->malloc_size;
1354f364e7cSRobert Mustacchi * int tagtval = UMEM_MALLOC_DECODE(tag->malloc_tag, size);
1364f364e7cSRobert Mustacchi *
1374f364e7cSRobert Mustacchi * if (tagval != MALLOC_MAGIC)
1384f364e7cSRobert Mustacchi * goto tofree;
1394f364e7cSRobert Mustacchi *
1404f364e7cSRobert Mustacchi * if (size > cache_max)
1414f364e7cSRobert Mustacchi * goto tofree;
1424f364e7cSRobert Mustacchi *
1434f364e7cSRobert Mustacchi * tmem_t *t = (uintptr_t)curthread() + umem_thr_offset;
1444f364e7cSRobert Mustacchi * void **roots = t->tm_roots;
1454f364e7cSRobert Mustacchi */
1464f364e7cSRobert Mustacchi #define PTC_FRINI_JDONE 0x0d
1474f364e7cSRobert Mustacchi #define PTC_FRINI_JFREE 0x23
1484f364e7cSRobert Mustacchi #define PTC_FRINI_MCS 0x29
1494f364e7cSRobert Mustacchi #define PTC_FRINI_JOV 0x2f
1504f364e7cSRobert Mustacchi #define PTC_FRINI_SOFF 0x3c
1514f364e7cSRobert Mustacchi static const uint8_t freeinit[] = {
1524f364e7cSRobert Mustacchi 0x55, /* pushl %ebp */
1534f364e7cSRobert Mustacchi 0x89, 0xe5, /* movl %esp, %ebp */
1544f364e7cSRobert Mustacchi 0x57, /* pushl %edi */
1554f364e7cSRobert Mustacchi 0x56, /* pushl %esi */
1564f364e7cSRobert Mustacchi 0x53, /* pushl %ebx */
1574f364e7cSRobert Mustacchi 0x8b, 0x45, 0x08, /* movl 0x8(%ebp), %eax */
1584f364e7cSRobert Mustacchi 0x85, 0xc0, /* testl %eax, %eax */
1594f364e7cSRobert Mustacchi 0x0f, 0x84, 0x00, 0x00, 0x00, 0x00, /* je $JDONE (done) */
1604f364e7cSRobert Mustacchi 0x83, 0xe8, 0x08, /* subl $0x8,%eax */
1614f364e7cSRobert Mustacchi 0x8b, 0x30, /* movl (%eax),%esi */
1624f364e7cSRobert Mustacchi 0x8b, 0x50, 0x04, /* movl 0x4(%eax),%edx */
1634f364e7cSRobert Mustacchi 0x01, 0xf2, /* addl %esi,%edx */
1644f364e7cSRobert Mustacchi 0x81, 0xfa, 0x00, 0xc0, 0x10, 0x3a, /* cmpl MAGIC32, %edx */
1654f364e7cSRobert Mustacchi 0x0f, 0x85, 0x00, 0x00, 0x00, 0x00, /* jne +JFREE (goto freebuf) */
1664f364e7cSRobert Mustacchi
1674f364e7cSRobert Mustacchi 0x81, 0xfe, 0x00, 0x00, 0x00, 0x00, /* cmpl sizeof ($C0), %esi */
1684f364e7cSRobert Mustacchi 0x0f, 0x87, 0x00, 0x00, 0x00, 0x00, /* ja +$JMP (errout) */
1694f364e7cSRobert Mustacchi 0x65, 0x8b, 0x0d, 0x00, 0x0, 0x00, 0x00, /* movl %gs:0x0,%ecx */
1704f364e7cSRobert Mustacchi 0x81, 0xc1, 0x00, 0x00, 0x00, 0x00, /* addl $0xOFF, %ecx */
1714f364e7cSRobert Mustacchi 0x8d, 0x51, 0x04 /* leal 0x4(%ecx),%edx */
1724f364e7cSRobert Mustacchi };
1734f364e7cSRobert Mustacchi
1744f364e7cSRobert Mustacchi /*
1754f364e7cSRobert Mustacchi * if (size <= $CACHE_SIZE) {
1764f364e7cSRobert Mustacchi * csize = $CACHE_SIZE;
1774f364e7cSRobert Mustacchi * } else ... ! goto next cache
1784f364e7cSRobert Mustacchi */
1794f364e7cSRobert Mustacchi #define PTC_INICACHE_CMP 0x02
1804f364e7cSRobert Mustacchi #define PTC_INICACHE_SIZE 0x09
1814f364e7cSRobert Mustacchi #define PTC_INICACHE_JMP 0x0e
1824f364e7cSRobert Mustacchi static const uint8_t inicache[] = {
1834f364e7cSRobert Mustacchi 0x81, 0xfe, 0xff, 0x00, 0x00, 0x00, /* cmpl sizeof ($C0), %esi */
1844f364e7cSRobert Mustacchi 0x77, 0x0a, /* ja +0xa */
1854f364e7cSRobert Mustacchi 0xbf, 0xff, 0x00, 0x00, 0x00, /* movl sizeof ($C0), %edi */
1864f364e7cSRobert Mustacchi 0xe9, 0x00, 0x00, 0x00, 0x00 /* jmp +$JMP (allocbuf) */
1874f364e7cSRobert Mustacchi };
1884f364e7cSRobert Mustacchi
1894f364e7cSRobert Mustacchi /*
1904f364e7cSRobert Mustacchi * if (size <= $CACHE_SIZE) {
1914f364e7cSRobert Mustacchi * csize = $CACHE_SIZE;
1924f364e7cSRobert Mustacchi * roots += $CACHE_NUM;
1934f364e7cSRobert Mustacchi * } else ... ! goto next cache
1944f364e7cSRobert Mustacchi */
1954f364e7cSRobert Mustacchi #define PTC_GENCACHE_CMP 0x02
1964f364e7cSRobert Mustacchi #define PTC_GENCACHE_NUM 0x0a
1974f364e7cSRobert Mustacchi #define PTC_GENCACHE_SIZE 0x0c
1984f364e7cSRobert Mustacchi #define PTC_GENCACHE_JMP 0x11
1994f364e7cSRobert Mustacchi static const uint8_t gencache[] = {
2004f364e7cSRobert Mustacchi 0x81, 0xfe, 0x00, 0x00, 0x00, 0x00, /* cmpl sizeof ($CACHE), %esi */
2014f364e7cSRobert Mustacchi 0x77, 0x0d, /* ja +0xd (next cache) */
2024f364e7cSRobert Mustacchi 0x83, 0xc2, 0x00, /* addl $4*$ii, %edx */
2034f364e7cSRobert Mustacchi 0xbf, 0x00, 0x00, 0x00, 0x00, /* movl sizeof ($CACHE), %edi */
2044f364e7cSRobert Mustacchi 0xe9, 0x00, 0x00, 0x00, 0x00 /* jmp +$JMP (allocbuf) */
2054f364e7cSRobert Mustacchi };
2064f364e7cSRobert Mustacchi
2074f364e7cSRobert Mustacchi /*
2084f364e7cSRobert Mustacchi * else if (size <= $CACHE_SIZE) {
2094f364e7cSRobert Mustacchi * csize = $CACHE_SIZE;
2104f364e7cSRobert Mustacchi * roots += $CACHE_NUM;
2114f364e7cSRobert Mustacchi * } else {
2124f364e7cSRobert Mustacchi * goto tofunc; ! goto tomalloc if ptcmalloc.
2134f364e7cSRobert Mustacchi * } ! goto tofree if ptcfree.
2144f364e7cSRobert Mustacchi */
2154f364e7cSRobert Mustacchi #define PTC_FINCACHE_CMP 0x02
2164f364e7cSRobert Mustacchi #define PTC_FINCACHE_JMP 0x07
2174f364e7cSRobert Mustacchi #define PTC_FINCACHE_NUM 0x0a
2184f364e7cSRobert Mustacchi #define PTC_FINCACHE_SIZE 0x0c
2194f364e7cSRobert Mustacchi static const uint8_t fincache[] = {
2204f364e7cSRobert Mustacchi 0x81, 0xfe, 0xff, 0x00, 0x00, 0x00, /* cmpl sizeof ($CLAST), %esi */
2214f364e7cSRobert Mustacchi 0x77, 0x00, /* ja +$JMP (to errout) */
2224f364e7cSRobert Mustacchi 0x83, 0xc2, 0x00, /* addl $4*($NCACHES-1), %edx */
2234f364e7cSRobert Mustacchi 0xbf, 0x00, 0x00, 0x00, 0x00, /* movl sizeof ($CLAST), %edi */
2244f364e7cSRobert Mustacchi };
2254f364e7cSRobert Mustacchi
2264f364e7cSRobert Mustacchi /*
2274f364e7cSRobert Mustacchi * if (*root == NULL)
2284f364e7cSRobert Mustacchi * goto tomalloc;
2294f364e7cSRobert Mustacchi *
2304f364e7cSRobert Mustacchi * malloc_data_t *ret = *root;
2314f364e7cSRobert Mustacchi * *root = *(void **)ret;
2324f364e7cSRobert Mustacchi * t->tm_size += csize;
2334f364e7cSRobert Mustacchi * ret->malloc_size = size;
2344f364e7cSRobert Mustacchi *
2354f364e7cSRobert Mustacchi * ret->malloc_data = UMEM_MALLOC_ENCODE(MALLOC_SECOND_MAGIC, size);
2364f364e7cSRobert Mustacchi * ret++;
2374f364e7cSRobert Mustacchi *
2384f364e7cSRobert Mustacchi * return ((void *)ret);
2394f364e7cSRobert Mustacchi * tomalloc:
2404f364e7cSRobert Mustacchi * return (malloc(orig_size));
2414f364e7cSRobert Mustacchi */
2424f364e7cSRobert Mustacchi #define PTC_MALFINI_ALLABEL 0x00
2434f364e7cSRobert Mustacchi #define PTC_MALFINI_JMLABEL 0x20
2444f364e7cSRobert Mustacchi #define PTC_MALFINI_JMADDR 0x25
2454f364e7cSRobert Mustacchi static const uint8_t malfini[] = {
2464f364e7cSRobert Mustacchi /* allocbuf: */
2474f364e7cSRobert Mustacchi 0x8b, 0x02, /* movl (%edx), %eax */
2484f364e7cSRobert Mustacchi 0x85, 0xc0, /* testl %eax, %eax */
2494f364e7cSRobert Mustacchi 0x74, 0x1a, /* je +0x1a (errout) */
2504f364e7cSRobert Mustacchi 0x8b, 0x18, /* movl (%eax), %esi */
2514f364e7cSRobert Mustacchi 0x89, 0x1a, /* movl %esi, (%edx) */
2524f364e7cSRobert Mustacchi 0x29, 0x39, /* subl %edi, (%ecx) */
2534f364e7cSRobert Mustacchi 0x89, 0x30, /* movl %esi, ($eax) */
2544f364e7cSRobert Mustacchi 0xba, 0x00, 0xc0, 0x10, 0x3a, /* movl $0x3a10c000,%edx */
2554f364e7cSRobert Mustacchi 0x29, 0xf2, /* subl %esi, %edx */
2564f364e7cSRobert Mustacchi 0x89, 0x50, 0x04, /* movl %edx, 0x4(%eax) */
2574f364e7cSRobert Mustacchi 0x83, 0xc0, 0x08, /* addl %0x8, %eax */
2584f364e7cSRobert Mustacchi 0x5b, /* popl %ebx */
2594f364e7cSRobert Mustacchi 0x5e, /* popl %esi */
2604f364e7cSRobert Mustacchi 0x5f, /* popl %edi */
2614f364e7cSRobert Mustacchi 0xc9, /* leave */
2624f364e7cSRobert Mustacchi 0xc3, /* ret */
2634f364e7cSRobert Mustacchi /* errout: */
2644f364e7cSRobert Mustacchi 0x5b, /* popl %ebx */
2654f364e7cSRobert Mustacchi 0x5e, /* popl %esi */
2664f364e7cSRobert Mustacchi 0x5f, /* popl %edi */
2674f364e7cSRobert Mustacchi 0xc9, /* leave */
2684f364e7cSRobert Mustacchi 0xe9, 0x00, 0x00, 0x00, 0x00 /* jmp $malloc */
2694f364e7cSRobert Mustacchi };
2704f364e7cSRobert Mustacchi
2714f364e7cSRobert Mustacchi /*
2724f364e7cSRobert Mustacchi * if (t->tm_size + csize > umem_ptc_size)
2734f364e7cSRobert Mustacchi * goto tofree;
2744f364e7cSRobert Mustacchi *
2754f364e7cSRobert Mustacchi * t->tm_size += csize
2764f364e7cSRobert Mustacchi * *(void **)tag = *root;
2774f364e7cSRobert Mustacchi * *root = tag;
2784f364e7cSRobert Mustacchi * return;
2794f364e7cSRobert Mustacchi * tofree:
2804f364e7cSRobert Mustacchi * free(buf);
2814f364e7cSRobert Mustacchi * return;
2824f364e7cSRobert Mustacchi */
2834f364e7cSRobert Mustacchi #define PTC_FRFINI_RBUFLABEL 0x00
2844f364e7cSRobert Mustacchi #define PTC_FRFINI_CACHEMAX 0x06
2854f364e7cSRobert Mustacchi #define PTC_FRFINI_DONELABEL 0x14
2864f364e7cSRobert Mustacchi #define PTC_FRFINI_JFLABEL 0x19
2874f364e7cSRobert Mustacchi #define PTC_FRFINI_JFADDR 0x1e
2884f364e7cSRobert Mustacchi static const uint8_t freefini[] = {
2894f364e7cSRobert Mustacchi /* freebuf: */
2904f364e7cSRobert Mustacchi 0x8b, 0x19, /* movl (%ecx),%ebx */
2914f364e7cSRobert Mustacchi 0x01, 0xfb, /* addl %edi,%ebx */
2924f364e7cSRobert Mustacchi 0x81, 0xfb, 0x00, 0x00, 0x00, 0x00, /* cmpl maxsize, %ebx */
2934f364e7cSRobert Mustacchi 0x73, 0x0d, /* jae +0xd <tofree> */
2944f364e7cSRobert Mustacchi 0x01, 0x39, /* addl %edi,(%ecx) */
2954f364e7cSRobert Mustacchi 0x8b, 0x3a, /* movl (%edx),%edi */
2964f364e7cSRobert Mustacchi 0x89, 0x38, /* movl %edi,(%eax) */
2974f364e7cSRobert Mustacchi 0x89, 0x02, /* movl %eax,(%edx) */
2984f364e7cSRobert Mustacchi /* done: */
2994f364e7cSRobert Mustacchi 0x5b, /* popl %ebx */
3004f364e7cSRobert Mustacchi 0x5e, /* popl %esi */
3014f364e7cSRobert Mustacchi 0x5f, /* popl %edi */
3024f364e7cSRobert Mustacchi 0xc9, /* leave */
3034f364e7cSRobert Mustacchi 0xc3, /* ret */
3044f364e7cSRobert Mustacchi /* realfree: */
3054f364e7cSRobert Mustacchi 0x5b, /* popl %ebx */
3064f364e7cSRobert Mustacchi 0x5e, /* popl %esi */
3074f364e7cSRobert Mustacchi 0x5f, /* popl %edi */
3084f364e7cSRobert Mustacchi 0xc9, /* leave */
3094f364e7cSRobert Mustacchi 0xe9, 0x00, 0x00, 0x00, 0x00 /* jmp free */
3104f364e7cSRobert Mustacchi };
3114f364e7cSRobert Mustacchi
3124f364e7cSRobert Mustacchi /*
3134f364e7cSRobert Mustacchi * Construct the initial part of malloc. off contains the offset from curthread
3144f364e7cSRobert Mustacchi * to the root of the tmem structure. ep is the address of the label to error
3154f364e7cSRobert Mustacchi * and jump to free. csize is the size of the largest umem_cache in ptcumem.
3164f364e7cSRobert Mustacchi */
3174f364e7cSRobert Mustacchi static int
genasm_malinit(uint8_t * bp,uint32_t off,uint32_t ep,uint32_t csize)3184f364e7cSRobert Mustacchi genasm_malinit(uint8_t *bp, uint32_t off, uint32_t ep, uint32_t csize)
3194f364e7cSRobert Mustacchi {
3204f364e7cSRobert Mustacchi uint32_t addr;
3214f364e7cSRobert Mustacchi
3224f364e7cSRobert Mustacchi bcopy(malinit, bp, sizeof (malinit));
3234f364e7cSRobert Mustacchi addr = PTC_JMPADDR(ep, PTC_MALINIT_JOUT);
3244f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_MALINIT_JOUT, sizeof (addr));
3254f364e7cSRobert Mustacchi bcopy(&csize, bp + PTC_MALINIT_MCS, sizeof (csize));
3264f364e7cSRobert Mustacchi addr = PTC_JMPADDR(ep, PTC_MALINIT_JOV);
3274f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_MALINIT_JOV, sizeof (addr));
3284f364e7cSRobert Mustacchi bcopy(&off, bp + PTC_MALINIT_SOFF, sizeof (off));
3294f364e7cSRobert Mustacchi
3304f364e7cSRobert Mustacchi return (sizeof (malinit));
3314f364e7cSRobert Mustacchi }
3324f364e7cSRobert Mustacchi
3334f364e7cSRobert Mustacchi static int
genasm_frinit(uint8_t * bp,uint32_t off,uint32_t dp,uint32_t ep,uint32_t mc)3344f364e7cSRobert Mustacchi genasm_frinit(uint8_t *bp, uint32_t off, uint32_t dp, uint32_t ep, uint32_t mc)
3354f364e7cSRobert Mustacchi {
3364f364e7cSRobert Mustacchi uint32_t addr;
3374f364e7cSRobert Mustacchi
3384f364e7cSRobert Mustacchi bcopy(freeinit, bp, sizeof (freeinit));
3394f364e7cSRobert Mustacchi addr = PTC_JMPADDR(dp, PTC_FRINI_JDONE);
3404f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_FRINI_JDONE, sizeof (addr));
3414f364e7cSRobert Mustacchi addr = PTC_JMPADDR(ep, PTC_FRINI_JFREE);
3424f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_FRINI_JFREE, sizeof (addr));
3434f364e7cSRobert Mustacchi bcopy(&mc, bp + PTC_FRINI_MCS, sizeof (mc));
3444f364e7cSRobert Mustacchi addr = PTC_JMPADDR(ep, PTC_FRINI_JOV);
3454f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_FRINI_JOV, sizeof (addr));
3464f364e7cSRobert Mustacchi bcopy(&off, bp + PTC_FRINI_SOFF, sizeof (off));
3474f364e7cSRobert Mustacchi return (sizeof (freeinit));
3484f364e7cSRobert Mustacchi }
3494f364e7cSRobert Mustacchi
3504f364e7cSRobert Mustacchi /*
3514f364e7cSRobert Mustacchi * Create the initial cache entry of the specified size. The value of ap tells
3524f364e7cSRobert Mustacchi * us what the address of the label to try and allocate a buffer. This value is
3534f364e7cSRobert Mustacchi * an offset from the current base to that value.
3544f364e7cSRobert Mustacchi */
3554f364e7cSRobert Mustacchi static int
genasm_firstcache(uint8_t * bp,uint32_t csize,uint32_t ap)3564f364e7cSRobert Mustacchi genasm_firstcache(uint8_t *bp, uint32_t csize, uint32_t ap)
3574f364e7cSRobert Mustacchi {
3584f364e7cSRobert Mustacchi uint32_t addr;
3594f364e7cSRobert Mustacchi
3604f364e7cSRobert Mustacchi bcopy(inicache, bp, sizeof (inicache));
3614f364e7cSRobert Mustacchi bcopy(&csize, bp + PTC_INICACHE_CMP, sizeof (csize));
3624f364e7cSRobert Mustacchi bcopy(&csize, bp + PTC_INICACHE_SIZE, sizeof (csize));
3634f364e7cSRobert Mustacchi addr = PTC_JMPADDR(ap, PTC_INICACHE_JMP);
3644f364e7cSRobert Mustacchi ASSERT(addr != 0);
3654f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_INICACHE_JMP, sizeof (addr));
3664f364e7cSRobert Mustacchi
3674f364e7cSRobert Mustacchi return (sizeof (inicache));
3684f364e7cSRobert Mustacchi }
3694f364e7cSRobert Mustacchi
3704f364e7cSRobert Mustacchi static int
genasm_gencache(uint8_t * bp,int num,uint32_t csize,uint32_t ap)3714f364e7cSRobert Mustacchi genasm_gencache(uint8_t *bp, int num, uint32_t csize, uint32_t ap)
3724f364e7cSRobert Mustacchi {
3734f364e7cSRobert Mustacchi uint32_t addr;
3744f364e7cSRobert Mustacchi uint8_t coff;
3754f364e7cSRobert Mustacchi
3764f364e7cSRobert Mustacchi ASSERT(256 / PTC_ROOT_SIZE > num);
3774f364e7cSRobert Mustacchi ASSERT(num != 0);
3784f364e7cSRobert Mustacchi bcopy(gencache, bp, sizeof (gencache));
3794f364e7cSRobert Mustacchi bcopy(&csize, bp + PTC_GENCACHE_CMP, sizeof (csize));
3804f364e7cSRobert Mustacchi bcopy(&csize, bp + PTC_GENCACHE_SIZE, sizeof (csize));
3814f364e7cSRobert Mustacchi coff = num * PTC_ROOT_SIZE;
3824f364e7cSRobert Mustacchi bcopy(&coff, bp + PTC_GENCACHE_NUM, sizeof (coff));
3834f364e7cSRobert Mustacchi addr = PTC_JMPADDR(ap, PTC_GENCACHE_JMP);
3844f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_GENCACHE_JMP, sizeof (addr));
3854f364e7cSRobert Mustacchi
3864f364e7cSRobert Mustacchi return (sizeof (gencache));
3874f364e7cSRobert Mustacchi }
3884f364e7cSRobert Mustacchi
3894f364e7cSRobert Mustacchi static int
genasm_lastcache(uint8_t * bp,int num,uint32_t csize,uint32_t ep)3904f364e7cSRobert Mustacchi genasm_lastcache(uint8_t *bp, int num, uint32_t csize, uint32_t ep)
3914f364e7cSRobert Mustacchi {
3924f364e7cSRobert Mustacchi uint8_t addr;
3934f364e7cSRobert Mustacchi
3944f364e7cSRobert Mustacchi ASSERT(ep <= 0xff && ep > 7);
3954f364e7cSRobert Mustacchi ASSERT(256 / PTC_ROOT_SIZE > num);
3964f364e7cSRobert Mustacchi bcopy(fincache, bp, sizeof (fincache));
3974f364e7cSRobert Mustacchi bcopy(&csize, bp + PTC_FINCACHE_CMP, sizeof (csize));
3984f364e7cSRobert Mustacchi bcopy(&csize, bp + PTC_FINCACHE_SIZE, sizeof (csize));
3994f364e7cSRobert Mustacchi addr = num * PTC_ROOT_SIZE;
4004f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_FINCACHE_NUM, sizeof (addr));
4014f364e7cSRobert Mustacchi addr = ep - PTC_FINCACHE_JMP - 1;
4024f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_FINCACHE_JMP, sizeof (addr));
4034f364e7cSRobert Mustacchi
4044f364e7cSRobert Mustacchi return (sizeof (fincache));
4054f364e7cSRobert Mustacchi }
4064f364e7cSRobert Mustacchi
4074f364e7cSRobert Mustacchi static int
genasm_malfini(uint8_t * bp,uintptr_t mptr)4084f364e7cSRobert Mustacchi genasm_malfini(uint8_t *bp, uintptr_t mptr)
4094f364e7cSRobert Mustacchi {
4104f364e7cSRobert Mustacchi uint32_t addr;
4114f364e7cSRobert Mustacchi
4124f364e7cSRobert Mustacchi bcopy(malfini, bp, sizeof (malfini));
4134f364e7cSRobert Mustacchi addr = PTC_JMPADDR(mptr, ((uintptr_t)bp + PTC_MALFINI_JMADDR));
4144f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_MALFINI_JMADDR, sizeof (addr));
4154f364e7cSRobert Mustacchi
4164f364e7cSRobert Mustacchi return (sizeof (malfini));
4174f364e7cSRobert Mustacchi }
4184f364e7cSRobert Mustacchi
4194f364e7cSRobert Mustacchi static int
genasm_frfini(uint8_t * bp,uint32_t maxthr,uintptr_t fptr)4204f364e7cSRobert Mustacchi genasm_frfini(uint8_t *bp, uint32_t maxthr, uintptr_t fptr)
4214f364e7cSRobert Mustacchi {
4224f364e7cSRobert Mustacchi uint32_t addr;
4234f364e7cSRobert Mustacchi
4244f364e7cSRobert Mustacchi bcopy(freefini, bp, sizeof (freefini));
4254f364e7cSRobert Mustacchi bcopy(&maxthr, bp + PTC_FRFINI_CACHEMAX, sizeof (maxthr));
4264f364e7cSRobert Mustacchi addr = PTC_JMPADDR(fptr, ((uintptr_t)bp + PTC_FRFINI_JFADDR));
4274f364e7cSRobert Mustacchi bcopy(&addr, bp + PTC_FRFINI_JFADDR, sizeof (addr));
4284f364e7cSRobert Mustacchi
4294f364e7cSRobert Mustacchi return (sizeof (freefini));
4304f364e7cSRobert Mustacchi }
4314f364e7cSRobert Mustacchi
4324f364e7cSRobert Mustacchi /*
4334f364e7cSRobert Mustacchi * The malloc inline assembly is constructed as follows:
4344f364e7cSRobert Mustacchi *
4354f364e7cSRobert Mustacchi * o Malloc prologue assembly
4364f364e7cSRobert Mustacchi * o Generic first-cache check
4374f364e7cSRobert Mustacchi * o n Generic cache checks (where n = _tmem_get_entries() - 2)
4384f364e7cSRobert Mustacchi * o Generic last-cache check
4394f364e7cSRobert Mustacchi * o Malloc epilogue assembly
4404f364e7cSRobert Mustacchi *
4414f364e7cSRobert Mustacchi * Generally there are at least three caches. When there is only one cache we
4424f364e7cSRobert Mustacchi * only use the generic last-cache. In the case where there are two caches, we
4434f364e7cSRobert Mustacchi * just leave out the middle ones.
4444f364e7cSRobert Mustacchi */
4454f364e7cSRobert Mustacchi static int
genasm_malloc(void * base,size_t len,int nents,int * umem_alloc_sizes)4464f364e7cSRobert Mustacchi genasm_malloc(void *base, size_t len, int nents, int *umem_alloc_sizes)
4474f364e7cSRobert Mustacchi {
4484f364e7cSRobert Mustacchi int ii, off;
4494f364e7cSRobert Mustacchi uint8_t *bp;
4504f364e7cSRobert Mustacchi size_t total;
4514f364e7cSRobert Mustacchi uint32_t allocoff, erroff;
4524f364e7cSRobert Mustacchi
4534f364e7cSRobert Mustacchi total = sizeof (malinit) + sizeof (malfini) + sizeof (fincache);
4544f364e7cSRobert Mustacchi
4554f364e7cSRobert Mustacchi if (nents >= 2)
4564f364e7cSRobert Mustacchi total += sizeof (inicache) + sizeof (gencache) * (nents - 2);
4574f364e7cSRobert Mustacchi
4584f364e7cSRobert Mustacchi if (total > len)
4594f364e7cSRobert Mustacchi return (1);
4604f364e7cSRobert Mustacchi
4614f364e7cSRobert Mustacchi erroff = total - sizeof (malfini) + PTC_MALFINI_JMLABEL;
4624f364e7cSRobert Mustacchi allocoff = total - sizeof (malfini) + PTC_MALFINI_ALLABEL;
4634f364e7cSRobert Mustacchi
4644f364e7cSRobert Mustacchi bp = base;
4654f364e7cSRobert Mustacchi
4664f364e7cSRobert Mustacchi off = genasm_malinit(bp, umem_tmem_off, erroff,
4674f364e7cSRobert Mustacchi umem_alloc_sizes[nents-1]);
4684f364e7cSRobert Mustacchi bp += off;
4694f364e7cSRobert Mustacchi allocoff -= off;
4704f364e7cSRobert Mustacchi erroff -= off;
4714f364e7cSRobert Mustacchi
4724f364e7cSRobert Mustacchi if (nents > 1) {
4734f364e7cSRobert Mustacchi off = genasm_firstcache(bp, umem_alloc_sizes[0], allocoff);
4744f364e7cSRobert Mustacchi bp += off;
4754f364e7cSRobert Mustacchi allocoff -= off;
4764f364e7cSRobert Mustacchi erroff -= off;
4774f364e7cSRobert Mustacchi }
4784f364e7cSRobert Mustacchi
4794f364e7cSRobert Mustacchi for (ii = 1; ii < nents - 1; ii++) {
4804f364e7cSRobert Mustacchi off = genasm_gencache(bp, ii, umem_alloc_sizes[ii], allocoff);
4814f364e7cSRobert Mustacchi bp += off;
4824f364e7cSRobert Mustacchi allocoff -= off;
4834f364e7cSRobert Mustacchi erroff -= off;
4844f364e7cSRobert Mustacchi }
4854f364e7cSRobert Mustacchi
4864f364e7cSRobert Mustacchi bp += genasm_lastcache(bp, nents - 1, umem_alloc_sizes[nents - 1],
4874f364e7cSRobert Mustacchi erroff);
4884f364e7cSRobert Mustacchi bp += genasm_malfini(bp, umem_genasm_omptr);
4894f364e7cSRobert Mustacchi ASSERT(((uintptr_t)bp - total) == (uintptr_t)base);
4904f364e7cSRobert Mustacchi
4914f364e7cSRobert Mustacchi return (0);
4924f364e7cSRobert Mustacchi }
4934f364e7cSRobert Mustacchi
4944f364e7cSRobert Mustacchi static int
genasm_free(void * base,size_t len,int nents,int * umem_alloc_sizes)4954f364e7cSRobert Mustacchi genasm_free(void *base, size_t len, int nents, int *umem_alloc_sizes)
4964f364e7cSRobert Mustacchi {
4974f364e7cSRobert Mustacchi uint8_t *bp;
4984f364e7cSRobert Mustacchi int ii, off;
4994f364e7cSRobert Mustacchi size_t total;
5004f364e7cSRobert Mustacchi uint32_t rbufoff, retoff, erroff;
5014f364e7cSRobert Mustacchi
5024f364e7cSRobert Mustacchi /* Assume that nents has already been audited for us */
5034f364e7cSRobert Mustacchi total = sizeof (freeinit) + sizeof (freefini) + sizeof (fincache);
5044f364e7cSRobert Mustacchi if (nents >= 2)
5054f364e7cSRobert Mustacchi total += sizeof (inicache) + sizeof (gencache) * (nents - 2);
5064f364e7cSRobert Mustacchi
5074f364e7cSRobert Mustacchi if (total > len)
5084f364e7cSRobert Mustacchi return (1);
5094f364e7cSRobert Mustacchi
5104f364e7cSRobert Mustacchi erroff = total - (sizeof (freefini) - PTC_FRFINI_JFLABEL);
5114f364e7cSRobert Mustacchi rbufoff = total - (sizeof (freefini) - PTC_FRFINI_RBUFLABEL);
5124f364e7cSRobert Mustacchi retoff = total - (sizeof (freefini) - PTC_FRFINI_DONELABEL);
5134f364e7cSRobert Mustacchi
5144f364e7cSRobert Mustacchi bp = base;
5154f364e7cSRobert Mustacchi
5164f364e7cSRobert Mustacchi off = genasm_frinit(bp, umem_tmem_off, retoff, erroff,
5174f364e7cSRobert Mustacchi umem_alloc_sizes[nents - 1]);
5184f364e7cSRobert Mustacchi bp += off;
5194f364e7cSRobert Mustacchi erroff -= off;
5204f364e7cSRobert Mustacchi rbufoff -= off;
5214f364e7cSRobert Mustacchi
5224f364e7cSRobert Mustacchi if (nents > 1) {
5234f364e7cSRobert Mustacchi off = genasm_firstcache(bp, umem_alloc_sizes[0], rbufoff);
5244f364e7cSRobert Mustacchi bp += off;
5254f364e7cSRobert Mustacchi erroff -= off;
5264f364e7cSRobert Mustacchi rbufoff -= off;
5274f364e7cSRobert Mustacchi }
5284f364e7cSRobert Mustacchi
5294f364e7cSRobert Mustacchi for (ii = 1; ii < nents - 1; ii++) {
5304f364e7cSRobert Mustacchi off = genasm_gencache(bp, ii, umem_alloc_sizes[ii], rbufoff);
5314f364e7cSRobert Mustacchi bp += off;
5324f364e7cSRobert Mustacchi rbufoff -= off;
5334f364e7cSRobert Mustacchi erroff -= off;
5344f364e7cSRobert Mustacchi }
5354f364e7cSRobert Mustacchi
5364f364e7cSRobert Mustacchi bp += genasm_lastcache(bp, nents - 1, umem_alloc_sizes[nents - 1],
5374f364e7cSRobert Mustacchi erroff);
5384f364e7cSRobert Mustacchi bp += genasm_frfini(bp, umem_ptc_size, umem_genasm_ofptr);
5394f364e7cSRobert Mustacchi ASSERT(((uintptr_t)bp - total) == (uintptr_t)base);
5404f364e7cSRobert Mustacchi
5414f364e7cSRobert Mustacchi return (0);
5424f364e7cSRobert Mustacchi }
5434f364e7cSRobert Mustacchi
544*b1e2e3fbSRobert Mustacchi boolean_t
umem_genasm(int * alloc_sizes,umem_cache_t ** caches,int ncaches)5454f364e7cSRobert Mustacchi umem_genasm(int *alloc_sizes, umem_cache_t **caches, int ncaches)
5464f364e7cSRobert Mustacchi {
5474f364e7cSRobert Mustacchi int nents, i;
5484f364e7cSRobert Mustacchi uint8_t *mptr;
5494f364e7cSRobert Mustacchi uint8_t *fptr;
5504f364e7cSRobert Mustacchi uint64_t v, *vptr;
551*b1e2e3fbSRobert Mustacchi size_t mplen, fplen;
552*b1e2e3fbSRobert Mustacchi uintptr_t mpbase, fpbase;
553*b1e2e3fbSRobert Mustacchi boolean_t ret = B_FALSE;
5544f364e7cSRobert Mustacchi
5554f364e7cSRobert Mustacchi mptr = (void *)((uintptr_t)umem_genasm_mptr + 5);
5564f364e7cSRobert Mustacchi fptr = (void *)((uintptr_t)umem_genasm_fptr + 5);
5574f364e7cSRobert Mustacchi if (umem_genasm_mptr == 0 || umem_genasm_msize == 0 ||
558*b1e2e3fbSRobert Mustacchi umem_genasm_fptr == 0 || umem_genasm_fsize == 0) {
559*b1e2e3fbSRobert Mustacchi return (B_FALSE);
560*b1e2e3fbSRobert Mustacchi }
561*b1e2e3fbSRobert Mustacchi
562*b1e2e3fbSRobert Mustacchi mplen = P2ROUNDUP(umem_genasm_msize, pagesize);
563*b1e2e3fbSRobert Mustacchi mpbase = P2ALIGN((uintptr_t)umem_genasm_mptr, pagesize);
564*b1e2e3fbSRobert Mustacchi fplen = P2ROUNDUP(umem_genasm_fsize, pagesize);
565*b1e2e3fbSRobert Mustacchi fpbase = P2ALIGN((uintptr_t)umem_genasm_mptr, pagesize);
566*b1e2e3fbSRobert Mustacchi
567*b1e2e3fbSRobert Mustacchi /*
568*b1e2e3fbSRobert Mustacchi * If the values straddle a page boundary, then we might need to
569*b1e2e3fbSRobert Mustacchi * actually remap two pages.
570*b1e2e3fbSRobert Mustacchi */
571*b1e2e3fbSRobert Mustacchi if (P2ALIGN(umem_genasm_msize + (uintptr_t)umem_genasm_mptr,
572*b1e2e3fbSRobert Mustacchi pagesize) != mpbase) {
573*b1e2e3fbSRobert Mustacchi mplen += pagesize;
574*b1e2e3fbSRobert Mustacchi }
575*b1e2e3fbSRobert Mustacchi
576*b1e2e3fbSRobert Mustacchi if (P2ALIGN(umem_genasm_fsize + (uintptr_t)umem_genasm_fptr,
577*b1e2e3fbSRobert Mustacchi pagesize) != fpbase) {
578*b1e2e3fbSRobert Mustacchi fplen += pagesize;
579*b1e2e3fbSRobert Mustacchi }
580*b1e2e3fbSRobert Mustacchi
581*b1e2e3fbSRobert Mustacchi if (mprotect((void *)mpbase, mplen, PROT_READ | PROT_WRITE |
582*b1e2e3fbSRobert Mustacchi PROT_EXEC) != 0) {
583*b1e2e3fbSRobert Mustacchi return (B_FALSE);
584*b1e2e3fbSRobert Mustacchi }
585*b1e2e3fbSRobert Mustacchi
586*b1e2e3fbSRobert Mustacchi if (mprotect((void *)fpbase, fplen, PROT_READ | PROT_WRITE |
587*b1e2e3fbSRobert Mustacchi PROT_EXEC) != 0) {
588*b1e2e3fbSRobert Mustacchi if (mprotect((void *)mpbase, mplen, PROT_READ | PROT_EXEC) !=
589*b1e2e3fbSRobert Mustacchi 0) {
590*b1e2e3fbSRobert Mustacchi umem_panic("genasm failed to restore memory "
591*b1e2e3fbSRobert Mustacchi "protection: %d", errno);
592*b1e2e3fbSRobert Mustacchi }
593*b1e2e3fbSRobert Mustacchi return (B_FALSE);
594*b1e2e3fbSRobert Mustacchi }
5954f364e7cSRobert Mustacchi
5964f364e7cSRobert Mustacchi /*
5974f364e7cSRobert Mustacchi * The total number of caches that we can service is the minimum of:
5984f364e7cSRobert Mustacchi * o the amount supported by libc
5994f364e7cSRobert Mustacchi * o the total number of umem caches
6004f364e7cSRobert Mustacchi * o we use a single byte addl, so it's 255 / sizeof (uintptr_t). For
6014f364e7cSRobert Mustacchi * 32-bit, this is 63.
6024f364e7cSRobert Mustacchi */
6034f364e7cSRobert Mustacchi nents = _tmem_get_nentries();
6044f364e7cSRobert Mustacchi
6054f364e7cSRobert Mustacchi if (UMEM_GENASM_MAX32 < nents)
6064f364e7cSRobert Mustacchi nents = UMEM_GENASM_MAX32;
6074f364e7cSRobert Mustacchi
6084f364e7cSRobert Mustacchi if (ncaches < nents)
6094f364e7cSRobert Mustacchi nents = ncaches;
6104f364e7cSRobert Mustacchi
611*b1e2e3fbSRobert Mustacchi /*
612*b1e2e3fbSRobert Mustacchi * If the number of per-thread caches has been set to zero or the
613*b1e2e3fbSRobert Mustacchi * per-thread cache size has been set to zero, don't bother trying to
614*b1e2e3fbSRobert Mustacchi * write any assembly and just use the default malloc and free. When we
615*b1e2e3fbSRobert Mustacchi * return, indicate that there is no PTC support.
616*b1e2e3fbSRobert Mustacchi */
617*b1e2e3fbSRobert Mustacchi if (nents == 0 || umem_ptc_size == 0) {
618*b1e2e3fbSRobert Mustacchi goto out;
619*b1e2e3fbSRobert Mustacchi }
6204f364e7cSRobert Mustacchi
6214f364e7cSRobert Mustacchi /* Take into account the jump */
6224f364e7cSRobert Mustacchi if (genasm_malloc(mptr, umem_genasm_msize, nents,
623*b1e2e3fbSRobert Mustacchi alloc_sizes) != 0) {
624*b1e2e3fbSRobert Mustacchi goto out;
625*b1e2e3fbSRobert Mustacchi }
6264f364e7cSRobert Mustacchi
6274f364e7cSRobert Mustacchi if (genasm_free(fptr, umem_genasm_fsize, nents,
628*b1e2e3fbSRobert Mustacchi alloc_sizes) != 0) {
629*b1e2e3fbSRobert Mustacchi goto out;
630*b1e2e3fbSRobert Mustacchi }
6314f364e7cSRobert Mustacchi
6324f364e7cSRobert Mustacchi /* nop out the jump with a multibyte jump */
6334f364e7cSRobert Mustacchi vptr = (void *)umem_genasm_mptr;
6344f364e7cSRobert Mustacchi v = MULTINOP;
6354f364e7cSRobert Mustacchi v |= *vptr & (0xffffffULL << 40);
6364f364e7cSRobert Mustacchi (void) atomic_swap_64(vptr, v);
6374f364e7cSRobert Mustacchi vptr = (void *)umem_genasm_fptr;
6384f364e7cSRobert Mustacchi v = MULTINOP;
6394f364e7cSRobert Mustacchi v |= *vptr & (0xffffffULL << 40);
6404f364e7cSRobert Mustacchi (void) atomic_swap_64(vptr, v);
6414f364e7cSRobert Mustacchi
6424f364e7cSRobert Mustacchi for (i = 0; i < nents; i++)
6434f364e7cSRobert Mustacchi caches[i]->cache_flags |= UMF_PTC;
6444f364e7cSRobert Mustacchi
645*b1e2e3fbSRobert Mustacchi ret = B_TRUE;
646*b1e2e3fbSRobert Mustacchi out:
647*b1e2e3fbSRobert Mustacchi if (mprotect((void *)mpbase, mplen, PROT_READ | PROT_EXEC) != 0) {
648*b1e2e3fbSRobert Mustacchi umem_panic("genasm failed to restore memory protection: %d",
649*b1e2e3fbSRobert Mustacchi errno);
650*b1e2e3fbSRobert Mustacchi }
651*b1e2e3fbSRobert Mustacchi
652*b1e2e3fbSRobert Mustacchi if (mprotect((void *)fpbase, fplen, PROT_READ | PROT_EXEC) != 0) {
653*b1e2e3fbSRobert Mustacchi umem_panic("genasm failed to restore memory protection: %d",
654*b1e2e3fbSRobert Mustacchi errno);
655*b1e2e3fbSRobert Mustacchi }
656*b1e2e3fbSRobert Mustacchi
657*b1e2e3fbSRobert Mustacchi return (ret);
6584f364e7cSRobert Mustacchi }
659