2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
31 * Revision 1.1.1.1 1998/09/22 21:05:34 wsanchez
32 * Import of Mac OS X kernel (~semeria)
34 * Revision 1.1.1.1 1998/03/07 02:25:55 wsanchez
35 * Import of OSF Mach kernel (~mburg)
37 * Revision 1.1.6.1 1995/01/06 19:47:19 devrcs
38 * mk6 CR668 - 1.3b26 merge
40 * [1994/10/12 22:19:28 dwm]
42 * Revision 1.1.3.4 1994/05/13 20:10:01 tmt
43 * Changed three unsigned casts to natural_t.
44 * [1994/05/12 22:12:28 tmt]
46 * Revision 1.1.3.2 1993/11/30 18:26:24 jph
47 * CR10228 -- Typo in unlock(), ledger_ledger should be child_ledger.
48 * [1993/11/30 16:10:43 jph]
50 * Revision 1.1.3.1 1993/11/24 21:22:14 jph
51 * CR9801 brezak merge, ledgers, security and NMK15_COMPAT
52 * [1993/11/23 22:41:07 jph]
54 * Revision 1.1.1.4 1993/09/08 14:17:36 brezak
55 * Include <mach/ledger_server.h> for protos.
57 * Revision 1.1.1.3 1993/08/20 14:16:55 brezak
66 * This is a half-hearted attempt at providing the parts of the
67 * ledger facility to satisfy the ledger interfaces.
69 * This implementation basically leaves the (dysfunctional) ledgers
70 * unfunctional and are mearly here to satisfy the Mach spec interface
74 #include <mach/mach_types.h>
75 #include <mach/message.h>
76 #include <kern/mach_param.h>
77 #include <kern/misc_protos.h>
78 #include <mach/port.h>
79 #include <kern/lock.h>
80 #include <kern/ipc_kobject.h>
81 #include <ipc/ipc_space.h>
82 #include <ipc/ipc_port.h>
83 #include <kern/host.h>
84 #include <kern/ledger.h>
85 #include <mach/ledger_server.h>
87 ledger_t root_wired_ledger
;
88 ledger_t root_paged_ledger
;
91 /* Utility routine to handle entries to a ledger */
97 /* Need to lock the ledger */
101 if (ledger
->ledger_limit
!= LEDGER_ITEM_INFINITY
&&
102 ledger
->ledger_balance
+ amount
> ledger
->ledger_limit
) {
103 /* XXX this is where you do BAD things */
104 printf("Ledger limit exceeded ! ledger=%x lim=%d balance=%d\n",
105 ledger
, ledger
->ledger_limit
,
106 ledger
->ledger_balance
);
107 ledger_unlock(ledger
);
108 return(KERN_RESOURCE_SHORTAGE
);
110 if ((natural_t
)(ledger
->ledger_balance
+ amount
)
111 < LEDGER_ITEM_INFINITY
)
112 ledger
->ledger_balance
+= amount
;
114 ledger
->ledger_balance
= LEDGER_ITEM_INFINITY
;
117 if (ledger
->ledger_balance
+ amount
> 0)
118 ledger
->ledger_balance
+= amount
;
120 ledger
->ledger_balance
= 0;
122 ledger_unlock(ledger
);
123 return(KERN_SUCCESS
);
126 /* Utility routine to create a new ledger */
130 ledger_t ledger_ledger
,
131 ledger_t ledger_parent
)
135 ledger
= (ledger_t
)kalloc(sizeof(ledger_data_t
));
136 if (ledger
== LEDGER_NULL
)
139 ledger
->ledger_self
= ipc_port_alloc_kernel();
140 if (ledger
->ledger_self
== IP_NULL
)
143 ledger_lock_init(ledger
);
144 ledger
->ledger_limit
= limit
;
145 ledger
->ledger_balance
= 0;
146 ledger
->ledger_service_port
= MACH_PORT_NULL
;
147 ledger
->ledger_ledger
= ledger_ledger
;
148 ledger
->ledger_parent
= ledger_parent
;
149 ipc_kobject_set(ledger
->ledger_self
, (ipc_kobject_t
)ledger
,
155 /* Utility routine to destroy a ledger */
160 /* XXX can be many send rights (copies) of this */
161 ipc_port_dealloc_kernel(ledger
->ledger_self
);
163 /* XXX release send right on service port */
164 kfree((vm_offset_t
)ledger
, sizeof(*ledger
));
169 * Inititalize the ledger facility
171 void ledger_init(void)
174 * Allocate the root ledgers; wired and paged.
176 root_wired_ledger
= ledger_allocate(LEDGER_ITEM_INFINITY
,
177 LEDGER_NULL
, LEDGER_NULL
);
178 if (root_wired_ledger
== LEDGER_NULL
)
179 panic("can't allocate root (wired) ledger");
180 ipc_port_make_send(root_wired_ledger
->ledger_self
);
182 root_paged_ledger
= ledger_allocate(LEDGER_ITEM_INFINITY
,
183 LEDGER_NULL
, LEDGER_NULL
);
184 if (root_paged_ledger
== LEDGER_NULL
)
185 panic("can't allocate root (paged) ledger");
186 ipc_port_make_send(root_paged_ledger
->ledger_self
);
190 * Create a subordinate ledger
192 kern_return_t
ledger_create(
193 ledger_t parent_ledger
,
194 ledger_t ledger_ledger
,
195 ledger_t
*new_ledger
,
196 ledger_item_t transfer
)
198 if (parent_ledger
== LEDGER_NULL
)
199 return(KERN_INVALID_ARGUMENT
);
201 if (ledger_ledger
== LEDGER_NULL
)
202 return(KERN_INVALID_LEDGER
);
205 * Allocate a new ledger and change the ledger_ledger for
208 ledger_lock(ledger_ledger
);
209 if ((ledger_ledger
->ledger_limit
!= LEDGER_ITEM_INFINITY
) &&
210 (ledger_ledger
->ledger_balance
+ sizeof(ledger_data_t
) >
211 ledger_ledger
->ledger_limit
)) {
212 ledger_unlock(ledger_ledger
);
213 return(KERN_RESOURCE_SHORTAGE
);
216 *new_ledger
= ledger_allocate(LEDGER_ITEM_INFINITY
, ledger_ledger
, parent_ledger
);
217 if (*new_ledger
== LEDGER_NULL
) {
218 ledger_unlock(ledger_ledger
);
219 return(KERN_RESOURCE_SHORTAGE
);
223 * Now transfer the limit for the new ledger from the parent
225 ledger_lock(parent_ledger
);
226 if (parent_ledger
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
227 /* Would the existing balance exceed the new limit ? */
228 if (parent_ledger
->ledger_limit
- transfer
< parent_ledger
->ledger_balance
) {
229 ledger_unlock(parent_ledger
);
230 ledger_unlock(ledger_ledger
);
231 return(KERN_RESOURCE_SHORTAGE
);
233 if (parent_ledger
->ledger_limit
- transfer
> 0)
234 parent_ledger
->ledger_limit
-= transfer
;
236 parent_ledger
->ledger_limit
= 0;
238 (*new_ledger
)->ledger_limit
= transfer
;
240 /* Charge the ledger against the ledger_ledger */
241 ledger_ledger
->ledger_balance
+= sizeof(ledger_data_t
);
242 ledger_unlock(parent_ledger
);
244 ledger_unlock(ledger_ledger
);
246 return(KERN_SUCCESS
);
252 kern_return_t
ledger_terminate(
255 if (ledger
== LEDGER_NULL
)
256 return(KERN_INVALID_ARGUMENT
);
258 /* You can't deallocate kernel ledgers */
259 if (ledger
== root_wired_ledger
||
260 ledger
== root_paged_ledger
)
261 return(KERN_INVALID_LEDGER
);
263 /* Lock the ledger */
266 /* the parent ledger gets back the limit */
267 ledger_lock(ledger
->ledger_parent
);
268 if (ledger
->ledger_parent
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
269 assert((natural_t
)(ledger
->ledger_parent
->ledger_limit
+
270 ledger
->ledger_limit
) <
271 LEDGER_ITEM_INFINITY
);
272 ledger
->ledger_parent
->ledger_limit
+= ledger
->ledger_limit
;
274 ledger_unlock(ledger
->ledger_parent
);
277 * XXX The spec says that you have to destroy all objects that
278 * have been created with this ledger. Nice work eh? For now
279 * Transfer the balance to the parent and let it worry about
282 /* XXX the parent ledger inherits the debt ?? */
283 (void) ledger_enter(ledger
->ledger_parent
, ledger
->ledger_balance
);
285 /* adjust the balance of the creation ledger */
286 (void) ledger_enter(ledger
->ledger_ledger
, -sizeof(*ledger
));
288 /* delete the ledger */
289 ledger_deallocate(ledger
);
291 return(KERN_SUCCESS
);
295 * Return the ledger limit and balance
297 kern_return_t
ledger_read(
299 ledger_item_t
*balance
,
300 ledger_item_t
*limit
)
302 if (ledger
== LEDGER_NULL
)
303 return(KERN_INVALID_ARGUMENT
);
306 *balance
= ledger
->ledger_balance
;
307 *limit
= ledger
->ledger_limit
;
308 ledger_unlock(ledger
);
310 return(KERN_SUCCESS
);
314 * Transfer resources from a parent ledger to a child
316 kern_return_t
ledger_transfer(
317 ledger_t parent_ledger
,
318 ledger_t child_ledger
,
319 ledger_item_t transfer
)
321 #define abs(v) ((v) > 0)?(v):-(v)
324 ledger_item_t amount
= abs(transfer
);
326 if (parent_ledger
== LEDGER_NULL
)
327 return(KERN_INVALID_ARGUMENT
);
329 if (child_ledger
== LEDGER_NULL
)
330 return(KERN_INVALID_ARGUMENT
);
332 /* Must be different ledgers */
333 if (parent_ledger
== child_ledger
)
334 return(KERN_INVALID_ARGUMENT
);
337 return(KERN_SUCCESS
);
339 ledger_lock(child_ledger
);
340 ledger_lock(parent_ledger
);
342 /* XXX Should be the parent you created it from ?? */
343 if (parent_ledger
!= child_ledger
->ledger_parent
) {
344 ledger_unlock(parent_ledger
);
345 ledger_unlock(child_ledger
);
346 return(KERN_INVALID_LEDGER
);
355 dest
= parent_ledger
;
358 if (src
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
359 /* Would the existing balance exceed the new limit ? */
360 if (src
->ledger_limit
- amount
< src
->ledger_balance
) {
361 ledger_unlock(parent_ledger
);
362 ledger_unlock(child_ledger
);
363 return(KERN_RESOURCE_SHORTAGE
);
365 if (src
->ledger_limit
- amount
> 0)
366 src
->ledger_limit
-= amount
;
368 src
->ledger_limit
= 0;
371 if (dest
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
372 if ((natural_t
)(dest
->ledger_limit
+ amount
)
373 < LEDGER_ITEM_INFINITY
)
374 dest
->ledger_limit
+= amount
;
376 dest
->ledger_limit
= (LEDGER_ITEM_INFINITY
- 1);
379 ledger_unlock(parent_ledger
);
380 ledger_unlock(child_ledger
);
382 return(KERN_SUCCESS
);
387 * Routine: convert_port_to_ledger
389 * Convert from a port to a ledger.
390 * Doesn't consume the port ref; the ledger produced may be null.
396 convert_port_to_ledger(
399 ledger_t ledger
= LEDGER_NULL
;
401 if (IP_VALID(port
)) {
403 if (ip_active(port
) &&
404 (ip_kotype(port
) == IKOT_LEDGER
))
405 ledger
= (ledger_t
) port
->ip_kobject
;
413 * Routine: convert_ledger_to_port
415 * Convert from a ledger to a port.
416 * Produces a naked send right which may be invalid.
422 convert_ledger_to_port(
427 port
= ipc_port_make_send(ledger
->ledger_self
);
439 /* XXX reference counting */
441 return(ipc_port_copy_send(ledger
->ledger_self
));