Statistics
| Branch: | Revision:

root / target-s390x / misc_helper.c @ 1de7afc9

History | View | Annotate | Download (10.4 kB)

1
/*
2
 *  S/390 misc helper routines
3
 *
4
 *  Copyright (c) 2009 Ulrich Hecht
5
 *  Copyright (c) 2009 Alexander Graf
6
 *
7
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9
 * License as published by the Free Software Foundation; either
10
 * version 2 of the License, or (at your option) any later version.
11
 *
12
 * This library is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15
 * Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
19
 */
20

    
21
#include "cpu.h"
22
#include "exec/memory.h"
23
#include "qemu/host-utils.h"
24
#include "helper.h"
25
#include <string.h>
26
#include "kvm.h"
27
#include "qemu/timer.h"
28
#ifdef CONFIG_KVM
29
#include <linux/kvm.h>
30
#endif
31

    
32
#if !defined(CONFIG_USER_ONLY)
33
#include "exec/softmmu_exec.h"
34
#include "sysemu.h"
35
#endif
36

    
37
/* #define DEBUG_HELPER */
38
#ifdef DEBUG_HELPER
39
#define HELPER_LOG(x...) qemu_log(x)
40
#else
41
#define HELPER_LOG(x...)
42
#endif
43

    
44
/* raise an exception */
45
void HELPER(exception)(CPUS390XState *env, uint32_t excp)
46
{
47
    HELPER_LOG("%s: exception %d\n", __func__, excp);
48
    env->exception_index = excp;
49
    cpu_loop_exit(env);
50
}
51

    
52
#ifndef CONFIG_USER_ONLY
53
void program_interrupt(CPUS390XState *env, uint32_t code, int ilc)
54
{
55
    qemu_log_mask(CPU_LOG_INT, "program interrupt at %#" PRIx64 "\n",
56
                  env->psw.addr);
57

    
58
    if (kvm_enabled()) {
59
#ifdef CONFIG_KVM
60
        kvm_s390_interrupt(env, KVM_S390_PROGRAM_INT, code);
61
#endif
62
    } else {
63
        env->int_pgm_code = code;
64
        env->int_pgm_ilc = ilc;
65
        env->exception_index = EXCP_PGM;
66
        cpu_loop_exit(env);
67
    }
68
}
69

    
70
/* SCLP service call */
71
uint32_t HELPER(servc)(CPUS390XState *env, uint32_t r1, uint64_t r2)
72
{
73
    int r;
74

    
75
    r = sclp_service_call(r1, r2);
76
    if (r < 0) {
77
        program_interrupt(env, -r, 4);
78
        return 0;
79
    }
80
    return r;
81
}
82

    
83
/* DIAG */
84
uint64_t HELPER(diag)(CPUS390XState *env, uint32_t num, uint64_t mem,
85
                      uint64_t code)
86
{
87
    uint64_t r;
88

    
89
    switch (num) {
90
    case 0x500:
91
        /* KVM hypercall */
92
        r = s390_virtio_hypercall(env, mem, code);
93
        break;
94
    case 0x44:
95
        /* yield */
96
        r = 0;
97
        break;
98
    case 0x308:
99
        /* ipl */
100
        r = 0;
101
        break;
102
    default:
103
        r = -1;
104
        break;
105
    }
106

    
107
    if (r) {
108
        program_interrupt(env, PGM_OPERATION, ILC_LATER_INC);
109
    }
110

    
111
    return r;
112
}
113

    
114
/* Store CPU ID */
115
void HELPER(stidp)(CPUS390XState *env, uint64_t a1)
116
{
117
    cpu_stq_data(env, a1, env->cpu_num);
118
}
119

    
120
/* Set Prefix */
121
void HELPER(spx)(CPUS390XState *env, uint64_t a1)
122
{
123
    uint32_t prefix;
124

    
125
    prefix = cpu_ldl_data(env, a1);
126
    env->psa = prefix & 0xfffff000;
127
    qemu_log("prefix: %#x\n", prefix);
128
    tlb_flush_page(env, 0);
129
    tlb_flush_page(env, TARGET_PAGE_SIZE);
130
}
131

    
132
/* Set Clock */
133
uint32_t HELPER(sck)(uint64_t a1)
134
{
135
    /* XXX not implemented - is it necessary? */
136

    
137
    return 0;
138
}
139

    
140
static inline uint64_t clock_value(CPUS390XState *env)
141
{
142
    uint64_t time;
143

    
144
    time = env->tod_offset +
145
        time2tod(qemu_get_clock_ns(vm_clock) - env->tod_basetime);
146

    
147
    return time;
148
}
149

    
150
/* Store Clock */
151
uint32_t HELPER(stck)(CPUS390XState *env, uint64_t a1)
152
{
153
    cpu_stq_data(env, a1, clock_value(env));
154

    
155
    return 0;
156
}
157

    
158
/* Store Clock Extended */
159
uint32_t HELPER(stcke)(CPUS390XState *env, uint64_t a1)
160
{
161
    cpu_stb_data(env, a1, 0);
162
    /* basically the same value as stck */
163
    cpu_stq_data(env, a1 + 1, clock_value(env) | env->cpu_num);
164
    /* more fine grained than stck */
165
    cpu_stq_data(env, a1 + 9, 0);
166
    /* XXX programmable fields */
167
    cpu_stw_data(env, a1 + 17, 0);
168

    
169
    return 0;
170
}
171

    
172
/* Set Clock Comparator */
173
void HELPER(sckc)(CPUS390XState *env, uint64_t a1)
174
{
175
    uint64_t time = cpu_ldq_data(env, a1);
176

    
177
    if (time == -1ULL) {
178
        return;
179
    }
180

    
181
    /* difference between now and then */
182
    time -= clock_value(env);
183
    /* nanoseconds */
184
    time = (time * 125) >> 9;
185

    
186
    qemu_mod_timer(env->tod_timer, qemu_get_clock_ns(vm_clock) + time);
187
}
188

    
189
/* Store Clock Comparator */
190
void HELPER(stckc)(CPUS390XState *env, uint64_t a1)
191
{
192
    /* XXX implement */
193
    cpu_stq_data(env, a1, 0);
194
}
195

    
196
/* Set CPU Timer */
197
void HELPER(spt)(CPUS390XState *env, uint64_t a1)
198
{
199
    uint64_t time = cpu_ldq_data(env, a1);
200

    
201
    if (time == -1ULL) {
202
        return;
203
    }
204

    
205
    /* nanoseconds */
206
    time = (time * 125) >> 9;
207

    
208
    qemu_mod_timer(env->cpu_timer, qemu_get_clock_ns(vm_clock) + time);
209
}
210

    
211
/* Store CPU Timer */
212
void HELPER(stpt)(CPUS390XState *env, uint64_t a1)
213
{
214
    /* XXX implement */
215
    cpu_stq_data(env, a1, 0);
216
}
217

    
218
/* Store System Information */
219
uint32_t HELPER(stsi)(CPUS390XState *env, uint64_t a0, uint32_t r0,
220
                      uint32_t r1)
221
{
222
    int cc = 0;
223
    int sel1, sel2;
224

    
225
    if ((r0 & STSI_LEVEL_MASK) <= STSI_LEVEL_3 &&
226
        ((r0 & STSI_R0_RESERVED_MASK) || (r1 & STSI_R1_RESERVED_MASK))) {
227
        /* valid function code, invalid reserved bits */
228
        program_interrupt(env, PGM_SPECIFICATION, 2);
229
    }
230

    
231
    sel1 = r0 & STSI_R0_SEL1_MASK;
232
    sel2 = r1 & STSI_R1_SEL2_MASK;
233

    
234
    /* XXX: spec exception if sysib is not 4k-aligned */
235

    
236
    switch (r0 & STSI_LEVEL_MASK) {
237
    case STSI_LEVEL_1:
238
        if ((sel1 == 1) && (sel2 == 1)) {
239
            /* Basic Machine Configuration */
240
            struct sysib_111 sysib;
241

    
242
            memset(&sysib, 0, sizeof(sysib));
243
            ebcdic_put(sysib.manuf, "QEMU            ", 16);
244
            /* same as machine type number in STORE CPU ID */
245
            ebcdic_put(sysib.type, "QEMU", 4);
246
            /* same as model number in STORE CPU ID */
247
            ebcdic_put(sysib.model, "QEMU            ", 16);
248
            ebcdic_put(sysib.sequence, "QEMU            ", 16);
249
            ebcdic_put(sysib.plant, "QEMU", 4);
250
            cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
251
        } else if ((sel1 == 2) && (sel2 == 1)) {
252
            /* Basic Machine CPU */
253
            struct sysib_121 sysib;
254

    
255
            memset(&sysib, 0, sizeof(sysib));
256
            /* XXX make different for different CPUs? */
257
            ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
258
            ebcdic_put(sysib.plant, "QEMU", 4);
259
            stw_p(&sysib.cpu_addr, env->cpu_num);
260
            cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
261
        } else if ((sel1 == 2) && (sel2 == 2)) {
262
            /* Basic Machine CPUs */
263
            struct sysib_122 sysib;
264

    
265
            memset(&sysib, 0, sizeof(sysib));
266
            stl_p(&sysib.capability, 0x443afc29);
267
            /* XXX change when SMP comes */
268
            stw_p(&sysib.total_cpus, 1);
269
            stw_p(&sysib.active_cpus, 1);
270
            stw_p(&sysib.standby_cpus, 0);
271
            stw_p(&sysib.reserved_cpus, 0);
272
            cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
273
        } else {
274
            cc = 3;
275
        }
276
        break;
277
    case STSI_LEVEL_2:
278
        {
279
            if ((sel1 == 2) && (sel2 == 1)) {
280
                /* LPAR CPU */
281
                struct sysib_221 sysib;
282

    
283
                memset(&sysib, 0, sizeof(sysib));
284
                /* XXX make different for different CPUs? */
285
                ebcdic_put(sysib.sequence, "QEMUQEMUQEMUQEMU", 16);
286
                ebcdic_put(sysib.plant, "QEMU", 4);
287
                stw_p(&sysib.cpu_addr, env->cpu_num);
288
                stw_p(&sysib.cpu_id, 0);
289
                cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
290
            } else if ((sel1 == 2) && (sel2 == 2)) {
291
                /* LPAR CPUs */
292
                struct sysib_222 sysib;
293

    
294
                memset(&sysib, 0, sizeof(sysib));
295
                stw_p(&sysib.lpar_num, 0);
296
                sysib.lcpuc = 0;
297
                /* XXX change when SMP comes */
298
                stw_p(&sysib.total_cpus, 1);
299
                stw_p(&sysib.conf_cpus, 1);
300
                stw_p(&sysib.standby_cpus, 0);
301
                stw_p(&sysib.reserved_cpus, 0);
302
                ebcdic_put(sysib.name, "QEMU    ", 8);
303
                stl_p(&sysib.caf, 1000);
304
                stw_p(&sysib.dedicated_cpus, 0);
305
                stw_p(&sysib.shared_cpus, 0);
306
                cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
307
            } else {
308
                cc = 3;
309
            }
310
            break;
311
        }
312
    case STSI_LEVEL_3:
313
        {
314
            if ((sel1 == 2) && (sel2 == 2)) {
315
                /* VM CPUs */
316
                struct sysib_322 sysib;
317

    
318
                memset(&sysib, 0, sizeof(sysib));
319
                sysib.count = 1;
320
                /* XXX change when SMP comes */
321
                stw_p(&sysib.vm[0].total_cpus, 1);
322
                stw_p(&sysib.vm[0].conf_cpus, 1);
323
                stw_p(&sysib.vm[0].standby_cpus, 0);
324
                stw_p(&sysib.vm[0].reserved_cpus, 0);
325
                ebcdic_put(sysib.vm[0].name, "KVMguest", 8);
326
                stl_p(&sysib.vm[0].caf, 1000);
327
                ebcdic_put(sysib.vm[0].cpi, "KVM/Linux       ", 16);
328
                cpu_physical_memory_rw(a0, (uint8_t *)&sysib, sizeof(sysib), 1);
329
            } else {
330
                cc = 3;
331
            }
332
            break;
333
        }
334
    case STSI_LEVEL_CURRENT:
335
        env->regs[0] = STSI_LEVEL_3;
336
        break;
337
    default:
338
        cc = 3;
339
        break;
340
    }
341

    
342
    return cc;
343
}
344

    
345
uint32_t HELPER(sigp)(CPUS390XState *env, uint64_t order_code, uint32_t r1,
346
                      uint64_t cpu_addr)
347
{
348
    int cc = 0;
349

    
350
    HELPER_LOG("%s: %016" PRIx64 " %08x %016" PRIx64 "\n",
351
               __func__, order_code, r1, cpu_addr);
352

    
353
    /* Remember: Use "R1 or R1 + 1, whichever is the odd-numbered register"
354
       as parameter (input). Status (output) is always R1. */
355

    
356
    switch (order_code) {
357
    case SIGP_SET_ARCH:
358
        /* switch arch */
359
        break;
360
    case SIGP_SENSE:
361
        /* enumerate CPU status */
362
        if (cpu_addr) {
363
            /* XXX implement when SMP comes */
364
            return 3;
365
        }
366
        env->regs[r1] &= 0xffffffff00000000ULL;
367
        cc = 1;
368
        break;
369
#if !defined(CONFIG_USER_ONLY)
370
    case SIGP_RESTART:
371
        qemu_system_reset_request();
372
        cpu_loop_exit(env);
373
        break;
374
    case SIGP_STOP:
375
        qemu_system_shutdown_request();
376
        cpu_loop_exit(env);
377
        break;
378
#endif
379
    default:
380
        /* unknown sigp */
381
        fprintf(stderr, "XXX unknown sigp: 0x%" PRIx64 "\n", order_code);
382
        cc = 3;
383
    }
384

    
385
    return cc;
386
}
387
#endif