L4Re/departure

Annotated libfsserver/lib/generic/pager.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
 * Generic pager functionality.
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@554 22
#include <mem/ipc.h>
paul@554 23
paul@6 24
#include "dataspace_server.h"
paul@6 25
#include "pager.h"
paul@6 26
paul@342 27
#include "copied_page_mapper.h"
paul@342 28
#include "masked_page_mapper.h"
paul@332 29
paul@6 30
paul@6 31
paul@86 32
/* Initialise the pager with a page mapper and the given flags controlling
paul@86 33
   access to a file. */
paul@86 34
paul@346 35
Pager::Pager(GenericPageMapper *mapper, map_flags_t map_flags)
paul@342 36
: _start(0), _size(0),
paul@342 37
  _mapper(mapper), _mapper_base(mapper), _mapper_masked(NULL),
paul@342 38
  _mapper_copied(NULL),
paul@346 39
  _map_flags(map_flags)
paul@6 40
{
paul@6 41
}
paul@6 42
paul@79 43
/* Close the pager. */
paul@79 44
paul@6 45
void Pager::close()
paul@6 46
{
paul@342 47
    if (_mapper_masked != NULL)
paul@342 48
    {
paul@342 49
        delete _mapper_masked;
paul@342 50
        _mapper_masked = NULL;
paul@342 51
    }
paul@342 52
paul@342 53
    if (_mapper_copied != NULL)
paul@342 54
    {
paul@342 55
        delete _mapper_copied;
paul@342 56
        _mapper_copied = NULL;
paul@342 57
    }
paul@6 58
}
paul@6 59
paul@53 60
/* Flush data to the file. */
paul@53 61
paul@53 62
long Pager::flush(offset_t populated_size, offset_t *size)
paul@53 63
{
paul@55 64
    _mapper->flush_all(_start, populated_size);
paul@53 65
paul@55 66
    *size = _mapper->get_data_size();
paul@55 67
    return L4_EOK;
paul@55 68
}
paul@53 69
paul@402 70
/* Resize the file. This will only resize the underlying file where masking and
paul@402 71
   copy-on-write mapping is not being performed. */
paul@53 72
paul@55 73
long Pager::resize(offset_t *size)
paul@55 74
{
paul@55 75
    _mapper->set_data_size(*size);
paul@55 76
paul@55 77
    *size = _mapper->get_data_size();
paul@53 78
    return L4_EOK;
paul@53 79
}
paul@53 80
paul@7 81
/* Expose a region of the file. */
paul@7 82
paul@339 83
long Pager::mmap(offset_t position, offset_t length,
paul@339 84
                 offset_t start_visible, offset_t end_visible,
paul@332 85
                 offset_t *start_pos, offset_t *end_pos, offset_t *size)
paul@6 86
{
paul@90 87
    /* Define region characteristics. */
paul@90 88
paul@7 89
    _start = trunc(position, PAGE_SIZE);
paul@7 90
    _size = round(position + length, PAGE_SIZE) - _start;
paul@6 91
paul@402 92
    /* Return the start and end positions plus file size. */
paul@90 93
paul@7 94
    *start_pos = _start;
paul@7 95
    *end_pos = _start + _size;
paul@342 96
    *size = _mapper_base->get_data_size();
paul@7 97
paul@332 98
    /* Permit masking of mapped regions. */
paul@332 99
paul@342 100
    if ((start_visible || end_visible) &&
paul@342 101
        ((*start_pos != start_visible) || (*end_pos != end_visible)))
paul@332 102
    {
paul@342 103
        /* Introduce the masked page and copied page mappers. */
paul@342 104
paul@342 105
        _mapper_masked = new MaskedPageMapper(_mapper_base, start_visible, end_visible);
paul@342 106
        _mapper_copied = new CopiedPageMapper(_mapper_masked);
paul@342 107
        _mapper = _mapper_copied;
paul@332 108
    }
paul@332 109
    else
paul@342 110
        _mapper = _mapper_base;
paul@332 111
paul@7 112
    return L4_EOK;
paul@6 113
}
paul@6 114
paul@6 115
/* Map a flexpage corresponding to the dataspace 'offset' involving a 'hot_spot'
paul@6 116
   (flexpage offset). */
paul@6 117
paul@410 118
long Pager::map(offset_t offset, map_address_t hot_spot, map_flags_t map_flags,
paul@90 119
                l4_snd_fpage_t *region)
paul@6 120
{
paul@6 121
    offset_t file_offset = _start + offset;
paul@6 122
    offset_t max_offset = _start + _size;
paul@87 123
paul@332 124
    /* Prevent access beyond that defined by the pager.
paul@332 125
       NOTE: Permitting executable requests here. This needs to be configured
paul@332 126
             when opening the pager or by another means. */
paul@87 127
paul@346 128
    if (map_flags & (~(_map_flags | L4RE_DS_F_X)))
paul@87 129
        return -L4_EACCESS;
paul@87 130
paul@342 131
    /* Obtain a flexpage from the page mapper. */
paul@6 132
paul@346 133
    Flexpage *flexpage = _mapper->get(file_offset, map_flags);
paul@332 134
paul@6 135
    /* Issue the flexpage via the IPC system. */
paul@6 136
paul@342 137
    long err = ipc_prepare_flexpage(flexpage, file_offset, max_offset,
paul@346 138
                                    hot_spot, map_flags, region);
paul@6 139
paul@37 140
    if (!err)
paul@87 141
        err = complete_Dataspace_map(*region);
paul@6 142
paul@342 143
    /* After the obtained flexpage is issued, it is queued for future reuse, if
paul@342 144
       appropriate for the mapper concerned. */
paul@6 145
paul@342 146
    _mapper->queue(flexpage);
paul@6 147
paul@37 148
    if (err)
paul@87 149
        return err;
paul@37 150
paul@6 151
    return IPC_MESSAGE_SENT;
paul@6 152
}
paul@6 153
paul@6 154
/* Return the total size of the data. */
paul@6 155
paul@6 156
offset_t Pager::get_data_size()
paul@6 157
{
paul@6 158
    return _mapper->get_data_size();
paul@6 159
}
paul@6 160
paul@6 161
// vim: tabstop=4 expandtab shiftwidth=4