2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
20 * @APPLE_LICENSE_HEADER_END@
28 * This is a half-hearted attempt at providing the parts of the
29 * ledger facility to satisfy the ledger interfaces.
31 * This implementation basically leaves the (dysfunctional) ledgers
32 * unfunctional and are mearly here to satisfy the Mach spec interface
36 #include <mach/mach_types.h>
37 #include <mach/message.h>
38 #include <mach/port.h>
39 #include <mach/ledger_server.h>
41 #include <kern/mach_param.h>
42 #include <kern/misc_protos.h>
43 #include <kern/lock.h>
44 #include <kern/ipc_kobject.h>
45 #include <kern/host.h>
46 #include <kern/ledger.h>
47 #include <kern/kalloc.h>
49 #include <ipc/ipc_space.h>
50 #include <ipc/ipc_port.h>
52 ledger_t root_wired_ledger
;
53 ledger_t root_paged_ledger
;
56 /* Utility routine to handle entries to a ledger */
62 /* Need to lock the ledger */
66 if (ledger
->ledger_limit
!= LEDGER_ITEM_INFINITY
&&
67 ledger
->ledger_balance
+ amount
> ledger
->ledger_limit
) {
68 /* XXX this is where you do BAD things */
69 printf("Ledger limit exceeded ! ledger=%x lim=%d balance=%d\n",
70 ledger
, ledger
->ledger_limit
,
71 ledger
->ledger_balance
);
72 ledger_unlock(ledger
);
73 return(KERN_RESOURCE_SHORTAGE
);
75 if ((ledger
->ledger_balance
+ amount
)
76 < LEDGER_ITEM_INFINITY
)
77 ledger
->ledger_balance
+= amount
;
79 ledger
->ledger_balance
= LEDGER_ITEM_INFINITY
;
82 if (ledger
->ledger_balance
+ amount
> 0)
83 ledger
->ledger_balance
+= amount
;
85 ledger
->ledger_balance
= 0;
87 ledger_unlock(ledger
);
91 /* Utility routine to create a new ledger */
95 ledger_t ledger_ledger
,
96 ledger_t ledger_parent
)
100 ledger
= (ledger_t
)kalloc(sizeof(ledger_data_t
));
101 if (ledger
== LEDGER_NULL
)
104 ledger
->ledger_self
= ipc_port_alloc_kernel();
105 if (ledger
->ledger_self
== IP_NULL
)
108 ledger_lock_init(ledger
);
109 ledger
->ledger_limit
= limit
;
110 ledger
->ledger_balance
= 0;
111 ledger
->ledger_service_port
= MACH_PORT_NULL
;
112 ledger
->ledger_ledger
= ledger_ledger
;
113 ledger
->ledger_parent
= ledger_parent
;
114 ipc_kobject_set(ledger
->ledger_self
, (ipc_kobject_t
)ledger
,
120 /* Utility routine to destroy a ledger */
125 /* XXX can be many send rights (copies) of this */
126 ipc_port_dealloc_kernel(ledger
->ledger_self
);
128 /* XXX release send right on service port */
129 kfree(ledger
, sizeof(*ledger
));
134 * Inititalize the ledger facility
136 void ledger_init(void)
139 * Allocate the root ledgers; wired and paged.
141 root_wired_ledger
= ledger_allocate(LEDGER_ITEM_INFINITY
,
142 LEDGER_NULL
, LEDGER_NULL
);
143 if (root_wired_ledger
== LEDGER_NULL
)
144 panic("can't allocate root (wired) ledger");
145 ipc_port_make_send(root_wired_ledger
->ledger_self
);
147 root_paged_ledger
= ledger_allocate(LEDGER_ITEM_INFINITY
,
148 LEDGER_NULL
, LEDGER_NULL
);
149 if (root_paged_ledger
== LEDGER_NULL
)
150 panic("can't allocate root (paged) ledger");
151 ipc_port_make_send(root_paged_ledger
->ledger_self
);
155 * Create a subordinate ledger
157 kern_return_t
ledger_create(
158 ledger_t parent_ledger
,
159 ledger_t ledger_ledger
,
160 ledger_t
*new_ledger
,
161 ledger_item_t transfer
)
163 if (parent_ledger
== LEDGER_NULL
)
164 return(KERN_INVALID_ARGUMENT
);
166 if (ledger_ledger
== LEDGER_NULL
)
167 return(KERN_INVALID_LEDGER
);
170 * Allocate a new ledger and change the ledger_ledger for
173 ledger_lock(ledger_ledger
);
174 if ((ledger_ledger
->ledger_limit
!= LEDGER_ITEM_INFINITY
) &&
175 (ledger_ledger
->ledger_balance
+ sizeof(ledger_data_t
) >
176 ledger_ledger
->ledger_limit
)) {
177 ledger_unlock(ledger_ledger
);
178 return(KERN_RESOURCE_SHORTAGE
);
181 *new_ledger
= ledger_allocate(LEDGER_ITEM_INFINITY
, ledger_ledger
, parent_ledger
);
182 if (*new_ledger
== LEDGER_NULL
) {
183 ledger_unlock(ledger_ledger
);
184 return(KERN_RESOURCE_SHORTAGE
);
188 * Now transfer the limit for the new ledger from the parent
190 ledger_lock(parent_ledger
);
191 if (parent_ledger
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
192 /* Would the existing balance exceed the new limit ? */
193 if (parent_ledger
->ledger_limit
- transfer
< parent_ledger
->ledger_balance
) {
194 ledger_unlock(parent_ledger
);
195 ledger_unlock(ledger_ledger
);
196 return(KERN_RESOURCE_SHORTAGE
);
198 if (parent_ledger
->ledger_limit
- transfer
> 0)
199 parent_ledger
->ledger_limit
-= transfer
;
201 parent_ledger
->ledger_limit
= 0;
203 (*new_ledger
)->ledger_limit
= transfer
;
205 /* Charge the ledger against the ledger_ledger */
206 ledger_ledger
->ledger_balance
+= sizeof(ledger_data_t
);
207 ledger_unlock(parent_ledger
);
209 ledger_unlock(ledger_ledger
);
211 return(KERN_SUCCESS
);
217 kern_return_t
ledger_terminate(
220 if (ledger
== LEDGER_NULL
)
221 return(KERN_INVALID_ARGUMENT
);
223 /* You can't deallocate kernel ledgers */
224 if (ledger
== root_wired_ledger
||
225 ledger
== root_paged_ledger
)
226 return(KERN_INVALID_LEDGER
);
228 /* Lock the ledger */
231 /* the parent ledger gets back the limit */
232 ledger_lock(ledger
->ledger_parent
);
233 if (ledger
->ledger_parent
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
234 assert((natural_t
)(ledger
->ledger_parent
->ledger_limit
+
235 ledger
->ledger_limit
) <
236 LEDGER_ITEM_INFINITY
);
237 ledger
->ledger_parent
->ledger_limit
+= ledger
->ledger_limit
;
239 ledger_unlock(ledger
->ledger_parent
);
242 * XXX The spec says that you have to destroy all objects that
243 * have been created with this ledger. Nice work eh? For now
244 * Transfer the balance to the parent and let it worry about
247 /* XXX the parent ledger inherits the debt ?? */
248 (void) ledger_enter(ledger
->ledger_parent
, ledger
->ledger_balance
);
250 /* adjust the balance of the creation ledger */
251 (void) ledger_enter(ledger
->ledger_ledger
, -sizeof(*ledger
));
253 /* delete the ledger */
254 ledger_deallocate(ledger
);
256 return(KERN_SUCCESS
);
260 * Return the ledger limit and balance
262 kern_return_t
ledger_read(
264 ledger_item_t
*balance
,
265 ledger_item_t
*limit
)
267 if (ledger
== LEDGER_NULL
)
268 return(KERN_INVALID_ARGUMENT
);
271 *balance
= ledger
->ledger_balance
;
272 *limit
= ledger
->ledger_limit
;
273 ledger_unlock(ledger
);
275 return(KERN_SUCCESS
);
279 * Transfer resources from a parent ledger to a child
281 kern_return_t
ledger_transfer(
282 ledger_t parent_ledger
,
283 ledger_t child_ledger
,
284 ledger_item_t transfer
)
286 #define abs(v) ((v) > 0)?(v):-(v)
289 ledger_item_t amount
= abs(transfer
);
291 if (parent_ledger
== LEDGER_NULL
)
292 return(KERN_INVALID_ARGUMENT
);
294 if (child_ledger
== LEDGER_NULL
)
295 return(KERN_INVALID_ARGUMENT
);
297 /* Must be different ledgers */
298 if (parent_ledger
== child_ledger
)
299 return(KERN_INVALID_ARGUMENT
);
302 return(KERN_SUCCESS
);
304 ledger_lock(child_ledger
);
305 ledger_lock(parent_ledger
);
307 /* XXX Should be the parent you created it from ?? */
308 if (parent_ledger
!= child_ledger
->ledger_parent
) {
309 ledger_unlock(parent_ledger
);
310 ledger_unlock(child_ledger
);
311 return(KERN_INVALID_LEDGER
);
320 dest
= parent_ledger
;
323 if (src
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
324 /* Would the existing balance exceed the new limit ? */
325 if (src
->ledger_limit
- amount
< src
->ledger_balance
) {
326 ledger_unlock(parent_ledger
);
327 ledger_unlock(child_ledger
);
328 return(KERN_RESOURCE_SHORTAGE
);
330 if (src
->ledger_limit
- amount
> 0)
331 src
->ledger_limit
-= amount
;
333 src
->ledger_limit
= 0;
336 if (dest
->ledger_limit
!= LEDGER_ITEM_INFINITY
) {
337 if ((natural_t
)(dest
->ledger_limit
+ amount
)
338 < LEDGER_ITEM_INFINITY
)
339 dest
->ledger_limit
+= amount
;
341 dest
->ledger_limit
= (LEDGER_ITEM_INFINITY
- 1);
344 ledger_unlock(parent_ledger
);
345 ledger_unlock(child_ledger
);
347 return(KERN_SUCCESS
);
352 * Routine: convert_port_to_ledger
354 * Convert from a port to a ledger.
355 * Doesn't consume the port ref; the ledger produced may be null.
361 convert_port_to_ledger(
364 ledger_t ledger
= LEDGER_NULL
;
366 if (IP_VALID(port
)) {
368 if (ip_active(port
) &&
369 (ip_kotype(port
) == IKOT_LEDGER
))
370 ledger
= (ledger_t
) port
->ip_kobject
;
378 * Routine: convert_ledger_to_port
380 * Convert from a ledger to a port.
381 * Produces a naked send right which may be invalid.
387 convert_ledger_to_port(
392 port
= ipc_port_make_send(ledger
->ledger_self
);
404 /* XXX reference counting */
406 return(ipc_port_copy_send(ledger
->ledger_self
));