vppinfra: remove linux/syscall.h
[vpp.git] / src / vlib / physmem.c
1 /*
2  * Copyright (c) 2018 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 #include <unistd.h>
17 #include <sys/types.h>
18 #include <sys/mount.h>
19 #include <sys/mman.h>
20 #include <sys/fcntl.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23
24 #include <vppinfra/linux/sysfs.h>
25 #include <vlib/vlib.h>
26 #include <vlib/physmem.h>
27 #include <vlib/unix/unix.h>
28 #include <vlib/pci/pci.h>
29 #include <vlib/linux/vfio.h>
30
31 #if defined(__x86_64__) && !defined(CLIB_SANITIZE_ADDR)
32 /* we keep physmem in low 38 bits of VA address space as some
33    IOMMU implamentation cannot map above that range */
34 #define VLIB_PHYSMEM_DEFAULT_BASE_ADDDR         (1ULL << 36)
35 #else
36 /* let kernel decide */
37 #define VLIB_PHYSMEM_DEFAULT_BASE_ADDDR         0
38 #endif
39
40 clib_error_t *
41 vlib_physmem_shared_map_create (vlib_main_t * vm, char *name, uword size,
42                                 u32 log2_page_sz, u32 numa_node,
43                                 u32 * map_index)
44 {
45   clib_pmalloc_main_t *pm = vm->physmem_main.pmalloc_main;
46   vlib_physmem_main_t *vpm = &vm->physmem_main;
47   vlib_physmem_map_t *map;
48   clib_pmalloc_arena_t *a;
49   clib_error_t *error = 0;
50   void *va;
51   uword i;
52
53   va = clib_pmalloc_create_shared_arena (pm, name, size, log2_page_sz,
54                                          numa_node);
55
56   if (va == 0)
57     return clib_error_return (0, "%U", format_clib_error,
58                               clib_pmalloc_last_error (pm));
59
60   a = clib_pmalloc_get_arena (pm, va);
61
62   pool_get (vpm->maps, map);
63   *map_index = map->index = map - vpm->maps;
64   map->base = va;
65   map->fd = a->fd;
66   map->n_pages = a->n_pages * a->subpages_per_page;
67   map->log2_page_size = a->log2_subpage_sz;
68   map->numa_node = a->numa_node;
69
70   for (i = 0; i < a->n_pages; i++)
71     {
72       uword pa =
73         clib_pmalloc_get_pa (pm, (u8 *) va + (i << a->log2_subpage_sz));
74
75       /* maybe iova */
76       if (pa == 0)
77         pa = pointer_to_uword (va);
78
79       vec_add1 (map->page_table, pa);
80     }
81
82   return error;
83 }
84
85 vlib_physmem_map_t *
86 vlib_physmem_get_map (vlib_main_t * vm, u32 index)
87 {
88   vlib_physmem_main_t *vpm = &vm->physmem_main;
89   return pool_elt_at_index (vpm->maps, index);
90 }
91
92 clib_error_t *
93 vlib_physmem_init (vlib_main_t * vm)
94 {
95   vlib_physmem_main_t *vpm = &vm->physmem_main;
96   clib_error_t *error = 0;
97   u64 *pt = 0;
98   void *p;
99
100   /* check if pagemap is accessible */
101   pt = clib_mem_vm_get_paddr (&pt, min_log2 (sysconf (_SC_PAGESIZE)), 1);
102   if (pt && pt[0])
103     vpm->flags |= VLIB_PHYSMEM_MAIN_F_HAVE_PAGEMAP;
104   vec_free (pt);
105
106   if ((error = linux_vfio_init (vm)))
107     return error;
108
109   p = clib_mem_alloc_aligned (sizeof (clib_pmalloc_main_t),
110                               CLIB_CACHE_LINE_BYTES);
111   memset (p, 0, sizeof (clib_pmalloc_main_t));
112   vpm->pmalloc_main = (clib_pmalloc_main_t *) p;
113
114   if (vpm->base_addr == 0)
115     vpm->base_addr = VLIB_PHYSMEM_DEFAULT_BASE_ADDDR;
116
117   clib_pmalloc_init (vpm->pmalloc_main, vpm->base_addr, vpm->max_size);
118
119   /* update base_addr and max_size per actual allocation */
120   vpm->base_addr = (uword) vpm->pmalloc_main->base;
121   vpm->max_size = (uword) vpm->pmalloc_main->max_pages <<
122     vpm->pmalloc_main->def_log2_page_sz;
123
124   return error;
125 }
126
127 static clib_error_t *
128 show_physmem (vlib_main_t * vm,
129               unformat_input_t * input, vlib_cli_command_t * cmd)
130 {
131   vlib_physmem_main_t *vpm = &vm->physmem_main;
132   unformat_input_t _line_input, *line_input = &_line_input;
133   u32 verbose = 0, map = 0;
134
135   if (unformat_user (input, unformat_line_input, line_input))
136     {
137       while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
138         {
139           if (unformat (line_input, "verbose"))
140             verbose = 1;
141           else if (unformat (line_input, "v"))
142             verbose = 1;
143           else if (unformat (line_input, "detail"))
144             verbose = 2;
145           else if (unformat (line_input, "d"))
146             verbose = 2;
147           else if (unformat (line_input, "map"))
148             map = 1;
149           else
150             break;
151         }
152       unformat_free (line_input);
153     }
154
155   if (map)
156     vlib_cli_output (vm, " %U", format_pmalloc_map, vpm->pmalloc_main);
157   else
158     vlib_cli_output (vm, " %U", format_pmalloc, vpm->pmalloc_main, verbose);
159
160   return 0;
161 }
162
163 /* *INDENT-OFF* */
164 VLIB_CLI_COMMAND (show_physmem_command, static) = {
165   .path = "show physmem",
166   .short_help = "show physmem [verbose | detail | map]",
167   .function = show_physmem,
168 };
169 /* *INDENT-ON* */
170
171 static clib_error_t *
172 vlib_physmem_config (vlib_main_t * vm, unformat_input_t * input)
173 {
174   vlib_physmem_main_t *vpm = &vm->physmem_main;
175
176   while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
177     {
178       if (unformat (input, "base-addr 0x%lx", &vpm->base_addr))
179         ;
180       else if (unformat (input, "max-size %U",
181                          unformat_memory_size, &vpm->max_size))
182         ;
183       else
184         return unformat_parse_error (input);
185     }
186
187   unformat_free (input);
188   return 0;
189 }
190
191 VLIB_EARLY_CONFIG_FUNCTION (vlib_physmem_config, "physmem");
192
193 /*
194  * fd.io coding-style-patch-verification: ON
195  *
196  * Local Variables:
197  * eval: (c-set-style "gnu")
198  * End:
199  */