]> Git Repo - qemu.git/blob - memory.c
cirrus: simplify linear framebuffer access functions
[qemu.git] / memory.c
1 /*
2  * Physical memory management
3  *
4  * Copyright 2011 Red Hat, Inc. and/or its affiliates
5  *
6  * Authors:
7  *  Avi Kivity <[email protected]>
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 };
129
130 /* Flattened global view of current active memory hierarchy.  Kept in sorted
131  * order.
132  */
133 struct FlatView {
134     FlatRange *ranges;
135     unsigned nr;
136     unsigned nr_allocated;
137 };
138
139 typedef struct AddressSpace AddressSpace;
140 typedef struct AddressSpaceOps AddressSpaceOps;
141
142 /* A system address space - I/O, memory, etc. */
143 struct AddressSpace {
144     const AddressSpaceOps *ops;
145     MemoryRegion *root;
146     FlatView current_map;
147     int ioeventfd_nb;
148     MemoryRegionIoeventfd *ioeventfds;
149 };
150
151 struct AddressSpaceOps {
152     void (*range_add)(AddressSpace *as, FlatRange *fr);
153     void (*range_del)(AddressSpace *as, FlatRange *fr);
154     void (*log_start)(AddressSpace *as, FlatRange *fr);
155     void (*log_stop)(AddressSpace *as, FlatRange *fr);
156     void (*ioeventfd_add)(AddressSpace *as, MemoryRegionIoeventfd *fd);
157     void (*ioeventfd_del)(AddressSpace *as, MemoryRegionIoeventfd *fd);
158 };
159
160 #define FOR_EACH_FLAT_RANGE(var, view)          \
161     for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var)
162
163 static bool flatrange_equal(FlatRange *a, FlatRange *b)
164 {
165     return a->mr == b->mr
166         && addrrange_equal(a->addr, b->addr)
167         && a->offset_in_region == b->offset_in_region;
168 }
169
170 static void flatview_init(FlatView *view)
171 {
172     view->ranges = NULL;
173     view->nr = 0;
174     view->nr_allocated = 0;
175 }
176
177 /* Insert a range into a given position.  Caller is responsible for maintaining
178  * sorting order.
179  */
180 static void flatview_insert(FlatView *view, unsigned pos, FlatRange *range)
181 {
182     if (view->nr == view->nr_allocated) {
183         view->nr_allocated = MAX(2 * view->nr, 10);
184         view->ranges = qemu_realloc(view->ranges,
185                                     view->nr_allocated * sizeof(*view->ranges));
186     }
187     memmove(view->ranges + pos + 1, view->ranges + pos,
188             (view->nr - pos) * sizeof(FlatRange));
189     view->ranges[pos] = *range;
190     ++view->nr;
191 }
192
193 static void flatview_destroy(FlatView *view)
194 {
195     qemu_free(view->ranges);
196 }
197
198 static bool can_merge(FlatRange *r1, FlatRange *r2)
199 {
200     return addrrange_end(r1->addr) == r2->addr.start
201         && r1->mr == r2->mr
202         && r1->offset_in_region + r1->addr.size == r2->offset_in_region
203         && r1->dirty_log_mask == r2->dirty_log_mask;
204 }
205
206 /* Attempt to simplify a view by merging ajacent ranges */
207 static void flatview_simplify(FlatView *view)
208 {
209     unsigned i, j;
210
211     i = 0;
212     while (i < view->nr) {
213         j = i + 1;
214         while (j < view->nr
215                && can_merge(&view->ranges[j-1], &view->ranges[j])) {
216             view->ranges[i].addr.size += view->ranges[j].addr.size;
217             ++j;
218         }
219         ++i;
220         memmove(&view->ranges[i], &view->ranges[j],
221                 (view->nr - j) * sizeof(view->ranges[j]));
222         view->nr -= j - i;
223     }
224 }
225
226 static void memory_region_prepare_ram_addr(MemoryRegion *mr);
227
228 static void as_memory_range_add(AddressSpace *as, FlatRange *fr)
229 {
230     ram_addr_t phys_offset, region_offset;
231
232     memory_region_prepare_ram_addr(fr->mr);
233
234     phys_offset = fr->mr->ram_addr;
235     region_offset = fr->offset_in_region;
236     /* cpu_register_physical_memory_log() wants region_offset for
237      * mmio, but prefers offseting phys_offset for RAM.  Humour it.
238      */
239     if ((phys_offset & ~TARGET_PAGE_MASK) <= IO_MEM_ROM) {
240         phys_offset += region_offset;
241         region_offset = 0;
242     }
243
244     cpu_register_physical_memory_log(fr->addr.start,
245                                      fr->addr.size,
246                                      phys_offset,
247                                      region_offset,
248                                      fr->dirty_log_mask);
249 }
250
251 static void as_memory_range_del(AddressSpace *as, FlatRange *fr)
252 {
253     if (fr->dirty_log_mask) {
254         cpu_physical_sync_dirty_bitmap(fr->addr.start,
255                                        fr->addr.start + fr->addr.size);
256     }
257     cpu_register_physical_memory(fr->addr.start, fr->addr.size,
258                                  IO_MEM_UNASSIGNED);
259 }
260
261 static void as_memory_log_start(AddressSpace *as, FlatRange *fr)
262 {
263     cpu_physical_log_start(fr->addr.start, fr->addr.size);
264 }
265
266 static void as_memory_log_stop(AddressSpace *as, FlatRange *fr)
267 {
268     cpu_physical_log_stop(fr->addr.start, fr->addr.size);
269 }
270
271 static void as_memory_ioeventfd_add(AddressSpace *as, MemoryRegionIoeventfd *fd)
272 {
273     int r;
274
275     assert(fd->match_data && fd->addr.size == 4);
276
277     r = kvm_set_ioeventfd_mmio_long(fd->fd, fd->addr.start, fd->data, true);
278     if (r < 0) {
279         abort();
280     }
281 }
282
283 static void as_memory_ioeventfd_del(AddressSpace *as, MemoryRegionIoeventfd *fd)
284 {
285     int r;
286
287     r = kvm_set_ioeventfd_mmio_long(fd->fd, fd->addr.start, fd->data, false);
288     if (r < 0) {
289         abort();
290     }
291 }
292
293 static const AddressSpaceOps address_space_ops_memory = {
294     .range_add = as_memory_range_add,
295     .range_del = as_memory_range_del,
296     .log_start = as_memory_log_start,
297     .log_stop = as_memory_log_stop,
298     .ioeventfd_add = as_memory_ioeventfd_add,
299     .ioeventfd_del = as_memory_ioeventfd_del,
300 };
301
302 static AddressSpace address_space_memory = {
303     .ops = &address_space_ops_memory,
304 };
305
306 static const MemoryRegionPortio *find_portio(MemoryRegion *mr, uint64_t offset,
307                                              unsigned width, bool write)
308 {
309     const MemoryRegionPortio *mrp;
310
311     for (mrp = mr->ops->old_portio; mrp->size; ++mrp) {
312         if (offset >= mrp->offset && offset < mrp->offset + mrp->len
313             && width == mrp->size
314             && (write ? (bool)mrp->write : (bool)mrp->read)) {
315             return mrp;
316         }
317     }
318     return NULL;
319 }
320
321 static void memory_region_iorange_read(IORange *iorange,
322                                        uint64_t offset,
323                                        unsigned width,
324                                        uint64_t *data)
325 {
326     MemoryRegion *mr = container_of(iorange, MemoryRegion, iorange);
327
328     if (mr->ops->old_portio) {
329         const MemoryRegionPortio *mrp = find_portio(mr, offset, width, false);
330
331         *data = ((uint64_t)1 << (width * 8)) - 1;
332         if (mrp) {
333             *data = mrp->read(mr->opaque, offset - mrp->offset);
334         }
335         return;
336     }
337     *data = mr->ops->read(mr->opaque, offset, width);
338 }
339
340 static void memory_region_iorange_write(IORange *iorange,
341                                         uint64_t offset,
342                                         unsigned width,
343                                         uint64_t data)
344 {
345     MemoryRegion *mr = container_of(iorange, MemoryRegion, iorange);
346
347     if (mr->ops->old_portio) {
348         const MemoryRegionPortio *mrp = find_portio(mr, offset, width, true);
349
350         if (mrp) {
351             mrp->write(mr->opaque, offset - mrp->offset, data);
352         }
353         return;
354     }
355     mr->ops->write(mr->opaque, offset, data, width);
356 }
357
358 static const IORangeOps memory_region_iorange_ops = {
359     .read = memory_region_iorange_read,
360     .write = memory_region_iorange_write,
361 };
362
363 static void as_io_range_add(AddressSpace *as, FlatRange *fr)
364 {
365     iorange_init(&fr->mr->iorange, &memory_region_iorange_ops,
366                  fr->addr.start,fr->addr.size);
367     ioport_register(&fr->mr->iorange);
368 }
369
370 static void as_io_range_del(AddressSpace *as, FlatRange *fr)
371 {
372     isa_unassign_ioport(fr->addr.start, fr->addr.size);
373 }
374
375 static void as_io_ioeventfd_add(AddressSpace *as, MemoryRegionIoeventfd *fd)
376 {
377     int r;
378
379     assert(fd->match_data && fd->addr.size == 2);
380
381     r = kvm_set_ioeventfd_pio_word(fd->fd, fd->addr.start, fd->data, true);
382     if (r < 0) {
383         abort();
384     }
385 }
386
387 static void as_io_ioeventfd_del(AddressSpace *as, MemoryRegionIoeventfd *fd)
388 {
389     int r;
390
391     r = kvm_set_ioeventfd_pio_word(fd->fd, fd->addr.start, fd->data, false);
392     if (r < 0) {
393         abort();
394     }
395 }
396
397 static const AddressSpaceOps address_space_ops_io = {
398     .range_add = as_io_range_add,
399     .range_del = as_io_range_del,
400     .ioeventfd_add = as_io_ioeventfd_add,
401     .ioeventfd_del = as_io_ioeventfd_del,
402 };
403
404 static AddressSpace address_space_io = {
405     .ops = &address_space_ops_io,
406 };
407
408 /* Render a memory region into the global view.  Ranges in @view obscure
409  * ranges in @mr.
410  */
411 static void render_memory_region(FlatView *view,
412                                  MemoryRegion *mr,
413                                  target_phys_addr_t base,
414                                  AddrRange clip)
415 {
416     MemoryRegion *subregion;
417     unsigned i;
418     target_phys_addr_t offset_in_region;
419     int64_t remain;
420     int64_t now;
421     FlatRange fr;
422     AddrRange tmp;
423
424     base += mr->addr;
425
426     tmp = addrrange_make(base, mr->size);
427
428     if (!addrrange_intersects(tmp, clip)) {
429         return;
430     }
431
432     clip = addrrange_intersection(tmp, clip);
433
434     if (mr->alias) {
435         base -= mr->alias->addr;
436         base -= mr->alias_offset;
437         render_memory_region(view, mr->alias, base, clip);
438         return;
439     }
440
441     /* Render subregions in priority order. */
442     QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) {
443         render_memory_region(view, subregion, base, clip);
444     }
445
446     if (!mr->terminates) {
447         return;
448     }
449
450     offset_in_region = clip.start - base;
451     base = clip.start;
452     remain = clip.size;
453
454     /* Render the region itself into any gaps left by the current view. */
455     for (i = 0; i < view->nr && remain; ++i) {
456         if (base >= addrrange_end(view->ranges[i].addr)) {
457             continue;
458         }
459         if (base < view->ranges[i].addr.start) {
460             now = MIN(remain, view->ranges[i].addr.start - base);
461             fr.mr = mr;
462             fr.offset_in_region = offset_in_region;
463             fr.addr = addrrange_make(base, now);
464             fr.dirty_log_mask = mr->dirty_log_mask;
465             flatview_insert(view, i, &fr);
466             ++i;
467             base += now;
468             offset_in_region += now;
469             remain -= now;
470         }
471         if (base == view->ranges[i].addr.start) {
472             now = MIN(remain, view->ranges[i].addr.size);
473             base += now;
474             offset_in_region += now;
475             remain -= now;
476         }
477     }
478     if (remain) {
479         fr.mr = mr;
480         fr.offset_in_region = offset_in_region;
481         fr.addr = addrrange_make(base, remain);
482         fr.dirty_log_mask = mr->dirty_log_mask;
483         flatview_insert(view, i, &fr);
484     }
485 }
486
487 /* Render a memory topology into a list of disjoint absolute ranges. */
488 static FlatView generate_memory_topology(MemoryRegion *mr)
489 {
490     FlatView view;
491
492     flatview_init(&view);
493
494     render_memory_region(&view, mr, 0, addrrange_make(0, INT64_MAX));
495     flatview_simplify(&view);
496
497     return view;
498 }
499
500 static void address_space_add_del_ioeventfds(AddressSpace *as,
501                                              MemoryRegionIoeventfd *fds_new,
502                                              unsigned fds_new_nb,
503                                              MemoryRegionIoeventfd *fds_old,
504                                              unsigned fds_old_nb)
505 {
506     unsigned iold, inew;
507
508     /* Generate a symmetric difference of the old and new fd sets, adding
509      * and deleting as necessary.
510      */
511
512     iold = inew = 0;
513     while (iold < fds_old_nb || inew < fds_new_nb) {
514         if (iold < fds_old_nb
515             && (inew == fds_new_nb
516                 || memory_region_ioeventfd_before(fds_old[iold],
517                                                   fds_new[inew]))) {
518             as->ops->ioeventfd_del(as, &fds_old[iold]);
519             ++iold;
520         } else if (inew < fds_new_nb
521                    && (iold == fds_old_nb
522                        || memory_region_ioeventfd_before(fds_new[inew],
523                                                          fds_old[iold]))) {
524             as->ops->ioeventfd_add(as, &fds_new[inew]);
525             ++inew;
526         } else {
527             ++iold;
528             ++inew;
529         }
530     }
531 }
532
533 static void address_space_update_ioeventfds(AddressSpace *as)
534 {
535     FlatRange *fr;
536     unsigned ioeventfd_nb = 0;
537     MemoryRegionIoeventfd *ioeventfds = NULL;
538     AddrRange tmp;
539     unsigned i;
540
541     FOR_EACH_FLAT_RANGE(fr, &as->current_map) {
542         for (i = 0; i < fr->mr->ioeventfd_nb; ++i) {
543             tmp = addrrange_shift(fr->mr->ioeventfds[i].addr,
544                                   fr->addr.start - fr->offset_in_region);
545             if (addrrange_intersects(fr->addr, tmp)) {
546                 ++ioeventfd_nb;
547                 ioeventfds = qemu_realloc(ioeventfds,
548                                           ioeventfd_nb * sizeof(*ioeventfds));
549                 ioeventfds[ioeventfd_nb-1] = fr->mr->ioeventfds[i];
550                 ioeventfds[ioeventfd_nb-1].addr = tmp;
551             }
552         }
553     }
554
555     address_space_add_del_ioeventfds(as, ioeventfds, ioeventfd_nb,
556                                      as->ioeventfds, as->ioeventfd_nb);
557
558     qemu_free(as->ioeventfds);
559     as->ioeventfds = ioeventfds;
560     as->ioeventfd_nb = ioeventfd_nb;
561 }
562
563 static void address_space_update_topology_pass(AddressSpace *as,
564                                                FlatView old_view,
565                                                FlatView new_view,
566                                                bool adding)
567 {
568     unsigned iold, inew;
569     FlatRange *frold, *frnew;
570
571     /* Generate a symmetric difference of the old and new memory maps.
572      * Kill ranges in the old map, and instantiate ranges in the new map.
573      */
574     iold = inew = 0;
575     while (iold < old_view.nr || inew < new_view.nr) {
576         if (iold < old_view.nr) {
577             frold = &old_view.ranges[iold];
578         } else {
579             frold = NULL;
580         }
581         if (inew < new_view.nr) {
582             frnew = &new_view.ranges[inew];
583         } else {
584             frnew = NULL;
585         }
586
587         if (frold
588             && (!frnew
589                 || frold->addr.start < frnew->addr.start
590                 || (frold->addr.start == frnew->addr.start
591                     && !flatrange_equal(frold, frnew)))) {
592             /* In old, but (not in new, or in new but attributes changed). */
593
594             if (!adding) {
595                 as->ops->range_del(as, frold);
596             }
597
598             ++iold;
599         } else if (frold && frnew && flatrange_equal(frold, frnew)) {
600             /* In both (logging may have changed) */
601
602             if (adding) {
603                 if (frold->dirty_log_mask && !frnew->dirty_log_mask) {
604                     as->ops->log_stop(as, frnew);
605                 } else if (frnew->dirty_log_mask && !frold->dirty_log_mask) {
606                     as->ops->log_start(as, frnew);
607                 }
608             }
609
610             ++iold;
611             ++inew;
612         } else {
613             /* In new */
614
615             if (adding) {
616                 as->ops->range_add(as, frnew);
617             }
618
619             ++inew;
620         }
621     }
622 }
623
624
625 static void address_space_update_topology(AddressSpace *as)
626 {
627     FlatView old_view = as->current_map;
628     FlatView new_view = generate_memory_topology(as->root);
629
630     address_space_update_topology_pass(as, old_view, new_view, false);
631     address_space_update_topology_pass(as, old_view, new_view, true);
632
633     as->current_map = new_view;
634     flatview_destroy(&old_view);
635     address_space_update_ioeventfds(as);
636 }
637
638 static void memory_region_update_topology(void)
639 {
640     if (memory_region_transaction_depth) {
641         return;
642     }
643
644     if (address_space_memory.root) {
645         address_space_update_topology(&address_space_memory);
646     }
647     if (address_space_io.root) {
648         address_space_update_topology(&address_space_io);
649     }
650 }
651
652 void memory_region_transaction_begin(void)
653 {
654     ++memory_region_transaction_depth;
655 }
656
657 void memory_region_transaction_commit(void)
658 {
659     assert(memory_region_transaction_depth);
660     --memory_region_transaction_depth;
661     memory_region_update_topology();
662 }
663
664 void memory_region_init(MemoryRegion *mr,
665                         const char *name,
666                         uint64_t size)
667 {
668     mr->ops = NULL;
669     mr->parent = NULL;
670     mr->size = size;
671     mr->addr = 0;
672     mr->offset = 0;
673     mr->terminates = false;
674     mr->priority = 0;
675     mr->may_overlap = false;
676     mr->alias = NULL;
677     QTAILQ_INIT(&mr->subregions);
678     memset(&mr->subregions_link, 0, sizeof mr->subregions_link);
679     QTAILQ_INIT(&mr->coalesced);
680     mr->name = qemu_strdup(name);
681     mr->dirty_log_mask = 0;
682     mr->ioeventfd_nb = 0;
683     mr->ioeventfds = NULL;
684 }
685
686 static bool memory_region_access_valid(MemoryRegion *mr,
687                                        target_phys_addr_t addr,
688                                        unsigned size)
689 {
690     if (!mr->ops->valid.unaligned && (addr & (size - 1))) {
691         return false;
692     }
693
694     /* Treat zero as compatibility all valid */
695     if (!mr->ops->valid.max_access_size) {
696         return true;
697     }
698
699     if (size > mr->ops->valid.max_access_size
700         || size < mr->ops->valid.min_access_size) {
701         return false;
702     }
703     return true;
704 }
705
706 static uint32_t memory_region_read_thunk_n(void *_mr,
707                                            target_phys_addr_t addr,
708                                            unsigned size)
709 {
710     MemoryRegion *mr = _mr;
711     unsigned access_size, access_size_min, access_size_max;
712     uint64_t access_mask;
713     uint32_t data = 0, tmp;
714     unsigned i;
715
716     if (!memory_region_access_valid(mr, addr, size)) {
717         return -1U; /* FIXME: better signalling */
718     }
719
720     if (!mr->ops->read) {
721         return mr->ops->old_mmio.read[bitops_ffsl(size)](mr->opaque, addr);
722     }
723
724     /* FIXME: support unaligned access */
725
726     access_size_min = mr->ops->impl.min_access_size;
727     if (!access_size_min) {
728         access_size_min = 1;
729     }
730     access_size_max = mr->ops->impl.max_access_size;
731     if (!access_size_max) {
732         access_size_max = 4;
733     }
734     access_size = MAX(MIN(size, access_size_max), access_size_min);
735     access_mask = -1ULL >> (64 - access_size * 8);
736     addr += mr->offset;
737     for (i = 0; i < size; i += access_size) {
738         /* FIXME: big-endian support */
739         tmp = mr->ops->read(mr->opaque, addr + i, access_size);
740         data |= (tmp & access_mask) << (i * 8);
741     }
742
743     return data;
744 }
745
746 static void memory_region_write_thunk_n(void *_mr,
747                                         target_phys_addr_t addr,
748                                         unsigned size,
749                                         uint64_t data)
750 {
751     MemoryRegion *mr = _mr;
752     unsigned access_size, access_size_min, access_size_max;
753     uint64_t access_mask;
754     unsigned i;
755
756     if (!memory_region_access_valid(mr, addr, size)) {
757         return; /* FIXME: better signalling */
758     }
759
760     if (!mr->ops->write) {
761         mr->ops->old_mmio.write[bitops_ffsl(size)](mr->opaque, addr, data);
762         return;
763     }
764
765     /* FIXME: support unaligned access */
766
767     access_size_min = mr->ops->impl.min_access_size;
768     if (!access_size_min) {
769         access_size_min = 1;
770     }
771     access_size_max = mr->ops->impl.max_access_size;
772     if (!access_size_max) {
773         access_size_max = 4;
774     }
775     access_size = MAX(MIN(size, access_size_max), access_size_min);
776     access_mask = -1ULL >> (64 - access_size * 8);
777     addr += mr->offset;
778     for (i = 0; i < size; i += access_size) {
779         /* FIXME: big-endian support */
780         mr->ops->write(mr->opaque, addr + i, (data >> (i * 8)) & access_mask,
781                        access_size);
782     }
783 }
784
785 static uint32_t memory_region_read_thunk_b(void *mr, target_phys_addr_t addr)
786 {
787     return memory_region_read_thunk_n(mr, addr, 1);
788 }
789
790 static uint32_t memory_region_read_thunk_w(void *mr, target_phys_addr_t addr)
791 {
792     return memory_region_read_thunk_n(mr, addr, 2);
793 }
794
795 static uint32_t memory_region_read_thunk_l(void *mr, target_phys_addr_t addr)
796 {
797     return memory_region_read_thunk_n(mr, addr, 4);
798 }
799
800 static void memory_region_write_thunk_b(void *mr, target_phys_addr_t addr,
801                                         uint32_t data)
802 {
803     memory_region_write_thunk_n(mr, addr, 1, data);
804 }
805
806 static void memory_region_write_thunk_w(void *mr, target_phys_addr_t addr,
807                                         uint32_t data)
808 {
809     memory_region_write_thunk_n(mr, addr, 2, data);
810 }
811
812 static void memory_region_write_thunk_l(void *mr, target_phys_addr_t addr,
813                                         uint32_t data)
814 {
815     memory_region_write_thunk_n(mr, addr, 4, data);
816 }
817
818 static CPUReadMemoryFunc * const memory_region_read_thunk[] = {
819     memory_region_read_thunk_b,
820     memory_region_read_thunk_w,
821     memory_region_read_thunk_l,
822 };
823
824 static CPUWriteMemoryFunc * const memory_region_write_thunk[] = {
825     memory_region_write_thunk_b,
826     memory_region_write_thunk_w,
827     memory_region_write_thunk_l,
828 };
829
830 static void memory_region_prepare_ram_addr(MemoryRegion *mr)
831 {
832     if (mr->backend_registered) {
833         return;
834     }
835
836     mr->ram_addr = cpu_register_io_memory(memory_region_read_thunk,
837                                           memory_region_write_thunk,
838                                           mr,
839                                           mr->ops->endianness);
840     mr->backend_registered = true;
841 }
842
843 void memory_region_init_io(MemoryRegion *mr,
844                            const MemoryRegionOps *ops,
845                            void *opaque,
846                            const char *name,
847                            uint64_t size)
848 {
849     memory_region_init(mr, name, size);
850     mr->ops = ops;
851     mr->opaque = opaque;
852     mr->terminates = true;
853     mr->backend_registered = false;
854 }
855
856 void memory_region_init_ram(MemoryRegion *mr,
857                             DeviceState *dev,
858                             const char *name,
859                             uint64_t size)
860 {
861     memory_region_init(mr, name, size);
862     mr->terminates = true;
863     mr->ram_addr = qemu_ram_alloc(dev, name, size);
864     mr->backend_registered = true;
865 }
866
867 void memory_region_init_ram_ptr(MemoryRegion *mr,
868                                 DeviceState *dev,
869                                 const char *name,
870                                 uint64_t size,
871                                 void *ptr)
872 {
873     memory_region_init(mr, name, size);
874     mr->terminates = true;
875     mr->ram_addr = qemu_ram_alloc_from_ptr(dev, name, size, ptr);
876     mr->backend_registered = true;
877 }
878
879 void memory_region_init_alias(MemoryRegion *mr,
880                               const char *name,
881                               MemoryRegion *orig,
882                               target_phys_addr_t offset,
883                               uint64_t size)
884 {
885     memory_region_init(mr, name, size);
886     mr->alias = orig;
887     mr->alias_offset = offset;
888 }
889
890 void memory_region_destroy(MemoryRegion *mr)
891 {
892     assert(QTAILQ_EMPTY(&mr->subregions));
893     memory_region_clear_coalescing(mr);
894     qemu_free((char *)mr->name);
895     qemu_free(mr->ioeventfds);
896 }
897
898 uint64_t memory_region_size(MemoryRegion *mr)
899 {
900     return mr->size;
901 }
902
903 void memory_region_set_offset(MemoryRegion *mr, target_phys_addr_t offset)
904 {
905     mr->offset = offset;
906 }
907
908 void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client)
909 {
910     uint8_t mask = 1 << client;
911
912     mr->dirty_log_mask = (mr->dirty_log_mask & ~mask) | (log * mask);
913     memory_region_update_topology();
914 }
915
916 bool memory_region_get_dirty(MemoryRegion *mr, target_phys_addr_t addr,
917                              unsigned client)
918 {
919     assert(mr->terminates);
920     return cpu_physical_memory_get_dirty(mr->ram_addr + addr, 1 << client);
921 }
922
923 void memory_region_set_dirty(MemoryRegion *mr, target_phys_addr_t addr)
924 {
925     assert(mr->terminates);
926     return cpu_physical_memory_set_dirty(mr->ram_addr + addr);
927 }
928
929 void memory_region_sync_dirty_bitmap(MemoryRegion *mr)
930 {
931     FlatRange *fr;
932
933     FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) {
934         if (fr->mr == mr) {
935             cpu_physical_sync_dirty_bitmap(fr->addr.start,
936                                            fr->addr.start + fr->addr.size);
937         }
938     }
939 }
940
941 void memory_region_set_readonly(MemoryRegion *mr, bool readonly)
942 {
943     /* FIXME */
944 }
945
946 void memory_region_reset_dirty(MemoryRegion *mr, target_phys_addr_t addr,
947                                target_phys_addr_t size, unsigned client)
948 {
949     assert(mr->terminates);
950     cpu_physical_memory_reset_dirty(mr->ram_addr + addr,
951                                     mr->ram_addr + addr + size,
952                                     1 << client);
953 }
954
955 void *memory_region_get_ram_ptr(MemoryRegion *mr)
956 {
957     if (mr->alias) {
958         return memory_region_get_ram_ptr(mr->alias) + mr->alias_offset;
959     }
960
961     assert(mr->terminates);
962
963     return qemu_get_ram_ptr(mr->ram_addr);
964 }
965
966 static void memory_region_update_coalesced_range(MemoryRegion *mr)
967 {
968     FlatRange *fr;
969     CoalescedMemoryRange *cmr;
970     AddrRange tmp;
971
972     FOR_EACH_FLAT_RANGE(fr, &address_space_memory.current_map) {
973         if (fr->mr == mr) {
974             qemu_unregister_coalesced_mmio(fr->addr.start, fr->addr.size);
975             QTAILQ_FOREACH(cmr, &mr->coalesced, link) {
976                 tmp = addrrange_shift(cmr->addr,
977                                       fr->addr.start - fr->offset_in_region);
978                 if (!addrrange_intersects(tmp, fr->addr)) {
979                     continue;
980                 }
981                 tmp = addrrange_intersection(tmp, fr->addr);
982                 qemu_register_coalesced_mmio(tmp.start, tmp.size);
983             }
984         }
985     }
986 }
987
988 void memory_region_set_coalescing(MemoryRegion *mr)
989 {
990     memory_region_clear_coalescing(mr);
991     memory_region_add_coalescing(mr, 0, mr->size);
992 }
993
994 void memory_region_add_coalescing(MemoryRegion *mr,
995                                   target_phys_addr_t offset,
996                                   uint64_t size)
997 {
998     CoalescedMemoryRange *cmr = qemu_malloc(sizeof(*cmr));
999
1000     cmr->addr = addrrange_make(offset, size);
1001     QTAILQ_INSERT_TAIL(&mr->coalesced, cmr, link);
1002     memory_region_update_coalesced_range(mr);
1003 }
1004
1005 void memory_region_clear_coalescing(MemoryRegion *mr)
1006 {
1007     CoalescedMemoryRange *cmr;
1008
1009     while (!QTAILQ_EMPTY(&mr->coalesced)) {
1010         cmr = QTAILQ_FIRST(&mr->coalesced);
1011         QTAILQ_REMOVE(&mr->coalesced, cmr, link);
1012         qemu_free(cmr);
1013     }
1014     memory_region_update_coalesced_range(mr);
1015 }
1016
1017 void memory_region_add_eventfd(MemoryRegion *mr,
1018                                target_phys_addr_t addr,
1019                                unsigned size,
1020                                bool match_data,
1021                                uint64_t data,
1022                                int fd)
1023 {
1024     MemoryRegionIoeventfd mrfd = {
1025         .addr.start = addr,
1026         .addr.size = size,
1027         .match_data = match_data,
1028         .data = data,
1029         .fd = fd,
1030     };
1031     unsigned i;
1032
1033     for (i = 0; i < mr->ioeventfd_nb; ++i) {
1034         if (memory_region_ioeventfd_before(mrfd, mr->ioeventfds[i])) {
1035             break;
1036         }
1037     }
1038     ++mr->ioeventfd_nb;
1039     mr->ioeventfds = qemu_realloc(mr->ioeventfds,
1040                                   sizeof(*mr->ioeventfds) * mr->ioeventfd_nb);
1041     memmove(&mr->ioeventfds[i+1], &mr->ioeventfds[i],
1042             sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb-1 - i));
1043     mr->ioeventfds[i] = mrfd;
1044     memory_region_update_topology();
1045 }
1046
1047 void memory_region_del_eventfd(MemoryRegion *mr,
1048                                target_phys_addr_t addr,
1049                                unsigned size,
1050                                bool match_data,
1051                                uint64_t data,
1052                                int fd)
1053 {
1054     MemoryRegionIoeventfd mrfd = {
1055         .addr.start = addr,
1056         .addr.size = size,
1057         .match_data = match_data,
1058         .data = data,
1059         .fd = fd,
1060     };
1061     unsigned i;
1062
1063     for (i = 0; i < mr->ioeventfd_nb; ++i) {
1064         if (memory_region_ioeventfd_equal(mrfd, mr->ioeventfds[i])) {
1065             break;
1066         }
1067     }
1068     assert(i != mr->ioeventfd_nb);
1069     memmove(&mr->ioeventfds[i], &mr->ioeventfds[i+1],
1070             sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb - (i+1)));
1071     --mr->ioeventfd_nb;
1072     mr->ioeventfds = qemu_realloc(mr->ioeventfds,
1073                                   sizeof(*mr->ioeventfds)*mr->ioeventfd_nb + 1);
1074     memory_region_update_topology();
1075 }
1076
1077 static void memory_region_add_subregion_common(MemoryRegion *mr,
1078                                                target_phys_addr_t offset,
1079                                                MemoryRegion *subregion)
1080 {
1081     MemoryRegion *other;
1082
1083     assert(!subregion->parent);
1084     subregion->parent = mr;
1085     subregion->addr = offset;
1086     QTAILQ_FOREACH(other, &mr->subregions, subregions_link) {
1087         if (subregion->may_overlap || other->may_overlap) {
1088             continue;
1089         }
1090         if (offset >= other->offset + other->size
1091             || offset + subregion->size <= other->offset) {
1092             continue;
1093         }
1094         printf("warning: subregion collision %llx/%llx vs %llx/%llx\n",
1095                (unsigned long long)offset,
1096                (unsigned long long)subregion->size,
1097                (unsigned long long)other->offset,
1098                (unsigned long long)other->size);
1099     }
1100     QTAILQ_FOREACH(other, &mr->subregions, subregions_link) {
1101         if (subregion->priority >= other->priority) {
1102             QTAILQ_INSERT_BEFORE(other, subregion, subregions_link);
1103             goto done;
1104         }
1105     }
1106     QTAILQ_INSERT_TAIL(&mr->subregions, subregion, subregions_link);
1107 done:
1108     memory_region_update_topology();
1109 }
1110
1111
1112 void memory_region_add_subregion(MemoryRegion *mr,
1113                                  target_phys_addr_t offset,
1114                                  MemoryRegion *subregion)
1115 {
1116     subregion->may_overlap = false;
1117     subregion->priority = 0;
1118     memory_region_add_subregion_common(mr, offset, subregion);
1119 }
1120
1121 void memory_region_add_subregion_overlap(MemoryRegion *mr,
1122                                          target_phys_addr_t offset,
1123                                          MemoryRegion *subregion,
1124                                          unsigned priority)
1125 {
1126     subregion->may_overlap = true;
1127     subregion->priority = priority;
1128     memory_region_add_subregion_common(mr, offset, subregion);
1129 }
1130
1131 void memory_region_del_subregion(MemoryRegion *mr,
1132                                  MemoryRegion *subregion)
1133 {
1134     assert(subregion->parent == mr);
1135     subregion->parent = NULL;
1136     QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link);
1137     memory_region_update_topology();
1138 }
1139
1140 void set_system_memory_map(MemoryRegion *mr)
1141 {
1142     address_space_memory.root = mr;
1143     memory_region_update_topology();
1144 }
1145
1146 void set_system_io_map(MemoryRegion *mr)
1147 {
1148     address_space_io.root = mr;
1149     memory_region_update_topology();
1150 }
This page took 0.090532 seconds and 4 git commands to generate.