b35c50
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
b35c50
From: Jeremy Linton <jeremy.linton@arm.com>
b35c50
Date: Tue, 6 Sep 2022 15:33:03 -0500
b35c50
Subject: [PATCH] Correct BSS zeroing on aarch64
b35c50
b35c50
The aarch64 loader doesn't use efi bootservices, and
b35c50
therefor it has a very minimal loader which makes a lot
b35c50
of assumptions about the kernel layout. With the ZBOOT
b35c50
changes, the layout has changed a bit and we not should
b35c50
really be parsing the PE sections to determine how much
b35c50
data to copy, otherwise the BSS won't be setup properly.
b35c50
b35c50
This code still makes a lot of assumptions about the
b35c50
the kernel layout, so its far from ideal, but it works.
b35c50
b35c50
Resolves: rhbz#2125069
b35c50
b35c50
Signed-off-by: Jeremy Linton <jeremy.linton@arm.com>
b35c50
---
b35c50
 grub-core/loader/arm64/linux.c | 27 ++++++++++++++++++++++-----
b35c50
 1 file changed, 22 insertions(+), 5 deletions(-)
b35c50
b35c50
diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c
b35c50
index 489d0c7173..419f2201df 100644
b35c50
--- a/grub-core/loader/arm64/linux.c
b35c50
+++ b/grub-core/loader/arm64/linux.c
b35c50
@@ -316,10 +316,12 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
b35c50
 static grub_err_t
b35c50
 parse_pe_header (void *kernel, grub_uint64_t *total_size,
b35c50
 		 grub_uint32_t *entry_offset,
b35c50
-		 grub_uint32_t *alignment)
b35c50
+		 grub_uint32_t *alignment,grub_uint32_t *code_size)
b35c50
 {
b35c50
   struct linux_arch_kernel_header *lh = kernel;
b35c50
   struct grub_armxx_linux_pe_header *pe;
b35c50
+  grub_uint16_t i;
b35c50
+  struct grub_pe32_section_table *sections;
b35c50
 
b35c50
   pe = (void *)((unsigned long)kernel + lh->hdr_offset);
b35c50
 
b35c50
@@ -329,6 +331,19 @@ parse_pe_header (void *kernel, grub_uint64_t *total_size,
b35c50
   *total_size   = pe->opt.image_size;
b35c50
   *entry_offset = pe->opt.entry_addr;
b35c50
   *alignment    = pe->opt.section_alignment;
b35c50
+  *code_size    = pe->opt.section_alignment;
b35c50
+
b35c50
+  sections = (struct grub_pe32_section_table *) ((char *)&pe->opt +
b35c50
+						 pe->coff.optional_header_size);
b35c50
+  grub_dprintf ("linux", "num_sections     : %d\n",  pe->coff.num_sections );
b35c50
+  for (i = 0 ; i < pe->coff.num_sections; i++)
b35c50
+    {
b35c50
+      grub_dprintf ("linux", "raw_size   : %lld\n",
b35c50
+		    (long long) sections[i].raw_data_size);
b35c50
+      grub_dprintf ("linux", "virt_size  : %lld\n",
b35c50
+		    (long long) sections[i].virtual_size);
b35c50
+      *code_size += sections[i].raw_data_size;
b35c50
+    }
b35c50
 
b35c50
   return GRUB_ERR_NONE;
b35c50
 }
b35c50
@@ -341,6 +356,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
b35c50
   grub_err_t err;
b35c50
   grub_off_t filelen;
b35c50
   grub_uint32_t align;
b35c50
+  grub_uint32_t code_size;
b35c50
   void *kernel = NULL;
b35c50
   int nx_supported = 1;
b35c50
 
b35c50
@@ -373,11 +389,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
b35c50
 
b35c50
   if (grub_arch_efi_linux_check_image (kernel) != GRUB_ERR_NONE)
b35c50
     goto fail;
b35c50
-  if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align) != GRUB_ERR_NONE)
b35c50
+  if (parse_pe_header (kernel, &kernel_size, &handover_offset, &align, &code_size) != GRUB_ERR_NONE)
b35c50
     goto fail;
b35c50
   grub_dprintf ("linux", "kernel mem size     : %lld\n", (long long) kernel_size);
b35c50
   grub_dprintf ("linux", "kernel entry offset : %d\n", handover_offset);
b35c50
   grub_dprintf ("linux", "kernel alignment    : 0x%x\n", align);
b35c50
+  grub_dprintf ("linux", "kernel size         : 0x%x\n", code_size);
b35c50
 
b35c50
   err = grub_efi_check_nx_image_support((grub_addr_t)kernel, filelen, &nx_supported);
b35c50
   if (err != GRUB_ERR_NONE)
b35c50
@@ -396,9 +413,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
b35c50
   kernel_addr = (void *)ALIGN_UP((grub_uint64_t)kernel_alloc_addr, align);
b35c50
 
b35c50
   grub_dprintf ("linux", "kernel @ %p\n", kernel_addr);
b35c50
-  grub_memcpy (kernel_addr, kernel, grub_min(filelen, kernel_size));
b35c50
-  if (kernel_size > filelen)
b35c50
-    grub_memset ((char *)kernel_addr + filelen, 0, kernel_size - filelen);
b35c50
+  grub_memcpy (kernel_addr, kernel, grub_min(code_size, kernel_size));
b35c50
+  if (kernel_size > code_size)
b35c50
+    grub_memset ((char *)kernel_addr + code_size, 0, kernel_size - code_size);
b35c50
   grub_free(kernel);
b35c50
   kernel = NULL;
b35c50