Skip to content

Commit 4df175d

Browse files
committed
feat: mm: added affinity pages allocator
This patch introduces a tagged pages allocator to address the existing problems of page aliasing on specific platforms and the requirement of page coloring. It implements an affinity-id aware page manager by separating the runtime page list into two types: a normal single linked-list and a multi-dimensional affinity-list. Changes: - Introduced tagged pages allocator and managing algorithm for affinity pages list - Modified components to support affinity-id list management - Updated page allocation and freeing functions to handle tagged pages - Added configuration options for page affinity block size and debugging - Modified mmap and elf loading to respect affinity settings - Enhanced page list management to support multi-dimensional affinity-list Signed-off-by: Shell <[email protected]>
1 parent e221cd5 commit 4df175d

File tree

14 files changed

+622
-210
lines changed

14 files changed

+622
-210
lines changed

components/dfs/dfs_v2/include/dfs_file.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,7 @@ struct dfs_mmap2_args
137137
int prot;
138138
int flags;
139139
off_t pgoffset;
140+
size_t min_align_size;
140141

141142
struct rt_lwp *lwp;
142143
void *ret;

components/dfs/dfs_v2/src/dfs_file_mmap.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ static void *_map_data_to_uspace(struct dfs_mmap2_args *mmap2, void *data, rt_er
7676
map_vaddr = (void *)((size_t)map_vaddr & ~ARCH_PAGE_MASK);
7777

7878
k_flags = lwp_user_mm_flag_to_kernel(mmap2->flags);
79+
k_flags = MMF_CREATE(k_flags, mmap2->min_align_size);
7980
k_attr = lwp_user_mm_attr_to_kernel(mmap2->prot);
8081

8182
map_vaddr = _do_mmap(lwp, map_vaddr, map_size, k_attr, k_flags, mmap2->pgoffset, data, code);

components/dfs/dfs_v2/src/dfs_pcache.c

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -694,14 +694,15 @@ static int dfs_page_unmap(struct dfs_page *page)
694694
return 0;
695695
}
696696

697-
static struct dfs_page *dfs_page_create(void)
697+
static struct dfs_page *dfs_page_create(off_t pos)
698698
{
699699
struct dfs_page *page = RT_NULL;
700+
int affid = RT_PAGE_PICK_AFFID(pos);
700701

701702
page = rt_calloc(1, sizeof(struct dfs_page));
702703
if (page)
703704
{
704-
page->page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
705+
page->page = rt_pages_alloc_tagged(0, affid, PAGE_ANY_AVAILABLE);
705706
if (page->page)
706707
{
707708
//memset(page->page, 0x00, ARCH_PAGE_SIZE);
@@ -992,12 +993,12 @@ static struct dfs_page *dfs_aspace_load_page(struct dfs_file *file, off_t pos)
992993
struct dfs_vnode *vnode = file->vnode;
993994
struct dfs_aspace *aspace = vnode->aspace;
994995

995-
page = dfs_page_create();
996+
page = dfs_page_create(pos);
996997
if (page)
997998
{
998999
page->aspace = aspace;
9991000
page->size = ARCH_PAGE_SIZE;
1000-
page->fpos = pos / ARCH_PAGE_SIZE * ARCH_PAGE_SIZE;
1001+
page->fpos = RT_ALIGN_DOWN(pos, ARCH_PAGE_SIZE);
10011002
aspace->ops->read(file, page);
10021003
page->ref_count ++;
10031004

components/lwp/lwp_elf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -576,7 +576,7 @@ static int elf_aux_fill(elf_load_info_t *load_info)
576576
elf_addr_t *aux_info;
577577
uint32_t random_value = rt_tick_get();
578578
size_t prot = PROT_READ | PROT_WRITE;
579-
size_t flags = MAP_PRIVATE;
579+
size_t flags = MAP_FIXED | MAP_PRIVATE;
580580
rt_lwp_t lwp = load_info->lwp;
581581
void *va;
582582

components/lwp/lwp_user_mm.c

Lines changed: 87 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -503,29 +503,99 @@ void *lwp_user_memory_remap_to_kernel(rt_lwp_t lwp, void *uaddr, size_t length)
503503

504504
return kaddr;
505505
}
506+
#include <dfs_dentry.h>
507+
#define _AFFBLK_PGOFFSET (RT_PAGE_AFFINITY_BLOCK_SIZE >> MM_PAGE_SHIFT)
508+
509+
static rt_base_t _aligned_for_weak_mapping(off_t *ppgoff, rt_size_t *plen, rt_size_t *palign)
510+
{
511+
off_t aligned_pgoffset, pgoffset = *ppgoff;
512+
rt_size_t length = *plen;
513+
rt_size_t min_align_size = *palign;
514+
rt_base_t aligned_size = 0;
515+
516+
if (pgoffset >= 0)
517+
{
518+
/* force an alignment */
519+
aligned_pgoffset =
520+
RT_ALIGN_DOWN(pgoffset, RT_PAGE_AFFINITY_BLOCK_SIZE >> MM_PAGE_SHIFT);
521+
aligned_size = (pgoffset - aligned_pgoffset) << MM_PAGE_SHIFT;
522+
523+
if (aligned_pgoffset != pgoffset)
524+
{
525+
/**
526+
* If requested pgoffset is not sitting on an aligned page offset,
527+
* expand the request mapping to force an alignment.
528+
*/
529+
length += aligned_size;
530+
pgoffset = aligned_pgoffset;
531+
}
532+
533+
/**
534+
* As this is a weak mapping, we can pick any reasonable address for our
535+
* requirement.
536+
*/
537+
min_align_size = RT_PAGE_AFFINITY_BLOCK_SIZE;
538+
}
539+
else
540+
{
541+
RT_ASSERT(0 && "Unexpected input");
542+
}
543+
544+
*ppgoff = pgoffset;
545+
*plen = length;
546+
*palign = min_align_size;
547+
548+
return aligned_size;
549+
}
506550

507551
void *lwp_mmap2(struct rt_lwp *lwp, void *addr, size_t length, int prot,
508552
int flags, int fd, off_t pgoffset)
509553
{
510554
rt_err_t rc;
511-
rt_size_t k_attr;
512-
rt_size_t k_flags;
513-
rt_size_t k_offset;
555+
rt_size_t k_attr, k_flags, k_offset, aligned_size = 0;
556+
rt_size_t min_align_size = 1 << MM_PAGE_SHIFT;
514557
rt_aspace_t uspace;
515558
rt_mem_obj_t mem_obj;
516559
void *ret = 0;
517-
LOG_D("%s(addr=0x%lx,length=%ld,fd=%d)", __func__, addr, length, fd);
560+
LOG_D("%s(addr=0x%lx,length=0x%lx,fd=%d,pgoff=0x%lx)", __func__, addr, length, fd, pgoffset);
561+
562+
/* alignment for affinity page block */
563+
if (flags & MAP_FIXED)
564+
{
565+
if (fd != -1)
566+
{
567+
/* requested mapping address */
568+
rt_base_t va_affid = RT_PAGE_PICK_AFFID(addr);
569+
rt_base_t pgoff_affid = RT_PAGE_PICK_AFFID(pgoffset << MM_PAGE_SHIFT);
570+
571+
/* filter illegal align address */
572+
if (va_affid != pgoff_affid)
573+
{
574+
LOG_W("Unaligned mapping address %p(pgoff=0x%lx) from fd=%d",
575+
addr, pgoffset, fd);
576+
}
577+
}
578+
else
579+
{
580+
/* anonymous mapping can always aligned */
581+
}
582+
}
583+
else
584+
{
585+
/* weak address selection */
586+
aligned_size = _aligned_for_weak_mapping(&pgoffset, &length, &min_align_size);
587+
}
518588

519589
if (fd == -1)
520590
{
521-
/**
522-
* todo: add threshold
523-
*/
591+
#ifdef RT_DEBUGGING_PAGE_THRESHOLD
524592
if (!_memory_threshold_ok())
525593
return (void *)-ENOMEM;
594+
#endif /* RT_DEBUGGING_PAGE_THRESHOLD */
526595

527596
k_offset = MM_PA_TO_OFF(addr);
528-
k_flags = lwp_user_mm_flag_to_kernel(flags) | MMF_MAP_PRIVATE;
597+
k_flags = MMF_CREATE(lwp_user_mm_flag_to_kernel(flags) | MMF_MAP_PRIVATE,
598+
min_align_size);
529599
k_attr = lwp_user_mm_attr_to_kernel(prot);
530600

531601
uspace = lwp->aspace;
@@ -553,6 +623,7 @@ void *lwp_mmap2(struct rt_lwp *lwp, void *addr, size_t length, int prot,
553623

554624
mmap2.addr = addr;
555625
mmap2.length = length;
626+
mmap2.min_align_size = min_align_size;
556627
mmap2.prot = prot;
557628
mmap2.flags = flags;
558629
mmap2.pgoffset = pgoffset;
@@ -572,7 +643,15 @@ void *lwp_mmap2(struct rt_lwp *lwp, void *addr, size_t length, int prot,
572643
}
573644

574645
if ((long)ret <= 0)
646+
{
575647
LOG_D("%s() => %ld", __func__, ret);
648+
}
649+
else
650+
{
651+
ret = (char *)ret + aligned_size;
652+
LOG_D("%s() => 0x%lx", __func__, ret);
653+
}
654+
576655
return ret;
577656
}
578657

components/mm/Kconfig

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
menu "Memory management"
22

3+
config RT_PAGE_AFFINITY_BLOCK_SIZE
4+
hex "Affinity block size in bytes for page management"
5+
default 0x1000
6+
help
7+
Page affinity block can be used to resolve the VIPT aliasing problem.
8+
It should be set to `1ul << ((index + block) - page_offset)` in this case.
9+
You could also exploit this as a tunning for cache coloring.
10+
311
config RT_USING_MEMBLOCK
412
bool "Using memblock"
513
default n
@@ -16,4 +24,8 @@ config RT_INIT_MEMORY_REGIONS
1624
memory into different types of regions. This variable specifies
1725
the maximum number of regions supported by the system.
1826

27+
config RT_DEBUGGING_ALIASING
28+
bool "Using aliasing paging debugger"
29+
default n
30+
1931
endmenu

components/mm/ioremap.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,15 @@ static void *_ioremap_type(void *paddr, size_t size, enum ioremap_type type)
3838
size_t attr;
3939
size_t lo_off;
4040
int err;
41+
size_t pa_off = (rt_ubase_t)paddr & ~(RT_PAGE_AFFINITY_BLOCK_SIZE - 1);
4142

42-
lo_off = (rt_ubase_t)paddr & ARCH_PAGE_MASK;
43+
lo_off = (rt_ubase_t)paddr - pa_off;
44+
pa_off = MM_PA_TO_OFF(pa_off);
4345

4446
struct rt_mm_va_hint hint = {
4547
.prefer = RT_NULL,
46-
.map_size = RT_ALIGN(size + lo_off, ARCH_PAGE_SIZE),
47-
.flags = 0,
48+
.map_size = RT_ALIGN(size + lo_off, RT_PAGE_AFFINITY_BLOCK_SIZE),
49+
.flags = MMF_CREATE(0, RT_PAGE_AFFINITY_BLOCK_SIZE),
4850
.limit_start = rt_ioremap_start,
4951
.limit_range_size = rt_ioremap_size,
5052
};
@@ -63,7 +65,7 @@ static void *_ioremap_type(void *paddr, size_t size, enum ioremap_type type)
6365
default:
6466
return v_addr;
6567
}
66-
err = rt_aspace_map_phy(&rt_kernel_space, &hint, attr, MM_PA_TO_OFF(paddr), (void **)&v_addr);
68+
err = rt_aspace_map_phy(&rt_kernel_space, &hint, attr, pa_off, (void **)&v_addr);
6769

6870
if (err)
6971
{

components/mm/mm_anon.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ int rt_varea_fix_private_locked(rt_varea_t ex_varea, void *pa,
581581
}
582582
else if (ex_obj->page_read)
583583
{
584-
page = rt_pages_alloc_ext(0, PAGE_ANY_AVAILABLE);
584+
page = rt_pages_alloc_tagged(0, RT_PAGE_PICK_AFFID(fault_vaddr), PAGE_ANY_AVAILABLE);
585585
if (page)
586586
{
587587
/** setup message & fetch the data from source object */

components/mm/mm_aspace.c

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1149,12 +1149,17 @@ static void *_ascending_search(rt_varea_t varea, rt_size_t req_size,
11491149
rt_varea_t nx_va = ASPACE_VAREA_NEXT(varea);
11501150
if (nx_va)
11511151
{
1152-
rt_size_t gap_size =
1153-
(char *)_lower(limit.end, (char *)nx_va->start - 1) - candidate + 1;
1154-
if (gap_size >= req_size)
1152+
if (candidate < (char *)nx_va->start)
11551153
{
1156-
ret = candidate;
1157-
break;
1154+
rt_size_t gap_size =
1155+
(char *)_lower(limit.end, (char *)nx_va->start - 1) -
1156+
candidate + 1;
1157+
1158+
if (gap_size >= req_size)
1159+
{
1160+
ret = candidate;
1161+
break;
1162+
}
11581163
}
11591164
}
11601165
else
@@ -1172,15 +1177,16 @@ static void *_find_head_and_asc_search(rt_aspace_t aspace, rt_size_t req_size,
11721177
struct _mm_range limit)
11731178
{
11741179
void *va = RT_NULL;
1180+
char *candidate = _align(limit.start, align_mask);
11751181

1176-
rt_varea_t varea = _aspace_bst_search_exceed(aspace, limit.start);
1182+
rt_varea_t varea = _aspace_bst_search_exceed(aspace, candidate);
11771183
if (varea)
11781184
{
1179-
char *candidate = _align(limit.start, align_mask);
11801185
rt_size_t gap_size = (char *)varea->start - candidate;
11811186
if (gap_size >= req_size)
11821187
{
1183-
rt_varea_t former = _aspace_bst_search(aspace, limit.start);
1188+
/* try previous memory region of varea if possible */
1189+
rt_varea_t former = ASPACE_VAREA_PREV(varea);
11841190
if (former)
11851191
{
11861192
candidate = _align((char *)former->start + former->size, align_mask);
@@ -1203,12 +1209,7 @@ static void *_find_head_and_asc_search(rt_aspace_t aspace, rt_size_t req_size,
12031209
}
12041210
else
12051211
{
1206-
char *candidate;
1207-
rt_size_t gap_size;
1208-
1209-
candidate = limit.start;
1210-
candidate = _align(candidate, align_mask);
1211-
gap_size = (char *)limit.end - candidate + 1;
1212+
rt_size_t gap_size = (char *)limit.end - candidate + 1;
12121213

12131214
if (gap_size >= req_size)
12141215
va = candidate;
@@ -1217,6 +1218,12 @@ static void *_find_head_and_asc_search(rt_aspace_t aspace, rt_size_t req_size,
12171218
return va;
12181219
}
12191220

1221+
/**
1222+
* Find a memory region that:
1223+
* - is free
1224+
* - sits inside the limit range
1225+
* - meets the alignment requirement
1226+
*/
12201227
static void *_find_free(rt_aspace_t aspace, void *prefer, rt_size_t req_size,
12211228
void *limit_start, rt_size_t limit_size,
12221229
mm_flag_t flags)
@@ -1231,20 +1238,42 @@ static void *_find_free(rt_aspace_t aspace, void *prefer, rt_size_t req_size,
12311238
align_mask = ~((1 << MMF_GET_ALIGN(flags)) - 1);
12321239
}
12331240

1234-
if (prefer != RT_NULL)
1241+
if (flags & MMF_MAP_FIXED)
12351242
{
1236-
/* if prefer and free, just return the prefer region */
1237-
prefer = _align(prefer, align_mask);
12381243
struct _mm_range range = {prefer, (char *)prefer + req_size - 1};
1239-
varea = _aspace_bst_search_overlap(aspace, range);
12401244

1245+
/* caller should guarantee that the request region is legal */
1246+
RT_ASSERT(!_not_in_range(flags, prefer, req_size, limit_start, limit_size));
1247+
1248+
varea = _aspace_bst_search_overlap(aspace, range);
12411249
if (!varea)
12421250
{
12431251
va = prefer;
12441252
}
1245-
else if (flags & MMF_MAP_FIXED)
1253+
else
1254+
{
1255+
/* region not freed */
1256+
}
1257+
}
1258+
else if (prefer != RT_NULL)
1259+
{
1260+
struct _mm_range range;
1261+
1262+
/* ceiling the prefer address */
1263+
prefer = _align(prefer, align_mask);
1264+
if (_not_in_range(flags, prefer, req_size, limit_start, limit_size))
12461265
{
1247-
/* OVERLAP */
1266+
prefer = limit_start;
1267+
}
1268+
1269+
range.start = prefer;
1270+
range.end = (char *)prefer + req_size - 1;
1271+
varea = _aspace_bst_search_overlap(aspace, range);
1272+
1273+
if (!varea)
1274+
{
1275+
/* if preferred and free, just return the prefer region */
1276+
va = prefer;
12481277
}
12491278
else
12501279
{

components/mm/mm_fault.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,15 +185,22 @@ int rt_aspace_fault_try_fix(rt_aspace_t aspace, struct rt_aspace_fault_msg *msg)
185185
case MM_FAULT_OP_EXECUTE:
186186
err = _exec_fault(varea, pa, msg);
187187
break;
188+
default:
189+
LOG_D("Unhandle exception");
190+
break;
188191
}
189192
}
190193
}
191194
else
192195
{
193-
LOG_I("%s: varea not found at 0x%lx", __func__, msg->fault_vaddr);
196+
LOG_W("%s: varea not found at 0x%lx", __func__, msg->fault_vaddr);
194197
}
195198
RD_UNLOCK(aspace);
196199
}
200+
else
201+
{
202+
LOG_W("No aspace found");
203+
}
197204

198205
return err;
199206
}

0 commit comments

Comments
 (0)