Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

firmware_loader: formalize built-in firmware API

Formalize the built-in firmware with a proper API. This can later
be used by other callers where all they need is built-in firmware.

We export the firmware_request_builtin() call for now only
under the TEST_FIRMWARE symbol namespace as there are no
direct modular users for it. If they pop up they are free
to export it generally. Built-in code always gets access to
the callers and we'll demonstrate a hidden user which has been
lurking in the kernel for a while and the reason why using a
proper API was better long term.

Reviewed-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Luis Chamberlain <mcgrof@kernel.org>
Link: https://lore.kernel.org/r/20211021155843.1969401-2-mcgrof@kernel.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Luis Chamberlain and committed by
Greg Kroah-Hartman
48d09e97 c87761db

+137 -79
+4 -2
drivers/base/firmware_loader/builtin/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 + obj-y += main.o 2 3 3 4 # Create $(fwdir) from $(CONFIG_EXTRA_FIRMWARE_DIR) -- if it doesn't have a 4 5 # leading /, it's relative to $(srctree). 5 6 fwdir := $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE_DIR)) 6 7 fwdir := $(addprefix $(srctree)/,$(filter-out /%,$(fwdir)))$(filter /%,$(fwdir)) 7 8 8 - obj-y := $(addsuffix .gen.o, $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE))) 9 + firmware := $(addsuffix .gen.o, $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE))) 10 + obj-y += $(firmware) 9 11 10 12 FWNAME = $(patsubst $(obj)/%.gen.S,%,$@) 11 13 FWSTR = $(subst $(comma),_,$(subst /,_,$(subst .,_,$(subst -,_,$(FWNAME))))) ··· 36 34 $(call filechk,fwbin) 37 35 38 36 # The .o files depend on the binaries directly; the .S files don't. 39 - $(addprefix $(obj)/, $(obj-y)): $(obj)/%.gen.o: $(fwdir)/% 37 + $(addprefix $(obj)/, $(firmware)): $(obj)/%.gen.o: $(fwdir)/% 40 38 41 39 targets := $(patsubst $(obj)/%,%, \ 42 40 $(shell find $(obj) -name \*.gen.S 2>/dev/null))
+100
drivers/base/firmware_loader/builtin/main.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Builtin firmware support */ 3 + 4 + #include <linux/firmware.h> 5 + #include "../firmware.h" 6 + 7 + /* Only if FW_LOADER=y */ 8 + #ifdef CONFIG_FW_LOADER 9 + 10 + extern struct builtin_fw __start_builtin_fw[]; 11 + extern struct builtin_fw __end_builtin_fw[]; 12 + 13 + static bool fw_copy_to_prealloc_buf(struct firmware *fw, 14 + void *buf, size_t size) 15 + { 16 + if (!buf) 17 + return true; 18 + if (size < fw->size) 19 + return false; 20 + memcpy(buf, fw->data, fw->size); 21 + return true; 22 + } 23 + 24 + /** 25 + * firmware_request_builtin() - load builtin firmware 26 + * @fw: pointer to firmware struct 27 + * @name: name of firmware file 28 + * 29 + * Some use cases in the kernel have a requirement so that no memory allocator 30 + * is involved as these calls take place early in boot process. An example is 31 + * the x86 CPU microcode loader. In these cases all the caller wants is to see 32 + * if the firmware was built-in and if so use it right away. This can be used 33 + * for such cases. 34 + * 35 + * This looks for the firmware in the built-in kernel. Only if the kernel was 36 + * built-in with the firmware you are looking for will this return successfully. 37 + * 38 + * Callers of this API do not need to use release_firmware() as the pointer to 39 + * the firmware is expected to be provided locally on the stack of the caller. 40 + **/ 41 + bool firmware_request_builtin(struct firmware *fw, const char *name) 42 + { 43 + struct builtin_fw *b_fw; 44 + 45 + if (!fw) 46 + return false; 47 + 48 + for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) { 49 + if (strcmp(name, b_fw->name) == 0) { 50 + fw->size = b_fw->size; 51 + fw->data = b_fw->data; 52 + return true; 53 + } 54 + } 55 + 56 + return false; 57 + } 58 + EXPORT_SYMBOL_NS_GPL(firmware_request_builtin, TEST_FIRMWARE); 59 + 60 + /** 61 + * firmware_request_builtin_buf() - load builtin firmware into optional buffer 62 + * @fw: pointer to firmware struct 63 + * @name: name of firmware file 64 + * @buf: If set this lets you use a pre-allocated buffer so that the built-in 65 + * firmware into is copied into. This field can be NULL. It is used by 66 + * callers such as request_firmware_into_buf() and 67 + * request_partial_firmware_into_buf() 68 + * @size: if buf was provided, the max size of the allocated buffer available. 69 + * If the built-in firmware does not fit into the pre-allocated @buf this 70 + * call will fail. 71 + * 72 + * This looks for the firmware in the built-in kernel. Only if the kernel was 73 + * built-in with the firmware you are looking for will this call possibly 74 + * succeed. If you passed a @buf the firmware will be copied into it *iff* the 75 + * built-in firmware fits into the pre-allocated buffer size specified in 76 + * @size. 77 + * 78 + * This caller is to be used internally by the firmware_loader only. 79 + **/ 80 + bool firmware_request_builtin_buf(struct firmware *fw, const char *name, 81 + void *buf, size_t size) 82 + { 83 + if (!firmware_request_builtin(fw, name)) 84 + return false; 85 + 86 + return fw_copy_to_prealloc_buf(fw, buf, size); 87 + } 88 + 89 + bool firmware_is_builtin(const struct firmware *fw) 90 + { 91 + struct builtin_fw *b_fw; 92 + 93 + for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) 94 + if (fw->data == b_fw->data) 95 + return true; 96 + 97 + return false; 98 + } 99 + 100 + #endif
+17
drivers/base/firmware_loader/firmware.h
··· 151 151 152 152 int assign_fw(struct firmware *fw, struct device *device); 153 153 154 + #ifdef CONFIG_FW_LOADER 155 + bool firmware_is_builtin(const struct firmware *fw); 156 + bool firmware_request_builtin_buf(struct firmware *fw, const char *name, 157 + void *buf, size_t size); 158 + #else /* module case */ 159 + static inline bool firmware_is_builtin(const struct firmware *fw) 160 + { 161 + return false; 162 + } 163 + static inline bool firmware_request_builtin_buf(struct firmware *fw, 164 + const char *name, 165 + void *buf, size_t size) 166 + { 167 + return false; 168 + } 169 + #endif 170 + 154 171 #ifdef CONFIG_FW_LOADER_PAGED_BUF 155 172 void fw_free_paged_buf(struct fw_priv *fw_priv); 156 173 int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed);
+1 -77
drivers/base/firmware_loader/main.c
··· 93 93 94 94 static struct firmware_cache fw_cache; 95 95 96 - /* Builtin firmware support */ 97 - 98 - #ifdef CONFIG_FW_LOADER 99 - 100 - extern struct builtin_fw __start_builtin_fw[]; 101 - extern struct builtin_fw __end_builtin_fw[]; 102 - 103 - static bool fw_copy_to_prealloc_buf(struct firmware *fw, 104 - void *buf, size_t size) 105 - { 106 - if (!buf) 107 - return true; 108 - if (size < fw->size) 109 - return false; 110 - memcpy(buf, fw->data, fw->size); 111 - return true; 112 - } 113 - 114 - static bool firmware_request_builtin(struct firmware *fw, const char *name) 115 - { 116 - struct builtin_fw *b_fw; 117 - 118 - if (!fw) 119 - return false; 120 - 121 - for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) { 122 - if (strcmp(name, b_fw->name) == 0) { 123 - fw->size = b_fw->size; 124 - fw->data = b_fw->data; 125 - return true; 126 - } 127 - } 128 - 129 - return false; 130 - } 131 - 132 - static bool firmware_request_builtin_buf(struct firmware *fw, const char *name, 133 - void *buf, size_t size) 134 - { 135 - if (!firmware_request_builtin(fw, name)) 136 - return false; 137 - return fw_copy_to_prealloc_buf(fw, buf, size); 138 - } 139 - 140 - static bool fw_is_builtin_firmware(const struct firmware *fw) 141 - { 142 - struct builtin_fw *b_fw; 143 - 144 - for (b_fw = __start_builtin_fw; b_fw != __end_builtin_fw; b_fw++) 145 - if (fw->data == b_fw->data) 146 - return true; 147 - 148 - return false; 149 - } 150 - 151 - #else /* Module case - no builtin firmware support */ 152 - 153 - static inline bool firmware_request_builtin(struct firmware *fw, 154 - const char *name) 155 - { 156 - return false; 157 - } 158 - 159 - static inline bool firmware_request_builtin_buf(struct firmware *fw, 160 - const char *name, void *buf, 161 - size_t size) 162 - { 163 - return false; 164 - } 165 - 166 - static inline bool fw_is_builtin_firmware(const struct firmware *fw) 167 - { 168 - return false; 169 - } 170 - #endif 171 - 172 96 static void fw_state_init(struct fw_priv *fw_priv) 173 97 { 174 98 struct fw_state *fw_st = &fw_priv->fw_st; ··· 992 1068 void release_firmware(const struct firmware *fw) 993 1069 { 994 1070 if (fw) { 995 - if (!fw_is_builtin_firmware(fw)) 1071 + if (!firmware_is_builtin(fw)) 996 1072 firmware_free_data(fw); 997 1073 kfree(fw); 998 1074 }
+15
include/linux/firmware.h
··· 20 20 struct module; 21 21 struct device; 22 22 23 + /* 24 + * Built-in firmware functionality is only available if FW_LOADER=y, but not 25 + * FW_LOADER=m 26 + */ 27 + #ifdef CONFIG_FW_LOADER 23 28 struct builtin_fw { 24 29 char *name; 25 30 void *data; 26 31 unsigned long size; 27 32 }; 33 + 34 + bool firmware_request_builtin(struct firmware *fw, const char *name); 28 35 29 36 /* We have to play tricks here much like stringify() to get the 30 37 __COUNTER__ macro to be expanded as we want it */ ··· 44 37 #define DECLARE_BUILTIN_FIRMWARE_SIZE(name, blob, size) \ 45 38 static const struct builtin_fw __fw_concat(__builtin_fw,__COUNTER__) \ 46 39 __used __section(".builtin_fw") = { name, blob, size } 40 + 41 + #else 42 + static inline bool firmware_request_builtin(struct firmware *fw, 43 + const char *name) 44 + { 45 + return false; 46 + } 47 + #endif 47 48 48 49 #if defined(CONFIG_FW_LOADER) || (defined(CONFIG_FW_LOADER_MODULE) && defined(MODULE)) 49 50 int request_firmware(const struct firmware **fw, const char *name,