aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Przywara <andre.przywara@arm.com>2017-02-16 05:41:20 -0500
committerMarc Zyngier <marc.zyngier@arm.com>2017-03-07 10:44:08 -0500
commita5e1e6ca94a8cec51571fd62e3eaec269717969c (patch)
tree92998b4189f7545cfca92f1813c0bf0dd0087903
parentba4dd156eabdca93501d92a980ba27fa5f4bbd27 (diff)
KVM: arm/arm64: VGIC: Fix command handling while ITS being disabled
The ITS spec says that ITS commands are only processed when the ITS is enabled (section 8.19.4, Enabled, bit[0]). Our emulation was not taking this into account. Fix this by checking the enabled state before handling CWRITER writes. On the other hand that means that CWRITER could advance while the ITS is disabled, and enabling it would need those commands to be processed. Fix this case as well by refactoring actual command processing and calling this from both the GITS_CWRITER and GITS_CTLR handlers. Reviewed-by: Eric Auger <eric.auger@redhat.com> Reviewed-by: Christoffer Dall <cdall@linaro.org> Signed-off-by: Andre Przywara <andre.przywara@arm.com> Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
-rw-r--r--virt/kvm/arm/vgic/vgic-its.c109
1 files changed, 65 insertions, 44 deletions
diff --git a/virt/kvm/arm/vgic/vgic-its.c b/virt/kvm/arm/vgic/vgic-its.c
index 571b64a01c50..8d1da1af4b09 100644
--- a/virt/kvm/arm/vgic/vgic-its.c
+++ b/virt/kvm/arm/vgic/vgic-its.c
@@ -360,29 +360,6 @@ static int its_sync_lpi_pending_table(struct kvm_vcpu *vcpu)
360 return ret; 360 return ret;
361} 361}
362 362
363static unsigned long vgic_mmio_read_its_ctlr(struct kvm *vcpu,
364 struct vgic_its *its,
365 gpa_t addr, unsigned int len)
366{
367 u32 reg = 0;
368
369 mutex_lock(&its->cmd_lock);
370 if (its->creadr == its->cwriter)
371 reg |= GITS_CTLR_QUIESCENT;
372 if (its->enabled)
373 reg |= GITS_CTLR_ENABLE;
374 mutex_unlock(&its->cmd_lock);
375
376 return reg;
377}
378
379static void vgic_mmio_write_its_ctlr(struct kvm *kvm, struct vgic_its *its,
380 gpa_t addr, unsigned int len,
381 unsigned long val)
382{
383 its->enabled = !!(val & GITS_CTLR_ENABLE);
384}
385
386static unsigned long vgic_mmio_read_its_typer(struct kvm *kvm, 363static unsigned long vgic_mmio_read_its_typer(struct kvm *kvm,
387 struct vgic_its *its, 364 struct vgic_its *its,
388 gpa_t addr, unsigned int len) 365 gpa_t addr, unsigned int len)
@@ -1161,33 +1138,16 @@ static void vgic_mmio_write_its_cbaser(struct kvm *kvm, struct vgic_its *its,
1161#define ITS_CMD_SIZE 32 1138#define ITS_CMD_SIZE 32
1162#define ITS_CMD_OFFSET(reg) ((reg) & GENMASK(19, 5)) 1139#define ITS_CMD_OFFSET(reg) ((reg) & GENMASK(19, 5))
1163 1140
1164/* 1141/* Must be called with the cmd_lock held. */
1165 * By writing to CWRITER the guest announces new commands to be processed. 1142static void vgic_its_process_commands(struct kvm *kvm, struct vgic_its *its)
1166 * To avoid any races in the first place, we take the its_cmd lock, which
1167 * protects our ring buffer variables, so that there is only one user
1168 * per ITS handling commands at a given time.
1169 */
1170static void vgic_mmio_write_its_cwriter(struct kvm *kvm, struct vgic_its *its,
1171 gpa_t addr, unsigned int len,
1172 unsigned long val)
1173{ 1143{
1174 gpa_t cbaser; 1144 gpa_t cbaser;
1175 u64 cmd_buf[4]; 1145 u64 cmd_buf[4];
1176 u32 reg;
1177 1146
1178 if (!its) 1147 /* Commands are only processed when the ITS is enabled. */
1179 return; 1148 if (!its->enabled)
1180
1181 mutex_lock(&its->cmd_lock);
1182
1183 reg = update_64bit_reg(its->cwriter, addr & 7, len, val);
1184 reg = ITS_CMD_OFFSET(reg);
1185 if (reg >= ITS_CMD_BUFFER_SIZE(its->cbaser)) {
1186 mutex_unlock(&its->cmd_lock);
1187 return; 1149 return;
1188 }
1189 1150
1190 its->cwriter = reg;
1191 cbaser = CBASER_ADDRESS(its->cbaser); 1151 cbaser = CBASER_ADDRESS(its->cbaser);
1192 1152
1193 while (its->cwriter != its->creadr) { 1153 while (its->cwriter != its->creadr) {
@@ -1207,6 +1167,34 @@ static void vgic_mmio_write_its_cwriter(struct kvm *kvm, struct vgic_its *its,
1207 if (its->creadr == ITS_CMD_BUFFER_SIZE(its->cbaser)) 1167 if (its->creadr == ITS_CMD_BUFFER_SIZE(its->cbaser))
1208 its->creadr = 0; 1168 its->creadr = 0;
1209 } 1169 }
1170}
1171
1172/*
1173 * By writing to CWRITER the guest announces new commands to be processed.
1174 * To avoid any races in the first place, we take the its_cmd lock, which
1175 * protects our ring buffer variables, so that there is only one user
1176 * per ITS handling commands at a given time.
1177 */
1178static void vgic_mmio_write_its_cwriter(struct kvm *kvm, struct vgic_its *its,
1179 gpa_t addr, unsigned int len,
1180 unsigned long val)
1181{
1182 u64 reg;
1183
1184 if (!its)
1185 return;
1186
1187 mutex_lock(&its->cmd_lock);
1188
1189 reg = update_64bit_reg(its->cwriter, addr & 7, len, val);
1190 reg = ITS_CMD_OFFSET(reg);
1191 if (reg >= ITS_CMD_BUFFER_SIZE(its->cbaser)) {
1192 mutex_unlock(&its->cmd_lock);
1193 return;
1194 }
1195 its->cwriter = reg;
1196
1197 vgic_its_process_commands(kvm, its);
1210 1198
1211 mutex_unlock(&its->cmd_lock); 1199 mutex_unlock(&its->cmd_lock);
1212} 1200}
@@ -1287,6 +1275,39 @@ static void vgic_mmio_write_its_baser(struct kvm *kvm,
1287 *regptr = reg; 1275 *regptr = reg;
1288} 1276}
1289 1277
1278static unsigned long vgic_mmio_read_its_ctlr(struct kvm *vcpu,
1279 struct vgic_its *its,
1280 gpa_t addr, unsigned int len)
1281{
1282 u32 reg = 0;
1283
1284 mutex_lock(&its->cmd_lock);
1285 if (its->creadr == its->cwriter)
1286 reg |= GITS_CTLR_QUIESCENT;
1287 if (its->enabled)
1288 reg |= GITS_CTLR_ENABLE;
1289 mutex_unlock(&its->cmd_lock);
1290
1291 return reg;
1292}
1293
1294static void vgic_mmio_write_its_ctlr(struct kvm *kvm, struct vgic_its *its,
1295 gpa_t addr, unsigned int len,
1296 unsigned long val)
1297{
1298 mutex_lock(&its->cmd_lock);
1299
1300 its->enabled = !!(val & GITS_CTLR_ENABLE);
1301
1302 /*
1303 * Try to process any pending commands. This function bails out early
1304 * if the ITS is disabled or no commands have been queued.
1305 */
1306 vgic_its_process_commands(kvm, its);
1307
1308 mutex_unlock(&its->cmd_lock);
1309}
1310
1290#define REGISTER_ITS_DESC(off, rd, wr, length, acc) \ 1311#define REGISTER_ITS_DESC(off, rd, wr, length, acc) \
1291{ \ 1312{ \
1292 .reg_offset = off, \ 1313 .reg_offset = off, \