blob: c400661409ab1ec9e39726581ef7acb24f178512 [file] [log] [blame]
Marc Zyngier1a89dd92013-01-21 19:36:12 -05001/*
2 * Copyright (C) 2012 ARM Ltd.
3 * Author: Marc Zyngier <marc.zyngier@arm.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 */
18
19#include <linux/kvm.h>
20#include <linux/kvm_host.h>
21#include <linux/interrupt.h>
22#include <linux/io.h>
23#include <asm/kvm_emulate.h>
24
25#define ACCESS_READ_VALUE (1 << 0)
26#define ACCESS_READ_RAZ (0 << 0)
27#define ACCESS_READ_MASK(x) ((x) & (1 << 0))
28#define ACCESS_WRITE_IGNORED (0 << 1)
29#define ACCESS_WRITE_SETBIT (1 << 1)
30#define ACCESS_WRITE_CLEARBIT (2 << 1)
31#define ACCESS_WRITE_VALUE (3 << 1)
32#define ACCESS_WRITE_MASK(x) ((x) & (3 << 1))
33
34static u32 mmio_data_read(struct kvm_exit_mmio *mmio, u32 mask)
35{
36 return *((u32 *)mmio->data) & mask;
37}
38
39static void mmio_data_write(struct kvm_exit_mmio *mmio, u32 mask, u32 value)
40{
41 *((u32 *)mmio->data) = value & mask;
42}
43
44/**
45 * vgic_reg_access - access vgic register
46 * @mmio: pointer to the data describing the mmio access
47 * @reg: pointer to the virtual backing of vgic distributor data
48 * @offset: least significant 2 bits used for word offset
49 * @mode: ACCESS_ mode (see defines above)
50 *
51 * Helper to make vgic register access easier using one of the access
52 * modes defined for vgic register access
53 * (read,raz,write-ignored,setbit,clearbit,write)
54 */
55static void vgic_reg_access(struct kvm_exit_mmio *mmio, u32 *reg,
56 phys_addr_t offset, int mode)
57{
58 int word_offset = (offset & 3) * 8;
59 u32 mask = (1UL << (mmio->len * 8)) - 1;
60 u32 regval;
61
62 /*
63 * Any alignment fault should have been delivered to the guest
64 * directly (ARM ARM B3.12.7 "Prioritization of aborts").
65 */
66
67 if (reg) {
68 regval = *reg;
69 } else {
70 BUG_ON(mode != (ACCESS_READ_RAZ | ACCESS_WRITE_IGNORED));
71 regval = 0;
72 }
73
74 if (mmio->is_write) {
75 u32 data = mmio_data_read(mmio, mask) << word_offset;
76 switch (ACCESS_WRITE_MASK(mode)) {
77 case ACCESS_WRITE_IGNORED:
78 return;
79
80 case ACCESS_WRITE_SETBIT:
81 regval |= data;
82 break;
83
84 case ACCESS_WRITE_CLEARBIT:
85 regval &= ~data;
86 break;
87
88 case ACCESS_WRITE_VALUE:
89 regval = (regval & ~(mask << word_offset)) | data;
90 break;
91 }
92 *reg = regval;
93 } else {
94 switch (ACCESS_READ_MASK(mode)) {
95 case ACCESS_READ_RAZ:
96 regval = 0;
97 /* fall through */
98
99 case ACCESS_READ_VALUE:
100 mmio_data_write(mmio, mask, regval >> word_offset);
101 }
102 }
103}
104
105/*
106 * I would have liked to use the kvm_bus_io_*() API instead, but it
107 * cannot cope with banked registers (only the VM pointer is passed
108 * around, and we need the vcpu). One of these days, someone please
109 * fix it!
110 */
111struct mmio_range {
112 phys_addr_t base;
113 unsigned long len;
114 bool (*handle_mmio)(struct kvm_vcpu *vcpu, struct kvm_exit_mmio *mmio,
115 phys_addr_t offset);
116};
117
118static const struct mmio_range vgic_ranges[] = {
119 {}
120};
121
122static const
123struct mmio_range *find_matching_range(const struct mmio_range *ranges,
124 struct kvm_exit_mmio *mmio,
125 phys_addr_t base)
126{
127 const struct mmio_range *r = ranges;
128 phys_addr_t addr = mmio->phys_addr - base;
129
130 while (r->len) {
131 if (addr >= r->base &&
132 (addr + mmio->len) <= (r->base + r->len))
133 return r;
134 r++;
135 }
136
137 return NULL;
138}
139
140/**
141 * vgic_handle_mmio - handle an in-kernel MMIO access
142 * @vcpu: pointer to the vcpu performing the access
143 * @run: pointer to the kvm_run structure
144 * @mmio: pointer to the data describing the access
145 *
146 * returns true if the MMIO access has been performed in kernel space,
147 * and false if it needs to be emulated in user space.
148 */
149bool vgic_handle_mmio(struct kvm_vcpu *vcpu, struct kvm_run *run,
150 struct kvm_exit_mmio *mmio)
151{
152 return KVM_EXIT_MMIO;
153}