@@ -390,4 +390,212 @@ do { \
390390 goto err_label; \
391391} while (0)
392392
393+ void __cmpxchg_user_key_called_with_bad_pointer (void );
394+
395+ #define CMPXCHG_USER_KEY_MAX_LOOPS 128
396+
397+ static __always_inline int __cmpxchg_user_key (unsigned long address , void * uval ,
398+ __uint128_t old , __uint128_t new ,
399+ unsigned long key , int size )
400+ {
401+ int rc = 0 ;
402+
403+ switch (size ) {
404+ case 1 : {
405+ unsigned int prev , shift , mask , _old , _new ;
406+ unsigned long count ;
407+
408+ shift = (3 ^ (address & 3 )) << 3 ;
409+ address ^= address & 3 ;
410+ _old = ((unsigned int )old & 0xff ) << shift ;
411+ _new = ((unsigned int )new & 0xff ) << shift ;
412+ mask = ~(0xff << shift );
413+ asm volatile (
414+ " spka 0(%[key])\n"
415+ " sacf 256\n"
416+ " llill %[count],%[max_loops]\n"
417+ "0: l %[prev],%[address]\n"
418+ "1: nr %[prev],%[mask]\n"
419+ " xilf %[mask],0xffffffff\n"
420+ " or %[new],%[prev]\n"
421+ " or %[prev],%[tmp]\n"
422+ "2: lr %[tmp],%[prev]\n"
423+ "3: cs %[prev],%[new],%[address]\n"
424+ "4: jnl 5f\n"
425+ " xr %[tmp],%[prev]\n"
426+ " xr %[new],%[tmp]\n"
427+ " nr %[tmp],%[mask]\n"
428+ " jnz 5f\n"
429+ " brct %[count],2b\n"
430+ "5: sacf 768\n"
431+ " spka %[default_key]\n"
432+ EX_TABLE_UA_LOAD_REG (0b , 5b , %[rc ], %[prev ])
433+ EX_TABLE_UA_LOAD_REG (1b , 5b , %[rc ], %[prev ])
434+ EX_TABLE_UA_LOAD_REG (3b , 5b , %[rc ], %[prev ])
435+ EX_TABLE_UA_LOAD_REG (4b , 5b , %[rc ], %[prev ])
436+ : [rc ] "+ & d " (rc),
437+ [prev ] "= & d " (prev),
438+ [address ] "+ Q " (*(int *)address),
439+ [tmp ] "+ & d " (_old),
440+ [new ] "+ & d " (_new),
441+ [mask ] "+ & d " (mask),
442+ [count ] "= a " (count)
443+ : [key ] "%[count]" (key << 4 ),
444+ [default_key ] "J" (PAGE_DEFAULT_KEY ),
445+ [max_loops ] "J" (CMPXCHG_USER_KEY_MAX_LOOPS )
446+ : "memory ", " cc ");
447+ * (unsigned char * )uval = prev >> shift ;
448+ if (!count )
449+ rc = - EAGAIN ;
450+ return rc ;
451+ }
452+ case 2 : {
453+ unsigned int prev , shift , mask , _old , _new ;
454+ unsigned long count ;
455+
456+ shift = (2 ^ (address & 2 )) << 3 ;
457+ address ^= address & 2 ;
458+ _old = ((unsigned int )old & 0xffff ) << shift ;
459+ _new = ((unsigned int )new & 0xffff ) << shift ;
460+ mask = ~(0xffff << shift );
461+ asm volatile (
462+ " spka 0(%[key])\n"
463+ " sacf 256\n"
464+ " llill %[count],%[max_loops]\n"
465+ "0: l %[prev],%[address]\n"
466+ "1: nr %[prev],%[mask]\n"
467+ " xilf %[mask],0xffffffff\n"
468+ " or %[new],%[prev]\n"
469+ " or %[prev],%[tmp]\n"
470+ "2: lr %[tmp],%[prev]\n"
471+ "3: cs %[prev],%[new],%[address]\n"
472+ "4: jnl 5f\n"
473+ " xr %[tmp],%[prev]\n"
474+ " xr %[new],%[tmp]\n"
475+ " nr %[tmp],%[mask]\n"
476+ " jnz 5f\n"
477+ " brct %[count],2b\n"
478+ "5: sacf 768\n"
479+ " spka %[default_key]\n"
480+ EX_TABLE_UA_LOAD_REG (0b , 5b , %[rc ], %[prev ])
481+ EX_TABLE_UA_LOAD_REG (1b , 5b , %[rc ], %[prev ])
482+ EX_TABLE_UA_LOAD_REG (3b , 5b , %[rc ], %[prev ])
483+ EX_TABLE_UA_LOAD_REG (4b , 5b , %[rc ], %[prev ])
484+ : [rc ] "+ & d " (rc),
485+ [prev ] "= & d " (prev),
486+ [address ] "+ Q " (*(int *)address),
487+ [tmp ] "+ & d " (_old),
488+ [new ] "+ & d " (_new),
489+ [mask ] "+ & d " (mask),
490+ [count ] "= a " (count)
491+ : [key ] "%[count]" (key << 4 ),
492+ [default_key ] "J" (PAGE_DEFAULT_KEY ),
493+ [max_loops ] "J" (CMPXCHG_USER_KEY_MAX_LOOPS )
494+ : "memory ", " cc ");
495+ * (unsigned short * )uval = prev >> shift ;
496+ if (!count )
497+ rc = - EAGAIN ;
498+ return rc ;
499+ }
500+ case 4 : {
501+ unsigned int prev = old ;
502+
503+ asm volatile (
504+ " spka 0(%[key])\n"
505+ " sacf 256\n"
506+ "0: cs %[prev],%[new],%[address]\n"
507+ "1: sacf 768\n"
508+ " spka %[default_key]\n"
509+ EX_TABLE_UA_LOAD_REG (0b , 1b , %[rc ], %[prev ])
510+ EX_TABLE_UA_LOAD_REG (1b , 1b , %[rc ], %[prev ])
511+ : [rc ] "+ & d " (rc),
512+ [prev ] "+ & d " (prev),
513+ [address ] "+ Q " (*(int *)address)
514+ : [new ] "d" ((unsigned int )new ),
515+ [key ] "a" (key << 4 ),
516+ [default_key ] "J" (PAGE_DEFAULT_KEY )
517+ : "memory ", " cc ");
518+ * (unsigned int * )uval = prev ;
519+ return rc ;
520+ }
521+ case 8 : {
522+ unsigned long prev = old ;
523+
524+ asm volatile (
525+ " spka 0(%[key])\n"
526+ " sacf 256\n"
527+ "0: csg %[prev],%[new],%[address]\n"
528+ "1: sacf 768\n"
529+ " spka %[default_key]\n"
530+ EX_TABLE_UA_LOAD_REG (0b , 1b , %[rc ], %[prev ])
531+ EX_TABLE_UA_LOAD_REG (1b , 1b , %[rc ], %[prev ])
532+ : [rc ] "+ & d " (rc),
533+ [prev ] "+ & d " (prev),
534+ [address ] "+ QS " (*(long *)address)
535+ : [new ] "d" ((unsigned long )new ),
536+ [key ] "a" (key << 4 ),
537+ [default_key ] "J" (PAGE_DEFAULT_KEY )
538+ : "memory ", " cc ");
539+ * (unsigned long * )uval = prev ;
540+ return rc ;
541+ }
542+ case 16 : {
543+ __uint128_t prev = old ;
544+
545+ asm volatile (
546+ " spka 0(%[key])\n"
547+ " sacf 256\n"
548+ "0: cdsg %[prev],%[new],%[address]\n"
549+ "1: sacf 768\n"
550+ " spka %[default_key]\n"
551+ EX_TABLE_UA_LOAD_REGPAIR (0b , 1b , %[rc ], %[prev ])
552+ EX_TABLE_UA_LOAD_REGPAIR (1b , 1b , %[rc ], %[prev ])
553+ : [rc ] "+ & d " (rc),
554+ [prev ] "+ & d " (prev),
555+ [address ] "+ QS " (*(__int128_t *)address)
556+ : [new ] "d" (new ),
557+ [key ] "a" (key << 4 ),
558+ [default_key ] "J" (PAGE_DEFAULT_KEY )
559+ : "memory ", " cc ");
560+ * (__uint128_t * )uval = prev ;
561+ return rc ;
562+ }
563+ }
564+ __cmpxchg_user_key_called_with_bad_pointer ();
565+ return rc ;
566+ }
567+
568+ /**
569+ * cmpxchg_user_key() - cmpxchg with user space target, honoring storage keys
570+ * @ptr: User space address of value to compare to @old and exchange with
571+ * @new. Must be aligned to sizeof(*@ptr).
572+ * @uval: Address where the old value of *@ptr is written to.
573+ * @old: Old value. Compared to the content pointed to by @ptr in order to
574+ * determine if the exchange occurs. The old value read from *@ptr is
575+ * written to *@uval.
576+ * @new: New value to place at *@ptr.
577+ * @key: Access key to use for checking storage key protection.
578+ *
579+ * Perform a cmpxchg on a user space target, honoring storage key protection.
580+ * @key alone determines how key checking is performed, neither
581+ * storage-protection-override nor fetch-protection-override apply.
582+ * The caller must compare *@uval and @old to determine if values have been
583+ * exchanged. In case of an exception *@uval is set to zero.
584+ *
585+ * Return: 0: cmpxchg executed
586+ * -EFAULT: an exception happened when trying to access *@ptr
587+ * -EAGAIN: maxed out number of retries (byte and short only)
588+ */
589+ #define cmpxchg_user_key (ptr , uval , old , new , key ) \
590+ ({ \
591+ __typeof__(ptr) __ptr = (ptr); \
592+ __typeof__(uval) __uval = (uval); \
593+ \
594+ BUILD_BUG_ON(sizeof(*(__ptr)) != sizeof(*(__uval))); \
595+ might_fault(); \
596+ __chk_user_ptr(__ptr); \
597+ __cmpxchg_user_key((unsigned long)(__ptr), (void *)(__uval), \
598+ (old), (new), (key), sizeof(*(__ptr))); \
599+ })
600+
393601#endif /* __S390_UACCESS_H */
0 commit comments