xref: /qemu/hw/s390x/sclpcpi.c (revision 1721fe75df1cbabf2665a2b76a6e7b5bc0fc036b)
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 "migration/vmstate.h"
58 
59 typedef struct Data {
60     uint8_t id_format;
61     uint8_t reserved0;
62     uint8_t system_type[8];
63     uint64_t reserved1;
64     uint8_t system_name[8];
65     uint64_t reserved2;
66     uint64_t system_level;
67     uint64_t reserved3;
68     uint8_t sysplex_name[8];
69     uint8_t reserved4[16];
70 } QEMU_PACKED Data;
71 
72 typedef struct ControlProgramIdMsg {
73     EventBufferHeader ebh;
74     Data data;
75 } QEMU_PACKED ControlProgramIdMsg;
76 
can_handle_event(uint8_t type)77 static bool can_handle_event(uint8_t type)
78 {
79     return type == SCLP_EVENT_CTRL_PGM_ID;
80 }
81 
send_mask(void)82 static sccb_mask_t send_mask(void)
83 {
84     return 0;
85 }
86 
87 /* Enable SCLP to accept buffers of event type CPI from the control-program. */
receive_mask(void)88 static sccb_mask_t receive_mask(void)
89 {
90     return SCLP_EVENT_MASK_CTRL_PGM_ID;
91 }
92 
write_event_data(SCLPEvent * event,EventBufferHeader * evt_buf_hdr)93 static int write_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr)
94 {
95     ControlProgramIdMsg *cpim = container_of(evt_buf_hdr, ControlProgramIdMsg,
96                                              ebh);
97     SCLPEventCPI *e = SCLP_EVENT_CPI(event);
98 
99     ascii_put(e->system_type, (char *)cpim->data.system_type,
100               sizeof(cpim->data.system_type));
101     ascii_put(e->system_name, (char *)cpim->data.system_name,
102               sizeof(cpim->data.system_name));
103     ascii_put(e->sysplex_name, (char *)cpim->data.sysplex_name,
104               sizeof(cpim->data.sysplex_name));
105     e->system_level = ldq_be_p(&cpim->data.system_level);
106     e->timestamp = qemu_clock_get_ns(QEMU_CLOCK_HOST);
107 
108     cpim->ebh.flags = SCLP_EVENT_BUFFER_ACCEPTED;
109     return SCLP_RC_NORMAL_COMPLETION;
110 }
111 
get_system_type(Object * obj,Error ** errp)112 static char *get_system_type(Object *obj, Error **errp)
113 {
114     SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
115 
116     return g_strndup((char *) e->system_type, sizeof(e->system_type));
117 }
118 
get_system_name(Object * obj,Error ** errp)119 static char *get_system_name(Object *obj, Error **errp)
120 {
121     SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
122 
123     return g_strndup((char *) e->system_name, sizeof(e->system_name));
124 }
125 
get_sysplex_name(Object * obj,Error ** errp)126 static char *get_sysplex_name(Object *obj, Error **errp)
127 {
128     SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
129 
130     return g_strndup((char *) e->sysplex_name, sizeof(e->sysplex_name));
131 }
132 
get_system_level(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)133 static void get_system_level(Object *obj, Visitor *v, const char *name,
134                              void *opaque, Error **errp)
135 {
136     SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
137 
138     visit_type_uint64(v, name, &e->system_level, errp);
139 }
140 
get_timestamp(Object * obj,Visitor * v,const char * name,void * opaque,Error ** errp)141 static void get_timestamp(Object *obj, Visitor *v, const char *name,
142                              void *opaque, Error **errp)
143 {
144     SCLPEventCPI *e = SCLP_EVENT_CPI(obj);
145 
146     visit_type_uint64(v, name, &e->timestamp, errp);
147 }
148 
149 static const VMStateDescription vmstate_sclpcpi = {
150     .name = "s390_control_program_id",
151     .version_id = 0,
152     .fields = (const VMStateField[]) {
153         VMSTATE_UINT8_ARRAY(system_type, SCLPEventCPI, 8),
154         VMSTATE_UINT8_ARRAY(system_name, SCLPEventCPI, 8),
155         VMSTATE_UINT64(system_level, SCLPEventCPI),
156         VMSTATE_UINT8_ARRAY(sysplex_name, SCLPEventCPI, 8),
157         VMSTATE_UINT64(timestamp, SCLPEventCPI),
158         VMSTATE_END_OF_LIST()
159     }
160 };
161 
cpi_class_init(ObjectClass * klass,const void * data)162 static void cpi_class_init(ObjectClass *klass, const void *data)
163 {
164     DeviceClass *dc = DEVICE_CLASS(klass);
165     SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
166 
167     dc->user_creatable = false;
168     dc->vmsd =  &vmstate_sclpcpi;
169 
170     k->can_handle_event = can_handle_event;
171     k->get_send_mask = send_mask;
172     k->get_receive_mask = receive_mask;
173     k->write_event_data = write_event_data;
174 
175     object_class_property_add_str(klass, "system_type", get_system_type, NULL);
176     object_class_property_set_description(klass, "system_type",
177             "operating system e.g. \"LINUX   \"");
178 
179     object_class_property_add_str(klass, "system_name", get_system_name, NULL);
180     object_class_property_set_description(klass, "system_name",
181             "user configurable name of the VM e.g. \"TESTVM  \"");
182 
183     object_class_property_add_str(klass, "sysplex_name", get_sysplex_name,
184                                   NULL);
185     object_class_property_set_description(klass, "sysplex_name",
186             "name of the cluster which the VM belongs to, if any"
187             " e.g. \"PLEX    \"");
188 
189     object_class_property_add(klass, "system_level", "uint64", get_system_level,
190                               NULL, NULL, NULL);
191     object_class_property_set_description(klass, "system_level",
192             "distribution and kernel version in Linux e.g. 74872343805430528");
193 
194     object_class_property_add(klass, "timestamp", "uint64", get_timestamp,
195                               NULL, NULL, NULL);
196     object_class_property_set_description(klass, "timestamp",
197             "latest update of CPI data in nanoseconds since the UNIX EPOCH");
198 }
199 
200 static const TypeInfo sclp_cpi_info = {
201     .name          = TYPE_SCLP_EVENT_CPI,
202     .parent        = TYPE_SCLP_EVENT,
203     .instance_size = sizeof(SCLPEventCPI),
204     .class_init    = cpi_class_init,
205 };
206 
sclp_cpi_register_types(void)207 static void sclp_cpi_register_types(void)
208 {
209     type_register_static(&sclp_cpi_info);
210 }
211 
212 type_init(sclp_cpi_register_types)
213