From 088b4d85c7a939339611846589a8bea7369bfa41 Mon Sep 17 00:00:00 2001 From: mengyingkun Date: Mon, 13 Feb 2023 16:25:08 +0800 Subject: [PATCH] loongarch: Add support for v4.0 interface Signed-off-by: mengyingkun (cherry picked from commit 048b61123f321de2f517f3a0aebc6c65f38f66f6) --- grub.patches | 1 + grub2.spec | 8 +- ...garch-Add-support-for-v4.0-interface.patch | 434 ++++++++++++++++++ 3 files changed, 442 insertions(+), 1 deletion(-) create mode 100644 loongarch-Add-support-for-v4.0-interface.patch diff --git a/grub.patches b/grub.patches index 6fa0591..c08de25 100644 --- a/grub.patches +++ b/grub.patches @@ -306,4 +306,5 @@ Patch0302: backport-fs-squash4-Fix-memory-leaks-in-grub_squash_iterate_d.patch Patch0303: backport-fs-iso9660-Fix-memory-leaks-in-grub_iso9660_susp_ite.patch %ifarch loongarch64 Patch0304: loongarch-Add-EFI-frame-buffer-support.patch +Patch0305: loongarch-Add-support-for-v4.0-interface.patch %endif diff --git a/grub2.spec b/grub2.spec index 556b664..2974f3b 100644 --- a/grub2.spec +++ b/grub2.spec @@ -14,7 +14,7 @@ Name: grub2 Epoch: 1 Version: 2.06 -Release: 22 +Release: 23 Summary: Bootloader with support for Linux, Multiboot and more License: GPLv3+ URL: http://www.gnu.org/software/grub/ @@ -439,6 +439,12 @@ fi %{_datadir}/man/man* %changelog +* Mon Feb 13 2023 mengyingkun - 1:2.06-23 +- Type:bugfix +- CVE:NA +- SUG:NA +- DESC:loongarch: Add support for v4.0 interface + * Wed Feb 8 2023 mengyingkun - 1:2.06-22 - Type:bugfix - CVE:NA diff --git a/loongarch-Add-support-for-v4.0-interface.patch b/loongarch-Add-support-for-v4.0-interface.patch new file mode 100644 index 0000000..8629604 --- /dev/null +++ b/loongarch-Add-support-for-v4.0-interface.patch @@ -0,0 +1,434 @@ +From d984a64ff93443630fde3211e1a8ec42d92a6b56 Mon Sep 17 00:00:00 2001 +From: mengyingkun +Date: Mon, 13 Feb 2023 14:40:16 +0800 +Subject: [PATCH] loongarch: Add support for v4.0 interface + +This patch adds support for parameter passing converntion +between bootloader and kernel, defined in the document +"loongson devsys firmware kernel interface specification v4.0" + +Signed-off-by: yangqiming +Signed-off-by: mengyingkun +--- + grub-core/lib/loongarch64/relocator.c | 2 +- + grub-core/loader/loongarch64/linux-elf.c | 177 ++++++++++++++++++++--- + grub-core/loader/loongarch64/linux.c | 49 ++----- + include/grub/loongarch64/linux.h | 20 +++ + 4 files changed, 190 insertions(+), 58 deletions(-) + +diff --git a/grub-core/lib/loongarch64/relocator.c b/grub-core/lib/loongarch64/relocator.c +index faa4553..587fc58 100644 +--- a/grub-core/lib/loongarch64/relocator.c ++++ b/grub-core/lib/loongarch64/relocator.c +@@ -122,7 +122,7 @@ grub_relocator64_boot (struct grub_relocator *rel, + unsigned i; + grub_addr_t vtarget; + +- err = grub_relocator_alloc_chunk_align (rel, &ch, 0, ++ err = grub_relocator_alloc_chunk_align (rel, &ch, 0x3000000, + (0xffffffff - stateset_size) + + 1, stateset_size, + grub_relocator_align, +diff --git a/grub-core/loader/loongarch64/linux-elf.c b/grub-core/loader/loongarch64/linux-elf.c +index 852e8f4..15f9984 100644 +--- a/grub-core/loader/loongarch64/linux-elf.c ++++ b/grub-core/loader/loongarch64/linux-elf.c +@@ -25,11 +25,14 @@ + #include + #include + ++#define GRUB_EFI_MMAP_NR_SLACK_SLOTS 8 ++ + #define GRUB_ADDRESS_TYPE_SYSRAM 1 + #define GRUB_ADDRESS_TYPE_RESERVED 2 + #define GRUB_ADDRESS_TYPE_ACPI 3 + #define GRUB_ADDRESS_TYPE_NVS 4 + #define GRUB_ADDRESS_TYPE_PMEM 5 ++ + #define GRUB_EFI_LOONGSON_BPI_TABLE_GUID \ + { 0x4660f721, 0x2ec5, 0x416a, \ + { 0x89, 0x9a, 0x43, 0x18, 0x02, 0x50, 0xa0, 0xc9 } \ +@@ -45,6 +48,16 @@ + { 0x9a, 0x46, 0x00, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \ + } + ++#define GRUB_EFI_LARCH_BOOT_MEMMAP_GUID \ ++ { 0x800f683f, 0xd08b, 0x423a, \ ++ { 0xa2, 0x93, 0x96, 0x5c, 0x3c, 0x6f, 0xe2, 0xb4 } \ ++ } ++ ++#define GRUB_EFI_LARCH_INITRD_MEDIA_GUID \ ++ { 0x5568e427, 0x68fc, 0x4f3d, \ ++ { 0xac, 0x74, 0xca, 0x55, 0x52, 0x31, 0xcc, 0x68 } \ ++ } ++ + static struct grub_relocator *relocator; + static grub_efi_guid_t screen_info_guid = GRUB_EFI_LARCH_SCREEN_INFO_GUID; + +@@ -271,6 +284,135 @@ free_screen_info: + return NULL; + } + ++static grub_err_t ++allocate_memmap_and_exit_boot (struct linux_loongarch64_kernel_params *kernel_params) ++{ ++ grub_err_t err; ++ grub_efi_status_t status; ++ grub_efi_uintn_t mmap_size, desc_size, size; ++ grub_efi_uint32_t desc_version; ++ grub_efi_memory_descriptor_t *mmap_buf; ++ grub_efi_boot_services_t *b; ++ struct efi_boot_memmap *m, tmp; ++ struct efi_initrd *tbl = NULL; ++ grub_efi_guid_t boot_memmap_guid = GRUB_EFI_LARCH_BOOT_MEMMAP_GUID; ++ grub_efi_guid_t initrd_media_guid = GRUB_EFI_LARCH_INITRD_MEDIA_GUID; ++ ++ setup_screen_info(); ++ ++ b = grub_efi_system_table->boot_services; ++ ++ grub_dprintf ("loongson", "ramdisk_addr:0x%"PRIxGRUB_UINT64_T", \ ++ size:0x%"PRIxGRUB_UINT64_T"\n", ++ kernel_params->ramdisk_addr, ++ kernel_params->ramdisk_size); ++#if 0 ++ char string[64]; ++ ++ /* Set initrd info to cmdline*/ ++ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size) ++ { ++ grub_printf ( "Initrd @ %p-%p\n", ++ (void *) kernel_params->ramdisk_addr, ++ (void *) (kernel_params->ramdisk_addr + kernel_params->ramdisk_size)); ++ /* initrd */ ++ grub_snprintf (string, ++ sizeof (GRUB_INITRD_STRING), ++ "initrd=0x%lx,0x%lx", ++ ((grub_uint64_t) kernel_params->ramdisk_addr & 0xffffffff), ++ (grub_uint64_t) kernel_params->ramdisk_size); ++ *(char*) ((grub_addr_t) kernel_params->linux_args + kernel_params->ramdisk_args_len - 2) = ' '; ++ grub_memcpy ((char*) ((grub_addr_t) kernel_params->linux_args + kernel_params->ramdisk_args_len - 1), ++ string, sizeof (GRUB_INITRD_STRING)); ++ } ++#else ++ /* Set initrd info to system table*/ ++ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size) ++ { ++ tbl = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (sizeof(struct efi_initrd))); ++ if (!tbl) ++ return grub_error (GRUB_ERR_IO, "cannot allocate tbl memory"); ++ tbl->base = kernel_params->ramdisk_addr; ++ tbl->size = kernel_params->ramdisk_size; ++ ++ status = b->install_configuration_table (&initrd_media_guid, tbl); ++ if (status != GRUB_EFI_SUCCESS) { ++ grub_error (GRUB_ERR_IO, "failed to install initrd media"); ++ goto free_tbl; ++ } ++ } ++#endif ++ ++ tmp.map_size = 0; ++ status = grub_efi_get_memory_map (&tmp.map_size, NULL, &tmp.map_key, ++ &tmp.desc_size, &tmp.desc_ver); ++ if (status != 0) { ++ grub_error (GRUB_ERR_IO, "cannot get memory map"); ++ goto uninstall_initrd_table; ++ } ++ size = tmp.map_size + tmp.desc_size * GRUB_EFI_MMAP_NR_SLACK_SLOTS; ++ m = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (sizeof(*m) + size)); ++ if (!m) { ++ grub_error (GRUB_ERR_IO, "cannot allocate m memory"); ++ goto uninstall_initrd_table; ++ } ++ ++ status = b->install_configuration_table (&boot_memmap_guid, m); ++ if (status != GRUB_EFI_SUCCESS) { ++ grub_error (GRUB_ERR_IO, "failed to install boot memmap"); ++ goto free_m; ++ } ++ ++ m->buff_size = m->map_size = size; ++ if (grub_efi_get_memory_map (&m->map_size, m->map, ++ &m->map_key, &m->desc_size, ++ &m->desc_ver) <= 0) ++ { ++ grub_error (GRUB_ERR_IO, "cannot get EFI memory map"); ++ goto uninstall_mem_table; ++ } ++ ++ mmap_size = grub_efi_find_mmap_size (); ++ if (! mmap_size) ++ goto uninstall_mem_table; ++ ++ mmap_buf = grub_efi_allocate_any_pages (GRUB_EFI_BYTES_TO_PAGES (mmap_size)); ++ err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, NULL, ++ &desc_size, &desc_version); ++ if (err) { ++ grub_error (GRUB_ERR_IO, "failed to finish boot services"); ++ goto free_map; ++ } ++ ++ return 0; ++ ++free_map: ++ if (mmap_buf) ++ grub_efi_free_pages ((grub_addr_t) mmap_buf, ++ GRUB_EFI_BYTES_TO_PAGES (mmap_size)); ++ ++uninstall_mem_table: ++ b->install_configuration_table (&boot_memmap_guid, NULL); ++ ++free_m: ++ if (m) ++ grub_efi_free_pages ((grub_addr_t) m, ++ GRUB_EFI_BYTES_TO_PAGES (sizeof(*m) + size)); ++ ++uninstall_initrd_table: ++ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size) ++ b->install_configuration_table (&initrd_media_guid, NULL); ++ ++free_tbl: ++ if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size) { ++ if (tbl) ++ grub_efi_free_pages ((grub_addr_t) tbl, ++ GRUB_EFI_BYTES_TO_PAGES (sizeof(struct efi_initrd))); ++ } ++ ++ return grub_error(GRUB_ERR_BAD_OS, "failed to V40 boot"); ++} ++ + static grub_err_t + allocate_fdt_and_exit_boot (struct linux_loongarch64_kernel_params *kernel_params) + { +@@ -400,12 +542,11 @@ grub_linux_loongarch_elf_make_argv (struct linux_loongarch64_kernel_params *kern + } + + if (kernel_params->ramdisk_addr && kernel_params->ramdisk_size) +- { +- size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4) \ +- + ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4) \ +- + ALIGN_UP (sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), +- 4); +- } ++ { ++ size += ALIGN_UP (sizeof (GRUB_RD_START_STRING), 4) ++ + ALIGN_UP (sizeof (GRUB_RD_SIZE_STRING), 4) ++ + ALIGN_UP (sizeof (GRUB_INITRD_STRING), 4); ++ } + size = ALIGN_UP (size, 8); + + /* alloc memory */ +@@ -427,33 +568,33 @@ grub_linux_loongarch_elf_make_argv (struct linux_loongarch64_kernel_params *kern + { + /* rd_start */ + grub_snprintf (linux_args, +- sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), ++ sizeof (GRUB_RD_START_STRING), + "rd_start=0x%lx", + (grub_uint64_t) kernel_params->ramdisk_addr); + *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; + linux_argv++; +- linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); ++ linux_args += ALIGN_UP (sizeof (GRUB_RD_START_STRING), 4); + kernel_params->linux_argc++; + + /* rd_size */ + grub_snprintf (linux_args, +- sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), ++ sizeof (GRUB_RD_SIZE_STRING), + "rd_size=0x%lx", + (grub_uint64_t) kernel_params->ramdisk_size); + *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; + linux_argv++; +- linux_args += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); ++ linux_args += ALIGN_UP (sizeof (GRUB_RD_SIZE_STRING), 4); + kernel_params->linux_argc++; + + /* initrd */ + grub_snprintf (linux_args, +- sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), ++ sizeof (GRUB_INITRD_STRING), + "initrd=0x%lx,0x%lx", + ((grub_uint64_t) kernel_params->ramdisk_addr & 0xffffffff), + (grub_uint64_t) kernel_params->ramdisk_size); + *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; + linux_argv++; +- linux_args += ALIGN_UP (sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), 4); ++ linux_args += ALIGN_UP (sizeof (GRUB_INITRD_STRING), 4); + kernel_params->linux_argc++; + } + +@@ -472,8 +613,6 @@ grub_linux_loongarch_elf_linux_boot_image (struct linux_loongarch64_kernel_param + struct grub_relocator64_state state; + grub_err_t err; + +- setup_screen_info (); +- + /* linux kernel type is ELF */ + grub_memset (&state, 0, sizeof (state)); + +@@ -481,14 +620,14 @@ grub_linux_loongarch_elf_linux_boot_image (struct linux_loongarch64_kernel_param + state.gpr[1] = kernel_params->kernel_addr; /* ra */ + if (grub_linux_loongarch_elf_get_boot_params (&boot_params) == 0) + { +- grub_printf("not find param, is fdt boot\n"); +- if (allocate_fdt_and_exit_boot (kernel_params) != GRUB_ERR_NONE) ++ grub_dprintf("loongson", "V4.0 boot\n"); ++ if (allocate_memmap_and_exit_boot (kernel_params) != GRUB_ERR_NONE) + return grub_errno; + state.gpr[4] = 1 << FLAGS_EFI_SUPPORT_BIT; /* a0 = flag */ +- state.gpr[5] = (grub_uint64_t)kernel_params->fdt; /* a1 = fdt */ +- state.gpr[6] = 0; /* a2 = flag */ ++ state.gpr[5] = (grub_uint64_t)kernel_params->linux_args; /* a1 = cmdline */ ++ state.gpr[6] = (grub_uint64_t)grub_efi_system_table; /* a2 = system_table */ + } else { +- grub_printf("find param, is bpi boot\n"); ++ grub_dprintf("loongson", "BPI boot\n"); + grub_linux_loongarch_elf_make_argv (kernel_params); + state.gpr[4] = kernel_params->linux_argc; /* a0 = argc */ + state.gpr[5] = kernel_params->linux_argv; /* a1 = args */ +diff --git a/grub-core/loader/loongarch64/linux.c b/grub-core/loader/loongarch64/linux.c +index 4c02194..03b7940 100644 +--- a/grub-core/loader/loongarch64/linux.c ++++ b/grub-core/loader/loongarch64/linux.c +@@ -230,7 +230,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "kernel @ %p\n", (void*) kernel_params.kernel_addr); + } + +- cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE); ++ cmdline_size = grub_loader_cmdline_size (argc, argv) + sizeof (LINUX_IMAGE) ++ + sizeof (GRUB_INITRD_STRING); ++ kernel_params.ramdisk_args_len = grub_loader_cmdline_size (argc, argv) ++ + sizeof (LINUX_IMAGE); + kernel_params.linux_argc = argc; + kernel_params.linux_args = grub_malloc (cmdline_size); + if (!kernel_params.linux_args) +@@ -250,7 +253,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + { + err = grub_create_loader_cmdline (argc, argv, + (char*) ((grub_addr_t) kernel_params.linux_args + sizeof (LINUX_IMAGE) - 1), +- cmdline_size, ++ kernel_params.ramdisk_args_len, + GRUB_VERIFY_KERNEL_CMDLINE); + if (err) + goto fail; +@@ -299,26 +302,6 @@ fail: + return grub_errno; + } + +-/* +- * This function returns a pointer to a legally allocated initrd buffer, +- * or NULL if unsuccessful +- */ +-static void * +-allocate_initrd_mem (int initrd_pages) +-{ +- grub_addr_t max_addr; +- +- if (grub_efi_get_ram_base (&max_addr) != GRUB_ERR_NONE) +- return NULL; +- +- max_addr += INITRD_MAX_ADDRESS_OFFSET - 1; +- +- return grub_efi_allocate_pages_real (max_addr, initrd_pages, +- GRUB_EFI_ALLOCATE_MAX_ADDRESS, +- GRUB_EFI_LOADER_DATA); +-} +- +- + static grub_err_t + grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +@@ -326,6 +309,7 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 }; + grub_size_t initrd_size; + void *initrd_mem = NULL; ++ grub_err_t err; + + if (argc == 0) + { +@@ -345,16 +329,9 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + initrd_size = grub_get_initrd_size (&initrd_ctx); + grub_dprintf ("linux", "Loading initrd\n"); + +- if (is_bpi_boot == 0) { +- grub_size_t initrd_pages; +- initrd_pages = (GRUB_EFI_BYTES_TO_PAGES (initrd_size)); +- initrd_mem = allocate_initrd_mem (initrd_pages); +- } else { +- grub_err_t err; +- initrd_mem = grub_linux_loongarch_alloc_initrd_mem_align (initrd_size, 0x10000, &err); +- if (err) +- goto fail; +- } ++ initrd_mem = grub_linux_loongarch_alloc_initrd_mem_align (initrd_size, 0x1000, &err); ++ if (err) ++ goto fail; + + if (!initrd_mem) + { +@@ -369,14 +346,10 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + kernel_params.ramdisk_addr = (grub_addr_t) initrd_mem; + kernel_params.ramdisk_size = initrd_size; + grub_dprintf ("linux", "ramdisk [addr=%p, size=0x%lx]\n", +- (void *) initrd_mem, initrd_size); ++ (void *) initrd_mem, initrd_size); + fail: + grub_initrd_close (&initrd_ctx); +- if (is_bpi_boot == 0) { +- if (initrd_mem && !kernel_params.ramdisk_addr) +- grub_efi_free_pages ((grub_addr_t) initrd_mem, +- GRUB_EFI_BYTES_TO_PAGES (initrd_size)); +- } ++ + return grub_errno; + } + +diff --git a/include/grub/loongarch64/linux.h b/include/grub/loongarch64/linux.h +index c010982..f20a719 100644 +--- a/include/grub/loongarch64/linux.h ++++ b/include/grub/loongarch64/linux.h +@@ -59,6 +59,7 @@ struct linux_loongarch64_kernel_params + grub_size_t kernel_size; /* kernel size */ + grub_addr_t ramdisk_addr; /* initrd load address */ + grub_size_t ramdisk_size; /* initrd size */ ++ int ramdisk_args_len; /* position of initrd in linux_args */ + int linux_argc; /* cmdline parameters number*/ + grub_addr_t linux_argv; /* cmdline parameters address*/ + void* linux_args; +@@ -73,12 +74,31 @@ struct linux_loongarch64_kernel_params + #define ELF64_LOADMASK (0xf000000000000000ULL) + #define FLAGS_EFI_SUPPORT_BIT 0 + ++/*initrd info*/ ++#define GRUB_RD_START_STRING "rd_start=0xXXXXXXXXXXXXXXXX" ++#define GRUB_RD_SIZE_STRING "rd_size=0xXXXXXXXXXXXXXXXX" ++#define GRUB_INITRD_STRING "initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX" ++ + #define FDT_ADDR_CELLS_STRING "#address-cells" + #define FDT_SIZE_CELLS_STRING "#size-cells" + #define FDT_ADDR_SIZE_EXTRA ((2 * grub_fdt_prop_entry_size (sizeof(grub_uint32_t))) + \ + sizeof (FDT_ADDR_CELLS_STRING) + \ + sizeof (FDT_SIZE_CELLS_STRING)) + ++struct efi_boot_memmap { ++ grub_efi_uintn_t map_size; ++ grub_efi_uintn_t desc_size; ++ grub_efi_uint32_t desc_ver; ++ grub_efi_uintn_t map_key; ++ grub_efi_uintn_t buff_size; ++ grub_efi_memory_descriptor_t map[]; ++}; ++ ++struct efi_initrd { ++ grub_efi_uintn_t base; ++ grub_efi_uintn_t size; ++}; ++ + /* + * These are set up by the setup-routine at boot-time: + */ +-- +2.33.0 +