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