2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
34 * This is a half-hearted attempt at providing the parts of the
35 * ledger facility to satisfy the ledger interfaces.
37 * This implementation basically leaves the (dysfunctional) ledgers
38 * unfunctional and are mearly here to satisfy the Mach spec interface
42 #include <mach/mach_types.h>
43 #include <mach/message.h>
44 #include <mach/port.h>
45 #include <mach/ledger_server.h>
47 #include <kern/mach_param.h>
48 #include <kern/misc_protos.h>
49 #include <kern/lock.h>
50 #include <kern/ipc_kobject.h>
51 #include <kern/host.h>
52 #include <kern/ledger.h>
53 #include <kern/kalloc.h>
55 #include <ipc/ipc_space.h>
56 #include <ipc/ipc_port.h>
58 ledger_t root_wired_ledger
;
59 ledger_t root_paged_ledger
;
62 /* Utility routine to handle entries to a ledger */
68 if (ledger
== LEDGER_NULL
)
71 /* Need to lock the ledger */
75 if (ledger
->ledger_limit
!= LEDGER_ITEM_INFINITY
&&
76 ledger
->ledger_balance
+ amount
> ledger
->ledger_limit
) {
77 /* XXX this is where you do BAD things */
78 printf("Ledger limit exceeded ! ledger=%p lim=%d balance=%d\n",
79 ledger
, ledger
->ledger_limit
,
80 ledger
->ledger_balance
);
81 ledger_unlock(ledger
);
82 return(KERN_RESOURCE_SHORTAGE
);
84 if ((ledger
->ledger_balance
+ amount
)
85 < LEDGER_ITEM_INFINITY
)
86 ledger
->ledger_balance
+= amount
;
88 ledger
->ledger_balance
= LEDGER_ITEM_INFINITY
;
91 if (ledger
->ledger_balance
+ amount
> 0)
92 ledger
->ledger_balance
+= amount
;
94 ledger
->ledger_balance
= 0;
96 ledger_unlock(ledger
);
100 /* Utility routine to create a new ledger */
104 ledger_t ledger_ledger
,
105 ledger_t ledger_parent
)
109 ledger
= (ledger_t
)kalloc(sizeof(ledger_data_t
));
110 if (ledger
== LEDGER_NULL
)
113 ledger
->ledger_self
= ipc_port_alloc_kernel();
114 if (ledger
->ledger_self
== IP_NULL
) {
115 kfree(ledger
, sizeof(ledger_data_t
));
119 ledger_lock_init(ledger
);
120 ledger
->ledger_limit
= limit
;
121 ledger
->ledger_balance
= 0;
122 ledger
->ledger_service_port
= MACH_PORT_NULL
;
123 ledger
->ledger_ledger
= ledger_ledger
;
124 ledger
->ledger_parent
= ledger_parent
;
125 ipc_kobject_set(ledger
->ledger_self
, (ipc_kobject_t
)ledger
,
131 /* Utility routine to destroy a ledger */
136 /* XXX can be many send rights (copies) of this */
137 ipc_port_dealloc_kernel(ledger
->ledger_self
);
139 /* XXX release send right on service port */
140 kfree(ledger
, sizeof(*ledger
));
145 * Inititalize the ledger facility
147 void ledger_init(void)
150 * Allocate the root ledgers; wired and paged.
152 root_wired_ledger
= ledger_allocate(LEDGER_ITEM_INFINITY
,
153 LEDGER_NULL
, LEDGER_NULL
);
154 if (root_wired_ledger
== LEDGER_NULL
)
155 panic("can't allocate root (wired) ledger");
156 ipc_port_make_send(root_wired_ledger
->ledger_self
);
158 root_paged_ledger
= ledger_allocate(LEDGER_ITEM_INFINITY
,
159 LEDGER_NULL
, LEDGER_NULL
);
160 if (root_paged_ledger
== LEDGER_NULL
)
161 panic("can't allocate root (paged) ledger");
162 ipc_port_make_send(root_paged_ledger
->ledger_self
);
166 * Create a subordinate ledger
168 kern_return_t
ledger_create(
169 ledger_t parent_ledger
,
170 ledger_t ledger_ledger
,
171 ledger_t
*new_ledger
,
172 ledger_item_t transfer
)
174 if (parent_ledger
== LEDGER_NULL
)
175 return(KERN_INVALID_ARGUMENT
);
177 if (ledger_ledger
== LEDGER_NULL
)
178 return(KERN_INVALID_LEDGER
);
181 * Allocate a new ledger and change the ledger_ledger for
184 ledger_lock(ledger_ledger
);
185 if ((ledger_ledger
->ledger_limit
!= LEDGER_ITEM_INFINITY
) &&
186 (ledger_ledger
->ledger_balance
+ sizeof(ledger_data_t
) >
187 ledger_ledger
->ledger_limit
)) {
188 ledger_unlock(ledger_ledger
);
189 return(KERN_RESOURCE_SHORTAGE
);
192 *new_ledger
= ledger_allocate(LEDGER_ITEM_INFINITY
, ledger_ledger
, parent_ledger
);
193 if (*new_ledger
== LEDGER_NULL
) {
194 ledger_unlock(ledger_ledger
);
195 return(KERN_RESOURCE_SHORTAGE
);
199 * Now transfer the limit for the new ledger from the parent
201 ledger_lock(parent_ledger
);
202 if (parent_ledger
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
203 /* Would the existing balance exceed the new limit ? */
204 if (parent_ledger
->ledger_limit
- transfer
< parent_ledger
->ledger_balance
) {
205 ledger_unlock(parent_ledger
);
206 ledger_unlock(ledger_ledger
);
207 return(KERN_RESOURCE_SHORTAGE
);
209 if (parent_ledger
->ledger_limit
- transfer
> 0)
210 parent_ledger
->ledger_limit
-= transfer
;
212 parent_ledger
->ledger_limit
= 0;
214 (*new_ledger
)->ledger_limit
= transfer
;
216 /* Charge the ledger against the ledger_ledger */
217 ledger_ledger
->ledger_balance
+= (ledger_item_t
)sizeof(ledger_data_t
);
218 ledger_unlock(parent_ledger
);
220 ledger_unlock(ledger_ledger
);
222 return(KERN_SUCCESS
);
228 kern_return_t
ledger_terminate(
231 if (ledger
== LEDGER_NULL
)
232 return(KERN_INVALID_ARGUMENT
);
234 /* You can't deallocate kernel ledgers */
235 if (ledger
== root_wired_ledger
||
236 ledger
== root_paged_ledger
)
237 return(KERN_INVALID_LEDGER
);
239 /* Lock the ledger */
242 /* the parent ledger gets back the limit */
243 ledger_lock(ledger
->ledger_parent
);
244 if (ledger
->ledger_parent
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
245 assert((natural_t
)(ledger
->ledger_parent
->ledger_limit
+
246 ledger
->ledger_limit
) <
247 LEDGER_ITEM_INFINITY
);
248 ledger
->ledger_parent
->ledger_limit
+= ledger
->ledger_limit
;
250 ledger_unlock(ledger
->ledger_parent
);
253 * XXX The spec says that you have to destroy all objects that
254 * have been created with this ledger. Nice work eh? For now
255 * Transfer the balance to the parent and let it worry about
258 /* XXX the parent ledger inherits the debt ?? */
259 (void) ledger_enter(ledger
->ledger_parent
, ledger
->ledger_balance
);
261 /* adjust the balance of the creation ledger */
262 (void) ledger_enter(ledger
->ledger_ledger
, (ledger_item_t
)-sizeof(*ledger
));
264 /* delete the ledger */
265 ledger_deallocate(ledger
);
267 return(KERN_SUCCESS
);
271 * Return the ledger limit and balance
273 kern_return_t
ledger_read(
275 ledger_item_t
*balance
,
276 ledger_item_t
*limit
)
278 if (ledger
== LEDGER_NULL
)
279 return(KERN_INVALID_ARGUMENT
);
282 *balance
= ledger
->ledger_balance
;
283 *limit
= ledger
->ledger_limit
;
284 ledger_unlock(ledger
);
286 return(KERN_SUCCESS
);
290 * Transfer resources from a parent ledger to a child
292 kern_return_t
ledger_transfer(
293 ledger_t parent_ledger
,
294 ledger_t child_ledger
,
295 ledger_item_t transfer
)
297 #define abs(v) ((v) > 0)?(v):-(v)
300 ledger_item_t amount
= abs(transfer
);
302 if (parent_ledger
== LEDGER_NULL
)
303 return(KERN_INVALID_ARGUMENT
);
305 if (child_ledger
== LEDGER_NULL
)
306 return(KERN_INVALID_ARGUMENT
);
308 /* Must be different ledgers */
309 if (parent_ledger
== child_ledger
)
310 return(KERN_INVALID_ARGUMENT
);
313 return(KERN_SUCCESS
);
315 ledger_lock(child_ledger
);
316 ledger_lock(parent_ledger
);
318 /* XXX Should be the parent you created it from ?? */
319 if (parent_ledger
!= child_ledger
->ledger_parent
) {
320 ledger_unlock(parent_ledger
);
321 ledger_unlock(child_ledger
);
322 return(KERN_INVALID_LEDGER
);
331 dest
= parent_ledger
;
334 if (src
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
335 /* Would the existing balance exceed the new limit ? */
336 if (src
->ledger_limit
- amount
< src
->ledger_balance
) {
337 ledger_unlock(parent_ledger
);
338 ledger_unlock(child_ledger
);
339 return(KERN_RESOURCE_SHORTAGE
);
341 if (src
->ledger_limit
- amount
> 0)
342 src
->ledger_limit
-= amount
;
344 src
->ledger_limit
= 0;
347 if (dest
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
348 if ((natural_t
)(dest
->ledger_limit
+ amount
)
349 < LEDGER_ITEM_INFINITY
)
350 dest
->ledger_limit
+= amount
;
352 dest
->ledger_limit
= (LEDGER_ITEM_INFINITY
- 1);
355 ledger_unlock(parent_ledger
);
356 ledger_unlock(child_ledger
);
358 return(KERN_SUCCESS
);
363 * Routine: convert_port_to_ledger
365 * Convert from a port to a ledger.
366 * Doesn't consume the port ref; the ledger produced may be null.
372 convert_port_to_ledger(
375 ledger_t ledger
= LEDGER_NULL
;
377 if (IP_VALID(port
)) {
379 if (ip_active(port
) &&
380 (ip_kotype(port
) == IKOT_LEDGER
))
381 ledger
= (ledger_t
) port
->ip_kobject
;
389 * Routine: convert_ledger_to_port
391 * Convert from a ledger to a port.
392 * Produces a naked send right which may be invalid.
398 convert_ledger_to_port(
403 if (ledger
== LEDGER_NULL
)
406 port
= ipc_port_make_send(ledger
->ledger_self
);
417 if (ledger
== LEDGER_NULL
)
420 return(ipc_port_copy_send(ledger
->ledger_self
));