aboutsummaryrefslogtreecommitdiff
path: root/hw/misc/armsse-cpuid.c
blob: 5f225096f603cda3aa852ebf2d1907a22405e012 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
/*
 * ARM SSE-200 CPU_IDENTITY register block
 *
 * Copyright (c) 2019 Linaro Limited
 * Written by Peter Maydell
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 or
 *  (at your option) any later version.
 */

/*
 * This is a model of the "CPU_IDENTITY" register block which is part of the
 * Arm SSE-200 and documented in
 * http://infocenter.arm.com/help/topic/com.arm.doc.101104_0100_00_en/corelink_sse200_subsystem_for_embedded_technical_reference_manual_101104_0100_00_en.pdf
 *
 * It consists of one read-only CPUID register (set by QOM property), plus the
 * usual ID registers.
 */

#include "qemu/osdep.h"
#include "qemu/log.h"
#include "qemu/module.h"
#include "trace.h"
#include "qapi/error.h"
#include "sysemu/sysemu.h"
#include "hw/sysbus.h"
#include "hw/registerfields.h"
#include "hw/misc/armsse-cpuid.h"
#include "hw/qdev-properties.h"

REG32(CPUID, 0x0)
REG32(PID4, 0xfd0)
REG32(PID5, 0xfd4)
REG32(PID6, 0xfd8)
REG32(PID7, 0xfdc)
REG32(PID0, 0xfe0)
REG32(PID1, 0xfe4)
REG32(PID2, 0xfe8)
REG32(PID3, 0xfec)
REG32(CID0, 0xff0)
REG32(CID1, 0xff4)
REG32(CID2, 0xff8)
REG32(CID3, 0xffc)

/* PID/CID values */
static const int sysinfo_id[] = {
    0x04, 0x00, 0x00, 0x00, /* PID4..PID7 */
    0x58, 0xb8, 0x0b, 0x00, /* PID0..PID3 */
    0x0d, 0xf0, 0x05, 0xb1, /* CID0..CID3 */
};

static uint64_t armsse_cpuid_read(void *opaque, hwaddr offset,
                                    unsigned size)
{
    ARMSSECPUID *s = ARMSSE_CPUID(opaque);
    uint64_t r;

    switch (offset) {
    case A_CPUID:
        r = s->cpuid;
        break;
    case A_PID4 ... A_CID3:
        r = sysinfo_id[(offset - A_PID4) / 4];
        break;
    default:
        qemu_log_mask(LOG_GUEST_ERROR,
                      "SSE CPU_IDENTITY read: bad offset 0x%x\n", (int)offset);
        r = 0;
        break;
    }
    trace_armsse_cpuid_read(offset, r, size);
    return r;
}

static void armsse_cpuid_write(void *opaque, hwaddr offset,
                                 uint64_t value, unsigned size)
{
    trace_armsse_cpuid_write(offset, value, size);

    qemu_log_mask(LOG_GUEST_ERROR,
                  "SSE CPU_IDENTITY: write to RO offset 0x%x\n", (int)offset);
}

static const MemoryRegionOps armsse_cpuid_ops = {
    .read = armsse_cpuid_read,
    .write = armsse_cpuid_write,
    .endianness = DEVICE_LITTLE_ENDIAN,
    /* byte/halfword accesses are just zero-padded on reads and writes */
    .impl.min_access_size = 4,
    .impl.max_access_size = 4,
    .valid.min_access_size = 1,
    .valid.max_access_size = 4,
};

static Property armsse_cpuid_props[] = {
    DEFINE_PROP_UINT32("CPUID", ARMSSECPUID, cpuid, 0),
    DEFINE_PROP_END_OF_LIST()
};

static void armsse_cpuid_init(Object *obj)
{
    SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
    ARMSSECPUID *s = ARMSSE_CPUID(obj);

    memory_region_init_io(&s->iomem, obj, &armsse_cpuid_ops,
                          s, "armsse-cpuid", 0x1000);
    sysbus_init_mmio(sbd, &s->iomem);
}

static void armsse_cpuid_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);

    /*
     * This device has no guest-modifiable state and so it
     * does not need a reset function or VMState.
     */

    dc->props = armsse_cpuid_props;
}

static const TypeInfo armsse_cpuid_info = {
    .name = TYPE_ARMSSE_CPUID,
    .parent = TYPE_SYS_BUS_DEVICE,
    .instance_size = sizeof(ARMSSECPUID),
    .instance_init = armsse_cpuid_init,
    .class_init = armsse_cpuid_class_init,
};

static void armsse_cpuid_register_types(void)
{
    type_register_static(&armsse_cpuid_info);
}

type_init(armsse_cpuid_register_types);