]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
boot: add helper for converting EFI_PHYSICAL_ADDRESS to a pointer
authorLennart Poettering <lennart@poettering.net>
Tue, 21 Sep 2021 19:57:51 +0000 (21:57 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 23 Sep 2021 15:24:28 +0000 (17:24 +0200)
This isn't trivial when trying to be compatible with 32bit archs, hence
add a set of helper macro-like functions that make the conversion safe.

src/boot/efi/cpio.c
src/boot/efi/devicetree.c
src/boot/efi/linux.c
src/boot/efi/measure.c
src/boot/efi/stub.c
src/boot/efi/util.h

index 9c99454d9a813d709a11f95d7fc9c898494663d5..10a044cc926a169005a15f631fec297aa9d32984 100644 (file)
@@ -452,7 +452,7 @@ EFI_STATUS pack_cpio(
 #if ENABLE_TPM
         err = tpm_log_event(
                         tpm_pcr,
-                        (EFI_PHYSICAL_ADDRESS) (UINTN) buffer,
+                        POINTER_TO_PHYSICAL_ADDRESS(buffer),
                         buffer_size,
                         tpm_description);
         if (EFI_ERROR(err))
index 87ae97a52e0659c7bdf492a52a52f2ccf20cc783..fd4b9c406c1a7f51507775537a8e2898bb38f776 100644 (file)
@@ -28,12 +28,6 @@ static UINTN devicetree_allocated(const struct devicetree_state *state) {
         return state->pages * EFI_PAGE_SIZE;
 }
 
-static VOID *devicetree_ptr(const struct devicetree_state *state) {
-        assert(state);
-        assert(state->addr <= UINTN_MAX);
-        return (VOID *)(UINTN)state->addr;
-}
-
 static EFI_STATUS devicetree_fixup(struct devicetree_state *state, UINTN len) {
         EFI_DT_FIXUP_PROTOCOL *fixup;
         UINTN size;
@@ -47,24 +41,24 @@ static EFI_STATUS devicetree_fixup(struct devicetree_state *state, UINTN len) {
                                               L"Could not locate device tree fixup protocol, skipping.");
 
         size = devicetree_allocated(state);
-        err = uefi_call_wrapper(fixup->Fixup, 4, fixup, devicetree_ptr(state), &size,
+        err = uefi_call_wrapper(fixup->Fixup, 4, fixup, PHYSICAL_ADDRESS_TO_POINTER(state->addr), &size,
                                 EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY);
         if (err == EFI_BUFFER_TOO_SMALL) {
                 EFI_PHYSICAL_ADDRESS oldaddr = state->addr;
                 UINTN oldpages = state->pages;
-                VOID *oldptr = devicetree_ptr(state);
+                VOID *oldptr = PHYSICAL_ADDRESS_TO_POINTER(state->addr);
 
                 err = devicetree_allocate(state, size);
                 if (EFI_ERROR(err))
                         return err;
 
-                CopyMem(devicetree_ptr(state), oldptr, len);
+                CopyMem(PHYSICAL_ADDRESS_TO_POINTER(state->addr), oldptr, len);
                 err = uefi_call_wrapper(BS->FreePages, 2, oldaddr, oldpages);
                 if (EFI_ERROR(err))
                         return err;
 
                 size = devicetree_allocated(state);
-                err = uefi_call_wrapper(fixup->Fixup, 4, fixup, devicetree_ptr(state), &size,
+                err = uefi_call_wrapper(fixup->Fixup, 4, fixup, PHYSICAL_ADDRESS_TO_POINTER(state->addr), &size,
                                         EFI_DT_APPLY_FIXUPS | EFI_DT_RESERVE_MEMORY);
         }
 
@@ -104,7 +98,7 @@ EFI_STATUS devicetree_install(struct devicetree_state *state,
         if (EFI_ERROR(err))
                 return err;
 
-        err = uefi_call_wrapper(handle->Read, 3, handle, &len, devicetree_ptr(state));
+        err = uefi_call_wrapper(handle->Read, 3, handle, &len, PHYSICAL_ADDRESS_TO_POINTER(state->addr));
         if (EFI_ERROR(err))
                 return err;
 
@@ -112,7 +106,7 @@ EFI_STATUS devicetree_install(struct devicetree_state *state,
         if (EFI_ERROR(err))
                 return err;
 
-        return uefi_call_wrapper(BS->InstallConfigurationTable, 2, &EfiDtbTableGuid, devicetree_ptr(state));
+        return uefi_call_wrapper(BS->InstallConfigurationTable, 2, &EfiDtbTableGuid, PHYSICAL_ADDRESS_TO_POINTER(state->addr));
 }
 
 void devicetree_cleanup(struct devicetree_state *state) {
index 529325fef9916ecf10bde9aed07e4a478c0c6654..3af69e4d578070df3260b3cabcea81d74d3c1bc0 100644 (file)
@@ -66,9 +66,10 @@ EFI_STATUS linux_exec(EFI_HANDLE image,
                                         EFI_SIZE_TO_PAGES(cmdline_len + 1), &addr);
                 if (EFI_ERROR(err))
                         return err;
-                CopyMem((VOID *)(UINTN)addr, cmdline, cmdline_len);
-                ((CHAR8 *)(UINTN)addr)[cmdline_len] = 0;
-                boot_params->hdr.cmd_line_ptr = (UINT32)addr;
+
+                CopyMem(PHYSICAL_ADDRESS_TO_POINTER(addr), cmdline, cmdline_len);
+                ((CHAR8 *) PHYSICAL_ADDRESS_TO_POINTER(addr))[cmdline_len] = 0;
+                boot_params->hdr.cmd_line_ptr = (UINT32) addr;
         }
 
         boot_params->hdr.ramdisk_image = (UINT32)initrd_addr;
index f73c9ff9ad6cc1d48100e57b85c683e27995ab99..de7856bacf90c85fc8240d40367260a29f925772 100644 (file)
@@ -168,7 +168,7 @@ EFI_STATUS tpm_log_load_options(const CHAR16 *load_options) {
         /* Measures a load options string into the TPM2, i.e. the kernel command line */
 
         err = tpm_log_event(TPM_PCR_INDEX_KERNEL_PARAMETERS,
-                            (EFI_PHYSICAL_ADDRESS) (UINTN) load_options,
+                            POINTER_TO_PHYSICAL_ADDRESS(load_options),
                             StrSize(load_options), load_options);
         if (EFI_ERROR(err))
                 return log_error_status_stall(err, L"Unable to add load options (i.e. kernel command) line measurement: %r", err);
index ad01ab138b6f136e73793270d092be4916cf4742..dad0f6133538063ab1119b8504451b6a9cdde12c 100644 (file)
@@ -55,13 +55,13 @@ static EFI_STATUS combine_initrd(
         if (EFI_ERROR(err))
                 return log_error_status_stall(err, L"Failed to allocate space for combined initrd: %r", err);
 
-        p = (UINT8*) (UINTN) base;
+        p = PHYSICAL_ADDRESS_TO_POINTER(base);
         if (initrd_base != 0) {
                 UINTN pad;
 
                 /* Order matters, the real initrd must come first, since it might include microcode updates
                  * which the kernel only looks for in the first cpio archive */
-                CopyMem(p, (VOID*) (UINTN) initrd_base, initrd_size);
+                CopyMem(p, PHYSICAL_ADDRESS_TO_POINTER(initrd_base), initrd_size);
                 p += initrd_size;
 
                 pad = ALIGN_TO(initrd_size, 4) - initrd_size;
@@ -81,7 +81,7 @@ static EFI_STATUS combine_initrd(
                 p += sysext_initrd_size;
         }
 
-        assert((UINT8*) (UINTN) base + n == p);
+        assert((UINT8*) PHYSICAL_ADDRESS_TO_POINTER(base) + n == p);
 
         *ret_initrd_base = base;
         *ret_initrd_size = n;
@@ -222,10 +222,10 @@ EFI_STATUS efi_main(EFI_HANDLE image, EFI_SYSTEM_TABLE *sys_table) {
                          &sysext_initrd,
                          &sysext_initrd_size);
 
-        linux_base = (EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->ImageBase + addrs[SECTION_LINUX];
+        linux_base = POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[SECTION_LINUX];
 
         initrd_size = szs[SECTION_INITRD];
-        initrd_base = initrd_size != 0 ? (EFI_PHYSICAL_ADDRESS) (UINTN) loaded_image->ImageBase + addrs[SECTION_INITRD] : 0;
+        initrd_base = initrd_size != 0 ? POINTER_TO_PHYSICAL_ADDRESS(loaded_image->ImageBase) + addrs[SECTION_INITRD] : 0;
 
         if (credential_initrd || sysext_initrd) {
                 /* If we have generated initrds dynamically, let's combine them with the built-in initrd. */
index 3a29ff2d7b26b4b4b0166e334b161da7b39bb135..ca95514d72b664a7c094f9bdd11b78edbb70cbbe 100644 (file)
@@ -124,3 +124,23 @@ static inline void strv_freep(CHAR16 ***p) {
 }
 
 EFI_STATUS open_directory(EFI_FILE_HANDLE root_dir, const CHAR16 *path, EFI_FILE_HANDLE *ret);
+
+/* Conversion between EFI_PHYSICAL_ADDRESS and pointers is not obvious. The former is always 64bit, even on
+ * 32bit archs. And gcc complains if we cast a pointer to an integer of a different size. Hence let's do the
+ * conversion indirectly: first into UINTN (which is defined by UEFI to have the same size as a pointer), and
+ * then extended to EFI_PHYSICAL_ADDRESS. */
+static inline EFI_PHYSICAL_ADDRESS POINTER_TO_PHYSICAL_ADDRESS(const void *p) {
+        return (EFI_PHYSICAL_ADDRESS) (UINTN) p;
+}
+
+static inline void *PHYSICAL_ADDRESS_TO_POINTER(EFI_PHYSICAL_ADDRESS addr) {
+#if __SIZEOF_POINTER__ == 4
+        /* On 32bit systems the address might not be convertible (as pointers are 32bit but
+         * EFI_PHYSICAL_ADDRESS 64bit) */
+        assert(addr <= UINT32_MAX);
+#elif __SIZEOF_POINTER__ != 8
+        #error "Unexpected pointer size"
+#endif
+
+        return (void*) (UINTN) addr;
+}