[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20230907153036.GBZPnsnNreLCyGpJFn@fat_crate.local>
Date: Thu, 7 Sep 2023 17:30:36 +0200
From: Borislav Petkov <bp@...en8.de>
To: Peter Zijlstra <peterz@...radead.org>
Cc: x86@...nel.org, linux-kernel@...r.kernel.org, David.Kaplan@....com,
Andrew.Cooper3@...rix.com, jpoimboe@...nel.org,
gregkh@...uxfoundation.org, nik.borisov@...e.com
Subject: Re: [PATCH v2 10/11] x86/alternatives: Simplify ALTERNATIVE_n()
On Thu, Sep 07, 2023 at 05:06:32PM +0200, Borislav Petkov wrote:
> > # ALT: oldnstr
> > 661:
> > # ALT: oldnstr
> > 661:
>
> I'll keep on playing with this.
Ok, below's what I've been thinking. It looks ok but I'll keep staring
at it for a while to make sure I'm not missing an angle.
We simply pass a number to the ALTERNATIVE macro, starting from 0. 0 is
the innermost invocation, 1 is the outer and so on. And then the labels
are unique and the sizes are correct. And we hardcode 0 to mean the
innermost macro invocation and use that for sizing of orig instr.
But I might be missing something so lemme poke at it more. Below is
a userspace program which makes this a lot easier to experiment with:
---
#include <stdio.h>
#define __stringify_1(x...) #x
#define __stringify(x...) __stringify_1(x)
#define alt_slen "662b-6610b"
#define alt_total_slen "663b-661b"
#define alt_rlen "665f-664f"
#define OLDINSTR(oldinstr, n) \
"# ALT: oldnstr\n" \
"661" #n ":\n\t" oldinstr "\n662:\n" \
"# ALT: padding\n" \
".skip -(((" alt_rlen ")-(" alt_slen ")) > 0) * " \
"((" alt_rlen ")-(" alt_slen ")),0x90\n" \
"663:\n"
#define ALTINSTR_ENTRY(ft_flags) \
".pushsection .altinstructions,\"a\"\n" \
" .long 6610b - .\n" /* label */ \
" .long 664f - .\n" /* new instruction */ \
" .4byte " __stringify(ft_flags) "\n" /* feature + flags */ \
" .byte " alt_total_slen "\n" /* source len */ \
" .byte " alt_rlen "\n" /* replacement len */ \
".popsection\n"
#define ALTINSTR_REPLACEMENT(newinstr) /* replacement */ \
".pushsection .altinstr_replacement, \"ax\"\n" \
"# ALT: replacement \n" \
"664:\n\t" newinstr "\n 665:\n" \
".popsection\n"
/*
* Define an alternative between two instructions. If @ft_flags is
* present, early code in apply_alternatives() replaces @oldinstr with
* @newinstr. ".skip" directive takes care of proper instruction padding
* in case @newinstr is longer than @oldinstr.
*
* Notably: @oldinstr may be an ALTERNATIVE() itself, also see
* apply_alternatives()
*/
#define __ALTERNATIVE(oldinstr, newinstr, ft_flags, n) \
OLDINSTR(oldinstr, n) \
ALTINSTR_ENTRY(ft_flags) \
ALTINSTR_REPLACEMENT(newinstr)
#define ALTERNATIVE(oldinstr, newinstr, ft_flags) \
__ALTERNATIVE(oldinstr, newinstr, ft_flags, 0)
#define ALTERNATIVE_2(oldinst, newinst1, flag1, newinst2, flag2) \
__ALTERNATIVE(__ALTERNATIVE(oldinst, newinst1, flag1, 0), \
newinst2, flag2, 1)
#define alternative_2(oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2) \
asm __inline volatile(ALTERNATIVE_2(oldinstr, newinstr1, ft_flags1, newinstr2, ft_flags2) ::: "memory")
int main(void)
{
alternative_2("", "pop %%rax", 1, "call main", 1);
return 0;
}
--
Regards/Gruss,
Boris.
https://people.kernel.org/tglx/notes-about-netiquette
Powered by blists - more mailing lists