root / hw / s390x / sclp.c @ 9c17d615
History | View | Annotate | Download (4 kB)
1 |
/*
|
---|---|
2 |
* SCLP Support
|
3 |
*
|
4 |
* Copyright IBM, Corp. 2012
|
5 |
*
|
6 |
* Authors:
|
7 |
* Christian Borntraeger <borntraeger@de.ibm.com>
|
8 |
* Heinz Graalfs <graalfs@linux.vnet.ibm.com>
|
9 |
*
|
10 |
* This work is licensed under the terms of the GNU GPL, version 2 or (at your
|
11 |
* option) any later version. See the COPYING file in the top-level directory.
|
12 |
*
|
13 |
*/
|
14 |
|
15 |
#include "cpu.h" |
16 |
#include "sysemu/kvm.h" |
17 |
#include "exec/memory.h" |
18 |
|
19 |
#include "sclp.h" |
20 |
|
21 |
static inline S390SCLPDevice *get_event_facility(void) |
22 |
{ |
23 |
ObjectProperty *op = object_property_find(qdev_get_machine(), |
24 |
"s390-sclp-event-facility",
|
25 |
NULL);
|
26 |
assert(op); |
27 |
return op->opaque;
|
28 |
} |
29 |
|
30 |
/* Provide information about the configuration, CPUs and storage */
|
31 |
static void read_SCP_info(SCCB *sccb) |
32 |
{ |
33 |
ReadInfo *read_info = (ReadInfo *) sccb; |
34 |
int shift = 0; |
35 |
|
36 |
while ((ram_size >> (20 + shift)) > 65535) { |
37 |
shift++; |
38 |
} |
39 |
read_info->rnmax = cpu_to_be16(ram_size >> (20 + shift));
|
40 |
read_info->rnsize = 1 << shift;
|
41 |
sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION); |
42 |
} |
43 |
|
44 |
static void sclp_execute(SCCB *sccb, uint64_t code) |
45 |
{ |
46 |
S390SCLPDevice *sdev = get_event_facility(); |
47 |
|
48 |
switch (code) {
|
49 |
case SCLP_CMDW_READ_SCP_INFO:
|
50 |
case SCLP_CMDW_READ_SCP_INFO_FORCED:
|
51 |
read_SCP_info(sccb); |
52 |
break;
|
53 |
default:
|
54 |
sdev->sclp_command_handler(sdev->ef, sccb, code); |
55 |
break;
|
56 |
} |
57 |
} |
58 |
|
59 |
int sclp_service_call(uint32_t sccb, uint64_t code)
|
60 |
{ |
61 |
int r = 0; |
62 |
SCCB work_sccb; |
63 |
|
64 |
hwaddr sccb_len = sizeof(SCCB);
|
65 |
|
66 |
/* first some basic checks on program checks */
|
67 |
if (cpu_physical_memory_is_io(sccb)) {
|
68 |
r = -PGM_ADDRESSING; |
69 |
goto out;
|
70 |
} |
71 |
if (sccb & ~0x7ffffff8ul) { |
72 |
r = -PGM_SPECIFICATION; |
73 |
goto out;
|
74 |
} |
75 |
|
76 |
/*
|
77 |
* we want to work on a private copy of the sccb, to prevent guests
|
78 |
* from playing dirty tricks by modifying the memory content after
|
79 |
* the host has checked the values
|
80 |
*/
|
81 |
cpu_physical_memory_read(sccb, &work_sccb, sccb_len); |
82 |
|
83 |
/* Valid sccb sizes */
|
84 |
if (be16_to_cpu(work_sccb.h.length) < sizeof(SCCBHeader) || |
85 |
be16_to_cpu(work_sccb.h.length) > SCCB_SIZE) { |
86 |
r = -PGM_SPECIFICATION; |
87 |
goto out;
|
88 |
} |
89 |
|
90 |
sclp_execute((SCCB *)&work_sccb, code); |
91 |
|
92 |
cpu_physical_memory_write(sccb, &work_sccb, |
93 |
be16_to_cpu(work_sccb.h.length)); |
94 |
|
95 |
sclp_service_interrupt(sccb); |
96 |
|
97 |
out:
|
98 |
return r;
|
99 |
} |
100 |
|
101 |
void sclp_service_interrupt(uint32_t sccb)
|
102 |
{ |
103 |
S390SCLPDevice *sdev = get_event_facility(); |
104 |
uint32_t param = sccb & ~3;
|
105 |
|
106 |
/* Indicate whether an event is still pending */
|
107 |
param |= sdev->event_pending(sdev->ef) ? 1 : 0; |
108 |
|
109 |
if (!param) {
|
110 |
/* No need to send an interrupt, there's nothing to be notified about */
|
111 |
return;
|
112 |
} |
113 |
s390_sclp_extint(param); |
114 |
} |
115 |
|
116 |
/* qemu object creation and initialization functions */
|
117 |
|
118 |
void s390_sclp_init(void) |
119 |
{ |
120 |
DeviceState *dev = qdev_create(NULL, "s390-sclp-event-facility"); |
121 |
|
122 |
object_property_add_child(qdev_get_machine(), "s390-sclp-event-facility",
|
123 |
OBJECT(dev), NULL);
|
124 |
qdev_init_nofail(dev); |
125 |
} |
126 |
|
127 |
static int s390_sclp_dev_init(SysBusDevice *dev) |
128 |
{ |
129 |
int r;
|
130 |
S390SCLPDevice *sdev = (S390SCLPDevice *)dev; |
131 |
S390SCLPDeviceClass *sclp = SCLP_S390_DEVICE_GET_CLASS(dev); |
132 |
|
133 |
r = sclp->init(sdev); |
134 |
if (!r) {
|
135 |
assert(sdev->event_pending); |
136 |
assert(sdev->sclp_command_handler); |
137 |
} |
138 |
|
139 |
return r;
|
140 |
} |
141 |
|
142 |
static void s390_sclp_device_class_init(ObjectClass *klass, void *data) |
143 |
{ |
144 |
SysBusDeviceClass *dc = SYS_BUS_DEVICE_CLASS(klass); |
145 |
|
146 |
dc->init = s390_sclp_dev_init; |
147 |
} |
148 |
|
149 |
static TypeInfo s390_sclp_device_info = {
|
150 |
.name = TYPE_DEVICE_S390_SCLP, |
151 |
.parent = TYPE_SYS_BUS_DEVICE, |
152 |
.instance_size = sizeof(S390SCLPDevice),
|
153 |
.class_init = s390_sclp_device_class_init, |
154 |
.class_size = sizeof(S390SCLPDeviceClass),
|
155 |
.abstract = true,
|
156 |
}; |
157 |
|
158 |
static void s390_sclp_register_types(void) |
159 |
{ |
160 |
type_register_static(&s390_sclp_device_info); |
161 |
} |
162 |
|
163 |
type_init(s390_sclp_register_types) |