]> rtime.felk.cvut.cz Git - jailhouse.git/blob - driver/sysfs.c
arm: Remove irq field from pending_irq
[jailhouse.git] / driver / sysfs.c
1 /*
2  * Jailhouse, a Linux-based partitioning hypervisor
3  *
4  * Copyright (c) Siemens AG, 2014-2015
5  *
6  * Authors:
7  *  Jan Kiszka <jan.kiszka@siemens.com>
8  *
9  * This work is licensed under the terms of the GNU GPL, version 2.  See
10  * the COPYING file in the top-level directory.
11  */
12
13 #include "cell.h"
14 #include "jailhouse.h"
15 #include "main.h"
16 #include "sysfs.h"
17
18 #include <jailhouse/hypercall.h>
19
20 /* For compatibility with older kernel versions */
21 #include <linux/version.h>
22
23 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
24 #define DEVICE_ATTR_RO(_name) \
25         struct device_attribute dev_attr_##_name = __ATTR_RO(_name)
26 #endif /* < 3.11 */
27
28 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
29 static ssize_t kobj_attr_show(struct kobject *kobj, struct attribute *attr,
30                               char *buf)
31 {
32         struct kobj_attribute *kattr;
33         ssize_t ret = -EIO;
34
35         kattr = container_of(attr, struct kobj_attribute, attr);
36         if (kattr->show)
37                 ret = kattr->show(kobj, kattr, buf);
38         return ret;
39 }
40
41 static ssize_t kobj_attr_store(struct kobject *kobj, struct attribute *attr,
42                                const char *buf, size_t count)
43 {
44         struct kobj_attribute *kattr;
45         ssize_t ret = -EIO;
46
47         kattr = container_of(attr, struct kobj_attribute, attr);
48         if (kattr->store)
49                 ret = kattr->store(kobj, kattr, buf, count);
50         return ret;
51 }
52
53 static const struct sysfs_ops cell_sysfs_ops = {
54         .show   = kobj_attr_show,
55         .store  = kobj_attr_store,
56 };
57 #define kobj_sysfs_ops cell_sysfs_ops
58 #endif /* < 3.14 */
59 /* End of compatibility section - remove as version become obsolete */
60
61 static struct kobject *cells_dir;
62
63 struct jailhouse_cpu_stats_attr {
64         struct kobj_attribute kattr;
65         unsigned int code;
66 };
67
68 static ssize_t stats_show(struct kobject *kobj, struct kobj_attribute *attr,
69                           char *buffer)
70 {
71         struct jailhouse_cpu_stats_attr *stats_attr =
72                 container_of(attr, struct jailhouse_cpu_stats_attr, kattr);
73         unsigned int code = JAILHOUSE_CPU_INFO_STAT_BASE + stats_attr->code;
74         struct cell *cell = container_of(kobj, struct cell, kobj);
75         unsigned long sum = 0;
76         unsigned int cpu;
77         int value;
78
79         for_each_cpu(cpu, &cell->cpus_assigned) {
80                 value = jailhouse_call_arg2(JAILHOUSE_HC_CPU_GET_INFO, cpu,
81                                             code);
82                 if (value > 0)
83                         sum += value;
84         }
85
86         return sprintf(buffer, "%lu\n", sum);
87 }
88
89 #define JAILHOUSE_CPU_STATS_ATTR(_name, _code) \
90         static struct jailhouse_cpu_stats_attr _name##_attr = { \
91                 .kattr = __ATTR(_name, S_IRUGO, stats_show, NULL), \
92                 .code = _code, \
93         }
94
95 JAILHOUSE_CPU_STATS_ATTR(vmexits_total, JAILHOUSE_CPU_STAT_VMEXITS_TOTAL);
96 JAILHOUSE_CPU_STATS_ATTR(vmexits_mmio, JAILHOUSE_CPU_STAT_VMEXITS_MMIO);
97 JAILHOUSE_CPU_STATS_ATTR(vmexits_management,
98                          JAILHOUSE_CPU_STAT_VMEXITS_MANAGEMENT);
99 JAILHOUSE_CPU_STATS_ATTR(vmexits_hypercall,
100                          JAILHOUSE_CPU_STAT_VMEXITS_HYPERCALL);
101 #ifdef CONFIG_X86
102 JAILHOUSE_CPU_STATS_ATTR(vmexits_pio, JAILHOUSE_CPU_STAT_VMEXITS_PIO);
103 JAILHOUSE_CPU_STATS_ATTR(vmexits_xapic, JAILHOUSE_CPU_STAT_VMEXITS_XAPIC);
104 JAILHOUSE_CPU_STATS_ATTR(vmexits_cr, JAILHOUSE_CPU_STAT_VMEXITS_CR);
105 JAILHOUSE_CPU_STATS_ATTR(vmexits_msr, JAILHOUSE_CPU_STAT_VMEXITS_MSR);
106 JAILHOUSE_CPU_STATS_ATTR(vmexits_cpuid, JAILHOUSE_CPU_STAT_VMEXITS_CPUID);
107 JAILHOUSE_CPU_STATS_ATTR(vmexits_xsetbv, JAILHOUSE_CPU_STAT_VMEXITS_XSETBV);
108 JAILHOUSE_CPU_STATS_ATTR(vmexits_exception,
109                          JAILHOUSE_CPU_STAT_VMEXITS_EXCEPTION);
110 #elif defined(CONFIG_ARM)
111 JAILHOUSE_CPU_STATS_ATTR(vmexits_maintenance, JAILHOUSE_CPU_STAT_VMEXITS_MAINTENANCE);
112 JAILHOUSE_CPU_STATS_ATTR(vmexits_virt_irq, JAILHOUSE_CPU_STAT_VMEXITS_VIRQ);
113 JAILHOUSE_CPU_STATS_ATTR(vmexits_virt_sgi, JAILHOUSE_CPU_STAT_VMEXITS_VSGI);
114 #endif
115
116 static struct attribute *no_attrs[] = {
117         &vmexits_total_attr.kattr.attr,
118         &vmexits_mmio_attr.kattr.attr,
119         &vmexits_management_attr.kattr.attr,
120         &vmexits_hypercall_attr.kattr.attr,
121 #ifdef CONFIG_X86
122         &vmexits_pio_attr.kattr.attr,
123         &vmexits_xapic_attr.kattr.attr,
124         &vmexits_cr_attr.kattr.attr,
125         &vmexits_msr_attr.kattr.attr,
126         &vmexits_cpuid_attr.kattr.attr,
127         &vmexits_xsetbv_attr.kattr.attr,
128         &vmexits_exception_attr.kattr.attr,
129 #elif defined(CONFIG_ARM)
130         &vmexits_maintenance_attr.kattr.attr,
131         &vmexits_virt_irq_attr.kattr.attr,
132         &vmexits_virt_sgi_attr.kattr.attr,
133 #endif
134         NULL
135 };
136
137 static struct attribute_group stats_attr_group = {
138         .attrs = no_attrs,
139         .name = "statistics"
140 };
141
142 static ssize_t id_show(struct kobject *kobj, struct kobj_attribute *attr,
143                        char *buffer)
144 {
145         struct cell *cell = container_of(kobj, struct cell, kobj);
146
147         return sprintf(buffer, "%u\n", cell->id);
148 }
149
150 static ssize_t state_show(struct kobject *kobj, struct kobj_attribute *attr,
151                           char *buffer)
152 {
153         struct cell *cell = container_of(kobj, struct cell, kobj);
154
155         switch (jailhouse_call_arg1(JAILHOUSE_HC_CELL_GET_STATE, cell->id)) {
156         case JAILHOUSE_CELL_RUNNING:
157                 return sprintf(buffer, "running\n");
158         case JAILHOUSE_CELL_RUNNING_LOCKED:
159                 return sprintf(buffer, "running/locked\n");
160         case JAILHOUSE_CELL_SHUT_DOWN:
161                 return sprintf(buffer, "shut down\n");
162         case JAILHOUSE_CELL_FAILED:
163                 return sprintf(buffer, "failed\n");
164         default:
165                 return sprintf(buffer, "invalid\n");
166         }
167 }
168
169 static ssize_t cpus_assigned_show(struct kobject *kobj,
170                                   struct kobj_attribute *attr, char *buf)
171 {
172         struct cell *cell = container_of(kobj, struct cell, kobj);
173         int written;
174
175 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0)
176         written = scnprintf(buf, PAGE_SIZE, "%*pb\n",
177                             cpumask_pr_args(&cell->cpus_assigned));
178 #else
179         written = cpumask_scnprintf(buf, PAGE_SIZE, &cell->cpus_assigned);
180         written += scnprintf(buf + written, PAGE_SIZE - written, "\n");
181 #endif
182         return written;
183 }
184
185 static ssize_t cpus_failed_show(struct kobject *kobj,
186                                 struct kobj_attribute *attr, char *buf)
187 {
188         struct cell *cell = container_of(kobj, struct cell, kobj);
189         cpumask_var_t cpus_failed;
190         unsigned int cpu;
191         int written;
192
193         if (!zalloc_cpumask_var(&cpus_failed, GFP_KERNEL))
194                 return -ENOMEM;
195
196         for_each_cpu(cpu, &cell->cpus_assigned)
197                 if (jailhouse_call_arg2(JAILHOUSE_HC_CPU_GET_INFO, cpu,
198                                         JAILHOUSE_CPU_INFO_STATE) ==
199                     JAILHOUSE_CPU_FAILED)
200                         cpumask_set_cpu(cpu, cpus_failed);
201
202 #if LINUX_VERSION_CODE >= KERNEL_VERSION(4,0,0)
203         written = scnprintf(buf, PAGE_SIZE, "%*pb\n",
204                             cpumask_pr_args(cpus_failed));
205 #else
206         written = cpumask_scnprintf(buf, PAGE_SIZE, cpus_failed);
207         written += scnprintf(buf + written, PAGE_SIZE - written, "\n");
208 #endif
209
210         free_cpumask_var(cpus_failed);
211
212         return written;
213 }
214
215 static struct kobj_attribute cell_id_attr = __ATTR_RO(id);
216 static struct kobj_attribute cell_state_attr = __ATTR_RO(state);
217 static struct kobj_attribute cell_cpus_assigned_attr =
218         __ATTR_RO(cpus_assigned);
219 static struct kobj_attribute cell_cpus_failed_attr = __ATTR_RO(cpus_failed);
220
221 static struct attribute *cell_attrs[] = {
222         &cell_id_attr.attr,
223         &cell_state_attr.attr,
224         &cell_cpus_assigned_attr.attr,
225         &cell_cpus_failed_attr.attr,
226         NULL,
227 };
228
229 static struct kobj_type cell_type = {
230         .release = jailhouse_cell_kobj_release,
231         .sysfs_ops = &kobj_sysfs_ops,
232         .default_attrs = cell_attrs,
233 };
234
235 int jailhouse_sysfs_cell_create(struct cell *cell, const char *name)
236 {
237         int err;
238
239         err = kobject_init_and_add(&cell->kobj, &cell_type, cells_dir, "%s",
240                                    name);
241         if (err) {
242                 jailhouse_cell_kobj_release(&cell->kobj);
243                 return err;
244         }
245
246         err = sysfs_create_group(&cell->kobj, &stats_attr_group);
247         if (err) {
248                 kobject_put(&cell->kobj);
249                 return err;
250         }
251
252         return 0;
253 }
254
255 void jailhouse_sysfs_cell_register(struct cell *cell)
256 {
257         kobject_uevent(&cell->kobj, KOBJ_ADD);
258 }
259
260 void jailhouse_sysfs_cell_delete(struct cell *cell)
261 {
262         sysfs_remove_group(&cell->kobj, &stats_attr_group);
263         kobject_put(&cell->kobj);
264 }
265
266 static ssize_t enabled_show(struct device *dev, struct device_attribute *attr,
267                             char *buffer)
268 {
269         return sprintf(buffer, "%d\n", jailhouse_enabled);
270 }
271
272 static ssize_t info_show(struct device *dev, char *buffer, unsigned int type)
273 {
274         ssize_t result;
275         long val = 0;
276
277         if (mutex_lock_interruptible(&jailhouse_lock) != 0)
278                 return -EINTR;
279
280         if (jailhouse_enabled)
281                 val = jailhouse_call_arg1(JAILHOUSE_HC_HYPERVISOR_GET_INFO,
282                                           type);
283         if (val >= 0)
284                 result = sprintf(buffer, "%ld\n", val);
285         else
286                 result = val;
287
288         mutex_unlock(&jailhouse_lock);
289         return result;
290 }
291
292 static ssize_t mem_pool_size_show(struct device *dev,
293                                   struct device_attribute *attr, char *buffer)
294 {
295         return info_show(dev, buffer, JAILHOUSE_INFO_MEM_POOL_SIZE);
296 }
297
298 static ssize_t mem_pool_used_show(struct device *dev,
299                                   struct device_attribute *attr, char *buffer)
300 {
301         return info_show(dev, buffer, JAILHOUSE_INFO_MEM_POOL_USED);
302 }
303
304 static ssize_t remap_pool_size_show(struct device *dev,
305                                     struct device_attribute *attr,
306                                     char *buffer)
307 {
308         return info_show(dev, buffer, JAILHOUSE_INFO_REMAP_POOL_SIZE);
309 }
310
311 static ssize_t remap_pool_used_show(struct device *dev,
312                                     struct device_attribute *attr,
313                                     char *buffer)
314 {
315         return info_show(dev, buffer, JAILHOUSE_INFO_REMAP_POOL_USED);
316 }
317
318 static DEVICE_ATTR_RO(enabled);
319 static DEVICE_ATTR_RO(mem_pool_size);
320 static DEVICE_ATTR_RO(mem_pool_used);
321 static DEVICE_ATTR_RO(remap_pool_size);
322 static DEVICE_ATTR_RO(remap_pool_used);
323
324 static struct attribute *jailhouse_sysfs_entries[] = {
325         &dev_attr_enabled.attr,
326         &dev_attr_mem_pool_size.attr,
327         &dev_attr_mem_pool_used.attr,
328         &dev_attr_remap_pool_size.attr,
329         &dev_attr_remap_pool_used.attr,
330         NULL
331 };
332
333 static struct attribute_group jailhouse_attribute_group = {
334         .name = NULL,
335         .attrs = jailhouse_sysfs_entries,
336 };
337
338 int jailhouse_sysfs_init(struct device *dev)
339 {
340         int err;
341
342         err = sysfs_create_group(&dev->kobj, &jailhouse_attribute_group);
343         if (err)
344                 return err;
345
346         cells_dir = kobject_create_and_add("cells", &dev->kobj);
347         if (!cells_dir) {
348                 sysfs_remove_group(&dev->kobj, &jailhouse_attribute_group);
349                 return -ENOMEM;
350         }
351
352         return 0;
353 }
354
355 void jailhouse_sysfs_exit(struct device *dev)
356 {
357         kobject_put(cells_dir);
358         sysfs_remove_group(&dev->kobj, &jailhouse_attribute_group);
359 }