All of lore.kernel.org
 help / color / mirror / Atom feed
* Grub UEFI memory allocation patch
@ 2010-04-03 20:06 Bernon, Rémi
  2010-04-03 20:22 ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 1 reply; 5+ messages in thread
From: Bernon, Rémi @ 2010-04-03 20:06 UTC (permalink / raw)
  To: grub-devel

[-- Attachment #1: Type: text/plain, Size: 1557 bytes --]

Hi,

I was trying for a few days to enable EFI boot on my laptop, and i've
encountered some issues with Grub2.

My motherboard is one of the modern Intel chipset motherboard, that
come with UEFI v2, and when i tried to boot using grub 1.98, compiled
with efi support, there was some memory allocation error message at
the kernel loading time, saying "cannot allocate protected mode page"
or something like that.

So, i looked into the grub source code, and found that it tries to
allocate memory at a hard coded memory address (0X10000), that was
already in use, for my computer.

I've also found parts of the code in loader/i386/linux.c that were
looking for free pages in the memory map, which is already done by the
EFI memory allocation function.
Actually, i've managed to make it working, by letting EFI find free
memory pages and allocate them, but i dont really know how important
this 0x10000 address is.

My fix works for me, but I think it may be connected to the fact I've
also build a relocatable kernel. I don't know enough about "kernel
loading" and bootloaders to determine if my fix will work well in all
situations or not, so maybe someone can tell me that.

Actually, i've still have an issue at shutdown time : the kernel (or
grub ?) crashes with an error message "Bad RIP value" and a full stack
trace with an EFI call, just when it is expected to power down. So, i
need to poweroff or reboot it manually, using the power switch. I
anyone have an idea from where the error comes, i'm interested.

Rémi

[-- Attachment #2: 909_efi_allocations.diff --]
[-- Type: text/x-patch, Size: 9275 bytes --]

diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h
index 5852a47..996b545 100644
--- a/include/grub/efi/efi.h
+++ b/include/grub/efi/efi.h
@@ -37,9 +37,22 @@ void *EXPORT_FUNC(grub_efi_open_protocol) (grub_efi_handle_t handle,
 					   grub_efi_uint32_t attributes);
 int EXPORT_FUNC(grub_efi_set_text_mode) (int on);
 void EXPORT_FUNC(grub_efi_stall) (grub_efi_uintn_t microseconds);
+
+void *
+EXPORT_FUNC(grub_efi_allocate_any_pages) (grub_efi_uintn_t pages,
+                                          grub_efi_memory_type_t memtype);
+void *
+EXPORT_FUNC(grub_efi_allocate_pages_before) (grub_efi_physical_address_t address,
+		 			     grub_efi_uintn_t pages,
+                                             grub_efi_memory_type_t memtype);
 void *
 EXPORT_FUNC(grub_efi_allocate_pages) (grub_efi_physical_address_t address,
 				      grub_efi_uintn_t pages);
+void *
+EXPORT_FUNC(grub_efi_typed_allocate_pages) (grub_efi_physical_address_t address,
+					    grub_efi_uintn_t pages,
+					    grub_efi_allocate_type_t type,
+	                                    grub_efi_memory_type_t memtype);
 void EXPORT_FUNC(grub_efi_free_pages) (grub_efi_physical_address_t address,
 				       grub_efi_uintn_t pages);
 int
diff --git a/kern/efi/mm.c b/kern/efi/mm.c
index ceb8fc9..0138ed3 100644
--- a/kern/efi/mm.c
+++ b/kern/efi/mm.c
@@ -49,6 +49,20 @@ static struct allocated_page *allocated_pages = 0;
 #define MIN_HEAP_SIZE	0x100000
 #define MAX_HEAP_SIZE	(1600 * 0x100000)
 
+void *
+grub_efi_allocate_any_pages (grub_efi_uintn_t pages,
+                             grub_efi_memory_type_t memtype)
+{
+  return grub_efi_typed_allocate_pages (0, pages, GRUB_EFI_ALLOCATE_ANY_PAGES, memtype);
+}
+
+void *
+grub_efi_allocate_pages_before (grub_efi_physical_address_t address,
+		 		grub_efi_uintn_t pages,
+                                grub_efi_memory_type_t memtype)
+{
+  return grub_efi_typed_allocate_pages (address, pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, memtype);
+}
 
 /* Allocate pages. Return the pointer to the first of allocated pages.  */
 void *
@@ -56,14 +70,6 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address,
 			 grub_efi_uintn_t pages)
 {
   grub_efi_allocate_type_t type;
-  grub_efi_status_t status;
-  grub_efi_boot_services_t *b;
-
-#if GRUB_TARGET_SIZEOF_VOID_P < 8
-  /* Limit the memory access to less than 4GB for 32-bit platforms.  */
-  if (address > 0xffffffff)
-    return 0;
-#endif
 
 #if GRUB_TARGET_SIZEOF_VOID_P < 8 || defined (MCMODEL_SMALL)
   if (address == 0)
@@ -80,20 +86,40 @@ grub_efi_allocate_pages (grub_efi_physical_address_t address,
     type = GRUB_EFI_ALLOCATE_ADDRESS;
 #endif
 
+  return grub_efi_typed_allocate_pages (address, pages, type, GRUB_EFI_LOADER_DATA);
+}
+
+void *
+grub_efi_typed_allocate_pages (grub_efi_physical_address_t address,
+			       grub_efi_uintn_t pages,
+			       grub_efi_allocate_type_t type,
+                               grub_efi_memory_type_t memtype)
+{
+  grub_efi_status_t status;
+  grub_efi_boot_services_t *b;
+
+#if GRUB_TARGET_SIZEOF_VOID_P < 8
+  /* Limit the memory access to less than 4GB for 32-bit platforms.  */
+  if (address > 0xffffffff)
+    return 0;
+#endif
+
   b = grub_efi_system_table->boot_services;
-  status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address);
-  if (status != GRUB_EFI_SUCCESS)
+  status = efi_call_4 (b->allocate_pages, type, memtype, pages, &address);
+  if (status != GRUB_EFI_SUCCESS) {
     return 0;
+  }
 
   if (address == 0)
     {
       /* Uggh, the address 0 was allocated... This is too annoying,
 	 so reallocate another one.  */
       address = 0xffffffff;
-      status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_LOADER_DATA, pages, &address);
+      status = efi_call_4 (b->allocate_pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, memtype, pages, &address);
       grub_efi_free_pages (0, pages);
-      if (status != GRUB_EFI_SUCCESS)
-	return 0;
+      if (status != GRUB_EFI_SUCCESS) {
+        return 0;
+      }
     }
 
   if (allocated_pages)
diff --git a/loader/i386/efi/linux.c b/loader/i386/efi/linux.c
index a6db22e..fda4362 100644
--- a/loader/i386/efi/linux.c
+++ b/loader/i386/efi/linux.c
@@ -161,10 +161,8 @@ free_pages (void)
 static int
 allocate_pages (grub_size_t prot_size)
 {
-  grub_efi_uintn_t desc_size;
-  grub_efi_memory_descriptor_t *mmap, *mmap_end;
-  grub_efi_uintn_t mmap_size, tmp_mmap_size;
-  grub_efi_memory_descriptor_t *desc;
+  grub_efi_memory_descriptor_t *mmap;
+  grub_efi_uintn_t mmap_size;
   grub_size_t real_size;
 
   /* Make sure that each size is aligned to a page boundary.  */
@@ -184,53 +182,7 @@ allocate_pages (grub_size_t prot_size)
   real_mode_mem = 0;
   prot_mode_mem = 0;
 
-  /* Read the memory map temporarily, to find free space.  */
-  mmap = grub_malloc (mmap_size);
-  if (! mmap)
-    return 0;
-
-  tmp_mmap_size = mmap_size;
-  if (grub_efi_get_memory_map (&tmp_mmap_size, mmap, 0, &desc_size, 0) <= 0)
-    grub_fatal ("cannot get memory map");
-
-  mmap_end = NEXT_MEMORY_DESCRIPTOR (mmap, tmp_mmap_size);
-
-  /* First, find free pages for the real mode code
-     and the memory map buffer.  */
-  for (desc = mmap;
-       desc < mmap_end;
-       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
-    {
-      /* Probably it is better to put the real mode code in the traditional
-	 space for safety.  */
-      if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
-	  && desc->physical_start <= 0x90000
-	  && desc->num_pages >= real_mode_pages)
-	{
-	  grub_efi_physical_address_t physical_end;
-	  grub_efi_physical_address_t addr;
-
-	  physical_end = desc->physical_start + (desc->num_pages << 12);
-	  if (physical_end > 0x90000)
-	    physical_end = 0x90000;
-
-	  grub_dprintf ("linux", "physical_start = %x, physical_end = %x\n",
-			(unsigned) desc->physical_start,
-			(unsigned) physical_end);
-	  addr = physical_end - real_size - mmap_size;
-	  if (addr < 0x10000)
-	    continue;
-
-	  grub_dprintf ("linux", "trying to allocate %u pages at %lx\n",
-			(unsigned) real_mode_pages, (unsigned long) addr);
-	  real_mode_mem = grub_efi_allocate_pages (addr, real_mode_pages);
-	  if (! real_mode_mem)
-	    grub_fatal ("cannot allocate pages");
-
-	  desc->num_pages -= real_mode_pages;
-	  break;
-	}
-    }
+  real_mode_mem = grub_efi_allocate_pages_before (0x90000, real_mode_pages, GRUB_EFI_LOADER_DATA);
 
   if (! real_mode_mem)
     {
@@ -242,7 +194,7 @@ allocate_pages (grub_size_t prot_size)
 
   /* Next, find free pages for the protected mode code.  */
   /* XXX what happens if anything is using this address?  */
-  prot_mode_mem = grub_efi_allocate_pages (0x100000, prot_mode_pages + 1);
+  prot_mode_mem = grub_efi_allocate_any_pages(prot_mode_pages + 1, GRUB_EFI_LOADER_DATA);
   if (! prot_mode_mem)
     {
       grub_error (GRUB_ERR_OUT_OF_MEMORY,
@@ -900,11 +852,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
 {
   grub_file_t file = 0;
   grub_ssize_t size;
-  grub_addr_t addr_min, addr_max;
-  grub_addr_t addr;
-  grub_efi_uintn_t mmap_size;
-  grub_efi_memory_descriptor_t *desc;
-  grub_efi_uintn_t desc_size;
+  grub_addr_t addr_max;
   struct linux_kernel_header *lh;
 
   if (argc == 0)
@@ -938,48 +886,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
      worse than that of Linux 2.3.xx, so avoid the last 64kb.  */
   addr_max -= 0x10000;
 
-  /* Usually, the compression ratio is about 50%.  */
-  addr_min = (grub_addr_t) prot_mode_mem + ((prot_mode_pages * 3) << 12)
-	     + page_align (size);
-
-  /* Find the highest address to put the initrd.  */
-  mmap_size = find_mmap_size ();
-  if (grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0) <= 0)
-    grub_fatal ("cannot get memory map");
-
-  addr = 0;
-  for (desc = mmap_buf;
-       desc < NEXT_MEMORY_DESCRIPTOR (mmap_buf, mmap_size);
-       desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size))
-    {
-      if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY
-	  && desc->num_pages >= initrd_pages)
-	{
-	  grub_efi_physical_address_t physical_end;
-
-	  physical_end = desc->physical_start + (desc->num_pages << 12);
-	  if (physical_end > addr_max)
-	    physical_end = addr_max;
-
-	  if (physical_end < page_align (size))
-	    continue;
-
-	  physical_end -= page_align (size);
-
-	  if ((physical_end >= addr_min) &&
-	      (physical_end >= desc->physical_start) &&
-	      (physical_end > addr))
-	    addr = physical_end;
-	}
-    }
-
-  if (addr == 0)
-    {
-      grub_error (GRUB_ERR_OUT_OF_MEMORY, "no free pages available");
-      goto fail;
-    }
-
-  initrd_mem = grub_efi_allocate_pages (addr, initrd_pages);
+  initrd_mem = grub_efi_allocate_pages_before (addr_max, initrd_pages, GRUB_EFI_LOADER_DATA);
   if (! initrd_mem)
     grub_fatal ("cannot allocate pages");
 
@@ -989,10 +896,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
       goto fail;
     }
 
-  grub_printf ("   [Initrd, addr=0x%x, size=0x%x]\n",
-	       (unsigned) addr, (unsigned) size);
+  grub_printf ("   [Initrd, addr=0x%lx, size=0x%x]\n",
+	       (grub_addr_t) initrd_mem, (unsigned) size);
 
-  lh->ramdisk_image = addr;
+  lh->ramdisk_image = (grub_addr_t) initrd_mem;
   lh->ramdisk_size = size;
   lh->root_dev = 0x0100; /* XXX */
 

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: Grub UEFI memory allocation patch
  2010-04-03 20:06 Grub UEFI memory allocation patch Bernon, Rémi
@ 2010-04-03 20:22 ` Vladimir 'φ-coder/phcoder' Serbinenko
  2010-04-03 20:42   ` Bernon, Rémi
  0 siblings, 1 reply; 5+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2010-04-03 20:22 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 572 bytes --]

Bernon wrote:
> I've also found parts of the code in loader/i386/linux.c that were
> looking for free pages in the memory map, which is already done by the
> EFI memory allocation function.
> Actually, i've managed to make it working, by letting EFI find free
> memory pages and allocate them, but i dont really know how important
> this 0x10000 address is.
>
>   
It is important and we have an experimental stuff in my newreloc branch
to workaround the problem. It was already explained on the list

-- 
Regards
Vladimir 'φ-coder/phcoder' Serbinenko



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 293 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Grub UEFI memory allocation patch
  2010-04-03 20:22 ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2010-04-03 20:42   ` Bernon, Rémi
  2010-04-03 20:59     ` Vladimir 'φ-coder/phcoder' Serbinenko
  0 siblings, 1 reply; 5+ messages in thread
From: Bernon, Rémi @ 2010-04-03 20:42 UTC (permalink / raw)
  To: The development of GNU GRUB

Actually, I've read the answer you made to someone who had the same
memory issue as I had, and I tried the newreloc branch, but it doesn't
even build when targeting efi platform. The "loader/i386/efi/linux.c"
file is missing in this branch.

I will look for explanation  about this part of code, in the mailing
list archives, however, as i said, the fix works fine for me. The only
error i have noticed, occurs on shutdown, and also occurs when i boot
using elilo.

Regards,
Rémi Bernon



^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Grub UEFI memory allocation patch
  2010-04-03 20:42   ` Bernon, Rémi
@ 2010-04-03 20:59     ` Vladimir 'φ-coder/phcoder' Serbinenko
  2010-04-03 21:07       ` Bernon, Rémi
  0 siblings, 1 reply; 5+ messages in thread
From: Vladimir 'φ-coder/phcoder' Serbinenko @ 2010-04-03 20:59 UTC (permalink / raw)
  To: The development of GNU GRUB

[-- Attachment #1: Type: text/plain, Size: 1139 bytes --]

Bernon wrote:
> Actually, I've read the answer you made to someone who had the same
> memory issue as I had, and I tried the newreloc branch, but it doesn't
> even build when targeting efi platform. The "loader/i386/efi/linux.c"
> file is missing in this branch.
>
>   
It was a mismerge. I've fixed it. Recently I was working on making this
branch mergeable into experimental and for this it needed some
restructure. I recommend trying r2130 of newreloc
> I will look for explanation  about this part of code, in the mailing
> list archives, however, as i said, the fix works fine for me.
Even if it does it needs a special support from kernel and doesn't allow
to handle e.g. FreeBSD so when it will be mergeable (probably next week)
your fix will be obsolete
>  The only
> error i have noticed, occurs on shutdown, and also occurs when i boot
> using elilo.
>
> Regards,
> Rémi Bernon
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>
>   


-- 
Regards
Vladimir 'φ-coder/phcoder' Serbinenko



[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 293 bytes --]

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: Grub UEFI memory allocation patch
  2010-04-03 20:59     ` Vladimir 'φ-coder/phcoder' Serbinenko
@ 2010-04-03 21:07       ` Bernon, Rémi
  0 siblings, 0 replies; 5+ messages in thread
From: Bernon, Rémi @ 2010-04-03 21:07 UTC (permalink / raw)
  To: The development of GNU GRUB

That's fine. I suspected that this required a specific kernel
configuration, as you have confirmed. I will try again the newreloc
branch.
Thanks.

Regards,
Rémi Bernon

2010/4/3 Vladimir 'φ-coder/phcoder' Serbinenko <phcoder@gmail.com>:
> Bernon wrote:
>> Actually, I've read the answer you made to someone who had the same
>> memory issue as I had, and I tried the newreloc branch, but it doesn't
>> even build when targeting efi platform. The "loader/i386/efi/linux.c"
>> file is missing in this branch.
>>
>>
> It was a mismerge. I've fixed it. Recently I was working on making this
> branch mergeable into experimental and for this it needed some
> restructure. I recommend trying r2130 of newreloc
>> I will look for explanation  about this part of code, in the mailing
>> list archives, however, as i said, the fix works fine for me.
> Even if it does it needs a special support from kernel and doesn't allow
> to handle e.g. FreeBSD so when it will be mergeable (probably next week)
> your fix will be obsolete
>>  The only
>> error i have noticed, occurs on shutdown, and also occurs when i boot
>> using elilo.
>>
>> Regards,
>> Rémi Bernon
>>
>>
>> _______________________________________________
>> Grub-devel mailing list
>> Grub-devel@gnu.org
>> http://lists.gnu.org/mailman/listinfo/grub-devel
>>
>>
>
>
> --
> Regards
> Vladimir 'φ-coder/phcoder' Serbinenko
>
>
>
> _______________________________________________
> Grub-devel mailing list
> Grub-devel@gnu.org
> http://lists.gnu.org/mailman/listinfo/grub-devel
>
>



^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2010-04-03 21:08 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-04-03 20:06 Grub UEFI memory allocation patch Bernon, Rémi
2010-04-03 20:22 ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-04-03 20:42   ` Bernon, Rémi
2010-04-03 20:59     ` Vladimir 'φ-coder/phcoder' Serbinenko
2010-04-03 21:07       ` Bernon, Rémi

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.