lib: trusty: Add `HSET_DEL_GET_COOKIE`

Adds a handle set operation that deletes the matching member
handle, and returns its cookie.

Test: aosp/3506455
Bug: 382291660
Change-Id: If0da8d830768218b9264cf2491c3b68ab0932ae0
diff --git a/lib/trusty/include/lib/trusty/handle_set.h b/lib/trusty/include/lib/trusty/handle_set.h
index c192170..9836a9b 100644
--- a/lib/trusty/include/lib/trusty/handle_set.h
+++ b/lib/trusty/include/lib/trusty/handle_set.h
@@ -29,6 +29,7 @@
 #define HSET_ADD 0
 #define HSET_DEL 1
 #define HSET_MOD 2
+#define HSET_DEL_GET_COOKIE 3
 
 __BEGIN_CDECLS
 
diff --git a/lib/trusty/uctx.c b/lib/trusty/uctx.c
index d9c6716..b3a775f 100644
--- a/lib/trusty/uctx.c
+++ b/lib/trusty/uctx.c
@@ -711,7 +711,9 @@
                             item->ref_list.prev);
 }
 
-static int _hset_del_item(struct handle* hset, struct htbl_entry* item) {
+static int _hset_del_item(struct handle* hset,
+                          struct htbl_entry* item,
+                          struct uevent* uevent) {
     uint del_cnt = 0;
     struct handle_ref* ref;
     struct handle_ref* tmp;
@@ -721,6 +723,9 @@
         if (ref->parent == hset) {
             del_cnt++;
             LTRACEF("%p: %p\n", ref->parent, ref->handle);
+            if (uevent) {
+                uevent->cookie = (user_addr_t)(uintptr_t)ref->cookie;
+            }
             list_delete(&ref->uctx_node);
             handle_set_detach_ref(ref);
             handle_decref(ref->handle);
@@ -750,37 +755,42 @@
 }
 
 static int _hset_ctrl_locked(handle_id_t hset_id,
-                             handle_id_t h_id,
                              uint32_t cmd,
-                             uint32_t event,
-                             void* cookie) {
+                             struct uevent* uevent) {
     int ret;
     int h_idx, hset_idx;
     struct uctx* ctx = current_uctx();
 
-    LTRACEF("%d: %d: cmd=%d\n", hset_id, h_id, cmd);
+    LTRACEF("%d: %d: cmd=%d\n", hset_id, uevent->handle, cmd);
 
     hset_idx = _check_handle_id(ctx, hset_id);
     if (hset_idx < 0)
         return hset_idx;
 
-    h_idx = _check_handle_id(ctx, h_id);
+    h_idx = _check_handle_id(ctx, uevent->handle);
     if (h_idx < 0)
         return h_idx;
 
     switch (cmd) {
     case HSET_ADD:
         ret = _hset_add_item(ctx->htbl[hset_idx].handle, &ctx->htbl[h_idx],
-                             h_id, event, cookie);
+                             uevent->handle, uevent->event,
+                             (void*)(uintptr_t)uevent->cookie);
         break;
 
     case HSET_DEL:
-        ret = _hset_del_item(ctx->htbl[hset_idx].handle, &ctx->htbl[h_idx]);
+        ret = _hset_del_item(ctx->htbl[hset_idx].handle, &ctx->htbl[h_idx],
+                             NULL);
+        break;
+
+    case HSET_DEL_GET_COOKIE:
+        ret = _hset_del_item(ctx->htbl[hset_idx].handle, &ctx->htbl[h_idx],
+                             uevent);
         break;
 
     case HSET_MOD:
         ret = _hset_mod_item(ctx->htbl[hset_idx].handle, &ctx->htbl[h_idx],
-                             event, cookie);
+                             uevent->event, (void*)(uintptr_t)uevent->cookie);
         break;
 
     default:
@@ -803,9 +813,12 @@
         return ret;
 
     mutex_acquire(&ctx->mlock);
-    ret = _hset_ctrl_locked(hset_id, uevent.handle, cmd, uevent.event,
-                            (void*)(uintptr_t)uevent.cookie);
+    ret = _hset_ctrl_locked(hset_id, cmd, &uevent);
     mutex_release(&ctx->mlock);
+    if (ret < 0)
+        return ret;
+    if (cmd == HSET_DEL_GET_COOKIE)
+        ret = copy_to_user(user_event, &uevent, sizeof(uevent));
     return ret;
 }