blob: 76f8494b331865dae05fb86d5006fb5b8e70b873 [file] [log] [blame]
/*
* Copyright (c) 2018 Cisco and/or its affiliates.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <unistd.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <sys/mman.h>
#include <sys/fcntl.h>
#include <sys/stat.h>
#include <unistd.h>
#include <vppinfra/clib.h>
#include <vppinfra/linux/sysfs.h>
#include <vlib/vlib.h>
#include <vlib/physmem.h>
#include <vlib/unix/unix.h>
#include <vlib/pci/pci.h>
#include <vlib/linux/vfio.h>
#if defined(__x86_64__) && !defined(CLIB_SANITIZE_ADDR)
/* we keep physmem in low 38 bits of VA address space as some
IOMMU implamentation cannot map above that range */
#define VLIB_PHYSMEM_DEFAULT_BASE_ADDDR (1ULL << 36)
#else
/* let kernel decide */
#define VLIB_PHYSMEM_DEFAULT_BASE_ADDDR 0
#endif
clib_error_t *
vlib_physmem_shared_map_create (vlib_main_t * vm, char *name, uword size,
u32 log2_page_sz, u32 numa_node,
u32 * map_index)
{
clib_pmalloc_main_t *pm = vm->physmem_main.pmalloc_main;
vlib_physmem_main_t *vpm = &vm->physmem_main;
vlib_physmem_map_t *map;
clib_pmalloc_arena_t *a;
clib_error_t *error = 0;
void *va;
uword i;
va = clib_pmalloc_create_shared_arena (pm, name, size, log2_page_sz,
numa_node);
if (va == 0)
return clib_error_return (0, "%U", format_clib_error,
clib_pmalloc_last_error (pm));
a = clib_pmalloc_get_arena (pm, va);
pool_get (vpm->maps, map);
*map_index = map->index = map - vpm->maps;
map->base = va;
map->fd = a->fd;
map->n_pages = a->n_pages * a->subpages_per_page;
map->log2_page_size = a->log2_subpage_sz;
map->numa_node = a->numa_node;
for (i = 0; i < a->n_pages; i++)
{
uword pa =
clib_pmalloc_get_pa (pm, (u8 *) va + (i << a->log2_subpage_sz));
/* maybe iova */
if (pa == 0)
pa = pointer_to_uword (va);
vec_add1 (map->page_table, pa);
}
return error;
}
vlib_physmem_map_t *
vlib_physmem_get_map (vlib_main_t * vm, u32 index)
{
vlib_physmem_main_t *vpm = &vm->physmem_main;
return pool_elt_at_index (vpm->maps, index);
}
clib_error_t *
vlib_physmem_init (vlib_main_t * vm)
{
vlib_physmem_main_t *vpm = &vm->physmem_main;
clib_error_t *error = 0;
u64 *pt = 0;
void *p;
/* check if pagemap is accessible */
pt = clib_mem_vm_get_paddr (&pt, min_log2 (sysconf (_SC_PAGESIZE)), 1);
if (pt && pt[0])
vpm->flags |= VLIB_PHYSMEM_MAIN_F_HAVE_PAGEMAP;
vec_free (pt);
if ((error = linux_vfio_init (vm)))
return error;
p = clib_mem_alloc_aligned (sizeof (clib_pmalloc_main_t),
CLIB_CACHE_LINE_BYTES);
memset (p, 0, sizeof (clib_pmalloc_main_t));
vpm->pmalloc_main = (clib_pmalloc_main_t *) p;
if (vpm->base_addr == 0)
vpm->base_addr = VLIB_PHYSMEM_DEFAULT_BASE_ADDDR;
clib_pmalloc_init (vpm->pmalloc_main, vpm->base_addr, vpm->max_size);
/* update base_addr and max_size per actual allocation */
vpm->base_addr = (uword) vpm->pmalloc_main->base;
vpm->max_size = (uword) vpm->pmalloc_main->max_pages <<
vpm->pmalloc_main->def_log2_page_sz;
return error;
}
static clib_error_t *
show_physmem (vlib_main_t * vm,
unformat_input_t * input, vlib_cli_command_t * cmd)
{
vlib_physmem_main_t *vpm = &vm->physmem_main;
unformat_input_t _line_input, *line_input = &_line_input;
u32 verbose = 0, map = 0;
if (unformat_user (input, unformat_line_input, line_input))
{
while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (line_input, "verbose"))
verbose = 1;
else if (unformat (line_input, "v"))
verbose = 1;
else if (unformat (line_input, "detail"))
verbose = 2;
else if (unformat (line_input, "d"))
verbose = 2;
else if (unformat (line_input, "map"))
map = 1;
else
break;
}
unformat_free (line_input);
}
if (map)
vlib_cli_output (vm, " %U", format_pmalloc_map, vpm->pmalloc_main);
else
vlib_cli_output (vm, " %U", format_pmalloc, vpm->pmalloc_main, verbose);
return 0;
}
/* *INDENT-OFF* */
VLIB_CLI_COMMAND (show_physmem_command, static) = {
.path = "show physmem",
.short_help = "show physmem [verbose | detail | map]",
.function = show_physmem,
};
/* *INDENT-ON* */
static clib_error_t *
vlib_physmem_config (vlib_main_t * vm, unformat_input_t * input)
{
vlib_physmem_main_t *vpm = &vm->physmem_main;
while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
{
if (unformat (input, "base-addr 0x%lx", &vpm->base_addr))
;
else if (unformat (input, "max-size %U",
unformat_memory_size, &vpm->max_size))
;
else
return unformat_parse_error (input);
}
unformat_free (input);
return 0;
}
VLIB_EARLY_CONFIG_FUNCTION (vlib_physmem_config, "physmem");
/*
* fd.io coding-style-patch-verification: ON
*
* Local Variables:
* eval: (c-set-style "gnu")
* End:
*/