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
Kirill Smelkov
linux
Commits
c90aad55
Commit
c90aad55
authored
Apr 13, 2021
by
Marc Zyngier
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'kvm-arm64/vgic-5.13' into kvmarm-master/next
Signed-off-by:
Marc Zyngier
<
maz@kernel.org
>
parents
d8f37d29
94ac0835
Changes
12
Show whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
706 additions
and
45 deletions
+706
-45
Documentation/virt/kvm/devices/arm-vgic-v3.rst
Documentation/virt/kvm/devices/arm-vgic-v3.rst
+1
-1
arch/arm64/kvm/vgic/vgic-init.c
arch/arm64/kvm/vgic/vgic-init.c
+7
-5
arch/arm64/kvm/vgic/vgic-kvm-device.c
arch/arm64/kvm/vgic/vgic-kvm-device.c
+5
-2
arch/arm64/kvm/vgic/vgic-mmio-v3.c
arch/arm64/kvm/vgic/vgic-mmio-v3.c
+50
-31
arch/arm64/kvm/vgic/vgic-mmio.c
arch/arm64/kvm/vgic/vgic-mmio.c
+4
-6
arch/arm64/kvm/vgic/vgic.h
arch/arm64/kvm/vgic/vgic.h
+1
-0
include/kvm/arm_vgic.h
include/kvm/arm_vgic.h
+1
-0
tools/testing/selftests/kvm/.gitignore
tools/testing/selftests/kvm/.gitignore
+1
-0
tools/testing/selftests/kvm/Makefile
tools/testing/selftests/kvm/Makefile
+1
-0
tools/testing/selftests/kvm/aarch64/vgic_init.c
tools/testing/selftests/kvm/aarch64/vgic_init.c
+551
-0
tools/testing/selftests/kvm/include/kvm_util.h
tools/testing/selftests/kvm/include/kvm_util.h
+9
-0
tools/testing/selftests/kvm/lib/kvm_util.c
tools/testing/selftests/kvm/lib/kvm_util.c
+75
-0
No files found.
Documentation/virt/kvm/devices/arm-vgic-v3.rst
View file @
c90aad55
...
...
@@ -228,7 +228,7 @@ Groups:
KVM_DEV_ARM_VGIC_CTRL_INIT
request the initialization of the VGIC, no additional parameter in
kvm_device_attr.addr.
kvm_device_attr.addr.
Must be called after all VCPUs have been created.
KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES
save all LPI pending bits into guest RAM pending tables.
...
...
arch/arm64/kvm/vgic/vgic-init.c
View file @
c90aad55
...
...
@@ -335,13 +335,14 @@ static void kvm_vgic_dist_destroy(struct kvm *kvm)
kfree
(
dist
->
spis
);
dist
->
spis
=
NULL
;
dist
->
nr_spis
=
0
;
dist
->
vgic_dist_base
=
VGIC_ADDR_UNDEF
;
if
(
kvm
->
arch
.
vgic
.
vgic_model
==
KVM_DEV_TYPE_ARM_VGIC_V3
)
{
list_for_each_entry_safe
(
rdreg
,
next
,
&
dist
->
rd_regions
,
list
)
{
list_del
(
&
rdreg
->
list
);
kfree
(
rdreg
);
}
if
(
dist
->
vgic_model
==
KVM_DEV_TYPE_ARM_VGIC_V3
)
{
list_for_each_entry_safe
(
rdreg
,
next
,
&
dist
->
rd_regions
,
list
)
vgic_v3_free_redist_region
(
rdreg
);
INIT_LIST_HEAD
(
&
dist
->
rd_regions
);
}
else
{
dist
->
vgic_cpu_base
=
VGIC_ADDR_UNDEF
;
}
if
(
vgic_has_its
(
kvm
))
...
...
@@ -362,6 +363,7 @@ void kvm_vgic_vcpu_destroy(struct kvm_vcpu *vcpu)
vgic_flush_pending_lpis
(
vcpu
);
INIT_LIST_HEAD
(
&
vgic_cpu
->
ap_list_head
);
vgic_cpu
->
rd_iodev
.
base_addr
=
VGIC_ADDR_UNDEF
;
}
/* To be called with kvm->lock held */
...
...
arch/arm64/kvm/vgic/vgic-kvm-device.c
View file @
c90aad55
...
...
@@ -87,7 +87,7 @@ int kvm_vgic_addr(struct kvm *kvm, unsigned long type, u64 *addr, bool write)
r
=
vgic_v3_set_redist_base
(
kvm
,
0
,
*
addr
,
0
);
goto
out
;
}
rdreg
=
list_first_entry
(
&
vgic
->
rd_regions
,
rdreg
=
list_first_entry
_or_null
(
&
vgic
->
rd_regions
,
struct
vgic_redist_region
,
list
);
if
(
!
rdreg
)
addr_ptr
=
&
undef_value
;
...
...
@@ -226,6 +226,9 @@ static int vgic_get_common_attr(struct kvm_device *dev,
u64
addr
;
unsigned
long
type
=
(
unsigned
long
)
attr
->
attr
;
if
(
copy_from_user
(
&
addr
,
uaddr
,
sizeof
(
addr
)))
return
-
EFAULT
;
r
=
kvm_vgic_addr
(
dev
->
kvm
,
type
,
&
addr
,
false
);
if
(
r
)
return
(
r
==
-
ENODEV
)
?
-
ENXIO
:
r
;
...
...
arch/arm64/kvm/vgic/vgic-mmio-v3.c
View file @
c90aad55
...
...
@@ -251,29 +251,34 @@ static void vgic_mmio_write_v3r_ctlr(struct kvm_vcpu *vcpu,
vgic_enable_lpis
(
vcpu
);
}
static
unsigned
long
vgic_mmio_read_v3r_typer
(
struct
kvm_vcpu
*
vcpu
,
gpa_t
addr
,
unsigned
int
len
)
static
bool
vgic_mmio_vcpu_rdist_is_last
(
struct
kvm_vcpu
*
vcpu
)
{
unsigned
long
mpidr
=
kvm_vcpu_get_mpidr_aff
(
vcpu
)
;
struct
vgic_dist
*
vgic
=
&
vcpu
->
kvm
->
arch
.
vgic
;
struct
vgic_cpu
*
vgic_cpu
=
&
vcpu
->
arch
.
vgic_cpu
;
struct
vgic_redist_region
*
rdreg
=
vgic_cpu
->
rdreg
;
int
target_vcpu_id
=
vcpu
->
vcpu_id
;
gpa_t
last_rdist_typer
=
rdreg
->
base
+
GICR_TYPER
+
(
rdreg
->
free_index
-
1
)
*
KVM_VGIC_V3_REDIST_SIZE
;
u64
value
;
struct
vgic_redist_region
*
iter
,
*
rdreg
=
vgic_cpu
->
rdreg
;
value
=
(
u64
)(
mpidr
&
GENMASK
(
23
,
0
))
<<
32
;
value
|=
((
target_vcpu_id
&
0xffff
)
<<
8
)
;
if
(
!
rdreg
)
return
false
;
if
(
addr
==
last_rdist_typer
)
value
|=
GICR_TYPER_LAST
;
if
(
vgic_has_its
(
vcpu
->
kvm
))
value
|=
GICR_TYPER_PLPIS
;
if
(
vgic_cpu
->
rdreg_index
<
rdreg
->
free_index
-
1
)
{
return
false
;
}
else
if
(
rdreg
->
count
&&
vgic_cpu
->
rdreg_index
==
(
rdreg
->
count
-
1
))
{
struct
list_head
*
rd_regions
=
&
vgic
->
rd_regions
;
gpa_t
end
=
rdreg
->
base
+
rdreg
->
count
*
KVM_VGIC_V3_REDIST_SIZE
;
return
extract_bytes
(
value
,
addr
&
7
,
len
);
/*
* the rdist is the last one of the redist region,
* check whether there is no other contiguous rdist region
*/
list_for_each_entry
(
iter
,
rd_regions
,
list
)
{
if
(
iter
->
base
==
end
&&
iter
->
free_index
>
0
)
return
false
;
}
}
return
true
;
}
static
unsigned
long
vgic_
uaccess
_read_v3r_typer
(
struct
kvm_vcpu
*
vcpu
,
static
unsigned
long
vgic_
mmio
_read_v3r_typer
(
struct
kvm_vcpu
*
vcpu
,
gpa_t
addr
,
unsigned
int
len
)
{
unsigned
long
mpidr
=
kvm_vcpu_get_mpidr_aff
(
vcpu
);
...
...
@@ -286,7 +291,9 @@ static unsigned long vgic_uaccess_read_v3r_typer(struct kvm_vcpu *vcpu,
if
(
vgic_has_its
(
vcpu
->
kvm
))
value
|=
GICR_TYPER_PLPIS
;
/* reporting of the Last bit is not supported for userspace */
if
(
vgic_mmio_vcpu_rdist_is_last
(
vcpu
))
value
|=
GICR_TYPER_LAST
;
return
extract_bytes
(
value
,
addr
&
7
,
len
);
}
...
...
@@ -612,7 +619,7 @@ static const struct vgic_register_region vgic_v3_rd_registers[] = {
VGIC_ACCESS_32bit
),
REGISTER_DESC_WITH_LENGTH_UACCESS
(
GICR_TYPER
,
vgic_mmio_read_v3r_typer
,
vgic_mmio_write_wi
,
vgic_uaccess_read_v3r_typer
,
vgic_mmio_uaccess_write_wi
,
8
,
NULL
,
vgic_mmio_uaccess_write_wi
,
8
,
VGIC_ACCESS_64bit
|
VGIC_ACCESS_32bit
),
REGISTER_DESC_WITH_LENGTH
(
GICR_WAKER
,
vgic_mmio_read_raz
,
vgic_mmio_write_wi
,
4
,
...
...
@@ -714,6 +721,7 @@ int vgic_register_redist_iodev(struct kvm_vcpu *vcpu)
return
-
EINVAL
;
vgic_cpu
->
rdreg
=
rdreg
;
vgic_cpu
->
rdreg_index
=
rdreg
->
free_index
;
rd_base
=
rdreg
->
base
+
rdreg
->
free_index
*
KVM_VGIC_V3_REDIST_SIZE
;
...
...
@@ -768,7 +776,7 @@ static int vgic_register_all_redist_iodevs(struct kvm *kvm)
}
/**
* vgic_v3_
insert_redist_region - Insert
a new redistributor region
* vgic_v3_
alloc_redist_region - Allocate
a new redistributor region
*
* Performs various checks before inserting the rdist region in the list.
* Those tests depend on whether the size of the rdist region is known
...
...
@@ -782,7 +790,7 @@ static int vgic_register_all_redist_iodevs(struct kvm *kvm)
*
* Return 0 on success, < 0 otherwise
*/
static
int
vgic_v3_
insert
_redist_region
(
struct
kvm
*
kvm
,
uint32_t
index
,
static
int
vgic_v3_
alloc
_redist_region
(
struct
kvm
*
kvm
,
uint32_t
index
,
gpa_t
base
,
uint32_t
count
)
{
struct
vgic_dist
*
d
=
&
kvm
->
arch
.
vgic
;
...
...
@@ -791,10 +799,6 @@ static int vgic_v3_insert_redist_region(struct kvm *kvm, uint32_t index,
size_t
size
=
count
*
KVM_VGIC_V3_REDIST_SIZE
;
int
ret
;
/* single rdist region already set ?*/
if
(
!
count
&&
!
list_empty
(
rd_regions
))
return
-
EINVAL
;
/* cross the end of memory ? */
if
(
base
+
size
<
base
)
return
-
EINVAL
;
...
...
@@ -805,11 +809,15 @@ static int vgic_v3_insert_redist_region(struct kvm *kvm, uint32_t index,
}
else
{
rdreg
=
list_last_entry
(
rd_regions
,
struct
vgic_redist_region
,
list
);
if
(
index
!=
rdreg
->
index
+
1
)
/* Don't mix single region and discrete redist regions */
if
(
!
count
&&
rdreg
->
count
)
return
-
EINVAL
;
/* Cannot add an explicitly sized regions after legacy region */
if
(
!
rdreg
->
count
)
if
(
!
count
)
return
-
EEXIST
;
if
(
index
!=
rdreg
->
index
+
1
)
return
-
EINVAL
;
}
...
...
@@ -848,11 +856,17 @@ static int vgic_v3_insert_redist_region(struct kvm *kvm, uint32_t index,
return
ret
;
}
void
vgic_v3_free_redist_region
(
struct
vgic_redist_region
*
rdreg
)
{
list_del
(
&
rdreg
->
list
);
kfree
(
rdreg
);
}
int
vgic_v3_set_redist_base
(
struct
kvm
*
kvm
,
u32
index
,
u64
addr
,
u32
count
)
{
int
ret
;
ret
=
vgic_v3_
insert
_redist_region
(
kvm
,
index
,
addr
,
count
);
ret
=
vgic_v3_
alloc
_redist_region
(
kvm
,
index
,
addr
,
count
);
if
(
ret
)
return
ret
;
...
...
@@ -861,8 +875,13 @@ int vgic_v3_set_redist_base(struct kvm *kvm, u32 index, u64 addr, u32 count)
* afterwards will register the iodevs when needed.
*/
ret
=
vgic_register_all_redist_iodevs
(
kvm
);
if
(
ret
)
if
(
ret
)
{
struct
vgic_redist_region
*
rdreg
;
rdreg
=
vgic_v3_rdist_region_from_index
(
kvm
,
index
);
vgic_v3_free_redist_region
(
rdreg
);
return
ret
;
}
return
0
;
}
...
...
arch/arm64/kvm/vgic/vgic-mmio.c
View file @
c90aad55
...
...
@@ -938,10 +938,9 @@ vgic_get_mmio_region(struct kvm_vcpu *vcpu, struct vgic_io_device *iodev,
return
region
;
}
static
int
vgic_uaccess_read
(
struct
kvm_vcpu
*
vcpu
,
struct
kvm_io_device
*
dev
,
static
int
vgic_uaccess_read
(
struct
kvm_vcpu
*
vcpu
,
struct
vgic_io_device
*
io
dev
,
gpa_t
addr
,
u32
*
val
)
{
struct
vgic_io_device
*
iodev
=
kvm_to_vgic_iodev
(
dev
);
const
struct
vgic_register_region
*
region
;
struct
kvm_vcpu
*
r_vcpu
;
...
...
@@ -960,10 +959,9 @@ static int vgic_uaccess_read(struct kvm_vcpu *vcpu, struct kvm_io_device *dev,
return
0
;
}
static
int
vgic_uaccess_write
(
struct
kvm_vcpu
*
vcpu
,
struct
kvm_io_device
*
dev
,
static
int
vgic_uaccess_write
(
struct
kvm_vcpu
*
vcpu
,
struct
vgic_io_device
*
io
dev
,
gpa_t
addr
,
const
u32
*
val
)
{
struct
vgic_io_device
*
iodev
=
kvm_to_vgic_iodev
(
dev
);
const
struct
vgic_register_region
*
region
;
struct
kvm_vcpu
*
r_vcpu
;
...
...
@@ -986,9 +984,9 @@ int vgic_uaccess(struct kvm_vcpu *vcpu, struct vgic_io_device *dev,
bool
is_write
,
int
offset
,
u32
*
val
)
{
if
(
is_write
)
return
vgic_uaccess_write
(
vcpu
,
&
dev
->
dev
,
offset
,
val
);
return
vgic_uaccess_write
(
vcpu
,
dev
,
offset
,
val
);
else
return
vgic_uaccess_read
(
vcpu
,
&
dev
->
dev
,
offset
,
val
);
return
vgic_uaccess_read
(
vcpu
,
dev
,
offset
,
val
);
}
static
int
dispatch_mmio_read
(
struct
kvm_vcpu
*
vcpu
,
struct
kvm_io_device
*
dev
,
...
...
arch/arm64/kvm/vgic/vgic.h
View file @
c90aad55
...
...
@@ -293,6 +293,7 @@ vgic_v3_rd_region_size(struct kvm *kvm, struct vgic_redist_region *rdreg)
struct
vgic_redist_region
*
vgic_v3_rdist_region_from_index
(
struct
kvm
*
kvm
,
u32
index
);
void
vgic_v3_free_redist_region
(
struct
vgic_redist_region
*
rdreg
);
bool
vgic_v3_rdist_overlap
(
struct
kvm
*
kvm
,
gpa_t
base
,
size_t
size
);
...
...
include/kvm/arm_vgic.h
View file @
c90aad55
...
...
@@ -322,6 +322,7 @@ struct vgic_cpu {
*/
struct
vgic_io_device
rd_iodev
;
struct
vgic_redist_region
*
rdreg
;
u32
rdreg_index
;
/* Contains the attributes and gpa of the LPI pending tables. */
u64
pendbaser
;
...
...
tools/testing/selftests/kvm/.gitignore
View file @
c90aad55
# SPDX-License-Identifier: GPL-2.0-only
/aarch64/get-reg-list
/aarch64/get-reg-list-sve
/aarch64/vgic_init
/s390x/memop
/s390x/resets
/s390x/sync_regs_test
...
...
tools/testing/selftests/kvm/Makefile
View file @
c90aad55
...
...
@@ -75,6 +75,7 @@ TEST_GEN_PROGS_x86_64 += steal_time
TEST_GEN_PROGS_aarch64
+=
aarch64/get-reg-list
TEST_GEN_PROGS_aarch64
+=
aarch64/get-reg-list-sve
TEST_GEN_PROGS_aarch64
+=
aarch64/vgic_init
TEST_GEN_PROGS_aarch64
+=
demand_paging_test
TEST_GEN_PROGS_aarch64
+=
dirty_log_test
TEST_GEN_PROGS_aarch64
+=
dirty_log_perf_test
...
...
tools/testing/selftests/kvm/aarch64/vgic_init.c
0 → 100644
View file @
c90aad55
// SPDX-License-Identifier: GPL-2.0
/*
* vgic init sequence tests
*
* Copyright (C) 2020, Red Hat, Inc.
*/
#define _GNU_SOURCE
#include <linux/kernel.h>
#include <sys/syscall.h>
#include <asm/kvm.h>
#include <asm/kvm_para.h>
#include "test_util.h"
#include "kvm_util.h"
#include "processor.h"
#define NR_VCPUS 4
#define REDIST_REGION_ATTR_ADDR(count, base, flags, index) (((uint64_t)(count) << 52) | \
((uint64_t)((base) >> 16) << 16) | ((uint64_t)(flags) << 12) | index)
#define REG_OFFSET(vcpu, offset) (((uint64_t)vcpu << 32) | offset)
#define GICR_TYPER 0x8
struct
vm_gic
{
struct
kvm_vm
*
vm
;
int
gic_fd
;
};
static
int
max_ipa_bits
;
/* helper to access a redistributor register */
static
int
access_redist_reg
(
int
gicv3_fd
,
int
vcpu
,
int
offset
,
uint32_t
*
val
,
bool
write
)
{
uint64_t
attr
=
REG_OFFSET
(
vcpu
,
offset
);
return
_kvm_device_access
(
gicv3_fd
,
KVM_DEV_ARM_VGIC_GRP_REDIST_REGS
,
attr
,
val
,
write
);
}
/* dummy guest code */
static
void
guest_code
(
void
)
{
GUEST_SYNC
(
0
);
GUEST_SYNC
(
1
);
GUEST_SYNC
(
2
);
GUEST_DONE
();
}
/* we don't want to assert on run execution, hence that helper */
static
int
run_vcpu
(
struct
kvm_vm
*
vm
,
uint32_t
vcpuid
)
{
ucall_init
(
vm
,
NULL
);
int
ret
=
_vcpu_ioctl
(
vm
,
vcpuid
,
KVM_RUN
,
NULL
);
if
(
ret
)
return
-
errno
;
return
0
;
}
static
struct
vm_gic
vm_gic_create
(
void
)
{
struct
vm_gic
v
;
v
.
vm
=
vm_create_default_with_vcpus
(
NR_VCPUS
,
0
,
0
,
guest_code
,
NULL
);
v
.
gic_fd
=
kvm_create_device
(
v
.
vm
,
KVM_DEV_TYPE_ARM_VGIC_V3
,
false
);
return
v
;
}
static
void
vm_gic_destroy
(
struct
vm_gic
*
v
)
{
close
(
v
->
gic_fd
);
kvm_vm_free
(
v
->
vm
);
}
/**
* Helper routine that performs KVM device tests in general and
* especially ARM_VGIC_V3 ones. Eventually the ARM_VGIC_V3
* device gets created, a legacy RDIST region is set at @0x0
* and a DIST region is set @0x60000
*/
static
void
subtest_dist_rdist
(
struct
vm_gic
*
v
)
{
int
ret
;
uint64_t
addr
;
/* Check existing group/attributes */
kvm_device_check_attr
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_DIST
);
kvm_device_check_attr
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST
);
/* check non existing attribute */
ret
=
_kvm_device_check_attr
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
0
);
TEST_ASSERT
(
ret
&&
errno
==
ENXIO
,
"attribute not supported"
);
/* misaligned DIST and REDIST address settings */
addr
=
0x1000
;
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_DIST
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"GICv3 dist base not 64kB aligned"
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"GICv3 redist base not 64kB aligned"
);
/* out of range address */
if
(
max_ipa_bits
)
{
addr
=
1ULL
<<
max_ipa_bits
;
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_DIST
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
E2BIG
,
"dist address beyond IPA limit"
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
E2BIG
,
"redist address beyond IPA limit"
);
}
/* set REDIST base address @0x0*/
addr
=
0x00000
;
kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST
,
&
addr
,
true
);
/* Attempt to create a second legacy redistributor region */
addr
=
0xE0000
;
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EEXIST
,
"GICv3 redist base set again"
);
/* Attempt to mix legacy and new redistributor regions */
addr
=
REDIST_REGION_ATTR_ADDR
(
NR_VCPUS
,
0x100000
,
0
,
0
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"attempt to mix GICv3 REDIST and REDIST_REGION"
);
/*
* Set overlapping DIST / REDIST, cannot be detected here. Will be detected
* on first vcpu run instead.
*/
addr
=
3
*
2
*
0x10000
;
kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_DIST
,
&
addr
,
true
);
}
/* Test the new REDIST region API */
static
void
subtest_redist_regions
(
struct
vm_gic
*
v
)
{
uint64_t
addr
,
expected_addr
;
int
ret
;
ret
=
kvm_device_check_attr
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST
);
TEST_ASSERT
(
!
ret
,
"Multiple redist regions advertised"
);
addr
=
REDIST_REGION_ATTR_ADDR
(
NR_VCPUS
,
0x100000
,
2
,
0
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"redist region attr value with flags != 0"
);
addr
=
REDIST_REGION_ATTR_ADDR
(
0
,
0x100000
,
0
,
0
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"redist region attr value with count== 0"
);
addr
=
REDIST_REGION_ATTR_ADDR
(
2
,
0x200000
,
0
,
1
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"attempt to register the first rdist region with index != 0"
);
addr
=
REDIST_REGION_ATTR_ADDR
(
2
,
0x201000
,
0
,
1
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"rdist region with misaligned address"
);
addr
=
REDIST_REGION_ATTR_ADDR
(
2
,
0x200000
,
0
,
0
);
kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
addr
=
REDIST_REGION_ATTR_ADDR
(
2
,
0x200000
,
0
,
1
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"register an rdist region with already used index"
);
addr
=
REDIST_REGION_ATTR_ADDR
(
1
,
0x210000
,
0
,
2
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"register an rdist region overlapping with another one"
);
addr
=
REDIST_REGION_ATTR_ADDR
(
1
,
0x240000
,
0
,
2
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"register redist region with index not +1"
);
addr
=
REDIST_REGION_ATTR_ADDR
(
1
,
0x240000
,
0
,
1
);
kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
addr
=
REDIST_REGION_ATTR_ADDR
(
1
,
1ULL
<<
max_ipa_bits
,
0
,
2
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
E2BIG
,
"register redist region with base address beyond IPA range"
);
addr
=
0x260000
;
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"Mix KVM_VGIC_V3_ADDR_TYPE_REDIST and REDIST_REGION"
);
/*
* Now there are 2 redist regions:
* region 0 @ 0x200000 2 redists
* region 1 @ 0x240000 1 redist
* Attempt to read their characteristics
*/
addr
=
REDIST_REGION_ATTR_ADDR
(
0
,
0
,
0
,
0
);
expected_addr
=
REDIST_REGION_ATTR_ADDR
(
2
,
0x200000
,
0
,
0
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
false
);
TEST_ASSERT
(
!
ret
&&
addr
==
expected_addr
,
"read characteristics of region #0"
);
addr
=
REDIST_REGION_ATTR_ADDR
(
0
,
0
,
0
,
1
);
expected_addr
=
REDIST_REGION_ATTR_ADDR
(
1
,
0x240000
,
0
,
1
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
false
);
TEST_ASSERT
(
!
ret
&&
addr
==
expected_addr
,
"read characteristics of region #1"
);
addr
=
REDIST_REGION_ATTR_ADDR
(
0
,
0
,
0
,
2
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
false
);
TEST_ASSERT
(
ret
&&
errno
==
ENOENT
,
"read characteristics of non existing region"
);
addr
=
0x260000
;
kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_DIST
,
&
addr
,
true
);
addr
=
REDIST_REGION_ATTR_ADDR
(
1
,
0x260000
,
0
,
2
);
ret
=
_kvm_device_access
(
v
->
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"register redist region colliding with dist"
);
}
/*
* VGIC KVM device is created and initialized before the secondary CPUs
* get created
*/
static
void
test_vgic_then_vcpus
(
void
)
{
struct
vm_gic
v
;
int
ret
,
i
;
v
.
vm
=
vm_create_default
(
0
,
0
,
guest_code
);
v
.
gic_fd
=
kvm_create_device
(
v
.
vm
,
KVM_DEV_TYPE_ARM_VGIC_V3
,
false
);
subtest_dist_rdist
(
&
v
);
/* Add the rest of the VCPUs */
for
(
i
=
1
;
i
<
NR_VCPUS
;
++
i
)
vm_vcpu_add_default
(
v
.
vm
,
i
,
guest_code
);
ret
=
run_vcpu
(
v
.
vm
,
3
);
TEST_ASSERT
(
ret
==
-
EINVAL
,
"dist/rdist overlap detected on 1st vcpu run"
);
vm_gic_destroy
(
&
v
);
}
/* All the VCPUs are created before the VGIC KVM device gets initialized */
static
void
test_vcpus_then_vgic
(
void
)
{
struct
vm_gic
v
;
int
ret
;
v
=
vm_gic_create
();
subtest_dist_rdist
(
&
v
);
ret
=
run_vcpu
(
v
.
vm
,
3
);
TEST_ASSERT
(
ret
==
-
EINVAL
,
"dist/rdist overlap detected on 1st vcpu run"
);
vm_gic_destroy
(
&
v
);
}
static
void
test_new_redist_regions
(
void
)
{
void
*
dummy
=
NULL
;
struct
vm_gic
v
;
uint64_t
addr
;
int
ret
;
v
=
vm_gic_create
();
subtest_redist_regions
(
&
v
);
kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_CTRL
,
KVM_DEV_ARM_VGIC_CTRL_INIT
,
NULL
,
true
);
ret
=
run_vcpu
(
v
.
vm
,
3
);
TEST_ASSERT
(
ret
==
-
ENXIO
,
"running without sufficient number of rdists"
);
vm_gic_destroy
(
&
v
);
/* step2 */
v
=
vm_gic_create
();
subtest_redist_regions
(
&
v
);
addr
=
REDIST_REGION_ATTR_ADDR
(
1
,
0x280000
,
0
,
2
);
kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
ret
=
run_vcpu
(
v
.
vm
,
3
);
TEST_ASSERT
(
ret
==
-
EBUSY
,
"running without vgic explicit init"
);
vm_gic_destroy
(
&
v
);
/* step 3 */
v
=
vm_gic_create
();
subtest_redist_regions
(
&
v
);
_kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
dummy
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EFAULT
,
"register a third region allowing to cover the 4 vcpus"
);
addr
=
REDIST_REGION_ATTR_ADDR
(
1
,
0x280000
,
0
,
2
);
kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_CTRL
,
KVM_DEV_ARM_VGIC_CTRL_INIT
,
NULL
,
true
);
ret
=
run_vcpu
(
v
.
vm
,
3
);
TEST_ASSERT
(
!
ret
,
"vcpu run"
);
vm_gic_destroy
(
&
v
);
}
static
void
test_typer_accesses
(
void
)
{
struct
vm_gic
v
;
uint64_t
addr
;
uint32_t
val
;
int
ret
,
i
;
v
.
vm
=
vm_create_default
(
0
,
0
,
guest_code
);
v
.
gic_fd
=
kvm_create_device
(
v
.
vm
,
KVM_DEV_TYPE_ARM_VGIC_V3
,
false
);
vm_vcpu_add_default
(
v
.
vm
,
3
,
guest_code
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
1
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"attempting to read GICR_TYPER of non created vcpu"
);
vm_vcpu_add_default
(
v
.
vm
,
1
,
guest_code
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
1
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
ret
&&
errno
==
EBUSY
,
"read GICR_TYPER before GIC initialized"
);
vm_vcpu_add_default
(
v
.
vm
,
2
,
guest_code
);
kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_CTRL
,
KVM_DEV_ARM_VGIC_CTRL_INIT
,
NULL
,
true
);
for
(
i
=
0
;
i
<
NR_VCPUS
;
i
++
)
{
ret
=
access_redist_reg
(
v
.
gic_fd
,
0
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
!
val
,
"read GICR_TYPER before rdist region setting"
);
}
addr
=
REDIST_REGION_ATTR_ADDR
(
2
,
0x200000
,
0
,
0
);
kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
/* The 2 first rdists should be put there (vcpu 0 and 3) */
ret
=
access_redist_reg
(
v
.
gic_fd
,
0
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
!
val
,
"read typer of rdist #0"
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
3
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x310
,
"read typer of rdist #1"
);
addr
=
REDIST_REGION_ATTR_ADDR
(
10
,
0x100000
,
0
,
1
);
ret
=
_kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"collision with previous rdist region"
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
1
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x100
,
"no redist region attached to vcpu #1 yet, last cannot be returned"
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
2
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x200
,
"no redist region attached to vcpu #2, last cannot be returned"
);
addr
=
REDIST_REGION_ATTR_ADDR
(
10
,
0x20000
,
0
,
1
);
kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
1
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x100
,
"read typer of rdist #1"
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
2
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x210
,
"read typer of rdist #1, last properly returned"
);
vm_gic_destroy
(
&
v
);
}
/**
* Test GICR_TYPER last bit with new redist regions
* rdist regions #1 and #2 are contiguous
* rdist region #0 @0x100000 2 rdist capacity
* rdists: 0, 3 (Last)
* rdist region #1 @0x240000 2 rdist capacity
* rdists: 5, 4 (Last)
* rdist region #2 @0x200000 2 rdist capacity
* rdists: 1, 2
*/
static
void
test_last_bit_redist_regions
(
void
)
{
uint32_t
vcpuids
[]
=
{
0
,
3
,
5
,
4
,
1
,
2
};
struct
vm_gic
v
;
uint64_t
addr
;
uint32_t
val
;
int
ret
;
v
.
vm
=
vm_create_default_with_vcpus
(
6
,
0
,
0
,
guest_code
,
vcpuids
);
v
.
gic_fd
=
kvm_create_device
(
v
.
vm
,
KVM_DEV_TYPE_ARM_VGIC_V3
,
false
);
kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_CTRL
,
KVM_DEV_ARM_VGIC_CTRL_INIT
,
NULL
,
true
);
addr
=
REDIST_REGION_ATTR_ADDR
(
2
,
0x100000
,
0
,
0
);
kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
addr
=
REDIST_REGION_ATTR_ADDR
(
2
,
0x240000
,
0
,
1
);
kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
addr
=
REDIST_REGION_ATTR_ADDR
(
2
,
0x200000
,
0
,
2
);
kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION
,
&
addr
,
true
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
0
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x000
,
"read typer of rdist #0"
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
1
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x100
,
"read typer of rdist #1"
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
2
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x200
,
"read typer of rdist #2"
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
3
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x310
,
"read typer of rdist #3"
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
5
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x500
,
"read typer of rdist #5"
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
4
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x410
,
"read typer of rdist #4"
);
vm_gic_destroy
(
&
v
);
}
/* Test last bit with legacy region */
static
void
test_last_bit_single_rdist
(
void
)
{
uint32_t
vcpuids
[]
=
{
0
,
3
,
5
,
4
,
1
,
2
};
struct
vm_gic
v
;
uint64_t
addr
;
uint32_t
val
;
int
ret
;
v
.
vm
=
vm_create_default_with_vcpus
(
6
,
0
,
0
,
guest_code
,
vcpuids
);
v
.
gic_fd
=
kvm_create_device
(
v
.
vm
,
KVM_DEV_TYPE_ARM_VGIC_V3
,
false
);
kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_CTRL
,
KVM_DEV_ARM_VGIC_CTRL_INIT
,
NULL
,
true
);
addr
=
0x10000
;
kvm_device_access
(
v
.
gic_fd
,
KVM_DEV_ARM_VGIC_GRP_ADDR
,
KVM_VGIC_V3_ADDR_TYPE_REDIST
,
&
addr
,
true
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
0
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x000
,
"read typer of rdist #0"
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
3
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x300
,
"read typer of rdist #1"
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
5
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x500
,
"read typer of rdist #2"
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
1
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x100
,
"read typer of rdist #3"
);
ret
=
access_redist_reg
(
v
.
gic_fd
,
2
,
GICR_TYPER
,
&
val
,
false
);
TEST_ASSERT
(
!
ret
&&
val
==
0x210
,
"read typer of rdist #3"
);
vm_gic_destroy
(
&
v
);
}
void
test_kvm_device
(
void
)
{
struct
vm_gic
v
;
int
ret
,
fd
;
v
.
vm
=
vm_create_default_with_vcpus
(
NR_VCPUS
,
0
,
0
,
guest_code
,
NULL
);
/* try to create a non existing KVM device */
ret
=
_kvm_create_device
(
v
.
vm
,
0
,
true
,
&
fd
);
TEST_ASSERT
(
ret
&&
errno
==
ENODEV
,
"unsupported device"
);
/* trial mode with VGIC_V3 device */
ret
=
_kvm_create_device
(
v
.
vm
,
KVM_DEV_TYPE_ARM_VGIC_V3
,
true
,
&
fd
);
if
(
ret
)
{
print_skip
(
"GICv3 not supported"
);
exit
(
KSFT_SKIP
);
}
v
.
gic_fd
=
kvm_create_device
(
v
.
vm
,
KVM_DEV_TYPE_ARM_VGIC_V3
,
false
);
ret
=
_kvm_create_device
(
v
.
vm
,
KVM_DEV_TYPE_ARM_VGIC_V3
,
false
,
&
fd
);
TEST_ASSERT
(
ret
&&
errno
==
EEXIST
,
"create GICv3 device twice"
);
kvm_create_device
(
v
.
vm
,
KVM_DEV_TYPE_ARM_VGIC_V3
,
true
);
if
(
!
_kvm_create_device
(
v
.
vm
,
KVM_DEV_TYPE_ARM_VGIC_V2
,
true
,
&
fd
))
{
ret
=
_kvm_create_device
(
v
.
vm
,
KVM_DEV_TYPE_ARM_VGIC_V2
,
false
,
&
fd
);
TEST_ASSERT
(
ret
&&
errno
==
EINVAL
,
"create GICv2 while v3 exists"
);
}
vm_gic_destroy
(
&
v
);
}
int
main
(
int
ac
,
char
**
av
)
{
max_ipa_bits
=
kvm_check_cap
(
KVM_CAP_ARM_VM_IPA_SIZE
);
test_kvm_device
();
test_vcpus_then_vgic
();
test_vgic_then_vcpus
();
test_new_redist_regions
();
test_typer_accesses
();
test_last_bit_redist_regions
();
test_last_bit_single_rdist
();
return
0
;
}
tools/testing/selftests/kvm/include/kvm_util.h
View file @
c90aad55
...
...
@@ -223,6 +223,15 @@ int vcpu_nested_state_set(struct kvm_vm *vm, uint32_t vcpuid,
#endif
void
*
vcpu_map_dirty_ring
(
struct
kvm_vm
*
vm
,
uint32_t
vcpuid
);
int
_kvm_device_check_attr
(
int
dev_fd
,
uint32_t
group
,
uint64_t
attr
);
int
kvm_device_check_attr
(
int
dev_fd
,
uint32_t
group
,
uint64_t
attr
);
int
_kvm_create_device
(
struct
kvm_vm
*
vm
,
uint64_t
type
,
bool
test
,
int
*
fd
);
int
kvm_create_device
(
struct
kvm_vm
*
vm
,
uint64_t
type
,
bool
test
);
int
_kvm_device_access
(
int
dev_fd
,
uint32_t
group
,
uint64_t
attr
,
void
*
val
,
bool
write
);
int
kvm_device_access
(
int
dev_fd
,
uint32_t
group
,
uint64_t
attr
,
void
*
val
,
bool
write
);
const
char
*
exit_reason_str
(
unsigned
int
exit_reason
);
void
virt_pgd_alloc
(
struct
kvm_vm
*
vm
,
uint32_t
pgd_memslot
);
...
...
tools/testing/selftests/kvm/lib/kvm_util.c
View file @
c90aad55
...
...
@@ -1728,6 +1728,81 @@ int _kvm_ioctl(struct kvm_vm *vm, unsigned long cmd, void *arg)
return
ioctl
(
vm
->
kvm_fd
,
cmd
,
arg
);
}
/*
* Device Ioctl
*/
int
_kvm_device_check_attr
(
int
dev_fd
,
uint32_t
group
,
uint64_t
attr
)
{
struct
kvm_device_attr
attribute
=
{
.
group
=
group
,
.
attr
=
attr
,
.
flags
=
0
,
};
return
ioctl
(
dev_fd
,
KVM_HAS_DEVICE_ATTR
,
&
attribute
);
}
int
kvm_device_check_attr
(
int
dev_fd
,
uint32_t
group
,
uint64_t
attr
)
{
int
ret
=
_kvm_device_check_attr
(
dev_fd
,
group
,
attr
);
TEST_ASSERT
(
ret
>=
0
,
"KVM_HAS_DEVICE_ATTR failed, rc: %i errno: %i"
,
ret
,
errno
);
return
ret
;
}
int
_kvm_create_device
(
struct
kvm_vm
*
vm
,
uint64_t
type
,
bool
test
,
int
*
fd
)
{
struct
kvm_create_device
create_dev
;
int
ret
;
create_dev
.
type
=
type
;
create_dev
.
fd
=
-
1
;
create_dev
.
flags
=
test
?
KVM_CREATE_DEVICE_TEST
:
0
;
ret
=
ioctl
(
vm_get_fd
(
vm
),
KVM_CREATE_DEVICE
,
&
create_dev
);
*
fd
=
create_dev
.
fd
;
return
ret
;
}
int
kvm_create_device
(
struct
kvm_vm
*
vm
,
uint64_t
type
,
bool
test
)
{
int
fd
,
ret
;
ret
=
_kvm_create_device
(
vm
,
type
,
test
,
&
fd
);
if
(
!
test
)
{
TEST_ASSERT
(
ret
>=
0
,
"KVM_CREATE_DEVICE IOCTL failed, rc: %i errno: %i"
,
ret
,
errno
);
return
fd
;
}
return
ret
;
}
int
_kvm_device_access
(
int
dev_fd
,
uint32_t
group
,
uint64_t
attr
,
void
*
val
,
bool
write
)
{
struct
kvm_device_attr
kvmattr
=
{
.
group
=
group
,
.
attr
=
attr
,
.
flags
=
0
,
.
addr
=
(
uintptr_t
)
val
,
};
int
ret
;
ret
=
ioctl
(
dev_fd
,
write
?
KVM_SET_DEVICE_ATTR
:
KVM_GET_DEVICE_ATTR
,
&
kvmattr
);
return
ret
;
}
int
kvm_device_access
(
int
dev_fd
,
uint32_t
group
,
uint64_t
attr
,
void
*
val
,
bool
write
)
{
int
ret
=
_kvm_device_access
(
dev_fd
,
group
,
attr
,
val
,
write
);
TEST_ASSERT
(
ret
>=
0
,
"KVM_SET|GET_DEVICE_ATTR IOCTL failed, rc: %i errno: %i"
,
ret
,
errno
);
return
ret
;
}
/*
* VM Dump
*
...
...
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