github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/utils/memory_allocator.c (about) 1 /* 2 * Copyright (c) 2013 Intel Corporation 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * Unless required by applicable law or agreed to in writing, software 9 * distributed under the License is distributed on an "AS IS" BASIS, 10 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11 * See the License for the specific language governing permissions and 12 * limitations under the License. 13 */ 14 15 #include "memory_allocator.h" 16 #include "pool_api.h" 17 #include "hw_utils.h" 18 #include "vmm_dbg.h" 19 #include "common_libc.h" 20 #include "lock.h" 21 #include "file_codes.h" 22 #ifdef JLMDEBUG 23 #include "jlmdebug.h" 24 #endif 25 26 #ifndef VMM_DEADLOOP 27 #define VMM_DEADLOOP() VMM_DEADLOOP_LOG(MEMORY_ALLOCATOR_C) 28 #endif 29 30 #ifndef VMM_ASSERT 31 #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(MEMORY_ALLOCATOR_C, __condition) 32 #endif 33 34 typedef struct { 35 UINT32 size; 36 UINT32 offset; 37 } MEM_ALLOCATION_INFO; 38 39 // pool per element size (2^x bytes, x = 0, 1,...11) 40 #define NUMBER_OF_POOLS 12 41 42 // pool per element size (2^x bytes, x = 0, 1,...11) 43 static POOL_HANDLE pools[NUMBER_OF_POOLS] = {POOL_INVALID_HANDLE}; 44 static VMM_LOCK lock = LOCK_INIT_STATE; 45 46 static UINT32 buffer_size_to_pool_index(UINT32 size) 47 { 48 UINT32 pool_index = 0; 49 UINT32 pool_element_size = 0; 50 51 VMM_ASSERT(size != 0); 52 hw_scan_bit_backward((UINT32 *)&pool_index, size); 53 pool_element_size = 1 << pool_index; 54 if(pool_element_size < size) { 55 pool_element_size = pool_element_size << 1; 56 pool_index++; 57 } 58 return pool_index; 59 } 60 61 #pragma warning (push) 62 #pragma warning (disable : 4100) 63 64 static void* vmm_mem_allocate_internal( char *file_name, 65 INT32 line_number, IN UINT32 size, IN UINT32 alignment) 66 { 67 POOL_HANDLE pool = NULL; 68 UINT32 pool_index = 0; 69 UINT32 pool_element_size = 0; 70 void* ptr; 71 UINT64 allocated_addr; 72 MEM_ALLOCATION_INFO *alloc_info; 73 UINT32 size_to_request; 74 75 // Unused variables 76 (void)file_name; 77 (void)line_number; 78 #ifdef JLMDEBUG1 79 bprint("In vmm_mem_allocate_internal size: %d, align: %08x\n", size, alignment); 80 #endif 81 82 // starting from 2KB+1 need a full page 83 if(size > ((2 KILOBYTE) - sizeof(MEM_ALLOCATION_INFO))) { 84 VMM_LOG(mask_anonymous, level_trace,"%s: WARNING: Memory allocator supports allocations of sizes up to 2040 bytes (requested size = 0x%x from %s:%d)\n", __FUNCTION__, size, file_name, line_number); 85 VMM_ASSERT(0); 86 return NULL; 87 } 88 89 if (alignment >= PAGE_4KB_SIZE) { 90 VMM_LOG(mask_anonymous, level_trace,"%s: WARNING: Requested alignment is 4K or more, use full page allocation (requested alignment = 0x%x)\n", __FUNCTION__, alignment); 91 VMM_ASSERT(0); 92 return NULL; 93 } 94 95 VMM_ASSERT(IS_POW_OF_2(alignment)); 96 VMM_ASSERT(alignment >= sizeof(MEM_ALLOCATION_INFO)); 97 98 if (alignment > sizeof(MEM_ALLOCATION_INFO)) { 99 UINT32 adjusted_size = (size < alignment) ? alignment : size; 100 size_to_request = adjusted_size * 2; 101 } 102 else { 103 size_to_request = size + sizeof(MEM_ALLOCATION_INFO); 104 } 105 106 pool_index = buffer_size_to_pool_index(size_to_request); 107 pool_element_size = 1 << pool_index; 108 109 lock_acquire(&lock); 110 #ifdef JLMDEBUG1 111 bprint("pool_index: %d, pools: 0x%016x,\nval = %p, expected = %p\n", 112 pool_index, pools, pools[pool_index], pools[0]); 113 #endif 114 pool = pools[pool_index]; 115 if(NULL == pool) { 116 pool = pools[pool_index] = assync_pool_create((UINT32)pool_element_size); 117 VMM_ASSERT(pool); 118 } 119 120 ptr = pool_allocate(pool); 121 lock_release(&lock); 122 if(NULL == ptr) { 123 return NULL; 124 } 125 126 vmm_zeromem(ptr, pool_element_size); 127 allocated_addr = (UINT64)ptr; 128 129 // Check alignment 130 VMM_ASSERT(ALIGN_BACKWARD(allocated_addr, (UINT64)alignment) == allocated_addr); 131 alloc_info = (MEM_ALLOCATION_INFO*) 132 (allocated_addr + alignment - sizeof(MEM_ALLOCATION_INFO)); 133 alloc_info->size = pool_element_size; 134 alloc_info->offset = alignment; 135 return (void *)(allocated_addr + alignment); 136 } 137 138 139 // vmm_mem_allocate() and vmm_mem_free() have allocation limit of 2048 bytes 140 // and need to be extended. vmm_page_alloc() and vmm_page_free() are 141 // a temporary solution for more than 2040 bytes using page alignment of 142 // buffer differentiating between vmm_malloc allocation() and vmm_page_alloc(). 143 void* vmm_mem_allocate( char *file_name, INT32 line_number, IN UINT32 size) 144 { 145 return vmm_mem_allocate_internal( file_name, line_number, 146 size, sizeof(MEM_ALLOCATION_INFO)); 147 } 148 149 void vmm_mem_free( char *file_name, INT32 line_number, IN void *buff) 150 { 151 MEM_ALLOCATION_INFO *alloc_info; 152 void* allocated_buffer; 153 UINT32 pool_element_size = 0; 154 UINT32 pool_index = 0; 155 POOL_HANDLE pool = NULL; 156 // Unused variables 157 (void)file_name; 158 (void)line_number; 159 160 if (buff == NULL) { 161 VMM_LOG(mask_anonymous, level_trace,"In %s#%d try to free NULL\n", file_name, line_number); 162 return; 163 } 164 165 alloc_info = (MEM_ALLOCATION_INFO*)((UINT64)buff - sizeof(MEM_ALLOCATION_INFO)); 166 pool_element_size = alloc_info->size; 167 VMM_ASSERT(IS_POW_OF_2(pool_element_size)); 168 169 pool_index = buffer_size_to_pool_index(pool_element_size); 170 allocated_buffer = (void*)((UINT64)buff - alloc_info->offset); 171 172 lock_acquire(&lock); 173 pool = pools[pool_index]; 174 VMM_ASSERT(pool != NULL); 175 176 pool_free(pool, allocated_buffer); 177 lock_release(&lock); 178 } 179 180 void* vmm_mem_allocate_aligned( char *file_name, INT32 line_number, 181 IN UINT32 size, IN UINT32 alignment) { 182 183 if (!IS_POW_OF_2(alignment)) { 184 VMM_LOG(mask_anonymous, level_trace,"%s: WARNING: Requested alignment is not power of 2\n", __FUNCTION__); 185 return NULL; 186 } 187 return vmm_mem_allocate_internal( file_name, line_number, size, alignment); 188 } 189 190 UINT32 vmm_mem_buff_size( char *file_name, INT32 line_number, IN void *buff) 191 { 192 MEM_ALLOCATION_INFO *alloc_info; 193 UINT32 pool_element_size = 0; 194 195 // Unused variables 196 (void)file_name; 197 (void)line_number; 198 if (buff == NULL) { 199 VMM_LOG(mask_anonymous, level_trace,"In %s#%d try to access NULL\n", file_name, line_number); 200 return 0; 201 } 202 alloc_info = (MEM_ALLOCATION_INFO*)((UINT64)buff - sizeof(MEM_ALLOCATION_INFO)); 203 pool_element_size = alloc_info->size; 204 VMM_ASSERT(IS_POW_OF_2(pool_element_size)); 205 return pool_element_size; 206 } 207 208 static UINT32 vmm_mem_pool_size_internal( char *file_name, INT32 line_number, 209 IN UINT32 size, IN UINT32 alignment) 210 { 211 UINT32 pool_index = 0; 212 UINT32 pool_element_size = 0; 213 UINT32 size_to_request; 214 215 // Unused variables 216 (void)file_name; 217 (void)line_number; 218 if (alignment > sizeof(MEM_ALLOCATION_INFO)) { 219 UINT32 adjusted_size = (size < alignment) ? alignment : size; 220 221 size_to_request = adjusted_size * 2; 222 } 223 else { 224 size_to_request = size + sizeof(MEM_ALLOCATION_INFO); 225 } 226 227 pool_index = buffer_size_to_pool_index(size_to_request); 228 pool_element_size = 1 << pool_index; 229 return pool_element_size; 230 } 231 232 UINT32 vmm_mem_pool_size( char *file_name, INT32 line_number, IN UINT32 size) 233 { 234 return vmm_mem_pool_size_internal( file_name, line_number, 235 size, sizeof(MEM_ALLOCATION_INFO)); 236 } 237 238 #pragma warning (pop) 239 240 #ifdef INCLUDE_UNUSED_CODE 241 void memory_allocator_print(void) 242 { 243 UINT32 i; 244 245 for(i = 0; i < NUMBER_OF_POOLS; i++) { 246 if(POOL_INVALID_HANDLE == pools[i]) { 247 VMM_LOG(mask_anonymous, level_trace,"\r\nPool #%d nor int use\r\n", i); 248 } 249 else { 250 pool_print(pools[i]); 251 } 252 } 253 } 254 #endif