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

drivers: meson: sm: correct meson_sm_* API retval handling

1. Following the ARM SMC32 calling convention, the return value
from secure monitor is a 32-bit signed integer. This patch changes
the type of the return value of the function meson_sm_call().

2. Now, when meson_sm_call() returns a 32-bit signed integer, we need
to ensure that this value is not negative. It is important to check
that the return value is not negative in both the meson_sm_call_read()
and meson_sm_call_write() functions.

3. Add a comment explaining why it is necessary to check if the SMC
return value is equal to 0 in the function meson_sm_call_read().
It is not obvious when reading this code.

Signed-off-by: Alexey Romanov <avromanov@salutedevices.com>
Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
Link: https://lore.kernel.org/r/20230830140850.17130-1-avromanov@salutedevices.com
Signed-off-by: Neil Armstrong <neil.armstrong@linaro.org>

authored by

Alexey Romanov and committed by
Neil Armstrong
0d423c4a 0bb80ecc

+14 -8
+13 -7
drivers/firmware/meson/meson_sm.c
··· 67 67 return cmd->smc_id; 68 68 } 69 69 70 - static u32 __meson_sm_call(u32 cmd, u32 arg0, u32 arg1, u32 arg2, 70 + static s32 __meson_sm_call(u32 cmd, u32 arg0, u32 arg1, u32 arg2, 71 71 u32 arg3, u32 arg4) 72 72 { 73 73 struct arm_smccc_res res; ··· 102 102 * Return: 0 on success, a negative value on error 103 103 */ 104 104 int meson_sm_call(struct meson_sm_firmware *fw, unsigned int cmd_index, 105 - u32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) 105 + s32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4) 106 106 { 107 - u32 cmd, lret; 107 + u32 cmd; 108 + s32 lret; 108 109 109 110 if (!fw->chip) 110 111 return -ENOENT; ··· 144 143 unsigned int bsize, unsigned int cmd_index, u32 arg0, 145 144 u32 arg1, u32 arg2, u32 arg3, u32 arg4) 146 145 { 147 - u32 size; 146 + s32 size; 148 147 int ret; 149 148 150 149 if (!fw->chip) ··· 159 158 if (meson_sm_call(fw, cmd_index, &size, arg0, arg1, arg2, arg3, arg4) < 0) 160 159 return -EINVAL; 161 160 162 - if (size > bsize) 161 + if (size < 0 || size > bsize) 163 162 return -EINVAL; 164 163 165 164 ret = size; 166 165 166 + /* In some cases (for example GET_CHIP_ID command), 167 + * SMC doesn't return the number of bytes read, even 168 + * though the bytes were actually read into sm_shmem_out. 169 + * So this check is needed. 170 + */ 167 171 if (!size) 168 172 size = bsize; 169 173 ··· 198 192 unsigned int size, unsigned int cmd_index, u32 arg0, 199 193 u32 arg1, u32 arg2, u32 arg3, u32 arg4) 200 194 { 201 - u32 written; 195 + s32 written; 202 196 203 197 if (!fw->chip) 204 198 return -ENOENT; ··· 214 208 if (meson_sm_call(fw, cmd_index, &written, arg0, arg1, arg2, arg3, arg4) < 0) 215 209 return -EINVAL; 216 210 217 - if (!written) 211 + if (written <= 0 || written > size) 218 212 return -EINVAL; 219 213 220 214 return written;
+1 -1
include/linux/firmware/meson/meson_sm.h
··· 19 19 struct meson_sm_firmware; 20 20 21 21 int meson_sm_call(struct meson_sm_firmware *fw, unsigned int cmd_index, 22 - u32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4); 22 + s32 *ret, u32 arg0, u32 arg1, u32 arg2, u32 arg3, u32 arg4); 23 23 int meson_sm_call_write(struct meson_sm_firmware *fw, void *buffer, 24 24 unsigned int b_size, unsigned int cmd_index, u32 arg0, 25 25 u32 arg1, u32 arg2, u32 arg3, u32 arg4);