Commit b9ce0034 authored by Charlie Jacobsen's avatar Charlie Jacobsen Committed by Vikram Narayanan

liblcd-v2: Make room for RAM map region (separate from heap).

This is kind of like an mmap region, but only for RAM. (The guest
virtual page tables will be configured for write back).

Use case: You get a RAM capability from some other guy, and you
want to map it into your physical/virtual address space. This is
reasonable to figure out manually for big RAM chunks that are
mapped one/two times. But for little tedious ones (string sharing),
it's helpful to have an allocator to assist and track free parts
of guest physical.

The RAM map region uses very course-grained physical address space
allocation (minimum 64 MBs). This leads to a lot of internal
fragmentation, but it should be tolerable since the region is big.
It also means we have a smaller bit of metadata for tracking the
region.
parent 39a20ffe
......@@ -42,7 +42,7 @@ int __liblcd_mem_itree_insert(gpa_t start, unsigned long size,
void __liblcd_mem_itree_delete(struct lcd_resource_node *n);
/*
* HEAP CONFIGURATION --------------------------------------------------
* HEAP --------------------------------------------------
*
* Heap is 2^12 pages, or 16 MBs.
*
......@@ -55,13 +55,41 @@ void __liblcd_mem_itree_delete(struct lcd_resource_node *n);
#define LCD_HEAP_MIN_ORDER 0
#define LCD_HEAP_MAX_ORDER 10
/* MEMORY SUBSYSTEM INTERNALS ------------------------------ */
/**
* __liblcd_mem_init -- Call during boot after mem itree initialized
* __liblcd_heap_init -- Call during boot after mem itree initialized
*
* This initializes the heap allocator.
*/
int __liblcd_mem_init(void);
int __liblcd_heap_init(void);
/*
* RAM MAPPING --------------------------------------------------
*
* RAM mapping area is 8 GBs (2^26 pages).
*
* The minimum address space block you can allocate from the RAM map
* area is 64 MBs (2^14 = 16,384 pages). This leads to a lot of internal
* fragmentation, but this is tolerable, so long as we don't need to
* map RAM more than 100 or so times. (The actual memory object will
* likely be considerably smaller than 64 MBs, so only the first
* few KBs may actually be backed/mapped in guest physical. But the
* entire 64 MB region will be considered occupied by the internal
* RAM map allocator.)
*
* The maximum address space block you can allocate from the RAM map
* area is 1 GB (2^18 = 262,144 pages).
*/
#define LCD_RAM_MAP_NR_PAGES_ORDER 26
#define LCD_RAM_MAP_SIZE LCD_RAM_MAP_REGION_SIZE
#define LCD_RAM_MAP_MIN_ORDER 14
#define LCD_RAM_MAP_MAX_ORDER 18
/**
* __liblcd_ram_map_init -- Call during boot after heap initialized
*
* This initializes the RAM map region allocator.
*/
int __liblcd_ram_map_init(void);
#endif /* LCD_DOMAINS_LIBLCD_H */
......@@ -47,9 +47,13 @@
*
* -- 2 GB HOLE (unmapped)
*
* -- 8 GB for RAM memory mapping region (think: kmap)
*
* -- 48 GB HOLE (unmapped)
*
* -- 256 GB for ioremap region (unmapped at boot)
*
* -- 2 GB HOLE (unmapped)
* -- 190 GB HOLE (unmapped)
*
* -- 2 GB for kernel module mapping area. The kernel module itself
* is mapped at the correct offset into this area so that
......@@ -71,10 +75,18 @@
* | (2 GB) |
* +---------------------------+ 0x0000 007f 8000 0000 (510 GB)
* | HOLE / Unmapped |
* | (246 GB) |
* +---------------------------+ 0x0000 0042 0000 0000 (264 GB)
* | ioremap region |
* | (256 GB) |
* | (190 GB) |
* +---------------------------+ 0x0000 0050 0000 0000 (320 GB)
* | ioremap Region |
* | (64 GB aligned) |
* | (256 GB) |
* +---------------------------+ 0x0000 0010 0000 0000 (64 GB)
* | HOLE / Unmapped |
* | (48 GB) |
* +---------------------------+ 0x0000 0004 0000 0000 (16 GB)
* | RAM Map Region |
* | (8 GB aligned) |
* | (8 GB) |
* +---------------------------+ 0x0000 0002 0000 0000 (8 GB)
* | HOLE / Unmapped |
* | (2 GB) |
......@@ -138,14 +150,21 @@
* unusable.)
*/
/* Sizes. The heap and ioremap are not mapped/backed at boot. */
/* Region sizes */
#define LCD_MISC_REGION_SIZE (1UL << 30) /* .................... 1 GB */
#define LCD_STACK_REGION_SIZE (1UL << 30) /* ................... 1 GB */
#define LCD_HEAP_REGION_SIZE (1UL << 30) /* .................... 1 GB */
#define LCD_RAM_MAP_REGION_SIZE (1UL << 30) /* ................. 8 GBs */
#define LCD_IOREMAP_REGION_SIZE (256UL << 30) /* ............... 256 GBs */
#define LCD_KERNEL_MODULE_REGION_SIZE (2UL << 30) /* ........... 2 GBs */
/* Component Sizes. */
#define LCD_UTCB_SIZE PAGE_SIZE /* ........................... 4 KBs */
#define LCD_BOOTSTRAP_PAGES_SIZE (2 * PAGE_SIZE) /* .......... 8 KBs */
#define LCD_BOOTSTRAP_PAGE_TABLES_SIZE (2 * PAGE_SIZE) /* .... 8 KBs */
#define LCD_STACK_SIZE (2 * PAGE_SIZE) /* .................... 8 KBs */
#define LCD_HEAP_SIZE (16UL << 20) /* ........................ 16 MBs */
#define LCD_IOREMAP_SIZE (16UL << 20) /* ..................... 16 MBs */
static inline void
__lcd_build_checks__(void)
......@@ -187,24 +206,33 @@ __lcd_build_checks__(void)
/* HOLE */
#define LCD_STACK_REGION_OFFSET (3UL << 30)
#define LCD_STACK_REGION_OFFSET \
(LCD_MISC_REGION_OFFSET + LCD_MISC_REGION_SIZE + 1UL << 30)
#define LCD_STACK_OFFSET \
(LCD_STACK_REGION_OFFSET + (1UL << 30) - LCD_STACK_SIZE)
(LCD_STACK_REGION_OFFSET + LCD_STACK_REGION_SIZE - LCD_STACK_SIZE)
/* HOLE */
#define LCD_HEAP_REGION_OFFSET (5UL << 30)
#define LCD_HEAP_REGION_OFFSET \
(LCD_STACK_REGION_OFFSET + LCD_STACK_REGION_SIZE + (1UL << 30))
#define LCD_HEAP_OFFSET LCD_HEAP_REGION_OFFSET
/* HOLE */
#define LCD_IOREMAP_REGION_OFFSET (8UL << 30)
#define LCD_RAM_MAP_REGION_OFFSET \
(LCD_HEAP_REGION_OFFSET + LCD_HEAP_REGION_SIZE + (2UL << 30))
#define LCD_RAM_MAP_OFFSET LCD_RAM_MAP_REGION_OFFSET
/* HOLE */
#define LCD_IOREMAP_REGION_OFFSET \
(LCD_RAM_MAP_REGION_OFFSET + LCD_RAM_MAP_REGION_SIZE + (48UL << 30))
#define LCD_IOREMAP_OFFSET LCD_IOREMAP_REGION_OFFSET
#define LCD_IOREMAP_REGION_SIZE (256UL << 30)
/* HOLE */
#define LCD_KERNEL_MODULE_REGION_OFFSET (510UL << 30)
#define LCD_KERNEL_MODULE_REGION_OFFSET \
(LCD_IOREMAP_REGION_OFFSET + LCD_IOREMAP_REGION_SIZE + (190UL << 30))
/* Addresses */
......@@ -230,6 +258,9 @@ __lcd_build_checks__(void)
#define LCD_HEAP_GP_ADDR __gpa(LCD_PHYS_BASE + LCD_HEAP_OFFSET)
#define LCD_HEAP_GV_ADDR __gva(LCD_VIRT_BASE + LCD_HEAP_OFFSET)
#define LCD_RAM_MAP_GP_ADDR __gpa(LCD_PHYS_BASE + LCD_RAM_MAP_OFFSET)
#define LCD_RAM_MAP_GV_ADDR __gva(LCD_VIRT_BASE + LCD_RAM_MAP_OFFSET)
#define LCD_IOREMAP_GP_ADDR __gpa(LCD_PHYS_BASE + LCD_IOREMAP_OFFSET)
#define LCD_IOREMAP_GV_ADDR __gva(LCD_VIRT_BASE + LCD_IOREMAP_OFFSET)
......
......@@ -113,58 +113,6 @@ fail1:
return ret;
}
int _lcd_mmap(cptr_t mo, unsigned int order, gpa_t base)
{
int ret;
/*
* Do low level syscall to map memory object
*/
ret = lcd_syscall_mmap(mo, base);
if (ret) {
LIBLCD_ERR("low level mmap failed");
goto fail1;
}
/*
* Insert into resource tree (unlike kliblcd, all of our
* memory objects are always contiguous in guest physical)
*/
ret = __liblcd_mem_itree_insert(base, (1UL << (PAGE_SHIFT + order)),
mo);
if (ret) {
LIBLCD_ERR("error inserting into mem itree");
goto fail2;
}
return 0;
fail2:
lcd_syscall_munmap(mo);
fail1:
return ret;
}
void _lcd_munmap(cptr_t mo, gpa_t base)
{
int ret;
struct lcd_resource_node *n;
/*
* Look up resource node for memory object in itree
*/
ret = lcd_phys_to_resource_node(base, &n);
if (ret) {
LIBLCD_ERR("couldn't find memory object in tree");
return;
}
/*
* Remove from tree
*/
__liblcd_mem_itree_delete(n);
/*
* Unmap memory object
*/
lcd_syscall_munmap(mo);
}
/* PAGE ALLOCATOR INTERNALS ---------------------------------------- */
static int
......@@ -260,13 +208,6 @@ heap_free_unmap_regular_mem_chunk(struct lcd_page_allocator *pa,
heap_free_unmap_metadata_memory_chunk(&pa->cbs, n_to_delete);
}
struct lcd_page_allocator_cbs heap_page_allocator_cbs = {
.alloc_map_metadata_memory_chunk = heap_alloc_map_metadata_memory_chunk,
.free_unmap_metadata_memory_chunk = heap_free_unmap_metadata_memory_chunk,
.alloc_map_regular_mem_chunk = heap_alloc_map_regular_mem_chunk,
.free_unmap_regular_mem_chunk = heap_free_unmap_regular_mem_chunk,
};
static inline gva_t heap_page_block_to_addr(struct lcd_page_block *pb)
{
return gva_add(LCD_HEAP_GV_ADDR,
......@@ -308,93 +249,6 @@ static inline struct lcd_page_block *heap_struct_page_to_page_block(
heap_struct_page_to_addr(p));
}
static int setup_struct_page_array(void)
{
struct lcd_page_block *pb;
unsigned int order;
unsigned long bytes;
/*
* Compute number of struct pages we need
*/
bytes = roundup_pow_of_two((1UL << LCD_HEAP_NR_PAGES_ORDER) *
sizeof(struct page));
order = ilog2(bytes >> PAGE_SHIFT);
/*
* Do the alloc
*/
pb = lcd_page_allocator_alloc(heap_allocator, order);
if (!pb) {
LIBLCD_ERR("error setting up struct page array for heap");
ret = -ENOMEM;
goto fail1;
}
/*
* Zero out the array (unnecessary right now, but just in case)
*/
heap_page_array = (void *)gva_val(lcd_page_block_to_addr(pb));
memset(heap_page_array,
0,
(1 << (order + PAGE_SHIFT)));
return 0;
fail1:
return ret;
}
void cpucache_init(void);
static void __init_refok kmalloc_init(void)
{
kmem_cache_init();
kmem_cache_init_late();
cpucache_init();
}
static int init_heap(void)
{
int ret;
/*
* Create new page allocator in heap region
*/
ret = lcd_page_allocator_create(LCD_HEAP_SIZE,
LCD_HEAP_MIN_ORDER,
LCD_HEAP_MAX_ORDER,
LCD_HEAP_MAX_ORDER,
&heap_page_allocator_cbs,
1, /* embed metadata */
&heap_allocator);
if (ret) {
LIBLCD_ERR("error initializing heap allocator");
goto fail1;
}
/*
* Set up struct page array
*/
ret = setup_struct_page_array();
if (ret) {
LIBLCD_ERR("error setting up struct page array for heap");
goto fail2;
}
/*
* Initialize kmalloc
*/
kmalloc_init();
/*
* Inform mem itree the page and slab allocators are up (and so
* it can start using kmalloc for allocating nodes)
*/
__liblcd_mem_itree_booted();
return 0;
fail2:
lcd_page_allocator_destroy(heap_allocator);
heap_allocator = NULL;
fail1:
return ret;
}
/* PAGE ALLOC INTERFACE ---------------------------------------- */
struct page *lcd_alloc_pages_exact_node(int nid, unsigned int flags,
......@@ -499,18 +353,96 @@ gva_t lcd_gpa2gva(gpa_t gpa)
/* INIT/EXIT -------------------------------------------------- */
int __liblcd_mem_init(void)
static int setup_struct_page_array(void)
{
struct lcd_page_block *pb;
unsigned int order;
unsigned long bytes;
/*
* Compute number of struct pages we need
*/
bytes = roundup_pow_of_two((1UL << LCD_HEAP_NR_PAGES_ORDER) *
sizeof(struct page));
order = ilog2(bytes >> PAGE_SHIFT);
/*
* Do the alloc
*/
pb = lcd_page_allocator_alloc(heap_allocator, order);
if (!pb) {
LIBLCD_ERR("error setting up struct page array for heap");
ret = -ENOMEM;
goto fail1;
}
/*
* Zero out the array (unnecessary right now, but just in case)
*/
heap_page_array = (void *)gva_val(lcd_page_block_to_addr(pb));
memset(heap_page_array,
0,
(1 << (order + PAGE_SHIFT)));
return 0;
fail1:
return ret;
}
void cpucache_init(void);
static void __init_refok kmalloc_init(void)
{
kmem_cache_init();
kmem_cache_init_late();
cpucache_init();
}
struct lcd_page_allocator_cbs heap_page_allocator_cbs = {
.alloc_map_metadata_memory_chunk = heap_alloc_map_metadata_memory_chunk,
.free_unmap_metadata_memory_chunk = heap_free_unmap_metadata_memory_chunk,
.alloc_map_regular_mem_chunk = heap_alloc_map_regular_mem_chunk,
.free_unmap_regular_mem_chunk = heap_free_unmap_regular_mem_chunk,
};
int __liblcd_heap_init(void)
{
int ret;
ret = init_heap();
/*
* Create new page allocator in heap region
*/
ret = lcd_page_allocator_create(LCD_HEAP_SIZE,
LCD_HEAP_MIN_ORDER,
LCD_HEAP_MAX_ORDER,
LCD_HEAP_MAX_ORDER,
&heap_page_allocator_cbs,
1, /* embed metadata */
&heap_allocator);
if (ret) {
LIBLCD_ERR("heap init failed");
LIBLCD_ERR("error initializing heap allocator");
goto fail1;
}
/*
* Set up struct page array
*/
ret = setup_struct_page_array();
if (ret) {
LIBLCD_ERR("error setting up struct page array for heap");
goto fail2;
}
/*
* Initialize kmalloc
*/
kmalloc_init();
/*
* Inform mem itree the page and slab allocators are up (and so
* it can start using kmalloc for allocating nodes)
*/
__liblcd_mem_itree_booted();
return 0;
fail2:
lcd_page_allocator_destroy(heap_allocator);
heap_allocator = NULL;
fail1:
return ret;
}
/*
* ram_map.c
*
* Code for mapping RAM memory objects in LCD's address
* spaces.
*/
/* LOW-LEVEL SYSTEM CALLS ---------------------------------------- */
int _lcd_mmap(cptr_t mo, unsigned int order, gpa_t base)
{
int ret;
/*
* Do low level syscall to map memory object
*/
ret = lcd_syscall_mmap(mo, base);
if (ret) {
LIBLCD_ERR("low level mmap failed");
goto fail1;
}
/*
* Insert into resource tree (unlike kliblcd, all of our
* memory objects are always contiguous in guest physical)
*/
ret = __liblcd_mem_itree_insert(base, (1UL << (PAGE_SHIFT + order)),
mo);
if (ret) {
LIBLCD_ERR("error inserting into mem itree");
goto fail2;
}
return 0;
fail2:
lcd_syscall_munmap(mo);
fail1:
return ret;
}
void _lcd_munmap(cptr_t mo, gpa_t base)
{
int ret;
struct lcd_resource_node *n;
/*
* Look up resource node for memory object in itree
*/
ret = lcd_phys_to_resource_node(base, &n);
if (ret) {
LIBLCD_ERR("couldn't find memory object in tree");
return;
}
/*
* Remove from tree
*/
__liblcd_mem_itree_delete(n);
/*
* Unmap memory object
*/
lcd_syscall_munmap(mo);
}
/* INIT/EXIT ---------------------------------------- */
int __liblcd_ram_map_init(void)
{
/* Initialize RAM map allocator */
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment