|
|
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.