1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2026 Richard Qin */
/*
* Memory Management System Calls
*
* Implements: brk, mmap (anonymous only), munmap, mprotect.
*
* Reference: docs/specs/syscall.md §7.2
*/
#include <lume/types.h>
#include <lume/task.h>
#include <lume/vmm.h>
#include <lume/errno.h>
#include <lume/mman.h>
#include <lume/config.h>
#include <lume/klog.h>
/* Page alignment helpers */
static inline uint64 page_align_up(uint64 x)
{
return (x + kPageSize - 1) & ~(kPageSize - 1);
}
static inline uint64 page_align_down(uint64 x)
{
return x & ~(kPageSize - 1);
}
/* ======================================================================
* sys_brk
* ====================================================================== */
int64 sys_brk(uint64 new_brk, uint64, uint64, uint64, uint64, uint64)
{
VmSpace* mm = current_task()->mm;
if (!mm)
return -ENOMEM; /* kernel threads have no user address space */
if (new_brk == 0) {
return static_cast<int64>(mm->brk_end);
}
if (mm->brk_start == 0) {
uint64 init_brk = page_align_up(new_brk);
mm->brk_start = init_brk;
mm->brk_end = init_brk;
}
if (new_brk < mm->brk_start) {
return -EINVAL;
}
uint64 new_end = page_align_up(new_brk);
if (new_end > mm->brk_end) {
uint64 grow = new_end - mm->brk_end;
int ret = vmm_map_user(mm, mm->brk_end, grow, VM_READ | VM_WRITE);
if (ret < 0) {
return ret;
}
} else if (new_end < mm->brk_end) {
uint64 shrink = mm->brk_end - new_end;
int ret = vmm_unmap_user(mm, new_end, shrink);
if (ret < 0) {
return ret;
}
}
mm->brk_end = new_end;
return static_cast<int64>(new_brk);
}
/* ======================================================================
* sys_mmap
* ====================================================================== */
int64 sys_mmap(uint64 addr, uint64 length, uint64 prot,
uint64 flags, uint64 fd, uint64 offset)
{
printk("[mmap] addr=%llx len=%llx prot=%llx flags=%llx fd=%lld off=%llx\n",
addr, length, prot, flags, static_cast<int64>(fd), offset);
if (length == 0) return -EINVAL;
length = page_align_up(length);
if (offset % kPageSize != 0) return -EINVAL;
if ((flags & MAP_PRIVATE) && (flags & MAP_SHARED)) return -EINVAL;
if (!(flags & MAP_PRIVATE) && !(flags & MAP_SHARED)) return -EINVAL;
VmSpace* mm = current_task()->mm;
if (!mm) return -ENOMEM;
/* Phase 2: only anonymous private mappings */
if (!(flags & MAP_ANONYMOUS)) {
printk("[mmap] REJECTED: file-backed mmap not implemented\n");
return -ENOSYS; /* File-backed mmap is Phase 3 */
}
if (flags & MAP_SHARED)
return -ENOSYS; /* Shared mappings are Phase 3 */
(void)fd;
/* Convert POSIX prot → MI permission flags */
uint64 vm_perm = 0;
if (prot & PROT_READ) vm_perm |= VM_READ;
if (prot & PROT_WRITE) vm_perm |= VM_WRITE;
if (prot & PROT_EXEC) vm_perm |= VM_EXEC;
vm_perm |= VM_USER;
uint64 va = addr;
if (flags & MAP_FIXED) {
if (va % kPageSize != 0) return -EINVAL;
} else if (va != 0) {
va = page_align_down(va);
}
if (va == 0) {
va = mm_find_free_va(mm, length, kPageSize);
if (!va) return -ENOMEM;
}
if (flags & MAP_FIXED) {
int ret = vmm_unmap_user(mm, va, length);
if (ret < 0) return ret;
}
int ret = vmm_map_user(mm, va, length, vm_perm);
if (ret < 0 && !(flags & MAP_FIXED) && addr != 0) {
uint64 fallback = mm_find_free_va(mm, length, kPageSize);
if (!fallback) return ret;
ret = vmm_map_user(mm, fallback, length, vm_perm);
if (ret < 0) return ret;
va = fallback;
} else if (ret < 0) {
return ret;
}
return static_cast<int64>(va);
}
/* ======================================================================
* sys_munmap
* ====================================================================== */
int64 sys_munmap(uint64 addr, uint64 length, uint64, uint64, uint64, uint64)
{
if (length == 0) return -EINVAL;
if (addr % kPageSize != 0) return -EINVAL;
length = page_align_up(length);
VmSpace* mm = current_task()->mm;
if (!mm) return -EINVAL;
return vmm_unmap_user(mm, addr, length);
}
/* ======================================================================
* sys_mprotect — Phase 2 stub
* ====================================================================== */
int64 sys_mprotect(uint64 addr, uint64 len, uint64 prot,
uint64, uint64, uint64)
{
if (len == 0) return -EINVAL;
if (addr % kPageSize != 0) return -EINVAL;
VmSpace* mm = current_task()->mm;
if (!mm) return -ENOMEM;
uint64 vm_perm = 0;
if (prot & PROT_READ) vm_perm |= VM_READ;
if (prot & PROT_WRITE) vm_perm |= VM_WRITE;
if (prot & PROT_EXEC) vm_perm |= VM_EXEC;
return vmm_protect_user(mm, addr, len, vm_perm);
}
|