NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: port-xen/58561 (panic: kernel diagnostic assertion, "x86_read_psl() == 0" failed: file, "/home/netbsd/10/src/sys/arch/x86/x86/pmap.c", line 3581)



> Date: Tue, 13 Jan 2026 15:50:10 +0100
> From: Manuel Bouyer <bouyer%antioche.eu.org@localhost>
> 
> Here's the updated patch

Thanks for working on this!  Some small issues:

> --- amd64/amd64/cpufunc.S	6 Sep 2025 02:53:22 -0000	1.70
> +++ amd64/amd64/cpufunc.S	13 Jan 2026 14:48:25 -0000
> @@ -184,7 +184,7 @@ ENTRY(wbinvd)
>  END(wbinvd)
>  
>  ENTRY(setusergs)
> -	CLI(ax)
> +	CLI2(ax, rdi)
>  	swapgs
>  	movw	%di, %gs
>  	swapgs

I think this can't be right.  %rdi is obviously not a free scratch
register: it's the first argument register.  But also, this code isn't
even used in Xen builds, is it?  Xen has its own setusergs in
xenfunc.c, doesn't it?

https://nxr.netbsd.org/xref/src/sys/arch/xen/x86/xenfunc.c?r=1.29#270

> --- amd64/amd64/spl.S	1 Mar 2023 08:38:50 -0000	1.49
> +++ amd64/amd64/spl.S	13 Jan 2026 14:48:25 -0000
> ...
> @@ -355,7 +356,7 @@ IDTVEC(doreti)
>  1:
>  	movl    %ebx,%eax
>  	movq	CPUVAR(IUNMASK)(,%rax,8),%rax
> -	CLI(si)
> +	CLI2(si, r14)
>  	andq	CPUVAR(IPENDING),%rax
>  	jz	2f
>  	bsrq	%rax,%rax		/* slow, but not worth optimizing */
> @@ -378,7 +379,7 @@ IDTVEC(doreti)
>  	movq	%rsp,%rdi
>  	KMSAN_INIT_ARG(8)
>  	call	_C_LABEL(trap)
> -	CLI(si)
> +	CLI2(si, rdi)
>  	jmp	.Ldoreti_checkast
>  3:
>  	CHECK_DEFERRED_SWITCH
> @@ -389,6 +390,6 @@ IDTVEC(doreti)
>  9:
>  	STI(si)
>  	call	_C_LABEL(do_pmap_load)
> -	CLI(si)
> +	CLI2(si, rdi)
>  	jmp	.Ldoreti_checkast		/* recheck ASTs */
>  IDTVEC_END(doreti)

Not immediately clear these registers are free here, can we
double-check and document in a comment exactly what registers are
involved on entry and exit to doreti?

> --- amd64/include/frameasm.h	30 Jul 2022 14:11:00 -0000	1.55
> +++ amd64/include/frameasm.h	13 Jan 2026 14:48:25 -0000
> ...
> + * ci_ilevel is nit 0, or

Nit: not `nit', `not'!

> +	cmpl $0, L_NOPREEMPT(%r ## temp_reg);			\
> +	jne 199f;						\
> ...
> +199:	movq CPUVAR(VCPU),%r ## temp_reg ;			\
>  	movb $1,EVTCHN_UPCALL_MASK(%r ## temp_reg);

Would be nice if we could make this work so the static branch
prediction (forward jump not taken) takes the right path here, but I
guess it's a pain because this is really doing

	KASSERT(l->l_nopreempt != 0 || curcpu()->ci_ilevel != 0 || ...)

> + 	movq $panicstr,%r ## temp_reg ;			 	\

Should this use _C_LABEL for consistency?

> +	cmpq $0, 0(%r ## temp_reg);				\

I always get confused about C symbols in MOV assembly directives.
Does temp_reg at this point hold a (possibly null) pointer to the
first character of the panic string, or a (possibly null) pointer to
the _pointer to_ first character of the panic string?

Shouldn't this be one of the two options?

	leaq	$panicstr,%rtmp
	cmpq	$0, 0(%rtmp)

or

	movq	$panicstr,%rtmp
	cmpq	$0,%rtmp

> +	movq _C_LABEL(cli_panic), %rdi;				\
> +	call _C_LABEL(panic);					\

Have you tested provoking this path to make sure it leads to a
sensible-looking panic?

> +/* CLI() with preemtion disabled */
> +#define CLI2(temp_reg, temp_reg2) \
> + 	movq CPUVAR(CURLWP),% ## temp_reg2 ;			\
> +	incl L_NOPREEMPT(% ## temp_reg2);			\
> + 	movq CPUVAR(VCPU),%r ## temp_reg ;			\
> +	movb $1,EVTCHN_UPCALL_MASK(%r ## temp_reg);		\
> +	decl L_NOPREEMPT(% ## temp_reg2);

Or, as an alternative to all the above issues...  What if we just make
CLI work using a single temporary register?  Requires one extra load
to reuse the register but I bet modern x86 CPUs will do enough fancy
register renaming and caching internally that it makes essentially no
difference except perhaps for a few bytes of code size:

	movq	CPUVAR(curlwp),%r ## temp_reg;
	incl	L_NOPREEMPT(%r ## temp_reg);
	movq	CPUVAR(VCPU),%r ## temp_reg2;
	movb	$1,EVTCHN_UPCALL_MASK(%r ## temp_reg);
	movq	CPUVAR(curlwp),%r ## temp_reg;
	decl	L_NOPREEMPT(%r ## temp_reg);

> --- xen/x86/xen_intr.c	25 Feb 2023 00:32:13 -0000	1.31
> +++ xen/x86/xen_intr.c	13 Jan 2026 14:48:26 -0000
> @@ -540,3 +547,9 @@ __strong_alias(cpu_intr_init, xen_cpu_in
>  __strong_alias(intr_allocate_io_intrsource, xen_intr_allocate_io_intrsource);
>  __strong_alias(intr_free_io_intrsource, xen_intr_free_io_intrsource);
>  #endif /* XENPV */
> +
> +
> +#if defined(DIAGNOSTIC) && defined(XENPV)
> +const char *cli_panic = "cli with preemtion";
> +const char *sti_panic = "sti with interrupts enabled";
> +#endif

const char cli_panic[] = "cli with preemtion";
const char sti_panic[] = "sti with interrupts enabled";

Don't need a mutable pointer to the immutable string in memory -- just
a symbol for the string is enough.


Home | Main Index | Thread Index | Old Index