forked from Minki/linux
65ea11ec6a
The caller expects %rdi to remain intact, push+pop it make that happen.
Fixes the following kind of explosions on my core2duo machine when
trying to reboot or shut down:
general protection fault: 0000 [#1] PREEMPT SMP
Modules linked in: i915 i2c_algo_bit drm_kms_helper cfbfillrect syscopyarea cfbimgblt sysfillrect sysimgblt fb_sys_fops cfbcopyarea drm netconsole configfs binfmt_misc iTCO_wdt psmouse pcspkr snd_hda_codec_idt e100 coretemp hwmon snd_hda_codec_generic i2c_i801 mii i2c_smbus lpc_ich mfd_core snd_hda_intel uhci_hcd snd_hda_codec snd_hwdep snd_hda_core ehci_pci 8250 ehci_hcd snd_pcm 8250_base usbcore evdev serial_core usb_common parport_pc parport snd_timer snd soundcore
CPU: 0 PID: 3070 Comm: reboot Not tainted 4.8.0-rc1-perf-dirty #69
Hardware name: /D946GZIS, BIOS TS94610J.86A.0087.2007.1107.1049 11/07/2007
task: ffff88012a0b4080 task.stack: ffff880123850000
RIP: 0010:[<ffffffff81003c92>] [<ffffffff81003c92>] x86_perf_event_update+0x52/0xc0
RSP: 0018:ffff880123853b60 EFLAGS: 00010087
RAX: 0000000000000001 RBX: ffff88012fc0a3c0 RCX: 000000000000001e
RDX: 0000000000000000 RSI: 0000000040000000 RDI: ffff88012b014800
RBP: ffff880123853b88 R08: ffffffffffffffff R09: 0000000000000000
R10: ffffea0004a012c0 R11: ffffea0004acedc0 R12: ffffffff80000001
R13: ffff88012b0149c0 R14: ffff88012b014800 R15: 0000000000000018
FS: 00007f8b155cd700(0000) GS:ffff88012fc00000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 00007f8b155f5000 CR3: 000000012a2d7000 CR4: 00000000000006f0
Stack:
ffff88012fc0a3c0 ffff88012b014800 0000000000000004 0000000000000001
ffff88012fc1b750 ffff880123853bb0 ffffffff81003d59 ffff88012b014800
ffff88012fc0a3c0 ffff88012b014800 ffff880123853bd8 ffffffff81003e13
Call Trace:
[<ffffffff81003d59>] x86_pmu_stop+0x59/0xd0
[<ffffffff81003e13>] x86_pmu_del+0x43/0x140
[<ffffffff8111705d>] event_sched_out.isra.105+0xbd/0x260
[<ffffffff8111738d>] __perf_remove_from_context+0x2d/0xb0
[<ffffffff8111745d>] __perf_event_exit_context+0x4d/0x70
[<ffffffff810c8826>] generic_exec_single+0xb6/0x140
[<ffffffff81117410>] ? __perf_remove_from_context+0xb0/0xb0
[<ffffffff81117410>] ? __perf_remove_from_context+0xb0/0xb0
[<ffffffff810c898f>] smp_call_function_single+0xdf/0x140
[<ffffffff81113d27>] perf_event_exit_cpu_context+0x87/0xc0
[<ffffffff81113d73>] perf_reboot+0x13/0x40
[<ffffffff8107578a>] notifier_call_chain+0x4a/0x70
[<ffffffff81075ad7>] __blocking_notifier_call_chain+0x47/0x60
[<ffffffff81075b06>] blocking_notifier_call_chain+0x16/0x20
[<ffffffff81076a1d>] kernel_restart_prepare+0x1d/0x40
[<ffffffff81076ae2>] kernel_restart+0x12/0x60
[<ffffffff81076d56>] SYSC_reboot+0xf6/0x1b0
[<ffffffff811a823c>] ? mntput_no_expire+0x2c/0x1b0
[<ffffffff811a83e4>] ? mntput+0x24/0x40
[<ffffffff811894fc>] ? __fput+0x16c/0x1e0
[<ffffffff811895ae>] ? ____fput+0xe/0x10
[<ffffffff81072fc3>] ? task_work_run+0x83/0xa0
[<ffffffff81001623>] ? exit_to_usermode_loop+0x53/0xc0
[<ffffffff8100105a>] ? trace_hardirqs_on_thunk+0x1a/0x1c
[<ffffffff81076e6e>] SyS_reboot+0xe/0x10
[<ffffffff814c4ba5>] entry_SYSCALL_64_fastpath+0x18/0xa3
Code: 7c 4c 8d af c0 01 00 00 49 89 fe eb 10 48 09 c2 4c 89 e0 49 0f b1 55 00 4c 39 e0 74 35 4d 8b a6 c0 01 00 00 41 8b 8e 60 01 00 00 <0f> 33 8b 35 6e 02 8c 00 48 c1 e2 20 85 f6 7e d2 48 89 d3 89 cf
RIP [<ffffffff81003c92>] x86_perf_event_update+0x52/0xc0
RSP <ffff880123853b60>
---[ end trace 7ec95181faf211be ]---
note: reboot[3070] exited with preempt_count 2
Cc: Borislav Petkov <bp@suse.de>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@kernel.org>
Fixes: f5967101e9
("x86/hweight: Get rid of the special calling convention")
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
80 lines
2.3 KiB
ArmAsm
80 lines
2.3 KiB
ArmAsm
#include <linux/linkage.h>
|
|
|
|
#include <asm/asm.h>
|
|
|
|
/*
|
|
* unsigned int __sw_hweight32(unsigned int w)
|
|
* %rdi: w
|
|
*/
|
|
ENTRY(__sw_hweight32)
|
|
|
|
#ifdef CONFIG_X86_64
|
|
movl %edi, %eax # w
|
|
#endif
|
|
__ASM_SIZE(push,) %__ASM_REG(dx)
|
|
movl %eax, %edx # w -> t
|
|
shrl %edx # t >>= 1
|
|
andl $0x55555555, %edx # t &= 0x55555555
|
|
subl %edx, %eax # w -= t
|
|
|
|
movl %eax, %edx # w -> t
|
|
shrl $2, %eax # w_tmp >>= 2
|
|
andl $0x33333333, %edx # t &= 0x33333333
|
|
andl $0x33333333, %eax # w_tmp &= 0x33333333
|
|
addl %edx, %eax # w = w_tmp + t
|
|
|
|
movl %eax, %edx # w -> t
|
|
shrl $4, %edx # t >>= 4
|
|
addl %edx, %eax # w_tmp += t
|
|
andl $0x0f0f0f0f, %eax # w_tmp &= 0x0f0f0f0f
|
|
imull $0x01010101, %eax, %eax # w_tmp *= 0x01010101
|
|
shrl $24, %eax # w = w_tmp >> 24
|
|
__ASM_SIZE(pop,) %__ASM_REG(dx)
|
|
ret
|
|
ENDPROC(__sw_hweight32)
|
|
|
|
ENTRY(__sw_hweight64)
|
|
#ifdef CONFIG_X86_64
|
|
pushq %rdi
|
|
pushq %rdx
|
|
|
|
movq %rdi, %rdx # w -> t
|
|
movabsq $0x5555555555555555, %rax
|
|
shrq %rdx # t >>= 1
|
|
andq %rdx, %rax # t &= 0x5555555555555555
|
|
movabsq $0x3333333333333333, %rdx
|
|
subq %rax, %rdi # w -= t
|
|
|
|
movq %rdi, %rax # w -> t
|
|
shrq $2, %rdi # w_tmp >>= 2
|
|
andq %rdx, %rax # t &= 0x3333333333333333
|
|
andq %rdi, %rdx # w_tmp &= 0x3333333333333333
|
|
addq %rdx, %rax # w = w_tmp + t
|
|
|
|
movq %rax, %rdx # w -> t
|
|
shrq $4, %rdx # t >>= 4
|
|
addq %rdx, %rax # w_tmp += t
|
|
movabsq $0x0f0f0f0f0f0f0f0f, %rdx
|
|
andq %rdx, %rax # w_tmp &= 0x0f0f0f0f0f0f0f0f
|
|
movabsq $0x0101010101010101, %rdx
|
|
imulq %rdx, %rax # w_tmp *= 0x0101010101010101
|
|
shrq $56, %rax # w = w_tmp >> 56
|
|
|
|
popq %rdx
|
|
popq %rdi
|
|
ret
|
|
#else /* CONFIG_X86_32 */
|
|
/* We're getting an u64 arg in (%eax,%edx): unsigned long hweight64(__u64 w) */
|
|
pushl %ecx
|
|
|
|
call __sw_hweight32
|
|
movl %eax, %ecx # stash away result
|
|
movl %edx, %eax # second part of input
|
|
call __sw_hweight32
|
|
addl %ecx, %eax # result
|
|
|
|
popl %ecx
|
|
ret
|
|
#endif
|
|
ENDPROC(__sw_hweight64)
|