2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_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. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
29 * This is a half-hearted attempt at providing the parts of the
30 * ledger facility to satisfy the ledger interfaces.
32 * This implementation basically leaves the (dysfunctional) ledgers
33 * unfunctional and are mearly here to satisfy the Mach spec interface
37 #include <mach/mach_types.h>
38 #include <mach/message.h>
39 #include <mach/port.h>
40 #include <mach/ledger_server.h>
42 #include <kern/mach_param.h>
43 #include <kern/misc_protos.h>
44 #include <kern/lock.h>
45 #include <kern/ipc_kobject.h>
46 #include <kern/host.h>
47 #include <kern/ledger.h>
48 #include <kern/kalloc.h>
50 #include <ipc/ipc_space.h>
51 #include <ipc/ipc_port.h>
53 ledger_t root_wired_ledger
;
54 ledger_t root_paged_ledger
;
57 /* Utility routine to handle entries to a ledger */
63 /* Need to lock the ledger */
67 if (ledger
->ledger_limit
!= LEDGER_ITEM_INFINITY
&&
68 ledger
->ledger_balance
+ amount
> ledger
->ledger_limit
) {
69 /* XXX this is where you do BAD things */
70 printf("Ledger limit exceeded ! ledger=%x lim=%d balance=%d\n",
71 ledger
, ledger
->ledger_limit
,
72 ledger
->ledger_balance
);
73 ledger_unlock(ledger
);
74 return(KERN_RESOURCE_SHORTAGE
);
76 if ((ledger
->ledger_balance
+ amount
)
77 < LEDGER_ITEM_INFINITY
)
78 ledger
->ledger_balance
+= amount
;
80 ledger
->ledger_balance
= LEDGER_ITEM_INFINITY
;
83 if (ledger
->ledger_balance
+ amount
> 0)
84 ledger
->ledger_balance
+= amount
;
86 ledger
->ledger_balance
= 0;
88 ledger_unlock(ledger
);
92 /* Utility routine to create a new ledger */
96 ledger_t ledger_ledger
,
97 ledger_t ledger_parent
)
101 ledger
= (ledger_t
)kalloc(sizeof(ledger_data_t
));
102 if (ledger
== LEDGER_NULL
)
105 ledger
->ledger_self
= ipc_port_alloc_kernel();
106 if (ledger
->ledger_self
== IP_NULL
)
109 ledger_lock_init(ledger
);
110 ledger
->ledger_limit
= limit
;
111 ledger
->ledger_balance
= 0;
112 ledger
->ledger_service_port
= MACH_PORT_NULL
;
113 ledger
->ledger_ledger
= ledger_ledger
;
114 ledger
->ledger_parent
= ledger_parent
;
115 ipc_kobject_set(ledger
->ledger_self
, (ipc_kobject_t
)ledger
,
121 /* Utility routine to destroy a ledger */
126 /* XXX can be many send rights (copies) of this */
127 ipc_port_dealloc_kernel(ledger
->ledger_self
);
129 /* XXX release send right on service port */
130 kfree(ledger
, sizeof(*ledger
));
135 * Inititalize the ledger facility
137 void ledger_init(void)
140 * Allocate the root ledgers; wired and paged.
142 root_wired_ledger
= ledger_allocate(LEDGER_ITEM_INFINITY
,
143 LEDGER_NULL
, LEDGER_NULL
);
144 if (root_wired_ledger
== LEDGER_NULL
)
145 panic("can't allocate root (wired) ledger");
146 ipc_port_make_send(root_wired_ledger
->ledger_self
);
148 root_paged_ledger
= ledger_allocate(LEDGER_ITEM_INFINITY
,
149 LEDGER_NULL
, LEDGER_NULL
);
150 if (root_paged_ledger
== LEDGER_NULL
)
151 panic("can't allocate root (paged) ledger");
152 ipc_port_make_send(root_paged_ledger
->ledger_self
);
156 * Create a subordinate ledger
158 kern_return_t
ledger_create(
159 ledger_t parent_ledger
,
160 ledger_t ledger_ledger
,
161 ledger_t
*new_ledger
,
162 ledger_item_t transfer
)
164 if (parent_ledger
== LEDGER_NULL
)
165 return(KERN_INVALID_ARGUMENT
);
167 if (ledger_ledger
== LEDGER_NULL
)
168 return(KERN_INVALID_LEDGER
);
171 * Allocate a new ledger and change the ledger_ledger for
174 ledger_lock(ledger_ledger
);
175 if ((ledger_ledger
->ledger_limit
!= LEDGER_ITEM_INFINITY
) &&
176 (ledger_ledger
->ledger_balance
+ sizeof(ledger_data_t
) >
177 ledger_ledger
->ledger_limit
)) {
178 ledger_unlock(ledger_ledger
);
179 return(KERN_RESOURCE_SHORTAGE
);
182 *new_ledger
= ledger_allocate(LEDGER_ITEM_INFINITY
, ledger_ledger
, parent_ledger
);
183 if (*new_ledger
== LEDGER_NULL
) {
184 ledger_unlock(ledger_ledger
);
185 return(KERN_RESOURCE_SHORTAGE
);
189 * Now transfer the limit for the new ledger from the parent
191 ledger_lock(parent_ledger
);
192 if (parent_ledger
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
193 /* Would the existing balance exceed the new limit ? */
194 if (parent_ledger
->ledger_limit
- transfer
< parent_ledger
->ledger_balance
) {
195 ledger_unlock(parent_ledger
);
196 ledger_unlock(ledger_ledger
);
197 return(KERN_RESOURCE_SHORTAGE
);
199 if (parent_ledger
->ledger_limit
- transfer
> 0)
200 parent_ledger
->ledger_limit
-= transfer
;
202 parent_ledger
->ledger_limit
= 0;
204 (*new_ledger
)->ledger_limit
= transfer
;
206 /* Charge the ledger against the ledger_ledger */
207 ledger_ledger
->ledger_balance
+= sizeof(ledger_data_t
);
208 ledger_unlock(parent_ledger
);
210 ledger_unlock(ledger_ledger
);
212 return(KERN_SUCCESS
);
218 kern_return_t
ledger_terminate(
221 if (ledger
== LEDGER_NULL
)
222 return(KERN_INVALID_ARGUMENT
);
224 /* You can't deallocate kernel ledgers */
225 if (ledger
== root_wired_ledger
||
226 ledger
== root_paged_ledger
)
227 return(KERN_INVALID_LEDGER
);
229 /* Lock the ledger */
232 /* the parent ledger gets back the limit */
233 ledger_lock(ledger
->ledger_parent
);
234 if (ledger
->ledger_parent
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
235 assert((natural_t
)(ledger
->ledger_parent
->ledger_limit
+
236 ledger
->ledger_limit
) <
237 LEDGER_ITEM_INFINITY
);
238 ledger
->ledger_parent
->ledger_limit
+= ledger
->ledger_limit
;
240 ledger_unlock(ledger
->ledger_parent
);
243 * XXX The spec says that you have to destroy all objects that
244 * have been created with this ledger. Nice work eh? For now
245 * Transfer the balance to the parent and let it worry about
248 /* XXX the parent ledger inherits the debt ?? */
249 (void) ledger_enter(ledger
->ledger_parent
, ledger
->ledger_balance
);
251 /* adjust the balance of the creation ledger */
252 (void) ledger_enter(ledger
->ledger_ledger
, -sizeof(*ledger
));
254 /* delete the ledger */
255 ledger_deallocate(ledger
);
257 return(KERN_SUCCESS
);
261 * Return the ledger limit and balance
263 kern_return_t
ledger_read(
265 ledger_item_t
*balance
,
266 ledger_item_t
*limit
)
268 if (ledger
== LEDGER_NULL
)
269 return(KERN_INVALID_ARGUMENT
);
272 *balance
= ledger
->ledger_balance
;
273 *limit
= ledger
->ledger_limit
;
274 ledger_unlock(ledger
);
276 return(KERN_SUCCESS
);
280 * Transfer resources from a parent ledger to a child
282 kern_return_t
ledger_transfer(
283 ledger_t parent_ledger
,
284 ledger_t child_ledger
,
285 ledger_item_t transfer
)
287 #define abs(v) ((v) > 0)?(v):-(v)
290 ledger_item_t amount
= abs(transfer
);
292 if (parent_ledger
== LEDGER_NULL
)
293 return(KERN_INVALID_ARGUMENT
);
295 if (child_ledger
== LEDGER_NULL
)
296 return(KERN_INVALID_ARGUMENT
);
298 /* Must be different ledgers */
299 if (parent_ledger
== child_ledger
)
300 return(KERN_INVALID_ARGUMENT
);
303 return(KERN_SUCCESS
);
305 ledger_lock(child_ledger
);
306 ledger_lock(parent_ledger
);
308 /* XXX Should be the parent you created it from ?? */
309 if (parent_ledger
!= child_ledger
->ledger_parent
) {
310 ledger_unlock(parent_ledger
);
311 ledger_unlock(child_ledger
);
312 return(KERN_INVALID_LEDGER
);
321 dest
= parent_ledger
;
324 if (src
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
325 /* Would the existing balance exceed the new limit ? */
326 if (src
->ledger_limit
- amount
< src
->ledger_balance
) {
327 ledger_unlock(parent_ledger
);
328 ledger_unlock(child_ledger
);
329 return(KERN_RESOURCE_SHORTAGE
);
331 if (src
->ledger_limit
- amount
> 0)
332 src
->ledger_limit
-= amount
;
334 src
->ledger_limit
= 0;
337 if (dest
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
338 if ((natural_t
)(dest
->ledger_limit
+ amount
)
339 < LEDGER_ITEM_INFINITY
)
340 dest
->ledger_limit
+= amount
;
342 dest
->ledger_limit
= (LEDGER_ITEM_INFINITY
- 1);
345 ledger_unlock(parent_ledger
);
346 ledger_unlock(child_ledger
);
348 return(KERN_SUCCESS
);
353 * Routine: convert_port_to_ledger
355 * Convert from a port to a ledger.
356 * Doesn't consume the port ref; the ledger produced may be null.
362 convert_port_to_ledger(
365 ledger_t ledger
= LEDGER_NULL
;
367 if (IP_VALID(port
)) {
369 if (ip_active(port
) &&
370 (ip_kotype(port
) == IKOT_LEDGER
))
371 ledger
= (ledger_t
) port
->ip_kobject
;
379 * Routine: convert_ledger_to_port
381 * Convert from a ledger to a port.
382 * Produces a naked send right which may be invalid.
388 convert_ledger_to_port(
393 port
= ipc_port_make_send(ledger
->ledger_self
);
405 /* XXX reference counting */
407 return(ipc_port_copy_send(ledger
->ledger_self
));