MOS Source Code
Loading...
Searching...
No Matches
paging.c
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#include "mos/io/io.h"
4#include "mos/mm/mm.h"
5#include "mos/mm/mmstat.h"
7
12#include <mos/mm/physical/pmm.h>
13#include <mos/mos_global.h>
15#include <mos/syslog/printk.h>
16#include <mos_stdlib.h>
17
18vmap_t *mm_get_free_vaddr_locked(mm_context_t *mmctx, size_t n_pages, ptr_t base_vaddr, valloc_flags flags)
19{
20 MOS_ASSERT_X(spinlock_is_locked(&mmctx->mm_lock), "insane mmctx->mm_lock state");
21 MOS_ASSERT_X(base_vaddr < MOS_KERNEL_START_VADDR, "Use mm_get_free_pages instead");
22
23 if (flags & VALLOC_EXACT)
24 {
25 const ptr_t end_vaddr = base_vaddr + n_pages * MOS_PAGE_SIZE;
26 // we need to find a free area that starts at base_vaddr
27 list_foreach(vmap_t, vmap, mmctx->mmaps)
28 {
29 const ptr_t this_vaddr = vmap->vaddr;
30 const ptr_t this_end_vaddr = this_vaddr + vmap->npages * MOS_PAGE_SIZE;
31
32 // see if this vmap overlaps with the area we want to allocate
33 if (this_vaddr < end_vaddr && this_end_vaddr > base_vaddr)
34 {
35 // this mmap overlaps with the area we want to allocate
36 // so we can't allocate here
37 return ERR_PTR(-ENOMEM);
38 }
39 }
40
41 if (end_vaddr > MOS_USER_END_VADDR)
42 return ERR_PTR(-ENOMEM);
43
44 // nothing seems to overlap
45 return vmap_create(mmctx, base_vaddr, n_pages);
46 }
47 else
48 {
49 ptr_t retry_addr = base_vaddr;
50 list_foreach(vmap_t, mmap, mmctx->mmaps)
51 {
52 // we've reached the end of the user address space?
53 if (retry_addr + n_pages * MOS_PAGE_SIZE > MOS_USER_END_VADDR)
54 return ERR_PTR(-ENOMEM);
55
56 const ptr_t this_vaddr = mmap->vaddr;
57 const ptr_t this_end_vaddr = this_vaddr + mmap->npages * MOS_PAGE_SIZE;
58
59 const ptr_t target_vaddr_end = retry_addr + n_pages * MOS_PAGE_SIZE;
60 if (this_vaddr < target_vaddr_end && this_end_vaddr > retry_addr)
61 {
62 // this mmap overlaps with the area we want to allocate
63 // so we can't allocate here
64 retry_addr = this_end_vaddr; // try the next area
65 }
66
67 if (retry_addr + n_pages * MOS_PAGE_SIZE <= this_vaddr)
68 {
69 // we've found a free area that is large enough
70 return vmap_create(mmctx, retry_addr, n_pages);
71 }
72 }
73
74 // we've reached the end of the list, no matter it's empty or not
75 if (retry_addr + n_pages * MOS_PAGE_SIZE <= MOS_USER_END_VADDR)
76 return vmap_create(mmctx, retry_addr, n_pages);
77
78 return ERR_PTR(-ENOMEM);
79 }
80}
81
82void mm_map_kernel_pages(mm_context_t *mmctx, ptr_t vaddr, pfn_t pfn, size_t npages, vm_flags flags)
83{
85 MOS_ASSERT(npages > 0);
87 pr_dinfo2(vmm, "mapping %zd pages at " PTR_FMT " to pfn " PFN_FMT, npages, vaddr, pfn);
88 mm_do_map(mmctx->pgd, vaddr, pfn, npages, flags, false);
90}
91
92vmap_t *mm_map_user_pages(mm_context_t *mmctx, ptr_t vaddr, pfn_t pfn, size_t npages, vm_flags flags, valloc_flags vaflags, vmap_type_t type, vmap_content_t content)
93{
95 vmap_t *vmap = mm_get_free_vaddr_locked(mmctx, npages, vaddr, vaflags);
96 if (unlikely(!vmap))
97 {
98 mos_warn("could not find %zd pages in the address space", npages);
100 return NULL;
101 }
102
103 pr_dinfo2(vmm, "mapping %zd pages at " PTR_FMT " to pfn " PFN_FMT, npages, vmap->vaddr, pfn);
104 vmap->vmflags = flags;
105 vmap->stat.regular = npages;
106 mm_do_map(mmctx->pgd, vmap->vaddr, pfn, npages, flags, false);
107 spinlock_release(&mmctx->mm_lock);
108 vmap_finalise_init(vmap, content, type);
109 return vmap;
110}
111
113{
114 vaddr = ALIGN_DOWN_TO_PAGE(vaddr);
115 pr_dinfo2(vmm, "filling page at " PTR_FMT " with " PFN_FMT, vaddr, pfn);
116
117 const pfn_t old_pfn = mm_do_get_pfn(ctx->pgd, vaddr);
118
119 if (unlikely(old_pfn == pfn))
120 {
121 mos_warn("trying to replace page at " PTR_FMT " with the same page " PFN_FMT, vaddr, pfn);
122 return;
123 }
124
125 if (likely(old_pfn))
126 pmm_unref_one(old_pfn); // unmapped
127
128 pmm_ref_one(pfn);
129 mm_do_map(ctx->pgd, vaddr, pfn, 1, flags, false);
130}
131
133{
134 vmap_t *dst_vmap = mm_get_free_vaddr_locked(dst_ctx, src_vmap->npages, src_vmap->vaddr, VALLOC_EXACT);
135
136 if (unlikely(!dst_vmap))
137 {
138 mos_warn("could not find %zd pages in the address space", src_vmap->npages);
139 return NULL;
140 }
141
142 pr_dinfo2(vmm, "copying mapping from " PTR_FMT ", %zu pages", src_vmap->vaddr, src_vmap->npages);
143 mm_do_copy(src_vmap->mmctx->pgd, dst_vmap->mmctx->pgd, src_vmap->vaddr, src_vmap->npages);
144
145 dst_vmap->vmflags = src_vmap->vmflags;
146 dst_vmap->io = src_vmap->io;
147 dst_vmap->io_offset = src_vmap->io_offset;
148 dst_vmap->content = src_vmap->content;
149 dst_vmap->type = src_vmap->type;
150 dst_vmap->stat = src_vmap->stat;
151 dst_vmap->on_fault = src_vmap->on_fault;
152
153 if (src_vmap->io)
154 io_ref(src_vmap->io);
155
156 return dst_vmap;
157}
158
160{
162 list_foreach(vmap_t, vmap, mmctx->mmaps)
163 {
164 if (vmap->vaddr <= vaddr && vaddr < vmap->vaddr + vmap->npages * MOS_PAGE_SIZE)
165 return true;
166 }
167
168 return false;
169}
170
171void mm_flag_pages_locked(mm_context_t *ctx, ptr_t vaddr, size_t npages, vm_flags flags)
172{
173 MOS_ASSERT(npages > 0);
175 pr_dinfo2(vmm, "flagging %zd pages at " PTR_FMT " with flags %x", npages, vaddr, flags);
176 mm_do_flag(ctx->pgd, vaddr, npages, flags);
177}
178
180{
181 pfn_t pfn = mm_do_get_pfn(ctx->pgd, vaddr);
182 return pfn << PML1_SHIFT | (vaddr % MOS_PAGE_SIZE);
183}
#define MOS_ASSERT_X(cond, msg,...)
Definition assert.h:15
#define MOS_ASSERT(cond)
Definition assert.h:14
#define mos_warn(fmt,...)
Definition assert.h:23
#define MOS_PAGE_SIZE
Definition autoconf.h:6
#define list_foreach(t, v, h)
Iterate over a list.
Definition list.h:83
void vmap_finalise_init(vmap_t *vmap, vmap_content_t content, vmap_type_t type)
Finalize the initialization of a vmap object.
Definition mm.c:257
vmap_type_t
Definition mm.h:30
vmap_t * vmap_create(mm_context_t *mmctx, ptr_t vaddr, size_t npages)
Create a vmap object and insert it into the address space.
Definition mm.c:159
vmap_content_t
Definition mm.h:21
valloc_flags
Definition paging.h:20
ptr_t mm_get_phys_addr(mm_context_t *ctx, ptr_t vaddr)
Definition paging.c:179
void mm_replace_page_locked(mm_context_t *ctx, ptr_t vaddr, pfn_t pfn, vm_flags flags)
Replace the mappings of a page with a new physical frame.
Definition paging.c:112
vmap_t * mm_clone_vmap_locked(vmap_t *src_vmap, mm_context_t *dst_ctx)
Remap a block of virtual memory from one page table to another, i.e. copy the mappings.
Definition paging.c:132
bool mm_get_is_mapped_locked(mm_context_t *mmctx, ptr_t vaddr)
Get if a virtual address is mapped in a page table.
Definition paging.c:159
vmap_t * mm_map_user_pages(mm_context_t *mmctx, ptr_t vaddr, pfn_t pfn, size_t npages, vm_flags flags, valloc_flags vaflags, vmap_type_t type, vmap_content_t content)
Definition paging.c:92
void mm_flag_pages_locked(mm_context_t *ctx, ptr_t vaddr, size_t npages, vm_flags flags)
Update the flags of a block of virtual memory.
Definition paging.c:171
void mm_map_kernel_pages(mm_context_t *mmctx, ptr_t vaddr, pfn_t pfn, size_t npages, vm_flags flags)
Map a block of virtual memory to a block of physical memory.
Definition paging.c:82
vmap_t * mm_get_free_vaddr_locked(mm_context_t *mmctx, size_t n_pages, ptr_t base_vaddr, valloc_flags flags)
Gets npages unmapped free pages from a page table.
Definition paging.c:18
@ VALLOC_EXACT
Allocate pages at the exact address.
Definition paging.h:22
#define pmm_ref_one(thing)
Definition pmm.h:146
#define pmm_unref_one(thing)
Definition pmm.h:147
io_t * io_ref(io_t *io)
Definition io.c:73
#define likely(x)
Definition mos_global.h:39
#define ALIGN_DOWN_TO_PAGE(addr)
Definition mos_global.h:76
#define unlikely(x)
Definition mos_global.h:40
#define NULL
Definition pb_syshdr.h:46
vm_flags
Definition platform.h:40
#define pr_dinfo2(feat, fmt,...)
Definition printk.h:27
#define MOS_KERNEL_START_VADDR
#define MOS_USER_END_VADDR
#define PML1_SHIFT
should_inline bool spinlock_is_locked(const spinlock_t *lock)
Definition spinlock.h:68
#define spinlock_acquire(lock)
Definition spinlock.h:61
#define spinlock_release(lock)
Definition spinlock.h:62
spinlock_t mm_lock
protects [pgd] and the [mmaps] list (the list itself, not the vmap_t objects)
Definition platform.h:81
list_head mmaps
Definition platform.h:83
pgd_t pgd
Definition platform.h:82
size_t regular
regular pages with no special flags being set or unset
Definition mmstat.h:65
Definition mm.h:58
vmap_content_t content
Definition mm.h:70
ptr_t vaddr
Definition mm.h:62
size_t npages
Definition mm.h:63
vmfault_handler_t on_fault
Definition mm.h:73
vm_flags vmflags
Definition mm.h:64
vmap_stat_t stat
Definition mm.h:72
io_t * io
Definition mm.h:67
mm_context_t * mmctx
Definition mm.h:65
off_t io_offset
Definition mm.h:68
vmap_type_t type
Definition mm.h:71
void mm_do_map(pgd_t top, ptr_t vaddr, pfn_t pfn, size_t n_pages, vm_flags flags, bool do_refcount)
Definition table_ops.c:23
void mm_do_copy(pgd_t src, pgd_t dst, ptr_t vaddr, size_t n_pages)
Definition table_ops.c:57
pfn_t mm_do_get_pfn(pgd_t top, ptr_t vaddr)
Definition table_ops.c:67
void mm_do_flag(pgd_t top, ptr_t vaddr, size_t n_pages, vm_flags flags)
Definition table_ops.c:29
unsigned long long pfn_t
Definition types.h:41
#define PFN_FMT
Definition types.h:42
#define PTR_FMT
Definition types.h:33
unsigned long ptr_t
Definition types.h:25