diff mbox series

[02/12] powerpc/pseries: Restructure hvc_get_chars() endianness

Message ID 20231011053711.93427-3-bgray@linux.ibm.com (mailing list archive)
State New
Headers show
Series Miscellaneous Sparse fixes | expand

Commit Message

Benjamin Gray Oct. 11, 2023, 5:37 a.m. UTC
Sparse reports an endian mismatch in hvc_get_chars().

At first it seemed like the retbuf should be __be64[], but actually
retbuf holds serialized registers returned by the hypervisor call, so
it's correctly CPU endian typed.

Instead, it is the be64_to_cpu() that's misleading. The intent is to do
a byte swap on a little endian CPU. The swap is required because we
wanted to store the register values to memory without 'swapping' bytes,
so that the high order byte of the first register is the first byte
in the result buffer.

In diagram form, on a LE CPU with the letters representing the return
string bytes:

    (register bytes) A B C D E F G H   I J K L M N O P
  (retbuf mem bytes) H G F E D C B A   P O N M L K J I
(buf/lbuf mem bytes) A B C D E F G H   I J K L M N O P

So retbuf stores the registers in CPU endian, and buf always stores in
big endian.

So replace the byte swap function with cpu_to_be64() and cast lbuf as an
array of __be64 to match the semantics closer.

Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
---
 arch/powerpc/platforms/pseries/hvconsole.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

Comments

Aneesh Kumar K V Oct. 30, 2023, 1:16 p.m. UTC | #1
Benjamin Gray <bgray@linux.ibm.com> writes:

> Sparse reports an endian mismatch in hvc_get_chars().
>
> At first it seemed like the retbuf should be __be64[], but actually
> retbuf holds serialized registers returned by the hypervisor call, so
> it's correctly CPU endian typed.
>
> Instead, it is the be64_to_cpu() that's misleading. The intent is to do
> a byte swap on a little endian CPU. The swap is required because we
> wanted to store the register values to memory without 'swapping' bytes,
> so that the high order byte of the first register is the first byte
> in the result buffer.
>
> In diagram form, on a LE CPU with the letters representing the return
> string bytes:
>
>     (register bytes) A B C D E F G H   I J K L M N O P
>   (retbuf mem bytes) H G F E D C B A   P O N M L K J I
> (buf/lbuf mem bytes) A B C D E F G H   I J K L M N O P
>
> So retbuf stores the registers in CPU endian, and buf always stores in
> big endian.
>
> So replace the byte swap function with cpu_to_be64() and cast lbuf as an
> array of __be64 to match the semantics closer.
>
> Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
> ---
>  arch/powerpc/platforms/pseries/hvconsole.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c
> index 1ac52963e08b..647718a15e78 100644
> --- a/arch/powerpc/platforms/pseries/hvconsole.c
> +++ b/arch/powerpc/platforms/pseries/hvconsole.c
> @@ -29,11 +29,11 @@ int hvc_get_chars(uint32_t vtermno, char *buf, int count)
>  {
>  	long ret;
>  	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
> -	unsigned long *lbuf = (unsigned long *)buf;
> +	__be64 *lbuf = (__be64 __force *)buf;
>  
>  	ret = plpar_hcall(H_GET_TERM_CHAR, retbuf, vtermno);
> -	lbuf[0] = be64_to_cpu(retbuf[1]);
> -	lbuf[1] = be64_to_cpu(retbuf[2]);
> +	lbuf[0] = cpu_to_be64(retbuf[1]);
> +	lbuf[1] = cpu_to_be64(retbuf[2]);
>  
>  	if (ret == H_SUCCESS)
>  		return retbuf[0];
>

There is no functionality change in this patch. It is clarifying the
details that it expect the buf to have the big-endian format and retbuf
contains native endian format.

Not sure why this was not picked.

Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
Christophe Leroy Feb. 20, 2024, 7:10 a.m. UTC | #2
Michael ? Any reason for not picking that one ?

Le 30/10/2023 à 14:16, Aneesh Kumar K.V a écrit :
> Benjamin Gray <bgray@linux.ibm.com> writes:
> 
>> Sparse reports an endian mismatch in hvc_get_chars().
>>
>> At first it seemed like the retbuf should be __be64[], but actually
>> retbuf holds serialized registers returned by the hypervisor call, so
>> it's correctly CPU endian typed.
>>
>> Instead, it is the be64_to_cpu() that's misleading. The intent is to do
>> a byte swap on a little endian CPU. The swap is required because we
>> wanted to store the register values to memory without 'swapping' bytes,
>> so that the high order byte of the first register is the first byte
>> in the result buffer.
>>
>> In diagram form, on a LE CPU with the letters representing the return
>> string bytes:
>>
>>      (register bytes) A B C D E F G H   I J K L M N O P
>>    (retbuf mem bytes) H G F E D C B A   P O N M L K J I
>> (buf/lbuf mem bytes) A B C D E F G H   I J K L M N O P
>>
>> So retbuf stores the registers in CPU endian, and buf always stores in
>> big endian.
>>
>> So replace the byte swap function with cpu_to_be64() and cast lbuf as an
>> array of __be64 to match the semantics closer.
>>
>> Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
>> ---
>>   arch/powerpc/platforms/pseries/hvconsole.c | 6 +++---
>>   1 file changed, 3 insertions(+), 3 deletions(-)
>>
>> diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c
>> index 1ac52963e08b..647718a15e78 100644
>> --- a/arch/powerpc/platforms/pseries/hvconsole.c
>> +++ b/arch/powerpc/platforms/pseries/hvconsole.c
>> @@ -29,11 +29,11 @@ int hvc_get_chars(uint32_t vtermno, char *buf, int count)
>>   {
>>   	long ret;
>>   	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
>> -	unsigned long *lbuf = (unsigned long *)buf;
>> +	__be64 *lbuf = (__be64 __force *)buf;
>>   
>>   	ret = plpar_hcall(H_GET_TERM_CHAR, retbuf, vtermno);
>> -	lbuf[0] = be64_to_cpu(retbuf[1]);
>> -	lbuf[1] = be64_to_cpu(retbuf[2]);
>> +	lbuf[0] = cpu_to_be64(retbuf[1]);
>> +	lbuf[1] = cpu_to_be64(retbuf[2]);
>>   
>>   	if (ret == H_SUCCESS)
>>   		return retbuf[0];
>>
> 
> There is no functionality change in this patch. It is clarifying the
> details that it expect the buf to have the big-endian format and retbuf
> contains native endian format.
> 
> Not sure why this was not picked.
> 
> Reviewed-by: Aneesh Kumar K.V <aneesh.kumar@linux.ibm.com>
diff mbox series

Patch

diff --git a/arch/powerpc/platforms/pseries/hvconsole.c b/arch/powerpc/platforms/pseries/hvconsole.c
index 1ac52963e08b..647718a15e78 100644
--- a/arch/powerpc/platforms/pseries/hvconsole.c
+++ b/arch/powerpc/platforms/pseries/hvconsole.c
@@ -29,11 +29,11 @@  int hvc_get_chars(uint32_t vtermno, char *buf, int count)
 {
 	long ret;
 	unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
-	unsigned long *lbuf = (unsigned long *)buf;
+	__be64 *lbuf = (__be64 __force *)buf;
 
 	ret = plpar_hcall(H_GET_TERM_CHAR, retbuf, vtermno);
-	lbuf[0] = be64_to_cpu(retbuf[1]);
-	lbuf[1] = be64_to_cpu(retbuf[2]);
+	lbuf[0] = cpu_to_be64(retbuf[1]);
+	lbuf[1] = cpu_to_be64(retbuf[2]);
 
 	if (ret == H_SUCCESS)
 		return retbuf[0];