summaryrefslogtreecommitdiff
path: root/physmem/container.c
diff options
context:
space:
mode:
Diffstat (limited to 'physmem/container.c')
-rw-r--r--physmem/container.c718
1 files changed, 0 insertions, 718 deletions
diff --git a/physmem/container.c b/physmem/container.c
deleted file mode 100644
index 76a8d01..0000000
--- a/physmem/container.c
+++ /dev/null
@@ -1,718 +0,0 @@
-/* container.c - container class for physical memory server.
- Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
- Written by Neal H. Walfield <neal@gnu.org>.
-
- This file is part of the GNU Hurd.
-
- The GNU Hurd is free software; you can redistribute it and/or
- modify it under the terms of the GNU General Public License as
- published by the Free Software Foundation; either version 2, or (at
- your option) any later version.
-
- The GNU Hurd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with the GNU Hurd; see the file COPYING. If not, write to
- the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139,
- USA. */
-
-#if HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <pthread.h>
-#include <compiler.h>
-#include <l4.h>
-
-#include <hurd/cap-server.h>
-#include <hurd/btree.h>
-
-#include "priv.h"
-#include "physmem.h"
-#include "zalloc.h"
-
-#include "output.h"
-
-
-static struct hurd_cap_class container_class;
-
-static inline void
-container_dump (struct container *cont)
-{
- struct frame_entry *fe;
-
- printf ("Container %x: ", cont);
- for (fe = hurd_btree_frame_entry_first (&cont->frame_entries); fe;
- fe = hurd_btree_frame_entry_next (fe))
- printf ("fe:%x %x+%x@%x on %x:%x+%x ",
- fe, fe->region.start, fe->region.size, fe->frame_offset,
- fe->frame, l4_address (fe->frame->memory),
- l4_size (fe->frame->memory));
- printf ("\n");
-}
-
-error_t
-container_attach (struct container *cont, struct frame_entry *frame_entry)
-{
- error_t err;
-
- assert (pthread_mutex_trylock (&cont->lock) == EBUSY);
-
- err = hurd_btree_frame_entry_insert (&cont->frame_entries, frame_entry);
- if (! err)
- frame_entry->container = cont;
-
- return err;
-}
-
-void
-container_detach (struct container *cont, struct frame_entry *frame_entry)
-{
- assert (pthread_mutex_trylock (&cont->lock) == EBUSY);
- assert (hurd_btree_frame_entry_find (&cont->frame_entries,
- &frame_entry->region));
- assert (cont == frame_entry->container);
-
- hurd_btree_frame_entry_detach (&cont->frame_entries, frame_entry);
-}
-
-/* CTX->obj should be a memory control object, not a container. */
-static error_t
-container_create (hurd_cap_rpc_context_t ctx)
-{
- error_t err;
- hurd_cap_obj_t obj;
- hurd_cap_handle_t handle;
-
- l4_msg_clear (ctx->msg);
-
- err = hurd_cap_class_alloc (&container_class, &obj);
- if (err)
- return err;
- hurd_cap_obj_unlock (obj);
-
- err = hurd_cap_bucket_inject (ctx->bucket, obj, ctx->sender, &handle);
- if (err)
- {
- hurd_cap_obj_lock (obj);
- hurd_cap_obj_drop (obj);
- return err;
- }
-
- /* The reply message consists of a single word, a capability handle
- which the client can use to refer to the container. */
-
- l4_msg_append_word (ctx->msg, handle);
-
- return 0;
-}
-
-static error_t
-container_share (hurd_cap_rpc_context_t ctx)
-{
- return EOPNOTSUPP;
-}
-
-static error_t
-container_allocate (hurd_cap_rpc_context_t ctx)
-{
- error_t err;
- struct container *cont = hurd_cap_obj_to_user (struct container *, ctx->obj);
- l4_word_t flags = l4_msg_word (ctx->msg, 1);
- uintptr_t start = l4_msg_word (ctx->msg, 2);
- size_t size = l4_msg_word (ctx->msg, 3);
- size_t amount;
- int i;
-
- /* We require three arguments (in addition to the cap id): the
- flags, the start and the size. */
- if (l4_untyped_words (l4_msg_msg_tag (ctx->msg)) != 4)
- {
- debug ("incorrect number of arguments passed. require 4 but got %d\n",
- l4_untyped_words (l4_msg_msg_tag (ctx->msg)));
- l4_msg_clear (ctx->msg);
- return EINVAL;
- }
-
- /* Allocate the memory. */
- l4_fpage_t fpages[L4_FPAGE_SPAN_MAX];
- int nr_fpages = l4_fpage_span (0, size - 1, fpages);
-
- pthread_mutex_lock (&cont->lock);
-
- for (err = 0, amount = 0, i = 0; i < nr_fpages; i ++)
- {
- /* FIXME: Check to make sure that the memory control object that
- this container refers to has enough memory to do each
- allocation. */
- struct frame_entry *fe = frame_entry_alloc ();
- assert (fe);
-
- err = frame_entry_create (cont, fe, start + l4_address (fpages[i]),
- l4_size (fpages[i]));
- if (err)
- {
- frame_entry_free (fe);
- break;
- }
-
- amount += l4_size (fpages[i]);
-
- /* XXX: Use the flags.
- frame->flags = flags; */
-
- pthread_mutex_unlock (&fe->frame->lock);
- }
-
- pthread_mutex_unlock (&cont->lock);
-
- l4_msg_clear (ctx->msg);
- l4_msg_append_word (ctx->msg, amount);
-
- return err;
-}
-
-static error_t
-container_deallocate (hurd_cap_rpc_context_t ctx)
-{
- error_t err = 0;
- struct container *cont = hurd_cap_obj_to_user (struct container *, ctx->obj);
- uintptr_t start = l4_msg_word (ctx->msg, 1);
- const size_t size = l4_msg_word (ctx->msg, 2);
- size_t remaining = size;
-
- /* We require two arguments (in addition to the cap id): the start
- and the size. */
- if (l4_untyped_words (l4_msg_msg_tag (ctx->msg)) != 3)
- {
- debug ("incorrect number of arguments passed. require 3 but got %d\n",
- l4_untyped_words (l4_msg_msg_tag (ctx->msg)));
- l4_msg_clear (ctx->msg);
- return EINVAL;
- }
-
- l4_msg_clear (ctx->msg);
-
- pthread_mutex_lock (&cont->lock);
-
- if ((size & (L4_MIN_PAGE_SIZE - 1)) != 0)
- {
- err = EINVAL;
- goto out;
- }
-
- struct frame_entry *next = frame_entry_find (cont, start, 1);
- if (! next)
- goto out;
-
- if (((start - next->region.start) & (L4_MIN_PAGE_SIZE - 1)) != 0)
- {
- err = EINVAL;
- goto out;
- }
-
- while (next && remaining > 0)
- {
- struct frame_entry *fe = next;
-
- /* We must get the region after FE before we potentially
- deallocate FE. */
- if (fe->region.start + fe->region.size < start + remaining)
- /* The region to deallocate extends beyond FE. */
- {
- next = hurd_btree_frame_entry_next (fe);
- if (next && fe->region.start + fe->region.size != next->region.start)
- /* NEXT does not immediately follow FE. */
- next = 0;
- }
- else
- /* FE is the last frame entry to process. */
- next = 0;
-
- /* The number of bytes to deallocate in this frame entry. */
- size_t length = fe->region.size - (start - fe->region.start);
- if (length > remaining)
- length = remaining;
- assert (length > 0);
-
- pthread_mutex_lock (&fe->frame->lock);
- err = frame_entry_deallocate (cont, fe, start, length);
- if (err)
- goto out;
-
- start += length;
- remaining -= length;
- }
-
- out:
- pthread_mutex_unlock (&cont->lock);
-
- if (remaining > 0)
- debug ("no frame entry at %x (of container %x) but %x bytes "
- "left to deallocate!\n", start, cont, remaining);
-
- /* Return the amount actually deallocated. */
- l4_msg_append_word (ctx->msg, size - remaining);
-
- return err;
-}
-
-static error_t
-container_map (hurd_cap_rpc_context_t ctx)
-{
- error_t err = 0;
- struct container *cont = hurd_cap_obj_to_user (struct container *, ctx->obj);
- l4_word_t flags = l4_msg_word (ctx->msg, 1);
- uintptr_t vaddr = l4_msg_word (ctx->msg, 2);
- uintptr_t index = l4_msg_word (ctx->msg, 3);
- size_t size = l4_msg_word (ctx->msg, 4);
-
- /* We require four arguments (in addition to the cap id). */
- if (l4_untyped_words (l4_msg_msg_tag (ctx->msg)) != 5)
- {
- debug ("incorrect number of arguments passed. require 5 but got %d\n",
- l4_untyped_words (l4_msg_msg_tag (ctx->msg)));
- l4_msg_clear (ctx->msg);
- return EINVAL;
- }
-
- l4_msg_clear (ctx->msg);
-
-#if 0
- printf ("container_map (index:%x, size:%x, vaddr:%x, flags: %x)\n",
- index, size, vaddr, flags);
-#endif
-
- /* SIZE must be a multiple of the minimum page size and VADDR must
- be aligned on a base page boundary. */
- if ((size & (L4_MIN_PAGE_SIZE - 1)) != 0
- || (vaddr & (L4_MIN_PAGE_SIZE - 1)) != 0)
- return EINVAL;
-
- pthread_mutex_lock (&cont->lock);
-
- struct frame_entry *fe;
- for (fe = frame_entry_find (cont, index, 1);
- fe && size > 0;
- fe = hurd_btree_frame_entry_next (fe))
- {
- if (index < fe->region.start)
- /* Hole between last frame and this one. */
- {
- err = EINVAL;
- break;
- }
-
- uintptr_t offset = index - fe->region.start;
- if ((offset & (getpagesize () - 1)))
- /* Not properly aligned. */
- {
- err = EINVAL;
- break;
- }
-
- size_t len = fe->region.size - offset;
- if (len > size)
- len = size;
-
- size_t amount;
-
- pthread_mutex_lock (&fe->frame->lock);
- err = frame_entry_map (fe, offset, len, extract_access (flags), vaddr,
- ctx->msg, &amount);
- pthread_mutex_unlock (&fe->frame->lock);
-
- assert (! err || err == ENOSPC);
-
- index += amount;
- size -= amount;
- vaddr += amount;
-
- if (err == ENOSPC)
- {
- err = 0;
- break;
- }
- }
-
- pthread_mutex_unlock (&cont->lock);
-
- return err;
-}
-
-static error_t
-container_copy (hurd_cap_rpc_context_t ctx)
-{
- error_t err = 0;
- struct hurd_cap_ctx_cap_use *cap_use;
- struct container *src_cont = hurd_cap_obj_to_user (struct container *,
- ctx->obj);
-
- /* SRC_START will move as we copy data; SRC_START_ORIG stays
- constant so that we can figure out how much we have copied. */
- uintptr_t src_start = l4_msg_word (ctx->msg, 1);
- const uintptr_t src_start_orig = src_start;
-
- l4_word_t dest_cont_handle = l4_msg_word (ctx->msg, 2);
- hurd_cap_obj_t dest_cap;
- struct container *dest_cont;
-
- uintptr_t dest_start = l4_msg_word (ctx->msg, 3);
-
- size_t count = l4_msg_word (ctx->msg, 4);
- size_t flags = l4_msg_word (ctx->msg, 5);
-
- struct frame_entry *sfe_next;
- int nr_fpages;
- l4_fpage_t fpages[L4_FPAGE_SPAN_MAX];
- int i;
-
- /* We require five arguments (in addition to the cap id). */
- if (l4_untyped_words (l4_msg_msg_tag (ctx->msg)) != 6)
- {
- debug ("incorrect number of arguments passed. require 6 but got %d\n",
- l4_untyped_words (l4_msg_msg_tag (ctx->msg)));
- l4_msg_clear (ctx->msg);
- return EINVAL;
- }
-
- l4_msg_clear (ctx->msg);
-
- if (ctx->handle == dest_cont_handle)
- /* The source container is the same as the destination
- container. */
- {
- dest_cont = src_cont;
- pthread_mutex_lock (&src_cont->lock);
- }
- else
- /* Look up the destination container. */
- {
- cap_use = alloca (hurd_cap_ctx_size ());
- err = hurd_cap_ctx_start_cap_use (ctx,
- dest_cont_handle, &container_class,
- cap_use, &dest_cap);
- if (err)
- goto out;
-
- hurd_cap_obj_unlock (dest_cap);
-
- dest_cont = hurd_cap_obj_to_user (struct container *, dest_cap);
-
- /* There is a possible dead lock scenario here: one thread
- copies from SRC to DEST and another from DEST to SRC. We
- lock based on the lexical order of the container
- pointers. */
- if (src_cont < dest_cont)
- {
- pthread_mutex_lock (&src_cont->lock);
- pthread_mutex_lock (&dest_cont->lock);
- }
- else
- {
- pthread_mutex_lock (&dest_cont->lock);
- pthread_mutex_lock (&src_cont->lock);
- }
- }
-
- if ((flags & HURD_PM_CONT_ALL_OR_NONE))
- /* Don't accept a partial copy. */
- {
- /* XXX: Make sure that all of the source is defined and has
- enough permission. */
-
- /* Check that no frames are located in the destination
- region. */
- struct frame_entry *fe = frame_entry_find (dest_cont, dest_start,
- count);
- if (fe)
- {
- err = EEXIST;
- goto clean_up;
- }
- }
-
- /* Find the frame entry in the source container which contains the
- start of the region to copy. */
- sfe_next = frame_entry_find (src_cont, src_start, 1);
- if (! sfe_next)
- {
- err = ENOENT;
- goto clean_up;
- }
-
- /* Make sure that SRC_START is aligned on a frame boundary. */
- if (((sfe_next->region.start - src_start) & (L4_MIN_PAGE_SIZE - 1)) != 0)
- {
- err = EINVAL;
- goto clean_up;
- }
-
- while (sfe_next && count)
- {
- struct frame_entry *sfe, *dfe;
- uintptr_t src_end;
-
- sfe = sfe_next;
-
- /* Does the source frame entry cover all of the memory that we
- need to copy? */
- if (src_start + count > sfe->region.start + sfe->region.size)
- /* No. We will have to read the following frame as well. */
- {
- src_end = sfe->region.start + sfe->region.size - 1;
-
- /* Get the next frame entry. */
- sfe_next = hurd_btree_frame_entry_next (sfe);
- if (sfe_next && sfe_next->region.start != src_end + 1)
- /* There is a gap between SFE and the next frame
- entry. */
- sfe_next = NULL;
- }
- else
- /* The end of the region to copy is contained within SFE. */
- {
- src_end = src_start + count - 1;
-
- /* Once we process this frame entry, we will be done. */
- sfe_next = NULL;
- }
-
- pthread_mutex_lock (&sfe->frame->lock);
-
- /* Get the frames we'll have in the destination container. */
- nr_fpages
- = l4_fpage_span (src_start - sfe->region.start + sfe->frame_offset,
- src_end - sfe->region.start + sfe->frame_offset,
- fpages);
- assert (nr_fpages > 0);
-
- for (i = 0; i < nr_fpages; i ++)
- {
- dfe = frame_entry_alloc ();
- if (! dfe)
- {
- pthread_mutex_unlock (&sfe->frame->lock);
- err = ENOMEM;
- goto clean_up;
- }
-
- /* XXX: We need to check the user's quota. */
- err = frame_entry_copy (dest_cont, dfe,
- dest_start, l4_size (fpages[i]),
- sfe,
- sfe->frame_offset
- + src_start - sfe->region.start,
- flags & HURD_PM_CONT_COPY_SHARED);
- if (err)
- {
- pthread_mutex_unlock (&sfe->frame->lock);
- frame_entry_free (dfe);
- goto clean_up;
- }
-
- src_start += l4_size (fpages[i]);
- dest_start += l4_size (fpages[i]);
- count -= l4_size (fpages[i]);
- }
-
- if (! (flags & HURD_PM_CONT_COPY_SHARED)
- && (sfe->frame->may_be_mapped & HURD_PM_CONT_WRITE))
- /* We just created a COW copy of SFE->FRAME and we have given
- out at least one map with write access. Revoke any write
- access to the frame. */
- {
- l4_fpage_t fpage = sfe->frame->memory;
- l4_set_rights (&fpage, L4_FPAGE_WRITABLE);
- l4_unmap_fpage (fpage);
- sfe->frame->may_be_mapped &= L4_FPAGE_EXECUTABLE|L4_FPAGE_READABLE;
- }
-
- pthread_mutex_unlock (&sfe->frame->lock);
- }
-
- if (count > 0)
- {
- assert (! sfe_next);
- err = ESRCH;
- }
-
- clean_up:
- assert (count == 0 || err);
-
- if (dest_cont == src_cont)
- /* If the source and destination are the same then don't unlock
- the same lock twice. */
- pthread_mutex_unlock (&src_cont->lock);
- else
- {
- /* Unlike with locking, the unlock order doesn't matter. */
- pthread_mutex_unlock (&src_cont->lock);
- pthread_mutex_unlock (&dest_cont->lock);
-
- hurd_cap_obj_lock (dest_cap);
- hurd_cap_ctx_end_cap_use (ctx, cap_use);
- }
-
- out:
- /* Return the amount actually copied. */
- l4_msg_append_word (ctx->msg, src_start - src_start_orig);
- return err;
-}
-
-error_t
-container_demuxer (hurd_cap_rpc_context_t ctx)
-{
- error_t err = 0;
-
- switch (l4_msg_label (ctx->msg))
- {
- case hurd_pm_container_create_id:
- err = container_create (ctx);
- break;
-
- case hurd_pm_container_share_id:
- err = container_share (ctx);
- break;
-
- case hurd_pm_container_allocate_id:
- err = container_allocate (ctx);
- break;
-
- case hurd_pm_container_deallocate_id:
- err = container_deallocate (ctx);
- break;
-
- case 128: /* The old container map implementation. */
- case hurd_pm_container_map_id:
- err = container_map (ctx);
- break;
-
- case hurd_pm_container_copy_id:
- err = container_copy (ctx);
- break;
-
- default:
- err = EOPNOTSUPP;
- }
-
- /* If the stub returns EOPNOTSUPP then we clear the message buffer,
- otherwise we assume that the message buffer contains a valid
- reply message and in which case we set the error code returned by
- the stub and have the demuxer succeed. */
- if (EXPECT_FALSE (err == EOPNOTSUPP))
- l4_msg_clear (ctx->msg);
-
- l4_set_msg_label (ctx->msg, err);
-
- if (err)
- debug ("%s: Returning %d to %x\n", __FUNCTION__, err, ctx->from);
-
- return 0;
-}
-
-error_t
-container_alloc (l4_word_t nr_fpages, l4_word_t *fpages,
- struct container **r_cont)
-{
- error_t err;
- hurd_cap_obj_t obj;
- struct container *cont;
- l4_word_t start;
- int i;
-
- err = hurd_cap_class_alloc (&container_class, &obj);
- if (err)
- return err;
-
- cont = hurd_cap_obj_to_user (struct container *, obj);
-
-#ifndef NDEBUG
- /* We just allocated CONT and we haven't given it to anyone else,
- however, frame_entry_create requires that CONT be locked and if
- it isn't, will trigger an assert. Make it happy. */
- pthread_mutex_lock (&cont->lock);
-#endif
-
- hurd_btree_frame_entry_tree_init (&cont->frame_entries);
- start = l4_address (fpages[0]);
- for (i = 0; i < nr_fpages; i ++)
- {
- struct frame_entry *fe = frame_entry_alloc ();
- if (! fe)
- {
- err = ENOMEM;
- break;
- }
-
- err = frame_entry_create (cont, fe,
- l4_address (fpages[i]) - start,
- l4_size (fpages[i]));
- if (err)
- {
- frame_entry_free (fe);
- break;
- }
-
- fe->frame->memory = fpages[i];
- pthread_mutex_unlock (&fe->frame->lock);
- }
-
-#ifndef NDEBUG
- pthread_mutex_unlock (&cont->lock);
-#endif
-
- if (! err)
- *r_cont = cont;
- return err;
-}
-
-
-/* Initialize a new container object. */
-static error_t
-container_init (hurd_cap_class_t cap_class, hurd_cap_obj_t obj)
-{
- struct container *cont = hurd_cap_obj_to_user (struct container *, obj);
-
- pthread_mutex_init (&cont->lock, 0);
- hurd_btree_frame_entry_tree_init (&cont->frame_entries);
-
- return 0;
-}
-
-/* Reinitialize a container object. */
-static void
-container_reinit (hurd_cap_class_t cap_class, hurd_cap_obj_t obj)
-{
- struct container *cont = hurd_cap_obj_to_user (struct container *, obj);
- struct frame_entry *fe, *next;
-
- assert (pthread_mutex_trylock (&cont->lock));
- pthread_mutex_unlock (&cont->lock);
-
- for (fe = hurd_btree_frame_entry_first (&cont->frame_entries);
- fe; fe = next)
- {
- next = hurd_btree_frame_entry_next (fe);
- pthread_mutex_lock (&fe->frame->lock);
- frame_entry_destroy (cont, fe, true);
- frame_entry_free (fe);
- }
-
- hurd_btree_frame_entry_tree_init (&cont->frame_entries);
-}
-
-/* Initialize the container class subsystem. */
-error_t
-container_class_init ()
-{
- return hurd_cap_class_init (&container_class, struct container *,
- container_init, NULL, container_reinit, NULL,
- container_demuxer);
-}