Skip to content

Commit b33c873

Browse files
committed
Merge tag 'kvm-arm-fixes-for-v4.14' of git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm into kvm-master
KVM/ARM Fixes for v4.14 - Fixes a number of issues with saving/restoring the ITS - Fixes a bug in KVM/ARM when branch profiling is enabled in Hyp mode - Fixes an emulation bug for 32-bit guests when injecting aborts - Fixes a failure to check if a kmalloc succeeds in the ITS emulation
2 parents 4191db2 + c2385ea commit b33c873

6 files changed

Lines changed: 81 additions & 49 deletions

File tree

arch/arm/kvm/emulate.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu)
227227
u32 return_offset = (is_thumb) ? 2 : 4;
228228

229229
kvm_update_psr(vcpu, UND_MODE);
230-
*vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) - return_offset;
230+
*vcpu_reg(vcpu, 14) = *vcpu_pc(vcpu) + return_offset;
231231

232232
/* Branch to exception vector */
233233
*vcpu_pc(vcpu) = exc_vector_base(vcpu) + vect_offset;
@@ -239,10 +239,8 @@ void kvm_inject_undefined(struct kvm_vcpu *vcpu)
239239
*/
240240
static void inject_abt(struct kvm_vcpu *vcpu, bool is_pabt, unsigned long addr)
241241
{
242-
unsigned long cpsr = *vcpu_cpsr(vcpu);
243-
bool is_thumb = (cpsr & PSR_T_BIT);
244242
u32 vect_offset;
245-
u32 return_offset = (is_thumb) ? 4 : 0;
243+
u32 return_offset = (is_pabt) ? 4 : 8;
246244
bool is_lpae;
247245

248246
kvm_update_psr(vcpu, ABT_MODE);

arch/arm/kvm/hyp/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Makefile for Kernel-based Virtual Machine module, HYP part
33
#
44

5-
ccflags-y += -fno-stack-protector
5+
ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
66

77
KVM=../../../../virt/kvm
88

arch/arm64/kvm/hyp/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Makefile for Kernel-based Virtual Machine module, HYP part
33
#
44

5-
ccflags-y += -fno-stack-protector
5+
ccflags-y += -fno-stack-protector -DDISABLE_BRANCH_PROFILING
66

77
KVM=../../../../virt/kvm
88

arch/arm64/kvm/inject_fault.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,26 @@
3333
#define LOWER_EL_AArch64_VECTOR 0x400
3434
#define LOWER_EL_AArch32_VECTOR 0x600
3535

36+
/*
37+
* Table taken from ARMv8 ARM DDI0487B-B, table G1-10.
38+
*/
39+
static const u8 return_offsets[8][2] = {
40+
[0] = { 0, 0 }, /* Reset, unused */
41+
[1] = { 4, 2 }, /* Undefined */
42+
[2] = { 0, 0 }, /* SVC, unused */
43+
[3] = { 4, 4 }, /* Prefetch abort */
44+
[4] = { 8, 8 }, /* Data abort */
45+
[5] = { 0, 0 }, /* HVC, unused */
46+
[6] = { 4, 4 }, /* IRQ, unused */
47+
[7] = { 4, 4 }, /* FIQ, unused */
48+
};
49+
3650
static void prepare_fault32(struct kvm_vcpu *vcpu, u32 mode, u32 vect_offset)
3751
{
3852
unsigned long cpsr;
3953
unsigned long new_spsr_value = *vcpu_cpsr(vcpu);
4054
bool is_thumb = (new_spsr_value & COMPAT_PSR_T_BIT);
41-
u32 return_offset = (is_thumb) ? 4 : 0;
55+
u32 return_offset = return_offsets[vect_offset >> 2][is_thumb];
4256
u32 sctlr = vcpu_cp15(vcpu, c1_SCTLR);
4357

4458
cpsr = mode | COMPAT_PSR_I_BIT;

virt/kvm/arm/arm.c

Lines changed: 14 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1326,21 +1326,12 @@ static void teardown_hyp_mode(void)
13261326
{
13271327
int cpu;
13281328

1329-
if (is_kernel_in_hyp_mode())
1330-
return;
1331-
13321329
free_hyp_pgds();
13331330
for_each_possible_cpu(cpu)
13341331
free_page(per_cpu(kvm_arm_hyp_stack_page, cpu));
13351332
hyp_cpu_pm_exit();
13361333
}
13371334

1338-
static int init_vhe_mode(void)
1339-
{
1340-
kvm_info("VHE mode initialized successfully\n");
1341-
return 0;
1342-
}
1343-
13441335
/**
13451336
* Inits Hyp-mode on all online CPUs
13461337
*/
@@ -1421,8 +1412,6 @@ static int init_hyp_mode(void)
14211412
}
14221413
}
14231414

1424-
kvm_info("Hyp mode initialized successfully\n");
1425-
14261415
return 0;
14271416

14281417
out_err:
@@ -1456,6 +1445,7 @@ int kvm_arch_init(void *opaque)
14561445
{
14571446
int err;
14581447
int ret, cpu;
1448+
bool in_hyp_mode;
14591449

14601450
if (!is_hyp_mode_available()) {
14611451
kvm_err("HYP mode not available\n");
@@ -1474,21 +1464,28 @@ int kvm_arch_init(void *opaque)
14741464
if (err)
14751465
return err;
14761466

1477-
if (is_kernel_in_hyp_mode())
1478-
err = init_vhe_mode();
1479-
else
1467+
in_hyp_mode = is_kernel_in_hyp_mode();
1468+
1469+
if (!in_hyp_mode) {
14801470
err = init_hyp_mode();
1481-
if (err)
1482-
goto out_err;
1471+
if (err)
1472+
goto out_err;
1473+
}
14831474

14841475
err = init_subsystems();
14851476
if (err)
14861477
goto out_hyp;
14871478

1479+
if (in_hyp_mode)
1480+
kvm_info("VHE mode initialized successfully\n");
1481+
else
1482+
kvm_info("Hyp mode initialized successfully\n");
1483+
14881484
return 0;
14891485

14901486
out_hyp:
1491-
teardown_hyp_mode();
1487+
if (!in_hyp_mode)
1488+
teardown_hyp_mode();
14921489
out_err:
14931490
teardown_common_resources();
14941491
return err;

virt/kvm/arm/vgic/vgic-its.c

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1466,6 +1466,16 @@ static void vgic_mmio_write_its_ctlr(struct kvm *kvm, struct vgic_its *its,
14661466
{
14671467
mutex_lock(&its->cmd_lock);
14681468

1469+
/*
1470+
* It is UNPREDICTABLE to enable the ITS if any of the CBASER or
1471+
* device/collection BASER are invalid
1472+
*/
1473+
if (!its->enabled && (val & GITS_CTLR_ENABLE) &&
1474+
(!(its->baser_device_table & GITS_BASER_VALID) ||
1475+
!(its->baser_coll_table & GITS_BASER_VALID) ||
1476+
!(its->cbaser & GITS_CBASER_VALID)))
1477+
goto out;
1478+
14691479
its->enabled = !!(val & GITS_CTLR_ENABLE);
14701480

14711481
/*
@@ -1474,6 +1484,7 @@ static void vgic_mmio_write_its_ctlr(struct kvm *kvm, struct vgic_its *its,
14741484
*/
14751485
vgic_its_process_commands(kvm, its);
14761486

1487+
out:
14771488
mutex_unlock(&its->cmd_lock);
14781489
}
14791490

@@ -1801,37 +1812,33 @@ typedef int (*entry_fn_t)(struct vgic_its *its, u32 id, void *entry,
18011812
static int scan_its_table(struct vgic_its *its, gpa_t base, int size, int esz,
18021813
int start_id, entry_fn_t fn, void *opaque)
18031814
{
1804-
void *entry = kzalloc(esz, GFP_KERNEL);
18051815
struct kvm *kvm = its->dev->kvm;
18061816
unsigned long len = size;
18071817
int id = start_id;
18081818
gpa_t gpa = base;
1819+
char entry[esz];
18091820
int ret;
18101821

1822+
memset(entry, 0, esz);
1823+
18111824
while (len > 0) {
18121825
int next_offset;
18131826
size_t byte_offset;
18141827

18151828
ret = kvm_read_guest(kvm, gpa, entry, esz);
18161829
if (ret)
1817-
goto out;
1830+
return ret;
18181831

18191832
next_offset = fn(its, id, entry, opaque);
1820-
if (next_offset <= 0) {
1821-
ret = next_offset;
1822-
goto out;
1823-
}
1833+
if (next_offset <= 0)
1834+
return next_offset;
18241835

18251836
byte_offset = next_offset * esz;
18261837
id += next_offset;
18271838
gpa += byte_offset;
18281839
len -= byte_offset;
18291840
}
1830-
ret = 1;
1831-
1832-
out:
1833-
kfree(entry);
1834-
return ret;
1841+
return 1;
18351842
}
18361843

18371844
/**
@@ -1940,6 +1947,14 @@ static int vgic_its_save_itt(struct vgic_its *its, struct its_device *device)
19401947
return 0;
19411948
}
19421949

1950+
/**
1951+
* vgic_its_restore_itt - restore the ITT of a device
1952+
*
1953+
* @its: its handle
1954+
* @dev: device handle
1955+
*
1956+
* Return 0 on success, < 0 on error
1957+
*/
19431958
static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
19441959
{
19451960
const struct vgic_its_abi *abi = vgic_its_get_abi(its);
@@ -1951,6 +1966,10 @@ static int vgic_its_restore_itt(struct vgic_its *its, struct its_device *dev)
19511966
ret = scan_its_table(its, base, max_size, ite_esz, 0,
19521967
vgic_its_restore_ite, dev);
19531968

1969+
/* scan_its_table returns +1 if all ITEs are invalid */
1970+
if (ret > 0)
1971+
ret = 0;
1972+
19541973
return ret;
19551974
}
19561975

@@ -2048,11 +2067,12 @@ static int vgic_its_device_cmp(void *priv, struct list_head *a,
20482067
static int vgic_its_save_device_tables(struct vgic_its *its)
20492068
{
20502069
const struct vgic_its_abi *abi = vgic_its_get_abi(its);
2070+
u64 baser = its->baser_device_table;
20512071
struct its_device *dev;
20522072
int dte_esz = abi->dte_esz;
2053-
u64 baser;
20542073

2055-
baser = its->baser_device_table;
2074+
if (!(baser & GITS_BASER_VALID))
2075+
return 0;
20562076

20572077
list_sort(NULL, &its->device_list, vgic_its_device_cmp);
20582078

@@ -2107,10 +2127,7 @@ static int handle_l1_dte(struct vgic_its *its, u32 id, void *addr,
21072127
ret = scan_its_table(its, gpa, SZ_64K, dte_esz,
21082128
l2_start_id, vgic_its_restore_dte, NULL);
21092129

2110-
if (ret <= 0)
2111-
return ret;
2112-
2113-
return 1;
2130+
return ret;
21142131
}
21152132

21162133
/**
@@ -2140,8 +2157,9 @@ static int vgic_its_restore_device_tables(struct vgic_its *its)
21402157
vgic_its_restore_dte, NULL);
21412158
}
21422159

2160+
/* scan_its_table returns +1 if all entries are invalid */
21432161
if (ret > 0)
2144-
ret = -EINVAL;
2162+
ret = 0;
21452163

21462164
return ret;
21472165
}
@@ -2198,17 +2216,17 @@ static int vgic_its_restore_cte(struct vgic_its *its, gpa_t gpa, int esz)
21982216
static int vgic_its_save_collection_table(struct vgic_its *its)
21992217
{
22002218
const struct vgic_its_abi *abi = vgic_its_get_abi(its);
2219+
u64 baser = its->baser_coll_table;
2220+
gpa_t gpa = BASER_ADDRESS(baser);
22012221
struct its_collection *collection;
22022222
u64 val;
2203-
gpa_t gpa;
22042223
size_t max_size, filled = 0;
22052224
int ret, cte_esz = abi->cte_esz;
22062225

2207-
gpa = BASER_ADDRESS(its->baser_coll_table);
2208-
if (!gpa)
2226+
if (!(baser & GITS_BASER_VALID))
22092227
return 0;
22102228

2211-
max_size = GITS_BASER_NR_PAGES(its->baser_coll_table) * SZ_64K;
2229+
max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
22122230

22132231
list_for_each_entry(collection, &its->collection_list, coll_list) {
22142232
ret = vgic_its_save_cte(its, collection, gpa, cte_esz);
@@ -2239,17 +2257,18 @@ static int vgic_its_save_collection_table(struct vgic_its *its)
22392257
static int vgic_its_restore_collection_table(struct vgic_its *its)
22402258
{
22412259
const struct vgic_its_abi *abi = vgic_its_get_abi(its);
2260+
u64 baser = its->baser_coll_table;
22422261
int cte_esz = abi->cte_esz;
22432262
size_t max_size, read = 0;
22442263
gpa_t gpa;
22452264
int ret;
22462265

2247-
if (!(its->baser_coll_table & GITS_BASER_VALID))
2266+
if (!(baser & GITS_BASER_VALID))
22482267
return 0;
22492268

2250-
gpa = BASER_ADDRESS(its->baser_coll_table);
2269+
gpa = BASER_ADDRESS(baser);
22512270

2252-
max_size = GITS_BASER_NR_PAGES(its->baser_coll_table) * SZ_64K;
2271+
max_size = GITS_BASER_NR_PAGES(baser) * SZ_64K;
22532272

22542273
while (read < max_size) {
22552274
ret = vgic_its_restore_cte(its, gpa, cte_esz);
@@ -2258,6 +2277,10 @@ static int vgic_its_restore_collection_table(struct vgic_its *its)
22582277
gpa += cte_esz;
22592278
read += cte_esz;
22602279
}
2280+
2281+
if (ret > 0)
2282+
return 0;
2283+
22612284
return ret;
22622285
}
22632286

0 commit comments

Comments
 (0)