CTC++ Coverage Report - Execution Profile    #35/1532

Files Summary | Functions Summary | Execution Profile | Index | No Index
First | Previous | Next | Last


File: arch/x86_64/kernel/e820.c
Instrumentation mode: function-decision-multicondition
TER: 71 % (172/242)

Start/ End/    
True False - Line Source

  1 /* 
  2  * Handle the memory map.
  3  * The functions here do the job until bootmem takes over.
  4  * $Id: e820.c,v 1.4 2002/09/19 19:25:32 ak Exp $
  5  *
  6  *  Getting sanitize_e820_map() in sync with i386 version by applying change:
  7  *  -  Provisions for empty E820 memory regions (reported by certain BIOSes).
  8  *     Alex Achenbach <xela@slit.de>, December 2002.
  9  *  Venkatesh Pallipadi <venkatesh.pallipadi@intel.com>
  10  *
  11  */
  12 #include <linux/config.h>
  13 #include <linux/kernel.h>
  14 #include <linux/types.h>
  15 #include <linux/init.h>
  16 #include <linux/bootmem.h>
  17 #include <linux/ioport.h>
  18 #include <linux/string.h>
  19 #include <linux/kexec.h>
  20 #include <linux/module.h>
  21 
  22 #include <asm/page.h>
  23 #include <asm/e820.h>
  24 #include <asm/proto.h>
  25 #include <asm/bootsetup.h>
  26 #include <asm/sections.h>
  27 
  28 /* 
  29  * PFN of last memory page.
  30  */
  31 unsigned long end_pfn; 
  32 EXPORT_SYMBOL(end_pfn);
  33 
  34 /* 
  35  * end_pfn only includes RAM, while end_pfn_map includes all e820 entries.
  36  * The direct mapping extends to end_pfn_map, so that we can directly access
  37  * apertures, ACPI and other tables without having to play with fixmaps.
  38  */ 
  39 unsigned long end_pfn_map; 
  40 
  41 /* 
  42  * Last pfn which the user wants to use.
  43  */
  44 unsigned long end_user_pfn = MAXMEM>>PAGE_SHIFT;  
  45 
  46 extern struct resource code_resource, data_resource;
  47 
  48 /* Check for some hardcoded bad areas that early boot is not allowed to touch */ 
 
24   49 static inline int bad_addr(unsigned long *addrp, unsigned long size)
  50 
  51    unsigned long addr = *addrp, last = addr + size; 
  52 
  53    /* various gunk below that needed for SMP startup */
18   54    if (addr < 0x8000) { 
  55       *addrp = 0x8000;
   56       return 1; 
  57    }
  58 
  59    /* direct mapping tables of the kernel */
12   60    if (last >= table_start<<PAGE_SHIFT && addr < table_end<<PAGE_SHIFT) { 
   60   T && T
 12   60   T && F
 - 60   F && _
  61       *addrp = table_end << PAGE_SHIFT; 
   62       return 1;
  63    } 
  64 
  65    /* initrd */ 
  66 #ifdef CONFIG_BLK_DEV_INITRD
  67    if (LOADER_TYPE && INITRD_START && last >= INITRD_START && 
  68        addr < INITRD_START+INITRD_SIZE) { 
  69       *addrp = INITRD_START + INITRD_SIZE; 
  70       return 1;
  71    } 
  72 #endif
  73    /* kernel code + 640k memory hole (later should not be needed, but 
  74       be paranoid for now) */
12 - 75    if (last >= 640*1024 && addr < __pa_symbol(&_end)) { 
 - 75   T && T
 - 75   T && F
 12   75   F && _
  76       *addrp = __pa_symbol(&_end);
 - 77       return 1;
  78    }
  79    /* XXX ramdisk image here? */ 
12    80    return 0;
  81 
  82 
 
30   83 int __init e820_mapped(unsigned long start, unsigned long end, unsigned type) 
  84 
  85    int i;
198 18   86    for (i = 0; i < e820.nr_map; i++) { 
  87       struct e820entry *ei = &e820.map[i]; 
36 162   88       if (type && ei->type != type) 
36    88     T && T
 12   88     T && F
 150   88     F && _
36    89          continue;
150 12   90       if (ei->addr >= end || ei->addr + ei->size <= start)
12    90     T || _
138    90     F || T
 12   90     F || F
150    91          continue; 
12    92       return 1; 
  93    } 
18    94    return 0;
  95 }
  96 
  97 /* 
  98  * Find a free area in a specific range. 
  99  */ 
 
12   100 unsigned long __init find_e820_area(unsigned long start, unsigned long end, unsigned size) 
  101 
  102    int i; 
12 - 103    for (i = 0; i < e820.nr_map; i++) { 
  104       struct e820entry *ei = &e820.map[i]; 
  105       unsigned long addr = ei->addr, last; 
12 - 106       if (ei->type != E820_RAM) 
 - 107          continue; 
  108       if (addr < start) 
  109          addr = start;
12 - 110       if (addr > ei->addr + ei->size) 
 - 111          continue; 
12 12   112       while (bad_addr(&addr, size) && addr+size < ei->addr + ei->size)
12    112     T && T
 - 112     T && F
 12   112     F && _
  113          ;
  114       last = addr + size;
12 - 115       if (last > ei->addr + ei->size)
 - 116          continue;
12 - 117       if (last > end) 
 - 118          continue;
12    119       return addr; 
  120    } 
 - 121    return -1UL;      
  122 
  123 
  124 /* 
  125  * Free bootmem based on the e820 table for a node.
  126  */
 
  127 void __init e820_bootmem_free(pg_data_t *pgdat, unsigned long start,unsigned long end)
  128 {
  129    int i;
48   130    for (i = 0; i < e820.nr_map; i++) {
  131       struct e820entry *ei = &e820.map[i]; 
  132       unsigned long last, addr;
  133 
  134       if (ei->type != E820_RAM || 
  135           ei->addr+ei->size <= start || 
36 12   136           ei->addr >= end)
36    136     T || _ || _
 - 136     F || T || _
 - 136     F || F || T
 12   136     F || F || F
36    137          continue;
  138 
  139       addr = round_up(ei->addr, PAGE_SIZE);
12 - 140       if (addr < start) 
  141          addr = start;
  142 
  143       last = round_down(ei->addr + ei->size, PAGE_SIZE); 
  144       if (last >= end)
  145          last = end; 
  146 
12 - 147       if (last > addr && last-addr >= PAGE_SIZE)
12    147     T && T
 - 147     T && F
 - 147     F && _
  148          free_bootmem_node(pgdat, addr, last-addr);
  149    }
  150 }
  151 
  152 /*
  153  * Find the highest page frame number we have available
  154  */
 
  155 unsigned long __init e820_end_of_ram(void)
  156 {
  157    int i;
  158    unsigned long end_pfn = 0;
  159    
48   160    for (i = 0; i < e820.nr_map; i++) {
  161       struct e820entry *ei = &e820.map[i]; 
  162       unsigned long start, end;
  163 
  164       start = round_up(ei->addr, PAGE_SIZE); 
  165       end = round_down(ei->addr + ei->size, PAGE_SIZE); 
48 - 166       if (start >= end)
 - 167          continue;
12 36   168       if (ei->type == E820_RAM) { 
12 - 169       if (end > end_pfn<<PAGE_SHIFT)
  170          end_pfn = end>>PAGE_SHIFT;
    171       } else { 
36 - 172          if (end > end_pfn_map<<PAGE_SHIFT) 
  173             end_pfn_map = end>>PAGE_SHIFT;
  174       } 
  175    }
  176 
- 177    if (end_pfn > end_pfn_map) 
  178       end_pfn_map = end_pfn;
- 179    if (end_pfn_map > MAXMEM>>PAGE_SHIFT)
  180       end_pfn_map = MAXMEM>>PAGE_SHIFT;
- 181    if (end_pfn > end_user_pfn)
  182       end_pfn = end_user_pfn;
- 183    if (end_pfn > end_pfn_map) 
  184       end_pfn = end_pfn_map; 
  185 
   186    return end_pfn;   
  187 }
  188 
  189 /* 
  190  * Compute how much memory is missing in a range.
  191  * Unlike the other functions in this file the arguments are in page numbers.
  192  */
  193 unsigned long __init
 
30   194 e820_hole_size(unsigned long start_pfn, unsigned long end_pfn)
  195 {
  196    unsigned long ram = 0;
  197    unsigned long start = start_pfn << PAGE_SHIFT;
  198    unsigned long end = end_pfn << PAGE_SHIFT;
  199    int i;
240 30   200    for (i = 0; i < e820.nr_map; i++) {
  201       struct e820entry *ei = &e820.map[i];
  202       unsigned long last, addr;
  203 
  204       if (ei->type != E820_RAM ||
  205           ei->addr+ei->size <= start ||
210 30   206           ei->addr >= end)
180    206     T || _ || _
30    206     F || T || _
 - 206     F || F || T
 30   206     F || F || F
210    207          continue;
  208 
  209       addr = round_up(ei->addr, PAGE_SIZE);
24   210       if (addr < start)
  211          addr = start;
  212 
  213       last = round_down(ei->addr + ei->size, PAGE_SIZE);
18 12   214       if (last >= end)
  215          last = end;
  216 
30 - 217       if (last > addr)
  218          ram += last - addr;
  219    }
30    220    return ((end - start) - ram) >> PAGE_SHIFT;
  221 }
  222 
  223 /*
  224  * Mark e820 reserved areas as busy for the resource manager.
  225  */
 
  226 void __init e820_reserve_resources(void)
  227 {
  228    int i;
48   229    for (i = 0; i < e820.nr_map; i++) {
  230       struct resource *res;
  231       res = alloc_bootmem_low(sizeof(struct resource));
    232       switch (e820.map[i].type) {
12    233       case E820_RAM:   res->name = "System RAM"; break;
12    233     break
   234       case E820_ACPI:   res->name = "ACPI Tables"; break;
   234     break
   235       case E820_NVS:   res->name = "ACPI Non-volatile Storage"; break;
   235     break
24    236       default:   res->name = "reserved";
  237       }
  238       res->start = e820.map[i].addr;
  239       res->end = res->start + e820.map[i].size - 1;
  240       res->flags = IORESOURCE_MEM | IORESOURCE_BUSY;
  241       request_resource(&iomem_resource, res);
12 36   242       if (e820.map[i].type == E820_RAM) {
  243          /*
  244           *  We don't know which RAM region contains kernel data,
  245           *  so we try it repeatedly and let the resource manager
  246           *  test it.
  247           */
  248          request_resource(res, &code_resource);
  249          request_resource(res, &data_resource);
  250 #ifdef CONFIG_KEXEC
  251          request_resource(res, &crashk_res);
  252 #endif
  253       }
  254    }
  255 }
  256 
  257 /* 
  258  * Add a memory region to the kernel e820 map.
  259  */ 
 
48 48   260 void __init add_memory_region(unsigned long start, unsigned long size, int type)
  261 {
  262    int x = e820.nr_map;
  263 
48 - 264    if (x == E820MAX) {
  265       printk(KERN_ERR "Ooops! Too many entries in the memory map!\n");
 - 266       return;
  267    }
  268 
  269    e820.map[x].addr = start;
  270    e820.map[x].size = size;
  271    e820.map[x].type = type;
  272    e820.nr_map++;
  273 }
  274 
 
  275 void __init e820_print_map(char *who)
  276 {
  277    int i;
  278 
48   279    for (i = 0; i < e820.nr_map; i++) {
  280       printk(" %s: %016Lx - %016Lx ", who,
  281          (unsigned long long) e820.map[i].addr,
  282          (unsigned long long) (e820.map[i].addr + e820.map[i].size));
    283       switch (e820.map[i].type) {
12    284       case E820_RAM:   printk("(usable)\n");
12    285             break;
24    286       case E820_RESERVED:
  287             printk("(reserved)\n");
24    288             break;
   289       case E820_ACPI:
  290             printk("(ACPI data)\n");
   291             break;
   292       case E820_NVS:
  293             printk("(ACPI NVS)\n");
   294             break;
 - 295       default:   printk("type %u\n", e820.map[i].type);
 - 296             break;
  297       }
  298    }
  299 }
  300 
  301 /*
  302  * Sanitize the BIOS e820 map.
  303  *
  304  * Some e820 responses include overlapping entries.  The following 
  305  * replaces the original e820 map with a new one, removing overlaps.
  306  *
  307  */
 
  308 static int __init sanitize_e820_map(struct e820entry * biosmap, char * pnr_map)
  309 {
  310    struct change_member {
  311       struct e820entry *pbios; /* pointer to original bios entry */
  312       unsigned long long addr; /* address for this change point */
  313    };
  314    static struct change_member change_point_list[2*E820MAX] __initdata;
  315    static struct change_member *change_point[2*E820MAX] __initdata;
  316    static struct e820entry *overlap_list[E820MAX] __initdata;
  317    static struct e820entry new_bios[E820MAX] __initdata;
  318    struct change_member *change_tmp;
  319    unsigned long current_type, last_type;
  320    unsigned long long last_addr;
  321    int chgidx, still_changing;
  322    int overlap_entries;
  323    int new_bios_entry;
  324    int old_nr, new_nr, chg_nr;
  325    int i;
  326 
  327    /*
  328       Visually we're performing the following (1,2,3,4 = memory types)...
  329 
  330       Sample memory map (w/overlaps):
  331          ____22__________________
  332          ______________________4_
  333          ____1111________________
  334          _44_____________________
  335          11111111________________
  336          ____________________33__
  337          ___________44___________
  338          __________33333_________
  339          ______________22________
  340          ___________________2222_
  341          _________111111111______
  342          _____________________11_
  343          _________________4______
  344 
  345       Sanitized equivalent (no overlap):
  346          1_______________________
  347          _44_____________________
  348          ___1____________________
  349          ____22__________________
  350          ______11________________
  351          _________1______________
  352          __________3_____________
  353          ___________44___________
  354          _____________33_________
  355          _______________2________
  356          ________________1_______
  357          _________________4______
  358          ___________________2____
  359          ____________________33__
  360          ______________________4_
  361    */
  362 
  363    /* if there's only one memory region, don't bother */
- 364    if (*pnr_map < 2)
 - 365       return -1;
  366 
  367    old_nr = *pnr_map;
  368 
  369    /* bail out if we find any unreasonable addresses in bios map */
48   370    for (i=0; i<old_nr; i++)
48 - 371       if (biosmap[i].addr + biosmap[i].size < biosmap[i].addr)
 - 372          return -1;
  373 
  374    /* create pointers for initial change-point information (for sorting) */
96   375    for (i=0; i < 2*old_nr; i++)
  376       change_point[i] = &change_point_list[i];
  377 
  378    /* record all known change-points (starting and ending addresses),
  379       omitting those that are for empty memory regions */
  380    chgidx = 0;
48   381    for (i=0; i < old_nr; i++)   {
48 - 382       if (biosmap[i].size != 0) {
  383          change_point[chgidx]->addr = biosmap[i].addr;
  384          change_point[chgidx++]->pbios = &biosmap[i];
  385          change_point[chgidx]->addr = biosmap[i].addr + biosmap[i].size;
  386          change_point[chgidx++]->pbios = &biosmap[i];
  387       }
  388    }
  389    chg_nr = chgidx;
  390 
  391    /* sort change-point list by memory addresses (low -> high) */
  392    still_changing = 1;
12   393    while (still_changing)   {
  394       still_changing = 0;
180 12   395       for (i=1; i < chg_nr; i++)  {
  396          /* if <current_addr> > <last_addr>, swap */
  397          /* or, if current=<start_addr> & last=<end_addr>, swap */
  398          if ((change_point[i]->addr < change_point[i-1]->addr) ||
  399             ((change_point[i]->addr == change_point[i-1]->addr) &&
  400              (change_point[i]->addr == change_point[i]->pbios->addr) &&
30 150   401              (change_point[i-1]->addr != change_point[i-1]->pbios->addr))
 - 401       (T) || ((_) && (_) && (_))
30    401       (F) || ((T) && (T) && (T))
 - 401       (F) || ((T) && (T) && (F))
 30   401       (F) || ((T) && (F) && (_))
 120   401       (F) || ((F) && (_) && (_))
  402             )
  403          {
  404             change_tmp = change_point[i];
  405             change_point[i] = change_point[i-1];
  406             change_point[i-1] = change_tmp;
  407             still_changing=1;
  408          }
  409       }
  410    }
  411 
  412    /* create a new bios memory map, removing overlaps */
  413    overlap_entries=0;    /* number of entries in the overlap table */
  414    new_bios_entry=0;    /* index for creating new bios map entries */
  415    last_type = 0;       /* start with undefined memory type */
  416    last_addr = 0;       /* start with 0 as last starting address */
  417    /* loop through change-points, determining affect on the new bios map */
96   418    for (chgidx=0; chgidx < chg_nr; chgidx++)
  419    {
  420       /* keep track of all overlapping bios entries */
48 48   421       if (change_point[chgidx]->addr == change_point[chgidx]->pbios->addr)
  422       {
  423          /* add map entry to overlap list (> 1 entry implies an overlap) */
  424          overlap_list[overlap_entries++]=change_point[chgidx]->pbios;
  425       }
    426       else
  427       {
  428          /* remove entry from list (order independent, so swap with last) */
78 48   429          for (i=0; i<overlap_entries; i++)
  430          {
48 30   431             if (overlap_list[i] == change_point[chgidx]->pbios)
  432                overlap_list[i] = overlap_list[overlap_entries-1];
  433          }
  434          overlap_entries--;
  435       }
  436       /* if there are overlapping entries, decide which "type" to use */
  437       /* (larger value takes precedence -- 1=usable, 2,3,4,4+=unusable) */
  438       current_type = 0;
108 96   439       for (i=0; i<overlap_entries; i++)
96 12   440          if (overlap_list[i]->type > current_type)
  441             current_type = overlap_list[i]->type;
  442       /* continue building up new bios map based on this information */
66 30   443       if (current_type != last_type)   {
48 18   444          if (last_type != 0)    {
  445             new_bios[new_bios_entry].size =
  446                change_point[chgidx]->addr - last_addr;
  447             /* move forward only if the new size was non-zero */
48 - 448             if (new_bios[new_bios_entry].size != 0)
48 - 449                if (++new_bios_entry >= E820MAX)
 - 450                   break;    /* no more space left for new bios entries */
  451          }
48 18   452          if (current_type != 0)   {
  453             new_bios[new_bios_entry].addr = change_point[chgidx]->addr;
  454             new_bios[new_bios_entry].type = current_type;
  455             last_addr=change_point[chgidx]->addr;
  456          }
  457          last_type = current_type;
  458       }
  459    }
  460    new_nr = new_bios_entry;   /* retain count for new bios entries */
  461 
  462    /* copy new bios mapping into original location */
  463    memcpy(biosmap, new_bios, new_nr*sizeof(struct e820entry));
  464    *pnr_map = new_nr;
  465 
   466    return 0;
  467 }
  468 
  469 /*
  470  * Copy the BIOS e820 map into a safe place.
  471  *
  472  * Sanity-check it while we're at it..
  473  *
  474  * If we're lucky and live on a modern system, the setup code
  475  * will have given us a memory map that we can use to properly
  476  * set up memory.  If we aren't, we'll fake a memory map.
  477  *
  478  * We check to see that the memory map contains at least 2 elements
  479  * before we'll use it, because the detection code in setup.S may
  480  * not be perfect and most every PC known to man has two memory
  481  * regions: one from 0 to 640k, and one from 1mb up.  (The IBM
  482  * thinkpad 560x, for example, does not cooperate with the memo