10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51618Srie * Common Development and Distribution License (the "License").
61618Srie * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
211618Srie
220Sstevel@tonic-gate /*
238598SRod.Evans@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
246812Sraf * Use is subject to license terms.
256812Sraf */
266812Sraf
276812Sraf /*
280Sstevel@tonic-gate * Copyright (c) 1988 AT&T
290Sstevel@tonic-gate * All Rights Reserved
300Sstevel@tonic-gate */
316812Sraf
320Sstevel@tonic-gate /*
330Sstevel@tonic-gate * Simplified version of malloc(), calloc() and free(), to be linked with
340Sstevel@tonic-gate * utilities that use [s]brk() and do not define their own version of the
350Sstevel@tonic-gate * routines.
360Sstevel@tonic-gate * The algorithm maps /dev/zero to get extra memory space.
370Sstevel@tonic-gate * Each call to mmap() creates a page. The pages are linked in a list.
380Sstevel@tonic-gate * Each page is divided in blocks. There is at least one block in a page.
390Sstevel@tonic-gate * New memory chunks are allocated on a first-fit basis.
400Sstevel@tonic-gate * Freed blocks are joined in larger blocks. Free pages are unmapped.
410Sstevel@tonic-gate */
420Sstevel@tonic-gate
430Sstevel@tonic-gate #include <stdlib.h>
440Sstevel@tonic-gate #include <sys/types.h>
450Sstevel@tonic-gate #include <sys/mman.h>
460Sstevel@tonic-gate #include <sys/debug.h>
470Sstevel@tonic-gate #include <memory.h>
480Sstevel@tonic-gate #include "_rtld.h"
490Sstevel@tonic-gate #include "msg.h"
500Sstevel@tonic-gate
510Sstevel@tonic-gate struct block {
520Sstevel@tonic-gate size_t size; /* Space available for user */
530Sstevel@tonic-gate struct page *page; /* Backwards reference to page */
540Sstevel@tonic-gate int status;
550Sstevel@tonic-gate struct block *next;
560Sstevel@tonic-gate void * memstart[1];
570Sstevel@tonic-gate };
580Sstevel@tonic-gate
590Sstevel@tonic-gate struct page {
600Sstevel@tonic-gate size_t size; /* Total page size (incl. header) */
610Sstevel@tonic-gate struct page *next;
620Sstevel@tonic-gate struct block block[1];
630Sstevel@tonic-gate };
640Sstevel@tonic-gate
650Sstevel@tonic-gate #define FREE 0
660Sstevel@tonic-gate #define BUSY 1
670Sstevel@tonic-gate
680Sstevel@tonic-gate #define HDR_BLOCK (sizeof (struct block) - sizeof (void *))
690Sstevel@tonic-gate #define HDR_PAGE (sizeof (struct page) - sizeof (void *))
700Sstevel@tonic-gate
710Sstevel@tonic-gate static struct page *memstart;
720Sstevel@tonic-gate
730Sstevel@tonic-gate #if DEBUG
740Sstevel@tonic-gate /*
750Sstevel@tonic-gate * When built for debugging, scribble a pattern over newly allocated and
760Sstevel@tonic-gate * freed memory.
770Sstevel@tonic-gate */
780Sstevel@tonic-gate #define NEWMEM 0
790Sstevel@tonic-gate #define FREMEM 1
800Sstevel@tonic-gate
810Sstevel@tonic-gate /* LINTED */
820Sstevel@tonic-gate const ulong_t patterns[] = {
83238Sseizo (ulong_t)0xbaddcafebaddcafeULL, (ulong_t)0xdeadbeefdeadbeefULL
840Sstevel@tonic-gate };
850Sstevel@tonic-gate
860Sstevel@tonic-gate static void
scribble(ulong_t * membgn,int pattern,size_t size)870Sstevel@tonic-gate scribble(ulong_t *membgn, int pattern, size_t size)
880Sstevel@tonic-gate {
890Sstevel@tonic-gate size_t memsize = size / sizeof (ulong_t);
900Sstevel@tonic-gate
910Sstevel@tonic-gate while (memsize--) {
920Sstevel@tonic-gate if (pattern == FREMEM)
930Sstevel@tonic-gate ASSERT(*membgn != patterns[pattern]);
940Sstevel@tonic-gate *membgn++ = patterns[pattern];
950Sstevel@tonic-gate }
960Sstevel@tonic-gate }
970Sstevel@tonic-gate #endif
980Sstevel@tonic-gate
990Sstevel@tonic-gate /*
1000Sstevel@tonic-gate * Defragmentation
1010Sstevel@tonic-gate */
1028598SRod.Evans@Sun.COM void
defrag()1038598SRod.Evans@Sun.COM defrag()
1040Sstevel@tonic-gate {
1058598SRod.Evans@Sun.COM struct page *page;
1068598SRod.Evans@Sun.COM Aliste idx;
1070Sstevel@tonic-gate
1088598SRod.Evans@Sun.COM for (APLIST_TRAVERSE(free_alp, idx, page)) {
1098598SRod.Evans@Sun.COM struct block *block;
1100Sstevel@tonic-gate
1118598SRod.Evans@Sun.COM for (block = page->block; block; block = block->next) {
1128598SRod.Evans@Sun.COM struct block *block2;
1130Sstevel@tonic-gate
1148598SRod.Evans@Sun.COM if (block->status == BUSY)
1158598SRod.Evans@Sun.COM continue;
1168598SRod.Evans@Sun.COM for (block2 = block->next; block2 &&
1178598SRod.Evans@Sun.COM block2->status == FREE; block2 = block2->next) {
1188598SRod.Evans@Sun.COM block->next = block2->next;
1198598SRod.Evans@Sun.COM block->size += block2->size + HDR_BLOCK;
1200Sstevel@tonic-gate }
1210Sstevel@tonic-gate }
1228598SRod.Evans@Sun.COM
1238598SRod.Evans@Sun.COM /*
1248598SRod.Evans@Sun.COM * If a page becomes free, leave it, and save the unmapping
1258598SRod.Evans@Sun.COM * expense, as we'll probably come back and reclaim the page
1268598SRod.Evans@Sun.COM * for later malloc activity.
1278598SRod.Evans@Sun.COM *
1288598SRod.Evans@Sun.COM * Free the defrag index.
1298598SRod.Evans@Sun.COM */
1308598SRod.Evans@Sun.COM aplist_delete(free_alp, &idx);
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate }
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate static void
split(struct block * block,size_t size)1350Sstevel@tonic-gate split(struct block *block, size_t size)
1360Sstevel@tonic-gate {
1370Sstevel@tonic-gate if (block->size > size + sizeof (struct block)) {
1380Sstevel@tonic-gate struct block *newblock;
1390Sstevel@tonic-gate /* LINTED */
1400Sstevel@tonic-gate newblock = (struct block *)
1410Sstevel@tonic-gate ((char *)block + HDR_BLOCK + size);
1420Sstevel@tonic-gate newblock->next = block->next;
1430Sstevel@tonic-gate block->next = newblock;
1440Sstevel@tonic-gate newblock->status = FREE;
1450Sstevel@tonic-gate newblock->page = block->page;
1460Sstevel@tonic-gate newblock->size = block->size - size - HDR_BLOCK;
1470Sstevel@tonic-gate block->size = size;
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate }
1500Sstevel@tonic-gate
1518598SRod.Evans@Sun.COM #include <stdio.h>
1520Sstevel@tonic-gate
1530Sstevel@tonic-gate /*
1540Sstevel@tonic-gate * Replace both malloc() and lmalloc() (libc's private memory allocator).
1550Sstevel@tonic-gate * They are both private here.
1560Sstevel@tonic-gate */
1570Sstevel@tonic-gate #pragma weak lmalloc = malloc
1580Sstevel@tonic-gate void *
malloc(size_t size)1590Sstevel@tonic-gate malloc(size_t size)
1600Sstevel@tonic-gate {
1610Sstevel@tonic-gate struct block *block;
1620Sstevel@tonic-gate struct page *page;
1630Sstevel@tonic-gate
1648598SRod.Evans@Sun.COM size = S_DROUND(size);
1650Sstevel@tonic-gate
1660Sstevel@tonic-gate /*
1670Sstevel@tonic-gate * Try to locate necessary space
1680Sstevel@tonic-gate */
1690Sstevel@tonic-gate for (page = memstart; page; page = page->next) {
1700Sstevel@tonic-gate for (block = page->block; block; block = block->next) {
1710Sstevel@tonic-gate if ((block->status == FREE) && (block->size >= size))
1720Sstevel@tonic-gate goto found;
1730Sstevel@tonic-gate }
1740Sstevel@tonic-gate }
1750Sstevel@tonic-gate found:
1760Sstevel@tonic-gate /*
1770Sstevel@tonic-gate * Need to allocate a new page
1780Sstevel@tonic-gate */
1790Sstevel@tonic-gate if (!page) {
1808598SRod.Evans@Sun.COM size_t totsize = size + HDR_PAGE;
1818598SRod.Evans@Sun.COM size_t totpage = S_ROUND(totsize, syspagsz);
1820Sstevel@tonic-gate
1838598SRod.Evans@Sun.COM if ((page = dz_map(0, 0, totpage,
1840Sstevel@tonic-gate PROT_READ | PROT_WRITE | PROT_EXEC,
1858598SRod.Evans@Sun.COM MAP_PRIVATE)) == MAP_FAILED)
1860Sstevel@tonic-gate return (0);
1870Sstevel@tonic-gate
1880Sstevel@tonic-gate page->next = memstart;
1890Sstevel@tonic-gate memstart = page;
1900Sstevel@tonic-gate page->size = totpage;
1910Sstevel@tonic-gate block = page->block;
1920Sstevel@tonic-gate block->next = 0;
1930Sstevel@tonic-gate block->status = FREE;
1940Sstevel@tonic-gate block->size = totpage - HDR_PAGE;
1950Sstevel@tonic-gate block->page = page;
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate
1980Sstevel@tonic-gate split(block, size);
1990Sstevel@tonic-gate #if DEBUG
2000Sstevel@tonic-gate scribble((ulong_t *)&block->memstart, NEWMEM, block->size);
2010Sstevel@tonic-gate #endif
2020Sstevel@tonic-gate block->status = BUSY;
2030Sstevel@tonic-gate return (&block->memstart);
2040Sstevel@tonic-gate }
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate void *
calloc(size_t num,size_t size)2070Sstevel@tonic-gate calloc(size_t num, size_t size)
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate void * mp;
2100Sstevel@tonic-gate
2110Sstevel@tonic-gate num *= size;
2120Sstevel@tonic-gate if ((mp = malloc(num)) == NULL)
2130Sstevel@tonic-gate return (NULL);
2140Sstevel@tonic-gate (void) memset(mp, 0, num);
2150Sstevel@tonic-gate return (mp);
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate
2180Sstevel@tonic-gate void *
realloc(void * ptr,size_t size)2198598SRod.Evans@Sun.COM realloc(void *ptr, size_t size)
2200Sstevel@tonic-gate {
2210Sstevel@tonic-gate struct block *block;
2220Sstevel@tonic-gate size_t osize;
2230Sstevel@tonic-gate void * newptr;
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate if (ptr == NULL)
2260Sstevel@tonic-gate return (malloc(size));
2270Sstevel@tonic-gate
2280Sstevel@tonic-gate /* LINTED */
2290Sstevel@tonic-gate block = (struct block *)((char *)ptr - HDR_BLOCK);
2308598SRod.Evans@Sun.COM size = S_DROUND(size);
2310Sstevel@tonic-gate osize = block->size;
2320Sstevel@tonic-gate
2330Sstevel@tonic-gate /*
2340Sstevel@tonic-gate * Join block with next one if it is free
2350Sstevel@tonic-gate */
2360Sstevel@tonic-gate if (block->next && block->next->status == FREE) {
2370Sstevel@tonic-gate block->size += block->next->size + HDR_BLOCK;
2380Sstevel@tonic-gate block->next = block->next->next;
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate
2410Sstevel@tonic-gate if (size <= block->size) {
2420Sstevel@tonic-gate split(block, size);
2430Sstevel@tonic-gate #if DEBUG
2440Sstevel@tonic-gate if (block->size > osize)
2450Sstevel@tonic-gate scribble((ulong_t *)((char *)ptr + osize), NEWMEM,
2460Sstevel@tonic-gate (block->size - osize));
2470Sstevel@tonic-gate #endif
2480Sstevel@tonic-gate return (ptr);
2490Sstevel@tonic-gate }
2500Sstevel@tonic-gate
2510Sstevel@tonic-gate if ((newptr = malloc(size)) == NULL)
2520Sstevel@tonic-gate return (NULL);
2530Sstevel@tonic-gate (void) memcpy(newptr, ptr, osize);
2540Sstevel@tonic-gate block->status = FREE;
255*8645SRod.Evans@Sun.COM
256*8645SRod.Evans@Sun.COM /*
257*8645SRod.Evans@Sun.COM * Add the free block to the free APlist for later defragmentation.
258*8645SRod.Evans@Sun.COM * However, this addition can only be achieved if there is room on the
259*8645SRod.Evans@Sun.COM * free APlist. The APlist can't be allowed to grow, as the growth
260*8645SRod.Evans@Sun.COM * requires a realloc(), which would recurse back here, resulting in an
261*8645SRod.Evans@Sun.COM * infinite loop. If the free APlist is full, defrag() now. This
262*8645SRod.Evans@Sun.COM * defragmentation might not be able to collapse any free space, but
263*8645SRod.Evans@Sun.COM * the free APlist will be cleared as part of the processing, ensuring
264*8645SRod.Evans@Sun.COM * room for the addition.
265*8645SRod.Evans@Sun.COM */
266*8645SRod.Evans@Sun.COM if (free_alp && (aplist_nitems(free_alp) >= aplist_arritems(free_alp)))
267*8645SRod.Evans@Sun.COM defrag();
2688598SRod.Evans@Sun.COM (void) aplist_test(&free_alp, block->page, AL_CNT_FREELIST);
2690Sstevel@tonic-gate return (newptr);
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate
2720Sstevel@tonic-gate /*
2730Sstevel@tonic-gate * Replace both free() and lfree() (libc's private memory allocator).
2740Sstevel@tonic-gate * They are both private here.
2750Sstevel@tonic-gate */
2760Sstevel@tonic-gate void
free(void * ptr)2778598SRod.Evans@Sun.COM free(void *ptr)
2780Sstevel@tonic-gate {
2790Sstevel@tonic-gate struct block *block;
2800Sstevel@tonic-gate
2810Sstevel@tonic-gate if (ptr == NULL)
2820Sstevel@tonic-gate return;
2830Sstevel@tonic-gate
2840Sstevel@tonic-gate /* LINTED */
2850Sstevel@tonic-gate block = (struct block *)((char *)ptr - HDR_BLOCK);
2860Sstevel@tonic-gate block->status = FREE;
2870Sstevel@tonic-gate #if DEBUG
2880Sstevel@tonic-gate scribble((ulong_t *)&block->memstart, FREMEM, block->size);
2890Sstevel@tonic-gate #endif
2908598SRod.Evans@Sun.COM (void) aplist_test(&free_alp, block->page, AL_CNT_FREELIST);
2910Sstevel@tonic-gate }
2920Sstevel@tonic-gate
2930Sstevel@tonic-gate /* ARGSUSED1 */
2940Sstevel@tonic-gate void
lfree(void * ptr,size_t size)2958598SRod.Evans@Sun.COM lfree(void *ptr, size_t size)
2960Sstevel@tonic-gate {
2970Sstevel@tonic-gate free(ptr);
2980Sstevel@tonic-gate }
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate /*
3010Sstevel@tonic-gate * We can use any memory after ld.so.1's .bss up until the next page boundary
3020Sstevel@tonic-gate * as allocatable memory.
3030Sstevel@tonic-gate */
3040Sstevel@tonic-gate void
addfree(void * ptr,size_t bytes)3058598SRod.Evans@Sun.COM addfree(void *ptr, size_t bytes)
3060Sstevel@tonic-gate {
3070Sstevel@tonic-gate struct block *block;
3080Sstevel@tonic-gate struct page *page;
3090Sstevel@tonic-gate
3100Sstevel@tonic-gate if (bytes <= sizeof (struct page))
3110Sstevel@tonic-gate return;
3120Sstevel@tonic-gate page = ptr;
3130Sstevel@tonic-gate page->next = memstart;
3140Sstevel@tonic-gate memstart = page;
3150Sstevel@tonic-gate page->size = bytes;
3160Sstevel@tonic-gate block = page->block;
3170Sstevel@tonic-gate block->next = 0;
3180Sstevel@tonic-gate block->status = FREE;
3190Sstevel@tonic-gate block->size = bytes - HDR_PAGE;
3200Sstevel@tonic-gate block->page = page;
3210Sstevel@tonic-gate }
322