Commit 424c3383 authored by Andre Przywara's avatar Andre Przywara Committed by Marc Zyngier

KVM: arm64: vgic-its: Implement basic ITS register handlers

Add emulation for some basic MMIO registers used in the ITS emulation.
This includes:
- GITS_{CTLR,TYPER,IIDR}
- ID registers
- GITS_{CBASER,CREADR,CWRITER}
  (which implement the ITS command buffer handling)
- GITS_BASER<n>

Most of the handlers are pretty straight forward, only the CWRITER
handler is a bit more involved by taking the new its_cmd mutex and
then iterating over the command buffer.
The registers holding base addresses and attributes are sanitised before
storing them.
Signed-off-by: default avatarAndre Przywara <andre.przywara@arm.com>
Reviewed-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
Tested-by: default avatarEric Auger <eric.auger@redhat.com>
Signed-off-by: default avatarMarc Zyngier <marc.zyngier@arm.com>
parent 1085fdc6
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/types.h> #include <linux/types.h>
#include <kvm/iodev.h> #include <kvm/iodev.h>
#include <linux/list.h>
#define VGIC_V3_MAX_CPUS 255 #define VGIC_V3_MAX_CPUS 255
#define VGIC_V2_MAX_CPUS 8 #define VGIC_V2_MAX_CPUS 8
...@@ -136,6 +137,21 @@ struct vgic_its { ...@@ -136,6 +137,21 @@ struct vgic_its {
bool enabled; bool enabled;
bool initialized; bool initialized;
struct vgic_io_device iodev; struct vgic_io_device iodev;
/* These registers correspond to GITS_BASER{0,1} */
u64 baser_device_table;
u64 baser_coll_table;
/* Protects the command queue */
struct mutex cmd_lock;
u64 cbaser;
u32 creadr;
u32 cwriter;
/* Protects the device and collection lists */
struct mutex its_lock;
struct list_head device_list;
struct list_head collection_list;
}; };
struct vgic_dist { struct vgic_dist {
......
This diff is collapsed.
...@@ -23,15 +23,15 @@ ...@@ -23,15 +23,15 @@
#include "vgic-mmio.h" #include "vgic-mmio.h"
/* extract @num bytes at @offset bytes offset in data */ /* extract @num bytes at @offset bytes offset in data */
static unsigned long extract_bytes(unsigned long data, unsigned int offset, unsigned long extract_bytes(unsigned long data, unsigned int offset,
unsigned int num) unsigned int num)
{ {
return (data >> (offset * 8)) & GENMASK_ULL(num * 8 - 1, 0); return (data >> (offset * 8)) & GENMASK_ULL(num * 8 - 1, 0);
} }
/* allows updates of any half of a 64-bit register (or the whole thing) */ /* allows updates of any half of a 64-bit register (or the whole thing) */
static u64 update_64bit_reg(u64 reg, unsigned int offset, unsigned int len, u64 update_64bit_reg(u64 reg, unsigned int offset, unsigned int len,
unsigned long val) unsigned long val)
{ {
int lower = (offset & 4) * 8; int lower = (offset & 4) * 8;
int upper = lower + 8 * len - 1; int upper = lower + 8 * len - 1;
......
...@@ -96,6 +96,12 @@ unsigned long vgic_data_mmio_bus_to_host(const void *val, unsigned int len); ...@@ -96,6 +96,12 @@ unsigned long vgic_data_mmio_bus_to_host(const void *val, unsigned int len);
void vgic_data_host_to_mmio_bus(void *buf, unsigned int len, void vgic_data_host_to_mmio_bus(void *buf, unsigned int len,
unsigned long data); unsigned long data);
unsigned long extract_bytes(unsigned long data, unsigned int offset,
unsigned int num);
u64 update_64bit_reg(u64 reg, unsigned int offset, unsigned int len,
unsigned long val);
unsigned long vgic_mmio_read_raz(struct kvm_vcpu *vcpu, unsigned long vgic_mmio_read_raz(struct kvm_vcpu *vcpu,
gpa_t addr, unsigned int len); gpa_t addr, unsigned int len);
......
...@@ -33,10 +33,16 @@ struct vgic_global __section(.hyp.text) kvm_vgic_global_state; ...@@ -33,10 +33,16 @@ struct vgic_global __section(.hyp.text) kvm_vgic_global_state;
/* /*
* Locking order is always: * Locking order is always:
* vgic_cpu->ap_list_lock * its->cmd_lock (mutex)
* vgic_irq->irq_lock * its->its_lock (mutex)
* vgic_cpu->ap_list_lock
* vgic_irq->irq_lock
* *
* (that is, always take the ap_list_lock before the struct vgic_irq lock). * If you need to take multiple locks, always take the upper lock first,
* then the lower ones, e.g. first take the its_lock, then the irq_lock.
* If you are already holding a lock and need to take a higher one, you
* have to drop the lower ranking lock first and re-aquire it after having
* taken the upper one.
* *
* When taking more than one ap_list_lock at the same time, always take the * When taking more than one ap_list_lock at the same time, always take the
* lowest numbered VCPU's ap_list_lock first, so: * lowest numbered VCPU's ap_list_lock first, so:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment