Skip to content

Commit 48d09e9

Browse files
mcgrofgregkh
authored andcommitted
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>
1 parent c87761d commit 48d09e9

5 files changed

Lines changed: 137 additions & 79 deletions

File tree

drivers/base/firmware_loader/builtin/Makefile

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
# SPDX-License-Identifier: GPL-2.0
2+
obj-y += main.o
23

34
# Create $(fwdir) from $(CONFIG_EXTRA_FIRMWARE_DIR) -- if it doesn't have a
45
# leading /, it's relative to $(srctree).
56
fwdir := $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE_DIR))
67
fwdir := $(addprefix $(srctree)/,$(filter-out /%,$(fwdir)))$(filter /%,$(fwdir))
78

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)
911

1012
FWNAME = $(patsubst $(obj)/%.gen.S,%,$@)
1113
FWSTR = $(subst $(comma),_,$(subst /,_,$(subst .,_,$(subst -,_,$(FWNAME)))))
@@ -34,7 +36,7 @@ $(obj)/%.gen.S: FORCE
3436
$(call filechk,fwbin)
3537

3638
# The .o files depend on the binaries directly; the .S files don't.
37-
$(addprefix $(obj)/, $(obj-y)): $(obj)/%.gen.o: $(fwdir)/%
39+
$(addprefix $(obj)/, $(firmware)): $(obj)/%.gen.o: $(fwdir)/%
3840

3941
targets := $(patsubst $(obj)/%,%, \
4042
$(shell find $(obj) -name \*.gen.S 2>/dev/null))
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
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

drivers/base/firmware_loader/firmware.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,23 @@ static inline void fw_state_done(struct fw_priv *fw_priv)
151151

152152
int assign_fw(struct firmware *fw, struct device *device);
153153

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+
154171
#ifdef CONFIG_FW_LOADER_PAGED_BUF
155172
void fw_free_paged_buf(struct fw_priv *fw_priv);
156173
int fw_grow_paged_buf(struct fw_priv *fw_priv, int pages_needed);

drivers/base/firmware_loader/main.c

Lines changed: 1 addition & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -93,82 +93,6 @@ DEFINE_MUTEX(fw_lock);
9393

9494
static struct firmware_cache fw_cache;
9595

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-
17296
static void fw_state_init(struct fw_priv *fw_priv)
17397
{
17498
struct fw_state *fw_st = &fw_priv->fw_st;
@@ -1068,7 +992,7 @@ EXPORT_SYMBOL(request_partial_firmware_into_buf);
1068992
void release_firmware(const struct firmware *fw)
1069993
{
1070994
if (fw) {
1071-
if (!fw_is_builtin_firmware(fw))
995+
if (!firmware_is_builtin(fw))
1072996
firmware_free_data(fw);
1073997
kfree(fw);
1074998
}

include/linux/firmware.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,19 @@ struct firmware {
2020
struct module;
2121
struct device;
2222

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
2328
struct builtin_fw {
2429
char *name;
2530
void *data;
2631
unsigned long size;
2732
};
2833

34+
bool firmware_request_builtin(struct firmware *fw, const char *name);
35+
2936
/* We have to play tricks here much like stringify() to get the
3037
__COUNTER__ macro to be expanded as we want it */
3138
#define __fw_concat1(x, y) x##y
@@ -38,6 +45,14 @@ struct builtin_fw {
3845
static const struct builtin_fw __fw_concat(__builtin_fw,__COUNTER__) \
3946
__used __section(".builtin_fw") = { name, blob, size }
4047

48+
#else
49+
static inline bool firmware_request_builtin(struct firmware *fw,
50+
const char *name)
51+
{
52+
return false;
53+
}
54+
#endif
55+
4156
#if defined(CONFIG_FW_LOADER) || (defined(CONFIG_FW_LOADER_MODULE) && defined(MODULE))
4257
int request_firmware(const struct firmware **fw, const char *name,
4358
struct device *device);

0 commit comments

Comments
 (0)