1  /*
   2   * \brief  CPU (processing time) manager session interface
   3   * \author Christian Helmuth
   4   * \date   2006-06-27
   5   */

   6  
   7  /*
   8   * Copyright (C) 2006-2013 Genode Labs GmbH
   9   *
  10   * This file is part of the Genode OS framework, which is distributed
  11   * under the terms of the GNU General Public License version 2.
  12   */

  13  
  14  #ifndef _INCLUDE__CPU_SESSION__CPU_SESSION_H_
  15  #define _INCLUDE__CPU_SESSION__CPU_SESSION_H_
  16  
  17  #include <cpu_session/capability.h>
  18  #include <base/stdint.h>
  19  #include <base/exception.h>
  20  #include <base/thread_state.h>
  21  #include <base/rpc_args.h>
  22  #include <base/signal.h>
  23  #include <base/affinity.h>
  24  #include <thread/capability.h>
  25  #include <pager/capability.h>
  26  #include <session/session.h>
  27  #include <ram_session/ram_session.h>
  28  
  29  namespace Genode { struct Cpu_session; }
  30  
  31  
  32  struct Genode::Cpu_session : Session
  33  {
  34     /*********************
  35      ** Exception types **
  36      *********************/

  37  
  38     class Thread_creation_failed : public Exception { };
  39     class State_access_failed    : public Exception { };
  40     class Quota_exceeded         : public Thread_creation_failed { };
  41     class Out_of_metadata        : public Exception { };
  42  
  43     static const char *service_name() { return "CPU"; }
  44  
  45     enum { THREAD_NAME_LEN = 48 };
  46     enum { PRIORITY_LIMIT = << 16 };
  47     enum { QUOTA_LIMIT_LOG2 = 15 };
  48     enum { QUOTA_LIMIT = << QUOTA_LIMIT_LOG2 };
  49     enum { DEFAULT_PRIORITY = 0 };
  50     enum { DEFAULT_WEIGHT = 10 };
  51  
  52     typedef Rpc_in_buffer<THREAD_NAME_LEN> Name;
  53  
  54     /**
  55      * Physical quota configuration
  56      */

  57     struct Quota;
  58  
  59     virtual ~Cpu_session() { }
  60  
  61     /**
  62      * Create a new thread
  63      *
  64      * \param quota  CPU quota that shall be granted to the thread
  65      * \param name   name for the thread
  66      * \param utcb   Base of the UTCB that will be used by the thread
  67      * \return       capability representing the new thread
  68      * \throw        Thread_creation_failed
  69      * \throw        Out_of_metadata
  70      * \throw        Quota_exceeded
  71      */

  72     virtual Thread_capability create_thread(size_t quota,
  73                                             Name const &name,
  74                                             addr_t utcb = 0)
 = 0;

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

  79     virtual Ram_dataspace_capability utcb(Thread_capability thread) = 0;

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

  86     virtual void kill_thread(Thread_capability thread) = 0;

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

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

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

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

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

 115     virtual void pause(Thread_capability thread) = 0;

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

 120     virtual void resume(Thread_capability thread) = 0;

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

 127     virtual void cancel_blocking(Thread_capability thread) = 0;

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

 136     virtual Thread_state state(Thread_capability thread) = 0;

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

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

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

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

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

 173     virtual void single_step(Thread_capability, bool) {}

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

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

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

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

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

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

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

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

 219     }

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

 229     virtual Dataspace_capability trace_control() = 0;

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

 238     virtual unsigned trace_control_index(Thread_capability thread) = 0;

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

 246     virtual Dataspace_capability trace_buffer(Thread_capability thread) = 0;

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

 254     virtual Dataspace_capability trace_policy(Thread_capability thread) = 0;

 255  
 256     /**
 257      * Define reference account for the CPU session
 258      *
 259      * \param   cpu_session    reference account
 260      *
 261      * \return  0 on success
 262      *
 263      * Each CPU session requires another CPU session as reference
 264      * account to transfer quota to and from. The reference account can
 265      * be defined only once.
 266      */

 267     virtual int ref_account(Cpu_session_capability cpu_session) = 0;

 268  
 269     /**
 270      * Transfer quota to another CPU session
 271      *
 272      * \param cpu_session  receiver of quota donation
 273      * \param amount       percentage of the session quota scaled up to
 274      *                     the `QUOTA_LIMIT` space
 275      * \return             0 on success
 276      *
 277      * Quota can only be transfered if the specified CPU session is
 278      * either the reference account for this session or vice versa.
 279      */

 280     virtual int transfer_quota(Cpu_session_capability cpu_session,
 281                                size_t amount)
 = 0;

 282  
 283     /**
 284      * Return quota configuration of the session
 285      */

 286     virtual Quota quota() = 0;

 287  
 288     /**
 289      * Scale up `value` from its space with `limit` to the `QUOTA_LIMIT` space
 290      */

 291     template<typename = size_t>
 292     static size_t quota_lim_upscale(size_t const value, size_t const limit) {
 293        return ((T)value << Cpu_session::QUOTA_LIMIT_LOG2) / limit; }

 294  
 295     /**
 296      * Scale down `value` from the `QUOTA_LIMIT` space to a space with `limit`
 297      */

 298     template<typename = size_t>
 299     static size_t quota_lim_downscale(size_t const value, size_t const limit) {
 300        return ((T)value * limit) >> Cpu_session::QUOTA_LIMIT_LOG2; }

 301  
 302     /*********************
 303      ** RPC declaration **
 304      *********************/

 305  
 306     GENODE_RPC_THROW(Rpc_create_thread, Thread_capability, create_thread,
 307                      GENODE_TYPE_LIST(Thread_creation_failed, Out_of_metadata),
 308                      size_t, Name const &, addr_t)
;
 309     GENODE_RPC(Rpc_utcb, Ram_dataspace_capability, utcb, Thread_capability);
 310     GENODE_RPC(Rpc_kill_thread, void, kill_thread, Thread_capability);
 311     GENODE_RPC(Rpc_set_pager, int, set_pager, Thread_capability, Pager_capability);
 312     GENODE_RPC(Rpc_start, int, start, Thread_capability, addr_t, addr_t);
 313     GENODE_RPC(Rpc_pause, void, pause, Thread_capability);
 314     GENODE_RPC(Rpc_resume, void, resume, Thread_capability);
 315     GENODE_RPC(Rpc_cancel_blocking, void, cancel_blocking, Thread_capability);
 316     GENODE_RPC_THROW(Rpc_get_state, Thread_state, state,
 317                      GENODE_TYPE_LIST(State_access_failed),
 318                      Thread_capability)
;
 319     GENODE_RPC_THROW(Rpc_set_state, void, state,
 320                      GENODE_TYPE_LIST(State_access_failed),
 321                      Thread_capability, Thread_state const &)
;
 322     GENODE_RPC(Rpc_exception_handler, void, exception_handler,
 323                                       Thread_capability, Signal_context_capability)
;
 324     GENODE_RPC(Rpc_single_step, void, single_step, Thread_capability, bool);
 325     GENODE_RPC(Rpc_affinity_space, Affinity::Space, affinity_space);
 326     GENODE_RPC(Rpc_affinity, void, affinity, Thread_capability, Affinity::Location);
 327     GENODE_RPC(Rpc_trace_control, Dataspace_capability, trace_control);
 328     GENODE_RPC(Rpc_trace_control_index, unsigned, trace_control_index, Thread_capability);
 329     GENODE_RPC(Rpc_trace_buffer, Dataspace_capability, trace_buffer, Thread_capability);
 330     GENODE_RPC(Rpc_trace_policy, Dataspace_capability, trace_policy, Thread_capability);
 331     GENODE_RPC(Rpc_ref_account, int, ref_account, Cpu_session_capability);
 332     GENODE_RPC(Rpc_transfer_quota, int, transfer_quota, Cpu_session_capability, size_t);
 333     GENODE_RPC(Rpc_quota, Quota, quota);
 334  
 335     /*
 336      * `GENODE_RPC_INTERFACE` declaration done manually
 337      *
 338      * The number of RPC functions of this interface exceeds the maximum
 339      * number of elements supported by `Meta::Type_list`. Therefore, we
 340      * construct the type list by hand using nested type tuples instead
 341      * of employing the convenience macro `GENODE_RPC_INTERFACE`.
 342      */

 343     typedef Meta::Type_tuple<Rpc_create_thread,
 344             Meta::Type_tuple<Rpc_utcb,
 345             Meta::Type_tuple<Rpc_kill_thread,
 346             Meta::Type_tuple<Rpc_set_pager,
 347             Meta::Type_tuple<Rpc_start,
 348             Meta::Type_tuple<Rpc_pause,
 349             Meta::Type_tuple<Rpc_resume,
 350             Meta::Type_tuple<Rpc_cancel_blocking,
 351             Meta::Type_tuple<Rpc_set_state,
 352             Meta::Type_tuple<Rpc_get_state,
 353             Meta::Type_tuple<Rpc_exception_handler,
 354             Meta::Type_tuple<Rpc_single_step,
 355             Meta::Type_tuple<Rpc_affinity_space,
 356             Meta::Type_tuple<Rpc_affinity,
 357             Meta::Type_tuple<Rpc_trace_control,
 358             Meta::Type_tuple<Rpc_trace_control_index,
 359             Meta::Type_tuple<Rpc_trace_buffer,
 360             Meta::Type_tuple<Rpc_trace_policy,
 361             Meta::Type_tuple<Rpc_ref_account,
 362             Meta::Type_tuple<Rpc_transfer_quota,
 363             Meta::Type_tuple<Rpc_quota,
 364                              Meta::Empty>

 365             
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 
>
 Rpc_functions;

 366  }
;

 367  
 368  struct Genode::Cpu_session::Quota
 369  {
 370     size_t super_period_us;
 371     size_t us;

 372  }
;

 373  
 374  #endif /* _INCLUDE__CPU_SESSION__CPU_SESSION_H_ */