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