| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Physical memory management | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Copyright 2011 Red Hat, Inc. and/or its affiliates | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Authors: | 
					
						
							|  |  |  |  *  Avi Kivity <avi@redhat.com> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * This work is licensed under the terms of the GNU GPL, version 2.  See | 
					
						
							|  |  |  |  * the COPYING file in the top-level directory. | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-01-13 17:44:23 +01:00
										 |  |  |  * Contributions after 2012-01-13 are licensed under the terms of the | 
					
						
							|  |  |  |  * GNU GPL, version 2 or (at your option) any later version. | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "memory.h"
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:04 +03:00
										 |  |  | #include "exec-memory.h"
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:08 +03:00
										 |  |  | #include "ioport.h"
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:10 +03:00
										 |  |  | #include "bitops.h"
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  | #include "kvm.h"
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | #include <assert.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-09-20 16:02:51 +03:00
										 |  |  | #include "memory-internal.h"
 | 
					
						
							| 
									
										
										
										
											2011-12-15 15:25:22 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-11-05 16:45:56 +01:00
										 |  |  | static unsigned memory_region_transaction_depth; | 
					
						
							|  |  |  | static bool memory_region_update_pending; | 
					
						
							| 
									
										
										
										
											2011-12-11 14:47:25 +02:00
										 |  |  | static bool global_dirty_log = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-08 15:05:50 +02:00
										 |  |  | static QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners | 
					
						
							|  |  |  |     = QTAILQ_HEAD_INITIALIZER(memory_listeners); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:13 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  | static QTAILQ_HEAD(, AddressSpace) address_spaces | 
					
						
							|  |  |  |     = QTAILQ_HEAD_INITIALIZER(address_spaces); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | typedef struct AddrRange AddrRange; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-03 11:56:14 +03:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  * Note using signed integers limits us to physical addresses at most | 
					
						
							|  |  |  |  * 63 bits wide.  They are needed for negative offsetting in aliases | 
					
						
							|  |  |  |  * (large MemoryRegion::alias_offset). | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | struct AddrRange { | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     Int128 start; | 
					
						
							|  |  |  |     Int128 size; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  | static AddrRange addrrange_make(Int128 start, Int128 size) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     return (AddrRange) { start, size }; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool addrrange_equal(AddrRange r1, AddrRange r2) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     return int128_eq(r1.start, r2.start) && int128_eq(r1.size, r2.size); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  | static Int128 addrrange_end(AddrRange r) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     return int128_add(r.start, r.size); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  | static AddrRange addrrange_shift(AddrRange range, Int128 delta) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     int128_addto(&range.start, delta); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     return range; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  | static bool addrrange_contains(AddrRange range, Int128 addr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return int128_ge(addr, range.start) | 
					
						
							|  |  |  |         && int128_lt(addr, addrrange_end(range)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | static bool addrrange_intersects(AddrRange r1, AddrRange r2) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     return addrrange_contains(r1, r2.start) | 
					
						
							|  |  |  |         || addrrange_contains(r2, r1.start); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static AddrRange addrrange_intersection(AddrRange r1, AddrRange r2) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     Int128 start = int128_max(r1.start, r2.start); | 
					
						
							|  |  |  |     Int128 end = int128_min(addrrange_end(r1), addrrange_end(r2)); | 
					
						
							|  |  |  |     return addrrange_make(start, int128_sub(end, start)); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-08 16:39:45 +02:00
										 |  |  | enum ListenerDirection { Forward, Reverse }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-08 21:05:17 +02:00
										 |  |  | static bool memory_listener_match(MemoryListener *listener, | 
					
						
							|  |  |  |                                   MemoryRegionSection *section) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return !listener->address_space_filter | 
					
						
							|  |  |  |         || listener->address_space_filter == section->address_space; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define MEMORY_LISTENER_CALL_GLOBAL(_callback, _direction, _args...)    \
 | 
					
						
							| 
									
										
										
										
											2012-02-08 16:39:45 +02:00
										 |  |  |     do {                                                                \ | 
					
						
							|  |  |  |         MemoryListener *_listener;                                      \ | 
					
						
							|  |  |  |                                                                         \ | 
					
						
							|  |  |  |         switch (_direction) {                                           \ | 
					
						
							|  |  |  |         case Forward:                                                   \ | 
					
						
							|  |  |  |             QTAILQ_FOREACH(_listener, &memory_listeners, link) {        \ | 
					
						
							| 
									
										
										
										
											2012-10-02 16:39:57 +02:00
										 |  |  |                 if (_listener->_callback) {                             \ | 
					
						
							|  |  |  |                     _listener->_callback(_listener, ##_args);           \ | 
					
						
							|  |  |  |                 }                                                       \ | 
					
						
							| 
									
										
										
										
											2012-02-08 16:39:45 +02:00
										 |  |  |             }                                                           \ | 
					
						
							|  |  |  |             break;                                                      \ | 
					
						
							|  |  |  |         case Reverse:                                                   \ | 
					
						
							|  |  |  |             QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners,        \ | 
					
						
							|  |  |  |                                    memory_listeners, link) {            \ | 
					
						
							| 
									
										
										
										
											2012-10-02 16:39:57 +02:00
										 |  |  |                 if (_listener->_callback) {                             \ | 
					
						
							|  |  |  |                     _listener->_callback(_listener, ##_args);           \ | 
					
						
							|  |  |  |                 }                                                       \ | 
					
						
							| 
									
										
										
										
											2012-02-08 16:39:45 +02:00
										 |  |  |             }                                                           \ | 
					
						
							|  |  |  |             break;                                                      \ | 
					
						
							|  |  |  |         default:                                                        \ | 
					
						
							|  |  |  |             abort();                                                    \ | 
					
						
							|  |  |  |         }                                                               \ | 
					
						
							|  |  |  |     } while (0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-08 21:05:17 +02:00
										 |  |  | #define MEMORY_LISTENER_CALL(_callback, _direction, _section, _args...) \
 | 
					
						
							|  |  |  |     do {                                                                \ | 
					
						
							|  |  |  |         MemoryListener *_listener;                                      \ | 
					
						
							|  |  |  |                                                                         \ | 
					
						
							|  |  |  |         switch (_direction) {                                           \ | 
					
						
							|  |  |  |         case Forward:                                                   \ | 
					
						
							|  |  |  |             QTAILQ_FOREACH(_listener, &memory_listeners, link) {        \ | 
					
						
							| 
									
										
										
										
											2012-10-02 16:39:57 +02:00
										 |  |  |                 if (_listener->_callback                                \ | 
					
						
							|  |  |  |                     && memory_listener_match(_listener, _section)) {    \ | 
					
						
							| 
									
										
										
										
											2012-02-08 21:05:17 +02:00
										 |  |  |                     _listener->_callback(_listener, _section, ##_args); \ | 
					
						
							|  |  |  |                 }                                                       \ | 
					
						
							|  |  |  |             }                                                           \ | 
					
						
							|  |  |  |             break;                                                      \ | 
					
						
							|  |  |  |         case Reverse:                                                   \ | 
					
						
							|  |  |  |             QTAILQ_FOREACH_REVERSE(_listener, &memory_listeners,        \ | 
					
						
							|  |  |  |                                    memory_listeners, link) {            \ | 
					
						
							| 
									
										
										
										
											2012-10-02 16:39:57 +02:00
										 |  |  |                 if (_listener->_callback                                \ | 
					
						
							|  |  |  |                     && memory_listener_match(_listener, _section)) {    \ | 
					
						
							| 
									
										
										
										
											2012-02-08 21:05:17 +02:00
										 |  |  |                     _listener->_callback(_listener, _section, ##_args); \ | 
					
						
							|  |  |  |                 }                                                       \ | 
					
						
							|  |  |  |             }                                                           \ | 
					
						
							|  |  |  |             break;                                                      \ | 
					
						
							|  |  |  |         default:                                                        \ | 
					
						
							|  |  |  |             abort();                                                    \ | 
					
						
							|  |  |  |         }                                                               \ | 
					
						
							|  |  |  |     } while (0) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-08 16:39:45 +02:00
										 |  |  | #define MEMORY_LISTENER_UPDATE_REGION(fr, as, dir, callback)            \
 | 
					
						
							| 
									
										
										
										
											2012-02-08 21:05:17 +02:00
										 |  |  |     MEMORY_LISTENER_CALL(callback, dir, (&(MemoryRegionSection) {       \ | 
					
						
							| 
									
										
										
										
											2012-02-08 16:39:45 +02:00
										 |  |  |         .mr = (fr)->mr,                                                 \ | 
					
						
							| 
									
										
										
										
											2012-10-02 20:13:51 +02:00
										 |  |  |         .address_space = (as),                                          \ | 
					
						
							| 
									
										
										
										
											2012-02-08 16:39:45 +02:00
										 |  |  |         .offset_within_region = (fr)->offset_in_region,                 \ | 
					
						
							|  |  |  |         .size = int128_get64((fr)->addr.size),                          \ | 
					
						
							|  |  |  |         .offset_within_address_space = int128_get64((fr)->addr.start),  \ | 
					
						
							| 
									
										
										
										
											2012-02-08 17:01:23 +02:00
										 |  |  |         .readonly = (fr)->readonly,                                     \ | 
					
						
							| 
									
										
										
										
											2012-02-08 21:05:17 +02:00
										 |  |  |               })) | 
					
						
							| 
									
										
										
										
											2012-02-08 16:39:45 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | struct CoalescedMemoryRange { | 
					
						
							|  |  |  |     AddrRange addr; | 
					
						
							|  |  |  |     QTAILQ_ENTRY(CoalescedMemoryRange) link; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  | struct MemoryRegionIoeventfd { | 
					
						
							|  |  |  |     AddrRange addr; | 
					
						
							|  |  |  |     bool match_data; | 
					
						
							|  |  |  |     uint64_t data; | 
					
						
							| 
									
										
										
										
											2012-07-05 17:16:27 +02:00
										 |  |  |     EventNotifier *e; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool memory_region_ioeventfd_before(MemoryRegionIoeventfd a, | 
					
						
							|  |  |  |                                            MemoryRegionIoeventfd b) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     if (int128_lt(a.addr.start, b.addr.start)) { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     } else if (int128_gt(a.addr.start, b.addr.start)) { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |         return false; | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     } else if (int128_lt(a.addr.size, b.addr.size)) { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     } else if (int128_gt(a.addr.size, b.addr.size)) { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |         return false; | 
					
						
							|  |  |  |     } else if (a.match_data < b.match_data) { | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } else  if (a.match_data > b.match_data) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } else if (a.match_data) { | 
					
						
							|  |  |  |         if (a.data < b.data) { | 
					
						
							|  |  |  |             return true; | 
					
						
							|  |  |  |         } else if (a.data > b.data) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-07-05 17:16:27 +02:00
										 |  |  |     if (a.e < b.e) { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |         return true; | 
					
						
							| 
									
										
										
										
											2012-07-05 17:16:27 +02:00
										 |  |  |     } else if (a.e > b.e) { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool memory_region_ioeventfd_equal(MemoryRegionIoeventfd a, | 
					
						
							|  |  |  |                                           MemoryRegionIoeventfd b) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return !memory_region_ioeventfd_before(a, b) | 
					
						
							|  |  |  |         && !memory_region_ioeventfd_before(b, a); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | typedef struct FlatRange FlatRange; | 
					
						
							|  |  |  | typedef struct FlatView FlatView; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Range of memory in the global map.  Addresses are absolute. */ | 
					
						
							|  |  |  | struct FlatRange { | 
					
						
							|  |  |  |     MemoryRegion *mr; | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |     hwaddr offset_in_region; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     AddrRange addr; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:02 +03:00
										 |  |  |     uint8_t dirty_log_mask; | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  |     bool readable; | 
					
						
							| 
									
										
										
										
											2011-09-25 14:48:47 +03:00
										 |  |  |     bool readonly; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Flattened global view of current active memory hierarchy.  Kept in sorted
 | 
					
						
							|  |  |  |  * order. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | struct FlatView { | 
					
						
							|  |  |  |     FlatRange *ranges; | 
					
						
							|  |  |  |     unsigned nr; | 
					
						
							|  |  |  |     unsigned nr_allocated; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:05 +03:00
										 |  |  | typedef struct AddressSpaceOps AddressSpaceOps; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | #define FOR_EACH_FLAT_RANGE(var, view)          \
 | 
					
						
							|  |  |  |     for (var = (view)->ranges; var < (view)->ranges + (view)->nr; ++var) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool flatrange_equal(FlatRange *a, FlatRange *b) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return a->mr == b->mr | 
					
						
							|  |  |  |         && addrrange_equal(a->addr, b->addr) | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  |         && a->offset_in_region == b->offset_in_region | 
					
						
							| 
									
										
										
										
											2011-09-25 14:48:47 +03:00
										 |  |  |         && a->readable == b->readable | 
					
						
							|  |  |  |         && a->readonly == b->readonly; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void flatview_init(FlatView *view) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     view->ranges = NULL; | 
					
						
							|  |  |  |     view->nr = 0; | 
					
						
							|  |  |  |     view->nr_allocated = 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Insert a range into a given position.  Caller is responsible for maintaining
 | 
					
						
							|  |  |  |  * sorting order. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void flatview_insert(FlatView *view, unsigned pos, FlatRange *range) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (view->nr == view->nr_allocated) { | 
					
						
							|  |  |  |         view->nr_allocated = MAX(2 * view->nr, 10); | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |         view->ranges = g_realloc(view->ranges, | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |                                     view->nr_allocated * sizeof(*view->ranges)); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     memmove(view->ranges + pos + 1, view->ranges + pos, | 
					
						
							|  |  |  |             (view->nr - pos) * sizeof(FlatRange)); | 
					
						
							|  |  |  |     view->ranges[pos] = *range; | 
					
						
							|  |  |  |     ++view->nr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void flatview_destroy(FlatView *view) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     g_free(view->ranges); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:03 +03:00
										 |  |  | static bool can_merge(FlatRange *r1, FlatRange *r2) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     return int128_eq(addrrange_end(r1->addr), r2->addr.start) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:03 +03:00
										 |  |  |         && r1->mr == r2->mr | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |         && int128_eq(int128_add(int128_make64(r1->offset_in_region), | 
					
						
							|  |  |  |                                 r1->addr.size), | 
					
						
							|  |  |  |                      int128_make64(r2->offset_in_region)) | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  |         && r1->dirty_log_mask == r2->dirty_log_mask | 
					
						
							| 
									
										
										
										
											2011-09-25 14:48:47 +03:00
										 |  |  |         && r1->readable == r2->readable | 
					
						
							|  |  |  |         && r1->readonly == r2->readonly; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:03 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Attempt to simplify a view by merging ajacent ranges */ | 
					
						
							|  |  |  | static void flatview_simplify(FlatView *view) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned i, j; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     i = 0; | 
					
						
							|  |  |  |     while (i < view->nr) { | 
					
						
							|  |  |  |         j = i + 1; | 
					
						
							|  |  |  |         while (j < view->nr | 
					
						
							|  |  |  |                && can_merge(&view->ranges[j-1], &view->ranges[j])) { | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |             int128_addto(&view->ranges[i].addr.size, view->ranges[j].addr.size); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:03 +03:00
										 |  |  |             ++j; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         ++i; | 
					
						
							|  |  |  |         memmove(&view->ranges[i], &view->ranges[j], | 
					
						
							|  |  |  |                 (view->nr - j) * sizeof(view->ranges[j])); | 
					
						
							|  |  |  |         view->nr -= j - i; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-11 10:40:25 +03:00
										 |  |  | static void memory_region_read_accessor(void *opaque, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                         hwaddr addr, | 
					
						
							| 
									
										
										
										
											2011-08-11 10:40:25 +03:00
										 |  |  |                                         uint64_t *value, | 
					
						
							|  |  |  |                                         unsigned size, | 
					
						
							|  |  |  |                                         unsigned shift, | 
					
						
							|  |  |  |                                         uint64_t mask) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     MemoryRegion *mr = opaque; | 
					
						
							|  |  |  |     uint64_t tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:29 +02:00
										 |  |  |     if (mr->flush_coalesced_mmio) { | 
					
						
							|  |  |  |         qemu_flush_coalesced_mmio_buffer(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-08-11 10:40:25 +03:00
										 |  |  |     tmp = mr->ops->read(mr->opaque, addr, size); | 
					
						
							|  |  |  |     *value |= (tmp & mask) << shift; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void memory_region_write_accessor(void *opaque, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                          hwaddr addr, | 
					
						
							| 
									
										
										
										
											2011-08-11 10:40:25 +03:00
										 |  |  |                                          uint64_t *value, | 
					
						
							|  |  |  |                                          unsigned size, | 
					
						
							|  |  |  |                                          unsigned shift, | 
					
						
							|  |  |  |                                          uint64_t mask) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     MemoryRegion *mr = opaque; | 
					
						
							|  |  |  |     uint64_t tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:29 +02:00
										 |  |  |     if (mr->flush_coalesced_mmio) { | 
					
						
							|  |  |  |         qemu_flush_coalesced_mmio_buffer(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-08-11 10:40:25 +03:00
										 |  |  |     tmp = (*value >> shift) & mask; | 
					
						
							|  |  |  |     mr->ops->write(mr->opaque, addr, tmp, size); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | static void access_with_adjusted_size(hwaddr addr, | 
					
						
							| 
									
										
										
										
											2011-08-11 10:40:25 +03:00
										 |  |  |                                       uint64_t *value, | 
					
						
							|  |  |  |                                       unsigned size, | 
					
						
							|  |  |  |                                       unsigned access_size_min, | 
					
						
							|  |  |  |                                       unsigned access_size_max, | 
					
						
							|  |  |  |                                       void (*access)(void *opaque, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                                      hwaddr addr, | 
					
						
							| 
									
										
										
										
											2011-08-11 10:40:25 +03:00
										 |  |  |                                                      uint64_t *value, | 
					
						
							|  |  |  |                                                      unsigned size, | 
					
						
							|  |  |  |                                                      unsigned shift, | 
					
						
							|  |  |  |                                                      uint64_t mask), | 
					
						
							|  |  |  |                                       void *opaque) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint64_t access_mask; | 
					
						
							|  |  |  |     unsigned access_size; | 
					
						
							|  |  |  |     unsigned i; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!access_size_min) { | 
					
						
							|  |  |  |         access_size_min = 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     if (!access_size_max) { | 
					
						
							|  |  |  |         access_size_max = 4; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     access_size = MAX(MIN(size, access_size_max), access_size_min); | 
					
						
							|  |  |  |     access_mask = -1ULL >> (64 - access_size * 8); | 
					
						
							|  |  |  |     for (i = 0; i < size; i += access_size) { | 
					
						
							|  |  |  |         /* FIXME: big-endian support */ | 
					
						
							|  |  |  |         access(opaque, addr + i, value, access_size, i * 8, access_mask); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:09 +03:00
										 |  |  | static const MemoryRegionPortio *find_portio(MemoryRegion *mr, uint64_t offset, | 
					
						
							|  |  |  |                                              unsigned width, bool write) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const MemoryRegionPortio *mrp; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (mrp = mr->ops->old_portio; mrp->size; ++mrp) { | 
					
						
							|  |  |  |         if (offset >= mrp->offset && offset < mrp->offset + mrp->len | 
					
						
							|  |  |  |             && width == mrp->size | 
					
						
							|  |  |  |             && (write ? (bool)mrp->write : (bool)mrp->read)) { | 
					
						
							|  |  |  |             return mrp; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:08 +03:00
										 |  |  | static void memory_region_iorange_read(IORange *iorange, | 
					
						
							|  |  |  |                                        uint64_t offset, | 
					
						
							|  |  |  |                                        unsigned width, | 
					
						
							|  |  |  |                                        uint64_t *data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-05 17:40:12 +02:00
										 |  |  |     MemoryRegionIORange *mrio | 
					
						
							|  |  |  |         = container_of(iorange, MemoryRegionIORange, iorange); | 
					
						
							|  |  |  |     MemoryRegion *mr = mrio->mr; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:08 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-05 17:40:12 +02:00
										 |  |  |     offset += mrio->offset; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:09 +03:00
										 |  |  |     if (mr->ops->old_portio) { | 
					
						
							| 
									
										
										
										
											2012-03-05 17:40:12 +02:00
										 |  |  |         const MemoryRegionPortio *mrp = find_portio(mr, offset - mrio->offset, | 
					
						
							|  |  |  |                                                     width, false); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |         *data = ((uint64_t)1 << (width * 8)) - 1; | 
					
						
							|  |  |  |         if (mrp) { | 
					
						
							| 
									
										
										
										
											2012-01-08 19:51:35 +02:00
										 |  |  |             *data = mrp->read(mr->opaque, offset); | 
					
						
							| 
									
										
										
										
											2011-09-18 14:51:58 +02:00
										 |  |  |         } else if (width == 2) { | 
					
						
							| 
									
										
										
										
											2012-03-05 17:40:12 +02:00
										 |  |  |             mrp = find_portio(mr, offset - mrio->offset, 1, false); | 
					
						
							| 
									
										
										
										
											2011-09-18 14:51:58 +02:00
										 |  |  |             assert(mrp); | 
					
						
							| 
									
										
										
										
											2012-01-08 19:51:35 +02:00
										 |  |  |             *data = mrp->read(mr->opaque, offset) | | 
					
						
							|  |  |  |                     (mrp->read(mr->opaque, offset + 1) << 8); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:09 +03:00
										 |  |  |         } | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-08-11 10:40:26 +03:00
										 |  |  |     *data = 0; | 
					
						
							| 
									
										
										
										
											2012-01-08 19:51:35 +02:00
										 |  |  |     access_with_adjusted_size(offset, data, width, | 
					
						
							| 
									
										
										
										
											2011-08-11 10:40:26 +03:00
										 |  |  |                               mr->ops->impl.min_access_size, | 
					
						
							|  |  |  |                               mr->ops->impl.max_access_size, | 
					
						
							|  |  |  |                               memory_region_read_accessor, mr); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:08 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void memory_region_iorange_write(IORange *iorange, | 
					
						
							|  |  |  |                                         uint64_t offset, | 
					
						
							|  |  |  |                                         unsigned width, | 
					
						
							|  |  |  |                                         uint64_t data) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-05 17:40:12 +02:00
										 |  |  |     MemoryRegionIORange *mrio | 
					
						
							|  |  |  |         = container_of(iorange, MemoryRegionIORange, iorange); | 
					
						
							|  |  |  |     MemoryRegion *mr = mrio->mr; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:08 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-05 17:40:12 +02:00
										 |  |  |     offset += mrio->offset; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:09 +03:00
										 |  |  |     if (mr->ops->old_portio) { | 
					
						
							| 
									
										
										
										
											2012-03-05 17:40:12 +02:00
										 |  |  |         const MemoryRegionPortio *mrp = find_portio(mr, offset - mrio->offset, | 
					
						
							|  |  |  |                                                     width, true); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |         if (mrp) { | 
					
						
							| 
									
										
										
										
											2012-01-08 19:51:35 +02:00
										 |  |  |             mrp->write(mr->opaque, offset, data); | 
					
						
							| 
									
										
										
										
											2011-09-18 14:51:58 +02:00
										 |  |  |         } else if (width == 2) { | 
					
						
							| 
									
										
										
										
											2012-08-26 10:12:47 +02:00
										 |  |  |             mrp = find_portio(mr, offset - mrio->offset, 1, true); | 
					
						
							| 
									
										
										
										
											2011-09-18 14:51:58 +02:00
										 |  |  |             assert(mrp); | 
					
						
							| 
									
										
										
										
											2012-01-08 19:51:35 +02:00
										 |  |  |             mrp->write(mr->opaque, offset, data & 0xff); | 
					
						
							|  |  |  |             mrp->write(mr->opaque, offset + 1, data >> 8); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:09 +03:00
										 |  |  |         } | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-01-08 19:51:35 +02:00
										 |  |  |     access_with_adjusted_size(offset, &data, width, | 
					
						
							| 
									
										
										
										
											2011-08-11 10:40:26 +03:00
										 |  |  |                               mr->ops->impl.min_access_size, | 
					
						
							|  |  |  |                               mr->ops->impl.max_access_size, | 
					
						
							|  |  |  |                               memory_region_write_accessor, mr); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:08 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-03-05 17:40:12 +02:00
										 |  |  | static void memory_region_iorange_destructor(IORange *iorange) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     g_free(container_of(iorange, MemoryRegionIORange, iorange)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-08 16:54:16 +02:00
										 |  |  | const IORangeOps memory_region_iorange_ops = { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:08 +03:00
										 |  |  |     .read = memory_region_iorange_read, | 
					
						
							|  |  |  |     .write = memory_region_iorange_write, | 
					
						
							| 
									
										
										
										
											2012-03-05 17:40:12 +02:00
										 |  |  |     .destructor = memory_region_iorange_destructor, | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:08 +03:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-08 15:00:18 +02:00
										 |  |  | static AddressSpace *memory_region_to_address_space(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  |     AddressSpace *as; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-08 15:00:18 +02:00
										 |  |  |     while (mr->parent) { | 
					
						
							|  |  |  |         mr = mr->parent; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  |     QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { | 
					
						
							|  |  |  |         if (mr == as->root) { | 
					
						
							|  |  |  |             return as; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-12-08 15:00:18 +02:00
										 |  |  |     } | 
					
						
							|  |  |  |     abort(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | /* Render a memory region into the global view.  Ranges in @view obscure
 | 
					
						
							|  |  |  |  * ranges in @mr. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | static void render_memory_region(FlatView *view, | 
					
						
							|  |  |  |                                  MemoryRegion *mr, | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |                                  Int128 base, | 
					
						
							| 
									
										
										
										
											2011-09-25 14:48:47 +03:00
										 |  |  |                                  AddrRange clip, | 
					
						
							|  |  |  |                                  bool readonly) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     MemoryRegion *subregion; | 
					
						
							|  |  |  |     unsigned i; | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |     hwaddr offset_in_region; | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     Int128 remain; | 
					
						
							|  |  |  |     Int128 now; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     FlatRange fr; | 
					
						
							|  |  |  |     AddrRange tmp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-14 11:54:58 +03:00
										 |  |  |     if (!mr->enabled) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     int128_addto(&base, int128_make64(mr->addr)); | 
					
						
							| 
									
										
										
										
											2011-09-25 14:48:47 +03:00
										 |  |  |     readonly |= mr->readonly; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     tmp = addrrange_make(base, mr->size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!addrrange_intersects(tmp, clip)) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     clip = addrrange_intersection(tmp, clip); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mr->alias) { | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |         int128_subfrom(&base, int128_make64(mr->alias->addr)); | 
					
						
							|  |  |  |         int128_subfrom(&base, int128_make64(mr->alias_offset)); | 
					
						
							| 
									
										
										
										
											2011-09-25 14:48:47 +03:00
										 |  |  |         render_memory_region(view, mr->alias, base, clip, readonly); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Render subregions in priority order. */ | 
					
						
							|  |  |  |     QTAILQ_FOREACH(subregion, &mr->subregions, subregions_link) { | 
					
						
							| 
									
										
										
										
											2011-09-25 14:48:47 +03:00
										 |  |  |         render_memory_region(view, subregion, base, clip, readonly); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:06 +03:00
										 |  |  |     if (!mr->terminates) { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     offset_in_region = int128_get64(int128_sub(clip.start, base)); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     base = clip.start; | 
					
						
							|  |  |  |     remain = clip.size; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Render the region itself into any gaps left by the current view. */ | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     for (i = 0; i < view->nr && int128_nz(remain); ++i) { | 
					
						
							|  |  |  |         if (int128_ge(base, addrrange_end(view->ranges[i].addr))) { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |         if (int128_lt(base, view->ranges[i].addr.start)) { | 
					
						
							|  |  |  |             now = int128_min(remain, | 
					
						
							|  |  |  |                              int128_sub(view->ranges[i].addr.start, base)); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |             fr.mr = mr; | 
					
						
							|  |  |  |             fr.offset_in_region = offset_in_region; | 
					
						
							|  |  |  |             fr.addr = addrrange_make(base, now); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:02 +03:00
										 |  |  |             fr.dirty_log_mask = mr->dirty_log_mask; | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  |             fr.readable = mr->readable; | 
					
						
							| 
									
										
										
										
											2011-09-25 14:48:47 +03:00
										 |  |  |             fr.readonly = readonly; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |             flatview_insert(view, i, &fr); | 
					
						
							|  |  |  |             ++i; | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |             int128_addto(&base, now); | 
					
						
							|  |  |  |             offset_in_region += int128_get64(now); | 
					
						
							|  |  |  |             int128_subfrom(&remain, now); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2012-10-29 18:22:36 +02:00
										 |  |  |         now = int128_sub(int128_min(int128_add(base, remain), | 
					
						
							|  |  |  |                                     addrrange_end(view->ranges[i].addr)), | 
					
						
							|  |  |  |                          base); | 
					
						
							|  |  |  |         int128_addto(&base, now); | 
					
						
							|  |  |  |         offset_in_region += int128_get64(now); | 
					
						
							|  |  |  |         int128_subfrom(&remain, now); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     if (int128_nz(remain)) { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |         fr.mr = mr; | 
					
						
							|  |  |  |         fr.offset_in_region = offset_in_region; | 
					
						
							|  |  |  |         fr.addr = addrrange_make(base, remain); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:02 +03:00
										 |  |  |         fr.dirty_log_mask = mr->dirty_log_mask; | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  |         fr.readable = mr->readable; | 
					
						
							| 
									
										
										
										
											2011-09-25 14:48:47 +03:00
										 |  |  |         fr.readonly = readonly; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |         flatview_insert(view, i, &fr); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Render a memory topology into a list of disjoint absolute ranges. */ | 
					
						
							|  |  |  | static FlatView generate_memory_topology(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     FlatView view; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     flatview_init(&view); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-07 12:59:55 +02:00
										 |  |  |     if (mr) { | 
					
						
							|  |  |  |         render_memory_region(&view, mr, int128_zero(), | 
					
						
							|  |  |  |                              addrrange_make(int128_zero(), int128_2_64()), false); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:03 +03:00
										 |  |  |     flatview_simplify(&view); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return view; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  | static void address_space_add_del_ioeventfds(AddressSpace *as, | 
					
						
							|  |  |  |                                              MemoryRegionIoeventfd *fds_new, | 
					
						
							|  |  |  |                                              unsigned fds_new_nb, | 
					
						
							|  |  |  |                                              MemoryRegionIoeventfd *fds_old, | 
					
						
							|  |  |  |                                              unsigned fds_old_nb) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     unsigned iold, inew; | 
					
						
							| 
									
										
										
										
											2012-02-08 16:39:06 +02:00
										 |  |  |     MemoryRegionIoeventfd *fd; | 
					
						
							|  |  |  |     MemoryRegionSection section; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     /* Generate a symmetric difference of the old and new fd sets, adding
 | 
					
						
							|  |  |  |      * and deleting as necessary. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     iold = inew = 0; | 
					
						
							|  |  |  |     while (iold < fds_old_nb || inew < fds_new_nb) { | 
					
						
							|  |  |  |         if (iold < fds_old_nb | 
					
						
							|  |  |  |             && (inew == fds_new_nb | 
					
						
							|  |  |  |                 || memory_region_ioeventfd_before(fds_old[iold], | 
					
						
							|  |  |  |                                                   fds_new[inew]))) { | 
					
						
							| 
									
										
										
										
											2012-02-08 16:39:06 +02:00
										 |  |  |             fd = &fds_old[iold]; | 
					
						
							|  |  |  |             section = (MemoryRegionSection) { | 
					
						
							| 
									
										
										
										
											2012-10-02 20:13:51 +02:00
										 |  |  |                 .address_space = as, | 
					
						
							| 
									
										
										
										
											2012-02-08 16:39:06 +02:00
										 |  |  |                 .offset_within_address_space = int128_get64(fd->addr.start), | 
					
						
							|  |  |  |                 .size = int128_get64(fd->addr.size), | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |             MEMORY_LISTENER_CALL(eventfd_del, Forward, §ion, | 
					
						
							| 
									
										
										
										
											2012-07-05 17:16:27 +02:00
										 |  |  |                                  fd->match_data, fd->data, fd->e); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |             ++iold; | 
					
						
							|  |  |  |         } else if (inew < fds_new_nb | 
					
						
							|  |  |  |                    && (iold == fds_old_nb | 
					
						
							|  |  |  |                        || memory_region_ioeventfd_before(fds_new[inew], | 
					
						
							|  |  |  |                                                          fds_old[iold]))) { | 
					
						
							| 
									
										
										
										
											2012-02-08 16:39:06 +02:00
										 |  |  |             fd = &fds_new[inew]; | 
					
						
							|  |  |  |             section = (MemoryRegionSection) { | 
					
						
							| 
									
										
										
										
											2012-10-02 20:13:51 +02:00
										 |  |  |                 .address_space = as, | 
					
						
							| 
									
										
										
										
											2012-02-08 16:39:06 +02:00
										 |  |  |                 .offset_within_address_space = int128_get64(fd->addr.start), | 
					
						
							|  |  |  |                 .size = int128_get64(fd->addr.size), | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  |             MEMORY_LISTENER_CALL(eventfd_add, Reverse, §ion, | 
					
						
							| 
									
										
										
										
											2012-07-05 17:16:27 +02:00
										 |  |  |                                  fd->match_data, fd->data, fd->e); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |             ++inew; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             ++iold; | 
					
						
							|  |  |  |             ++inew; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void address_space_update_ioeventfds(AddressSpace *as) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     FlatRange *fr; | 
					
						
							|  |  |  |     unsigned ioeventfd_nb = 0; | 
					
						
							|  |  |  |     MemoryRegionIoeventfd *ioeventfds = NULL; | 
					
						
							|  |  |  |     AddrRange tmp; | 
					
						
							|  |  |  |     unsigned i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 13:53:41 +02:00
										 |  |  |     FOR_EACH_FLAT_RANGE(fr, as->current_map) { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |         for (i = 0; i < fr->mr->ioeventfd_nb; ++i) { | 
					
						
							|  |  |  |             tmp = addrrange_shift(fr->mr->ioeventfds[i].addr, | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |                                   int128_sub(fr->addr.start, | 
					
						
							|  |  |  |                                              int128_make64(fr->offset_in_region))); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |             if (addrrange_intersects(fr->addr, tmp)) { | 
					
						
							|  |  |  |                 ++ioeventfd_nb; | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |                 ioeventfds = g_realloc(ioeventfds, | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |                                           ioeventfd_nb * sizeof(*ioeventfds)); | 
					
						
							|  |  |  |                 ioeventfds[ioeventfd_nb-1] = fr->mr->ioeventfds[i]; | 
					
						
							|  |  |  |                 ioeventfds[ioeventfd_nb-1].addr = tmp; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     address_space_add_del_ioeventfds(as, ioeventfds, ioeventfd_nb, | 
					
						
							|  |  |  |                                      as->ioeventfds, as->ioeventfd_nb); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     g_free(as->ioeventfds); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |     as->ioeventfds = ioeventfds; | 
					
						
							|  |  |  |     as->ioeventfd_nb = ioeventfd_nb; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:12 +03:00
										 |  |  | static void address_space_update_topology_pass(AddressSpace *as, | 
					
						
							|  |  |  |                                                FlatView old_view, | 
					
						
							|  |  |  |                                                FlatView new_view, | 
					
						
							|  |  |  |                                                bool adding) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     unsigned iold, inew; | 
					
						
							|  |  |  |     FlatRange *frold, *frnew; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Generate a symmetric difference of the old and new memory maps.
 | 
					
						
							|  |  |  |      * Kill ranges in the old map, and instantiate ranges in the new map. | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     iold = inew = 0; | 
					
						
							|  |  |  |     while (iold < old_view.nr || inew < new_view.nr) { | 
					
						
							|  |  |  |         if (iold < old_view.nr) { | 
					
						
							|  |  |  |             frold = &old_view.ranges[iold]; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             frold = NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (inew < new_view.nr) { | 
					
						
							|  |  |  |             frnew = &new_view.ranges[inew]; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             frnew = NULL; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (frold | 
					
						
							|  |  |  |             && (!frnew | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |                 || int128_lt(frold->addr.start, frnew->addr.start) | 
					
						
							|  |  |  |                 || (int128_eq(frold->addr.start, frnew->addr.start) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |                     && !flatrange_equal(frold, frnew)))) { | 
					
						
							|  |  |  |             /* In old, but (not in new, or in new but attributes changed). */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:12 +03:00
										 |  |  |             if (!adding) { | 
					
						
							| 
									
										
										
										
											2012-02-08 15:05:50 +02:00
										 |  |  |                 MEMORY_LISTENER_UPDATE_REGION(frold, as, Reverse, region_del); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:12 +03:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |             ++iold; | 
					
						
							|  |  |  |         } else if (frold && frnew && flatrange_equal(frold, frnew)) { | 
					
						
							|  |  |  |             /* In both (logging may have changed) */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:12 +03:00
										 |  |  |             if (adding) { | 
					
						
							| 
									
										
										
										
											2012-02-08 21:36:02 +02:00
										 |  |  |                 MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, region_nop); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:12 +03:00
										 |  |  |                 if (frold->dirty_log_mask && !frnew->dirty_log_mask) { | 
					
						
							| 
									
										
										
										
											2012-02-08 15:05:50 +02:00
										 |  |  |                     MEMORY_LISTENER_UPDATE_REGION(frnew, as, Reverse, log_stop); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:12 +03:00
										 |  |  |                 } else if (frnew->dirty_log_mask && !frold->dirty_log_mask) { | 
					
						
							| 
									
										
										
										
											2012-02-08 15:05:50 +02:00
										 |  |  |                     MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, log_start); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:12 +03:00
										 |  |  |                 } | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:02 +03:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |             ++iold; | 
					
						
							|  |  |  |             ++inew; | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |             /* In new */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:12 +03:00
										 |  |  |             if (adding) { | 
					
						
							| 
									
										
										
										
											2012-02-08 15:05:50 +02:00
										 |  |  |                 MEMORY_LISTENER_UPDATE_REGION(frnew, as, Forward, region_add); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:12 +03:00
										 |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |             ++inew; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:12 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void address_space_update_topology(AddressSpace *as) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-02 13:53:41 +02:00
										 |  |  |     FlatView old_view = *as->current_map; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:12 +03:00
										 |  |  |     FlatView new_view = generate_memory_topology(as->root); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     address_space_update_topology_pass(as, old_view, new_view, false); | 
					
						
							|  |  |  |     address_space_update_topology_pass(as, old_view, new_view, true); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 13:53:41 +02:00
										 |  |  |     *as->current_map = new_view; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     flatview_destroy(&old_view); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |     address_space_update_ioeventfds(as); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:13 +03:00
										 |  |  | void memory_region_transaction_begin(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:32 +02:00
										 |  |  |     qemu_flush_coalesced_mmio_buffer(); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:13 +03:00
										 |  |  |     ++memory_region_transaction_depth; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_transaction_commit(void) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  |     AddressSpace *as; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:13 +03:00
										 |  |  |     assert(memory_region_transaction_depth); | 
					
						
							|  |  |  |     --memory_region_transaction_depth; | 
					
						
							| 
									
										
										
										
											2012-11-05 16:45:56 +01:00
										 |  |  |     if (!memory_region_transaction_depth && memory_region_update_pending) { | 
					
						
							|  |  |  |         memory_region_update_pending = false; | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:31 +02:00
										 |  |  |         MEMORY_LISTENER_CALL_GLOBAL(begin, Forward); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  |         QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { | 
					
						
							|  |  |  |             address_space_update_topology(as); | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:31 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         MEMORY_LISTENER_CALL_GLOBAL(commit, Forward); | 
					
						
							| 
									
										
										
										
											2011-09-14 12:16:20 +03:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:13 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:48 +03:00
										 |  |  | static void memory_region_destructor_none(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void memory_region_destructor_ram(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     qemu_ram_free(mr->ram_addr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void memory_region_destructor_ram_from_ptr(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     qemu_ram_free_from_ptr(mr->ram_addr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void memory_region_destructor_iomem(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  | static void memory_region_destructor_rom_device(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     qemu_ram_free(mr->ram_addr & TARGET_PAGE_MASK); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-20 16:22:55 +02:00
										 |  |  | static bool memory_region_wrong_endianness(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-01-07 09:45:14 +01:00
										 |  |  | #ifdef TARGET_WORDS_BIGENDIAN
 | 
					
						
							| 
									
										
										
										
											2011-11-20 16:22:55 +02:00
										 |  |  |     return mr->ops->endianness == DEVICE_LITTLE_ENDIAN; | 
					
						
							|  |  |  | #else
 | 
					
						
							|  |  |  |     return mr->ops->endianness == DEVICE_BIG_ENDIAN; | 
					
						
							|  |  |  | #endif
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | void memory_region_init(MemoryRegion *mr, | 
					
						
							|  |  |  |                         const char *name, | 
					
						
							|  |  |  |                         uint64_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     mr->ops = NULL; | 
					
						
							|  |  |  |     mr->parent = NULL; | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     mr->size = int128_make64(size); | 
					
						
							|  |  |  |     if (size == UINT64_MAX) { | 
					
						
							|  |  |  |         mr->size = int128_2_64(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     mr->addr = 0; | 
					
						
							| 
									
										
										
										
											2012-01-02 13:20:11 +02:00
										 |  |  |     mr->subpage = false; | 
					
						
							| 
									
										
										
										
											2011-09-14 11:54:58 +03:00
										 |  |  |     mr->enabled = true; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:06 +03:00
										 |  |  |     mr->terminates = false; | 
					
						
							| 
									
										
										
										
											2011-12-08 15:58:43 +02:00
										 |  |  |     mr->ram = false; | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  |     mr->readable = true; | 
					
						
							| 
									
										
										
										
											2011-09-25 14:48:47 +03:00
										 |  |  |     mr->readonly = false; | 
					
						
							| 
									
										
										
										
											2012-01-02 15:40:52 +02:00
										 |  |  |     mr->rom_device = false; | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:48 +03:00
										 |  |  |     mr->destructor = memory_region_destructor_none; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     mr->priority = 0; | 
					
						
							|  |  |  |     mr->may_overlap = false; | 
					
						
							|  |  |  |     mr->alias = NULL; | 
					
						
							|  |  |  |     QTAILQ_INIT(&mr->subregions); | 
					
						
							|  |  |  |     memset(&mr->subregions_link, 0, sizeof mr->subregions_link); | 
					
						
							|  |  |  |     QTAILQ_INIT(&mr->coalesced); | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     mr->name = g_strdup(name); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:02 +03:00
										 |  |  |     mr->dirty_log_mask = 0; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |     mr->ioeventfd_nb = 0; | 
					
						
							|  |  |  |     mr->ioeventfds = NULL; | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:29 +02:00
										 |  |  |     mr->flush_coalesced_mmio = false; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static bool memory_region_access_valid(MemoryRegion *mr, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                        hwaddr addr, | 
					
						
							| 
									
										
										
										
											2011-11-13 13:05:27 +02:00
										 |  |  |                                        unsigned size, | 
					
						
							|  |  |  |                                        bool is_write) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-11-13 13:05:27 +02:00
										 |  |  |     if (mr->ops->valid.accepts | 
					
						
							|  |  |  |         && !mr->ops->valid.accepts(mr->opaque, addr, size, is_write)) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     if (!mr->ops->valid.unaligned && (addr & (size - 1))) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /* Treat zero as compatibility all valid */ | 
					
						
							|  |  |  |     if (!mr->ops->valid.max_access_size) { | 
					
						
							|  |  |  |         return true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (size > mr->ops->valid.max_access_size | 
					
						
							|  |  |  |         || size < mr->ops->valid.min_access_size) { | 
					
						
							|  |  |  |         return false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-02 13:12:08 +02:00
										 |  |  | static uint64_t memory_region_dispatch_read1(MemoryRegion *mr, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                              hwaddr addr, | 
					
						
							| 
									
										
										
										
											2012-01-02 13:12:08 +02:00
										 |  |  |                                              unsigned size) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-08-11 10:40:25 +03:00
										 |  |  |     uint64_t data = 0; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-13 13:05:27 +02:00
										 |  |  |     if (!memory_region_access_valid(mr, addr, size, false)) { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |         return -1U; /* FIXME: better signalling */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:10 +03:00
										 |  |  |     if (!mr->ops->read) { | 
					
						
							|  |  |  |         return mr->ops->old_mmio.read[bitops_ffsl(size)](mr->opaque, addr); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     /* FIXME: support unaligned access */ | 
					
						
							| 
									
										
										
										
											2012-01-08 19:51:35 +02:00
										 |  |  |     access_with_adjusted_size(addr, &data, size, | 
					
						
							| 
									
										
										
										
											2011-08-11 10:40:25 +03:00
										 |  |  |                               mr->ops->impl.min_access_size, | 
					
						
							|  |  |  |                               mr->ops->impl.max_access_size, | 
					
						
							|  |  |  |                               memory_region_read_accessor, mr); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  |     return data; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-02 13:12:08 +02:00
										 |  |  | static void adjust_endianness(MemoryRegion *mr, uint64_t *data, unsigned size) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-01-02 13:12:08 +02:00
										 |  |  |     if (memory_region_wrong_endianness(mr)) { | 
					
						
							|  |  |  |         switch (size) { | 
					
						
							|  |  |  |         case 1: | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 2: | 
					
						
							|  |  |  |             *data = bswap16(*data); | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         case 4: | 
					
						
							|  |  |  |             *data = bswap32(*data); | 
					
						
							| 
									
										
										
										
											2012-01-07 09:45:15 +01:00
										 |  |  |             break; | 
					
						
							| 
									
										
										
										
											2012-01-02 13:12:08 +02:00
										 |  |  |         default: | 
					
						
							|  |  |  |             abort(); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static uint64_t memory_region_dispatch_read(MemoryRegion *mr, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                             hwaddr addr, | 
					
						
							| 
									
										
										
										
											2012-01-02 13:12:08 +02:00
										 |  |  |                                             unsigned size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     uint64_t ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ret = memory_region_dispatch_read1(mr, addr, size); | 
					
						
							|  |  |  |     adjust_endianness(mr, &ret, size); | 
					
						
							|  |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-02 13:12:08 +02:00
										 |  |  | static void memory_region_dispatch_write(MemoryRegion *mr, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                          hwaddr addr, | 
					
						
							| 
									
										
										
										
											2012-01-02 13:12:08 +02:00
										 |  |  |                                          uint64_t data, | 
					
						
							|  |  |  |                                          unsigned size) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-11-13 13:05:27 +02:00
										 |  |  |     if (!memory_region_access_valid(mr, addr, size, true)) { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |         return; /* FIXME: better signalling */ | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-01-02 13:12:08 +02:00
										 |  |  |     adjust_endianness(mr, &data, size); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:10 +03:00
										 |  |  |     if (!mr->ops->write) { | 
					
						
							|  |  |  |         mr->ops->old_mmio.write[bitops_ffsl(size)](mr->opaque, addr, data); | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     /* FIXME: support unaligned access */ | 
					
						
							| 
									
										
										
										
											2012-01-08 19:51:35 +02:00
										 |  |  |     access_with_adjusted_size(addr, &data, size, | 
					
						
							| 
									
										
										
										
											2011-08-11 10:40:25 +03:00
										 |  |  |                               mr->ops->impl.min_access_size, | 
					
						
							|  |  |  |                               mr->ops->impl.max_access_size, | 
					
						
							|  |  |  |                               memory_region_write_accessor, mr); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_init_io(MemoryRegion *mr, | 
					
						
							|  |  |  |                            const MemoryRegionOps *ops, | 
					
						
							|  |  |  |                            void *opaque, | 
					
						
							|  |  |  |                            const char *name, | 
					
						
							|  |  |  |                            uint64_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     memory_region_init(mr, name, size); | 
					
						
							|  |  |  |     mr->ops = ops; | 
					
						
							|  |  |  |     mr->opaque = opaque; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:06 +03:00
										 |  |  |     mr->terminates = true; | 
					
						
							| 
									
										
										
										
											2012-01-01 18:02:31 +02:00
										 |  |  |     mr->destructor = memory_region_destructor_iomem; | 
					
						
							| 
									
										
										
										
											2012-03-08 19:16:39 +02:00
										 |  |  |     mr->ram_addr = ~(ram_addr_t)0; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_init_ram(MemoryRegion *mr, | 
					
						
							|  |  |  |                             const char *name, | 
					
						
							|  |  |  |                             uint64_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     memory_region_init(mr, name, size); | 
					
						
							| 
									
										
										
										
											2011-12-08 15:58:43 +02:00
										 |  |  |     mr->ram = true; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:06 +03:00
										 |  |  |     mr->terminates = true; | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:48 +03:00
										 |  |  |     mr->destructor = memory_region_destructor_ram; | 
					
						
							| 
									
										
										
										
											2011-12-20 15:59:12 +02:00
										 |  |  |     mr->ram_addr = qemu_ram_alloc(size, mr); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_init_ram_ptr(MemoryRegion *mr, | 
					
						
							|  |  |  |                                 const char *name, | 
					
						
							|  |  |  |                                 uint64_t size, | 
					
						
							|  |  |  |                                 void *ptr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     memory_region_init(mr, name, size); | 
					
						
							| 
									
										
										
										
											2011-12-08 15:58:43 +02:00
										 |  |  |     mr->ram = true; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:06 +03:00
										 |  |  |     mr->terminates = true; | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:48 +03:00
										 |  |  |     mr->destructor = memory_region_destructor_ram_from_ptr; | 
					
						
							| 
									
										
										
										
											2011-12-20 15:59:12 +02:00
										 |  |  |     mr->ram_addr = qemu_ram_alloc_from_ptr(size, ptr, mr); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_init_alias(MemoryRegion *mr, | 
					
						
							|  |  |  |                               const char *name, | 
					
						
							|  |  |  |                               MemoryRegion *orig, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                               hwaddr offset, | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |                               uint64_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     memory_region_init(mr, name, size); | 
					
						
							|  |  |  |     mr->alias = orig; | 
					
						
							|  |  |  |     mr->alias_offset = offset; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  | void memory_region_init_rom_device(MemoryRegion *mr, | 
					
						
							|  |  |  |                                    const MemoryRegionOps *ops, | 
					
						
							| 
									
										
										
										
											2011-08-26 00:35:15 +03:00
										 |  |  |                                    void *opaque, | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  |                                    const char *name, | 
					
						
							|  |  |  |                                    uint64_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     memory_region_init(mr, name, size); | 
					
						
							| 
									
										
										
										
											2011-08-25 14:56:14 +03:00
										 |  |  |     mr->ops = ops; | 
					
						
							| 
									
										
										
										
											2011-08-26 00:35:15 +03:00
										 |  |  |     mr->opaque = opaque; | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  |     mr->terminates = true; | 
					
						
							| 
									
										
										
										
											2012-01-02 15:40:52 +02:00
										 |  |  |     mr->rom_device = true; | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  |     mr->destructor = memory_region_destructor_rom_device; | 
					
						
							| 
									
										
										
										
											2011-12-20 15:59:12 +02:00
										 |  |  |     mr->ram_addr = qemu_ram_alloc(size, mr); | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | static uint64_t invalid_read(void *opaque, hwaddr addr, | 
					
						
							| 
									
										
										
										
											2011-10-23 16:01:19 +02:00
										 |  |  |                              unsigned size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     MemoryRegion *mr = opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!mr->warning_printed) { | 
					
						
							|  |  |  |         fprintf(stderr, "Invalid read from memory region %s\n", mr->name); | 
					
						
							|  |  |  |         mr->warning_printed = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return -1U; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | static void invalid_write(void *opaque, hwaddr addr, uint64_t data, | 
					
						
							| 
									
										
										
										
											2011-10-23 16:01:19 +02:00
										 |  |  |                           unsigned size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     MemoryRegion *mr = opaque; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!mr->warning_printed) { | 
					
						
							|  |  |  |         fprintf(stderr, "Invalid write to memory region %s\n", mr->name); | 
					
						
							|  |  |  |         mr->warning_printed = true; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const MemoryRegionOps reservation_ops = { | 
					
						
							|  |  |  |     .read = invalid_read, | 
					
						
							|  |  |  |     .write = invalid_write, | 
					
						
							|  |  |  |     .endianness = DEVICE_NATIVE_ENDIAN, | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_init_reservation(MemoryRegion *mr, | 
					
						
							|  |  |  |                                     const char *name, | 
					
						
							|  |  |  |                                     uint64_t size) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     memory_region_init_io(mr, &reservation_ops, mr, name, size); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | void memory_region_destroy(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     assert(QTAILQ_EMPTY(&mr->subregions)); | 
					
						
							| 
									
										
										
										
											2012-10-17 17:14:41 +02:00
										 |  |  |     assert(memory_region_transaction_depth == 0); | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:48 +03:00
										 |  |  |     mr->destructor(mr); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     memory_region_clear_coalescing(mr); | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     g_free((char *)mr->name); | 
					
						
							|  |  |  |     g_free(mr->ioeventfds); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | uint64_t memory_region_size(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     if (int128_eq(mr->size, int128_2_64())) { | 
					
						
							|  |  |  |         return UINT64_MAX; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return int128_get64(mr->size); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-20 15:53:11 +02:00
										 |  |  | const char *memory_region_name(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return mr->name; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-08 15:58:43 +02:00
										 |  |  | bool memory_region_is_ram(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return mr->ram; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-15 17:20:34 +02:00
										 |  |  | bool memory_region_is_logging(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return mr->dirty_log_mask; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-08 16:05:11 +02:00
										 |  |  | bool memory_region_is_rom(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return mr->ram && mr->readonly; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | void memory_region_set_log(MemoryRegion *mr, bool log, unsigned client) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:02 +03:00
										 |  |  |     uint8_t mask = 1 << client; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_begin(); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:02 +03:00
										 |  |  |     mr->dirty_log_mask = (mr->dirty_log_mask & ~mask) | (log * mask); | 
					
						
							| 
									
										
										
										
											2012-11-05 16:45:56 +01:00
										 |  |  |     memory_region_update_pending |= mr->enabled; | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_commit(); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | bool memory_region_get_dirty(MemoryRegion *mr, hwaddr addr, | 
					
						
							|  |  |  |                              hwaddr size, unsigned client) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:06 +03:00
										 |  |  |     assert(mr->terminates); | 
					
						
							| 
									
										
										
										
											2012-01-22 16:38:21 +00:00
										 |  |  |     return cpu_physical_memory_get_dirty(mr->ram_addr + addr, size, | 
					
						
							|  |  |  |                                          1 << client); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | void memory_region_set_dirty(MemoryRegion *mr, hwaddr addr, | 
					
						
							|  |  |  |                              hwaddr size) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:06 +03:00
										 |  |  |     assert(mr->terminates); | 
					
						
							| 
									
										
										
										
											2011-10-16 16:04:59 +00:00
										 |  |  |     return cpu_physical_memory_set_dirty_range(mr->ram_addr + addr, size, -1); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_sync_dirty_bitmap(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  |     AddressSpace *as; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:02 +03:00
										 |  |  |     FlatRange *fr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  |     QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { | 
					
						
							|  |  |  |         FOR_EACH_FLAT_RANGE(fr, as->current_map) { | 
					
						
							|  |  |  |             if (fr->mr == mr) { | 
					
						
							|  |  |  |                 MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync); | 
					
						
							|  |  |  |             } | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:02 +03:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_set_readonly(MemoryRegion *mr, bool readonly) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-09-25 14:48:47 +03:00
										 |  |  |     if (mr->readonly != readonly) { | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |         memory_region_transaction_begin(); | 
					
						
							| 
									
										
										
										
											2011-09-25 14:48:47 +03:00
										 |  |  |         mr->readonly = readonly; | 
					
						
							| 
									
										
										
										
											2012-11-05 16:45:56 +01:00
										 |  |  |         memory_region_update_pending |= mr->enabled; | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |         memory_region_transaction_commit(); | 
					
						
							| 
									
										
										
										
											2011-09-25 14:48:47 +03:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  | void memory_region_rom_device_set_readable(MemoryRegion *mr, bool readable) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (mr->readable != readable) { | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |         memory_region_transaction_begin(); | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  |         mr->readable = readable; | 
					
						
							| 
									
										
										
										
											2012-11-05 16:45:56 +01:00
										 |  |  |         memory_region_update_pending |= mr->enabled; | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |         memory_region_transaction_commit(); | 
					
						
							| 
									
										
										
										
											2011-08-08 19:58:49 +03:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | void memory_region_reset_dirty(MemoryRegion *mr, hwaddr addr, | 
					
						
							|  |  |  |                                hwaddr size, unsigned client) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:06 +03:00
										 |  |  |     assert(mr->terminates); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:02 +03:00
										 |  |  |     cpu_physical_memory_reset_dirty(mr->ram_addr + addr, | 
					
						
							|  |  |  |                                     mr->ram_addr + addr + size, | 
					
						
							|  |  |  |                                     1 << client); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void *memory_region_get_ram_ptr(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (mr->alias) { | 
					
						
							|  |  |  |         return memory_region_get_ram_ptr(mr->alias) + mr->alias_offset; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:06 +03:00
										 |  |  |     assert(mr->terminates); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-08-30 00:38:24 +02:00
										 |  |  |     return qemu_get_ram_ptr(mr->ram_addr & TARGET_PAGE_MASK); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  | static void memory_region_update_coalesced_range_as(MemoryRegion *mr, AddressSpace *as) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     FlatRange *fr; | 
					
						
							|  |  |  |     CoalescedMemoryRange *cmr; | 
					
						
							|  |  |  |     AddrRange tmp; | 
					
						
							| 
									
										
										
										
											2012-10-02 18:21:54 +02:00
										 |  |  |     MemoryRegionSection section; | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  |     FOR_EACH_FLAT_RANGE(fr, as->current_map) { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |         if (fr->mr == mr) { | 
					
						
							| 
									
										
										
										
											2012-10-02 18:21:54 +02:00
										 |  |  |             section = (MemoryRegionSection) { | 
					
						
							| 
									
										
										
										
											2012-10-02 20:13:51 +02:00
										 |  |  |                 .address_space = as, | 
					
						
							| 
									
										
										
										
											2012-10-02 18:21:54 +02:00
										 |  |  |                 .offset_within_address_space = int128_get64(fr->addr.start), | 
					
						
							|  |  |  |                 .size = int128_get64(fr->addr.size), | 
					
						
							|  |  |  |             }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             MEMORY_LISTENER_CALL(coalesced_mmio_del, Reverse, §ion, | 
					
						
							|  |  |  |                                  int128_get64(fr->addr.start), | 
					
						
							|  |  |  |                                  int128_get64(fr->addr.size)); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |             QTAILQ_FOREACH(cmr, &mr->coalesced, link) { | 
					
						
							|  |  |  |                 tmp = addrrange_shift(cmr->addr, | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |                                       int128_sub(fr->addr.start, | 
					
						
							|  |  |  |                                                  int128_make64(fr->offset_in_region))); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |                 if (!addrrange_intersects(tmp, fr->addr)) { | 
					
						
							|  |  |  |                     continue; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |                 tmp = addrrange_intersection(tmp, fr->addr); | 
					
						
							| 
									
										
										
										
											2012-10-02 18:21:54 +02:00
										 |  |  |                 MEMORY_LISTENER_CALL(coalesced_mmio_add, Forward, §ion, | 
					
						
							|  |  |  |                                      int128_get64(tmp.start), | 
					
						
							|  |  |  |                                      int128_get64(tmp.size)); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  | static void memory_region_update_coalesced_range(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     AddressSpace *as; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { | 
					
						
							|  |  |  |         memory_region_update_coalesced_range_as(mr, as); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | void memory_region_set_coalescing(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     memory_region_clear_coalescing(mr); | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     memory_region_add_coalescing(mr, 0, int128_get64(mr->size)); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_add_coalescing(MemoryRegion *mr, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                   hwaddr offset, | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |                                   uint64_t size) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     CoalescedMemoryRange *cmr = g_malloc(sizeof(*cmr)); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |     cmr->addr = addrrange_make(int128_make64(offset), int128_make64(size)); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     QTAILQ_INSERT_TAIL(&mr->coalesced, cmr, link); | 
					
						
							|  |  |  |     memory_region_update_coalesced_range(mr); | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:29 +02:00
										 |  |  |     memory_region_set_flush_coalesced(mr); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_clear_coalescing(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     CoalescedMemoryRange *cmr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:29 +02:00
										 |  |  |     qemu_flush_coalesced_mmio_buffer(); | 
					
						
							|  |  |  |     mr->flush_coalesced_mmio = false; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     while (!QTAILQ_EMPTY(&mr->coalesced)) { | 
					
						
							|  |  |  |         cmr = QTAILQ_FIRST(&mr->coalesced); | 
					
						
							|  |  |  |         QTAILQ_REMOVE(&mr->coalesced, cmr, link); | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |         g_free(cmr); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     } | 
					
						
							|  |  |  |     memory_region_update_coalesced_range(mr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:29 +02:00
										 |  |  | void memory_region_set_flush_coalesced(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     mr->flush_coalesced_mmio = true; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_clear_flush_coalesced(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     qemu_flush_coalesced_mmio_buffer(); | 
					
						
							|  |  |  |     if (QTAILQ_EMPTY(&mr->coalesced)) { | 
					
						
							|  |  |  |         mr->flush_coalesced_mmio = false; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  | void memory_region_add_eventfd(MemoryRegion *mr, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                hwaddr addr, | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |                                unsigned size, | 
					
						
							|  |  |  |                                bool match_data, | 
					
						
							|  |  |  |                                uint64_t data, | 
					
						
							| 
									
										
										
										
											2012-07-05 17:16:27 +02:00
										 |  |  |                                EventNotifier *e) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     MemoryRegionIoeventfd mrfd = { | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |         .addr.start = int128_make64(addr), | 
					
						
							|  |  |  |         .addr.size = int128_make64(size), | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |         .match_data = match_data, | 
					
						
							|  |  |  |         .data = data, | 
					
						
							| 
									
										
										
										
											2012-07-05 17:16:27 +02:00
										 |  |  |         .e = e, | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |     }; | 
					
						
							|  |  |  |     unsigned i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-15 20:30:28 +02:00
										 |  |  |     adjust_endianness(mr, &mrfd.data, size); | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_begin(); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |     for (i = 0; i < mr->ioeventfd_nb; ++i) { | 
					
						
							|  |  |  |         if (memory_region_ioeventfd_before(mrfd, mr->ioeventfds[i])) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     ++mr->ioeventfd_nb; | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     mr->ioeventfds = g_realloc(mr->ioeventfds, | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |                                   sizeof(*mr->ioeventfds) * mr->ioeventfd_nb); | 
					
						
							|  |  |  |     memmove(&mr->ioeventfds[i+1], &mr->ioeventfds[i], | 
					
						
							|  |  |  |             sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb-1 - i)); | 
					
						
							|  |  |  |     mr->ioeventfds[i] = mrfd; | 
					
						
							| 
									
										
										
										
											2012-11-05 16:45:56 +01:00
										 |  |  |     memory_region_update_pending |= mr->enabled; | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_commit(); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_del_eventfd(MemoryRegion *mr, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                hwaddr addr, | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |                                unsigned size, | 
					
						
							|  |  |  |                                bool match_data, | 
					
						
							|  |  |  |                                uint64_t data, | 
					
						
							| 
									
										
										
										
											2012-07-05 17:16:27 +02:00
										 |  |  |                                EventNotifier *e) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     MemoryRegionIoeventfd mrfd = { | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |         .addr.start = int128_make64(addr), | 
					
						
							|  |  |  |         .addr.size = int128_make64(size), | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |         .match_data = match_data, | 
					
						
							|  |  |  |         .data = data, | 
					
						
							| 
									
										
										
										
											2012-07-05 17:16:27 +02:00
										 |  |  |         .e = e, | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |     }; | 
					
						
							|  |  |  |     unsigned i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-15 20:30:28 +02:00
										 |  |  |     adjust_endianness(mr, &mrfd.data, size); | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_begin(); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |     for (i = 0; i < mr->ioeventfd_nb; ++i) { | 
					
						
							|  |  |  |         if (memory_region_ioeventfd_equal(mrfd, mr->ioeventfds[i])) { | 
					
						
							|  |  |  |             break; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     assert(i != mr->ioeventfd_nb); | 
					
						
							|  |  |  |     memmove(&mr->ioeventfds[i], &mr->ioeventfds[i+1], | 
					
						
							|  |  |  |             sizeof(*mr->ioeventfds) * (mr->ioeventfd_nb - (i+1))); | 
					
						
							|  |  |  |     --mr->ioeventfd_nb; | 
					
						
							| 
									
										
										
										
											2011-08-20 22:09:37 -05:00
										 |  |  |     mr->ioeventfds = g_realloc(mr->ioeventfds, | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  |                                   sizeof(*mr->ioeventfds)*mr->ioeventfd_nb + 1); | 
					
						
							| 
									
										
										
										
											2012-11-05 16:45:56 +01:00
										 |  |  |     memory_region_update_pending |= mr->enabled; | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_commit(); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:11 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | static void memory_region_add_subregion_common(MemoryRegion *mr, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                                hwaddr offset, | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |                                                MemoryRegion *subregion) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     MemoryRegion *other; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_begin(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     assert(!subregion->parent); | 
					
						
							|  |  |  |     subregion->parent = mr; | 
					
						
							|  |  |  |     subregion->addr = offset; | 
					
						
							|  |  |  |     QTAILQ_FOREACH(other, &mr->subregions, subregions_link) { | 
					
						
							|  |  |  |         if (subregion->may_overlap || other->may_overlap) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |         if (int128_gt(int128_make64(offset), | 
					
						
							|  |  |  |                       int128_add(int128_make64(other->addr), other->size)) | 
					
						
							|  |  |  |             || int128_le(int128_add(int128_make64(offset), subregion->size), | 
					
						
							|  |  |  |                          int128_make64(other->addr))) { | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-08-22 11:14:56 -05:00
										 |  |  | #if 0
 | 
					
						
							| 
									
										
										
										
											2011-09-15 23:16:49 +02:00
										 |  |  |         printf("warning: subregion collision %llx/%llx (%s) " | 
					
						
							|  |  |  |                "vs %llx/%llx (%s)\n", | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |                (unsigned long long)offset, | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |                (unsigned long long)int128_get64(subregion->size), | 
					
						
							| 
									
										
										
										
											2011-09-15 23:16:49 +02:00
										 |  |  |                subregion->name, | 
					
						
							|  |  |  |                (unsigned long long)other->addr, | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |                (unsigned long long)int128_get64(other->size), | 
					
						
							| 
									
										
										
										
											2011-09-15 23:16:49 +02:00
										 |  |  |                other->name); | 
					
						
							| 
									
										
										
										
											2011-08-22 11:14:56 -05:00
										 |  |  | #endif
 | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     } | 
					
						
							|  |  |  |     QTAILQ_FOREACH(other, &mr->subregions, subregions_link) { | 
					
						
							|  |  |  |         if (subregion->priority >= other->priority) { | 
					
						
							|  |  |  |             QTAILQ_INSERT_BEFORE(other, subregion, subregions_link); | 
					
						
							|  |  |  |             goto done; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     QTAILQ_INSERT_TAIL(&mr->subregions, subregion, subregions_link); | 
					
						
							|  |  |  | done: | 
					
						
							| 
									
										
										
										
											2012-11-05 16:45:56 +01:00
										 |  |  |     memory_region_update_pending |= mr->enabled && subregion->enabled; | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_commit(); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_add_subregion(MemoryRegion *mr, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                  hwaddr offset, | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |                                  MemoryRegion *subregion) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     subregion->may_overlap = false; | 
					
						
							|  |  |  |     subregion->priority = 0; | 
					
						
							|  |  |  |     memory_region_add_subregion_common(mr, offset, subregion); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_add_subregion_overlap(MemoryRegion *mr, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                          hwaddr offset, | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |                                          MemoryRegion *subregion, | 
					
						
							|  |  |  |                                          unsigned priority) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     subregion->may_overlap = true; | 
					
						
							|  |  |  |     subregion->priority = priority; | 
					
						
							|  |  |  |     memory_region_add_subregion_common(mr, offset, subregion); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_del_subregion(MemoryRegion *mr, | 
					
						
							|  |  |  |                                  MemoryRegion *subregion) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_begin(); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  |     assert(subregion->parent == mr); | 
					
						
							|  |  |  |     subregion->parent = NULL; | 
					
						
							|  |  |  |     QTAILQ_REMOVE(&mr->subregions, subregion, subregions_link); | 
					
						
							| 
									
										
										
										
											2012-11-05 16:45:56 +01:00
										 |  |  |     memory_region_update_pending |= mr->enabled && subregion->enabled; | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_commit(); | 
					
						
							| 
									
										
										
										
											2011-09-14 11:54:58 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_region_set_enabled(MemoryRegion *mr, bool enabled) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     if (enabled == mr->enabled) { | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_begin(); | 
					
						
							| 
									
										
										
										
											2011-09-14 11:54:58 +03:00
										 |  |  |     mr->enabled = enabled; | 
					
						
							| 
									
										
										
										
											2012-11-05 16:45:56 +01:00
										 |  |  |     memory_region_update_pending = true; | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_commit(); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:01 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | void memory_region_set_address(MemoryRegion *mr, hwaddr addr) | 
					
						
							| 
									
										
										
										
											2011-09-14 12:10:12 +03:00
										 |  |  | { | 
					
						
							|  |  |  |     MemoryRegion *parent = mr->parent; | 
					
						
							|  |  |  |     unsigned priority = mr->priority; | 
					
						
							|  |  |  |     bool may_overlap = mr->may_overlap; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (addr == mr->addr || !parent) { | 
					
						
							|  |  |  |         mr->addr = addr; | 
					
						
							|  |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     memory_region_transaction_begin(); | 
					
						
							|  |  |  |     memory_region_del_subregion(parent, mr); | 
					
						
							|  |  |  |     if (may_overlap) { | 
					
						
							|  |  |  |         memory_region_add_subregion_overlap(parent, addr, mr, priority); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         memory_region_add_subregion(parent, addr, mr); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     memory_region_transaction_commit(); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | void memory_region_set_alias_offset(MemoryRegion *mr, hwaddr offset) | 
					
						
							| 
									
										
										
										
											2011-12-04 19:16:50 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     assert(mr->alias); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     if (offset == mr->alias_offset) { | 
					
						
							| 
									
										
										
										
											2011-12-04 19:16:50 +02:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_begin(); | 
					
						
							|  |  |  |     mr->alias_offset = offset; | 
					
						
							| 
									
										
										
										
											2012-11-05 16:45:56 +01:00
										 |  |  |     memory_region_update_pending |= mr->enabled; | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_commit(); | 
					
						
							| 
									
										
										
										
											2011-12-04 19:16:50 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-19 12:06:23 +02:00
										 |  |  | ram_addr_t memory_region_get_ram_addr(MemoryRegion *mr) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     return mr->ram_addr; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-08 15:00:18 +02:00
										 |  |  | static int cmp_flatrange_addr(const void *addr_, const void *fr_) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     const AddrRange *addr = addr_; | 
					
						
							|  |  |  |     const FlatRange *fr = fr_; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (int128_le(addrrange_end(*addr), fr->addr.start)) { | 
					
						
							|  |  |  |         return -1; | 
					
						
							|  |  |  |     } else if (int128_ge(addr->start, addrrange_end(fr->addr))) { | 
					
						
							|  |  |  |         return 1; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static FlatRange *address_space_lookup(AddressSpace *as, AddrRange addr) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-10-02 13:53:41 +02:00
										 |  |  |     return bsearch(&addr, as->current_map->ranges, as->current_map->nr, | 
					
						
							| 
									
										
										
										
											2011-12-08 15:00:18 +02:00
										 |  |  |                    sizeof(FlatRange), cmp_flatrange_addr); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | MemoryRegionSection memory_region_find(MemoryRegion *address_space, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                                        hwaddr addr, uint64_t size) | 
					
						
							| 
									
										
										
										
											2011-12-08 15:00:18 +02:00
										 |  |  | { | 
					
						
							|  |  |  |     AddressSpace *as = memory_region_to_address_space(address_space); | 
					
						
							|  |  |  |     AddrRange range = addrrange_make(int128_make64(addr), | 
					
						
							|  |  |  |                                      int128_make64(size)); | 
					
						
							|  |  |  |     FlatRange *fr = address_space_lookup(as, range); | 
					
						
							|  |  |  |     MemoryRegionSection ret = { .mr = NULL, .size = 0 }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!fr) { | 
					
						
							|  |  |  |         return ret; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 13:53:41 +02:00
										 |  |  |     while (fr > as->current_map->ranges | 
					
						
							| 
									
										
										
										
											2011-12-08 15:00:18 +02:00
										 |  |  |            && addrrange_intersects(fr[-1].addr, range)) { | 
					
						
							|  |  |  |         --fr; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     ret.mr = fr->mr; | 
					
						
							|  |  |  |     range = addrrange_intersection(range, fr->addr); | 
					
						
							|  |  |  |     ret.offset_within_region = fr->offset_in_region; | 
					
						
							|  |  |  |     ret.offset_within_region += int128_get64(int128_sub(range.start, | 
					
						
							|  |  |  |                                                         fr->addr.start)); | 
					
						
							|  |  |  |     ret.size = int128_get64(range.size); | 
					
						
							|  |  |  |     ret.offset_within_address_space = int128_get64(range.start); | 
					
						
							| 
									
										
										
										
											2012-02-08 17:01:23 +02:00
										 |  |  |     ret.readonly = fr->readonly; | 
					
						
							| 
									
										
										
										
											2011-12-08 15:00:18 +02:00
										 |  |  |     return ret; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-15 16:24:49 +02:00
										 |  |  | void memory_global_sync_dirty_bitmap(MemoryRegion *address_space) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-12-11 14:47:25 +02:00
										 |  |  |     AddressSpace *as = memory_region_to_address_space(address_space); | 
					
						
							|  |  |  |     FlatRange *fr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 13:53:41 +02:00
										 |  |  |     FOR_EACH_FLAT_RANGE(fr, as->current_map) { | 
					
						
							| 
									
										
										
										
											2012-02-08 15:05:50 +02:00
										 |  |  |         MEMORY_LISTENER_UPDATE_REGION(fr, as, Forward, log_sync); | 
					
						
							| 
									
										
										
										
											2011-12-11 14:47:25 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_global_dirty_log_start(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     global_dirty_log = true; | 
					
						
							| 
									
										
										
										
											2012-02-08 21:05:17 +02:00
										 |  |  |     MEMORY_LISTENER_CALL_GLOBAL(log_global_start, Forward); | 
					
						
							| 
									
										
										
										
											2011-12-11 14:47:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_global_dirty_log_stop(void) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     global_dirty_log = false; | 
					
						
							| 
									
										
										
										
											2012-02-08 21:05:17 +02:00
										 |  |  |     MEMORY_LISTENER_CALL_GLOBAL(log_global_stop, Reverse); | 
					
						
							| 
									
										
										
										
											2011-12-11 14:47:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void listener_add_address_space(MemoryListener *listener, | 
					
						
							|  |  |  |                                        AddressSpace *as) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     FlatRange *fr; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-04-04 15:15:41 +01:00
										 |  |  |     if (listener->address_space_filter | 
					
						
							| 
									
										
										
										
											2012-10-02 20:13:51 +02:00
										 |  |  |         && listener->address_space_filter != as) { | 
					
						
							| 
									
										
										
										
											2012-04-04 15:15:41 +01:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-12-11 14:47:25 +02:00
										 |  |  |     if (global_dirty_log) { | 
					
						
							| 
									
										
										
										
											2012-10-02 16:39:57 +02:00
										 |  |  |         if (listener->log_global_start) { | 
					
						
							|  |  |  |             listener->log_global_start(listener); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-12-11 14:47:25 +02:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-10-02 16:39:57 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 13:53:41 +02:00
										 |  |  |     FOR_EACH_FLAT_RANGE(fr, as->current_map) { | 
					
						
							| 
									
										
										
										
											2011-12-11 14:47:25 +02:00
										 |  |  |         MemoryRegionSection section = { | 
					
						
							|  |  |  |             .mr = fr->mr, | 
					
						
							| 
									
										
										
										
											2012-10-02 20:13:51 +02:00
										 |  |  |             .address_space = as, | 
					
						
							| 
									
										
										
										
											2011-12-11 14:47:25 +02:00
										 |  |  |             .offset_within_region = fr->offset_in_region, | 
					
						
							|  |  |  |             .size = int128_get64(fr->addr.size), | 
					
						
							|  |  |  |             .offset_within_address_space = int128_get64(fr->addr.start), | 
					
						
							| 
									
										
										
										
											2012-02-08 17:01:23 +02:00
										 |  |  |             .readonly = fr->readonly, | 
					
						
							| 
									
										
										
										
											2011-12-11 14:47:25 +02:00
										 |  |  |         }; | 
					
						
							| 
									
										
										
										
											2012-10-02 16:39:57 +02:00
										 |  |  |         if (listener->region_add) { | 
					
						
							|  |  |  |             listener->region_add(listener, §ion); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2011-12-11 14:47:25 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 20:13:51 +02:00
										 |  |  | void memory_listener_register(MemoryListener *listener, AddressSpace *filter) | 
					
						
							| 
									
										
										
										
											2011-12-11 14:47:25 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-02-08 15:05:50 +02:00
										 |  |  |     MemoryListener *other = NULL; | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  |     AddressSpace *as; | 
					
						
							| 
									
										
										
										
											2012-02-08 15:05:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-02-08 21:05:17 +02:00
										 |  |  |     listener->address_space_filter = filter; | 
					
						
							| 
									
										
										
										
											2012-02-08 15:05:50 +02:00
										 |  |  |     if (QTAILQ_EMPTY(&memory_listeners) | 
					
						
							|  |  |  |         || listener->priority >= QTAILQ_LAST(&memory_listeners, | 
					
						
							|  |  |  |                                              memory_listeners)->priority) { | 
					
						
							|  |  |  |         QTAILQ_INSERT_TAIL(&memory_listeners, listener, link); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |         QTAILQ_FOREACH(other, &memory_listeners, link) { | 
					
						
							|  |  |  |             if (listener->priority < other->priority) { | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         QTAILQ_INSERT_BEFORE(other, listener, link); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { | 
					
						
							|  |  |  |         listener_add_address_space(listener, as); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-12-11 14:47:25 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void memory_listener_unregister(MemoryListener *listener) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-02-08 15:05:50 +02:00
										 |  |  |     QTAILQ_REMOVE(&memory_listeners, listener, link); | 
					
						
							| 
									
										
										
										
											2011-12-15 16:24:49 +02:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-12-08 15:00:18 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 14:59:23 +02:00
										 |  |  | void address_space_init(AddressSpace *as, MemoryRegion *root) | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:04 +03:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_begin(); | 
					
						
							| 
									
										
										
										
											2012-10-02 13:53:41 +02:00
										 |  |  |     as->root = root; | 
					
						
							|  |  |  |     as->current_map = g_new(FlatView, 1); | 
					
						
							|  |  |  |     flatview_init(as->current_map); | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  |     QTAILQ_INSERT_TAIL(&address_spaces, as, address_spaces_link); | 
					
						
							|  |  |  |     as->name = NULL; | 
					
						
							| 
									
										
										
										
											2012-08-23 13:02:30 +02:00
										 |  |  |     memory_region_transaction_commit(); | 
					
						
							| 
									
										
										
										
											2012-10-03 16:22:53 +02:00
										 |  |  |     address_space_init_dispatch(as); | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:04 +03:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2011-07-26 14:26:08 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-07 12:59:55 +02:00
										 |  |  | void address_space_destroy(AddressSpace *as) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     /* Flush out anything from MemoryListeners listening in on this */ | 
					
						
							|  |  |  |     memory_region_transaction_begin(); | 
					
						
							|  |  |  |     as->root = NULL; | 
					
						
							|  |  |  |     memory_region_transaction_commit(); | 
					
						
							|  |  |  |     QTAILQ_REMOVE(&address_spaces, as, address_spaces_link); | 
					
						
							|  |  |  |     address_space_destroy_dispatch(as); | 
					
						
							|  |  |  |     flatview_destroy(as->current_map); | 
					
						
							|  |  |  |     g_free(as->current_map); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | uint64_t io_mem_read(MemoryRegion *mr, hwaddr addr, unsigned size) | 
					
						
							| 
									
										
										
										
											2011-11-21 12:27:03 +02:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-08 18:08:35 +02:00
										 |  |  |     return memory_region_dispatch_read(mr, addr, size); | 
					
						
							| 
									
										
										
										
											2011-11-21 12:27:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  | void io_mem_write(MemoryRegion *mr, hwaddr addr, | 
					
						
							| 
									
										
										
										
											2011-11-21 12:27:03 +02:00
										 |  |  |                   uint64_t val, unsigned size) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2012-03-08 18:08:35 +02:00
										 |  |  |     memory_region_dispatch_write(mr, addr, val, size); | 
					
						
							| 
									
										
										
										
											2011-11-21 12:27:03 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  | typedef struct MemoryRegionList MemoryRegionList; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct MemoryRegionList { | 
					
						
							|  |  |  |     const MemoryRegion *mr; | 
					
						
							|  |  |  |     bool printed; | 
					
						
							|  |  |  |     QTAILQ_ENTRY(MemoryRegionList) queue; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | typedef QTAILQ_HEAD(queue, MemoryRegionList) MemoryRegionListHead; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static void mtree_print_mr(fprintf_function mon_printf, void *f, | 
					
						
							|  |  |  |                            const MemoryRegion *mr, unsigned int level, | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                            hwaddr base, | 
					
						
							| 
									
										
										
										
											2011-09-27 15:00:41 +02:00
										 |  |  |                            MemoryRegionListHead *alias_print_queue) | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  | { | 
					
						
							| 
									
										
										
										
											2011-09-27 15:00:41 +02:00
										 |  |  |     MemoryRegionList *new_ml, *ml, *next_ml; | 
					
						
							|  |  |  |     MemoryRegionListHead submr_print_queue; | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  |     const MemoryRegion *submr; | 
					
						
							|  |  |  |     unsigned int i; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-31 10:49:02 +01:00
										 |  |  |     if (!mr || !mr->enabled) { | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  |         return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for (i = 0; i < level; i++) { | 
					
						
							|  |  |  |         mon_printf(f, "  "); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (mr->alias) { | 
					
						
							|  |  |  |         MemoryRegionList *ml; | 
					
						
							|  |  |  |         bool found = false; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         /* check if the alias is already in the queue */ | 
					
						
							| 
									
										
										
										
											2011-09-27 15:00:41 +02:00
										 |  |  |         QTAILQ_FOREACH(ml, alias_print_queue, queue) { | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  |             if (ml->mr == mr->alias && !ml->printed) { | 
					
						
							|  |  |  |                 found = true; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (!found) { | 
					
						
							|  |  |  |             ml = g_new(MemoryRegionList, 1); | 
					
						
							|  |  |  |             ml->mr = mr->alias; | 
					
						
							|  |  |  |             ml->printed = false; | 
					
						
							| 
									
										
										
										
											2011-09-27 15:00:41 +02:00
										 |  |  |             QTAILQ_INSERT_TAIL(alias_print_queue, ml, queue); | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  |         } | 
					
						
							| 
									
										
										
										
											2012-02-04 16:25:42 +01:00
										 |  |  |         mon_printf(f, TARGET_FMT_plx "-" TARGET_FMT_plx | 
					
						
							|  |  |  |                    " (prio %d, %c%c): alias %s @%s " TARGET_FMT_plx | 
					
						
							|  |  |  |                    "-" TARGET_FMT_plx "\n", | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  |                    base + mr->addr, | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |                    base + mr->addr | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                    + (hwaddr)int128_get64(mr->size) - 1, | 
					
						
							| 
									
										
										
										
											2011-09-27 15:00:31 +02:00
										 |  |  |                    mr->priority, | 
					
						
							| 
									
										
										
										
											2012-02-04 16:25:42 +01:00
										 |  |  |                    mr->readable ? 'R' : '-', | 
					
						
							|  |  |  |                    !mr->readonly && !(mr->rom_device && mr->readable) ? 'W' | 
					
						
							|  |  |  |                                                                       : '-', | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  |                    mr->name, | 
					
						
							|  |  |  |                    mr->alias->name, | 
					
						
							|  |  |  |                    mr->alias_offset, | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |                    mr->alias_offset | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                    + (hwaddr)int128_get64(mr->size) - 1); | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  |     } else { | 
					
						
							| 
									
										
										
										
											2012-02-04 16:25:42 +01:00
										 |  |  |         mon_printf(f, | 
					
						
							|  |  |  |                    TARGET_FMT_plx "-" TARGET_FMT_plx " (prio %d, %c%c): %s\n", | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  |                    base + mr->addr, | 
					
						
							| 
									
										
										
										
											2011-10-16 13:19:17 +02:00
										 |  |  |                    base + mr->addr | 
					
						
							| 
									
										
										
										
											2012-10-23 12:30:10 +02:00
										 |  |  |                    + (hwaddr)int128_get64(mr->size) - 1, | 
					
						
							| 
									
										
										
										
											2011-09-27 15:00:31 +02:00
										 |  |  |                    mr->priority, | 
					
						
							| 
									
										
										
										
											2012-02-04 16:25:42 +01:00
										 |  |  |                    mr->readable ? 'R' : '-', | 
					
						
							|  |  |  |                    !mr->readonly && !(mr->rom_device && mr->readable) ? 'W' | 
					
						
							|  |  |  |                                                                       : '-', | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  |                    mr->name); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2011-09-27 15:00:41 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     QTAILQ_INIT(&submr_print_queue); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  |     QTAILQ_FOREACH(submr, &mr->subregions, subregions_link) { | 
					
						
							| 
									
										
										
										
											2011-09-27 15:00:41 +02:00
										 |  |  |         new_ml = g_new(MemoryRegionList, 1); | 
					
						
							|  |  |  |         new_ml->mr = submr; | 
					
						
							|  |  |  |         QTAILQ_FOREACH(ml, &submr_print_queue, queue) { | 
					
						
							|  |  |  |             if (new_ml->mr->addr < ml->mr->addr || | 
					
						
							|  |  |  |                 (new_ml->mr->addr == ml->mr->addr && | 
					
						
							|  |  |  |                  new_ml->mr->priority > ml->mr->priority)) { | 
					
						
							|  |  |  |                 QTAILQ_INSERT_BEFORE(ml, new_ml, queue); | 
					
						
							|  |  |  |                 new_ml = NULL; | 
					
						
							|  |  |  |                 break; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (new_ml) { | 
					
						
							|  |  |  |             QTAILQ_INSERT_TAIL(&submr_print_queue, new_ml, queue); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QTAILQ_FOREACH(ml, &submr_print_queue, queue) { | 
					
						
							|  |  |  |         mtree_print_mr(mon_printf, f, ml->mr, level + 1, base + mr->addr, | 
					
						
							|  |  |  |                        alias_print_queue); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-11-13 12:00:55 +02:00
										 |  |  |     QTAILQ_FOREACH_SAFE(ml, &submr_print_queue, queue, next_ml) { | 
					
						
							| 
									
										
										
										
											2011-09-27 15:00:41 +02:00
										 |  |  |         g_free(ml); | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | void mtree_info(fprintf_function mon_printf, void *f) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     MemoryRegionListHead ml_head; | 
					
						
							|  |  |  |     MemoryRegionList *ml, *ml2; | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  |     AddressSpace *as; | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     QTAILQ_INIT(&ml_head); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-10-02 15:28:50 +02:00
										 |  |  |     QTAILQ_FOREACH(as, &address_spaces, address_spaces_link) { | 
					
						
							|  |  |  |         if (!as->name) { | 
					
						
							|  |  |  |             continue; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         mon_printf(f, "%s\n", as->name); | 
					
						
							|  |  |  |         mtree_print_mr(mon_printf, f, as->root, 0, 0, &ml_head); | 
					
						
							| 
									
										
										
										
											2012-03-10 16:58:35 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     mon_printf(f, "aliases\n"); | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  |     /* print aliased regions */ | 
					
						
							|  |  |  |     QTAILQ_FOREACH(ml, &ml_head, queue) { | 
					
						
							|  |  |  |         if (!ml->printed) { | 
					
						
							|  |  |  |             mon_printf(f, "%s\n", ml->mr->name); | 
					
						
							|  |  |  |             mtree_print_mr(mon_printf, f, ml->mr, 0, 0, &ml_head); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     QTAILQ_FOREACH_SAFE(ml, &ml_head, queue, ml2) { | 
					
						
							| 
									
										
										
										
											2011-11-13 12:00:55 +02:00
										 |  |  |         g_free(ml); | 
					
						
							| 
									
										
										
										
											2011-09-11 20:22:05 +00:00
										 |  |  |     } | 
					
						
							|  |  |  | } |