The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/osfmk/i386/i386_vm_init.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2003-2006 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
    5  * 
    6  * This file contains Original Code and/or Modifications of Original Code
    7  * as defined in and that are subject to the Apple Public Source License
    8  * Version 2.0 (the 'License'). You may not use this file except in
    9  * compliance with the License. The rights granted to you under the License
   10  * may not be used to create, or enable the creation or redistribution of,
   11  * unlawful or unlicensed copies of an Apple operating system, or to
   12  * circumvent, violate, or enable the circumvention or violation of, any
   13  * terms of an Apple operating system software license agreement.
   14  * 
   15  * Please obtain a copy of the License at
   16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
   17  * 
   18  * The Original Code and all software distributed under the License are
   19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   23  * Please see the License for the specific language governing rights and
   24  * limitations under the License.
   25  * 
   26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
   27  */
   28 /*
   29  * @OSF_COPYRIGHT@
   30  */
   31 /* 
   32  * Mach Operating System
   33  * Copyright (c) 1991,1990,1989, 1988 Carnegie Mellon University
   34  * All Rights Reserved.
   35  * 
   36  * Permission to use, copy, modify and distribute this software and its
   37  * documentation is hereby granted, provided that both the copyright
   38  * notice and this permission notice appear in all copies of the
   39  * software, derivative works or modified versions, and any portions
   40  * thereof, and that both notices appear in supporting documentation.
   41  * 
   42  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
   43  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
   44  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
   45  * 
   46  * Carnegie Mellon requests users of this software to return to
   47  * 
   48  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
   49  *  School of Computer Science
   50  *  Carnegie Mellon University
   51  *  Pittsburgh PA 15213-3890
   52  * 
   53  * any improvements or extensions that they make and grant Carnegie Mellon
   54  * the rights to redistribute these changes.
   55  */
   56 
   57 #include <platforms.h>
   58 #include <mach_kdb.h>
   59 
   60 #include <mach/i386/vm_param.h>
   61 
   62 #include <string.h>
   63 #include <mach/vm_param.h>
   64 #include <mach/vm_prot.h>
   65 #include <mach/machine.h>
   66 #include <mach/time_value.h>
   67 #include <kern/spl.h>
   68 #include <kern/assert.h>
   69 #include <kern/debug.h>
   70 #include <kern/misc_protos.h>
   71 #include <kern/cpu_data.h>
   72 #include <kern/processor.h>
   73 #include <vm/vm_page.h>
   74 #include <vm/pmap.h>
   75 #include <vm/vm_kern.h>
   76 #include <i386/pmap.h>
   77 #include <i386/ipl.h>
   78 #include <i386/misc_protos.h>
   79 #include <i386/mp_slave_boot.h>
   80 #include <i386/cpuid.h>
   81 #include <mach/thread_status.h>
   82 #include <pexpert/i386/efi.h>
   83 #include "i386_lowmem.h"
   84 
   85 vm_size_t       mem_size = 0; 
   86 vm_offset_t     first_avail = 0;/* first after page tables */
   87 
   88 uint64_t        max_mem;        /* Size of physical memory (bytes), adjusted by maxmem */
   89 uint64_t        mem_actual;
   90 uint64_t        sane_size = 0;  /* Memory size to use for defaults calculations */
   91 
   92 #define MAXBOUNCEPOOL   (128 * 1024 * 1024)
   93 #define MAXLORESERVE    ( 32 * 1024 * 1024)
   94 
   95 extern int bsd_mbuf_cluster_reserve(void);
   96 
   97 
   98 uint32_t        bounce_pool_base = 0;
   99 uint32_t        bounce_pool_size = 0;
  100 
  101 static void     reserve_bouncepool(uint32_t);
  102 
  103 
  104 pmap_paddr_t     avail_start, avail_end;
  105 vm_offset_t     virtual_avail, virtual_end;
  106 static pmap_paddr_t     avail_remaining;
  107 vm_offset_t     static_memory_end = 0;
  108 
  109 #include        <mach-o/loader.h>
  110 vm_offset_t     edata, etext, end;
  111 
  112 /*
  113  * _mh_execute_header is the mach_header for the currently executing
  114  * 32 bit kernel
  115  */
  116 extern struct mach_header _mh_execute_header;
  117 void *sectTEXTB; int sectSizeTEXT;
  118 void *sectDATAB; int sectSizeDATA;
  119 void *sectOBJCB; int sectSizeOBJC;
  120 void *sectLINKB; int sectSizeLINK;
  121 void *sectPRELINKB; int sectSizePRELINK;
  122 void *sectHIBB; int sectSizeHIB;
  123 
  124 extern void *getsegdatafromheader(struct mach_header *, const char *, int *);
  125 extern struct segment_command *getsegbyname(const char *);
  126 extern struct section *firstsect(struct segment_command *);
  127 extern struct section *nextsect(struct segment_command *, struct section *);
  128 
  129 
  130 void
  131 i386_macho_zerofill(void)
  132 {
  133         struct segment_command  *sgp;
  134         struct section          *sp;
  135 
  136         sgp = getsegbyname("__DATA");
  137         if (sgp) {
  138                 sp = firstsect(sgp);
  139                 if (sp) {
  140                         do {
  141                                 if ((sp->flags & S_ZEROFILL))
  142                                         bzero((char *) sp->addr, sp->size);
  143                         } while ((sp = nextsect(sgp, sp)));
  144                 }
  145         }
  146 
  147         return;
  148 }
  149 
  150 /*
  151  * Basic VM initialization.
  152  */
  153 void
  154 i386_vm_init(uint64_t   maxmem,
  155              boolean_t  IA32e,
  156              boot_args  *args)
  157 {
  158         pmap_memory_region_t *pmptr;
  159         pmap_memory_region_t *prev_pmptr;
  160         EfiMemoryRange *mptr;
  161         unsigned int mcount;
  162         unsigned int msize;
  163         ppnum_t fap;
  164         unsigned int i;
  165         unsigned int safeboot;
  166         ppnum_t maxpg = 0;
  167         uint32_t pmap_type;
  168         uint32_t maxbouncepoolsize;
  169         uint32_t maxloreserve;
  170         uint32_t maxdmaaddr;
  171 
  172         /*
  173          * Now retrieve addresses for end, edata, and etext 
  174          * from MACH-O headers.
  175          */
  176 
  177         sectTEXTB = (void *) getsegdatafromheader(
  178                 &_mh_execute_header, "__TEXT", &sectSizeTEXT);
  179         sectDATAB = (void *) getsegdatafromheader(
  180                 &_mh_execute_header, "__DATA", &sectSizeDATA);
  181         sectOBJCB = (void *) getsegdatafromheader(
  182                 &_mh_execute_header, "__OBJC", &sectSizeOBJC);
  183         sectLINKB = (void *) getsegdatafromheader(
  184                 &_mh_execute_header, "__LINKEDIT", &sectSizeLINK);
  185         sectHIBB = (void *)getsegdatafromheader(
  186                 &_mh_execute_header, "__HIB", &sectSizeHIB);
  187         sectPRELINKB = (void *) getsegdatafromheader(
  188                 &_mh_execute_header, "__PRELINK", &sectSizePRELINK);
  189 
  190         etext = (vm_offset_t) sectTEXTB + sectSizeTEXT;
  191         edata = (vm_offset_t) sectDATAB + sectSizeDATA;
  192 
  193         vm_set_page_size();
  194 
  195         /*
  196          * Compute the memory size.
  197          */
  198 
  199         if ((1 == vm_himemory_mode) || PE_parse_boot_arg("-x", &safeboot)) {
  200                 maxpg = 1 << (32 - I386_PGSHIFT);
  201         }
  202         avail_remaining = 0;
  203         avail_end = 0;
  204         pmptr = pmap_memory_regions;
  205         prev_pmptr = 0;
  206         pmap_memory_region_count = pmap_memory_region_current = 0;
  207         fap = (ppnum_t) i386_btop(first_avail);
  208 
  209         mptr = (EfiMemoryRange *)args->MemoryMap;
  210         if (args->MemoryMapDescriptorSize == 0)
  211                 panic("Invalid memory map descriptor size");
  212         msize = args->MemoryMapDescriptorSize;
  213         mcount = args->MemoryMapSize / msize;
  214 
  215 #define FOURGIG 0x0000000100000000ULL
  216 
  217         for (i = 0; i < mcount; i++, mptr = (EfiMemoryRange *)(((vm_offset_t)mptr) + msize)) {
  218                 ppnum_t base, top;
  219 
  220                 if (pmap_memory_region_count >= PMAP_MEMORY_REGIONS_SIZE) {
  221                         kprintf("WARNING: truncating memory region count at %d\n", pmap_memory_region_count);
  222                         break;
  223                 }
  224                 base = (ppnum_t) (mptr->PhysicalStart >> I386_PGSHIFT);
  225                 top = (ppnum_t) ((mptr->PhysicalStart) >> I386_PGSHIFT) + mptr->NumberOfPages - 1;
  226 
  227                 switch (mptr->Type) {
  228                 case kEfiLoaderCode:
  229                 case kEfiLoaderData:
  230                 case kEfiBootServicesCode:
  231                 case kEfiBootServicesData:
  232                 case kEfiConventionalMemory:
  233                         /*
  234                          * Consolidate usable memory types into one.
  235                          */
  236                         pmap_type = kEfiConventionalMemory;
  237                         sane_size += (uint64_t)(mptr->NumberOfPages << I386_PGSHIFT);
  238                         break;
  239 
  240                 case kEfiRuntimeServicesCode:
  241                 case kEfiRuntimeServicesData:
  242                 case kEfiACPIReclaimMemory:
  243                 case kEfiACPIMemoryNVS:
  244                 case kEfiPalCode:
  245                         /*
  246                          * sane_size should reflect the total amount of physical ram
  247                          * in the system, not just the amount that is available for
  248                          * the OS to use
  249                          */
  250                         sane_size += (uint64_t)(mptr->NumberOfPages << I386_PGSHIFT);
  251                         /* fall thru */
  252 
  253                 case kEfiUnusableMemory:
  254                 case kEfiMemoryMappedIO:
  255                 case kEfiMemoryMappedIOPortSpace:
  256                 case kEfiReservedMemoryType:
  257                 default:
  258                         pmap_type = mptr->Type;
  259                 }
  260 
  261                 kprintf("EFI region: type = %u/%d,  base = 0x%x,  top = 0x%x\n", mptr->Type, pmap_type, base, top);
  262 
  263                 if (maxpg) {
  264                         if (base >= maxpg)
  265                                 break;
  266                         top = (top > maxpg) ? maxpg : top;
  267                 }
  268 
  269                 /*
  270                  * handle each region
  271                  */
  272                 if ((mptr->Attribute & EFI_MEMORY_RUNTIME) == EFI_MEMORY_RUNTIME ||
  273                     pmap_type != kEfiConventionalMemory) {
  274                         prev_pmptr = 0;
  275                         continue;
  276                 } else {
  277                         /*
  278                          * Usable memory region
  279                          */
  280                         if (top < I386_LOWMEM_RESERVED) {
  281                                 prev_pmptr = 0;
  282                                 continue;
  283                         }
  284                         if (top < fap) {
  285                                 /*
  286                                  * entire range below first_avail
  287                                  * salvage some low memory pages
  288                                  * we use some very low memory at startup
  289                                  * mark as already allocated here
  290                                  */
  291                                 if (base >= I386_LOWMEM_RESERVED)
  292                                         pmptr->base = base;
  293                                 else
  294                                         pmptr->base = I386_LOWMEM_RESERVED;
  295                                 /*
  296                                  * mark as already mapped
  297                                  */
  298                                 pmptr->alloc = pmptr->end = top;
  299                                 pmptr->type = pmap_type;
  300                         }
  301                         else if ( (base < fap) && (top > fap) ) {
  302                                 /*
  303                                  * spans first_avail
  304                                  * put mem below first avail in table but
  305                                  * mark already allocated
  306                                  */
  307                                 pmptr->base = base;
  308                                 pmptr->alloc = pmptr->end = (fap - 1);
  309                                 pmptr->type = pmap_type;
  310                                 /*
  311                                  * we bump these here inline so the accounting
  312                                  * below works correctly
  313                                  */
  314                                 pmptr++;
  315                                 pmap_memory_region_count++;
  316                                 pmptr->alloc = pmptr->base = fap;
  317                                 pmptr->type = pmap_type;
  318                                 pmptr->end = top;
  319                         }
  320                         else {
  321                                 /*
  322                                  * entire range useable
  323                                  */
  324                                 pmptr->alloc = pmptr->base = base;
  325                                 pmptr->type = pmap_type;
  326                                 pmptr->end = top;
  327                         }
  328 
  329                         if (i386_ptob(pmptr->end) > avail_end )
  330                                 avail_end = i386_ptob(pmptr->end);
  331 
  332                         avail_remaining += (pmptr->end - pmptr->base);
  333 
  334                         /*
  335                          * Consolidate contiguous memory regions, if possible
  336                          */
  337                         if (prev_pmptr &&
  338                             pmptr->type == prev_pmptr->type &&
  339                             pmptr->base == pmptr->alloc &&
  340                             pmptr->base == (prev_pmptr->end + 1)) {
  341                                 prev_pmptr->end = pmptr->end;
  342                         } else {
  343                                 pmap_memory_region_count++;
  344                                 prev_pmptr = pmptr;
  345                                 pmptr++;
  346                         }
  347                 }
  348         }
  349 
  350 
  351 #ifdef PRINT_PMAP_MEMORY_TABLE
  352         {
  353         unsigned int j;
  354         pmap_memory_region_t *p = pmap_memory_regions;
  355         vm_offset_t region_start, region_end;
  356         vm_offset_t efi_start, efi_end;
  357         for (j=0;j<pmap_memory_region_count;j++, p++) {
  358             kprintf("type %d base 0x%x alloc 0x%x top 0x%x\n", p->type,
  359                     p->base << I386_PGSHIFT, p->alloc << I386_PGSHIFT, p->end << I386_PGSHIFT);
  360             region_start = p->base << I386_PGSHIFT;
  361             region_end = (p->end << I386_PGSHIFT) - 1;
  362             mptr = args->MemoryMap;
  363             for (i=0; i<mcount; i++, mptr = (EfiMemoryRange *)(((vm_offset_t)mptr) + msize)) {
  364                 if (mptr->Type != kEfiLoaderCode &&
  365                     mptr->Type != kEfiLoaderData &&
  366                     mptr->Type != kEfiBootServicesCode &&
  367                     mptr->Type != kEfiBootServicesData &&
  368                     mptr->Type != kEfiConventionalMemory) {
  369                 efi_start = (vm_offset_t)mptr->PhysicalStart;
  370                 efi_end = efi_start + ((vm_offset_t)mptr->NumberOfPages << I386_PGSHIFT) - 1;
  371                 if ((efi_start >= region_start && efi_start <= region_end) ||
  372                     (efi_end >= region_start && efi_end <= region_end)) {
  373                     kprintf(" *** Overlapping region with EFI runtime region %d\n", i);
  374                 }
  375                 }
  376                 
  377             }
  378         }
  379         }
  380 #endif
  381 
  382         avail_start = first_avail;
  383         mem_actual = sane_size;
  384 
  385 #define MEG             (1024*1024)
  386 
  387         /*
  388          * For user visible memory size, round up to 128 Mb - accounting for the various stolen memory
  389          * not reported by EFI.
  390          */
  391 
  392         sane_size = (sane_size + 128 * MEG - 1) & ~((uint64_t)(128 * MEG - 1));
  393 
  394         /*
  395          * if user set maxmem, reduce memory sizes
  396          */
  397         if ( (maxmem > (uint64_t)first_avail) && (maxmem < sane_size)) {
  398                 ppnum_t discarded_pages  = (sane_size - maxmem) >> I386_PGSHIFT;
  399                 ppnum_t highest_pn = 0;
  400                 ppnum_t cur_alloc  = 0;
  401                 uint64_t        pages_to_use;
  402                 unsigned        cur_region = 0;
  403 
  404                 sane_size = maxmem;
  405 
  406                 if (avail_remaining > discarded_pages)
  407                         avail_remaining -= discarded_pages;
  408                 else
  409                         avail_remaining = 0;
  410                 
  411                 pages_to_use = avail_remaining;
  412 
  413                 while (cur_region < pmap_memory_region_count && pages_to_use) {
  414                         for (cur_alloc = pmap_memory_regions[cur_region].alloc;
  415                              cur_alloc < pmap_memory_regions[cur_region].end && pages_to_use;
  416                              cur_alloc++) {
  417                                 if (cur_alloc > highest_pn)
  418                                         highest_pn = cur_alloc;
  419                                 pages_to_use--;
  420                         }
  421                         if (pages_to_use == 0)
  422                                 pmap_memory_regions[cur_region].end = cur_alloc;
  423 
  424                         cur_region++;
  425                 }
  426                 pmap_memory_region_count = cur_region;
  427 
  428                 avail_end = i386_ptob(highest_pn + 1);
  429         }
  430 
  431         /*
  432          * mem_size is only a 32 bit container... follow the PPC route
  433          * and pin it to a 2 Gbyte maximum
  434          */
  435         if (sane_size > (FOURGIG >> 1))
  436                 mem_size = (vm_size_t)(FOURGIG >> 1);
  437         else
  438                 mem_size = (vm_size_t)sane_size;
  439         max_mem = sane_size;
  440 
  441         kprintf("Physical memory %llu MB\n", sane_size/MEG);
  442 
  443         if (!PE_parse_boot_arg("max_valid_dma_addr", &maxdmaaddr))
  444                 max_valid_dma_address = 1024ULL * 1024ULL * 4096ULL;
  445         else
  446                 max_valid_dma_address = ((uint64_t) maxdmaaddr) * 1024ULL * 1024ULL;
  447 
  448         if (!PE_parse_boot_arg("maxbouncepool", &maxbouncepoolsize))
  449                 maxbouncepoolsize = MAXBOUNCEPOOL;
  450         else
  451                 maxbouncepoolsize = maxbouncepoolsize * (1024 * 1024);
  452 
  453         /*
  454          * bsd_mbuf_cluster_reserve depends on sane_size being set
  455          * in order to correctly determine the size of the mbuf pool
  456          * that will be reserved
  457          */
  458         if (!PE_parse_boot_arg("maxloreserve", &maxloreserve))
  459                 maxloreserve = MAXLORESERVE + bsd_mbuf_cluster_reserve();
  460         else
  461                 maxloreserve = maxloreserve * (1024 * 1024);
  462 
  463 
  464         if (avail_end >= max_valid_dma_address) {
  465                 if (maxbouncepoolsize)
  466                         reserve_bouncepool(maxbouncepoolsize);
  467 
  468                 if (maxloreserve)
  469                         vm_lopage_poolsize = maxloreserve / PAGE_SIZE;
  470         }
  471         
  472         /*
  473          *      Initialize kernel physical map.
  474          *      Kernel virtual address starts at VM_KERNEL_MIN_ADDRESS.
  475          */
  476         pmap_bootstrap(0, IA32e);
  477 }
  478 
  479 
  480 unsigned int
  481 pmap_free_pages(void)
  482 {
  483         return avail_remaining;
  484 }
  485 
  486 
  487 boolean_t
  488 pmap_next_page(
  489                ppnum_t *pn)
  490 {
  491         
  492         if (avail_remaining) while (pmap_memory_region_current < pmap_memory_region_count) {
  493                 if (pmap_memory_regions[pmap_memory_region_current].alloc ==
  494                     pmap_memory_regions[pmap_memory_region_current].end) {
  495                         pmap_memory_region_current++;
  496                         continue;
  497                 }
  498                 *pn = pmap_memory_regions[pmap_memory_region_current].alloc++;
  499                 avail_remaining--;
  500 
  501                 return TRUE;
  502         }
  503         return FALSE;
  504 }
  505 
  506 
  507 boolean_t
  508 pmap_valid_page(
  509         ppnum_t pn)
  510 {
  511         unsigned int i;
  512         pmap_memory_region_t *pmptr = pmap_memory_regions;
  513 
  514         assert(pn);
  515         for (i = 0; i < pmap_memory_region_count; i++, pmptr++) {
  516                 if ( (pn >= pmptr->base) && (pn <= pmptr->end) )
  517                         return TRUE;
  518         }
  519         return FALSE;
  520 }
  521 
  522 
  523 static void
  524 reserve_bouncepool(uint32_t bounce_pool_wanted)
  525 {
  526         pmap_memory_region_t *pmptr  = pmap_memory_regions;
  527         pmap_memory_region_t *lowest = NULL;
  528         unsigned int i;
  529         unsigned int pages_needed;
  530 
  531         pages_needed = bounce_pool_wanted / PAGE_SIZE;
  532 
  533         for (i = 0; i < pmap_memory_region_count; i++, pmptr++) {
  534                 if ( (pmptr->end - pmptr->alloc) >= pages_needed ) {
  535                         if ( (lowest == NULL) || (pmptr->alloc < lowest->alloc) )
  536                                 lowest = pmptr;
  537                 }
  538         }
  539         if ( (lowest != NULL) ) {
  540                 bounce_pool_base = lowest->alloc * PAGE_SIZE;
  541                 bounce_pool_size = bounce_pool_wanted;
  542 
  543                 lowest->alloc += pages_needed;
  544                 avail_remaining -= pages_needed;
  545         }
  546 }

Cache object: 96f1b8e75bdf40e68dbdfbb4013ffb9c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.