summaryrefslogtreecommitdiff
path: root/viengoos/cap-lookup.c
diff options
context:
space:
mode:
Diffstat (limited to 'viengoos/cap-lookup.c')
-rw-r--r--viengoos/cap-lookup.c324
1 files changed, 324 insertions, 0 deletions
diff --git a/viengoos/cap-lookup.c b/viengoos/cap-lookup.c
new file mode 100644
index 0000000..d80e701
--- /dev/null
+++ b/viengoos/cap-lookup.c
@@ -0,0 +1,324 @@
+/* cap-lookup.c - Address space walker.
+ Copyright (C) 2007 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 3 of the
+ License, 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 this program. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <hurd/cap.h>
+#include <hurd/folio.h>
+#include <hurd/stddef.h>
+#include <assert.h>
+
+#include "bits.h"
+
+#ifdef RM_INTERN
+#include "object.h"
+#endif
+
+union rt
+{
+ struct cap cap;
+ struct cap *capp;
+};
+
+enum lookup_mode
+ {
+ want_cap,
+ want_slot,
+ want_object
+ };
+
+static bool
+lookup (activity_t activity,
+ struct cap *root, addr_t address,
+ enum cap_type type, bool *writable,
+ enum lookup_mode mode, union rt *rt)
+{
+ struct cap *start = root;
+
+ l4_uint64_t addr = addr_prefix (address);
+ l4_word_t remaining = addr_depth (address);
+ /* The code below assumes that the REMAINING significant bits are in the
+ lower bits, not upper. */
+ addr >>= (ADDR_BITS - remaining);
+
+ struct cap fake_slot;
+
+ /* Assume the object is writable until proven otherwise. */
+ int w = true;
+
+ while (remaining > 0)
+ {
+ assert (CAP_TYPE_MIN <= root->type && root->type <= CAP_TYPE_MAX);
+
+ if (cap_is_a (root, cap_rcappage))
+ /* The page directory is read-only. Note the weakened access
+ appropriately. */
+ {
+ if (type != -1 && type != cap_rpage && type != cap_rcappage)
+ {
+ debug (1, "Read-only cappage at %llx/%d but %s requires "
+ "write access",
+ addr_prefix (addr_chop (address, remaining)),
+ addr_depth (address) - remaining,
+ cap_type_string (type));
+
+ /* Translating this capability does not provide write
+ access. The only objects that are useful without write
+ access are read-only pages and read-only capability
+ pages. If the user is not looking for one of those,
+ then bail. */
+ return false;
+ }
+
+ w = false;
+ }
+
+ if (CAP_GUARD_BITS (root))
+ /* Check that ADDR contains the guard. */
+ {
+ int gdepth = CAP_GUARD_BITS (root);
+
+ if (gdepth > remaining)
+ {
+ debug (1, "Translating %llx/%d; not enough bits (%d) to "
+ "translate %d-bit guard at /%d",
+ addr_prefix (address), addr_depth (address),
+ remaining, gdepth, ADDR_BITS - remaining);
+ return false;
+ }
+
+ int guard = extract_bits64_inv (addr, remaining - 1, gdepth);
+ if (CAP_GUARD (root) != guard)
+ {
+ debug (1, "Guard 0x%llx/%d does not match 0x%llx's "
+ "bits %d-%d => 0x%x",
+ CAP_GUARD (root), CAP_GUARD_BITS (root), addr,
+ remaining - gdepth, remaining - 1, guard);
+ return false;
+ }
+
+ remaining -= gdepth;
+ }
+
+ if (remaining == 0)
+ /* We've translate the guard bits and there are no bits left
+ to translate. We now designate the object and not the
+ slot, however, if we designate an object, we always return
+ the slot pointing to it. */
+ break;
+
+ switch (root->type)
+ {
+ case cap_cappage:
+ case cap_rcappage:
+ {
+ /* Index the page table. */
+ int bits = CAP_SUBPAGE_SIZE_LOG2 (root);
+ if (remaining < bits)
+ {
+ debug (1, "Translating " ADDR_FMT "; not enough bits (%d) "
+ "to index %d-bit cappage at " ADDR_FMT,
+ ADDR_PRINTF (address), remaining, bits,
+ ADDR_PRINTF (addr_chop (address, remaining)));
+ return false;
+ }
+
+ struct object *object = cap_to_object (activity, root);
+ if (! object)
+ {
+#ifdef RM_INTERN
+ debug (1, "Failed to get object with OID %llx",
+ root->oid);
+#endif
+ return false;
+ }
+
+ int offset = CAP_SUBPAGE_OFFSET (root)
+ + extract_bits64_inv (addr, remaining - 1, bits);
+ assert (0 <= offset && offset < CAPPAGE_SLOTS);
+ remaining -= bits;
+
+ root = &object->caps[offset];
+ break;
+ }
+
+ case cap_folio:
+ if (remaining < FOLIO_OBJECTS_LOG2)
+ {
+ debug (1, "Translating " ADDR_FMT "; not enough bits (%d) "
+ "to index folio at " ADDR_FMT,
+ ADDR_PRINTF (address), remaining,
+ ADDR_PRINTF (addr_chop (address, remaining)));
+ return false;
+ }
+
+ struct object *object = cap_to_object (activity, root);
+#ifdef RM_INTERN
+ if (! object)
+ {
+ debug (1, "Failed to get object with OID %llx",
+ root->oid);
+ return false;
+ }
+#else
+ assert (object);
+#endif
+
+ struct folio *folio = (struct folio *) object;
+
+ root = &fake_slot;
+
+ int i = extract_bits64_inv (addr, remaining - 1, FOLIO_OBJECTS_LOG2);
+ if (folio->objects[i].type == cap_void)
+ {
+ memset (root, 0, sizeof (*root));
+ root->type = cap_void;
+ }
+ else
+ {
+
+#ifdef RM_INTERN
+ struct object_desc *fdesc;
+ fdesc = object_to_object_desc (object);
+
+ object = object_find (activity, fdesc->oid + i + 1);
+ assert (object);
+ *root = object_to_cap (object);
+#else
+ root->addr_trans = CAP_ADDR_TRANS_VOID;
+ root->type = folio->objects[i].type;
+ cap_set_shadow (root, cap_get_shadow (&folio->objects[i]));
+#endif
+ }
+
+ remaining -= FOLIO_OBJECTS_LOG2;
+ break;
+
+ default:
+ /* We designate a non-address bit translating object but we
+ have no bits left to translate. */
+ debug (1, "Encountered a %s at %llx/%d, expected a cappage",
+ cap_type_string (root->type),
+ addr_prefix (addr_chop (address, remaining)),
+ addr_depth (address) - remaining);
+ return false;
+ }
+
+ if (remaining == 0)
+ /* We've indexed the object and have no bits remaining to
+ translate. */
+ {
+ if (CAP_GUARD_BITS (root) && mode == want_object)
+ /* The caller wants an object but we haven't translated
+ the slot's guard. */
+ {
+ debug (1, "Found slot at %llx/%d but referenced object "
+ "(%s) has an untranslated guard of %lld/%d!",
+ addr_prefix (address), addr_depth (address),
+ cap_type_string (root->type), CAP_GUARD (root),
+ CAP_GUARD_BITS (root));
+ return false;
+ }
+
+ break;
+ }
+ }
+ assert (remaining == 0);
+
+ if (! cap_is_a (root, type))
+ /* Types don't match. They may, however, be compatible. */
+ {
+ if (((cap_is_a (root, cap_rpage) || cap_is_a (root, cap_page))
+ && (type == cap_rpage || type == cap_page))
+ || ((cap_is_a (root, cap_rcappage) || cap_is_a (root, cap_cappage))
+ && (type == cap_rcappage || type == cap_cappage)))
+ /* Type are compatible. We just need to downgrade the
+ rights. */
+ w = false;
+ else if (type != -1)
+ /* Incompatible types. */
+ {
+ as_dump_from (activity, start, __func__);
+ debug (4, "Requested type %s but cap at 0x%llx/%d designates a %s",
+ cap_type_string (type),
+ addr_prefix (address), addr_depth (address),
+ cap_type_string (root->type));
+ return false;
+ }
+ }
+
+ if (cap_is_a (root, cap_rpage) || cap_is_a (root, cap_rcappage))
+ w = false;
+
+ if (writable)
+ *writable = w;
+
+ if (mode == want_slot)
+ {
+ if (root == &fake_slot)
+ {
+ debug (1, "%llx/%d resolves to a folio object but want a slot",
+ addr_prefix (address), addr_depth (address));
+ return false;
+ }
+ rt->capp = root;
+ return true;
+ }
+ else
+ {
+ rt->cap = *root;
+ return true;
+ }
+}
+
+struct cap
+cap_lookup_rel (activity_t activity,
+ struct cap *root, addr_t address,
+ enum cap_type type, bool *writable)
+{
+ union rt rt;
+
+ if (! lookup (activity, root, address, type, writable, want_cap, &rt))
+ return (struct cap) { .type = cap_void };
+ return rt.cap;
+}
+
+struct cap
+object_lookup_rel (activity_t activity,
+ struct cap *root, addr_t address,
+ enum cap_type type, bool *writable)
+{
+ union rt rt;
+
+ if (! lookup (activity, root, address, type, writable, want_object, &rt))
+ return (struct cap) { .type = cap_void };
+ return rt.cap;
+}
+
+struct cap *
+slot_lookup_rel (activity_t activity,
+ struct cap *root, addr_t address,
+ enum cap_type type, bool *writable)
+{
+ union rt rt;
+
+ if (! lookup (activity, root, address, type, writable, want_slot, &rt))
+ return NULL;
+ return rt.capp;
+}
+