From: Marc Zyngier <maz@kernel.org>
To: Will Deacon <will@kernel.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>,
catalin.marinas@arm.com, linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, kernel-team@android.com,
rananta@google.com
Subject: Re: [GIT PULL] arm64 fixes for -rc7
Date: Tue, 18 Mar 2025 11:46:31 +0000 [thread overview]
Message-ID: <86tt7qmui0.wl-maz@kernel.org> (raw)
In-Reply-To: <20250317160034.GA12267@willie-the-truck>
On Mon, 17 Mar 2025 16:00:35 +0000,
Will Deacon <will@kernel.org> wrote:
>
> Hi Linus,
>
> On Fri, Mar 14, 2025 at 10:34:57AM -1000, Linus Torvalds wrote:
> > On Fri, 14 Mar 2025 at 06:05, Will Deacon <will@kernel.org> wrote:
> > >
> > > Summary in the tag, but the main one is a horrible macro fix for our
> > > TLB flushing code which resulted in over-invalidation on the MMU
> > > notifier path.
> >
> > From a quick look, that macro is still quite broken. Maybe not in ways
> > that matter, but still...
> >
> > In particular, the 'stride' argument is used multiple times, and
> > without parentheses.
> >
> > The 'lpa' argument is also used multiple times, and the input to that
> > is typically something like kvm_lpa2_is_enabled(), so I think it
> > potentially generates lots of pointless duplicate code with that
> > BUG_ON() in system_supports_lpa2() -> cpus_have_final_cap().
> >
> > Maybe the compiler figures it out. But that macro is bad, bad, bad.
> > When it looks like a function, it should act like a function, and not
> > evaluate its arguments multiple times.
> >
> > The most immediate bug may have been fixed, but not the actual real
> > horror of that thing.
>
> Yes, the minimal fix for -rc7 avoids explicitly mutating the macro
> arguments but we still have the multiple-evaluation problem you point
> out above.
>
> Ideally, this function would be rewritten as a 'static inline' but it
> was moved from C code into a macro as part of 360839027a6e ("arm64: tlb:
> Refactor the core flush algorithm of __flush_tlb_range") because we need
> to propagate the 'op' argument down to the low-level asm where it's
> stringified as part of the instruction mnemonic.
>
> I'll have a crack at reworking things to take a 'const char *' instead,
> but it won't be for 6.14 as it'll be reasonably invasive.
I had a go at the 'const char *' approach, but couldn't make it work
reliably without making it very invasive.
I ended up with a slightly bigger hammer (see below) that survived
booting on a test box and running a couple of VMs. I wouldn't trust it
with anything more important than that though.
M.
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 8104aee4f9a08..0ff635cf8abf5 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -393,45 +393,93 @@ static inline void arch_tlbbatch_flush(struct arch_tlbflush_unmap_batch *batch)
* operations can only span an even number of pages. We save this for last to
* ensure 64KB start alignment is maintained for the LPA2 case.
*/
+typedef void (*tlbi_level_fn_t)(u64, int);
+typedef void (*tlbi_fn_t)(u64);
+
+#define __TLBI_LEVEL_FN(t, s) \
+static inline void tlbi_level_##t##s(u64 addr, int level) \
+{ \
+ __tlbi_level(t##s, addr, level); \
+} \
+static inline void tlbi_user_level_##t##s(u64 addr, int level) \
+{ \
+ __tlbi_user_level(t##s, addr, level); \
+}
+
+#define __TLBI_FN(t, s) \
+static inline void tlbi_##t##s(u64 addr) \
+{ \
+ __tlbi(t##s, addr); \
+} \
+static inline void tlbi_user_##t##s(u64 addr) \
+{ \
+ __tlbi_user(t##s, addr); \
+}
+
+#define TLBI_FNS(t) \
+ __TLBI_FN(t, ) \
+ __TLBI_FN(t, is) \
+ __TLBI_FN(r##t, ) \
+ __TLBI_FN(r##t, is) \
+ __TLBI_LEVEL_FN(t, ) \
+ __TLBI_LEVEL_FN(t, is) \
+ __TLBI_LEVEL_FN(r##t, ) \
+ __TLBI_LEVEL_FN(r##t, is)
+
+/* These are the TLBI instructions we allow for range operation */
+TLBI_FNS(ipas2e1)
+TLBI_FNS(vae1)
+TLBI_FNS(vale1)
+TLBI_FNS(vaale1)
+
+static __always_inline
+void __flush_tlb_range_by_op(tlbi_level_fn_t il, tlbi_level_fn_t iul,
+ tlbi_fn_t ri, tlbi_fn_t riu,
+ u64 start, u64 pages, int stride,
+ u16 asid, int tlb_level,
+ bool tlbi_user, bool lpa2)
+{
+ int num = 0;
+ int scale = 3;
+ int shift = lpa2 ? 16 : PAGE_SHIFT;
+ unsigned long addr;
+
+ while (pages > 0) {
+ if (!system_supports_tlb_range() ||
+ pages == 1 ||
+ (lpa2 && start != ALIGN(start, SZ_64K))) {
+ addr = __TLBI_VADDR(start, asid);
+ il(addr, tlb_level);
+ if (tlbi_user)
+ iul(addr, tlb_level);
+ start += stride;
+ pages -= stride >> PAGE_SHIFT;
+ continue;
+ }
+
+ num = __TLBI_RANGE_NUM(pages, scale);
+ if (num >= 0) {
+ addr = __TLBI_VADDR_RANGE(start >> shift, asid,
+ scale, num, tlb_level);
+ ri(addr);
+ if (tlbi_user)
+ riu(addr);
+ start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT;
+ pages -= __TLBI_RANGE_PAGES(num, scale);
+ }
+ scale--;
+ }
+}
+
#define __flush_tlb_range_op(op, start, pages, stride, \
- asid, tlb_level, tlbi_user, lpa2) \
-do { \
- typeof(start) __flush_start = start; \
- typeof(pages) __flush_pages = pages; \
- int num = 0; \
- int scale = 3; \
- int shift = lpa2 ? 16 : PAGE_SHIFT; \
- unsigned long addr; \
- \
- while (__flush_pages > 0) { \
- if (!system_supports_tlb_range() || \
- __flush_pages == 1 || \
- (lpa2 && __flush_start != ALIGN(__flush_start, SZ_64K))) { \
- addr = __TLBI_VADDR(__flush_start, asid); \
- __tlbi_level(op, addr, tlb_level); \
- if (tlbi_user) \
- __tlbi_user_level(op, addr, tlb_level); \
- __flush_start += stride; \
- __flush_pages -= stride >> PAGE_SHIFT; \
- continue; \
- } \
- \
- num = __TLBI_RANGE_NUM(__flush_pages, scale); \
- if (num >= 0) { \
- addr = __TLBI_VADDR_RANGE(__flush_start >> shift, asid, \
- scale, num, tlb_level); \
- __tlbi(r##op, addr); \
- if (tlbi_user) \
- __tlbi_user(r##op, addr); \
- __flush_start += __TLBI_RANGE_PAGES(num, scale) << PAGE_SHIFT; \
- __flush_pages -= __TLBI_RANGE_PAGES(num, scale);\
- } \
- scale--; \
- } \
-} while (0)
+ asid, tlb_level, tlbi_user, lpa2) \
+ __flush_tlb_range_by_op(tlbi_level_##op, tlbi_user_level_##op, \
+ tlbi_r##op, tlbi_user_r##op, \
+ start, pages, stride, asid, \
+ tlb_level, tlbi_user, lpa2)
#define __flush_s2_tlb_range_op(op, start, pages, stride, tlb_level) \
- __flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false, kvm_lpa2_is_enabled());
+ __flush_tlb_range_op(op, start, pages, stride, 0, tlb_level, false, kvm_lpa2_is_enabled())
static inline bool __flush_tlb_range_limit_excess(unsigned long start,
unsigned long end, unsigned long pages, unsigned long stride)
--
Without deviation from the norm, progress is not possible.
next prev parent reply other threads:[~2025-03-18 12:02 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-03-14 16:04 [GIT PULL] arm64 fixes for -rc7 Will Deacon
2025-03-14 20:34 ` Linus Torvalds
2025-03-17 16:00 ` Will Deacon
2025-03-18 11:43 ` Will Deacon
2025-03-18 11:46 ` Marc Zyngier [this message]
2025-03-14 21:03 ` pr-tracker-bot
-- strict thread matches above, loose matches on Subject: below --
2024-11-08 11:57 Will Deacon
2024-11-08 17:39 ` pr-tracker-bot
2022-09-23 18:28 Will Deacon
2022-09-23 22:43 ` Linus Torvalds
2022-09-28 10:46 ` Mark Rutland
2022-09-23 22:53 ` pr-tracker-bot
2022-05-13 16:52 Will Deacon
2022-05-13 17:30 ` pr-tracker-bot
2021-08-20 8:53 Will Deacon
2021-08-20 20:09 ` pr-tracker-bot
2020-12-02 17:17 Will Deacon
2020-12-02 20:48 ` pr-tracker-bot
2020-03-20 15:35 Will Deacon
2020-03-20 17:15 ` pr-tracker-bot
2019-08-28 17:32 [GIT PULL] arm64: Fixes " Will Deacon
2019-08-28 17:45 ` pr-tracker-bot
2018-07-27 11:51 [GIT PULL] arm64: fixes " Will Deacon
2018-05-25 16:04 Will Deacon
2016-07-08 14:49 Will Deacon
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=86tt7qmui0.wl-maz@kernel.org \
--to=maz@kernel.org \
--cc=catalin.marinas@arm.com \
--cc=kernel-team@android.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=rananta@google.com \
--cc=torvalds@linux-foundation.org \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).