162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 */
262306a36Sopenharmony_ci#include <linux/linkage.h>
362306a36Sopenharmony_ci#include <linux/errno.h>
462306a36Sopenharmony_ci#include <asm/asm.h>
562306a36Sopenharmony_ci#include <asm/msr.h>
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#ifdef CONFIG_X86_64
862306a36Sopenharmony_ci/*
962306a36Sopenharmony_ci * int {rdmsr,wrmsr}_safe_regs(u32 gprs[8]);
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * reg layout: u32 gprs[eax, ecx, edx, ebx, esp, ebp, esi, edi]
1262306a36Sopenharmony_ci *
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci.macro op_safe_regs op
1562306a36Sopenharmony_ciSYM_FUNC_START(\op\()_safe_regs)
1662306a36Sopenharmony_ci	pushq %rbx
1762306a36Sopenharmony_ci	pushq %r12
1862306a36Sopenharmony_ci	movq	%rdi, %r10	/* Save pointer */
1962306a36Sopenharmony_ci	xorl	%r11d, %r11d	/* Return value */
2062306a36Sopenharmony_ci	movl    (%rdi), %eax
2162306a36Sopenharmony_ci	movl    4(%rdi), %ecx
2262306a36Sopenharmony_ci	movl    8(%rdi), %edx
2362306a36Sopenharmony_ci	movl    12(%rdi), %ebx
2462306a36Sopenharmony_ci	movl    20(%rdi), %r12d
2562306a36Sopenharmony_ci	movl    24(%rdi), %esi
2662306a36Sopenharmony_ci	movl    28(%rdi), %edi
2762306a36Sopenharmony_ci1:	\op
2862306a36Sopenharmony_ci2:	movl    %eax, (%r10)
2962306a36Sopenharmony_ci	movl	%r11d, %eax	/* Return value */
3062306a36Sopenharmony_ci	movl    %ecx, 4(%r10)
3162306a36Sopenharmony_ci	movl    %edx, 8(%r10)
3262306a36Sopenharmony_ci	movl    %ebx, 12(%r10)
3362306a36Sopenharmony_ci	movl    %r12d, 20(%r10)
3462306a36Sopenharmony_ci	movl    %esi, 24(%r10)
3562306a36Sopenharmony_ci	movl    %edi, 28(%r10)
3662306a36Sopenharmony_ci	popq %r12
3762306a36Sopenharmony_ci	popq %rbx
3862306a36Sopenharmony_ci	RET
3962306a36Sopenharmony_ci3:
4062306a36Sopenharmony_ci	movl    $-EIO, %r11d
4162306a36Sopenharmony_ci	jmp     2b
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	_ASM_EXTABLE(1b, 3b)
4462306a36Sopenharmony_ciSYM_FUNC_END(\op\()_safe_regs)
4562306a36Sopenharmony_ci.endm
4662306a36Sopenharmony_ci
4762306a36Sopenharmony_ci#else /* X86_32 */
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci.macro op_safe_regs op
5062306a36Sopenharmony_ciSYM_FUNC_START(\op\()_safe_regs)
5162306a36Sopenharmony_ci	pushl %ebx
5262306a36Sopenharmony_ci	pushl %ebp
5362306a36Sopenharmony_ci	pushl %esi
5462306a36Sopenharmony_ci	pushl %edi
5562306a36Sopenharmony_ci	pushl $0              /* Return value */
5662306a36Sopenharmony_ci	pushl %eax
5762306a36Sopenharmony_ci	movl    4(%eax), %ecx
5862306a36Sopenharmony_ci	movl    8(%eax), %edx
5962306a36Sopenharmony_ci	movl    12(%eax), %ebx
6062306a36Sopenharmony_ci	movl    20(%eax), %ebp
6162306a36Sopenharmony_ci	movl    24(%eax), %esi
6262306a36Sopenharmony_ci	movl    28(%eax), %edi
6362306a36Sopenharmony_ci	movl    (%eax), %eax
6462306a36Sopenharmony_ci1:	\op
6562306a36Sopenharmony_ci2:	pushl %eax
6662306a36Sopenharmony_ci	movl    4(%esp), %eax
6762306a36Sopenharmony_ci	popl (%eax)
6862306a36Sopenharmony_ci	addl    $4, %esp
6962306a36Sopenharmony_ci	movl    %ecx, 4(%eax)
7062306a36Sopenharmony_ci	movl    %edx, 8(%eax)
7162306a36Sopenharmony_ci	movl    %ebx, 12(%eax)
7262306a36Sopenharmony_ci	movl    %ebp, 20(%eax)
7362306a36Sopenharmony_ci	movl    %esi, 24(%eax)
7462306a36Sopenharmony_ci	movl    %edi, 28(%eax)
7562306a36Sopenharmony_ci	popl %eax
7662306a36Sopenharmony_ci	popl %edi
7762306a36Sopenharmony_ci	popl %esi
7862306a36Sopenharmony_ci	popl %ebp
7962306a36Sopenharmony_ci	popl %ebx
8062306a36Sopenharmony_ci	RET
8162306a36Sopenharmony_ci3:
8262306a36Sopenharmony_ci	movl    $-EIO, 4(%esp)
8362306a36Sopenharmony_ci	jmp     2b
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	_ASM_EXTABLE(1b, 3b)
8662306a36Sopenharmony_ciSYM_FUNC_END(\op\()_safe_regs)
8762306a36Sopenharmony_ci.endm
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#endif
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ciop_safe_regs rdmsr
9262306a36Sopenharmony_ciop_safe_regs wrmsr
9362306a36Sopenharmony_ci
94