typename allocator<T>::pointer allocator<T>::allocate(size_type n, void *const hint) { const size_type nb = n * sizeof(T); # if DEBUG_SMA_TRACE_INTERFACE std::cout << "alloc " << nb << " bytes (n=" << n << ", hint=" << static_cast<void *>(hint) << ")" << std::endl; # endif assert(nb > 0); if (!(nb > 0)) { std::cerr << "cannot allocate a memory block of size " << nb << std::endl; goto badalloc; } if (nb > memfree->size()) { std::cerr << "triing to allocate a memory block of size " << nb << " bytes, " << "but the managed memory has only a size of " << memfree->size() << " bytes." << std::endl; goto badalloc; } {//block auto mask = create_mask(nb, memfree->size()); const size_type pos = find_free_memory(*memfree, mask); assert(0 <= pos && pos <= memfree->size()); if (pos < memfree->size()) { # if DEBUG_SMA_TRACE_MEMALLOCATION std::cout << "reserved memory: " << mask.count() << " bytes -> " << (memfree->count() - mask.count()) << " bytes free." << std::endl; # endif *memfree = reserve_memory(*memfree, std::move(mask)); # if DEBUG_SMA_TRACE_MEMALLOCATION print_free_memory(); # endif return calc_pointer(memstart, pos); } else { # if DEBUG_SMA_TRACE_MEMALLOCATION std::cout << "not enough free memory to allocate " << nb << " bytes." << std::endl; print_free_memory(); # endif } } badalloc: /* not enough memory free */ throw std::bad_alloc(); return nullptr; }
static int dom0_memory_reserve(uint32_t rsv_size) { uint64_t pfn, vstart, vaddr; uint32_t i, num_block, size, allocated_size = 0; #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 13, 0) dma_addr_t dma_handle; #endif /* 2M as memory block */ num_block = rsv_size / SIZE_PER_BLOCK; rsv_mm_info = vmalloc(sizeof(struct memblock_info) * num_block); if (!rsv_mm_info) { XEN_ERR("Unable to allocate device memory information\n"); return -ENOMEM; } memset(rsv_mm_info, 0, sizeof(struct memblock_info) * num_block); /* try alloc size of 4M once */ for (i = 0; i < num_block; i += 2) { vstart = (unsigned long) __get_free_pages(GFP_ATOMIC, MAX_NUM_ORDER); if (vstart == 0) break; dom0_dev.num_bigblock = i / 2 + 1; allocated_size = SIZE_PER_BLOCK * (i + 2); /* size of 4M */ size = DOM0_MEMBLOCK_SIZE * 2; vaddr = vstart; while (size > 0) { SetPageReserved(virt_to_page(vaddr)); vaddr += PAGE_SIZE; size -= PAGE_SIZE; } pfn = virt_to_pfn(vstart); rsv_mm_info[i].pfn = pfn; rsv_mm_info[i].vir_addr = vstart; rsv_mm_info[i + 1].pfn = pfn + DOM0_MEMBLOCK_SIZE / PAGE_SIZE; rsv_mm_info[i + 1].vir_addr = vstart + DOM0_MEMBLOCK_SIZE; } /*if it failed to alloc 4M, and continue to alloc 2M once */ for (; i < num_block; i++) { vstart = (unsigned long) __get_free_pages(GFP_ATOMIC, DOM0_CONTIG_NUM_ORDER); if (vstart == 0) { XEN_ERR("allocate memory fail.\n"); dom0_memory_free(allocated_size); return -ENOMEM; } allocated_size += SIZE_PER_BLOCK; size = DOM0_MEMBLOCK_SIZE; vaddr = vstart; while (size > 0) { SetPageReserved(virt_to_page(vaddr)); vaddr += PAGE_SIZE; size -= PAGE_SIZE; } pfn = virt_to_pfn(vstart); rsv_mm_info[i].pfn = pfn; rsv_mm_info[i].vir_addr = vstart; } sort_viraddr(rsv_mm_info, num_block); for (i = 0; i< num_block; i++) { /* * This API is used to exchage MFN for getting a block of * contiguous physical addresses, its maximum size is 2M. */ #if LINUX_VERSION_CODE < KERNEL_VERSION(3, 13, 0) if (xen_create_contiguous_region(rsv_mm_info[i].vir_addr, DOM0_CONTIG_NUM_ORDER, 0) == 0) { #else if (xen_create_contiguous_region(rsv_mm_info[i].pfn * PAGE_SIZE, DOM0_CONTIG_NUM_ORDER, 0, &dma_handle) == 0) { #endif rsv_mm_info[i].exchange_flag = 1; rsv_mm_info[i].mfn = pfn_to_mfn(rsv_mm_info[i].pfn); rsv_mm_info[i].used = 0; } else { XEN_ERR("exchange memeory fail\n"); rsv_mm_info[i].exchange_flag = 0; dom0_dev.fail_times++; if (dom0_dev.fail_times > MAX_EXCHANGE_FAIL_TIME) { dom0_memory_free(rsv_size); return -EFAULT; } } } return 0; } static int dom0_prepare_memsegs(struct memory_info *meminfo, struct dom0_mm_data *mm_data) { uint32_t num_block; int idx; /* check if there is a free name buffer */ memcpy(mm_data->name, meminfo->name, DOM0_NAME_MAX); mm_data->name[DOM0_NAME_MAX - 1] = '\0'; idx = dom0_find_mempos(); if (idx < 0) return -1; num_block = meminfo->size / SIZE_PER_BLOCK; /* find free memory and new memory segments*/ find_free_memory(num_block, mm_data); find_memseg(num_block, mm_data); /* update private memory data */ mm_data->refcnt++; mm_data->mem_size = meminfo->size; /* update global memory data */ dom0_dev.mm_data[idx] = mm_data; dom0_dev.num_mem_ctx++; dom0_dev.used_memsize += mm_data->mem_size; return 0; }