A patch to enhance biosdisk initrd loading speed for grub2

2012-08-01 Thread Wang Weber
Hi,

I am very interested in GRUB2. Recently I found that the linux initrd
loading speed (i386-pc) is quite poor compared with GRUB1. I compared
grub-1.98 with grub0.97, it is almost 7 times worse.

After checking the code of them, the reason is GRUB1 has a simple track
buffer for biosdisk, every time it tries to read a whole track from disk if
possible. For GRUB2, there is no such buffer, so it will read less than a
track every time. This greatly affects the performance of disk reading.

I see that grub2.00 extends the generic disk cache from 8 sectors
(grub1.98) to 64 sectors. This helps to increase the performance, however
it is still worse than GRUB1.

So I ported the track buffer from GRUB1 to grub1.98 and grub2.00, my test
with a USB stick shows that loading a 106M initrd (it is true, we use big
initrd), grub2.00 costs about 15 seconds, with this patch grub2.00 costs
about 11 seconds.

The performance increment is bigger on grub1.98 than on grub2.00, because
grub2.00 has a larger cache. However, I believe it is reasonable to add
additional buffer layer for specific architecture/platform. Specifically
for i386-pc, there is a legacy 63 sectors per track limitation, the
additional buffer greatly enhance disk reading performance.

I am very glad if you are interested in this patch, and I am glad to share
it with the GRUB community. Indeed, GRUB2 is a wonderful tool, you did a
great job!

Thanks,
-Wenbo(Weber)
___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel


"couldn't terminate EFI services" error caused by buggy BIOS and the workaround

2014-10-23 Thread Wang Weber
Hi,

I am using grub-1.99 on a x86 platform. The BIOS is originated from AMI and
customized a little by our company. When booting up Linux 3.X, I can see
the error message "couldn't terminate EFI services".

According to the colaberate debug by both SW/FW side, it is found that
before grub calls EFI API exit_boot_services(), the internal finish_key is
changed. See the following code and notes for details.


Code from GRUB-1.99
=

  if (grub_efi_get_memory_map (&finish_mmap_size, finish_mmap_buf,
&finish_key,
   &finish_desc_size, &finish_desc_version) < 0)
return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map");
  if (outbuf && *outbuf_size < finish_mmap_size)
return grub_error (GRUB_ERR_IO, "memory map buffer is too small");
  finish_mmap_buf = grub_malloc (finish_mmap_size);
  if (!finish_mmap_buf)
return grub_errno;
  if (grub_efi_get_memory_map (&finish_mmap_size, finish_mmap_buf,
&finish_key,
   &finish_desc_size, &finish_desc_version) <=
0)  <== see note 1
return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map");
  b = grub_efi_system_table->boot_services;
  status = efi_call_2 (b->exit_boot_services,
grub_efi_image_handle,<== see note 2
   finish_key);
  if (status != GRUB_EFI_SUCCESS)
return grub_error (GRUB_ERR_IO, "couldn't terminate EFI services");

Note 1:
BIOS returns the memory map and the finish_key = X

Note 2:
BIOS changes the memory map and the internal finish_key becomes X+1, so the
input finish_key does not match the interna key, the API call fails.

==


Since the BIOS core is from AMI we cannot correct the FW behavior so we did
a small modification to the GRUB (see below). We retry the exit boot
service API and this solves the problem.
Please consider if this modification is reasonable for future grub releases.

PS. I also checked the latest grub-2.00 code however this part of code is
the same as grub-1.99, so grub upgrade cannot help.


do {
  if (grub_efi_get_memory_map (&finish_mmap_size, finish_mmap_buf,
&finish_key,
   &finish_desc_size, &finish_desc_version) < 0)
return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map");
  if (outbuf && *outbuf_size < finish_mmap_size)
return grub_error (GRUB_ERR_IO, "memory map buffer is too small");
  finish_mmap_buf = grub_malloc (finish_mmap_size);
  if (!finish_mmap_buf)
return grub_errno;
  if (grub_efi_get_memory_map (&finish_mmap_size, finish_mmap_buf,
&finish_key,
   &finish_desc_size, &finish_desc_version) <=
0)
return grub_error (GRUB_ERR_IO, "couldn't retrieve memory map");
  b = grub_efi_system_table->boot_services;
  status = efi_call_2 (b->exit_boot_services, grub_efi_image_handle,
   finish_key);

  if (status != GRUB_EFI_SUCCESS) {
grub_free(finish_mmap_buf);
  }

} while (status != GRUB_EFI_SUCCESS && retry++ < 2);  <== retry calling
exit boot service

if (status != GRUB_EFI_SUCCESS)
  return grub_error (GRUB_ERR_IO, "couldn't terminate EFI services");



Thanks,
- Weber Wang
___
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel