2 /* Library functions to maintain internal data copying tables.
4 * April 21 2006: Initial version (Ben Gras)
10 #include <minix/sysutil.h>
13 #include <minix/syslib.h>
14 #include <minix/safecopies.h>
15 #include <minix/com.h>
18 #define ACCESS_CHECK(a) { \
19 if((a) & ~(CPF_READ|CPF_WRITE|CPF_TRY)) { \
25 #define GID_CHECK(gid) { \
26 if(!GRANT_VALID(gid) || GRANT_IDX(gid) >= ngrants || \
27 GRANT_SEQ(gid) != grants[GRANT_IDX(gid)].cp_seq) { \
33 #define GID_CHECK_USED(gid) { \
35 if(!(grants[GRANT_IDX(gid)].cp_flags & CPF_USED)) { \
41 #define NR_STATIC_GRANTS 3
42 static cp_grant_t static_grants
[NR_STATIC_GRANTS
];
43 static cp_grant_t
*grants
= NULL
;
44 static int ngrants
= 0;
45 static int freelist
= -1;
48 * Preallocate more grants that will be free for subsequent use. If a specific
49 * number of grants is given (i.e., count > 0), the total number of grants will
50 * be increased by that amount. If no number of grants is given (count == 0),
51 * double(ish) the size of the table. The latter is used internally. This
52 * function may fail, either because the maximum number of slots is reached or
53 * because no new memory can be allocated. In that case, nothing will change;
54 * the caller must check afterward whether there are newly available grants.
57 cpf_prealloc(unsigned int count
)
59 cp_grant_t
*new_grants
;
62 if (!ngrants
&& count
<= NR_STATIC_GRANTS
) {
63 /* Use statically allocated grants the first time. */
64 new_size
= NR_STATIC_GRANTS
;
65 new_grants
= static_grants
;
68 if (ngrants
>= GRANT_MAX_IDX
)
71 if (count
> (unsigned)(GRANT_MAX_IDX
- ngrants
))
72 count
= (unsigned)(GRANT_MAX_IDX
- ngrants
);
73 new_size
= ngrants
+ (int)count
;
75 new_size
= (1+ngrants
)*2;
76 if (new_size
>= GRANT_MAX_IDX
)
77 new_size
= GRANT_MAX_IDX
;
78 assert(new_size
> ngrants
);
80 /* Allocate a block of new size. */
81 if(!(new_grants
=malloc(new_size
* sizeof(grants
[0])))) {
86 /* Copy old block to new block. */
87 if(grants
&& ngrants
> 0)
88 memcpy(new_grants
, grants
, ngrants
* sizeof(grants
[0]));
91 * Make sure new slots are marked unused (CPF_USED is clear).
92 * Also start with a zero sequence number, for consistency; since the
93 * grant table is never shrunk, this introduces no issues by itself.
94 * Finally, form a new free list, in ascending order so that the lowest
95 * IDs get allocated first. Both the zeroed sequence number and the
96 * ascending order are necessary so that the first grant to be
97 * allocated has a zero ID (see the live update comment below).
99 for(g
= ngrants
; g
< new_size
; g
++) {
100 new_grants
[g
].cp_flags
= 0;
101 new_grants
[g
].cp_seq
= 0;
102 new_grants
[g
].cp_u
.cp_free
.cp_next
=
103 (g
< new_size
- 1) ? (g
+ 1) : freelist
;
106 /* Inform kernel about new size (and possibly new location). */
107 if((sys_setgrant(new_grants
, new_size
))) {
108 if(new_grants
!= static_grants
) free(new_grants
);
109 return; /* Failed - don't grow then. */
112 /* Update internal data. */
113 if(grants
&& ngrants
> 0 && grants
!= static_grants
) free(grants
);
120 cpf_new_grantslot(void)
122 /* Find a new, free grant slot in the grant table, grow it if
123 * necessary. If no free slot is found and the grow failed,
124 * return -1. Otherwise, return grant slot number.
128 /* Obtain a free slot. */
129 if ((g
= freelist
) == -1) {
130 /* Table full - try to make the table larger. */
132 if ((g
= freelist
) == -1) {
133 /* ngrants hasn't increased. */
139 /* Basic sanity checks - if we get this far, g must be a valid,
144 assert(!(grants
[g
].cp_flags
& CPF_USED
));
146 /* Take the slot off the free list, and return its slot number. */
147 freelist
= grants
[g
].cp_u
.cp_free
.cp_next
;
153 cpf_grant_direct(endpoint_t who_to
, vir_bytes addr
, size_t bytes
, int access
)
157 ACCESS_CHECK(access
);
159 /* Get new slot to put new grant in. */
160 if((g
= cpf_new_grantslot()) < 0)
163 /* Fill in new slot data. */
164 grants
[g
].cp_u
.cp_direct
.cp_who_to
= who_to
;
165 grants
[g
].cp_u
.cp_direct
.cp_start
= addr
;
166 grants
[g
].cp_u
.cp_direct
.cp_len
= bytes
;
167 grants
[g
].cp_faulted
= GRANT_INVALID
;
169 grants
[g
].cp_flags
= access
| CPF_DIRECT
| CPF_USED
| CPF_VALID
;
171 return GRANT_ID(g
, grants
[g
].cp_seq
);
175 cpf_grant_indirect(endpoint_t who_to
, endpoint_t who_from
, cp_grant_id_t gr
)
177 /* Grant process A access into process B. B has granted us access as grant
182 /* Obtain new slot. */
183 if((g
= cpf_new_grantslot()) < 0)
186 /* Fill in new slot data. */
187 grants
[g
].cp_u
.cp_indirect
.cp_who_to
= who_to
;
188 grants
[g
].cp_u
.cp_indirect
.cp_who_from
= who_from
;
189 grants
[g
].cp_u
.cp_indirect
.cp_grant
= gr
;
190 grants
[g
].cp_faulted
= GRANT_INVALID
;
192 grants
[g
].cp_flags
= CPF_USED
| CPF_INDIRECT
| CPF_VALID
;
194 return GRANT_ID(g
, grants
[g
].cp_seq
);
198 cpf_grant_magic(endpoint_t who_to
, endpoint_t who_from
,
199 vir_bytes addr
, size_t bytes
, int access
)
201 /* Grant process A access into process B. Not everyone can do this. */
204 ACCESS_CHECK(access
);
206 /* Obtain new slot. */
207 if((g
= cpf_new_grantslot()) < 0)
210 /* Fill in new slot data. */
211 grants
[g
].cp_u
.cp_magic
.cp_who_to
= who_to
;
212 grants
[g
].cp_u
.cp_magic
.cp_who_from
= who_from
;
213 grants
[g
].cp_u
.cp_magic
.cp_start
= addr
;
214 grants
[g
].cp_u
.cp_magic
.cp_len
= bytes
;
215 grants
[g
].cp_faulted
= GRANT_INVALID
;
217 grants
[g
].cp_flags
= CPF_USED
| CPF_MAGIC
| CPF_VALID
| access
;
219 return GRANT_ID(g
, grants
[g
].cp_seq
);
223 * Revoke previously granted access, identified by grant ID. Return -1 on
224 * error, with errno set as appropriate. Return 0 on success, with one
225 * exception: return GRANT_FAULTED (1) if a grant was created with CPF_TRY and
226 * during its lifetime, a copy from or to the grant experienced a soft fault.
229 cpf_revoke(cp_grant_id_t grant
)
233 GID_CHECK_USED(grant
);
235 g
= GRANT_IDX(grant
);
238 * If a safecopy action on a (direct or magic) grant with the CPF_TRY
239 * flag failed on a soft fault, the kernel will have set the cp_faulted
240 * field to the grant identifier. Here, we test this and return
241 * GRANT_FAULTED (1) on a match.
243 r
= ((grants
[g
].cp_flags
& CPF_TRY
) &&
244 grants
[g
].cp_faulted
== grant
) ? GRANT_FAULTED
: 0;
247 * Make grant invalid by setting flags to 0, clearing CPF_USED.
248 * This invalidates the grant.
250 grants
[g
].cp_flags
= 0;
254 * Increase the grant slot's sequence number now, rather than on
255 * allocation, because live update relies on the first allocated grant
256 * having a zero ID (SEF_STATE_TRANSFER_GID) and thus a zero sequence
259 if (grants
[g
].cp_seq
< GRANT_MAX_SEQ
- 1)
262 grants
[g
].cp_seq
= 0;
265 * Put the grant back on the free list. The list is single-headed, so
266 * the last freed grant will be the first to be reused. Especially
267 * given the presence of sequence numbers, this is not a problem.
269 grants
[g
].cp_u
.cp_free
.cp_next
= freelist
;
276 * START OF DEPRECATED API
278 * The grant preallocation and (re)assignment API below imposes that grant IDs
279 * stay the same across reuse, thus disallowing that the grants' sequence
280 * numbers be updated as a part of reassignment. As a result, this API does
281 * not offer the same protection against accidental reuse of an old grant by a
282 * remote party as the regular API does, and is therefore deprecated.
285 cpf_getgrants(cp_grant_id_t
*grant_ids
, int n
)
289 for(i
= 0; i
< n
; i
++) {
290 if((grant_ids
[i
] = cpf_new_grantslot()) < 0)
292 grants
[grant_ids
[i
]].cp_flags
= CPF_USED
;
293 grants
[grant_ids
[i
]].cp_seq
= 0;
296 /* return however many grants were assigned. */
301 cpf_setgrant_direct(gid
, who
, addr
, bytes
, access
)
309 ACCESS_CHECK(access
);
311 /* Fill in new slot data. */
312 grants
[gid
].cp_flags
= access
| CPF_DIRECT
| CPF_USED
| CPF_VALID
;
313 grants
[gid
].cp_u
.cp_direct
.cp_who_to
= who
;
314 grants
[gid
].cp_u
.cp_direct
.cp_start
= addr
;
315 grants
[gid
].cp_u
.cp_direct
.cp_len
= bytes
;
321 cpf_setgrant_indirect(gid
, who_to
, who_from
, his_gid
)
323 endpoint_t who_to
, who_from
;
324 cp_grant_id_t his_gid
;
328 /* Fill in new slot data. */
329 grants
[gid
].cp_flags
= CPF_USED
| CPF_INDIRECT
| CPF_VALID
;
330 grants
[gid
].cp_u
.cp_indirect
.cp_who_to
= who_to
;
331 grants
[gid
].cp_u
.cp_indirect
.cp_who_from
= who_from
;
332 grants
[gid
].cp_u
.cp_indirect
.cp_grant
= his_gid
;
338 cpf_setgrant_magic(gid
, who_to
, who_from
, addr
, bytes
, access
)
340 endpoint_t who_to
, who_from
;
346 ACCESS_CHECK(access
);
348 /* Fill in new slot data. */
349 grants
[gid
].cp_flags
= CPF_USED
| CPF_MAGIC
| CPF_VALID
| access
;
350 grants
[gid
].cp_u
.cp_magic
.cp_who_to
= who_to
;
351 grants
[gid
].cp_u
.cp_magic
.cp_who_from
= who_from
;
352 grants
[gid
].cp_u
.cp_magic
.cp_start
= addr
;
353 grants
[gid
].cp_u
.cp_magic
.cp_len
= bytes
;
359 cpf_setgrant_disable(gid
)
364 /* Grant is now no longer valid, but still in use. */
365 grants
[gid
].cp_flags
= CPF_USED
;
370 * END OF DEPRECATED API
376 /* Inform the kernel about the location of the grant table. This is needed
380 sys_setgrant(grants
, ngrants
); /* Do we need error checking? */