master
c 221 lines 7.44 KB
Raw
1 /*
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
4 * SCLP event type 11 - Control-Program Identification (CPI):
5 * CPI is used to send program identifiers from the guest to the
6 * Service-Call Logical Processor (SCLP). It is not sent by the SCLP.
7 *
8 * Control-program identifiers provide data about the guest operating
9 * system. The control-program identifiers are: system type, system name,
10 * system level and sysplex name.
11 *
12 * In Linux, all the control-program identifiers are user configurable. The
13 * system type, system name, and sysplex name use EBCDIC characters from
14 * this set: capital A-Z, 0-9, $, @, #, and blank. In Linux, the system
15 * type, system name and sysplex name are arbitrary free-form texts.
16 *
17 * In Linux, the 8-byte hexadecimal system-level has the format
18 * 0x<a><b><cc><dd><eeee><ff><gg><hh>, where:
19 * <a>: is a 4-bit digit, its most significant bit indicates hypervisor use
20 * <b>: is one digit that represents Linux distributions as follows
21 * 0: generic Linux
22 * 1: Red Hat Enterprise Linux
23 * 2: SUSE Linux Enterprise Server
24 * 3: Canonical Ubuntu
25 * 4: Fedora
26 * 5: openSUSE Leap
27 * 6: Debian GNU/Linux
28 * 7: Red Hat Enterprise Linux CoreOS
29 * <cc>: are two digits for a distribution-specific encoding of the major
30 * version of the distribution
31 * <dd>: are two digits for a distribution-specific encoding of the minor
32 * version of the distribution
33 * <eeee>: are four digits for the patch level of the distribution
34 * <ff>: are two digits for the major version of the kernel
35 * <gg>: are two digits for the minor version of the kernel
36 * <hh>: are two digits for the stable version of the kernel
37 * (e.g. 74872343805430528, when converted to hex is 0x010a000000060b00). On
38 * machines prior to z16, some of the values are not available to display.
39 *
40 * Sysplex refers to a cluster of logical partitions that communicates and
41 * co-operates with each other.
42 *
43 * The CPI feature is supported since 10.1.
44 *
45 * Copyright IBM, Corp. 2024
46 *
47 * Authors:
48 * Shalini Chellathurai Saroja <shalini@linux.ibm.com>
49 *
50 */
51
52 #include "qemu/osdep.h"
53 #include "qemu/timer.h"
54 #include "hw/s390x/event-facility.h"
55 #include "hw/s390x/ebcdic.h"
56 #include "qapi/qapi-visit-machine.h"
57 #include "qapi/qapi-events-machine-s390x.h"
58 #include "migration/vmstate.h"
59
60 typedef struct Data {
61 uint8_t id_format;
62 uint8_t reserved0;
63 uint8_t system_type[8];
64 uint64_t reserved1;
65 uint8_t system_name[8];
66 uint64_t reserved2;
67 uint64_t system_level;
68 uint64_t reserved3;
69 uint8_t sysplex_name[8];
70 uint8_t reserved4[16];
71 } QEMU_PACKED Data;
72
73 typedef struct ControlProgramIdMsg {
74 EventBufferHeader ebh;
75 Data data;
76 } QEMU_PACKED ControlProgramIdMsg;
77
78 static bool can_handle_event(uint8_t type)
79 {
80 return type == SCLP_EVENT_CTRL_PGM_ID;
81 }
82
83 static sccb_mask_t send_mask(void)
84 {
85 return 0;
86 }
87
88 /* Enable SCLP to accept buffers of event type CPI from the control-program. */
89 static sccb_mask_t receive_mask(void)
90 {
91 return SCLP_EVENT_MASK_CTRL_PGM_ID;
92 }
93
94 static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
95 {
96 ControlProgramIdMsg *cpim = container_of(evt_buf_hdr, ControlProgramIdMsg,
97 ebh);
98 SCLPEventCPI *e = SCLP_EVENT_CPI(event);
99
100 /* Caller checks sccb length, buffer header checking is our duty */
101 if (be16_to_cpu(evt_buf_hdr->length) != sizeof(ControlProgramIdMsg)) {
102 return SCLP_RC_INCONSISTENT_LENGTHS;
103 }
104
105 ascii_put(e->system_type, (char *)cpim->data.system_type,
106 sizeof(cpim->data.system_type));
107 ascii_put(e->system_name, (char *)cpim->data.system_name,
108 sizeof(cpim->data.system_name));
109 ascii_put(e->sysplex_name, (char *)cpim->data.sysplex_name,
110 sizeof(cpim->data.sysplex_name));
111 e->system_level = ldq_be_p(&cpim->data.system_level);
112 e->timestamp = qemu_clock_get_ns(QEMU_CLOCK_HOST);
113
114 cpim->ebh.flags = SCLP_EVENT_BUFFER_ACCEPTED;
115
116 qapi_event_send_sclp_cpi_info_available();
117
118 return SCLP_RC_NORMAL_COMPLETION;
119 }
120
121 static char *get_system_type(Object *obj, Error **errp)
122 {
123 SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
124
125 return g_strndup((char *) e->system_type, sizeof(e->system_type));
126 }
127
128 static char *get_system_name(Object *obj, Error **errp)
129 {
130 SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
131
132 return g_strndup((char *) e->system_name, sizeof(e->system_name));
133 }
134
135 static char *get_sysplex_name(Object *obj, Error **errp)
136 {
137 SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
138
139 return g_strndup((char *) e->sysplex_name, sizeof(e->sysplex_name));
140 }
141
142 static void get_system_level(Object *obj, Visitor *v, const char *name,
143 void *opaque, Error **errp)
144 {
145 SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
146
147 visit_type_uint64(v, name, &e->system_level, errp);
148 }
149
150 static void get_timestamp(Object *obj, Visitor *v, const char *name,
151 void *opaque, Error **errp)
152 {
153 SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
154
155 visit_type_uint64(v, name, &e->timestamp, errp);
156 }
157
158 static const VMStateDescription vmstate_sclpcpi = {
159 .name = "s390_control_program_id",
160 .version_id = 0,
161 .fields = (const VMStateField[]) {
162 VMSTATE_UINT8_ARRAY(system_type, SCLPEventCPI, 8),
163 VMSTATE_UINT8_ARRAY(system_name, SCLPEventCPI, 8),
164 VMSTATE_UINT64(system_level, SCLPEventCPI),
165 VMSTATE_UINT8_ARRAY(sysplex_name, SCLPEventCPI, 8),
166 VMSTATE_UINT64(timestamp, SCLPEventCPI),
167 VMSTATE_END_OF_LIST()
168 }
169 };
170
171 static void cpi_class_init(ObjectClass *klass, const void *data)
172 {
173 DeviceClass *dc = DEVICE_CLASS(klass);
174 SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
175
176 dc->user_creatable = false;
177 dc->vmsd = &vmstate_sclpcpi;
178
179 k->can_handle_event = can_handle_event;
180 k->get_send_mask = send_mask;
181 k->get_receive_mask = receive_mask;
182 k->write_event_data = write_event_data;
183
184 object_class_property_add_str(klass, "system_type", get_system_type, NULL);
185 object_class_property_set_description(klass, "system_type",
186 "operating system e.g. \"LINUX \"");
187
188 object_class_property_add_str(klass, "system_name", get_system_name, NULL);
189 object_class_property_set_description(klass, "system_name",
190 "user configurable name of the VM e.g. \"TESTVM \"");
191
192 object_class_property_add_str(klass, "sysplex_name", get_sysplex_name,
193 NULL);
194 object_class_property_set_description(klass, "sysplex_name",
195 "name of the cluster which the VM belongs to, if any"
196 " e.g. \"PLEX \"");
197
198 object_class_property_add(klass, "system_level", "uint64", get_system_level,
199 NULL, NULL, NULL);
200 object_class_property_set_description(klass, "system_level",
201 "distribution and kernel version in Linux e.g. 74872343805430528");
202
203 object_class_property_add(klass, "timestamp", "uint64", get_timestamp,
204 NULL, NULL, NULL);
205 object_class_property_set_description(klass, "timestamp",
206 "latest update of CPI data in nanoseconds since the UNIX EPOCH");
207 }
208
209 static const TypeInfo sclp_cpi_info = {
210 .name = TYPE_SCLP_EVENT_CPI,
211 .parent = TYPE_SCLP_EVENT,
212 .instance_size = sizeof(SCLPEventCPI),
213 .class_init = cpi_class_init,
214 };
215
216 static void sclp_cpi_register_types(void)
217 {
218 type_register_static(&sclp_cpi_info);
219 }
220
221 type_init(sclp_cpi_register_types)