Linux Kernel
3.7.1
Main Page
Related Pages
Modules
Namespaces
Data Structures
Files
File List
Globals
All
Data Structures
Namespaces
Files
Functions
Variables
Typedefs
Enumerations
Enumerator
Macros
Groups
Pages
drivers
s390
char
vmcp.c
Go to the documentation of this file.
1
/*
2
* Copyright IBM Corp. 2004, 2010
3
* Interface implementation for communication with the z/VM control program
4
*
5
* Author(s): Christian Borntraeger <
[email protected]
>
6
*
7
* z/VMs CP offers the possibility to issue commands via the diagnose code 8
8
* this driver implements a character device that issues these commands and
9
* returns the answer of CP.
10
*
11
* The idea of this driver is based on cpint from Neale Ferguson and #CP in CMS
12
*/
13
14
#include <linux/fs.h>
15
#include <
linux/init.h
>
16
#include <
linux/compat.h
>
17
#include <linux/kernel.h>
18
#include <
linux/miscdevice.h
>
19
#include <linux/slab.h>
20
#include <linux/export.h>
21
#include <asm/compat.h>
22
#include <
asm/cpcmd.h
>
23
#include <asm/debug.h>
24
#include <asm/uaccess.h>
25
#include "
vmcp.h
"
26
27
static
debug_info_t
*vmcp_debug;
28
29
static
int
vmcp_open(
struct
inode
*
inode
,
struct
file
*
file
)
30
{
31
struct
vmcp_session
*session;
32
33
if
(!
capable
(
CAP_SYS_ADMIN
))
34
return
-
EPERM
;
35
36
session =
kmalloc
(
sizeof
(*session),
GFP_KERNEL
);
37
if
(!session)
38
return
-
ENOMEM
;
39
40
session->
bufsize
=
PAGE_SIZE
;
41
session->
response
=
NULL
;
42
session->
resp_size
= 0;
43
mutex_init
(&session->
mutex
);
44
file->
private_data
= session;
45
return
nonseekable_open
(inode, file);
46
}
47
48
static
int
vmcp_release(
struct
inode *inode,
struct
file *file)
49
{
50
struct
vmcp_session
*session;
51
52
session = file->
private_data
;
53
file->
private_data
=
NULL
;
54
free_pages
((
unsigned
long
)session->
response
,
get_order
(session->
bufsize
));
55
kfree
(session);
56
return
0;
57
}
58
59
static
ssize_t
60
vmcp_read(
struct
file *file,
char
__user *buff,
size_t
count
, loff_t *ppos)
61
{
62
ssize_t
ret
;
63
size_t
size
;
64
struct
vmcp_session
*session;
65
66
session = file->
private_data
;
67
if
(
mutex_lock_interruptible
(&session->
mutex
))
68
return
-
ERESTARTSYS
;
69
if
(!session->
response
) {
70
mutex_unlock
(&session->
mutex
);
71
return
0;
72
}
73
size =
min_t
(
size_t
, session->
resp_size
, session->
bufsize
);
74
ret =
simple_read_from_buffer
(buff, count, ppos,
75
session->
response
, size);
76
77
mutex_unlock
(&session->
mutex
);
78
79
return
ret
;
80
}
81
82
static
ssize_t
83
vmcp_write(
struct
file *file,
const
char
__user *buff,
size_t
count,
84
loff_t *ppos)
85
{
86
char
*
cmd
;
87
struct
vmcp_session
*session;
88
89
if
(count > 240)
90
return
-
EINVAL
;
91
cmd =
kmalloc
(count + 1,
GFP_KERNEL
);
92
if
(!cmd)
93
return
-
ENOMEM
;
94
if
(
copy_from_user
(cmd, buff, count)) {
95
kfree
(cmd);
96
return
-
EFAULT
;
97
}
98
cmd[
count
] =
'\0'
;
99
session = file->
private_data
;
100
if
(
mutex_lock_interruptible
(&session->
mutex
)) {
101
kfree
(cmd);
102
return
-
ERESTARTSYS
;
103
}
104
if
(!session->
response
)
105
session->
response
= (
char
*)
__get_free_pages
(
GFP_KERNEL
106
|
__GFP_REPEAT
|
GFP_DMA
,
107
get_order
(session->
bufsize
));
108
if
(!session->
response
) {
109
mutex_unlock
(&session->
mutex
);
110
kfree
(cmd);
111
return
-
ENOMEM
;
112
}
113
debug_text_event(vmcp_debug, 1, cmd);
114
session->
resp_size
=
cpcmd
(cmd, session->
response
, session->
bufsize
,
115
&session->
resp_code
);
116
mutex_unlock
(&session->
mutex
);
117
kfree
(cmd);
118
*ppos = 0;
/* reset the file pointer after a command */
119
return
count
;
120
}
121
122
123
/*
124
* These ioctls are available, as the semantics of the diagnose 8 call
125
* does not fit very well into a Linux call. Diagnose X'08' is described in
126
* CP Programming Services SC24-6084-00
127
*
128
* VMCP_GETCODE: gives the CP return code back to user space
129
* VMCP_SETBUF: sets the response buffer for the next write call. diagnose 8
130
* expects adjacent pages in real storage and to make matters worse, we
131
* dont know the size of the response. Therefore we default to PAGESIZE and
132
* let userspace to change the response size, if userspace expects a bigger
133
* response
134
*/
135
static
long
vmcp_ioctl(
struct
file *file,
unsigned
int
cmd,
unsigned
long
arg
)
136
{
137
struct
vmcp_session
*session;
138
int
__user
*
argp
;
139
int
temp
;
140
141
session = file->
private_data
;
142
if
(
is_compat_task
())
143
argp = compat_ptr(arg);
144
else
145
argp = (
int
__user
*)arg;
146
if
(
mutex_lock_interruptible
(&session->
mutex
))
147
return
-
ERESTARTSYS
;
148
switch
(cmd) {
149
case
VMCP_GETCODE
:
150
temp = session->
resp_code
;
151
mutex_unlock
(&session->
mutex
);
152
return
put_user
(temp, argp);
153
case
VMCP_SETBUF
:
154
free_pages
((
unsigned
long
)session->
response
,
155
get_order
(session->
bufsize
));
156
session->
response
=
NULL
;
157
temp =
get_user
(session->
bufsize
, argp);
158
if
(
get_order
(session->
bufsize
) > 8) {
159
session->
bufsize
=
PAGE_SIZE
;
160
temp = -
EINVAL
;
161
}
162
mutex_unlock
(&session->
mutex
);
163
return
temp
;
164
case
VMCP_GETSIZE
:
165
temp = session->
resp_size
;
166
mutex_unlock
(&session->
mutex
);
167
return
put_user
(temp, argp);
168
default
:
169
mutex_unlock
(&session->
mutex
);
170
return
-
ENOIOCTLCMD
;
171
}
172
}
173
174
static
const
struct
file_operations
vmcp_fops = {
175
.owner =
THIS_MODULE
,
176
.open = vmcp_open,
177
.release = vmcp_release,
178
.read = vmcp_read,
179
.write = vmcp_write,
180
.unlocked_ioctl = vmcp_ioctl,
181
.compat_ioctl = vmcp_ioctl,
182
.llseek =
no_llseek
,
183
};
184
185
static
struct
miscdevice
vmcp_dev = {
186
.name =
"vmcp"
,
187
.minor =
MISC_DYNAMIC_MINOR
,
188
.fops = &vmcp_fops,
189
};
190
191
static
int
__init
vmcp_init(
void
)
192
{
193
int
ret
;
194
195
if
(!
MACHINE_IS_VM
)
196
return
0;
197
198
vmcp_debug =
debug_register
(
"vmcp"
, 1, 1, 240);
199
if
(!vmcp_debug)
200
return
-
ENOMEM
;
201
202
ret =
debug_register_view
(vmcp_debug, &
debug_hex_ascii_view
);
203
if
(ret) {
204
debug_unregister
(vmcp_debug);
205
return
ret
;
206
}
207
208
ret =
misc_register
(&vmcp_dev);
209
if
(ret)
210
debug_unregister
(vmcp_debug);
211
return
ret
;
212
}
213
device_initcall
(vmcp_init);
Generated on Thu Jan 10 2013 14:17:38 for Linux Kernel by
1.8.2