diff mbox

[2/2] crypto: ccp - Mark driver as little-endian only

Message ID 20170328095814.3734615-2-arnd@arndb.de (mailing list archive)
State Superseded
Delegated to: Herbert Xu
Headers show

Commit Message

Arnd Bergmann March 28, 2017, 9:58 a.m. UTC
The driver causes a warning when built as big-endian:

drivers/crypto/ccp/ccp-dev-v5.c: In function 'ccp5_perform_des3':
include/uapi/linux/byteorder/big_endian.h:32:26: error: large integer implicitly truncated to unsigned type [-Werror=overflow]
 #define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
                          ^
include/linux/byteorder/generic.h:87:21: note: in expansion of macro '__cpu_to_le32'
 #define cpu_to_le32 __cpu_to_le32
                     ^~~~~~~~~~~~~
drivers/crypto/ccp/ccp-dev-v5.c:436:28: note: in expansion of macro 'cpu_to_le32'
  CCP5_CMD_KEY_MEM(&desc) = cpu_to_le32(CCP_MEMTYPE_SB);

The warning is correct, doing a 32-bit byte swap on a value that gets
assigned into a bit field cannot work, since we would only write zeroes
in this case, regardless of the input.

In fact, the use of bit fields in hardware defined data structures is
not portable to start with, so until all these bit fields get replaced
by something else, the driver cannot work on big-endian machines, and
I'm adding an annotation here to prevent it from being selected.

The CCPv3 code seems to not suffer from this problem, only v5 uses
bitfields.

Fixes: 4b394a232df7 ("crypto: ccp - Let a v5 CCP provide the same function as v3")
Signed-off-by: Arnd Bergmann <arnd@arndb.de>
---
 drivers/crypto/ccp/Kconfig | 1 +
 1 file changed, 1 insertion(+)

Comments

Gary R Hook March 28, 2017, 2:08 p.m. UTC | #1
Ack. Didn't reply all....  Sorry, Arnd.

There was a krobot warning about this and I submitted a patch just now.

(I thought) my mistake was (in this function) not handling the structure
elements in the same manner as other functions. My patch rectifies that.

On 03/28/2017 04:58 AM, Arnd Bergmann wrote:
> The driver causes a warning when built as big-endian:
>
> drivers/crypto/ccp/ccp-dev-v5.c: In function 'ccp5_perform_des3':
> include/uapi/linux/byteorder/big_endian.h:32:26: error: large integer
> implicitly truncated to unsigned type [-Werror=overflow]
>  #define __cpu_to_le32(x) ((__force __le32)__swab32((x)))
>                           ^
> include/linux/byteorder/generic.h:87:21: note: in expansion of macro
> '__cpu_to_le32'
>  #define cpu_to_le32 __cpu_to_le32
>                      ^~~~~~~~~~~~~
> drivers/crypto/ccp/ccp-dev-v5.c:436:28: note: in expansion of macro
> 'cpu_to_le32'
>   CCP5_CMD_KEY_MEM(&desc) = cpu_to_le32(CCP_MEMTYPE_SB);
>
> The warning is correct, doing a 32-bit byte swap on a value that gets
> assigned into a bit field cannot work, since we would only write zeroes
> in this case, regardless of the input.

Yes, this was all wrong.

> In fact, the use of bit fields in hardware defined data structures is
> not portable to start with, so until all these bit fields get replaced
> by something else, the driver cannot work on big-endian machines, and
> I'm adding an annotation here to prevent it from being selected.

This is a driver that talks to hardware, a device which, AFAIK, has no
plan to be implemented in a big endian flavor. I clearly need to be more
diligent in building with various checkers enabled. I'd prefer my fix
over your suggested refusal to compile, if that's okay.

> The CCPv3 code seems to not suffer from this problem, only v5 uses
> bitfields.

Yes, I took a different approach when I wrote the code. IMO (arguably)
more readable. Same result: words full of hardware-dependent bit patterns.

Please help me understand what I could do better.
Arnd Bergmann March 28, 2017, 2:59 p.m. UTC | #2
On Tue, Mar 28, 2017 at 4:08 PM, Gary R Hook <ghook@amd.com> wrote:

>> In fact, the use of bit fields in hardware defined data structures is
>> not portable to start with, so until all these bit fields get replaced
>> by something else, the driver cannot work on big-endian machines, and
>> I'm adding an annotation here to prevent it from being selected.
>
>
> This is a driver that talks to hardware, a device which, AFAIK, has no
> plan to be implemented in a big endian flavor. I clearly need to be more
> diligent in building with various checkers enabled. I'd prefer my fix
> over your suggested refusal to compile, if that's okay.

It's hard to predict the future. If this device ever makes it into an
ARM based chip, the chances are relatively high that someone
will eventually run a big-endian kernel on it. As long as it's guaranteed
to be x86-only, the risk of anyone running into the bug is close to
zero, but we normally still try to write device drivers in portable C
code to prevent it from getting copied incorrectly into another driver.

>> The CCPv3 code seems to not suffer from this problem, only v5 uses
>> bitfields.
>
>
> Yes, I took a different approach when I wrote the code. IMO (arguably)
> more readable. Same result: words full of hardware-dependent bit patterns.
>
> Please help me understand what I could do better.

The rule for portable drivers is that you must not use bitfields in structures
that can be accessed by the hardware. I think you can do this in a more
readable way by removing the CCP5_CMD_* macros etc completely
and just accessing the members of the structure as __le32 words.
The main advantage for readability here is that you can grep for the
struct members and see where they are used without following the
macros. If it helps, you can also encapsulate the generation of the
word inside of an inline function, like:

static inline __le32 ccp5_cmd_dw0(bool soc, bool ioc, bool init, bool
eom, u32 engine)
{
        u32 dw0 = (soc  ? CCP5_WORD0_SOC  : 0)  |
                  (ioc  ? CCP5_WORD0_IOC  : 0)  |
                  (init ? CCP5_WORD0_INIT : 0)  |
                  (eom  ? CCP5_WORD0_EOM  : 0)  |
                CCP5_WORD0_ENGINE(engine);

        return __cpu_to_le32(dw0);
}

...
desc->dw0 = ccp5_cmd_dw0(op->soc, 0, op->init, op->oem, op->engine);

       Arnd
Gary R Hook March 28, 2017, 3:26 p.m. UTC | #3
On 03/28/2017 09:59 AM, Arnd Bergmann wrote:
> On Tue, Mar 28, 2017 at 4:08 PM, Gary R Hook <ghook@amd.com> wrote:
>
>>> In fact, the use of bit fields in hardware defined data structures is
>>> not portable to start with, so until all these bit fields get replaced
>>> by something else, the driver cannot work on big-endian machines, and
>>> I'm adding an annotation here to prevent it from being selected.
>>
>>
>> This is a driver that talks to hardware, a device which, AFAIK, has no
>> plan to be implemented in a big endian flavor. I clearly need to be more
>> diligent in building with various checkers enabled. I'd prefer my fix
>> over your suggested refusal to compile, if that's okay.
>
> It's hard to predict the future. If this device ever makes it into an
> ARM based chip, the chances are relatively high that someone
> will eventually run a big-endian kernel on it. As long as it's guaranteed
> to be x86-only, the risk of anyone running into the bug is close to
> zero, but we normally still try to write device drivers in portable C
> code to prevent it from getting copied incorrectly into another driver.

Understood, and I had surmised as such. Totally agree.

>>> The CCPv3 code seems to not suffer from this problem, only v5 uses
>>> bitfields.
>>
>>
>> Yes, I took a different approach when I wrote the code. IMO (arguably)
>> more readable. Same result: words full of hardware-dependent bit patterns.
>>
>> Please help me understand what I could do better.
>
> The rule for portable drivers is that you must not use bitfields in
> structures
> that can be accessed by the hardware. I think you can do this in a more
> readable way by removing the CCP5_CMD_* macros etc completely
> and just accessing the members of the structure as __le32 words.
> The main advantage for readability here is that you can grep for the
> struct members and see where they are used without following the
> macros. If it helps, you can also encapsulate the generation of the
> word inside of an inline function, like:
>

Please see my follow-on patch.
diff mbox

Patch

diff --git a/drivers/crypto/ccp/Kconfig b/drivers/crypto/ccp/Kconfig
index 2238f77aa248..07af9ece84f9 100644
--- a/drivers/crypto/ccp/Kconfig
+++ b/drivers/crypto/ccp/Kconfig
@@ -1,6 +1,7 @@ 
 config CRYPTO_DEV_CCP_DD
 	tristate "Cryptographic Coprocessor device driver"
 	depends on CRYPTO_DEV_CCP
+	depends on !CPU_BIG_ENDIAN || BROKEN
 	default m
 	select HW_RANDOM
 	select DMA_ENGINE