1// -*- Mode: C++ -*- 2// vim:ft=cpp 3/** 4 * \file 5 * \brief Region mapper interface 6 */ 7/* 8 * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>, 9 * Alexander Warg <warg@os.inf.tu-dresden.de>, 10 * Björn Döbel <doebel@os.inf.tu-dresden.de>, 11 * Torsten Frenzel <frenzel@os.inf.tu-dresden.de> 12 * economic rights: Technische Universität Dresden (Germany) 13 * 14 * This file is part of TUD:OS and distributed under the terms of the 15 * GNU General Public License 2. 16 * Please see the COPYING-GPL-2 file for details. 17 * 18 * As a special exception, you may use this file as part of a free software 19 * library without restriction. Specifically, if other files instantiate 20 * templates or use macros or inline functions from this file, or you compile 21 * this file and link it with other files to produce an executable, this 22 * file does not by itself cause the resulting executable to be covered by 23 * the GNU General Public License. This exception does not however 24 * invalidate any other reasons why the executable file might be covered by 25 * the GNU General Public License. 26 */ 27#pragma once 28 29#include <l4/sys/types.h> 30#include <l4/sys/l4int.h> 31#include <l4/sys/capability> 32#include <l4/re/protocols.h> 33#include <l4/sys/pager> 34#include <l4/sys/cxx/ipc_iface> 35#include <l4/sys/cxx/ipc_ret_array> 36#include <l4/sys/cxx/types> 37#include <l4/re/consts> 38#include <l4/re/dataspace> 39 40namespace L4Re { 41 42/** 43 * \defgroup api_l4re_rm Region map API 44 * \ingroup api_l4re 45 * \brief Virtual address-space management. 46 * 47 * A region map object implements two protocols. The first protocol is the 48 * kernel page-fault protocol, to resolve page faults for threads running in an 49 * L4 task. The second protocol is the region map protocol itself, which allows 50 * managing the virtual memory address space of an L4 task. 51 * 52 * There are two basic concepts provided by the region map abstraction: 53 * - **Areas** are reserved ranges in the virtual memory address space. 54 * - **Regions** are areas that are backed by (part of) a dataspace, i.e. 55 * accessing them results in access to the physical memory the dataspace 56 * manages. 57 * 58 * Areas can be reserved for special use or for attaching a dataspace at a later 59 * time. When attaching a dataspace, the user can instruct the region map to 60 * search for an appropriate range to attach to. Regions are skipped in this 61 * search since they already have dataspaces attached to them, and areas are 62 * skipped because they are reserved. 63 * 64 * When a region map receives a page fault IPC, the region map will check if the 65 * faulting virtual address lies in a region. If yes, it will answer the page 66 * fault IPC with a mapping from the backing dataspace. If not, an error is 67 * returned. 68 * 69 * \see L4Re::Dataspace, L4Re::Rm, 70 * \see \ref l4re_concepts_ds_rm 71 */ 72 73/** 74 * \brief Region map 75 * \headerfile rm l4/re/rm 76 * \ingroup api_l4re_rm 77 * 78 * \see \link api_l4re_rm Region map API \endlink. 79 */ 80class L4_EXPORT Rm : 81 public L4::Kobject_t<Rm, L4::Pager, L4RE_PROTO_RM, 82 L4::Type_info::Demand_t<1> > 83{ 84public: 85 typedef L4Re::Dataspace::Offset Offset; 86 87 /// Result values for detach operation. 88 enum Detach_result 89 { 90 Detached_ds = 0, ///< Detached data sapce. 91 Kept_ds = 1, ///< Kept data space. 92 Split_ds = 2, ///< Splitted data space, and done. 93 Detach_result_mask = 3, 94 95 Detach_again = 4, ///< Detached data space, more to do. 96 }; 97 98 99 enum Region_flag_shifts 100 { 101 /// Start of Rm cache bits 102 Caching_shift = Dataspace::F::Caching_shift, 103 }; 104 105 /** Rm flags definitions. */ 106 struct F 107 { 108 /// Flags for attach operation. 109 enum Attach_flags : l4_uint32_t 110 { 111 /// Search for a suitable address range. 112 Search_addr = 0x20000, 113 /// Search only in area, or map into area. 114 In_area = 0x40000, 115 /// Eagerly map the attached data space in. 116 Eager_map = 0x80000, 117 /// Mask of all attach flags. 118 Attach_mask = 0xf0000, 119 }; 120 121 L4_TYPES_FLAGS_OPS_DEF(Attach_flags); 122 123 enum Region_flags : l4_uint16_t 124 { 125 /// Region rights 126 Rights_mask = 0x0f, 127 R = Dataspace::F::R, 128 W = Dataspace::F::W, 129 X = Dataspace::F::X, 130 RW = Dataspace::F::RW, 131 RX = Dataspace::F::RX, 132 RWX = Dataspace::F::RWX, 133 134 /// Free the portion of the data space after detach 135 Detach_free = 0x200, 136 /// Region has a pager 137 Pager = 0x400, 138 /// Region is reserved (blocked) 139 Reserved = 0x800, 140 141 142 /// Mask of all Rm cache bits 143 Caching_mask = Dataspace::F::Caching_mask, 144 /// Cache bits for normal cacheable memory 145 Cache_normal = Dataspace::F::Normal, 146 /// Cache bits for buffered (write combining) memory 147 Cache_buffered = Dataspace::F::Bufferable, 148 /// Cache bits for uncached memory 149 Cache_uncached = Dataspace::F::Uncacheable, 150 151 /// Mask for all bits for cache options and rights. 152 Ds_map_mask = 0xff, 153 154 /// Mask of all region flags 155 Region_flags_mask = 0xffff, 156 }; 157 158 L4_TYPES_FLAGS_OPS_DEF(Region_flags); 159 160 friend constexpr Dataspace::Flags map_flags(Region_flags rf) 161 { 162 return Dataspace::Flags((l4_uint16_t)rf & Ds_map_mask); 163 } 164 165 struct Flags : L4::Types::Flags_ops_t<Flags> 166 { 167 l4_uint32_t raw; 168 Flags() = default; 169 explicit constexpr Flags(l4_uint32_t f) : raw(f) {} 170 constexpr Flags(Attach_flags rf) : raw((l4_uint32_t)rf) {} 171 constexpr Flags(Region_flags rf) : raw((l4_uint32_t)rf) {} 172 173 friend constexpr Dataspace::Flags map_flags(Flags f) 174 { 175 return Dataspace::Flags(f.raw & Ds_map_mask); 176 } 177 178 constexpr Region_flags region_flags() const 179 { 180 return Region_flags(raw & Region_flags_mask); 181 } 182 183 constexpr Attach_flags attach_flags() const 184 { 185 return Attach_flags(raw & Attach_mask); 186 } 187 188 constexpr bool r() const { return raw & L4_FPAGE_RO; } 189 constexpr bool w() const { return raw & L4_FPAGE_W; } 190 constexpr bool x() const { return raw & L4_FPAGE_X; } 191 constexpr unsigned cap_rights() const 192 { return w() ? L4_CAP_FPAGE_RW : L4_CAP_FPAGE_RO; } 193 }; 194 195 friend constexpr Flags operator | (Region_flags l, Attach_flags r) 196 { return Flags(l) | Flags(r); } 197 198 friend constexpr Flags operator | (Attach_flags l, Region_flags r) 199 { return Flags(l) | Flags(r); } 200 }; 201 202 using Attach_flags = F::Attach_flags; 203 using Region_flags = F::Region_flags; 204 using Flags = F::Flags; 205 206 /// Flags for detach operation 207 enum Detach_flags 208 { 209 /** 210 * \brief Do an unmap of the exact region given. 211 * \internal 212 * 213 * This flag is useful for _detach(). 214 * 215 * Using this mode for detach, unmaps the exact region given. 216 * This has the effect that parts of regions may stay in the address space. 217 */ 218 Detach_exact = 1, 219 /** 220 * \brief Do an unmap of all overlapping regions. 221 * \internal 222 * 223 * This flag is useful for _detach(). 224 * 225 * Using this mode for detach, unmaps all regions that overlap with 226 * the given region. 227 */ 228 Detach_overlap = 2, 229 230 /** 231 * \brief Do not free the detached data space, ignore the F::Detach_free 232 * \internal 233 * 234 * This flag is useful for _detach(). 235 * 236 */ 237 Detach_keep = 4, 238 }; 239 240 /** 241 * \brief Reserve the given area in the region map. 242 * \param[in,out] start The virtual start address of the area to reserve. 243 * Returns the start address of the area. 244 * \param size The size of the area to reserve (in bytes). 245 * \param flags Flags for the reserved area (see 246 * #L4Re::Rm::F::Region_flags and 247 * #L4Re::Rm::F::Attach_flags). 248 * \param align Alignment of area if searched as bits (log2 value). 249 * \retval 0 Success 250 * \retval -L4_EADDRNOTAVAIL The given area cannot be reserved. 251 * \retval <0 IPC errors 252 * 253 * This function reserves an area within the virtual address space managed 254 * by the region map. There are two kinds of areas available: 255 * - Reserved areas (\a flags = F::Reserved), where no data spaces can be 256 * attached 257 * - Special purpose areas (\a flags = 0), where data spaces can be attached 258 * to the area via the F::In_area flag and a start address within the area 259 * itself. 260 * 261 * \note When searching for a free place in the virtual address space 262 * (with \a flags = F::Search_addr), the space between \a start and the end of 263 * the virtual address space is searched. 264 */ 265 long reserve_area(l4_addr_t *start, unsigned long size, 266 Flags flags = Flags(0), 267 unsigned char align = L4_PAGESHIFT) const noexcept 268 { return reserve_area_t::call(c(), start, size, flags, align); } 269 270 L4_RPC_NF(long, reserve_area, (L4::Ipc::In_out<l4_addr_t *> start, 271 unsigned long size, 272 Flags flags, 273 unsigned char align)); 274 275 /** 276 * \brief Reserve the given area in the region map. 277 * \param[in,out] start The virtual start address of the area to reserve. 278 * Returns the start address of the area. 279 * \param size The size of the area to reserve (in bytes). 280 * \param flags Flags for the reserved area (see F::Region_flags and 281 * F::Attach_flags). 282 * \param align Alignment of area if searched as bits (log2 value). 283 * \retval 0 Success 284 * \retval -L4_EADDRNOTAVAIL The given area cannot be reserved. 285 * \retval <0 IPC errors 286 * 287 * For more information, please refer to the analogous function 288 * \see L4Re::Rm::reserve_area. 289 */ 290 template< typename T > 291 long reserve_area(T **start, unsigned long size, 292 Flags flags = Flags(0), 293 unsigned char align = L4_PAGESHIFT) const noexcept 294 { return reserve_area_t::call(c(), (l4_addr_t*)start, size, flags, align); } 295 296 /** 297 * \brief Free an area from the region map. 298 * 299 * \param addr An address within the area to free. 300 * \retval 0 Success 301 * \retval -L4_ENOENT No area found. 302 * \retval <0 IPC errors 303 * 304 * \note The data spaces that are attached to that area are not detached by 305 * this operation. 306 * \see reserve_area() for more information about areas. 307 */ 308 L4_RPC(long, free_area, (l4_addr_t addr)); 309 310 L4_RPC_NF(long, attach, (L4::Ipc::In_out<l4_addr_t *> start, 311 unsigned long size, Flags flags, 312 L4::Ipc::Opt<L4::Ipc::Cap<Dataspace> > mem, 313 Offset offs, unsigned char align, 314 L4::Ipc::Opt<l4_cap_idx_t> client_cap)); 315 316 L4_RPC_NF(long, detach, (l4_addr_t addr, unsigned long size, unsigned flags, 317 l4_addr_t &start, l4_addr_t &rsize, 318 l4_cap_idx_t &mem_cap)); 319 320 /** 321 * \brief Attach a data space to a region. 322 * 323 * \param[in,out] start Virtual start address where the region manager 324 * shall attach the data space. Will be rounded down to 325 * the nearest start of a page. 326 * If #L4Re::Rm::F::Search_addr is given this value is 327 * used as the start address to search for a free 328 * virtual memory region and the resulting address is 329 * returned here. 330 * If #L4Re::Rm::F::In_area is given the value is used 331 * as a selector for the area (see 332 * #L4Re::Rm::reserve_area) to attach the data space 333 * to. 334 * \param size Size of the data space to attach (in bytes). Will be 335 * rounded up to the nearest multiple of the page size. 336 * \param flags The flags control how and with which rights the 337 * dataspace is attached to the region. See 338 * #L4Re::Rm::F::Attach_flags and 339 * #L4Re::Rm::F::Region_flags. The caller must specify 340 * the desired rights of the attached region 341 * explicitly. The default set of rights is empty. If 342 * the `F::Eager_map` flag is set this function may 343 * also return L4Re::Dataspace::map error codes if the 344 * mapping fails. 345 * \param mem Data space. 346 * \param offs Offset into the data space to use. 347 * \param align Alignment of the virtual region, log2-size, default: 348 * a page (#L4_PAGESHIFT). This is only meaningful if 349 * the #L4Re::Rm::F::Search_addr flag is used. 350 * 351 * \retval 0 Success 352 * \retval -L4_ENOENT No area could be found (see 353 * #L4Re::Rm::F::In_area) 354 * \retval -L4_EPERM Operation not allowed. 355 * \retval -L4_EINVAL 356 * \retval -L4_EADDRNOTAVAIL The given address is not available. 357 * \retval <0 IPC errors 358 * 359 * Makes the whole or parts of a data space visible in the virtual memory 360 * of the corresponding task. The corresponding region in the virtual 361 * address space is backed with the contents of the dataspace. 362 * 363 * \note When searching for a free place in the virtual address space, 364 * the space between \a start and the end of the virtual address space is 365 * searched. 366 * 367 * \note There is no region object created, instead the region is 368 * defined by a virtual address within this range (see #L4Re::Rm::find). 369 */ 370 long attach(l4_addr_t *start, unsigned long size, Flags flags, 371 L4::Ipc::Cap<Dataspace> mem, Offset offs = 0, 372 unsigned char align = L4_PAGESHIFT) const noexcept; 373 374 /** 375 * \copydoc L4Re::Rm::attach 376 */ 377 template< typename T > 378 long attach(T **start, unsigned long size, Flags flags, 379 L4::Ipc::Cap<Dataspace> mem, Offset offs = 0, 380 unsigned char align = L4_PAGESHIFT) const noexcept 381 { 382 union X { l4_addr_t a; T* t; }; 383 X *x = reinterpret_cast<X*>(start); 384 return attach(&x->a, size, flags, mem, offs, align); 385 } 386 387#if __cplusplus >= 201103L 388 template< typename T > 389 class Unique_region 390 { 391 private: 392 T _addr; 393 L4::Cap<Rm> _rm; 394 395 public: 396 Unique_region(Unique_region const &) = delete; 397 Unique_region &operator = (Unique_region const &) = delete; 398 399 Unique_region() noexcept 400 : _addr(0), _rm(L4::Cap<Rm>::Invalid) {} 401 402 explicit Unique_region(T addr) noexcept 403 : _addr(addr), _rm(L4::Cap<Rm>::Invalid) {} 404 405 Unique_region(T addr, L4::Cap<Rm> const &rm) noexcept 406 : _addr(addr), _rm(rm) {} 407 408 Unique_region(Unique_region &&o) noexcept : _addr(o.get()), _rm(o._rm) 409 { o.release(); } 410 411 Unique_region &operator = (Unique_region &&o) noexcept 412 { 413 if (&o != this) 414 { 415 if (_rm.is_valid()) 416 _rm->detach(l4_addr_t(_addr), 0); 417 _rm = o._rm; 418 _addr = o.release(); 419 } 420 return *this; 421 } 422 423 ~Unique_region() noexcept 424 { 425 if (_rm.is_valid()) 426 _rm->detach(l4_addr_t(_addr), 0); 427 } 428 429 T get() const noexcept 430 { return _addr; } 431 432 T release() noexcept 433 { 434 _rm = L4::Cap<Rm>::Invalid; 435 return _addr; 436 } 437 438 void reset(T addr, L4::Cap<Rm> const &rm) noexcept 439 { 440 if (_rm.is_valid()) 441 _rm->detach(l4_addr_t(_addr), 0); 442 443 _rm = rm; 444 _addr = addr; 445 } 446 447 void reset() noexcept 448 { reset(0, L4::Cap<Rm>::Invalid); } 449 450 bool is_valid() const noexcept 451 { return _rm.is_valid(); } 452 453 /** \brief Dereference the pointer. */ 454 T operator * () const noexcept { return _addr; } 455 456 /** \brief Member access for the object. */ 457 T operator -> () const noexcept { return _addr; } 458 }; 459 460 template< typename T > 461 long attach(Unique_region<T> *start, unsigned long size, Flags flags, 462 L4::Ipc::Cap<Dataspace> mem, Offset offs = 0, 463 unsigned char align = L4_PAGESHIFT) const noexcept 464 { 465 l4_addr_t addr = (l4_addr_t)start->get(); 466 467 long res = attach(&addr, size, flags, mem, offs, align); 468 if (res < 0) 469 return res; 470 471 start->reset((T)addr, L4::Cap<Rm>(cap())); 472 return res; 473 } 474#endif 475 476 /** 477 * \brief Detach a region from the address space. 478 * 479 * \param addr Virtual address of region, any address within the 480 * region is valid. 481 * \param[out] mem Dataspace that is affected. Give 0 if not interested. 482 * \param task This argument specifies the task where the pages are 483 * unmapped. Provide L4::Cap<L4::Task>::Invalid for none. 484 * The default is the current task. 485 * 486 * \retval #Detach_result On success. 487 * \retval -L4_ENOENT No region found. 488 * \retval <0 IPC errors 489 * 490 * Frees a region in the virtual address space given by addr (address type). 491 * The corresponding part of the address space is now available again. 492 */ 493 int detach(l4_addr_t addr, L4::Cap<Dataspace> *mem, 494 L4::Cap<L4::Task> const &task = This_task) const noexcept; 495 496 /** 497 * \copydoc L4Re::Rm::detach 498 */ 499 int detach(void *addr, L4::Cap<Dataspace> *mem, 500 L4::Cap<L4::Task> const &task = This_task) const noexcept; 501 502 /** 503 * \brief Detach all regions of the specified interval. 504 * 505 * \param start Start of area to detach, must be within region. 506 * \param size Size of of area to detach (in bytes). 507 * \param[out] mem Dataspace that is affected. Give 0 if not interested. 508 * \param task This argument specifies the task where the pages are 509 * unmapped. Provide L4::Cap<L4::Task>::Invalid for none. 510 * The default is the current task. 511 * 512 * \retval #Detach_result On success. 513 * \retval -L4_ENOENT No region found. 514 * \retval <0 IPC errors 515 * 516 * Frees all regions within the interval given by start and size. If a 517 * region overlaps the start or the end of the interval this region is only 518 * detached partly. If the interval is within one region the original region 519 * is split up into two separate regions. 520 */ 521 int detach(l4_addr_t start, unsigned long size, L4::Cap<Dataspace> *mem, 522 L4::Cap<L4::Task> const &task) const noexcept; 523 524 /** 525 * \brief Find a region given an address and size. 526 * 527 * \param[in,out] addr Address to look for. Returns the start address of the 528 * found region. 529 * \param[in,out] size Size of the area to look for (in bytes). Returns the 530 * size of the found region (in bytes). 531 * \param[out] offset Offset at the beginning of the region within the 532 * associated dataspace. 533 * \param[out] flags Region flags, see F::Region_flags (and F::In_area). 534 * \param[out] m Associated dataspace or paging service. 535 * 536 * \retval 0 Success 537 * \retval -L4_EPERM Operation not allowed. 538 * \retval -L4_ENOENT No region found. 539 * \retval <0 IPC errors 540 * 541 * This function returns the properties of the region that contains the area 542 * described by the addr and size parameter. If no such region is found but 543 * a reserved area, the area is returned and F::In_area is set in `flags`. 544 * Note, in the case of an area the `offset` and `m` return values are 545 * invalid. 546 * 547 * \verbatim 548 size-out 549 / \ 550 / \ 551 addr-out \ 552 ^________________\ 553 ------------|----------------|------------------ 554 | | Region | Dataspace | 555 | |_______|___|____| | 556 ------------|-------|---|----------------------- 557 \ / |\ / 558 \ / | |> size-in 559 offset-out | 560 |> addr-in 561 \endverbatim 562 * 563 * 564 * \note The value of the size input parameter should be 1 to assure that a 565 * region can be determined unambiguously. 566 * 567 */ 568 int find(l4_addr_t *addr, unsigned long *size, Offset *offset, 569 L4Re::Rm::Flags *flags, L4::Cap<Dataspace> *m) noexcept 570 { return find_t::call(c(), addr, size, flags, offset, m); } 571 572 L4_RPC_NF(int, find, (L4::Ipc::In_out<l4_addr_t *> addr, 573 L4::Ipc::In_out<unsigned long *> size, 574 L4Re::Rm::Flags *flags, Offset *offset, 575 L4::Ipc::As_value<L4::Cap<Dataspace> > *m)); 576 577 /** 578 * A range of virtual addresses. 579 */ 580 struct Range 581 { 582 /// First address of the range. 583 l4_addr_t start; 584 /// Last address of the range. 585 l4_addr_t end; 586 }; 587 588 /** 589 * A region is a range of virtual addresses which is backed by a dataspace. 590 * 591 * \see api_l4re_rm 592 */ 593 using Region = Range; 594 595 /** 596 * An area is a range of virtual addresses which is reserved, 597 * see L4Re::Rm::reserve_area(). 598 * 599 * \see api_l4re_rm 600 */ 601 using Area = Range; 602 603 /** 604 * Return the list of regions whose starting addresses are higher or equal to 605 * `start` in the address space managed by this region map. 606 * 607 * \param start Virtual address from where to start searching. 608 * \param[out] regions List of regions found in this region map. 609 * 610 * \retval >=0 Number of returned regions in the `regions` array. 611 * \retval <0 IPC errors 612 * 613 * \note The returned list of regions might not be complete and the caller 614 * shall use the function repeatedly with a start address one larger 615 * that the end address of the last region from the previous call. 616 */ 617 L4_RPC(long, get_regions, (l4_addr_t start, L4::Ipc::Ret_array<Range> regions)); 618 619 /** 620 * Return the list of areas whose starting addresses are higher or equal to 621 * `start` in the address space managed by this region map. 622 * 623 * \param start Virtual address from where to start searching. 624 * \param[out] areas List of areas found in this region map. 625 * 626 * \retval >=0 Number of returned areas in the `areas` array. 627 * \retval <0 IPC errors 628 * 629 * \note The returned list of areas might not be complete and the caller 630 * shall use the function repeatedly with a start address one larger 631 * than the end address of the last area from the previous call. 632 */ 633 634 L4_RPC(long, get_areas, (l4_addr_t start, L4::Ipc::Ret_array<Range> areas)); 635 636 int detach(l4_addr_t start, unsigned long size, L4::Cap<Dataspace> *mem, 637 L4::Cap<L4::Task> task, unsigned flags) const noexcept; 638 639 typedef L4::Typeid::Rpcs<attach_t, detach_t, find_t, 640 reserve_area_t, free_area_t, 641 get_regions_t, get_areas_t> Rpcs; 642}; 643 644 645inline int 646Rm::detach(l4_addr_t addr, L4::Cap<Dataspace> *mem, 647 L4::Cap<L4::Task> const &task) const noexcept 648{ return detach(addr, 1, mem, task, Detach_overlap); } 649 650inline int 651Rm::detach(void *addr, L4::Cap<Dataspace> *mem, 652 L4::Cap<L4::Task> const &task) const noexcept 653{ return detach((l4_addr_t)addr, 1, mem, task, Detach_overlap); } 654 655inline int 656Rm::detach(l4_addr_t addr, unsigned long size, L4::Cap<Dataspace> *mem, 657 L4::Cap<L4::Task> const &task) const noexcept 658{ return detach(addr, size, mem, task, Detach_exact); } 659 660}; 661