/* Mmap management. */
/*
* GRUB -- GRand Unified Bootloader
* Copyright (C) 2009 Free Software Foundation, Inc.
*
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* GRUB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GRUB. If not, see <http://www.gnu.org/licenses/>.
*/
GRUB_MOD_LICENSE ("GPLv3+");
#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
#endif
{
/* This function resolves overlapping regions and sorts the memory map.
It uses scanline (sweeping) algorithm.
*/
/* If same page is used by multiple types it's resolved
according to priority:
1 - free memory
2 - memory usable by firmware-aware code
3 - unusable memory
4 - a range deliberately empty
*/
int priority[] =
{
[GRUB_MEMORY_AVAILABLE] = 1,
[GRUB_MEMORY_RESERVED] = 3,
[GRUB_MEMORY_ACPI] = 2,
[GRUB_MEMORY_CODE] = 3,
[GRUB_MEMORY_NVS] = 3,
[GRUB_MEMORY_HOLE] = 4,
};
int i, done;
/* Scanline events. */
struct grub_mmap_scan
{
/* At which memory address. */
/* 0 = region starts, 1 = region ends. */
int type;
/* Which type of memory region? */
int memtype;
};
struct grub_mmap_scan t;
/* Previous scanline event. */
int lasttype;
/* Current scanline event. */
int curtype;
/* How many regions of given type overlap at current location? */
/* Number of mmap chunks. */
int mmap_num;
#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
#endif
{
mmap_num++;
return 0;
}
{
scanline_events[i].type = 0;
else
{
type);
}
i++;
i++;
return 0;
}
mmap_num = 0;
#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
mmap_num++;
#endif
/* Initialize variables. */
scanline_events = (struct grub_mmap_scan *)
if (! scanline_events)
{
return grub_error (GRUB_ERR_OUT_OF_MEMORY,
"couldn't allocate space for new memory map");
}
i = 0;
#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
/* Register scanline events. */
{
scanline_events[i].type = 0;
else
i++;
i++;
}
#endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */
/* Primitive bubble sort. It has complexity O(n^2) but since we're
unlikely to have more than 100 chunks it's probably one of the
fastest for one purpose. */
done = 1;
while (done)
{
done = 0;
{
t = scanline_events[i + 1];
scanline_events[i] = t;
done = 1;
}
}
for (i = 0; i < 2 * mmap_num; i++)
{
unsigned k;
/* Process event. */
if (scanline_events[i].type)
else
/* Determine current region type. */
curtype = -1;
for (k = 0; k < ARRAY_SIZE (priority); k++)
curtype = k;
/* Announce region to the hook if necessary. */
&& lasttype != -1
&& lasttype != GRUB_MEMORY_HOLE
{
return GRUB_ERR_NONE;
}
/* Update last values if necessary. */
{
}
}
return GRUB_ERR_NONE;
}
#ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
int
{
cur = (struct grub_mmap_region *)
grub_malloc (sizeof (struct grub_mmap_region));
if (! cur)
{
"couldn't allocate memory map overlay");
return 0;
}
{
return 0;
}
}
{
{
return err;
if (prev)
else
return GRUB_ERR_NONE;
}
}
#endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */
static inline grub_uint64_t
{
int i, j;
/* Find first fixed bit. */
for (i = 0; i < 64; i++)
if ((mask & (1ULL << i)) != 0)
break;
j = 0;
for (; i < 64; i++)
if ((mask & (1ULL << i)) == 0)
{
if ((iterator & (1ULL << j)) != 0)
ret |= 1ULL << i;
j++;
}
return ret;
}
static grub_err_t
{
char * str;
{
int i;
(unsigned long long) size);
/* How many trailing zeros? */
/* How many zeros in mask? */
var = 0;
for (i = 0; i < 64; i++)
if (! (badmask & (1ULL << i)))
var++;
iterator = 0;
else
{
low = 0;
/* Find starting value. Keep low and high such that
fill_mask (low) < addr and fill_mask (high) >= addr;
*/
{
else
}
}
iterator++)
{
}
return 0;
}
if (argc != 1)
while (1)
{
/* Parse address and mask. */
if (*str == ',')
str++;
if (*str == ',')
str++;
if (grub_errno == GRUB_ERR_BAD_NUMBER)
{
grub_errno = 0;
return GRUB_ERR_NONE;
}
/* When part of a page is tainted, we discard the whole of it. There's
no point in providing sub-page chunks. */
}
}
static grub_uint64_t
{
char *ptr;
switch (*ptr)
{
case 'K':
return ret << 10;
case 'M':
return ret << 20;
case 'G':
return ret << 30;
case 'T':
return ret << 40;
}
return ret;
}
static grub_err_t
{
{
return 0;
return 0;
}
if (argc != 2)
if (grub_errno)
return grub_errno;
if (grub_errno)
return grub_errno;
return GRUB_ERR_NONE;
}
static grub_err_t
{
if (argc != 2)
if (grub_errno)
return grub_errno;
if (grub_errno)
return grub_errno;
return grub_errno;
return GRUB_ERR_NONE;
}
{
N_("ADDR1,MASK1[,ADDR2,MASK2[,...]]"),
N_("Declare memory regions as badram."));
N_("FROM[K|M|G] TO[K|M|G]"),
N_("Remove any memory regions in specified range."));
N_("FROM[K|M|G] TO[K|M|G]"),
N_("Add an available memory region in the specified range."));
}
{
}