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

x86/uaccess: utilize CONFIG_CC_HAS_ASM_GOTO_OUTPUT

Clang-11 shipped support for outputs to asm goto statments along the
fallthrough path. Double up some of the get_user() and related macros
to be able to take advantage of this extended GNU C extension. This
should help improve the generated code's performance for these accesses.

Cc: Bill Wendling <morbo@google.com>
Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Nick Desaulniers <ndesaulniers@google.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

authored by

Nick Desaulniers and committed by
Linus Torvalds
865c50e1 d55564cf

+66
+66
arch/x86/include/asm/uaccess.h
··· 310 310 } \ 311 311 } while (0) 312 312 313 + #ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT 314 + 315 + #ifdef CONFIG_X86_32 316 + #define __get_user_asm_u64(x, ptr, label) do { \ 317 + unsigned int __gu_low, __gu_high; \ 318 + const unsigned int __user *__gu_ptr; \ 319 + __gu_ptr = (const void __user *)(ptr); \ 320 + __get_user_asm(__gu_low, ptr, "l", "=r", label); \ 321 + __get_user_asm(__gu_high, ptr+1, "l", "=r", label); \ 322 + (x) = ((unsigned long long)__gu_high << 32) | __gu_low; \ 323 + } while (0) 324 + #else 325 + #define __get_user_asm_u64(x, ptr, label) \ 326 + __get_user_asm(x, ptr, "q", "=r", label) 327 + #endif 328 + 329 + #define __get_user_size(x, ptr, size, label) \ 330 + do { \ 331 + __chk_user_ptr(ptr); \ 332 + switch (size) { \ 333 + unsigned char x_u8__; \ 334 + case 1: \ 335 + __get_user_asm(x_u8__, ptr, "b", "=q", label); \ 336 + (x) = x_u8__; \ 337 + break; \ 338 + case 2: \ 339 + __get_user_asm(x, ptr, "w", "=r", label); \ 340 + break; \ 341 + case 4: \ 342 + __get_user_asm(x, ptr, "l", "=r", label); \ 343 + break; \ 344 + case 8: \ 345 + __get_user_asm_u64(x, ptr, label); \ 346 + break; \ 347 + default: \ 348 + (x) = __get_user_bad(); \ 349 + } \ 350 + } while (0) 351 + 352 + #define __get_user_asm(x, addr, itype, ltype, label) \ 353 + asm_volatile_goto("\n" \ 354 + "1: mov"itype" %[umem],%[output]\n" \ 355 + _ASM_EXTABLE_UA(1b, %l2) \ 356 + : [output] ltype(x) \ 357 + : [umem] "m" (__m(addr)) \ 358 + : : label) 359 + 360 + #else // !CONFIG_CC_HAS_ASM_GOTO_OUTPUT 361 + 313 362 #ifdef CONFIG_X86_32 314 363 #define __get_user_asm_u64(x, ptr, retval) \ 315 364 ({ \ ··· 426 377 [output] ltype(x) \ 427 378 : [umem] "m" (__m(addr)), \ 428 379 [efault] "i" (-EFAULT), "0" (err)) 380 + 381 + #endif // CONFIG_CC_ASM_GOTO_OUTPUT 429 382 430 383 /* FIXME: this hack is definitely wrong -AK */ 431 384 struct __large_struct { unsigned long buf[100]; }; ··· 503 452 #define unsafe_put_user(x, ptr, label) \ 504 453 __put_user_size((__typeof__(*(ptr)))(x), (ptr), sizeof(*(ptr)), label) 505 454 455 + #ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT 456 + #define unsafe_get_user(x, ptr, err_label) \ 457 + do { \ 458 + __inttype(*(ptr)) __gu_val; \ 459 + __get_user_size(__gu_val, (ptr), sizeof(*(ptr)), err_label); \ 460 + (x) = (__force __typeof__(*(ptr)))__gu_val; \ 461 + } while (0) 462 + #else // !CONFIG_CC_HAS_ASM_GOTO_OUTPUT 506 463 #define unsafe_get_user(x, ptr, err_label) \ 507 464 do { \ 508 465 int __gu_err; \ ··· 519 460 (x) = (__force __typeof__(*(ptr)))__gu_val; \ 520 461 if (unlikely(__gu_err)) goto err_label; \ 521 462 } while (0) 463 + #endif // CONFIG_CC_HAS_ASM_GOTO_OUTPUT 522 464 523 465 /* 524 466 * We want the unsafe accessors to always be inlined and use ··· 546 486 547 487 #define HAVE_GET_KERNEL_NOFAULT 548 488 489 + #ifdef CONFIG_CC_HAS_ASM_GOTO_OUTPUT 490 + #define __get_kernel_nofault(dst, src, type, err_label) \ 491 + __get_user_size(*((type *)(dst)), (__force type __user *)(src), \ 492 + sizeof(type), err_label) 493 + #else // !CONFIG_CC_HAS_ASM_GOTO_OUTPUT 549 494 #define __get_kernel_nofault(dst, src, type, err_label) \ 550 495 do { \ 551 496 int __kr_err; \ ··· 560 495 if (unlikely(__kr_err)) \ 561 496 goto err_label; \ 562 497 } while (0) 498 + #endif // CONFIG_CC_HAS_ASM_GOTO_OUTPUT 563 499 564 500 #define __put_kernel_nofault(dst, src, type, err_label) \ 565 501 __put_user_size(*((type *)(src)), (__force type __user *)(dst), \