]> git.proxmox.com Git - grub2.git/blobdiff - grub-core/mmap/mmap.c
mmap: Fix memory leak when iterating over mapped memory
[grub2.git] / grub-core / mmap / mmap.c
index 07a71336ba5fa4a7f8bc054cd5ba1362241bcf6b..c8c8312c56f2651db2cdd05f19d7f079d5dccc99 100644 (file)
@@ -20,6 +20,7 @@
 #include <grub/memory.h>
 #include <grub/machine/memory.h>
 #include <grub/err.h>
+#include <grub/lockdown.h>
 #include <grub/misc.h>
 #include <grub/mm.h>
 #include <grub/command.h>
@@ -35,43 +36,86 @@ static int curhandle = 1;
 
 #endif
 
-grub_err_t
-grub_mmap_iterate (grub_memory_hook_t hook)
+static int current_priority = 1;
+
+/* Scanline events. */
+struct grub_mmap_scan
+{
+  /* At which memory address. */
+  grub_uint64_t pos;
+  /* 0 = region starts, 1 = region ends. */
+  int type;
+  /* Which type of memory region? */
+  grub_memory_type_t memtype;
+  /* Priority. 0 means coming from firmware.  */
+  int priority;
+};
+
+/* Context for grub_mmap_iterate.  */
+struct grub_mmap_iterate_ctx
 {
+  struct grub_mmap_scan *scanline_events;
+  int i;
+};
+
+/* Helper for grub_mmap_iterate.  */
+static int
+count_hook (grub_uint64_t addr __attribute__ ((unused)),
+           grub_uint64_t size __attribute__ ((unused)),
+           grub_memory_type_t type __attribute__ ((unused)), void *data)
+{
+  int *mmap_num = data;
 
+  (*mmap_num)++;
+  return 0;
+}
+
+/* Helper for grub_mmap_iterate.  */
+static int
+fill_hook (grub_uint64_t addr, grub_uint64_t size, grub_memory_type_t type,
+          void *data)
+{
+  struct grub_mmap_iterate_ctx *ctx = data;
+
+  if (type == GRUB_MEMORY_HOLE)
+    {
+      grub_dprintf ("mmap", "Unknown memory type %d. Assuming unusable\n",
+                   type);
+      type = GRUB_MEMORY_RESERVED;
+    }
+
+  ctx->scanline_events[ctx->i].pos = addr;
+  ctx->scanline_events[ctx->i].type = 0;
+  ctx->scanline_events[ctx->i].memtype = type;
+  ctx->scanline_events[ctx->i].priority = 0;
+
+  ctx->i++;
+
+  ctx->scanline_events[ctx->i].pos = addr + size;
+  ctx->scanline_events[ctx->i].type = 1;
+  ctx->scanline_events[ctx->i].memtype = type;
+  ctx->scanline_events[ctx->i].priority = 0;
+  ctx->i++;
+
+  return 0;
+}
+
+struct mm_list
+{
+  struct mm_list *next;
+  grub_memory_type_t val;
+  int present;
+};
+
+grub_err_t
+grub_mmap_iterate (grub_memory_hook_t hook, void *hook_data)
+{
   /* 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,
-    };
-
+  struct grub_mmap_iterate_ctx ctx;
   int i, done;
 
-  /* Scanline events. */
-  struct grub_mmap_scan
-  {
-    /* At which memory address. */
-    grub_uint64_t pos;
-    /* 0 = region starts, 1 = region ends. */
-    int type;
-    /* Which type of memory region? */
-    int memtype;
-  };
-  struct grub_mmap_scan *scanline_events;
   struct grub_mmap_scan t;
 
   /* Previous scanline event. */
@@ -79,8 +123,9 @@ grub_mmap_iterate (grub_memory_hook_t hook)
   int lasttype;
   /* Current scanline event. */
   int curtype;
-  /* How many regions of given type overlap at current location? */
-  int present[ARRAY_SIZE (priority)];
+  /* How many regions of given type/priority overlap at current location? */
+  /* Normally there shouldn't be more than one region per priority but be robust.  */
+  struct mm_list *present;
   /* Number of mmap chunks. */
   int mmap_num;
 
@@ -88,42 +133,6 @@ grub_mmap_iterate (grub_memory_hook_t hook)
   struct grub_mmap_region *cur;
 #endif
 
-  auto int NESTED_FUNC_ATTR count_hook (grub_uint64_t, grub_uint64_t,
-                                       grub_uint32_t);
-  int NESTED_FUNC_ATTR count_hook (grub_uint64_t addr __attribute__ ((unused)),
-                                  grub_uint64_t size __attribute__ ((unused)),
-                                  grub_memory_type_t type __attribute__ ((unused)))
-  {
-    mmap_num++;
-    return 0;
-  }
-
-  auto int NESTED_FUNC_ATTR fill_hook (grub_uint64_t, grub_uint64_t,
-                                       grub_uint32_t);
-  int NESTED_FUNC_ATTR fill_hook (grub_uint64_t addr,
-                                 grub_uint64_t size,
-                                 grub_memory_type_t type)
-  {
-    scanline_events[i].pos = addr;
-    scanline_events[i].type = 0;
-    if (type < ARRAY_SIZE (priority) && priority[type])
-      scanline_events[i].memtype = type;
-    else
-      {
-       grub_dprintf ("mmap", "Unknown memory type %d. Assuming unusable\n",
-                     type);
-       scanline_events[i].memtype = GRUB_MEMORY_RESERVED;
-      }
-    i++;
-
-    scanline_events[i].pos = addr + size;
-    scanline_events[i].type = 1;
-    scanline_events[i].memtype = scanline_events[i - 1].memtype;
-    i++;
-
-    return 0;
-  }
-
   mmap_num = 0;
 
 #ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
@@ -131,40 +140,41 @@ grub_mmap_iterate (grub_memory_hook_t hook)
     mmap_num++;
 #endif
 
-  grub_machine_mmap_iterate (count_hook);
+  grub_machine_mmap_iterate (count_hook, &mmap_num);
 
   /* Initialize variables. */
-  grub_memset (present, 0, sizeof (present));
-  scanline_events = (struct grub_mmap_scan *)
-    grub_malloc (sizeof (struct grub_mmap_scan) * 2 * mmap_num);
+  ctx.scanline_events = (struct grub_mmap_scan *)
+    grub_calloc (mmap_num, sizeof (struct grub_mmap_scan) * 2);
+
+  present = grub_calloc (current_priority, sizeof (present[0]));
 
-  if (! scanline_events)
+  if (! ctx.scanline_events || !present)
     {
-      return grub_error (GRUB_ERR_OUT_OF_MEMORY,
-                        "couldn't allocate space for new memory map");
+      grub_free (ctx.scanline_events);
+      grub_free (present);
+      return grub_errno;
     }
 
-  i = 0;
+  ctx.i = 0;
 #ifndef GRUB_MMAP_REGISTER_BY_FIRMWARE
   /* Register scanline events. */
   for (cur = grub_mmap_overlays; cur; cur = cur->next)
     {
-      scanline_events[i].pos = cur->start;
-      scanline_events[i].type = 0;
-      if (cur->type < ARRAY_SIZE (priority) && priority[cur->type])
-       scanline_events[i].memtype = cur->type;
-      else
-       scanline_events[i].memtype = GRUB_MEMORY_RESERVED;
-      i++;
-
-      scanline_events[i].pos = cur->end;
-      scanline_events[i].type = 1;
-      scanline_events[i].memtype = scanline_events[i - 1].memtype;
-      i++;
+      ctx.scanline_events[ctx.i].pos = cur->start;
+      ctx.scanline_events[ctx.i].type = 0;
+      ctx.scanline_events[ctx.i].memtype = cur->type;
+      ctx.scanline_events[ctx.i].priority = cur->priority;
+      ctx.i++;
+
+      ctx.scanline_events[ctx.i].pos = cur->end;
+      ctx.scanline_events[ctx.i].type = 1;
+      ctx.scanline_events[ctx.i].memtype = cur->type;
+      ctx.scanline_events[ctx.i].priority = cur->priority;
+      ctx.i++;
     }
 #endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */
 
-  grub_machine_mmap_iterate (fill_hook);
+  grub_machine_mmap_iterate (fill_hook, &ctx);
 
   /* 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
@@ -174,43 +184,93 @@ grub_mmap_iterate (grub_memory_hook_t hook)
     {
       done = 0;
       for (i = 0; i < 2 * mmap_num - 1; i++)
-       if (scanline_events[i + 1].pos < scanline_events[i].pos
-           || (scanline_events[i + 1].pos == scanline_events[i].pos
-               && scanline_events[i + 1].type == 0
-               && scanline_events[i].type == 1))
+       if (ctx.scanline_events[i + 1].pos < ctx.scanline_events[i].pos
+           || (ctx.scanline_events[i + 1].pos == ctx.scanline_events[i].pos
+               && ctx.scanline_events[i + 1].type == 0
+               && ctx.scanline_events[i].type == 1))
          {
-           t = scanline_events[i + 1];
-           scanline_events[i + 1] = scanline_events[i];
-           scanline_events[i] = t;
+           t = ctx.scanline_events[i + 1];
+           ctx.scanline_events[i + 1] = ctx.scanline_events[i];
+           ctx.scanline_events[i] = t;
            done = 1;
          }
     }
 
-  lastaddr = scanline_events[0].pos;
-  lasttype = scanline_events[0].memtype;
+  lastaddr = ctx.scanline_events[0].pos;
+  lasttype = ctx.scanline_events[0].memtype;
   for (i = 0; i < 2 * mmap_num; i++)
     {
-      unsigned k;
       /* Process event. */
-      if (scanline_events[i].type)
-       present[scanline_events[i].memtype]--;
+      if (ctx.scanline_events[i].type)
+       {
+         if (present[ctx.scanline_events[i].priority].present)
+           {
+             if (present[ctx.scanline_events[i].priority].val == ctx.scanline_events[i].memtype)
+               {
+                 if (present[ctx.scanline_events[i].priority].next)
+                   {
+                     struct mm_list *p = present[ctx.scanline_events[i].priority].next;
+                     present[ctx.scanline_events[i].priority] = *p;
+                     grub_free (p);
+                   }
+                 else
+                   {
+                     present[ctx.scanline_events[i].priority].present = 0;
+                   }
+               }
+             else
+               {
+                 struct mm_list **q = &(present[ctx.scanline_events[i].priority].next), *p;
+                 for (; *q; q = &((*q)->next))
+                   if ((*q)->val == ctx.scanline_events[i].memtype)
+                     {
+                       p = *q;
+                       *q = p->next;
+                       grub_free (p);
+                       break;
+                     }
+               }
+           }
+       }
       else
-       present[scanline_events[i].memtype]++;
+       {
+         if (!present[ctx.scanline_events[i].priority].present)
+           {
+             present[ctx.scanline_events[i].priority].present = 1;
+             present[ctx.scanline_events[i].priority].val = ctx.scanline_events[i].memtype;
+           }
+         else
+           {
+             struct mm_list *n = grub_malloc (sizeof (*n));
+             n->val = ctx.scanline_events[i].memtype;
+             n->present = 1;
+             n->next = present[ctx.scanline_events[i].priority].next;
+             present[ctx.scanline_events[i].priority].next = n;
+           }
+       }
 
       /* Determine current region type. */
       curtype = -1;
-      for (k = 0; k < ARRAY_SIZE (priority); k++)
-       if (present[k] && (curtype == -1 || priority[k] > priority[curtype]))
-         curtype = k;
+      {
+       int k;
+       for (k = current_priority - 1; k >= 0; k--)
+         if (present[k].present)
+           {
+             curtype = present[k].val;
+             break;
+           }
+      }
 
       /* Announce region to the hook if necessary. */
       if ((curtype == -1 || curtype != lasttype)
-         && lastaddr != scanline_events[i].pos
+         && lastaddr != ctx.scanline_events[i].pos
          && lasttype != -1
          && lasttype != GRUB_MEMORY_HOLE
-         && hook (lastaddr, scanline_events[i].pos - lastaddr, lasttype))
+         && hook (lastaddr, ctx.scanline_events[i].pos - lastaddr, lasttype,
+                  hook_data))
        {
-         grub_free (scanline_events);
+         grub_free (ctx.scanline_events);
+         grub_free (present);
          return GRUB_ERR_NONE;
        }
 
@@ -218,11 +278,12 @@ grub_mmap_iterate (grub_memory_hook_t hook)
       if (curtype == -1 || curtype != lasttype)
        {
          lasttype = curtype;
-         lastaddr = scanline_events[i].pos;
+         lastaddr = ctx.scanline_events[i].pos;
        }
     }
 
-  grub_free (scanline_events);
+  grub_free (ctx.scanline_events);
+  grub_free (present);
   return GRUB_ERR_NONE;
 }
 
@@ -237,17 +298,14 @@ grub_mmap_register (grub_uint64_t start, grub_uint64_t size, int type)
   cur = (struct grub_mmap_region *)
     grub_malloc (sizeof (struct grub_mmap_region));
   if (! cur)
-    {
-      grub_error (GRUB_ERR_OUT_OF_MEMORY,
-                 "couldn't allocate memory map overlay");
-      return 0;
-    }
+    return 0;
 
   cur->next = grub_mmap_overlays;
   cur->start = start;
   cur->end = start + size;
   cur->type = type;
   cur->handle = curhandle++;
+  cur->priority = current_priority++;
   grub_mmap_overlays = cur;
 
   if (grub_machine_mmap_register (start, size, type, curhandle))
@@ -265,11 +323,12 @@ grub_mmap_unregister (int handle)
 {
   struct grub_mmap_region *cur, *prev;
 
-  for (cur = grub_mmap_overlays, prev = 0; cur; prev= cur, cur = cur->next)
+  for (cur = grub_mmap_overlays, prev = 0; cur; prev = cur, cur = cur->next)
     if (handle == cur->handle)
       {
        grub_err_t err;
-       if ((err = grub_machine_mmap_unregister (handle)))
+       err = grub_machine_mmap_unregister (handle);
+       if (err)
          return err;
 
        if (prev)
@@ -279,26 +338,30 @@ grub_mmap_unregister (int handle)
        grub_free (cur);
        return GRUB_ERR_NONE;
       }
-  return grub_error (GRUB_ERR_BAD_ARGUMENT, "mmap overlay not found");
+  return grub_error (GRUB_ERR_BUG, "mmap overlay not found");
 }
 
 #endif /* ! GRUB_MMAP_REGISTER_BY_FIRMWARE */
 
 #define CHUNK_SIZE     0x400
 
+struct badram_entry {
+  grub_uint64_t addr, mask;
+};
+
 static inline grub_uint64_t
-fill_mask (grub_uint64_t addr, grub_uint64_t mask, grub_uint64_t iterator)
+fill_mask (struct badram_entry *entry, grub_uint64_t iterator)
 {
   int i, j;
-  grub_uint64_t ret = (addr & mask);
+  grub_uint64_t ret = (entry->addr & entry->mask);
 
   /* Find first fixed bit. */
   for (i = 0; i < 64; i++)
-    if ((mask & (1ULL << i)) != 0)
+    if ((entry->mask & (1ULL << i)) != 0)
       break;
   j = 0;
   for (; i < 64; i++)
-    if ((mask & (1ULL << i)) == 0)
+    if ((entry->mask & (1ULL << i)) == 0)
       {
        if ((iterator & (1ULL << j)) != 0)
          ret |= 1ULL << i;
@@ -307,67 +370,67 @@ fill_mask (grub_uint64_t addr, grub_uint64_t mask, grub_uint64_t iterator)
   return ret;
 }
 
+/* Helper for grub_cmd_badram.  */
+static int
+badram_iter (grub_uint64_t addr, grub_uint64_t size,
+            grub_memory_type_t type __attribute__ ((unused)), void *data)
+{
+  struct badram_entry *entry = data;
+  grub_uint64_t iterator, low, high, cur;
+  int tail, var;
+  int i;
+  grub_dprintf ("badram", "hook %llx+%llx\n", (unsigned long long) addr,
+               (unsigned long long) size);
+
+  /* How many trailing zeros? */
+  for (tail = 0; ! (entry->mask & (1ULL << tail)); tail++);
+
+  /* How many zeros in mask? */
+  var = 0;
+  for (i = 0; i < 64; i++)
+    if (! (entry->mask & (1ULL << i)))
+      var++;
+
+  if (fill_mask (entry, 0) >= addr)
+    iterator = 0;
+  else
+    {
+      low = 0;
+      high = ~0ULL;
+      /* Find starting value. Keep low and high such that
+        fill_mask (low) < addr and fill_mask (high) >= addr;
+      */
+      while (high - low > 1)
+       {
+         cur = (low + high) / 2;
+         if (fill_mask (entry, cur) >= addr)
+           high = cur;
+         else
+           low = cur;
+       }
+      iterator = high;
+    }
+
+  for (; iterator < (1ULL << (var - tail))
+        && (cur = fill_mask (entry, iterator)) < addr + size;
+       iterator++)
+    {
+      grub_dprintf ("badram", "%llx (size %llx) is a badram range\n",
+                   (unsigned long long) cur, (1ULL << tail));
+      grub_mmap_register (cur, (1ULL << tail), GRUB_MEMORY_HOLE);
+    }
+  return 0;
+}
+
 static grub_err_t
 grub_cmd_badram (grub_command_t cmd __attribute__ ((unused)),
                 int argc, char **args)
 {
-  char * str;
-  grub_uint64_t badaddr, badmask;
-
-  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t,
-                                grub_memory_type_t);
-  int NESTED_FUNC_ATTR hook (grub_uint64_t addr,
-                            grub_uint64_t size,
-                            grub_memory_type_t type __attribute__ ((unused)))
-  {
-    grub_uint64_t iterator, low, high, cur;
-    int tail, var;
-    int i;
-    grub_dprintf ("badram", "hook %llx+%llx\n", (unsigned long long) addr,
-                 (unsigned long long) size);
-
-    /* How many trailing zeros? */
-    for (tail = 0; ! (badmask & (1ULL << tail)); tail++);
-
-    /* How many zeros in mask? */
-    var = 0;
-    for (i = 0; i < 64; i++)
-      if (! (badmask & (1ULL << i)))
-       var++;
-
-    if (fill_mask (badaddr, badmask, 0) >= addr)
-      iterator = 0;
-    else
-      {
-       low = 0;
-       high = ~0ULL;
-       /* Find starting value. Keep low and high such that
-          fill_mask (low) < addr and fill_mask (high) >= addr;
-       */
-       while (high - low > 1)
-         {
-           cur = (low + high) / 2;
-           if (fill_mask (badaddr, badmask, cur) >= addr)
-             high = cur;
-           else
-             low = cur;
-         }
-       iterator = high;
-      }
-
-    for (; iterator < (1ULL << (var - tail))
-          && (cur = fill_mask (badaddr, badmask, iterator)) < addr + size;
-        iterator++)
-      {
-       grub_dprintf ("badram", "%llx (size %llx) is a badram range\n",
-                     (unsigned long long) cur, (1ULL << tail));
-       grub_mmap_register (cur, (1ULL << tail), GRUB_MEMORY_HOLE);
-      }
-    return 0;
-  }
+  const char *str;
+  struct badram_entry entry;
 
   if (argc != 1)
-    return grub_error (GRUB_ERR_BAD_ARGUMENT, "badram string required");
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
 
   grub_dprintf ("badram", "executing badram\n");
 
@@ -376,10 +439,10 @@ grub_cmd_badram (grub_command_t cmd __attribute__ ((unused)),
   while (1)
     {
       /* Parse address and mask.  */
-      badaddr = grub_strtoull (str, &str, 16);
+      entry.addr = grub_strtoull (str, &str, 16);
       if (*str == ',')
        str++;
-      badmask = grub_strtoull (str, &str, 16);
+      entry.mask = grub_strtoull (str, &str, 16);
       if (*str == ',')
        str++;
 
@@ -391,12 +454,13 @@ grub_cmd_badram (grub_command_t cmd __attribute__ ((unused)),
 
       /* When part of a page is tainted, we discard the whole of it.  There's
         no point in providing sub-page chunks.  */
-      badmask &= ~(CHUNK_SIZE - 1);
+      entry.mask &= ~(CHUNK_SIZE - 1);
 
       grub_dprintf ("badram", "badram %llx:%llx\n",
-                   (unsigned long long) badaddr, (unsigned long long) badmask);
+                   (unsigned long long) entry.addr,
+                   (unsigned long long) entry.mask);
 
-      grub_mmap_iterate (hook);
+      grub_mmap_iterate (badram_iter, &entry);
     }
 }
 
@@ -404,7 +468,7 @@ static grub_uint64_t
 parsemem (const char *str)
 {
   grub_uint64_t ret;
-  char *ptr;
+  const char *ptr;
 
   ret = grub_strtoul (str, &ptr, 0);
 
@@ -422,44 +486,48 @@ parsemem (const char *str)
   return ret;
 }
 
-static grub_err_t
-grub_cmd_cutmem (grub_command_t cmd __attribute__ ((unused)),
-                int argc, char **args)
-{
+struct cutmem_range {
   grub_uint64_t from, to;
+};
 
-  auto int NESTED_FUNC_ATTR hook (grub_uint64_t, grub_uint64_t,
-                                grub_memory_type_t);
-  int NESTED_FUNC_ATTR hook (grub_uint64_t addr,
-                            grub_uint64_t size,
-                            grub_memory_type_t type __attribute__ ((unused)))
-  {
-    grub_uint64_t end = addr + size;
-
-    if (addr <= from)
-      addr = from;
-    if (end >= to)
-      end = to;
+/* Helper for grub_cmd_cutmem.  */
+static int
+cutmem_iter (grub_uint64_t addr, grub_uint64_t size,
+            grub_memory_type_t type __attribute__ ((unused)), void *data)
+{
+  struct cutmem_range *range = data;
+  grub_uint64_t end = addr + size;
 
-    if (end <= addr)
-      return 0;
+  if (addr <= range->from)
+    addr = range->from;
+  if (end >= range->to)
+    end = range->to;
 
-    grub_mmap_register (addr, end - addr, GRUB_MEMORY_HOLE);
+  if (end <= addr)
     return 0;
-  }
+
+  grub_mmap_register (addr, end - addr, GRUB_MEMORY_HOLE);
+  return 0;
+}
+
+static grub_err_t
+grub_cmd_cutmem (grub_command_t cmd __attribute__ ((unused)),
+                int argc, char **args)
+{
+  struct cutmem_range range;
 
   if (argc != 2)
-    return grub_error (GRUB_ERR_BAD_ARGUMENT, "argements required");
+    return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("two arguments expected"));
 
-  from = parsemem (args[0]);
+  range.from = parsemem (args[0]);
   if (grub_errno)
     return grub_errno;
 
-  to = parsemem (args[1]);
+  range.to = parsemem (args[1]);
   if (grub_errno)
     return grub_errno;
 
-  grub_mmap_iterate (hook);
+  grub_mmap_iterate (cutmem_iter, &range);
 
   return GRUB_ERR_NONE;
 }
@@ -469,12 +537,12 @@ static grub_command_t cmd, cmd_cut;
 \f
 GRUB_MOD_INIT(mmap)
 {
-  cmd = grub_register_command ("badram", grub_cmd_badram,
-                              N_("ADDR1,MASK1[,ADDR2,MASK2[,...]]"),
-                              N_("Declare memory regions as badram."));
-  cmd_cut = grub_register_command ("cutmem", grub_cmd_cutmem,
-                                  N_("FROM[K|M|G] TO[K|M|G]"),
-                                  N_("Remove any memory regions in specified range."));
+  cmd = grub_register_command_lockdown ("badram", grub_cmd_badram,
+                                        N_("ADDR1,MASK1[,ADDR2,MASK2[,...]]"),
+                                        N_("Declare memory regions as faulty (badram)."));
+  cmd_cut = grub_register_command_lockdown ("cutmem", grub_cmd_cutmem,
+                                            N_("FROM[K|M|G] TO[K|M|G]"),
+                                            N_("Remove any memory regions in specified range."));
 
 }