Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/arch/s390/hypfs/hypfs_vm.c
10817 views
1
/*
2
* Hypervisor filesystem for Linux on s390. z/VM implementation.
3
*
4
* Copyright (C) IBM Corp. 2006
5
* Author(s): Michael Holzheu <[email protected]>
6
*/
7
8
#include <linux/types.h>
9
#include <linux/errno.h>
10
#include <linux/string.h>
11
#include <linux/vmalloc.h>
12
#include <asm/ebcdic.h>
13
#include <asm/timex.h>
14
#include "hypfs.h"
15
16
#define NAME_LEN 8
17
#define DBFS_D2FC_HDR_VERSION 0
18
19
static char local_guest[] = " ";
20
static char all_guests[] = "* ";
21
static char *guest_query;
22
23
struct diag2fc_data {
24
__u32 version;
25
__u32 flags;
26
__u64 used_cpu;
27
__u64 el_time;
28
__u64 mem_min_kb;
29
__u64 mem_max_kb;
30
__u64 mem_share_kb;
31
__u64 mem_used_kb;
32
__u32 pcpus;
33
__u32 lcpus;
34
__u32 vcpus;
35
__u32 cpu_min;
36
__u32 cpu_max;
37
__u32 cpu_shares;
38
__u32 cpu_use_samp;
39
__u32 cpu_delay_samp;
40
__u32 page_wait_samp;
41
__u32 idle_samp;
42
__u32 other_samp;
43
__u32 total_samp;
44
char guest_name[NAME_LEN];
45
};
46
47
struct diag2fc_parm_list {
48
char userid[NAME_LEN];
49
char aci_grp[NAME_LEN];
50
__u64 addr;
51
__u32 size;
52
__u32 fmt;
53
};
54
55
static int diag2fc(int size, char* query, void *addr)
56
{
57
unsigned long residual_cnt;
58
unsigned long rc;
59
struct diag2fc_parm_list parm_list;
60
61
memcpy(parm_list.userid, query, NAME_LEN);
62
ASCEBC(parm_list.userid, NAME_LEN);
63
parm_list.addr = (unsigned long) addr ;
64
parm_list.size = size;
65
parm_list.fmt = 0x02;
66
memset(parm_list.aci_grp, 0x40, NAME_LEN);
67
rc = -1;
68
69
asm volatile(
70
" diag %0,%1,0x2fc\n"
71
"0:\n"
72
EX_TABLE(0b,0b)
73
: "=d" (residual_cnt), "+d" (rc) : "0" (&parm_list) : "memory");
74
75
if ((rc != 0 ) && (rc != -2))
76
return rc;
77
else
78
return -residual_cnt;
79
}
80
81
/*
82
* Allocate buffer for "query" and store diag 2fc at "offset"
83
*/
84
static void *diag2fc_store(char *query, unsigned int *count, int offset)
85
{
86
void *data;
87
int size;
88
89
do {
90
size = diag2fc(0, query, NULL);
91
if (size < 0)
92
return ERR_PTR(-EACCES);
93
data = vmalloc(size + offset);
94
if (!data)
95
return ERR_PTR(-ENOMEM);
96
if (diag2fc(size, query, data + offset) == 0)
97
break;
98
vfree(data);
99
} while (1);
100
*count = (size / sizeof(struct diag2fc_data));
101
102
return data;
103
}
104
105
static void diag2fc_free(const void *data)
106
{
107
vfree(data);
108
}
109
110
#define ATTRIBUTE(sb, dir, name, member) \
111
do { \
112
void *rc; \
113
rc = hypfs_create_u64(sb, dir, name, member); \
114
if (IS_ERR(rc)) \
115
return PTR_ERR(rc); \
116
} while(0)
117
118
static int hpyfs_vm_create_guest(struct super_block *sb,
119
struct dentry *systems_dir,
120
struct diag2fc_data *data)
121
{
122
char guest_name[NAME_LEN + 1] = {};
123
struct dentry *guest_dir, *cpus_dir, *samples_dir, *mem_dir;
124
int dedicated_flag, capped_value;
125
126
capped_value = (data->flags & 0x00000006) >> 1;
127
dedicated_flag = (data->flags & 0x00000008) >> 3;
128
129
/* guest dir */
130
memcpy(guest_name, data->guest_name, NAME_LEN);
131
EBCASC(guest_name, NAME_LEN);
132
strim(guest_name);
133
guest_dir = hypfs_mkdir(sb, systems_dir, guest_name);
134
if (IS_ERR(guest_dir))
135
return PTR_ERR(guest_dir);
136
ATTRIBUTE(sb, guest_dir, "onlinetime_us", data->el_time);
137
138
/* logical cpu information */
139
cpus_dir = hypfs_mkdir(sb, guest_dir, "cpus");
140
if (IS_ERR(cpus_dir))
141
return PTR_ERR(cpus_dir);
142
ATTRIBUTE(sb, cpus_dir, "cputime_us", data->used_cpu);
143
ATTRIBUTE(sb, cpus_dir, "capped", capped_value);
144
ATTRIBUTE(sb, cpus_dir, "dedicated", dedicated_flag);
145
ATTRIBUTE(sb, cpus_dir, "count", data->vcpus);
146
ATTRIBUTE(sb, cpus_dir, "weight_min", data->cpu_min);
147
ATTRIBUTE(sb, cpus_dir, "weight_max", data->cpu_max);
148
ATTRIBUTE(sb, cpus_dir, "weight_cur", data->cpu_shares);
149
150
/* memory information */
151
mem_dir = hypfs_mkdir(sb, guest_dir, "mem");
152
if (IS_ERR(mem_dir))
153
return PTR_ERR(mem_dir);
154
ATTRIBUTE(sb, mem_dir, "min_KiB", data->mem_min_kb);
155
ATTRIBUTE(sb, mem_dir, "max_KiB", data->mem_max_kb);
156
ATTRIBUTE(sb, mem_dir, "used_KiB", data->mem_used_kb);
157
ATTRIBUTE(sb, mem_dir, "share_KiB", data->mem_share_kb);
158
159
/* samples */
160
samples_dir = hypfs_mkdir(sb, guest_dir, "samples");
161
if (IS_ERR(samples_dir))
162
return PTR_ERR(samples_dir);
163
ATTRIBUTE(sb, samples_dir, "cpu_using", data->cpu_use_samp);
164
ATTRIBUTE(sb, samples_dir, "cpu_delay", data->cpu_delay_samp);
165
ATTRIBUTE(sb, samples_dir, "mem_delay", data->page_wait_samp);
166
ATTRIBUTE(sb, samples_dir, "idle", data->idle_samp);
167
ATTRIBUTE(sb, samples_dir, "other", data->other_samp);
168
ATTRIBUTE(sb, samples_dir, "total", data->total_samp);
169
return 0;
170
}
171
172
int hypfs_vm_create_files(struct super_block *sb, struct dentry *root)
173
{
174
struct dentry *dir, *file;
175
struct diag2fc_data *data;
176
unsigned int count = 0;
177
int rc, i;
178
179
data = diag2fc_store(guest_query, &count, 0);
180
if (IS_ERR(data))
181
return PTR_ERR(data);
182
183
/* Hpervisor Info */
184
dir = hypfs_mkdir(sb, root, "hyp");
185
if (IS_ERR(dir)) {
186
rc = PTR_ERR(dir);
187
goto failed;
188
}
189
file = hypfs_create_str(sb, dir, "type", "z/VM Hypervisor");
190
if (IS_ERR(file)) {
191
rc = PTR_ERR(file);
192
goto failed;
193
}
194
195
/* physical cpus */
196
dir = hypfs_mkdir(sb, root, "cpus");
197
if (IS_ERR(dir)) {
198
rc = PTR_ERR(dir);
199
goto failed;
200
}
201
file = hypfs_create_u64(sb, dir, "count", data->lcpus);
202
if (IS_ERR(file)) {
203
rc = PTR_ERR(file);
204
goto failed;
205
}
206
207
/* guests */
208
dir = hypfs_mkdir(sb, root, "systems");
209
if (IS_ERR(dir)) {
210
rc = PTR_ERR(dir);
211
goto failed;
212
}
213
214
for (i = 0; i < count; i++) {
215
rc = hpyfs_vm_create_guest(sb, dir, &(data[i]));
216
if (rc)
217
goto failed;
218
}
219
diag2fc_free(data);
220
return 0;
221
222
failed:
223
diag2fc_free(data);
224
return rc;
225
}
226
227
struct dbfs_d2fc_hdr {
228
u64 len; /* Length of d2fc buffer without header */
229
u16 version; /* Version of header */
230
char tod_ext[16]; /* TOD clock for d2fc */
231
u64 count; /* Number of VM guests in d2fc buffer */
232
char reserved[30];
233
} __attribute__ ((packed));
234
235
struct dbfs_d2fc {
236
struct dbfs_d2fc_hdr hdr; /* 64 byte header */
237
char buf[]; /* d2fc buffer */
238
} __attribute__ ((packed));
239
240
static int dbfs_diag2fc_create(void **data, void **data_free_ptr, size_t *size)
241
{
242
struct dbfs_d2fc *d2fc;
243
unsigned int count;
244
245
d2fc = diag2fc_store(guest_query, &count, sizeof(d2fc->hdr));
246
if (IS_ERR(d2fc))
247
return PTR_ERR(d2fc);
248
get_clock_ext(d2fc->hdr.tod_ext);
249
d2fc->hdr.len = count * sizeof(struct diag2fc_data);
250
d2fc->hdr.version = DBFS_D2FC_HDR_VERSION;
251
d2fc->hdr.count = count;
252
memset(&d2fc->hdr.reserved, 0, sizeof(d2fc->hdr.reserved));
253
*data = d2fc;
254
*data_free_ptr = d2fc;
255
*size = d2fc->hdr.len + sizeof(struct dbfs_d2fc_hdr);
256
return 0;
257
}
258
259
static struct hypfs_dbfs_file dbfs_file_2fc = {
260
.name = "diag_2fc",
261
.data_create = dbfs_diag2fc_create,
262
.data_free = diag2fc_free,
263
};
264
265
int hypfs_vm_init(void)
266
{
267
if (!MACHINE_IS_VM)
268
return 0;
269
if (diag2fc(0, all_guests, NULL) > 0)
270
guest_query = all_guests;
271
else if (diag2fc(0, local_guest, NULL) > 0)
272
guest_query = local_guest;
273
else
274
return -EACCES;
275
return hypfs_dbfs_create_file(&dbfs_file_2fc);
276
}
277
278
void hypfs_vm_exit(void)
279
{
280
if (!MACHINE_IS_VM)
281
return;
282
hypfs_dbfs_remove_file(&dbfs_file_2fc);
283
}
284
285