9
9
#include < Kernel/Arch/i386/PIT.h>
10
10
#include < Kernel/Devices/NullDevice.h>
11
11
#include < Kernel/FileSystem/Custody.h>
12
- #include < Kernel/FileSystem/Ext2FileSystem.h>
13
- #include < Kernel/FileSystem/ProcFS.h>
14
12
#include < Kernel/FileSystem/DevPtsFS.h>
15
- #include < Kernel/FileSystem/TmpFS .h>
13
+ #include < Kernel/FileSystem/Ext2FileSystem .h>
16
14
#include < Kernel/FileSystem/FIFO.h>
17
15
#include < Kernel/FileSystem/FileDescription.h>
18
16
#include < Kernel/FileSystem/InodeWatcher.h>
17
+ #include < Kernel/FileSystem/ProcFS.h>
19
18
#include < Kernel/FileSystem/SharedMemory.h>
19
+ #include < Kernel/FileSystem/TmpFS.h>
20
20
#include < Kernel/FileSystem/VirtualFileSystem.h>
21
21
#include < Kernel/IO.h>
22
22
#include < Kernel/KBufferBuilder.h>
@@ -108,6 +108,12 @@ static unsigned prot_to_region_access_flags(int prot)
108
108
return access;
109
109
}
110
110
111
+ Region& Process::allocate_split_region (const Region& source_region, const Range& range)
112
+ {
113
+ m_regions.append (Region::create_user_accessible (range, source_region.name (), source_region.access ()));
114
+ return m_regions.last ();
115
+ }
116
+
111
117
Region* Process::allocate_region (VirtualAddress vaddr, size_t size, const String& name, int prot, bool commit)
112
118
{
113
119
auto range = allocate_range (vaddr, size);
@@ -154,11 +160,20 @@ bool Process::deallocate_region(Region& region)
154
160
return false ;
155
161
}
156
162
157
- Region* Process::region_from_range (VirtualAddress vaddr, size_t size)
163
+ Region* Process::region_from_range (const Range& range)
164
+ {
165
+ size_t size = PAGE_ROUND_UP (range.size ());
166
+ for (auto & region : m_regions) {
167
+ if (region.vaddr () == range.base () && region.size () == size)
168
+ return ®ion;
169
+ }
170
+ return nullptr ;
171
+ }
172
+
173
+ Region* Process::region_containing (const Range& range)
158
174
{
159
- size = PAGE_ROUND_UP (size);
160
175
for (auto & region : m_regions) {
161
- if (region.vaddr () == vaddr && region. size () == size )
176
+ if (region.contains (range) )
162
177
return ®ion;
163
178
}
164
179
return nullptr ;
@@ -168,7 +183,7 @@ int Process::sys$set_mmap_name(void* addr, size_t size, const char* name)
168
183
{
169
184
if (!validate_read_str (name))
170
185
return -EFAULT;
171
- auto * region = region_from_range (VirtualAddress ((u32 )addr), size);
186
+ auto * region = region_from_range ({ VirtualAddress ((u32 )addr), size } );
172
187
if (!region)
173
188
return -EINVAL;
174
189
region->set_name (String (name));
@@ -220,17 +235,46 @@ void* Process::sys$mmap(const Syscall::SC_mmap_params* params)
220
235
221
236
int Process::sys$munmap(void * addr, size_t size)
222
237
{
223
- auto * region = region_from_range (VirtualAddress ((u32 )addr), size);
224
- if (!region)
225
- return -EINVAL;
226
- if (!deallocate_region (*region))
227
- return -EINVAL;
228
- return 0 ;
238
+ Range range_to_unmap { VirtualAddress ((u32 )addr), size };
239
+ if (auto * whole_region = region_from_range (range_to_unmap)) {
240
+ bool success = deallocate_region (*whole_region);
241
+ ASSERT (success);
242
+ return 0 ;
243
+ }
244
+
245
+ if (auto * old_region = region_containing (range_to_unmap)) {
246
+ Range old_region_range = old_region->range ();
247
+ auto remaining_ranges_after_unmap = old_region_range.carve (range_to_unmap);
248
+ ASSERT (!remaining_ranges_after_unmap.is_empty ());
249
+ auto make_replacement_region = [&](const Range& new_range) -> Region& {
250
+ auto & new_region = allocate_split_region (*old_region, new_range);
251
+ ASSERT (new_range.base () >= old_region_range.base ());
252
+ size_t new_range_offset_in_old_region = new_range.base ().get () - old_region_range.base ().get ();
253
+ size_t first_physical_page_of_new_region_in_old_region = new_range_offset_in_old_region / PAGE_SIZE;
254
+ for (size_t i = 0 ; i < new_region.page_count (); ++i) {
255
+ new_region.vmo ().physical_pages ()[i] = old_region->vmo ().physical_pages ()[first_physical_page_of_new_region_in_old_region + i];
256
+ }
257
+ return new_region;
258
+ };
259
+ Vector<Region*, 2 > new_regions;
260
+ for (auto & new_range : remaining_ranges_after_unmap) {
261
+ new_regions.unchecked_append (&make_replacement_region (new_range));
262
+ }
263
+ deallocate_region (*old_region);
264
+ for (auto * new_region : new_regions) {
265
+ MM.map_region (*this , *new_region);
266
+ }
267
+ return 0 ;
268
+ }
269
+
270
+ // FIXME: We should also support munmap() across multiple regions. (#175)
271
+
272
+ return -EINVAL;
229
273
}
230
274
231
275
int Process::sys$mprotect(void * addr, size_t size, int prot)
232
276
{
233
- auto * region = region_from_range (VirtualAddress ((u32 )addr), size);
277
+ auto * region = region_from_range ({ VirtualAddress ((u32 )addr), size } );
234
278
if (!region)
235
279
return -EINVAL;
236
280
region->set_writable (prot & PROT_WRITE);
@@ -2930,4 +2974,3 @@ int Process::sys$get_process_name(char* buffer, int buffer_size)
2930
2974
strncpy (buffer, m_name.characters (), buffer_size);
2931
2975
return 0 ;
2932
2976
}
2933
-
0 commit comments