aboutsummaryrefslogtreecommitdiff
path: root/include/hw/mem/memory-device.h
blob: c0a58087ccc16df8f1df97bd6b61575371f59858 (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
 * Memory Device Interface
 *
 * Copyright (c) 2018 Red Hat, Inc.
 *
 * Authors:
 *  David Hildenbrand <david@redhat.com>
 *
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 * See the COPYING file in the top-level directory.
 */

#ifndef MEMORY_DEVICE_H
#define MEMORY_DEVICE_H

#include "hw/qdev-core.h"
#include "qapi/qapi-types-machine.h"
#include "qom/object.h"

#define TYPE_MEMORY_DEVICE "memory-device"

typedef struct MemoryDeviceClass MemoryDeviceClass;
DECLARE_CLASS_CHECKERS(MemoryDeviceClass, MEMORY_DEVICE,
                       TYPE_MEMORY_DEVICE)
#define MEMORY_DEVICE(obj) \
     INTERFACE_CHECK(MemoryDeviceState, (obj), TYPE_MEMORY_DEVICE)

typedef struct MemoryDeviceState MemoryDeviceState;

/**
 * MemoryDeviceClass:
 *
 * All memory devices need to implement TYPE_MEMORY_DEVICE as an interface.
 *
 * A memory device is a device that owns a memory region which is
 * mapped into guest physical address space at a certain address. The
 * address in guest physical memory can either be specified explicitly
 * or get assigned automatically.
 *
 * Some memory device might not own a memory region in certain device
 * configurations. Such devices can logically get (un)plugged, however,
 * empty memory devices are mostly ignored by the memory device code.
 *
 * Conceptually, memory devices only span one memory region. If multiple
 * successive memory regions are used, a covering memory region has to
 * be provided. Scattered memory regions are not supported for single
 * devices.
 *
 * The device memory region returned via @get_memory_region may either be a
 * single RAM memory region or a memory region container with subregions
 * that are RAM memory regions or aliases to RAM memory regions. Other
 * memory regions or subregions are not supported.
 *
 * If the device memory region returned via @get_memory_region is a
 * memory region container, it's supported to dynamically (un)map subregions
 * as long as the number of memslots returned by @get_memslots() won't
 * be exceeded and as long as all memory regions are of the same kind (e.g.,
 * all RAM or all ROM).
 */
struct MemoryDeviceClass {
    /* private */
    InterfaceClass parent_class;

    /*
     * Return the address of the memory device in guest physical memory.
     *
     * Called when (un)plugging a memory device or when iterating over
     * all memory devices mapped into guest physical address space.
     *
     * If "0" is returned, no address has been specified by the user and
     * no address has been assigned to this memory device yet.
     */
    uint64_t (*get_addr)(const MemoryDeviceState *md);

    /*
     * Set the address of the memory device in guest physical memory.
     *
     * Called when plugging the memory device to configure the determined
     * address in guest physical memory.
     */
    void (*set_addr)(MemoryDeviceState *md, uint64_t addr, Error **errp);

    /*
     * Return the amount of memory provided by the memory device currently
     * usable ("plugged") by the VM.
     *
     * Called when calculating the total amount of ram available to the
     * VM (e.g. to report memory stats to the user).
     *
     * This is helpful for devices that dynamically manage the amount of
     * memory accessible by the guest via the reserved memory region. For
     * most devices, this corresponds to the size of the memory region.
     */
    uint64_t (*get_plugged_size)(const MemoryDeviceState *md, Error **errp);

    /*
     * Return the memory region of the memory device. If the device is
     * completely empty, returns NULL without an error.
     *
     * Called when (un)plugging the memory device, to (un)map the
     * memory region in guest physical memory, but also to detect the
     * required alignment during address assignment or when the size of the
     * memory region is required.
     */
    MemoryRegion *(*get_memory_region)(MemoryDeviceState *md, Error **errp);

    /*
     * Optional: Instruct the memory device to decide how many memory slots
     * it requires, not exceeding the given limit.
     *
     * Called exactly once when pre-plugging the memory device, before
     * querying the number of memslots using @get_memslots the first time.
     */
    void (*decide_memslots)(MemoryDeviceState *md, unsigned int limit);

    /*
     * Optional for memory devices that require only a single memslot,
     * required for all other memory devices: Return the number of memslots
     * (distinct RAM memory regions in the device memory region) that are
     * required by the device.
     *
     * If this function is not implemented, the assumption is "1".
     *
     * Called when (un)plugging the memory device, to check if the requirements
     * can be satisfied, and to do proper accounting.
     */
    unsigned int (*get_memslots)(MemoryDeviceState *md);

    /*
     * Optional: Return the desired minimum alignment of the device in guest
     * physical address space. The final alignment is computed based on this
     * alignment and the alignment requirements of the memory region.
     *
     * Called when plugging the memory device to detect the required alignment
     * during address assignment.
     */
    uint64_t (*get_min_alignment)(const MemoryDeviceState *md);

    /*
     * Translate the memory device into #MemoryDeviceInfo.
     */
    void (*fill_device_info)(const MemoryDeviceState *md,
                             MemoryDeviceInfo *info);
};

/*
 * Traditionally, KVM/vhost in many setups supported 509 memslots, whereby
 * 253 memslots were "reserved" for boot memory and other devices (such
 * as PCI BARs, which can get mapped dynamically) and 256 memslots were
 * dedicated for DIMMs. These magic numbers worked reliably in the past.
 *
 * Further, using many memslots can negatively affect performance, so setting
 * the soft-limit of memslots used by memory devices to the traditional
 * DIMM limit of 256 sounds reasonable.
 *
 * If we have less than 509 memslots, we will instruct memory devices that
 * support automatically deciding how many memslots to use to only use a single
 * one.
 *
 * Hotplugging vhost devices with at least 509 memslots is not expected to
 * cause problems, not even when devices automatically decided how many memslots
 * to use.
 */
#define MEMORY_DEVICES_SOFT_MEMSLOT_LIMIT 256
#define MEMORY_DEVICES_SAFE_MAX_MEMSLOTS 509

MemoryDeviceInfoList *qmp_memory_device_list(void);
uint64_t get_plugged_memory_size(void);
unsigned int memory_devices_get_reserved_memslots(void);
bool memory_devices_memslot_auto_decision_active(void);
void memory_device_pre_plug(MemoryDeviceState *md, MachineState *ms,
                            Error **errp);
void memory_device_plug(MemoryDeviceState *md, MachineState *ms);
void memory_device_unplug(MemoryDeviceState *md, MachineState *ms);
uint64_t memory_device_get_region_size(const MemoryDeviceState *md,
                                       Error **errp);

#endif