Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion libsel4vm/arch_include/arm/sel4vm/arch/guest_vm_arch.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,14 @@ typedef int (*unhandled_vcpu_fault_callback_fn)(vm_vcpu_t *vcpu, uint32_t hsr, v
#define VM_FAULT_EP_SLOT 1
#define VM_CSPACE_SLOT VM_FAULT_EP_SLOT + CONFIG_MAX_NUM_NODES

struct vm_arch {};
struct vm_arch {

/* Details about the GIC context are implementation specific and thus
* completely opaque. All we can provide in the VM data structure is space
* for a context pointer.
*/
void *vgic_context;
};

/***
* @struct vm_vcpu_arch
Expand Down
24 changes: 24 additions & 0 deletions libsel4vm/src/arch/arm/vgic/gicv2.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,27 @@ struct gic_dist_map {
uint32_t periph_id[12]; /* [0xFC0, 0xFF0) */
uint32_t component_id[4]; /* [0xFF0, 0xFFF] */
};

static inline bool gic_dist_is_enabled(vgic_t *vgic)
{
return (0 != vgic->dist->enable);
}

static inline void vgic_dist_set_ctlr(vgic_t *vgic, uint32_t data)
{
/* ToDo: we should care about bit 0 only and ignore all the others. */

switch (data) {
case 0:
DDIST("disabling gic distributor\n");
vgic->dist->enable = 0;
break;
case 1:
DDIST("enabling gic distributor\n");
vgic->dist->enable = 1;
break;
default:
ZF_LOGE("Unknown dist ctlr encoding 0x%x", data);
break;
}
}
152 changes: 64 additions & 88 deletions libsel4vm/src/arch/arm/vgic/vdist.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,139 +27,121 @@
#define IRQ_BIT(irq) (1U << ((irq) % 32))


static inline void set_sgi_ppi_pending(struct gic_dist_map *gic_dist, int irq, bool set_pending, int vcpu_id)
static inline void set_sgi_ppi_pending(vgic_t *vgic, int irq, bool set_pending, int vcpu_id)
{
if (set_pending) {
gic_dist->pending_set0[vcpu_id] |= IRQ_BIT(irq);
gic_dist->pending_clr0[vcpu_id] |= IRQ_BIT(irq);
vgic->dist->pending_set0[vcpu_id] |= IRQ_BIT(irq);
vgic->dist->pending_clr0[vcpu_id] |= IRQ_BIT(irq);
} else {
gic_dist->pending_set0[vcpu_id] &= ~IRQ_BIT(irq);
gic_dist->pending_clr0[vcpu_id] &= ~IRQ_BIT(irq);
vgic->dist->pending_set0[vcpu_id] &= ~IRQ_BIT(irq);
vgic->dist->pending_clr0[vcpu_id] &= ~IRQ_BIT(irq);
}
}

static inline void set_spi_pending(struct gic_dist_map *gic_dist, int irq, bool set_pending)
static inline void set_spi_pending(vgic_t *vgic, int irq, bool set_pending)
{
if (set_pending) {
gic_dist->pending_set[IRQ_IDX(irq)] |= IRQ_BIT(irq);
gic_dist->pending_clr[IRQ_IDX(irq)] |= IRQ_BIT(irq);
vgic->dist->pending_set[IRQ_IDX(irq)] |= IRQ_BIT(irq);
vgic->dist->pending_clr[IRQ_IDX(irq)] |= IRQ_BIT(irq);
} else {
gic_dist->pending_set[IRQ_IDX(irq)] &= ~IRQ_BIT(irq);
gic_dist->pending_clr[IRQ_IDX(irq)] &= ~IRQ_BIT(irq);
vgic->dist->pending_set[IRQ_IDX(irq)] &= ~IRQ_BIT(irq);
vgic->dist->pending_clr[IRQ_IDX(irq)] &= ~IRQ_BIT(irq);
}
}

static inline void set_pending(struct gic_dist_map *gic_dist, int irq, bool set_pending, int vcpu_id)
static inline void set_pending(vgic_t *vgic, int irq, bool set_pending, int vcpu_id)
{
if (irq < NUM_VCPU_LOCAL_VIRQS) {
set_sgi_ppi_pending(gic_dist, irq, set_pending, vcpu_id);
set_sgi_ppi_pending(vgic->dist, irq, set_pending, vcpu_id);
return;
}
set_spi_pending(gic_dist, irq, set_pending);
set_spi_pending(vgic->dist, irq, set_pending);
}

static inline bool is_sgi_ppi_pending(struct gic_dist_map *gic_dist, int irq, int vcpu_id)
static inline bool is_sgi_ppi_pending(vgic_t *vgic, int irq, int vcpu_id)
{
return !!(gic_dist->pending_set0[vcpu_id] & IRQ_BIT(irq));
return !!(vgic->dist->pending_set0[vcpu_id] & IRQ_BIT(irq));
}

static inline bool is_spi_pending(struct gic_dist_map *gic_dist, int irq)
static inline bool is_spi_pending(vgic_t *vgic, int irq)
{
return !!(gic_dist->pending_set[IRQ_IDX(irq)] & IRQ_BIT(irq));
return !!(vgic->dist->pending_set[IRQ_IDX(irq)] & IRQ_BIT(irq));
}

static inline bool is_pending(struct gic_dist_map *gic_dist, int irq, int vcpu_id)
static inline bool is_pending(vgic_t *vgic, int irq, int vcpu_id)
{
if (irq < NUM_VCPU_LOCAL_VIRQS) {
return is_sgi_ppi_pending(gic_dist, irq, vcpu_id);
return is_sgi_ppi_pending(vgic, irq, vcpu_id);

}
return is_spi_pending(gic_dist, irq);
return is_spi_pending(vgic, irq);
}

static inline void set_sgi_ppi_enable(struct gic_dist_map *gic_dist, int irq, bool set_enable, int vcpu_id)
static inline void set_sgi_ppi_enable(vgic_t *vgic, int irq, bool set_enable, int vcpu_id)
{
if (set_enable) {
gic_dist->enable_set0[vcpu_id] |= IRQ_BIT(irq);
gic_dist->enable_clr0[vcpu_id] |= IRQ_BIT(irq);
vgic->dist->enable_set0[vcpu_id] |= IRQ_BIT(irq);
vgic->dist->enable_clr0[vcpu_id] |= IRQ_BIT(irq);
} else {
gic_dist->enable_set0[vcpu_id] &= ~IRQ_BIT(irq);
gic_dist->enable_clr0[vcpu_id] &= ~IRQ_BIT(irq);
vgic->dist->enable_set0[vcpu_id] &= ~IRQ_BIT(irq);
vgic->dist->enable_clr0[vcpu_id] &= ~IRQ_BIT(irq);
}
}

static inline void set_spi_enable(struct gic_dist_map *gic_dist, int irq, bool set_enable)
static inline void set_spi_enable(vgic_t *vgic, int irq, bool set_enable)
{
if (set_enable) {
gic_dist->enable_set[IRQ_IDX(irq)] |= IRQ_BIT(irq);
gic_dist->enable_clr[IRQ_IDX(irq)] |= IRQ_BIT(irq);
vgic->dist->enable_set[IRQ_IDX(irq)] |= IRQ_BIT(irq);
vgic->dist->enable_clr[IRQ_IDX(irq)] |= IRQ_BIT(irq);
} else {
gic_dist->enable_set[IRQ_IDX(irq)] &= ~IRQ_BIT(irq);
gic_dist->enable_clr[IRQ_IDX(irq)] &= ~IRQ_BIT(irq);
vgic->dist->enable_set[IRQ_IDX(irq)] &= ~IRQ_BIT(irq);
vgic->dist->enable_clr[IRQ_IDX(irq)] &= ~IRQ_BIT(irq);
}
}

static inline void set_enable(struct gic_dist_map *gic_dist, int irq, bool set_enable, int vcpu_id)
static inline void set_enable(vgic_t *vgic, int irq, bool set_enable, int vcpu_id)
{
if (irq < NUM_VCPU_LOCAL_VIRQS) {
set_sgi_ppi_enable(gic_dist, irq, set_enable, vcpu_id);
set_sgi_ppi_enable(vgic->dist, irq, set_enable, vcpu_id);
return;
}
set_spi_enable(gic_dist, irq, set_enable);
set_spi_enable(vgic->dist, irq, set_enable);
}

static inline bool is_sgi_ppi_enabled(struct gic_dist_map *gic_dist, int irq, int vcpu_id)
static inline bool is_sgi_ppi_enabled(vgic_t *vgic, int irq, int vcpu_id)
{
return !!(gic_dist->enable_set0[vcpu_id] & IRQ_BIT(irq));
return !!(vgic->dist->enable_set0[vcpu_id] & IRQ_BIT(irq));
}

static inline bool is_spi_enabled(struct gic_dist_map *gic_dist, int irq)
static inline bool is_spi_enabled(vgic_t *vgic, int irq)
{
return !!(gic_dist->enable_set[IRQ_IDX(irq)] & IRQ_BIT(irq));
return !!(vgic->dist->enable_set[IRQ_IDX(irq)] & IRQ_BIT(irq));
}

static inline bool is_enabled(struct gic_dist_map *gic_dist, int irq, int vcpu_id)
static inline bool is_enabled(vgic_t *vgic, int irq, int vcpu_id)
{
if (irq < NUM_VCPU_LOCAL_VIRQS) {
return is_sgi_ppi_enabled(gic_dist, irq, vcpu_id);
return is_sgi_ppi_enabled(vgic, irq, vcpu_id);
}
return is_spi_enabled(gic_dist, irq);
return is_spi_enabled(vgic, irq);
}

static inline bool is_sgi_ppi_active(struct gic_dist_map *gic_dist, int irq, int vcpu_id)
static inline bool is_sgi_ppi_active(vgic_t *vgic, int irq, int vcpu_id)
{
return !!(gic_dist->active0[vcpu_id] & IRQ_BIT(irq));
return !!(vgic->dist->active0[vcpu_id] & IRQ_BIT(irq));
}

static inline bool is_spi_active(struct gic_dist_map *gic_dist, int irq)
static inline bool is_spi_active(vgic_t *vgic, int irq)
{
return !!(gic_dist->active[IRQ_IDX(irq)] & IRQ_BIT(irq));
return !!(vgic->dist->active[IRQ_IDX(irq)] & IRQ_BIT(irq));
}

static inline bool is_active(struct gic_dist_map *gic_dist, int irq, int vcpu_id)
static inline bool is_active(vgic_t *vgic, int irq, int vcpu_id)
{
if (irq < NUM_VCPU_LOCAL_VIRQS) {
return is_sgi_ppi_active(gic_dist, irq, vcpu_id);
return is_sgi_ppi_active(vgic, irq, vcpu_id);
}
return is_spi_active(gic_dist, irq);
}

static int vgic_dist_enable(vgic_t *vgic, vm_t *vm)
{
assert(vgic);
assert(vgic->dist);
DDIST("enabling gic distributor\n");
vgic->dist->enable = 1;
return 0;
}

static int vgic_dist_disable(vgic_t *vgic, vm_t *vm)
{
assert(vgic);
assert(vgic->dist);
DDIST("disabling gic distributor\n");
vgic->dist->enable = 0;
return 0;
return is_spi_active(vgic, irq);
}

static void vgic_dist_enable_irq(vgic_t *vgic, vm_vcpu_t *vcpu, int irq)
Expand All @@ -171,7 +153,7 @@ static void vgic_dist_enable_irq(vgic_t *vgic, vm_vcpu_t *vcpu, int irq)
struct virq_handle *virq_data = virq_find_irq_data(vgic, vcpu, irq);
if (virq_data) {
/* STATE b) */
if (!is_pending(vgic->dist, virq_data->virq, vcpu->vcpu_id)) {
if (!is_pending(vgic, virq_data->virq, vcpu->vcpu_id)) {
virq_ack(vcpu, virq_data);
}
} else {
Expand Down Expand Up @@ -207,12 +189,12 @@ static int vgic_dist_set_pending_irq(vgic_t *vgic, vm_vcpu_t *vcpu, int irq)

struct virq_handle *virq_data = virq_find_irq_data(vgic, vcpu, irq);

if (!virq_data || !vgic->dist->enable || !is_enabled(vgic->dist, irq, vcpu->vcpu_id)) {
if (!virq_data || !gic_dist_is_enabled(vgic) || !is_enabled(vgic->dist, irq, vcpu->vcpu_id)) {
DDIST("IRQ not enabled (%d) on vcpu %d\n", irq, vcpu->vcpu_id);
return -1;
}

if (is_pending(vgic->dist, virq_data->virq, vcpu->vcpu_id)) {
if (is_pending(vgic, virq_data->virq, vcpu->vcpu_id)) {
return 0;
}

Expand Down Expand Up @@ -254,8 +236,8 @@ static int vgic_dist_clr_pending_irq(vgic_t *vgic, vm_vcpu_t *vcpu, int irq)
return 0;
}

static memory_fault_result_t vgic_dist_reg_read(vm_t *vm, vm_vcpu_t *vcpu,
vgic_t *vgic, seL4_Word offset)
static memory_fault_result_t vgic_dist_reg_read(vgic_t *vgic, vm_vcpu_t *vcpu,
seL4_Word offset)
{
int err = 0;
fault_t *fault = vcpu->vcpu_arch.fault;
Expand Down Expand Up @@ -411,8 +393,8 @@ static inline void emulate_reg_write_access(uint32_t *vreg, fault_t *fault)
*vreg = fault_emulate(fault, *vreg);
}

static memory_fault_result_t vgic_dist_reg_write(vm_t *vm, vm_vcpu_t *vcpu,
vgic_t *vgic, seL4_Word offset)
static memory_fault_result_t vgic_dist_reg_write(vgic_t *vgic, vm_vcpu_t *vcpu,
seL4_Word offset)
{
int err = 0;
fault_t *fault = vcpu->vcpu_arch.fault;
Expand All @@ -424,14 +406,7 @@ static memory_fault_result_t vgic_dist_reg_write(vm_t *vm, vm_vcpu_t *vcpu,
uint32_t data;
switch (offset) {
case RANGE32(GIC_DIST_CTLR, GIC_DIST_CTLR):
data = fault_get_data(fault);
if (data == 1) {
vgic_dist_enable(vgic, vm);
} else if (data == 0) {
vgic_dist_disable(vgic, vm);
} else {
ZF_LOGE("Unknown enable register encoding");
}
vgic_dist_set_ctlr(vgic, fault_get_data(fault));
break;
case RANGE32(GIC_DIST_TYPER, GIC_DIST_TYPER):
break;
Expand Down Expand Up @@ -590,6 +565,9 @@ static memory_fault_result_t handle_vgic_dist_fault(vm_t *vm, vm_vcpu_t *vcpu, u
size_t fault_length,
void *cookie)
{
/* The vcpu has a vm reference, it must match the vm parameter. */
assert(vm == vcpu->vm);

/* There is a fault object per vcpu with much more context, the parameters
* fault_addr and fault_length are no longer used.
*/
Expand All @@ -598,15 +576,13 @@ static memory_fault_result_t handle_vgic_dist_fault(vm_t *vm, vm_vcpu_t *vcpu, u
assert(fault_addr == fault_get_address(vcpu->vcpu_arch.fault));

assert(cookie);
struct vgic_dist_device *d = (typeof(d))cookie;
vgic_t *vgic = d->vgic;
assert(vgic->dist);
vgic_t *vgic = (typeof(vgic))cookie;

seL4_Word addr = fault_get_address(fault);
assert(addr >= d->pstart);
seL4_Word offset = addr - d->pstart;
assert(offset < PAGE_SIZE_4K);
assert(addr >= vgic->mapped_dist.paddr);
seL4_Word offset = addr - vgic->mapped_dist.paddr;
assert(offset < vgic->mapped_dist.size);

return fault_is_read(fault) ? vgic_dist_reg_read(vm, vcpu, vgic, offset)
: vgic_dist_reg_write(vm, vcpu, vgic, offset);
return fault_is_read(fault) ? vgic_dist_reg_read(vgic, vcpu, offset)
: vgic_dist_reg_write(vgic, vcpu, offset);
}
20 changes: 13 additions & 7 deletions libsel4vm/src/arch/arm/vgic/vgic.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,21 @@

#include <sel4vm/guest_vm.h>

typedef struct vgic vgic_t;

struct vgic_dist_device {
uintptr_t pstart;
typedef struct {
uintptr_t paddr;
size_t size;
vgic_t *vgic;
};
vm_memory_reservation_t *vm_res;
} vm_mapping_t;

extern const struct vgic_dist_device dev_vgic_dist;
typedef struct vgic vgic_t;

int vm_install_vgic(vm_t *vm);
int vm_vgic_maintenance_handler(vm_vcpu_t *vcpu);

static inline vgic_t *get_vgic_from_vm(vm_t *vm)
{
assert(vm);
vgic_t *vgic = (typeof(vgic))(vm->arch.vgic_context);
assert(vgic);
return vgic;
}
Loading