1// vi:set ft=cpp: -*- Mode: C++ -*- 2/* 3 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>, 4 * Alexander Warg <warg@os.inf.tu-dresden.de>, 5 * Torsten Frenzel <frenzel@os.inf.tu-dresden.de> 6 * economic rights: Technische Universität Dresden (Germany) 7 * 8 * This file is part of TUD:OS and distributed under the terms of the 9 * GNU General Public License 2. 10 * Please see the COPYING-GPL-2 file for details. 11 * 12 * As a special exception, you may use this file as part of a free software 13 * library without restriction. Specifically, if other files instantiate 14 * templates or use macros or inline functions from this file, or you compile 15 * this file and link it with other files to produce an executable, this 16 * file does not by itself cause the resulting executable to be covered by 17 * the GNU General Public License. This exception does not however 18 * invalidate any other reasons why the executable file might be covered by 19 * the GNU General Public License. 20 */ 21#pragma once 22 23#include <cstring> 24#include <cstddef> 25#include <l4/sys/types.h> 26#include <l4/cxx/list> 27#include <l4/cxx/minmax> 28#include <l4/re/dataspace> 29#include <l4/re/dataspace-sys.h> 30#include <l4/sys/cxx/ipc_legacy> 31 32namespace L4Re { namespace Util { 33 34/** 35 * Dataspace server class. 36 * 37 * The default implementation of the interface provides a continuous dataspace 38 * with contiguous pages. 39 */ 40class Dataspace_svr 41{ 42private: 43 typedef L4::Ipc::Gen_fpage<L4::Ipc::Snd_item> Snd_fpage; 44public: 45 L4_RPC_LEGACY_DISPATCH(L4Re::Dataspace); 46 47 typedef Snd_fpage::Map_type Map_type; 48 typedef Snd_fpage::Cacheopt Cache_type; 49 50 Dataspace_svr() noexcept 51 : _ds_start(0), _ds_size(0), _map_flags(Snd_fpage::Map), 52 _cache_flags(Snd_fpage::Cached) 53 {} 54 55 virtual ~Dataspace_svr() noexcept {} 56 57 /** 58 * Map a region of the dataspace 59 * 60 * \param offset Offset to start within data space 61 * \param local_addr Local address to map to. 62 * \param flags Dataspace flags, see #L4Re::Dataspace::F::Flags. 63 * \param min_addr Defines start of receive window. 64 * \param max_addr Defines end of receive window. 65 * \param[out] memory Send fpage to map 66 * 67 * \retval 0 Success 68 * \retval <0 Error 69 */ 70 int map(Dataspace::Offset offset, 71 Dataspace::Map_addr local_addr, 72 Dataspace::Flags flags, 73 Dataspace::Map_addr min_addr, 74 Dataspace::Map_addr max_addr, 75 L4::Ipc::Snd_fpage &memory); 76 77 /** 78 * A hook that is called as the first operation in each map 79 * request. 80 * \param offs Offs param to map 81 * \param flags Flags param to map 82 * \param min Min param to map 83 * \param max Max param to map 84 * \retval <0 Error and the map request will be aborted with that error. 85 * \retval >=0 Success 86 * 87 * \see map 88 */ 89 virtual int map_hook(Dataspace::Offset offs, 90 Dataspace::Flags flags, 91 Dataspace::Map_addr min, 92 Dataspace::Map_addr max) 93 { 94 (void)offs; (void)flags; (void)min; (void)max; 95 return 0; 96 } 97 98 /** 99 * Take a reference to this dataspace 100 * 101 * Default does nothing. 102 */ 103 virtual void take() noexcept 104 {} 105 106 /** 107 * Release a reference to this dataspace 108 * 109 * \return Number of references to the dataspace 110 * 111 * Default does nothing and returns always zero. 112 */ 113 virtual unsigned long release() noexcept 114 { return 0; } 115 116 /** 117 * Copy from src dataspace to this destination dataspace 118 * 119 * \param dst_offs Offset into the destination dataspace 120 * \param src_id Local id of the source dataspace 121 * \param src_offs Offset into the source dataspace 122 * \param size Number of bytes to copy 123 * 124 * \retval >=0 Number of bytes copied 125 * \retval <0 An error occured. The error code may depend on the 126 * implementation. 127 */ 128 virtual long copy(l4_addr_t dst_offs, l4_umword_t src_id, 129 l4_addr_t src_offs, unsigned long size) noexcept 130 { 131 (void)dst_offs; (void)src_id; (void)src_offs; (void)size; 132 return -L4_ENODEV; 133 } 134 135 /** 136 * Clear a region in the dataspace 137 * 138 * \param offs Start of the region 139 * \param size Size of the region 140 * 141 * \retval 0 Success 142 * \retval <0 Error 143 */ 144 virtual long clear(unsigned long offs, unsigned long size) const noexcept; 145 146 /** 147 * Allocate a region within a dataspace 148 * 149 * \param offset Offset in the dataspace, in bytes. 150 * \param size Size of the range, in bytes. 151 * \param access Access mode with which the memory backing the dataspace 152 * region should be allocated. 153 * 154 * \retval 0 Success 155 * \retval <0 Error 156 */ 157 virtual long allocate(l4_addr_t offset, l4_size_t size, unsigned access) noexcept 158 { (void)offset; (void)size; (void)access; return -L4_ENODEV; } 159 160 /** 161 * Define the size of the flexpage to map 162 * 163 * \return flexpage size 164 */ 165 virtual unsigned long page_shift() const noexcept 166 { return L4_LOG2_PAGESIZE; } 167 168 /** 169 * Return whether the dataspace is static 170 * 171 * \return True if dataspace is static 172 */ 173 virtual bool is_static() const noexcept 174 { return true; } 175 176 177 long op_map(L4Re::Dataspace::Rights rights, 178 L4Re::Dataspace::Offset offset, 179 L4Re::Dataspace::Map_addr spot, 180 L4Re::Dataspace::Flags flags, 181 L4::Ipc::Snd_fpage &fp) 182 { 183 auto rf = map_flags(rights); 184 185 if (!rf.w() && flags.w()) 186 return -L4_EPERM; 187 188 return map(offset, spot, flags & rf, 0, ~0, fp); 189 } 190 191 long op_allocate(L4Re::Dataspace::Rights rights, 192 L4Re::Dataspace::Offset offset, 193 L4Re::Dataspace::Size size) 194 { return allocate(offset, size, rights & 3); } 195 196 long op_copy_in(L4Re::Dataspace::Rights rights, 197 L4Re::Dataspace::Offset dst_offs, 198 L4::Ipc::Snd_fpage const &src_cap, 199 L4Re::Dataspace::Offset src_offs, 200 L4Re::Dataspace::Size sz) 201 { 202 if (!src_cap.id_received()) 203 return -L4_EINVAL; 204 205 if (!(rights & L4_CAP_FPAGE_W)) 206 return -L4_EACCESS; 207 208 if (sz == 0) 209 return L4_EOK; 210 211 return copy(dst_offs, src_cap.data(), src_offs, sz); 212 } 213 214 long op_info(L4Re::Dataspace::Rights rights, L4Re::Dataspace::Stats &s) 215 { 216 s.size = size(); 217 // only return writable if really writable 218 s.flags = Dataspace::Flags(0); 219 if (map_flags(rights).w()) 220 s.flags |= Dataspace::F::W; 221 return L4_EOK; 222 } 223 224 long op_clear(L4Re::Dataspace::Rights rights, 225 L4Re::Dataspace::Offset offset, 226 L4Re::Dataspace::Size size) 227 { 228 if (!map_flags(rights).w()) 229 return -L4_EACCESS; 230 231 return clear(offset, size); 232 } 233 234 235protected: 236 unsigned long size() const noexcept 237 { return _ds_size; } 238 unsigned long map_flags() const noexcept 239 { return _map_flags; } 240 unsigned long page_size() const noexcept 241 { return 1UL << page_shift(); } 242 unsigned long round_size() const noexcept 243 { return l4_round_size(size(), page_shift()); } 244 bool check_limit(l4_addr_t offset) const noexcept 245 { return offset < round_size(); } 246 247 L4Re::Dataspace::Flags 248 map_flags(L4Re::Dataspace::Rights rights = L4_CAP_FPAGE_W) const noexcept 249 { 250 auto f = (_rw_flags & L4Re::Dataspace::Flags(0x0f)) | L4Re::Dataspace::F::Caching_mask; 251 if (!(rights & L4_CAP_FPAGE_W)) 252 f &= ~L4Re::Dataspace::F::W; 253 254 return f; 255 } 256 257protected: 258 void size(unsigned long size) noexcept { _ds_size = size; } 259 260 l4_addr_t _ds_start; 261 l4_size_t _ds_size; 262 Map_type _map_flags; 263 Cache_type _cache_flags; 264 L4Re::Dataspace::Flags _rw_flags; 265}; 266 267}} 268