1f6c98f92SHeinz Graalfs /*
2f6c98f92SHeinz Graalfs * SCLP Support
3f6c98f92SHeinz Graalfs *
4f6c98f92SHeinz Graalfs * Copyright IBM, Corp. 2012
5f6c98f92SHeinz Graalfs *
6f6c98f92SHeinz Graalfs * Authors:
7f6c98f92SHeinz Graalfs * Christian Borntraeger <borntraeger@de.ibm.com>
8f6c98f92SHeinz Graalfs * Heinz Graalfs <graalfs@linux.vnet.ibm.com>
9f6c98f92SHeinz Graalfs *
10f6c98f92SHeinz Graalfs * This work is licensed under the terms of the GNU GPL, version 2 or (at your
11f6c98f92SHeinz Graalfs * option) any later version. See the COPYING file in the top-level directory.
12f6c98f92SHeinz Graalfs *
13f6c98f92SHeinz Graalfs */
14f6c98f92SHeinz Graalfs
159615495aSPeter Maydell #include "qemu/osdep.h"
16393fc4c7SPhilippe Mathieu-Daudé #include "qemu/units.h"
17da34e65cSMarkus Armbruster #include "qapi/error.h"
18311467f7SDavid Hildenbrand #include "hw/boards.h"
1983c9f4caSPaolo Bonzini #include "hw/s390x/sclp.h"
20477a72a1SHeinz Graalfs #include "hw/s390x/event-facility.h"
218cba80c3SFrank Blaschka #include "hw/s390x/s390-pci-bus.h"
22b038411dSFarhan Ali #include "hw/s390x/ipl.h"
23a67f05b3SPierre Morel #include "hw/s390x/cpu-topology.h"
243d9836e4SCédric Le Goater #include "hw/s390x/s390-virtio-ccw.h"
25f6c98f92SHeinz Graalfs
get_sclp_device(void)263d9836e4SCédric Le Goater static SCLPDevice *get_sclp_device(void)
2725a3c5afSDavid Hildenbrand {
28989fd865SChristian Borntraeger static SCLPDevice *sclp;
29989fd865SChristian Borntraeger
30989fd865SChristian Borntraeger if (!sclp) {
313d9836e4SCédric Le Goater sclp = S390_CCW_MACHINE(qdev_get_machine())->sclp;
32989fd865SChristian Borntraeger }
33989fd865SChristian Borntraeger return sclp;
3425a3c5afSDavid Hildenbrand }
3525a3c5afSDavid Hildenbrand
sclp_command_code_valid(uint32_t code)360f73c5b3SJanosch Frank static inline bool sclp_command_code_valid(uint32_t code)
370f73c5b3SJanosch Frank {
380f73c5b3SJanosch Frank switch (code & SCLP_CMD_CODE_MASK) {
390f73c5b3SJanosch Frank case SCLP_CMDW_READ_SCP_INFO:
400f73c5b3SJanosch Frank case SCLP_CMDW_READ_SCP_INFO_FORCED:
410f73c5b3SJanosch Frank case SCLP_CMDW_READ_CPU_INFO:
420f73c5b3SJanosch Frank case SCLP_CMDW_CONFIGURE_IOA:
430f73c5b3SJanosch Frank case SCLP_CMDW_DECONFIGURE_IOA:
440f73c5b3SJanosch Frank case SCLP_CMD_READ_EVENT_DATA:
450f73c5b3SJanosch Frank case SCLP_CMD_WRITE_EVENT_DATA:
460f73c5b3SJanosch Frank case SCLP_CMD_WRITE_EVENT_MASK:
470f73c5b3SJanosch Frank return true;
480f73c5b3SJanosch Frank }
490f73c5b3SJanosch Frank return false;
500f73c5b3SJanosch Frank }
510f73c5b3SJanosch Frank
sccb_verify_boundary(uint64_t sccb_addr,uint16_t sccb_len,uint32_t code)521ecd6078SCollin Walling static bool sccb_verify_boundary(uint64_t sccb_addr, uint16_t sccb_len,
531ecd6078SCollin Walling uint32_t code)
54db13387cSCollin Walling {
55db13387cSCollin Walling uint64_t sccb_max_addr = sccb_addr + sccb_len - 1;
56ed3288ffSThomas Huth uint64_t sccb_boundary = (sccb_addr & TARGET_PAGE_MASK) + TARGET_PAGE_SIZE;
57db13387cSCollin Walling
581ecd6078SCollin Walling switch (code & SCLP_CMD_CODE_MASK) {
591ecd6078SCollin Walling case SCLP_CMDW_READ_SCP_INFO:
601ecd6078SCollin Walling case SCLP_CMDW_READ_SCP_INFO_FORCED:
611ecd6078SCollin Walling case SCLP_CMDW_READ_CPU_INFO:
621ecd6078SCollin Walling /*
631ecd6078SCollin Walling * An extended-length SCCB is only allowed for Read SCP/CPU Info and
641ecd6078SCollin Walling * is allowed to exceed the 4k boundary. The respective commands will
651ecd6078SCollin Walling * set the length field to the required length if an insufficient
661ecd6078SCollin Walling * SCCB length is provided.
671ecd6078SCollin Walling */
681ecd6078SCollin Walling if (s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB)) {
691ecd6078SCollin Walling return true;
701ecd6078SCollin Walling }
711ecd6078SCollin Walling /* fallthrough */
721ecd6078SCollin Walling default:
73db13387cSCollin Walling if (sccb_max_addr < sccb_boundary) {
74db13387cSCollin Walling return true;
75db13387cSCollin Walling }
761ecd6078SCollin Walling }
77db13387cSCollin Walling
78db13387cSCollin Walling return false;
79db13387cSCollin Walling }
80db13387cSCollin Walling
prepare_cpu_entries(MachineState * ms,CPUEntry * entry,int * count)81912d70d2SCollin Walling static void prepare_cpu_entries(MachineState *ms, CPUEntry *entry, int *count)
82026546e6SDavid Hildenbrand {
834dd4200eSDavid Hildenbrand uint8_t features[SCCB_CPU_FEATURE_LEN] = { 0 };
84026546e6SDavid Hildenbrand int i;
85026546e6SDavid Hildenbrand
864dd4200eSDavid Hildenbrand s390_get_feat_block(S390_FEAT_TYPE_SCLP_CPU, features);
87bb535bb6SDavid Hildenbrand for (i = 0, *count = 0; i < ms->possible_cpus->len; i++) {
88bb535bb6SDavid Hildenbrand if (!ms->possible_cpus->cpus[i].cpu) {
89bb535bb6SDavid Hildenbrand continue;
90bb535bb6SDavid Hildenbrand }
91bb535bb6SDavid Hildenbrand entry[*count].address = ms->possible_cpus->cpus[i].arch_id;
92bb535bb6SDavid Hildenbrand entry[*count].type = 0;
93bb535bb6SDavid Hildenbrand memcpy(entry[*count].features, features, sizeof(features));
94bb535bb6SDavid Hildenbrand (*count)++;
95026546e6SDavid Hildenbrand }
96026546e6SDavid Hildenbrand }
97026546e6SDavid Hildenbrand
980260b978SCollin Walling #define SCCB_REQ_LEN(s, max_cpus) (sizeof(s) + max_cpus * sizeof(CPUEntry))
990260b978SCollin Walling
ext_len_sccb_supported(SCCBHeader header)1001ecd6078SCollin Walling static inline bool ext_len_sccb_supported(SCCBHeader header)
1011ecd6078SCollin Walling {
1021ecd6078SCollin Walling return s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB) &&
1031ecd6078SCollin Walling header.control_mask[2] & SCLP_VARIABLE_LENGTH_RESPONSE;
1041ecd6078SCollin Walling }
1051ecd6078SCollin Walling
106f6c98f92SHeinz Graalfs /* Provide information about the configuration, CPUs and storage */
read_SCP_info(SCLPDevice * sclp,SCCB * sccb)10725a3c5afSDavid Hildenbrand static void read_SCP_info(SCLPDevice *sclp, SCCB *sccb)
108f6c98f92SHeinz Graalfs {
109f6c98f92SHeinz Graalfs ReadInfo *read_info = (ReadInfo *) sccb;
110311467f7SDavid Hildenbrand MachineState *machine = MACHINE(qdev_get_machine());
111bb535bb6SDavid Hildenbrand int cpu_count;
1121def6656SMatthew Rosato int rnsize, rnmax;
1130260b978SCollin Walling int required_len = SCCB_REQ_LEN(ReadInfo, machine->possible_cpus->len);
1141ecd6078SCollin Walling int offset_cpu = s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB) ?
1151ecd6078SCollin Walling offsetof(ReadInfo, entries) :
1161ecd6078SCollin Walling SCLP_READ_SCP_INFO_FIXED_CPU_OFFSET;
1171a7a5688SCollin Walling CPUEntry *entries_start = (void *)sccb + offset_cpu;
1180260b978SCollin Walling
1190260b978SCollin Walling if (be16_to_cpu(sccb->h.length) < required_len) {
1201ecd6078SCollin Walling if (ext_len_sccb_supported(sccb->h)) {
1211ecd6078SCollin Walling sccb->h.length = cpu_to_be16(required_len);
1221ecd6078SCollin Walling }
1230260b978SCollin Walling sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
1240260b978SCollin Walling return;
1250260b978SCollin Walling }
1268cc3aecfSJason J. Herne
127a67f05b3SPierre Morel if (s390_has_topology()) {
128a67f05b3SPierre Morel read_info->stsi_parm = SCLP_READ_SCP_INFO_MNEST;
129a67f05b3SPierre Morel }
130a67f05b3SPierre Morel
1318cc3aecfSJason J. Herne /* CPU information */
1321a7a5688SCollin Walling prepare_cpu_entries(machine, entries_start, &cpu_count);
1338cc3aecfSJason J. Herne read_info->entries_cpu = cpu_to_be16(cpu_count);
1341a7a5688SCollin Walling read_info->offset_cpu = cpu_to_be16(offset_cpu);
135ae71ed86SLike Xu read_info->highest_cpu = cpu_to_be16(machine->smp.max_cpus - 1);
1368cc3aecfSJason J. Herne
137059be520SDavid Hildenbrand read_info->ibc_val = cpu_to_be32(s390_get_ibc_val());
138059be520SDavid Hildenbrand
1394dd4200eSDavid Hildenbrand /* Configuration Characteristic (Extension) */
1404dd4200eSDavid Hildenbrand s390_get_feat_block(S390_FEAT_TYPE_SCLP_CONF_CHAR,
1414dd4200eSDavid Hildenbrand read_info->conf_char);
1424dd4200eSDavid Hildenbrand s390_get_feat_block(S390_FEAT_TYPE_SCLP_CONF_CHAR_EXT,
1434dd4200eSDavid Hildenbrand read_info->conf_char_ext);
1444dd4200eSDavid Hildenbrand
145fabdada9SCollin Walling if (s390_has_feat(S390_FEAT_EXTENDED_LENGTH_SCCB)) {
146fabdada9SCollin Walling s390_get_feat_block(S390_FEAT_TYPE_SCLP_FAC134,
147fabdada9SCollin Walling &read_info->fac134);
148fabdada9SCollin Walling }
149fabdada9SCollin Walling
1508cba80c3SFrank Blaschka read_info->facilities = cpu_to_be64(SCLP_HAS_CPU_INFO |
15180b7a265SCornelia Huck SCLP_HAS_IOA_RECONFIG);
152f6c98f92SHeinz Graalfs
1533fad3252SDavid Hildenbrand read_info->mha_pow = s390_get_mha_pow();
154a3669307SDavid Hildenbrand read_info->hmfai = cpu_to_be32(s390_get_hmfai());
1551def6656SMatthew Rosato
15671a2fd35SDavid Hildenbrand rnsize = 1 << (sclp->increment_size - 20);
1571def6656SMatthew Rosato if (rnsize <= 128) {
1581def6656SMatthew Rosato read_info->rnsize = rnsize;
1591def6656SMatthew Rosato } else {
1601def6656SMatthew Rosato read_info->rnsize = 0;
1611def6656SMatthew Rosato read_info->rnsize2 = cpu_to_be32(rnsize);
1621def6656SMatthew Rosato }
1631def6656SMatthew Rosato
16482fab5c5SDavid Hildenbrand /* we don't support standby memory, maxram_size is never exposed */
16582fab5c5SDavid Hildenbrand rnmax = machine->ram_size >> sclp->increment_size;
1661def6656SMatthew Rosato if (rnmax < 0x10000) {
1671def6656SMatthew Rosato read_info->rnmax = cpu_to_be16(rnmax);
1681def6656SMatthew Rosato } else {
1691def6656SMatthew Rosato read_info->rnmax = cpu_to_be16(0);
1701def6656SMatthew Rosato read_info->rnmax2 = cpu_to_be64(rnmax);
1711def6656SMatthew Rosato }
1721def6656SMatthew Rosato
173*bb185de4SJared Rossi s390_ipl_convert_loadparm((char *)S390_CCW_MACHINE(machine)->loadparm,
174*bb185de4SJared Rossi read_info->loadparm);
175b038411dSFarhan Ali
176f6c98f92SHeinz Graalfs sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
177f6c98f92SHeinz Graalfs }
178f6c98f92SHeinz Graalfs
1798cc3aecfSJason J. Herne /* Provide information about the CPU */
sclp_read_cpu_info(SCLPDevice * sclp,SCCB * sccb)18025a3c5afSDavid Hildenbrand static void sclp_read_cpu_info(SCLPDevice *sclp, SCCB *sccb)
1818cc3aecfSJason J. Herne {
182912d70d2SCollin Walling MachineState *machine = MACHINE(qdev_get_machine());
1838cc3aecfSJason J. Herne ReadCpuInfo *cpu_info = (ReadCpuInfo *) sccb;
184bb535bb6SDavid Hildenbrand int cpu_count;
1850260b978SCollin Walling int required_len = SCCB_REQ_LEN(ReadCpuInfo, machine->possible_cpus->len);
1860260b978SCollin Walling
1870260b978SCollin Walling if (be16_to_cpu(sccb->h.length) < required_len) {
1881ecd6078SCollin Walling if (ext_len_sccb_supported(sccb->h)) {
1891ecd6078SCollin Walling sccb->h.length = cpu_to_be16(required_len);
1901ecd6078SCollin Walling }
1910260b978SCollin Walling sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
1920260b978SCollin Walling return;
1930260b978SCollin Walling }
1948cc3aecfSJason J. Herne
195912d70d2SCollin Walling prepare_cpu_entries(machine, cpu_info->entries, &cpu_count);
1968cc3aecfSJason J. Herne cpu_info->nr_configured = cpu_to_be16(cpu_count);
1978cc3aecfSJason J. Herne cpu_info->offset_configured = cpu_to_be16(offsetof(ReadCpuInfo, entries));
1988cc3aecfSJason J. Herne cpu_info->nr_standby = cpu_to_be16(0);
1998cc3aecfSJason J. Herne
2008cc3aecfSJason J. Herne /* The standby offset is 16-byte for each CPU */
2018cc3aecfSJason J. Herne cpu_info->offset_standby = cpu_to_be16(cpu_info->offset_configured
2028cc3aecfSJason J. Herne + cpu_info->nr_configured*sizeof(CPUEntry));
2038cc3aecfSJason J. Herne
2048cc3aecfSJason J. Herne
2058cc3aecfSJason J. Herne sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_READ_COMPLETION);
2068cc3aecfSJason J. Herne }
2078cc3aecfSJason J. Herne
sclp_configure_io_adapter(SCLPDevice * sclp,SCCB * sccb,bool configure)20880b7a265SCornelia Huck static void sclp_configure_io_adapter(SCLPDevice *sclp, SCCB *sccb,
20980b7a265SCornelia Huck bool configure)
21080b7a265SCornelia Huck {
21180b7a265SCornelia Huck int rc;
21280b7a265SCornelia Huck
21380b7a265SCornelia Huck if (be16_to_cpu(sccb->h.length) < 16) {
21480b7a265SCornelia Huck rc = SCLP_RC_INSUFFICIENT_SCCB_LENGTH;
21580b7a265SCornelia Huck goto out_err;
21680b7a265SCornelia Huck }
21780b7a265SCornelia Huck
21880b7a265SCornelia Huck switch (((IoaCfgSccb *)sccb)->atype) {
21980b7a265SCornelia Huck case SCLP_RECONFIG_PCI_ATYPE:
22080b7a265SCornelia Huck if (s390_has_feat(S390_FEAT_ZPCI)) {
22180b7a265SCornelia Huck if (configure) {
22280b7a265SCornelia Huck s390_pci_sclp_configure(sccb);
22380b7a265SCornelia Huck } else {
22480b7a265SCornelia Huck s390_pci_sclp_deconfigure(sccb);
22580b7a265SCornelia Huck }
22680b7a265SCornelia Huck return;
22780b7a265SCornelia Huck }
22880b7a265SCornelia Huck /* fallthrough */
22980b7a265SCornelia Huck default:
23080b7a265SCornelia Huck rc = SCLP_RC_ADAPTER_TYPE_NOT_RECOGNIZED;
23180b7a265SCornelia Huck }
23280b7a265SCornelia Huck
23380b7a265SCornelia Huck out_err:
23480b7a265SCornelia Huck sccb->h.response_code = cpu_to_be16(rc);
23580b7a265SCornelia Huck }
23680b7a265SCornelia Huck
sclp_execute(SCLPDevice * sclp,SCCB * sccb,uint32_t code)23725a3c5afSDavid Hildenbrand static void sclp_execute(SCLPDevice *sclp, SCCB *sccb, uint32_t code)
238f6c98f92SHeinz Graalfs {
23925a3c5afSDavid Hildenbrand SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
24025a3c5afSDavid Hildenbrand SCLPEventFacility *ef = sclp->event_facility;
241477a72a1SHeinz Graalfs SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
242559a17a1SHeinz Graalfs
2435f04c14aSJason J. Herne switch (code & SCLP_CMD_CODE_MASK) {
244f6c98f92SHeinz Graalfs case SCLP_CMDW_READ_SCP_INFO:
245f6c98f92SHeinz Graalfs case SCLP_CMDW_READ_SCP_INFO_FORCED:
24625a3c5afSDavid Hildenbrand sclp_c->read_SCP_info(sclp, sccb);
247f6c98f92SHeinz Graalfs break;
2488cc3aecfSJason J. Herne case SCLP_CMDW_READ_CPU_INFO:
24925a3c5afSDavid Hildenbrand sclp_c->read_cpu_info(sclp, sccb);
2508cc3aecfSJason J. Herne break;
25180b7a265SCornelia Huck case SCLP_CMDW_CONFIGURE_IOA:
25280b7a265SCornelia Huck sclp_configure_io_adapter(sclp, sccb, true);
2538cba80c3SFrank Blaschka break;
25480b7a265SCornelia Huck case SCLP_CMDW_DECONFIGURE_IOA:
25580b7a265SCornelia Huck sclp_configure_io_adapter(sclp, sccb, false);
2568cba80c3SFrank Blaschka break;
257f6c98f92SHeinz Graalfs default:
258477a72a1SHeinz Graalfs efc->command_handler(ef, sccb, code);
259f6c98f92SHeinz Graalfs break;
260f6c98f92SHeinz Graalfs }
261f6c98f92SHeinz Graalfs }
262f6c98f92SHeinz Graalfs
2630f73c5b3SJanosch Frank /*
2640f73c5b3SJanosch Frank * We only need the address to have something valid for the
2650f73c5b3SJanosch Frank * service_interrupt call.
2660f73c5b3SJanosch Frank */
2670f73c5b3SJanosch Frank #define SCLP_PV_DUMMY_ADDR 0x4000
sclp_service_call_protected(S390CPU * cpu,uint64_t sccb,uint32_t code)2686d3910c9SPhilippe Mathieu-Daudé int sclp_service_call_protected(S390CPU *cpu, uint64_t sccb, uint32_t code)
2690f73c5b3SJanosch Frank {
2706d3910c9SPhilippe Mathieu-Daudé CPUS390XState *env = &cpu->env;
2710f73c5b3SJanosch Frank SCLPDevice *sclp = get_sclp_device();
2720f73c5b3SJanosch Frank SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
273c1db53a5SCollin Walling SCCBHeader header;
274c1db53a5SCollin Walling g_autofree SCCB *work_sccb = NULL;
2750f73c5b3SJanosch Frank
276c1db53a5SCollin Walling s390_cpu_pv_mem_read(env_archcpu(env), 0, &header, sizeof(SCCBHeader));
277c1db53a5SCollin Walling
278c1db53a5SCollin Walling work_sccb = g_malloc0(be16_to_cpu(header.length));
279c1db53a5SCollin Walling s390_cpu_pv_mem_read(env_archcpu(env), 0, work_sccb,
280c1db53a5SCollin Walling be16_to_cpu(header.length));
2810f73c5b3SJanosch Frank
2820f73c5b3SJanosch Frank if (!sclp_command_code_valid(code)) {
283c1db53a5SCollin Walling work_sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
2840f73c5b3SJanosch Frank goto out_write;
2850f73c5b3SJanosch Frank }
2860f73c5b3SJanosch Frank
287c1db53a5SCollin Walling sclp_c->execute(sclp, work_sccb, code);
2880f73c5b3SJanosch Frank out_write:
289c1db53a5SCollin Walling s390_cpu_pv_mem_write(env_archcpu(env), 0, work_sccb,
290c1db53a5SCollin Walling be16_to_cpu(work_sccb->h.length));
2910f73c5b3SJanosch Frank sclp_c->service_interrupt(sclp, SCLP_PV_DUMMY_ADDR);
2920f73c5b3SJanosch Frank return 0;
2930f73c5b3SJanosch Frank }
2940f73c5b3SJanosch Frank
sclp_service_call(S390CPU * cpu,uint64_t sccb,uint32_t code)2956d3910c9SPhilippe Mathieu-Daudé int sclp_service_call(S390CPU *cpu, uint64_t sccb, uint32_t code)
296f6c98f92SHeinz Graalfs {
2976d3910c9SPhilippe Mathieu-Daudé CPUS390XState *env = &cpu->env;
29825a3c5afSDavid Hildenbrand SCLPDevice *sclp = get_sclp_device();
29925a3c5afSDavid Hildenbrand SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
300c1db53a5SCollin Walling SCCBHeader header;
301c1db53a5SCollin Walling g_autofree SCCB *work_sccb = NULL;
302f6c98f92SHeinz Graalfs
303f6c98f92SHeinz Graalfs /* first some basic checks on program checks */
3046e252802SThomas Huth if (env->psw.mask & PSW_MASK_PSTATE) {
305e6de76fcSDaniel Henrique Barboza return -PGM_PRIVILEGED;
3066e252802SThomas Huth }
307f6c98f92SHeinz Graalfs if (cpu_physical_memory_is_io(sccb)) {
308e6de76fcSDaniel Henrique Barboza return -PGM_ADDRESSING;
309f6c98f92SHeinz Graalfs }
3106e252802SThomas Huth if ((sccb & ~0x1fffUL) == 0 || (sccb & ~0x1fffUL) == env->psa
3116e252802SThomas Huth || (sccb & ~0x7ffffff8UL) != 0) {
312e6de76fcSDaniel Henrique Barboza return -PGM_SPECIFICATION;
313f6c98f92SHeinz Graalfs }
314f6c98f92SHeinz Graalfs
315c1db53a5SCollin Walling /* the header contains the actual length of the sccb */
316c1db53a5SCollin Walling cpu_physical_memory_read(sccb, &header, sizeof(SCCBHeader));
317c1db53a5SCollin Walling
318c1db53a5SCollin Walling /* Valid sccb sizes */
319c1db53a5SCollin Walling if (be16_to_cpu(header.length) < sizeof(SCCBHeader)) {
320c1db53a5SCollin Walling return -PGM_SPECIFICATION;
321c1db53a5SCollin Walling }
322c1db53a5SCollin Walling
323f6c98f92SHeinz Graalfs /*
324f6c98f92SHeinz Graalfs * we want to work on a private copy of the sccb, to prevent guests
325f6c98f92SHeinz Graalfs * from playing dirty tricks by modifying the memory content after
326f6c98f92SHeinz Graalfs * the host has checked the values
327f6c98f92SHeinz Graalfs */
328c1db53a5SCollin Walling work_sccb = g_malloc0(be16_to_cpu(header.length));
329c1db53a5SCollin Walling cpu_physical_memory_read(sccb, work_sccb, be16_to_cpu(header.length));
330f6c98f92SHeinz Graalfs
3310f73c5b3SJanosch Frank if (!sclp_command_code_valid(code)) {
332c1db53a5SCollin Walling work_sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
333679b8447SJanosch Frank goto out_write;
334679b8447SJanosch Frank }
335f6c98f92SHeinz Graalfs
3361ecd6078SCollin Walling if (!sccb_verify_boundary(sccb, be16_to_cpu(work_sccb->h.length), code)) {
337c1db53a5SCollin Walling work_sccb->h.response_code = cpu_to_be16(SCLP_RC_SCCB_BOUNDARY_VIOLATION);
3386f6c9333SJanosch Frank goto out_write;
3396f6c9333SJanosch Frank }
3406f6c9333SJanosch Frank
341c1db53a5SCollin Walling sclp_c->execute(sclp, work_sccb, code);
342679b8447SJanosch Frank out_write:
343c1db53a5SCollin Walling cpu_physical_memory_write(sccb, work_sccb,
344c1db53a5SCollin Walling be16_to_cpu(work_sccb->h.length));
345f6c98f92SHeinz Graalfs
3461723a1b6SDavid Hildenbrand sclp_c->service_interrupt(sclp, sccb);
347f6c98f92SHeinz Graalfs
348e6de76fcSDaniel Henrique Barboza return 0;
349f6c98f92SHeinz Graalfs }
350f6c98f92SHeinz Graalfs
service_interrupt(SCLPDevice * sclp,uint32_t sccb)3511723a1b6SDavid Hildenbrand static void service_interrupt(SCLPDevice *sclp, uint32_t sccb)
352f6c98f92SHeinz Graalfs {
3531723a1b6SDavid Hildenbrand SCLPEventFacility *ef = sclp->event_facility;
354477a72a1SHeinz Graalfs SCLPEventFacilityClass *efc = EVENT_FACILITY_GET_CLASS(ef);
355477a72a1SHeinz Graalfs
356559a17a1SHeinz Graalfs uint32_t param = sccb & ~3;
357559a17a1SHeinz Graalfs
358559a17a1SHeinz Graalfs /* Indicate whether an event is still pending */
359477a72a1SHeinz Graalfs param |= efc->event_pending(ef) ? 1 : 0;
360559a17a1SHeinz Graalfs
361559a17a1SHeinz Graalfs if (!param) {
362559a17a1SHeinz Graalfs /* No need to send an interrupt, there's nothing to be notified about */
363559a17a1SHeinz Graalfs return;
364559a17a1SHeinz Graalfs }
365559a17a1SHeinz Graalfs s390_sclp_extint(param);
366f6c98f92SHeinz Graalfs }
367f6c98f92SHeinz Graalfs
sclp_service_interrupt(uint32_t sccb)3681723a1b6SDavid Hildenbrand void sclp_service_interrupt(uint32_t sccb)
3691723a1b6SDavid Hildenbrand {
3701723a1b6SDavid Hildenbrand SCLPDevice *sclp = get_sclp_device();
3711723a1b6SDavid Hildenbrand SCLPDeviceClass *sclp_c = SCLP_GET_CLASS(sclp);
3721723a1b6SDavid Hildenbrand
3731723a1b6SDavid Hildenbrand sclp_c->service_interrupt(sclp, sccb);
3741723a1b6SDavid Hildenbrand }
3751723a1b6SDavid Hildenbrand
376f6c98f92SHeinz Graalfs /* qemu object creation and initialization functions */
sclp_realize(DeviceState * dev,Error ** errp)377515190d9SDavid Hildenbrand static void sclp_realize(DeviceState *dev, Error **errp)
378515190d9SDavid Hildenbrand {
3791cf065fbSDavid Hildenbrand MachineState *machine = MACHINE(qdev_get_machine());
380515190d9SDavid Hildenbrand SCLPDevice *sclp = SCLP(dev);
3811cf065fbSDavid Hildenbrand uint64_t hw_limit;
3821cf065fbSDavid Hildenbrand int ret;
383515190d9SDavid Hildenbrand
3848b638c43SDavid Hildenbrand /*
3858b638c43SDavid Hildenbrand * qdev_device_add searches the sysbus for TYPE_SCLP_EVENTS_BUS. As long
3868b638c43SDavid Hildenbrand * as we can't find a fitting bus via the qom tree, we have to add the
3878b638c43SDavid Hildenbrand * event facility to the sysbus, so e.g. a sclp console can be created.
3888b638c43SDavid Hildenbrand */
389992861fbSMarkus Armbruster if (!sysbus_realize(SYS_BUS_DEVICE(sclp->event_facility), errp)) {
390992861fbSMarkus Armbruster return;
39168424112SMarkus Armbruster }
3921cf065fbSDavid Hildenbrand
3931cf065fbSDavid Hildenbrand ret = s390_set_memory_limit(machine->maxram_size, &hw_limit);
3941cf065fbSDavid Hildenbrand if (ret == -E2BIG) {
395992861fbSMarkus Armbruster error_setg(errp, "host supports a maximum of %" PRIu64 " GB",
396393fc4c7SPhilippe Mathieu-Daudé hw_limit / GiB);
3971cf065fbSDavid Hildenbrand } else if (ret) {
398992861fbSMarkus Armbruster error_setg(errp, "setting the guest size failed");
3991cf065fbSDavid Hildenbrand }
400515190d9SDavid Hildenbrand }
401515190d9SDavid Hildenbrand
sclp_memory_init(SCLPDevice * sclp)4021cf065fbSDavid Hildenbrand static void sclp_memory_init(SCLPDevice *sclp)
4031cf065fbSDavid Hildenbrand {
4041cf065fbSDavid Hildenbrand MachineState *machine = MACHINE(qdev_get_machine());
4055c30ef93SChristian Borntraeger MachineClass *machine_class = MACHINE_GET_CLASS(qdev_get_machine());
4061cf065fbSDavid Hildenbrand ram_addr_t initial_mem = machine->ram_size;
4071cf065fbSDavid Hildenbrand int increment_size = 20;
4081cf065fbSDavid Hildenbrand
4091cf065fbSDavid Hildenbrand /* The storage increment size is a multiple of 1M and is a power of 2.
4105c30ef93SChristian Borntraeger * For some machine types, the number of storage increments must be
4115c30ef93SChristian Borntraeger * MAX_STORAGE_INCREMENTS or fewer.
4121cf065fbSDavid Hildenbrand * The variable 'increment_size' is an exponent of 2 that can be
4131cf065fbSDavid Hildenbrand * used to calculate the size (in bytes) of an increment. */
4145c30ef93SChristian Borntraeger while (machine_class->fixup_ram_size != NULL &&
4155c30ef93SChristian Borntraeger (initial_mem >> increment_size) > MAX_STORAGE_INCREMENTS) {
4161cf065fbSDavid Hildenbrand increment_size++;
4171cf065fbSDavid Hildenbrand }
41871a2fd35SDavid Hildenbrand sclp->increment_size = increment_size;
4191cf065fbSDavid Hildenbrand }
4201cf065fbSDavid Hildenbrand
sclp_init(Object * obj)421515190d9SDavid Hildenbrand static void sclp_init(Object *obj)
422515190d9SDavid Hildenbrand {
423515190d9SDavid Hildenbrand SCLPDevice *sclp = SCLP(obj);
424515190d9SDavid Hildenbrand Object *new;
425515190d9SDavid Hildenbrand
426515190d9SDavid Hildenbrand new = object_new(TYPE_SCLP_EVENT_FACILITY);
427d2623129SMarkus Armbruster object_property_add_child(obj, TYPE_SCLP_EVENT_FACILITY, new);
428515190d9SDavid Hildenbrand object_unref(new);
429515190d9SDavid Hildenbrand sclp->event_facility = EVENT_FACILITY(new);
4301cf065fbSDavid Hildenbrand
4311cf065fbSDavid Hildenbrand sclp_memory_init(sclp);
432515190d9SDavid Hildenbrand }
433515190d9SDavid Hildenbrand
sclp_class_init(ObjectClass * oc,void * data)434515190d9SDavid Hildenbrand static void sclp_class_init(ObjectClass *oc, void *data)
435515190d9SDavid Hildenbrand {
43625a3c5afSDavid Hildenbrand SCLPDeviceClass *sc = SCLP_CLASS(oc);
437515190d9SDavid Hildenbrand DeviceClass *dc = DEVICE_CLASS(oc);
438515190d9SDavid Hildenbrand
439515190d9SDavid Hildenbrand dc->desc = "SCLP (Service-Call Logical Processor)";
440515190d9SDavid Hildenbrand dc->realize = sclp_realize;
441515190d9SDavid Hildenbrand dc->hotpluggable = false;
442515190d9SDavid Hildenbrand set_bit(DEVICE_CATEGORY_MISC, dc->categories);
443e6cb60bfSThomas Huth /*
444e6cb60bfSThomas Huth * Reason: Creates TYPE_SCLP_EVENT_FACILITY in sclp_init
445e6cb60bfSThomas Huth * which is a non-pluggable sysbus device
446e6cb60bfSThomas Huth */
447e6cb60bfSThomas Huth dc->user_creatable = false;
44825a3c5afSDavid Hildenbrand
44925a3c5afSDavid Hildenbrand sc->read_SCP_info = read_SCP_info;
45025a3c5afSDavid Hildenbrand sc->read_cpu_info = sclp_read_cpu_info;
45125a3c5afSDavid Hildenbrand sc->execute = sclp_execute;
4521723a1b6SDavid Hildenbrand sc->service_interrupt = service_interrupt;
453515190d9SDavid Hildenbrand }
454515190d9SDavid Hildenbrand
4555e78c98bSBernhard Beschow static const TypeInfo sclp_info = {
456515190d9SDavid Hildenbrand .name = TYPE_SCLP,
457515190d9SDavid Hildenbrand .parent = TYPE_DEVICE,
458515190d9SDavid Hildenbrand .instance_init = sclp_init,
459515190d9SDavid Hildenbrand .instance_size = sizeof(SCLPDevice),
460515190d9SDavid Hildenbrand .class_init = sclp_class_init,
461515190d9SDavid Hildenbrand .class_size = sizeof(SCLPDeviceClass),
462515190d9SDavid Hildenbrand };
463515190d9SDavid Hildenbrand
register_types(void)4640844df77SMatthew Rosato static void register_types(void)
4650844df77SMatthew Rosato {
466515190d9SDavid Hildenbrand type_register_static(&sclp_info);
4670844df77SMatthew Rosato }
4680844df77SMatthew Rosato type_init(register_types);
469