// vi:set ft=cpp: -*- Mode: C++ -*-
/**
 * \file
 * Pager and Io_pager C++ interface.
 */
/*
 * (c) 2014 Alexander Warg <alexander.warg@kernkonzept.com>
 *
 * This file is part of TUD:OS and distributed under the terms of the
 * GNU General Public License 2.
 * Please see the COPYING-GPL-2 file for details.
 *
 * As a special exception, you may use this file as part of a free software
 * library without restriction.  Specifically, if other files instantiate
 * templates or use macros or inline functions from this file, or you compile
 * this file and link it with other files to produce an executable, this
 * file does not by itself cause the resulting executable to be covered by
 * the GNU General Public License.  This exception does not however
 * invalidate any other reasons why the executable file might be covered by
 * the GNU General Public License.
 */

#pragma once

#include <l4/sys/capability>
#include <l4/sys/types.h>
#include <l4/sys/cxx/ipc_types>
#include <l4/sys/cxx/ipc_iface>

namespace L4 {

/**
 * Io_pager interface.
 *
 * \note This interface is IA32 specific.
 *
 * This class defines the interface for handling IO page faults. IO page
 * faults happen when a thread tries to access an IO port that it does not
 * currently have access to.
 *
 * Depending on the microkernel's implementation, IO page faults can be
 * handled in two ways.
 *
 * If the microkernel does not support IO page faults, this IO pagefault
 * interface is not used. Instead, the microkernel sends an exception IPC to
 * the thread's exception handler (L4::Exception), indicating a #GP (exception
 * number 13). The exception handler must consult the faulting instruction to
 * determine the cause of the exception. This is the default in Fiasco.OC.
 *
 * In contrast, if the microkernel supports IO page faults, the microkernel
 * will generate an IO page fault message and send it to the thread's page
 * fault handler (pager). The page fault handler can implement this interface
 * to handle the IO page faults.
 *
 * \note A program may use this mechanism to implement a lazy IO port access
 * scheme.
 *
 * \note The page fault and exception handlers are set with the
 * L4::Thread::control interface.
 */
class L4_EXPORT Io_pager :
  public Kobject_0t<Io_pager, L4_PROTO_IO_PAGE_FAULT>
{
public:
  /**
   * IO page fault protocol message.
   *
   * \param      io_pfa  Flex-page describing the faulting IO-port.
   * \param      pc      Faulting program counter.
   * \param      rwin    The receive window for a flex-page mapping.
   * \param[out] fp      Optional: flex-page descriptor to send to the task
   *                     raising the page fault.
   *
   * \return System call message tag; use l4_error() to check for errors.
   *
   * IO-port fault messages are usually generated by the kernel and an
   * IO-page-fault handler needs to be in place to handle such faults
   * and generate a reply, potentially filling in `fp`.
   */
  L4_INLINE_RPC(
      l4_msgtag_t, io_page_fault, (l4_fpage_t io_pfa, l4_umword_t pc,
                                   L4::Ipc::Rcv_fpage rwin,
                                   L4::Ipc::Opt<L4::Ipc::Snd_fpage &> fp));

  typedef L4::Typeid::Rpc_nocode<io_page_fault_t> Rpcs;
};

/**
 * Pager interface including the Io_pager interface.
 *
 * This class defines the interface for handling page fault IPC. If a thread
 * causes a page fault, the microkernel synthesises a page fault IPC message
 * and sends it to the thread's page fault handler (pager). The pager can then
 * handle the message, for example by establishing a suitable page mapping.
 *
 * The page fault handler is set with the L4::Thread::control interface.
 */
class L4_EXPORT Pager :
  public Kobject_t<Pager, Io_pager, L4_PROTO_PAGE_FAULT>
{
public:
  /**
   * Page-fault protocol message.
   *
   * \param      pfa     Faulting address including failure reason: bits [0:2].
   * \param      pc      Faulting program counter.
   * \param      rwin    Receive window for a flex-page mapping resolving the
   *                     page fault.
   * \param[out] fp      Optional: flex-page descriptor to send to the task
   *                     raising the page fault.
   *
   * \return System call message tag; use l4_error() to check for errors.
   *
   * Page-fault messages are usually generated by the kernel and need to
   * be handled by an appropriate handler function, potentially filling in `fp`
   * for the reply.
   *
   * `pfa` encoding is as shown:
   *
   * |       [63/31 .. 3]       | 2 | 1 | 0 |
   * |:------------------------:|:-:|:-:|:-:|
   * |            PFA           | X | W | r |
   *
   * - __PFA__ Bits 63/31..3 of `pfa` are the page fault address bits 63/31
   *           to 3, bits 2..0 are masked.
   * - __X__   Bit 2 of `pfa` if set, indicates a page fault during instruction
   *           fetch. Note, this bit is implementation-defined and might always
   *           be clear. Therefore, if this bit is clear it does not imply
   *           that the page fault is not due to an instruction fetch.
   * - __W__   Bit 1 of `pfa` is set to 1 for a page fault due to a write
   *           operation.
   * - __r__   Bit0: reserved, undefined.
   */
  L4_INLINE_RPC(
      l4_msgtag_t, page_fault, (l4_umword_t pfa, l4_umword_t pc,
                                L4::Ipc::Rcv_fpage rwin,
                                L4::Ipc::Opt<L4::Ipc::Snd_fpage &> fp));

  typedef L4::Typeid::Rpc_nocode<page_fault_t> Rpcs;
};

}