|
|
1.1 ! root 1: /* ! 2: * Copyright (C) 2010 Piotr JaroszyĆski <[email protected]> ! 3: * ! 4: * This program is free software; you can redistribute it and/or ! 5: * modify it under the terms of the GNU General Public License as ! 6: * published by the Free Software Foundation; either version 2 of the ! 7: * License, or any later version. ! 8: * ! 9: * This program is distributed in the hope that it will be useful, but ! 10: * WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ! 12: * General Public License for more details. ! 13: * ! 14: * You should have received a copy of the GNU General Public License ! 15: * along with this program; if not, write to the Free Software ! 16: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. ! 17: */ ! 18: ! 19: FILE_LICENCE(GPL2_OR_LATER); ! 20: ! 21: #include <valgrind/memcheck.h> ! 22: ! 23: /** @file ! 24: * ! 25: * iPXE user memory allocation API for linux ! 26: * ! 27: */ ! 28: ! 29: #include <assert.h> ! 30: #include <ipxe/umalloc.h> ! 31: ! 32: #include <linux_api.h> ! 33: ! 34: /** Special address returned for empty allocations */ ! 35: #define NOWHERE ((void *)-1) ! 36: ! 37: /** Poison to make the metadata more unique */ ! 38: #define POISON 0xa5a5a5a5 ! 39: #define min(a,b) (((a)<(b))?(a):(b)) ! 40: ! 41: /** Metadata stored at the beginning of all allocations */ ! 42: struct metadata ! 43: { ! 44: unsigned poison; ! 45: size_t size; ! 46: }; ! 47: ! 48: #define SIZE_MD (sizeof(struct metadata)) ! 49: ! 50: /** Simple realloc which passes most of the work to mmap(), mremap() and munmap() */ ! 51: static void * linux_realloc(void *ptr, size_t size) ! 52: { ! 53: struct metadata md = {0, 0}; ! 54: struct metadata * mdptr = NULL; ! 55: ! 56: DBG2("linux_realloc(%p, %zd)\n", ptr, size); ! 57: ! 58: /* Check whether we have a valid pointer */ ! 59: if (ptr != NULL && ptr != NOWHERE) { ! 60: mdptr = ptr - SIZE_MD; ! 61: VALGRIND_MAKE_MEM_DEFINED(mdptr, SIZE_MD); ! 62: md = *mdptr; ! 63: VALGRIND_MAKE_MEM_NOACCESS(mdptr, SIZE_MD); ! 64: ! 65: /* Check for poison in the metadata */ ! 66: if (md.poison != POISON) { ! 67: DBG("linux_realloc bad poison: 0x%x (expected 0x%x)\n", md.poison, POISON); ! 68: return NULL; ! 69: } ! 70: } else { ! 71: /* Handle NOWHERE as NULL */ ! 72: ptr = NULL; ! 73: } ! 74: ! 75: /* ! 76: * At this point, ptr is either NULL or pointing to a region allocated by us. ! 77: * In the latter case mdptr is pointing to a valid metadata, otherwise it is NULL. ! 78: */ ! 79: ! 80: /* Handle deallocation or allocation of size 0 */ ! 81: if (size == 0) { ! 82: if (mdptr) { ! 83: if (linux_munmap(mdptr, md.size)) ! 84: DBG("linux_realloc munmap failed: %s\n", linux_strerror(linux_errno)); ! 85: VALGRIND_FREELIKE_BLOCK(ptr, sizeof(*mdptr)); ! 86: } ! 87: return NOWHERE; ! 88: } ! 89: ! 90: if (ptr) { ! 91: char *vbits = NULL; ! 92: ! 93: if (RUNNING_ON_VALGRIND > 0) ! 94: vbits = linux_realloc(NULL, min(size, md.size)); ! 95: ! 96: /* prevent an unused variable warning when building w/o valgrind support */ ! 97: #ifndef NVALGRIND ! 98: VALGRIND_GET_VBITS(ptr, vbits, min(size, md.size)); ! 99: #endif ! 100: ! 101: VALGRIND_FREELIKE_BLOCK(ptr, SIZE_MD); ! 102: ! 103: mdptr = linux_mremap(mdptr, md.size + SIZE_MD, size + SIZE_MD, MREMAP_MAYMOVE); ! 104: if (mdptr == MAP_FAILED) { ! 105: DBG("linux_realloc mremap failed: %s\n", linux_strerror(linux_errno)); ! 106: return NULL; ! 107: } ! 108: ptr = ((void *)mdptr) + SIZE_MD; ! 109: ! 110: VALGRIND_MALLOCLIKE_BLOCK(ptr, size, SIZE_MD, 0); ! 111: /* prevent an unused variable warning when building w/o valgrind support */ ! 112: #ifndef NVALGRIND ! 113: VALGRIND_SET_VBITS(ptr, vbits, min(size, md.size)); ! 114: #endif ! 115: ! 116: if (RUNNING_ON_VALGRIND > 0) ! 117: linux_realloc(vbits, 0); ! 118: } else { ! 119: mdptr = linux_mmap(NULL, size + SIZE_MD, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ! 120: if (mdptr == MAP_FAILED) { ! 121: DBG("linux_realloc mmap failed: %s\n", linux_strerror(linux_errno)); ! 122: return NULL; ! 123: } ! 124: ptr = ((void *)mdptr) + SIZE_MD; ! 125: VALGRIND_MALLOCLIKE_BLOCK(ptr, size, SIZE_MD, 0); ! 126: } ! 127: ! 128: /* Update the metadata */ ! 129: VALGRIND_MAKE_MEM_DEFINED(mdptr, SIZE_MD); ! 130: mdptr->poison = POISON; ! 131: mdptr->size = size; ! 132: VALGRIND_MAKE_MEM_NOACCESS(mdptr, SIZE_MD); ! 133: // VALGRIND_MALLOCLIKE_BLOCK ignores redzones currently, make our own ! 134: VALGRIND_MAKE_MEM_NOACCESS(ptr + size, SIZE_MD); ! 135: ! 136: return ptr; ! 137: } ! 138: ! 139: /** ! 140: * Reallocate external memory ! 141: * ! 142: * @v old_ptr Memory previously allocated by umalloc(), or UNULL ! 143: * @v new_size Requested size ! 144: * @ret new_ptr Allocated memory, or UNULL ! 145: * ! 146: * Calling realloc() with a new size of zero is a valid way to free a ! 147: * memory block. ! 148: */ ! 149: static userptr_t linux_urealloc(userptr_t old_ptr, size_t new_size) ! 150: { ! 151: return (userptr_t)linux_realloc((void *)old_ptr, new_size); ! 152: } ! 153: ! 154: PROVIDE_UMALLOC(linux, urealloc, linux_urealloc);
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.