Re: [PATCH v8 02/17] xen: introduce generic non-atomic test_*bit()

2024-05-06 Thread Jan Beulich
On 06.05.2024 10:16, Oleksii wrote:
> On Mon, 2024-05-06 at 08:33 +0200, Jan Beulich wrote:
>> On 03.05.2024 19:15, Oleksii wrote:
>>> On Thu, 2024-04-25 at 17:35 +0200, Jan Beulich wrote:
>   #include 
>   
> +#ifndef arch_check_bitop_size
> +#define arch_check_bitop_size(addr)

 Can this really do nothing? Passing the address of an object
 smaller
 than
 bitop_uint_t will read past the object in the generic__*_bit()
 functions.
>>> It seems RISC-V isn' happy with the following generic definition:
>>>    extern void __bitop_bad_size(void);
>>>    
>>>    /* - Please tidy above here 
>>> 
>>>    - */
>>>    
>>>    #include 
>>>    
>>>    #ifndef arch_check_bitop_size
>>>    
>>>    #define bitop_bad_size(addr) sizeof(*(addr)) <
>>> sizeof(bitop_uint_t)
>>>    
>>>    #define arch_check_bitop_size(addr) \
>>>    if ( bitop_bad_size(addr) ) __bitop_bad_size();
>>>    
>>>    #endif /* arch_check_bitop_size */
>>
>> I'm afraid you've re-discovered something that was also found during
>> the
>> original Arm porting effort. As nice and logical as it would (seem
>> to) be
>> to have bitop_uint_t match machine word size, there are places ...
>>
>>> The following errors occurs. bitop_uint_t for RISC-V is defined as
>>> unsigned long for now:
>>
>> ... where we assume such operations can be done on 32-bit quantities.
> Based on RISC-V spec machine word is 32-bit, so then I can just drop
> re-definition of bitop_uint_t in riscv/asm/types.h and use the
> definition of bitop_uint_t in xen/types.h.
> Also it will be needed to update __AMO() macros in /asm/bitops.h
> in the following way:
>#if BITOP_BITS_PER_WORD == 64
>#define __AMO(op)   "amo" #op ".d"
>#elif BITOP_BITS_PER_WORD == 32
>#define __AMO(op)   "amo" #op ".w"
>#else
>#error "Unexpected BITS_PER_LONG"
>#endif
> Note: BITS_PER_LONG was changed to BITOP_BITS_PER_WORD !
> 
> Only one question remains for me. Given that there are some operations 
> whichcan be performed on 32-bit quantities, it seems to me that bitop_uint_t
> can only be uint32_t.
> Am I correct? If yes, do we need to have ability to redefine
> bitop_uint_t and BITOP_BITS_PER_WORD in xen/types.h:
>#ifndef BITOP_TYPE
>#define BITOP_BITS_PER_WORD 32
>
>typedef uint32_t bitop_uint_t;
>#endif

Probably not, right now. Hence me having said "As nice and logical as it
would (seem to) be" in the earlier reply.

Jan



Re: [PATCH v8 02/17] xen: introduce generic non-atomic test_*bit()

2024-05-06 Thread Oleksii
On Mon, 2024-05-06 at 08:33 +0200, Jan Beulich wrote:
> On 03.05.2024 19:15, Oleksii wrote:
> > On Thu, 2024-04-25 at 17:35 +0200, Jan Beulich wrote:
> > > >   #include 
> > > >   
> > > > +#ifndef arch_check_bitop_size
> > > > +#define arch_check_bitop_size(addr)
> > > 
> > > Can this really do nothing? Passing the address of an object
> > > smaller
> > > than
> > > bitop_uint_t will read past the object in the generic__*_bit()
> > > functions.
> > It seems RISC-V isn' happy with the following generic definition:
> >    extern void __bitop_bad_size(void);
> >    
> >    /* - Please tidy above here 
> > 
> >    - */
> >    
> >    #include 
> >    
> >    #ifndef arch_check_bitop_size
> >    
> >    #define bitop_bad_size(addr) sizeof(*(addr)) <
> > sizeof(bitop_uint_t)
> >    
> >    #define arch_check_bitop_size(addr) \
> >    if ( bitop_bad_size(addr) ) __bitop_bad_size();
> >    
> >    #endif /* arch_check_bitop_size */
> 
> I'm afraid you've re-discovered something that was also found during
> the
> original Arm porting effort. As nice and logical as it would (seem
> to) be
> to have bitop_uint_t match machine word size, there are places ...
> 
> > The following errors occurs. bitop_uint_t for RISC-V is defined as
> > unsigned long for now:
> 
> ... where we assume such operations can be done on 32-bit quantities.
Based on RISC-V spec machine word is 32-bit, so then I can just drop
re-definition of bitop_uint_t in riscv/asm/types.h and use the
definition of bitop_uint_t in xen/types.h.
Also it will be needed to update __AMO() macros in /asm/bitops.h
in the following way:
   #if BITOP_BITS_PER_WORD == 64
   #define __AMO(op)   "amo" #op ".d"
   #elif BITOP_BITS_PER_WORD == 32
   #define __AMO(op)   "amo" #op ".w"
   #else
   #error "Unexpected BITS_PER_LONG"
   #endif
Note: BITS_PER_LONG was changed to BITOP_BITS_PER_WORD !

Only one question remains for me. Given that there are some operations whichcan 
be performed on 32-bit quantities, it seems to me that bitop_uint_t
can only be uint32_t.
Am I correct? If yes, do we need to have ability to redefine
bitop_uint_t and BITOP_BITS_PER_WORD in xen/types.h:
   #ifndef BITOP_TYPE
   #define BITOP_BITS_PER_WORD 32
   
   typedef uint32_t bitop_uint_t;
   #endif

~ Oleksii

> 
> Jan
> 
> >     ./common/symbols-dummy.o -o ./.xen-syms.0
> > riscv64-linux-gnu-ld: prelink.o: in function `atomic_sub':
> > /build/xen/./arch/riscv/include/asm/atomic.h:152: undefined
> > reference
> > to `__bitop_bad_size'
> > riscv64-linux-gnu-ld: prelink.o: in function
> > `evtchn_check_pollers':
> > /build/xen/common/event_channel.c:1531: undefined reference to
> > `__bitop_bad_size'
> > riscv64-linux-gnu-ld: /build/xen/common/event_channel.c:1521:
> > undefined
> > reference to `__bitop_bad_size'
> > riscv64-linux-gnu-ld: prelink.o: in function `evtchn_init':
> > /build/xen/common/event_channel.c:1541: undefined reference to
> > `__bitop_bad_size'
> > riscv64-linux-gnu-ld: prelink.o: in function `_read_lock':
> > /build/xen/./include/xen/rwlock.h:94: undefined reference to
> > `__bitop_bad_size'
> > riscv64-linux-gnu-ld:
> > prelink.o:/build/xen/./arch/riscv/include/asm/atomic.h:195: more
> > undefined references to `__bitop_bad_size' follow
> > riscv64-linux-gnu-ld: ./.xen-syms.0: hidden symbol
> > `__bitop_bad_size'
> > isn't defined
> > riscv64-linux-gnu-ld: final link failed: bad value
> > make[2]: *** [arch/riscv/Makefile:15: xen-syms] Error 1
> > 
> > ~ Oleksii
> 





Re: [PATCH v8 02/17] xen: introduce generic non-atomic test_*bit()

2024-05-06 Thread Jan Beulich
On 03.05.2024 19:15, Oleksii wrote:
> On Thu, 2024-04-25 at 17:35 +0200, Jan Beulich wrote:
>>>   #include 
>>>   
>>> +#ifndef arch_check_bitop_size
>>> +#define arch_check_bitop_size(addr)
>>
>> Can this really do nothing? Passing the address of an object smaller
>> than
>> bitop_uint_t will read past the object in the generic__*_bit()
>> functions.
> It seems RISC-V isn' happy with the following generic definition:
>extern void __bitop_bad_size(void);
>
>/* - Please tidy above here 
>- */
>
>#include 
>
>#ifndef arch_check_bitop_size
>
>#define bitop_bad_size(addr) sizeof(*(addr)) < sizeof(bitop_uint_t)
>
>#define arch_check_bitop_size(addr) \
>if ( bitop_bad_size(addr) ) __bitop_bad_size();
>
>#endif /* arch_check_bitop_size */

I'm afraid you've re-discovered something that was also found during the
original Arm porting effort. As nice and logical as it would (seem to) be
to have bitop_uint_t match machine word size, there are places ...

> The following errors occurs. bitop_uint_t for RISC-V is defined as
> unsigned long for now:

... where we assume such operations can be done on 32-bit quantities.

Jan

> ./common/symbols-dummy.o -o ./.xen-syms.0
> riscv64-linux-gnu-ld: prelink.o: in function `atomic_sub':
> /build/xen/./arch/riscv/include/asm/atomic.h:152: undefined reference
> to `__bitop_bad_size'
> riscv64-linux-gnu-ld: prelink.o: in function `evtchn_check_pollers':
> /build/xen/common/event_channel.c:1531: undefined reference to
> `__bitop_bad_size'
> riscv64-linux-gnu-ld: /build/xen/common/event_channel.c:1521: undefined
> reference to `__bitop_bad_size'
> riscv64-linux-gnu-ld: prelink.o: in function `evtchn_init':
> /build/xen/common/event_channel.c:1541: undefined reference to
> `__bitop_bad_size'
> riscv64-linux-gnu-ld: prelink.o: in function `_read_lock':
> /build/xen/./include/xen/rwlock.h:94: undefined reference to
> `__bitop_bad_size'
> riscv64-linux-gnu-ld:
> prelink.o:/build/xen/./arch/riscv/include/asm/atomic.h:195: more
> undefined references to `__bitop_bad_size' follow
> riscv64-linux-gnu-ld: ./.xen-syms.0: hidden symbol `__bitop_bad_size'
> isn't defined
> riscv64-linux-gnu-ld: final link failed: bad value
> make[2]: *** [arch/riscv/Makefile:15: xen-syms] Error 1
> 
> ~ Oleksii




Re: [PATCH v8 02/17] xen: introduce generic non-atomic test_*bit()

2024-05-03 Thread Oleksii
On Thu, 2024-04-25 at 17:35 +0200, Jan Beulich wrote:
> >   #include 
> >   
> > +#ifndef arch_check_bitop_size
> > +#define arch_check_bitop_size(addr)
> 
> Can this really do nothing? Passing the address of an object smaller
> than
> bitop_uint_t will read past the object in the generic__*_bit()
> functions.
It seems RISC-V isn' happy with the following generic definition:
   extern void __bitop_bad_size(void);
   
   /* - Please tidy above here 
   - */
   
   #include 
   
   #ifndef arch_check_bitop_size
   
   #define bitop_bad_size(addr) sizeof(*(addr)) < sizeof(bitop_uint_t)
   
   #define arch_check_bitop_size(addr) \
   if ( bitop_bad_size(addr) ) __bitop_bad_size();
   
   #endif /* arch_check_bitop_size */

The following errors occurs. bitop_uint_t for RISC-V is defined as
unsigned long for now:
./common/symbols-dummy.o -o ./.xen-syms.0
riscv64-linux-gnu-ld: prelink.o: in function `atomic_sub':
/build/xen/./arch/riscv/include/asm/atomic.h:152: undefined reference
to `__bitop_bad_size'
riscv64-linux-gnu-ld: prelink.o: in function `evtchn_check_pollers':
/build/xen/common/event_channel.c:1531: undefined reference to
`__bitop_bad_size'
riscv64-linux-gnu-ld: /build/xen/common/event_channel.c:1521: undefined
reference to `__bitop_bad_size'
riscv64-linux-gnu-ld: prelink.o: in function `evtchn_init':
/build/xen/common/event_channel.c:1541: undefined reference to
`__bitop_bad_size'
riscv64-linux-gnu-ld: prelink.o: in function `_read_lock':
/build/xen/./include/xen/rwlock.h:94: undefined reference to
`__bitop_bad_size'
riscv64-linux-gnu-ld:
prelink.o:/build/xen/./arch/riscv/include/asm/atomic.h:195: more
undefined references to `__bitop_bad_size' follow
riscv64-linux-gnu-ld: ./.xen-syms.0: hidden symbol `__bitop_bad_size'
isn't defined
riscv64-linux-gnu-ld: final link failed: bad value
make[2]: *** [arch/riscv/Makefile:15: xen-syms] Error 1

~ Oleksii



Re: [PATCH v8 02/17] xen: introduce generic non-atomic test_*bit()

2024-04-26 Thread Jan Beulich
On 26.04.2024 10:14, Oleksii wrote:
> On Thu, 2024-04-25 at 17:35 +0200, Jan Beulich wrote:
>>>   /* - Please tidy above here -
>>>  */
>>>   
>>>   #include 
>>>   
>>> +#ifndef arch_check_bitop_size
>>> +#define arch_check_bitop_size(addr)
>>
>> Can this really do nothing? Passing the address of an object smaller
>> than
>> bitop_uint_t will read past the object in the generic__*_bit()
>> functions.
> Agree, in generic case it would be better to add:
> #define arch_check_bitop_size(addr) (sizeof(*(addr)) <
> sizeof(bitop_uint_t))

At which point x86 won't need any special casing anymore, I think.

Jan



Re: [PATCH v8 02/17] xen: introduce generic non-atomic test_*bit()

2024-04-26 Thread Oleksii
On Thu, 2024-04-25 at 17:35 +0200, Jan Beulich wrote:
> >   /* - Please tidy above here -
> >  */
> >   
> >   #include 
> >   
> > +#ifndef arch_check_bitop_size
> > +#define arch_check_bitop_size(addr)
> 
> Can this really do nothing? Passing the address of an object smaller
> than
> bitop_uint_t will read past the object in the generic__*_bit()
> functions.
Agree, in generic case it would be better to add:
#define arch_check_bitop_size(addr) (sizeof(*(addr)) <
sizeof(bitop_uint_t))

Originally, it was defined as empty becuase majority of supported
architectures by Xen don't do this check and I decided to use this
definition as generic.

Thanks.

~ Oleksii



Re: [PATCH v8 02/17] xen: introduce generic non-atomic test_*bit()

2024-04-25 Thread Jan Beulich
On 17.04.2024 12:04, Oleksii Kurochko wrote:
> --- a/xen/arch/ppc/include/asm/page.h
> +++ b/xen/arch/ppc/include/asm/page.h
> @@ -4,7 +4,7 @@
>  
>  #include 
>  
> -#include 
> +#include 
>  #include 

This wants to move up into the xen/*.h group then, like you have done ...

> --- a/xen/arch/ppc/mm-radix.c
> +++ b/xen/arch/ppc/mm-radix.c
> @@ -1,11 +1,11 @@
>  /* SPDX-License-Identifier: GPL-2.0-or-later */
> +#include 
>  #include 
>  #include 
>  #include 
>  #include 
>  #include 
>  
> -#include 
>  #include 
>  #include 
>  #include 

.. e.g. here.

> --- a/xen/include/xen/bitops.h
> +++ b/xen/include/xen/bitops.h
> @@ -65,10 +65,137 @@ static inline int generic_flsl(unsigned long x)
>   * scope
>   */
>  
> +#define BITOP_MASK(nr)  ((bitop_uint_t)1 << ((nr) % BITOP_BITS_PER_WORD))
> +
> +#define BITOP_WORD(nr)  ((nr) / BITOP_BITS_PER_WORD)
> +
>  /* - Please tidy above here - */
>  
>  #include 
>  
> +#ifndef arch_check_bitop_size
> +#define arch_check_bitop_size(addr)

Can this really do nothing? Passing the address of an object smaller than
bitop_uint_t will read past the object in the generic__*_bit() functions.

> +#endif
> +
> +/**
> + * generic__test_and_set_bit - Set a bit and return its old value
> + * @nr: Bit to set
> + * @addr: Address to count from
> + *
> + * This operation is non-atomic and can be reordered.
> + * If two examples of this operation race, one can appear to succeed
> + * but actually fail.  You must protect multiple accesses with a lock.
> + */
> +static always_inline bool
> +generic__test_and_set_bit(unsigned long nr, volatile void *addr)
> +{
> +bitop_uint_t mask = BITOP_MASK(nr);
> +volatile bitop_uint_t *p = ((volatile bitop_uint_t *)addr) + 
> BITOP_WORD(nr);

The revision log suggests excess parentheses were dropped from such cast
expressions.

> --- a/xen/include/xen/types.h
> +++ b/xen/include/xen/types.h
> @@ -64,6 +64,11 @@ typedef __u64 __be64;
>  
>  typedef unsigned int __attribute__((__mode__(__pointer__))) uintptr_t;
>  
> +#ifndef BITOP_TYPE
> +#define BITOP_BITS_PER_WORD 32
> +typedef uint32_t bitop_uint_t;

Personally I find this indentation odd / misleading. For pre-processor
directives the # preferrably remains first on a line (as was iirc
demanded by earlier C standards), followed by one or more blanks if so
desired. File-scope declarations imo should never be indented.

Jan



[PATCH v8 02/17] xen: introduce generic non-atomic test_*bit()

2024-04-17 Thread Oleksii Kurochko
The following generic functions were introduced:
* test_bit
* generic__test_and_set_bit
* generic__test_and_clear_bit
* generic__test_and_change_bit

Also, the patch introduces the following generics which are
used by the functions mentioned above:
* BITOP_BITS_PER_WORD
* BITOP_MASK
* BITOP_WORD
* BITOP_TYPE

These functions and macros can be useful for architectures
that don't have corresponding arch-specific instructions.

Because of that x86 has the following check in the macros test_bit(),
__test_and_set_bit(), __test_and_clear_bit(), __test_and_change_bit():
if ( bitop_bad_size(addr) ) __bitop_bad_size();
It was necessary to make bitop bad size check generic too, so
arch_check_bitop_size() was introduced and defined as empty for other
architectures except x86.

Signed-off-by: Oleksii Kurochko 
---
   The context ("* Find First Set bit.  Bits are labelled from 1." in 
xen/bitops.h )
   suggests there's a dependency on an uncommitted patch. It happens becuase 
the current patch
   series is based on Andrew's patch series ( 
https://lore.kernel.org/xen-devel/20240313172716.2325427-1-andrew.coop...@citrix.com/T/#t
 ),
   but if everything is okay with the current one patch it can be merged 
without Andrew's patch series being merged.
---
 Changes in V8:
  - drop __pure for function which uses volatile.
  - drop unnessary () in generic__test_and_change_bit() for addr casting.
  - update prototype of generic_test_bit() and test_bit(): now it returns bool
instead of int.
  - update generic_test_bit() to use BITOP_MASK().
  - Deal with fls{l} changes: it should be in the patch with introduced generic 
fls{l}.
  - add a footer with explanation of dependency on an uncommitted patch after 
Signed-off.
  - abstract bitop_size().
  - move BITOP_TYPE define to .
---
 Changes in V7:
  - move everything to xen/bitops.h to follow the same approach for all generic
bit ops.
  - put together BITOP_BITS_PER_WORD and bitops_uint_t.
  - make BITOP_MASK more generic.
  - drop #ifdef ... #endif around BITOP_MASK, BITOP_WORD as they are generic
enough.
  - drop "_" for generic__{test_and_set_bit,...}().
  - drop " != 0" for functions which return bool.
  - add volatile during the cast for generic__{...}().
  - update the commit message.
  - update arch related code to follow the proposed generic approach.
---
 Changes in V6:
  - Nothing changed ( only rebase )
---
 Changes in V5:
   - new patch
---
 xen/arch/arm/arm64/livepatch.c|   1 -
 xen/arch/arm/include/asm/bitops.h |  67 
 xen/arch/ppc/include/asm/bitops.h |  52 
 xen/arch/ppc/include/asm/page.h   |   2 +-
 xen/arch/ppc/mm-radix.c   |   2 +-
 xen/arch/x86/include/asm/bitops.h |  30 +++
 xen/include/xen/bitops.h  | 127 ++
 xen/include/xen/types.h   |   5 ++
 8 files changed, 145 insertions(+), 141 deletions(-)

diff --git a/xen/arch/arm/arm64/livepatch.c b/xen/arch/arm/arm64/livepatch.c
index df2cebedde..4bc8ed9be5 100644
--- a/xen/arch/arm/arm64/livepatch.c
+++ b/xen/arch/arm/arm64/livepatch.c
@@ -10,7 +10,6 @@
 #include 
 #include 
 
-#include 
 #include 
 #include 
 #include 
diff --git a/xen/arch/arm/include/asm/bitops.h 
b/xen/arch/arm/include/asm/bitops.h
index 5104334e48..8e16335e76 100644
--- a/xen/arch/arm/include/asm/bitops.h
+++ b/xen/arch/arm/include/asm/bitops.h
@@ -22,9 +22,6 @@
 #define __set_bit(n,p)set_bit(n,p)
 #define __clear_bit(n,p)  clear_bit(n,p)
 
-#define BITOP_BITS_PER_WORD 32
-#define BITOP_MASK(nr)  (1UL << ((nr) % BITOP_BITS_PER_WORD))
-#define BITOP_WORD(nr)  ((nr) / BITOP_BITS_PER_WORD)
 #define BITS_PER_BYTE   8
 
 #define ADDR (*(volatile int *) addr)
@@ -76,70 +73,6 @@ bool test_and_change_bit_timeout(int nr, volatile void *p,
 bool clear_mask16_timeout(uint16_t mask, volatile void *p,
   unsigned int max_try);
 
-/**
- * __test_and_set_bit - Set a bit and return its old value
- * @nr: Bit to set
- * @addr: Address to count from
- *
- * This operation is non-atomic and can be reordered.
- * If two examples of this operation race, one can appear to succeed
- * but actually fail.  You must protect multiple accesses with a lock.
- */
-static inline int __test_and_set_bit(int nr, volatile void *addr)
-{
-unsigned int mask = BITOP_MASK(nr);
-volatile unsigned int *p =
-((volatile unsigned int *)addr) + BITOP_WORD(nr);
-unsigned int old = *p;
-
-*p = old | mask;
-return (old & mask) != 0;
-}
-
-/**
- * __test_and_clear_bit - Clear a bit and return its old value
- * @nr: Bit to clear
- * @addr: Address to count from
- *
- * This operation is non-atomic and can be reordered.
- * If two examples of this operation race, one can appear to succeed
- * but actually fail.  You must protect multiple accesses with a lock.
- */
-static inline int __test_and_clear_bit(int nr, volatile void *addr)
-{
-unsigned int mask =