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: 44+ 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 18:28 ` Will Deacon
2022-09-23 22:43 ` Linus Torvalds
2022-09-23 22:43 ` Linus Torvalds
2022-09-28 10:46 ` Mark Rutland
2022-09-28 10:46 ` Mark Rutland
2022-09-23 22:53 ` pr-tracker-bot
2022-09-23 22:53 ` pr-tracker-bot
2022-05-13 16:52 Will Deacon
2022-05-13 16:52 ` Will Deacon
2022-05-13 17:30 ` pr-tracker-bot
2022-05-13 17:30 ` pr-tracker-bot
2021-08-20 8:53 Will Deacon
2021-08-20 8:53 ` Will Deacon
2021-08-20 20:09 ` pr-tracker-bot
2021-08-20 20:09 ` pr-tracker-bot
2020-12-02 17:17 Will Deacon
2020-12-02 17:17 ` Will Deacon
2020-12-02 20:48 ` pr-tracker-bot
2020-12-02 20:48 ` pr-tracker-bot
2020-03-20 15:35 Will Deacon
2020-03-20 15:35 ` Will Deacon
2020-03-20 17:15 ` pr-tracker-bot
2020-03-20 17:15 ` pr-tracker-bot
2019-08-28 17:32 [GIT PULL] arm64: Fixes " Will Deacon
2019-08-28 17:32 ` Will Deacon
2019-08-28 17:32 ` Will Deacon
2019-08-28 17:45 ` pr-tracker-bot
2019-08-28 17:45 ` pr-tracker-bot
2019-08-28 17:45 ` pr-tracker-bot
2018-07-27 11:51 [GIT PULL] arm64: fixes " Will Deacon
2018-07-27 11:51 ` Will Deacon
2018-05-25 16:04 Will Deacon
2018-05-25 16:04 ` Will Deacon
2016-07-08 14:49 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.