[Bug 293382] Dead lock and kernel crash around closefp_impl

From: <bugzilla-noreply_at_freebsd.org>
Date: Fri, 17 Apr 2026 13:00:42 UTC
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=293382

--- Comment #94 from Kristofer Peterson <kris@tranception.com> ---
The description of INVLPGB in Volume 3 of the AMD64 Architecture Programmer's
Manual is not terribly clear; it would have been nice had they included a
pseudo-code description similar to what you find in the Intel documentation.

I was curious how other operating systems chose to use and implement INVLPGB
given presumably the same information; I include a short extract below from the
Linux kernel.

Bit 31 of ECX is represented by a stride enum which suggests their
interpretation of INVLPGB is inline with what Kyle outlined yesterday.

Obviously this is no substitute for clear authoritative documentation or
guidance from AMD but hopefully a useful data point.

Excerpt from Linux source
file: arch/x86/include/asm/tlb.h
repo: https://github.com/torvalds/linux.git
-----------------------------------------------------------------------------
31:enum addr_stride {
32:     PTE_STRIDE = 0,
33:     PMD_STRIDE = 1
34:};
35:
36:/*
37: * INVLPGB can be targeted by virtual address, PCID, ASID, or any
combination
38: * of the three. For example:
39: * - FLAG_VA | FLAG_INCLUDE_GLOBAL: invalidate all TLB entries at the
address
40: * - FLAG_PCID:                          invalidate all TLB entries matching
the PCID
41: *
42: * The first is used to invalidate (kernel) mappings at a particular
43: * address across all processes.
44: *
45: * The latter invalidates all TLB entries matching a PCID.
46: */
47:#define INVLPGB_FLAG_VA                      BIT(0)
48:#define INVLPGB_FLAG_PCID            BIT(1)
49:#define INVLPGB_FLAG_ASID            BIT(2)
50:#define INVLPGB_FLAG_INCLUDE_GLOBAL  BIT(3)
51:#define INVLPGB_FLAG_FINAL_ONLY              BIT(4)
52:#define INVLPGB_FLAG_INCLUDE_NESTED  BIT(5)
53:
54:/* The implied mode when all bits are clear: */
55:#define INVLPGB_MODE_ALL_NONGLOBALS  0UL
56:
57:#ifdef CONFIG_BROADCAST_TLB_FLUSH
58:/*
59: * INVLPGB does broadcast TLB invalidation across all the CPUs in the
system.
60: *
61: * The INVLPGB instruction is weakly ordered, and a batch of invalidations
can
62: * be done in a parallel fashion.
63: *
64: * The instruction takes the number of extra pages to invalidate, beyond the
65: * first page, while __invlpgb gets the more human readable number of pages
to
66: * invalidate.
67: *
68: * The bits in rax[0:2] determine respectively which components of the
address
69: * (VA, PCID, ASID) get compared when flushing. If neither bits are set,
*any*
70: * address in the specified range matches.
71: *
72: * Since it is desired to only flush TLB entries for the ASID that is
executing
73: * the instruction (a host/hypervisor or a guest), the ASID valid bit should
74: * always be set. On a host/hypervisor, the hardware will use the ASID value
75: * specified in EDX[15:0] (which should be 0). On a guest, the hardware will
76: * use the actual ASID value of the guest.
77: *
78: * TLBSYNC is used to ensure that pending INVLPGB invalidations initiated
from
79: * this CPU have completed.
80: */
81:static inline void __invlpgb(unsigned long asid, unsigned long pcid,
82:                          unsigned long addr, u16 nr_pages,
83:                          enum addr_stride stride, u8 flags)
84:{
85:     u64 rax = addr | flags | INVLPGB_FLAG_ASID;
86:     u32 ecx = (stride << 31) | (nr_pages - 1);
87:     u32 edx = (pcid << 16) | asid;
88:
89:     /* The low bits in rax are for flags. Verify addr is clean. */
90:     VM_WARN_ON_ONCE(addr & ~PAGE_MASK);
91:
92:     /* INVLPGB; supported in binutils >= 2.36. */
93:     asm volatile(".byte 0x0f, 0x01, 0xfe" :: "a" (rax), "c" (ecx), "d"
(edx));
94:}

-- 
You are receiving this mail because:
You are the assignee for the bug.