~ubuntu-branches/ubuntu/vivid/qemu-linaro/vivid

« back to all changes in this revision

Viewing changes to memory_mapping.c

  • Committer: Ricardo Salveti de Araujo
  • Date: 2012-09-20 18:39:31 UTC
  • mfrom: (12922.1.2 qemu-linaro)
  • Revision ID: ricardo.salveti@linaro.org-20120920183931-sp3cg6kpdl8dmwo9
* New upstream release.
  - support emulated systems with more than 2G of memory. (LP: #1030588)
* Drop powerpc-missing-include.patch - merged upstream.
* Update debian/control:
  - drop perl build dependency.
  - add libfdt-dev build dependency.
* Update debian/qemu-keymaps.install file.
* Update debian/rules:
  - update QEMU_CPU for ARM architecture: armv4l -> armv7l.
  - update conf_audio_drv: default to PulseAudio since PA is the default on
    Ubuntu.
  - enable KVM on ARM architecture.
  - enable flat device tree support (--enable-fdt). (LP: #1030594)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * QEMU memory mapping
 
3
 *
 
4
 * Copyright Fujitsu, Corp. 2011, 2012
 
5
 *
 
6
 * Authors:
 
7
 *     Wen Congyang <wency@cn.fujitsu.com>
 
8
 *
 
9
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
 
10
 * See the COPYING file in the top-level directory.
 
11
 *
 
12
 */
 
13
 
 
14
#include "cpu.h"
 
15
#include "cpu-all.h"
 
16
#include "memory_mapping.h"
 
17
 
 
18
static void memory_mapping_list_add_mapping_sorted(MemoryMappingList *list,
 
19
                                                   MemoryMapping *mapping)
 
20
{
 
21
    MemoryMapping *p;
 
22
 
 
23
    QTAILQ_FOREACH(p, &list->head, next) {
 
24
        if (p->phys_addr >= mapping->phys_addr) {
 
25
            QTAILQ_INSERT_BEFORE(p, mapping, next);
 
26
            return;
 
27
        }
 
28
    }
 
29
    QTAILQ_INSERT_TAIL(&list->head, mapping, next);
 
30
}
 
31
 
 
32
static void create_new_memory_mapping(MemoryMappingList *list,
 
33
                                      target_phys_addr_t phys_addr,
 
34
                                      target_phys_addr_t virt_addr,
 
35
                                      ram_addr_t length)
 
36
{
 
37
    MemoryMapping *memory_mapping;
 
38
 
 
39
    memory_mapping = g_malloc(sizeof(MemoryMapping));
 
40
    memory_mapping->phys_addr = phys_addr;
 
41
    memory_mapping->virt_addr = virt_addr;
 
42
    memory_mapping->length = length;
 
43
    list->last_mapping = memory_mapping;
 
44
    list->num++;
 
45
    memory_mapping_list_add_mapping_sorted(list, memory_mapping);
 
46
}
 
47
 
 
48
static inline bool mapping_contiguous(MemoryMapping *map,
 
49
                                      target_phys_addr_t phys_addr,
 
50
                                      target_phys_addr_t virt_addr)
 
51
{
 
52
    return phys_addr == map->phys_addr + map->length &&
 
53
           virt_addr == map->virt_addr + map->length;
 
54
}
 
55
 
 
56
/*
 
57
 * [map->phys_addr, map->phys_addr + map->length) and
 
58
 * [phys_addr, phys_addr + length) have intersection?
 
59
 */
 
60
static inline bool mapping_have_same_region(MemoryMapping *map,
 
61
                                            target_phys_addr_t phys_addr,
 
62
                                            ram_addr_t length)
 
63
{
 
64
    return !(phys_addr + length < map->phys_addr ||
 
65
             phys_addr >= map->phys_addr + map->length);
 
66
}
 
67
 
 
68
/*
 
69
 * [map->phys_addr, map->phys_addr + map->length) and
 
70
 * [phys_addr, phys_addr + length) have intersection. The virtual address in the
 
71
 * intersection are the same?
 
72
 */
 
73
static inline bool mapping_conflict(MemoryMapping *map,
 
74
                                    target_phys_addr_t phys_addr,
 
75
                                    target_phys_addr_t virt_addr)
 
76
{
 
77
    return virt_addr - map->virt_addr != phys_addr - map->phys_addr;
 
78
}
 
79
 
 
80
/*
 
81
 * [map->virt_addr, map->virt_addr + map->length) and
 
82
 * [virt_addr, virt_addr + length) have intersection. And the physical address
 
83
 * in the intersection are the same.
 
84
 */
 
85
static inline void mapping_merge(MemoryMapping *map,
 
86
                                 target_phys_addr_t virt_addr,
 
87
                                 ram_addr_t length)
 
88
{
 
89
    if (virt_addr < map->virt_addr) {
 
90
        map->length += map->virt_addr - virt_addr;
 
91
        map->virt_addr = virt_addr;
 
92
    }
 
93
 
 
94
    if ((virt_addr + length) >
 
95
        (map->virt_addr + map->length)) {
 
96
        map->length = virt_addr + length - map->virt_addr;
 
97
    }
 
98
}
 
99
 
 
100
void memory_mapping_list_add_merge_sorted(MemoryMappingList *list,
 
101
                                          target_phys_addr_t phys_addr,
 
102
                                          target_phys_addr_t virt_addr,
 
103
                                          ram_addr_t length)
 
104
{
 
105
    MemoryMapping *memory_mapping, *last_mapping;
 
106
 
 
107
    if (QTAILQ_EMPTY(&list->head)) {
 
108
        create_new_memory_mapping(list, phys_addr, virt_addr, length);
 
109
        return;
 
110
    }
 
111
 
 
112
    last_mapping = list->last_mapping;
 
113
    if (last_mapping) {
 
114
        if (mapping_contiguous(last_mapping, phys_addr, virt_addr)) {
 
115
            last_mapping->length += length;
 
116
            return;
 
117
        }
 
118
    }
 
119
 
 
120
    QTAILQ_FOREACH(memory_mapping, &list->head, next) {
 
121
        if (mapping_contiguous(memory_mapping, phys_addr, virt_addr)) {
 
122
            memory_mapping->length += length;
 
123
            list->last_mapping = memory_mapping;
 
124
            return;
 
125
        }
 
126
 
 
127
        if (phys_addr + length < memory_mapping->phys_addr) {
 
128
            /* create a new region before memory_mapping */
 
129
            break;
 
130
        }
 
131
 
 
132
        if (mapping_have_same_region(memory_mapping, phys_addr, length)) {
 
133
            if (mapping_conflict(memory_mapping, phys_addr, virt_addr)) {
 
134
                continue;
 
135
            }
 
136
 
 
137
            /* merge this region into memory_mapping */
 
138
            mapping_merge(memory_mapping, virt_addr, length);
 
139
            list->last_mapping = memory_mapping;
 
140
            return;
 
141
        }
 
142
    }
 
143
 
 
144
    /* this region can not be merged into any existed memory mapping. */
 
145
    create_new_memory_mapping(list, phys_addr, virt_addr, length);
 
146
}
 
147
 
 
148
void memory_mapping_list_free(MemoryMappingList *list)
 
149
{
 
150
    MemoryMapping *p, *q;
 
151
 
 
152
    QTAILQ_FOREACH_SAFE(p, &list->head, next, q) {
 
153
        QTAILQ_REMOVE(&list->head, p, next);
 
154
        g_free(p);
 
155
    }
 
156
 
 
157
    list->num = 0;
 
158
    list->last_mapping = NULL;
 
159
}
 
160
 
 
161
void memory_mapping_list_init(MemoryMappingList *list)
 
162
{
 
163
    list->num = 0;
 
164
    list->last_mapping = NULL;
 
165
    QTAILQ_INIT(&list->head);
 
166
}
 
167
 
 
168
static CPUArchState *find_paging_enabled_cpu(CPUArchState *start_cpu)
 
169
{
 
170
    CPUArchState *env;
 
171
 
 
172
    for (env = start_cpu; env != NULL; env = env->next_cpu) {
 
173
        if (cpu_paging_enabled(env)) {
 
174
            return env;
 
175
        }
 
176
    }
 
177
 
 
178
    return NULL;
 
179
}
 
180
 
 
181
int qemu_get_guest_memory_mapping(MemoryMappingList *list)
 
182
{
 
183
    CPUArchState *env, *first_paging_enabled_cpu;
 
184
    RAMBlock *block;
 
185
    ram_addr_t offset, length;
 
186
    int ret;
 
187
 
 
188
    first_paging_enabled_cpu = find_paging_enabled_cpu(first_cpu);
 
189
    if (first_paging_enabled_cpu) {
 
190
        for (env = first_paging_enabled_cpu; env != NULL; env = env->next_cpu) {
 
191
            ret = cpu_get_memory_mapping(list, env);
 
192
            if (ret < 0) {
 
193
                return -1;
 
194
            }
 
195
        }
 
196
        return 0;
 
197
    }
 
198
 
 
199
    /*
 
200
     * If the guest doesn't use paging, the virtual address is equal to physical
 
201
     * address.
 
202
     */
 
203
    QLIST_FOREACH(block, &ram_list.blocks, next) {
 
204
        offset = block->offset;
 
205
        length = block->length;
 
206
        create_new_memory_mapping(list, offset, offset, length);
 
207
    }
 
208
 
 
209
    return 0;
 
210
}
 
211
 
 
212
void qemu_get_guest_simple_memory_mapping(MemoryMappingList *list)
 
213
{
 
214
    RAMBlock *block;
 
215
 
 
216
    QLIST_FOREACH(block, &ram_list.blocks, next) {
 
217
        create_new_memory_mapping(list, block->offset, 0, block->length);
 
218
    }
 
219
}
 
220
 
 
221
void memory_mapping_filter(MemoryMappingList *list, int64_t begin,
 
222
                           int64_t length)
 
223
{
 
224
    MemoryMapping *cur, *next;
 
225
 
 
226
    QTAILQ_FOREACH_SAFE(cur, &list->head, next, next) {
 
227
        if (cur->phys_addr >= begin + length ||
 
228
            cur->phys_addr + cur->length <= begin) {
 
229
            QTAILQ_REMOVE(&list->head, cur, next);
 
230
            list->num--;
 
231
            continue;
 
232
        }
 
233
 
 
234
        if (cur->phys_addr < begin) {
 
235
            cur->length -= begin - cur->phys_addr;
 
236
            if (cur->virt_addr) {
 
237
                cur->virt_addr += begin - cur->phys_addr;
 
238
            }
 
239
            cur->phys_addr = begin;
 
240
        }
 
241
 
 
242
        if (cur->phys_addr + cur->length > begin + length) {
 
243
            cur->length -= cur->phys_addr + cur->length - begin - length;
 
244
        }
 
245
    }
 
246
}