All of lore.kernel.org
 help / color / mirror / Atom feed
From: Paolo Bonzini <pbonzini@redhat.com>
To: Arthur Chunqi Li <yzt356@gmail.com>
Cc: kvm@vger.kernel.org, jan.kiszka@web.de, gleb@redhat.com
Subject: Re: [RFC PATCH] kvm-unit-tests : Basic architecture of VMX nested test case
Date: Thu, 18 Jul 2013 07:52:21 +0200	[thread overview]
Message-ID: <51E78295.2010700@redhat.com> (raw)
In-Reply-To: <1374087242-6125-1-git-send-email-yzt356@gmail.com>

Il 17/07/2013 20:54, Arthur Chunqi Li ha scritto:
> +/* entry_sysenter */
> +asm(
> +	".align	4, 0x90\n\t"
> +	".globl	entry_sysenter\n\t"
> +	"entry_sysenter:\n\t"
> +	SAVE_GPR
> +	"	and	$0xf, %rax\n\t"
> +	"	push	%rax\n\t"

push should be wrong here, the first argument is in %rdi.

> +	"	call	syscall_handler\n\t"
> +	LOAD_GPR
> +	"	vmresume\n\t"
> +);
> +
> +int exit_handler()

This (and syscall_handler too) needs __attribute__((__used__)) because
it's only used from assembly.

Please add "static" to all functions except main, it triggers better
compiler optimization and warnings and it will avoid nasty surprises in
the future if the compiler becomes smarter.

> +{
> +	int ret;
> +
> +	current->exits++;
> +	current->guest_regs = regs;
> +	if (is_hypercall())
> +		ret = handle_hypercall();
> +	else
> +		ret = current->exit_handler();
> +	regs = current->guest_regs;
> +	switch (ret) {
> +	case VMX_TEST_VMEXIT:
> +	case VMX_TEST_RESUME:
> +		return ret;
> +	case VMX_TEST_EXIT:
> +		break;
> +	default:
> +		printf("ERROR : Invalid exit_handler return val %d.\n"
> +			, ret);
> +	}

Here have to propagate the exit codes through multiple levels, because
we're not using setjmp/longjmp.  Not a big deal.  My worries with this
version are below.

> +	print_vmexit_info();
> +	exit(-1);
> +	return 0;
> +}
> +
> +int vmx_run()
> +{
> +	bool ret;
> +	u32 eax;
> +	u64 rsp;
> +
> +	asm volatile("mov %%rsp, %0\n\t" : "=r"(rsp));
> +	vmcs_write(HOST_RSP, rsp);
> +	asm volatile("vmlaunch;seta %0\n\t" : "=m"(ret));

setbe (this path is probably untested because it never happens in practice).

Also, missing memory clobber.

> +	if (ret) {
> +		printf("%s : vmlaunch failed.\n", __func__);
> +		return 1;
> +	}
> +	while (1) {
> +		asm volatile(
> +			LOAD_GPR_C
> +			"vmresume;seta %0\n\t"
> +			: "=m"(ret));

setbe and missing memory clobber.

> +		if (ret) {
> +			printf("%s : vmresume failed.\n", __func__);
> +			return 1;
> +		}
> +		asm volatile(
> +			".global vmx_return\n\t"

.global should not be needed.

> +			"vmx_return:\n\t"
> +			SAVE_GPR_C
> +			"call exit_handler\n\t"
> +			"mov %%eax, %0\n\t"
> +			: "=r"(eax)
> +		);

I had written a long explanation here about why I don't trust the
compiler to do the right thing, and ideas about how to fix that.  But in
the end the only workable solution is a single assembly blob like vmx.c
in KVM to do vmlaunch/vmresume, so I'll get right to the point:

   *  the "similarity with KVM code" and "as little assembly as  *
   *  possible" goals are mutually exclusive                     *

and for a testsuite I'd prefer the latter---which means I'd still favor
setjmp/longjmp.

Now, here is the long explanation.

I must admit that the code looks nice.  There are some nits I'd like to
see done differently (such as putting vmx_return at the beginning of the
while (1), and the vmresume asm at the end), but it is indeed nice.

However, it is also very deceiving, because the processor is not doing
what the code says.  If I see:

       vmlaunch();
       exit(-1);

it is clear that magic happens in vmlaunch().  If I see

       asm volatile("vmlaunch;setbe %0\n\t" : "=m"(ret));
       if (ret) {
           ...
       }
       asm("vmx_return:")

it is absolutely not clear that the setbe and "if" are skipped on a
successful vmlaunch.  So, at the very least you need a comment before
those "if (ret)" to document the control flow, or you can use a jmp like
this:

       asm volatile goto ("vmlaunch;jmp %0\n\t"
                          : : : "memory" : vmlaunch_error);
       if (0) {
           vmlaunch_error: ...
       }

The unconditional jump and "asm goto" make it clear that magic happens.

By the way, "asm goto" is also needed to tell the compiler that the
vmlaunch and vmresume asms reenter at vmx_resume(*).  Without it, there
is no guarantee that rsp is the same when you save it and at the
vmx_resume entry point (in fact, I'd feel safer if you did the vmwrite
to HOST_RSP and vmlaunch in the same "asm goto".

Using "asm goto" to tell the compiler about vmx_resume poses another
problem.  "asm goto" takes a C label, vmx_resume is an assembly label.
The compiler might put extra instruction between the C label and
vmx_resume, for example to read back values it has spilled to the stack.

Overall, I don't trust the compiler to compile this code right
(especially if we later include a 32-bit version) and the only solution
is to write the whole thing in assembly.  If you want to write the logic
in C, you need the setjmp/longjmp version.  That version needs no such
guarantee because all the trampolines are away from the hands of the
compiler.

Paolo

> +		switch (eax) {
> +		case VMX_TEST_VMEXIT:
> +			return 0;
> +		case VMX_TEST_RESUME:
> +			break;
> +		default:
> +			printf("%s : unhandled ret from exit_handler.\n", __func__);
> +			return 1;
> +		}
> +	}
> +	return 0;
> +}


  reply	other threads:[~2013-07-18  5:52 UTC|newest]

Thread overview: 24+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2013-07-17 18:54 [RFC PATCH] kvm-unit-tests : Basic architecture of VMX nested test case Arthur Chunqi Li
2013-07-18  5:52 ` Paolo Bonzini [this message]
2013-07-18  7:26   ` Gleb Natapov
2013-07-18 10:47     ` Paolo Bonzini
2013-07-18 11:06       ` Gleb Natapov
2013-07-18 12:08         ` Paolo Bonzini
2013-07-18 14:11           ` Arthur Chunqi Li
2013-07-18 19:57           ` Gleb Natapov
2013-07-19  6:42             ` Paolo Bonzini
2013-07-19  9:40               ` Gleb Natapov
2013-07-19 12:06                 ` Paolo Bonzini
2013-07-24  6:11                   ` Arthur Chunqi Li
2013-07-24  6:40                     ` Paolo Bonzini
2013-07-24  6:46                       ` Arthur Chunqi Li
2013-07-24  6:48                         ` Paolo Bonzini
2013-07-24  8:48                           ` Arthur Chunqi Li
2013-07-24  8:53                             ` Jan Kiszka
2013-07-24  9:16                             ` Paolo Bonzini
2013-07-24  9:56                               ` Arthur Chunqi Li
2013-07-24 10:03                                 ` Jan Kiszka
2013-07-24 10:16                                   ` Arthur Chunqi Li
2013-07-24 10:24                                     ` Jan Kiszka
2013-07-24 11:20                                       ` Arthur Chunqi Li
2013-07-24 11:25                                         ` Jan Kiszka

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=51E78295.2010700@redhat.com \
    --to=pbonzini@redhat.com \
    --cc=gleb@redhat.com \
    --cc=jan.kiszka@web.de \
    --cc=kvm@vger.kernel.org \
    --cc=yzt356@gmail.com \
    /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.