4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
17 * * Neither the name of Intel Corporation nor the names of its
18 * contributors may be used to endorse or promote products derived
19 * from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42 #include <sys/types.h>
44 #include <sys/queue.h>
48 #include <sys/ioctl.h>
52 #include <rte_memory.h>
53 #include <rte_memzone.h>
54 #include <rte_launch.h>
56 #include <rte_eal_memconfig.h>
57 #include <rte_per_lcore.h>
58 #include <rte_lcore.h>
59 #include <rte_common.h>
60 #include <rte_string_fns.h>
62 #include "eal_private.h"
63 #include "eal_internal_cfg.h"
64 #include "eal_filesystem.h"
65 #include <exec-env/rte_dom0_common.h>
67 #define PAGE_SIZE RTE_PGSIZE_4K
68 #define DEFAUL_DOM0_NAME "dom0-mem"
70 static int xen_fd = -1;
71 static const char sys_dir_path[] = "/sys/kernel/mm/dom0-mm/memsize-mB";
74 * Try to mmap *size bytes in /dev/zero. If it is successful, return the
75 * pointer to the mmap'd area and keep *size unmodified. Else, retry
76 * with a smaller zone: decrease *size by mem_size until it reaches
77 * 0. In this case, return NULL. Note: this function returns an address
78 * which is a multiple of mem_size size.
81 xen_get_virtual_area(size_t *size, size_t mem_size)
87 RTE_LOG(DEBUG, EAL, "Ask a virtual area of 0x%zu bytes\n", *size);
89 fd = open("/dev/zero", O_RDONLY);
91 RTE_LOG(ERR, EAL, "Cannot open /dev/zero\n");
95 addr = mmap(NULL, (*size) + mem_size, PROT_READ,
97 if (addr == MAP_FAILED)
99 } while (addr == MAP_FAILED && *size > 0);
101 if (addr == MAP_FAILED) {
103 RTE_LOG(ERR, EAL, "Cannot get a virtual area\n");
107 munmap(addr, (*size) + mem_size);
110 /* align addr to a mem_size boundary */
111 aligned_addr = (uintptr_t)addr;
112 aligned_addr = RTE_ALIGN_CEIL(aligned_addr, mem_size);
113 addr = (void *)(aligned_addr);
115 RTE_LOG(DEBUG, EAL, "Virtual area found at %p (size = 0x%zx)\n",
122 * Get memory size configuration from /sys/devices/virtual/misc/dom0_mm
123 * /memsize-mB/memsize file, and the size unit is mB.
126 get_xen_memory_size(void)
129 unsigned long mem_size = 0;
130 static const char *file_name;
132 file_name = "memsize";
133 snprintf(path, sizeof(path), "%s/%s",
134 sys_dir_path, file_name);
136 if (eal_parse_sysfs_value(path, &mem_size) < 0)
140 rte_exit(EXIT_FAILURE,"XEN-DOM0:the %s/%s was not"
141 " configured.\n",sys_dir_path, file_name);
143 rte_exit(EXIT_FAILURE,"XEN-DOM0:the %s/%s must be"
144 " even number.\n",sys_dir_path, file_name);
146 if (mem_size > DOM0_CONFIG_MEMSIZE)
147 rte_exit(EXIT_FAILURE,"XEN-DOM0:the %s/%s should not be larger"
148 " than %d mB\n",sys_dir_path, file_name, DOM0_CONFIG_MEMSIZE);
154 * Based on physical address to caculate MFN in Xen Dom0.
157 rte_xen_mem_phy2mch(int32_t memseg_id, const phys_addr_t phy_addr)
160 uint64_t mfn, mfn_offset;
161 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
162 struct rte_memseg *memseg = mcfg->memseg;
164 /* find the memory segment owning the physical address */
165 if (memseg_id == -1) {
166 for (i = 0; i < RTE_MAX_MEMSEG; i++) {
167 if ((phy_addr >= memseg[i].phys_addr) &&
168 (phy_addr < memseg[i].phys_addr +
175 return RTE_BAD_PHYS_ADDR;
178 mfn_id = (phy_addr - memseg[memseg_id].phys_addr) / RTE_PGSIZE_2M;
180 /*the MFN is contiguous in 2M */
181 mfn_offset = (phy_addr - memseg[memseg_id].phys_addr) %
182 RTE_PGSIZE_2M / PAGE_SIZE;
183 mfn = mfn_offset + memseg[memseg_id].mfn[mfn_id];
185 /** return mechine address */
186 return mfn * PAGE_SIZE + phy_addr % PAGE_SIZE;
190 rte_xen_dom0_memory_init(void)
192 void *vir_addr, *vma_addr = NULL;
194 uint32_t i, requested, mem_size, memseg_idx, num_memseg = 0;
196 struct memory_info meminfo;
197 struct memseg_info seginfo[RTE_MAX_MEMSEG];
198 int flags, page_size = getpagesize();
199 struct rte_mem_config *mcfg = rte_eal_get_configuration()->mem_config;
200 struct rte_memseg *memseg = mcfg->memseg;
201 uint64_t total_mem = internal_config.memory;
203 memset(seginfo, 0, sizeof(seginfo));
204 memset(&meminfo, 0, sizeof(struct memory_info));
206 mem_size = get_xen_memory_size();
207 requested = (unsigned) (total_mem / 0x100000);
208 if (requested > mem_size)
209 /* if we didn't satisfy total memory requirements */
210 rte_exit(EXIT_FAILURE,"Not enough memory available! Requested: %uMB,"
211 " available: %uMB\n", requested, mem_size);
212 else if (total_mem != 0)
213 mem_size = requested;
215 /* Check FD and open once */
217 xen_fd = open(DOM0_MM_DEV, O_RDWR);
219 RTE_LOG(ERR, EAL, "Can not open %s\n",DOM0_MM_DEV);
224 meminfo.size = mem_size;
226 /* construct memory mangement name for Dom0 */
227 snprintf(meminfo.name, DOM0_NAME_MAX, "%s-%s",
228 internal_config.hugefile_prefix, DEFAUL_DOM0_NAME);
230 /* Notify kernel driver to allocate memory */
231 ret = ioctl(xen_fd, RTE_DOM0_IOCTL_PREPARE_MEMSEG, &meminfo);
233 RTE_LOG(ERR, EAL, "XEN DOM0:failed to get memory\n");
238 /* Get number of memory segment from driver */
239 ret = ioctl(xen_fd, RTE_DOM0_IOCTL_GET_NUM_MEMSEG, &num_memseg);
241 RTE_LOG(ERR, EAL, "XEN DOM0:failed to get memseg count.\n");
246 if(num_memseg > RTE_MAX_MEMSEG){
247 RTE_LOG(ERR, EAL, "XEN DOM0: the memseg count %d is greater"
248 " than max memseg %d.\n",num_memseg, RTE_MAX_MEMSEG);
253 /* get all memory segements information */
254 ret = ioctl(xen_fd, RTE_DOM0_IOCTL_GET_MEMSEG_INFO, seginfo);
256 RTE_LOG(ERR, EAL, "XEN DOM0:failed to get memseg info.\n");
261 /* map all memory segments to contiguous user space */
262 for (memseg_idx = 0; memseg_idx < num_memseg; memseg_idx++)
264 vma_len = seginfo[memseg_idx].size;
267 * get the biggest virtual memory area up to vma_len. If it fails,
268 * vma_addr is NULL, so let the kernel provide the address.
270 vma_addr = xen_get_virtual_area(&vma_len, RTE_PGSIZE_2M);
271 if (vma_addr == NULL) {
273 vma_len = RTE_PGSIZE_2M;
275 flags = MAP_SHARED | MAP_FIXED;
277 seginfo[memseg_idx].size = vma_len;
278 vir_addr = mmap(vma_addr, seginfo[memseg_idx].size,
279 PROT_READ|PROT_WRITE, flags, xen_fd,
280 memseg_idx * page_size);
281 if (vir_addr == MAP_FAILED) {
282 RTE_LOG(ERR, EAL, "XEN DOM0:Could not mmap %s\n",
288 memseg[memseg_idx].addr = vir_addr;
289 memseg[memseg_idx].phys_addr = page_size *
290 seginfo[memseg_idx].pfn ;
291 memseg[memseg_idx].len = seginfo[memseg_idx].size;
292 for ( i = 0; i < seginfo[memseg_idx].size / RTE_PGSIZE_2M; i++)
293 memseg[memseg_idx].mfn[i] = seginfo[memseg_idx].mfn[i];
295 /* MFNs are continuous in 2M, so assume that page size is 2M */
296 memseg[memseg_idx].hugepage_sz = RTE_PGSIZE_2M;
298 memseg[memseg_idx].nchannel = mcfg->nchannel;
299 memseg[memseg_idx].nrank = mcfg->nrank;
301 /* NUMA is not suppoted in Xen Dom0, so only set socket 0*/
302 memseg[memseg_idx].socket_id = 0;
315 * This creates the memory mappings in the secondary process to match that of
316 * the server process. It goes through each memory segment in the DPDK runtime
317 * configuration, mapping them in order to form a contiguous block in the
318 * virtual memory space
321 rte_xen_dom0_memory_attach(void)
323 const struct rte_mem_config *mcfg;
324 unsigned s = 0; /* s used to track the segment number */
328 char name[DOM0_NAME_MAX] = {0};
329 int page_size = getpagesize();
331 mcfg = rte_eal_get_configuration()->mem_config;
333 /* Check FD and open once */
335 xen_fd = open(DOM0_MM_DEV, O_RDWR);
337 RTE_LOG(ERR, EAL, "Can not open %s\n",DOM0_MM_DEV);
342 /* construct memory mangement name for Dom0 */
343 snprintf(name, DOM0_NAME_MAX, "%s-%s",
344 internal_config.hugefile_prefix, DEFAUL_DOM0_NAME);
345 /* attach to memory segments of primary process */
346 ret = ioctl(xen_fd, RTE_DOM0_IOCTL_ATTACH_TO_MEMSEG, name);
348 RTE_LOG(ERR, EAL,"attach memory segments fail.\n");
352 /* map all segments into memory to make sure we get the addrs */
353 for (s = 0; s < RTE_MAX_MEMSEG; ++s) {
356 * the first memory segment with len==0 is the one that
357 * follows the last valid segment.
359 if (mcfg->memseg[s].len == 0)
362 vir_addr = mmap(mcfg->memseg[s].addr, mcfg->memseg[s].len,
363 PROT_READ|PROT_WRITE, MAP_SHARED|MAP_FIXED, xen_fd,
365 if (vir_addr == MAP_FAILED) {
366 RTE_LOG(ERR, EAL, "Could not mmap %llu bytes "
367 "in %s to requested address [%p]\n",
368 (unsigned long long)mcfg->memseg[s].len, DOM0_MM_DEV,
369 mcfg->memseg[s].addr);