Statistics
| Branch: | Revision:

root / hw / dataplane / hostmem.c @ 0d09e41a

History | View | Annotate | Download (5.4 kB)

1
/*
2
 * Thread-safe guest to host memory mapping
3
 *
4
 * Copyright 2012 Red Hat, Inc. and/or its affiliates
5
 *
6
 * Authors:
7
 *   Stefan Hajnoczi <stefanha@redhat.com>
8
 *
9
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10
 * See the COPYING file in the top-level directory.
11
 *
12
 */
13

    
14
#include "exec/address-spaces.h"
15
#include "hw/virtio/dataplane/hostmem.h"
16

    
17
static int hostmem_lookup_cmp(const void *phys_, const void *region_)
18
{
19
    hwaddr phys = *(const hwaddr *)phys_;
20
    const HostMemRegion *region = region_;
21

    
22
    if (phys < region->guest_addr) {
23
        return -1;
24
    } else if (phys >= region->guest_addr + region->size) {
25
        return 1;
26
    } else {
27
        return 0;
28
    }
29
}
30

    
31
/**
32
 * Map guest physical address to host pointer
33
 */
34
void *hostmem_lookup(HostMem *hostmem, hwaddr phys, hwaddr len, bool is_write)
35
{
36
    HostMemRegion *region;
37
    void *host_addr = NULL;
38
    hwaddr offset_within_region;
39

    
40
    qemu_mutex_lock(&hostmem->current_regions_lock);
41
    region = bsearch(&phys, hostmem->current_regions,
42
                     hostmem->num_current_regions,
43
                     sizeof(hostmem->current_regions[0]),
44
                     hostmem_lookup_cmp);
45
    if (!region) {
46
        goto out;
47
    }
48
    if (is_write && region->readonly) {
49
        goto out;
50
    }
51
    offset_within_region = phys - region->guest_addr;
52
    if (len <= region->size - offset_within_region) {
53
        host_addr = region->host_addr + offset_within_region;
54
    }
55
out:
56
    qemu_mutex_unlock(&hostmem->current_regions_lock);
57

    
58
    return host_addr;
59
}
60

    
61
/**
62
 * Install new regions list
63
 */
64
static void hostmem_listener_commit(MemoryListener *listener)
65
{
66
    HostMem *hostmem = container_of(listener, HostMem, listener);
67

    
68
    qemu_mutex_lock(&hostmem->current_regions_lock);
69
    g_free(hostmem->current_regions);
70
    hostmem->current_regions = hostmem->new_regions;
71
    hostmem->num_current_regions = hostmem->num_new_regions;
72
    qemu_mutex_unlock(&hostmem->current_regions_lock);
73

    
74
    /* Reset new regions list */
75
    hostmem->new_regions = NULL;
76
    hostmem->num_new_regions = 0;
77
}
78

    
79
/**
80
 * Add a MemoryRegionSection to the new regions list
81
 */
82
static void hostmem_append_new_region(HostMem *hostmem,
83
                                      MemoryRegionSection *section)
84
{
85
    void *ram_ptr = memory_region_get_ram_ptr(section->mr);
86
    size_t num = hostmem->num_new_regions;
87
    size_t new_size = (num + 1) * sizeof(hostmem->new_regions[0]);
88

    
89
    hostmem->new_regions = g_realloc(hostmem->new_regions, new_size);
90
    hostmem->new_regions[num] = (HostMemRegion){
91
        .host_addr = ram_ptr + section->offset_within_region,
92
        .guest_addr = section->offset_within_address_space,
93
        .size = section->size,
94
        .readonly = section->readonly,
95
    };
96
    hostmem->num_new_regions++;
97
}
98

    
99
static void hostmem_listener_append_region(MemoryListener *listener,
100
                                           MemoryRegionSection *section)
101
{
102
    HostMem *hostmem = container_of(listener, HostMem, listener);
103

    
104
    /* Ignore non-RAM regions, we may not be able to map them */
105
    if (!memory_region_is_ram(section->mr)) {
106
        return;
107
    }
108

    
109
    /* Ignore regions with dirty logging, we cannot mark them dirty */
110
    if (memory_region_is_logging(section->mr)) {
111
        return;
112
    }
113

    
114
    hostmem_append_new_region(hostmem, section);
115
}
116

    
117
/* We don't implement most MemoryListener callbacks, use these nop stubs */
118
static void hostmem_listener_dummy(MemoryListener *listener)
119
{
120
}
121

    
122
static void hostmem_listener_section_dummy(MemoryListener *listener,
123
                                           MemoryRegionSection *section)
124
{
125
}
126

    
127
static void hostmem_listener_eventfd_dummy(MemoryListener *listener,
128
                                           MemoryRegionSection *section,
129
                                           bool match_data, uint64_t data,
130
                                           EventNotifier *e)
131
{
132
}
133

    
134
static void hostmem_listener_coalesced_mmio_dummy(MemoryListener *listener,
135
                                                  MemoryRegionSection *section,
136
                                                  hwaddr addr, hwaddr len)
137
{
138
}
139

    
140
void hostmem_init(HostMem *hostmem)
141
{
142
    memset(hostmem, 0, sizeof(*hostmem));
143

    
144
    qemu_mutex_init(&hostmem->current_regions_lock);
145

    
146
    hostmem->listener = (MemoryListener){
147
        .begin = hostmem_listener_dummy,
148
        .commit = hostmem_listener_commit,
149
        .region_add = hostmem_listener_append_region,
150
        .region_del = hostmem_listener_section_dummy,
151
        .region_nop = hostmem_listener_append_region,
152
        .log_start = hostmem_listener_section_dummy,
153
        .log_stop = hostmem_listener_section_dummy,
154
        .log_sync = hostmem_listener_section_dummy,
155
        .log_global_start = hostmem_listener_dummy,
156
        .log_global_stop = hostmem_listener_dummy,
157
        .eventfd_add = hostmem_listener_eventfd_dummy,
158
        .eventfd_del = hostmem_listener_eventfd_dummy,
159
        .coalesced_mmio_add = hostmem_listener_coalesced_mmio_dummy,
160
        .coalesced_mmio_del = hostmem_listener_coalesced_mmio_dummy,
161
        .priority = 10,
162
    };
163

    
164
    memory_listener_register(&hostmem->listener, &address_space_memory);
165
    if (hostmem->num_new_regions > 0) {
166
        hostmem_listener_commit(&hostmem->listener);
167
    }
168
}
169

    
170
void hostmem_finalize(HostMem *hostmem)
171
{
172
    memory_listener_unregister(&hostmem->listener);
173
    g_free(hostmem->new_regions);
174
    g_free(hostmem->current_regions);
175
    qemu_mutex_destroy(&hostmem->current_regions_lock);
176
}