123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532 |
- /*
- * Copyright (c) 2023 Agustina Arzille.
- *
- * This program 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.
- *
- * This program 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/>.
- *
- * Interfaces for capabilities.
- */
- #ifndef KERN_CAP_H
- #define KERN_CAP_H
- #include <assert.h>
- #include <stdint.h>
- #include <kern/hlist.h>
- #include <kern/init.h>
- #include <kern/ipc.h>
- #include <kern/list.h>
- #include <kern/pqueue.h>
- #include <kern/slist.h>
- #include <kern/spinlock.h>
- #include <kern/sref.h>
- #include <kern/user.h>
- struct task;
- struct thread;
- // Capability types.
- enum
- {
- CAP_TYPE_CHANNEL,
- CAP_TYPE_FLOW,
- CAP_TYPE_TASK,
- CAP_TYPE_THREAD,
- CAP_TYPE_KERNEL,
- CAP_TYPE_MAX,
- };
- // Size of an alert message, in bytes.
- #define CAP_ALERT_SIZE 16
- // Alert types.
- enum
- {
- CAP_ALERT_USER,
- CAP_ALERT_INTR,
- CAP_ALERT_THREAD_DIED,
- CAP_ALERT_TASK_DIED,
- CAP_ALERT_CHAN_CLOSED,
- };
- // Kernel-sent alert.
- struct cap_kern_alert
- {
- int type;
- union
- {
- struct
- {
- uint32_t irq;
- uint32_t count;
- } intr;
- int thread_id;
- int task_id;
- int any_id;
- uintptr_t tag;
- };
- };
- static_assert (sizeof (struct cap_kern_alert) <= CAP_ALERT_SIZE,
- "struct cap_kern_alert is too big");
- static_assert (OFFSETOF (struct cap_kern_alert, intr.irq) ==
- OFFSETOF (struct cap_kern_alert, thread_id) &&
- OFFSETOF (struct cap_kern_alert, thread_id) ==
- OFFSETOF (struct cap_kern_alert, task_id),
- "invalid layout for cap_kern_alert");
- struct cap_base
- {
- uintptr_t tflags;
- struct sref_counter sref;
- };
- // Kernel capabilities.
- enum
- {
- CAP_KERNEL_MEMORY, // Allows mapping physical memory.
- CAP_KERNEL_DEVICE, // Allows registering interrupts.
- CAP_KERNEL_MAX,
- };
- struct cap_thread_info
- {
- uint32_t size;
- struct futex_td *futex_td;
- void *thread_ptr;
- int signal;
- int pinned;
- };
- #define CAPABILITY struct cap_base base
- // Flags used in 'cap_flow_create'.
- #define CAP_FLOW_HANDLE_INTR 0x01 // Flow can handle interrupts.
- #define CAP_FLOW_EXT_PAGER 0x02 // Flow is an external pager.
- #define CAP_FLOW_PAGER_FLUSHES 0x04 // Pager needs to flush dirty pages.
- struct vm_object;
- struct vm_page;
- struct cap_flow
- {
- CAPABILITY;
- uintptr_t tag;
- uintptr_t entry;
- struct
- {
- struct spinlock lock;
- struct list receivers;
- struct hlist alloc;
- struct pqueue pending;
- } alerts;
- struct
- {
- struct cap_lpad *free_list;
- struct list waiters;
- struct spinlock lock;
- } lpads;
- };
- struct cap_channel
- {
- CAPABILITY;
- struct cap_flow *flow;
- uintptr_t tag;
- struct vm_object *vmobj;
- };
- struct cap_task
- {
- CAPABILITY;
- struct task *task;
- };
- struct cap_thread
- {
- CAPABILITY;
- struct thread *thread;
- };
- struct cap_kernel
- {
- CAPABILITY;
- int kind;
- };
- // Triplet of iterators.
- struct cap_iters
- {
- struct ipc_iov_iter iov;
- struct ipc_cap_iter cap;
- struct ipc_vme_iter vme;
- };
- struct bulletin;
- // Cast a capability to the base type.
- #define CAP_BASE(x) ((struct cap_base *)(x))
- #define CAP(x) \
- _Generic (x, \
- struct cap_kernel * : CAP_BASE (x), \
- struct cap_thread * : CAP_BASE (x), \
- struct cap_task * : CAP_BASE (x), \
- struct cap_channel *: CAP_BASE (x), \
- struct cap_flow * : CAP_BASE (x), \
- default: (x))
- // Flags for the read/clean page interfaces.
- #define CAP_PAGES_MORE 0x01 // There are more pages for the object.
- #define CAP_PAGES_ADV_SKIP 0x02 // Advance iovec if page is not dirty.
- struct cap_page_info
- {
- uint32_t size;
- uint32_t flags;
- uintptr_t tag;
- uint32_t offset_cnt;
- uint64_t *offsets;
- struct iovec *iovs;
- uint32_t iov_cnt;
- struct ipc_msg_vme vme;
- };
- // Get a capability's type.
- static inline uint32_t
- cap_type (const struct cap_base *cap)
- {
- return ((uint32_t)(cap->tflags >> (sizeof (uintptr_t) * 8 - 8)));
- }
- #define cap_type(cap) (cap_type)(CAP (cap))
- // Acquire or release a reference on a capability.
- static inline void
- cap_base_acq (struct cap_base *cap)
- {
- sref_counter_inc (&cap->sref);
- }
- static inline void
- cap_base_rel (struct cap_base *cap)
- {
- sref_counter_dec (&cap->sref);
- }
- #define cap_base_acq(cap) (cap_base_acq) (CAP (cap))
- #define cap_base_rel(cap) (cap_base_rel) (CAP (cap))
- // Flags for the 'cap_recv_alert' function.
- #define CAP_ALERT_NONBLOCK 0x01 // Don't block when sending an alert.
- /*
- * Intern a capability within the local space. Returns the new capability
- * index, or a negated errno value on error.
- */
- int cap_intern (struct cap_base *cap, uint32_t flags);
- #define cap_intern(cap, flags) (cap_intern) (CAP (cap), (flags))
- // Create a flow.
- int cap_flow_create (struct cap_flow **outp, uint32_t flags,
- uintptr_t tag, uintptr_t entry);
- // Create a channel for a flow.
- int cap_channel_create (struct cap_channel **outp, struct cap_flow *flow,
- uintptr_t tag);
- // Create a capability representing a task.
- int cap_task_create (struct cap_task **outp, struct task *task);
- // Create a capability representing a thread.
- int cap_thread_create (struct cap_thread **outp, struct thread *thread);
- // Get a capability's tag (Used for channels and flows).
- int cap_get_tag (const struct cap_base *cap, uintptr_t *tagp);
- #define cap_get_tag(cap, tagp) (cap_get_tag) (CAP (cap), (tagp))
- // Hook a channel to a remote flow in a task.
- int cap_flow_hook (struct cap_channel **outp, struct task *task, int cap_idx);
- // Send and receive iterator triplets to a capability.
- ssize_t cap_send_iters (struct cap_base *cap, struct cap_iters *in_it,
- struct cap_iters *out_it, struct ipc_msg_data *data,
- uint32_t xflags);
- // Reply to the current message with an iterator triplet or error value.
- ssize_t cap_reply_iters (struct cap_iters *it, int rv);
- // Pull an iterator triplet from the current message.
- ssize_t cap_pull_iters (struct cap_iters *it, struct ipc_msg_data *data);
- // Push an iterator triplet to the current message.
- ssize_t cap_push_iters (struct cap_iters *it, struct ipc_msg_data *data);
- // Receive an alert from a flow.
- int cap_recv_alert (struct cap_flow *flow, void *buf,
- uint32_t flags, struct ipc_msg_data *mdata);
- // Send an alert to a flow.
- int cap_send_alert (struct cap_base *cap, const void *buf,
- uint32_t flags, uint32_t prio);
- #define cap_send_alert(cap, buf, flags, prio) \
- (cap_send_alert) (CAP (cap), buf, flags, prio)
- // Add and remove a landing pad to/from a flow.
- int cap_flow_add_lpad (struct cap_flow *flow, void *stack, size_t size,
- struct ipc_msg *msg, struct ipc_msg_data *mdata,
- struct cap_thread_info *info);
- int cap_flow_rem_lpad (struct cap_flow *flow, uintptr_t stack, bool unmap);
- // Register a flow for interrupt handling.
- int cap_intr_register (struct cap_flow *flow, uint32_t irq);
- // Unregister a flow for interrupt handling.
- int cap_intr_unregister (struct cap_flow *flow, uint32_t irq);
- // Register a thread on a flow to notify on its death.
- int cap_thread_register (struct cap_flow *flow, struct thread *thread);
- // Register a task on a flow to notify on its death.
- int cap_task_register (struct cap_flow *flow, struct task *task);
- // Unregister a thread.
- int cap_thread_unregister (struct cap_flow *flow, struct thread *thread);
- // Unregister a task.
- int cap_task_unregister (struct cap_flow *flow, struct task *task);
- // Traverse a list of dead notifications.
- void cap_notify_dead (struct bulletin *bulletin);
- // Request pages from a channel.
- ssize_t cap_request_pages (struct cap_channel *chp, uint64_t off,
- uint32_t nr_pages, struct vm_page **pages);
- // Reply with pages to a channel.
- ssize_t cap_reply_pagereq (const uintptr_t *src, uint32_t cnt);
- /*
- * Get the VM object associated to a channel.
- *
- * The VM object is typically constructed when a mapping request is made,
- * such as for the 'mmap' system call. Note that once constructed and until
- * it's destroyed, the object will be the same.
- */
- struct vm_object* cap_channel_get_vmobj (struct cap_channel *ch);
- // Unreference a VM object obtained from a channel.
- void cap_channel_put_vmobj (struct cap_channel *chp);
- // Mark a channel as being shared.
- bool cap_channel_mark_shared (struct cap_base *cap);
- #define cap_iters_init_impl(it, buf, size, iov_init) \
- do \
- { \
- iov_init (&(it)->iov, (void *)(buf), size); \
- ipc_cap_iter_init (&(it)->cap, 0, 0); \
- ipc_vme_iter_init (&(it)->vme, 0, 0); \
- } \
- while (0)
- // Initialize a capability's iterators with a plain buffer and size.
- #define cap_iters_init_buf(it, buf, size) \
- cap_iters_init_impl (it, buf, size, ipc_iov_iter_init_buf)
- // Initialize a capability's iterators with a number of iovecs.
- #define cap_iters_init_iov(it, iovs, nr_iovs) \
- cap_iters_init_impl (it, iovs, nr_iovs, ipc_iov_iter_init)
- // Initialize a capability's iterators with a message structure.
- #define cap_iters_init_msg(it, msg) \
- do \
- { \
- ipc_iov_iter_init (&(it)->iov, (msg)->iovs, (msg)->iov_cnt); \
- ipc_cap_iter_init (&(it)->cap, (msg)->caps, (msg)->cap_cnt); \
- ipc_vme_iter_init (&(it)->vme, (msg)->vmes, (msg)->vme_cnt); \
- } \
- while (0)
- // Send raw bytes to a capability and receive the reply.
- static inline ssize_t
- cap_send_bytes (struct cap_base *cap, const void *src, size_t src_size,
- void *dst, size_t dst_size)
- {
- struct cap_iters in, out;
- cap_iters_init_buf (&in, src, src_size);
- cap_iters_init_buf (&out, dst, dst_size);
- return (cap_send_iters (cap, &in, &out, NULL, 0));
- }
- #define cap_send_bytes(cap, src, src_size, dst, dst_size) \
- (cap_send_bytes) (CAP (cap), (src), (src_size), (dst), (dst_size))
- // Send bytes in iovecs and receive the reply.
- static inline ssize_t
- cap_send_iov (struct cap_base *cap, const struct iovec *src, uint32_t nr_src,
- struct iovec *dst, uint32_t nr_dst)
- {
- if (!user_check_range (src, nr_src * sizeof (*src)) ||
- !user_check_range (dst, nr_dst * sizeof (*dst)))
- return (-EFAULT);
- struct cap_iters in, out;
- cap_iters_init_iov (&in, src, nr_src);
- cap_iters_init_iov (&out, dst, nr_dst);
- return (cap_send_iters (cap, &in, &out, NULL, 0));
- }
- #define cap_send_iov(cap, src, nr_src, dst, nr_dst) \
- (cap_send_iov) (CAP (cap), (src), (nr_src), (dst), (nr_dst))
- // Send and receive full messages and also the metadata.
- static inline ssize_t
- cap_send_msg (struct cap_base *cap, const struct ipc_msg *src,
- struct ipc_msg *dst, struct ipc_msg_data *data)
- {
- if (!user_check_struct (src, sizeof (*src)) ||
- !user_check_struct (dst, sizeof (*dst)))
- return (-EFAULT);
- struct cap_iters in, out;
- cap_iters_init_msg (&in, src);
- cap_iters_init_msg (&out, dst);
- return (cap_send_iters (cap, &in, &out, data, 0));
- }
- #define cap_send_msg(cap, src, dst, data) \
- (cap_send_msg) (CAP (cap), (src), (dst), (data))
- // Reply to the current message with raw bytes or an error.
- static inline int
- cap_reply_bytes (const void *src, size_t bytes, int err)
- {
- struct cap_iters it;
- cap_iters_init_buf (&it, src, bytes);
- return (cap_reply_iters (&it, err));
- }
- // Reply to the current message with bytes in iovecs or an error.
- static inline int
- cap_reply_iov (const struct iovec *iov, uint32_t nr_iov, int err)
- {
- if (!user_check_range (iov, nr_iov * sizeof (*iov)))
- return (-EFAULT);
- struct cap_iters it;
- cap_iters_init_iov (&it, iov, nr_iov);
- return (cap_reply_iters (&it, err));
- }
- // Reply to the current message with a full IPC message or an error.
- static inline int
- cap_reply_msg (const struct ipc_msg *msg, int err)
- {
- if (!user_check_struct (msg, sizeof (*msg)))
- return (-EFAULT);
- struct cap_iters it;
- cap_iters_init_msg (&it, msg);
- return (cap_reply_iters (&it, err));
- }
- // Pull raw bytes from the current message.
- static inline ssize_t
- cap_pull_bytes (void *dst, size_t bytes, struct ipc_msg_data *mdata)
- {
- struct cap_iters it;
- cap_iters_init_buf (&it, dst, bytes);
- return (cap_pull_iters (&it, mdata));
- }
- // Pull iovecs from the current message.
- static inline ssize_t
- cap_pull_iov (struct iovec *iovs, uint32_t nr_iovs, struct ipc_msg_data *mdata)
- {
- if (!user_check_range (iovs, nr_iovs * sizeof (*iovs)))
- return (-EFAULT);
- struct cap_iters it;
- cap_iters_init_iov (&it, iovs, nr_iovs);
- return (cap_pull_iters (&it, mdata));
- }
- // Pull an IPC message from the current message.
- static inline ssize_t
- cap_pull_msg (struct ipc_msg *msg, struct ipc_msg_data *mdata)
- {
- if (!user_check_struct (msg, sizeof (*msg)))
- return (-EFAULT);
- struct cap_iters it;
- cap_iters_init_msg (&it, msg);
- return (cap_pull_iters (&it, mdata));
- }
- // Push raw bytes into the current message.
- static inline ssize_t
- cap_push_bytes (const void *src, size_t bytes, struct ipc_msg_data *mdata)
- {
- struct cap_iters it;
- cap_iters_init_buf (&it, src, bytes);
- return (cap_push_iters (&it, mdata));
- }
- // Push iovecs into the current message.
- static inline ssize_t
- cap_push_iov (const struct iovec *iovs, uint32_t nr_iovs,
- struct ipc_msg_data *mdata)
- {
- if (!user_check_range (iovs, nr_iovs * sizeof (*iovs)))
- return (-EFAULT);
- struct cap_iters it;
- cap_iters_init_iov (&it, iovs, nr_iovs);
- return (cap_push_iters (&it, mdata));
- }
- // Push an IPC message to the current message.
- static inline ssize_t
- cap_push_msg (const struct ipc_msg *msg, struct ipc_msg_data *mdata)
- {
- if (!user_check_struct (msg, sizeof (*msg)))
- return (-EFAULT);
- struct cap_iters it;
- cap_iters_init_msg (&it, msg);
- return (cap_push_iters (&it, mdata));
- }
- /*
- * This init operation provides :
- * - capabilities fully operational.
- */
- INIT_OP_DECLARE (cap_setup);
- #endif
|