Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * VMware VMCI Driver
0004  *
0005  * Copyright (C) 2012 VMware, Inc. All rights reserved.
0006  */
0007 
0008 #include <linux/vmw_vmci_defs.h>
0009 #include <linux/vmw_vmci_api.h>
0010 #include <linux/completion.h>
0011 #include <linux/hash.h>
0012 #include <linux/kernel.h>
0013 #include <linux/list.h>
0014 #include <linux/module.h>
0015 #include <linux/sched.h>
0016 #include <linux/slab.h>
0017 
0018 #include "vmci_datagram.h"
0019 #include "vmci_doorbell.h"
0020 #include "vmci_resource.h"
0021 #include "vmci_driver.h"
0022 #include "vmci_route.h"
0023 
0024 
0025 #define VMCI_DOORBELL_INDEX_BITS    6
0026 #define VMCI_DOORBELL_INDEX_TABLE_SIZE  (1 << VMCI_DOORBELL_INDEX_BITS)
0027 #define VMCI_DOORBELL_HASH(_idx)    hash_32(_idx, VMCI_DOORBELL_INDEX_BITS)
0028 
0029 /*
0030  * DoorbellEntry describes the a doorbell notification handle allocated by the
0031  * host.
0032  */
0033 struct dbell_entry {
0034     struct vmci_resource resource;
0035     struct hlist_node node;
0036     struct work_struct work;
0037     vmci_callback notify_cb;
0038     void *client_data;
0039     u32 idx;
0040     u32 priv_flags;
0041     bool run_delayed;
0042     atomic_t active;    /* Only used by guest personality */
0043 };
0044 
0045 /* The VMCI index table keeps track of currently registered doorbells. */
0046 struct dbell_index_table {
0047     spinlock_t lock;    /* Index table lock */
0048     struct hlist_head entries[VMCI_DOORBELL_INDEX_TABLE_SIZE];
0049 };
0050 
0051 static struct dbell_index_table vmci_doorbell_it = {
0052     .lock = __SPIN_LOCK_UNLOCKED(vmci_doorbell_it.lock),
0053 };
0054 
0055 /*
0056  * The max_notify_idx is one larger than the currently known bitmap index in
0057  * use, and is used to determine how much of the bitmap needs to be scanned.
0058  */
0059 static u32 max_notify_idx;
0060 
0061 /*
0062  * The notify_idx_count is used for determining whether there are free entries
0063  * within the bitmap (if notify_idx_count + 1 < max_notify_idx).
0064  */
0065 static u32 notify_idx_count;
0066 
0067 /*
0068  * The last_notify_idx_reserved is used to track the last index handed out - in
0069  * the case where multiple handles share a notification index, we hand out
0070  * indexes round robin based on last_notify_idx_reserved.
0071  */
0072 static u32 last_notify_idx_reserved;
0073 
0074 /* This is a one entry cache used to by the index allocation. */
0075 static u32 last_notify_idx_released = PAGE_SIZE;
0076 
0077 
0078 /*
0079  * Utility function that retrieves the privilege flags associated
0080  * with a given doorbell handle. For guest endpoints, the
0081  * privileges are determined by the context ID, but for host
0082  * endpoints privileges are associated with the complete
0083  * handle. Hypervisor endpoints are not yet supported.
0084  */
0085 int vmci_dbell_get_priv_flags(struct vmci_handle handle, u32 *priv_flags)
0086 {
0087     if (priv_flags == NULL || handle.context == VMCI_INVALID_ID)
0088         return VMCI_ERROR_INVALID_ARGS;
0089 
0090     if (handle.context == VMCI_HOST_CONTEXT_ID) {
0091         struct dbell_entry *entry;
0092         struct vmci_resource *resource;
0093 
0094         resource = vmci_resource_by_handle(handle,
0095                            VMCI_RESOURCE_TYPE_DOORBELL);
0096         if (!resource)
0097             return VMCI_ERROR_NOT_FOUND;
0098 
0099         entry = container_of(resource, struct dbell_entry, resource);
0100         *priv_flags = entry->priv_flags;
0101         vmci_resource_put(resource);
0102     } else if (handle.context == VMCI_HYPERVISOR_CONTEXT_ID) {
0103         /*
0104          * Hypervisor endpoints for notifications are not
0105          * supported (yet).
0106          */
0107         return VMCI_ERROR_INVALID_ARGS;
0108     } else {
0109         *priv_flags = vmci_context_get_priv_flags(handle.context);
0110     }
0111 
0112     return VMCI_SUCCESS;
0113 }
0114 
0115 /*
0116  * Find doorbell entry by bitmap index.
0117  */
0118 static struct dbell_entry *dbell_index_table_find(u32 idx)
0119 {
0120     u32 bucket = VMCI_DOORBELL_HASH(idx);
0121     struct dbell_entry *dbell;
0122 
0123     hlist_for_each_entry(dbell, &vmci_doorbell_it.entries[bucket],
0124                  node) {
0125         if (idx == dbell->idx)
0126             return dbell;
0127     }
0128 
0129     return NULL;
0130 }
0131 
0132 /*
0133  * Add the given entry to the index table.  This willi take a reference to the
0134  * entry's resource so that the entry is not deleted before it is removed from
0135  * the * table.
0136  */
0137 static void dbell_index_table_add(struct dbell_entry *entry)
0138 {
0139     u32 bucket;
0140     u32 new_notify_idx;
0141 
0142     vmci_resource_get(&entry->resource);
0143 
0144     spin_lock_bh(&vmci_doorbell_it.lock);
0145 
0146     /*
0147      * Below we try to allocate an index in the notification
0148      * bitmap with "not too much" sharing between resources. If we
0149      * use less that the full bitmap, we either add to the end if
0150      * there are no unused flags within the currently used area,
0151      * or we search for unused ones. If we use the full bitmap, we
0152      * allocate the index round robin.
0153      */
0154     if (max_notify_idx < PAGE_SIZE || notify_idx_count < PAGE_SIZE) {
0155         if (last_notify_idx_released < max_notify_idx &&
0156             !dbell_index_table_find(last_notify_idx_released)) {
0157             new_notify_idx = last_notify_idx_released;
0158             last_notify_idx_released = PAGE_SIZE;
0159         } else {
0160             bool reused = false;
0161             new_notify_idx = last_notify_idx_reserved;
0162             if (notify_idx_count + 1 < max_notify_idx) {
0163                 do {
0164                     if (!dbell_index_table_find
0165                         (new_notify_idx)) {
0166                         reused = true;
0167                         break;
0168                     }
0169                     new_notify_idx = (new_notify_idx + 1) %
0170                         max_notify_idx;
0171                 } while (new_notify_idx !=
0172                      last_notify_idx_released);
0173             }
0174             if (!reused) {
0175                 new_notify_idx = max_notify_idx;
0176                 max_notify_idx++;
0177             }
0178         }
0179     } else {
0180         new_notify_idx = (last_notify_idx_reserved + 1) % PAGE_SIZE;
0181     }
0182 
0183     last_notify_idx_reserved = new_notify_idx;
0184     notify_idx_count++;
0185 
0186     entry->idx = new_notify_idx;
0187     bucket = VMCI_DOORBELL_HASH(entry->idx);
0188     hlist_add_head(&entry->node, &vmci_doorbell_it.entries[bucket]);
0189 
0190     spin_unlock_bh(&vmci_doorbell_it.lock);
0191 }
0192 
0193 /*
0194  * Remove the given entry from the index table.  This will release() the
0195  * entry's resource.
0196  */
0197 static void dbell_index_table_remove(struct dbell_entry *entry)
0198 {
0199     spin_lock_bh(&vmci_doorbell_it.lock);
0200 
0201     hlist_del_init(&entry->node);
0202 
0203     notify_idx_count--;
0204     if (entry->idx == max_notify_idx - 1) {
0205         /*
0206          * If we delete an entry with the maximum known
0207          * notification index, we take the opportunity to
0208          * prune the current max. As there might be other
0209          * unused indices immediately below, we lower the
0210          * maximum until we hit an index in use.
0211          */
0212         while (max_notify_idx > 0 &&
0213                !dbell_index_table_find(max_notify_idx - 1))
0214             max_notify_idx--;
0215     }
0216 
0217     last_notify_idx_released = entry->idx;
0218 
0219     spin_unlock_bh(&vmci_doorbell_it.lock);
0220 
0221     vmci_resource_put(&entry->resource);
0222 }
0223 
0224 /*
0225  * Creates a link between the given doorbell handle and the given
0226  * index in the bitmap in the device backend. A notification state
0227  * is created in hypervisor.
0228  */
0229 static int dbell_link(struct vmci_handle handle, u32 notify_idx)
0230 {
0231     struct vmci_doorbell_link_msg link_msg;
0232 
0233     link_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
0234                         VMCI_DOORBELL_LINK);
0235     link_msg.hdr.src = VMCI_ANON_SRC_HANDLE;
0236     link_msg.hdr.payload_size = sizeof(link_msg) - VMCI_DG_HEADERSIZE;
0237     link_msg.handle = handle;
0238     link_msg.notify_idx = notify_idx;
0239 
0240     return vmci_send_datagram(&link_msg.hdr);
0241 }
0242 
0243 /*
0244  * Unlinks the given doorbell handle from an index in the bitmap in
0245  * the device backend. The notification state is destroyed in hypervisor.
0246  */
0247 static int dbell_unlink(struct vmci_handle handle)
0248 {
0249     struct vmci_doorbell_unlink_msg unlink_msg;
0250 
0251     unlink_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
0252                           VMCI_DOORBELL_UNLINK);
0253     unlink_msg.hdr.src = VMCI_ANON_SRC_HANDLE;
0254     unlink_msg.hdr.payload_size = sizeof(unlink_msg) - VMCI_DG_HEADERSIZE;
0255     unlink_msg.handle = handle;
0256 
0257     return vmci_send_datagram(&unlink_msg.hdr);
0258 }
0259 
0260 /*
0261  * Notify another guest or the host.  We send a datagram down to the
0262  * host via the hypervisor with the notification info.
0263  */
0264 static int dbell_notify_as_guest(struct vmci_handle handle, u32 priv_flags)
0265 {
0266     struct vmci_doorbell_notify_msg notify_msg;
0267 
0268     notify_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
0269                           VMCI_DOORBELL_NOTIFY);
0270     notify_msg.hdr.src = VMCI_ANON_SRC_HANDLE;
0271     notify_msg.hdr.payload_size = sizeof(notify_msg) - VMCI_DG_HEADERSIZE;
0272     notify_msg.handle = handle;
0273 
0274     return vmci_send_datagram(&notify_msg.hdr);
0275 }
0276 
0277 /*
0278  * Calls the specified callback in a delayed context.
0279  */
0280 static void dbell_delayed_dispatch(struct work_struct *work)
0281 {
0282     struct dbell_entry *entry = container_of(work,
0283                          struct dbell_entry, work);
0284 
0285     entry->notify_cb(entry->client_data);
0286     vmci_resource_put(&entry->resource);
0287 }
0288 
0289 /*
0290  * Dispatches a doorbell notification to the host context.
0291  */
0292 int vmci_dbell_host_context_notify(u32 src_cid, struct vmci_handle handle)
0293 {
0294     struct dbell_entry *entry;
0295     struct vmci_resource *resource;
0296 
0297     if (vmci_handle_is_invalid(handle)) {
0298         pr_devel("Notifying an invalid doorbell (handle=0x%x:0x%x)\n",
0299              handle.context, handle.resource);
0300         return VMCI_ERROR_INVALID_ARGS;
0301     }
0302 
0303     resource = vmci_resource_by_handle(handle,
0304                        VMCI_RESOURCE_TYPE_DOORBELL);
0305     if (!resource) {
0306         pr_devel("Notifying an unknown doorbell (handle=0x%x:0x%x)\n",
0307              handle.context, handle.resource);
0308         return VMCI_ERROR_NOT_FOUND;
0309     }
0310 
0311     entry = container_of(resource, struct dbell_entry, resource);
0312     if (entry->run_delayed) {
0313         if (!schedule_work(&entry->work))
0314             vmci_resource_put(resource);
0315     } else {
0316         entry->notify_cb(entry->client_data);
0317         vmci_resource_put(resource);
0318     }
0319 
0320     return VMCI_SUCCESS;
0321 }
0322 
0323 /*
0324  * Register the notification bitmap with the host.
0325  */
0326 bool vmci_dbell_register_notification_bitmap(u64 bitmap_ppn)
0327 {
0328     int result;
0329     struct vmci_notify_bm_set_msg bitmap_set_msg = { };
0330 
0331     bitmap_set_msg.hdr.dst = vmci_make_handle(VMCI_HYPERVISOR_CONTEXT_ID,
0332                           VMCI_SET_NOTIFY_BITMAP);
0333     bitmap_set_msg.hdr.src = VMCI_ANON_SRC_HANDLE;
0334     bitmap_set_msg.hdr.payload_size = sizeof(bitmap_set_msg) -
0335         VMCI_DG_HEADERSIZE;
0336     if (vmci_use_ppn64())
0337         bitmap_set_msg.bitmap_ppn64 = bitmap_ppn;
0338     else
0339         bitmap_set_msg.bitmap_ppn32 = (u32) bitmap_ppn;
0340 
0341     result = vmci_send_datagram(&bitmap_set_msg.hdr);
0342     if (result != VMCI_SUCCESS) {
0343         pr_devel("Failed to register (PPN=%llu) as notification bitmap (error=%d)\n",
0344              bitmap_ppn, result);
0345         return false;
0346     }
0347     return true;
0348 }
0349 
0350 /*
0351  * Executes or schedules the handlers for a given notify index.
0352  */
0353 static void dbell_fire_entries(u32 notify_idx)
0354 {
0355     u32 bucket = VMCI_DOORBELL_HASH(notify_idx);
0356     struct dbell_entry *dbell;
0357 
0358     spin_lock_bh(&vmci_doorbell_it.lock);
0359 
0360     hlist_for_each_entry(dbell, &vmci_doorbell_it.entries[bucket], node) {
0361         if (dbell->idx == notify_idx &&
0362             atomic_read(&dbell->active) == 1) {
0363             if (dbell->run_delayed) {
0364                 vmci_resource_get(&dbell->resource);
0365                 if (!schedule_work(&dbell->work))
0366                     vmci_resource_put(&dbell->resource);
0367             } else {
0368                 dbell->notify_cb(dbell->client_data);
0369             }
0370         }
0371     }
0372 
0373     spin_unlock_bh(&vmci_doorbell_it.lock);
0374 }
0375 
0376 /*
0377  * Scans the notification bitmap, collects pending notifications,
0378  * resets the bitmap and invokes appropriate callbacks.
0379  */
0380 void vmci_dbell_scan_notification_entries(u8 *bitmap)
0381 {
0382     u32 idx;
0383 
0384     for (idx = 0; idx < max_notify_idx; idx++) {
0385         if (bitmap[idx] & 0x1) {
0386             bitmap[idx] &= ~1;
0387             dbell_fire_entries(idx);
0388         }
0389     }
0390 }
0391 
0392 /*
0393  * vmci_doorbell_create() - Creates a doorbell
0394  * @handle:     A handle used to track the resource.  Can be invalid.
0395  * @flags:      Flag that determines context of callback.
0396  * @priv_flags: Privileges flags.
0397  * @notify_cb:  The callback to be ivoked when the doorbell fires.
0398  * @client_data:        A parameter to be passed to the callback.
0399  *
0400  * Creates a doorbell with the given callback. If the handle is
0401  * VMCI_INVALID_HANDLE, a free handle will be assigned, if
0402  * possible. The callback can be run immediately (potentially with
0403  * locks held - the default) or delayed (in a kernel thread) by
0404  * specifying the flag VMCI_FLAG_DELAYED_CB. If delayed execution
0405  * is selected, a given callback may not be run if the kernel is
0406  * unable to allocate memory for the delayed execution (highly
0407  * unlikely).
0408  */
0409 int vmci_doorbell_create(struct vmci_handle *handle,
0410              u32 flags,
0411              u32 priv_flags,
0412              vmci_callback notify_cb, void *client_data)
0413 {
0414     struct dbell_entry *entry;
0415     struct vmci_handle new_handle;
0416     int result;
0417 
0418     if (!handle || !notify_cb || flags & ~VMCI_FLAG_DELAYED_CB ||
0419         priv_flags & ~VMCI_PRIVILEGE_ALL_FLAGS)
0420         return VMCI_ERROR_INVALID_ARGS;
0421 
0422     entry = kmalloc(sizeof(*entry), GFP_KERNEL);
0423     if (entry == NULL) {
0424         pr_warn("Failed allocating memory for datagram entry\n");
0425         return VMCI_ERROR_NO_MEM;
0426     }
0427 
0428     if (vmci_handle_is_invalid(*handle)) {
0429         u32 context_id = vmci_get_context_id();
0430 
0431         if (context_id == VMCI_INVALID_ID) {
0432             pr_warn("Failed to get context ID\n");
0433             result = VMCI_ERROR_NO_RESOURCES;
0434             goto free_mem;
0435         }
0436 
0437         /* Let resource code allocate a free ID for us */
0438         new_handle = vmci_make_handle(context_id, VMCI_INVALID_ID);
0439     } else {
0440         bool valid_context = false;
0441 
0442         /*
0443          * Validate the handle.  We must do both of the checks below
0444          * because we can be acting as both a host and a guest at the
0445          * same time. We always allow the host context ID, since the
0446          * host functionality is in practice always there with the
0447          * unified driver.
0448          */
0449         if (handle->context == VMCI_HOST_CONTEXT_ID ||
0450             (vmci_guest_code_active() &&
0451              vmci_get_context_id() == handle->context)) {
0452             valid_context = true;
0453         }
0454 
0455         if (!valid_context || handle->resource == VMCI_INVALID_ID) {
0456             pr_devel("Invalid argument (handle=0x%x:0x%x)\n",
0457                  handle->context, handle->resource);
0458             result = VMCI_ERROR_INVALID_ARGS;
0459             goto free_mem;
0460         }
0461 
0462         new_handle = *handle;
0463     }
0464 
0465     entry->idx = 0;
0466     INIT_HLIST_NODE(&entry->node);
0467     entry->priv_flags = priv_flags;
0468     INIT_WORK(&entry->work, dbell_delayed_dispatch);
0469     entry->run_delayed = flags & VMCI_FLAG_DELAYED_CB;
0470     entry->notify_cb = notify_cb;
0471     entry->client_data = client_data;
0472     atomic_set(&entry->active, 0);
0473 
0474     result = vmci_resource_add(&entry->resource,
0475                    VMCI_RESOURCE_TYPE_DOORBELL,
0476                    new_handle);
0477     if (result != VMCI_SUCCESS) {
0478         pr_warn("Failed to add new resource (handle=0x%x:0x%x), error: %d\n",
0479             new_handle.context, new_handle.resource, result);
0480         goto free_mem;
0481     }
0482 
0483     new_handle = vmci_resource_handle(&entry->resource);
0484     if (vmci_guest_code_active()) {
0485         dbell_index_table_add(entry);
0486         result = dbell_link(new_handle, entry->idx);
0487         if (VMCI_SUCCESS != result)
0488             goto destroy_resource;
0489 
0490         atomic_set(&entry->active, 1);
0491     }
0492 
0493     *handle = new_handle;
0494 
0495     return result;
0496 
0497  destroy_resource:
0498     dbell_index_table_remove(entry);
0499     vmci_resource_remove(&entry->resource);
0500  free_mem:
0501     kfree(entry);
0502     return result;
0503 }
0504 EXPORT_SYMBOL_GPL(vmci_doorbell_create);
0505 
0506 /*
0507  * vmci_doorbell_destroy() - Destroy a doorbell.
0508  * @handle:     The handle tracking the resource.
0509  *
0510  * Destroys a doorbell previously created with vmcii_doorbell_create. This
0511  * operation may block waiting for a callback to finish.
0512  */
0513 int vmci_doorbell_destroy(struct vmci_handle handle)
0514 {
0515     struct dbell_entry *entry;
0516     struct vmci_resource *resource;
0517 
0518     if (vmci_handle_is_invalid(handle))
0519         return VMCI_ERROR_INVALID_ARGS;
0520 
0521     resource = vmci_resource_by_handle(handle,
0522                        VMCI_RESOURCE_TYPE_DOORBELL);
0523     if (!resource) {
0524         pr_devel("Failed to destroy doorbell (handle=0x%x:0x%x)\n",
0525              handle.context, handle.resource);
0526         return VMCI_ERROR_NOT_FOUND;
0527     }
0528 
0529     entry = container_of(resource, struct dbell_entry, resource);
0530 
0531     if (!hlist_unhashed(&entry->node)) {
0532         int result;
0533 
0534         dbell_index_table_remove(entry);
0535 
0536         result = dbell_unlink(handle);
0537         if (VMCI_SUCCESS != result) {
0538 
0539             /*
0540              * The only reason this should fail would be
0541              * an inconsistency between guest and
0542              * hypervisor state, where the guest believes
0543              * it has an active registration whereas the
0544              * hypervisor doesn't. One case where this may
0545              * happen is if a doorbell is unregistered
0546              * following a hibernation at a time where the
0547              * doorbell state hasn't been restored on the
0548              * hypervisor side yet. Since the handle has
0549              * now been removed in the guest, we just
0550              * print a warning and return success.
0551              */
0552             pr_devel("Unlink of doorbell (handle=0x%x:0x%x) unknown by hypervisor (error=%d)\n",
0553                  handle.context, handle.resource, result);
0554         }
0555     }
0556 
0557     /*
0558      * Now remove the resource from the table.  It might still be in use
0559      * after this, in a callback or still on the delayed work queue.
0560      */
0561     vmci_resource_put(&entry->resource);
0562     vmci_resource_remove(&entry->resource);
0563 
0564     kfree(entry);
0565 
0566     return VMCI_SUCCESS;
0567 }
0568 EXPORT_SYMBOL_GPL(vmci_doorbell_destroy);
0569 
0570 /*
0571  * vmci_doorbell_notify() - Ring the doorbell (and hide in the bushes).
0572  * @dst:        The handlle identifying the doorbell resource
0573  * @priv_flags: Priviledge flags.
0574  *
0575  * Generates a notification on the doorbell identified by the
0576  * handle. For host side generation of notifications, the caller
0577  * can specify what the privilege of the calling side is.
0578  */
0579 int vmci_doorbell_notify(struct vmci_handle dst, u32 priv_flags)
0580 {
0581     int retval;
0582     enum vmci_route route;
0583     struct vmci_handle src;
0584 
0585     if (vmci_handle_is_invalid(dst) ||
0586         (priv_flags & ~VMCI_PRIVILEGE_ALL_FLAGS))
0587         return VMCI_ERROR_INVALID_ARGS;
0588 
0589     src = VMCI_INVALID_HANDLE;
0590     retval = vmci_route(&src, &dst, false, &route);
0591     if (retval < VMCI_SUCCESS)
0592         return retval;
0593 
0594     if (VMCI_ROUTE_AS_HOST == route)
0595         return vmci_ctx_notify_dbell(VMCI_HOST_CONTEXT_ID,
0596                          dst, priv_flags);
0597 
0598     if (VMCI_ROUTE_AS_GUEST == route)
0599         return dbell_notify_as_guest(dst, priv_flags);
0600 
0601     pr_warn("Unknown route (%d) for doorbell\n", route);
0602     return VMCI_ERROR_DST_UNREACHABLE;
0603 }
0604 EXPORT_SYMBOL_GPL(vmci_doorbell_notify);