* [PATCH vRESEND] Improve cbfs detection
@ 2024-05-17 7:52 Vladimir Serbinenko
0 siblings, 0 replies; only message in thread
From: Vladimir Serbinenko @ 2024-05-17 7:52 UTC (permalink / raw)
To: grub-devel; +Cc: Vladimir Serbinenko
With FMAP and non-continuous SPI old way of reading CBFS pointer
is no longer reliable. Hence use new lbio tags to detect the correct
cbfs layout
Signed-off-by: Vladimir Serbinenko <phcoder@gmail.com>
---
grub-core/fs/cbfs.c | 131 ++++++++++++++++++++++++++++-------
include/grub/coreboot/lbio.h | 25 ++++++-
2 files changed, 131 insertions(+), 25 deletions(-)
diff --git a/grub-core/fs/cbfs.c b/grub-core/fs/cbfs.c
index 8ab7106af..7234da7ee 100644
--- a/grub-core/fs/cbfs.c
+++ b/grub-core/fs/cbfs.c
@@ -26,6 +26,7 @@
#include <grub/dl.h>
#include <grub/i18n.h>
#include <grub/cbfs_core.h>
+#include <grub/coreboot/lbio.h>
GRUB_MOD_LICENSE ("GPLv3+");
@@ -273,7 +274,8 @@ grub_cbfs_close (grub_file_t file)
#if (defined (__i386__) || defined (__x86_64__)) && !defined (GRUB_UTIL) \
&& !defined (GRUB_MACHINE_EMU) && !defined (GRUB_MACHINE_XEN)
-static char *cbfsdisk_addr;
+static struct grub_linuxbios_flash_mmap_window *cbfsdisk_map;
+static grub_uint32_t cbfsdisk_map_size;
static grub_off_t cbfsdisk_size = 0;
static int
@@ -289,10 +291,10 @@ grub_cbfsdisk_iterate (grub_disk_dev_iterate_hook_t hook, void *hook_data,
static grub_err_t
grub_cbfsdisk_open (const char *name, grub_disk_t disk)
{
- if (grub_strcmp (name, "cbfsdisk"))
+ if (grub_strcmp (name, "cbfsdisk") && cbfsdisk_size > 0)
return grub_error (GRUB_ERR_UNKNOWN_DEVICE, "not a cbfsdisk");
- disk->total_sectors = cbfsdisk_size / GRUB_DISK_SECTOR_SIZE;
+ disk->total_sectors = cbfsdisk_size >> GRUB_DISK_SECTOR_BITS;
disk->max_agglomerate = GRUB_DISK_MAX_MAX_AGGLOMERATE;
disk->id = 0;
@@ -307,10 +309,40 @@ grub_cbfsdisk_close (grub_disk_t disk __attribute((unused)))
static grub_err_t
grub_cbfsdisk_read (grub_disk_t disk __attribute((unused)),
grub_disk_addr_t sector,
- grub_size_t size, char *buf)
+ grub_size_t size_sectors, char *buf)
{
- grub_memcpy (buf, cbfsdisk_addr + (sector << GRUB_DISK_SECTOR_BITS),
- size << GRUB_DISK_SECTOR_BITS);
+ grub_off_t off = sector << GRUB_DISK_SECTOR_BITS;
+ grub_size_t size = size_sectors << GRUB_DISK_SECTOR_BITS;
+ while (size > 0)
+ {
+ unsigned int i;
+ grub_size_t to_read;
+ grub_off_t reg_offset;
+ for (i = 0; i < cbfsdisk_map_size; i++)
+ if (cbfsdisk_map[i].flash_base <= off && off < cbfsdisk_map[i].flash_base + cbfsdisk_map[i].size)
+ break;
+ if (i == cbfsdisk_map_size)
+ {
+ grub_off_t next = -1;
+ for (i = 0; i < cbfsdisk_map_size; i++)
+ if (cbfsdisk_map[i].flash_base > off && next > cbfsdisk_map[i].flash_base)
+ next = cbfsdisk_map[i].flash_base;
+ to_read = grub_min (size, next - off);
+ grub_memset (buf, 0xff, to_read);
+ grub_dprintf("cbfs", "Filling 0x%x bytes\n", (unsigned) to_read);
+ buf += to_read;
+ size -= to_read;
+ off += to_read;
+ continue;
+ }
+ reg_offset = off - cbfsdisk_map[i].flash_base;
+ to_read = grub_min (size, cbfsdisk_map[i].size - reg_offset);
+ grub_memcpy (buf, (void *) (grub_addr_t) (cbfsdisk_map[i].host_base + reg_offset), to_read);
+ grub_dprintf("cbfs", "Copying %p,0x%x bytes\n", (void *) (grub_addr_t) (cbfsdisk_map[i].host_base + reg_offset), (unsigned) to_read);
+ buf += to_read;
+ size -= to_read;
+ off += to_read;
+ }
return 0;
}
@@ -336,29 +368,80 @@ static struct grub_disk_dev grub_cbfsdisk_dev =
.next = 0
};
+struct cbtable_iter_ctxt {
+ int has_coreboot;
+ struct grub_linuxbios_table_spi_flash *spi;
+ struct grub_linuxbios_table_boot_media *boot_media;
+};
+
+static int cbtable_iter (grub_linuxbios_table_item_t item,
+ void *ctxt_in)
+{
+ struct cbtable_iter_ctxt *ctxt = ctxt_in;
+
+ ctxt->has_coreboot = 1;
+
+ if (item->tag == GRUB_LINUXBIOS_MEMBER_SPI_FLASH)
+ ctxt->spi = (void *) (item + 1);
+
+ if (item->tag == GRUB_LINUXBIOS_MEMBER_BOOT_MEDIA)
+ ctxt->boot_media = (void *) (item + 1);
+
+ return 0;
+}
+
static void
init_cbfsdisk (void)
{
- grub_uint32_t ptr;
- struct cbfs_header *head;
-
- ptr = *((grub_uint32_t *) grub_absolute_pointer (0xfffffffc));
- head = (struct cbfs_header *) (grub_addr_t) ptr;
- grub_dprintf ("cbfs", "head=%p\n", head);
-
- /* coreboot current supports only ROMs <= 16 MiB. Bigger ROMs will
- have problems as RCBA is 18 MiB below end of 32-bit typically,
- so either memory map would have to be rearranged or we'd need to support
- reading ROMs through controller directly.
- */
- if (ptr < 0xff000000
- || 0xffffffff - ptr < (grub_uint32_t) sizeof (*head) + 0xf
- || !validate_head (head))
+ struct cbtable_iter_ctxt ctxt = {
+ 0, 0, 0
+ };
+
+ grub_linuxbios_table_iterate (cbtable_iter, &ctxt);
+
+ if (!ctxt.has_coreboot)
return;
- cbfsdisk_size = ALIGN_UP (grub_be_to_cpu32 (head->romsize),
- GRUB_DISK_SECTOR_SIZE);
- cbfsdisk_addr = (void *) (grub_addr_t) (0x100000000ULL - cbfsdisk_size);
+ if (ctxt.spi)
+ {
+ cbfsdisk_map = ctxt.spi->mmap_table;
+ cbfsdisk_map_size = ctxt.spi->mmap_count;
+ cbfsdisk_size = ctxt.spi->flash_size;
+ }
+ else
+ {
+ if (ctxt.boot_media)
+ cbfsdisk_size = ALIGN_UP (grub_be_to_cpu32 (ctxt.boot_media->boot_media_size),
+ GRUB_DISK_SECTOR_SIZE);
+ else
+ {
+ grub_uint32_t ptr;
+ struct cbfs_header *head;
+
+ ptr = *((grub_uint32_t *) grub_absolute_pointer (0xfffffffc));
+ head = (struct cbfs_header *) (grub_addr_t) ptr;
+ grub_dprintf ("cbfs", "head=%p\n", head);
+
+ /* coreboot current supports only ROMs <= 16 MiB. Bigger ROMs will
+ have problems as RCBA is 18 MiB below end of 32-bit typically,
+ so either memory map would have to be rearranged or we'd need to support
+ reading ROMs through controller directly.
+ */
+ if (ptr < 0xff000000
+ || 0xffffffff - ptr < (grub_uint32_t) sizeof (*head) + 0xf
+ || !validate_head (head))
+ return;
+
+ cbfsdisk_size = ALIGN_UP (grub_be_to_cpu32 (head->romsize),
+ GRUB_DISK_SECTOR_SIZE);
+ }
+ cbfsdisk_map_size = 1;
+ static struct grub_linuxbios_flash_mmap_window singleton;
+ singleton.flash_base = 0;
+ singleton.host_base = 0x100000000ULL - cbfsdisk_size;
+ singleton.size = cbfsdisk_size;
+ cbfsdisk_map = &singleton;
+ }
grub_disk_dev_register (&grub_cbfsdisk_dev);
}
diff --git a/include/grub/coreboot/lbio.h b/include/grub/coreboot/lbio.h
index 5076d36c7..f8641f463 100644
--- a/include/grub/coreboot/lbio.h
+++ b/include/grub/coreboot/lbio.h
@@ -71,7 +71,9 @@ enum
GRUB_LINUXBIOS_MEMBER_LINK = 0x11,
GRUB_LINUXBIOS_MEMBER_FRAMEBUFFER = 0x12,
GRUB_LINUXBIOS_MEMBER_TIMESTAMPS = 0x16,
- GRUB_LINUXBIOS_MEMBER_CBMEMC = 0x17
+ GRUB_LINUXBIOS_MEMBER_CBMEMC = 0x17,
+ GRUB_LINUXBIOS_MEMBER_SPI_FLASH = 0x29,
+ GRUB_LINUXBIOS_MEMBER_BOOT_MEDIA = 0x30,
};
struct grub_linuxbios_table_framebuffer {
@@ -100,6 +102,27 @@ struct grub_linuxbios_mem_region
} GRUB_PACKED;
typedef struct grub_linuxbios_mem_region *mem_region_t;
+struct grub_linuxbios_flash_mmap_window {
+ grub_uint32_t flash_base;
+ grub_uint32_t host_base;
+ grub_uint32_t size;
+} GRUB_PACKED;
+
+struct grub_linuxbios_table_spi_flash {
+ grub_uint32_t flash_size;
+ grub_uint32_t sector_size;
+ grub_uint32_t erase_cmd;
+ grub_uint32_t mmap_count;
+ struct grub_linuxbios_flash_mmap_window mmap_table[0];
+} GRUB_PACKED;
+
+struct grub_linuxbios_table_boot_media {
+ grub_uint64_t fmap_offset;
+ grub_uint64_t cbfs_offset;
+ grub_uint64_t cbfs_size;
+ grub_uint64_t boot_media_size;
+} GRUB_PACKED;
+
grub_err_t
EXPORT_FUNC(grub_linuxbios_table_iterate) (int (*hook) (grub_linuxbios_table_item_t,
void *),
--
2.39.2
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
https://lists.gnu.org/mailman/listinfo/grub-devel
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2024-05-17 7:52 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-05-17 7:52 [PATCH vRESEND] Improve cbfs detection Vladimir Serbinenko
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.