FreeNOS
ProcessShares.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015 Niek Linnenbank
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <FreeNOS/System.h>
19#include <MemoryContext.h>
20#include <MemoryChannel.h>
21#include <List.h>
22#include <ListIterator.h>
23#include <SplitAllocator.h>
24#include "ProcessEvent.h"
25#include "ProcessManager.h"
26
32
34{
36 List<ProcessID> pids;
37
38 // Make a list of unique process IDs which
39 // have a share with this Process
40 Size size = m_shares.size();
41 for (Size i = 0; i < size; i++)
42 {
43 MemoryShare *sh = m_shares.get(i);
44 if (sh)
45 {
46 if (!pids.contains(sh->pid))
47 pids.append(sh->pid);
48
49 releaseShare(sh, i);
50 }
51 }
52
53 // Raise process terminated events
54 for (ListIterator<ProcessID> i(pids); i.hasCurrent(); i++)
55 {
56 ProcessID pid = i.current();
57 Process *proc = procs->get(pid);
58 if (proc)
59 {
60 ProcessEvent event;
61 event.type = ProcessTerminated;
62 event.number = m_pid;
63 procs->raiseEvent(proc, &event);
64 }
65 }
66}
67
69{
70 return m_pid;
71}
72
77
83
86 Size tagId,
87 Address virt,
88 Size size)
89{
90 MemoryShare *share = ZERO;
92
93 if (size == 0 || size % PAGESIZE)
94 return InvalidArgument;
95
96 // This code currently does not support intra-core IPC
98
99 // Allocate MemoryShare objects
100 share = new MemoryShare;
101 if (!share)
102 {
103 ERROR("failed to allocate MemoryShare");
104 return OutOfMemory;
105 }
106
107 // Fill the share object
108 share->pid = pid;
109 share->coreId = coreId;
110 share->tagId = tagId;
111 share->range.virt = virt;
112 share->range.size = size;
113
114 // For the kernel channel, set to unattached to ensure releaseShare() always works
115 share->attached = !(pid == KERNEL_PID);
116
117 // Translate to physical address
118 if ((result = m_memory->lookup(share->range.virt, &share->range.phys)) != MemoryContext::Success)
119 {
120 ERROR("failed to translate share virtual address at " <<
121 (void *)share->range.virt << ": " << (int)result);
122 delete share;
123 return MemoryMapError;
124 }
125 assert(!(share->range.phys & ~PAGEMASK));
126
127 // Retrieve memory access permissions
128 if ((result = m_memory->access(share->range.virt, &share->range.access)) != MemoryContext::Success)
129 {
130 ERROR("failed to retrieve share access permissions for virtual address " <<
131 (void *)share->range.virt << ": " << (int)result);
132 delete share;
133 return MemoryMapError;
134 }
135
136 // insert into shares list
137 Size idx = 0;
138 m_shares.insert(idx, share);
139 return Success;
140}
141
144{
145 MemoryShare *localShare = ZERO;
146 MemoryShare *remoteShare = ZERO;
147 MemoryContext *localMem = m_memory;
148 MemoryContext *remoteMem = instance.getMemoryContext();
149 Arch::Cache cache;
150 Allocator::Range allocPhys, allocVirt;
151 Size idx = 0;
152
153 if (share->range.size == 0)
154 return InvalidArgument;
155
156 // Check if the share already exists
157 if (findShare(share->pid, share->coreId, share->tagId) != ZERO)
158 return AlreadyExists;
159
160 // Check if the remote share is still detaching
161 remoteShare = instance.findShare(m_pid, share->coreId, share->tagId);
162 if (remoteShare && !remoteShare->attached)
163 {
164 return DetachInProgress;
165 }
166
167 // Allocate local
168 localShare = new MemoryShare;
169 if (!localShare)
170 {
171 ERROR("failed to allocate MemoryShare for local process");
172 return OutOfMemory;
173 }
174
175 // Allocate remote
176 remoteShare = new MemoryShare;
177 if (!remoteShare)
178 {
179 ERROR("failed to allocate MemoryShare for remote process");
180 delete localShare;
181 return OutOfMemory;
182 }
183
184 // Allocate actual pages
185 allocPhys.address = 0;
186 allocPhys.size = share->range.size;
187 allocPhys.alignment = PAGESIZE;
188
189 if (Kernel::instance()->getAllocator()->allocate(allocPhys, allocVirt) != Allocator::Success)
190 {
191 ERROR("failed to allocate pages for MemoryShare");
192 return OutOfMemory;
193 }
194
195 // Zero out the pages
196 MemoryBlock::set((void *) allocVirt.address, 0, share->range.size);
197 for (Size i = 0; i < share->range.size; i+=PAGESIZE)
198 cache.cleanData(allocVirt.address + i);
199
200 // Fill the local share object
201 localShare->pid = instance.getProcessID();
202 localShare->coreId = Kernel::instance()->getCoreInfo()->coreId;
203 localShare->tagId = share->tagId;
204 localShare->range.phys = allocPhys.address;
205 localShare->range.size = share->range.size;
206 localShare->range.access = Memory::User | share->range.access;
207 localShare->attached = true;
208
209 // Map in the local process
210 if (localMem->findFree(localShare->range.size, MemoryMap::UserShare, &localShare->range.virt) != MemoryContext::Success ||
211 localMem->mapRangeContiguous(&localShare->range) != MemoryContext::Success)
212 {
213 ERROR("failed to map MemoryShare in local process");
214 delete localShare;
215 delete remoteShare;
216 return OutOfMemory;
217 }
218 // Fill the remote share object
219 remoteShare->pid = m_pid;
220 remoteShare->coreId = localShare->coreId;
221 remoteShare->tagId = localShare->tagId;
222 remoteShare->range.phys = localShare->range.phys;
223 remoteShare->range.size = localShare->range.size;
224 remoteShare->range.access = localShare->range.access;
225 remoteShare->attached = true;
226
227 // Map in the remote process
228 if (remoteMem->findFree(remoteShare->range.size, MemoryMap::UserShare, &remoteShare->range.virt) != MemoryContext::Success ||
229 remoteMem->mapRangeContiguous(&remoteShare->range) != MemoryContext::Success)
230 {
231 ERROR("failed to map MemoryShare in remote process");
232 delete localShare;
233 delete remoteShare;
234 return OutOfMemory;
235 }
236 // insert into shares list
237 m_shares.insert(idx, localShare);
238 instance.m_shares.insert(idx, remoteShare);
239
240 // raise event on the remote process
242 Process *proc = procs->get(instance.getProcessID());
243 ProcessEvent event;
244 event.type = ShareCreated;
245 event.number = m_pid;
246 MemoryBlock::copy(&event.share, remoteShare, sizeof(*remoteShare));
247 procs->raiseEvent(proc, &event);
248
249 // Update parameter outputs
250 MemoryBlock::copy(share, localShare, sizeof(*share));
251 return Success;
252}
253
255{
256 const Size size = m_shares.size();
257 MemoryShare *s = 0;
258
259 for (Size i = 0; i < size; i++)
260 {
261 if ((s = m_shares.get(i)) != ZERO)
262 {
263 if (s->pid != pid)
264 continue;
265
266 releaseShare(s, i);
267 }
268 }
269 return Success;
270}
271
273{
275
276 // Only release physical memory if both processes have detached.
277 // Note that in case all memory shares for a certain ProcessID have
278 // been detached but not yet released, and due to a very unlikely race
279 // condition (ProcessID reuse) a new memory share was just created (before old ones were released)
280 // the new memory share would also be detached here, resulting in a memory
281 // share with is detached in this process but attached and useless in the
282 // other process.
283 if (s->attached)
284 {
286 if (proc)
287 {
288 ProcessShares & shares = proc->getShares();
289 const Size size = shares.m_shares.size();
290
291 // Mark all process shares detached in the other process
292 for (Size i = 0; i < size; i++)
293 {
294 MemoryShare *otherShare = shares.m_shares.get(i);
295 if (otherShare)
296 {
297 assert(otherShare->coreId == coreInfo.coreId);
298
299 if (otherShare->pid == m_pid && otherShare->coreId == s->coreId)
300 {
301 otherShare->attached = false;
302 }
303 }
304 }
305 }
306 }
307 else
308 {
309 // Only release physical memory pages if the other
310 // process already detached earlier
312
313 for (Size i = 0; i < s->range.size; i += PAGESIZE)
314 alloc->release(s->range.phys + i);
315 }
316
317 // Unmap the share
319
320 // Release the share object
321 delete s;
322
323 // Remove share from our administration
324 if (!m_shares.remove(idx))
325 {
326 return NotFound;
327 }
328 else
329 {
330 return Success;
331 }
332}
333
335 const Size coreId,
336 const Size tagId)
337{
338 const Size size = m_shares.size();
339
340 for (Size i = 0; i < size; i++)
341 {
342 MemoryShare *s = m_shares.get(i);
343
344 if (s != ZERO)
345 {
347
348 if (s->pid == pid && s->coreId == coreId && s->tagId == tagId)
349 {
350 return s;
351 }
352 }
353 }
354
355 return ZERO;
356}
357
359{
360 const MemoryShare *s = findShare(share->pid, share->coreId, share->tagId);
361 if (s != ZERO)
362 {
363 MemoryBlock::copy(share, s, sizeof(MemoryShare));
364 return Success;
365 }
366
367 return NotFound;
368}
u8 coreId
Definition IntelACPI.h:1
ARMv6 cache management implementation.
Definition ARMCacheV6.h:43
Memory Allocator.
Definition Allocator.h:47
virtual Result release(const Address addr)
Release memory.
Definition Allocator.cpp:89
virtual Result cleanData(Address addr)
Clean one data page.
Definition Cache.cpp:20
CoreInfo * getCoreInfo()
Get CoreInfo.
Definition Kernel.cpp:158
SplitAllocator * getAllocator()
Get physical memory allocator.
Definition Kernel.cpp:138
ProcessManager * getProcessManager()
Get process manager.
Definition Kernel.cpp:143
Iterate through a List.
virtual bool hasCurrent() const
Check if there is a current item on the List.
Simple linked list template class.
Definition List.h:37
void append(T t)
Insert an item at the end of the list.
Definition List.h:139
virtual bool contains(const T t) const
Check whether an element is on the List.
Definition List.h:219
Size size() const
Get the size of the list.
Definition List.h:392
static void * set(void *dest, int ch, unsigned count)
Fill memory with a constant byte.
static Size copy(void *dest, const void *src, Size count)
Copy memory from one place to another.
Virtual memory abstract interface.
Result
Result codes.
virtual Result findFree(Size size, MemoryMap::Region region, Address *virt) const
Find unused memory.
virtual Result unmapRange(Memory::Range *range)
Unmaps a range of virtual memory.
virtual Result mapRangeContiguous(Memory::Range *range)
Map a range of contiguous physical pages to virtual addresses.
virtual Result access(Address virt, Memory::Access *access) const =0
Get Access flags for a virtual address.
virtual Result lookup(Address virt, Address *phys) const =0
Translate virtual address to physical address.
@ UserShare
< User shared dynamic memory mappings
Definition MemoryMap.h:60
Represents a process which may run on the host.
Result raiseEvent(Process *proc, const struct ProcessEvent *event)
Raise kernel event for a Process.
Process * get(const ProcessID id)
Retrieve a Process by it's ID.
Manages memory shares for a Process.
const ProcessID getProcessID() const
Get process.
Result readShare(MemoryShare *share)
Read memory share by Process, Core and Tag IDs.
Result setMemoryContext(MemoryContext *context)
Set MemoryContext.
Result createShare(ProcessShares &instance, MemoryShare *share)
ProcessID m_pid
ProcessID associated to these shares.
MemoryShare * findShare(const ProcessID pid, const Size coreId, const Size tagId)
Retrieve MemoryShare object.
MemoryContext * m_memory
MemoryContext instance.
Result releaseShare(MemoryShare *share, Size idx)
Release one memory share.
ProcessShares(ProcessID pid)
Constructor.
virtual ~ProcessShares()
Destructor function.
Result removeShares(ProcessID pid)
Remove all shares for the given ProcessID.
MemoryContext * getMemoryContext()
Get MemoryContext object.
Index< MemoryShare, MaximumMemoryShares > m_shares
Contains all memory shares.
Represents a process which may run on the host.
Definition Process.h:45
ProcessShares & getShares()
Get process shares.
Definition Process.cpp:85
static Kernel * instance()
Retrieve the instance.
Definition Singleton.h:86
@ ProcessTerminated
@ ShareCreated
#define KERNEL_PID
Definition ProcessID.h:36
#define PAGESIZE
ARM uses 4K pages.
Definition ARMConstant.h:97
#define PAGEMASK
Mask to find the page.
CoreInfo coreInfo
Local CoreInfo instance.
#define assert(exp)
Insert program diagnostics.
Definition assert.h:60
u32 ProcessID
Process Identification Number.
Definition Types.h:140
unsigned long Address
A memory address.
Definition Types.h:131
#define ERROR(msg)
Output an error message.
Definition Log.h:61
unsigned int Size
Any sane size indicator cannot go negative.
Definition Types.h:128
#define ZERO
Zero value.
Definition Macros.h:43
@ User
Definition Memory.h:44
Describes a range of memory.
Definition Allocator.h:66
Size alignment
Alignment in bytes or ZERO for default alignment.
Definition Allocator.h:69
Address address
Starting address of the memory range.
Definition Allocator.h:67
Size size
Amount of memory in bytes.
Definition Allocator.h:68
uint coreId
Core identifier.
Definition CoreInfo.h:66
Size size
Size in number of bytes.
Definition Memory.h:59
Address phys
Physical address.
Definition Memory.h:58
Address virt
Virtual address.
Definition Memory.h:57
Access access
Page access flags.
Definition Memory.h:60
Represents a process which may run on the host.
ProcessEventType type
ProcessShares::MemoryShare share
bool attached
True if the share is attached (used by both processes)
ProcessID pid
Remote process id for this share.
Size tagId
Share tag id is defined by the application.
Memory::Range range
Physical memory address range.
Size coreId
CoreId for the other process.