. pci driver now returns devices, even when they have been pci_reserve()d
[minix3.git] / lib / syslib / safecopies.c
blob468c98d77aa8bfe98bfb873a0c6d28747c1f7935
2 /* Library functions to maintain internal data copying tables.
4 * April 21 2006: Initial version (Ben Gras)
6 */
8 #include <lib.h>
9 #include <errno.h>
10 #include <minix/sysutil.h>
11 #include <assert.h>
12 #include <stdlib.h>
13 #include <minix/syslib.h>
14 #include <minix/safecopies.h>
15 #include <minix/com.h>
16 #include <string.h>
18 #define ACCESS_CHECK(a) { \
19 if((a) & ~(CPF_READ|CPF_WRITE)) { \
20 errno = EINVAL; \
21 return -1; \
22 } \
25 #define GID_CHECK(gid) { \
26 if(!GRANT_VALID(gid) || (gid) < 0 || (gid) >= ngrants) {\
27 errno = EINVAL; \
28 return -1; \
29 } \
32 #define GID_CHECK_USED(gid) { \
33 GID_CHECK(gid); \
34 if(!(grants[gid].cp_flags & CPF_USED)) { \
35 errno = EINVAL; \
36 return -1; \
37 } \
40 PRIVATE cp_grant_t *grants = NULL;
41 PRIVATE int ngrants = 0;
43 PRIVATE void
44 cpf_grow(void)
46 /* Grow the grants table if possible. */
47 cp_grant_t *new_grants;
48 cp_grant_id_t g;
49 int new_size;
51 new_size = (1+ngrants)*2;
52 assert(new_size > ngrants);
54 /* Allocate a block of new size. */
55 if(!(new_grants=malloc(new_size * sizeof(grants[0]))))
56 return;
58 /* Copy old block to new block. */
59 if(grants && ngrants > 0)
60 memcpy(new_grants, grants, ngrants * sizeof(grants[0]));
62 /* Make sure new slots are marked unused (CPF_USED is clear). */
63 for(g = ngrants; g < new_size; g++)
64 new_grants[g].cp_flags = 0;
66 /* Inform kernel about new size (and possibly new location). */
67 if((sys_setgrant(new_grants, new_size))) {
68 free(new_grants);
69 return; /* Failed - don't grow then. */
72 /* Update internal data. */
73 if(grants && ngrants > 0) free(grants);
74 grants = new_grants;
75 ngrants = new_size;
78 PRIVATE cp_grant_id_t
79 cpf_new_grantslot(void)
81 /* Find a new, free grant slot in the grant table, grow it if
82 * necessary. If no free slot is found and the grow failed,
83 * return -1. Otherwise, return grant slot number.
85 cp_grant_id_t g;
87 /* Find free slot. */
88 for(g = 0; g < ngrants && (grants[g].cp_flags & CPF_USED); g++)
91 assert(g <= ngrants);
93 /* No free slot found? */
94 if(g == ngrants) {
95 cpf_grow();
96 assert(g <= ngrants); /* ngrants can't shrink. */
97 if(g == ngrants) {
98 /* ngrants hasn't increased. */
99 errno = ENOSPC;
100 return -1;
104 /* Basic sanity checks - if we get this far, g must be a valid,
105 * free slot.
107 assert(GRANT_VALID(g));
108 assert(g >= 0);
109 assert(g < ngrants);
110 assert(!(grants[g].cp_flags & CPF_USED));
112 return g;
115 PUBLIC cp_grant_id_t
116 cpf_grant_direct(endpoint_t who_to, vir_bytes addr, size_t bytes, int access)
118 cp_grant_id_t g;
119 int r;
121 /* Get new slot to put new grant in. */
122 if((g = cpf_new_grantslot()) < 0)
123 return -1;
125 assert(GRANT_VALID(g));
126 assert(g >= 0);
127 assert(g < ngrants);
128 assert(!(grants[g].cp_flags & CPF_USED));
130 if((r=cpf_setgrant_direct(g, who_to, addr, bytes, access)) < 0) {
131 cpf_revoke(g);
132 return GRANT_INVALID;
135 return g;
138 PUBLIC cp_grant_id_t
139 cpf_grant_indirect(endpoint_t who_to, endpoint_t who_from, cp_grant_id_t gr)
141 /* Grant process A access into process B. B has granted us access as grant
142 * id 'gr'.
144 cp_grant_id_t g;
145 int r;
147 /* Obtain new slot. */
148 if((g = cpf_new_grantslot()) < 0)
149 return -1;
151 /* Basic sanity checks. */
152 assert(GRANT_VALID(g));
153 assert(g >= 0);
154 assert(g < ngrants);
155 assert(!(grants[g].cp_flags & CPF_USED));
157 /* Fill in new slot data. */
158 if((r=cpf_setgrant_indirect(g, who_to, who_from, gr)) < 0) {
159 cpf_revoke(g);
160 return GRANT_INVALID;
163 return g;
166 PUBLIC cp_grant_id_t
167 cpf_grant_magic(endpoint_t who_to, endpoint_t who_from,
168 vir_bytes addr, size_t bytes, int access)
170 /* Grant process A access into process B. Not everyone can do this. */
171 cp_grant_id_t g;
172 int r;
174 ACCESS_CHECK(access);
176 /* Obtain new slot. */
177 if((g = cpf_new_grantslot()) < 0)
178 return -1;
180 /* Basic sanity checks. */
181 assert(GRANT_VALID(g));
182 assert(g >= 0);
183 assert(g < ngrants);
184 assert(!(grants[g].cp_flags & CPF_USED));
186 if((r=cpf_setgrant_magic(g, who_to, who_from, addr,
187 bytes, access)) < 0) {
188 cpf_revoke(g);
189 return -1;
192 return g;
195 PUBLIC int
196 cpf_revoke(cp_grant_id_t g)
198 /* Revoke previously granted access, identified by grant id. */
199 GID_CHECK_USED(g);
201 /* Make grant invalid by setting flags to 0, clearing CPF_USED.
202 * This invalidates the grant.
204 grants[g].cp_flags = 0;
206 return 0;
209 PUBLIC int
210 cpf_lookup(cp_grant_id_t g, endpoint_t *granter, endpoint_t *grantee)
212 /* First check slot validity, and if it's in use currently. */
213 GID_CHECK_USED(g);
215 if(grants[g].cp_flags & CPF_DIRECT) {
216 if(granter) *granter = SELF;
217 if(grantee) *grantee = grants[g].cp_u.cp_direct.cp_who_to;
218 } else if(grants[g].cp_flags & CPF_MAGIC) {
219 if(granter) *granter = grants[g].cp_u.cp_magic.cp_who_from;
220 if(grantee) *grantee = grants[g].cp_u.cp_magic.cp_who_to;
221 } else return -1;
223 return 0;
226 PUBLIC int
227 cpf_getgrants(grant_ids, n)
228 cp_grant_id_t *grant_ids;
229 int n;
231 cp_grant_id_t g;
232 int i;
234 for(i = 0; i < n; i++) {
235 if((grant_ids[i] = cpf_new_grantslot()) < 0)
236 break;
237 grants[grant_ids[i]].cp_flags = CPF_USED;
240 /* return however many grants were assigned. */
241 return i;
244 PUBLIC int
245 cpf_setgrant_direct(gid, who, addr, bytes, access)
246 cp_grant_id_t gid;
247 endpoint_t who;
248 vir_bytes addr;
249 size_t bytes;
250 int access;
252 GID_CHECK(gid);
253 ACCESS_CHECK(access);
255 grants[gid].cp_flags = access | CPF_DIRECT | CPF_USED | CPF_VALID;
256 grants[gid].cp_u.cp_direct.cp_who_to = who;
257 grants[gid].cp_u.cp_direct.cp_start = addr;
258 grants[gid].cp_u.cp_direct.cp_len = bytes;
260 return 0;
263 PUBLIC int
264 cpf_setgrant_indirect(gid, who_to, who_from, his_gid)
265 cp_grant_id_t gid;
266 endpoint_t who_to, who_from;
267 cp_grant_id_t his_gid;
269 GID_CHECK(gid);
271 /* Fill in new slot data. */
272 grants[gid].cp_flags = CPF_USED | CPF_INDIRECT | CPF_VALID;
273 grants[gid].cp_u.cp_indirect.cp_who_to = who_to;
274 grants[gid].cp_u.cp_indirect.cp_who_from = who_from;
275 grants[gid].cp_u.cp_indirect.cp_grant = his_gid;
277 return 0;
280 PUBLIC int
281 cpf_setgrant_magic(gid, who_to, who_from, addr, bytes, access)
282 cp_grant_id_t gid;
283 endpoint_t who_to, who_from;
284 vir_bytes addr;
285 size_t bytes;
286 int access;
288 GID_CHECK(gid);
289 ACCESS_CHECK(access);
291 /* Fill in new slot data. */
292 grants[gid].cp_flags = CPF_USED | CPF_MAGIC | CPF_VALID | access;
293 grants[gid].cp_u.cp_magic.cp_who_to = who_to;
294 grants[gid].cp_u.cp_magic.cp_who_from = who_from;
295 grants[gid].cp_u.cp_magic.cp_start = addr;
296 grants[gid].cp_u.cp_magic.cp_len = bytes;
298 return 0;
301 PUBLIC int
302 cpf_setgrant_disable(gid)
303 cp_grant_id_t gid;
305 GID_CHECK(gid);
307 /* Grant is now no longer valid, but still in use. */
308 grants[gid].cp_flags = CPF_USED;
310 return 0;