2020-07-29 20:47:36 +08:00
|
|
|
From 55f6c378c70e139d28f1d8b60bb0197946659fb1 Mon Sep 17 00:00:00 2001
|
2019-09-30 10:52:04 -04:00
|
|
|
From: Zhao Lei <zhaolei59@huawei.com>
|
|
|
|
|
Date: Mon, 25 Feb 2019 18:04:10 +0800
|
2020-07-29 20:47:36 +08:00
|
|
|
Subject: [PATCH 219/220] Workaround for EFI Bug (Plan3)
|
2019-09-30 10:52:04 -04:00
|
|
|
|
|
|
|
|
Signed-off-by: Zhao Lei <zhaolei59@huawei.com>
|
|
|
|
|
---
|
|
|
|
|
grub-core/disk/efi/efidisk.c | 108 ++++++++++++++++++++++++++++++++++++++++++-
|
|
|
|
|
1 file changed, 107 insertions(+), 1 deletion(-)
|
|
|
|
|
|
|
|
|
|
diff --git a/grub-core/disk/efi/efidisk.c b/grub-core/disk/efi/efidisk.c
|
2020-07-29 20:47:36 +08:00
|
|
|
index 54c227b..abb98aa 100644
|
2019-09-30 10:52:04 -04:00
|
|
|
--- a/grub-core/disk/efi/efidisk.c
|
|
|
|
|
+++ b/grub-core/disk/efi/efidisk.c
|
|
|
|
|
@@ -27,12 +27,19 @@
|
|
|
|
|
#include <grub/efi/efi.h>
|
|
|
|
|
#include <grub/efi/disk.h>
|
|
|
|
|
|
|
|
|
|
+typedef enum {
|
|
|
|
|
+ GRUB_EFI_BIOS_OVERFLOW_INIT,
|
|
|
|
|
+ GRUB_EFI_BIOS_OVERFLOW_EXIST,
|
|
|
|
|
+ GRUB_EFI_BIOS_OVERFLOW_NOEXIST
|
|
|
|
|
+} grub_efi_bios_overflow_t;
|
|
|
|
|
+
|
|
|
|
|
struct grub_efidisk_data
|
|
|
|
|
{
|
|
|
|
|
grub_efi_handle_t handle;
|
|
|
|
|
grub_efi_device_path_t *device_path;
|
|
|
|
|
grub_efi_device_path_t *last_device_path;
|
|
|
|
|
grub_efi_block_io_t *block_io;
|
|
|
|
|
+ grub_efi_bios_overflow_t bios_overflow;
|
|
|
|
|
struct grub_efidisk_data *next;
|
|
|
|
|
};
|
|
|
|
|
|
2020-07-29 20:47:36 +08:00
|
|
|
@@ -107,6 +114,7 @@ make_devices (void)
|
2019-09-30 10:52:04 -04:00
|
|
|
d->device_path = dp;
|
|
|
|
|
d->last_device_path = ldp;
|
|
|
|
|
d->block_io = bio;
|
|
|
|
|
+ d->bios_overflow = GRUB_EFI_BIOS_OVERFLOW_INIT;
|
|
|
|
|
d->next = devices;
|
|
|
|
|
devices = d;
|
|
|
|
|
}
|
2020-07-29 20:47:36 +08:00
|
|
|
@@ -540,8 +548,9 @@ grub_efidisk_close (struct grub_disk *disk __attribute__ ((unused)))
|
2019-09-30 10:52:04 -04:00
|
|
|
grub_dprintf ("efidisk", "closing %s\n", disk->name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+
|
|
|
|
|
static grub_efi_status_t
|
|
|
|
|
-grub_efidisk_readwrite (struct grub_disk *disk, grub_disk_addr_t sector,
|
|
|
|
|
+__grub_efidisk_readwrite (struct grub_disk *disk, grub_disk_addr_t sector,
|
|
|
|
|
grub_size_t size, char *buf, int wr)
|
|
|
|
|
{
|
|
|
|
|
struct grub_efidisk_data *d;
|
2020-07-29 20:47:36 +08:00
|
|
|
@@ -584,6 +593,103 @@ grub_efidisk_readwrite (struct grub_disk *disk, grub_disk_addr_t sector,
|
2019-09-30 10:52:04 -04:00
|
|
|
return status;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
+static void grub_efidisk_set_overflow(struct grub_disk *disk)
|
|
|
|
|
+{
|
|
|
|
|
+ struct grub_efidisk_data *d = disk->data;
|
|
|
|
|
+
|
|
|
|
|
+ char *buf;
|
|
|
|
|
+ int read_len;
|
|
|
|
|
+ int buf_len;
|
|
|
|
|
+
|
|
|
|
|
+ static char magic_list[] = {0x55, 0xaa};
|
|
|
|
|
+ unsigned int magic_index;
|
|
|
|
|
+
|
|
|
|
|
+ if (d->bios_overflow != GRUB_EFI_BIOS_OVERFLOW_INIT)
|
|
|
|
|
+ return;
|
|
|
|
|
+
|
|
|
|
|
+ if (d->block_io->media->removable_media) {
|
|
|
|
|
+ d->bios_overflow = GRUB_EFI_BIOS_OVERFLOW_NOEXIST;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ read_len = (1 << disk->log_sector_size);
|
|
|
|
|
+
|
|
|
|
|
+ /* read_len + 9 is enough, we use more */
|
|
|
|
|
+ buf_len = (read_len + 8) * 2;
|
|
|
|
|
+
|
|
|
|
|
+ buf = grub_malloc(buf_len);
|
|
|
|
|
+ if (!buf) {
|
|
|
|
|
+ grub_printf("grub_efidisk_set_overflow: malloc failed, ignore operation %s\n", disk->name);
|
|
|
|
|
+ d->bios_overflow = GRUB_EFI_BIOS_OVERFLOW_EXIST;
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (magic_index = 0; magic_index < sizeof(magic_list)/sizeof(magic_list[0]); magic_index++) {
|
|
|
|
|
+ int buf_index;
|
|
|
|
|
+
|
|
|
|
|
+ grub_memset(buf + read_len, magic_list[magic_index], buf_len - read_len);
|
|
|
|
|
+
|
|
|
|
|
+ /*
|
|
|
|
|
+ * If disk can not read, we can not determine overflow state now,
|
|
|
|
|
+ * just leave GRUB_EFI_BIOS_OVERFLOW_INIT state and re-check on
|
|
|
|
|
+ * next operation of this disk.
|
|
|
|
|
+ */
|
|
|
|
|
+ if (GRUB_EFI_SUCCESS != __grub_efidisk_readwrite(disk, 0, 1, buf, 0)) {
|
|
|
|
|
+ d->bios_overflow = GRUB_EFI_BIOS_OVERFLOW_INIT;
|
|
|
|
|
+ goto out;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (buf_index = read_len; buf_index < buf_len; buf_index++) {
|
|
|
|
|
+ if (buf[buf_index] != magic_list[magic_index]) {
|
|
|
|
|
+ d->bios_overflow = GRUB_EFI_BIOS_OVERFLOW_EXIST;
|
|
|
|
|
+ goto out;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ d->bios_overflow = GRUB_EFI_BIOS_OVERFLOW_NOEXIST;
|
|
|
|
|
+
|
|
|
|
|
+out:
|
|
|
|
|
+ grub_free(buf);
|
|
|
|
|
+ return;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static int grub_efidisk_check_overflow(struct grub_disk *disk)
|
|
|
|
|
+{
|
|
|
|
|
+ struct grub_efidisk_data *d = disk->data;
|
|
|
|
|
+ int ret;
|
|
|
|
|
+
|
|
|
|
|
+ grub_efidisk_set_overflow(disk);
|
|
|
|
|
+
|
|
|
|
|
+ switch (d->bios_overflow) {
|
|
|
|
|
+ case GRUB_EFI_BIOS_OVERFLOW_INIT:
|
|
|
|
|
+ ret = 0;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case GRUB_EFI_BIOS_OVERFLOW_NOEXIST:
|
|
|
|
|
+ ret = 0;
|
|
|
|
|
+ break;
|
|
|
|
|
+ case GRUB_EFI_BIOS_OVERFLOW_EXIST:
|
|
|
|
|
+ ret = 1;
|
|
|
|
|
+ break;
|
|
|
|
|
+ default:
|
|
|
|
|
+ grub_printf("grub_efidisk_check_overflow: internal error in bios_overflow value(%d), ignore operation %s\n", d->bios_overflow, disk->name);
|
|
|
|
|
+ ret = 1;
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return ret;
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static grub_efi_status_t
|
|
|
|
|
+grub_efidisk_readwrite (struct grub_disk *disk, grub_disk_addr_t sector,
|
|
|
|
|
+ grub_size_t size, char *buf, int wr)
|
|
|
|
|
+{
|
|
|
|
|
+ if (grub_efidisk_check_overflow(disk))
|
|
|
|
|
+ return GRUB_ERR_UNKNOWN_DEVICE;
|
|
|
|
|
+
|
|
|
|
|
+ return __grub_efidisk_readwrite(disk, sector, size, buf, wr);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
static grub_err_t
|
|
|
|
|
grub_efidisk_read (struct grub_disk *disk, grub_disk_addr_t sector,
|
|
|
|
|
grub_size_t size, char *buf)
|
2020-07-29 20:47:36 +08:00
|
|
|
--
|
|
|
|
|
1.8.3.1
|
|
|
|
|
|