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