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