|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999, 2000 University of Utah and the Flux Group. ! 3: * All rights reserved. ! 4: * ! 5: * This file is part of the Flux OSKit. The OSKit is free software, also known ! 6: * as "open source;" you can redistribute it and/or modify it under the terms ! 7: * of the GNU General Public License (GPL), version 2, as published by the Free ! 8: * Software Foundation (FSF). To explore alternate licensing terms, contact ! 9: * the University of Utah at [email protected] or +1-801-585-3271. ! 10: * ! 11: * The OSKit is distributed in the hope that it will be useful, but WITHOUT ANY ! 12: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS ! 13: * FOR A PARTICULAR PURPOSE. See the GPL for more details. You should have ! 14: * received a copy of the GPL along with the OSKit; see the file COPYING. If ! 15: * not, write to the FSF, 59 Temple Place #330, Boston, MA 02111-1307, USA. ! 16: */ ! 17: ! 18: #include <oskit/com.h> ! 19: #include <oskit/com/mem.h> ! 20: #include <oskit/com/services.h> ! 21: #include <oskit/dev/dev.h> ! 22: #include <oskit/dev/osenv_mem.h> ! 23: ! 24: #include <oskit/lmm.h> ! 25: #include <oskit/machine/base_vm.h> ! 26: #include <oskit/machine/physmem.h> ! 27: #include <oskit/machine/phys_lmm.h> ! 28: ! 29: #include <string.h> ! 30: ! 31: #include <cpus.h> ! 32: #include "lock.h" ! 33: #include "kalloc.h" ! 34: #include "zalloc.h" ! 35: #include "assert.h" ! 36: #include <machine/spl.h> ! 37: ! 38: #include <vm/vm_kern.h> ! 39: ! 40: #include "ds_oskit.h" ! 41: ! 42: #define in_oskit_interrupt (nested_pic_mask != 0) ! 43: extern unsigned int nested_pic_mask; /* osenv_irq.c */ ! 44: ! 45: decl_simple_lock_data(, phys_lmm_lock) ! 46: decl_simple_lock_data(extern, vm_page_queue_free_lock) ! 47: ! 48: extern int vm_page_unqueued_count; /* vm_resident.c */ ! 49: extern zone_t vm_page_zone; ! 50: extern vm_offset_t virtual_space_start; ! 51: extern vm_offset_t virtual_space_end; ! 52: ! 53: int lmm_wants_pages; ! 54: ! 55: #define debug_protect_page(p) ((void)(p)) ! 56: #define debug_unprotect_page(p) ((void)(p)) ! 57: ! 58: ! 59: /* Update the VM system's counts of free pages in the LMM. ! 60: Called at sploskit with phys_lmm_lock held. */ ! 61: static void ! 62: update_counts (void) ! 63: { ! 64: vm_page_unqueued_count = atop (lmm_avail (&malloc_lmm, 0)); ! 65: } ! 66: ! 67: ! 68: void * ! 69: alloc_for_oskit (oskit_size_t size, osenv_memflags_t flags, unsigned align) ! 70: { ! 71: kern_return_t kr; ! 72: lmm_flags_t lmm_flags; ! 73: ! 74: assert (align <= size); ! 75: ! 76: if (flags & OSENV_AUTO_SIZE) ! 77: { ! 78: oskit_size_t *p; ! 79: size += sizeof (oskit_size_t); ! 80: if (align > sizeof (oskit_size_t)) ! 81: panic ("autosize + align %u", align); ! 82: /* XXX how would I recover the beginning of the block in free? ! 83: size += align - sizeof (oskit_size_t); ! 84: */ ! 85: else ! 86: align = sizeof (oskit_size_t); ! 87: p = alloc_for_oskit (size, flags &~ OSENV_AUTO_SIZE, align); ! 88: if (p == 0) ! 89: return 0; ! 90: p = (void *) (((oskit_addr_t) (p + 1) + align - 1) &~ (align - 1)); ! 91: p[-1] = size; ! 92: return p; ! 93: } ! 94: ! 95: lmm_flags = (((flags & OSENV_ISADMA_MEM) ? LMMF_16MB : 0) ! 96: | ((flags & OSENV_X861MB_MEM) ? LMMF_1MB : 0)); ! 97: ! 98: if (lmm_flags != 0) ! 99: assert (flags & OSENV_VIRT_EQ_PHYS); ! 100: ! 101: if (mach_osenv == 0) ! 102: /* This is early oskit startup code before the kernel is set up. ! 103: Always go directly to physical memory. */ ! 104: flags |= OSENV_VIRT_EQ_PHYS|OSENV_PHYS_WIRED|OSENV_PHYS_CONTIG; ! 105: ! 106: if (in_oskit_interrupt) ! 107: /* The oskit documentation says an interrupt caller must set the flag. */ ! 108: assert (flags & OSENV_NONBLOCKING); ! 109: ! 110: if (!(flags & (OSENV_NONBLOCKING|OSENV_PHYS_WIRED))) ! 111: { ! 112: /* Unwired virtual memory will do. */ ! 113: ! 114: if (size < PAGE_SIZE) ! 115: /* For less than a page we don't want to waste partial pages, ! 116: and we don't want to bother with a second-tier allocator ! 117: for virtual memory, so just give him wired memory. */ ! 118: return (void *) kalloc (size); ! 119: else ! 120: { ! 121: vm_offset_t addr; ! 122: kr = kmem_alloc_pageable (kernel_map, &addr, size); ! 123: return kr ? 0 : (void *) addr; ! 124: } ! 125: } ! 126: ! 127: if (!(flags & (OSENV_VIRT_EQ_PHYS|OSENV_NONBLOCKING)) ! 128: && (!(flags & OSENV_PHYS_CONTIG) || size <= PAGE_SIZE)) ! 129: { ! 130: /* Wired virtual memory will do. */ ! 131: return (void *) kalloc (size); ! 132: } ! 133: ! 134: /* We need physically contiguous memory. This we get directly from the ! 135: lmm, which might also be used by vm_page_grab. All users of the lmm ! 136: must go to sploskit or above and take the phys_lmm_lock. This blocks ! 137: out any interrupts that might go to the oskit (and get us here). */ ! 138: while (1) ! 139: { ! 140: spl_t s; ! 141: void *block; ! 142: ! 143: s = sploskit (); ! 144: simple_lock (&phys_lmm_lock); ! 145: ! 146: if (align) ! 147: block = lmm_alloc_aligned (&malloc_lmm, size, lmm_flags, ! 148: ffs (align) - 1, 0); ! 149: else ! 150: block = lmm_alloc (&malloc_lmm, size, lmm_flags); ! 151: ! 152: update_counts (); ! 153: ! 154: simple_unlock (&phys_lmm_lock); ! 155: splx (s); ! 156: ! 157: if (block) ! 158: return block; ! 159: ! 160: if (flags & OSENV_NONBLOCKING) ! 161: return 0; ! 162: ! 163: /* There is no space in the lmm. There may well be pages available on ! 164: the VM system's free list. If we're sure we are not being called ! 165: from an interrupt handler here, which we should be guaranteed by ! 166: checking for OSENV_NONBLOCKING, then we can just access the free ! 167: list directly here (vm_page_grab). Another approach is to just wake ! 168: up the pageout daemon to have it find some pages for the lmm and ! 169: then block until it wakes us up. lmm_wants_pages accumulates the ! 170: number of pages wanted by blocked threads like ourselves. ! 171: consider_lmm_collect will produce some memory, set lmm_want_pages to ! 172: zero, and wake up all blocked threads to retry their allocations. */ ! 173: lmm_wants_pages += atop (round_page (size)); ! 174: thread_wakeup_one ((event_t)&vm_page_queue_free_count); ! 175: assert_wait ((event_t)&lmm_wants_pages, FALSE); ! 176: thread_block (0); ! 177: /* The pageout daemon woke us up (see consider_lmm_collect) ! 178: after putting some memory back into the LMM for us. ! 179: XXX make sure we don't loop in livelock? */ ! 180: } ! 181: } ! 182: ! 183: ! 184: void ! 185: free_for_oskit (void *block, osenv_memflags_t flags, oskit_size_t size) ! 186: { ! 187: if (flags & OSENV_AUTO_SIZE) ! 188: { ! 189: oskit_size_t *p = block; ! 190: size = *--p; ! 191: block = p; ! 192: } ! 193: ! 194: if (mach_osenv == 0) ! 195: /* This is early oskit startup code before the kernel is set up. ! 196: Always go directly to physical memory. */ ! 197: flags |= OSENV_VIRT_EQ_PHYS|OSENV_PHYS_WIRED|OSENV_PHYS_CONTIG; ! 198: ! 199: #if 0 ! 200: if (in_oskit_interrupt) ! 201: /* The oskit documentation says an interrupt caller must set the flag. */ ! 202: assert (flags & OSENV_NONBLOCKING); ! 203: #endif /* ... but oskit/linux/shared/s_kmem.c doesn't. */ ! 204: ! 205: if ((oskit_addr_t) block < phys_mem_max) ! 206: { ! 207: /* We got physical memory directly from the lmm. */ ! 208: spl_t s; ! 209: ! 210: s = sploskit (); ! 211: simple_lock (&phys_lmm_lock); ! 212: ! 213: lmm_free (&malloc_lmm, block, size); ! 214: update_counts (); ! 215: ! 216: simple_unlock (&phys_lmm_lock); ! 217: splx (s); ! 218: } ! 219: else ! 220: { ! 221: if (in_oskit_interrupt) ! 222: { ! 223: /* This should be impossible if the caller (oskit) is consistent ! 224: in its use of OSENV_NONBLOCKING for allocations and ! 225: deallocations. alloc_for_oskit will always get physical ! 226: memory when called with the flag set. */ ! 227: panic ("free_for_oskit of virtual memory from interrupt level"); ! 228: /* If this ever happens, make a little free list and have the ! 229: pageout daemon run over it doing kfree. */ ! 230: } ! 231: else ! 232: kfree ((vm_offset_t) block, size); ! 233: } ! 234: } ! 235: ! 236: ! 237: /*** Entry points from the VM system. ***/ ! 238: ! 239: ! 240: /* Called only from vm_page_bootstrap, only for estimate. */ ! 241: unsigned int pmap_free_pages() ! 242: { ! 243: return atop (lmm_avail (&malloc_lmm, 0)); ! 244: } ! 245: ! 246: ! 247: /* This is called from pmap_bootstrap for kernel page table pages, and from ! 248: pmap_steal_memory for physical pages to back kernel virtual memory ! 249: allocated in early Mach startup. */ ! 250: vm_offset_t ! 251: pmap_grab_page (void) ! 252: { ! 253: void *page = lmm_alloc_page (&malloc_lmm, 0); ! 254: if (page == 0) ! 255: panic ("Not enough memory to initialize Mach"); ! 256: return (vm_offset_t) page; ! 257: } ! 258: ! 259: int ! 260: init_alloc (vm_size_t size, vm_offset_t *p) ! 261: { ! 262: void *block = lmm_alloc (&malloc_lmm, size, 0); ! 263: if (block == 0) ! 264: return 0; ! 265: *p = (vm_offset_t) block; ! 266: return 1; ! 267: } ! 268: ! 269: ! 270: /* in zalloc.c XXX */ ! 271: extern vm_offset_t zdata; ! 272: extern vm_size_t zdata_size; ! 273: ! 274: ! 275: void pmap_startup( ! 276: vm_offset_t *startp, ! 277: vm_offset_t *endp) ! 278: { ! 279: unsigned int i, npages, initial_pages; ! 280: vm_page_t pages; ! 281: ! 282: /* Calculate how many pages can possibly go into the VM pool, ! 283: taking into account the space required for each page's own ! 284: vm_page_t structure. */ ! 285: npages = ((lmm_avail (&malloc_lmm, 0) - round_page(zdata_size)) / ! 286: (PAGE_SIZE + sizeof *pages)); ! 287: ! 288: /* We will allocate a quarter of the pages to start with. ! 289: That ought to be plenty enough to get the kernel up and running. ! 290: Once the pageout daemon has started, it will equalize the ! 291: free page queue and LMM free pool sizes. */ ! 292: initial_pages = npages / 4; ! 293: ! 294: /* Steal some memory for the zone system, including enough ! 295: to cover the initial vm_page structures we will steal. */ ! 296: zdata_size = (round_page (virtual_space_start + zdata_size + ! 297: initial_pages * sizeof *pages) ! 298: - virtual_space_start); ! 299: zdata = pmap_steal_memory (zdata_size); ! 300: ! 301: /* Steal vm_page structures from the zone system, ! 302: and physical pages from the LMM. */ ! 303: pages = (void *) zdata; ! 304: for (i = 0; i < initial_pages; ++i) ! 305: { ! 306: vm_page_t mem = pages++; ! 307: void *page = lmm_alloc_page (&malloc_lmm, 0); ! 308: vm_page_init (mem, (vm_offset_t) page); ! 309: debug_protect_page (page); ! 310: vm_page_release (mem, FALSE); ! 311: } ! 312: ! 313: /* Account for the memory swiped for vm_page structures, ! 314: and return the rest of the stolen memory to the zone system. */ ! 315: zdata_size = zdata + zdata_size - (vm_offset_t) pages; ! 316: zdata = (vm_offset_t) pages; ! 317: ! 318: /* Set the initial record of the number of pages available in the ! 319: LMM to a deliberate lie. This value will be used to set paging ! 320: algorithm parameters that should be based on what things look ! 321: like with all available physical pages in the VM pool. So here ! 322: we use the calculation that takes into account the overhead of ! 323: vm_page_t structures that we will have to consume to put pages ! 324: into the pool. Counting the free pages in the LMM will show ! 325: more pages available than we admit, since we haven't allocated ! 326: all of those structures up front. As soon as the pageout daemon ! 327: gets started up, it will recalculate from the LMM. */ ! 328: vm_page_unqueued_count = npages - initial_pages; ! 329: ! 330: ! 331: /* ! 332: * We have to re-align virtual_space_start, ! 333: * because pmap_steal_memory has been using it. ! 334: */ ! 335: ! 336: virtual_space_start = round_page(virtual_space_start); ! 337: ! 338: *startp = virtual_space_start; ! 339: *endp = virtual_space_end; ! 340: } ! 341: ! 342: ! 343: void ! 344: vm_page_grab_oskit_page (void) ! 345: { ! 346: void *page; ! 347: vm_page_t m; ! 348: ! 349: do ! 350: { ! 351: spl_t s = sploskit (); ! 352: simple_lock (&phys_lmm_lock); ! 353: ! 354: page = lmm_alloc_page (&malloc_lmm, 0); ! 355: ! 356: update_counts (); ! 357: ! 358: debug_protect_page (page); ! 359: simple_unlock (&phys_lmm_lock); ! 360: splx (s); ! 361: ! 362: if (page == 0) ! 363: panic (__FUNCTION__); ! 364: ! 365: m = (vm_page_t) zget(vm_page_zone); ! 366: if (m == VM_PAGE_NULL) ! 367: { ! 368: /* The zone is out of space. A normal zalloc would call ! 369: kmem_alloc_wired and wind up recursing down to here trying to ! 370: get a page. So instead we just stuff a physical page directly ! 371: into the zone, and loop for a new one to satisfy our caller. */ ! 372: debug_unprotect_page (page); ! 373: zcram(vm_page_zone, (vm_offset_t) page, PAGE_SIZE); ! 374: } ! 375: } while (m == VM_PAGE_NULL); ! 376: ! 377: vm_page_init(m, (vm_offset_t) page); ! 378: vm_page_release(m, FALSE); ! 379: } ! 380: ! 381: ! 382: #define PAGE_BATCH 32 ! 383: ! 384: /* Called by the pageout daemon to see if the vm_page_free_queue ! 385: and the LMM want to tango. */ ! 386: ! 387: void ! 388: consider_lmm_collect (void) ! 389: { ! 390: spl_t s; ! 391: unsigned int need; ! 392: ! 393: /* First check if the LMM needs pages back for alloc_for_oskit calls. */ ! 394: if (vm_page_unqueued_count < lmm_wants_pages ! 395: || vm_page_queue_free_count > 8 * vm_page_unqueued_count) /* random */ ! 396: { ! 397: /* The LMM needs some physical pages back from the VM pool. */ ! 398: need = lmm_wants_pages > PAGE_BATCH ? lmm_wants_pages : PAGE_BATCH; ! 399: ! 400: while (need > 0) ! 401: { ! 402: unsigned int batch = need > PAGE_BATCH ? PAGE_BATCH : need; ! 403: void *pages[PAGE_BATCH]; ! 404: unsigned int i; ! 405: ! 406: for (i = 0; i < batch; ++i) ! 407: { ! 408: vm_page_t mem = vm_page_grab (FALSE); ! 409: if (mem == VM_PAGE_NULL) ! 410: break; ! 411: pages[i] = (void *) mem->phys_addr; ! 412: zfree (vm_page_zone, (vm_offset_t) mem); ! 413: debug_unprotect_page (pages[i]); ! 414: } ! 415: ! 416: s = sploskit (); ! 417: simple_lock (&phys_lmm_lock); ! 418: ! 419: while (i-- > 0) ! 420: lmm_free_page (&malloc_lmm, (void *) pages[i]); ! 421: ! 422: update_counts (); ! 423: ! 424: simple_unlock (&phys_lmm_lock); ! 425: splx (s); ! 426: ! 427: if (i < batch) ! 428: break; ! 429: need -= batch; ! 430: } ! 431: } ! 432: ! 433: /* If lmm_wants_pages is set, then some threads are blocked in ! 434: alloc_for_oskit. This might still be the case even if the memory was ! 435: released to the LMM before we ran so that we didn't do anything above. ! 436: We need to wake the blocked threads so they will all retry their ! 437: allocations. */ ! 438: if (lmm_wants_pages != 0) ! 439: { ! 440: lmm_wants_pages = 0; ! 441: thread_wakeup ((event_t)&lmm_wants_pages); ! 442: } ! 443: ! 444: /* Any time the VM pool has fewer free pages than the LMM does, ! 445: we give it half the LMM's free pages. */ ! 446: ! 447: if (vm_page_queue_free_count < vm_page_unqueued_count) ! 448: { ! 449: s = sploskit (); ! 450: simple_lock (&phys_lmm_lock); ! 451: ! 452: need = vm_page_unqueued_count / 2; ! 453: ! 454: /* We allocate only a single page at a time from the LMM, since we ! 455: don't need contiguous pages, and would rather use up fragmented ! 456: pages so as to leave the contiguous regions for those who need them. ! 457: ! 458: We must go to sploskit to call into the LMM, but back up to spl0 to ! 459: deliver the new pages to the VM system. We don't want to do this ! 460: for every single page allocation from the LMM, so we allocate ! 461: individual pages from the LMM in batches of PAGE_BATCH pages and ! 462: then reenable interrupts to deliver those pages before going back ! 463: for more. */ ! 464: ! 465: while (need > 0) ! 466: { ! 467: unsigned int batch = need > PAGE_BATCH ? PAGE_BATCH : need; ! 468: void *pages[PAGE_BATCH]; ! 469: unsigned int i; ! 470: ! 471: for (i = 0; i < batch; ++i) ! 472: { ! 473: /* This allocation should never fail, since we keep track ! 474: of the number of pages available in the lmm. */ ! 475: pages[i] = lmm_alloc_page (&malloc_lmm, 0); ! 476: if (pages[i] == 0) ! 477: panic ("LMM unexpectedly out of physical pages"); ! 478: debug_protect_page (pages[i]); ! 479: } ! 480: ! 481: update_counts (); ! 482: ! 483: simple_unlock (&phys_lmm_lock); ! 484: splx (s); ! 485: ! 486: while (i-- > 0) ! 487: vm_page_create ((vm_offset_t) pages[i], ! 488: (vm_offset_t) pages[i] + PAGE_SIZE); ! 489: ! 490: need -= batch; ! 491: if (need == 0) ! 492: break; ! 493: ! 494: s = sploskit (); ! 495: simple_lock (&phys_lmm_lock); ! 496: } ! 497: } ! 498: } ! 499: ! 500: ! 501: /*** oskit_osenv_mem_t COM object implementation ***/ ! 502: ! 503: ! 504: /* ! 505: * There is one and only one memory interface in this implementation. ! 506: */ ! 507: static struct oskit_osenv_mem_ops osenv_mem_ops; ! 508: static struct oskit_osenv_mem osenv_mem_object = {&osenv_mem_ops}; ! 509: ! 510: static OSKIT_COMDECL ! 511: mem_query(oskit_osenv_mem_t *s, const oskit_iid_t *iid, void **out_ihandle) ! 512: { ! 513: if (memcmp(iid, &oskit_iunknown_iid, sizeof(*iid)) == 0 || ! 514: memcmp(iid, &oskit_osenv_mem_iid, sizeof(*iid)) == 0) { ! 515: *out_ihandle = s; ! 516: return 0; ! 517: } ! 518: ! 519: *out_ihandle = 0; ! 520: return OSKIT_E_NOINTERFACE; ! 521: }; ! 522: ! 523: static OSKIT_COMDECL_U ! 524: mem_addref(oskit_osenv_mem_t *s) ! 525: { ! 526: /* Only one object */ ! 527: return 1; ! 528: } ! 529: ! 530: static OSKIT_COMDECL_U ! 531: mem_release(oskit_osenv_mem_t *s) ! 532: { ! 533: /* Only one object */ ! 534: return 1; ! 535: } ! 536: ! 537: static void * OSKIT_COMCALL ! 538: mem_alloc(oskit_osenv_mem_t *o, oskit_size_t size, ! 539: osenv_memflags_t flags, unsigned align) ! 540: { ! 541: return alloc_for_oskit (size, flags, align); ! 542: } ! 543: ! 544: static OSKIT_COMDECL_V ! 545: mem_free(oskit_osenv_mem_t *o, void *block, ! 546: osenv_memflags_t flags, oskit_size_t size) ! 547: { ! 548: free_for_oskit (block, flags, size); ! 549: } ! 550: ! 551: static oskit_addr_t OSKIT_COMCALL ! 552: mem_getphys(oskit_osenv_mem_t *o, oskit_addr_t va) ! 553: { ! 554: /* We can only use kvtophys for memory allocated with OSENV_PHYS_CONTIG. ! 555: But at least some code (e.g. eepro100 driver) will call us with an ! 556: address on a kernel stack and expect to get a physical address from that. ! 557: Checking the kernel pmap is a little heavy but should be correct in ! 558: all cases. */ ! 559: return pmap_extract (kernel_pmap, va); ! 560: } ! 561: ! 562: static oskit_addr_t OSKIT_COMCALL ! 563: mem_getvirt(oskit_osenv_mem_t *o, oskit_addr_t pa) ! 564: { ! 565: return ((oskit_addr_t)phystokv(pa)); ! 566: } ! 567: ! 568: static oskit_addr_t OSKIT_COMCALL ! 569: mem_physmax(oskit_osenv_mem_t *o) ! 570: { ! 571: return phys_mem_max; ! 572: } ! 573: ! 574: static OSKIT_COMDECL_U ! 575: mem_mapphys(oskit_osenv_mem_t *o, oskit_addr_t pa, ! 576: oskit_size_t size, void **addr, int flags) ! 577: { ! 578: kern_return_t kr; ! 579: vm_offset_t kva; ! 580: ! 581: if (trunc_page (pa) != 0 && ! 582: trunc_page (pa) >= trunc_page (phys_mem_min) && ! 583: round_page (pa + size) < round_page (phys_mem_max)) ! 584: { ! 585: /* Direct mapping already covers it. */ ! 586: *addr = (void *) phystokv (pa); ! 587: return 0; ! 588: } ! 589: ! 590: kr = kmem_alloc_pageable (kernel_map, &kva, round_page (size)); ! 591: if (kr) ! 592: return OSKIT_E_OUTOFMEMORY; ! 593: ! 594: pmap_map (kva, trunc_page (pa), round_page (pa + size), ! 595: VM_PROT_READ | VM_PROT_WRITE); ! 596: ! 597: *addr = (char *) kva + (pa & PAGE_MASK); ! 598: return 0; ! 599: } ! 600: ! 601: #if NCPUS > 1 ! 602: /* This function is used as a callback from smp_init_paging. */ ! 603: oskit_addr_t ! 604: smp_map_range (oskit_addr_t start, oskit_size_t size) ! 605: { ! 606: oskit_error_t err = mem_mapphys (0, start, size, (void **)&start, 0); ! 607: return err ? 0 : start; ! 608: } ! 609: #endif ! 610: ! 611: ! 612: static struct oskit_osenv_mem_ops osenv_mem_ops = { ! 613: mem_query, ! 614: mem_addref, ! 615: mem_release, ! 616: mem_alloc, ! 617: mem_free, ! 618: mem_getphys, ! 619: mem_getvirt, ! 620: mem_physmax, ! 621: mem_mapphys, ! 622: }; ! 623: ! 624: /* ! 625: * Return a reference to the one and only memory interface object. ! 626: */ ! 627: oskit_osenv_mem_t * ! 628: oskit_create_osenv_mem(void) ! 629: { ! 630: return &osenv_mem_object; ! 631: } ! 632: ! 633: ! 634: /*** oskit_mem_t COM object implementation ***/ ! 635: ! 636: ! 637: /* the COM object */ ! 638: static struct oskit_mem_ops mem_ops; ! 639: static oskit_mem_t oskit_mem = { &mem_ops }; ! 640: ! 641: ! 642: static OSKIT_COMDECL ! 643: mem2_query(oskit_mem_t *m, const oskit_iid_t *iid, void **out_ihandle) ! 644: { ! 645: if (memcmp(iid, &oskit_iunknown_iid, sizeof(*iid)) == 0 || ! 646: memcmp(iid, &oskit_mem_iid, sizeof(*iid)) == 0) { ! 647: *out_ihandle = m; ! 648: return 0; ! 649: } ! 650: ! 651: *out_ihandle = 0; ! 652: return OSKIT_E_NOINTERFACE; ! 653: }; ! 654: ! 655: static OSKIT_COMDECL_U ! 656: mem2_addref(oskit_mem_t *m) ! 657: { ! 658: /* No reference counting; only one of them */ ! 659: return 1; ! 660: } ! 661: ! 662: static OSKIT_COMDECL_U ! 663: mem2_release(oskit_mem_t *m) ! 664: { ! 665: /* No reference counting; only one of them */ ! 666: return 1; ! 667: } ! 668: ! 669: static void * OSKIT_COMCALL ! 670: mem2_alloc(oskit_mem_t *m, oskit_u32_t size, oskit_u32_t flags) ! 671: { ! 672: return alloc_for_oskit (size, flags, 0); ! 673: } ! 674: ! 675: static void * OSKIT_COMCALL ! 676: mem2_realloc(oskit_mem_t *m, void *ptr, ! 677: oskit_u32_t oldsize, oskit_u32_t newsize, oskit_u32_t flags) ! 678: { ! 679: if (flags & OSKIT_MEM_AUTO_SIZE) ! 680: { ! 681: oskit_size_t *op = ptr, *new; ! 682: oldsize = *--op; ! 683: newsize += sizeof (oskit_size_t); ! 684: new = alloc_for_oskit (newsize, flags, 0); ! 685: if (new) ! 686: { ! 687: *new++ = newsize; ! 688: memcpy (new, ptr, oldsize - sizeof (oskit_size_t)); ! 689: free_for_oskit (op, flags, oldsize); ! 690: } ! 691: return new; ! 692: } ! 693: else ! 694: { ! 695: void *new = alloc_for_oskit (newsize, flags, 0); ! 696: if (new) ! 697: { ! 698: memcpy (new, ptr, oldsize); ! 699: free_for_oskit (ptr, flags, oldsize); ! 700: } ! 701: return new; ! 702: } ! 703: } ! 704: ! 705: static void *OSKIT_COMCALL ! 706: mem2_alloc_aligned(oskit_mem_t *m, ! 707: oskit_u32_t size, oskit_u32_t flags, oskit_u32_t align) ! 708: { ! 709: return alloc_for_oskit (size, flags, align); ! 710: } ! 711: ! 712: static void OSKIT_COMCALL ! 713: mem2_free(oskit_mem_t *m, void *ptr, oskit_u32_t size, oskit_u32_t flags) ! 714: { ! 715: if (ptr) ! 716: free_for_oskit (ptr, flags, size); ! 717: } ! 718: ! 719: static oskit_u32_t OSKIT_COMCALL ! 720: mem2_getsize(oskit_mem_t *m, void *ptr) ! 721: { ! 722: if (ptr) { ! 723: oskit_u32_t *chunk = (oskit_u32_t *)ptr - 1; ! 724: ! 725: return *chunk; ! 726: } ! 727: return 0; ! 728: } ! 729: ! 730: static void *OSKIT_COMCALL ! 731: mem2_alloc_gen(oskit_mem_t *m, ! 732: oskit_u32_t size, oskit_u32_t flags, ! 733: oskit_u32_t align_bits, oskit_u32_t align_ofs) ! 734: { ! 735: if (align_ofs != 0) ! 736: panic ("alloc with align_bits=%u align_ofs=%u", ! 737: align_bits, align_ofs); ! 738: return alloc_for_oskit (size, flags, 1 << align_bits); ! 739: } ! 740: ! 741: static oskit_size_t OSKIT_COMCALL ! 742: mem2_avail(oskit_mem_t *m, oskit_u32_t flags) ! 743: { ! 744: panic ("mem_avail"); ! 745: } ! 746: ! 747: static OSKIT_COMDECL_V ! 748: mem2_dump(oskit_mem_t *m) ! 749: { ! 750: panic ("mem_dump"); ! 751: } ! 752: ! 753: static struct oskit_mem_ops mem_ops = { ! 754: mem2_query, ! 755: mem2_addref, ! 756: mem2_release, ! 757: mem2_alloc, ! 758: mem2_realloc, ! 759: mem2_alloc_aligned, ! 760: mem2_free, ! 761: mem2_getsize, ! 762: mem2_alloc_gen, ! 763: mem2_avail, ! 764: mem2_dump, ! 765: }; ! 766: ! 767: /* ! 768: * Not a lot to do in this impl. ! 769: */ ! 770: oskit_mem_t * ! 771: oskit_mem_init(void) ! 772: { ! 773: return &oskit_mem; ! 774: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.