Statistics
| Branch: | Revision:

root / memory.c @ 7267c094

History | View | Annotate | Download (34.7 kB)

1
/*
2
 * Physical memory management
3
 *
4
 * Copyright 2011 Red Hat, Inc. and/or its affiliates
5
 *
6
 * Authors:
7
 *  Avi Kivity <avi@redhat.com>
8
 *
9
 * This work is licensed under the terms of the GNU GPL, version 2.  See
10
 * the COPYING file in the top-level directory.
11
 *
12
 */
13

    
14
#include "memory.h"
15
#include "exec-memory.h"
16
#include "ioport.h"
17
#include "bitops.h"
18
#include "kvm.h"
19
#include <assert.h>
20

    
21
unsigned memory_region_transaction_depth = 0;
22

    
23
typedef struct AddrRange AddrRange;
24

    
25
/*
26
 * Note using signed integers limits us to physical addresses at most
27
 * 63 bits wide.  They are needed for negative offsetting in aliases
28
 * (large MemoryRegion::alias_offset).
29
 */
30
struct AddrRange {
31
    int64_t start;
32
    int64_t size;
33
};
34

    
35
static AddrRange addrrange_make(int64_t start, int64_t size)
36
{
37
    return (AddrRange) { start, size };
38
}
39

    
40
static bool addrrange_equal(AddrRange r1, AddrRange r2)
41
{
42
    return r1.start == r2.start && r1.size == r2.size;
43
}
44

    
45
static int64_t addrrange_end(AddrRange r)
46
{
47
    return r.start + r.size;
48
}
49

    
50
static AddrRange addrrange_shift(AddrRange range, int64_t delta)
51
{
52
    range.start += delta;
53
    return range;
54
}
55

    
56
static bool addrrange_intersects(AddrRange r1, AddrRange r2)
57
{
58
    return (r1.start >= r2.start && r1.start < r2.start + r2.size)
59
        || (r2.start >= r1.start && r2.start < r1.start + r1.size);
60
}
61

    
62
static AddrRange addrrange_intersection(AddrRange r1, AddrRange r2)
63
{
64
    int64_t start = MAX(r1.start, r2.start);
65
    /* off-by-one arithmetic to prevent overflow */
66
    int64_t end = MIN(addrrange_end(r1) - 1, addrrange_end(r2) - 1);
67
    return addrrange_make(start, end - start + 1);
68
}
69

    
70
struct CoalescedMemoryRange {
71
    AddrRange addr;
72
    QTAILQ_ENTRY(CoalescedMemoryRange) link;
73
};
74

    
75
struct MemoryRegionIoeventfd {
76
    AddrRange addr;
77
    bool match_data;
78
    uint64_t data;
79
    int fd;
80
};
81

    
82
static bool memory_region_ioeventfd_before(MemoryRegionIoeventfd a,
83
                                           MemoryRegionIoeventfd b)
84
{
85
    if (a.addr.start < b.addr.start) {
86
        return true;
87
    } else if (a.addr.start > b.addr.start) {
88
        return false;
89
    } else if (a.addr.size < b.addr.size) {
90
        return true;
91
    } else if (a.addr.size > b.addr.size) {
92
        return false;
93
    } else if (a.match_data < b.match_data) {
94
        return true;
95
    } else  if (a.match_data > b.match_data) {
96
        return false;
97
    } else if (a.match_data) {
98
        if (a.data < b.data) {
99
            return true;
100
        } else if (a.data > b.data) {
101
            return false;
102
        }
103
    }
104
    if (a.fd < b.fd) {
105
        return true;
106
    } else if (a.fd > b.fd) {
107
        return false;
108
    }
109
    return false;
110
}
111

    
112
static bool memory_region_ioeventfd_equal(MemoryRegionIoeventfd a,
113
                                          MemoryRegionIoeventfd b)
114
{
115
    return !memory_region_ioeventfd_before(a, b)
116
        && !memory_region_ioeventfd_before(b, a);
117
}
118

    
119
typedef struct FlatRange FlatRange;
120
typedef struct FlatView FlatView;
121

    
122
/* Range of memory in the global map.  Addresses are absolute. */
123
struct FlatRange {
124
    MemoryRegion *mr;
125
    target_phys_addr_t offset_in_region;
126
    AddrRange addr;
127
    uint8_t dirty_log_mask;
128
    bool readable;
129
};
130

    
131
/* Flattened global view of current active memory hierarchy.  Kept in sorted
132
 * order.
133
 */
134
struct FlatView {
135
    FlatRange *ranges;
136
    unsigned nr;
137
    unsigned nr_allocated;
138
};
139

    
140
typedef struct AddressSpace AddressSpace;
141
typedef struct AddressSpaceOps AddressSpaceOps;
142

    
143
/* A system address space - I/O, memory, etc. */
144
struct AddressSpace {
145
    const AddressSpaceOps *ops;
146
    MemoryRegion *root;
147
    FlatView current_map;
148
    int ioeventfd_nb;
149
    MemoryRegionIoeventfd *ioeventfds;
150
};
151

    
152
struct AddressSpaceOps {
153
    void (*range_add)(AddressSpace *as, FlatRange *fr);
154
    void (*range_del)(AddressSpace *as, FlatRange *fr);
155
    void (*log_start)(AddressSpace *as, FlatRange *fr);
156
    void (*log_stop)(AddressSpace *as, FlatRange *fr);
157
    void (*ioeventfd_add)(AddressSpace *as, MemoryRegionIoeventfd *fd);
158
    void (*ioeventfd_del)(AddressSpace *as, MemoryRegionIoeventfd *fd);
159
};
160

    
161
#define FOR_EACH_FLAT_RANGE(var, view)          \
162
    for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var)
163

    
164
static bool flatrange_equal(FlatRange *a, FlatRange *b)
165
{
166
    return a->mr == b->mr
167
        && addrrange_equal(a->addr, b->addr)
168
        && a->offset_in_region == b->offset_in_region
169
        && a->readable == b->readable;
170
}
171

    
172
static void flatview_init(FlatView *view)
173
{
174
    view->ranges = NULL;
175
    view->nr = 0;
176
    view->nr_allocated = 0;
177
}
178

    
179
/* Insert a range into a given position.  Caller is responsible for maintaining
180
 * sorting order.
181
 */
182
static void flatview_insert(FlatView *view, unsigned pos, FlatRange *range)
183
{
184
    if (view->nr == view->nr_allocated) {
185
        view->nr_allocated = MAX(2 * view->nr, 10);
186
        view->ranges = g_realloc(view->ranges,
187
                                    view->nr_allocated * sizeof(*view->ranges));
188
    }
189
    memmove(view->ranges + pos + 1, view->ranges + pos,
190
            (view->nr - pos) * sizeof(FlatRange));
191
    view->ranges[pos] = *range;
192
    ++view->nr;
193
}
194

    
195
static void flatview_destroy(FlatView *view)
196
{
197
    g_free(view->ranges);
198
}
199

    
200
static bool can_merge(FlatRange *r1, FlatRange *r2)
201
{
202
    return addrrange_end(r1->addr) == r2->addr.start
203
        && r1->mr == r2->mr
204
        && r1->offset_in_region + r1->addr.size == r2->offset_in_region
205
        && r1->dirty_log_mask == r2->dirty_log_mask
206
        && r1->readable == r2->readable;
207
}
208

    
209
/* Attempt to simplify a view by merging ajacent ranges */
210
static void flatview_simplify(FlatView *view)
211
{
212
    unsigned i, j;
213

    
214
    i = 0;
215
    while (i < view->nr) {
216
        j = i + 1;
217
        while (j < view->nr
218
               && can_merge(&view->ranges[j-1], &view->ranges[j])) {
219
            view->ranges[i].addr.size += view->ranges[j].addr.size;
220
            ++j;
221
        }
222
        ++i;
223
        memmove(&view->ranges[i], &view->ranges[j],
224
                (view->nr - j) * sizeof(view->ranges[j]));
225
        view->nr -= j - i;
226
    }
227
}
228

    
229
static void memory_region_prepare_ram_addr(MemoryRegion *mr);
230

    
231
static void as_memory_range_add(AddressSpace *as, FlatRange *fr)
232
{
233
    ram_addr_t phys_offset, region_offset;
234

    
235
    memory_region_prepare_ram_addr(fr->mr);
236

    
237
    phys_offset = fr->mr->ram_addr;
238
    region_offset = fr->offset_in_region;
239
    /* cpu_register_physical_memory_log() wants region_offset for
240
     * mmio, but prefers offseting phys_offset for RAM.  Humour it.
241
     */
242
    if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
243
        phys_offset += region_offset;
244
        region_offset = 0;
245
    }
246

    
247
    if (!fr->readable) {
248
        phys_offset &= TARGET_PAGE_MASK;
249
    }
250

    
251
    cpu_register_physical_memory_log(fr->addr.start,
252
                                     fr->addr.size,
253
                                     phys_offset,
254
                                     region_offset,
255
                                     fr->dirty_log_mask);
256
}
257

    
258
static void as_memory_range_del(AddressSpace *as, FlatRange *fr)
259
{
260
    if (fr->dirty_log_mask) {
261
        cpu_physical_sync_dirty_bitmap(fr->addr.start,
262
                                       fr->addr.start + fr->addr.size);
263
    }
264
    cpu_register_physical_memory(fr->addr.start, fr->addr.size,
265
                                 IO_MEM_UNASSIGNED);
266
}
267

    
268
static void as_memory_log_start(AddressSpace *as, FlatRange *fr)
269
{
270
    cpu_physical_log_start(fr->addr.start, fr->addr.size);
271
}
272

    
273
static void as_memory_log_stop(AddressSpace *as, FlatRange *fr)
274
{
275
    cpu_physical_log_stop(fr->addr.start, fr->addr.size);
276
}
277

    
278
static void as_memory_ioeventfd_add(AddressSpace *as, MemoryRegionIoeventfd *fd)
279
{
280
    int r;
281

    
282
    assert(fd->match_data && fd->addr.size == 4);
283

    
284
    r = kvm_set_ioeventfd_mmio_long(fd->fd, fd->addr.start, fd->data, true);
285
    if (r < 0) {
286
        abort();
287
    }
288
}
289

    
290
static void as_memory_ioeventfd_del(AddressSpace *as, MemoryRegionIoeventfd *fd)
291
{
292
    int r;
293

    
294
    r = kvm_set_ioeventfd_mmio_long(fd->fd, fd->addr.start, fd->data, false);
295
    if (r < 0) {
296
        abort();
297
    }
298
}
299

    
300
static const AddressSpaceOps address_space_ops_memory = {
301
    .range_add = as_memory_range_add,
302
    .range_del = as_memory_range_del,
303
    .log_start = as_memory_log_start,
304
    .log_stop = as_memory_log_stop,
305
    .ioeventfd_add = as_memory_ioeventfd_add,
306
    .ioeventfd_del = as_memory_ioeventfd_del,
307
};
308

    
309
static AddressSpace address_space_memory = {
310
    .ops = &address_space_ops_memory,
311
};
312

    
313
static const MemoryRegionPortio *find_portio(MemoryRegion *mr, uint64_t offset,
314
                                             unsigned width, bool write)
315
{
316
    const MemoryRegionPortio *mrp;
317

    
318
    for (mrp = mr->ops->old_portio; mrp->size; ++mrp) {
319
        if (offset >= mrp->offset && offset < mrp->offset + mrp->len
320
            && width == mrp->size
321
            && (write ? (bool)mrp->write : (bool)mrp->read)) {
322
            return mrp;
323
        }
324
    }
325
    return NULL;
326
}
327

    
328
static void memory_region_iorange_read(IORange *iorange,
329
                                       uint64_t offset,
330
                                       unsigned width,
331
                                       uint64_t *data)
332
{
333
    MemoryRegion *mr = container_of(iorange, MemoryRegion, iorange);
334

    
335
    if (mr->ops->old_portio) {
336
        const MemoryRegionPortio *mrp = find_portio(mr, offset, width, false);
337

    
338
        *data = ((uint64_t)1 << (width * 8)) - 1;
339
        if (mrp) {
340
            *data = mrp->read(mr->opaque, offset - mrp->offset);
341
        }
342
        return;
343
    }
344
    *data = mr->ops->read(mr->opaque, offset, width);
345
}
346

    
347
static void memory_region_iorange_write(IORange *iorange,
348
                                        uint64_t offset,
349
                                        unsigned width,
350
                                        uint64_t data)
351
{
352
    MemoryRegion *mr = container_of(iorange, MemoryRegion, iorange);
353

    
354
    if (mr->ops->old_portio) {
355
        const MemoryRegionPortio *mrp = find_portio(mr, offset, width, true);
356

    
357
        if (mrp) {
358
            mrp->write(mr->opaque, offset - mrp->offset, data);
359
        }
360
        return;
361
    }
362
    mr->ops->write(mr->opaque, offset, data, width);
363
}
364

    
365
static const IORangeOps memory_region_iorange_ops = {
366
    .read = memory_region_iorange_read,
367
    .write = memory_region_iorange_write,
368
};
369

    
370
static void as_io_range_add(AddressSpace *as, FlatRange *fr)
371
{
372
    iorange_init(&fr->mr->iorange, &memory_region_iorange_ops,
373
                 fr->addr.start,fr->addr.size);
374
    ioport_register(&fr->mr->iorange);
375
}
376

    
377
static void as_io_range_del(AddressSpace *as, FlatRange *fr)
378
{
379
    isa_unassign_ioport(fr->addr.start, fr->addr.size);
380
}
381

    
382
static void as_io_ioeventfd_add(AddressSpace *as, MemoryRegionIoeventfd *fd)
383
{
384
    int r;
385

    
386
    assert(fd->match_data && fd->addr.size == 2);
387

    
388
    r = kvm_set_ioeventfd_pio_word(fd->fd, fd->addr.start, fd->data, true);
389
    if (r < 0) {
390
        abort();
391
    }
392
}
393

    
394
static void as_io_ioeventfd_del(AddressSpace *as, MemoryRegionIoeventfd *fd)
395
{
396
    int r;
397

    
398
    r = kvm_set_ioeventfd_pio_word(fd->fd, fd->addr.start, fd->data, false);
399
    if (r < 0) {
400
        abort();
401
    }
402
}
403

    
404
static const AddressSpaceOps address_space_ops_io = {
405
    .range_add = as_io_range_add,
406
    .range_del = as_io_range_del,
407
    .ioeventfd_add = as_io_ioeventfd_add,
408
    .ioeventfd_del = as_io_ioeventfd_del,
409
};
410

    
411
static AddressSpace address_space_io = {
412
    .ops = &address_space_ops_io,
413
};
414

    
415
/* Render a memory region into the global view.  Ranges in @view obscure
416
 * ranges in @mr.
417
 */
418
static void render_memory_region(FlatView *view,
419
                                 MemoryRegion *mr,
420
                                 target_phys_addr_t base,
421
                                 AddrRange clip)
422
{
423
    MemoryRegion *subregion;
424
    unsigned i;
425
    target_phys_addr_t offset_in_region;
426
    int64_t remain;
427
    int64_t now;
428
    FlatRange fr;
429
    AddrRange tmp;
430

    
431
    base += mr->addr;
432

    
433
    tmp = addrrange_make(base, mr->size);
434

    
435
    if (!addrrange_intersects(tmp, clip)) {
436
        return;
437
    }
438

    
439
    clip = addrrange_intersection(tmp, clip);
440

    
441
    if (mr->alias) {
442
        base -= mr->alias->addr;
443
        base -= mr->alias_offset;
444
        render_memory_region(view, mr->alias, base, clip);
445
        return;
446
    }
447

    
448
    /* Render subregions in priority order. */
449
    QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) {
450
        render_memory_region(view, subregion, base, clip);
451
    }
452

    
453
    if (!mr->terminates) {
454
        return;
455
    }
456

    
457
    offset_in_region = clip.start - base;
458
    base = clip.start;
459
    remain = clip.size;
460

    
461
    /* Render the region itself into any gaps left by the current view. */
462
    for (i = 0; i < view->nr && remain; ++i) {
463
        if (base >= addrrange_end(view->ranges[i].addr)) {
464
            continue;
465
        }
466
        if (base < view->ranges[i].addr.start) {
467
            now = MIN(remain, view->ranges[i].addr.start - base);
468
            fr.mr = mr;
469
            fr.offset_in_region = offset_in_region;
470
            fr.addr = addrrange_make(base, now);
471
            fr.dirty_log_mask = mr->dirty_log_mask;
472
            fr.readable = mr->readable;
473
            flatview_insert(view, i, &fr);
474
            ++i;
475
            base += now;
476
            offset_in_region += now;
477
            remain -= now;
478
        }
479
        if (base == view->ranges[i].addr.start) {
480
            now = MIN(remain, view->ranges[i].addr.size);
481
            base += now;
482
            offset_in_region += now;
483
            remain -= now;
484
        }
485
    }
486
    if (remain) {
487
        fr.mr = mr;
488
        fr.offset_in_region = offset_in_region;
489
        fr.addr = addrrange_make(base, remain);
490
        fr.dirty_log_mask = mr->dirty_log_mask;
491
        fr.readable = mr->readable;
492
        flatview_insert(view, i, &fr);
493
    }
494
}
495

    
496
/* Render a memory topology into a list of disjoint absolute ranges. */
497
static FlatView generate_memory_topology(MemoryRegion *mr)
498
{
499
    FlatView view;
500

    
501
    flatview_init(&view);
502

    
503
    render_memory_region(&view, mr, 0, addrrange_make(0, INT64_MAX));
504
    flatview_simplify(&view);
505

    
506
    return view;
507
}
508

    
509
static void address_space_add_del_ioeventfds(AddressSpace *as,
510
                                             MemoryRegionIoeventfd *fds_new,
511
                                             unsigned fds_new_nb,
512
                                             MemoryRegionIoeventfd *fds_old,
513
                                             unsigned fds_old_nb)
514
{
515
    unsigned iold, inew;
516

    
517
    /* Generate a symmetric difference of the old and new fd sets, adding
518
     * and deleting as necessary.
519
     */
520

    
521
    iold = inew = 0;
522
    while (iold < fds_old_nb || inew < fds_new_nb) {
523
        if (iold < fds_old_nb
524
            && (inew == fds_new_nb
525
                || memory_region_ioeventfd_before(fds_old[iold],
526
                                                  fds_new[inew]))) {
527
            as->ops->ioeventfd_del(as, &fds_old[iold]);
528
            ++iold;
529
        } else if (inew < fds_new_nb
530
                   && (iold == fds_old_nb
531
                       || memory_region_ioeventfd_before(fds_new[inew],
532
                                                         fds_old[iold]))) {
533
            as->ops->ioeventfd_add(as, &fds_new[inew]);
534
            ++inew;
535
        } else {
536
            ++iold;
537
            ++inew;
538
        }
539
    }
540
}
541

    
542
static void address_space_update_ioeventfds(AddressSpace *as)
543
{
544
    FlatRange *fr;
545
    unsigned ioeventfd_nb = 0;
546
    MemoryRegionIoeventfd *ioeventfds = NULL;
547
    AddrRange tmp;
548
    unsigned i;
549

    
550
    FOR_EACH_FLAT_RANGE(fr, &as->current_map) {
551
        for (i = 0; i < fr->mr->ioeventfd_nb; ++i) {
552
            tmp = addrrange_shift(fr->mr->ioeventfds[i].addr,
553
                                  fr->addr.start - fr->offset_in_region);
554
            if (addrrange_intersects(fr->addr, tmp)) {
555
                ++ioeventfd_nb;
556
                ioeventfds = g_realloc(ioeventfds,
557
                                          ioeventfd_nb * sizeof(*ioeventfds));
558
                ioeventfds[ioeventfd_nb-1] = fr->mr->ioeventfds[i];
559
                ioeventfds[ioeventfd_nb-1].addr = tmp;
560
            }
561
        }
562
    }
563

    
564
    address_space_add_del_ioeventfds(as, ioeventfds, ioeventfd_nb,
565
                                     as->ioeventfds, as->ioeventfd_nb);
566

    
567
    g_free(as->ioeventfds);
568
    as->ioeventfds = ioeventfds;
569
    as->ioeventfd_nb = ioeventfd_nb;
570
}
571

    
572
static void address_space_update_topology_pass(AddressSpace *as,
573
                                               FlatView old_view,
574
                                               FlatView new_view,
575
                                               bool adding)
576
{
577
    unsigned iold, inew;
578
    FlatRange *frold, *frnew;
579

    
580
    /* Generate a symmetric difference of the old and new memory maps.
581
     * Kill ranges in the old map, and instantiate ranges in the new map.
582
     */
583
    iold = inew = 0;
584
    while (iold < old_view.nr || inew < new_view.nr) {
585
        if (iold < old_view.nr) {
586
            frold = &old_view.ranges[iold];
587
        } else {
588
            frold = NULL;
589
        }
590
        if (inew < new_view.nr) {
591
            frnew = &new_view.ranges[inew];
592
        } else {
593
            frnew = NULL;
594
        }
595

    
596
        if (frold
597
            && (!frnew
598
                || frold->addr.start < frnew->addr.start
599
                || (frold->addr.start == frnew->addr.start
600
                    && !flatrange_equal(frold, frnew)))) {
601
            /* In old, but (not in new, or in new but attributes changed). */
602

    
603
            if (!adding) {
604
                as->ops->range_del(as, frold);
605
            }
606

    
607
            ++iold;
608
        } else if (frold && frnew && flatrange_equal(frold, frnew)) {
609
            /* In both (logging may have changed) */
610

    
611
            if (adding) {
612
                if (frold->dirty_log_mask && !frnew->dirty_log_mask) {
613
                    as->ops->log_stop(as, frnew);
614
                } else if (frnew->dirty_log_mask && !frold->dirty_log_mask) {
615
                    as->ops->log_start(as, frnew);
616
                }
617
            }
618

    
619
            ++iold;
620
            ++inew;
621
        } else {
622
            /* In new */
623

    
624
            if (adding) {
625
                as->ops->range_add(as, frnew);
626
            }
627

    
628
            ++inew;
629
        }
630
    }
631
}
632

    
633

    
634
static void address_space_update_topology(AddressSpace *as)
635
{
636
    FlatView old_view = as->current_map;
637
    FlatView new_view = generate_memory_topology(as->root);
638

    
639
    address_space_update_topology_pass(as, old_view, new_view, false);
640
    address_space_update_topology_pass(as, old_view, new_view, true);
641

    
642
    as->current_map = new_view;
643
    flatview_destroy(&old_view);
644
    address_space_update_ioeventfds(as);
645
}
646

    
647
static void memory_region_update_topology(void)
648
{
649
    if (memory_region_transaction_depth) {
650
        return;
651
    }
652

    
653
    if (address_space_memory.root) {
654
        address_space_update_topology(&address_space_memory);
655
    }
656
    if (address_space_io.root) {
657
        address_space_update_topology(&address_space_io);
658
    }
659
}
660

    
661
void memory_region_transaction_begin(void)
662
{
663
    ++memory_region_transaction_depth;
664
}
665

    
666
void memory_region_transaction_commit(void)
667
{
668
    assert(memory_region_transaction_depth);
669
    --memory_region_transaction_depth;
670
    memory_region_update_topology();
671
}
672

    
673
static void memory_region_destructor_none(MemoryRegion *mr)
674
{
675
}
676

    
677
static void memory_region_destructor_ram(MemoryRegion *mr)
678
{
679
    qemu_ram_free(mr->ram_addr);
680
}
681

    
682
static void memory_region_destructor_ram_from_ptr(MemoryRegion *mr)
683
{
684
    qemu_ram_free_from_ptr(mr->ram_addr);
685
}
686

    
687
static void memory_region_destructor_iomem(MemoryRegion *mr)
688
{
689
    cpu_unregister_io_memory(mr->ram_addr);
690
}
691

    
692
static void memory_region_destructor_rom_device(MemoryRegion *mr)
693
{
694
    qemu_ram_free(mr->ram_addr & TARGET_PAGE_MASK);
695
    cpu_unregister_io_memory(mr->ram_addr & ~(TARGET_PAGE_MASK | IO_MEM_ROMD));
696
}
697

    
698
void memory_region_init(MemoryRegion *mr,
699
                        const char *name,
700
                        uint64_t size)
701
{
702
    mr->ops = NULL;
703
    mr->parent = NULL;
704
    mr->size = size;
705
    mr->addr = 0;
706
    mr->offset = 0;
707
    mr->terminates = false;
708
    mr->readable = true;
709
    mr->destructor = memory_region_destructor_none;
710
    mr->priority = 0;
711
    mr->may_overlap = false;
712
    mr->alias = NULL;
713
    QTAILQ_INIT(&mr->subregions);
714
    memset(&mr->subregions_link, 0, sizeof mr->subregions_link);
715
    QTAILQ_INIT(&mr->coalesced);
716
    mr->name = g_strdup(name);
717
    mr->dirty_log_mask = 0;
718
    mr->ioeventfd_nb = 0;
719
    mr->ioeventfds = NULL;
720
}
721

    
722
static bool memory_region_access_valid(MemoryRegion *mr,
723
                                       target_phys_addr_t addr,
724
                                       unsigned size)
725
{
726
    if (!mr->ops->valid.unaligned && (addr & (size - 1))) {
727
        return false;
728
    }
729

    
730
    /* Treat zero as compatibility all valid */
731
    if (!mr->ops->valid.max_access_size) {
732
        return true;
733
    }
734

    
735
    if (size > mr->ops->valid.max_access_size
736
        || size < mr->ops->valid.min_access_size) {
737
        return false;
738
    }
739
    return true;
740
}
741

    
742
static uint32_t memory_region_read_thunk_n(void *_mr,
743
                                           target_phys_addr_t addr,
744
                                           unsigned size)
745
{
746
    MemoryRegion *mr = _mr;
747
    unsigned access_size, access_size_min, access_size_max;
748
    uint64_t access_mask;
749
    uint32_t data = 0, tmp;
750
    unsigned i;
751

    
752
    if (!memory_region_access_valid(mr, addr, size)) {
753
        return -1U; /* FIXME: better signalling */
754
    }
755

    
756
    if (!mr->ops->read) {
757
        return mr->ops->old_mmio.read[bitops_ffsl(size)](mr->opaque, addr);
758
    }
759

    
760
    /* FIXME: support unaligned access */
761

    
762
    access_size_min = mr->ops->impl.min_access_size;
763
    if (!access_size_min) {
764
        access_size_min = 1;
765
    }
766
    access_size_max = mr->ops->impl.max_access_size;
767
    if (!access_size_max) {
768
        access_size_max = 4;
769
    }
770
    access_size = MAX(MIN(size, access_size_max), access_size_min);
771
    access_mask = -1ULL >> (64 - access_size * 8);
772
    addr += mr->offset;
773
    for (i = 0; i < size; i += access_size) {
774
        /* FIXME: big-endian support */
775
        tmp = mr->ops->read(mr->opaque, addr + i, access_size);
776
        data |= (tmp & access_mask) << (i * 8);
777
    }
778

    
779
    return data;
780
}
781

    
782
static void memory_region_write_thunk_n(void *_mr,
783
                                        target_phys_addr_t addr,
784
                                        unsigned size,
785
                                        uint64_t data)
786
{
787
    MemoryRegion *mr = _mr;
788
    unsigned access_size, access_size_min, access_size_max;
789
    uint64_t access_mask;
790
    unsigned i;
791

    
792
    if (!memory_region_access_valid(mr, addr, size)) {
793
        return; /* FIXME: better signalling */
794
    }
795

    
796
    if (!mr->ops->write) {
797
        mr->ops->old_mmio.write[bitops_ffsl(size)](mr->opaque, addr, data);
798
        return;
799
    }
800

    
801
    /* FIXME: support unaligned access */
802

    
803
    access_size_min = mr->ops->impl.min_access_size;
804
    if (!access_size_min) {
805
        access_size_min = 1;
806
    }
807
    access_size_max = mr->ops->impl.max_access_size;
808
    if (!access_size_max) {
809
        access_size_max = 4;
810
    }
811
    access_size = MAX(MIN(size, access_size_max), access_size_min);
812
    access_mask = -1ULL >> (64 - access_size * 8);
813
    addr += mr->offset;
814
    for (i = 0; i < size; i += access_size) {
815
        /* FIXME: big-endian support */
816
        mr->ops->write(mr->opaque, addr + i, (data >> (i * 8)) & access_mask,
817
                       access_size);
818
    }
819
}
820

    
821
static uint32_t memory_region_read_thunk_b(void *mr, target_phys_addr_t addr)
822
{
823
    return memory_region_read_thunk_n(mr, addr, 1);
824
}
825

    
826
static uint32_t memory_region_read_thunk_w(void *mr, target_phys_addr_t addr)
827
{
828
    return memory_region_read_thunk_n(mr, addr, 2);
829
}
830

    
831
static uint32_t memory_region_read_thunk_l(void *mr, target_phys_addr_t addr)
832
{
833
    return memory_region_read_thunk_n(mr, addr, 4);
834
}
835

    
836
static void memory_region_write_thunk_b(void *mr, target_phys_addr_t addr,
837
                                        uint32_t data)
838
{
839
    memory_region_write_thunk_n(mr, addr, 1, data);
840
}
841

    
842
static void memory_region_write_thunk_w(void *mr, target_phys_addr_t addr,
843
                                        uint32_t data)
844
{
845
    memory_region_write_thunk_n(mr, addr, 2, data);
846
}
847

    
848
static void memory_region_write_thunk_l(void *mr, target_phys_addr_t addr,
849
                                        uint32_t data)
850
{
851
    memory_region_write_thunk_n(mr, addr, 4, data);
852
}
853

    
854
static CPUReadMemoryFunc * const memory_region_read_thunk[] = {
855
    memory_region_read_thunk_b,
856
    memory_region_read_thunk_w,
857
    memory_region_read_thunk_l,
858
};
859

    
860
static CPUWriteMemoryFunc * const memory_region_write_thunk[] = {
861
    memory_region_write_thunk_b,
862
    memory_region_write_thunk_w,
863
    memory_region_write_thunk_l,
864
};
865

    
866
static void memory_region_prepare_ram_addr(MemoryRegion *mr)
867
{
868
    if (mr->backend_registered) {
869
        return;
870
    }
871

    
872
    mr->destructor = memory_region_destructor_iomem;
873
    mr->ram_addr = cpu_register_io_memory(memory_region_read_thunk,
874
                                          memory_region_write_thunk,
875
                                          mr,
876
                                          mr->ops->endianness);
877
    mr->backend_registered = true;
878
}
879

    
880
void memory_region_init_io(MemoryRegion *mr,
881
                           const MemoryRegionOps *ops,
882
                           void *opaque,
883
                           const char *name,
884
                           uint64_t size)
885
{
886
    memory_region_init(mr, name, size);
887
    mr->ops = ops;
888
    mr->opaque = opaque;
889
    mr->terminates = true;
890
    mr->backend_registered = false;
891
}
892

    
893
void memory_region_init_ram(MemoryRegion *mr,
894
                            DeviceState *dev,
895
                            const char *name,
896
                            uint64_t size)
897
{
898
    memory_region_init(mr, name, size);
899
    mr->terminates = true;
900
    mr->destructor = memory_region_destructor_ram;
901
    mr->ram_addr = qemu_ram_alloc(dev, name, size);
902
    mr->backend_registered = true;
903
}
904

    
905
void memory_region_init_ram_ptr(MemoryRegion *mr,
906
                                DeviceState *dev,
907
                                const char *name,
908
                                uint64_t size,
909
                                void *ptr)
910
{
911
    memory_region_init(mr, name, size);
912
    mr->terminates = true;
913
    mr->destructor = memory_region_destructor_ram_from_ptr;
914
    mr->ram_addr = qemu_ram_alloc_from_ptr(dev, name, size, ptr);
915
    mr->backend_registered = true;
916
}
917

    
918
void memory_region_init_alias(MemoryRegion *mr,
919
                              const char *name,
920
                              MemoryRegion *orig,
921
                              target_phys_addr_t offset,
922
                              uint64_t size)
923
{
924
    memory_region_init(mr, name, size);
925
    mr->alias = orig;
926
    mr->alias_offset = offset;
927
}
928

    
929
void memory_region_init_rom_device(MemoryRegion *mr,
930
                                   const MemoryRegionOps *ops,
931
                                   DeviceState *dev,
932
                                   const char *name,
933
                                   uint64_t size)
934
{
935
    memory_region_init(mr, name, size);
936
    mr->terminates = true;
937
    mr->destructor = memory_region_destructor_rom_device;
938
    mr->ram_addr = qemu_ram_alloc(dev, name, size);
939
    mr->ram_addr |= cpu_register_io_memory(memory_region_read_thunk,
940
                                           memory_region_write_thunk,
941
                                           mr,
942
                                           mr->ops->endianness);
943
    mr->ram_addr |= IO_MEM_ROMD;
944
    mr->backend_registered = true;
945
}
946

    
947
void memory_region_destroy(MemoryRegion *mr)
948
{
949
    assert(QTAILQ_EMPTY(&mr->subregions));
950
    mr->destructor(mr);
951
    memory_region_clear_coalescing(mr);
952
    g_free((char *)mr->name);
953
    g_free(mr->ioeventfds);
954
}
955

    
956
uint64_t memory_region_size(MemoryRegion *mr)
957
{
958
    return mr->size;
959
}
960

    
961
void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offset)
962
{
963
    mr->offset = offset;
964
}
965

    
966
void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
967
{
968
    uint8_t mask = 1 << client;
969

    
970
    mr->dirty_log_mask = (mr->dirty_log_mask & ~mask) | (log * mask);
971
    memory_region_update_topology();
972
}
973

    
974
bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
975
                             unsigned client)
976
{
977
    assert(mr->terminates);
978
    return cpu_physical_memory_get_dirty(mr->ram_addr + addr, 1 << client);
979
}
980

    
981
void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr)
982
{
983
    assert(mr->terminates);
984
    return cpu_physical_memory_set_dirty(mr->ram_addr + addr);
985
}
986

    
987
void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
988
{
989
    FlatRange *fr;
990

    
991
    FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) {
992
        if (fr->mr == mr) {
993
            cpu_physical_sync_dirty_bitmap(fr->addr.start,
994
                                           fr->addr.start + fr->addr.size);
995
        }
996
    }
997
}
998

    
999
void memory_region_set_readonly(MemoryRegion *mr, bool readonly)
1000
{
1001
    /* FIXME */
1002
}
1003

    
1004
void memory_region_rom_device_set_readable(MemoryRegion *mr, bool readable)
1005
{
1006
    if (mr->readable != readable) {
1007
        mr->readable = readable;
1008
        memory_region_update_topology();
1009
    }
1010
}
1011

    
1012
void memory_region_reset_dirty(MemoryRegion *mr, target_phys_addr_t addr,
1013
                               target_phys_addr_t size, unsigned client)
1014
{
1015
    assert(mr->terminates);
1016
    cpu_physical_memory_reset_dirty(mr->ram_addr + addr,
1017
                                    mr->ram_addr + addr + size,
1018
                                    1 << client);
1019
}
1020

    
1021
void *memory_region_get_ram_ptr(MemoryRegion *mr)
1022
{
1023
    if (mr->alias) {
1024
        return memory_region_get_ram_ptr(mr->alias) + mr->alias_offset;
1025
    }
1026

    
1027
    assert(mr->terminates);
1028

    
1029
    return qemu_get_ram_ptr(mr->ram_addr);
1030
}
1031

    
1032
static void memory_region_update_coalesced_range(MemoryRegion *mr)
1033
{
1034
    FlatRange *fr;
1035
    CoalescedMemoryRange *cmr;
1036
    AddrRange tmp;
1037

    
1038
    FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) {
1039
        if (fr->mr == mr) {
1040
            qemu_unregister_coalesced_mmio(fr->addr.start, fr->addr.size);
1041
            QTAILQ_FOREACH(cmr, &mr->coalesced, link) {
1042
                tmp = addrrange_shift(cmr->addr,
1043
                                      fr->addr.start - fr->offset_in_region);
1044
                if (!addrrange_intersects(tmp, fr->addr)) {
1045
                    continue;
1046
                }
1047
                tmp = addrrange_intersection(tmp, fr->addr);
1048
                qemu_register_coalesced_mmio(tmp.start, tmp.size);
1049
            }
1050
        }
1051
    }
1052
}
1053

    
1054
void memory_region_set_coalescing(MemoryRegion *mr)
1055
{
1056
    memory_region_clear_coalescing(mr);
1057
    memory_region_add_coalescing(mr, 0, mr->size);
1058
}
1059

    
1060
void memory_region_add_coalescing(MemoryRegion *mr,
1061
                                  target_phys_addr_t offset,
1062
                                  uint64_t size)
1063
{
1064
    CoalescedMemoryRange *cmr = g_malloc(sizeof(*cmr));
1065

    
1066
    cmr->addr = addrrange_make(offset, size);
1067
    QTAILQ_INSERT_TAIL(&mr->coalesced, cmr, link);
1068
    memory_region_update_coalesced_range(mr);
1069
}
1070

    
1071
void memory_region_clear_coalescing(MemoryRegion *mr)
1072
{
1073
    CoalescedMemoryRange *cmr;
1074

    
1075
    while (!QTAILQ_EMPTY(&mr->coalesced)) {
1076
        cmr = QTAILQ_FIRST(&mr->coalesced);
1077
        QTAILQ_REMOVE(&mr->coalesced, cmr, link);
1078
        g_free(cmr);
1079
    }
1080
    memory_region_update_coalesced_range(mr);
1081
}
1082

    
1083
void memory_region_add_eventfd(MemoryRegion *mr,
1084
                               target_phys_addr_t addr,
1085
                               unsigned size,
1086
                               bool match_data,
1087
                               uint64_t data,
1088
                               int fd)
1089
{
1090
    MemoryRegionIoeventfd mrfd = {
1091
        .addr.start = addr,
1092
        .addr.size = size,
1093
        .match_data = match_data,
1094
        .data = data,
1095
        .fd = fd,
1096
    };
1097
    unsigned i;
1098

    
1099
    for (i = 0; i < mr->ioeventfd_nb; ++i) {
1100
        if (memory_region_ioeventfd_before(mrfd, mr->ioeventfds[i])) {
1101
            break;
1102
        }
1103
    }
1104
    ++mr->ioeventfd_nb;
1105
    mr->ioeventfds = g_realloc(mr->ioeventfds,
1106
                                  sizeof(*mr->ioeventfds) * mr->ioeventfd_nb);
1107
    memmove(&mr->ioeventfds[i+1], &mr->ioeventfds[i],
1108
            sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb-1 - i));
1109
    mr->ioeventfds[i] = mrfd;
1110
    memory_region_update_topology();
1111
}
1112

    
1113
void memory_region_del_eventfd(MemoryRegion *mr,
1114
                               target_phys_addr_t addr,
1115
                               unsigned size,
1116
                               bool match_data,
1117
                               uint64_t data,
1118
                               int fd)
1119
{
1120
    MemoryRegionIoeventfd mrfd = {
1121
        .addr.start = addr,
1122
        .addr.size = size,
1123
        .match_data = match_data,
1124
        .data = data,
1125
        .fd = fd,
1126
    };
1127
    unsigned i;
1128

    
1129
    for (i = 0; i < mr->ioeventfd_nb; ++i) {
1130
        if (memory_region_ioeventfd_equal(mrfd, mr->ioeventfds[i])) {
1131
            break;
1132
        }
1133
    }
1134
    assert(i != mr->ioeventfd_nb);
1135
    memmove(&mr->ioeventfds[i], &mr->ioeventfds[i+1],
1136
            sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb - (i+1)));
1137
    --mr->ioeventfd_nb;
1138
    mr->ioeventfds = g_realloc(mr->ioeventfds,
1139
                                  sizeof(*mr->ioeventfds)*mr->ioeventfd_nb + 1);
1140
    memory_region_update_topology();
1141
}
1142

    
1143
static void memory_region_add_subregion_common(MemoryRegion *mr,
1144
                                               target_phys_addr_t offset,
1145
                                               MemoryRegion *subregion)
1146
{
1147
    MemoryRegion *other;
1148

    
1149
    assert(!subregion->parent);
1150
    subregion->parent = mr;
1151
    subregion->addr = offset;
1152
    QTAILQ_FOREACH(other, &mr->subregions, subregions_link) {
1153
        if (subregion->may_overlap || other->may_overlap) {
1154
            continue;
1155
        }
1156
        if (offset >= other->offset + other->size
1157
            || offset + subregion->size <= other->offset) {
1158
            continue;
1159
        }
1160
        printf("warning: subregion collision %llx/%llx vs %llx/%llx\n",
1161
               (unsigned long long)offset,
1162
               (unsigned long long)subregion->size,
1163
               (unsigned long long)other->offset,
1164
               (unsigned long long)other->size);
1165
    }
1166
    QTAILQ_FOREACH(other, &mr->subregions, subregions_link) {
1167
        if (subregion->priority >= other->priority) {
1168
            QTAILQ_INSERT_BEFORE(other, subregion, subregions_link);
1169
            goto done;
1170
        }
1171
    }
1172
    QTAILQ_INSERT_TAIL(&mr->subregions, subregion, subregions_link);
1173
done:
1174
    memory_region_update_topology();
1175
}
1176

    
1177

    
1178
void memory_region_add_subregion(MemoryRegion *mr,
1179
                                 target_phys_addr_t offset,
1180
                                 MemoryRegion *subregion)
1181
{
1182
    subregion->may_overlap = false;
1183
    subregion->priority = 0;
1184
    memory_region_add_subregion_common(mr, offset, subregion);
1185
}
1186

    
1187
void memory_region_add_subregion_overlap(MemoryRegion *mr,
1188
                                         target_phys_addr_t offset,
1189
                                         MemoryRegion *subregion,
1190
                                         unsigned priority)
1191
{
1192
    subregion->may_overlap = true;
1193
    subregion->priority = priority;
1194
    memory_region_add_subregion_common(mr, offset, subregion);
1195
}
1196

    
1197
void memory_region_del_subregion(MemoryRegion *mr,
1198
                                 MemoryRegion *subregion)
1199
{
1200
    assert(subregion->parent == mr);
1201
    subregion->parent = NULL;
1202
    QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link);
1203
    memory_region_update_topology();
1204
}
1205

    
1206
void set_system_memory_map(MemoryRegion *mr)
1207
{
1208
    address_space_memory.root = mr;
1209
    memory_region_update_topology();
1210
}
1211

    
1212
void set_system_io_map(MemoryRegion *mr)
1213
{
1214
    address_space_io.root = mr;
1215
    memory_region_update_topology();
1216
}