1 // © 2022 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4
5 #include <assert.h>
6 #include <hyptypes.h>
7
8 #include <atomic.h>
9 #include <gpt.h>
10 #include <object.h>
11 #include <spinlock.h>
12 #include <util.h>
13 #include <vdevice.h>
14
15 #include "event_handlers.h"
16
17 error_t
vdevice_attach_phys(vdevice_t * vdevice,memextent_t * memextent)18 vdevice_attach_phys(vdevice_t *vdevice, memextent_t *memextent)
19 {
20 assert(vdevice != NULL);
21 assert(memextent != NULL);
22 assert(vdevice->type != VDEVICE_TYPE_NONE);
23
24 vdevice_t *null_vdevice = NULL;
25 return atomic_compare_exchange_strong_explicit(&memextent->vdevice,
26 &null_vdevice, vdevice,
27 memory_order_release,
28 memory_order_release)
29 ? OK
30 : ERROR_BUSY;
31 }
32
33 void
vdevice_detach_phys(vdevice_t * vdevice,memextent_t * memextent)34 vdevice_detach_phys(vdevice_t *vdevice, memextent_t *memextent)
35 {
36 vdevice_t *old_vdevice = atomic_exchange_explicit(
37 &memextent->vdevice, NULL, memory_order_relaxed);
38 assert(old_vdevice == vdevice);
39 }
40
41 bool
vdevice_handle_gpt_values_equal(gpt_type_t type,gpt_value_t x,gpt_value_t y)42 vdevice_handle_gpt_values_equal(gpt_type_t type, gpt_value_t x, gpt_value_t y)
43 {
44 assert(type == GPT_TYPE_VDEVICE);
45
46 return x.vdevice == y.vdevice;
47 }
48
49 error_t
vdevice_handle_object_create_addrspace(addrspace_create_t params)50 vdevice_handle_object_create_addrspace(addrspace_create_t params)
51 {
52 addrspace_t *addrspace = params.addrspace;
53 assert(addrspace != NULL);
54
55 spinlock_init(&addrspace->vdevice_lock);
56
57 gpt_config_t config = gpt_config_default();
58 gpt_config_set_max_bits(&config, VDEVICE_MAX_GPT_BITS);
59 gpt_config_set_rcu_read(&config, true);
60
61 return gpt_init(&addrspace->vdevice_gpt, addrspace->header.partition,
62 config, util_bit((index_t)GPT_TYPE_VDEVICE));
63 }
64
65 void
vdevice_handle_object_cleanup_addrspace(addrspace_t * addrspace)66 vdevice_handle_object_cleanup_addrspace(addrspace_t *addrspace)
67 {
68 assert(addrspace != NULL);
69
70 gpt_destroy(&addrspace->vdevice_gpt);
71 }
72
73 error_t
vdevice_attach_vmaddr(vdevice_t * vdevice,addrspace_t * addrspace,vmaddr_t ipa,size_t size)74 vdevice_attach_vmaddr(vdevice_t *vdevice, addrspace_t *addrspace, vmaddr_t ipa,
75 size_t size)
76 {
77 error_t err;
78
79 assert(vdevice != NULL);
80 assert(addrspace != NULL);
81 assert(vdevice->type != VDEVICE_TYPE_NONE);
82
83 if (vdevice->addrspace != NULL) {
84 err = ERROR_BUSY;
85 goto out;
86 }
87
88 gpt_entry_t entry = {
89 .type = GPT_TYPE_VDEVICE,
90 .value = { .vdevice = vdevice },
91 };
92
93 spinlock_acquire(&addrspace->vdevice_lock);
94
95 err = gpt_insert(&addrspace->vdevice_gpt, ipa, size, entry, true);
96
97 spinlock_release(&addrspace->vdevice_lock);
98
99 if (err == OK) {
100 vdevice->addrspace = object_get_addrspace_additional(addrspace);
101 vdevice->ipa = ipa;
102 vdevice->size = size;
103 }
104
105 out:
106 return err;
107 }
108
109 void
vdevice_detach_vmaddr(vdevice_t * vdevice)110 vdevice_detach_vmaddr(vdevice_t *vdevice)
111 {
112 assert(vdevice != NULL);
113 assert(vdevice->type != VDEVICE_TYPE_NONE);
114
115 addrspace_t *addrspace = vdevice->addrspace;
116 assert(addrspace != NULL);
117
118 gpt_entry_t entry = {
119 .type = GPT_TYPE_VDEVICE,
120 .value = { .vdevice = vdevice },
121 };
122
123 spinlock_acquire(&addrspace->vdevice_lock);
124
125 error_t err = gpt_remove(&addrspace->vdevice_gpt, vdevice->ipa,
126 vdevice->size, entry);
127 assert(err == OK);
128
129 spinlock_release(&addrspace->vdevice_lock);
130
131 vdevice->addrspace = NULL;
132
133 object_put_addrspace(addrspace);
134 }
135