diff mbox series

[2/5] xen/wait: Extend the description of how this logic actually works

Message ID 20220718071825.22113-3-andrew.cooper3@citrix.com (mailing list archive)
State New, archived
Headers show
Series xen/wait: Improvements | expand

Commit Message

Andrew Cooper July 18, 2022, 7:18 a.m. UTC
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
---
CC: Jan Beulich <JBeulich@suse.com>
CC: Roger Pau Monné <roger.pau@citrix.com>
CC: Wei Liu <wl@xen.org>
---
 xen/common/wait.c | 29 +++++++++++++++++++++++++----
 1 file changed, 25 insertions(+), 4 deletions(-)

Comments

Jan Beulich July 18, 2022, 10 a.m. UTC | #1
On 18.07.2022 09:18, Andrew Cooper wrote:
> @@ -199,9 +211,18 @@ void check_wakeup_from_wait(void)
>      }
>  
>      /*
> -     * Hand-rolled longjmp().  Returns to __prepare_to_wait(), and lands on a
> -     * `rep movs` instruction.  All other GPRs are restored from the stack, so
> -     * are available for use here.
> +     * Hand-rolled longjmp().
> +     *
> +     * check_wakeup_from_wait() is always called with a shallow stack,
> +     * immediately after the vCPU has been rescheduled.
> +     *
> +     * Adjust %rsp to be the correct depth for the (deeper) stack we want to
> +     * restore, then prepare %rsi, %rdi and %rcx such that when we intercept
> +     * the rep movs in __prepare_to_wait(), it copies from wqv->stack over the
> +     * active stack.

I'm struggling with the use of "intercept" here, but I guess that's just
because I'm not a native speaker.

> +     * All other GPRs are available for use; they're either restored from
> +     * wqv->stack or explicitly clobbered.

You talking of "other GPRs" - there aren't any which are explicitly
clobbered. It's only the previously named ones which are. Hence I'd like
to ask that the respective parts of the sentence be dropped. Then
Reviewed-by: Jan Beulich <jbeulich@suse.com>

Jan
Andrew Cooper July 18, 2022, 10:11 a.m. UTC | #2
On 18/07/2022 11:00, Jan Beulich wrote:
> On 18.07.2022 09:18, Andrew Cooper wrote:
>> @@ -199,9 +211,18 @@ void check_wakeup_from_wait(void)
>>      }
>>  
>>      /*
>> -     * Hand-rolled longjmp().  Returns to __prepare_to_wait(), and lands on a
>> -     * `rep movs` instruction.  All other GPRs are restored from the stack, so
>> -     * are available for use here.
>> +     * Hand-rolled longjmp().
>> +     *
>> +     * check_wakeup_from_wait() is always called with a shallow stack,
>> +     * immediately after the vCPU has been rescheduled.
>> +     *
>> +     * Adjust %rsp to be the correct depth for the (deeper) stack we want to
>> +     * restore, then prepare %rsi, %rdi and %rcx such that when we intercept
>> +     * the rep movs in __prepare_to_wait(), it copies from wqv->stack over the
>> +     * active stack.
> I'm struggling with the use of "intercept" here, but I guess that's just
> because I'm not a native speaker.

"intercept" is the same terminology used in the middle of
__prepare_to_wait()'s block.

It's because we have a weird setup where this is (now) a noreturn
function merging into the middle of a function which already executed once.

I'm happy to change it if it's unclear, but I can't think of a better
description.

>> +     * All other GPRs are available for use; they're either restored from
>> +     * wqv->stack or explicitly clobbered.
> You talking of "other GPRs" - there aren't any which are explicitly
> clobbered. It's only the previously named ones which are. Hence I'd like
> to ask that the respective parts of the sentence be dropped. Then
> Reviewed-by: Jan Beulich <jbeulich@suse.com>

It becomes true in the next patch.  I'll try and shuffle things.

~Andrew
Jan Beulich July 18, 2022, 10:49 a.m. UTC | #3
On 18.07.2022 12:11, Andrew Cooper wrote:
> On 18/07/2022 11:00, Jan Beulich wrote:
>> On 18.07.2022 09:18, Andrew Cooper wrote:
>>> @@ -199,9 +211,18 @@ void check_wakeup_from_wait(void)
>>>      }
>>>  
>>>      /*
>>> -     * Hand-rolled longjmp().  Returns to __prepare_to_wait(), and lands on a
>>> -     * `rep movs` instruction.  All other GPRs are restored from the stack, so
>>> -     * are available for use here.
>>> +     * Hand-rolled longjmp().
>>> +     *
>>> +     * check_wakeup_from_wait() is always called with a shallow stack,
>>> +     * immediately after the vCPU has been rescheduled.
>>> +     *
>>> +     * Adjust %rsp to be the correct depth for the (deeper) stack we want to
>>> +     * restore, then prepare %rsi, %rdi and %rcx such that when we intercept
>>> +     * the rep movs in __prepare_to_wait(), it copies from wqv->stack over the
>>> +     * active stack.
>> I'm struggling with the use of "intercept" here, but I guess that's just
>> because I'm not a native speaker.
> 
> "intercept" is the same terminology used in the middle of
> __prepare_to_wait()'s block.
> 
> It's because we have a weird setup where this is (now) a noreturn
> function merging into the middle of a function which already executed once.
> 
> I'm happy to change it if it's unclear, but I can't think of a better
> description.

"... when we go back to ..."? (But I'm not meaning to insist on a
wording change.)

Jan
diff mbox series

Patch

diff --git a/xen/common/wait.c b/xen/common/wait.c
index 3ebb884fe738..4dcfa17a8a3f 100644
--- a/xen/common/wait.c
+++ b/xen/common/wait.c
@@ -137,7 +137,19 @@  static void __prepare_to_wait(struct waitqueue_vcpu *wqv)
             do_softirq();
     }
 
-    /* Hand-rolled setjmp(). */
+    /*
+     * Hand-rolled setjmp().
+     *
+     * __prepare_to_wait() is the leaf of a deep calltree.  Preserve the GPRs,
+     * bounds check what we want to stash in wqv->stack, copy the active stack
+     * (up to cpu_info) into wqv->stack, then return normally.  Our caller
+     * will shortly schedule() and discard the current context.
+     *
+     * The copy out is performed with a rep movsb.  When
+     * check_wakeup_from_wait() longjmp()'s back into us, %rsp is pre-adjusted
+     * to be suitable and %rsi/%rdi are swapped, so the rep movsb instead
+     * copies in from wqv->stack over the active stack.
+     */
     asm volatile (
         "push %%rax; push %%rbx; push %%rdx; push %%rbp;"
         "push %%r8;  push %%r9;  push %%r10; push %%r11;"
@@ -199,9 +211,18 @@  void check_wakeup_from_wait(void)
     }
 
     /*
-     * Hand-rolled longjmp().  Returns to __prepare_to_wait(), and lands on a
-     * `rep movs` instruction.  All other GPRs are restored from the stack, so
-     * are available for use here.
+     * Hand-rolled longjmp().
+     *
+     * check_wakeup_from_wait() is always called with a shallow stack,
+     * immediately after the vCPU has been rescheduled.
+     *
+     * Adjust %rsp to be the correct depth for the (deeper) stack we want to
+     * restore, then prepare %rsi, %rdi and %rcx such that when we intercept
+     * the rep movs in __prepare_to_wait(), it copies from wqv->stack over the
+     * active stack.
+     *
+     * All other GPRs are available for use; they're either restored from
+     * wqv->stack or explicitly clobbered.
      */
     asm volatile (
         "mov %1,%%"__OP"sp; jmp .L_wq_resume;"