1  /*
   2   * \brief  CPU (processing time) manager session interface
   3   * \author Christian Helmuth
   4   * \date   2006-06-27
   5   *
   6   * :Question:
   7   *
   8   *   Why are thread operations not methods of the thread but
   9   *   methods of the CPU session?
  10   *
  11   * :Answer:
  12   *
  13   *   This enables the CPU session to impose policies on thread
  14   *   operations. These policies are based on the session
  15   *   construction arguments. If thread operations would be
  16   *   provided as thread methods, Thread would need to consult
  17   *   its container object (its CPU session) about the authorization
  18   *   of each operation and, thereby, would introduce a circular
  19   *   dependency between CPU session and Thread.
  20   */

  21  
  22  /*
  23   * Copyright (C) 2006-2013 Genode Labs GmbH
  24   *
  25   * This file is part of the Genode OS framework, which is distributed
  26   * under the terms of the GNU General Public License version 2.
  27   */

  28  
  29  #ifndef _INCLUDE__CPU_SESSION__CPU_SESSION_H_
  30  #define _INCLUDE__CPU_SESSION__CPU_SESSION_H_
  31  
  32  #include <base/stdint.h>
  33  #include <base/exception.h>
  34  #include <base/thread_state.h>
  35  #include <base/rpc_args.h>
  36  #include <base/signal.h>
  37  #include <base/affinity.h>
  38  #include <thread/capability.h>
  39  #include <pager/capability.h>
  40  #include <session/session.h>
  41  #include <ram_session/ram_session.h>
  42  
  43  namespace Genode {
  44  
  45     struct Cpu_session : Session
  46     {
  47           /*********************
  48            ** Exception types **
  49            *********************/

  50  
  51           class Thread_creation_failed : public Exception { };
  52           class State_access_failed : public Exception { };
  53           class Out_of_metadata : public Exception { };
  54  
  55           static const char *service_name() { return "CPU"; }
  56  
  57           enum { THREAD_NAME_LEN = 48 };
  58           enum { PRIORITY_LIMIT = << 16 };
  59           enum { DEFAULT_PRIORITY = 0 };
  60  
  61           typedef Rpc_in_buffer<THREAD_NAME_LEN> Name;
  62  
  63           virtual ~Cpu_session() { }
  64  
  65           /**
  66            * Create a new thread
  67            *
  68            * \param   name  name for the thread
  69            * \param   utcb  Base of the UTCB that will be used by the thread
  70            * \return        capability representing the new thread
  71            * \throw         Thread_creation_failed
  72            * \throw         Out_of_metadata
  73            */

  74           virtual Thread_capability create_thread(Name const &name,
  75                                                   addr_t utcb = 0)
 = 0;

  76  
  77           /**
  78            * Get dataspace of the UTCB that is used by the specified thread
  79            */

  80           virtual Ram_dataspace_capability utcb(Thread_capability thread) = 0;

  81  
  82           /**
  83            * Kill an existing thread
  84            *
  85            * \param thread  capability of the thread to kill
  86            */

  87           virtual void kill_thread(Thread_capability thread) = 0;

  88  
  89           /**
  90            * Set paging capabilities for thread
  91            *
  92            * \param thread  thread to configure
  93            * \param pager   capability used to propagate page faults
  94            */

  95           virtual int set_pager(Thread_capability thread,
  96                                 Pager_capability  pager)
 = 0;

  97  
  98           /**
  99            * Modify instruction and stack pointer of thread - start the
 100            * thread
 101            *
 102            * \param thread  thread to start
 103            * \param ip      initial instruction pointer
 104            * \param sp      initial stack pointer
 105            *
 106            * \return        0 on success
 107            */

 108           virtual int start(Thread_capability thread, addr_t ip, addr_t sp) = 0;

 109  
 110           /**
 111            * Pause the specified thread
 112            *
 113            * After calling this function, the execution of the thread can be
 114            * continued by calling `resume`.
 115            */

 116           virtual void pause(Thread_capability thread) = 0;

 117  
 118           /**
 119            * Resume the specified thread
 120            */

 121           virtual void resume(Thread_capability thread) = 0;

 122  
 123           /**
 124            * Cancel a currently blocking operation
 125            *
 126            * \param thread  thread to unblock
 127            */

 128           virtual void cancel_blocking(Thread_capability thread) = 0;

 129  
 130           /**
 131            * Get the current state of a specific thread
 132            *
 133            * \param thread  targeted thread
 134            * \return        state of the targeted thread
 135            * \throw         State_access_failed
 136            */

 137           virtual Thread_state state(Thread_capability thread) = 0;

 138  
 139           /**
 140            * Override the current state of a specific thread
 141            *
 142            * \param thread  targeted thread
 143            * \param state   state that shall be applied
 144            * \throw         State_access_failed
 145            */

 146           virtual void state(Thread_capability thread,
 147                              Thread_state const &state)
 = 0;

 148  
 149           /**
 150            * Register signal handler for exceptions of the specified thread
 151            *
 152            * If `thread` is an invalid capability, the default exception
 153            * handler for the CPU session is set. This handler is used for
 154            * all threads that have no explicitly installed exception handler.
 155            * The new default signal handler will take effect for threads
 156            * created after the call.
 157            *
 158            * On Linux, this exception is delivered when the process triggers
 159            * a SIGCHLD. On other platforms, this exception is delivered on
 160            * the occurrence of CPU exceptions such as division by zero.
 161            */

 162           virtual void exception_handler(Thread_capability         thread,
 163                                          Signal_context_capability handler)
 = 0;

 164  
 165           /**
 166            * Enable/disable single stepping for specified thread.
 167            *
 168            * Since this functions is currently supported by a small number of
 169            * platforms, we provide a default implementation
 170            *
 171            * \param thread  thread to set into single step mode
 172            * \param enable  true = enable single-step mode; false = disable
 173            */

 174           virtual void single_step(Thread_capability, bool) {}

 175  
 176           /**
 177            * Return affinity space of CPU nodes available to the CPU session
 178            *
 179            * The dimension of the affinity space as returned by this function
 180            * represent the physical CPUs that are available.
 181            */

 182           virtual Affinity::Space affinity_space() const = 0;

 183  
 184           /**
 185            * Define affinity of thread to one or multiple CPU nodes
 186            *
 187            * In the normal case, a thread is assigned to a single CPU.
 188            * Specifying more than one CPU node is supposed to principally
 189            * allow a CPU service to balance the load of threads among
 190            * multiple CPUs.
 191            */

 192           virtual void affinity(Thread_capability thread,
 193                                 Affinity::Location affinity)
 = 0;

 194  
 195           /**
 196            * Translate generic priority value to kernel-specific priority levels
 197            *
 198            * \param pf_prio_limit  maximum priority used for the kernel, must
 199            *                       be power of 2
 200            * \param prio           generic priority value as used by the CPU
 201            *                       session interface
 202            * \param inverse        order of platform priorities, if true
 203            *                       `pf_prio_limit` corresponds to the highest
 204            *                       priority, otherwise it refers to the
 205            *                       lowest priority.
 206            * \return               platform-specific priority value
 207            */

 208           static unsigned scale_priority(unsigned pf_prio_limit, unsigned prio,
 209                                          bool inverse = true)

 210           {
 211              /*
 212               * Generic priority values are (0 is highest, `PRIORITY_LIMIT`
 213               * is lowest. On platforms where priority levels are defined
 214               * the other way round, we have to invert the priority value.
 215               */

 216              prio = inverse ? Cpu_session::PRIORITY_LIMIT - prio : prio;
 217  
 218              /* scale value to platform priority range 0..pf_prio_limit */
 219              return (prio*pf_prio_limit)/Cpu_session::PRIORITY_LIMIT;

 220           }

 221  
 222           /**
 223            * Request trace control dataspace
 224            *
 225            * The trace-control dataspace is used to propagate tracing
 226            * control information from core to the threads of a CPU session.
 227            *
 228            * The trace-control dataspace is accounted to the CPU session.
 229            */

 230           virtual Dataspace_capability trace_control() = 0;

 231  
 232           /**
 233            * Request index of a trace control block for given thread
 234            *
 235            * The trace control dataspace contains the control blocks for
 236            * all threads of the CPU session. Each thread gets assigned a
 237            * different index by the CPU service.
 238            */

 239           virtual unsigned trace_control_index(Thread_capability thread) = 0;

 240  
 241           /**
 242            * Request trace buffer for the specified thread
 243            *
 244            * The trace buffer is not accounted to the CPU session. It is
 245            * owned by a TRACE session.
 246            */

 247           virtual Dataspace_capability trace_buffer(Thread_capability thread) = 0;

 248  
 249           /**
 250            * Request trace policy
 251            *
 252            * The trace policy buffer is not accounted to the CPU session. It
 253            * is owned by a TRACE session.
 254            */

 255           virtual Dataspace_capability trace_policy(Thread_capability thread) = 0;

 256  
 257  
 258           /*********************
 259            ** RPC declaration **
 260            *********************/

 261  
 262           GENODE_RPC_THROW(Rpc_create_thread, Thread_capability, create_thread,
 263                            GENODE_TYPE_LIST(Thread_creation_failed, Out_of_metadata),
 264                            Name const &, addr_t)
;
 265           GENODE_RPC(Rpc_utcb, Ram_dataspace_capability, utcb, Thread_capability);
 266           GENODE_RPC(Rpc_kill_thread, void, kill_thread, Thread_capability);
 267           GENODE_RPC(Rpc_set_pager, int, set_pager, Thread_capability, Pager_capability);
 268           GENODE_RPC(Rpc_start, int, start, Thread_capability, addr_t, addr_t);
 269           GENODE_RPC(Rpc_pause, void, pause, Thread_capability);
 270           GENODE_RPC(Rpc_resume, void, resume, Thread_capability);
 271           GENODE_RPC(Rpc_cancel_blocking, void, cancel_blocking, Thread_capability);
 272           GENODE_RPC_THROW(Rpc_get_state, Thread_state, state,
 273                            GENODE_TYPE_LIST(State_access_failed),
 274                            Thread_capability)
;
 275           GENODE_RPC_THROW(Rpc_set_state, void, state,
 276                            GENODE_TYPE_LIST(State_access_failed),
 277                            Thread_capability, Thread_state const &)
;
 278           GENODE_RPC(Rpc_exception_handler, void, exception_handler,
 279                                             Thread_capability, Signal_context_capability)
;
 280           GENODE_RPC(Rpc_single_step, void, single_step, Thread_capability, bool);
 281           GENODE_RPC(Rpc_affinity_space, Affinity::Space, affinity_space);
 282           GENODE_RPC(Rpc_affinity, void, affinity, Thread_capability, Affinity::Location);
 283           GENODE_RPC(Rpc_trace_control, Dataspace_capability, trace_control);
 284           GENODE_RPC(Rpc_trace_control_index, unsigned, trace_control_index, Thread_capability);
 285           GENODE_RPC(Rpc_trace_buffer, Dataspace_capability, trace_buffer, Thread_capability);
 286           GENODE_RPC(Rpc_trace_policy, Dataspace_capability, trace_policy, Thread_capability);
 287  
 288           /*
 289            * `GENODE_RPC_INTERFACE` declaration done manually
 290            *
 291            * The number of RPC function of this interface exceeds the maximum
 292            * number of elements supported by `Meta::Type_list`. Therefore, we
 293            * construct the type list by hand using nested type tuples instead
 294            * of employing the convenience macro `GENODE_RPC_INTERFACE`.
 295            */

 296           typedef Meta::Type_tuple<Rpc_create_thread,
 297                   Meta::Type_tuple<Rpc_utcb,
 298                   Meta::Type_tuple<Rpc_kill_thread,
 299                   Meta::Type_tuple<Rpc_set_pager,
 300                   Meta::Type_tuple<Rpc_start,
 301                   Meta::Type_tuple<Rpc_pause,
 302                   Meta::Type_tuple<Rpc_resume,
 303                   Meta::Type_tuple<Rpc_cancel_blocking,
 304                   Meta::Type_tuple<Rpc_set_state,
 305                   Meta::Type_tuple<Rpc_get_state,
 306                   Meta::Type_tuple<Rpc_exception_handler,
 307                   Meta::Type_tuple<Rpc_single_step,
 308                   Meta::Type_tuple<Rpc_affinity_space,
 309                   Meta::Type_tuple<Rpc_affinity,
 310                   Meta::Type_tuple<Rpc_trace_control,
 311                   Meta::Type_tuple<Rpc_trace_control_index,
 312                   Meta::Type_tuple<Rpc_trace_buffer,
 313                   Meta::Type_tuple<Rpc_trace_policy,
 314                                    Meta::Empty>

 315                   >
 >
 >
 >
 >
 >
 >
 >
 >
 >
 >
 >
 >
 >
 >
 >
 >
 Rpc_functions;

 316     }
;

 317  }

 318  
 319  #endif /* _INCLUDE__CPU_SESSION__CPU_SESSION_H_ */