From 8af974459b2dde129f67544b41a6742d201abfc7 Mon Sep 17 00:00:00 2001 From: lxpzlm Date: Fri, 17 Jun 2022 10:56:13 +0800 Subject: [PATCH 1/4] update to grub2-2.02-123.el8_6.8 Signed-off-by: lxpzlm --- ...loader-grub_load_and_start_image-doe.patch | 72 + ...hainloader-simplify-the-loader-state.patch | 335 ++ ...ot-Add-API-to-pass-context-to-loader.patch | 161 + ...i-chainloader-Use-grub_loader_set_ex.patch | 150 + ...linux-Avoid-a-use-after-free-in-the-.patch | 44 + ...386-efi-linux-Use-grub_loader_set_ex.patch | 300 ++ ...linux-Fix-a-memory-leak-in-the-initr.patch | 78 + ...-leak-device_name-on-error-in-grub_f.patch | 42 + ...g-Abort-sooner-if-a-read-operation-f.patch | 201 + ...g-Refuse-to-handle-multiple-image-he.patch | 31 + ...g-Drop-greyscale-support-to-fix-heap.patch | 173 + ...g-Avoid-heap-OOB-R-W-inserting-huff-.patch | 43 + ...-png-Sanity-check-some-huffman-codes.patch | 43 + ...eg-Abort-sooner-if-a-read-operation-.patch | 258 ++ ...eg-Do-not-reallocate-a-given-huff-ta.patch | 32 + ...eg-Refuse-to-handle-multiple-start-o.patch | 47 + ...eg-Block-int-underflow-wild-pointer-.patch | 56 + ...ix-array-out-of-bounds-formatting-un.patch | 37 + ...ff-Block-overly-large-netbuff-allocs.patch | 49 + 0520-net-ip-Do-IP-fragment-maths-safely.patch | 47 + ...le-free-addresses-on-corrupt-DNS-res.patch | 59 + ...ad-past-the-end-of-the-string-we-re-.patch | 74 + ...-a-UAF-and-double-free-from-a-failed.patch | 115 + ...ng-for-grub_error-should-be-a-litera.patch | 54 + 0525-net-tftp-Avoid-a-trivial-UAF.patch | 38 + ...tear-down-socket-if-it-s-already-bee.patch | 45 + ...Fix-OOB-write-for-split-http-headers.patch | 49 + ...or-out-on-headers-with-LF-without-CR.patch | 51 + ...ead-past-the-end-of-nat-journal-entr.patch | 75 + ...-not-read-past-the-end-of-nat-bitmap.patch | 135 + ...ot-copy-file-names-that-are-too-long.patch | 41 + ...eral-fuzz-issues-with-invalid-dir-it.patch | 82 + ...efi_status_t-from-grub_efi_get_varia.patch | 144 + ...on-to-read-EFI-variables-with-attrib.patch | 77 + 0535-Define-GRUB_EFI_SHIM_LOCK_GUID.patch | 32 + ...grub_min-and-grub_max-more-resilient.patch | 85 + ...FS-switch-to-using-grub_min-grub_max.patch | 95 + ...oot_time-also-call-grub_dprintf-boot.patch | 49 + ...dules-make-.module_license-read-only.patch | 33 + ...p-.llvm_addrsig-sections-and-similar.patch | 42 + ...locate-space-for-non-allocable-secti.patch | 38 + ...eader-struct-and-fix-some-bad-naming.patch | 84 + ...nel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch | 88 + ...ule-sections-at-page-aligned-address.patch | 361 ++ ...-nx-add-memory-attribute-get-set-API.patch | 321 ++ ...-page-permissions-for-loaded-modules.patch | 266 ++ 0547-nx-set-attrs-in-our-kernel-loaders.patch | 572 +++ ...x-compatible-flag-in-EFI-grub-images.patch | 37 + ...efi_get_variable-type-in-our-loaders.patch | 52 + 1000-loongarch64-add-support.patch | 3968 ----------------- 1001-bls-make-list.patch | 119 - grub.macros | 18 +- grub.patches | 52 +- grub2.spec | 34 +- sbat.csv.in | 4 +- 55 files changed, 5460 insertions(+), 4128 deletions(-) create mode 100644 0501-loader-efi-chainloader-grub_load_and_start_image-doe.patch create mode 100644 0502-loader-efi-chainloader-simplify-the-loader-state.patch create mode 100644 0503-commands-boot-Add-API-to-pass-context-to-loader.patch create mode 100644 0504-loader-efi-chainloader-Use-grub_loader_set_ex.patch create mode 100644 0505-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch create mode 100644 0506-loader-i386-efi-linux-Use-grub_loader_set_ex.patch create mode 100644 0507-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch create mode 100644 0508-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch create mode 100644 0509-video-readers-png-Abort-sooner-if-a-read-operation-f.patch create mode 100644 0510-video-readers-png-Refuse-to-handle-multiple-image-he.patch create mode 100644 0511-video-readers-png-Drop-greyscale-support-to-fix-heap.patch create mode 100644 0512-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch create mode 100644 0513-video-readers-png-Sanity-check-some-huffman-codes.patch create mode 100644 0514-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch create mode 100644 0515-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch create mode 100644 0516-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch create mode 100644 0517-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch create mode 100644 0518-normal-charset-Fix-array-out-of-bounds-formatting-un.patch create mode 100644 0519-net-netbuff-Block-overly-large-netbuff-allocs.patch create mode 100644 0520-net-ip-Do-IP-fragment-maths-safely.patch create mode 100644 0521-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch create mode 100644 0522-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch create mode 100644 0523-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch create mode 100644 0524-misc-Format-string-for-grub_error-should-be-a-litera.patch create mode 100644 0525-net-tftp-Avoid-a-trivial-UAF.patch create mode 100644 0526-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch create mode 100644 0527-net-http-Fix-OOB-write-for-split-http-headers.patch create mode 100644 0528-net-http-Error-out-on-headers-with-LF-without-CR.patch create mode 100644 0529-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch create mode 100644 0530-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch create mode 100644 0531-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch create mode 100644 0532-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch create mode 100644 0533-efi-Return-grub_efi_status_t-from-grub_efi_get_varia.patch create mode 100644 0534-efi-Add-a-function-to-read-EFI-variables-with-attrib.patch create mode 100644 0535-Define-GRUB_EFI_SHIM_LOCK_GUID.patch create mode 100644 0536-misc-Make-grub_min-and-grub_max-more-resilient.patch create mode 100644 0537-ReiserFS-switch-to-using-grub_min-grub_max.patch create mode 100644 0538-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch create mode 100644 0539-modules-make-.module_license-read-only.patch create mode 100644 0540-modules-strip-.llvm_addrsig-sections-and-similar.patch create mode 100644 0541-modules-Don-t-allocate-space-for-non-allocable-secti.patch create mode 100644 0542-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch create mode 100644 0543-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch create mode 100644 0544-modules-load-module-sections-at-page-aligned-address.patch create mode 100644 0545-nx-add-memory-attribute-get-set-API.patch create mode 100644 0546-nx-set-page-permissions-for-loaded-modules.patch create mode 100644 0547-nx-set-attrs-in-our-kernel-loaders.patch create mode 100644 0548-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch create mode 100644 0549-Fixup-grub_efi_get_variable-type-in-our-loaders.patch delete mode 100644 1000-loongarch64-add-support.patch delete mode 100644 1001-bls-make-list.patch diff --git a/0501-loader-efi-chainloader-grub_load_and_start_image-doe.patch b/0501-loader-efi-chainloader-grub_load_and_start_image-doe.patch new file mode 100644 index 0000000..1383d29 --- /dev/null +++ b/0501-loader-efi-chainloader-grub_load_and_start_image-doe.patch @@ -0,0 +1,72 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Thu, 28 Apr 2022 21:53:36 +0100 +Subject: [PATCH] loader/efi/chainloader: grub_load_and_start_image doesn't + load and start + +grub_load_and_start_image only loads an image - it still requires the +caller to start it. This renames it to grub_load_image. + +It's called from 2 places: +- grub_cmd_chainloader when not using the shim protocol. +- grub_secureboot_chainloader_boot if handle_image returns an error. +In this case, the image is loaded and then nothing else happens which +seems strange. I assume the intention is that it falls back to LoadImage +and StartImage if handle_image fails, so I've made it do that. + +Signed-off-by: Chris Coulson +(cherry picked from commit b4d70820a65c00561045856b7b8355461a9545f6) +(cherry picked from commit 05b16a6be50b1910609740a66b561276fa490538) +(cherry picked from commit 16486a34f3aa41a94e334e86db1a1e21e9b0a45f) +(cherry picked from commit 4a23f40cb6400d94621de688a7e79dfe124f5a63) +--- + grub-core/loader/efi/chainloader.c | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 29663f7180..d75d345003 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -835,7 +835,7 @@ grub_secureboot_chainloader_unload (void) + } + + static grub_err_t +-grub_load_and_start_image(void *boot_image) ++grub_load_image(void *boot_image) + { + grub_efi_boot_services_t *b; + grub_efi_status_t status; +@@ -877,13 +877,23 @@ grub_load_and_start_image(void *boot_image) + static grub_err_t + grub_secureboot_chainloader_boot (void) + { ++ grub_efi_boot_services_t *b; + int rc; ++ + rc = handle_image ((void *)(unsigned long)address, fsize); + if (rc == 0) + { +- grub_load_and_start_image((void *)(unsigned long)address); ++ /* We weren't able to attempt to execute the image, so fall back ++ * to LoadImage / StartImage. ++ */ ++ rc = grub_load_image((void *)(unsigned long)address); ++ if (rc == 0) ++ grub_chainloader_boot (); + } + ++ b = grub_efi_system_table->boot_services; ++ efi_call_1 (b->unload_image, image_handle); ++ + grub_loader_unset (); + return grub_errno; + } +@@ -1072,7 +1082,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + } + else if (rc == 0) + { +- grub_load_and_start_image(boot_image); ++ grub_load_image(boot_image); + grub_file_close (file); + grub_device_close (dev); + grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); diff --git a/0502-loader-efi-chainloader-simplify-the-loader-state.patch b/0502-loader-efi-chainloader-simplify-the-loader-state.patch new file mode 100644 index 0000000..4eb34ff --- /dev/null +++ b/0502-loader-efi-chainloader-simplify-the-loader-state.patch @@ -0,0 +1,335 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Fri, 29 Apr 2022 21:13:08 +0100 +Subject: [PATCH] loader/efi/chainloader: simplify the loader state + +When not using the shim lock protocol, the chainloader command retains +the source buffer and device path passed to LoadImage, requiring the +unload hook passed to grub_loader_set to free them. It isn't required +to retain this state though - they aren't required by StartImage or +anything else in the boot hook, so clean them up before +grub_cmd_chainloader finishes. + +This also wraps the loader state when using the shim lock protocol +inside a struct. + +Signed-off-by: Chris Coulson +(cherry picked from commit fa39862933b3be1553a580a3a5c28073257d8046) +(cherry picked from commit 0333343ee99c4e88f062789263c94291c057251b) +[rharwood: verifying twice] +(cherry picked from commit 6080ad5d91d6a80d5f67c592dd33b6dd413e9453) +[rharwood: double frees and unintialized, context fuzz - orig_dp] +Signed-off-by: Robbie Harwood +(cherry picked from commit b44b88ae45008611ec0469fb47139f4c0d1ee233) +--- + grub-core/loader/efi/chainloader.c | 160 +++++++++++++++++++++++-------------- + 1 file changed, 102 insertions(+), 58 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index d75d345003..afeb1fc97e 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -47,38 +47,21 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + +-static grub_efi_physical_address_t address; +-static grub_efi_uintn_t pages; +-static grub_ssize_t fsize; +-static grub_efi_device_path_t *file_path; + static grub_efi_handle_t image_handle; +-static grub_efi_char16_t *cmdline; +-static grub_ssize_t cmdline_len; +-static grub_efi_handle_t dev_handle; + +-static grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table); ++struct grub_secureboot_chainloader_context { ++ grub_efi_physical_address_t address; ++ grub_efi_uintn_t pages; ++ grub_ssize_t fsize; ++ grub_efi_device_path_t *file_path; ++ grub_efi_char16_t *cmdline; ++ grub_ssize_t cmdline_len; ++ grub_efi_handle_t dev_handle; ++}; ++static struct grub_secureboot_chainloader_context *sb_context; + + static grub_err_t +-grub_chainloader_unload (void) +-{ +- grub_efi_boot_services_t *b; +- +- b = grub_efi_system_table->boot_services; +- efi_call_1 (b->unload_image, image_handle); +- grub_efi_free_pages (address, pages); +- +- grub_free (file_path); +- grub_free (cmdline); +- cmdline = 0; +- file_path = 0; +- dev_handle = 0; +- +- grub_dl_unref (my_mod); +- return GRUB_ERR_NONE; +-} +- +-static grub_err_t +-grub_chainloader_boot (void) ++grub_start_image (grub_efi_handle_t handle) + { + grub_efi_boot_services_t *b; + grub_efi_status_t status; +@@ -86,7 +69,7 @@ grub_chainloader_boot (void) + grub_efi_char16_t *exit_data = NULL; + + b = grub_efi_system_table->boot_services; +- status = efi_call_3 (b->start_image, image_handle, &exit_data_size, &exit_data); ++ status = efi_call_3 (b->start_image, handle, &exit_data_size, &exit_data); + if (status != GRUB_EFI_SUCCESS) + { + if (exit_data) +@@ -110,11 +93,37 @@ grub_chainloader_boot (void) + if (exit_data) + grub_efi_free_pool (exit_data); + +- grub_loader_unset (); +- + return grub_errno; + } + ++static grub_err_t ++grub_chainloader_unload (void) ++{ ++ grub_efi_loaded_image_t *loaded_image; ++ grub_efi_boot_services_t *b; ++ ++ loaded_image = grub_efi_get_loaded_image (image_handle); ++ if (loaded_image != NULL) ++ grub_free (loaded_image->load_options); ++ ++ b = grub_efi_system_table->boot_services; ++ efi_call_1 (b->unload_image, image_handle); ++ ++ grub_dl_unref (my_mod); ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_chainloader_boot (void) ++{ ++ grub_err_t err; ++ ++ err = grub_start_image (image_handle); ++ ++ grub_loader_unset (); ++ return err; ++} ++ + static grub_err_t + copy_file_path (grub_efi_file_path_device_path_t *fp, + const char *str, grub_efi_uint16_t len) +@@ -149,7 +158,7 @@ make_file_path (grub_efi_device_path_t *dp, const char *filename) + char *dir_start; + char *dir_end; + grub_size_t size; +- grub_efi_device_path_t *d; ++ grub_efi_device_path_t *d, *file_path; + + dir_start = grub_strchr (filename, ')'); + if (! dir_start) +@@ -520,10 +529,12 @@ grub_efi_get_media_file_path (grub_efi_device_path_t *dp) + } + + static grub_efi_boolean_t +-handle_image (void *data, grub_efi_uint32_t datasize) ++handle_image (struct grub_secureboot_chainloader_context *load_context) + { + grub_efi_loaded_image_t *li, li_bak; + grub_efi_status_t efi_status; ++ void *data = (void *)(unsigned long)load_context->address; ++ grub_efi_uint32_t datasize = load_context->fsize; + void *buffer = NULL; + char *buffer_aligned = NULL; + grub_efi_uint32_t i; +@@ -534,6 +545,7 @@ handle_image (void *data, grub_efi_uint32_t datasize) + grub_uint32_t buffer_size; + int found_entry_point = 0; + int rc; ++ grub_efi_status_t (*entry_point) (grub_efi_handle_t image_handle, grub_efi_system_table_t *system_table); + + rc = read_header (data, datasize, &context); + if (rc < 0) +@@ -791,10 +803,10 @@ handle_image (void *data, grub_efi_uint32_t datasize) + grub_memcpy (&li_bak, li, sizeof (grub_efi_loaded_image_t)); + li->image_base = buffer_aligned; + li->image_size = context.image_size; +- li->load_options = cmdline; +- li->load_options_size = cmdline_len; +- li->file_path = grub_efi_get_media_file_path (file_path); +- li->device_handle = dev_handle; ++ li->load_options = load_context->cmdline; ++ li->load_options_size = load_context->cmdline_len; ++ li->file_path = grub_efi_get_media_file_path (load_context->file_path); ++ li->device_handle = load_context->dev_handle; + if (!li->file_path) + { + grub_error (GRUB_ERR_UNKNOWN_DEVICE, "no matching file path found"); +@@ -823,19 +835,22 @@ error_exit: + static grub_err_t + grub_secureboot_chainloader_unload (void) + { +- grub_efi_free_pages (address, pages); +- grub_free (file_path); +- grub_free (cmdline); +- cmdline = 0; +- file_path = 0; +- dev_handle = 0; ++ grub_efi_free_pages (sb_context->address, sb_context->pages); ++ grub_free (sb_context->file_path); ++ grub_free (sb_context->cmdline); ++ grub_free (sb_context); ++ ++ sb_context = 0; + + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; + } + + static grub_err_t +-grub_load_image(void *boot_image) ++grub_load_image(grub_efi_device_path_t *file_path, void *boot_image, ++ grub_efi_uintn_t image_size, grub_efi_handle_t dev_handle, ++ grub_efi_char16_t *cmdline, grub_ssize_t cmdline_len, ++ grub_efi_handle_t *image_handle_out) + { + grub_efi_boot_services_t *b; + grub_efi_status_t status; +@@ -844,7 +859,7 @@ grub_load_image(void *boot_image) + b = grub_efi_system_table->boot_services; + + status = efi_call_6 (b->load_image, 0, grub_efi_image_handle, file_path, +- boot_image, fsize, &image_handle); ++ boot_image, image_size, image_handle_out); + if (status != GRUB_EFI_SUCCESS) + { + if (status == GRUB_EFI_OUT_OF_RESOURCES) +@@ -857,7 +872,7 @@ grub_load_image(void *boot_image) + /* LoadImage does not set a device handler when the image is + loaded from memory, so it is necessary to set it explicitly here. + This is a mess. */ +- loaded_image = grub_efi_get_loaded_image (image_handle); ++ loaded_image = grub_efi_get_loaded_image (*image_handle_out); + if (! loaded_image) + { + grub_error (GRUB_ERR_BAD_OS, "no loaded image available"); +@@ -879,20 +894,25 @@ grub_secureboot_chainloader_boot (void) + { + grub_efi_boot_services_t *b; + int rc; ++ grub_efi_handle_t handle = 0; + +- rc = handle_image ((void *)(unsigned long)address, fsize); ++ rc = handle_image (sb_context); + if (rc == 0) + { + /* We weren't able to attempt to execute the image, so fall back + * to LoadImage / StartImage. + */ +- rc = grub_load_image((void *)(unsigned long)address); ++ rc = grub_load_image(sb_context->file_path, ++ (void *)(unsigned long)sb_context->address, ++ sb_context->fsize, sb_context->dev_handle, ++ sb_context->cmdline, sb_context->cmdline_len, ++ &handle); + if (rc == 0) +- grub_chainloader_boot (); ++ grub_start_image (handle); + } + + b = grub_efi_system_table->boot_services; +- efi_call_1 (b->unload_image, image_handle); ++ efi_call_1 (b->unload_image, handle); + + grub_loader_unset (); + return grub_errno; +@@ -906,10 +926,16 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_status_t status; + grub_efi_boot_services_t *b; + grub_device_t dev = 0; +- grub_efi_device_path_t *dp = 0; ++ grub_efi_device_path_t *dp = 0, *file_path = 0; + char *filename; + void *boot_image = 0; + int rc; ++ grub_efi_physical_address_t address = 0; ++ grub_ssize_t fsize; ++ grub_efi_uintn_t pages = 0; ++ grub_efi_char16_t *cmdline = 0; ++ grub_ssize_t cmdline_len = 0; ++ grub_efi_handle_t dev_handle = 0; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -917,12 +943,6 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + + grub_dl_ref (my_mod); + +- /* Initialize some global variables. */ +- address = 0; +- image_handle = 0; +- file_path = 0; +- dev_handle = 0; +- + b = grub_efi_system_table->boot_services; + + if (argc > 1) +@@ -1074,17 +1094,35 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("chain", "linuxefi_secure_validate: %d\n", rc); + if (rc > 0) + { ++ sb_context = grub_malloc (sizeof (*sb_context)); ++ if (sb_context == NULL) ++ goto fail; ++ sb_context->address = address; ++ sb_context->fsize = fsize; ++ sb_context->pages = pages; ++ sb_context->file_path = file_path; ++ sb_context->cmdline = cmdline; ++ sb_context->cmdline_len = cmdline_len; ++ sb_context->dev_handle = dev_handle; ++ + grub_file_close (file); + grub_device_close (dev); ++ + grub_loader_set (grub_secureboot_chainloader_boot, + grub_secureboot_chainloader_unload, 0); + return 0; + } + else if (rc == 0) + { +- grub_load_image(boot_image); ++ grub_load_image(file_path, boot_image, fsize, dev_handle, cmdline, ++ cmdline_len, &image_handle); + grub_file_close (file); + grub_device_close (dev); ++ ++ /* We're finished with the source image buffer and file path now */ ++ efi_call_2 (b->free_pages, address, pages); ++ grub_free (file_path); ++ + grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); + + return 0; +@@ -1106,6 +1144,12 @@ fail: + if (cmdline) + grub_free (cmdline); + ++ if (image_handle != 0) ++ { ++ efi_call_1 (b->unload_image, image_handle); ++ image_handle = 0; ++ } ++ + grub_dl_unref (my_mod); + + return grub_errno; diff --git a/0503-commands-boot-Add-API-to-pass-context-to-loader.patch b/0503-commands-boot-Add-API-to-pass-context-to-loader.patch new file mode 100644 index 0000000..4270078 --- /dev/null +++ b/0503-commands-boot-Add-API-to-pass-context-to-loader.patch @@ -0,0 +1,161 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Fri, 29 Apr 2022 21:16:02 +0100 +Subject: [PATCH] commands/boot: Add API to pass context to loader + +Loaders rely on global variables for saving context which is consumed +in the boot hook and freed in the unload hook. In the case where a loader +command is executed twice, calling grub_loader_set a second time executes +the unload hook, but in some cases this runs when the loader's global +context has already been updated, resulting in the updated context being +freed and potential use-after-free bugs when the boot hook is subsequently +called. + +This adds a new API (grub_loader_set_ex) which allows a loader to specify +context that is passed to its boot and unload hooks. This is an alternative +to requiring that loaders call grub_loader_unset before mutating their +global context. + +Signed-off-by: Chris Coulson +(cherry picked from commit 4322a64dde7e8fedb58e50b79408667129d45dd3) +(cherry picked from commit 937ad0e2159b6b8cb0d2ce3515da3a8b797c7927) +(cherry picked from commit 873038ae7048f6cae8a3ebb2f97a8d361a080e13) +(cherry picked from commit 7eefe9ba7e8f1557705f0f854ab7a3014d6cb5e2) +--- + grub-core/commands/boot.c | 66 +++++++++++++++++++++++++++++++++++++++++------ + include/grub/loader.h | 5 ++++ + 2 files changed, 63 insertions(+), 8 deletions(-) + +diff --git a/grub-core/commands/boot.c b/grub-core/commands/boot.c +index bbca81e947..53691a62d9 100644 +--- a/grub-core/commands/boot.c ++++ b/grub-core/commands/boot.c +@@ -27,10 +27,20 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + +-static grub_err_t (*grub_loader_boot_func) (void); +-static grub_err_t (*grub_loader_unload_func) (void); ++static grub_err_t (*grub_loader_boot_func) (void *); ++static grub_err_t (*grub_loader_unload_func) (void *); ++static void *grub_loader_context; + static int grub_loader_flags; + ++struct grub_simple_loader_hooks ++{ ++ grub_err_t (*boot) (void); ++ grub_err_t (*unload) (void); ++}; ++ ++/* Don't heap allocate this to avoid making grub_loader_set fallible. */ ++static struct grub_simple_loader_hooks simple_loader_hooks; ++ + struct grub_preboot + { + grub_err_t (*preboot_func) (int); +@@ -44,6 +54,29 @@ static int grub_loader_loaded; + static struct grub_preboot *preboots_head = 0, + *preboots_tail = 0; + ++static grub_err_t ++grub_simple_boot_hook (void *context) ++{ ++ struct grub_simple_loader_hooks *hooks; ++ ++ hooks = (struct grub_simple_loader_hooks *) context; ++ return hooks->boot (); ++} ++ ++static grub_err_t ++grub_simple_unload_hook (void *context) ++{ ++ struct grub_simple_loader_hooks *hooks; ++ grub_err_t ret; ++ ++ hooks = (struct grub_simple_loader_hooks *) context; ++ ++ ret = hooks->unload (); ++ grub_memset (hooks, 0, sizeof (*hooks)); ++ ++ return ret; ++} ++ + int + grub_loader_is_loaded (void) + { +@@ -110,28 +143,45 @@ grub_loader_unregister_preboot_hook (struct grub_preboot *hnd) + } + + void +-grub_loader_set (grub_err_t (*boot) (void), +- grub_err_t (*unload) (void), +- int flags) ++grub_loader_set_ex (grub_err_t (*boot) (void *), ++ grub_err_t (*unload) (void *), ++ void *context, ++ int flags) + { + if (grub_loader_loaded && grub_loader_unload_func) +- grub_loader_unload_func (); ++ grub_loader_unload_func (grub_loader_context); + + grub_loader_boot_func = boot; + grub_loader_unload_func = unload; ++ grub_loader_context = context; + grub_loader_flags = flags; + + grub_loader_loaded = 1; + } + ++void ++grub_loader_set (grub_err_t (*boot) (void), ++ grub_err_t (*unload) (void), ++ int flags) ++{ ++ grub_loader_set_ex (grub_simple_boot_hook, ++ grub_simple_unload_hook, ++ &simple_loader_hooks, ++ flags); ++ ++ simple_loader_hooks.boot = boot; ++ simple_loader_hooks.unload = unload; ++} ++ + void + grub_loader_unset(void) + { + if (grub_loader_loaded && grub_loader_unload_func) +- grub_loader_unload_func (); ++ grub_loader_unload_func (grub_loader_context); + + grub_loader_boot_func = 0; + grub_loader_unload_func = 0; ++ grub_loader_context = 0; + + grub_loader_loaded = 0; + } +@@ -158,7 +208,7 @@ grub_loader_boot (void) + return err; + } + } +- err = (grub_loader_boot_func) (); ++ err = (grub_loader_boot_func) (grub_loader_context); + + for (cur = preboots_tail; cur; cur = cur->prev) + if (! err) +diff --git a/include/grub/loader.h b/include/grub/loader.h +index b208642821..1846fa6c5f 100644 +--- a/include/grub/loader.h ++++ b/include/grub/loader.h +@@ -40,6 +40,11 @@ void EXPORT_FUNC (grub_loader_set) (grub_err_t (*boot) (void), + grub_err_t (*unload) (void), + int flags); + ++void EXPORT_FUNC (grub_loader_set_ex) (grub_err_t (*boot) (void *), ++ grub_err_t (*unload) (void *), ++ void *context, ++ int flags); ++ + /* Unset current loader, if any. */ + void EXPORT_FUNC (grub_loader_unset) (void); + diff --git a/0504-loader-efi-chainloader-Use-grub_loader_set_ex.patch b/0504-loader-efi-chainloader-Use-grub_loader_set_ex.patch new file mode 100644 index 0000000..4ccc6df --- /dev/null +++ b/0504-loader-efi-chainloader-Use-grub_loader_set_ex.patch @@ -0,0 +1,150 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Fri, 29 Apr 2022 21:30:56 +0100 +Subject: [PATCH] loader/efi/chainloader: Use grub_loader_set_ex + +This ports the EFI chainloader to use grub_loader_set_ex in order to fix +a use-after-free bug that occurs when grub_cmd_chainloader is executed +more than once before a boot attempt is performed. + +Signed-off-by: Chris Coulson +(cherry picked from commit 4b7f0402b7cb0f67a93be736f2b75b818d7f44c9) +(cherry picked from commit fc1a79bf0e0bc019362ace46d908a92b48dcd55b) +(cherry picked from commit f5b653dfe00271384ff7fbd82db926ab95dbd80e) +(cherry picked from commit 535a9d787f71ed6eb43e7c3a136a149684ec62ea) +[rharwood: context sludge from previous commit] +Signed-off-by: Robbie Harwood +--- + grub-core/loader/efi/chainloader.c | 38 ++++++++++++++++++++++---------------- + 1 file changed, 22 insertions(+), 16 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index afeb1fc97e..720f6181e5 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -47,8 +47,6 @@ GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; + +-static grub_efi_handle_t image_handle; +- + struct grub_secureboot_chainloader_context { + grub_efi_physical_address_t address; + grub_efi_uintn_t pages; +@@ -58,7 +56,6 @@ struct grub_secureboot_chainloader_context { + grub_ssize_t cmdline_len; + grub_efi_handle_t dev_handle; + }; +-static struct grub_secureboot_chainloader_context *sb_context; + + static grub_err_t + grub_start_image (grub_efi_handle_t handle) +@@ -97,11 +94,14 @@ grub_start_image (grub_efi_handle_t handle) + } + + static grub_err_t +-grub_chainloader_unload (void) ++grub_chainloader_unload (void *context) + { ++ grub_efi_handle_t image_handle; + grub_efi_loaded_image_t *loaded_image; + grub_efi_boot_services_t *b; + ++ image_handle = (grub_efi_handle_t) context; ++ + loaded_image = grub_efi_get_loaded_image (image_handle); + if (loaded_image != NULL) + grub_free (loaded_image->load_options); +@@ -114,10 +114,12 @@ grub_chainloader_unload (void) + } + + static grub_err_t +-grub_chainloader_boot (void) ++grub_chainloader_boot (void *context) + { ++ grub_efi_handle_t image_handle; + grub_err_t err; + ++ image_handle = (grub_efi_handle_t) context; + err = grub_start_image (image_handle); + + grub_loader_unset (); +@@ -833,15 +835,17 @@ error_exit: + } + + static grub_err_t +-grub_secureboot_chainloader_unload (void) ++grub_secureboot_chainloader_unload (void *context) + { ++ struct grub_secureboot_chainloader_context *sb_context; ++ ++ sb_context = (struct grub_secureboot_chainloader_context *) context; ++ + grub_efi_free_pages (sb_context->address, sb_context->pages); + grub_free (sb_context->file_path); + grub_free (sb_context->cmdline); + grub_free (sb_context); + +- sb_context = 0; +- + grub_dl_unref (my_mod); + return GRUB_ERR_NONE; + } +@@ -890,12 +894,15 @@ grub_load_image(grub_efi_device_path_t *file_path, void *boot_image, + } + + static grub_err_t +-grub_secureboot_chainloader_boot (void) ++grub_secureboot_chainloader_boot (void *context) + { ++ struct grub_secureboot_chainloader_context *sb_context; + grub_efi_boot_services_t *b; + int rc; + grub_efi_handle_t handle = 0; + ++ sb_context = (struct grub_secureboot_chainloader_context *) context; ++ + rc = handle_image (sb_context); + if (rc == 0) + { +@@ -936,6 +943,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_efi_char16_t *cmdline = 0; + grub_ssize_t cmdline_len = 0; + grub_efi_handle_t dev_handle = 0; ++ grub_efi_handle_t image_handle = 0; ++ struct grub_secureboot_chainloader_context *sb_context = 0; + + if (argc == 0) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); +@@ -1108,8 +1117,8 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + grub_file_close (file); + grub_device_close (dev); + +- grub_loader_set (grub_secureboot_chainloader_boot, +- grub_secureboot_chainloader_unload, 0); ++ grub_loader_set_ex (grub_secureboot_chainloader_boot, ++ grub_secureboot_chainloader_unload, sb_context, 0); + return 0; + } + else if (rc == 0) +@@ -1123,7 +1132,7 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + efi_call_2 (b->free_pages, address, pages); + grub_free (file_path); + +- grub_loader_set (grub_chainloader_boot, grub_chainloader_unload, 0); ++ grub_loader_set_ex (grub_chainloader_boot, grub_chainloader_unload, image_handle, 0); + + return 0; + } +@@ -1145,10 +1154,7 @@ fail: + grub_free (cmdline); + + if (image_handle != 0) +- { +- efi_call_1 (b->unload_image, image_handle); +- image_handle = 0; +- } ++ efi_call_1 (b->unload_image, image_handle); + + grub_dl_unref (my_mod); + diff --git a/0505-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch b/0505-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch new file mode 100644 index 0000000..cdbd769 --- /dev/null +++ b/0505-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch @@ -0,0 +1,44 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Mon, 2 May 2022 14:39:31 +0200 +Subject: [PATCH] loader/i386/efi/linux: Avoid a use-after-free in the linuxefi + loader + +In some error paths in grub_cmd_linux, the pointer to lh may be +dereferenced after the buffer it points to has been freed. There aren't +any security implications from this because nothing else uses the +allocator after the buffer is freed and before the pointer is +dereferenced, but fix it anyway. + +Signed-off-by: Chris Coulson +(cherry picked from commit 8224f5a71af94bec8697de17e7e579792db9f9e2) +(cherry picked from commit 4744b62e20d07674017213ac54d7442d679f9d1a) +(cherry picked from commit 329633cb060957c3d2aca677ac733f07b213a63f) +(cherry picked from commit 47b839b0a801ee4852447a85fb5de91dc7d2c856) +--- + grub-core/loader/i386/efi/linux.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index a043df891f..c9a2b47370 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -482,9 +482,6 @@ fail: + if (file) + grub_file_close (file); + +- if (kernel) +- grub_free (kernel); +- + if (grub_errno != GRUB_ERR_NONE) + { + grub_dl_unref (my_mod); +@@ -500,6 +497,8 @@ fail: + kernel_free (params, sizeof(*params)); + } + ++ grub_free (kernel); ++ + return grub_errno; + } + diff --git a/0506-loader-i386-efi-linux-Use-grub_loader_set_ex.patch b/0506-loader-i386-efi-linux-Use-grub_loader_set_ex.patch new file mode 100644 index 0000000..a0f04a2 --- /dev/null +++ b/0506-loader-i386-efi-linux-Use-grub_loader_set_ex.patch @@ -0,0 +1,300 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Mon, 2 May 2022 17:04:23 +0200 +Subject: [PATCH] loader/i386/efi/linux: Use grub_loader_set_ex + +This ports the linuxefi loader to use grub_loader_set_ex in order to fix +a use-after-fre bug that occurs when grub_cmd_linux is executed more than +once before a boot attempt is performed. + +This is more complicated than for the chainloader command, as the initrd +command needs access to the loader state. To solve this, the linuxefi +module registers a dummy initrd command at startup that returns an error. +The linuxefi command then registers a proper initrd command with a higher +priority that is passed the loader state. + +Signed-off-by: Chris Coulson +(cherry picked from commit 7cf736436b4c934df5ddfa6f44b46a7e07d99fdc) +[rharwood/pjones: set kernel_size in context] +(cherry picked from commit 9c056391f7a36ea480de9a759c12e55a90f2040a) +[rharwood: verifying twice] +Signed-off-by: Robbie Harwood +(cherry picked from commit df804892f1a754d88a9779320f9429bf40d2a1b3) +(cherry picked from commit d1b506f6c910b96ad47a20247b438c6402a74948) +--- + grub-core/loader/i386/efi/linux.c | 146 +++++++++++++++++++++++--------------- + 1 file changed, 87 insertions(+), 59 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index c9a2b47370..77a0734786 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -34,13 +34,19 @@ + GRUB_MOD_LICENSE ("GPLv3+"); + + static grub_dl_t my_mod; +-static int loaded; +-static void *kernel_mem; +-static grub_uint64_t kernel_size; +-static void *initrd_mem; +-static grub_uint32_t handover_offset; +-struct linux_kernel_params *params; +-static char *linux_cmdline; ++ ++static grub_command_t cmd_linux, cmd_initrd; ++static grub_command_t cmd_linuxefi, cmd_initrdefi; ++ ++struct grub_linuxefi_context { ++ void *kernel_mem; ++ grub_uint64_t kernel_size; ++ grub_uint32_t handover_offset; ++ struct linux_kernel_params *params; ++ char *cmdline; ++ ++ void *initrd_mem; ++}; + + #define MIN(a, b) \ + ({ typeof (a) _a = (a); \ +@@ -123,25 +129,32 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) + } + + static grub_err_t +-grub_linuxefi_boot (void) ++grub_linuxefi_boot (void *data) + { ++ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data; ++ + asm volatile ("cli"); + +- return grub_efi_linux_boot ((char *)kernel_mem, +- handover_offset, +- params); ++ return grub_efi_linux_boot ((char *)context->kernel_mem, ++ context->handover_offset, ++ context->params); + } + + static grub_err_t +-grub_linuxefi_unload (void) ++grub_linuxefi_unload (void *data) + { ++ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) data; ++ struct linux_kernel_params *params = context->params; ++ + grub_dl_unref (my_mod); +- loaded = 0; + +- kernel_free(initrd_mem, params->ramdisk_size); +- kernel_free(linux_cmdline, params->cmdline_size + 1); +- kernel_free(kernel_mem, kernel_size); +- kernel_free(params, sizeof(*params)); ++ kernel_free (context->initrd_mem, params->ramdisk_size); ++ kernel_free (context->cmdline, params->cmdline_size + 1); ++ kernel_free (context->kernel_mem, context->kernel_size); ++ kernel_free (params, sizeof(*params)); ++ cmd_initrd->data = 0; ++ cmd_initrdefi->data = 0; ++ grub_free (context); + + return GRUB_ERR_NONE; + } +@@ -188,13 +201,14 @@ read(grub_file_t file, grub_uint8_t *bufp, grub_size_t len) + #define HIGH_U32(val) ((grub_uint32_t)(((grub_addr_t)(val) >> 32) & 0xffffffffull)) + + static grub_err_t +-grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), +- int argc, char *argv[]) ++grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + { + grub_file_t *files = 0; + int i, nfiles = 0; + grub_size_t size = 0; + grub_uint8_t *ptr; ++ struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data; ++ struct linux_kernel_params *params; + + if (argc == 0) + { +@@ -202,12 +216,14 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + +- if (!loaded) ++ if (!context) + { + grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); + goto fail; + } + ++ params = context->params; ++ + files = grub_calloc (argc, sizeof (files[0])); + if (!files) + goto fail; +@@ -226,19 +242,19 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + } + } + +- initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); +- if (initrd_mem == NULL) ++ context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); ++ if (context->initrd_mem == NULL) + goto fail; +- grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); ++ grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem); + + params->ramdisk_size = LOW_U32(size); +- params->ramdisk_image = LOW_U32(initrd_mem); ++ params->ramdisk_image = LOW_U32(context->initrd_mem); + #if defined(__x86_64__) + params->ext_ramdisk_size = HIGH_U32(size); +- params->ext_ramdisk_image = HIGH_U32(initrd_mem); ++ params->ext_ramdisk_image = HIGH_U32(context->initrd_mem); + #endif + +- ptr = initrd_mem; ++ ptr = context->initrd_mem; + + for (i = 0; i < nfiles; i++) + { +@@ -264,8 +280,8 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), + grub_file_close (files[i]); + grub_free (files); + +- if (initrd_mem && grub_errno) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)initrd_mem, ++ if (context->initrd_mem && grub_errno) ++ grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem, + BYTES_TO_PAGES(size)); + + return grub_errno; +@@ -281,6 +297,12 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + void *kernel = NULL; + int setup_header_end_offset; + int rc; ++ void *kernel_mem = 0; ++ grub_uint64_t kernel_size = 0; ++ grub_uint32_t handover_offset; ++ struct linux_kernel_params *params = 0; ++ char *cmdline = 0; ++ struct grub_linuxefi_context *context = 0; + + grub_dl_ref (my_mod); + +@@ -407,27 +429,27 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "new lh is at %p\n", lh); + + grub_dprintf ("linux", "setting up cmdline\n"); +- linux_cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); +- if (!linux_cmdline) ++ cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); ++ if (!cmdline) + goto fail; +- grub_dprintf ("linux", "linux_cmdline = %p\n", linux_cmdline); ++ grub_dprintf ("linux", "cmdline = %p\n", cmdline); + +- grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); ++ grub_memcpy (cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); + grub_create_loader_cmdline (argc, argv, +- linux_cmdline + sizeof (LINUX_IMAGE) - 1, ++ cmdline + sizeof (LINUX_IMAGE) - 1, + lh->cmdline_size - (sizeof (LINUX_IMAGE) - 1), + GRUB_VERIFY_KERNEL_CMDLINE); + +- grub_dprintf ("linux", "cmdline:%s\n", linux_cmdline); ++ grub_dprintf ("linux", "cmdline:%s\n", cmdline); + grub_dprintf ("linux", "setting lh->cmd_line_ptr to 0x%08x\n", +- LOW_U32(linux_cmdline)); +- lh->cmd_line_ptr = LOW_U32(linux_cmdline); ++ LOW_U32(cmdline)); ++ lh->cmd_line_ptr = LOW_U32(cmdline); + #if defined(__x86_64__) +- if ((grub_efi_uintn_t)linux_cmdline > 0xffffffffull) ++ if ((grub_efi_uintn_t)cmdline > 0xffffffffull) + { + grub_dprintf ("linux", "setting params->ext_cmd_line_ptr to 0x%08x\n", +- HIGH_U32(linux_cmdline)); +- params->ext_cmd_line_ptr = HIGH_U32(linux_cmdline); ++ HIGH_U32(cmdline)); ++ params->ext_cmd_line_ptr = HIGH_U32(cmdline); + } + #endif + +@@ -452,16 +474,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; +- kernel_mem = kernel_alloc (lh->init_size, N_("can't allocate kernel")); ++ kernel_size = lh->init_size; ++ kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel")); + restore_addresses(); + if (!kernel_mem) + goto fail; + grub_dprintf("linux", "kernel_mem = %p\n", kernel_mem); + +- grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); +- +- loaded = 1; +- + grub_dprintf ("linux", "setting lh->code32_start to 0x%08x\n", + LOW_U32(kernel_mem)); + lh->code32_start = LOW_U32(kernel_mem); +@@ -478,33 +497,42 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + "setting lh->ext_loader_{type,ver} = {0x%02x,0x%02x}\n", + params->ext_loader_type, params->ext_loader_ver); + ++ context = grub_zalloc (sizeof (*context)); ++ if (!context) ++ goto fail; ++ context->kernel_mem = kernel_mem; ++ context->kernel_size = kernel_size; ++ context->handover_offset = handover_offset; ++ context->params = params; ++ context->cmdline = cmdline; ++ ++ grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0); ++ ++ cmd_initrd->data = context; ++ cmd_initrdefi->data = context; ++ ++ grub_file_close (file); ++ grub_free (kernel); ++ return 0; ++ + fail: + if (file) + grub_file_close (file); + +- if (grub_errno != GRUB_ERR_NONE) +- { +- grub_dl_unref (my_mod); +- loaded = 0; +- } ++ grub_dl_unref (my_mod); + +- if (!loaded) +- { +- if (lh) +- kernel_free (linux_cmdline, lh->cmdline_size + 1); ++ if (lh) ++ kernel_free (cmdline, lh->cmdline_size + 1); + +- kernel_free (kernel_mem, kernel_size); +- kernel_free (params, sizeof(*params)); +- } ++ kernel_free (kernel_mem, kernel_size); ++ kernel_free (params, sizeof(*params)); + ++ grub_free (context); + grub_free (kernel); + + return grub_errno; + } + +-static grub_command_t cmd_linux, cmd_initrd; +-static grub_command_t cmd_linuxefi, cmd_initrdefi; +- + GRUB_MOD_INIT(linux) + { + cmd_linux = diff --git a/0507-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch b/0507-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch new file mode 100644 index 0000000..6236395 --- /dev/null +++ b/0507-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch @@ -0,0 +1,78 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Chris Coulson +Date: Tue, 3 May 2022 09:47:35 +0200 +Subject: [PATCH] loader/i386/efi/linux: Fix a memory leak in the initrd + command + +Subsequent invocations of the initrd command result in the previous +initrd being leaked, so fix that. + +Signed-off-by: Chris Coulson +(cherry picked from commit d98af31ce1e31bb22163960d53f5eb28c66582a0) +(cherry picked from commit 62234d6a00e6d1dd8e017ff161d359feb5234082) +(cherry picked from commit bda5a10716dc9676400dce1374232452f46d0bc4) +(cherry picked from commit b862299a8502282a09af8e6c6189edd5b0a368b0) +--- + grub-core/loader/i386/efi/linux.c | 21 ++++++++++++--------- + 1 file changed, 12 insertions(+), 9 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 77a0734786..8337191921 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -209,6 +209,7 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + grub_uint8_t *ptr; + struct grub_linuxefi_context *context = (struct grub_linuxefi_context *) cmd->data; + struct linux_kernel_params *params; ++ void *initrd_mem = 0; + + if (argc == 0) + { +@@ -242,19 +243,19 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + } + } + +- context->initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); +- if (context->initrd_mem == NULL) ++ initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); ++ if (initrd_mem == NULL) + goto fail; +- grub_dprintf ("linux", "initrd_mem = %p\n", context->initrd_mem); ++ grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); + + params->ramdisk_size = LOW_U32(size); +- params->ramdisk_image = LOW_U32(context->initrd_mem); ++ params->ramdisk_image = LOW_U32(initrd_mem); + #if defined(__x86_64__) + params->ext_ramdisk_size = HIGH_U32(size); +- params->ext_ramdisk_image = HIGH_U32(context->initrd_mem); ++ params->ext_ramdisk_image = HIGH_U32(initrd_mem); + #endif + +- ptr = context->initrd_mem; ++ ptr = initrd_mem; + + for (i = 0; i < nfiles; i++) + { +@@ -273,6 +274,9 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + ptr += ALIGN_UP_OVERHEAD (cursize, 4); + } + ++ kernel_free(context->initrd_mem, params->ramdisk_size); ++ ++ context->initrd_mem = initrd_mem; + params->ramdisk_size = size; + + fail: +@@ -280,9 +284,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + grub_file_close (files[i]); + grub_free (files); + +- if (context->initrd_mem && grub_errno) +- grub_efi_free_pages ((grub_efi_physical_address_t)(grub_addr_t)context->initrd_mem, +- BYTES_TO_PAGES(size)); ++ if (initrd_mem && grub_errno) ++ kernel_free (initrd_mem, size); + + return grub_errno; + } diff --git a/0508-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch b/0508-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch new file mode 100644 index 0000000..3afccaf --- /dev/null +++ b/0508-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Fri, 25 Jun 2021 02:19:05 +1000 +Subject: [PATCH] kern/file: Do not leak device_name on error in + grub_file_open() + +If we have an error in grub_file_open() before we free device_name, we +will leak it. + +Free device_name in the error path and null out the pointer in the good +path once we free it there. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 1499a5068839fa37cb77ecef4b5bdacbd1ed12ea) +(cherry picked from commit 2ec50b289d8b24922433439533113087f111f110) +(cherry picked from commit 17c36ae88d7d6040cabc01cd4a21e71ff4731668) +(cherry picked from commit 723e7dbedb7669343e564d453d21b8ed2ab81216) +--- + grub-core/kern/file.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/kern/file.c b/grub-core/kern/file.c +index 2efc31da94..f062fc21e7 100644 +--- a/grub-core/kern/file.c ++++ b/grub-core/kern/file.c +@@ -81,6 +81,7 @@ grub_file_open (const char *name, enum grub_file_type type) + + device = grub_device_open (device_name); + grub_free (device_name); ++ device_name = NULL; + if (! device) + goto fail; + +@@ -135,6 +136,7 @@ grub_file_open (const char *name, enum grub_file_type type) + return file; + + fail: ++ grub_free (device_name); + if (device) + grub_device_close (device); + diff --git a/0509-video-readers-png-Abort-sooner-if-a-read-operation-f.patch b/0509-video-readers-png-Abort-sooner-if-a-read-operation-f.patch new file mode 100644 index 0000000..db3764a --- /dev/null +++ b/0509-video-readers-png-Abort-sooner-if-a-read-operation-f.patch @@ -0,0 +1,201 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 14:02:55 +1000 +Subject: [PATCH] video/readers/png: Abort sooner if a read operation fails + +Fuzzing revealed some inputs that were taking a long time, potentially +forever, because they did not bail quickly upon encountering an I/O error. + +Try to catch I/O errors sooner and bail out. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 882be97d1df6449b9fd4d593f0cb70005fde3494) +(cherry picked from commit 3f6fc3ebfd58fcdb3fe6c2f7a5a4fa05772ae786) +(cherry picked from commit aac5b8257d4078c3f764216aeae3367bdc19043f) +(cherry picked from commit e9e58c9711de334fcf48a651ee20c21f2855a4bd) +--- + grub-core/video/readers/png.c | 55 ++++++++++++++++++++++++++++++++++++------- + 1 file changed, 47 insertions(+), 8 deletions(-) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 0157ff7420..e2a6b1cf3c 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -142,6 +142,7 @@ static grub_uint8_t + grub_png_get_byte (struct grub_png_data *data) + { + grub_uint8_t r; ++ grub_ssize_t bytes_read = 0; + + if ((data->inside_idat) && (data->idat_remain == 0)) + { +@@ -175,7 +176,14 @@ grub_png_get_byte (struct grub_png_data *data) + } + + r = 0; +- grub_file_read (data->file, &r, 1); ++ bytes_read = grub_file_read (data->file, &r, 1); ++ ++ if (bytes_read != 1) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: unexpected end of data"); ++ return 0; ++ } + + if (data->inside_idat) + data->idat_remain--; +@@ -231,15 +239,16 @@ grub_png_decode_image_palette (struct grub_png_data *data, + if (len == 0) + return GRUB_ERR_NONE; + +- for (i = 0; 3 * i < len && i < 256; i++) ++ grub_errno = GRUB_ERR_NONE; ++ for (i = 0; 3 * i < len && i < 256 && grub_errno == GRUB_ERR_NONE; i++) + for (j = 0; j < 3; j++) + data->palette[i][j] = grub_png_get_byte (data); +- for (i *= 3; i < len; i++) ++ for (i *= 3; i < len && grub_errno == GRUB_ERR_NONE; i++) + grub_png_get_byte (data); + + grub_png_get_dword (data); + +- return GRUB_ERR_NONE; ++ return grub_errno; + } + + static grub_err_t +@@ -256,9 +265,13 @@ grub_png_decode_image_header (struct grub_png_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: invalid image size"); + + color_bits = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + data->is_16bit = (color_bits == 16); + + color_type = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + /* According to PNG spec, no other types are valid. */ + if ((color_type & ~(PNG_COLOR_MASK_ALPHA | PNG_COLOR_MASK_COLOR)) +@@ -340,14 +353,20 @@ grub_png_decode_image_header (struct grub_png_data *data) + if (grub_png_get_byte (data) != PNG_COMPRESSION_BASE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: compression method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (grub_png_get_byte (data) != PNG_FILTER_TYPE_BASE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: filter method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (grub_png_get_byte (data) != PNG_INTERLACE_NONE) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: interlace method not supported"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + /* Skip crc checksum. */ + grub_png_get_dword (data); +@@ -449,7 +468,7 @@ grub_png_get_huff_code (struct grub_png_data *data, struct huff_table *ht) + int code, i; + + code = 0; +- for (i = 0; i < ht->max_length; i++) ++ for (i = 0; i < ht->max_length && grub_errno == GRUB_ERR_NONE; i++) + { + code = (code << 1) + grub_png_get_bits (data, 1); + if (code < ht->maxval[i]) +@@ -504,8 +523,14 @@ grub_png_init_dynamic_block (struct grub_png_data *data) + grub_uint8_t lens[DEFLATE_HCLEN_MAX]; + + nl = DEFLATE_HLIT_BASE + grub_png_get_bits (data, 5); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + nd = DEFLATE_HDIST_BASE + grub_png_get_bits (data, 5); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + nb = DEFLATE_HCLEN_BASE + grub_png_get_bits (data, 4); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if ((nl > DEFLATE_HLIT_MAX) || (nd > DEFLATE_HDIST_MAX) || + (nb > DEFLATE_HCLEN_MAX)) +@@ -533,7 +558,7 @@ grub_png_init_dynamic_block (struct grub_png_data *data) + data->dist_offset); + + prev = 0; +- for (i = 0; i < nl + nd; i++) ++ for (i = 0; i < nl + nd && grub_errno == GRUB_ERR_NONE; i++) + { + int n, code; + struct huff_table *ht; +@@ -721,17 +746,21 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + len = cplens[n]; + if (cplext[n]) + len += grub_png_get_bits (data, cplext[n]); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + n = grub_png_get_huff_code (data, &data->dist_table); + dist = cpdist[n]; + if (cpdext[n]) + dist += grub_png_get_bits (data, cpdext[n]); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + pos = data->wp - dist; + if (pos < 0) + pos += WSIZE; + +- while (len > 0) ++ while (len > 0 && grub_errno == GRUB_ERR_NONE) + { + data->slide[data->wp] = data->slide[pos]; + grub_png_output_byte (data, data->slide[data->wp]); +@@ -759,7 +788,11 @@ grub_png_decode_image_data (struct grub_png_data *data) + int final; + + cmf = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + flg = grub_png_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if ((cmf & 0xF) != Z_DEFLATED) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, +@@ -774,7 +807,11 @@ grub_png_decode_image_data (struct grub_png_data *data) + int block_type; + + final = grub_png_get_bits (data, 1); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + block_type = grub_png_get_bits (data, 2); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + switch (block_type) + { +@@ -790,7 +827,7 @@ grub_png_decode_image_data (struct grub_png_data *data) + grub_png_get_byte (data); + grub_png_get_byte (data); + +- for (i = 0; i < len; i++) ++ for (i = 0; i < len && grub_errno == GRUB_ERR_NONE; i++) + grub_png_output_byte (data, grub_png_get_byte (data)); + + break; +@@ -1045,6 +1082,8 @@ grub_png_decode_png (struct grub_png_data *data) + + len = grub_png_get_dword (data); + type = grub_png_get_dword (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ break; + data->next_offset = data->file->offset + len + 4; + + switch (type) diff --git a/0510-video-readers-png-Refuse-to-handle-multiple-image-he.patch b/0510-video-readers-png-Refuse-to-handle-multiple-image-he.patch new file mode 100644 index 0000000..f882341 --- /dev/null +++ b/0510-video-readers-png-Refuse-to-handle-multiple-image-he.patch @@ -0,0 +1,31 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 14:13:40 +1000 +Subject: [PATCH] video/readers/png: Refuse to handle multiple image headers + +This causes the bitmap to be leaked. Do not permit multiple image headers. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 8ce433557adeadbc46429aabb9f850b02ad2bdfb) +(cherry picked from commit 6e10bba6a4cbfd6c7bf116f41fd4e037465e19d8) +(cherry picked from commit 812272d919ecfd368c008f15b677d369616ada54) +(cherry picked from commit c04569b35600aa29d5b4cd8990a8ee1dd1162c72) +--- + grub-core/video/readers/png.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index e2a6b1cf3c..8955b8ecfd 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -258,6 +258,9 @@ grub_png_decode_image_header (struct grub_png_data *data) + int color_bits; + enum grub_video_blit_format blt; + ++ if (data->image_width || data->image_height) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "png: two image headers found"); ++ + data->image_width = grub_png_get_dword (data); + data->image_height = grub_png_get_dword (data); + diff --git a/0511-video-readers-png-Drop-greyscale-support-to-fix-heap.patch b/0511-video-readers-png-Drop-greyscale-support-to-fix-heap.patch new file mode 100644 index 0000000..ba88782 --- /dev/null +++ b/0511-video-readers-png-Drop-greyscale-support-to-fix-heap.patch @@ -0,0 +1,173 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 18:51:35 +1000 +Subject: [PATCH] video/readers/png: Drop greyscale support to fix heap + out-of-bounds write + +A 16-bit greyscale PNG without alpha is processed in the following loop: + + for (i = 0; i < (data->image_width * data->image_height); + i++, d1 += 4, d2 += 2) + { + d1[R3] = d2[1]; + d1[G3] = d2[1]; + d1[B3] = d2[1]; + } + +The increment of d1 is wrong. d1 is incremented by 4 bytes per iteration, +but there are only 3 bytes allocated for storage. This means that image +data will overwrite somewhat-attacker-controlled parts of memory - 3 bytes +out of every 4 following the end of the image. + +This has existed since greyscale support was added in 2013 in commit +3ccf16dff98f (grub-core/video/readers/png.c: Support grayscale). + +Saving starfield.png as a 16-bit greyscale image without alpha in the gimp +and attempting to load it causes grub-emu to crash - I don't think this code +has ever worked. + +Delete all PNG greyscale support. + +Fixes: CVE-2021-3695 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 0e1d163382669bd734439d8864ee969616d971d9) +[rharwood: context conflict] +Signed-off-by: Robbie Harwood +(cherry picked from commit 4c631c8119206b3178912df2905434d967661c3d) +(cherry picked from commit 6d5d5f51266b8113c6ba560835500e3c135f3722) +(cherry picked from commit b20fc5589561a8c57a2071b2ae93fcdcf51a10d4) +--- + grub-core/video/readers/png.c | 85 +++---------------------------------------- + 1 file changed, 6 insertions(+), 79 deletions(-) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index 8955b8ecfd..a3161e25b6 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -100,7 +100,7 @@ struct grub_png_data + + unsigned image_width, image_height; + int bpp, is_16bit; +- int raw_bytes, is_gray, is_alpha, is_palette; ++ int raw_bytes, is_alpha, is_palette; + int row_bytes, color_bits; + grub_uint8_t *image_data; + +@@ -296,13 +296,13 @@ grub_png_decode_image_header (struct grub_png_data *data) + data->bpp = 3; + else + { +- data->is_gray = 1; +- data->bpp = 1; ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: color type not supported"); + } + + if ((color_bits != 8) && (color_bits != 16) + && (color_bits != 4 +- || !(data->is_gray || data->is_palette))) ++ || !data->is_palette)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "png: bit depth must be 8 or 16"); + +@@ -331,7 +331,7 @@ grub_png_decode_image_header (struct grub_png_data *data) + } + + #ifndef GRUB_CPU_WORDS_BIGENDIAN +- if (data->is_16bit || data->is_gray || data->is_palette) ++ if (data->is_16bit || data->is_palette) + #endif + { + data->image_data = grub_calloc (data->image_height, data->row_bytes); +@@ -899,27 +899,8 @@ grub_png_convert_image (struct grub_png_data *data) + int shift; + int mask = (1 << data->color_bits) - 1; + unsigned j; +- if (data->is_gray) +- { +- /* Generic formula is +- (0xff * i) / ((1U << data->color_bits) - 1) +- but for allowed bit depth of 1, 2 and for it's +- equivalent to +- (0xff / ((1U << data->color_bits) - 1)) * i +- Precompute the multipliers to avoid division. +- */ + +- const grub_uint8_t multipliers[5] = { 0xff, 0xff, 0x55, 0x24, 0x11 }; +- for (i = 0; i < (1U << data->color_bits); i++) +- { +- grub_uint8_t col = multipliers[data->color_bits] * i; +- palette[i][0] = col; +- palette[i][1] = col; +- palette[i][2] = col; +- } +- } +- else +- grub_memcpy (palette, data->palette, 3 << data->color_bits); ++ grub_memcpy (palette, data->palette, 3 << data->color_bits); + d1c = d1; + d2c = d2; + for (j = 0; j < data->image_height; j++, d1c += data->image_width * 3, +@@ -956,60 +937,6 @@ grub_png_convert_image (struct grub_png_data *data) + } + return; + } +- +- if (data->is_gray) +- { +- switch (data->bpp) +- { +- case 4: +- /* 16-bit gray with alpha. */ +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 4) +- { +- d1[R4] = d2[3]; +- d1[G4] = d2[3]; +- d1[B4] = d2[3]; +- d1[A4] = d2[1]; +- } +- break; +- case 2: +- if (data->is_16bit) +- /* 16-bit gray without alpha. */ +- { +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 2) +- { +- d1[R3] = d2[1]; +- d1[G3] = d2[1]; +- d1[B3] = d2[1]; +- } +- } +- else +- /* 8-bit gray with alpha. */ +- { +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 4, d2 += 2) +- { +- d1[R4] = d2[1]; +- d1[G4] = d2[1]; +- d1[B4] = d2[1]; +- d1[A4] = d2[0]; +- } +- } +- break; +- /* 8-bit gray without alpha. */ +- case 1: +- for (i = 0; i < (data->image_width * data->image_height); +- i++, d1 += 3, d2++) +- { +- d1[R3] = d2[0]; +- d1[G3] = d2[0]; +- d1[B3] = d2[0]; +- } +- break; +- } +- return; +- } + + { + /* Only copy the upper 8 bit. */ diff --git a/0512-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch b/0512-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch new file mode 100644 index 0000000..a25685c --- /dev/null +++ b/0512-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 23:25:07 +1000 +Subject: [PATCH] video/readers/png: Avoid heap OOB R/W inserting huff table + items + +In fuzzing we observed crashes where a code would attempt to be inserted +into a huffman table before the start, leading to a set of heap OOB reads +and writes as table entries with negative indices were shifted around and +the new code written in. + +Catch the case where we would underflow the array and bail. + +Fixes: CVE-2021-3696 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 1ae9a91d42cb40da8a6f11fac65541858e340afa) +(cherry picked from commit 132ccc681cf642ad748580f26b54c9259a7f43fd) +(cherry picked from commit 3a70e1f6e69af6e0d3c3cf526faa44dc0c80ac19) +(cherry picked from commit 809d25ffa6b89d390a66d2f3cf3090196f07e2aa) +--- + grub-core/video/readers/png.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index a3161e25b6..d7ed5aa6cf 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -438,6 +438,13 @@ grub_png_insert_huff_item (struct huff_table *ht, int code, int len) + for (i = len; i < ht->max_length; i++) + n += ht->maxval[i]; + ++ if (n > ht->num_values) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: out of range inserting huffman table item"); ++ return; ++ } ++ + for (i = 0; i < n; i++) + ht->values[ht->num_values - i] = ht->values[ht->num_values - i - 1]; + diff --git a/0513-video-readers-png-Sanity-check-some-huffman-codes.patch b/0513-video-readers-png-Sanity-check-some-huffman-codes.patch new file mode 100644 index 0000000..4ba2e4d --- /dev/null +++ b/0513-video-readers-png-Sanity-check-some-huffman-codes.patch @@ -0,0 +1,43 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 6 Jul 2021 19:19:11 +1000 +Subject: [PATCH] video/readers/png: Sanity check some huffman codes + +ASAN picked up two OOB global reads: we weren't checking if some code +values fit within the cplens or cpdext arrays. Check and throw an error +if not. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit c3a8ab0cbd24153ec7b1f84a96ddfdd72ef8d117) +(cherry picked from commit 5d09addf58086aa11d5f9a91af5632ff87c2d2ee) +(cherry picked from commit ff12584f9376a472f37d4ec14213fd29bf3b233a) +(cherry picked from commit ac8b5464a076d2e38ecf7f761be9cd1f5bbeb784) +--- + grub-core/video/readers/png.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/grub-core/video/readers/png.c b/grub-core/video/readers/png.c +index d7ed5aa6cf..7f2ba7849b 100644 +--- a/grub-core/video/readers/png.c ++++ b/grub-core/video/readers/png.c +@@ -753,6 +753,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + int len, dist, pos; + + n -= 257; ++ if (((unsigned int) n) >= ARRAY_SIZE (cplens)) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: invalid huff code"); + len = cplens[n]; + if (cplext[n]) + len += grub_png_get_bits (data, cplext[n]); +@@ -760,6 +763,9 @@ grub_png_read_dynamic_block (struct grub_png_data *data) + return grub_errno; + + n = grub_png_get_huff_code (data, &data->dist_table); ++ if (((unsigned int) n) >= ARRAY_SIZE (cpdist)) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "png: invalid huff code"); + dist = cpdist[n]; + if (cpdext[n]) + dist += grub_png_get_bits (data, cpdext[n]); diff --git a/0514-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch b/0514-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch new file mode 100644 index 0000000..b5c2ca9 --- /dev/null +++ b/0514-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch @@ -0,0 +1,258 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Jun 2021 14:16:14 +1000 +Subject: [PATCH] video/readers/jpeg: Abort sooner if a read operation fails + +Fuzzing revealed some inputs that were taking a long time, potentially +forever, because they did not bail quickly upon encountering an I/O error. + +Try to catch I/O errors sooner and bail out. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit ab2e5d2e4bff488bbb557ed435a61ae102ef9f0c) +(cherry picked from commit 1ff8df0d2dea8ec7c8575241d5e7d6622c204ec3) +(cherry picked from commit b07767383b74a0ce7135c09ba8701510d4ad32f0) +(cherry picked from commit 5f097165152d61d4aea02f26dc789d840147d50e) +--- + grub-core/video/readers/jpeg.c | 86 ++++++++++++++++++++++++++++++++++-------- + 1 file changed, 70 insertions(+), 16 deletions(-) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index e31602f766..10225abd53 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -109,9 +109,17 @@ static grub_uint8_t + grub_jpeg_get_byte (struct grub_jpeg_data *data) + { + grub_uint8_t r; ++ grub_ssize_t bytes_read; + + r = 0; +- grub_file_read (data->file, &r, 1); ++ bytes_read = grub_file_read (data->file, &r, 1); ++ ++ if (bytes_read != 1) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: unexpected end of data"); ++ return 0; ++ } + + return r; + } +@@ -120,9 +128,17 @@ static grub_uint16_t + grub_jpeg_get_word (struct grub_jpeg_data *data) + { + grub_uint16_t r; ++ grub_ssize_t bytes_read; + + r = 0; +- grub_file_read (data->file, &r, sizeof (grub_uint16_t)); ++ bytes_read = grub_file_read (data->file, &r, sizeof (grub_uint16_t)); ++ ++ if (bytes_read != sizeof (grub_uint16_t)) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: unexpected end of data"); ++ return 0; ++ } + + return grub_be_to_cpu16 (r); + } +@@ -135,6 +151,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data) + if (data->bit_mask == 0) + { + data->bit_save = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: file read error"); ++ return 0; ++ } + if (data->bit_save == JPEG_ESC_CHAR) + { + if (grub_jpeg_get_byte (data) != 0) +@@ -143,6 +164,11 @@ grub_jpeg_get_bit (struct grub_jpeg_data *data) + "jpeg: invalid 0xFF in data stream"); + return 0; + } ++ if (grub_errno != GRUB_ERR_NONE) ++ { ++ grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: file read error"); ++ return 0; ++ } + } + data->bit_mask = 0x80; + } +@@ -161,7 +187,7 @@ grub_jpeg_get_number (struct grub_jpeg_data *data, int num) + return 0; + + msb = value = grub_jpeg_get_bit (data); +- for (i = 1; i < num; i++) ++ for (i = 1; i < num && grub_errno == GRUB_ERR_NONE; i++) + value = (value << 1) + (grub_jpeg_get_bit (data) != 0); + if (!msb) + value += 1 - (1 << num); +@@ -202,6 +228,8 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) + while (data->file->offset + sizeof (count) + 1 <= next_marker) + { + id = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + ac = (id >> 4) & 1; + id &= 0xF; + if (id > 1) +@@ -252,6 +280,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) + + next_marker = data->file->offset; + next_marker += grub_jpeg_get_word (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + + if (next_marker > data->file->size) + { +@@ -263,6 +293,8 @@ grub_jpeg_decode_quan_table (struct grub_jpeg_data *data) + <= next_marker) + { + id = grub_jpeg_get_byte (data); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (id >= 0x10) /* Upper 4-bit is precision. */ + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only 8-bit precision is supported"); +@@ -294,6 +326,9 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) + next_marker = data->file->offset; + next_marker += grub_jpeg_get_word (data); + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + if (grub_jpeg_get_byte (data) != 8) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: only 8-bit precision is supported"); +@@ -319,6 +354,8 @@ grub_jpeg_decode_sof (struct grub_jpeg_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); + + ss = grub_jpeg_get_byte (data); /* Sampling factor. */ ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (!id) + { + grub_uint8_t vs, hs; +@@ -498,7 +535,7 @@ grub_jpeg_idct_transform (jpeg_data_unit_t du) + } + } + +-static void ++static grub_err_t + grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + { + int h1, h2, qt; +@@ -513,6 +550,9 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + data->dc_value[id] += + grub_jpeg_get_number (data, grub_jpeg_get_huff_code (data, h1)); + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + du[0] = data->dc_value[id] * (int) data->quan_table[qt][0]; + pos = 1; + while (pos < ARRAY_SIZE (data->quan_table[qt])) +@@ -527,11 +567,13 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + num >>= 4; + pos += num; + ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; ++ + if (pos >= ARRAY_SIZE (jpeg_zigzag_order)) + { +- grub_error (GRUB_ERR_BAD_FILE_TYPE, +- "jpeg: invalid position in zigzag order!?"); +- return; ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: invalid position in zigzag order!?"); + } + + du[jpeg_zigzag_order[pos]] = val * (int) data->quan_table[qt][pos]; +@@ -539,6 +581,7 @@ grub_jpeg_decode_du (struct grub_jpeg_data *data, int id, jpeg_data_unit_t du) + } + + grub_jpeg_idct_transform (du); ++ return GRUB_ERR_NONE; + } + + static void +@@ -597,7 +640,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + data_offset += grub_jpeg_get_word (data); + + cc = grub_jpeg_get_byte (data); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (cc != 3 && cc != 1) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: component count must be 1 or 3"); +@@ -610,7 +654,8 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + id = grub_jpeg_get_byte (data) - 1; + if ((id < 0) || (id >= 3)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid index"); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + ht = grub_jpeg_get_byte (data); + data->comp_index[id][1] = (ht >> 4); + data->comp_index[id][2] = (ht & 0xF) + 2; +@@ -618,11 +663,14 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + if ((data->comp_index[id][1] < 0) || (data->comp_index[id][1] > 3) || + (data->comp_index[id][2] < 0) || (data->comp_index[id][2] > 3)) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: invalid hufftable index"); ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + } + + grub_jpeg_get_byte (data); /* Skip 3 unused bytes. */ + grub_jpeg_get_word (data); +- ++ if (grub_errno != GRUB_ERR_NONE) ++ return grub_errno; + if (data->file->offset != data_offset) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); + +@@ -640,6 +688,7 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + { + unsigned c1, vb, hb, nr1, nc1; + int rst = data->dri; ++ grub_err_t err = GRUB_ERR_NONE; + + vb = 8 << data->log_vs; + hb = 8 << data->log_hs; +@@ -660,17 +709,22 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + + for (r2 = 0; r2 < (1U << data->log_vs); r2++) + for (c2 = 0; c2 < (1U << data->log_hs); c2++) +- grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); ++ { ++ err = grub_jpeg_decode_du (data, 0, data->ydu[r2 * 2 + c2]); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ } + + if (data->color_components >= 3) + { +- grub_jpeg_decode_du (data, 1, data->cbdu); +- grub_jpeg_decode_du (data, 2, data->crdu); ++ err = grub_jpeg_decode_du (data, 1, data->cbdu); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ err = grub_jpeg_decode_du (data, 2, data->crdu); ++ if (err != GRUB_ERR_NONE) ++ return err; + } + +- if (grub_errno) +- return grub_errno; +- + nr2 = (data->r1 == nr1 - 1) ? (data->image_height - data->r1 * vb) : vb; + nc2 = (c1 == nc1 - 1) ? (data->image_width - c1 * hb) : hb; + diff --git a/0515-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch b/0515-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch new file mode 100644 index 0000000..7677c8d --- /dev/null +++ b/0515-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Jun 2021 14:16:58 +1000 +Subject: [PATCH] video/readers/jpeg: Do not reallocate a given huff table + +Fix a memory leak where an invalid file could cause us to reallocate +memory for a huffman table we had already allocated memory for. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit bc06e12b4de55cc6f926af9f064170c82b1403e9) +(cherry picked from commit 5298bf758ea39a90537f9a1c76541ff2f21b970b) +(cherry picked from commit aae6bac7f26c6b848156ed7adcff83309b833664) +(cherry picked from commit bc58c0da3aed59486042759a03fe61a9782e36ce) +--- + grub-core/video/readers/jpeg.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 10225abd53..caa211f06d 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -245,6 +245,9 @@ grub_jpeg_decode_huff_table (struct grub_jpeg_data *data) + n += count[i]; + + id += ac * 2; ++ if (data->huff_value[id] != NULL) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: attempt to reallocate huffman table"); + data->huff_value[id] = grub_malloc (n); + if (grub_errno) + return grub_errno; diff --git a/0516-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch b/0516-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch new file mode 100644 index 0000000..bc4ef25 --- /dev/null +++ b/0516-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 28 Jun 2021 14:25:17 +1000 +Subject: [PATCH] video/readers/jpeg: Refuse to handle multiple start of + streams + +An invalid file could contain multiple start of stream blocks, which +would cause us to reallocate and leak our bitmap. Refuse to handle +multiple start of streams. + +Additionally, fix a grub_error() call formatting. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit f3a854def3e281b7ad4bbea730cd3046de1da52f) +(cherry picked from commit db0154828989a0a52ee59a4dda8c3803752bc827) +(cherry picked from commit 75afb375ef46bc99a7faf5879d0283934e34db97) +(cherry picked from commit 82f8de94e19be775cdabd05528dc7acf0cb485a7) +--- + grub-core/video/readers/jpeg.c | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index caa211f06d..1df1171d78 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -677,6 +677,9 @@ grub_jpeg_decode_sos (struct grub_jpeg_data *data) + if (data->file->offset != data_offset) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: extra byte in sos"); + ++ if (*data->bitmap) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "jpeg: too many start of scan blocks"); ++ + if (grub_video_bitmap_create (data->bitmap, data->image_width, + data->image_height, + GRUB_VIDEO_BLIT_FORMAT_RGB_888)) +@@ -699,8 +702,8 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + nc1 = (data->image_width + hb - 1) >> (3 + data->log_hs); + + if (data->bitmap_ptr == NULL) +- return grub_error(GRUB_ERR_BAD_FILE_TYPE, +- "jpeg: attempted to decode data before start of stream"); ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: attempted to decode data before start of stream"); + + for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) diff --git a/0517-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch b/0517-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch new file mode 100644 index 0000000..9434ba1 --- /dev/null +++ b/0517-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch @@ -0,0 +1,56 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Wed, 7 Jul 2021 15:38:19 +1000 +Subject: [PATCH] video/readers/jpeg: Block int underflow -> wild pointer write + +Certain 1 px wide images caused a wild pointer write in +grub_jpeg_ycrcb_to_rgb(). This was caused because in grub_jpeg_decode_data(), +we have the following loop: + +for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) + +We did not check if vb * width >= hb * nc1. + +On a 64-bit platform, if that turns out to be negative, it will underflow, +be interpreted as unsigned 64-bit, then be added to the 64-bit pointer, so +we see data->bitmap_ptr jump, e.g.: + +0x6180_0000_0480 to +0x6181_0000_0498 + ^ + ~--- carry has occurred and this pointer is now far away from + any object. + +On a 32-bit platform, it will decrement the pointer, creating a pointer +that won't crash but will overwrite random data. + +Catch the underflow and error out. + +Fixes: CVE-2021-3697 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 41aeb2004db9924fecd9f2dd64bc2a5a5594a4b5) +(cherry picked from commit 5f9582490792108306d047379fed2371bee286f8) +(cherry picked from commit 7e4bf25d9bb5219fbf11c523296dc3bd78b80698) +(cherry picked from commit 397ecffe404b892470c41f4d24340526d3d33666) +--- + grub-core/video/readers/jpeg.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/grub-core/video/readers/jpeg.c b/grub-core/video/readers/jpeg.c +index 1df1171d78..2da04094b3 100644 +--- a/grub-core/video/readers/jpeg.c ++++ b/grub-core/video/readers/jpeg.c +@@ -705,6 +705,10 @@ grub_jpeg_decode_data (struct grub_jpeg_data *data) + return grub_error (GRUB_ERR_BAD_FILE_TYPE, + "jpeg: attempted to decode data before start of stream"); + ++ if (vb * data->image_width <= hb * nc1) ++ return grub_error (GRUB_ERR_BAD_FILE_TYPE, ++ "jpeg: cannot decode image with these dimensions"); ++ + for (; data->r1 < nr1 && (!data->dri || rst); + data->r1++, data->bitmap_ptr += (vb * data->image_width - hb * nc1) * 3) + for (c1 = 0; c1 < nc1 && (!data->dri || rst); diff --git a/0518-normal-charset-Fix-array-out-of-bounds-formatting-un.patch b/0518-normal-charset-Fix-array-out-of-bounds-formatting-un.patch new file mode 100644 index 0000000..2043b05 --- /dev/null +++ b/0518-normal-charset-Fix-array-out-of-bounds-formatting-un.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 13 Jul 2021 13:24:38 +1000 +Subject: [PATCH] normal/charset: Fix array out-of-bounds formatting unicode + for display + +In some cases attempting to display arbitrary binary strings leads +to ASAN splats reading the widthspec array out of bounds. + +Check the index. If it would be out of bounds, return a width of 1. +I don't know if that's strictly correct, but we're not really expecting +great display of arbitrary binary data, and it's certainly not worse than +an OOB read. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit fdf32abc7a3928852422c0f291d8cd1dd6b34a8d) +(cherry picked from commit f2c10aaf335b88a69885375c4d68ffab2429df77) +(cherry picked from commit 4c942e1ba8d1f1199a58d2eb139022ae22f75cb2) +(cherry picked from commit 83efea59ad671d043b3a48fe0581f11beb63303c) +--- + grub-core/normal/charset.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/grub-core/normal/charset.c b/grub-core/normal/charset.c +index f902b13b44..7b2de12001 100644 +--- a/grub-core/normal/charset.c ++++ b/grub-core/normal/charset.c +@@ -395,6 +395,8 @@ grub_unicode_estimate_width (const struct grub_unicode_glyph *c) + { + if (grub_unicode_get_comb_type (c->base)) + return 0; ++ if (((unsigned long) (c->base >> 3)) >= ARRAY_SIZE (widthspec)) ++ return 1; + if (widthspec[c->base >> 3] & (1 << (c->base & 7))) + return 2; + else diff --git a/0519-net-netbuff-Block-overly-large-netbuff-allocs.patch b/0519-net-netbuff-Block-overly-large-netbuff-allocs.patch new file mode 100644 index 0000000..6d590ee --- /dev/null +++ b/0519-net-netbuff-Block-overly-large-netbuff-allocs.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 8 Mar 2022 23:47:46 +1100 +Subject: [PATCH] net/netbuff: Block overly large netbuff allocs + +A netbuff shouldn't be too huge. It's bounded by MTU and TCP segment +reassembly. + +This helps avoid some bugs (and provides a spot to instrument to catch +them at their source). + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit ee9591103004cd13b4efadda671536090ca7fd57) +(cherry picked from commit acde668bb9d9fa862a1a63e3bbd5fa47fdfa9183) +(cherry picked from commit e47ad2eb4fe38ef2bdcab52245286f31170e73e3) +(cherry picked from commit 3517b6baf69ee77065f0216ff29190ad392a2c84) +--- + grub-core/net/netbuff.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/grub-core/net/netbuff.c b/grub-core/net/netbuff.c +index dbeeefe478..d5e9e9a0d7 100644 +--- a/grub-core/net/netbuff.c ++++ b/grub-core/net/netbuff.c +@@ -79,10 +79,23 @@ grub_netbuff_alloc (grub_size_t len) + + COMPILE_TIME_ASSERT (NETBUFF_ALIGN % sizeof (grub_properly_aligned_t) == 0); + ++ /* ++ * The largest size of a TCP packet is 64 KiB, and everything else ++ * should be a lot smaller - most MTUs are 1500 or less. Cap data ++ * size at 64 KiB + a buffer. ++ */ ++ if (len > 0xffffUL + 0x1000UL) ++ { ++ grub_error (GRUB_ERR_BUG, ++ "attempted to allocate a packet that is too big"); ++ return NULL; ++ } ++ + if (len < NETBUFFMINLEN) + len = NETBUFFMINLEN; + + len = ALIGN_UP (len, NETBUFF_ALIGN); ++ + #ifdef GRUB_MACHINE_EMU + data = grub_malloc (len + sizeof (*nb)); + #else diff --git a/0520-net-ip-Do-IP-fragment-maths-safely.patch b/0520-net-ip-Do-IP-fragment-maths-safely.patch new file mode 100644 index 0000000..433d703 --- /dev/null +++ b/0520-net-ip-Do-IP-fragment-maths-safely.patch @@ -0,0 +1,47 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 20 Dec 2021 19:41:21 +1100 +Subject: [PATCH] net/ip: Do IP fragment maths safely + +This avoids an underflow and subsequent unpleasantness. + +Fixes: CVE-2022-28733 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit eb74e5743ca7e18a5e75c392fe0b21d1549a1936) +(cherry picked from commit 552ad34583e788542e9ca08524a0d4bc8f98c297) +(cherry picked from commit 2c8cb7e3b8b48b136a950e5692fa6251b76df90e) +(cherry picked from commit 17bb2fe79e6b9688cf2008b840af9022804204ec) +--- + grub-core/net/ip.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/grub-core/net/ip.c b/grub-core/net/ip.c +index 9a4e589aa3..c766ac65f5 100644 +--- a/grub-core/net/ip.c ++++ b/grub-core/net/ip.c +@@ -25,6 +25,7 @@ + #include + #include + #include ++#include + #include + + struct iphdr { +@@ -552,7 +553,14 @@ grub_net_recv_ip4_packets (struct grub_net_buff *nb, + { + rsm->total_len = (8 * (grub_be_to_cpu16 (iph->frags) & OFFSET_MASK) + + (nb->tail - nb->data)); +- rsm->total_len -= ((iph->verhdrlen & 0xf) * sizeof (grub_uint32_t)); ++ ++ if (grub_sub (rsm->total_len, (iph->verhdrlen & 0xf) * sizeof (grub_uint32_t), ++ &rsm->total_len)) ++ { ++ grub_dprintf ("net", "IP reassembly size underflow\n"); ++ return GRUB_ERR_NONE; ++ } ++ + rsm->asm_netbuff = grub_netbuff_alloc (rsm->total_len); + if (!rsm->asm_netbuff) + { diff --git a/0521-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch b/0521-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch new file mode 100644 index 0000000..1fa2c3e --- /dev/null +++ b/0521-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Thu, 16 Sep 2021 01:29:54 +1000 +Subject: [PATCH] net/dns: Fix double-free addresses on corrupt DNS response + +grub_net_dns_lookup() takes as inputs a pointer to an array of addresses +("addresses") for the given name, and pointer to a number of addresses +("naddresses"). grub_net_dns_lookup() is responsible for allocating +"addresses", and the caller is responsible for freeing it if +"naddresses" > 0. + +The DNS recv_hook will sometimes set and free the addresses array, +for example if the packet is too short: + + if (ptr + 10 >= nb->tail) + { + if (!*data->naddresses) + grub_free (*data->addresses); + grub_netbuff_free (nb); + return GRUB_ERR_NONE; + } + +Later on the nslookup command code unconditionally frees the "addresses" +array. Normally this is fine: the array is either populated with valid +data or is NULL. But in these sorts of error cases it is neither NULL +nor valid and we get a double-free. + +Only free "addresses" if "naddresses" > 0. + +It looks like the other use of grub_net_dns_lookup() is not affected. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit eb2e69fcf51307757e43f55ee8c9354d1ee42dd1) +(cherry picked from commit d801a27e7acec6c1a83067fab0bb975877eaf704) +(cherry picked from commit 4d8b6e36ddfda4084e370b3b08c432e8a462e9be) +(cherry picked from commit ae133c18f304cb0a22c569c98abc62e15ccf56d0) +--- + grub-core/net/dns.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c +index 906ec7d678..135faac035 100644 +--- a/grub-core/net/dns.c ++++ b/grub-core/net/dns.c +@@ -667,9 +667,11 @@ grub_cmd_nslookup (struct grub_command *cmd __attribute__ ((unused)), + grub_net_addr_to_str (&addresses[i], buf); + grub_printf ("%s\n", buf); + } +- grub_free (addresses); + if (naddresses) +- return GRUB_ERR_NONE; ++ { ++ grub_free (addresses); ++ return GRUB_ERR_NONE; ++ } + return grub_error (GRUB_ERR_NET_NO_DOMAIN, N_("no DNS record found")); + } + diff --git a/0522-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch b/0522-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch new file mode 100644 index 0000000..bd7797a --- /dev/null +++ b/0522-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch @@ -0,0 +1,74 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 20 Dec 2021 21:55:43 +1100 +Subject: [PATCH] net/dns: Don't read past the end of the string we're checking + against + +I don't really understand what's going on here but fuzzing found +a bug where we read past the end of check_with. That's a C string, +so use grub_strlen() to make sure we don't overread it. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 6a97b3f4b1d5173aa516edc6dedbc63de7306d21) +(cherry picked from commit e0589624e86bc96666cbdb62f6e55cafec2871b3) +(cherry picked from commit 95ecbc0b9aacfd43ba96cccc50daaf39eccd9f7f) +(cherry picked from commit 110eee925ecd9efeebb8d018b042fcf067a443c2) +--- + grub-core/net/dns.c | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/grub-core/net/dns.c b/grub-core/net/dns.c +index 135faac035..17961a9f18 100644 +--- a/grub-core/net/dns.c ++++ b/grub-core/net/dns.c +@@ -146,11 +146,18 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + int *length, char *set) + { + const char *readable_ptr = check_with; ++ int readable_len; + const grub_uint8_t *ptr; + char *optr = set; + int bytes_processed = 0; + if (length) + *length = 0; ++ ++ if (readable_ptr != NULL) ++ readable_len = grub_strlen (readable_ptr); ++ else ++ readable_len = 0; ++ + for (ptr = name_at; ptr < tail && bytes_processed < tail - head + 2; ) + { + /* End marker. */ +@@ -172,13 +179,16 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + ptr = head + (((ptr[0] & 0x3f) << 8) | ptr[1]); + continue; + } +- if (readable_ptr && grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0) ++ if (readable_ptr != NULL && (*ptr > readable_len || grub_memcmp (ptr + 1, readable_ptr, *ptr) != 0)) + return 0; + if (grub_memchr (ptr + 1, 0, *ptr) + || grub_memchr (ptr + 1, '.', *ptr)) + return 0; + if (readable_ptr) +- readable_ptr += *ptr; ++ { ++ readable_ptr += *ptr; ++ readable_len -= *ptr; ++ } + if (readable_ptr && *readable_ptr != '.' && *readable_ptr != 0) + return 0; + bytes_processed += *ptr + 1; +@@ -192,7 +202,10 @@ check_name_real (const grub_uint8_t *name_at, const grub_uint8_t *head, + if (optr) + *optr++ = '.'; + if (readable_ptr && *readable_ptr) +- readable_ptr++; ++ { ++ readable_ptr++; ++ readable_len--; ++ } + ptr += *ptr + 1; + } + return 0; diff --git a/0523-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch b/0523-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch new file mode 100644 index 0000000..6df1527 --- /dev/null +++ b/0523-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch @@ -0,0 +1,115 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Mon, 20 Sep 2021 01:12:24 +1000 +Subject: [PATCH] net/tftp: Prevent a UAF and double-free from a failed seek + +A malicious tftp server can cause UAFs and a double free. + +An attempt to read from a network file is handled by grub_net_fs_read(). If +the read is at an offset other than the current offset, grub_net_seek_real() +is invoked. + +In grub_net_seek_real(), if a backwards seek cannot be satisfied from the +currently received packets, and the underlying transport does not provide +a seek method, then grub_net_seek_real() will close and reopen the network +protocol layer. + +For tftp, the ->close() call goes to tftp_close() and frees the tftp_data_t +file->data. The file->data pointer is not nulled out after the free. + +If the ->open() call fails, the file->data will not be reallocated and will +continue point to a freed memory block. This could happen from a server +refusing to send the requisite ack to the new tftp request, for example. + +The seek and the read will then fail, but the grub_file continues to exist: +the failed seek does not necessarily cause the entire file to be thrown +away (e.g. where the file is checked to see if it is gzipped/lzio/xz/etc., +a read failure is interpreted as a decompressor passing on the file, not as +an invalidation of the entire grub_file_t structure). + +This means subsequent attempts to read or seek the file will use the old +file->data after free. Eventually, the file will be close()d again and +file->data will be freed again. + +Mark a net_fs file that doesn't reopen as broken. Do not permit read() or +close() on a broken file (seek is not exposed directly to the file API - +it is only called as part of read, so this blocks seeks as well). + +As an additional defence, null out the ->data pointer if tftp_open() fails. +That would have lead to a simple null pointer dereference rather than +a mess of UAFs. + +This may affect other protocols, I haven't checked. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit dada1dda695439bb55b2848dddc2d89843552f81) +(cherry picked from commit 352c5ae8a9fc715712e6ecbd7ccb6218122c748f) +(cherry picked from commit 61a010085ab9f0ecf42677773a6fc212f1579b0a) +(cherry picked from commit 277d38531a47be78ac5062894e449726db2baf65) +--- + grub-core/net/net.c | 11 +++++++++-- + grub-core/net/tftp.c | 1 + + include/grub/net.h | 1 + + 3 files changed, 11 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/net.c b/grub-core/net/net.c +index a27c53eee1..b9e2a4d100 100644 +--- a/grub-core/net/net.c ++++ b/grub-core/net/net.c +@@ -1625,7 +1625,8 @@ grub_net_fs_close (grub_file_t file) + grub_netbuff_free (file->device->net->packs.first->nb); + grub_net_remove_packet (file->device->net->packs.first); + } +- file->device->net->protocol->close (file); ++ if (!file->device->net->broken) ++ file->device->net->protocol->close (file); + grub_free (file->device->net->name); + return GRUB_ERR_NONE; + } +@@ -1847,7 +1848,10 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset) + file->device->net->stall = 0; + err = file->device->net->protocol->open (file, file->device->net->name); + if (err) +- return err; ++ { ++ file->device->net->broken = 1; ++ return err; ++ } + grub_net_fs_read_real (file, NULL, offset); + return grub_errno; + } +@@ -1856,6 +1860,9 @@ grub_net_seek_real (struct grub_file *file, grub_off_t offset) + static grub_ssize_t + grub_net_fs_read (grub_file_t file, char *buf, grub_size_t len) + { ++ if (file->device->net->broken) ++ return -1; ++ + if (file->offset != file->device->net->offset) + { + grub_err_t err; +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index aa0424dcee..85be965470 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -402,6 +402,7 @@ tftp_open (struct grub_file *file, const char *filename) + { + grub_net_udp_close (data->sock); + grub_free (data); ++ file->data = NULL; + return grub_errno; + } + +diff --git a/include/grub/net.h b/include/grub/net.h +index 9cf6da6897..0d31f00664 100644 +--- a/include/grub/net.h ++++ b/include/grub/net.h +@@ -280,6 +280,7 @@ typedef struct grub_net + grub_fs_t fs; + int eof; + int stall; ++ int broken; + } *grub_net_t; + + extern grub_net_t (*EXPORT_VAR (grub_net_open)) (const char *name); diff --git a/0524-misc-Format-string-for-grub_error-should-be-a-litera.patch b/0524-misc-Format-string-for-grub_error-should-be-a-litera.patch new file mode 100644 index 0000000..f4a4f32 --- /dev/null +++ b/0524-misc-Format-string-for-grub_error-should-be-a-litera.patch @@ -0,0 +1,54 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Glenn Washburn +Date: Thu, 4 Mar 2021 18:22:32 -0600 +Subject: [PATCH] misc: Format string for grub_error() should be a literal + +Signed-off-by: Glenn Washburn +Reviewed-by: Daniel Kiper +(cherry-picked from commit 60875f4e15d704b875969b415501802b531c4db3) +(cherry-picked from commit 6353cbd63cb3615a2b7aece183e3b177250d9415) +--- + grub-core/loader/efi/chainloader.c | 2 +- + grub-core/net/tftp.c | 2 +- + grub-core/script/lexer.c | 2 +- + 3 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 720f6181e5..8e658f713e 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -79,7 +79,7 @@ grub_start_image (grub_efi_handle_t handle) + *grub_utf16_to_utf8 ((grub_uint8_t *) buf, + exit_data, exit_data_size) = 0; + +- grub_error (GRUB_ERR_BAD_OS, buf); ++ grub_error (GRUB_ERR_BAD_OS, "%s", buf); + grub_free (buf); + } + } +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index 85be965470..69a9ba6979 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -253,7 +253,7 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)), + case TFTP_ERROR: + data->have_oack = 1; + grub_netbuff_free (nb); +- grub_error (GRUB_ERR_IO, (char *) tftph->u.err.errmsg); ++ grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg); + grub_error_save (&data->save_err); + return GRUB_ERR_NONE; + default: +diff --git a/grub-core/script/lexer.c b/grub-core/script/lexer.c +index 5fb0cbd0bc..27daad791c 100644 +--- a/grub-core/script/lexer.c ++++ b/grub-core/script/lexer.c +@@ -349,7 +349,7 @@ void + grub_script_yyerror (struct grub_parser_param *state, char const *err) + { + if (err) +- grub_error (GRUB_ERR_INVALID_COMMAND, err); ++ grub_error (GRUB_ERR_INVALID_COMMAND, "%s", err); + + grub_print_error (); + state->err++; diff --git a/0525-net-tftp-Avoid-a-trivial-UAF.patch b/0525-net-tftp-Avoid-a-trivial-UAF.patch new file mode 100644 index 0000000..8c44b1f --- /dev/null +++ b/0525-net-tftp-Avoid-a-trivial-UAF.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 18 Jan 2022 14:29:20 +1100 +Subject: [PATCH] net/tftp: Avoid a trivial UAF + +Under tftp errors, we print a tftp error message from the tftp header. +However, the tftph pointer is a pointer inside nb, the netbuff. Previously, +we were freeing the nb and then dereferencing it. Don't do that, use it +and then free it later. + +This isn't really _bad_ per se, especially as we're single-threaded, but +it trips up fuzzers. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 956f4329cec23e4375182030ca9b2be631a61ba5) +(cherry picked from commit dbe9abcdee6ce796811111b67e3f24eefe2135d1) +(cherry picked from commit 72ae9c5d389d2c0337c44edead6e00db0bb84039) +(cherry picked from commit 6a367d5b45cee3b452319cbaba1052f045c68081) +--- + grub-core/net/tftp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/grub-core/net/tftp.c b/grub-core/net/tftp.c +index 69a9ba6979..09e1511ccf 100644 +--- a/grub-core/net/tftp.c ++++ b/grub-core/net/tftp.c +@@ -252,9 +252,9 @@ tftp_receive (grub_net_udp_socket_t sock __attribute__ ((unused)), + return GRUB_ERR_NONE; + case TFTP_ERROR: + data->have_oack = 1; +- grub_netbuff_free (nb); + grub_error (GRUB_ERR_IO, "%s", tftph->u.err.errmsg); + grub_error_save (&data->save_err); ++ grub_netbuff_free (nb); + return GRUB_ERR_NONE; + default: + grub_netbuff_free (nb); diff --git a/0526-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch b/0526-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch new file mode 100644 index 0000000..75082a8 --- /dev/null +++ b/0526-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch @@ -0,0 +1,45 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 1 Mar 2022 23:14:15 +1100 +Subject: [PATCH] net/http: Do not tear down socket if it's already been torn + down + +It's possible for data->sock to get torn down in tcp error handling. +If we unconditionally tear it down again we will end up doing writes +to an offset of the NULL pointer when we go to tear it down again. + +Detect if it has been torn down and don't do it again. + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit ec233d3ecf995293304de443579aab5c46c49e85) +(cherry picked from commit d39cf87ed701b9f0900daed7f672e07994d37ce8) +(cherry picked from commit e0aa5c3acec70eac3489d6df1893a93726cbce3a) +(cherry picked from commit d29000397693cae279291b75ff89e5b9a5e2ed97) +--- + grub-core/net/http.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index b52b558d63..5223ca57a4 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -427,7 +427,7 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + return err; + } + +- for (i = 0; !data->headers_recv && i < 100; i++) ++ for (i = 0; data->sock && !data->headers_recv && i < 100; i++) + { + grub_net_tcp_retransmit (); + grub_net_poll_cards (300, &data->headers_recv); +@@ -435,7 +435,8 @@ http_establish (struct grub_file *file, grub_off_t offset, int initial) + + if (!data->headers_recv) + { +- grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); ++ if (data->sock) ++ grub_net_tcp_close (data->sock, GRUB_NET_TCP_ABORT); + if (data->err) + { + char *str = data->errmsg; diff --git a/0527-net-http-Fix-OOB-write-for-split-http-headers.patch b/0527-net-http-Fix-OOB-write-for-split-http-headers.patch new file mode 100644 index 0000000..eea35d6 --- /dev/null +++ b/0527-net-http-Fix-OOB-write-for-split-http-headers.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 8 Mar 2022 18:17:03 +1100 +Subject: [PATCH] net/http: Fix OOB write for split http headers + +GRUB has special code for handling an http header that is split +across two packets. + +The code tracks the end of line by looking for a "\n" byte. The +code for split headers has always advanced the pointer just past the +end of the line, whereas the code that handles unsplit headers does +not advance the pointer. This extra advance causes the length to be +one greater, which breaks an assumption in parse_line(), leading to +it writing a NUL byte one byte past the end of the buffer where we +reconstruct the line from the two packets. + +It's conceivable that an attacker controlled set of packets could +cause this to zero out the first byte of the "next" pointer of the +grub_mm_region structure following the current_line buffer. + +Do not advance the pointer in the split header case. + +Fixes: CVE-2022-28734 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit e9fb459638811c12b0989dbf64e3e124974ef617) +(cherry picked from commit b604916beb6c39e8ed27f72851eb16f3eaa293c5) +(cherry picked from commit c3c6b1167a43275991efd6847160a46ce3839fae) +(cherry picked from commit 9b4ef71ed4f6fce00e868e3223cdbfb734e840d6) +--- + grub-core/net/http.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index 5223ca57a4..7fa2dcaea7 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -193,9 +193,7 @@ http_receive (grub_net_tcp_socket_t sock __attribute__ ((unused)), + int have_line = 1; + char *t; + ptr = grub_memchr (nb->data, '\n', nb->tail - nb->data); +- if (ptr) +- ptr++; +- else ++ if (ptr == NULL) + { + have_line = 0; + ptr = (char *) nb->tail; diff --git a/0528-net-http-Error-out-on-headers-with-LF-without-CR.patch b/0528-net-http-Error-out-on-headers-with-LF-without-CR.patch new file mode 100644 index 0000000..a50904e --- /dev/null +++ b/0528-net-http-Error-out-on-headers-with-LF-without-CR.patch @@ -0,0 +1,51 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Axtens +Date: Tue, 8 Mar 2022 19:04:40 +1100 +Subject: [PATCH] net/http: Error out on headers with LF without CR + +In a similar vein to the previous patch, parse_line() would write +a NUL byte past the end of the buffer if there was an HTTP header +with a LF rather than a CRLF. + +RFC-2616 says: + + Many HTTP/1.1 header field values consist of words separated by LWS + or special characters. These special characters MUST be in a quoted + string to be used within a parameter value (as defined in section 3.6). + +We don't support quoted sections or continuation lines, etc. + +If we see an LF that's not part of a CRLF, bail out. + +Fixes: CVE-2022-28734 + +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit d232ad41ac4979a9de4d746e5fdff9caf0e303de) +(cherry picked from commit 8960e6d6137090a7e8c6592077da6e387a4ef972) +(cherry picked from commit 9b6b9398c90dd76ce0b935d21c4ecb8954c4b2b7) +(cherry picked from commit 3eef2cc845f7ed34a89d8d0a7042d7768e43eaad) +--- + grub-core/net/http.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/grub-core/net/http.c b/grub-core/net/http.c +index 7fa2dcaea7..745f429b51 100644 +--- a/grub-core/net/http.c ++++ b/grub-core/net/http.c +@@ -69,7 +69,15 @@ parse_line (grub_file_t file, http_data_t data, char *ptr, grub_size_t len) + char *end = ptr + len; + while (end > ptr && *(end - 1) == '\r') + end--; ++ ++ /* LF without CR. */ ++ if (end == ptr + len) ++ { ++ data->errmsg = grub_strdup (_("invalid HTTP header - LF without CR")); ++ return GRUB_ERR_NONE; ++ } + *end = 0; ++ + /* Trailing CRLF. */ + if (data->in_chunk_len == 1) + { diff --git a/0529-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch b/0529-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch new file mode 100644 index 0000000..93637a4 --- /dev/null +++ b/0529-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch @@ -0,0 +1,75 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Wed, 6 Apr 2022 18:03:37 +0530 +Subject: [PATCH] fs/f2fs: Do not read past the end of nat journal entries + +A corrupt f2fs file system could specify a nat journal entry count +that is beyond the maximum NAT_JOURNAL_ENTRIES. + +Check if the specified nat journal entry count before accessing the +array, and throw an error if it is too large. + +Signed-off-by: Sudhakar Kuppusamy +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit a3988cb3f0a108dd67ac127a79a4c8479d23334e) +(cherry picked from commit 7125978aa7d6068812ef6da0ab38ce521ae7eba1) +(cherry picked from commit e488538cbf9fc63796c7047550b0598e1ef95c03) +(cherry picked from commit a2e520d7ced2ded854fb24f3718530e1e6d7dd5e) +--- + grub-core/fs/f2fs.c | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 1cad2615f3..09dc932420 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -632,23 +632,27 @@ get_nat_journal (struct grub_f2fs_data *data) + return err; + } + +-static grub_uint32_t +-get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid) ++static grub_err_t ++get_blkaddr_from_nat_journal (struct grub_f2fs_data *data, grub_uint32_t nid, ++ grub_uint32_t *blkaddr) + { + grub_uint16_t n = grub_le_to_cpu16 (data->nat_j.n_nats); +- grub_uint32_t blkaddr = 0; + grub_uint16_t i; + ++ if (n >= NAT_JOURNAL_ENTRIES) ++ return grub_error (GRUB_ERR_BAD_FS, ++ "invalid number of nat journal entries"); ++ + for (i = 0; i < n; i++) + { + if (grub_le_to_cpu32 (data->nat_j.entries[i].nid) == nid) + { +- blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr); ++ *blkaddr = grub_le_to_cpu32 (data->nat_j.entries[i].ne.block_addr); + break; + } + } + +- return blkaddr; ++ return GRUB_ERR_NONE; + } + + static grub_uint32_t +@@ -656,10 +660,13 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + { + struct grub_f2fs_nat_block *nat_block; + grub_uint32_t seg_off, block_off, entry_off, block_addr; +- grub_uint32_t blkaddr; ++ grub_uint32_t blkaddr = 0; + grub_err_t err; + +- blkaddr = get_blkaddr_from_nat_journal (data, nid); ++ err = get_blkaddr_from_nat_journal (data, nid, &blkaddr); ++ if (err != GRUB_ERR_NONE) ++ return 0; ++ + if (blkaddr) + return blkaddr; + diff --git a/0530-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch b/0530-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch new file mode 100644 index 0000000..07de7cd --- /dev/null +++ b/0530-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch @@ -0,0 +1,135 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Wed, 6 Apr 2022 18:49:09 +0530 +Subject: [PATCH] fs/f2fs: Do not read past the end of nat bitmap + +A corrupt f2fs filesystem could have a block offset or a bitmap +offset that would cause us to read beyond the bounds of the nat +bitmap. + +Introduce the nat_bitmap_size member in grub_f2fs_data which holds +the size of nat bitmap. + +Set the size when loading the nat bitmap in nat_bitmap_ptr(), and +catch when an invalid offset would create a pointer past the end of +the allocated space. + +Check against the bitmap size in grub_f2fs_test_bit() test bit to avoid +reading past the end of the nat bitmap. + +Signed-off-by: Sudhakar Kuppusamy +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 62d63d5e38c67a6e349148bf7cb87c560e935a7e) +(cherry picked from commit 92219e6d379b5b4d30b05361830b72ab1d95d281) +(cherry picked from commit c23d97e3b56594bf0f802d94062e14b221143115) +(cherry picked from commit e9536dd7fbdc632efbe3506386dbfb3bfc0465c8) +--- + grub-core/fs/f2fs.c | 33 +++++++++++++++++++++++++++------ + 1 file changed, 27 insertions(+), 6 deletions(-) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 09dc932420..33e565b180 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -122,6 +122,7 @@ GRUB_MOD_LICENSE ("GPLv3+"); + #define F2FS_INLINE_DOTS 0x10 /* File having implicit dot dentries. */ + + #define MAX_VOLUME_NAME 512 ++#define MAX_NAT_BITMAP_SIZE 3900 + + enum FILE_TYPE + { +@@ -183,7 +184,7 @@ struct grub_f2fs_checkpoint + grub_uint32_t checksum_offset; + grub_uint64_t elapsed_time; + grub_uint8_t alloc_type[MAX_ACTIVE_LOGS]; +- grub_uint8_t sit_nat_version_bitmap[3900]; ++ grub_uint8_t sit_nat_version_bitmap[MAX_NAT_BITMAP_SIZE]; + grub_uint32_t checksum; + } GRUB_PACKED; + +@@ -302,6 +303,7 @@ struct grub_f2fs_data + + struct grub_f2fs_nat_journal nat_j; + char *nat_bitmap; ++ grub_uint32_t nat_bitmap_size; + + grub_disk_t disk; + struct grub_f2fs_node *inode; +@@ -377,15 +379,20 @@ sum_blk_addr (struct grub_f2fs_data *data, int base, int type) + } + + static void * +-nat_bitmap_ptr (struct grub_f2fs_data *data) ++nat_bitmap_ptr (struct grub_f2fs_data *data, grub_uint32_t *nat_bitmap_size) + { + struct grub_f2fs_checkpoint *ckpt = &data->ckpt; + grub_uint32_t offset; ++ *nat_bitmap_size = MAX_NAT_BITMAP_SIZE; + + if (grub_le_to_cpu32 (data->sblock.cp_payload) > 0) + return ckpt->sit_nat_version_bitmap; + + offset = grub_le_to_cpu32 (ckpt->sit_ver_bitmap_bytesize); ++ if (offset >= MAX_NAT_BITMAP_SIZE) ++ return NULL; ++ ++ *nat_bitmap_size = *nat_bitmap_size - offset; + + return ckpt->sit_nat_version_bitmap + offset; + } +@@ -438,11 +445,15 @@ grub_f2fs_crc_valid (grub_uint32_t blk_crc, void *buf, const grub_uint32_t len) + } + + static int +-grub_f2fs_test_bit (grub_uint32_t nr, const char *p) ++grub_f2fs_test_bit (grub_uint32_t nr, const char *p, grub_uint32_t len) + { + int mask; ++ grub_uint32_t shifted_nr = (nr >> 3); + +- p += (nr >> 3); ++ if (shifted_nr >= len) ++ return -1; ++ ++ p += shifted_nr; + mask = 1 << (7 - (nr & 0x07)); + + return mask & *p; +@@ -662,6 +673,7 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + grub_uint32_t seg_off, block_off, entry_off, block_addr; + grub_uint32_t blkaddr = 0; + grub_err_t err; ++ int result_bit; + + err = get_blkaddr_from_nat_journal (data, nid, &blkaddr); + if (err != GRUB_ERR_NONE) +@@ -682,8 +694,15 @@ get_node_blkaddr (struct grub_f2fs_data *data, grub_uint32_t nid) + ((seg_off * data->blocks_per_seg) << 1) + + (block_off & (data->blocks_per_seg - 1)); + +- if (grub_f2fs_test_bit (block_off, data->nat_bitmap)) ++ result_bit = grub_f2fs_test_bit (block_off, data->nat_bitmap, ++ data->nat_bitmap_size); ++ if (result_bit > 0) + block_addr += data->blocks_per_seg; ++ else if (result_bit == -1) ++ { ++ grub_free (nat_block); ++ return 0; ++ } + + err = grub_f2fs_block_read (data, block_addr, nat_block); + if (err) +@@ -832,7 +851,9 @@ grub_f2fs_mount (grub_disk_t disk) + if (err) + goto fail; + +- data->nat_bitmap = nat_bitmap_ptr (data); ++ data->nat_bitmap = nat_bitmap_ptr (data, &data->nat_bitmap_size); ++ if (data->nat_bitmap == NULL) ++ goto fail; + + err = get_nat_journal (data); + if (err) diff --git a/0531-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch b/0531-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch new file mode 100644 index 0000000..3444e4f --- /dev/null +++ b/0531-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch @@ -0,0 +1,41 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Sudhakar Kuppusamy +Date: Wed, 6 Apr 2022 18:17:43 +0530 +Subject: [PATCH] fs/f2fs: Do not copy file names that are too long + +A corrupt f2fs file system might specify a name length which is greater +than the maximum name length supported by the GRUB f2fs driver. + +We will allocate enough memory to store the overly long name, but there +are only F2FS_NAME_LEN bytes in the source, so we would read past the end +of the source. + +While checking directory entries, do not copy a file name with an invalid +length. + +Signed-off-by: Sudhakar Kuppusamy +Signed-off-by: Daniel Axtens +Reviewed-by: Daniel Kiper +(cherry picked from commit 9a891f638509e031d322c94e3cbcf38d36f3993a) +(cherry picked from commit 13f9160ae0d2806baed459884999356817096cd7) +(cherry picked from commit a48ba4d48b3c66431e6bbeb386078efc6602110c) +(cherry picked from commit f0440b61cebbab807638b90eb2ae86265d6cf49f) +--- + grub-core/fs/f2fs.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/grub-core/fs/f2fs.c b/grub-core/fs/f2fs.c +index 33e565b180..07ea34196c 100644 +--- a/grub-core/fs/f2fs.c ++++ b/grub-core/fs/f2fs.c +@@ -998,6 +998,10 @@ grub_f2fs_check_dentries (struct grub_f2fs_dir_iter_ctx *ctx) + + ftype = ctx->dentry[i].file_type; + name_len = grub_le_to_cpu16 (ctx->dentry[i].name_len); ++ ++ if (name_len >= F2FS_NAME_LEN) ++ return 0; ++ + filename = grub_malloc (name_len + 1); + if (!filename) + return 0; diff --git a/0532-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch b/0532-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch new file mode 100644 index 0000000..289f139 --- /dev/null +++ b/0532-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch @@ -0,0 +1,82 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Darren Kenny +Date: Tue, 29 Mar 2022 10:49:56 +0000 +Subject: [PATCH] fs/btrfs: Fix several fuzz issues with invalid dir item + sizing + +According to the btrfs code in Linux, the structure of a directory item +leaf should be of the form: + + |struct btrfs_dir_item|name|data| + +in GRUB the name len and data len are in the grub_btrfs_dir_item +structure's n and m fields respectively. + +The combined size of the structure, name and data should be less than +the allocated memory, a difference to the Linux kernel's struct +btrfs_dir_item is that the grub_btrfs_dir_item has an extra field for +where the name is stored, so we adjust for that too. + +Signed-off-by: Darren Kenny +Reviewed-by: Daniel Kiper +(cherry picked from commit 6d3f06c0b6a8992b9b1bb0e62af93ac5ff2781f0) +[rharwood: we've an extra variable here] +Signed-off-by: Robbie Harwood +(cherry picked from commit e3e21b9a81aea09dd43368cf097c1029a8380d82) +(cherry picked from commit ab14a39777edb60c99751d4fdf1cc254a4faebf5) +(cherry picked from commit 90a9fbd5969325993e069ee5a04a802b59657920) +--- + grub-core/fs/btrfs.c | 26 ++++++++++++++++++++++++++ + 1 file changed, 26 insertions(+) + +diff --git a/grub-core/fs/btrfs.c b/grub-core/fs/btrfs.c +index 3faf9056c7..9da2952f70 100644 +--- a/grub-core/fs/btrfs.c ++++ b/grub-core/fs/btrfs.c +@@ -1834,6 +1834,7 @@ grub_btrfs_dir (grub_device_t device, const char *path, + grub_uint64_t tree; + grub_uint8_t type; + char *new_path = NULL; ++ grub_size_t est_size = 0; + + if (!data) + return grub_errno; +@@ -1900,6 +1901,18 @@ grub_btrfs_dir (grub_device_t device, const char *path, + break; + } + ++ if (direl == NULL || ++ grub_add (grub_le_to_cpu16 (direl->n), ++ grub_le_to_cpu16 (direl->m), &est_size) || ++ grub_add (est_size, sizeof (*direl), &est_size) || ++ grub_sub (est_size, sizeof (direl->name), &est_size) || ++ est_size > allocated) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ r = -grub_errno; ++ goto out; ++ } ++ + for (cdirel = direl; + (grub_uint8_t *) cdirel - (grub_uint8_t *) direl + < (grub_ssize_t) elemsize; +@@ -1910,6 +1923,19 @@ grub_btrfs_dir (grub_device_t device, const char *path, + char c; + struct grub_btrfs_inode inode; + struct grub_dirhook_info info; ++ ++ if (cdirel == NULL || ++ grub_add (grub_le_to_cpu16 (cdirel->n), ++ grub_le_to_cpu16 (cdirel->m), &est_size) || ++ grub_add (est_size, sizeof (*cdirel), &est_size) || ++ grub_sub (est_size, sizeof (cdirel->name), &est_size) || ++ est_size > allocated) ++ { ++ grub_errno = GRUB_ERR_OUT_OF_RANGE; ++ r = -grub_errno; ++ goto out; ++ } ++ + err = grub_btrfs_read_inode (data, &inode, cdirel->key.object_id, + tree); + grub_memset (&info, 0, sizeof (info)); diff --git a/0533-efi-Return-grub_efi_status_t-from-grub_efi_get_varia.patch b/0533-efi-Return-grub_efi_status_t-from-grub_efi_get_varia.patch new file mode 100644 index 0000000..0bc744f --- /dev/null +++ b/0533-efi-Return-grub_efi_status_t-from-grub_efi_get_varia.patch @@ -0,0 +1,144 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Thu, 3 Dec 2020 16:01:46 +0100 +Subject: [PATCH] efi: Return grub_efi_status_t from grub_efi_get_variable() + +This is needed to properly detect and report UEFI Secure Boot status +to the x86 Linux kernel. The functionality will be added by subsequent +patches. + +Signed-off-by: Daniel Kiper +Signed-off-by: Marco A Benatto +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +(cherry picked from commit 04ae030d0eea8668d4417702d88bf2cf04713d80) +(cherry picked from commit ed33b47f00bc0d728197357b8ae632028f91599b) +--- + grub-core/commands/efi/efifwsetup.c | 8 ++++---- + grub-core/kern/efi/efi.c | 16 +++++++++------- + grub-core/video/efi_gop.c | 2 +- + include/grub/efi/efi.h | 7 ++++--- + 4 files changed, 18 insertions(+), 15 deletions(-) + +diff --git a/grub-core/commands/efi/efifwsetup.c b/grub-core/commands/efi/efifwsetup.c +index 7a137a72a2..eaca032838 100644 +--- a/grub-core/commands/efi/efifwsetup.c ++++ b/grub-core/commands/efi/efifwsetup.c +@@ -38,8 +38,8 @@ grub_cmd_fwsetup (grub_command_t cmd __attribute__ ((unused)), + grub_size_t oi_size; + grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; + +- old_os_indications = grub_efi_get_variable ("OsIndications", &global, +- &oi_size); ++ grub_efi_get_variable ("OsIndications", &global, &oi_size, ++ (void **) &old_os_indications); + + if (old_os_indications != NULL && oi_size == sizeof (os_indications)) + os_indications |= *old_os_indications; +@@ -63,8 +63,8 @@ efifwsetup_is_supported (void) + grub_size_t oi_size = 0; + grub_efi_guid_t global = GRUB_EFI_GLOBAL_VARIABLE_GUID; + +- os_indications_supported = grub_efi_get_variable ("OsIndicationsSupported", +- &global, &oi_size); ++ grub_efi_get_variable ("OsIndicationsSupported", &global, &oi_size, ++ (void **) &os_indications_supported); + + if (!os_indications_supported) + return 0; +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 2863956458..335033975d 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -241,9 +241,9 @@ grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid, + return grub_error (GRUB_ERR_IO, "could not set EFI variable `%s'", var); + } + +-void * ++grub_efi_status_t + grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, +- grub_size_t *datasize_out) ++ grub_size_t *datasize_out, void **data_out) + { + grub_efi_status_t status; + grub_efi_uintn_t datasize = 0; +@@ -252,13 +252,14 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + void *data; + grub_size_t len, len16; + ++ *data_out = NULL; + *datasize_out = 0; + + len = grub_strlen (var); + len16 = len * GRUB_MAX_UTF16_PER_UTF8; + var16 = grub_calloc (len16 + 1, sizeof (var16[0])); + if (!var16) +- return NULL; ++ return GRUB_EFI_OUT_OF_RESOURCES; + len16 = grub_utf8_to_utf16 (var16, len16, (grub_uint8_t *) var, len, NULL); + var16[len16] = 0; + +@@ -269,14 +270,14 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + if (status != GRUB_EFI_BUFFER_TOO_SMALL || !datasize) + { + grub_free (var16); +- return NULL; ++ return status; + } + + data = grub_malloc (datasize); + if (!data) + { + grub_free (var16); +- return NULL; ++ return GRUB_EFI_OUT_OF_RESOURCES; + } + + status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, data); +@@ -284,12 +285,13 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + + if (status == GRUB_EFI_SUCCESS) + { ++ *data_out = data; + *datasize_out = datasize; +- return data; ++ return status; + } + + grub_free (data); +- return NULL; ++ return status; + } + + #pragma GCC diagnostic ignored "-Wcast-align" +diff --git a/grub-core/video/efi_gop.c b/grub-core/video/efi_gop.c +index 9fcc41ac03..ec217db70f 100644 +--- a/grub-core/video/efi_gop.c ++++ b/grub-core/video/efi_gop.c +@@ -302,7 +302,7 @@ grub_video_gop_get_edid (struct grub_video_edid_info *edid_info) + char edidname[] = "agp-internal-edid"; + grub_size_t datasize; + grub_uint8_t *data; +- data = grub_efi_get_variable (edidname, &efi_var_guid, &datasize); ++ grub_efi_get_variable (edidname, &efi_var_guid, &datasize, (void **) &data); + if (data && datasize > 16) + { + copy_size = datasize - 16; +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 4411ffa16b..90a85d7d9a 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -113,9 +113,10 @@ grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memo + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version, + grub_efi_memory_descriptor_t *virtual_map); +-void *EXPORT_FUNC (grub_efi_get_variable) (const char *variable, +- const grub_efi_guid_t *guid, +- grub_size_t *datasize_out); ++grub_efi_status_t EXPORT_FUNC (grub_efi_get_variable) (const char *variable, ++ const grub_efi_guid_t *guid, ++ grub_size_t *datasize_out, ++ void **data_out); + grub_err_t + EXPORT_FUNC (grub_efi_set_variable) (const char *var, + const grub_efi_guid_t *guid, diff --git a/0534-efi-Add-a-function-to-read-EFI-variables-with-attrib.patch b/0534-efi-Add-a-function-to-read-EFI-variables-with-attrib.patch new file mode 100644 index 0000000..8bc2666 --- /dev/null +++ b/0534-efi-Add-a-function-to-read-EFI-variables-with-attrib.patch @@ -0,0 +1,77 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Daniel Kiper +Date: Thu, 3 Dec 2020 16:01:47 +0100 +Subject: [PATCH] efi: Add a function to read EFI variables with attributes + +It will be used to properly detect and report UEFI Secure Boot status to +the x86 Linux kernel. The functionality will be added by subsequent patches. + +Signed-off-by: Ignat Korchagin +Signed-off-by: Daniel Kiper +Signed-off-by: Marco A Benatto +Signed-off-by: Javier Martinez Canillas +Reviewed-by: Daniel Kiper +(cherry picked from commit ac5c9367548750e75ed1e7fc4354a3d20186d733) +(cherry picked from commit 51b11f8b3ab96c38efb1636d9c53b5a86503f1f2) +--- + grub-core/kern/efi/efi.c | 16 +++++++++++++--- + include/grub/efi/efi.h | 5 +++++ + 2 files changed, 18 insertions(+), 3 deletions(-) + +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index 335033975d..fccea20a01 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -242,8 +242,11 @@ grub_efi_set_variable(const char *var, const grub_efi_guid_t *guid, + } + + grub_efi_status_t +-grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, +- grub_size_t *datasize_out, void **data_out) ++grub_efi_get_variable_with_attributes (const char *var, ++ const grub_efi_guid_t *guid, ++ grub_size_t *datasize_out, ++ void **data_out, ++ grub_efi_uint32_t *attributes) + { + grub_efi_status_t status; + grub_efi_uintn_t datasize = 0; +@@ -280,7 +283,7 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + return GRUB_EFI_OUT_OF_RESOURCES; + } + +- status = efi_call_5 (r->get_variable, var16, guid, NULL, &datasize, data); ++ status = efi_call_5 (r->get_variable, var16, guid, attributes, &datasize, data); + grub_free (var16); + + if (status == GRUB_EFI_SUCCESS) +@@ -294,6 +297,13 @@ grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, + return status; + } + ++grub_efi_status_t ++grub_efi_get_variable (const char *var, const grub_efi_guid_t *guid, ++ grub_size_t *datasize_out, void **data_out) ++{ ++ return grub_efi_get_variable_with_attributes (var, guid, datasize_out, data_out, NULL); ++} ++ + #pragma GCC diagnostic ignored "-Wcast-align" + + /* Search the mods section from the PE32/PE32+ image. This code uses +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 90a85d7d9a..7af979b184 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -113,6 +113,11 @@ grub_err_t EXPORT_FUNC (grub_efi_set_virtual_address_map) (grub_efi_uintn_t memo + grub_efi_uintn_t descriptor_size, + grub_efi_uint32_t descriptor_version, + grub_efi_memory_descriptor_t *virtual_map); ++grub_efi_status_t EXPORT_FUNC (grub_efi_get_variable_with_attributes) (const char *variable, ++ const grub_efi_guid_t *guid, ++ grub_size_t *datasize_out, ++ void **data_out, ++ grub_efi_uint32_t *attributes); + grub_efi_status_t EXPORT_FUNC (grub_efi_get_variable) (const char *variable, + const grub_efi_guid_t *guid, + grub_size_t *datasize_out, diff --git a/0535-Define-GRUB_EFI_SHIM_LOCK_GUID.patch b/0535-Define-GRUB_EFI_SHIM_LOCK_GUID.patch new file mode 100644 index 0000000..6b00c5c --- /dev/null +++ b/0535-Define-GRUB_EFI_SHIM_LOCK_GUID.patch @@ -0,0 +1,32 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 11 May 2022 16:20:52 -0400 +Subject: [PATCH] Define GRUB_EFI_SHIM_LOCK_GUID + +Added in f76a27996c34900f2c369a8a0d6ac72ae2faa988 ("efi: Make shim_lock +GUID and protocol type public"), but that commit also manipulates the +lock protocol definition and some other guids we don't care about right +now. + +Signed-off-by: Robbie Harwood +(cherry picked from commit e44d6f8e801fae4716dd2528d7194f759c52aa12) +--- + include/grub/efi/api.h | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 37e7b16287..2a243fd290 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -349,6 +349,11 @@ + { 0x86, 0x2e, 0xc0, 0x1c, 0xdc, 0x29, 0x1f, 0x44 } \ + } + ++#define GRUB_EFI_SHIM_LOCK_GUID \ ++ { 0x605dab50, 0xe046, 0x4300, \ ++ { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } \ ++ } ++ + struct grub_efi_sal_system_table + { + grub_uint32_t signature; diff --git a/0536-misc-Make-grub_min-and-grub_max-more-resilient.patch b/0536-misc-Make-grub_min-and-grub_max-more-resilient.patch new file mode 100644 index 0000000..3cca336 --- /dev/null +++ b/0536-misc-Make-grub_min-and-grub_max-more-resilient.patch @@ -0,0 +1,85 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 21 Mar 2022 16:06:10 -0400 +Subject: [PATCH] misc: Make grub_min() and grub_max() more resilient. + +grub_min(a,b) and grub_max(a,b) use a relatively naive implementation +which leads to several problems: +- they evaluate their parameters more than once +- the naive way to address this, to declare temporary variables in a + statement-expression, isn't resilient against nested uses, because + MIN(a,MIN(b,c)) results in the temporary variables being declared in + two nested scopes, which may result in a build warning depending on + your build options. + +This patch changes our implementation to use a statement-expression +inside a helper macro, and creates the symbols for the temporary +variables with __COUNTER__ (A GNU C cpp extension) and token pasting to +create uniquely named internal variables. + +Signed-off-by: Peter Jones +(cherry picked from commit 2d6800450fa731d7b3ef9893986806e88e819eb6) +(cherry picked from commit adaf6a5ae66fb8a23274e3030e9df2714d0fc396) +(cherry picked from commit 5282d19d1942d9c3470337a84aa4a92562ba1575) +--- + grub-core/loader/multiboot_elfxx.c | 4 +--- + include/grub/misc.h | 25 +++++++++++++++++++++++-- + 2 files changed, 24 insertions(+), 5 deletions(-) + +diff --git a/grub-core/loader/multiboot_elfxx.c b/grub-core/loader/multiboot_elfxx.c +index f2318e0d16..87f6e31aa6 100644 +--- a/grub-core/loader/multiboot_elfxx.c ++++ b/grub-core/loader/multiboot_elfxx.c +@@ -35,9 +35,7 @@ + #endif + + #include +- +-#define CONCAT(a,b) CONCAT_(a, b) +-#define CONCAT_(a,b) a ## b ++#include + + #pragma GCC diagnostic ignored "-Wcast-align" + +diff --git a/include/grub/misc.h b/include/grub/misc.h +index 6be6a88f65..7ef1a1a87e 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -35,6 +35,14 @@ + #define ARRAY_SIZE(array) (sizeof (array) / sizeof (array[0])) + #define COMPILE_TIME_ASSERT(cond) switch (0) { case 1: case !(cond): ; } + ++#ifndef CONCAT_ ++#define CONCAT_(a, b) a ## b ++#endif ++ ++#ifndef CONCAT ++#define CONCAT(a, b) CONCAT_(a, b) ++#endif ++ + #define grub_dprintf(condition, ...) grub_real_dprintf(GRUB_FILE, __LINE__, condition, __VA_ARGS__) + + void *EXPORT_FUNC(grub_memmove) (void *dest, const void *src, grub_size_t n); +@@ -524,7 +532,20 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file, + #define grub_boot_time(...) + #endif + +-#define grub_max(a, b) (((a) > (b)) ? (a) : (b)) +-#define grub_min(a, b) (((a) < (b)) ? (a) : (b)) ++#define _grub_min(a, b, _a, _b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a < _b ? _a : _b; }) ++#define grub_min(a, b) _grub_min(a, b, \ ++ CONCAT(_a_,__COUNTER__), \ ++ CONCAT(_b_,__COUNTER__)) ++ ++#define _grub_max(a, b, _a, _b) \ ++ ({ typeof (a) _a = (a); \ ++ typeof (b) _b = (b); \ ++ _a > _b ? _a : _b; }) ++#define grub_max(a, b) _grub_max(a, b, \ ++ CONCAT(_a_,__COUNTER__), \ ++ CONCAT(_b_,__COUNTER__)) + + #endif /* ! GRUB_MISC_HEADER */ diff --git a/0537-ReiserFS-switch-to-using-grub_min-grub_max.patch b/0537-ReiserFS-switch-to-using-grub_min-grub_max.patch new file mode 100644 index 0000000..c3baecf --- /dev/null +++ b/0537-ReiserFS-switch-to-using-grub_min-grub_max.patch @@ -0,0 +1,95 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 21 Apr 2022 16:31:17 -0400 +Subject: [PATCH] ReiserFS: switch to using grub_min()/grub_max() + +This is a minor cleanup patch to remove the bespoke MIN() and MAX() +definitions from the reiserfs driver, and uses grub_min() / grub_max() +instead. + +Signed-off-by: Peter Jones +(cherry picked from commit 5fc601574fce99b32fe4dfb55bd8f3ab0175fd6a) +(cherry picked from commit 31e581893c564582c729fd0c033d3ce021854be8) +(cherry picked from commit 2c46aae48eabcf91d7ed34a7bed2b59aa80c2c03) +--- + grub-core/fs/reiserfs.c | 28 +++++++++------------------- + 1 file changed, 9 insertions(+), 19 deletions(-) + +diff --git a/grub-core/fs/reiserfs.c b/grub-core/fs/reiserfs.c +index 39736f63c6..9556c15ff0 100644 +--- a/grub-core/fs/reiserfs.c ++++ b/grub-core/fs/reiserfs.c +@@ -42,16 +42,6 @@ + + GRUB_MOD_LICENSE ("GPLv3+"); + +-#define MIN(a, b) \ +- ({ typeof (a) _a = (a); \ +- typeof (b) _b = (b); \ +- _a < _b ? _a : _b; }) +- +-#define MAX(a, b) \ +- ({ typeof (a) _a = (a); \ +- typeof (b) _b = (b); \ +- _a > _b ? _a : _b; }) +- + #define REISERFS_SUPER_BLOCK_OFFSET 0x10000 + #define REISERFS_MAGIC_LEN 12 + #define REISERFS_MAGIC_STRING "ReIsEr" +@@ -1076,7 +1066,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + grub_reiserfs_set_key_type (&key, GRUB_REISERFS_ANY, 2); + initial_position = off; + current_position = 0; +- final_position = MIN (len + initial_position, node->size); ++ final_position = grub_min (len + initial_position, node->size); + grub_dprintf ("reiserfs", + "Reading from %lld to %lld (%lld instead of requested %ld)\n", + (unsigned long long) initial_position, +@@ -1115,8 +1105,8 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + grub_dprintf ("reiserfs_blocktype", "D: %u\n", (unsigned) block); + if (initial_position < current_position + item_size) + { +- offset = MAX ((signed) (initial_position - current_position), 0); +- length = (MIN (item_size, final_position - current_position) ++ offset = grub_max ((signed) (initial_position - current_position), 0); ++ length = (grub_min (item_size, final_position - current_position) + - offset); + grub_dprintf ("reiserfs", + "Reading direct block %u from %u to %u...\n", +@@ -1161,9 +1151,9 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + grub_dprintf ("reiserfs_blocktype", "I: %u\n", (unsigned) block); + if (current_position + block_size >= initial_position) + { +- offset = MAX ((signed) (initial_position - current_position), +- 0); +- length = (MIN (block_size, final_position - current_position) ++ offset = grub_max ((signed) (initial_position - current_position), ++ 0); ++ length = (grub_min (block_size, final_position - current_position) + - offset); + grub_dprintf ("reiserfs", + "Reading indirect block %u from %u to %u...\n", +@@ -1205,7 +1195,7 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + switch (found.type) + { + case GRUB_REISERFS_DIRECT: +- read_length = MIN (len, item_size - file->offset); ++ read_length = grub_min (len, item_size - file->offset); + grub_disk_read (found.data->disk, + (found.block_number * block_size) / GRUB_DISK_SECTOR_SIZE, + grub_le_to_cpu16 (found.header.item_location) + file->offset, +@@ -1224,12 +1214,12 @@ grub_reiserfs_read_real (struct grub_fshelp_node *node, + item_size, (char *) indirect_block_ptr); + if (grub_errno) + goto fail; +- len = MIN (len, file->size - file->offset); ++ len = grub_min (len, file->size - file->offset); + for (indirect_block = file->offset / block_size; + indirect_block < indirect_block_count && read_length < len; + indirect_block++) + { +- read = MIN (block_size, len - read_length); ++ read = grub_min (block_size, len - read_length); + grub_disk_read (found.data->disk, + (grub_le_to_cpu32 (indirect_block_ptr[indirect_block]) * block_size) / GRUB_DISK_SECTOR_SIZE, + file->offset % block_size, read, diff --git a/0538-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch b/0538-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch new file mode 100644 index 0000000..9455dd1 --- /dev/null +++ b/0538-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch @@ -0,0 +1,49 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 24 Mar 2022 14:40:01 -0400 +Subject: [PATCH] misc: make grub_boot_time() also call + grub_dprintf("boot",...) + +Currently grub_boot_time() includes valuable debugging messages, but if +you build without BOOT_TIME_STATS enabled, they are silently and +confusingly compiled away. + +This patch changes grub_boot_time() to also log when "boot" is enabled +in DEBUG, regardless of BOOT_TIME_STATS. + +Signed-off-by: Peter Jones +(cherry picked from commit 4fd282de00df05ce289467861deb7a0e186cfbd7) +(cherry picked from commit cc7e60a9f3ad1fa74b9cd48a7e66b1976f9a554a) +(cherry picked from commit 9e78e5749d5c99a01c96c9c0d9ec3e98633a4cbd) +--- + grub-core/kern/misc.c | 3 ++- + include/grub/misc.h | 2 +- + 2 files changed, 3 insertions(+), 2 deletions(-) + +diff --git a/grub-core/kern/misc.c b/grub-core/kern/misc.c +index 859d71659a..b375e486a4 100644 +--- a/grub-core/kern/misc.c ++++ b/grub-core/kern/misc.c +@@ -1336,7 +1336,8 @@ grub_real_boot_time (const char *file, + n->next = 0; + + va_start (args, fmt); +- n->msg = grub_xvasprintf (fmt, args); ++ n->msg = grub_xvasprintf (fmt, args); ++ grub_dprintf ("boot", "%s\n", n->msg); + va_end (args); + + *boot_time_last = n; +diff --git a/include/grub/misc.h b/include/grub/misc.h +index 7ef1a1a87e..1b722c8185 100644 +--- a/include/grub/misc.h ++++ b/include/grub/misc.h +@@ -529,7 +529,7 @@ void EXPORT_FUNC(grub_real_boot_time) (const char *file, + const char *fmt, ...) __attribute__ ((format (GNU_PRINTF, 3, 4))); + #define grub_boot_time(...) grub_real_boot_time(GRUB_FILE, __LINE__, __VA_ARGS__) + #else +-#define grub_boot_time(...) ++#define grub_boot_time(fmt, ...) grub_dprintf("boot", fmt "\n", ##__VA_ARGS__) + #endif + + #define _grub_min(a, b, _a, _b) \ diff --git a/0539-modules-make-.module_license-read-only.patch b/0539-modules-make-.module_license-read-only.patch new file mode 100644 index 0000000..94dc892 --- /dev/null +++ b/0539-modules-make-.module_license-read-only.patch @@ -0,0 +1,33 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 24 Feb 2022 16:32:51 -0500 +Subject: [PATCH] modules: make .module_license read-only + +Currently .module_license is set writable (that is, the section has the +SHF_WRITE flag set) in the module's ELF headers. This probably never +actually matters, but it can't possibly be correct. + +This patch sets that data as "const", which causes that flag not to be +set. + +Signed-off-by: Peter Jones +(cherry picked from commit 2eff3e2c9d9e6b75daa81b840c96f112ef7d5de6) +(cherry picked from commit 3c3c1858d1c056eee660d67888be80e7eae498ca) +(cherry picked from commit ebcce09e35ef6916a2d1ddbf0906e9f3f5c539ad) +--- + include/grub/dl.h | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 6a3e251b45..9ec6caf3f9 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -121,7 +121,7 @@ grub_mod_fini (void) + #define ATTRIBUTE_USED __unused__ + #endif + #define GRUB_MOD_LICENSE(license) \ +- static char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license; ++ static const char grub_module_license[] __attribute__ ((section (GRUB_MOD_SECTION (module_license)), ATTRIBUTE_USED)) = "LICENSE=" license; + #define GRUB_MOD_DEP(name) \ + static const char grub_module_depend_##name[] \ + __attribute__((section(GRUB_MOD_SECTION(moddeps)), ATTRIBUTE_USED)) = #name diff --git a/0540-modules-strip-.llvm_addrsig-sections-and-similar.patch b/0540-modules-strip-.llvm_addrsig-sections-and-similar.patch new file mode 100644 index 0000000..51aba29 --- /dev/null +++ b/0540-modules-strip-.llvm_addrsig-sections-and-similar.patch @@ -0,0 +1,42 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Thu, 24 Feb 2022 16:40:11 -0500 +Subject: [PATCH] modules: strip .llvm_addrsig sections and similar. + +Currently grub modules built with clang or gcc have several sections +which we don't actually need or support. + +We already have a list of section to skip in genmod.sh, and this patch +adds the following sections to that list (as well as a few newlines): + +.note.gnu.property +.llvm* + +Note that the glob there won't work without a new enough linker, but the +failure is just reversion to the status quo, so that's not a big problem. + +Signed-off-by: Peter Jones +(cherry picked from commit e85d1c4d795f8135ad0acfa36d64760d12d6fed1) +(cherry picked from commit d3024204b2e2c69ecb91392eeb87c1e6835c3743) +(cherry picked from commit f729241a34394b1019d83d75ffe6bfe0986ab274) +--- + grub-core/genmod.sh.in | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/grub-core/genmod.sh.in b/grub-core/genmod.sh.in +index 1250589b3f..c2c5280d75 100644 +--- a/grub-core/genmod.sh.in ++++ b/grub-core/genmod.sh.in +@@ -57,8 +57,11 @@ if test x@TARGET_APPLE_LINKER@ != x1; then + @TARGET_STRIP@ --strip-unneeded \ + -K grub_mod_init -K grub_mod_fini \ + -K _grub_mod_init -K _grub_mod_fini \ +- -R .note.gnu.gold-version -R .note.GNU-stack \ ++ -R .note.GNU-stack \ ++ -R .note.gnu.gold-version \ ++ -R .note.gnu.property \ + -R .gnu.build.attributes \ ++ -R '.llvm*' \ + -R .rel.gnu.build.attributes \ + -R .rela.gnu.build.attributes \ + -R .eh_frame -R .rela.eh_frame -R .rel.eh_frame \ diff --git a/0541-modules-Don-t-allocate-space-for-non-allocable-secti.patch b/0541-modules-Don-t-allocate-space-for-non-allocable-secti.patch new file mode 100644 index 0000000..12c1a59 --- /dev/null +++ b/0541-modules-Don-t-allocate-space-for-non-allocable-secti.patch @@ -0,0 +1,38 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 21 Mar 2022 16:56:10 -0400 +Subject: [PATCH] modules: Don't allocate space for non-allocable sections. + +Currently when loading grub modules, we allocate space for all sections, +including those without SHF_ALLOC set. We then copy the sections that +/do/ have SHF_ALLOC set into the allocated memory, leaving some of our +allocation untouched forever. Additionally, on platforms with GOT +fixups and trampolines, we currently compute alignment round-ups for the +sections and sections with sh_size = 0. + +This patch removes the extra space from the allocation computation, and +makes the allocation computation loop skip empty sections as the loading +loop does. + +Signed-off-by: Peter Jones +(cherry picked from commit 03215e342f552396ab08125ea769b1e166417ec1) +(cherry picked from commit 91518751b9bcba078e3f4385f4b2f6c39cab49cd) +(cherry picked from commit ee945970425488bd5b72d837706764a6a0fde46c) +--- + grub-core/kern/dl.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 520126beab..ba1b33c20b 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -290,6 +290,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + i < e->e_shnum; + i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) + { ++ if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC)) ++ continue; ++ + tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size; + if (talign < s->sh_addralign) + talign = s->sh_addralign; diff --git a/0542-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch b/0542-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch new file mode 100644 index 0000000..8cc3da5 --- /dev/null +++ b/0542-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch @@ -0,0 +1,84 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Fri, 25 Mar 2022 15:40:12 -0400 +Subject: [PATCH] pe: add the DOS header struct and fix some bad naming. + +In order to properly validate a loaded kernel's support for being loaded +without a writable stack or executable, we need to be able to properly +parse arbitrary PE headers. + +Currently, pe32.h is written in such a way that the MS-DOS header that +tells us where to find the PE header in the binary can't be accessed. +Further, for some reason it calls the DOS MZ magic "GRUB_PE32_MAGIC". + +This patch adds the structure for the DOS header, renames the DOS magic +define, and adds defines for the actual PE magic. + +Signed-off-by: Peter Jones +(cherry picked from commit 955f47aa8300387eecf18b0866d21dde7720593d) +(cherry picked from commit 662744c2e986cb770fe49e71e019aaf33a66272d) +(cherry picked from commit 4b541b7e76b77d131ff534e537a622551e774a2b) +--- + grub-core/loader/arm64/linux.c | 2 +- + include/grub/efi/pe32.h | 28 ++++++++++++++++++++++++++-- + 2 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index e1923cf725..24ab0f0074 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -57,7 +57,7 @@ grub_armxx_efi_linux_check_image (struct linux_armxx_kernel_header * lh) + if (lh->magic != GRUB_LINUX_ARMXX_MAGIC_SIGNATURE) + return grub_error(GRUB_ERR_BAD_OS, "invalid magic number"); + +- if ((lh->code0 & 0xffff) != GRUB_PE32_MAGIC) ++ if ((lh->code0 & 0xffff) != GRUB_DOS_MAGIC) + return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, + N_("plain image kernel not supported - rebuild with CONFIG_(U)EFI_STUB enabled")); + +diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h +index c03cc599f6..2241f6317b 100644 +--- a/include/grub/efi/pe32.h ++++ b/include/grub/efi/pe32.h +@@ -45,7 +45,30 @@ + + #define GRUB_PE32_MSDOS_STUB_SIZE 0x80 + +-#define GRUB_PE32_MAGIC 0x5a4d ++#define GRUB_DOS_MAGIC 0x5a4d ++ ++struct grub_dos_header ++{ ++ grub_uint16_t magic; ++ grub_uint16_t cblp; ++ grub_uint16_t cp; ++ grub_uint16_t crlc; ++ grub_uint16_t cparhdr; ++ grub_uint16_t minalloc; ++ grub_uint16_t maxalloc; ++ grub_uint16_t ss; ++ grub_uint16_t sp; ++ grub_uint16_t csum; ++ grub_uint16_t ip; ++ grub_uint16_t cs; ++ grub_uint16_t lfarlc; ++ grub_uint16_t ovno; ++ grub_uint16_t res0[4]; ++ grub_uint16_t oemid; ++ grub_uint16_t oeminfo; ++ grub_uint16_t res1[10]; ++ grub_uint32_t lfanew; ++}; + + /* According to the spec, the minimal alignment is 512 bytes... + But some examples (such as EFI drivers in the Intel +@@ -271,7 +294,8 @@ struct grub_pe32_section_table + + + +-#define GRUB_PE32_SIGNATURE_SIZE 4 ++#define GRUB_PE32_SIGNATURE_SIZE 4 ++#define GRUB_PE32_SIGNATURE "PE\0\0" + + struct grub_pe32_header + { diff --git a/0543-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch b/0543-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch new file mode 100644 index 0000000..7d7a44a --- /dev/null +++ b/0543-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch @@ -0,0 +1,88 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Wed, 9 Feb 2022 16:08:20 -0500 +Subject: [PATCH] EFI: allocate kernel in EFI_RUNTIME_SERVICES_CODE instead of + EFI_LOADER_DATA. + +On some of the firmwares with more security mitigations, EFI_LOADER_DATA +doesn't get you executable memory, and we take a fault and reboot when +we enter kernel. + +This patch correctly allocates the kernel code as EFI_RUNTIME_SERVICES_CODE +rather than EFI_LOADER_DATA. + +Signed-off-by: Peter Jones +[rharwood: use kernel_size] +Signed-off-by: Robbie Harwood +(cherry picked from commit 8b31058a12d3e85f0f0180ac90b98d6465fccbb7) +(cherry picked from commit 460df66aab9b3a57fc0d14a21a595cd467c4b13e) +(cherry picked from commit 2380ad45c78ed12710f1186eda9f2ba38c20f6ba) +--- + grub-core/loader/i386/efi/linux.c | 19 +++++++++++++------ + 1 file changed, 13 insertions(+), 6 deletions(-) + +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 8337191921..3d4069e4c6 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -86,7 +86,9 @@ kernel_free(void *addr, grub_efi_uintn_t size) + } + + static void * +-kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) ++kernel_alloc(grub_efi_uintn_t size, ++ grub_efi_memory_type_t memtype, ++ const char * const errmsg) + { + void *addr = 0; + unsigned int i; +@@ -112,7 +114,7 @@ kernel_alloc(grub_efi_uintn_t size, const char * const errmsg) + prev_max = max; + addr = grub_efi_allocate_pages_real (max, pages, + max_addresses[i].alloc_type, +- GRUB_EFI_LOADER_DATA); ++ memtype); + if (addr) + grub_dprintf ("linux", "Allocated at %p\n", addr); + } +@@ -243,7 +245,8 @@ grub_cmd_initrd (grub_command_t cmd, int argc, char *argv[]) + } + } + +- initrd_mem = kernel_alloc(size, N_("can't allocate initrd")); ++ initrd_mem = kernel_alloc(size, GRUB_EFI_RUNTIME_SERVICES_DATA, ++ N_("can't allocate initrd")); + if (initrd_mem == NULL) + goto fail; + grub_dprintf ("linux", "initrd_mem = %p\n", initrd_mem); +@@ -411,7 +414,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + #endif + +- params = kernel_alloc (sizeof(*params), "cannot allocate kernel parameters"); ++ params = kernel_alloc (sizeof(*params), GRUB_EFI_RUNTIME_SERVICES_DATA, ++ "cannot allocate kernel parameters"); + if (!params) + goto fail; + grub_dprintf ("linux", "params = %p\n", params); +@@ -432,7 +436,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_dprintf ("linux", "new lh is at %p\n", lh); + + grub_dprintf ("linux", "setting up cmdline\n"); +- cmdline = kernel_alloc (lh->cmdline_size + 1, N_("can't allocate cmdline")); ++ cmdline = kernel_alloc (lh->cmdline_size + 1, ++ GRUB_EFI_RUNTIME_SERVICES_DATA, ++ N_("can't allocate cmdline")); + if (!cmdline) + goto fail; + grub_dprintf ("linux", "cmdline = %p\n", cmdline); +@@ -478,7 +484,8 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + max_addresses[1].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + max_addresses[2].addr = GRUB_EFI_MAX_ALLOCATION_ADDRESS; + kernel_size = lh->init_size; +- kernel_mem = kernel_alloc (kernel_size, N_("can't allocate kernel")); ++ kernel_mem = kernel_alloc (kernel_size, GRUB_EFI_RUNTIME_SERVICES_CODE, ++ N_("can't allocate kernel")); + restore_addresses(); + if (!kernel_mem) + goto fail; diff --git a/0544-modules-load-module-sections-at-page-aligned-address.patch b/0544-modules-load-module-sections-at-page-aligned-address.patch new file mode 100644 index 0000000..5cc42b1 --- /dev/null +++ b/0544-modules-load-module-sections-at-page-aligned-address.patch @@ -0,0 +1,361 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 21 Mar 2022 17:45:40 -0400 +Subject: [PATCH] modules: load module sections at page-aligned addresses + +Currently we load module sections at whatever alignment gcc+ld happened +to dump into the ELF section header, which is often pretty useless. For +example, by default time.mod has these sections on a current x86_64 +build: + +$ eu-readelf -a grub-core/time.mod |& grep ^Section -A13 +Section Headers: +[Nr] Name Type Addr Off Size ES Flags Lk Inf Al +[ 0] NULL 0 00000000 00000000 0 0 0 0 +[ 1] .text PROGBITS 0 00000040 0000015e 0 AX 0 0 1 +[ 2] .rela.text RELA 0 00000458 000001e0 24 I 8 1 8 +[ 3] .rodata.str1.1 PROGBITS 0 0000019e 000000a1 1 AMS 0 0 1 +[ 4] .module_license PROGBITS 0 00000240 0000000f 0 A 0 0 8 +[ 5] .data PROGBITS 0 0000024f 00000000 0 WA 0 0 1 +[ 6] .bss NOBITS 0 00000250 00000008 0 WA 0 0 8 +[ 7] .modname PROGBITS 0 00000250 00000005 0 0 0 1 +[ 8] .symtab SYMTAB 0 00000258 00000150 24 9 6 8 +[ 9] .strtab STRTAB 0 000003a8 000000ab 0 0 0 1 +[10] .shstrtab STRTAB 0 00000638 00000059 0 0 0 1 + +With NX protections being page based, loading sections with either a 1 +or 8 *byte* alignment does absolutely nothing to help us out. + +This patch switches most EFI platforms to load module sections at 4kB +page-aligned addresses. To do so, it adds an new per-arch function, +grub_arch_dl_min_alignment(), which returns the alignment needed for +dynamically loaded sections (in bytes). Currently it sets it to 4096 +when GRUB_MACHINE_EFI is true on x86_64, i386, arm, arm64, and emu, and +1-byte alignment on everything else. + +It then changes the allocation size computation and the loader code in +grub_dl_load_segments() to align the locations and sizes up to these +boundaries, and fills any added padding with zeros. + +All of this happens before relocations are applied, so the relocations +factor that in with no change. + +As an aside, initially Daniel Kiper and I thought that it might be a +better idea to split the modules up into top-level sections as +.text.modules, .rodata.modules, .data.modules, etc., so that their page +permissions would get set by the loader that's loading grub itself. +This turns out to have two significant downsides: 1) either in mkimage +or in grub_dl_relocate_symbols(), you wind up having to dynamically +process the relocations to accommodate the moved module sections, and 2) +you then need to change the permissions on the modules and change them +back while relocating them in grub_dl_relocate_symbols(), which means +that any loader that /does/ honor the section flags but does /not/ +generally support NX with the memory attributes API will cause grub to +fail. + +Signed-off-by: Peter Jones +(cherry picked from commit 31d52500b281619d92b03b2c2d30fe15aedaf326) +(cherry picked from commit 04f1df6b665493e38de66018aebe377fdac4ceec) +[rharwood: not risc-v yet] +Signed-off-by: Robbie Harwood +(cherry picked from commit 62c48da3ef51fc4f98746fbc35791ec2beab0426) +--- + grub-core/kern/arm/dl.c | 13 +++++++++++++ + grub-core/kern/arm64/dl.c | 13 +++++++++++++ + grub-core/kern/dl.c | 29 +++++++++++++++++++++-------- + grub-core/kern/emu/full.c | 13 +++++++++++++ + grub-core/kern/i386/dl.c | 13 +++++++++++++ + grub-core/kern/ia64/dl.c | 9 +++++++++ + grub-core/kern/mips/dl.c | 8 ++++++++ + grub-core/kern/powerpc/dl.c | 9 +++++++++ + grub-core/kern/sparc64/dl.c | 9 +++++++++ + grub-core/kern/x86_64/dl.c | 13 +++++++++++++ + include/grub/dl.h | 2 ++ + docs/grub-dev.texi | 6 +++--- + 12 files changed, 126 insertions(+), 11 deletions(-) + +diff --git a/grub-core/kern/arm/dl.c b/grub-core/kern/arm/dl.c +index eab9d17ff2..9260737936 100644 +--- a/grub-core/kern/arm/dl.c ++++ b/grub-core/kern/arm/dl.c +@@ -278,3 +278,16 @@ grub_arch_dl_check_header (void *ehdr) + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/arm64/dl.c b/grub-core/kern/arm64/dl.c +index fb03373190..826f8e721e 100644 +--- a/grub-core/kern/arm64/dl.c ++++ b/grub-core/kern/arm64/dl.c +@@ -191,3 +191,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index ba1b33c20b..5c2153acf9 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -278,7 +278,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + { + unsigned i; + const Elf_Shdr *s; +- grub_size_t tsize = 0, talign = 1; ++ grub_size_t tsize = 0, talign = 1, arch_addralign = 1; + #if !defined (__i386__) && !defined (__x86_64__) + grub_size_t tramp; + grub_size_t got; +@@ -286,16 +286,24 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + #endif + char *ptr; + ++ arch_addralign = grub_arch_dl_min_alignment (); ++ + for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) + { ++ grub_size_t sh_addralign; ++ grub_size_t sh_size; ++ + if (s->sh_size == 0 || !(s->sh_flags & SHF_ALLOC)) + continue; + +- tsize = ALIGN_UP (tsize, s->sh_addralign) + s->sh_size; +- if (talign < s->sh_addralign) +- talign = s->sh_addralign; ++ sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign); ++ sh_size = ALIGN_UP(s->sh_size, sh_addralign); ++ ++ tsize = ALIGN_UP (tsize, sh_addralign) + sh_size; ++ if (talign < sh_addralign) ++ talign = sh_addralign; + } + + #if !defined (__i386__) && !defined (__x86_64__) +@@ -324,6 +332,9 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + i < e->e_shnum; + i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize)) + { ++ grub_size_t sh_addralign = ALIGN_UP(s->sh_addralign, arch_addralign); ++ grub_size_t sh_size = ALIGN_UP(s->sh_size, sh_addralign); ++ + if (s->sh_flags & SHF_ALLOC) + { + grub_dl_segment_t seg; +@@ -336,17 +347,19 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + { + void *addr; + +- ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, s->sh_addralign); ++ ptr = (char *) ALIGN_UP ((grub_addr_t) ptr, sh_addralign); + addr = ptr; +- ptr += s->sh_size; ++ ptr += sh_size; + + switch (s->sh_type) + { + case SHT_PROGBITS: + grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size); ++ grub_memset ((char *)addr + s->sh_size, 0, ++ sh_size - s->sh_size); + break; + case SHT_NOBITS: +- grub_memset (addr, 0, s->sh_size); ++ grub_memset (addr, 0, sh_size); + break; + } + +@@ -355,7 +368,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + else + seg->addr = 0; + +- seg->size = s->sh_size; ++ seg->size = sh_size; + seg->section = i; + seg->next = mod->segment; + mod->segment = seg; +diff --git a/grub-core/kern/emu/full.c b/grub-core/kern/emu/full.c +index e8d63b1f5f..1de1c28eb0 100644 +--- a/grub-core/kern/emu/full.c ++++ b/grub-core/kern/emu/full.c +@@ -67,3 +67,16 @@ grub_arch_dl_init_linker (void) + } + #endif + ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/i386/dl.c b/grub-core/kern/i386/dl.c +index 1346da5cc9..d6b4681fc9 100644 +--- a/grub-core/kern/i386/dl.c ++++ b/grub-core/kern/i386/dl.c +@@ -79,3 +79,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/grub-core/kern/ia64/dl.c b/grub-core/kern/ia64/dl.c +index ebcf316298..3bb753a89b 100644 +--- a/grub-core/kern/ia64/dl.c ++++ b/grub-core/kern/ia64/dl.c +@@ -143,3 +143,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + } + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/mips/dl.c b/grub-core/kern/mips/dl.c +index 5d7d299c74..6d83bd71e9 100644 +--- a/grub-core/kern/mips/dl.c ++++ b/grub-core/kern/mips/dl.c +@@ -272,3 +272,11 @@ grub_arch_dl_init_linker (void) + grub_dl_register_symbol ("_gp_disp", &_gp_disp_dummy, 0, 0); + } + ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/powerpc/dl.c b/grub-core/kern/powerpc/dl.c +index 3a7fa3ed3d..577e27d871 100644 +--- a/grub-core/kern/powerpc/dl.c ++++ b/grub-core/kern/powerpc/dl.c +@@ -165,3 +165,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/sparc64/dl.c b/grub-core/kern/sparc64/dl.c +index 739be47174..c741c1782e 100644 +--- a/grub-core/kern/sparc64/dl.c ++++ b/grub-core/kern/sparc64/dl.c +@@ -184,3 +184,12 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++ return 1; ++} +diff --git a/grub-core/kern/x86_64/dl.c b/grub-core/kern/x86_64/dl.c +index 3a73e6e6ce..6c20b7c367 100644 +--- a/grub-core/kern/x86_64/dl.c ++++ b/grub-core/kern/x86_64/dl.c +@@ -114,3 +114,16 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + + return GRUB_ERR_NONE; + } ++ ++/* ++ * Tell the loader what our minimum section alignment is. ++ */ ++grub_size_t ++grub_arch_dl_min_alignment (void) ++{ ++#ifdef GRUB_MACHINE_EFI ++ return 4096; ++#else ++ return 1; ++#endif ++} +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 9ec6caf3f9..dd4c3e7ff4 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -280,6 +280,8 @@ grub_err_t grub_arch_dl_check_header (void *ehdr); + grub_err_t + grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, + Elf_Shdr *s, grub_dl_segment_t seg); ++grub_size_t ++grub_arch_dl_min_alignment (void); + #endif + + #if defined (_mips) +diff --git a/docs/grub-dev.texi b/docs/grub-dev.texi +index 03d53498c5..dbfb94bc06 100644 +--- a/docs/grub-dev.texi ++++ b/docs/grub-dev.texi +@@ -638,9 +638,9 @@ declare startup asm file ($cpu_$platform_startup) as well as any other files + (e.g. init.c and callwrap.S) (e.g. $cpu_$platform = kern/$cpu/$platform/init.c). + At this stage you will also need to add dummy dl.c and cache.S with functions + grub_err_t grub_arch_dl_check_header (void *ehdr), grub_err_t +-grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c) and +-void grub_arch_sync_caches (void *address, grub_size_t len) (cache.S). They +-won't be used for now. ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr) (dl.c), grub_uint32_t ++grub_arch_dl_min_alignment (void), and void grub_arch_sync_caches (void ++*address, grub_size_t len) (cache.S). They won't be used for now. + + You will need to create directory include/$cpu/$platform and a file + include/$cpu/types.h. The later folowing this template: diff --git a/0545-nx-add-memory-attribute-get-set-API.patch b/0545-nx-add-memory-attribute-get-set-API.patch new file mode 100644 index 0000000..eec3160 --- /dev/null +++ b/0545-nx-add-memory-attribute-get-set-API.patch @@ -0,0 +1,321 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 22 Mar 2022 10:56:21 -0400 +Subject: [PATCH] nx: add memory attribute get/set API + +For NX, we need to set the page access permission attributes for write +and execute permissions. + +This patch adds two new primitives, grub_set_mem_attrs() and +grub_clear_mem_attrs(), and associated constant definitions, to be used +for that purpose. + +For most platforms, it adds a dummy implementation that returns +GRUB_ERR_NONE. On EFI platforms, it adds a common helper function, +grub_efi_status_to_err(), which translates EFI error codes to grub error +codes, adds headers for the EFI Memory Attribute Protocol (still pending +standardization), and an implementation of the grub nx primitives using +it. + +Signed-off-by: Peter Jones +[rharwood: add pjones's none/nyi fixup] +(cherry picked from commit 35de78a8d32b9fad5291ec96fd3cbb9cf2f4a80b) +(cherry picked from commit 46cb4f9557bdba1db0a17d012df705d94d81a9f6) +[rharwood: context fuzz, guids] +Signed-off-by: Robbie Harwood +(cherry picked from commit 7d8eea48e82c4ef572cc0f9d3252487c1d7e5729) +--- + grub-core/kern/efi/efi.c | 36 +++++++++++++ + grub-core/kern/efi/mm.c | 131 +++++++++++++++++++++++++++++++++++++++++++++++ + include/grub/efi/api.h | 25 +++++++++ + include/grub/efi/efi.h | 2 + + include/grub/mm.h | 32 ++++++++++++ + 5 files changed, 226 insertions(+) + +diff --git a/grub-core/kern/efi/efi.c b/grub-core/kern/efi/efi.c +index fccea20a01..09468dc5d5 100644 +--- a/grub-core/kern/efi/efi.c ++++ b/grub-core/kern/efi/efi.c +@@ -1093,3 +1093,39 @@ grub_efi_compare_device_paths (const grub_efi_device_path_t *dp1, + + return 0; + } ++ ++grub_err_t ++grub_efi_status_to_err (grub_efi_status_t status) ++{ ++ grub_err_t err; ++ switch (status) ++ { ++ case GRUB_EFI_SUCCESS: ++ err = GRUB_ERR_NONE; ++ break; ++ case GRUB_EFI_INVALID_PARAMETER: ++ default: ++ err = GRUB_ERR_BAD_ARGUMENT; ++ break; ++ case GRUB_EFI_OUT_OF_RESOURCES: ++ err = GRUB_ERR_OUT_OF_MEMORY; ++ break; ++ case GRUB_EFI_DEVICE_ERROR: ++ err = GRUB_ERR_IO; ++ break; ++ case GRUB_EFI_WRITE_PROTECTED: ++ err = GRUB_ERR_WRITE_ERROR; ++ break; ++ case GRUB_EFI_SECURITY_VIOLATION: ++ err = GRUB_ERR_ACCESS_DENIED; ++ break; ++ case GRUB_EFI_NOT_FOUND: ++ err = GRUB_ERR_FILE_NOT_FOUND; ++ break; ++ case GRUB_EFI_ABORTED: ++ err = GRUB_ERR_WAIT; ++ break; ++ } ++ ++ return err; ++} +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 9e76f23e5f..2cf4a4883a 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -730,3 +730,134 @@ grub_efi_get_ram_base(grub_addr_t *base_addr) + return GRUB_ERR_NONE; + } + #endif ++ ++static inline grub_uint64_t ++grub_mem_attrs_to_uefi_mem_attrs (grub_uint64_t attrs) ++{ ++ grub_uint64_t ret = GRUB_EFI_MEMORY_RP | ++ GRUB_EFI_MEMORY_RO | ++ GRUB_EFI_MEMORY_XP; ++ ++ if (attrs & GRUB_MEM_ATTR_R) ++ ret &= ~GRUB_EFI_MEMORY_RP; ++ ++ if (attrs & GRUB_MEM_ATTR_W) ++ ret &= ~GRUB_EFI_MEMORY_RO; ++ ++ if (attrs & GRUB_MEM_ATTR_X) ++ ret &= ~GRUB_EFI_MEMORY_XP; ++ ++ return ret; ++} ++ ++static inline grub_uint64_t ++uefi_mem_attrs_to_grub_mem_attrs (grub_uint64_t attrs) ++{ ++ grub_uint64_t ret = GRUB_MEM_ATTR_R | ++ GRUB_MEM_ATTR_W | ++ GRUB_MEM_ATTR_X; ++ ++ if (attrs & GRUB_EFI_MEMORY_RP) ++ ret &= ~GRUB_MEM_ATTR_R; ++ ++ if (attrs & GRUB_EFI_MEMORY_RO) ++ ret &= ~GRUB_MEM_ATTR_W; ++ ++ if (attrs & GRUB_EFI_MEMORY_XP) ++ ret &= ~GRUB_MEM_ATTR_X; ++ ++ return ret; ++} ++ ++grub_err_t ++grub_get_mem_attrs (grub_addr_t addr, grub_size_t size, grub_uint64_t *attrs) ++{ ++ grub_efi_memory_attribute_protocol_t *proto; ++ grub_efi_physical_address_t physaddr = addr; ++ grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; ++ grub_efi_status_t efi_status; ++ ++ proto = grub_efi_locate_protocol (&protocol_guid, 0); ++ if (!proto) ++ return GRUB_ERR_NOT_IMPLEMENTED_YET; ++ ++ if (physaddr & 0xfff || size & 0xfff || size == 0 || attrs == NULL) ++ { ++ grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" and attrs %p\n", ++ __func__, physaddr, physaddr+size-1, attrs); ++ return 0; ++ } ++ ++ efi_status = efi_call_4(proto->get_memory_attributes, ++ proto, physaddr, size, attrs); ++ *attrs = uefi_mem_attrs_to_grub_mem_attrs (*attrs); ++ ++ return grub_efi_status_to_err (efi_status); ++} ++ ++grub_err_t ++grub_update_mem_attrs (grub_addr_t addr, grub_size_t size, ++ grub_uint64_t set_attrs, grub_uint64_t clear_attrs) ++{ ++ grub_efi_memory_attribute_protocol_t *proto; ++ grub_efi_physical_address_t physaddr = addr; ++ grub_efi_guid_t protocol_guid = GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID; ++ grub_efi_status_t efi_status = GRUB_EFI_SUCCESS; ++ grub_uint64_t before = 0, after = 0, uefi_set_attrs, uefi_clear_attrs; ++ grub_err_t err; ++ ++ proto = grub_efi_locate_protocol (&protocol_guid, 0); ++ if (!proto) ++ return GRUB_ERR_NONE; ++ ++ err = grub_get_mem_attrs (addr, size, &before); ++ if (err) ++ grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n", ++ addr, size, &before, err); ++ ++ if (physaddr & 0xfff || size & 0xfff || size == 0) ++ { ++ grub_dprintf ("nx", "%s called on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" +%s%s%s -%s%s%s\n", ++ __func__, physaddr, physaddr + size - 1, ++ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : ""); ++ return 0; ++ } ++ ++ uefi_set_attrs = grub_mem_attrs_to_uefi_mem_attrs (set_attrs); ++ grub_dprintf ("nx", "translating set_attrs from 0x%lx to 0x%lx\n", set_attrs, uefi_set_attrs); ++ uefi_clear_attrs = grub_mem_attrs_to_uefi_mem_attrs (clear_attrs); ++ grub_dprintf ("nx", "translating clear_attrs from 0x%lx to 0x%lx\n", clear_attrs, uefi_clear_attrs); ++ if (uefi_set_attrs) ++ efi_status = efi_call_4(proto->set_memory_attributes, ++ proto, physaddr, size, uefi_set_attrs); ++ if (efi_status == GRUB_EFI_SUCCESS && uefi_clear_attrs) ++ efi_status = efi_call_4(proto->clear_memory_attributes, ++ proto, physaddr, size, uefi_clear_attrs); ++ ++ err = grub_get_mem_attrs (addr, size, &after); ++ if (err) ++ grub_dprintf ("nx", "grub_get_mem_attrs(0x%"PRIxGRUB_ADDR", %"PRIuGRUB_SIZE", %p) -> 0x%x\n", ++ addr, size, &after, err); ++ ++ grub_dprintf ("nx", "set +%s%s%s -%s%s%s on 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" before:%c%c%c after:%c%c%c\n", ++ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ addr, addr + size - 1, ++ (before & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (before & GRUB_MEM_ATTR_W) ? 'w' : '-', ++ (before & GRUB_MEM_ATTR_X) ? 'x' : '-', ++ (after & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (after & GRUB_MEM_ATTR_W) ? 'w' : '-', ++ (after & GRUB_MEM_ATTR_X) ? 'x' : '-'); ++ ++ return grub_efi_status_to_err (efi_status); ++} +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 2a243fd290..510a4030f5 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -354,6 +354,11 @@ + { 0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23 } \ + } + ++#define GRUB_EFI_MEMORY_ATTRIBUTE_PROTOCOL_GUID \ ++ { 0xf4560cf6, 0x40ec, 0x4b4a, \ ++ { 0xa1, 0x92, 0xbf, 0x1d, 0x57, 0xd0, 0xb1, 0x89 } \ ++ } ++ + struct grub_efi_sal_system_table + { + grub_uint32_t signature; +@@ -2091,6 +2096,26 @@ struct grub_efi_rng_protocol + }; + typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t; + ++struct grub_efi_memory_attribute_protocol ++{ ++ grub_efi_status_t (*get_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t *attributes); ++ grub_efi_status_t (*set_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t attributes); ++ grub_efi_status_t (*clear_memory_attributes) ( ++ struct grub_efi_memory_attribute_protocol *this, ++ grub_efi_physical_address_t base_address, ++ grub_efi_uint64_t length, ++ grub_efi_uint64_t attributes); ++}; ++typedef struct grub_efi_memory_attribute_protocol grub_efi_memory_attribute_protocol_t; ++ + #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ + || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) + +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index 7af979b184..a635bcb0a9 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -159,4 +159,6 @@ struct grub_net_card; + grub_efi_handle_t + grub_efinet_get_device_handle (struct grub_net_card *card); + ++grub_err_t EXPORT_FUNC(grub_efi_status_to_err) (grub_efi_status_t status); ++ + #endif /* ! GRUB_EFI_EFI_HEADER */ +diff --git a/include/grub/mm.h b/include/grub/mm.h +index 9c38dd3ca5..d81623d226 100644 +--- a/include/grub/mm.h ++++ b/include/grub/mm.h +@@ -22,6 +22,7 @@ + + #include + #include ++#include + #include + + #ifndef NULL +@@ -38,6 +39,37 @@ void *EXPORT_FUNC(grub_realloc) (void *ptr, grub_size_t size); + void *EXPORT_FUNC(grub_memalign) (grub_size_t align, grub_size_t size); + #endif + ++#define GRUB_MEM_ATTR_R 0x0000000000000004LLU ++#define GRUB_MEM_ATTR_W 0x0000000000000002LLU ++#define GRUB_MEM_ATTR_X 0x0000000000000001LLU ++ ++#ifdef GRUB_MACHINE_EFI ++grub_err_t EXPORT_FUNC(grub_get_mem_attrs) (grub_addr_t addr, ++ grub_size_t size, ++ grub_uint64_t *attrs); ++grub_err_t EXPORT_FUNC(grub_update_mem_attrs) (grub_addr_t addr, ++ grub_size_t size, ++ grub_uint64_t set_attrs, ++ grub_uint64_t clear_attrs); ++#else /* !GRUB_MACHINE_EFI */ ++static inline grub_err_t ++grub_get_mem_attrs (grub_addr_t addr __attribute__((__unused__)), ++ grub_size_t size __attribute__((__unused__)), ++ grub_uint64_t *attrs __attribute__((__unused__))) ++{ ++ return GRUB_ERR_NONE; ++} ++ ++static inline grub_err_t ++grub_update_mem_attrs (grub_addr_t addr __attribute__((__unused__)), ++ grub_size_t size __attribute__((__unused__)), ++ grub_uint64_t set_attrs __attribute__((__unused__)), ++ grub_uint64_t clear_attrs __attribute__((__unused__))) ++{ ++ return GRUB_ERR_NONE; ++} ++#endif /* GRUB_MACHINE_EFI */ ++ + void grub_mm_check_real (const char *file, int line); + #define grub_mm_check() grub_mm_check_real (GRUB_FILE, __LINE__); + diff --git a/0546-nx-set-page-permissions-for-loaded-modules.patch b/0546-nx-set-page-permissions-for-loaded-modules.patch new file mode 100644 index 0000000..0d40b91 --- /dev/null +++ b/0546-nx-set-page-permissions-for-loaded-modules.patch @@ -0,0 +1,266 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Mon, 21 Mar 2022 17:46:35 -0400 +Subject: [PATCH] nx: set page permissions for loaded modules. + +For NX, we need to set write and executable permissions on the sections +of grub modules when we load them. + +On sections with SHF_ALLOC set, which is typically everything except +.modname and the symbol and string tables, this patch clears the Read +Only flag on sections that have the ELF flag SHF_WRITE set, and clears +the No eXecute flag on sections with SHF_EXECINSTR set. In all other +cases it sets both flags. + +Signed-off-by: Peter Jones +[rharwood: arm tgptr -> tgaddr] +Signed-off-by: Robbie Harwood +(cherry-picked from commit ca74904ede0406b594cbedc52ce8e38a6633d2ae) +(cherry picked from commit 2e2e72026f41cf7cffeb46a6a47f3c67d0b3be45) +(cherry picked from commit 736e5ccd9175d31ebea848f3b627f3e99988bb0a) +--- + grub-core/kern/dl.c | 120 +++++++++++++++++++++++++++++++++++++++------------- + include/grub/dl.h | 44 +++++++++++++++++++ + 2 files changed, 134 insertions(+), 30 deletions(-) + +diff --git a/grub-core/kern/dl.c b/grub-core/kern/dl.c +index 5c2153acf9..68d3177f5e 100644 +--- a/grub-core/kern/dl.c ++++ b/grub-core/kern/dl.c +@@ -286,6 +286,8 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + #endif + char *ptr; + ++ grub_dprintf ("modules", "loading segments for \"%s\"\n", mod->name); ++ + arch_addralign = grub_arch_dl_min_alignment (); + + for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); +@@ -385,6 +387,7 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) + ptr += got; + #endif + ++ grub_dprintf ("modules", "done loading segments for \"%s\"\n", mod->name); + return GRUB_ERR_NONE; + } + +@@ -518,23 +521,6 @@ grub_dl_find_section (Elf_Ehdr *e, const char *name) + return s; + return NULL; + } +-static long +-grub_dl_find_section_index (Elf_Ehdr *e, const char *name) +-{ +- Elf_Shdr *s; +- const char *str; +- unsigned i; +- +- s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); +- str = (char *) e + s->sh_offset; +- +- for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); +- i < e->e_shnum; +- i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) +- if (grub_strcmp (str + s->sh_name, name) == 0) +- return (long)i; +- return -1; +-} + + /* Me, Vladimir Serbinenko, hereby I add this module check as per new + GNU module policy. Note that this license check is informative only. +@@ -661,6 +647,7 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) + Elf_Shdr *s; + unsigned i; + ++ grub_dprintf ("modules", "relocating symbols for \"%s\"\n", mod->name); + for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); + i < e->e_shnum; + i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) +@@ -669,24 +656,95 @@ grub_dl_relocate_symbols (grub_dl_t mod, void *ehdr) + grub_dl_segment_t seg; + grub_err_t err; + +- /* Find the target segment. */ +- for (seg = mod->segment; seg; seg = seg->next) +- if (seg->section == s->sh_info) +- break; ++ seg = grub_dl_find_segment(mod, s->sh_info); ++ if (!seg) ++ continue; + +- if (seg) +- { +- if (!mod->symtab) +- return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); ++ if (!mod->symtab) ++ return grub_error (GRUB_ERR_BAD_MODULE, "relocation without symbol table"); + +- err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg); +- if (err) +- return err; +- } ++ err = grub_arch_dl_relocate_symbols (mod, ehdr, s, seg); ++ if (err) ++ return err; + } + ++ grub_dprintf ("modules", "done relocating symbols for \"%s\"\n", mod->name); + return GRUB_ERR_NONE; + } ++ ++static grub_err_t ++grub_dl_set_mem_attrs (grub_dl_t mod, void *ehdr) ++{ ++ unsigned i; ++ const Elf_Shdr *s; ++ const Elf_Ehdr *e = ehdr; ++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) ++ grub_size_t arch_addralign = grub_arch_dl_min_alignment (); ++ grub_addr_t tgaddr; ++ grub_uint64_t tgsz; ++#endif ++ ++ grub_dprintf ("modules", "updating memory attributes for \"%s\"\n", ++ mod->name); ++ for (i = 0, s = (const Elf_Shdr *)((const char *) e + e->e_shoff); ++ i < e->e_shnum; ++ i++, s = (const Elf_Shdr *)((const char *) s + e->e_shentsize)) ++ { ++ grub_dl_segment_t seg; ++ grub_uint64_t set_attrs = GRUB_MEM_ATTR_R; ++ grub_uint64_t clear_attrs = GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X; ++ ++ seg = grub_dl_find_segment(mod, i); ++ if (!seg) ++ continue; ++ ++ if (seg->size == 0 || !(s->sh_flags & SHF_ALLOC)) ++ continue; ++ ++ if (s->sh_flags & SHF_WRITE) ++ { ++ set_attrs |= GRUB_MEM_ATTR_W; ++ clear_attrs &= ~GRUB_MEM_ATTR_W; ++ } ++ ++ if (s->sh_flags & SHF_EXECINSTR) ++ { ++ set_attrs |= GRUB_MEM_ATTR_X; ++ clear_attrs &= ~GRUB_MEM_ATTR_X; ++ } ++ ++ grub_dprintf ("modules", "setting memory attrs for section \"%s\" to -%s%s%s+%s%s%s\n", ++ grub_dl_get_section_name(e, s), ++ (clear_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (clear_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (clear_attrs & GRUB_MEM_ATTR_X) ? "x" : "", ++ (set_attrs & GRUB_MEM_ATTR_R) ? "r" : "", ++ (set_attrs & GRUB_MEM_ATTR_W) ? "w" : "", ++ (set_attrs & GRUB_MEM_ATTR_X) ? "x" : ""); ++ grub_update_mem_attrs ((grub_addr_t)(seg->addr), seg->size, set_attrs, clear_attrs); ++ } ++ ++#if !defined (__i386__) && !defined (__x86_64__) && !defined(__riscv) ++ tgaddr = grub_min((grub_addr_t)mod->tramp, (grub_addr_t)mod->got); ++ tgsz = grub_max((grub_addr_t)mod->trampptr, (grub_addr_t)mod->gotptr) - tgaddr; ++ ++ if (tgsz) ++ { ++ tgsz = ALIGN_UP(tgsz, arch_addralign); ++ ++ grub_dprintf ("modules", "updating attributes for GOT and trampolines\n", ++ mod->name); ++ grub_update_mem_attrs (tgaddr, tgsz, GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_X, ++ GRUB_MEM_ATTR_W); ++ } ++#endif ++ ++ grub_dprintf ("modules", "done updating module memory attributes for \"%s\"\n", ++ mod->name); ++ ++ return GRUB_ERR_NONE; ++} ++ + static void + grub_dl_print_gdb_info (grub_dl_t mod, Elf_Ehdr *e) + { +@@ -752,6 +810,7 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + mod->ref_count = 1; + + grub_dprintf ("modules", "relocating to %p\n", mod); ++ + /* Me, Vladimir Serbinenko, hereby I add this module check as per new + GNU module policy. Note that this license check is informative only. + Modules have to be licensed under GPLv3 or GPLv3+ (optionally +@@ -765,7 +824,8 @@ grub_dl_load_core_noinit (void *addr, grub_size_t size) + || grub_dl_resolve_dependencies (mod, e) + || grub_dl_load_segments (mod, e) + || grub_dl_resolve_symbols (mod, e) +- || grub_dl_relocate_symbols (mod, e)) ++ || grub_dl_relocate_symbols (mod, e) ++ || grub_dl_set_mem_attrs (mod, e)) + { + mod->fini = 0; + grub_dl_unload (mod); +diff --git a/include/grub/dl.h b/include/grub/dl.h +index dd4c3e7ff4..6f46b7e86f 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #endif + + /* +@@ -268,6 +269,49 @@ grub_dl_is_persistent (grub_dl_t mod) + return mod->persistent; + } + ++static inline const char * ++grub_dl_get_section_name (const Elf_Ehdr *e, const Elf_Shdr *s) ++{ ++ Elf_Shdr *str_s; ++ const char *str; ++ ++ str_s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); ++ str = (char *) e + str_s->sh_offset; ++ ++ return str + s->sh_name; ++} ++ ++static inline long ++grub_dl_find_section_index (Elf_Ehdr *e, const char *name) ++{ ++ Elf_Shdr *s; ++ const char *str; ++ unsigned i; ++ ++ s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); ++ str = (char *) e + s->sh_offset; ++ ++ for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); ++ i < e->e_shnum; ++ i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) ++ if (grub_strcmp (str + s->sh_name, name) == 0) ++ return (long)i; ++ return -1; ++} ++ ++/* Return the segment for a section of index N */ ++static inline grub_dl_segment_t ++grub_dl_find_segment (grub_dl_t mod, unsigned n) ++{ ++ grub_dl_segment_t seg; ++ ++ for (seg = mod->segment; seg; seg = seg->next) ++ if (seg->section == n) ++ return seg; ++ ++ return NULL; ++} ++ + #endif + + void * EXPORT_FUNC(grub_resolve_symbol) (const char *name); diff --git a/0547-nx-set-attrs-in-our-kernel-loaders.patch b/0547-nx-set-attrs-in-our-kernel-loaders.patch new file mode 100644 index 0000000..3fddaae --- /dev/null +++ b/0547-nx-set-attrs-in-our-kernel-loaders.patch @@ -0,0 +1,572 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 22 Mar 2022 10:57:07 -0400 +Subject: [PATCH] nx: set attrs in our kernel loaders + +For NX, our kernel loaders need to set write and execute page +permissions on allocated pages and the stack. + +This patch adds those calls. + +Signed-off-by: Peter Jones +[rharwood: fix aarch64 callsites] +(cherry-picked from commit a9f79a997f01a83b36cdfa89ef2e72ac2a17c06c) +[rharwood: double verification] +(cherry picked from commit daba852bd3e4d7b7784b19cf7acf107dc3c0dce4) +[rharwood: stack_attrs initialization, no risc-v, arm renames, arm age] +Signed-off-by: Robbie Harwood +(cherry picked from commit 3a402a2e54b3468b20eae182d98913600a6b68dd) +--- + grub-core/kern/efi/mm.c | 78 ++++++++++++++++++ + grub-core/loader/arm64/linux.c | 16 +++- + grub-core/loader/arm64/xen_boot.c | 4 +- + grub-core/loader/efi/chainloader.c | 11 +++ + grub-core/loader/efi/linux.c | 162 ++++++++++++++++++++++++++++++++++++- + grub-core/loader/i386/efi/linux.c | 26 +++++- + grub-core/loader/i386/linux.c | 5 ++ + include/grub/efi/efi.h | 6 +- + include/grub/efi/linux.h | 17 +++- + include/grub/efi/pe32.h | 2 + + 10 files changed, 312 insertions(+), 15 deletions(-) + +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 2cf4a4883a..8a896144df 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -602,6 +602,82 @@ print_memory_map (grub_efi_memory_descriptor_t *memory_map, + } + #endif + ++grub_addr_t grub_stack_addr = (grub_addr_t)-1ll; ++grub_size_t grub_stack_size = 0; ++ ++static void ++grub_nx_init (void) ++{ ++ grub_uint64_t attrs, stack_attrs; ++ grub_err_t err; ++ grub_addr_t stack_current, stack_end; ++ const grub_uint64_t page_size = 4096; ++ const grub_uint64_t page_mask = ~(page_size - 1); ++ ++ /* ++ * These are to confirm that the flags are working as expected when ++ * debugging. ++ */ ++ attrs = 0; ++ stack_current = (grub_addr_t)grub_nx_init & page_mask; ++ err = grub_get_mem_attrs (stack_current, page_size, &attrs); ++ if (err) ++ { ++ grub_dprintf ("nx", ++ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", ++ stack_current, err); ++ grub_error_pop (); ++ } ++ else ++ grub_dprintf ("nx", "page attrs for grub_nx_init (%p) are %c%c%c\n", ++ grub_dl_load_core, ++ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-'); ++ ++ stack_current = (grub_addr_t)&stack_current & page_mask; ++ err = grub_get_mem_attrs (stack_current, page_size, &stack_attrs); ++ if (err) ++ { ++ grub_dprintf ("nx", ++ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", ++ stack_current, err); ++ grub_error_pop (); ++ } ++ else ++ { ++ attrs = stack_attrs; ++ grub_dprintf ("nx", "page attrs for stack (%p) are %c%c%c\n", ++ &attrs, ++ (attrs & GRUB_MEM_ATTR_R) ? 'r' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'w' : '-', ++ (attrs & GRUB_MEM_ATTR_R) ? 'x' : '-'); ++ } ++ ++ for (stack_end = stack_current + page_size ; ++ !(attrs & GRUB_MEM_ATTR_R); ++ stack_end += page_size) ++ { ++ err = grub_get_mem_attrs (stack_current, page_size, &attrs); ++ if (err) ++ { ++ grub_dprintf ("nx", ++ "grub_get_mem_attrs(0x%"PRIxGRUB_UINT64_T", ...) -> 0x%x\n", ++ stack_current, err); ++ grub_error_pop (); ++ break; ++ } ++ } ++ if (stack_end > stack_current) ++ { ++ grub_stack_addr = stack_current; ++ grub_stack_size = stack_end - stack_current; ++ grub_dprintf ("nx", ++ "detected stack from 0x%"PRIxGRUB_ADDR" to 0x%"PRIxGRUB_ADDR"\n", ++ grub_stack_addr, grub_stack_addr + grub_stack_size - 1); ++ } ++} ++ + void + grub_efi_mm_init (void) + { +@@ -615,6 +691,8 @@ grub_efi_mm_init (void) + grub_efi_uint64_t required_pages; + int mm_status; + ++ grub_nx_init (); ++ + /* Prepare a memory region to store two memory maps. */ + memory_map = grub_efi_allocate_any_pages (2 * BYTES_TO_PAGES (MEMORY_MAP_SIZE)); + if (! memory_map) +diff --git a/grub-core/loader/arm64/linux.c b/grub-core/loader/arm64/linux.c +index 24ab0f0074..37f5d0c7eb 100644 +--- a/grub-core/loader/arm64/linux.c ++++ b/grub-core/loader/arm64/linux.c +@@ -191,7 +191,8 @@ free_params (void) + } + + grub_err_t +-grub_armxx_efi_linux_boot_image (grub_addr_t addr, char *args) ++grub_armxx_efi_linux_boot_image (grub_addr_t addr, grub_size_t size, char *args, ++ int nx_supported) + { + grub_err_t retval; + +@@ -201,7 +202,8 @@ grub_armxx_efi_linux_boot_image (grub_addr_t addr, char *args) + + grub_dprintf ("linux", "linux command line: '%s'\n", args); + +- retval = grub_efi_linux_boot ((char *)addr, handover_offset, (void *)addr); ++ retval = grub_efi_linux_boot (addr, size, handover_offset, ++ (void *)addr, nx_supported); + + /* Never reached... */ + free_params(); +@@ -211,7 +213,10 @@ grub_armxx_efi_linux_boot_image (grub_addr_t addr, char *args) + static grub_err_t + grub_linux_boot (void) + { +- return grub_armxx_efi_linux_boot_image((grub_addr_t)kernel_addr, linux_args); ++ return grub_armxx_efi_linux_boot_image((grub_addr_t)kernel_addr, ++ (grub_size_t)kernel_size, ++ linux_args, ++ 0); + } + + static grub_err_t +@@ -340,6 +345,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + struct grub_armxx_linux_pe_header *pe; + int rc; + grub_err_t err; ++ int nx_supported = 1; + + grub_dl_ref (my_mod); + +@@ -395,6 +401,10 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + } + ++ err = grub_efi_check_nx_image_support((grub_addr_t) kernel_addr, kernel_size, &nx_supported); ++ if (err != GRUB_ERR_NONE) ++ goto fail; ++ + pe = (void *)((unsigned long)kernel_addr + lh.hdr_offset); + handover_offset = pe->opt.entry_addr; + +diff --git a/grub-core/loader/arm64/xen_boot.c b/grub-core/loader/arm64/xen_boot.c +index 1a337866f0..1fd1bbb4bd 100644 +--- a/grub-core/loader/arm64/xen_boot.c ++++ b/grub-core/loader/arm64/xen_boot.c +@@ -266,7 +266,9 @@ xen_boot (void) + return err; + + return grub_armxx_efi_linux_boot_image (xen_hypervisor->start, +- xen_hypervisor->cmdline); ++ xen_hypervisor->size, ++ xen_hypervisor->cmdline, ++ 0); + } + + static void +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 8e658f713e..b72e6bd5e3 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -1055,6 +1055,17 @@ grub_cmd_chainloader (grub_command_t cmd __attribute__ ((unused)), + goto fail; + } + ++ /* ++ * The OS kernel is going to set its own permissions when it takes over ++ * paging a few million instructions from now, and load_image() will set up ++ * anything that's needed based on the section headers, so there's no point ++ * in doing anything but clearing the protection bits here. ++ */ ++ grub_dprintf("nx", "setting attributes for %p (%lu bytes) to %llx\n", ++ (void *)(grub_addr_t)address, fsize, 0llu); ++ grub_update_mem_attrs (address, fsize, ++ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W|GRUB_MEM_ATTR_X, 0); ++ + #if defined (__i386__) || defined (__x86_64__) + if (fsize >= (grub_ssize_t) sizeof (struct grub_macho_fat_header)) + { +diff --git a/grub-core/loader/efi/linux.c b/grub-core/loader/efi/linux.c +index 927d89a90d..421502bd25 100644 +--- a/grub-core/loader/efi/linux.c ++++ b/grub-core/loader/efi/linux.c +@@ -66,16 +66,125 @@ grub_linuxefi_secure_validate (void *data, grub_uint32_t size) + + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wcast-align" ++#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" ++ ++grub_err_t ++grub_efi_check_nx_image_support (grub_addr_t kernel_addr, ++ grub_size_t kernel_size, ++ int *nx_supported) ++{ ++ struct grub_dos_header *doshdr; ++ grub_size_t sz = sizeof (*doshdr); ++ ++ struct grub_pe32_header_32 *pe32; ++ struct grub_pe32_header_64 *pe64; ++ ++ int image_is_compatible = 0; ++ int is_64_bit; ++ ++ if (kernel_size < sz) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); ++ ++ doshdr = (void *)kernel_addr; ++ ++ if ((doshdr->magic & 0xffff) != GRUB_DOS_MAGIC) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel DOS magic is invalid")); ++ ++ sz = doshdr->lfanew + sizeof (*pe32); ++ if (kernel_size < sz) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); ++ ++ pe32 = (struct grub_pe32_header_32 *)(kernel_addr + doshdr->lfanew); ++ pe64 = (struct grub_pe32_header_64 *)pe32; ++ ++ if (grub_memcmp (pe32->signature, GRUB_PE32_SIGNATURE, ++ GRUB_PE32_SIGNATURE_SIZE) != 0) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel PE magic is invalid")); ++ ++ switch (pe32->coff_header.machine) ++ { ++ case GRUB_PE32_MACHINE_ARMTHUMB_MIXED: ++ case GRUB_PE32_MACHINE_I386: ++ is_64_bit = 0; ++ break; ++ case GRUB_PE32_MACHINE_ARM64: ++ case GRUB_PE32_MACHINE_IA64: ++ case GRUB_PE32_MACHINE_X86_64: ++ is_64_bit = 1; ++ break; ++ default: ++ return grub_error (GRUB_ERR_BAD_OS, N_("PE machine type 0x%04hx unknown"), ++ pe32->coff_header.machine); ++ } ++ ++ if (is_64_bit) ++ { ++ sz = doshdr->lfanew + sizeof (*pe64); ++ if (kernel_size < sz) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel is too small")); ++ ++ if (pe64->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT) ++ image_is_compatible = 1; ++ } ++ else ++ { ++ if (pe32->optional_header.dll_characteristics & GRUB_PE32_NX_COMPAT) ++ image_is_compatible = 1; ++ } ++ ++ *nx_supported = image_is_compatible; ++ return GRUB_ERR_NONE; ++} ++ ++grub_err_t ++grub_efi_check_nx_required (int *nx_required) ++{ ++ grub_efi_status_t status; ++ grub_efi_guid_t guid = GRUB_EFI_SHIM_LOCK_GUID; ++ grub_size_t mok_policy_sz = 0; ++ char *mok_policy = NULL; ++ grub_uint32_t mok_policy_attrs = 0; ++ ++ status = grub_efi_get_variable_with_attributes ("MokPolicy", &guid, ++ &mok_policy_sz, ++ (void **)&mok_policy, ++ &mok_policy_attrs); ++ if (status == GRUB_EFI_NOT_FOUND || ++ mok_policy_sz == 0 || ++ mok_policy == NULL) ++ { ++ *nx_required = 0; ++ return GRUB_ERR_NONE; ++ } ++ ++ *nx_required = 0; ++ if (mok_policy_sz < 1 || ++ mok_policy_attrs != (GRUB_EFI_VARIABLE_BOOTSERVICE_ACCESS | ++ GRUB_EFI_VARIABLE_RUNTIME_ACCESS) || ++ (mok_policy[mok_policy_sz-1] & GRUB_MOK_POLICY_NX_REQUIRED)) ++ *nx_required = 1; ++ ++ return GRUB_ERR_NONE; ++} + + typedef void (*handover_func) (void *, grub_efi_system_table_t *, void *); + + grub_err_t +-grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, +- void *kernel_params) ++grub_efi_linux_boot (grub_addr_t kernel_addr, grub_size_t kernel_size, ++ grub_off_t handover_offset, void *kernel_params, ++ int nx_supported) + { + grub_efi_loaded_image_t *loaded_image = NULL; + handover_func hf; + int offset = 0; ++ grub_uint64_t stack_set_attrs = GRUB_MEM_ATTR_R | ++ GRUB_MEM_ATTR_W | ++ GRUB_MEM_ATTR_X; ++ grub_uint64_t stack_clear_attrs = 0; ++ grub_uint64_t kernel_set_attrs = stack_set_attrs; ++ grub_uint64_t kernel_clear_attrs = stack_clear_attrs; ++ grub_uint64_t attrs; ++ int nx_required = 0; + + #ifdef __x86_64__ + offset = 512; +@@ -88,12 +197,57 @@ grub_efi_linux_boot (void *kernel_addr, grub_off_t handover_offset, + */ + loaded_image = grub_efi_get_loaded_image (grub_efi_image_handle); + if (loaded_image) +- loaded_image->image_base = kernel_addr; ++ loaded_image->image_base = (void *)kernel_addr; + else + grub_dprintf ("linux", "Loaded Image base address could not be set\n"); + + grub_dprintf ("linux", "kernel_addr: %p handover_offset: %p params: %p\n", +- kernel_addr, (void *)(grub_efi_uintn_t)handover_offset, kernel_params); ++ (void *)kernel_addr, (void *)handover_offset, kernel_params); ++ ++ ++ if (nx_required && !nx_supported) ++ return grub_error (GRUB_ERR_BAD_OS, N_("kernel does not support NX loading required by policy")); ++ ++ if (nx_supported) ++ { ++ kernel_set_attrs &= ~GRUB_MEM_ATTR_W; ++ kernel_clear_attrs |= GRUB_MEM_ATTR_W; ++ stack_set_attrs &= ~GRUB_MEM_ATTR_X; ++ stack_clear_attrs |= GRUB_MEM_ATTR_X; ++ } ++ ++ grub_dprintf ("nx", "Setting attributes for 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to r%cx\n", ++ kernel_addr, kernel_addr + kernel_size - 1, ++ (kernel_set_attrs & GRUB_MEM_ATTR_W) ? 'w' : '-'); ++ grub_update_mem_attrs (kernel_addr, kernel_size, ++ kernel_set_attrs, kernel_clear_attrs); ++ ++ grub_get_mem_attrs (kernel_addr, 4096, &attrs); ++ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", ++ (grub_addr_t)kernel_addr, ++ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", ++ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", ++ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); ++ if (grub_stack_addr != (grub_addr_t)-1ll) ++ { ++ grub_dprintf ("nx", "Setting attributes for stack at 0x%"PRIxGRUB_ADDR"-0x%"PRIxGRUB_ADDR" to rw%c\n", ++ grub_stack_addr, grub_stack_addr + grub_stack_size - 1, ++ (stack_set_attrs & GRUB_MEM_ATTR_X) ? 'x' : '-'); ++ grub_update_mem_attrs (grub_stack_addr, grub_stack_size, ++ stack_set_attrs, stack_clear_attrs); ++ ++ grub_get_mem_attrs (grub_stack_addr, 4096, &attrs); ++ grub_dprintf ("nx", "permissions for 0x%"PRIxGRUB_ADDR" are %s%s%s\n", ++ grub_stack_addr, ++ (attrs & GRUB_MEM_ATTR_R) ? "r" : "-", ++ (attrs & GRUB_MEM_ATTR_W) ? "w" : "-", ++ (attrs & GRUB_MEM_ATTR_X) ? "x" : "-"); ++ } ++ ++#if defined(__i386__) || defined(__x86_64__) ++ asm volatile ("cli"); ++#endif ++ + hf = (handover_func)((char *)kernel_addr + handover_offset + offset); + grub_dprintf ("linux", "handover_func() = %p\n", hf); + hf (grub_efi_image_handle, grub_efi_system_table, kernel_params); +diff --git a/grub-core/loader/i386/efi/linux.c b/grub-core/loader/i386/efi/linux.c +index 3d4069e4c6..d80d6ec312 100644 +--- a/grub-core/loader/i386/efi/linux.c ++++ b/grub-core/loader/i386/efi/linux.c +@@ -44,7 +44,7 @@ struct grub_linuxefi_context { + grub_uint32_t handover_offset; + struct linux_kernel_params *params; + char *cmdline; +- ++ int nx_supported; + void *initrd_mem; + }; + +@@ -110,13 +110,19 @@ kernel_alloc(grub_efi_uintn_t size, + pages = BYTES_TO_PAGES(size); + grub_dprintf ("linux", "Trying to allocate %lu pages from %p\n", + pages, (void *)max); ++ size = pages * GRUB_EFI_PAGE_SIZE; + + prev_max = max; + addr = grub_efi_allocate_pages_real (max, pages, + max_addresses[i].alloc_type, + memtype); + if (addr) +- grub_dprintf ("linux", "Allocated at %p\n", addr); ++ { ++ grub_dprintf ("linux", "Allocated at %p\n", addr); ++ grub_update_mem_attrs ((grub_addr_t)addr, size, ++ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, ++ GRUB_MEM_ATTR_X); ++ } + } + + while (grub_error_pop ()) +@@ -137,9 +143,11 @@ grub_linuxefi_boot (void *data) + + asm volatile ("cli"); + +- return grub_efi_linux_boot ((char *)context->kernel_mem, ++ return grub_efi_linux_boot ((grub_addr_t)context->kernel_mem, ++ context->kernel_size, + context->handover_offset, +- context->params); ++ context->params, ++ context->nx_supported); + } + + static grub_err_t +@@ -308,7 +316,9 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_uint32_t handover_offset; + struct linux_kernel_params *params = 0; + char *cmdline = 0; ++ int nx_supported = 1; + struct grub_linuxefi_context *context = 0; ++ grub_err_t err; + + grub_dl_ref (my_mod); + +@@ -352,6 +362,13 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + } + } + ++ err = grub_efi_check_nx_image_support ((grub_addr_t)kernel, filelen, ++ &nx_supported); ++ if (err != GRUB_ERR_NONE) ++ return err; ++ grub_dprintf ("linux", "nx is%s supported by this kernel\n", ++ nx_supported ? "" : " not"); ++ + lh = (struct linux_i386_kernel_header *)kernel; + grub_dprintf ("linux", "original lh is at %p\n", kernel); + +@@ -515,6 +532,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + context->handover_offset = handover_offset; + context->params = params; + context->cmdline = cmdline; ++ context->nx_supported = nx_supported; + + grub_loader_set_ex (grub_linuxefi_boot, grub_linuxefi_unload, context, 0); + +diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c +index ef8fcb9e1b..c160ddb0ea 100644 +--- a/grub-core/loader/i386/linux.c ++++ b/grub-core/loader/i386/linux.c +@@ -831,6 +831,11 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), + grub_memset (&linux_params, 0, sizeof (linux_params)); + grub_memcpy (&linux_params.setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1); + ++ grub_dprintf("efi", "setting attributes for %p (%zu bytes) to +rw-x\n", ++ &linux_params, sizeof (lh) + len); ++ grub_update_mem_attrs ((grub_addr_t)&linux_params, sizeof (lh) + len, ++ GRUB_MEM_ATTR_R|GRUB_MEM_ATTR_W, GRUB_MEM_ATTR_X); ++ + linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR; + linux_params.kernel_alignment = (1 << align); + linux_params.ps_mouse = linux_params.padding10 = 0; +diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h +index a635bcb0a9..8ca8c38f9a 100644 +--- a/include/grub/efi/efi.h ++++ b/include/grub/efi/efi.h +@@ -135,12 +135,16 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi_handle_t hnd, + char **device, + char **path); + ++extern grub_addr_t EXPORT_VAR(grub_stack_addr); ++extern grub_size_t EXPORT_VAR(grub_stack_size); ++ + #if defined(__arm__) || defined(__aarch64__) + void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void); + grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *); + #include + grub_err_t grub_armxx_efi_linux_check_image(struct linux_armxx_kernel_header *lh); +-grub_err_t grub_armxx_efi_linux_boot_image(grub_addr_t addr, char *args); ++grub_err_t grub_armxx_efi_linux_boot_image(grub_addr_t addr, grub_size_t size, ++ char *args, int nx_enabled); + #endif + + grub_addr_t grub_efi_section_addr (const char *section); +diff --git a/include/grub/efi/linux.h b/include/grub/efi/linux.h +index 0033d9305a..8130b19590 100644 +--- a/include/grub/efi/linux.h ++++ b/include/grub/efi/linux.h +@@ -22,10 +22,23 @@ + #include + #include + ++#define GRUB_MOK_POLICY_NX_REQUIRED 0x1 ++ + int + EXPORT_FUNC(grub_linuxefi_secure_validate) (void *data, grub_uint32_t size); ++ + grub_err_t +-EXPORT_FUNC(grub_efi_linux_boot) (void *kernel_address, grub_off_t offset, +- void *kernel_param); ++EXPORT_FUNC(grub_efi_linux_boot) (grub_addr_t kernel_address, ++ grub_size_t kernel_size, ++ grub_off_t handover_offset, ++ void *kernel_param, int nx_enabled); ++ ++grub_err_t ++EXPORT_FUNC(grub_efi_check_nx_image_support) (grub_addr_t kernel_addr, ++ grub_size_t kernel_size, ++ int *nx_supported); ++ ++grub_err_t ++EXPORT_FUNC(grub_efi_check_nx_required) (int *nx_required); + + #endif /* ! GRUB_EFI_LINUX_HEADER */ +diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h +index 2241f6317b..45c9f8b756 100644 +--- a/include/grub/efi/pe32.h ++++ b/include/grub/efi/pe32.h +@@ -172,6 +172,8 @@ struct grub_pe32_optional_header + struct grub_pe32_data_directory reserved_entry; + }; + ++#define GRUB_PE32_NX_COMPAT 0x0100 ++ + struct grub_pe64_optional_header + { + grub_uint16_t magic; diff --git a/0548-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch b/0548-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch new file mode 100644 index 0000000..801efca --- /dev/null +++ b/0548-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch @@ -0,0 +1,37 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Peter Jones +Date: Tue, 22 Mar 2022 10:57:20 -0400 +Subject: [PATCH] nx: set the nx compatible flag in EFI grub images + +For NX, we need the grub binary to announce that it is compatible with +the NX feature. This implies that when loading the executable grub +image, several attributes are true: + +- the binary doesn't need an executable stack +- the binary doesn't need sections to be both executable and writable +- the binary knows how to use the EFI Memory Attributes protocol on code + it is loading. + +This patch adds a definition for the PE DLL Characteristics flag +GRUB_PE32_NX_COMPAT, and changes grub-mkimage to set that flag. + +Signed-off-by: Peter Jones +(cherry picked from commit 0c7f1aed5a87f75051b421903a900ccb4bbd795a) +(cherry picked from commit 2f9446d488da96de963f4ffe03b0a1c60a4664f5) +(cherry picked from commit f56671343622b0e0216340cd07e77dfc4e88a97a) +--- + util/mkimage.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/util/mkimage.c b/util/mkimage.c +index 16418e245d..c77025904c 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -1358,6 +1358,7 @@ grub_install_generate_image (const char *dir, const char *prefix, + section = (struct grub_pe32_section_table *)(o64 + 1); + } + ++ PE_OHDR (o32, o64, dll_characteristics) = grub_host_to_target16 (GRUB_PE32_NX_COMPAT); + PE_OHDR (o32, o64, header_size) = grub_host_to_target32 (header_size); + PE_OHDR (o32, o64, entry_addr) = grub_host_to_target32 (layout.start_address); + PE_OHDR (o32, o64, image_base) = 0; diff --git a/0549-Fixup-grub_efi_get_variable-type-in-our-loaders.patch b/0549-Fixup-grub_efi_get_variable-type-in-our-loaders.patch new file mode 100644 index 0000000..8ec08c8 --- /dev/null +++ b/0549-Fixup-grub_efi_get_variable-type-in-our-loaders.patch @@ -0,0 +1,52 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Robbie Harwood +Date: Wed, 11 May 2022 16:37:14 -0400 +Subject: [PATCH] Fixup grub_efi_get_variable() type in our loaders + +Has a new type now that we have 04ae030d0eea8668d4417702d88bf2cf04713d80 +("efi: Return grub_efi_status_t from grub_efi_get_variable()"). + +Signed-off-by: Robbie Harwood +(cherry picked from commit d27cee05d31a9612f0b877d2de727b22cc3ec51a) +--- + grub-core/kern/efi/init.c | 4 ++-- + grub-core/kern/efi/sb.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/grub-core/kern/efi/init.c b/grub-core/kern/efi/init.c +index 501608f743..565ce541f5 100644 +--- a/grub-core/kern/efi/init.c ++++ b/grub-core/kern/efi/init.c +@@ -104,8 +104,8 @@ grub_efi_env_init (void) + struct grub_envblk envblk_s = { NULL, 0 }; + grub_envblk_t envblk = &envblk_s; + +- envblk_s.buf = grub_efi_get_variable ("GRUB_ENV", &efi_grub_guid, +- &envblk_s.size); ++ grub_efi_get_variable ("GRUB_ENV", &efi_grub_guid, &envblk_s.size, ++ &envblk_s.buf); + if (!envblk_s.buf || envblk_s.size < 1) + return; + +diff --git a/grub-core/kern/efi/sb.c b/grub-core/kern/efi/sb.c +index d74778b0ca..f84d7d3080 100644 +--- a/grub-core/kern/efi/sb.c ++++ b/grub-core/kern/efi/sb.c +@@ -35,7 +35,7 @@ grub_efi_secure_boot (void) + char *setup_mode = NULL; + grub_efi_boolean_t ret = 0; + +- secure_boot = grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize); ++ grub_efi_get_variable("SecureBoot", &efi_var_guid, &datasize, &secure_boot); + if (datasize != 1 || !secure_boot) + { + grub_dprintf ("secureboot", "No SecureBoot variable\n"); +@@ -43,7 +43,7 @@ grub_efi_secure_boot (void) + } + grub_dprintf ("secureboot", "SecureBoot: %d\n", *secure_boot); + +- setup_mode = grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize); ++ grub_efi_get_variable("SetupMode", &efi_var_guid, &datasize, &setup_mode); + if (datasize != 1 || !setup_mode) + { + grub_dprintf ("secureboot", "No SetupMode variable\n"); diff --git a/1000-loongarch64-add-support.patch b/1000-loongarch64-add-support.patch deleted file mode 100644 index 2d83c94..0000000 --- a/1000-loongarch64-add-support.patch +++ /dev/null @@ -1,3968 +0,0 @@ -From febee03c70471fd2ce6f0b4cc0f365c32c106ab3 Mon Sep 17 00:00:00 2001 -From: Fedora Ninjas -Date: Wed, 18 May 2022 23:50:45 +0800 -Subject: [PATCH] add loongarch64 support - ---- - conf/Makefile.common | 4 + - configure.ac | 9 + - gentpl.py | 5 +- - grub-core/Makefile.am | 7 + - grub-core/Makefile.core.def | 20 + - grub-core/kern/efi/mm.c | 29 +- - grub-core/kern/elfXX.c | 6 + - grub-core/kern/loongarch64/cache.S | 26 + - grub-core/kern/loongarch64/dl.c | 258 +++++++++ - grub-core/kern/loongarch64/efi/init.c | 76 +++ - grub-core/kern/loongarch64/efi/startup.S | 45 ++ - grub-core/kern/loongarch64/init.c | 47 ++ - grub-core/lib/loongarch64/efi/loongson.c | 505 ++++++++++++++++ - grub-core/lib/loongarch64/efi/loongson_asm.S | 58 ++ - grub-core/lib/loongarch64/relocator.c | 163 ++++++ - grub-core/lib/loongarch64/relocator_asm.S | 51 ++ - grub-core/lib/loongarch64/setjmp.S | 74 +++ - grub-core/lib/loongson/reboot.c | 33 ++ - grub-core/lib/setjmp.S | 2 + - grub-core/loader/efi/chainloader.c | 2 + - grub-core/loader/loongarch64/linux.c | 580 +++++++++++++++++++ - include/grub/dl.h | 2 +- - include/grub/efi/api.h | 3 +- - include/grub/efi/pe32.h | 2 + - include/grub/elf.h | 55 ++ - include/grub/loongarch64/asm.h | 10 + - include/grub/loongarch64/efi/boot.h | 0 - include/grub/loongarch64/efi/loader.h | 25 + - include/grub/loongarch64/efi/loongson.h | 290 ++++++++++ - include/grub/loongarch64/efi/memory.h | 14 + - include/grub/loongarch64/efi/time.h | 0 - include/grub/loongarch64/io.h | 62 ++ - include/grub/loongarch64/kernel.h | 24 + - include/grub/loongarch64/linux.h | 22 + - include/grub/loongarch64/loongarch64.h | 30 + - include/grub/loongarch64/memory.h | 57 ++ - include/grub/loongarch64/relocator.h | 38 ++ - include/grub/loongarch64/setjmp.h | 27 + - include/grub/loongarch64/time.h | 39 ++ - include/grub/loongarch64/types.h | 34 ++ - include/grub/util/install.h | 1 + - util/grub-install-common.c | 43 +- - util/grub-install.c | 16 + - util/grub-mkimagexx.c | 349 ++++++++++- - util/grub-mknetdir.c | 3 +- - util/grub-module-verifier.c | 46 ++ - util/mkimage.c | 16 + - 47 files changed, 3176 insertions(+), 32 deletions(-) - create mode 100644 grub-core/kern/loongarch64/cache.S - create mode 100644 grub-core/kern/loongarch64/dl.c - create mode 100644 grub-core/kern/loongarch64/efi/init.c - create mode 100644 grub-core/kern/loongarch64/efi/startup.S - create mode 100644 grub-core/kern/loongarch64/init.c - create mode 100644 grub-core/lib/loongarch64/efi/loongson.c - create mode 100644 grub-core/lib/loongarch64/efi/loongson_asm.S - create mode 100644 grub-core/lib/loongarch64/relocator.c - create mode 100644 grub-core/lib/loongarch64/relocator_asm.S - create mode 100644 grub-core/lib/loongarch64/setjmp.S - create mode 100644 grub-core/lib/loongson/reboot.c - create mode 100644 grub-core/loader/loongarch64/linux.c - create mode 100644 include/grub/loongarch64/asm.h - create mode 100644 include/grub/loongarch64/efi/boot.h - create mode 100644 include/grub/loongarch64/efi/loader.h - create mode 100644 include/grub/loongarch64/efi/loongson.h - create mode 100644 include/grub/loongarch64/efi/memory.h - create mode 100644 include/grub/loongarch64/efi/time.h - create mode 100644 include/grub/loongarch64/io.h - create mode 100644 include/grub/loongarch64/kernel.h - create mode 100644 include/grub/loongarch64/linux.h - create mode 100644 include/grub/loongarch64/loongarch64.h - create mode 100644 include/grub/loongarch64/memory.h - create mode 100644 include/grub/loongarch64/relocator.h - create mode 100644 include/grub/loongarch64/setjmp.h - create mode 100644 include/grub/loongarch64/time.h - create mode 100644 include/grub/loongarch64/types.h - -diff --git a/conf/Makefile.common b/conf/Makefile.common -index 521cdda..cc1d190 100644 ---- a/conf/Makefile.common -+++ b/conf/Makefile.common -@@ -20,6 +20,10 @@ endif - if COND_powerpc_ieee1275 - CFLAGS_PLATFORM += -mcpu=powerpc - endif -+if COND_loongarch64 -+ CFLAGS_PLATFORM += -fno-strict-aliasing -march=loongarch64 -mabi=lp64 -fno-plt -Wa,-mla-global-with-pcrel -+ CPPFLAGS_PLATFORM = -fno-strict-aliasing -march=loongarch64 -mabi=lp64 -fno-plt -Wa,-mla-global-with-pcrel -+endif - - # Other options - -diff --git a/configure.ac b/configure.ac -index f59a7b8..4715d17 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -116,6 +116,10 @@ case "$target_cpu" in - i[[3456]]86) target_cpu=i386 ;; - amd64) target_cpu=x86_64 ;; - sparc) target_cpu=sparc64 ;; -+ loongarch64) -+ target_cpu=loongarch64 -+ machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_LOONGARCH64=1" -+ ;; - mipsel|mips64el) - target_cpu=mipsel - machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_MIPSEL=1" -@@ -148,6 +152,7 @@ if test "x$with_platform" = x; then - powerpc64-*) platform=ieee1275 ;; - powerpc64le-*) platform=ieee1275 ;; - sparc64-*) platform=ieee1275 ;; -+ loongarch64-*) platform=efi;; - mipsel-*) platform=loongson ;; - mips-*) platform=arc ;; - ia64-*) platform=efi ;; -@@ -196,6 +201,7 @@ case "$target_cpu"-"$platform" in - mipsel-yeeloong) platform=loongson ;; - mipsel-fuloong) platform=loongson ;; - mipsel-loongson) ;; -+ loongarch64-efi) ;; - arm-uboot) ;; - arm-coreboot) ;; - arm-efi) ;; -@@ -251,6 +257,7 @@ case "$platform" in - pc) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_PCBIOS=1" ;; - emu) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_EMU=1" ;; - loongson) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS_LOONGSON=1" ;; -+ loongson64) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_LOONARCH64=1" ;; - qemu_mips) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS_QEMU_MIPS=1" ;; - arc) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_ARC=1" ;; - esac -@@ -2098,6 +2105,8 @@ AM_CONDITIONAL([COND_mips_arc], [test "(" x$target_cpu = xmips -o x$target_cpu = - AM_CONDITIONAL([COND_sparc64_ieee1275], [test x$target_cpu = xsparc64 -a x$platform = xieee1275]) - AM_CONDITIONAL([COND_sparc64_emu], [test x$target_cpu = xsparc64 -a x$platform = xemu]) - AM_CONDITIONAL([COND_powerpc_ieee1275], [test x$target_cpu = xpowerpc -a x$platform = xieee1275]) -+AM_CONDITIONAL([COND_loongarch64_efi], [test x$target_cpu = xloongarch64 -a x$platform = xefi]) -+AM_CONDITIONAL([COND_loongarch64], [test x$target_cpu = xloongarch64]) - AM_CONDITIONAL([COND_mips], [test x$target_cpu = xmips -o x$target_cpu = xmipsel]) - AM_CONDITIONAL([COND_mipsel], [test x$target_cpu = xmipsel]) - AM_CONDITIONAL([COND_mipseb], [test x$target_cpu = xmips]) -diff --git a/gentpl.py b/gentpl.py -index d662c30..3afd642 100644 ---- a/gentpl.py -+++ b/gentpl.py -@@ -32,7 +32,7 @@ GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot", - "mips_loongson", "sparc64_ieee1275", - "powerpc_ieee1275", "mips_arc", "ia64_efi", - "mips_qemu_mips", "arm_uboot", "arm_efi", "arm64_efi", -- "arm_coreboot"] -+ "arm_coreboot", "loongarch64_efi"] - - GROUPS = {} - -@@ -44,13 +44,14 @@ GROUPS["x86_64"] = [ "x86_64_efi" ] - GROUPS["x86"] = GROUPS["i386"] + GROUPS["x86_64"] - GROUPS["mips"] = [ "mips_loongson", "mips_qemu_mips", "mips_arc" ] - GROUPS["sparc64"] = [ "sparc64_ieee1275" ] -+GROUPS["loongarch64"] = [ "loongarch64_efi" ] - GROUPS["powerpc"] = [ "powerpc_ieee1275" ] - GROUPS["arm"] = [ "arm_uboot", "arm_efi", "arm_coreboot" ] - GROUPS["arm64"] = [ "arm64_efi" ] - - # Groups based on firmware - GROUPS["pc"] = [ "i386_pc" ] --GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi" ] -+GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi", "loongarch64_efi"] - GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ] - GROUPS["uboot"] = [ "arm_uboot" ] - GROUPS["xen"] = [ "i386_xen", "x86_64_xen" ] -diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am -index 308ad88..24e2ac3 100644 ---- a/grub-core/Makefile.am -+++ b/grub-core/Makefile.am -@@ -222,6 +222,13 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h - KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h - endif - -+if COND_loongarch64_efi -+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h -+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h -+KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h -+KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loongson.h -+endif -+ - if COND_powerpc_ieee1275 - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h - KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h -diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def -index ef06f8c..74e66d3 100644 ---- a/grub-core/Makefile.core.def -+++ b/grub-core/Makefile.core.def -@@ -95,6 +95,9 @@ kernel = { - arm_coreboot_ldflags = '-Wl,-r,-d'; - arm_coreboot_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; - -+ loongarch64_efi_ldflags = '-Wl,-r,-d'; -+ loongarch64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version -R .eh_frame'; -+ - i386_pc_startup = kern/i386/pc/startup.S; - i386_efi_startup = kern/i386/efi/startup.S; - x86_64_efi_startup = kern/x86_64/efi/startup.S; -@@ -105,6 +108,7 @@ kernel = { - i386_coreboot_startup = kern/i386/coreboot/startup.S; - i386_multiboot_startup = kern/i386/coreboot/startup.S; - mips_startup = kern/mips/startup.S; -+ loongarch64_efi_startup = kern/loongarch64/efi/startup.S; - sparc64_ieee1275_startup = kern/sparc64/ieee1275/crt0.S; - powerpc_ieee1275_startup = kern/powerpc/ieee1275/startup.S; - arm_uboot_startup = kern/arm/startup.S; -@@ -295,6 +299,14 @@ kernel = { - extra_dist = video/sis315_init.c; - mips_loongson = commands/keylayouts.c; - -+ loongarch64 = kern/loongarch64/init.c; -+ loongarch64 = kern/loongarch64/dl.c; -+ loongarch64 = kern/loongarch64/cache.S; -+ loongarch64 = kern/generic/rtc_get_time_ms.c; -+ loongarch64_efi = kern/loongarch64/efi/init.c; -+ loongarch64_efi = lib/loongarch64/efi/loongson.c; -+ loongarch64_efi = lib/loongarch64/efi/loongson_asm.S; -+ - powerpc_ieee1275 = kern/powerpc/cache.S; - powerpc_ieee1275 = kern/powerpc/dl.c; - powerpc_ieee1275 = kern/powerpc/compiler-rt.S; -@@ -810,6 +822,7 @@ module = { - enable = sparc64_ieee1275; - enable = powerpc_ieee1275; - enable = mips_arc; -+ enable = loongarch64_efi; - enable = ia64_efi; - enable = arm_efi; - enable = arm64_efi; -@@ -896,6 +909,7 @@ module = { - i386_qemu = lib/i386/halt.c; - xen = lib/xen/halt.c; - efi = lib/efi/halt.c; -+ loongarch64_efi = commands/acpihalt.c; - ieee1275 = lib/ieee1275/halt.c; - emu = lib/emu/halt.c; - uboot = lib/dummy/halt.c; -@@ -911,6 +925,7 @@ module = { - mips_arc = lib/mips/arc/reboot.c; - mips_loongson = lib/mips/loongson/reboot.c; - mips_qemu_mips = lib/mips/qemu_mips/reboot.c; -+ loongarch64_efi = lib/loongson/reboot.c; - xen = lib/xen/reboot.c; - uboot = lib/uboot/reboot.c; - arm_coreboot = lib/dummy/reboot.c; -@@ -1608,6 +1623,8 @@ module = { - efi = lib/efi/relocator.c; - mips = lib/mips/relocator_asm.S; - mips = lib/mips/relocator.c; -+ loongarch64 = lib/loongarch64/relocator_asm.S; -+ loongarch64 = lib/loongarch64/relocator.c; - powerpc = lib/powerpc/relocator_asm.S; - powerpc = lib/powerpc/relocator.c; - xen = lib/xen/relocator.c; -@@ -1620,6 +1637,7 @@ module = { - extra_dist = kern/powerpc/cache_flush.S; - - enable = mips; -+ enable = loongarch64; - enable = powerpc; - enable = x86; - enable = xen; -@@ -1737,6 +1755,7 @@ module = { - xen = loader/i386/xen.c; - i386_pc = lib/i386/pc/vesa_modes_table.c; - mips = loader/mips/linux.c; -+ loongarch64 = loader/loongarch64/linux.c; - powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c; - sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c; - ia64_efi = loader/ia64/efi/linux.c; -@@ -1838,6 +1857,7 @@ module = { - enable = arm_efi; - enable = arm64_efi; - enable = mips; -+ enable = loongarch64_efi; - }; - - module = { -diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c -index 9e76f23..fb087e3 100644 ---- a/grub-core/kern/efi/mm.c -+++ b/grub-core/kern/efi/mm.c -@@ -157,7 +157,11 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, - grub_efi_physical_address_t ret = address; - - /* Limit the memory access to less than 4GB for 32-bit platforms. */ -+#ifdef GRUB_CPU_LOONGARCH64 -+ if (address > grub_efi_max_usable_address()) -+#else - if (address > GRUB_EFI_MAX_USABLE_ADDRESS) -+#endif - { - grub_error (GRUB_ERR_BAD_ARGUMENT, - N_("invalid memory address (0x%llx > 0x%llx)"), -@@ -177,7 +181,11 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, - { - /* Uggh, the address 0 was allocated... This is too annoying, - so reallocate another one. */ -+#ifdef GRUB_CPU_LOONGARCH64 -+ ret = grub_efi_max_usable_address(); -+#else - ret = address; -+#endif - status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret); - grub_efi_free_pages (0, pages); - if (status != GRUB_EFI_SUCCESS) -@@ -195,9 +203,14 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, - void * - grub_efi_allocate_any_pages (grub_efi_uintn_t pages) - { -- return grub_efi_allocate_pages_real (GRUB_EFI_MAX_USABLE_ADDRESS, -+#ifdef GRUB_CPU_LOONGARCH64 -+ return grub_efi_allocate_pages_real (grub_efi_max_usable_address(), - pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, - GRUB_EFI_LOADER_DATA); -+#else -+ return grub_efi_allocate_pages_real (GRUB_EFI_MAX_USABLE_ADDRESS, -+ pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, -+#endif GRUB_EFI_LOADER_DATA); - } - - void * -@@ -471,7 +484,9 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, - desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) - { - if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY --#if 1 -+#ifdef GRUB_CPU_LOONGARCH64 -+ && desc->physical_start <= grub_efi_max_usable_address() -+#else - && desc->physical_start <= GRUB_EFI_MAX_ALLOCATION_ADDRESS - #endif - && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000 -@@ -486,8 +501,14 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, - - desc->physical_start); - desc->physical_start = 0x100000; - } -- --#if 1 -+#ifdef GRUB_CPU_LOONGARCH64 -+ if (BYTES_TO_PAGES (filtered_desc->physical_start) -+ + filtered_desc->num_pages -+ > BYTES_TO_PAGES_DOWN (grub_efi_max_usable_address())) -+ filtered_desc->num_pages -+ = (BYTES_TO_PAGES_DOWN (grub_efi_max_usable_address()) -+ - BYTES_TO_PAGES (filtered_desc->physical_start)); -+#else - if (BYTES_TO_PAGES (filtered_desc->physical_start) - + filtered_desc->num_pages - > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS)) -diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c -index 1859d18..8b1dce9 100644 ---- a/grub-core/kern/elfXX.c -+++ b/grub-core/kern/elfXX.c -@@ -134,6 +134,12 @@ grub_elfXX_load (grub_elf_t elf, const char *filename, - load_addr &= 0x3FFFFFFFFFFFFFFFULL; - break; - } -+#ifdef GRUB_CPU_LOONGARCH64 -+ grub_uint64_t addr; -+ asm volatile ("csrrd %0, 0x181" : "=r" (addr)); -+ if ((load_addr >> 48) != (addr >> 48)) -+ return grub_error (GRUB_ERR_BAD_OS, "bad address space"); -+#endif - load_addr += (grub_addr_t) load_offset; - - if (load_addr < load_base) -diff --git a/grub-core/kern/loongarch64/cache.S b/grub-core/kern/loongarch64/cache.S -new file mode 100644 -index 0000000..d291c67 ---- /dev/null -+++ b/grub-core/kern/loongarch64/cache.S -@@ -0,0 +1,26 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2009,2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+ -+FUNCTION (grub_arch_sync_caches) -+ jr $ra -+ -+FUNCTION (grub_arch_sync_dma_caches) -+ jr $ra -+ -diff --git a/grub-core/kern/loongarch64/dl.c b/grub-core/kern/loongarch64/dl.c -new file mode 100644 -index 0000000..a6fd387 ---- /dev/null -+++ b/grub-core/kern/loongarch64/dl.c -@@ -0,0 +1,258 @@ -+/* loongarch64/dl.c - arch-dependent part of loadable module support */ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2002,2005,2007,2009,2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+/* Check if EHDR is a valid ELF header. */ -+grub_err_t -+grub_arch_dl_check_header (void *ehdr) -+{ -+ Elf_Ehdr *e = ehdr; -+ -+ /* Check the magic numbers. */ -+ if (e->e_ident[EI_CLASS] != ELFCLASS64 -+ || e->e_ident[EI_DATA] != ELFDATA2LSB -+ || e->e_machine != EM_LOONGARCH64) -+ return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic")); -+ -+ return GRUB_ERR_NONE; -+} -+ -+#pragma GCC diagnostic ignored "-Wcast-align" -+ -+grub_err_t -+grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)), -+ grub_size_t *tramp, grub_size_t *got) -+{ -+ *tramp = 0; -+ *got = 0; -+ return GRUB_ERR_NONE; -+} -+ -+/* Relocate symbols. */ -+grub_err_t -+grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, -+ Elf_Shdr *s, grub_dl_segment_t seg) -+{ -+ Elf_Ehdr *e = ehdr; -+ Elf_Rel *rel, *max; -+ grub_uint64_t oprs[10240]={0}; -+ int opri=-1; -+ grub_uint32_t la_abs = 0; -+ -+ for (rel = (Elf_Rel *) ((char *) e + s->sh_offset), -+ max = (Elf_Rel *) ((char *) rel + s->sh_size); -+ rel < max; -+ rel = (Elf_Rel *) ((char *) rel + s->sh_entsize)) -+ { -+ grub_uint8_t *addr; -+ Elf_Sym *sym; -+ Elf_Addr r_info; -+ grub_uint64_t sym_value; -+ -+ if (seg->size < rel->r_offset) -+ return grub_error (GRUB_ERR_BAD_MODULE, -+ "reloc offset is out of the segment"); -+ -+ r_info = (grub_uint64_t) (rel->r_info); -+ -+ addr = (grub_uint8_t *) ((char*)seg->addr + rel->r_offset); -+ sym = (Elf_Sym *) ((char*)mod->symtab -+ + mod->symsize * ELF_R_SYM (r_info)); -+ sym_value = sym->st_value; -+ if (s->sh_type == SHT_RELA) -+ { -+ sym_value += ((Elf_Rela *) rel)->r_addend; -+ } -+ switch (ELF_R_TYPE (r_info)) -+ { -+ case R_LARCH_64: -+ { -+ *(grub_uint64_t *)addr=(grub_uint64_t)sym_value; -+ } -+ break; -+ case R_LARCH_MARK_LA: -+ { -+ la_abs=1; -+ } -+ break; -+ case R_LARCH_SOP_PUSH_PCREL: -+ { -+ opri++; -+ oprs[opri]=(grub_uint64_t)(sym_value-(grub_uint64_t)addr); -+ } -+ break; -+ case R_LARCH_SOP_PUSH_ABSOLUTE: -+ { -+ opri++; -+ oprs[opri]=(grub_uint64_t)sym_value; -+ } -+ break; -+ case R_LARCH_SOP_PUSH_PLT_PCREL: -+ { -+ opri++; -+ oprs[opri]=(grub_uint64_t)(sym_value-(grub_uint64_t)addr); -+ } -+ break; -+ case R_LARCH_SOP_SUB: -+ { -+ grub_uint64_t opr2=oprs[opri]; -+ opri--; -+ grub_uint64_t opr1=oprs[opri]; -+ opri--; -+ opri++; -+ oprs[opri]=opr1 - opr2; -+ } -+ break; -+ case R_LARCH_SOP_SL: -+ { -+ grub_uint64_t opr2=oprs[opri]; -+ opri--; -+ grub_uint64_t opr1=oprs[opri]; -+ opri--; -+ opri++; -+ oprs[opri]=opr1 << opr2; -+ } -+ break; -+ case R_LARCH_SOP_SR: -+ { -+ grub_uint64_t opr2=oprs[opri]; -+ opri--; -+ grub_uint64_t opr1=oprs[opri]; -+ opri--; -+ opri++; -+ oprs[opri]=opr1 >> opr2; -+ } -+ break; -+ case R_LARCH_SOP_ADD: -+ { -+ grub_uint64_t opr2=oprs[opri]; -+ opri--; -+ grub_uint64_t opr1=oprs[opri]; -+ opri--; -+ opri++; -+ oprs[opri]=opr1 + opr2; -+ } -+ break; -+ case R_LARCH_SOP_AND: -+ { -+ grub_uint64_t opr2=oprs[opri]; -+ opri--; -+ grub_uint64_t opr1=oprs[opri]; -+ opri--; -+ opri++; -+ oprs[opri]=opr1 & opr2; -+ } -+ break; -+ case R_LARCH_SOP_IF_ELSE: -+ { -+ grub_uint64_t opr3=oprs[opri]; -+ opri--; -+ grub_uint64_t opr2=oprs[opri]; -+ opri--; -+ grub_uint64_t opr1=oprs[opri]; -+ opri--; -+ if(opr1){ -+ opri++; -+ oprs[opri]=opr2; -+ } else { -+ opri++; -+ oprs[opri]=opr3; -+ } -+ } -+ break; -+ case R_LARCH_SOP_POP_32_S_10_5: -+ { -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | ((opr1 & 0x1f) << 10); -+ } -+ break; -+ case R_LARCH_SOP_POP_32_U_10_12: -+ { -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | ((opr1 & 0xfff) << 10); -+ } -+ break; -+ case R_LARCH_SOP_POP_32_S_10_12: -+ { -+ if(la_abs==1) -+ la_abs=0; -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *(grub_uint64_t *)addr= (*(grub_uint64_t *)addr) | ((opr1 & 0xfff) << 10); -+ } -+ break; -+ case R_LARCH_SOP_POP_32_S_10_16: -+ { -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *(grub_uint64_t *)addr= (*(grub_uint64_t *)addr) | ((opr1 & 0xffff) << 10); -+ } -+ break; -+ case R_LARCH_SOP_POP_32_S_10_16_S2: -+ { -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *(grub_uint64_t *)addr= (*(grub_uint64_t *)addr) | (((opr1 >> 2) & 0xffff) << 10); -+ } -+ break; -+ case R_LARCH_SOP_POP_32_S_5_20: -+ { -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *(grub_uint64_t *)addr= (*(grub_uint64_t *)addr) | ((opr1 & 0xfffff)<<5) ; -+ } -+ break; -+ case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: -+ { -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | (((opr1 >> 2) & 0xffff) << 10); -+ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | ((opr1 >> 18) & 0x1f); -+ } -+ break; -+ case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: -+ { -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | (((opr1 >> 2) & 0xffff) << 10); -+ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | ((opr1 >> 18) & 0x3ff); -+ } -+ break; -+ default: -+ { -+ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, -+ N_("relocation 0x%x is not implemented yet"), -+ ELF_R_TYPE (r_info)); -+ } -+ break; -+ } -+ } -+ -+ return GRUB_ERR_NONE; -+} -+ -diff --git a/grub-core/kern/loongarch64/efi/init.c b/grub-core/kern/loongarch64/efi/init.c -new file mode 100644 -index 0000000..b21d4f1 ---- /dev/null -+++ b/grub-core/kern/loongarch64/efi/init.c -@@ -0,0 +1,76 @@ -+/* init.c - initialize an arm-based EFI system */ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2013 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+static grub_uint64_t tmr; -+static grub_efi_event_t tmr_evt; -+ -+static grub_uint64_t -+grub_efi_get_time_ms (void) -+{ -+ return tmr; -+} -+ -+static void -+grub_loongson_increment_timer (grub_efi_event_t event __attribute__ ((unused)), -+ void *context __attribute__ ((unused))) -+{ -+ tmr += 10; -+} -+ -+ -+ -+void -+grub_machine_init (void) -+{ -+ grub_efi_boot_services_t *b; -+ -+ grub_efi_init (); -+ -+ b = grub_efi_system_table->boot_services; -+ efi_call_5 (b->create_event, GRUB_EFI_EVT_TIMER | GRUB_EFI_EVT_NOTIFY_SIGNAL, -+ GRUB_EFI_TPL_CALLBACK, grub_loongson_increment_timer, NULL, &tmr_evt); -+ efi_call_3 (b->set_timer, tmr_evt, GRUB_EFI_TIMER_PERIODIC, 100000); -+ -+ grub_install_get_time_ms (grub_efi_get_time_ms); -+} -+ -+void -+grub_machine_fini (int flags) -+{ -+ grub_efi_boot_services_t *b; -+ -+ if (!(flags & GRUB_LOADER_FLAG_NORETURN)) -+ return; -+ -+ b = grub_efi_system_table->boot_services; -+ -+ efi_call_3 (b->set_timer, tmr_evt, GRUB_EFI_TIMER_CANCEL, 0); -+ efi_call_1 (b->close_event, tmr_evt); -+ -+ grub_efi_fini (); -+} -diff --git a/grub-core/kern/loongarch64/efi/startup.S b/grub-core/kern/loongarch64/efi/startup.S -new file mode 100644 -index 0000000..1ffff08 ---- /dev/null -+++ b/grub-core/kern/loongarch64/efi/startup.S -@@ -0,0 +1,45 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2013 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+ -+ .file "startup.S" -+ .text -+ .globl start, _start -+ .align 4 -+ -+FUNCTION(start) -+FUNCTION(_start) -+ /* -+ * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in a1/a0. -+ */ -+ addi.d $sp, $sp, -16 -+ st.d $ra, $sp, 0 -+ -+ la $a2, grub_efi_image_handle -+ st.d $a0, $a2, 0 -+ la $a2, grub_efi_system_table -+ st.d $a1, $a2, 0 -+ -+ bl grub_main -+ -+1: -+ ld.d $ra, $sp, 0 -+ addi.d $sp, $sp, 16 -+ jr $ra -+ -diff --git a/grub-core/kern/loongarch64/init.c b/grub-core/kern/loongarch64/init.c -new file mode 100644 -index 0000000..b2de930 ---- /dev/null -+++ b/grub-core/kern/loongarch64/init.c -@@ -0,0 +1,47 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2009,2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+ -+grub_uint32_t grub_arch_cpuclock; -+ -+/* FIXME: use interrupt to count high. */ -+grub_uint64_t -+grub_get_rtc (void) -+{ -+ static grub_uint32_t high = 0; -+ static grub_uint32_t last = 0; -+ grub_uint32_t low; -+ -+ asm volatile ("csrrd %0, " GRUB_CPU_LOONGARCH_COP0_TIMER_COUNT : "=r" (low)); -+ if (low < last) -+ high++; -+ last = low; -+ -+ return (((grub_uint64_t) high) << 32) | low; -+} -+ -+void -+grub_timer_init (grub_uint32_t cpuclock) -+{ -+ grub_arch_cpuclock = cpuclock; -+ grub_install_get_time_ms (grub_rtc_get_time_ms); -+} -diff --git a/grub-core/lib/loongarch64/efi/loongson.c b/grub-core/lib/loongarch64/efi/loongson.c -new file mode 100644 -index 0000000..8b60d82 ---- /dev/null -+++ b/grub-core/lib/loongarch64/efi/loongson.c -@@ -0,0 +1,505 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+#define loongson_params (&loongson_boot_params->boot_params.efi.smbios.lp) -+#define loongson_boot_params_size ALIGN_UP (sizeof (*loongson_boot_params), 8) -+#define loongson_reset_code_size (&grub_efi_loongson_reset_end - &grub_efi_loongson_reset_start) -+ -+extern grub_uint8_t grub_efi_loongson_reset_start; -+extern grub_uint8_t grub_efi_loongson_reset_end; -+ -+static struct -+{ -+ grub_efi_loongson_boot_params boot_params; -+ grub_efi_loongson_memory_map memory_map; -+ grub_efi_loongson_cpu_info cpu_info; -+ grub_efi_loongson_system_info system_info; -+ grub_efi_loongson_irq_src_routing_table irq_src_routing_table; -+ grub_efi_loongson_interface_info interface_info; -+ grub_efi_loongson_special_attribute special_attribute; -+ grub_efi_loongson_board_devices board_devices; -+} GRUB_PACKED -+* loongson_boot_params; -+ -+static void -+grub_efi_loongson_init_reset_system (void) -+{ -+ grub_efi_loongson_boot_params *boot_params; -+ grub_uint8_t *reset_code_addr = (grub_uint8_t *) loongson_boot_params + -+ loongson_boot_params_size; -+ -+ boot_params = &loongson_boot_params->boot_params; -+ grub_efi_loongson_reset_system_addr = -+ (grub_uint64_t) grub_efi_system_table->runtime_services->reset_system; -+ grub_memcpy (reset_code_addr, &grub_efi_loongson_reset_start, loongson_reset_code_size); -+ grub_arch_sync_caches (reset_code_addr, loongson_reset_code_size); -+ -+ boot_params->reset_system.reset_cold = (grub_uint64_t) reset_code_addr + -+ ((grub_uint64_t) &grub_efi_loongson_reset_cold - -+ (grub_uint64_t) &grub_efi_loongson_reset_start); -+ boot_params->reset_system.reset_warm = (grub_uint64_t) reset_code_addr + -+ ((grub_uint64_t) &grub_efi_loongson_reset_warm - -+ (grub_uint64_t) &grub_efi_loongson_reset_start); -+ boot_params->reset_system.shutdown = (grub_uint64_t) reset_code_addr + -+ ((grub_uint64_t) &grub_efi_loongson_reset_shutdown - -+ (grub_uint64_t) &grub_efi_loongson_reset_start); -+ boot_params->reset_system.do_suspend = (grub_uint64_t) reset_code_addr + -+ ((grub_uint64_t) &grub_efi_loongson_reset_suspend - -+ (grub_uint64_t) &grub_efi_loongson_reset_start); -+} -+ -+static void -+grub_efi_loongson_init_smbios (grub_efi_loongson_smbios_table *smbios_table) -+{ -+ grub_efi_loongson_smbios_table *dst = &loongson_boot_params->boot_params.efi.smbios; -+ -+ dst->vers = smbios_table->vers; -+ dst->vga_bios = smbios_table->vga_bios; -+} -+ -+static void -+grub_efi_loongson_init_cpu_info (grub_efi_loongson_smbios_table *smbios_table) -+{ -+ grub_efi_loongson_cpu_info *src = (void *) smbios_table->lp.cpu_offset; -+ grub_efi_loongson_cpu_info *dst = &loongson_boot_params->cpu_info; -+ -+ if (!src) -+ return; -+ -+ grub_memcpy (dst, src, sizeof (grub_efi_loongson_cpu_info)); -+ loongson_params->cpu_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; -+} -+ -+static void -+grub_efi_loongson_init_system_info (grub_efi_loongson_smbios_table *smbios_table) -+{ -+ grub_efi_loongson_system_info *src = (void *) smbios_table->lp.system_offset; -+ grub_efi_loongson_system_info *dst = &loongson_boot_params->system_info; -+ -+ if (!src) -+ return; -+ -+ grub_memcpy (dst, src, sizeof (grub_efi_loongson_system_info)); -+ loongson_params->system_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; -+} -+ -+static void -+grub_efi_loongson_init_irq_src_routing_table (grub_efi_loongson_smbios_table *smbios_table) -+{ -+ grub_efi_loongson_irq_src_routing_table *src = (void *) smbios_table->lp.irq_offset; -+ grub_efi_loongson_irq_src_routing_table *dst = &loongson_boot_params->irq_src_routing_table; -+ -+ if (!src) -+ return; -+ -+ grub_memcpy (dst, src, sizeof (grub_efi_loongson_irq_src_routing_table)); -+ loongson_params->irq_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; -+} -+ -+static void -+grub_efi_loongson_init_interface_info (grub_efi_loongson_smbios_table *smbios_table) -+{ -+ grub_efi_loongson_interface_info *src = (void *) smbios_table->lp.interface_offset; -+ grub_efi_loongson_interface_info *dst = &loongson_boot_params->interface_info; -+ -+ if (!src) -+ return; -+ -+ grub_memcpy (dst, src, sizeof (grub_efi_loongson_interface_info)); -+ loongson_params->interface_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; -+} -+ -+static void -+grub_efi_loongson_init_special_attribute (grub_efi_loongson_smbios_table *smbios_table) -+{ -+ grub_efi_loongson_special_attribute *src = (void *) smbios_table->lp.special_offset; -+ grub_efi_loongson_special_attribute *dst = &loongson_boot_params->special_attribute; -+ -+ if (!src) -+ return; -+ -+ grub_memcpy (dst, src, sizeof (grub_efi_loongson_special_attribute)); -+ loongson_params->special_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; -+} -+ -+static void -+grub_efi_loongson_init_board_devices (grub_efi_loongson_smbios_table *smbios_table) -+{ -+ grub_efi_loongson_board_devices *src = (void *) smbios_table->lp.boarddev_table_offset; -+ grub_efi_loongson_board_devices *dst = &loongson_boot_params->board_devices; -+ -+ if (!src) -+ return; -+ -+ grub_memcpy (dst, src, sizeof (grub_efi_loongson_board_devices)); -+ loongson_params->boarddev_table_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; -+} -+ -+#define ADD_MEMORY_DESCRIPTOR(desc, size) \ -+ ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) -+ -+static void -+grub_efi_loongson_init_memory_map (grub_efi_loongson_smbios_table *smbios_table, -+ grub_efi_memory_descriptor_t *mmap_buf, -+ grub_efi_uintn_t mmap_size, -+ grub_efi_uintn_t desc_size) -+{ -+ grub_efi_loongson_memory_map *src = (void *) smbios_table->lp.memory_offset; -+ grub_efi_loongson_memory_map *dst = &loongson_boot_params->memory_map; -+ grub_efi_memory_descriptor_t *mmap_end; -+ grub_efi_memory_descriptor_t *desc; -+ grub_efi_memory_descriptor_t *desc_next; -+ grub_efi_uint32_t mem_types_reserved[] = -+ { -+ 1, // GRUB_EFI_RESERVED_MEMORY_TYPE -+ 0, // GRUB_EFI_LOADER_CODE -+ 0, // GRUB_EFI_LOADER_DATA -+ 0, // GRUB_EFI_BOOT_SERVICES_CODE -+ 0, // GRUB_EFI_BOOT_SERVICES_DATA -+ 1, // GRUB_EFI_RUNTIME_SERVICES_CODE -+ 1, // GRUB_EFI_RUNTIME_SERVICES_DATA -+ 0, // GRUB_EFI_CONVENTIONAL_MEMORY -+ 1, // GRUB_EFI_UNUSABLE_MEMORY -+ 0, // GRUB_EFI_ACPI_RECLAIM_MEMORY -+ 0, // GRUB_EFI_ACPI_MEMORY_NVS -+ 1, // GRUB_EFI_MEMORY_MAPPED_IO -+ 1, // GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE -+ 1, // GRUB_EFI_PAL_CODE -+ 1, // GRUB_EFI_PERSISTENT_MEMORY -+ }; -+ grub_uint32_t need_sort = 1; -+ -+ if (!src) -+ return; -+ -+ dst->vers = src->vers; -+ dst->nr_map = 0; -+ dst->mem_freq = src->mem_freq; -+ loongson_params->memory_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; -+ -+ if (!mmap_buf || !mmap_size || !desc_size) -+ return; -+ -+ mmap_end = ADD_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); -+ -+ /* drop reserved */ -+ for (desc = mmap_buf, -+ desc_next = desc; -+ desc < mmap_end; -+ desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) -+ { -+ desc->type = mem_types_reserved[desc->type]; -+ if (desc->type) -+ continue; -+ -+ if (desc != desc_next) -+ *desc_next = *desc; -+ desc_next = ADD_MEMORY_DESCRIPTOR (desc_next, desc_size); -+ } -+ mmap_end = desc_next; -+ -+ /* sort: low->high */ -+ while (need_sort) -+ { -+ need_sort = 0; -+ -+ for (desc = mmap_buf, -+ desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size); -+ (desc < mmap_end) && (desc_next < mmap_end); -+ desc = desc_next, -+ desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) -+ { -+ grub_efi_memory_descriptor_t tmp; -+ -+ if (desc->physical_start <= desc_next->physical_start) -+ continue; -+ -+ tmp = *desc; -+ *desc = *desc_next; -+ *desc_next = tmp; -+ need_sort = 1; -+ } -+ } -+ -+ /* combine continuous memory map */ -+ for (desc = mmap_buf, -+ desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size); -+ desc_next < mmap_end; -+ desc_next = ADD_MEMORY_DESCRIPTOR (desc_next, desc_size)) -+ { -+ grub_efi_physical_address_t prev_end = desc->physical_start + (desc->num_pages << 12); -+ -+ if (prev_end == desc_next->physical_start) -+ { -+ desc->num_pages += desc_next->num_pages; -+ continue; -+ } -+ -+ desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size); -+ grub_memcpy (desc, desc_next, desc_size); -+ } -+ mmap_end = ADD_MEMORY_DESCRIPTOR (desc, desc_size); -+ -+ /* write to loongson memory map */ -+ for (desc = mmap_buf; -+ desc < mmap_end; -+ desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) -+ { -+ grub_efi_physical_address_t physical_start = grub_vtop ((void *) desc->physical_start); -+ grub_efi_physical_address_t physical_end = physical_start + (desc->num_pages << 12); -+ -+ physical_start = ALIGN_UP (physical_start, 0x100000); -+ physical_end = ALIGN_DOWN (physical_end, 0x100000); -+ -+ if (physical_start >= physical_end || (physical_end - physical_start) < 0x100000) -+ continue; -+ -+ dst->map[dst->nr_map].node_id = (desc->physical_start >> 44) & 0xf; -+ dst->map[dst->nr_map].mem_type = GRUB_EFI_LOONGSON_SYSTEM_RAM; -+ dst->map[dst->nr_map].mem_start = physical_start; -+ dst->map[dst->nr_map].mem_size = (physical_end - physical_start) >> 20; -+ -+ grub_dprintf ("loongson", "memory map %03u: 0x%016lx 0x%016lx @ %u\n", -+ dst->nr_map, physical_start, physical_end - physical_start, -+ dst->map[dst->nr_map].node_id); -+ -+ dst->nr_map ++; -+ } -+} -+ -+#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) -+#define SUB_MEMORY_DESCRIPTOR(desc, size) \ -+ ((grub_efi_memory_descriptor_t *) ((char *) (desc) - (size))) -+ -+void -+grub_efi_loongson_alloc_boot_params (void) -+{ -+ grub_efi_memory_descriptor_t *mmap_buf; -+ grub_efi_memory_descriptor_t *mmap_end; -+ grub_efi_memory_descriptor_t *desc; -+ grub_efi_uintn_t mmap_size; -+ grub_efi_uintn_t desc_size; -+ grub_efi_physical_address_t address; -+ grub_efi_allocate_type_t type; -+ grub_efi_uintn_t pages; -+ grub_efi_status_t status; -+ grub_efi_boot_services_t *b; -+ int mm_status; -+ -+ type = GRUB_EFI_ALLOCATE_ADDRESS; -+ pages = BYTES_TO_PAGES (loongson_boot_params_size + loongson_reset_code_size); -+ -+ mmap_size = (1 << 12); -+ mmap_buf = grub_malloc (mmap_size); -+ if (!mmap_buf) -+ grub_fatal ("out of memory!"); -+ -+ mm_status = grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0); -+ if (mm_status == 0) -+ { -+ grub_free (mmap_buf); -+ mmap_size += desc_size * 32; -+ -+ mmap_buf = grub_malloc (mmap_size); -+ if (!mmap_buf) -+ grub_fatal ("out of memory!"); -+ -+ mm_status = grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0); -+ } -+ -+ if (mm_status < 0) -+ grub_fatal ("cannot get memory map!"); -+ -+ mmap_end = ADD_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); -+ -+ for (desc = SUB_MEMORY_DESCRIPTOR (mmap_end, desc_size); -+ desc >= mmap_buf; -+ desc = SUB_MEMORY_DESCRIPTOR (desc, desc_size)) -+ { -+ if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY) -+ continue; -+ if (desc->physical_start >= grub_efi_max_usable_address()) -+ continue; -+ if (desc->num_pages < pages) -+ continue; -+ -+ address = desc->physical_start; -+ break; -+ } -+ -+ grub_free (mmap_buf); -+ -+ b = grub_efi_system_table->boot_services; -+ status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_RUNTIME_SERVICES_DATA, pages, &address); -+ if (status != GRUB_EFI_SUCCESS) -+ grub_fatal ("cannot allocate Loongson boot parameters!"); -+ -+ loongson_boot_params = (void *) ((grub_addr_t) address); -+} -+ -+void -+grub_efi_loongson_free_boot_params (void) -+{ -+ grub_efi_free_pages ((grub_addr_t) loongson_boot_params, -+ BYTES_TO_PAGES (loongson_boot_params_size + loongson_reset_code_size)); -+} -+ -+void * -+grub_efi_loongson_get_smbios_table (void) -+{ -+ static grub_efi_loongson_smbios_table *smbios_table; -+ grub_efi_loongson_boot_params *old_boot_params; -+ struct bootparamsinterface* boot_params; -+ void * tmp_boot_params = NULL; -+ char * p = NULL; -+ if(smbios_table) -+ return smbios_table; -+ -+ tmp_boot_params = grub_efi_loongson_get_boot_params(); -+ if(tmp_boot_params == NULL) -+ { -+ grub_dprintf("loongson", "tmp_boot_params is NULL\n"); -+ return tmp_boot_params; -+ } -+ -+ boot_params = (struct bootparamsinterface *)tmp_boot_params; -+ p = (char *)&(boot_params->signature); -+ if(grub_strncmp(p, "BPI", 3) == 0) -+ { -+ grub_dprintf("loongson", "find new bpi\n"); -+ return boot_params ? boot_params : 0; -+ } -+ else -+ { -+ old_boot_params = (grub_efi_loongson_boot_params *)tmp_boot_params; -+ /* -+ { -+ grub_dprintf("loongson", "smbios addr%llx\n", &old_boot_params->efi.smbios); -+ grub_dprintf("loongson", "smbios vers%d\n", (grub_uint16_t)(&old_boot_params->efi.smbios.vers)); -+ grub_dprintf("loongson", "smbios vga_bios%d\n", &old_boot_params->efi.smbios.vga_bios); -+ grub_dprintf("loongson", "lp memory offset %llx\n", &old_boot_params->efi.smbios.lp.memory_offset); -+ grub_dprintf("loongson", "lp cpu offset %llx\n", &old_boot_params->efi.smbios.lp.cpu_offset); -+ grub_dprintf("loongson", "lp system offset %llx\n", &old_boot_params->efi.smbios.lp.system_offset); -+ grub_dprintf("loongson", "lp irq offset %llx\n", &old_boot_params->efi.smbios.lp.irq_offset); -+ grub_dprintf("loongson", "lp interface offset %llx\n", &old_boot_params->efi.smbios.p.interface_offset); -+ grub_dprintf("loongson", "lp special offset %llx\n", &old_boot_params->efi.smbios.lp.special_offset); -+ grub_dprintf("loongson", "lp boarddev table offset %llx\n", &old_boot_params->efi.smbios.lp.boarddev_table_offset); -+ } -+ */ -+ return old_boot_params ? &old_boot_params->efi.smbios : 0; -+ } -+ -+} -+ -+int -+grub_efi_is_loongson (void) -+{ -+ return grub_efi_loongson_get_smbios_table () ? 1 : 0; -+} -+ -+void * -+grub_efi_loongson_get_boot_params (void) -+{ -+ static void * boot_params = NULL; -+ grub_efi_configuration_table_t *tables; -+ grub_efi_guid_t smbios_guid = GRUB_EFI_LOONGSON_SMBIOS_TABLE_GUID; -+ unsigned int i; -+ -+ if (boot_params) -+ return boot_params; -+ -+ /* Look for Loongson SMBIOS in UEFI config tables. */ -+ tables = grub_efi_system_table->configuration_table; -+ -+ for (i = 0; i < grub_efi_system_table->num_table_entries; i++) -+ if (grub_memcmp (&tables[i].vendor_guid, &smbios_guid, sizeof (smbios_guid)) == 0) -+ { -+ boot_params= tables[i].vendor_table; -+ grub_dprintf ("loongson", "found registered SMBIOS @ %p\n", boot_params); -+ break; -+ } -+ return boot_params; -+} -+ -+grub_uint8_t -+grub_efi_loongson_calculatesum8 (const grub_uint8_t *buffer, grub_efi_uintn_t length) -+{ -+ grub_uint8_t sum; -+ grub_efi_uintn_t count; -+ -+ for (sum = 0, count = 0; count < length; count++) -+ { -+ sum = (grub_uint8_t) (sum + *(buffer + count)); -+ } -+ return sum; -+} -+ -+grub_uint8_t -+grub_efi_loongson_grub_calculatechecksum8 (const grub_uint8_t *buffer, grub_efi_uintn_t length) -+{ -+ grub_uint8_t checksum; -+ -+ checksum = grub_efi_loongson_calculatesum8(buffer, length); -+ -+ return (grub_uint8_t) (0x100 - checksum); -+} -+ -+ -+grub_uint32_t -+grub_efi_loongson_memmap_sort(struct memmap array[], grub_uint32_t length, mem_map * bpmem, grub_uint32_t index, grub_uint32_t memtype) -+{ -+ grub_uint64_t tempmemsize = 0; -+ grub_uint32_t j = 0; -+ grub_uint32_t t = 0; -+ -+ for(j = 0; j < length;) -+ { -+ tempmemsize = array[j].memsize; -+ for(t = j + 1; t < length; t++) -+ { -+ if(array[j].memstart + tempmemsize == array[t].memstart) -+ { -+ tempmemsize += array[t].memsize; -+ } -+ else -+ { -+ break; -+ } -+ } -+ bpmem->map[index].memtype = memtype; -+ bpmem->map[index].memstart = array[j].memstart; -+ bpmem->map[index].memsize = tempmemsize; -+ grub_dprintf("loongson", "map[%d]:type %x, start 0x%llx, end 0x%llx\n", -+ index, -+ bpmem->map[index].memtype, -+ bpmem->map[index].memstart, -+ bpmem->map[index].memstart+ bpmem->map[index].memsize -+ ); -+ j = t; -+ index++; -+ } -+ return index; -+} -+ -diff --git a/grub-core/lib/loongarch64/efi/loongson_asm.S b/grub-core/lib/loongarch64/efi/loongson_asm.S -new file mode 100644 -index 0000000..4a04d34 ---- /dev/null -+++ b/grub-core/lib/loongarch64/efi/loongson_asm.S -@@ -0,0 +1,58 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+ -+ .file "loongson_asm.S" -+ .text -+ -+ .align 4 -+ -+VARIABLE (grub_efi_loongson_reset_start) -+ -+VARIABLE (grub_efi_loongson_reset_system_addr) -+ .dword 0 -+ -+reset_system: -+ bl 1f -+ move $a1, $zero -+1: -+ ld.d $t8, $ra, -16 -+ move $a2, $zero -+ jr $t8 -+ move $a3, $zero -+ -+FUNCTION(grub_efi_loongson_reset_cold) -+ b reset_system -+ li.w $a0, 0 -+ -+FUNCTION(grub_efi_loongson_reset_warm) -+ b reset_system -+ li.w $a0, 1 -+ -+FUNCTION(grub_efi_loongson_reset_shutdown) -+ b reset_system -+ li.w $a0, 2 -+ -+FUNCTION(grub_efi_loongson_reset_suspend) -+ b reset_system -+ li.w $a0, 3 -+ -+VARIABLE (grub_efi_loongson_reset_end) -+ -+ -diff --git a/grub-core/lib/loongarch64/relocator.c b/grub-core/lib/loongarch64/relocator.c -new file mode 100644 -index 0000000..f6c1b01 ---- /dev/null -+++ b/grub-core/lib/loongarch64/relocator.c -@@ -0,0 +1,163 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+#include -+ -+#include -+#include -+ -+extern grub_uint8_t grub_relocator_forward_start; -+extern grub_uint8_t grub_relocator_forward_end; -+extern grub_uint8_t grub_relocator_backward_start; -+extern grub_uint8_t grub_relocator_backward_end; -+ -+#define REGW_SIZEOF (4 * sizeof (grub_uint32_t)) -+#define JUMP_SIZEOF (2 * sizeof (grub_uint32_t)) -+ -+#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator_##x##_end \ -+ - &grub_relocator_##x##_start) -+#define RELOCATOR_SIZEOF(x) (RELOCATOR_SRC_SIZEOF(x) \ -+ + REGW_SIZEOF * 3) -+grub_size_t grub_relocator_align = sizeof (grub_uint64_t); -+grub_size_t grub_relocator_forward_size; -+grub_size_t grub_relocator_backward_size; -+grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF; -+ -+void -+grub_cpu_relocator_init (void) -+{ -+ grub_relocator_forward_size = RELOCATOR_SIZEOF(forward); -+ grub_relocator_backward_size = RELOCATOR_SIZEOF(backward); -+} -+ -+static void -+write_reg (int regn, grub_uint64_t val, void **target) -+{ -+ grub_uint32_t lu12iw=0x14000000; -+ grub_uint32_t ori=0x03800000; -+ grub_uint32_t lu32id=0x16000000; -+ grub_uint32_t lu52id=0x03000000; -+ -+ *(grub_uint32_t *) *target = (lu12iw | (grub_uint32_t)((val & 0xfffff000)>>12<<5) | (grub_uint32_t)regn);; -+ *target = ((grub_uint32_t *) *target) + 1; -+ *(grub_uint32_t *) *target = (ori | (grub_uint32_t)((val & 0xfff)<<10) | (grub_uint32_t)(regn | regn<<5)); -+ *target = ((grub_uint32_t *) *target) + 1; -+ *(grub_uint32_t *) *target = (lu32id | (grub_uint32_t)((val & 0xfffff00000000)>>32<<5) | (grub_uint32_t)regn);; -+ *target = ((grub_uint32_t *) *target) + 1; -+ *(grub_uint32_t *) *target = (lu52id | (grub_uint32_t)((val & 0xfff0000000000000)>>52<<10) | (grub_uint32_t)(regn | regn<<5));; -+ *target = ((grub_uint32_t *) *target) + 1; -+} -+ -+static void -+write_jump (int regn, void **target) -+{ -+ grub_uint32_t andi=0x4c000000; -+ grub_uint32_t nop=0x03400000; -+ -+ *(grub_uint32_t *) *target = (andi | (grub_uint32_t)(regn<<5)); -+ *target = ((grub_uint32_t *) *target) + 1; -+ *(grub_uint32_t *) *target = nop; -+ *target = ((grub_uint32_t *) *target) + 1; -+} -+ -+void -+grub_cpu_relocator_jumper (void *rels, grub_addr_t addr) -+{ -+ write_reg (1, addr, &rels); -+ write_jump (1, &rels); -+} -+ -+void -+grub_cpu_relocator_backward (void *ptr0, void *src, void *dest, -+ grub_size_t size) -+{ -+ void *ptr = ptr0; -+ write_reg (8, (grub_uint64_t) src, &ptr); -+ write_reg (9, (grub_uint64_t) dest, &ptr); -+ write_reg (10, (grub_uint64_t) size, &ptr); -+ grub_memcpy (ptr, &grub_relocator_backward_start, -+ RELOCATOR_SRC_SIZEOF (backward)); -+} -+ -+void -+grub_cpu_relocator_forward (void *ptr0, void *src, void *dest, -+ grub_size_t size) -+{ -+ void *ptr = ptr0; -+ write_reg (8, (grub_uint64_t) src, &ptr); -+ write_reg (9, (grub_uint64_t) dest, &ptr); -+ write_reg (10, (grub_uint64_t) size, &ptr); -+ grub_memcpy (ptr, &grub_relocator_forward_start, -+ RELOCATOR_SRC_SIZEOF (forward)); -+} -+ -+grub_err_t -+grub_relocator64_boot (struct grub_relocator *rel, -+ struct grub_relocator64_state state) -+{ -+ grub_relocator_chunk_t ch; -+ void *ptr; -+ grub_err_t err; -+ void *relst; -+ grub_size_t relsize; -+ grub_size_t stateset_size = 31 * REGW_SIZEOF + JUMP_SIZEOF; -+ unsigned i; -+ grub_addr_t vtarget; -+ -+ err = grub_relocator_alloc_chunk_align (rel, &ch, 0, -+ (0xffffffff - stateset_size) -+ + 1, stateset_size, -+ grub_relocator_align, -+ GRUB_RELOCATOR_PREFERENCE_NONE, 0); -+ if (err) -+ return err; -+ -+ ptr = get_virtual_current_address (ch); -+ for (i = 1; i < 32; i++) -+ write_reg (i, state.gpr[i], &ptr); -+ write_jump (state.jumpreg, &ptr); -+ -+ vtarget = (grub_addr_t) grub_map_memory (get_physical_target_address (ch), -+ stateset_size); -+ -+ err = grub_relocator_prepare_relocs (rel, vtarget, &relst, &relsize); -+ if (err) -+ return err; -+ -+ grub_arch_sync_caches ((void *) relst, relsize); -+ -+ grub_uint64_t val; -+ __asm__ __volatile__( -+ "li.w %0, 0x4\n\t" -+ "csrxchg $r0, %0, 0x0\n\t" -+ : "=r"(val) -+ : -+ : -+ ); -+ -+ ((void (*) (void)) relst) (); -+ -+ /* Not reached. */ -+ return GRUB_ERR_NONE; -+} -diff --git a/grub-core/lib/loongarch64/relocator_asm.S b/grub-core/lib/loongarch64/relocator_asm.S -new file mode 100644 -index 0000000..cf1724d ---- /dev/null -+++ b/grub-core/lib/loongarch64/relocator_asm.S -@@ -0,0 +1,51 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+ -+ .p2align 4 /* force 16-byte alignment */ -+ -+VARIABLE (grub_relocator_forward_start) -+ -+copycont1: -+ ld.d $r11,$r8,0 -+ st.d $r11,$r9,0 -+ addi.d $r8, $r8, 8 -+ addi.d $r10, $r10, -8 -+ addi.d $r9, $r9, 8 -+ bne $r10, $r0, copycont1 -+ -+VARIABLE (grub_relocator_forward_end) -+ -+VARIABLE (grub_relocator_backward_start) -+ -+ add.d $r9, $r9, $r10 -+ add.d $r8, $r8, $r10 -+ /* Backward movsl is implicitly off-by-one. compensate that. */ -+ addi.d $r9, $r9, -8 -+ addi.d $r8, $r8, -8 -+copycont2: -+ ld.w $r11,$r8,0 -+ st.w $r11,$r9,0 -+ addi.d $r8, $r8, -8 -+ addi.d $r10, $r10, -8 -+ addi.d $r9, $r9, -8 -+ bne $r10, $r0, copycont2 -+ -+VARIABLE (grub_relocator_backward_end) -+ -diff --git a/grub-core/lib/loongarch64/setjmp.S b/grub-core/lib/loongarch64/setjmp.S -new file mode 100644 -index 0000000..47db814 ---- /dev/null -+++ b/grub-core/lib/loongarch64/setjmp.S -@@ -0,0 +1,74 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2003,2007,2009 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+ -+ .file "setjmp.S" -+ -+GRUB_MOD_LICENSE "GPLv3+" -+ -+ .text -+ -+/* -+ * int grub_setjmp (grub_jmp_buf env) -+ */ -+FUNCTION(grub_setjmp) -+ GRUB_ASM_REG_S $s0, $a0,0 -+ GRUB_ASM_REG_S $s1, $a0,8 -+ GRUB_ASM_REG_S $s2, $a0,16 -+ GRUB_ASM_REG_S $s3, $a0,24 -+ GRUB_ASM_REG_S $s4, $a0,32 -+ GRUB_ASM_REG_S $s5, $a0,40 -+ GRUB_ASM_REG_S $s6, $a0,48 -+ GRUB_ASM_REG_S $s7, $a0,56 -+ GRUB_ASM_REG_S $s8, $a0,64 -+ GRUB_ASM_REG_S $fp, $a0,72 -+ GRUB_ASM_REG_S $sp, $a0,80 -+ GRUB_ASM_REG_S $ra, $a0,88 -+ move $v0, $zero -+ move $v1, $zero -+ jr $ra -+ nop -+/* -+ * int grub_longjmp (grub_jmp_buf env, int val) -+ */ -+FUNCTION(grub_longjmp) -+ GRUB_ASM_REG_L $s0, $a0,0 -+ GRUB_ASM_REG_L $s1, $a0,8 -+ GRUB_ASM_REG_L $s2, $a0,16 -+ GRUB_ASM_REG_L $s3, $a0,24 -+ GRUB_ASM_REG_L $s4, $a0,32 -+ GRUB_ASM_REG_L $s5, $a0,40 -+ GRUB_ASM_REG_L $s6, $a0,48 -+ GRUB_ASM_REG_L $s7, $a0,56 -+ GRUB_ASM_REG_L $s8, $a0,64 -+ GRUB_ASM_REG_L $fp, $a0,72 -+ GRUB_ASM_REG_L $sp, $a0,80 -+ GRUB_ASM_REG_L $ra, $a0,88 -+ addi.w $v0, $zero, 1 -+ /* -+ * replace: movn $v0, $a1, $a1 -+ */ -+ bnez $a1, .ZW0 -+ addi.d $v0, $a1, 0 -+.ZW0: -+ addi.d $v1,$zero,0 -+ jr $ra -+ nop -diff --git a/grub-core/lib/loongson/reboot.c b/grub-core/lib/loongson/reboot.c -new file mode 100644 -index 0000000..107787a ---- /dev/null -+++ b/grub-core/lib/loongson/reboot.c -@@ -0,0 +1,33 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2011 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+ -+void -+grub_la_reboot (void) -+{ -+ grub_machine_fini (GRUB_LOADER_FLAG_NORETURN); -+ efi_call_4 (grub_efi_system_table->runtime_services->reset_system, -+ GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL); -+ for (;;) ; -+} -diff --git a/grub-core/lib/setjmp.S b/grub-core/lib/setjmp.S -index f6e4905..023dc90 100644 ---- a/grub-core/lib/setjmp.S -+++ b/grub-core/lib/setjmp.S -@@ -15,6 +15,8 @@ - #include "./arm/setjmp.S" - #elif defined(__aarch64__) - #include "./arm64/setjmp.S" -+#elif defined(__loongarch64) -+#include "./loongarch64/setjmp.S" - #else - #error "Unknown target cpu type" - #endif -diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c -index 29663f7..c0ca17d 100644 ---- a/grub-core/loader/efi/chainloader.c -+++ b/grub-core/loader/efi/chainloader.c -@@ -332,6 +332,8 @@ static const grub_uint16_t machine_type __attribute__((__unused__)) = - GRUB_PE32_MACHINE_I386; - #elif defined(__ia64__) - GRUB_PE32_MACHINE_IA64; -+#elif defined(__loongarch64) -+ GRUB_PE32_MACHINE_LOONGARCH64; - #else - #error this architecture is not supported by grub2 - #endif -diff --git a/grub-core/loader/loongarch64/linux.c b/grub-core/loader/loongarch64/linux.c -new file mode 100644 -index 0000000..c769bb2 ---- /dev/null -+++ b/grub-core/loader/loongarch64/linux.c -@@ -0,0 +1,580 @@ -+/* linux.c - boot Linux */ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2003,2004,2005,2007,2009,2010,2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+ -+ -+GRUB_MOD_LICENSE ("GPLv3+"); -+ -+#pragma GCC diagnostic ignored "-Wcast-align" -+ -+typedef unsigned long size_t; -+ -+static grub_dl_t my_mod; -+ -+static int loaded; -+ -+static grub_uint32_t tmp_index = 0; -+static grub_size_t linux_size; -+ -+static struct grub_relocator *relocator; -+static grub_addr_t target_addr, entry_addr; -+static int linux_argc; -+static grub_uint8_t *linux_args_addr; -+static grub_off_t rd_addr_arg_off, rd_size_arg_off; -+static grub_off_t initrd_addr_arg_off; -+static int initrd_loaded = 0; -+ -+ -+static grub_uint32_t j = 0; -+static grub_uint32_t t = 0; -+grub_uint64_t tempMemsize = 0; -+grub_uint32_t free_index = 0; -+grub_uint32_t reserve_index = 0; -+grub_uint32_t acpi_table_index = 0; -+grub_uint32_t acpi_nvs_index = 0; -+ -+static inline grub_size_t -+page_align (grub_size_t size) -+{ -+ return (size + (1 << 12) - 1) & (~((1 << 12) - 1)); -+} -+ -+/* Find the optimal number of pages for the memory map. Is it better to -+ move this code to efi/mm.c? */ -+static grub_efi_uintn_t -+find_mmap_size (void) -+{ -+ static grub_efi_uintn_t mmap_size = 0; -+ -+ if (mmap_size != 0) -+ return mmap_size; -+ -+ mmap_size = (1 << 12); -+ while (1) -+ { -+ int ret; -+ grub_efi_memory_descriptor_t *mmap; -+ grub_efi_uintn_t desc_size; -+ -+ mmap = grub_malloc (mmap_size); -+ if (! mmap) -+ return 0; -+ -+ ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0); -+ grub_free (mmap); -+ -+ if (ret < 0) -+ { -+ grub_error (GRUB_ERR_IO, "cannot get memory map"); -+ return 0; -+ } -+ else if (ret > 0) -+ break; -+ -+ mmap_size += (1 << 12); -+ } -+ -+ -+ /* Increase the size a bit for safety, because GRUB allocates more on -+ later, and EFI itself may allocate more. */ -+ mmap_size += (1 << 12); -+ -+ return page_align (mmap_size); -+} -+ -+static grub_err_t -+grub_linux_boot (void) -+{ -+ struct grub_relocator64_state state; -+ grub_int8_t checksum = 0; -+ grub_efi_memory_descriptor_t * lsdesc = NULL; -+ -+ grub_memset (&state, 0, sizeof (state)); -+ -+ /* Boot the kernel. */ -+ state.gpr[1] = entry_addr; -+ grub_dprintf("loongson", "entry_addr is %p\n", state.gpr[1]); -+ state.gpr[4] = linux_argc; -+ grub_dprintf("loongson", "linux_argc is %d\n", state.gpr[4]); -+ state.gpr[5] = (grub_addr_t) linux_args_addr; -+ grub_dprintf("loongson", "args_addr is %p\n", state.gpr[5]); -+ -+ if(grub_efi_is_loongson ()) -+ { -+ grub_efi_uintn_t mmap_size; -+ grub_efi_uintn_t desc_size; -+ grub_efi_memory_descriptor_t *mmap_buf; -+ grub_err_t err; -+ struct bootparamsinterface * boot_params; -+ void * tmp_boot_params = NULL; -+ grub_efi_uint8_t new_interface_flag = 0; -+ mem_map * new_interface_mem = NULL; -+ char *p = NULL; -+ -+ struct memmap reserve_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; -+ struct memmap free_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; -+ struct memmap acpi_table_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; -+ struct memmap acpi_nvs_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; -+ -+ grub_memset(reserve_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); -+ grub_memset(free_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); -+ grub_memset(acpi_table_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); -+ grub_memset(acpi_nvs_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); -+ -+ tmp_boot_params = grub_efi_loongson_get_boot_params(); -+ if(tmp_boot_params == NULL) -+ { -+ grub_printf("not find param\n"); -+ return -1; -+ } -+ -+ boot_params = (struct bootparamsinterface *)tmp_boot_params; -+ p = (char *)&(boot_params->signature); -+ if(grub_strncmp(p, "BPI", 3) == 0) -+ { -+ /* Check extlist headers */ -+ ext_list * listpointer = NULL; -+ listpointer = boot_params->extlist; -+ for( ;listpointer != NULL; listpointer = listpointer->next) -+ { -+ char *pl= (char *)&(listpointer->signature); -+ if(grub_strncmp(pl, "MEM", 3) == 0) -+ { -+ new_interface_mem = (mem_map *)listpointer; -+ } -+ } -+ -+ new_interface_flag = 1; -+ grub_dprintf("loongson", "get new parameter interface\n"); -+ }else{ -+ new_interface_flag = 0; -+ grub_dprintf("loongson", "get old parameter interface\n"); -+ } -+ state.gpr[6] = (grub_uint64_t)tmp_boot_params; -+ grub_dprintf("loongson", "boot_params is %p\n", state.gpr[6]); -+ -+ mmap_size = find_mmap_size (); -+ if (! mmap_size) -+ return grub_errno; -+ mmap_buf = grub_efi_allocate_any_pages (page_align (mmap_size) >> 12); -+ if (! mmap_buf) -+ return grub_error (GRUB_ERR_IO, "cannot allocate memory map"); -+ err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, NULL, -+ &desc_size, NULL); -+ if (err) -+ return err; -+ -+ if(new_interface_flag) -+ { -+ if (!mmap_buf || !mmap_size || !desc_size) -+ return -1; -+ tmp_index = new_interface_mem -> mapcount; -+ -+ /* -+ According to UEFI SPEC,mmap_buf is the accurate Memory Map array \ -+ now we can fill platform specific memory structure. -+ */ -+ for(lsdesc = mmap_buf; lsdesc < (grub_efi_memory_descriptor_t *)((char *)mmap_buf + mmap_size); -+ lsdesc = (grub_efi_memory_descriptor_t *)((char *)lsdesc + desc_size)) -+ { -+ /* Recovery */ -+ if((lsdesc->type != GRUB_EFI_ACPI_RECLAIM_MEMORY) && \ -+ (lsdesc->type != GRUB_EFI_ACPI_MEMORY_NVS) && \ -+ (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_DATA) && \ -+ (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_CODE) && \ -+ (lsdesc->type != GRUB_EFI_RESERVED_MEMORY_TYPE) && \ -+ (lsdesc->type != GRUB_EFI_PAL_CODE)) -+ { -+ free_mem[free_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM; -+ free_mem[free_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; -+ free_mem[free_index].memsize = lsdesc->num_pages * 4096; -+ free_index++; -+ -+ /*ACPI*/ -+ }else if((lsdesc->type == GRUB_EFI_ACPI_RECLAIM_MEMORY)){ -+ acpi_table_mem[acpi_table_index].memtype = GRUB_EFI_LOONGSON_ACPI_TABLE; -+ acpi_table_mem[acpi_table_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; -+ acpi_table_mem[acpi_table_index].memsize = lsdesc->num_pages * 4096; -+ acpi_table_index++; -+ }else if((lsdesc->type == GRUB_EFI_ACPI_MEMORY_NVS)){ -+ acpi_nvs_mem[acpi_nvs_index].memtype = GRUB_EFI_LOONGSON_ACPI_NVS; -+ acpi_nvs_mem[acpi_nvs_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; -+ acpi_nvs_mem[acpi_nvs_index].memsize = lsdesc->num_pages * 4096; -+ acpi_nvs_index++; -+ -+ /* Reserve */ -+ }else{ -+ reserve_mem[reserve_index].memtype = GRUB_EFI_LOONGSON_MEMORY_RESERVED; -+ reserve_mem[reserve_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; -+ reserve_mem[reserve_index].memsize = lsdesc->num_pages * 4096; -+ reserve_index++; -+ } -+ } -+ -+ /* Recovery sort */ -+ for(j = 0; j < free_index;) -+ { -+ tempMemsize = free_mem[j].memsize; -+ for(t = j + 1; t < free_index; t++) -+ { -+ if((free_mem[j].memstart + tempMemsize == free_mem[t].memstart) && (free_mem[j].memtype == free_mem[t].memtype)) -+ { -+ tempMemsize += free_mem[t].memsize; -+ }else{ -+ break; -+ } -+ } -+ -+ new_interface_mem->map[tmp_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM; -+ new_interface_mem->map[tmp_index].memstart = free_mem[j].memstart; -+ new_interface_mem->map[tmp_index].memsize = tempMemsize; -+ grub_dprintf("loongson", "map[%d]:type %x, start 0x%llx, end 0x%llx\n", -+ tmp_index, -+ new_interface_mem->map[tmp_index].memtype, -+ new_interface_mem->map[tmp_index].memstart, -+ new_interface_mem->map[tmp_index].memstart+ new_interface_mem->map[tmp_index].memsize -+ ); -+ j = t; -+ tmp_index++; -+ } -+ /*ACPI Sort*/ -+ tmp_index = grub_efi_loongson_memmap_sort(acpi_table_mem, acpi_table_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_TABLE); -+ tmp_index = grub_efi_loongson_memmap_sort(acpi_nvs_mem, acpi_nvs_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_NVS); -+ /*Reserve Sort*/ -+ grub_uint64_t loongarch_addr; -+ asm volatile ("csrrd %0, 0x181" : "=r" (loongarch_addr)); -+ if((loongarch_addr & 0xff00000000000000) == 0x9000000000000000){ -+ tmp_index = grub_efi_loongson_memmap_sort(reserve_mem, reserve_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED); -+ }else{ -+ tmp_index = grub_efi_loongson_memmap_sort(reserve_mem, reserve_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED + 1); -+ } -+ -+ new_interface_mem->mapcount = tmp_index; -+ new_interface_mem->header.checksum = 0; -+ -+ checksum = grub_efi_loongson_grub_calculatechecksum8(new_interface_mem, new_interface_mem->header.length); -+ new_interface_mem->header.checksum = checksum; -+ } -+ } -+ -+ state.jumpreg = 1; -+ grub_relocator64_boot (relocator, state); -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_linux_unload (void) -+{ -+ grub_relocator_unload (relocator); -+ grub_dl_unref (my_mod); -+ -+ loaded = 0; -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_linux_load32 (grub_elf_t elf, const char *filename) -+{ -+ Elf32_Addr base; -+ grub_err_t err; -+ grub_uint8_t *playground; -+ -+ /* Linux's entry point incorrectly contains a virtual address. */ -+ entry_addr = elf->ehdr.ehdr32.e_entry; -+ -+ linux_size = grub_elf32_size (elf, &base, 0); -+ if (linux_size == 0) -+ return grub_errno; -+ target_addr = base; -+ linux_size = ALIGN_UP (base + linux_size - base, 8); -+ -+ relocator = grub_relocator_new (); -+ if (!relocator) -+ return grub_errno; -+ -+ { -+ grub_relocator_chunk_t ch; -+ err = grub_relocator_alloc_chunk_addr (relocator, &ch, -+ grub_vtop ((void *) target_addr), -+ linux_size); -+ if (err) -+ return err; -+ playground = get_virtual_current_address (ch); -+ } -+ -+ /* Now load the segments into the area we claimed. */ -+ return grub_elf32_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0); -+} -+ -+static grub_err_t -+grub_linux_load64 (grub_elf_t elf, const char *filename) -+{ -+ Elf64_Addr base; -+ grub_err_t err; -+ grub_uint8_t *playground; -+ -+ /* Linux's entry point incorrectly contains a virtual address. */ -+ entry_addr = elf->ehdr.ehdr64.e_entry; -+ grub_dprintf("loongson", "entry address = %p\n", entry_addr); -+ -+ linux_size = grub_elf64_size (elf, &base, 0); -+ grub_dprintf("loongson", "base = %p\n", base); -+ -+ if (linux_size == 0) -+ return grub_errno; -+ target_addr = base; -+ linux_size = ALIGN_UP (base + linux_size - base, 8); -+ -+ relocator = grub_relocator_new (); -+ // linux_size=0x322fa80; -+ if (!relocator) -+ return grub_errno; -+ -+ { -+ grub_relocator_chunk_t ch; -+ err = grub_relocator_alloc_chunk_addr (relocator, &ch, -+ grub_vtop ((void *) target_addr), -+ linux_size); -+ if (err) -+ return err; -+ playground = get_virtual_current_address (ch); -+ } -+ -+ /* Now load the segments into the area we claimed. */ -+ return grub_elf64_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0); -+} -+ -+static grub_err_t -+grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), -+ int argc, char *argv[]) -+{ -+ grub_elf_t elf = 0; -+ int size; -+ int i; -+ grub_uint64_t *linux_argv; -+ char *linux_args; -+ grub_err_t err; -+ -+ if (argc == 0) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); -+ -+ elf = grub_elf_open (argv[0],GRUB_FILE_TYPE_LINUX_KERNEL); -+ if (! elf) -+ return grub_errno; -+ -+ if (elf->ehdr.ehdr32.e_type != ET_EXEC) -+ { -+ grub_elf_close (elf); -+ return grub_error (GRUB_ERR_UNKNOWN_OS, -+ N_("this ELF file is not of the right type")); -+ } -+ -+ /* Release the previously used memory. */ -+ grub_loader_unset (); -+ loaded = 0; -+ -+ /* For arguments. */ -+ linux_argc = argc; -+ /* Main arguments. */ -+ size = (linux_argc) * sizeof (grub_uint64_t); -+ /* Initrd address and size. */ -+ size += 3 * sizeof (grub_uint64_t); -+ /* NULL terminator. */ -+ size += sizeof (grub_uint64_t); -+ /* First argument is always "a0". */ -+ size += ALIGN_UP (sizeof ("a0"), 4); -+ /* Normal arguments. */ -+ for (i = 1; i < argc; i++) -+ size += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); -+ -+ /* rd arguments. */ -+ size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); -+ size += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); -+ size += ALIGN_UP (sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), 4); -+ -+ size = ALIGN_UP (size, 8); -+ -+ if (grub_elf_is_elf32 (elf)) -+ err = grub_linux_load32 (elf, argv[0]); -+ else -+ if (grub_elf_is_elf64 (elf)) -+ err = grub_linux_load64 (elf, argv[0]); -+ else -+ err = grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic")); -+ -+ grub_elf_close (elf); -+ -+ if (err) -+ return err; -+ -+ { -+ grub_relocator_chunk_t ch; -+ err = grub_relocator_alloc_chunk_align (relocator, &ch, -+ 0, (0xffffffff - size) + 1, -+ size, 8, -+ GRUB_RELOCATOR_PREFERENCE_HIGH, 0); -+ if (err) -+ return err; -+ linux_args_addr = get_virtual_current_address (ch); -+ } -+ -+ linux_argv = (grub_uint64_t *) linux_args_addr; -+ linux_args = (char *) (linux_argv + (linux_argc + 1 + 3)); -+ -+ grub_memcpy (linux_args, "a0", sizeof ("a0")); -+ *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; -+ linux_argv++; -+ linux_args += ALIGN_UP (sizeof ("a0"), 4); -+ -+ for (i = 1; i < argc; i++) -+ { -+ grub_memcpy (linux_args, argv[i], grub_strlen (argv[i]) + 1); -+ *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; -+ linux_argv++; -+ linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); -+ } -+ -+ /* Reserve space for rd arguments. */ -+ rd_addr_arg_off = (grub_uint8_t *) linux_args - linux_args_addr; -+ linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); -+ *linux_argv = 0; -+ linux_argv++; -+ -+ rd_size_arg_off = (grub_uint8_t *) linux_args - linux_args_addr; -+ linux_args += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); -+ *linux_argv = 0; -+ linux_argv++; -+ -+ /* Reserve space for initrd arguments. */ -+ initrd_addr_arg_off = (grub_uint8_t *) linux_args - linux_args_addr; -+ linux_args += ALIGN_UP (sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), 4); -+ *linux_argv = 0; -+ linux_argv++; -+ -+ *linux_argv = 0; -+ -+ grub_loader_set (grub_linux_boot, grub_linux_unload, 0); -+ initrd_loaded = 0; -+ loaded = 1; -+ grub_dl_ref (my_mod); -+ -+ return GRUB_ERR_NONE; -+} -+ -+static grub_err_t -+grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), -+ int argc, char *argv[]) -+{ -+ grub_size_t size = 0; -+ void *initrd_dest; -+ grub_err_t err; -+ struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 }; -+ -+ if (argc == 0) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); -+ -+ if (!loaded) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); -+ -+ if (initrd_loaded) -+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd command can be issued."); -+ -+ if (grub_initrd_init (argc, argv, &initrd_ctx)) -+ goto fail; -+ -+ size = grub_get_initrd_size (&initrd_ctx); -+ -+ { -+ grub_relocator_chunk_t ch; -+ err = grub_relocator_alloc_chunk_align (relocator, &ch, -+ 0, (0xffffffff - size) + 1, -+ size, 0x10000, -+ GRUB_RELOCATOR_PREFERENCE_HIGH, 0); -+ -+ if (err) -+ goto fail; -+ initrd_dest = get_virtual_current_address (ch); -+ } -+ -+ if (grub_initrd_load (&initrd_ctx, argv, initrd_dest)) -+ goto fail; -+ -+ grub_snprintf ((char *) linux_args_addr + rd_addr_arg_off, -+ sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), "rd_start=0x%lx", -+ (grub_uint64_t) initrd_dest); -+ ((grub_uint64_t *) linux_args_addr)[linux_argc] -+ = (grub_uint64_t) ((grub_addr_t) linux_args_addr + rd_addr_arg_off); -+ linux_argc++; -+ -+ grub_snprintf ((char *) linux_args_addr + rd_size_arg_off, -+ sizeof ("rd_size=0xXXXXXXXXXXXXXXXXX"), "rd_size=0x%lx", -+ (grub_uint64_t) size); -+ ((grub_uint64_t *) linux_args_addr)[linux_argc] -+ = (grub_uint64_t) ((grub_addr_t) linux_args_addr + rd_size_arg_off); -+ linux_argc++; -+ -+ -+ grub_snprintf ((char *) linux_args_addr + initrd_addr_arg_off, -+ sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), "initrd=0x%lx,0x%lx", -+ ((grub_uint64_t) initrd_dest & 0xffffffff), (grub_uint64_t) size); -+ ((grub_uint64_t *) linux_args_addr)[linux_argc] -+ = (grub_uint64_t) ((grub_addr_t) linux_args_addr + initrd_addr_arg_off); -+ linux_argc++; -+ -+ initrd_loaded = 1; -+ -+ fail: -+ grub_initrd_close (&initrd_ctx); -+ -+ return grub_errno; -+} -+ -+static grub_command_t cmd_linux, cmd_initrd; -+ -+GRUB_MOD_INIT(linux) -+{ -+ cmd_linux = grub_register_command ("linux", grub_cmd_linux, -+ 0, N_("Load Linux.")); -+ cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, -+ 0, N_("Load initrd.")); -+ my_mod = mod; -+} -+ -+GRUB_MOD_FINI(linux) -+{ -+ grub_unregister_command (cmd_linux); -+ grub_unregister_command (cmd_initrd); -+} -diff --git a/include/grub/dl.h b/include/grub/dl.h -index 6a3e251..c1b6dd9 100644 ---- a/include/grub/dl.h -+++ b/include/grub/dl.h -@@ -314,7 +314,7 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, - #define GRUB_ARCH_DL_GOT_ALIGN 4 - #endif - --#if defined (__aarch64__) || defined (__sparc__) -+#if defined (__aarch64__) || defined (__sparc__) || defined (__loongarch64) - #define GRUB_ARCH_DL_TRAMP_ALIGN 8 - #define GRUB_ARCH_DL_GOT_ALIGN 8 - #endif -diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h -index 37e7b16..049326c 100644 ---- a/include/grub/efi/api.h -+++ b/include/grub/efi/api.h -@@ -2087,7 +2087,8 @@ struct grub_efi_rng_protocol - typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t; - - #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ -- || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) -+ || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ -+ || defined (__loongarch64) - - #define efi_call_0(func) func() - #define efi_call_1(func, a) func(a) -diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h -index c03cc59..be88c54 100644 ---- a/include/grub/efi/pe32.h -+++ b/include/grub/efi/pe32.h -@@ -66,6 +66,7 @@ struct grub_pe32_coff_header - }; - - #define GRUB_PE32_MACHINE_I386 0x14c -+#define GRUB_PE32_MACHINE_LOONGARCH64 0x6264 - #define GRUB_PE32_MACHINE_IA64 0x200 - #define GRUB_PE32_MACHINE_X86_64 0x8664 - #define GRUB_PE32_MACHINE_ARMTHUMB_MIXED 0x01c2 -@@ -329,6 +330,7 @@ struct grub_pe32_fixup_block - #define GRUB_PE32_REL_BASED_IA64_IMM64 9 - #define GRUB_PE32_REL_BASED_DIR64 10 - #define GRUB_PE32_REL_BASED_HIGH3ADJ 11 -+#define GRUB_PE32_REL_BASED_LOONGARCH64 8 - - struct grub_pe32_symbol - { -diff --git a/include/grub/elf.h b/include/grub/elf.h -index c8492f9..2c0b163 100644 ---- a/include/grub/elf.h -+++ b/include/grub/elf.h -@@ -247,6 +247,7 @@ typedef struct - #define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ - #define EM_NUM 95 - #define EM_AARCH64 183 /* ARM 64-bit architecture */ -+#define EM_LOONGARCH64 258 /* LoongArch64 architecture */ - - /* If it is necessary to assign new unofficial EM_* values, please - pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the -@@ -1448,6 +1449,60 @@ typedef struct - #define OHWA0_R4KEOP_CHECKED 0x00000001 - #define OHWA1_R4KEOP_CLEAN 0x00000002 - -+/* LOONGARCH64 relocs. */ -+#define R_LARCH_NONE 0 -+#define R_LARCH_32 1 -+#define R_LARCH_64 2 -+#define R_LARCH_RELATIVE 3 -+#define R_LARCH_COPY 4 -+#define R_LARCH_JUMP_SLOT 5 -+#define R_LARCH_TLS_DTPMOD32 6 -+#define R_LARCH_TLS_DTPMOD64 7 -+#define R_LARCH_TLS_DTPREL32 8 -+#define R_LARCH_TLS_DTPREL64 9 -+#define R_LARCH_TLS_TPREL32 10 -+#define R_LARCH_TLS_TPREL64 11 -+#define R_LARCH_IRELATIVE 12 -+#define R_LARCH_MARK_LA 20 -+#define R_LARCH_MARK_PCREL 21 -+#define R_LARCH_SOP_PUSH_PCREL 22 -+#define R_LARCH_SOP_PUSH_ABSOLUTE 23 -+#define R_LARCH_SOP_PUSH_DUP 24 -+#define R_LARCH_SOP_PUSH_GPREL 25 -+#define R_LARCH_SOP_PUSH_TLS_TPREL 26 -+#define R_LARCH_SOP_PUSH_TLS_GOT 27 -+#define R_LARCH_SOP_PUSH_TLS_GD 28 -+#define R_LARCH_SOP_PUSH_PLT_PCREL 29 -+#define R_LARCH_SOP_ASSERT 30 -+#define R_LARCH_SOP_NOT 31 -+#define R_LARCH_SOP_SUB 32 -+#define R_LARCH_SOP_SL 33 -+#define R_LARCH_SOP_SR 34 -+#define R_LARCH_SOP_ADD 35 -+#define R_LARCH_SOP_AND 36 -+#define R_LARCH_SOP_IF_ELSE 37 -+#define R_LARCH_SOP_POP_32_S_10_5 38 -+#define R_LARCH_SOP_POP_32_U_10_12 39 -+#define R_LARCH_SOP_POP_32_S_10_12 40 -+#define R_LARCH_SOP_POP_32_S_10_16 41 -+#define R_LARCH_SOP_POP_32_S_10_16_S2 42 -+#define R_LARCH_SOP_POP_32_S_5_20 43 -+#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2 44 -+#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2 45 -+#define R_LARCH_SOP_POP_32_U 46 -+#define R_LARCH_ADD8 47 -+#define R_LARCH_ADD16 48 -+#define R_LARCH_ADD24 49 -+#define R_LARCH_ADD32 50 -+#define R_LARCH_ADD64 51 -+#define R_LARCH_SUB8 52 -+#define R_LARCH_SUB16 53 -+#define R_LARCH_SUB24 54 -+#define R_LARCH_SUB32 55 -+#define R_LARCH_SUB64 56 -+#define R_LARCH_GNU_VTINHERIT 57 -+#define R_LARCH_GNU_VTENTRY 58 -+ - /* MIPS relocs. */ - - #define R_MIPS_NONE 0 /* No reloc */ -diff --git a/include/grub/loongarch64/asm.h b/include/grub/loongarch64/asm.h -new file mode 100644 -index 0000000..c3e77e9 ---- /dev/null -+++ b/include/grub/loongarch64/asm.h -@@ -0,0 +1,10 @@ -+#ifndef GRUB_LOONGARCH64_ASM_HEADER -+#define GRUB_LOONGARCH64_ASM_HEADER 1 -+ -+#define GRUB_ASM_T4 $a4 -+#define GRUB_ASM_T5 $a5 -+#define GRUB_ASM_SZREG 8 -+#define GRUB_ASM_REG_S st.d -+#define GRUB_ASM_REG_L ld.d -+ -+#endif -diff --git a/include/grub/loongarch64/efi/boot.h b/include/grub/loongarch64/efi/boot.h -new file mode 100644 -index 0000000..e69de29 -diff --git a/include/grub/loongarch64/efi/loader.h b/include/grub/loongarch64/efi/loader.h -new file mode 100644 -index 0000000..71a0159 ---- /dev/null -+++ b/include/grub/loongarch64/efi/loader.h -@@ -0,0 +1,25 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2002,2003,2004,2006,2007,2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_LOADER_MACHINE_HEADER -+#define GRUB_LOADER_MACHINE_HEADER 1 -+ -+#include -+#include -+ -+#endif /* ! GRUB_LOADER_MACHINE_HEADER */ -diff --git a/include/grub/loongarch64/efi/loongson.h b/include/grub/loongarch64/efi/loongson.h -new file mode 100644 -index 0000000..fa32ef5 ---- /dev/null -+++ b/include/grub/loongarch64/efi/loongson.h -@@ -0,0 +1,290 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_EFI_LOONGSON_HEADER -+#define GRUB_EFI_LOONGSON_HEADER 1 -+ -+#include -+ -+#include -+ -+#define GRUB_EFI_LOONGSON_SMBIOS_TABLE_GUID \ -+ { 0x4660f721, 0x2ec5, 0x416a, \ -+ { 0x89, 0x9a, 0x43, 0x18, 0x02, 0x50, 0xa0, 0xc9 } \ -+ } -+ -+#define GRUB_EFI_LOONGSON_MMAP_MAX 128 -+typedef enum -+ { -+ GRUB_EFI_LOONGSON_SYSTEM_RAM = 1, -+ GRUB_EFI_LOONGSON_MEMORY_RESERVED, -+ GRUB_EFI_LOONGSON_ACPI_TABLE, -+ GRUB_EFI_LOONGSON_ACPI_NVS, -+ GRUB_EFI_LOONGSON_MAX_MEMORY_TYPE -+ } -+grub_efi_loongson_memory_type; -+ -+typedef struct -+{ -+ grub_uint16_t vers; /* version */ -+ grub_uint32_t nr_map; /* number of memory_maps */ -+ grub_uint32_t mem_freq; /* memory frequence */ -+ struct mem_map { -+ grub_uint32_t node_id; /* node_id which memory attached to */ -+ grub_uint32_t mem_type; /* system memory, pci memory, pci io, etc. */ -+ grub_uint64_t mem_start; /* memory map start address */ -+ grub_uint32_t mem_size; /* each memory_map size, not the total size */ -+ } map[GRUB_EFI_LOONGSON_MMAP_MAX]; -+} GRUB_PACKED -+grub_efi_loongson_memory_map; -+ -+/* -+ * Capability and feature descriptor structure for LOONGARCH CPU -+ */ -+typedef struct -+{ -+ grub_uint16_t vers; /* version */ -+ grub_uint32_t processor_id; /* PRID, e.g. 6305, 6306 */ -+ grub_uint32_t cputype; /* Loongson_3A/3B, etc. */ -+ grub_uint32_t total_node; /* num of total numa nodes */ -+ grub_uint16_t cpu_startup_core_id; /* Boot core id */ -+ grub_uint16_t reserved_cores_mask; -+ grub_uint32_t cpu_clock_freq; /* cpu_clock */ -+ grub_uint32_t nr_cpus; -+} GRUB_PACKED -+grub_efi_loongson_cpu_info; -+ -+#define GRUB_EFI_LOONGSON_MAX_UARTS 64 -+ -+typedef struct -+{ -+ grub_uint32_t iotype; /* see include/linux/serial_core.h */ -+ grub_uint32_t uartclk; -+ grub_uint32_t int_offset; -+ grub_uint64_t uart_base; -+} GRUB_PACKED -+grub_efi_loongson_uart_device; -+ -+#define GRUB_EFI_LOONGSON_MAX_SENSORS 64 -+ -+typedef struct -+{ -+ char name[32]; /* a formal name */ -+ char label[64]; /* a flexible description */ -+ grub_uint32_t type; /* SENSOR_* */ -+ grub_uint32_t id; /* instance id of a sensor-class */ -+ grub_uint32_t fan_policy; -+ grub_uint32_t fan_percent; /* only for constant speed policy */ -+ grub_uint64_t base_addr; /* base address of device registers */ -+} GRUB_PACKED -+grub_efi_loongson_sensor_device; -+ -+typedef struct -+{ -+ grub_uint16_t vers; /* version */ -+ grub_uint32_t ccnuma_smp; /* 0: no numa; 1: has numa */ -+ grub_uint32_t sing_double_channel; /* 1:single; 2:double */ -+ grub_uint32_t nr_uarts; -+ grub_efi_loongson_uart_device uarts[GRUB_EFI_LOONGSON_MAX_UARTS]; -+ grub_uint32_t nr_sensors; -+ grub_efi_loongson_sensor_device sensors[GRUB_EFI_LOONGSON_MAX_SENSORS]; -+ char has_ec; -+ char ec_name[32]; -+ grub_uint64_t ec_base_addr; -+ char has_tcm; -+ char tcm_name[32]; -+ grub_uint64_t tcm_base_addr; -+ grub_uint64_t workarounds; /* see workarounds.h */ -+} GRUB_PACKED -+grub_efi_loongson_system_info; -+ -+typedef struct -+{ -+ grub_uint16_t vers; -+ grub_uint16_t size; -+ grub_uint16_t rtr_bus; -+ grub_uint16_t rtr_devfn; -+ grub_uint32_t vendor; -+ grub_uint32_t device; -+ grub_uint32_t PIC_type; /* conform use HT or PCI to route to CPU-PIC */ -+ grub_uint64_t ht_int_bit; /* 3A: 1<<24; 3B: 1<<16 */ -+ grub_uint64_t ht_enable; /* irqs used in this PIC */ -+ grub_uint32_t node_id; /* node id: 0x0-0; 0x1-1; 0x10-2; 0x11-3 */ -+ grub_uint64_t pci_mem_start_addr; -+ grub_uint64_t pci_mem_end_addr; -+ grub_uint64_t pci_io_start_addr; -+ grub_uint64_t pci_io_end_addr; -+ grub_uint64_t pci_config_addr; -+ grub_uint32_t dma_mask_bits; -+} GRUB_PACKED -+grub_efi_loongson_irq_src_routing_table; -+ -+typedef struct -+{ -+ grub_uint16_t vers; /* version */ -+ grub_uint16_t size; -+ grub_uint8_t flag; -+ char description[64]; -+} GRUB_PACKED -+grub_efi_loongson_interface_info; -+ -+#define GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER 128 -+ -+typedef struct -+{ -+ grub_uint64_t start; /* resource start address */ -+ grub_uint64_t end; /* resource end address */ -+ char name[64]; -+ grub_uint32_t flags; -+} -+grub_efi_loongson_resource; -+ -+/* arch specific additions */ -+typedef struct -+{ -+} -+grub_efi_loongson_archdev_data; -+ -+typedef struct -+{ -+ char name[64]; /* hold the device name */ -+ grub_uint32_t num_resources; /* number of device_resource */ -+ /* for each device's resource */ -+ grub_efi_loongson_resource resource[GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER]; -+ /* arch specific additions */ -+ grub_efi_loongson_archdev_data archdata; -+} -+grub_efi_loongson_board_devices; -+ -+typedef struct -+{ -+ grub_uint16_t vers; /* version */ -+ char special_name[64]; /* special_atribute_name */ -+ grub_uint32_t loongson_special_type; /* type of special device */ -+ /* for each device's resource */ -+ grub_efi_loongson_resource resource[GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER]; -+} -+grub_efi_loongson_special_attribute; -+ -+typedef struct -+{ -+ grub_uint64_t memory_offset; /* efi_loongson_memory_map struct offset */ -+ grub_uint64_t cpu_offset; /* efi_loongson_cpuinfo struct offset */ -+ grub_uint64_t system_offset; /* efi_loongson_system_info struct offset */ -+ grub_uint64_t irq_offset; /* efi_loongson_irq_src_routing_table struct offset */ -+ grub_uint64_t interface_offset; /* interface_info struct offset */ -+ grub_uint64_t special_offset; /* efi_loongson_special_attribute struct offset */ -+ grub_uint64_t boarddev_table_offset; /* efi_loongson_board_devices offset */ -+} -+grub_efi_loongson_params; -+ -+typedef struct -+{ -+ grub_uint16_t vers; /* version */ -+ grub_uint64_t vga_bios; /* vga_bios address */ -+ grub_efi_loongson_params lp; -+} -+grub_efi_loongson_smbios_table; -+ -+typedef struct -+{ -+ grub_uint64_t reset_cold; -+ grub_uint64_t reset_warm; -+ grub_uint64_t reset_type; -+ grub_uint64_t shutdown; -+ grub_uint64_t do_suspend; /* NULL if not support */ -+} -+grub_efi_loongson_reset_system; -+ -+typedef struct -+{ -+ grub_uint64_t mps; /* MPS table */ -+ grub_uint64_t acpi; /* ACPI table (IA64 ext 0.71) */ -+ grub_uint64_t acpi20; /* ACPI table (ACPI 2.0) */ -+ grub_efi_loongson_smbios_table smbios; /* SM BIOS table */ -+ grub_uint64_t sal_systab; /* SAL system table */ -+ grub_uint64_t boot_info; /* boot info table */ -+} -+grub_efi_loongson; -+ -+typedef struct -+{ -+ grub_efi_loongson efi; -+ grub_efi_loongson_reset_system reset_system; -+} -+grub_efi_loongson_boot_params; -+ -+extern grub_uint64_t grub_efi_loongson_reset_system_addr; -+ -+extern void grub_efi_loongson_reset_cold (void); -+extern void grub_efi_loongson_reset_warm (void); -+extern void grub_efi_loongson_reset_shutdown (void); -+extern void grub_efi_loongson_reset_suspend (void); -+ -+void grub_efi_loongson_alloc_boot_params (void); -+void grub_efi_loongson_free_boot_params (void); -+void * grub_efi_loongson_get_smbios_table (void); -+ -+int EXPORT_FUNC(grub_efi_is_loongson) (void); -+ -+grub_uint8_t -+EXPORT_FUNC(grub_efi_loongson_calculatesum8) (const grub_uint8_t *Buffer, grub_efi_uintn_t Length); -+ -+grub_uint8_t -+EXPORT_FUNC(grub_efi_loongson_grub_calculatechecksum8) (const grub_uint8_t *Buffer, grub_efi_uintn_t Length); -+ -+ -+void * -+EXPORT_FUNC(grub_efi_loongson_get_boot_params) (void); -+ -+typedef struct _extention_list_hdr{ -+ grub_uint64_t signature; -+ grub_uint32_t length; -+ grub_uint8_t revision; -+ grub_uint8_t checksum; -+ struct _extention_list_hdr *next; -+}GRUB_PACKED -+ext_list; -+ -+typedef struct bootparamsinterface { -+ grub_uint64_t signature; //{'B', 'P', 'I', '_', '0', '_', '1'} -+ grub_efi_system_table_t *systemtable; -+ ext_list *extlist; -+}GRUB_PACKED -+bootparamsinterface; -+ -+typedef struct { -+ ext_list header; // {'M', 'E', 'M'} -+ grub_uint8_t mapcount; -+ struct GRUB_PACKED memmap { -+ grub_uint32_t memtype; -+ grub_uint64_t memstart; -+ grub_uint64_t memsize; -+ } map[GRUB_EFI_LOONGSON_MMAP_MAX]; -+}GRUB_PACKED -+mem_map; -+ -+typedef struct { -+ ext_list header; // {VBIOS} -+ grub_uint64_t vbiosaddr; -+}GRUB_PACKED -+vbios; -+ -+grub_uint32_t -+EXPORT_FUNC (grub_efi_loongson_memmap_sort) (struct memmap array[], grub_uint32_t length, mem_map * bpmem, grub_uint32_t index, grub_uint32_t memtype); -+#endif /* ! GRUB_EFI_LOONGSON_HEADER */ -diff --git a/include/grub/loongarch64/efi/memory.h b/include/grub/loongarch64/efi/memory.h -new file mode 100644 -index 0000000..b8556c7 ---- /dev/null -+++ b/include/grub/loongarch64/efi/memory.h -@@ -0,0 +1,14 @@ -+#ifndef GRUB_MEMORY_CPU_HEADER -+#include -+ -+#define GRUB_EFI_MAX_USABLE_ADDRESS 0x9800000fffffffffUL -+#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS -+ -+static inline grub_uint64_t grub_efi_max_usable_address(void) -+{ -+ grub_uint64_t addr; -+ asm volatile ("csrrd %0, 0x181" : "=r" (addr)); -+ return addr |= 0xffffffffffUL; -+} -+ -+#endif /* ! GRUB_MEMORY_CPU_HEADER */ -diff --git a/include/grub/loongarch64/efi/time.h b/include/grub/loongarch64/efi/time.h -new file mode 100644 -index 0000000..e69de29 -diff --git a/include/grub/loongarch64/io.h b/include/grub/loongarch64/io.h -new file mode 100644 -index 0000000..5f34103 ---- /dev/null -+++ b/include/grub/loongarch64/io.h -@@ -0,0 +1,62 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2009,2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_IO_H -+#define GRUB_IO_H 1 -+ -+#include -+ -+typedef grub_addr_t grub_port_t; -+ -+static __inline unsigned char -+grub_inb (grub_port_t port) -+{ -+ return *(volatile grub_uint8_t *) port; -+} -+ -+static __inline unsigned short int -+grub_inw (grub_port_t port) -+{ -+ return *(volatile grub_uint16_t *) port; -+} -+ -+static __inline unsigned int -+grub_inl (grub_port_t port) -+{ -+ return *(volatile grub_uint32_t *) port; -+} -+ -+static __inline void -+grub_outb (unsigned char value, grub_port_t port) -+{ -+ *(volatile grub_uint8_t *) port = value; -+} -+ -+static __inline void -+grub_outw (unsigned short int value, grub_port_t port) -+{ -+ *(volatile grub_uint16_t *) port = value; -+} -+ -+static __inline void -+grub_outl (unsigned int value, grub_port_t port) -+{ -+ *(volatile grub_uint32_t *) port = value; -+} -+ -+#endif /* _SYS_IO_H */ -diff --git a/include/grub/loongarch64/kernel.h b/include/grub/loongarch64/kernel.h -new file mode 100644 -index 0000000..909d539 ---- /dev/null -+++ b/include/grub/loongarch64/kernel.h -@@ -0,0 +1,24 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2005,2006,2007,2008,2009,2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_KERNEL_CPU_HEADER -+#define GRUB_KERNEL_CPU_HEADER 1 -+ -+#include -+ -+#endif /* ! GRUB_KERNEL_MACHINE_HEADER */ -diff --git a/include/grub/loongarch64/linux.h b/include/grub/loongarch64/linux.h -new file mode 100644 -index 0000000..cbf8775 ---- /dev/null -+++ b/include/grub/loongarch64/linux.h -@@ -0,0 +1,22 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2013 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_LOONGARCH64_LINUX_HEADER -+#define GRUB_LOONGARCH64_LINUX_HEADER 1 -+ -+#endif /* ! GRUB_LOONGARCH64_LINUX_HEADER */ -diff --git a/include/grub/loongarch64/loongarch64.h b/include/grub/loongarch64/loongarch64.h -new file mode 100644 -index 0000000..ea3be3d ---- /dev/null -+++ b/include/grub/loongarch64/loongarch64.h -@@ -0,0 +1,30 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2010,2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_REGISTERS_CPU_HEADER -+#define GRUB_REGISTERS_CPU_HEADER 1 -+ -+#ifdef ASM_FILE -+#define GRUB_CPU_REGISTER_WRAP(x) x -+#else -+#define GRUB_CPU_REGISTER_WRAP(x) #x -+#endif -+ -+#define GRUB_CPU_LOONGARCH_COP0_TIMER_COUNT GRUB_CPU_REGISTER_WRAP(9) -+ -+#endif -diff --git a/include/grub/loongarch64/memory.h b/include/grub/loongarch64/memory.h -new file mode 100644 -index 0000000..03398b3 ---- /dev/null -+++ b/include/grub/loongarch64/memory.h -@@ -0,0 +1,57 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_MEMORY_CPU_HEADER -+#define GRUB_MEMORY_CPU_HEADER 1 -+ -+#ifndef ASM_FILE -+#include -+#include -+#include -+#endif -+ -+#ifndef ASM_FILE -+ -+typedef grub_addr_t grub_phys_addr_t; -+ -+static inline grub_phys_addr_t -+grub_vtop (void *a) -+{ -+ if (-1 == ((grub_int64_t) a >> 32)) -+ return ((grub_phys_addr_t) a) & 0x1fffffffUL; -+ return ((grub_phys_addr_t) a) & 0xffffffffffffUL; -+} -+ -+static inline void * -+grub_map_memory (grub_phys_addr_t a, grub_size_t size) -+{ -+ grub_uint64_t addr; -+ -+ asm volatile ("csrrd %0, 0x181" : "=r" (addr)); -+ return (void *) (a | (addr & 0xffffffffffffff00UL)); -+} -+ -+static inline void -+grub_unmap_memory (void *a __attribute__ ((unused)), -+ grub_size_t size __attribute__ ((unused))) -+{ -+} -+ -+#endif -+ -+#endif -diff --git a/include/grub/loongarch64/relocator.h b/include/grub/loongarch64/relocator.h -new file mode 100644 -index 0000000..8815314 ---- /dev/null -+++ b/include/grub/loongarch64/relocator.h -@@ -0,0 +1,38 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_RELOCATOR_CPU_HEADER -+#define GRUB_RELOCATOR_CPU_HEADER 1 -+ -+#include -+#include -+#include -+ -+struct grub_relocator64_state -+{ -+ /* gpr[0] is ignored since it's hardwired to 0. */ -+ grub_uint64_t gpr[32]; -+ /* Register holding target $pc. */ -+ int jumpreg; -+}; -+ -+grub_err_t -+grub_relocator64_boot (struct grub_relocator *rel, -+ struct grub_relocator64_state state); -+ -+#endif /* ! GRUB_RELOCATOR_CPU_HEADER */ -diff --git a/include/grub/loongarch64/setjmp.h b/include/grub/loongarch64/setjmp.h -new file mode 100644 -index 0000000..d9a0776 ---- /dev/null -+++ b/include/grub/loongarch64/setjmp.h -@@ -0,0 +1,27 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2002,2004,2006,2007,2009,2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_SETJMP_CPU_HEADER -+#define GRUB_SETJMP_CPU_HEADER 1 -+ -+typedef grub_uint64_t grub_jmp_buf[12]; -+ -+int grub_setjmp (grub_jmp_buf env) RETURNS_TWICE; -+void grub_longjmp (grub_jmp_buf env, int val) __attribute__ ((noreturn)); -+ -+#endif /* ! GRUB_SETJMP_CPU_HEADER */ -diff --git a/include/grub/loongarch64/time.h b/include/grub/loongarch64/time.h -new file mode 100644 -index 0000000..c9a7334 ---- /dev/null -+++ b/include/grub/loongarch64/time.h -@@ -0,0 +1,39 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2003,2004,2005,2007,2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef KERNEL_CPU_TIME_HEADER -+#define KERNEL_CPU_TIME_HEADER 1 -+ -+#ifndef GRUB_UTIL -+ -+#define GRUB_TICKS_PER_SECOND (grub_arch_cpuclock / 2) -+ -+void grub_timer_init (grub_uint32_t cpuclock); -+ -+/* Return the real time in ticks. */ -+grub_uint64_t grub_get_rtc (void); -+ -+extern grub_uint32_t grub_arch_cpuclock; -+#endif -+ -+static inline void -+grub_cpu_idle(void) -+{ -+} -+ -+#endif -diff --git a/include/grub/loongarch64/types.h b/include/grub/loongarch64/types.h -new file mode 100644 -index 0000000..5dc7f21 ---- /dev/null -+++ b/include/grub/loongarch64/types.h -@@ -0,0 +1,34 @@ -+/* -+ * GRUB -- GRand Unified Bootloader -+ * Copyright (C) 2002,2006,2007,2009,2017 Free Software Foundation, Inc. -+ * -+ * GRUB is free software: you can redistribute it and/or modify -+ * it under the terms of the GNU General Public License as published by -+ * the Free Software Foundation, either version 3 of the License, or -+ * (at your option) any later version. -+ * -+ * GRUB is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -+ * GNU General Public License for more details. -+ * -+ * You should have received a copy of the GNU General Public License -+ * along with GRUB. If not, see . -+ */ -+ -+#ifndef GRUB_TYPES_CPU_HEADER -+#define GRUB_TYPES_CPU_HEADER 1 -+ -+/* The size of void *. */ -+#define GRUB_TARGET_SIZEOF_VOID_P 8 -+ -+/* The size of long. */ -+#define GRUB_TARGET_SIZEOF_LONG 8 -+ -+#ifdef GRUB_CPU_LOONGARCH -+/* loongarch is little-endian. */ -+#undef GRUB_TARGET_WORDS_BIGENDIAN -+ -+#endif /* ! GRUB_TYPES_CPU_HEADER */ -+ -+#endif -diff --git a/include/grub/util/install.h b/include/grub/util/install.h -index dad1756..33feae9 100644 ---- a/include/grub/util/install.h -+++ b/include/grub/util/install.h -@@ -107,6 +107,7 @@ enum grub_install_plat - GRUB_INSTALL_PLATFORM_X86_64_XEN, - GRUB_INSTALL_PLATFORM_ARM64_EFI, - GRUB_INSTALL_PLATFORM_ARM_COREBOOT, -+ GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI, - GRUB_INSTALL_PLATFORM_MAX - }; - -diff --git a/util/grub-install-common.c b/util/grub-install-common.c -index fde4ca7..6504637 100644 ---- a/util/grub-install-common.c -+++ b/util/grub-install-common.c -@@ -738,27 +738,28 @@ static struct - const char *platform; - } platforms[GRUB_INSTALL_PLATFORM_MAX] = - { -- [GRUB_INSTALL_PLATFORM_I386_PC] = { "i386", "pc" }, -- [GRUB_INSTALL_PLATFORM_I386_EFI] = { "i386", "efi" }, -- [GRUB_INSTALL_PLATFORM_I386_QEMU] = { "i386", "qemu" }, -- [GRUB_INSTALL_PLATFORM_I386_COREBOOT] = { "i386", "coreboot" }, -- [GRUB_INSTALL_PLATFORM_I386_MULTIBOOT] = { "i386", "multiboot" }, -- [GRUB_INSTALL_PLATFORM_I386_IEEE1275] = { "i386", "ieee1275" }, -- [GRUB_INSTALL_PLATFORM_X86_64_EFI] = { "x86_64", "efi" }, -- [GRUB_INSTALL_PLATFORM_I386_XEN] = { "i386", "xen" }, -- [GRUB_INSTALL_PLATFORM_X86_64_XEN] = { "x86_64", "xen" }, -- [GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON] = { "mipsel", "loongson" }, -- [GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS] = { "mipsel", "qemu_mips" }, -- [GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS] = { "mips", "qemu_mips" }, -- [GRUB_INSTALL_PLATFORM_MIPSEL_ARC] = { "mipsel", "arc" }, -- [GRUB_INSTALL_PLATFORM_MIPS_ARC] = { "mips", "arc" }, -- [GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275] = { "sparc64", "ieee1275" }, -- [GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275] = { "powerpc", "ieee1275" }, -- [GRUB_INSTALL_PLATFORM_IA64_EFI] = { "ia64", "efi" }, -- [GRUB_INSTALL_PLATFORM_ARM_EFI] = { "arm", "efi" }, -- [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64", "efi" }, -- [GRUB_INSTALL_PLATFORM_ARM_UBOOT] = { "arm", "uboot" }, -- [GRUB_INSTALL_PLATFORM_ARM_COREBOOT] = { "arm", "coreboot" }, -+ [GRUB_INSTALL_PLATFORM_I386_PC] = { "i386", "pc" }, -+ [GRUB_INSTALL_PLATFORM_I386_EFI] = { "i386", "efi" }, -+ [GRUB_INSTALL_PLATFORM_I386_QEMU] = { "i386", "qemu" }, -+ [GRUB_INSTALL_PLATFORM_I386_COREBOOT] = { "i386", "coreboot" }, -+ [GRUB_INSTALL_PLATFORM_I386_MULTIBOOT] = { "i386", "multiboot" }, -+ [GRUB_INSTALL_PLATFORM_I386_IEEE1275] = { "i386", "ieee1275" }, -+ [GRUB_INSTALL_PLATFORM_X86_64_EFI] = { "x86_64", "efi" }, -+ [GRUB_INSTALL_PLATFORM_I386_XEN] = { "i386", "xen" }, -+ [GRUB_INSTALL_PLATFORM_X86_64_XEN] = { "x86_64", "xen" }, -+ [GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON] = { "mipsel", "loongson" }, -+ [GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS] = { "mipsel", "qemu_mips" }, -+ [GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS] = { "mips", "qemu_mips" }, -+ [GRUB_INSTALL_PLATFORM_MIPSEL_ARC] = { "mipsel", "arc" }, -+ [GRUB_INSTALL_PLATFORM_MIPS_ARC] = { "mips", "arc" }, -+ [GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275] = { "sparc64", "ieee1275" }, -+ [GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275] = { "powerpc", "ieee1275" }, -+ [GRUB_INSTALL_PLATFORM_IA64_EFI] = { "ia64", "efi" }, -+ [GRUB_INSTALL_PLATFORM_ARM_EFI] = { "arm", "efi" }, -+ [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64", "efi" }, -+ [GRUB_INSTALL_PLATFORM_ARM_UBOOT] = { "arm", "uboot" }, -+ [GRUB_INSTALL_PLATFORM_ARM_COREBOOT] = { "arm", "coreboot" }, -+ [GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI] = { "loongarch64", "efi" }, - }; - - char * -diff --git a/util/grub-install.c b/util/grub-install.c -index 65bb2f9..28b5d74 100644 ---- a/util/grub-install.c -+++ b/util/grub-install.c -@@ -322,6 +322,8 @@ get_default_platform (void) - return "arm-uboot"; - #elif defined (__aarch64__) - return "arm64-efi"; -+#elif defined (__loongarch64) -+ return "loongarch64-efi"; - #elif defined (__amd64__) || defined (__x86_64__) || defined (__i386__) - return grub_install_get_default_x86_platform (); - #else -@@ -477,6 +479,7 @@ have_bootdev (enum grub_install_plat pl) - case GRUB_INSTALL_PLATFORM_IA64_EFI: - case GRUB_INSTALL_PLATFORM_ARM_EFI: - case GRUB_INSTALL_PLATFORM_ARM64_EFI: -+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: - case GRUB_INSTALL_PLATFORM_I386_IEEE1275: - case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: - case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: -@@ -895,6 +898,7 @@ main (int argc, char *argv[]) - case GRUB_INSTALL_PLATFORM_I386_EFI: - case GRUB_INSTALL_PLATFORM_IA64_EFI: - case GRUB_INSTALL_PLATFORM_X86_64_EFI: -+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: - is_efi = 1; - grub_util_error (_("this utility cannot be used for EFI platforms" - " because it does not support UEFI Secure Boot")); -@@ -921,6 +925,7 @@ main (int argc, char *argv[]) - case GRUB_INSTALL_PLATFORM_ARM_EFI: - case GRUB_INSTALL_PLATFORM_ARM64_EFI: - case GRUB_INSTALL_PLATFORM_IA64_EFI: -+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: - case GRUB_INSTALL_PLATFORM_I386_IEEE1275: - case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: - case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: -@@ -965,6 +970,7 @@ main (int argc, char *argv[]) - case GRUB_INSTALL_PLATFORM_ARM_EFI: - case GRUB_INSTALL_PLATFORM_ARM64_EFI: - case GRUB_INSTALL_PLATFORM_IA64_EFI: -+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: - case GRUB_INSTALL_PLATFORM_I386_IEEE1275: - case GRUB_INSTALL_PLATFORM_ARM_UBOOT: - case GRUB_INSTALL_PLATFORM_I386_QEMU: -@@ -1110,6 +1116,9 @@ main (int argc, char *argv[]) - case GRUB_INSTALL_PLATFORM_ARM64_EFI: - efi_file = "BOOTAA64.EFI"; - break; -+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: -+ efi_file = "BOOTLOONGARCH64.EFI"; -+ break; - default: - grub_util_error ("%s", _("You've found a bug")); - break; -@@ -1137,6 +1146,9 @@ main (int argc, char *argv[]) - case GRUB_INSTALL_PLATFORM_ARM64_EFI: - efi_file = "grubaa64.efi"; - break; -+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: -+ efi_file = "grubloongarch64.efi"; -+ break; - default: - efi_file = "grub.efi"; - break; -@@ -1440,6 +1452,7 @@ main (int argc, char *argv[]) - case GRUB_INSTALL_PLATFORM_ARM_EFI: - case GRUB_INSTALL_PLATFORM_ARM64_EFI: - case GRUB_INSTALL_PLATFORM_IA64_EFI: -+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: - g = grub_util_guess_efi_drive (*curdev); - break; - case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: -@@ -1581,6 +1594,7 @@ main (int argc, char *argv[]) - case GRUB_INSTALL_PLATFORM_ARM_EFI: - case GRUB_INSTALL_PLATFORM_ARM64_EFI: - case GRUB_INSTALL_PLATFORM_IA64_EFI: -+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: - core_name = "core.efi"; - snprintf (mkimage_target, sizeof (mkimage_target), - "%s-%s", -@@ -1683,6 +1697,7 @@ main (int argc, char *argv[]) - case GRUB_INSTALL_PLATFORM_ARM_EFI: - case GRUB_INSTALL_PLATFORM_ARM64_EFI: - case GRUB_INSTALL_PLATFORM_IA64_EFI: -+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: - case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: - case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: - case GRUB_INSTALL_PLATFORM_I386_COREBOOT: -@@ -1917,6 +1932,7 @@ main (int argc, char *argv[]) - case GRUB_INSTALL_PLATFORM_ARM_EFI: - case GRUB_INSTALL_PLATFORM_ARM64_EFI: - case GRUB_INSTALL_PLATFORM_IA64_EFI: -+ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: - { - char *dst = grub_util_path_concat (2, efidir, efi_file); - grub_install_copy_file (imgfile, dst, 1); -diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c -index 1bb5eb8..240e193 100644 ---- a/util/grub-mkimagexx.c -+++ b/util/grub-mkimagexx.c -@@ -783,6 +783,9 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, - struct grub_ia64_trampoline *tr = (void *) (pe_target + tramp_off); - grub_uint64_t *gpptr = (void *) (pe_target + got_off); - unsigned unmatched_adr_got_page = 0; -+ grub_uint64_t oprs[10240]= {0}; -+ int opri = -1; -+ grub_uint32_t la_abs = 0; - #define MASK19 ((1 << 19) - 1) - #else - grub_uint32_t *tr = (void *) (pe_target + tramp_off); -@@ -1122,6 +1125,173 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, - } - break; - } -+ case EM_LOONGARCH64: -+ { -+ sym_addr += addend; -+ switch (ELF_R_TYPE (info)) -+ { -+ case R_LARCH_64: -+ { -+ *target=(grub_uint64_t)sym_addr; -+ } -+ break; -+ case R_LARCH_MARK_LA: -+ { -+ la_abs=1; -+ } -+ break; -+ case R_LARCH_SOP_PUSH_PCREL: -+ { -+ opri++; -+ oprs[opri]=(grub_uint64_t)(sym_addr-(target_section_addr+offset+image_target->vaddr_offset)); -+ } -+ break; -+ case R_LARCH_SOP_PUSH_ABSOLUTE: -+ { -+ opri++; -+ oprs[opri]=(grub_uint64_t)sym_addr; -+ } -+ break; -+ case R_LARCH_SOP_PUSH_PLT_PCREL: -+ { -+ opri++; -+ oprs[opri]=(grub_uint64_t)(sym_addr-(target_section_addr+offset+image_target->vaddr_offset)); -+ } -+ break; -+ case R_LARCH_SOP_SUB: -+ { -+ grub_uint64_t opr2=oprs[opri]; -+ opri--; -+ grub_uint64_t opr1=oprs[opri]; -+ opri--; -+ opri++; -+ oprs[opri]=opr1 - opr2; -+ } -+ break; -+ case R_LARCH_SOP_SL: -+ { -+ grub_uint64_t opr2=oprs[opri]; -+ opri--; -+ grub_uint64_t opr1=oprs[opri]; -+ opri--; -+ opri++; -+ oprs[opri]=opr1 << opr2; -+ } -+ break; -+ case R_LARCH_SOP_SR: -+ { -+ grub_uint64_t opr2=oprs[opri]; -+ opri--; -+ grub_uint64_t opr1=oprs[opri]; -+ opri--; -+ opri++; -+ oprs[opri]=opr1 >> opr2; -+ } -+ break; -+ case R_LARCH_SOP_ADD: -+ { -+ grub_uint64_t opr2=oprs[opri]; -+ opri--; -+ grub_uint64_t opr1=oprs[opri]; -+ opri--; -+ opri++; -+ oprs[opri]=opr1 + opr2; -+ } -+ break; -+ case R_LARCH_SOP_AND: -+ { -+ grub_uint64_t opr2=oprs[opri]; -+ opri--; -+ grub_uint64_t opr1=oprs[opri]; -+ opri--; -+ opri++; -+ oprs[opri]=opr1 & opr2; -+ } -+ break; -+ case R_LARCH_SOP_IF_ELSE: -+ { -+ grub_uint64_t opr3=oprs[opri]; -+ opri--; -+ grub_uint64_t opr2=oprs[opri]; -+ opri--; -+ grub_uint64_t opr1=oprs[opri]; -+ opri--; -+ if(opr1){ -+ opri++; -+ oprs[opri]=opr2; -+ } else { -+ opri++; -+ oprs[opri]=opr3; -+ } -+ } -+ break; -+ case R_LARCH_SOP_POP_32_S_10_5: -+ { -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *target=(*target) | ((opr1 & 0x1f) << 10); -+ } -+ break; -+ case R_LARCH_SOP_POP_32_U_10_12: -+ { -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *target=(*target) | ((opr1 & 0xfff) << 10); -+ } -+ break; -+ case R_LARCH_SOP_POP_32_S_10_12: -+ { -+ if(la_abs==1) -+ la_abs=0; -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *target = (*target) | ((opr1 & 0xfff) << 10); -+ } -+ break; -+ case R_LARCH_SOP_POP_32_S_10_16: -+ { -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *target = (*target) | ((opr1 & 0xffff) << 10); -+ } -+ break; -+ case R_LARCH_SOP_POP_32_S_10_16_S2: -+ { -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *target = (*target) | (((opr1 >> 2) & 0xffff) << 10); -+ } -+ break; -+ case R_LARCH_SOP_POP_32_S_5_20: -+ { -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *target = (*target) | ((opr1 & 0xfffff)<<5) ; -+ } -+ break; -+ case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: -+ { -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *target =(*target) | (((opr1 >> 2) & 0xffff) << 10); -+ *target =(*target) | ((opr1 >> 18) & 0x1f); -+ } -+ break; -+ case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: -+ { -+ grub_uint64_t opr1 = oprs[opri]; -+ opri--; -+ *target =(*target) | (((opr1 >> 2) & 0xffff) << 10); -+ *target =(*target) | ((opr1 >> 18) & 0x3ff); -+ } -+ break; -+ default: -+ grub_util_error (_("relocation 0x%x is not implemented yet"), -+ (unsigned int) ELF_R_TYPE (info)); -+ break; -+ } -+ break; -+ } - #endif - #if defined(MKIMAGE_ELF32) - case EM_ARM: -@@ -1310,7 +1480,10 @@ add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type, - - /* The spec does not mention the requirement of a Page RVA. - Here, align the address with a 4K boundary for safety. */ -- b->page_rva = (addr & ~(0x1000 - 1)); -+#ifdef GRUB_CPU_LOONGARCH64 -+ if (type) -+#endif -+ b->page_rva = (addr & ~(0x1000 - 1)); - b->block_size = sizeof (*b); - } - -@@ -1320,7 +1493,11 @@ add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type, - - /* Add a new entry. */ - cur_index = ((b->block_size - sizeof (*b)) >> 1); -+#ifdef GRUB_CPU_LOONGARCH64 -+ entry = GRUB_PE32_FIXUP_ENTRY (type, type ? (addr - b->page_rva) : addr); -+#else - entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva); -+#endif - b->entries[cur_index] = grub_host_to_target16 (entry); - b->block_size += 2; - } -@@ -1366,6 +1543,10 @@ static void - translate_relocation_pe (struct translate_context *ctx, - Elf_Addr addr, - Elf_Addr info, -+#ifdef GRUB_CPU_LOONGARCH64 -+ Elf_Addr sym_addr, -+ Elf_Addr addend, -+#endif - const struct grub_install_image_target_desc *image_target) - { - /* Necessary to relocate only absolute addresses. */ -@@ -1477,6 +1658,133 @@ translate_relocation_pe (struct translate_context *ctx, - } - break; - break; -+ case EM_LOONGARCH64: -+ switch (ELF_R_TYPE (info)) -+ { -+ case R_LARCH_NONE: -+ break; -+ case R_LARCH_32: -+ break; -+ case R_LARCH_64: -+ { -+ ctx->current_address = add_fixup_entry ( -+ &ctx->lst, -+ GRUB_PE32_REL_BASED_DIR64, -+ addr, 0, ctx->current_address, -+ image_target); -+ } -+ break; -+ case R_LARCH_RELATIVE: -+ break; -+ case R_LARCH_COPY: -+ break; -+ case R_LARCH_JUMP_SLOT: -+ break; -+ case R_LARCH_TLS_DTPMOD32: -+ break; -+ case R_LARCH_TLS_DTPMOD64: -+ break; -+ case R_LARCH_TLS_DTPREL32: -+ break; -+ case R_LARCH_TLS_DTPREL64: -+ break; -+ case R_LARCH_TLS_TPREL32: -+ break; -+ case R_LARCH_TLS_TPREL64: -+ break; -+ case R_LARCH_IRELATIVE: -+ break; -+ case R_LARCH_MARK_LA: -+ { -+ ctx->current_address = add_fixup_entry ( -+ &ctx->lst, -+ GRUB_PE32_REL_BASED_LOONGARCH64, -+ addr, 0, ctx->current_address, -+ image_target); -+ } -+ break; -+ case R_LARCH_MARK_PCREL: -+ break; -+ case R_LARCH_SOP_PUSH_PCREL: -+ break; -+ case R_LARCH_SOP_PUSH_ABSOLUTE: -+ break; -+ case R_LARCH_SOP_PUSH_DUP: -+ break; -+ case R_LARCH_SOP_PUSH_GPREL: -+ break; -+ case R_LARCH_SOP_PUSH_TLS_TPREL: -+ break; -+ case R_LARCH_SOP_PUSH_TLS_GOT: -+ break; -+ case R_LARCH_SOP_PUSH_TLS_GD: -+ break; -+ case R_LARCH_SOP_PUSH_PLT_PCREL: -+ break; -+ case R_LARCH_SOP_ASSERT: -+ break; -+ case R_LARCH_SOP_NOT: -+ break; -+ case R_LARCH_SOP_SUB: -+ break; -+ case R_LARCH_SOP_SL: -+ break; -+ case R_LARCH_SOP_SR: -+ break; -+ case R_LARCH_SOP_ADD: -+ break; -+ case R_LARCH_SOP_AND: -+ break; -+ case R_LARCH_SOP_IF_ELSE: -+ break; -+ case R_LARCH_SOP_POP_32_S_10_5: -+ break; -+ case R_LARCH_SOP_POP_32_U_10_12: -+ break; -+ case R_LARCH_SOP_POP_32_S_10_12: -+ break; -+ case R_LARCH_SOP_POP_32_S_10_16: -+ break; -+ case R_LARCH_SOP_POP_32_S_10_16_S2: -+ break; -+ case R_LARCH_SOP_POP_32_S_5_20: -+ break; -+ case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: -+ break; -+ case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: -+ break; -+ case R_LARCH_SOP_POP_32_U: -+ break; -+ case R_LARCH_ADD8: -+ break; -+ case R_LARCH_ADD16: -+ break; -+ case R_LARCH_ADD24: -+ break; -+ case R_LARCH_ADD32: -+ break; -+ case R_LARCH_ADD64: -+ break; -+ case R_LARCH_SUB8: -+ break; -+ case R_LARCH_SUB16: -+ break; -+ case R_LARCH_SUB24: -+ break; -+ case R_LARCH_SUB32: -+ break; -+ case R_LARCH_SUB64: -+ break; -+ case R_LARCH_GNU_VTINHERIT: -+ break; -+ case R_LARCH_GNU_VTENTRY: -+ break; -+ default: -+ grub_util_error (_("relocation 0x%x is not implemented yet"), -+ (unsigned int) ELF_R_TYPE (info)); -+ break; -+ } -+ break; - #if defined(MKIMAGE_ELF32) - case EM_ARM: - switch (ELF_R_TYPE (info)) -@@ -1565,10 +1873,18 @@ static void - translate_relocation (struct translate_context *ctx, - Elf_Addr addr, - Elf_Addr info, -+#ifdef GRUB_CPU_LOONGARCH64 -+ Elf_Addr sym_addr, -+ Elf_Addr addend, -+#endif - const struct grub_install_image_target_desc *image_target) - { - if (image_target->id == IMAGE_EFI) -+#ifdef GRUB_CPU_LOONGARCH64 -+ translate_relocation_pe (ctx, addr, info, sym_addr, addend, image_target); -+#else - translate_relocation_pe (ctx, addr, info, image_target); -+#endif - else - translate_relocation_raw (ctx, addr, info, image_target); - } -@@ -1709,11 +2025,21 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, - if ((grub_target_to_host32 (s->sh_type) == SHT_REL) || - (grub_target_to_host32 (s->sh_type) == SHT_RELA)) - { -+#ifdef GRUB_CPU_LOONGARCH64 -+ Elf_Rela *r; -+#else - Elf_Rel *r; -+#endif - Elf_Word rtab_size, r_size, num_rs; - Elf_Off rtab_offset; - Elf_Addr section_address; - Elf_Word j; -+#ifdef GRUB_CPU_LOONGARCH64 -+ Elf_Shdr *symtab_section; -+ -+ symtab_section = (Elf_Shdr *) ((char *) smd->sections -+ + (grub_target_to_host32 (s->sh_link) * smd->section_entsize)); -+#endif - - if (!SUFFIX (is_kept_reloc_section) (s, image_target, smd)) - { -@@ -1732,20 +2058,39 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, - - section_address = smd->vaddrs[grub_le_to_cpu32 (s->sh_info)]; - -+#ifdef GRUB_CPU_LOONGARCH64 -+ for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset); -+ j < num_rs; -+ j++, r = (Elf_Rela *) ((char *) r + r_size)) -+#else - for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset); - j < num_rs; - j++, r = (Elf_Rel *) ((char *) r + r_size)) -+#endif - { - Elf_Addr info; - Elf_Addr offset; - Elf_Addr addr; -+#ifdef GRUB_CPU_LOONGARCH64 -+ Elf_Addr sym_addr; -+ Elf_Addr addend; -+#endif - - offset = grub_target_to_host (r->r_offset); - info = grub_target_to_host (r->r_info); -- -+#ifdef GRUB_CPU_LOONGARCH64 -+ sym_addr = SUFFIX (get_symbol_address) (e, symtab_section, -+ ELF_R_SYM (info), image_target); -+ addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? -+ grub_target_to_host (r->r_addend) : 0; -+#endif - addr = section_address + offset; - -+#ifdef GRUB_CPU_LOONGARCH64 -+ translate_relocation (&ctx, addr, info, sym_addr, addend, image_target); -+#else - translate_relocation (&ctx, addr, info, image_target); -+#endif - } - } - -diff --git a/util/grub-mknetdir.c b/util/grub-mknetdir.c -index ae31271..c998850 100644 ---- a/util/grub-mknetdir.c -+++ b/util/grub-mknetdir.c -@@ -112,7 +112,8 @@ static struct - [GRUB_INSTALL_PLATFORM_X86_64_EFI] = { "x86_64-efi", "efinet", ".efi" }, - [GRUB_INSTALL_PLATFORM_IA64_EFI] = { "ia64-efi", "efinet", ".efi" }, - [GRUB_INSTALL_PLATFORM_ARM_EFI] = { "arm-efi", "efinet", ".efi" }, -- [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64-efi", "efinet", ".efi" } -+ [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64-efi", "efinet", ".efi" }, -+ [GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI] = { "loongarch64-efi", "efinet", ".efi" } - }; - - static void -diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c -index 03ba1ab..4a9943a 100644 ---- a/util/grub-module-verifier.c -+++ b/util/grub-module-verifier.c -@@ -119,6 +119,52 @@ struct grub_module_verifier_arch archs[] = { - -1 - } - }, -+ { "loongarch64", 8, 0, EM_LOONGARCH64, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ -+ R_LARCH_NONE, -+ R_LARCH_32, -+ R_LARCH_64, -+ R_LARCH_RELATIVE, -+ R_LARCH_COPY, -+ R_LARCH_JUMP_SLOT, -+ R_LARCH_TLS_DTPMOD32, -+ R_LARCH_TLS_DTPMOD64, -+ R_LARCH_TLS_DTPREL32, -+ R_LARCH_TLS_DTPREL64, -+ R_LARCH_TLS_TPREL32, -+ R_LARCH_TLS_TPREL64, -+ R_LARCH_IRELATIVE, -+ R_LARCH_MARK_LA, -+ R_LARCH_MARK_PCREL, -+ R_LARCH_SOP_PUSH_PCREL, -+ R_LARCH_SOP_PUSH_ABSOLUTE, -+ R_LARCH_SOP_PUSH_DUP, -+ R_LARCH_SOP_PUSH_GPREL, -+ R_LARCH_SOP_PUSH_TLS_TPREL, -+ R_LARCH_SOP_PUSH_TLS_GOT, -+ R_LARCH_SOP_PUSH_TLS_GD, -+ R_LARCH_SOP_PUSH_PLT_PCREL, -+ R_LARCH_SOP_ASSERT, -+ R_LARCH_SOP_NOT, -+ R_LARCH_SOP_SUB, -+ R_LARCH_SOP_SL, -+ R_LARCH_SOP_SR, -+ R_LARCH_SOP_ADD, -+ R_LARCH_SOP_AND, -+ R_LARCH_SOP_IF_ELSE, -+ R_LARCH_SOP_POP_32_S_10_5, -+ R_LARCH_SOP_POP_32_U_10_12, -+ R_LARCH_SOP_POP_32_S_10_12, -+ R_LARCH_SOP_POP_32_S_10_16, -+ R_LARCH_SOP_POP_32_S_10_16_S2, -+ R_LARCH_SOP_POP_32_S_5_20, -+ R_LARCH_SOP_POP_32_S_0_5_10_16_S2, -+ R_LARCH_SOP_POP_32_S_0_10_10_16_S2, -+ R_LARCH_SOP_POP_32_U, -+ -1 -+ }, (int[]){ -+ -1 -+ } -+ }, - }; - - struct platform_whitelist { -diff --git a/util/mkimage.c b/util/mkimage.c -index 16418e2..0d39c07 100644 ---- a/util/mkimage.c -+++ b/util/mkimage.c -@@ -609,6 +609,22 @@ static const struct grub_install_image_target_desc image_targets[] = - .pe_target = GRUB_PE32_MACHINE_ARM64, - .elf_target = EM_AARCH64, - }, -+ { -+ .dirname = "loongarch64-efi", -+ .names = { "loongarch64-efi", NULL }, -+ .voidp_sizeof = 8, -+ .bigendian = 0, -+ .id = IMAGE_EFI, -+ .flags = PLATFORM_FLAGS_NONE, -+ .total_module_size = TARGET_NO_FIELD, -+ .decompressor_compressed_size = TARGET_NO_FIELD, -+ .decompressor_uncompressed_size = TARGET_NO_FIELD, -+ .decompressor_uncompressed_addr = TARGET_NO_FIELD, -+ .section_align = GRUB_PE32_SECTION_ALIGNMENT, -+ .vaddr_offset = EFI64_HEADER_SIZE, -+ .pe_target = GRUB_PE32_MACHINE_LOONGARCH64, -+ .elf_target = EM_LOONGARCH64, -+ }, - }; - - #include --- -2.27.0 - diff --git a/1001-bls-make-list.patch b/1001-bls-make-list.patch deleted file mode 100644 index ac39162..0000000 --- a/1001-bls-make-list.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Zhongling He -Date: Tue, 29 Mar 2022 17:27:13 +0800 -Subject: [PATCH] Fix a bug in bls_make_list, blscfg - -We have encountered a bug while running LifseaOS aarch64 version without -initrd. This commit fixes this bug. It may have fixed some potential -bugs as well. - -There are 4 partitions in a LifseaOS disk image: -- The 1st partition is for BIOS bootloader -- The 2nd partition is for UEFI booting, which contains grub binary - compiled from this source code, grubaa64.efi -- The 3rd partition contains grub.cfg files and - loader/entries/ostree-1-LifseaOS.conf -- The 4th partition contains rootfs - -Since x86_64 supports both BIOS and UEFI booting and we employ BIOS -booting for x86_64 (w/o initrd) image, we don't put the grub2 binary -compiled into the 2nd partition. As a result, this bug was not observed. -However, aarch64 only supports UEFI booting. In other words, we are -using this grub2 to boot LifseaOS (w/o initrd). - -grubaa64.efi from the 2nd partition will read `/grub2/grub.cfg` in the -3rd partition. - -``` -... - set ignition_firstboot="ignition.firstboot -${ignition_network_kcmdline}" -fi - -blscfg -``` - -`blscfg` is a command to convert `loader/entries/ostree-1-LifseaOS.conf` -into a typical grub.cfg. However, here comes the bug. While booting, an -error message will appear. - -``` -error: ../../grub-core/loader/arm64/linux.c:292:filename expected. -Press any key to continue. -``` - -This is because the bug in `blscfg` unexpectedly add a line, `initrd`, -into the generated grub.cfg file. Grub2 will expect an initrd file path -after `initrd`. As a result, the error occurs. - -In grub-core/command/blscfg.c:676, if `initrds` is a non-NULL pointer, -then `src` will contain a `initrd` line. - -``` -static void create_entry (struct bls_entry *entry){ - ... - initrds = bls_make_list (entry, "initrd", NULL); // - ... - if (initrds){ - ... - tmp = grub_stpcpy(initrd, "initrd "); - ... - } - ... - src = grub_xasprintf ("load_video\n" - "set gfx_payload=keep\n" - "insmod gzio\n" - "linux %s%s%s%s\n" - "%s", - GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options -: "", - initrd ? initrd : ""); -``` - -In grub-core/command/blscfg.c:562, `bls_make_list` will always return a -non-NULL pointer except for a `grub_malloc` error. - -``` -static char **bls_make_list (struct bls_entry *entry, const char *key, -int *num) -{ - ... - list = grub_malloc (sizeof (char *)); - if (!list) - return NULL; - list[0] = NULL; - ... - return list; -} -``` - -Therefore, `initrd` like will be appended into the auto-generated -grub.cfg if `grub_malloc` succeed, regardless of whether initrd is -stated in config file. Our bug fix, same as upstream, modifies the -behaviour of `bls_make_list`. `bls_make_list` will now return a non-NULL -pointer only if the required field actually exists. - ---- - grub-core/commands/blscfg.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c -index 795a9f9..bf18270 100644 ---- a/grub-core/commands/blscfg.c -+++ b/grub-core/commands/blscfg.c -@@ -589,6 +589,12 @@ static char **bls_make_list (struct bls_entry *entry, const char *key, int *num) - list[nlist] = NULL; - } - -+ if (!nlist) -+ { -+ grub_free (list); -+ return NULL; -+ } -+ - if (num) - *num = nlist; - --- -2.27.0 - diff --git a/grub.macros b/grub.macros index e6ef9ea..783cb57 100644 --- a/grub.macros +++ b/grub.macros @@ -92,7 +92,7 @@ %endif -%global efi_only aarch64 %{arm} loongarch64 +%global efi_only aarch64 %{arm} %global efi_arch x86_64 ia64 %{efi_only} %ifarch %{efi_arch} %global with_efi_arch 1 @@ -122,7 +122,7 @@ %global platform_modules " appendedsig " %endif -%ifarch aarch64 %{arm} loongarch64 +%ifarch aarch64 %{arm} %global platform_modules " " %endif @@ -187,14 +187,6 @@ )} %endif -%ifarch loongarch64 -%global with_emu_arch 0 -%global efiarch loongarch64 -%global target_cpu_name loongarch64 -%global grub_target_name loongarch64-efi -%global package_arch efi-loongarch64 -%endif - %global _target_platform %{target_cpu_name}-%{_vendor}-%{_target_os}%{?_gnu} %global _alt_target_platform %{alt_target_cpu_name}-%{_vendor}-%{_target_os}%{?_gnu} @@ -230,7 +222,7 @@ %ifarch x86_64 %global with_efi_common 1 -%global with_legacy_modules 1 +%global with_legacy_modules 0 %global with_legacy_common 0 %else %global with_efi_common 0 @@ -387,11 +379,11 @@ for x in grub-mkimage ; do \\\ done \ %{nil} -%global grub_modules " all_video boot blscfg btrfs \\\ +%global grub_modules " all_video boot blscfg \\\ cat configfile cryptodisk echo ext2 \\\ fat font gcry_rijndael gcry_rsa gcry_serpent \\\ gcry_sha256 gcry_twofish gcry_whirlpool \\\ - gfxmenu gfxterm gzio halt hfsplus http \\\ + gfxmenu gfxterm gzio halt http \\\ increment iso9660 jpeg loadenv loopback linux \\\ lvm luks mdraid09 mdraid1x minicmd net \\\ normal part_apple part_msdos part_gpt \\\ diff --git a/grub.patches b/grub.patches index 0387df7..54b52a2 100644 --- a/grub.patches +++ b/grub.patches @@ -498,6 +498,52 @@ Patch0497: 0497-x86-efi-Re-arrange-grub_cmd_linux-a-little-bit.patch Patch0498: 0498-x86-efi-Make-our-own-allocator-for-kernel-stuff.patch Patch0499: 0499-x86-efi-Allow-initrd-params-cmdline-allocations-abov.patch Patch0500: 0500-x86-efi-Reduce-maximum-bounce-buffer-size-to-16-MiB.patch -# Support loongarch64 -#Patch1000: 1000-loongarch64-add-support.patch -Patch1001: 1001-bls-make-list.patch +Patch0501: 0501-loader-efi-chainloader-grub_load_and_start_image-doe.patch +Patch0502: 0502-loader-efi-chainloader-simplify-the-loader-state.patch +Patch0503: 0503-commands-boot-Add-API-to-pass-context-to-loader.patch +Patch0504: 0504-loader-efi-chainloader-Use-grub_loader_set_ex.patch +Patch0505: 0505-loader-i386-efi-linux-Avoid-a-use-after-free-in-the-.patch +Patch0506: 0506-loader-i386-efi-linux-Use-grub_loader_set_ex.patch +Patch0507: 0507-loader-i386-efi-linux-Fix-a-memory-leak-in-the-initr.patch +Patch0508: 0508-kern-file-Do-not-leak-device_name-on-error-in-grub_f.patch +Patch0509: 0509-video-readers-png-Abort-sooner-if-a-read-operation-f.patch +Patch0510: 0510-video-readers-png-Refuse-to-handle-multiple-image-he.patch +Patch0511: 0511-video-readers-png-Drop-greyscale-support-to-fix-heap.patch +Patch0512: 0512-video-readers-png-Avoid-heap-OOB-R-W-inserting-huff-.patch +Patch0513: 0513-video-readers-png-Sanity-check-some-huffman-codes.patch +Patch0514: 0514-video-readers-jpeg-Abort-sooner-if-a-read-operation-.patch +Patch0515: 0515-video-readers-jpeg-Do-not-reallocate-a-given-huff-ta.patch +Patch0516: 0516-video-readers-jpeg-Refuse-to-handle-multiple-start-o.patch +Patch0517: 0517-video-readers-jpeg-Block-int-underflow-wild-pointer-.patch +Patch0518: 0518-normal-charset-Fix-array-out-of-bounds-formatting-un.patch +Patch0519: 0519-net-netbuff-Block-overly-large-netbuff-allocs.patch +Patch0520: 0520-net-ip-Do-IP-fragment-maths-safely.patch +Patch0521: 0521-net-dns-Fix-double-free-addresses-on-corrupt-DNS-res.patch +Patch0522: 0522-net-dns-Don-t-read-past-the-end-of-the-string-we-re-.patch +Patch0523: 0523-net-tftp-Prevent-a-UAF-and-double-free-from-a-failed.patch +Patch0524: 0524-misc-Format-string-for-grub_error-should-be-a-litera.patch +Patch0525: 0525-net-tftp-Avoid-a-trivial-UAF.patch +Patch0526: 0526-net-http-Do-not-tear-down-socket-if-it-s-already-bee.patch +Patch0527: 0527-net-http-Fix-OOB-write-for-split-http-headers.patch +Patch0528: 0528-net-http-Error-out-on-headers-with-LF-without-CR.patch +Patch0529: 0529-fs-f2fs-Do-not-read-past-the-end-of-nat-journal-entr.patch +Patch0530: 0530-fs-f2fs-Do-not-read-past-the-end-of-nat-bitmap.patch +Patch0531: 0531-fs-f2fs-Do-not-copy-file-names-that-are-too-long.patch +Patch0532: 0532-fs-btrfs-Fix-several-fuzz-issues-with-invalid-dir-it.patch +Patch0533: 0533-efi-Return-grub_efi_status_t-from-grub_efi_get_varia.patch +Patch0534: 0534-efi-Add-a-function-to-read-EFI-variables-with-attrib.patch +Patch0535: 0535-Define-GRUB_EFI_SHIM_LOCK_GUID.patch +Patch0536: 0536-misc-Make-grub_min-and-grub_max-more-resilient.patch +Patch0537: 0537-ReiserFS-switch-to-using-grub_min-grub_max.patch +Patch0538: 0538-misc-make-grub_boot_time-also-call-grub_dprintf-boot.patch +Patch0539: 0539-modules-make-.module_license-read-only.patch +Patch0540: 0540-modules-strip-.llvm_addrsig-sections-and-similar.patch +Patch0541: 0541-modules-Don-t-allocate-space-for-non-allocable-secti.patch +Patch0542: 0542-pe-add-the-DOS-header-struct-and-fix-some-bad-naming.patch +Patch0543: 0543-EFI-allocate-kernel-in-EFI_RUNTIME_SERVICES_CODE-ins.patch +Patch0544: 0544-modules-load-module-sections-at-page-aligned-address.patch +Patch0545: 0545-nx-add-memory-attribute-get-set-API.patch +Patch0546: 0546-nx-set-page-permissions-for-loaded-modules.patch +Patch0547: 0547-nx-set-attrs-in-our-kernel-loaders.patch +Patch0548: 0548-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch +Patch0549: 0549-Fixup-grub_efi_get_variable-type-in-our-loaders.patch diff --git a/grub2.spec b/grub2.spec index 32ef860..d83fba2 100644 --- a/grub2.spec +++ b/grub2.spec @@ -1,18 +1,13 @@ -%define anolis_release .0.1 %undefine _hardened_build %global tarversion 2.02 %undefine _missing_build_ids_terminate_build %global _configure_gnuconfig_hack 0 -%ifarch loongarch64 -%global _configure_gnuconfig_hack 1 -%endif - Name: grub2 Epoch: 1 Version: 2.02 -Release: 123%{anolis_release}%{?dist} +Release: 123%{?dist}.8 Summary: Bootloader with support for Linux, Multiboot and more Group: System Environment/Base License: GPLv3+ @@ -119,7 +114,7 @@ Requires(post): dracut %{desc} This subpackage provides tools for support of all platforms. -%ifarch x86_64 loongarch64 +%ifarch x86_64 %package tools-efi Summary: Support tools for GRUB. Group: System Environment/Base @@ -171,8 +166,8 @@ This subpackage provides tools for support of all platforms. mkdir grub-%{grubefiarch}-%{tarversion} grep -A100000 '# stuff "make" creates' .gitignore > grub-%{grubefiarch}-%{tarversion}/.gitignore cp %{SOURCE4} grub-%{grubefiarch}-%{tarversion}/unifont.pcf.gz -sed -e "s,@@VERSION@@,%{evr},g" %{SOURCE19} \ - > grub-%{grubefiarch}-%{tarversion}/sbat.csv +sed -e "s,@@VERSION@@,%{version},g" -e "s,@@VERSION_RELEASE@@,%{version}-%{release},g" \ + %{SOURCE19} > grub-%{grubefiarch}-%{tarversion}/sbat.csv git add grub-%{grubefiarch}-%{tarversion} %endif %if 0%{with_alt_efi_arch} @@ -189,11 +184,6 @@ git add grub-%{grublegacyarch}-%{tarversion} %endif git commit -m "After making subdirs" -%ifarch loongarch64 -%_update_config_sub -%_update_config_guess -%endif - %build %if 0%{with_efi_arch} %{expand:%do_primary_efi_build %%{grubefiarch} %%{grubefiname} %%{grubeficdname} %%{_target_platform} %%{efi_target_cflags} %%{efi_host_cflags} %{old_sb_ca} %{old_sb_cer} %{old_sb_key} %{sb_ca} %{sb_cer} %{sb_key}} @@ -235,11 +225,8 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir ln -s %{name}-set-password ${RPM_BUILD_ROOT}/%{_sbindir}/%{name}-setpassword echo '.so man8/%{name}-set-password.8' > ${RPM_BUILD_ROOT}/%{_datadir}/man/man8/%{name}-setpassword.8 %ifnarch x86_64 -rm -vf ${RPM_BUILD_ROOT}/%{_sbindir}/%{name}-bios-setup -%endif - -%ifnarch x86_64 loongarch64 rm -vf ${RPM_BUILD_ROOT}/%{_bindir}/%{name}-render-label +rm -vf ${RPM_BUILD_ROOT}/%{_sbindir}/%{name}-bios-setup rm -vf ${RPM_BUILD_ROOT}/%{_sbindir}/%{name}-macbless %endif @@ -399,7 +386,7 @@ fi %{_datadir}/man/man1/%{name}-editenv* %{_datadir}/man/man1/%{name}-mkpasswd-* -%ifarch x86_64 loongarch64 +%ifarch x86_64 %files tools-efi %{_sbindir}/%{name}-macbless %{_bindir}/%{name}-render-label @@ -523,10 +510,11 @@ fi %endif %changelog -* Wed May 17 2022 Bo Ren - 2.02-123.0.1 -- Build pc-modules package on x86_64 (geliwei@openanolis.org) -- Add loongarch64 base support (zhangwenlong@loongson.cn)(chenguoqi@loongson.cn) -- Fix a bug in bls_make_list, blscfg. (zhonglingh@linux.alibaba.com) +* Fri Jun 03 2022 Robbie Harwood - 2.06-123.el8_6.8 +- CVE fixes for 2022-06-07 +- CVE-2022-28736 CVE-2022-28735 CVE-2022-28734 CVE-2022-28733 +- CVE-2021-3697 CVE-2021-3696 CVE-2021-3695 +- Resolves: #2031899 * Mon Mar 28 2022 Robbie Harwood - 2.06-123 - Bump for signing diff --git a/sbat.csv.in b/sbat.csv.in index 24545c0..55b3d10 100755 --- a/sbat.csv.in +++ b/sbat.csv.in @@ -1,3 +1,3 @@ sbat,1,SBAT Version,sbat,1,https://github.com/rhboot/shim/blob/main/SBAT.md -grub,1,Free Software Foundation,grub,2.02,https://www.gnu.org/software/grub/ -grub.rhel8,1,Red Hat Enterprise Linux 8,grub2,@@VERSION@@,mail:secalert@redhat.com \ No newline at end of file +grub,2,Free Software Foundation,grub,@@VERSION@@,https//www.gnu.org/software/grub/ +grub.rh,2,Red Hat,grub2,@@VERSION_RELEASE@@,mailto:secalert@redhat.com -- Gitee From 1fa6dae1466c8f4daa446a4d48d91f9e051c5d31 Mon Sep 17 00:00:00 2001 From: songmingliang Date: Tue, 17 May 2022 18:12:12 +0800 Subject: [PATCH 2/4] build: build pc-modules package on x86_64 --- grub.macros | 2 +- grub2.spec | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/grub.macros b/grub.macros index 783cb57..681f069 100644 --- a/grub.macros +++ b/grub.macros @@ -222,7 +222,7 @@ %ifarch x86_64 %global with_efi_common 1 -%global with_legacy_modules 0 +%global with_legacy_modules 1 %global with_legacy_common 0 %else %global with_efi_common 0 diff --git a/grub2.spec b/grub2.spec index d83fba2..d5336ac 100644 --- a/grub2.spec +++ b/grub2.spec @@ -1,3 +1,4 @@ +%define anolis_release .0.1 %undefine _hardened_build %global tarversion 2.02 @@ -7,7 +8,7 @@ Name: grub2 Epoch: 1 Version: 2.02 -Release: 123%{?dist}.8 +Release: 123%{anolis_release}%{?dist}.8 Summary: Bootloader with support for Linux, Multiboot and more Group: System Environment/Base License: GPLv3+ @@ -510,6 +511,9 @@ fi %endif %changelog +* Fri Jun 17 2022 Bo Ren - 2.02-123.0.1.8 +- Build pc-modules package on x86_64 (geliwei@openanolis.org) + * Fri Jun 03 2022 Robbie Harwood - 2.06-123.el8_6.8 - CVE fixes for 2022-06-07 - CVE-2022-28736 CVE-2022-28735 CVE-2022-28734 CVE-2022-28733 -- Gitee From 51492996b054817e883a62ecb810f42fb5bdac22 Mon Sep 17 00:00:00 2001 From: songmingliang Date: Tue, 17 May 2022 18:43:45 +0800 Subject: [PATCH 3/4] Add loongarch64 base support --- 1000-loongarch64-add-support.patch | 3968 ++++++++++++++++++++++++++++ grub.macros | 12 +- grub.patches | 2 + grub2.spec | 19 +- 4 files changed, 3996 insertions(+), 5 deletions(-) create mode 100644 1000-loongarch64-add-support.patch diff --git a/1000-loongarch64-add-support.patch b/1000-loongarch64-add-support.patch new file mode 100644 index 0000000..2d83c94 --- /dev/null +++ b/1000-loongarch64-add-support.patch @@ -0,0 +1,3968 @@ +From febee03c70471fd2ce6f0b4cc0f365c32c106ab3 Mon Sep 17 00:00:00 2001 +From: Fedora Ninjas +Date: Wed, 18 May 2022 23:50:45 +0800 +Subject: [PATCH] add loongarch64 support + +--- + conf/Makefile.common | 4 + + configure.ac | 9 + + gentpl.py | 5 +- + grub-core/Makefile.am | 7 + + grub-core/Makefile.core.def | 20 + + grub-core/kern/efi/mm.c | 29 +- + grub-core/kern/elfXX.c | 6 + + grub-core/kern/loongarch64/cache.S | 26 + + grub-core/kern/loongarch64/dl.c | 258 +++++++++ + grub-core/kern/loongarch64/efi/init.c | 76 +++ + grub-core/kern/loongarch64/efi/startup.S | 45 ++ + grub-core/kern/loongarch64/init.c | 47 ++ + grub-core/lib/loongarch64/efi/loongson.c | 505 ++++++++++++++++ + grub-core/lib/loongarch64/efi/loongson_asm.S | 58 ++ + grub-core/lib/loongarch64/relocator.c | 163 ++++++ + grub-core/lib/loongarch64/relocator_asm.S | 51 ++ + grub-core/lib/loongarch64/setjmp.S | 74 +++ + grub-core/lib/loongson/reboot.c | 33 ++ + grub-core/lib/setjmp.S | 2 + + grub-core/loader/efi/chainloader.c | 2 + + grub-core/loader/loongarch64/linux.c | 580 +++++++++++++++++++ + include/grub/dl.h | 2 +- + include/grub/efi/api.h | 3 +- + include/grub/efi/pe32.h | 2 + + include/grub/elf.h | 55 ++ + include/grub/loongarch64/asm.h | 10 + + include/grub/loongarch64/efi/boot.h | 0 + include/grub/loongarch64/efi/loader.h | 25 + + include/grub/loongarch64/efi/loongson.h | 290 ++++++++++ + include/grub/loongarch64/efi/memory.h | 14 + + include/grub/loongarch64/efi/time.h | 0 + include/grub/loongarch64/io.h | 62 ++ + include/grub/loongarch64/kernel.h | 24 + + include/grub/loongarch64/linux.h | 22 + + include/grub/loongarch64/loongarch64.h | 30 + + include/grub/loongarch64/memory.h | 57 ++ + include/grub/loongarch64/relocator.h | 38 ++ + include/grub/loongarch64/setjmp.h | 27 + + include/grub/loongarch64/time.h | 39 ++ + include/grub/loongarch64/types.h | 34 ++ + include/grub/util/install.h | 1 + + util/grub-install-common.c | 43 +- + util/grub-install.c | 16 + + util/grub-mkimagexx.c | 349 ++++++++++- + util/grub-mknetdir.c | 3 +- + util/grub-module-verifier.c | 46 ++ + util/mkimage.c | 16 + + 47 files changed, 3176 insertions(+), 32 deletions(-) + create mode 100644 grub-core/kern/loongarch64/cache.S + create mode 100644 grub-core/kern/loongarch64/dl.c + create mode 100644 grub-core/kern/loongarch64/efi/init.c + create mode 100644 grub-core/kern/loongarch64/efi/startup.S + create mode 100644 grub-core/kern/loongarch64/init.c + create mode 100644 grub-core/lib/loongarch64/efi/loongson.c + create mode 100644 grub-core/lib/loongarch64/efi/loongson_asm.S + create mode 100644 grub-core/lib/loongarch64/relocator.c + create mode 100644 grub-core/lib/loongarch64/relocator_asm.S + create mode 100644 grub-core/lib/loongarch64/setjmp.S + create mode 100644 grub-core/lib/loongson/reboot.c + create mode 100644 grub-core/loader/loongarch64/linux.c + create mode 100644 include/grub/loongarch64/asm.h + create mode 100644 include/grub/loongarch64/efi/boot.h + create mode 100644 include/grub/loongarch64/efi/loader.h + create mode 100644 include/grub/loongarch64/efi/loongson.h + create mode 100644 include/grub/loongarch64/efi/memory.h + create mode 100644 include/grub/loongarch64/efi/time.h + create mode 100644 include/grub/loongarch64/io.h + create mode 100644 include/grub/loongarch64/kernel.h + create mode 100644 include/grub/loongarch64/linux.h + create mode 100644 include/grub/loongarch64/loongarch64.h + create mode 100644 include/grub/loongarch64/memory.h + create mode 100644 include/grub/loongarch64/relocator.h + create mode 100644 include/grub/loongarch64/setjmp.h + create mode 100644 include/grub/loongarch64/time.h + create mode 100644 include/grub/loongarch64/types.h + +diff --git a/conf/Makefile.common b/conf/Makefile.common +index 521cdda..cc1d190 100644 +--- a/conf/Makefile.common ++++ b/conf/Makefile.common +@@ -20,6 +20,10 @@ endif + if COND_powerpc_ieee1275 + CFLAGS_PLATFORM += -mcpu=powerpc + endif ++if COND_loongarch64 ++ CFLAGS_PLATFORM += -fno-strict-aliasing -march=loongarch64 -mabi=lp64 -fno-plt -Wa,-mla-global-with-pcrel ++ CPPFLAGS_PLATFORM = -fno-strict-aliasing -march=loongarch64 -mabi=lp64 -fno-plt -Wa,-mla-global-with-pcrel ++endif + + # Other options + +diff --git a/configure.ac b/configure.ac +index f59a7b8..4715d17 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -116,6 +116,10 @@ case "$target_cpu" in + i[[3456]]86) target_cpu=i386 ;; + amd64) target_cpu=x86_64 ;; + sparc) target_cpu=sparc64 ;; ++ loongarch64) ++ target_cpu=loongarch64 ++ machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_LOONGARCH64=1" ++ ;; + mipsel|mips64el) + target_cpu=mipsel + machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_CPU_MIPSEL=1" +@@ -148,6 +152,7 @@ if test "x$with_platform" = x; then + powerpc64-*) platform=ieee1275 ;; + powerpc64le-*) platform=ieee1275 ;; + sparc64-*) platform=ieee1275 ;; ++ loongarch64-*) platform=efi;; + mipsel-*) platform=loongson ;; + mips-*) platform=arc ;; + ia64-*) platform=efi ;; +@@ -196,6 +201,7 @@ case "$target_cpu"-"$platform" in + mipsel-yeeloong) platform=loongson ;; + mipsel-fuloong) platform=loongson ;; + mipsel-loongson) ;; ++ loongarch64-efi) ;; + arm-uboot) ;; + arm-coreboot) ;; + arm-efi) ;; +@@ -251,6 +257,7 @@ case "$platform" in + pc) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_PCBIOS=1" ;; + emu) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_EMU=1" ;; + loongson) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS_LOONGSON=1" ;; ++ loongson64) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_LOONARCH64=1" ;; + qemu_mips) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_MIPS_QEMU_MIPS=1" ;; + arc) machine_CPPFLAGS="$machine_CPPFLAGS -DGRUB_MACHINE_ARC=1" ;; + esac +@@ -2098,6 +2105,8 @@ AM_CONDITIONAL([COND_mips_arc], [test "(" x$target_cpu = xmips -o x$target_cpu = + AM_CONDITIONAL([COND_sparc64_ieee1275], [test x$target_cpu = xsparc64 -a x$platform = xieee1275]) + AM_CONDITIONAL([COND_sparc64_emu], [test x$target_cpu = xsparc64 -a x$platform = xemu]) + AM_CONDITIONAL([COND_powerpc_ieee1275], [test x$target_cpu = xpowerpc -a x$platform = xieee1275]) ++AM_CONDITIONAL([COND_loongarch64_efi], [test x$target_cpu = xloongarch64 -a x$platform = xefi]) ++AM_CONDITIONAL([COND_loongarch64], [test x$target_cpu = xloongarch64]) + AM_CONDITIONAL([COND_mips], [test x$target_cpu = xmips -o x$target_cpu = xmipsel]) + AM_CONDITIONAL([COND_mipsel], [test x$target_cpu = xmipsel]) + AM_CONDITIONAL([COND_mipseb], [test x$target_cpu = xmips]) +diff --git a/gentpl.py b/gentpl.py +index d662c30..3afd642 100644 +--- a/gentpl.py ++++ b/gentpl.py +@@ -32,7 +32,7 @@ GRUB_PLATFORMS = [ "emu", "i386_pc", "i386_efi", "i386_qemu", "i386_coreboot", + "mips_loongson", "sparc64_ieee1275", + "powerpc_ieee1275", "mips_arc", "ia64_efi", + "mips_qemu_mips", "arm_uboot", "arm_efi", "arm64_efi", +- "arm_coreboot"] ++ "arm_coreboot", "loongarch64_efi"] + + GROUPS = {} + +@@ -44,13 +44,14 @@ GROUPS["x86_64"] = [ "x86_64_efi" ] + GROUPS["x86"] = GROUPS["i386"] + GROUPS["x86_64"] + GROUPS["mips"] = [ "mips_loongson", "mips_qemu_mips", "mips_arc" ] + GROUPS["sparc64"] = [ "sparc64_ieee1275" ] ++GROUPS["loongarch64"] = [ "loongarch64_efi" ] + GROUPS["powerpc"] = [ "powerpc_ieee1275" ] + GROUPS["arm"] = [ "arm_uboot", "arm_efi", "arm_coreboot" ] + GROUPS["arm64"] = [ "arm64_efi" ] + + # Groups based on firmware + GROUPS["pc"] = [ "i386_pc" ] +-GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi" ] ++GROUPS["efi"] = [ "i386_efi", "x86_64_efi", "ia64_efi", "arm_efi", "arm64_efi", "loongarch64_efi"] + GROUPS["ieee1275"] = [ "i386_ieee1275", "sparc64_ieee1275", "powerpc_ieee1275" ] + GROUPS["uboot"] = [ "arm_uboot" ] + GROUPS["xen"] = [ "i386_xen", "x86_64_xen" ] +diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am +index 308ad88..24e2ac3 100644 +--- a/grub-core/Makefile.am ++++ b/grub-core/Makefile.am +@@ -222,6 +222,13 @@ KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/memory.h + KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/kernel.h + endif + ++if COND_loongarch64_efi ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/efi.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/efi/disk.h ++KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/acpi.h ++KERNEL_HEADER_FILES += $(top_builddir)/include/grub/machine/loongson.h ++endif ++ + if COND_powerpc_ieee1275 + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/ieee1275/ieee1275.h + KERNEL_HEADER_FILES += $(top_srcdir)/include/grub/terminfo.h +diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def +index ef06f8c..74e66d3 100644 +--- a/grub-core/Makefile.core.def ++++ b/grub-core/Makefile.core.def +@@ -95,6 +95,9 @@ kernel = { + arm_coreboot_ldflags = '-Wl,-r,-d'; + arm_coreboot_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version'; + ++ loongarch64_efi_ldflags = '-Wl,-r,-d'; ++ loongarch64_efi_stripflags = '--strip-unneeded -K start -R .note -R .comment -R .note.gnu.gold-version -R .eh_frame'; ++ + i386_pc_startup = kern/i386/pc/startup.S; + i386_efi_startup = kern/i386/efi/startup.S; + x86_64_efi_startup = kern/x86_64/efi/startup.S; +@@ -105,6 +108,7 @@ kernel = { + i386_coreboot_startup = kern/i386/coreboot/startup.S; + i386_multiboot_startup = kern/i386/coreboot/startup.S; + mips_startup = kern/mips/startup.S; ++ loongarch64_efi_startup = kern/loongarch64/efi/startup.S; + sparc64_ieee1275_startup = kern/sparc64/ieee1275/crt0.S; + powerpc_ieee1275_startup = kern/powerpc/ieee1275/startup.S; + arm_uboot_startup = kern/arm/startup.S; +@@ -295,6 +299,14 @@ kernel = { + extra_dist = video/sis315_init.c; + mips_loongson = commands/keylayouts.c; + ++ loongarch64 = kern/loongarch64/init.c; ++ loongarch64 = kern/loongarch64/dl.c; ++ loongarch64 = kern/loongarch64/cache.S; ++ loongarch64 = kern/generic/rtc_get_time_ms.c; ++ loongarch64_efi = kern/loongarch64/efi/init.c; ++ loongarch64_efi = lib/loongarch64/efi/loongson.c; ++ loongarch64_efi = lib/loongarch64/efi/loongson_asm.S; ++ + powerpc_ieee1275 = kern/powerpc/cache.S; + powerpc_ieee1275 = kern/powerpc/dl.c; + powerpc_ieee1275 = kern/powerpc/compiler-rt.S; +@@ -810,6 +822,7 @@ module = { + enable = sparc64_ieee1275; + enable = powerpc_ieee1275; + enable = mips_arc; ++ enable = loongarch64_efi; + enable = ia64_efi; + enable = arm_efi; + enable = arm64_efi; +@@ -896,6 +909,7 @@ module = { + i386_qemu = lib/i386/halt.c; + xen = lib/xen/halt.c; + efi = lib/efi/halt.c; ++ loongarch64_efi = commands/acpihalt.c; + ieee1275 = lib/ieee1275/halt.c; + emu = lib/emu/halt.c; + uboot = lib/dummy/halt.c; +@@ -911,6 +925,7 @@ module = { + mips_arc = lib/mips/arc/reboot.c; + mips_loongson = lib/mips/loongson/reboot.c; + mips_qemu_mips = lib/mips/qemu_mips/reboot.c; ++ loongarch64_efi = lib/loongson/reboot.c; + xen = lib/xen/reboot.c; + uboot = lib/uboot/reboot.c; + arm_coreboot = lib/dummy/reboot.c; +@@ -1608,6 +1623,8 @@ module = { + efi = lib/efi/relocator.c; + mips = lib/mips/relocator_asm.S; + mips = lib/mips/relocator.c; ++ loongarch64 = lib/loongarch64/relocator_asm.S; ++ loongarch64 = lib/loongarch64/relocator.c; + powerpc = lib/powerpc/relocator_asm.S; + powerpc = lib/powerpc/relocator.c; + xen = lib/xen/relocator.c; +@@ -1620,6 +1637,7 @@ module = { + extra_dist = kern/powerpc/cache_flush.S; + + enable = mips; ++ enable = loongarch64; + enable = powerpc; + enable = x86; + enable = xen; +@@ -1737,6 +1755,7 @@ module = { + xen = loader/i386/xen.c; + i386_pc = lib/i386/pc/vesa_modes_table.c; + mips = loader/mips/linux.c; ++ loongarch64 = loader/loongarch64/linux.c; + powerpc_ieee1275 = loader/powerpc/ieee1275/linux.c; + sparc64_ieee1275 = loader/sparc64/ieee1275/linux.c; + ia64_efi = loader/ia64/efi/linux.c; +@@ -1838,6 +1857,7 @@ module = { + enable = arm_efi; + enable = arm64_efi; + enable = mips; ++ enable = loongarch64_efi; + }; + + module = { +diff --git a/grub-core/kern/efi/mm.c b/grub-core/kern/efi/mm.c +index 9e76f23..fb087e3 100644 +--- a/grub-core/kern/efi/mm.c ++++ b/grub-core/kern/efi/mm.c +@@ -157,7 +157,11 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + grub_efi_physical_address_t ret = address; + + /* Limit the memory access to less than 4GB for 32-bit platforms. */ ++#ifdef GRUB_CPU_LOONGARCH64 ++ if (address > grub_efi_max_usable_address()) ++#else + if (address > GRUB_EFI_MAX_USABLE_ADDRESS) ++#endif + { + grub_error (GRUB_ERR_BAD_ARGUMENT, + N_("invalid memory address (0x%llx > 0x%llx)"), +@@ -177,7 +181,11 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + { + /* Uggh, the address 0 was allocated... This is too annoying, + so reallocate another one. */ ++#ifdef GRUB_CPU_LOONGARCH64 ++ ret = grub_efi_max_usable_address(); ++#else + ret = address; ++#endif + status = efi_call_4 (b->allocate_pages, alloctype, memtype, pages, &ret); + grub_efi_free_pages (0, pages); + if (status != GRUB_EFI_SUCCESS) +@@ -195,9 +203,14 @@ grub_efi_allocate_pages_real (grub_efi_physical_address_t address, + void * + grub_efi_allocate_any_pages (grub_efi_uintn_t pages) + { +- return grub_efi_allocate_pages_real (GRUB_EFI_MAX_USABLE_ADDRESS, ++#ifdef GRUB_CPU_LOONGARCH64 ++ return grub_efi_allocate_pages_real (grub_efi_max_usable_address(), + pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, + GRUB_EFI_LOADER_DATA); ++#else ++ return grub_efi_allocate_pages_real (GRUB_EFI_MAX_USABLE_ADDRESS, ++ pages, GRUB_EFI_ALLOCATE_MAX_ADDRESS, ++#endif GRUB_EFI_LOADER_DATA); + } + + void * +@@ -471,7 +484,9 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + desc = NEXT_MEMORY_DESCRIPTOR (desc, desc_size)) + { + if (desc->type == GRUB_EFI_CONVENTIONAL_MEMORY +-#if 1 ++#ifdef GRUB_CPU_LOONGARCH64 ++ && desc->physical_start <= grub_efi_max_usable_address() ++#else + && desc->physical_start <= GRUB_EFI_MAX_ALLOCATION_ADDRESS + #endif + && desc->physical_start + PAGES_TO_BYTES (desc->num_pages) > 0x100000 +@@ -486,8 +501,14 @@ filter_memory_map (grub_efi_memory_descriptor_t *memory_map, + - desc->physical_start); + desc->physical_start = 0x100000; + } +- +-#if 1 ++#ifdef GRUB_CPU_LOONGARCH64 ++ if (BYTES_TO_PAGES (filtered_desc->physical_start) ++ + filtered_desc->num_pages ++ > BYTES_TO_PAGES_DOWN (grub_efi_max_usable_address())) ++ filtered_desc->num_pages ++ = (BYTES_TO_PAGES_DOWN (grub_efi_max_usable_address()) ++ - BYTES_TO_PAGES (filtered_desc->physical_start)); ++#else + if (BYTES_TO_PAGES (filtered_desc->physical_start) + + filtered_desc->num_pages + > BYTES_TO_PAGES_DOWN (GRUB_EFI_MAX_ALLOCATION_ADDRESS)) +diff --git a/grub-core/kern/elfXX.c b/grub-core/kern/elfXX.c +index 1859d18..8b1dce9 100644 +--- a/grub-core/kern/elfXX.c ++++ b/grub-core/kern/elfXX.c +@@ -134,6 +134,12 @@ grub_elfXX_load (grub_elf_t elf, const char *filename, + load_addr &= 0x3FFFFFFFFFFFFFFFULL; + break; + } ++#ifdef GRUB_CPU_LOONGARCH64 ++ grub_uint64_t addr; ++ asm volatile ("csrrd %0, 0x181" : "=r" (addr)); ++ if ((load_addr >> 48) != (addr >> 48)) ++ return grub_error (GRUB_ERR_BAD_OS, "bad address space"); ++#endif + load_addr += (grub_addr_t) load_offset; + + if (load_addr < load_base) +diff --git a/grub-core/kern/loongarch64/cache.S b/grub-core/kern/loongarch64/cache.S +new file mode 100644 +index 0000000..d291c67 +--- /dev/null ++++ b/grub-core/kern/loongarch64/cache.S +@@ -0,0 +1,26 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009,2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++ ++FUNCTION (grub_arch_sync_caches) ++ jr $ra ++ ++FUNCTION (grub_arch_sync_dma_caches) ++ jr $ra ++ +diff --git a/grub-core/kern/loongarch64/dl.c b/grub-core/kern/loongarch64/dl.c +new file mode 100644 +index 0000000..a6fd387 +--- /dev/null ++++ b/grub-core/kern/loongarch64/dl.c +@@ -0,0 +1,258 @@ ++/* loongarch64/dl.c - arch-dependent part of loadable module support */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2005,2007,2009,2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* Check if EHDR is a valid ELF header. */ ++grub_err_t ++grub_arch_dl_check_header (void *ehdr) ++{ ++ Elf_Ehdr *e = ehdr; ++ ++ /* Check the magic numbers. */ ++ if (e->e_ident[EI_CLASS] != ELFCLASS64 ++ || e->e_ident[EI_DATA] != ELFDATA2LSB ++ || e->e_machine != EM_LOONGARCH64) ++ return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic")); ++ ++ return GRUB_ERR_NONE; ++} ++ ++#pragma GCC diagnostic ignored "-Wcast-align" ++ ++grub_err_t ++grub_arch_dl_get_tramp_got_size (const void *ehdr __attribute__ ((unused)), ++ grub_size_t *tramp, grub_size_t *got) ++{ ++ *tramp = 0; ++ *got = 0; ++ return GRUB_ERR_NONE; ++} ++ ++/* Relocate symbols. */ ++grub_err_t ++grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr, ++ Elf_Shdr *s, grub_dl_segment_t seg) ++{ ++ Elf_Ehdr *e = ehdr; ++ Elf_Rel *rel, *max; ++ grub_uint64_t oprs[10240]={0}; ++ int opri=-1; ++ grub_uint32_t la_abs = 0; ++ ++ for (rel = (Elf_Rel *) ((char *) e + s->sh_offset), ++ max = (Elf_Rel *) ((char *) rel + s->sh_size); ++ rel < max; ++ rel = (Elf_Rel *) ((char *) rel + s->sh_entsize)) ++ { ++ grub_uint8_t *addr; ++ Elf_Sym *sym; ++ Elf_Addr r_info; ++ grub_uint64_t sym_value; ++ ++ if (seg->size < rel->r_offset) ++ return grub_error (GRUB_ERR_BAD_MODULE, ++ "reloc offset is out of the segment"); ++ ++ r_info = (grub_uint64_t) (rel->r_info); ++ ++ addr = (grub_uint8_t *) ((char*)seg->addr + rel->r_offset); ++ sym = (Elf_Sym *) ((char*)mod->symtab ++ + mod->symsize * ELF_R_SYM (r_info)); ++ sym_value = sym->st_value; ++ if (s->sh_type == SHT_RELA) ++ { ++ sym_value += ((Elf_Rela *) rel)->r_addend; ++ } ++ switch (ELF_R_TYPE (r_info)) ++ { ++ case R_LARCH_64: ++ { ++ *(grub_uint64_t *)addr=(grub_uint64_t)sym_value; ++ } ++ break; ++ case R_LARCH_MARK_LA: ++ { ++ la_abs=1; ++ } ++ break; ++ case R_LARCH_SOP_PUSH_PCREL: ++ { ++ opri++; ++ oprs[opri]=(grub_uint64_t)(sym_value-(grub_uint64_t)addr); ++ } ++ break; ++ case R_LARCH_SOP_PUSH_ABSOLUTE: ++ { ++ opri++; ++ oprs[opri]=(grub_uint64_t)sym_value; ++ } ++ break; ++ case R_LARCH_SOP_PUSH_PLT_PCREL: ++ { ++ opri++; ++ oprs[opri]=(grub_uint64_t)(sym_value-(grub_uint64_t)addr); ++ } ++ break; ++ case R_LARCH_SOP_SUB: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 - opr2; ++ } ++ break; ++ case R_LARCH_SOP_SL: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 << opr2; ++ } ++ break; ++ case R_LARCH_SOP_SR: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 >> opr2; ++ } ++ break; ++ case R_LARCH_SOP_ADD: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 + opr2; ++ } ++ break; ++ case R_LARCH_SOP_AND: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 & opr2; ++ } ++ break; ++ case R_LARCH_SOP_IF_ELSE: ++ { ++ grub_uint64_t opr3=oprs[opri]; ++ opri--; ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ if(opr1){ ++ opri++; ++ oprs[opri]=opr2; ++ } else { ++ opri++; ++ oprs[opri]=opr3; ++ } ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_5: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | ((opr1 & 0x1f) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_U_10_12: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | ((opr1 & 0xfff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_12: ++ { ++ if(la_abs==1) ++ la_abs=0; ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr= (*(grub_uint64_t *)addr) | ((opr1 & 0xfff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_16: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr= (*(grub_uint64_t *)addr) | ((opr1 & 0xffff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_16_S2: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr= (*(grub_uint64_t *)addr) | (((opr1 >> 2) & 0xffff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_5_20: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr= (*(grub_uint64_t *)addr) | ((opr1 & 0xfffff)<<5) ; ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | (((opr1 >> 2) & 0xffff) << 10); ++ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | ((opr1 >> 18) & 0x1f); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | (((opr1 >> 2) & 0xffff) << 10); ++ *(grub_uint64_t *)addr=(*(grub_uint64_t *)addr) | ((opr1 >> 18) & 0x3ff); ++ } ++ break; ++ default: ++ { ++ return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, ++ N_("relocation 0x%x is not implemented yet"), ++ ELF_R_TYPE (r_info)); ++ } ++ break; ++ } ++ } ++ ++ return GRUB_ERR_NONE; ++} ++ +diff --git a/grub-core/kern/loongarch64/efi/init.c b/grub-core/kern/loongarch64/efi/init.c +new file mode 100644 +index 0000000..b21d4f1 +--- /dev/null ++++ b/grub-core/kern/loongarch64/efi/init.c +@@ -0,0 +1,76 @@ ++/* init.c - initialize an arm-based EFI system */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2013 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++static grub_uint64_t tmr; ++static grub_efi_event_t tmr_evt; ++ ++static grub_uint64_t ++grub_efi_get_time_ms (void) ++{ ++ return tmr; ++} ++ ++static void ++grub_loongson_increment_timer (grub_efi_event_t event __attribute__ ((unused)), ++ void *context __attribute__ ((unused))) ++{ ++ tmr += 10; ++} ++ ++ ++ ++void ++grub_machine_init (void) ++{ ++ grub_efi_boot_services_t *b; ++ ++ grub_efi_init (); ++ ++ b = grub_efi_system_table->boot_services; ++ efi_call_5 (b->create_event, GRUB_EFI_EVT_TIMER | GRUB_EFI_EVT_NOTIFY_SIGNAL, ++ GRUB_EFI_TPL_CALLBACK, grub_loongson_increment_timer, NULL, &tmr_evt); ++ efi_call_3 (b->set_timer, tmr_evt, GRUB_EFI_TIMER_PERIODIC, 100000); ++ ++ grub_install_get_time_ms (grub_efi_get_time_ms); ++} ++ ++void ++grub_machine_fini (int flags) ++{ ++ grub_efi_boot_services_t *b; ++ ++ if (!(flags & GRUB_LOADER_FLAG_NORETURN)) ++ return; ++ ++ b = grub_efi_system_table->boot_services; ++ ++ efi_call_3 (b->set_timer, tmr_evt, GRUB_EFI_TIMER_CANCEL, 0); ++ efi_call_1 (b->close_event, tmr_evt); ++ ++ grub_efi_fini (); ++} +diff --git a/grub-core/kern/loongarch64/efi/startup.S b/grub-core/kern/loongarch64/efi/startup.S +new file mode 100644 +index 0000000..1ffff08 +--- /dev/null ++++ b/grub-core/kern/loongarch64/efi/startup.S +@@ -0,0 +1,45 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2013 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++ ++ .file "startup.S" ++ .text ++ .globl start, _start ++ .align 4 ++ ++FUNCTION(start) ++FUNCTION(_start) ++ /* ++ * EFI_SYSTEM_TABLE and EFI_HANDLE are passed in a1/a0. ++ */ ++ addi.d $sp, $sp, -16 ++ st.d $ra, $sp, 0 ++ ++ la $a2, grub_efi_image_handle ++ st.d $a0, $a2, 0 ++ la $a2, grub_efi_system_table ++ st.d $a1, $a2, 0 ++ ++ bl grub_main ++ ++1: ++ ld.d $ra, $sp, 0 ++ addi.d $sp, $sp, 16 ++ jr $ra ++ +diff --git a/grub-core/kern/loongarch64/init.c b/grub-core/kern/loongarch64/init.c +new file mode 100644 +index 0000000..b2de930 +--- /dev/null ++++ b/grub-core/kern/loongarch64/init.c +@@ -0,0 +1,47 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009,2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++ ++grub_uint32_t grub_arch_cpuclock; ++ ++/* FIXME: use interrupt to count high. */ ++grub_uint64_t ++grub_get_rtc (void) ++{ ++ static grub_uint32_t high = 0; ++ static grub_uint32_t last = 0; ++ grub_uint32_t low; ++ ++ asm volatile ("csrrd %0, " GRUB_CPU_LOONGARCH_COP0_TIMER_COUNT : "=r" (low)); ++ if (low < last) ++ high++; ++ last = low; ++ ++ return (((grub_uint64_t) high) << 32) | low; ++} ++ ++void ++grub_timer_init (grub_uint32_t cpuclock) ++{ ++ grub_arch_cpuclock = cpuclock; ++ grub_install_get_time_ms (grub_rtc_get_time_ms); ++} +diff --git a/grub-core/lib/loongarch64/efi/loongson.c b/grub-core/lib/loongarch64/efi/loongson.c +new file mode 100644 +index 0000000..8b60d82 +--- /dev/null ++++ b/grub-core/lib/loongarch64/efi/loongson.c +@@ -0,0 +1,505 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define loongson_params (&loongson_boot_params->boot_params.efi.smbios.lp) ++#define loongson_boot_params_size ALIGN_UP (sizeof (*loongson_boot_params), 8) ++#define loongson_reset_code_size (&grub_efi_loongson_reset_end - &grub_efi_loongson_reset_start) ++ ++extern grub_uint8_t grub_efi_loongson_reset_start; ++extern grub_uint8_t grub_efi_loongson_reset_end; ++ ++static struct ++{ ++ grub_efi_loongson_boot_params boot_params; ++ grub_efi_loongson_memory_map memory_map; ++ grub_efi_loongson_cpu_info cpu_info; ++ grub_efi_loongson_system_info system_info; ++ grub_efi_loongson_irq_src_routing_table irq_src_routing_table; ++ grub_efi_loongson_interface_info interface_info; ++ grub_efi_loongson_special_attribute special_attribute; ++ grub_efi_loongson_board_devices board_devices; ++} GRUB_PACKED ++* loongson_boot_params; ++ ++static void ++grub_efi_loongson_init_reset_system (void) ++{ ++ grub_efi_loongson_boot_params *boot_params; ++ grub_uint8_t *reset_code_addr = (grub_uint8_t *) loongson_boot_params + ++ loongson_boot_params_size; ++ ++ boot_params = &loongson_boot_params->boot_params; ++ grub_efi_loongson_reset_system_addr = ++ (grub_uint64_t) grub_efi_system_table->runtime_services->reset_system; ++ grub_memcpy (reset_code_addr, &grub_efi_loongson_reset_start, loongson_reset_code_size); ++ grub_arch_sync_caches (reset_code_addr, loongson_reset_code_size); ++ ++ boot_params->reset_system.reset_cold = (grub_uint64_t) reset_code_addr + ++ ((grub_uint64_t) &grub_efi_loongson_reset_cold - ++ (grub_uint64_t) &grub_efi_loongson_reset_start); ++ boot_params->reset_system.reset_warm = (grub_uint64_t) reset_code_addr + ++ ((grub_uint64_t) &grub_efi_loongson_reset_warm - ++ (grub_uint64_t) &grub_efi_loongson_reset_start); ++ boot_params->reset_system.shutdown = (grub_uint64_t) reset_code_addr + ++ ((grub_uint64_t) &grub_efi_loongson_reset_shutdown - ++ (grub_uint64_t) &grub_efi_loongson_reset_start); ++ boot_params->reset_system.do_suspend = (grub_uint64_t) reset_code_addr + ++ ((grub_uint64_t) &grub_efi_loongson_reset_suspend - ++ (grub_uint64_t) &grub_efi_loongson_reset_start); ++} ++ ++static void ++grub_efi_loongson_init_smbios (grub_efi_loongson_smbios_table *smbios_table) ++{ ++ grub_efi_loongson_smbios_table *dst = &loongson_boot_params->boot_params.efi.smbios; ++ ++ dst->vers = smbios_table->vers; ++ dst->vga_bios = smbios_table->vga_bios; ++} ++ ++static void ++grub_efi_loongson_init_cpu_info (grub_efi_loongson_smbios_table *smbios_table) ++{ ++ grub_efi_loongson_cpu_info *src = (void *) smbios_table->lp.cpu_offset; ++ grub_efi_loongson_cpu_info *dst = &loongson_boot_params->cpu_info; ++ ++ if (!src) ++ return; ++ ++ grub_memcpy (dst, src, sizeof (grub_efi_loongson_cpu_info)); ++ loongson_params->cpu_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; ++} ++ ++static void ++grub_efi_loongson_init_system_info (grub_efi_loongson_smbios_table *smbios_table) ++{ ++ grub_efi_loongson_system_info *src = (void *) smbios_table->lp.system_offset; ++ grub_efi_loongson_system_info *dst = &loongson_boot_params->system_info; ++ ++ if (!src) ++ return; ++ ++ grub_memcpy (dst, src, sizeof (grub_efi_loongson_system_info)); ++ loongson_params->system_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; ++} ++ ++static void ++grub_efi_loongson_init_irq_src_routing_table (grub_efi_loongson_smbios_table *smbios_table) ++{ ++ grub_efi_loongson_irq_src_routing_table *src = (void *) smbios_table->lp.irq_offset; ++ grub_efi_loongson_irq_src_routing_table *dst = &loongson_boot_params->irq_src_routing_table; ++ ++ if (!src) ++ return; ++ ++ grub_memcpy (dst, src, sizeof (grub_efi_loongson_irq_src_routing_table)); ++ loongson_params->irq_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; ++} ++ ++static void ++grub_efi_loongson_init_interface_info (grub_efi_loongson_smbios_table *smbios_table) ++{ ++ grub_efi_loongson_interface_info *src = (void *) smbios_table->lp.interface_offset; ++ grub_efi_loongson_interface_info *dst = &loongson_boot_params->interface_info; ++ ++ if (!src) ++ return; ++ ++ grub_memcpy (dst, src, sizeof (grub_efi_loongson_interface_info)); ++ loongson_params->interface_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; ++} ++ ++static void ++grub_efi_loongson_init_special_attribute (grub_efi_loongson_smbios_table *smbios_table) ++{ ++ grub_efi_loongson_special_attribute *src = (void *) smbios_table->lp.special_offset; ++ grub_efi_loongson_special_attribute *dst = &loongson_boot_params->special_attribute; ++ ++ if (!src) ++ return; ++ ++ grub_memcpy (dst, src, sizeof (grub_efi_loongson_special_attribute)); ++ loongson_params->special_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; ++} ++ ++static void ++grub_efi_loongson_init_board_devices (grub_efi_loongson_smbios_table *smbios_table) ++{ ++ grub_efi_loongson_board_devices *src = (void *) smbios_table->lp.boarddev_table_offset; ++ grub_efi_loongson_board_devices *dst = &loongson_boot_params->board_devices; ++ ++ if (!src) ++ return; ++ ++ grub_memcpy (dst, src, sizeof (grub_efi_loongson_board_devices)); ++ loongson_params->boarddev_table_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; ++} ++ ++#define ADD_MEMORY_DESCRIPTOR(desc, size) \ ++ ((grub_efi_memory_descriptor_t *) ((char *) (desc) + (size))) ++ ++static void ++grub_efi_loongson_init_memory_map (grub_efi_loongson_smbios_table *smbios_table, ++ grub_efi_memory_descriptor_t *mmap_buf, ++ grub_efi_uintn_t mmap_size, ++ grub_efi_uintn_t desc_size) ++{ ++ grub_efi_loongson_memory_map *src = (void *) smbios_table->lp.memory_offset; ++ grub_efi_loongson_memory_map *dst = &loongson_boot_params->memory_map; ++ grub_efi_memory_descriptor_t *mmap_end; ++ grub_efi_memory_descriptor_t *desc; ++ grub_efi_memory_descriptor_t *desc_next; ++ grub_efi_uint32_t mem_types_reserved[] = ++ { ++ 1, // GRUB_EFI_RESERVED_MEMORY_TYPE ++ 0, // GRUB_EFI_LOADER_CODE ++ 0, // GRUB_EFI_LOADER_DATA ++ 0, // GRUB_EFI_BOOT_SERVICES_CODE ++ 0, // GRUB_EFI_BOOT_SERVICES_DATA ++ 1, // GRUB_EFI_RUNTIME_SERVICES_CODE ++ 1, // GRUB_EFI_RUNTIME_SERVICES_DATA ++ 0, // GRUB_EFI_CONVENTIONAL_MEMORY ++ 1, // GRUB_EFI_UNUSABLE_MEMORY ++ 0, // GRUB_EFI_ACPI_RECLAIM_MEMORY ++ 0, // GRUB_EFI_ACPI_MEMORY_NVS ++ 1, // GRUB_EFI_MEMORY_MAPPED_IO ++ 1, // GRUB_EFI_MEMORY_MAPPED_IO_PORT_SPACE ++ 1, // GRUB_EFI_PAL_CODE ++ 1, // GRUB_EFI_PERSISTENT_MEMORY ++ }; ++ grub_uint32_t need_sort = 1; ++ ++ if (!src) ++ return; ++ ++ dst->vers = src->vers; ++ dst->nr_map = 0; ++ dst->mem_freq = src->mem_freq; ++ loongson_params->memory_offset = (grub_uint64_t) dst - (grub_uint64_t) loongson_params; ++ ++ if (!mmap_buf || !mmap_size || !desc_size) ++ return; ++ ++ mmap_end = ADD_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); ++ ++ /* drop reserved */ ++ for (desc = mmap_buf, ++ desc_next = desc; ++ desc < mmap_end; ++ desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) ++ { ++ desc->type = mem_types_reserved[desc->type]; ++ if (desc->type) ++ continue; ++ ++ if (desc != desc_next) ++ *desc_next = *desc; ++ desc_next = ADD_MEMORY_DESCRIPTOR (desc_next, desc_size); ++ } ++ mmap_end = desc_next; ++ ++ /* sort: low->high */ ++ while (need_sort) ++ { ++ need_sort = 0; ++ ++ for (desc = mmap_buf, ++ desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size); ++ (desc < mmap_end) && (desc_next < mmap_end); ++ desc = desc_next, ++ desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) ++ { ++ grub_efi_memory_descriptor_t tmp; ++ ++ if (desc->physical_start <= desc_next->physical_start) ++ continue; ++ ++ tmp = *desc; ++ *desc = *desc_next; ++ *desc_next = tmp; ++ need_sort = 1; ++ } ++ } ++ ++ /* combine continuous memory map */ ++ for (desc = mmap_buf, ++ desc_next = ADD_MEMORY_DESCRIPTOR (desc, desc_size); ++ desc_next < mmap_end; ++ desc_next = ADD_MEMORY_DESCRIPTOR (desc_next, desc_size)) ++ { ++ grub_efi_physical_address_t prev_end = desc->physical_start + (desc->num_pages << 12); ++ ++ if (prev_end == desc_next->physical_start) ++ { ++ desc->num_pages += desc_next->num_pages; ++ continue; ++ } ++ ++ desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size); ++ grub_memcpy (desc, desc_next, desc_size); ++ } ++ mmap_end = ADD_MEMORY_DESCRIPTOR (desc, desc_size); ++ ++ /* write to loongson memory map */ ++ for (desc = mmap_buf; ++ desc < mmap_end; ++ desc = ADD_MEMORY_DESCRIPTOR (desc, desc_size)) ++ { ++ grub_efi_physical_address_t physical_start = grub_vtop ((void *) desc->physical_start); ++ grub_efi_physical_address_t physical_end = physical_start + (desc->num_pages << 12); ++ ++ physical_start = ALIGN_UP (physical_start, 0x100000); ++ physical_end = ALIGN_DOWN (physical_end, 0x100000); ++ ++ if (physical_start >= physical_end || (physical_end - physical_start) < 0x100000) ++ continue; ++ ++ dst->map[dst->nr_map].node_id = (desc->physical_start >> 44) & 0xf; ++ dst->map[dst->nr_map].mem_type = GRUB_EFI_LOONGSON_SYSTEM_RAM; ++ dst->map[dst->nr_map].mem_start = physical_start; ++ dst->map[dst->nr_map].mem_size = (physical_end - physical_start) >> 20; ++ ++ grub_dprintf ("loongson", "memory map %03u: 0x%016lx 0x%016lx @ %u\n", ++ dst->nr_map, physical_start, physical_end - physical_start, ++ dst->map[dst->nr_map].node_id); ++ ++ dst->nr_map ++; ++ } ++} ++ ++#define BYTES_TO_PAGES(bytes) (((bytes) + 0xfff) >> 12) ++#define SUB_MEMORY_DESCRIPTOR(desc, size) \ ++ ((grub_efi_memory_descriptor_t *) ((char *) (desc) - (size))) ++ ++void ++grub_efi_loongson_alloc_boot_params (void) ++{ ++ grub_efi_memory_descriptor_t *mmap_buf; ++ grub_efi_memory_descriptor_t *mmap_end; ++ grub_efi_memory_descriptor_t *desc; ++ grub_efi_uintn_t mmap_size; ++ grub_efi_uintn_t desc_size; ++ grub_efi_physical_address_t address; ++ grub_efi_allocate_type_t type; ++ grub_efi_uintn_t pages; ++ grub_efi_status_t status; ++ grub_efi_boot_services_t *b; ++ int mm_status; ++ ++ type = GRUB_EFI_ALLOCATE_ADDRESS; ++ pages = BYTES_TO_PAGES (loongson_boot_params_size + loongson_reset_code_size); ++ ++ mmap_size = (1 << 12); ++ mmap_buf = grub_malloc (mmap_size); ++ if (!mmap_buf) ++ grub_fatal ("out of memory!"); ++ ++ mm_status = grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0); ++ if (mm_status == 0) ++ { ++ grub_free (mmap_buf); ++ mmap_size += desc_size * 32; ++ ++ mmap_buf = grub_malloc (mmap_size); ++ if (!mmap_buf) ++ grub_fatal ("out of memory!"); ++ ++ mm_status = grub_efi_get_memory_map (&mmap_size, mmap_buf, 0, &desc_size, 0); ++ } ++ ++ if (mm_status < 0) ++ grub_fatal ("cannot get memory map!"); ++ ++ mmap_end = ADD_MEMORY_DESCRIPTOR (mmap_buf, mmap_size); ++ ++ for (desc = SUB_MEMORY_DESCRIPTOR (mmap_end, desc_size); ++ desc >= mmap_buf; ++ desc = SUB_MEMORY_DESCRIPTOR (desc, desc_size)) ++ { ++ if (desc->type != GRUB_EFI_CONVENTIONAL_MEMORY) ++ continue; ++ if (desc->physical_start >= grub_efi_max_usable_address()) ++ continue; ++ if (desc->num_pages < pages) ++ continue; ++ ++ address = desc->physical_start; ++ break; ++ } ++ ++ grub_free (mmap_buf); ++ ++ b = grub_efi_system_table->boot_services; ++ status = efi_call_4 (b->allocate_pages, type, GRUB_EFI_RUNTIME_SERVICES_DATA, pages, &address); ++ if (status != GRUB_EFI_SUCCESS) ++ grub_fatal ("cannot allocate Loongson boot parameters!"); ++ ++ loongson_boot_params = (void *) ((grub_addr_t) address); ++} ++ ++void ++grub_efi_loongson_free_boot_params (void) ++{ ++ grub_efi_free_pages ((grub_addr_t) loongson_boot_params, ++ BYTES_TO_PAGES (loongson_boot_params_size + loongson_reset_code_size)); ++} ++ ++void * ++grub_efi_loongson_get_smbios_table (void) ++{ ++ static grub_efi_loongson_smbios_table *smbios_table; ++ grub_efi_loongson_boot_params *old_boot_params; ++ struct bootparamsinterface* boot_params; ++ void * tmp_boot_params = NULL; ++ char * p = NULL; ++ if(smbios_table) ++ return smbios_table; ++ ++ tmp_boot_params = grub_efi_loongson_get_boot_params(); ++ if(tmp_boot_params == NULL) ++ { ++ grub_dprintf("loongson", "tmp_boot_params is NULL\n"); ++ return tmp_boot_params; ++ } ++ ++ boot_params = (struct bootparamsinterface *)tmp_boot_params; ++ p = (char *)&(boot_params->signature); ++ if(grub_strncmp(p, "BPI", 3) == 0) ++ { ++ grub_dprintf("loongson", "find new bpi\n"); ++ return boot_params ? boot_params : 0; ++ } ++ else ++ { ++ old_boot_params = (grub_efi_loongson_boot_params *)tmp_boot_params; ++ /* ++ { ++ grub_dprintf("loongson", "smbios addr%llx\n", &old_boot_params->efi.smbios); ++ grub_dprintf("loongson", "smbios vers%d\n", (grub_uint16_t)(&old_boot_params->efi.smbios.vers)); ++ grub_dprintf("loongson", "smbios vga_bios%d\n", &old_boot_params->efi.smbios.vga_bios); ++ grub_dprintf("loongson", "lp memory offset %llx\n", &old_boot_params->efi.smbios.lp.memory_offset); ++ grub_dprintf("loongson", "lp cpu offset %llx\n", &old_boot_params->efi.smbios.lp.cpu_offset); ++ grub_dprintf("loongson", "lp system offset %llx\n", &old_boot_params->efi.smbios.lp.system_offset); ++ grub_dprintf("loongson", "lp irq offset %llx\n", &old_boot_params->efi.smbios.lp.irq_offset); ++ grub_dprintf("loongson", "lp interface offset %llx\n", &old_boot_params->efi.smbios.p.interface_offset); ++ grub_dprintf("loongson", "lp special offset %llx\n", &old_boot_params->efi.smbios.lp.special_offset); ++ grub_dprintf("loongson", "lp boarddev table offset %llx\n", &old_boot_params->efi.smbios.lp.boarddev_table_offset); ++ } ++ */ ++ return old_boot_params ? &old_boot_params->efi.smbios : 0; ++ } ++ ++} ++ ++int ++grub_efi_is_loongson (void) ++{ ++ return grub_efi_loongson_get_smbios_table () ? 1 : 0; ++} ++ ++void * ++grub_efi_loongson_get_boot_params (void) ++{ ++ static void * boot_params = NULL; ++ grub_efi_configuration_table_t *tables; ++ grub_efi_guid_t smbios_guid = GRUB_EFI_LOONGSON_SMBIOS_TABLE_GUID; ++ unsigned int i; ++ ++ if (boot_params) ++ return boot_params; ++ ++ /* Look for Loongson SMBIOS in UEFI config tables. */ ++ tables = grub_efi_system_table->configuration_table; ++ ++ for (i = 0; i < grub_efi_system_table->num_table_entries; i++) ++ if (grub_memcmp (&tables[i].vendor_guid, &smbios_guid, sizeof (smbios_guid)) == 0) ++ { ++ boot_params= tables[i].vendor_table; ++ grub_dprintf ("loongson", "found registered SMBIOS @ %p\n", boot_params); ++ break; ++ } ++ return boot_params; ++} ++ ++grub_uint8_t ++grub_efi_loongson_calculatesum8 (const grub_uint8_t *buffer, grub_efi_uintn_t length) ++{ ++ grub_uint8_t sum; ++ grub_efi_uintn_t count; ++ ++ for (sum = 0, count = 0; count < length; count++) ++ { ++ sum = (grub_uint8_t) (sum + *(buffer + count)); ++ } ++ return sum; ++} ++ ++grub_uint8_t ++grub_efi_loongson_grub_calculatechecksum8 (const grub_uint8_t *buffer, grub_efi_uintn_t length) ++{ ++ grub_uint8_t checksum; ++ ++ checksum = grub_efi_loongson_calculatesum8(buffer, length); ++ ++ return (grub_uint8_t) (0x100 - checksum); ++} ++ ++ ++grub_uint32_t ++grub_efi_loongson_memmap_sort(struct memmap array[], grub_uint32_t length, mem_map * bpmem, grub_uint32_t index, grub_uint32_t memtype) ++{ ++ grub_uint64_t tempmemsize = 0; ++ grub_uint32_t j = 0; ++ grub_uint32_t t = 0; ++ ++ for(j = 0; j < length;) ++ { ++ tempmemsize = array[j].memsize; ++ for(t = j + 1; t < length; t++) ++ { ++ if(array[j].memstart + tempmemsize == array[t].memstart) ++ { ++ tempmemsize += array[t].memsize; ++ } ++ else ++ { ++ break; ++ } ++ } ++ bpmem->map[index].memtype = memtype; ++ bpmem->map[index].memstart = array[j].memstart; ++ bpmem->map[index].memsize = tempmemsize; ++ grub_dprintf("loongson", "map[%d]:type %x, start 0x%llx, end 0x%llx\n", ++ index, ++ bpmem->map[index].memtype, ++ bpmem->map[index].memstart, ++ bpmem->map[index].memstart+ bpmem->map[index].memsize ++ ); ++ j = t; ++ index++; ++ } ++ return index; ++} ++ +diff --git a/grub-core/lib/loongarch64/efi/loongson_asm.S b/grub-core/lib/loongarch64/efi/loongson_asm.S +new file mode 100644 +index 0000000..4a04d34 +--- /dev/null ++++ b/grub-core/lib/loongarch64/efi/loongson_asm.S +@@ -0,0 +1,58 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++ ++ .file "loongson_asm.S" ++ .text ++ ++ .align 4 ++ ++VARIABLE (grub_efi_loongson_reset_start) ++ ++VARIABLE (grub_efi_loongson_reset_system_addr) ++ .dword 0 ++ ++reset_system: ++ bl 1f ++ move $a1, $zero ++1: ++ ld.d $t8, $ra, -16 ++ move $a2, $zero ++ jr $t8 ++ move $a3, $zero ++ ++FUNCTION(grub_efi_loongson_reset_cold) ++ b reset_system ++ li.w $a0, 0 ++ ++FUNCTION(grub_efi_loongson_reset_warm) ++ b reset_system ++ li.w $a0, 1 ++ ++FUNCTION(grub_efi_loongson_reset_shutdown) ++ b reset_system ++ li.w $a0, 2 ++ ++FUNCTION(grub_efi_loongson_reset_suspend) ++ b reset_system ++ li.w $a0, 3 ++ ++VARIABLE (grub_efi_loongson_reset_end) ++ ++ +diff --git a/grub-core/lib/loongarch64/relocator.c b/grub-core/lib/loongarch64/relocator.c +new file mode 100644 +index 0000000..f6c1b01 +--- /dev/null ++++ b/grub-core/lib/loongarch64/relocator.c +@@ -0,0 +1,163 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++#include ++#include ++ ++extern grub_uint8_t grub_relocator_forward_start; ++extern grub_uint8_t grub_relocator_forward_end; ++extern grub_uint8_t grub_relocator_backward_start; ++extern grub_uint8_t grub_relocator_backward_end; ++ ++#define REGW_SIZEOF (4 * sizeof (grub_uint32_t)) ++#define JUMP_SIZEOF (2 * sizeof (grub_uint32_t)) ++ ++#define RELOCATOR_SRC_SIZEOF(x) (&grub_relocator_##x##_end \ ++ - &grub_relocator_##x##_start) ++#define RELOCATOR_SIZEOF(x) (RELOCATOR_SRC_SIZEOF(x) \ ++ + REGW_SIZEOF * 3) ++grub_size_t grub_relocator_align = sizeof (grub_uint64_t); ++grub_size_t grub_relocator_forward_size; ++grub_size_t grub_relocator_backward_size; ++grub_size_t grub_relocator_jumper_size = JUMP_SIZEOF + REGW_SIZEOF; ++ ++void ++grub_cpu_relocator_init (void) ++{ ++ grub_relocator_forward_size = RELOCATOR_SIZEOF(forward); ++ grub_relocator_backward_size = RELOCATOR_SIZEOF(backward); ++} ++ ++static void ++write_reg (int regn, grub_uint64_t val, void **target) ++{ ++ grub_uint32_t lu12iw=0x14000000; ++ grub_uint32_t ori=0x03800000; ++ grub_uint32_t lu32id=0x16000000; ++ grub_uint32_t lu52id=0x03000000; ++ ++ *(grub_uint32_t *) *target = (lu12iw | (grub_uint32_t)((val & 0xfffff000)>>12<<5) | (grub_uint32_t)regn);; ++ *target = ((grub_uint32_t *) *target) + 1; ++ *(grub_uint32_t *) *target = (ori | (grub_uint32_t)((val & 0xfff)<<10) | (grub_uint32_t)(regn | regn<<5)); ++ *target = ((grub_uint32_t *) *target) + 1; ++ *(grub_uint32_t *) *target = (lu32id | (grub_uint32_t)((val & 0xfffff00000000)>>32<<5) | (grub_uint32_t)regn);; ++ *target = ((grub_uint32_t *) *target) + 1; ++ *(grub_uint32_t *) *target = (lu52id | (grub_uint32_t)((val & 0xfff0000000000000)>>52<<10) | (grub_uint32_t)(regn | regn<<5));; ++ *target = ((grub_uint32_t *) *target) + 1; ++} ++ ++static void ++write_jump (int regn, void **target) ++{ ++ grub_uint32_t andi=0x4c000000; ++ grub_uint32_t nop=0x03400000; ++ ++ *(grub_uint32_t *) *target = (andi | (grub_uint32_t)(regn<<5)); ++ *target = ((grub_uint32_t *) *target) + 1; ++ *(grub_uint32_t *) *target = nop; ++ *target = ((grub_uint32_t *) *target) + 1; ++} ++ ++void ++grub_cpu_relocator_jumper (void *rels, grub_addr_t addr) ++{ ++ write_reg (1, addr, &rels); ++ write_jump (1, &rels); ++} ++ ++void ++grub_cpu_relocator_backward (void *ptr0, void *src, void *dest, ++ grub_size_t size) ++{ ++ void *ptr = ptr0; ++ write_reg (8, (grub_uint64_t) src, &ptr); ++ write_reg (9, (grub_uint64_t) dest, &ptr); ++ write_reg (10, (grub_uint64_t) size, &ptr); ++ grub_memcpy (ptr, &grub_relocator_backward_start, ++ RELOCATOR_SRC_SIZEOF (backward)); ++} ++ ++void ++grub_cpu_relocator_forward (void *ptr0, void *src, void *dest, ++ grub_size_t size) ++{ ++ void *ptr = ptr0; ++ write_reg (8, (grub_uint64_t) src, &ptr); ++ write_reg (9, (grub_uint64_t) dest, &ptr); ++ write_reg (10, (grub_uint64_t) size, &ptr); ++ grub_memcpy (ptr, &grub_relocator_forward_start, ++ RELOCATOR_SRC_SIZEOF (forward)); ++} ++ ++grub_err_t ++grub_relocator64_boot (struct grub_relocator *rel, ++ struct grub_relocator64_state state) ++{ ++ grub_relocator_chunk_t ch; ++ void *ptr; ++ grub_err_t err; ++ void *relst; ++ grub_size_t relsize; ++ grub_size_t stateset_size = 31 * REGW_SIZEOF + JUMP_SIZEOF; ++ unsigned i; ++ grub_addr_t vtarget; ++ ++ err = grub_relocator_alloc_chunk_align (rel, &ch, 0, ++ (0xffffffff - stateset_size) ++ + 1, stateset_size, ++ grub_relocator_align, ++ GRUB_RELOCATOR_PREFERENCE_NONE, 0); ++ if (err) ++ return err; ++ ++ ptr = get_virtual_current_address (ch); ++ for (i = 1; i < 32; i++) ++ write_reg (i, state.gpr[i], &ptr); ++ write_jump (state.jumpreg, &ptr); ++ ++ vtarget = (grub_addr_t) grub_map_memory (get_physical_target_address (ch), ++ stateset_size); ++ ++ err = grub_relocator_prepare_relocs (rel, vtarget, &relst, &relsize); ++ if (err) ++ return err; ++ ++ grub_arch_sync_caches ((void *) relst, relsize); ++ ++ grub_uint64_t val; ++ __asm__ __volatile__( ++ "li.w %0, 0x4\n\t" ++ "csrxchg $r0, %0, 0x0\n\t" ++ : "=r"(val) ++ : ++ : ++ ); ++ ++ ((void (*) (void)) relst) (); ++ ++ /* Not reached. */ ++ return GRUB_ERR_NONE; ++} +diff --git a/grub-core/lib/loongarch64/relocator_asm.S b/grub-core/lib/loongarch64/relocator_asm.S +new file mode 100644 +index 0000000..cf1724d +--- /dev/null ++++ b/grub-core/lib/loongarch64/relocator_asm.S +@@ -0,0 +1,51 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++ ++ .p2align 4 /* force 16-byte alignment */ ++ ++VARIABLE (grub_relocator_forward_start) ++ ++copycont1: ++ ld.d $r11,$r8,0 ++ st.d $r11,$r9,0 ++ addi.d $r8, $r8, 8 ++ addi.d $r10, $r10, -8 ++ addi.d $r9, $r9, 8 ++ bne $r10, $r0, copycont1 ++ ++VARIABLE (grub_relocator_forward_end) ++ ++VARIABLE (grub_relocator_backward_start) ++ ++ add.d $r9, $r9, $r10 ++ add.d $r8, $r8, $r10 ++ /* Backward movsl is implicitly off-by-one. compensate that. */ ++ addi.d $r9, $r9, -8 ++ addi.d $r8, $r8, -8 ++copycont2: ++ ld.w $r11,$r8,0 ++ st.w $r11,$r9,0 ++ addi.d $r8, $r8, -8 ++ addi.d $r10, $r10, -8 ++ addi.d $r9, $r9, -8 ++ bne $r10, $r0, copycont2 ++ ++VARIABLE (grub_relocator_backward_end) ++ +diff --git a/grub-core/lib/loongarch64/setjmp.S b/grub-core/lib/loongarch64/setjmp.S +new file mode 100644 +index 0000000..47db814 +--- /dev/null ++++ b/grub-core/lib/loongarch64/setjmp.S +@@ -0,0 +1,74 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2003,2007,2009 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++ ++ .file "setjmp.S" ++ ++GRUB_MOD_LICENSE "GPLv3+" ++ ++ .text ++ ++/* ++ * int grub_setjmp (grub_jmp_buf env) ++ */ ++FUNCTION(grub_setjmp) ++ GRUB_ASM_REG_S $s0, $a0,0 ++ GRUB_ASM_REG_S $s1, $a0,8 ++ GRUB_ASM_REG_S $s2, $a0,16 ++ GRUB_ASM_REG_S $s3, $a0,24 ++ GRUB_ASM_REG_S $s4, $a0,32 ++ GRUB_ASM_REG_S $s5, $a0,40 ++ GRUB_ASM_REG_S $s6, $a0,48 ++ GRUB_ASM_REG_S $s7, $a0,56 ++ GRUB_ASM_REG_S $s8, $a0,64 ++ GRUB_ASM_REG_S $fp, $a0,72 ++ GRUB_ASM_REG_S $sp, $a0,80 ++ GRUB_ASM_REG_S $ra, $a0,88 ++ move $v0, $zero ++ move $v1, $zero ++ jr $ra ++ nop ++/* ++ * int grub_longjmp (grub_jmp_buf env, int val) ++ */ ++FUNCTION(grub_longjmp) ++ GRUB_ASM_REG_L $s0, $a0,0 ++ GRUB_ASM_REG_L $s1, $a0,8 ++ GRUB_ASM_REG_L $s2, $a0,16 ++ GRUB_ASM_REG_L $s3, $a0,24 ++ GRUB_ASM_REG_L $s4, $a0,32 ++ GRUB_ASM_REG_L $s5, $a0,40 ++ GRUB_ASM_REG_L $s6, $a0,48 ++ GRUB_ASM_REG_L $s7, $a0,56 ++ GRUB_ASM_REG_L $s8, $a0,64 ++ GRUB_ASM_REG_L $fp, $a0,72 ++ GRUB_ASM_REG_L $sp, $a0,80 ++ GRUB_ASM_REG_L $ra, $a0,88 ++ addi.w $v0, $zero, 1 ++ /* ++ * replace: movn $v0, $a1, $a1 ++ */ ++ bnez $a1, .ZW0 ++ addi.d $v0, $a1, 0 ++.ZW0: ++ addi.d $v1,$zero,0 ++ jr $ra ++ nop +diff --git a/grub-core/lib/loongson/reboot.c b/grub-core/lib/loongson/reboot.c +new file mode 100644 +index 0000000..107787a +--- /dev/null ++++ b/grub-core/lib/loongson/reboot.c +@@ -0,0 +1,33 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2011 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++void ++grub_la_reboot (void) ++{ ++ grub_machine_fini (GRUB_LOADER_FLAG_NORETURN); ++ efi_call_4 (grub_efi_system_table->runtime_services->reset_system, ++ GRUB_EFI_RESET_COLD, GRUB_EFI_SUCCESS, 0, NULL); ++ for (;;) ; ++} +diff --git a/grub-core/lib/setjmp.S b/grub-core/lib/setjmp.S +index f6e4905..023dc90 100644 +--- a/grub-core/lib/setjmp.S ++++ b/grub-core/lib/setjmp.S +@@ -15,6 +15,8 @@ + #include "./arm/setjmp.S" + #elif defined(__aarch64__) + #include "./arm64/setjmp.S" ++#elif defined(__loongarch64) ++#include "./loongarch64/setjmp.S" + #else + #error "Unknown target cpu type" + #endif +diff --git a/grub-core/loader/efi/chainloader.c b/grub-core/loader/efi/chainloader.c +index 29663f7..c0ca17d 100644 +--- a/grub-core/loader/efi/chainloader.c ++++ b/grub-core/loader/efi/chainloader.c +@@ -332,6 +332,8 @@ static const grub_uint16_t machine_type __attribute__((__unused__)) = + GRUB_PE32_MACHINE_I386; + #elif defined(__ia64__) + GRUB_PE32_MACHINE_IA64; ++#elif defined(__loongarch64) ++ GRUB_PE32_MACHINE_LOONGARCH64; + #else + #error this architecture is not supported by grub2 + #endif +diff --git a/grub-core/loader/loongarch64/linux.c b/grub-core/loader/loongarch64/linux.c +new file mode 100644 +index 0000000..c769bb2 +--- /dev/null ++++ b/grub-core/loader/loongarch64/linux.c +@@ -0,0 +1,580 @@ ++/* linux.c - boot Linux */ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2003,2004,2005,2007,2009,2010,2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++GRUB_MOD_LICENSE ("GPLv3+"); ++ ++#pragma GCC diagnostic ignored "-Wcast-align" ++ ++typedef unsigned long size_t; ++ ++static grub_dl_t my_mod; ++ ++static int loaded; ++ ++static grub_uint32_t tmp_index = 0; ++static grub_size_t linux_size; ++ ++static struct grub_relocator *relocator; ++static grub_addr_t target_addr, entry_addr; ++static int linux_argc; ++static grub_uint8_t *linux_args_addr; ++static grub_off_t rd_addr_arg_off, rd_size_arg_off; ++static grub_off_t initrd_addr_arg_off; ++static int initrd_loaded = 0; ++ ++ ++static grub_uint32_t j = 0; ++static grub_uint32_t t = 0; ++grub_uint64_t tempMemsize = 0; ++grub_uint32_t free_index = 0; ++grub_uint32_t reserve_index = 0; ++grub_uint32_t acpi_table_index = 0; ++grub_uint32_t acpi_nvs_index = 0; ++ ++static inline grub_size_t ++page_align (grub_size_t size) ++{ ++ return (size + (1 << 12) - 1) & (~((1 << 12) - 1)); ++} ++ ++/* Find the optimal number of pages for the memory map. Is it better to ++ move this code to efi/mm.c? */ ++static grub_efi_uintn_t ++find_mmap_size (void) ++{ ++ static grub_efi_uintn_t mmap_size = 0; ++ ++ if (mmap_size != 0) ++ return mmap_size; ++ ++ mmap_size = (1 << 12); ++ while (1) ++ { ++ int ret; ++ grub_efi_memory_descriptor_t *mmap; ++ grub_efi_uintn_t desc_size; ++ ++ mmap = grub_malloc (mmap_size); ++ if (! mmap) ++ return 0; ++ ++ ret = grub_efi_get_memory_map (&mmap_size, mmap, 0, &desc_size, 0); ++ grub_free (mmap); ++ ++ if (ret < 0) ++ { ++ grub_error (GRUB_ERR_IO, "cannot get memory map"); ++ return 0; ++ } ++ else if (ret > 0) ++ break; ++ ++ mmap_size += (1 << 12); ++ } ++ ++ ++ /* Increase the size a bit for safety, because GRUB allocates more on ++ later, and EFI itself may allocate more. */ ++ mmap_size += (1 << 12); ++ ++ return page_align (mmap_size); ++} ++ ++static grub_err_t ++grub_linux_boot (void) ++{ ++ struct grub_relocator64_state state; ++ grub_int8_t checksum = 0; ++ grub_efi_memory_descriptor_t * lsdesc = NULL; ++ ++ grub_memset (&state, 0, sizeof (state)); ++ ++ /* Boot the kernel. */ ++ state.gpr[1] = entry_addr; ++ grub_dprintf("loongson", "entry_addr is %p\n", state.gpr[1]); ++ state.gpr[4] = linux_argc; ++ grub_dprintf("loongson", "linux_argc is %d\n", state.gpr[4]); ++ state.gpr[5] = (grub_addr_t) linux_args_addr; ++ grub_dprintf("loongson", "args_addr is %p\n", state.gpr[5]); ++ ++ if(grub_efi_is_loongson ()) ++ { ++ grub_efi_uintn_t mmap_size; ++ grub_efi_uintn_t desc_size; ++ grub_efi_memory_descriptor_t *mmap_buf; ++ grub_err_t err; ++ struct bootparamsinterface * boot_params; ++ void * tmp_boot_params = NULL; ++ grub_efi_uint8_t new_interface_flag = 0; ++ mem_map * new_interface_mem = NULL; ++ char *p = NULL; ++ ++ struct memmap reserve_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ struct memmap free_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ struct memmap acpi_table_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ struct memmap acpi_nvs_mem[GRUB_EFI_LOONGSON_MMAP_MAX]; ++ ++ grub_memset(reserve_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ grub_memset(free_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ grub_memset(acpi_table_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ grub_memset(acpi_nvs_mem, 0, sizeof(struct memmap) * GRUB_EFI_LOONGSON_MMAP_MAX); ++ ++ tmp_boot_params = grub_efi_loongson_get_boot_params(); ++ if(tmp_boot_params == NULL) ++ { ++ grub_printf("not find param\n"); ++ return -1; ++ } ++ ++ boot_params = (struct bootparamsinterface *)tmp_boot_params; ++ p = (char *)&(boot_params->signature); ++ if(grub_strncmp(p, "BPI", 3) == 0) ++ { ++ /* Check extlist headers */ ++ ext_list * listpointer = NULL; ++ listpointer = boot_params->extlist; ++ for( ;listpointer != NULL; listpointer = listpointer->next) ++ { ++ char *pl= (char *)&(listpointer->signature); ++ if(grub_strncmp(pl, "MEM", 3) == 0) ++ { ++ new_interface_mem = (mem_map *)listpointer; ++ } ++ } ++ ++ new_interface_flag = 1; ++ grub_dprintf("loongson", "get new parameter interface\n"); ++ }else{ ++ new_interface_flag = 0; ++ grub_dprintf("loongson", "get old parameter interface\n"); ++ } ++ state.gpr[6] = (grub_uint64_t)tmp_boot_params; ++ grub_dprintf("loongson", "boot_params is %p\n", state.gpr[6]); ++ ++ mmap_size = find_mmap_size (); ++ if (! mmap_size) ++ return grub_errno; ++ mmap_buf = grub_efi_allocate_any_pages (page_align (mmap_size) >> 12); ++ if (! mmap_buf) ++ return grub_error (GRUB_ERR_IO, "cannot allocate memory map"); ++ err = grub_efi_finish_boot_services (&mmap_size, mmap_buf, NULL, ++ &desc_size, NULL); ++ if (err) ++ return err; ++ ++ if(new_interface_flag) ++ { ++ if (!mmap_buf || !mmap_size || !desc_size) ++ return -1; ++ tmp_index = new_interface_mem -> mapcount; ++ ++ /* ++ According to UEFI SPEC,mmap_buf is the accurate Memory Map array \ ++ now we can fill platform specific memory structure. ++ */ ++ for(lsdesc = mmap_buf; lsdesc < (grub_efi_memory_descriptor_t *)((char *)mmap_buf + mmap_size); ++ lsdesc = (grub_efi_memory_descriptor_t *)((char *)lsdesc + desc_size)) ++ { ++ /* Recovery */ ++ if((lsdesc->type != GRUB_EFI_ACPI_RECLAIM_MEMORY) && \ ++ (lsdesc->type != GRUB_EFI_ACPI_MEMORY_NVS) && \ ++ (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_DATA) && \ ++ (lsdesc->type != GRUB_EFI_RUNTIME_SERVICES_CODE) && \ ++ (lsdesc->type != GRUB_EFI_RESERVED_MEMORY_TYPE) && \ ++ (lsdesc->type != GRUB_EFI_PAL_CODE)) ++ { ++ free_mem[free_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM; ++ free_mem[free_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ free_mem[free_index].memsize = lsdesc->num_pages * 4096; ++ free_index++; ++ ++ /*ACPI*/ ++ }else if((lsdesc->type == GRUB_EFI_ACPI_RECLAIM_MEMORY)){ ++ acpi_table_mem[acpi_table_index].memtype = GRUB_EFI_LOONGSON_ACPI_TABLE; ++ acpi_table_mem[acpi_table_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ acpi_table_mem[acpi_table_index].memsize = lsdesc->num_pages * 4096; ++ acpi_table_index++; ++ }else if((lsdesc->type == GRUB_EFI_ACPI_MEMORY_NVS)){ ++ acpi_nvs_mem[acpi_nvs_index].memtype = GRUB_EFI_LOONGSON_ACPI_NVS; ++ acpi_nvs_mem[acpi_nvs_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ acpi_nvs_mem[acpi_nvs_index].memsize = lsdesc->num_pages * 4096; ++ acpi_nvs_index++; ++ ++ /* Reserve */ ++ }else{ ++ reserve_mem[reserve_index].memtype = GRUB_EFI_LOONGSON_MEMORY_RESERVED; ++ reserve_mem[reserve_index].memstart = (lsdesc->physical_start) & 0xffffffffffff; ++ reserve_mem[reserve_index].memsize = lsdesc->num_pages * 4096; ++ reserve_index++; ++ } ++ } ++ ++ /* Recovery sort */ ++ for(j = 0; j < free_index;) ++ { ++ tempMemsize = free_mem[j].memsize; ++ for(t = j + 1; t < free_index; t++) ++ { ++ if((free_mem[j].memstart + tempMemsize == free_mem[t].memstart) && (free_mem[j].memtype == free_mem[t].memtype)) ++ { ++ tempMemsize += free_mem[t].memsize; ++ }else{ ++ break; ++ } ++ } ++ ++ new_interface_mem->map[tmp_index].memtype = GRUB_EFI_LOONGSON_SYSTEM_RAM; ++ new_interface_mem->map[tmp_index].memstart = free_mem[j].memstart; ++ new_interface_mem->map[tmp_index].memsize = tempMemsize; ++ grub_dprintf("loongson", "map[%d]:type %x, start 0x%llx, end 0x%llx\n", ++ tmp_index, ++ new_interface_mem->map[tmp_index].memtype, ++ new_interface_mem->map[tmp_index].memstart, ++ new_interface_mem->map[tmp_index].memstart+ new_interface_mem->map[tmp_index].memsize ++ ); ++ j = t; ++ tmp_index++; ++ } ++ /*ACPI Sort*/ ++ tmp_index = grub_efi_loongson_memmap_sort(acpi_table_mem, acpi_table_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_TABLE); ++ tmp_index = grub_efi_loongson_memmap_sort(acpi_nvs_mem, acpi_nvs_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_ACPI_NVS); ++ /*Reserve Sort*/ ++ grub_uint64_t loongarch_addr; ++ asm volatile ("csrrd %0, 0x181" : "=r" (loongarch_addr)); ++ if((loongarch_addr & 0xff00000000000000) == 0x9000000000000000){ ++ tmp_index = grub_efi_loongson_memmap_sort(reserve_mem, reserve_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED); ++ }else{ ++ tmp_index = grub_efi_loongson_memmap_sort(reserve_mem, reserve_index, new_interface_mem, tmp_index, GRUB_EFI_LOONGSON_MEMORY_RESERVED + 1); ++ } ++ ++ new_interface_mem->mapcount = tmp_index; ++ new_interface_mem->header.checksum = 0; ++ ++ checksum = grub_efi_loongson_grub_calculatechecksum8(new_interface_mem, new_interface_mem->header.length); ++ new_interface_mem->header.checksum = checksum; ++ } ++ } ++ ++ state.jumpreg = 1; ++ grub_relocator64_boot (relocator, state); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_linux_unload (void) ++{ ++ grub_relocator_unload (relocator); ++ grub_dl_unref (my_mod); ++ ++ loaded = 0; ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_linux_load32 (grub_elf_t elf, const char *filename) ++{ ++ Elf32_Addr base; ++ grub_err_t err; ++ grub_uint8_t *playground; ++ ++ /* Linux's entry point incorrectly contains a virtual address. */ ++ entry_addr = elf->ehdr.ehdr32.e_entry; ++ ++ linux_size = grub_elf32_size (elf, &base, 0); ++ if (linux_size == 0) ++ return grub_errno; ++ target_addr = base; ++ linux_size = ALIGN_UP (base + linux_size - base, 8); ++ ++ relocator = grub_relocator_new (); ++ if (!relocator) ++ return grub_errno; ++ ++ { ++ grub_relocator_chunk_t ch; ++ err = grub_relocator_alloc_chunk_addr (relocator, &ch, ++ grub_vtop ((void *) target_addr), ++ linux_size); ++ if (err) ++ return err; ++ playground = get_virtual_current_address (ch); ++ } ++ ++ /* Now load the segments into the area we claimed. */ ++ return grub_elf32_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0); ++} ++ ++static grub_err_t ++grub_linux_load64 (grub_elf_t elf, const char *filename) ++{ ++ Elf64_Addr base; ++ grub_err_t err; ++ grub_uint8_t *playground; ++ ++ /* Linux's entry point incorrectly contains a virtual address. */ ++ entry_addr = elf->ehdr.ehdr64.e_entry; ++ grub_dprintf("loongson", "entry address = %p\n", entry_addr); ++ ++ linux_size = grub_elf64_size (elf, &base, 0); ++ grub_dprintf("loongson", "base = %p\n", base); ++ ++ if (linux_size == 0) ++ return grub_errno; ++ target_addr = base; ++ linux_size = ALIGN_UP (base + linux_size - base, 8); ++ ++ relocator = grub_relocator_new (); ++ // linux_size=0x322fa80; ++ if (!relocator) ++ return grub_errno; ++ ++ { ++ grub_relocator_chunk_t ch; ++ err = grub_relocator_alloc_chunk_addr (relocator, &ch, ++ grub_vtop ((void *) target_addr), ++ linux_size); ++ if (err) ++ return err; ++ playground = get_virtual_current_address (ch); ++ } ++ ++ /* Now load the segments into the area we claimed. */ ++ return grub_elf64_load (elf, filename, playground - base, GRUB_ELF_LOAD_FLAGS_NONE, 0, 0); ++} ++ ++static grub_err_t ++grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ grub_elf_t elf = 0; ++ int size; ++ int i; ++ grub_uint64_t *linux_argv; ++ char *linux_args; ++ grub_err_t err; ++ ++ if (argc == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ ++ elf = grub_elf_open (argv[0],GRUB_FILE_TYPE_LINUX_KERNEL); ++ if (! elf) ++ return grub_errno; ++ ++ if (elf->ehdr.ehdr32.e_type != ET_EXEC) ++ { ++ grub_elf_close (elf); ++ return grub_error (GRUB_ERR_UNKNOWN_OS, ++ N_("this ELF file is not of the right type")); ++ } ++ ++ /* Release the previously used memory. */ ++ grub_loader_unset (); ++ loaded = 0; ++ ++ /* For arguments. */ ++ linux_argc = argc; ++ /* Main arguments. */ ++ size = (linux_argc) * sizeof (grub_uint64_t); ++ /* Initrd address and size. */ ++ size += 3 * sizeof (grub_uint64_t); ++ /* NULL terminator. */ ++ size += sizeof (grub_uint64_t); ++ /* First argument is always "a0". */ ++ size += ALIGN_UP (sizeof ("a0"), 4); ++ /* Normal arguments. */ ++ for (i = 1; i < argc; i++) ++ size += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); ++ ++ /* rd arguments. */ ++ size += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); ++ size += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); ++ size += ALIGN_UP (sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), 4); ++ ++ size = ALIGN_UP (size, 8); ++ ++ if (grub_elf_is_elf32 (elf)) ++ err = grub_linux_load32 (elf, argv[0]); ++ else ++ if (grub_elf_is_elf64 (elf)) ++ err = grub_linux_load64 (elf, argv[0]); ++ else ++ err = grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-dependent ELF magic")); ++ ++ grub_elf_close (elf); ++ ++ if (err) ++ return err; ++ ++ { ++ grub_relocator_chunk_t ch; ++ err = grub_relocator_alloc_chunk_align (relocator, &ch, ++ 0, (0xffffffff - size) + 1, ++ size, 8, ++ GRUB_RELOCATOR_PREFERENCE_HIGH, 0); ++ if (err) ++ return err; ++ linux_args_addr = get_virtual_current_address (ch); ++ } ++ ++ linux_argv = (grub_uint64_t *) linux_args_addr; ++ linux_args = (char *) (linux_argv + (linux_argc + 1 + 3)); ++ ++ grub_memcpy (linux_args, "a0", sizeof ("a0")); ++ *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; ++ linux_argv++; ++ linux_args += ALIGN_UP (sizeof ("a0"), 4); ++ ++ for (i = 1; i < argc; i++) ++ { ++ grub_memcpy (linux_args, argv[i], grub_strlen (argv[i]) + 1); ++ *linux_argv = (grub_uint64_t) (grub_addr_t) linux_args; ++ linux_argv++; ++ linux_args += ALIGN_UP (grub_strlen (argv[i]) + 1, 4); ++ } ++ ++ /* Reserve space for rd arguments. */ ++ rd_addr_arg_off = (grub_uint8_t *) linux_args - linux_args_addr; ++ linux_args += ALIGN_UP (sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), 4); ++ *linux_argv = 0; ++ linux_argv++; ++ ++ rd_size_arg_off = (grub_uint8_t *) linux_args - linux_args_addr; ++ linux_args += ALIGN_UP (sizeof ("rd_size=0xXXXXXXXXXXXXXXXX"), 4); ++ *linux_argv = 0; ++ linux_argv++; ++ ++ /* Reserve space for initrd arguments. */ ++ initrd_addr_arg_off = (grub_uint8_t *) linux_args - linux_args_addr; ++ linux_args += ALIGN_UP (sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), 4); ++ *linux_argv = 0; ++ linux_argv++; ++ ++ *linux_argv = 0; ++ ++ grub_loader_set (grub_linux_boot, grub_linux_unload, 0); ++ initrd_loaded = 0; ++ loaded = 1; ++ grub_dl_ref (my_mod); ++ ++ return GRUB_ERR_NONE; ++} ++ ++static grub_err_t ++grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), ++ int argc, char *argv[]) ++{ ++ grub_size_t size = 0; ++ void *initrd_dest; ++ grub_err_t err; ++ struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 }; ++ ++ if (argc == 0) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); ++ ++ if (!loaded) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first")); ++ ++ if (initrd_loaded) ++ return grub_error (GRUB_ERR_BAD_ARGUMENT, "only one initrd command can be issued."); ++ ++ if (grub_initrd_init (argc, argv, &initrd_ctx)) ++ goto fail; ++ ++ size = grub_get_initrd_size (&initrd_ctx); ++ ++ { ++ grub_relocator_chunk_t ch; ++ err = grub_relocator_alloc_chunk_align (relocator, &ch, ++ 0, (0xffffffff - size) + 1, ++ size, 0x10000, ++ GRUB_RELOCATOR_PREFERENCE_HIGH, 0); ++ ++ if (err) ++ goto fail; ++ initrd_dest = get_virtual_current_address (ch); ++ } ++ ++ if (grub_initrd_load (&initrd_ctx, argv, initrd_dest)) ++ goto fail; ++ ++ grub_snprintf ((char *) linux_args_addr + rd_addr_arg_off, ++ sizeof ("rd_start=0xXXXXXXXXXXXXXXXX"), "rd_start=0x%lx", ++ (grub_uint64_t) initrd_dest); ++ ((grub_uint64_t *) linux_args_addr)[linux_argc] ++ = (grub_uint64_t) ((grub_addr_t) linux_args_addr + rd_addr_arg_off); ++ linux_argc++; ++ ++ grub_snprintf ((char *) linux_args_addr + rd_size_arg_off, ++ sizeof ("rd_size=0xXXXXXXXXXXXXXXXXX"), "rd_size=0x%lx", ++ (grub_uint64_t) size); ++ ((grub_uint64_t *) linux_args_addr)[linux_argc] ++ = (grub_uint64_t) ((grub_addr_t) linux_args_addr + rd_size_arg_off); ++ linux_argc++; ++ ++ ++ grub_snprintf ((char *) linux_args_addr + initrd_addr_arg_off, ++ sizeof ("initrd=0xXXXXXXXXXXXXXXXX,0xXXXXXXXXXXXXXXXX"), "initrd=0x%lx,0x%lx", ++ ((grub_uint64_t) initrd_dest & 0xffffffff), (grub_uint64_t) size); ++ ((grub_uint64_t *) linux_args_addr)[linux_argc] ++ = (grub_uint64_t) ((grub_addr_t) linux_args_addr + initrd_addr_arg_off); ++ linux_argc++; ++ ++ initrd_loaded = 1; ++ ++ fail: ++ grub_initrd_close (&initrd_ctx); ++ ++ return grub_errno; ++} ++ ++static grub_command_t cmd_linux, cmd_initrd; ++ ++GRUB_MOD_INIT(linux) ++{ ++ cmd_linux = grub_register_command ("linux", grub_cmd_linux, ++ 0, N_("Load Linux.")); ++ cmd_initrd = grub_register_command ("initrd", grub_cmd_initrd, ++ 0, N_("Load initrd.")); ++ my_mod = mod; ++} ++ ++GRUB_MOD_FINI(linux) ++{ ++ grub_unregister_command (cmd_linux); ++ grub_unregister_command (cmd_initrd); ++} +diff --git a/include/grub/dl.h b/include/grub/dl.h +index 6a3e251..c1b6dd9 100644 +--- a/include/grub/dl.h ++++ b/include/grub/dl.h +@@ -314,7 +314,7 @@ grub_arch_dl_get_tramp_got_size (const void *ehdr, grub_size_t *tramp, + #define GRUB_ARCH_DL_GOT_ALIGN 4 + #endif + +-#if defined (__aarch64__) || defined (__sparc__) ++#if defined (__aarch64__) || defined (__sparc__) || defined (__loongarch64) + #define GRUB_ARCH_DL_TRAMP_ALIGN 8 + #define GRUB_ARCH_DL_GOT_ALIGN 8 + #endif +diff --git a/include/grub/efi/api.h b/include/grub/efi/api.h +index 37e7b16..049326c 100644 +--- a/include/grub/efi/api.h ++++ b/include/grub/efi/api.h +@@ -2087,7 +2087,8 @@ struct grub_efi_rng_protocol + typedef struct grub_efi_rng_protocol grub_efi_rng_protocol_t; + + #if (GRUB_TARGET_SIZEOF_VOID_P == 4) || defined (__ia64__) \ +- || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) ++ || defined (__aarch64__) || defined (__MINGW64__) || defined (__CYGWIN__) \ ++ || defined (__loongarch64) + + #define efi_call_0(func) func() + #define efi_call_1(func, a) func(a) +diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h +index c03cc59..be88c54 100644 +--- a/include/grub/efi/pe32.h ++++ b/include/grub/efi/pe32.h +@@ -66,6 +66,7 @@ struct grub_pe32_coff_header + }; + + #define GRUB_PE32_MACHINE_I386 0x14c ++#define GRUB_PE32_MACHINE_LOONGARCH64 0x6264 + #define GRUB_PE32_MACHINE_IA64 0x200 + #define GRUB_PE32_MACHINE_X86_64 0x8664 + #define GRUB_PE32_MACHINE_ARMTHUMB_MIXED 0x01c2 +@@ -329,6 +330,7 @@ struct grub_pe32_fixup_block + #define GRUB_PE32_REL_BASED_IA64_IMM64 9 + #define GRUB_PE32_REL_BASED_DIR64 10 + #define GRUB_PE32_REL_BASED_HIGH3ADJ 11 ++#define GRUB_PE32_REL_BASED_LOONGARCH64 8 + + struct grub_pe32_symbol + { +diff --git a/include/grub/elf.h b/include/grub/elf.h +index c8492f9..2c0b163 100644 +--- a/include/grub/elf.h ++++ b/include/grub/elf.h +@@ -247,6 +247,7 @@ typedef struct + #define EM_XTENSA 94 /* Tensilica Xtensa Architecture */ + #define EM_NUM 95 + #define EM_AARCH64 183 /* ARM 64-bit architecture */ ++#define EM_LOONGARCH64 258 /* LoongArch64 architecture */ + + /* If it is necessary to assign new unofficial EM_* values, please + pick large random numbers (0x8523, 0xa7f2, etc.) to minimize the +@@ -1448,6 +1449,60 @@ typedef struct + #define OHWA0_R4KEOP_CHECKED 0x00000001 + #define OHWA1_R4KEOP_CLEAN 0x00000002 + ++/* LOONGARCH64 relocs. */ ++#define R_LARCH_NONE 0 ++#define R_LARCH_32 1 ++#define R_LARCH_64 2 ++#define R_LARCH_RELATIVE 3 ++#define R_LARCH_COPY 4 ++#define R_LARCH_JUMP_SLOT 5 ++#define R_LARCH_TLS_DTPMOD32 6 ++#define R_LARCH_TLS_DTPMOD64 7 ++#define R_LARCH_TLS_DTPREL32 8 ++#define R_LARCH_TLS_DTPREL64 9 ++#define R_LARCH_TLS_TPREL32 10 ++#define R_LARCH_TLS_TPREL64 11 ++#define R_LARCH_IRELATIVE 12 ++#define R_LARCH_MARK_LA 20 ++#define R_LARCH_MARK_PCREL 21 ++#define R_LARCH_SOP_PUSH_PCREL 22 ++#define R_LARCH_SOP_PUSH_ABSOLUTE 23 ++#define R_LARCH_SOP_PUSH_DUP 24 ++#define R_LARCH_SOP_PUSH_GPREL 25 ++#define R_LARCH_SOP_PUSH_TLS_TPREL 26 ++#define R_LARCH_SOP_PUSH_TLS_GOT 27 ++#define R_LARCH_SOP_PUSH_TLS_GD 28 ++#define R_LARCH_SOP_PUSH_PLT_PCREL 29 ++#define R_LARCH_SOP_ASSERT 30 ++#define R_LARCH_SOP_NOT 31 ++#define R_LARCH_SOP_SUB 32 ++#define R_LARCH_SOP_SL 33 ++#define R_LARCH_SOP_SR 34 ++#define R_LARCH_SOP_ADD 35 ++#define R_LARCH_SOP_AND 36 ++#define R_LARCH_SOP_IF_ELSE 37 ++#define R_LARCH_SOP_POP_32_S_10_5 38 ++#define R_LARCH_SOP_POP_32_U_10_12 39 ++#define R_LARCH_SOP_POP_32_S_10_12 40 ++#define R_LARCH_SOP_POP_32_S_10_16 41 ++#define R_LARCH_SOP_POP_32_S_10_16_S2 42 ++#define R_LARCH_SOP_POP_32_S_5_20 43 ++#define R_LARCH_SOP_POP_32_S_0_5_10_16_S2 44 ++#define R_LARCH_SOP_POP_32_S_0_10_10_16_S2 45 ++#define R_LARCH_SOP_POP_32_U 46 ++#define R_LARCH_ADD8 47 ++#define R_LARCH_ADD16 48 ++#define R_LARCH_ADD24 49 ++#define R_LARCH_ADD32 50 ++#define R_LARCH_ADD64 51 ++#define R_LARCH_SUB8 52 ++#define R_LARCH_SUB16 53 ++#define R_LARCH_SUB24 54 ++#define R_LARCH_SUB32 55 ++#define R_LARCH_SUB64 56 ++#define R_LARCH_GNU_VTINHERIT 57 ++#define R_LARCH_GNU_VTENTRY 58 ++ + /* MIPS relocs. */ + + #define R_MIPS_NONE 0 /* No reloc */ +diff --git a/include/grub/loongarch64/asm.h b/include/grub/loongarch64/asm.h +new file mode 100644 +index 0000000..c3e77e9 +--- /dev/null ++++ b/include/grub/loongarch64/asm.h +@@ -0,0 +1,10 @@ ++#ifndef GRUB_LOONGARCH64_ASM_HEADER ++#define GRUB_LOONGARCH64_ASM_HEADER 1 ++ ++#define GRUB_ASM_T4 $a4 ++#define GRUB_ASM_T5 $a5 ++#define GRUB_ASM_SZREG 8 ++#define GRUB_ASM_REG_S st.d ++#define GRUB_ASM_REG_L ld.d ++ ++#endif +diff --git a/include/grub/loongarch64/efi/boot.h b/include/grub/loongarch64/efi/boot.h +new file mode 100644 +index 0000000..e69de29 +diff --git a/include/grub/loongarch64/efi/loader.h b/include/grub/loongarch64/efi/loader.h +new file mode 100644 +index 0000000..71a0159 +--- /dev/null ++++ b/include/grub/loongarch64/efi/loader.h +@@ -0,0 +1,25 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2003,2004,2006,2007,2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_LOADER_MACHINE_HEADER ++#define GRUB_LOADER_MACHINE_HEADER 1 ++ ++#include ++#include ++ ++#endif /* ! GRUB_LOADER_MACHINE_HEADER */ +diff --git a/include/grub/loongarch64/efi/loongson.h b/include/grub/loongarch64/efi/loongson.h +new file mode 100644 +index 0000000..fa32ef5 +--- /dev/null ++++ b/include/grub/loongarch64/efi/loongson.h +@@ -0,0 +1,290 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_EFI_LOONGSON_HEADER ++#define GRUB_EFI_LOONGSON_HEADER 1 ++ ++#include ++ ++#include ++ ++#define GRUB_EFI_LOONGSON_SMBIOS_TABLE_GUID \ ++ { 0x4660f721, 0x2ec5, 0x416a, \ ++ { 0x89, 0x9a, 0x43, 0x18, 0x02, 0x50, 0xa0, 0xc9 } \ ++ } ++ ++#define GRUB_EFI_LOONGSON_MMAP_MAX 128 ++typedef enum ++ { ++ GRUB_EFI_LOONGSON_SYSTEM_RAM = 1, ++ GRUB_EFI_LOONGSON_MEMORY_RESERVED, ++ GRUB_EFI_LOONGSON_ACPI_TABLE, ++ GRUB_EFI_LOONGSON_ACPI_NVS, ++ GRUB_EFI_LOONGSON_MAX_MEMORY_TYPE ++ } ++grub_efi_loongson_memory_type; ++ ++typedef struct ++{ ++ grub_uint16_t vers; /* version */ ++ grub_uint32_t nr_map; /* number of memory_maps */ ++ grub_uint32_t mem_freq; /* memory frequence */ ++ struct mem_map { ++ grub_uint32_t node_id; /* node_id which memory attached to */ ++ grub_uint32_t mem_type; /* system memory, pci memory, pci io, etc. */ ++ grub_uint64_t mem_start; /* memory map start address */ ++ grub_uint32_t mem_size; /* each memory_map size, not the total size */ ++ } map[GRUB_EFI_LOONGSON_MMAP_MAX]; ++} GRUB_PACKED ++grub_efi_loongson_memory_map; ++ ++/* ++ * Capability and feature descriptor structure for LOONGARCH CPU ++ */ ++typedef struct ++{ ++ grub_uint16_t vers; /* version */ ++ grub_uint32_t processor_id; /* PRID, e.g. 6305, 6306 */ ++ grub_uint32_t cputype; /* Loongson_3A/3B, etc. */ ++ grub_uint32_t total_node; /* num of total numa nodes */ ++ grub_uint16_t cpu_startup_core_id; /* Boot core id */ ++ grub_uint16_t reserved_cores_mask; ++ grub_uint32_t cpu_clock_freq; /* cpu_clock */ ++ grub_uint32_t nr_cpus; ++} GRUB_PACKED ++grub_efi_loongson_cpu_info; ++ ++#define GRUB_EFI_LOONGSON_MAX_UARTS 64 ++ ++typedef struct ++{ ++ grub_uint32_t iotype; /* see include/linux/serial_core.h */ ++ grub_uint32_t uartclk; ++ grub_uint32_t int_offset; ++ grub_uint64_t uart_base; ++} GRUB_PACKED ++grub_efi_loongson_uart_device; ++ ++#define GRUB_EFI_LOONGSON_MAX_SENSORS 64 ++ ++typedef struct ++{ ++ char name[32]; /* a formal name */ ++ char label[64]; /* a flexible description */ ++ grub_uint32_t type; /* SENSOR_* */ ++ grub_uint32_t id; /* instance id of a sensor-class */ ++ grub_uint32_t fan_policy; ++ grub_uint32_t fan_percent; /* only for constant speed policy */ ++ grub_uint64_t base_addr; /* base address of device registers */ ++} GRUB_PACKED ++grub_efi_loongson_sensor_device; ++ ++typedef struct ++{ ++ grub_uint16_t vers; /* version */ ++ grub_uint32_t ccnuma_smp; /* 0: no numa; 1: has numa */ ++ grub_uint32_t sing_double_channel; /* 1:single; 2:double */ ++ grub_uint32_t nr_uarts; ++ grub_efi_loongson_uart_device uarts[GRUB_EFI_LOONGSON_MAX_UARTS]; ++ grub_uint32_t nr_sensors; ++ grub_efi_loongson_sensor_device sensors[GRUB_EFI_LOONGSON_MAX_SENSORS]; ++ char has_ec; ++ char ec_name[32]; ++ grub_uint64_t ec_base_addr; ++ char has_tcm; ++ char tcm_name[32]; ++ grub_uint64_t tcm_base_addr; ++ grub_uint64_t workarounds; /* see workarounds.h */ ++} GRUB_PACKED ++grub_efi_loongson_system_info; ++ ++typedef struct ++{ ++ grub_uint16_t vers; ++ grub_uint16_t size; ++ grub_uint16_t rtr_bus; ++ grub_uint16_t rtr_devfn; ++ grub_uint32_t vendor; ++ grub_uint32_t device; ++ grub_uint32_t PIC_type; /* conform use HT or PCI to route to CPU-PIC */ ++ grub_uint64_t ht_int_bit; /* 3A: 1<<24; 3B: 1<<16 */ ++ grub_uint64_t ht_enable; /* irqs used in this PIC */ ++ grub_uint32_t node_id; /* node id: 0x0-0; 0x1-1; 0x10-2; 0x11-3 */ ++ grub_uint64_t pci_mem_start_addr; ++ grub_uint64_t pci_mem_end_addr; ++ grub_uint64_t pci_io_start_addr; ++ grub_uint64_t pci_io_end_addr; ++ grub_uint64_t pci_config_addr; ++ grub_uint32_t dma_mask_bits; ++} GRUB_PACKED ++grub_efi_loongson_irq_src_routing_table; ++ ++typedef struct ++{ ++ grub_uint16_t vers; /* version */ ++ grub_uint16_t size; ++ grub_uint8_t flag; ++ char description[64]; ++} GRUB_PACKED ++grub_efi_loongson_interface_info; ++ ++#define GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER 128 ++ ++typedef struct ++{ ++ grub_uint64_t start; /* resource start address */ ++ grub_uint64_t end; /* resource end address */ ++ char name[64]; ++ grub_uint32_t flags; ++} ++grub_efi_loongson_resource; ++ ++/* arch specific additions */ ++typedef struct ++{ ++} ++grub_efi_loongson_archdev_data; ++ ++typedef struct ++{ ++ char name[64]; /* hold the device name */ ++ grub_uint32_t num_resources; /* number of device_resource */ ++ /* for each device's resource */ ++ grub_efi_loongson_resource resource[GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER]; ++ /* arch specific additions */ ++ grub_efi_loongson_archdev_data archdata; ++} ++grub_efi_loongson_board_devices; ++ ++typedef struct ++{ ++ grub_uint16_t vers; /* version */ ++ char special_name[64]; /* special_atribute_name */ ++ grub_uint32_t loongson_special_type; /* type of special device */ ++ /* for each device's resource */ ++ grub_efi_loongson_resource resource[GRUB_EFI_LOONGSON_MAX_RESOURCE_NUMBER]; ++} ++grub_efi_loongson_special_attribute; ++ ++typedef struct ++{ ++ grub_uint64_t memory_offset; /* efi_loongson_memory_map struct offset */ ++ grub_uint64_t cpu_offset; /* efi_loongson_cpuinfo struct offset */ ++ grub_uint64_t system_offset; /* efi_loongson_system_info struct offset */ ++ grub_uint64_t irq_offset; /* efi_loongson_irq_src_routing_table struct offset */ ++ grub_uint64_t interface_offset; /* interface_info struct offset */ ++ grub_uint64_t special_offset; /* efi_loongson_special_attribute struct offset */ ++ grub_uint64_t boarddev_table_offset; /* efi_loongson_board_devices offset */ ++} ++grub_efi_loongson_params; ++ ++typedef struct ++{ ++ grub_uint16_t vers; /* version */ ++ grub_uint64_t vga_bios; /* vga_bios address */ ++ grub_efi_loongson_params lp; ++} ++grub_efi_loongson_smbios_table; ++ ++typedef struct ++{ ++ grub_uint64_t reset_cold; ++ grub_uint64_t reset_warm; ++ grub_uint64_t reset_type; ++ grub_uint64_t shutdown; ++ grub_uint64_t do_suspend; /* NULL if not support */ ++} ++grub_efi_loongson_reset_system; ++ ++typedef struct ++{ ++ grub_uint64_t mps; /* MPS table */ ++ grub_uint64_t acpi; /* ACPI table (IA64 ext 0.71) */ ++ grub_uint64_t acpi20; /* ACPI table (ACPI 2.0) */ ++ grub_efi_loongson_smbios_table smbios; /* SM BIOS table */ ++ grub_uint64_t sal_systab; /* SAL system table */ ++ grub_uint64_t boot_info; /* boot info table */ ++} ++grub_efi_loongson; ++ ++typedef struct ++{ ++ grub_efi_loongson efi; ++ grub_efi_loongson_reset_system reset_system; ++} ++grub_efi_loongson_boot_params; ++ ++extern grub_uint64_t grub_efi_loongson_reset_system_addr; ++ ++extern void grub_efi_loongson_reset_cold (void); ++extern void grub_efi_loongson_reset_warm (void); ++extern void grub_efi_loongson_reset_shutdown (void); ++extern void grub_efi_loongson_reset_suspend (void); ++ ++void grub_efi_loongson_alloc_boot_params (void); ++void grub_efi_loongson_free_boot_params (void); ++void * grub_efi_loongson_get_smbios_table (void); ++ ++int EXPORT_FUNC(grub_efi_is_loongson) (void); ++ ++grub_uint8_t ++EXPORT_FUNC(grub_efi_loongson_calculatesum8) (const grub_uint8_t *Buffer, grub_efi_uintn_t Length); ++ ++grub_uint8_t ++EXPORT_FUNC(grub_efi_loongson_grub_calculatechecksum8) (const grub_uint8_t *Buffer, grub_efi_uintn_t Length); ++ ++ ++void * ++EXPORT_FUNC(grub_efi_loongson_get_boot_params) (void); ++ ++typedef struct _extention_list_hdr{ ++ grub_uint64_t signature; ++ grub_uint32_t length; ++ grub_uint8_t revision; ++ grub_uint8_t checksum; ++ struct _extention_list_hdr *next; ++}GRUB_PACKED ++ext_list; ++ ++typedef struct bootparamsinterface { ++ grub_uint64_t signature; //{'B', 'P', 'I', '_', '0', '_', '1'} ++ grub_efi_system_table_t *systemtable; ++ ext_list *extlist; ++}GRUB_PACKED ++bootparamsinterface; ++ ++typedef struct { ++ ext_list header; // {'M', 'E', 'M'} ++ grub_uint8_t mapcount; ++ struct GRUB_PACKED memmap { ++ grub_uint32_t memtype; ++ grub_uint64_t memstart; ++ grub_uint64_t memsize; ++ } map[GRUB_EFI_LOONGSON_MMAP_MAX]; ++}GRUB_PACKED ++mem_map; ++ ++typedef struct { ++ ext_list header; // {VBIOS} ++ grub_uint64_t vbiosaddr; ++}GRUB_PACKED ++vbios; ++ ++grub_uint32_t ++EXPORT_FUNC (grub_efi_loongson_memmap_sort) (struct memmap array[], grub_uint32_t length, mem_map * bpmem, grub_uint32_t index, grub_uint32_t memtype); ++#endif /* ! GRUB_EFI_LOONGSON_HEADER */ +diff --git a/include/grub/loongarch64/efi/memory.h b/include/grub/loongarch64/efi/memory.h +new file mode 100644 +index 0000000..b8556c7 +--- /dev/null ++++ b/include/grub/loongarch64/efi/memory.h +@@ -0,0 +1,14 @@ ++#ifndef GRUB_MEMORY_CPU_HEADER ++#include ++ ++#define GRUB_EFI_MAX_USABLE_ADDRESS 0x9800000fffffffffUL ++#define GRUB_EFI_MAX_ALLOCATION_ADDRESS GRUB_EFI_MAX_USABLE_ADDRESS ++ ++static inline grub_uint64_t grub_efi_max_usable_address(void) ++{ ++ grub_uint64_t addr; ++ asm volatile ("csrrd %0, 0x181" : "=r" (addr)); ++ return addr |= 0xffffffffffUL; ++} ++ ++#endif /* ! GRUB_MEMORY_CPU_HEADER */ +diff --git a/include/grub/loongarch64/efi/time.h b/include/grub/loongarch64/efi/time.h +new file mode 100644 +index 0000000..e69de29 +diff --git a/include/grub/loongarch64/io.h b/include/grub/loongarch64/io.h +new file mode 100644 +index 0000000..5f34103 +--- /dev/null ++++ b/include/grub/loongarch64/io.h +@@ -0,0 +1,62 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2009,2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_IO_H ++#define GRUB_IO_H 1 ++ ++#include ++ ++typedef grub_addr_t grub_port_t; ++ ++static __inline unsigned char ++grub_inb (grub_port_t port) ++{ ++ return *(volatile grub_uint8_t *) port; ++} ++ ++static __inline unsigned short int ++grub_inw (grub_port_t port) ++{ ++ return *(volatile grub_uint16_t *) port; ++} ++ ++static __inline unsigned int ++grub_inl (grub_port_t port) ++{ ++ return *(volatile grub_uint32_t *) port; ++} ++ ++static __inline void ++grub_outb (unsigned char value, grub_port_t port) ++{ ++ *(volatile grub_uint8_t *) port = value; ++} ++ ++static __inline void ++grub_outw (unsigned short int value, grub_port_t port) ++{ ++ *(volatile grub_uint16_t *) port = value; ++} ++ ++static __inline void ++grub_outl (unsigned int value, grub_port_t port) ++{ ++ *(volatile grub_uint32_t *) port = value; ++} ++ ++#endif /* _SYS_IO_H */ +diff --git a/include/grub/loongarch64/kernel.h b/include/grub/loongarch64/kernel.h +new file mode 100644 +index 0000000..909d539 +--- /dev/null ++++ b/include/grub/loongarch64/kernel.h +@@ -0,0 +1,24 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2005,2006,2007,2008,2009,2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_KERNEL_CPU_HEADER ++#define GRUB_KERNEL_CPU_HEADER 1 ++ ++#include ++ ++#endif /* ! GRUB_KERNEL_MACHINE_HEADER */ +diff --git a/include/grub/loongarch64/linux.h b/include/grub/loongarch64/linux.h +new file mode 100644 +index 0000000..cbf8775 +--- /dev/null ++++ b/include/grub/loongarch64/linux.h +@@ -0,0 +1,22 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2013 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_LOONGARCH64_LINUX_HEADER ++#define GRUB_LOONGARCH64_LINUX_HEADER 1 ++ ++#endif /* ! GRUB_LOONGARCH64_LINUX_HEADER */ +diff --git a/include/grub/loongarch64/loongarch64.h b/include/grub/loongarch64/loongarch64.h +new file mode 100644 +index 0000000..ea3be3d +--- /dev/null ++++ b/include/grub/loongarch64/loongarch64.h +@@ -0,0 +1,30 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2010,2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_REGISTERS_CPU_HEADER ++#define GRUB_REGISTERS_CPU_HEADER 1 ++ ++#ifdef ASM_FILE ++#define GRUB_CPU_REGISTER_WRAP(x) x ++#else ++#define GRUB_CPU_REGISTER_WRAP(x) #x ++#endif ++ ++#define GRUB_CPU_LOONGARCH_COP0_TIMER_COUNT GRUB_CPU_REGISTER_WRAP(9) ++ ++#endif +diff --git a/include/grub/loongarch64/memory.h b/include/grub/loongarch64/memory.h +new file mode 100644 +index 0000000..03398b3 +--- /dev/null ++++ b/include/grub/loongarch64/memory.h +@@ -0,0 +1,57 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_MEMORY_CPU_HEADER ++#define GRUB_MEMORY_CPU_HEADER 1 ++ ++#ifndef ASM_FILE ++#include ++#include ++#include ++#endif ++ ++#ifndef ASM_FILE ++ ++typedef grub_addr_t grub_phys_addr_t; ++ ++static inline grub_phys_addr_t ++grub_vtop (void *a) ++{ ++ if (-1 == ((grub_int64_t) a >> 32)) ++ return ((grub_phys_addr_t) a) & 0x1fffffffUL; ++ return ((grub_phys_addr_t) a) & 0xffffffffffffUL; ++} ++ ++static inline void * ++grub_map_memory (grub_phys_addr_t a, grub_size_t size) ++{ ++ grub_uint64_t addr; ++ ++ asm volatile ("csrrd %0, 0x181" : "=r" (addr)); ++ return (void *) (a | (addr & 0xffffffffffffff00UL)); ++} ++ ++static inline void ++grub_unmap_memory (void *a __attribute__ ((unused)), ++ grub_size_t size __attribute__ ((unused))) ++{ ++} ++ ++#endif ++ ++#endif +diff --git a/include/grub/loongarch64/relocator.h b/include/grub/loongarch64/relocator.h +new file mode 100644 +index 0000000..8815314 +--- /dev/null ++++ b/include/grub/loongarch64/relocator.h +@@ -0,0 +1,38 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_RELOCATOR_CPU_HEADER ++#define GRUB_RELOCATOR_CPU_HEADER 1 ++ ++#include ++#include ++#include ++ ++struct grub_relocator64_state ++{ ++ /* gpr[0] is ignored since it's hardwired to 0. */ ++ grub_uint64_t gpr[32]; ++ /* Register holding target $pc. */ ++ int jumpreg; ++}; ++ ++grub_err_t ++grub_relocator64_boot (struct grub_relocator *rel, ++ struct grub_relocator64_state state); ++ ++#endif /* ! GRUB_RELOCATOR_CPU_HEADER */ +diff --git a/include/grub/loongarch64/setjmp.h b/include/grub/loongarch64/setjmp.h +new file mode 100644 +index 0000000..d9a0776 +--- /dev/null ++++ b/include/grub/loongarch64/setjmp.h +@@ -0,0 +1,27 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2004,2006,2007,2009,2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_SETJMP_CPU_HEADER ++#define GRUB_SETJMP_CPU_HEADER 1 ++ ++typedef grub_uint64_t grub_jmp_buf[12]; ++ ++int grub_setjmp (grub_jmp_buf env) RETURNS_TWICE; ++void grub_longjmp (grub_jmp_buf env, int val) __attribute__ ((noreturn)); ++ ++#endif /* ! GRUB_SETJMP_CPU_HEADER */ +diff --git a/include/grub/loongarch64/time.h b/include/grub/loongarch64/time.h +new file mode 100644 +index 0000000..c9a7334 +--- /dev/null ++++ b/include/grub/loongarch64/time.h +@@ -0,0 +1,39 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2003,2004,2005,2007,2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef KERNEL_CPU_TIME_HEADER ++#define KERNEL_CPU_TIME_HEADER 1 ++ ++#ifndef GRUB_UTIL ++ ++#define GRUB_TICKS_PER_SECOND (grub_arch_cpuclock / 2) ++ ++void grub_timer_init (grub_uint32_t cpuclock); ++ ++/* Return the real time in ticks. */ ++grub_uint64_t grub_get_rtc (void); ++ ++extern grub_uint32_t grub_arch_cpuclock; ++#endif ++ ++static inline void ++grub_cpu_idle(void) ++{ ++} ++ ++#endif +diff --git a/include/grub/loongarch64/types.h b/include/grub/loongarch64/types.h +new file mode 100644 +index 0000000..5dc7f21 +--- /dev/null ++++ b/include/grub/loongarch64/types.h +@@ -0,0 +1,34 @@ ++/* ++ * GRUB -- GRand Unified Bootloader ++ * Copyright (C) 2002,2006,2007,2009,2017 Free Software Foundation, Inc. ++ * ++ * GRUB is free software: you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation, either version 3 of the License, or ++ * (at your option) any later version. ++ * ++ * GRUB is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GRUB. If not, see . ++ */ ++ ++#ifndef GRUB_TYPES_CPU_HEADER ++#define GRUB_TYPES_CPU_HEADER 1 ++ ++/* The size of void *. */ ++#define GRUB_TARGET_SIZEOF_VOID_P 8 ++ ++/* The size of long. */ ++#define GRUB_TARGET_SIZEOF_LONG 8 ++ ++#ifdef GRUB_CPU_LOONGARCH ++/* loongarch is little-endian. */ ++#undef GRUB_TARGET_WORDS_BIGENDIAN ++ ++#endif /* ! GRUB_TYPES_CPU_HEADER */ ++ ++#endif +diff --git a/include/grub/util/install.h b/include/grub/util/install.h +index dad1756..33feae9 100644 +--- a/include/grub/util/install.h ++++ b/include/grub/util/install.h +@@ -107,6 +107,7 @@ enum grub_install_plat + GRUB_INSTALL_PLATFORM_X86_64_XEN, + GRUB_INSTALL_PLATFORM_ARM64_EFI, + GRUB_INSTALL_PLATFORM_ARM_COREBOOT, ++ GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI, + GRUB_INSTALL_PLATFORM_MAX + }; + +diff --git a/util/grub-install-common.c b/util/grub-install-common.c +index fde4ca7..6504637 100644 +--- a/util/grub-install-common.c ++++ b/util/grub-install-common.c +@@ -738,27 +738,28 @@ static struct + const char *platform; + } platforms[GRUB_INSTALL_PLATFORM_MAX] = + { +- [GRUB_INSTALL_PLATFORM_I386_PC] = { "i386", "pc" }, +- [GRUB_INSTALL_PLATFORM_I386_EFI] = { "i386", "efi" }, +- [GRUB_INSTALL_PLATFORM_I386_QEMU] = { "i386", "qemu" }, +- [GRUB_INSTALL_PLATFORM_I386_COREBOOT] = { "i386", "coreboot" }, +- [GRUB_INSTALL_PLATFORM_I386_MULTIBOOT] = { "i386", "multiboot" }, +- [GRUB_INSTALL_PLATFORM_I386_IEEE1275] = { "i386", "ieee1275" }, +- [GRUB_INSTALL_PLATFORM_X86_64_EFI] = { "x86_64", "efi" }, +- [GRUB_INSTALL_PLATFORM_I386_XEN] = { "i386", "xen" }, +- [GRUB_INSTALL_PLATFORM_X86_64_XEN] = { "x86_64", "xen" }, +- [GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON] = { "mipsel", "loongson" }, +- [GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS] = { "mipsel", "qemu_mips" }, +- [GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS] = { "mips", "qemu_mips" }, +- [GRUB_INSTALL_PLATFORM_MIPSEL_ARC] = { "mipsel", "arc" }, +- [GRUB_INSTALL_PLATFORM_MIPS_ARC] = { "mips", "arc" }, +- [GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275] = { "sparc64", "ieee1275" }, +- [GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275] = { "powerpc", "ieee1275" }, +- [GRUB_INSTALL_PLATFORM_IA64_EFI] = { "ia64", "efi" }, +- [GRUB_INSTALL_PLATFORM_ARM_EFI] = { "arm", "efi" }, +- [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64", "efi" }, +- [GRUB_INSTALL_PLATFORM_ARM_UBOOT] = { "arm", "uboot" }, +- [GRUB_INSTALL_PLATFORM_ARM_COREBOOT] = { "arm", "coreboot" }, ++ [GRUB_INSTALL_PLATFORM_I386_PC] = { "i386", "pc" }, ++ [GRUB_INSTALL_PLATFORM_I386_EFI] = { "i386", "efi" }, ++ [GRUB_INSTALL_PLATFORM_I386_QEMU] = { "i386", "qemu" }, ++ [GRUB_INSTALL_PLATFORM_I386_COREBOOT] = { "i386", "coreboot" }, ++ [GRUB_INSTALL_PLATFORM_I386_MULTIBOOT] = { "i386", "multiboot" }, ++ [GRUB_INSTALL_PLATFORM_I386_IEEE1275] = { "i386", "ieee1275" }, ++ [GRUB_INSTALL_PLATFORM_X86_64_EFI] = { "x86_64", "efi" }, ++ [GRUB_INSTALL_PLATFORM_I386_XEN] = { "i386", "xen" }, ++ [GRUB_INSTALL_PLATFORM_X86_64_XEN] = { "x86_64", "xen" }, ++ [GRUB_INSTALL_PLATFORM_MIPSEL_LOONGSON] = { "mipsel", "loongson" }, ++ [GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS] = { "mipsel", "qemu_mips" }, ++ [GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS] = { "mips", "qemu_mips" }, ++ [GRUB_INSTALL_PLATFORM_MIPSEL_ARC] = { "mipsel", "arc" }, ++ [GRUB_INSTALL_PLATFORM_MIPS_ARC] = { "mips", "arc" }, ++ [GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275] = { "sparc64", "ieee1275" }, ++ [GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275] = { "powerpc", "ieee1275" }, ++ [GRUB_INSTALL_PLATFORM_IA64_EFI] = { "ia64", "efi" }, ++ [GRUB_INSTALL_PLATFORM_ARM_EFI] = { "arm", "efi" }, ++ [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64", "efi" }, ++ [GRUB_INSTALL_PLATFORM_ARM_UBOOT] = { "arm", "uboot" }, ++ [GRUB_INSTALL_PLATFORM_ARM_COREBOOT] = { "arm", "coreboot" }, ++ [GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI] = { "loongarch64", "efi" }, + }; + + char * +diff --git a/util/grub-install.c b/util/grub-install.c +index 65bb2f9..28b5d74 100644 +--- a/util/grub-install.c ++++ b/util/grub-install.c +@@ -322,6 +322,8 @@ get_default_platform (void) + return "arm-uboot"; + #elif defined (__aarch64__) + return "arm64-efi"; ++#elif defined (__loongarch64) ++ return "loongarch64-efi"; + #elif defined (__amd64__) || defined (__x86_64__) || defined (__i386__) + return grub_install_get_default_x86_platform (); + #else +@@ -477,6 +479,7 @@ have_bootdev (enum grub_install_plat pl) + case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: +@@ -895,6 +898,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_I386_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: + case GRUB_INSTALL_PLATFORM_X86_64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + is_efi = 1; + grub_util_error (_("this utility cannot be used for EFI platforms" + " because it does not support UEFI Secure Boot")); +@@ -921,6 +925,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: + case GRUB_INSTALL_PLATFORM_POWERPC_IEEE1275: +@@ -965,6 +970,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + case GRUB_INSTALL_PLATFORM_I386_IEEE1275: + case GRUB_INSTALL_PLATFORM_ARM_UBOOT: + case GRUB_INSTALL_PLATFORM_I386_QEMU: +@@ -1110,6 +1116,9 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + efi_file = "BOOTAA64.EFI"; + break; ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: ++ efi_file = "BOOTLOONGARCH64.EFI"; ++ break; + default: + grub_util_error ("%s", _("You've found a bug")); + break; +@@ -1137,6 +1146,9 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + efi_file = "grubaa64.efi"; + break; ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: ++ efi_file = "grubloongarch64.efi"; ++ break; + default: + efi_file = "grub.efi"; + break; +@@ -1440,6 +1452,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + g = grub_util_guess_efi_drive (*curdev); + break; + case GRUB_INSTALL_PLATFORM_SPARC64_IEEE1275: +@@ -1581,6 +1594,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + core_name = "core.efi"; + snprintf (mkimage_target, sizeof (mkimage_target), + "%s-%s", +@@ -1683,6 +1697,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + case GRUB_INSTALL_PLATFORM_MIPSEL_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_MIPS_QEMU_MIPS: + case GRUB_INSTALL_PLATFORM_I386_COREBOOT: +@@ -1917,6 +1932,7 @@ main (int argc, char *argv[]) + case GRUB_INSTALL_PLATFORM_ARM_EFI: + case GRUB_INSTALL_PLATFORM_ARM64_EFI: + case GRUB_INSTALL_PLATFORM_IA64_EFI: ++ case GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI: + { + char *dst = grub_util_path_concat (2, efidir, efi_file); + grub_install_copy_file (imgfile, dst, 1); +diff --git a/util/grub-mkimagexx.c b/util/grub-mkimagexx.c +index 1bb5eb8..240e193 100644 +--- a/util/grub-mkimagexx.c ++++ b/util/grub-mkimagexx.c +@@ -783,6 +783,9 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, + struct grub_ia64_trampoline *tr = (void *) (pe_target + tramp_off); + grub_uint64_t *gpptr = (void *) (pe_target + got_off); + unsigned unmatched_adr_got_page = 0; ++ grub_uint64_t oprs[10240]= {0}; ++ int opri = -1; ++ grub_uint32_t la_abs = 0; + #define MASK19 ((1 << 19) - 1) + #else + grub_uint32_t *tr = (void *) (pe_target + tramp_off); +@@ -1122,6 +1125,173 @@ SUFFIX (relocate_addrs) (Elf_Ehdr *e, struct section_metadata *smd, + } + break; + } ++ case EM_LOONGARCH64: ++ { ++ sym_addr += addend; ++ switch (ELF_R_TYPE (info)) ++ { ++ case R_LARCH_64: ++ { ++ *target=(grub_uint64_t)sym_addr; ++ } ++ break; ++ case R_LARCH_MARK_LA: ++ { ++ la_abs=1; ++ } ++ break; ++ case R_LARCH_SOP_PUSH_PCREL: ++ { ++ opri++; ++ oprs[opri]=(grub_uint64_t)(sym_addr-(target_section_addr+offset+image_target->vaddr_offset)); ++ } ++ break; ++ case R_LARCH_SOP_PUSH_ABSOLUTE: ++ { ++ opri++; ++ oprs[opri]=(grub_uint64_t)sym_addr; ++ } ++ break; ++ case R_LARCH_SOP_PUSH_PLT_PCREL: ++ { ++ opri++; ++ oprs[opri]=(grub_uint64_t)(sym_addr-(target_section_addr+offset+image_target->vaddr_offset)); ++ } ++ break; ++ case R_LARCH_SOP_SUB: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 - opr2; ++ } ++ break; ++ case R_LARCH_SOP_SL: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 << opr2; ++ } ++ break; ++ case R_LARCH_SOP_SR: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 >> opr2; ++ } ++ break; ++ case R_LARCH_SOP_ADD: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 + opr2; ++ } ++ break; ++ case R_LARCH_SOP_AND: ++ { ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ opri++; ++ oprs[opri]=opr1 & opr2; ++ } ++ break; ++ case R_LARCH_SOP_IF_ELSE: ++ { ++ grub_uint64_t opr3=oprs[opri]; ++ opri--; ++ grub_uint64_t opr2=oprs[opri]; ++ opri--; ++ grub_uint64_t opr1=oprs[opri]; ++ opri--; ++ if(opr1){ ++ opri++; ++ oprs[opri]=opr2; ++ } else { ++ opri++; ++ oprs[opri]=opr3; ++ } ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_5: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target=(*target) | ((opr1 & 0x1f) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_U_10_12: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target=(*target) | ((opr1 & 0xfff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_12: ++ { ++ if(la_abs==1) ++ la_abs=0; ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target = (*target) | ((opr1 & 0xfff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_16: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target = (*target) | ((opr1 & 0xffff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_10_16_S2: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target = (*target) | (((opr1 >> 2) & 0xffff) << 10); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_5_20: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target = (*target) | ((opr1 & 0xfffff)<<5) ; ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target =(*target) | (((opr1 >> 2) & 0xffff) << 10); ++ *target =(*target) | ((opr1 >> 18) & 0x1f); ++ } ++ break; ++ case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: ++ { ++ grub_uint64_t opr1 = oprs[opri]; ++ opri--; ++ *target =(*target) | (((opr1 >> 2) & 0xffff) << 10); ++ *target =(*target) | ((opr1 >> 18) & 0x3ff); ++ } ++ break; ++ default: ++ grub_util_error (_("relocation 0x%x is not implemented yet"), ++ (unsigned int) ELF_R_TYPE (info)); ++ break; ++ } ++ break; ++ } + #endif + #if defined(MKIMAGE_ELF32) + case EM_ARM: +@@ -1310,7 +1480,10 @@ add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type, + + /* The spec does not mention the requirement of a Page RVA. + Here, align the address with a 4K boundary for safety. */ +- b->page_rva = (addr & ~(0x1000 - 1)); ++#ifdef GRUB_CPU_LOONGARCH64 ++ if (type) ++#endif ++ b->page_rva = (addr & ~(0x1000 - 1)); + b->block_size = sizeof (*b); + } + +@@ -1320,7 +1493,11 @@ add_fixup_entry (struct fixup_block_list **cblock, grub_uint16_t type, + + /* Add a new entry. */ + cur_index = ((b->block_size - sizeof (*b)) >> 1); ++#ifdef GRUB_CPU_LOONGARCH64 ++ entry = GRUB_PE32_FIXUP_ENTRY (type, type ? (addr - b->page_rva) : addr); ++#else + entry = GRUB_PE32_FIXUP_ENTRY (type, addr - b->page_rva); ++#endif + b->entries[cur_index] = grub_host_to_target16 (entry); + b->block_size += 2; + } +@@ -1366,6 +1543,10 @@ static void + translate_relocation_pe (struct translate_context *ctx, + Elf_Addr addr, + Elf_Addr info, ++#ifdef GRUB_CPU_LOONGARCH64 ++ Elf_Addr sym_addr, ++ Elf_Addr addend, ++#endif + const struct grub_install_image_target_desc *image_target) + { + /* Necessary to relocate only absolute addresses. */ +@@ -1477,6 +1658,133 @@ translate_relocation_pe (struct translate_context *ctx, + } + break; + break; ++ case EM_LOONGARCH64: ++ switch (ELF_R_TYPE (info)) ++ { ++ case R_LARCH_NONE: ++ break; ++ case R_LARCH_32: ++ break; ++ case R_LARCH_64: ++ { ++ ctx->current_address = add_fixup_entry ( ++ &ctx->lst, ++ GRUB_PE32_REL_BASED_DIR64, ++ addr, 0, ctx->current_address, ++ image_target); ++ } ++ break; ++ case R_LARCH_RELATIVE: ++ break; ++ case R_LARCH_COPY: ++ break; ++ case R_LARCH_JUMP_SLOT: ++ break; ++ case R_LARCH_TLS_DTPMOD32: ++ break; ++ case R_LARCH_TLS_DTPMOD64: ++ break; ++ case R_LARCH_TLS_DTPREL32: ++ break; ++ case R_LARCH_TLS_DTPREL64: ++ break; ++ case R_LARCH_TLS_TPREL32: ++ break; ++ case R_LARCH_TLS_TPREL64: ++ break; ++ case R_LARCH_IRELATIVE: ++ break; ++ case R_LARCH_MARK_LA: ++ { ++ ctx->current_address = add_fixup_entry ( ++ &ctx->lst, ++ GRUB_PE32_REL_BASED_LOONGARCH64, ++ addr, 0, ctx->current_address, ++ image_target); ++ } ++ break; ++ case R_LARCH_MARK_PCREL: ++ break; ++ case R_LARCH_SOP_PUSH_PCREL: ++ break; ++ case R_LARCH_SOP_PUSH_ABSOLUTE: ++ break; ++ case R_LARCH_SOP_PUSH_DUP: ++ break; ++ case R_LARCH_SOP_PUSH_GPREL: ++ break; ++ case R_LARCH_SOP_PUSH_TLS_TPREL: ++ break; ++ case R_LARCH_SOP_PUSH_TLS_GOT: ++ break; ++ case R_LARCH_SOP_PUSH_TLS_GD: ++ break; ++ case R_LARCH_SOP_PUSH_PLT_PCREL: ++ break; ++ case R_LARCH_SOP_ASSERT: ++ break; ++ case R_LARCH_SOP_NOT: ++ break; ++ case R_LARCH_SOP_SUB: ++ break; ++ case R_LARCH_SOP_SL: ++ break; ++ case R_LARCH_SOP_SR: ++ break; ++ case R_LARCH_SOP_ADD: ++ break; ++ case R_LARCH_SOP_AND: ++ break; ++ case R_LARCH_SOP_IF_ELSE: ++ break; ++ case R_LARCH_SOP_POP_32_S_10_5: ++ break; ++ case R_LARCH_SOP_POP_32_U_10_12: ++ break; ++ case R_LARCH_SOP_POP_32_S_10_12: ++ break; ++ case R_LARCH_SOP_POP_32_S_10_16: ++ break; ++ case R_LARCH_SOP_POP_32_S_10_16_S2: ++ break; ++ case R_LARCH_SOP_POP_32_S_5_20: ++ break; ++ case R_LARCH_SOP_POP_32_S_0_5_10_16_S2: ++ break; ++ case R_LARCH_SOP_POP_32_S_0_10_10_16_S2: ++ break; ++ case R_LARCH_SOP_POP_32_U: ++ break; ++ case R_LARCH_ADD8: ++ break; ++ case R_LARCH_ADD16: ++ break; ++ case R_LARCH_ADD24: ++ break; ++ case R_LARCH_ADD32: ++ break; ++ case R_LARCH_ADD64: ++ break; ++ case R_LARCH_SUB8: ++ break; ++ case R_LARCH_SUB16: ++ break; ++ case R_LARCH_SUB24: ++ break; ++ case R_LARCH_SUB32: ++ break; ++ case R_LARCH_SUB64: ++ break; ++ case R_LARCH_GNU_VTINHERIT: ++ break; ++ case R_LARCH_GNU_VTENTRY: ++ break; ++ default: ++ grub_util_error (_("relocation 0x%x is not implemented yet"), ++ (unsigned int) ELF_R_TYPE (info)); ++ break; ++ } ++ break; + #if defined(MKIMAGE_ELF32) + case EM_ARM: + switch (ELF_R_TYPE (info)) +@@ -1565,10 +1873,18 @@ static void + translate_relocation (struct translate_context *ctx, + Elf_Addr addr, + Elf_Addr info, ++#ifdef GRUB_CPU_LOONGARCH64 ++ Elf_Addr sym_addr, ++ Elf_Addr addend, ++#endif + const struct grub_install_image_target_desc *image_target) + { + if (image_target->id == IMAGE_EFI) ++#ifdef GRUB_CPU_LOONGARCH64 ++ translate_relocation_pe (ctx, addr, info, sym_addr, addend, image_target); ++#else + translate_relocation_pe (ctx, addr, info, image_target); ++#endif + else + translate_relocation_raw (ctx, addr, info, image_target); + } +@@ -1709,11 +2025,21 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, + if ((grub_target_to_host32 (s->sh_type) == SHT_REL) || + (grub_target_to_host32 (s->sh_type) == SHT_RELA)) + { ++#ifdef GRUB_CPU_LOONGARCH64 ++ Elf_Rela *r; ++#else + Elf_Rel *r; ++#endif + Elf_Word rtab_size, r_size, num_rs; + Elf_Off rtab_offset; + Elf_Addr section_address; + Elf_Word j; ++#ifdef GRUB_CPU_LOONGARCH64 ++ Elf_Shdr *symtab_section; ++ ++ symtab_section = (Elf_Shdr *) ((char *) smd->sections ++ + (grub_target_to_host32 (s->sh_link) * smd->section_entsize)); ++#endif + + if (!SUFFIX (is_kept_reloc_section) (s, image_target, smd)) + { +@@ -1732,20 +2058,39 @@ make_reloc_section (Elf_Ehdr *e, struct grub_mkimage_layout *layout, + + section_address = smd->vaddrs[grub_le_to_cpu32 (s->sh_info)]; + ++#ifdef GRUB_CPU_LOONGARCH64 ++ for (j = 0, r = (Elf_Rela *) ((char *) e + rtab_offset); ++ j < num_rs; ++ j++, r = (Elf_Rela *) ((char *) r + r_size)) ++#else + for (j = 0, r = (Elf_Rel *) ((char *) e + rtab_offset); + j < num_rs; + j++, r = (Elf_Rel *) ((char *) r + r_size)) ++#endif + { + Elf_Addr info; + Elf_Addr offset; + Elf_Addr addr; ++#ifdef GRUB_CPU_LOONGARCH64 ++ Elf_Addr sym_addr; ++ Elf_Addr addend; ++#endif + + offset = grub_target_to_host (r->r_offset); + info = grub_target_to_host (r->r_info); +- ++#ifdef GRUB_CPU_LOONGARCH64 ++ sym_addr = SUFFIX (get_symbol_address) (e, symtab_section, ++ ELF_R_SYM (info), image_target); ++ addend = (s->sh_type == grub_target_to_host32 (SHT_RELA)) ? ++ grub_target_to_host (r->r_addend) : 0; ++#endif + addr = section_address + offset; + ++#ifdef GRUB_CPU_LOONGARCH64 ++ translate_relocation (&ctx, addr, info, sym_addr, addend, image_target); ++#else + translate_relocation (&ctx, addr, info, image_target); ++#endif + } + } + +diff --git a/util/grub-mknetdir.c b/util/grub-mknetdir.c +index ae31271..c998850 100644 +--- a/util/grub-mknetdir.c ++++ b/util/grub-mknetdir.c +@@ -112,7 +112,8 @@ static struct + [GRUB_INSTALL_PLATFORM_X86_64_EFI] = { "x86_64-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_IA64_EFI] = { "ia64-efi", "efinet", ".efi" }, + [GRUB_INSTALL_PLATFORM_ARM_EFI] = { "arm-efi", "efinet", ".efi" }, +- [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64-efi", "efinet", ".efi" } ++ [GRUB_INSTALL_PLATFORM_ARM64_EFI] = { "arm64-efi", "efinet", ".efi" }, ++ [GRUB_INSTALL_PLATFORM_LOONGARCH64_EFI] = { "loongarch64-efi", "efinet", ".efi" } + }; + + static void +diff --git a/util/grub-module-verifier.c b/util/grub-module-verifier.c +index 03ba1ab..4a9943a 100644 +--- a/util/grub-module-verifier.c ++++ b/util/grub-module-verifier.c +@@ -119,6 +119,52 @@ struct grub_module_verifier_arch archs[] = { + -1 + } + }, ++ { "loongarch64", 8, 0, EM_LOONGARCH64, GRUB_MODULE_VERIFY_SUPPORTS_REL | GRUB_MODULE_VERIFY_SUPPORTS_RELA, (int[]){ ++ R_LARCH_NONE, ++ R_LARCH_32, ++ R_LARCH_64, ++ R_LARCH_RELATIVE, ++ R_LARCH_COPY, ++ R_LARCH_JUMP_SLOT, ++ R_LARCH_TLS_DTPMOD32, ++ R_LARCH_TLS_DTPMOD64, ++ R_LARCH_TLS_DTPREL32, ++ R_LARCH_TLS_DTPREL64, ++ R_LARCH_TLS_TPREL32, ++ R_LARCH_TLS_TPREL64, ++ R_LARCH_IRELATIVE, ++ R_LARCH_MARK_LA, ++ R_LARCH_MARK_PCREL, ++ R_LARCH_SOP_PUSH_PCREL, ++ R_LARCH_SOP_PUSH_ABSOLUTE, ++ R_LARCH_SOP_PUSH_DUP, ++ R_LARCH_SOP_PUSH_GPREL, ++ R_LARCH_SOP_PUSH_TLS_TPREL, ++ R_LARCH_SOP_PUSH_TLS_GOT, ++ R_LARCH_SOP_PUSH_TLS_GD, ++ R_LARCH_SOP_PUSH_PLT_PCREL, ++ R_LARCH_SOP_ASSERT, ++ R_LARCH_SOP_NOT, ++ R_LARCH_SOP_SUB, ++ R_LARCH_SOP_SL, ++ R_LARCH_SOP_SR, ++ R_LARCH_SOP_ADD, ++ R_LARCH_SOP_AND, ++ R_LARCH_SOP_IF_ELSE, ++ R_LARCH_SOP_POP_32_S_10_5, ++ R_LARCH_SOP_POP_32_U_10_12, ++ R_LARCH_SOP_POP_32_S_10_12, ++ R_LARCH_SOP_POP_32_S_10_16, ++ R_LARCH_SOP_POP_32_S_10_16_S2, ++ R_LARCH_SOP_POP_32_S_5_20, ++ R_LARCH_SOP_POP_32_S_0_5_10_16_S2, ++ R_LARCH_SOP_POP_32_S_0_10_10_16_S2, ++ R_LARCH_SOP_POP_32_U, ++ -1 ++ }, (int[]){ ++ -1 ++ } ++ }, + }; + + struct platform_whitelist { +diff --git a/util/mkimage.c b/util/mkimage.c +index 16418e2..0d39c07 100644 +--- a/util/mkimage.c ++++ b/util/mkimage.c +@@ -609,6 +609,22 @@ static const struct grub_install_image_target_desc image_targets[] = + .pe_target = GRUB_PE32_MACHINE_ARM64, + .elf_target = EM_AARCH64, + }, ++ { ++ .dirname = "loongarch64-efi", ++ .names = { "loongarch64-efi", NULL }, ++ .voidp_sizeof = 8, ++ .bigendian = 0, ++ .id = IMAGE_EFI, ++ .flags = PLATFORM_FLAGS_NONE, ++ .total_module_size = TARGET_NO_FIELD, ++ .decompressor_compressed_size = TARGET_NO_FIELD, ++ .decompressor_uncompressed_size = TARGET_NO_FIELD, ++ .decompressor_uncompressed_addr = TARGET_NO_FIELD, ++ .section_align = GRUB_PE32_SECTION_ALIGNMENT, ++ .vaddr_offset = EFI64_HEADER_SIZE, ++ .pe_target = GRUB_PE32_MACHINE_LOONGARCH64, ++ .elf_target = EM_LOONGARCH64, ++ }, + }; + + #include +-- +2.27.0 + diff --git a/grub.macros b/grub.macros index 681f069..c610494 100644 --- a/grub.macros +++ b/grub.macros @@ -92,7 +92,7 @@ %endif -%global efi_only aarch64 %{arm} +%global efi_only aarch64 %{arm} loongarch64 %global efi_arch x86_64 ia64 %{efi_only} %ifarch %{efi_arch} %global with_efi_arch 1 @@ -122,7 +122,7 @@ %global platform_modules " appendedsig " %endif -%ifarch aarch64 %{arm} +%ifarch aarch64 %{arm} loongarch64 %global platform_modules " " %endif @@ -187,6 +187,14 @@ )} %endif +%ifarch loongarch64 +%global with_emu_arch 0 +%global efiarch loongarch64 +%global target_cpu_name loongarch64 +%global grub_target_name loongarch64-efi +%global package_arch efi-loongarch64 +%endif + %global _target_platform %{target_cpu_name}-%{_vendor}-%{_target_os}%{?_gnu} %global _alt_target_platform %{alt_target_cpu_name}-%{_vendor}-%{_target_os}%{?_gnu} diff --git a/grub.patches b/grub.patches index 54b52a2..a636e77 100644 --- a/grub.patches +++ b/grub.patches @@ -547,3 +547,5 @@ Patch0546: 0546-nx-set-page-permissions-for-loaded-modules.patch Patch0547: 0547-nx-set-attrs-in-our-kernel-loaders.patch Patch0548: 0548-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch Patch0549: 0549-Fixup-grub_efi_get_variable-type-in-our-loaders.patch +# Support loongarch64 +#Patch1000: 1000-loongarch64-add-support.patch diff --git a/grub2.spec b/grub2.spec index d5336ac..e19077b 100644 --- a/grub2.spec +++ b/grub2.spec @@ -5,6 +5,10 @@ %undefine _missing_build_ids_terminate_build %global _configure_gnuconfig_hack 0 +%ifarch loongarch64 +%global _configure_gnuconfig_hack 1 +%endif + Name: grub2 Epoch: 1 Version: 2.02 @@ -115,7 +119,7 @@ Requires(post): dracut %{desc} This subpackage provides tools for support of all platforms. -%ifarch x86_64 +%ifarch x86_64 loongarch64 %package tools-efi Summary: Support tools for GRUB. Group: System Environment/Base @@ -185,6 +189,11 @@ git add grub-%{grublegacyarch}-%{tarversion} %endif git commit -m "After making subdirs" +%ifarch loongarch64 +%_update_config_sub +%_update_config_guess +%endif + %build %if 0%{with_efi_arch} %{expand:%do_primary_efi_build %%{grubefiarch} %%{grubefiname} %%{grubeficdname} %%{_target_platform} %%{efi_target_cflags} %%{efi_host_cflags} %{old_sb_ca} %{old_sb_cer} %{old_sb_key} %{sb_ca} %{sb_cer} %{sb_key}} @@ -226,8 +235,11 @@ rm -f $RPM_BUILD_ROOT%{_infodir}/dir ln -s %{name}-set-password ${RPM_BUILD_ROOT}/%{_sbindir}/%{name}-setpassword echo '.so man8/%{name}-set-password.8' > ${RPM_BUILD_ROOT}/%{_datadir}/man/man8/%{name}-setpassword.8 %ifnarch x86_64 -rm -vf ${RPM_BUILD_ROOT}/%{_bindir}/%{name}-render-label rm -vf ${RPM_BUILD_ROOT}/%{_sbindir}/%{name}-bios-setup +%endif + +%ifnarch x86_64 loongarch64 +rm -vf ${RPM_BUILD_ROOT}/%{_bindir}/%{name}-render-label rm -vf ${RPM_BUILD_ROOT}/%{_sbindir}/%{name}-macbless %endif @@ -387,7 +399,7 @@ fi %{_datadir}/man/man1/%{name}-editenv* %{_datadir}/man/man1/%{name}-mkpasswd-* -%ifarch x86_64 +%ifarch x86_64 loongarch64 %files tools-efi %{_sbindir}/%{name}-macbless %{_bindir}/%{name}-render-label @@ -513,6 +525,7 @@ fi %changelog * Fri Jun 17 2022 Bo Ren - 2.02-123.0.1.8 - Build pc-modules package on x86_64 (geliwei@openanolis.org) +- Add loongarch64 base support (zhangwenlong@loongson.cn)(chenguoqi@loongson.cn) * Fri Jun 03 2022 Robbie Harwood - 2.06-123.el8_6.8 - CVE fixes for 2022-06-07 -- Gitee From b9d33296a90f470f8dd02b5abc5995f005b4e937 Mon Sep 17 00:00:00 2001 From: songmingliang Date: Thu, 19 May 2022 00:17:50 +0800 Subject: [PATCH 4/4] Fix a bug in bls_make_list, blscfg --- 1001-bls-make-list.patch | 119 +++++++++++++++++++++++++++++++++++++++ grub.patches | 1 + grub2.spec | 1 + 3 files changed, 121 insertions(+) create mode 100644 1001-bls-make-list.patch diff --git a/1001-bls-make-list.patch b/1001-bls-make-list.patch new file mode 100644 index 0000000..ac39162 --- /dev/null +++ b/1001-bls-make-list.patch @@ -0,0 +1,119 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Zhongling He +Date: Tue, 29 Mar 2022 17:27:13 +0800 +Subject: [PATCH] Fix a bug in bls_make_list, blscfg + +We have encountered a bug while running LifseaOS aarch64 version without +initrd. This commit fixes this bug. It may have fixed some potential +bugs as well. + +There are 4 partitions in a LifseaOS disk image: +- The 1st partition is for BIOS bootloader +- The 2nd partition is for UEFI booting, which contains grub binary + compiled from this source code, grubaa64.efi +- The 3rd partition contains grub.cfg files and + loader/entries/ostree-1-LifseaOS.conf +- The 4th partition contains rootfs + +Since x86_64 supports both BIOS and UEFI booting and we employ BIOS +booting for x86_64 (w/o initrd) image, we don't put the grub2 binary +compiled into the 2nd partition. As a result, this bug was not observed. +However, aarch64 only supports UEFI booting. In other words, we are +using this grub2 to boot LifseaOS (w/o initrd). + +grubaa64.efi from the 2nd partition will read `/grub2/grub.cfg` in the +3rd partition. + +``` +... + set ignition_firstboot="ignition.firstboot +${ignition_network_kcmdline}" +fi + +blscfg +``` + +`blscfg` is a command to convert `loader/entries/ostree-1-LifseaOS.conf` +into a typical grub.cfg. However, here comes the bug. While booting, an +error message will appear. + +``` +error: ../../grub-core/loader/arm64/linux.c:292:filename expected. +Press any key to continue. +``` + +This is because the bug in `blscfg` unexpectedly add a line, `initrd`, +into the generated grub.cfg file. Grub2 will expect an initrd file path +after `initrd`. As a result, the error occurs. + +In grub-core/command/blscfg.c:676, if `initrds` is a non-NULL pointer, +then `src` will contain a `initrd` line. + +``` +static void create_entry (struct bls_entry *entry){ + ... + initrds = bls_make_list (entry, "initrd", NULL); // + ... + if (initrds){ + ... + tmp = grub_stpcpy(initrd, "initrd "); + ... + } + ... + src = grub_xasprintf ("load_video\n" + "set gfx_payload=keep\n" + "insmod gzio\n" + "linux %s%s%s%s\n" + "%s", + GRUB_BOOT_DEVICE, clinux, options ? " " : "", options ? options +: "", + initrd ? initrd : ""); +``` + +In grub-core/command/blscfg.c:562, `bls_make_list` will always return a +non-NULL pointer except for a `grub_malloc` error. + +``` +static char **bls_make_list (struct bls_entry *entry, const char *key, +int *num) +{ + ... + list = grub_malloc (sizeof (char *)); + if (!list) + return NULL; + list[0] = NULL; + ... + return list; +} +``` + +Therefore, `initrd` like will be appended into the auto-generated +grub.cfg if `grub_malloc` succeed, regardless of whether initrd is +stated in config file. Our bug fix, same as upstream, modifies the +behaviour of `bls_make_list`. `bls_make_list` will now return a non-NULL +pointer only if the required field actually exists. + +--- + grub-core/commands/blscfg.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/grub-core/commands/blscfg.c b/grub-core/commands/blscfg.c +index 795a9f9..bf18270 100644 +--- a/grub-core/commands/blscfg.c ++++ b/grub-core/commands/blscfg.c +@@ -589,6 +589,12 @@ static char **bls_make_list (struct bls_entry *entry, const char *key, int *num) + list[nlist] = NULL; + } + ++ if (!nlist) ++ { ++ grub_free (list); ++ return NULL; ++ } ++ + if (num) + *num = nlist; + +-- +2.27.0 + diff --git a/grub.patches b/grub.patches index a636e77..63b9afb 100644 --- a/grub.patches +++ b/grub.patches @@ -549,3 +549,4 @@ Patch0548: 0548-nx-set-the-nx-compatible-flag-in-EFI-grub-images.patch Patch0549: 0549-Fixup-grub_efi_get_variable-type-in-our-loaders.patch # Support loongarch64 #Patch1000: 1000-loongarch64-add-support.patch +Patch1001: 1001-bls-make-list.patch diff --git a/grub2.spec b/grub2.spec index e19077b..b7a8c85 100644 --- a/grub2.spec +++ b/grub2.spec @@ -526,6 +526,7 @@ fi * Fri Jun 17 2022 Bo Ren - 2.02-123.0.1.8 - Build pc-modules package on x86_64 (geliwei@openanolis.org) - Add loongarch64 base support (zhangwenlong@loongson.cn)(chenguoqi@loongson.cn) +- Fix a bug in bls_make_list, blscfg. (zhonglingh@linux.alibaba.com) * Fri Jun 03 2022 Robbie Harwood - 2.06-123.el8_6.8 - CVE fixes for 2022-06-07 -- Gitee