Skip to content

Commit

Permalink
mm: Add mpagemap
Browse files Browse the repository at this point in the history
Add mpagemap, a system call to fetch PTE data from a range of address
space.
It's more or less mincore-like, but doesn't take into account the page
cache, it just dumps PTEs. This is useful for userspace testing, etc.

Signed-off-by: Pedro Falcato <[email protected]>
  • Loading branch information
heatd committed Jan 4, 2024
1 parent 8f02bfc commit 1fe4b9b
Show file tree
Hide file tree
Showing 7 changed files with 180 additions and 2 deletions.
20 changes: 20 additions & 0 deletions kernel/arch/arm64/syscall_table.json
Original file line number Diff line number Diff line change
Expand Up @@ -2614,5 +2614,25 @@
]
],
"return_type": "int"
},
{
"name": "mpagemap",
"nr": 153,
"nr_args": 3,
"args": [
[
"void *",
"addr"
],
[
"size_t",
"length"
],
[
"u64 *",
"pagemap"
]
],
"return_type": "int"
}
]
20 changes: 20 additions & 0 deletions kernel/arch/riscv64/syscall_table.json
Original file line number Diff line number Diff line change
Expand Up @@ -2686,5 +2686,25 @@
]
],
"return_type": "int"
},
{
"name": "mpagemap",
"nr": 153,
"nr_args": 3,
"args": [
[
"void *",
"addr"
],
[
"size_t",
"length"
],
[
"u64 *",
"pagemap"
]
],
"return_type": "int"
}
]
20 changes: 20 additions & 0 deletions kernel/arch/x86_64/syscall_table.json
Original file line number Diff line number Diff line change
Expand Up @@ -2730,5 +2730,25 @@
]
],
"return_type": "int"
},
{
"name": "mpagemap",
"nr": 153,
"nr_args": 3,
"args": [
[
"void *",
"addr"
],
[
"size_t",
"length"
],
[
"u64 *",
"pagemap"
]
],
"return_type": "int"
}
]
24 changes: 24 additions & 0 deletions kernel/include/uapi/mincore.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2024 Pedro Falcato
* This file is part of Onyx, and is released under the terms of the MIT License
* check LICENSE at the root directory for more information
*
* SPDX-License-Identifier: MIT
*/
#ifndef _UAPI_MINCORE_H
#define _UAPI_MINCORE_H

#define PAGE_PRESENT (1 << 0)
#define PAGE_GLOBAL (1 << 1)
#define PAGE_WRITABLE (1 << 2)
#define PAGE_EXECUTABLE (1 << 3)
#define PAGE_DIRTY (1 << 4)
#define PAGE_ACCESSED (1 << 5)
#define PAGE_USER (1 << 6)
#define PAGE_HUGE (1 << 7)

/* Reserve the 12 bottom bits for flags, this lines up nicely with 4K pages */

#define MAPPING_INFO_PADDR(x) ((x) & -4096UL)

#endif
2 changes: 1 addition & 1 deletion kernel/kernel/mm/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mm-y:= bootmem.o page.o pagealloc.o vm_object.o vm.o vmalloc.o reclaim.o amap.o anon.o
mm-y:= bootmem.o page.o pagealloc.o vm_object.o vm.o vmalloc.o reclaim.o amap.o anon.o mincore.o
mm-$(CONFIG_KUNIT)+= vm_tests.o

ifeq ($(CONFIG_KASAN), y)
Expand Down
94 changes: 94 additions & 0 deletions kernel/kernel/mm/mincore.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Copyright (c) 2024 Pedro Falcato
* This file is part of Onyx, and is released under the terms of the MIT License
* check LICENSE at the root directory for more information
*
* SPDX-License-Identifier: MIT
*/

#include <onyx/process.h>
#include <onyx/vm.h>

// TODO: Export this stuff in some header, and avoid sticking everything into vm.cpp
vm_area_struct *vm_search(struct mm_address_space *mm, void *addr, size_t length)
REQUIRES_SHARED(mm->vm_lock);

static long do_pagemap(struct mm_address_space *as, unsigned long start, unsigned long end,
u64 *pagemap)
{

scoped_mutex g{as->vm_lock};
long pfns_processed = 0;
struct vm_area_struct *vma = vm_search(as, (void *) start, 1);
if (!vma)
return -ENOMEM;

while (vma)
{
if (vma->vm_start > end)
break;

spin_lock(&as->page_table_lock);

/* Note: This is bad and slow(er). Nonetheless, it does the job for now */
for (; start < end; start += PAGE_SIZE)
pagemap[pfns_processed++] = __get_mapping_info((void *) start, as);

spin_unlock(&as->page_table_lock);

if (start == end)
break;

vma = containerof_null_safe(bst_next(&as->region_tree, &vma->vm_tree_node),
struct vm_area_struct, vm_tree_node);
}

return pfns_processed;
}

int sys_mpagemap(void *addr, size_t length, u64 *pagemap)
{
unsigned long start = (unsigned long) addr & -PAGE_SIZE;
length += (unsigned long) addr & (PAGE_SIZE - 1);
unsigned long end = ALIGN_TO(start + length, PAGE_SIZE);
struct mm_address_space *as = get_current_address_space();
struct page *buffer;
int ret = 0;

if (start < as->start || end > as->end)
return -EINVAL;

buffer = alloc_page(GFP_KERNEL);
if (!buffer)
return -ENOMEM;

while (start < end)
{
/* Limit runs to PAGE_SIZE / sizeof(u64) */
u64 *kbuffer = (u64 *) PAGE_TO_VIRT(buffer);
unsigned long this_run_end = cul::min(end, start + (PAGE_SIZE / sizeof(u64)));
long processed = do_pagemap(as, start, this_run_end, kbuffer);

if (processed == 0)
break;

if (processed < 0)
{
ret = processed;
break;
}

if (copy_to_user(pagemap, kbuffer, processed * sizeof(u64)) < 0)
{
ret = -EFAULT;
break;
}

pagemap += processed;
start += processed << PAGE_SHIFT;
}

free_page(buffer);

return ret;
}
2 changes: 1 addition & 1 deletion musl

0 comments on commit 1fe4b9b

Please sign in to comment.