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