L4Re/departure

Annotated libmem/lib/src/flexpage.cc

554:b3eab5c45452
19 months ago Paul Boddie Moved flexpage-related IPC functions into libmem, also incorporating the invalidation of derived flexpages into the flexpage abstraction.
paul@93 1
/*
paul@93 2
 * A flexpage abstraction.
paul@93 3
 *
paul@554 4
 * Copyright (C) 2021, 2022, 2023 Paul Boddie <paul@boddie.org.uk>
paul@93 5
 *
paul@93 6
 * This program is free software; you can redistribute it and/or
paul@93 7
 * modify it under the terms of the GNU General Public License as
paul@93 8
 * published by the Free Software Foundation; either version 2 of
paul@93 9
 * the License, or (at your option) any later version.
paul@93 10
 *
paul@93 11
 * This program is distributed in the hope that it will be useful,
paul@93 12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
paul@93 13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
paul@93 14
 * GNU General Public License for more details.
paul@93 15
 *
paul@93 16
 * You should have received a copy of the GNU General Public License
paul@93 17
 * along with this program; if not, write to the Free Software
paul@93 18
 * Foundation, Inc., 51 Franklin Street, Fifth Floor,
paul@93 19
 * Boston, MA  02110-1301, USA
paul@93 20
 */
paul@93 21
paul@0 22
#include <algorithm>
paul@0 23
paul@0 24
#include "flexpage.h"
paul@554 25
#include "ipc.h"
paul@0 26
paul@0 27
paul@0 28
paul@342 29
/* Virtual destructor required for introspection. */
paul@342 30
paul@342 31
Flexpage::~Flexpage()
paul@342 32
{
paul@342 33
}
paul@342 34
paul@0 35
/* Reset the flexpage using 'offset', being the file offset. */
paul@0 36
paul@0 37
void Flexpage::reset(offset_t offset)
paul@0 38
{
paul@332 39
    if (region == NULL)
paul@332 40
        return;
paul@332 41
paul@0 42
    _counter = 0;
paul@333 43
    _flags = 0;
paul@0 44
paul@0 45
    /* By definition (see "Flexible-Sized Page Objects - Object-Orientation
paul@0 46
       in Operation Systems"), flexpages are aligned to multiples of their
paul@0 47
       size.
paul@0 48
paul@0 49
       The size of the flexpage depends on the amount of space around the
paul@0 50
       accessed page. It cannot exceed the size of the memory region. */
paul@0 51
paul@0 52
    size = max_multiple(region->start, region->end, PAGE_SIZE);
paul@0 53
paul@0 54
    /* The base address of the flexpage is computed from the region start
paul@0 55
       and flexpage size. It will be no lower than the region start.
paul@0 56
paul@0 57
       Sent flexpages may use higher bases due to receive window constraints,
paul@0 58
       these being communicated by the "hot spot". */
paul@0 59
paul@0 60
    base_addr = round(region->start, size);
paul@0 61
paul@0 62
    /* Get the file offset for the base of the flexpage. This will be a
paul@0 63
       multiple of the flexpage size for alignment purposes. */
paul@0 64
paul@0 65
    base_offset = trunc(offset, size);
paul@0 66
paul@0 67
    /* The page being accessed is relative to the base.
paul@0 68
       (This is transient information recording the initialising access
paul@0 69
       details.) */
paul@0 70
paul@0 71
    page_offset = trunc(offset - base_offset, PAGE_SIZE);
paul@0 72
    page_addr = base_addr + page_offset;
paul@0 73
}
paul@0 74
paul@332 75
/* Set a region. */
paul@332 76
paul@332 77
void Flexpage::set_region(Region *region)
paul@332 78
{
paul@332 79
    this->region = region;
paul@332 80
}
paul@332 81
paul@110 82
/* Decrement the usage counter, returning whether the flexpage is now no longer
paul@110 83
   used. */
paul@110 84
paul@0 85
bool Flexpage::decrement()
paul@0 86
{
paul@0 87
    if (_counter)
paul@0 88
    {
paul@0 89
        _counter--;
paul@0 90
        return _counter == 0;
paul@0 91
    }
paul@0 92
    else
paul@0 93
        return 0;
paul@0 94
}
paul@0 95
paul@110 96
/* Increment the usage counter. */
paul@110 97
paul@0 98
void Flexpage::increment()
paul@0 99
{
paul@0 100
    _counter++;
paul@0 101
}
paul@0 102
paul@554 103
/* Unmap and invalidate the flexpage, meaning that it should not now be in
paul@554 104
   use. */
paul@110 105
paul@0 106
void Flexpage::invalidate()
paul@0 107
{
paul@0 108
    _counter = 0;
paul@554 109
    ipc_unmap_flexpage(this);
paul@554 110
paul@554 111
    /* Unmap and invalidate all derived flexpages. */
paul@554 112
paul@554 113
    disassociate();
paul@0 114
}
paul@0 115
paul@110 116
/* Return whether the flexpage is in use and is therefore valid. */
paul@110 117
paul@0 118
bool Flexpage::valid()
paul@0 119
{
paul@0 120
    return _counter != 0;
paul@0 121
}
paul@0 122
paul@0 123
/* Return whether the flexpage supports the given file 'position'. */
paul@0 124
paul@0 125
bool Flexpage::supports_position(offset_t position)
paul@0 126
{
paul@0 127
    return (base_offset <= position) && (position < (base_offset + size));
paul@0 128
}
paul@0 129
paul@86 130
/* Upgrade the flags involved with this flexpage. This is used to track the
paul@86 131
   maximal flags employed by the different pagers, with the result being used in
paul@86 132
   unmap operations. */
paul@86 133
paul@121 134
void Flexpage::upgrade(map_flags_t flags)
paul@11 135
{
paul@11 136
    if (flags && (flags != _flags))
paul@11 137
        _flags |= flags;
paul@11 138
}
paul@11 139
paul@115 140
/* Return whether the flexpage has been modified due to write access having been
paul@115 141
   granted for any user of the page. */
paul@115 142
paul@115 143
bool Flexpage::modified()
paul@115 144
{
paul@333 145
    return _flags & L4RE_DS_F_W;
paul@115 146
}
paul@115 147
paul@0 148
/* Return a "send" flexpage for an access to 'offset' by positioning it relative
paul@0 149
   to 'hot_spot' for the receive flexpage window. */
paul@0 150
paul@86 151
SendFlexpage Flexpage::to_send(offset_t offset, offset_t hot_spot,
paul@121 152
                               map_flags_t flags, offset_t max_offset)
paul@0 153
{
paul@0 154
    /* The dataspace offset of the flexpage base is a multiple of the flexpage
paul@0 155
       size. */
paul@0 156
paul@0 157
    offset_t receive_base_offset = trunc(offset, size);
paul@0 158
paul@0 159
    /* The offset of the accessed page within the flexpage is constrained by the
paul@0 160
       current flexpage size. */
paul@0 161
paul@0 162
    offset_t page_offset = trunc(offset - receive_base_offset, PAGE_SIZE);
paul@0 163
paul@0 164
    /* The receive flexpage offset (hot spot) must be constrained to the
paul@0 165
       flexpage, both the size and the start. */
paul@0 166
paul@0 167
    offset_t receive_size;
paul@0 168
paul@0 169
    if (max_offset)
paul@23 170
    {
paul@23 171
        receive_size = trunc_multiple(max_offset - receive_base_offset, PAGE_SIZE);
paul@23 172
        receive_size = std::min(size, receive_size);
paul@23 173
    }
paul@0 174
    else
paul@0 175
        receive_size = size;
paul@0 176
paul@3 177
    if (!receive_size)
paul@86 178
        return SendFlexpage(base_addr, page_order(0), flags);
paul@3 179
paul@374 180
    /* Employ the page-aligned hot spot for compatibility with the page
paul@374 181
       offset, thus handling any non-aligned values sent in map requests. */
paul@374 182
paul@374 183
    offset_t hot_spot_page = trunc(hot_spot, PAGE_SIZE);
paul@374 184
    offset_t receive_page_offset = hot_spot_page % receive_size;
paul@0 185
paul@0 186
    while ((receive_size > PAGE_SIZE) && (receive_page_offset != page_offset))
paul@0 187
    {
paul@0 188
        receive_size /= 2;
paul@374 189
        receive_page_offset = hot_spot_page % receive_size;
paul@0 190
    }
paul@0 191
paul@0 192
    /* The flexpage base address is adjusted using the difference in page
paul@0 193
       offsets. Where the receive flexpage offset is constained further, the
paul@0 194
       base address will be raised to become closer to the accessed page. */
paul@0 195
paul@0 196
    offset_t adjustment = page_offset - receive_page_offset;
paul@0 197
paul@86 198
    return SendFlexpage(base_addr + adjustment, page_order(receive_size), flags);
paul@0 199
}
paul@0 200
paul@0 201
/* Return a representation of the flexpage for unmapping. */
paul@0 202
paul@0 203
SendFlexpage Flexpage::to_unmap()
paul@0 204
{
paul@450 205
    return SendFlexpage(base_addr, page_order(size), L4_FPAGE_RWX);
paul@0 206
}
paul@0 207
paul@332 208
/* Associate another flexpage with this flexpage. */
paul@332 209
paul@332 210
void Flexpage::associate(Flexpage *flexpage)
paul@332 211
{
paul@332 212
    derived.push_back(flexpage);
paul@332 213
}
paul@332 214
paul@554 215
/* Invalidate and unmap all derived flexpages. */
paul@554 216
paul@332 217
void Flexpage::disassociate()
paul@332 218
{
paul@554 219
    DerivedFlexpages::iterator it;
paul@554 220
paul@554 221
    for (it = derived.begin(); it != derived.end(); it++)
paul@554 222
        (*it)->invalidate();
paul@554 223
paul@332 224
    derived.clear();
paul@332 225
}
paul@332 226
paul@0 227
// vim: tabstop=4 expandtab shiftwidth=4