This command for x86_64 and arm64 shows current paging table on platforms
in question.

Signed-off-by: Vladimir Serbinenko <phco...@gmail.com>
---
 grub-core/Makefile.core.def          |   8 ++
 grub-core/commands/arm64/lspaging.c  | 138 +++++++++++++++++++++++++++
 grub-core/commands/x86_64/lspaging.c | 115 ++++++++++++++++++++++
 3 files changed, 261 insertions(+)
 create mode 100644 grub-core/commands/arm64/lspaging.c
 create mode 100644 grub-core/commands/x86_64/lspaging.c

diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def
index f70e02e69..7f8cb3f7d 100644
--- a/grub-core/Makefile.core.def
+++ b/grub-core/Makefile.core.def
@@ -814,6 +814,14 @@ module = {
   enable = efi;
 };
 
+module = {
+  name = lspaging;
+  x86_64_efi = commands/x86_64/lspaging.c;
+  arm64_efi = commands/arm64/lspaging.c;
+  enable = arm64_efi;
+  enable = x86_64_efi;
+};
+
 module = {
   name = lsefimmap;
 
diff --git a/grub-core/commands/arm64/lspaging.c 
b/grub-core/commands/arm64/lspaging.c
new file mode 100644
index 000000000..3d18a09c3
--- /dev/null
+++ b/grub-core/commands/arm64/lspaging.c
@@ -0,0 +1,138 @@
+/* lspaging.c  - Display paging table.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2025  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  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/>.
+ */
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/normal.h>
+#include <grub/charset.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/dl.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+typedef enum {UNMAPPED, NONIDENTITY, IDENTITY} mapping_type_t;
+
+static const char *mapping_names[] = {
+  "unmapped",
+  "non-identity",
+  "identity",
+};
+
+static bool
+process_level(grub_uint64_t *start_address, mapping_type_t *start_type,
+             grub_uint64_t *next_address, grub_uint64_t *lx, grub_uint64_t 
cur_address, int offset)
+{
+  mapping_type_t cur_type;
+  grub_uint64_t entry = ((grub_uint64_t *)*lx)[(cur_address >> offset) & 
0x1ff];
+  switch (entry & 3)
+    {
+    case 0:
+    case 2:
+      cur_type = UNMAPPED;
+      break;
+    case 3: /* Table entry */
+      if (offset != 12)
+       {
+         *lx = (entry & 0xfffffffff000);
+         return false;
+       }
+      /* Fallthrough */
+    case 1:
+      cur_type = ((entry & 0xfffffffff000) == (cur_address & 0xfffffffff000)) 
? IDENTITY : NONIDENTITY;
+      break;
+    }
+
+  *next_address = ((cur_address >> offset) + 1) << offset;
+
+  if (*start_type != cur_type)
+    {
+      if (cur_address != 0)
+       grub_printf("%08lx-%08lx: %s\n", *start_address, cur_address, 
mapping_names[*start_type]);
+      *start_type = cur_type;
+      *start_address = cur_address;
+    }
+
+  return true;
+}
+
+static grub_err_t
+grub_cmd_lspaging (struct grub_command *cmd __attribute__ ((unused)),
+               int argc __attribute__ ((unused)),
+               char **args __attribute__ ((unused)))
+{
+  grub_uint64_t tcr_el1, ttbr0_el1;
+  grub_uint64_t id_aa64mmfr3_el1;
+  asm volatile ("mrs       %0, id_aa64mmfr3_el1": "=r"(id_aa64mmfr3_el1));
+
+  if (id_aa64mmfr3_el1 & 0xf)
+    {
+      grub_uint64_t tcr2_el1;
+
+      asm volatile ("mrs       %0, s3_0_c2_c0_3": "=r"(tcr2_el1));
+      if ((tcr2_el1 >> 5) & 1)
+       return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "Parsing D128 tables 
isn't supported yet");
+    }
+  asm volatile ("mrs       %0, tcr_el1": "=r"(tcr_el1));
+
+  if ((tcr_el1 >> 14) & 3)
+    return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "non-4K page tables aren't 
supported yet");
+
+  grub_uint64_t t0sz = tcr_el1 & 0x3f;
+
+  if (t0sz >= 25)
+    return grub_error(GRUB_ERR_NOT_IMPLEMENTED_YET, "T0SZ %ld isn't supported 
yet", t0sz);
+
+  asm volatile ("mrs       %0, ttbr0_el1": "=r"(ttbr0_el1));
+
+  grub_uint64_t baddr = (ttbr0_el1 & 0xfffffffffffell);
+  grub_uint64_t start_address = 0, cur_address = 0, next_address = 0;
+  mapping_type_t start_type = UNMAPPED;
+
+  grub_printf("baddr=%lx\n", baddr);
+
+  for (cur_address = 0; cur_address < 0x7fffffffffff; cur_address = 
next_address)
+    {
+      grub_uint64_t lx = baddr;
+      if (process_level(&start_address, &start_type, &next_address, &lx, 
cur_address, 39))
+       continue;
+      if (process_level(&start_address, &start_type, &next_address, &lx, 
cur_address, 30))
+       continue;
+      if (process_level(&start_address, &start_type, &next_address, &lx, 
cur_address, 21))
+       continue;
+      process_level(&start_address, &start_type, &next_address, &lx, 
cur_address, 12);
+    }
+
+  grub_printf("%08lx-%08lx: %s\n", start_address, cur_address, 
mapping_names[start_type]);
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(lspaging)
+{
+  cmd = grub_register_command ("lspaging", grub_cmd_lspaging, "",
+                              "Display paging table.");
+}
+
+GRUB_MOD_FINI(lspaging)
+{
+  grub_unregister_command (cmd);
+}
diff --git a/grub-core/commands/x86_64/lspaging.c 
b/grub-core/commands/x86_64/lspaging.c
new file mode 100644
index 000000000..ddd39904f
--- /dev/null
+++ b/grub-core/commands/x86_64/lspaging.c
@@ -0,0 +1,115 @@
+/* lspaging.c  - Display paging table.  */
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2025  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  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/>.
+ */
+#include <grub/types.h>
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/normal.h>
+#include <grub/charset.h>
+#include <grub/efi/api.h>
+#include <grub/efi/efi.h>
+#include <grub/dl.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+typedef enum {UNMAPPED, NONIDENTITY, IDENTITY} mapping_type_t;
+
+static const char *mapping_names[] = {
+  "unmapped",
+  "non-identity",
+  "identity",
+};
+
+static bool
+process_level(grub_uint64_t *start_address, mapping_type_t *start_type,
+             grub_uint64_t *next_address, grub_uint64_t *lx, grub_uint64_t 
cur_address, int offset)
+{
+  mapping_type_t cur_type;
+  grub_uint64_t entry = ((grub_uint64_t *)*lx)[(cur_address >> offset) & 
0x1ff];
+  if ((entry & 1) && offset != 12 && !(entry & 0x80))
+    {
+      *lx = (entry & 0xfffffffff000);
+      return false;
+    }
+
+  if ((entry & 1) == 0)
+    {
+      cur_type = UNMAPPED;
+    }
+  else
+    {
+      cur_type = ((entry & 0xfffffffff000) == (cur_address & 0xfffffffff000)) 
? IDENTITY : NONIDENTITY;
+    }
+
+  *next_address = ((cur_address >> offset) + 1) << offset;
+
+  if (*start_type != cur_type)
+    {
+      if (cur_address != 0)
+       grub_printf("%08lx-%08lx: %s\n", *start_address, cur_address, 
mapping_names[*start_type]);
+      *start_type = cur_type;
+      *start_address = cur_address;
+    }
+
+  return true;
+}
+
+static grub_err_t
+grub_cmd_lspaging (struct grub_command *cmd __attribute__ ((unused)),
+               int argc __attribute__ ((unused)),
+               char **args __attribute__ ((unused)))
+{
+  grub_uint64_t cr3;
+
+  asm volatile ("movq       %%cr3, %0": "=r"(cr3));
+
+  grub_uint64_t baddr = cr3;
+  grub_uint64_t start_address = 0, cur_address = 0, next_address = 0;
+  mapping_type_t start_type = UNMAPPED;
+
+  grub_printf("baddr=%lx\n", baddr);
+
+  for (cur_address = 0; cur_address < 0x7fffffffffff; cur_address = 
next_address)
+    {
+      grub_uint64_t lx = baddr;
+      if (process_level(&start_address, &start_type, &next_address, &lx, 
cur_address, 39))
+       continue;
+      if (process_level(&start_address, &start_type, &next_address, &lx, 
cur_address, 30))
+       continue;
+      if (process_level(&start_address, &start_type, &next_address, &lx, 
cur_address, 21))
+       continue;
+      process_level(&start_address, &start_type, &next_address, &lx, 
cur_address, 12);
+    }
+
+  grub_printf("%08lx-%08lx: %s\n", start_address, cur_address, 
mapping_names[start_type]);
+
+  return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd;
+
+GRUB_MOD_INIT(lspaging)
+{
+  cmd = grub_register_command ("lspaging", grub_cmd_lspaging, "",
+                              "Display paging table.");
+}
+
+GRUB_MOD_FINI(lspaging)
+{
+  grub_unregister_command (cmd);
+}
-- 
2.49.0


_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to