From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from list by lists.gnu.org with archive (Exim 4.90_1) id 1mShwP-0007rW-T7 for mharc-grub-devel@gnu.org; Tue, 21 Sep 2021 11:44:17 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]:37536) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mShwN-0007rM-Tl for grub-devel@gnu.org; Tue, 21 Sep 2021 11:44:15 -0400 Received: from mail.logicbricks.com ([89.201.165.134]:59248) by eggs.gnu.org with esmtps (TLS1.2:RSA_AES_128_CBC_SHA1:128) (Exim 4.90_1) (envelope-from ) id 1mShwF-0003CV-VI for grub-devel@gnu.org; Tue, 21 Sep 2021 11:44:15 -0400 From: =?iso-8859-2?Q?Mislav_Stubli=E6?= To: "grub-devel@gnu.org" Subject: [PATCH] loader/i386/linux: Add device tree support Thread-Topic: [PATCH] loader/i386/linux: Add device tree support Thread-Index: Adeu/MqjJoLaQ/koRkCfQ2kh8dtrVw== Date: Tue, 21 Sep 2021 15:37:45 +0000 Message-ID: <6DF2B90AE826754EAEE52A5F86D6E41C787D78CF@mail.xylon.local> Accept-Language: en-US, hr-HR Content-Language: en-US X-MS-Has-Attach: X-MS-TNEF-Correlator: Content-Type: text/plain; charset="iso-8859-2" Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Received-SPF: pass client-ip=89.201.165.134; envelope-from=Mislav.Stublic@logicbricks.com; helo=mail.logicbricks.com X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: The development of GNU GRUB List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 21 Sep 2021 15:44:16 -0000 Hi, This implements device tree support for x86. Unfortunately I haven't been a= ble to test this on latest master but I have tested against 2.04 and it wor= ks fine. I will test on master later but I wanted to get some initial comme= nts if this is going in the right direction. What I haven't tested is firmw= are DTB loading support which only calls grub_efi_get_firmware_fdt from ker= n/efi implementation as I don't have hardware to test this scenario. Mislav Signed-off-by: Mislav Stubli=E6 --- grub-core/Makefile.am | 1 + grub-core/Makefile.core.def | 2 + grub-core/loader/i386/linux.c | 159 ++++++++++++++++++++++++++++++++++++++= ++-- include/grub/efi/efi.h | 5 +- include/grub/i386/linux.h | 21 +++++- 5 files changed, 181 insertions(+), 7 deletions(-) diff --git a/grub-core/Makefile.am b/grub-core/Makefile.am index ee88e44..1b9ba1f 100644 --- a/grub-core/Makefile.am +++ b/grub-core/Makefile.am @@ -186,6 +186,7 @@ KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/i38= 6/tsc.h KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/pci.h KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/acpi.h KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/i386/pmtimer.h +KERNEL_HEADER_FILES +=3D $(top_srcdir)/include/grub/fdt.h endif if COND_ia64_efi diff --git a/grub-core/Makefile.core.def b/grub-core/Makefile.core.def index 8022e1c..e499057 100644 --- a/grub-core/Makefile.core.def +++ b/grub-core/Makefile.core.def @@ -227,7 +227,9 @@ kernel =3D { x86_64_xen =3D kern/x86_64/dl.c; x86_64_efi =3D kern/x86_64/efi/callwrap.S; x86_64_efi =3D kern/i386/efi/init.c; + x86_64_efi =3D kern/efi/fdt.c; x86_64_efi =3D bus/pci.c; + x86_64_efi =3D lib/fdt.c; xen =3D kern/i386/tsc.c; xen =3D kern/i386/xen/tsc.c; diff --git a/grub-core/loader/i386/linux.c b/grub-core/loader/i386/linux.c index 9f74a96..9c67a54 100644 --- a/grub-core/loader/i386/linux.c +++ b/grub-core/loader/i386/linux.c @@ -37,6 +37,7 @@ #include #include #include +#include GRUB_MOD_LICENSE ("GPLv3+"); @@ -77,6 +78,7 @@ static void *efi_mmap_buf; static grub_size_t maximal_cmdline_size; static struct linux_kernel_params linux_params; static char *linux_cmdline; +static void *current_fdt =3D NULL; #ifdef GRUB_MACHINE_EFI static grub_efi_uintn_t efi_mmap_size; #else @@ -398,6 +400,38 @@ grub_linux_boot_mmap_fill (grub_uint64_t addr, grub_ui= nt64_t size, return 0; } +struct grub_fdt_ctx +{ + grub_addr_t fdt_target; + grub_memory_type_t mem_type; +}; + +static int +grub_linux_boot_acpi_find (grub_uint64_t addr, grub_uint64_t size, + grub_memory_type_t type, void *data) +{ + struct grub_fdt_ctx *fdt_ctx =3D data; + grub_uint64_t fdt_size =3D grub_fdt_get_totalsize(current_fdt); + grub_uint64_t setup_data_header =3D sizeof(struct linux_i386_kernel_head= er_setup_data); + + + if (type !=3D fdt_ctx->mem_type) + return 0; + + if (size < setup_data_header + fdt_size) + return 0; + + grub_dprintf ("fdt", "addr =3D 0x%lx, size =3D 0x%x, need_size =3D 0x%x,= type =3D %d\n", + (unsigned long) addr, + (unsigned) size, + (unsigned) setup_data_header + fdt_size, + fdt_ctx->mem_type); + + fdt_ctx->fdt_target =3D addr; + + return 1; +} + static grub_err_t grub_linux_boot (void) { @@ -411,6 +445,10 @@ grub_linux_boot (void) }; grub_size_t mmap_size; grub_size_t cl_offset; + struct grub_fdt_ctx fdt_ctx =3D {0}; + grub_uint64_t target_setup_data; + struct linux_i386_kernel_header_setup_data *tmp_setup_data; + grub_size_t fdt_size; #ifdef GRUB_MACHINE_IEEE1275 { @@ -579,6 +617,57 @@ grub_linux_boot (void) return grub_errno; ctx.params->mmap_size =3D ctx.e820_num; + if (current_fdt) + { + fdt_ctx.mem_type =3D GRUB_MEMORY_ACPI; +#ifdef GRUB_MACHINE_EFI + grub_efi_mmap_iterate (grub_linux_boot_acpi_find, &fdt_ctx, 0); +#else + grub_mmap_iterate (grub_linux_boot_acpi_find, &fdt_ctx); +#endif + if (!fdt_ctx.fdt_target) + { + fdt_ctx.mem_type =3D GRUB_MEMORY_NVS; +#ifdef GRUB_MACHINE_EFI + grub_efi_mmap_iterate (grub_linux_boot_acpi_find, &fdt_ctx, 0); +#else + grub_mmap_iterate (grub_linux_boot_acpi_find, &fdt_ctx); +#endif + } + } + + if (fdt_ctx.fdt_target) + { + grub_relocator_chunk_t ch; + + fdt_size =3D grub_fdt_get_totalsize (current_fdt); + + err =3D grub_relocator_alloc_chunk_addr (relocator, &ch, + fdt_ctx.fdt_target, + sizeof(*tmp_setup_data) + + fdt_size); + if (!err) + { + tmp_setup_data =3D grub_zalloc (sizeof (*tmp_setup_data) + fdt_s= ize); + if (tmp_setup_data) + { + target_setup_data =3D get_virtual_current_address (ch); + tmp_setup_data->next =3D 0; + tmp_setup_data->type =3D GRUB_SETUP_DTB; + tmp_setup_data->len =3D fdt_size; + grub_memcpy (tmp_setup_data->data, current_fdt, fdt_size); + grub_memcpy (target_setup_data, tmp_setup_data, + sizeof (*tmp_setup_data) + fdt_size); + + /* finalize FDT kernel target */ + ctx.params->setup_data =3D target_setup_data; + + grub_free (tmp_setup_data); + grub_free (current_fdt); + } + } + } + #ifdef GRUB_MACHINE_EFI { grub_efi_uintn_t efi_desc_size; @@ -591,9 +680,9 @@ grub_linux_boot (void) &efi_desc_size, &efi_desc_version)= ; if (err) return err; - + /* Note that no boot services are available from here. */ - efi_mmap_target =3D ctx.real_mode_target + efi_mmap_target =3D ctx.real_mode_target + ((grub_uint8_t *) efi_mmap_buf - (grub_uint8_t *) real_mode_mem); /* Pass EFI parameters. */ if (grub_le_to_cpu16 (ctx.params->version) >=3D 0x0208) @@ -743,7 +832,7 @@ grub_cmd_linux (grub_command_t cmd __attribute__ ((unus= ed)), align =3D 0; relocatable =3D 0; } - + if (grub_le_to_cpu16 (lh.version) >=3D 0x020a) { min_align =3D lh.min_alignment; @@ -1123,7 +1212,66 @@ grub_cmd_initrd (grub_command_t cmd __attribute__ ((= unused)), return grub_errno; } -static grub_command_t cmd_linux, cmd_initrd; +static grub_err_t +grub_cmd_devicetree (grub_command_t cmd __attribute__ ((unused)), + int argc, char *argv[]) +{ + grub_file_t dtb; + void *new_fdt; + int size; + + if (current_fdt) + grub_free (current_fdt); + current_fdt =3D NULL; + +#ifdef GRUB_MACHINE_EFI + /* no dtb file, try firmware */ + if (argc =3D=3D 0) + { + current_fdt =3D grub_efi_get_firmware_fdt(); + if (current_fdt) + return GRUB_ERR_NONE; + + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("firmware dtb not found= ")); + } +#endif + + if (argc !=3D 1) + return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("dtb filename expected"))= ; + + dtb =3D grub_file_open (argv[0], GRUB_FILE_TYPE_DEVICE_TREE_IMAGE); + if (!dtb) + return grub_errno; + + size =3D grub_file_size (dtb); + new_fdt =3D grub_zalloc (size); + if (!new_fdt) + return grub_errno; + + grub_dprintf ("loader", "Loading device tree to %p\n", + new_fdt); + if (grub_file_read (dtb, new_fdt, size) < size) + { + grub_free (new_fdt); + return grub_error (GRUB_ERR_FILE_READ_ERROR, + N_("unable to read dtb file %s"), + argv[0]); + } + + if (grub_fdt_check_header (new_fdt, size) !=3D 0) + { + grub_free (new_fdt); + return grub_error (GRUB_ERR_BAD_FILE_TYPE, N_("invalid device tree")= ); + } + + current_fdt =3D new_fdt; + + grub_file_close (dtb); + + return grub_errno; +} + +static grub_command_t cmd_linux, cmd_initrd, cmd_devicetree; GRUB_MOD_INIT(linux) { @@ -1131,6 +1279,9 @@ GRUB_MOD_INIT(linux) 0, N_("Load Linux.")); cmd_initrd =3D grub_register_command ("initrd", grub_cmd_initrd, 0, N_("Load initrd.")); + cmd_devicetree =3D grub_register_command_lockdown ("devicetree", grub_cm= d_devicetree, + /* TRANSLATORS: DTB stan= ds for device tree blob. */ + 0, N_("Load DTB file."))= ; my_mod =3D mod; } diff --git a/include/grub/efi/efi.h b/include/grub/efi/efi.h index 83d958f..a095925 100644 --- a/include/grub/efi/efi.h +++ b/include/grub/efi/efi.h @@ -96,8 +96,11 @@ extern void (*EXPORT_VAR(grub_efi_net_config)) (grub_efi= _handle_t hnd, char **device, char **path); -#if defined(__arm__) || defined(__aarch64__) || defined(__riscv) +#if defined(__arm__) || defined(__aarch64__) || defined(__riscv) || define= d(__x86_64__) void *EXPORT_FUNC(grub_efi_get_firmware_fdt)(void); +#endif + +#if defined(__arm__) || defined(__aarch64__) || defined(__riscv) grub_err_t EXPORT_FUNC(grub_efi_get_ram_base)(grub_addr_t *); #include grub_err_t grub_arch_efi_linux_check_image(struct linux_arch_kernel_header= *lh); diff --git a/include/grub/i386/linux.h b/include/grub/i386/linux.h index eddf925..b66413d 100644 --- a/include/grub/i386/linux.h +++ b/include/grub/i386/linux.h @@ -84,6 +84,23 @@ struct grub_e820_mmap grub_uint32_t type; } GRUB_PACKED; +/* taken from linux kernel bootparam.h */ +#define GRUB_SETUP_NONE 0 +#define GRUB_SETUP_E820_EXT 1 +#define GRUB_SETUP_DTB 2 +#define GRUB_SETUP_PCI 3 +#define GRUB_SETUP_EFI 4 +#define GRUB_SETUP_APPLE_PROPERTIES 5 +#define GRUB_SETUP_JAILHOUSE 6 +#define GRUB_SETUP_INDIRECT (1<<31) + +struct linux_i386_kernel_header_setup_data { + grub_uint64_t next; + grub_uint32_t type; + grub_uint32_t len; + grub_uint8_t data[0]; +}; + enum { GRUB_VIDEO_LINUX_TYPE_TEXT =3D 0x01, @@ -134,7 +151,7 @@ struct linux_i386_kernel_header grub_uint16_t heap_end_ptr; /* Free memory after setup end */ grub_uint16_t pad1; /* Unused */ grub_uint32_t cmd_line_ptr; /* Points to the kernel command lin= e */ - grub_uint32_t initrd_addr_max; /* Highest address for initrd */ + grub_uint32_t initrd_addr_max; /* Highest address for initrd */ grub_uint32_t kernel_alignment; grub_uint8_t relocatable; grub_uint8_t min_alignment; @@ -144,7 +161,7 @@ struct linux_i386_kernel_header grub_uint64_t hardware_subarch_data; grub_uint32_t payload_offset; grub_uint32_t payload_length; - grub_uint64_t setup_data; + grub_uint64_t setup_data; /* linked list of additional boot p= arameters (E820, DTB, PCI)*/ grub_uint64_t pref_address; grub_uint32_t init_size; grub_uint32_t handover_offset; -- 1.8.3.1 ----- Disclaimer ----- This e-mail message and its attachments may contain privileged and/or confi= dential information. Please do not read the message if You are not its desi= gnated recipient. If You have received this message by mistake, please info= rm its sender and destroy the original message and its attachments without = reading or storing of any kind. Any unauthorized use, distribution, reprodu= ction or publication of this message is forbidden. ----- Pravne napomene ----- Ova elektronicka poruka i njeni prilozi mogu sadrzavati povlastene informac= ije i/ili povjerljive informacije. Molimo Vas da poruku ne citate ako niste= njen naznaceni primatelj. Ako ste ovu poruku primili greskom, molimo Vas d= a o tome obavijestite posiljatelja i da izvornu poruku i njene privitke uni= stite bez citanja ili bilo kakvog pohranjivanja. Svaka neovlastena upotreba= , distribucija, reprodukcija ili priopcavanje ove poruke zabranjena je.