qemu

Форк
0
/
cpu-target.c 
474 строки · 12.8 Кб
1
/*
2
 * Target-specific parts of the CPU object
3
 *
4
 *  Copyright (c) 2003 Fabrice Bellard
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it under the terms of the GNU Lesser General Public
8
 * License as published by the Free Software Foundation; either
9
 * version 2 of the License, or (at your option) any later version.
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14
 * Lesser General Public License for more details.
15
 *
16
 * You should have received a copy of the GNU Lesser General Public
17
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18
 */
19

20
#include "qemu/osdep.h"
21
#include "qapi/error.h"
22

23
#include "exec/target_page.h"
24
#include "exec/page-protection.h"
25
#include "hw/qdev-core.h"
26
#include "hw/qdev-properties.h"
27
#include "qemu/error-report.h"
28
#include "qemu/qemu-print.h"
29
#include "migration/vmstate.h"
30
#ifdef CONFIG_USER_ONLY
31
#include "qemu.h"
32
#else
33
#include "hw/core/sysemu-cpu-ops.h"
34
#include "exec/address-spaces.h"
35
#include "exec/memory.h"
36
#endif
37
#include "sysemu/cpus.h"
38
#include "sysemu/tcg.h"
39
#include "exec/tswap.h"
40
#include "exec/replay-core.h"
41
#include "exec/cpu-common.h"
42
#include "exec/exec-all.h"
43
#include "exec/tb-flush.h"
44
#include "exec/translate-all.h"
45
#include "exec/log.h"
46
#include "hw/core/accel-cpu.h"
47
#include "trace/trace-root.h"
48
#include "qemu/accel.h"
49

50
#ifndef CONFIG_USER_ONLY
51
static int cpu_common_post_load(void *opaque, int version_id)
52
{
53
    CPUState *cpu = opaque;
54

55
    /* 0x01 was CPU_INTERRUPT_EXIT. This line can be removed when the
56
       version_id is increased. */
57
    cpu->interrupt_request &= ~0x01;
58
    tlb_flush(cpu);
59

60
    /* loadvm has just updated the content of RAM, bypassing the
61
     * usual mechanisms that ensure we flush TBs for writes to
62
     * memory we've translated code from. So we must flush all TBs,
63
     * which will now be stale.
64
     */
65
    tb_flush(cpu);
66

67
    return 0;
68
}
69

70
static int cpu_common_pre_load(void *opaque)
71
{
72
    CPUState *cpu = opaque;
73

74
    cpu->exception_index = -1;
75

76
    return 0;
77
}
78

79
static bool cpu_common_exception_index_needed(void *opaque)
80
{
81
    CPUState *cpu = opaque;
82

83
    return tcg_enabled() && cpu->exception_index != -1;
84
}
85

86
static const VMStateDescription vmstate_cpu_common_exception_index = {
87
    .name = "cpu_common/exception_index",
88
    .version_id = 1,
89
    .minimum_version_id = 1,
90
    .needed = cpu_common_exception_index_needed,
91
    .fields = (const VMStateField[]) {
92
        VMSTATE_INT32(exception_index, CPUState),
93
        VMSTATE_END_OF_LIST()
94
    }
95
};
96

97
static bool cpu_common_crash_occurred_needed(void *opaque)
98
{
99
    CPUState *cpu = opaque;
100

101
    return cpu->crash_occurred;
102
}
103

104
static const VMStateDescription vmstate_cpu_common_crash_occurred = {
105
    .name = "cpu_common/crash_occurred",
106
    .version_id = 1,
107
    .minimum_version_id = 1,
108
    .needed = cpu_common_crash_occurred_needed,
109
    .fields = (const VMStateField[]) {
110
        VMSTATE_BOOL(crash_occurred, CPUState),
111
        VMSTATE_END_OF_LIST()
112
    }
113
};
114

115
const VMStateDescription vmstate_cpu_common = {
116
    .name = "cpu_common",
117
    .version_id = 1,
118
    .minimum_version_id = 1,
119
    .pre_load = cpu_common_pre_load,
120
    .post_load = cpu_common_post_load,
121
    .fields = (const VMStateField[]) {
122
        VMSTATE_UINT32(halted, CPUState),
123
        VMSTATE_UINT32(interrupt_request, CPUState),
124
        VMSTATE_END_OF_LIST()
125
    },
126
    .subsections = (const VMStateDescription * const []) {
127
        &vmstate_cpu_common_exception_index,
128
        &vmstate_cpu_common_crash_occurred,
129
        NULL
130
    }
131
};
132
#endif
133

134
bool cpu_exec_realizefn(CPUState *cpu, Error **errp)
135
{
136
    /* cache the cpu class for the hotpath */
137
    cpu->cc = CPU_GET_CLASS(cpu);
138

139
    if (!accel_cpu_common_realize(cpu, errp)) {
140
        return false;
141
    }
142

143
    /* Wait until cpu initialization complete before exposing cpu. */
144
    cpu_list_add(cpu);
145

146
#ifdef CONFIG_USER_ONLY
147
    assert(qdev_get_vmsd(DEVICE(cpu)) == NULL ||
148
           qdev_get_vmsd(DEVICE(cpu))->unmigratable);
149
#else
150
    if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
151
        vmstate_register(NULL, cpu->cpu_index, &vmstate_cpu_common, cpu);
152
    }
153
    if (cpu->cc->sysemu_ops->legacy_vmsd != NULL) {
154
        vmstate_register(NULL, cpu->cpu_index, cpu->cc->sysemu_ops->legacy_vmsd, cpu);
155
    }
156
#endif /* CONFIG_USER_ONLY */
157

158
    return true;
159
}
160

161
void cpu_exec_unrealizefn(CPUState *cpu)
162
{
163
#ifndef CONFIG_USER_ONLY
164
    CPUClass *cc = CPU_GET_CLASS(cpu);
165

166
    if (cc->sysemu_ops->legacy_vmsd != NULL) {
167
        vmstate_unregister(NULL, cc->sysemu_ops->legacy_vmsd, cpu);
168
    }
169
    if (qdev_get_vmsd(DEVICE(cpu)) == NULL) {
170
        vmstate_unregister(NULL, &vmstate_cpu_common, cpu);
171
    }
172
#endif
173

174
    cpu_list_remove(cpu);
175
    /*
176
     * Now that the vCPU has been removed from the RCU list, we can call
177
     * accel_cpu_common_unrealize, which may free fields using call_rcu.
178
     */
179
    accel_cpu_common_unrealize(cpu);
180
}
181

182
/*
183
 * This can't go in hw/core/cpu.c because that file is compiled only
184
 * once for both user-mode and system builds.
185
 */
186
static Property cpu_common_props[] = {
187
#ifdef CONFIG_USER_ONLY
188
    /*
189
     * Create a property for the user-only object, so users can
190
     * adjust prctl(PR_SET_UNALIGN) from the command-line.
191
     * Has no effect if the target does not support the feature.
192
     */
193
    DEFINE_PROP_BOOL("prctl-unalign-sigbus", CPUState,
194
                     prctl_unalign_sigbus, false),
195
#else
196
    /*
197
     * Create a memory property for system CPU object, so users can
198
     * wire up its memory.  The default if no link is set up is to use
199
     * the system address space.
200
     */
201
    DEFINE_PROP_LINK("memory", CPUState, memory, TYPE_MEMORY_REGION,
202
                     MemoryRegion *),
203
#endif
204
    DEFINE_PROP_END_OF_LIST(),
205
};
206

207
#ifndef CONFIG_USER_ONLY
208
static bool cpu_get_start_powered_off(Object *obj, Error **errp)
209
{
210
    CPUState *cpu = CPU(obj);
211
    return cpu->start_powered_off;
212
}
213

214
static void cpu_set_start_powered_off(Object *obj, bool value, Error **errp)
215
{
216
    CPUState *cpu = CPU(obj);
217
    cpu->start_powered_off = value;
218
}
219
#endif
220

221
void cpu_class_init_props(DeviceClass *dc)
222
{
223
#ifndef CONFIG_USER_ONLY
224
    ObjectClass *oc = OBJECT_CLASS(dc);
225

226
    /*
227
     * We can't use DEFINE_PROP_BOOL in the Property array for this
228
     * property, because we want this to be settable after realize.
229
     */
230
    object_class_property_add_bool(oc, "start-powered-off",
231
                                   cpu_get_start_powered_off,
232
                                   cpu_set_start_powered_off);
233
#endif
234

235
    device_class_set_props(dc, cpu_common_props);
236
}
237

238
void cpu_exec_initfn(CPUState *cpu)
239
{
240
    cpu->as = NULL;
241
    cpu->num_ases = 0;
242

243
#ifndef CONFIG_USER_ONLY
244
    cpu->memory = get_system_memory();
245
    object_ref(OBJECT(cpu->memory));
246
#endif
247
}
248

249
char *cpu_model_from_type(const char *typename)
250
{
251
    const char *suffix = "-" CPU_RESOLVING_TYPE;
252

253
    if (!object_class_by_name(typename)) {
254
        return NULL;
255
    }
256

257
    if (g_str_has_suffix(typename, suffix)) {
258
        return g_strndup(typename, strlen(typename) - strlen(suffix));
259
    }
260

261
    return g_strdup(typename);
262
}
263

264
const char *parse_cpu_option(const char *cpu_option)
265
{
266
    ObjectClass *oc;
267
    CPUClass *cc;
268
    gchar **model_pieces;
269
    const char *cpu_type;
270

271
    model_pieces = g_strsplit(cpu_option, ",", 2);
272
    if (!model_pieces[0]) {
273
        error_report("-cpu option cannot be empty");
274
        exit(1);
275
    }
276

277
    oc = cpu_class_by_name(CPU_RESOLVING_TYPE, model_pieces[0]);
278
    if (oc == NULL) {
279
        error_report("unable to find CPU model '%s'", model_pieces[0]);
280
        g_strfreev(model_pieces);
281
        exit(EXIT_FAILURE);
282
    }
283

284
    cpu_type = object_class_get_name(oc);
285
    cc = CPU_CLASS(oc);
286
    cc->parse_features(cpu_type, model_pieces[1], &error_fatal);
287
    g_strfreev(model_pieces);
288
    return cpu_type;
289
}
290

291
#ifndef cpu_list
292
static void cpu_list_entry(gpointer data, gpointer user_data)
293
{
294
    CPUClass *cc = CPU_CLASS(OBJECT_CLASS(data));
295
    const char *typename = object_class_get_name(OBJECT_CLASS(data));
296
    g_autofree char *model = cpu_model_from_type(typename);
297

298
    if (cc->deprecation_note) {
299
        qemu_printf("  %s (deprecated)\n", model);
300
    } else {
301
        qemu_printf("  %s\n", model);
302
    }
303
}
304

305
static void cpu_list(void)
306
{
307
    GSList *list;
308

309
    list = object_class_get_list_sorted(TYPE_CPU, false);
310
    qemu_printf("Available CPUs:\n");
311
    g_slist_foreach(list, cpu_list_entry, NULL);
312
    g_slist_free(list);
313
}
314
#endif
315

316
void list_cpus(void)
317
{
318
    cpu_list();
319
}
320

321
/* enable or disable single step mode. EXCP_DEBUG is returned by the
322
   CPU loop after each instruction */
323
void cpu_single_step(CPUState *cpu, int enabled)
324
{
325
    if (cpu->singlestep_enabled != enabled) {
326
        cpu->singlestep_enabled = enabled;
327

328
#if !defined(CONFIG_USER_ONLY)
329
        const AccelOpsClass *ops = cpus_get_accel();
330
        if (ops->update_guest_debug) {
331
            ops->update_guest_debug(cpu);
332
        }
333
#endif
334

335
        trace_breakpoint_singlestep(cpu->cpu_index, enabled);
336
    }
337
}
338

339
void cpu_abort(CPUState *cpu, const char *fmt, ...)
340
{
341
    va_list ap;
342
    va_list ap2;
343

344
    va_start(ap, fmt);
345
    va_copy(ap2, ap);
346
    fprintf(stderr, "qemu: fatal: ");
347
    vfprintf(stderr, fmt, ap);
348
    fprintf(stderr, "\n");
349
    cpu_dump_state(cpu, stderr, CPU_DUMP_FPU | CPU_DUMP_CCOP);
350
    if (qemu_log_separate()) {
351
        FILE *logfile = qemu_log_trylock();
352
        if (logfile) {
353
            fprintf(logfile, "qemu: fatal: ");
354
            vfprintf(logfile, fmt, ap2);
355
            fprintf(logfile, "\n");
356
            cpu_dump_state(cpu, logfile, CPU_DUMP_FPU | CPU_DUMP_CCOP);
357
            qemu_log_unlock(logfile);
358
        }
359
    }
360
    va_end(ap2);
361
    va_end(ap);
362
    replay_finish();
363
#if defined(CONFIG_USER_ONLY)
364
    {
365
        struct sigaction act;
366
        sigfillset(&act.sa_mask);
367
        act.sa_handler = SIG_DFL;
368
        act.sa_flags = 0;
369
        sigaction(SIGABRT, &act, NULL);
370
    }
371
#endif
372
    abort();
373
}
374

375
/* physical memory access (slow version, mainly for debug) */
376
#if defined(CONFIG_USER_ONLY)
377
int cpu_memory_rw_debug(CPUState *cpu, vaddr addr,
378
                        void *ptr, size_t len, bool is_write)
379
{
380
    int flags;
381
    vaddr l, page;
382
    void * p;
383
    uint8_t *buf = ptr;
384
    ssize_t written;
385
    int ret = -1;
386
    int fd = -1;
387

388
    while (len > 0) {
389
        page = addr & TARGET_PAGE_MASK;
390
        l = (page + TARGET_PAGE_SIZE) - addr;
391
        if (l > len)
392
            l = len;
393
        flags = page_get_flags(page);
394
        if (!(flags & PAGE_VALID)) {
395
            goto out_close;
396
        }
397
        if (is_write) {
398
            if (flags & PAGE_WRITE) {
399
                /* XXX: this code should not depend on lock_user */
400
                p = lock_user(VERIFY_WRITE, addr, l, 0);
401
                if (!p) {
402
                    goto out_close;
403
                }
404
                memcpy(p, buf, l);
405
                unlock_user(p, addr, l);
406
            } else {
407
                /* Bypass the host page protection using ptrace. */
408
                if (fd == -1) {
409
                    fd = open("/proc/self/mem", O_WRONLY);
410
                    if (fd == -1) {
411
                        goto out;
412
                    }
413
                }
414
                /*
415
                 * If there is a TranslationBlock and we weren't bypassing the
416
                 * host page protection, the memcpy() above would SEGV,
417
                 * ultimately leading to page_unprotect(). So invalidate the
418
                 * translations manually. Both invalidation and pwrite() must
419
                 * be under mmap_lock() in order to prevent the creation of
420
                 * another TranslationBlock in between.
421
                 */
422
                mmap_lock();
423
                tb_invalidate_phys_range(addr, addr + l - 1);
424
                written = pwrite(fd, buf, l,
425
                                 (off_t)(uintptr_t)g2h_untagged(addr));
426
                mmap_unlock();
427
                if (written != l) {
428
                    goto out_close;
429
                }
430
            }
431
        } else if (flags & PAGE_READ) {
432
            /* XXX: this code should not depend on lock_user */
433
            p = lock_user(VERIFY_READ, addr, l, 1);
434
            if (!p) {
435
                goto out_close;
436
            }
437
            memcpy(buf, p, l);
438
            unlock_user(p, addr, 0);
439
        } else {
440
            /* Bypass the host page protection using ptrace. */
441
            if (fd == -1) {
442
                fd = open("/proc/self/mem", O_RDONLY);
443
                if (fd == -1) {
444
                    goto out;
445
                }
446
            }
447
            if (pread(fd, buf, l,
448
                      (off_t)(uintptr_t)g2h_untagged(addr)) != l) {
449
                goto out_close;
450
            }
451
        }
452
        len -= l;
453
        buf += l;
454
        addr += l;
455
    }
456
    ret = 0;
457
out_close:
458
    if (fd != -1) {
459
        close(fd);
460
    }
461
out:
462
    return ret;
463
}
464
#endif
465

466
bool target_words_bigendian(void)
467
{
468
    return TARGET_BIG_ENDIAN;
469
}
470

471
const char *target_name(void)
472
{
473
    return TARGET_NAME;
474
}
475

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.