Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
cb547637
Commit
cb547637
authored
Jul 28, 2018
by
Paolo Bonzini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
kvm: selftests: add test for nested state save/restore
Signed-off-by:
Paolo Bonzini
<
pbonzini@redhat.com
>
parent
8fcc4b59
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
132 additions
and
1 deletion
+132
-1
tools/testing/selftests/kvm/include/vmx.h
tools/testing/selftests/kvm/include/vmx.h
+33
-0
tools/testing/selftests/kvm/lib/x86.c
tools/testing/selftests/kvm/lib/x86.c
+29
-0
tools/testing/selftests/kvm/state_test.c
tools/testing/selftests/kvm/state_test.c
+70
-1
No files found.
tools/testing/selftests/kvm/include/vmx.h
View file @
cb547637
...
@@ -380,6 +380,30 @@ static inline int vmptrld(uint64_t vmcs_pa)
...
@@ -380,6 +380,30 @@ static inline int vmptrld(uint64_t vmcs_pa)
return
ret
;
return
ret
;
}
}
static
inline
int
vmptrst
(
uint64_t
*
value
)
{
uint64_t
tmp
;
uint8_t
ret
;
__asm__
__volatile__
(
"vmptrst %[value]; setna %[ret]"
:
[
value
]
"=m"
(
tmp
),
[
ret
]
"=rm"
(
ret
)
:
:
"cc"
,
"memory"
);
*
value
=
tmp
;
return
ret
;
}
/*
* A wrapper around vmptrst that ignores errors and returns zero if the
* vmptrst instruction fails.
*/
static
inline
uint64_t
vmptrstz
(
void
)
{
uint64_t
value
=
0
;
vmptrst
(
&
value
);
return
value
;
}
/*
/*
* No guest state (e.g. GPRs) is established by this vmlaunch.
* No guest state (e.g. GPRs) is established by this vmlaunch.
*/
*/
...
@@ -444,6 +468,15 @@ static inline int vmresume(void)
...
@@ -444,6 +468,15 @@ static inline int vmresume(void)
return
ret
;
return
ret
;
}
}
static
inline
void
vmcall
(
void
)
{
/* Currently, L1 destroys our GPRs during vmexits. */
__asm__
__volatile__
(
"push %%rbp; vmcall; pop %%rbp"
:
:
:
"rax"
,
"rbx"
,
"rcx"
,
"rdx"
,
"rsi"
,
"rdi"
,
"r8"
,
"r9"
,
"r10"
,
"r11"
,
"r12"
,
"r13"
,
"r14"
,
"r15"
);
}
static
inline
int
vmread
(
uint64_t
encoding
,
uint64_t
*
value
)
static
inline
int
vmread
(
uint64_t
encoding
,
uint64_t
*
value
)
{
{
uint64_t
tmp
;
uint64_t
tmp
;
...
...
tools/testing/selftests/kvm/lib/x86.c
View file @
cb547637
...
@@ -736,6 +736,10 @@ struct kvm_x86_state {
...
@@ -736,6 +736,10 @@ struct kvm_x86_state {
struct
kvm_xcrs
xcrs
;
struct
kvm_xcrs
xcrs
;
struct
kvm_sregs
sregs
;
struct
kvm_sregs
sregs
;
struct
kvm_debugregs
debugregs
;
struct
kvm_debugregs
debugregs
;
union
{
struct
kvm_nested_state
nested
;
char
nested_
[
16384
];
};
struct
kvm_msrs
msrs
;
struct
kvm_msrs
msrs
;
};
};
...
@@ -758,6 +762,14 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid)
...
@@ -758,6 +762,14 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid)
struct
kvm_msr_list
*
list
;
struct
kvm_msr_list
*
list
;
struct
kvm_x86_state
*
state
;
struct
kvm_x86_state
*
state
;
int
nmsrs
,
r
,
i
;
int
nmsrs
,
r
,
i
;
static
int
nested_size
=
-
1
;
if
(
nested_size
==
-
1
)
{
nested_size
=
kvm_check_cap
(
KVM_CAP_NESTED_STATE
);
TEST_ASSERT
(
nested_size
<=
sizeof
(
state
->
nested_
),
"Nested state size too big, %i > %zi"
,
nested_size
,
sizeof
(
state
->
nested_
));
}
nmsrs
=
kvm_get_num_msrs
(
vm
);
nmsrs
=
kvm_get_num_msrs
(
vm
);
list
=
malloc
(
sizeof
(
*
list
)
+
nmsrs
*
sizeof
(
list
->
indices
[
0
]));
list
=
malloc
(
sizeof
(
*
list
)
+
nmsrs
*
sizeof
(
list
->
indices
[
0
]));
...
@@ -791,6 +803,17 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid)
...
@@ -791,6 +803,17 @@ struct kvm_x86_state *vcpu_save_state(struct kvm_vm *vm, uint32_t vcpuid)
TEST_ASSERT
(
r
==
0
,
"Unexpected result from KVM_GET_SREGS, r: %i"
,
TEST_ASSERT
(
r
==
0
,
"Unexpected result from KVM_GET_SREGS, r: %i"
,
r
);
r
);
if
(
nested_size
)
{
state
->
nested
.
size
=
sizeof
(
state
->
nested_
);
r
=
ioctl
(
vcpu
->
fd
,
KVM_GET_NESTED_STATE
,
&
state
->
nested
);
TEST_ASSERT
(
r
==
0
,
"Unexpected result from KVM_GET_NESTED_STATE, r: %i"
,
r
);
TEST_ASSERT
(
state
->
nested
.
size
<=
nested_size
,
"Nested state size too big, %i (KVM_CHECK_CAP gave %i)"
,
state
->
nested
.
size
,
nested_size
);
}
else
state
->
nested
.
size
=
0
;
state
->
msrs
.
nmsrs
=
nmsrs
;
state
->
msrs
.
nmsrs
=
nmsrs
;
for
(
i
=
0
;
i
<
nmsrs
;
i
++
)
for
(
i
=
0
;
i
<
nmsrs
;
i
++
)
state
->
msrs
.
entries
[
i
].
index
=
list
->
indices
[
i
];
state
->
msrs
.
entries
[
i
].
index
=
list
->
indices
[
i
];
...
@@ -811,6 +834,12 @@ void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *s
...
@@ -811,6 +834,12 @@ void vcpu_load_state(struct kvm_vm *vm, uint32_t vcpuid, struct kvm_x86_state *s
struct
vcpu
*
vcpu
=
vcpu_find
(
vm
,
vcpuid
);
struct
vcpu
*
vcpu
=
vcpu_find
(
vm
,
vcpuid
);
int
r
;
int
r
;
if
(
state
->
nested
.
size
)
{
r
=
ioctl
(
vcpu
->
fd
,
KVM_SET_NESTED_STATE
,
&
state
->
nested
);
TEST_ASSERT
(
r
==
0
,
"Unexpected result from KVM_SET_NESTED_STATE, r: %i"
,
r
);
}
r
=
ioctl
(
vcpu
->
fd
,
KVM_SET_XSAVE
,
&
state
->
xsave
);
r
=
ioctl
(
vcpu
->
fd
,
KVM_SET_XSAVE
,
&
state
->
xsave
);
TEST_ASSERT
(
r
==
0
,
"Unexpected result from KVM_SET_XSAVE, r: %i"
,
TEST_ASSERT
(
r
==
0
,
"Unexpected result from KVM_SET_XSAVE, r: %i"
,
r
);
r
);
...
...
tools/testing/selftests/kvm/state_test.c
View file @
cb547637
...
@@ -18,6 +18,7 @@
...
@@ -18,6 +18,7 @@
#include "kvm_util.h"
#include "kvm_util.h"
#include "x86.h"
#include "x86.h"
#include "vmx.h"
#define VCPU_ID 5
#define VCPU_ID 5
#define PORT_SYNC 0x1000
#define PORT_SYNC 0x1000
...
@@ -45,16 +46,75 @@ static inline void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1)
...
@@ -45,16 +46,75 @@ static inline void __exit_to_l0(uint16_t port, uint64_t arg0, uint64_t arg1)
static
bool
have_nested_state
;
static
bool
have_nested_state
;
void
guest_code
(
void
)
void
l2_guest_code
(
void
)
{
GUEST_SYNC
(
5
);
/* Exit to L1 */
vmcall
();
GUEST_SYNC
(
7
);
/* Done, exit to L1 and never come back. */
vmcall
();
}
void
l1_guest_code
(
struct
vmx_pages
*
vmx_pages
)
{
#define L2_GUEST_STACK_SIZE 64
unsigned
long
l2_guest_stack
[
L2_GUEST_STACK_SIZE
];
GUEST_ASSERT
(
vmx_pages
->
vmcs_gpa
);
GUEST_ASSERT
(
prepare_for_vmx_operation
(
vmx_pages
));
GUEST_ASSERT
(
vmptrstz
()
==
vmx_pages
->
vmcs_gpa
);
GUEST_SYNC
(
3
);
GUEST_ASSERT
(
vmptrstz
()
==
vmx_pages
->
vmcs_gpa
);
prepare_vmcs
(
vmx_pages
,
l2_guest_code
,
&
l2_guest_stack
[
L2_GUEST_STACK_SIZE
]);
GUEST_SYNC
(
4
);
GUEST_ASSERT
(
vmptrstz
()
==
vmx_pages
->
vmcs_gpa
);
GUEST_ASSERT
(
!
vmlaunch
());
GUEST_ASSERT
(
vmptrstz
()
==
vmx_pages
->
vmcs_gpa
);
GUEST_ASSERT
(
vmreadz
(
VM_EXIT_REASON
)
==
EXIT_REASON_VMCALL
);
/* Check that the launched state is preserved. */
GUEST_ASSERT
(
vmlaunch
());
GUEST_ASSERT
(
!
vmresume
());
GUEST_ASSERT
(
vmreadz
(
VM_EXIT_REASON
)
==
EXIT_REASON_VMCALL
);
GUEST_SYNC
(
6
);
GUEST_ASSERT
(
vmreadz
(
VM_EXIT_REASON
)
==
EXIT_REASON_VMCALL
);
GUEST_ASSERT
(
!
vmresume
());
GUEST_ASSERT
(
vmreadz
(
VM_EXIT_REASON
)
==
EXIT_REASON_VMCALL
);
vmwrite
(
GUEST_RIP
,
vmreadz
(
GUEST_RIP
)
+
3
);
GUEST_ASSERT
(
!
vmresume
());
GUEST_ASSERT
(
vmreadz
(
VM_EXIT_REASON
)
==
EXIT_REASON_VMCALL
);
GUEST_SYNC
(
8
);
}
void
guest_code
(
struct
vmx_pages
*
vmx_pages
)
{
{
GUEST_SYNC
(
1
);
GUEST_SYNC
(
1
);
GUEST_SYNC
(
2
);
GUEST_SYNC
(
2
);
if
(
vmx_pages
)
l1_guest_code
(
vmx_pages
);
exit_to_l0
(
PORT_DONE
,
0
,
0
);
exit_to_l0
(
PORT_DONE
,
0
,
0
);
}
}
int
main
(
int
argc
,
char
*
argv
[])
int
main
(
int
argc
,
char
*
argv
[])
{
{
struct
vmx_pages
*
vmx_pages
=
NULL
;
vm_vaddr_t
vmx_pages_gva
=
0
;
struct
kvm_regs
regs1
,
regs2
;
struct
kvm_regs
regs1
,
regs2
;
struct
kvm_vm
*
vm
;
struct
kvm_vm
*
vm
;
struct
kvm_run
*
run
;
struct
kvm_run
*
run
;
...
@@ -69,6 +129,15 @@ int main(int argc, char *argv[])
...
@@ -69,6 +129,15 @@ int main(int argc, char *argv[])
run
=
vcpu_state
(
vm
,
VCPU_ID
);
run
=
vcpu_state
(
vm
,
VCPU_ID
);
vcpu_regs_get
(
vm
,
VCPU_ID
,
&
regs1
);
vcpu_regs_get
(
vm
,
VCPU_ID
,
&
regs1
);
if
(
kvm_check_cap
(
KVM_CAP_NESTED_STATE
))
{
vmx_pages
=
vcpu_alloc_vmx
(
vm
,
&
vmx_pages_gva
);
vcpu_args_set
(
vm
,
VCPU_ID
,
1
,
vmx_pages_gva
);
}
else
{
printf
(
"will skip nested state checks
\n
"
);
vcpu_args_set
(
vm
,
VCPU_ID
,
1
,
0
);
}
for
(
stage
=
1
;;
stage
++
)
{
for
(
stage
=
1
;;
stage
++
)
{
_vcpu_run
(
vm
,
VCPU_ID
);
_vcpu_run
(
vm
,
VCPU_ID
);
TEST_ASSERT
(
run
->
exit_reason
==
KVM_EXIT_IO
,
TEST_ASSERT
(
run
->
exit_reason
==
KVM_EXIT_IO
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment