Annotation of OSKit-Mach/oskit/osenv_mem.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.