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 77 static bool can_handle_event(uint8_t type) 78 { 79 return type == SCLP_EVENT_CTRL_PGM_ID; 80 } 81 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. */ 88 static sccb_mask_t receive_mask(void) 89 { 90 return SCLP_EVENT_MASK_CTRL_PGM_ID; 91 } 92 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 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 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 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 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 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 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 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