github.com/jlmucb/cloudproxy@v0.0.0-20170830161738-b5aa0b619bc4/cpvmm/vmm/memory/memory_manager/gpm.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 <vmm_defs.h>
    16  #include <gpm_api.h>
    17  #include <memory_address_mapper_api.h>
    18  #include <host_memory_manager_api.h>
    19  #include <e820_abstraction.h>
    20  #include <heap.h>
    21  #include <vmm_dbg.h>
    22  #include "file_codes.h"
    23  
    24  #define VMM_DEADLOOP()          VMM_DEADLOOP_LOG(GPM_C)
    25  #define VMM_ASSERT(__condition) VMM_ASSERT_LOG(GPM_C, __condition)
    26  #ifdef JLMDEBUG
    27  #include "jlmdebug.h"
    28  #endif
    29  
    30  #define GPM_INVALID_MAPPING (MAM_MAPPING_SUCCESSFUL + 1)
    31  #define GPM_MMIO            (MAM_MAPPING_SUCCESSFUL + 2)
    32  
    33  
    34  typedef struct GPM_S {
    35          MAM_HANDLE gpa_to_hpa;
    36          MAM_HANDLE hpa_to_gpa;
    37  } GPM;
    38  
    39  static BOOLEAN gpm_get_range_details_and_advance_mam_iterator(IN MAM_HANDLE mam_handle,
    40                             IN OUT MAM_MEMORY_RANGES_ITERATOR* mem_ranges_iter,
    41                             OUT UINT64* range_start, OUT UINT64* range_size) {
    42      MAM_MEMORY_RANGES_ITERATOR iter = *mem_ranges_iter;
    43      MAM_MAPPING_RESULT res;
    44  
    45      VMM_ASSERT(*mem_ranges_iter != MAM_INVALID_MEMORY_RANGES_ITERATOR);
    46      do {
    47          UINT64 tgt_addr;
    48          MAM_ATTRIBUTES attrs;
    49  
    50          iter = mam_get_range_details_from_iterator(mam_handle, iter, range_start, range_size);
    51          res = mam_get_mapping(mam_handle, *range_start, &tgt_addr, &attrs);
    52      } while ((res != MAM_MAPPING_SUCCESSFUL) &&
    53               (res != GPM_MMIO) &&
    54               (iter != MAM_INVALID_MEMORY_RANGES_ITERATOR));
    55  
    56      *mem_ranges_iter = iter;
    57      if (iter != MAM_INVALID_MEMORY_RANGES_ITERATOR) {
    58          return TRUE;
    59      }
    60      if ((res == MAM_MAPPING_SUCCESSFUL) || (res == GPM_MMIO)) {
    61          return TRUE;
    62      }
    63      return FALSE;
    64  }
    65  
    66  
    67  BOOLEAN gpm_remove_all_relevant_hpa_to_gpa_mapping(GPM* gpm, GPA gpa, UINT64 size) {
    68      MAM_HANDLE gpa_to_hpa;
    69      MAM_HANDLE hpa_to_gpa;
    70      UINT64 gpa_tmp;
    71      gpa_to_hpa = gpm->gpa_to_hpa;
    72      hpa_to_gpa = gpm->hpa_to_gpa;
    73  
    74      // Remove all hpa mappings
    75      for (gpa_tmp = gpa; gpa_tmp < gpa + size; gpa_tmp += PAGE_4KB_SIZE) {
    76          UINT64 hpa;
    77          MAM_ATTRIBUTES attrs;
    78  
    79          if (mam_get_mapping(gpa_to_hpa, gpa_tmp, &hpa, &attrs) == MAM_MAPPING_SUCCESSFUL) {
    80              if (!mam_insert_not_existing_range(hpa_to_gpa, hpa, PAGE_4KB_SIZE, GPM_INVALID_MAPPING)) {
    81                  return FALSE;
    82              }
    83          }
    84      }
    85      return TRUE;
    86  }
    87  
    88  
    89  GPM_HANDLE gpm_create_mapping(void) {
    90      GPM* gpm;
    91      MAM_HANDLE gpa_to_hpa;
    92      MAM_HANDLE hpa_to_gpa;
    93  
    94      gpm = (GPM*)vmm_memory_alloc(sizeof(GPM));
    95      if (gpm == NULL) {
    96          goto failed_to_allocated_gpm;
    97      }
    98      gpa_to_hpa = mam_create_mapping(MAM_NO_ATTRIBUTES);
    99      if (gpa_to_hpa == MAM_INVALID_HANDLE) {
   100          goto failed_to_allocate_gpa_to_hpa_mapping;
   101      }
   102      hpa_to_gpa = mam_create_mapping(MAM_NO_ATTRIBUTES);
   103      if (hpa_to_gpa == MAM_INVALID_HANDLE) {
   104          goto failed_to_allocate_hpa_to_gpa_mapping;
   105      }
   106      gpm->gpa_to_hpa = gpa_to_hpa;
   107      gpm->hpa_to_gpa = hpa_to_gpa;
   108      return (GPM_HANDLE)gpm;
   109  
   110  failed_to_allocate_hpa_to_gpa_mapping:
   111          mam_destroy_mapping(gpa_to_hpa);
   112  failed_to_allocate_gpa_to_hpa_mapping:
   113          vmm_memory_free(gpm);
   114  failed_to_allocated_gpm:
   115          return GPM_INVALID_HANDLE;
   116  }
   117  
   118  BOOLEAN gpm_add_mapping(IN GPM_HANDLE gpm_handle, IN GPA gpa, IN HPA hpa, IN UINT64 size, MAM_ATTRIBUTES attrs) {
   119          GPM* gpm = (GPM*)gpm_handle;
   120      MAM_HANDLE gpa_to_hpa;
   121  
   122      if (gpm_handle == GPM_INVALID_HANDLE) {
   123          return FALSE;
   124      }
   125      gpa_to_hpa = gpm->gpa_to_hpa;
   126      if (!mam_insert_range(gpa_to_hpa, (UINT64)gpa, (UINT64)hpa, size, attrs)) {
   127          return FALSE;
   128      }
   129  #ifdef USE_HPA_TO_GPA
   130      MAM_HANDLE hpa_to_gpa;
   131      hpa_to_gpa = gpm->hpa_to_gpa;
   132      if (!mam_insert_range(hpa_to_gpa, (UINT64)hpa, (UINT64)gpa, size, attrs)) {
   133          return FALSE;
   134      }
   135  #endif
   136      return TRUE;
   137  }
   138  
   139  BOOLEAN gpm_remove_mapping(IN GPM_HANDLE gpm_handle, IN GPA gpa, IN UINT64 size) {
   140          GPM* gpm = (GPM*)gpm_handle;
   141      MAM_HANDLE gpa_to_hpa;
   142  
   143      if (gpm_handle == GPM_INVALID_HANDLE) {
   144          return FALSE;
   145      }
   146  #ifdef USE_HPA_TO_GPA
   147      // Remove all hpa mappings
   148      if (!gpm_remove_all_relevant_hpa_to_gpa_mapping(gpm, gpa, size)) {
   149          return FALSE;
   150      }
   151  #endif
   152      gpa_to_hpa = gpm->gpa_to_hpa;
   153      return (BOOLEAN)mam_insert_not_existing_range(gpa_to_hpa, (UINT64)gpa, size, GPM_INVALID_MAPPING);
   154  }
   155  
   156  
   157  BOOLEAN gpm_add_mmio_range(IN GPM_HANDLE gpm_handle, IN GPA gpa, IN UINT64 size) {
   158      GPM* gpm = (GPM*)gpm_handle;
   159      MAM_HANDLE gpa_to_hpa;
   160  
   161      if (gpm_handle == GPM_INVALID_HANDLE) {
   162          return FALSE;
   163      }
   164  
   165  #ifdef USE_HPA_TO_GPA
   166      // Remove all hpa mappings
   167      if (!gpm_remove_all_relevant_hpa_to_gpa_mapping(gpm, gpa, size)) {
   168          return FALSE;
   169      }
   170  #endif
   171      gpa_to_hpa = gpm->gpa_to_hpa;
   172      return (BOOLEAN)mam_insert_not_existing_range(gpa_to_hpa,
   173                            (UINT64)gpa, size, GPM_MMIO);
   174  }
   175  
   176  BOOLEAN gpm_is_mmio_address(IN GPM_HANDLE gpm_handle, IN GPA gpa) {
   177      GPM* gpm = (GPM*)gpm_handle;
   178      MAM_HANDLE gpa_to_hpa;
   179      UINT64 hpa_tmp;
   180      MAM_MAPPING_RESULT res;
   181      MAM_ATTRIBUTES attrs;
   182  
   183      if (gpm_handle == GPM_INVALID_HANDLE) {
   184          return FALSE;
   185      }
   186      gpa_to_hpa = gpm->gpa_to_hpa;
   187      res = (BOOLEAN)mam_get_mapping(gpa_to_hpa, (UINT64)gpa, &hpa_tmp, &attrs);
   188      if (res != GPM_MMIO) {
   189          return FALSE;
   190      }
   191      return TRUE;
   192  }
   193  
   194  
   195  BOOLEAN gpm_gpa_to_hpa(IN GPM_HANDLE gpm_handle, IN GPA gpa, OUT HPA* hpa, 
   196                          OUT MAM_ATTRIBUTES *hpa_attrs) {
   197      GPM* gpm = (GPM*)gpm_handle;
   198      MAM_HANDLE gpa_to_hpa;
   199      UINT64 hpa_tmp;
   200      MAM_MAPPING_RESULT res;
   201      MAM_ATTRIBUTES attrs;
   202  
   203      if (gpm_handle == GPM_INVALID_HANDLE) {
   204          return FALSE;
   205      }
   206      gpa_to_hpa = gpm->gpa_to_hpa;
   207      res = mam_get_mapping(gpa_to_hpa, (UINT64)gpa, &hpa_tmp, &attrs);
   208      if (res != MAM_MAPPING_SUCCESSFUL) {
   209          return FALSE;
   210      }
   211      *hpa = *((HPA*)(&hpa_tmp));
   212      *hpa_attrs = *((MAM_ATTRIBUTES*)(&attrs));
   213      return TRUE;
   214  }
   215  
   216  BOOLEAN gpm_gpa_to_hva(IN GPM_HANDLE gpm_handle, IN GPA gpa, OUT HVA* hva) {
   217          GPM* gpm = (GPM*)gpm_handle;
   218      MAM_HANDLE gpa_to_hpa;
   219      UINT64 hpa_tmp;
   220      UINT64 hva_tmp;
   221      HPA hpa;
   222      MAM_MAPPING_RESULT res;
   223      MAM_ATTRIBUTES attrs;
   224  
   225      if (gpm_handle == GPM_INVALID_HANDLE) {
   226          return FALSE;
   227      }
   228      gpa_to_hpa = gpm->gpa_to_hpa;
   229      res = (BOOLEAN)mam_get_mapping(gpa_to_hpa, (UINT64)gpa, &hpa_tmp, &attrs);
   230      if (res != MAM_MAPPING_SUCCESSFUL) {
   231          return FALSE;
   232      }
   233      hpa = *((HPA*)(&hpa_tmp));
   234      res = hmm_hpa_to_hva(hpa, &hva_tmp);
   235      if (res) {
   236          *hva = *((HVA*)(&hva_tmp));
   237      }
   238      else {
   239          VMM_LOG(mask_anonymous, level_trace,"Warning!!! Failed Translation Host Physical to Host Virtual\n");
   240      }
   241      return res;
   242  }
   243  
   244  BOOLEAN gpm_hpa_to_gpa(IN GPM_HANDLE gpm_handle, IN HPA hpa, OUT GPA* gpa) {
   245          GPM* gpm = (GPM*)gpm_handle;
   246      MAM_HANDLE hpa_to_gpa;
   247      UINT64 gpa_tmp;
   248      MAM_MAPPING_RESULT res;
   249      MAM_ATTRIBUTES attrs;
   250  
   251      if (gpm_handle == GPM_INVALID_HANDLE) {
   252          return FALSE;
   253      }
   254  
   255      hpa_to_gpa = gpm->hpa_to_gpa;
   256      res = mam_get_mapping(hpa_to_gpa, (UINT64)hpa, &gpa_tmp, &attrs);
   257      if (res != MAM_MAPPING_SUCCESSFUL) {
   258          return FALSE;
   259      }
   260      *gpa = *((GPA*)(&gpa_tmp));
   261      return TRUE;
   262  }
   263  
   264  BOOLEAN gpm_create_e820_map(IN GPM_HANDLE gpm_handle,
   265                              OUT E820_HANDLE* e820_handle) {
   266      GPM* gpm = (GPM*)gpm_handle;
   267      MAM_HANDLE gpa_to_hpa;
   268      E820_HANDLE e820_map;
   269      E820_ABSTRACTION_RANGE_ITERATOR e820_iter;
   270      MAM_MEMORY_RANGES_ITERATOR mem_ranges_iter;
   271      GPA range_start;
   272      UINT64 range_size;
   273      GPA addr;
   274      UINT64 size;
   275  
   276      if (gpm_handle == GPM_INVALID_HANDLE) {
   277          return FALSE;
   278      }
   279      gpa_to_hpa = gpm->gpa_to_hpa;
   280      if (!e820_abstraction_create_new_map(&e820_map)) {
   281          return FALSE;
   282      }
   283      e820_iter = e820_abstraction_iterator_get_first(E820_ORIGINAL_MAP);
   284      mem_ranges_iter = mam_get_memory_ranges_iterator(gpa_to_hpa);
   285      if ((mem_ranges_iter == MAM_INVALID_MEMORY_RANGES_ITERATOR) ||
   286          (e820_iter == E820_ABSTRACTION_NULL_ITERATOR)) {
   287          return FALSE;
   288      }
   289      if(!gpm_get_range_details_and_advance_mam_iterator(gpa_to_hpa, &mem_ranges_iter, &range_start, &range_size)) {
   290          // No appropriate ranges exist
   291          return FALSE;
   292      }
   293      while (e820_iter != E820_ABSTRACTION_NULL_ITERATOR) {
   294          const INT15_E820_MEMORY_MAP_ENTRY_EXT* orig_map_entry = e820_abstraction_iterator_get_range_details(e820_iter);
   295  
   296          if (((UINT64)range_start >= orig_map_entry->basic_entry.base_address) &&
   297              ((UINT64)range_start + range_size <= orig_map_entry->basic_entry.base_address + orig_map_entry->basic_entry.length)) {
   298              BOOLEAN encountered_non_contigues_regions = FALSE;
   299              while ((mem_ranges_iter != MAM_INVALID_MEMORY_RANGES_ITERATOR) &&
   300                     ((UINT64)range_start + range_size <= orig_map_entry->basic_entry.base_address + orig_map_entry->basic_entry.length)) {
   301  
   302                  if(!gpm_get_range_details_and_advance_mam_iterator(gpa_to_hpa, &mem_ranges_iter, &addr, &size)) {
   303                      // There are no more ranges
   304                      break;
   305                  }
   306                  if (addr > (range_start + range_size)) {
   307                      if (!e820_abstraction_add_new_range(e820_map, range_start, range_size, orig_map_entry->basic_entry.address_range_type, orig_map_entry->extended_attributes)) {
   308                          goto failed_to_fill;
   309                      }
   310                      range_start = addr;
   311                      range_size = size;
   312                      encountered_non_contigues_regions = TRUE;
   313                      break;
   314                  }
   315                  else {
   316                      VMM_ASSERT(addr == (range_start + range_size));
   317                      range_size += size;
   318                  }
   319              }
   320              if (encountered_non_contigues_regions) {
   321                  continue; // resume outer loop iterations.
   322              }
   323              if ((UINT64)range_start + range_size > orig_map_entry->basic_entry.base_address + orig_map_entry->basic_entry.length) {
   324                  continue; // There are global_case for it
   325              }
   326              VMM_ASSERT(mem_ranges_iter == MAM_INVALID_MEMORY_RANGES_ITERATOR);
   327              if (!e820_abstraction_add_new_range(e820_map, range_start, range_size, orig_map_entry->basic_entry.address_range_type, orig_map_entry->extended_attributes)) {
   328                  goto failed_to_fill;
   329              }
   330              break; // There are no more gpm ranges
   331          }
   332          else if ((range_start + range_size) <= orig_map_entry->basic_entry.base_address) {
   333              // Skip the range
   334              if (mem_ranges_iter == MAM_INVALID_MEMORY_RANGES_ITERATOR) {
   335                  break; // No more valid ranges
   336              }
   337              if (!gpm_get_range_details_and_advance_mam_iterator(gpa_to_hpa, &mem_ranges_iter, &range_start, &range_size)) {
   338                  break;
   339              }
   340              continue;
   341          }
   342          else if (orig_map_entry->basic_entry.base_address + orig_map_entry->basic_entry.length <= range_start) {
   343              e820_iter = e820_abstraction_iterator_get_next(E820_ORIGINAL_MAP, e820_iter);
   344              continue;
   345          }
   346          else if ((range_start < orig_map_entry->basic_entry.base_address) &&
   347                   (range_start + range_size > orig_map_entry->basic_entry.base_address)) {
   348              range_size = range_start + range_size - orig_map_entry->basic_entry.base_address;
   349              range_start = orig_map_entry->basic_entry.base_address;
   350              continue;
   351          }
   352          else {
   353              UINT64 new_size = orig_map_entry->basic_entry.base_address + orig_map_entry->basic_entry.length - range_start;
   354              VMM_ASSERT(range_start >= orig_map_entry->basic_entry.base_address);
   355              VMM_ASSERT(range_start + range_size > orig_map_entry->basic_entry.base_address + orig_map_entry->basic_entry.length);
   356              VMM_ASSERT(new_size > 0);
   357  
   358              if (!e820_abstraction_add_new_range(e820_map, range_start, new_size, orig_map_entry->basic_entry.address_range_type, orig_map_entry->extended_attributes)) {
   359                  goto failed_to_fill;
   360              }
   361              range_start += new_size;
   362              range_size -= new_size;
   363              continue;
   364          }
   365      }
   366      *e820_handle = e820_map;
   367      return TRUE;
   368  
   369  failed_to_fill:
   370      e820_abstraction_destroy_map(e820_map);
   371      return FALSE;
   372  }
   373  
   374  void gpm_destroy_e820_map(IN E820_HANDLE e820_handle) {
   375      e820_abstraction_destroy_map(e820_handle);
   376  }
   377  
   378  
   379  MAM_MEMORY_RANGES_ITERATOR gpm_advance_mam_iterator_to_appropriate_range(MAM_HANDLE mam_handle, MAM_MEMORY_RANGES_ITERATOR iter) {
   380      UINT64 src_addr;
   381      UINT64 tgt_addr;
   382      MAM_ATTRIBUTES attr;
   383      MAM_MAPPING_RESULT res;
   384      UINT64 size;
   385  
   386      src_addr = mam_get_range_start_address_from_iterator(mam_handle, iter);
   387      res = mam_get_mapping(mam_handle, src_addr, &tgt_addr, &attr);
   388      while ((res != MAM_MAPPING_SUCCESSFUL) &&
   389             (res != GPM_MMIO) &&
   390             (iter != MAM_INVALID_MEMORY_RANGES_ITERATOR)) {
   391          iter = mam_get_range_details_from_iterator(mam_handle, iter, &src_addr, &size);
   392          src_addr = mam_get_range_start_address_from_iterator(mam_handle, iter);
   393          res = mam_get_mapping(mam_handle, src_addr, &tgt_addr, &attr);
   394      }
   395      return iter;
   396  }
   397  
   398  GPM_RANGES_ITERATOR gpm_get_ranges_iterator(IN GPM_HANDLE gpm_handle) {
   399      GPM* gpm = (GPM*)gpm_handle;
   400      MAM_HANDLE gpa_to_hpa;
   401      MAM_MEMORY_RANGES_ITERATOR iter;
   402  
   403      if (gpm_handle == GPM_INVALID_HANDLE) {
   404          return GPM_INVALID_RANGES_ITERATOR;
   405      }
   406      gpa_to_hpa = gpm->gpa_to_hpa;
   407      iter = mam_get_memory_ranges_iterator(gpa_to_hpa);
   408      if (iter == MAM_INVALID_MEMORY_RANGES_ITERATOR) {
   409          return GPM_INVALID_RANGES_ITERATOR;
   410      }
   411      iter = gpm_advance_mam_iterator_to_appropriate_range(gpa_to_hpa, iter);
   412      if (iter == MAM_INVALID_MEMORY_RANGES_ITERATOR) {
   413          return GPM_INVALID_RANGES_ITERATOR;
   414      }
   415      return (GPM_RANGES_ITERATOR)iter;
   416  }
   417  
   418  GPM_RANGES_ITERATOR gpm_get_range_details_from_iterator(IN GPM_HANDLE gpm_handle,
   419                                   IN GPM_RANGES_ITERATOR iter, OUT GPA* gpa_out,
   420                                   OUT UINT64* size_out) {
   421      GPM* gpm = (GPM*)gpm_handle;
   422      MAM_HANDLE gpa_to_hpa;
   423      MAM_MEMORY_RANGES_ITERATOR mam_iter = (MAM_MEMORY_RANGES_ITERATOR)iter;
   424  
   425      // BEFORE_VMLAUNCH. CRITICAL check that should not fail.
   426      VMM_ASSERT(gpm_handle != GPM_INVALID_HANDLE);
   427  
   428      if (iter == GPM_INVALID_RANGES_ITERATOR) {
   429          *gpa_out = ~((UINT64)0);
   430          *size_out = 0;
   431          return GPM_INVALID_RANGES_ITERATOR;
   432      }
   433      gpa_to_hpa = gpm->gpa_to_hpa;
   434      mam_iter = mam_get_range_details_from_iterator(gpa_to_hpa, mam_iter, gpa_out, size_out);
   435      mam_iter = gpm_advance_mam_iterator_to_appropriate_range(gpa_to_hpa, mam_iter);
   436      if (mam_iter == MAM_INVALID_MEMORY_RANGES_ITERATOR) {
   437          return GPM_INVALID_RANGES_ITERATOR;
   438      }
   439      return (GPM_RANGES_ITERATOR)mam_iter;
   440  }
   441  
   442  #pragma warning (disable : 4100)
   443  #pragma warning (disable : 4189)
   444  
   445  void gpm_print(GPM_HANDLE gpm_handle USED_IN_DEBUG_ONLY)
   446  {
   447  VMM_DEBUG_CODE(
   448  
   449      E820_HANDLE guest_e820 = NULL;
   450      GPM_RANGES_ITERATOR gpm_iter = GPM_INVALID_RANGES_ITERATOR;
   451      BOOLEAN status = FALSE;
   452      GPA guest_range_addr = 0;
   453      UINT64 guest_range_size = 0;
   454      HPA host_range_addr = 0;
   455          MAM_ATTRIBUTES attrs;
   456  
   457      VMM_LOG(mask_anonymous, level_trace,"GPM ranges:\r\n");
   458      gpm_iter = gpm_get_ranges_iterator(gpm_handle);
   459      while(GPM_INVALID_RANGES_ITERATOR != gpm_iter) {
   460          gpm_iter = gpm_get_range_details_from_iterator(gpm_handle,
   461                                   gpm_iter, &guest_range_addr, &guest_range_size);
   462          status = gpm_gpa_to_hpa(gpm_handle, guest_range_addr, &host_range_addr, &attrs);
   463          if(FALSE == status) {
   464              VMM_LOG(mask_anonymous, level_trace,"GPM no mapping for gpa %p\r\n", guest_range_addr);
   465          }
   466          else {
   467              VMM_LOG(mask_anonymous, level_trace,"  base %p size %p\r\n", guest_range_addr, guest_range_size);
   468          }
   469      }
   470      gpm_create_e820_map(gpm_handle, &guest_e820);
   471      e820_abstraction_print_memory_map(guest_e820);
   472      )
   473  }
   474  
   475  BOOLEAN gpm_copy(GPM_HANDLE src, GPM_HANDLE dst, BOOLEAN override_attrs, 
   476                   MAM_ATTRIBUTES set_attrs)
   477  {
   478      GPM_RANGES_ITERATOR src_iter = GPM_INVALID_RANGES_ITERATOR;
   479      GPA guest_range_addr = 0;
   480      UINT64 guest_range_size = 0;
   481      HPA host_range_addr = 0;
   482      BOOLEAN status = FALSE;
   483      MAM_ATTRIBUTES attrs;
   484  
   485      src_iter = gpm_get_ranges_iterator(src);
   486      while(GPM_INVALID_RANGES_ITERATOR != src_iter) {
   487          src_iter = gpm_get_range_details_from_iterator(src,
   488                                   src_iter, &guest_range_addr,
   489                                   &guest_range_size);
   490          status = gpm_gpa_to_hpa(src, guest_range_addr, &host_range_addr, &attrs);
   491          if(FALSE == status) {  // no mapping - is it mmio?
   492              if(gpm_is_mmio_address(src, guest_range_addr)){
   493                  status = gpm_add_mmio_range(dst, guest_range_addr, guest_range_size);
   494                  if(FALSE == status) {
   495                      goto failure;
   496                  }
   497              }
   498              else {
   499                  // normal memory - should not fail the mapping translation
   500                  goto failure;
   501              }
   502          }
   503          else {
   504              if (override_attrs) {
   505                  status = gpm_add_mapping(dst, guest_range_addr, host_range_addr, 
   506                                           guest_range_size, set_attrs);
   507              }
   508              else {
   509                  status = gpm_add_mapping(dst, guest_range_addr, host_range_addr, guest_range_size, attrs);
   510              }
   511              if(FALSE == status) {
   512                  goto failure;
   513              }
   514          }
   515      }
   516      return TRUE;
   517  
   518  failure:
   519      return FALSE;
   520  }
   521