|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
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.
11: *
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
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /*
23: * @OSF_COPYRIGHT@
24: */
25: /*
26: * HISTORY
27: *
28: * Revision 1.1.1.1 1998/09/22 21:05:34 wsanchez
29: * Import of Mac OS X kernel (~semeria)
30: *
31: * Revision 1.1.1.1 1998/03/07 02:25:55 wsanchez
32: * Import of OSF Mach kernel (~mburg)
33: *
34: * Revision 1.1.6.1 1995/01/06 19:47:19 devrcs
35: * mk6 CR668 - 1.3b26 merge
36: * new file for mk6
37: * [1994/10/12 22:19:28 dwm]
38: *
39: * Revision 1.1.3.4 1994/05/13 20:10:01 tmt
40: * Changed three unsigned casts to natural_t.
41: * [1994/05/12 22:12:28 tmt]
42: *
43: * Revision 1.1.3.2 1993/11/30 18:26:24 jph
44: * CR10228 -- Typo in unlock(), ledger_ledger should be child_ledger.
45: * [1993/11/30 16:10:43 jph]
46: *
47: * Revision 1.1.3.1 1993/11/24 21:22:14 jph
48: * CR9801 brezak merge, ledgers, security and NMK15_COMPAT
49: * [1993/11/23 22:41:07 jph]
50: *
51: * Revision 1.1.1.4 1993/09/08 14:17:36 brezak
52: * Include <mach/ledger_server.h> for protos.
53: *
54: * Revision 1.1.1.3 1993/08/20 14:16:55 brezak
55: * Created.
56: *
57: * $EndLog$
58: */
59:
60: /*
61: * 8/13/93
62: *
63: * This is a half-hearted attempt at providing the parts of the
64: * ledger facility to satisfy the ledger interfaces.
65: *
66: * This implementation basically leaves the (dysfunctional) ledgers
67: * unfunctional and are mearly here to satisfy the Mach spec interface
68: * reqirements.
69: */
70:
71: #include <mach/mach_types.h>
72: #include <mach/message.h>
73: #include <kern/mach_param.h>
74: #include <kern/misc_protos.h>
75: #include <mach/port.h>
76: #include <kern/lock.h>
77: #include <kern/ipc_kobject.h>
78: #include <ipc/ipc_space.h>
79: #include <ipc/ipc_port.h>
80: #include <kern/host.h>
81: #include <kern/ledger.h>
82: #include <mach/ledger_server.h>
83:
84: ledger_t root_wired_ledger;
85: ledger_t root_paged_ledger;
86:
87:
88: /* Utility routine to handle entries to a ledger */
89: kern_return_t
90: ledger_enter(
91: ledger_t ledger,
92: ledger_item_t amount)
93: {
94: /* Need to lock the ledger */
95: ledger_lock(ledger);
96:
97: if (amount > 0) {
98: if (ledger->ledger_limit != LEDGER_ITEM_INFINITY &&
99: ledger->ledger_balance + amount > ledger->ledger_limit) {
100: /* XXX this is where you do BAD things */
101: printf("Ledger limit exceeded ! ledger=%x lim=%d balance=%d\n",
102: ledger, ledger->ledger_limit,
103: ledger->ledger_balance);
104: ledger_unlock(ledger);
105: return(KERN_RESOURCE_SHORTAGE);
106: }
107: if ((natural_t)(ledger->ledger_balance + amount)
108: < LEDGER_ITEM_INFINITY)
109: ledger->ledger_balance += amount;
110: else
111: ledger->ledger_balance = LEDGER_ITEM_INFINITY;
112: }
113: else if (amount) {
114: if (ledger->ledger_balance + amount > 0)
115: ledger->ledger_balance += amount;
116: else
117: ledger->ledger_balance = 0;
118: }
119: ledger_unlock(ledger);
120: return(KERN_SUCCESS);
121: }
122:
123: /* Utility routine to create a new ledger */
124: static ledger_t
125: ledger_allocate(
126: ledger_item_t limit,
127: ledger_t ledger_ledger,
128: ledger_t ledger_parent)
129: {
130: ledger_t ledger;
131:
132: ledger = (ledger_t)kalloc(sizeof(ledger_data_t));
133: if (ledger == LEDGER_NULL)
134: return(LEDGER_NULL);
135:
136: ledger->ledger_self = ipc_port_alloc_kernel();
137: if (ledger->ledger_self == IP_NULL)
138: return(LEDGER_NULL);
139:
140: ledger_lock_init(ledger);
141: ledger->ledger_limit = limit;
142: ledger->ledger_balance = 0;
143: ledger->ledger_service_port = MACH_PORT_NULL;
144: ledger->ledger_ledger = ledger_ledger;
145: ledger->ledger_parent = ledger_parent;
146: ipc_kobject_set(ledger->ledger_self, (ipc_kobject_t)ledger,
147: IKOT_LEDGER);
148:
149: return(ledger);
150: }
151:
152: /* Utility routine to destroy a ledger */
153: static void
154: ledger_deallocate(
155: ledger_t ledger)
156: {
157: /* XXX can be many send rights (copies) of this */
158: ipc_port_dealloc_kernel(ledger->ledger_self);
159:
160: /* XXX release send right on service port */
161: kfree((vm_offset_t)ledger, sizeof(*ledger));
162: }
163:
164:
165: /*
166: * Inititalize the ledger facility
167: */
168: void ledger_init(void)
169: {
170: /*
171: * Allocate the root ledgers; wired and paged.
172: */
173: root_wired_ledger = ledger_allocate(LEDGER_ITEM_INFINITY,
174: LEDGER_NULL, LEDGER_NULL);
175: if (root_wired_ledger == LEDGER_NULL)
176: panic("can't allocate root (wired) ledger");
177: ipc_port_make_send(root_wired_ledger->ledger_self);
178:
179: root_paged_ledger = ledger_allocate(LEDGER_ITEM_INFINITY,
180: LEDGER_NULL, LEDGER_NULL);
181: if (root_paged_ledger == LEDGER_NULL)
182: panic("can't allocate root (paged) ledger");
183: ipc_port_make_send(root_paged_ledger->ledger_self);
184: }
185:
186: /*
187: * Create a subordinate ledger
188: */
189: kern_return_t ledger_create(
190: ledger_t parent_ledger,
191: ledger_t ledger_ledger,
192: ledger_t *new_ledger,
193: ledger_item_t transfer)
194: {
195: if (parent_ledger == LEDGER_NULL)
196: return(KERN_INVALID_ARGUMENT);
197:
198: if (ledger_ledger == LEDGER_NULL)
199: return(KERN_INVALID_LEDGER);
200:
201: /*
202: * Allocate a new ledger and change the ledger_ledger for
203: * its space.
204: */
205: ledger_lock(ledger_ledger);
206: if ((ledger_ledger->ledger_limit != LEDGER_ITEM_INFINITY) &&
207: (ledger_ledger->ledger_balance + sizeof(ledger_data_t) >
208: ledger_ledger->ledger_limit)) {
209: ledger_unlock(ledger_ledger);
210: return(KERN_RESOURCE_SHORTAGE);
211: }
212:
213: *new_ledger = ledger_allocate(LEDGER_ITEM_INFINITY, ledger_ledger, parent_ledger);
214: if (*new_ledger == LEDGER_NULL) {
215: ledger_unlock(ledger_ledger);
216: return(KERN_RESOURCE_SHORTAGE);
217: }
218:
219: /*
220: * Now transfer the limit for the new ledger from the parent
221: */
222: ledger_lock(parent_ledger);
223: if (parent_ledger->ledger_limit != LEDGER_ITEM_INFINITY) {
224: /* Would the existing balance exceed the new limit ? */
225: if (parent_ledger->ledger_limit - transfer < parent_ledger->ledger_balance) {
226: ledger_unlock(parent_ledger);
227: ledger_unlock(ledger_ledger);
228: return(KERN_RESOURCE_SHORTAGE);
229: }
230: if (parent_ledger->ledger_limit - transfer > 0)
231: parent_ledger->ledger_limit -= transfer;
232: else
233: parent_ledger->ledger_limit = 0;
234: }
235: (*new_ledger)->ledger_limit = transfer;
236:
237: /* Charge the ledger against the ledger_ledger */
238: ledger_ledger->ledger_balance += sizeof(ledger_data_t);
239: ledger_unlock(parent_ledger);
240:
241: ledger_unlock(ledger_ledger);
242:
243: return(KERN_SUCCESS);
244: }
245:
246: /*
247: * Get the remote ledger service port
248: */
249: kern_return_t ledger_get_remote(
250: ledger_t ledger,
251: host_t host,
252: ledger_t *service)
253: {
254: if (ledger == LEDGER_NULL)
255: return(KERN_INVALID_ARGUMENT);
256:
257: if (host == HOST_NULL)
258: return(KERN_INVALID_ARGUMENT);
259:
260: /* XXX if host != this host, call remote host */
261: ledger_lock(ledger);
262: *service = convert_port_to_ledger(ledger->ledger_service_port);
263: ledger_unlock(ledger);
264:
265: return(KERN_SUCCESS);
266: }
267:
268: /*
269: * Return the ledger limit and balance
270: */
271: kern_return_t ledger_read(
272: ledger_t ledger,
273: ledger_item_t *balance,
274: ledger_item_t *limit)
275: {
276: if (ledger == LEDGER_NULL)
277: return(KERN_INVALID_ARGUMENT);
278:
279: ledger_lock(ledger);
280: *balance = ledger->ledger_balance;
281: *limit = ledger->ledger_limit;
282: ledger_unlock(ledger);
283:
284: return(KERN_SUCCESS);
285: }
286:
287: /*
288: * Sets the remote ledger service port
289: */
290: kern_return_t ledger_set_remote(
291: ledger_t ledger,
292: ledger_t service)
293: {
294: if (ledger == LEDGER_NULL)
295: return(KERN_INVALID_ARGUMENT);
296:
297: /* XXX Check that service port is a port */
298:
299: ledger_lock(ledger);
300: ledger->ledger_service_port = service->ledger_self;
301: ledger_unlock(ledger);
302:
303: return(KERN_SUCCESS);
304: }
305:
306: /*
307: * Destroy a ledger
308: */
309: kern_return_t ledger_terminate(
310: ledger_t ledger)
311: {
312: if (ledger == LEDGER_NULL)
313: return(KERN_INVALID_ARGUMENT);
314:
315: /* You can't deallocate kernel ledgers */
316: if (ledger == root_wired_ledger ||
317: ledger == root_paged_ledger)
318: return(KERN_INVALID_LEDGER);
319:
320: /* Lock the ledger */
321: ledger_lock(ledger);
322:
323: /* the parent ledger gets back the limit */
324: ledger_lock(ledger->ledger_parent);
325: if (ledger->ledger_parent->ledger_limit != LEDGER_ITEM_INFINITY) {
326: assert((natural_t)(ledger->ledger_parent->ledger_limit +
327: ledger->ledger_limit) <
328: LEDGER_ITEM_INFINITY);
329: ledger->ledger_parent->ledger_limit += ledger->ledger_limit;
330: }
331: ledger_unlock(ledger->ledger_parent);
332:
333: /*
334: * XXX The spec says that you have to destroy all objects that
335: * have been created with this ledger. Nice work eh? For now
336: * Transfer the balance to the parent and let it worry about
337: * it.
338: */
339: /* XXX the parent ledger inherits the debt ?? */
340: (void) ledger_enter(ledger->ledger_parent, ledger->ledger_balance);
341:
342: /* adjust the balance of the creation ledger */
343: (void) ledger_enter(ledger->ledger_ledger, -sizeof(*ledger));
344:
345: /* delete the ledger */
346: ledger_deallocate(ledger);
347:
348: return(KERN_SUCCESS);
349: }
350:
351: /*
352: * Transfer resources from a parent ledger to a child
353: */
354: kern_return_t ledger_transfer(
355: ledger_t parent_ledger,
356: ledger_t child_ledger,
357: ledger_item_t transfer)
358: {
359: #define abs(v) ((v) > 0)?(v):-(v)
360:
361: ledger_t src, dest;
362: ledger_item_t amount = abs(transfer);
363:
364: if (parent_ledger == LEDGER_NULL)
365: return(KERN_INVALID_ARGUMENT);
366:
367: if (child_ledger == LEDGER_NULL)
368: return(KERN_INVALID_ARGUMENT);
369:
370: /* Must be different ledgers */
371: if (parent_ledger == child_ledger)
372: return(KERN_INVALID_ARGUMENT);
373:
374: if (transfer == 0)
375: return(KERN_SUCCESS);
376:
377: ledger_lock(child_ledger);
378: ledger_lock(parent_ledger);
379:
380: /* XXX Should be the parent you created it from ?? */
381: if (parent_ledger != child_ledger->ledger_parent) {
382: ledger_unlock(parent_ledger);
383: ledger_unlock(child_ledger);
384: return(KERN_INVALID_LEDGER);
385: }
386:
387: if (transfer > 0) {
388: dest = child_ledger;
389: src = parent_ledger;
390: }
391: else {
392: src = child_ledger;
393: dest = parent_ledger;
394: }
395:
396: if (src->ledger_limit != LEDGER_ITEM_INFINITY) {
397: /* Would the existing balance exceed the new limit ? */
398: if (src->ledger_limit - amount < src->ledger_balance) {
399: ledger_unlock(parent_ledger);
400: ledger_unlock(child_ledger);
401: return(KERN_RESOURCE_SHORTAGE);
402: }
403: if (src->ledger_limit - amount > 0)
404: src->ledger_limit -= amount;
405: else
406: src->ledger_limit = 0;
407: }
408:
409: if (dest->ledger_limit != LEDGER_ITEM_INFINITY) {
410: if ((natural_t)(dest->ledger_limit + amount)
411: < LEDGER_ITEM_INFINITY)
412: dest->ledger_limit += amount;
413: else
414: dest->ledger_limit = (LEDGER_ITEM_INFINITY - 1);
415: }
416:
417: ledger_unlock(parent_ledger);
418: ledger_unlock(child_ledger);
419:
420: return(KERN_SUCCESS);
421: #undef abs
422: }
423:
424: /*
425: * Routine: convert_port_to_ledger
426: * Purpose:
427: * Convert from a port to a ledger.
428: * Doesn't consume the port ref; the ledger produced may be null.
429: * Conditions:
430: * Nothing locked.
431: */
432:
433: ledger_t
434: convert_port_to_ledger(
435: ipc_port_t port)
436: {
437: ledger_t ledger = LEDGER_NULL;
438:
439: if (IP_VALID(port)) {
440: ip_lock(port);
441: if (ip_active(port) &&
442: (ip_kotype(port) == IKOT_LEDGER))
443: ledger = (ledger_t) port->ip_kobject;
444: ip_unlock(port);
445: }
446:
447: return ledger;
448: }
449:
450: /*
451: * Routine: convert_ledger_to_port
452: * Purpose:
453: * Convert from a ledger to a port.
454: * Produces a naked send right which may be invalid.
455: * Conditions:
456: * Nothing locked.
457: */
458:
459: ipc_port_t
460: convert_ledger_to_port(
461: ledger_t ledger)
462: {
463: ipc_port_t port;
464:
465: port = ipc_port_make_send(ledger->ledger_self);
466:
467: return port;
468: }
469:
470: /*
471: * Copy a ledger
472: */
473: ipc_port_t
474: ledger_copy(
475: ledger_t ledger)
476: {
477: /* XXX reference counting */
478: assert(ledger);
479: return(ipc_port_copy_send(ledger->ledger_self));
480: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.