/[hurd]/hurd-l4/physmem/container.c
ViewVC logotype

Diff of /hurd-l4/physmem/container.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 1.11 by marcus, Mon Nov 1 20:54:00 2004 UTC revision 1.12 by neal, Tue Jan 11 18:15:26 2005 UTC
# Line 1  Line 1 
1  /* container.c - container class for physical memory server.  /* container.c - container class for physical memory server.
2     Copyright (C) 2003 Free Software Foundation, Inc.     Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
3     Written by Marcus Brinkmann.     Written by Neal H. Walfield <neal@gnu.org>.
4    
5     This file is part of the GNU Hurd.     This file is part of the GNU Hurd.
6    
7     The GNU Hurd is free software; you can redistribute it and/or     The GNU Hurd is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Lesser General Public     modify it under the terms of the GNU General Public License as
9     License as published by the Free Software Foundation; either     published by the Free Software Foundation; either version 2, or (at
10     version 2.1 of the License, or (at your option) any later version.     your option) any later version.
11      
12     The GNU Hurd is distributed in the hope that it will be useful,     The GNU Hurd is distributed in the hope that it will be useful, but
13     but WITHOUT ANY WARRANTY; without even the implied warranty of     WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15     Lesser General Public License for more details.     General Public License for more details.
16      
17     You should have received a copy of the GNU Lesser General Public     You should have received a copy of the GNU General Public License
18     License along with the GNU C Library; if not, write to the Free     along with the GNU Hurd; see the file COPYING.  If not, write to
19     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA     the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
20     02111-1307 USA.  */     USA.  */
21    
22  #if HAVE_CONFIG_H  #if HAVE_CONFIG_H
23  #include <config.h>  #include <config.h>
24  #endif  #endif
25    
26  #include <stdlib.h>  #include <stdlib.h>
27    #include <errno.h>
28    #include <pthread.h>
29    #include <compiler.h>
30  #include <l4.h>  #include <l4.h>
31    
32  #include <hurd/cap-server.h>  #include <hurd/cap-server.h>
33    #include <hurd/btree.h>
34    
35  #include "physmem.h"  #include "physmem.h"
36  #include "zalloc.h"  #include "zalloc.h"
37    
38    #include "output.h"
39    
40    
41  static void  static struct hurd_cap_class container_class;
42  container_reinit (hurd_cap_class_t cap_class, hurd_cap_obj_t obj)  
43    
44    /* CTX->obj should be a memory control object, not a container.  */
45    static error_t
46    container_create (hurd_cap_rpc_context_t ctx)
47  {  {
48    container_t container = hurd_cap_obj_to_user (container_t, obj);    error_t err;
49    l4_word_t nr_fpages;    hurd_cap_obj_t obj;
50      hurd_cap_handle_t handle;
51    
52    nr_fpages = container->nr_fpages;    l4_msg_clear (ctx->msg);
53    
54    l4_unmap_fpages (nr_fpages, container->fpages);    err = hurd_cap_class_alloc (&container_class, &obj);
55      if (err)
56        return err;
57      hurd_cap_obj_unlock (obj);
58    
59    while (nr_fpages > 0)    err = hurd_cap_bucket_inject (ctx->bucket, obj, ctx->sender, &handle);
60      if (err)
61      {      {
62        l4_fpage_t fpage = container->fpages[--nr_fpages];        hurd_cap_obj_drop (obj);
63        zfree (l4_address (fpage), l4_size (fpage));        return err;
64      }      }
65    
66      /* The reply message consists of a single word, a capability handle
67         which the client can use to refer to the container.  */
68    
69      l4_msg_append_word (ctx->msg, handle);
70    
71      debug ("Created handle %x\n", handle);
72    
73      return 0;
74  }  }
75    
76    static error_t
77  error_t  container_share (hurd_cap_rpc_context_t ctx)
 container_map (hurd_cap_rpc_context_t ctx)  
78  {  {
79    container_t container = hurd_cap_obj_to_user (container_t, ctx->obj);    return EOPNOTSUPP;
80    l4_word_t offset = l4_page_trunc (l4_msg_word (ctx->msg, 1));  }
   l4_word_t rights = l4_msg_word (ctx->msg, 1) & 0x7;  
   l4_word_t size = l4_page_round (l4_msg_word (ctx->msg, 2));  
   l4_word_t vaddr = l4_page_trunc (l4_msg_word (ctx->msg, 3));  
   l4_word_t start;  
   l4_word_t end;  
   l4_word_t nr_fpages;  
 #define MAX_MAP_ITEMS ((L4_NUM_MRS - 1) / 2)  
   l4_fpage_t fpages[MAX_MAP_ITEMS];  
   l4_word_t i;  
81    
82    /* FIXME FIXME FIXME */  static error_t
83    if (offset > 0x8000000)  container_allocate (hurd_cap_rpc_context_t ctx)
84    {
85      error_t err;
86      struct container *container = hurd_cap_obj_to_user (struct container *,
87                                                          ctx->obj);
88      l4_word_t flags = l4_msg_word (ctx->msg, 1);
89      uintptr_t start = l4_msg_word (ctx->msg, 2);
90      size_t size = l4_msg_word (ctx->msg, 3);
91      size_t amount;
92      int i;
93    
94      /* We require at least three arguments (in addition to the cap id):
95         the flags, the start and the size.  */
96      if (l4_untyped_words (l4_msg_msg_tag (ctx->msg)) != 4)
97      {      {
98        /* Allocation.  */        debug ("incorrect number of arguments passed.  require 4 but got %d\n",
99        start = zalloc (size);               l4_untyped_words (l4_msg_msg_tag (ctx->msg)));
100        end = start + size - 1;        l4_msg_clear (ctx->msg);
101          return EINVAL;
102        }
103    
104      /* Allocate the memory.  */
105      l4_fpage_t fpages[L4_FPAGE_SPAN_MAX];
106      int nr_fpages = l4_fpage_span (0, size - 1, fpages);
107    
108      for (err = 0, amount = 0, i = 0; i < nr_fpages; i ++)
109        {
110          /* FIXME: Check to make sure that the memory control object that
111             this container refers to has enough memory to do each
112             allocation.  */
113          struct frame_entry *fe = frame_entry_alloc ();
114          if (! fe)
115            break;
116    
117          err = frame_entry_new (container, fe, start + l4_address (fpages[i]),
118                                 l4_size (fpages[i]));
119          if (err)
120            {
121              frame_entry_dealloc (fe);
122              break;
123            }
124    
125          amount += l4_size (fpages[i]);
126    
127          /* XXX: Use the flags.
128             frame->flags = flags; */
129      }      }
130    else  
131      l4_msg_clear (ctx->msg);
132      l4_msg_append_word (ctx->msg, amount);
133    
134      return err;
135    }
136    
137    static error_t
138    container_deallocate (hurd_cap_rpc_context_t ctx)
139    {
140      error_t err;
141      struct container *container = hurd_cap_obj_to_user (struct container *,
142                                                          ctx->obj);
143      uintptr_t start = l4_msg_word (ctx->msg, 1);
144      size_t size = l4_msg_word (ctx->msg, 2);
145      struct frame_entry *fe;
146    
147      /* We require at least two arguments (in addition to the cap id):
148         the start and the size.  */
149      if (l4_untyped_words (l4_msg_msg_tag (ctx->msg)) != 3)
150      {      {
151        /* FIXME: Currently, we just trust that everything is all-right.  */        debug ("incorrect number of arguments passed.  require 3 but got %d\n",
152        start = l4_address (container->fpages[0]) + offset;               l4_untyped_words (l4_msg_msg_tag (ctx->msg)));
153        end = start + size - 1;        l4_msg_clear (ctx->msg);
154          return EINVAL;
155      }      }
156    
157    l4_msg_clear (ctx->msg);    l4_msg_clear (ctx->msg);
   nr_fpages = l4_fpage_xspan (start, end, vaddr, fpages, MAX_MAP_ITEMS);  
158    
159    for (i = 0; i < nr_fpages; i++)    fe = frame_entry_find (container, start, size);
160      if (! fe)
161        /* Nothing was allocated in this region.  */
162        return 0;
163    
164      /* Find the first region which overlaps with this one.  */
165      while (1)
166        {
167          struct frame_entry *prev = hurd_btree_frame_entry_prev (fe);
168    
169          if (! prev
170              || ! overlap (prev->region.start, prev->region.size, start, size))
171            break;
172    
173          fe = prev;
174        }
175    
176      for (;;)
177      {      {
178        l4_map_item_t map_item;        struct frame_entry *next = hurd_btree_frame_entry_next (fe);
       l4_fpage_t fpage;  
179    
180        fpage = fpages[i];        if (start <= fe->region.start
181        l4_set_rights (&fpage, rights);            && start + size <= fe->region.start + fe->region.size)
182        map_item = l4_map_item (fpage, vaddr);          /* Deallocate the entire frame entry.  */
183        l4_msg_append_map_item (ctx->msg, map_item);          {
184        vaddr += l4_size (fpage);            frame_entry_drop (container, fe);
185              frame_entry_dealloc (fe);
186            }
187          else
188            /* We keep part of the region.  */
189            {
190              int i;
191              l4_fpage_t fpages[L4_FPAGE_SPAN_MAX];
192              int nr_fpages;
193    
194              /* Detach the frame entry from its container: frame entries
195                 in the same container cannot overlap and we are going to
196                 replace it with a set of smaller frame entries covering
197                 the physical memory which will not be deallocated.  */
198              frame_entry_detach (container, fe);
199    
200              if (start >= fe->region.start)
201                /* We keep part of the start of the region.  */
202                {
203                  nr_fpages = l4_fpage_span (0, start - fe->region.start, fpages);
204    
205                  for (i = 0; i < nr_fpages; i ++)
206                    {
207                      struct frame_entry *subfe = frame_entry_alloc ();
208                      assert (fe);
209    
210                      err = frame_entry_use (container, subfe,
211                                             start + l4_address (fpages[i]),
212                                             l4_size (fpages[i]),
213                                             fe->frame, l4_address (fpages[i]));
214                      assert_perror (err);
215                    }
216                }
217    
218              if (start + size < fe->region.start + fe->region.size)
219                /* We keep part of the end of the region.  */
220                {
221                  nr_fpages = l4_fpage_span (0, size - start, fpages);
222    
223                  for (i = 0; i < nr_fpages; i ++)
224                    {
225                      struct frame_entry *subfe = frame_entry_alloc ();
226                      assert (fe);
227    
228                      err = frame_entry_use (container, subfe,
229                                             start + l4_address (fpages[i]),
230                                             l4_size (fpages[i]),
231                                             fe->frame, l4_address (fpages[i]));
232                      assert_perror (err);
233                    }
234                }
235    
236              frame_deref (fe->frame);
237              frame_entry_dealloc (fe);
238            }
239    
240          if (! next || ! overlap (next->region.start, next->region.size,
241                                   start, size))
242            break;
243          fe = next;
244      }      }
245    
246    return 0;    return 0;
247  }  }
248    
249    static error_t
250    container_map (hurd_cap_rpc_context_t ctx)
251    {
252      struct container *container = hurd_cap_obj_to_user (struct container *,
253                                                          ctx->obj);
254      uintptr_t index = l4_page_trunc (l4_msg_word (ctx->msg, 1));
255      l4_word_t rights = l4_msg_word (ctx->msg, 1) & 0x7;
256      size_t size = l4_page_round (l4_msg_word (ctx->msg, 2));
257      uintptr_t vaddr = l4_page_trunc (l4_msg_word (ctx->msg, 3));
258      int nr_fpages;
259    #define MAX_MAP_ITEMS ((L4_NUM_MRS - 1) / 2)
260      int i;
261    
262      l4_msg_clear (ctx->msg);
263      
264      pthread_mutex_lock (&container->lock);
265    
266      for (i = 0; i < MAX_MAP_ITEMS && size > 0; )
267        {
268          l4_fpage_t fpages[MAX_MAP_ITEMS];
269          struct frame_entry *fe;
270    
271          /* Get the memory.  */
272          fe = frame_entry_find (container, index, 1);
273          if (! fe)
274            {
275              pthread_mutex_unlock (&container->lock);
276              return errno;
277            }
278    
279          /* Allocate the memory (if needed).  */
280          if (! fe->frame)
281            {
282              fe->frame = frame_alloc (fe->region.size);
283              if (! fe->frame)
284                {
285                  pthread_mutex_unlock (&container->lock);
286                  return errno;
287                }
288    
289              frame_use (fe->frame, fe);
290            }
291    
292          frame_memory_bind (fe->frame);
293          fe->frame->may_be_mapped = true;
294    
295          /* This might only be a partial mapping of a memory.  Subtract
296             the desired index from where the memory actually starts and
297             add that to the address of the physical memory block.  */
298          l4_word_t mem
299            = l4_address (fe->frame->memory) + index - fe->region.start;
300          l4_word_t amount = fe->region.size - (index - fe->region.start);
301    
302          /* Does the user want all that we can give?  */
303          if (amount > size)
304            amount = size;
305    
306          /* Adjust the index and the size.  */
307          size -= amount;
308          index += amount;
309    
310          nr_fpages = l4_fpage_xspan (mem, mem + amount - 1,
311                                      vaddr, &fpages[i], MAX_MAP_ITEMS - i);
312          for (; i < MAX_MAP_ITEMS && amount > 0; i ++)
313            {
314              l4_map_item_t map_item;
315    
316              assert (nr_fpages > 0);
317    
318              /* Set the desired permissions.  */
319              l4_set_rights (&fpages[i], rights);
320    
321              /* Add the mad item to the message.  */
322              map_item = l4_map_item (fpages[i], vaddr);
323              l4_msg_append_map_item (ctx->msg, map_item);
324    
325              mem += l4_size (fpages[i]);
326              vaddr += l4_size (fpages[i]);
327              amount -= l4_size (fpages[i]);
328              nr_fpages --;
329            }
330    
331          assert (nr_fpages == 0);
332        }
333    
334      pthread_mutex_unlock (&container->lock);
335    
336      return 0;
337    }
338    
339    enum container_ops
340      {
341        container_create_id = 130,
342        container_share_id,
343        container_allocate_id,
344        container_deallocate_id,
345        container_map_id
346      };
347    
348  error_t  error_t
349  container_demuxer (hurd_cap_rpc_context_t ctx)  container_demuxer (hurd_cap_rpc_context_t ctx)
350  {  {
351    error_t err = 0;    error_t err = 0;
352    
353      debug ("Message %d from %x\n", l4_msg_label (ctx->msg), ctx->from);
354    switch (l4_msg_label (ctx->msg))    switch (l4_msg_label (ctx->msg))
355      {      {
356        /* PHYSMEM_MAP */      case container_create_id:
357      case 128:        err = container_create (ctx);
358          break;
359    
360        case container_share_id:
361          err = container_share (ctx);
362          break;
363    
364        case container_allocate_id:
365          err = container_allocate (ctx);
366          break;
367    
368        case container_deallocate_id:
369          err = container_deallocate (ctx);
370          break;
371    
372        case 128: /* The old container map implementation.  */
373        case container_map_id:
374        err = container_map (ctx);        err = container_map (ctx);
375        break;        break;
376    
# Line 114  container_demuxer (hurd_cap_rpc_context_ Line 378  container_demuxer (hurd_cap_rpc_context_
378        err = EOPNOTSUPP;        err = EOPNOTSUPP;
379      }      }
380    
381    return err;    /* If the stub returns EOPNOTSUPP then we clear the message buffer,
382  }       otherwise we assume that the message buffer contains a valid
383         reply message and in which case we set the error code returned by
384         the stub and have the demuxer succeed.  */
385      if (EXPECT_FALSE (err == EOPNOTSUPP))
386        l4_msg_clear (ctx->msg);
387    
388      l4_set_msg_label (ctx->msg, err);
389    
390      debug ("Returning error %d\n", err);
 static struct hurd_cap_class container_class;  
391    
392  /* Initialize the container class subsystem.  */    return 0;
 error_t  
 container_class_init ()  
 {  
   return hurd_cap_class_init (&container_class, container_t,  
                               NULL, NULL, container_reinit, NULL,  
                               container_demuxer);  
393  }  }
   
394    
 /* Allocate a new container object covering the NR_FPAGES fpages  
    listed in FPAGES.  The object returned is locked and has one  
    reference.  */  
395  error_t  error_t
396  container_alloc (l4_word_t nr_fpages, l4_word_t *fpages,  container_alloc (l4_word_t nr_fpages, l4_word_t *fpages,
397                   container_t *r_container)                   struct container **r_container)
398  {  {
399    error_t err;    error_t err;
400    hurd_cap_obj_t obj;    hurd_cap_obj_t obj;
401    container_t container;    struct container *container;
402      l4_word_t start;
403      int i;
404    
405    err = hurd_cap_class_alloc (&container_class, &obj);    err = hurd_cap_class_alloc (&container_class, &obj);
406    if (err)    if (err)
407      return err;      return err;
408    
409    container = hurd_cap_obj_to_user (container_t, obj);    container = hurd_cap_obj_to_user (struct container *, obj);
410    assert (nr_fpages <= L4_FPAGE_SPAN_MAX);  
411    container->nr_fpages = nr_fpages;    hurd_btree_frame_entry_tree_init (&container->frame_entries);
412    memcpy (container->fpages, fpages, sizeof (l4_fpage_t) * nr_fpages);    start = l4_address (fpages[0]);
413      for (i = 0; i < nr_fpages; i ++)
414        {
415          struct frame_entry *fe = frame_entry_alloc ();
416          if (! fe)
417            return ENOMEM;
418    
419          err = frame_entry_new (container, fe,
420                                 l4_address (fpages[i]) - start,
421                                 l4_size (fpages[i]));
422          if (err)
423            {
424              frame_entry_dealloc (fe);
425              return err;
426            }
427    
428          fe->frame = frame_alloc (l4_size (fpages[i]));
429          if (! fe->frame)
430            {
431              frame_entry_drop (container, fe);
432              frame_entry_dealloc (fe);
433              return ENOMEM;
434            }
435    
436          frame_use (fe->frame, fe);
437    
438          fe->frame->memory = fpages[i];
439        }
440    
441    *r_container = container;    *r_container = container;
442    return 0;    return 0;
443  }  }
444    
445    
446    static void
447    container_reinit (hurd_cap_class_t cap_class, hurd_cap_obj_t obj)
448    {
449      struct container *container = hurd_cap_obj_to_user (struct container *,
450                                                          obj);
451      struct frame_entry *fe, *next;
452    
453      /* We don't need to lock the container as we know we are the only
454         ones who can now access it.  */
455      for (fe = hurd_btree_frame_entry_first (&container->frame_entries);
456           fe; fe = next)
457        {
458          next = hurd_btree_frame_entry_next (fe);
459          frame_entry_drop (container, fe);
460          frame_entry_dealloc (fe);
461        }
462      hurd_btree_frame_entry_tree_init (&container->frame_entries);
463    }
464    
465    
466    /* Initialize the container class subsystem.  */
467    error_t
468    container_class_init ()
469    {
470      return hurd_cap_class_init (&container_class, struct container *,
471                                  NULL, NULL, container_reinit, NULL,
472                                  container_demuxer);
473    }
474    

Legend:
Removed from v.1.11  
changed lines
  Added in v.1.12

savannah-hackers-public@gnu.org
ViewVC Help
Powered by ViewVC 1.1.26