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 
28 {
29  m_pid = pid;
30  m_memory = ZERO;
31 }
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 
74 {
75  return m_memory;
76 }
77 
79 {
80  m_memory = ctx;
81  return Success;
82 }
83 
85  Size coreId,
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 {
274  assert(s->coreId == coreInfo.coreId);
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
318  m_memory->unmapRange(&s->range);
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  {
346  assert(s->coreId == coreInfo.coreId);
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 }
MemoryBlock::copy
static Size copy(void *dest, const void *src, Size count)
Copy memory from one place to another.
Definition: MemoryBlock.cpp:36
ProcessManager::raiseEvent
Result raiseEvent(Process *proc, const struct ProcessEvent *event)
Raise kernel event for a Process.
Definition: ProcessManager.cpp:325
ProcessShares::~ProcessShares
virtual ~ProcessShares()
Destructor function.
Definition: ProcessShares.cpp:33
ProcessShares::MemoryShare::tagId
Size tagId
Share tag id is defined by the application.
Definition: ProcessShares.h:57
SplitAllocator.h
ProcessManager
Represents a process which may run on the host.
Definition: ProcessManager.h:44
MemoryContext
Virtual memory abstract interface.
Definition: MemoryContext.h:42
ProcessShares::MemoryShare
Definition: ProcessShares.h:48
MemoryContext::unmapRange
virtual Result unmapRange(Memory::Range *range)
Unmaps a range of virtual memory.
Definition: MemoryContext.cpp:95
MemoryContext::access
virtual Result access(Address virt, Memory::Access *access) const =0
Get Access flags for a virtual address.
ProcessShares::MemoryShare::pid
ProcessID pid
Remote process id for this share.
Definition: ProcessShares.h:51
Process
Represents a process which may run on the host.
Definition: Process.h:44
MemoryBlock::set
static void * set(void *dest, int ch, unsigned count)
Fill memory with a constant byte.
Definition: MemoryBlock.cpp:25
Allocator
Memory Allocator.
Definition: Allocator.h:46
PAGEMASK
#define PAGEMASK
Mask to find the page.
Definition: ARMConstant.h:121
Memory::User
@ User
Definition: Memory.h:44
PAGESIZE
#define PAGESIZE
ARM uses 4K pages.
Definition: ARMConstant.h:97
ProcessShares::OutOfMemory
@ OutOfMemory
Definition: ProcessShares.h:71
ProcessID
u32 ProcessID
Process Identification Number.
Definition: Types.h:140
MemoryMap::UserShare
@ UserShare
< User shared dynamic memory mappings
Definition: MemoryMap.h:60
Address
unsigned long Address
A memory address.
Definition: Types.h:131
Allocator::Range::address
Address address
Starting address of the memory range.
Definition: Allocator.h:67
Kernel::getAllocator
SplitAllocator * getAllocator()
Get physical memory allocator.
Definition: Kernel.cpp:138
ProcessShares::MemoryShare::range
Memory::Range range
Physical memory address range.
Definition: ProcessShares.h:60
KERNEL_PID
#define KERNEL_PID
Definition: ProcessID.h:36
Allocator::Range::alignment
Size alignment
Alignment in bytes or ZERO for default alignment.
Definition: Allocator.h:69
ProcessShares::MemoryShare::coreId
Size coreId
CoreId for the other process.
Definition: ProcessShares.h:54
Kernel::getProcessManager
ProcessManager * getProcessManager()
Get process manager.
Definition: Kernel.cpp:143
ProcessTerminated
@ ProcessTerminated
Definition: ProcessEvent.h:34
Process::getShares
ProcessShares & getShares()
Get process shares.
Definition: Process.cpp:85
Allocator::Range::size
Size size
Amount of memory in bytes.
Definition: Allocator.h:68
CoreInfo::coreId
uint coreId
Core identifier.
Definition: CoreInfo.h:66
MemoryContext::lookup
virtual Result lookup(Address virt, Address *phys) const =0
Translate virtual address to physical address.
Kernel::getCoreInfo
CoreInfo * getCoreInfo()
Get CoreInfo.
Definition: Kernel.cpp:158
ProcessEvent
Represents a process which may run on the host.
Definition: ProcessEvent.h:40
Allocator::Success
@ Success
Definition: Allocator.h:55
Memory::Range::phys
Address phys
Physical address.
Definition: Memory.h:58
ListIterator::hasCurrent
virtual bool hasCurrent() const
Check if there is a current item on the List.
Definition: ListIterator.h:104
MemoryContext::Result
Result
Result codes.
Definition: MemoryContext.h:49
ARMCacheV6
ARMv6 cache management implementation.
Definition: ARMCacheV6.h:42
List::append
void append(T t)
Insert an item at the end of the list.
Definition: List.h:139
ProcessManager.h
ProcessShares::MemoryMapError
@ MemoryMapError
Definition: ProcessShares.h:70
ProcessEvent.h
MemoryContext::Success
@ Success
Definition: MemoryContext.h:51
MemoryContext::findFree
virtual Result findFree(Size size, MemoryMap::Region region, Address *virt) const
Find unused memory.
Definition: MemoryContext.cpp:117
ProcessShares::ProcessShares
ProcessShares(ProcessID pid)
Constructor.
Definition: ProcessShares.cpp:27
Size
unsigned int Size
Any sane size indicator cannot go negative.
Definition: Types.h:128
WeakSingleton< Kernel >::instance
static Kernel * instance()
Retrieve the instance.
Definition: Singleton.h:86
Cache::cleanData
virtual Result cleanData(Address addr)
Clean one data page.
Definition: Cache.cpp:20
ProcessManager::get
Process * get(const ProcessID id)
Retrieve a Process by it's ID.
Definition: ProcessManager.cpp:95
ProcessShares::readShare
Result readShare(MemoryShare *share)
Read memory share by Process, Core and Tag IDs.
Definition: ProcessShares.cpp:358
ProcessShares::createShare
Result createShare(ProcessShares &instance, MemoryShare *share)
Definition: ProcessShares.cpp:142
ProcessShares::findShare
MemoryShare * findShare(const ProcessID pid, const Size coreId, const Size tagId)
Retrieve MemoryShare object.
Definition: ProcessShares.cpp:334
coreInfo
CoreInfo coreInfo
Local CoreInfo instance.
ProcessShares::MemoryShare::attached
bool attached
True if the share is attached (used by both processes)
Definition: ProcessShares.h:63
ProcessEvent::share
ProcessShares::MemoryShare share
Definition: ProcessEvent.h:44
Allocator::Range
Describes a range of memory.
Definition: Allocator.h:65
ProcessShares::getMemoryContext
MemoryContext * getMemoryContext()
Get MemoryContext object.
Definition: ProcessShares.cpp:73
ShareCreated
@ ShareCreated
Definition: ProcessEvent.h:33
ListIterator.h
assert
#define assert(exp)
Insert program diagnostics.
Definition: assert.h:60
ERROR
#define ERROR(msg)
Output an error message.
Definition: Log.h:61
ProcessShares::releaseShare
Result releaseShare(MemoryShare *share, Size idx)
Release one memory share.
Definition: ProcessShares.cpp:272
Allocator::release
virtual Result release(const Address addr)
Release memory.
Definition: Allocator.cpp:89
List::contains
virtual bool contains(const T t) const
Check whether an element is on the List.
Definition: List.h:219
Memory::Range::virt
Address virt
Virtual address.
Definition: Memory.h:57
ProcessShares::getProcessID
const ProcessID getProcessID() const
Get process.
Definition: ProcessShares.cpp:68
MemoryChannel.h
ProcessShares::m_shares
Index< MemoryShare, MaximumMemoryShares > m_shares
Contains all memory shares.
Definition: ProcessShares.h:183
List
Simple linked list template class.
Definition: List.h:36
MemoryContext.h
ProcessEvent::type
ProcessEventType type
Definition: ProcessEvent.h:42
ProcessShares::NotFound
@ NotFound
Definition: ProcessShares.h:74
Memory::Range::size
Size size
Size in number of bytes.
Definition: Memory.h:59
ProcessShares::Result
Result
Definition: ProcessShares.h:66
Memory::Range::access
Access access
Page access flags.
Definition: Memory.h:60
ProcessShares::m_memory
MemoryContext * m_memory
MemoryContext instance.
Definition: ProcessShares.h:180
ProcessShares::removeShares
Result removeShares(ProcessID pid)
Remove all shares for the given ProcessID.
Definition: ProcessShares.cpp:254
ZERO
#define ZERO
Zero value.
Definition: Macros.h:43
ProcessShares::DetachInProgress
@ DetachInProgress
Definition: ProcessShares.h:73
coreId
u8 coreId
Definition: IntelACPI.h:64
ProcessShares::InvalidArgument
@ InvalidArgument
Definition: ProcessShares.h:69
ProcessShares::AlreadyExists
@ AlreadyExists
Definition: ProcessShares.h:72
MemoryContext::mapRangeContiguous
virtual Result mapRangeContiguous(Memory::Range *range)
Map a range of contiguous physical pages to virtual addresses.
Definition: MemoryContext.cpp:46
ProcessShares::setMemoryContext
Result setMemoryContext(MemoryContext *context)
Set MemoryContext.
Definition: ProcessShares.cpp:78
List.h
ProcessShares::m_pid
ProcessID m_pid
ProcessID associated to these shares.
Definition: ProcessShares.h:177
ProcessShares
Manages memory shares for a Process.
Definition: ProcessShares.h:39
ListIterator
Iterate through a List.
Definition: ListIterator.h:37
ProcessShares::Success
@ Success
Definition: ProcessShares.h:68